Android MediaPlayer中的RTSP(一):RTSP簡介

背景:

我在最近的項目中遇到了使用Android的MediaPlayer來進行RTSP播放的場景。但對於RTSP這種流媒體協議,其實Android原生的播放器支持得不是很好,所以有許多需要修改的地方。

本文主要簡單介紹RTSP協議及其在MediaPlayer中的層級,後續會記錄下在項目中遇到的具體情況及對應的修改。

RTSP播放器架構

播放器的架構很清晰,
apk–>MediaPlayer->media_server–>廠商自己的Player(和NuPalyer/StagefrightPlayer一個層級)–>FFmpeg
如下圖。
 RTSP播放器架構
因爲走Android MediaPlayer的流程,拉流的部分是使用FFmpeg實現的,所以FFmpeg是最核心的部分,主要的修改,也即是針對FFmpeg裏RTSP部分的修改,以適配項目的特殊性。

##RTSP協議簡介##
###1、簡介###
RTSP屬於應用層協議,被用於控制媒體流的傳輸,它爲多媒體服務扮演“網絡遠程控制”的角色,對流媒體提供了諸如暫停,快進等控制,而它本身並不傳輸數據。

因爲RTSP的作用相當於流媒體服務器的遠程控制,所以客戶端需要和服務器進行命令交互,以到達建立/釋放連接及遠程控制的目的。命令連接基於TCP,一般使用554端口。而數據傳輸可以選擇TCP或UDP來傳送,這個需要看服務端的支持情況及客戶端的選擇。
RTSP負責建立和控制會話,RTP/TCP負責多媒體的傳輸,RTCP配合RTP做控制和流量統計,他們是合作的關係。
這裏寫圖片描述

###2、RTSP的消息###
RTSP的消息有兩大類,一是請求消息(request),一是迴應消息(response),兩種消息的格式不同。

請求消息格式:

方法 URI RTSP版本 CR LF
消息頭 CR LF CR LF
消息體 CR LF
其中方法包括OPTIONS、SETUP、PLAY、TEARDOWN等待,URI是接收方(服務端)的地址,例如:rtsp://192.168.22.136:5000/v0,每行後面的CR LF表示回車換行,需要接收端有相應的解析,最後一個消息頭需要有兩個CR LF。

迴應消息格式:

RTSP版本 狀態碼 解釋 CR LF
消息頭 CR LF CR LF
消息體 CR LF
其中RTSP版本一般都是RTSP/1.0,狀態碼是一個數值,200表示成功,解釋是與狀態碼對應的文本解釋。

狀態碼和HTTP差不多,由三位數組成,表示方法執行的結果,定義如下:

1XX:保留,將來使用;
2XX:成功,操作被接收、理解、接受(received,understand,accepted);
3XX:重定向,要完成操作必須進行進一步操作;
4XX:客戶端出錯,請求有語法錯誤或無法實現;
5XX:服務器出錯,服務器無法實現合法的請求。

RTSP中定義的方法有:OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE, SCALE, GET_PARAMETER ,SET_PARAMETER 。
在下面的交互流程中的例子中,會簡單介紹這些方法的使用。

3 SDP各個參數簡單介紹

這裏寫圖片描述

注: "a="字段描述節目時長。直播用 clock=表示,描述直播時移時長;點播用 ntp=表示 ,描述點播節目時長。具體參見 rfc 2326。

舉例如下:
直播:直播時移時長爲 1 小時
a=range:clock=20100817T000742.55Z-20100818T000742.55Z
點播: a=range:npt=0-246.655
注: "c="字段表示連接描述,可使用組播地址;如果是組播地址,字段包含了媒體流的目的地址。也就是說,通過單播 rtsp 獲取當前直播頻道的組播地址,然後加入這個組播播放。具體參見 rfc 2326。例如: c=IN IP4 225.61.100.28/16
注: "m"字段表示負載類型(PT): RTP 信息包中的有效載荷域(Payload Type Field)的長度爲 7位,因此 RTP 可支持 128 種不同的有效載荷類型。具體參見 rfc 3551。

SDP例子

DESCRIBE rtsp://61.149.64.212:554/live/ch11091521323921117877.sdp?playtype=1&boid=001&backupagent=61.149.64.212:554&clienttype=1&time=20180510144608+08&life=172800&ifpricereqsnd=1&vcdnid=001&userid=09-20170912003-01&mediaid=ch11091521323921117877&ctype=5&TSTVTimeLife=604800&contname=&authid=0&UserLiveType=1&stbid=801100c8bb1d8e97&nodelevel=3&terminalflag=1&bitrate=3 RTSP/1.0
Accept: application/sdp
CSeq: 2

