diff options
author | Tim-Philipp Müller <tim@centricular.net> | 2005-10-14 12:43:30 +0000 |
---|---|---|
committer | Tim-Philipp Müller <tim@centricular.net> | 2005-10-14 12:43:30 +0000 |
commit | 22b9a5cd4310a0c4b4ab1508c0ac8fb6a951f061 (patch) | |
tree | 7425a287d6c908eb1acda5b99793ac69343d7a32 /gst/matroska/ebml-write.c | |
parent | fb495736bc531080df1a7874d7ef3b94679d25a9 (diff) |
Port matroska muxer to 0.9 (#318847).
Original commit message from CVS:
Reviewed by: Tim-Philipp Müller <tim at centricular dot net>
* configure.ac:
* gst/matroska/Makefile.am:
* gst/matroska/ebml-ids.h:
* gst/matroska/ebml-write.c:
* gst/matroska/ebml-write.h:
* gst/matroska/matroska-ids.h:
* gst/matroska/matroska-mux.c:
* gst/matroska/matroska-mux.h:
* gst/matroska/matroska.c: (plugin_init):
Port matroska muxer to 0.9 (#318847).
Diffstat (limited to 'gst/matroska/ebml-write.c')
-rw-r--r-- | gst/matroska/ebml-write.c | 394 |
1 files changed, 292 insertions, 102 deletions
diff --git a/gst/matroska/ebml-write.c b/gst/matroska/ebml-write.c index 139c4d0b..27bc6b55 100644 --- a/gst/matroska/ebml-write.c +++ b/gst/matroska/ebml-write.c @@ -1,5 +1,6 @@ /* GStreamer EBML I/O * (c) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net> + * (c) 2005 Michal Benes <michal.benes@xeris.cz> * * ebml-write.c: write EBML data to file/stream * @@ -28,85 +29,116 @@ #include "ebml-write.h" #include "ebml-ids.h" -enum -{ - /* FILL ME */ - LAST_SIGNAL -}; -static void gst_ebml_write_class_init (GstEbmlWriteClass * klass); -static void gst_ebml_write_init (GstEbmlWrite * ebml); -static GstStateChangeReturn gst_ebml_write_change_state (GstElement * element, - GstStateChange transition); +GST_DEBUG_CATEGORY_STATIC (gst_ebml_write_debug); +#define GST_CAT_DEFAULT gst_ebml_write_debug -static GstElementClass *parent_class = NULL; +#define _do_init(thing) \ + GST_DEBUG_CATEGORY_INIT (gst_ebml_write_debug, "GstEbmlWrite", 0, "Write EBML structured data") +GST_BOILERPLATE_FULL (GstEbmlWrite, gst_ebml_write, GstObject, GST_TYPE_OBJECT, + _do_init) + + static void gst_ebml_write_finalize (GObject * object); -GType -gst_ebml_write_get_type (void) -{ - static GType gst_ebml_write_type = 0; - - if (!gst_ebml_write_type) { - static const GTypeInfo gst_ebml_write_info = { - sizeof (GstEbmlWriteClass), - NULL, - NULL, - (GClassInitFunc) gst_ebml_write_class_init, - NULL, - NULL, - sizeof (GstEbmlWrite), - 0, - (GInstanceInitFunc) gst_ebml_write_init, - }; - - gst_ebml_write_type = - g_type_register_static (GST_TYPE_ELEMENT, "GstEbmlWrite", - &gst_ebml_write_info, 0); - } - return gst_ebml_write_type; + static void gst_ebml_write_base_init (gpointer g_class) +{ } static void gst_ebml_write_class_init (GstEbmlWriteClass * klass) { - GstElementClass *gstelement_class = (GstElementClass *) klass; - - parent_class = g_type_class_ref (GST_TYPE_ELEMENT); + GObjectClass *object = G_OBJECT_CLASS (klass); - gstelement_class->change_state = gst_ebml_write_change_state; + object->finalize = gst_ebml_write_finalize; } static void -gst_ebml_write_init (GstEbmlWrite * ebml) +gst_ebml_write_init (GstEbmlWrite * ebml, GstEbmlWriteClass * klass) { ebml->srcpad = NULL; ebml->pos = 0; ebml->cache = NULL; + ebml->cache_size = 0; +} + +static void +gst_ebml_write_finalize (GObject * object) +{ + GstEbmlWrite *ebml = GST_EBML_WRITE (object); + + gst_object_unref (ebml->srcpad); + + GST_CALL_PARENT (G_OBJECT_CLASS, finalize, (object)); +} + + +/** + * gst_ebml_write_new: + * @srcpad: Source pad to which the output will be pushed. + * + * Creates a new #GstEbmlWrite. + * + * Returns: a new #GstEbmlWrite + */ +GstEbmlWrite * +gst_ebml_write_new (GstPad * srcpad) +{ + GstEbmlWrite *ebml = + GST_EBML_WRITE (g_object_new (GST_TYPE_EBML_WRITE, NULL)); + + ebml->srcpad = gst_object_ref (srcpad); + + gst_ebml_write_reset (ebml); + + return ebml; } -static GstStateChangeReturn -gst_ebml_write_change_state (GstElement * element, GstStateChange transition) + +/** + * gst_ebml_write_reset: + * @ebml: a #GstEbmlWrite. + * + * Reset internal state of #GstEbmlWrite. + */ +void +gst_ebml_write_reset (GstEbmlWrite * ebml) { - GstEbmlWrite *ebml = GST_EBML_WRITE (element); - - switch (transition) { - case GST_STATE_CHANGE_PAUSED_TO_READY: - ebml->pos = 0; - break; - default: - break; + ebml->pos = 0; + + if (ebml->cache) { + gst_buffer_unref (ebml->cache); + ebml->cache = NULL; } + ebml->cache_size = 0; + ebml->last_write_result = GST_FLOW_OK; +} - if (GST_ELEMENT_CLASS (parent_class)->change_state) - return GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); - return GST_STATE_CHANGE_SUCCESS; +/** + * gst_ebml_last_write_result: + * @ebml: a #GstEbmlWrite. + * + * Returns: GST_FLOW_OK if there was not write error since the last call of + * gst_ebml_last_write_result or code of the error. + */ +GstFlowReturn +gst_ebml_last_write_result (GstEbmlWrite * ebml) +{ + GstFlowReturn res = ebml->last_write_result; + + ebml->last_write_result = GST_FLOW_OK; + + return res; } -/* - * Caching. + +/** + * gst_ebml_write_set_cache: + * @ebml: a #GstEbmlWrite. + * @size: size of the cache. + * Create a cache. * * The idea is that you use this for writing a lot * of small elements. This will just "queue" all of @@ -114,7 +146,6 @@ gst_ebml_write_change_state (GstElement * element, GstStateChange transition) * at once. This saves memory and time for buffer * allocation and init, and it looks better. */ - void gst_ebml_write_set_cache (GstEbmlWrite * ebml, guint size) { @@ -124,11 +155,18 @@ gst_ebml_write_set_cache (GstEbmlWrite * ebml, guint size) 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_ebml_write_flush_cache: + * @ebml: a #GstEbmlWrite. + * + * Flush the cache. + */ void gst_ebml_write_flush_cache (GstEbmlWrite * ebml) { @@ -141,16 +179,25 @@ gst_ebml_write_flush_cache (GstEbmlWrite * ebml) g_assert (GST_BUFFER_SIZE (ebml->cache) + GST_BUFFER_OFFSET (ebml->cache) == ebml->pos); - gst_pad_push (ebml->srcpad, GST_DATA (ebml->cache)); + if (ebml->last_write_result == GST_FLOW_OK) + ebml->last_write_result = gst_pad_push (ebml->srcpad, ebml->cache); + ebml->cache = NULL; + ebml->cache_size = 0; ebml->handled = 0; } -/* - * One-element buffer, in case of no cache. If there is + +/** + * gst_ebml_write_element_new: + * @ebml: a #GstEbmlWrite. + * @size: size of the requested buffer. + * + * Create a buffer for one element. If there is * a cache, use that instead. + * + * Returns: A new #GstBuffer. */ - static GstBuffer * gst_ebml_write_element_new (GstEbmlWrite * ebml, guint size) { @@ -162,7 +209,7 @@ gst_ebml_write_element_new (GstEbmlWrite * ebml, guint size) /* prefer cache */ if (ebml->cache) { - if (GST_BUFFER_MAXSIZE (ebml->cache) - GST_BUFFER_SIZE (ebml->cache) < size) { + 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 { @@ -177,10 +224,14 @@ gst_ebml_write_element_new (GstEbmlWrite * ebml, guint size) return buf; } -/* + +/** + * gst_ebml_write_element_id: + * @buf: Buffer to which id should be written. + * @id: Element ID that should be written. + * * Write element ID into a buffer. */ - static void gst_ebml_write_element_id (GstBuffer * buf, guint32 id) { @@ -208,29 +259,38 @@ gst_ebml_write_element_id (GstBuffer * buf, guint32 id) } } -/* + +/** + * gst_ebml_write_element_size: + * @buf: #GstBuffer to which size should be written. + * @size: Element length. + * * Write element length into a buffer. */ - static void gst_ebml_write_element_size (GstBuffer * buf, guint64 size) { guint8 *data = GST_BUFFER_DATA (buf) + GST_BUFFER_SIZE (buf); guint bytes = 1, mask = 0x80; - /* how many bytes? */ - while ((size >> ((bytes - 1) * 8)) >= mask && bytes <= 8) { - mask >>= 1; - bytes++; - } + if (size != GST_EBML_SIZE_UNKNOWN) { + /* how many bytes? - use mask-1 because an all-1 bitset is not allowed */ + while ((size >> ((bytes - 1) * 8)) >= (mask - 1) && bytes <= 8) { + mask >>= 1; + bytes++; + } - /* if invalid size, use max. */ - if (bytes > 8) { - GST_WARNING ("Invalid size, maximizing"); + /* if invalid size, use max. */ + if (bytes > 8) { + GST_WARNING ("Invalid size, writing size unknown"); + mask = 0x01; + bytes = 8; + /* Now here's a real FIXME: we cannot read those yet! */ + size = GST_EBML_SIZE_UNKNOWN; + } + } else { mask = 0x01; bytes = 8; - /* Now here's a real FIXME: we cannot read those yet! */ - size = G_GINT64_CONSTANT (0x00ffffffffffffff); } /* write out, BE, with length size marker */ @@ -243,10 +303,15 @@ gst_ebml_write_element_size (GstBuffer * buf, guint64 size) } } -/* + +/** + * gst_ebml_write_element_data: + * @buf: #GstBuffer to which data should be written. + * @write: Data that should be written. + * @length: Length of the data. + * * Write element data into a buffer. */ - static void gst_ebml_write_element_data (GstBuffer * buf, guint8 * write, guint64 length) { @@ -256,10 +321,14 @@ gst_ebml_write_element_data (GstBuffer * buf, guint8 * write, guint64 length) GST_BUFFER_SIZE (buf) += length; } -/* + +/** + * gst_ebml_write_element_push: + * @ebml: #GstEbmlWrite + * @buf: #GstBuffer to be written. + * * Write out buffer by moving it to the next element. */ - static void gst_ebml_write_element_push (GstEbmlWrite * ebml, GstBuffer * buf) { @@ -276,25 +345,30 @@ gst_ebml_write_element_push (GstEbmlWrite * ebml, GstBuffer * buf) return; } - gst_pad_push (ebml->srcpad, GST_DATA (buf)); + if (ebml->last_write_result == GST_FLOW_OK) + ebml->last_write_result = gst_pad_push (ebml->srcpad, buf); } -/* + +/** + * gst_ebml_write_seek: + * @ebml: #GstEbmlWrite + * @pos: Seek position. + * * Seek. */ - void gst_ebml_write_seek (GstEbmlWrite * ebml, guint64 pos) { GstEvent *seek; + GstPad *peer_pad; /* Cache seeking. A bit dangerous, we assume the client writer * knows what he's doing... */ if (ebml->cache) { /* within bounds? */ if (pos >= GST_BUFFER_OFFSET (ebml->cache) && - pos < - GST_BUFFER_OFFSET (ebml->cache) + GST_BUFFER_MAXSIZE (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; @@ -307,15 +381,27 @@ gst_ebml_write_seek (GstEbmlWrite * ebml, guint64 pos) } } - seek = gst_event_new_seek (GST_FORMAT_BYTES | GST_SEEK_METHOD_SET, pos); - gst_pad_push (ebml->srcpad, GST_DATA (seek)); + seek = gst_event_new_newsegment (FALSE, 1.0, GST_FORMAT_BYTES, + pos, -1, GST_CLOCK_TIME_NONE); + peer_pad = GST_PAD_PEER (ebml->srcpad); + if (peer_pad) { + gst_pad_send_event (peer_pad, seek); + } else { + GST_WARNING_OBJECT (ebml, "Can not seek: no peer pad"); + } + ebml->pos = pos; } -/* - * Get no. bytes needed to write a uint. - */ +/** + * gst_ebml_write_get_uint_size: + * @num: Number to be encoded. + * + * Get number of bytes needed to write a uint. + * + * Returns: Encoded uint length. + */ static guint gst_ebml_write_get_uint_size (guint64 num) { @@ -330,10 +416,14 @@ gst_ebml_write_get_uint_size (guint64 num) } -/* +/** + * gst_ebml_write_set_uint: + * @buf: #GstBuffer to which ithe number should be written. + * @num: Number to be written. + * @size: Encoded number length. + * * Write an uint into a buffer. */ - static void gst_ebml_write_set_uint (GstBuffer * buf, guint64 num, guint size) { @@ -347,10 +437,15 @@ gst_ebml_write_set_uint (GstBuffer * buf, guint64 num, guint size) } } -/* - * Data type wrappers. - */ +/** + * gst_ebml_write_uint: + * @ebml: #GstEbmlWrite + * @id: Element ID. + * @num: Number to be written. + * + * Write uint element. + */ void gst_ebml_write_uint (GstEbmlWrite * ebml, guint32 id, guint64 num) { @@ -364,6 +459,15 @@ gst_ebml_write_uint (GstEbmlWrite * ebml, guint32 id, guint64 num) gst_ebml_write_element_push (ebml, buf); } + +/** + * gst_ebml_write_sint: + * @ebml: #GstEbmlWrite + * @id: Element ID. + * @num: Number to be written. + * + * Write sint element. + */ void gst_ebml_write_sint (GstEbmlWrite * ebml, guint32 id, gint64 num) { @@ -392,6 +496,15 @@ gst_ebml_write_sint (GstEbmlWrite * ebml, guint32 id, gint64 num) gst_ebml_write_element_push (ebml, buf); } + +/** + * gst_ebml_write_float: + * @ebml: #GstEbmlWrite + * @id: Element ID. + * @num: Number to be written. + * + * Write float element. + */ void gst_ebml_write_float (GstEbmlWrite * ebml, guint32 id, gdouble num) { @@ -413,6 +526,15 @@ gst_ebml_write_float (GstEbmlWrite * ebml, guint32 id, gdouble num) gst_ebml_write_element_push (ebml, buf); } + +/** + * gst_ebml_write_ascii: + * @ebml: #GstEbmlWrite + * @id: Element ID. + * @str: String to be written. + * + * Write string element. + */ void gst_ebml_write_ascii (GstEbmlWrite * ebml, guint32 id, const gchar * str) { @@ -425,25 +547,49 @@ gst_ebml_write_ascii (GstEbmlWrite * ebml, guint32 id, const gchar * str) gst_ebml_write_element_push (ebml, buf); } + +/** + * gst_ebml_write_utf8: + * @ebml: #GstEbmlWrite + * @id: Element ID. + * @str: String to be written. + * + * Write utf8 encoded string element. + */ void gst_ebml_write_utf8 (GstEbmlWrite * ebml, guint32 id, const gchar * str) { gst_ebml_write_ascii (ebml, id, str); } -/* date should be in seconds since the unix epoch */ + +/** + * gst_ebml_write_date: + * @ebml: #GstEbmlWrite + * @id: Element ID. + * @date: Date in seconds since the unix epoch. + * + * Write date element. + */ void gst_ebml_write_date (GstEbmlWrite * ebml, guint32 id, gint64 date) { gst_ebml_write_sint (ebml, id, (date - GST_EBML_DATE_OFFSET) * GST_SECOND); } -/* +/** + * gst_ebml_write_master_start: + * @ebml: #GstEbmlWrite + * @id: Element ID. + * + * Start wiriting mater element. + * * Master writing is annoying. We use a size marker of * the max. allowed length, so that we can later fill it * in validly. + * + * Returns: Master starting position. */ - guint64 gst_ebml_write_master_start (GstEbmlWrite * ebml, guint32 id) { @@ -453,12 +599,20 @@ gst_ebml_write_master_start (GstEbmlWrite * ebml, guint32 id) t = GST_BUFFER_SIZE (buf); gst_ebml_write_element_id (buf, id); pos += GST_BUFFER_SIZE (buf) - t; - gst_ebml_write_element_size (buf, -1); + gst_ebml_write_element_size (buf, GST_EBML_SIZE_UNKNOWN); gst_ebml_write_element_push (ebml, buf); return pos; } + +/** + * gst_ebml_write_master_finish: + * @ebml: #GstEbmlWrite + * @startpos: Master starting position. + * + * Finish writing master element. + */ void gst_ebml_write_master_finish (GstEbmlWrite * ebml, guint64 startpos) { @@ -476,6 +630,16 @@ gst_ebml_write_master_finish (GstEbmlWrite * ebml, guint64 startpos) gst_ebml_write_seek (ebml, pos); } + +/** + * gst_ebml_write_binary: + * @ebml: #GstEbmlWrite + * @id: Element ID. + * @binary: Data to be written. + * @length: Length of the data + * + * Write an element with binary data. + */ void gst_ebml_write_binary (GstEbmlWrite * ebml, guint32 id, guint8 * binary, guint64 length) @@ -488,13 +652,20 @@ gst_ebml_write_binary (GstEbmlWrite * ebml, gst_ebml_write_element_push (ebml, buf); } -/* + +/** + * gst_ebml_write_buffer_header: + * @ebml: #GstEbmlWrite + * @id: Element ID. + * @length: Length of the data + * + * Write header of the binary element (use with gst_ebml_write_buffer function). + * * For things like video frames and audio samples, * you want to use this function, as it doesn't have * the overhead of memcpy() that other functions * such as write_binary() do have. */ - void gst_ebml_write_buffer_header (GstEbmlWrite * ebml, guint32 id, guint64 length) { @@ -505,13 +676,29 @@ gst_ebml_write_buffer_header (GstEbmlWrite * ebml, guint32 id, guint64 length) gst_ebml_write_element_push (ebml, buf); } + +/** + * gst_ebml_write_buffer: + * @ebml: #GstEbmlWrite + * @data: #GstBuffer cointaining the data. + * + * Write binary element (see gst_ebml_write_buffer_header). + */ void gst_ebml_write_buffer (GstEbmlWrite * ebml, GstBuffer * data) { gst_ebml_write_element_push (ebml, data); } -/* + +/** + * gst_ebml_replace_uint: + * @ebml: #GstEbmlWrite + * @pos: Position of the uint that should be replaced. + * @num: New value. + * + * Replace uint with a new value. + * * When replacing a uint, we assume that it is *always* * 8-byte, since that's the safest guess we can do. This * is just for simplicity. @@ -519,7 +706,6 @@ gst_ebml_write_buffer (GstEbmlWrite * ebml, GstBuffer * data) * FIXME: this function needs to be replaced with something * proper. This is a crude hack. */ - void gst_ebml_replace_uint (GstEbmlWrite * ebml, guint64 pos, guint64 num) { @@ -533,10 +719,14 @@ gst_ebml_replace_uint (GstEbmlWrite * ebml, guint64 pos, guint64 num) gst_ebml_write_seek (ebml, oldpos); } -/* +/** + * gst_ebml_write_header: + * @ebml: #GstEbmlWrite + * @doctype: Document type. + * @version: Document type version. + * * Write EBML header. */ - void gst_ebml_write_header (GstEbmlWrite * ebml, gchar * doctype, guint version) { |