@@ -704,6 +704,18 @@ int avio_closep(AVIOContext **s);
int avio_open_dyn_buf(AVIOContext **s);
/**
+ * Return the written size and a pointer to the buffer.
+ * The AVIOContext stream is left intact.
+ * The buffer must NOT be freed.
+ * No padding is added to the buffer.
+ *
+ * @param s IO context
+ * @param pbuffer pointer to a byte buffer
+ * @return the length of the byte buffer
+ */
+int avio_get_dyn_buf(AVIOContext *s, uint8_t **pbuffer);
+
+/**
* Return the written size and a pointer to the buffer. The buffer
* must be freed with av_free().
* Padding of AV_INPUT_BUFFER_PADDING_SIZE is added to the buffer.
@@ -1277,6 +1277,23 @@ int ffio_open_dyn_packet_buf(AVIOContext **s, int max_packet_size)
return url_open_dyn_buf_internal(s, max_packet_size);
}
+int avio_get_dyn_buf(AVIOContext *s, uint8_t **pbuffer)
+{
+ DynBuffer *d;
+
+ if (!s) {
+ *pbuffer = NULL;
+ return 0;
+ }
+
+ avio_flush(s);
+
+ d = s->opaque;
+ *pbuffer = d->buffer;
+
+ return d->size;
+}
+
int avio_close_dyn_buf(AVIOContext *s, uint8_t **pbuffer)
{
DynBuffer *d;
@@ -367,6 +367,28 @@ static void end_ebml_master_crc32(AVIOContext *pb, AVIOContext **dyn_cp, Matrosk
*dyn_cp = NULL;
}
+/**
+* Complete ebml master whithout destroying the buffer, allowing for later updates
+*/
+static void end_ebml_master_crc32_preliminary(AVIOContext *pb, AVIOContext **dyn_cp, MatroskaMuxContext *mkv,
+ ebml_master master)
+{
+ uint8_t *buf, crc[4];
+ int size, skip = 0;
+
+ if (pb->seekable) {
+
+ size = avio_get_dyn_buf(*dyn_cp, &buf);
+ if (mkv->write_crc && mkv->mode != MODE_WEBM) {
+ skip = 6; /* Skip reserved 6-byte long void element from the dynamic buffer. */
+ AV_WL32(crc, av_crc(av_crc_get_table(AV_CRC_32_IEEE_LE), UINT32_MAX, buf + skip, size - skip) ^ UINT32_MAX);
+ put_ebml_binary(pb, EBML_ID_CRC32, crc, sizeof(crc));
+ }
+ avio_write(pb, buf + skip, size - skip);
+ end_ebml_master(pb, master);
+ }
+}
+
static void put_xiph_size(AVIOContext *pb, int size)
{
ffio_fill(pb, 255, size / 255);
@@ -1308,8 +1330,10 @@ static int mkv_write_tracks(AVFormatContext *s)
return ret;
}
- if (pb->seekable && !mkv->is_live)
+ if (pb->seekable && !mkv->is_live) {
put_ebml_void(pb, avio_tell(mkv->tracks_bc));
+ end_ebml_master_crc32_preliminary(pb, &mkv->tracks_bc, mkv, mkv->tracks_master);
+ }
else
end_ebml_master_crc32(pb, &mkv->tracks_bc, mkv, mkv->tracks_master);
@@ -1553,8 +1577,10 @@ static int mkv_write_tags(AVFormatContext *s)
}
if (mkv->tags.pos) {
- if (s->pb->seekable && !mkv->is_live)
+ if (s->pb->seekable && !mkv->is_live) {
put_ebml_void(s->pb, avio_tell(mkv->tags_bc));
+ end_ebml_master_crc32_preliminary(s->pb, &mkv->tags_bc, mkv, mkv->tags);
+ }
else
end_ebml_master_crc32(s->pb, &mkv->tags_bc, mkv, mkv->tags);
}
@@ -1810,8 +1836,10 @@ static int mkv_write_header(AVFormatContext *s)
put_ebml_void(pb, 11); // assumes double-precision float to be written
}
}
- if (s->pb->seekable && !mkv->is_live)
+ if (s->pb->seekable && !mkv->is_live) {
put_ebml_void(s->pb, avio_tell(pb));
+ end_ebml_master_crc32_preliminary(s->pb, &mkv->info_bc, mkv, mkv->info);
+ }
else
end_ebml_master_crc32(s->pb, &mkv->info_bc, mkv, mkv->info);
pb = s->pb;