3. RTP负载类型与编码映射:PT值与编码格式对应关系

RTP头里有个字段叫 PT(Payload Type),7 个比特,取值范围 0–127。说白了,它就是告诉接收端:「我这包里装的是 H.264 还是 Opus,你拿什么解码器来解。」

我刚开始接触 RTP 时,总觉得 PT 就是个编号,后来踩过坑才明白——PT 值背后牵涉到编码协商、动态映射、甚至整个流媒体系统的兼容性。这一节,咱们就把 PT 和编码格式的映射关系彻底讲透。

3.1 静态 PT 值:RFC 定义的固定映射

早期的 RTP 规范(RFC 3551)为一些经典编码分配了固定的 PT 值。这些值被称为「静态 PT」,范围是 0–95。接收端看到这些 PT 值,不需要额外协商就知道该用什么解码器。

PT 值 编码格式 时钟频率 (Hz) 声道数 典型应用
0 PCMU (G.711 μ-law) 8000 1 VoIP 电话
3 GSM 8000 1 早期移动通信
4 G.723 8000 1 低码率语音
8 PCMA (G.711 A-law) 8000 1 VoIP 电话(欧洲)
9 G.722 8000 1 宽带语音
10 L16 (线性 PCM, 2 声道) 44100 2 CD 音质传输
11 L16 (线性 PCM, 1 声道) 44100 1 单声道高保真
14 MPA (MPEG-1/2 Audio) 90000 1 MPEG 音频流
26 JPEG 90000 — MJPEG 视频
31 H.261 90000 — 早期视频会议
32 MPV (MPEG-1 Video) 90000 — MPEG-1 视频
34 H.263 90000 — 视频通话
我的经验:静态 PT 值在今天的流媒体系统中已经很少用了。我最近一次见到 PT=0 的 PCMU 流,是在一个老旧的 SIP 网关对接项目里。现代编码(H.264、AAC、Opus)全走动态 PT,因为静态表里根本没给它们留位置。

3.2 动态 PT 值:SDP 协商的核心

静态 PT 只覆盖了 0–95 中的一小部分,而且很多编码(比如 H.264、VP9、Opus)是后来才出现的。RFC 3551 规定,96–127 这 32 个值留给「动态 PT」——说白了,就是让通信双方通过 SDP 协议自己商量:「我用 PT=96 代表 H.264,你同意吗?」

为什么会这样设计?你想想看,如果每出一个新编码就要 IANA 分配一个固定 PT,那 RFC 得改到猴年马月。动态 PT 给了系统极大的灵活性。

SDP 中的 PT 映射示例

下面是一个典型的 SDP 片段,展示了动态 PT 的映射方式:

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

这段 SDP 的意思是:

  • 视频流在端口 5004 上传输,支持三种编码
  • PT=96 对应 H.264,时钟频率 90000 Hz
  • PT=97 对应 VP8,时钟频率 90000 Hz
  • PT=98 对应 H.265,时钟频率 90000 Hz
  • a=fmtp 行进一步描述了 H.264 的参数(打包模式、profile 等级)
关键点:动态 PT 的映射只在当前 RTP 会话中有效。同一个 PT=96,在会话 A 里可能是 H.264,在会话 B 里可能是 Opus。接收端必须根据 SDP 协商结果来解析 PT 值,不能硬编码。

3.3 常用音视频编码的 PT 值速查

我把实际项目中常见的编码及其 PT 值整理成了一张速查表。静态 PT 直接查表,动态 PT 是业界约定俗成的常用值(实际以 SDP 协商为准)。

