Detailed explanation of iOS ijkplayer data caching process


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 thread is started here
In the read_thread function, if the ijkplayer player is in a buffering state, the ffp->packet_buffering flag is 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);//The buffering buffer status will be checked here
In the ffp_check_buffering_l function, it will be judged whether the number of undecoded packets received is greater than the minimum playable packet size, and if it is greater than the minimum playable packet size
And then judge the number of audio and video streams and whether the request for audio and video streams is terminated. If all conditions are met, modify the buffer switch code of the audio and video streams as follows:
        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);//Turn off buffering and start playing here
            }
        }
It can be seen from here that if you want to modify the playback buffer time and buffer length of ijkplayer, you can do so by modifying 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);
    }
}
From the above analysis, it can be seen that when the buffering state is modified by the ffp_toggle_buffering(ffp, 0); function, the AudioQueue will be called through the SDL function in the middle to start playback


Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324440080&siteId=291194637