天天看點

音視訊處理工具FFmpeg與Java結合的簡單使用

作者:音視訊流媒體技術

一、什麼是FFmpeg

FFmpeg是一套可以用來記錄、轉換數字音頻、視訊,并能将其轉化為流的開源計算機程式。采用LGPL或GPL許可證。它提供了錄制、轉換以及流化音視訊的完整解決方案。它包含了非常先進的音頻/視訊編解碼庫libavcodec,為了保證高可移植性和編解碼品質,libavcodec裡很多code都是從頭開發的。項目的名稱來自MPEG視訊編碼标準,前面的"FF"代表"Fast Forward"。 -- 引用自百度百科

二、項目組成

FFmpeg是一套可以用來記錄、轉換數字音頻、視訊,并能将其轉化為流的開源計算機程式。它包括了領先的音/視訊編碼庫libavcodec等。

libavformat:用于各種音視訊封裝格式的生成和解析,包括擷取解碼所需資訊以生成解碼上下文結構和讀取音視訊幀等功能;

libavcodec:用于各種類型聲音/圖像編解碼;

libavutil:包含一些公共的工具函數;

libswscale:用于視訊場景比例縮放、色彩映射轉換;

libpostproc:用于後期效果處理;

ffmpeg:該項目提供的一個工具,可用于格式轉換、解碼或電視卡即時編碼等;

ffsever:一個 HTTP 多媒體即時廣播串流伺服器;

ffplay:是一個簡單的播放器,使用ffmpeg 庫解析和解碼,通過SDL顯示;

三、FFmpeg使用場景

3.1、以下列舉幾個開發中常用的功能:

  • ffmpeg在Linux下和windows下的視訊采集;
  • 視訊格式轉換;
  • 視訊截圖功能;
  • 音視訊合成功能;
  • 視訊添加水印功能;

3.2、誰在使用:

  • 使用FFmpeg作為核心視訊播放器:Mplayer,ffplay,射手播放器,暴風影音,KMPlayer,QQ影音等
  • 使用FFmpeg作為核心的Directshow Filter:ffdshow,lav filters等
  • 使用FFmpeg作為核心的轉碼工具:ffmpeg,格式工廠等

四、如何使用

4.1、FFmpeg如何下載下傳和安裝

FFmpeg可以在Linux、windows以及Mac系統中使用,官網提供了各種系統的安裝包,下載下傳安裝包請移步FFmpeg官網:FFmpeg

安裝包下載下傳完成後,對其進行解壓,由于我的開發環境為Windows系統,就已Windows安裝包為例進行示範。解壓後的目錄結構如下圖所示:

音視訊處理工具FFmpeg與Java結合的簡單使用

以上目錄中,我們使用最多的就是bin目錄下的ffmpeg.exe檔案了,官網給出了一個簡單的例子,我們先來看一下:

音視訊處理工具FFmpeg與Java結合的簡單使用

轉換視訊和音頻從未如此簡單。

圖中的指令是Linux下進行操作的,Windows下并無差異,下面我們分别來使用指令行以及Java代碼來進行示範視訊格式轉換、音視訊合并以及視訊按幀截圖功能。

相關學習資料推薦,點選下方連結免費報名,先碼住不迷路~】

【免費分享】音視訊學習資料包、大廠面試題、技術視訊和學習路線圖,資料包括(C/C++,Linux,FFmpeg webRTC rtmp hls rtsp ffplay srs 等等)有需要的可以點選加群免費領取~

音視訊處理工具FFmpeg與Java結合的簡單使用

4.2、視訊格式轉換

首先我們要來到FFmpeg的解壓目錄,進入到bin目錄中,在此目錄中打開cmd工具。如下圖所示:

音視訊處理工具FFmpeg與Java結合的簡單使用

注:在位址欄中輸入“cmd”,按回車,即可在此目錄直接打開cmd工具。此處我準備了一個視訊檔案以及一個音頻檔案用于下面功能示範。

在cmd工具中鍵入以下指令即可完成視訊格式的轉換:

ffmpeg.exe -i test1.mp4 newVideo.avi           

