FFmpeg音视频同步的问题
FFmpeg音视频同步的问题
音视频同步问题
音视频流里都包含了播放速率的信息,音频使用采样率来表示,而视频则采用 f/s
来表示,但是我们却不能简单地用这两个数据来对音视频进行同步,我们需要使用
DTS
(解码时间戳)和
PTS
(播放时间戳)这两个数据;我们知道影视数据在存储时,会存在多种帧形式,例如
MPEG
中就采用了
I
,
B
和
P
,由于
B
帧的存在使得
PTS
和
DTS
存在不同(原因见附录),如图
1
所示为一个简单的例子;当然真正影响我们音视频同步的是
PTS
。
我们可以从影视文件中获得包的 PTS
,但是我们无法直接获得帧(我们真正关心的)的
PTS
,解决办法是用一帧的第一个包的
PTS
作为这一帧的
PTS
,这是可行的,因为当一个包开始一帧时,
avcodec_decode_video()
会调用为帧申请存储空间的函数,我们可以重写这个函数,在其中加入获取包
DTS
的方法(这是很容易的),因为
ffmpeg
会重新给包进行排序,因此被
avcodec_decode_video()
处理过的包的
DTS
和返回的帧的
PTS
是相同的,这样就可以得到帧的
PTS
了。
当然有时我们可能没法得到这个 PTS
,那样我们使用内部
video_clock
(记录视频已经过去的时间);
这样我们就可以使用 PTS
来重新队列化我们的帧(
queue_picture
);
然后,我们可以去获得音频的播放时间 PTS
。
get_audio_clock ():
把 audio_clock
作为音频的
pts
,但是在
audio_decode_frame
()计算的
audio_clock
的是假定缓冲满的情况,而实际上可能缓冲是不满的,我们需要减去空闲的部分的时间:
pts -= (double)hw_buf_size / bytes_per_sec;
audio_decode_frame ():音频解码
读取包时,获取其 pts
,放入
audio_clock
中;
播放时根据缓冲大小和播放速率计算播放时间;
获得这两个pts 后,我们有三个选择:视频同步音频
(
计算音视频
PTS
只差,来决定视频是否有延迟
)
、音频同步视频(根据音视频
PTS
差值调整音频取的样值,即改变音频缓冲区的大小)和音频视频同步外部时钟(同前一个)。
附录:
I frame :帧内编码帧 又称
intra picture ,
I
帧通常是每个
GOP
(
MPEG
所使用的一种视频压缩技术)的第一个帧,经过适度地压缩,做为随机访问的参考点,可以当成图象。
I
帧可以看成是一个图像经过压缩后的产物。
P frame: 前向预测编码帧 又称
predictive-frame
,通过充分将低于图像序列中前面已编码帧的时间冗余信息来压缩传输数据量的编码图像,也叫预测帧;
B frame: 双向预测内插编码帧 又称
bi-directional interpolated prediction frame
,既考虑与源图像序列前面已编码帧,也顾及源图像序列后面已编码帧之间的时间冗余信息来压缩传输数据量的编码图像,也叫双向预测帧;
I frame: 自身可以通过视频解压算法解压成一张单独的完整的图片。
P frame :需要参考其前面的一个
I frame
或者
B frame
来生成一张完整的图片。
B frame: 则要参考其前一个
I
或者
P
帧及其后面的一个
P
帧来生成一张完整的图片。
I frame 的解码不依赖于任何的其它的帧
.
而
p frame
的解码则依赖于其前面的
I frame
或者
P frame.B frame
的解码则依赖于其前的最近的一个
I frame
或者
P frame
及其后的最近的一个
P frame.