執行文件下載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”


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM