[原創(chuàng )] 如何讀標準和代碼 - H.264樂(lè )園 - 視頻技術(shù)論壇 中華視頻網(wǎng)|ffmpeg...
| 首先首先,還是要弄清楚編解碼的流程和 H.264 的關(guān)鍵技術(shù),看白皮書(shū)就知道了,另外 H.264 綜述類(lèi)的文章和別人的學(xué)位論文一般也會(huì )講到; 其次其次,弄清楚代碼的各個(gè)函數實(shí)現的功能,這個(gè)可以看看 JM 代碼里各個(gè)函數前面的函數說(shuō)明; 最后最后,弄清楚標準各個(gè)章節講的什么內容:這里只說(shuō)重要的。第三章是名詞解釋?zhuān)谒恼率强s略語(yǔ),第五章是一些計算方式和運算符號的說(shuō)明,第六章是與 H.264 相關(guān)的一些視頻基礎知識和 H.264 中用到的一些過(guò)程推導,第七章是 NALU 及其以下語(yǔ)法結構的語(yǔ)法和語(yǔ)義(如果要知道碼流結構就要看這一章了),第八章是詳細說(shuō)明解碼過(guò)程中某一個(gè)模塊的功能怎么完成,第九章是熵編碼,附錄 A 是關(guān)于 profile 和 level 的具體規定,附錄 B 是關(guān)于如何從字節流中解析 NALU(標準沒(méi)有說(shuō)明如何在 RTP 流中解析 NALU)。
有了上面的基本知識,下面我們結合對碼流的解析過(guò)程來(lái)講講怎么讀標準: 1、如果是字節流的碼流當然就首先要對字節流進(jìn)行解析,這就要看附錄 B 了;如果是 RTP 格式的碼流,那首先就要按 RFC3984 來(lái)解析了(標準沒(méi)有規定 RTP 格式碼流的解析過(guò)程);
2、字節流解析完后提取出來(lái)的就是 NALU 了,對 NALU 的解析就要看 7.3.1 小節了。第七章中黑色的粗體字都是在碼流中可能出現的語(yǔ)法元素,解碼器的首要任務(wù)就是要對這些語(yǔ)法元素進(jìn)行解析。對于這些碼流中的語(yǔ)法元素我們要進(jìn)行解析必須知道三個(gè)問(wèn)題: (1)、什么時(shí)候存在于碼流中?這樣我們才能知道當前解析的是哪個(gè)語(yǔ)法元素; (2)、采用什么樣的熵編碼方式?這樣我們才能知道如何解析; (3)、含義是什么?這樣我們才知道解析出來(lái)之后用來(lái)干什么。 三個(gè)問(wèn)題的答案分別是: (1)、有 if 條件關(guān)聯(lián)的就是可能出現的,沒(méi)有 if 條件關(guān)聯(lián)的就是必然出現的。例如,7.3.1 小節表中的 forbidden_zero_bit 就沒(méi)有 if 條件關(guān)聯(lián),所以它必然出現在碼流中; (2)、每個(gè)語(yǔ)法表最后一列都對所在行語(yǔ)法元素的熵編碼方式做了規定,而最后一列各個(gè)符號具體是代表什么編碼方式那就去看 7.2 小節最后的部分; (3)、看 7.4 小節與語(yǔ)法表對應的語(yǔ)義部分,例如你查的語(yǔ)法表是 7.3.1,那么該語(yǔ)法表里出現的語(yǔ)法元素的解釋就在 7.4.1 小節中。
3、NALU 的前面三個(gè)語(yǔ)法元素所組成的一個(gè)字節我們稱(chēng)為 NALU 頭,其余部分(也就是語(yǔ)法表 7.3.1 中的其余部分)我們稱(chēng)為 NALU 體。對 NALU 體的解析要看 7.3.2 小節。因為 NALU 有很多種類(lèi)型,所以要針對 NALU 的不同類(lèi)型去解析 NALU 體(表 7-1 說(shuō)明了不同 NALU 對應的語(yǔ)法表)。例如,如果當前的 NALU 是 SPS,那么當然就要看 7.3.1 小節;如果當前的 NALU 是 DPA,那么當然就要看 7.3.2.9.1 小節了;
4、對于屬于 VCL 的 NALU(哪些 NALU 是 VCL NALU 呢?如果你看了 nal_unit_type 的語(yǔ)義,你就應該知道),例如表 7-1 中類(lèi)型為 5 的 NALU,根據表 7-1 我們知道 NALU 體的語(yǔ)法表是 7.3.2.8。而從 7.3.2.8 我們可以看到,對這種 NALU 的 NALU 體解析實(shí)際就是對片級語(yǔ)法進(jìn)行解析。語(yǔ)法表 7.3.2.8 顯示片級語(yǔ)法解析首先要解析 slice_header()(這種帶括號的表示是另一個(gè)語(yǔ)法結構),那么 slice_header() 怎么解析呢?往下看,7.3.3 的所有內容都被第一行的 slice_header() 包括在內,所以 7.3.3 就是對 slice_header() 這個(gè)語(yǔ)法層的碼流規定;
5、按照語(yǔ)法表 7.3.2.8 解析完了 slice_header() 就該解析 slice_data() 了。下面以最常見(jiàn)的 I 幀(CAVLC 熵編碼、非 MBAFF)的解析過(guò)程為例簡(jiǎn)單描述怎么繼續讀標準。這時(shí)在碼流中出現的第一個(gè) slice_data() 層的語(yǔ)法元素是語(yǔ)法表 7.3.4 中的 macroblock_layer(),也就是說(shuō)直接到了宏塊層的語(yǔ)法解析,那就要又要看 7.3.5 小節了;
6、基于我們對編解碼流程的了解,我們知道解碼是一個(gè)預測值加殘差得到重建圖像的過(guò)程,那么我們下面的解碼過(guò)程就要分成兩步走了:首先,得到預測值;其次,得到殘差?;谖覀儗?H.264 關(guān)鍵技術(shù)的了解,我們知道 intra 宏塊(提醒:我們舉的例子是 I 幀,因此解析的是 intra 宏塊)的預測值是需要使用到預測模式的,所以我們需要解析語(yǔ)法表 7.3.5 中的 mb_pred(mb_type) 語(yǔ)法層,那么又去看 7.3.5.1 小節。按照 7.3.5.1 小節解析出宏塊或塊的預測方式后我們怎么計算預測值呢?去看標準 8.3 小節;得到預測值后我們繼續按照語(yǔ)法表 7.3.5 解析語(yǔ)法元素直到 residual() 語(yǔ)法層,這就又要去看 7.3.5.3 小節;按照 7.3.5.3 小節解析出殘差系數后我們如何把它還原成真實(shí)的殘差呢?去看標準 8.5 小節;
7、預測值和殘差都有了,加起來(lái)就是解碼圖像了。解碼的主要工作到此也算基本完成了。當然,上面的過(guò)程中還會(huì )用到標準其他章節的相關(guān)內容(例如,8.5 小節會(huì )用到 5.7 小節中定義的 InverseRasterScan),這就留給大家自己去學(xué)習了。
上面講了如何讀標準,那么如何讀代碼呢?非常簡(jiǎn)單,因為你現在已經(jīng)知道了代碼中各個(gè)函數所實(shí)現的功能以及標準各個(gè)章節所涉及的內容,那么你就該知道標準某個(gè)部分的內容與代碼中的哪個(gè)函數對應,因此對于你想詳細了解實(shí)現過(guò)程的模塊,對照標準去仔細啃那個(gè)函數吧。對于代碼中不明白的變量或者參數,把程序跑起來(lái),看第 1 個(gè) MB 解碼時(shí)候該變量的值是多少,第 23 個(gè) MB 解碼時(shí)候該變量的值是多少……多做幾個(gè)觀(guān)察值,注意不要選擇特殊位置,然后總結一下規律,這樣你就自然能分析出該變量的作用和含義了。
以上講的是解碼過(guò)程,編碼過(guò)程就是解碼的反過(guò)程,因此同理。
——天之驕子·firstime—— 2008年8月5日
| |
本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請
點(diǎn)擊舉報。