上一篇:H264的基本原理(二)------ H264編碼原理
1、H264的結構圖
2、H264的編碼分層
H.264原始碼流(裸流)是由一個接一個NALU組成,它的功能分爲兩層,VCL(視頻編碼層)和 NAL(網絡提取層).
(1)NAL層 (視頻數據網絡抽象層)
因爲H264最終還是要在網絡上進行傳輸,在傳輸的時候,網絡包的最大傳輸單元是1500字節,一個H264的幀往往是大於1500字節的,所以需要將一個幀拆成多個包進行傳輸。這些拆包、組包等工作都在NAL層去處理。
(2)VCL層 (視頻編碼層)
對視頻的原始數據進行壓縮。
3、碼流的基本概念
(1)SODB ,String Of Data Bits 原始數據比特流
因爲它是流的形式,所以長度不一定是8倍數,它是由 VLC 層產生的。由於我們計算機是以8倍數去處理數據所以計算機在處理H264時,就需要 RBSP。
(2)RBSP,SODB + tailing bits (原始字節序列載荷)
由於它是一個壓縮流,SODB 不知道是在何處結束,所以算法在SODB最後一位補一個1,沒有按字節對齊的則補 0。
(3)EBSP (擴展字節序列載荷)
在生成壓縮流之後,在每一幀的開頭加一個起始位,這個起始位一般是 00 00 00 01 或者是 00 00 01。所以在h264碼流中規定每有兩個連續的00 00,就增加一個0x03。
補充:EBSP 和 RBSP的區別
A、NALU的主體涉及到三個重要的名詞,分別爲EBSP、RBSP和SODB。其中EBSP完全等價於NALU主體,而且它們三個的結構關係爲:EBSP包含RBSP,RBSP包含SODB。
在h264的文檔中,並沒有EBSP這一名詞出現,但是在h264的官方參考軟件JM裏,卻使用了EBSP。NALU的組成部分爲:
NALU = NALU Header + RBSP
其實嚴格來說,這個等式是不成立的,因爲RBSP並不等於NALU刨去NALU Header。嚴格來說,NALU的組成部分應爲:
NALU = NALU Header + EBSP
其中的EBSP爲擴展字節序列載荷(Encapsulated Byte Sequence Payload),而RBSP爲原始字節序列載荷(Raw Byte Sequence Payload)。
B、那爲什麼要弄一個EBSP呢?
EBSP相較於RBSP,多了防止競爭的一個字節:0x03。
我們知道,NALU的起始碼爲0x000001或0x00000001,同時H264規定,當檢測到0x000000時,也可以表示當前NALU的結束。那這樣就會產生一個問題,就是如果在NALU的內部,出現了0x000001或0x000000時該怎麼辦?
所以H264就提出了“防止競爭”這樣一種機制,當編碼器編碼完一個NAL時,應該檢測NALU內部,是否出現如下左側的四個序列。當檢測到它們存在時,編碼器就在最後一個字節前,插入一個新的字節:0x03。
這樣一來,當我們拿到EBSP時,就需要檢測EBSP內是否有序列:0x000003,如果有,則去掉其中的0x03。這樣一來,我們就能得到原始字節序列載荷:RBSP。
(4)NALU(NAL Unit)
在EBSP的基礎上,加1字節的NAL 頭
NAL Header(1B) + EBSP
4、NAL Unit
如上圖所示,生成的H264視頻幀是由多個切片組成的。一個H264的幀至少由一個切片組成,不能沒有切片,可以是一個到多個不能沒有。在網絡傳輸的時候一個H264幀可能需要切開去傳,一個一次傳不完,這就按照切片來切。每一個切片組成一個NAL Unit。
5、切片 與 宏塊的關係
宏塊分類 | 意義 |
---|---|
mb_type(宏塊類型) | 確定該 MB 是幀內或幀間(P 或 B)編碼模式,確定該 MB 分割的尺寸 |
mb_pred(宏塊的預測) | 確定幀內預測模式(幀內宏塊)確定表 0 或表 1 參考圖 像,和每一宏塊分割的差分編碼的運動矢量(幀間宏塊,除 8×8 宏塊分割的幀內 MB) |
sub_mb_pred | (只對 8×8MB 分割的幀內 MB)確定每一子宏塊的子宏 塊分割,每一宏塊分割的表 0 和/或表 1 的參考圖象;每一 宏塊子分割的差分編碼運動矢量。 |
coded_block_pattern | 指出哪個 8×8 塊(亮度和彩色)包 編碼變換系數 |
mb_qp_delta | 量化參數的改變值 |
residual(殘差數據) | 預測後對應於殘差圖象取樣的編碼變換系數 |
在切片數據中,包含若干個宏塊。在一個宏塊中,又包含了宏塊類型、宏塊預測、殘差數據。
5、切片 與 宏塊的關係
H264碼流的分層結構,如圖:
1幀 = n個片
1片 = n個宏塊
1宏塊 = 16x16yuv數據
內容參考: