mxfdec: Index table driven demuxing and seeking
authorTomas Härdin <tomas.hardin@codemill.se>
Thu, 8 Dec 2011 19:28:49 +0000 (20:28 +0100)
committerTomas Härdin <tomas.hardin@codemill.se>
Thu, 8 Dec 2011 19:28:49 +0000 (20:28 +0100)
This adds OPAtom support and proper seeking.
D-10 and non-seekable OP1a streams still use the old demuxing/seeking code.

libavformat/mxfdec.c
tests/ref/seek/lavf_mxf

index 37245df..47717c6 100644 (file)
@@ -197,6 +197,9 @@ typedef struct {
     int parsing_backward;
     int64_t last_forward_tell;
     int last_forward_partition;
+    int current_edit_unit;
+    int current_stream;
+    int d10;
 } MXFContext;
 
 enum MXFWrappingScheme {
@@ -372,7 +375,7 @@ static int mxf_decrypt_triplet(AVFormatContext *s, AVPacket *pkt, KLVPacket *klv
     return 0;
 }
 
-static int mxf_read_packet(AVFormatContext *s, AVPacket *pkt)
+static int mxf_read_packet_old(AVFormatContext *s, AVPacket *pkt)
 {
     KLVPacket klv;
 
@@ -418,6 +421,65 @@ static int mxf_read_packet(AVFormatContext *s, AVPacket *pkt)
     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)
+        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;
+    }
+
+    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;
@@ -925,6 +987,8 @@ static const MXFCodecUL mxf_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;
@@ -1252,6 +1316,11 @@ 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;
@@ -1291,8 +1360,8 @@ static int mxf_parse_structural_metadata(MXFContext *mxf)
             }
         }
         if (st->codec->codec_type != AVMEDIA_TYPE_DATA && (*essence_container_ul)[15] > 0x01) {
-            av_log(mxf->fc, AV_LOG_WARNING, "only frame wrapped mappings are correctly supported\n");
-            st->need_parsing = AVSTREAM_PARSE_FULL;
+            /* TODO: decode timestamps */
+            st->need_parsing = AVSTREAM_PARSE_TIMESTAMPS;
         }
 
         if ((ret = mxf_parse_index(mxf, material_track->track_id, st)))
@@ -1659,7 +1728,11 @@ static int mxf_read_seek(AVFormatContext *s, int stream_index, int64_t sample_ti
 {
     AVStream *st = s->streams[stream_index];
     int64_t seconds;
+    MXFContext* mxf = s->priv_data;
+    int64_t seekpos;
+    int index;
 
+    if (mxf->d10) {
     if (!s->bit_rate)
         return -1;
     if (sample_time < 0)
@@ -1668,6 +1741,27 @@ static int mxf_read_seek(AVFormatContext *s, int stream_index, int64_t sample_ti
     if (avio_seek(s->pb, (s->bit_rate * seconds) >> 3, SEEK_SET) < 0)
         return -1;
     ff_update_cur_dts(s, st, sample_time);
+    } else {
+        if (st->nb_index_entries <= 0)
+            return -1;
+
+        index = av_index_search_timestamp(st, sample_time, flags);
+
+        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;
+        }
+
+        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;
+        avio_seek(s->pb, seekpos, SEEK_SET);
+    }
     return 0;
 }
 
index 4c1aecc..00dea3d 100644 (file)
@@ -2,52 +2,47 @@ 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.000000 pts: NOPTS    pos:   6144 size: 24801
 ret: 0         st:-1 flags:1  ts: 1.894167
-ret:-1
+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:-1
+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.000000 pts: NOPTS    pos:   6144 size: 24801
-ret: 0         st: 1 flags:0  ts: 2.560000
-ret:-1
+ret:-1         st: 1 flags:0  ts: 2.560000
 ret: 0         st: 1 flags:1  ts: 1.480000
-ret:-1
+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: NOPTS    pos:   6144 size: 24801
+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.000000 pts: NOPTS    pos:   6144 size: 24801
-ret: 0         st: 0 flags:0  ts: 2.160000
-ret:-1
+ret:-1         st: 0 flags:0  ts: 2.160000
 ret: 0         st: 0 flags:1  ts: 1.040000
-ret:-1
+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.000000 pts: NOPTS    pos:   6144 size: 24801
 ret: 0         st: 1 flags:1  ts: 2.840000
-ret:-1
-ret: 0         st:-1 flags:0  ts: 1.730004
-ret:-1
+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:-1
+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.000000 pts: NOPTS    pos:   6144 size: 24801
 ret: 0         st: 0 flags:1  ts: 2.400000
-ret:-1
-ret: 0         st: 1 flags:0  ts: 1.320000
-ret:-1
+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.200000 pts: NOPTS    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.000000 pts: NOPTS    pos:   6144 size: 24801
 ret: 0         st:-1 flags:1  ts: 1.989173
-ret:-1
+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:-1
+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.000000 pts: NOPTS    pos:   6144 size: 24801
-ret: 0         st: 1 flags:0  ts: 2.680000
-ret:-1
+ret:-1         st: 1 flags:0  ts: 2.680000
 ret: 0         st: 1 flags:1  ts: 1.560000
-ret:-1
+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.480000 pts: NOPTS    pos:   6144 size: 24801
+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.000000 pts: NOPTS    pos:   6144 size: 24801