RTSP协议
RTSP简述
RTSP协议是一个基于文本的多媒体播放控制协议,属于应用层。它主要用来控制具有实时特性的数据的发送,但其本身并不用于传送流媒体数据,而必须依赖下层传输协议(如RTP/RTCP)所提供的服务来完成流媒体数据的传送。RTSP负责定义具体的控制信息、操作方法、状态码,以及描述与RTP之间的交互操作。
RTSP的URL格式一般如下:
rtsp://host{:port}/{abs_path}/content_name
- host:有效的域名或IP地址;
- port:端口号,缺省为554,若为缺省可不填写,否则必须写明。
例如,一个完整的RTSP URL写为:
rtsp://192.168.1.55:554/test
RTSP报文
RTSP是一种基于文本的协议,用CRLF(回车换行)作为每一行的结束符(类似http协议),其好处是,在使用过程中可以方便地增加自定义仓鼠,也方便抓包分析。从消息传送方向上来分,RTSP的报文有两类:请求报文和响应报文。请求报文是指从客户端项服务器发送的请求,响应报文是指从服务器到客户端的回应。
RTSP请求报文的常用方法与作用:
方法 | 描述 |
---|---|
OPTIONS | 获得服务器支持的可用方法 |
DESCRIBE | 得到会话描述信息 |
SETUP | 客户端请求建立会话,并确立传输模式 |
TEARDOWN | 客户端发起关闭会话请求 |
PLAY | 客户端发起播放请求 |
一次基本的RTSP交互过程如下,C表示客户端,S表示服务端。
步骤 | 方向 | 信息 | 描述 |
---|---|---|---|
1 | C->S | OPTION request | Client询问Server有哪些方法可用 |
S->C | OPTION response | Server回应信息中包含所有可用的方法 | |
2 | C->S | DESCRIBE request | Client请求得到Server提供的媒体初始化描述信息 |
S->C | DESCRIBE response | Server回应媒体初始化信息,主要是SDP(会话描述协议) | |
3 | C->S | SETUP request | 设置会话属性以及传输模式,请求建立会话 |
S->C | SETUP response | Server建议会话,返回会话标识符以及会话相关信息 | |
4 | C->S | PLAY request | Client请求播放 |
S->C | PLAY response | Server回应播放请求信息 | |
5 | S->C | Media Data Transfer | 发送流媒体数据 |
6 | C->S | TEARDOWN request | Client请求关闭会话 |
S->C | TEARDOWN response | Server回应关闭会话请求 |
OPTIONS
示例代码如下:
static void Main(string[] args)
{
IPAddress iPAddress = IPAddress.Parse("172.20.124.156");
IPEndPoint iPEndPoint = new IPEndPoint(iPAddress, 554);
TcpClient tcpClient = new TcpClient();
tcpClient.Connect(iPEndPoint);
Thread thread = new Thread(Recv)
{
IsBackground = true,
};
thread.Start(tcpClient);
const string CRLF = "
";
string options = "OPTIONS rtsp://172.20.124.156:554/Stream RTSP/1.0" + CRLF;
options += "CSeq: 1" + CRLF;
options += CRLF;//切记这个一定要多发送一个CRLF,否则服务器一直等待这个结束符,而不返回信息
byte[] bys = Encoding.UTF8.GetBytes(options);
tcpClient.GetStream().Write(bys, 0, bys.Length);
Console.ReadKey();
}
/// <summary>
/// 接收
/// </summary>
/// <param name="sender"></param>
private static void Recv(object sender)
{
TcpClient tcpClient = sender as TcpClient;
NetworkStream networkStream = tcpClient.GetStream();
StreamReader streamReader = new StreamReader(networkStream);
while(tcpClient.Connected)
{
string line = streamReader.ReadLine();
if(line == null)
{
break;
}
Console.WriteLine(line);
}
Console.WriteLine("连接断开了!");
}
服务端返回示例信息:
RTSP/1.0 200 OK
CSeq: 1
Session: pcNoizrGg
Public: DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE, OPTIONS, ANNOUNCE, RECORD
DESCRIBE
客户端向服务器请求媒体资源描述,服务器端通过SDP格式回应客户端的请求。资源描述中会列出所有请求媒体的媒体流及其相关信息,示例代码如下:
static void Main(string[] args)
{
IPAddress iPAddress = IPAddress.Parse("172.20.124.156");
IPEndPoint iPEndPoint = new IPEndPoint(iPAddress, 554);
TcpClient tcpClient = new TcpClient();
tcpClient.Connect(iPEndPoint);
Thread thread = new Thread(Recv)
{
IsBackground = true,
};
thread.Start(tcpClient);
const string CRLF = "
";
string options = "OPTIONS rtsp://172.20.124.156:554/Stream RTSP/1.0" + CRLF;
options += "CSeq: 1" + CRLF;
options += CRLF;//切记这个一定要多发送一个CRLF,否则服务器一直等待这个结束符,而不返回信息
byte[] bys = Encoding.UTF8.GetBytes(options);
tcpClient.GetStream().Write(bys, 0, bys.Length);
Thread.Sleep(1000);
//请求媒体资源描述
string describe = "DESCRIBE rtsp://172.20.124.156:554/Stream RTSP/1.0" + CRLF;
describe += "CSeq: 2" + CRLF;
describe += CRLF;
bys = Encoding.UTF8.GetBytes(describe);
tcpClient.GetStream().Write(bys, 0, bys.Length);
Console.ReadKey();
}
/// <summary>
/// 接收
/// </summary>
/// <param name="sender"></param>
private static void Recv(object sender)
{
TcpClient tcpClient = sender as TcpClient;
NetworkStream networkStream = tcpClient.GetStream();
StreamReader streamReader = new StreamReader(networkStream);
while(tcpClient.Connected)
{
string line = streamReader.ReadLine();
if(line == null)
{
break;
}
Console.WriteLine(line);
}
Console.WriteLine("连接断开了!");
}
服务器响应信息如下:
RTSP/1.0 200 OK
CSeq: 1
Session: pqFLiz9Mg
Public: DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE, OPTIONS, ANNOUNCE, RECORD
RTSP/1.0 200 OK
Session: pqFLiz9Mg
Content-Length: 380
CSeq: 2
v=0
o=- 0 0 IN IP4 127.0.0.1
s=EasyDarwin
i=EasyDarwin
c=IN IP4 127.0.0.1
t=0 0
a=x-qt-text-nam:EasyDarwin
a=x-qt-text-inf:EasyDarwin
a=x-qt-text-cmt:source application::EasyDarwin
a=x-qt-text-aut:
a=x-qt-text-cpy:
m=video 0 RTP/AVP 96
a=rtpmap:96 H264/90000
a=fmtp:96 packetization-mode=1;sprop-parameter-sets=,2QAH6y0AoAt0IAAAAMAgAAAHkeMGVA=
a=control:streamid=0
SETUP
SETUP请求确定了具体的媒体流如何传输,该请求必须在PLAY请求之前发送。SETUP请求包含媒体流的URL和客户端用于接收RTP数据(audio or video)的端口以及接收RTCP数据(meta information)的端口。服务器端的回复通常包含客户端请求参数的确认,并会补充缺失的部分,比如服务器选择的发送端口。每一个媒体流在发送PLAY请求之前,都要首先通过SETUP请求来进行相应的配置。
示例代码如下:
static void Main(string[] args)
{
IPAddress iPAddress = IPAddress.Parse("172.20.124.156");
IPEndPoint iPEndPoint = new IPEndPoint(iPAddress, 554);
TcpClient tcpClient = new TcpClient();
tcpClient.Connect(iPEndPoint);
Thread thread = new Thread(Recv)
{
IsBackground = true,
};
thread.Start(tcpClient);
const string CRLF = "
";
string options = "OPTIONS rtsp://172.20.124.156:554/Stream RTSP/1.0" + CRLF;
options += "CSeq: 1" + CRLF;
options += CRLF;//切记这个一定要多发送一个CRLF,否则服务器一直等待这个结束符,而不返回信息
byte[] bys = Encoding.UTF8.GetBytes(options);
tcpClient.GetStream().Write(bys, 0, bys.Length);
Thread.Sleep(1000);
//请求媒体资源描述
string describe = "DESCRIBE rtsp://172.20.124.156:554/Stream RTSP/1.0" + CRLF;
describe += "CSeq: 2" + CRLF;
describe += CRLF;
bys = Encoding.UTF8.GetBytes(describe);
tcpClient.GetStream().Write(bys, 0, bys.Length);
Thread.Sleep(1000);
//SETUP
string setup = "SETUP rtsp://172.20.124.156:554/Stream RTSP/1.0" + CRLF;
setup += "CSeq: 3" + CRLF;
setup += "Transport: RTP/AVP;unicast;client__port=8000-9000" + CRLF;
setup += CRLF;
bys = Encoding.UTF8.GetBytes(setup);
tcpClient.GetStream().Write(bys, 0, bys.Length);
Console.ReadKey();
}
/// <summary>
/// 接收
/// </summary>
/// <param name="sender"></param>
private static void Recv(object sender)
{
TcpClient tcpClient = sender as TcpClient;
NetworkStream networkStream = tcpClient.GetStream();
StreamReader streamReader = new StreamReader(networkStream);
while(tcpClient.Connected)
{
string line = streamReader.ReadLine();
if(line == null)
{
break;
}
Console.WriteLine(line);
}
Console.WriteLine("连接断开了!");
}
服务器返回信息:
RTSP/1.0 200 OK
CSeq: 1
Session: 9R52ZzrGg
Public: DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE, OPTIONS, ANNOUNCE, RECORD
RTSP/1.0 200 OK
Content-Length: 380
CSeq: 2
Session: 9R52ZzrGg
v=0
o=- 0 0 IN IP4 127.0.0.1
s=EasyDarwin
i=EasyDarwin
c=IN IP4 127.0.0.1
t=0 0
a=x-qt-text-nam:EasyDarwin
a=x-qt-text-inf:EasyDarwin
a=x-qt-text-cmt:source application::EasyDarwin
a=x-qt-text-aut:
a=x-qt-text-cpy:
m=video 0 RTP/AVP 96
a=rtpmap:96 H264/90000
a=fmtp:96 packetization-mode=1;sprop-parameter-sets=,2QAH6y0AoAt0IAAAAMAgAAAHkeMGVA=
a=control:streamid=0
RTSP/1.0 200 OK
CSeq: 3
Session: 9R52ZzrGg
Transport: RTP/AVP;unicast;client__port=8000-9000
PLAY
客户端通过PLAY请求来播放一个或全部媒体流,PLAY请求可以发送一次或多次,发送一次时,URL为包含所有媒体流的地址,发送多次时,每一次请求携带的URL只包含一个响应的媒体流。PLAY请求中可指定播放的range,若未指定,则从媒体流的开始播放到结束,如果媒体流在播放过程中被暂停,则可在暂停处重新启动流的播放。
播放示例代码为:
string play = "PLAY rtsp://172.20.124.156:554/Stream RTSP/1.0" + CRLF;
play += "CSeq: 4" + CRLF;
play += CRLF;
PAUSE
PAUSE请求会暂停一个或所有媒体流,后续可通过PLAY请求恢复播放。PAUSE请求中携带所请求媒体流的URL,若参数range存在,则指明在何处暂停,若该参数不存在,则暂停立即生效,切暂停时长不确定。
暂停示例代码:
string pause = "PAUSE rtsp://172.20.124.156:554/Stream RTSP/1.0" + CRLF;
pause += "CSeq: 5" + CRLF;
pause += $"Session: {session}" + CRLF;
pause += CRLF;
TEARDOWN
结束会话请求,该请求会停止所有媒体流,并释放服务器上的相关会话数据。
string teardown = "TEARDOWN rtsp://172.20.124.156:554/Stream RTSP/1.0" + CRLF;
teardown += "CSeq: 8" + CRLF;
teardown += $"Session: {session}" + CRLF;
teardown += CRLF;