3. RTSP协议详解:DESCRIBE/SETUP/PLAY、SDP解析与RTP/RTCP传输
各位同学,今天我们来啃一块硬骨头——RTSP协议。说实话,我刚入行那会儿,觉得RTSP就是个「遥控器」,无非就是播放、暂停、停止。直到我在一个海量摄像头接入的项目里被狠狠坑了一把,才真正意识到:不懂RTSP细节,你连摄像头画面都拉不出来。
RTSP全称是Real Time Streaming Protocol,实时流传输协议。它本身不传视频数据,只负责「控制」。你想想看,就像你看电视,遥控器负责换台、调音量,但真正播放画面的是电视机本身。RTSP就是那个遥控器,而RTP才是那个电视机。
3.1 RTSP请求方法:DESCRIBE / SETUP / PLAY
一个标准的RTSP会话,通常走三步:先问清楚对方有什么(DESCRIBE),再商量怎么传(SETUP),最后喊开始(PLAY)。我习惯把这叫做「三握手」,虽然它和TCP的三次握手不是一回事。
3.1.1 DESCRIBE —— 先问问摄像头支持什么
DESCRIBE请求,说白了就是客户端对摄像头说:「嘿,你有什么格式?报上来。」摄像头会返回一个SDP描述,里面包含了视频编码、分辨率、帧率等信息。
C->S: DESCRIBE rtsp://192.168.1.100:554/stream1 RTSP/1.0
CSeq: 1
Accept: application/sdp
S->C: RTSP/1.0 200 OK
CSeq: 1
Content-Type: application/sdp
Content-Length: 123
v=0
o=- 1234567890 1234567890 IN IP4 192.168.1.100
s=Live Stream
m=video 0 RTP/AVP 96
a=rtpmap:96 H264/90000
a=framerate:25
这里有个坑,我曾经遇到过:有些老摄像头返回的SDP里,rtpmap的编码名称写的是大写「H264」,而有些写的是小写「h264」。如果你用字符串硬匹配,就会匹配不上。我建议解析时统一转成大写再比较。
Accept: application/sdp 头,否则有些摄像头会返回415 Unsupported Media Type。我当年调试了整整一个下午才发现是少了这个头。
3.1.2 SETUP —— 商量传输通道
拿到SDP之后,下一步就是SETUP。这一步要确定两件事:用什么传输协议(UDP还是TCP),以及用什么端口。我个人习惯用TCP传输RTP,因为UDP在公网环境下容易丢包,而且很多防火墙会拦UDP。
C->S: SETUP rtsp://192.168.1.100:554/stream1/track1 RTSP/1.0
CSeq: 2
Transport: RTP/AVP/TCP;unicast;interleaved=0-1
S->C: RTSP/1.0 200 OK
CSeq: 2
Transport: RTP/AVP/TCP;unicast;interleaved=0-1;ssrc=12345678
Session: 87654321
注意这里的 interleaved=0-1,0表示RTP通道,1表示RTCP通道。这个数字是成对出现的,不能乱写。我记得有一次写代码时把interleaved写成了0-2,结果RTCP数据一直收不到,排查了半天才发现是通道号不连续。
3.1.3 PLAY —— 开始拉流
SETUP成功后,服务器会返回一个Session ID。接下来用这个Session ID发PLAY请求,摄像头就开始推流了。
C->S: PLAY rtsp://192.168.1.100:554/stream1 RTSP/1.0
CSeq: 3
Session: 87654321
Range: npt=0.000-
S->C: RTSP/1.0 200 OK
CSeq: 3
Session: 87654321
RTP-Info: url=rtsp://192.168.1.100:554/stream1/track1;seq=12345;rtptime=987654321
这里 Range: npt=0.000- 表示从开头开始播放。如果是直播流,其实写不写都行。但如果是录像回放,这个参数就很重要了。
3.2 SDP协议解析
SDP全称Session Description Protocol,会话描述协议。它不负责传输,只负责「描述」。就像你去餐厅吃饭,菜单上写着菜名和价格,但厨师怎么做是另一回事。SDP就是那个菜单。
SDP的格式是key=value,每行一个字段。常用的字段有:
| 字段 | 含义 | 示例 |
|---|---|---|
| v= | 协议版本 | v=0 |
| o= | 会话发起者 | o=- 1234567890 1234567890 IN IP4 192.168.1.100 |
| s= | 会话名称 | s=Live Stream |
| m= | 媒体描述 | m=video 0 RTP/AVP 96 |
| a= | 属性行 | a=rtpmap:96 H264/90000 |
解析SDP时,最核心的是 m= 和 a= 行。m= 告诉你有几个媒体流(视频、音频),a= 告诉你每个流的具体参数。我一般会这样解析:
def parse_sdp(sdp_str):
media_info = {}
current_media = None
for line in sdp_str.split('\n'):
line = line.strip()
if not line:
continue
if line.startswith('m='):
# 解析媒体行
parts = line[2:].split()
current_media = {
'type': parts[0], # video 或 audio
'port': int(parts[1]),
'protocol': parts[2],
'payload_type': int(parts[3])
}
media_info[current_media['type']] = current_media
elif line.startswith('a=') and current_media:
# 解析属性行
key_value = line[2:].split(':', 1)
if key_value[0] == 'rtpmap':
# rtpmap:96 H264/90000
payload, codec = key_value[1].split(' ', 1)
codec_name, clock_rate = codec.split('/')
current_media['codec'] = codec_name.upper()
current_media['clock_rate'] = int(clock_rate)
return media_info
3.3 RTP/RTCP传输机制
好了,现在RTSP已经协商好了,SDP也解析完了,接下来就是真正的数据传输环节——RTP和RTCP。
3.3.1 RTP —— 真正的视频数据
RTP全称Real-time Transport Protocol,实时传输协议。它负责把视频帧切成一个个小包,加上时间戳和序列号,然后发出去。接收端根据这些信息重组画面。
RTP包的结构是这样的:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|V=2|P|X| CC |M| PT | sequence number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| timestamp |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| synchronization source (SSRC) identifier |
+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
| contributing source (CSRC) identifiers |
| .... |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
这里有几个关键字段:
- sequence number:序列号,每发一个包加1。用来检测丢包和排序。
- timestamp:时间戳,单位是时钟频率的倒数(比如H264是90000Hz)。用来同步播放。
- SSRC:同步源标识,每个流唯一。同一个摄像头的视频和音频SSRC不同。
我在项目中遇到过一个问题:有些摄像头的时间戳会溢出回绕。比如从0xFFFFFFFF突然变成0x00000000。如果你不做处理,播放器会以为时间倒流了。我建议用相对时间戳,或者检测到回绕时加一个偏移量。
3.3.2 RTCP —— 反馈和控制
RTCP全称RTP Control Protocol,RTP控制协议。它不传视频数据,只传「报告」。比如丢包率、延迟、抖动等。说白了就是接收端告诉发送端:「你发的包我收到了多少,丢了多少。」
RTCP有几种类型:
- SR(Sender Report):发送端报告,包含发送的包数和字节数。
- RR(Receiver Report):接收端报告,包含丢包率、延迟等信息。
- SDES(Source Description):源描述,包含CNAME等信息。
- BYE:结束会话。
RTCP的发送频率有讲究。RFC规定RTCP的带宽不能超过总带宽的5%。也就是说,如果你在传10Mbps的视频,RTCP最多只能占500Kbps。我一般会设置RTCP的发送间隔为5秒一次,既不会太频繁占用带宽,又能及时反馈网络状况。
3.4 总结一下
RTSP、SDP、RTP/RTCP这三者配合起来,就是一个完整的视频流传输体系:
- RTSP负责「控制」—— 协商参数、开始播放、停止播放。
- SDP负责「描述」—— 告诉对方视频是什么格式。
- RTP负责「传输」—— 把视频数据切成包发出去。
- RTCP负责「反馈」—— 报告网络质量,帮助调整传输策略。
嗯,这一章内容不少,但都是实战中必须掌握的基础。下一章我们会讲如何用代码实现一个RTSP客户端,到时候这些理论知识就会变成实实在在的代码了。