RTSP

0 阅读14分钟

RTSP 全称 Real Time Streaming Protocol(实时流传输协议) ,是由 IETF 制定的应用层网络协议,标准文档 RFC2326(后续有 RTSP 2.0 RFC7826),默认传输端口为 554(TCP/UDP 均支持,主流用 TCP)。

RTSP vs RTP vs RTCP

  • RTSP:「指挥官」—— 只发控制指令,比如客户端向摄像头 / 流媒体服务器发送 PLAY(播放)PAUSE(暂停)TEARDOWN(断开) 指令,服务器响应指令;不碰任何音视频裸数据。
  • RTP:「快递员」—— 真正负责传输音视频媒体数据的协议(H264/H265 视频帧、AAC/G711 音频帧);追求实时性优先,不保证传输可靠性,主流基于 UDP 传输(也可基于 TCP),是流媒体数据的核心载体。
  • RTCP:「监工 + 反馈员」—— RTP 的「配套控制协议」,和 RTP 成对使用;不传输媒体数据,只做两件事:① 监控 RTP 传输的质量(丢包率、时延、抖动);② 向发送端反馈传输状态,用于同步音视频、调整码率;③ 管理会话成员。

核心 6 大基础方法(按使用频率排序,必须熟记)

1. OPTIONS - 能力协商(会话第一步,必执行)

  • 作用:客户端向服务端查询「服务端支持哪些 RTSP 方法」(比如是否支持 PLAY、PAUSE、SETUP 等),是建立 RTSP 会话的第一个请求
  • 特点:无副作用,服务端响应后会返回支持的所有方法列表,比如 Public: OPTIONS, DESCRIBE, SETUP, PLAY, PAUSE, TEARDOWN

2. DESCRIBE - 获取媒体流的详细描述信息(核心前置)

  • 作用:客户端向服务端请求「音视频流的元数据信息」,服务端会返回一个 SDP 格式 的文本数据(下文重点讲 SDP);
  • 核心价值:SDP 数据里包含了音视频的核心参数—— 视频编码格式(H264/H265)、音频编码格式(AAC/G711)、分辨率、码率、RTP 传输的端口号、采样率等,没有 SDP,客户端就无法解码播放 RTP 传输的媒体流

3. SETUP - 建立媒体流传输通道(最关键的步骤)

  • 作用:客户端基于 DESCRIBE 获取的 SDP 信息,与服务端协商媒体流的传输方式,是 RTSP 会话的核心步骤;
  • 协商核心内容:✔ 确定传输协议:主流是 RTP/UDP(实时性最优),也可选 RTP/TCP(穿透防火墙能力强,可靠传输);✔ 协商传输端口:客户端会指定 RTP 的传输端口,服务端确认后,后续的音视频数据就通过这个端口传输;✔ 绑定会话 ID:服务端返回一个 Session ID,后续所有指令都需要携带这个 ID,服务端以此识别客户端的会话状态;
  • 核心:SETUP 执行成功,意味着「RTP 媒体流的传输通道已打通」,只差最后一步播放指令。

4. PLAY - 开始播放媒体流(核心播放指令)

  • 作用:客户端向服务端发送「播放指令」,服务端收到后,立即通过已协商好的 RTP 通道,向客户端推送音视频数据;
  • 扩展能力:支持指定播放范围,比如 PLAY rtsp://xxx/stream RTSP/1.0\r\nRange: npt=0.000-\r\n(从 0 秒开始播放到结束),也支持快进(指定起始时间)。
  • 关键:PLAY 执行后,客户端开始接收 RTP 数据包,解码后即可看到实时音视频画面。

5. PAUSE - 暂停播放媒体流

  • 作用:客户端向服务端发送「暂停指令」,服务端收到后,立即停止推送 RTP 媒体流,但 RTSP 的控制连接和 Session 会话不会断开;
  • 特点:暂停后,客户端发送 PLAY 指令可无缝继续播放,服务端会从暂停的时间点继续推送数据,这就是「有状态」的体现。

6. TEARDOWN - 销毁会话,断开连接(收尾指令)

  • 作用:客户端向服务端发送「断开指令」,服务端收到后,执行三件事:① 停止推送 RTP 媒体流;② 销毁当前的 Session 会话;③ 关闭 RTSP 控制连接和 RTP 传输通道;
  • 特点:执行后,客户端若要重新播放,必须重新走一遍完整的 RTSP 流程(OPTIONS→DESCRIBE→SETUP→PLAY),因为会话状态已清空。

通用报文格式

所有 RTSP 请求 / 响应报文(包括 OPTIONS、DESCRIBE、SETUP、PLAY 等)都遵循这个统一、强制的格式,这是 RFC2326 标准规定的,格式错误直接导致服务端返回 400 Bad Request 错误

通用规则(所有 RTSP 报文都满足)

  1. RTSP 是 明文文本协议,所有报文都是 ASCII 字符组成,可读性极强;
  2. 报文没有请求体 / 响应体,只有「行头信息」+「结束空行」,这是和 HTTP 最大的区别之一(HTTP 可以有 Body);
  3. 每行的结束符 必须是 \r\n (回车 + 换行)不能只用 \n,这是 99% 开发者踩的第一个坑;
  4. 整个报文的 结束标志是「连续两个 \r\n(即空行),服务端读到 \r\n\r\n 才认为报文接收完成。

请求报文(客户端 -> 服务器)

请求行  \r\n  
消息头1 \r\n  
消息头2 \r\n  
...     \r\n  
(可选消息头)  
\r\n  <--- 必须的结束空行,无任何字符
1.「请求行」- 第一行,强制必填,固定格式
    1. OPTIONS [RTSP目标URL] RTSP/1.0 \r\n
  • OPTIONS :RTSP 方法名,大写(RTSP 所有方法名必须大写,小写无效);
  • [RTSP目标URL] :要访问的流媒体完整地址,如 rtsp://192.168.1.100:554/stream1rtsp://admin:123456@192.168.1.200/onvif1
  • RTSP/1.0 :RTSP 协议版本号,主流固定为 RTSP/1.0(RTSP2.0 兼容,但 99% 的设备 / 服务器只支持 1.0);
  • 结尾必须跟 \r\n,不能省略。
2. [消息头」- 核心必选头域(2 个,缺一不可)

RTSP OPTIONS 请求报文,最少只需要 2 个核心头域,就能被服务端正确识别并响应,这是最简可用版,也是开发中最常用的版本,优先级最高:

✔ 必选头 1:CSeq: [数字]

全称:Command Sequence,指令序列号,RTSP 协议的核心必选头域,没有例外!

  • 作用:服务端通过这个序列号,将「请求」和「响应」一一对应;
  • 规则:从 1 开始,客户端发起的每一个 RTSP 请求(OPTIONS→DESCRIBE→SETUP→PLAY...),这个数字必须严格自增 1
  • 示例:CSeq: 1 (OPTIONS 是第一个请求,所以固定填 1,DESCRIBE 就填 2,SETUP 填 3,以此类推);
  • 格式:冒号后必须跟一个空格,再写数字,结尾 \r\n
✔ 必选头 2:User-Agent: [客户端标识]

客户端身份标识,RTSP 协议强制要求,无此头域部分服务端会拒绝响应。

  • 作用:告诉服务端,当前发起请求的是什么客户端(播放器 / 程序 / 设备);
  • 规则:内容可自定义,无严格规范,开发中写通用值即可;
  • 推荐值(开发首选):
    • 通用:User-Agent: Lavf/58.20.100 (FFmpeg 的标识,兼容性最好,所有设备都识别)
    • 自定义:User-Agent: MyRTSPPlayer/1.0
  • 格式:冒号后空格,结尾 \r\n
3. 「消息头」- 可选扩展头域(按需添加,非必须)

以下头域是可选的,只有在特定场景下需要添加,最简版 OPTIONS 完全不需要,新手可以暂时忽略,后续开发用到再补即可:

  • Authorization: [认证信息] :当服务端开启账号密码认证时添加(比如摄像头的 admin/123456),用于携带加密的账号密码;
  • Session: [会话ID] :只有在已经建立 Session 后的 OPTIONS 请求才需要(比如播放中再次查询能力),首次 OPTIONS 无 Session,不填;
  • Accept: application/sdp :告诉服务端,客户端支持接收 SDP 格式的响应(其实 OPTIONS 无响应体,填了也不影响)。

SDP 协议

SDP 全称 Session Description Protocol(会话描述协议)不是传输协议,也不是控制协议,只是一种「标准化的文本格式」,用于描述音视频会话的元数据信息。

SDP 与 RTSP 的强绑定关系

RTSP 的 DESCRIBE 方法的唯一返回内容就是 SDP 文本,SDP 是 RTSP 的「媒体流说明书」—— 客户端只有读懂了这份说明书,才知道如何解码 RTP 传输的音视频数据。

SDP 核心作用

SDP 文本中包含了客户端播放流媒体必须的所有信息,核心内容包括:

  1. 会话基本信息:会话名称、创建时间、会话时长;
  2. 网络信息:传输地址(IP)、传输协议(RTP/UDP);
  3. 媒体流信息:
    • 视频流:编码格式(H264/H265)、负载类型(Payload Type)、RTP 端口号、分辨率、帧率;
    • 音频流:编码格式(AAC/G711A/U)、负载类型、采样率、声道数、RTP 端口号;

实例

v=0                          // SDP版本号,固定为0  
o=- 123456 123456 IN IP4 192.168.1.100  // 会话发起者信息  
s=IPC Camera Stream          // 会话名称(摄像头流名称)  
c=IN IP4 192.168.1.100       // 媒体流传输的IP地址  
t=0 0                        // 会话时长,0表示永久播放  
m=video 5000 RTP/AVP 96      // 视频流:端口5000,RTP协议,负载类型96(H264)  
a=rtpmap:96 H264/90000       // 编码格式H264,时钟频率90000(视频标准)  
a=fmtp:96 profile-level-id=420029;sprop-parameter-sets=xxx  // H264参数集  
m=audio 5002 RTP/AVP 8       // 音频流:端口5002,RTP协议,负载类型8(G711U)  
a=rtpmap:8 PCMU/8000         // 编码格式G711U,采样率8000Hz,单声道

解读:这个 SDP 告诉客户端,服务端会通过 UDP 的 5000 端口发 H264 视频流,5002 端口发 G711U 音频流,客户端按这个规则解码即可播放。

固定流程

前提: 客户端与服务端已建立 TCP 连接(RTSP 默认走 554 端口 TCP)

客户端 → 服务端:OPTIONS rtsp://xxx/stream RTSP/1.0  【查询服务端能力】  
服务端 → 客户端:RTSP/1.0 200 OK + 支持的方法列表    【响应能力】  
客户端 → 服务端:DESCRIBE rtsp://xxx/stream RTSP/1.0 【获取SDP媒体信息】  
服务端 → 客户端:RTSP/1.0 200 OK + SDP文本内容       【返回流参数】  
客户端 → 服务端:SETUP rtsp://xxx/stream RTSP/1.0    【协商传输通道,指定RTP/UDP+端口】  
服务端 → 客户端:RTSP/1.0 200 OK + Session ID       【通道建立成功,返回会话ID】  
客户端 → 服务端:PLAY rtsp://xxx/stream RTSP/1.0     【发送播放指令】  
服务端 → 客户端:RTSP/1.0 200 OK                    【开始推送RTP媒体流】  
↓  
【此时客户端接收RTP数据,解码播放实时音视频】  
↓  
客户端 → 服务端:PAUSE rtsp://xxx/stream RTSP/1.0    【可选:暂停播放】  
服务端 → 客户端:RTSP/1.0 200 OK                    【停止推送RTP流,会话保留】  
↓  
客户端 → 服务端:PLAY rtsp://xxx/stream RTSP/1.0     【可选:继续播放】  
服务端 → 客户端:RTSP/1.0 200 OK                    【继续推送RTP流】  
↓  
客户端 → 服务端:TEARDOWN rtsp://xxx/stream RTSP/1.0 【断开连接】  
服务端 → 客户端:RTSP/1.0 200 OK                    【销毁会话,关闭所有通道】

流程是固定且不可逆的:必须先 OPTIONS,再 DESCRIBE,再 SETUP,最后 PLAY,跳过任何一步都会失败;
所有指令都需要携带 RTSP/1.0 版本号,和 HTTP 的HTTP/1.1类似;
从 PLAY 开始,才会有真正的音视频数据传输,之前的步骤都是「控制层协商」。

点播 / 组播

RTSP 支持两种主流的流媒体传输模式,对应不同的业务场景,本质是 RTP 媒体流的分发方式不同:

  1. 点播模式(On-Demand,主流模式,90% 场景使用)
  • 核心:一对一传输,客户端主动发起 RTSP 请求后,服务端才会为该客户端单独建立 RTP 传输通道,推送音视频流;
  • 特点:客户端断开后,服务端立即停止对该客户端的流推送,资源按需分配;
  • 适用场景:安防摄像头取流(手机 / 电脑看单个摄像头)、视频监控、个人直播、点播类实时视频。
  1. 组播模式(Multicast,组播模式)
  • 核心:一对多传输,服务端只需要将 RTP 媒体流发送到一个「组播 IP 地址 + 端口」,所有加入该组播组的客户端,都能接收同一股流数据;
  • 特点:服务端只发一次流,多客户端共享,极大节省服务端带宽和资源(比如 100 个客户端看同一路流,服务端只需要推送 1 次);
  • 适用场景:多路客户端观看同一路实时视频(比如商场大屏监控、直播间多人观看)、局域网内大规模视频分发。

补充:组播需要网络支持(路由器开启组播),公网环境下组播几乎不可用,所以公网场景都是点播模式。

RTSP 认证机制

绝大多数 RTSP 服务端(比如海康 / 大华摄像头、流媒体服务器)都会开启身份认证,防止非法设备取流,RTSP 支持两种主流认证方式:

  1. Basic 认证:明文传输用户名和密码(base64 编码,本质还是明文),安全性低,一般只在局域网内使用;
    • 将「用户名:密码」做 Base64 编码后,放在Authorization请求头中
    • Authorization: Basic YWRtaW46MTIzNDU2 # 对应 用户名:密码 = admin:123456 的Base64编码
  2. Digest 摘要认证(主流推荐):基于哈希算法(MD5)生成摘要,不传输明文密码,安全性高,是所有设备的默认认证方式;
    • 客户端发送 RTSP 请求后,服务端返回 401 Unauthorized 并携带认证参数,客户端通过 MD5 哈希计算响应值,全程不传输明文密码;
    • 认证参数:realm(认证域)、nonce(服务器随机数)、algorithm(哈希算法,通常 MD5
    • Authorization: Digest username="明文", realm="明文", nonce="明文", uri="明文", response="密文"
# 步骤1:计算HA1 = MD5(用户名:realm:密码)  
HA1 = MD5("admin:Honeywell_Camera:123456")  
  
# 步骤2:计算HA2 = MD5(请求方法:RTSP_URI)  
HA2 = MD5("OPTIONS:rtsp://10.15.2.231:332/profile1")  
  
# 步骤3:计算response = MD5(HA1:nonce:HA2)  
response = MD5("{HA1}:{nonce}:{HA2}")

认证流程:客户端发送 RTSP 请求后,服务端返回 401 Unauthorized 并携带认证参数,客户端携带加密后的用户名密码重新请求,认证通过后才能继续交互。

经验总结

换行符必须是 \r\n,不能是 \n

RTSP 协议标准强制要求:每行结尾必须是回车 + 换行(\r\n) ,Linux/macOS 的默认换行符是\n,Windows 是\r\n

  • ❌ 错误:OPTIONS rtsp://xxx RTSP/1.0\n
  • ✅ 正确:OPTIONS rtsp://xxx RTSP/1.0\r\n

后果:服务端无法识别报文结束位置,一直等待,最终超时断开连接,无任何响应。

报文结尾必须有「空行」\r\n\r\n

整个 OPTIONS 报文的最后,必须是连续两个 \r\n,也就是一个空行,无任何字符。

  • ❌ 错误:最后一行是 User-Agent: xxx\r\n,没有后续的\r\n
  • ✅ 正确:最后一行是 User-Agent: xxx\r\n + \r\n

后果:服务端认为报文未传输完成,一直等待,超时后返回 400 错误。

CSeq 序列号必须从 1 开始,严格自增

OPTIONS 是 RTSP 会话的第一个请求,所以 CSeq 必须填1,后续的 DESCRIBE 填2,SETUP 填3,PLAY 填4,以此类推,不能跳号、不能重复、不能从 0 开始

后果:服务端无法匹配请求和响应,返回乱序错误,或直接忽略请求。

RTSP 方法名、协议版本必须「大写」

  • OPTIONS 必须大写,不能写options/Option
  • RTSP/1.0 必须大写,不能写rtsp/1.0

后果:服务端无法识别方法,返回 405 Method Not Allowed(方法不允许)。

头域的冒号后「必须加一个空格」

RTSP 所有头域的格式都是 Key: Value,冒号和值之间必须有且只有一个空格。

  • ❌ 错误:CSeq:1User-Agent:Lavf/58.20.100
  • ✅ 正确:CSeq: 1User-Agent: Lavf/58.20.100

后果:服务端解析头域失败,返回 400 错误。

OPTIONS 报文「无请求体」

千万不要在报文最后加任何内容,RTSP 的 OPTIONS(包括所有方法)都没有请求体,只有头信息 + 空行,加了多余内容会被服务端判定为格式错误。