From 650e17d88b63b5aca6e0a43483e89e64b0f7d2dd Mon Sep 17 00:00:00 2001 From: James Almer Date: Mon, 3 Oct 2016 19:27:30 -0300 Subject: [PATCH] avformat/matroskaenc: write a CRC32 element on Tags Implements part of ticket #4347 Tested-by: Dave Rice Tested-by: Jerome Martinez Reviewed-by: Michael Niedermayer Signed-off-by: James Almer --- 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 e36f7e22cb..24deec8497 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; @@ -1359,6 +1361,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; @@ -1367,14 +1370,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; } @@ -1392,6 +1396,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; @@ -1402,13 +1407,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; } @@ -1426,13 +1431,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; } @@ -1442,26 +1446,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); } } @@ -1471,12 +1477,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; } @@ -2252,16 +2262,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 77c1cd4b86..bdbe956ebe 100644 --- a/tests/ref/fate/rgb24-mkv +++ b/tests/ref/fate/rgb24-mkv @@ -1,5 +1,5 @@ -d8fbc09b7061d57eb8efa807d1462c41 *tests/data/fate/rgb24-mkv.matroska -58345 tests/data/fate/rgb24-mkv.matroska +cc45779160972ebab95412ba75f35d4c *tests/data/fate/rgb24-mkv.matroska +58351 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 19907155d4..cde5cf98b7 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 5a3293f672..8c47f86a84 100644 --- a/tests/ref/lavf/mkv +++ b/tests/ref/lavf/mkv @@ -1,6 +1,6 @@ -c7c1e2e55e8f04708deb6a552ae59fda *./tests/data/lavf/lavf.mkv -472917 ./tests/data/lavf/lavf.mkv +af35b4e2fdea37a8874dbfbf7a691011 *./tests/data/lavf/lavf.mkv +472923 ./tests/data/lavf/lavf.mkv ./tests/data/lavf/lavf.mkv CRC=0xec6c3c68 -82cd3b90ed54ede177d1a7e6c96ee801 *./tests/data/lavf/lavf.mkv -320587 ./tests/data/lavf/lavf.mkv +9daaedc22e6580cf6c7364e486fd1ee0 *./tests/data/lavf/lavf.mkv +320593 ./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 7bd1586112..26df54535b 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