上一篇Live555源碼解析(1) - Main 尋根問祖,留其筋骨將main()函數(shù)脈絡(luò)做了整體分析,通常來講本篇應(yīng)從服務(wù)器的創(chuàng)建開始講起,但如前文所述,Live555媒體服務(wù)器是基于RTSP協(xié)議實現(xiàn),為了便于源碼閱讀, 在這里有必要先整體介紹下RTSP協(xié)議及相關(guān)協(xié)議內(nèi)容。如讀者已掌握RTSP內(nèi)容,則可跳過本篇,繼續(xù)下一篇Live555源碼解析(3) - 服務(wù)開啟,愿者上鉤的閱讀。
編寫本篇前,盡可能詳細地翻譯了RTSP Sepc,如有興趣,可同時閱讀RTSP Spec中文版。
1. RTSP簡史
RTSP出現(xiàn)以前,最熱的大概就是HTTP協(xié)議。想象一下,當(dāng)你需要欣賞網(wǎng)絡(luò)中的某一段視頻,通過HTTP協(xié)議訪問其URL、開始下載、下載完成后播放。對于早期的視頻采集設(shè)備、網(wǎng)絡(luò)帶寬或是負責(zé)渲染的顯示器而言,似乎多給予一點耐心、多重連幾次斷開的HTTP連接、甚至多校驗幾次下載后文件的完整性,體驗上也還能過得去。畢竟那時候的分辨率、幀率、帶寬限制了互聯(lián)網(wǎng)途徑傳播媒體文件的大小,信息的分享只能通過各種硬盤、U盤、光盤以存儲后文件的形式進行傳輸。
隨著硬件設(shè)備技術(shù)的發(fā)展,采集設(shè)備分辨率在提升,顯示器支持了更高的幀率,網(wǎng)絡(luò)帶寬也指數(shù)增長,這都為更好的觀影體驗提供了基礎(chǔ)支持。隨著網(wǎng)絡(luò)資源的日益豐富,用戶時間的稀缺性日益凸顯,為了快速觀看、判別視訊本身是否符合自身口味,在線實時觀看成了一大述求。而傳統(tǒng)的HTTP下載顯然不能夠匹配該需求,因此在尋求streaming的道路上,RTSP脫穎而出。
RTSP全稱實時流協(xié)議(Real Time Streaming Protocol),它是一個網(wǎng)絡(luò)控制協(xié)議,設(shè)計用于娛樂、會議系統(tǒng)中控制流媒體服務(wù)器。RTSP用于在希望通訊的兩端建立并控制媒體會話(session),客戶端通過發(fā)出VCR-style命令如play、record和pause等來實時控制媒體流。
RTSP處理流時會根據(jù)端點間可用帶寬大小,將音視頻等數(shù)據(jù)切割成小分組(packet)進行傳輸,使得客戶端在播放一個分組的同時,可以解壓緩存中第二個甚至下載第三個分組。通過緩存和多碼率流技術(shù),用戶將不會感覺到數(shù)據(jù)間存在停頓。至于RTSP的特性,則主要體現(xiàn)在如下方面:
- 多服務(wù)器兼容 :媒體流可來自不同服務(wù)器
- 可協(xié)商:客戶端和服務(wù)器可協(xié)商feature支持程度
- HTTP親和性:盡可能重用HTTP概念,包括認證、狀態(tài)碼、解析等
- 易解析:HTML或MIME解析器均可在RTSP中適用
- 易擴展:新的方法或參數(shù)甚至協(xié)議本身均可添加或定制
- 防火墻親和性:傳輸層或應(yīng)用層防火墻均可被協(xié)議較好處理
- 服務(wù)器控制:控制概念易于理解,服務(wù)器不允許向客戶端傳輸不能被客戶端關(guān)閉的流
- 多場景適用:RTSP提供幀級別精度,適用于更多媒體應(yīng)用場景
1.1 相關(guān)協(xié)議介紹
RTSP組合使用了可靠傳輸協(xié)議TCP(控制)和高效傳輸協(xié)議UDP(內(nèi)容)來串流(streaming)內(nèi)容給用戶。它支持點播(Video-On-Demand)以及直播(Live Streaming)服務(wù)。
RTSP協(xié)議本身并不負責(zé)數(shù)據(jù)傳輸,通常(非必須)是通過RTP(Real-time Transport Protocol)配合RTCP(Real-time Control Protocol)完成數(shù)據(jù)流和控制命令(同步、QOS管理等)的傳輸。具體應(yīng)用中,三者的關(guān)系如下圖所示:

