I've updated and extended the metadata reading to include some of the
numeric types, based on the feedback from the comments about adding to
the utility functions of AVDictionary, I've directly formatted the
values as strings in the .mov format code seams less risky.

Kevin
From 91515aec2e964e0fb499378e31cd7782bf93482a Mon Sep 17 00:00:00 2001
From: Kevin Wheatley <kevin.j.wheat...@gmail.com>
Date: Thu, 3 Sep 2015 15:58:49 +0100
Subject: [PATCH] avformat/mov: Extend metadata handling to read in the keys from the 'keys' atom

Signed-off-by: Kevin Wheatley <kevin.j.wheat...@gmail.com>
---
 libavformat/isom.h |    1 +
 libavformat/mov.c  |   63 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 64 insertions(+), 0 deletions(-)

diff --git a/libavformat/isom.h b/libavformat/isom.h
index aee9d6e..8c20ec9 100644
--- a/libavformat/isom.h
+++ b/libavformat/isom.h
@@ -206,6 +206,7 @@ typedef struct MOVContext {
     void *audible_fixed_key;
     int audible_fixed_key_size;
     struct AVAES *aes_decrypt;
+    AVDictionary *keys_d; // Use a dictionary as an array a little bit ugly
 } MOVContext;
 
 int ff_mp4_read_descr_len(AVIOContext *pb);
diff --git a/libavformat/mov.c b/libavformat/mov.c
index 92d90db..46c4b17 100644
--- a/libavformat/mov.c
+++ b/libavformat/mov.c
@@ -265,6 +265,7 @@ static int mov_read_udta_string(MOVContext *c, AVIOContext *pb, MOVAtom atom)
     uint32_t data_type = 0, str_size, str_size_alloc;
     int (*parse)(MOVContext*, AVIOContext*, unsigned, const char*) = NULL;
     int raw = 0;
+    AVDictionaryEntry *entry = NULL;
 
     switch (atom.type) {
     case MKTAG( '@','P','R','M'): key = "premiere_version"; raw = 1; break;
@@ -351,6 +352,13 @@ static int mov_read_udta_string(MOVContext *c, AVIOContext *pb, MOVAtom atom)
     case MKTAG(0xa9,'w','r','n'): key = "warning";   break;
     case MKTAG(0xa9,'w','r','t'): key = "composer";  break;
     case MKTAG(0xa9,'x','y','z'): key = "location";  break;
+    default:
+        snprintf(key2, sizeof(key2), "%08x", atom.type);
+        entry = av_dict_get(c->keys_d, key2, entry, 0);
+        if (entry)
+            key = entry->value;
+        av_log(c->fc, AV_LOG_TRACE, "Attempting to match unknown atom type %08x %s in keys => '%s'\n", atom.type, key2, key);
+        break;
     }
 retry:
     if (c->itunes_metadata && atom.size > 8) {
@@ -3184,6 +3192,58 @@ static int mov_read_meta(MOVContext *c, AVIOContext *pb, MOVAtom atom)
     return 0;
 }
 
