音視頻開發-H264數據組成

H264

H264結構中,一個視頻圖像編碼後的數據叫做一,一幀由一個片(slice)或多個片組成,一個由一個或多個宏塊(MB)組成,一個宏塊由16x16的yuv數據組成。宏塊作爲H264編碼的基本單位。

一個宏塊由一個16×16亮度像素和附加的一個8×8 Cb和一個8×8 Cr彩色像素塊組成,我們常見的YUV格式I420

SODB(數據比特串) 最原始的編碼數據,即VCL數據;

RBSP(原始字節序列載荷)SODB的後面填加了結尾比特(RBSP trailing bits 一個bit“1”)若干比特“0”,以便字節對齊;

EBSP( 擴展字節序列載荷)RBSP基礎上填加了仿校驗字節(0X03)它的原因是:在 NALU 加到Annexb上時,需要添加每組NALU之前的開始碼StartCodePrefix(0x00000001 or 0x000001),如果該NALU對應的slice一幀的開始則用4位字節表示,0x00000001,否則用3位字節表示0x000001(是一幀的一部分)。另外,爲了使NALU主體中不包括與開始碼相沖突的,在編碼時,每遇到兩個字節連續爲0,就插入一個字節的0x03。解碼時將0x03去掉。也稱爲脫殼操作

注: 0x00表示16進制2位,則2進制的八位(8bit = 1byte)。即一個字節。所以0x00 00 00 01是4位字節,0x00 00 01是3位字節。

數據構成 NAL

NAL (Network Abstract Layer), 即網絡抽象層。
一般來說編碼器編出的首幀數據爲PPSSPS,接着爲I幀,然後是P幀
在這裏插入圖片描述
在這裏插入圖片描述
編碼器將每個NAL各自獨立、完整地放入一個分組,因爲分組都有頭部,解碼器可以方便地檢測出NAL的分界,並依次取出NAL進行解碼。

起始碼、結束碼

每個 NAL 前有一個起始碼 0x00 00 01(或者0x00 00 00 01),解碼器檢測每個起始碼,作爲一個NAL的起始標識,當檢測到下一個起始碼時,當前NAL結束。

同時H.264規定,當檢測到0x000000時,也可以表徵當前NAL的結束。那麼NAL中數據出現0x0000010x000000時怎麼辦?H.264引入了防止競爭機制,如果編碼器檢測到NAL數據存在0x0000010x000000時,編碼器會在最後個字節前插入一個新的字節0x03,這樣:

0x000000>0x00000300
0x000001>0x00000301
0x000002>0x00000302
0x000003>0x00000303

解碼器檢測到0x000003時,把03拋棄,恢復原始數據(脫殼操作)。解碼器在解碼時,首先逐個字節讀取NAL的數據,統計 NAL 的長度,然後再開始解碼。

網絡傳輸結構 NALU

H264在網絡傳輸的是NALUNALU的結構是:NAL頭+RBSP,實際傳輸中的數據流如圖所示:
在這裏插入圖片描述
NALU頭用來標識後面的RBSP什麼類型的數據,是否會被其他幀參考以及網絡傳輸是否有錯誤。

NAL Header

NALU頭結構
長度:1byte(1字節) = 8位
forbidden_bit(1bit) + nal_reference_bit(2bit) + nal_unit_type(5bit)

  1. forbidden_bit:禁止位,初始爲0,當網絡發現NAL單元有比特錯誤時可設置該比特爲1,以便接收方糾錯或丟掉該單元。
  2. nal_reference_bit:nal重要性指示,標誌該NAL單元的重要性,值越大,越重要,解碼器在解碼處理不過來的時候,可以丟掉重要性爲0的NALU

例如: 0x65 表示關鍵幀IDR

0 11 00101
禁止位 = 0
相關性 = 11
NAL類型 = 5

這裏以16進制顯示 2^4=16,4位,即0110 = 60101 = 5
最後數據爲0x65
即一個起始碼0x00000001 + 0x65 + RBSP
0x000001的開頭一般是當一幀數據比較大時,需要拆分爲幾個子段,子段的開頭就是0x000001開頭的,一幀的開頭就是3000x00000001 (4位字節)

nal_unit_type

NAL類型

nal_reference_bit

0

未使用

0

1

非IDR的片

此片屬於參考幀,則不等於0,

不屬於參考幀,則等與0

2

片數據A分區

同上

3

片數據B分區

同上

4

片數據C分區

同上

5

IDR圖像的片

6

6

補充增強信息單元(SEI)

0

7

序列參數集

非0

8

圖像參數集

