3. RTP协议概述

各位同学,今天我们来聊聊RTP协议里一个看似简单、实则暗藏玄机的话题——负载类型(Payload Type,简称PT)。

说白了,PT值就是RTP包的“身份证”。它告诉接收端:这个包里装的是H.264视频,还是AAC音频,或者是Opus语音。没有这个标识,接收端根本不知道该怎么解码。

我刚开始做流媒体时,就吃过PT值的亏。有一次调试一个视频通话系统,画面死活出不来。查了半天,发现发送端填的PT值是96,接收端却按H.264去解——其实96对应的是动态负载类型,但两边协商没做好。嗯,从那以后我再也不敢小看这个8位的字段了。

3.1 PT值的标准定义

RTP协议在RFC 3550中定义,PT字段占用8个bit,取值范围0-127。其中0-95是静态分配,96-127留给动态协商。

静态PT值由IANA统一注册,常见的有:

PT值 编码格式 时钟频率(Hz) 声道数 说明
0 PCMU 8000 1 G.711 μ-law
3 GSM 8000 1 全速率
8 PCMA 8000 1 G.711 A-law
10 L16 44100 2 立体声PCM
14 MPA 90000 1 MPEG音频
26 JPEG 90000 - MJPEG视频
31 H.261 90000 - 老古董了
32 MPV 90000 - MPEG-1视频
34 H.263 90000 - 早期视频编码

关键点:静态PT值只覆盖了最基础的编码格式。像H.264、AAC、Opus这些现代编码,全部使用动态PT值(96-127)。

3.2 动态PT值的协商机制

你可能会问:为什么H.264不用一个固定的PT值?

原因很简单。H.264有几十个profile和level,AAC有LC、HE、HEv2等变种,Opus的比特率可调范围极大。如果每个变种都分配一个静态PT值,IANA那点地址空间早就不够用了。

所以,动态PT值的协商就派上了用场。这个过程通常通过SIP或RTSP的SDP协商来完成。

我个人习惯把协商过程总结为三步:

  1. 发送方声明:在SDP中列出支持的编码格式及其对应的动态PT值
  2. 接收方选择:从发送方列出的格式中选择一个或多个
  3. 建立映射:双方确认PT值与编码格式的对应关系

举个例子,一个典型的SDP片段长这样:

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

这里,96和97都映射到H.264,但参数不同。接收端可以根据自身能力选择其中一个。

我的经验:动态PT值协商时,建议把最常用的编码格式放在前面。如果接收端不支持第一个,会尝试第二个。我曾经见过一个设备只解析SDP中的第一个rtpmap,后面的全忽略——虽然这不符合规范,但现实世界就是这么魔幻。

3.3 常见编码的PT值映射

下面这张表是我在实际项目中常用的映射关系,大家可以直接参考:

编码格式 典型PT值 时钟频率 SDP中的rtpmap 备注
H.264 96 90000 H264/90000 最常用
H.265 98 90000 H265/90000 4K/8K场景
AAC-LC 97 48000 MP4A-LATM/48000/2 注意声道数
Opus 99 48000 opus/48000/2 WebRTC首选
VP8 100 90000 VP8/90000 WebRTC视频
VP9 101 90000 VP9/90000 高压缩率
G.722 9 8000 G722/8000 静态PT值
iLBC 102 8000 iLBC/8000 旧版VoIP

避坑指南:我曾经遇到过一个设备,它把AAC的时钟频率写成了44100而不是48000。结果接收端按44100去解码,音频全部变调。记住,AAC的采样率在SDP中必须与实际编码参数一致,不能随便写。

3.4 PT值协商的完整流程

为了让大家更直观地理解,我画了一张流程图:

动态PT值协商流程图 发送方 接收方 1. 准备SDP 列出支持的编码 INVITE (SDP) 2. 解析SDP 选择支持的编码 200 OK (SDP) 3. 确认映射 PT ↔ 编码绑定 ACK 4. 开始RTP传输 4. 开始RTP传输 RTP流 (PT=96)

这个流程看起来简单,但实际项目中坑不少。我挑几个常见的说说:

  • PT值冲突:两个不同的编码用了同一个PT值。我遇到过SDP里写了两个rtpmap都指向96,接收端直接崩溃。
  • 时钟频率不匹配:视频编码统一用90000,音频则各不相同。写错时钟频率会导致音画不同步。
  • fmtp参数遗漏:H.264的packetization-mode、profile-level-id这些参数不写,接收端可能无法正确解码。

核心原则:动态PT值协商的本质是“先沟通,再传输”。发送方不能想当然地认为接收方支持某种编码,必须通过SDP交换能力信息。这也是RTP协议设计精妙之处——它把编码格式的协商留给了上层协议,自己只负责传输。

3.5 实际项目中的PT值选择建议

做了这么多年流媒体,我总结了几条PT值选择的经验:

  1. 优先使用96-100:大部分设备默认支持这个范围,兼容性最好
  2. 避免使用127:有些老设备把127当作保留值,可能会出问题
  3. 音频和视频的PT值不要重叠:虽然理论上可以,但调试时容易混淆
  4. 同一个编码的不同参数用不同PT值:方便接收端做能力协商

我的习惯:在项目中,我会固定一套PT值映射表。比如H.264主配置用96,H.264基线配置用97,AAC用98,Opus用99。这样不管是调试还是维护,大家都清楚。团队里新来的同事也不用猜。

好了,关于PT值与编码映射的内容就讲到这里。记住,PT值虽然只有8位,但它承载了编码格式协商的全部信息。搞懂了它,RTP协议就算入门了一半。