1.RTP介紹
實時傳輸協議RTP(Real-time Transport Protocol)是一個網絡傳輸協議,它是由IETF的多媒體傳輸工作小組1996年在RFC 1889中公布的,后在RFC3550中進行更新。
國際電信聯盟ITU-T也發布了自己的RTP文檔,作為H.225.0,但是后來當IETF發布了關於它的穩定的標准RFC后就被取消了。它作為因特網標准在 [ RFC 3550 ] 有詳細說明.
RTP協議詳細說明了在互聯網上傳遞音頻和視頻的標准數據包格式。它一開始被設計為一個多播協議,但后來被用在很多單播應用中。RTP協議常用於流媒體系統(配合RTSP協議),
視頻會議和一鍵通(Push toTalk)系統(配合H.323或SIP),使它成為IP電話產業的技術基礎。RTP協議和RTP控制協議RTCP一起使用,而且它是建立在用戶數據報協議上的(UDP)。
2.RTP內容
RTP標准定義了兩個子協議 ,RTP和RTCP
數據傳輸協議RTP,用於實時傳輸數據。該協議提供的信息包括:時間戳(用於同步)、序列號(用於丟包和重排序檢測)、以及負載格式(用於說明數據的編碼格式)。
控制協議RTCP,用於QoS反饋和同步媒體流。相對於RTP來說,RTCP所占的帶寬非常小,通常只有5%。
3.RTP的使用
3.1.為什么要使用RTP
一提到流媒體傳輸、一談到什么視頻監控、視頻會議、語音電話(VOIP),都離不開RTP協議的應用,但當大家都根據經驗或者別人的應用而選擇RTP協議的時候,你可曾想過,為什么我們要使用RTP來進行流媒體的傳輸呢?為什么我們一定要用RTP?難道TCP、UDP或者其他的網絡協議不能達到我們的要求么?
像TCP這樣的可靠傳輸協議,通過超時和重傳機制來保證傳輸數據流中的每一個bit的正確性,但這樣會使得無論從協議的實現還是傳輸的過程都變得非常的復雜。而且,當傳輸過程中有數據丟失的時候,由於對數據丟失的檢測(超時檢測)和重傳,會數據流的傳輸被迫暫停和延時。
或許你會說,我們可以利用客戶端構造一個足夠大的緩沖區來保證顯示的正常,這種方法對於從網絡播放音視頻來說是可以接受的,但是對於一些需要實時交互的場合(如視頻聊天、視頻會議等),如果這種緩沖超過了200ms,將會產生難以接受的實時性體驗。
3.2.為什么RTP可以解決上述時延問題
RTP協議是一種基於UDP的傳輸協議,RTP本身並不能為按順序傳送數據包提供可靠的傳送機制,也不提供流量控制或擁塞控制,它依靠RTCP提供這些服務。
這樣,對於那些丟失的數據包,不存在由於超時檢測而帶來的延時,同時,對於那些丟棄的包,也可以由上層根據其重要性來選擇性的重傳。比如,對於I幀、P幀、B幀數據,由於其重要性依次降低,
故在網絡狀況不好的情況下,可以考慮在B幀丟失甚至P幀丟失的情況下不進行重傳,這樣,在客戶端方面,雖然可能會有短暫的不清晰畫面,但卻保證了實時性的體驗和要求。
4.RTP的協議層次
4.1.傳輸層的子層
下圖給出了流媒體應用中的一個典型的協議體系結構。
從圖中可以看出,RTP被划分在傳輸層,它建立在UDP上。同UDP協議一樣,為了實現其實時傳輸功能,RTP也有固定的封裝形式。
RTP用來為端到端的實時傳輸提供時間信息和流同步,但並不保證服務質量。服務質量由RTCP來提供。
4.2.應用層的一部分
從應用開發者的角度看,RTP 應當是應用層的一部分。在應用的發送端,開發者必須編寫用 RTP 封裝分組的程序代碼,然后把 RTP 分組交給 UDP 插口接口。在接收端,
RTP 分組通過 UDP 插口接口進入應用層后,還要利用開發者編寫的程序代碼從 RTP 分組中把應用數據塊提取出來。
5.RTP報文
5.1.RTP分組
RTP分組只包含RTP數據,而控制是由RTCP協議提供。RTP在1025到65535之間選擇一個未使用的偶數UDP端口號,而在同一次會話中的RTCP則使用下一個奇數UDP端口號。
端口號5004和5005分別用作RTP和RTCP的默認端口號。RTP分組的首部格式如圖2所示,其中前12個字節是必須的。
5.2.RTP首部
5.2.1.RTP報文頭格式(見RFC3550 Page12):
1).版本號(V):用來標志使用的RTP版本,占2位,當前協議版本號為2
2).填充位(P):填充標志,占1位,如果P=1,則該RTP包的尾部就包含附加的填充字節,在該報文的尾部填充一個或多個額外的八位組,它們不是有效載荷的一部分。
3).擴展位(X):擴展標志,占1位,如果X=1,則在RTP固定頭部后面就跟有一個擴展頭部
4).CSRC計數器(CC):CSRC計數器,占4位,指示固定頭部后面跟着的CSRC 標識符的個數
5).標記位(M):標記,占1位,該位的解釋由配置文檔(Profile)來承擔,不同的有效載荷有不同的含義,一般而言,對於視頻,標記一幀的結束;對於音頻,標記會話的開始。
6).載荷類型(PayloadType): 有效荷載類型,占7位,用於說明RTP報文中有效載荷的類型,如GSM音頻、JPEM圖像等,在流媒體中大部分是用來區分音頻流和視頻流的,這樣便於客戶端進行解析。
7).序列號(SN):占16位,用於標識發送者所發送的RTP報文的序列號,每發送一個報文,序列號增1。接收端可以據此檢測丟包和重建包序列,當下層的承載協議用UDP的時候,網絡狀況不好的時候可以用來檢查丟包,同時出現網絡抖動的情況可以用來對數據進行重新排序,序列號的初始值是隨機的,同時音頻包和視頻包的sequence是分別記數的。
8).時間戳(Timestamp): 占32位,記錄了該包中數據的第一個字節的采樣時刻。在一次會話開始時,時間戳初始化成一個初始值。即使在沒有信號發送時,時間戳的數值也要隨時間而不斷地增加(時間在流逝嘛)。時鍾頻率依賴於負載數據格式,並在描述文件(profile)中進行描述。一般而言,必須使用90 kHz 時鍾頻率。接收者使用時戳來計算延遲和延遲抖動,並進行同步控制。
9).同步源標識符(SSRC):占32位,用於標識同步信源,同步源就是指RTP包流的來源。在同一個RTP會話中不能有兩個相同的SSRC值。該標識符是隨機選取的,RFC1889推薦了MD5隨機算法。
10).貢獻源列表(CSRC List):可以有0~15個,每個CSRC標識符占32位,用來標志對一個RTP混合器產生的新包有貢獻的所有RTP包的源。由混合器將這些有貢獻的SSRC標識符插入表中。SSRC標識符都被列出來,以便接收端能正確指出交談雙方的身份。
5.2.2.取一段碼流如下:
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????
其中,
80 是V_P_X_CC
e0 是M_PT
00 1e 是SequenceNum
00 00 d2 f0 是Timestamp
00 00 00 00是SSRC
把前兩字節換成二進制如下
1000 0000 1110 0000
按順序解釋如下:
10 是V;
0 是P;
0 是X;
0000 是CC;
1 是M;
110 0000 是PT;
5.2.3.RTP擴展頭結構
圖 Rtp擴展頭
若 RTP 固定頭中的擴展比特位置1(注意:如果有CSRC列表,則在CSRC列表之后),
則一個長度可變的頭擴展部分被加到 RTP 固定頭之后。頭擴展包含 16 比特的長度域,指示擴展項中 32 比特字的個數,不包括 4 個字節擴展頭(因此零是有效值)。
RTP 固定頭之后只允許有一個頭擴展。為允許多個互操作實現獨立生成不同的頭擴展,或某種特定實現有多種不同的頭擴展,擴展項的前 16 比特用以識別標識符或參數。這 16 比特的格式由具體實現的上層協議定義。基本的 RTP 說明並不定義任何頭擴展本身。
5.3.RTP數據部分
5.3.1.RTP荷載H264碼流
1).碼流結構
RFC3984是H.264的baseline碼流在RTP方式下傳輸的規范,
2).荷載結構
荷載格式定義三個不同的基本荷載結構,接收者可以通過RTP荷載的第一個字節后5位(如上圖)識別荷載結構。
I、 單個NAL單元包:荷載中只包含一個NAL單元。NAL頭類型域等於原始 NAL單元類型,即在范圍1到23之間
II、 聚合包:本類型用於聚合多個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
III、分片單元:用於分片單個NAL單元到多個RTP包。現存兩個版本FU-A,FU-B,用NAL單元類型 28,29標識
對三種荷載結構的原文描述如下:
Common Structure of the RTP Payload Format:
The payload format defines three different basic payload structures.
A receiver can identify the payload structure by the first byte of
the RTP payload, which co-serves as the RTP payload header and, in
some cases, as the first byte of the payload. This byte is always
structured as a NAL unit header. The NAL unit type field indicates
which structure is present. The possible structures are as follows:
Single NAL Unit Packet: Contains only a single NAL unit in the
payload. The NAL header type field will be equal to the original NAL
unit type; i.e., in the range of 1 to 23, inclusive. Specified in
section 5.6.
Aggregation packet: Packet type used to aggregate multiple NAL units
into a single RTP payload. This packet exists in four versions, the
Single-Time Aggregation Packet type A (STAP-A), the Single-Time
Aggregation Packet type B (STAP-B), Multi-Time Aggregation Packet
(MTAP) with 16-bit offset (MTAP16), and Multi-Time Aggregation Packet
(MTAP) with 24-bit offset (MTAP24). The NAL unit type numbers
assigned for STAP-A, STAP-B, MTAP16, and MTAP24 are 24, 25, 26, and
27, respectively. Specified in section 5.7.
Fragmentation unit: Used to fragment a single NAL unit over multiple
RTP packets. Exists with two versions, FU-A and FU-B, identified
with the NAL unit type numbers 28 and 29, respectively. Specified in
section 5.8.
Table 1. Summary of NAL unit types and their payload structures
Type Packet Type name Section
---------------------------------------------------------
0 undefined -
1-23 NAL unit Single NAL unit packet per H.264 5.6
24 STAP-A Single-time aggregation packet 5.7.1
25 STAP-B Single-time aggregation packet 5.7.1
26 MTAP16 Multi-time aggregation packet 5.7.2
27 MTAP24 Multi-time aggregation packet 5.7.2
28 FU-A Fragmentation unit 5.8
29 FU-B Fragmentation unit 5.8
30-31 undefined -
同時又有三種封包模式,每種封包模式支持不同的荷載結構(具體使用哪種封包模式可以充SDP會話中取得),原文:
Packetization Modes
This memo specifies three cases of packetization modes:
o Single NAL unit mode
o Non-interleaved mode
o Interleaved mode
The single NAL unit mode is targeted for conversational systems that
comply with ITU-T Recommendation H.241 [15] (see section 12.1). The
non-interleaved mode is targeted for conversational systems that may
not comply with ITU-T Recommendation H.241. In the non-interleaved
mode, NAL units are transmitted in NAL unit decoding order. The
interleaved mode is targeted for systems that do not require very low
end-to-end latency. The interleaved mode allows transmission of NAL
units out of NAL unit decoding order.
The packetization mode in use MAY be signaled by the value of the
OPTIONAL packetization-mode MIME parameter or by external means. The
used packetization mode governs which NAL unit types are allowed in
RTP payloads. Table 3 summarizes the allowed NAL unit types for each
packetization mode. Some NAL unit type values (indicated as
undefined in Table 3) are reserved for future extensions. NAL units
of those types SHOULD NOT be sent by a sender and MUST be ignored by
a receiver. For example, the Types 1-23, with the associated packet
type "NAL unit", are allowed in "Single NAL Unit Mode" and in "Non-
Interleaved Mode", but disallowed in "Interleaved Mode".
Packetization modes are explained in more detail in section 6.
RFC 3984 RTP Payload Format for H.264 Video February 2005
Table 3. Summary of allowed NAL unit types for each packetization
mode (yes = allowed, no = disallowed, ig = ignore)
Type Packet Single NAL Non-Interleaved Interleaved
Unit Mode Mode Mode
-------------------------------------------------------------
0 undefined ig ig ig
1-23 NAL unit yes yes no
24 STAP-A no yes no
25 STAP-B no no yes
26 MTAP16 no no yes
27 MTAP24 no no yes
28 FU-A no yes yes
29 FU-B no no yes
30-31 undefined ig ig ig
常用的打包時的分包規則是:如果小於MTU采用單個NAL單元包,如果大於MTU就采用FUs分片方式。
因為常用的打包方式就是單個NAL包和FU-A方式
3).單個NAL包單元
定義在此的NAL單元包必須只包含一個。這意味聚合包和分片單元不可以用在單個NAL 單元包中。並且RTP序號必須符合NAL單元的解碼順序。NAL單元的第一字節和RTP荷載頭第一個字節重合。
打包H264碼流時,只需在幀前面加上12字節的RTP頭即可,具體來說:
12字節的RTP頭后面的就是音視頻數據。一個封裝單個NAL單元包到RTP的NAL單元流的RTP序號必須符合NAL單元的解碼順序。
對於 NALU 的長度小於 MTU 大小的包, 一般采用單一 NAL 單元模式.
對於一個原始的 H.264 NALU 單元常由[Start Code] [NALU Header] [NALU Payload]三部分組成, 其中 Start Code 用於標示這是一個 NALU 單元的開始, 必須是 "00 00 00 01" 或 "00 00 01", NALU 頭僅一個字節, 其后都是 NALU 單元內容.
打包時去除 "00 00 01" 或 "00 00 00 01" 的開始碼, 把其他數據封包的 RTP 包即可.
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|F|NRI| type | |
+-+-+-+-+-+-+-+-+ |
| |
| Bytes 2..n of a Single NAL unit |
| |
| +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| :...OPTIONAL RTP padding |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
如有一個 H.264 的 NALU 是這樣的:
[00 00 00 01 67 42 A0 1E 23 56 0E 2F ... ]
這是一個序列參數集 NAL 單元. [00 00 00 01] 是四個字節的開始碼, 67 是 NALU 頭, 42 開始的數據是 NALU 內容.
封裝成 RTP 包將如下:
[ RTP Header ] [ 67 42 A0 1E 23 56 0E 2F ]
即只要去掉 4 個字節的開始碼就可以了.
4).分片單元(FU-A)
數據比較大的H264視頻包,被RTP分片發送。12字節的RTP頭后面跟隨的就是FU-A分片:
當 NALU 的長度超過 MTU 時, 就必須對 NALU 單元進行分片封包. 也稱為 Fragmentation Units (FUs).
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| FU indicator | FU header | |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| |
| FU payload |
| |
| +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| :...OPTIONAL RTP padding |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Figure 14. RTP payload format for FU-A
I、FU indicator有以下格式:
+---------------+
|0|1|2|3|4|5|6|7|
+-+-+-+-+-+-+-+-+
|F|NRI| Type |
+---------------+
FU指示字節的類型域Type=28表示FU-A。。NRI域的值必須根據分片NAL單元的NRI域的值設置。
NAL單元荷載類型定義見下表
表1. 單元類型以及荷載結構總結
.Type Packet Type name
---------------------------------------------------------
0 undefined -
1-23 NAL unit Single NAL unit packet per H.264
24 STAP-A Single-time aggregation packet
25 STAP-B Single-time aggregation packet
26 MTAP16 Multi-time aggregation packet
27 MTAP24 Multi-time aggregation packet
28 FU-A Fragmentation unit
29 FU-B Fragmentation unit
30-31 undefined
II、FU header的格式如下:
+---------------+
|0|1|2|3|4|5|6|7|
+-+-+-+-+-+-+-+-+
|S|E|R| Type |
+---------------+
S: 1 bit 當設置成1,開始位指示分片NAL單元的開始。當跟隨的FU荷載不是分片NAL單元荷載的開始,開始位設為0。
E: 1 bit 當設置成1, 結束位指示分片NAL單元的結束,即, 荷載的最后字節也是分片NAL單元的最后一個字節。 當跟隨的FU荷載不是分片NAL單元的最后分片,結束位設置為0。
R: 1 bit 保留位必須設置為0,接收者必須忽略該位。
Type: 5 bits
III、打包和解包
打包:當編碼器在編碼時需要將原有一個NAL按照FU-A進行分片,原有的NAL的單元頭與分片后的FU-A的單元頭有如下關系:
原始的NAL頭的前三位為FU indicator的前三位,原始的NAL頭的后五位為FU header的后五位,
FU indicator與FU header的剩余位數根據實際情況決定。
解包:當接收端收到FU-A的分片數據,需要將所有的分片包組合還原成原始的NAl包時,FU-A的單元頭與還原后的NAL的關系如下:
還原后的NAL頭的八位是由FU indicator的前三位加FU header的后五位組成,即:
nal_unit_type = (fu_indicator & 0xe0) | (fu_header & 0x1f)
IV、取一段碼流分析如下:
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????$
前12字節是RTP Header
7c是FU indicator
85是FU Header
FU indicator(0x7C)和FU Header(0x85)換成二進制如下
0111 1100 1000 0101
按順序解析如下:
0 是F
11 是NRI
11100 是FU Type,這里是28,即FU-A
1 是S,Start,說明是分片的第一包
0 是E,End,如果是分片的最后一包,設置為1,這里不是
0 是R,Remain,保留位,總是0
00101 是NAl Type,這里是5,說明是關鍵幀(不知道為什么是關鍵幀請自行谷歌)
打包時,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類型。
V、注意
分片只定義於單個NAL單元不用於任何聚合包。NAL單元的一個分片由整數個連續NAL單元字節組成。每個NAL單元字節必須正好是該NAL單元一個分片的一部分。
相同NAL單元的分片必須使用遞增的RTP序號連續順序發送(第一和最后分片之間沒有其他的RTP包)。相似,NAL單元必須按照RTP順序號的順序裝配。
當一個NAL單元被分片運送在分片單元(FUs)中時,被引用為分片NAL單元。STAPs,MTAPs不可以被分片。 FUs不可以嵌套。
即, 一個FU 不可以包含另一個FU。運送FU的RTP時戳被設置成分片NAL單元的NALU時刻。
5).組合封包模式
當 NALU 的長度特別小時, 可以把幾個 NALU 單元封在一個 RTP 包中.
5.3.2.RTP荷載PS流
針對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)的取值如下:
a、 MPEG-4 視頻流: 0x10;
b、 H.264 視頻流: 0x1B;
c、 SVAC 視頻流: 0x80;
d、 G.711 音頻流: 0x90;
e、 G.722.1 音頻流: 0x92;
f、 G.723.1 音頻流: 0x93;
g、 G.729 音頻流: 0x99;
h、 SVAC音頻流: 0x9B。
1).PS包頭
圖
I、 Pack start code:包起始碼字段,值為0x000001BA的位串,用來標志一個包的開始。
II、 System clock reference base,system clock reference extenstion:系統時鍾參考字段。
III、 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,具體看上圖
最后一位是保留位(0xf8),定義了是否有擴展,二進制如下
1111 1000
前5位跳過,后3位指示了擴展長度,這里是0.
2).系統標題
圖
Systemheader當且僅當pack是第一個數據包時才存在,即PS包頭之后就是系統標題。取值0x000001BB的位串,指出系統標題的開始,暫時不需要處理,讀取Header Length直接跳過即可。
3).節目映射流
Systemheader當且僅當pack是第一個數據包時才存在,即系統標題之后就是節目流映射。取值0x000001BC的位串,指出節目流映射的開始,暫時不需要處理,讀取Header Length直接跳過即可。前5字節的結構同系統標題,見上圖。
取一段碼流分析系統標題和節目映射流
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,循環冗余校驗。
到這里節目映射流解析完畢。
4).PES分組頭部
圖
別被這么長的圖嚇到,其實原理相同,但是,你必須處理其中的每一位。
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;
第7、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,貼一下解析函數
[cpp] view plain copy
unsigned long parse_time_stamp (const unsigned char *p)
{
unsigned long b;
//共33位,溢出后從0開始
unsigned long val;
//第1個字節的第5、6、7位
b = *p++;
val = (b & 0x0e) << 29;
//第2個字節的8位和第3個字節的前7位
b = (*(p++)) << 8;
b += *(p++);
val += ((b & 0xfffe) << 14);
//第4個字節的8位和第5個字節的前7位
b = (*(p++)) << 8;
b += *(p++);
val += ((b & 0xfffe) >> 1);
return val;
}
其他字段可參考協議解析
ps:
遇到00 00 01 bd的,這個是私有流的標識
6.RTP的會話過程
當應用程序建立一個RTP會話時,應用程序將確定一對目的傳輸地址。目的傳輸地址由一個網絡地址和一對端口組成,有兩個端口:
一個給RTP包,一個給RTCP包,使得RTP/RTCP數據能夠正確發送。RTP數據發向偶數的UDP端口,而對應的控制信號RTCP數據發向相鄰的奇數UDP端口(偶數的UDP端口+1),這樣就構成一個UDP端口對。
RTP的發送過程如下,接收過程則相反。
RTP協議從上層接收流媒體信息碼流(如H.264),封裝成RTP數據包;RTCP從上層接收控制信息,封裝成RTCP控制包。
RTP將RTP 數據包發往UDP端口對中偶數端口;RTCP將RTCP控制包發往UDP端口對中的接收端口,即奇數端口。
7.RTP的profile機制
RTP為具體的應用提供了非常大的靈活性,它將傳輸協議與具體的應用環境、具體的控制策略分開,傳輸協議本身只提供完成實時傳輸的機制,開發者可以根據不同的應用環境,自主選擇合適的配置環境、以及合適的控制策略。
這里所說的控制策略指的是你可以根據自己特定的應用需求,來實現特定的一些RTCP控制算法,比如前面提到的丟包的檢測算法、丟包的重傳策略、一些視頻會議應用中的控制方案等等(這些策略我可能將在后續的文章中進行描述)。
對於上面說的合適的配置環境,主要是指RTP的相關配置和負載格式的定義。RTP協議為了廣泛地支持各種多媒體格式(如 H.264, MPEG-4, MJPEG, MPEG),沒有在協議中體現出具體的應用配置,而是通過profile配置文件以及負載類型格式說明文件的形式來提供。
對於任何一種特定的應用,RTP定義了一個profile文件以及相關的負載格式說明,相關的文件如下所示:
《RTP Profile for Audio and Video Conferences with Minimal Control》(RFC3551)
《RTP Payload Format for H.264 Video》(RFC3984)
《RTP Payload Format for MPEG-4 Audio/Visual Streams》(RFC3016)
等等,想了解更多可以點擊這里:http://en.wikipedia.org/wiki/RTP_audio_video_profile
說明:如果應用程序不使用專有的方案來提供有效載荷類型(payload type)、順序號或者時間戳,而是使用標准的RTP協議,應用程序就更容易與其他的網絡應用程序配合運行,
這是大家都希望的事情。例如,如果有兩個不同的公司都在開發因特網電話軟件,他們都把RTP合並到他們的產品中,這樣就有希望:使用不同公司電話軟件的用戶之間能夠進行通信。
8.RTCP的主要功能
服務質量的監視與反饋、媒體間的同步,以及多播組中成員的標識。在RTP會話期 間,各參與者周期性地傳送RTCP包。RTCP包中含有已發送的數據包的數量、丟失的數據包的數量等統計資料,
因此,各參與者可以利用這些信息動態地改變傳輸速率,甚至改變有效載荷類型。RTP和RTCP配合使用,它們能以有效的反饋和最小的開銷使傳輸效率最佳化,因而特別適合傳送網上的實時數據。
9.RTCP的使用
RTCP 控制協議需要與RTP數據協議一起配合使用,當應用程序啟動一個RTP會話時將同時占用兩個端口,分別供RTP 和RTCP使用。RTP本身並不能為按序傳輸數據包提供可靠的保證,
也不提供流量控制和擁塞控制,這些都由RTCP來負責完成。通常RTCP會采用與 RTP相同的分發機制,向會話中的所有成員周期性地發送控制信息,應用程序通過接收這些數據,
從中獲取會話參與者的相關資料,以及網絡狀況、分組丟失概率等反饋信息,從而能夠對服務質量進行控制或者對網絡狀況進行診斷。
10.RTCP報文
RTCP也是用UDP來傳送的,但RTCP封裝的僅僅是一些控制信息,因而分組很短,所以可以將多個RTCP分組封裝在一個UDP包中。RTCP有如下五種分組類型。
類型 |
縮寫表示 |
用途 |
200 |
SR(Sender Report) |
發送端報告 |
201 |
RR(Receiver Report) |
接收端報告 |
202 |
SDES(Source Description Items) |
源點描述 |
203 |
BYE |
結束傳輸 |
204 |
. APP |
特定應用 |
上述五種分組的封裝大同小異,下面只講述SR類型,而其它類型請參考RFC3550。
發送端報告分組SR(Sender Report)用來使發送端以多播方式向所有接收端報告發送情況。SR分組的主要內容有:相應的RTP流的SSRC,RTP流中最新產生的RTP分組的時間戳和NTP,RTP流包含的分組數,RTP流包含的字節數。
SR包的封裝如下圖所示。
版本(V):同RTP包頭域。
填充(P):同RTP包頭域。
接收報告計數器(RC):5比特,該SR包中的接收報告塊的數目,可以為零。
包類型(PT):8比特,SR包是200。
長度域(Length):16比特,其中存放的是該SR包以32比特為單位的總長度減一。
同步源(SSRC):SR包發送者的同步源標識符。與對應RTP包中的SSRC一樣。
NTP Timestamp(Network time protocol):SR包發送時的絕對時間值。NTP的作用是同步不同的RTP媒體流。
RTP Timestamp:與NTP時間戳對應,與RTP數據包中的RTP時間戳具有相同的單位和隨機初始值。
Sender’s packet count:從開始發送包到產生這個SR包這段時間里,發送者發送的RTP數據包的總數. SSRC改變時,這個域清零。
Sender`s octet count:從開始發送包到產生這個SR包這段時間里,發送者發送的凈荷數據的總字節數(不包括頭部和填充)。發送者改變其SSRC時,這個域要清零。
同步源n的SSRC標識符:該報告塊中包含的是從該源接收到的包的統計信息。
丟失率(Fraction Lost):表明從上一個SR或RR包發出以來從同步源n(SSRC_n)來的RTP數據包的丟失率。
累計的包丟失數目:從開始接收到SSRC_n的包到發送SR,從SSRC_n傳過來的RTP數據包的丟失總數。
收到的擴展最大序列號:從SSRC_n收到的RTP數據包中最大的序列號,
接收抖動(Interarrival jitter):RTP數據包接受時間的統計方差估計 上次SR時間戳(Last SR,LSR):取最近從SSRC_n收到的SR包中的NTP時間戳的中間32比特。如果目前還沒收到SR包,則該域清零。
上次SR以來的延時(Delay since last SR,DLSR):上次從SSRC_n收到SR包到發送本報告的延時。
RTCP數據報攜帶有服務質量監控的必要信息,能夠對服務質量進行動態的調整,並能夠對網絡擁塞進行有效的控制。由於RTCP數據報采用的是多播方式,
因此會話中的所有成員都可以通過RTCP數據報返回的控制信息,來了解其他參與者的當前情況。
在一個典型的應用場合下,發送媒體流的應用程序將周期性地產生發送端報告SR,該RTCP數據報含有不同媒體流間的同步信息,以及已經發送的數據報和字節的計數,
接收端根據這些信息可以估計出實際的數據傳輸速率。另一方面,接收端會向所有已知的發送端發送接收端報告RR,
該RTCP數據報含有已接收數據報的最大序列號、丟失的數據報數目、延時抖動和時間戳等重要信息,發送端應用根據這些信息可以估計出往返時延,
並且可以根據數據報丟失概率和時延抖動情況動態調整發送速率,以改善網絡擁塞狀況,或者根據網絡狀況平滑地調整應用程序的服務質量。
11.代碼描述
RTP header :
/*
* RTP header
*/
typedef struct
{
#if 0 //BIG_ENDIA
unsigned int version:2; /* protocol version */
unsigned int p:1; /* padding flag */
unsigned int x:1; /* header extension flag */
unsigned int cc:4; /* CSRC count */
unsigned int m:1; /* marker bit */
unsigned int pt:7; /* payload type */
unsigned int seq:16; /* sequence number */
#else
unsigned int cc:4; /* CSRC count */
unsigned int x:1; /* header extension flag */
unsigned int p:1; /* padding flag */
unsigned int version:2; /* protocol version */
unsigned int pt:7; /* payload type */
unsigned int m:1; /* marker bit */
unsigned int seq:16; /* sequence number */
#endif
u_int32 ts; /* timestamp */
u_int32 ssrc; /* synchronization source */
u_int32 csrc[1]; /* optional CSRC list */
} rtp_hdr_t;
RTCP Common header :
/*
* RTCP common header word
*/
typedef struct {
#if 0 //BIG_ENDIA
unsigned int version:2; /* protocol version */
unsigned int p:1; /* padding flag */
unsigned int count:5; /* varies by packet type */
#else
unsigned int count:5; /* varies by packet type */
unsigned int p:1; /* padding flag */
unsigned int version:2; /* protocol version */
#endif
unsigned int pt:8; /* RTCP packet type */
unsigned short length; /* pkt len in words, w/o this word */
} rtcp_common_t;
12.參考的原文:
https://github.com/EasyDarwin/Course/tree/master/流媒體開發實戰進階(RTSP視頻播放器)
http://blog.csdn.net/pu1030/article/details/7619908
http://blog.csdn.net/bripengandre/article/details/2238818
http://blog.csdn.net/chen495810242/article/details/39207305
http://www.360doc.com/content/11/1009/15/496343_154624612.shtml
https://tools.ietf.org/html/rfc3550
https://tools.ietf.org/html/rfc3984