static inline int get_frame_length
(
    libavsmash_audio_decode_handler_t *adhp,
    uint32_t                           frame_number,
    uint32_t                          *frame_length,
    libavsmash_summary_t             **sp
)
{
    lsmash_sample_t sample;
    if( lsmash_get_sample_info_from_media_timeline( adhp->root, adhp->track_ID, frame_number, &sample ) )
        return -1;
    *sp = &adhp->config.entries[ sample.index - 1 ];
    libavsmash_summary_t *s = *sp;
    if( s->extended.frame_length == 0 )
    {
        /* variable frame length
         * Guess the frame length from sample duration. */
        if( lsmash_get_sample_delta_from_media_timeline( adhp->root, adhp->track_ID, frame_number, frame_length ) )
            return -1;
        *frame_length *= s->extended.upsampling;
    }
    else
        /* constant frame length */
        *frame_length = s->extended.frame_length;
    return 0;
}
int libavsmash_video_get_sample_duration
(
    libavsmash_video_decode_handler_t *vdhp,
    uint32_t                           coded_sample_number,
    uint32_t                          *sample_duration
)
{
    return lsmash_get_sample_delta_from_media_timeline( vdhp->root, vdhp->track_id, coded_sample_number, sample_duration );
}
uint64_t libavsmash_count_overall_pcm_samples
(
    libavsmash_audio_decode_handler_t *adhp,
    int                                output_sample_rate,
    uint64_t                          *skip_decoded_samples     /* converted to upsampled in this function */
)
{
    codec_configuration_t *config = &adhp->config;
    extended_summary_t    *es     = NULL;
    /* Here, the decoder upsampling is defined only when libavcodec doesn't return upsampled length as AVCodecContext.frame_size. */
    int      current_sample_rate       = 0;     /* after the decoder upsampling */
    uint32_t current_index             = 0;
    uint32_t current_frame_length      = 0;     /* before the decoder upsampling */
    uint64_t sequence_pcm_count        = 0;     /* before the decoder upsampling */
    uint64_t prior_sequences_pcm_count = 0;     /* before the decoder upsampling */
    uint64_t overall_pcm_count         = 0;     /* after the decoder and the resampler upsampling */
    uint64_t orig_skip_decoded_samples = *skip_decoded_samples; /* before the decoder upsampling */
    /* Count the number of output PCM audio samples in each sequence. */
    *skip_decoded_samples = 0;
    for( uint32_t i = 1; i <= adhp->frame_count; i++ )
    {
        /* Get configuration index. */
        lsmash_sample_t sample;
        if( lsmash_get_sample_info_from_media_timeline( adhp->root, adhp->track_ID, i, &sample ) )
            continue;
        if( current_index != sample.index )
        {
            es = &config->entries[ sample.index - 1 ].extended;
            current_index = sample.index;
        }
        else if( !es )
            continue;
        /* Get audio frame length. */
        uint32_t frame_length;
        if( es->frame_length )
            frame_length = es->frame_length;
        else if( lsmash_get_sample_delta_from_media_timeline( adhp->root, adhp->track_ID, i, &frame_length ) )
            continue;
        /* */
        if( (current_sample_rate != es->sample_rate && es->sample_rate > 0)
         || current_frame_length != frame_length )
        {
            /* Encountered a new sequence. */
            if( current_sample_rate > 0 )
            {
                /* Add the number of decoded PCM audio samples which shall be skipped. */
                if( orig_skip_decoded_samples > prior_sequences_pcm_count )
                {
                    if( orig_skip_decoded_samples >= prior_sequences_pcm_count + sequence_pcm_count )
                        /* All decoded PCM audio samples in the previous sequence shall be skipped. */
                        *skip_decoded_samples += sequence_pcm_count * es->upsampling;
                    else
                        /* 0 < orig_skip_decoded_samples - prior_sequences_pcm_count < sequence_pcm_count
                         * Partial decoded PCM audio samples in the previous sequence are not skipped. */
                        *skip_decoded_samples += (orig_skip_decoded_samples - prior_sequences_pcm_count) * es->upsampling;
                }
                prior_sequences_pcm_count += sequence_pcm_count;
                /* Add the number of output PCM audio samples in the previous sequence. */
                overall_pcm_count += count_sequence_output_pcm_samples( sequence_pcm_count * es->upsampling,
                                                                        *skip_decoded_samples,
                                                                        current_sample_rate,
                                                                        output_sample_rate );
                sequence_pcm_count = 0;
            }
            current_sample_rate  = es->sample_rate > 0 ? es->sample_rate : config->ctx->sample_rate;
            current_frame_length = frame_length;
        }
        sequence_pcm_count += frame_length;
    }
    if( !es || (sequence_pcm_count == 0 && overall_pcm_count == 0) )
        return 0;
    /* Count the number of output PCM audio samples in the last sequence. */
    if( orig_skip_decoded_samples > prior_sequences_pcm_count )
        *skip_decoded_samples += (orig_skip_decoded_samples - prior_sequences_pcm_count) * es->upsampling;
    current_sample_rate = es->sample_rate > 0 ? es->sample_rate : config->ctx->sample_rate;
    overall_pcm_count += count_sequence_output_pcm_samples( sequence_pcm_count * es->upsampling,
                                                            *skip_decoded_samples,
                                                            current_sample_rate,
                                                            output_sample_rate );
    /* Return the number of output PCM audio samples. */
    return overall_pcm_count;
}