Reputation: 5001
I am trying to invoke a shell command through Java code following the instructions of Mkyong. My code is :
public class ExecuteShellCommand {
public static void main(){
String absolutePath = "/home/marievi/Downloads/small.mp4";
String command = "ffmpeg -i " + absolutePath;
ExecuteShellCommand obj = new ExecuteShellCommand();
String output = obj.executeCommand(command);
System.out.println(output);
}
public String executeCommand(String command) {
StringBuffer output = new StringBuffer();
Process p;
try {
p = Runtime.getRuntime().exec(command);
p.waitFor();
BufferedReader reader =
new BufferedReader(new InputStreamReader(p.getInputStream()));
String line = "";
while ((line = reader.readLine()) != null) {
output.append(line + "\n");
}
} catch (Exception e) {
e.printStackTrace();
}
return output.toString();
}
}
but I get an empty output, and only a newline is printed. However, when I run the code with Mkyong's example :
public static void main(){
ExecuteShellCommand obj = new ExecuteShellCommand();
String domainName = "google.com";
String command = "ping -c 3 " + domainName;
String output = obj.executeCommand(command);
System.out.println(output);
}
output is printed. Any idea what is going wrong? When I directly execute the command :
ffmpeg -i /home/marievi/Downloads/small.mp4
from the command line, I get the desired output :
ffmpeg version 3.3.4-1~14.04.york1 Copyright (c) 2000-2017 the FFmpeg developers
built with gcc 4.8 (Ubuntu 4.8.4-2ubuntu1~14.04.3)
configuration: --prefix=/usr --extra-version='1~14.04.york1' --toolchain=hardened --libdir=/usr/lib/x86_64-linux-gnu --incdir=/usr/include/x86_64-linux-gnu --enable-gpl --disable-stripping --enable-avresample --enable-avisynth --enable-gnutls --enable-ladspa --enable-libass --enable-libbluray --enable-libbs2b --enable-libcaca --enable-libcdio --enable-libflite --enable-libfontconfig --enable-libfreetype --enable-libfribidi --enable-libgme --enable-libgsm --enable-libmp3lame --enable-libopenjpeg --enable-libmodplug --enable-libopus --enable-libpulse --enable-librubberband --enable-libshine --enable-libsnappy --enable-libsoxr --enable-libspeex --enable-libssh --enable-libtheora --enable-libtwolame --enable-libvorbis --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx265 --enable-libxvid --enable-libzmq --enable-libzvbi --enable-omx --enable-openal --enable-opengl --enable-sdl2 --enable-libdc1394 --enable-libiec61883 --enable-chromaprint --enable-frei0r --enable-libopencv --enable-libx264 --enable-shared
libavutil 55. 58.100 / 55. 58.100
libavcodec 57. 89.100 / 57. 89.100
libavformat 57. 71.100 / 57. 71.100
libavdevice 57. 6.100 / 57. 6.100
libavfilter 6. 82.100 / 6. 82.100
libavresample 3. 5. 0 / 3. 5. 0
libswscale 4. 6.100 / 4. 6.100
libswresample 2. 7.100 / 2. 7.100
libpostproc 54. 5.100 / 54. 5.100
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from '/home/maxez/Downloads/small.mp4':
Metadata:
major_brand : mp42
minor_version : 0
compatible_brands: mp42isomavc1
creation_time : 2010-03-20T21:29:11.000000Z
encoder : HandBrake 0.9.4 2009112300
Duration: 00:00:05.57, start: 0.000000, bitrate: 551 kb/s
Stream #0:0(und): Video: h264 (Constrained Baseline) (avc1 / 0x31637661), yuv420p(tv, bt709), 560x320, 465 kb/s, 30 fps, 30 tbr, 90k tbn, 60 tbc (default)
Metadata:
creation_time : 2010-03-20T21:29:11.000000Z
encoder : JVT/AVC Coding
Stream #0:1(eng): Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, mono, fltp, 83 kb/s (default)
Metadata:
creation_time : 2010-03-20T21:29:11.000000Z
Upvotes: 1
Views: 422
Reputation: 44308
Do yourself a favor and avoid relying on mkyong.com. That site just regurgitates things you can easily find in public documentation, with no regard to how bad or stale its advice is, or how obsolete the information is.
Indeed, Runtime.exec has been obsolete for the last thirteen years. Its replacement, introduced way back in Java 5, is ProcessBuilder. By using ProcessBuilder, you can allow the error output of the external process to be shown in the same place as your Java program’s error output. Currently, you are not showing it anywhere, so there’s no way to know what went wrong.
Similarly, StringBuffer is obsolete and very old; its replacement is StringBuilder. They are identical except that StringBuffer has the extra overhead of thread safety, which is rarely useful.
Also, waitFor()
waits for the process to end. Obviously, then, you should not be calling it before you have read the output of the process. Call it after you have read all lines of output.
Finally, an exception means “the operation did not succeed, and you should not continue as if it did succeed.” If you get an exception, your process did not succeed. Since reading the output of the process is fundamental to what you’re trying to do, it does not make sense to continue. Instead, wrap any caught exception in an unchecked exception, like RuntimeException. (An even better choice would be removing the try/catch entirely, and adding those exception types to the throws
clause your executeCommand and main methods.)
public static void main() {
String absolutePath = "/home/marievi/Downloads/small.mp4";
String[] command = { "ffmpeg", "-i", absolutePath };
ExecuteShellCommand obj = new ExecuteShellCommand();
String output = obj.executeCommand(command);
System.out.println(output);
}
public String executeCommand(String[] command) {
StringBuilder output = new StringBuilder();
try {
ProcessBuilder builder = new ProcessBuilder(command);
// Share standard input/output/error descriptors with Java process...
builder.inheritIO();
// ... except standard output, so we can read it with getInputStream().
builder.redirectOutput(ProcessBuilder.Redirect.PIPE);
Process p = builder.start();
try (BufferedReader reader =
new BufferedReader(new InputStreamReader(p.getInputStream()))) {
String line = "";
while ((line = reader.readLine()) != null) {
output.append(line + "\n");
}
}
p.waitFor();
} catch (IOException | InterruptedException e) {
// Process failed; do not attempt to continue!
throw new RuntimeException(e);
}
return output.toString();
}
Upvotes: 3
Reputation: 300
There is nothing wrong with your code. Only ffmpeg writes to stderr instead of stdout.
You can make it work by replacing getInputStream() with getErrorStream().
Upvotes: 1