@@ -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[];
@@ -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;
}