• 执行文件下载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”

  • 相关阅读:
    jar包和war包的区别:
    tail
    redis
    查看Linux操作系统版本
    CentOS 7.0 systemd代替service
    周刊(三月最后一期)
    周刊第四期
    周刊第三期
    周刊第二期
    周刊(第一期)
  • 原文地址:https://www.cnblogs.com/xinyuyuanm/p/3049950.html
Copyright © 2020-2023  润新知