+static int mov_read_keys(MOVContext *c, AVIOContext *pb, MOVAtom atom)
+{
+    AVDictionaryEntry *entry = NULL;
+    uint32_t key_count, key_size, key_namespace, key_num;
+    char *key_str;
+    char key_num_str[8+1] = { 0 }; // Use hexadecimal string of a 32 bit integer + terminator
+    int ret;
+
+    avio_r8(pb); /* version */
+    avio_rb24(pb); /* flags */
+    key_count = avio_rb32(pb);
+    
+    av_log(c->fc, AV_LOG_VERBOSE,
+           "Reading keys sz: %"PRId64" %u\n", atom.size, key_count);
+
+    key_num = 1; // Keys are numbered from 1 and refered to in the ilst following.
+    while (key_count--) {
+        key_size = avio_rb32(pb) - 8;
+        key_namespace = avio_rl32(pb);
+        if (key_namespace == MKTAG('m','d','t','a')) {
+            key_str = av_malloc(key_size + 1); /* Add null terminator */
+            if (!key_str) {
+                return AVERROR(ENOMEM);
+            }
+
+            ret = ffio_read_size(pb, key_str, key_size);
+            if (ret < 0) {
+                av_freep(&key_str);
+                return ret;
+            }
+            
+            key_str[key_size] = 0;
+            if (key_str[0]) {
+                snprintf(key_num_str, sizeof(key_num_str), "%08x", av_be2ne32(key_num));
+                av_dict_set(&(c->keys_d), key_num_str, key_str, 0);
+            }
+            av_freep(&key_str);
+        } else {
+            // Don't know what to do with other namespaces... ignore
+            avio_seek(pb, key_size, SEEK_CUR);
+        }
+        ++key_num;
+    }
+
+    while (entry = av_dict_get(c->keys_d, "", entry, AV_DICT_IGNORE_SUFFIX)) {
+            av_log(c->fc, AV_LOG_TRACE,
+                   "Read metadata key %s: '%s'\n", entry->key, entry->value);
+    }
+
+    return 0;
+}
+
 static int mov_read_tkhd(MOVContext *c, AVIOContext *pb, MOVAtom atom)
 {
     int i;
@@ -3786,6 +3846,7 @@ static const MOVParseTableEntry mov_default_parse_table[] = {
 { MKTAG('h','d','l','r'), mov_read_hdlr },
 { MKTAG('i','l','s','t'), mov_read_ilst },
 { MKTAG('j','p','2','h'), mov_read_jp2h },
+{ MKTAG('k','e','y','s'), mov_read_keys },
 { MKTAG('m','d','a','t'), mov_read_mdat },
 { MKTAG('m','d','h','d'), mov_read_mdhd },
 { MKTAG('m','d','i','a'), mov_read_default },
@@ -4203,6 +4264,8 @@ static int mov_read_close(AVFormatContext *s)
     av_freep(&mov->fragment_index_data);
 
     av_freep(&mov->aes_decrypt);
+    
+    av_dict_free(&mov->keys_d);
 
     return 0;
 }
-- 
1.7.1

From 0e85e8b299c5361ed13935f99ad64e6cf6f69aca Mon Sep 17 00:00:00 2001
From: Kevin Wheatley <kevin.j.wheat...@gmail.com>
Date: Fri, 4 Sep 2015 15:47:58 +0100
Subject: [PATCH] avformat/mov: Add support for numeric data value metadata handling

Signed-off-by: Kevin Wheatley <kevin.j.wheat...@gmail.com>
---
 libavformat/mov.c |  165 ++++++++++++++++++++++++++++++++++++++++++++++++----
 1 files changed, 152 insertions(+), 13 deletions(-)

diff --git a/libavformat/mov.c b/libavformat/mov.c
index 46c4b17..18fd1cd 100644
--- a/libavformat/mov.c
+++ b/libavformat/mov.c
@@ -255,6 +255,88 @@ static int mov_metadata_loci(MOVContext *c, AVIOContext *pb, unsigned len)
     return av_dict_set(&c->fc->metadata, key, buf, 0);
 }
 
