avformat/mxfdec: read reel_name and source timecode from physical source package
authorMark Reid <mindmark@gmail.com>
Sun, 5 Oct 2014 00:42:51 +0000 (17:42 -0700)
committerMichael Niedermayer <michaelni@gmx.at>
Tue, 7 Oct 2014 01:13:06 +0000 (03:13 +0200)
Reviewed-by: Tomas Härdin <tomas.hardin@codemill.se>
Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
libavformat/mxfdec.c

index 7a4633f..ef4c4ec 100644 (file)
@@ -188,6 +188,7 @@ typedef struct {
     int tracks_count;
     MXFDescriptor *descriptor; /* only one */
     UID descriptor_ref;
+    char *name;
 } MXFPackage;
 
 typedef struct {
@@ -731,6 +732,27 @@ static int mxf_read_sequence(void *arg, AVIOContext *pb, int tag, int size, UID
     return 0;
 }
 
+static int mxf_read_utf16_string(AVIOContext *pb, int size, char** str)
+{
+    int ret;
+    size_t buf_size;
+
+    if (size < 0)
+        return AVERROR(EINVAL);
+
+    buf_size = size + size / 2 + 1;
+    *str = av_malloc(buf_size);
+    if (!*str)
+        return AVERROR(ENOMEM);
+
+    if ((ret = avio_get_str16be(pb, size, *str, buf_size)) < 0) {
+        av_freep(str);
+        return ret;
+    }
+
+    return ret;
+}
+
 static int mxf_read_source_package(void *arg, AVIOContext *pb, int tag, int size, UID uid, int64_t klv_offset)
 {
     MXFPackage *package = arg;
@@ -751,6 +773,8 @@ static int mxf_read_source_package(void *arg, AVIOContext *pb, int tag, int size
     case 0x4701:
         avio_read(pb, package->descriptor_ref, 16);
         break;
+    case 0x4402:
+        return mxf_read_utf16_string(pb, size, &package->name);
     }
     return 0;
 }
@@ -1374,6 +1398,78 @@ static int mxf_add_timecode_metadata(AVDictionary **pm, const char *key, AVTimec
     return 0;
 }
 
+static int mxf_parse_physical_source_package(MXFContext *mxf, MXFTrack *source_track, AVStream *st)
+{
+    MXFPackage *temp_package = NULL;
+    MXFPackage *physical_package = NULL;
+    MXFTrack *physical_track = NULL;
+    MXFStructuralComponent *component = NULL;
+    MXFStructuralComponent *sourceclip = NULL;
+    MXFTimecodeComponent *mxf_tc = NULL;
+    int i, j, k;
+    AVTimecode tc;
+    int flags;
+    int64_t start_position;
+
+    for (i = 0; i < source_track->sequence->structural_components_count; i++) {
+        component = mxf_resolve_strong_ref(mxf, &source_track->sequence->structural_components_refs[i], SourceClip);
+        if (!component)
+            continue;
+
+        for (j = 0; j < mxf->packages_count; j++) {
+            temp_package = mxf_resolve_strong_ref(mxf, &mxf->packages_refs[j], SourcePackage);
+            if (!temp_package)
+                continue;
+            if (!memcmp(temp_package->package_uid, component->source_package_uid, 16)){
+                physical_package = temp_package;
+                sourceclip = component;
+                break;
+            }
+        }
+        if (!physical_package)
+            break;
+
+        /* the name of physical source package is name of the reel or tape */
+        if (physical_package->name[0])
+            av_dict_set(&st->metadata, "reel_name", physical_package->name, 0);
+
+        /* the source timecode is calculated by adding the start_position of the sourceclip from the file source package track
+         * to the start_frame of the timecode component located on one of the tracks of the physical source package.
+         */
+        for (j = 0; j < physical_package->tracks_count; j++) {
+            if (!(physical_track = mxf_resolve_strong_ref(mxf, &physical_package->tracks_refs[j], Track))) {
+                av_log(mxf->fc, AV_LOG_ERROR, "could not resolve source track strong ref\n");
+                continue;
+            }
+
+            if (!(physical_track->sequence = mxf_resolve_strong_ref(mxf, &physical_track->sequence_ref, Sequence))) {
+                av_log(mxf->fc, AV_LOG_ERROR, "could not resolve source track sequence strong ref\n");
+                continue;
+            }
+
+            for (k = 0; k < physical_track->sequence->structural_components_count; k++) {
+                component = mxf_resolve_strong_ref(mxf, &physical_track->sequence->structural_components_refs[k], TimecodeComponent);
+                if (!component)
+                    continue;
+
+                mxf_tc = (MXFTimecodeComponent*)component;
+                flags = mxf_tc->drop_frame == 1 ? AV_TIMECODE_FLAG_DROPFRAME : 0;
+                /* scale sourceclip start_position to match physical track edit rate */
+                start_position = av_rescale_q(sourceclip->start_position,
+                                              physical_track->edit_rate,
+                                              source_track->edit_rate);
+
+                if (av_timecode_init(&tc, mxf_tc->rate, flags, start_position + mxf_tc->start_frame, mxf->fc) == 0) {
+                    mxf_add_timecode_metadata(&st->metadata, "timecode", &tc);
+                    return 0;
+                }
+            }
+        }
+    }
+
+    return 0;
+}
+
 static int mxf_parse_structural_metadata(MXFContext *mxf)
 {
     MXFPackage *material_package = NULL;
@@ -1571,6 +1667,8 @@ static int mxf_parse_structural_metadata(MXFContext *mxf)
         }
         av_log(mxf->fc, AV_LOG_VERBOSE, "\n");
 
+        mxf_parse_physical_source_package(mxf, source_track, st);
+
         if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
             source_track->intra_only = mxf_is_intra_only(descriptor);
             container_ul = mxf_get_codec_ul(mxf_picture_essence_container_uls, essence_container_ul);
@@ -1706,27 +1804,6 @@ fail_and_free:
     return ret;
 }
 
-static int mxf_read_utf16_string(AVIOContext *pb, int size, char** str)
-{
-    int ret;
-    size_t buf_size;
-
-    if (size < 0)
-        return AVERROR(EINVAL);
-
-    buf_size = size + size / 2 + 1;
-    *str = av_malloc(buf_size);
-    if (!*str)
-        return AVERROR(ENOMEM);
-
-    if ((ret = avio_get_str16be(pb, size, *str, buf_size)) < 0) {
-        av_freep(str);
-        return ret;
-    }
-
-    return ret;
-}
-
 static int mxf_uid_to_str(UID uid, char **str)
 {
     int i;
@@ -2544,6 +2621,7 @@ static int mxf_read_close(AVFormatContext *s)
         case SourcePackage:
         case MaterialPackage:
             av_freep(&((MXFPackage *)mxf->metadata_sets[i])->tracks_refs);
+            av_freep(&((MXFPackage *)mxf->metadata_sets[i])->name);
             break;
         case IndexTableSegment:
             seg = (MXFIndexTableSegment *)mxf->metadata_sets[i];