3. RTP负载类型与编码映射:PT值与编码格式对应关系
聊到RTP,有个东西你绕不开——负载类型(Payload Type,PT)。说白了,它就是RTP包里的一个“标签”,告诉接收方:“嘿,我这包里装的是H.264视频,还是AAC音频?”
我刚开始接触RTP时,总觉得PT就是个数字而已。直到有一次调试一个视频通话系统,画面死活出不来,抓包一看——PT值对不上。嗯,从那以后我再也不敢小看这个字段了。
3.1 PT字段:RTP包的“身份证”
RTP头部里有个7位的PT字段,取值范围0-127。它决定了接收端怎么解析这个包里的数据。
你想想看,如果发送端说“这是H.264”,接收端却按MPEG-2去解码,那画面肯定花掉。所以PT值的映射必须双方约定好。
核心要点:PT值就是编码格式的“代号”。发送端填什么,接收端就得按什么解。两边不一致,通信就崩。
3.2 静态负载类型:0-95,RFC定义的“老规矩”
PT值0-95属于静态负载类型。这些值在RFC 3551里写死了,比如PCMU是0,PCMA是8,GSM是3。你只要看到PT=0,就知道是G.711 μ-law音频,不用猜。
但这里有个坑——静态类型只覆盖了最老的那批编码格式。H.264、AAC、Opus这些“新贵”都不在里面。为什么?因为RFC 3551是2003年的东西,那时候H.264还没普及呢。
| PT值 | 编码格式 | 时钟频率(Hz) | 声道数 |
|---|---|---|---|
| 0 | PCMU (G.711 μ-law) | 8000 | 1 |
| 3 | GSM | 8000 | 1 |
| 4 | G.723 | 8000 | 1 |
| 8 | PCMA (G.711 A-law) | 8000 | 1 |
| 10 | L16 (线性PCM 16位) | 44100 | 2 |
| 14 | MPA (MPEG-1/2 Audio) | 90000 | 1 |
| 26 | JPEG (Motion JPEG) | 90000 | - |
| 31 | H.261 | 90000 | - |
| 32 | MPV (MPEG-1/2 Video) | 90000 | - |
| 34 | H.263 | 90000 | - |
个人经验:我在做VoIP网关时,经常要处理PT=0和PT=8的转换。国内用PCMA多,国外用PCMU多。两边不通时,抓包一看PT值就明白了。
3.3 动态负载类型:96-127,现代编码的“自留地”
PT值96-127是动态负载类型。说白了,就是留给应用自己定义的。H.264、AAC、Opus、VP8、VP9……这些现代编码格式都用这个范围。
为什么叫“动态”?因为同一个PT值在不同会话里可能代表不同编码。比如这次通话PT=96是H.264,下次通话PT=96可能是VP8。全靠SDP协商时约定。
我见过不少新手踩的坑:写死PT=96表示H.264,结果对方用PT=96传AAC,解码直接崩。记住——动态类型必须通过SDP协商,不能硬编码。
| PT值范围 | 类型 | 特点 | 典型编码 |
|---|---|---|---|
| 0-95 | 静态 | RFC定义,全局固定 | PCMU、PCMA、GSM、H.261 |
| 96-127 | 动态 | SDP协商,会话内有效 | H.264、AAC、Opus、VP8 |
3.4 常用编码格式的PT值:实战中的“熟面孔”
下面这几个PT值,你在实际项目中几乎天天见。我按使用频率排个序:
3.4.1 H.264 — 视频编码的“扛把子”
H.264没有静态PT值,通常用96-102之间的值。我在WebRTC项目里,H.264的PT值最常见的是96或100。但记住——这不是标准,全靠SDP里写:
// SDP中H.264的典型声明
m=video 5004 RTP/AVP 96
a=rtpmap:96 H264/90000
a=fmtp:96 packetization-mode=1;profile-level-id=42e01f
这里96就是动态分配的。时钟频率90000是视频的“老传统”,所有视频编码都用这个值。
3.4.2 AAC — 音频编码的“音质担当”
AAC在RTP里通常用96-127之间的值。但要注意——AAC有好几种变体:AAC-LC、AAC-HE、AAC-LD。我在做直播项目时,AAC的PT值常用97或98:
// SDP中AAC的典型声明
m=audio 5006 RTP/AVP 97
a=rtpmap:97 MPEG4-GENERIC/48000/2
a=fmtp:97 streamtype=5;profile-level-id=1;mode=AAC-hbr;sizelength=13;indexlength=3;indexdeltalength=3
这里48000是采样率,2是声道数。fmtp那串参数看着复杂,其实就是告诉接收端AAC的打包细节。
避坑指南:我曾经在AAC的PT值上吃过亏。对方SDP里写PT=97是AAC,但实际发的是AAC-LD(低延迟版)。我的解码器只支持AAC-LC,结果音频全是噪声。后来我养成了习惯——不光看PT值,还要看fmtp里的profile-level-id。
3.4.3 Opus — 新时代的“全能选手”
Opus是WebRTC的“亲儿子”,PT值通常用111或112。它的时钟频率固定是48000Hz:
// SDP中Opus的典型声明
m=audio 5008 RTP/AVP 111
a=rtpmap:111 opus/48000/2
a=fmtp:111 minptime=10;useinbandfec=1
Opus有个好处——它自带前向纠错(FEC)。minptime=10表示最小打包时长10ms,useinbandfec=1开启带内FEC。我在弱网环境下特别喜欢用Opus,丢包30%还能听清。
3.5 编码映射的核心逻辑:一张图看懂
下面这张图展示了PT值从SDP协商到RTP收发的完整流程:
3.6 实战中的PT值选择建议
说了这么多理论,来点实际的。我在多个项目里总结了几条PT值选择的原则:
- 视频优先用96-100:H.264、H.265、VP8、VP9都往这个范围放。我习惯把H.264放96,VP8放97,这样排查时一眼能认出来。
- 音频优先用111-116:Opus放111,AAC放112,PCMU/PCMA用静态值0和8。这个范围跟WebRTC默认值一致,兼容性好。
- 避免用127:有些老设备把127当保留值,用了可能出问题。我吃过这个亏,后来再也不用127了。
- SDP里必须写rtpmap:动态类型不写rtpmap,接收端根本不知道PT对应什么编码。这是新手最容易犯的错误。
我的习惯:每次搭建新系统,我都会先写一份PT值分配表,贴在项目文档里。比如:PT=96 H.264视频,PT=111 Opus音频,PT=112 AAC音频。团队里所有人都按这个来,省得后期排查时抓瞎。
3.7 常见问题与排查思路
最后分享几个我遇到过的PT值相关故障,你以后八成也会碰到:
| 现象 | 可能原因 | 排查方法 |
|---|---|---|
| 视频黑屏,音频正常 | 视频PT值映射错误,解码器不匹配 | 抓包看RTP的PT值,对比SDP中的rtpmap |
| 音频噪声或静音 | AAC的profile-level-id不匹配 | 检查fmtp参数,确认AAC变体一致 |
| 双方SDP交换正常,但媒体不通 | 动态PT值冲突,两个编码用了同一个PT | 检查SDP中是否有重复的PT值 |
| WebRTC通话中突然断流 | Opus的minptime设置不一致 | 确认双方minptime相同,建议都用10ms |
嗯,PT值这块内容就这些。说白了就是“协商-映射-收发”三个步骤。你只要记住:静态类型看RFC,动态类型看SDP,大部分问题都能解决。