[FFmpeg-devel] [PATCH] libavformat/mxfenc: write package name metadata

Mark Reid mindmark at gmail.com
Fri Feb 13 01:36:53 CET 2015


---
 libavformat/avio.h        |  6 ++++
 libavformat/aviobuf.c     | 50 +++++++++++++++++---------------
 libavformat/mxfenc.c      | 74 ++++++++++++++++++++++++++++++++++++++++-------
 tests/ref/lavf/mxf        |  6 ++--
 tests/ref/lavf/mxf_d10    |  2 +-
 tests/ref/lavf/mxf_opatom |  2 +-
 6 files changed, 101 insertions(+), 39 deletions(-)

diff --git a/libavformat/avio.h b/libavformat/avio.h
index b9b4017..8fc7e27 100644
--- a/libavformat/avio.h
+++ b/libavformat/avio.h
@@ -234,6 +234,12 @@ int avio_put_str(AVIOContext *s, const char *str);
 int avio_put_str16le(AVIOContext *s, const char *str);
 
 /**
+ * Convert an UTF-8 string to UTF-16BE and write it.
+ * @return number of bytes written.
+ */
+int avio_put_str16be(AVIOContext *s, const char *str);
+
+/**
  * Passing this as the "whence" parameter to a seek function causes it to
  * return the filesize without seeking anywhere. Supporting this is optional.
  * If it is not supported then the seek function will return <0.
diff --git a/libavformat/aviobuf.c b/libavformat/aviobuf.c
index 3d77a7f..506f292 100644
--- a/libavformat/aviobuf.c
+++ b/libavformat/aviobuf.c
@@ -342,29 +342,33 @@ int avio_put_str(AVIOContext *s, const char *str)
     return len;
 }
 
-int avio_put_str16le(AVIOContext *s, const char *str)
-{
-    const uint8_t *q = str;
-    int ret = 0;
-    int err = 0;
-
-    while (*q) {
-        uint32_t ch;
-        uint16_t tmp;
-
-        GET_UTF8(ch, *q++, goto invalid;)
-        PUT_UTF16(ch, tmp, avio_wl16(s, tmp); ret += 2;)
-        continue;
-invalid:
-        av_log(s, AV_LOG_ERROR, "Invaid UTF8 sequence in avio_put_str16le\n");
-        err = AVERROR(EINVAL);
-    }
-    avio_wl16(s, 0);
-    if (err)
-        return err;
-    ret += 2;
-    return ret;
-}
+#define PUT_STR16(type, write) \
+    int avio_put_str16 ##type(AVIOContext *s, const char *str)\
+{\
+    const uint8_t *q = str;\
+    int ret = 0;\
+    int err = 0;\
+    while (*q) {\
+        uint32_t ch;\
+        uint16_t tmp;\
+        GET_UTF8(ch, *q++, goto invalid;)\
+        PUT_UTF16(ch, tmp, write(s, tmp); ret += 2;)\
+        continue;\
+invalid:\
+        av_log(s, AV_LOG_ERROR, "Invaid UTF8 sequence in avio_put_str16" #type "\n");\
+        err = AVERROR(EINVAL);\
+    }\
+    write(s, 0);\
+    if (err)\
+    return err;\
+    ret += 2;\
+    return ret;\
+}\
+
+PUT_STR16(le, avio_wl16)
+PUT_STR16(be, avio_wb16)
+
+#undef PUT_STR16
 
 int ff_get_v_length(uint64_t val)
 {
diff --git a/libavformat/mxfenc.c b/libavformat/mxfenc.c
index 17ad132..c25f5fd 100644
--- a/libavformat/mxfenc.c
+++ b/libavformat/mxfenc.c
@@ -624,14 +624,44 @@ static void mxf_write_preface(AVFormatContext *s)
 }
 
 /*
- * Write a local tag containing an ascii string as utf-16
+ * Returns the length of the UTF-16 string, in 16-bit characters, that would result
+ * from decoding the utf-8 string.
+ */
+static uint64_t mxf_utf16len(const char *utf8_str)
+{
+    const uint8_t *q = utf8_str;
+    uint64_t size = 0;
+    while (*q) {
+        uint32_t ch;
+        GET_UTF8(ch, *q++, goto invalid;)
+        if (ch < 0x10000)
+            size++;
+        else
+            size += 2;
+        continue;
+invalid:
+        av_log(NULL, AV_LOG_ERROR, "Invaid UTF8 sequence in mxf_utf16len\n\n");
+    }
+    size += 1;
+    return size;
+}
+
+/*
+ * Returns the calculated length a local tag containing an utf-8 string as utf-16
+ */
+static uint64_t mxf_utf16_local_tag_length(const char *utf8_str)
+{
+    return utf8_str? 4 + mxf_utf16len(utf8_str) * 2: 0;
+}
+
+/*
+ * Write a local tag containing an utf-8 string as utf-16
  */
 static void mxf_write_local_tag_utf16(AVIOContext *pb, int tag, const char *value)
 {
-    int i, size = strlen(value);
+    int size = mxf_utf16len(value);
     mxf_write_local_tag(pb, size*2, tag);
-    for (i = 0; i < size; i++)
-        avio_wb16(pb, value[i]);
+    avio_put_str16be(pb, value);
 }
 
 static void mxf_write_identification(AVFormatContext *s)
