[FFmpeg-devel,v3,17/25] avformat/mov: read urim metadata from meta

Submitted by erkki.seppala.ext@nokia.com on Sept. 19, 2016, 1:25 p.m.

Details

Message ID 1474291548-17810-18-git-send-email-erkki.seppala.ext@nokia.com
State New
Headers show

Commit Message

erkki.seppala.ext@nokia.com Sept. 19, 2016, 1:25 p.m.
The data is read into side packet AV_PKT_DATA_TIMED_METADATA_INFO of
format AVTimedMetadata.

Signed-off-by: Erkki Seppälä <erkki.seppala.ext@nokia.com>
Signed-off-by: OZOPlayer <OZOPL@nokia.com>
---
 libavformat/mov.c | 141 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 141 insertions(+)

Patch hide | download patch | download mbox

diff --git a/libavformat/mov.c b/libavformat/mov.c
index f9126c4..059c7c4 100644
--- a/libavformat/mov.c
+++ b/libavformat/mov.c
@@ -2039,6 +2039,145 @@  static int mov_rewrite_dvd_sub_extradata(AVStream *st)
     return 0;
 }
 
+static int mov_parse_urim_uri_data(AVIOContext *pb, AVStream *st, MOVMeta *meta)
+{
+    int64_t size = avio_rb32(pb);
+    uint32_t uri = avio_rb32(pb); /* "uri " */
+    avio_r8(pb);                  /* version */
+    avio_rb24(pb);                /* flags */
+
+    if (size < 12 || size >= 1024)
+        return AVERROR(ENOMEM);
+
+    if (uri == AV_RB32("uri ")) {
+        int remaining = size - 12;
+        int64_t pos = avio_tell(pb);
+        uint32_t string_len = 0;
+
+        while (string_len < remaining && avio_r8(pb) != 0) {
+            ++string_len;
+        }
+        avio_seek(pb, pos, SEEK_SET);
+
+        if (string_len >= remaining)
+            return AVERROR_INVALIDDATA;
+
+        meta->tag = MKTAG('u', 'r', 'i', 'm');
+        meta->data = av_malloc(string_len + 1);
+        if (!meta->data)
+            return AVERROR(ENOMEM);
+
+        avio_read(pb, meta->data, string_len);
+        ((char*) meta->data)[string_len] = 0;
+        meta->length = string_len;
+        remaining -= string_len;
+        avio_r8(pb);            /* read the null terminator */
+        remaining--;
+
+        avio_skip(pb, remaining);
+    } else {
+        avio_skip(pb, size - 12);
+    }
+
+    return 0;
+}
+
+static int mov_parse_urim_conf_data(AVIOContext *pb, AVStream *st, int64_t remaining, MOVMeta *meta)
+{
+    int64_t size;
+    uint32_t tag;
+    int64_t data_size;
+
+    if (remaining < 12)
+        return 0;
+
+    size = avio_rb32(pb);
+    tag = avio_rl32(pb);
+    avio_r8(pb);                /* version */
+    avio_rb24(pb);              /* flags */
+    remaining -= 12;
+    data_size = size - 12;
+
+    if (data_size < 0 || data_size > remaining) {
+        avio_skip(pb, remaining);
+        return 0;
+    }
+
+    meta->conf.data = av_malloc(data_size);
+    if (!meta->conf.data)
+        return AVERROR(ENOMEM);
+
+    meta->conf.tag = tag;
+    meta->conf.length = data_size;
+    avio_read(pb, meta->conf.data, data_size);
+    remaining -= data_size;
+    avio_skip(pb, remaining);
+
+    return 0;
+}
+
+static int mov_parse_urim_data(AVIOContext *pb, AVStream *st, int64_t remaining)
+{
+    int64_t pos = avio_tell(pb);
+    int ret;
+    MOVMeta meta;
+
+    memset(&meta, 0, sizeof(meta));
+
+    ret = mov_parse_urim_uri_data(pb, st, &meta);
+    if (ret)
+        return ret;
+
+    remaining -= avio_tell(pb) - pos;
+    ret = mov_parse_urim_conf_data(pb, st, remaining, &meta);
+
+    // all data has been collected; now build the actual side channel
+    // object from the collected data
+    if (ret == 0) {
+        int tmdLength = sizeof(AVTimedMetadataInfo) + meta.length + meta.conf.length;
+        AVTimedMetadataInfo *tmd = av_malloc(tmdLength);
+        if (!tmd) {
+            ret = -1;
+        } else {
+            AVPacketSideData *sd;
+            ret = av_reallocp_array(&st->side_data,
+                                    st->nb_side_data + 1, sizeof(*sd));
+            if (ret >= 0) {
+                char* data;
+
+                sd = st->side_data + st->nb_side_data;
+                st->nb_side_data++;
+
+                sd->type = AV_PKT_DATA_TIMED_METADATA_INFO;
+                sd->size = sizeof(*tmd) + meta.length + meta.conf.length;
+                sd->data = (uint8_t*) tmd;
+
+                tmd->meta_tag[0] = (meta.tag >> 0) & 0xff;
+                tmd->meta_tag[1] = (meta.tag >> 8) & 0xff;
+                tmd->meta_tag[2] = (meta.tag >> 16) & 0xff;
+                tmd->meta_tag[3] = (meta.tag >> 24) & 0xff;
+                tmd->meta_length = meta.length;
+                tmd->conf_tag[0] = (meta.conf.tag >> 0) & 0xff;
+                tmd->conf_tag[1] = (meta.conf.tag >> 8) & 0xff;
+                tmd->conf_tag[2] = (meta.conf.tag >> 16) & 0xff;
+                tmd->conf_tag[3] = (meta.conf.tag >> 24) & 0xff;
+                tmd->conf_length = meta.conf.length;
+                data = (char*) (tmd + 1);
+
+                memcpy(data, meta.data, meta.length);
+                data += meta.length;
+                memcpy(data, meta.conf.data, meta.conf.length);
+            } else {
+                av_freep(&tmd);
+            }
+        }
+    }
+    av_freep(&meta.data);
+    av_freep(&meta.conf.data);
+
+    return ret;
+}
+
 static int mov_parse_stsd_data(MOVContext *c, AVIOContext *pb,
                                 AVStream *st, MOVStreamContext *sc,
                                 int64_t size)
@@ -2098,6 +2237,8 @@  FF_ENABLE_DEPRECATION_WARNINGS
                 }
             }
         }
+    } else if (st->codecpar->codec_tag == MKTAG('u', 'r', 'i', 'm')) {
+        ret = mov_parse_urim_data(pb, st, size);
     } else {
         /* other codec type, just skip (rtp, mp4s ...) */
         avio_skip(pb, size);