请接上一个简书内容观看,会对上一章的代码进行改进和修改~~~
ffmpeg播放器4-音视频同步
1.ffmpeg 音视频同步的开发
AudioChannel中:getPcm()方法中 获取到音频播放的相对时间
//获得 frame 的一个相对播放时间 (相对开始播放的时间)
// 获取相对播放这一段数据的秒数
clock = frame->pts * av_q2d(time_base);
VideoChannel.cpp中 play()中 callback之前 获取当前画面的播放时间,并与音频中的播放时间进行对比:
// 获得 当前这一个画面 播放的相对时间
double clock = frame->best_effort_timestamp * av_q2d(time_base);
// 计算额外的延迟时间
double extra_delay = frame->repeat_pict / (2*fps);
// 真实需要的间隔时间
frame_delays += extra_delay;
if (!audioChannel || clock == 0) {
// 休眠 微秒 -> #include <libavutil/time.h> 防止卡顿
av_usleep(frame_delays * 1000 * 1000);
} else {
// 用来比较音视频
double audioClock = audioChannel->clock;
// 音视频相差的间隔
double diff = clock - audioClock;
if (diff > 0) {
// 视频比较快 让视频休眠时间长一些
av_usleep((frame_delays + diff) * 1000 * 1000);
} else if (diff < 0) {
// 音频比较快
if(fabs(diff) >= 0.05){
// 丢包 packet
// packets.sync();
// 丢包 frame
frames.sync();
continue;
}else{
// 不睡眠 赶上音频播放进度
}
} else {
av_usleep(frame_delays * 1000 * 1000);
}
}
2.相关知识整理
简书链接:
音视频同步方式:
1、将视频根据音频同步(以音频为主)
2、以视频为主
3、以一个外部时间进度为主
帧率:单位时间内 需要显示多少个图像 25fp:1s内显示25个图像
//音频
//获得 frame 的一个相对播放时间 (相对开始播放的时间)
// 获取相对播放这一段数据的秒数
clock = frame->pts * av_q2d(time_base);
//视频
// 获得 当前这一个画面 播放的相对时间
double clock = frame->best_effort_timestamp * av_q2d(time_base);
I frame :帧内编码帧 ,I 帧通常是每个 GOP(MPEG 所使用的一种视频压缩技术)的第一个帧,经过适度地压缩,做为随机访问的参考点,可以当成图象。I帧可以看成是一个图像经过压缩后的产物。
P frame: 前向预测编码帧,通过充分将低于图像序列中前面已编码帧的时间冗余信息来压缩传输数据量的编码图像,也叫预测帧;
B frame: 双向预测内插编码帧 ,既考虑与源图像序列前面已编码帧,也顾及源图像序列后面已编码帧之间的时间冗余信息来压缩传输数据量的编码图像,也叫双向预测帧;
I frame:自身可以通过视频解压算法解压成一张单独的完整的图片。
P frame:需要参考其前面的一个I frame 或者B frame来生成一张完整的图片。
B frame:则要参考其前一个I或者P帧及其后面的一个P帧来生成一张完整的图片。
PTS:Presentation Time Stamp。PTS主要用于度量解码后的音视频帧什么时候被显示出来
DTS:Decode Time Stamp。DTS主要是标识读入内存中的帧数据在什么时候开始送入解码器中进行解码。
在没有B帧存在的情况下DTS的顺序和PTS的顺序应该是一样的。
DTS主要用于视频的解码,在解码阶段使用。PTS主要用于视频的同步和输出.在显示的时候使用。
如上图:I frame 的解码不依赖于任何的其它的帧.而p frame的解码则依赖于其前面的I frame或者P frame.B frame的解码则依赖于其前的最近的一个I frame或者P frame 及其后的最近的一个P frame.