aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndreas Rheinhardt <andreas.rheinhardt@outlook.com>2022-01-14 01:18:24 +0100
committerAndreas Rheinhardt <andreas.rheinhardt@outlook.com>2022-01-19 11:40:56 +0100
commit6b1968e939472125f97947fe62a534364212f573 (patch)
tree25529c20521c1251e9d9a68841791d39f6c02369
parentdc555de823ac7e9be73dddafda26e4b15ea1cc3f (diff)
downloadffmpeg-6b1968e939472125f97947fe62a534364212f573.tar.gz
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@outlook.com>
-rw-r--r--libavformat/matroskaenc.c39
1 files 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);