Browse code

matroskadec: parse the channel layout mask for FLAC

It is commonly stored in a vorbiscomment block in codec private data.

Anton Khirnov authored on 2014/05/26 19:48:56
Showing 11 changed files
... ...
@@ -166,7 +166,8 @@ OBJS-$(CONFIG_LXF_DEMUXER)               += lxfdec.o
166 166
 OBJS-$(CONFIG_M4V_DEMUXER)               += m4vdec.o rawdec.o
167 167
 OBJS-$(CONFIG_M4V_MUXER)                 += rawenc.o
168 168
 OBJS-$(CONFIG_MATROSKA_DEMUXER)          += matroskadec.o matroska.o  \
169
-                                            isom.o rmsipr.o
169
+                                            isom.o rmsipr.o \
170
+                                            oggparsevorbis.o vorbiscomment.o
170 171
 OBJS-$(CONFIG_MATROSKA_MUXER)            += matroskaenc.o matroska.o \
171 172
                                             isom.o avc.o hevc.o \
172 173
                                             flacenc_header.o avlanguage.o wv.o
... ...
@@ -141,7 +141,7 @@ static int flac_read_header(AVFormatContext *s)
141 141
             if (metadata_type == FLAC_METADATA_TYPE_VORBIS_COMMENT) {
142 142
                 AVDictionaryEntry *chmask;
143 143
 
144
-                if (ff_vorbis_comment(s, &s->metadata, buffer, metadata_size)) {
144
+                if (ff_vorbis_comment(s, &s->metadata, buffer, metadata_size, 1)) {
145 145
                     av_log(s, AV_LOG_WARNING, "error parsing VorbisComment metadata\n");
146 146
                 }
147 147
 
... ...
@@ -55,6 +55,7 @@
55 55
 #include "internal.h"
56 56
 #include "isom.h"
57 57
 #include "matroska.h"
58
+#include "oggdec.h"
58 59
 /* For ff_codec_get_id(). */
59 60
 #include "riff.h"
60 61
 #include "rmsipr.h"
... ...
@@ -1443,6 +1444,7 @@ static int matroska_parse_flac(AVFormatContext *s,
1443 1443
                                MatroskaTrack *track,
1444 1444
                                int *offset)
1445 1445
 {
1446
+    AVStream *st = track->stream;
1446 1447
     uint8_t *p = track->codec_priv.data;
1447 1448
     int size   = track->codec_priv.size;
1448 1449
 
... ...
@@ -1454,6 +1456,42 @@ static int matroska_parse_flac(AVFormatContext *s,
1454 1454
     *offset = 8;
1455 1455
     track->codec_priv.size = 8 + FLAC_STREAMINFO_SIZE;
1456 1456
 
1457
+    p    += track->codec_priv.size;
1458
+    size -= track->codec_priv.size;
1459
+
1460
+    /* parse the remaining metadata blocks if present */
1461
+    while (size >= 4) {
1462
+        int block_last, block_type, block_size;
1463
+
1464
+        flac_parse_block_header(p, &block_last, &block_type, &block_size);
1465
+
1466
+        p    += 4;
1467
+        size -= 4;
1468
+        if (block_size > size)
1469
+            return 0;
1470
+
1471
+        /* check for the channel mask */
1472
+        if (block_type == FLAC_METADATA_TYPE_VORBIS_COMMENT) {
1473
+            AVDictionary *dict = NULL;
1474
+            AVDictionaryEntry *chmask;
1475
+
1476
+            ff_vorbis_comment(s, &dict, p, block_size, 0);
1477
+            chmask = av_dict_get(dict, "WAVEFORMATEXTENSIBLE_CHANNEL_MASK", NULL, 0);
1478
+            if (chmask) {
1479
+                uint64_t mask = strtol(chmask->value, NULL, 0);
1480
+                if (!mask || mask & ~0x3ffffULL) {
1481
+                    av_log(s, AV_LOG_WARNING,
1482
+                           "Invalid value of WAVEFORMATEXTENSIBLE_CHANNEL_MASK\n");
1483
+                } else
1484
+                    st->codec->channel_layout = mask;
1485
+            }
1486
+            av_dict_free(&dict);
1487
+        }
1488
+
1489
+        p    += block_size;
1490
+        size -= block_size;
1491
+    }
1492
+
1457 1493
     return 0;
1458 1494
 }
1459 1495
 
... ...
@@ -122,7 +122,8 @@ extern const struct ogg_codec ff_speex_codec;
122 122
 extern const struct ogg_codec ff_theora_codec;
123 123
 extern const struct ogg_codec ff_vorbis_codec;
124 124
 
125
-int ff_vorbis_comment(AVFormatContext *ms, AVDictionary **m, const uint8_t *buf, int size);
125
+int ff_vorbis_comment(AVFormatContext *ms, AVDictionary **m,
126
+                      const uint8_t *buf, int size, int parse_picture);
126 127
 
127 128
 static inline int
128 129
 ogg_find_stream (struct ogg * ogg, int serial)
... ...
@@ -81,7 +81,7 @@ static int celt_header(AVFormatContext *s, int idx)
81 81
     } else if (priv && priv->extra_headers_left) {
82 82
         /* Extra headers (vorbiscomment) */
83 83
 
84
-        ff_vorbis_comment(s, &st->metadata, p, os->psize);
84
+        ff_vorbis_comment(s, &st->metadata, p, os->psize, 1);
85 85
         priv->extra_headers_left--;
86 86
         return 1;
87 87
     } else {
... ...
@@ -69,7 +69,7 @@ flac_header (AVFormatContext * s, int idx)
69 69
 
70 70
         avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate);
71 71
     } else if (mdt == FLAC_METADATA_TYPE_VORBIS_COMMENT) {
72
-        ff_vorbis_comment (s, &st->metadata, os->buf + os->pstart + 4, os->psize - 4);
72
+        ff_vorbis_comment (s, &st->metadata, os->buf + os->pstart + 4, os->psize - 4, 1);
73 73
     }
74 74
 
75 75
     return 1;
... ...
@@ -97,7 +97,7 @@ ogm_header(AVFormatContext *s, int idx)
97 97
     } else if (bytestream2_peek_byte(&p) == 3) {
98 98
         bytestream2_skip(&p, 7);
99 99
         if (bytestream2_get_bytes_left(&p) > 1)
100
-            ff_vorbis_comment(s, &st->metadata, p.buffer, bytestream2_get_bytes_left(&p) - 1);
100
+            ff_vorbis_comment(s, &st->metadata, p.buffer, bytestream2_get_bytes_left(&p) - 1, 1);
101 101
     }
