/* 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; }
uint64_t libavsmash_get_pcm_audio_samples ( libavsmash_audio_decode_handler_t *adhp, libavsmash_audio_output_handler_t *aohp, void *buf, int64_t start, int64_t wanted_length ) { codec_configuration_t *config = &adhp->config; if( config->error ) return 0; uint32_t frame_number; uint64_t output_length = 0; enum audio_output_flag output_flags; aohp->request_length = wanted_length; if( start > 0 && start == adhp->next_pcm_sample_number ) { frame_number = adhp->last_frame_number; output_flags = AUDIO_OUTPUT_NO_FLAGS; output_length += output_pcm_samples_from_buffer( aohp, adhp->frame_buffer, (uint8_t **)&buf, &output_flags ); if( output_flags & AUDIO_OUTPUT_ENOUGH ) goto audio_out; if( adhp->packet.size <= 0 ) ++frame_number; aohp->output_sample_offset = 0; } else { /* Seek audio stream. */ if( flush_resampler_buffers( aohp->avr_ctx ) < 0 ) { config->error = 1; if( config->lh.show_log ) config->lh.show_log( &config->lh, LW_LOG_FATAL, "Failed to flush resampler buffers.\n" "It is recommended you reopen the file." ); return 0; } libavsmash_flush_buffers( config ); if( config->error ) return 0; adhp->next_pcm_sample_number = 0; adhp->last_frame_number = 0; uint64_t start_frame_pos; if( start >= 0 ) start_frame_pos = start; else { uint64_t silence_length = -start; put_silence_audio_samples( (int)(silence_length * aohp->output_block_align), aohp->output_bits_per_sample == 8, (uint8_t **)&buf ); output_length += silence_length; aohp->request_length -= silence_length; start_frame_pos = 0; } start_frame_pos += aohp->skip_decoded_samples; frame_number = find_start_audio_frame( adhp, aohp->output_sample_rate, aohp->skip_decoded_samples, start_frame_pos, &aohp->output_sample_offset ); } do { AVPacket *pkt = &adhp->packet; if( frame_number > adhp->frame_count ) { if( config->delay_count ) { /* Null packet */ av_init_packet( pkt ); pkt->data = NULL; pkt->size = 0; -- config->delay_count; } else goto audio_out; } else if( pkt->size <= 0 ) /* Getting an audio packet must be after flushing all remaining samples in resampler's FIFO buffer. */ while( get_sample( adhp->root, adhp->track_ID, frame_number, config, pkt ) == 2 ) if( config->update_pending ) /* Update the decoder configuration. */ update_configuration( adhp->root, adhp->track_ID, config ); /* Decode and output from an audio packet. */ output_flags = AUDIO_OUTPUT_NO_FLAGS; output_length += output_pcm_samples_from_packet( aohp, config->ctx, pkt, adhp->frame_buffer, (uint8_t **)&buf, &output_flags ); if( output_flags & AUDIO_DECODER_DELAY ) ++ config->delay_count; if( output_flags & AUDIO_RECONFIG_FAILURE ) { config->error = 1; if( config->lh.show_log ) config->lh.show_log( &config->lh, LW_LOG_FATAL, "Failed to reconfigure resampler.\n" "It is recommended you reopen the file." ); goto audio_out; } if( output_flags & AUDIO_OUTPUT_ENOUGH ) goto audio_out; ++frame_number; } while( 1 ); audio_out: adhp->next_pcm_sample_number = start + output_length; adhp->last_frame_number = frame_number; return output_length; }