static int get_requested_picture
(
    libavsmash_video_decode_handler_t *vdhp,
    AVFrame                           *picture,
    uint32_t                           sample_number
)
{
#define MAX_ERROR_COUNT 3       /* arbitrary */
    codec_configuration_t *config = &vdhp->config;
    uint32_t config_index;
    if( sample_number < vdhp->first_valid_frame_number || vdhp->sample_count == 1 )
    {
        /* Get the index of the decoder configuration. */
        lsmash_sample_t sample;
        uint32_t decoding_sample_number = get_decoding_sample_number( vdhp->order_converter, vdhp->first_valid_frame_number );
        if( lsmash_get_sample_info_from_media_timeline( vdhp->root, vdhp->track_id, decoding_sample_number, &sample ) < 0 )
            goto video_fail;
        config_index = sample.index;
        /* Copy the first valid video frame data. */
        av_frame_unref( picture );
        if( av_frame_ref( picture, vdhp->first_valid_frame ) < 0 )
            goto video_fail;
        /* Force seeking at the next access for valid video frame. */
        vdhp->last_sample_number = vdhp->sample_count + 1;
        goto return_frame;
    }
    uint32_t start_number;  /* number of sample, for normal decoding, where decoding starts excluding decoding delay */
    uint32_t rap_number;    /* number of sample, for seeking, where decoding starts excluding decoding delay */
    int seek_mode = vdhp->seek_mode;
    int roll_recovery = 0;
    if( sample_number > vdhp->last_sample_number
     && sample_number <= vdhp->last_sample_number + vdhp->forward_seek_threshold )
    {
        start_number = vdhp->last_sample_number + 1 + config->delay_count;
        rap_number   = vdhp->last_rap_number;
    }
    else
    {
        roll_recovery = find_random_accessible_point( vdhp, sample_number, 0, &rap_number );
        if( rap_number == vdhp->last_rap_number && sample_number > vdhp->last_sample_number )
        {
            roll_recovery = 0;
            start_number  = vdhp->last_sample_number + 1 + config->delay_count;
        }
        else
        {
            /* Require starting to decode from random accessible sample. */
            vdhp->last_rap_number = rap_number;
            start_number = seek_video( vdhp, picture, sample_number, rap_number, roll_recovery || seek_mode != SEEK_MODE_NORMAL );
        }
    }
    /* Get the desired picture. */
    int error_count = 0;
    while( start_number == 0    /* Failed to seek. */
     || config->update_pending  /* Need to update the decoder configuration to decode pictures. */
     || get_picture( vdhp, picture, start_number, sample_number + config->delay_count ) < 0 )
    {
        if( config->update_pending )
        {
            roll_recovery = find_random_accessible_point( vdhp, sample_number, 0, &rap_number );
            vdhp->last_rap_number = rap_number;
        }
        else
        {
            /* Failed to get the desired picture. */
            if( config->error || seek_mode == SEEK_MODE_AGGRESSIVE )
                goto video_fail;
            if( ++error_count > MAX_ERROR_COUNT || rap_number <= 1 )
            {
                if( seek_mode == SEEK_MODE_UNSAFE )
                    goto video_fail;
                /* Retry to decode from the same random accessible sample with error ignorance. */
                seek_mode = SEEK_MODE_AGGRESSIVE;
            }
            else
            {
                /* Retry to decode from more past random accessible sample. */
                roll_recovery = find_random_accessible_point( vdhp, sample_number, rap_number - 1, &rap_number );
                if( vdhp->last_rap_number == rap_number )
                    goto video_fail;
                vdhp->last_rap_number = rap_number;
            }
        }
        start_number = seek_video( vdhp, picture, sample_number, rap_number, roll_recovery || seek_mode != SEEK_MODE_NORMAL );
    }
    vdhp->last_sample_number = sample_number;
    config_index = config->index;
return_frame:;
    /* Don't exceed the maximum presentation size specified for each sequence. */
    extended_summary_t *extended = &config->entries[ config_index - 1 ].extended;
    if( config->ctx->width > extended->width )
        config->ctx->width = extended->width;
    if( config->ctx->height > extended->height )
        config->ctx->height = extended->height;
    return 0;
video_fail:
    /* fatal error of decoding */
    lw_log_show( &config->lh, LW_LOG_WARNING, "Couldn't read video frame." );
    return -1;
#undef MAX_ERROR_COUNT
}
static int get_requested_picture
(
    lwlibav_video_decode_handler_t *vdhp,
    AVFrame                        *picture,
    uint32_t                        frame_number
)
{
#define MAX_ERROR_COUNT 3   /* arbitrary */
    if( frame_number > vdhp->frame_count )
        frame_number = vdhp->frame_count;
    uint32_t extradata_index;
    if( frame_number == vdhp->last_frame_number
     || frame_number == vdhp->last_frame_number + vdhp->last_half_offset )
    {
        /* The last frame is the requested frame. */
        if( copy_last_frame( vdhp, picture ) < 0 )
            goto video_fail;
        extradata_index = vdhp->frame_list[frame_number].extradata_index;
        goto return_frame;
    }
    if( frame_number < vdhp->first_valid_frame_number || vdhp->frame_count == 1 )
    {
        /* Copy the first valid video frame data. */
        av_frame_unref( picture );
        if( av_frame_ref( picture, vdhp->first_valid_frame ) < 0 )
            goto video_fail;
        /* Force seeking at the next access for valid video frame. */
        vdhp->last_frame_number = vdhp->frame_count + 1;
        vdhp->last_frame_buffer = picture;
        /* Return the first valid video frame. */
        extradata_index = vdhp->frame_list[ vdhp->first_valid_frame_number ].extradata_index;
        goto return_frame;
    }
    uint32_t start_number;  /* number of sample, for normal decoding, where decoding starts excluding decoding delay */
    uint32_t rap_number;    /* number of sample, for seeking, where decoding starts excluding decoding delay */
    uint32_t last_frame_number = vdhp->last_frame_number + vdhp->last_half_offset;
    int      seek_mode         = vdhp->seek_mode;
    int64_t  rap_pos           = INT64_MIN;
    if( frame_number > last_frame_number
     && frame_number <= last_frame_number + vdhp->forward_seek_threshold )
    {
        start_number = last_frame_number + 1 + vdhp->exh.delay_count;
        rap_number   = vdhp->last_rap_number;
    }
    else
    {
        lwlibav_find_random_accessible_point( vdhp, frame_number, 0, &rap_number );
        if( rap_number == vdhp->last_rap_number && frame_number > last_frame_number )
            start_number = last_frame_number + 1 + vdhp->exh.delay_count;
        else
        {
            /* Require starting to decode from random accessible sample. */
            rap_pos = lwlibav_get_random_accessible_point_position( vdhp, rap_number );
            vdhp->last_rap_number = rap_number;
            start_number = seek_video( vdhp, picture, frame_number, rap_number, rap_pos, seek_mode != SEEK_MODE_NORMAL );
        }
    }
    /* Get requested picture. */
    int error_count = 0;
    while( start_number == 0
        || get_picture( vdhp, picture, start_number, frame_number + vdhp->exh.delay_count, rap_number ) < 0 )
    {
        /* Failed to get desired picture. */
        if( vdhp->error || seek_mode == SEEK_MODE_AGGRESSIVE )
            goto video_fail;
        if( ++error_count > MAX_ERROR_COUNT || rap_number <= 1 )
        {
            if( seek_mode == SEEK_MODE_UNSAFE )
                goto video_fail;
            /* Retry to decode from the same random accessible sample with error ignorance. */
            seek_mode = SEEK_MODE_AGGRESSIVE;
        }
        else
        {
            /* Retry to decode from more past random accessible sample. */
            lwlibav_find_random_accessible_point( vdhp, frame_number, rap_number - 1, &rap_number );
            rap_pos = lwlibav_get_random_accessible_point_position( vdhp, rap_number );
            vdhp->last_rap_number = rap_number;
        }
        start_number = seek_video( vdhp, picture, frame_number, rap_number, rap_pos, seek_mode != SEEK_MODE_NORMAL );
    }
    vdhp->last_frame_number = frame_number;
    vdhp->last_frame_buffer = picture;
    if( vdhp->last_half_frame == UINT32_MAX )
    {
        /* The second field was requested in this time.
         * Shift the last frame number to the first field number. */
        vdhp->last_frame_number -= 1;
        vdhp->last_half_frame    = 1;
    }
    extradata_index = vdhp->frame_list[frame_number].extradata_index;
return_frame:;
    /* Don't exceed the maximum presentation size specified for each sequence. */
    lwlibav_extradata_t *entry = &vdhp->exh.entries[extradata_index];
    if( vdhp->ctx->width > entry->width )
        vdhp->ctx->width = entry->width;
    if( vdhp->ctx->height > entry->height )
        vdhp->ctx->height = entry->height;
    return 0;
video_fail:
    /* fatal error of decoding */
    if( vdhp->lh.show_log )
        vdhp->lh.show_log( &vdhp->lh, LW_LOG_ERROR, "Couldn't get the requested video frame." );
    return -1;
#undef MAX_ERROR_COUNT
}