@@ -648,7 +678,9 @@ static void mxf_write_identification(AVFormatContext *s)
 
     version = s->flags & AVFMT_FLAG_BITEXACT ?
         "0.0.0" : AV_STRINGIFY(LIBAVFORMAT_VERSION);
-    length = 84 + (strlen(company)+strlen(product)+strlen(version))*2; // utf-16
+    length = 72 + mxf_utf16_local_tag_length(company) +
+                  mxf_utf16_local_tag_length(product) +
+                  mxf_utf16_local_tag_length(version);
     klv_encode_ber_length(pb, length);
 
     // write uid
@@ -659,7 +691,6 @@ static void mxf_write_identification(AVFormatContext *s)
     // write generation uid
     mxf_write_local_tag(pb, 16, 0x3C09);
     mxf_write_uuid(pb, Identification, 1);
-
     mxf_write_local_tag_utf16(pb, 0x3C01, company); // Company Name
     mxf_write_local_tag_utf16(pb, 0x3C02, product); // Product Name
     mxf_write_local_tag_utf16(pb, 0x3C04, version); // Version String
@@ -1092,20 +1123,29 @@ static void mxf_write_generic_sound_desc(AVFormatContext *s, AVStream *st)
     mxf_write_generic_sound_common(s, st, mxf_generic_sound_descriptor_key, 0);
 }
 
