1. 程式人生 > 程式設計 >java使用FFmpeg合成視訊和音訊並獲取視訊中的音訊等操作(例項程式碼詳解)

java使用FFmpeg合成視訊和音訊並獲取視訊中的音訊等操作(例項程式碼詳解)

FFmpeg是一套可以用來記錄、轉換數字音訊、視訊,並能將其轉化為流的開源計算機程式。

ffmpeg命令引數如下:

java使用FFmpeg合成視訊和音訊並獲取視訊中的音訊等操作(例項程式碼詳解)

通用選項

-L license
-h 幫助
-fromats 顯示可用的格式,編解碼的,協議的。。。
-f fmt 強迫採用格式fmt
-I filename 輸入檔案
-y 覆蓋輸出檔案
-t duration 設定紀錄時間 hh:mm:ss[.xxx]格式的記錄時間也支援
-ss position 搜尋到指定的時間 [-]hh:mm:ss[.xxx]的格式也支援
-title string 設定標題
-author string 設定作者
-copyright string 設定版權

-comment string 設定評論
-target type 設定目標檔案型別(vcd,svcd,dvd) 所有的格式選項(位元率,編解碼以及緩衝區大小)自動設定 ,只需要輸入如下的就可以了:
ffmpeg -i myfile.avi -target vcd /tmp/vcd.mpg
-hq 啟用高質量設定
-itsoffset offset 設定以秒為基準的時間偏移,該選項影響所有後面的輸入檔案。該偏移被加到輸入檔案的時戳,定義一個正偏移意味著相應的流被延遲了 offset秒。 [-]hh:mm:ss[.xxx]的格式也支援

視訊選項

-b bitrate 設定位元率,預設200kb/s
-r fps 設定幀頻 預設25

-s size 設定幀大小 格式為WXH 預設160X128.下面的簡寫也可以直接使用:
Sqcif 128X96 qcif 176X144 cif 252X288 4cif 704X576
-aspect aspect 設定橫縱比 4:3 16:9 或 1.3333 1.7777
-croptop size 設定頂部切除帶大小 畫素單位
-cropbottom size –cropleft size –cropright size
-padtop size 設定頂部補齊的大小 畫素單位
-padbottom size –padleft size –padright size –padcolor color 設定補齊條顏色(hex,6個16進位制的數,紅:綠:蘭排列,比如 000000代表黑色)
-vn 不做視訊記錄
-bt tolerance 設定視訊位元速率容忍度kbit/s
-maxrate bitrate設定最大視訊位元速率容忍度
-minrate bitreate 設定最小視訊位元速率容忍度
-bufsize size 設定位元速率控制緩衝區大小
-vcodec codec 強制使用codec編解碼方式。 如果用copy表示原始編解碼資料必須被拷貝。
-sameq 使用同樣視訊質量作為源(VBR)
-pass n 選擇處理遍數(1或者2)。兩遍編碼非常有用。第一遍生成統計資訊,第二遍生成精確的請求的位元速率
-passlogfile file 選擇兩遍的紀錄檔名為file

高階選項

