RTSP(Real Time Streaming Protocol)
RTSP協(xié)議,這應(yīng)該是實時性最好的了,如果要想實時性要求很高,比如0.5s以內(nèi),這個是不錯的選擇。前陣子模仿spydroid寫了個建議的rtsp服務(wù)器,其實就是options,describe,setup,play,pause,teardown這幾步了,這個協(xié)議用的最廣泛,網(wǎng)上介紹也比較多。要想真正深入了解rtsp協(xié)議,c++語言功底好的可以查看live555 。Real Time Streaming Protocol或者RTSP(實時流媒體協(xié)議),是由Real network 和 Netscape共同提出的如何有效地在IP網(wǎng)絡(luò)上傳輸流媒體數(shù)據(jù)的應(yīng)用層協(xié)議。RTSP提供一 種可擴展的框架,使能夠提供可控制的,按需傳輸實時數(shù)據(jù),比如音頻和視頻文件。源數(shù)據(jù)可以包括現(xiàn)場數(shù)據(jù)的反饋和存貯的文件。rtsp對流媒體提供了諸如暫停,快進等控制,而它本身并不傳輸數(shù)據(jù),rtsp作用相當(dāng)于流媒體服務(wù)器的遠(yuǎn)程控制。傳輸數(shù)據(jù)可以通過傳輸層的tcp,udp協(xié)議,rtsp也提供了基于rtp傳輸機制的一些有效的方法。
RTSP消息格式
RTSP的消息有兩大類,一是請求消息(request),一是回應(yīng)消息(response),兩種消息的格式不同.
請求消息:
方法 URI RTSP版本 CR LF
消息頭 CR LF CR LF
消息體 CR LF
其中方法包括OPTION回應(yīng)中所有的命令,URI是接受方的地址,例如
rtsp://192.168.20.136
RTSP版本一般都是 RTSP/1.0.每行后面的CR LF表示回車換行,需要接受端有相應(yīng)的解析,最后一個消息頭需要有兩個CR LF
回應(yīng)消息:
RTSP版本 狀態(tài)碼 解釋 CR LF
消息頭 CR LF CR LF
消息體 CR LF
其中RTSP版本一般都是RTSP/1.0,狀態(tài)碼是一個數(shù)值,200表示成功,解釋是與狀態(tài)碼對應(yīng) 的文本解釋。
簡單的rtsp交互過程
C表示rtsp客戶端,S表示rtsp服務(wù)端
1.C->S:OPTION request //詢問S有哪些方法可用
1.S->C:OPTION response //S回應(yīng)信息中包括提供的所有可用方法
2.C->S:DESCRIBE request //要求得到S提供的媒體初始化描述信息
2.S->C:DESCRIBE response //S回應(yīng)媒體初始化描述信息,主要是sdp
3.C->S:SETUP request //設(shè)置會話的屬性,以及傳輸模式,提醒S建立會話
3.S->C:SETUP response //S建立會話,返回會話標(biāo)識符,以及會話相關(guān)信息
4.C->S:PLAY request //C請求播放
4.S->C:PLAY response //S回應(yīng)該請求的信息
5.S->C:發(fā)送流媒體數(shù)據(jù)
6.C->S:TEARDOWN request //C請求關(guān)閉會話
6.S->C:TEARDOWN response //S回應(yīng)該請求
上述的過程是標(biāo)準(zhǔn)的、友好的rtsp流程,但實際的需求中并不一定按部就班來。
其中第3和4步是必需的!
第一步,只要服務(wù)器客戶端約定好,有哪些方法可用,則option請求可以不要。第二步,如果我們有其他途徑得到媒體初始化描述信息(比如http請求等等),則我們也不需要通過rtsp中的describe請求來完成。第五步,可以根據(jù)系統(tǒng)需求的設(shè)計來決定是否需要。
RTP不象http和ftp可完整的下載整個影視文件,它是以固定的數(shù)據(jù)率在網(wǎng)絡(luò)上發(fā)送數(shù)據(jù),客戶端也是按照這種速度觀看影視文件,當(dāng)影視畫面播放過后,就不可以再重復(fù)播放,除非重新向服務(wù)器端要求數(shù)據(jù)。
RTSP與RTP最大的區(qū)別在于:RTSP是一種雙向?qū)崟r數(shù)據(jù)傳輸協(xié)議,它允許客戶端向服務(wù)器端發(fā)送請求,如回放、快進、倒退等操作。當(dāng)然,RTSP可基于RTP來傳送數(shù)據(jù),還可以選擇TCP、UDP、組播UDP等通道來發(fā)送數(shù)據(jù),具有很好的擴展性。它時一種類似與http協(xié)議的網(wǎng)絡(luò)應(yīng)用層協(xié)議。
RTSP處于應(yīng)用層,而RTP/RTCP處于傳輸層。RTSP負(fù)責(zé)建立以及控制會話,RTP負(fù)責(zé)多媒體數(shù)據(jù)的傳輸。而RTCP是一個實時傳輸控制協(xié)議,配合RTP做控制和流量監(jiān)控。封裝發(fā)送端及接收端(主要)的統(tǒng)計報表。這些信息包括丟包率,接收抖動等信息。發(fā)送端根據(jù)接收端的反饋信息做響應(yīng)的處理。RTP與RTCP相結(jié)合雖然保證了實時數(shù)據(jù)的傳輸,但也有自己的缺點。最顯著的是當(dāng)有許多用戶一起加入會話進程的時候,由于每個參與者都周期發(fā)送RTCP信息包,導(dǎo)致RTCP包泛濫(flooding)。
RTMP——Real Time Messaging Protocol(實時消息傳輸協(xié)議)
RTMP是由Adobe公司提出的,在互聯(lián)網(wǎng)TCP/IP五層體系結(jié)構(gòu)中應(yīng)用層,RTMP協(xié)議是基于TCP協(xié)議的,也就是說RTMP實際上是使用TCP作為傳輸協(xié)議。TCP協(xié)議在處在傳輸層,是面向連接的協(xié)議,能夠為數(shù)據(jù)的傳輸提供可靠保障,因此數(shù)據(jù)在網(wǎng)絡(luò)上傳輸不會出現(xiàn)丟包的情況。不過這種可靠的保障也會造成一些問題,也就是說前面的數(shù)據(jù)包沒有交付到目的地,后面的數(shù)據(jù)也無法進行傳輸。幸運的是,目前的網(wǎng)絡(luò)帶寬基本上可以滿足RTMP協(xié)議傳輸普通質(zhì)量視頻的要求。
RTMP傳輸?shù)臄?shù)據(jù)的基本單元為Message,但是實際上傳輸?shù)淖钚卧荂hunk(消息塊),因為RTMP協(xié)議為了提升傳輸速度,在傳輸數(shù)據(jù)的時候,會把Message拆分開來,形成更小的塊,這些塊就是Chunk。
消息(Message)的結(jié)構(gòu)
Message結(jié)構(gòu)分析
1.Message Type:它是一個消息類型的ID,通過該ID接收方可以判斷接收到的數(shù)據(jù)的類型,從而做相應(yīng)的處理。Message Type ID在1-7的消息用于協(xié)議控制,這些消息一般是RTMP協(xié)議自身管理要使用的消息,用戶一般情況下無需操作其中的數(shù)據(jù)。Message Type ID為8,9的消息分別用于傳輸音頻和視頻數(shù)據(jù)。Message Type ID為15-20的消息用于發(fā)送AMF編碼的命令,負(fù)責(zé)用戶與服務(wù)器之間的交互,比如播放,暫停等。
2.Playload Length: 消息負(fù)載的長度,即音視頻相關(guān)信息的的數(shù)據(jù)長度,4個字節(jié)
3.TimeStamp:時間戳,3個字節(jié)。
4.Stream ID:消息的唯一標(biāo)識。拆分消息成Chunk時添加該ID,從而在還原時根據(jù)該ID識別Chunk屬于哪個消息。
5.Message Body:消息體,承載了音視頻等信息。
消息塊(Chunk)
通過上圖可以看出,消息塊在結(jié)構(gòu)上與與消息類似,有Header和Body。
1.Basic Header:基本的頭部信息,在頭部信息里面包含了chunk stream ID(流通道Id,用來標(biāo)識指定的通道)和chunk type(chunk的類型)。
2.Message Header:消息的頭部信息,包含了要發(fā)送的實際信息(可能是完整的,也可能是一部分)的描述信息。Message Header的格式和長度取決于Basic Header的chunk type。
3.Extended TimeStamp:擴展時間戳。
4.Chunk Data:塊數(shù)據(jù)。
RTMP在傳輸數(shù)據(jù)的時候,發(fā)送端會把需要傳輸?shù)拿襟w數(shù)據(jù)封裝成消息,然后把消息拆分成消息塊,再一個一個進行傳輸。接收端收到消息塊后,根據(jù)Message Stream ID重新將消息塊進行組裝、組合成消息,再解除該消息的封裝處理就可以還原出媒體數(shù)據(jù)。由此可以看出,RTMP收發(fā)數(shù)據(jù)是以Chunk為單位,而不是以Message為單位。需要注意的是,RTMP發(fā)送Chunk必須是一個一個發(fā)送,后面的Chunk必須等前面的Chunk發(fā)送完成。
1.簡要介紹
RTMP協(xié)議是應(yīng)用層協(xié)議,是要靠底層可靠的傳輸層協(xié)議(通常是TCP)來保證信息傳輸?shù)目煽啃缘摹T诨趥鬏攲訁f(xié)議的鏈接建立完成后,一個RTMP協(xié)議的流媒體推流需要經(jīng)過以下幾個步驟:握手,建立連接,建立流,推流。RTMP連接都是以握手作為開始的。建立連接階段用于建立客戶端與服務(wù)器之間的“網(wǎng)絡(luò)連接”;建立流階段用于建立客戶端與服務(wù)器之間的“網(wǎng)絡(luò)流”;推流階段用于傳輸視音頻數(shù)據(jù)。
接下來就簡單介紹下這一過程
2.握手
在rtmp連接建立后,服務(wù)端與客戶端需要通過3次交換報文完成握手,握手其他的協(xié)議不同,是由三個靜態(tài)大小的塊,而不是可變大小的塊組成的,客戶端與服務(wù)器發(fā)送相同的三個chunk,客戶端發(fā)送c0,c1,c2,服務(wù)端發(fā)送s0,s1,s2。
發(fā)送規(guī)則
握手開始于客戶端發(fā)送 C0,C1 塊。
在發(fā)送 C2 之前客戶端必須等待接收 S1 。
在發(fā)送任何數(shù)據(jù)之前客戶端必須等待接收 S2。
服務(wù)端在發(fā)送 S0 和 S1 之前必須等待接收 C0,也可以等待接收 C1。
服務(wù)端在發(fā)送 S2 之前必須等待接收 C1。
服務(wù)端在發(fā)送任何數(shù)據(jù)之前必須等待接收 C2。
數(shù)據(jù)格式
C0與S0
C0和S0的長度是一個字節(jié),在 S0 中這個字段表示服務(wù)器選擇的 RTMP 版本。rtmp1.0規(guī)范所定義的版本是 3;0-2 是早期產(chǎn)品所用的,已被丟棄;4-31保留在未來使用;32-255 不允許使用(為了區(qū)分其他以某一字符開始的文本協(xié)議)。如果服務(wù)無法識別客戶端請求的版本,應(yīng)該返回 3 。客戶端可以選擇減到版本 3 或選擇取消握手。
C1與S1
C1 和 S1 有 1536 字節(jié)長,由下列字段組成:
時間:4 字節(jié) 本字段包含時間戳。該時間戳應(yīng)該是發(fā)送這個數(shù)據(jù)塊的端點的后續(xù)塊的時間起始點。可以是 0,* 或其他的 任何值。為了同步多個流,端點可能發(fā)送其塊流的當(dāng)前值。
零:4 字節(jié) 本字段必須是全零。
隨機數(shù)據(jù):1528 字節(jié)。 本字段可以包含任何值。 因為每個端點必須用自己初始化的握手和對端初始化的握 手來區(qū)分身份,所以這個數(shù)據(jù)應(yīng)有充分的隨機性。但是并不需要加密安全的隨機值,或者動態(tài)值
C2與S2
C2 和 S2 消息有 1536 字節(jié)長。只是 S1 和 C1 的回復(fù)。本消息由下列字段組成。
時間:4 字節(jié) 本字段必須包含對等段發(fā)送的時間(對 C2 來說是 S1,對 S2 來說是 C1)。
時間 2:4 字節(jié) 本字段必須包含先前發(fā)送的并被對端讀取的包的時間戳。
隨機回復(fù):1528 字節(jié) 本字段必須包含對端發(fā)送的隨機數(shù)據(jù)字段(對 C2 來說是 S1,對 S2 來說是 C1) 。 每個對等端可以用時間和時間 2 字段中的時間戳來快速地估計帶寬和延遲。 但這樣做可 能并不實用。
RTMP握手的這個過程就是完成了兩件事:1. 校驗客戶端和服務(wù)器端RTMP協(xié)議版本號,2. 是發(fā)了一堆數(shù)據(jù),猜想應(yīng)該是測試一下網(wǎng)絡(luò)狀況,看看有沒有傳錯或者不能傳的情況。
3.建立網(wǎng)絡(luò)連接
客戶端發(fā)送命令消息中的“連接”(connect)到服務(wù)器,請求與一個服務(wù)應(yīng)用實例建立連接。
服務(wù)器接收到連接命令消息后,發(fā)送確認(rèn)窗口大小(Window Acknowledgement Size)協(xié)議消息到客戶端,同時連接到連接命令中提到的應(yīng)用程序。
服務(wù)器發(fā)送設(shè)置帶寬()協(xié)議消息到客戶端。
客戶端處理設(shè)置帶寬協(xié)議消息后,發(fā)送確認(rèn)窗口大小(Window Acknowledgement Size)協(xié)議消息到服務(wù)器端。
服務(wù)器發(fā)送用戶控制消息中的“流開始”(Stream Begin)消息到客戶端。
服務(wù)器發(fā)送命令消息中的“結(jié)果”(_result),通知客戶端連接的狀態(tài)。
注意:
這里面的connect 命令消息,命令里面包含什么東西,協(xié)議中沒有說,真實通信中要指定一些編解碼的信息,這些信息是以AMF格式發(fā)送的, 其中audioCodecs和videoCodecs這兩個指定音視頻編碼信息的不能少的。
Window Acknowledgement Size 是設(shè)置接收端消息窗口大小,一般是2500000字節(jié),即告訴客戶端你在收到我設(shè)置的窗口大小的這么多數(shù)據(jù)之后給我返回一個ACK消息,告訴我你收到了這么多消息。在實際做推流的時候推流端要接收很少的服務(wù)器數(shù)據(jù),遠(yuǎn)遠(yuǎn)到達(dá)不了窗口大小,所以基本不用考慮這點。而對于服務(wù)器返回的ACK消息一般也不做處理,我們默認(rèn)服務(wù)器都已經(jīng)收到了這么多消息。
服務(wù)器返回的_result命令類型消息的payload length一般不會大于128字節(jié),但是在最新的nginx-rtmp中返回的消息長度會大于128字節(jié),所以一定要做好收包,組包的工作。
4.建立網(wǎng)絡(luò)流
創(chuàng)建完網(wǎng)絡(luò)連接之后就可以創(chuàng)建網(wǎng)絡(luò)流了
客戶端發(fā)送命令消息中releaseStream命令到服務(wù)器端
客戶端發(fā)送命令消息中FCPublish命令到服務(wù)器端
客戶端發(fā)送命令消息中的“創(chuàng)建流”(createStream)命令到服務(wù)器端。
服務(wù)器端接收到“創(chuàng)建流”命令后,發(fā)送命令消息中的“結(jié)果”(_result),通知客戶端流的狀態(tài)。
解析服務(wù)器返回的消息會得到一個stream ID, 這個ID也就是以后和服務(wù)器通信的 message stream ID, 一般返回的是1,不固定。
5.推流命令
推流準(zhǔn)備工作的最后一步是 Publish Stream,即向服務(wù)器發(fā)一個publish命令,這個命令的message stream ID 就是上面 create stream 之后服務(wù)器返回的stream ID,發(fā)完這個命令一般不用等待服務(wù)器返回的回應(yīng),直接下一步發(fā)送音視頻數(shù)據(jù)。有些rtmp庫 還會發(fā)setMetaData消息,這個消息可以發(fā)也可以不發(fā),里面包含了一些音視頻編碼的信息。
當(dāng)以上工作都完成的時候,就可以發(fā)送音視頻了。