3、RTP负载类型(PT)详解:PT值的定义与范围、静态负载类型与动态负载类型、常见音视频编码的PT映射
RTP 头里有个 7 比特的字段,叫 Payload Type(PT)。说白了,它就是告诉接收端:「这包数据是啥编码格式」。我刚开始调 RTP 流的时候,总觉得 PT 就是个编号,后来踩了几次坑才发现——PT 要是配错了,解码器根本认不出数据,画面直接花掉。
核心要点:PT 值决定了接收端用什么解码器来处理 RTP 负载。一个错误的 PT 映射,会导致整个流媒体会话失败。
3.1 PT 值的定义与范围
PT 字段占 7 位,取值范围是 0–127。但实际使用中,这个范围被分成了两段:
| 范围 | 类型 | 说明 |
|---|---|---|
| 0–95 | 静态负载类型 | 由 IANA 分配,编码格式固定 |
| 96–127 | 动态负载类型 | 通过 SDP 协商,编码格式可变 |
你可能会问:为什么要有静态和动态之分?嗯,早期 RTP 设计时,音视频编码种类不多,静态分配就够了。后来 H.264、VP8、Opus 这些编码陆续出现,静态范围不够用,才有了动态范围。
我的习惯:静态 PT 值尽量别改,那是行业约定。动态 PT 值我一般从 96 开始分配,避免和已有标准冲突。
3.2 静态负载类型
静态 PT 值 0–95 里,真正被 IANA 分配的大概只有前 34 个。剩下的保留未用。我列几个最常用的:
| PT 值 | 编码名称 | 时钟频率 (Hz) | 声道数 |
|---|---|---|---|
| 0 | PCMU | 8000 | 1 |
| 3 | GSM | 8000 | 1 |
| 4 | G723 | 8000 | 1 |
| 8 | PCMA | 8000 | 1 |
| 9 | G722 | 8000 | 1 |
| 10 | L16 (2 声道) | 44100 | 2 |
| 11 | L16 (1 声道) | 44100 | 1 |
| 13 | CN (舒适噪声) | 8000 | 1 |
| 26 | JPEG | 90000 | — |
| 31 | H.261 | 90000 | — |
| 34 | H.263 | 90000 | — |
注意看,音频的时钟频率大多是 8000 Hz,视频统一用 90000 Hz。为什么视频用 90000?因为 90000 能被 25、30、50、60 这些常见帧率整除,时间戳精度够用。
我曾经踩过的坑:有一次把 PCMU 的 PT 值写成了 8(PCMA 的值),结果接收端用 A-law 解码 μ-law 数据,出来的声音全是噪音。排查了半小时才发现是 PT 映射错了。
3.3 动态负载类型
动态 PT 值 96–127 没有固定编码格式。发送端和接收端通过 SDP 协商,告诉对方「我用 PT 96 代表 H.264」。举个例子:
m=video 5004 RTP/AVP 96
a=rtpmap:96 H264/90000
a=fmtp:96 packetization-mode=1; profile-level-id=42e01f
这段 SDP 的意思是:视频流用 PT 96,编码是 H.264,时钟频率 90000 Hz,打包模式是 1(NAL 单元模式)。
动态 PT 的分配没有硬性规定,但业界有一些不成文的习惯:
- 96–100:常用 H.264
- 101–105:常用 Opus 或 AAC
- 106–110:常用 VP8 或 VP9
- 111–127:留给自定义编码或扩展
我建议:同一个会话里,不同编码的 PT 值不要重复。我曾经见过一个系统,音频和视频都用 PT 100,结果解码器全乱了。
3.4 常见音视频编码的 PT 映射
我把实际项目中最常用的 PT 映射整理成了一张表。这张表我调了不下 50 次流,基本覆盖了 90% 的场景:
| 编码 | PT 值 | 类型 | 时钟频率 | 备注 |
|---|---|---|---|---|
| PCMU | 0 | 静态 | 8000 | μ-law,VoIP 标配 |
| PCMA | 8 | 静态 | 8000 | A-law,欧洲常用 |
| G.722 | 9 | 静态 | 8000 | 宽带音频,7 kHz |
| Opus | 动态 (通常 96–100) | 动态 | 48000 | WebRTC 首选 |
| AAC | 动态 (通常 101–105) | 动态 | 44100/48000 | MPEG-4 音频 |
| H.264 | 动态 (通常 96–100) | 动态 | 90000 | 视频编码主流 |
| H.265 | 动态 (通常 106–110) | 动态 | 90000 | 4K/8K 视频 |
| VP8 | 动态 (通常 106–110) | 动态 | 90000 | WebRTC 视频 |
| JPEG | 26 | 静态 | 90000 | 老式监控设备 |
这里有个细节:Opus 的时钟频率是 48000 Hz,不是 8000。因为 Opus 支持 20 kHz 以上的全频带音频,采样率必须高。我刚开始用 Opus 时,把时钟频率写成了 8000,结果时间戳计算全错,音频播放一顿一顿的。
实战要点:动态 PT 值必须在 SDP 中明确声明。接收端收到 RTP 包后,先查 PT 值,再查 SDP 映射,最后选解码器。缺了任何一步,流都解不出来。
3.5 PT 映射的完整流程
我画了一张图,把 PT 映射的完整流程串起来。你一看就明白:
流程其实不复杂:发送端先选好编码,再根据编码类型选 PT 值(静态或动态)。动态 PT 需要先通过 SDP 告诉接收端映射关系。然后封装 RTP 包,把 PT 值填进头部。接收端收到包后,根据 PT 值找到对应的解码器,开始解码。
我曾经遇到的一个典型案例:有一次调试 WebRTC 视频通话,H.264 的 PT 值在 SDP 里写的是 96,但实际 RTP 包里 PT 字段是 100。接收端查不到映射,直接丢弃了所有视频包。排查了整整一天,才发现是发送端代码里硬编码了 PT 100,没读 SDP 的配置。
3.6 调试 PT 映射的实用技巧
调了这么多年 RTP 流,我总结了几条经验,分享给你:
- 用 Wireshark 抓包验证:过滤
rtp,看每个包的 PT 字段。如果 PT 值和 SDP 声明的不一致,那就是问题。 - 检查 SDP 的 rtpmap 行:确保编码名称、时钟频率写对了。我见过有人把 H264 写成 H.264(带点),结果解析失败。
- 动态 PT 值不要跨会话复用:不同媒体流(音频、视频)的 PT 值最好分开。音频用 96–100,视频用 101–105,避免混淆。
- 注意 fmtp 参数:H.264 的 packetization-mode、profile-level-id 这些参数,直接影响解码器行为。漏了任何一个,画面都可能出问题。
我的调试习惯:每次改 PT 映射后,先用 ffplay 或 VLC 拉流测试。如果能正常播放,说明 PT 映射没问题。如果花屏或没声音,先查 PT 值。
PT 这个字段,看起来简单,但它是 RTP 会话的「翻译官」。翻译错了,再好的编码数据也白搭。你想想看,接收端拿到一个 PT=96 的包,它得先查 SDP 才知道这是 H.264 还是 Opus。如果 SDP 没配好,或者 PT 值写错了,整个流就断了。
嗯,PT 映射这块,我建议你多动手抓包看看。看多了,自然就熟了。