-g gop_size 設定影象組大小
-intra 僅適用幀內編碼
-qscale q 使用固定的視訊量化標度(VBR)
-qmin q 最小視訊量化標度(VBR)
-qmax q 最大視訊量化標度(VBR)
-qdiff q 量化標度間最大偏差 (VBR)
-qblur blur 視訊量化標度柔化(VBR)
-qcomp compression 視訊量化標度壓縮(VBR)
-rc_init_cplx complexity 一遍編碼的初始複雜度
-b_qfactor factor 在p和b幀間的qp因子
-i_qfactor factor 在p和i幀間的qp因子
-b_qoffset offset 在p和b幀間的qp偏差
-i_qoffset offset 在p和i幀間的qp偏差
-rc_eq equation 設定位元速率控制方程 預設tex^qComp
-rc_override override 特定間隔下的速率控制過載
-me method 設定運動估計的方法 可用方法有 zero phods log x1 epzs(預設) full
-dct_algo algo 設定dct的演算法 可用的有 0 FF_DCT_AUTO 預設的DCT 1 FF_DCT_FASTINT 2 FF_DCT_INT 3 FF_DCT_MMX 4 FF_DCT_MLIB 5 FF_DCT_ALTIVEC
-idct_algo algo 設定idct演算法。可用的有 0 FF_IDCT_AUTO 預設的IDCT 1 FF_IDCT_INT 2 FF_IDCT_SIMPLE 3 FF_IDCT_SIMPLEMMX 4 FF_IDCT_LIBMPEG2MMX 5 FF_IDCT_PS2 6 FF_IDCT_MLIB 7 FF_IDCT_ARM 8 FF_IDCT_ALTIVEC 9 FF_IDCT_SH4 10 FF_IDCT_SIMPLEARM
-er n 設定錯誤殘留為n 1 FF_ER_CAREFULL 預設 2 FF_ER_COMPLIANT 3 FF_ER_AGGRESSIVE 4 FF_ER_VERY_AGGRESSIVE
-ec bit_mask 設定錯誤掩蔽為bit_mask,該值為如下值的位掩碼 1 FF_EC_GUESS_MVS (default=enabled) 2 FF_EC_DEBLOCK (default=enabled)
-bf frames 使用frames B 幀,支援mpeg1,mpeg2,mpeg4
-mbd mode 巨集塊決策 0 FF_MB_DECISION_SIMPLE 使用mb_cmp 1 FF_MB_DECISION_BITS 2 FF_MB_DECISION_RD
-4mv 使用4個運動向量 僅用於mpeg4
-part 使用資料劃分 僅用於mpeg4
-bug param 繞過沒有被自動監測到編碼器的問題
-strict strictness 跟標準的嚴格性
-aic 使能高階幀內編碼 h263+
-umv 使能無限運動向量 h263+
-deinterlace 不採用交織方法
-interlace 強迫交織法編碼 僅對mpeg2和mpeg4有效。當你的輸入是交織的並且你想要保持交織以最小影象損失的時候採用該選項。可選的方法是不交織,但是損失更大
-psnr 計算壓縮幀的psnr
-vstats 輸出視訊編碼統計到vstats_hhmmss.log
-vhook module 插入視訊處理模組 module 包括了模組名和引數,用空格分開

音訊選項

-ab bitrate 設定音訊位元速率
-ar freq 設定音訊取樣率
-ac channels 設定通道 預設為1
-an 不使能音訊紀錄
-acodec codec 使用codec編解碼

音視訊捕獲選項

-vd device 設定視訊捕獲裝置。比如/dev/video0
-vc channel 設定視訊捕獲通道 DV1394專用
-tvstd standard 設定電視標準 NTSC PAL(SECAM)
-dv1394 設定DV1394捕獲
-av device 設定音訊裝置 比如/dev/dsp

高階選項

-map file:stream 設定輸入流對映
-debug 列印特定除錯資訊
-benchmark 為基準測試加入時間
-hex 傾倒每一個輸入包
-bitexact 僅使用位精確演算法 用於編解碼測試
-ps size 設定包大小,以bits為單位
-re 以本地幀頻讀資料,主要用於模擬捕獲裝置
-loop 迴圈輸入流。只工作於影象流,用於ffserver測試

橫向合併視訊

ffmpeg -i input1.mp4 -i input2.mp4 -lavfi hstack output.mp4

上面的命令雖然可以合併視訊,兩個視訊可以正常播放,但是隻保留了前面一個的音訊。

下面會介紹怎麼避開這個坑。

注意這時候input1和input2必須同樣的高度,如果不一樣的高度可以使用-shortest引數來保證同樣的高度。

如果希望合併多個視訊,可以使用下面命令列。

ffmpeg -i input1.mp4 -i input2.mp4 -i input3.mp4 -lavfi hstack=inputs=3 output.mp4

其中input=3表示希望合併的視訊的個數

縱向合併視訊

ffmpeg -i input1.mp4 -i input2.mp4 -lavfi vstack output.mp4

網格合併視訊

當多個視訊時,還可以合併成網格狀,比如2x2,3x3這種。但是視訊個數不一定需要是偶數,如果是奇數,可以用黑色圖片來佔位。

ffmpeg -f lavfi -i color=c=black:s=1280x720 -vframes 1 black.png

該命令將建立一張1280*720的圖片

然後就可以使用下面這個命令來合併成網格視訊了,如果只有三個視訊,可以選擇上面建立的黑色圖片替代。

ffmpeg -i top_left.mp4 -i top_right.mp4 -i bottom_left.mp4 -i bottom_right.mp4 \
-lavfi "[0:v][1:v]hstack[top];[2:v][3:v]hstack[bottom];[top][bottom]vstack"
-shortest 2by2grid.mp4

上面建立的是正規的2x2網格視訊。想象一下,現在只有三個視訊,我想把第一個視訊擺放在第一行的中間,然後把第二、三個視訊擺放在第二行。那麼就可以使用下面兩個命令了。

ffmpeg -f lavfi -i color=c=black:s=640x720 -vframes 1 black.png

ffmpeg -i black.png -i top_center.mp4 -i bottom_left.mp4 -i bottom_right.mp4
-lavfi "[0:v][1:v][0:v]hstack=inputs=3[top];[2:v][3:v]hstack[bottom];[top][bottom]vstack"
-shortest 3_videos_2x2_grid.mp4

