在前面的文章中,我们介绍了播放器的视频渲染及音频渲染的相关知识,这些都是单独进行的,一旦在现实开发中将视频及音频结合在一起播放就会出现音视频不同步的问题。

下面我们就来分析一下如何解决音视频同步的问题。

如果简单的按照音频的采样率与视频的帧率去播放,由于机器运行速度,解码效率等种种造成时间差异的因素影响,很难同步,音视频时间差将会呈现线性增长。

三种同步策略

业界对于音视频同步一般是三种策略:

1、 以外部时钟为参考对象,将音频和视频同步到此时间  

对于以前在学校物理课堂中学习的参照物相关知识,我想大多数同学首先想到的多是这种方式。
但是因为人对声音的变化的敏感度比对视觉变化的敏感度大得多,所以如果使用这种方式频繁去调整音频的的话可能会产生一些沙沙或刺耳的杂音,这是很影响用户体验的。

但也不是说这种方式很不好,只是不太适用于单个音视频的同步而已,但是对于多路音视频的同步则比较适用了。

2、 以视频为基准,音频去同步视频的时间

这个方案就是以视频时间为基准,判断音频快了还是慢了,从而调整音频的播放速度,其实是一个动态的追赶与等待的过程。但是前面说了人体对于声音的变化太敏感,而对于画面的变化不太敏感,
而这个方案也是需要频繁调整音频的,所以这种方案并没有太好的效果。

3、 以音频为基准,视频去同步音频的时间

这个方案的原理刚好与方案2的原理相反。就是以音频时间为基准,判断视频是快了还是慢了,从而调整视频的播放速度。因为人体对于画面的变化不太敏感,所以在同步的过程如果视频轻微等待或者丢掉一些画面帧也不太影响观看体验。
因而这个方案最合适。

实际上音视频不可能做到完全的同步,这就是一个你追我赶的过程,我们能做到的只是尽可能的同步,结合热的感官敏感性选出较为合适的方案。

主要伪代码如下:

        // 获得 相对播放这一段数据的秒数
double audioClock = audioFrame->pts * av_q2d(time_base);


//获得 当前这一个画面 播放的相对的时间
double videoClock = frame->best_effort_timestamp * av_q2d(time_base);
//额外的间隔时间
double extra_delay = frame->repeat_pict / (2 * fps);
// 视频真实需要的间隔时间
double delays = extra_delay + frame_delays;

if(videoClock == 0){
//正常播放
av_usleep(delays * 1000000);
}else{

// 比较音频和视频到底谁快了

double diff = delays - audioClock;

if(diff > 0){

// 视频快了,视频需要等待音频
av_usleep((delays + diff) * 1000000);

}else if(diff < 0){

// 音频快了,视频需要丢包
// 这里主要丢包只能丢掉P帧和B帧,不能丢掉I帧关键帧
}

}

如果在实践中发现同步效果不好,建议参考github上面的ffmpeg开源项目中的ffplay.c源码,看看ffplay是如何进行同步的。  

最后如果你对音视频开发感兴趣可扫码关注,后续我们共同探讨,共同进步

ffmpeg音视频同步的几种策略_音视频同步


扫码关注公众号【音视频开发进阶】,一起学习多媒体音视频开发~~~

ffmpeg音视频同步的几种策略_音视频开发_02


喜欢就点个吧 ▽