本篇文章朋友在广东吃饭的时候突然想到的...近期就有想写几篇关于执行文件下载的笔记,所以回家到后之就奋笔疾书的写出来发表了
Windows 下执行 ffmpeg 命令,
D:/tools/ffmpeg/bin>ffmpeg.exe -i "某视频文件载下URL" -f flv D:/1.flv
可以胜利直接将载下链接入输源转为 1.flv。
String raw2flvCmd = "D:/tools/ffmpeg/bin/ffmpeg.exe -i \"某视频文件载下URL\" -f flv 1.flv"; Runtime.getRuntime().exec(raw2flvCmd);
可以停止胜利调用。
Linux 下执行 ffmpeg 命令,
/usr/local/ffmpeg/bin/ffmpeg -i "某视频文件载下URL" -f flv /usr/userfile/ffmpeg/tempfile/1.flv
也可以胜利直接将载下链接入输源转为 1.flv。
String raw2flvCmd = "/usr/local/ffmpeg/bin/ffmpeg -i \"某视频文件载下URL\" -f flv /usr/userfile/ffmpeg/tempfile/1.flv"; Runtime.getRuntime().exec(raw2flvCmd);
FFmpeg 会报错:
No such file or directory:"某视频文件载下URL"。
stackoverflow 上有人遇到了类似的问题:
但终究没人给出准确的解决方案。
为什么 terminal 执行常正的统一条命令行语句,Java 调用就挂了呢?看来 Java 并没有将程序员的意图精良地达转给底层。
笔者经过多次测试,于终找到解决办法。既然 terminal 可以胜利执行,动启 shell,然后自定义命令行作为数参传递给 shell 解释器。shell 道知如何将程序员的意图达转给底层。用使 sh -c,将自定义 CMD 行作为其数参,最后用使 java.lang.Runtimeexec(String[] cmdarray):
String raw2flvCmd = "/usr/local/ffmpeg/bin/ffmpeg -i \"某视频文件载下URL\" -f flv /usr/userfile/ffmpeg/tempfile/1.flv"; Runtime.getRuntime().exec(new String[]{"sh","-c",raw2flvCmd});
问题解而刃迎。
Runtime.getRuntime().exec(raw2flvCmd);会开启一个子程进,如果以后线程想待等该子程进执行终了后之再继承往下执行,可以调用 java.lang.Process 的 waitFor() 法方:
Process process = null; try { String raw2flvCmd = "/usr/local/ffmpeg/bin/ffmpeg -i \"某视频文件载下URL\" -f flv /usr/userfile/ffmpeg/tempfile/1.flv"; process = Runtime.getRuntime().exec(new String[]{"sh","-c",raw2flvCmd}); process.waitFor(); } catch (Exception e) { //do some thing }
以后线程会待等子程进 process 执行结束,然后继承往下执行。
值得注意的一点是,ffmpeg 程进在执行时,会生产量大出输信息,如果我们没有实时将流出输的话,放存这些信息的缓存会很快填满,后之该程进待等我们将这些信息出输,然而我们也在待等该程进执行结束(process.waitFor();很明显 process 不会结束因为它也在待等我们),于是一个很经典的死锁案例就此生产。
种这况情表现为我们的子程进阻塞住了,而我们动启该子程进的线程由于始终没有拿到 waitFor() 的回返也就此止步于那条语句。
所以我们要需不断地从该子程进中的 input stream 中读出数据以确保它不会阻塞。
When Runtime.exec() won't
Navigate yourself around pitfalls related to the Runtime.exec() method
这篇文章对此停止了深入分析,并给出了推荐解决方案。我们根据该文将我们 Linux 下的 Java 调用 FFmpeg 终究完善为:
Process process = null; try { String raw2flvCmd = "/usr/local/ffmpeg/bin/ffmpeg -i \"某视频文件载下URL\" -f flv /usr/userfile/ffmpeg/tempfile/1.flv"; process = Runtime.getRuntime().exec(new String[]{"sh","-c",raw2flvCmd}); StreamGobbler errorGobbler = new StreamGobbler(process.getErrorStream(), "ERROR"); errorGobbler.start();// kick off stderr StreamGobbler outGobbler = new StreamGobbler(process.getInputStream(), "STDOUT"); outGobbler.start();// kick off stdout process.waitFor(); } catch (Exception e) { //do some thing }
其中 StreamGobbler 源码为:
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.PrintWriter; public class StreamGobbler extends Thread { InputStream is; String type; OutputStream os; public StreamGobbler(InputStream is, String type) { this(is, type, null); } public StreamGobbler(InputStream is, String type, OutputStream redirect) { this.is = is; this.type = type; this.os = redirect; } @Override public void run() { try { PrintWriter pw = null; if (os != null) pw = new PrintWriter(os); InputStreamReader isr = new InputStreamReader(is); BufferedReader br = new BufferedReader(isr); String line = null; while ((line = br.readLine()) != null) { if (pw != null) pw.println(line); System.out.println(type + ">" + line); } if (pw != null) pw.flush(); } catch (IOException ioe) { ioe.printStackTrace(); } } }
文章结束给大家分享下程序员的一些笑话语录: 警告
有一个小伙子在一个办公大楼的门口抽着烟,一个妇女路过他身边,并对他 说, “你知道不知道这个东西会危害你的健康?我是说, 你有没有注意到香烟 盒上的那个警告(Warning)?”
小伙子说,“没事儿,我是一个程序员”。
那妇女说,“这又怎样?”
程序员说,“我们从来不关心 Warning,只关心 Error”