+static int mov_read_data_value_int(MOVContext *c, AVIOContext *pb,
+                                        unsigned len, const char *key)
+{
+    int64_t value = 0;
+    switch (len)
+    {
+        case 1:
+            value = (int64_t) avio_r8(pb);
+            break;
+        case 2:
+            value = (int64_t) avio_rb16(pb);
+            break;
+        case 3:
+            value = (int64_t) avio_rb24(pb);
+            break;
+        case 4:
+            value = (int64_t) avio_rb32(pb);
+            break;
+        case 8:
+            value = (int64_t) avio_rb64(pb);
+            break;
+    }
+
+    c->fc->event_flags |= AVFMT_EVENT_FLAG_METADATA_UPDATED;
+    return av_dict_set_int(&c->fc->metadata, key, value, 0);
+}
+
+static int mov_read_data_value_uint(MOVContext *c, AVIOContext *pb,
+                                        unsigned len, const char *key)
+{
+    uint64_t value = 0;
+    char valuestr[22];
+    switch (len)
+    {
+        case 1:
+            value = avio_r8(pb);
+            break;
+        case 2:
+            value = avio_rb16(pb);
+            break;
+        case 3:
+            value = avio_rb24(pb);
+            break;
+        case 4:
+            value = avio_rb32(pb);
+            break;
+        case 8:
+            value = avio_rb64(pb);
+            break;
+    }
+    snprintf(valuestr, sizeof(valuestr), "%"PRIu64, value);
+
+    c->fc->event_flags |= AVFMT_EVENT_FLAG_METADATA_UPDATED;
+    return av_dict_set(&c->fc->metadata, key, valuestr, 0);
+}
+
+static int mov_read_data_value_float32(MOVContext *c, AVIOContext *pb,
+                                        unsigned len, const char *key)
+{
+    union av_intfloat32 value;
+    char valuestr[17]; // sign + 1 + point + 8 + e + sign + 3 + term
+ 
+    value.i = avio_rb32(pb);
+    snprintf(valuestr, sizeof(valuestr), "%.9g", value.f);
+ 
+    c->fc->event_flags |= AVFMT_EVENT_FLAG_METADATA_UPDATED;
+    return av_dict_set(&c->fc->metadata, key, valuestr, 0);
+}
+
+static int mov_read_data_value_float64(MOVContext *c, AVIOContext *pb,
+                                        unsigned len, const char *key)
+{
+    union av_intfloat64 value;
+    char valuestr[26]; // sign + 1 + point + 16 + e + sign + 4 + term
+
+    value.i = avio_rb64(pb);
+    snprintf(valuestr, sizeof(valuestr), "%.9g", value.f);
+ 
+    c->fc->event_flags |= AVFMT_EVENT_FLAG_METADATA_UPDATED;
+    return av_dict_set(&c->fc->metadata, key, valuestr, 0);
+}
+
 static int mov_read_udta_string(MOVContext *c, AVIOContext *pb, MOVAtom atom)
 {
     char tmp_key[5];
@@ -262,9 +344,10 @@ static int mov_read_udta_string(MOVContext *c, AVIOContext *pb, MOVAtom atom)
     char *str = NULL;
     const char *key = NULL;
     uint16_t langcode = 0;
-    uint32_t data_type = 0, str_size, str_size_alloc;
+    uint32_t data_type = 0, data_locale = 0, str_size, str_size_alloc;
     int (*parse)(MOVContext*, AVIOContext*, unsigned, const char*) = NULL;
     int raw = 0;
+    int ret = 0;
     AVDictionaryEntry *entry = NULL;
 
     switch (atom.type) {
@@ -357,7 +440,7 @@ static int mov_read_udta_string(MOVContext *c, AVIOContext *pb, MOVAtom atom)
         entry = av_dict_get(c->keys_d, key2, entry, 0);
         if (entry)
             key = entry->value;
-        av_log(c->fc, AV_LOG_TRACE, "Attempting to match unknown atom type %08x %s in keys => '%s'\n", atom.type, key2, key);
+        av_log(c->fc, AV_LOG_TRACE, "Attempting to match unknown atom type %08x %.4s %s in keys => '%s'\n", atom.type, (char*)&atom.type, key2, key);
         break;
     }
 retry:
@@ -366,7 +449,7 @@ retry:
         int tag = avio_rl32(pb);
         if (tag == MKTAG('d','a','t','a') && data_size <= atom.size) {
             data_type = avio_rb32(pb); // type
-            avio_rb32(pb); // unknown
+            data_locale = avio_rb32(pb); // locale
             str_size = data_size - 16;
             atom.size -= 16;
 
@@ -399,6 +482,62 @@ retry:
 
     if (!key)
         return 0;
+
+    av_log(c->fc, AV_LOG_TRACE, "Found '%s' %u %u\n", key, str_size, data_type);
+    switch (data_type)
+    {
+        case 0:  // Reserved
+        case 1:  // UTF-8
+        case 2:  // UTF-16
+        case 3:  // S/JIS
+        case 4:  // UTF-8 machine sortable
+        case 5:  // UTF-16 machine sortable
+            break;
+        case 21: // BE signed int
+        case 65: // 8-bit Signed Integer
+        case 66: // BE 16-bit Signed Integer
+        case 67: // BE 32-bit Signed Integer
+        case 74: // BE 64-bit Signed Integer
+            if ((str_size > 0 && str_size < 5) || (str_size == 8)) {
+                parse = mov_read_data_value_int;
+            }
+            break;
+        case 22: // BE unsigned int
+        case 75: // BE 8-bit Unsigned Integer
+        case 76: // BE 16-bit Unsigned Integer
+        case 77: // BE 32-bit Unsigned Integer
+        case 78: // BE 64-bit Unsigned Integer
+            if ((str_size > 0 && str_size < 5) || (str_size == 8)) {
+                parse = mov_read_data_value_uint;
+            }
+            break;
+        case 23: // BE float 32
+            if (str_size == 4) {
+                parse = mov_read_data_value_float32;
+            }
+            break;
+        case 24: // BE float 64
+            if (str_size == 8) {
+                parse = mov_read_data_value_float64;
+            }
+            break;
+        case 13: // JPEG
+        case 14: // PNG
+        case 27: // BMP
+            av_log(c->fc, AV_LOG_TRACE, "Unsupported data value '%s' %u %u - image type\n", key, str_size, data_type);
+            break;
+        case 28: // QuickTime Metadata atom
+        case 70: // BE PointF32 2D x, y
+        case 71: // BE DimensionsF32 2D width, height
+        case 72: // BE RectF32 2D Rectangle x, y, width, height
+        case 79: // AffineTransformF64 matrix BEFloat64[3][3]
+            av_log(c->fc, AV_LOG_TRACE, "Unsupported data value '%s' %u %u\n", key, str_size, data_type);
+            break;
+        default:
+            av_log(c->fc, AV_LOG_TRACE, "Unknown data value '%s' %u %u\n", key, str_size, data_type);
+            break;
+    }
+
     if (atom.size < 0 || str_size >= INT_MAX/2)
         return AVERROR_INVALIDDATA;
 
@@ -409,12 +548,12 @@ retry:
         return AVERROR(ENOMEM);
 
     if (parse)
-        parse(c, pb, str_size, key);
+        ret = parse(c, pb, str_size, key);
     else {
         if (!raw && (data_type == 3 || (data_type == 0 && (langcode < 0x400 || langcode == 0x7fff)))) { // MAC Encoded
-            mov_read_mac_string(c, pb, str_size, str, str_size_alloc);
+            ret = mov_read_mac_string(c, pb, str_size, str, str_size_alloc);
         } else {
-            int ret = ffio_read_size(pb, str, str_size);
+            ret = ffio_read_size(pb, str, str_size);
             if (ret < 0) {
                 av_free(str);
                 return ret;
@@ -433,7 +572,7 @@ retry:
             key, str, (char*)&atom.type, str_size_alloc, atom.size);
 
     av_freep(&str);
-    return 0;
+    return ret;
 }
 
 static int mov_read_chpl(MOVContext *c, AVIOContext *pb, MOVAtom atom)
@@ -3207,11 +3346,12 @@ static int mov_read_keys(MOVContext *c, AVIOContext *pb, MOVAtom atom)
     av_log(c->fc, AV_LOG_VERBOSE,
            "Reading keys sz: %"PRId64" %u\n", atom.size, key_count);
 
-    key_num = 1; // Keys are numbered from 1 and refered to in the ilst following.
-    while (key_count--) {
-        key_size = avio_rb32(pb) - 8;
+    // Note: keys are numbered from 1 and refered to by number in the ilst following.
+    for (key_num = 1; key_num <= key_count; ++key_num) {
+        key_size = avio_rb32(pb);
         key_namespace = avio_rl32(pb);
-        if (key_namespace == MKTAG('m','d','t','a')) {
+        if (key_size > 8 && key_namespace == MKTAG('m','d','t','a')) {
+            key_size -= 8;
             key_str = av_malloc(key_size + 1); /* Add null terminator */
             if (!key_str) {
                 return AVERROR(ENOMEM);
@@ -3230,10 +3370,9 @@ static int mov_read_keys(MOVContext *c, AVIOContext *pb, MOVAtom atom)
             }
             av_freep(&key_str);
         } else {
-            // Don't know what to do with other namespaces... ignore
+            // Don't know what to do with small keys or other namespaces... ignore
             avio_seek(pb, key_size, SEEK_CUR);
         }
-        ++key_num;
     }
 
     while (entry = av_dict_get(c->keys_d, "", entry, AV_DICT_IGNORE_SUFFIX)) {
-- 
1.7.1

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel

Reply via email to