影片編碼流程探討—以H.264編碼為例

Li-shuang Yu
SWAG
Published in
10 min readJan 3, 2023

Swag 平台上有大量的影音內容,處理過程中牽涉到影像的編碼、解碼。了解我們常用的 H.264 編碼的原理與工作流程,可以幫助我們在調教編碼器的時候,不再單純依賴直覺,而是依據編碼解碼的原理進行合理操作。網路上常見講解編碼解碼的文章都是將各部分功能條列,並對細項分頭描述。本文則從流程切入,希望能帶給讀者抽象流程的理解,更能了解網路上常見的內容的背後意涵。

概述

影像編碼的主要流程為「預測(prediction)」->「轉換(transformation)與量化(quantization)」->「熵編碼(entropy coding)」。

編碼器先用已知的資訊預測當前的影格,將當前影格分成預測的資訊剩餘(residual)的資訊。剩餘的圖像資訊經由轉換後,可以進行壓縮,將影響較小的資訊去除,達到大幅縮小資訊量的目的。最後,這些資訊會依據發生頻率進行編碼,在不影響內容的情況下,進一步壓低所需空間。

編碼器在轉換壓縮後,會像解碼器一樣,將壓縮的資料重新解壓縮成影格,用來當作新的已知資訊,預測下一個影格。這樣,就可以保持接收端解碼器的誤差不會越來越大,接收者可以看到一致的結果。

另外,H.264 編碼器是將影格切為巨集區塊(macroblock, MB)處理。巨集區塊大小最主要有 16 x 16 或 4 x 4,大的區塊應對大色塊,而小的區塊處理細節畫面。一搬進行方向是由左到右、由上而下,先處理好的區塊就可以視為新的已知資訊,可用來預測後處理的區塊。

預測

巨集區塊的資訊,通常會跟同一影格鄰近巨集區塊或前後影格的像素相關。此時巨集區塊的值就可以分解成以其它區塊預測的部分,加上預測誤差。預測的部分可以簡易描述要查找的區塊。而誤差的部分則可以在之後近一步壓縮。H.264 編碼器,有 2 種預測資訊的來源:

1. 跨影格預測(Inter prediction)

就是用較早解碼影格的像素資訊做預測。雖說是預測,但進行方式是相反的。用當前的巨集區塊的方框去之前解碼的影格移動比對,尋找預測誤差最小的方框,如圖所示。而到最佳預測方框所需移動的向量,就是位移補償。預測後,只要紀錄位移補償與誤差,可以減少紀錄重複的像素資訊。

巨集區塊從之前解碼的影格比較均方誤差 (meas square error, MSE),找出最適合的引用區塊,紀錄位移補償。此處的位移補償的向量是 (1, -2)。

注意較早解碼影格不一定代表影格本身時間的先後順序。巨集區塊的預測可用之前或是之後的影格,但一定是先解碼的已知資訊。因此,巨集區塊可區分為只用之前影格資訊的 P 巨集區塊 (P MB),和兩個方向都可以的B巨集區塊 (B MB)。其中 B 巨集區塊壓縮效率較好,但也更複雜,由於影格需要重新排序,延遲也會延長。B 巨集區塊僅在主設定檔 (main profile) 提供。

2. 影格內預測(Intra prediction)

I 巨集區塊 (I MB)。限定用同一影格先前已編碼的巨集區塊進行預測,可能是左方巨集區塊預測,上方巨集區塊預測,或是這些巨集區塊的平均。如圖。

預測後,以哪些巨集區塊與何種平均方式預測,加上誤差,可以減少紀錄重複的像素資訊。

巨集區塊的像素資訊會從左方或上方解碼的像素獲得。這裡顯示 9 種取樣方式的其中一種。
巨集區塊裡的像素會從左方或上方已解碼的像素預測。箭頭即預測方向。這裡顯示多種預測模式的其中一種。

我們常見的I影格(I frame)、P影格(P frame)以及B影格(B frame),與上述各種巨集區塊有以下關係:
I 影格,只會包含 I 巨集區塊。
P 影格,可包含 I 巨集區塊或 P 巨集區塊。
B 影格,上述巨集區塊皆可包含。

轉換與量化

巨集區塊經過預測後,留下剩餘的資訊 (residual MB),也就是預測誤差需要處理。首先會經過離散餘弦轉換,得出的係數再藉由量化進行壓縮。編碼器也是在此階段控制量化量以達到目標位元率 (bitrate)。

離散餘弦轉換 (discrete cosine transform,DCT)

預測誤差相較於原始像素強度資訊,由於像素間的相關性大幅降低,較容易處理。此時對這些資訊進行離散餘弦轉換,係數矩陣會有由左上到右下遞減的特徵。離散餘弦轉換類似傅立葉轉換 (Fourier transform),轉換後各頻率的係數會由左上(低頻),往右下(高頻)排列。通常左上的數值最大,接著會如同扇形等高線般向右下逐步減少。這種特徵適合鋸齒形 (zigzag) 的掃描方式,形成的實數一維陣列在接下來的量化後通常會帶有一長串可省略的 0。

對巨集區塊進行鋸齒形掃描。

量化

轉換後接著就是以量化減少資訊。量化是將這些實數數值改以有限的整數取代。會丟失小數或是餘數的資訊,因此才會減少資訊量。量化時使用的數值越少,損失越多。編碼器在操作的時候,則是使用量化參數 (quantization parameter, QP),量化參數越大代表量化時每一階跨度越大,可視為使用的數值越少,損失越多。

