如何讀標準和代碼(H.264)

轉自 http://bbs.chinavideo.org/viewthread.php?tid=4164&extra=page%3D1%26amp%3Bfilter%3Ddigest

首先,還是要弄清楚編解碼的流程和 H.264 的關鍵技術,看白皮書就知道了,另外 H.264 綜述類



的文章和別人的學位論文一般也會講到;
其次其次,弄清楚代碼的各個函數實現的功能,這個可以看看 JM 代碼裏各個函數前面的函數說明



最後最後,弄清楚標準各個章節講的什麼內容:這裏只說重要的。第三章是名詞解釋,第四章是縮


略語,第五章是一些計算方式和運算符號的說明,第六章是與 H.264 相關的一些視頻基礎知識和 


H.264 中用到的一些過程推導,第七章是 NALU 及其以下語法結構的語法和語義(如果要知道碼流


結構就要看這一章了),第八章是詳細說明解碼過程中某一個模塊的功能怎麼完成,第九章是熵編


碼,附錄 A 是關於 profile 和 level 的具體規定,附錄 B 是關於如何從字節流中解析 NALU(


標準沒有說明如何在 RTP 流中解析 NALU)。




     有了上面的基本知識,下面我們結合對碼流的解析過程來講講怎麼讀標準:
1、如果是字節流的碼流當然就首先要對字節流進行解析,這就要看附錄 B 了;如果是 RTP 格式的


碼流,那首先就要按 RFC3984 來解析了(標準沒有規定 RTP 格式碼流的解析過程);


2、字節流解析完後提取出來的就是 NALU 了,對 NALU 的解析就要看 7.3.1 小節了。第七章中黑


色的粗體字都是在碼流中可能出現的語法元素,解碼器的首要任務就是要對這些語法元素進行解析


。對於這些碼流中的語法元素我們要進行解析必須知道三個問題:
(1)、什麼時候存在於碼流中?這樣我們才能知道當前解析的是哪個語法元素;
(2)、採用什麼樣的熵編碼方式?這樣我們才能知道如何解析;
(3)、含義是什麼?這樣我們才知道解析出來之後用來幹什麼。
     三個問題的答案分別是:
(1)、有 if 條件關聯的就是可能出現的,沒有 if 條件關聯的就是必然出現的。例如,7.3.1 小


節表中的 forbidden_zero_bit 就沒有 if 條件關聯,所以它必然出現在碼流中;
(2)、每個語法表最後一列都對所在行語法元素的熵編碼方式做了規定,而最後一列各個符號具體


是代表什麼編碼方式那就去看 7.2 小節最後的部分;
(3)、看 7.4 小節與語法表對應的語義部分,例如你查的語法表是 7.3.1,那麼該語法表裏出現


的語法元素的解釋就在 7.4.1 小節中。


3、NALU 的前面三個語法元素所組成的一個字節我們稱爲 NALU 頭,其餘部分(也就是語法表 


7.3.1 中的其餘部分)我們稱爲 NALU 體。對 NALU 體的解析要看 7.3.2 小節。因爲 NALU 有很


多種類型,所以要針對 NALU 的不同類型去解析 NALU 體(表 7-1 說明了不同 NALU 對應的語法


表)。例如,如果當前的 NALU 是 SPS,那麼當然就要看 7.3.1 小節;如果當前的 NALU 是 DPA


,那麼當然就要看 7.3.2.9.1 小節了;


4、對於屬於 VCL 的 NALU(哪些 NALU 是 VCL NALU 呢?如果你看了 nal_unit_type 的語義,


你就應該知道),例如表 7-1 中類型爲 5 的 NALU,根據表 7-1 我們知道 NALU 體的語法表是 


7.3.2.8。而從 7.3.2.8 我們可以看到,對這種 NALU 的 NALU 體解析實際就是對片級語法進行解


析。語法表 7.3.2.8 顯示片級語法解析首先要解析 slice_header()(這種帶括號的表示是另一個


語法結構),那麼 slice_header() 怎麼解析呢?往下看,7.3.3 的所有內容都被第一行的 


slice_header() 包括在內,所以 7.3.3 就是對 slice_header() 這個語法層的碼流規定;


5、按照語法表 7.3.2.8 解析完了 slice_header() 就該解析 slice_data() 了。下面以最常見


的 I 幀(CAVLC 熵編碼、非 MBAFF)的解析過程爲例簡單描述怎麼繼續讀標準。這時在碼流中出現


的第一個 slice_data() 層的語法元素是語法表 7.3.4 中的 macroblock_layer(),也就是說直


接到了宏塊層的語法解析,那就要又要看 7.3.5 小節了;


6、基於我們對編解碼流程的瞭解,我們知道解碼是一個預測值加殘差得到重建圖像的過程,那麼我


們下面的解碼過程就要分成兩步走了:首先,得到預測值;其次,得到殘差。基於我們對 H.264 關


鍵技術的瞭解,我們知道 intra 宏塊(提醒:我們舉的例子是 I 幀,因此解析的是 intra 宏塊


)的預測值是需要使用到預測模式的,所以我們需要解析語法表 7.3.5 中的 mb_pred(mb_type) 


語法層,那麼又去看 7.3.5.1 小節。按照 7.3.5.1 小節解析出宏塊或塊的預測方式後我們怎麼計


算預測值呢?去看標準 8.3 小節;得到預測值後我們繼續按照語法表 7.3.5 解析語法元素直到 


residual() 語法層,這就又要去看 7.3.5.3 小節;按照 7.3.5.3 小節解析出殘差係數後我們如


何把它還原成真實的殘差呢?去看標準 8.5 小節;


7、預測值和殘差都有了,加起來就是解碼圖像了。解碼的主要工作到此也算基本完成了。當然,上


面的過程中還會用到標準其他章節的相關內容(例如,8.5 小節會用到 5.7 小節中定義的 


InverseRasterScan),這就留給大家自己去學習了。




      上面講了如何讀標準,那麼如何讀代碼呢?非常簡單,因爲你現在已經知道了代碼中各個函


數所實現的功能以及標準各個章節所涉及的內容,那麼你就該知道標準某個部分的內容與代碼中的


哪個函數對應,因此對於你想詳細瞭解實現過程的模塊,對照標準去仔細啃那個函數吧。對於代碼


中不明白的變量或者參數,把程序跑起來,看第 1 個 MB 解碼時候該變量的值是多少,第 23 個 


MB 解碼時候該變量的值是多少……多做幾個觀察值,注意不要選擇特殊位置,然後總結一下規律,


這樣你就自然能分析出該變量的作用和含義了。




      以上講的是解碼過程,編碼過程就是解碼的反過程,因此同理。








——天之驕子·firstime——
         2008年8月5日
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章