2. RTSP方法
RTSP中并沒有連接的概念,而是通過會話(Session)進行管理。每個會話有對應(yīng)的會話ID,會話中可能可能涉及一至多個流,會話生命周期中,客戶端也可能切換連接(如TCP)來傳遞RTSP請求(request)。
| method | direction | object | requirement |
|---|---|---|---|
| DESCRIBE | C->S | P,S | recommended |
| ANNOUNCE | C->S, S->C | P,S | optional |
| GET_PARAMETER | C->S, S->C | P,S | optional |
| OPTIONS | C->S, S->C | P,S | required(S->C:optional) |
| PAUSE | C->S | P,S | recommended |
| PLAY | C->S | P,S | required |
| RECORD | C->S | P,S | optional |
| REDIRECT | S->C | P,S | optional |
| SETUP | C->S | S | required |
| SET_PARAMETER | C->S,S->C | P,S | optional |
| TEARDOWN | C->S | P,S | required |
P: 呈現(xiàn)(Presentation),S:流(Stream)
一個RTSP應(yīng)用(如點播)生命周期內(nèi),通常會話(所有交互)過程如下圖所示:

2.1 必選方法
對于上述交互中涉及的RTSP方法,說明如下:
-
OPTIONS
用于請求服務(wù)器所支持的所有方法C->S OPTIONS rtsp://video.foocorp.com:554 RTSP/1.0 CSeq: 1 S->C RTSP/1.0 200 OK CSeq: 1 Public: DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE, RECORD -
DESCRIBE(推薦級別)
用于請求URL指定對象的描述信息,通常描述信息使用SDP(Session Description Protocol)格式。C->S DESCRIBE rtsp://video.foocorp.com:554/streams/example.rm RTSP/1.0 CSeq: 2 S->C RTSP/1.0 200 OK CSeq: 2 Content-Type: application/sdp Content-Length: 210 m=video 0 RTP/AVP 96 a=control:streamid=0 a=range:npt=0-7.741000 a=length:npt=7.741000 a=rtpmap:96 MP4V-ES/5544 a=mimetype:string;"video/MP4V-ES" a=AvgBitRate:integer;304018 a=StreamName:string;"hinted video track" m=audio 0 RTP/AVP 97 a=control:streamid=1 a=range:npt=0-7.712000 a=length:npt=7.712000 a=rtpmap:97 mpeg4-generic/32000/2 a=mimetype:string;"audio/mpeg4-generic" a=AvgBitRate:integer;65790 a=StreamName:string;"hinted audio track"SDP協(xié)議格式
SDP(Session Description Protocol)是一個用來描述多媒體會話的應(yīng)用層控制協(xié)議,是一個基于文本的協(xié)議,用于會話建立過程中的媒體類型和編碼方案的協(xié)商等。SDP描述由許多文本行組成,文本行的格式為<類型>=<值>,<類型>是一個字母,<值>是結(jié)構(gòu)化的文本串,其格式依<類型>而定。<type>=<value>[CRLF]sdp的格式:
v=<version> (協(xié)議版本) o=<username> <session id> <version> <network type> <address type> <address> (所有者/創(chuàng)建者和會話標識符) s=<session name> (會話名稱) i=<session description> (會話信息) u=<URI> (URI 描述) e=<email address> (Email 地址) p=<phone number> (電話號碼) c=<network type> <address type> <connection address> (連接信息) b=<modifier>:<bandwidth-value> (帶寬信息) t=<start time> <stop time> (會話活動時間) r=<repeat interval> <active duration> <list of offsets from start-time>(0或多次重復(fù)次數(shù)) z=<adjustment time> <offset> <adjustment time> <offset> .... k=<method> k=<method>:<encryption key> (加密密鑰) a=<attribute> (0 個或多個會話屬性行) a=<attribute>:<value> m=<media> <port> <transport> <fmt list> (媒體名稱和傳輸?shù)刂? -
SETUP
用于請求URL使用指定傳輸格式,必須在PLAY前發(fā)出。C->S SETUP rtsp://video.foocorp.com:554/streams/example.rm RTSP/1.0 CSeq: 3 Transport: rtp/udp;unicast;client_port=5067-5068 S->C RTSP/1.0 200 OK CSeq: 3 Session: 12345678 Transport: rtp/udp;client_port=5067-5068;server_port=6023-6024客戶端請求中,指明了用于接收RTP數(shù)據(jù)(音視頻)的本地端口5067,以及RTCP數(shù)據(jù)(元信息)的端口5068。這里圖示說明下RTSP(554/8554)、RTP、RTCP端口關(guān)系。
可以看到,RTCP端口是基于RTP的,且始終為其端口值+1。服務(wù)器回復(fù)中,確認了客戶端所請求的端口,并給出服務(wù)器端對應(yīng)開辟的端口值6023/6024。
-
PLAY
用于請求服務(wù)器使用SETUP中確認的機制開始傳輸數(shù)據(jù),客戶端不應(yīng)在SETUP請求未被確認應(yīng)答成功前發(fā)出PLAY請求。另外需要注意,PLAY請求是需要排隊的,其中可攜帶Range域以指明區(qū)間。C->S PLAY rtsp://video.foocorp.com:554/streams/example.rm RTSP/1.0 CSeq: 4 Range: npt=5-20 Session: 12345678 S->C RTSP/1.0 200 OK CSeq: 4 Session: 12345678 -
TEARDOWN
用于請求終止會話,將停止會話中所有相關(guān)流,并釋放資源。C->S TEARDOWN rtsp://video.foocorp.com:554/streams/example.rm RTSP/1.0 CSeq: 5 Session: 12345678 S->C RTSP/1.0 200 OK CSeq: 5
2.2 可選方法
除了上一小節(jié)中提到的5種必選方法外,還有如下方法是可選的。
-
ANNOUNCE
ANNOUNCE方法有兩個用途:- 從服務(wù)器發(fā)送給客戶端時:用于更新實時會話描述
- 從客戶端發(fā)送給服務(wù)器時:推送URL指定的呈現(xiàn)或媒體對象的描述
如果呈現(xiàn)途中插入新流,應(yīng)重發(fā)完整描述,而不僅僅是增量。這樣一來,也就支持了動態(tài)移除組件。
C->S: ANNOUNCE rtsp://video.foocorp.com:554/streams/example.rm RTSP/1.0 CSeq: 10 Session: 47112344 Content-Type: application/sdp Content-Length: 332 v=0 o=mhandley 2890844526 2890845468 IN IP4 126.16.64.4 s=SDP Seminar i=A Seminar on the session description protocol u=http://www.cs.ucl.ac.uk/staff/M.Handley/sdp.03.ps e=mjh@isi.edu (Mark Handley) c=IN IP4 224.2.17.12/127 t=2873397496 2873404696 a=recvonly m=audio 3456 RTP/AVP 0 m=video 2232 RTP/AVP 31 S->C: RTSP/1.0 200 OK CSeq: 10 -
GET_PARAMETER
用于請求URI指定呈現(xiàn)或流的參數(shù)值?;貜?fù)的內(nèi)容有待實現(xiàn),不帶任何實體主體的GET_PARAMETER可用于測試客戶端或服務(wù)器是否在線(類似“ping”程序)。S->C: GET_PARAMETER rtsp://example.com/fizzle/foo RTSP/1.0 CSeq: 431 Content-Type: text/parameters Session: 12345678 Content-Length: 15 packets_received jitter C->S: RTSP/1.0 200 OK CSeq: 431 Content-Length: 46 Content-Type: text/parameters packets_received: 10 jitter: 0.3838 -
SET_PARAMETER
SET_PARAMETER請求用于設(shè)置URI指定呈現(xiàn)或流的參數(shù)值。
每條請求應(yīng)當(dāng)只包含一個參數(shù)以允許客戶端確定失敗原因,如果請求中包含多個參數(shù),服務(wù)器必須只在所有參數(shù)都能成功設(shè)置情況下生效。服務(wù)器應(yīng)當(dāng)允許同一參數(shù)多次設(shè)置同一值,但可拒絕設(shè)置為不同值。
注意:媒體流傳輸參數(shù)必須通過SETUP請求來設(shè)置C->S: SET_PARAMETER rtsp://example.com/fizzle/foo RTSP/1.0 CSeq: 421 Content-Length: 20 Content-type: text/parameters barparam: barstuff S->C: RTSP/1.0 451 Invalid Parameter CSeq: 421 Content-Length: 10 Content-type: text/parameters barparam -
PAUSE
PAUSE請求會臨時中斷流傳輸,如果URL指定的是某一個流,則該流的播放和錄制會被暫停。例如,對于音頻而言,相當(dāng)于靜音操作。如果URL指定的是一組流,則呈現(xiàn)或組中所有活動流將會被暫停。當(dāng)恢復(fù)播放或錄制時,所有軌道的流必須進行同步。
此過程中,所有服務(wù)器資源均會保留,除非SETUP時,頭中有參數(shù)指定延時,那么服務(wù)器可能在觸發(fā)延時后關(guān)閉會話并釋放資源。C->S: PAUSE rtsp://example.com/fizzle/foo RTSP/1.0 CSeq: 834 Session: 12345678 S->C: RTSP/1.0 200 OK CSeq: 834 Date: 23 Jan 1997 15:35:06 GMT -
RECORD
RECORD方法用于開始錄制當(dāng)前呈現(xiàn)描述中的一段媒體數(shù)據(jù),UTC格式時間戳包含開始點和結(jié)尾點。如未給出時間范圍,則使用呈現(xiàn)描述中的開始點和結(jié)尾點。如會話已處于運行中,則立即開始錄制。
服務(wù)器決定將錄制數(shù)據(jù)保存在請求URI或其他URI,如使用其他URI,需回復(fù)“201(Created)”并包含實體以描述請求狀態(tài)和新資源位置信息。
一個支持直播情境下錄制的服務(wù)器必須支持clock格式,這里smpte格式并沒有意義。C->S: RECORD rtsp://example.com/meeting/audio.en RTSP/1.0 CSeq: 954 Session: 12345678 Conference: 128.16.64.19/32492374 -
REDIRECT
REDIRECT請求用于提示客戶端它必須連接至另一個服務(wù)器,其中強制包含了Location頭,以指明新的服務(wù)器URL。其中還可能包含Range參數(shù),指明何時重定向?qū)⑸АH绻蛻舳讼M蛟揢RI發(fā)送和接收媒體,則客戶端必須先對當(dāng)前會話發(fā)出TEARDOWN請求,然后向目標主機發(fā)出SETUP請求新的會話。S->C: REDIRECT rtsp://example.com/fizzle/foo RTSP/1.0 CSeq: 732 Location: rtsp://bigserver.com:8001 Range: clock=19960213T143205Z-
2.3 RTSP狀態(tài)機