合併音訊和視訊

ffmpeg -i video.mp4 -i audio.wav -c:v copy -c:a aac -strict experimental output.mp4

如果視訊中已經包含了音訊,這個時候還可以替換視訊中的音訊,使用下面命令列。

ffmpeg -i video.mp4 -i audio.wav -c:v copy -c:a aac -strict experimental
-map 0:v:0 -map 1:a:0 output.mp4

合併兩個音訊

ffmpeg -i input1.mp3 -i input2.mp3 -filter_complex amerge -ac 2 -c:a libmp3lame -q:a 4 output.mp3

獲取視訊中的音訊

ffmpeg -i input.mp4 -vn -y -acodec copy output.m4a

去掉視訊中的音訊

ffmpeg -i input.mp4 -an output.mp4

現在介紹,怎麼合併兩個視訊並保留兩個視訊中的音訊。也就是抖音中的合拍功能。
1.合併兩個視訊,但是發現只有一個聲音。無所謂。
2.抽取兩個視訊中的音訊,然後合併成一個音訊。
3.將這個音訊替換到之前的合併視訊中。
4.ok了。
5.可以使用ffplay播放了。

附上java程式碼,可直接使用。使用前需要先將FFmpeg的bin目錄配置在環境變數中。配置完成後,在cmd中拼 ffmpeg -version

如果能ping通說明配置成功,然後直接使用以下程式碼即可成功。

package com.util;
 
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;
 
/**
 * 視訊中獲取音訊檔案
 */
public class VideoUtils {
 //FFmpeg全路徑
 private static final String FFMPEG_PATH = "D:\\666\\ffmpeg-20190730-a0c1970-win64-static\\bin\\ffmpeg.exe";
 //音訊儲存路徑
 private static final String TMP_PATH = "D:\\666";
 
 /**
  * 從視訊中提取音訊資訊
  * @param videoUrl
  * @return
  */
 public static String videoToAudio(String videoUrl){
  String aacFile = "";
  try {
   aacFile = TMP_PATH + "/" + new SimpleDateFormat("yyyyMMddHHmmss").format(new Date())
     + UUID.randomUUID().toString().replaceAll("-","") + ".mp3";
   String command = FFMPEG_PATH + " -i "+ videoUrl + " -vn -acodec copy "+ aacFile;
   System.out.println("video to audio command : " + command);
   Process process = Runtime.getRuntime().exec(command);
   process.waitFor();
  } catch (Exception e) {
   e.printStackTrace();
  }
  return "";
 }
 
 public static void main(String[] args){
 try {
// videoToAudio("D:\\laji\\2.mp4");
 String videoInputPath = "D:\\laji\\aa.mp4";
 String audioInputPath = "D:\\laji\\a.mp3";
 String videoOutPath = "D:\\laji\\bb1.avi";
 convetor(videoInputPath,audioInputPath,videoOutPath);
 } catch (Exception e) {
 e.printStackTrace();
 }
 System.out.println("---------獲取音訊檔案成功!-----------");
 
 }
 /**
  * @param videoInputPath 原視訊的全路徑
  * @param audioInputPath 音訊的全路徑
  * @param videoOutPath 視訊與音訊結合之後的視訊的路徑
  * @throws Exception
  */
 public static void convetor(String videoInputPath,String audioInputPath,String videoOutPath)
   throws Exception {
  Process process = null;
  try {
   String command =FFMPEG_PATH + " -i " + videoInputPath + " -i " + audioInputPath + " -c:v copy -c:a aac -strict experimental " + 
    " -map 0:v:0 -map 1:a:0 "
    + " -y " + videoOutPath;
   process = Runtime.getRuntime().exec(command);
   process.waitFor();
  } catch (IOException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
  // 使用這種方式會在瞬間大量消耗CPU和記憶體等系統資源,所以這裡我們需要對流進行處理
  InputStream errorStream = process.getErrorStream();
  InputStreamReader inputStreamReader = new InputStreamReader(errorStream);
  BufferedReader br = new BufferedReader(inputStreamReader);
 
  String line = "";
  while ((line = br.readLine()) != null) {
  }
  if (br != null) {
   br.close();
  }
  if (inputStreamReader != null) {
   inputStreamReader.close();
  }
  if (errorStream != null) {
   errorStream.close();
  }
 
 }
 
}

總結

到此這篇關於java使用FFmpeg合成視訊和音訊並獲取視訊中的音訊等操作(例項程式碼詳解)的文章就介紹到這了,更多相關java使用FFmpeg合成視訊和音訊內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!