H.264 NAL層解析(0x00000001,編碼,打包,NALU)
1.引言 H.264的主要目標(biāo): 1.高的視頻壓縮比 2.良好的網(wǎng)絡(luò)親和性 解決方案: VCL video codinglayer 視頻編碼層 NAL network abstraction layer 網(wǎng)絡(luò)提取層 VCL:核心算法引擎,塊,,宏塊及片的語法級別的定義 NAL:片級以上的語法級別(如序列參數(shù)集和圖像參數(shù)集),同時支持以下功能:獨立片解碼,,起始碼唯一保證,,SEI以及流格式編碼數(shù)據(jù)傳送 VCL設(shè)計目標(biāo):盡可能地獨立于網(wǎng)絡(luò)的情況下進(jìn)行高效的編解碼 NAL設(shè)計目標(biāo):根據(jù)不同的網(wǎng)絡(luò)把數(shù)據(jù)打包成相應(yīng)的格式,將VCL產(chǎn)生的比特字符串適配到各種各樣的網(wǎng)絡(luò)和多元環(huán)境中,。 NALU頭結(jié)構(gòu):NALU類型(5bit),、重要性指示位(2bit)、禁止位(1bit),。 NALU類型:1~12由H.264使用,,24~31由H.264以外的應(yīng)用使用。 重要性指示:標(biāo)志該NAL單元用于重建時的重要性,,值越大,,越重要。 禁止位:網(wǎng)絡(luò)發(fā)現(xiàn)NAL單元有比特錯誤時可設(shè)置該比特為1,,以便接收方丟掉該單元,。
2.NAL語法語義 NAL層句法: 在編碼器輸出的碼流中,數(shù)據(jù)的基本單元是句法元素,。 句法表征句法元素的組織結(jié)構(gòu),。 語義闡述句法元素的具體含義。 分組都有頭部,,解碼器可以很方便的檢測出NAL的分界,,依次取出NAL進(jìn)行解碼。 但為了節(jié)省碼流,,H.264沒有另外在NAL的頭部設(shè)立表示起始位置的句法元素,。 如果編碼數(shù)據(jù)是存儲在介質(zhì)上的,由于NAL是依次緊密相連的,,解碼器就無法在數(shù)據(jù)流中分辨出每個NAL的起始位置和終止位置,。 解決方案:在每個NAL前添加起始碼:0X000001 在某些類型的介質(zhì)上,為了尋址的方便,,要求數(shù)據(jù)流在長度上對齊,,或某個常數(shù)的整數(shù)倍。所以在起始碼前添加若干字節(jié)的0來填充,。 檢測NAL的開始: 0X000001和0X00000001 我們必須考慮當(dāng)NAL內(nèi)部出現(xiàn)了0X000001和0X000000 如果NALU對應(yīng)的Slice為一幀的開始,,則用4字節(jié)表示,即0x00000001,;否則用3字節(jié)表示,,0x000001。
解決方案:為了防止NAL內(nèi)部出現(xiàn)0x000001的數(shù)據(jù),h.264又提出'防止競爭
emulation prevention"機制,,在編碼完一個NAL時,,如果檢測出有連續(xù)兩個0x00字節(jié),就在后面插入一個0x03,,則在NAL數(shù)據(jù)內(nèi)肯定不會存在NAL起始碼0x000001,。當(dāng)解碼器在NAL內(nèi)部檢測到0x000003的數(shù)據(jù),就把0x03拋棄,,恢復(fù)原始數(shù)據(jù),。 0x000001 >>>>>> 0x00000301(起始碼) 0x000002 >>>>>> 0x00000302(保留) 0x000003 >>>>>> 0x00000303(保證解碼器正常工作)
H.264提出了“防止競爭”機制: 0X000000——0X00000300 0X000001——0X00000301 0X000002——0X00000302 0X000003——0X00000303 為此,我們可以知道: 在NAL單元中,,下面的三字節(jié)序列不應(yīng)在任何字節(jié)對齊的位置出現(xiàn) 0X000000 0X000001 0X000002
Forbidden_zero_bit=0; Nal_ref_idc:表示NAL的優(yōu)先級,。0~3,取值越大,,表示當(dāng)前NAL越重要,,需要優(yōu)先受到保護(hù)。如果當(dāng)前NAL是屬于參考幀的片,,或是序列參數(shù)集,,或是圖像參數(shù)集這些重要的單位時,本句法元素必需大于0,。 Nal_unit_type:當(dāng)前NAL 單元的類型 標(biāo)識NAL單元中的RBSP數(shù)據(jù)類型,,其中,nal_unit_type為1,, 2,, 3, 4,, 5的NAL單元稱為VCL的NAL單元,,其他類型的NAL單元為非VCL的NAL單元。 § 0:未規(guī)定 § 1:非IDR圖像中不采用數(shù)據(jù)劃分的片段 § 2:非IDR圖像中A類數(shù)據(jù)劃分片段 § 3:非IDR圖像中B類數(shù)據(jù)劃分片段 § 4:非IDR圖像中C類數(shù)據(jù)劃分片段 § 5:IDR圖像的片段 § 6:補充增強信息(SEI) § 7:序列參數(shù)集(SPS) § 8:圖像參數(shù)集(PPS) § 9:分割符 § 10:序列結(jié)束符 § 11:流結(jié)束符 § 12:填充數(shù)據(jù) § 13:序列參數(shù)集擴展 § 14:帶前綴的NAL單元 § 15:子序列參數(shù)集 § 16 –18:保留 § 19:不采用數(shù)據(jù)劃分的輔助編碼圖像片段 § 20:編碼片段擴展 § 21 –23:保留 § 24 –31:未規(guī)定
3.H.264的NAL層處理 結(jié)構(gòu)示意圖: NAL以NALU(NAL unit)為單元來支持編碼數(shù)據(jù)在基于分組交換技術(shù)網(wǎng)絡(luò)中傳輸,。它定義了符合傳輸層或存儲介質(zhì)要求的數(shù)據(jù)格式,,同時給出頭信息,從而提供了視頻編碼和外部世界的接口,。 NALU:定義了可用于基于分組和基于比特流系統(tǒng)的基本格式
RTP封裝:只針對基于NAL單元的本地NAL接口,。 三種不同的數(shù)據(jù)形式: SODB 數(shù)據(jù)比特串-->最原始的編碼數(shù)據(jù) (raw) RBSP 原始字節(jié)序列載荷-->在SODB的后面填加了結(jié)尾比特(RBSP trailing bits一個bit“1”)若干比特“0”,以便字節(jié)對齊 EBSP 擴展字節(jié)序列載荷-->在RBSP基礎(chǔ)上填加了仿校驗字節(jié)(0X03)它的原因是: 在NALU加到Annexb上時,需要添加每組NALU之前的開始碼StartCodePrefix,如果該NALU對應(yīng)的slice為一幀的開始則用4位字節(jié)表示,,0x00000001,否則用3位字節(jié)表示0x000001.為了使NALU主體中不包括與開始碼相沖突的,,在編碼時,每遇到兩個字節(jié)連續(xù)為0,,就插入一個字節(jié)的0x03,。解碼時將0x03去掉,。也稱為脫殼操作
處理過程: 1.將VCL層輸出的SODB封裝成nal_unit, Nal_unit是一個通用封裝格式,,可以適用于有序字節(jié)流方式和IP包交換方式,。 2.針對不同的傳送網(wǎng)絡(luò)(電路交換|包交換),將nal_unit 封裝成針對不同網(wǎng)絡(luò)的封裝格式,。
第一步的具體過程: VCL層輸出的比特流SODB(String OfData Bits),,到nal_unit之間,經(jīng)過了以下三步處理: 1.SODB字節(jié)對齊處理后封裝成RBSP(RawByte Sequence Payload),。
2.為防止RBSP的字節(jié)流與有序字節(jié)流傳送方式下的SCP(start_code_prefix_one_3bytes,0x000001)出現(xiàn)字節(jié)競爭情形,,循環(huán)檢測RBSP前三個字節(jié),,在出現(xiàn)字節(jié)競爭時在第三字節(jié)前加入emulation_prevention_three_byte(0x03) 具體方法: nal_unit( NumBytesInNALunit ) { forbidden_zero_bit nal_ref_idc nal_unit_type NumBytesInRBSP = 0 for( i = 1; i < NumBytesInNALunit;i++ ) { if( i + 2 < NumBytesInNALunit&& next_bits( 24 ) = = 0x000003 ) { rbsp_byte[ NumBytesInRBSP++ ] rbsp_byte[ NumBytesInRBSP++ ] i += 2 emulation_prevention_three_byte /*equal to 0x03 */ } else rbsp_byte[ NumBytesInRBSP++ ] } } 3. 防字節(jié)競爭處理后的RBSP再加一個字節(jié)的header(forbidden_zero_bit+ nal_ref_idc+ nal_unit_type),封裝成nal_unit.
第二步的具體過程:
case1:有序字節(jié)流的封裝
byte_stream_nal_unit( NumBytesInNALunit ) { while( next_bits( 24 ) != 0x000001 ) zero_byte /* equal to 0x00 */ if( more_data_in_byte_stream( ) ) { start_code_prefix_one_3bytes /* equal to 0x000001 */nal_unit( NumBytesInNALunit ) } } 類似H.320和MPEG-2/H.222.0等傳輸系統(tǒng),,傳輸NAL作為有序連續(xù)字節(jié)或比特流,,同時要依靠數(shù)據(jù)本身識別NAL單元邊界。在這樣的應(yīng)用系統(tǒng)中,,H.264/AVC規(guī)范定義了字節(jié)流格式,,每個NAL單元前面增加3個字節(jié)的前綴,即同步字節(jié),。在比特流應(yīng)用中,,每個圖像需要增加一個附加字節(jié)作為邊界定位。還有一種可選特性,,在字節(jié)流中增加附加數(shù)據(jù),,用做擴充發(fā)送數(shù)據(jù)量,能實現(xiàn)快速邊界定位,,恢復(fù)同步 Case2:IP網(wǎng)絡(luò)的RTP打包封裝 分組打包的規(guī)則 (1)額外開銷要少,,使MTU尺寸在100~64k字節(jié)范圍都可以; (2)不用對分組內(nèi)的數(shù)據(jù)解碼就可以判別該分組的重要性,; (3)載荷規(guī)范應(yīng)當(dāng)保證不用解碼就可識別由于其他的比特丟失而造成的分組不可解碼,; (4)支持將NALU分割成多個RTP分組; (5)支持將多個NALU匯集在一個RTP分組中,。 RTP的頭標(biāo)可以是NALU的頭標(biāo),,并可以實現(xiàn)以上的打包規(guī)則。 一個RTP分組里放入一個NALU,,將NALU(包括同時作為載荷頭標(biāo)的NALU頭)放入RTP的載荷中,,設(shè)置RTP頭標(biāo)值。為了避免IP層對大分組的再一次分割,,片分組的大小一般都要小于MTU尺寸,。由于包傳送的路徑不同,解碼端要重新對片分組排序,RTP包含的次序信息可以用來解決這一問題,。 NALU分割 對于預(yù)先已經(jīng)編碼的內(nèi)容,,NALU可能大于MTU尺寸的限制。雖然IP層的分割可以使數(shù)據(jù)塊小于64千字節(jié),,但無法在應(yīng)用層實現(xiàn)保護(hù),,從而降低了非等重保護(hù)方案的效果。由于UDP數(shù)據(jù)包小于64千字節(jié),,而且一個片的長度對某些應(yīng)用場合來說太小,,所以應(yīng)用層打包是RTP打包方案的一部分。 新的討論方案(IETF)應(yīng)當(dāng)符合以下特征: (1)NALU的分塊以按RTP次序號升序傳輸,; (2)能夠標(biāo)記第一個和最后一個NALU分塊,; (3)可以檢測丟失的分塊。 NALU合并 一些NALU如SEI,、參數(shù)集等非常小,,將它們合并在一起有利于減少頭標(biāo)開銷。已有兩種集合分組: (1)單一時間集合分組(STAP),,按時間戳進(jìn)行組合,; (2)多時間集合分組(MTAP),不同時間戳也可以組合,。 NAL規(guī)范視頻數(shù)據(jù)的格式,,主要是提供頭部信息,以適合各種媒體的傳輸和存儲,。NAL支持各種網(wǎng)絡(luò),,包括: 1.任何使用RTP/IP協(xié)議的實時有線和無線Internet 服務(wù) 2.作為MP4文件存儲和多媒體信息文件服務(wù) 3.MPEG-2系統(tǒng) 4.其它網(wǎng) NAL規(guī)定一種通用的格式,既適合面向包傳輸,,也適合流傳送,。實際上,包傳輸和流傳輸?shù)姆绞绞窍嗤?,不同之處是傳輸前面增加了一個起始碼前綴 在類似Internet/RTP面向包傳送協(xié)議系統(tǒng)中,,包結(jié)構(gòu)中包含包邊界識別字節(jié),在這種情況下,,不需要同步字節(jié),。
NAL單元分為VCL和非VCL兩種 VCL NAL單元包含視頻圖像采樣信息, 非VCL包含各種有關(guān)的附加信息,,例如參數(shù)集(頭部信息,,應(yīng)用到大量的VCL NAL單元)、提高性能的附加信息,、定時信息等
參數(shù)集: 參數(shù)集是很少變化的信息,,用于大量VCL NAL單元的解碼,,分為兩種類型: 1.序列參數(shù)集,作用于一串連續(xù)的視頻圖像,,即視頻序列,。兩個IDR圖像之間為序列參數(shù)集。IDR和I幀的區(qū)別見下面,。 2.圖像參數(shù)集,,作用于視頻序列中的一個或多個個別的圖像序列和圖像參數(shù)集機制,減少了重復(fù)參數(shù)的傳送,,每個VCL NAL單元包含一個標(biāo)識,,指向有關(guān)的圖像參數(shù)集,每個圖像參數(shù)集包含一個標(biāo)識,,指向有關(guān)的序列參數(shù)集的內(nèi)容因此,,只用少數(shù)的指針信息,引用大量的參數(shù),,大大減少每個VCL NAL單元重復(fù)傳送的信息。 序列和圖像參數(shù)集可以在發(fā)送VCL NAL單元以前發(fā)送,,并且重復(fù)傳送,,大大提高糾錯能力。序列和圖像參數(shù)集可以在“帶內(nèi)”,,也可以用更為可靠的其他“帶外”通道傳送,。
存儲單元: 一組指定格式的NAL單元稱為存儲單元,每個存儲單元對應(yīng)一個圖像,。每個存儲單元包含一組VCL NAL單元,,組成一個主編碼圖像,VCL NAL單元由表示視頻圖像采樣的像條所組成,。存儲單元前面可以加一個前綴,,分界存儲單元,附加增強信息(SEI)(如圖像定時信息)也可以放在主編碼圖像的前面,。主編碼圖像后附加的VCL NAL單元,,包含同一圖像的冗余表示,稱為冗余編碼圖像,,當(dāng)主編碼圖像數(shù)據(jù)丟失或損壞時,,可用冗余編碼圖像解碼。
編碼視頻序列: 一個編碼視頻序列由一串連續(xù)的存儲單元組成,,使用同一序列參數(shù)集,。每個視頻序列可獨立解碼。編碼序列的開始是即時刷新存儲單元(IDR),。IDR是一個I幀圖像,,表示后面的圖像不用參考以前的圖像,。一個NAL單元流可包含一個或更多的編碼視頻序列。
I幀和IDR幀的區(qū)別: 1.在 H.264 中 I 幀并不具有隨機訪問的能力,,這個功能由 IDR 承擔(dān),。以前的標(biāo)準(zhǔn)中由 I 幀承擔(dān)。 2.IDR 會導(dǎo)致 DPB (參考幀列表——這是關(guān)鍵所在)清空,,而 I 不會,。 3.I和IDR幀其實都是I幀,都是使用幀內(nèi)預(yù)測的。但是IDR幀的作用是立刻刷新,使錯誤不致傳播,從IDR幀開始,重新算一個新的序列開始編碼,。 4.IDR圖像一定是I圖像,,但I(xiàn)圖像不一定是IDR圖像。一個序列中可以有很多的I圖像,,I圖像之后的圖像可以引用I圖像之間的圖像做運動參考,。
關(guān)于h264拆包,按照FU-A方式說明: 1)第一個FU-A包的FU indicator:F應(yīng)該為當(dāng)前NALU頭的F,,而NRI應(yīng)該為當(dāng)前NALU頭的NRI,,Type則等于28,表明它是FU-A包,。FU header生成方法:S = 1,,E = 0,R = 0,,Type則等于NALU頭中的Type,。 |
|