使用 ffmpeg 命令進行視頻的編輯

摘要

最近項目用到 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 教學——嗶哩嗶哩


  1. FFMPEG 視音頻編解碼零基礎學習方法 ↩︎

  2. 使用 ffmpeg 連接音視頻 ↩︎

  3. java操作ffmpeg爲視頻添加背景音樂的評論 ↩︎

  4. ffmpeg 調整音視頻播放速度 ↩︎

  5. 如何用FFmpeg截取視頻、調整分辨率和提取音軌? ↩︎

  6. 追求視頻畫質,教你如何使用 ffmpeg 壓制出高質量的視頻!——嗶哩嗶哩 ↩︎

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章