RTSP/1.0 200 OK
Server: ZXUSS100 1.0
Cache-Control: no-cache
Content-Base: rtsp://61.149.64.212:554/live/ch11091521323921117877.sdp/
Content-Length: 267
Content-Type: application/sdp
CSeq: 2
Date: Thu, 10 May 2018 06:48:32 GMT
Expires: Thu, 10 May 2018 06:48:32 GMT

v=0
o=- 0 0 IN IP4 61.149.64.212
s=ZMSS RTSP Server
c=IN IP4 239.2.1.232/16 
b=AS:2500 
t=0 0
a=control:*
a=range:clock=20180503T064832.00Z-20180510T064832.00Z
m=video 8000 RTP/AVP 33
a=rtpmap:33 MP2T/90000
a=control:trackID=2
a=3GPP-Adaptation-Support:5

###4、RTSP交互流程###
一次基本的RTSP操作過程如下:

  1. 客戶端連接到流服務器併發送一個RTSP描述命令(DESCRIBE)
  2. 流服務器通過一個SDP描述來進行反饋,反饋信息包括流數量、媒體類型等信息
  3. 客戶端再分析該SDP描述,併爲會話中的每一個流發送一個RTSP建立命令(SETUP),RTSP建立命令告訴服務器客戶端用於接收媒體數據的端口
  4. 客戶端發送一個播放命令(PLAY),服務器就開始在TCP/UDP上傳送媒體流(RTP包)到客戶端
  5. 在播放過程中客戶端還可以向服務器發送命令來控制快進、快退和暫停等
  6. 最後,客戶端可發送一個終止命令(TERADOWN)來結束流媒體會話

例子如下:

/*OPTIONS 主要功能:獲取服務器/客戶端支持的能力集,
關鍵字段:
Public:服務器支持的命令,在此例子中是用於獲取服務器支持的命令,可以看到服務器回覆我們支持DESCRIBE,OPTIONS,SETUP,TEARDOWN,PLAY,PAUSE,GET_PARAMETER,SET_PARAMETER
特殊說明:在一個RTSP交互流程中OPTIONS方法並不是必須的,前提是你知道服務器支持哪些命令
*/
OPTIONS rtsp://61.149.64.212:554/live/ch11091521323921117877.sdp?playtype=1&boid=001&backupagent=61.149.64.212:554&clienttype=1&time=20180510144608+08&life=172800&ifpricereqsnd=1&vcdnid=001&userid=09-20170912003-01&mediaid=ch11091521323921117877&ctype=5&TSTVTimeLife=604800&contname=&authid=0&UserLiveType=1&stbid=801100c8bb1d8e97&nodelevel=3&terminalflag=1&bitrate=3 RTSP/1.0
CSeq: 1

RTSP/1.0 200 OK
Public: DESCRIBE,OPTIONS,SETUP,TEARDOWN,PLAY,PAUSE,GET_PARAMETER,SET_PARAMETER
Server: ZXUSS100 1.0 CSeq: 1

/*
DESCRIBE 主要功能:從服務器獲取流媒體文件格式信息,從服務器獲取流媒體文件傳輸信息
關鍵字段:
Content-Type:一般是SDP
Content-length:一般是SDP的長度
特殊說明:媒體信息通過SDP協議給出,例如這個例子中服務器回覆range:clock=20180503T064832.00Z-20180510T064832.00Z,告訴客戶端服務器的可時移range,並且是clock(絕對時間描述),也就是PLAY階段請求的時間是ISO 8601時間戳標準
*/
DESCRIBE rtsp://61.149.64.212:554/live/ch11091521323921117877.sdp?playtype=1&boid=001&backupagent=61.149.64.212:554&clienttype=1&time=20180510144608+08&life=172800&ifpricereqsnd=1&vcdnid=001&userid=09-20170912003-01&mediaid=ch11091521323921117877&ctype=5&TSTVTimeLife=604800&contname=&authid=0&UserLiveType=1&stbid=801100c8bb1d8e97&nodelevel=3&terminalflag=1&bitrate=3 RTSP/1.0
Accept: application/sdp
CSeq: 2

RTSP/1.0 200 OK
Server: ZXUSS100 1.0
Cache-Control: no-cache
Content-Base: rtsp://61.149.64.212:554/live/ch11091521323921117877.sdp/
Content-Length: 267
Content-Type: application/sdp
CSeq: 2
Date: Thu, 10 May 2018 06:48:32 GMT
Expires: Thu, 10 May 2018 06:48:32 GMT

