第二讲:时间戳体系——PTS、DTS、STC 的三角关系

各位同学好,我是老张。今天咱们聊聊机顶盒里最绕不开的一个话题——时间戳体系。

说实话,我刚入行那会儿,也被 PTS、DTS、STC 这三个缩写搞得晕头转向。后来在项目里踩过坑,才真正理解了它们的关系。今天我把这些经验分享给你。

1. 为什么需要时间戳?

你想想看,机顶盒播放视频时,视频流和音频流是分开传输的。如果没有统一的时间基准,画面和声音就会「各说各话」。

我见过一个项目,因为时间戳没处理好,视频播到一半,声音还在放上一段的内容。用户投诉说「这机顶盒是不是坏了?」——其实不是硬件问题,就是时间戳乱了。

所以,时间戳的核心作用就两个:

  • 同步:让音视频在正确的时间点播放
  • 排序:告诉解码器数据包的先后顺序

2. PTS——显示时间戳

PTS 全称是 Presentation Time Stamp,说白了就是「这个画面/声音应该在什么时候显示出来」。

举个例子:

  • 视频帧 A 的 PTS = 1000ms,表示它应该在 1 秒时显示
  • 音频帧 B 的 PTS = 1000ms,表示它应该在 1 秒时播放

当这两个 PTS 对齐时,画面和声音就同步了。

重要概念:PTS 是相对于系统时钟 STC 的。不是绝对时间,而是相对时间。

我在项目中遇到过一个问题:某个码流里视频 PTS 是 33 位计数器,音频 PTS 是 27 位计数器。两者精度不同,直接比较会出错。后来我统一做了归一化处理才解决。

3. DTS——解码时间戳

DTS 全称是 Decoding Time Stamp,表示「这个数据包应该在什么时候开始解码」。

你可能会问:为什么需要 DTS?PTS 不是已经告诉什么时候显示了吗?

嗯,这里要注意。视频编码时,有些帧是参考帧(I 帧),有些是预测帧(P 帧、B 帧)。B 帧需要依赖后面的帧才能解码,所以解码顺序和显示顺序不一样。

举个例子:

  • 显示顺序:I1 → P2 → B3 → P4
  • 解码顺序:I1 → P2 → P4 → B3

你看,B3 虽然显示在 P2 之后,但解码时它需要等 P4 解码完才能解。所以 DTS 和 PTS 就分开了。

我的经验:对于没有 B 帧的码流(比如某些低延迟场景),DTS 和 PTS 是相等的。但只要有 B 帧,两者一定不同。

4. STC——系统时钟

STC 全称是 System Time Clock,它是机顶盒内部的「心跳」。

所有的时间戳都要跟 STC 比较。比如:

  • 当 PTS == STC 时,显示这一帧
  • 当 DTS == STC 时,开始解码

STC 是怎么来的?通常有两种方式:

  1. 本地晶振:机顶盒自己产生 27MHz 时钟
  2. PCR 恢复:从传输流中提取 PCR(节目时钟基准),同步到本地

我建议优先使用 PCR 恢复的方式。因为发送端和接收端的时钟如果不一致,时间长了就会累积误差。我曾经在一个项目中,本地晶振偏差了 50ppm,播了 2 小时后音视频差了 300ms——用户直接投诉了。

5. 时间戳的生成与传递

时间戳的生成通常发生在编码端。编码器在压缩音视频时,会记录每个数据包的 PTS 和 DTS。

传递过程是这样的:

  1. 编码器生成 PTS/DTS,写入码流
  2. 解复用器从码流中提取时间戳
  3. 解码器根据 DTS 调度解码
  4. 显示模块根据 PTS 调度显示

这里有个关键点:时间戳的精度。MPEG-2 标准中,PTS 用 33 位表示,精度是 90kHz 时钟(约 11.1μs)。

参数
时钟频率 90 kHz
PTS 位数 33 位
最大可表示时间 约 26.5 小时
精度 约 11.1 μs

注意:PTS 只有 33 位,大约 26.5 小时会回绕一次。如果你的机顶盒需要长时间运行,必须处理回绕问题。我见过一个 DVR 项目,因为没处理回绕,录了 30 小时的节目,后半段全部不同步。

6. 实战中的时间戳处理

在实际代码中,我们经常需要比较两个 PTS 的大小。但因为有回绕,不能直接比较。

我常用的方法是:

// 判断 pts1 是否早于 pts2(考虑回绕)
bool is_pts_earlier(uint32_t pts1, uint32_t pts2) {
    uint32_t diff = pts2 - pts1;
    // 如果差值小于 2^31,说明 pts1 早于 pts2
    return (diff & 0x80000000) == 0;
}

这个技巧在嵌入式系统里很实用。因为 32 位无符号整数的减法,天然处理了回绕。

我的习惯:在项目中,我会把 PTS 统一转换成 64 位整数,避免回绕问题。虽然多占点内存,但省心很多。

7. 常见问题与避坑指南

最后,我总结几个常见问题:

  • PTS 抖动:编码器生成的时间戳可能不均匀,需要做平滑处理
  • PCR 抖动:传输过程中 PCR 可能被干扰,需要滤波
  • 音视频 PTS 不匹配:可能是解复用器解析错误,也可能是编码器问题

我曾经遇到一个坑:某个码流的音频 PTS 比视频 PTS 慢了 40ms,但用户说「感觉声音滞后」。后来发现是音频解码器内部有缓冲,导致实际播放延迟。最后我们在音频输出路径上做了补偿才解决。

好了,这一讲的内容就到这里。时间戳体系是音视频同步的基石,理解透了,后面的算法实现就水到渠成了。

下一讲,我们会深入音视频同步的三种主流算法,到时候见。