[FFmpeg-devel] [PATCH 10/11] avformat/matroskaenc: write a CRC32 element on Tags

James Almer jamrial at gmail.com
Tue Oct 4 02:37:06 EEST 2016


Implements part of ticket #4347

Signed-off-by: James Almer <jamrial at 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



More information about the ffmpeg-devel mailing list