一、什么是 RTSP?協議
1.1 RTSP 協議簡介?
RTSP,全稱實時流傳輸協議(Real Time Streaming Protocol),是一種位于應用層的網絡協議。它主要用于在流媒體系統中控制實時數據(如音頻、視頻等)的傳輸,并不直接負責媒體數據的傳輸,而是像一個 “遙控器”,通過發送一系列指令(如播放、暫停、快進、后退等)來對媒體流的傳輸過程進行管理和控制。?
1.2 RTSP傳輸基本原理
我們所說的RTSP傳輸并不是只依靠RTSP協議,還要依賴RTP、RTCP、SDP協議共同實現媒體數據流的傳輸和控制。
1.2.1 RTSP?
- 作用:RTSP 主要負責對實時媒體流的傳輸進行控制,協調客戶端和服務器之間的交互。它可以建立和終止媒體會話,以及對媒體流的播放狀態進行控制。?
- 傳輸方式:RTSP 本身通常使用 TCP 進行傳輸。這是因為 RTSP 的控制指令需要可靠的傳輸,確保指令能夠準確無誤地到達對方,避免因指令丟失或錯誤而導致的控制混亂。?
1.2.2 RTP
- 作用:RTP(Real-time Transport Protocol,實時傳輸協議)主要負責實時媒體數據(如音頻、視頻)的實際傳輸,RTP包是音視頻數據的載體。它能夠為實時數據提供時間戳、序列號等信息,幫助接收端正確地重組和播放媒體數據。?
- 傳輸方式:RTP 通常基于 UDP 進行傳輸。由于 UDP 具有傳輸速度快、延遲低的特點,能夠很好地滿足實時媒體數據對實時性的要求。雖然 UDP 不保證數據傳輸的可靠性,可能會出現數據包丟失的情況,但對于音頻、視頻等實時數據來說,少量的數據包丟失對播放效果的影響相對較小,而實時性更為重要。
1.2.3 RTCP
- 作用:RTCP(Real-time Transport Control Protocol,實時傳輸控制協議)與 RTP 配合使用,主要用于監控 RTP 數據傳輸的質量。它可以收集和反饋諸如數據包丟失率、延遲抖動、網絡擁塞等信息,以便發送端和接收端根據這些信息調整傳輸策略,從而保證媒體流的傳輸質量。?
- 傳輸方式:RTCP 一般也基于 UDP 進行傳輸,并且通常與 RTP 共享同一個端口對(RTCP使用對應的RTP端口號+1的端口,例如某一視頻流RTP端口號31590,該視頻流RTCP端口號31591),以便更好地與 RTP 協同工作,及時獲取和反饋傳輸質量信息。?
(注意!!! 音頻和視頻流的rtp與rtcp分開發送,假設一場直播中有一個音頻流和一個視頻流,那么音頻RTP發送端口A,音頻RTCP發送端口A+1,視頻RTP發送端口B,視頻RTCP發送端口B+1, A != B)
1.2.4 SDP?
- 作用:SDP(Session Description Protocol,會話描述協議)用于描述媒體會話的相關信息,如媒體類型(音頻、視頻)、編碼格式、傳輸地址、端口號等。它為通信雙方提供了協商媒體會話參數的基礎,讓接收端能夠了解如何正確接收和解析媒體數據。?
- 傳輸方式:SDP 本身并不負責數據的傳輸,它通常作為其他協議(?RTSP)消息的一部分進行傳輸。例如,在 RTSP 的會話建立過程中,服務器會通過 RTSP 消息將包含 SDP 信息的數據發送給客戶端,客戶端根據 SDP 信息來準備接收和播放媒體流。?
1.3 TCP、UDP 傳輸區別?
- 連接方式:TCP 是面向連接的協議,在數據傳輸之前需要通過三次握手建立連接,數據傳輸完成后需要通過四次揮手釋放連接;而 UDP 是無連接的協議,通信雙方在傳輸數據之前不需要建立連接,可以直接發送數據。?
- 可靠性:TCP 具有可靠傳輸的特點,它通過序列號、確認應答、重傳機制等確保數據能夠準確、完整地到達接收端,并且數據傳輸的順序與發送順序一致;UDP 不提供可靠性保障,它不保證數據的到達,也不保證數據傳輸的順序,可能會出現數據包丟失、重復或亂序的情況。?
- 傳輸速度:由于 TCP 需要進行連接建立、確認應答、重傳等操作,會增加額外的開銷,因此傳輸速度相對較慢;UDP 不需要這些額外的操作,開銷較小,傳輸速度更快,實時性更好。?
- 適用場景:TCP 適用于對可靠性要求較高的場景,如文件傳輸、電子郵件、網頁瀏覽等,這些場景中數據的準確性和完整性至關重要;UDP 適用于對實時性要求較高的場景,如音頻、視頻傳輸、實時游戲、視頻會議等,這些場景中少量的數據丟失對整體效果影響不大,但對傳輸延遲有較高的要求。
下面對RTP,RTCP,RTSP,SDP分開詳解
二、RTP 協議
2.1 RTP 報文頭部
RTP 報文的核心設計目標是讓實時媒體數據在網絡中跑得又快又準。它的結構分為?固定頭部(12 字節)?和?媒體數據負載,固定頭部字段包括:
字段標識 | 位寬(bit) | 功能說明 |
---|---|---|
V(版本號) | 2 位 | RTP 的 “身份證”,目前通用版本是2 (二進制10 ),確保大家用同一種規則通信。 |
P(填充標志) | 1 位 | 特殊情況下加的 “填充物”,比如某些加密算法需要數據對齊時,末尾會補幾個字節(但這些字節不算有效內容)。若?P=1 ,報文尾部會填充?1 個或多個額外字節。 |
X(擴展標志) | 1 位 | 允許自定義 “插件” 字段,比如在直播中傳遞分辨率、幀率等額外信息。若?X=1 ,RTP 固定頭部后會緊跟?自定義擴展報頭(需協商格式,擴展元數據等)。 |
CC(CSRC 計數器) | 4 位 | 指示后續?CSRC 標識符的數量(僅混音場景非零,最多 15 個)。 |
M(標記位) | 1 位 | 語義由載荷類型定義: -?視頻:標記一幀的結束(如關鍵幀邊界); -?音頻:標記一幀的開始(如會話切換點)。 |
PT(有效載荷類型) | 7 位 | 定義載荷的媒體格式(視頻/音頻)。 - 比如 96=H.264視頻 ,8=PCMA音頻 ,這些編號不是固定的,需要在 SDP 協議中提前約定。 |
序列號 | 16 位 | 每發 1 個包序號 + 1(初始值隨機): 接收端通過序號檢測?丟包、亂序,并重建數據順序。 |
時戳(Timestamp) | 32 位 | 標記載荷第一個字節的采樣時刻: |
SSRC(同步信源) | 32 位 | 區分不同數據流的 “名字”: |
?除此之外還有貢獻信源(CSRC)標識符(長度可變,所以不屬于固定頭部):每個CSRC標識符占32位,可以有0~15個。每個CSRC標識了包含在該RTP 報?有效載荷中的所有貢獻信源。
對于Timestamp,SSRC和CSRC,這里詳細解釋一下:
時間戳(Timestamp):
想象你在錄制一段視頻:
- 每按下一次快門(采樣),時間戳就增加一個固定值。比如 30fps 的視頻,每幀增加
3000
(90kHz 時鐘下的單位),就像每過 33.3ms 給幀打個標記; - 接收端根據這些標記,就能知道幀該按什么順序播放,以及如何與音頻同步(比如說話的聲音和嘴型同時出現)。
?同步源(SSRC)
假設一場多人直播:
- 主播的攝像頭(SSRC_A)和嘉賓的攝像頭(SSRC_B)是兩個獨立的視頻流;
- 即使它們通過同一個網絡傳輸,接收端也能通過 SSRC_A 和 SSRC_B 把畫面分開顯示;
- SSRC 是隨機生成的,如果兩個設備不巧生成了相同的 SSRC,就像兩個人進了同一間房,需要重新分配(沖突概率極低)。
貢獻源(CSRC)
想象一個在線合唱比賽:
- 每個歌手的麥克風都是獨立的 SSRC(SSRC1、SSRC2、SSRC3);
- 混音器把他們的聲音合并成一個流(新的 SSRC_M),并在 CSRC 列表中記錄原始的 SSRC1、SSRC2、SSRC3;
- 聽眾收到這個合并流時,通過查看CSRC就能知道每個聲音來自誰。
RTP 之所以要設計這些頭部字段就是為了:
- 序列號解決順序問題(包是否丟失或亂序);
- 時間戳解決時間問題(媒體數據何時該播放);
- SSRC解決來源問題(數據是誰發的);
- CSRC解決混音問題(合并后的數據來自哪里)。
這種設計讓 RTP 在 UDP 上實現了低延遲、高可控性的實時傳輸,即使網絡不穩定,也能通過 RTCP 反饋(見下文)動態調整,確保音視頻流暢。
2.2?RTP 報文有效載荷
2.2.1 H264裸碼流封包解包
(一)H.264 碼流的基本結構:NALU
H.264 視頻流的核心單元是NALU(Network Abstraction Layer Unit),它像快遞包裹一樣包含視頻數據和元信息。每個 NALU 由兩部分組成(不考慮startcode):
- NALU 頭(1 字節):
- F(1 位):錯誤標志,通常為 0(正常傳輸);
- NRI(2 位):重要性等級(00 = 可丟棄,11 = 最高優先級),比如 I 幀的 NRI 通常為 11;
- Type(5 位):標識 NALU 類型(如
5=IDR幀
,7=SPS參數集
)。
- NALU 負載:實際的視頻數據(如 I 幀像素、P 幀殘差等)。
關于NALU詳細可以參考:萬字長文詳解 H.264 編碼原理與 NALU 格式:走進視頻壓縮世界_h264-CSDN博客
關鍵問題:
- 一個 NALU 可能非常大(如 1080P 的 I 幀可達 200KB),而 UDP 包最大負載約 1500 字節(MTU限制),必須分片傳輸;
- 多個小 NALU(如 SPS、PPS、SEI)可以合并成一個 RTP 包,減少傳輸開銷。
(二)RTP 封包策略
RTP 封裝 H.264 的核心是將 NALU 適配到網絡傳輸單元,主要有三種模式:
1. 單一 NALU 模式(Single NALU Packet)
- 適用場景:NALU 大小 ≤ 1400 字節(如 P 幀、B 幀、SPS/PPS)。
- 封包結構:
?RTP頭(12字節) + NALU頭(1字節) + NALU負載
- 示例:SPS(25 字節)直接封裝為一個 RTP 包,RTP 頭的PT
取
H.264 負載類型。
- 示例:SPS(25 字節)直接封裝為一個 RTP 包,RTP 頭的PT
- 優勢:簡單高效,接收端無需重組;
- 局限:無法處理大 NALU(如 I 幀)。
2. 組合包模式(Aggregation Packet)
將多個小 NALU 合并到一個 RTP 包中,分為兩種類型:
- STAP-A(單時間聚合包):
- 適用場景:同一時間生成的多個小 NALU(如 SPS+PPS+SEI)。
- 封包結構:
?RTP頭 + STAP-A頭(1字節) + [NALU長度(2字節) + NALU頭 + NALU負載] × N
- STAP-A 頭:
Type=24
,保留 F 和 NRI 與第一個 NALU 一致。
- STAP-A 頭:
- 示例:WebRTC 中常將 SPS 和 PPS 封裝在一個 STAP-A 包中,減少首幀延遲(WebRTC實際數據流傳輸也是RTP包)。
- MTAP(多時間聚合包):
- 適用場景:不同時間生成的 NALU(如跨幀的 SEI)。
- 復雜點:需記錄每個 NALU 的時間戳偏移(如 MTAP16 用 16 位存儲偏移量)。
3. 分片模式(Fragmentation Unit)
將大 NALU 拆分為多個 RTP 包,核心是FU-A 分片單元:
- 適用場景:NALU > 1400 字節(如 1080P 的 I 幀)。
- 封包結構:
?RTP頭 + FU指示符(1字節) + FU頭(1字節) + NALU分片負載
- FU 指示符:
- 前 3 位保留 F 和 NRI,與原始 NALU 頭一致;
Type=28
(FU-A 類型)。
- FU 頭:
- S(1 位):分片開始標志(僅第一個包為 1);
- E(1 位):分片結束標志(僅最后一個包為 1);
- R(1 位):保留位(0);
- Type(5 位):原始 NALU 的 Type(如
5=IDR幀
)。
- FU 指示符:
- 分片示例:
- 一個 200KB 的 IDR 幀被拆分為 145 個 RTP 包,第一個包
S=1,E=0
,最后一個包S=0,E=1
。
- 一個 200KB 的 IDR 幀被拆分為 145 個 RTP 包,第一個包
這里對FU指示符和FU頭展開解釋一下:
FU指示符(FU indication)
+---------------+
|0|1|2|3|4|5|6|7|
+-+-+-+-+-+-+-+-+
|F|NRI| Type |
+---------------+
這??的的F和NRI就是NALU的Header中的F和NRI,即NALU頭的前?三個bit位,后?的 TYPE就是NALU的FU-A類型28,這樣在RTP固定頭后?第?字節的后?5bit提取出來就確認了該 RTP包承載的不是?個完整的NALU,是其?部分。 那么問題來了,?個NALU切分成多個RTP包傳輸,那么到底從哪?開始哪?結束呢?可能有?說RTP包固定頭不是有mark標記么,注意區分那個是以幀圖像的結束標記,這?要確定是NALU結束的標記,其次NALU的類型呢?那么就需要RTP固定12字節后?的Fu Header來進?區分。
FU頭(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。也就是說?個NALU切?時,第?個切?的SE是10,然后中間的切?是00,最后?個切?時11。
R: 1 bit? 保留位必須設置為0,接收者必須忽略該位。
Type: 5 bits? 此處的Type就是NALU頭中的Type,取1-23的那個值,表示 NAL單元荷載類型定義。
總結一下:
當一個大 NALU(如 IDR 幀)被拆分為多個 RTP 包傳輸時,如何讓接收端知道 “分片從哪開始、到哪結束,以及原 NALU 是什么類型”?成為核心問題。這里的關鍵是?RTP 負載中的「FU 指示符」和「FU 頭」,而非 RTP 固定頭的M
標記 ——
1. 字段分工:誰來標記 NALU 的邊界?
層級 | 字段 | 作用 | 誤區提醒 |
---|---|---|---|
RTP 固定頭 | M (標記位) | 標記一幀圖像的邊界(如整幀視頻的結束),而非單個 NALU 的邊界。 | 若一幀包含多個 NALU(如 I 幀含多個 Slice),M 無法標記 NALU 的結束。 |
RTP 負載頭 | FU 指示符 | 第 1 字節,前 3 位繼承原 NALU 的F (錯誤標志)和NRI (優先級),后 5 位置為28 (標識這是FU-A 分片包)。 | 告訴接收端:“我不是完整 NALU,是分片的一部分。” |
RTP 負載頭 | FU 頭 | 第 2 字節,用S (開始)、E (結束)、Type (原 NALU 類型)回答三個問題:- 這是該 NALU 的第幾個分片?( S=1 →開頭,E=1 →結尾)- 原 NALU 是什么類型?(如 Type=5 →IDR 幀) | 承載 NALU 的 “身份信息” 和 “位置信息”。 |
2. 分片標記的工作流程
以一個 200KB 的 IDR 幀(原 NALU Type=5,NRI=11,F=0)為例:
-
拆分時:
- 將 NALU 拆分為
N
個 RTP 包,每個包的負載結構為:[FU指示符] + [FU頭] + [分片數據]
; - FU 指示符:前 3 位是
0 11
(F=0,NRI=11),后 5 位是11100
(Type=28,標識 FU-A); - FU 頭:
- 第一個分片:
S=1, E=0, Type=5
(告訴接收端:“我是這個 IDR 幀的開頭,原類型是 5”); - 中間分片:
S=0, E=0, Type=5
(“我是中間部分”); - 最后一個分片:
S=0, E=1, Type=5
(“我是結尾,拼完我就完整了”)。
- 第一個分片:
- 將 NALU 拆分為
-
重組時:
- 接收端先檢查 RTP 負載的第一個字節(FU 指示符):若 Type=28,判定為分片包;
- 提取 FU 頭的
S
和E
位,按序列號順序收集分片:- 當
S=1
時,創建新的 NALU 緩存,記錄原 NALU 的F
(0)和NRI
(11); - 持續拼接分片數據,直到遇到
E=1
的包; - 最后,用緩存的
F+NRI
(0 11) + FU 頭的Type
(5),還原出完整的 NALU 頭(0x65
,即二進制0 11 0101
),再拼接負載,得到原始 NALU。
- 當
3. 為什么不用 RTP 的M
位標記 NALU 結束?
- 場景沖突:
M
位是幀級標記(如 H.264 的一幀可能包含多個 NALU,比如 I 幀由 SPS、PPS、IDR Slice 等多個 NALU 組成)。若用M
標記 NALU 結束,會導致一幀內的多個 NALU 被錯誤分割。 - 粒度不足:NALU 是 H.264 的基本單元,
M
位的語義由 payload type 定義(不同編碼可能不同),而 FU 頭的S/E
是專為 NALU 分片設計的精準標記,邏輯更內聚。
通過 FU 指示符和 FU 頭的分工,RTP 完美解決了 “大 NALU 拆分后如何傳遞邊界和類型信息” 的問題。這種設計讓分片和重組過程既高效又精準,確保即使網絡分片,接收端也能還原出完整的 NALU 供解碼器處理。
2.2.2?AAC裸碼流封包解包
(一)AAC碼流存儲格式:ADTS 幀
AAC 音頻流的核心單元是ADTS(Audio Data Transport Stream)幀,它包含音頻數據和元信息。每個 ADTS 幀由兩部分組成:
- ADTS 頭(7 字節):
- 同步字(12 位):固定為
0xFFF
,用于快速定位幀起始位置,類似快遞單號的唯一標識; - MPEG 版本(2 位):
0
表示 MPEG-4,1
表示 MPEG-2; - 保護位(1 位):
0
表示無 CRC 校驗,1
表示有校驗(實際中很少使用); - Profile(2 位):標識 AAC 類型(如
01
=LC,11
=HE-AAC); - 采樣率索引(4 位):對應實際采樣率(如
0x06
=24kHz); - 聲道配置(4 位):
0x02
= 立體聲,0x03
=5.1 聲道; - 幀長度(13 位):整個 ADTS 幀的字節數(包括頭和負載),類似包裹總重量;
- 緩沖器狀態(11 位):通常設為
0x7FF
表示碼率可變。
- 同步字(12 位):固定為
- ADTS 負載:實際的音頻數據(如 PCM 采樣的壓縮結果)。
?關于ADTS詳細可以參考:
深入探索 AAC 編碼原理與 ADTS 格式:音頻世界的智慧結晶_aac編碼原理-CSDN博客
關鍵問題:
- ADTS 頭的冗余性:每個幀都包含相同的配置信息(如采樣率),導致帶寬浪費;
- 實時性要求:音頻幀需快速傳輸,避免播放延遲。
(二)RTP 封裝策略
RTP 封裝 AAC 的核心是將 ADTS 幀適配到網絡傳輸單元,主要有兩種模式:
1. 單一 AU 模式(Single AU Packet)
- 適用場景:ADTS 幀較小(如 48kHz 立體聲每幀約 1024 字節),且網絡 MTU 足夠大(如 1500 字節)。
- 封包結構:
?RTP頭(12字節) + AU頭(2字節) + ADTS負載
- AU 頭:
- 高 13 位表示 ADTS 負載長度(不包括頭,單位bit);
- 低 3 位保留(通常為 0)。
- 示例:一個 1024 字節的 ADTS 負載封裝為 RTP 包,RTP 頭的
PT為
AAC 負載類型,Marker=1
標識幀開始。
- AU 頭:
- 優勢:簡單高效,接收端無需重組;
- 局限:若 ADTS 幀超過 MTU 需分片(但實際中 AAC 幀通常較小)。
2. 組合 AU 模式(Aggregation Packet)
將多個 ADTS 幀合并到一個 RTP 包中,減少包頭開銷:
- 適用場景:連續的小 ADTS 幀(如語音聊天中的短幀)。
- 封包結構:
?RTP頭 + AU頭長度(2字節) + AU頭(2字節)× N + padding bits + ADTS負載 × N
- AU 頭長度:頭兩個字節表示au-header的?度,單位是bit。 ?個AU-header?度是兩個字節(16bit)因為可以有多個au-header所以AU-headers-length的值是 16的倍數,?般?頻都是單個?頻數據流的發送,所以AU-headers-length的值是16;
- AU 頭:每個 ADTS 幀對應一個 AU 頭,指示負載長度。
- 示例:4 個 256 字節的 ADTS 幀合并成一個 RTP 包,AU 頭長度為
0x0010
(16 字節),每個 AU 頭指示 256 字節負載。
(三)封包解包流程
-
發送端處理流程:
- 步驟 1:解析 ADTS 頭,提取采樣率、聲道數等參數;
- 步驟 2:
- 若 ADTS 幀 ≤ 1400 字節 → 單一 AU 模式;
- 若多個連續 ADTS 幀總大小 ≤ 1400 字節 → 組合 AU 模式;
- 步驟 3:填充 RTP 頭字段:
- 序列號:每包遞增 1,用于檢測丟包;
- 時間戳:基于采樣率計算(如 44.1kHz 時,每幀 1024 采樣點的時間戳增量為
(1024 × 90000) / 44100 ≈ 2097
); - SSRC:唯一標識音頻流(如麥克風設備 ID)。
-
冗余控制:
- ADTS 頭冗余優化:通過 SDP 傳遞配置信息(如采樣率、聲道數),RTP 包中僅保留必要字段;
- 負載類型選擇:
PT=97
對應mpeg4-generic
,PT=101
對應AMR-WB
,需在 SDP 中聲明。
(四)解包還原:從 RTP 包到 ADTS 幀的逆向工程
接收端的核心任務是將碎片化的 RTP 包還原為可解碼的 ADTS 幀,流程如下:
1.?RTP 頭解析
- 序列號檢查:
- 維護接收窗口(如最近 1024 個包),檢測連續序列號缺失(丟包);
- 若丟包率超過閾值(如 3%),觸發 FEC(前向糾錯)或 RTX 重傳。
- 時間戳同步:
- 基于時間戳計算播放延遲(如當前時間戳與參考時間戳的差值);
- 若延遲超過緩沖區容量(如 50ms),丟棄舊包以避免卡頓。
2. 組合包拆分與錯誤處理
- AU 頭解析:
- 讀取 RTP 負載的前 2 字節,獲取 AU 頭長度;
- 根據 AU 頭長度遍歷每個 AU 頭,提取 ADTS 負載長度;
- 按順序拼接 ADTS 負載,恢復完整的 ADTS 幀。
- 錯誤處理:
- 若 AU 頭長度無效(如非 16 的倍數),丟棄整個 RTP 包;
- 若 ADTS 負載長度與實際數據不符,觸發錯誤隱藏(如靜音或重復前一幀)。
3. ADTS 頭重建
- 配置信息復用:
- 若 SDP 已傳遞采樣率、聲道數等參數,重建 ADTS 頭時復用這些信息;
- 僅保留同步字、幀長度等必要字段,減少冗余。
總結一下:
RTP 封裝 AAC 的本質是將音頻數據適配到網絡傳輸的最小單元,通過兩種模式的靈活組合解決了以下問題:
- 高效傳輸:組合包模式減少包頭冗余,提升帶寬利用率;
- 實時性保障:時間戳和序列號共同構建了音頻幀的同步和順序控制機制;
- 兼容性擴展:SDP 協商和負載類型聲明確保跨設備互通。
通過這種設計,AAC 音頻流得以在 UDP 上實現低延遲、高容錯的實時傳輸,支撐了語音通話、在線音樂等核心場景。
三、RTCP協議
?RTCP(Real-time Transport Control Protocol,實時傳輸控制協議)是 RTP 的 “孿生兄弟”——RTP 負責 “送貨”(傳輸媒體數據),RTCP 則負責 “監控物流”(反饋質量、同步時鐘、管理會話)。RTCP與RTP聯合?作,RTP實施實際數據的傳輸,RTCP則負責將控制包送?參與中的每個?。其主要功能是就RTP正在提供的服務質量做出反饋。
要注意的是,RTCP 不直接描述單個 RTP 包,它描述的是整個發送方或接收方的狀態以及一段時間內的統計信息。關聯性通過?SSRC
?和?時間窗口?來實現。
字段名 | 長度(bit) | 通俗解釋 |
---|---|---|
Version(V) | 2 | RTP 協議的版本號,目前通用版本是?2(雙方必須用同一版本才能正常通信)。 |
Padding(P) | 1 | 若?P=1 ,報文末尾會額外塞幾個字節,用來適配加密算法或底層傳輸的固定長度要求。 |
Item count(IC) | 5 | 記錄分組里有多少個小條目(比如誰在說話、網絡質量報告),最多存?31 個;如果用不到條目,IC 可以設 0 或被 “借去干別的”。 |
Packet type(PT) | 8 | 標記這是啥類型的 RTCP 分組,比如: -? 200 = 發送方匯報數據(SR)-? 201 = 接收方反饋質量(RR)- 還有身份信息(SDES)、退出通知(BYE)、自定義消息(APP)。 |
Length(M) | 16 | 分組總長度,每 1 個單位等于 4 字節(比如?Length=1 ?→ 代表 4 字節);這個長度不含前面固定的 4 字節頭部。(也就是說length為0也是合理的,說明只有4字節的頭部(這種情況IC也是0))。 |
(一)RTCP 的核心功能
RTCP 的設計目標是為 RTP 傳輸提供 “雙向溝通機制”,核心功能可概括為四類:
- 質量反饋:接收端通過 RTCP 向發送端報告丟包率、延遲抖動等數據,發送端據此調整碼率或重傳策略(比如視頻會議中卡頓后自動降低清晰度)。
- 時鐘同步:通過 NTP(網絡時間協議)時間戳將不同媒體流(如音頻、視頻)對齊到同一時間軸,解決 “唇音不同步” 問題。
- 會話管理:標識參與者身份(如用戶名、設備 ID),并處理加入 / 離開會話的通知(比如直播中觀眾退出時發送信號)。
- 擴展能力:支持自定義消息(如傳輸額外的元數據),為特殊場景(如 VR 直播的姿態數據)預留擴展空間。
傳輸特性:RTCP 與 RTP 共用 UDP 端口對,RTCP 端口固定為 “RTP 端口 + 1”(如 RTP 用 5004,則 RTCP 用 5005)。
(二) RTCP 報文類型
RTCP 通過 5 種報文類型實現上述功能,每種報文都有統一的頭部格式和專屬的 payload 結構:
報文類型 | 縮寫 | PT 值 | 核心作用 | 發送方 |
---|---|---|---|---|
發送方報告 | SR | 200 | 發送端匯報發送統計(如總發包數、時鐘信息) | 媒體發送者(如攝像頭、麥克風) |
接收方報告 | RR | 201 | 接收端反饋接收質量(如丟包率、抖動) | 媒體接收者(如播放器、瀏覽器) |
源描述報告 | SDES | 202 | 傳遞參與者信息(如用戶名、郵箱) | 所有會話參與者 |
離開通知 | BYE | 203 | 告知其他參與者自己退出會話 | 即將離開的參與者 |
應用自定義 | APP | 204 | 傳輸自定義數據(如私有協議擴展) | 按需由應用發送 |
1. 發送方報告(SR)
SR 由媒體發送端(如攝像頭)定期發送,包含自身的發送統計和時鐘信息,是同步音視頻的關鍵。
結構解析(共 28 字節起):
- 固定頭部:版本(V=2)、填充位(P)、報告數(RC,最多 31 個);
- 核心字段:
- NTP 時間戳(64 位?符號整數):當前(報告發出)的絕對時間(如
2024-05-20 12:00:00.123
),用于跨設備同步(該時間戳的?32 bites以NTP格式表示,從1900年1?1?開始計數,以秒為單位。低32 bites表示秒后?的?數。如果需要轉化Unix時間到NTP時間,在Unix時間加上2,208,988,800即可。); - RTP 時間戳(32 位):與 RTP 包中時間戳同源(如視頻 90kHz 時鐘下的計數);
- 時間戳 (
NTP Timestamp
,?RTP Timestamp
) 在 SR 中協同工作,提供媒體時鐘與掛鐘時間的映射關系。 - 發送統計:表示這個同步源從這個會話開始到現在總發包數、總字節數(用于計算碼率)。
- NTP 時間戳(64 位?符號整數):當前(報告發出)的絕對時間(如
實例:某攝像頭的 SR 顯示 “NTP 時間 = 1629408000.123,RTP 時間 = 12345678,總發包數 = 1000”,接收端可據此計算 “1 個 RTP 時間單位≈多少毫秒”,實現時鐘對齊。
2. 接收方報告(RR)
RR 由媒體接收端(如播放器)發送,反饋 RTP 包的接收質量,幫助發送端調整策略。
結構解析(共 24 字節起):
- 固定頭部:與 SR 相同,RC 表示反饋的發送源數量;
- 報告塊(每個 32 字節):
- 丟包率(8 位):0~255 表示 0~100%(如 64=25% 丟包);
- 累計丟包數(24 位):從會話開始至今丟失的總包數;
- 抖動(32 位):網絡延遲波動的統計值(值越大,畫面越可能卡頓);
- 最后接收的 SR 時間(LSR):用于計算往返延遲。
實例:播放器發送 RR,丟包率 = 128(50%),抖動 = 100ms,發送端收到后可能降低碼率或啟用 FEC(前向糾錯)。
3. 源描述報告(SDES)
SDES 用于傳遞會話參與者的元信息,確保多方通信時能識別彼此。
必選字段:
- CNAME(規范名):唯一且永久的標識(如
user123@domain.com
),即使設備重啟(SSRC 變化)也能關聯到同一用戶; - 可選字段:NAME(昵稱)、EMAIL(郵箱)、PHONE(電話)等。
實例:視頻會議中,SDES 報文攜帶 “CNAME=alice@company.com,NAME=Alice”,其他參與者能在界面顯示 “Alice 正在發言”。
4. 離開通知(BYE)
當設備退出會話(如關閉播放器、斷網),BYE 報文會通知其他參與者 “我已離開”,避免資源浪費。
結構:包含退出的 SSRC 列表,可選 “離開原因”(如 “用戶主動退出”)。
注意:BYE 可能丟失(如網絡中斷),接收端需通過 “超時未收到 RTP/RTCP” 判斷對方離線。
5. 應用自定義(APP)
APP 允許應用自定義消息格式,用于標準 RTCP 未覆蓋的場景(如 VR 直播中的設備姿態同步)。
結構:4 字節 ASCII 標識(如 “VRTP”)+ 自定義數據,接收端不認識的 APP 報文會被忽略。
四、總結一下RTP和RTCP如何協同
(一)RTCP 如何“描述” RTP 數據?
-
SSRC
?(Synchronization Source Identifier) 是核心紐帶:-
每個 RTP 流(通常來自一個源,如攝像頭或麥克風)在 RTP 會話中被分配一個唯一的 32 位?
SSRC
?標識符。 -
這個?
SSRC
?值出現在每個屬于該流的 RTP 包的頭部。 -
關鍵的關聯點:?RTCP 數據包(特別是 Sender Report - SR 和 Receiver Report - RR)也包含這個?
SSRC
?標識符。 -
因此,接收端收到一個 RTCP SR 包時,它看到包里的?
SSRC = X
,就知道這個報告描述的是所有?SSRC = X
?的 RTP 包的發送方狀態(在 SR 中)或者接收方對該流的接收狀態(在 RR 中)。
-
-
時間窗口:
-
RTCP 報告(SR/RR)不是為單個 RTP 包生成的。它們周期性地發送(通常每 5 秒左右,或至少占會話帶寬的 5%)。
-
SR 報告包含發送方在上一個報告間隔期間發送的所有 RTP 包的累積統計信息(發送的包總數、發送的字節總數)。
-
RR 報告包含接收方在上一個報告間隔期間接收到的來自特定?
SSRC
(在 RR 塊中指定)的所有 RTP 包的累積統計信息(如丟包數、累計丟包數、最高接收序列號、抖動等)。
-
-
序列號 (
sequence number
) 的作用:-
每個 RTP 包都有一個單調遞增的 16 位序列號。
-
RTCP RR 報告中包含?
extended highest sequence number received
(接收到的最高序列號的擴展形式)和?cumulative number of packets lost
(累計丟包數)。 -
接收端通過比較預期應接收到的序列號范圍(基于之前的最高序列號和包間隔)和實際接收到的序列號,可以計算出在報告間隔內的丟包情況。雖然報告是累積的,但結合序列號信息,接收端能知道在哪個大致的序列號范圍內發生了丟包。
-
-
總結關聯性:?RTCP 通過共享?
SSRC
?將報告與特定的 RTP 流關聯起來。報告提供的是該流在前一個時間窗口內的整體發送或接收性能的統計摘要,而不是針對單個 RTP 包。接收端利用序列號信息可以推斷出大致的丟包位置。
(二)?RTCP 和 RTP 中的事件戳如何協同控制音視頻同步?
建立媒體時間與真實時間的映射關系
音視頻同步的本質是:讓屬于同一時刻采集的音頻樣本和視頻幀,在播放端也于同一時刻播放出來。問題在于:
-
音頻和視頻是獨立的 RTP 流:它們有各自獨立的?
SSRC
、獨立的 RTP 序列號、獨立的 RTP 時間戳序列(基于各自的采樣率)。 -
RTP 時間戳是相對的:音頻時間戳基于音頻采樣率(如 48000 Hz,每樣本時間戳增量為 1),視頻時間戳基于視頻時鐘頻率(如 90000 Hz,每幀時間戳增量取決于幀率)。兩者單位不同,無法直接比較。
-
設備時鐘不同步:發送端和接收端的系統時鐘(掛鐘時間)可能不同步,且各自存在漂移。
RTCP SR 包 (NTP Timestamp
?+?RTP Timestamp
) 解決了這個問題!?它為每個獨立的媒體流提供了一個將自身媒體時間戳 (RTP Timestamp
) 映射到絕對真實世界時間 (NTP Timestamp
) 的基準點。
協同控制音視頻同步的步驟:
假設有一個視頻會議場景,包含一個音頻流 (SSRC_A
) 和一個視頻流 (SSRC_V
)。
-
發送端捕獲與標記
-
當發送端決定為音頻流?
SSRC_A
?發送一個 SR 包時:-
原子性操作:?它瞬間同時完成以下動作:
-
捕獲當前 NTP 時間 (
NTP_TS_A
):?獲取精確的掛鐘時間(理想情況下與 NTP 服務器同步)。 -
捕獲當前音頻 RTP 時間戳 (
RTP_TS_A
):?讀取此刻音頻采樣時鐘計數器的值。這個值代表了捕獲設備在?NTP_TS_A
?這個絕對時間點正在處理的音頻樣本的時間戳。
-
-
-
同樣,當為視頻流?
SSRC_V
?發送 SR 包時:-
原子性操作:?瞬間同時捕獲:
-
捕獲當前 NTP 時間 (
NTP_TS_V
)。?(注意:NTP_TS_A
?和?NTP_TS_V
?可能不同,因為 SR 發送時間不同) -
捕獲當前視頻 RTP 時間戳 (
RTP_TS_V
)。
-
-
-
-
發送端打包 SR:
-
對于音頻 SR (
SSRC_A
): 將?NTP_TS_A
?和?RTP_TS_A
?打包進 SR 包發送。 -
對于視頻 SR (
SSRC_V
): 將?NTP_TS_V
?和?RTP_TS_V
?打包進 SR 包發送。
-
-
接收端接收與計算映射關系?
-
接收端收到音頻流的 SR (
SSRC_A
):-
記錄?
NTP_TS_A
?(發送端在發送此 SR 時的絕對時間)。 -
記錄?
RTP_TS_A
?(在?NTP_TS_A
?時刻,音頻流的媒體時間戳)。 -
建立音頻流映射:?
RTP_TS_A
?(音頻時間) <==>?NTP_TS_A
?(絕對時間)
-
-
接收端收到視頻流的 SR (
SSRC_V
):-
記錄?
NTP_TS_V
。 -
記錄?
RTP_TS_V
。 -
建立視頻流映射:?
RTP_TS_V
?(視頻時間) <==>?NTP_TS_V
?(絕對時間)
-
-
關鍵點:?接收端現在知道如何把音頻時間戳轉換成絕對時間,也知道如何把視頻時間戳轉換成絕對時間。絕對時間 (
NTP Timestamp
) 成為了一個公共的、統一的時間軸!
-
-
接收端同步播放:
-
假設接收端要播放一個音頻包:
-
該音頻包有自己的 RTP 時間戳?
audio_ts
。 -
接收端利用音頻流的映射關系?(
RTP_TS_A
?<==>?NTP_TS_A
),計算出?audio_ts
?對應的絕對時間?target_ntp_audio
。計算原理:-
計算音頻時間差:
delta_audio_ts = audio_ts - RTP_TS_A
-
計算對應的絕對時間差 (基于音頻采樣率):
delta_ntp = delta_audio_ts / audio_sample_rate
?(例如?audio_sample_rate = 48000
) -
目標絕對時間:
target_ntp_audio = NTP_TS_A + delta_ntp
-
-
-
假設接收端要播放一個視頻幀:
-
該視頻幀有自己的 RTP 時間戳?
video_ts
。 -
接收端利用視頻流的映射關系?(
RTP_TS_V
?<==>?NTP_TS_V
),計算出?video_ts
?對應的絕對時間?target_ntp_video
。計算原理:-
計算視頻時間差:
delta_video_ts = video_ts - RTP_TS_V
-
計算對應的絕對時間差 (基于視頻時鐘頻率):
delta_ntp = delta_video_ts / video_clock_rate
?(例如?video_clock_rate = 90000
) -
目標絕對時間:
target_ntp_video = NTP_TS_V + delta_ntp
-
-
-
同步決策:
-
播放器有一個統一的播放時間軸,基于接收端本地估算的 NTP 時間?(接收端本地時鐘最好也同步到 NTP)。
-
播放器計算當前本地估算的 NTP 時間?
current_ntp_local
。 -
對于即將播放的音頻樣本和視頻幀:
-
它計算音頻樣本的目標絕對時間?
target_ntp_audio
。 -
它計算視頻幀的目標絕對時間?
target_ntp_video
。 -
播放準則:?當?
current_ntp_local
?達到或略晚于?target_ntp_audio
?時,播放該音頻樣本;當?current_ntp_local
?達到或略晚于?target_ntp_video
?時,播放該視頻幀。
-
-
效果:?因為?
target_ntp_audio
?和?target_ntp_video
?都是根據發送端同一個物理時刻(分別由各自的 SR 捕獲)映射出來的絕對時間,所以原本在發送端同一物理時刻采集的音頻和視頻,它們的?target_ntp
?值會非常接近(理想情況下相等)。播放器在相同的?current_ntp_local
?時間播放它們,就實現了音畫同步!
-
-
想象兩個跑步者(音頻流和視頻流)在不同的跑道上(不同的時間戳序列)。裁判(發送端)在特定時刻(NTP_TS_A/V
)分別記錄下他們各自跑了多遠(RTP_TS_A/V
)。在終點(接收端),另一個裁判根據這些記錄,可以推算出兩個跑步者在裁判記錄的那個共同時刻各自的位置。這樣,終點裁判就能知道,當第一個跑步者到達某個位置時(某個音頻時間戳),第二個跑步者應該在哪里(對應的視頻時間戳),從而判斷他們是否“齊頭并進”(音畫同步)。
五、RTSP協議
(一)RTSP 是什么:不止于 “傳輸” 的控制協議
RTSP 是一種基于文本的應用層協議,語法類似 HTTP,但專為實時媒體控制設計。它的核心作用是:
- 協調會話:讓客戶端(如播放器)和服務器(如直播服務器)達成共識(如媒體格式、傳輸方式);
- 控制流傳輸:通過 “播放”“暫停”“錄制” 等指令管理 RTP 流(音視頻數據由 RTP 實際傳輸);
- 維護狀態:全程跟蹤會話進度(如當前播放位置、傳輸端口),類似打電話時保持通話狀態。
一句話總結:RTSP 是 “指揮官”,RTP 是 “運輸兵”,前者發號施令,后者運送數據。
(二)RTSP 與 HTTP:看似相似,實則不同
RTSP 常被比作 “HTTP 的親戚”,但兩者在核心機制上有本質區別:
對比維度 | RTSP | HTTP |
---|---|---|
核心功能 | 控制媒體流(播放、錄制等) | 傳輸靜態資源(網頁、文件等) |
狀態管理 | 有狀態(保持會話 Session) | 無狀態(每次請求獨立) |
請求方向 | 客戶端和服務器可雙向發送請求 | 僅客戶端發送請求,服務器被動響應 |
數據傳輸 | 媒體數據通過 RTP “帶外” 傳輸(獨立通道) | 數據通過 HTTP 報文 “帶內” 傳輸 |
特有方法 | 支持 PLAY、RECORD、SETUP 等指令 | 主要用 GET、POST、PUT 等 |
舉例:用 RTSP 看直播時,你可以隨時發送 “暫停” 指令,服務器會記住當前播放位置;而用 HTTP 下載視頻,暫停后需重新請求,服務器不會保留你的進度。
(三)推流流程:如何把視頻 “上傳” 到服務器?
推流(如主播直播)是將本地音視頻通過 RTSP 發送到服務器的過程,核心步驟分六步:
1. 第一步:OPTIONS——“問問服務器支持啥功能”
- 客戶端→服務器:發送
OPTIONS
請求,詢問服務器支持哪些操作(如能否錄制、能否暫停)。
- 服務器→客戶端:回復
Public
字段,列出支持的方法(如OPTIONS, DESCRIBE, RECORD
等)。
- 作用:避免客戶端發送服務器不支持的指令,浪費資源。
2. 第二步:ANNOUNCE——“告訴服務器我要發啥”
- 客戶端→服務器:發送
ANNOUNCE
請求,攜帶 SDP(會話描述協議)信息,說明要推的媒體格式(如視頻用 H.264、音頻用 AAC)、采樣率等。
- 服務器→客戶端:回復確認,并返回
Session ID
(會話標識,后續操作需攜帶)。
- 作用:讓服務器提前準備好接收特定格式的媒體流。
3. 第三步:SETUP——“約定傳輸通道”
- 客戶端→服務器:發送
SETUP
請求,指定傳輸方式(如 UDP)和客戶端端口(如 RTP 用 31590,RTCP 用 31591)。
- 服務器→客戶端:回復確認,告知服務器端口(如 RTP 用 59472),并綁定
Session ID
。
- 細節:如果推流包含視頻和音頻,需分別
SETUP
(各自用獨立端口)。 - 作用:打通客戶端和服務器的 “數據高速公路”,確保 RTP 流能準確傳輸。
4. 第四步:RECORD——“推流開始”
- 客戶端→服務器:發送
RECORD
請求,指令服務器開始接收 RTP 流。
- 服務器→客戶端:回復確認,開始等待 RTP 數據。
- 作用:正式啟動推流,此時客戶端會通過 RTP 端口發送音視頻數據。
5. 第五步:RTP 傳輸 ——“數據真正開始流動”
- 客戶端通過
SETUP
約定的 UDP 端口,持續發送 RTP 包(視頻用一個端口,音頻用另一個)。


?
- 同時定時發送 RTCP 包反饋傳輸質量(如丟包率),服務器據此調整策略。

6. 第六步:TEARDOWN——“結束會話”
- 客戶端→服務器:發送
TEARDOWN
請求,告知 “推流結束”。
- 服務器→客戶端:回復確認,釋放端口和會話資源。
- 作用:優雅關閉連接,避免資源浪費。
總結:
(四)拉流流程:如何從服務器 “拉取” 視頻?
拉流(如觀眾看直播)是客戶端從服務器獲取媒體流的過程,步驟與推流類似,但部分關鍵指令不同:
步驟 | 拉流操作 | 與推流的核心區別 |
---|---|---|
1. OPTIONS | 同推流(查詢服務器支持的方法) | 無 |
2. DESCRIBE | 客戶端請求服務器發送 SDP(媒體描述) | 推流用 ANNOUNCE(客戶端主動告知),拉流用 DESCRIBE(客戶端主動查詢) |
3. SETUP | 同推流(約定傳輸端口) | 無 |
4. PLAY | 客戶端指令服務器開始發送 RTP 流 | 推流用 RECORD(客戶端發數據),拉流用 PLAY(服務器發數據) |
5. RTP 傳輸 | 服務器通過 RTP 發送音視頻數據到客戶端 | 數據方向相反(服務器→客戶端) |
6. TEARDOWN | 同推流(關閉會話) | 無 |
舉例:拉流時,DESCRIBE
就像觀眾問 “你這有什么節目?”,服務器用 SDP 回復 “有 H.264 視頻和 AAC 音頻”;PLAY
則像說 “開始播放吧”,服務器隨后通過 RTP 發送數據。




(五)總結
1. Session ID:
- 由服務器在
ANNOUNCE
或SETUP
時生成(如ditmIrW4Z20X
),后續所有操作必須攜帶。 - 作用:服務器通過它識別 “哪個客戶端在操作哪個流”,避免混淆。
2. Transport 字段:
格式示例:Transport: RTP/AVP/UDP;unicast;client_port=31590-31591;server_port=59472-59473
RTP/AVP
:用 RTP 傳輸,采用 AVP(音頻視頻配置文件);unicast
:單播(一對一傳輸);client_port/server_port
:客戶端和服務器的 RTP/RTCP 端口對(RTP 用前一個,RTCP 用后一個)。- 作用:明確數據走哪條 “路”,用什么 “規則” 傳輸。
3. CSeq:
- 每個 RTSP 請求 / 響應都有一個遞增的序列號(如
CSeq: 1
、CSeq: 2
)。 - 作用:匹配請求和響應(避免混亂),比如客戶端發
CSeq:3
的請求,服務器必須用CSeq:3
回復。
4. SDP協議作用(key-value):
- 包含媒體類型(視頻 / 音頻)、編碼格式(H.264/AAC)、采樣率等關鍵信息。
- 推流時由客戶端通過
ANNOUNCE
發送,拉流時由服務器通過DESCRIBE
返回。 - 作用:讓雙方對 “要傳輸的媒體是什么樣的” 達成共識。