具體使用請參考官方文檔:ffmpeg Documentation

具體效果如下圖所示:

音視訊處理工具FFmpeg與Java結合的簡單使用

以上是使用指令行進行操作,也可在Java中進行操作:

視訊格式轉換代碼:

/**
 * 簡易視訊處理 -- (cmd(windows): ffmpeg.exe -i test1.mp4 newVideo.avi)
 *
 * @param ffmpegPath      ffmpeg.exe檔案路徑,可在rest或者admin中進行配置,使用配置檔案進行讀取
 * @param videoInputPath  視訊檔案路徑(輸入)
 * @param videoOutputPath 轉換完成的檔案路徑(輸出)
 * @throws IOException
 */
public static void videoConvert(String ffmpegPath, String videoInputPath, String videoOutputPath) throws IOException {
	// 建構指令
	List<String> command = Lists.newArrayList();
	command.add(ffmpegPath);
	command.add("-i");
	command.add(videoInputPath);
	command.add(videoOutputPath);
	// 執行操作
	ProcessBuilder builder = new ProcessBuilder(command);
	Process process = builder.start();
	InputStream errorStream = process.getErrorStream();
	InputStreamReader isr = new InputStreamReader(errorStream);
	BufferedReader br = new BufferedReader(isr);
	String line = "";
	while ((line = br.readLine()) != null) {
	}
	if (br != null) {
		br.close();
	}
	if (isr != null) {
		isr.close();
	}
	if (errorStream != null) {
		errorStream.close();
	}
}           

測試代碼:

@Test
public void testVideoConvert() {
	FfmpegProperties ffmpegProperties = SpringContextHolder.getBean(FfmpegProperties.class);
	try {
		FfmpegUtil.videoConvert(ffmpegProperties.getFfmpegFile(), "D:\\tools\\ffmpeg\\bin\\test1.mp4", "D:\\tools\\ffmpeg\\bin\\newVideo.avi");
	} catch (IOException e) {
		e.printStackTrace();
	}
}           

由于使用的是SpringBoot,ffmpeg.exe檔案路徑配置在了appliction.yml中,是以使用了自定義的FfmpegProperties對其進行讀取,下述所有例子均使用相同配置,如下所示:

ffmpeg:
  ffmpegFile: D:/tools/ffmpeg/bin/ffmpeg.exe #ffmpeg可執行檔案路徑
  outputVideoSuffix: .mp4 #輸出視訊的字尾名
  outputCoverSuffix: .jpg #輸出縮略圖的字尾名           

4.3、音視訊合并

音視訊合并會使用到兩個輸入資源,一個音頻資源和一個視訊資源,此處的例子為一個10s的視訊與一個20s的音頻,我要達到的效果是視訊播放完畢,便退出播放,剩餘音頻不再進行播放。

ffmpeg.exe -i test2.mp3 -i test1.mp4 -t 10 -y newVideo.mp4           

此處:-t代表的是視訊的時間,而-y代表覆寫輸出檔案,直接在cmd工具中執行指令即可

注:在編寫指令是,音頻檔案一定要在視訊檔案的前面,否則合成出來的視訊是有問題的,你會發現音頻并沒有合成進來。

以上是使用指令行進行操作,也可在Java中進行操作:

/**
 * 音視訊合并,視訊結束,音頻結束 -- (cmd(windows): ffmpeg.exe -i test2.mp3 -i test1.mp4 -t 10 -y newVideo.mp4)
 *
 * @param ffmpegPath      ffmpeg.exe檔案路徑,可在rest或者admin中進行配置,使用配置檔案進行讀取
 * @param audioInputPath  音頻檔案路徑(輸入)
 * @param videoInputPath  視訊檔案路徑(輸入)
 * @param time            檔案時長
 * @param videoOutputPath 轉換完成的檔案路徑(輸出)
 * @throws IOException
 */
