mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-28 03:00:35 +00:00
matroskamux: fix ebml write caching with bytewriter implementation
Also cache a bit more during header writing. Fixes #619273.
This commit is contained in:
parent
7895ddbc38
commit
81bf657aa7
3 changed files with 27 additions and 55 deletions
|
@ -62,7 +62,6 @@ gst_ebml_write_init (GstEbmlWrite * ebml, GstEbmlWriteClass * klass)
|
|||
ebml->pos = 0;
|
||||
|
||||
ebml->cache = NULL;
|
||||
ebml->cache_size = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -73,7 +72,7 @@ gst_ebml_write_finalize (GObject * object)
|
|||
gst_object_unref (ebml->srcpad);
|
||||
|
||||
if (ebml->cache) {
|
||||
gst_buffer_unref (ebml->cache);
|
||||
gst_byte_writer_free (ebml->cache);
|
||||
ebml->cache = NULL;
|
||||
}
|
||||
|
||||
|
@ -116,10 +115,9 @@ gst_ebml_write_reset (GstEbmlWrite * ebml)
|
|||
ebml->pos = 0;
|
||||
|
||||
if (ebml->cache) {
|
||||
gst_buffer_unref (ebml->cache);
|
||||
gst_byte_writer_free (ebml->cache);
|
||||
ebml->cache = NULL;
|
||||
}
|
||||
ebml->cache_size = 0;
|
||||
ebml->last_write_result = GST_FLOW_OK;
|
||||
ebml->timestamp = GST_CLOCK_TIME_NONE;
|
||||
ebml->need_newsegment = TRUE;
|
||||
|
@ -159,16 +157,11 @@ gst_ebml_last_write_result (GstEbmlWrite * ebml)
|
|||
void
|
||||
gst_ebml_write_set_cache (GstEbmlWrite * ebml, guint size)
|
||||
{
|
||||
/* FIXME: This is currently broken. I don't know why yet. */
|
||||
return;
|
||||
|
||||
g_return_if_fail (ebml->cache == NULL);
|
||||
|
||||
ebml->cache = gst_buffer_new_and_alloc (size);
|
||||
ebml->cache_size = size;
|
||||
GST_BUFFER_SIZE (ebml->cache) = 0;
|
||||
GST_BUFFER_OFFSET (ebml->cache) = ebml->pos;
|
||||
ebml->handled = 0;
|
||||
GST_DEBUG ("Starting cache at %" G_GUINT64_FORMAT, ebml->pos);
|
||||
ebml->cache = gst_byte_writer_new_with_size (size, FALSE);
|
||||
ebml->cache_pos = ebml->pos;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -180,30 +173,27 @@ gst_ebml_write_set_cache (GstEbmlWrite * ebml, guint size)
|
|||
void
|
||||
gst_ebml_write_flush_cache (GstEbmlWrite * ebml)
|
||||
{
|
||||
GstBuffer *buffer;
|
||||
|
||||
if (!ebml->cache)
|
||||
return;
|
||||
|
||||
/* this is very important. It may fail, in which case the client
|
||||
* programmer didn't use the cache somewhere. That's fatal. */
|
||||
g_assert (ebml->handled == GST_BUFFER_SIZE (ebml->cache));
|
||||
g_assert (GST_BUFFER_SIZE (ebml->cache) +
|
||||
GST_BUFFER_OFFSET (ebml->cache) == ebml->pos);
|
||||
buffer = gst_byte_writer_free_and_get_buffer (ebml->cache);
|
||||
ebml->cache = NULL;
|
||||
GST_DEBUG ("Flushing cache of size %d", GST_BUFFER_SIZE (buffer));
|
||||
|
||||
if (ebml->last_write_result == GST_FLOW_OK) {
|
||||
if (ebml->need_newsegment) {
|
||||
GstEvent *ev;
|
||||
|
||||
g_assert (ebml->handled == 0);
|
||||
ev = gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_BYTES, 0, -1, 0);
|
||||
if (gst_pad_push_event (ebml->srcpad, ev))
|
||||
ebml->need_newsegment = FALSE;
|
||||
}
|
||||
ebml->last_write_result = gst_pad_push (ebml->srcpad, ebml->cache);
|
||||
ebml->last_write_result = gst_pad_push (ebml->srcpad, buffer);
|
||||
} else {
|
||||
gst_buffer_unref (buffer);
|
||||
}
|
||||
|
||||
ebml->cache = NULL;
|
||||
ebml->cache_size = 0;
|
||||
ebml->handled = 0;
|
||||
}
|
||||
|
||||
|
||||
|
@ -226,17 +216,6 @@ gst_ebml_write_element_new (GstEbmlWrite * ebml, guint size)
|
|||
/* length, ID */
|
||||
size += 12;
|
||||
|
||||
/* prefer cache */
|
||||
if (ebml->cache) {
|
||||
if (ebml->cache_size - GST_BUFFER_SIZE (ebml->cache) < size) {
|
||||
GST_LOG ("Cache available, but too small. Clearing...");
|
||||
gst_ebml_write_flush_cache (ebml);
|
||||
} else {
|
||||
return ebml->cache;
|
||||
}
|
||||
}
|
||||
|
||||
/* else, use a one-element buffer. This is slower */
|
||||
buf = gst_buffer_new_and_alloc (size);
|
||||
GST_BUFFER_SIZE (buf) = 0;
|
||||
GST_BUFFER_TIMESTAMP (buf) = ebml->timestamp;
|
||||
|
@ -352,16 +331,14 @@ gst_ebml_write_element_data (GstBuffer * buf, guint8 * write, guint64 length)
|
|||
static void
|
||||
gst_ebml_write_element_push (GstEbmlWrite * ebml, GstBuffer * buf)
|
||||
{
|
||||
guint data_size = GST_BUFFER_SIZE (buf) - ebml->handled;
|
||||
guint data_size = GST_BUFFER_SIZE (buf);
|
||||
|
||||
ebml->pos += data_size;
|
||||
if (buf == ebml->cache) {
|
||||
ebml->handled += data_size;
|
||||
}
|
||||
|
||||
/* if there's no cache, then don't push it! */
|
||||
if (ebml->cache) {
|
||||
g_assert (buf == ebml->cache);
|
||||
gst_byte_writer_put_data (ebml->cache, GST_BUFFER_DATA (buf), data_size);
|
||||
gst_buffer_unref (buf);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -369,7 +346,6 @@ gst_ebml_write_element_push (GstEbmlWrite * ebml, GstBuffer * buf)
|
|||
if (ebml->need_newsegment) {
|
||||
GstEvent *ev;
|
||||
|
||||
g_assert (ebml->handled == 0);
|
||||
ev = gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_BYTES, 0, -1, 0);
|
||||
if (gst_pad_push_event (ebml->srcpad, ev))
|
||||
ebml->need_newsegment = FALSE;
|
||||
|
@ -378,8 +354,7 @@ gst_ebml_write_element_push (GstEbmlWrite * ebml, GstBuffer * buf)
|
|||
gst_buffer_set_caps (buf, GST_PAD_CAPS (ebml->srcpad));
|
||||
ebml->last_write_result = gst_pad_push (ebml->srcpad, buf);
|
||||
} else {
|
||||
if (buf != ebml->cache)
|
||||
gst_buffer_unref (buf);
|
||||
gst_buffer_unref (buf);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -400,14 +375,11 @@ gst_ebml_write_seek (GstEbmlWrite * ebml, guint64 pos)
|
|||
* knows what he's doing... */
|
||||
if (ebml->cache) {
|
||||
/* within bounds? */
|
||||
if (pos >= GST_BUFFER_OFFSET (ebml->cache) &&
|
||||
pos < GST_BUFFER_OFFSET (ebml->cache) + ebml->cache_size) {
|
||||
GST_BUFFER_SIZE (ebml->cache) = pos - GST_BUFFER_OFFSET (ebml->cache);
|
||||
if (ebml->pos > pos)
|
||||
ebml->handled -= ebml->pos - pos;
|
||||
else
|
||||
ebml->handled += pos - ebml->pos;
|
||||
if (pos >= ebml->cache_pos &&
|
||||
pos <= ebml->cache_pos + ebml->cache->parent.size) {
|
||||
ebml->pos = pos;
|
||||
gst_byte_writer_set_pos (ebml->cache, ebml->pos - ebml->cache_pos);
|
||||
return;
|
||||
} else {
|
||||
GST_LOG ("Seek outside cache range. Clearing...");
|
||||
gst_ebml_write_flush_cache (ebml);
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
#include <glib.h>
|
||||
#include <gst/gst.h>
|
||||
#include <gst/base/gstbytewriter.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
|
@ -48,9 +49,8 @@ typedef struct _GstEbmlWrite {
|
|||
guint64 pos;
|
||||
GstClockTime timestamp;
|
||||
|
||||
GstBuffer *cache;
|
||||
guint cache_size;
|
||||
guint handled;
|
||||
GstByteWriter *cache;
|
||||
guint64 cache_pos;
|
||||
|
||||
GstFlowReturn last_write_result;
|
||||
|
||||
|
|
|
@ -2005,14 +2005,14 @@ gst_matroska_mux_start (GstMatroskaMux * mux)
|
|||
doctype, mux->doctype_version);
|
||||
gst_ebml_write_header (ebml, doctype, mux->doctype_version);
|
||||
|
||||
/* the rest of the header is cached */
|
||||
gst_ebml_write_set_cache (ebml, 0x1000);
|
||||
|
||||
/* start a segment */
|
||||
mux->segment_pos =
|
||||
gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_SEGMENT);
|
||||
mux->segment_master = ebml->pos;
|
||||
|
||||
/* the rest of the header is cached */
|
||||
gst_ebml_write_set_cache (ebml, 0x1000);
|
||||
|
||||
/* seekhead (table of contents) - we set the positions later */
|
||||
mux->seekhead_pos = ebml->pos;
|
||||
master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_SEEKHEAD);
|
||||
|
|
Loading…
Reference in a new issue