由於儲存空間和資料傳輸速度的限制,我們可能沒辦法將錄影設備所錄製到的資訊,或是藉由軟體演算出來的畫面完好無損地保存或是傳送。影片是給人看的,但是人類的眼睛的分辨能力有限,非常細微的訊號差異其實感受不太出來,因此可以使用一些會改變原本影像訊號的方式來將其重新編碼(Encode)成和原始影像訊號看起來差異不大的格式,減少儲存影像訊號所佔用空間和加快傳送影像訊號時的速度,而這種壓縮影像訊號的方式就稱為有損壓縮(Lossy Compression)。有損壓縮影像訊號的方式有很多種,常見的格式為MPEG-4、H.264、VP8,另外還有比較後來才出現的H.265、VP9、AV1格式。有些編碼格式除了可以做有損壓縮外,還可以做無損壓縮(Lossless Compression),將原始的影片畫質完整地保留下來。這篇文章並不會去比較影片編碼格式的畫質優劣,因為相同編碼格式的影片,其畫質可以藉由增加影片的位元率來提高。取而代之地,這邊文章將會實際地去對相同檔案做不同格式的轉檔,並以SSIM(structural similarity)指標為準,來比較在幾乎相同畫質下的不同格式的影片,其位元率的差異如何。



有損影片壓縮

有損影像壓縮的原則

有損(Lossy)影響壓縮,顧名思義就是將影像訊號使用破壞性壓縮,使用較少、有限的資料量來還原出接近原始的影像訊號,以縮小儲存影像訊號所需的空間。

由於影像是給人看的,因此理論上會儘量保留會對人類肉眼比較敏感的資訊,並移除或是減少人類肉眼不敏感的部份。

影片壓縮

一部影片是由很多張影像(影格)所構成,由於這些影像有時間順序,因此在進行影片編碼時,我們不需要將其所有的影像都完整地儲存下來,而是可以藉由計算連續的影格,將其有變動和沒變動的部份分開來儲存,因此沒變動的影像部份,儘管會在多個影格中出現,但也還是只需要儲存一份的資訊就好,如此一來就能把儲存空間節省下來。當然,這樣子做的話也會讓影片在解碼的時候需要去參考前後影像的資料來繪製出目前要播放出來的完整影像。

影片的位元率

影片的位元率直接影響著影片檔案的大小,這點很重要,因為有些人可能會提出這樣無理的要求:「我想要保留影片的位元率,但是要讓影片檔案變小一點。」

實際上影片檔案所需佔用的儲存空間算法如下:

儲存空間 = 平均位元率 * 影片時間長度

單看影片的位元率,即便是使用同一個編碼器所編碼出來的影片,也無法比較出兩個影片的畫質優劣。這是因為影片的壓縮如同上述所提,除了會壓縮單張影像之外,也會針對影像和影像之間的關係進行處理,處理得愈多,位元率自然就愈低,但影片畫質並不會因此下降或是提升。

若要比較相同片源的影片畫質,最好還是參考以下文章來計算重製後的影片和片源的畫質差異程度……數字會說話!

https://magiclen.org/ffmpeg-psnr-ssim/

常見的壓縮格式

影片壓縮的格式有許多種,不同的壓縮格式會使用不同的演算法來對影像訊號進行壓縮,影格之間的處理方式也有所不同。愈新的影片編碼格式通常會有愈好的壓縮率,但也需要更久的運算時間來進行編碼和解碼的動作。

MPEG-4

MPEG-4(此處指MPEG-4 Part 2)是MPEG(Moving Picture Experts Group)在1990年代所制定的影片編碼標準,提供多種Profile。代表的編碼器有Xvid和DivX,前者採用GPL開源,更為流通,基於MPEG-4 ASP(Advanced Simple Profile)標準。

H.264

H.264是由多個組織組成的JVT(Joint Video Team)在2000年代所制定的標準,也被分類在MPEG-4之下(MPEG-4 Part 10),也稱為MPEG-4 AVC,可以寫成H.264/AVC。H.264可在相同畫質下提供比過去MPEG-4標準更低的位元率。代表的編碼器為x264。

H.265

H.264是由JVT在2010年代所制定的標準,在MPEG-H之下(MPEG-H Part 2),也稱為MPEG-H HEVC( High Efficiency Video Coding),可在相同畫質下提供比MPEG-4 AVC標準更低的位元率。代表的編碼器為x265。

VP8

由於MPEG系列的格式要商業運用的話都需要繳交授權費用,因此Google和On2 Technologies就在制定了VP8,並在2010年將On2 Technologies收購之後將VP8開源(BSD授權),使其成為可以免費授權使用的高品質影片編碼格式,常與H.264做比較。官方的編碼器為libvpx。

