int libavsmash_video_find_first_valid_frame ( libavsmash_video_decode_handler_t *vdhp ) { codec_configuration_t *config = &vdhp->config; for( uint32_t i = 1; i <= vdhp->sample_count + get_decoder_delay( config->ctx ); i++ ) { AVPacket pkt = { 0 }; get_sample( vdhp->root, vdhp->track_id, i, config, &pkt ); av_frame_unref( vdhp->frame_buffer ); int got_picture; if( decode_video_packet( config->ctx, vdhp->frame_buffer, &got_picture, &pkt ) >= 0 && got_picture ) { vdhp->first_valid_frame_number = i - MIN( get_decoder_delay( config->ctx ), config->delay_count ); if( vdhp->first_valid_frame_number > 1 || vdhp->sample_count == 1 ) { vdhp->first_valid_frame = av_frame_clone( vdhp->frame_buffer ); if( !vdhp->first_valid_frame ) return -1; av_frame_unref( vdhp->frame_buffer ); } break; } else if( pkt.data ) ++ config->delay_count; } return 0; }
static int get_picture ( libavsmash_video_decode_handler_t *vdhp, AVFrame *picture, uint32_t current, uint32_t goal ) { codec_configuration_t *config = &vdhp->config; int got_picture = (current > goal); while( current <= goal ) { int ret = decode_video_sample( vdhp, picture, &got_picture, current ); if( ret == -1 ) return -1; else if( ret == 1 ) /* Sample doesn't exist. */ break; ++current; if( config->update_pending ) /* A new decoder configuration is needed. Anyway, stop getting picture. */ break; if( !got_picture ) { /* Fundamental seek operations after the decoder initialization is already done, but * more input samples are required to output and the goal become more distant. */ ++ config->delay_count; ++ goal; } } /* Flush the last frames. */ if( current > vdhp->sample_count && get_decoder_delay( config->ctx ) ) while( current <= goal ) { AVPacket pkt = { 0 }; av_init_packet( &pkt ); pkt.data = NULL; pkt.size = 0; av_frame_unref( picture ); if( decode_video_packet( config->ctx, picture, &got_picture, &pkt ) < 0 ) { lw_log_show( &config->lh, LW_LOG_WARNING, "Failed to decode and flush a video frame." ); return -1; } ++current; } return got_picture ? 0 : -1; }
int lwlibav_find_first_valid_video_frame ( lwlibav_video_decode_handler_t *vdhp ) { vdhp->movable_frame_buffer = av_frame_alloc(); if( !vdhp->movable_frame_buffer ) return -1; vdhp->av_seek_flags = (vdhp->lw_seek_flags & SEEK_POS_BASED) ? AVSEEK_FLAG_BYTE : vdhp->lw_seek_flags == 0 ? AVSEEK_FLAG_FRAME : 0; if( vdhp->frame_count != 1 ) { vdhp->av_seek_flags |= AVSEEK_FLAG_BACKWARD; uint32_t rap_number; lwlibav_find_random_accessible_point( vdhp, 1, 0, &rap_number ); int64_t rap_pos = lwlibav_get_random_accessible_point_position( vdhp, rap_number ); if( av_seek_frame( vdhp->format, vdhp->stream_index, rap_pos, vdhp->av_seek_flags ) < 0 ) av_seek_frame( vdhp->format, vdhp->stream_index, rap_pos, vdhp->av_seek_flags | AVSEEK_FLAG_ANY ); } uint32_t decoder_delay = get_decoder_delay( vdhp->ctx ); uint32_t thread_delay = decoder_delay - vdhp->ctx->has_b_frames; AVPacket *pkt = &vdhp->packet; for( uint32_t i = 1; i <= vdhp->frame_count + vdhp->exh.delay_count; i++ ) { lwlibav_get_av_frame( vdhp->format, vdhp->stream_index, i, pkt ); av_frame_unref( vdhp->frame_buffer ); int got_picture; int ret = avcodec_decode_video2( vdhp->ctx, vdhp->frame_buffer, &got_picture, pkt ); /* Handle decoder delay derived from PAFF field coded pictures. */ if( i <= vdhp->frame_count && i > decoder_delay && !got_picture && vdhp->frame_list[i].repeat_pict == 0 ) { /* No output picture since the second field coded picture of the next frame is not decoded yet. */ if( decoder_delay - thread_delay < 2 * vdhp->ctx->has_b_frames + 1UL ) decoder_delay = thread_delay + 2 * vdhp->ctx->has_b_frames + 1UL; } if( ret >= 0 ) { if( got_picture ) { /* Found the first valid video frame. */ vdhp->first_valid_frame_number = i - MIN( decoder_delay, vdhp->exh.delay_count ); if( vdhp->first_valid_frame_number > 1 || vdhp->frame_count == 1 ) { vdhp->first_valid_frame = av_frame_clone( vdhp->frame_buffer ); if( !vdhp->first_valid_frame ) return -1; av_frame_unref( vdhp->frame_buffer ); } break; } else if( pkt->data ) /* Output is delayed. */ ++ vdhp->exh.delay_count; else /* No more output. * Failed to find the first valid video frame. */ return -1; } } return 0; }
/* This function returns the number of the next sample. */ static uint32_t seek_video ( libavsmash_video_decode_handler_t *vdhp, AVFrame *picture, uint32_t composition_sample_number, uint32_t rap_number, int error_ignorance ) { /* Prepare to decode from random accessible sample. */ codec_configuration_t *config = &vdhp->config; if( config->update_pending ) /* Update the decoder configuration. */ update_configuration( vdhp->root, vdhp->track_id, config ); else libavsmash_flush_buffers( config ); if( config->error ) return 0; int got_picture; int output_ready = 0; uint64_t rap_cts = 0; uint32_t i; uint32_t decoder_delay = get_decoder_delay( config->ctx ); uint32_t goal = composition_sample_number + decoder_delay; for( i = rap_number; i < goal; i++ ) { if( config->index == config->queue.index ) config->delay_count = MIN( decoder_delay, i - rap_number ); int ret = decode_video_sample( vdhp, picture, &got_picture, i ); if( got_picture ) { output_ready = 1; if( decoder_delay > config->delay_count ) { /* Shorten the distance to the goal if we got a frame earlier than expected. */ uint32_t new_decoder_delay = config->delay_count; goal -= decoder_delay - new_decoder_delay; decoder_delay = new_decoder_delay; } } else if( output_ready ) { /* More input samples are required to output and the goal become more distant. */ ++decoder_delay; ++goal; } /* Some decoders return -1 when feeding a leading sample. * We don't consider as an error if the return value -1 is caused by a leading sample since it's not fatal at all. */ if( i == vdhp->last_rap_number ) rap_cts = picture->pts; if( ret == -1 && (uint64_t)picture->pts >= rap_cts && !error_ignorance ) { lw_log_show( &config->lh, LW_LOG_WARNING, "Failed to decode a video frame." ); return 0; } else if( ret >= 1 ) /* No decoding occurs. */ break; } if( config->index == config->queue.index ) config->delay_count = MIN( decoder_delay, i - rap_number ); return i; }
static uint32_t seek_video ( lwlibav_video_decode_handler_t *vdhp, AVFrame *picture, uint32_t presentation_sample_number, uint32_t rap_number, int64_t rap_pos, int error_ignorance ) { /* Prepare to decode from random accessible sample. */ lwlibav_extradata_handler_t *exhp = &vdhp->exh; int extradata_index = vdhp->frame_list[rap_number].extradata_index; if( extradata_index != exhp->current_index ) /* Update the decoder configuration. */ lwlibav_update_configuration( (lwlibav_decode_handler_t *)vdhp, rap_number, extradata_index, rap_pos ); else lwlibav_flush_buffers( (lwlibav_decode_handler_t *)vdhp ); if( vdhp->error ) return 0; if( av_seek_frame( vdhp->format, vdhp->stream_index, rap_pos, vdhp->av_seek_flags ) < 0 ) av_seek_frame( vdhp->format, vdhp->stream_index, rap_pos, vdhp->av_seek_flags | AVSEEK_FLAG_ANY ); int got_picture = 0; int64_t rap_pts = AV_NOPTS_VALUE; uint32_t current; uint32_t decoder_delay = get_decoder_delay( vdhp->ctx ); uint32_t thread_delay = decoder_delay - vdhp->ctx->has_b_frames; uint32_t goal = presentation_sample_number + decoder_delay; exhp->delay_count = 0; vdhp->last_half_frame = 0; for( current = rap_number; current <= goal; current++ ) { int ret = decode_video_picture( vdhp, picture, &got_picture, ¤t, goal, rap_number ); if( ret == -2 ) return 0; else if( ret >= 1 ) { /* No decoding occurs. */ got_picture = 0; break; } /* Handle decoder delay derived from PAFF field coded pictures. */ if( current <= vdhp->frame_count && current >= rap_number + decoder_delay && !got_picture && vdhp->frame_list[current].repeat_pict == 0 ) { /* No output picture since the second field coded picture of the next frame is not decoded yet. */ if( decoder_delay - thread_delay < 2 * vdhp->ctx->has_b_frames + 1UL ) { uint32_t new_decoder_delay = thread_delay + 2 * vdhp->ctx->has_b_frames + 1UL; goal += new_decoder_delay - decoder_delay; decoder_delay = new_decoder_delay; } } if( got_picture ) { exhp->delay_count = MIN( decoder_delay, current - rap_number ); uint32_t frame_number = current - exhp->delay_count; vdhp->last_half_frame = (frame_number <= vdhp->frame_count && vdhp->frame_list[frame_number].repeat_pict == 0); } /* Some decoders return -1 when feeding a leading sample. * We don't consider as an error if the return value -1 is caused by a leading sample since it's not fatal at all. */ if( current == vdhp->last_rap_number && picture->pts != AV_NOPTS_VALUE ) rap_pts = picture->pts; if( ret == -1 && (picture->pts == AV_NOPTS_VALUE || picture->pts >= rap_pts) && !error_ignorance ) { if( vdhp->lh.show_log ) vdhp->lh.show_log( &vdhp->lh, LW_LOG_ERROR, "Failed to decode a video frame." ); return 0; } } exhp->delay_count = MIN( decoder_delay, current - rap_number ); if( current > rap_number && vdhp->last_half_frame ) { if( got_picture ) /* first field of PAFF field coded picture */ vdhp->last_half_offset = 0; else { /* second field of PAFF field coded picture */ vdhp->last_half_frame = UINT32_MAX; vdhp->last_half_offset = 1; /* A picture of the second field is already decoded. */ } } else { vdhp->last_half_frame = 0; vdhp->last_half_offset = 0; } return current; }