RTSP 與 RTMP 協議
來源:https://www.jianshu.com/p/c2284659452f
RTSP(Real Time Streaming Protocol)
RTSP協議,這應該是實時性最好的了,如果要想實時性要求很高,比如0.5s以內,這個是不錯的選擇。前陣子模仿spydroid寫了個建議的rtsp服務器,其實就是options,describe,setup,play,pause,teardown這幾步了,這個協議用的最廣泛,網上介紹也比較多。要想真正深入了解rtsp協議,c++語言功底好的可以查看live555 。Real Time Streaming Protocol或者RTSP(實時流媒體協議),是由Real network 和 Netscape共同提出的如何有效地在IP網絡上傳輸流媒體數據的應用層協議。RTSP提供一 種可擴展的框架,使能夠提供可控制的,按需傳輸實時數據,比如音頻和視頻文件。源數據可以包括現場數據的反饋和存貯的文件。rtsp對流媒體提供了諸如暫停,快進等控制,而它本身並不傳輸數據,rtsp作用相當於流媒體服務器的遠程控制。傳輸數據可以通過傳輸層的tcp,udp協議,rtsp也提供了基於rtp傳輸機制的一些有效的方法。
RTSP消息格式
RTSP的消息有兩大類,一是請求消息(request),一是回應消息(response),兩種消息的格式不同.
請求消息:
方法 URI RTSP版本 CR LF
消息頭 CR LF CR LF
消息體 CR LF
其中方法包括OPTION回應中所有的命令,URI是接受方的地址,例如
rtsp://192.168.20.136
RTSP版本一般都是 RTSP/1.0.每行后面的CR LF表示回車換行,需要接受端有相應的解析,最后一個消息頭需要有兩個CR LF
回應消息:
RTSP版本 狀態碼 解釋 CR LF
消息頭 CR LF CR LF
消息體 CR LF
其中RTSP版本一般都是RTSP/1.0,狀態碼是一個數值,200表示成功,解釋是與狀態碼對應 的文本解釋。
簡單的rtsp交互過程
C表示rtsp客戶端,S表示rtsp服務端
1.C->S:OPTION request //詢問S有哪些方法可用
1.S->C:OPTION response //S回應信息中包括提供的所有可用方法
2.C->S:DESCRIBE request //要求得到S提供的媒體初始化描述信息
2.S->C:DESCRIBE response //S回應媒體初始化描述信息,主要是sdp
3.C->S:SETUP request //設置會話的屬性,以及傳輸模式,提醒S建立會話
3.S->C:SETUP response //S建立會話,返回會話標識符,以及會話相關信息
4.C->S:PLAY request //C請求播放
4.S->C:PLAY response //S回應該請求的信息
5.S->C:發送流媒體數據
6.C->S:TEARDOWN request //C請求關閉會話
6.S->C:TEARDOWN response //S回應該請求
上述的過程是標准的、友好的rtsp流程,但實際的需求中並不一定按部就班來。
其中第3和4步是必需的!
第一步,只要服務器客戶端約定好,有哪些方法可用,則option請求可以不要。第二步,如果我們有其他途徑得到媒體初始化描述信息(比如http請求等等),則我們也不需要通過rtsp中的describe請求來完成。第五步,可以根據系統需求的設計來決定是否需要。
RTP不象http和ftp可完整的下載整個影視文件,它是以固定的數據率在網絡上發送數據,客戶端也是按照這種速度觀看影視文件,當影視畫面播放過后,就不可以再重復播放,除非重新向服務器端要求數據。
RTSP與RTP最大的區別在於:RTSP是一種雙向實時數據傳輸協議,它允許客戶端向服務器端發送請求,如回放、快進、倒退等操作。當然,RTSP可基於RTP來傳送數據,還可以選擇TCP、UDP、組播UDP等通道來發送數據,具有很好的擴展性。它時一種類似與http協議的網絡應用層協議。
RTSP處於應用層,而RTP/RTCP處於傳輸層。RTSP負責建立以及控制會話,RTP負責多媒體數據的傳輸。而RTCP是一個實時傳輸控制協議,配合RTP做控制和流量監控。封裝發送端及接收端(主要)的統計報表。這些信息包括丟包率,接收抖動等信息。發送端根據接收端的反饋信息做響應的處理。RTP與RTCP相結合雖然保證了實時數據的傳輸,但也有自己的缺點。最顯著的是當有許多用戶一起加入會話進程的時候,由於每個參與者都周期發送RTCP信息包,導致RTCP包泛濫(flooding)。
RTMP——Real Time Messaging Protocol(實時消息傳輸協議)
RTMP是由Adobe公司提出的,在互聯網TCP/IP五層體系結構中應用層,RTMP協議是基於TCP協議的,也就是說RTMP實際上是使用TCP作為傳輸協議。TCP協議在處在傳輸層,是面向連接的協議,能夠為數據的傳輸提供可靠保障,因此數據在網絡上傳輸不會出現丟包的情況。不過這種可靠的保障也會造成一些問題,也就是說前面的數據包沒有交付到目的地,后面的數據也無法進行傳輸。幸運的是,目前的網絡帶寬基本上可以滿足RTMP協議傳輸普通質量視頻的要求。
RTMP傳輸的數據的基本單元為Message,但是實際上傳輸的最小單元是Chunk(消息塊),因為RTMP協議為了提升傳輸速度,在傳輸數據的時候,會把Message拆分開來,形成更小的塊,這些塊就是Chunk。
消息(Message)的結構