-static void mxf_write_package(AVFormatContext *s, enum MXFMetadataSetType type)
+static void mxf_write_package(AVFormatContext *s, enum MXFMetadataSetType type, const char *package_name)
 {
     MXFContext *mxf = s->priv_data;
     AVIOContext *pb = s->pb;
     int i, track_count = s->nb_streams+1;
+    uint64_t name_size = 0;
+
+    if (package_name)
+        name_size = mxf_utf16_local_tag_length(package_name);
+
+    if (name_size >= INT16_MAX){
+        av_log(s, AV_LOG_WARNING, "package name size %"PRIx64" invalid (too large), ignoring\n", name_size);
+        name_size = 0;
+    }
 
     if (type == MaterialPackage) {
         mxf_write_metadata_key(pb, 0x013600);
         PRINT_KEY(s, "Material Package key", pb->buf_ptr - 16);
-        klv_encode_ber_length(pb, 92 + 16*track_count);
+        klv_encode_ber_length(pb, 92 + name_size + (16*track_count));
     } else {
         mxf_write_metadata_key(pb, 0x013700);
         PRINT_KEY(s, "Source Package key", pb->buf_ptr - 16);
-        klv_encode_ber_length(pb, 112 + 16*track_count); // 20 bytes length for descriptor reference
+        klv_encode_ber_length(pb, 112 + name_size + (16*track_count)); // 20 bytes length for descriptor reference
     }
 
     // write uid
@@ -1119,6 +1159,10 @@ static void mxf_write_package(AVFormatContext *s, enum MXFMetadataSetType type)
     mxf_write_umid(s, type == SourcePackage);
     PRINT_KEY(s, "package umid second part", pb->buf_ptr - 16);
 
+    // package name
+    if (name_size)
+        mxf_write_local_tag_utf16(pb, 0x4402, package_name);
+
     // package creation date
     mxf_write_local_tag(pb, 8, 0x4405);
     avio_wb64(pb, mxf->timestamp);
@@ -1187,11 +1231,19 @@ static int mxf_write_essence_container_data(AVFormatContext *s)
 
 static int mxf_write_header_metadata_sets(AVFormatContext *s)
 {
+    char *material_package_name = NULL;
+    char *file_package_name = NULL;
+    AVDictionaryEntry *entry = NULL;
+
+    if (entry = av_dict_get(s->metadata, "material_package_name", NULL, 0))
+       material_package_name = entry->value;
+    if (entry = av_dict_get(s->metadata, "file_package_name", NULL, 0))
+        file_package_name = entry->value;
     mxf_write_preface(s);
     mxf_write_identification(s);
     mxf_write_content_storage(s);
-    mxf_write_package(s, MaterialPackage);
-    mxf_write_package(s, SourcePackage);
+    mxf_write_package(s, MaterialPackage, material_package_name);
+    mxf_write_package(s, SourcePackage, file_package_name);
     mxf_write_essence_container_data(s);
     return 0;
 }
diff --git a/tests/ref/lavf/mxf b/tests/ref/lavf/mxf
index 236661c..38db9ac 100644
--- a/tests/ref/lavf/mxf
+++ b/tests/ref/lavf/mxf
@@ -1,9 +1,9 @@
-dbc4ced82ef1c2fa4df3571b4f994a22 *./tests/data/lavf/lavf.mxf
+c4eb3fab4d6b24687b81913036c79ce9 *./tests/data/lavf/lavf.mxf
 525369 ./tests/data/lavf/lavf.mxf
 ./tests/data/lavf/lavf.mxf CRC=0xdbfff6f1
-fe4294023cd990938f042c7855405f63 *./tests/data/lavf/lavf.mxf
+54cb97d1fc47c58f5580e8c897ef0874 *./tests/data/lavf/lavf.mxf
 560697 ./tests/data/lavf/lavf.mxf
 ./tests/data/lavf/lavf.mxf CRC=0x11a6178e
-ef0c741e17bf7963fc51adcb6bab8ec8 *./tests/data/lavf/lavf.mxf
+872c48b66705925cb0c6d638c82cd7d4 *./tests/data/lavf/lavf.mxf
 525369 ./tests/data/lavf/lavf.mxf
 ./tests/data/lavf/lavf.mxf CRC=0xdbfff6f1
diff --git a/tests/ref/lavf/mxf_d10 b/tests/ref/lavf/mxf_d10
index ff7d876..7a5e154 100644
--- a/tests/ref/lavf/mxf_d10
+++ b/tests/ref/lavf/mxf_d10
@@ -1,3 +1,3 @@
-87e0903ef7ea55b1a032b9d878588683 *./tests/data/lavf/lavf.mxf_d10
+c92818ebed05077efb27fc47a0351730 *./tests/data/lavf/lavf.mxf_d10
 5330989 ./tests/data/lavf/lavf.mxf_d10
 ./tests/data/lavf/lavf.mxf_d10 CRC=0x6c74d488
diff --git a/tests/ref/lavf/mxf_opatom b/tests/ref/lavf/mxf_opatom
index d62d803..c6c0785 100644
--- a/tests/ref/lavf/mxf_opatom
+++ b/tests/ref/lavf/mxf_opatom
@@ -1,3 +1,3 @@
-8b312335b1af76e0133092c2658cd4a4 *./tests/data/lavf/lavf.mxf_opatom
+17c93938b3d8c61c29caf6ad9ae5f22e *./tests/data/lavf/lavf.mxf_opatom
 4716601 ./tests/data/lavf/lavf.mxf_opatom
 ./tests/data/lavf/lavf.mxf_opatom CRC=0xbdd696b9
-- 
2.2.1



More information about the ffmpeg-devel mailing list