音視頻開發(fā)之旅(56) -H264/AVC基本結(jié)構(gòu)

從這篇開始,我們進(jìn)入H264的學(xué)習(xí)實踐,主要分三個階段

  1. 學(xué)習(xí)H264基本結(jié)構(gòu)和碼流協(xié)議;2. 了解具體編碼壓縮技術(shù);3. 分析了解相關(guān)開源庫 x264和h264bitstream。

這篇我們來一起學(xué)習(xí)H264的基本結(jié)構(gòu)

目錄

  1. H264/AVC的目標(biāo)和方案
  2. H264分層結(jié)構(gòu)- VCL和NAL
  3. NALU HEAD解析
  4. NALU payload
  5. I/P/B幀的特點
  6. 切片Slice和宏塊
  7. 資料
  8. 收獲

一、H264/AVC的目標(biāo)和方案

音視頻編碼的標(biāo)準(zhǔn)由標(biāo)準(zhǔn)發(fā)展組織制定,主要兩大組織:ISO(國際標(biāo)準(zhǔn)化組織和國際電工委員會)和ITU-T(國際電信聯(lián)盟的電信標(biāo)準(zhǔn)化部門)

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等聯(lián)合制定

H.264 的主要目標(biāo):

1)高的視頻壓縮比,當(dāng)初提出的指標(biāo)是比H.263,MPEG-4,約為它們的2 倍,現(xiàn)在都已基本實現(xiàn);
2)良好的網(wǎng)絡(luò)親和性,即可適用于各種傳輸網(wǎng)絡(luò)。
為此,H.264 的功能分為兩層,即視頻編碼層(VCL)和網(wǎng)絡(luò)提取層(NAL)。
VCL 數(shù)據(jù)即編碼處理的輸出,它表示被壓縮編碼后的視頻數(shù)據(jù)序列。
在VCL 數(shù)據(jù)傳輸或存儲之前,這些編碼的VCL 數(shù)據(jù),先被映射或封裝進(jìn)NAL 單元中。

*** h264編碼的主要流程**


壓縮技術(shù)
H264/MPEG-4 part10 是運用比較廣泛的編碼標(biāo)準(zhǔn)協(xié)議
為了實現(xiàn)目標(biāo),H264在H263的基礎(chǔ)上增加了如下壓縮技術(shù)

1. 雙向運動補(bǔ)償
2. 以小塊進(jìn)行的可變塊運動補(bǔ)償
3. 四分之一像素運動補(bǔ)償
4. 環(huán)路濾波器
5. 變長編碼
6. 加權(quán)預(yù)測
7. 可伸縮視頻編碼
8. 多視點編碼等

二、H264分層結(jié)構(gòu)- VCL和NAL

上一小節(jié),我們?yōu)榱藢崿F(xiàn)H264的兩個目標(biāo),H264功能上進(jìn)行了分層,視頻編碼層(VCL, Video Coding Layer)網(wǎng)絡(luò)提取層(NAL, Network Abstraction Layer)。
其中,VCL(Video Coding Layer)視頻編碼層,包括核心壓縮引擎和塊、宏塊和片的語法級別定義,設(shè)計目標(biāo)是盡可能地獨立于網(wǎng)絡(luò)進(jìn)行高效的編碼,負(fù)責(zé)有效表示視頻數(shù)據(jù)的內(nèi)容。
而 NAL(Network Abstraction Layer)網(wǎng)絡(luò)提取層,負(fù)責(zé)將 VCL 產(chǎn)生的比特字符串適配到各種各樣的網(wǎng)絡(luò)和多元環(huán)境中,覆蓋了所有片級以上的語法級別; 一個NALU 單元常由 [NALU Header] + [NALU Payload] 部分組成,
NAL對VCL進(jìn)行了封裝包裹

圖片來自:VCL & NAL (H.264/AVC)

三、NALU HEAD解析

為了分析H264,我們先通過如下命令 提取視頻

保留編碼格式:ffmpeg -i test.mp4 -vcodec copy -an test_copy.h264

強(qiáng)制格式:ffmpeg -i test.mp4 -vcodec libx264 -an test.h264

然后用010Editor打開提取的h264文件,如下所示:


