1. RTSP 协议基础:从一次真实推流失败说起
各位好,我是老周。做流媒体这行十几年了,RTSP 算是我最早接触的协议之一。记得刚入行那会儿,我负责一个安防项目,摄像头输出的 RTSP 流在 VLC 里播得好好的,换成我们自研的播放器就卡死。查了三天,最后发现是 RTSP 的 DESCRIBE 请求里少带了一个 Accept 头——服务器返回了 MPEG-TS 描述,而我们只解析了 SDP。嗯,从那以后我就养成了一个习惯:搞 RTSP 推流,先把协议交互流程刻在脑子里。
今天这一章,我们就从 RTSP 协议本身讲起。你可能会问:WebRTC 推流为什么要学 RTSP?说白了,RTSP 是控制信令,RTP 是数据载体,RTCP 是质量监控——这三兄弟配合好了,才能把摄像头、编码器的数据送到 WebRTC 的轨道里。下面我们一个一个拆开看。
1.1 RTSP 协议概述
RTSP(Real Time Streaming Protocol)是 IETF 在 RFC 2326 里定义的。它本质上是一个应用层控制协议,负责多媒体流的建立、播放、暂停、录制等操作。你可以把它想象成电视遥控器——按播放键、暂停键、快进键,但电视画面本身是通过其他通道传过来的。
核心要点:RTSP 不传输媒体数据,只传输控制命令。媒体数据走 RTP,控制走 RTSP,两者通过 Session ID 关联。
RTSP 的语法和 HTTP 很像,都是请求-响应模式,也支持类似 OPTIONS、DESCRIBE、SETUP、PLAY 这些方法。但有个关键区别:RTSP 是有状态的。服务器需要记住每个会话当前处于什么阶段——是刚建立、正在播放、还是暂停了。HTTP 是无状态的,每次请求都是独立的。
我个人习惯把 RTSP 的状态机画成一张图,方便调试时对照。下面这张 SVG 就是 RTSP 推流最核心的交互流程:
1.2 RTSP 与 RTP/RTCP 的关系
很多初学者会把 RTSP 和 RTP 搞混。我打个比方你就明白了:
- RTSP 是遥控器——负责按播放、暂停、停止
- RTP 是电视信号线——负责传输音视频数据
- RTCP 是信号质量监测仪——告诉你信号有没有丢包、延迟多少
这三者配合工作的典型场景是这样的:
- 客户端通过 RTSP 发送
SETUP请求,告诉服务器「我要用 UDP 端口 5000 和 5001 收数据」 - 服务器在端口 5000 上发送 RTP 包(音视频数据),在端口 5001 上发送 RTCP 包(质量报告)
- 客户端通过 RTCP 的 Sender Report (SR) 和 Receiver Report (RR) 计算丢包率、抖动、RTT
- 如果丢包率太高,客户端可以通过 RTSP 的
SET_PARAMETER请求调整编码参数
我的经验:在 WebRTC 推流场景中,RTSP 的 RTP 数据通常需要经过转码或重封装才能送入 WebRTC 的 PeerConnection。直接透传 RTP 包是不行的——WebRTC 有自己的 RTP 扩展头和 FEC 机制。我踩过这个坑,后来在中间加了一层 RTP 解包再组包才解决。
下面这张表总结了 RTSP、RTP、RTCP 的核心差异:
| 特性 | RTSP | RTP | RTCP |
|---|---|---|---|
| 功能 | 会话控制(播放/暂停/停止) | 媒体数据传输 | 质量监控与反馈 |
| 传输层 | TCP(默认)或 UDP | UDP(常用)或 TCP | UDP(与 RTP 同端口或 +1) |
| 可靠性 | 可靠(TCP 保证) | 不可靠(UDP 无重传) | 不可靠,但周期性发送 |
| 端口 | 554(默认) | 动态协商(通过 SETUP) | RTP 端口 + 1 |
| 关键字段 | CSeq, Session, Transport | SSRC, Sequence Number, Timestamp | SSRC, Fraction Lost, Cumulative Lost |
1.3 RTSP 消息格式与交互流程
RTSP 的消息格式和 HTTP 1.1 几乎一样。一个典型的 RTSP 请求长这样:
DESCRIBE rtsp://192.168.1.100:554/live/ch1 RTSP/1.0
CSeq: 2
Accept: application/sdp
User-Agent: MyRTSPClient/1.0
服务器响应:
RTSP/1.0 200 OK
CSeq: 2
Content-Type: application/sdp
Content-Length: 142
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=fmtp:96 packetization-mode=1;profile-level-id=42e01f;sprop-parameter-sets=Z0IACpY1QFAe2A==,aM4G4g==
这里有几个关键点:
- CSeq:序列号,请求和响应必须配对。我见过有人忘了递增 CSeq,结果服务器一直返回 400 Bad Request
- Session:会话 ID,在 SETUP 响应中返回,后续请求都要带上
- Transport:传输参数,包括协议(RTP/AVP)、传输方式(unicast/multicast)、端口号、interleaved 模式等
注意:RTSP 的 Transport 头字段非常容易出错。我曾经在 SETUP 请求里写错了端口范围,服务器返回了 461 Unsupported Transport。正确的格式应该是:Transport: RTP/AVP/UDP;unicast;client_port=5000-5001。注意端口是成对出现的——偶数给 RTP,奇数给 RTCP。
完整的 RTSP 交互流程,我习惯用「五步握手」来记忆:
- OPTIONS:客户端问服务器「你支持哪些方法?」服务器回复「我支持 DESCRIBE, SETUP, PLAY, TEARDOWN」
- DESCRIBE:客户端问「你的媒体流是什么格式?」服务器回复 SDP 描述(编码、分辨率、帧率等)
- SETUP:客户端说「我要在端口 5000-5001 收数据,请准备好」服务器回复 Session ID 和确认的端口
- PLAY:客户端说「开始推流!」服务器开始发送 RTP 数据
- TEARDOWN:客户端说「结束会话」服务器释放资源
你可能会问:为什么需要 OPTIONS 这一步?直接 DESCRIBE 不行吗?嗯,有些老旧摄像头只支持基本方法,不支持 PAUSE 或 RECORD。OPTIONS 可以让你提前知道服务器的能力,避免后续请求失败。我在对接海康和大华的摄像头时就发现,它们的 OPTIONS 响应里方法列表不一样——海康支持 GET_PARAMETER,大华不支持。
1.4 实际推流中的常见问题
最后分享几个我在 RTSP 推流中踩过的坑:
- UDP 端口被防火墙拦截:很多生产环境只开放了 554 端口(RTSP 控制),但 RTP 数据走的是随机高位端口。解决方案是用 RTSP over TCP(interleaved 模式),把 RTP 数据也封装在 TCP 连接里传输
- SDP 中的 sprop-parameter-sets 缺失:H.264 的 SPS/PPS 必须通过 SDP 传给客户端。如果服务器没带,客户端就无法解码。我遇到过摄像头固件 bug,SDP 里 sprop-parameter-sets 是空的,后来在 SETUP 之后手动发了一个
GET_PARAMETER才拿到 - RTCP 超时导致会话断开:有些服务器会监控 RTCP 报告,如果一段时间没收到就认为客户端挂了。我在做 WebRTC 转 RTSP 推流时,因为 WebRTC 的 RTCP 间隔和 RTSP 标准不一致,导致服务器频繁断开连接。后来在中间件里模拟了 RTCP 报告才解决
调试技巧:抓包是排查 RTSP 问题最有效的手段。我常用 Wireshark 的 rtsp 过滤器和 rtp 过滤器。重点关注 CSeq 是否连续、Transport 头是否正确、SDP 是否完整。另外,很多 RTSP 服务器会在响应里带 Server 头,比如 Server: Live555 Streaming Media v2023.01.19,这能帮你快速定位是哪个开源库。