[FFmpeg-cvslog] avformat/matroskaenc: Avoid seeks when writing EBML header

Andreas Rheinhardt git at videolan.org
Wed Jan 19 13:54:28 EET 2022


ffmpeg | branch: master | Andreas Rheinhardt <andreas.rheinhardt at outlook.com> | Fri Jan 14 01:18:24 2022 +0100| [6b1968e939472125f97947fe62a534364212f573] | committer: Andreas Rheinhardt

avformat/matroskaenc: Avoid seeks when writing EBML header

Using start/end_ebml_master() to write an EBML Master element
uses seeks under the hood. This does not work if the output is
unseekable with the AVIOContext's buffer being very small
(the size of the currently written Matroska EBML header is 40)
or with the AVIOContext being in direct mode, because then
this seek can't be performed in the AVIOContext's buffer.
So using an approach that does not rely on seeking at all
is preferable; this is achieved by switching to EbmlWriter.

Also factor writing the EBML header out into a function of its own.

Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt at outlook.com>

> http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=6b1968e939472125f97947fe62a534364212f573
---

 libavformat/matroskaenc.c | 39 ++++++++++++++++++++++++---------------
 1 file changed, 24 insertions(+), 15 deletions(-)

diff --git a/libavformat/matroskaenc.c b/libavformat/matroskaenc.c
index 53016d34ec..f3c0dde5c2 100644
--- a/libavformat/matroskaenc.c
+++ b/libavformat/matroskaenc.c
@@ -214,10 +214,6 @@ typedef struct MatroskaMuxContext {
     uint32_t            segment_uid[4];
 } MatroskaMuxContext;
 
-/** 2 bytes * 7 for EBML IDs, 7 1-byte EBML lengths, 6 1-byte uint,
- * 8 byte for "matroska" doctype string */
-#define MAX_EBML_HEADER_SIZE 35
-
 /** 2 bytes * 3 for EBML IDs, 3 1-byte EBML lengths, 8 bytes for 64 bit
  * offset, 4 bytes for target EBML ID */
 #define MAX_SEEKENTRY_SIZE 21
@@ -464,6 +460,13 @@ static void ebml_writer_add_uid(EbmlWriter *writer, uint32_t id,
     elem->priv.uint = val;
 }
 
+static void ebml_writer_add_uint(EbmlWriter *writer, uint32_t id,
+                                 uint64_t val)
+{
+    EbmlElement *elem = ebml_writer_add(writer, id, EBML_UINT);
+    elem->priv.uint = val;
+}
+
 static int ebml_writer_str_len(EbmlElement *elem)
 {
     size_t len = strlen(elem->priv.str);
@@ -2115,11 +2118,26 @@ static int64_t get_metadata_duration(AVFormatContext *s)
     return max;
 }
 
+static void ebml_write_header(AVIOContext *pb,
+                              const char *doctype, int version)
+{
+    EBML_WRITER(8);
+    ebml_writer_open_master(&writer, EBML_ID_HEADER);
+    ebml_writer_add_uint  (&writer, EBML_ID_EBMLVERSION,              1);
+    ebml_writer_add_uint  (&writer, EBML_ID_EBMLREADVERSION,          1);
+    ebml_writer_add_uint  (&writer, EBML_ID_EBMLMAXIDLENGTH,          4);
+    ebml_writer_add_uint  (&writer, EBML_ID_EBMLMAXSIZELENGTH,        8);
+    ebml_writer_add_string(&writer, EBML_ID_DOCTYPE,            doctype);
+    ebml_writer_add_uint  (&writer, EBML_ID_DOCTYPEVERSION,     version);
+    ebml_writer_add_uint  (&writer, EBML_ID_DOCTYPEREADVERSION,       2);
+    /* The size is bounded, so no need to check this. */
+    ebml_writer_write(&writer, pb);
+}
+
 static int mkv_write_header(AVFormatContext *s)
 {
     MatroskaMuxContext *mkv = s->priv_data;
     AVIOContext *pb = s->pb;
-    ebml_master ebml_header;
     const AVDictionaryEntry *tag;
     int ret, i, version = 2;
     int64_t creation_time;
@@ -2136,16 +2154,7 @@ static int mkv_write_header(AVFormatContext *s)
             version = 4;
     }
 
-    ebml_header = start_ebml_master(pb, EBML_ID_HEADER, MAX_EBML_HEADER_SIZE);
-    put_ebml_uint  (pb, EBML_ID_EBMLVERSION       ,           1);
-    put_ebml_uint  (pb, EBML_ID_EBMLREADVERSION   ,           1);
-    put_ebml_uint  (pb, EBML_ID_EBMLMAXIDLENGTH   ,           4);
-    put_ebml_uint  (pb, EBML_ID_EBMLMAXSIZELENGTH ,           8);
-    put_ebml_string(pb, EBML_ID_DOCTYPE           , s->oformat->name);
-    put_ebml_uint  (pb, EBML_ID_DOCTYPEVERSION    ,     version);
-    put_ebml_uint  (pb, EBML_ID_DOCTYPEREADVERSION,           2);
-    end_ebml_master(pb, ebml_header);
-
+    ebml_write_header(pb, s->oformat->name, version);
     put_ebml_id(pb, MATROSKA_ID_SEGMENT);
     put_ebml_size_unknown(pb, 8);
     mkv->segment_offset = avio_tell(pb);



More information about the ffmpeg-cvslog mailing list