@@ -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);
}
@@ -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
@@ -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
@@ -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
@@ -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
Implements part of ticket #4347 Signed-off-by: James Almer <jamrial@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(-)