public static void audioVideoMerge(String ffmpegPath, String audioInputPath, String videoInputPath, double time, String videoOutputPath) throws IOException {
	// 建構指令
	List<String> command = Lists.newArrayList();
	command.add(ffmpegPath);
	command.add("-i");
	command.add(audioInputPath);
	command.add("-i");
	command.add(videoInputPath);
	command.add("-t");
	command.add(String.valueOf(time));
	command.add("-y");
	command.add(videoOutputPath);
	// 執行操作
	ProcessBuilder builder = new ProcessBuilder(command);
	Process process = builder.start();
	InputStream errorStream = process.getErrorStream();
	InputStreamReader isr = new InputStreamReader(errorStream);
	BufferedReader br = new BufferedReader(isr);
	String line = "";
	while ((line = br.readLine()) != null) {
	}
	if (br != null) {
		br.close();
	}
	if (isr != null) {
		isr.close();
	}
	if (errorStream != null) {
		errorStream.close();
	}
}           

測試代碼:

@Test
public void testAudioVideoMerge() {
	FfmpegProperties ffmpegProperties = SpringContextHolder.getBean(FfmpegProperties.class);
	try {
		FfmpegUtil.audioVideoMerge(ffmpegProperties.getFfmpegFile(), "D:\\tools\\ffmpeg\\bin\\test2.mp3", "D:\\tools\\ffmpeg\\bin\\test1.mp4", 10, "D:\\tools\\ffmpeg\\bin\\newVideo.mp4");
	} catch (IOException e) {
		e.printStackTrace();
	}
}           

4.4、視訊按幀截圖

這個功能沒什麼好說的,主要用于使用者手動截圖或者上傳視訊生成縮略圖。

ffmpeg.exe -ss 00:00:01 -y -i test1.mp4 -vframes 1 new.jpg           

此處:-ss position 搜尋到指定的時間 [-]hh:mm:ss[.xxx]的格式也支援,-vframes 設定轉換多少桢(frame)的視訊,此指令是擷取第一秒第一幀的截圖。

注:生成的截圖最好使用jpg格式,占用空間較小,如果需要使用其他格式,根據業務需求自行設定即可。

以上是使用指令行進行操作,也可在Java中進行操作:

/**
 * 擷取第一秒第一幀的縮略圖 -- (cmd(windows): ffmpeg.exe -ss 00:00:01 -y -i test1.mp4 -vframes 1 new.jpg)
 *
 * @param ffmpegPath      ffmpeg.exe檔案路徑,可在rest或者admin中進行配置,使用配置檔案進行讀取
 * @param videoInputPath  視訊檔案路徑(輸入)
 * @param coverOutputPath 縮略圖輸出路徑
 * @throws IOException
 */
public static void getVideoCover(String ffmpegPath, String videoInputPath, String coverOutputPath) throws IOException {
	// 建構指令
	List<String> command = Lists.newArrayList();
	command.add(ffmpegPath);
	command.add("-ss");
	command.add("00:00:01");
	command.add("-y");
	command.add("-i");
	command.add(videoInputPath);
	command.add("-vframes");
	command.add("1");
	command.add(coverOutputPath);
	// 執行操作
	ProcessBuilder builder = new ProcessBuilder(command);
	Process process = builder.start();
	InputStream errorStream = process.getErrorStream();
	InputStreamReader isr = new InputStreamReader(errorStream);
	BufferedReader br = new BufferedReader(isr);
	String line = "";
	while ((line = br.readLine()) != null) {
	}
	if (br != null) {
		br.close();
	}
	if (isr != null) {
		isr.close();
	}
	if (errorStream != null) {
		errorStream.close();
	}
}           

測試代碼:

@Test
public void testGetVideoCover() {
	FfmpegProperties ffmpegProperties = SpringContextHolder.getBean(FfmpegProperties.class);
	try {
		FfmpegUtil.getVideoCover(ffmpegProperties.getFfmpegFile(), "D:\\tools\\ffmpeg\\bin\\test1.mp4", "D:\\tools\\ffmpeg\\bin\\new.jpg");
	} catch (IOException e) {
		e.printStackTrace();
	}
}           

以上就是FFmpeg的簡單使用,如果有更為複雜的需求,直接參考官方文檔進行使用即可。

原文 https://zhuanlan.zhihu.com/p/38961122

繼續閱讀