2、RTP协议核心:RTP头部结构、SSRC与CSRC、RTP时间戳机制、Payload Type

各位同学,咱们今天来啃RTP协议的核心。说实话,RTP这玩意儿看着简单,但坑特别多。我当年第一次做音视频同步时,就被时间戳给坑惨了——画面和声音差了快两秒,排查了一整天才发现是时间戳基值没对齐。好,咱们从头捋一遍。

2.1 RTP固定头部结构:12字节的硬规矩

RTP头部,说白了就是12个字节的固定结构。不管你是传H.264还是传G.711,这12个字节一个都不能少。我习惯把这12字节拆成四个32位字来看,这样好记。

偏移(字节) 位域 字段 长度(bit) 说明
0 0-1 V (Version) 2 版本号,当前固定为2
0 2 P (Padding) 1 填充标志,1表示尾部有填充字节
0 3 X (Extension) 1 扩展头部标志
0 4-7 CC (CSRC Count) 4 CSRC标识符数量
1 0-7 M (Marker) 1 标记位,视频帧边界常用
1 1-7 PT (Payload Type) 7 负载类型,标识编码格式
2-3 0-15 Sequence Number 16 序列号,每发一个包+1
4-7 0-31 Timestamp 32 时间戳,采样时刻
8-11 0-31 SSRC 32 同步源标识符
12-... 0-31 CSRC List 32*CC 贡献源列表,仅当CC>0时存在

核心要点:RTP头部最小12字节,最大可以扩展到12 + 4*15 = 72字节(当CC=15且X=1时)。但实际项目中,99%的情况只用12字节固定头。

这里有个细节——序列号是16位的,意味着它会循环。从0到65535,然后回到0。我在项目中遇到过接收端没处理好序列号回绕,导致丢包检测全乱套的情况。嗯,后面讲丢包重传时咱们再细聊。

2.2 SSRC与CSRC:谁在说话?

SSRC,全称是Synchronization Source,同步源。说白了,就是给每个RTP流发一个唯一的身份证号。32位随机数,理论上冲突概率很低,但也不是零。

我记得有一次做多方视频会议,两个终端随机出来的SSRC居然撞了。接收端直接疯掉,画面来回跳。后来怎么解决的?我们在SIP信令里加了个SSRC协商机制,强制服务端分配。

实战建议:SSRC冲突虽然概率低,但生产环境一定要做冲突检测。RFC 3550建议:收到同一SSRC但源传输地址不同的包时,必须进行冲突处理。最简单的做法是重新生成SSRC并发送RTCP BYE。

CSRC呢?Contributing Source,贡献源。这玩意儿在混音场景下特别有用。举个例子:一个MCU(多点控制单元)把三个人的音频混成一路RTP流,那这路流的SSRC是MCU自己的,但CSRC列表里会填上那三个人的SSRC。接收端看到CSRC列表,就知道这包音频是谁贡献的。

CSRC最多15个,因为CC字段只有4位。你想想看,15路混音,一般场景也够用了。

2.3 RTP时间戳机制:同步的灵魂

时间戳,这是RTP里最容易被误解的字段。很多人以为时间戳就是绝对时间,其实不是。RTP时间戳是一个单调递增的计数器,它的增量取决于采样率和帧间隔。

咱们直接看公式:

时间戳增量 = 采样率 / 帧率

举例:
- 音频:采样率 8000Hz,帧长 20ms → 增量 = 8000 * 0.02 = 160
- 视频:采样率 90000Hz,帧率 30fps → 增量 = 90000 / 30 = 3000

注意:视频的RTP时间戳采样率固定为90000Hz,这是历史原因——MPEG标准定的。音频则用实际采样率,比如8000、16000、44100、48000。千万别搞混!

我刚开始做流媒体时,犯过一个低级错误:把视频时间戳的增量算成了90000/25=3600,结果25fps的视频在接收端播放时一卡一卡的。后来才发现,我算的是理论值,但编码器实际输出帧率是29.97,增量应该是90000/29.97≈3003。差这3个计数,累积几秒就明显不同步了。

时间戳的初始值,RFC建议随机初始化。为什么?为了防止加密场景下的已知明文攻击。但实际项目中,很多实现直接设为0,也没出大问题。我个人习惯用随机值,毕竟安全无小事。

2.4 Payload Type:告诉对方怎么解码

PT字段,7位,取值范围0-127。其中0-96是静态分配的类型,96-127是动态类型,需要通过SDP协商。

PT值 编码格式 采样率(Hz) 声道数
0 PCMU (G.711 μ-law) 8000 1
3 GSM 8000 1
8 PCMA (G.711 A-law) 8000 1
10 L16 (线性PCM 16位) 44100 2
26 JPEG (MJPEG) 90000 -
31 H.261 90000 -
96-127 动态类型(H.264/HEVC/Opus等) 由SDP指定 由SDP指定

你看,H.264没有静态PT值,所以必须用动态类型。在SDP里这样写:

m=video 5004 RTP/AVP 96
a=rtpmap:96 H264/90000
a=fmtp:96 packetization-mode=1;profile-level-id=42e01f

这里96就是动态PT,后面跟着编码名和时钟频率。fmtp行是编码参数,H.264的packetization-mode=1表示使用非交错模式,这是最常用的。

避坑指南:我曾经遇到一个设备,它把H.264的PT硬编码成99,但SDP里写的是96。结果接收端按96去查编码表,发现没注册,直接丢包。所以PT值一定要和SDP协商结果一致,别自己硬写。

2.5 知识体系总览

说了这么多,咱们用一张图把RTP核心串起来。这张图我画了好几次才满意,把头部结构、SSRC/CSRC、时间戳、PT的关系都理清了。

RTP协议核心知识体系 RTP协议核心知识体系 RTP固定头部 (12字节) 头部字段详解 SSRC / CSRC 时间戳机制 Payload Type 关键字段 • V=2 (版本固定) • P: 填充标志 • X: 扩展标志 • M: 标记位 (帧边界) 标识符体系 • SSRC: 流唯一ID • CSRC: 混音贡献源 • 32位随机数 • 需做冲突检测 时间戳规则 • 音频: 实际采样率 • 视频: 固定90000Hz • 增量 = 采样率/帧率 • 初始值随机化 负载类型 • 0-95: 静态分配 • 96-127: 动态类型 • 通过SDP协商 • 标识编码格式 核心目标:为音视频同步提供基础 注:四个核心要素共同构成RTP协议的基础,缺一不可 时间戳增量计算公式 ΔTimestamp = 采样率 / 帧率 例:音频8kHz/20ms→160 | 视频90kHz/30fps→3000

这张图把RTP核心的四个要素串起来了。你仔细看,头部字段是骨架,SSRC/CSRC是身份标识,时间戳是同步的命脉,PT是解码的钥匙。四者缺一不可。