matroskadec: parse the channel layout mask for FLAC
authorAnton Khirnov <anton@khirnov.net>
Mon, 26 May 2014 10:48:56 +0000 (12:48 +0200)
committerAnton Khirnov <anton@khirnov.net>
Wed, 28 May 2014 05:50:32 +0000 (07:50 +0200)
It is commonly stored in a vorbiscomment block in codec private data.

libavformat/Makefile
libavformat/flacdec.c
libavformat/matroskadec.c
libavformat/oggdec.h
libavformat/oggparsecelt.c
libavformat/oggparseflac.c
libavformat/oggparseogm.c
libavformat/oggparseopus.c
libavformat/oggparsespeex.c
libavformat/oggparsetheora.c
libavformat/oggparsevorbis.c

index ae3bcbd..39cfafa 100644 (file)
@@ -166,7 +166,8 @@ OBJS-$(CONFIG_LXF_DEMUXER)               += lxfdec.o
 OBJS-$(CONFIG_M4V_DEMUXER)               += m4vdec.o rawdec.o
 OBJS-$(CONFIG_M4V_MUXER)                 += rawenc.o
 OBJS-$(CONFIG_MATROSKA_DEMUXER)          += matroskadec.o matroska.o  \
-                                            isom.o rmsipr.o
+                                            isom.o rmsipr.o \
+                                            oggparsevorbis.o vorbiscomment.o
 OBJS-$(CONFIG_MATROSKA_MUXER)            += matroskaenc.o matroska.o \
                                             isom.o avc.o hevc.o \
                                             flacenc_header.o avlanguage.o wv.o
index ee40a20..05286c7 100644 (file)
@@ -141,7 +141,7 @@ static int flac_read_header(AVFormatContext *s)
             if (metadata_type == FLAC_METADATA_TYPE_VORBIS_COMMENT) {
                 AVDictionaryEntry *chmask;
 
-                if (ff_vorbis_comment(s, &s->metadata, buffer, metadata_size)) {
+                if (ff_vorbis_comment(s, &s->metadata, buffer, metadata_size, 1)) {
                     av_log(s, AV_LOG_WARNING, "error parsing VorbisComment metadata\n");
                 }
 
index 2056391..e376bae 100644 (file)
@@ -55,6 +55,7 @@
 #include "internal.h"
 #include "isom.h"
 #include "matroska.h"
+#include "oggdec.h"
 /* For ff_codec_get_id(). */
 #include "riff.h"
 #include "rmsipr.h"
@@ -1443,6 +1444,7 @@ static int matroska_parse_flac(AVFormatContext *s,
                                MatroskaTrack *track,
                                int *offset)
 {
+    AVStream *st = track->stream;
     uint8_t *p = track->codec_priv.data;
     int size   = track->codec_priv.size;
 
@@ -1454,6 +1456,42 @@ static int matroska_parse_flac(AVFormatContext *s,
     *offset = 8;
     track->codec_priv.size = 8 + FLAC_STREAMINFO_SIZE;
 
+    p    += track->codec_priv.size;
+    size -= track->codec_priv.size;
+
+    /* parse the remaining metadata blocks if present */
+    while (size >= 4) {
+        int block_last, block_type, block_size;
+
+        flac_parse_block_header(p, &block_last, &block_type, &block_size);
+
+        p    += 4;
+        size -= 4;
+        if (block_size > size)
+            return 0;
+
+        /* check for the channel mask */
+        if (block_type == FLAC_METADATA_TYPE_VORBIS_COMMENT) {
+            AVDictionary *dict = NULL;
+            AVDictionaryEntry *chmask;
+
+            ff_vorbis_comment(s, &dict, p, block_size, 0);
+            chmask = av_dict_get(dict, "WAVEFORMATEXTENSIBLE_CHANNEL_MASK", NULL, 0);
+            if (chmask) {
+                uint64_t mask = strtol(chmask->value, NULL, 0);
+                if (!mask || mask & ~0x3ffffULL) {
+                    av_log(s, AV_LOG_WARNING,
+                           "Invalid value of WAVEFORMATEXTENSIBLE_CHANNEL_MASK\n");
+                } else
+                    st->codec->channel_layout = mask;
+            }
+            av_dict_free(&dict);
+        }
+
+        p    += block_size;
+        size -= block_size;
+    }
+
     return 0;
 }
 
index 918378d..893c330 100644 (file)
@@ -122,7 +122,8 @@ extern const struct ogg_codec ff_speex_codec;
 extern const struct ogg_codec ff_theora_codec;
 extern const struct ogg_codec ff_vorbis_codec;
 
-int ff_vorbis_comment(AVFormatContext *ms, AVDictionary **m, const uint8_t *buf, int size);
+int ff_vorbis_comment(AVFormatContext *ms, AVDictionary **m,
+                      const uint8_t *buf, int size, int parse_picture);
 
 static inline int
 ogg_find_stream (struct ogg * ogg, int serial)
index 0deccc2..e3ea586 100644 (file)
@@ -81,7 +81,7 @@ static int celt_header(AVFormatContext *s, int idx)
     } else if (priv && priv->extra_headers_left) {
         /* Extra headers (vorbiscomment) */
 
-        ff_vorbis_comment(s, &st->metadata, p, os->psize);
+        ff_vorbis_comment(s, &st->metadata, p, os->psize, 1);
         priv->extra_headers_left--;
         return 1;
     } else {
index f59b400..7808aad 100644 (file)
@@ -69,7 +69,7 @@ flac_header (AVFormatContext * s, int idx)
 
         avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate);
     } else if (mdt == FLAC_METADATA_TYPE_VORBIS_COMMENT) {
-        ff_vorbis_comment (s, &st->metadata, os->buf + os->pstart + 4, os->psize - 4);
+        ff_vorbis_comment (s, &st->metadata, os->buf + os->pstart + 4, os->psize - 4, 1);
     }
 
     return 1;
index 2313625..74d9e10 100644 (file)
@@ -97,7 +97,7 @@ ogm_header(AVFormatContext *s, int idx)
     } else if (bytestream2_peek_byte(&p) == 3) {
         bytestream2_skip(&p, 7);
         if (bytestream2_get_bytes_left(&p) > 1)
-            ff_vorbis_comment(s, &st->metadata, p.buffer, bytestream2_get_bytes_left(&p) - 1);
+            ff_vorbis_comment(s, &st->metadata, p.buffer, bytestream2_get_bytes_left(&p) - 1, 1);
     }
 
     return 1;