102 102
 
103 103
     return 1;
... ...
@@ -74,7 +74,7 @@ static int opus_header(AVFormatContext *avf, int idx)
74 74
     if (priv->need_comments) {
75 75
         if (os->psize < 8 || memcmp(packet, "OpusTags", 8))
76 76
             return AVERROR_INVALIDDATA;
77
-        ff_vorbis_comment(avf, &st->metadata, packet + 8, os->psize - 8);
77
+        ff_vorbis_comment(avf, &st->metadata, packet + 8, os->psize - 8, 1);
78 78
         priv->need_comments--;
79 79
         return 1;
80 80
     }
... ...
@@ -79,7 +79,7 @@ static int speex_header(AVFormatContext *s, int idx) {
79 79
 
80 80
         avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate);
81 81
     } else
82
-        ff_vorbis_comment(s, &st->metadata, p, os->psize);
82
+        ff_vorbis_comment(s, &st->metadata, p, os->psize, 1);
83 83
 
84 84
     spxp->seq++;
85 85
     return 1;
... ...
@@ -116,7 +116,7 @@ static int theora_header(AVFormatContext *s, int idx)
116 116
     }
117 117
     break;
118 118
     case 0x81:
119
-        ff_vorbis_comment(s, &st->metadata, os->buf + os->pstart + 7, os->psize - 7);
119
+        ff_vorbis_comment(s, &st->metadata, os->buf + os->pstart + 7, os->psize - 7, 1);
120 120
     case 0x82:
121 121
         if (!thp->version)
122 122
             return AVERROR_INVALIDDATA;
... ...
@@ -72,7 +72,8 @@ static int ogm_chapter(AVFormatContext *as, uint8_t *key, uint8_t *val)
72 72
 }
73 73
 
74 74
 int ff_vorbis_comment(AVFormatContext *as, AVDictionary **m,
75
-                      const uint8_t *buf, int size)
75
+                      const uint8_t *buf, int size,
76
+                      int parse_picture)
76 77
 {
77 78
     const uint8_t *p   = buf;
78 79
     const uint8_t *end = buf + size;
... ...
@@ -137,7 +138,7 @@ int ff_vorbis_comment(AVFormatContext *as, AVDictionary **m,
137 137
              * 'METADATA_BLOCK_PICTURE'. This is the preferred and
138 138
              * recommended way of embedding cover art within VorbisComments."
139 139
              */
140
-            if (!strcmp(tt, "METADATA_BLOCK_PICTURE")) {
140
+            if (!strcmp(tt, "METADATA_BLOCK_PICTURE") && parse_picture) {
141 141
                 int ret;
142 142
                 char *pict = av_malloc(vl);
143 143
 
... ...
@@ -305,7 +306,7 @@ static int vorbis_header(AVFormatContext *s, int idx)
305 305
     } else if (os->buf[os->pstart] == 3) {
306 306
         if (os->psize > 8 &&
307 307
             ff_vorbis_comment(s, &st->metadata, os->buf + os->pstart + 7,
308
-                              os->psize - 8) >= 0) {
308
+                              os->psize - 8, 1) >= 0) {
309 309
             unsigned new_len;
310 310
 
311 311
             int ret = ff_replaygain_export(st, st->metadata);