VP9

西元2013年,VP8的後繼格式VP9誕生,可在相同畫質下提供比過去VP8更低的位元率。官方的編碼器為libvpx。

AV1

AV1是由多個組織組成的開放媒體聯盟(AOMedia)在2018年開發出來的影片編碼格式,其編碼技術主要來自於Google開天窗的VP10(VP9的下一代),因此可以在相同畫質下提供比過去VP9更低的位元率。官方的編碼器為libaom。

影片壓縮格式的優劣

通常愈晚出來的影片格式壓縮效果會愈好,但也會需要更多的運算時間來進行編碼和解碼的動作。像是H.265、VP9、AV1這樣的格式,若沒有辦法被硬體編碼或解碼的話,就需要用到大量的CPU運算資源透過軟體程式來進行編碼或解碼,因此即便它們擁有比MPEG-4、H.264、VP8格式還要先進的技術,在硬體等級比較不好的電腦設備上若無法順暢地編解也等同無用武之地。所以,現階段最流行的格式還是H.264,雖然它不是最好的,卻是最實用的。

MEPG-4(Xvid)、H.264(x264)、H.265(x265)、VP8、VP9、AV1的比較

接下來才是本篇文章的重頭戲,筆者將會使用一個解析度為1920x1080、FPS為24、像素格式為yuv420p、長度為30秒的無損壓縮的片源,來實際對MEPG-4、H.264、H.265、VP8、VP9和AV1格式進行轉檔測試。

測試用的影片檔

這個測試用的影片檔案來自於這個網站提供的Big Buck Bunny未壓縮影片檔。筆者擷取了其中的4:30~5:00的片段,其平均位元率為597197Kbps。

接著使用FFmpeg,以x265將其無損壓製成MP4檔案,使用的指令如下:

ffmpeg -i 'Big Buck Bunny.y4m' -vcodec libx265 -x265-params lossless=1 -preset veryslow 'Big Buck Bunny.mp4'

可以透過以下連結下載壓製好的檔案:

https://file.magiclen.org/index.php?file=426967204275636b2042756e6e792e726172

這個以x265壓縮後的影片,位元率為93314Kbps,約只有原先的15.63%。如果以VP9格式來做無損壓縮的話,使用的指令如下:

ffmpeg -i 'Big Buck Bunny.y4m' -vcodec vp9 -lossless 1 -speed 0 'Big Buck Bunny.webm'

這個以VP9壓縮後的影片,位元率為111791Kbps,約有原先的18.71%。由此可知,無損壓縮下,x265是比VP9還要來得好的。

編碼器

為了編碼出不同格式的檔案,筆者使用了多種不同的編碼器,都是透過FFmpeg 4.1.1來操作。列表如下:

  • libxvid 1.3.5:用來進行MPEG-4的編碼。
  • libx264 snapshot-20190211-2245:用來進行H.264的編碼。
  • libx265 3.0:用來進行H.265的編碼。
  • libvpx 1.6.1:用來進行VP8和VP9的編碼。
  • libvpx 1.0.0-20190212:用來進行AV1的編碼。

畫質差異分析工具

為了比較影片檔案之間的畫質差異,筆者使用了FFmpeg來計算PSNR和SSIM(作法可參考這篇文章),也用FFmpeg來擷取影片中的影格畫面,並使用ImageDifferencer 1.0.1來比較影像在壓縮前與壓縮後的差異(可參考這篇文章)。

片源的影格擷取

以下是從片源的第16秒所取得的影格畫面:

vcodec

使用的FFmpeg指令如下:

ffmpeg -i 'Big Buck Bunny.mp4' -ss 16 -vframes 1 'Big Buck Bunny.png'

CRF(Constant Rate Factor)和qscale

CRF是x264、x265、libvpx、libaom用來控制影片畫質的參數,數值愈低畫質愈高(位元率相對愈高),x264和x265的CRF範圍都是0~51;libvpx和libaom的CRF範圍是0~63(VP8最低只能設到4)。Xvid並沒有CRF,但它有類似的qscale可以用,範圍是1~31,數值愈低畫質愈高。

若要使用CRF來控制x264和x265的編碼畫質,FFmpeg指令寫法如下:

ffmpeg -i 輸入影片路徑 -vcodec libx264/libx265 -crf 20 -preset veryslow 輸出影片路徑

