时间戳原理:PTS、DTS、PCR 的概念与关系
做音视频开发,时间戳是绕不开的核心概念。我刚开始接触这块时,总觉得不就是几个时间点嘛,有什么难的?结果第一次做播放器,画面和声音对不上,调试了整整两天。后来才发现,是我对 PTS、DTS、PCR 的理解太表面了。
说白了,时间戳就是给每一帧数据贴上的「时间标签」。没有它,解码器不知道什么时候该干活,渲染器不知道什么时候该显示。整个系统就乱套了。
2.1 三个核心时间戳
我们先看三个最基础的概念。我习惯用一个比喻来理解它们:
- PTS(显示时间戳) —— 告诉渲染器:这一帧什么时候显示
- DTS(解码时间戳) —— 告诉解码器:这一帧什么时候解码
- PCR(节目时钟基准) —— 告诉整个系统:现在是什么「标准时间」
你想想看,如果只有 PTS 没有 DTS,遇到 B 帧就麻烦了。解码器得先解码后面的帧,才能得到前面的帧。这时候解码顺序和显示顺序不一样,必须靠 DTS 来调度。
关键点:PTS 和 DTS 的单位都是 90kHz 时钟周期,也就是 1/90000 秒。这是 MPEG 标准里定死的,别问为什么,记住就行。
2.2 PTS 与 DTS 的关系
我记得第一次看 H.264 码流分析时,发现 PTS 和 DTS 的值不一样,当时就懵了。后来才明白,这是视频编码的「帧类型」导致的。
视频帧分三种:
| 帧类型 | 全称 | PTS 与 DTS 关系 | 说明 |
|---|---|---|---|
| I 帧 | 关键帧 | PTS = DTS | 独立解码,不需要参考其他帧 |
| P 帧 | 前向预测帧 | PTS = DTS | 只参考前面的 I 或 P 帧 |
| B 帧 | 双向预测帧 | PTS ≠ DTS | 需要参考前后帧,解码顺序和显示顺序不同 |
为什么会这样?因为 B 帧要参考后面的帧才能解码。比如显示顺序是 I1 → B2 → P3,但解码顺序必须是 I1 → P3 → B2。这时候:
- I1 的 DTS = 1,PTS = 1
- P3 的 DTS = 2,PTS = 3
- B2 的 DTS = 3,PTS = 2
你看,B 帧的 DTS 比 PTS 大。解码器先解 P3,但显示时要等 B2 先出来。这就是为什么播放器必须同时维护两个队列:解码队列和显示队列。
实战经验:我在做低延迟直播时,发现如果 GOP 里 B 帧太多,解码器压力会很大。后来我建议编码器只用 I 帧和 P 帧,虽然压缩率低了一点,但延迟降了 30%。
2.3 PCR:系统的「时钟源」
PCR 是节目时钟基准,它不像 PTS/DTS 那样跟具体帧绑定,而是作为一个独立的时间参考信号,周期性地插入到传输流中。
我打个比方:PTS 和 DTS 是每个乘客的「登机时间」,PCR 是机场的「标准时钟」。所有乘客都要对照这个时钟来安排自己的时间。
PCR 的作用有两个:
- 同步解码器时钟 —— 接收端用 PCR 来校准自己的本地时钟,保证和发送端一致
- 作为 PTS/DTS 的参考 —— 解码器比较 PTS 和当前 PCR,决定什么时候解码/显示
PCR 的插入频率有严格规定:至少每 100ms 一次,精度要求 27MHz。为什么是 27MHz?因为 MPEG 系统的系统时钟就是 27MHz,PCR 就是从这个时钟派生出来的。
注意:PCR 的抖动(jitter)不能超过 ±500ns。如果 PCR 不稳定,接收端的时钟锁相环(PLL)就会失锁,导致音画不同步。我曾经遇到过一个机顶盒播放 10 分钟后声音越来越快,最后查出来是编码器 PCR 插入间隔不均匀。
2.4 三者的协作流程
我们用一个完整的播放流程来看它们怎么配合:
- 解复用器从传输流中提取 PCR,更新本地系统时钟
- 解复用器把音视频包分别送入各自的解码缓冲区
- 解码器检查每个包的 DTS,到了就解码
- 解码后的帧放入显示缓冲区,等待 PTS 到达
- 渲染器比较 PTS 和当前 PCR,到了就显示
这个流程里,PCR 是「裁判」,PTS 和 DTS 是「运动员」。裁判的哨声(PCR)决定了运动员什么时候起跑(解码/显示)。
下面这张图展示了三者的关系:
2.5 常见问题与避坑
在实际项目中,时间戳相关的问题特别多。我挑几个最常见的说说:
- PTS 回绕 —— 时间戳是 33 位计数器,最大值约 26.5 小时。超过后会归零。播放器如果没处理好,音画会突然错位。我建议用有符号比较,或者检测差值是否超过半周期。
- PCR 不连续 —— 有些编码器在码流切换时 PCR 会跳变。接收端 PLL 会失锁,导致几秒钟的卡顿。解决办法是在切换点插入 PCR 重置标志。
- 音视频 PTS 偏差 —— 理想情况下音频和视频的 PTS 应该对齐,但实际编码器可能偏差几十毫秒。播放器需要做「音画同步补偿」,一般以音频为基准,微调视频的显示时间。
我的习惯:在调试阶段,我会把每个帧的 PTS、DTS、当前 PCR 都打印出来,画成时间线图。一眼就能看出哪里出了问题。这个习惯帮我解决过至少 5 个棘手的同步问题。
2.6 小结
PTS、DTS、PCR 是音画同步的三大基石。PTS 告诉系统「什么时候显示」,DTS 告诉系统「什么时候解码」,PCR 告诉系统「现在是什么时间」。三者缺一不可。