2.4 嵌入式二進制數(shù)據(jù)(Embedded (Interleaved) Binary Data)
某些防火墻設(shè)計或其他環(huán)境因素可能迫使服務(wù)器將RTSP方法交錯進流數(shù)據(jù)中。該種交錯操作應(yīng)盡可能避免,因為它提高了客戶端和服務(wù)器操作的復(fù)雜度,也增加了額外的開銷。嵌入式二進制數(shù)據(jù)應(yīng)當(dāng)只在RTSP通過TCP傳輸時使用。
C->S SETUP rtsp://example.com/media.mp4 RTSP/1.0
CSeq: 3
Transport: RTP/AVP/TCP;interleaved=0-1
S->C RTSP/1.0 200 OK
CSeq: 3
Date: 05 Jun 1997 18:57:18 GMT
Transport: RTP/AVP/TCP;interleaved=0-1
Session: 12345678
C->S PLAY rtsp://example.com/media.mp4 RTSP/1.0
CSeq: 4
Session: 12345678
S->C RTSP/1.0 200 OK
CSeq: 4
Session: 12345678
Date: 05 Jun 1997 18:59:15 GMT
RTP-Info: url=rtsp://example.com/media.mp4;
seq=232433;rtptime=972948234
S->C $\000{2 byte length}{"length" bytes data, w/RTP header}
$\000{2 byte length}{"length" bytes data, w/RTP header}
$\001{2 byte length}{"length" bytes RTCP packet}
3. Live555 openRTSP
openRTSP a command-line RTSP client
openRTSP是用于打開、串流、接收以及可選地錄制媒體流的命令行客戶端,媒體流通過RTSP URL指定,URL前綴為"rtsp://"。
本系列只以MediaServer源碼為分析對象,因此對openRTSP不做討論。
4. 實踐檢驗
4.1 RTSP測試源
由于Windows真機環(huán)境負責(zé),進程較多,進行抓包分析時干擾項很多,因此測試時創(chuàng)建了虛擬機,在發(fā)行版Ubuntu上進行了搭建。 Live555MediaServer Ubuntu可以直接下載,下載后在相同目錄下放置媒體文件進行測試即可。
4.2 Wireshark抓包分析
下面就對應(yīng)Wireshark抓包以及前述會話過程進行驗證。
服務(wù)器地址:192.168.63.130:8554
客戶端地址:192.168.63.1 :9571
4.2.1 TCP 三路握手
沒有太多好說的,TCP標準三路握手,確定了窗口大?。╓in),MSS等選項。

