音視頻流媒體開發(fā)-目錄
iOS知識點-目錄
Android-目錄
Flutter-目錄
數據結構與算法-目錄
uni-pp-目錄
1 H264打包RTP的?法
RTP的特點不僅僅?持承載在UDP上琼掠,這樣利于低延遲?視頻數據的傳輸,另外?個特點是它允許通過其它協(xié)議接收端和發(fā)送端協(xié)商?視頻數據的封裝和編解碼格式狡逢,這樣固定頭的playload type字段就?較靈活酵紫。截??前為?或颊,RTP是我?過傳輸?視頻數據類型最多的,具體參考:
https://en.wikipedia.org/wiki/RTP_payload_formats危纫。
今天我以H264裸碼流NALU為例溢吻,給?家講述下如何進?H264的打包,這也是我上??篇封裝格式講解的固定套路怔毛,其中H264打包的詳細?法要參考RFC6184?檔员萍。
H.264 標 準 協(xié) 議 定 義 了 兩 種 不 同 的 類 型 : ? 種 是 VCL 即 Video Coding Layer , ? 種 是 NAL 即Network Abstraction Layer拣度。其中前者就是編碼器吐出來的原始編碼數據碎绎,沒有考慮傳輸和存儲問 題 。 后 ? 這 種 就 是 為 了 展 現 H.264 的 ? 絡 親 和 性 抗果, 對 VCL 輸 出 的 slice ? 數 據 進 ? 了 封 裝 為NALUs(NAL Units)混卵,然后再封裝為RTP包進?傳輸,這些都是H.264的基礎窖张,?后續(xù)?章。
NALU的基本格式是:NALU Header + NALU Data,其中NALU的頭由?個字節(jié)組成如下所示:
參考?檔:
https://tools.ietf.org/html/rfc3984 過時的
https://tools.ietf.org/html/rfc6184 最新的
我們看到1-11就是NALU的單個包類型蚁滋,但是?個NALU的??是不?樣的宿接,如果是?視頻數據的SPS PPS才??個字節(jié),對于IDR幀辕录,則有可能??KB睦霎。
這樣把NALU打包到RTP?式就很多,分為:
- ?個RTP包承載?個NALU走诞;
- 多個NALU合并到?個RTP副女;
- ?個?的NALU切分成多個RTP。
同時由于時間戳的問題蚣旱,就有了24-29?種類型碑幅。
但是對于發(fā)送端組RTP包的??來說戴陡,盡可能找簡單的打包?式。對于接受端則需要適配各種發(fā)送端的打包?式沟涨,因為?法決定輸?源的打包?式恤批。這?先分享下我們的打包?式,?較簡單(打包的時候不要搞太復雜的模式):
- 我們對于NALU的?度<=1400(rtp payload size)的則采?的是單?NALU打包到單?的RTP包中裹赴;
- 我們對于NALU的?度>1400的則采?了FU-A的?式進?了打包喜庞,這種就是把?個?的NALU進?了切分,最后接收?則進?了合并棋返,把多個RTP包合并成?個完整的NALU即可延都;
- 為什么NALU的?度?于1400字節(jié)就要進?FU-A切?,是因為底層MTU??值固定為1500睛竣,從傳輸效率講晰房,這??1400作為切分條件。
同時我們發(fā)現現在視頻監(jiān)控領域攝像頭通過RTP 傳輸碼流的打包?式都是基本這種酵颁,這種打包?案簡單容易實現嫉你,?滿?需要。如下圖所示:
① 28躏惋、29幽污、30三個RTP分別傳輸的SPS、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包時間戳也是?樣的吝梅;
那么到底將單?的NALU打包到RTP或者把?較?的NLAU打包到多個RTP即FU-A?式是怎么操作的呢虱疏?
1.1 打包?式之Single NAL Unit
就是?個RTP包打包?個單獨的NALU?式,其實最好理解憔涉,就是在RTP固定頭后?直接填充NLAU單元數據即可订框,即:
RTP Header + NALU Header + NALU Data; (不包括startcode)
為驗證猜想,進?了抓包和寫?件兜叨,我們發(fā)現寫?件的SPS和抓包RTP包固定頭后?的負載完全是?致的穿扳,寫?件中的SPS:
抓包中的RTP固定頭后?的SPS:
1.2 打包?式之FU-A
這種打包?式也不復雜,為了解釋清楚国旷,需要了解下?兩個數據包頭即FU indicator和Fu header矛物。
FU indication
這??的的F和NRI已經在NALU的Header解釋清楚了,就是NALU頭的前?三個bit位跪但,后?的TYPE就是NALU的FU-A類型28履羞,這樣在RTP固定頭后?第?字節(jié)的后?5bit提取出來就確認了該RTP包承載的不是?個完整的NALU,是其?部分屡久。
那么問題來了忆首,?個NALU切分成多個RTP包傳輸,那么到底從哪?開始哪?結束呢被环?可能有?說RTP包固定頭不是有mark標記么糙及,注意區(qū)分那個是以幀圖像的結束標記,這?要確定是NALU結束的標記筛欢,其次NALU的類型呢浸锨?那么就需要RTP固定12字節(jié)后?的Fu Header來進?區(qū)分。
FU header
字段解釋:
S: 1 bit 當設置成1,開始位指示分?NAL單元的開始版姑。當跟隨的FU荷載不是分?NAL單元荷載的開始柱搜,開始位設為0。
E: 1 bit 當設置成1, 結束位指示分?NAL單元的結束剥险,即, 荷載的最后字節(jié)也是分?NAL單元的最后?個字節(jié)聪蘸,當跟隨的FU荷載不是分?NAL單元的最后分?,結束位設置為0。
也就是說?個NALU切?時表制,第?個切?的SE是10健爬,然后中間的切?是00,最后?個切?時11夫凸。
R: 1 bit
保留位必須設置為0,接收者必須忽略該位阱持。
Type: 5 bits
此處的Type就是NALU頭中的Type,取1-23的那個值夭拌,表示 NAL單元荷載類型定義,
綜上所述:
對于?較?的NLAU進?FU-A切?時,其中NALU的Header字段在RTP打包時劃分為兩個字節(jié)
1鸽扁、NALU header的前3bit為RTP固定頭后?第?個字節(jié)FU-indication的前3bit蒜绽,后?5bit后?跟了FU-A打包這種類型28;
2、NALU header的后?5bit變成了RTP固定頭第?字節(jié)的后?5bit,其中前3bit標識了分?的開始和結束桶现。
為了驗證這種打包?式躲雅,我們同樣進?了寫?件和抓包,對第?個IDR幀的NLAU采取的這種分?進?了研究骡和。
第?個IDR幀的NALU第?個切?:
FU indication
?六機制:0x7C
?進制:0111 1100
FU header
?六進制:0x85
?進制:1000 0101
這?的SE是10相赁,則說明該RTP包承載的NALU的第?個切?。
這樣我們提取FU indication字節(jié)的前3bit位和Fu header字節(jié)后5bit位則為0110 0101即0x65這剛好符合IDR幀的NALU Header定義,后?的b8 00 00 03等?進制就是NALU的DATA字段慰于。
第?個IDR幀的NALU第?個切?:
FU indication
?六機制:0x7C
?進制:0111 1100
FU header
?六進制:0x05
?進制:0000 0101
這?的SE是00钮科,則說明該RTP包承載的NALU的中間切?。
按照同樣?法提取婆赠,則NALU Header的?進制為0110 0101即0x65绵脯,同樣說明是IDR幀類型,類似這種的中間切?有很多休里,從31-56RTP包都是中間切?蛆挫,直到最后?個NALU的切?。
第?個IDR幀的NALU最后?個切?:
FU indication
?六機制:0x7C
?進制:0111 1100
FU header
?六進制:0x45
?進制:0100 0101
這?的SE是01妙黍,則說明該RTP包承載的NALU的最后?個切?悴侵。
當然通過抓包你還可以到IDR幀時?較?的,?后?的P幀就相對?較?废境,因為?個NALU切?4次就完了畜挨,同樣能看到時間戳的變化值等信息。
我們可以看到發(fā)送端?般采?Single NAL Unit和FU-A打包?式就基本可以將H264數據發(fā)送到接收端了噩凹,對于AAC?頻來說巴元,直接將ADTS頭部去掉以1024字節(jié)組成?幀直接塞到RTP即可,打包并不難驮宴。?于其他的封裝格式如PS逮刨、TS或者H265,VPx等數據如何打包RTP,以后再給?家進?分享堵泽,完善這個傳輸系列修己。