其中,「-preset veryslow」參數可以儘可能地在保有相同的畫質下,減少位元率。(如果要把位元率減少到極致,可以使用「-preset placebo」,不過編碼速度會很慢!)

若要使用CRF來控制libvpx(VP8、VP9)的編碼畫質,FFmpeg指令寫法如下:

ffmpeg -i 輸入影片路徑 -vcodec libvpx/libvpx-vp9 -b:v 0 -crf 20 -speed 0 輸出影片路徑

其中,「-speed 0」的功用類似x264和x265的「-preset veryslow」。

若要使用CRF來控制libaom的編碼畫質,FFmpeg指令寫法如下:

ffmpeg -i 輸入影片路徑 -vcodec libaom-av1 -b:v 0 -crf 20 -strict -2 輸出影片路徑

其中,「-strict -2」是用來允許使用FFmpeg實驗性的功能(因為AV1還是FFmpeg 4.1.1的實驗性功能)。

若要使用qscale來控制Xvid的編碼畫質,FFmpeg指令寫法如下:

ffmpeg -i 輸入影片路徑 -vcodec libxvid -qscale:v 3 輸出影片路徑

開始比較

底下將會以H.264(x264)作為基準,針對其三種不同的CRF參數的畫質等級(視覺無損、標準畫質和筆者可接受的最低畫質)來將片源進行有損壓縮,並且計算出這三種CRF參數壓縮後的結果與片源的SSIM指標,這三個SSIM指標會被當作是這三種畫質等級「視覺無損」、「標準畫質」和「筆者可接受的最低畫質」的SSIM參考值。接著再以其它影片編碼格式使用不同的CRF或qscale參數來將片源進行有損壓縮,同樣拿它們計算出與片源的SSIM指標,然後找出落在剛才提到的三種畫質等級的SSIM參考值的有哪些。最後再來比較這些SSIM指標相近的影片,其位元率的高低。

CRF 18

根據FFmpeg的文件,當x264的CRF參數設為18時,可以得到「視覺無損」(visually lossless)的畫質,也就是雖然不是真的無損,但人類肉眼看起來的結果是跟片源一模一樣的。在實際使用18作為CRF參數值來進行轉檔後,可以得到位元率為4303Kbps的影片。此時的影片與片源的PSNR為47.847180,SSIM為0.992476。

影格擷取如下:

vcodec

與原始影格的差異如下:

vcodec

從上圖可以看出x264在壓縮影像的時候會先從丟失邊緣的細節開始。

再來就是找出能讓x265、VP8、VP9、AV1、MPEG-4轉出SSIM接近0.992476的CRF或是qsacle參數了。

當x265的CRF參數設為20時,可以得到位元率為3066Kbps的影片。此時的影片與片源的PSNR為47.982695,SSIM為0.992113。

影格擷取如下:

vcodec

與原始影格的差異如下:

vcodec

從上圖可以看出x265在壓縮影像的時候也會先從丟失邊緣的細節開始。

當VP8的CRF參數設為4時,可以得到位元率為12670Kbps的影片。此時的影片與片源的PSNR為46.312157,SSIM為0.990618。(無法達到我們視覺無損的標準)

影格擷取如下:

vcodec

與原始影格的差異如下:

vcodec

從上圖可以猜測出VP8在壓縮影像的時候會蠻均勻地改變整張影像的亮度和色彩,也因此會保留比較多的細節。

當VP9的CRF參數設為15時,可以得到位元率為6086Kbps的影片。此時的影片與片源的PSNR為48.658626,SSIM為0.992856。

影格擷取如下:

vcodec

與原始影格的差異如下:

vcodec

從上圖可以猜測出VP9在壓縮影像的時候會比VP8還更均勻地改變整張影像的亮度和色彩,以保留更多的細節。

當AV1的CRF參數設為20時,可以得到位元率為3331Kbps的影片。此時的影片與片源的PSNR為48.304780,SSIM為0.992418。

影格擷取如下:

vcodec

與原始影格的差異如下:

vcodec

從上圖可以猜測出AV1在壓縮影像的時候,採取的策略類似VP8。

當MPEG-4的qscale參數設為2時,可以得到位元率為13539Kbps的影片。此時的影片與片源的PSNR為47.151285,SSIM為0.990024。(把qscale參數設為1的話,可以獲得超過視覺無損的畫質,但是位元率會變非常高)

影格擷取如下:

vcodec

與原始影格的差異如下:

vcodec

從上圖可以猜測出MPEG-4在壓縮影像的時候,會先從丟失邊緣的細節開始,但它也會稍微均勻地改變整張影像的亮度和色彩,使得細節不被丟失得那麼嚴重。