编码格式 类型 PT 值 时钟频率 备注
PCMU 音频 0 (静态) 8000 G.711 μ-law
PCMA 音频 8 (静态) 8000 G.711 A-law
Opus 音频 动态 (常用 111) 48000 WebRTC 首选
AAC 音频 动态 (常用 97) 44100/48000 需配合 LATM/ADTS
G.722 音频 9 (静态) 8000 实际编码是 16000 Hz
iLBC 音频 动态 (常用 98) 8000 旧版 WebRTC
H.264 视频 动态 (常用 96) 90000 最广泛使用的视频编码
H.265 视频 动态 (常用 98) 90000 4K/8K 视频
VP8 视频 动态 (常用 97) 90000 WebRTC 默认
VP9 视频 动态 (常用 99) 90000 Google 新一代
AV1 视频 动态 (常用 100) 90000 开放媒体联盟
JPEG 视频 26 (静态) 90000 MJPEG 监控流
避坑指南:我曾经在一个项目中,接收端硬编码了 PT=96 就是 H.264。结果发送端用 PT=96 传了 VP8,画面直接花屏。后来我加了一条规则:所有动态 PT 必须在 SDP 协商后动态建立解码器,绝不允许硬编码映射表。

3.4 PT 值与时钟频率的关系

你可能注意到了,视频编码的时钟频率几乎都是 90000 Hz,而音频编码则五花八门(8000、16000、44100、48000)。

为什么视频统一用 90000?

  • 90000 是 25 fps、30 fps、50 fps、60 fps 的公倍数
  • 它能让 RTP 时间戳以整数步长递增,避免浮点误差
  • 这是 MPEG 系统标准(ISO/IEC 13818-1)定下来的,RTP 沿用了这个约定

音频就不一样了。音频的采样率直接决定了 RTP 时间戳的步长。比如 Opus 用 48000 Hz,每帧 20 ms,时间戳步长就是 960。如果用 8000 Hz,同样 20 ms 的帧,步长只有 160。

我的习惯:做音画同步时,我从来不用 PT 值直接算时间。PT 只告诉我「这是什么编码」,时间戳的计算必须依赖 SDP 里声明的时钟频率。把 PT 和时间戳混为一谈,是新手最容易犯的错误。

3.5 动态 PT 协商的完整流程

为了让你更直观地理解动态 PT 的协商过程,我画了一张流程图。它展示了一个典型的 WebRTC 或 SIP 场景中,发送端和接收端如何通过 SDP 交换 PT 映射信息。

动态 PT 协商流程图 动态 PT 协商流程 发送端 接收端 1. 生成 SDP Offer m=video 5004 RTP/AVP 96 97 SDP Offer 2. 解析并生成 SDP Answer a=rtpmap:96 H264/90000 SDP Answer 3. 建立 PT 映射表 PT=96 → H.264 3. 建立 PT 映射表 PT=96 → H.264 4. 发送 RTP 包 4. 接收并解码 RTP 流 (PT=96, H.264) PT 映射只在当前会话有效 下次会话可能 PT=96 代表 VP8

这个流程看起来简单,但实际项目中经常出问题。我遇到过最典型的情况是:接收端没有正确解析 SDP 中的 a=rtpmap 行,导致 PT 映射表建立失败。结果就是 RTP 包到了,解码器却不知道用什么格式解。

3.6 实战建议:PT 值处理的最佳实践

  1. 永远不要硬编码动态 PT 值——哪怕你只在内部系统用,也请通过 SDP 协商。我见过太多因为硬编码导致对接失败的血泪史。
  2. 静态 PT 值也要验证——虽然 RFC 定义了静态映射,但有些老旧设备可能不按规范来。收到 PT=0 时,最好还是确认一下是不是真的 PCMU。
  3. PT 值变化要能动态适应——在同一个 RTP 会话中,发送端可以切换 PT 值(比如从 H.264 切到 H.265)。接收端必须能根据 PT 值的变化动态切换解码器。
  4. 日志里一定要打印 PT 映射表——排查问题时,第一件事就是看 SDP 协商出来的 PT 映射是否正确。我习惯在初始化阶段把映射表完整打印出来。
一句话总结:PT 值是 RTP 包的「编码身份证」。静态 PT 是历史遗产,动态 PT 是现代流媒体的基石。理解 PT 映射,就是理解 RTP 如何与编码格式解耦——这是设计可扩展流媒体系统的关键。