[FFmpeg-devel] [PATCH 1/5] mxfdec: Parse IndexTableSegments and convert them into AVIndexEntry arrays

Michael Niedermayer michaelni at gmx.at
Sun Nov 13 20:41:13 CET 2011


On Fri, Nov 11, 2011 at 03:42:22PM +0100, Tomas Härdin wrote:
> New thread since the old one is rather cluttered.
> 
> I incorporated Georg's single_eubc patch and split the system item hack
> into its own patch.
> This patch is rather clean now IMO.
[...]
> +static int mxf_get_sorted_table_segments(MXFContext *mxf, int *nb_sorted_segments, MXFIndexTableSegment ***sorted_segments)
> +{
> +    int i, j, nb_segments = 0;
> +    MXFIndexTableSegment **unsorted_segments;
> +    int last_body_sid = -1, last_index_sid = -1, last_index_start = -1;
> +
> +    /* count number of segments, allocate arrays and copy unsorted segments */
> +    for (i = 0; i < mxf->metadata_sets_count; i++)
> +        if (mxf->metadata_sets[i]->type == IndexTableSegment)
> +            nb_segments++;
> +
> +    if (!(unsorted_segments = av_calloc(nb_segments, sizeof(*unsorted_segments))) ||
> +        !(*sorted_segments  = av_calloc(nb_segments, sizeof(**sorted_segments)))) {
> +        av_free(unsorted_segments);
> +        return AVERROR(ENOMEM);
> +    }
> +
> +    for (i = j = 0; i < mxf->metadata_sets_count; i++)
> +        if (mxf->metadata_sets[i]->type == IndexTableSegment)
> +            unsorted_segments[j++] = (MXFIndexTableSegment*)mxf->metadata_sets[i];
> +
> +    *nb_sorted_segments = 0;

> +
> +    /* sort segments by {BodySID, IndexSID, IndexStartPosition}, remove duplicates while we're at it */
> +    for (i = 0; i < nb_segments; i++) {
> +        int best = -1, best_body_sid = -1, best_index_sid = -1, best_index_start = -1;
> +
> +        for (j = 0; j < nb_segments; j++) {
> +            MXFIndexTableSegment *s = unsorted_segments[j];
> +
> +            /* Require larger BosySID, IndexSID or IndexStartPosition then the previous entry. This removes duplicates.
> +             * We want the smallest values for the keys than what we currently have, unless this is the first such entry this time around.
> +             */
> +            if ((i == 0     || s->body_sid > last_body_sid || s->index_sid > last_index_sid || s->index_start_position > last_index_start) &&
> +                (best == -1 || s->body_sid < best_body_sid || s->index_sid < best_index_sid || s->index_start_position < best_index_start)) {
> +                best             = j;
> +                best_body_sid    = s->body_sid;
> +                best_index_sid   = s->index_sid;
> +                best_index_start = s->index_start_position;
> +            }
> +        }
> +
> +        /* no suitable entry found -> we're done */
> +        if (best == -1)
> +            break;
> +
> +        (*sorted_segments)[(*nb_sorted_segments)++] = unsorted_segments[best];
> +        last_body_sid    = best_body_sid;
> +        last_index_sid   = best_index_sid;
> +        last_index_start = best_index_start;
> +    }

how many entries can the to be sorted table contain? iam asking due
to the scalability of the selection sort. if its alot the C qsort()
should be considered otherwise it doesnt matter

also the last/best variable sets could be replaced by a pointer each


> +
> +    av_free(unsorted_segments);
> +
> +    return 0;
> +}
> +
> +static int mxf_parse_index(MXFContext *mxf, int i, AVStream *st)
> +{
> +    int64_t accumulated_offset = 0;
> +    int j, k, ret, nb_sorted_segments;
> +    MXFIndexTableSegment **sorted_segments;
> +    
> +    if ((ret = mxf_get_sorted_table_segments(mxf, &nb_sorted_segments, &sorted_segments)))
> +        return ret;

trailing whitespace isnt allowed in git


> +
> +    for (j = 0; j < nb_sorted_segments; j++) {
> +        int n_delta = i;
> +        int duration, sample_duration = 1, last_sample_size = 0;
> +        int64_t segment_size;
> +        MXFIndexTableSegment *tableseg = sorted_segments[j];
> +
> +        /* reset accumulated_offset on BodySID change */
> +        if (j > 0 && tableseg->body_sid != sorted_segments[j-1]->body_sid)
> +            accumulated_offset = 0;
> +
> +        /* HACK: How to correctly link between streams and slices? */
> +        if (i < st->index)
> +            n_delta++;
> +        if (n_delta >= tableseg->nb_delta_entries && st->index != 0)
> +            continue;
> +        duration = tableseg->index_duration > 0 ? tableseg->index_duration :
> +            st->duration - st->nb_index_entries;
> +        segment_size = tableseg->edit_unit_byte_count * duration;
> +        /* check small EditUnitByteCount for audio */
> +        if (tableseg->edit_unit_byte_count && tableseg->edit_unit_byte_count < 32
> +            && !tableseg->index_duration) {
> +            /* duration might be prime relative to the new sample_duration,
> +             * which means we need to handle the last frame differently */
> +            sample_duration = 8192;
> +            last_sample_size = (duration % sample_duration) * tableseg->edit_unit_byte_count;
> +            tableseg->edit_unit_byte_count *= sample_duration;
> +            duration /= sample_duration;
> +            if (last_sample_size) duration++;
> +        }


> +        st->index_entries_allocated_size += duration * sizeof(*st->index_entries);
> +        if (st->index_entries_allocated_size / sizeof(*st->index_entries) < st->nb_index_entries + duration) {
> +            av_log(mxf->fc, AV_LOG_ERROR, "index_entries_allocated_size overflow; "
> +                                          "segment duration %i unreasonably large?\n", duration);
> +            return AVERROR_INVALIDDATA;
> +        }
> +        if (!(st->index_entries = av_realloc(st->index_entries, st->index_entries_allocated_size))) {
> +            av_free(sorted_segments);
> +            return AVERROR(ENOMEM);
> +        }
> +        for (k = 0; k < duration; k++) {
> +            AVIndexEntry *e = &st->index_entries[st->nb_index_entries];
> +            if (k < tableseg->nb_index_entries) {
> +                e->pos = tableseg->stream_offset_entries[k];
> +                if (n_delta < tableseg->nb_delta_entries) {
> +                    if (n_delta < tableseg->nb_delta_entries - 1) {
> +                        e->size =
> +                            tableseg->slice_offset_entries[k][tableseg->slice[n_delta+1]-1] +
> +                            tableseg->element_delta[n_delta+1] -
> +                            tableseg->element_delta[n_delta];
> +                        if (tableseg->slice[n_delta] > 0)
> +                            e->size -= tableseg->slice_offset_entries[k][tableseg->slice[n_delta]-1];
> +                    } else if (k < duration - 1) {
> +                        e->size = tableseg->stream_offset_entries[k+1] -
> +                            tableseg->stream_offset_entries[k] -
> +                            tableseg->slice_offset_entries[k][tableseg->slice[tableseg->nb_delta_entries-1]-1] -
> +                            tableseg->element_delta[tableseg->nb_delta_entries-1];
> +                    } else
> +                        e->size = 0;
> +                    if (tableseg->slice[n_delta] > 0)
> +                        e->pos += tableseg->slice_offset_entries[k][tableseg->slice[n_delta]-1];
> +                    e->pos += tableseg->element_delta[n_delta];
> +                }
> +                e->flags = !(tableseg->flag_entries[k] & 0x30) ? AVINDEX_KEYFRAME : 0;
> +            } else {
> +                e->pos = (int64_t)k * tableseg->edit_unit_byte_count + accumulated_offset;
> +                if (n_delta < tableseg->nb_delta_entries - 1)
> +                    e->size = tableseg->element_delta[n_delta+1] - tableseg->element_delta[n_delta];
> +                else {
> +                    /* use smaller size for last sample if we should */
> +                    if (last_sample_size && k == duration - 1)
> +                        e->size = last_sample_size;
> +                    else
> +                        e->size = tableseg->edit_unit_byte_count;
> +                    if (tableseg->nb_delta_entries)
> +                        e->size -= tableseg->element_delta[tableseg->nb_delta_entries-1];
> +                }
> +                if (n_delta < tableseg->nb_delta_entries)
> +                    e->pos += tableseg->element_delta[n_delta];
> +                e->flags = AVINDEX_KEYFRAME;
> +            }
> +            if (k > 0 && e->pos < mxf->first_essence_length && accumulated_offset == 0)
> +                e->pos += mxf->first_essence_kl_length;
> +            e->timestamp = sample_duration * st->nb_index_entries++;
> +            av_dlog(mxf->fc, "Stream %d IndexEntry %d n_Delta %d Offset %"PRIx64" Timestamp %"PRId64"\n",
> +                    st->index, st->nb_index_entries, n_delta, e->pos, e->timestamp);
> +            e->pos += mxf->essence_offset;
> +            e->min_distance = 0;
> +        }
> +        accumulated_offset += segment_size;
> +    }

why does this not use av_add_index_entry() ?


[...]

-- 
Michael     GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB

Freedom in capitalist society always remains about the same as it was in
ancient Greek republics: Freedom for slave owners. -- Vladimir Lenin
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: Digital signature
URL: <http://ffmpeg.org/pipermail/ffmpeg-devel/attachments/20111113/44a1fa1b/attachment.asc>


More information about the ffmpeg-devel mailing list