static void mov_build_index(MOVContext *mov, AVStream *st)

{

    MOVStreamContext *sc = st->priv_data;

    int64_t current_offset;

    int64_t current_dts = 0;

    unsigned int stts_index = 0;

    unsigned int stsc_index = 0;

    unsigned int stss_index = 0;

    unsigned int stps_index = 0;

    unsigned int i, j;

    uint64_t stream_size = 0;



    /* adjust first dts according to edit list */

    if (sc->time_offset && mov->time_scale > 0) {

        if (sc->time_offset < 0)

            sc->time_offset = av_rescale(sc->time_offset, sc->time_scale, mov->time_scale);

        current_dts = -sc->time_offset;

        if (sc->ctts_data && sc->stts_data && sc->stts_data[0].duration &&

            sc->ctts_data[0].duration / sc->stts_data[0].duration > 16) {

            /* more than 16 frames delay, dts are likely wrong

               this happens with files created by iMovie */

            sc->wrong_dts = 1;

            st->internal->avctx->has_b_frames = 1;

        }

    }



    /* only use old uncompressed audio chunk demuxing when stts specifies it */

    if (!(st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO &&

          sc->stts_count == 1 && sc->stts_data[0].duration == 1)) {

        unsigned int current_sample = 0;

        unsigned int stts_sample = 0;

        unsigned int sample_size;

        unsigned int distance = 0;

        unsigned int rap_group_index = 0;

        unsigned int rap_group_sample = 0;

        int rap_group_present = sc->rap_group_count && sc->rap_group;

        int key_off = (sc->keyframes && sc->keyframes[0] > 0) || (sc->stps_data && sc->stps_data[0] > 0);



        current_dts -= sc->dts_shift;



        if (!sc->sample_count)

            return;

        if (sc->sample_count >= UINT_MAX / sizeof(*st->index_entries) - st->nb_index_entries)

            return;

        if (av_reallocp_array(&st->index_entries,

                              st->nb_index_entries + sc->sample_count,

                              sizeof(*st->index_entries)) < 0) {

            st->nb_index_entries = 0;

            return;

        }

        st->index_entries_allocated_size = (st->nb_index_entries + sc->sample_count) * sizeof(*st->index_entries);



        for (i = 0; i < sc->chunk_count; i++) {

            current_offset = sc->chunk_offsets[i];

            while (mov_stsc_index_valid(stsc_index, sc->stsc_count) &&

                i + 1 == sc->stsc_data[stsc_index + 1].first)

                stsc_index++;

            for (j = 0; j < sc->stsc_data[stsc_index].count; j++) {

                int keyframe = 0;

                if (current_sample >= sc->sample_count) {

                    av_log(mov->fc, AV_LOG_ERROR, "wrong sample count\n");

                    return;

                }



                if (!sc->keyframe_absent && (!sc->keyframe_count || current_sample+key_off == sc->keyframes[stss_index])) {

                    keyframe = 1;

                    if (stss_index + 1 < sc->keyframe_count)

                        stss_index++;

                } else if (sc->stps_count && current_sample+key_off == sc->stps_data[stps_index]) {

                    keyframe = 1;

                    if (stps_index + 1 < sc->stps_count)

                        stps_index++;

                }

                if (rap_group_present && rap_group_index < sc->rap_group_count) {

                    if (sc->rap_group[rap_group_index].index > 0)

                        keyframe = 1;

                    if (++rap_group_sample == sc->rap_group[rap_group_index].count) {

                        rap_group_sample = 0;

                        rap_group_index++;

                    }

                }

                if (keyframe)

                    distance = 0;

                sample_size = sc->sample_size > 0 ? sc->sample_size : sc->sample_sizes[current_sample];

                if (sc->pseudo_stream_id == -1 ||

                   sc->stsc_data[stsc_index].id - 1 == sc->pseudo_stream_id) {

                    AVIndexEntry *e = &st->index_entries[st->nb_index_entries++];

                    e->pos = current_offset;

                    e->timestamp = current_dts;

                    e->size = sample_size;

                    e->min_distance = distance;

                    e->flags = keyframe ? AVINDEX_KEYFRAME : 0;

                    av_log(mov->fc, AV_LOG_TRACE, "AVIndex stream %d, sample %d, offset %"PRIx64", dts %"PRId64", "

                            "size %d, distance %d, keyframe %d\n", st->index, current_sample,

                            current_offset, current_dts, sample_size, distance, keyframe);

                }



                current_offset += sample_size;

                stream_size += sample_size;

                current_dts += sc->stts_data[stts_index].duration;

                distance++;

                stts_sample++;

                current_sample++;

                if (stts_index + 1 < sc->stts_count && stts_sample == sc->stts_data[stts_index].count) {

                    stts_sample = 0;

                    stts_index++;

                }

            }

        }

        if (st->duration > 0)

            st->codecpar->bit_rate = stream_size*8*sc->time_scale/st->duration;

    } else {

        unsigned chunk_samples, total = 0;



        // compute total chunk count

        for (i = 0; i < sc->stsc_count; i++) {

            unsigned count, chunk_count;



            chunk_samples = sc->stsc_data[i].count;

            if (i != sc->stsc_count - 1 &&

                sc->samples_per_frame && chunk_samples % sc->samples_per_frame) {

                av_log(mov->fc, AV_LOG_ERROR, "error unaligned chunk\n");

                return;

            }



            if (sc->samples_per_frame >= 160) { // gsm

                count = chunk_samples / sc->samples_per_frame;

            } else if (sc->samples_per_frame > 1) {

                unsigned samples = (1024/sc->samples_per_frame)*sc->samples_per_frame;

                count = (chunk_samples+samples-1) / samples;

            } else {

                count = (chunk_samples+1023) / 1024;

            }



            if (mov_stsc_index_valid(i, sc->stsc_count))

                chunk_count = sc->stsc_data[i+1].first - sc->stsc_data[i].first;

            else

                chunk_count = sc->chunk_count - (sc->stsc_data[i].first - 1);

            total += chunk_count * count;

        }



        av_log(mov->fc, AV_LOG_TRACE, "chunk count %d\n", total);

        if (total >= UINT_MAX / sizeof(*st->index_entries) - st->nb_index_entries)

            return;

        if (av_reallocp_array(&st->index_entries,

                              st->nb_index_entries + total,

                              sizeof(*st->index_entries)) < 0) {

            st->nb_index_entries = 0;

            return;

        }

        st->index_entries_allocated_size = (st->nb_index_entries + total) * sizeof(*st->index_entries);



        // populate index

        for (i = 0; i < sc->chunk_count; i++) {

            current_offset = sc->chunk_offsets[i];

            if (mov_stsc_index_valid(stsc_index, sc->stsc_count) &&

                i + 1 == sc->stsc_data[stsc_index + 1].first)

                stsc_index++;

            chunk_samples = sc->stsc_data[stsc_index].count;



            while (chunk_samples > 0) {

                AVIndexEntry *e;

                unsigned size, samples;



                if (sc->samples_per_frame > 1 && !sc->bytes_per_frame) {

                    avpriv_request_sample(mov->fc,

                           "Zero bytes per frame, but %d samples per frame",

                           sc->samples_per_frame);

                    return;

                }



                if (sc->samples_per_frame >= 160) { // gsm

                    samples = sc->samples_per_frame;

                    size = sc->bytes_per_frame;

                } else {

                    if (sc->samples_per_frame > 1) {

                        samples = FFMIN((1024 / sc->samples_per_frame)*

                                        sc->samples_per_frame, chunk_samples);

                        size = (samples / sc->samples_per_frame) * sc->bytes_per_frame;

                    } else {

                        samples = FFMIN(1024, chunk_samples);

                        size = samples * sc->sample_size;

                    }

                }



                if (st->nb_index_entries >= total) {

                    av_log(mov->fc, AV_LOG_ERROR, "wrong chunk count %d\n", total);

                    return;

                }

                e = &st->index_entries[st->nb_index_entries++];

                e->pos = current_offset;

                e->timestamp = current_dts;

                e->size = size;

                e->min_distance = 0;

                e->flags = AVINDEX_KEYFRAME;

                av_log(mov->fc, AV_LOG_TRACE, "AVIndex stream %d, chunk %d, offset %"PRIx64", dts %"PRId64", "

                        "size %d, duration %d\n", st->index, i, current_offset, current_dts,

                        size, samples);



                current_offset += size;

                current_dts += samples;

                chunk_samples -= samples;

            }

        }

    }

}
