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; }
uint64_t lwlibav_audio_get_pcm_samples ( lwlibav_audio_decode_handler_t *adhp, lwlibav_audio_output_handler_t *aohp, void *buf, int64_t start, int64_t wanted_length ) { if( adhp->error ) return 0; uint32_t frame_number; uint32_t rap_number = 0; uint32_t past_rap_number = 0; uint64_t output_length = 0; enum audio_output_flag output_flags = AUDIO_OUTPUT_NO_FLAGS; AVPacket *pkt = &adhp->packet; AVPacket *alter_pkt = &adhp->alter_packet; int already_gotten; aohp->request_length = wanted_length; if( start > 0 && start == adhp->next_pcm_sample_number ) { frame_number = adhp->last_frame_number; 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( alter_pkt->size <= 0 ) ++frame_number; aohp->output_sample_offset = 0; already_gotten = 0; } else { /* Seek audio stream. */ adhp->next_pcm_sample_number = 0; adhp->last_frame_number = 0; /* Get frame_number. */ 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; } frame_number = find_start_audio_frame( adhp, aohp->output_sample_rate, start_frame_pos, &aohp->output_sample_offset ); retry_seek: av_packet_unref( pkt ); /* Flush audio resampler buffers. */ if( flush_resampler_buffers( aohp->avr_ctx ) < 0 ) { adhp->error = 1; lw_log_show( &adhp->lh, LW_LOG_FATAL, "Failed to flush resampler buffers.\n" "It is recommended you reopen the file." ); return 0; } /* Flush audio decoder buffers. */ lwlibav_extradata_handler_t *exhp = &adhp->exh; int extradata_index = adhp->frame_list[frame_number].extradata_index; if( extradata_index != exhp->current_index ) { /* Update the extradata. */ rap_number = get_audio_rap( adhp, frame_number ); assert( rap_number != 0 ); lwlibav_update_configuration( (lwlibav_decode_handler_t *)adhp, rap_number, extradata_index, 0 ); } else lwlibav_flush_buffers( (lwlibav_decode_handler_t *)adhp ); if( adhp->error ) return 0; /* Seek and get a audio packet. */ rap_number = seek_audio( adhp, frame_number, past_rap_number, pkt, output_flags != AUDIO_OUTPUT_NO_FLAGS ? adhp->frame_buffer : NULL ); already_gotten = 1; } do { if( already_gotten ) { already_gotten = 0; make_decodable_packet( alter_pkt, pkt ); } else if( frame_number > adhp->frame_count ) { av_packet_unref( pkt ); if( adhp->exh.delay_count || !(output_flags & AUDIO_OUTPUT_ENOUGH) ) { /* Null packet */ av_init_packet( pkt ); make_null_packet( pkt ); *alter_pkt = *pkt; if( adhp->exh.delay_count ) adhp->exh.delay_count -= 1; } else goto audio_out; } else if( alter_pkt->size <= 0 ) { /* Getting an audio packet must be after flushing all remaining samples in resampler's FIFO buffer. */ lwlibav_get_av_frame( adhp->format, adhp->stream_index, frame_number, pkt ); make_decodable_packet( alter_pkt, pkt ); } /* Decode and output from an audio packet. */ output_flags = AUDIO_OUTPUT_NO_FLAGS; output_length += output_pcm_samples_from_packet( aohp, adhp->ctx, alter_pkt, adhp->frame_buffer, (uint8_t **)&buf, &output_flags ); if( output_flags & AUDIO_DECODER_DELAY ) { if( rap_number > 1 && (output_flags & AUDIO_DECODER_ERROR) ) { /* Retry to seek from more past audio keyframe because libavformat might have failed seek. * This operation occurs only at the first decoding time after seek. */ past_rap_number = get_audio_rap( adhp, rap_number - 1 ); if( past_rap_number && past_rap_number < rap_number ) goto retry_seek; } ++ adhp->exh.delay_count; } else /* Disable seek retry. */ rap_number = 0; if( output_flags & AUDIO_RECONFIG_FAILURE ) { adhp->error = 1; lw_log_show( &adhp->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; if( output_flags & (AUDIO_DECODER_ERROR | AUDIO_DECODER_RECEIVED_PACKET) ) ++frame_number; } while( 1 ); audio_out: adhp->next_pcm_sample_number = start + output_length; adhp->last_frame_number = frame_number; return output_length; }