Add bit reader and byte reader classes, including documentation and an extensive...
authorSebastian Dröge <slomo@circular-chaos.org>
Mon, 6 Oct 2008 12:41:53 +0000 (12:41 +0000)
committerSebastian Dröge <slomo@circular-chaos.org>
Mon, 6 Oct 2008 12:41:53 +0000 (12:41 +0000)
Original commit message from CVS:
* docs/libs/gstreamer-libs-docs.sgml:
* docs/libs/gstreamer-libs-sections.txt:
* libs/gst/base/Makefile.am:
* libs/gst/base/gstbitreader.c: (gst_bit_reader_new),
(gst_bit_reader_new_from_buffer), (gst_bit_reader_free),
(gst_bit_reader_init), (gst_bit_reader_init_from_buffer),
(gst_bit_reader_set_pos), (gst_bit_reader_get_pos),
(gst_bit_reader_get_remaining), (gst_bit_reader_skip),
(gst_bit_reader_skip_to_byte):
* libs/gst/base/gstbitreader.h:
* libs/gst/base/gstbytereader.c: (GDOUBLE_SWAP_LE_BE),
(GFLOAT_SWAP_LE_BE), (gst_byte_reader_new),
(gst_byte_reader_new_from_buffer), (gst_byte_reader_free),
(gst_byte_reader_init), (gst_byte_reader_init_from_buffer),
(gst_byte_reader_set_pos), (gst_byte_reader_get_pos),
(gst_byte_reader_get_remaining), (gst_byte_reader_skip),
(gst_byte_reader_get_uint8), (gst_byte_reader_get_int8),
(gst_byte_reader_peek_uint8), (gst_byte_reader_peek_int8),
(gst_byte_reader_get_uint24_le), (gst_byte_reader_get_uint24_be),
(gst_byte_reader_get_int24_le), (gst_byte_reader_get_int24_be),
(gst_byte_reader_peek_uint24_le), (gst_byte_reader_peek_uint24_be),
(gst_byte_reader_peek_int24_le), (gst_byte_reader_peek_int24_be):
* libs/gst/base/gstbytereader.h:
* tests/check/Makefile.am:
* tests/check/libs/bitreader.c: (GST_START_TEST),
(gst_bit_reader_suite):
* tests/check/libs/bytereader.c: (GST_START_TEST),
(gst_byte_reader_suite):
Add bit reader and byte reader classes, including documentation
and an extensive unit test suite. Fixes bug #553554.

ChangeLog
docs/libs/gstreamer-libs-docs.sgml
docs/libs/gstreamer-libs-sections.txt
libs/gst/base/Makefile.am
libs/gst/base/gstbitreader.c [new file with mode: 0644]
libs/gst/base/gstbitreader.h [new file with mode: 0644]
libs/gst/base/gstbytereader.c [new file with mode: 0644]
libs/gst/base/gstbytereader.h [new file with mode: 0644]
tests/check/Makefile.am
tests/check/libs/bitreader.c [new file with mode: 0644]
tests/check/libs/bytereader.c [new file with mode: 0644]

index f249bc4..235b1cc 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,36 @@
+2008-10-06  Sebastian Dröge  <sebastian.droege@collabora.co.uk>
+
+       * docs/libs/gstreamer-libs-docs.sgml:
+       * docs/libs/gstreamer-libs-sections.txt:
+       * libs/gst/base/Makefile.am:
+       * libs/gst/base/gstbitreader.c: (gst_bit_reader_new),
+       (gst_bit_reader_new_from_buffer), (gst_bit_reader_free),
+       (gst_bit_reader_init), (gst_bit_reader_init_from_buffer),
+       (gst_bit_reader_set_pos), (gst_bit_reader_get_pos),
+       (gst_bit_reader_get_remaining), (gst_bit_reader_skip),
+       (gst_bit_reader_skip_to_byte):
+       * libs/gst/base/gstbitreader.h:
+       * libs/gst/base/gstbytereader.c: (GDOUBLE_SWAP_LE_BE),
+       (GFLOAT_SWAP_LE_BE), (gst_byte_reader_new),
+       (gst_byte_reader_new_from_buffer), (gst_byte_reader_free),
+       (gst_byte_reader_init), (gst_byte_reader_init_from_buffer),
+       (gst_byte_reader_set_pos), (gst_byte_reader_get_pos),
+       (gst_byte_reader_get_remaining), (gst_byte_reader_skip),
+       (gst_byte_reader_get_uint8), (gst_byte_reader_get_int8),
+       (gst_byte_reader_peek_uint8), (gst_byte_reader_peek_int8),
+       (gst_byte_reader_get_uint24_le), (gst_byte_reader_get_uint24_be),
+       (gst_byte_reader_get_int24_le), (gst_byte_reader_get_int24_be),
+       (gst_byte_reader_peek_uint24_le), (gst_byte_reader_peek_uint24_be),
+       (gst_byte_reader_peek_int24_le), (gst_byte_reader_peek_int24_be):
+       * libs/gst/base/gstbytereader.h:
+       * tests/check/Makefile.am:
+       * tests/check/libs/bitreader.c: (GST_START_TEST),
+       (gst_bit_reader_suite):
+       * tests/check/libs/bytereader.c: (GST_START_TEST),
+       (gst_byte_reader_suite):
+       Add bit reader and byte reader classes, including documentation
+       and an extensive unit test suite. Fixes bug #553554.
+
 2008-10-06  Wim Taymans  <wim.taymans@collabora.co.uk>
 
        * libs/gst/base/gstbasesink.c: (gst_base_sink_get_position),
index ce0c597..3daaa2d 100644 (file)
@@ -8,6 +8,8 @@
 <!ENTITY GstBaseSrc SYSTEM "xml/gstbasesrc.xml">
 <!ENTITY GstBaseSink SYSTEM "xml/gstbasesink.xml">
 <!ENTITY GstBaseTransform SYSTEM "xml/gstbasetransform.xml">
+<!ENTITY GstBitReader SYSTEM "xml/gstbitreader.xml">
+<!ENTITY GstByteReader SYSTEM "xml/gstbytereader.xml">
 <!ENTITY GstCollectPads SYSTEM "xml/gstcollectpads.xml">
 <!ENTITY GstPushSrc SYSTEM "xml/gstpushsrc.xml">
 <!ENTITY GstTypeFindHelper SYSTEM "xml/gsttypefindhelper.xml">
@@ -64,6 +66,8 @@
       &GstPushSrc;
 
       &GstAdapter;
+      &GstBitReader;
+      &GstByteReader;
       &GstCollectPads;
       &GstTypeFindHelper;
       &GstDataQueue;
index 1efd3a3..385026a 100644 (file)
@@ -217,7 +217,6 @@ GST_ADAPTER_GET_CLASS
 gst_adapter_get_type
 </SECTION>
 
-
 <SECTION>
 <FILE>gstbasesrc</FILE>
 <TITLE>GstBaseSrc</TITLE>
@@ -333,6 +332,112 @@ gst_base_transform_get_type
 
 
 <SECTION>
+<FILE>gstbitreader</FILE>
+<TITLE>GstBitReader</TITLE>
+<INCLUDE>gst/base/gstbitreader.h</INCLUDE>
+GstBitReader
+
+GST_BIT_READER_INIT
+GST_BIT_READER_INIT_FROM_BUFFER
+
+gst_bit_reader_new
+gst_bit_reader_new_from_buffer
+gst_bit_reader_free
+
+gst_bit_reader_init
+gst_bit_reader_init_from_buffer
+
+gst_bit_reader_get_pos
+gst_bit_reader_get_remaining
+gst_bit_reader_set_pos
+gst_bit_reader_skip
+gst_bit_reader_skip_to_byte
+
+gst_bit_reader_get_bits_uint16
+gst_bit_reader_get_bits_uint32
+gst_bit_reader_get_bits_uint64
+gst_bit_reader_get_bits_uint8
+
+gst_bit_reader_peek_bits_uint16
+gst_bit_reader_peek_bits_uint32
+gst_bit_reader_peek_bits_uint64
+gst_bit_reader_peek_bits_uint8
+</SECTION>
+
+<SECTION>
+<FILE>gstbytereader</FILE>
+<TITLE>GstByteReader</TITLE>
+<INCLUDE>gst/base/gstbytereader.h</INCLUDE>
+GstByteReader
+
+GST_BYTE_READER_INIT
+GST_BYTE_READER_INIT_FROM_BUFFER
+
+gst_byte_reader_new
+gst_byte_reader_new_from_buffer
+gst_byte_reader_free
+
+gst_byte_reader_init
+gst_byte_reader_init_from_buffer
+
+gst_byte_reader_get_pos
+gst_byte_reader_get_remaining
+gst_byte_reader_set_pos
+gst_byte_reader_skip
+
+gst_byte_reader_get_int8
+gst_byte_reader_get_int16_be
+gst_byte_reader_get_int16_le
+gst_byte_reader_get_int24_be
+gst_byte_reader_get_int24_le
+gst_byte_reader_get_int32_be
+gst_byte_reader_get_int32_le
+gst_byte_reader_get_int64_be
+gst_byte_reader_get_int64_le
+
+gst_byte_reader_get_uint8
+gst_byte_reader_get_uint16_be
+gst_byte_reader_get_uint16_le
+gst_byte_reader_get_uint24_be
+gst_byte_reader_get_uint24_le
+gst_byte_reader_get_uint32_be
+gst_byte_reader_get_uint32_le
+gst_byte_reader_get_uint64_be
+gst_byte_reader_get_uint64_le
+
+gst_byte_reader_peek_int8
+gst_byte_reader_peek_int16_be
+gst_byte_reader_peek_int16_le
+gst_byte_reader_peek_int24_be
+gst_byte_reader_peek_int24_le
+gst_byte_reader_peek_int32_be
+gst_byte_reader_peek_int32_le
+gst_byte_reader_peek_int64_be
+gst_byte_reader_peek_int64_le
+
+gst_byte_reader_peek_uint8
+gst_byte_reader_peek_uint16_be
+gst_byte_reader_peek_uint16_le
+gst_byte_reader_peek_uint24_be
+gst_byte_reader_peek_uint24_le
+gst_byte_reader_peek_uint32_be
+gst_byte_reader_peek_uint32_le
+gst_byte_reader_peek_uint64_be
+gst_byte_reader_peek_uint64_le
+
+
+gst_byte_reader_get_float32_le
+gst_byte_reader_get_float32_be
+gst_byte_reader_get_float64_le
+gst_byte_reader_get_float64_be
+
+gst_byte_reader_peek_float32_le
+gst_byte_reader_peek_float32_be
+gst_byte_reader_peek_float64_le
+gst_byte_reader_peek_float64_be
+</SECTION>
+
+<SECTION>
 <FILE>gstcollectpads</FILE>
 <TITLE>GstCollectPads</TITLE>
 <INCLUDE>gst/base/gstcollectpads.h</INCLUDE>
index 0c72e5d..be657a8 100644 (file)
@@ -7,6 +7,8 @@ libgstbase_@GST_MAJORMINOR@_la_SOURCES = \
        gstbasesink.c           \
        gstbasesrc.c            \
        gstbasetransform.c      \
+       gstbitreader.c          \
+       gstbytereader.c         \
        gstcollectpads.c        \
        gstpushsrc.c            \
        gsttypefindhelper.c     \
@@ -24,6 +26,8 @@ libgstbase_@GST_MAJORMINOR@include_HEADERS =  \
        gstbasesink.h           \
        gstbasesrc.h            \
        gstbasetransform.h      \
+       gstbitreader.h          \
+       gstbytereader.h         \
        gstcollectpads.h        \
        gstpushsrc.h            \
        gsttypefindhelper.h     \
