1、音视频同步基础概念:PTS、DTS、时间基与音画不同步的宏观分类
做音频同步问题定位,第一件事不是拿工具抓波形,而是先把脑子里的概念对齐。我见过太多工程师拿着日志说“PTS 跳了”,但问他 PTS 和 DTS 到底谁管谁,说不清楚。嗯,这章我们就先把地基打牢。
1.1 时间基:一切同步的锚点
时间基(Time Base)说白了就是一把尺子。多媒体文件里的时间戳,都是用这把尺子量出来的。常见的尺子有毫秒(ms)、微秒(μs),还有 MPEG 时代留下的 90kHz 时钟。
为什么是 90kHz?
90kHz 是 MPEG 标准里定义的系统时钟频率。它刚好能被常见的视频帧率整除:24、25、30、50、60。这样算 PTS 的时候不会出现小数,避免精度丢失。我在项目中遇到过用 100kHz 做时间基的私有封装,结果每帧都差 0.1 微秒,半小时后音画偏了 3 帧——这种坑踩一次就记住了。
| 时间基 | 精度 | 常见场景 |
|---|---|---|
| 1/90,000 秒(90kHz) | ≈ 11.1 μs | MPEG-TS、H.264/H.265 封装 |
| 1/1,000 秒(毫秒) | 1 ms | RTMP、FLV、MP4 部分工具链 |
| 1/10,000,000 秒(100ns) | 100 ns | Windows Media、DirectShow |
你想想看,如果视频用 90kHz,音频用毫秒,两个时间戳直接做减法,结果一定是乱的。所以第一步永远是确认时间基是否统一。
1.2 PTS 与 DTS:两个时间戳,各管各的事
PTS(Presentation Time Stamp)是“什么时候该显示”。DTS(Decoding Time Stamp)是“什么时候该解码”。对于大部分音频帧来说,PTS 等于 DTS,因为音频帧之间没有依赖关系。但视频不一样——尤其是 B 帧存在的时候。
个人习惯:我排查同步问题时,永远先看 PTS。DTS 乱了一般是编码器或解复用器的问题,但 PTS 乱了一定会直接体现在音画不同步上。
举个例子,一个 GOP 结构是 I-B-P-B-P,解码顺序是 I-P-B-P-B,但显示顺序是 I-B-P-B-P。这时候 DTS 和 PTS 就不一样了。如果解复用器把 DTS 当成 PTS 送出去,画面就会提前或延迟显示。
// 伪代码:PTS 与 DTS 的关系
// 假设帧率 30fps,时间基 90kHz
frame_0 (I): DTS = 0, PTS = 0
frame_1 (B): DTS = 3000, PTS = 3000 // 实际显示在 frame_2 之前
frame_2 (P): DTS = 1500, PTS = 6000 // 解码早,显示晚
frame_3 (B): DTS = 4500, PTS = 9000
frame_4 (P): DTS = 6000, PTS = 12000
你看,DTS 是单调递增的,但 PTS 不是。如果播放器按 DTS 送显,B 帧就全乱了。
1.3 音画不同步的宏观分类
我把实际项目中遇到的同步问题分成三类。这样分类不是为了学术,是为了快速定位——拿到问题先对号入座。
- 固定偏移型:音频始终比视频快 N 毫秒,或者始终慢 N 毫秒。原因通常是封装时时间基没对齐,或者某个环节做了固定延迟补偿。
- 渐进漂移型:刚开始是同步的,播放 10 分钟后开始偏,越偏越多。这是采样率偏差或时钟漂移的典型症状。
- 随机跳变型:音画时而同步,时而突然错位,过一会儿又自己恢复。这种最头疼,通常是网络抖动、丢帧重传、或者解复用器 PTS 处理逻辑有 bug。
我曾经遇到一个直播项目,音频始终比视频慢 200ms。排查了两天,最后发现是音频采集设备内部做了 200ms 的降噪缓冲,但 SDK 没把这个延迟告诉封装层。嗯,从那以后我养成了一个习惯:任何音频设备接入,先测端到端延迟。
下面这张图可以帮你快速理解三类问题的区别:
1.4 时间戳的连续性检查
拿到一个不同步的流,我第一件事就是拉 PTS 曲线。不是看绝对值,而是看差值。音频 PTS 差值应该等于音频帧时长,视频 PTS 差值应该等于视频帧间隔。如果差值忽大忽小,那问题大概率出在封装或传输环节。
一个小技巧:用 ffprobe 把 PTS 导出来,扔到 Excel 里画折线图。斜率稳定的就是正常的,斜率突变的地方就是问题点。我靠这个方法在半小时内定位过一个直播推流 SDK 的 PTS 重置 bug。
# 导出视频帧 PTS 到文本
ffprobe -v error -select_streams v:0 -show_entries frame=pkt_pts_time -of csv=p=0 input.mp4 > video_pts.txt
# 导出音频帧 PTS
ffprobe -v error -select_streams a:0 -show_entries frame=pkt_pts_time -of csv=p=0 input.mp4 > audio_pts.txt
然后计算相邻帧的 PTS 差值。如果视频是 30fps,理想差值应该是 33.33ms。如果出现 66ms 或 16ms,说明有丢帧或重复帧。音频同理,48kHz 采样率、每帧 1024 个采样,理想差值应该是 21.33ms。
1.5 小结
这一章我们聊了时间基、PTS、DTS 和同步问题的宏观分类。说白了,同步问题的根因就两个:时间戳算错了,或者时间戳用错了。后面的章节我们会深入每个环节,从采集到渲染,一步步拆解。
嗯,概念部分就到这里。记住一句话:先确认时间基,再检查 PTS 连续性,最后对号入座找分类。这三步走完,80% 的问题已经能定位到方向了。