[java]通過Java,在ubuntu使用mencoder進行webm格式視屏剪輯合併
一、背景
最近專案中遇到需要將.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
將多個原視訊用空格隔開即可。