本篇文章朋友在廣東吃飯的時候突然想到的...近期就有想寫幾篇關於執行文件下載的筆記,所以回家到后之就奮筆疾書的寫出來發表了
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 上有人遇到了類似的問題:
但終究沒人給出准確的解決方案。
為什么 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”