diff mbox

[FFmpeg-devel,15/21] libavformat/mov: read urim metadata from meta

Message ID 1471943019-14136-16-git-send-email-erkki.seppala.ext@nokia.com
State Superseded
Headers show

Commit Message

erkki.seppala.ext@nokia.com Aug. 23, 2016, 9:03 a.m. UTC
From: Erkki Seppälä <erkki.seppala.ext@nokia.com>

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/isom.h |   1 +
 libavformat/mov.c  | 163 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 164 insertions(+)
diff mbox

Patch

diff --git a/libavformat/isom.h b/libavformat/isom.h
index 9ad898a..b4220c0 100644
--- a/libavformat/isom.h
+++ b/libavformat/isom.h
@@ -27,6 +27,7 @@ 
 #include "avio.h"
 #include "internal.h"
 #include "dv.h"
+#include "movmeta.h"
 
 /* isom.c */
 extern const AVCodecTag ff_mp4_obj_type[];
diff --git a/libavformat/mov.c b/libavformat/mov.c
index 275b532..fb233b6 100644
--- a/libavformat/mov.c
+++ b/libavformat/mov.c
@@ -2041,6 +2041,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(AVTimedMetadata) + meta.length + meta.conf.length;
+        AVTimedMetadata *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)
@@ -2100,6 +2239,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);
@@ -3207,6 +3348,28 @@  static int mov_read_tref(MOVContext *c, AVIOContext *pb, MOVAtom atom)
             sc->nb_tref_ids++;
             remaining -= 4;
         }
+
+        if (sc->nb_tref_ids) {
+            int i;
+            AVTrackReferences *trefs_side;
+            int *trefs_tracks;
+
+            trefs_side = (void*) av_stream_new_side_data(st,
+                                                         AV_PKT_DATA_TRACK_REFERENCES,
+                                                         sizeof(AVTrackReferences) + sizeof(int) * sc->nb_tref_ids);
+            if (!trefs_side)
+                return AVERROR(ENOMEM);
+            trefs_side->nb_tracks = sc->nb_tref_ids;
+            trefs_side->tag[0] = (sc->tref_tag >>  0) & 0xff;
+            trefs_side->tag[1] = (sc->tref_tag >>  8) & 0xff;
+            trefs_side->tag[2] = (sc->tref_tag >> 16) & 0xff;
+            trefs_side->tag[3] = (sc->tref_tag >> 24) & 0xff;
+            trefs_tracks = (void*) (trefs_side + 1);
+            for (i = 0; i < sc->nb_tref_ids; ++i) {
+                trefs_tracks[i] = sc->tref_ids[i];
+            }
+        }
+
         avio_seek(pb, remaining, SEEK_CUR);
         return ret;
     }