本文介紹一個基於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的大小,大於則表示音頻數據先到了,不播放並保留在音頻緩存數組裏。