H264 分成兩種流格式,一種是 Annex-B 格式(上圖看到的就是這種格式),一種是 RTP 包流的格式。
Annex-B 格式是默認(rèn)的輸出格式。數(shù)據(jù)單元的分割使用[StartCode] (0x000001或0x00000001 )作為起始碼。

NALU 單元常由 [NALU Header] [NALU Payload] 組成,

NALU Header是緊隨StartCode后的一個字節(jié),按照位劃分三塊。

其中第1位,表示禁止位,為1禁止使用該NALU單元,為0可以使用。
第2-3位是參考級別(NRI,NAL ref idc)表示重要性,值越大說明越重要。比如在做丟幀處理時,就是通過這兩位來判斷該幀是否被依賴,進(jìn)而決定是否可以被丟棄。
后面的5位表示NLAU的類型,其值的含義具體見下表

圖片來自:https://zhuanlan.zhihu.com/p/71928833
我們可以看到NAL類型分為兩類,VCL和非VCL。其中 包含圖像數(shù)據(jù)的unit屬于VCL NAL units; SPS、PPS、和SEI 屬于Non-VCL NAL Units;

下面我們分別看下 我們的h264截圖中的 06、67、68代表什么意思?

0x06 --二進(jìn)制化--》00000110 --取后五位--》000 00110 值位6 ,查看上表,發(fā)現(xiàn)是SEI即補(bǔ)充增強(qiáng)信息單元,可以向視頻碼流中加入額外信息的方法

0x67 --二進(jìn)制化--》01100111 --取后五位--》000 00111 值位7 ,查看上表,發(fā)現(xiàn)是SPS 即序列參數(shù)集,保存了一組編碼視頻序列(Coded Video Sequence)的全局參數(shù)

0x68 --二進(jìn)制化--》01101000 --取后五位--》000 01000 值位8 ,查看上表,發(fā)現(xiàn)是PPS 即圖像參數(shù)集,該類型保存了整體圖像相關(guān)的參數(shù)。

除了上面這些,更多的是00 00 00 01 41,或者00 00 00 01 01那么41、01又是什么吶?

0x41 --二進(jìn)制化--》01000001 --取后五位--》000 00001 值位1 ,查看上表,發(fā)現(xiàn)是非IDR幀,可以是 I/P/B幀

其中IDR是一種I幀,告訴解碼器,之前依賴的解碼參數(shù)集合可以被刷新了

0x01 --二進(jìn)制化--》00000001 --取后五位--》000 00001 值位1 ,查看上表,發(fā)現(xiàn)是非IDR幀,可以是 I/P/B幀 ,相比41,這個幀的重要性很低,可以丟棄

四、NALU payload

NALU的主體涉及到三個重要的名詞,分別為EBSP、RBSP和SODB。其中EBSP完全等價于NALU主體,而且它們?nèi)齻€的結(jié)構(gòu)關(guān)系為:
EBSP包含RBSP,RBSP包含SODB。

** SODB: String Of Data Bits** 原始數(shù)據(jù)比特流,就是最原始的編碼/壓縮得到的數(shù)據(jù)

RBSP: Raw Byte Sequence Payload,又稱原始字節(jié)序列載荷。和SODB關(guān)系如下:
RBSP = SODB + RBSP Trailing Bits(RBSP尾部補(bǔ)齊字節(jié))
引入RBSP Trailing Bits做8位字節(jié)補(bǔ)齊。

EBSP: Encapsulated Byte Sequence Payload: 擴(kuò)展字節(jié)序列載荷

