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 }