summaryrefslogtreecommitdiff
path: root/libavformat/mov.c
diff options
context:
space:
mode:
authorAnton Khirnov <anton@khirnov.net>2014-04-01 23:22:21 +0200
committerAnton Khirnov <anton@khirnov.net>2014-04-10 13:53:32 +0200
commit9a07fac678a8540d076e635061bbaa4ed09a9431 (patch)
tree312cd41ac04bf43ba69a877e0e2c70f9d42a74ab /libavformat/mov.c
parentad8159e0fe2bfc1c34739f0956ce464f9859b5a7 (diff)
mov: read hydrogenaudio replaygain information
Diffstat (limited to 'libavformat/mov.c')
-rw-r--r--libavformat/mov.c97
1 files changed, 97 insertions, 0 deletions
diff --git a/libavformat/mov.c b/libavformat/mov.c
index 2900b1edc0..30f7f6e264 100644
--- a/libavformat/mov.c
+++ b/libavformat/mov.c
@@ -45,6 +45,7 @@
#include "libavcodec/get_bits.h"
#include "id3v1.h"
#include "mov_chan.h"
+#include "replaygain.h"
#if CONFIG_ZLIB
#include <zlib.h>
@@ -2236,6 +2237,88 @@ static int mov_read_ilst(MOVContext *c, AVIOContext *pb, MOVAtom atom)
return ret;
}
+static int mov_read_replaygain(MOVContext *c, AVIOContext *pb, int size)
+{
+ int64_t end = avio_tell(pb) + size;
+ uint8_t *key = NULL, *val = NULL;
+ int i;
+
+ for (i = 0; i < 2; i++) {
+ uint8_t **p;
+ uint32_t len, tag;
+
+ if (end - avio_tell(pb) <= 12)
+ break;
+
+ len = avio_rb32(pb);
+ tag = avio_rl32(pb);
+ avio_skip(pb, 4); // flags
+
+ if (len < 12 || len - 12 > end - avio_tell(pb))
+ break;
+ len -= 12;
+
+ if (tag == MKTAG('n', 'a', 'm', 'e'))
+ p = &key;
+ else if (tag == MKTAG('d', 'a', 't', 'a') && len > 4) {
+ avio_skip(pb, 4);
+ len -= 4;
+ p = &val;
+ } else
+ break;
+
+ *p = av_malloc(len + 1);
+ if (!*p)
+ break;
+ avio_read(pb, *p, len);
+ (*p)[len] = 0;
+ }
+
+ if (key && val) {
+ av_dict_set(&c->fc->metadata, key, val,
+ AV_DICT_DONT_STRDUP_KEY | AV_DICT_DONT_STRDUP_VAL);
+ key = val = NULL;
+ }
+
+ avio_seek(pb, end, SEEK_SET);
+ av_freep(&key);
+ av_freep(&val);
+ return 0;
+}
+
+static int mov_read_custom(MOVContext *c, AVIOContext *pb, MOVAtom atom)
+{
+ int64_t end = avio_tell(pb) + atom.size;
+ uint32_t tag, len;
+
+ if (atom.size < 8)
+ goto fail;
+
+ len = avio_rb32(pb);
+ tag = avio_rl32(pb);
+
+ if (len > atom.size)
+ goto fail;
+
+ if (tag == MKTAG('m', 'e', 'a', 'n') && len > 12) {
+ uint8_t domain[128];
+ int domain_len;
+
+ avio_skip(pb, 4); // flags
+ len -= 12;
+
+ domain_len = avio_get_str(pb, len, domain, sizeof(domain));
+ avio_skip(pb, len - domain_len);
+ if (!strcmp(domain, "org.hydrogenaudio.replaygain"))
+ return mov_read_replaygain(c, pb, end - avio_tell(pb));
+ }
+
+fail:
+ av_log(c->fc, AV_LOG_VERBOSE,
+ "Unhandled or malformed custom metadata of size %"PRId64"\n", atom.size);
+ return 0;
+}
+
static int mov_read_meta(MOVContext *c, AVIOContext *pb, MOVAtom atom)
{
while (atom.size > 8) {
@@ -2665,6 +2748,7 @@ static const MOVParseTableEntry mov_default_parse_table[] = {
{ MKTAG('d','v','c','1'), mov_read_dvc1 },
{ MKTAG('s','b','g','p'), mov_read_sbgp },
{ MKTAG('h','v','c','C'), mov_read_glbl },
+{ MKTAG('-','-','-','-'), mov_read_custom },
{ 0, NULL }
};
@@ -2958,6 +3042,19 @@ static int mov_read_header(AVFormatContext *s)
}
}
+ for (i = 0; i < s->nb_streams; i++) {
+ AVStream *st = s->streams[i];
+
+ if (st->codec->codec_type != AVMEDIA_TYPE_AUDIO)
+ continue;
+
+ err = ff_replaygain_export(st, s->metadata);
+ if (err < 0) {
+ mov_read_close(s);
+ return err;
+ }
+ }
+
return 0;
}