diff --git a/src/main/java/com/github/kokorin/jaffree/ffmpeg/FFmpeg.java b/src/main/java/com/github/kokorin/jaffree/ffmpeg/FFmpeg.java index 0a3f8177..0edf7932 100644 --- a/src/main/java/com/github/kokorin/jaffree/ffmpeg/FFmpeg.java +++ b/src/main/java/com/github/kokorin/jaffree/ffmpeg/FFmpeg.java @@ -59,6 +59,7 @@ public class FFmpeg { private LogLevel logLevel = LogLevel.INFO; private String contextName = null; + private Integer executorTimeoutMillis = null; private final Path executable; @@ -387,6 +388,26 @@ public FFmpeg setContextName(final String contextName) { return this; } + /** + * Overrides the default {@link com.github.kokorin.jaffree.process.Executor} timeout. + *

+ * Most normal use cases will easily complete within the default timeout. It is not recommended + * to set an explicit timeout value unless you have actually experienced unwanted timeouts. + *

+ * A value of 0 will disable the timeout. + * That is, Jaffree will wait indefinitely for the Executor to complete. + * + * @param executorTimeoutMillis the custom executor timeout in milliseconds + * @return this + */ + public FFmpeg setExecutorTimeoutMillis(final int executorTimeoutMillis) { + if (executorTimeoutMillis < 0) { + throw new IllegalArgumentException("Executor timeout cannot be negative"); + } + this.executorTimeoutMillis = executorTimeoutMillis; + return this; + } + /** * Starts synchronous ffmpeg execution. *

@@ -480,11 +501,16 @@ protected ProcessHandler createProcessHandler() { helpers.add(progressHelper); } - return new ProcessHandler(executable, contextName) - .setStdErrReader(createStdErrReader(outputListener)) - .setStdOutReader(createStdOutReader()) - .setHelpers(helpers) - .setArguments(buildArguments()); + ProcessHandler processHandler = + new ProcessHandler(executable, contextName) + .setStdErrReader(createStdErrReader(outputListener)) + .setStdOutReader(createStdOutReader()) + .setHelpers(helpers) + .setArguments(buildArguments()); + if (executorTimeoutMillis != null) { + processHandler.setExecutorTimeoutMillis(executorTimeoutMillis); + } + return processHandler; } /** diff --git a/src/main/java/com/github/kokorin/jaffree/process/ProcessHandler.java b/src/main/java/com/github/kokorin/jaffree/process/ProcessHandler.java index a7e5b3e3..73e8012f 100644 --- a/src/main/java/com/github/kokorin/jaffree/process/ProcessHandler.java +++ b/src/main/java/com/github/kokorin/jaffree/process/ProcessHandler.java @@ -49,8 +49,9 @@ public class ProcessHandler { private List helpers = null; private Stopper stopper = null; private List arguments = Collections.emptyList(); + private int executorTimeoutMillis = DEFAULT_EXECUTOR_TIMEOUT_MILLIS; - private static final int EXECUTOR_TIMEOUT_MILLIS = 10_000; + private static final int DEFAULT_EXECUTOR_TIMEOUT_MILLIS = 10_000; private static final Logger LOGGER = LoggerFactory.getLogger(ProcessHandler.class); /** @@ -120,6 +121,20 @@ public synchronized ProcessHandler setArguments(final List arguments) return this; } + /** + * Overrides the default Executor timeout. + *

+ * A value of 0 is interpreted as "wait indefinitely". + * + * @param executorTimeoutMillis the new Executor timeout in milliseconds + */ + public void setExecutorTimeoutMillis(final int executorTimeoutMillis) { + if (executorTimeoutMillis < 0) { + throw new IllegalArgumentException("Executor timeout cannot be negative"); + } + this.executorTimeoutMillis = executorTimeoutMillis; + } + /** * Executes a program. *

@@ -180,7 +195,7 @@ protected T interactWithProcess(final Process process) { status = process.waitFor(); LOGGER.info("Process has finished with status: {}", status); - waitForExecutorToStop(executor, EXECUTOR_TIMEOUT_MILLIS); + waitForExecutorToStop(executor, executorTimeoutMillis); } catch (InterruptedException e) { LOGGER.warn("Process has been interrupted"); if (stopper != null) { @@ -308,9 +323,10 @@ private static void waitForExecutorToStop(final Executor executor, final long ti throws InterruptedException { LOGGER.debug("Waiting for Executor to stop"); - long waitStarted = System.currentTimeMillis(); + final long waitStarted = System.currentTimeMillis(); do { - if (System.currentTimeMillis() - waitStarted > timeoutMillis) { + // Zero timeout means "wait indefinitely" + if (timeoutMillis > 0 && System.currentTimeMillis() - waitStarted > timeoutMillis) { LOGGER.warn("Executor hasn't stopped in {} millis, won't wait longer", timeoutMillis); break;