Try to handle invalid ffmpeg arguments more gracefully (fixes #77)

Instead of outright crashing, if the user has modified the ffmpeg arguments,
they are given the chance to re-try with the defaults.
This commit is contained in:
Jonas Herzig
2017-08-12 11:34:06 +02:00
parent a2f8c88a3d
commit b9ea572e19
6 changed files with 244 additions and 40 deletions

View File

@@ -39,6 +39,7 @@ import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
import static com.google.common.collect.Iterables.getLast;
import static com.replaymod.render.ReplayModRender.LOGGER;
import static net.minecraft.client.renderer.GlStateManager.*;
import static org.lwjgl.opengl.GL11.GL_COLOR_BUFFER_BIT;
import static org.lwjgl.opengl.GL11.GL_DEPTH_BUFFER_BIT;
@@ -66,6 +67,7 @@ public class VideoRenderer implements RenderInfo {
private final GuiVideoRenderer gui;
private boolean paused;
private boolean cancelled;
private volatile Throwable failureCause;
private Framebuffer guiFramebuffer;
private int displayWidth, displayHeight;
@@ -76,7 +78,7 @@ public class VideoRenderer implements RenderInfo {
this.timeline = timeline;
this.gui = new GuiVideoRenderer(this);
this.renderingPipeline = Pipelines.newPipeline(settings.getRenderMethod(), this,
videoWriter = new VideoWriter(settings) {
videoWriter = new VideoWriter(this) {
@Override
public void consume(RGBFrame frame) {
gui.updatePreview(frame);
@@ -89,7 +91,7 @@ public class VideoRenderer implements RenderInfo {
* Render this video.
* @return {@code true} if rendering was successful, {@code false} if the user aborted rendering (or the window was closed)
*/
public boolean renderVideo() {
public boolean renderVideo() throws Throwable {
FMLCommonHandler.instance().bus().post(new ReplayRenderEvent.Pre(this));
setup();
@@ -138,6 +140,10 @@ public class VideoRenderer implements RenderInfo {
FMLCommonHandler.instance().bus().post(new ReplayRenderEvent.Post(this));
if (failureCause != null) {
throw failureCause;
}
return !cancelled;
}
@@ -250,7 +256,13 @@ public class VideoRenderer implements RenderInfo {
ReplayMod.soundHandler.playRenderSuccessSound();
new GuiRenderingDone(ReplayModRender.instance, videoWriter.getVideoFile(), totalFrames, settings).display();
try {
if (!hasFailed()) {
new GuiRenderingDone(ReplayModRender.instance, videoWriter.getVideoFile(), totalFrames, settings).display();
}
} catch (VideoWriter.FFmpegStartupException e) {
setFailure(e);
}
// Finally, resize the Minecraft framebuffer to the actual width/height of the window
mc.resize(displayWidth, displayHeight);
@@ -326,7 +338,7 @@ public class VideoRenderer implements RenderInfo {
return;
}
}
} while (paused);
} while (paused && !hasFailed());
}
private boolean displaySizeChanged() {
@@ -367,6 +379,20 @@ public class VideoRenderer implements RenderInfo {
renderingPipeline.cancel();
}
public boolean hasFailed() {
return failureCause != null;
}
public synchronized void setFailure(Throwable cause) {
if (this.failureCause != null) {
LOGGER.error("Further failure during failed rendering: ", cause);
} else {
LOGGER.error("Failure during rendering: ", cause);
this.failureCause = cause;
cancel();
}
}
private class TimelinePlayer extends AbstractTimelinePlayer {
public TimelinePlayer(ReplayHandler replayHandler) {
super(replayHandler);