非0

9

分界符

0

10

序列結束

0

11

碼流結束

0

12

填充

0

13..23

保留

0

24..31

不保留

0

在這裏插入圖片描述
所謂參考幀,就是在其他幀解碼時需要參照的幀。比如一個I幀可能被一個或多個B幀參考,一個B幀可能被某個P幀參考。

IDRI幀是非常重要的,他一丟,那麼這個序列的所有幀都沒辦法解碼了

序列參數集(SPS)圖像參數集(PPS)也很重要,沒有序列參數集(SPS),這個序列的幀就沒法解;
沒有圖像參數集(PPS),那用到這個圖像參數集(PPS)的幀都沒法解。

NALU順序

H.264/AVC標準對送到解碼器的NAL單元順序是有嚴格要求的,如果NAL單元的順序是混亂的,必須將其重新依照規範組織後送入解碼器,否則解碼器不能夠正確解碼。

  1. 序列參數集SPS

    必須在傳送所有以此參數集爲參考的其他NAL單元之前傳送,不過允許這些NAL單元中間出現重複的序列參數集NAL單元。

    所謂重複的詳細解釋爲:序列參數集NAL單元都有其專門的標識,如果兩個序列參數集NAL單元的標識相同,就可以認爲後一個只不過是前一個的拷貝,而非新的序列參數集。

  2. 圖像參數集PPS

    必須在所有以此參數集爲參考的其他NAL單元之前傳送,不過允許這些NAL單元中間出現重複的圖像參數集NAL單元,這一點與上述的序列參數集NAL單元是相同的。

  3. 不同基本編碼圖像中的片段(slice)單元和數據劃分片段(data partition)單元在順序上不可以相互交叉,即不允許屬於某一基本編碼圖像的一系列片段(slice)單元和數據劃分片段(data partition)單元中忽然出現另一個基本編碼圖像的片段(slice)單元片段和數據劃分片段(data partition)單元。

  4. 參考圖像的影響:如果一幅圖像P2以另一幅圖像P1爲參考,則屬於P2的所有片段(slice)單元和數據劃分片段(data partition)單元必須在屬於P1的片段和數據劃分片段之後,無論是基本編碼圖像還是冗餘編碼圖像都必須遵守這個規則。

  5. 基本編碼圖像的所有片段(slice)單元和數據劃分片段(data partition)單元必須在屬於相應冗餘編碼圖像的片段(slice)單元和數據劃分片段(data partition)單元之前。

  6. 如果數據流中出現了連續的無參考基本編碼圖像,則圖像序號小的在前面。

  7. 如果 arbitrary_slice_order_allowed_flag 置爲1,一個基本編碼圖像中的片段(slice)單元和數據劃分片段(data partition)單元的順序是任意的,如果 arbitrary_slice_order_allowed_flag 置爲零,則要按照片段中第一個宏塊的位置來確定片段的順序,若使用數據劃分,則A類數據劃分片段在B類數據劃分片段之前,B類數據劃分片段在C類數據劃分片段之前,而且對應不同片段的數據劃分片段不能相互交叉,也不能與沒有數據劃分的片段相互交叉。

  8. 如果存在SEI(補充增強信息)單元的話,它必須在它所對應的基本編碼圖像的片段(slice)單元和數據劃分片段(data partition)單元之前,並同時必須緊接在上一個基本編碼圖像的所有片段(slice)單元和數據劃分片段(data partition)單元后邊。假如 SEI 屬於多個基本編碼圖像,其順序僅以第一個基本編碼圖像爲參照。

  9. 如果存在圖像分割符的話,它必須在所有 SEI 單元基本編碼圖像的所有片段slice)單元和數據劃分片段(data partition)單元之前,並且緊接着上一個基本編碼圖像那些NAL單元

  10. 如果存在序列結束符,且序列結束符後還有圖像,則該圖像必須是IDR(即時解碼器刷新)圖像。序列結束符的位置應當在屬於這個IDR圖像的分割符、SEI 單元等數據之前,且緊接着前面那些圖像的NAL單元。如果序列結束符後沒有圖像了,那麼它的就在比特流中所有圖像數據之後。

  11. 流結束符在比特流中的最後。

H264的官方文檔 :http://read.pudn.com/downloads208/sourcecode/multimedia/981579/H.264%E5%AE%98%E6%96%B9%E4%B8%AD%E6%96%87%E7%89%88.pdf

參考自文章:
https://blog.csdn.net/yuanchunsi/article/details/73194569
https://blog.csdn.net/yangzhongxuan/article/details/8003494

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章