前言
-------------
H264結(jié)構(gòu)中,一個(gè)視頻圖像編碼后的數(shù)據(jù)叫做一幀,一幀由一個(gè)片(slice)或多個(gè)片組成,一個(gè)片由一個(gè)或多個(gè)宏塊(MB)組成,一個(gè)宏塊由16x16的yuv數(shù)據(jù)組成。宏塊作為H264編碼的基本單位。
-------------------------
名詞解釋
-------------------------
場(chǎng)和幀 : 視頻的一場(chǎng)或一幀可用來產(chǎn)生一個(gè)編碼圖像。在電視中,為減少大面積閃爍現(xiàn)象,把一幀分成兩個(gè)隔行的場(chǎng)。
宏塊 :一個(gè)編碼圖像通常劃分成若干宏塊組成,一個(gè)宏塊由一個(gè)16×16亮度像素和附加的一個(gè)8×8 Cb和一個(gè)8×8 Cr彩色像素塊組成。
片:每個(gè)圖象中,若干宏塊被排列成片的形式。片分為I片、B片、P片和其他一些片。
-- I片只包含I宏塊,P片可包含P和I宏塊,而B片可包含B和I宏塊。
-- I宏塊利用從當(dāng)前片中已解碼的像素作為參考進(jìn)行幀內(nèi)預(yù)測(cè)。
-- P宏塊利用前面已編碼圖象作為參考圖象進(jìn)行幀內(nèi)預(yù)測(cè)。
-- B宏塊則利用雙向的參考圖象(前一幀和后一幀)進(jìn)行幀內(nèi)預(yù)測(cè)。
片的目的是為了限制誤碼的擴(kuò)散和傳輸,使編碼片相互間是獨(dú)立的。某片的預(yù)測(cè)不能以其它片中的宏塊為參考圖像,這樣某一片中的預(yù)測(cè)誤差才不會(huì)傳播到其它片中去。
-----------------------------------------------
H264/AVC 的分層結(jié)構(gòu)
-----------------------------------------------
H.264的主要目標(biāo)是:
1.高的視頻壓縮比;
2.良好的網(wǎng)絡(luò)親和性;
為了完成這些目標(biāo)H264的解決方案是:
1.VCL video coding layer 視頻編碼層;
2.NAL network abstraction layer 網(wǎng)絡(luò)提取層;
其中,VCL層是對(duì)核心算法引擎,塊,宏塊及片的語法級(jí)別的定義,他最終輸出編碼完的數(shù)據(jù) SODB;
NAL層定義片級(jí)以上的語法級(jí)別(如序列參數(shù)集和圖像參數(shù)集,針對(duì)網(wǎng)絡(luò)傳輸),同時(shí)支持以下功能:獨(dú)立片解碼,起始碼唯一保證,SEI以及流格式編碼數(shù)據(jù)傳送,NAL層將SODB打包成RBSP然后加上NAL頭,組成一個(gè)NALU(NAL單元);
---------------------------------------------
H264網(wǎng)絡(luò)傳輸?shù)慕Y(jié)構(gòu)
---------------------------------------------
H264在網(wǎng)絡(luò)傳輸?shù)氖荖ALU,NALU的結(jié)構(gòu)是:NAL頭+RBSP,實(shí)際傳輸中的數(shù)據(jù)流如圖所示:
從前
面的分析我們知道,VCL層出來的是編碼完的視頻幀數(shù)據(jù),這些幀可能是I、B、P幀,而且這些幀可能屬于不同的序列,再者同一個(gè)序列還有相對(duì)應(yīng)的一套序列
參數(shù)集和圖片參數(shù)集等等,所以要完成視頻的解碼,不僅需要傳輸VCL層編碼出來的視頻幀數(shù)據(jù),還需要傳輸序列參數(shù)集、圖像參數(shù)集等數(shù)據(jù)。
NALU頭用來標(biāo)識(shí)后面的RBSP是什么類型的數(shù)據(jù),他是否會(huì)被其他幀參考以及網(wǎng)絡(luò)傳輸是否有錯(cuò)誤。
RBSP用來存放下表中的一種:
RBSP類型 |
所寫 |
描述 |
參數(shù)集 |
PS |
序列的全局信息,如圖像尺寸,視頻格式等 |
增強(qiáng)信息 |
SEI |
視頻序列解碼的增強(qiáng)信息 |
圖像界定符 |
PD |
視頻圖像的邊界 |
編碼片 |
SLICE |
編碼片的頭信息和數(shù)據(jù) |
數(shù)據(jù)分割 |
|
DP片層的數(shù)據(jù),用于錯(cuò)誤恢復(fù)解碼 |
序列結(jié)束符 |
|
表明一個(gè)序列的結(jié)束,下一個(gè)圖像為IDR圖像 |
流結(jié)束符 |
|
表明該流中已沒有圖像 |
填充數(shù)據(jù) |
|
亞元數(shù)據(jù),用于填充字節(jié) |
其中,
參數(shù)集:包括序列參數(shù)集 SPS 和圖像參數(shù)集 PPS
SPS 包含的是針對(duì)一連續(xù)編碼視頻序列的參數(shù),如標(biāo)識(shí)符 seq_parameter_set_id、幀數(shù)及 POC 的約束、參考幀數(shù)目、解碼圖像尺寸和幀場(chǎng)編碼模式選擇標(biāo)識(shí)等等。
PPS對(duì)應(yīng)的是一個(gè)序列中某一幅圖像或者某幾幅圖像,其參數(shù)如標(biāo)識(shí)符 pic_parameter_set_id、可選的 seq_parameter_set_id、熵編碼模式選擇標(biāo)識(shí)、片組數(shù)目、初始量化參數(shù)和去方塊濾波系數(shù)調(diào)整標(biāo)識(shí)等等。
數(shù)據(jù)分割:組成片的編碼數(shù)據(jù)存放在 3 個(gè)獨(dú)立的
DP(數(shù)據(jù)分割,A、B、C)中,各自包含一個(gè)編碼片的子集。分割A包含片頭和片中每個(gè)宏塊頭數(shù)據(jù)。分割B包含幀內(nèi)和 SI 片宏塊的編碼殘差數(shù)據(jù)。分割
C包含幀間宏塊的編碼殘差數(shù)據(jù)。每個(gè)分割可放在獨(dú)立的 NAL 單元并獨(dú)立傳輸。
-----------------------------------------
NALU頭結(jié)構(gòu)
----------------------------------------
NALU頭結(jié)構(gòu):nal_unit_type(5bit)+nal_reference_bit(2bit)+forbidden_bit(1bit)
1.nal_unit_type:NALU類型取值如下表所示。
nal_unit_type
|
NAL類型
|
C
|
0
|
未使用
|
|
1
|
非IDR圖像中不采用數(shù)據(jù)劃分的片段
|
2,3,4
|
2
|
非IDR圖像中A類數(shù)據(jù)劃分片段
|
2
|
3
|
非IDR圖像中B類數(shù)據(jù)劃分片段
|
3
|
4
|
非IDR圖像中C類數(shù)據(jù)劃分片段
|
4
|
5
|
IDR圖像的片
|
2,3
|
6
|
補(bǔ)充增強(qiáng)信息單元(SEI)
|
5
|
7
|
序列參數(shù)集
|
0
|
8
|
圖像參數(shù)集
|
1
|
9
|
分界符
|
6
|
10
|
序列結(jié)束
|
7
|
11
|
碼流結(jié)束
|
8
|
12
|
填充
|
9
|
13..23
|
保留
|
|
24..31
|
不保留
|
|
2.nal_reference_bit:nal重要性指示,標(biāo)志該NAL單元的重要性,值越大,越重要,解碼器在解碼處理不過來的時(shí)候,可以丟掉重要性為0的NALU。不同類型的NALU的重要性指示如下表所示。
nal_unit_type
|
NAL類型
|
nal_reference_bit
|
0
|
未使用
|
0
|
1
|
非IDR的片
|
此片屬于參考幀,則不等于0,
不屬于參考幀,則等與0
|
2
|
片數(shù)據(jù)A分區(qū)
|
同上
|
3
|
片數(shù)據(jù)B分區(qū)
|
同上
|
4
|
片數(shù)據(jù)C分區(qū)
|
同上
|
5
|
IDR圖像的片
|
5
|
6
|
補(bǔ)充增強(qiáng)信息單元(SEI)
|
0
|
7
|
序列參數(shù)集
|
非0
|
8
|
圖像參數(shù)集
|
非0
|
9
|
分界符
|
0
|
10
|
序列結(jié)束
|
0
|
11
|
碼流結(jié)束
|
0
|
12
|
填充
|
0
|
13..23
|
保留
|
0
|
24..31
|
不保留
|
0
|
所謂參考幀,就是在其他幀解碼時(shí)需要參照的幀。比如一個(gè)I幀可能被一個(gè)或多個(gè)B幀參考,一個(gè)B幀可能被某個(gè)P幀參考。
從這個(gè)表我們也可以看出來,DIR的I幀是非常重要的,他一丟,那么這個(gè)序列的所有幀都沒辦法解碼了;然后序列參數(shù)集和圖像參數(shù)集也很重要,沒有序列參數(shù)集,這個(gè)序列的幀就沒法解;沒有圖像參數(shù)集,那用到這個(gè)圖像參數(shù)集的幀都沒法解。
3.forbidden_bit:禁止位,初始為0,當(dāng)網(wǎng)絡(luò)發(fā)現(xiàn)NAL單元有比特錯(cuò)誤時(shí)可設(shè)置該比特為1,以便接收方糾錯(cuò)或丟掉該單元。
-------------------------------------
NAL的開始和結(jié)束
-------------------------------
編碼器將每個(gè)NAL各自獨(dú)立、完整地放入一個(gè)分組,因?yàn)榉纸M都有頭部,解碼器可以方便地檢測(cè)出NAL的分界,并依次取出NAL進(jìn)行解碼。每個(gè)NAL前有一個(gè)起始碼 0x00 00 01(或者0x00 00 00 01),解碼器檢測(cè)每個(gè)起始碼,作為一個(gè)NAL的起始標(biāo)識(shí),當(dāng)檢測(cè)到下一個(gè)起始碼時(shí),當(dāng)前NAL結(jié)束。同時(shí)H.264規(guī)定,當(dāng)檢測(cè)到0x000000時(shí),也可以表征當(dāng)前NAL的結(jié)束。那么NAL中數(shù)據(jù)出現(xiàn)0x000001或0x000000時(shí)怎么辦?H.264引入了防止競(jìng)爭(zhēng)機(jī)制,如果編碼器檢測(cè)到NAL數(shù)據(jù)存在0x000001或0x000000時(shí),編碼器會(huì)在最后個(gè)字節(jié)前插入一個(gè)新的字節(jié)0x03,這樣:
0x000000->0x00000300
0x000001->0x00000301
0x000002->0x00000302
0x000003->0x00000303
解碼器檢測(cè)到0x000003時(shí),把03拋棄,恢復(fù)原始數(shù)據(jù)。解碼器在解碼時(shí),首先逐個(gè)字節(jié)讀取NAL的數(shù)據(jù),統(tǒng)計(jì)NAL的長(zhǎng)度,然后再開始解碼。
--------------------------------------
NALU的順序要求
--------------------------------------
H.264/AVC標(biāo)準(zhǔn)對(duì)送到解碼器的NAL單元順序是有嚴(yán)格要求的,如果NAL單元的順序是混亂的,必須將其重新依照規(guī)范組織后送入解碼器,否則解碼器不能夠正確解碼。
1.序列參數(shù)集NAL單元 必須在傳送所有以此參數(shù)集為參考的其他NAL單元之前傳送,不過允許這些NAL單元中間出現(xiàn)重復(fù)的序列參數(shù)集NAL單元。
所謂重復(fù)的詳細(xì)解釋為:序列參數(shù)集NAL單元都有其專門的標(biāo)識(shí),如果兩個(gè)序列參數(shù)集NAL單元的標(biāo)識(shí)相同,就可以認(rèn)為后一個(gè)只不過是前一個(gè)的拷貝,而非新的序列參數(shù)集。
2.圖像參數(shù)集NAL單元 必須在所有以此參數(shù)集為參考的其他NAL單元之前傳送,不過允許這些NAL單元中間出現(xiàn)重復(fù)的圖像參數(shù)集NAL單元,這一點(diǎn)與上述的序列參數(shù)集NAL單元是相同的。
3.不同基本編碼圖像中的片段(slice)單元和數(shù)據(jù)劃分片段(data
partition)單元在順序上不可以相互交叉,即不允許屬于某一基本編碼圖像的一系列片段(slice)單元和數(shù)據(jù)劃分片段(data
partition)單元中忽然出現(xiàn)另一個(gè)基本編碼圖像的片段(slice)單元片段和數(shù)據(jù)劃分片段(data partition)單元。
4.參考圖像的影響:如果一幅圖像以另一幅圖像為參考,則屬于前者的所有片段(slice)單元和數(shù)據(jù)劃分片段(data partition)單元必須在屬于后者的片段和數(shù)據(jù)劃分片段之后,無論是基本編碼圖像還是冗余編碼圖像都必須遵守這個(gè)規(guī)則。
5.基本編碼圖像的所有片段(slice)單元和數(shù)據(jù)劃分片段(data partition)單元必須在屬于相應(yīng)冗余編碼圖像的片段(slice)單元和數(shù)據(jù)劃分片段(data partition)單元之前。
6.如果數(shù)據(jù)流中出現(xiàn)了連續(xù)的無參考基本編碼圖像,則圖像序號(hào)小的在前面。
7.如果arbitrary_slice_order_allowed_flag置為1,一個(gè)基本編碼圖像中的片段(slice)單元和數(shù)據(jù)劃分片段(data partition)單元的順序是任意的,如果arbitrary_slice_order_allowed_flag置為零,則要按照片段中第一個(gè)宏塊的位置來確定片段的順序,若使用數(shù)據(jù)劃分,則A類數(shù)據(jù)劃分片段在B類數(shù)據(jù)劃分片段之前,B類數(shù)據(jù)劃分片段在C類數(shù)據(jù)劃分片段之前,而且對(duì)應(yīng)不同片段的數(shù)據(jù)劃分片段不能相互交叉,也不能與沒有數(shù)據(jù)劃分的片段相互交叉。
8.如果存在SEI(補(bǔ)充增強(qiáng)信息)單元的話,它必須在它所對(duì)應(yīng)的基本編碼圖像的片段(slice)單元和數(shù)據(jù)劃分片段(data
partition)單元之前,并同時(shí)必須緊接在上一個(gè)基本編碼圖像的所有片段(slice)單元和數(shù)據(jù)劃分片段(data
partition)單元后邊。假如SEI屬于多個(gè)基本編碼圖像,其順序僅以第一個(gè)基本編碼圖像為參照。
9.如果存在圖像分割符的話,它必須在所有SEI 單元、基本編碼圖像的所有片段slice)單元和數(shù)據(jù)劃分片段(data partition)單元之前,并且緊接著上一個(gè)基本編碼圖像那些NAL單元。
10.如果存在序列結(jié)束符,且序列結(jié)束符后還有圖像,則該圖像必須是IDR(即時(shí)解碼器刷新)圖像。序列結(jié)束符的位置應(yīng)當(dāng)在屬于這個(gè)IDR圖像的分割符、SEI 單元等數(shù)據(jù)之前,且緊接著前面那些圖像的NAL單元。如果序列結(jié)束符后沒有圖像了,那么它的就在比特流中所有圖像數(shù)據(jù)之后。
11.流結(jié)束符在比特流中的最后。
|