From e86783648f925c4dd77ee22a23ee75391c105743 Mon Sep 17 00:00:00 2001 From: MatthewWhitaker Date: Tue, 26 Jun 2018 20:17:41 -0600 Subject: [PATCH] Added the ability to execute FFmpeg and FFprobe synchronously --- .../nl/bravobit/ffmpeg/FFbinaryInterface.java | 17 ++++ .../ffmpeg/FFcommandExecuteSynchronous.java | 78 +++++++++++++++++++ .../main/java/nl/bravobit/ffmpeg/FFmpeg.java | 17 ++++ .../main/java/nl/bravobit/ffmpeg/FFprobe.java | 17 ++++ .../ffmpeg/example/ExampleActivity.java | 12 +++ 5 files changed, 141 insertions(+) create mode 100644 android-ffmpeg/src/main/java/nl/bravobit/ffmpeg/FFcommandExecuteSynchronous.java diff --git a/android-ffmpeg/src/main/java/nl/bravobit/ffmpeg/FFbinaryInterface.java b/android-ffmpeg/src/main/java/nl/bravobit/ffmpeg/FFbinaryInterface.java index 7e57b80..f2e00ed 100644 --- a/android-ffmpeg/src/main/java/nl/bravobit/ffmpeg/FFbinaryInterface.java +++ b/android-ffmpeg/src/main/java/nl/bravobit/ffmpeg/FFbinaryInterface.java @@ -23,6 +23,23 @@ interface FFbinaryInterface { */ FFtask execute(String[] cmd, FFcommandExecuteResponseHandler ffcommandExecuteResponseHandler); + /** + * Executes a command synchronously + * + * @param environmentVars Environment variables + * @param cmd command to execute + * @return The output of the command + */ + String execute(Map environmentVars, String[] cmd); + + /** + * Executes a command synchronously + * + * @param cmd command to execute + * @return The output of the command + */ + String execute(String[] cmd); + /** * Checks if FF binary is supported on this device * diff --git a/android-ffmpeg/src/main/java/nl/bravobit/ffmpeg/FFcommandExecuteSynchronous.java b/android-ffmpeg/src/main/java/nl/bravobit/ffmpeg/FFcommandExecuteSynchronous.java new file mode 100644 index 0000000..89b912e --- /dev/null +++ b/android-ffmpeg/src/main/java/nl/bravobit/ffmpeg/FFcommandExecuteSynchronous.java @@ -0,0 +1,78 @@ +package nl.bravobit.ffmpeg; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.Map; +import java.util.concurrent.TimeoutException; + +public class FFcommandExecuteSynchronous { + + private final String[] cmd; + private Map environment; + private final ShellCommand shellCommand; + private final long timeout; + private long startTime; + private Process process; + private String output = ""; + + FFcommandExecuteSynchronous(String[] cmd, Map environment, long timeout) { + this.cmd = cmd; + this.timeout = timeout; + this.environment = environment; + this.shellCommand = new ShellCommand(); + } + + private CommandResult runCommand() { + startTime = System.currentTimeMillis(); + try { + process = shellCommand.run(cmd, environment); + if (process == null) { + return CommandResult.getDummyFailureResponse(); + } + Log.d("Running publishing updates method"); + checkAndUpdateProcess(); + return CommandResult.getOutputFromProcess(process); + } catch (TimeoutException e) { + Log.e("FFmpeg binary timed out", e); + return new CommandResult(false, e.getMessage()); + } catch (Exception e) { + Log.e("Error running FFmpeg binary", e); + } finally { + Util.destroyProcess(process); + } + return CommandResult.getDummyFailureResponse(); + } + + public String execute() { + CommandResult commandResult = runCommand(); + output += commandResult.output; + return output; + } + + private void checkAndUpdateProcess() throws TimeoutException { + while (!Util.isProcessCompleted(process)) { + + // checking if process is completed + if (Util.isProcessCompleted(process)) { + return; + } + + // Handling timeout + if (timeout != Long.MAX_VALUE && System.currentTimeMillis() > startTime + timeout) { + throw new TimeoutException("FFmpeg binary timed out"); + } + + try { + String line; + BufferedReader reader = new BufferedReader(new InputStreamReader(process.getErrorStream())); + while ((line = reader.readLine()) != null) { + output += line + "\n"; + } + } catch (IOException e) { + e.printStackTrace(); + } + } + } + +} diff --git a/android-ffmpeg/src/main/java/nl/bravobit/ffmpeg/FFmpeg.java b/android-ffmpeg/src/main/java/nl/bravobit/ffmpeg/FFmpeg.java index 0adb87e..b33aa40 100644 --- a/android-ffmpeg/src/main/java/nl/bravobit/ffmpeg/FFmpeg.java +++ b/android-ffmpeg/src/main/java/nl/bravobit/ffmpeg/FFmpeg.java @@ -138,6 +138,23 @@ public FFtask execute(String[] cmd, FFcommandExecuteResponseHandler ffmpegExecut return execute(null, cmd, ffmpegExecuteResponseHandler); } + @Override + public String execute(Map environmentVars, String[] cmd) { + if (cmd.length != 0) { + String[] ffmpegBinary = new String[]{FileUtils.getFFmpeg(context.provide()).getAbsolutePath()}; + String[] command = concatenate(ffmpegBinary, cmd); + FFcommandExecuteSynchronous synchronous = new FFcommandExecuteSynchronous(command, environmentVars, timeout); + return synchronous.execute(); + } else { + throw new IllegalArgumentException("shell command cannot be empty"); + } + } + + @Override + public String execute(String[] cmd) { + return execute(null, cmd); + } + @Override public boolean isCommandRunning(FFtask task) { return task != null && !task.isProcessCompleted(); diff --git a/android-ffmpeg/src/main/java/nl/bravobit/ffmpeg/FFprobe.java b/android-ffmpeg/src/main/java/nl/bravobit/ffmpeg/FFprobe.java index b1002d2..3ccbf45 100644 --- a/android-ffmpeg/src/main/java/nl/bravobit/ffmpeg/FFprobe.java +++ b/android-ffmpeg/src/main/java/nl/bravobit/ffmpeg/FFprobe.java @@ -138,6 +138,23 @@ public FFtask execute(String[] cmd, FFcommandExecuteResponseHandler ffcommandExe return execute(null, cmd, ffcommandExecuteResponseHandler); } + @Override + public String execute(Map environmentVars, String[] cmd) { + if (cmd.length != 0) { + String[] ffprobeBinary = new String[]{FileUtils.getFFprobe(context.provide()).getAbsolutePath()}; + String[] command = concatenate(ffprobeBinary, cmd); + FFcommandExecuteSynchronous synchronous = new FFcommandExecuteSynchronous(command, environmentVars, timeout); + return synchronous.execute(); + } else { + throw new IllegalArgumentException("shell command cannot be empty"); + } + } + + @Override + public String execute(String[] cmd) { + return execute(null, cmd); + } + public boolean isCommandRunning(FFtask task) { return task != null && !task.isProcessCompleted(); } diff --git a/sample/src/main/java/nl/bravobit/ffmpeg/example/ExampleActivity.java b/sample/src/main/java/nl/bravobit/ffmpeg/example/ExampleActivity.java index 4a747c3..62b7ed3 100644 --- a/sample/src/main/java/nl/bravobit/ffmpeg/example/ExampleActivity.java +++ b/sample/src/main/java/nl/bravobit/ffmpeg/example/ExampleActivity.java @@ -24,6 +24,7 @@ public void onCreate(Bundle savedInstanceState) { // ffmpeg is supported versionFFmpeg(); //ffmpegTestTaskQuit(); + synchronousVersionFFmpeg(); } else { // ffmpeg is not supported Timber.e("ffmpeg not supported!"); @@ -32,6 +33,7 @@ public void onCreate(Bundle savedInstanceState) { if (FFprobe.getInstance(this).isSupported()) { // ffprobe is supported versionFFprobe(); + synchronousVersionFFprobe(); } else { // ffprobe is not supported Timber.e("ffprobe not supported!"); @@ -69,6 +71,16 @@ public void onProgress(String message) { }); } + private void synchronousVersionFFmpeg() { + Timber.d("version ffmpeg synchronous"); + Timber.d(FFmpeg.getInstance(this).execute(new String[]{"-version"})); + } + + private void synchronousVersionFFprobe() { + Timber.d("version ffprobe synchronous"); + Timber.d(FFprobe.getInstance(this).execute(new String[]{"-version"})); + } + private void ffmpegTestTaskQuit() { String[] command = {"-i", "input.mp4", "output.mov"};