diff --git a/libs/gst/base/gstbitreader.c b/libs/gst/base/gstbitreader.c
new file mode 100644 (file)
index 0000000..7647ab9
--- /dev/null
@@ -0,0 +1,400 @@
+/* GStreamer
+ *
+ * Copyright (C) 2008 Sebastian Dröge <sebastian.droege@collabora.co.uk>.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstbitreader.h"
+
+#include <string.h>
+
+/**
+ * SECTION:gstbitreader
+ * @short_description: Reads any number of bits from a memory buffer
+ *
+ * #GstBitReader provides a bit reader that can read any number of bits
+ * from a memory buffer. It provides functions for reading any number of bits
+ * into 8, 16, 32 and 64 bit variables.
+ */
+
+/**
+ * gst_bit_reader_new:
+ * @data: Data from which the #GstBitReader should read
+ * @size: Size of @data in bytes
+ *
+ * Create a new #GstBitReader instance, which will read from @data.
+ *
+ * Returns: a new #GstBitReader instance
+ *
+ * Since: 0.10.22
+ */
+GstBitReader *
+gst_bit_reader_new (const guint8 * data, guint size)
+{
+  GstBitReader *ret = g_slice_new0 (GstBitReader);
+
+  ret->data = data;
+  ret->size = size;
+
+  return ret;
+}
+
+/**
+ * gst_bit_reader_new_from_buffer:
+ * @buffer: Buffer from which the #GstBitReader should read
+ *
+ * Create a new #GstBitReader instance, which will read from the
+ * #GstBuffer @buffer.
+ *
+ * Returns: a new #GstBitReader instance
+ *
+ * Since: 0.10.22
+ */
+GstBitReader *
+gst_bit_reader_new_from_buffer (const GstBuffer * buffer)
+{
+  g_return_val_if_fail (GST_IS_BUFFER (buffer), NULL);
+
+  return gst_bit_reader_new (GST_BUFFER_DATA (buffer),
+      GST_BUFFER_SIZE (buffer));
+}
+
+/**
+ * gst_bit_reader_free:
+ * @reader: a #GstBitReader instance
+ *
+ * Frees a #GstBitReader instance, which was previously allocated by
+ * gst_bit_reader_new() or gst_bit_reader_new_from_buffer().
+ * 
+ * Since: 0.10.22
+ */
+void
+gst_bit_reader_free (GstBitReader * reader)
+{
+  g_return_if_fail (reader != NULL);
+
+  g_slice_free (GstBitReader, reader);
+}
+
+/**
+ * gst_bit_reader_init:
+ * @reader: a #GstBitReader instance
+ * @data: Data from which the #GstBitReader should read
+ * @size: Size of @data in bytes
+ *
+ * Initializes a #GstBitReader instance to read from @data. This function
+ * can be called on already initialized instances.
+ * 
+ * Since: 0.10.22
+ */
+void
+gst_bit_reader_init (GstBitReader * reader, const guint8 * data, guint size)
+{
+  g_return_if_fail (reader != NULL);
+
+  reader->data = data;
+  reader->size = size;
+  reader->byte = reader->bit = 0;
+}
+
+/**
+ * gst_bit_reader_init:
+ * @reader: a #GstBitReader instance
+ * @buffer: Buffer from which the #GstBitReader should read
+ *
+ * Initializes a #GstBitReader instance to read from @buffer. This function
+ * can be called on already initialized instances.
+ * 
+ * Since: 0.10.22
+ */
+void
+gst_bit_reader_init_from_buffer (GstBitReader * reader,
+    const GstBuffer * buffer)
+{
+  g_return_if_fail (GST_IS_BUFFER (buffer));
+
+  gst_bit_reader_init (reader, GST_BUFFER_DATA (buffer),
+      GST_BUFFER_SIZE (buffer));
+}
+
+/**
+ * gst_bit_reader_set_pos:
+ * @reader: a #GstBitReader instance
+ * @pos: The new position in bits
+ *
+ * Sets the new position of a #GstBitReader instance to @pos in bits.
+ *
+ * Returns: %TRUE if the position could be set successfully, %FALSE
+ * otherwise.
+ * 
+ * Since: 0.10.22
+ */
+gboolean
+gst_bit_reader_set_pos (GstBitReader * reader, guint pos)
+{
+  g_return_val_if_fail (reader != NULL, FALSE);
+
+  if (pos > reader->size * 8)
+    return FALSE;
+
+  reader->byte = pos / 8;
+  reader->bit = pos % 8;
+
+  return TRUE;
+}
+
+/**
+ * gst_bit_reader_get_pos:
+ * @reader: a #GstBitReader instance
+ *
+ * Returns the current position of a #GstBitReader instance in bits.
+ *
+ * Returns: The current position of @reader in bits.
+ * 
+ * Since: 0.10.22
+ */
+guint
+gst_bit_reader_get_pos (const GstBitReader * reader)
+{
+  g_return_val_if_fail (reader != NULL, 0);
+
+  return reader->byte * 8 + reader->bit;
+}
+
+/**
+ * gst_bit_reader_get_remaining:
+ * @reader: a #GstBitReader instance
+ *
+ * Returns the remaining number of bits of a #GstBitReader instance.
+ *
+ * Returns: The remaining number of bits of @reader instance.
+ * 
+ * Since: 0.10.22
+ */
+guint
+gst_bit_reader_get_remaining (const GstBitReader * reader)
+{
+  g_return_val_if_fail (reader != NULL, 0);
+
+  return reader->size * 8 - (reader->byte * 8 + reader->bit);
+}
+
+/**
+ * gst_bit_reader_skip:
+ * @reader: a #GstBitReader instance
+ * @nbits: the number of bits to skip
+ *
+ * Skips @nbits bits of the #GstBitReader instance.
+ *
+ * Returns: %TRUE if @nbits bits could be skipped, %FALSE otherwise.
+ * 
+ * Since: 0.10.22
+ */
+gboolean
+gst_bit_reader_skip (GstBitReader * reader, guint nbits)
+{
+  g_return_val_if_fail (reader != NULL, FALSE);
+
+  if (gst_bit_reader_get_remaining (reader) < nbits)
+    return FALSE;
+
+  reader->bit += nbits;
+  reader->byte += reader->bit / 8;
+  reader->bit = reader->bit % 8;
+
+  return TRUE;
+}
+
+/**
+ * gst_bit_reader_skip_to_byte:
+ * @reader: a #GstBitReader instance
+ *
+ * Skips until the next byte.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ * 
+ * Since: 0.10.22
+ */
+gboolean
+gst_bit_reader_skip_to_byte (GstBitReader * reader)
+{
+  g_return_val_if_fail (reader != NULL, FALSE);
+
+  if (reader->byte > reader->size)
+    return FALSE;
+
+  if (reader->bit) {
+    reader->bit = 0;
+    reader->byte++;
+  }
+
+  return TRUE;
+}
+
+/**
+ * gst_bit_reader_get_bits_uint8:
+ * @reader: a #GstBitReader instance
+ * @val: Pointer to a #guint8 to store the result
+ * @nbits: number of bits to read
+ *
+ * Read @nbits bits into @val and update the current position.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ * 
+ * Since: 0.10.22
+ */
+
+/**
+ * gst_bit_reader_get_bits_uint16:
+ * @reader: a #GstBitReader instance
+ * @val: Pointer to a #guint16 to store the result
+ * @nbits: number of bits to read
+ *
+ * Read @nbits bits into @val and update the current position.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ * 
+ * Since: 0.10.22
+ */
+
+/**
+ * gst_bit_reader_get_bits_uint32:
+ * @reader: a #GstBitReader instance
+ * @val: Pointer to a #guint32 to store the result
+ * @nbits: number of bits to read
+ *
+ * Read @nbits bits into @val and update the current position.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ * 
+ * Since: 0.10.22
+ */
+
+/**
+ * gst_bit_reader_get_bits_uint64:
+ * @reader: a #GstBitReader instance
+ * @val: Pointer to a #guint64 to store the result
+ * @nbits: number of bits to read
+ *
+ * Read @nbits bits into @val and update the current position.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ * 
+ * Since: 0.10.22
+ */
+
+/**
+ * gst_bit_reader_peek_bits_uint8:
+ * @reader: a #GstBitReader instance
+ * @val: Pointer to a #guint8 to store the result
+ * @nbits: number of bits to read
+ *
+ * Read @nbits bits into @val but keep the current position.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ * 
+ * Since: 0.10.22
+ */
+
+/**
+ * gst_bit_reader_peek_bits_uint16:
+ * @reader: a #GstBitReader instance
+ * @val: Pointer to a #guint16 to store the result
+ * @nbits: number of bits to read
+ *
+ * Read @nbits bits into @val but keep the current position.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ * 
+ * Since: 0.10.22
+ */
+
+/**
+ * gst_bit_reader_peek_bits_uint32:
+ * @reader: a #GstBitReader instance
+ * @val: Pointer to a #guint32 to store the result
+ * @nbits: number of bits to read
+ *
+ * Read @nbits bits into @val but keep the current position.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ * 
+ * Since: 0.10.22
+ */
+
+/**
+ * gst_bit_reader_peek_bits_uint64:
+ * @reader: a #GstBitReader instance
+ * @val: Pointer to a #guint64 to store the result
+ * @nbits: number of bits to read
+ *
+ * Read @nbits bits into @val but keep the current position.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ * 
+ * Since: 0.10.22
+ */
+
+#define GST_BIT_READER_READ_BITS(bits) \
+gboolean \
+gst_bit_reader_get_bits_uint##bits (GstBitReader *reader, guint##bits *val, guint nbits) \
+{ \
+  guint##bits ret = 0; \
+  \
+  g_return_val_if_fail (reader != NULL, FALSE); \
+  g_return_val_if_fail (val != NULL, FALSE); \
+  g_return_val_if_fail (nbits <= bits, FALSE); \
+  \
+  if (reader->byte * 8 + reader->bit + nbits > reader->size * 8) \
+    return FALSE; \
+  \
+  while (nbits > 0) { \
+    guint toread = MIN (nbits, 8 - reader->bit); \
+    \
+    ret <<= toread; \
+    ret |= (reader->data[reader->byte] & (0xff >> reader->bit)) >> (8 - toread - reader->bit); \
+    \
+    reader->bit += toread; \
+    if (reader->bit >= 8) { \
+      reader->byte++; \
+      reader->bit = 0; \
+    } \
+    nbits -= toread; \
+  } \
+  \
+  *val = ret; \
+  return TRUE; \
+} \
+\
+gboolean \
+gst_bit_reader_peek_bits_uint##bits (const GstBitReader *reader, guint##bits *val, guint nbits) \
+{ \
+  GstBitReader tmp; \
+  \
+  g_return_val_if_fail (reader != NULL, FALSE); \
+  tmp = *reader; \
+  return gst_bit_reader_get_bits_uint##bits (&tmp, val, nbits); \
+}
+
+GST_BIT_READER_READ_BITS (8);
+GST_BIT_READER_READ_BITS (16);
+GST_BIT_READER_READ_BITS (32);
+GST_BIT_READER_READ_BITS (64);
diff --git a/libs/gst/base/gstbitreader.h b/libs/gst/base/gstbitreader.h
new file mode 100644 (file)
index 0000000..5dc16a3
--- /dev/null
@@ -0,0 +1,99 @@
+/* GStreamer
+ *
+ * Copyright (C) 2008 Sebastian Dröge <sebastian.droege@collabora.co.uk>.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * 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.
+ */
+
+#ifndef __GST_BIT_READER_H__
+#define __GST_BIT_READER_H__
+
+#include <gst/gst.h>
+
+G_BEGIN_DECLS
+
+/**
+ * GstBitReader:
+ * @data: Data from which the bit reader will read
+ * @size: Size of @data in bytes
+ * @byte: Current byte position
+ * @bit: Bit position in the current byte
+ *
+ * A bit reader instance.
+ */
+typedef struct {
+  const guint8 *data;
+  guint size;
+
+  guint byte;  /* Byte position */
+  guint bit;   /* Bit position in the current byte */
+} GstBitReader;
+
+GstBitReader * gst_bit_reader_new (const guint8 *data, guint size);
+GstBitReader * gst_bit_reader_new_from_buffer (const GstBuffer *buffer);
+void gst_bit_reader_free (GstBitReader *reader);
+
+void gst_bit_reader_init (GstBitReader *reader, const guint8 *data, guint size);
+void gst_bit_reader_init_from_buffer (GstBitReader *reader, const GstBuffer *buffer);
+
+gboolean gst_bit_reader_set_pos (GstBitReader *reader, guint pos);
+
+guint gst_bit_reader_get_pos (const GstBitReader *reader);
+guint gst_bit_reader_get_remaining (const GstBitReader *reader);
+
+gboolean gst_bit_reader_skip (GstBitReader *reader, guint nbits);
+gboolean gst_bit_reader_skip_to_byte (GstBitReader *reader);
+
+gboolean gst_bit_reader_get_bits_uint8 (GstBitReader *reader, guint8 *val, guint nbits);
+gboolean gst_bit_reader_get_bits_uint16 (GstBitReader *reader, guint16 *val, guint nbits);
+gboolean gst_bit_reader_get_bits_uint32 (GstBitReader *reader, guint32 *val, guint nbits);
+gboolean gst_bit_reader_get_bits_uint64 (GstBitReader *reader, guint64 *val, guint nbits);
+
+gboolean gst_bit_reader_peek_bits_uint8 (const GstBitReader *reader, guint8 *val, guint nbits);
+gboolean gst_bit_reader_peek_bits_uint16 (const GstBitReader *reader, guint16 *val, guint nbits);
+gboolean gst_bit_reader_peek_bits_uint32 (const GstBitReader *reader, guint32 *val, guint nbits);
+gboolean gst_bit_reader_peek_bits_uint64 (const GstBitReader *reader, guint64 *val, guint nbits);
+
+/**
+ * GST_BIT_READER_INIT:
+ * @data: Data from which the #GstBitReader should read
+ * @size: Size of @data in bytes
+ *
+ * A #GstBitReader must be initialized with this macro, before it can be
+ * used. This macro can used be to initialize a variable, but it cannot
+ * be assigned to a variable. In that case you have to use
+ * gst_bit_reader_init().
+ *
+ * Since: 0.10.22
+ */
+#define GST_BIT_READER_INIT(data, size) {data, size, 0, 0}
+
+/**
+ * GST_BIT_READER_INIT_FROM_BUFFER:
+ * @buffer: Buffer from which the #GstBitReader should read
+ *
+ * A #GstBitReader must be initialized with this macro, before it can be
+ * used. This macro can used be to initialize a variable, but it cannot
+ * be assigned to a variable. In that case you have to use
+ * gst_bit_reader_init().
+ *
+ * Since: 0.10.22
+ */
+#define GST_BIT_READER_INIT_FROM_BUFFER(buffer) {GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer), 0, 0}
+
+G_END_DECLS
+
+#endif /* __GST_BIT_READER_H__ */
diff --git a/libs/gst/base/gstbytereader.c b/libs/gst/base/gstbytereader.c
new file mode 100644 (file)
index 0000000..cb91ea7
--- /dev/null
@@ -0,0 +1,1231 @@
+/* GStreamer
+ *
+ * Copyright (C) 2008 Sebastian Dröge <sebastian.droege@collabora.co.uk>.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstbytereader.h"
+
+#include <string.h>
+
+/**
+ * SECTION:gstbytereader
+ * @short_description: Reads different integer and floating point types from a memory buffer
+ *
+ * #GstByteReader provides a byte reader that can read different integer and
+ * floating point types from a memory buffer. It provides functions for reading
+ * signed/unsigned, little/big endian integers of 8, 16, 24, 32 and 64 bits
+ * and functions for reading little/big endian floating points numbers of
+ * 32 and 64 bits.
+ */
+
+
+/* Copied from gst/floatcast/floatcast.h as this is in gst-plugins-base */
+
+inline static gdouble
+GDOUBLE_SWAP_LE_BE (gdouble in)
+{
+  union
+  {
+    guint64 i;
+    gdouble d;
+  } u;
+
+  u.d = in;
+  u.i = GUINT64_SWAP_LE_BE (u.i);
+  return u.d;
+}
+
+inline static gfloat
+GFLOAT_SWAP_LE_BE (gfloat in)
+{
+  union
+  {
+    guint32 i;
+    gfloat f;
+  } u;
+
+  u.f = in;
+  u.i = GUINT32_SWAP_LE_BE (u.i);
+  return u.f;
+}
+
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+#define GFLOAT_TO_LE(val)    ((gfloat) (val))
+#define GFLOAT_TO_BE(val)    (GFLOAT_SWAP_LE_BE (val))
+#define GDOUBLE_TO_LE(val)   ((gdouble) (val))
+#define GDOUBLE_TO_BE(val)   (GDOUBLE_SWAP_LE_BE (val))
+
+#elif G_BYTE_ORDER == G_BIG_ENDIAN
+#define GFLOAT_TO_LE(val)    (GFLOAT_SWAP_LE_BE (val))
+#define GFLOAT_TO_BE(val)    ((gfloat) (val))
+#define GDOUBLE_TO_LE(val)   (GDOUBLE_SWAP_LE_BE (val))
+#define GDOUBLE_TO_BE(val)   ((gdouble) (val))
+
+#else /* !G_LITTLE_ENDIAN && !G_BIG_ENDIAN */
+#error unknown ENDIAN type
+#endif /* !G_LITTLE_ENDIAN && !G_BIG_ENDIAN */
+
+#define GFLOAT_FROM_LE(val)  (GFLOAT_TO_LE (val))
+#define GFLOAT_FROM_BE(val)  (GFLOAT_TO_BE (val))
+#define GDOUBLE_FROM_LE(val) (GDOUBLE_TO_LE (val))
+#define GDOUBLE_FROM_BE(val) (GDOUBLE_TO_BE (val))
+
+
+/**
+ * gst_byte_reader_new:
+ * @data: Data from which the #GstByteReader should read
+ * @size: Size of @data in bytes
+ *
+ * Create a new #GstByteReader instance, which will read from @data.
+ *
+ * Returns: a new #GstByteReader instance
+ *
+ * Since: 0.10.22
+ */
+GstByteReader *
+gst_byte_reader_new (const guint8 * data, guint size)
+{
+  GstByteReader *ret = g_slice_new0 (GstByteReader);
+
+  ret->data = data;
+  ret->size = size;
+
+  return ret;
+}
+
+/**
+ * gst_byte_reader_new_from_buffer:
+ * @buffer: Buffer from which the #GstByteReader should read
+ *
+ * Create a new #GstByteReader instance, which will read from the
+ * #GstBuffer @buffer.
+ *
+ * Returns: a new #GstByteReader instance
+ *
+ * Since: 0.10.22
+ */
+GstByteReader *
+gst_byte_reader_new_from_buffer (const GstBuffer * buffer)
+{
+  g_return_val_if_fail (GST_IS_BUFFER (buffer), NULL);
+
+  return gst_byte_reader_new (GST_BUFFER_DATA (buffer),
+      GST_BUFFER_SIZE (buffer));
+}
+
+/**
+ * gst_byte_reader_free:
+ * @reader: a #GstByteReader instance
+ *
+ * Frees a #GstByteReader instance, which was previously allocated by
+ * gst_byte_reader_new() or gst_byte_reader_new_from_buffer().
+ * 
+ * Since: 0.10.22
+ */
+void
+gst_byte_reader_free (GstByteReader * reader)
+{
+  g_return_if_fail (reader != NULL);
+
+  g_slice_free (GstByteReader, reader);
+}
+
+/**
+ * gst_byte_reader_init:
+ * @reader: a #GstByteReader instance
+ * @data: Data from which the #GstByteReader should read
+ * @size: Size of @data in bytes
+ *
+ * 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)
+{
+  g_return_if_fail (reader != NULL);
+
+  reader->data = data;
+  reader->size = size;
+  reader->byte = 0;
+}
+
+/**
+ * gst_byte_reader_init:
+ * @reader: a #GstByteReader instance
+ * @buffer: Buffer from which the #GstByteReader should read
+ *
+ * Initializes a #GstByteReader instance to read from @buffer. This function
+ * can be called on already initialized instances.
+ * 
+ * Since: 0.10.22
+ */
+void
+gst_byte_reader_init_from_buffer (GstByteReader * reader,
+    const GstBuffer * buffer)
+{
+  g_return_if_fail (GST_IS_BUFFER (buffer));
+
+  gst_byte_reader_init (reader, GST_BUFFER_DATA (buffer),
+      GST_BUFFER_SIZE (buffer));
+}
+
+/**
+ * gst_byte_reader_set_pos:
+ * @reader: a #GstByteReader instance
+ * @pos: The new position in bytes
+ *
+ * Sets the new position of a #GstByteReader instance to @pos 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)
+{
+  g_return_val_if_fail (reader != NULL, FALSE);
+
+  if (pos > reader->size)
+    return FALSE;
+
+  reader->byte = pos;
+
+  return TRUE;
+}
+
+/**
+ * gst_byte_reader_get_pos:
+ * @reader: a #GstByteReader instance
+ *
+ * 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)
+{
+  g_return_val_if_fail (reader != NULL, 0);
+
+  return reader->byte;
+}
+
+/**
+ * gst_byte_reader_get_remaining:
+ * @reader: a #GstByteReader instance
+ *
+ * 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)
+{
+  g_return_val_if_fail (reader != NULL, 0);
+
+  return reader->size - reader->byte;
+}
+
+/**
+ * gst_byte_reader_skip:
+ * @reader: a #GstByteReader instance
+ * @nbytes: the number of bytes to skip
+ *
+ * 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)
+{
+  g_return_val_if_fail (reader != NULL, FALSE);
+
+  if (gst_byte_reader_get_remaining (reader) < nbytes)
+    return FALSE;
+
+  reader->byte += nbytes;
+
+  return TRUE;
+}
+
+/**
+ * gst_byte_reader_get_uint8:
+ * @reader: a #GstByteReader instance
+ * @val: Pointer to a #guint8 to store the result
+ *
+ * Read an unsigned 8 bit integer into @val and update the current position.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ * 
+ * Since: 0.10.22
+ */
+
+/**
+ * gst_byte_reader_get_int8:
+ * @reader: a #GstByteReader instance
+ * @val: Pointer to a #gint8 to store the result
+ *
+ * Read a signed 8 bit integer into @val and update the current position.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ * 
+ * Since: 0.10.22
+ */
+
+/**
+ * gst_byte_reader_peek_uint8:
+ * @reader: a #GstByteReader instance
+ * @val: Pointer to a #guint8 to store the result
+ *
+ * Read a signed 8 bit integer into @val but keep the current position.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ * 
+ * Since: 0.10.22
+ */
+
+/**
+ * gst_byte_reader_peek_int8:
+ * @reader: a #GstByteReader instance
+ * @val: Pointer to a #gint8 to store the result
+ *
+ * Read a signed 8 bit integer into @val but keep the current position.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ * 
+ * Since: 0.10.22
+ */
+
+/**
+ * gst_byte_reader_get_uint16_le:
+ * @reader: a #GstByteReader instance
+ * @val: Pointer to a #guint16 to store the result
+ *
+ * Read an unsigned 16 bit little endian integer into @val
+ * and update the current position.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ * 
+ * Since: 0.10.22
+ */
+
+/**
+ * gst_byte_reader_get_int16_le:
+ * @reader: a #GstByteReader instance
+ * @val: Pointer to a #gint16 to store the result
+ *
+ * Read a signed 16 bit little endian integer into @val
+ * and update the current position.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ * 
+ * Since: 0.10.22
+ */
+
+/**
+ * gst_byte_reader_peek_uint16_le:
+ * @reader: a #GstByteReader instance
+ * @val: Pointer to a #guint16 to store the result
+ *
+ * Read a signed 16 bit little endian integer into @val
+ * but keep the current position.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ * 
+ * Since: 0.10.22
+ */
+
+/**
+ * gst_byte_reader_peek_int16_le:
+ * @reader: a #GstByteReader instance
+ * @val: Pointer to a #gint16 to store the result
+ *
+ * Read a signed 16 bit little endian integer into @val
+ * but keep the current position.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ * 
+ * Since: 0.10.22
+ */
+
+/**
+ * gst_byte_reader_get_uint16_be:
+ * @reader: a #GstByteReader instance
+ * @val: Pointer to a #guint16 to store the result
+ *
+ * Read an unsigned 16 bit big endian integer into @val
+ * and update the current position.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ * 
+ * Since: 0.10.22
+ */
+
+/**
+ * gst_byte_reader_get_int16_be:
+ * @reader: a #GstByteReader instance
+ * @val: Pointer to a #gint16 to store the result
+ *
+ * Read a signed 16 bit big endian integer into @val
+ * and update the current position.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ * 
+ * Since: 0.10.22
+ */
+
+/**
+ * gst_byte_reader_peek_uint16_be:
+ * @reader: a #GstByteReader instance
+ * @val: Pointer to a #guint16 to store the result
+ *
+ * Read a signed 16 bit big endian integer into @val
+ * but keep the current position.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ * 
+ * Since: 0.10.22
+ */
+
+/**
+ * gst_byte_reader_peek_int16_be:
+ * @reader: a #GstByteReader instance
+ * @val: Pointer to a #gint16 to store the result
+ *
+ * Read a signed 16 bit big endian integer into @val
+ * but keep the current position.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ * 
+ * Since: 0.10.22
+ */
+
+/**
+ * gst_byte_reader_get_uint24_le:
+ * @reader: a #GstByteReader instance
+ * @val: Pointer to a #guint32 to store the result
+ *
+ * Read an unsigned 24 bit little endian integer into @val
+ * and update the current position.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ * 
+ * Since: 0.10.22
+ */
+
+/**
+ * gst_byte_reader_get_int24_le:
+ * @reader: a #GstByteReader instance
+ * @val: Pointer to a #gint32 to store the result
+ *
+ * Read a signed 24 bit little endian integer into @val
+ * and update the current position.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ * 
+ * Since: 0.10.22
+ */
+
+/**
+ * gst_byte_reader_peek_uint24_le:
+ * @reader: a #GstByteReader instance
+ * @val: Pointer to a #guint32 to store the result
+ *
+ * Read a signed 24 bit little endian integer into @val
+ * but keep the current position.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ * 
+ * Since: 0.10.22
+ */
+
+/**
+ * gst_byte_reader_peek_int24_le:
+ * @reader: a #GstByteReader instance
+ * @val: Pointer to a #gint32 to store the result
+ *
+ * Read a signed 24 bit little endian integer into @val
+ * but keep the current position.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ * 
+ * Since: 0.10.22
+ */
+
+/**
+ * gst_byte_reader_get_uint24_be:
+ * @reader: a #GstByteReader instance
+ * @val: Pointer to a #guint32 to store the result
+ *
+ * Read an unsigned 24 bit big endian integer into @val
+ * and update the current position.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ * 
+ * Since: 0.10.22
+ */
+
+/**
+ * gst_byte_reader_get_int24_be:
+ * @reader: a #GstByteReader instance
+ * @val: Pointer to a #gint32 to store the result
+ *
+ * Read a signed 24 bit big endian integer into @val
+ * and update the current position.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ * 
+ * Since: 0.10.22
+ */
+
+/**
+ * gst_byte_reader_peek_uint24_be:
+ * @reader: a #GstByteReader instance
+ * @val: Pointer to a #guint32 to store the result
+ *
+ * Read a signed 24 bit big endian integer into @val
+ * but keep the current position.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ * 
+ * Since: 0.10.22
+ */
+
+/**
+ * gst_byte_reader_peek_int24_be:
+ * @reader: a #GstByteReader instance
+ * @val: Pointer to a #gint32 to store the result
+ *
+ * Read a signed 24 bit big endian integer into @val
+ * but keep the current position.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ * 
+ * Since: 0.10.22
+ */
+
+
+/**
+ * gst_byte_reader_get_uint32_le:
+ * @reader: a #GstByteReader instance
+ * @val: Pointer to a #guint32 to store the result
+ *
+ * Read an unsigned 32 bit little endian integer into @val
+ * and update the current position.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ * 
+ * Since: 0.10.22
+ */
+
+/**
+ * gst_byte_reader_get_int32_le:
+ * @reader: a #GstByteReader instance
+ * @val: Pointer to a #gint32 to store the result
+ *
+ * Read a signed 32 bit little endian integer into @val
+ * and update the current position.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ * 
+ * Since: 0.10.22
+ */
+
+/**
+ * gst_byte_reader_peek_uint32_le:
+ * @reader: a #GstByteReader instance
+ * @val: Pointer to a #guint32 to store the result
+ *
+ * Read a signed 32 bit little endian integer into @val
+ * but keep the current position.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ * 
+ * Since: 0.10.22
+ */
+
+/**
+ * gst_byte_reader_peek_int32_le:
+ * @reader: a #GstByteReader instance
+ * @val: Pointer to a #gint32 to store the result
+ *
+ * Read a signed 32 bit little endian integer into @val
+ * but keep the current position.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ * 
+ * Since: 0.10.22
+ */
+
+/**
+ * gst_byte_reader_get_uint32_be:
+ * @reader: a #GstByteReader instance
+ * @val: Pointer to a #guint32 to store the result
+ *
+ * Read an unsigned 32 bit big endian integer into @val
+ * and update the current position.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ * 
+ * Since: 0.10.22
+ */
+
+/**
+ * gst_byte_reader_get_int32_be:
+ * @reader: a #GstByteReader instance
+ * @val: Pointer to a #gint32 to store the result
+ *
+ * Read a signed 32 bit big endian integer into @val
+ * and update the current position.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ * 
+ * Since: 0.10.22
+ */
+
+/**
+ * gst_byte_reader_peek_uint32_be:
+ * @reader: a #GstByteReader instance
+ * @val: Pointer to a #guint32 to store the result
+ *
+ * Read a signed 32 bit big endian integer into @val
+ * but keep the current position.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ * 
+ * Since: 0.10.22
+ */
+
+/**
+ * gst_byte_reader_peek_int32_be:
+ * @reader: a #GstByteReader instance
+ * @val: Pointer to a #gint32 to store the result
+ *
+ * Read a signed 32 bit big endian integer into @val
+ * but keep the current position.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ * 
+ * Since: 0.10.22
+ */
+
+/**
+ * gst_byte_reader_get_uint64_le:
+ * @reader: a #GstByteReader instance
+ * @val: Pointer to a #guint64 to store the result
+ *
+ * Read an unsigned 64 bit little endian integer into @val
+ * and update the current position.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ * 
+ * Since: 0.10.22
+ */
+
+/**
+ * gst_byte_reader_get_int64_le:
+ * @reader: a #GstByteReader instance
+ * @val: Pointer to a #gint64 to store the result
+ *
+ * Read a signed 64 bit little endian integer into @val
+ * and update the current position.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ * 
+ * Since: 0.10.22
+ */
+
+/**
+ * gst_byte_reader_peek_uint64_le:
+ * @reader: a #GstByteReader instance
+ * @val: Pointer to a #guint64 to store the result
+ *
+ * Read a signed 64 bit little endian integer into @val
+ * but keep the current position.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ * 
+ * Since: 0.10.22
+ */
+
+/**
+ * gst_byte_reader_peek_int64_le:
+ * @reader: a #GstByteReader instance
+ * @val: Pointer to a #gint64 to store the result
+ *
+ * Read a signed 64 bit little endian integer into @val
+ * but keep the current position.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ * 
+ * Since: 0.10.22
+ */
+
+/**
+ * gst_byte_reader_get_uint64_be:
+ * @reader: a #GstByteReader instance
+ * @val: Pointer to a #guint64 to store the result
+ *
+ * Read an unsigned 64 bit big endian integer into @val
+ * and update the current position.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ * 
+ * Since: 0.10.22
+ */
+
+/**
+ * gst_byte_reader_get_int64_be:
+ * @reader: a #GstByteReader instance
+ * @val: Pointer to a #gint64 to store the result
+ *
+ * Read a signed 64 bit big endian integer into @val
+ * and update the current position.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ * 
+ * Since: 0.10.22
+ */
+
+/**
+ * gst_byte_reader_peek_uint64_be:
+ * @reader: a #GstByteReader instance
+ * @val: Pointer to a #guint64 to store the result
+ *
+ * Read a signed 64 bit big endian integer into @val
+ * but keep the current position.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ * 
+ * Since: 0.10.22
+ */
+
+/**
+ * gst_byte_reader_peek_int64_be:
+ * @reader: a #GstByteReader instance
+ * @val: Pointer to a #gint64 to store the result
+ *
+ * Read a signed 64 bit big endian integer into @val
+ * but keep the current position.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ * 
+ * Since: 0.10.22
+ */
+
+#define GST_BYTE_READER_READ_INTS(bits) \
+gboolean \
+gst_byte_reader_get_uint##bits##_le (GstByteReader *reader, guint##bits *val) \
+{ \
+  g_return_val_if_fail (reader != NULL, FALSE); \
+  g_return_val_if_fail (val != NULL, FALSE); \
+  \
+  if (reader->byte + bits / 8 > reader->size) \
+    return FALSE; \
+  \
+  *val = GST_READ_UINT##bits##_LE (&reader->data[reader->byte]); \
+  reader->byte += bits / 8; \
+  return TRUE; \
+} \
+\
+gboolean \
+gst_byte_reader_get_uint##bits##_be (GstByteReader *reader, guint##bits *val) \
+{ \
+  g_return_val_if_fail (reader != NULL, FALSE); \
+  g_return_val_if_fail (val != NULL, FALSE); \
+  \
+  if (reader->byte + bits / 8 > reader->size) \
+    return FALSE; \
+  \
+  *val = GST_READ_UINT##bits##_BE (&reader->data[reader->byte]); \
+  reader->byte += bits / 8; \
+  return TRUE; \
+} \
+\
+gboolean \
+gst_byte_reader_get_int##bits##_le (GstByteReader *reader, gint##bits *val) \
+{ \
+  g_return_val_if_fail (reader != NULL, FALSE); \
+  g_return_val_if_fail (val != NULL, FALSE); \
+  \
+  if (reader->byte + bits / 8 > reader->size) \
+    return FALSE; \
+  \
+  *val = GST_READ_UINT##bits##_LE (&reader->data[reader->byte]); \
+  reader->byte += bits / 8; \
+  return TRUE; \
+} \
+\
+gboolean \
+gst_byte_reader_get_int##bits##_be (GstByteReader *reader, gint##bits *val) \
+{ \
+  g_return_val_if_fail (reader != NULL, FALSE); \
+  g_return_val_if_fail (val != NULL, FALSE); \
+  \
+  if (reader->byte + bits / 8 > reader->size) \
+    return FALSE; \
+  \
+  *val = GST_READ_UINT##bits##_BE (&reader->data[reader->byte]); \
+  reader->byte += bits / 8; \
+  return TRUE; \
+} \
+gboolean \
+gst_byte_reader_peek_uint##bits##_le (GstByteReader *reader, guint##bits *val) \
+{ \
+  g_return_val_if_fail (reader != NULL, FALSE); \
+  g_return_val_if_fail (val != NULL, FALSE); \
+  \
+  if (reader->byte + bits / 8 > reader->size) \
+    return FALSE; \
+  \
+  *val = GST_READ_UINT##bits##_LE (&reader->data[reader->byte]); \
+  return TRUE; \
+} \
+\
+gboolean \
+gst_byte_reader_peek_uint##bits##_be (GstByteReader *reader, guint##bits *val) \
+{ \
+  g_return_val_if_fail (reader != NULL, FALSE); \
+  g_return_val_if_fail (val != NULL, FALSE); \
+  \
+  if (reader->byte + bits / 8 > reader->size) \
+    return FALSE; \
+  \
+  *val = GST_READ_UINT##bits##_BE (&reader->data[reader->byte]); \
+  return TRUE; \
+} \
+\
+gboolean \
+gst_byte_reader_peek_int##bits##_le (GstByteReader *reader, gint##bits *val) \
+{ \
+  g_return_val_if_fail (reader != NULL, FALSE); \
+  g_return_val_if_fail (val != NULL, FALSE); \
+  \
+  if (reader->byte + bits / 8 > reader->size) \
+    return FALSE; \
+  \
+  *val = GST_READ_UINT##bits##_LE (&reader->data[reader->byte]); \
+  return TRUE; \
+} \
+\
+gboolean \
+gst_byte_reader_peek_int##bits##_be (GstByteReader *reader, gint##bits *val) \
+{ \
+  g_return_val_if_fail (reader != NULL, FALSE); \
+  g_return_val_if_fail (val != NULL, FALSE); \
+  \
+  if (reader->byte + bits / 8 > reader->size) \
+    return FALSE; \
+  \
+  *val = GST_READ_UINT##bits##_BE (&reader->data[reader->byte]); \
+  return TRUE; \
+}
+
+
+GST_BYTE_READER_READ_INTS (16);
+GST_BYTE_READER_READ_INTS (32);
+GST_BYTE_READER_READ_INTS (64);
+
+gboolean
+gst_byte_reader_get_uint8 (GstByteReader * reader, guint8 * val)
+{
+  g_return_val_if_fail (reader != NULL, FALSE);
+  g_return_val_if_fail (val != NULL, FALSE);
+
+  if (reader->byte + 1 > reader->size)
+    return FALSE;
+
+  *val = GST_READ_UINT8 (&reader->data[reader->byte]);
+  reader->byte++;
+  return TRUE;
+}
+
+gboolean
+gst_byte_reader_get_int8 (GstByteReader * reader, gint8 * val)
+{
+  g_return_val_if_fail (reader != NULL, FALSE);
+  g_return_val_if_fail (val != NULL, FALSE);
+
+  if (reader->byte + 1 > reader->size)
+    return FALSE;
+
+  *val = GST_READ_UINT8 (&reader->data[reader->byte]);
+  reader->byte++;
+  return TRUE;
+}
+
+gboolean
+gst_byte_reader_peek_uint8 (GstByteReader * reader, guint8 * val)
+{
+  g_return_val_if_fail (reader != NULL, FALSE);
+  g_return_val_if_fail (val != NULL, FALSE);
+
+  if (reader->byte + 1 > reader->size)
+    return FALSE;
+
+  *val = GST_READ_UINT8 (&reader->data[reader->byte]);
+  return TRUE;
+}
+
+gboolean
+gst_byte_reader_peek_int8 (GstByteReader * reader, gint8 * val)
+{
+  g_return_val_if_fail (reader != NULL, FALSE);
+  g_return_val_if_fail (val != NULL, FALSE);
+
+  if (reader->byte + 1 > reader->size)
+    return FALSE;
+
+  *val = GST_READ_UINT8 (&reader->data[reader->byte]);
+  return TRUE;
+}
+
+gboolean
+gst_byte_reader_get_uint24_le (GstByteReader * reader, guint32 * val)
+{
+  g_return_val_if_fail (reader != NULL, FALSE);
+  g_return_val_if_fail (val != NULL, FALSE);
+
+  if (reader->byte + 3 > reader->size)
+    return FALSE;
+
+  *val =
+      (reader->data[reader->byte] | (reader->data[reader->byte +
+              1] << 8) | (reader->data[reader->byte + 2] << 16));
+  reader->byte += 3;
+  return TRUE;
+}
+
+gboolean
+gst_byte_reader_get_uint24_be (GstByteReader * reader, guint32 * val)
+{
+  g_return_val_if_fail (reader != NULL, FALSE);
+  g_return_val_if_fail (val != NULL, FALSE);
+
+  if (reader->byte + 3 > reader->size)
+    return FALSE;
+
+  *val =
+      (reader->data[reader->byte + 2] | (reader->data[reader->byte +
+              1] << 8) | (reader->data[reader->byte] << 16));
+  reader->byte += 3;
+  return TRUE;
+}
+
+gboolean
+gst_byte_reader_get_int24_le (GstByteReader * reader, gint32 * val)
+{
+  guint32 ret;
+
+  g_return_val_if_fail (reader != NULL, FALSE);
+  g_return_val_if_fail (val != NULL, FALSE);
+
+  if (reader->byte + 3 > reader->size)
+    return FALSE;
+
+  ret =
+      (reader->data[reader->byte] | (reader->data[reader->byte +
+              1] << 8) | (reader->data[reader->byte + 2] << 16));
+
+  if (ret & 0x00800000)
+    ret |= 0xff000000;
+
+  reader->byte += 3;
+
+  *val = ret;
+  return TRUE;
+}
+
+gboolean
+gst_byte_reader_get_int24_be (GstByteReader * reader, gint32 * val)
+{
+  guint32 ret;
+
+  g_return_val_if_fail (reader != NULL, FALSE);
+  g_return_val_if_fail (val != NULL, FALSE);
+
+  if (reader->byte + 3 > reader->size)
+    return FALSE;
+
+  ret =
+      (reader->data[reader->byte + 2] | (reader->data[reader->byte +
+              1] << 8) | (reader->data[reader->byte] << 16));
+  if (ret & 0x00800000)
+    ret |= 0xff000000;
+
+  reader->byte += 3;
+
+  *val = ret;
+  return TRUE;
+}
+
+gboolean
+gst_byte_reader_peek_uint24_le (GstByteReader * reader, guint32 * val)
+{
+  g_return_val_if_fail (reader != NULL, FALSE);
+  g_return_val_if_fail (val != NULL, FALSE);
+
+  if (reader->byte + 3 > reader->size)
+    return FALSE;
+
+  *val =
+      (reader->data[reader->byte] | (reader->data[reader->byte +
+              1] << 8) | (reader->data[reader->byte + 2] << 16));
+  return TRUE;
+}
+
+gboolean
+gst_byte_reader_peek_uint24_be (GstByteReader * reader, guint32 * val)
+{
+  g_return_val_if_fail (reader != NULL, FALSE);
+  g_return_val_if_fail (val != NULL, FALSE);
+
+  if (reader->byte + 3 > reader->size)
+    return FALSE;
+
+  *val =
+      (reader->data[reader->byte + 2] | (reader->data[reader->byte +
+              1] << 8) | (reader->data[reader->byte] << 16));
+  return TRUE;
+}
+
+gboolean
+gst_byte_reader_peek_int24_le (GstByteReader * reader, gint32 * val)
+{
+  guint32 ret;
+
+  g_return_val_if_fail (reader != NULL, FALSE);
+  g_return_val_if_fail (val != NULL, FALSE);
+
+  if (reader->byte + 3 > reader->size)
+    return FALSE;
+
+  ret =
+      (reader->data[reader->byte] | (reader->data[reader->byte +
+              1] << 8) | (reader->data[reader->byte + 2] << 16));
+
+  if (ret & 0x00800000)
+    ret |= 0xff000000;
+
+  *val = ret;
+  return TRUE;
+}
+
+gboolean
+gst_byte_reader_peek_int24_be (GstByteReader * reader, gint32 * val)
+{
+  guint32 ret;
+
+  g_return_val_if_fail (reader != NULL, FALSE);
+  g_return_val_if_fail (val != NULL, FALSE);
+
+  if (reader->byte + 3 > reader->size)
+    return FALSE;
+
+  ret =
+      (reader->data[reader->byte + 2] | (reader->data[reader->byte +
+              1] << 8) | (reader->data[reader->byte] << 16));
+  if (ret & 0x00800000)
+    ret |= 0xff000000;
+
+  *val = ret;
+  return TRUE;
+}
+
+/**
+ * gst_byte_reader_get_float32_le:
+ * @reader: a #GstByteReader instance
+ * @val: Pointer to a #gfloat to store the result
+ *
+ * Read a 32 bit little endian integer into @val
+ * and update the current position.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ * 
+ * Since: 0.10.22
+ */
+
+/**
+ * gst_byte_reader_peek_float32_le:
+ * @reader: a #GstByteReader instance
+ * @val: Pointer to a #gfloat to store the result
+ *
+ * Read a 32 bit little endian integer into @val
+ * but keep the current position.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ * 
+ * Since: 0.10.22
+ */
+
+/**
+ * gst_byte_reader_get_float32_be:
+ * @reader: a #GstByteReader instance
+ * @val: Pointer to a #gfloat to store the result
+ *
+ * Read a 32 bit big endian integer into @val
+ * and update the current position.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ * 
+ * Since: 0.10.22
+ */
+
+/**
+ * gst_byte_reader_peek_float32_be:
+ * @reader: a #GstByteReader instance
+ * @val: Pointer to a #gfloat to store the result
+ *
+ * Read a 32 bit big endian integer into @val
+ * but keep the current position.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ * 
+ * Since: 0.10.22
+ */
+
+/**
+ * gst_byte_reader_get_float64_le:
+ * @reader: a #GstByteReader instance
+ * @val: Pointer to a #gdouble to store the result
+ *
+ * Read a 64 bit little endian integer into @val
+ * and update the current position.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ * 
+ * Since: 0.10.22
+ */
+
+/**
+ * gst_byte_reader_peek_float64_le:
+ * @reader: a #GstByteReader instance
+ * @val: Pointer to a #gdouble to store the result
+ *
+ * Read a 64 bit little endian integer into @val
+ * but keep the current position.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ * 
+ * Since: 0.10.22
+ */
+
+/**
+ * gst_byte_reader_get_float64_be:
+ * @reader: a #GstByteReader instance
+ * @val: Pointer to a #gdouble to store the result
+ *
+ * Read a 64 bit big endian integer into @val
+ * and update the current position.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ * 
+ * Since: 0.10.22
+ */
+
+/**
+ * gst_byte_reader_peek_float64_be:
+ * @reader: a #GstByteReader instance
+ * @val: Pointer to a #gdouble to store the result
+ *
+ * Read a 64 bit big endian integer into @val
+ * but keep the current position.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ * 
+ * Since: 0.10.22
+ */
+
+#define GST_BYTE_READER_READ_FLOATS(bits, type, TYPE) \
+gboolean \
+gst_byte_reader_get_float##bits##_le (GstByteReader *reader, g##type *val) \
+{ \
+  g##type ret; \
+  \
+  g_return_val_if_fail (reader != NULL, FALSE); \
+  g_return_val_if_fail (val != NULL, FALSE); \
+  \
+  if (reader->byte + bits / 8 > reader->size) \
+    return FALSE; \
+  \
+  memcpy (&ret, &reader->data[reader->byte], bits / 8); \
+  *val = G##TYPE##_FROM_LE (ret); \
+  reader->byte += bits / 8; \
+  return TRUE; \
+} \
+gboolean \
+gst_byte_reader_get_float##bits##_be (GstByteReader *reader, g##type *val) \
+{ \
+  g##type ret; \
+  \
+  g_return_val_if_fail (reader != NULL, FALSE); \
+  g_return_val_if_fail (val != NULL, FALSE); \
+  \
+  if (reader->byte + bits / 8 > reader->size) \
+    return FALSE; \
+  \
+  memcpy (&ret, &reader->data[reader->byte], bits / 8); \
+  *val = G##TYPE##_FROM_BE (ret); \
+  reader->byte += bits / 8; \
+  return TRUE; \
+} \
+gboolean \
+gst_byte_reader_peek_float##bits##_le (GstByteReader *reader, g##type *val) \
+{ \
+  g##type ret; \
+  \
+  g_return_val_if_fail (reader != NULL, FALSE); \
+  g_return_val_if_fail (val != NULL, FALSE); \
+  \
+  if (reader->byte + bits / 8 > reader->size) \
+    return FALSE; \
+  \
+  memcpy (&ret, &reader->data[reader->byte], bits / 8); \
+  *val = G##TYPE##_FROM_LE (ret); \
+  return TRUE; \
+} \
+gboolean \
+gst_byte_reader_peek_float##bits##_be (GstByteReader *reader, g##type *val) \
+{ \
+  g##type ret; \
+  \
+  g_return_val_if_fail (reader != NULL, FALSE); \
+  g_return_val_if_fail (val != NULL, FALSE); \
+  \
+  if (reader->byte + bits / 8 > reader->size) \
+    return FALSE; \
+  \
+  memcpy (&ret, &reader->data[reader->byte], bits / 8); \
+  *val = G##TYPE##_FROM_BE (ret); \
+  return TRUE; \
+}
+
+GST_BYTE_READER_READ_FLOATS (32, float, FLOAT);
+GST_BYTE_READER_READ_FLOATS (64, double, DOUBLE);
diff --git a/libs/gst/base/gstbytereader.h b/libs/gst/base/gstbytereader.h
new file mode 100644 (file)
index 0000000..28534c0
--- /dev/null
@@ -0,0 +1,134 @@
+/* GStreamer
+ *
+ * Copyright (C) 2008 Sebastian Dröge <sebastian.droege@collabora.co.uk>.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * 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.
+ */
+
+#ifndef __GST_BYTE_READER_H__
+#define __GST_BYTE_READER_H__
+
+#include <gst/gst.h>
+
+G_BEGIN_DECLS
+
+/**
+ * GstByteReader:
+ * @data: Data from which the bit reader will read
+ * @size: Size of @data in bytes
+ * @byte: Current byte position
+ *
+ * A byte reader instance.
+ */
+typedef struct {
+  const guint8 *data;
+  guint size;
+
+  guint byte;  /* Byte position */
+} GstByteReader;
+
+GstByteReader * gst_byte_reader_new (const guint8 *data, guint size);
+GstByteReader * gst_byte_reader_new_from_buffer (const GstBuffer *buffer);
+void gst_byte_reader_free (GstByteReader *reader);
+
+void gst_byte_reader_init (GstByteReader *reader, const guint8 *data, guint size);
+void gst_byte_reader_init_from_buffer (GstByteReader *reader, const GstBuffer *buffer);
+
+gboolean gst_byte_reader_set_pos (GstByteReader *reader, guint pos);
+
+guint gst_byte_reader_get_pos (const GstByteReader *reader);
+guint gst_byte_reader_get_remaining (const GstByteReader *reader);
+
+gboolean gst_byte_reader_skip (GstByteReader *reader, guint nbytes);
+
+gboolean gst_byte_reader_get_uint8 (GstByteReader *reader, guint8 *val);
+gboolean gst_byte_reader_get_int8 (GstByteReader *reader, gint8 *val);
+gboolean gst_byte_reader_get_uint16_le (GstByteReader *reader, guint16 *val);
+gboolean gst_byte_reader_get_int16_le (GstByteReader *reader, gint16 *val);
+gboolean gst_byte_reader_get_uint16_be (GstByteReader *reader, guint16 *val);
+gboolean gst_byte_reader_get_int16_be (GstByteReader *reader, gint16 *val);
+gboolean gst_byte_reader_get_uint24_le (GstByteReader *reader, guint32 *val);
+gboolean gst_byte_reader_get_int24_le (GstByteReader *reader, gint32 *val);
+gboolean gst_byte_reader_get_uint24_be (GstByteReader *reader, guint32 *val);
+gboolean gst_byte_reader_get_int24_be (GstByteReader *reader, gint32 *val);
+gboolean gst_byte_reader_get_uint32_le (GstByteReader *reader, guint32 *val);
+gboolean gst_byte_reader_get_int32_le (GstByteReader *reader, gint32 *val);
+gboolean gst_byte_reader_get_uint32_be (GstByteReader *reader, guint32 *val);
+gboolean gst_byte_reader_get_int32_be (GstByteReader *reader, gint32 *val);
+gboolean gst_byte_reader_get_uint64_le (GstByteReader *reader, guint64 *val);
+gboolean gst_byte_reader_get_int64_le (GstByteReader *reader, gint64 *val);
+gboolean gst_byte_reader_get_uint64_be (GstByteReader *reader, guint64 *val);
+gboolean gst_byte_reader_get_int64_be (GstByteReader *reader, gint64 *val);
+
+gboolean gst_byte_reader_peek_uint8 (GstByteReader *reader, guint8 *val);
+gboolean gst_byte_reader_peek_int8 (GstByteReader *reader, gint8 *val);
+gboolean gst_byte_reader_peek_uint16_le (GstByteReader *reader, guint16 *val);
+gboolean gst_byte_reader_peek_int16_le (GstByteReader *reader, gint16 *val);
+gboolean gst_byte_reader_peek_uint16_be (GstByteReader *reader, guint16 *val);
+gboolean gst_byte_reader_peek_int16_be (GstByteReader *reader, gint16 *val);
+gboolean gst_byte_reader_peek_uint24_le (GstByteReader *reader, guint32 *val);
+gboolean gst_byte_reader_peek_int24_le (GstByteReader *reader, gint32 *val);
+gboolean gst_byte_reader_peek_uint24_be (GstByteReader *reader, guint32 *val);
+gboolean gst_byte_reader_peek_int24_be (GstByteReader *reader, gint32 *val);
+gboolean gst_byte_reader_peek_uint32_le (GstByteReader *reader, guint32 *val);
+gboolean gst_byte_reader_peek_int32_le (GstByteReader *reader, gint32 *val);
+gboolean gst_byte_reader_peek_uint32_be (GstByteReader *reader, guint32 *val);
+gboolean gst_byte_reader_peek_int32_be (GstByteReader *reader, gint32 *val);
+gboolean gst_byte_reader_peek_uint64_le (GstByteReader *reader, guint64 *val);
+gboolean gst_byte_reader_peek_int64_le (GstByteReader *reader, gint64 *val);
+gboolean gst_byte_reader_peek_uint64_be (GstByteReader *reader, guint64 *val);
+gboolean gst_byte_reader_peek_int64_be (GstByteReader *reader, gint64 *val);
+
+gboolean gst_byte_reader_get_float32_le (GstByteReader *reader, gfloat *val);
+gboolean gst_byte_reader_get_float32_be (GstByteReader *reader, gfloat *val);
+gboolean gst_byte_reader_get_float64_le (GstByteReader *reader, gdouble *val);
+gboolean gst_byte_reader_get_float64_be (GstByteReader *reader, gdouble *val);
+
+gboolean gst_byte_reader_peek_float32_le (GstByteReader *reader, gfloat *val);
+gboolean gst_byte_reader_peek_float32_be (GstByteReader *reader, gfloat *val);
+gboolean gst_byte_reader_peek_float64_le (GstByteReader *reader, gdouble *val);
+gboolean gst_byte_reader_peek_float64_be (GstByteReader *reader, gdouble *val);
+
+/**
+ * GST_BYTE_READER_INIT:
+ * @data: Data from which the #GstByteReader should read
+ * @size: Size of @data in bytes
+ *
+ * A #GstByteReader must be initialized with this macro, before it can be
+ * used. This macro can used be to initialize a variable, but it cannot
+ * be assigned to a variable. In that case you have to use
+ * gst_byte_reader_init().
+ *
+ * Since: 0.10.22
+ */
+#define GST_BYTE_READER_INIT(data, size) {data, size, 0}
+
+/**
+ * GST_BYTE_READER_INIT_FROM_BUFFER:
+ * @buffer: Buffer from which the #GstByteReader should read
+ *
+ * A #GstByteReader must be initialized with this macro, before it can be
+ * used. This macro can used be to initialize a variable, but it cannot
+ * be assigned to a variable. In that case you have to use
+ * gst_byte_reader_init().
+ *
+ * Since: 0.10.22
+ */
+#define GST_BYTE_READER_INIT_FROM_BUFFER(buffer) {GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer), 0}
+
+G_END_DECLS
+
+#endif /* __GST_BYTE_READER_H__ */
index 2dddc93..b9a9767 100644 (file)
@@ -100,6 +100,8 @@ check_PROGRAMS =                            \
        libs/libsabi                            \
        libs/gdp                                \
        libs/adapter                            \
