生活随笔
收集整理的這篇文章主要介紹了
RTP之H264封包和解包
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
RTP之H264封包和解包
目錄
H264打包RTP的方法 打包方式之Single NAL Unit打包方式之FU-A FU indicationFU header
1. H264打包RTP的方法
RTP的特點不僅僅?持承載在UDP上,這樣利于低延遲?視頻數(shù)據(jù)的傳輸,另外?個特點是它允許通過其它協(xié)議接收端和發(fā)送端協(xié)商?視頻數(shù)據(jù)的封裝和編解碼格式,這樣固定頭的playload type字段就?較靈活。截??前為?,RTP是我?過傳輸?視頻數(shù)據(jù)類型最多的,具體參考:https://en.wikipedia.org/wiki/RTP_payload_formats以H264裸碼流NALU為例,進(jìn)?H264的打包,其中H264打包的詳細(xì)?法要參考RFC6184?檔。H.264標(biāo)準(zhǔn)協(xié)議定義了兩種不同的類型:?種是VCL即Video Coding Layer , ? 種 是 NAL 即Network Abstraction Layer。其中前者就是編碼器吐出來的原始編碼數(shù)據(jù),沒有考慮傳輸和存儲問題。后?這種就是為了展現(xiàn)H.264的?絡(luò)親和性,對VCL輸出的slice?數(shù)據(jù)進(jìn)?了封裝為NALUs(NAL Units),然后再封裝為RTP包進(jìn)?傳輸,這些都是H.264的基礎(chǔ),?后續(xù)?章。NALU的基本格式是:NALU Header + NALU Data,其中NALU的頭由?個字節(jié)組成如下所示:
+---------------+|0|1|2|3|4|5|6|7|+-+-+-+-+-+-+-+-+|F
|NRI
| Type
|+---------------+
其中 F (1bit):如果是壞幀,則置1,其余H.264固定為0。NRI(2 bit):?來指示該NALU 的重要性等級。值越?,表示當(dāng)前NALU越重要。具體?于0 時取何值,沒有具體規(guī)定。
例如:如果是00,則表示此幀即使丟失了,也不影響解碼;其他值則表示此幀如果丟失了,會影響解碼,這個字段指明了該NALU的重要性,但是實際我們不太關(guān)?這個字段。Nalu_Type(5 bit):NAL Unit的類型,這個值指明了NALU的類型,其中NALU的類型?下表
Nalu_TypeNALU內(nèi)容備注
| 0 | 未指定 | |
| 1 | ?IDR圖像編碼的slice | ?如普通I、P、B幀 |
| 2 | 編碼slice數(shù)據(jù)劃分A | 2類型時,只傳遞?中最重要的信息,如?頭,?中宏塊的預(yù)測模式等;?般不會?到; |
| 3 | 編碼slice數(shù)據(jù)劃分B | 3類型是只傳輸殘差;?般不會?到; |
| 4 | 編碼slice數(shù)據(jù)劃分C | 4時則只可以傳輸殘差中的AC系數(shù);?般不會?到; |
| 5 | IDR圖像中的編碼slice | IDR幀,IDR?定是I幀但是I幀不?定是IDR幀。 |
| 6 | SEI補充增強信息單元 | 可以存?些私有數(shù)據(jù)等; |
| 7 | SPS 序列參數(shù)集 | 編碼的參數(shù)配置 |
| 8 | PPS 圖像參數(shù)集 | 編碼的參數(shù)配置 |
| 9 | 接?單元定界符 | |
| 10 | 序列結(jié)束 | |
| 11 | 碼流結(jié)束 | |
| 12 | 填充數(shù)據(jù) | |
| 24 | STAP-A Single-time aggregation packet | 單?時間聚合包模式,意味著?個RTP包可以傳輸多個NALU,但是這些NALU的編碼時間要?樣才能聚合到?個RTP。 |
| 25 | STAP-B Single-time aggregation packet | 單?時間聚合包模式,?STAP-B多?個DON |
| 26 | MTAP 16 Muti-time aggregation packet | 多個時間聚合包模式:意味著?個RTP包可以傳輸多個NALU,但是這些NALU的編碼時間有可能不?樣。 |
| 27 | MTAP 24 Muti-time aggregation packet | 多個時間的聚合包模式 |
| 28 | FU-A Fragmentation unit | 分包模式:當(dāng)?個RTP容納不下?個NALU時,就需要FUs這種格式。 |
| 29 FU-B | Fragmention unit | 分包模式 |
| 30-31 | 未指定,保留 | |
參考?檔:https://tools.ietf.org/html/rfc6184我們看到1-11就是NALU的單個包類型,但是?個NALU的??是不?樣的,如果是?視頻數(shù)據(jù)的SPS PPS才??個字節(jié),對于IDR幀,則有可能??KB。這樣把NALU打包到RTP?式就很多,分為: ?個RTP包承載?個NALU;多個NALU合并到?個RTP;?個?的NALU切分成多個RTP 同時由于時間戳的問題,就有了24-29?種類型。但是對于發(fā)送端組RTP包的??來說,盡可能找簡單的打包?式。對于接受端則需要適配各種發(fā)送端的打包?式,因為?法決定輸?源的打包?式。這?先分享下我們的打包?式,?較簡單(打包的時候不要搞太復(fù)雜的模式): 我們對于NALU的?度<=1400(rtp payload size)的則采?的是單?NALU打包到單?的RTP包中;我們對于NALU的?度>1400的則采?了FU-A的?式進(jìn)?了打包,這種就是把?個?的NALU進(jìn)?了切分,最后接收?則進(jìn)?了合并,把多個RTP包合并成?個完整的NALU即可;為什么NALU的?度?于1400字節(jié)就要進(jìn)?FU-A切?,是因為底層MTU??值固定為1500,從傳輸效率講,這??1400作為切分條件。 同時我們發(fā)現(xiàn)現(xiàn)在視頻監(jiān)控領(lǐng)域攝像頭通過RTP 傳輸碼流的打包?式都是基本這種,這種打包?案簡單容易實現(xiàn),?滿?需要。
28、29、30三個RTP分別傳輸?shù)腟PS、PPS、SEI這三種NALU,其中?個NALU分到?個RTP包,這是單?打包?式;31、32三個RTP包分別傳輸了IDR幀的NALU單元,由于?較?,發(fā)送?采?了FU-A的打包?式;上圖還顯示了SPS、PPS、SEI的RTP包固定頭,Seq初始值不為0,為隨機值,并且?個RTP包就順序+1,這跟上?分析的?致;上?SPS、PPS、SEI本身不涉及時間戳,但是這?頭填充為和??后?的第?個RTP保持?致,同樣IDR的NALU切分的不同RTP包時間戳也是?樣的;RTP一般一個包的大小是140bbyte左右,指的是RTP payload,不包含RTP headerudp每個包有大小限制,MTU一般是1500byte,sendto一次不能發(fā)送超過1500byte的數(shù)據(jù)RTP包有大小之分 SPS:25byte左右PPS:5byte左右SEI:600byte左右I幀:1080p為200K字節(jié)左右,一個RTP包發(fā)送不完一個I幀 同一個NALU劃分成多個RTP包進(jìn)行發(fā)送,比如I幀拆分成多個RTP包一個RTP包也可以發(fā)送多個NALU,比如:sps和pps、sei幀一起發(fā)送,很多時候,為了簡化程序,sps,pps,sei幀還是發(fā)送獨立的包。那么到底將單?的NALU打包到RTP或者把?較?的NLAU打包到多個RTP即FU-A?式是怎么操作的呢?
1. 打包方式之Single NAL Unit
就是?個RTP包打包?個單獨的NALU?式,其實最好理解,就是在RTP固定頭后?直接填充NLAU單元數(shù)據(jù)即可,即:RTP Header + NALU Header + NALU Data; (不包括startcode)進(jìn)?抓包和寫?件,我們發(fā)現(xiàn)寫?件的SPS和抓包RTP包固定頭后?的負(fù)載完全是?致的,寫?件中的SPS:抓包中的RTP固定頭后?的SEI:
2. 打包方式之FU-A
這種打包?式也不復(fù)雜,為了解釋清楚,需要了解下?兩個數(shù)據(jù)包頭即FU indicator和Fu header
1. FU indication
+---------------+|0|1|2|3|4|5|6|7|+-+-+-+-+-+-+-+-+|F
|NRI
| Type
|+---------------+
這??的的F和NRI已經(jīng)在NALU的Header解釋清楚了,就是NALU頭的前?三個bit位,后?的TYPE就是NALU的FU-A類型28,這樣在RTP固定頭后?第?字節(jié)的后?5bit提取出來就確認(rèn)了該RTP包承載的不是?個完整的NALU,是其?部分。那么問題來了,?個NALU切分成多個RTP包傳輸,那么到底從哪?開始哪?結(jié)束呢?可能有?說RTP包固定頭不是有mark標(biāo)記么,注意區(qū)分那個是以幀圖像的結(jié)束標(biāo)記,這?要確定是NALU結(jié)束的標(biāo)記,其次NALU的類型呢?那么就需要RTP固定12字節(jié)后?的Fu Header來進(jìn)?區(qū)分。
2. FU header
+---------------+|0|1|2|3|4|5|6|7|+-+-+-+-+-+-+-+-+|S
|E
|R
| Type
|+---------------+
字段解釋:
S: 1 bit,當(dāng)設(shè)置成1,開始位指示分?NAL單元的開始。當(dāng)跟隨的FU荷載不是分?NAL單元荷載的開始,開始位設(shè)為0。E: 1 bit,當(dāng)設(shè)置成1, 結(jié)束位指示分?NAL單元的結(jié)束,即, 荷載的最后字節(jié)也是分?NAL單元的最后?個字節(jié),當(dāng)跟隨的FU荷載不是分?NAL單元的最后分?,結(jié)束位設(shè)置為0。也就是說?個NALU切?時,第?個切?的SE是10,然后中間的切?是00,最后?個切?時01。R: 1 bit,保留位必須設(shè)置為0,接收者必須忽略該位。Type: 5 bits:此處的Type就是NALU頭中的Type,取1-23的那個值,表示 NAL單元荷載類型定義。 綜上所述:
對于?較?的NLAU進(jìn)?FU-A切?時,其中NALU的Header字段在RTP打包時劃分為兩個字節(jié)
NALU header的前3bit為RTP固定頭后?第?個字節(jié)FU-indication的前3bit,后?5bit后?跟了FU-A打包這種類型28;NALU header的后?5bit變成了RTP固定頭第?字節(jié)的后?5bit,其中前3bit標(biāo)識了分?的開始和結(jié)束 為了驗證這種打包?式,我們同樣進(jìn)?了寫?件和抓包,對第?個IDR幀的NLAU采取的這種分?進(jìn)?了研究。
第?個IDR幀的NALU第?個切?:
FU indication
?六機制:
0x7C
?進(jìn)制:
0111 1100
FU header
?六進(jìn)制:
0x85
?進(jìn)制:
1000 0101
這?的SE是
10,則說明該RTP包承載的NALU的第?個切?
這樣我們提取FU indication字節(jié)的前3bit位和Fu header字節(jié)后5bit位則為0110 0101即0x65這剛好符合IDR幀的NALU Header定義,后?的88 84 00 2f等?進(jìn)制就是NALU的DATA字段。第?個IDR幀的NALU第?個切?:
FU indication
?六機制:
0x7C
?進(jìn)制:
0111 1100
FU header
?六進(jìn)制:
0x05
?進(jìn)制:
0000 0101
這?的SE是
00,則說明該RTP包承載的NALU的中間切?。
按照同樣?法提取,則NALU Header的?進(jìn)制為0110 0101即0x65,同樣說明是IDR幀類型,類似這種的中間切?有很多,從31-56RTP包都是中間切?,直到最后?個NALU的切?。第?個IDR幀的NALU最后?個切?:
FU indication
?六機制:
0x7C
?進(jìn)制:
0111 1100
FU header
?六進(jìn)制:
0x45
?進(jìn)制:
0100 0101
這?的SE是
01,則說明該RTP包承載的NALU的最后?個切?
當(dāng)然通過抓包你還可以到IDR幀時?較?的,?后?的P幀就相對?較?,因為?個NALU切?4次就完了,同樣能看到時間戳的變化值等信息。我們可以看到發(fā)送端?般采?Single NAL Unit和FU-A打包?式就基本可以將H264數(shù)據(jù)發(fā)送到接收端了,對于AAC?頻來說,直接將ADTS頭部去掉以1024字節(jié)組成?幀直接塞到RTP即可,打包并不難。
總結(jié)
以上是生活随笔為你收集整理的RTP之H264封包和解包的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。