📹 第一章 流媒体与RTSP/RTP/RTCP简介
📄 一句话概括

RTSP 说的「容器文件」不是 MP4 那种盒子结构,指的是「一次呈现包含多路媒体」。 一份 SDP 里每出现一行 m=,就是一路。两路就要 SETUP 两次。

📝 本节和前面几节的关系

上一节讲实体,这一节讲实体里装的东西。 「容器文件」这个词容易误会成 MP4/MKV 那种封装格式, 其实 RFC 2326 里它指的是「一组媒体流的集合」,和文件格式无关。 封装格式那件事看 26 课, 那是编码侧的盒子结构。

一、先把这个词摘清楚

同一句话在两种语境里意思完全不同:

语境 「容器」指什么 例子
封装格式 把音视频装进一个文件的盒子 MP4、MKV、AVI
RTSP 规范 一次呈现里的多路媒体集合 SDP 里两条 m= 行

RFC 2326 的定义是后者:一个 presentation 由一个或多个媒体流组成,这些流共享时间轴, 可以一起控。 所以这一节讲的是「一组」这个概念,不是讲 MP4 的 box 怎么排。

书里放在「RTSP 重要概念」下面,也是这个意思——它和集合控制、实体是同一层的概念,不是编码话题。

二、SDP 里怎么表示多路

SDP 是纯文本,一行一个字段,类型=值。 其中 m= 开头的行最特殊:它标志着「新的一路媒体开始了」。

行 意思 后面跟什么
v=0 协议版本 —
o= 发起者与版本号 —
s= 会话名 —
t= 起止时间 —
m=video 0 RTP/AVP 96 一路视频,负载类型 96 a= 行
a=rtpmap:96 H264/90000 96 是 H.264,时钟 90000 —
m=audio 0 RTP/AVP 97 一路音频,负载类型 97 a= 行
a=rtpmap:97 PCMU/8000 97 是 G.711,时钟 8000 —

规律很简单:第一个 m= 之前是会话级字段,之后每个 m= 带一组自己的 a=, 一直到下一个 m= 为止。 解析器的写法就是「遇到 m= 就开一个新的媒体对象」。

三、两路就要两次 SETUP

SDP 里有两条 m=,客户端就要发两次 SETUP。

步 发几次 针对谁
OPTIONS 1 整组
DESCRIBE 1 整组
SETUP 2 trackID=0 和 trackID=1
PLAY 1 整组
TEARDOWN 1 整组

为什么 SETUP 要两次而 PLAY 只要一次:SETUP 是「给某一路分配传输参数」,每路都要各自的端口; PLAY 是「让整组开始跑」,一次就够。

这也是最容易写错的地方:只 SETUP 了视频就 PLAY,音频不会来,而代码往往还在等音频包, 表现为「画面有了没声音」。

四、负载类型是关键线索

m= 行里那个数字(96、97)叫负载类型(payload type),它本身不说明编码格式。 真正说明格式的是紧跟其后的 a=rtpmap 行。

负载类型 含义 说明
0 PCMU(G.711 μ 律) 静态,固定
8 PCMA(G.711 A 律) 静态,固定
26 JPEG 静态,固定
96~127 动态 看 a=rtpmap 才知道

96 以上都是动态的——同一份 SDP 里 96 可能是 H.264,换个设备 96 又可能是 H.265。 所以别硬编码「96 就是 H.264」,一定要读 a=rtpmap。 这是国产设备对接里最常见的错:有的设备 H.265 也用 96,不读 rtpmap 就当成 H.264 去解, 解出来当然是花屏。

五、动手 Demo:容器文件就是一个 SDP 里的几个 m= 行

这段造一份带视频和音频的 SDP,逐行标注意思,再数出有几路。 重点看负载类型那两行:96 和 97 都不是固定含义的。

sdp = [(u"v=0", u"协议版本"), (u"s=IP Camera", u"会话名"),
       (u"a=control:*", u"整组的控制地址"),
       (u"m=video 0 RTP/AVP 96", u"第一路:视频"),
       (u"a=rtpmap:96 H264/90000", u"96 就是 H.264"),
       (u"m=audio 0 RTP/AVP 97", u"第二路:音频"),
       (u"a=rtpmap:97 PCMU/8000", u"97 就是 G.711")]

