流媒体协议

image-20260520092716153

RTSP 在上层发号施令(管控制),RTP 在底层埋头搬砖(运数据),RTCP 在旁边盯着质量(做监督)

三者关系:

  • RTSP:控制播放、暂停和会话参数;RTP/RTCP 还可通过 RTSP 的 TCP 连接交错传输,不能理解为控制连接一定不承载媒体字节。
  • RTP:封装媒体载荷、时间戳和序列号,常运行于 UDP 之上,也可使用 TCP 等承载;RTP 本身不保证可靠、有序或按时送达。
  • RTCP:发送传输质量、同步和参与者信息;NACK 等反馈属于扩展机制,是否重传或调整码率由协议协商和实现决定。

传统 RTP/UDP 会话通常使用偶数 RTP 端口及相邻的奇数 RTCP 端口,但这是常见约定。SDP 可以明确协商 RTCP 端口,rtcp-mux 还允许两者共用同一端口:

  • RTP 占用偶数端口 $N$(如 9000)传输按载荷格式封装的媒体数据(通常为编码后的码流);
  • RTCP 占用相邻的奇数端口 $N+1$(如 9001)传输控制反馈报告。

RTP(实时传输协议)

  • RTP/RTCP 是实际传输数据的协议

头部

0               1               2               3
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|V=2|P|X|  CC   |M|     PT      |       sequence number         | // 4Byte 固定 
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                      timestamp                               |  // 4Byte 固定 
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|           synchronization source (SSRC) identifier           |  // 4Byte 固定 
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|            contributing source (CSRC) identifiers            |  <- 每个4 字节, 共 CC 个
|                               ...                            |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|   extension header (opt)   |       ext_length                |  <- 16 bit + 16 bit
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                       extension data …                       |  <- ext_length × 4 字节
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                           payload …                          |

固定头部字段

固定头部最少 12 字节;CSRC 列表和扩展头会增加总头部长度:

  • V (2 bits):版本号(通常为2)
  • P (1 bit):填充位(末尾有填充字节时置1)
  • X (1 bit):扩展头标志
  • CC (4 bits):CSRC计数器(混合流数量)
  • M (1 bit):含义由载荷规范定义;H.264 通常标记访问单元末尾,某些音频格式用于标记 talkspurt 开始,不能通用解释为“静音”
  • PT (7 bits):载荷类型。RTP/AVP 中 PCMU(G.711 μ-law)静态 PT 为 0,PCMA(A-law)为 8;H.264 通常使用 SDP 协商的动态 PT,96 只是常见取值。
  • Sequence Number:包序号(检测丢包和乱序)
  • Timestamp:时间戳(基于采样频率的时钟值)
  • SSRC:会话内同步源的 32 位标识,一个会话可以有多个 SSRC;发送方需检测并处理冲突
  • CSRC:贡献源列表(混流时使用)

扩展头部

​ 扩展头部是RTP协议的一个重要扩展机制,它是RTP头部的扩展标志(X)位决定的,它允许在RTP数据包中添加额外的信息,以满足特定应用的需求。扩展头部的格式如下:

  • 扩展头部标识符:占16位,用于标识扩展头部的类型和格式。不同的标识符对应不同的扩展头部定义,使得接收端能够正确解析扩展头部的内容。
  • 扩展头部长度:16 位,按 32 位字计数,不包含前面的 4 字节扩展头自身。
  • 扩展头部内容:扩展头部的内容根据具体的扩展头部标识符而定,可以包含各种类型的信息,如时间戳扩展、序列号扩展、加密信息等。扩展头部的灵活性使得RTP协议能够适应不断发展的应用需求。扩展头部的使用提高了RTP协议的适应性和扩展性,使得RTP协议能够在多种复杂的网络环境中稳定运行,并满足不同应用的特定需求。

RTP会话过程

会话建立

  RTP会话的建立是实时数据传输的起点,涉及多个关键步骤,确保数据能够正确传输到接收端。

  • 确定传输地址:按会话协商结果确定 RTP/RTCP 的传输地址、端口及是否复用。
  • 初始化 RTP 和 RTCP:设置源标识、序列号、时间戳及 RTCP 报告状态。
  • SSRC 的生成:通常随机选取,会话内可能发生碰撞,必须按协议处理;不能保证随机生成就绝不重复。

载荷

H.264 封装

RTP 是传输协议,H.264 是编码格式。RTP 对 H.264 码流进行封装传输。

┌─────────────┬──────────────────────────────────────────┐
│  RTP Header │              RTP Payload                 │
│   (12字节)   │   (H.264 NALU数据,不含起始码)             │
└─────────────┴──────────────────────────────────────────┘
H.264 NALU 头格式

在RTP头之后就是数据负载部分,在H264的负载封装中,第一个字节包含了数据传输的类型

