一、背景
最近項目中遇到需要將.webm視頻進行剪輯並合並的需求,系統為ubuntu。開始嘗試使用ffmpeg,在java中調用指令剪輯已存在的問題沒有問題,但將剪輯後的文件拼接起來的時候ffmpeg會報文件不存在的錯誤,暫時無法解,所以後來換成了mencoder。
二、指令調用
首先,定義執行命令方法。
/** * 系統執行指定控制臺命令 */ public static boolean commandExecution(String command) throws Exception { logger.info("執行指令 " + command); boolean flg = true; try { Process proc = Runtime.getRuntime().exec(command); DriverThreadPool.clearStream(proc.getInputStream()); DriverThreadPool.clearStream(proc.getErrorStream()); if (proc.waitFor() != 0) { if (proc.exitValue() != 0) { logger.info("指令執行失敗" + command); flg = false; } } } catch (Exception e) { flg = false; throw e; } return flg; }
其中 Runtime.getRuntime().exec()方法如果要等待系統執行完指令再繼續運行需要調用proc.waitFor()方法。
而waitFor()方法中需要注意一個坑,在exec()執行後,java會為這個系統指令創建三個流:標准輸入流、標准輸出流和標准錯誤流,執行指令的過程中系統會不斷向輸入流和錯誤流寫數據,如果不及時處理這兩個流,可能會使得流的緩存區暫滿而主線程阻塞。
嘗試過在主線程內直接循環讀取流,發現執行mencoder命令後依然會造成阻塞,所以後來使用兩個線程單獨讀取輸入流和錯誤流解决了問題,但這裏注意在程序結束的時候需要吧線程池關閉掉,否則這兩個線程依然會不斷讀取。
/** * 流處理 */ public static void clearStream(InputStream stream) { // 處理buffer的線程 executor.execute(() -> { String line = null; try (BufferedReader in = new BufferedReader(new InputStreamReader(stream));) { while ((line = in.readLine()) != null) { logger.info(line); } } catch (Exception e) { logger.error(line); } }); }
三、安裝mencoder與webm格式的相關編碼庫
在ubuntu執行指令如下:
sudo apt-get update sudo apt-get install mencoder sudo apt-get install libavformat-dev // mencoder中lavf的支持庫 sudo apt install libvpx-dev // webm格式編碼VP80的支出庫
隨後java中調用指令如下:
mencoder -ovc copy -oac copy source.webm -o target.webm -of lavf -lavfopts format=webm -lavcopts acodec=vorbis:vcodec=libvpx -ffourcc VP80 -ss 00:10 -endpos 00:20
-ovc copy -oac COPY錶示音頻源和視屏源使用源視頻格式,-o錶示複制目標,-of lavf錶示使用lavf庫,format=webm -lavcopts acodec=vorbis:vcodec=libvpx錶示指定web格式,-ffourcc VP80錶示使用VP80編碼,-ss 00:10 -endpos 00:20錶示截取source.webm的10秒到20秒,然後輸出到target.webm。
進行了幾個視頻的剪輯後,需要將多個視頻進行合並。
mencoder -ovc copy -oac copy source1.webm source2.webm source3.webm -o target.webm -of lavf -lavfopts format=webm -lavcopts acodec=vorbis:vcodec=libvpx -ffourcc VP80
將多個原視頻用空格隔開即可。