本篇文章朋友在广东吃饭的时候突然想到的...近期就有想写几篇关于执行文件下载的笔记,所以回家到后之就奋笔疾书的写出来发表了
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 上有人遇到了类似的问题:
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();
}
}
}
文章结束给大家分享下程序员的一些笑话语录: 警告 有一个小伙子在一个办公大楼的门口抽着烟,一个妇女路过他身边,并对他 说, “你知道不知道这个东西会危害你的健康?我是说, 你有没有注意到香烟 盒上的那个警告(Warning)?” 小伙子说,“没事儿,我是一个程序员”。 那妇女说,“这又怎样?” 程序员说,“我们从来不关心 Warning,只关心 Error” |