Java 调用 FFMPEG 命令时用 url 作为输入源,Linux 下出现 “no such file or directory” 问题的解决
2013-04-28 15:27
1096 查看
Windows 下执行 ffmpeg 命令,
D:/tools/ffmpeg/bin>ffmpeg.exe -i "某视频文件下载URL" -f flv D:/1.flv
可以成功直接将下载链接输入源转为 1.flv。
可以进行成功调用。
Linux 下执行 ffmpeg 命令,
/usr/local/ffmpeg/bin/ffmpeg -i "某视频文件下载URL" -f flv /usr/userfile/ffmpeg/tempfile/1.flv
也可以成功直接将下载链接输入源转为 1.flv。
FFmpeg 会报错:
No such file or directory:"某视频文件下载URL"。
stackoverflow 上有人遇到了类似的问题:
FFMPEG “no such file or directory” on Android
I am trying to use the ffmpeg binary and call it via a native linux command in android. Most of the commands work fine but the problem is that when i need to pass an http url as an input to the -i option i get "No such file or directory" for the url.
The url however is existing and running the SAME command on a mac does the job as expected.
但最终没人给出正确的解决方案。
为什么 terminal 执行正常的同一条命令行语句,Java 调用就挂了呢?看来 Java 并没有将程序员的意图良好地转达给底层。
笔者经过多次测试,终于找到解决办法。既然 terminal 可以成功执行,启动 shell,然后自定义命令行作为参数传递给 shell 解释器。shell 知道如何将程序员的意图转达给底层。使用 sh -c,将自定义 CMD 行作为其参数,最后使用 java.lang.Runtimeexec(String[] cmdarray):
问题迎刃而解。
Runtime.getRuntime().exec(raw2flvCmd);会开启一个子进程,如果当前线程想等待该子进程执行完毕之后再继续往下执行,可以调用 java.lang.Process 的 waitFor() 方法:
当前线程会等待子进程 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 最终完善为:
其中 StreamGobbler 源码为:
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 上有人遇到了类似的问题:
FFMPEG “no such file or directory” on Android
I am trying to use the ffmpeg binary and call it via a native linux command in android. Most of the commands work fine but the problem is that when i need to pass an http url as an input to the -i option i get "No such file or directory" for the url.
The url however is existing and running the SAME command on a mac does the job as expected.
但最终没人给出正确的解决方案。
为什么 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(); } } }最后补充一点,关闭所有的 io 输入/输出以及错误流、调用 Process 的 destroy() 方法关闭子进程。不然程序可能会出现"java.io.IOException: error=24, Too many open files"。
相关文章推荐
- 执行文件下载Java 调用 FFMPEG 命令时用 url 作为输入源,Linux 下出现 “no such file or directory” 问题的解决
- Java 调用 FFMPEG 命令时用 url 作为输入源,Linux 下出现 “no such file or directory” 问题的解决
- Python调用SIFT出现的问题:No such file or directory: '*.sift' 解决办法,超好用
- 解决“运行arm-linux-gcc命令,提示No such file or directory”的问题
- 解决“运行arm-linux-gcc命令,提示No such file or directory”的问题
- 解决“运行arm-linux-gcc命令,提示No such file or directory”的问题
- cloudera-scm-server启动时出现Caused by: java.io.FileNotFoundException: /var/lib/cloudera-scm-server/.keystore (No such file or directory)问题解决方法(图文详解)
- 出现arm-none-linux-gnueabi-gcc: No such file or directory的解决方法
- Linux执行.sh文件,提示No such file or directory的问题的解决方法
- linux终端出现bash: setup.bash: No such file or directory,和.bashrc文件的问题
- Linux执行.sh文件,提示No such file or directory的问题的解决方法
- Qt 5 在Windows下 出现QApplication: No such file or directory 问题的解决办法
- 在android系统命令行中执行arm linux程序,出现/system/bin/sh: .xxx No such file or directory问题
- 如何恢复误删除的rpm包命令解决-bash: /usr/bin/yum: No such file or directory的问题
- 解决ubuntu下Android Studio出现“aapt” IOException error=2, No such file or directory问题
- (转)解决Linux:cannot open shared object file: No such file or directory 类似问题
- 出现fatal error: pulse/pulseaudio.h: No such file or directory问题解决
- 【Linux】执行shell脚本出现异常:bad interpreter: No such file or directory如何解决
- QT5.0.1在WIN7下 出现QApplication: No such file or directory 问题的解决办法
- QT5.5.0在Windows7(64bit)下 出现QApplication: No such file or directory 问题的解决办法