+       libs/bitreader                          \
+       libs/bytereader                         \
        libs/gstnetclientclock                  \
        libs/gstnettimeprovider                 \
        libs/transform1                         
@@ -150,6 +152,12 @@ elements_filesrc_CFLAGS=$(GST_OBJ_CFLAGS) $(CHECK_CFLAGS) -DTESTFILE=\"$(top_src
 libs_basesrc_LDADD = \
        $(top_builddir)/libs/gst/base/libgstbase-@GST_MAJORMINOR@.la \
        $(LDADD)
+libs_bitreader_LDADD = \
+       $(top_builddir)/libs/gst/base/libgstbase-@GST_MAJORMINOR@.la \
+       $(LDADD)
+libs_bytereader_LDADD = \
+       $(top_builddir)/libs/gst/base/libgstbase-@GST_MAJORMINOR@.la \
+       $(LDADD)
 libs_adapter_LDADD = \
        $(top_builddir)/libs/gst/base/libgstbase-@GST_MAJORMINOR@.la \
        $(LDADD)
diff --git a/tests/check/libs/bitreader.c b/tests/check/libs/bitreader.c
new file mode 100644 (file)
index 0000000..3b93742
--- /dev/null
@@ -0,0 +1,248 @@
+/* GStreamer
+ *
+ * unit test for GstBitReader
+ *
+ * Copyright (C) <2008> Sebastian Dröge <sebastian.droege@collabora.co.uk>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gst.h>
+#include <gst/check/gstcheck.h>
+#include <gst/base/gstbitreader.h>
+
+#ifndef fail_unless_equals_int64
+#define fail_unless_equals_int64(a, b)                                 \
+G_STMT_START {                                                         \
+  gint64 first = a;                                                    \
+  gint64 second = b;                                                   \
+  fail_unless(first == second,                                         \
+    "'" #a "' (%" G_GINT64_FORMAT ") is not equal to '" #b"' (%"       \
+    G_GINT64_FORMAT ")", first, second);                               \
+} G_STMT_END;
+#endif
+
+GST_START_TEST (test_initialization)
+{
+  guint8 data[] = { 0x01, 0x02, 0x03, 0x04 };
+  GstBuffer *buffer = gst_buffer_new ();
+  GstBitReader reader = GST_BIT_READER_INIT (data, 4);
+  GstBitReader *reader2;
+  guint8 x;
+
+  GST_BUFFER_DATA (buffer) = data;
+  GST_BUFFER_SIZE (buffer) = 4;
+
+  fail_unless (gst_bit_reader_get_bits_uint8 (&reader, &x, 8));
+  fail_unless_equals_int (x, 0x01);
+  fail_unless (gst_bit_reader_get_bits_uint8 (&reader, &x, 8));
+  fail_unless_equals_int (x, 0x02);
+
+  memset (&reader, 0, sizeof (GstBitReader));
+
+  gst_bit_reader_init (&reader, data, 4);
+  fail_unless (gst_bit_reader_get_bits_uint8 (&reader, &x, 8));
+  fail_unless_equals_int (x, 0x01);
+  fail_unless (gst_bit_reader_get_bits_uint8 (&reader, &x, 8));
+  fail_unless_equals_int (x, 0x02);
+
+  gst_bit_reader_init_from_buffer (&reader, buffer);
+  fail_unless (gst_bit_reader_get_bits_uint8 (&reader, &x, 8));
+  fail_unless_equals_int (x, 0x01);
+  fail_unless (gst_bit_reader_get_bits_uint8 (&reader, &x, 8));
+  fail_unless_equals_int (x, 0x02);
+
+  reader2 = gst_bit_reader_new (data, 4);
+  fail_unless (gst_bit_reader_get_bits_uint8 (reader2, &x, 8));
+  fail_unless_equals_int (x, 0x01);
+  fail_unless (gst_bit_reader_get_bits_uint8 (reader2, &x, 8));
+  fail_unless_equals_int (x, 0x02);
+  gst_bit_reader_free (reader2);
+
+  reader2 = gst_bit_reader_new_from_buffer (buffer);
+  fail_unless (gst_bit_reader_get_bits_uint8 (reader2, &x, 8));
+  fail_unless_equals_int (x, 0x01);
+  fail_unless (gst_bit_reader_get_bits_uint8 (reader2, &x, 8));
+  fail_unless_equals_int (x, 0x02);
+  gst_bit_reader_free (reader2);
+
+  gst_buffer_unref (buffer);
+}
+
+GST_END_TEST;
+
+#define GET_CHECK(reader, dest, bits, nbits, val) { \
+  fail_unless (gst_bit_reader_get_bits_uint##bits (reader, &dest, nbits)); \
+  fail_unless_equals_uint64 (dest, val); \
+}
+
+#define PEEK_CHECK(reader, dest, bits, nbits, val) { \
+  fail_unless (gst_bit_reader_peek_bits_uint##bits (reader, &dest, nbits)); \
+  fail_unless_equals_uint64 (dest, val); \
+}
+
+#define GET_CHECK_FAIL(reader, dest, bits, nbits) { \
+  fail_if (gst_bit_reader_get_bits_uint##bits (reader, &dest, nbits)); \
+}
+
+#define PEEK_CHECK_FAIL(reader, dest, bits, nbits) { \
+  fail_if (gst_bit_reader_peek_bits_uint##bits (reader, &dest, nbits)); \
+}
+
+GST_START_TEST (test_get_bits)
+{
+  guint8 data[] = { 0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xef,
+    0xfe, 0xdc, 0xba, 0x09, 0x87, 0x65, 0x43, 0x21
+  };
+  GstBitReader reader = GST_BIT_READER_INIT (data, 16);
+  guint8 a;
+  guint16 b;
+  guint32 c;
+  guint64 d;
+
+  /* 8 bit */
+  GET_CHECK (&reader, a, 8, 8, 0x12);
+  GET_CHECK (&reader, a, 8, 4, 0x03);
+  GET_CHECK (&reader, a, 8, 4, 0x04);
+  GET_CHECK (&reader, a, 8, 3, 0x02);
+  GET_CHECK (&reader, a, 8, 1, 0x01);
+  GET_CHECK (&reader, a, 8, 2, 0x01);
+  GET_CHECK (&reader, a, 8, 2, 0x02);
+
+  PEEK_CHECK (&reader, a, 8, 8, 0x78);
+  PEEK_CHECK (&reader, a, 8, 8, 0x78);
+  fail_unless (gst_bit_reader_skip (&reader, 8));
+
+  PEEK_CHECK (&reader, a, 8, 8, 0x90);
+  GET_CHECK (&reader, a, 8, 1, 0x01);
+  GET_CHECK (&reader, a, 8, 1, 0x00);
+  GET_CHECK (&reader, a, 8, 1, 0x00);
+  GET_CHECK (&reader, a, 8, 1, 0x01);
+  fail_unless (gst_bit_reader_skip (&reader, 4));
+
+  fail_unless (gst_bit_reader_skip (&reader, 10 * 8));
+  GET_CHECK (&reader, a, 8, 8, 0x21);
+  GET_CHECK_FAIL (&reader, a, 8, 1);
+  PEEK_CHECK_FAIL (&reader, a, 8, 1);
+
+  /* 16 bit */
+  gst_bit_reader_init (&reader, data, 16);
+
+  GET_CHECK (&reader, b, 16, 16, 0x1234);
+  PEEK_CHECK (&reader, b, 16, 13, 0x0acf);
+  GET_CHECK (&reader, b, 16, 8, 0x56);
+  GET_CHECK (&reader, b, 16, 4, 0x07);
+  GET_CHECK (&reader, b, 16, 2, 0x02);
+  GET_CHECK (&reader, b, 16, 2, 0x00);
+  PEEK_CHECK (&reader, b, 16, 8, 0x90);
+  fail_unless (gst_bit_reader_skip (&reader, 11 * 8));
+  GET_CHECK (&reader, b, 16, 8, 0x21);
+  GET_CHECK_FAIL (&reader, b, 16, 16);
+  PEEK_CHECK_FAIL (&reader, b, 16, 16);
+
+  /* 32 bit */
+  gst_bit_reader_init (&reader, data, 16);
+
+  GET_CHECK (&reader, c, 32, 32, 0x12345678);
+  GET_CHECK (&reader, c, 32, 24, 0x90abcd);
+  GET_CHECK (&reader, c, 32, 16, 0xeffe);
+  GET_CHECK (&reader, c, 32, 8, 0xdc);
+  GET_CHECK (&reader, c, 32, 4, 0x0b);
+  GET_CHECK (&reader, c, 32, 2, 0x02);
+  GET_CHECK (&reader, c, 32, 2, 0x02);
+  PEEK_CHECK (&reader, c, 32, 8, 0x09);
+  fail_unless (gst_bit_reader_skip (&reader, 3 * 8));
+  GET_CHECK (&reader, c, 32, 15, 0x2190);
+  GET_CHECK (&reader, c, 32, 1, 0x1);
+  GET_CHECK_FAIL (&reader, c, 32, 1);
+
+  /* 64 bit */
+  gst_bit_reader_init (&reader, data, 16);
+
+  GET_CHECK (&reader, d, 64, 64, G_GINT64_CONSTANT (0x1234567890abcdef));
+  GET_CHECK (&reader, d, 64, 7, 0xfe >> 1);
+  GET_CHECK (&reader, d, 64, 1, 0x00);
+  GET_CHECK (&reader, d, 64, 24, 0xdcba09);
+  GET_CHECK (&reader, d, 64, 32, 0x87654321);
+  GET_CHECK_FAIL (&reader, d, 64, 32);
+}
+
+GST_END_TEST;
+
+#undef GET_CHECK
+#undef PEEK_CHECK
+#undef GET_CHECK_FAIL
+#undef PEEK_CHECK_FAIL
+
+GST_START_TEST (test_position_tracking)
+{
+  guint8 data[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+  };
+  GstBitReader reader = GST_BIT_READER_INIT (data, 16);
+  guint8 a;
+
+  fail_unless_equals_int (gst_bit_reader_get_pos (&reader), 0);
+  fail_unless_equals_int (gst_bit_reader_get_remaining (&reader), 16 * 8);
+
+  fail_unless (gst_bit_reader_get_bits_uint8 (&reader, &a, 3));
+  fail_unless_equals_int (gst_bit_reader_get_pos (&reader), 3);
+  fail_unless_equals_int (gst_bit_reader_get_remaining (&reader), 16 * 8 - 3);
+
+  fail_unless (gst_bit_reader_set_pos (&reader, 9));
+  fail_unless_equals_int (gst_bit_reader_get_pos (&reader), 9);
+  fail_unless_equals_int (gst_bit_reader_get_remaining (&reader), 16 * 8 - 9);
+
+  fail_unless (gst_bit_reader_skip (&reader, 3));
+  fail_unless_equals_int (gst_bit_reader_get_pos (&reader), 12);
+  fail_unless_equals_int (gst_bit_reader_get_remaining (&reader), 16 * 8 - 12);
+
+  fail_unless (gst_bit_reader_skip_to_byte (&reader));
+  fail_unless_equals_int (gst_bit_reader_get_pos (&reader), 16);
+  fail_unless_equals_int (gst_bit_reader_get_remaining (&reader), 16 * 8 - 16);
+
+  fail_unless (gst_bit_reader_set_pos (&reader, 16 * 8));
+  fail_unless_equals_int (gst_bit_reader_get_pos (&reader), 16 * 8);
+  fail_unless_equals_int (gst_bit_reader_get_remaining (&reader), 0);
+
+  fail_unless (gst_bit_reader_skip (&reader, 0));
+  fail_if (gst_bit_reader_skip (&reader, 1));
+  fail_unless (gst_bit_reader_skip_to_byte (&reader));
+}
+
+GST_END_TEST;
+
+static Suite *
+gst_bit_reader_suite (void)
+{
+  Suite *s = suite_create ("GstBitReader");
+  TCase *tc_chain = tcase_create ("general");
+
+  suite_add_tcase (s, tc_chain);
+
+  tcase_add_test (tc_chain, test_initialization);
+  tcase_add_test (tc_chain, test_get_bits);
+  tcase_add_test (tc_chain, test_position_tracking);
+
+  return s;
+}
+
+
+GST_CHECK_MAIN (gst_bit_reader);
diff --git a/tests/check/libs/bytereader.c b/tests/check/libs/bytereader.c
new file mode 100644 (file)
index 0000000..c4ba8f9
--- /dev/null
@@ -0,0 +1,484 @@
+/* GStreamer
+ *
+ * unit test for GstByteReader
+ *
+ * Copyright (C) <2008> Sebastian Dröge <sebastian.droege@collabora.co.uk>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gst.h>
+#include <gst/check/gstcheck.h>
+#include <gst/base/gstbytereader.h>
+
+#ifndef fail_unless_equals_int64
+#define fail_unless_equals_int64(a, b)                                 \
+G_STMT_START {                                                         \
+  gint64 first = a;                                                    \
+  gint64 second = b;                                                   \
+  fail_unless(first == second,                                         \
+    "'" #a "' (%" G_GINT64_FORMAT ") is not equal to '" #b"' (%"       \
+    G_GINT64_FORMAT ")", first, second);                               \
+} G_STMT_END;
+#endif
+
+GST_START_TEST (test_initialization)
+{
+  guint8 data[] = { 0x01, 0x02, 0x03, 0x04 };
+  GstBuffer *buffer = gst_buffer_new ();
+  GstByteReader reader = GST_BYTE_READER_INIT (data, 4);
+  GstByteReader *reader2;
+  guint8 x;
+
+  GST_BUFFER_DATA (buffer) = data;
+  GST_BUFFER_SIZE (buffer) = 4;
+
+  fail_unless (gst_byte_reader_get_uint8 (&reader, &x));
+  fail_unless_equals_int (x, 0x01);
+  fail_unless (gst_byte_reader_get_uint8 (&reader, &x));
+  fail_unless_equals_int (x, 0x02);
+
+  memset (&reader, 0, sizeof (GstByteReader));
+
+  gst_byte_reader_init (&reader, data, 4);
+  fail_unless (gst_byte_reader_get_uint8 (&reader, &x));
+  fail_unless_equals_int (x, 0x01);
+  fail_unless (gst_byte_reader_get_uint8 (&reader, &x));
+  fail_unless_equals_int (x, 0x02);
+
+  gst_byte_reader_init_from_buffer (&reader, buffer);
+  fail_unless (gst_byte_reader_get_uint8 (&reader, &x));
+  fail_unless_equals_int (x, 0x01);
+  fail_unless (gst_byte_reader_get_uint8 (&reader, &x));
+  fail_unless_equals_int (x, 0x02);
+
+  reader2 = gst_byte_reader_new (data, 4);
+  fail_unless (gst_byte_reader_get_uint8 (reader2, &x));
+  fail_unless_equals_int (x, 0x01);
+  fail_unless (gst_byte_reader_get_uint8 (reader2, &x));
+  fail_unless_equals_int (x, 0x02);
+  gst_byte_reader_free (reader2);
+
+  reader2 = gst_byte_reader_new_from_buffer (buffer);
+  fail_unless (gst_byte_reader_get_uint8 (reader2, &x));
+  fail_unless_equals_int (x, 0x01);
+  fail_unless (gst_byte_reader_get_uint8 (reader2, &x));
+  fail_unless_equals_int (x, 0x02);
+  gst_byte_reader_free (reader2);
+
+  gst_buffer_unref (buffer);
+}
+
+GST_END_TEST;
+
+#define GET_CHECK8(reader, dest, val) { \
+  fail_unless (gst_byte_reader_get_uint8 (reader, &dest)); \
+  fail_unless_equals_uint64 (dest, val); \
+}
+
+#define GET_CHECK(reader, dest, bits, endianness, val) { \
+  fail_unless (gst_byte_reader_get_uint##bits##_##endianness (reader, &dest)); \
+  fail_unless_equals_uint64 (dest, val); \
+}
+
+#define GET_CHECK_FAIL8(reader, dest) { \
+  fail_if (gst_byte_reader_get_uint8 (reader, &dest)); \
+}
+
+#define GET_CHECK_FAIL(reader, dest, bits, endianness) { \
+  fail_if (gst_byte_reader_get_uint##bits##_##endianness (reader, &dest)); \
+}
+
+#define PEEK_CHECK8(reader, dest, val) { \
+  fail_unless (gst_byte_reader_peek_uint8 (reader, &dest)); \
+  fail_unless_equals_uint64 (dest, val); \
+}
+
+#define PEEK_CHECK(reader, dest, bits, endianness, val) { \
+  fail_unless (gst_byte_reader_peek_uint##bits##_##endianness (reader, &dest)); \
+  fail_unless_equals_uint64 (dest, val); \
+}
+
+#define PEEK_CHECK_FAIL8(reader, dest) { \
+  fail_if (gst_byte_reader_peek_uint8 (reader, &dest)); \
+}
+
+#define PEEK_CHECK_FAIL(reader, dest, bits, endianness) { \
+  fail_if (gst_byte_reader_peek_uint##bits##_##endianness (reader, &dest)); \
+}
+
+GST_START_TEST (test_get_uint_le)
+{
+  guint8 data[] = { 0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xef,
+    0xfe, 0xdc, 0xba, 0x09, 0x87, 0x65, 0x43, 0x21
+  };
+  GstByteReader reader = GST_BYTE_READER_INIT (data, 16);
+  guint8 a;
+  guint16 b;
+  guint32 c;
+  guint64 d;
+
+  GET_CHECK8 (&reader, a, 0x12);
+  GET_CHECK (&reader, b, 16, le, 0x5634);
+  GET_CHECK (&reader, c, 24, le, 0xab9078);
+  GET_CHECK (&reader, c, 32, le, 0xdcfeefcd);
+  fail_unless (gst_byte_reader_set_pos (&reader, 0));
+  GET_CHECK (&reader, d, 64, le, G_GINT64_CONSTANT (0xefcdab9078563412));
+  GET_CHECK (&reader, d, 64, le, G_GINT64_CONSTANT (0x2143658709badcfe));
+
+  GET_CHECK_FAIL8 (&reader, a);
+  GET_CHECK_FAIL (&reader, b, 16, le);
+  GET_CHECK_FAIL (&reader, c, 24, le);
+  GET_CHECK_FAIL (&reader, c, 32, le);
+  GET_CHECK_FAIL (&reader, d, 64, le);
+
+  fail_unless (gst_byte_reader_set_pos (&reader, 0));
+
+  PEEK_CHECK8 (&reader, a, 0x12);
+  PEEK_CHECK (&reader, b, 16, le, 0x3412);
+  PEEK_CHECK (&reader, c, 24, le, 0x563412);
+  PEEK_CHECK (&reader, c, 32, le, 0x78563412);
+  PEEK_CHECK (&reader, d, 64, le, G_GINT64_CONSTANT (0xefcdab9078563412));
+
+  fail_unless (gst_byte_reader_set_pos (&reader, 16));
+  PEEK_CHECK_FAIL8 (&reader, a);
+  PEEK_CHECK_FAIL (&reader, b, 16, le);
+  PEEK_CHECK_FAIL (&reader, c, 24, le);
+  PEEK_CHECK_FAIL (&reader, c, 32, le);
+  PEEK_CHECK_FAIL (&reader, d, 64, le);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_get_uint_be)
+{
+  guint8 data[] = { 0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xef,
+    0xfe, 0xdc, 0xba, 0x09, 0x87, 0x65, 0x43, 0x21
+  };
+  GstByteReader reader = GST_BYTE_READER_INIT (data, 16);
+  guint8 a;
+  guint16 b;
+  guint32 c;
+  guint64 d;
+
+  GET_CHECK8 (&reader, a, 0x12);
+  GET_CHECK (&reader, b, 16, be, 0x3456);
+  GET_CHECK (&reader, c, 24, be, 0x7890ab);
+  GET_CHECK (&reader, c, 32, be, 0xcdeffedc);
+  fail_unless (gst_byte_reader_set_pos (&reader, 0));
+  GET_CHECK (&reader, d, 64, be, G_GINT64_CONSTANT (0x1234567890abcdef));
+  GET_CHECK (&reader, d, 64, be, G_GINT64_CONSTANT (0xfedcba0987654321));
+
+  GET_CHECK_FAIL8 (&reader, a);
+  GET_CHECK_FAIL (&reader, b, 16, be);
+  GET_CHECK_FAIL (&reader, c, 24, be);
+  GET_CHECK_FAIL (&reader, c, 32, be);
+  GET_CHECK_FAIL (&reader, d, 64, be);
+
+  fail_unless (gst_byte_reader_set_pos (&reader, 0));
+
+  PEEK_CHECK8 (&reader, a, 0x12);
+  PEEK_CHECK (&reader, b, 16, be, 0x1234);
+  PEEK_CHECK (&reader, c, 24, be, 0x123456);
+  PEEK_CHECK (&reader, c, 32, be, 0x12345678);
+  PEEK_CHECK (&reader, d, 64, be, G_GINT64_CONSTANT (0x1234567890abcdef));
+
+  fail_unless (gst_byte_reader_set_pos (&reader, 16));
+  PEEK_CHECK_FAIL8 (&reader, a);
+  PEEK_CHECK_FAIL (&reader, b, 16, be);
+  PEEK_CHECK_FAIL (&reader, c, 24, be);
+  PEEK_CHECK_FAIL (&reader, c, 32, be);
+  PEEK_CHECK_FAIL (&reader, d, 64, be);
+}
+
+GST_END_TEST;
+
+#undef GET_CHECK8
+#undef GET_CHECK
+#undef PEEK_CHECK8
+#undef PEEK_CHECK
+#undef GET_CHECK_FAIL8
+#undef GET_CHECK_FAIL
+#undef PEEK_CHECK_FAIL8
+#undef PEEK_CHECK_FAIL
+
+#define GET_CHECK8(reader, dest, val) { \
+  fail_unless (gst_byte_reader_get_int8 (reader, &dest)); \
+  fail_unless_equals_int64 (dest, val); \
+}
+
+#define GET_CHECK(reader, dest, bits, endianness, val) { \
+  fail_unless (gst_byte_reader_get_int##bits##_##endianness (reader, &dest)); \
+  fail_unless_equals_int64 (dest, val); \
+}
+
+#define GET_CHECK_FAIL8(reader, dest) { \
+  fail_if (gst_byte_reader_get_int8 (reader, &dest)); \
+}
+
+#define GET_CHECK_FAIL(reader, dest, bits, endianness) { \
+  fail_if (gst_byte_reader_get_int##bits##_##endianness (reader, &dest)); \
+}
+
+#define PEEK_CHECK8(reader, dest, val) { \
+  fail_unless (gst_byte_reader_peek_int8 (reader, &dest)); \
+  fail_unless_equals_int64 (dest, val); \
+}
+
+#define PEEK_CHECK(reader, dest, bits, endianness, val) { \
+  fail_unless (gst_byte_reader_peek_int##bits##_##endianness (reader, &dest)); \
+  fail_unless_equals_int64 (dest, val); \
+}
+
+#define PEEK_CHECK_FAIL8(reader, dest) { \
+  fail_if (gst_byte_reader_peek_int8 (reader, &dest)); \
+}
+
+#define PEEK_CHECK_FAIL(reader, dest, bits, endianness) { \
+  fail_if (gst_byte_reader_peek_int##bits##_##endianness (reader, &dest)); \
+}
+
+GST_START_TEST (test_get_int_le)
+{
+  guint8 data[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+  };
+  GstByteReader reader = GST_BYTE_READER_INIT (data, 16);
+  gint8 a;
+  gint16 b;
+  gint32 c;
+  gint64 d;
+
+  GET_CHECK8 (&reader, a, -1);
+  GET_CHECK (&reader, b, 16, le, -1);
+  GET_CHECK (&reader, c, 24, le, -1);
+  GET_CHECK (&reader, c, 32, le, -1);
+  fail_unless (gst_byte_reader_set_pos (&reader, 0));
+  GET_CHECK (&reader, d, 64, le, G_GINT64_CONSTANT (-1));
+  GET_CHECK (&reader, d, 64, le, G_GINT64_CONSTANT (-1));
+
+  GET_CHECK_FAIL8 (&reader, a);
+  GET_CHECK_FAIL (&reader, b, 16, le);
+  GET_CHECK_FAIL (&reader, c, 24, le);
+  GET_CHECK_FAIL (&reader, c, 32, le);
+  GET_CHECK_FAIL (&reader, d, 64, le);
+
+  fail_unless (gst_byte_reader_set_pos (&reader, 0));
+
+  PEEK_CHECK8 (&reader, a, -1);
+  PEEK_CHECK (&reader, b, 16, le, -1);
+  PEEK_CHECK (&reader, c, 24, le, -1);
+  PEEK_CHECK (&reader, c, 32, le, -1);
+  PEEK_CHECK (&reader, d, 64, le, G_GINT64_CONSTANT (-1));
+
+  fail_unless (gst_byte_reader_set_pos (&reader, 16));
+  PEEK_CHECK_FAIL8 (&reader, a);
+  PEEK_CHECK_FAIL (&reader, b, 16, le);
+  PEEK_CHECK_FAIL (&reader, c, 24, le);
+  PEEK_CHECK_FAIL (&reader, c, 32, le);
+  PEEK_CHECK_FAIL (&reader, d, 64, le);
+
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_get_int_be)
+{
+  guint8 data[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+  };
+  GstByteReader reader = GST_BYTE_READER_INIT (data, 16);
+  gint8 a;
+  gint16 b;
+  gint32 c;
+  gint64 d;
+
+  GET_CHECK8 (&reader, a, -1);
+  GET_CHECK (&reader, b, 16, be, -1);
+  GET_CHECK (&reader, c, 24, be, -1);
+  GET_CHECK (&reader, c, 32, be, -1);
+  fail_unless (gst_byte_reader_set_pos (&reader, 0));
+  GET_CHECK (&reader, d, 64, be, G_GINT64_CONSTANT (-1));
+  GET_CHECK (&reader, d, 64, be, G_GINT64_CONSTANT (-1));
+
+  GET_CHECK_FAIL8 (&reader, a);
+  GET_CHECK_FAIL (&reader, b, 16, be);
+  GET_CHECK_FAIL (&reader, c, 24, be);
+  GET_CHECK_FAIL (&reader, c, 32, be);
+  GET_CHECK_FAIL (&reader, d, 64, be);
+
+  fail_unless (gst_byte_reader_set_pos (&reader, 0));
+
+  PEEK_CHECK8 (&reader, a, -1);
+  PEEK_CHECK (&reader, b, 16, be, -1);
+  PEEK_CHECK (&reader, c, 24, be, -1);
+  PEEK_CHECK (&reader, c, 32, be, -1);
+  PEEK_CHECK (&reader, d, 64, be, G_GINT64_CONSTANT (-1));
+
+  fail_unless (gst_byte_reader_set_pos (&reader, 16));
+  PEEK_CHECK_FAIL8 (&reader, a);
+  PEEK_CHECK_FAIL (&reader, b, 16, be);
+  PEEK_CHECK_FAIL (&reader, c, 24, be);
+  PEEK_CHECK_FAIL (&reader, c, 32, be);
+  PEEK_CHECK_FAIL (&reader, d, 64, be);
+
+}
+
+GST_END_TEST;
+
+#undef GET_CHECK8
+#undef GET_CHECK
+#undef PEEK_CHECK8
+#undef PEEK_CHECK
+#undef GET_CHECK_FAIL8
+#undef GET_CHECK_FAIL
+#undef PEEK_CHECK_FAIL8
+#undef PEEK_CHECK_FAIL
+
+#define GET_CHECK(reader, dest, bits, endianness, val) { \
+  fail_unless (gst_byte_reader_get_float##bits##_##endianness (reader, &dest)); \
+  fail_unless_equals_float (dest, val); \
+}
+
+#define GET_CHECK_FAIL(reader, dest, bits, endianness) { \
+  fail_if (gst_byte_reader_get_float##bits##_##endianness (reader, &dest)); \
+}
+
+#define PEEK_CHECK(reader, dest, bits, endianness, val) { \
+  fail_unless (gst_byte_reader_peek_float##bits##_##endianness (reader, &dest)); \
+  fail_unless_equals_float (dest, val); \
+}
+
+#define PEEK_CHECK_FAIL(reader, dest, bits, endianness) { \
+  fail_if (gst_byte_reader_peek_float##bits##_##endianness (reader, &dest)); \
+}
+
+GST_START_TEST (test_get_float_le)
+{
+  guint8 data[] = {
+    0x00, 0x00, 0x80, 0x3f,
+    0x00, 0x00, 0x80, 0xbf,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x3f,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xbf,
+  };
+  GstByteReader reader = GST_BYTE_READER_INIT (data, 24);
+  gfloat a;
+  gdouble b;
+
+  PEEK_CHECK (&reader, a, 32, le, 1.0);
+  GET_CHECK (&reader, a, 32, le, 1.0);
+  GET_CHECK (&reader, a, 32, le, -1.0);
+  PEEK_CHECK (&reader, b, 64, le, 1.0);
+  GET_CHECK (&reader, b, 64, le, 1.0);
+  GET_CHECK (&reader, b, 64, le, -1.0);
+  GET_CHECK_FAIL (&reader, a, 32, le);
+  GET_CHECK_FAIL (&reader, b, 64, le);
+  PEEK_CHECK_FAIL (&reader, a, 32, le);
+  PEEK_CHECK_FAIL (&reader, b, 64, le);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_get_float_be)
+{
+  guint8 data[] = {
+    0x3f, 0x80, 0x00, 0x00,
+    0xbf, 0x80, 0x00, 0x00,
+    0x3f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0xbf, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+  };
+  GstByteReader reader = GST_BYTE_READER_INIT (data, 24);
+  gfloat a;
+  gdouble b;
+
+  PEEK_CHECK (&reader, a, 32, be, 1.0);
+  GET_CHECK (&reader, a, 32, be, 1.0);
+  GET_CHECK (&reader, a, 32, be, -1.0);
+  PEEK_CHECK (&reader, b, 64, be, 1.0);
+  GET_CHECK (&reader, b, 64, be, 1.0);
+  GET_CHECK (&reader, b, 64, be, -1.0);
+  GET_CHECK_FAIL (&reader, a, 32, be);
+  GET_CHECK_FAIL (&reader, b, 64, be);
+  PEEK_CHECK_FAIL (&reader, a, 32, be);
+  PEEK_CHECK_FAIL (&reader, b, 64, be);
+}
+
+GST_END_TEST;
+
+#undef GET_CHECK
+#undef PEEK_CHECK
+#undef GET_CHECK_FAIL
+#undef PEEK_CHECK_FAIL
+
+GST_START_TEST (test_position_tracking)
+{
+  guint8 data[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+  };
+  GstByteReader reader = GST_BYTE_READER_INIT (data, 16);
+  guint8 a;
+
+  fail_unless_equals_int (gst_byte_reader_get_pos (&reader), 0);
+  fail_unless_equals_int (gst_byte_reader_get_remaining (&reader), 16);
+
+  fail_unless (gst_byte_reader_get_uint8 (&reader, &a));
+  fail_unless_equals_int (gst_byte_reader_get_pos (&reader), 1);
+  fail_unless_equals_int (gst_byte_reader_get_remaining (&reader), 16 - 1);
+
+  fail_unless (gst_byte_reader_set_pos (&reader, 8));
+  fail_unless_equals_int (gst_byte_reader_get_pos (&reader), 8);
+  fail_unless_equals_int (gst_byte_reader_get_remaining (&reader), 16 - 8);
+
+  fail_unless (gst_byte_reader_skip (&reader, 4));
+  fail_unless_equals_int (gst_byte_reader_get_pos (&reader), 12);
+  fail_unless_equals_int (gst_byte_reader_get_remaining (&reader), 16 - 12);
+
+  fail_unless (gst_byte_reader_set_pos (&reader, 16));
+  fail_unless_equals_int (gst_byte_reader_get_pos (&reader), 16);
+  fail_unless_equals_int (gst_byte_reader_get_remaining (&reader), 0);
+
+  fail_unless (gst_byte_reader_skip (&reader, 0));
+  fail_if (gst_byte_reader_skip (&reader, 1));
+}
+
+GST_END_TEST;
+
+static Suite *
+gst_byte_reader_suite (void)
+{
+  Suite *s = suite_create ("GstByteReader");
+  TCase *tc_chain = tcase_create ("general");
+
+  suite_add_tcase (s, tc_chain);
+
+  tcase_add_test (tc_chain, test_initialization);
+  tcase_add_test (tc_chain, test_get_uint_le);
+  tcase_add_test (tc_chain, test_get_uint_be);
+  tcase_add_test (tc_chain, test_get_int_le);
+  tcase_add_test (tc_chain, test_get_int_be);
+  tcase_add_test (tc_chain, test_get_float_le);
+  tcase_add_test (tc_chain, test_get_float_be);
+  tcase_add_test (tc_chain, test_position_tracking);
+
+  return s;
+}
+
+
+GST_CHECK_MAIN (gst_byte_reader);