summaryrefslogtreecommitdiff
path: root/gst/matroska/ebml-read.c
diff options
context:
space:
mode:
Diffstat (limited to 'gst/matroska/ebml-read.c')
-rw-r--r--gst/matroska/ebml-read.c858
1 files changed, 223 insertions, 635 deletions
diff --git a/gst/matroska/ebml-read.c b/gst/matroska/ebml-read.c
index acf8d61b7..2a62f24e4 100644
--- a/gst/matroska/ebml-read.c
+++ b/gst/matroska/ebml-read.c
@@ -40,497 +40,253 @@
#define NAN (0.0 / 0.0)
#endif
-GST_DEBUG_CATEGORY_STATIC (ebmlread_debug);
+GST_DEBUG_CATEGORY (ebmlread_debug);
#define GST_CAT_DEFAULT ebmlread_debug
-static void gst_ebml_read_class_init (GstEbmlReadClass * klass);
-
-static void gst_ebml_read_init (GstEbmlRead * ebml);
-
-static GstStateChangeReturn gst_ebml_read_change_state (GstElement * element,
- GstStateChange transition);
+/* Peeks following element id and element length in datastream provided
+ * by @peek with @ctx as user data.
+ * Returns GST_FLOW_UNEXPECTED if not enough data to read id and length.
+ * Otherwise, @needed provides the prefix length (id + length), and
+ * @length provides element length.
+ *
+ * @object and @offset are provided for informative messaging/debug purposes.
+ */
+GstFlowReturn
+gst_ebml_peek_id_length (guint32 * _id, guint64 * _length, guint * _needed,
+ GstPeekData peek, gpointer * ctx, GstElement * el, guint64 offset)
+{
+ guint needed;
+ const guint8 *buf;
+ gint len_mask = 0x80, read = 1, n = 1, num_ffs = 0;
+ guint64 total;
+ guint8 b;
-/* convenience functions */
-static GstFlowReturn gst_ebml_read_peek_bytes (GstEbmlRead * ebml, guint size,
- GstBuffer ** p_buf, guint8 ** bytes);
-static GstFlowReturn gst_ebml_read_pull_bytes (GstEbmlRead * ebml, guint size,
- GstBuffer ** p_buf, guint8 ** bytes);
+ g_return_val_if_fail (_id != NULL, GST_FLOW_ERROR);
+ g_return_val_if_fail (_length != NULL, GST_FLOW_ERROR);
+ g_return_val_if_fail (_needed != NULL, GST_FLOW_ERROR);
+ /* well ... */
+ *_id = (guint32) GST_EBML_SIZE_UNKNOWN;
+ *_length = GST_EBML_SIZE_UNKNOWN;
-static GstElementClass *parent_class; /* NULL */
+ /* read element id */
+ needed = 2;
+ buf = peek (ctx, needed);
+ if (!buf)
+ goto not_enough_data;
-GType
-gst_ebml_read_get_type (void)
-{
- static GType gst_ebml_read_type; /* 0 */
-
- if (!gst_ebml_read_type) {
- static const GTypeInfo gst_ebml_read_info = {
- sizeof (GstEbmlReadClass),
- NULL,
- NULL,
- (GClassInitFunc) gst_ebml_read_class_init,
- NULL,
- NULL,
- sizeof (GstEbmlRead),
- 0,
- (GInstanceInitFunc) gst_ebml_read_init,
- };
-
- gst_ebml_read_type =
- g_type_register_static (GST_TYPE_ELEMENT, "GstEbmlRead",
- &gst_ebml_read_info, 0);
+ b = GST_READ_UINT8 (buf);
+ total = (guint64) b;
+ while (read <= 4 && !(total & len_mask)) {
+ read++;
+ len_mask >>= 1;
}
+ if (G_UNLIKELY (read > 4))
+ goto invalid_id;
- return gst_ebml_read_type;
-}
+ /* need id and at least something for subsequent length */
+ needed = read + 1;
+ buf = peek (ctx, needed);
+ if (!buf)
+ goto not_enough_data;
-void
-gst_ebml_level_free (GstEbmlLevel * level)
-{
- g_slice_free (GstEbmlLevel, level);
-}
+ while (n < read) {
+ b = GST_READ_UINT8 (buf + n);
+ total = (total << 8) | b;
+ ++n;
+ }
+ *_id = (guint32) total;
-static void
-gst_ebml_finalize (GObject * obj)
-{
- GstEbmlRead *ebml = GST_EBML_READ (obj);
-
- g_list_foreach (ebml->level, (GFunc) gst_ebml_level_free, NULL);
- g_list_free (ebml->level);
- ebml->level = NULL;
- if (ebml->cached_buffer) {
- gst_buffer_unref (ebml->cached_buffer);
- ebml->cached_buffer = NULL;
+ /* read element length */
+ b = GST_READ_UINT8 (buf + n);
+ total = (guint64) b;
+ len_mask = 0x80;
+ read = 1;
+ while (read <= 8 && !(total & len_mask)) {
+ read++;
+ len_mask >>= 1;
}
+ if (G_UNLIKELY (read > 8))
+ goto invalid_length;
+ if ((total &= (len_mask - 1)) == len_mask - 1)
+ num_ffs++;
- G_OBJECT_CLASS (parent_class)->finalize (obj);
-}
+ needed += read - 1;
+ buf = peek (ctx, needed);
+ if (!buf)
+ goto not_enough_data;
-static void
-gst_ebml_read_class_init (GstEbmlReadClass * klass)
-{
- GstElementClass *gstelement_class = (GstElementClass *) klass;
- GObjectClass *gobject_class = (GObjectClass *) klass;
-
- parent_class = g_type_class_peek_parent (klass);
+ buf += (needed - read);
+ n = 1;
+ while (n < read) {
+ guint8 b = GST_READ_UINT8 (buf + n);
- GST_DEBUG_CATEGORY_INIT (ebmlread_debug, "ebmlread",
- 0, "EBML stream helper class");
+ if (G_UNLIKELY (b == 0xff))
+ num_ffs++;
+ total = (total << 8) | b;
+ ++n;
+ }
- gobject_class->finalize = gst_ebml_finalize;
+ if (G_UNLIKELY (read == num_ffs))
+ *_length = G_MAXUINT64;
+ else
+ *_length = total;
+ *_length = total;
- gstelement_class->change_state =
- GST_DEBUG_FUNCPTR (gst_ebml_read_change_state);
-}
+ *_needed = needed;
-static void
-gst_ebml_read_init (GstEbmlRead * ebml)
-{
- ebml->sinkpad = NULL;
- ebml->level = NULL;
-}
+ return GST_FLOW_OK;
-static GstStateChangeReturn
-gst_ebml_read_change_state (GstElement * element, GstStateChange transition)
-{
- GstStateChangeReturn ret;
- GstEbmlRead *ebml = GST_EBML_READ (element);
-
- switch (transition) {
- case GST_STATE_CHANGE_READY_TO_PAUSED:
- if (!ebml->sinkpad) {
- g_return_val_if_reached (GST_STATE_CHANGE_FAILURE);
- }
- break;
- default:
- break;
+ /* ERRORS */
+not_enough_data:
+ {
+ *_needed = needed;
+ return GST_FLOW_UNEXPECTED;
}
-
- ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
-
- switch (transition) {
- case GST_STATE_CHANGE_PAUSED_TO_READY:
- {
- g_list_foreach (ebml->level, (GFunc) gst_ebml_level_free, NULL);
- g_list_free (ebml->level);
- ebml->level = NULL;
- if (ebml->cached_buffer) {
- gst_buffer_unref (ebml->cached_buffer);
- ebml->cached_buffer = NULL;
- }
- ebml->offset = 0;
- break;
- }
- default:
- break;
+invalid_id:
+ {
+ GST_ERROR_OBJECT (el,
+ "Invalid EBML ID size tag (0x%x) at position %" G_GUINT64_FORMAT " (0x%"
+ G_GINT64_MODIFIER "x)", (guint) b, offset, offset);
+ return GST_FLOW_ERROR;
+ }
+invalid_length:
+ {
+ GST_ERROR_OBJECT (el,
+ "Invalid EBML length size tag (0x%x) at position %" G_GUINT64_FORMAT
+ " (0x%" G_GINT64_MODIFIER "x)", (guint) b, offset, offset);
+ return GST_FLOW_ERROR;
}
-
- return ret;
}
-/*
- * Used in push mode.
- * Provided buffer is used as cache, based on offset 0, and no further reads
- * will be issued.
- */
-
+/* setup for parsing @buf at position @offset on behalf of @el.
+ * Takes ownership of @buf. */
void
-gst_ebml_read_reset_cache (GstEbmlRead * ebml, GstBuffer * buffer,
+gst_ebml_read_init (GstEbmlRead * ebml, GstElement * el, GstBuffer * buf,
guint64 offset)
{
- if (ebml->cached_buffer)
- gst_buffer_unref (ebml->cached_buffer);
-
- ebml->cached_buffer = buffer;
- ebml->push_cache = TRUE;
- buffer = gst_buffer_make_metadata_writable (buffer);
- GST_BUFFER_OFFSET (buffer) = offset;
- ebml->offset = offset;
- g_list_foreach (ebml->level, (GFunc) gst_ebml_level_free, NULL);
- g_list_free (ebml->level);
- ebml->level = NULL;
-}
+ GstEbmlMaster m;
-/*
- * Return: the amount of levels in the hierarchy that the
- * current element lies higher than the previous one.
- * The opposite isn't done - that's auto-done using master
- * element reading.
- */
+ g_return_if_fail (el);
+ g_return_if_fail (buf);
-static guint
-gst_ebml_read_element_level_up (GstEbmlRead * ebml)
-{
- guint num = 0;
- guint64 pos = ebml->offset;
-
- while (ebml->level != NULL) {
- GstEbmlLevel *level = ebml->level->data;
-
- if (pos >= level->start + level->length) {
- ebml->level = g_list_delete_link (ebml->level, ebml->level);
- gst_ebml_level_free (level);
- num++;
- } else {
- break;
- }
- }
-
- return num;
+ ebml->el = el;
+ ebml->offset = offset;
+ ebml->buf = buf;
+ ebml->readers = g_array_sized_new (FALSE, FALSE, sizeof (GstEbmlMaster), 10);
+ m.offset = ebml->offset;
+ gst_byte_reader_init (&m.br, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
+ g_array_append_val (ebml->readers, m);
}
-/*
- * Calls pull_range for (offset,size) without advancing our offset
- */
-static GstFlowReturn
-gst_ebml_read_peek_bytes (GstEbmlRead * ebml, guint size, GstBuffer ** p_buf,
- guint8 ** bytes)
+void
+gst_ebml_read_clear (GstEbmlRead * ebml)
{
- GstFlowReturn ret;
-
- /* Caching here actually makes much less difference than one would expect.
- * We do it mainly to avoid pulling buffers of 1 byte all the time */
- if (ebml->cached_buffer) {
- guint64 cache_offset = GST_BUFFER_OFFSET (ebml->cached_buffer);
- guint cache_size = GST_BUFFER_SIZE (ebml->cached_buffer);
-
- if (cache_offset <= ebml->offset &&
- (ebml->offset + size) <= (cache_offset + cache_size)) {
- if (p_buf)
- *p_buf = gst_buffer_create_sub (ebml->cached_buffer,
- ebml->offset - cache_offset, size);
- if (bytes)
- *bytes =
- GST_BUFFER_DATA (ebml->cached_buffer) + ebml->offset - cache_offset;
- return GST_FLOW_OK;
- }
- /* not enough data in the cache, free cache and get a new one */
- /* never drop pushed cache */
- if (ebml->push_cache) {
- if (ebml->offset == cache_offset + cache_size)
- return GST_FLOW_END;
- else
- return GST_FLOW_UNEXPECTED;
- }
- gst_buffer_unref (ebml->cached_buffer);
- ebml->cached_buffer = NULL;
- }
-
- /* refill the cache */
- ret = gst_pad_pull_range (ebml->sinkpad, ebml->offset, MAX (size, 64 * 1024),
- &ebml->cached_buffer);
- if (ret != GST_FLOW_OK) {
- ebml->cached_buffer = NULL;
- return ret;
- }
-
- if (GST_BUFFER_SIZE (ebml->cached_buffer) >= size) {
- if (p_buf)
- *p_buf = gst_buffer_create_sub (ebml->cached_buffer, 0, size);
- if (bytes)
- *bytes = GST_BUFFER_DATA (ebml->cached_buffer);
- return GST_FLOW_OK;
- }
-
- /* Not possible to get enough data, try a last time with
- * requesting exactly the size we need */
- gst_buffer_unref (ebml->cached_buffer);
- ebml->cached_buffer = NULL;
-
- ret =
- gst_pad_pull_range (ebml->sinkpad, ebml->offset, size,
- &ebml->cached_buffer);
- if (ret != GST_FLOW_OK) {
- GST_DEBUG_OBJECT (ebml, "pull_range returned %d", ret);
- if (p_buf)
- *p_buf = NULL;
- if (bytes)
- *bytes = NULL;
- return ret;
- }
-
- if (GST_BUFFER_SIZE (ebml->cached_buffer) < size) {
- GST_WARNING_OBJECT (ebml, "Dropping short buffer at offset %"
- G_GUINT64_FORMAT ": wanted %u bytes, got %u bytes", ebml->offset,
- size, GST_BUFFER_SIZE (ebml->cached_buffer));
-
- gst_buffer_unref (ebml->cached_buffer);
- ebml->cached_buffer = NULL;
- if (p_buf)
- *p_buf = NULL;
- if (bytes)
- *bytes = NULL;
- return GST_FLOW_UNEXPECTED;
- }
-
- if (p_buf)
- *p_buf = gst_buffer_create_sub (ebml->cached_buffer, 0, size);
- if (bytes)
- *bytes = GST_BUFFER_DATA (*p_buf);
-
- return GST_FLOW_OK;
+ if (ebml->readers)
+ g_array_free (ebml->readers, TRUE);
+ ebml->readers = NULL;
+ if (ebml->buf)
+ gst_buffer_unref (ebml->buf);
+ ebml->buf = NULL;
+ ebml->el = NULL;
}
-/*
- * Calls pull_range for (offset,size) and advances our offset by size
- */
-static GstFlowReturn
-gst_ebml_read_pull_bytes (GstEbmlRead * ebml, guint size, GstBuffer ** p_buf,
- guint8 ** bytes)
+static const guint8 *
+gst_ebml_read_peek (GstByteReader * br, guint peek)
{
- GstFlowReturn ret;
-
- ret = gst_ebml_read_peek_bytes (ebml, size, p_buf, bytes);
- if (ret != GST_FLOW_OK)
- return ret;
+ const guint8 *data;
- ebml->offset += size;
- return GST_FLOW_OK;
+ if (G_LIKELY (gst_byte_reader_peek_data (br, peek, &data)))
+ return data;
+ else
+ return NULL;
}
-/*
- * Read: the element content data ID.
- * Return: FALSE on error.
- */
-
static GstFlowReturn
-gst_ebml_read_element_id (GstEbmlRead * ebml, guint32 * id, guint * level_up)
+gst_ebml_peek_id_full (GstEbmlRead * ebml, guint32 * id, guint64 * length,
+ guint * prefix)
{
- guint8 *buf;
- gint len_mask = 0x80, read = 1, n = 1;
- guint32 total;
- guint8 b;
GstFlowReturn ret;
+ const guint8 *data = NULL;
- ret = gst_ebml_read_peek_bytes (ebml, 1, NULL, &buf);
+ ret = gst_ebml_peek_id_length (id, length, prefix,
+ (GstPeekData) gst_ebml_read_peek, (gpointer) gst_ebml_read_br (ebml),
+ ebml->el, gst_ebml_read_get_pos (ebml));
if (ret != GST_FLOW_OK)
return ret;
- b = GST_READ_UINT8 (buf);
-
- total = (guint32) b;
-
- while (read <= 4 && !(total & len_mask)) {
- read++;
- len_mask >>= 1;
- }
- if (read > 4) {
- GST_ERROR_OBJECT (ebml,
- "Invalid EBML ID size tag (0x%x) at position %" G_GUINT64_FORMAT " (0x%"
- G_GINT64_MODIFIER "x)", (guint) b, ebml->offset, ebml->offset);
- return GST_FLOW_ERROR;
- }
+ GST_LOG_OBJECT (ebml->el, "id 0x%x at offset 0x%" G_GINT64_MODIFIER "x"
+ " of length %" G_GUINT64_FORMAT ", prefix %d", *id,
+ gst_ebml_read_get_pos (ebml), *length, *prefix);
- ret = gst_ebml_read_peek_bytes (ebml, read, NULL, &buf);
- if (ret != GST_FLOW_OK)
- return ret;
+#ifndef GST_DISABLE_GST_DEBUG
+ {
+ GstByteReader *br = gst_ebml_read_br (ebml);
+ guint size = gst_byte_reader_get_remaining (br);
+ gst_byte_reader_peek_data (br, size, &data);
- while (n < read) {
- b = GST_READ_UINT8 (buf + n);
- total = (total << 8) | b;
- ++n;
+ GST_LOG_OBJECT (ebml->el, "current br %p; remaining %d", br, size);
+ if (data)
+ GST_MEMDUMP_OBJECT (ebml->el, "element", data, MIN (size, *length));
}
+#endif
- *id = total;
+ return ret;
+}
- /* level */
- if (level_up)
- *level_up = gst_ebml_read_element_level_up (ebml);
+GstFlowReturn
+gst_ebml_peek_id (GstEbmlRead * ebml, guint32 * id)
+{
+ guint64 length;
+ guint needed;
- ebml->offset += read;
- return GST_FLOW_OK;
+ return gst_ebml_peek_id_full (ebml, id, &length, &needed);
}
/*
- * Read: element content length.
- * Return: the number of bytes read or -1 on error.
+ * Read the next element, the contents are supposed to be sub-elements which
+ * can be read separately. A new bytereader is setup for doing so.
*/
-
-static GstFlowReturn
-gst_ebml_read_element_length (GstEbmlRead * ebml, guint64 * length,
- gint * rread)
+GstFlowReturn
+gst_ebml_read_master (GstEbmlRead * ebml, guint32 * id)
{
+ guint64 length;
+ guint prefix;
+ const guint8 *data;
GstFlowReturn ret;
- guint8 *buf;
- gint len_mask = 0x80, read = 1, n = 1, num_ffs = 0;
- guint64 total;
- guint8 b;
+ GstEbmlMaster m;
- ret = gst_ebml_read_peek_bytes (ebml, 1, NULL, &buf);
+ ret = gst_ebml_peek_id_full (ebml, id, &length, &prefix);
if (ret != GST_FLOW_OK)
return ret;
- b = GST_READ_UINT8 (buf);
+ /* we just at least peeked the id */
+ g_assert (gst_byte_reader_skip (gst_ebml_read_br (ebml), prefix));
- total = (guint64) b;
+ m.offset = gst_ebml_read_get_pos (ebml);
+ if (!gst_byte_reader_get_data (gst_ebml_read_br (ebml), length, &data))
+ return GST_FLOW_PARSE;
- while (read <= 8 && !(total & len_mask)) {
- read++;
- len_mask >>= 1;
- }
- if (read > 8) {
- GST_ERROR_OBJECT (ebml,
- "Invalid EBML length size tag (0x%x) at position %" G_GUINT64_FORMAT
- " (0x%" G_GINT64_MODIFIER "x)", (guint) b, ebml->offset, ebml->offset);
- return GST_FLOW_ERROR;
- }
-
- if ((total &= (len_mask - 1)) == len_mask - 1)
- num_ffs++;
-
- ret = gst_ebml_read_peek_bytes (ebml, read, NULL, &buf);
- if (ret != GST_FLOW_OK)
- return ret;
-
- while (n < read) {
- guint8 b = GST_READ_UINT8 (buf + n);
-
- if (b == 0xff)
- num_ffs++;
- total = (total << 8) | b;
- ++n;
- }
-
- if (read == num_ffs)
- *length = G_MAXUINT64;
- else
- *length = total;
-
- if (rread)
- *rread = read;
-
- ebml->offset += read;
+ GST_LOG_OBJECT (ebml->el, "pushing level %d at offset %" G_GUINT64_FORMAT,
+ ebml->readers->len, m.offset);
+ gst_byte_reader_init (&m.br, data, length);
+ g_array_append_val (ebml->readers, m);
return GST_FLOW_OK;
}
-/*
- * Return: the ID of the next element.
- * Level_up contains the amount of levels that this
- * next element lies higher than the previous one.
- */
-
+/* explicitly pop a bytereader from stack. Usually invoked automagically. */
GstFlowReturn
-gst_ebml_peek_id (GstEbmlRead * ebml, guint * level_up, guint32 * id)
+gst_ebml_read_pop_master (GstEbmlRead * ebml)
{
- guint64 off;
- guint level_up_tmp = 0;
- GstFlowReturn ret;
-
- g_assert (level_up);
- g_assert (id);
-
- *level_up = 0;
-
-next:
- off = ebml->offset; /* save offset */
+ g_return_val_if_fail (ebml->readers, GST_FLOW_ERROR);
- if ((ret = gst_ebml_read_element_id (ebml, id, &level_up_tmp)) != GST_FLOW_OK) {
- if (ret != GST_FLOW_END)
- return ret;
- else {
- /* simulate dummy VOID element,
- * and have the call stack bail out all the way */
- *id = GST_EBML_ID_VOID;
- *level_up = G_MAXUINT32 >> 2;
- return GST_FLOW_OK;
- }
- }
-
- ebml->offset = off; /* restore offset */
-
- *level_up += level_up_tmp;
- level_up_tmp = 0;
-
- switch (*id) {
- case GST_EBML_ID_VOID:
- GST_DEBUG_OBJECT (ebml, "Skipping EBML Void element");
- if ((ret = gst_ebml_read_skip (ebml)) != GST_FLOW_OK)
- return ret;
- goto next;
- break;
- case GST_EBML_ID_CRC32:
- GST_DEBUG_OBJECT (ebml, "Skipping EBML CRC32 element");
- if ((ret = gst_ebml_read_skip (ebml)) != GST_FLOW_OK)
- return ret;
- goto next;
- break;
+ /* never remove initial bytereader */
+ if (ebml->readers->len > 1) {
+ GST_LOG_OBJECT (ebml->el, "popping level %d", ebml->readers->len - 1);
+ g_array_remove_index (ebml->readers, ebml->readers->len - 1);
}
- return ret;
-}
-
-/*
- * Return the length of the stream in bytes
- */
-
-gint64
-gst_ebml_read_get_length (GstEbmlRead * ebml)
-{
- GstFormat fmt = GST_FORMAT_BYTES;
- gint64 end;
-
- /* FIXME: what to do if we don't get the upstream length */
- if (!gst_pad_query_peer_duration (ebml->sinkpad, &fmt, &end) ||
- fmt != GST_FORMAT_BYTES || end < 0)
- g_return_val_if_reached (0);
-
- return end;
-}
-
-/*
- * Seek to a given offset.
- */
-
-GstFlowReturn
-gst_ebml_read_seek (GstEbmlRead * ebml, guint64 offset)
-{
- if (offset >= gst_ebml_read_get_length (ebml))
- return GST_FLOW_UNEXPECTED;
-
- ebml->offset = offset;
-
return GST_FLOW_OK;
}
@@ -543,17 +299,16 @@ gst_ebml_read_skip (GstEbmlRead * ebml)
{
guint64 length;
guint32 id;
+ guint prefix;
GstFlowReturn ret;
- ret = gst_ebml_read_element_id (ebml, &id, NULL);
+ ret = gst_ebml_peek_id_full (ebml, &id, &length, &prefix);
if (ret != GST_FLOW_OK)
return ret;
- ret = gst_ebml_read_element_length (ebml, &length, NULL);
- if (ret != GST_FLOW_OK)
- return ret;
+ if (!gst_byte_reader_skip (gst_ebml_read_br (ebml), length + prefix))
+ return GST_FLOW_PARSE;
- ebml->offset += length;
return ret;
}
@@ -565,24 +320,30 @@ GstFlowReturn
gst_ebml_read_buffer (GstEbmlRead * ebml, guint32 * id, GstBuffer ** buf)
{
guint64 length;
+ guint prefix;
GstFlowReturn ret;
- ret = gst_ebml_read_element_id (ebml, id, NULL);
+ ret = gst_ebml_peek_id_full (ebml, id, &length, &prefix);
if (ret != GST_FLOW_OK)
return ret;
- ret = gst_ebml_read_element_length (ebml, &length, NULL);
- if (ret != GST_FLOW_OK)
- return ret;
+ /* we just at least peeked the id */
+ g_assert (gst_byte_reader_skip (gst_ebml_read_br (ebml), prefix));
+
+ if (G_LIKELY (length > 0)) {
+ guint offset;
- if (length == 0) {
+ offset = gst_ebml_read_get_pos (ebml) - ebml->offset;
+ if (G_LIKELY (gst_byte_reader_skip (gst_ebml_read_br (ebml), length))) {
+ *buf = gst_buffer_create_sub (ebml->buf, offset, length);
+ } else {
+ *buf = NULL;
+ return GST_FLOW_PARSE;
+ }
+ } else {
*buf = gst_buffer_new ();
- return GST_FLOW_OK;
}
- *buf = NULL;
- ret = gst_ebml_read_pull_bytes (ebml, (guint) length, buf, NULL);
-
return ret;
}
@@ -591,33 +352,29 @@ gst_ebml_read_buffer (GstEbmlRead * ebml, guint32 * id, GstBuffer ** buf)
*/
static GstFlowReturn
-gst_ebml_read_bytes (GstEbmlRead * ebml, guint32 * id, guint8 ** data,
+gst_ebml_read_bytes (GstEbmlRead * ebml, guint32 * id, const guint8 ** data,
guint * size)
{
guint64 length;
+ guint prefix;
GstFlowReturn ret;
*size = 0;
- ret = gst_ebml_read_element_id (ebml, id, NULL);
+ ret = gst_ebml_peek_id_full (ebml, id, &length, &prefix);
if (ret != GST_FLOW_OK)
return ret;
- ret = gst_ebml_read_element_length (ebml, &length, NULL);
- if (ret != GST_FLOW_OK)
- return ret;
-
- if (length == 0) {
- *data = NULL;
- return ret;
- }
+ /* we just at least peeked the id */
+ g_assert (gst_byte_reader_skip (gst_ebml_read_br (ebml), prefix));
*data = NULL;
- ret = gst_ebml_read_pull_bytes (ebml, (guint) length, NULL, data);
- if (ret != GST_FLOW_OK)
- return ret;
+ if (G_LIKELY (length >= 0)) {
+ if (!gst_byte_reader_get_data (gst_ebml_read_br (ebml), length, data))
+ return GST_FLOW_PARSE;
+ }
- *size = (guint) length;
+ *size = length;
return ret;
}
@@ -629,7 +386,7 @@ gst_ebml_read_bytes (GstEbmlRead * ebml, guint32 * id, guint8 ** data,
GstFlowReturn
gst_ebml_read_uint (GstEbmlRead * ebml, guint32 * id, guint64 * num)
{
- guint8 *data;
+ const guint8 *data;
guint size;
GstFlowReturn ret;
@@ -638,9 +395,10 @@ gst_ebml_read_uint (GstEbmlRead * ebml, guint32 * id, guint64 * num)
return ret;
if (size < 1 || size > 8) {
- GST_ERROR_OBJECT (ebml,
+ GST_ERROR_OBJECT (ebml->el,
"Invalid integer element size %d at position %" G_GUINT64_FORMAT " (0x%"
- G_GINT64_MODIFIER "x)", size, ebml->offset - size, ebml->offset - size);
+ G_GINT64_MODIFIER "x)", size, gst_ebml_read_get_pos (ebml) - size,
+ gst_ebml_read_get_pos (ebml) - size);
return GST_FLOW_ERROR;
}
*num = 0;
@@ -660,7 +418,7 @@ gst_ebml_read_uint (GstEbmlRead * ebml, guint32 * id, guint64 * num)
GstFlowReturn
gst_ebml_read_sint (GstEbmlRead * ebml, guint32 * id, gint64 * num)
{
- guint8 *data;
+ const guint8 *data;
guint size;
gboolean negative = 0;
GstFlowReturn ret;
@@ -670,9 +428,10 @@ gst_ebml_read_sint (GstEbmlRead * ebml, guint32 * id, gint64 * num)
return ret;
if (size < 1 || size > 8) {
- GST_ERROR_OBJECT (ebml,
+ GST_ERROR_OBJECT (ebml->el,
"Invalid integer element size %d at position %" G_GUINT64_FORMAT " (0x%"
- G_GINT64_MODIFIER "x)", size, ebml->offset - size, ebml->offset - size);
+ G_GINT64_MODIFIER "x)", size, gst_ebml_read_get_pos (ebml) - size,
+ gst_ebml_read_get_pos (ebml) - size);
return GST_FLOW_ERROR;
}
@@ -709,7 +468,7 @@ struct _ext_float
};
static gdouble
-_ext2dbl (guint8 * data)
+_ext2dbl (const guint8 * data)
{
struct _ext_float ext;
guint64 m = 0;
@@ -738,7 +497,7 @@ _ext2dbl (guint8 * data)
GstFlowReturn
gst_ebml_read_float (GstEbmlRead * ebml, guint32 * id, gdouble * num)
{
- guint8 *data;
+ const guint8 *data;
guint size;
GstFlowReturn ret;
@@ -747,9 +506,10 @@ gst_ebml_read_float (GstEbmlRead * ebml, guint32 * id, gdouble * num)
return ret;
if (size != 4 && size != 8 && size != 10) {
- GST_ERROR_OBJECT (ebml,
+ GST_ERROR_OBJECT (ebml->el,
"Invalid float element size %d at position %" G_GUINT64_FORMAT " (0x%"
- G_GINT64_MODIFIER "x)", size, ebml->offset - size, ebml->offset - size);
+ G_GINT64_MODIFIER "x)", size, gst_ebml_read_get_pos (ebml) - size,
+ gst_ebml_read_get_pos (ebml) - size);
return GST_FLOW_ERROR;
}
@@ -781,7 +541,7 @@ gst_ebml_read_float (GstEbmlRead * ebml, guint32 * id, gdouble * num)
static GstFlowReturn
gst_ebml_read_string (GstEbmlRead * ebml, guint32 * id, gchar ** str)
{
- guint8 *data;
+ const guint8 *data;
guint size;
GstFlowReturn ret;
@@ -838,7 +598,7 @@ gst_ebml_read_utf8 (GstEbmlRead * ebml, guint32 * id, gchar ** str)
GstFlowReturn ret;
#ifndef GST_DISABLE_GST_DEBUG
- guint64 oldoff = ebml->offset;
+ guint64 oldoff = gst_ebml_read_get_pos (ebml);
#endif
ret = gst_ebml_read_string (ebml, id, str);
@@ -847,7 +607,7 @@ gst_ebml_read_utf8 (GstEbmlRead * ebml, guint32 * id, gchar ** str)
if (str != NULL && *str != NULL && **str != '\0' &&
!g_utf8_validate (*str, -1, NULL)) {
- GST_WARNING_OBJECT (ebml,
+ GST_WARNING_OBJECT (ebml->el,
"Invalid UTF-8 string at offset %" G_GUINT64_FORMAT, oldoff);
}
@@ -875,35 +635,6 @@ gst_ebml_read_date (GstEbmlRead * ebml, guint32 * id, gint64 * date)
}
/*
- * Read the next element, but only the header. The contents
- * are supposed to be sub-elements which can be read separately.
- */
-
-GstFlowReturn
-gst_ebml_read_master (GstEbmlRead * ebml, guint32 * id)
-{
- GstEbmlLevel *level;
- guint64 length;
- GstFlowReturn ret;
-
- ret = gst_ebml_read_element_id (ebml, id, NULL);
- if (ret != GST_FLOW_OK)
- return ret;
-
- ret = gst_ebml_read_element_length (ebml, &length, NULL);
- if (ret != GST_FLOW_OK)
- return ret;
-
- /* remember level */
- level = g_slice_new (GstEbmlLevel);
- level->start = ebml->offset;
- level->length = length;
- ebml->level = g_list_prepend (ebml->level, level);
-
- return GST_FLOW_OK;
-}
-
-/*
* Read the next element as binary data.
*/
@@ -911,7 +642,7 @@ GstFlowReturn
gst_ebml_read_binary (GstEbmlRead * ebml,
guint32 * id, guint8 ** binary, guint64 * length)
{
- guint8 *data;
+ const guint8 *data;
guint size;
GstFlowReturn ret;
@@ -924,146 +655,3 @@ gst_ebml_read_binary (GstEbmlRead * ebml,
return GST_FLOW_OK;
}
-
-/*
- * Read an EBML header.
- */
-
-GstFlowReturn
-gst_ebml_read_header (GstEbmlRead * ebml, gchar ** doctype, guint * version)
-{
- /* this function is the first to be called */
- guint32 id;
- guint level_up;
- GstFlowReturn ret;
-
- /* default init */
- if (doctype)
- *doctype = NULL;
- if (version)
- *version = 1;
-
- ret = gst_ebml_peek_id (ebml, &level_up, &id);
- if (ret != GST_FLOW_OK)
- return ret;
-
- GST_DEBUG_OBJECT (ebml, "id: %08x", GST_READ_UINT32_BE (&id));
-
- if (level_up != 0 || id != GST_EBML_ID_HEADER) {
- GST_ERROR_OBJECT (ebml, "Failed to read header");
- return GST_FLOW_ERROR;
- }
- ret = gst_ebml_read_master (ebml, &id);
- if (ret != GST_FLOW_OK)
- return ret;
-
- while (TRUE) {
- ret = gst_ebml_peek_id (ebml, &level_up, &id);
- if (ret != GST_FLOW_OK)
- return ret;
-
- /* end-of-header */
- if (level_up)
- break;
-
- switch (id) {
- /* is our read version uptodate? */
- case GST_EBML_ID_EBMLREADVERSION:{
- guint64 num;
-
- ret = gst_ebml_read_uint (ebml, &id, &num);
- if (ret != GST_FLOW_OK)
- return ret;
- g_assert (id == GST_EBML_ID_EBMLREADVERSION);
- if (num != GST_EBML_VERSION) {
- GST_ERROR_OBJECT (ebml, "Unsupported EBML version %" G_GUINT64_FORMAT,
- num);
- return GST_FLOW_ERROR;
- }
-
- GST_DEBUG_OBJECT (ebml, "EbmlReadVersion: %" G_GUINT64_FORMAT, num);
- break;
- }
-
- /* we only handle 8 byte lengths at max */
- case GST_EBML_ID_EBMLMAXSIZELENGTH:{
- guint64 num;
-
- ret = gst_ebml_read_uint (ebml, &id, &num);
- if (ret != GST_FLOW_OK)
- return ret;
- g_assert (id == GST_EBML_ID_EBMLMAXSIZELENGTH);
- if (num > sizeof (guint64)) {
- GST_ERROR_OBJECT (ebml,
- "Unsupported EBML maximum size %" G_GUINT64_FORMAT, num);
- return GST_FLOW_ERROR;
- }
- GST_DEBUG_OBJECT (ebml, "EbmlMaxSizeLength: %" G_GUINT64_FORMAT, num);
- break;
- }
-
- /* we handle 4 byte IDs at max */
- case GST_EBML_ID_EBMLMAXIDLENGTH:{
- guint64 num;
-
- ret = gst_ebml_read_uint (ebml, &id, &num);
- if (ret != GST_FLOW_OK)
- return ret;
- g_assert (id == GST_EBML_ID_EBMLMAXIDLENGTH);
- if (num > sizeof (guint32)) {
- GST_ERROR_OBJECT (ebml,
- "Unsupported EBML maximum ID %" G_GUINT64_FORMAT, num);
- return GST_FLOW_ERROR;
- }
- GST_DEBUG_OBJECT (ebml, "EbmlMaxIdLength: %" G_GUINT64_FORMAT, num);
- break;
- }
-
- case GST_EBML_ID_DOCTYPE:{
- gchar *text;
-
- ret = gst_ebml_read_ascii (ebml, &id, &text);
- if (ret != GST_FLOW_OK)
- return ret;
- g_assert (id == GST_EBML_ID_DOCTYPE);
-
- GST_DEBUG_OBJECT (ebml, "EbmlDocType: %s", GST_STR_NULL (text));
-
- if (doctype) {
- g_free (*doctype);
- *doctype = text;
- } else
- g_free (text);
- break;
- }
-
- case GST_EBML_ID_DOCTYPEREADVERSION:{
- guint64 num;
-
- ret = gst_ebml_read_uint (ebml, &id, &num);
- if (ret != GST_FLOW_OK)
- return ret;
- g_assert (id == GST_EBML_ID_DOCTYPEREADVERSION);
- if (version)
- *version = num;
- GST_DEBUG_OBJECT (ebml, "EbmlReadVersion: %" G_GUINT64_FORMAT, num);
- break;
- }
-
- default:
- GST_WARNING_OBJECT (ebml,
- "Unknown data type 0x%x in EBML header (ignored)", id);
- /* pass-through */
-
- /* we ignore these two, as they don't tell us anything we care about */
- case GST_EBML_ID_EBMLVERSION:
- case GST_EBML_ID_DOCTYPEVERSION:
- ret = gst_ebml_read_skip (ebml);
- if (ret != GST_FLOW_OK)
- return ret;
- break;
- }
- }
-
- return GST_FLOW_OK;
-}