4、实战:Wireshark抓包分析:抓取RTP/RTCP数据包、过滤与定位音视频流、解析RTP头部字段、提取RTCP SR包中的同步信息
说实话,很多搞音视频的同学,理论背得滚瓜烂熟,一遇到线上音画不同步就抓瞎。为什么?因为你没亲眼看过RTP包长什么样。
Wireshark就是我们的“音视频显微镜”。今天我就带你亲手抓一次包,把RTP和RTCP的底裤扒干净。嗯,咱们不搞虚的,直接上实战。
本章目标:学会用Wireshark抓取RTP/RTCP数据包,精准定位音视频流,解析RTP头部字段,并从RTCP SR包中提取NTP和RTP时间戳,计算音视频同步所需的绝对时间。
4.1 抓包前的准备工作
我个人习惯,抓包前先做三件事:
- 关闭无关应用——浏览器、下载工具全关,减少噪声包。
- 确定抓包接口——如果你在PC上测试,选连接摄像头或麦克风的网卡;如果在服务器上,选监听端口对应的接口。
- 设置抓包过滤器——别上来就抓全量,包太多你根本看不过来。
我建议直接用这个过滤器:
udp.port == 5004 || udp.port == 5005
5004是RTP默认端口,5005是RTCP默认端口。当然,你的应用可能用别的端口,改一下就行。
小技巧:如果你不确定端口,可以先抓几秒全量包,然后用 rtp 或 rtcp 作为显示过滤器,Wireshark会自动识别RTP流。
4.2 开始抓包与过滤音视频流
好,现在开始抓包。假设你正在开一个视频会议,或者播放一个RTSP流。点击Wireshark的“开始捕获”按钮,等个10-15秒,然后停止。
包已经抓下来了,但里面混杂着各种UDP包。怎么快速找到音视频流?
用这个显示过滤器:
rtp
Wireshark会自动把所有RTP包高亮出来。你会发现,RTP包通常成对出现——一路音频,一路视频。怎么区分?看SSRC(同步源标识符)。
我个人习惯,先统计一下SSRC:
Statistics -> RTP -> Show All Streams
这里会列出所有RTP流,包括SSRC、源地址、目的地址、包数、丢包率。音频流的包通常更小(比如160字节),视频流的包更大(可能1400字节以上)。
注意:如果抓包环境中有NAT或端口转发,源地址可能不是真实发送端。这时候别慌,看SSRC就够了——SSRC在会话期间是唯一的。
4.3 解析RTP头部字段
选中一个RTP包,展开Wireshark底部的RTP协议树。你会看到这样的结构:
Real-Time Transport Protocol
[Stream setup by SDP (frame 1)]
10.. .... = Version: RFC 1889 Version (2)
..0. .... = Padding: False
...0 .... = Extension: False
.... 0000 = Contributing source identifiers count: 0
0... .... = Marker: False
Payload type: DynamicRTP-Type-96 (96)
Sequence number: 12345
Timestamp: 3600
Synchronization Source identifier: 0x3a1b2c3d (975318589)
我来拆解一下每个字段的实际意义:
| 字段 | 长度 | 作用 | 实战注意点 |
|---|---|---|---|
| Version | 2 bits | RTP版本号,目前都是2 | 如果看到版本号不是2,说明包可能被篡改或解析错误 |
| Padding | 1 bit | 是否有填充字节 | 某些加密场景会用,普通流很少见 |
| Extension | 1 bit | 是否有头部扩展 | WebRTC常用扩展,比如abs-send-time |
| CSRC count | 4 bits | 贡献源数量 | 混音场景才有,普通点对点通信为0 |
| Marker | 1 bit | 标记位,通常用于帧边界 | 视频关键帧的第一个包Marker=1 |
| Payload Type | 7 bits | 编码类型标识 | 96-127是动态类型,需要对照SDP |
| Sequence Number | 16 bits | 包序号,检测丢包和乱序 | 每个RTP流独立计数,从随机值开始 |
| Timestamp | 32 bits | 媒体采样时间戳 | 音频和视频的时钟频率不同,不能直接比较 |
| SSRC | 32 bits | 同步源标识符 | 同一路流的所有包SSRC相同 |
这里有个坑,我踩过好几次——Timestamp字段不是绝对时间。音频的时钟频率通常是8000Hz或48000Hz,视频是90000Hz。所以音频的Timestamp增长慢,视频增长快。你直接拿音频的Timestamp和视频的Timestamp比大小?没意义。
那怎么比?得靠RTCP SR包。
4.4 提取RTCP SR包中的同步信息
RTCP SR(Sender Report)包,是RTP流的“时间锚点”。它里面包含了两个关键时间戳:
- NTP Timestamp:绝对时间,从1900年1月1日开始的秒数,64位。
- RTP Timestamp:对应同一时刻的RTP时间戳,32位。
有了这两个值,你就能把RTP时间戳映射到真实世界的时间。说白了,就是给RTP流“对表”。
在Wireshark里,找到RTCP SR包的方法:
rtcp && rtcp.packet_type == 200
展开后,你会看到:
RTCP Sender Report
Packet type: Sender Report (200)
Length: 12 (52 bytes)
SSRC: 0x3a1b2c3d
NTP timestamp: Feb 15, 2025 14:23:45.123456 UTC
RTP timestamp: 1080000
Sender's packet count: 1500
Sender's octet count: 2400000
注意看,NTP Timestamp显示的是人类可读的时间,而RTP Timestamp是1080000。这意味着:当绝对时间是2025年2月15日14:23:45.123456时,视频RTP时间戳是1080000。
音频流也有自己的RTCP SR包。找到音频的SSRC,再找对应的SR包:
rtcp && rtcp.packet_type == 200 && rtcp.ssrc == 0x音频SSRC
假设音频SR包显示:
- NTP: Feb 15, 2025 14:23:45.123456 UTC
- RTP Timestamp: 96000
好了,现在你有了两个流的“时间锚点”。怎么判断音画是否同步?
很简单:
- 从视频流中选一个RTP包,记下它的RTP Timestamp(比如1089000)。
- 计算这个包相对于SR包的RTP时间差:1089000 - 1080000 = 9000。
- 视频时钟频率是90000Hz,所以时间差 = 9000 / 90000 = 0.1秒。
- 从音频流中选一个RTP包,记下它的RTP Timestamp(比如96800)。
- 计算音频时间差:96800 - 96000 = 800。音频时钟频率是8000Hz,时间差 = 800 / 8000 = 0.1秒。
两个流的时间差都是0.1秒,说明它们相对于SR包是同步的。如果视频是0.1秒,音频是0.15秒,那就差了50毫秒——这就是音画不同步的根源。
核心公式:
绝对时间 = SR包的NTP时间 + (当前RTP时间戳 - SR包的RTP时间戳) / 时钟频率
音频时钟频率:8000Hz(PCMU/PCMA)、48000Hz(Opus/AAC)
视频时钟频率:90000Hz(H.264/H.265/VP8/VP9)
4.5 用SVG图梳理核心逻辑
上面讲的内容有点多,我画张图帮你理清思路:
4.6 避坑指南
实战中,有几个坑我反复踩过,今天一并告诉你:
坑1:NTP时间戳的精度问题
RTCP SR包中的NTP时间戳是64位,但Wireshark显示时只精确到微秒。如果你需要纳秒级精度,得自己解析原始字节。不过对于音画同步来说,微秒级已经够了。
坑2:SR包发送频率
RTCP SR包不是每个RTP包都发,通常几秒才发一个。如果你抓包时间短,可能抓不到SR包。我建议至少抓30秒,确保每个流都有至少一个SR包。
坑3:多路流共用一个SSRC?
我曾经遇到一个奇葩设备,音频和视频用了同一个SSRC。这种情况Wireshark会混淆。解决办法:看Payload Type,音频通常是0、8、96等,视频是96-127。如果还分不清,看包大小——音频包小,视频包大。
4.7 小结
今天这一章,我们亲手抓了RTP包,过滤出了音视频流,解析了RTP头部字段,还从RTCP SR包里提取了同步信息。说白了,音画同步的核心就一句话:把RTP时间戳映射到NTP绝对时间,然后比较两个流的时间差。