index babd0f0..cfdf35d 100644 (file)
@@ -74,7 +74,7 @@ static int opus_header(AVFormatContext *avf, int idx)
     if (priv->need_comments) {
         if (os->psize < 8 || memcmp(packet, "OpusTags", 8))
             return AVERROR_INVALIDDATA;
-        ff_vorbis_comment(avf, &st->metadata, packet + 8, os->psize - 8);
+        ff_vorbis_comment(avf, &st->metadata, packet + 8, os->psize - 8, 1);
         priv->need_comments--;
         return 1;
     }
index 42480a3..6d70e99 100644 (file)
@@ -79,7 +79,7 @@ static int speex_header(AVFormatContext *s, int idx) {
 
         avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate);
     } else
-        ff_vorbis_comment(s, &st->metadata, p, os->psize);
+        ff_vorbis_comment(s, &st->metadata, p, os->psize, 1);
 
     spxp->seq++;
     return 1;
index 035bdc2..8a5e1d8 100644 (file)
@@ -116,7 +116,7 @@ static int theora_header(AVFormatContext *s, int idx)
     }
     break;
     case 0x81:
-        ff_vorbis_comment(s, &st->metadata, os->buf + os->pstart + 7, os->psize - 7);
+        ff_vorbis_comment(s, &st->metadata, os->buf + os->pstart + 7, os->psize - 7, 1);
     case 0x82:
         if (!thp->version)
             return AVERROR_INVALIDDATA;
index 3eac0ba..58cb4a6 100644 (file)
@@ -72,7 +72,8 @@ static int ogm_chapter(AVFormatContext *as, uint8_t *key, uint8_t *val)
 }
 
 int ff_vorbis_comment(AVFormatContext *as, AVDictionary **m,
-                      const uint8_t *buf, int size)
+                      const uint8_t *buf, int size,
+                      int parse_picture)
 {
     const uint8_t *p   = buf;
     const uint8_t *end = buf + size;
@@ -137,7 +138,7 @@ int ff_vorbis_comment(AVFormatContext *as, AVDictionary **m,
              * 'METADATA_BLOCK_PICTURE'. This is the preferred and
              * recommended way of embedding cover art within VorbisComments."
              */
-            if (!strcmp(tt, "METADATA_BLOCK_PICTURE")) {
+            if (!strcmp(tt, "METADATA_BLOCK_PICTURE") && parse_picture) {
                 int ret;
                 char *pict = av_malloc(vl);
 
@@ -305,7 +306,7 @@ static int vorbis_header(AVFormatContext *s, int idx)
     } else if (os->buf[os->pstart] == 3) {
         if (os->psize > 8 &&
             ff_vorbis_comment(s, &st->metadata, os->buf + os->pstart + 7,
-                              os->psize - 8) >= 0) {
+                              os->psize - 8, 1) >= 0) {
             unsigned new_len;
 
             int ret = ff_replaygain_export(st, st->metadata);