4.2.2 OPTIONS

OPTIONS請求、回復(fù),有如下幾個注意點:
- 中間有夾雜一個TCP協(xié)議的ACK用于確認收到請求,且ACK=141。為什么是141,因為OPTIONS請求中TCP Segment長度為140,所以下一個為141
- 回復(fù)中 Public域中明確給出了所支持的方法
4.2.3 DESCRIBE

DESCRIBE請求、回復(fù),沒有夾雜ACK?;貜?fù)中以SDP協(xié)議格式給出了會話ID及其他會話屬性。注意最后一個字段Meida Attribute中表明了control:track1,該值將在下一步SETUP中使用到。
4.2.4 SETUP

服務(wù)器在回復(fù)SETUP請求后,注意客戶端有連續(xù)發(fā)出4個RTP/RTCP請求給服務(wù)器。
4.2.5 PLAY

PLAY請求中使用聚合控制URL,針對呈現(xiàn)本身,可同時作用于其中的多個流。Range值為從0開始到結(jié)束。

緊跟其后的是MPEG TS協(xié)議包,實際上是RTP協(xié)議通過UDP在傳遞TS流信息。
4.2.6 GET_PARAMETER

4.2.7 PAUSE

PAUSE中未攜帶Range域,表示立即暫停。客戶端在收到服務(wù)器回復(fù)后,進行了額外ACK。
4.2.8 TEARDOWN

客戶端請求關(guān)閉會話,Receiver Report屬于客戶端發(fā)往服務(wù)器的RTCP控制命令。
4.2.9 TCP四路斷開

為什么不是四條,因為該種情況下兩端同時斷開,只需要將ACK放入發(fā)出的FIN中即可,不需要單獨發(fā)送一條消息。
