本文介绍一个基于FFMPEG的开源播放器kxmovie音视频同步
项目下载地址为: 点击打开链接
同步
同步有两类,一类是流内同步,其主要任务是保证单个媒体流内的时间关系,如按照规定的帧率播放一段视频;另一类是流间同步,主要任务是保证不同媒体流之间的时间关系,如音频和视频之间的播放时间关系。
DTS和PTS
DTS(Decoding Time Stamp)解码时间戳 ,
代码中视频帧DTS代码如下
constint64_t frameDuration = av_frame_get_pkt_duration(_videoFrame);
if (frameDuration) {
frame.duration = frameDuration *_videoTimeBase;
frame.duration +=_videoFrame->repeat_pict *_videoTimeBase * 0.5;
} else {
frame.duration =1.0 / _fps;
}
frame.duration =av_frame_get_pkt_duration(_audioFrame) *_audioTimeBase;
PTS(Presentation Time Stamp)显示时间戳
代码中视频帧PTS代码如下
frame.position = av_frame_get_best_effort_timestamp(_videoFrame) * _videoTimeBase;
frame.position =av_frame_get_best_effort_timestamp(_audioFrame) *_audioTimeBase;
视频流内同步
const NSTimeInterval correction = [selftickCorrection];
constNSTimeInterval time = MAX(interval + correction, 0.01);
#ifdef DEBUG
//NSLog(@"time = %f,correction = %f",time,correction);
#endif
dispatch_time_t popTime =dispatch_time(DISPATCH_TIME_NOW, time *NSEC_PER_SEC);
dispatch_after(popTime,dispatch_get_main_queue(), ^(void){
[selftick];
});
音视频流之间的同步
NSUInteger count =_audioFrames.count;
if (count >0) {
KxAudioFrame *frame =_audioFrames[0];
if (_decoder.validVideo) {
constCGFloat delta = _moviePosition - frame.position;
if (delta < -0.1) {
memset(outData,0, numFrames * numChannels *sizeof(float));
break;// silence and exit
}
[_audioFramesremoveObjectAtIndex:0];
if (delta >0.1 && count > 1) {
continue;
}
}
kxmovie的同步方法是音频帧根据视频帧同步,播放音频帧时,判断音频帧的pts与当前的显示的视频帧的pts的大小,大于则表示音频数据先到了,不播放并保留在音频缓存数组里。