原值與量化後的對照,可以看到當量化參數為 2 的時候,剩下 5 階的數值。當量化參數為 5 的時候,階數只剩下 3。

如同前面所說,由其在高頻的部分,許多原本趨近於零的數量化後會呈現連續的 0。連續的 0 可以用運行長度編碼 (run-length encoding) 來進一步減少所需的空間。如果選擇量化量高,則丟失的資訊越多,壓縮率越高。編碼器在尋求滿足目標位元率時,會動態決定使用的量化參數來達成目標。

轉換與量化完成後,編碼器會將壓縮的資訊,先乘上量化量,再進行逆離散餘弦轉換 (inverse discrete cosine transform),解壓縮還原成預測誤差。解壓縮的預測誤差,加上上一個步驟的預測資訊,就還原成解碼的影格。可以用來預測下一個要處理的巨集區塊。由於經過量化壓縮,解壓縮的預測誤差已經與壓縮前的預測誤差不同,也就是失真了。

熵編碼

影格經過處理後,產生的資訊也可以經過內容編碼再進一步縮減所需空間。其原則是發生頻率越高的內容用越短的碼字 (code word) 表示。H.264 支援 2 種編碼方式:

適應性可變長度編碼 (Context-based Adaptive Variable-Length Coding, CAVLC)

是一種可變長度編碼(variable length coding)。其對應碼字的推論是基於霍夫曼編碼(Huffman coding)。不過實際上 H.264 有提供現成的編碼表,大部分清況下編碼器只需參照編碼即可,並不以自己計算產生專屬的編碼表。此編碼方式較基礎,碼字的長度皆為整數,如果遇到某個值發生頻率高於50%的情況下,受限於碼字不能小於1的情況,壓縮效率較差,也沒有處理傳輸錯誤的情況。適應性可變長度編碼是基線設定檔 (baseline profile) 使用的熵編碼方式。

適應性二元算術編碼 (Context-based Adaptive Binary Arithmetic Coding, CBABC)

是以算術編碼(arithmetic coding)為基礎。此編碼計算方式較複雜,僅主設定檔提供支援,但能較適應性可變長度編碼更接近理論壓縮極限,壓縮效率較佳。

Apple VideoToolbox 的相關設定

檢視 Apple 的 VideoToolbox 裡面跟 H.264 相關的介面,VTCompressionProperties.h。我們可以尋找跟本文主題相關設定。

可選擇設定檔(profile),從基線設定檔、主設定檔與高設定檔(high profile)。

VT_EXPORT const CFStringRef kVTCompressionPropertyKey_ProfileLevel;

VT_EXPORT const CFStringRef kVTProfileLevel_H264_Baseline_1_3;
VT_EXPORT const CFStringRef kVTProfileLevel_H264_Baseline_3_0;
...
VT_EXPORT const CFStringRef kVTProfileLevel_H264_ConstrainedHigh_AutoLevel;

像下面這是與設定是否使用 B 影格相關。

VT_EXPORT const CFStringRef kVTCompressionPropertyKey_AllowFrameReordering;

如同我們講到,編碼器量化參數不提供直接設定,而是設定平均位元率,交由編碼器決定。

VT_EXPORT const CFStringRef kVTCompressionPropertyKey_AverageBitRate;

支援本文所提的兩種熵編碼的方式。

VT_EXPORT const CFStringRef kVTCompressionPropertyKey_H264EntropyMode;

VT_EXPORT const CFStringRef kVTH264EntropyMode_CAVLC;
VT_EXPORT const CFStringRef kVTH264EntropyMode_CABAC;

文件在解釋適應性二元算術編碼時,提醒我們應選擇支援的設定檔,避免產生錯誤結果。然而,在具備了對編碼器的知識後,這種設定錯誤就不容易產生。

/**
...
Care should be taken when using this property -- changes may result in a configuration
which is not compatible with a requested Profile and Level. Results in this case are undefined,
and could include encode errors or a non-compliant output stream.
*/

結語

經過「預測」->「轉換」->「熵編碼」的處理,影格資料基本上就完成編碼輸出了。解碼器將拿到的資訊進行逆向處理,就可以解碼還原成影格顯示了。解碼器只要依據指示進行逆運算,相較之下是較簡單,可在運算力較差的裝置執行。

對比之下,編碼器在各階段要依據使用者要求做出適合的組合,像是預測階段要選擇預測方式、搜尋範圍內適合預測的巨集區塊,轉換階段要選擇適合的量化參數,熵編碼也要選擇適合的編碼表,這樣的決策組合可多達上百種,也就需要更有力的機器。

我們在進行存擋影片或直播影片編碼參數調教時,可以藉由對編碼器較深入的認識,選擇適當的組合。例如直播時,可以關閉 B 預測模式縮短延遲。在接收端運算能力充足的情況下,可以選擇主設定檔以使用壓縮效率更好的適應性二元算術編碼等。另外我們也會知道當我們調低目標位元率時,編碼時會傾向用更高的量化參數,也就代表犧牲更多畫質,來達成目的。

參考資料
Richardson, Iain. E. G. The H.264 advance video compression standard: Wiley, 2010.

名詞翻譯參考
國家教育研究院—樂詞網

--

--