From 31029e30fa99d3d44403901850a00ce8e69b42dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomas=20H=C3=A4rdin?= Date: Fri, 16 Dec 2011 09:19:01 +0100 Subject: [PATCH 1/8] mxfdec: Move mxf_read_packet*() near the bottom of the file This simplifies future commits. --- libavformat/mxfdec.c | 222 +++++++++++++++++++++---------------------- 1 file changed, 111 insertions(+), 111 deletions(-) diff --git a/libavformat/mxfdec.c b/libavformat/mxfdec.c index 17eadbfd77..8447da5d2b 100644 --- a/libavformat/mxfdec.c +++ b/libavformat/mxfdec.c @@ -380,117 +380,6 @@ static int mxf_decrypt_triplet(AVFormatContext *s, AVPacket *pkt, KLVPacket *klv return 0; } -static int mxf_read_packet_old(AVFormatContext *s, AVPacket *pkt) -{ - KLVPacket klv; - - while (!url_feof(s->pb)) { - if (klv_read_packet(&klv, s->pb) < 0) - return -1; - PRINT_KEY(s, "read packet", klv.key); - av_dlog(s, "size %"PRIu64" offset %#"PRIx64"\n", klv.length, klv.offset); - if (IS_KLV_KEY(klv.key, mxf_encrypted_triplet_key)) { - int res = mxf_decrypt_triplet(s, pkt, &klv); - if (res < 0) { - av_log(s, AV_LOG_ERROR, "invalid encoded triplet\n"); - return -1; - } - return 0; - } - if (IS_KLV_KEY(klv.key, mxf_essence_element_key) || - IS_KLV_KEY(klv.key, mxf_avid_essence_element_key)) { - int index = mxf_get_stream_index(s, &klv); - if (index < 0) { - av_log(s, AV_LOG_ERROR, "error getting stream index %d\n", AV_RB32(klv.key+12)); - goto skip; - } - if (s->streams[index]->discard == AVDISCARD_ALL) - goto skip; - /* check for 8 channels AES3 element */ - if (klv.key[12] == 0x06 && klv.key[13] == 0x01 && klv.key[14] == 0x10) { - if (mxf_get_d10_aes3_packet(s->pb, s->streams[index], pkt, klv.length) < 0) { - av_log(s, AV_LOG_ERROR, "error reading D-10 aes3 frame\n"); - return -1; - } - } else { - int ret = av_get_packet(s->pb, pkt, klv.length); - if (ret < 0) - return ret; - } - pkt->stream_index = index; - pkt->pos = klv.offset; - return 0; - } else - skip: - avio_skip(s->pb, klv.length); - } - return AVERROR_EOF; -} - -static int mxf_read_packet(AVFormatContext *s, AVPacket *pkt) -{ - MXFContext *mxf = s->priv_data; - AVIndexEntry *e; - int ret; - int64_t ret64; - KLVPacket klv; - AVStream *st; - - /* TODO: better logic for this? - * only files that lack all index segments prior to the essence need this */ - if (!s->pb->seekable && mxf->op != OPAtom || mxf->d10 || mxf->broken_index) - return mxf_read_packet_old(s, pkt); - - if (mxf->current_stream >= s->nb_streams) { - mxf->current_edit_unit++; - mxf->current_stream = 0; - } - - st = s->streams[mxf->current_stream]; - - if (mxf->current_edit_unit >= st->nb_index_entries) - return AVERROR_EOF; - - e = &st->index_entries[mxf->current_edit_unit]; - - if ((ret64 = avio_seek(s->pb, e->pos, SEEK_SET)) < 0) - return ret64; - - if (mxf->op == OPAtom) { - /* OPAtom - no KL, just essence */ - if ((ret = av_get_packet(s->pb, pkt, e->size)) != e->size) - return ret < 0 ? ret : AVERROR_EOF; - } else { - /* read KL, read L bytes of essence */ - if ((ret = klv_read_packet(&klv, s->pb)) < 0) - return ret; - - /* untested, but looks OK */ - if (IS_KLV_KEY(klv.key, mxf_encrypted_triplet_key)) { - int res = mxf_decrypt_triplet(s, pkt, &klv); - if (res < 0) { - av_log(s, AV_LOG_ERROR, "invalid encoded triplet\n"); - return -1; - } - return 0; - } - - if ((ret = av_get_packet(s->pb, pkt, klv.length)) != klv.length) - return ret < 0 ? ret : AVERROR_EOF; - - pkt->pos = e->pos; - } - - if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO && mxf->ptses && mxf->current_edit_unit < mxf->nb_ptses) { - pkt->dts = mxf->current_edit_unit + mxf->first_dts; - pkt->pts = mxf->ptses[mxf->current_edit_unit]; - } - - pkt->stream_index = mxf->current_stream++; - - return 0; -} - static int mxf_read_primer_pack(void *arg, AVIOContext *pb, int tag, int size, UID uid, int64_t klv_offset) { MXFContext *mxf = arg; @@ -1826,6 +1715,117 @@ static int mxf_read_header(AVFormatContext *s, AVFormatParameters *ap) return mxf_parse_structural_metadata(mxf); } +static int mxf_read_packet_old(AVFormatContext *s, AVPacket *pkt) +{ + KLVPacket klv; + + while (!url_feof(s->pb)) { + if (klv_read_packet(&klv, s->pb) < 0) + return -1; + PRINT_KEY(s, "read packet", klv.key); + av_dlog(s, "size %"PRIu64" offset %#"PRIx64"\n", klv.length, klv.offset); + if (IS_KLV_KEY(klv.key, mxf_encrypted_triplet_key)) { + int res = mxf_decrypt_triplet(s, pkt, &klv); + if (res < 0) { + av_log(s, AV_LOG_ERROR, "invalid encoded triplet\n"); + return -1; + } + return 0; + } + if (IS_KLV_KEY(klv.key, mxf_essence_element_key) || + IS_KLV_KEY(klv.key, mxf_avid_essence_element_key)) { + int index = mxf_get_stream_index(s, &klv); + if (index < 0) { + av_log(s, AV_LOG_ERROR, "error getting stream index %d\n", AV_RB32(klv.key+12)); + goto skip; + } + if (s->streams[index]->discard == AVDISCARD_ALL) + goto skip; + /* check for 8 channels AES3 element */ + if (klv.key[12] == 0x06 && klv.key[13] == 0x01 && klv.key[14] == 0x10) { + if (mxf_get_d10_aes3_packet(s->pb, s->streams[index], pkt, klv.length) < 0) { + av_log(s, AV_LOG_ERROR, "error reading D-10 aes3 frame\n"); + return -1; + } + } else { + int ret = av_get_packet(s->pb, pkt, klv.length); + if (ret < 0) + return ret; + } + pkt->stream_index = index; + pkt->pos = klv.offset; + return 0; + } else + skip: + avio_skip(s->pb, klv.length); + } + return AVERROR_EOF; +} + +static int mxf_read_packet(AVFormatContext *s, AVPacket *pkt) +{ + MXFContext *mxf = s->priv_data; + AVIndexEntry *e; + int ret; + int64_t ret64; + KLVPacket klv; + AVStream *st; + + /* TODO: better logic for this? + * only files that lack all index segments prior to the essence need this */ + if (!s->pb->seekable && mxf->op != OPAtom || mxf->d10 || mxf->broken_index) + return mxf_read_packet_old(s, pkt); + + if (mxf->current_stream >= s->nb_streams) { + mxf->current_edit_unit++; + mxf->current_stream = 0; + } + + st = s->streams[mxf->current_stream]; + + if (mxf->current_edit_unit >= st->nb_index_entries) + return AVERROR_EOF; + + e = &st->index_entries[mxf->current_edit_unit]; + + if ((ret64 = avio_seek(s->pb, e->pos, SEEK_SET)) < 0) + return ret64; + + if (mxf->op == OPAtom) { + /* OPAtom - no KL, just essence */ + if ((ret = av_get_packet(s->pb, pkt, e->size)) != e->size) + return ret < 0 ? ret : AVERROR_EOF; + } else { + /* read KL, read L bytes of essence */ + if ((ret = klv_read_packet(&klv, s->pb)) < 0) + return ret; + + /* untested, but looks OK */ + if (IS_KLV_KEY(klv.key, mxf_encrypted_triplet_key)) { + int res = mxf_decrypt_triplet(s, pkt, &klv); + if (res < 0) { + av_log(s, AV_LOG_ERROR, "invalid encoded triplet\n"); + return -1; + } + return 0; + } + + if ((ret = av_get_packet(s->pb, pkt, klv.length)) != klv.length) + return ret < 0 ? ret : AVERROR_EOF; + + pkt->pos = e->pos; + } + + if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO && mxf->ptses && mxf->current_edit_unit < mxf->nb_ptses) { + pkt->dts = mxf->current_edit_unit + mxf->first_dts; + pkt->pts = mxf->ptses[mxf->current_edit_unit]; + } + + pkt->stream_index = mxf->current_stream++; + + return 0; +} + static int mxf_read_close(AVFormatContext *s) { MXFContext *mxf = s->priv_data; From 8ce41721a4a29711211f8dad0c86502caf86f4d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomas=20H=C3=A4rdin?= Date: Thu, 15 Dec 2011 16:47:49 +0100 Subject: [PATCH 2/8] mxfdec: Add MXFIndexTables This structs collects MXFIndexTableSegments belonging to one IndexSID and some other bits of useful information. --- libavformat/mxfdec.c | 97 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) diff --git a/libavformat/mxfdec.c b/libavformat/mxfdec.c index 8447da5d2b..88eb4c4927 100644 --- a/libavformat/mxfdec.c +++ b/libavformat/mxfdec.c @@ -177,6 +177,17 @@ typedef struct { enum MXFMetadataSetType type; } MXFMetadataSet; +/* decoded index table */ +typedef struct { + int index_sid; + int body_sid; + int nb_ptses; /* number of PTSes or total duration of index */ + int64_t first_dts; /* DTS = EditUnit + first_dts */ + int64_t *ptses; /* maps EditUnit -> PTS */ + int nb_segments; + MXFIndexTableSegment **segments; /* sorted by IndexStartPosition */ +} MXFIndexTable; + typedef struct { MXFPartition *partitions; unsigned partitions_count; @@ -204,6 +215,8 @@ typedef struct { int64_t first_dts; /* DTS = EditUnit + first_dts */ int64_t *ptses; /* maps EditUnit -> PTS */ int nb_ptses; + int nb_index_tables; + MXFIndexTable *index_tables; } MXFContext; enum MXFWrappingScheme { @@ -1211,6 +1224,72 @@ static int mxf_compute_ptses(MXFContext *mxf, MXFIndexTableSegment **sorted_segm return 0; } +/** + * Sorts and collects index table segments into index tables. + * Also computes PTSes if possible. + */ +static int mxf_compute_index_tables(MXFContext *mxf) +{ + int i, j, ret, nb_sorted_segments; + MXFIndexTableSegment **sorted_segments = NULL; + + if ((ret = mxf_get_sorted_table_segments(mxf, &nb_sorted_segments, &sorted_segments)) || + nb_sorted_segments <= 0) { + av_log(mxf->fc, AV_LOG_WARNING, "broken or empty index\n"); + return 0; + } + + /* sanity check and count unique BodySIDs/IndexSIDs */ + for (i = 0; i < nb_sorted_segments; i++) { + if (i == 0 || sorted_segments[i-1]->index_sid != sorted_segments[i]->index_sid) + mxf->nb_index_tables++; + else if (sorted_segments[i-1]->body_sid != sorted_segments[i]->body_sid) { + av_log(mxf->fc, AV_LOG_ERROR, "found inconsistent BodySID\n"); + ret = AVERROR_INVALIDDATA; + goto finish_decoding_index; + } + } + + if (!(mxf->index_tables = av_calloc(mxf->nb_index_tables, sizeof(MXFIndexTable)))) { + av_log(mxf->fc, AV_LOG_ERROR, "failed to allocate index tables\n"); + ret = AVERROR(ENOMEM); + goto finish_decoding_index; + } + + /* distribute sorted segments to index tables */ + for (i = j = 0; i < nb_sorted_segments; i++) { + if (i != 0 && sorted_segments[i-1]->index_sid != sorted_segments[i]->index_sid) { + /* next IndexSID */ + j++; + } + + mxf->index_tables[j].nb_segments++; + } + + for (i = j = 0; j < mxf->nb_index_tables; i += mxf->index_tables[j++].nb_segments) { + MXFIndexTable *t = &mxf->index_tables[j]; + + if (!(t->segments = av_calloc(t->nb_segments, sizeof(MXFIndexTableSegment*)))) { + av_log(mxf->fc, AV_LOG_ERROR, "failed to allocate IndexTableSegment pointer array\n"); + ret = AVERROR(ENOMEM); + goto finish_decoding_index; + } + + if (sorted_segments[i]->index_start_position) + av_log(mxf->fc, AV_LOG_WARNING, "IndexSID %i starts at EditUnit %"PRId64" - seeking may not work as expected\n", + sorted_segments[i]->index_sid, sorted_segments[i]->index_start_position); + + memcpy(t->segments, &sorted_segments[i], t->nb_segments * sizeof(MXFIndexTableSegment*)); + t->index_sid = sorted_segments[i]->index_sid; + t->body_sid = sorted_segments[i]->body_sid; + } + + ret = 0; +finish_decoding_index: + av_free(sorted_segments); + return ret; +} + static int mxf_parse_structural_metadata(MXFContext *mxf) { MXFPackage *material_package = NULL; @@ -1617,6 +1696,7 @@ static int mxf_read_header(AVFormatContext *s, AVFormatParameters *ap) MXFContext *mxf = s->priv_data; KLVPacket klv; int64_t essence_offset = 0; + int ret; mxf->last_forward_tell = INT64_MAX; @@ -1712,6 +1792,18 @@ static int mxf_read_header(AVFormatContext *s, AVFormatParameters *ap) mxf_compute_essence_containers(mxf); + if ((ret = mxf_compute_index_tables(mxf)) < 0) + return ret; + + if (mxf->nb_index_tables > 1) { + /* TODO: look up which IndexSID to use via EssenceContainerData */ + av_log(mxf->fc, AV_LOG_INFO, "got %i index tables - only the first one (IndexSID %i) will be used\n", + mxf->nb_index_tables, mxf->index_tables[0].index_sid); + } else if (mxf->nb_index_tables == 0 && mxf->op == OPAtom) { + av_log(mxf->fc, AV_LOG_ERROR, "cannot demux OPAtom without an index\n"); + return AVERROR_INVALIDDATA; + } + return mxf_parse_structural_metadata(mxf); } @@ -1871,6 +1963,11 @@ static int mxf_read_close(AVFormatContext *s) av_freep(&mxf->aesc); av_freep(&mxf->local_tags); av_freep(&mxf->ptses); + + for (i = 0; i < mxf->nb_index_tables; i++) + av_freep(&mxf->index_tables[i].segments); + av_freep(&mxf->index_tables); + return 0; } From 2212e040b72646a2c0588bc90f1a05760121a495 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomas=20H=C3=A4rdin?= Date: Fri, 16 Dec 2011 09:42:52 +0100 Subject: [PATCH 3/8] mxfdec: Add "fake" index to MXFIndexTable to assist seeking This changes mxf_compute_ptses() to be used for MXFIndexTable, and also adds code for computing the fake index to it. This also temporarily disables PTS computation. A future patch will restore it. --- libavformat/mxfdec.c | 48 ++++++++++++++++++++++++----------------- tests/ref/seek/lavf_mxf | 44 ++++++++++++++++++------------------- 2 files changed, 50 insertions(+), 42 deletions(-) diff --git a/libavformat/mxfdec.c b/libavformat/mxfdec.c index 88eb4c4927..8e45562db9 100644 --- a/libavformat/mxfdec.c +++ b/libavformat/mxfdec.c @@ -186,6 +186,7 @@ typedef struct { int64_t *ptses; /* maps EditUnit -> PTS */ int nb_segments; MXFIndexTableSegment **segments; /* sorted by IndexStartPosition */ + AVIndexEntry *fake_index; /* used for calling ff_index_search_timestamp() */ } MXFIndexTable; typedef struct { @@ -1139,35 +1140,35 @@ static int mxf_parse_index(MXFContext *mxf, int track_id, AVStream *st, MXFIndex return 0; } -static int mxf_compute_ptses(MXFContext *mxf, MXFIndexTableSegment **sorted_segments, int nb_sorted_segments) +static int mxf_compute_ptses_fake_index(MXFContext *mxf, MXFIndexTable *index_table) { - int ret, i, j, x; + int i, j, x; int8_t max_temporal_offset = -128; /* first compute how many entries we have */ - for (i = 0; i < nb_sorted_segments; i++) { - MXFIndexTableSegment *s = sorted_segments[i]; + for (i = 0; i < index_table->nb_segments; i++) { + MXFIndexTableSegment *s = index_table->segments[i]; if (!s->nb_index_entries) return 0; /* no TemporalOffsets */ - if (s->nb_index_entries == 2 * s->index_duration + 1) - mxf->nb_ptses += s->index_duration; /* Avid index */ - else - mxf->nb_ptses += s->nb_index_entries; + index_table->nb_ptses += s->index_duration; } /* paranoid check */ - if (mxf->nb_ptses <= 0) + if (index_table->nb_ptses <= 0) return 0; - if (!(mxf->ptses = av_calloc(mxf->nb_ptses, sizeof(int64_t)))) + if (!(index_table->ptses = av_calloc(index_table->nb_ptses, sizeof(int64_t))) || + !(index_table->fake_index = av_calloc(index_table->nb_ptses, sizeof(AVIndexEntry)))) { + av_freep(&index_table->ptses); return AVERROR(ENOMEM); + } /* we may have a few bad TemporalOffsets * make sure the corresponding PTSes don't have the bogus value 0 */ - for (x = 0; x < mxf->nb_ptses; x++) - mxf->ptses[x] = AV_NOPTS_VALUE; + for (x = 0; x < index_table->nb_ptses; x++) + index_table->ptses[x] = AV_NOPTS_VALUE; /** * We have this: @@ -1196,8 +1197,8 @@ static int mxf_compute_ptses(MXFContext *mxf, MXFIndexTableSegment **sorted_segm * then settings mxf->first_dts = -max(TemporalOffset[x]). * The latter makes DTS <= PTS. */ - for (i = x = 0; i < nb_sorted_segments; i++) { - MXFIndexTableSegment *s = sorted_segments[i]; + for (i = x = 0; i < index_table->nb_segments; i++) { + MXFIndexTableSegment *s = index_table->segments[i]; int index_delta = 1; if (s->nb_index_entries == 2 * s->index_duration + 1) @@ -1207,19 +1208,22 @@ static int mxf_compute_ptses(MXFContext *mxf, MXFIndexTableSegment **sorted_segm int offset = s->temporal_offset_entries[j] / index_delta; int index = x + offset; - if (index < 0 || index >= mxf->nb_ptses) { + index_table->fake_index[x].timestamp = x; + index_table->fake_index[x].flags = !(s->flag_entries[j] & 0x30) ? AVINDEX_KEYFRAME : 0; + + if (index < 0 || index >= index_table->nb_ptses) { av_log(mxf->fc, AV_LOG_ERROR, "index entry %i + TemporalOffset %i = %i, which is out of bounds\n", x, offset, index); continue; } - mxf->ptses[index] = x; + index_table->ptses[index] = x; max_temporal_offset = FFMAX(max_temporal_offset, offset); } } - mxf->first_dts = -max_temporal_offset; + index_table->first_dts = -max_temporal_offset; return 0; } @@ -1282,6 +1286,9 @@ static int mxf_compute_index_tables(MXFContext *mxf) memcpy(t->segments, &sorted_segments[i], t->nb_segments * sizeof(MXFIndexTableSegment*)); t->index_sid = sorted_segments[i]->index_sid; t->body_sid = sorted_segments[i]->body_sid; + + if ((ret = mxf_compute_ptses_fake_index(mxf, t)) < 0) + goto finish_decoding_index; } ret = 0; @@ -1496,8 +1503,7 @@ static int mxf_parse_structural_metadata(MXFContext *mxf) goto fail_and_free; } - ret = mxf_compute_ptses(mxf, sorted_segments, nb_sorted_segments); - + ret = 0; fail_and_free: av_free(sorted_segments); return ret; @@ -1964,8 +1970,10 @@ static int mxf_read_close(AVFormatContext *s) av_freep(&mxf->local_tags); av_freep(&mxf->ptses); - for (i = 0; i < mxf->nb_index_tables; i++) + for (i = 0; i < mxf->nb_index_tables; i++) { av_freep(&mxf->index_tables[i].segments); + av_freep(&mxf->index_tables[i].fake_index); + } av_freep(&mxf->index_tables); return 0; diff --git a/tests/ref/seek/lavf_mxf b/tests/ref/seek/lavf_mxf index cc634a8af2..00dea3d8fd 100644 --- a/tests/ref/seek/lavf_mxf +++ b/tests/ref/seek/lavf_mxf @@ -1,48 +1,48 @@ -ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 6144 size: 24801 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 6144 size: 24801 ret: 0 st:-1 flags:0 ts:-1.000000 -ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 6144 size: 24801 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 6144 size: 24801 ret: 0 st:-1 flags:1 ts: 1.894167 -ret: 0 st: 0 flags:1 dts: 0.840000 pts: 0.960000 pos: 460800 size: 24712 +ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 460800 size: 24712 ret: 0 st: 0 flags:0 ts: 0.800000 -ret: 0 st: 0 flags:1 dts: 0.840000 pts: 0.960000 pos: 460800 size: 24712 +ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 460800 size: 24712 ret: 0 st: 0 flags:1 ts:-0.320000 -ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 6144 size: 24801 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 6144 size: 24801 ret:-1 st: 1 flags:0 ts: 2.560000 ret: 0 st: 1 flags:1 ts: 1.480000 -ret: 0 st: 0 flags:1 dts: 0.840000 pts: 0.960000 pos: 460800 size: 24712 +ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 460800 size: 24712 ret: 0 st:-1 flags:0 ts: 0.365002 -ret: 0 st: 0 flags:1 dts: 0.360000 pts: 0.480000 pos: 211968 size: 24787 +ret: 0 st: 0 flags:1 dts: 0.400000 pts: NOPTS pos: 211968 size: 24787 ret: 0 st:-1 flags:1 ts:-0.740831 -ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 6144 size: 24801 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 6144 size: 24801 ret:-1 st: 0 flags:0 ts: 2.160000 ret: 0 st: 0 flags:1 ts: 1.040000 -ret: 0 st: 0 flags:1 dts: 0.840000 pts: 0.960000 pos: 460800 size: 24712 +ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 460800 size: 24712 ret: 0 st: 1 flags:0 ts:-0.040000 -ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 6144 size: 24801 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 6144 size: 24801 ret: 0 st: 1 flags:1 ts: 2.840000 -ret: 0 st: 0 flags:1 dts: 0.840000 pts: 0.960000 pos: 460800 size: 24712 +ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 460800 size: 24712 ret:-1 st:-1 flags:0 ts: 1.730004 ret: 0 st:-1 flags:1 ts: 0.624171 -ret: 0 st: 0 flags:1 dts: 0.360000 pts: 0.480000 pos: 211968 size: 24787 +ret: 0 st: 0 flags:1 dts: 0.400000 pts: NOPTS pos: 211968 size: 24787 ret: 0 st: 0 flags:0 ts:-0.480000 -ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 6144 size: 24801 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 6144 size: 24801 ret: 0 st: 0 flags:1 ts: 2.400000 -ret: 0 st: 0 flags:1 dts: 0.840000 pts: 0.960000 pos: 460800 size: 24712 +ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 460800 size: 24712 ret:-1 st: 1 flags:0 ts: 1.320000 ret: 0 st: 1 flags:1 ts: 0.200000 -ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 6144 size: 24801 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 6144 size: 24801 ret: 0 st:-1 flags:0 ts:-0.904994 -ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 6144 size: 24801 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 6144 size: 24801 ret: 0 st:-1 flags:1 ts: 1.989173 -ret: 0 st: 0 flags:1 dts: 0.840000 pts: 0.960000 pos: 460800 size: 24712 +ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 460800 size: 24712 ret: 0 st: 0 flags:0 ts: 0.880000 -ret: 0 st: 0 flags:1 dts: 0.840000 pts: 0.960000 pos: 460800 size: 24712 +ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 460800 size: 24712 ret: 0 st: 0 flags:1 ts:-0.240000 -ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 6144 size: 24801 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 6144 size: 24801 ret:-1 st: 1 flags:0 ts: 2.680000 ret: 0 st: 1 flags:1 ts: 1.560000 -ret: 0 st: 0 flags:1 dts: 0.840000 pts: 0.960000 pos: 460800 size: 24712 +ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 460800 size: 24712 ret: 0 st:-1 flags:0 ts: 0.460008 -ret: 0 st: 0 flags:1 dts: 0.840000 pts: 0.960000 pos: 460800 size: 24712 +ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 460800 size: 24712 ret: 0 st:-1 flags:1 ts:-0.645825 -ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 6144 size: 24801 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 6144 size: 24801 From b56adc784288bdbe5e34e581e8081b51a2a3eb5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomas=20H=C3=A4rdin?= Date: Fri, 16 Dec 2011 09:50:58 +0100 Subject: [PATCH 4/8] mxfdec: Replace zero IndexDurations with st->duration The mxf_d10 muxer outputs files with zero IndexDurations.. --- libavformat/mxfdec.c | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/libavformat/mxfdec.c b/libavformat/mxfdec.c index 8e45562db9..cb2dbf78ea 100644 --- a/libavformat/mxfdec.c +++ b/libavformat/mxfdec.c @@ -1234,7 +1234,7 @@ static int mxf_compute_ptses_fake_index(MXFContext *mxf, MXFIndexTable *index_ta */ static int mxf_compute_index_tables(MXFContext *mxf) { - int i, j, ret, nb_sorted_segments; + int i, j, k, ret, nb_sorted_segments; MXFIndexTableSegment **sorted_segments = NULL; if ((ret = mxf_get_sorted_table_segments(mxf, &nb_sorted_segments, &sorted_segments)) || @@ -1289,6 +1289,27 @@ static int mxf_compute_index_tables(MXFContext *mxf) if ((ret = mxf_compute_ptses_fake_index(mxf, t)) < 0) goto finish_decoding_index; + + /* fix zero IndexDurations */ + for (k = 0; k < t->nb_segments; k++) { + if (t->segments[k]->index_duration) + continue; + + if (t->nb_segments > 1) + av_log(mxf->fc, AV_LOG_WARNING, "IndexSID %i segment %i has zero IndexDuration and there's more than one segment\n", + t->index_sid, k); + + if (mxf->fc->nb_streams <= 0) { + av_log(mxf->fc, AV_LOG_WARNING, "no streams?\n"); + break; + } + + /* assume the first stream's duration is reasonable + * leave index_duration = 0 on further segments in case we have any (unlikely) + */ + t->segments[k]->index_duration = mxf->fc->streams[0]->duration; + break; + } } ret = 0; @@ -1798,6 +1819,11 @@ static int mxf_read_header(AVFormatContext *s, AVFormatParameters *ap) mxf_compute_essence_containers(mxf); + /* we need to do this before computing the index tables + * to be able to fill in zero IndexDurations with st->duration */ + if ((ret = mxf_parse_structural_metadata(mxf)) < 0) + return ret; + if ((ret = mxf_compute_index_tables(mxf)) < 0) return ret; @@ -1810,7 +1836,7 @@ static int mxf_read_header(AVFormatContext *s, AVFormatParameters *ap) return AVERROR_INVALIDDATA; } - return mxf_parse_structural_metadata(mxf); + return 0; } static int mxf_read_packet_old(AVFormatContext *s, AVPacket *pkt) From 36c305f9db0ed9e0a4313f11683ea0de7efc496f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomas=20H=C3=A4rdin?= Date: Thu, 15 Dec 2011 16:53:38 +0100 Subject: [PATCH 5/8] mxfdec: Add mxf_edit_unit_absolute_offset() This maps an EditUnit in an index table to the corresponding absolute offset in the file. --- libavformat/mxfdec.c | 49 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/libavformat/mxfdec.c b/libavformat/mxfdec.c index cb2dbf78ea..98a71459b6 100644 --- a/libavformat/mxfdec.c +++ b/libavformat/mxfdec.c @@ -1014,6 +1014,55 @@ static int64_t mxf_essence_container_length(MXFContext *mxf, int body_sid) return ret; } +/* EditUnit -> absolute offset */ +static int mxf_edit_unit_absolute_offset(MXFContext *mxf, MXFIndexTable *index_table, int64_t edit_unit, int64_t *edit_unit_out, int64_t *offset_out, int nag) +{ + int i; + int offset_temp = 0; + + for (i = 0; i < index_table->nb_segments; i++) { + MXFIndexTableSegment *s = index_table->segments[i]; + + edit_unit = FFMAX(edit_unit, s->index_start_position); /* clamp if trying to seek before start */ + + if (edit_unit < s->index_start_position + s->index_duration) { + int64_t index = edit_unit - s->index_start_position; + + if (s->edit_unit_byte_count) + offset_temp += s->edit_unit_byte_count * index; + else if (s->nb_index_entries) { + if (s->nb_index_entries == 2 * s->index_duration + 1) + index *= 2; /* Avid index */ + + if (index < 0 || index > s->nb_index_entries) { + av_log(mxf->fc, AV_LOG_ERROR, "IndexSID %i segment at %"PRId64" IndexEntryArray too small\n", + index_table->index_sid, s->index_start_position); + return AVERROR_INVALIDDATA; + } + + offset_temp = s->stream_offset_entries[index]; + } else { + av_log(mxf->fc, AV_LOG_ERROR, "IndexSID %i segment at %"PRId64" missing EditUnitByteCount and IndexEntryArray\n", + index_table->index_sid, s->index_start_position); + return AVERROR_INVALIDDATA; + } + + if (edit_unit_out) + *edit_unit_out = edit_unit; + + return mxf_absolute_bodysid_offset(mxf, index_table->body_sid, offset_temp, offset_out); + } else { + /* EditUnitByteCount == 0 for VBR indexes, which is fine since they use explicit StreamOffsets */ + offset_temp += s->edit_unit_byte_count * s->index_duration; + } + } + + if (nag) + av_log(mxf->fc, AV_LOG_ERROR, "failed to map EditUnit %"PRId64" in IndexSID %i to an offset\n", edit_unit, index_table->index_sid); + + return AVERROR_INVALIDDATA; +} + static int mxf_parse_index(MXFContext *mxf, int track_id, AVStream *st, MXFIndexTableSegment **sorted_segments, int nb_sorted_segments) { int64_t accumulated_offset = 0; From 2eba8da67572c7e9fa06191fd86312ae42116630 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomas=20H=C3=A4rdin?= Date: Fri, 16 Dec 2011 10:53:41 +0100 Subject: [PATCH 6/8] mxfdec: Hybrid demuxing/seeking solution This uses the old demuxing code for OP1a and separate demuxing code for OPAtom. Timestamp output is added to the old demuxing code. The seeking code is made to seek to the start of the desired EditUnit only, from which the normal demuxing code takes over (if OP1a). This means we don't use delta entries or slices, only StreamOffsets. OPAtom seeking basically works like before. This also makes D-10 seeking behave the same way as OP1a and OPAtom. In other words, we allow seeking before the start or past the end for D-10 too. This fixes ticket #746. --- libavformat/mxfdec.c | 163 +++++++++++++++++++++++------------- tests/ref/seek/lavf_mxf | 44 +++++----- tests/ref/seek/lavf_mxf_d10 | 36 ++++---- 3 files changed, 144 insertions(+), 99 deletions(-) diff --git a/libavformat/mxfdec.c b/libavformat/mxfdec.c index 98a71459b6..bf70d7cbcb 100644 --- a/libavformat/mxfdec.c +++ b/libavformat/mxfdec.c @@ -1014,6 +1014,29 @@ static int64_t mxf_essence_container_length(MXFContext *mxf, int body_sid) return ret; } +/** + * Returns the end position of the essence container with given BodySID, or zero if unknown + */ +static int64_t mxf_essence_container_end(MXFContext *mxf, int body_sid) +{ + int x; + int64_t ret = 0; + + for (x = 0; x < mxf->partitions_count; x++) { + MXFPartition *p = &mxf->partitions[x]; + + if (p->body_sid != body_sid) + continue; + + if (!p->essence_length) + return 0; + + ret = p->essence_offset + p->essence_length; + } + + return ret; +} + /* EditUnit -> absolute offset */ static int mxf_edit_unit_absolute_offset(MXFContext *mxf, MXFIndexTable *index_table, int64_t edit_unit, int64_t *edit_unit_out, int64_t *offset_out, int nag) { @@ -1888,6 +1911,32 @@ static int mxf_read_header(AVFormatContext *s, AVFormatParameters *ap) return 0; } +/** + * Computes DTS and PTS for the given video packet based on its offset. + */ +static void mxf_packet_timestamps(MXFContext *mxf, AVPacket *pkt) +{ + int64_t next_ofs; + MXFIndexTable *t = &mxf->index_tables[0]; + + /* find mxf->current_edit_unit so that the next edit unit starts ahead of pkt->pos */ + for (;;) { + if (mxf_edit_unit_absolute_offset(mxf, t, mxf->current_edit_unit + 1, NULL, &next_ofs, 0) < 0) + break; + + if (next_ofs > pkt->pos) + break; + + mxf->current_edit_unit++; + } + + if (mxf->current_edit_unit >= t->nb_ptses) + return; + + pkt->dts = mxf->current_edit_unit + t->first_dts; + pkt->pts = t->ptses[mxf->current_edit_unit]; +} + static int mxf_read_packet_old(AVFormatContext *s, AVPacket *pkt) { KLVPacket klv; @@ -1927,6 +1976,10 @@ static int mxf_read_packet_old(AVFormatContext *s, AVPacket *pkt) } pkt->stream_index = index; pkt->pos = klv.offset; + + if (s->streams[index]->codec->codec_type == AVMEDIA_TYPE_VIDEO) + mxf_packet_timestamps(s->priv_data, pkt); /* offset -> EditUnit -> DTS/PTS */ + return 0; } else skip: @@ -1938,63 +1991,51 @@ static int mxf_read_packet_old(AVFormatContext *s, AVPacket *pkt) static int mxf_read_packet(AVFormatContext *s, AVPacket *pkt) { MXFContext *mxf = s->priv_data; - AVIndexEntry *e; - int ret; - int64_t ret64; - KLVPacket klv; + int ret, size; + int64_t ret64, pos, next_pos; AVStream *st; + MXFIndexTable *t; - /* TODO: better logic for this? - * only files that lack all index segments prior to the essence need this */ - if (!s->pb->seekable && mxf->op != OPAtom || mxf->d10 || mxf->broken_index) + if (mxf->op != OPAtom) return mxf_read_packet_old(s, pkt); - if (mxf->current_stream >= s->nb_streams) { - mxf->current_edit_unit++; - mxf->current_stream = 0; - } + /* OPAtom - clip wrapped demuxing */ + st = s->streams[0]; + t = &mxf->index_tables[0]; - st = s->streams[mxf->current_stream]; - - if (mxf->current_edit_unit >= st->nb_index_entries) + if (mxf->current_edit_unit >= st->duration) return AVERROR_EOF; - e = &st->index_entries[mxf->current_edit_unit]; + if ((ret = mxf_edit_unit_absolute_offset(mxf, t, mxf->current_edit_unit, NULL, &pos, 1)) < 0) + return ret; - if ((ret64 = avio_seek(s->pb, e->pos, SEEK_SET)) < 0) + /* compute size by finding the next edit unit or the end of the essence container + * not pretty, but it works */ + if ((ret = mxf_edit_unit_absolute_offset(mxf, t, mxf->current_edit_unit + 1, NULL, &next_pos, 0)) < 0 && + (next_pos = mxf_essence_container_end(mxf, t->body_sid)) <= 0) { + av_log(s, AV_LOG_ERROR, "unable to compute the size of the last packet\n"); + return AVERROR_INVALIDDATA; + } + + if ((size = next_pos - pos) <= 0) { + av_log(s, AV_LOG_ERROR, "bad size: %i\n", size); + return AVERROR_INVALIDDATA; + } + + if ((ret64 = avio_seek(s->pb, pos, SEEK_SET)) < 0) return ret64; - if (mxf->op == OPAtom) { - /* OPAtom - no KL, just essence */ - if ((ret = av_get_packet(s->pb, pkt, e->size)) != e->size) - return ret < 0 ? ret : AVERROR_EOF; - } else { - /* read KL, read L bytes of essence */ - if ((ret = klv_read_packet(&klv, s->pb)) < 0) - return ret; - - /* untested, but looks OK */ - if (IS_KLV_KEY(klv.key, mxf_encrypted_triplet_key)) { - int res = mxf_decrypt_triplet(s, pkt, &klv); - if (res < 0) { - av_log(s, AV_LOG_ERROR, "invalid encoded triplet\n"); - return -1; - } - return 0; - } - - if ((ret = av_get_packet(s->pb, pkt, klv.length)) != klv.length) + if ((ret = av_get_packet(s->pb, pkt, size)) != size) return ret < 0 ? ret : AVERROR_EOF; - pkt->pos = e->pos; + if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO && t->ptses && + mxf->current_edit_unit >= 0 && mxf->current_edit_unit < t->nb_ptses) { + pkt->dts = mxf->current_edit_unit + t->first_dts; + pkt->pts = t->ptses[mxf->current_edit_unit]; } - if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO && mxf->ptses && mxf->current_edit_unit < mxf->nb_ptses) { - pkt->dts = mxf->current_edit_unit + mxf->first_dts; - pkt->pts = mxf->ptses[mxf->current_edit_unit]; - } - - pkt->stream_index = mxf->current_stream++; + pkt->stream_index = 0; + mxf->current_edit_unit++; return 0; } @@ -2078,9 +2119,10 @@ static int mxf_read_seek(AVFormatContext *s, int stream_index, int64_t sample_ti int64_t seconds; MXFContext* mxf = s->priv_data; int64_t seekpos; - int index; + int ret; + MXFIndexTable *t; - if (mxf->d10) { + if (mxf->index_tables <= 0) { if (!s->bit_rate) return -1; if (sample_time < 0) @@ -2090,24 +2132,27 @@ static int mxf_read_seek(AVFormatContext *s, int stream_index, int64_t sample_ti return -1; ff_update_cur_dts(s, st, sample_time); } else { - if (st->nb_index_entries <= 0) - return -1; + t = &mxf->index_tables[0]; - index = av_index_search_timestamp(st, sample_time, flags); + /* clamp above zero, else ff_index_search_timestamp() returns negative + * this also means we allow seeking before the start */ + sample_time = FFMAX(sample_time, 0); - av_dlog(s, "stream %d, timestamp %"PRId64", sample %d\n", st->index, sample_time, index); - - if (index < 0) { - if (sample_time < st->index_entries[0].timestamp) - index = 0; - else - return -1; + if (t->fake_index) { + /* behave as if we have a proper index */ + if ((sample_time = ff_index_search_timestamp(t->fake_index, t->nb_ptses, sample_time, flags)) < 0) + return sample_time; + } else { + /* no IndexEntryArray (one or more CBR segments) + * make sure we don't seek past the end */ + sample_time = FFMIN(sample_time, st->duration - 1); } - seekpos = st->index_entries[index].pos; - av_update_cur_dts(s, st, st->index_entries[index].timestamp); - mxf->current_edit_unit = st->index_entries[index].timestamp; - mxf->current_stream = 0; + if ((ret = mxf_edit_unit_absolute_offset(mxf, t, sample_time, &sample_time, &seekpos, 1)) << 0) + return ret; + + av_update_cur_dts(s, st, sample_time); + mxf->current_edit_unit = sample_time; avio_seek(s->pb, seekpos, SEEK_SET); } return 0; diff --git a/tests/ref/seek/lavf_mxf b/tests/ref/seek/lavf_mxf index 00dea3d8fd..cc634a8af2 100644 --- a/tests/ref/seek/lavf_mxf +++ b/tests/ref/seek/lavf_mxf @@ -1,48 +1,48 @@ -ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 6144 size: 24801 +ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 6144 size: 24801 ret: 0 st:-1 flags:0 ts:-1.000000 -ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 6144 size: 24801 +ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 6144 size: 24801 ret: 0 st:-1 flags:1 ts: 1.894167 -ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 460800 size: 24712 +ret: 0 st: 0 flags:1 dts: 0.840000 pts: 0.960000 pos: 460800 size: 24712 ret: 0 st: 0 flags:0 ts: 0.800000 -ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 460800 size: 24712 +ret: 0 st: 0 flags:1 dts: 0.840000 pts: 0.960000 pos: 460800 size: 24712 ret: 0 st: 0 flags:1 ts:-0.320000 -ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 6144 size: 24801 +ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 6144 size: 24801 ret:-1 st: 1 flags:0 ts: 2.560000 ret: 0 st: 1 flags:1 ts: 1.480000 -ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 460800 size: 24712 +ret: 0 st: 0 flags:1 dts: 0.840000 pts: 0.960000 pos: 460800 size: 24712 ret: 0 st:-1 flags:0 ts: 0.365002 -ret: 0 st: 0 flags:1 dts: 0.400000 pts: NOPTS pos: 211968 size: 24787 +ret: 0 st: 0 flags:1 dts: 0.360000 pts: 0.480000 pos: 211968 size: 24787 ret: 0 st:-1 flags:1 ts:-0.740831 -ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 6144 size: 24801 +ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 6144 size: 24801 ret:-1 st: 0 flags:0 ts: 2.160000 ret: 0 st: 0 flags:1 ts: 1.040000 -ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 460800 size: 24712 +ret: 0 st: 0 flags:1 dts: 0.840000 pts: 0.960000 pos: 460800 size: 24712 ret: 0 st: 1 flags:0 ts:-0.040000 -ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 6144 size: 24801 +ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 6144 size: 24801 ret: 0 st: 1 flags:1 ts: 2.840000 -ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 460800 size: 24712 +ret: 0 st: 0 flags:1 dts: 0.840000 pts: 0.960000 pos: 460800 size: 24712 ret:-1 st:-1 flags:0 ts: 1.730004 ret: 0 st:-1 flags:1 ts: 0.624171 -ret: 0 st: 0 flags:1 dts: 0.400000 pts: NOPTS pos: 211968 size: 24787 +ret: 0 st: 0 flags:1 dts: 0.360000 pts: 0.480000 pos: 211968 size: 24787 ret: 0 st: 0 flags:0 ts:-0.480000 -ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 6144 size: 24801 +ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 6144 size: 24801 ret: 0 st: 0 flags:1 ts: 2.400000 -ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 460800 size: 24712 +ret: 0 st: 0 flags:1 dts: 0.840000 pts: 0.960000 pos: 460800 size: 24712 ret:-1 st: 1 flags:0 ts: 1.320000 ret: 0 st: 1 flags:1 ts: 0.200000 -ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 6144 size: 24801 +ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 6144 size: 24801 ret: 0 st:-1 flags:0 ts:-0.904994 -ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 6144 size: 24801 +ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 6144 size: 24801 ret: 0 st:-1 flags:1 ts: 1.989173 -ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 460800 size: 24712 +ret: 0 st: 0 flags:1 dts: 0.840000 pts: 0.960000 pos: 460800 size: 24712 ret: 0 st: 0 flags:0 ts: 0.880000 -ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 460800 size: 24712 +ret: 0 st: 0 flags:1 dts: 0.840000 pts: 0.960000 pos: 460800 size: 24712 ret: 0 st: 0 flags:1 ts:-0.240000 -ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 6144 size: 24801 +ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 6144 size: 24801 ret:-1 st: 1 flags:0 ts: 2.680000 ret: 0 st: 1 flags:1 ts: 1.560000 -ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 460800 size: 24712 +ret: 0 st: 0 flags:1 dts: 0.840000 pts: 0.960000 pos: 460800 size: 24712 ret: 0 st:-1 flags:0 ts: 0.460008 -ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 460800 size: 24712 +ret: 0 st: 0 flags:1 dts: 0.840000 pts: 0.960000 pos: 460800 size: 24712 ret: 0 st:-1 flags:1 ts:-0.645825 -ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 6144 size: 24801 +ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 6144 size: 24801 diff --git a/tests/ref/seek/lavf_mxf_d10 b/tests/ref/seek/lavf_mxf_d10 index c05870f402..4cfe595415 100644 --- a/tests/ref/seek/lavf_mxf_d10 +++ b/tests/ref/seek/lavf_mxf_d10 @@ -2,52 +2,52 @@ ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 6144 size:150000 ret: 0 st:-1 flags:0 ts:-1.000000 ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 6144 size:150000 ret: 0 st:-1 flags:1 ts: 1.894167 -ret:-1 +ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:5117952 size:150000 ret: 0 st: 0 flags:0 ts: 0.800000 -ret:-1 +ret: 0 st: 0 flags:1 dts: 0.800000 pts: 0.800000 pos:4265984 size:150000 ret: 0 st: 0 flags:1 ts:-0.320000 ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 6144 size:150000 ret: 0 st: 1 flags:0 ts: 2.560000 -ret:-1 +ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:5117952 size:150000 ret: 0 st: 1 flags:1 ts: 1.480000 -ret:-1 +ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:5117952 size:150000 ret: 0 st:-1 flags:0 ts: 0.365002 -ret: 0 st: 0 flags:1 dts: 0.360000 pts: 0.360000 pos: 6144 size:150000 +ret: 0 st: 0 flags:1 dts: 0.360000 pts: 0.360000 pos:1923072 size:150000 ret: 0 st:-1 flags:1 ts:-0.740831 ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 6144 size:150000 ret: 0 st: 0 flags:0 ts: 2.160000 -ret:-1 +ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:5117952 size:150000 ret: 0 st: 0 flags:1 ts: 1.040000 -ret:-1 +ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:5117952 size:150000 ret: 0 st: 1 flags:0 ts:-0.040000 ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 6144 size:150000 ret: 0 st: 1 flags:1 ts: 2.840000 -ret:-1 +ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:5117952 size:150000 ret: 0 st:-1 flags:0 ts: 1.730004 -ret:-1 +ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:5117952 size:150000 ret: 0 st:-1 flags:1 ts: 0.624171 -ret:-1 +ret: 0 st: 0 flags:1 dts: 0.640000 pts: 0.640000 pos:3414016 size:150000 ret: 0 st: 0 flags:0 ts:-0.480000 ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 6144 size:150000 ret: 0 st: 0 flags:1 ts: 2.400000 -ret:-1 +ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:5117952 size:150000 ret: 0 st: 1 flags:0 ts: 1.320000 -ret:-1 +ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:5117952 size:150000 ret: 0 st: 1 flags:1 ts: 0.200000 -ret: 0 st: 0 flags:1 dts: 0.200000 pts: 0.200000 pos: 6144 size:150000 +ret: 0 st: 0 flags:1 dts: 0.200000 pts: 0.200000 pos:1071104 size:150000 ret: 0 st:-1 flags:0 ts:-0.904994 ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 6144 size:150000 ret: 0 st:-1 flags:1 ts: 1.989173 -ret:-1 +ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:5117952 size:150000 ret: 0 st: 0 flags:0 ts: 0.880000 -ret:-1 +ret: 0 st: 0 flags:1 dts: 0.880000 pts: 0.880000 pos:4691968 size:150000 ret: 0 st: 0 flags:1 ts:-0.240000 ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 6144 size:150000 ret: 0 st: 1 flags:0 ts: 2.680000 -ret:-1 +ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:5117952 size:150000 ret: 0 st: 1 flags:1 ts: 1.560000 -ret:-1 +ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:5117952 size:150000 ret: 0 st:-1 flags:0 ts: 0.460008 -ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 6144 size:150000 +ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos:2562048 size:150000 ret: 0 st:-1 flags:1 ts:-0.645825 ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 6144 size:150000 From f98726551c4fdff30099a919e8c4ab746c297f18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomas=20H=C3=A4rdin?= Date: Fri, 16 Dec 2011 10:58:46 +0100 Subject: [PATCH 7/8] mxfdec: Remove dead/useless code --- libavformat/mxfdec.c | 176 +------------------------------------------ 1 file changed, 1 insertion(+), 175 deletions(-) diff --git a/libavformat/mxfdec.c b/libavformat/mxfdec.c index bf70d7cbcb..4438c6992b 100644 --- a/libavformat/mxfdec.c +++ b/libavformat/mxfdec.c @@ -210,12 +210,6 @@ typedef struct { int64_t last_forward_tell; int last_forward_partition; int current_edit_unit; - int current_stream; - int d10; - int broken_index; - int64_t first_dts; /* DTS = EditUnit + first_dts */ - int64_t *ptses; /* maps EditUnit -> PTS */ - int nb_ptses; int nb_index_tables; MXFIndexTable *index_tables; } MXFContext; @@ -904,8 +898,6 @@ static const MXFCodecUL mxf_sound_essence_container_uls[] = { { { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, 0, CODEC_ID_NONE }, }; -static UID mxf_d10_ul = { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x0D,0x01,0x03,0x01,0x02,0x01,0x01,0x01 }; - static int mxf_get_sorted_table_segments(MXFContext *mxf, int *nb_sorted_segments, MXFIndexTableSegment ***sorted_segments) { int i, j, nb_segments = 0; @@ -991,29 +983,6 @@ static int mxf_absolute_bodysid_offset(MXFContext *mxf, int body_sid, int64_t of return AVERROR_INVALIDDATA; } -/** - * Returns the length of the essence container with given BodySID, or zero if unknown - */ -static int64_t mxf_essence_container_length(MXFContext *mxf, int body_sid) -{ - int x; - int64_t ret = 0; - - for (x = 0; x < mxf->partitions_count; x++) { - MXFPartition *p = &mxf->partitions[x]; - - if (p->body_sid != body_sid) - continue; - - if (!p->essence_length) - return 0; - - ret += p->essence_length; - } - - return ret; -} - /** * Returns the end position of the essence container with given BodySID, or zero if unknown */ @@ -1086,132 +1055,6 @@ static int mxf_edit_unit_absolute_offset(MXFContext *mxf, MXFIndexTable *index_t return AVERROR_INVALIDDATA; } -static int mxf_parse_index(MXFContext *mxf, int track_id, AVStream *st, MXFIndexTableSegment **sorted_segments, int nb_sorted_segments) -{ - int64_t accumulated_offset = 0; - int j, k, l, ret; - int n_delta = track_id - 1; /* TrackID = 1-based stream index */ - - if (track_id < 1) { - av_log(mxf->fc, AV_LOG_ERROR, "TrackID not positive: %i\n", track_id); - return AVERROR_INVALIDDATA; - } - - for (j = 0; j < nb_sorted_segments; j++) { - int duration, sample_duration = 1, last_sample_size = 0; - int64_t segment_size; - MXFIndexTableSegment *tableseg = sorted_segments[j]; - int index_delta = 1, last_size_unknown = 0; - int64_t last_pos = 0; - - /* reset accumulated_offset on BodySID change */ - if (j > 0 && tableseg->body_sid != sorted_segments[j-1]->body_sid) - accumulated_offset = 0; - - if (tableseg->nb_index_entries == 2 * tableseg->index_duration + 1) { - /* Avid index - duplicate entries and total size as last entry */ - index_delta = 2; - } - - 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++; - } - - if (duration <= 0) { - av_log(mxf->fc, AV_LOG_WARNING, "0 duration in index for stream %i\n", st->index); - mxf->broken_index = 1; - return 0; - } - - for (k = l = 0; k < duration; k++, l += index_delta) { - int64_t pos; - int size, flags = 0; - - if (l < tableseg->nb_index_entries) { - pos = tableseg->stream_offset_entries[l]; - if (n_delta < tableseg->nb_delta_entries) { - if (n_delta < tableseg->nb_delta_entries - 1) { - size = - tableseg->slice_offset_entries[l][tableseg->slice[n_delta+1]-1] + - tableseg->element_delta[n_delta+1] - - tableseg->element_delta[n_delta]; - if (tableseg->slice[n_delta] > 0) - size -= tableseg->slice_offset_entries[l][tableseg->slice[n_delta]-1]; - } else if (l < tableseg->nb_index_entries - 1) { - size = tableseg->stream_offset_entries[l+1] - - tableseg->stream_offset_entries[l] - - tableseg->slice_offset_entries[l][tableseg->slice[tableseg->nb_delta_entries-1]-1] - - tableseg->element_delta[tableseg->nb_delta_entries-1]; - } else - size = 0; - if (tableseg->slice[n_delta] > 0) - pos += tableseg->slice_offset_entries[l][tableseg->slice[n_delta]-1]; - pos += tableseg->element_delta[n_delta]; - } else - size = 0; - flags = !(tableseg->flag_entries[l] & 0x30) ? AVINDEX_KEYFRAME : 0; - } else { - pos = (int64_t)k * tableseg->edit_unit_byte_count + accumulated_offset; - if (n_delta < tableseg->nb_delta_entries - 1) - 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) - size = last_sample_size; - else - size = tableseg->edit_unit_byte_count; - if (tableseg->nb_delta_entries) - size -= tableseg->element_delta[tableseg->nb_delta_entries-1]; - } - if (n_delta < tableseg->nb_delta_entries) - pos += tableseg->element_delta[n_delta]; - flags = AVINDEX_KEYFRAME; - } - - if (last_size_unknown) - st->index_entries[st->nb_index_entries-1].size = pos - last_pos; - - last_size_unknown = size == 0; - last_pos = pos; - - if (mxf_absolute_bodysid_offset(mxf, tableseg->body_sid, pos, &pos) < 0) { - /* probably partial file - no point going further for this stream */ - break; - } - - av_dlog(mxf->fc, "Stream %d IndexEntry %d TrackID %d Offset %"PRIx64" Timestamp %"PRId64"\n", - st->index, st->nb_index_entries, track_id, pos, sample_duration * st->nb_index_entries); - - if ((ret = av_add_index_entry(st, pos, sample_duration * st->nb_index_entries, size, 0, flags)) < 0) - return ret; - } - - if (last_size_unknown) { - int64_t ecl = mxf_essence_container_length(mxf, tableseg->body_sid); - - if (ecl > 0) - st->index_entries[st->nb_index_entries-1].size = ecl - last_pos; - } - - accumulated_offset += segment_size; - } - - return 0; -} - static int mxf_compute_ptses_fake_index(MXFContext *mxf, MXFIndexTable *index_table) { int i, j, x; @@ -1394,8 +1237,7 @@ static int mxf_parse_structural_metadata(MXFContext *mxf) { MXFPackage *material_package = NULL; MXFPackage *temp_package = NULL; - int i, j, k, ret, nb_sorted_segments; - MXFIndexTableSegment **sorted_segments = NULL; + int i, j, k, ret; av_dlog(mxf->fc, "metadata sets count %d\n", mxf->metadata_sets_count); /* TODO: handle multiple material packages (OP3x) */ @@ -1408,12 +1250,6 @@ static int mxf_parse_structural_metadata(MXFContext *mxf) return -1; } - if ((ret = mxf_get_sorted_table_segments(mxf, &nb_sorted_segments, &sorted_segments)) || - nb_sorted_segments <= 0) { - av_log(mxf->fc, AV_LOG_WARNING, "broken or empty index\n"); - mxf->broken_index = 1; - } - for (i = 0; i < material_package->tracks_count; i++) { MXFPackage *source_package = NULL; MXFTrack *material_track = NULL; @@ -1544,10 +1380,6 @@ static int mxf_parse_structural_metadata(MXFContext *mxf) } } - /* HACK: revert to the old demuxing/seeking scode for D-10 for now */ - if (mxf_match_uid(essence_container_ul, mxf_d10_ul, 14)) - mxf->d10 = 1; - /* TODO: drop PictureEssenceCoding and SoundEssenceCompression, only check EssenceContainer */ codec_ul = mxf_get_codec_ul(ff_mxf_codec_uls, &descriptor->essence_codec_ul); st->codec->codec_id = codec_ul->id; @@ -1590,15 +1422,10 @@ static int mxf_parse_structural_metadata(MXFContext *mxf) /* TODO: decode timestamps */ st->need_parsing = AVSTREAM_PARSE_TIMESTAMPS; } - - if (!mxf->broken_index && - (ret = mxf_parse_index(mxf, material_track->track_id, st, sorted_segments, nb_sorted_segments))) - goto fail_and_free; } ret = 0; fail_and_free: - av_free(sorted_segments); return ret; } @@ -2084,7 +1911,6 @@ static int mxf_read_close(AVFormatContext *s) av_freep(&mxf->metadata_sets); av_freep(&mxf->aesc); av_freep(&mxf->local_tags); - av_freep(&mxf->ptses); for (i = 0; i < mxf->nb_index_tables; i++) { av_freep(&mxf->index_tables[i].segments); From 0e764cf54115adf9b17bb8422116c6c1e3fd08a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomas=20H=C3=A4rdin?= Date: Fri, 16 Dec 2011 11:02:04 +0100 Subject: [PATCH 8/8] mxfdec: Don't parse slices or DeltaEntryArrays The most recent demuxing/seeking code doesn't need them --- libavformat/mxfdec.c | 51 +------------------------------------------- 1 file changed, 1 insertion(+), 50 deletions(-) diff --git a/libavformat/mxfdec.c b/libavformat/mxfdec.c index 4438c6992b..3a0962429c 100644 --- a/libavformat/mxfdec.c +++ b/libavformat/mxfdec.c @@ -148,17 +148,12 @@ typedef struct { int edit_unit_byte_count; int index_sid; int body_sid; - int slice_count; AVRational index_edit_rate; uint64_t index_start_position; uint64_t index_duration; - int *slice; - int *element_delta; - int nb_delta_entries; int8_t *temporal_offset_entries; int *flag_entries; uint64_t *stream_offset_entries; - uint32_t **slice_offset_entries; int nb_index_entries; } MXFIndexTableSegment; @@ -665,25 +660,6 @@ static int mxf_read_source_package(void *arg, AVIOContext *pb, int tag, int size return 0; } -static int mxf_read_delta_entry_array(AVIOContext *pb, MXFIndexTableSegment *segment) -{ - int i, length; - - segment->nb_delta_entries = avio_rb32(pb); - length = avio_rb32(pb); - - if (!(segment->slice = av_calloc(segment->nb_delta_entries, sizeof(*segment->slice))) || - !(segment->element_delta = av_calloc(segment->nb_delta_entries, sizeof(*segment->element_delta)))) - return AVERROR(ENOMEM); - - for (i = 0; i < segment->nb_delta_entries; i++) { - avio_r8(pb); /* PosTableIndex */ - segment->slice[i] = avio_r8(pb); - segment->element_delta[i] = avio_rb32(pb); - } - return 0; -} - static int mxf_read_index_entry_array(AVIOContext *pb, MXFIndexTableSegment *segment) { int i, j, length; @@ -696,24 +672,12 @@ static int mxf_read_index_entry_array(AVIOContext *pb, MXFIndexTableSegment *seg !(segment->stream_offset_entries = av_calloc(segment->nb_index_entries, sizeof(*segment->stream_offset_entries)))) return AVERROR(ENOMEM); - if (segment->slice_count && - !(segment->slice_offset_entries = av_calloc(segment->nb_index_entries, sizeof(*segment->slice_offset_entries)))) - return AVERROR(ENOMEM); - for (i = 0; i < segment->nb_index_entries; i++) { segment->temporal_offset_entries[i] = avio_r8(pb); avio_r8(pb); /* KeyFrameOffset */ segment->flag_entries[i] = avio_r8(pb); segment->stream_offset_entries[i] = avio_rb64(pb); - if (segment->slice_count) { - if (!(segment->slice_offset_entries[i] = av_calloc(segment->slice_count, sizeof(**segment->slice_offset_entries)))) - return AVERROR(ENOMEM); - - for (j = 0; j < segment->slice_count; j++) - segment->slice_offset_entries[i][j] = avio_rb32(pb); - } - - avio_skip(pb, length - 11 - 4 * segment->slice_count); + avio_skip(pb, length - 11); } return 0; } @@ -734,13 +698,6 @@ static int mxf_read_index_table_segment(void *arg, AVIOContext *pb, int tag, int segment->body_sid = avio_rb32(pb); av_dlog(NULL, "BodySID %d\n", segment->body_sid); break; - case 0x3F08: - segment->slice_count = avio_r8(pb); - av_dlog(NULL, "SliceCount %d\n", segment->slice_count); - break; - case 0x3F09: - av_dlog(NULL, "DeltaEntryArray found\n"); - return mxf_read_delta_entry_array(pb, segment); case 0x3F0A: av_dlog(NULL, "IndexEntryArray found\n"); return mxf_read_index_entry_array(pb, segment); @@ -1892,15 +1849,9 @@ static int mxf_read_close(AVFormatContext *s) break; case IndexTableSegment: seg = (MXFIndexTableSegment *)mxf->metadata_sets[i]; - if (seg->slice_count) - for (j = 0; j < seg->nb_index_entries; j++) - av_freep(&seg->slice_offset_entries[j]); - av_freep(&seg->slice); - av_freep(&seg->element_delta); av_freep(&seg->temporal_offset_entries); av_freep(&seg->flag_entries); av_freep(&seg->stream_offset_entries); - av_freep(&seg->slice_offset_entries); break; default: break;