音视频同步:时间戳与缓冲区
画面与声音为什么会渐渐走散?从 PTS、时钟选择和缓冲策略,理解播放器里的时间。
我们习惯把视频理解成连续播放的一组图片,但播放器真正处理的是带有时间信息的流。声音和画面各有节奏,解码耗时也会变化。如果简单地“解出一帧就画一帧”,在某些输入上看似正常,在另一些输入上却会越播越不同步。理解时间戳,是建立正确同步策略的起点。
时间戳不是帧编号
PTS 表示展示时间,DTS 表示解码时间。在存在帧重排序的编码中,两者可能不同。时间戳还需要结合 time base 才有实际意义:一个数值并不天然表示毫秒。跨流比较时间之前,应当先换算到统一的时间单位,避免整数精度与舍入带来逐渐积累的偏差。
不要用固定帧率乘帧编号去替代真实 PTS,尤其是在可变帧率内容中。跳转后也不能沿用上一次的展示基准,应当等待新的有效时间戳并重新建立时钟关系。把“媒体时间”和“系统单调时间”分别命名,能减少很多隐蔽的单位错误。
先选一只可信的主时钟
常见策略以音频时钟为主,因为音频设备按照稳定的采样节奏消耗数据,而视频帧可以适度延迟或丢弃。没有音频时,可以使用外部单调时钟作为基准。音频时钟并不等于“已经送到设备的采样数量”,还需要扣除尚在设备缓冲区中的数据。
音频时钟 = 已提交音频的结束时间 - 设备中尚未播放的时长
视频偏差 = 当前视频帧 PTS - 音频时钟
偏差较小:按正常节奏展示
视频领先:稍后展示,等待主时钟
视频落后:根据阈值丢弃过期画面
缓冲区是在用延迟交换稳定
更大的缓冲区能吸收解码与网络波动,但也增加了响应延迟。点播、实时通话和本地预览的目标不同,不能套用同一组容量。最好按时间预算而不是仅按帧数量限制队列,因为不同内容的帧率、分辨率和解码成本可能相差很大。
把同步问题变成可观察的数据
记录音视频偏差分布、丢帧数量、队列时长和音频欠载次数,比只观察一段视频更有帮助。测试时覆盖可变帧率、长时间播放、暂停恢复、倍速与多次跳转。缓慢增加的偏差常与时间单位或时钟估计有关,突然跳变则可能来自队列未清理或时间戳不连续。
先统一时间单位,再明确主时钟,最后按预算设计缓冲。这几个看起来朴素的选择,往往比不断调整延迟常量更能解决真正的问题。
感谢阅读,希望这些思考对你有所启发。