It is commonly stored in a vorbiscomment block in codec private data.tags/n2.3
| @@ -166,7 +166,8 @@ OBJS-$(CONFIG_LXF_DEMUXER) += lxfdec.o | |||||
| OBJS-$(CONFIG_M4V_DEMUXER) += m4vdec.o rawdec.o | OBJS-$(CONFIG_M4V_DEMUXER) += m4vdec.o rawdec.o | ||||
| OBJS-$(CONFIG_M4V_MUXER) += rawenc.o | OBJS-$(CONFIG_M4V_MUXER) += rawenc.o | ||||
| OBJS-$(CONFIG_MATROSKA_DEMUXER) += matroskadec.o matroska.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 \ | OBJS-$(CONFIG_MATROSKA_MUXER) += matroskaenc.o matroska.o \ | ||||
| isom.o avc.o hevc.o \ | isom.o avc.o hevc.o \ | ||||
| flacenc_header.o avlanguage.o wv.o | flacenc_header.o avlanguage.o wv.o | ||||
| @@ -141,7 +141,7 @@ static int flac_read_header(AVFormatContext *s) | |||||
| if (metadata_type == FLAC_METADATA_TYPE_VORBIS_COMMENT) { | if (metadata_type == FLAC_METADATA_TYPE_VORBIS_COMMENT) { | ||||
| AVDictionaryEntry *chmask; | 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"); | av_log(s, AV_LOG_WARNING, "error parsing VorbisComment metadata\n"); | ||||
| } | } | ||||
| @@ -55,6 +55,7 @@ | |||||
| #include "internal.h" | #include "internal.h" | ||||
| #include "isom.h" | #include "isom.h" | ||||
| #include "matroska.h" | #include "matroska.h" | ||||
| #include "oggdec.h" | |||||
| /* For ff_codec_get_id(). */ | /* For ff_codec_get_id(). */ | ||||
| #include "riff.h" | #include "riff.h" | ||||
| #include "rmsipr.h" | #include "rmsipr.h" | ||||
| @@ -1443,6 +1444,7 @@ static int matroska_parse_flac(AVFormatContext *s, | |||||
| MatroskaTrack *track, | MatroskaTrack *track, | ||||
| int *offset) | int *offset) | ||||
| { | { | ||||
| AVStream *st = track->stream; | |||||
| uint8_t *p = track->codec_priv.data; | uint8_t *p = track->codec_priv.data; | ||||
| int size = track->codec_priv.size; | int size = track->codec_priv.size; | ||||
| @@ -1454,6 +1456,42 @@ static int matroska_parse_flac(AVFormatContext *s, | |||||
| *offset = 8; | *offset = 8; | ||||
| track->codec_priv.size = 8 + FLAC_STREAMINFO_SIZE; | 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; | return 0; | ||||
| } | } | ||||
| @@ -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_theora_codec; | ||||
| extern const struct ogg_codec ff_vorbis_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 | static inline int | ||||
| ogg_find_stream (struct ogg * ogg, int serial) | ogg_find_stream (struct ogg * ogg, int serial) | ||||
| @@ -81,7 +81,7 @@ static int celt_header(AVFormatContext *s, int idx) | |||||
| } else if (priv && priv->extra_headers_left) { | } else if (priv && priv->extra_headers_left) { | ||||
| /* Extra headers (vorbiscomment) */ | /* 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--; | priv->extra_headers_left--; | ||||
| return 1; | return 1; | ||||
| } else { | } else { | ||||
| @@ -69,7 +69,7 @@ flac_header (AVFormatContext * s, int idx) | |||||
| avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate); | avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate); | ||||
| } else if (mdt == FLAC_METADATA_TYPE_VORBIS_COMMENT) { | } 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; | return 1; | ||||
| @@ -97,7 +97,7 @@ ogm_header(AVFormatContext *s, int idx) | |||||
| } else if (bytestream2_peek_byte(&p) == 3) { | } else if (bytestream2_peek_byte(&p) == 3) { | ||||
| bytestream2_skip(&p, 7); | bytestream2_skip(&p, 7); | ||||
| if (bytestream2_get_bytes_left(&p) > 1) | 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; | return 1; | ||||
| @@ -74,7 +74,7 @@ static int opus_header(AVFormatContext *avf, int idx) | |||||
| if (priv->need_comments) { | if (priv->need_comments) { | ||||
| if (os->psize < 8 || memcmp(packet, "OpusTags", 8)) | if (os->psize < 8 || memcmp(packet, "OpusTags", 8)) | ||||
| return AVERROR_INVALIDDATA; | 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--; | priv->need_comments--; | ||||
| return 1; | return 1; | ||||
| } | } | ||||
| @@ -79,7 +79,7 @@ static int speex_header(AVFormatContext *s, int idx) { | |||||
| avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate); | avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate); | ||||
| } else | } else | ||||
| ff_vorbis_comment(s, &st->metadata, p, os->psize); | |||||
| ff_vorbis_comment(s, &st->metadata, p, os->psize, 1); | |||||
| spxp->seq++; | spxp->seq++; | ||||
| return 1; | return 1; | ||||
| @@ -116,7 +116,7 @@ static int theora_header(AVFormatContext *s, int idx) | |||||
| } | } | ||||
| break; | break; | ||||
| case 0x81: | 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: | case 0x82: | ||||
| if (!thp->version) | if (!thp->version) | ||||
| return AVERROR_INVALIDDATA; | return AVERROR_INVALIDDATA; | ||||
| @@ -72,7 +72,8 @@ static int ogm_chapter(AVFormatContext *as, uint8_t *key, uint8_t *val) | |||||
| } | } | ||||
| int ff_vorbis_comment(AVFormatContext *as, AVDictionary **m, | 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 *p = buf; | ||||
| const uint8_t *end = buf + size; | 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 | * 'METADATA_BLOCK_PICTURE'. This is the preferred and | ||||
| * recommended way of embedding cover art within VorbisComments." | * recommended way of embedding cover art within VorbisComments." | ||||
| */ | */ | ||||
| if (!strcmp(tt, "METADATA_BLOCK_PICTURE")) { | |||||
| if (!strcmp(tt, "METADATA_BLOCK_PICTURE") && parse_picture) { | |||||
| int ret; | int ret; | ||||
| char *pict = av_malloc(vl); | char *pict = av_malloc(vl); | ||||
| @@ -305,7 +306,7 @@ static int vorbis_header(AVFormatContext *s, int idx) | |||||
| } else if (os->buf[os->pstart] == 3) { | } else if (os->buf[os->pstart] == 3) { | ||||
| if (os->psize > 8 && | if (os->psize > 8 && | ||||
| ff_vorbis_comment(s, &st->metadata, os->buf + os->pstart + 7, | ff_vorbis_comment(s, &st->metadata, os->buf + os->pstart + 7, | ||||
| os->psize - 8) >= 0) { | |||||
| os->psize - 8, 1) >= 0) { | |||||
| unsigned new_len; | unsigned new_len; | ||||
| int ret = ff_replaygain_export(st, st->metadata); | int ret = ff_replaygain_export(st, st->metadata); | ||||