n = sum(1 for line, _ in sdp if line.startswith(u"m="))
print(n)          # 有几路媒体,就要 SETUP 几次

实跑输出:

--------------------------------------------------------------------
容器文件就是一个 SDP 里的几个 m= 行
--------------------------------------------------------------------
**RTSP 说的「容器文件」不是 MP4 那种盒子结构**,指的是「一次呈现里包含多路媒体」。
  一份 SDP 里每出现一行 `m=`,就是一路媒体。

  行                              意思
  -----------------------------------------------------------------
  v=0                             协议版本,永远是 0
  o=- 1 1 IN IP4 192.168.1.64     会话发起者与版本号
  s=IP Camera                     会话名
  t=0 0                           起止时间,0 0 表示不限
  a=control:*                     整组的控制地址
  m=video 0 RTP/AVP 96            第一路:视频,负载类型 96
  a=rtpmap:96 H264/90000          96 就是 H.264,时钟 90000
  a=control:trackID=0             这一路的控制后缀
  m=audio 0 RTP/AVP 97            第二路:音频,负载类型 97
  a=rtpmap:97 PCMU/8000           97 就是 G.711 μ 律,时钟 8000
  a=control:trackID=1             这一路的控制后缀

**这份 SDP 有 2 行 m=,所以这一路「呈现」里有 2 路媒体。**
  播放器拿到它,就得 SETUP 2 次、PLAY 一次(PLAY 整组)、再各占一对端口。

**只取视频不要音频**也常见:
  URL 后面换个通道号(如 101 而不是 102),或者只在 SETUP 时对 trackID=0 发起。
  **注意**:只 SETUP 一路,PLAY 时仍然用整组 URL,这时服务端只发你 SETUP 过的那一路。

数出来是 2,所以这份 SDP 对应的会话要 SETUP 两次。 如果只 SETUP 视频那一路,PLAY 之后只会收到视频包——这不是设备坏了,是你没要音频。

负载类型那两行值得再强调一次:96 和 97 都是动态类型,它们的含义完全由 a=rtpmap 决定。 同一台设备换成 H.265,可能还是 96,只是 a=rtpmap:96 H265/90000。 不读这一行就硬编码解码器,遇到 H.265 就是必然花屏。

还有一处容易漏:a=control:trackID=0 这种行每个 m= 下面各有一个, 它们是 SETUP 时的 URL 后缀。 漏了它就只能猜 trackID=0/1——大多数设备确实是这么编号的,但国标设备有时用别的形式, 猜错就是 404。

30 秒实验

  1. 抓一份真实的 DESCRIBE 响应,数 m= 行有几条。
  2. 把每条 m= 后面的 a=rtpmap 抄下来,看负载类型分别是多少、对应什么编码。
  3. 只 SETUP 视频那一路,PLAY 之后看抓包里有没有 RTP 音频包。

常见误区

  1. 以为 RTSP 的「容器文件」是 MP4 那种封装。 RFC 2326 里它指「一次呈现包含多路媒体」, 和文件格式无关。
  2. 以为一条 SETUP 能管所有路。 每路都要单独 SETUP,各自分配端口。
  3. 以为负载类型 96 就是 H.264。 96 以上都是动态的,必须读 a=rtpmap 才知道是 H.264 还是 H.265。
自测三问(点开对答案) 1. SDP 里怎么看出有几路媒体? —— 数 `m=` 开头的行。每一条 m= 就是一路,后面跟着它自己的 a= 行,直到下一个 m= 为止。 2. 两路媒体要 SETUP 几次、PLAY 几次? —— SETUP 两次(各分各的端口),PLAY 一次(作用于整组)。 3. 负载类型 96 一定是 H.264 吗? —— 不一定。96 到 127 是动态类型,含义由同一份 SDP 里的 a=rtpmap 决定。 硬编码 96=H.264 遇到 H.265 就花屏。

下一节讲会话:Session 号怎么来的、为什么 60 秒就会被回收、保活该多久一次。

相关笔记