Implements part of ticket #4347 Signed-off-by: James Almer <jamr...@gmail.com> --- This one got messy because we update Duration tags at the end of the muxing process, and the entire master needs to be finalized before the CRC32 can be calculated.
libavformat/matroskaenc.c | 58 +++++++++++++++++++++++++++++------------------ tests/ref/fate/rgb24-mkv | 4 ++-- tests/ref/lavf/mka | 4 ++-- tests/ref/lavf/mkv | 8 +++---- tests/ref/seek/lavf-mkv | 44 +++++++++++++++++------------------ 5 files changed, 66 insertions(+), 52 deletions(-) diff --git a/libavformat/matroskaenc.c b/libavformat/matroskaenc.c index c63ecdd..4dfcc55 100644 --- a/libavformat/matroskaenc.c +++ b/libavformat/matroskaenc.c @@ -107,6 +107,8 @@ typedef struct MatroskaMuxContext { const AVClass *class; int mode; AVIOContext *dyn_bc; + AVIOContext *tags_bc; + ebml_master tags; ebml_master segment; int64_t segment_offset; ebml_master cluster; @@ -1343,6 +1345,7 @@ static int mkv_write_tag_targets(AVFormatContext *s, unsigned int elementid, unsigned int uid, ebml_master *tags, ebml_master* tag) { + AVIOContext *pb; MatroskaMuxContext *mkv = s->priv_data; ebml_master targets; int ret; @@ -1351,14 +1354,15 @@ static int mkv_write_tag_targets(AVFormatContext *s, ret = mkv_add_seekhead_entry(mkv->main_seekhead, MATROSKA_ID_TAGS, avio_tell(s->pb)); if (ret < 0) return ret; - *tags = start_ebml_master(s->pb, MATROSKA_ID_TAGS, 0); + start_ebml_master_crc32(s->pb, &mkv->tags_bc, tags, MATROSKA_ID_TAGS, 0); } + pb = mkv->tags_bc; - *tag = start_ebml_master(s->pb, MATROSKA_ID_TAG, 0); - targets = start_ebml_master(s->pb, MATROSKA_ID_TAGTARGETS, 0); + *tag = start_ebml_master(pb, MATROSKA_ID_TAG, 0); + targets = start_ebml_master(pb, MATROSKA_ID_TAGTARGETS, 0); if (elementid) - put_ebml_uint(s->pb, elementid, uid); - end_ebml_master(s->pb, targets); + put_ebml_uint(pb, elementid, uid); + end_ebml_master(pb, targets); return 0; } @@ -1376,6 +1380,7 @@ static int mkv_check_tag_name(const char *name, unsigned int elementid) static int mkv_write_tag(AVFormatContext *s, AVDictionary *m, unsigned int elementid, unsigned int uid, ebml_master *tags) { + MatroskaMuxContext *mkv = s->priv_data; ebml_master tag; int ret; AVDictionaryEntry *t = NULL; @@ -1386,13 +1391,13 @@ static int mkv_write_tag(AVFormatContext *s, AVDictionary *m, unsigned int eleme while ((t = av_dict_get(m, "", t, AV_DICT_IGNORE_SUFFIX))) { if (mkv_check_tag_name(t->key, elementid)) { - ret = mkv_write_simpletag(s->pb, t); + ret = mkv_write_simpletag(mkv->tags_bc, t); if (ret < 0) return ret; } } - end_ebml_master(s->pb, tag); + end_ebml_master(mkv->tags_bc, tag); return 0; } @@ -1410,13 +1415,12 @@ static int mkv_check_tag(AVDictionary *m, unsigned int elementid) static int mkv_write_tags(AVFormatContext *s) { MatroskaMuxContext *mkv = s->priv_data; - ebml_master tags = {0}; 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, &tags); + ret = mkv_write_tag(s, s->metadata, 0, 0, &mkv->tags); if (ret < 0) return ret; } @@ -1426,26 +1430,28 @@ static int mkv_write_tags(AVFormatContext *s) if (!mkv_check_tag(st->metadata, MATROSKA_ID_TAGTARGETS_TRACKUID)) continue; - ret = mkv_write_tag(s, st->metadata, MATROSKA_ID_TAGTARGETS_TRACKUID, i + 1, &tags); + ret = mkv_write_tag(s, st->metadata, MATROSKA_ID_TAGTARGETS_TRACKUID, i + 1, &mkv->tags); if (ret < 0) return ret; } if (s->pb->seekable && !mkv->is_live) { for (i = 0; i < s->nb_streams; i++) { + AVIOContext *pb; ebml_master tag_target; ebml_master tag; - mkv_write_tag_targets(s, MATROSKA_ID_TAGTARGETS_TRACKUID, i + 1, &tags, &tag_target); + mkv_write_tag_targets(s, MATROSKA_ID_TAGTARGETS_TRACKUID, i + 1, &mkv->tags, &tag_target); + pb = mkv->tags_bc; - tag = start_ebml_master(s->pb, MATROSKA_ID_SIMPLETAG, 0); - put_ebml_string(s->pb, MATROSKA_ID_TAGNAME, "DURATION"); - mkv->stream_duration_offsets[i] = avio_tell(s->pb); + tag = start_ebml_master(pb, MATROSKA_ID_SIMPLETAG, 0); + put_ebml_string(pb, MATROSKA_ID_TAGNAME, "DURATION"); + mkv->stream_duration_offsets[i] = avio_tell(pb); // Reserve space to write duration as a 20-byte string. // 2 (ebml id) + 1 (data size) + 20 (data) - put_ebml_void(s->pb, 23); - end_ebml_master(s->pb, tag); - end_ebml_master(s->pb, tag_target); + put_ebml_void(pb, 23); + end_ebml_master(pb, tag); + end_ebml_master(pb, tag_target); } } @@ -1455,12 +1461,16 @@ static int mkv_write_tags(AVFormatContext *s) if (!mkv_check_tag(ch->metadata, MATROSKA_ID_TAGTARGETS_CHAPTERUID)) continue; - ret = mkv_write_tag(s, ch->metadata, MATROSKA_ID_TAGTARGETS_CHAPTERUID, ch->id + mkv->chapter_id_offset, &tags); + ret = mkv_write_tag(s, ch->metadata, MATROSKA_ID_TAGTARGETS_CHAPTERUID, ch->id + mkv->chapter_id_offset, &mkv->tags); if (ret < 0) return ret; } - if (tags.pos) - end_ebml_master(s->pb, tags); + if (mkv->tags.pos) { + if (s->pb->seekable && !mkv->is_live) + put_ebml_void(s->pb, avio_tell(mkv->tags_bc) + ((mkv->mode != MODE_WEBM) ? 2 /* ebml id + data size */ + 4 /* CRC32 */ : 0)); + else + end_ebml_master_crc32(s->pb, &mkv->tags_bc, mkv, mkv->tags); + } return 0; } @@ -2236,16 +2246,20 @@ static int mkv_write_trailer(AVFormatContext *s) mkv->stream_durations[i]); if (!mkv->is_live && mkv->stream_duration_offsets[i] > 0) { - avio_seek(pb, mkv->stream_duration_offsets[i], SEEK_SET); + avio_seek(mkv->tags_bc, mkv->stream_duration_offsets[i], SEEK_SET); snprintf(duration_string, 20, "%02d:%02d:%012.9f", (int) duration_sec / 3600, ((int) duration_sec / 60) % 60, fmod(duration_sec, 60)); - put_ebml_binary(pb, MATROSKA_ID_TAGSTRING, duration_string, 20); + put_ebml_binary(mkv->tags_bc, MATROSKA_ID_TAGSTRING, duration_string, 20); } } } + if (mkv->tags.pos && !mkv->is_live) { + avio_seek(pb, mkv->tags.pos, SEEK_SET); + end_ebml_master_crc32(pb, &mkv->tags_bc, mkv, mkv->tags); + } avio_seek(pb, currentpos, SEEK_SET); } diff --git a/tests/ref/fate/rgb24-mkv b/tests/ref/fate/rgb24-mkv index 01b069c..3cd1887 100644 --- a/tests/ref/fate/rgb24-mkv +++ b/tests/ref/fate/rgb24-mkv @@ -1,5 +1,5 @@ -f2ec884f82ecf5754afc0c9a2babe4aa *tests/data/fate/rgb24-mkv.matroska -58352 tests/data/fate/rgb24-mkv.matroska +cddd0f9c0efc6592bd3026b8c47471c3 *tests/data/fate/rgb24-mkv.matroska +58358 tests/data/fate/rgb24-mkv.matroska #tb 0: 1/10 #media_type 0: video #codec_id 0: rawvideo diff --git a/tests/ref/lavf/mka b/tests/ref/lavf/mka index 1990715..cde5cf9 100644 --- a/tests/ref/lavf/mka +++ b/tests/ref/lavf/mka @@ -1,3 +1,3 @@ -927a5d1e7837735271f57b329f1c9d7a *./tests/data/lavf/lavf.mka -43672 ./tests/data/lavf/lavf.mka +afd0c76b5fd8ca5ee47d12af7f92d024 *./tests/data/lavf/lavf.mka +43678 ./tests/data/lavf/lavf.mka ./tests/data/lavf/lavf.mka CRC=0x3a1da17e diff --git a/tests/ref/lavf/mkv b/tests/ref/lavf/mkv index 951feac..63ed7da 100644 --- a/tests/ref/lavf/mkv +++ b/tests/ref/lavf/mkv @@ -1,6 +1,6 @@ -b3599e3229821a84116b4f03f324a08b *./tests/data/lavf/lavf.mkv -472938 ./tests/data/lavf/lavf.mkv +aa0fabb3a1564adbdbd27310b1643ca3 *./tests/data/lavf/lavf.mkv +472944 ./tests/data/lavf/lavf.mkv ./tests/data/lavf/lavf.mkv CRC=0xec6c3c68 -c56b90945e6e14a9b4b7f1ab94e3ad28 *./tests/data/lavf/lavf.mkv -320608 ./tests/data/lavf/lavf.mkv +85f86c9d5641c2344b9b389f38fad890 *./tests/data/lavf/lavf.mkv +320614 ./tests/data/lavf/lavf.mkv ./tests/data/lavf/lavf.mkv CRC=0xec6c3c68 diff --git a/tests/ref/seek/lavf-mkv b/tests/ref/seek/lavf-mkv index 7bd1586..26df545 100644 --- a/tests/ref/seek/lavf-mkv +++ b/tests/ref/seek/lavf-mkv @@ -1,48 +1,48 @@ -ret: 0 st: 1 flags:1 dts: 0.000000 pts: 0.000000 pos: 818 size: 208 +ret: 0 st: 1 flags:1 dts: 0.000000 pts: 0.000000 pos: 824 size: 208 ret: 0 st:-1 flags:0 ts:-1.000000 -ret: 0 st: 0 flags:1 dts: 0.011000 pts: 0.011000 pos: 1034 size: 27837 +ret: 0 st: 0 flags:1 dts: 0.011000 pts: 0.011000 pos: 1040 size: 27837 ret: 0 st:-1 flags:1 ts: 1.894167 -ret: 0 st: 0 flags:1 dts: 0.971000 pts: 0.971000 pos: 292460 size: 27834 +ret: 0 st: 0 flags:1 dts: 0.971000 pts: 0.971000 pos: 292466 size: 27834 ret: 0 st: 0 flags:0 ts: 0.788000 -ret: 0 st: 0 flags:1 dts: 0.971000 pts: 0.971000 pos: 292460 size: 27834 +ret: 0 st: 0 flags:1 dts: 0.971000 pts: 0.971000 pos: 292466 size: 27834 ret: 0 st: 0 flags:1 ts:-0.317000 -ret: 0 st: 0 flags:1 dts: 0.011000 pts: 0.011000 pos: 1034 size: 27837 +ret: 0 st: 0 flags:1 dts: 0.011000 pts: 0.011000 pos: 1040 size: 27837 ret:-1 st: 1 flags:0 ts: 2.577000 ret: 0 st: 1 flags:1 ts: 1.471000 -ret: 0 st: 1 flags:1 dts: 0.993000 pts: 0.993000 pos: 320301 size: 209 +ret: 0 st: 1 flags:1 dts: 0.993000 pts: 0.993000 pos: 320307 size: 209 ret: 0 st:-1 flags:0 ts: 0.365002 -ret: 0 st: 0 flags:1 dts: 0.491000 pts: 0.491000 pos: 147007 size: 27925 +ret: 0 st: 0 flags:1 dts: 0.491000 pts: 0.491000 pos: 147013 size: 27925 ret: 0 st:-1 flags:1 ts:-0.740831 -ret: 0 st: 0 flags:1 dts: 0.011000 pts: 0.011000 pos: 1034 size: 27837 +ret: 0 st: 0 flags:1 dts: 0.011000 pts: 0.011000 pos: 1040 size: 27837 ret:-1 st: 0 flags:0 ts: 2.153000 ret: 0 st: 0 flags:1 ts: 1.048000 -ret: 0 st: 0 flags:1 dts: 0.971000 pts: 0.971000 pos: 292460 size: 27834 +ret: 0 st: 0 flags:1 dts: 0.971000 pts: 0.971000 pos: 292466 size: 27834 ret: 0 st: 1 flags:0 ts:-0.058000 -ret: 0 st: 1 flags:1 dts: 0.000000 pts: 0.000000 pos: 818 size: 208 +ret: 0 st: 1 flags:1 dts: 0.000000 pts: 0.000000 pos: 824 size: 208 ret: 0 st: 1 flags:1 ts: 2.836000 -ret: 0 st: 1 flags:1 dts: 0.993000 pts: 0.993000 pos: 320301 size: 209 +ret: 0 st: 1 flags:1 dts: 0.993000 pts: 0.993000 pos: 320307 size: 209 ret:-1 st:-1 flags:0 ts: 1.730004 ret: 0 st:-1 flags:1 ts: 0.624171 -ret: 0 st: 0 flags:1 dts: 0.491000 pts: 0.491000 pos: 147007 size: 27925 +ret: 0 st: 0 flags:1 dts: 0.491000 pts: 0.491000 pos: 147013 size: 27925 ret: 0 st: 0 flags:0 ts:-0.482000 -ret: 0 st: 0 flags:1 dts: 0.011000 pts: 0.011000 pos: 1034 size: 27837 +ret: 0 st: 0 flags:1 dts: 0.011000 pts: 0.011000 pos: 1040 size: 27837 ret: 0 st: 0 flags:1 ts: 2.413000 -ret: 0 st: 0 flags:1 dts: 0.971000 pts: 0.971000 pos: 292460 size: 27834 +ret: 0 st: 0 flags:1 dts: 0.971000 pts: 0.971000 pos: 292466 size: 27834 ret:-1 st: 1 flags:0 ts: 1.307000 ret: 0 st: 1 flags:1 ts: 0.201000 -ret: 0 st: 1 flags:1 dts: 0.000000 pts: 0.000000 pos: 818 size: 208 +ret: 0 st: 1 flags:1 dts: 0.000000 pts: 0.000000 pos: 824 size: 208 ret: 0 st:-1 flags:0 ts:-0.904994 -ret: 0 st: 0 flags:1 dts: 0.011000 pts: 0.011000 pos: 1034 size: 27837 +ret: 0 st: 0 flags:1 dts: 0.011000 pts: 0.011000 pos: 1040 size: 27837 ret: 0 st:-1 flags:1 ts: 1.989173 -ret: 0 st: 0 flags:1 dts: 0.971000 pts: 0.971000 pos: 292460 size: 27834 +ret: 0 st: 0 flags:1 dts: 0.971000 pts: 0.971000 pos: 292466 size: 27834 ret: 0 st: 0 flags:0 ts: 0.883000 -ret: 0 st: 0 flags:1 dts: 0.971000 pts: 0.971000 pos: 292460 size: 27834 +ret: 0 st: 0 flags:1 dts: 0.971000 pts: 0.971000 pos: 292466 size: 27834 ret: 0 st: 0 flags:1 ts:-0.222000 -ret: 0 st: 0 flags:1 dts: 0.011000 pts: 0.011000 pos: 1034 size: 27837 +ret: 0 st: 0 flags:1 dts: 0.011000 pts: 0.011000 pos: 1040 size: 27837 ret:-1 st: 1 flags:0 ts: 2.672000 ret: 0 st: 1 flags:1 ts: 1.566000 -ret: 0 st: 1 flags:1 dts: 0.993000 pts: 0.993000 pos: 320301 size: 209 +ret: 0 st: 1 flags:1 dts: 0.993000 pts: 0.993000 pos: 320307 size: 209 ret: 0 st:-1 flags:0 ts: 0.460008 -ret: 0 st: 0 flags:1 dts: 0.491000 pts: 0.491000 pos: 147007 size: 27925 +ret: 0 st: 0 flags:1 dts: 0.491000 pts: 0.491000 pos: 147013 size: 27925 ret: 0 st:-1 flags:1 ts:-0.645825 -ret: 0 st: 0 flags:1 dts: 0.011000 pts: 0.011000 pos: 1034 size: 27837 +ret: 0 st: 0 flags:1 dts: 0.011000 pts: 0.011000 pos: 1040 size: 27837 -- 2.9.1 _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel