H.264編碼格式簡單分析


  本文記錄一下H.264的編碼格式。H.264官方文檔:https://github.com/jiayayao/DataSheet/tree/master/encode-decode/h264

一、H.264編碼格式

  H.264從層次來看分為兩層:視頻編碼層(VCL, Video Coding Layer)和網絡提取層(NAL,Network Abstraction Layer)。VCL輸出的是原始數據比特流(SODB,String of data bits),表示H.264的語法元素編碼完成后的實際的原始二進制碼流。SODB通常不能保證字節對齊,故需要補齊為原始字節序列負荷(RBSP,Raw Byte Sequence Payload)。H.264引入了片(slice)的概念,每個片只攜帶該片自身獨有的句法元素,一個片的丟失不會影響其他片的解碼,還可以通過該片前后的片來恢復該片的解碼。

       NAL層實際上就是最終輸出的H.264碼流,它是由一個個NALU組成的,每個NALU包括一組對應於視頻編碼數據的NAL頭信息和一個原始字節序列負荷(RBSP,Raw Byte Sequence Payload)。以上名詞之間的關系如下:

RBSP = SODB + RBSP trailing bits
NALU = NAL header(1 byte) + RBSP
H.264 = Start Code Prefix(3 bytes) + NALU + Start Code Prefix(3 bytes) + NALU +…

  所以H.264碼流的結構如下:

  每個NALU之間由起始碼(Start Code Prefix)分隔,起始碼分為兩種:0x000001(3 bytes) or 0x00000001(4 bytes). 如果NALU 對應的Slice 為一幀的開始,則用4 字節表示,即0x00000001;否則用3 字節表示,0x000001.NALU針對起始碼設計了防止沖突機制,如果出現連續的0x000000,0x000001,0x000002,0x000003時,會在兩個0之間插入03,如下:

0x00 00 00 -> 0x00 00 03 00
0x00 00 01 -> 0x00 00 03 01
0x00 00 02 -> 0x00 00 03 02
0x00 00 03 -> 0x00 00 03 03

  一個NALU就是編碼后的一幀數據。NAL header是一個字節:

  forbidden_zero_bit(1 bit) 禁止位,等於0;

  nal_ref_idc(2 bit)指示當前NAL的優先級,取值范圍為0~3,值越高,表示當前NAL越重要。H.264規定,如果當前NAL是序列參數集,或是圖像參數等,該值必須大於0.比如nal_unit_type等於5時,nal_ref_idc大於0;nal_unit_type等於6,9,10,11或12時,nal_ref_idc等於0;

  nal_unit_type表示當前NALU的類型,表格如下:

nal_unit_type

NAL類型

C

0

未使用

 

1

不分區、非IDR圖像的片

2,3,4

2

片分區A

2

3

片分區B

3

4

片分區C

4

5

IDR圖像中的片

2,3

6

補充增強信息單元(SEI)

5

7

序列參數集(SPS)

0

8

圖像參數集(PPS)

1

9

 分界符

 6 

10

序列結束

7

11 碼流結束 8
12 填充 9
13~23 保留  
24~31 未使用  

  nal_unit_type=5時,表示當前NAL是IDR圖像的一個片,此時,IDR圖像中的每個片的nal_unit_type都應該等於5.

  一般H.264原始碼流是以SPS->PPS->SEI->IDR->SCLICE->SCLICE…開頭的。 

  GOP即Group of picture(圖像組),指兩個I幀之間的距離。即幾秒有一個關鍵幀。一般在2、3秒之間。

二、H.264 Tips

  H.264有兩種封裝格式:

  (1)annexb模式:傳統模式,使用start code來分隔NAL, SPS和PPS是在ES流的頭部;

        Annex-B: startCode Nalu1, startCode Nalu2......startCode NaluN

  (2)mp4模式:沒有start code,使用NALU長度(固定字節,通常為4個字節)來分隔NAL。AVCodecContext的extradata內部保存着分隔的字節數,SPS和PPS;

        mp4(AVCC): NaluLength Nalu1, LaluLength Lalu2, ......NaluLength NaluN

  SPS的頭部是0x67,PPS的頭部是0x68,要保持對數據的敏感性。

       IDR幀:IDR幀都是I幀,H.264引入IDR圖像是為了解碼的重同步,當解碼器解碼到IDR幀時,會立即將參考幀隊列清空,將已解碼的數據全部輸出或拋棄,重新查找參數及,開始一個新的序列。IDR幀之后的圖像永遠不會引用IDR幀之前圖像的數據來解碼。IDR幀一定是I幀,I幀不一定是IDR幀。

  當解碼器性能不足需要丟幀時,nal_ref_idc可以作為判斷能否丟幀的依據。如果nal_ref_idc為0,則可以丟棄。當該幀nal_unit_type等於6,9,10,11或12時,nal_ref_idc為0。部分非IDR幀的nal_ref_idc也為0,也可以丟棄。丟棄的同時也能保證不會花屏。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM