從這篇開始,我們進入H264的學習實踐,主要分三個階段
- 學習H264基本結構和碼流協議;2. 瞭解具體編碼壓縮技術;3. 分析瞭解相關開源庫 x264和h264bitstream。
這篇我們來一起學習H264的基本結構
目錄
- H264/AVC的目標和方案
- H264分層結構- VCL和NAL
- NALU HEAD解析
- NALU payload
- I/P/B幀的特點
- 切片Slice和宏塊
- 資料
- 收穫
一、H264/AVC的目標和方案
音視頻編碼的標準由標準發展組織制定,主要兩大組織:ISO(國際標準化組織和國際電工委員會)和ITU-T(國際電信聯盟的電信標準化部門)
MPEG-1、MPEG-2、MPEG-4 part2、有ISO制定
H.261、H.262、H.263有ITU-T制定
H264/MPEG-4 part10 以及HEVC(h265) 有ISO和ITU-T等聯合制定
H.264 的主要目標:
1)高的視頻壓縮比,當初提出的指標是比H.263,MPEG-4,約爲它們的2 倍,現在都已基本實現;
2)良好的網絡親和性,即可適用於各種傳輸網絡。
爲此,H.264 的功能分爲兩層,即視頻編碼層(VCL)和網絡提取層(NAL)。
VCL 數據即編碼處理的輸出,它表示被壓縮編碼後的視頻數據序列。
在VCL 數據傳輸或存儲之前,這些編碼的VCL 數據,先被映射或封裝進NAL 單元中。
*** h264編碼的主要流程**
壓縮技術
H264/MPEG-4 part10 是運用比較廣泛的編碼標準協議
爲了實現目標,H264在H263的基礎上增加了如下壓縮技術
1. 雙向運動補償
2. 以小塊進行的可變塊運動補償
3. 四分之一像素運動補償
4. 環路濾波器
5. 變長編碼
6. 加權預測
7. 可伸縮視頻編碼
8. 多視點編碼等
二、H264分層結構- VCL和NAL
上一小節,我們爲了實現H264的兩個目標,H264功能上進行了分層,視頻編碼層(VCL, Video Coding Layer)和網絡提取層(NAL, Network Abstraction Layer)。
其中,VCL(Video Coding Layer)視頻編碼層,包括核心壓縮引擎和塊、宏塊和片的語法級別定義,設計目標是儘可能地獨立於網絡進行高效的編碼,負責有效表示視頻數據的內容。
而 NAL(Network Abstraction Layer)網絡提取層,負責將 VCL 產生的比特字符串適配到各種各樣的網絡和多元環境中,覆蓋了所有片級以上的語法級別; 一個NALU 單元常由 [NALU Header] + [NALU Payload] 部分組成,
NAL對VCL進行了封裝包裹
三、NALU HEAD解析
爲了分析H264,我們先通過如下命令 提取視頻
保留編碼格式:ffmpeg -i test.mp4 -vcodec copy -an test_copy.h264
強制格式:ffmpeg -i test.mp4 -vcodec libx264 -an test.h264
然後用010Editor打開提取的h264文件,如下所示:
H264 分成兩種流格式,一種是 Annex-B 格式(上圖看到的就是這種格式),一種是 RTP 包流的格式。
Annex-B 格式是默認的輸出格式。數據單元的分割使用[StartCode] (0x000001或0x00000001 )作爲起始碼。
NALU 單元常由 [NALU Header] [NALU Payload] 組成,
NALU Header是緊隨StartCode後的一個字節,按照位劃分三塊。
其中第1位,表示禁止位,爲1禁止使用該NALU單元,爲0可以使用。
第2-3位是參考級別(NRI,NAL ref idc)表示重要性,值越大說明越重要。比如在做丟幀處理時,就是通過這兩位來判斷該幀是否被依賴,進而決定是否可以被丟棄。
後面的5位表示NLAU的類型,其值的含義具體見下表
圖片來自:https://zhuanlan.zhihu.com/p/71928833
我們可以看到NAL類型分爲兩類,VCL和非VCL。其中 包含圖像數據的unit屬於VCL NAL units; SPS、PPS、和SEI 屬於Non-VCL NAL Units;
下面我們分別看下 我們的h264截圖中的 06、67、68代表什麼意思?
0x06 --二進制化--》00000110 --取後五位--》000 00110 值位6 ,查看上表,發現是SEI即補充增強信息單元,可以向視頻碼流中加入額外信息的方法
0x67 --二進制化--》01100111 --取後五位--》000 00111 值位7 ,查看上表,發現是SPS 即序列參數集,保存了一組編碼視頻序列(Coded Video Sequence)的全局參數
0x68 --二進制化--》01101000 --取後五位--》000 01000 值位8 ,查看上表,發現是PPS 即圖像參數集,該類型保存了整體圖像相關的參數。
除了上面這些,更多的是00 00 00 01 41,或者00 00 00 01 01那麼41、01又是什麼吶?
0x41 --二進制化--》01000001 --取後五位--》000 00001 值位1 ,查看上表,發現是非IDR幀,可以是 I/P/B幀
其中IDR是一種I幀,告訴解碼器,之前依賴的解碼參數集合可以被刷新了
0x01 --二進制化--》00000001 --取後五位--》000 00001 值位1 ,查看上表,發現是非IDR幀,可以是 I/P/B幀 ,相比41,這個幀的重要性很低,可以丟棄
四、NALU payload
NALU的主體涉及到三個重要的名詞,分別爲EBSP、RBSP和SODB。其中EBSP完全等價於NALU主體,而且它們三個的結構關係爲:
EBSP包含RBSP,RBSP包含SODB。
** SODB: String Of Data Bits** 原始數據比特流,就是最原始的編碼/壓縮得到的數據
RBSP: Raw Byte Sequence Payload,又稱原始字節序列載荷。和SODB關係如下:
RBSP = SODB + RBSP Trailing Bits(RBSP尾部補齊字節)
引入RBSP Trailing Bits做8位字節補齊。
EBSP: Encapsulated Byte Sequence Payload: 擴展字節序列載荷
如果RBSP種也包括了StartCode(0x000001
或0x00000001
)怎麼辦呢?所以,就有了防止競爭字節(0x03
)
編碼時,掃描RBSP,如果遇到連續兩個0x00
字節,就在後面添加防止競爭字節(0x03
);解碼時,同樣掃描EBSP,進行逆向操作即可。
圖片來自:視頻和視頻幀:H264編碼格式整理
圖片來自:H264/AVC 句法和語義詳解(三):NALU詳解二(EBSP、RBSP與SODB
五、I/P/B幀的特點
通過第三小節我們通過 NAL的Type表瞭解到。5代表IDR幀、1代表非IDR幀。這一小節,我們就來了解下視頻的I/P/B幀。
I幀:幀內編碼幀 intra picture,關鍵幀,I 幀通常是每個 GOP的第一個幀,進行幀內預測壓縮,作爲P/B幀的參考幀。
I幀的特點如下:
它是一個全幀壓縮編碼幀。它將全幀圖像信息進行JPEG壓縮編碼及傳輸;
解碼時僅用I幀的數據就可重構完整圖像;
I幀描述了圖像背景和運動主體的詳情;
I幀不需要參考其他畫面而生成;
I幀是P幀和B幀的參考幀(其質量直接影響到同組中以後各幀的質量);
I幀是幀組GOP的基礎幀(第一幀),在一組中只有一個I幀;
I幀不需要考慮運動矢量;
I幀所佔數據的信息量比較大。
P幀: 前向預測編碼幀 predictive-frame,主要進行幀間編碼,參考前面的I/P幀,去除時間冗餘信息,P幀沒有完整畫面數據,只有與前面I/P的畫面差別的數據。解碼時需要用之前緩存I/P幀疊加上本幀的差異數據,生成最終畫面
P幀的特點如下:
P幀是I幀後面相隔1~2幀的編碼幀;
P幀採用運動補償的方法傳送它與前面的I或P幀的差值及運動矢量(預測誤差);
解碼時必須將I幀中的預測值與預測誤差求和後才能重構完整的P幀圖像;
P幀屬於前向預測的幀間編碼。它只參考前面最靠近它的I幀或P幀;
P幀可以是其後面P幀的參考幀,也可以是其前後的B幀的參考幀;
由於P幀是參考幀,它可能造成解碼錯誤的擴散;
由於是差值傳送,P幀的壓縮比較高。
B幀: 雙向預測幀 bi-directional interpolated prediction frame,考慮前面的I/P幀以及後面的P幀之間的時間冗餘信息來壓縮傳輸數據量的編碼圖像;要解碼B幀,不僅要取得之前的緩存畫面,還要解碼之後的畫面,通過前後畫面的與本幀數據的疊加取得最終的畫面。B幀壓縮率高,但是解碼時CPU消耗多些。
B幀特點如下:
B幀是由前面的I或P幀和後面的P幀來進行預測的;
B幀傳送的是它與前面的I或P幀和後面的P幀之間的預測誤差及運動矢量;
B幀是雙向預測編碼幀;
B幀壓縮比最高,因爲它只反映丙參考幀間運動主體的變化情況,預測比較準確;
B幀不是參考幀,不會造成解碼錯誤的擴散。
GOP:兩個I幀之間是一個圖像序列,主要用作形容一個 i 幀 到下一個 i 幀之間的間隔了多少個幀,一個序列的第一個圖像是 IDR 圖像(立即刷新圖像),IDR 圖像都是 I 幀圖像。
增大GOP圖片組能有效的減少編碼後的視頻體積,但是也會降低視頻質量。
GOP 越長,B 幀所佔比例更高,編碼的率失真性能越高。
使用H.264 Video ES Viewer工具打開一個test.264文件 查看每個NAL的類型以及VCL數數據大小以及幀類型。
六、切片Slice和宏塊
GOP、幀、片、宏之間的關係
片的主要作用是用作宏塊(Macroblock)的載體, 目的是爲限制誤碼的擴散和傳輸。
如何限制誤碼的擴散和傳輸?
每個片(slice)都應該是互相獨立被傳輸的,某片的預測(片內預測和片間預測)不能以其它片中的宏塊(Macroblock)爲參考圖像。
每個分片也包含着頭和數據兩部分:
分片頭中包含着分片類型、宏塊類型、幀的數量、分片屬於那個圖像以及對應的幀的設置和參數等信息。
分片數據中則是宏塊,這裏就是我們要找的存儲像素(YUV)數據的地方
什麼是宏塊
宏塊是視頻信息的主要承載者,因爲它包含着每一個像素的亮度和色度信息。視頻解碼最主要的工作則是提供高效的方式從碼流中獲得宏塊中的像素陣列。
組成部分:一個宏塊由一個16×16亮度像素和附加的一個8×8 Cb和一個 8×8 Cr 彩色像素塊組成。每個圖象中,若干宏塊被排列成片的形式。
** 常用的宏塊類型:**
I宏塊:採用幀內預測宏塊,可能位於I/P/B幀(因爲在P和B幀中也是可以進行幀內預測的)
P宏塊:採用單向幀間預測,只存在於P幀
B宏塊:採用雙向幀間預測,只存在於B幀
** 切片(slice)類型跟宏塊類型的關係**
I片:只包 I宏塊,I 宏塊利用從當前片中已解碼的像素作爲參考進行幀內預測(不能取其它片中的已解碼像素作爲參考進行幀內預測)。
P片:可包 P和I宏塊,P 宏塊利用前面已編碼圖象作爲參考圖象進行幀內預測,一個幀內編碼的宏塊可進一步作宏塊的分割:即 16×16、16×8、8×16 或 8×8 亮度像素塊(以及附帶的彩色像素);如果選了 8×8 的子宏塊,則可再分成各種子宏塊的分割,其尺寸爲 8×8、8×4、4×8 或 4×4 亮度像素塊(以及附帶的彩色像素)。
B片:可包 B和I宏塊,B 宏塊則利用雙向的參考圖象(當前和 來的已編碼圖象幀)進行幀內預測。
SP片(切換P):用於不同編碼流之間的切換,包含 P 和/或 I 宏塊
SI片:擴展檔次中必須具有的切換,它包 了一種特殊類型的編碼宏塊,叫做 SI 宏塊,SI 也是擴展檔次中的必備功能。
我們通過H264Visa工具來查看h264的 NALU、Slice、marcoblock、以及YUV數據如下:
七、資料
本篇的內容很多來下面的參考資料的學習,結合自己的理解進行整理和描述,以及通過碼流分析工具進行查看分析。 感謝如下作者的輸出。
- 圖書 《視頻編碼全角度詳解》
- 圖書 《新一代視頻壓縮編碼標準 — H.264/AVC》
- 李超-H264基本原理
- 深入淺出理解視頻編碼H264結構
- 視頻和視頻幀:H264編碼格式整理
- H264編碼總結
- VCL & NAL (H.264/AVC)
八、收穫
通過本篇的學習
- 瞭解H264的結構 VCL和NAL的分層
- 瞭解NALU HEAD對應的一個字節代表的含義和類型,SPS、PPS、SEI、IDR、非IDR等,以及瞭解I/P/B幀的特性
- 瞭解NALU PayLoad的結構
- 瞭解對幀分片和宏塊的定義和目的。
- 通過碼流分析工具結合實踐更好的理解。
感謝你的閱讀
下一篇我們分析學習H264的編碼技術之幀內預測,歡迎關注公衆號“音視頻開發之旅”,一起學習成長。
歡迎交流