/* GStreamer byte reader
*
* Copyright (C) 2008 Sebastian Dröge <sebastian.droege@collabora.co.uk>.
- * Copyright (C) 2009 Tim-Philipp Müller <tim centricular net>
+ * Copyright (C) 2009,2014 Tim-Philipp Müller <tim centricular net>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
/**
* SECTION:gstbytereader
+ * @title: GstByteReader
* @short_description: Reads different integer, string and floating point
* types from a memory buffer
*
*/
/**
- * gst_byte_reader_new:
+ * gst_byte_reader_new: (skip)
* @data: (in) (transfer none) (array length=size): data from which the
* #GstByteReader should read
* @size: Size of @data in bytes
* Free-function: gst_byte_reader_free
*
* Returns: (transfer full): a new #GstByteReader instance
- *
- * Since: 0.10.22
*/
GstByteReader *
gst_byte_reader_new (const guint8 * data, guint size)
*
* Frees a #GstByteReader instance, which was previously allocated by
* gst_byte_reader_new().
- *
- * Since: 0.10.22
*/
void
gst_byte_reader_free (GstByteReader * reader)
*
* Initializes a #GstByteReader instance to read from @data. This function
* can be called on already initialized instances.
- *
- * Since: 0.10.22
*/
void
gst_byte_reader_init (GstByteReader * reader, const guint8 * data, guint size)
}
/**
+ * gst_byte_reader_peek_sub_reader: (skip)
+ * @reader: an existing and initialized #GstByteReader instance
+ * @sub_reader: a #GstByteReader instance to initialize as sub-reader
+ * @size: size of @sub_reader in bytes
+ *
+ * Initializes a #GstByteReader sub-reader instance to contain @size bytes of
+ * data from the current position of @reader. This is useful to read chunked
+ * formats and make sure that one doesn't read beyond the size of the sub-chunk.
+ *
+ * Unlike gst_byte_reader_get_sub_reader(), this function does not modify the
+ * current position of @reader.
+ *
+ * Returns: FALSE on error or if @reader does not contain @size more bytes from
+ * the current position, and otherwise TRUE
+ *
+ * Since: 1.6
+ */
+gboolean
+gst_byte_reader_peek_sub_reader (GstByteReader * reader,
+ GstByteReader * sub_reader, guint size)
+{
+ return _gst_byte_reader_peek_sub_reader_inline (reader, sub_reader, size);
+}
+
+/**
+ * gst_byte_reader_get_sub_reader: (skip)
+ * @reader: an existing and initialized #GstByteReader instance
+ * @sub_reader: a #GstByteReader instance to initialize as sub-reader
+ * @size: size of @sub_reader in bytes
+ *
+ * Initializes a #GstByteReader sub-reader instance to contain @size bytes of
+ * data from the current position of @reader. This is useful to read chunked
+ * formats and make sure that one doesn't read beyond the size of the sub-chunk.
+ *
+ * Unlike gst_byte_reader_peek_sub_reader(), this function also modifies the
+ * position of @reader and moves it forward by @size bytes.
+ *
+ * Returns: FALSE on error or if @reader does not contain @size more bytes from
+ * the current position, and otherwise TRUE
+ *
+ * Since: 1.6
+ */
+gboolean
+gst_byte_reader_get_sub_reader (GstByteReader * reader,
+ GstByteReader * sub_reader, guint size)
+{
+ return _gst_byte_reader_get_sub_reader_inline (reader, sub_reader, size);
+}
+
+/**
* gst_byte_reader_set_pos:
* @reader: a #GstByteReader instance
* @pos: The new position in bytes
*
* Returns: %TRUE if the position could be set successfully, %FALSE
* otherwise.
- *
- * Since: 0.10.22
*/
gboolean
gst_byte_reader_set_pos (GstByteReader * reader, guint pos)
* Returns the current position of a #GstByteReader instance in bytes.
*
* Returns: The current position of @reader in bytes.
- *
- * Since: 0.10.22
*/
guint
gst_byte_reader_get_pos (const GstByteReader * reader)
* Returns the remaining number of bytes of a #GstByteReader instance.
*
* Returns: The remaining number of bytes of @reader instance.
- *
- * Since: 0.10.22
*/
guint
gst_byte_reader_get_remaining (const GstByteReader * reader)
* Returns the total number of bytes of a #GstByteReader instance.
*
* Returns: The total number of bytes of @reader instance.
- *
- * Since: 0.10.26
*/
guint
gst_byte_reader_get_size (const GstByteReader * reader)
* Skips @nbytes bytes of the #GstByteReader instance.
*
* Returns: %TRUE if @nbytes bytes could be skipped, %FALSE otherwise.
- *
- * Since: 0.10.22
*/
gboolean
gst_byte_reader_skip (GstByteReader * reader, guint nbytes)
* Read an unsigned 8 bit integer into @val and update the current position.
*
* Returns: %TRUE if successful, %FALSE otherwise.
- *
- * Since: 0.10.22
*/
/**
* Read a signed 8 bit integer into @val and update the current position.
*
* Returns: %TRUE if successful, %FALSE otherwise.
- *
- * Since: 0.10.22
*/
/**
* Read an unsigned 8 bit integer into @val but keep the current position.
*
* Returns: %TRUE if successful, %FALSE otherwise.
- *
- * Since: 0.10.22
*/
/**
* Read a signed 8 bit integer into @val but keep the current position.
*
* Returns: %TRUE if successful, %FALSE otherwise.
- *
- * Since: 0.10.22
*/
/**
* and update the current position.
*
* Returns: %TRUE if successful, %FALSE otherwise.
- *
- * Since: 0.10.22
*/
/**
* and update the current position.
*
* Returns: %TRUE if successful, %FALSE otherwise.
- *
- * Since: 0.10.22
*/
/**
* but keep the current position.
*
* Returns: %TRUE if successful, %FALSE otherwise.
- *
- * Since: 0.10.22
*/
/**
* but keep the current position.
*
* Returns: %TRUE if successful, %FALSE otherwise.
- *
- * Since: 0.10.22
*/
/**
* and update the current position.
*
* Returns: %TRUE if successful, %FALSE otherwise.
- *
- * Since: 0.10.22
*/
/**
* and update the current position.
*
* Returns: %TRUE if successful, %FALSE otherwise.
- *
- * Since: 0.10.22
*/
/**
* but keep the current position.
*
* Returns: %TRUE if successful, %FALSE otherwise.
- *
- * Since: 0.10.22
*/
/**
* but keep the current position.
*
* Returns: %TRUE if successful, %FALSE otherwise.
- *
- * Since: 0.10.22
*/
/**
* and update the current position.
*
* Returns: %TRUE if successful, %FALSE otherwise.
- *
- * Since: 0.10.22
*/
/**
* and update the current position.
*
* Returns: %TRUE if successful, %FALSE otherwise.
- *
- * Since: 0.10.22
*/
/**
* but keep the current position.
*
* Returns: %TRUE if successful, %FALSE otherwise.
- *
- * Since: 0.10.22
*/
/**
* but keep the current position.
*
* Returns: %TRUE if successful, %FALSE otherwise.
- *
- * Since: 0.10.22
*/
/**
* and update the current position.
*
* Returns: %TRUE if successful, %FALSE otherwise.
- *
- * Since: 0.10.22
*/
/**
* and update the current position.
*
* Returns: %TRUE if successful, %FALSE otherwise.
- *
- * Since: 0.10.22
*/
/**
* but keep the current position.
*
* Returns: %TRUE if successful, %FALSE otherwise.
- *
- * Since: 0.10.22
*/
/**
* but keep the current position.
*
* Returns: %TRUE if successful, %FALSE otherwise.
- *
- * Since: 0.10.22
*/
* and update the current position.
*
* Returns: %TRUE if successful, %FALSE otherwise.
- *
- * Since: 0.10.22
*/
/**
* and update the current position.
*
* Returns: %TRUE if successful, %FALSE otherwise.
- *
- * Since: 0.10.22
*/
/**
* but keep the current position.
*
* Returns: %TRUE if successful, %FALSE otherwise.
- *
- * Since: 0.10.22
*/
/**
* but keep the current position.
*
* Returns: %TRUE if successful, %FALSE otherwise.
- *
- * Since: 0.10.22
*/
/**
* and update the current position.
*
* Returns: %TRUE if successful, %FALSE otherwise.
- *
- * Since: 0.10.22
*/
/**
* and update the current position.
*
* Returns: %TRUE if successful, %FALSE otherwise.
- *
- * Since: 0.10.22
*/
/**
* but keep the current position.
*
* Returns: %TRUE if successful, %FALSE otherwise.
- *
- * Since: 0.10.22
*/
/**
* but keep the current position.
*
* Returns: %TRUE if successful, %FALSE otherwise.
- *
- * Since: 0.10.22
*/
/**
* and update the current position.
*
* Returns: %TRUE if successful, %FALSE otherwise.
- *
- * Since: 0.10.22
*/
/**
* and update the current position.
*
* Returns: %TRUE if successful, %FALSE otherwise.
- *
- * Since: 0.10.22
*/
/**
* but keep the current position.
*
* Returns: %TRUE if successful, %FALSE otherwise.
- *
- * Since: 0.10.22
*/
/**
* but keep the current position.
*
* Returns: %TRUE if successful, %FALSE otherwise.
- *
- * Since: 0.10.22
*/
/**
* and update the current position.
*
* Returns: %TRUE if successful, %FALSE otherwise.
- *
- * Since: 0.10.22
*/
/**
* and update the current position.
*
* Returns: %TRUE if successful, %FALSE otherwise.
- *
- * Since: 0.10.22
*/
/**
* but keep the current position.
*
* Returns: %TRUE if successful, %FALSE otherwise.
- *
- * Since: 0.10.22
*/
/**
* but keep the current position.
*
* Returns: %TRUE if successful, %FALSE otherwise.
- *
- * Since: 0.10.22
*/
#define GST_BYTE_READER_PEEK_GET(bits,type,name) \
* and update the current position.
*
* Returns: %TRUE if successful, %FALSE otherwise.
- *
- * Since: 0.10.22
*/
/**
* but keep the current position.
*
* Returns: %TRUE if successful, %FALSE otherwise.
- *
- * Since: 0.10.22
*/
/**
* and update the current position.
*
* Returns: %TRUE if successful, %FALSE otherwise.
- *
- * Since: 0.10.22
*/
/**
* but keep the current position.
*
* Returns: %TRUE if successful, %FALSE otherwise.
- *
- * Since: 0.10.22
*/
/**
* and update the current position.
*
* Returns: %TRUE if successful, %FALSE otherwise.
- *
- * Since: 0.10.22
*/
/**
* but keep the current position.
*
* Returns: %TRUE if successful, %FALSE otherwise.
- *
- * Since: 0.10.22
*/
/**
* and update the current position.
*
* Returns: %TRUE if successful, %FALSE otherwise.
- *
- * Since: 0.10.22
*/
/**
* but keep the current position.
*
* Returns: %TRUE if successful, %FALSE otherwise.
- *
- * Since: 0.10.22
*/
GST_BYTE_READER_PEEK_GET(32,gfloat,float32_le)
* position if at least @size bytes are left and
* updates the current position.
*
- *
* Returns: %TRUE if successful, %FALSE otherwise.
- *
- * Since: 0.10.22
*/
gboolean
gst_byte_reader_get_data (GstByteReader * reader, guint size,
* position if at least @size bytes are left and
* keeps the current position.
*
- *
* Returns: %TRUE if successful, %FALSE otherwise.
- *
- * Since: 0.10.22
*/
gboolean
gst_byte_reader_peek_data (const GstByteReader * reader, guint size,
* updates the current position. Free with g_free() when no longer needed.
*
* Returns: %TRUE if successful, %FALSE otherwise.
- *
- * Since: 0.10.24
*/
gboolean
gst_byte_reader_dup_data (GstByteReader * reader, guint size, guint8 ** val)
return _gst_byte_reader_dup_data_inline (reader, size, val);
}
+/* Special optimized scan for mask 0xffffff00 and pattern 0x00000100 */
+static inline gint
+_scan_for_start_code (const guint8 * data, guint offset, guint size)
+{
+ guint8 *pdata = (guint8 *) data;
+ guint8 *pend = (guint8 *) (data + size - 4);
+
+ while (pdata <= pend) {
+ if (pdata[2] > 1) {
+ pdata += 3;
+ } else if (pdata[1]) {
+ pdata += 2;
+ } else if (pdata[0] || pdata[2] != 1) {
+ pdata++;
+ } else {
+ return (pdata - data + offset);
+ }
+ }
+
+ /* nothing found */
+ return -1;
+}
+
+static inline guint
+_masked_scan_uint32_peek (const GstByteReader * reader,
+ guint32 mask, guint32 pattern, guint offset, guint size, guint32 * value)
+{
+ const guint8 *data;
+ guint32 state;
+ guint i;
+
+ g_return_val_if_fail (size > 0, -1);
+ g_return_val_if_fail ((guint64) offset + size <= reader->size - reader->byte,
+ -1);
+
+ /* we can't find the pattern with less than 4 bytes */
+ if (G_UNLIKELY (size < 4))
+ return -1;
+
+ data = reader->data + reader->byte + offset;
+
+ /* Handle special case found in MPEG and H264 */
+ if ((pattern == 0x00000100) && (mask == 0xffffff00)) {
+ guint ret = _scan_for_start_code (data, offset, size);
+ if (G_UNLIKELY (value))
+ *value = (1 << 8) | data[ret + 3];
+ return ret;
+ }
+
+ /* set the state to something that does not match */
+ state = ~pattern;
+
+ /* now find data */
+ for (i = 0; i < size; i++) {
+ /* throw away one byte and move in the next byte */
+ state = ((state << 8) | data[i]);
+ if (G_UNLIKELY ((state & mask) == pattern)) {
+ /* we have a match but we need to have skipped at
+ * least 4 bytes to fill the state. */
+ if (G_LIKELY (i >= 3)) {
+ if (value)
+ *value = state;
+ return offset + i - 3;
+ }
+ }
+ }
+
+ /* nothing found */
+ return -1;
+}
+
+
/**
* gst_byte_reader_masked_scan_uint32:
* @reader: a #GstByteReader
* Returns: offset of the first match, or -1 if no match was found.
*
* Example:
- * <programlisting>
+ * |[
* // Assume the reader contains 0x00 0x01 0x02 ... 0xfe 0xff
*
* gst_byte_reader_masked_scan_uint32 (reader, 0xffffffff, 0x00010203, 0, 256);
* // -> returns 2
* gst_byte_reader_masked_scan_uint32 (reader, 0xffff0000, 0x02030000, 0, 4);
* // -> returns -1
- * </programlisting>
- *
- * Since: 0.10.24
+ * ]|
*/
guint
gst_byte_reader_masked_scan_uint32 (const GstByteReader * reader, guint32 mask,
guint32 pattern, guint offset, guint size)
{
- const guint8 *data;
- guint32 state;
- guint i;
-
- g_return_val_if_fail (size > 0, -1);
- g_return_val_if_fail ((guint64) offset + size <= reader->size - reader->byte,
- -1);
-
- /* we can't find the pattern with less than 4 bytes */
- if (G_UNLIKELY (size < 4))
- return -1;
-
- data = reader->data + reader->byte + offset;
-
- /* set the state to something that does not match */
- state = ~pattern;
-
- /* now find data */
- for (i = 0; i < size; i++) {
- /* throw away one byte and move in the next byte */
- state = ((state << 8) | data[i]);
- if (G_UNLIKELY ((state & mask) == pattern)) {
- /* we have a match but we need to have skipped at
- * least 4 bytes to fill the state. */
- if (G_LIKELY (i >= 3))
- return offset + i - 3;
- }
- }
+ return _masked_scan_uint32_peek (reader, mask, pattern, offset, size, NULL);
+}
- /* nothing found */
- return -1;
+/**
+ * gst_byte_reader_masked_scan_uint32_peek:
+ * @reader: a #GstByteReader
+ * @mask: mask to apply to data before matching against @pattern
+ * @pattern: pattern to match (after mask is applied)
+ * @offset: offset from which to start scanning, relative to the current
+ * position
+ * @size: number of bytes to scan from offset
+ * @value: pointer to uint32 to return matching data
+ *
+ * Scan for pattern @pattern with applied mask @mask in the byte reader data,
+ * starting from offset @offset relative to the current position.
+ *
+ * The bytes in @pattern and @mask are interpreted left-to-right, regardless
+ * of endianness. All four bytes of the pattern must be present in the
+ * byte reader data for it to match, even if the first or last bytes are masked
+ * out.
+ *
+ * It is an error to call this function without making sure that there is
+ * enough data (offset+size bytes) in the byte reader.
+ *
+ * Returns: offset of the first match, or -1 if no match was found.
+ *
+ * Since: 1.6
+ */
+guint
+gst_byte_reader_masked_scan_uint32_peek (const GstByteReader * reader,
+ guint32 mask, guint32 pattern, guint offset, guint size, guint32 * value)
+{
+ return _masked_scan_uint32_peek (reader, mask, pattern, offset, size, value);
}
#define GST_BYTE_READER_SCAN_STRING(bits) \
* This function will fail if no NUL-terminator was found in in the data.
*
* Returns: %TRUE if a string could be skipped, %FALSE otherwise.
- *
- * Since: 0.10.24
*/
/**
* gst_byte_reader_skip_string_utf8:
* This function will fail if no NUL-terminator was found in in the data.
*
* Returns: %TRUE if a string could be skipped, %FALSE otherwise.
- *
- * Since: 0.10.24
*/
GST_BYTE_READER_SKIP_STRING (8);
* This function will fail if no NUL-terminator was found in in the data.
*
* Returns: %TRUE if a string could be skipped, %FALSE otherwise.
- *
- * Since: 0.10.24
*/
GST_BYTE_READER_SKIP_STRING (16);
* This function will fail if no NUL-terminator was found in in the data.
*
* Returns: %TRUE if a string could be skipped, %FALSE otherwise.
- *
- * Since: 0.10.24
*/
GST_BYTE_READER_SKIP_STRING (32);
* gst_byte_reader_peek_string:
* @reader: a #GstByteReader instance
* @str: (out) (transfer none) (array zero-terminated=1): address of a
- * #gchar pointer varieble in which to store the result
+ * #gchar pointer variable in which to store the result
*
* Returns a constant pointer to the current data position if there is
* a NUL-terminated string in the data (this could be just a NUL terminator).
* This function will fail if no NUL-terminator was found in in the data.
*
* Returns: %TRUE if a string could be skipped, %FALSE otherwise.
- *
- * Since: 0.10.24
*/
/**
* gst_byte_reader_peek_string_utf8:
* @reader: a #GstByteReader instance
* @str: (out) (transfer none) (array zero-terminated=1): address of a
- * #gchar pointer varieble in which to store the result
+ * #gchar pointer variable in which to store the result
*
* Returns a constant pointer to the current data position if there is
* a NUL-terminated string in the data (this could be just a NUL terminator).
* This function will fail if no NUL-terminator was found in in the data.
*
* Returns: %TRUE if a string could be skipped, %FALSE otherwise.
- *
- * Since: 0.10.24
*/
gboolean
gst_byte_reader_peek_string_utf8 (const GstByteReader * reader,
* gst_byte_reader_get_string_utf8:
* @reader: a #GstByteReader instance
* @str: (out) (transfer none) (array zero-terminated=1): address of a
- * #gchar pointer varieble in which to store the result
+ * #gchar pointer variable in which to store the result
*
* Returns a constant pointer to the current data position if there is
* a NUL-terminated string in the data (this could be just a NUL terminator),
* This function will fail if no NUL-terminator was found in in the data.
*
* Returns: %TRUE if a string could be found, %FALSE otherwise.
- *
- * Since: 0.10.24
*/
gboolean
gst_byte_reader_get_string_utf8 (GstByteReader * reader, const gchar ** str)
* gst_byte_reader_dup_string_utf8:
* @reader: a #GstByteReader instance
* @str: (out) (transfer full) (array zero-terminated=1): address of a
- * #gchar pointer varieble in which to store the result
+ * #gchar pointer variable in which to store the result
*
* Free-function: g_free
*
*
* Returns: %TRUE if a string could be read into @str, %FALSE otherwise. The
* string put into @str must be freed with g_free() when no longer needed.
- *
- * Since: 0.10.24
*/
GST_BYTE_READER_DUP_STRING (8, gchar);
* gst_byte_reader_dup_string_utf16:
* @reader: a #GstByteReader instance
* @str: (out) (transfer full) (array zero-terminated=1): address of a
- * #guint16 pointer varieble in which to store the result
+ * #guint16 pointer variable in which to store the result
*
* Free-function: g_free
*
*
* Returns: %TRUE if a string could be read, %FALSE otherwise. The
* string put into @str must be freed with g_free() when no longer needed.
- *
- * Since: 0.10.24
*/
GST_BYTE_READER_DUP_STRING (16, guint16);
* gst_byte_reader_dup_string_utf32:
* @reader: a #GstByteReader instance
* @str: (out) (transfer full) (array zero-terminated=1): address of a
- * #guint32 pointer varieble in which to store the result
+ * #guint32 pointer variable in which to store the result
*
* Free-function: g_free
*
*
* Returns: %TRUE if a string could be read, %FALSE otherwise. The
* string put into @str must be freed with g_free() when no longer needed.
- *
- * Since: 0.10.24
*/
GST_BYTE_READER_DUP_STRING (32, guint32);