本文主要描述音视频同步原理,及常见的音视频同步方案,并以代码示例,展示如何以音频的播放时长为基准,将视频同步到音频上以实现视音频的同步播放。
1.音视频同步简单介绍
对于一个播放器,一般来说,其基本构成均可划分为以下几部分: 数据接收(网络/本地)->解复用->音视频解码->音视频同步->音视频输出。 基本框架如下图所示:
为什么需要音视频同步?
媒体数据经过解复用流程后,音频/视频解码便是独立的,也是独立播放的。而在音频流和视频流中,其播放速度都是有相关信息指定的:
视频:帧率,表示视频一秒显示的帧数。
音频:采样率,表示音频一秒播放的样本的个数。
从帧率及采样率,即可知道视频/音频播放速度。声卡和显卡均是以一帧数据来作为播放单位,如果单纯依赖帧率及采样率来进行播放,在理想条件下,应该是同步的,不会出现偏差。
以一个44.1KHz的AAC音频流和24FPS的视频流为例:
一个AAC音频frame每个声道包含1024个采样点,则一个frame的播放时长(duration)为:(1024/44100)×1000ms = 23.22ms;一个视频frame播放时长(duration)为:1000ms/24 = 41.67ms。理想情况下,音视频完全同步,音视频播放过程如下图所示:
但实际情况下,如果用上面那种简单的方式,慢慢的就会出现音视频不同步的情况,要不是视频播放快了,要么是音频播放快了。可能的原因如下:
一帧的播放时间,难以精准控制。音视频解码及渲染的耗时不同,可能造成每一帧输出有一点细微差距,长久累计,不同步便越来越明显。(例如受限于性能,42ms才能输出一帧)
音频输出是线性的,而视频输出可能是非线性,从而导致有偏差。
媒体流本身音视频有差距。(特别是TS实时流,音视频能播放的第一个帧起点不同)
所以,解决音视频同步问题,引入了时间戳:
首先选择一个参考时钟(要求参考时钟上的时间是线性递增的);
编码时依据参考时钟上的给每个音视频数据块都打上时间戳;
播放时,根据音视频时间戳及参考时钟,来调整播放。
所以,视频和音频的同步实际上是一个动态的过程,同步是暂时的,不同步则是常态。以参考时钟为标准,放快了就减慢播放速度;播放快了就加快播放的速度。
接下来,我们介绍媒体流中时间戳的概念。
2.DTS和PTS简介
2.1I/P/B帧
在介绍DTS/PTS之前,我们先了解I/P/B帧的概念。I/P/B帧本身和音视频同步关系不大,但理解其概念有助于我们了解DTS/PTS存在的意义。
视频本质上是由一帧帧画面组成,但实际应用过程中,每一帧画面会进行压缩(编码)处理,已达到减少空间占用的目的。
编码方式可以分为帧内编码和帧间编码。
内编码方式:
即只利用了单帧图像内的空间相关性,对冗余数据进行编码,达到压缩效果,而没有利用时间相关性,不使用运动补偿。所以单靠自己,便能完整解码出一帧画面。
帧间编码:
由于视频的特性,相邻的帧之间其实是很相似的,通常是运动矢量的变化。利用其时间相关性,可以通过参考帧运动矢量的变化来预测图像,并结合预测图像与原始图像的差分