41

I have an application, running on the Playframework, which needs to encode some video files. I used

Process pr = Runtime.getRuntime().exec(execCode)

for this (and it works perfectly), but as I need both, the output stream and the error stream, I am trying to use ProcessBuilder (as is also recommended).

But I cannot get it to work (testing on a MacBook). Is there a fundamental difference between the Runtime method and the ProcessBuilder?

This is my code for ProcessBuilder (exactly the same code works when replaced by Runtime.getRuntime().exec())

    String execCode = "/opt/local/bin/ffmpeg -i file [...]"; 
    ProcessBuilder pb = new ProcessBuilder(execCode);
    pb.redirectErrorStream(true);
    pb.directory(new File("/Users/[...]/data/"));
    Process pr = pb.start();

This is the console output:

11:00:18,277 ERROR ~ There was a problem with with processing MediaFile[13] with error Error during coding process: Cannot run program "/opt/local/bin/ffmpeg -i /Users/[...]/data/media/1/1/test.mov [...] /Users/[...]/data/media/1/13/encoded.mp3" (in directory "/Users/[...]/data"): error=2, No such file or directory
java.lang.Exception: Error during coding process: Cannot run program "/opt/local/bin/ffmpeg -i /Users/Luuk/Documents/Java/idoms-server/data/media/1/1/test.mov -y -f mpegts -acodec libmp3lame -ar 48000 -b:a 64000 -vn -flags +loop -cmp +chroma -partitions +parti4x4+partp8x8+partb8x8 -subq 5 -trellis 1 -refs 1 -coder 0 -me_range 16 -keyint_min 25 -sc_threshold 40 -i_qfactor 0.71 -bt 200k -maxrate -1 -bufsize -1 -rc_eq 'blurCplx^(1-qComp)' -qcomp 0.6 -qmin 10 -qmax 51 -qdiff 4 -level 30  -g 30 -async 2 /Users/Luuk/Documents/Java/idoms-server/data/media/1/13/encoded.mp3" (in directory "/Users/Luuk/Documents/Java/idoms-server/data"): error=2, No such file or directory
    at logic.server.MediaCoder.encodeMediaFile(MediaCoder.java:313)
    at logic.server.MediaCoder.doJob(MediaCoder.java:54)
    at play.jobs.Job.doJobWithResult(Job.java:50)
    at play.jobs.Job.call(Job.java:146)
    at play.jobs.Job$1.call(Job.java:66)
    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
    at java.util.concurrent.FutureTask.run(FutureTask.java:138)
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:98)
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:206)
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
    at java.lang.Thread.run(Thread.java:680)
Caused by: java.io.IOException: Cannot run program "/opt/local/bin/ffmpeg -i /Users/Luuk/Documents/Java/idoms-server/data/media/1/1/test.mov -y -f mpegts -acodec libmp3lame -ar 48000 -b:a 64000 -vn -flags +loop -cmp +chroma -partitions +parti4x4+partp8x8+partb8x8 -subq 5 -trellis 1 -refs 1 -coder 0 -me_range 16 -keyint_min 25 -sc_threshold 40 -i_qfactor 0.71 -bt 200k -maxrate -1 -bufsize -1 -rc_eq 'blurCplx^(1-qComp)' -qcomp 0.6 -qmin 10 -qmax 51 -qdiff 4 -level 30  -g 30 -async 2 /Users/Luuk/Documents/Java/idoms-server/data/media/1/13/encoded.mp3" (in directory "/Users/Luuk/Documents/Java/idoms-server/data"): error=2, No such file or directory
    at java.lang.ProcessBuilder.start(ProcessBuilder.java:460)
    at logic.server.MediaCoder.encodeMediaFile(MediaCoder.java:189)
    ... 11 more
Caused by: java.io.IOException: error=2, No such file or directory
    at java.lang.UNIXProcess.forkAndExec(Native Method)
    at java.lang.UNIXProcess.<init>(UNIXProcess.java:53)
    at java.lang.ProcessImpl.start(ProcessImpl.java:91)
    at java.lang.ProcessBuilder.start(ProcessBuilder.java:453)
    ... 12 more
Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
Luuk D. Jansen
  • 4,402
  • 8
  • 47
  • 90

2 Answers2

84

You need to specify the arguments as separate Strings:

new ProcessBuilder("cmd", "arg1", "arg2", ...);

The constructor accepts String, varargs, and List<String>.

See ProcessBuilder documentation.

jhamm
  • 24,124
  • 39
  • 105
  • 179
Neet
  • 3,937
  • 15
  • 18
  • also I cant find `FSTL` on that list – SSpoke Sep 23 '15 at 00:14
  • 1
    Thank you for the solution. Saved me from stress. – Mohit Jan 23 '16 at 15:32
  • 1
    Same problem with ffmpeg as well, this saved my day; if command is the command you would use with exec(), a simple command.split(" ") should do the trick – Riccardo Cossu Feb 05 '16 at 10:25
  • 1
    If the constructor accepts a string, why do we need to specify the arguments as separate Strings (varargs) ? – Alan Evangelista Jul 15 '21 at 22:37
  • 1
    @RiccardoCossu command.split(" ") does not always work where the command has a string argument that has spaces. Something like `sh talk.sh "Hello World"` will break the String "Hello World" into pieces. – lordvidex Mar 27 '22 at 14:18
1

If you don't want to break your commands into tokens everytime, you could try

new ProcessBuilder("sh", "-c", execCode); // Linux / Unix terminal

OR

new ProcessBuilder("cmd", "/c", execCode); // Windows command line
lordvidex
  • 3,581
  • 3
  • 17
  • 25