H264实时编码及NALU,RTP传输(ZZ)
生活随笔
收集整理的這篇文章主要介紹了
H264实时编码及NALU,RTP传输(ZZ)
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
rfc3984
Standards Track [Page 2] RFC 3984 RTP Payload Format for H.264 Video February 2005 1.
按照RFC3984協(xié)議實現(xiàn)H264視頻流媒體
nalu單元 包起始 0x 00 00 00 01
H.264 NAL格式及分析器
http://hi.baidu.com/zsw%5Fdavy/b ... c409cc7cd92ace.html
http://hi.baidu.com/zsw_davy/blo ... 081312c8fc7acc.html
----------------------------------比特流信息----------------------------------------------
①NALU(Network Abstract Layer Unit):兩標準中的比特流都是以NAL為單位,每個NAL單元包含一個RBSP,NALU的頭信息定義了RBSP所屬類型。類型一般包括序列參數(shù)集(SPS)、圖像參數(shù)集(PPS)、增強信息(SEI)、條帶(Slice)等,其中,SPS和PPS屬于參數(shù)集,兩標準采用參數(shù)集機制是為了將一些主要的序列、圖像參數(shù)(解碼圖像尺寸、片組數(shù)、參考幀數(shù)、量化和濾波參數(shù)標記等)與其他參數(shù)分離,通過解碼器先解碼出來。此外,為了增強圖像的清晰度,AVS-M添加了圖像頭(Picture head)信息。讀取NALU流程中,每個NALU前有一個起始碼0x000001,為防止 內(nèi)部0x000001序列競爭,H.264編碼器在最后一字節(jié)前插入一個新的字節(jié)——0x03,所以解碼器檢測到該序列時,需將0x03刪掉,而AVS-M只需識別出起始碼0x000001。
②讀取宏塊類型(mb type)和宏塊編碼模板(cbp):編解碼圖像以宏塊劃分,一個宏塊由一個16*16亮度塊和相應的一個8*8cb和一個8*8cr色度塊組成。
(a) 兩標準的幀內(nèi)、幀間預測時宏塊的劃分是有區(qū)別的。H.264中,I_slice亮度塊有Intra_4*4和Intra_16*16兩種模式,色度塊只有8*8模式;P_slice宏塊分為16*16、16*8、8*16、8*8、8*4、4*8、4*4共7種模式。而AVS-M中,I_slice亮度塊有I_4*4和I_Direct兩模式,P_slice時宏塊的劃分和H.264中的劃分一致。
(b) 兩標準的宏塊cbp值計算也不相同。H.264中,Intra_16*16宏塊的亮度(色度)cbp直接通過讀mb type得到;非Intra_16*16宏塊的亮度cbp=coded_block_pattern%16,色度cbp=coded_block_pattern/16 。其中,亮度cbp最低4位有效,每位決定對應宏塊的殘差系數(shù)能不能為0;色度cbp為0時,對應殘差系數(shù)為0,cbp為1時,DC殘差系數(shù)不為0,AC系數(shù)為0,cbp為2時,DC、AC殘差系數(shù)都不為0。AVS-M中,當宏塊類型不是P_skip時,直接從碼流中得到cbp的索引值,并以此索引值查表得到codenum值,再以codenum查表分別得到幀內(nèi)/幀間cbp。此cbp為6位,每位代表宏塊按8*8劃分時能不能包含非零系數(shù),當變換系數(shù)不為0時,需進一步讀cbp_4*4中每位值來判斷一個8*8塊中4個4*4塊的系數(shù)能不能為0。
---------------------------------------------------------------------------------------------
總的來說H264的碼流的打包方式有兩種,一種為annex-b byte stream format的格式,這個是絕大部分編碼器的默認輸出格式,就是每個幀的開頭的3~4個字節(jié)是H264的start_code,0x00000001或者0x000001。
另一種是原始的NAL打包格式,就是開始的若干字節(jié)(1,2,4字節(jié))是NAL的長度,而不是start_code,此時必須借助某個全局的數(shù)據(jù)來獲得編碼器的profile,level,PPS,SPS等信息才可以解碼。
----------------------------------------------------------------------------
AVC vs. H.264
AVC and H.264 are synonymous. The standard is known by the full names "ISO/IEC 14496-10" and "ITU-T Recommendation H.264". In addition, a number of alternate names are used (or have been) in reference to this standard. These include:
All of the above (and those I've missed) include the Annex B byte-stream format. Unlike earlier MPEG1/2/4 and H.26x codecs, the H.264 specification proper does not define a full bit-stream syntax. It describes a number of NAL (Network Abstraction Layer) units, a sequence of which can be decoded into video frames. These NAL units have no boundary markers, and rely on some unspecified format to provide framing.
Annex B of of the document specifies one such format, which wraps NAL units in a format resembling a traditional MPEG video elementary stream, thus making it suitable for use with containers like MPEG PS/TS unable to provide the required framing. Other formats, such as ISO base media based formats, are able to properly separate the NAL units and do not need the Annex B wrapping.
The H.264 spec suffers from a deficiency. It defines several header-type NAL units (SPS and PPS) without specifying how to pack them into the single codec data field available in most containers. Fortunately, most containers seem to have adopted the packing used by the ISO format known as MP4. 1. H.264起始碼
?? 在網(wǎng)絡(luò)傳輸h264數(shù)據(jù)時,一個UDP包就是一個NALU,解碼器可以很方便的檢測出NAL分界和解碼。但是如果編碼數(shù)據(jù)存儲為一個文件,原來的解碼器將無法從數(shù)據(jù)流中分別出每個NAL的起始位置和終止位置,為此h.264用起始碼來解決這一問題。
?? H.264編碼時,在每個NAL前添加起始碼 0x000001,解碼器在碼流中檢測到起始碼,當前NAL結(jié)束。為了防止NAL內(nèi)部出現(xiàn)0x000001的數(shù)據(jù),h.264又提出'防止競爭 emulation prevention"機制,在編碼完一個NAL時,如果檢測出有連續(xù)兩個0x00字節(jié),就在后面插入一個0x03。當解碼器在NAL內(nèi)部檢測到0x000003的數(shù)據(jù),就把0x03拋棄,恢復原始數(shù)據(jù)。
0x000000?? >>>>>>?? 0x00000300
0x000001?? >>>>>>?? 0x00000301
0x000002?? >>>>>>?? 0x00000302
0x000003?? >>>>>>?? 0x00000303
附上h.264解碼nalu中檢測起始碼的算法流程??
for(;;)
{
if next 24 bits are 0x000001
{
?? ??? startCodeFound = true
?? ??? break;
}
else
{
?? ??? flush 8 bits??
}
}// for(;;)
if(true == startCodeFound)
{
??? //startcode found
??? // Flush the start code found
??? flush 24 bits??
??? //Now navigate up to next start code and put the in between stuff
??? // in the nal structure.
??? for(;;)
??? {
?? ?? get next 24 bits & check if it equals to 0x000001
?? ?? if(false == (next 24 bits == 000001))
?? ?? {
?? ?? ?? // search for pattern 0x000000
?? ?? ?? check if next 24 bits are 0x000000
?? ?? ?? if(false == result)
?? ?? ?? {
?? ?? ?? ?? ??? // copy the byte into the buffer
?? ?? ?? ?? ??? copy one byte to the Nal unit ?? ?? ?? ???
?? ?? ?? }
?? ?? ?? else
?? ?? ?? {
?? ?? ?? ?? ??? break;
?? ?? ?? }
?? ?? }
?? ?? else
?? ?? {
?? ?? ?? ??? break;
?? ?? }
?? }//for(;;)
}
?? 2. MPEG4起始碼
?? ??? MPEG4的特色是VOP,沒有NALU的概念,仍使用startcode對每幀進行分界。MPEG4的起始碼是0x000001. 另外MPEG4中很多起始碼也很有用,比如video_object_sequence_start_code 0x000001B0 表示一個視頻對象序列的開始,VO_start_code 0x000001B6 表示一個VOP的開始. 0x000001B6之后的兩位,是00表示 I frame, 01 表示 P frame, 10 表示 B frame. 1.引言
H.264的主要目標:
1.高的視頻壓縮比
2.良好的網(wǎng)絡(luò)親和性
解決方案:
VCL?? video coding layer ?? 視頻編碼層
NAL?? network abstraction layer?? 網(wǎng)絡(luò)提取層
VCL:核心算法引擎,塊,宏塊及片的語法級別的定義
NAL:片級以上的語法級別(如序列參數(shù)集和圖像參數(shù)集),同時支持以下功能:獨立片解碼,起始碼唯一保證,SEI以及流格式編碼數(shù)據(jù)傳送
VCL設(shè)計目標:盡可能地獨立于網(wǎng)絡(luò)的情況下進行高效的編解碼
NAL設(shè)計目標:根據(jù)不同的網(wǎng)絡(luò)把數(shù)據(jù)打包成相應的格式,將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以外的應用使用。
重要性指示:標志該NAL單元用于重建時的重要性,值越大,越重要。
禁止位:網(wǎng)絡(luò)發(fā)現(xiàn)NAL單元有比特錯誤時可設(shè)置該比特為1,以便接收方丟掉該單元。
2.NAL語法語義
NAL層句法:
在編碼器輸出的碼流中,數(shù)據(jù)的基本單元是句法元素。
句法表征句法元素的組織結(jié)構(gòu)。
語義闡述句法元素的具體含義。
分組都有頭部,解碼器可以很方便的檢測出NAL的分界,依次取出NAL進行解碼。
但為了節(jié)省碼流,H.264沒有另外在NAL的頭部設(shè)立表示起始位置的句法元素。
如果編碼數(shù)據(jù)是存儲在介質(zhì)上的,由于NAL是依次緊密相連的,解碼器就無法在數(shù)據(jù)流中分辨出每個NAL的起始位置和終止位置。
解決方案:在每個NAL前添加起始碼:0X000001
在某些類型的介質(zhì)上,為了尋址的方便,要求數(shù)據(jù)流在長度上對齊,或某個常數(shù)的整數(shù)倍。所以在起始碼前添加若干字節(jié)的0來填充。
檢測NAL的開始:
0X000001和0X000000
我們必須考慮當NAL內(nèi)部出現(xiàn)了0X000001和0X000000
解決方案:
H.264提出了“防止競爭”機制:
0X000000——0X00000300
0X000001——0X00000301
0X000002——0X00000302
0X000003——0X00000303
為此,我們可以知道:
在NAL單元中,下面的三字節(jié)序列不應在任何字節(jié)對齊的位置出現(xiàn)
0X000000
0X000001
0X000002
Forbidden_zero_bit =0;
Nal_ref_idc:表示NAL的優(yōu)先級。0~3,取值越大,表示當前NAL越重要,需要優(yōu)先受到保護。如果當前NAL是屬于參考幀的片,或是序列參數(shù)集,或是圖像參數(shù)集這些重要的單位時,本句法元素必需大于0。
Nal_unit_type:當前NAL 單元的類型
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ù)
RBSP 原始字節(jié)序列載荷-->在SODB的后面填加了結(jié)尾比特(RBSP trailing bits 一個bit“1”)若干比特“0”,以便字節(jié)對齊
EBSP 擴展字節(jié)序列載荷-->在RBSP基礎(chǔ)上填加了仿校驗字節(jié)(0X03)它的原因是: 在NALU加到Annexb上時,需要添加每組NALU之前的開始碼StartCodePrefix,如果該NALU對應的slice為一幀的開始則用4位字節(jié)表示,ox00000001,否則用3位字節(jié)表示ox000001.為了使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 Of Data Bits),到nal_unit之間,經(jīng)過了以下三步處理:
1.SODB字節(jié)對齊處理后封裝成RBSP(Raw Byte 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單元邊界。在這樣的應用系統(tǒng)中,H.264/AVC規(guī)范定義了字節(jié)流格式,每個NAL單元前面增加3個字節(jié)的前綴,即同步字節(jié)。在比特流應用中,每個圖像需要增加一個附加字節(jié)作為邊界定位。還有一種可選特性,在字節(jié)流中增加附加數(shù)據(jù),用做擴充發(fā)送數(shù)據(jù)量,能實現(xiàn)快速邊界定位,恢復同步
Case2:IP網(wǎng)絡(luò)的RTP打包封裝
分組打包的規(guī)則
(1)額外開銷要少,使MTU尺寸在100~64k字節(jié)范圍都可以;
(2)不用對分組內(nèi)的數(shù)據(jù)解碼就可以判別該分組的重要性;
(3)載荷規(guī)范應當保證不用解碼就可識別由于其他的比特丟失而造成的分組不可解碼;
(4)支持將NALU分割成多個RTP分組;
?? (5)支持將多個NALU匯集在一個RTP分組中。
RTP的頭標可以是NALU的頭標,并可以實現(xiàn)以上的打包規(guī)則。
一個RTP分組里放入一個NALU,將NALU(包括同時作為載荷頭標的NALU頭)放入RTP的載荷中,設(shè)置RTP頭標值。為了避免IP層對大分組的再一次分割,片分組的大小一般都要小于MTU尺寸。由于包傳送的路徑不同,解碼端要重新對片分組排序,RTP包含的次序信息可以用來解決這一問題。
NALU分割
對于預先已經(jīng)編碼的內(nèi)容,NALU可能大于MTU尺寸的限制。雖然IP層的分割可以使數(shù)據(jù)塊小于64千字節(jié),但無法在應用層實現(xiàn)保護,從而降低了非等重保護方案的效果。由于UDP數(shù)據(jù)包小于64千字節(jié),而且一個片的長度對某些應用場合來說太小,所以應用層打包是RTP打包方案的一部分。
新的討論方案(IETF)應當符合以下特征:
(1)NALU的分塊以按RTP次序號升序傳輸;
(2)能夠標記第一個和最后一個NALU分塊;
(3)可以檢測丟失的分塊。
NALU合并
一些NALU如SEI、參數(shù)集等非常小,將它們合并在一起有利于減少頭標開銷。已有兩種集合分組:
(1)單一時間集合分組(STAP),按時間戳進行組合;
(2)多時間集合分組(MTAP),不同時間戳也可以組合。
NAL規(guī)范視頻數(shù)據(jù)的格式,主要是提供頭部信息,以適合各種媒體的傳輸和存儲。NAL支持各種網(wǎng)絡(luò),包括:
1.任何使用RTP/IP協(xié)議的實時有線和無線Internet 服務
2.作為MP4文件存儲和多媒體信息文件服務
3.MPEG-2系統(tǒng)
4.其它網(wǎng)
NAL規(guī)定一種通用的格式,既適合面向包傳輸,也適合流傳送。實際上,包傳輸和流傳輸?shù)姆绞绞窍嗤?#xff0c;不同之處是傳輸前面增加了一個起始碼前綴
在類似Internet/RTP面向包傳送協(xié)議系統(tǒng)中,包結(jié)構(gòu)中包含包邊界識別字節(jié),在這種情況下,不需要同步字節(jié)。
NAL單元分為VCL和非VCL兩種
VCL NAL單元包含視頻圖像采樣信息,
非VCL包含各種有關(guān)的附加信息,例如參數(shù)集(頭部信息,應用到大量的VCL NAL單元)、提高性能的附加信息、定時信息等
參數(shù)集:
參數(shù)集是很少變化的信息,用于大量VCL NAL單元的解碼,分為兩種類型:
1.序列參數(shù)集,作用于一串連續(xù)的視頻圖像,即視頻序列。
兩個IDR圖像之間為序列參數(shù)集。IDR和I幀的區(qū)別見下面。
2.?? 圖像參數(shù)集,作用于視頻序列中的一個或多個個別的圖像
序列和圖像參數(shù)集機制,減少了重復參數(shù)的傳送,每個VCL NAL單元包含一個標識,指
向有關(guān)的圖像參數(shù)集,每個圖像參數(shù)集包含一個標識,指向有關(guān)的序列參數(shù)集的內(nèi)容
因此,只用少數(shù)的指針信息,引用大量的參數(shù),大大減少每個VCL NAL單元重復傳送的信息。
序列和圖像參數(shù)集可以在發(fā)送VCL NAL單元以前發(fā)送,并且重復傳送,大大提高糾錯能力。序列和圖像參數(shù)集可以在“帶內(nèi)”,也可以用更為可靠的其他“帶外”通道傳送。
Standards Track [Page 2] RFC 3984 RTP Payload Format for H.264 Video February 2005 1.
按照RFC3984協(xié)議實現(xiàn)H264視頻流媒體
nalu單元 包起始 0x 00 00 00 01
H.264 NAL格式及分析器
http://hi.baidu.com/zsw%5Fdavy/b ... c409cc7cd92ace.html
http://hi.baidu.com/zsw_davy/blo ... 081312c8fc7acc.html
----------------------------------比特流信息----------------------------------------------
①NALU(Network Abstract Layer Unit):兩標準中的比特流都是以NAL為單位,每個NAL單元包含一個RBSP,NALU的頭信息定義了RBSP所屬類型。類型一般包括序列參數(shù)集(SPS)、圖像參數(shù)集(PPS)、增強信息(SEI)、條帶(Slice)等,其中,SPS和PPS屬于參數(shù)集,兩標準采用參數(shù)集機制是為了將一些主要的序列、圖像參數(shù)(解碼圖像尺寸、片組數(shù)、參考幀數(shù)、量化和濾波參數(shù)標記等)與其他參數(shù)分離,通過解碼器先解碼出來。此外,為了增強圖像的清晰度,AVS-M添加了圖像頭(Picture head)信息。讀取NALU流程中,每個NALU前有一個起始碼0x000001,為防止 內(nèi)部0x000001序列競爭,H.264編碼器在最后一字節(jié)前插入一個新的字節(jié)——0x03,所以解碼器檢測到該序列時,需將0x03刪掉,而AVS-M只需識別出起始碼0x000001。
②讀取宏塊類型(mb type)和宏塊編碼模板(cbp):編解碼圖像以宏塊劃分,一個宏塊由一個16*16亮度塊和相應的一個8*8cb和一個8*8cr色度塊組成。
(a) 兩標準的幀內(nèi)、幀間預測時宏塊的劃分是有區(qū)別的。H.264中,I_slice亮度塊有Intra_4*4和Intra_16*16兩種模式,色度塊只有8*8模式;P_slice宏塊分為16*16、16*8、8*16、8*8、8*4、4*8、4*4共7種模式。而AVS-M中,I_slice亮度塊有I_4*4和I_Direct兩模式,P_slice時宏塊的劃分和H.264中的劃分一致。
(b) 兩標準的宏塊cbp值計算也不相同。H.264中,Intra_16*16宏塊的亮度(色度)cbp直接通過讀mb type得到;非Intra_16*16宏塊的亮度cbp=coded_block_pattern%16,色度cbp=coded_block_pattern/16 。其中,亮度cbp最低4位有效,每位決定對應宏塊的殘差系數(shù)能不能為0;色度cbp為0時,對應殘差系數(shù)為0,cbp為1時,DC殘差系數(shù)不為0,AC系數(shù)為0,cbp為2時,DC、AC殘差系數(shù)都不為0。AVS-M中,當宏塊類型不是P_skip時,直接從碼流中得到cbp的索引值,并以此索引值查表得到codenum值,再以codenum查表分別得到幀內(nèi)/幀間cbp。此cbp為6位,每位代表宏塊按8*8劃分時能不能包含非零系數(shù),當變換系數(shù)不為0時,需進一步讀cbp_4*4中每位值來判斷一個8*8塊中4個4*4塊的系數(shù)能不能為0。
---------------------------------------------------------------------------------------------
總的來說H264的碼流的打包方式有兩種,一種為annex-b byte stream format的格式,這個是絕大部分編碼器的默認輸出格式,就是每個幀的開頭的3~4個字節(jié)是H264的start_code,0x00000001或者0x000001。
另一種是原始的NAL打包格式,就是開始的若干字節(jié)(1,2,4字節(jié))是NAL的長度,而不是start_code,此時必須借助某個全局的數(shù)據(jù)來獲得編碼器的profile,level,PPS,SPS等信息才可以解碼。
----------------------------------------------------------------------------
AVC vs. H.264
AVC and H.264 are synonymous. The standard is known by the full names "ISO/IEC 14496-10" and "ITU-T Recommendation H.264". In addition, a number of alternate names are used (or have been) in reference to this standard. These include:
- MPEG-4 part 10
- MPEG-4 AVC
- AVC
- MPEG-4 (in the broadcasting world MPEG4 part 2 is ignored)
- H.264
- JVT (Joint Video Team, nowadays rarely used referring to actual spec)
- H.26L (early drafts went by this name)
All of the above (and those I've missed) include the Annex B byte-stream format. Unlike earlier MPEG1/2/4 and H.26x codecs, the H.264 specification proper does not define a full bit-stream syntax. It describes a number of NAL (Network Abstraction Layer) units, a sequence of which can be decoded into video frames. These NAL units have no boundary markers, and rely on some unspecified format to provide framing.
Annex B of of the document specifies one such format, which wraps NAL units in a format resembling a traditional MPEG video elementary stream, thus making it suitable for use with containers like MPEG PS/TS unable to provide the required framing. Other formats, such as ISO base media based formats, are able to properly separate the NAL units and do not need the Annex B wrapping.
The H.264 spec suffers from a deficiency. It defines several header-type NAL units (SPS and PPS) without specifying how to pack them into the single codec data field available in most containers. Fortunately, most containers seem to have adopted the packing used by the ISO format known as MP4. 1. H.264起始碼
?? 在網(wǎng)絡(luò)傳輸h264數(shù)據(jù)時,一個UDP包就是一個NALU,解碼器可以很方便的檢測出NAL分界和解碼。但是如果編碼數(shù)據(jù)存儲為一個文件,原來的解碼器將無法從數(shù)據(jù)流中分別出每個NAL的起始位置和終止位置,為此h.264用起始碼來解決這一問題。
?? H.264編碼時,在每個NAL前添加起始碼 0x000001,解碼器在碼流中檢測到起始碼,當前NAL結(jié)束。為了防止NAL內(nèi)部出現(xiàn)0x000001的數(shù)據(jù),h.264又提出'防止競爭 emulation prevention"機制,在編碼完一個NAL時,如果檢測出有連續(xù)兩個0x00字節(jié),就在后面插入一個0x03。當解碼器在NAL內(nèi)部檢測到0x000003的數(shù)據(jù),就把0x03拋棄,恢復原始數(shù)據(jù)。
0x000000?? >>>>>>?? 0x00000300
0x000001?? >>>>>>?? 0x00000301
0x000002?? >>>>>>?? 0x00000302
0x000003?? >>>>>>?? 0x00000303
附上h.264解碼nalu中檢測起始碼的算法流程??
for(;;)
{
if next 24 bits are 0x000001
{
?? ??? startCodeFound = true
?? ??? break;
}
else
{
?? ??? flush 8 bits??
}
}// for(;;)
if(true == startCodeFound)
{
??? //startcode found
??? // Flush the start code found
??? flush 24 bits??
??? //Now navigate up to next start code and put the in between stuff
??? // in the nal structure.
??? for(;;)
??? {
?? ?? get next 24 bits & check if it equals to 0x000001
?? ?? if(false == (next 24 bits == 000001))
?? ?? {
?? ?? ?? // search for pattern 0x000000
?? ?? ?? check if next 24 bits are 0x000000
?? ?? ?? if(false == result)
?? ?? ?? {
?? ?? ?? ?? ??? // copy the byte into the buffer
?? ?? ?? ?? ??? copy one byte to the Nal unit ?? ?? ?? ???
?? ?? ?? }
?? ?? ?? else
?? ?? ?? {
?? ?? ?? ?? ??? break;
?? ?? ?? }
?? ?? }
?? ?? else
?? ?? {
?? ?? ?? ??? break;
?? ?? }
?? }//for(;;)
}
?? 2. MPEG4起始碼
?? ??? MPEG4的特色是VOP,沒有NALU的概念,仍使用startcode對每幀進行分界。MPEG4的起始碼是0x000001. 另外MPEG4中很多起始碼也很有用,比如video_object_sequence_start_code 0x000001B0 表示一個視頻對象序列的開始,VO_start_code 0x000001B6 表示一個VOP的開始. 0x000001B6之后的兩位,是00表示 I frame, 01 表示 P frame, 10 表示 B frame. 1.引言
H.264的主要目標:
1.高的視頻壓縮比
2.良好的網(wǎng)絡(luò)親和性
解決方案:
VCL?? video coding layer ?? 視頻編碼層
NAL?? network abstraction layer?? 網(wǎng)絡(luò)提取層
VCL:核心算法引擎,塊,宏塊及片的語法級別的定義
NAL:片級以上的語法級別(如序列參數(shù)集和圖像參數(shù)集),同時支持以下功能:獨立片解碼,起始碼唯一保證,SEI以及流格式編碼數(shù)據(jù)傳送
VCL設(shè)計目標:盡可能地獨立于網(wǎng)絡(luò)的情況下進行高效的編解碼
NAL設(shè)計目標:根據(jù)不同的網(wǎng)絡(luò)把數(shù)據(jù)打包成相應的格式,將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以外的應用使用。
重要性指示:標志該NAL單元用于重建時的重要性,值越大,越重要。
禁止位:網(wǎng)絡(luò)發(fā)現(xiàn)NAL單元有比特錯誤時可設(shè)置該比特為1,以便接收方丟掉該單元。
2.NAL語法語義
NAL層句法:
在編碼器輸出的碼流中,數(shù)據(jù)的基本單元是句法元素。
句法表征句法元素的組織結(jié)構(gòu)。
語義闡述句法元素的具體含義。
分組都有頭部,解碼器可以很方便的檢測出NAL的分界,依次取出NAL進行解碼。
但為了節(jié)省碼流,H.264沒有另外在NAL的頭部設(shè)立表示起始位置的句法元素。
如果編碼數(shù)據(jù)是存儲在介質(zhì)上的,由于NAL是依次緊密相連的,解碼器就無法在數(shù)據(jù)流中分辨出每個NAL的起始位置和終止位置。
解決方案:在每個NAL前添加起始碼:0X000001
在某些類型的介質(zhì)上,為了尋址的方便,要求數(shù)據(jù)流在長度上對齊,或某個常數(shù)的整數(shù)倍。所以在起始碼前添加若干字節(jié)的0來填充。
檢測NAL的開始:
0X000001和0X000000
我們必須考慮當NAL內(nèi)部出現(xiàn)了0X000001和0X000000
解決方案:
H.264提出了“防止競爭”機制:
0X000000——0X00000300
0X000001——0X00000301
0X000002——0X00000302
0X000003——0X00000303
為此,我們可以知道:
在NAL單元中,下面的三字節(jié)序列不應在任何字節(jié)對齊的位置出現(xiàn)
0X000000
0X000001
0X000002
Forbidden_zero_bit =0;
Nal_ref_idc:表示NAL的優(yōu)先級。0~3,取值越大,表示當前NAL越重要,需要優(yōu)先受到保護。如果當前NAL是屬于參考幀的片,或是序列參數(shù)集,或是圖像參數(shù)集這些重要的單位時,本句法元素必需大于0。
Nal_unit_type:當前NAL 單元的類型
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ù)
RBSP 原始字節(jié)序列載荷-->在SODB的后面填加了結(jié)尾比特(RBSP trailing bits 一個bit“1”)若干比特“0”,以便字節(jié)對齊
EBSP 擴展字節(jié)序列載荷-->在RBSP基礎(chǔ)上填加了仿校驗字節(jié)(0X03)它的原因是: 在NALU加到Annexb上時,需要添加每組NALU之前的開始碼StartCodePrefix,如果該NALU對應的slice為一幀的開始則用4位字節(jié)表示,ox00000001,否則用3位字節(jié)表示ox000001.為了使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 Of Data Bits),到nal_unit之間,經(jīng)過了以下三步處理:
1.SODB字節(jié)對齊處理后封裝成RBSP(Raw Byte 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單元邊界。在這樣的應用系統(tǒng)中,H.264/AVC規(guī)范定義了字節(jié)流格式,每個NAL單元前面增加3個字節(jié)的前綴,即同步字節(jié)。在比特流應用中,每個圖像需要增加一個附加字節(jié)作為邊界定位。還有一種可選特性,在字節(jié)流中增加附加數(shù)據(jù),用做擴充發(fā)送數(shù)據(jù)量,能實現(xiàn)快速邊界定位,恢復同步
Case2:IP網(wǎng)絡(luò)的RTP打包封裝
分組打包的規(guī)則
(1)額外開銷要少,使MTU尺寸在100~64k字節(jié)范圍都可以;
(2)不用對分組內(nèi)的數(shù)據(jù)解碼就可以判別該分組的重要性;
(3)載荷規(guī)范應當保證不用解碼就可識別由于其他的比特丟失而造成的分組不可解碼;
(4)支持將NALU分割成多個RTP分組;
?? (5)支持將多個NALU匯集在一個RTP分組中。
RTP的頭標可以是NALU的頭標,并可以實現(xiàn)以上的打包規(guī)則。
一個RTP分組里放入一個NALU,將NALU(包括同時作為載荷頭標的NALU頭)放入RTP的載荷中,設(shè)置RTP頭標值。為了避免IP層對大分組的再一次分割,片分組的大小一般都要小于MTU尺寸。由于包傳送的路徑不同,解碼端要重新對片分組排序,RTP包含的次序信息可以用來解決這一問題。
NALU分割
對于預先已經(jīng)編碼的內(nèi)容,NALU可能大于MTU尺寸的限制。雖然IP層的分割可以使數(shù)據(jù)塊小于64千字節(jié),但無法在應用層實現(xiàn)保護,從而降低了非等重保護方案的效果。由于UDP數(shù)據(jù)包小于64千字節(jié),而且一個片的長度對某些應用場合來說太小,所以應用層打包是RTP打包方案的一部分。
新的討論方案(IETF)應當符合以下特征:
(1)NALU的分塊以按RTP次序號升序傳輸;
(2)能夠標記第一個和最后一個NALU分塊;
(3)可以檢測丟失的分塊。
NALU合并
一些NALU如SEI、參數(shù)集等非常小,將它們合并在一起有利于減少頭標開銷。已有兩種集合分組:
(1)單一時間集合分組(STAP),按時間戳進行組合;
(2)多時間集合分組(MTAP),不同時間戳也可以組合。
NAL規(guī)范視頻數(shù)據(jù)的格式,主要是提供頭部信息,以適合各種媒體的傳輸和存儲。NAL支持各種網(wǎng)絡(luò),包括:
1.任何使用RTP/IP協(xié)議的實時有線和無線Internet 服務
2.作為MP4文件存儲和多媒體信息文件服務
3.MPEG-2系統(tǒng)
4.其它網(wǎng)
NAL規(guī)定一種通用的格式,既適合面向包傳輸,也適合流傳送。實際上,包傳輸和流傳輸?shù)姆绞绞窍嗤?#xff0c;不同之處是傳輸前面增加了一個起始碼前綴
在類似Internet/RTP面向包傳送協(xié)議系統(tǒng)中,包結(jié)構(gòu)中包含包邊界識別字節(jié),在這種情況下,不需要同步字節(jié)。
NAL單元分為VCL和非VCL兩種
VCL NAL單元包含視頻圖像采樣信息,
非VCL包含各種有關(guān)的附加信息,例如參數(shù)集(頭部信息,應用到大量的VCL NAL單元)、提高性能的附加信息、定時信息等
參數(shù)集:
參數(shù)集是很少變化的信息,用于大量VCL NAL單元的解碼,分為兩種類型:
1.序列參數(shù)集,作用于一串連續(xù)的視頻圖像,即視頻序列。
兩個IDR圖像之間為序列參數(shù)集。IDR和I幀的區(qū)別見下面。
2.?? 圖像參數(shù)集,作用于視頻序列中的一個或多個個別的圖像
序列和圖像參數(shù)集機制,減少了重復參數(shù)的傳送,每個VCL NAL單元包含一個標識,指
向有關(guān)的圖像參數(shù)集,每個圖像參數(shù)集包含一個標識,指向有關(guān)的序列參數(shù)集的內(nèi)容
因此,只用少數(shù)的指針信息,引用大量的參數(shù),大大減少每個VCL NAL單元重復傳送的信息。
序列和圖像參數(shù)集可以在發(fā)送VCL NAL單元以前發(fā)送,并且重復傳送,大大提高糾錯能力。序列和圖像參數(shù)集可以在“帶內(nèi)”,也可以用更為可靠的其他“帶外”通道傳送。
總結(jié)
以上是生活随笔為你收集整理的H264实时编码及NALU,RTP传输(ZZ)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C# Winform实现捕获窗体最小化、
- 下一篇: DC保存至BMP图像