RTSP 协议基础:语法结构、请求方法与状态码
RTSP 这个协议,说白了就是视频流的遥控器。你想想看,我们平时看视频,要点播放、暂停、拖动进度条——RTSP 干的就是类似的事,只不过它控制的是网络上的实时流媒体。
我记得刚接触 RTSP 时,总觉得它跟 HTTP 长得太像了。确实,它们都用文本格式,都有请求行和头部字段。但本质区别在哪?HTTP 是「请求-响应」一次完事,RTSP 是「建立会话-持续控制」——它维护着一个状态机。这一点,很多新手会栽跟头。
2.1 RTSP 的语法结构
RTSP 的报文分两种:请求和响应。结构非常清晰,我拆开来说。
请求报文
方法 URI RTSP版本
头部字段1: 值
头部字段2: 值
...
空行
消息体(可选)
举个例子,一个典型的 SETUP 请求长这样:
SETUP rtsp://example.com/media.mp4/track1 RTSP/1.0
CSeq: 3
Transport: RTP/AVP;unicast;client_port=8000-8001
这里有个关键点:CSeq 字段。每个请求都必须带一个序列号,服务器响应时会把同样的 CSeq 带回来。这样客户端就能把请求和响应一一对应上。我在项目中遇到过有人忘了递增 CSeq,结果服务器一直返回 400——排查了半天才发现是序列号没变。
响应报文
RTSP版本 状态码 原因短语
头部字段1: 值
头部字段2: 值
...
空行
消息体(可选)
比如:
RTSP/1.0 200 OK
CSeq: 3
Session: 12345678
Transport: RTP/AVP;unicast;client_port=8000-8001;server_port=9000-9001
注意那个 Session 字段。服务器会在 SETUP 响应里分配一个会话 ID,后续所有操作都得带上它。嗯,这个 ID 就是整个推流会话的「身份证」。
核心要点:RTSP 报文是文本格式,每行以 CRLF(\r\n)结尾。空行是头部和消息体的分界线,不能省略。
2.2 五大核心请求方法
RTSP 定义了十几种方法,但实际推流场景中,90% 的交互靠下面这五个方法完成。我按调用顺序给你捋一遍。
| 方法 | 作用 | 调用时机 |
|---|---|---|
| OPTIONS | 查询服务器支持哪些方法 | 第一步,握手 |
| DESCRIBE | 获取媒体描述信息(SDP) | 第二步,了解媒体 |
| SETUP | 建立传输通道,协商参数 | 第三步,准备传输 |
| PLAY | 开始播放/推流 | 第四步,开始传输 |
| PAUSE | 暂停播放/推流 | 播放中,临时暂停 |
| TEARDOWN | 终止会话,释放资源 | 最后一步,清理 |
OPTIONS — 先打个招呼
客户端发 OPTIONS,服务器回复它支持哪些方法。这步不是必须的,但我建议你加上。为什么?因为不同服务器实现有差异,有的不支持 PAUSE,有的不支持 GET_PARAMETER。提前摸清底细,后面少踩坑。
C -> S: OPTIONS rtsp://example.com/media.mp4 RTSP/1.0
CSeq: 1
S -> C: RTSP/1.0 200 OK
CSeq: 1
Public: OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE
你看,服务器在 Public 字段里列了它支持的方法。如果它没列 PAUSE,你就别发 PAUSE 了。
DESCRIBE — 看看媒体长什么样
DESCRIBE 用来获取媒体描述信息,服务器通常返回 SDP(Session Description Protocol)。SDP 里包含了视频编码格式、分辨率、帧率、音频采样率、RTP 负载类型等关键信息。
C -> S: DESCRIBE rtsp://example.com/media.mp4 RTSP/1.0
CSeq: 2
Accept: application/sdp
S -> C: RTSP/1.0 200 OK
CSeq: 2
Content-Type: application/sdp
Content-Length: 142
v=0
o=- 123456 789012 IN IP4 192.168.1.1
s=Media Presentation
m=video 0 RTP/AVP 96
a=rtpmap:96 H264/90000
a=framerate:30
m=audio 0 RTP/AVP 97
a=rtpmap:97 MPEG4-GENERIC/16000/2
这里要注意:Accept: application/sdp 告诉服务器我要 SDP 格式。有些服务器也支持其他格式,但 SDP 是事实标准。
我的经验:DESCRIBE 返回的 SDP 里,m= 行定义了媒体轨道。一个视频文件可能有多个轨道(视频、音频、字幕),每个轨道需要单独 SETUP。我曾经遇到过一个流有 3 个音频轨道,只 SETUP 了第一个,结果播放器没声音——排查了半天才发现少 SETUP 了一个轨道。
SETUP — 搭桥铺路
SETUP 是 RTSP 里最复杂的方法。它要协商传输协议、端口号、组播还是单播、RTP 还是 RTCP。这一步搞不定,后面全白搭。
C -> S: SETUP rtsp://example.com/media.mp4/track1 RTSP/1.0
CSeq: 3
Transport: RTP/AVP;unicast;client_port=8000-8001
Transport 字段的格式:
- 传输协议:RTP/AVP(标准 RTP)、RTP/AVP/TCP(RTP over TCP)、RTP/AVP/UDP(RTP over UDP)
- 传输模式:unicast(单播)、multicast(组播)
- 端口:client_port 是客户端 RTP/RTCP 端口,server_port 是服务器端口
服务器响应时会确认或修改传输参数:
S -> C: RTSP/1.0 200 OK
CSeq: 3
Session: 12345678
Transport: RTP/AVP;unicast;client_port=8000-8001;server_port=9000-9001
注意这里多了 Session: 12345678。这个会话 ID 后续所有请求都得带上。
避坑指南:我曾经在项目中遇到一个问题——客户端发了 SETUP,服务器也返回了 200 OK,但 RTP 数据就是收不到。后来发现是 NAT 没做端口映射。如果你在内网环境测试没问题,部署到公网就出问题,先检查防火墙和 NAT 配置。
PLAY — 开闸放流
SETUP 成功后,发 PLAY 开始传输数据。可以指定播放范围:
C -> S: PLAY rtsp://example.com/media.mp4 RTSP/1.0
CSeq: 4
Session: 12345678
Range: npt=0.000-
Range: npt=0.000- 表示从开头播到结束。NPT 是 Normal Play Time,单位是秒。你也可以指定时间段,比如 npt=10.0-20.0。
服务器响应:
S -> C: RTSP/1.0 200 OK
CSeq: 4
Session: 12345678
RTP-Info: url=rtsp://example.com/media.mp4/track1;seq=0;rtptime=0
RTP-Info 字段告诉客户端:RTP 序列号从 0 开始,时间戳从 0 开始。客户端拿到这个信息,才能正确解码 RTP 包。
PAUSE — 暂停一下
PAUSE 很简单,就是暂停播放。服务器会停止发送 RTP 数据,但保持会话:
C -> S: PAUSE rtsp://example.com/media.mp4 RTSP/1.0
CSeq: 5
Session: 12345678
恢复播放时再发一次 PLAY 就行。注意:PAUSE 不是所有服务器都支持,OPTIONS 阶段可以确认。
TEARDOWN — 好聚好散
推流结束,发 TEARDOWN 释放资源。服务器会关闭 RTP 会话,回收端口和内存:
C -> S: TEARDOWN rtsp://example.com/media.mp4 RTSP/1.0
CSeq: 6
Session: 12345678
响应:
S -> C: RTSP/1.0 200 OK
CSeq: 6
Session: 12345678
之后这个会话 ID 就失效了。如果你忘了发 TEARDOWN,服务器可能会一直占用资源——我见过有人写测试脚本,每次跑完都不发 TEARDOWN,结果服务器上挂了上百个僵尸会话。
2.3 状态码详解
RTSP 的状态码和 HTTP 基本一致,但有几个是 RTSP 特有的。我列了最常用的几个:
| 状态码 | 含义 | 常见场景 |
|---|---|---|
| 200 OK | 请求成功 | 一切正常 |
| 301 Moved Permanently | 资源永久重定向 | 服务器迁移,客户端需更新 URL |
| 302 Moved Temporarily | 资源临时重定向 | 负载均衡,客户端重试新地址 |
| 400 Bad Request | 请求语法错误 | CSeq 重复、头部格式不对 |
| 401 Unauthorized | 需要认证 | 服务器要求用户名密码 |
| 403 Forbidden | 禁止访问 | 权限不足 |
| 404 Not Found | 资源不存在 | URL 写错了 |
| 405 Method Not Allowed | 方法不被支持 | 服务器不支持 PAUSE |
| 454 Session Not Found | 会话 ID 无效 | 会话已过期或从未建立 |
| 455 Method Not Valid in This State | 当前状态不允许此方法 | 还没 SETUP 就发 PLAY |
| 500 Internal Server Error | 服务器内部错误 | 服务器崩了 |
| 551 Option not supported | 请求中的选项不支持 | Transport 参数服务器不认 |
这里有两个 RTSP 特有的状态码,我重点说一下:
- 454 Session Not Found:你发了 PLAY,但服务器说「我不认识这个会话」。原因通常是会话超时了,或者你忘了在请求里带 Session 字段。
- 455 Method Not Valid in This State:这是 RTSP 状态机在保护你。比如你还没 SETUP 就发 PLAY,服务器会直接拒绝。顺序搞错了。
记住这个顺序:OPTIONS → DESCRIBE → SETUP → PLAY → PAUSE(可选)→ TEARDOWN。跳步就会收到 455。
2.4 RTSP 状态机与交互流程
RTSP 维护着一个状态机。客户端和服务器各自跟踪当前状态,只有合法的方法才能被接受。我画了一张图,把整个流程串起来:
从图里能看出来,状态转换是有严格顺序的:
- Init → Ready:通过 SETUP 建立传输通道
- Ready → Playing:通过 PLAY 开始传输
- Playing → Ready:通过 PAUSE 暂停
- Ready → Init:通过 TEARDOWN 终止
如果你在 Playing 状态直接发 SETUP,服务器会返回 455。嗯,这就是状态机在保护你。
我的建议:写客户端代码时,最好维护一个状态变量。每次发请求前检查当前状态是否合法。我见过太多人忽略这一步,结果线上出了各种诡异的 455 错误。
2.5 常见问题与排查思路
最后,我总结几个实际项目中经常遇到的问题:
- 401 Unauthorized:服务器要求认证。RTSP 支持 Basic 和 Digest 两种认证方式,和 HTTP 一样。记得在请求头里加
Authorization字段。 - 454 Session Not Found:会话超时或 ID 错误。检查请求里有没有带
Session字段,以及会话是否还在有效期内。 - Transport 协商失败:客户端说我要 UDP,服务器说我只支持 TCP。这时候要么客户端改用 TCP,要么服务器开启 UDP 支持。我建议优先用 TCP,穿透性好,不容易被防火墙拦截。
- RTP 数据收不到:SETUP 和 PLAY 都返回 200 OK,但就是没数据。先检查端口对不对,再检查防火墙。用 Wireshark 抓包是最直接的排查方式。
避坑指南:我曾经在项目中遇到一个诡异的问题——客户端发 PLAY 后,服务器返回 200 OK,但 RTP 数据延迟了 5 秒才到。后来发现是服务器端做了缓冲,Range 字段没指定起始时间,服务器从文件头开始读,而文件头有大量元数据。加上 Range: npt=0.000- 后问题解决。