CRF 23

x264的預設CRF值為23,所以是標準畫質。在實際使用23作為CRF參數值來進行轉檔後,可以得到位元率為2341Kbps的影片。此時的影片與片源的PSNR為44.985929,SSIM為0.987396。

再來就是找出能讓x265、VP8、VP9、AV1、MPEG-4轉出SSIM接近0.987396的CRF或是qsacle參數了。

當x265的CRF參數設為24時,可以得到位元率為1883Kbps的影片。此時的影片與片源的PSNR為45.745517,SSIM為0.988000。

當VP8的CRF參數設為12時,可以得到位元率為6500Kbps的影片。此時的影片與片源的PSNR為45.044315,SSIM為0.987444。

當VP9的CRF參數設為27時,可以得到位元率為3122Kbps的影片。此時的影片與片源的PSNR為45.615088,SSIM為0.987342。

當AV1的CRF參數設為30時,可以得到位元率為1837Kbps的影片。此時的影片與片源的PSNR為45.546846,SSIM為0.987268。

當MPEG-4的qscale參數設為3時,可以得到位元率為9399Kbps的影片。此時的影片與片源的PSNR為44.750343,SSIM為0.984686。所以還是qscale參數設為2時的SSIM會比較接近0.987396。

CRF 30

x264的CRF值若高於30,轉出來的畫質實在是傷眼睛,可以明顯看到影像出現色塊,所以筆者覺得30是可接受的最低畫質。在實際使用30作為CRF參數值來進行轉檔後,可以得到位元率為1046Kbps的影片。此時的影片與片源的PSNR為40.739121,SSIM為0.972788。

影格擷取如下:

vcodec

與原始影格的差異如下:

vcodec

與視覺無損的影格差異如下:

vcodec

從上圖可以看出x264在更低的位元率時主要會丟失更多邊緣的細節。

當x265的CRF參數設為31時,可以得到位元率為812Kbps的影片。此時的影片與片源的PSNR為41.536069,SSIM為0.973679。

影格擷取如下:

vcodec

與原始影格的差異如下:

vcodec

與視覺無損的影格差異如下:

vcodec

當VP8的CRF參數設為37時,可以得到位元率為2977Kbps的影片。此時的影片與片源的PSNR為41.127550,SSIM為0.971314。

影格擷取如下:

vcodec

與原始影格的差異如下:

vcodec

與CRF為4時的影格差異如下:

vcodec

當VP9的CRF參數設為39時,可以得到位元率為1400Kbps的影片。此時的影片與片源的PSNR為41.536900,SSIM為0.972837。

影格擷取如下:

vcodec

與原始影格的差異如下:

vcodec

與視覺無損的影格差異如下:

vcodec

從上圖可以看出vp9在低位元率的時候並不太會偏重丟失哪方面的細節。

當AV1的CRF參數設為41時,可以得到位元率為840Kbps的影片。此時的影片與片源的PSNR為41.613474,SSIM為0.973708。

影格擷取如下:

vcodec

與原始影格的差異如下:

vcodec

與視覺無損的影格差異如下:

vcodec

當MPEG-4的qscale參數設為5時,可以得到位元率為5752Kbps的影片。此時的影片與片源的PSNR為41.684421,SSIM為0.972059。

影格擷取如下:

vcodec

與原始影格的差異如下:

vcodec

與qscale為2時的影格差異如下:

vcodec

結論

在畫質等級為「視覺無損」時,如果x264的位元率是100%,則x265是71.25%,VP8是294.45%以上,VP9是141.44%,AV1是77.41%,MPEG-4是314.64%以上。因此在高畫質的情況下,使用x265、AV1都是不錯的選擇。

在畫質等級為「標準畫質」時,如果x264的位元率是100%,則x265是80.44%,VP8是277.66%,VP9是133.36%,AV1是78.47%,MPEG-4約是578.34%以下。因此在標準畫質的情況下,依然還是使用x265、AV1才是不錯的選擇。

在畫質等級為「筆者可接受的最低畫質」時,如果x264的位元率是100%,則x265是77.63%,VP8是284.61%,VP9是133.84%,AV1是78.95%,MPEG-4是540.60%。因此在低畫質的情況下,仍然還是使用x265、AV1才是不錯的選擇。

FFmpeg指令方面,x264可接受的CRF範圍是18~30,x265可接受的CRF範圍是20~31,VP8可接受的CRF範圍是4~37,VP9可接受的CRF範圍是15~39,AV1可接受的CRF範圍是20~41,MPEG-4(xvid)可接受的qscale範圍是2~5。