《H.264/AVC視訊編解碼技術詳解》視訊教程已經在“CSDN學院”上線,視訊中詳述了H.264的背景、標準協議和實現,並通過一個實戰工程的形式對H.264的標準進行解析和實現,歡迎觀看!

“紙上得來終覺淺,絕知此事要躬行”,只有自己按照標準文件以程式碼的形式操作一遍,才能對視訊壓縮編碼標準的思想和方法有足夠深刻的理解和體會!

GitHub程式碼地址:點選這裡

H.264中Slice Body——巨集塊結構(Macroblock)的解析

1.Slice Data結構的定義

在已經實現了一個slice的header部分之後,下面的工作將是研究如何解析一個slice的主體,即Slice Body部分。一個Slice的body部分主要是一個個的巨集塊結構Macroblock組成,此外還存在一些輔助的資訊。標準文件中規定的slice_data()結構如下圖:

從文件中我們可以看出,Slice_data結構中獨立的語法元素並不多,主要只有以下幾個:

  1. cabac_alignment_one_bit:表示如果碼流啟用了CABAC演算法,那麼碼流在這裡必須使用若干個位元1實現位元組對齊。
  2. mb_skip_run和mb_skip_flag:這兩個語法元素都用於表示巨集塊結構是否可以被跳過。“跳過”的巨集塊指的是,在幀間預測的slice中,當影象區域平坦時,碼流中跳過這個巨集塊的所有資料,不進行傳輸,只通過這兩個語法元素進行標記。在解碼端,跳過的巨集塊通過周圍已經重建的巨集塊來進行恢復。mb_skip_run用於熵編碼使用CAVLC時,用一個語法元素表示連續跳過的巨集塊的個數;mb_skip_flag用於熵編碼使用CABAC時,表示每一個巨集塊是否被跳過。
  3. mb_field_decoding_flag:標識位,用於在幀場自適應的碼流中標識某個巨集塊是幀模式還是場模式。
  4. end_of_slice_flag:在CABAC模式下的一個標識位,表示是否到了slice的末尾。

上述的幾個語法元素毫無疑問僅僅佔用了全部資料很少的一部分,其他大部分的資料都包含在巨集塊結構中,即上表中的macroblock_layer()結構。

2. 巨集塊(Macroblock)結構

從上表中我們可以看出,一個Slice結構中巨集塊實際上佔據了絕大部分。在標準中一個巨集塊的結構定義為下表:

(1). mb_type:

在一個巨集塊中,最開始的語法元素為巨集塊的型別:mb_type。從表中我們可以看出,根據mb_type的值是否等於I_PCM,整個解析方法分為兩大類:PCM型別和非PCM型別,判斷依據是當mb_type為25時為I_PCM模式,否則為非I_PCM模式。

當這個巨集塊為I_PCM模式時,巨集塊中以差分編碼的形式儲存巨集塊原始的畫素值。此時存在如下幾個語法元素:

  • pcm_alignment_zero_bit:填充位,用位元0來填充直到按位元組對齊;
  • pcm_sample_luma:256個亮度分量的差分畫素值;
  • pcm_sample_chroma:若干個色度分量的差分畫素值,實際數量由碼流的顏色格式指定。例如對於最常用的4:2:0格式的視訊,共有128個色度畫素值。

除了mb_type等於25時可以確定為I_PCM格式之外,其他的mb_type值可能根據幀型別(或slice型別)的不同而不同。比如對於I slice,mb_type的非PCM模式可以選擇0~24這些值之一;對於P slice,mb_type只能取0~4這5個值;對於B slice,mb_type可以取0~22這些值之一。目前我們所處理的碼流全部由I幀構成,因此我們暫時只考慮I slice的情況。下圖是標準文件中規定的I slice的mb_type列表的一部分,完整列表在協議文件的表7-11中:

從上表中我們可以看出,mb_type不僅僅表示了巨集塊的分割方式,還包含了一些其他的附加資訊,如幀內預測模式、亮度和色度分量的coded_block_pattern。當幀內預測使用16×16模式時,巨集塊整個巨集塊的預測資訊相同,因此不需要為各個子巨集塊分別指定預測模式,這樣可以有效減少消耗的碼流。

(2). transform_size_8x8_flag

該語法元素為一個標識位,用於表示在環路濾波之前,預測殘差的變換系數解碼時依照的尺寸。當該標識位為1時,預測殘差按照8×8畫素塊進行解碼;當該標誌位不存在或者為0時,預測殘差按照4×4畫素塊進行解碼。

(3). coded_block_pattern

coded_block_pattern語法元素常簡稱做cbp,用於表示當前巨集塊內的4個8×8子塊編碼對其中的哪個的殘差係數進行編碼。值得注意的是該語法元素僅僅在巨集塊為非I_16x16模式時才存在,因為在I_16x16模式時cbp的有關資訊已經在mb_type中體現。

(4). mb_qp_delta

mb_qp_delta表示巨集塊層的量化引數偏移值,取值範圍為[-26, 25]。我們在前面已經在PPS中獲取了整個序列的量化引數初始值(由pic_init_qp_minus26計算),在slice header中獲取slice層的量化引數偏移slice_qp_delta,因此每一個slice第一個巨集塊的量化引數可通過下面的公式計算:

QP0=pic_init_qp+26+slice_qp_delta+mb_qp_delta

從第二個巨集塊開始,每個巨集塊實際量化引數的計算方法為:
QPn=(QPm+mb_qp_delta+52)%52