From 936f242b4cd98eef68a7b82599da1baa1f3729a2 Mon Sep 17 00:00:00 2001 From: CrushedPixel Date: Wed, 15 Jul 2015 16:50:51 +0200 Subject: [PATCH] Added Encoding Presets to GuiRenderSettings and removed Checkbox for Custom Resolution --- .../replaymod/gui/GuiConstants.java | 1 - .../replaymod/gui/GuiRenderSettings.java | 121 ++++++++++++------ .../replaymod/settings/EncodingPreset.java | 46 +++++++ .../replaymod/settings/RenderOptions.java | 4 +- .../assets/replaymod/lang/en_US.lang | 9 +- 5 files changed, 136 insertions(+), 45 deletions(-) create mode 100644 src/main/java/eu/crushedpixel/replaymod/settings/EncodingPreset.java diff --git a/src/main/java/eu/crushedpixel/replaymod/gui/GuiConstants.java b/src/main/java/eu/crushedpixel/replaymod/gui/GuiConstants.java index 2e4df532..270dcae0 100755 --- a/src/main/java/eu/crushedpixel/replaymod/gui/GuiConstants.java +++ b/src/main/java/eu/crushedpixel/replaymod/gui/GuiConstants.java @@ -63,7 +63,6 @@ public class GuiConstants { public static final int RENDER_SETTINGS_RENDER_BUTTON = 9002; public static final int RENDER_SETTINGS_CANCEL_BUTTON = 9003; - public static final int RENDER_SETTINGS_RESOLUTION_CHECKBOX = 9004; public static final int RENDER_SETTINGS_INTERPOLATION_BUTTON = 9007; public static final int RENDER_SETTINGS_FORCECHUNKS_BUTTON = 9008; public static final int RENDER_SETTINGS_FRAMERATE_SLIDER = 9009; diff --git a/src/main/java/eu/crushedpixel/replaymod/gui/GuiRenderSettings.java b/src/main/java/eu/crushedpixel/replaymod/gui/GuiRenderSettings.java index 20ec2556..0f0fa38c 100644 --- a/src/main/java/eu/crushedpixel/replaymod/gui/GuiRenderSettings.java +++ b/src/main/java/eu/crushedpixel/replaymod/gui/GuiRenderSettings.java @@ -5,6 +5,7 @@ import eu.crushedpixel.replaymod.gui.elements.*; import eu.crushedpixel.replaymod.gui.elements.listeners.SelectionListener; import eu.crushedpixel.replaymod.holders.GuiEntryListEntry; import eu.crushedpixel.replaymod.replay.ReplayHandler; +import eu.crushedpixel.replaymod.settings.EncodingPreset; import eu.crushedpixel.replaymod.settings.RenderOptions; import eu.crushedpixel.replaymod.utils.MouseUtils; import eu.crushedpixel.replaymod.utils.ReplayFileIO; @@ -18,6 +19,7 @@ import net.minecraft.client.resources.I18n; import net.minecraftforge.fml.client.FMLClientHandler; import net.minecraftforge.fml.client.config.GuiCheckBox; import org.apache.commons.io.FileUtils; +import org.apache.commons.io.FilenameUtils; import org.lwjgl.input.Keyboard; import org.lwjgl.util.Point; @@ -34,16 +36,16 @@ public class GuiRenderSettings extends GuiScreen { //for default file private static final String DATE_FORMAT = "yyyy_MM_dd_HH_mm_ss"; private static final SimpleDateFormat FILE_FORMAT = new SimpleDateFormat(DATE_FORMAT); - private static final String WEBM_EXTENSION = ".webm"; private static final int LEFT_BORDER = 10; private GuiAdvancedButton renderButton, cancelButton, advancedButton; private GuiDropdown rendererDropdown; + private GuiDropdown encodingPresetDropdown; private int virtualY, virtualHeight; - private GuiCheckBox customResolution, ignoreCamDir, enableGreenscreen; + private GuiCheckBox ignoreCamDir, enableGreenscreen; private GuiNumberInput xRes, yRes; private GuiToggleButton interpolation, forceChunks; private GuiVideoFramerateSlider framerateSlider; @@ -79,12 +81,17 @@ public class GuiRenderSettings extends GuiScreen { i++; } + encodingPresetDropdown = new GuiDropdown(fontRendererObj, 0, 0, 200, 5); + encodingPresetDropdown.addSelectionListener(new EncodingDropdownListener()); + + for (EncodingPreset preset : EncodingPreset.values()) { + encodingPresetDropdown.addElement(preset); + } + renderButton = new GuiAdvancedButton(GuiConstants.RENDER_SETTINGS_RENDER_BUTTON, 0, 0, I18n.format("replaymod.gui.render")); cancelButton = new GuiAdvancedButton(GuiConstants.RENDER_SETTINGS_CANCEL_BUTTON, 0, 0, I18n.format("replaymod.gui.cancel")); advancedButton = new GuiAdvancedButton(GuiConstants.RENDER_SETTINGS_ADVANCED_BUTTON, 0, 0, I18n.format("replaymod.gui.rendersettings.advanced")); - customResolution = new GuiCheckBox(GuiConstants.RENDER_SETTINGS_RESOLUTION_CHECKBOX, 0, 0, I18n.format("replaymod.gui.rendersettings.customresolution"), false); - xRes = new GuiNumberInput(fontRendererObj, 0, 0, 50, 1, 100000, mc.displayWidth, false) { @Override public void moveCursorBy(int move) { @@ -124,8 +131,6 @@ public class GuiRenderSettings extends GuiScreen { bitrateInput = new GuiNumberInputWithText(fontRendererObj, 0, 0, 50, 1D, null, 10000D, false, " kbps"); - xRes.setElementEnabled(false); - yRes.setElementEnabled(false); bitrateInput.setElementEnabled(true); framerateSlider = new GuiVideoFramerateSlider(GuiConstants.RENDER_SETTINGS_FRAMERATE_SLIDER, 0, 0, ReplayMod.replaySettings.getVideoFramerate(), @@ -133,7 +138,7 @@ public class GuiRenderSettings extends GuiScreen { File defaultFile = null; try { - defaultFile = new File(ReplayFileIO.getRenderFolder(), FILE_FORMAT.format(Calendar.getInstance().getTime())+WEBM_EXTENSION); + defaultFile = new File(ReplayFileIO.getRenderFolder(), FILE_FORMAT.format(Calendar.getInstance().getTime())+"."+ EncodingPreset.MP4DEFAULT.getFileExtension()); } catch(IOException ioe) { ioe.printStackTrace(); } @@ -171,11 +176,12 @@ public class GuiRenderSettings extends GuiScreen { ignoreCamDir = new GuiCheckBox(GuiConstants.RENDER_SETTINGS_STATIC_CAMERA, 0, 0, I18n.format("replaymod.gui.rendersettings.stablecamera"), false); ignoreCamDir.enabled = false; + encodingPresetDropdown.setSelectionIndex(0); + permanentButtons.add(advancedButton); permanentButtons.add(renderButton); permanentButtons.add(cancelButton); - defaultButtons.add(customResolution); defaultButtons.add(framerateSlider); defaultButtons.add(ignoreCamDir); defaultButtons.add(outputFileChooser); @@ -199,16 +205,22 @@ public class GuiRenderSettings extends GuiScreen { w1 = rendererDropdown.width + fontRendererObj.getStringWidth(I18n.format("replaymod.gui.rendersettings.renderer") + ":")+10; rendererDropdown.yPosition = virtualY + 15 + 15; - rendererDropdown.xPosition = (width-w1)/2 + fontRendererObj.getStringWidth(I18n.format("replaymod.gui.rendersettings.renderer") + ":")+10; + rendererDropdown.xPosition = encodingPresetDropdown.xPosition = + (width-w1)/2 + fontRendererObj.getStringWidth(I18n.format("replaymod.gui.rendersettings.renderer") + ":")+10; - int w2 = customResolution.width + 5 + xRes.width + 5 + fontRendererObj.getStringWidth("*") + 5 + yRes.width; + encodingPresetDropdown.yPosition = rendererDropdown.yPosition + 20 + 10; - customResolution.yPosition = virtualY + 15 + 5 + 20 + 10 +5+fontRendererObj.getStringWidth("*")+5; - customResolution.xPosition = (width- w2)/2; + String customResString = I18n.format("replaymod.gui.rendersettings.customresolution"); + int customResWidth = fontRendererObj.getStringWidth(customResString); - xRes.xPosition = customResolution.xPosition + customResolution.width + 5; + int w2 = customResWidth + 5 + xRes.width + 5 + fontRendererObj.getStringWidth("*") + 5 + yRes.width; + + int yPos = virtualY + 15 + 5 + 50 + 10 + 5+fontRendererObj.getStringWidth("*")+5; + int xPos = (width- w2)/2; + + xRes.xPosition = xPos + customResWidth + 5; yRes.xPosition = xRes.xPosition+xRes.width+5+fontRendererObj.getStringWidth("*")+5; - xRes.yPosition = yRes.yPosition = customResolution.yPosition-3; + xRes.yPosition = yRes.yPosition = yPos-3; int w3 = interpolation.width + 10 + forceChunks.width; @@ -281,16 +293,26 @@ public class GuiRenderSettings extends GuiScreen { if(!advancedTab) { this.drawString(fontRendererObj, I18n.format("replaymod.gui.rendersettings.renderer") + ":", - (width - w1) / 2, rendererDropdown.yPosition + 8, Color.WHITE.getRGB()); + (width - w1) / 2, rendererDropdown.yPosition + 6, Color.WHITE.getRGB()); + + this.drawString(fontRendererObj, I18n.format("replaymod.gui.rendersettings.presets") + ":", + (width - w1) / 2, encodingPresetDropdown.yPosition + 6, Color.WHITE.getRGB()); + + String resString = I18n.format("replaymod.gui.rendersettings.customresolution")+":"; + int strWidth = fontRendererObj.getStringWidth(resString); + + this.drawString(fontRendererObj, resString, + xRes.xPosition - strWidth - 5, xRes.yPosition+6, Color.WHITE.getRGB()); xRes.drawTextBox(); yRes.drawTextBox(); bitrateInput.drawTextBox(); - this.drawString(fontRendererObj, "*", xRes.xPosition + xRes.width + 5, xRes.yPosition + 3, Color.WHITE.getRGB()); + this.drawString(fontRendererObj, "*", xRes.xPosition + xRes.width + 5, xRes.yPosition + 6, Color.WHITE.getRGB()); String bitrateString = I18n.format("replaymod.gui.settings.bitrate")+": "; this.drawString(fontRendererObj, bitrateString, forceChunks.xPosition, bitrateInput.yPosition + 6, Color.WHITE.getRGB()); + encodingPresetDropdown.drawTextBox(); rendererDropdown.drawTextBox(); } else { commandInput.drawTextBox(); @@ -310,25 +332,27 @@ public class GuiRenderSettings extends GuiScreen { @Override protected void mouseClicked(int mouseX, int mouseY, int mouseButton) throws IOException { if(!rendererDropdown.mouseClickedResult(mouseX, mouseY)) { - if(!advancedTab) { - xRes.mouseClicked(mouseX, mouseY, mouseButton); - yRes.mouseClicked(mouseX, mouseY, mouseButton); - bitrateInput.mouseClicked(mouseX, mouseY, mouseButton); - } else { - commandInput.mouseClicked(mouseX, mouseY, mouseButton); - ffmpegArguments.mouseClicked(mouseX, mouseY, mouseButton); - } + if(!encodingPresetDropdown.mouseClickedResult(mouseX, mouseY)) { + if(!advancedTab) { + xRes.mouseClicked(mouseX, mouseY, mouseButton); + yRes.mouseClicked(mouseX, mouseY, mouseButton); + bitrateInput.mouseClicked(mouseX, mouseY, mouseButton); + } else { + commandInput.mouseClicked(mouseX, mouseY, mouseButton); + ffmpegArguments.mouseClicked(mouseX, mouseY, mouseButton); + } - if(mouseButton == 0) { - List toHandle = new ArrayList(); - toHandle.addAll(permanentButtons); - toHandle.addAll(advancedTab ? advancedButtons : defaultButtons); + if(mouseButton == 0) { + List toHandle = new ArrayList(); + toHandle.addAll(permanentButtons); + toHandle.addAll(advancedTab ? advancedButtons : defaultButtons); - for(GuiButton b : toHandle) { - b.mousePressed(this.mc, mouseX, mouseY); - if(b.mousePressed(this.mc, mouseX, mouseY)) { - b.playPressSound(this.mc.getSoundHandler()); - actionPerformed(b); + for(GuiButton b : toHandle) { + b.mousePressed(this.mc, mouseX, mouseY); + if(b.mousePressed(this.mc, mouseX, mouseY)) { + b.playPressSound(this.mc.getSoundHandler()); + actionPerformed(b); + } } } } @@ -350,10 +374,10 @@ public class GuiRenderSettings extends GuiScreen { protected void keyTyped(char typedChar, int keyCode) throws IOException { if(!advancedTab) { if(keyCode == Keyboard.KEY_TAB) { - if(xRes.isFocused() && customResolution.isChecked()) { + if(xRes.isFocused()) { xRes.setFocused(false); yRes.setFocused(true); - } else if(yRes.isFocused() && customResolution.isChecked()) { + } else if(yRes.isFocused()) { yRes.setFocused(false); xRes.setFocused(true); } @@ -400,11 +424,7 @@ public class GuiRenderSettings extends GuiScreen { } else if(defaultButtons.contains(button) && !advancedTab) { if(button instanceof GuiCheckBox) ((GuiCheckBox)button).setIsChecked(!((GuiCheckBox)button).isChecked()); - if(button.id == GuiConstants.RENDER_SETTINGS_RESOLUTION_CHECKBOX) { - boolean enabled = customResolution.isChecked(); - xRes.setElementEnabled(enabled); - yRes.setElementEnabled(enabled); - } else if(button.id == GuiConstants.RENDER_SETTINGS_OUTPUT_CHOOSER) { + else if(button.id == GuiConstants.RENDER_SETTINGS_OUTPUT_CHOOSER) { Point mouse = MouseUtils.getMousePos(); outputFileChooser.mouseClick(mc, mouse.getX(), mouse.getY(), 0); } @@ -468,7 +488,10 @@ public class GuiRenderSettings extends GuiScreen { options.setBitrate(bitrateInput.getIntValue() + "K"); //Bitrate value is in Kilobytes + //remove the extension from the output file File outputFile = outputFileChooser.getSelectedFile(); + outputFile = new File(outputFile.getParent(), FilenameUtils.getBaseName(outputFile.getAbsolutePath())); + if(outputFile.exists()) FileUtils.deleteQuietly(outputFile); options.setOutputFile(outputFile); @@ -546,6 +569,24 @@ public class GuiRenderSettings extends GuiScreen { } } + private class EncodingDropdownListener implements SelectionListener { + @Override + public void onSelectionChanged(int selectionIndex) { + EncodingPreset preset = encodingPresetDropdown.getElement(selectionIndex); + + bitrateInput.setEnabled(preset.hasBitrateSetting()); + ffmpegArguments.setText(preset.getCommandLineArgs()); + + outputFileChooser.setAllowedExtensions(new String[]{preset.getFileExtension()}); + + File selectedFile = outputFileChooser.getSelectedFile(); + if(selectedFile != null) { + String newName = FilenameUtils.getBaseName(selectedFile.getAbsolutePath())+"."+preset.getFileExtension(); + outputFileChooser.setSelectedFile(new File(selectedFile.getParent(), newName)); + } + } + } + @Override public void onGuiClosed() { Keyboard.enableRepeatEvents(false); diff --git a/src/main/java/eu/crushedpixel/replaymod/settings/EncodingPreset.java b/src/main/java/eu/crushedpixel/replaymod/settings/EncodingPreset.java new file mode 100644 index 00000000..1ba24699 --- /dev/null +++ b/src/main/java/eu/crushedpixel/replaymod/settings/EncodingPreset.java @@ -0,0 +1,46 @@ +package eu.crushedpixel.replaymod.settings; + +import eu.crushedpixel.replaymod.holders.GuiEntryListEntry; +import lombok.AllArgsConstructor; +import lombok.Getter; +import net.minecraft.client.resources.I18n; + +@AllArgsConstructor +public enum EncodingPreset implements GuiEntryListEntry { + + MP4DEFAULT("replaymod.gui.rendersettings.presets.mp4.default", + "-f rawvideo -pix_fmt argb -s %WIDTH%x%HEIGHT% -r %FPS% -i - -an -c:v libx264 -preset ultrafast -pix_fmt yuv420p %FILENAME%.mp4", "mp4"), + + MP4CUSTOM("replaymod.gui.rendersettings.presets.mp4.custom", + "-f rawvideo -pix_fmt argb -s %WIDTH%x%HEIGHT% -r %FPS% -i - -an -c:v libx264 -b:v %BITRATE% -pix_fmt yuv420p %FILENAME%.mp4", "mp4"), + + MP4POTATO("replaymod.gui.rendersettings.presets.mp4.potato", + "-f rawvideo -pix_fmt argb -s %WIDTH%x%HEIGHT% -r %FPS% -i - -an -c:v libx264 -preset ultrafast -crf 51 -pix_fmt yuv420p %FILENAME%.mp4", "mp4"), + + MKVLOSSLESS("replaymod.gui.rendersettings.presets.mkv.lossless", + "-f rawvideo -pix_fmt argb -s %WIDTH%x%HEIGHT% -r %FPS% -i - -an -c:v libx264 -preset ultrafast -qp 0 %FILENAME%.mkv", "mkv"), + + WEBMCUSTOM("replaymod.gui.rendersettings.presets.webm.custom", + "-f rawvideo -pix_fmt argb -s %WIDTH%x%HEIGHT% -r %FPS% -i - -an -c:v libvpx -b:v %BITRATE% %FILENAME%.webm", "webm"); + + private String name; + + @Getter + private String commandLineArgs; + + @Getter + private String fileExtension; + + public boolean hasBitrateSetting() { + return commandLineArgs.contains("%BITRATE%"); + } + + @Override + public String getDisplayString() { + return getI18nName(); + } + + public String getI18nName() { + return I18n.format(name); + } +} diff --git a/src/main/java/eu/crushedpixel/replaymod/settings/RenderOptions.java b/src/main/java/eu/crushedpixel/replaymod/settings/RenderOptions.java index 75a13bce..685be13a 100644 --- a/src/main/java/eu/crushedpixel/replaymod/settings/RenderOptions.java +++ b/src/main/java/eu/crushedpixel/replaymod/settings/RenderOptions.java @@ -27,9 +27,7 @@ public final class RenderOptions { // Highly advanced private String exportCommand = "ffmpeg"; - private String exportCommandArgs = "-f rawvideo -pix_fmt argb -s %WIDTH%x%HEIGHT% -r %FPS% -i - " + - "-an " + - "-c:v libvpx -b:v %BITRATE% %FILENAME%"; + private String exportCommandArgs = ""; public int getFps() { return fps; diff --git a/src/main/resources/assets/replaymod/lang/en_US.lang b/src/main/resources/assets/replaymod/lang/en_US.lang index 7983e16a..53c8b3b9 100644 --- a/src/main/resources/assets/replaymod/lang/en_US.lang +++ b/src/main/resources/assets/replaymod/lang/en_US.lang @@ -306,7 +306,7 @@ replaymod.gui.rendersettings.renderer.stereoscopic.description=Renders the video replaymod.gui.rendersettings.renderer.cubic.description=Renders the video with a 360 degree panoramic view, using Cubic Projection. This is useable by several 360 degree video players (and the Oculus Rift), for example VR Player. replaymod.gui.rendersettings.renderer.equirectangular.description=Renders the video with a 360 degree panoramic view, using Equirectangular Projection. This is useable by YouTube's new 360 degree video function, and several video players (and the Oculus Rift), for example VR Player. -replaymod.gui.rendersettings.customresolution=Custom Video Resolution +replaymod.gui.rendersettings.customresolution=Video Resolution replaymod.gui.rendersettings.customresolution.warning.cubic=Cubic Rendering requires an aspect ratio of 4:3 replaymod.gui.rendersettings.customresolution.warning.equirectangular=Equirectangular Rendering requires an aspect ratio of 2:1 replaymod.gui.rendersettings.resolution=Video Resolution @@ -328,6 +328,13 @@ replaymod.gui.rendersettings.exportyoutube=Export for YouTube replaymod.gui.rendersettings.basic=Basic Settings replaymod.gui.rendersettings.advanced=Advanced Settings +replaymod.gui.rendersettings.presets=Encoding Presets +replaymod.gui.rendersettings.presets.mp4.default=MP4 - Default +replaymod.gui.rendersettings.presets.mp4.custom=MP4 - Custom Bitrate +replaymod.gui.rendersettings.presets.mp4.potato=MP4 - Potato +replaymod.gui.rendersettings.presets.mkv.lossless=MKV - Lossless +replaymod.gui.rendersettings.presets.webm.custom=WEBM - Custom Bitrate + #Rendering GUI replaymod.gui.rendering.title=Rendering Video replaymod.gui.rendering.pause=Pause Rendering