+---------------+
|F| NRI | Type  | 
+---------------+
 1   2     5 bits

h264的NALU头长度为:1字节

字段长度说明
F (forbidden_zero_bit)1 bit必须为 0
NRI (nal_ref_idc)2 bitNALU 重要性,值越大越重要(0-3)
Type5 bitNALU 类型

Type 取值:

  • 1-23:单个 NAL 单元包
  • 24-27:组合包(STAP-A、STAP-B、MTAP16、MTAP24)
  • 28-29:分片包(FU-A、FU-B)

例如:

  • 0x67(二进制:0110 0111)

    • 拆解:F=0,NRI=11(最高重要性),Type=7(SPS)。
  • 0x68(二进制:0110 1000)

    • 拆解:F=0,NRI=11(最高重要性),Type=8(PPS)。
  • 0x65(二进制:0110 0101)

    • 拆解:F=0,NRI=11(最高重要性),Type=5(IDR 图像的编码切片)。
  • 0x41(二进制:0100 0001)

    • 拆解:F=0,NRI=10(中重要性),Type=1(非 IDR 图像的编码切片;I/P/B 类型需继续解析 slice header)。
单 NALU 模式

image-20260522090918420

​ 单一NAL单元模式是最简单的RTP封装方式,每个RTP包只包含一个H.264的NAL单元。这种模式适用于NAL单元大小较小,且网络条件较好,不需要对NAL单元进行分片或聚合的场景。在这种模式下,RTP负载的第一个字节是NAL单元的头信息(1字节),紧接着是 NAL 单元的字节序列载荷(EBSP,可能含 emulation prevention 字节),不是直接去除防竞争字节后的 RBSP。封装和解封装过程简单,易于实现。由于每个RTP包只包含一个NAL单元,因此在解码端可以快速识别和处理每个NAL单元,减少了处理复杂度。适用于NAL单元较小(如SPS、PPS等参数集或较小的I帧切片)的场景,或者在网络带宽充足且对延迟要求不高的情况下。

  • NAL 类型(NAL Unit Type): 1–23
  • 结构: RTP 载荷直接就是一个完整的 NAL 单元(不含起始码 0x00000001),若要避免 IP 分片,需要从路径 MTU 中扣除 IP、UDP、RTP 及扩展等头部开销,再判断整个 NALU 是否能装入单包。
  • 处理: 按 SSRC、序列号和 RTP 时间戳重排、检测丢包并组装访问单元;M 位可作为边界提示,但收到 M=1 并不能证明此前所有分片都已到齐。
分片封包(FU-A)

RTP Header + FU indicator (1字节) + FU header(1字节) + Fragment data

FU indicator :

+---------------+  
|0|1|2|3|4|5|6|7|
+-+-+-+-+-+-+-+-+
|F|NRI|  Type   |
+---------------+

Type = 28 表示这是FU-A

FU header :

+---------------+
|0|1|2|3|4|5|6|7|
+-+-+-+-+-+-+-+-+
|S|E|R|  Type   |
+---------------+
  • S(开始位): 1 bit, 当设置成1,指示分片NAL单元的开始。当跟随的FU荷载不是分片NAL单元荷载的开始,开始位设为0。
  • E(结束位): 1 bit, 当设置成1,指示分片NAL单元的结束,即,荷载的最后字节也是分片NAL单元的最后一个字节。当跟随的 FU荷载不是分片NAL单元的最后分片,结束位设置为0。
  • R(保留位): 1 bit, 保留位必须设置为0,接收者必须忽略该位。
  • Type(类型):5 bit,原始NAL类型

H.265 封装

H.265 NALU头格式
+-------------------------------+
| F |   Type    |  LayerId  |TID|
+-------------------------------+
Bits: F(1), Type(6), LayerId(6), TID(3)

h265的NALU头长度为:2字节

字段长度说明
F (forbidden_zero_bit)1 bit禁止位。最高位(第 15 位),必须为 0。若为 1 则标识该帧为无效帧、损坏帧。
Type (nal_unit_type)6 bit帧类型(第 9 ~ 14 位)。0 - 31:VCL NAL 单元(携带编码视频图像数据的流,如 19/20 为 IDR 关键帧,1 为普通 P/B 帧)。32 - 63:非 VCL NAL 单元(控制数据流,如 32 为 VPS,33 为 SPS,34 为 PPS)。
LayerId (nuh_layer_id)6 bit层标识(第 3 ~ 8 位)目前普通单视角的 IPC 编码中一般固定为 0
TID (nuh_temporal_id_plus1)3 bit时间层 ID 加 1,合法值为 1~7,不能为 0;实际时间层 ID 为 TID − 1。单时间层码流常为 1,不能把所有码流都固定写成 1。

参考:RTP;RTP/AVP;rtcp-mux;H.264 RTP;H.265 RTP。