执行文件下载Java 调用 FFMPEG 命令时用 url 作为输入源,Linux 下出现 “no such file or directory” 问题的解决

本篇文章朋友在广东吃饭的时候突然想到的...近期就有想写几篇关于执行文件下载的笔记,所以回家到后之就奋笔疾书的写出来发表了

        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”

原文地址:https://www.cnblogs.com/xinyuyuanm/p/3049950.html