From 9b75309c19b2eb7fb57263cfd81ad18691a7a633 Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Tue, 5 Oct 2010 09:40:43 +0000 Subject: matroskaenc: write metadata patch by Anton Khirnov anton _at_ khirnov _dot_ net Originally committed as revision 25341 to svn://svn.ffmpeg.org/ffmpeg/trunk --- libavformat/matroskaenc.c | 99 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) (limited to 'libavformat') diff --git a/libavformat/matroskaenc.c b/libavformat/matroskaenc.c index ba9bbd5..29fddce 100644 --- a/libavformat/matroskaenc.c +++ b/libavformat/matroskaenc.c @@ -25,6 +25,7 @@ #include "matroska.h" #include "avc.h" #include "flacenc.h" +#include "avlanguage.h" #include "libavutil/intreadwrite.h" #include "libavutil/random_seed.h" #include "libavutil/lfg.h" @@ -688,6 +689,99 @@ static int mkv_write_chapters(AVFormatContext *s) return 0; } +static void mkv_write_simpletag(ByteIOContext *pb, AVMetadataTag *t) +{ + uint8_t *key = av_strdup(t->key); + uint8_t *p = key; + const uint8_t *lang = NULL; + ebml_master tag; + + if ((p = strrchr(p, '-')) && + (lang = av_convert_lang_to(p + 1, AV_LANG_ISO639_2_BIBL))) + *p = 0; + + p = key; + while (*p) { + if (*p == ' ') + *p = '_'; + else if (*p >= 'a' && *p <= 'z') + *p -= 'a' - 'A'; + p++; + } + + tag = start_ebml_master(pb, MATROSKA_ID_SIMPLETAG, 0); + put_ebml_string(pb, MATROSKA_ID_TAGNAME, key); + if (lang) + put_ebml_string(pb, MATROSKA_ID_TAGLANG, lang); + put_ebml_string(pb, MATROSKA_ID_TAGSTRING, t->value); + end_ebml_master(pb, tag); + + av_freep(&key); +} + +static int mkv_write_tag(AVFormatContext *s, AVMetadata *m, unsigned int elementid, + unsigned int uid, ebml_master *tags) +{ + MatroskaMuxContext *mkv = s->priv_data; + ebml_master tag, targets; + AVMetadataTag *t = NULL; + int ret; + + if (!tags->pos) { + ret = mkv_add_seekhead_entry(mkv->main_seekhead, MATROSKA_ID_TAGS, url_ftell(s->pb)); + if (ret < 0) return ret; + + *tags = start_ebml_master(s->pb, MATROSKA_ID_TAGS, 0); + } + + tag = start_ebml_master(s->pb, MATROSKA_ID_TAG, 0); + targets = start_ebml_master(s->pb, MATROSKA_ID_TAGTARGETS, 0); + if (elementid) + put_ebml_uint(s->pb, elementid, uid); + end_ebml_master(s->pb, targets); + + while ((t = av_metadata_get(m, "", t, AV_METADATA_IGNORE_SUFFIX))) + mkv_write_simpletag(s->pb, t); + + end_ebml_master(s->pb, tag); + return 0; +} + +static int mkv_write_tags(AVFormatContext *s) +{ + ebml_master tags = {0}; + int i, ret; + + if (av_metadata_get(s->metadata, "", NULL, AV_METADATA_IGNORE_SUFFIX)) { + ret = mkv_write_tag(s, s->metadata, 0, 0, &tags); + if (ret < 0) return ret; + } + + for (i = 0; i < s->nb_streams; i++) { + AVStream *st = s->streams[i]; + + if (!av_metadata_get(st->metadata, "", 0, AV_METADATA_IGNORE_SUFFIX)) + continue; + + ret = mkv_write_tag(s, st->metadata, MATROSKA_ID_TAGTARGETS_TRACKUID, i + 1, &tags); + if (ret < 0) return ret; + } + + for (i = 0; i < s->nb_chapters; i++) { + AVChapter *ch = s->chapters[i]; + + if (!av_metadata_get(ch->metadata, "", NULL, AV_METADATA_IGNORE_SUFFIX)) + continue; + + ret = mkv_write_tag(s, ch->metadata, MATROSKA_ID_TAGTARGETS_CHAPTERUID, ch->id, &tags); + if (ret < 0) return ret; + } + + if (tags.pos) + end_ebml_master(s->pb, tags); + return 0; +} + static int mkv_write_header(AVFormatContext *s) { MatroskaMuxContext *mkv = s->priv_data; @@ -758,6 +852,9 @@ static int mkv_write_header(AVFormatContext *s) if (mkv->mode != MODE_WEBM) { ret = mkv_write_chapters(s); if (ret < 0) return ret; + + ret = mkv_write_tags(s); + if (ret < 0) return ret; } if (url_is_streamed(s->pb)) @@ -1089,6 +1186,7 @@ AVOutputFormat matroska_muxer = { .flags = AVFMT_GLOBALHEADER | AVFMT_VARIABLE_FPS, .codec_tag = (const AVCodecTag* const []){ff_codec_bmp_tags, ff_codec_wav_tags, 0}, .subtitle_codec = CODEC_ID_TEXT, + .metadata_conv = ff_mkv_metadata_conv, }; #endif @@ -1122,5 +1220,6 @@ AVOutputFormat matroska_audio_muxer = { mkv_write_trailer, .flags = AVFMT_GLOBALHEADER, .codec_tag = (const AVCodecTag* const []){ff_codec_wav_tags, 0}, + .metadata_conv = ff_mkv_metadata_conv, }; #endif -- cgit v1.1