一、为什么需要音视频同步
1、视频显示和音频播放运行在两个不同的线程,线程调度由操作系统控制,所以计算帧的播放时长时难以精准控制。
2、音视频解码及渲染的耗时不同,可能造成每一帧输出有细微差距,长久累计,不同步会越来越明显。
二、如何音视频同步?
为了解决音视频同步问题,引入了时间戳。首先选择一个参考时钟(要求参考时钟上的时间是线性递增的)。编码时依据参考时钟给每个音视频数据块都打上时间戳;播放时,再根据音视频时间戳及参考时钟,来调整播放。所以,视频和音频的同步实际上是一个动态的过程,同步是暂时的,不同步则是常态。以参考时钟为标准,放快了就减慢播放速度;播放快了就加快播放的速度。
一般来说有以下三种同步策略:
将视频同步到音频上:就是以音频的播放速度为基准来同步视频,ffplay默认的同步机制。
将音频同步到视频上:就是以视频的播放速度为基准来同步音频,一般不常用。
将视频和音频同步到外部的时钟上:选择一个外部时钟为基准,视频和音频的播放速度都以该时钟为标准。
当播放源比参考时钟慢,则加快其播放速度,或者丢弃;快了,则延迟播放。
这三种是最基本的策略,考虑到人对声音的敏感度要强于视频,频繁调节音频会带来较差的观感体验,且音频的播放时钟为线性增长,所以一般会以音频时钟为参考时钟,视频同步到音频上。在实际使用时基于这三种策略会做一些优化调整。
例如:调整策略可以尽量采用渐进的方式,因为音视频同步是一个动态调节的过程,一次调整让音视频PTS完全同步,没有必要,也不现实,且可能导致异常播放较为明显。实际操作中,一般保持音视频差异在一个范围内即可认为同步,这个范围被称为同步阈值。
三、时钟的概念
可以把音频时钟和视频时钟看作两个手表,音频时钟的更新是在sdl_audio_callback()中,每次回调一次函数更新一下音频时钟的pts,当然不更新pts时手表也是在跑的。视频时钟的更新是在video_refresh()中,默认每隔0.01秒检查一次两块手表的差异,来不断调整视频的时钟,使两者的差异控制在同步阈值内。
1、时钟结构体Clock
typedef struct Clock {
double pts; // 时钟基础, 当前帧(待播放)显示时间戳,播放后,当前帧变成上一帧
// 当前pts与当前系统时钟的差值, audio、video对于该值是独立的
double pts_drift; // clock base minus time at which we updated the clock
// 当前时钟(如视频时钟)最后一次更新时间,也可称当前时钟时间
double last_updated; // 最后一次更新的系统时钟
double speed; // 时钟速度控制,用于控制播放速度
// 播放序列,所谓播放序列就是一段连续的播放动作,一个seek操作会启动一段新的播放序列
int serial; // clock is based on a packet with this serial
int paused; // = 1 说明是暂停状态
// 指向packet_serial
int* queue_serial; //指向对应PacketQueue的序列号 用于过时时钟检测
} Clock;
Clock结构体记录了时钟的各个字段,用于设置时钟和读取时钟。以下是各字段的含义
pts:帧的显示时间戳,单位是秒(代码中根据时间基换成秒)
pts_drift:重要字段,c->pts - c->last_updated,是个很大的负数。理解为pts相对更新时间(系统时间)的偏移值。这个值的作用是在读取时间时,计算pts更新后经过了多少秒,来预估当前的时钟值。比如系统时间10点时更新了pts为10秒,那么过了5秒后去读取时钟,时钟应该为15秒。下面是ffplay读取时钟时的计算逻辑,c->speed默认为1。
static double get_clock(Clock *c)
{
if (*c->queue_serial != c->serial)
return NAN;
if (c->paused) {
return c->pts;
} else {
double time = av_gettime_relative() / 1000000.0;
return c->pts_drift + time - (time - c->last_updated) * (1.0 - c->speed);
}
}
last_updated:最近一次更新时钟的系统时间戳
c->pts_drift为c->pts - last_updated(最近一次更新时钟的系统时间戳),c->speed初始为1.0,所以上面的代码简化为c->pts_drift + time= c->pts - last_updat

最低0.47元/天 解锁文章
1725

被折叠的 条评论
为什么被折叠?



