Java自学者论坛

 找回密码
 立即注册

手机号码,快捷登录

恭喜Java自学者论坛(https://www.javazxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,会员资料板块,购买链接:点击进入购买VIP会员

JAVA高级面试进阶训练营视频教程

Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程Go语言视频零基础入门到精通Java架构师3期(课件+源码)
Java开发全终端实战租房项目视频教程SpringBoot2.X入门到高级使用教程大数据培训第六期全套视频教程深度学习(CNN RNN GAN)算法原理Java亿级流量电商系统视频教程
互联网架构师视频教程年薪50万Spark2.0从入门到精通年薪50万!人工智能学习路线教程年薪50万大数据入门到精通学习路线年薪50万机器学习入门到精通教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程MySQL入门到精通教程
查看: 687|回复: 0

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

[复制链接]
  • TA的每日心情
    奋斗
    2024-11-24 15:47
  • 签到天数: 804 天

    [LV.10]以坛为家III

    2053

    主题

    2111

    帖子

    72万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    726782
    发表于 2021-7-10 20:03:57 | 显示全部楼层 |阅读模式

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

            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”

    哎...今天够累的,签到来了1...
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|小黑屋|Java自学者论坛 ( 声明:本站文章及资料整理自互联网,用于Java自学者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2025-2-1 04:00 , Processed in 0.060744 second(s), 29 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表