如果RBSP種也包括了StartCode(0x0000010x00000001怎么辦呢?所以,就有了防止競爭字節(jié)(0x03

編碼時,掃描RBSP,如果遇到連續(xù)兩個0x00字節(jié),就在后面添加防止競爭字節(jié)(0x03;解碼時,同樣掃描EBSP,進(jìn)行逆向操作即可。

圖片來自:視頻和視頻幀:H264編碼格式整理

圖片來自:H264/AVC 句法和語義詳解(三):NALU詳解二(EBSP、RBSP與SODB

五、I/P/B幀的特點

通過第三小節(jié)我們通過 NAL的Type表了解到。5代表IDR幀、1代表非IDR幀。這一小節(jié),我們就來了解下視頻的I/P/B幀。


I幀:幀內(nèi)編碼幀 intra picture,關(guān)鍵幀,I 幀通常是每個 GOP的第一個幀,進(jìn)行幀內(nèi)預(yù)測壓縮,作為P/B幀的參考幀。
I幀的特點如下:

    它是一個全幀壓縮編碼幀。它將全幀圖像信息進(jìn)行JPEG壓縮編碼及傳輸; 
    解碼時僅用I幀的數(shù)據(jù)就可重構(gòu)完整圖像; 
    I幀描述了圖像背景和運動主體的詳情; 
    I幀不需要參考其他畫面而生成; 
    I幀是P幀和B幀的參考幀(其質(zhì)量直接影響到同組中以后各幀的質(zhì)量); 
    I幀是幀組GOP的基礎(chǔ)幀(第一幀),在一組中只有一個I幀; 
    I幀不需要考慮運動矢量; 
    I幀所占數(shù)據(jù)的信息量比較大。 

P幀: 前向預(yù)測編碼幀 predictive-frame,主要進(jìn)行幀間編碼,參考前面的I/P幀,去除時間冗余信息,P幀沒有完整畫面數(shù)據(jù),只有與前面I/P的畫面差別的數(shù)據(jù)。解碼時需要用之前緩存I/P幀疊加上本幀的差異數(shù)據(jù),生成最終畫面
P幀的特點如下:

    P幀是I幀后面相隔1~2幀的編碼幀; 
    P幀采用運動補(bǔ)償?shù)姆椒▊魉退c前面的I或P幀的差值及運動矢量(預(yù)測誤差); 
    解碼時必須將I幀中的預(yù)測值與預(yù)測誤差求和后才能重構(gòu)完整的P幀圖像; 
    P幀屬于前向預(yù)測的幀間編碼。它只參考前面最靠近它的I幀或P幀; 
    P幀可以是其后面P幀的參考幀,也可以是其前后的B幀的參考幀; 
    由于P幀是參考幀,它可能造成解碼錯誤的擴(kuò)散; 
    由于是差值傳送,P幀的壓縮比較高。 

B幀: 雙向預(yù)測幀 bi-directional interpolated prediction frame,考慮前面的I/P幀以及后面的P幀之間的時間冗余信息來壓縮傳輸數(shù)據(jù)量的編碼圖像;要解碼B幀,不僅要取得之前的緩存畫面,還要解碼之后的畫面,通過前后畫面的與本幀數(shù)據(jù)的疊加取得最終的畫面。B幀壓縮率高,但是解碼時CPU消耗多些。
B幀特點如下:

    B幀是由前面的I或P幀和后面的P幀來進(jìn)行預(yù)測的; 
    B幀傳送的是它與前面的I或P幀和后面的P幀之間的預(yù)測誤差及運動矢量; 
    B幀是雙向預(yù)測編碼幀; 
    B幀壓縮比最高,因為它只反映丙參考幀間運動主體的變化情況,預(yù)測比較準(zhǔn)確; 
    B幀不是參考幀,不會造成解碼錯誤的擴(kuò)散。

GOP:兩個I幀之間是一個圖像序列,主要用作形容一個 i 幀 到下一個 i 幀之間的間隔了多少個幀,一個序列的第一個圖像是 IDR 圖像(立即刷新圖像),IDR 圖像都是 I 幀圖像。
增大GOP圖片組能有效的減少編碼后的視頻體積,但是也會降低視頻質(zhì)量。
GOP 越長,B 幀所占比例更高,編碼的率失真性能越高。

使用H.264 Video ES Viewer工具打開一個test.264文件 查看每個NAL的類型以及VCL數(shù)數(shù)據(jù)大小以及幀類型。

六、切片Slice和宏塊

GOP、幀、片、宏之間的關(guān)系

片的主要作用是用作宏塊(Macroblock)的載體, 目的是為限制誤碼的擴(kuò)散和傳輸。
如何限制誤碼的擴(kuò)散和傳輸?
每個片(slice)都應(yīng)該是互相獨立被傳輸?shù)?,某片的預(yù)測(片內(nèi)預(yù)測和片間預(yù)測)不能以其它片中的宏塊(Macroblock)為參考圖像。

每個分片也包含著頭和數(shù)據(jù)兩部分:

分片頭中包含著分片類型、宏塊類型、幀的數(shù)量、分片屬于那個圖像以及對應(yīng)的幀的設(shè)置和參數(shù)等信息。
分片數(shù)據(jù)中則是宏塊,這里就是我們要找的存儲像素(YUV)數(shù)據(jù)的地方

什么是宏塊

宏塊是視頻信息的主要承載者,因為它包含著每一個像素的亮度和色度信息。視頻解碼最主要的工作則是提供高效的方式從碼流中獲得宏塊中的像素陣列。

組成部分:一個宏塊由一個16×16亮度像素和附加的一個8×8 Cb和一個 8×8 Cr 彩色像素塊組成。每個圖象中,若干宏塊被排列成片的形式。

** 常用的宏塊類型:**
I宏塊:采用幀內(nèi)預(yù)測宏塊,可能位于I/P/B幀(因為在P和B幀中也是可以進(jìn)行幀內(nèi)預(yù)測的)
P宏塊:采用單向幀間預(yù)測,只存在于P幀
B宏塊:采用雙向幀間預(yù)測,只存在于B幀

** 切片(slice)類型跟宏塊類型的關(guān)系**

I片:只包 I宏塊,I 宏塊利用從當(dāng)前片中已解碼的像素作為參考進(jìn)行幀內(nèi)預(yù)測(不能取其它片中的已解碼像素作為參考進(jìn)行幀內(nèi)預(yù)測)。
P片:可包 P和I宏塊,P 宏塊利用前面已編碼圖象作為參考圖象進(jìn)行幀內(nèi)預(yù)測,一個幀內(nèi)編碼的宏塊可進(jìn)一步作宏塊的分割:即 16×16、16×8、8×16 或 8×8 亮度像素塊(以及附帶的彩色像素);如果選了 8×8 的子宏塊,則可再分成各種子宏塊的分割,其尺寸為 8×8、8×4、4×8 或 4×4 亮度像素塊(以及附帶的彩色像素)。
B片:可包 B和I宏塊,B 宏塊則利用雙向的參考圖象(當(dāng)前和 來的已編碼圖象幀)進(jìn)行幀內(nèi)預(yù)測。
SP片(切換P):用于不同編碼流之間的切換,包含 P 和/或 I 宏塊
SI片:擴(kuò)展檔次中必須具有的切換,它包 了一種特殊類型的編碼宏塊,叫做 SI 宏塊,SI 也是擴(kuò)展檔次中的必備功能。

我們通過H264Visa工具來查看h264的 NALU、Slice、marcoblock、以及YUV數(shù)據(jù)如下:


七、資料

本篇的內(nèi)容很多來下面的參考資料的學(xué)習(xí),結(jié)合自己的理解進(jìn)行整理和描述,以及通過碼流分析工具進(jìn)行查看分析。 感謝如下作者的輸出。

  1. 圖書 《視頻編碼全角度詳解》
  2. 圖書 《新一代視頻壓縮編碼標(biāo)準(zhǔn) — H.264/AVC》
  3. 李超-H264基本原理
  4. 深入淺出理解視頻編碼H264結(jié)構(gòu)
  5. 視頻和視頻幀:H264編碼格式整理
  6. H264編碼總結(jié)
  7. VCL & NAL (H.264/AVC)

八、收獲

通過本篇的學(xué)習(xí)

  1. 了解H264的結(jié)構(gòu) VCL和NAL的分層
  2. 了解NALU HEAD對應(yīng)的一個字節(jié)代表的含義和類型,SPS、PPS、SEI、IDR、非IDR等,以及了解I/P/B幀的特性
  3. 了解NALU PayLoad的結(jié)構(gòu)
  4. 了解對幀分片和宏塊的定義和目的。
  5. 通過碼流分析工具結(jié)合實踐更好的理解。

感謝你的閱讀
下一篇我們分析學(xué)習(xí)H264的編碼技術(shù)之幀內(nèi)預(yù)測,歡迎關(guān)注公眾號“音視頻開發(fā)之旅”,一起學(xué)習(xí)成長。
歡迎交流

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容