音视频同步
主要解析:以音频为基准,让视频合成音频
思路
-
视频慢了则丢掉部分视频帧(视觉->画⾯跳帧)
-
视频快了则继续渲染上⼀帧
具体实现
一个国际标准:音频帧-视频帧时间戳的差值在-100ms~25ms内流畅
1.差值=音频播放时间戳-视频播放时间戳----diff=pts_audio-pts_video(注意区分!!)
2.判断逻辑:
(无法感知区间:min=-125ms,max=45ms)
- max<diff:画后音前,视频落后了,丢帧不渲染(赶进度),直接下一帧
- min<diff<max:正常渲染
- diff<min:画前音后,视频超前了,持续显示当前帧,
视频播放线程先睡会_阻塞:sleep(diff-max)
然后继续渲染当前视频帧
ffplay具体源码
c
/* if video is slave, we try to correct big delays by
duplicating or deleting a frame
通过重复帧或者删除帧来纠正延迟*/
diff = get_clock(&is->vidclk) - get_master_clock(is);
/* skip or repeat frame. We take into account the
delay to compute the threshold. I still don't know
if it is the best guess */
sync_threshold = FFMAX(AV_SYNC_THRESHOLD_MIN,
FFMIN(AV_SYNC_THRESHOLD_MAX, delay));
if (!isnan(diff) && fabs(diff) < is->max_frame_duration) { // diff在最大帧duration内
if (diff <= -sync_threshold) { // 视频已经落后了
delay = FFMAX(0, delay + diff); // 上一帧持续的时间往小的方向去调整
}
else if (diff >= sync_threshold && delay > AV_SYNC_FRAMEDUP_THRESHOLD) {
// 视频超前
delay = delay + diff; // 上一帧持续时间往大的方向去调整
av_log(NULL, AV_LOG_INFO, "video: delay=%0.3f A-V=%f\n",
delay, -diff);
}
else if (diff >= sync_threshold) {
// 上一帧持续时间往大的方向去调整
delay = 2 * delay; // 保持在 2 * AV_SYNC_FRAMEDUP_THRESHOLD内, 即是2*0.1 = 0.2秒内
} else {
// 音视频同步精度在 -sync_threshold ~ +sync_threshold
// 其他条件就是 delay = delay; 维持原来的delay, 依靠frame_timer+duration和当前时间进行对比
}
}