1. 音画同步基础:PTS、DTS、时间基的概念与关系,为什么音画会不同步?
做音视频开发的人,十有八九都被音画不同步折磨过。我自己入行那会儿,第一次处理直播流,画面比声音快了将近两秒,排查了整整一个下午才发现是时间基换算出了岔子。从那以后,我就把 PTS、DTS、时间基这三个概念刻在了脑子里。
说白了,音画同步的核心就一句话:让音频和视频按照正确的时间顺序播放。但要做到这一点,你得先理解 FFmpeg 里用来描述「时间」的那套机制。
1.1 PTS 和 DTS:两个时间戳,各司其职
先看两个最基础的概念:PTS(Presentation Time Stamp) 和 DTS(Decoding Time Stamp)。
- PTS:显示时间戳。告诉解码器「这帧画面应该在什么时候显示给用户」。
- DTS:解码时间戳。告诉解码器「这帧数据应该在什么时候开始解码」。
你可能会问:为什么需要两个时间戳?直接一个 PTS 不就行了?
嗯,这里要注意。在大多数情况下,PTS 和 DTS 是相等的。但一旦遇到 B 帧(双向预测帧),事情就变了。B 帧需要依赖前后的帧才能解码,所以解码顺序和显示顺序不一样。
举个例子: 一个典型的 GOP(图像组)解码顺序是 I → P → B → B → P,但显示顺序是 I → B → B → P → P。DTS 跟着解码顺序走,PTS 跟着显示顺序走。
我在项目中遇到过几次因为 B 帧导致的时间戳错乱。有一次做视频转码,输出文件总是卡顿,查了半天才发现是 DTS 没有按解码顺序重新排列。嗯,从那以后我养成了一个习惯:处理 B 帧时,一定同时检查 PTS 和 DTS。
1.2 时间基(Time Base):时间戳的「刻度尺」
光有 PTS 和 DTS 还不够。你想想看,不同封装格式、不同编码器,它们的时间精度不一样。有的用毫秒,有的用微秒,有的甚至用 1/90000 秒。这时候就需要一个统一的东西来换算——时间基(Time Base)。
时间基本质上是一个分数,比如 1/1000 表示每个时间单位是 1 毫秒,1/90000 表示每个时间单位是 1/90000 秒(MPEG-TS 的常用精度)。
FFmpeg 里用 AVRational 结构体来表示时间基:
typedef struct AVRational {
int num; // 分子
int den; // 分母
} AVRational;
换算公式很简单:实际时间(秒) = PTS × (num / den)。
我的习惯: 拿到一个流之后,第一件事就是打印它的时间基。很多同步问题,根源就是时间基换算错了。
1.3 PTS、DTS、时间基的关系
这三者的关系,可以用一张图来概括。下面是我自己画的一个结构图,帮你理清思路。
从图上可以看得很清楚:时间基是底层刻度,PTS 和 DTS 是上层数值。没有时间基,PTS 和 DTS 就是一堆没有意义的整数。
1.4 为什么音画会不同步?
搞清楚了上面的概念,再来分析音画不同步的原因,就清晰多了。我总结了几种最常见的场景:
| 原因分类 | 具体表现 | 常见场景 |
|---|---|---|
| 时间基不一致 | 音频用 1/1000,视频用 1/90000,直接比较 PTS 数值 | 混流、转封装时未统一时间基 |
| PTS 跳变或回退 | 某帧的 PTS 突然变小或出现负值 | 网络丢包、推流中断后重连 |
| B 帧导致 DTS/PTS 错位 | 解码顺序和显示顺序不一致,未正确处理 | 编码器配置了 B 帧,但解封装时未排序 |
| 音频/视频帧率不匹配 | 音频 44.1kHz,视频 30fps,累积误差越来越大 | 原始素材帧率非标准值 |
| 解码器延迟 | 视频解码耗时 > 音频解码耗时,导致视频滞后 | 高分辨率视频在低性能设备上播放 |
我曾经踩过的坑: 有一次做 RTMP 拉流,音频和视频的 PTS 看起来都正常,但播放就是不同步。后来用 ffprobe 一查,发现音频流的时间基是 1/1000,视频流的时间基是 1/90000。两个流的 PTS 数值直接比较,差了 90 倍。嗯,这种问题最隐蔽,也最容易忽略。
1.5 如何快速排查音画不同步?
给你一个我自己的排查清单,遇到不同步问题时按顺序检查:
- 打印时间基:用
ffprobe -show_streams查看音频和视频的time_base是否一致。 - 检查 PTS 连续性:看 PTS 是否单调递增,有没有跳变或回退。
- 确认 B 帧处理:如果编码器用了 B 帧,确保解封装后按 DTS 排序。
- 计算累积误差:用
PTS × time_base换算成实际秒数,看音频和视频的差值是否在合理范围内(通常 < 100ms 人眼不易察觉)。
一个小技巧: 在 FFmpeg 命令行里加 -vsync 2 或 -async 1 可以强制同步,但治标不治本。真正解决问题,还是要从时间基和 PTS 入手。
好了,这一章的内容就到这里。PTS、DTS、时间基这三个概念,是音画同步的基石。后面的章节里,我们会一步步深入,看看 FFmpeg 具体怎么处理这些时间信息,以及如何用代码实现精准同步。