Also parses TemporalOffsets.

Based on patches from Tomas Härdin <[email protected]>.

Changed av_calloc to av_mallocz, comment cosmetics, factored part
of mxf_read_header to its own function.
---
 libavformat/mxfdec.c |  173 +++++++++++++++++++++++++++++++++++++++++---------
 1 files changed, 142 insertions(+), 31 deletions(-)

diff --git a/libavformat/mxfdec.c b/libavformat/mxfdec.c
index 31e7f5e..9d40f7a 100644
--- a/libavformat/mxfdec.c
+++ b/libavformat/mxfdec.c
@@ -69,6 +69,7 @@ typedef enum {
     OP_3B,
     OP_3C,
     OP_ATOM,
+    OP_SONY_OPT,  /* FATE sample, violates the spec in places */
 } MXFOP;
 
 typedef struct {
@@ -79,6 +80,12 @@ typedef struct {
     int index_sid;
     int body_sid;
     int64_t this_partition;
+    int64_t essence_offset;         ///< absolute offset of essence
+    int64_t essence_length;
+    int32_t kag_size;
+    int64_t header_byte_count;
+    int64_t index_byte_count;
+    int pack_length;
 } MXFPartition;
 
 typedef struct {
@@ -148,6 +155,7 @@ typedef struct {
     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;
@@ -200,7 +208,8 @@ enum MXFWrappingScheme {
     Clip,
 };
 
-typedef int MXFMetadataReadFunc(void *arg, AVIOContext *pb, int tag, int size, 
UID uid);
+/* NOTE: klv_offset is not set (-1) for local keys */
+typedef int MXFMetadataReadFunc(void *arg, AVIOContext *pb, int tag, int size, 
UID uid, int64_t klv_offset);
 
 typedef struct {
     const UID key;
@@ -413,7 +422,7 @@ static int mxf_read_packet(AVFormatContext *s, AVPacket 
*pkt)
     return AVERROR_EOF;
 }
 
-static int mxf_read_primer_pack(void *arg, AVIOContext *pb, int tag, int size, 
UID uid)
+static int mxf_read_primer_pack(void *arg, AVIOContext *pb, int tag, int size, 
UID uid, int64_t klv_offset)
 {
     MXFContext *mxf = arg;
     int item_num = avio_rb32(pb);
@@ -433,7 +442,7 @@ static int mxf_read_primer_pack(void *arg, AVIOContext *pb, 
int tag, int size, U
     return 0;
 }
 
-static int mxf_read_partition_pack(void *arg, AVIOContext *pb, int tag, int 
size, UID uid)
+static int mxf_read_partition_pack(void *arg, AVIOContext *pb, int tag, int 
size, UID uid, int64_t klv_offset)
 {
     MXFContext *mxf = arg;
     MXFPartition *partition;
@@ -461,6 +470,7 @@ static int mxf_read_partition_pack(void *arg, AVIOContext 
*pb, int tag, int size
 
     memset(partition, 0, sizeof(*partition));
     mxf->partitions_count++;
+    partition->pack_length = avio_tell(pb) - klv_offset + size;
 
     switch(uid[13]) {
     case 2:
@@ -480,11 +490,13 @@ static int mxf_read_partition_pack(void *arg, AVIOContext 
*pb, int tag, int size
     /* consider both footers to be closed (there is only Footer and 
CompleteFooter) */
     partition->closed = partition->type == PART_TYPE_FOOTER || !(uid[14] & 1);
     partition->complete = uid[14] > 2;
-    avio_skip(pb, 8);
+    avio_skip(pb, 4);
+    partition->kag_size = avio_rb32(pb);
     partition->this_partition = avio_rb64(pb);
     partition->previous_partition = avio_rb64(pb);
     footer_partition = avio_rb64(pb);
-    avio_skip(pb, 16);
+    partition->header_byte_count = avio_rb64(pb);
+    partition->index_byte_count = avio_rb64(pb);
     partition->index_sid = avio_rb32(pb);
     avio_skip(pb, 8);
     partition->body_sid = avio_rb32(pb);
@@ -516,8 +528,22 @@ static int mxf_read_partition_pack(void *arg, AVIOContext 
*pb, int tag, int size
     else if (op[12] == 3 && op[13] == 2) mxf->op = OP_3B;
     else if (op[12] == 3 && op[13] == 3) mxf->op = OP_3C;
     else if (op[12] == 0x10)             mxf->op = OP_ATOM;
-    else
-        av_log(mxf->fc, AV_LOG_ERROR, "unknown operational pattern: %02xh 
%02xh\n", op[12], op[13]);
+    else if (op[12] == 64&& op[13] == 1) mxf->op = OP_SONY_OPT;
+    else {
+        av_log(mxf->fc, AV_LOG_ERROR, "unknown operational pattern: %02xh 
%02xh - guessing OP1a\n", op[12], op[13]);
+        mxf->op = OP_1A;
+    }
+
+    if (partition->kag_size <= 0 || partition->kag_size > (1 << 20)) {
+        av_log(mxf->fc, AV_LOG_WARNING, "invalid KAGSize %i - guessing ", 
partition->kag_size);
+
+        if (mxf->op == OP_SONY_OPT)
+            partition->kag_size = 512;
+        else
+            partition->kag_size = 1;
+
+        av_log(mxf->fc, AV_LOG_WARNING, "%i\n", partition->kag_size);
+    }
 
     return 0;
 }
@@ -534,7 +560,7 @@ static int mxf_add_metadata_set(MXFContext *mxf, void 
*metadata_set)
     return 0;
 }
 
-static int mxf_read_cryptographic_context(void *arg, AVIOContext *pb, int tag, 
int size, UID uid)
+static int mxf_read_cryptographic_context(void *arg, AVIOContext *pb, int tag, 
int size, UID uid, int64_t klv_offset)
 {
     MXFCryptoContext *cryptocontext = arg;
     if (size != 16)
@@ -544,7 +570,7 @@ static int mxf_read_cryptographic_context(void *arg, 
AVIOContext *pb, int tag, i
     return 0;
 }
 
-static int mxf_read_content_storage(void *arg, AVIOContext *pb, int tag, int 
size, UID uid)
+static int mxf_read_content_storage(void *arg, AVIOContext *pb, int tag, int 
size, UID uid, int64_t klv_offset)
 {
     MXFContext *mxf = arg;
     switch (tag) {
@@ -562,7 +588,7 @@ static int mxf_read_content_storage(void *arg, AVIOContext 
*pb, int tag, int siz
     return 0;
 }
 
-static int mxf_read_source_clip(void *arg, AVIOContext *pb, int tag, int size, 
UID uid)
+static int mxf_read_source_clip(void *arg, AVIOContext *pb, int tag, int size, 
UID uid, int64_t klv_offset)
 {
     MXFStructuralComponent *source_clip = arg;
     switch(tag) {
@@ -584,7 +610,7 @@ static int mxf_read_source_clip(void *arg, AVIOContext *pb, 
int tag, int size, U
     return 0;
 }
 
-static int mxf_read_material_package(void *arg, AVIOContext *pb, int tag, int 
size, UID uid)
+static int mxf_read_material_package(void *arg, AVIOContext *pb, int tag, int 
size, UID uid, int64_t klv_offset)
 {
     MXFPackage *package = arg;
     switch(tag) {
@@ -602,7 +628,7 @@ static int mxf_read_material_package(void *arg, AVIOContext 
*pb, int tag, int si
     return 0;
 }
 
-static int mxf_read_track(void *arg, AVIOContext *pb, int tag, int size, UID 
uid)
+static int mxf_read_track(void *arg, AVIOContext *pb, int tag, int size, UID 
uid, int64_t klv_offset)
 {
     MXFTrack *track = arg;
     switch(tag) {
@@ -623,7 +649,7 @@ static int mxf_read_track(void *arg, AVIOContext *pb, int 
tag, int size, UID uid
     return 0;
 }
 
-static int mxf_read_sequence(void *arg, AVIOContext *pb, int tag, int size, 
UID uid)
+static int mxf_read_sequence(void *arg, AVIOContext *pb, int tag, int size, 
UID uid, int64_t klv_offset)
 {
     MXFSequence *sequence = arg;
     switch(tag) {
@@ -647,7 +673,7 @@ static int mxf_read_sequence(void *arg, AVIOContext *pb, 
int tag, int size, UID
     return 0;
 }
 
-static int mxf_read_source_package(void *arg, AVIOContext *pb, int tag, int 
size, UID uid)
+static int mxf_read_source_package(void *arg, AVIOContext *pb, int tag, int 
size, UID uid, int64_t klv_offset)
 {
     MXFPackage *package = arg;
     switch(tag) {
@@ -717,19 +743,22 @@ static int mxf_read_index_entry_array(AVIOContext *pb, 
MXFIndexTableSegment *seg
 
     length = avio_rb32(pb);
 
-    segment->flag_entries          = av_mallocz(segment->nb_index_entries *
-                                                
sizeof(*segment->flag_entries));
-    segment->stream_offset_entries = av_mallocz(segment->nb_index_entries *
-                                       
sizeof(*segment->stream_offset_entries));
-    segment->slice_offset_entries  = av_mallocz(segment->nb_index_entries *
-                                       sizeof(*segment->slice_offset_entries));
-
-    if (!segment->flag_entries || !segment->stream_offset_entries ||
-        !segment->slice_offset_entries)
+    segment->temporal_offset_entries = av_mallocz(segment->nb_index_entries *
+                                 sizeof(*segment->temporal_offset_entries));
+    segment->flag_entries            = av_mallocz(segment->nb_index_entries *
+                                 sizeof(*segment->flag_entries));
+    segment->stream_offset_entries   = av_mallocz(segment->nb_index_entries *
+                                 sizeof(*segment->stream_offset_entries));
+    segment->slice_offset_entries    = av_mallocz(segment->nb_index_entries *
+                                 sizeof(*segment->slice_offset_entries));
+
+    if (!segment->flag_entries         || !segment->stream_offset_entries ||
+        !segment->slice_offset_entries || !segment->temporal_offset_entries)
         goto errmem;
 
     for (i = 0; i < segment->nb_index_entries; i++) {
-        avio_rb16(pb);  /* TemporalOffset and KeyFrameOffset */
+        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) {
@@ -753,10 +782,11 @@ errmem:
     av_freep(&segment->flag_entries);
     av_freep(&segment->stream_offset_entries);
     av_freep(&segment->slice_offset_entries);
+    av_freep(&segment->temporal_offset_entries);
     return AVERROR(ENOMEM);
 }
 
-static int mxf_read_index_table_segment(void *arg, AVIOContext *pb, int tag, 
int size, UID uid)
+static int mxf_read_index_table_segment(void *arg, AVIOContext *pb, int tag, 
int size, UID uid, int64_t klv_offset)
 {
     MXFIndexTableSegment *segment = arg;
     switch(tag) {
@@ -819,7 +849,7 @@ static void mxf_read_pixel_layout(AVIOContext *pb, 
MXFDescriptor *descriptor)
     ff_mxf_decode_pixel_layout(layout, &descriptor->pix_fmt);
 }
 
-static int mxf_read_generic_descriptor(void *arg, AVIOContext *pb, int tag, 
int size, UID uid)
+static int mxf_read_generic_descriptor(void *arg, AVIOContext *pb, int tag, 
int size, UID uid, int64_t klv_offset)
 {
     MXFDescriptor *descriptor = arg;
     switch(tag) {
@@ -1350,7 +1380,7 @@ static int mxf_read_local_tags(MXFContext *mxf, KLVPacket 
*klv, MXFMetadataReadF
         }
         if (ctx_size && tag == 0x3C0A)
             avio_read(pb, ctx->uid, 16);
-        else if (read_child(ctx, pb, tag, size, uid) < 0)
+        else if (read_child(ctx, pb, tag, size, uid, -1) < 0)
             return -1;
 
         avio_seek(pb, next, SEEK_SET);
@@ -1435,6 +1465,79 @@ static int mxf_parse_handle_partition_or_eof(MXFContext 
*mxf)
     return mxf->parsing_backward ? mxf_seek_to_previous_partition(mxf) : 1;
 }
 
+/**
+ * Figure out the proper offset and length of the essence container
+ * in each partition
+ */
+static void mxf_compute_essence_containers(MXFContext *mxf)
+{
+    int x;
+
+    /* everything is already correct */
+    if (mxf->op == OP_ATOM)
+        return;
+
+    for (x = 0; x < mxf->partitions_count; x++) {
+        MXFPartition *p = &mxf->partitions[x];
+
+        if (!p->body_sid)
+            continue;       /* BodySID == 0 -> no essence */
+
+        if (x >= mxf->partitions_count - 1)
+            break;          /* last partition - can't compute length (and we 
don't need to) */
+
+        /* essence container spans to the next partition */
+        p->essence_length = mxf->partitions[x+1].this_partition - 
p->essence_offset;
+
+        if (p->essence_length < 0) {
+            /* next ThisPartition < essence_offset */
+            p->essence_length = 0;
+            av_log(mxf->fc, AV_LOG_ERROR, "partition %i: bad ThisPartition = 
%lx\n",
+                   x+1, mxf->partitions[x+1].this_partition);
+        }
+    }
+}
+
+static int64_t round_to_kag(int64_t position, int kag_size)
+{
+    /* TODO: account for run-in? the spec isn't clear whether KAG should 
account for it */
+    /* NOTE: kag_size may be any integer between 1 - 2^10 */
+    int64_t ret = (position / kag_size) * kag_size;
+    return ret == position ? ret : ret + kag_size;
+}
+
+static inline void compute_partition_essence_offset(AVFormatContext *s,
+                                                    MXFContext *mxf,
+                                                    KLVPacket *klv)
+{
+    MXFPartition *cur_part = mxf->current_partition;
+    /* for OP1a we compute essence_offset
+     * for OPAtom we point essence_offset after the KL
+     *     (usually op1a_essence_offset + 20 or 25)
+     * TODO: for OP1a we could eliminate this entire if statement, always
+     *       stopping parsing at op1a_essence_offset
+     *       for OPAtom we still need the actual essence_offset though
+     *       (the KL's length can vary)
+     */
+    int64_t op1a_essence_offset =
+        round_to_kag(cur_part->this_partition + cur_part->pack_length,
+                     cur_part->kag_size) +
+        round_to_kag(cur_part->header_byte_count, cur_part->kag_size) +
+        round_to_kag(cur_part->index_byte_count, cur_part->kag_size);
+
+    if (mxf->op == OP_ATOM) {
+        /* point essence_offset to the actual data
+         * OPAtom has all the essence in one big KLV
+         */
+        cur_part->essence_offset = avio_tell(s->pb);
+        cur_part->essence_length = klv->length;
+    } else {
+        /* NOTE: op1a_essence_offset may be less than to klv.offset
+         * (C0023S01.mxf)  */
+        cur_part->essence_offset = op1a_essence_offset;
+    }
+}
+
 static int mxf_read_header(AVFormatContext *s, AVFormatParameters *ap)
 {
     MXFContext *mxf = s->priv_data;
@@ -1466,9 +1569,13 @@ static int mxf_read_header(AVFormatContext *s, 
AVFormatParameters *ap)
         if (IS_KLV_KEY(klv.key, mxf_encrypted_triplet_key) ||
             IS_KLV_KEY(klv.key, mxf_essence_element_key) ||
             IS_KLV_KEY(klv.key, mxf_system_item_key)) {
-        if (IS_KLV_KEY(klv.key, mxf_system_item_key)) {
-            mxf->system_item = 1;
-        }
+            if (!mxf->current_partition->essence_offset) {
+                compute_partition_essence_offset(s, mxf, &klv);
+            }
+
+            if (IS_KLV_KEY(klv.key, mxf_system_item_key)) {
+                mxf->system_item = 1;
+            }
 
             if (!mxf->essence_offset)
                 mxf->essence_offset = klv.offset;
@@ -1496,7 +1603,7 @@ static int mxf_read_header(AVFormatContext *s, 
AVFormatParameters *ap)
                     res = mxf_read_local_tags(mxf, &klv, metadata->read, 
metadata->ctx_size, metadata->type);
                 } else {
                     uint64_t next = avio_tell(s->pb) + klv.length;
-                    res = metadata->read(mxf, s->pb, 0, 0, klv.key);
+                    res = metadata->read(mxf, s->pb, 0, klv.length, klv.key, 
klv.offset);
                     avio_seek(s->pb, next, SEEK_SET);
                 }
                 if (res < 0) {
@@ -1515,6 +1622,9 @@ static int mxf_read_header(AVFormatContext *s, 
AVFormatParameters *ap)
         return AVERROR_INVALIDDATA;
     }
     avio_seek(s->pb, mxf->essence_offset, SEEK_SET);
+
+    mxf_compute_essence_containers(mxf);
+
     return mxf_parse_structural_metadata(mxf);
 }
 
@@ -1548,6 +1658,7 @@ static int mxf_read_close(AVFormatContext *s)
                     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);
-- 
1.7.8

_______________________________________________
libav-devel mailing list
[email protected]
https://lists.libav.org/mailman/listinfo/libav-devel

Reply via email to