FFmpeg全名是Fast Forward MPEG(Moving Picture Experts Group),為開源的影音多媒體處理框架,可以進行影音的解碼、編碼、編碼轉換、混合、抽取、串流和濾鏡,無論影音格式是從哪個地方出來的,從過去到現在的影音格式它幾乎都能夠支援。當然,它也可以利用x264這款高品質的開源H.264編碼器來進行H.264編碼。
x264雖然本身有提供指令工具,且能支援幾種輸出的檔案容器(如.mp4
、.mkv
),但基於它無法同時處理音訊的原因,我們很少會直接使用它,而是會透過其它前端的介面來使用x264的函式庫。一般來說,使用x264進行影片編碼會選擇使用--crf
參數來設定CRF(Constant Rate Factor)控制影片畫質,數值愈低畫質愈高(位元率相對愈高)。此外,x264指令工具還有提供一個--preset
參數,它可以幫助我們快速設定x264編碼時所用的眾多參數。依照編碼速度的不同,preset由快到慢可以分為:ultrafast
、superfast
、veryfast
、faster
、fast
、medium
、slow
、slower
、veryslow
、placebo
這9個等級,原則上愈慢則會有更好的壓縮效果或是畫質。
使用FFmpeg指令工具來操作x264編碼器時,x264
的--crf
參數會對應到FFmpeg的-crf
參數,數值範圍為0 ~ 51,預設值為23,18左右即達到視覺無損;--preset
參數會對應到FFmpeg的-preset
參數,預設值為medium
。
透過FFmpeg輸出視覺無損的H.264/MPEG-4 AVC影片的指令如下:
透過FFmpeg輸出標準畫質的H.264/MPEG-4 AVC影片的指令如下:
使用最高的壓縮效果來輸出視覺無損的H.264/MPEG-4 AVC影片,指令如下:
使用最低的壓縮率來輸出視覺無損的H.264/MPEG-4 AVC影片(通常作為輸出正式結果前的測試),指令如下:
不過實際上,即便用CRF編碼模式,-preset
參數還是會影響到輸出畫質的。可參考這篇文章來比較看看。
4:2:0/4:2:2/4:4:4和8-bit/10-bit影片編碼
預設情況下,FFmpeg使用x264來編碼H.264/MPEG-4 AVC時,會根據影片輸入源來決定輸出的色彩取樣方式和色彩深度。常見的色彩取樣方式為4:2:0(支援硬體解碼),特殊情況下才會去用到4:2:2或是4:4:4。色彩取樣對於畫面的呈現差異並不明顯,但對於後製寬容度的影響比較大。而色彩深度則影響到影片的顏色表現範圍,這個要看影片來源,如果影片原本就是用10-bit深度的設備進行錄製或是製作的話,那麼降轉成8-bit時就會出現色班、色塊等色階不連續的情況。
FFmpeg指令工具可以利用-pix_fmt
參數來設定輸出影片的像素格式來決定其色彩取樣方式和像素格式,搭配libx264編碼時,會自動選擇適當的H.264/MPEG-4 AVC Profile來使用。
像素格式yuv420p
,代表要使用8-bit 4:2:0進行編碼;yuv422p
,代表要使用8-bit 4:2:2進行編碼;yuv444p
,代表要使用8-bit 4:4:4進行編碼;yuv420p10le
,代表要使用10-bit 4:2:0進行編碼;yuv422p10le
,代表要使用10-bit 4:2:2進行編碼;yuv444p10le
,代表要使用10-bit 4:4:4進行編碼。
透過FFmpeg輸出視覺無損的10-bit H.264/MPEG-4 AVC影片的指令如下:
CVBR(約束的變動位元率)
CRF是以畫質為基準的影片編碼方式,所以其編碼結果會根據該片段內的複雜程度來決定其所使用的位元率,也就是變動位元率(VBR)。因此,對於複雜的運動場景,位元率被拉得很高,如果這個影片是用在網路串流的話,使用者就容易發生卡頓的情形。CVBR編碼模式是以VBR編碼模式為基礎,再增加位元率最大值(也可加上最小值)的限制,若是x264在編碼時發現該片段需要比設定的位元率最大值還要更大的位元率才有辦法處理的話,就會自動調高CRF(降低畫質)來進行編碼。
替FFmpeg加上-maxrate
參數傳入要設定的位元率最大值,另外還要傳入-bufsize
參數來設定解碼器用的緩衝空間。-bufsize
參數的值並沒有固定,我們可以先把它設為跟-maxrate
參數一樣或是一半的值,再慢慢往上加,直到最終的輸出位元率接近我們設定的位元率最大值。如果不設定-bufsize
參數的話,輸出的位元率會偏低;如果有適當地設定-bufsize
參數,我們就可以利用以下公式來預估編碼後的影片大小:
#{{{
{ \text{約束的變動位元率(Kbps, Kb/s)} \times \text{時間(s, 秒)} \over \text{8(b/B)} } = \text{影片的大小(KB)}
}}}#
為什麼要有-bufsize
參數?當我們在網路串流影片的時候,影片資料並不是被我們接收到之後就立刻解碼播放到螢幕上,而是會先存入「緩衝空間」。假設我們的網路頻寬有1Mbps,經過N秒就有N Mb的資料進入緩衝空間中。由於影片位元率是變動的,可能第1秒的資料只佔了0.5 Mb,而第2秒的資料卻有1.5 Mb,我們的播放器再播放第1秒影片內容的時候,就會取得第2秒一部份的影片內容,放在緩衝空間中。若緩衝空間至少有0.5 Mb,即便我們的網路頻寬不足1.5Mbps,這個影片也可以順暢播放。-maxrate
參數的值其實也代表著使用者最低限度的網路頻寬,搭配-bufsize
參數來使用時,設定愈高的緩衝空間,可以允許影片的某些片段使用比-maxrate
設定的最大位元率還要更大的位元率來處理複雜的場景。
透過FFmpeg輸出視覺無損的CVBR 3Mbps H.264/MPEG-4 AVC影片的指令如下:
二次編碼(2-pass)
如果是為了要輸出固定大小的影片而使用CVBR編碼模式的話,可能就得重複轉好幾次檔,找出適當的-bufsize
參數的值。其實有個更好的方式只要固定編碼兩次就好了,第一次編碼的目的是收集編碼影片來源時所得到的資訊(預設會在工作目錄中被存成ffmpeg2pass-0.log
和ffmpeg2pass-0.log.mbtree
檔案),第二次是利用已收集到的資訊和相同的影片來源編碼出位元率有被精確控制過的影片。
利用FFmpeg提供的-b:v
(-vb
)參數,可以直接設定影片的平均位元率。再加上-pass 1
參數表示要進行第一次編碼;-pass 2
參數表示要進行第二次編碼。
例如要使用最高的壓縮效果輸出平均位元率為3Mbps的H.264/MPEG-4 AVC影片,第一次編碼的指令如下:
由於第一次編碼輸出的影片檔案,其位元率可能會和我們從參數設定的位元率有所差距,所以不讓它儲存成檔案。當然,您也可以選擇存下來,因為說不定它就正好是我們要的位元率,這樣也不需要繼續接下來的第二次編碼了。另外,這個指令還用了-an
和-sn
參數使FFmpeg不要去處理音軌和字幕軌;-y
參數使FFmpeg不詢問是否覆蓋檔案。上面的指令是給Unix-like的作業系統用的,如果是Windows的話要使用下面這個指令:
第二次編碼的指令如下:
無損壓縮
H.264支援無損壓縮,只要將-crf
參數設為0
就好了,FFmpeg會將H.264 Profile設為High 4:4:4 Predictive
。
使用最高的壓縮效果來輸出無損畫質的H.264/MPEG-4 AVC影片,指令如下:
Tune
針對不同地影像來源類型或是輸出目的,x264還可以加上--tune
參數控制一些編碼細項來優化結果。FFmpeg對應的參數為-tune
。-tune
可以使用的值有以下幾種:
film
:影像來源為現代電影或是3D動畫。(無大範圍同色色塊的影像)animation
:2D動畫。(有大範圍同色色塊,且上、下張變化不大的影像)grain
:老電影。(有顆粒感的影像)stillimage
:幻燈片類的影片。fastdecode
:輸出適合在低端設備播放的影片。zerolatency
:輸出適合低延遲串流的影片。psnr
、ssim
:針對PSNR或是SSIM進行優化,對視覺品質可能沒有實質意義上的幫助。