v=0
o=- 0 0 IN IP4 61.149.64.212
s=ZMSS RTSP Server
c=IN IP4 239.2.1.232/16 
b=AS:2500 
t=0 0
a=control:*
a=range:clock=20180503T064832.00Z-20180510T064832.00Z
m=video 8000 RTP/AVP 33
a=rtpmap:33 MP2T/90000
a=control:trackID=2
a=3GPP-Adaptation-Support:5

/*
SETUP 主要功能:與服務器協商流媒體傳輸方式,此過程中,建立RTP通道
關鍵字段:
Transport:指明服務器支持的傳輸方式及傳輸端口,地址等等信息。
在例子中參數MP2T/RTP/UDP指明服務器傳輸媒體數據將使用UDP傳輸;參數server_port=8000-8001;source=239.2.1.232指明瞭服務器的地址和端口號;destination=192.168.1.4指明客戶端地址,這個例子中爲內網地址,對於這種情況需要做NAT穿透。
特殊說明:需要注意的是,媒體服務器的地址source=239.2.1.232,爲組播地址,需要加入RTP組播來拉流。(但在此例子中,我試過使用該地址拉流也沒數據)
*/
SETUP rtsp://61.149.64.212:554/live/ch11091521323921117877.sdp/trackID=2 RTSP/1.0
Transport: MP2T/RTP/UDP;unicast;client_port=5000-5001
CSeq: 3

RTSP/1.0 200 OK
Server: ZXUSS100 1.0
CSeq: 3
Date: Thu, 10 May 2018 06:48:32 GMT
Expires: Thu, 10 May 2018 06:48:32 GMT
Session: 65536595
Transport: MP2T/RTP/UDP;destination=192.168.1.4;client_port=5000-5001;server_port=8000-8001;source=239.2.1.232

/*
PLAY 主要功能:與服務器協商流媒體播放
關鍵字段:
Range:播放時間支持兩種格式,Range: npt=0.0-end或者Range:clock=20100318T021919.35Z-20100318T031919.80Z
方法1 位置描述,相對時間描述——npt(normalplay time)
•beginning      節目起始點
•now            當前播放點
•end            節目結束點
•相對時間		 媒體的相對時間
方法2 時間描述,絕對時間描述——clock,ISO 8601時間戳標準
•直接用數字形式表示與起始點的時間

Scale:播放速度 例如1倍速,Scale: 1.0
特殊說明:RTP-Info是前段回覆我們的媒體服務器信息,可以看到這裏和之前setup階段前端回覆的source地址並不一樣。
(這纔是媒體服務器的地址,這地方的衝突,可能是服務器寫的不標準)
*/
PLAY rtsp://61.149.64.212:554/live/ch11091521323921117877.sdp/ RTSP/1.0
Range: clock=20180510T060000.00Z-
Scale: 1.0
CSeq: 4
Session: 65536595

RTSP/1.0 200 OK
Server: ZXUSS100 1.0
CSeq: 4
Range: clock=20180510T060000.00Z-20180510T064832.93Z
Scale: 1.0
Session: 65536595
RTP-Info: url=rtsp://61.149.64.132:12370/live/ch11091521323921117877.sdp/trackID=2;seq=0;rtptime=841899578

/*
GET_PARAMETER 主要功能:1、從服務器獲取參數,目前主要獲取時間範圍;2、保持RTSP連接(發送空的GET_PARAMETER)
在此例子中,是第二種用途,keep-alive
*/
GET_PARAMETER rtsp://61.149.64.212:554/live/ch11091521323921117877.sdp/ RTSP/1.0
CSeq: 5
Session: 65536595

RTSP/1.0 200 OK
Server: ZXUSS100 1.0
CSeq: 5
Session: 65536595


總結

本文介紹了一個相對簡單清晰的RTSP交互實例,但是在實際情況中,因爲項目使用的是FFmpeg的RTSP來進行拉流的,特別是整合到MediaPlayer中使用,還是有許多情況需要考慮並完善的:

1、SETUP階段的協議選擇:載流協議是UDP還是TCP,是否使用RTP承載,嘗試一種載流協議不支持後的切換流程
2、重定向的完善:正常來說,一般在SETUP階段後,就不會再有重定向了,因爲這樣需要重新斷開再連接,但是實際使用中有些服務器是會在PLAY階段去重定向的
3、NAT穿透: 使用UDP載流時,處於內網的客戶端該如何進行NAT的打洞,以讓服務器能將數據傳送給客戶端
4、與MediaPlayer的整合:PLAY中使用絕對時間描述時,該如何與MediaPlayer整合
5、媒體服務器的選擇:即上面例子中提到的情況

這些是之前遇到的部分問題,我將在後續文章中說明這些問題。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章