摘要
最近項目用到 ffmpeg 的命令對視頻或音頻進行編輯,在這裏由項目需求出發做一個歸納。
通過雷霄驊先生的一篇博文1 可以瞭解關於 ffmpeg 詳盡的知識和用途,讓人不由得對這位先驅產生敬意。
文末的參考資料中可以看到一些文檔以及教程。通過這些文檔和教程,就可以在滿足了需求之後再回頭學習各個命令的意義和作用,從而在遇到新需求時能夠更加快速的找到解決方案。
涉及的 ffmpeg 命令
預設的配置值
//質量參數, 0~50, 越小質量越高. 18~23 肉眼不可分辨的變化
private $crf = 16;
//編碼預設值 preset: 可選:ultrafast, superfast, veryfast, faster, fast, medium, slow, slower, veryslow, placebo
private $preset = 'ultrafast';
質量參數 crf
越小,質量越高,輸出的文件就越大;編碼預設值 preset
可以理解爲壓制程度與時間的關係值,時間越長,壓制程度就要高,輸出的文件就越小,反之同理。
項目需要對視頻進行一系列的操作,最終輸出處理後的視頻。所以,在這個一系列操作的過程中,我把編碼預設值設成了 ultrafast
,是希望儘量縮短這個過程所耗費的時間。當然,這是由操作所需的臨時空間換來的。操作完成後,再由 2-pass
壓制視頻爲所需的文件大小輸出。
而關於質量參數的值,系統默認的好像是 18,但是經過多次操作後,視頻的質量還是有了肉眼可分辨的下降。設爲 16 是可滿足我項目的需求的一個值。
爲視頻添加字幕
ffmpeg -i {$originFileTmpPath} -vf subtitles={$subtitlePath} -crf {$this->crf} -preset {$this->preset} {$subFilePath}
根據輸入文件內容,拼接音頻並輸出到指定路徑:(此處用的是博文2的方法二「FFmpeg concat 分離器」)
ffmpeg -f concat -safe 0 -i {$fileListPath} -c copy {$finalFilePath}
這裏多了 -safe 0
,原因是:
在 filelist.txt 裏面加入/的話會報一個不安全文件路徑的錯誤
Unsafe file path
只要加上-safe 0
就可以解決啦
保留原聲合併音(視)頻3
ffmpeg -i {$input} -i {$addFilePath} -filter_complex amix=inputs=2:duration=first:dropout_transition=2 -crf {$this->crf} -preset {$this->preset} {$output}
注意:inputs=輸入流數量,duration=決定流的結束(longest最長輸入時間,shortest最短,first第一個輸入持續的時間),dropout_transition= 輸入流結束時,容量重整時間
截取時間段內的音頻
ffmpeg -ss {$startTime} -i {$input} -to {$endTime} -c copy -copyts {$outputPath}
ffmpeg -ss {$startTime} -i {$input} -t {$duration} -c copy {$outputPath}
如果你僅僅在輸入文件之前( -i 之前)指定了 ss 選項,那麼時間戳會被重置爲 0,此時選項 t 和選項 to 產生的效果一樣。
如:ffmpeg -ss 00:01:00 -i video.mp4 -to 00:02:00 -c copy cut.mp4
ffmpeg -i video.mp4 -ss 00:01:00 -to 00:02:00 -c copy cut.mp4
上面例子中,第一個命令會得到從 00:01:00 到 00:03:00 的片斷,而第二個命令會真正得到從 00:01:00 到 00:02:00 的片斷。
關於 mpeg 格式的截取,這個 關於I幀的解釋:什麼是GOP 博文裏的一個測試還是很具象地解釋了 mpeg 格式爲什麼難以精確剪輯。
關於視頻的精確剪輯,直接:
ffmpeg -i {$input} -ss {$startTime} -to {$endTime} {$outputPath}
ffmpeg 會默認重新解碼編碼,從而截取精確的視頻時間段。當然,所耗的時間也會變長了。
調整音頻速率4
ffmpeg -i {$input} -filter:a atempo={$multiple} {$output}
$multiple float|int 倍率調整範圍爲[0.5, 2.0]
超過調整範圍時,比如 4 倍,可以通過重複參數實現:
ffmpeg -i {$input} -filter:a atempo=2,atempo=2 {$output}
去除音視頻的原聲
ffmpeg -i {$input} -c:v copy -an {$output}
-c:v copy
表示複製視頻,-an
表示不需要音頻。
爲不帶音頻的視頻文件添加音頻
ffmpeg -i {$input} -i {$audio} {$output}
#0:0
表示視頻流,#0:1
表示音頻流。該命令只適用於給音頻流爲空的視頻文件添加音頻流。
生成指定長度的空白音頻
ffmpeg -f lavfi -i aevalsrc=0 -t {$seconds} -q:a 9 -ac 1 -ar 16000 -acodec pcm_s16le {$output}
視頻轉音頻,wav 格式
ffmpeg -i {$input} -vn -ar 16000 -ac {$channel} -f wav {$output}
-vn
表示不需要視頻。
生成視頻封面圖
ffmpeg -ss 00:00:00 -t 00:00:00.001 -i {$input} -r 1 -f image2 {$output}
改變音頻文件的音量
ffmpeg -i {$input} -filter: volume={$multiple} -y {$output}
獲取音視頻時長
ffmpeg -i {$input} 2>&1 | grep 'Duration' | cut -d ' ' -f 4 | sed s/,//
通過命令行命令,搜索、截取出 00:00:00 格式的音視頻時長。
獲取視頻幀圖
ffmpeg -i {$input} -vf scale=160:-1 -r {$numPerSecond} -start_number 000000 {$dir}/%11d.png
-start_number
設置輸出文件名開始的數字。
修改視頻分辨率5
ffmpeg -i {$input} -vf scale=iw*{$multiple}:ih*{$multiple} -crf {$this->crf} -preset {$this->preset} {$output}
-vf
表示濾鏡。scale
爲濾鏡裏的縮放功能。iw/ih
表示原始尺寸的大小。scale=-1:ih*2
表示高度乘 2,寬度等比縮放。
2-pass 壓制視頻可自定義碼率6 = 可自定義大小
ffmpeg -i {$input} -strict -2 -passlogfile {$dir} -vb {$bitRate}k -pass 1 -f mp4 -y /dev/null
ffmpeg -i {$input} -strict -2 -passlogfile {$dir} -vb {$bitRate}k -pass 2 -f mp4 {$output}
兩條命令可以分開執行,也可以用 &&
連接一起執行。
-strict -2 -passlogfile {$dir}
用於指定生成中間臨時文件的目錄。
-vb
可理解爲 video bitrate。
參考資料
2015 年中文翻譯的文檔
官網英文文檔
FFmpeg 分 P 教學——嗶哩嗶哩