音视频同步基础知识—ffplay.c源码分析

作者:罗上文,微信:Loken1,公众号:FFmpeg弦外之音

之前的文章,已经把音频,视频的 解码线程,播放线程通通讲了一遍,现在到了播放器实现最复杂的功能之一,就是音视频同步。

FFplay 支持 3 种同步方式,如下:

1,以音频时钟为主时钟,默认方式。

2,以视频时钟为主时钟。

3,以外部时钟为主时钟。

因为音频流的连续性非常强,例如一秒需要播放 48000 个样本。而视频流通常1秒只需播放 24 帧。而且人的耳朵对音频特别敏感。

所以第一种方式以音频时钟为准是最常用的,其他两种方式几乎没有应用场景。


先普及一下音视频同步的一些基本概念。

1,为什么需要进行音视频同步?

答:由于计算机系统大部分是分时系统,所以当负载过高或者设备性能差的时候,音频播放线程 或者 视频播放线程会卡顿,调度不过来,导致视频画面已经更新了,但是声音还没放出来。这种不同步的差异如果越积越大,就会明显体验不好。典型的场景就是,演讲视频里面的口型跟声音。

2,如何把音频播放 跟 视频播放做到完全同步?

答:无法做到,音频与视频的播放,几乎不能完全同步,不信你可以用 FFplay 播放一个视频试试,控制台输出的 A-V 大多数时间都不是 0 。完全同步的话 A-V 就是 0。

1-4

通常我们只需要把音视频不同步的程度,控制在一个合理的阈值内 就可以了。人的感官没有那么敏感的,只要在阈值内,就感受不到不同步了。

虽然不同步是常态,但是感受不到就不算是了。

3,如果只有视频流,没有音频流,如何进行同步?

答:不需要进行同步,只有音频流跟视频流同时播放的时候才需要同步。


由于每一个音频样本就打一个 pts 过于繁琐与麻烦,而且音视频不需要完全同步,控制在阈值内即可。所以大部分音频标准会把多个样本塞进去一个帧,只对一个帧打 PTS 即可。对于 aac 来说,通常一个 AVFrame 里面有 1024 个音频样本。

因此,如果采样率是 48000 每秒,那一帧音频(AVFrame)可以播放 0.021s。

无论是音频还是视频,播放的逻辑都是,在预定的时间(pts)播放对应的 AVFrame

还是以 juren-30s.mp4 为例,它的帧率是 1/24,采样率是 1/48000。也就是每隔0.041s 播放一帧视频,每隔 0.021s 播放一帧音频。

因此这个文件的播放过程应该如下图:

1-1

上面的流程图是,在下午2点整的时候,播放 juren-30s.mp4 文件,那在 14:00:00 的时候就会播放第一帧视频跟第一帧音频。按照预定的时间 pts,第四帧视频应该在 14:00:00:123 的时刻播放,第 7 帧音频差不多也需要播放,所以算同时播放第 7 帧音频吧。

补充:第7帧音频预定播放时间是 14:00:00:126,有一点点误差,但是为了方便讲解,我假设第七帧的预定时间是 14:00:00:123

假如,计算机突然打开另一个软件,做了大量计算,导致视频播放线程没及时调度过来,从而导致 第四帧视频在 14:00:00:143 的时刻才播放,因此视频流就比预定的时候 14:00:00:123 慢了 0.02s。

那是不是就说明音视频开始不同步了?

不是,视频帧不在预定的时间播放,不代表音视频不同步。因为音频帧也可能不在预定的时间播放,假设音频播放线程也没有及时调度过来,也是在第 14:00:00:143 的时刻才播放第 7 帧音频。

那在 14:00:00:143 这一刻,音视频就是完全同步的,虽然他们没有在预定的时间播放。


再假设一个场景,系统卡顿,导致第四帧视频在 14:00:00:153 的时刻才播放,但是音频播放线程卡顿没那么严重,在 14:00:00:136 的时候已经开始播放第 7 帧了。

对应视频流, 14:00:00:153 比预定的时间 14:00:00:123 慢了 0.03s,那是不是就说明视频比音频慢了 0.03s?

也不是,因为 音频流本来应该在 14:00:00:126 的时刻播放第 7 帧,但到了 14:00:00:136 才播放第 7 帧,音频也慢了 0.01s。

正确的描述是,视频流比预定的时间慢了 0.03s,音频流比预定的时间慢了 0.01s,预定的时间可以对消掉,所以,计算过程如下:

视频pts - 预定时间 = 0.03
音频pts - 预定时间 = 0.01
视频pts - 音频pts = 0.02

现在已经计算出 音频 跟 视频 的时间差,但是以音频为主时钟 跟 与 视频为主时钟又有什么区别呢?无论以哪个为主时钟,时间差都是一样的啊?

答:没错,时间差都是一样的。

以音频为主时钟的逻辑是这样,按 juren-30s.mp4 的 pts 来说,在听到 第 7 帧音频的第一个样本的时候,你的眼睛就应该同时看到第 4 帧视频画面。

第 7 帧音频 跟 第 4 帧视频应该在同一时刻播放,假设音频播放线程卡顿,在 14:00:00:153 的时候才播放第7帧音频,但是视频播放线程无卡顿,那 14:00:00:123 的时候,视频播放线程本来应该去取第四帧视频播放,但是由于第7帧音频还未播放,所以第三帧视频需要继续显示0.03s,等待音频。

这就是以音频为主时钟的逻辑,拉长或者缩短视频帧的播放时长,或者丢弃视频帧。

如果是以视频为主时钟的情况,那在 14:00:00:123 的时候,视频播放线程就正常去取第四帧播放就行,因为确实已经到了第四帧播放的时间点,音频慢了,就缩短音频帧的播放时长就行,不需要视频流慢下来。

以视频为主时钟,就是拉长或者缩短音频帧的播放时长,但是不会丢弃音频帧。音频帧连续性太长,丢帧很容易被耳朵发现。

上面的例子是假设用来说明的,一般音视频不会一下子就差那么多,不同步的程度是一点一滴累加的。当累加的值超过阈值,就需要我们的程序做干预。



感谢 NETINT(镕铭微电子) 赞助《FFmpeg原理》免费版一书的服务器费用,下面是 VPU 产品介绍

版权所属 xianwanzhiyin.net 罗上文 2024 all right reserved,powered by Gitbook该文件修订时间: 2023-05-17 11:39:55

results matching ""

    No results matching ""