ijkplayer buffering过程
static void *SDL_RunThread(void *data)
{
@autoreleasepool {
SDL_Thread *thread = data;
pthread_setname_np(thread->name);
thread->retval = thread->func(thread->data);
return NULL;
}
}
//read_thread线程在此处开启
在read_thread函数内 如果ijkplayer播放器处于缓冲状态ffp->packet_buffering标志位为true
if (ffp->packet_buffering) {
io_tick_counter = SDL_GetTickHR();
if (abs((int)(io_tick_counter - prev_io_tick_counter)) > BUFFERING_CHECK_PER_MILLISECONDS) {
prev_io_tick_counter = io_tick_counter;
ffp_check_buffering_l(ffp);
}
}
ffp_check_buffering_l(ffp);//此处会检查buffering缓冲状态
在ffp_check_buffering_l函数内会判断收到的未解码数据包个数是否大于最小能播放的数据包大小 当大于最小播放数据包
并且再判断音视频流的个数和音视频流的请求是否中止 如果都满足条件就修改音视频流的缓冲开关 代码如下:
if (is->buffer_indicator_queue && is->buffer_indicator_queue->nb_packets > 0) {
if ( (is->audioq.nb_packets > MIN_MIN_FRAMES || is->audio_stream < 0 || is->audioq.abort_request)
&& (is->videoq.nb_packets > MIN_MIN_FRAMES || is->video_stream < 0 || is->videoq.abort_request)) {
ffp_toggle_buffering(ffp, 0);//此处关闭缓冲 开始播放
}
}
通过此处可以看出如果想修改ijkplayer的播放缓冲时间和缓冲长度 可以通过修改 MIN_MIN_FRAMES 来实现
#define MIN_MIN_FRAMES 5
void ffp_toggle_buffering(FFPlayer *ffp, int start_buffering)
{
SDL_LockMutex(ffp->is->play_mutex);
ffp_toggle_buffering_l(ffp, start_buffering);
SDL_UnlockMutex(ffp->is->play_mutex);
}
void ffp_toggle_buffering_l(FFPlayer *ffp, int buffering_on)
{
if (!ffp->packet_buffering)
return;
VideoState *is = ffp->is;
if (buffering_on && !is->buffering_on) {
av_log(ffp, AV_LOG_DEBUG, "ffp_toggle_buffering_l: start\n");
is->buffering_on = 1;
stream_update_pause_l(ffp);
ffp_notify_msg1(ffp, FFP_MSG_BUFFERING_START);
} else if (!buffering_on && is->buffering_on){
av_log(ffp, AV_LOG_DEBUG, "ffp_toggle_buffering_l: end\n");
is->buffering_on = 0;
stream_update_pause_l(ffp);
ffp_notify_msg1(ffp, FFP_MSG_BUFFERING_END);
}
}
static void stream_update_pause_l(FFPlayer *ffp)
{
VideoState *is = ffp->is;
if (!is->step && (is->pause_req || is->buffering_on)) {
stream_toggle_pause_l(ffp, 1);
} else {
stream_toggle_pause_l(ffp, 0);
}
}
/* pause or resume the video */
static void stream_toggle_pause_l(FFPlayer *ffp, int pause_on)
{
VideoState *is = ffp->is;
if (is->paused && !pause_on) {
is->frame_timer += av_gettime_relative() / 1000000.0 - is->vidclk.last_updated;
#ifdef FFP_MERGE
if (is->read_pause_return != AVERROR(ENOSYS)) {
is->vidclk.paused = 0;
}
#endif
set_clock(&is->vidclk, get_clock(&is->vidclk), is->vidclk.serial);
} else {
}
set_clock(&is->extclk, get_clock(&is->extclk), is->extclk.serial);
is->paused = is->audclk.paused = is->vidclk.paused = is->extclk.paused = pause_on;
SDL_AoutPauseAudio(ffp->aout, pause_on);
}
void SDL_AoutPauseAudio(SDL_Aout *aout, int pause_on)
{
if (aout && aout->pause_audio)
aout->pause_audio(aout, pause_on);
}
static void aout_pause_audio(SDL_Aout *aout, int pause_on)
{
SDLTRACE("aout_pause_audio(%d)\n", pause_on);
SDL_Aout_Opaque *opaque = aout->opaque;
if (pause_on) {
[opaque->aoutController pause];
} else {
[opaque->aoutController play];
}
}
- (void)play
{
if (!_audioQueueRef)
return;
self.spec.callback(self.spec.userdata, NULL, 0);
@synchronized(_lock) {
_isPaused = NO;
NSError *error = nil;
if (NO == [[AVAudioSession sharedInstance] setActive:YES error:&error]) {
NSLog(@"AudioQueue: AVAudioSession.setActive(YES) failed: %@\n", error ? [error localizedDescription] : @"nil");
}
OSStatus status = AudioQueueStart(_audioQueueRef, NULL);
if (status != noErr)
NSLog(@"AudioQueue: AudioQueueStart failed (%d)\n", (int)status);
}
}
通过以上分析可以看出当通过 ffp_toggle_buffering(ffp, 0);函数修改缓冲状态时中间会通过SDL函数来调用AudioQueue来开始播放