寫在前面:RTP的解析,網上找了不少資料,可是都不全,因此我力圖整理出一個比較全面的解析,html
其中借鑑了不少文章,我都列在了文章最後,在此表示感謝。windows
互聯網的發展離不開你們的無私奉獻,我決定從我作起,但願你們支持。網絡
原創不易,轉載請附上連接,謝謝http://blog.csdn.net/chen495810242/article/details/39207305ide
圖1函數
1) V:RTP協議的版本號,佔2位,當前協議版本號爲2編碼
2) P:填充標誌,佔1位,若是P=1,則在該報文的尾部填充一個或多個額外的八位組,它們不是有效載荷的一部分。加密
3) X:擴展標誌,佔1位,若是X=1,則在RTP報頭後跟有一個擴展報頭spa
4) CC:CSRC計數器,佔4位,指示CSRC 標識符的個數.net
5) M: 標記,佔1位,不一樣的有效載荷有不一樣的含義,對於視頻,標記一幀的結束;對於音頻,標記會話的開始。3d
6) PT: 有效荷載類型,佔7位,用於說明RTP報文中有效載荷的類型,如GSM音頻、JPEM圖像等,在流媒體中大部分是用來區分音頻流和視頻流的,這樣便於客戶端進行解析。
7) 序列號:佔16位,用於標識發送者所發送的RTP報文的序列號,每發送一個報文,序列號增1。這個字段當下層的承載協議用UDP的時候,網絡情況很差的時候能夠用來檢查丟包。同時出現網絡抖動的狀況能夠用來對數據進行從新排序,序列號的初始值是隨機的,同時音頻包和視頻包的sequence是分別記數的。
8) 時戳(Timestamp):佔32位,必須使用90 kHz 時鐘頻率。時戳反映了該RTP報文的第一個八位組的採樣時刻。接收者使用時戳來計算延遲和延遲抖動,並進行同步控制。
9) 同步信源(SSRC)標識符:佔32位,用於標識同步信源。該標識符是隨機選擇的,參加同一視頻會議的兩個同步信源不能有相同的SSRC。
10) 特約信源(CSRC)標識符:每一個CSRC標識符佔32位,能夠有0~15個。每一個CSRC標識了包含在該RTP報文有效載荷中的全部特約信源。
注:基本的RTP說明並不定義任何頭擴展自己,若是遇到X=1,須要特殊處理
取一段碼流以下:
80 e0 00 1e 00 00 d2 f0 00 00 00 00 41 9b 6b 49 €?....??....A?kI
e1 0f 26 53 02 1a ff06 59 97 1d d2 2e 8c 50 01 ?.&S....Y?.?.?P.
cc 13 ec 52 77 4e e50e 7b fd 16 11 66 27 7c b4 ?.?RwN?.{?..f'|?
f6 e1 29 d5 d6 a4 ef3e 12 d8 fd 6c 97 51 e7 e9 ??)????>.??l?Q??
cfc7 5e c8 a9 51 f6 82 65 d6 48 5a 86 b0 e0 8c ??^??Q??e?HZ????
荷載格式定義三個不一樣的基本荷載結構,接收者能夠經過RTP荷載的第一個字節後5位(如圖2)識別荷載結構。
1) 單個NAL單元包:荷載中只包含一個NAL單元。NAL頭類型域等於原始 NAL單元類型,即在範圍1到23之間
2) 聚合包:本類型用於聚合多個NAL單元到單個RTP荷載中。本包有四種版本,單時間聚合包類型A (STAP-A),單時間聚合包類型B (STAP-B),多時間聚合包類型(MTAP)16位位移(MTAP16), 多時間聚合包類型(MTAP)24位位移(MTAP24)。賦予STAP-A, STAP-B, MTAP16, MTAP24的NAL單元類型號分別是 24,25, 26, 27
3) 分片單元:用於分片單個NAL單元到多個RTP包。現存兩個版本FU-A,FU-B,用NAL單元類型 28,29標識
經常使用的打包時的分包規則是:若是小於MTU採用單個NAL單元包,若是大於MTU就採用FUs分片方式。
定義在此的NAL單元包必須只包含一個。這意味聚合包和分片單元不能夠用在單個NAL 單元包中。而且RTP序號必須符合NAL單元的解碼順序。NAL單元的第一字節和RTP荷載頭第一個字節重合。如圖3。
打包H264碼流時,只需在幀前面加上12字節的RTP頭便可。分片只定義於單個NAL單元不用於任何聚合包。NAL單元的一個分片由整數個連續NAL單元字節組成。每一個NAL單元字節必須正好是該NAL單元一個分片的一部分。相同NAL單元的分片必須使用遞增的RTP序號連續順序發送(第一和最後分片之間沒有其餘的RTP包)。類似,NAL單元必須按照RTP順序號的順序裝配。
當一個NAL單元被分片運送在分片單元(FUs)中時,被引用爲分片NAL單元。STAPs,MTAPs不能夠被分片。 FUs不能夠嵌套。 即, 一個FU 不能夠包含另外一個FU。運送FU的RTP時戳被設置成分片NAL單元的NALU時刻。
圖 4 表示FU-A的RTP荷載格式。FU-A由1字節的分片單元指示(如圖5),1字節的分片單元頭(如圖6),和分片單元荷載組成。S: 1 bit 當設置成1,開始位指示分片NAL單元的開始。當跟隨的FU荷載不是分片NAL單元荷載的開始,開始位設爲0。
E: 1 bit 當設置成1, 結束位指示分片NAL單元的結束,即, 荷載的最後字節也是分片NAL單元的最後一個字節。當跟隨的 FU荷載不是分片NAL單元的最後分片,結束位設置爲0。
R: 1 bit 保留位必須設置爲0,接收者必須忽略該位
打包時,原始的NAL頭的前三位爲FU indicator的前三位,原始的NAL頭的後五位爲FU header的後五位。80 60 01 0f 00 0e 10 00 00 0000 00 7c 85 88 82 €`..........|???
00 0a 7f ca 94 05 3b7f 3e 7f fe 14 2b 27 26 f8 ...??.;.>.?.+'&?
89 88 dd 85 62 e1 6dfc 33 01 38 1a 10 35 f2 14 ????b?m?3.8..5?.
84 6e 21 24 8f 72 62f0 51 7e 10 5f 0d 42 71 12 ?n!$?rb?Q~._.Bq.
17 65 62 a1 f1 44 dc df 4b 4a 38 aa 96 b7 dd 24 .eb??D??KJ8????$打包時,FUindicator的F、NRI是NAL Header中的F、NRI,Type是28;FU Header的S、E、R分別按照分片起始位置設置,Type是NAL Header中的Type。
解包時,取FU indicator的前三位和FU Header的後五位,即0110 0101(0x65)爲NAL類型。針對H264 作以下PS 封裝:每一個IDR NALU 前通常都會包含SPS、PPS 等NALU,所以將SPS、PPS、IDR 的NALU 封裝爲一個PS 包,包括ps 頭,而後加上PS system header,PS system map,PES header+h264 raw data。因此一個IDR NALU PS 包由外到內順序是:PSheader| PS system header | PS system Map | PES header | h264 raw data。對於其它非關鍵幀的PS 包,就簡單多了,直接加上PS頭和PES 頭就能夠了。順序爲:PS header | PES header | h264raw data。以上是對只有視頻video 的狀況,若是要把音頻Audio也打包進PS 封裝,也能夠。當有音頻數據時,將數據加上PES header 放到視頻PES 後就能夠了。順序以下:PS 包=PS頭|PES(video)|PES(audio),再用RTP 封裝發送就能夠了。
GB28181 對RTP 傳輸的數據負載類型有規定(參考GB28181 附錄B),負載類型中96-127
RFC2250 建議96 表示PS 封裝,建議97 爲MPEG-4,建議98 爲H264
即咱們接收到的RTP 包首先須要判斷負載類型,若負載類型爲96,則採用PS 解複用,將音視頻分開解碼。若負載類型爲98,直接按照H264 的解碼類型解碼。
注:此方法不必定準確,取決於打包格式是否標準
PS 包中的流類型(stream type)的取值以下:
1) MPEG-4 視頻流: 0x10;
2) H.264 視頻流: 0x1B;
3) SVAC 視頻流: 0x80;
4) G.711 音頻流: 0x90;
5) G.722.1 音頻流: 0x92;
6) G.723.1 音頻流: 0x93;
7) G.729 音頻流: 0x99;
8) SVAC音頻流: 0x9B。圖7
1) Pack start code:包起始碼字段,值爲0x000001BA的位串,用來標誌一個包的開始。
2) System clock reference base,system clock reference extenstion:系統時鐘參考字段。
3) Pack stuffing length :包填充長度字段,3 位整數,規定該字段後填充字節的個數
80 60 53 1f 00 94 89 00 00 0000 00 00 00 01 ba €`S..??........?
7e ff 3e fb 44 01 00 5f 6b f8 00 00 01 e0 14 53 ~.>?D.._k?...?.S
80 80 05 2f bf cf bed1 1c 42 56 7b 13 58 0a 1e €€./????.BV{.X..
08 b1 4f 33 69 35 0453 6d 33 a8 04 15 58 d9 21 .?O3i5.Sm3?..X?!
9741 b9 f1 75 3d 94 2b 1f bc 0b b2 b4 97 bf 93 ?A??u=?+.?.?????
前12位是RTP Header,這裏再也不贅述;
000001ba是包頭起始碼;
接下來的9位包括了SCR,SCRE,MUXRate,具體看圖7
最後一位是保留位(0xf8),定義了是否有擴展,二進制以下
1111 1000
前5位跳過,後3位指示了擴展長度,這裏是0.
Systemheader當且僅當pack是第一個數據包時才存在,即系統標題以後就是節目流映射。取值0x000001BC的位串,指出節目流映射的開始,暫時不須要處理,讀取Header Length直接跳過便可。前5字節的結構同系統標題,見圖8。
取一段碼流分析系統標題和節目映射流
00 00 01 ba 45 a9 d4 5c 34 0100 5f 6b f8 00 00 ...?E??\4.._k?..
01 bb 00 0c 80 cc f5 04 e1 7f e0 e0 e8 c0 c0 20 .?..€??.?.?????
00 00 01 bc 00 1e e1 ff00 00 00 18 1b e0 00 0c ...?..?......?..
2a 0a 7f ff 00 00 0708 1f fe a0 5a 90 c0 00 00 *........??Z??..
00 00 00 00 00 00 01 e0 7f e0 80 80 0521 6a 75 .......?.?€€.!ju
前14個字節是PS包頭(注意,沒有擴展);
接下來的00 00 01 bb是系統標題起始碼;
接下來的00 0c說明了系統標題的長度(不包括起始碼和長度字節自己);
接下來的12個字節是系統標題的具體內容,這裏不作解析;
繼續看到00 00 01 bc,這是節目映射流起始碼;
緊接着的00 1e一樣表明長度;
跳過e1 ff,基本沒用;
接下來是00 18,表明基本流長度,說明了後面還有24個字節;
接下來的1b,意思是H264編碼格式;
下一個字節e0,意思是視頻流;
接下里00 0c,一樣表明接下的長度12個字節;
跳過這12個字節,看到90,這是G.711音頻格式;
下一個字節是c0,表明音頻流;
接下來的00 00一樣表明長度,這裏是0;
接下來4個字節是CRC,循環冗餘校驗。
到這裏節目映射流解析完畢。(好累)。
原創不易,轉載請附上連接,謝謝http://blog.csdn.net/chen495810242/article/details/39207305
好戲還在後頭呢。
圖9
別被這麼長的圖嚇到,其實原理相同,可是,你必須處理其中的每一位。
1) Packet start code prefix:值爲0x000001的位串,它和後面的stream id 構成了標識分組開始的分組起始碼,用來標誌一個包的開始。
2) Stream id:在節目流中,它規定了基本流的號碼和類型。0x(C0~DF)指音頻,0x(E0~EF)爲視頻
3) PES packet length:16 位字段,指出了PES 分組中跟在該字段後的字節數目。值爲0 表示PES 分組長度要麼沒有規定要麼沒有限制。這種狀況只容許出如今有效負載包含來源於傳輸流分組中某個視頻基本流的字節的PES 分組中。
4) PTS_DTS:2 位字段。當值爲'10'時,PTS 字段應出如今PES 分組標題中;當值爲'11'時,PTS 字段和DTS 字段都應出如今PES 分組標題中;當值爲'00'時,PTS 字段和DTS 字段都不出如今PES分組標題中。值'01'是不容許的。
5) ESCR:1位。置'1'時表示ESCR 基礎和擴展字段出如今PES 分組標題中;值爲'0'表示沒有ESCR 字段。
6) ESrate:1 位。置'1'時表示ES rate 字段出如今PES 分組標題中;值爲'0'表示沒有ES rate 字段。
7) DSMtrick mode:1 位。置'1'時表示有8 位特技方式字段;值爲'0'表示沒有該字段。
8) Additionalinfo:1 位。附加版權信息標誌字段。置'1'時表示有附加拷貝信息字段;值爲'0'表示沒有該字段。
9) CRC:1 位。置'1'時表示CRC 字段出如今PES 分組標題中;值爲'0'表示沒有該字段。
10) Extensionflag:1 位標誌。置'1'時表示PES 分組標題中有擴展字段;值爲'0'表示沒有該字段。
PES header data length: 8 位。PES 標題數據長度字段。指出包含在PES 分組標題中的可選字段和任何填充字節所佔用的總字節數。該字段以前的字節指出了有無可選字段。
老規矩,上碼流:
00 00 01 e0 21 33 80 80 05 2b 5f df 5c 95 71 84 ...?!3€€.+_?\?q?
aa e4 e9 e9 ec 40 cc17 e0 68 7b 23 f6 89 df 90 ?????@?.?h{#????
a9d4 be 74 b9 67 ad 34 6d f0 92 0d 5a 48 dd 13 ???t?g?4m??.ZH?.
00 00 01是起始碼;
e0是視頻流;
21 33 是幀長度;
接下來的兩個80 80見下面的二進制解析;
下一個字節05指出了可選字段的長度,前一字節指出了有無可選字段;
接下來的5字節是PTS;
第七、8字節的二進制以下:
1000 0000 1000 0000
按順序解析:
第7個字節:
10 是標誌位,必須是10;
00 是加擾控制字段,‘00’表示沒有加密,剩下的01,10,11由用戶自定義;
0 是優先級,1爲高,0爲低;
0 是數據對齊指示字段;
0 是版權字段;
0 是原始或拷貝字段。置'1'時表示相關PES分組有效負載的內容是原始的;'0'表示內容是一份拷貝;
第8個字節:
10 是PTS_DTS字段,這裏是10,表示有PTS,沒有DTS;
0 是ESCR標誌字段,這裏爲0,表示沒有該段;
0 是ES速率標誌字段,,這裏爲0,表示沒有該段;
0 是DSM特技方式標誌字段,,這裏爲0,表示沒有該段;
0 是附加版權信息標誌字段,,這裏爲0,表示沒有該段;
0 是PESCRC標誌字段,,這裏爲0,表示沒有該段;
0 是PES擴展標誌字段,,這裏爲0,表示沒有該段;
本段碼流只有PTS,貼一下解析函數
其餘字段可參考協議解析
ps:
遇到00 00 01 bd的,這個是私有流的標識
ps:
另外,有的hk攝像頭回調而後解讀出來的原始h.264碼流,有的一包裏只有分界符數據(nal_unit_type=9)或補充加強信息單元(nal_unit_type=6),若是直接送入解碼器,有可能會出現問題,這裏的處理方式要麼丟棄這兩個部分,要麼和以後的數據合起來,再送入解碼器裏,若有遇到的朋友能夠交流一下:)
寫在後面:
第一次發原創,在這裏感謝 @cmengwei 的無私幫助,提供了不少幫助,很是感謝。
文檔我都放在了個人資源裏面,有1個下載積分,你們不要吝嗇,絕對值得!
《RTP Payload Format for H.264 Video》
http://download.csdn.net/detail/chen495810242/7904367
《MPEG2-2(13818中文版)》
http://download.csdn.net/detail/chen495810242/7904401
RTP荷載H264的代碼參考:
http://blog.csdn.net/dengzikun/article/details/5807694
RTP荷載PS流的代碼參考:
http://www.pudn.com/downloads33/sourcecode/windows/multimedia/detail105823.html
http://www.oschina.net/code/snippet_99626_23737
請不要跟我要源碼,參考我提供的這些,你足以寫出一個能夠正常運行的程序。
授人以魚不如授人以漁。
其餘參考:
http://blog.csdn.net/duanbeibei/article/details/1698183
http://blog.csdn.net/wwyyxx26/article/details/15224879
原創不易,轉載請附上連接,謝謝http://blog.csdn.net/chen495810242/article/details/39207305