diff options
author | Andreas Rheinhardt <andreas.rheinhardt@gmail.com> | 2020-04-04 15:35:48 +0200 |
---|---|---|
committer | Andreas Rheinhardt <andreas.rheinhardt@gmail.com> | 2020-04-13 08:08:42 +0200 |
commit | bd7dea3f4f185a32966d7542837030d843c8518d (patch) | |
tree | ac6cf675b9983f1f3a83b3db08a3df7a953dc155 /libavformat | |
parent | 3c3ad1deb0826e14697858e91985ff113d6ace23 (diff) |
avformat/matroskaenc: Don't waste bytes writing durations
Tags in the Matroska file format can be summarized as follows: There is
a level 1-element called Tags containing one or many Tag elements each
of which in turn contain a Targets element and one or many SimpleTags.
Each SimpleTag roughly corresponds to a single key-value pair similar to
an AVDictionaryEntry. The Targets meanwhile contains information to what
the metadata contained in the SimpleTags contained in the containing Tag
applies (i.e. to the file as a whole or to an individual track).
The Matroska muxer writes such metadata. It puts the metadata of every
stream into a Tag whose Targets makes it point to the corresponding
track. And if the output is seekable, then it also adds another Tag for
each track whose Targets corresponds to the track and where it reserves
space in a SimpleTag to write the duration at the end of the muxing
process into.
Yet there is no reason to write two Tag elements for a track and a few
bytes (typically 24 bytes per track) can be saved by adding the duration
SimpleTag to the other Tag of the same track (if it exists).
FATE has been updated because the output files changed. (Tests that
write to unseekable output (pipes) needn't be updated (no duration tag
has ever been written for them) and the same applies to tests without
further metadata.)
Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@gmail.com>
Diffstat (limited to 'libavformat')
-rw-r--r-- | libavformat/matroskaenc.c | 48 |
1 files changed, 21 insertions, 27 deletions
diff --git a/libavformat/matroskaenc.c b/libavformat/matroskaenc.c index 39da238ae0..58e89b232e 100644 --- a/libavformat/matroskaenc.c +++ b/libavformat/matroskaenc.c @@ -1517,14 +1517,14 @@ static int mkv_check_tag_name(const char *name, uint32_t elementid) } static int mkv_write_tag(AVFormatContext *s, AVDictionary *m, uint32_t elementid, - uint64_t uid) + uint64_t uid, ebml_master *tag) { MatroskaMuxContext *mkv = s->priv_data; - ebml_master tag; + ebml_master tag2; int ret; AVDictionaryEntry *t = NULL; - ret = mkv_write_tag_targets(s, elementid, uid, &tag); + ret = mkv_write_tag_targets(s, elementid, uid, tag ? tag : &tag2); if (ret < 0) return ret; @@ -1536,7 +1536,9 @@ static int mkv_write_tag(AVFormatContext *s, AVDictionary *m, uint32_t elementid } } - end_ebml_master(mkv->tags_bc, tag); + if (!tag) + end_ebml_master(mkv->tags_bc, tag2); + return 0; } @@ -1554,53 +1556,43 @@ static int mkv_check_tag(AVDictionary *m, uint32_t elementid) static int mkv_write_tags(AVFormatContext *s) { MatroskaMuxContext *mkv = s->priv_data; + ebml_master tag, *tagp; int i, ret; ff_metadata_conv_ctx(s, ff_mkv_metadata_conv, NULL); if (mkv_check_tag(s->metadata, 0)) { - ret = mkv_write_tag(s, s->metadata, 0, 0); + ret = mkv_write_tag(s, s->metadata, 0, 0, NULL); if (ret < 0) return ret; } + tagp = (s->pb->seekable & AVIO_SEEKABLE_NORMAL) && !mkv->is_live ? &tag : NULL; for (i = 0; i < s->nb_streams; i++) { AVStream *st = s->streams[i]; if (st->codecpar->codec_type == AVMEDIA_TYPE_ATTACHMENT) continue; - if (!mkv_check_tag(st->metadata, MATROSKA_ID_TAGTARGETS_TRACKUID)) + if (!tagp && !mkv_check_tag(st->metadata, MATROSKA_ID_TAGTARGETS_TRACKUID)) continue; - ret = mkv_write_tag(s, st->metadata, MATROSKA_ID_TAGTARGETS_TRACKUID, i + 1); + ret = mkv_write_tag(s, st->metadata, MATROSKA_ID_TAGTARGETS_TRACKUID, + i + 1, tagp); if (ret < 0) return ret; - } - - if ((s->pb->seekable & AVIO_SEEKABLE_NORMAL) && !mkv->is_live) { - for (i = 0; i < s->nb_streams; i++) { - AVIOContext *pb; - AVStream *st = s->streams[i]; - ebml_master tag_target; - ebml_master tag; - if (st->codecpar->codec_type == AVMEDIA_TYPE_ATTACHMENT) - continue; - - ret = mkv_write_tag_targets(s, MATROSKA_ID_TAGTARGETS_TRACKUID, - i + 1, &tag_target); - if (ret < 0) - return ret; - pb = mkv->tags_bc; + if (tagp) { + AVIOContext *pb = mkv->tags_bc; + ebml_master simpletag; - tag = start_ebml_master(pb, MATROSKA_ID_SIMPLETAG, 0); + simpletag = start_ebml_master(pb, MATROSKA_ID_SIMPLETAG, 0); put_ebml_string(pb, MATROSKA_ID_TAGNAME, "DURATION"); mkv->tracks[i].duration_offset = avio_tell(pb); // Reserve space to write duration as a 20-byte string. // 2 (ebml id) + 1 (data size) + 20 (data) put_ebml_void(pb, 23); + end_ebml_master(pb, simpletag); end_ebml_master(pb, tag); - end_ebml_master(pb, tag_target); } } @@ -1612,7 +1604,8 @@ static int mkv_write_tags(AVFormatContext *s) continue; ret = mkv_write_tag(s, ch->metadata, MATROSKA_ID_TAGTARGETS_CHAPTERUID, - (uint32_t)ch->id + (uint64_t)mkv->chapter_id_offset); + (uint32_t)ch->id + (uint64_t)mkv->chapter_id_offset, + NULL); if (ret < 0) return ret; } @@ -1626,7 +1619,8 @@ static int mkv_write_tags(AVFormatContext *s) if (!mkv_check_tag(st->metadata, MATROSKA_ID_TAGTARGETS_ATTACHUID)) continue; - ret = mkv_write_tag(s, st->metadata, MATROSKA_ID_TAGTARGETS_ATTACHUID, attachment->fileuid); + ret = mkv_write_tag(s, st->metadata, MATROSKA_ID_TAGTARGETS_ATTACHUID, + attachment->fileuid, NULL); if (ret < 0) return ret; } |