Message結構分析
1.Message Type:它是一個消息類型的ID,通過該ID接收方可以判斷接收到的數據的類型,從而做相應的處理。Message Type ID在1-7的消息用於協議控制,這些消息一般是RTMP協議自身管理要使用的消息,用戶一般情況下無需操作其中的數據。Message Type ID為8,9的消息分別用於傳輸音頻和視頻數據。Message Type ID為15-20的消息用於發送AMF編碼的命令,負責用戶與服務器之間的交互,比如播放,暫停等。
2.Playload Length: 消息負載的長度,即音視頻相關信息的的數據長度,4個字節
3.TimeStamp:時間戳,3個字節。
4.Stream ID:消息的唯一標識。拆分消息成Chunk時添加該ID,從而在還原時根據該ID識別Chunk屬於哪個消息。
5.Message Body:消息體,承載了音視頻等信息。
消息塊(Chunk)

通過上圖可以看出,消息塊在結構上與與消息類似,有Header和Body。
1.Basic Header:基本的頭部信息,在頭部信息里面包含了chunk stream ID(流通道Id,用來標識指定的通道)和chunk type(chunk的類型)。
2.Message Header:消息的頭部信息,包含了要發送的實際信息(可能是完整的,也可能是一部分)的描述信息。Message Header的格式和長度取決於Basic Header的chunk type。
3.Extended TimeStamp:擴展時間戳。
4.Chunk Data:塊數據。
RTMP在傳輸數據的時候,發送端會把需要傳輸的媒體數據封裝成消息,然后把消息拆分成消息塊,再一個一個進行傳輸。接收端收到消息塊后,根據Message Stream ID重新將消息塊進行組裝、組合成消息,再解除該消息的封裝處理就可以還原出媒體數據。由此可以看出,RTMP收發數據是以Chunk為單位,而不是以Message為單位。需要注意的是,RTMP發送Chunk必須是一個一個發送,后面的Chunk必須等前面的Chunk發送完成。
1.簡要介紹
RTMP協議是應用層協議,是要靠底層可靠的傳輸層協議(通常是TCP)來保證信息傳輸的可靠性的。在基於傳輸層協議的鏈接建立完成后,一個RTMP協議的流媒體推流需要經過以下幾個步驟:握手,建立連接,建立流,推流。RTMP連接都是以握手作為開始的。建立連接階段用於建立客戶端與服務器之間的“網絡連接”;建立流階段用於建立客戶端與服務器之間的“網絡流”;推流階段用於傳輸視音頻數據。
接下來就簡單介紹下這一過程
2.握手
在rtmp連接建立后,服務端與客戶端需要通過3次交換報文完成握手,握手其他的協議不同,是由三個靜態大小的塊,而不是可變大小的塊組成的,客戶端與服務器發送相同的三個chunk,客戶端發送c0,c1,c2,服務端發送s0,s1,s2。
發送規則
握手開始於客戶端發送 C0,C1 塊。
在發送 C2 之前客戶端必須等待接收 S1 。
在發送任何數據之前客戶端必須等待接收 S2。
服務端在發送 S0 和 S1 之前必須等待接收 C0,也可以等待接收 C1。
服務端在發送 S2 之前必須等待接收 C1。
服務端在發送任何數據之前必須等待接收 C2。
數據格式
C0與S0
C0和S0的長度是一個字節,在 S0 中這個字段表示服務器選擇的 RTMP 版本。rtmp1.0規范所定義的版本是 3;0-2 是早期產品所用的,已被丟棄;4-31保留在未來使用;32-255 不允許使用(為了區分其他以某一字符開始的文本協議)。如果服務無法識別客戶端請求的版本,應該返回 3 。客戶端可以選擇減到版本 3 或選擇取消握手。
C1與S1
C1 和 S1 有 1536 字節長,由下列字段組成:
時間:4 字節 本字段包含時間戳。該時間戳應該是發送這個數據塊的端點的后續塊的時間起始點。可以是 0,* 或其他的 任何值。為了同步多個流,端點可能發送其塊流的當前值。
零:4 字節 本字段必須是全零。
隨機數據:1528 字節。 本字段可以包含任何值。 因為每個端點必須用自己初始化的握手和對端初始化的握 手來區分身份,所以這個數據應有充分的隨機性。但是並不需要加密安全的隨機值,或者動態值
C2與S2
C2 和 S2 消息有 1536 字節長。只是 S1 和 C1 的回復。本消息由下列字段組成。
時間:4 字節 本字段必須包含對等段發送的時間(對 C2 來說是 S1,對 S2 來說是 C1)。
時間 2:4 字節 本字段必須包含先前發送的並被對端讀取的包的時間戳。
隨機回復:1528 字節 本字段必須包含對端發送的隨機數據字段(對 C2 來說是 S1,對 S2 來說是 C1) 。 每個對等端可以用時間和時間 2 字段中的時間戳來快速地估計帶寬和延遲。 但這樣做可 能並不實用。
RTMP握手的這個過程就是完成了兩件事:1. 校驗客戶端和服務器端RTMP協議版本號,2. 是發了一堆數據,猜想應該是測試一下網絡狀況,看看有沒有傳錯或者不能傳的情況。
3.建立網絡連接
客戶端發送命令消息中的“連接”(connect)到服務器,請求與一個服務應用實例建立連接。
服務器接收到連接命令消息后,發送確認窗口大小(Window Acknowledgement Size)協議消息到客戶端,同時連接到連接命令中提到的應用程序。
服務器發送設置帶寬()協議消息到客戶端。
客戶端處理設置帶寬協議消息后,發送確認窗口大小(Window Acknowledgement Size)協議消息到服務器端。
服務器發送用戶控制消息中的“流開始”(Stream Begin)消息到客戶端。
服務器發送命令消息中的“結果”(_result),通知客戶端連接的狀態。
注意:
這里面的connect 命令消息,命令里面包含什么東西,協議中沒有說,真實通信中要指定一些編解碼的信息,這些信息是以AMF格式發送的, 其中audioCodecs和videoCodecs這兩個指定音視頻編碼信息的不能少的。
Window Acknowledgement Size 是設置接收端消息窗口大小,一般是2500000字節,即告訴客戶端你在收到我設置的窗口大小的這么多數據之后給我返回一個ACK消息,告訴我你收到了這么多消息。在實際做推流的時候推流端要接收很少的服務器數據,遠遠到達不了窗口大小,所以基本不用考慮這點。而對於服務器返回的ACK消息一般也不做處理,我們默認服務器都已經收到了這么多消息。
服務器返回的_result命令類型消息的payload length一般不會大於128字節,但是在最新的nginx-rtmp中返回的消息長度會大於128字節,所以一定要做好收包,組包的工作。
4.建立網絡流
創建完網絡連接之后就可以創建網絡流了
客戶端發送命令消息中releaseStream命令到服務器端
客戶端發送命令消息中FCPublish命令到服務器端
客戶端發送命令消息中的“創建流”(createStream)命令到服務器端。
服務器端接收到“創建流”命令后,發送命令消息中的“結果”(_result),通知客戶端流的狀態。
解析服務器返回的消息會得到一個stream ID, 這個ID也就是以后和服務器通信的 message stream ID, 一般返回的是1,不固定。
5.推流命令
推流准備工作的最后一步是 Publish Stream,即向服務器發一個publish命令,這個命令的message stream ID 就是上面 create stream 之后服務器返回的stream ID,發完這個命令一般不用等待服務器返回的回應,直接下一步發送音視頻數據。有些rtmp庫 還會發setMetaData消息,這個消息可以發也可以不發,里面包含了一些音視頻編碼的信息。
當以上工作都完成的時候,就可以發送音視頻了。
============== End