bitwriter: Add a generic bit writer
authorWind Yuan <feng.yuan@intel.com>
Tue, 12 Nov 2013 07:00:51 +0000 (15:00 +0800)
committerVíctor Manuel Jáquez Leal <vjaquez@igalia.com>
Sun, 6 May 2018 15:05:21 +0000 (17:05 +0200)
GstBitWriter provides a bit writer that can write any number of
bits into a memory buffer. It provides functions for writing any
number of bits into 8, 16, 32 and 64 bit variables.

https://bugzilla.gnome.org/show_bug.cgi?id=707543

docs/libs/gstreamer-libs-docs.sgml
docs/libs/gstreamer-libs-sections.txt
libs/gst/base/Makefile.am
libs/gst/base/gstbitwriter-docs.h [new file with mode: 0644]
libs/gst/base/gstbitwriter.c [new file with mode: 0644]
libs/gst/base/gstbitwriter.h [new file with mode: 0644]
libs/gst/base/meson.build
win32/common/libgstbase.def

index 8225f13..620db5b 100644 (file)
@@ -44,6 +44,7 @@
 
       <xi:include href="xml/gstadapter.xml" />
       <xi:include href="xml/gstbitreader.xml" />
+      <xi:include href="xml/gstbitwriter.xml" />
       <xi:include href="xml/gstbytereader.xml" />
       <xi:include href="xml/gstbytewriter.xml" />
       <xi:include href="xml/gstcollectpads.xml" />
index 1da69ce..19b331a 100644 (file)
@@ -517,6 +517,62 @@ GST_BIT_READER
 </SECTION>
 
 <SECTION>
+<FILE>gstbitwriter</FILE>
+<TITLE>GstBitWriter</TITLE>
+<INCLUDE>gst/base/gstbitwriter.h</INCLUDE>
+GstBitWriter
+
+gst_bit_writer_new
+gst_bit_writer_new_with_size
+gst_bit_writer_new_with_data
+
+gst_bit_writer_free
+gst_bit_writer_free_and_get_buffer
+gst_bit_writer_free_and_get_data
+
+gst_bit_writer_init
+gst_bit_writer_init_with_size
+gst_bit_writer_init_with_data
+
+gst_bit_writer_reset
+gst_bit_writer_reset_and_get_buffer
+gst_bit_writer_reset_and_get_data
+
+gst_bit_writer_set_pos
+
+gst_bit_writer_get_size
+gst_bit_writer_get_data
+gst_bit_writer_get_remaining
+
+gst_bit_writer_get_size_unchecked
+gst_bit_writer_get_data_unchecked
+gst_bit_writer_set_pos_unchecked
+gst_bit_writer_get_remaining_unchecked
+
+gst_bit_writer_put_bits_uint16
+gst_bit_writer_put_bits_uint32
+gst_bit_writer_put_bits_uint64
+gst_bit_writer_put_bits_uint8
+gst_bit_writer_put_bytes
+
+gst_bit_writer_put_bits_uint16_unchecked
+gst_bit_writer_put_bits_uint32_unchecked
+gst_bit_writer_put_bits_uint64_unchecked
+gst_bit_writer_put_bits_uint8_unchecked
+gst_bit_writer_put_bytes_unchecked
+
+gst_bit_writer_align_bytes
+gst_bit_writer_align_bytes_unchecked
+
+<SUBSECTION Standard>
+GST_BIT_WRITER_BIT_SIZE
+GST_BIT_WRITER_DATA
+
+<SUBSECTION Private>
+GST_BIT_WRITER
+</SECTION>
+
+<SECTION>
 <FILE>gstbytereader</FILE>
 <TITLE>GstByteReader</TITLE>
 <INCLUDE>gst/base/gstbytereader.h</INCLUDE>
index 76551f8..199a25a 100644 (file)
@@ -10,6 +10,7 @@ libgstbase_@GST_API_VERSION@_la_SOURCES = \
        gstbasesrc.c            \
        gstbasetransform.c      \
        gstbitreader.c          \
+       gstbitwriter.c          \
        gstbytereader.c         \
        gstbytewriter.c         \
        gstcollectpads.c        \
@@ -36,6 +37,7 @@ libgstbase_@GST_API_VERSION@include_HEADERS = \
        gstbasesrc.h            \
        gstbasetransform.h      \
        gstbitreader.h          \
+       gstbitwriter.h          \
        gstbytereader.h         \
        gstbytewriter.h         \
        gstcollectpads.h        \
@@ -49,6 +51,7 @@ noinst_HEADERS = \
        gstbytereader-docs.h \
        gstbytewriter-docs.h \
        gstbitreader-docs.h \
+       gstbitwriter-docs.h \
        gstindex.h
 
 EXTRA_DIST = gstindex.c gstmemindex.c
diff --git a/libs/gst/base/gstbitwriter-docs.h b/libs/gst/base/gstbitwriter-docs.h
new file mode 100644 (file)
index 0000000..bc44db8
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ *  GStreamer bit writer dummy header for gtk-doc
+ *
+ *  Copyright (C) 2013 Intel Corporation
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  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
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+/* This header is not installed, it just contains stuff for gtk-doc to parse,
+ * in particular docs and some dummy function declarations for the static
+ * inline functions we generate via macros in gstbitwriter.h.
+ */
+
+#error "This header should never be included in code, it is only for gtk-doc"
+
+/**
+ * gst_bit_writer_put_bits_uint8_unchecked:
+ * @bitwriter: a #GstBitWriter instance
+ * @value: value of #guint8 to write
+ * @nbits: number of bits to write
+ *
+ * Write @nbits bits of @value to #GstBitWriter without checking whether
+ * there is enough space
+ */
+void gst_bit_writer_put_bits_uint8_unchecked (GstBitWriter *bitwriter, guint8 value, guint nbits);
+
+/**
+ * gst_bit_writer_put_bits_uint16_unchecked:
+ * @bitwriter: a #GstBitWriter instance
+ * @value: value of #guint16 to write
+ * @nbits: number of bits to write
+ *
+ * Write @nbits bits of @value to #GstBitWriter without checking whether
+ * there is enough space
+ */
+void gst_bit_writer_put_bits_uint16_unchecked (GstBitWriter *bitwriter, guint16 value, guint nbits);
+
+/**
+ * gst_bit_writer_put_bits_uint32_unchecked:
+ * @bitwriter: a #GstBitWriter instance
+ * @value: value of #guint32 to write
+ * @nbits: number of bits to write
+ *
+ * Write @nbits bits of @value to #GstBitWriter without checking whether
+ * there is enough space
+ */
+void gst_bit_writer_put_bits_uint32_unchecked (GstBitWriter *bitwriter, guint32 value, guint nbits);
+
+/**
+ * gst_bit_writer_put_bits_uint64_unchecked:
+ * @bitwriter: a #GstBitWriter instance
+ * @value: value of #guint64 to write
+ * @nbits: number of bits to write
+ *
+ * Write @nbits bits of @value to #GstBitWriter without checking whether
+ * there is enough space
+ */
+void gst_bit_writer_put_bits_uint64_unchecked (GstBitWriter *bitwriter, guint64 value, guint nbits);
+
+/**
+ * gst_bit_writer_put_bytes_unchecked:
+ * @bitwriter: a #GstBitWriter instance
+ * @data: pointer of data to write
+ * @nbytes: number of bytes to write
+ *
+ * Write @nbytes bytes of @data to #GstBitWriter without checking whether
+ * there is enough space
+ */
+void gst_bit_writer_put_bytes_unchecked (GstBitWriter *bitwriter, const guint8 *data, guint nbytes);
+
+/**
+ * gst_bit_writer_align_bytes_unchecked:
+ * @bitwriter: a #GstBitWriter instance
+ * @trailing_bit: trailing bits of last byte, 0 or 1
+ *
+ * Write trailing bit to align last byte of @data without checking whether there
+ * is enough space
+ */
+void gst_bit_writer_align_bytes_unchecked (GstBitWriter *bitwriter, guint8 trailing_bit);
diff --git a/libs/gst/base/gstbitwriter.c b/libs/gst/base/gstbitwriter.c
new file mode 100644 (file)
index 0000000..89e9fbc
--- /dev/null
@@ -0,0 +1,444 @@
+/*
+ *  gstbitwriter.c - bitstream writer
+ *
+ *  Copyright (C) 2013 Intel Corporation
+ *  Copyright (C) 2018 Igalia, S.L.
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  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
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#define GST_BIT_WRITER_DISABLE_INLINES
+#include "gstbitwriter.h"
+
+/**
+ * SECTION:gstbitwriter
+ * @title: GstBitWriter
+ * @short_description: Writes any number of bits into a memory buffer
+ *
+ * #GstBitWriter provides a bit writer that can write any number of
+ * bits into a memory buffer. It provides functions for writing any
+ * number of bits into 8, 16, 32 and 64 bit variables.
+ */
+
+/**
+ * gst_bit_writer_new:
+ *
+ * Creates a new, empty #GstBitWriter instance.
+ *
+ * Free-function: gst_bit_writer_free
+ *
+ * Returns: (transfer full): a new, empty #GstByteWriter instance
+ **/
+GstBitWriter *
+gst_bit_writer_new (void)
+{
+  GstBitWriter *ret = g_slice_new0 (GstBitWriter);
+
+  ret->owned = TRUE;
+  ret->auto_grow = TRUE;
+  return ret;
+}
+
+/**
+ * gst_bit_writer_new_size:
+ * @size: Initial size of data in bytes
+ * @fixed: If %TRUE the data can't be reallocated
+ *
+ * Creates a #GstBitWriter instance with the given initial data size.
+ *
+ * Free-function: gst_bit_writer_free
+ *
+ * Returns: (transfer full): a new #GstBitWriter instance
+ */
+GstBitWriter *
+gst_bit_writer_new_with_size (guint size, gboolean fixed)
+{
+  GstBitWriter *ret = g_slice_new0 (GstBitWriter);
+
+  gst_bit_writer_init_with_size (ret, size, fixed);
+  return ret;
+}
+
+/**
+ * gst_bit_writer_new_with_data:
+ * @data: Memory area for writing
+ * @size: Size of @data in bytes
+ * @initialized: if %TRUE the complete data can be read from the beginning
+ *
+ * Creates a new #GstBitWriter instance with the given memory area. If
+ * @initialized is %TRUE it is possible to read @size bits from the
+ * #GstBitWriter from the beginnig.
+ *
+ * Free-function: gst_bit_writer_free
+ *
+ * Returns: (transfer full): a new #GstBitWriter instance
+ */
+GstBitWriter *
+gst_bit_writer_new_with_data (guint8 * data, guint size, gboolean initialized)
+{
+  GstBitWriter *ret = g_slice_new0 (GstBitWriter);
+
+  gst_bit_writer_init_with_data (ret, data, size, initialized);
+
+  return ret;
+}
+
+/**
+ * gst_bit_writer_init:
+ * @bitwriter: #GstBitWriter instance
+ *
+ * Initializes @bitwriter to an empty instance.
+ **/
+void
+gst_bit_writer_init (GstBitWriter * bitwriter)
+{
+  g_return_if_fail (bitwriter != NULL);
+
+  memset (bitwriter, 0, sizeof (GstBitWriter));
+  bitwriter->owned = TRUE;
+  bitwriter->auto_grow = TRUE;
+}
+
+/**
+ * gst_bit_writer_init_with_size:
+ * @bitwriter: #GstBitWriter instance
+ * @size: the size on bytes to allocate for data
+ * @fixed: If %TRUE the data can't be reallocated
+ *
+ * Initializes a #GstBitWriter instance and allocates the given data
+ * @size.
+ */
+void
+gst_bit_writer_init_with_size (GstBitWriter * bitwriter, guint size,
+    gboolean fixed)
+{
+  g_return_if_fail (bitwriter != NULL);
+
+  gst_bit_writer_init (bitwriter);
+
+  _gst_bit_writer_check_remaining (bitwriter, size << 3);
+
+  bitwriter->auto_grow = !fixed;
+}
+
+/**
+ * gst_bit_writer_init_with_data:
+ * @bitwriter: #GstBitWriter instance
+ * @data: (array length=size) (transfer none): Memory area for writing
+ * @size: Size of @data in bytes
+ * @initialized: If %TRUE the complete data can be read from the beginning
+ *
+ * Initializes @bitwriter with the given memory area @data. IF
+ * @initialized is %TRUE it is possible to read @size bits from the
+ * #GstBitWriter from the beginning.
+ */
+void
+gst_bit_writer_init_with_data (GstBitWriter * bitwriter, guint8 * data,
+    guint size, gboolean initialized)
+{
+  g_return_if_fail (bitwriter != NULL);
+
+  gst_bit_writer_init (bitwriter);
+
+  bitwriter->data = data;
+  bitwriter->bit_capacity = size * 8;
+  bitwriter->bit_size = (initialized) ? size << 3 : 0;
+  bitwriter->auto_grow = FALSE;
+  bitwriter->owned = FALSE;
+}
+
+/**
+ * gst_bit_writer_reset:
+ * @bitwriter: #GstBitWriter instance
+ *
+ * Resets @bitwriter and frees the data if it's owned by @bitwriter.
+ */
+void
+gst_bit_writer_reset (GstBitWriter * bitwriter)
+{
+  g_return_if_fail (bitwriter != NULL);
+
+  if (bitwriter->owned)
+    g_free (bitwriter->data);
+  memset (bitwriter, 0, sizeof (GstBitWriter));
+}
+
+/**
+ * gst_bit_writer_reset_and_get_data:
+ * @bitwriter: a #GstBitWriter instance
+ *
+ * Resets @bitwriter and returns the current data.
+ *
+ * Free-function: g_free
+ *
+ * Returns: (array) (transfer full): the current data. g_free() after
+ *     usage.
+ **/
+guint8 *
+gst_bit_writer_reset_and_get_data (GstBitWriter * bitwriter)
+{
+  guint8 *data;
+
+  g_return_val_if_fail (bitwriter != NULL, NULL);
+
+  data = bitwriter->data;
+  if (bitwriter->owned)
+    data = g_memdup (data, bitwriter->bit_size >> 3);
+  gst_bit_writer_reset (bitwriter);
+
+  return data;
+}
+
+/**
+ * gst_bit_writer_reset_and_get_buffer:
+ * @bitwriter: a #GstBitWriter instance
+ *
+ * Resets @bitwriter and returns the current data as #GstBuffer.
+ *
+ * Free-function: gst_buffer_unref
+ *
+ * Returns: (transfer full): a new allocated #GstBuffer wrapping the
+ *     current data. gst_buffer_unref() after usage.
+ **/
+GstBuffer *
+gst_bit_writer_reset_and_get_buffer (GstBitWriter * bitwriter)
+{
+  GstBuffer *buffer;
+  gpointer data;
+  gsize size;
+
+  g_return_val_if_fail (bitwriter != NULL, NULL);
+
+  size = bitwriter->bit_size >> 3;
+  data = gst_bit_writer_reset_and_get_data (bitwriter);
+
+  /* we cannot rely on buffers allocated externally, thus let's dup
+   * the data */
+  if (data && !bitwriter->owned)
+    data = g_memdup (data, size);
+
+  buffer = gst_buffer_new ();
+  if (data != NULL) {
+    gst_buffer_append_memory (buffer,
+        gst_memory_new_wrapped (0, data, size, 0, size, data, g_free));
+  }
+
+  return buffer;
+}
+
+/**
+ * gst_bit_writer_free:
+ * @bitwriter: (in) (transfer full): #GstBitWriter instance
+ *
+ * Frees @bitwriter and the allocated data inside.
+ */
+void
+gst_bit_writer_free (GstBitWriter * bitwriter)
+{
+  g_return_if_fail (bitwriter != NULL);
+
+  gst_bit_writer_reset (bitwriter);
+  g_slice_free (GstBitWriter, bitwriter);
+}
+
+/**
+ * gst_bit_writer_free_and_get_data:
+ * @bitwriter: (in) (transfer full): #GstBitWriter instance
+ *
+ * Frees @bitwriter without destroying the internal data, which is
+ * returned.
+ *
+ * Free-function: g_free
+ *
+ * Returns: (array) (transfer full): the current data. g_free() after
+ *     usage.
+ **/
+guint8 *
+gst_bit_writer_free_and_get_data (GstBitWriter * bitwriter)
+{
+  guint8 *data;
+
+  g_return_val_if_fail (bitwriter != NULL, NULL);
+
+  data = gst_bit_writer_reset_and_get_data (bitwriter);
+  g_slice_free (GstBitWriter, bitwriter);
+
+  return data;
+}
+
+/**
+ * gst_bit_writer_free_and_get_buffer:
+ * @bitwriter: (in) (transfer full): #GstBitWriter instance
+ *
+ * Frees @bitwriter without destroying the internal data, which is
+ * returned as #GstBuffer.
+ *
+ * Free-function: gst_buffer_unref
+ *
+ * Returns: (transfer full): a new allocated #GstBuffer wrapping the
+ *     data inside. gst_buffer_unref() after usage.
+ **/
+GstBuffer *
+gst_bit_writer_free_and_get_buffer (GstBitWriter * bitwriter)
+{
+  GstBuffer *buffer;
+
+  g_return_val_if_fail (bitwriter != NULL, NULL);
+
+  buffer = gst_bit_writer_reset_and_get_buffer (bitwriter);
+  g_slice_free (GstBitWriter, bitwriter);
+
+  return buffer;
+}
+
+/**
+ * gst_bit_writer_get_size:
+ * @bitwriter: a #GstBitWriter instance
+ *
+ * Get size of written @data
+ *
+ * Returns: size of bits written in @data
+ */
+guint
+gst_bit_writer_get_size (const GstBitWriter * bitwriter)
+{
+  return _gst_bit_writer_get_size_inline (bitwriter);
+}
+
+/**
+ * gst_bit_writer_get_data:
+ * @bitwriter: a #GstBitWriter instance
+ *
+ * Get written data pointer
+ *
+ * Returns: data pointer
+ */
+guint8 *
+gst_bit_writer_get_data (const GstBitWriter * bitwriter)
+{
+  return _gst_bit_writer_get_data_inline (bitwriter);
+}
+
+/**
+ * gst_bit_writer_get_pos:
+ * @bitwriter: a #GstBitWriter instance
+ * @pos: The new position in bits
+ *
+ * Set the new postion of data end which should be the new size of @data.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise
+ */
+gboolean
+gst_bit_writer_set_pos (GstBitWriter * bitwriter, guint pos)
+{
+  return _gst_bit_writer_set_pos_inline (bitwriter, pos);
+}
+
+/**
+ * gst_bit_writer_put_bits_uint8:
+ * @bitwriter: a #GstBitWriter instance
+ * @value: value of #guint8 to write
+ * @nbits: number of bits to write
+ *
+ * Write @nbits bits of @value to #GstBitWriter.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ */
+
+/**
+ * gst_bit_writer_put_bits_uint16:
+ * @bitwriter: a #GstBitWriter instance
+ * @value: value of #guint16 to write
+ * @nbits: number of bits to write
+ *
+ * Write @nbits bits of @value to #GstBitWriter.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ */
+
+/**
+ * gst_bit_writer_put_bits_uint32:
+ * @bitwriter: a #GstBitWriter instance
+ * @value: value of #guint32 to write
+ * @nbits: number of bits to write
+ *
+ * Write @nbits bits of @value to #GstBitWriter.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ */
+
+/**
+ * gst_bit_writer_put_bits_uint64:
+ * @bitwriter: a #GstBitWriter instance
+ * @value: value of #guint64 to write
+ * @nbits: number of bits to write
+ *
+ * Write @nbits bits of @value to #GstBitWriter.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ */
+
+/* *INDENT-OFF* */
+#define GST_BIT_WRITER_WRITE_BITS(bits) \
+gboolean \
+gst_bit_writer_put_bits_uint##bits (GstBitWriter *bitwriter, guint##bits value, guint nbits) \
+{ \
+  return _gst_bit_writer_put_bits_uint##bits##_inline (bitwriter, value, nbits); \
+}
+
+GST_BIT_WRITER_WRITE_BITS (8)
+GST_BIT_WRITER_WRITE_BITS (16)
+GST_BIT_WRITER_WRITE_BITS (32)
+GST_BIT_WRITER_WRITE_BITS (64)
+#undef GST_BIT_WRITER_WRITE_BITS
+/* *INDENT-ON* */
+
+/**
+ * gst_bit_writer_put_bytes:
+ * @bitwriter: a #GstBitWriter instance
+ * @data: pointer of data to write
+ * @nbytes: number of bytes to write
+ *
+ * Write @nbytes bytes of @data to #GstBitWriter.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ */
+gboolean
+gst_bit_writer_put_bytes (GstBitWriter * bitwriter, const guint8 * data,
+    guint nbytes)
+{
+  return _gst_bit_writer_put_bytes_inline (bitwriter, data, nbytes);
+}
+
+/**
+ * gst_bit_writer_align_bytes:
+ * @bitwriter: a #GstBitWriter instance
+ * @trailing_bit: trailing bits of last byte, 0 or 1
+ *
+ * Write trailing bit to align last byte of @data. @trailing_bit can
+ * only be 1 or 0.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ */
+gboolean
+gst_bit_writer_align_bytes (GstBitWriter * bitwriter, guint8 trailing_bit)
+{
+  return _gst_bit_writer_align_bytes_inline (bitwriter, trailing_bit);
+}
diff --git a/libs/gst/base/gstbitwriter.h b/libs/gst/base/gstbitwriter.h
new file mode 100644 (file)
index 0000000..9e0b7c8
--- /dev/null
@@ -0,0 +1,386 @@
+/*
+ *  gstbitwriter.h - bitstream writer
+ *
+ *  Copyright (C) 2013 Intel Corporation
+ *  Copyright (C) 2018 Igalia, S. L.
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  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
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_BIT_WRITER_H
+#define GST_BIT_WRITER_H
+
+#include <gst/gst.h>
+#include <gst/base/base-prelude.h>
+
+G_BEGIN_DECLS
+
+#define GST_BIT_WRITER_DATA(writer)     ((writer)->data)
+#define GST_BIT_WRITER_BIT_SIZE(writer) ((writer)->bit_size)
+#define GST_BIT_WRITER(writer)          ((GstBitWriter *) (writer))
+
+typedef struct _GstBitWriter GstBitWriter;
+
+/**
+ * GstBitWriter:
+ * @data: Allocated @data for bit writer to write
+ * @bit_size: Size of written @data in bits
+ *
+ * Private:
+ * @bit_capacity: Capacity of the allocated @data
+ * @auto_grow: @data space can auto grow
+ * @destroy_data: The #GDestroyNotify function called with #data when the memory
+ *                is freed
+ *
+ * A bit writer instance.
+ */
+struct _GstBitWriter
+{
+  guint8 *data;
+  guint bit_size;
+
+  /*< private >*/
+  guint bit_capacity;
+  gboolean auto_grow;
+  gboolean owned;
+  gpointer _gst_reserved[GST_PADDING];
+};
+
+GST_BASE_API
+GstBitWriter *  gst_bit_writer_new              (void) G_GNUC_MALLOC;
+
+GST_BASE_API
+GstBitWriter *  gst_bit_writer_new_with_size    (guint32 size, gboolean fixed) G_GNUC_MALLOC;
+
+GST_BASE_API
+GstBitWriter *  gst_bit_writer_new_with_data    (guint8 *data, guint size,
+                                                gboolean initialized) G_GNUC_MALLOC;
+
+GST_BASE_API
+void            gst_bit_writer_free             (GstBitWriter *bitwriter);
+
+GST_BASE_API
+guint8 *        gst_bit_writer_free_and_get_data (GstBitWriter *bitwriter);
+
+GST_BASE_API
+GstBuffer *     gst_bit_writer_free_and_get_buffer (GstBitWriter *bitwriter);
+
+GST_BASE_API
+void            gst_bit_writer_init             (GstBitWriter *bitwriter);
+
+GST_BASE_API
+void            gst_bit_writer_init_with_size   (GstBitWriter *bitwriter,
+                                                guint32 size, gboolean fixed);
+
+GST_BASE_API
+void            gst_bit_writer_init_with_data   (GstBitWriter *bitwriter,  guint8 *data,
+                                                guint size, gboolean initialized);
+
+GST_BASE_API
+void            gst_bit_writer_reset            (GstBitWriter *bitwriter);
+
+GST_BASE_API
+guint8 *        gst_bit_writer_reset_and_get_data (GstBitWriter *bitwriter);
+
+GST_BASE_API
+GstBuffer *     gst_bit_writer_reset_and_get_buffer (GstBitWriter *bitwriter);
+
+GST_BASE_API
+guint           gst_bit_writer_get_size         (const GstBitWriter *bitwriter);
+
+GST_BASE_API
+guint8 *        gst_bit_writer_get_data         (const GstBitWriter *bitwriter);
+
+GST_BASE_API
+gboolean        gst_bit_writer_set_pos          (GstBitWriter *bitwriter, guint pos);
+
+GST_BASE_API
+guint           gst_bit_writer_get_remaining    (const GstBitWriter *bitwriter);
+
+GST_BASE_API
+gboolean        gst_bit_writer_put_bits_uint8   (GstBitWriter *bitwriter, guint8 value,
+                                                guint nbits);
+
+GST_BASE_API
+gboolean        gst_bit_writer_put_bits_uint16  (GstBitWriter *bitwriter, guint16 value,
+                                                guint nbits);
+
+GST_BASE_API
+gboolean        gst_bit_writer_put_bits_uint32  (GstBitWriter *bitwriter, guint32 value,
+                                                guint nbits);
+
+GST_BASE_API
+gboolean        gst_bit_writer_put_bits_uint64  (GstBitWriter *bitwriter, guint64 value,
+                                                guint nbits);
+
+GST_BASE_API
+gboolean        gst_bit_writer_put_bytes        (GstBitWriter *bitwriter, const guint8 *data,
+                                                guint nbytes);
+
+GST_BASE_API
+gboolean        gst_bit_writer_align_bytes      (GstBitWriter *bitwriter, guint8 trailing_bit);
+
+static const guint8 _gst_bit_writer_bit_filling_mask[9] = {
+    0x00, 0x01, 0x03, 0x07,
+    0x0F, 0x1F, 0x3F, 0x7F,
+    0xFF
+};
+
+/* Aligned to 256 bytes */
+#define __GST_BITS_WRITER_ALIGNMENT_MASK 2047
+#define __GST_BITS_WRITER_ALIGNED(bitsize)                   \
+    (((bitsize) + __GST_BITS_WRITER_ALIGNMENT_MASK)&(~__GST_BITS_WRITER_ALIGNMENT_MASK))
+
+static inline gboolean
+_gst_bit_writer_check_remaining (GstBitWriter * bitwriter, guint32 bits)
+{
+  guint32 new_bit_size = bits + bitwriter->bit_size;
+  guint32 clear_pos;
+
+  g_assert (bitwriter->bit_size <= bitwriter->bit_capacity);
+  if (new_bit_size <= bitwriter->bit_capacity)
+    return TRUE;
+
+  if (!bitwriter->auto_grow)
+    return FALSE;
+
+  /* auto grow space */
+  new_bit_size = __GST_BITS_WRITER_ALIGNED (new_bit_size);
+  g_assert (new_bit_size
+      && ((new_bit_size & __GST_BITS_WRITER_ALIGNMENT_MASK) == 0));
+  clear_pos = ((bitwriter->bit_size + 7) >> 3);
+  bitwriter->data = g_realloc (bitwriter->data, (new_bit_size >> 3));
+  memset (bitwriter->data + clear_pos, 0, (new_bit_size >> 3) - clear_pos);
+  bitwriter->bit_capacity = new_bit_size;
+  return TRUE;
+}
+
+#undef __GST_BITS_WRITER_ALIGNMENT_MASK
+#undef __GST_BITS_WRITER_ALIGNED
+
+#define __GST_BIT_WRITER_WRITE_BITS_UNCHECKED(bits) \
+static inline void \
+gst_bit_writer_put_bits_uint##bits##_unchecked( \
+    GstBitWriter *bitwriter, \
+    guint##bits value, \
+    guint nbits \
+) \
+{ \
+    guint byte_pos, bit_offset; \
+    guint8  *cur_byte; \
+    guint fill_bits; \
+    \
+    byte_pos = (bitwriter->bit_size >> 3); \
+    bit_offset = (bitwriter->bit_size & 0x07); \
+    cur_byte = bitwriter->data + byte_pos; \
+    g_assert (nbits <= bits); \
+    g_assert( bit_offset < 8 && \
+            bitwriter->bit_size <= bitwriter->bit_capacity); \
+    \
+    while (nbits) { \
+        fill_bits = ((8 - bit_offset) < nbits ? (8 - bit_offset) : nbits); \
+        nbits -= fill_bits; \
+        bitwriter->bit_size += fill_bits; \
+        \
+        *cur_byte |= (((value >> nbits) & _gst_bit_writer_bit_filling_mask[fill_bits]) \
+                      << (8 - bit_offset - fill_bits)); \
+        ++cur_byte; \
+        bit_offset = 0; \
+    } \
+    g_assert(cur_byte <= \
+           (bitwriter->data + (bitwriter->bit_capacity >> 3))); \
+}
+
+__GST_BIT_WRITER_WRITE_BITS_UNCHECKED (8)
+__GST_BIT_WRITER_WRITE_BITS_UNCHECKED (16)
+__GST_BIT_WRITER_WRITE_BITS_UNCHECKED (32)
+__GST_BIT_WRITER_WRITE_BITS_UNCHECKED (64)
+#undef __GST_BIT_WRITER_WRITE_BITS_UNCHECKED
+
+static inline guint
+gst_bit_writer_get_size_unchecked (const GstBitWriter * bitwriter)
+{
+  return GST_BIT_WRITER_BIT_SIZE (bitwriter);
+}
+
+static inline guint8 *
+gst_bit_writer_get_data_unchecked (const GstBitWriter * bitwriter)
+{
+  return GST_BIT_WRITER_DATA (bitwriter);
+}
+
+static inline gboolean
+gst_bit_writer_set_pos_unchecked (GstBitWriter * bitwriter, guint pos)
+{
+  GST_BIT_WRITER_BIT_SIZE (bitwriter) = pos;
+  return TRUE;
+}
+
+static inline guint
+gst_bit_writer_get_remaining_unchecked (const GstBitWriter * bitwriter)
+{
+  return bitwriter->bit_capacity - bitwriter->bit_size;
+}
+
+static inline void
+gst_bit_writer_put_bytes_unchecked (GstBitWriter * bitwriter,
+    const guint8 * data, guint nbytes)
+{
+  if ((bitwriter->bit_size & 0x07) == 0) {
+    memcpy (&bitwriter->data[bitwriter->bit_size >> 3], data, nbytes);
+    bitwriter->bit_size += (nbytes << 3);
+  } else {
+    g_assert (0);
+    while (nbytes) {
+      gst_bit_writer_put_bits_uint8_unchecked (bitwriter, *data, 8);
+      --nbytes;
+      ++data;
+    }
+  }
+}
+
+static inline void
+gst_bit_writer_align_bytes_unchecked (GstBitWriter * bitwriter,
+    guint8 trailing_bit)
+{
+  guint32 bit_offset, bit_left;
+  guint8 value = 0;
+
+  bit_offset = (bitwriter->bit_size & 0x07);
+  if (!bit_offset)
+    return;
+
+  bit_left = 8 - bit_offset;
+  if (trailing_bit)
+    value = _gst_bit_writer_bit_filling_mask[bit_left];
+  return gst_bit_writer_put_bits_uint8_unchecked (bitwriter, value, bit_left);
+}
+
+#define __GST_BIT_WRITER_WRITE_BITS_INLINE(bits) \
+static inline gboolean \
+_gst_bit_writer_put_bits_uint##bits##_inline( \
+    GstBitWriter *bitwriter, \
+    guint##bits value, \
+    guint nbits \
+) \
+{ \
+    g_return_val_if_fail(bitwriter != NULL, FALSE); \
+    g_return_val_if_fail(nbits != 0, FALSE); \
+    g_return_val_if_fail(nbits <= bits, FALSE); \
+    \
+    if (!_gst_bit_writer_check_remaining(bitwriter, nbits)) \
+        return FALSE; \
+    gst_bit_writer_put_bits_uint##bits##_unchecked(bitwriter, value, nbits); \
+    return TRUE; \
+}
+
+__GST_BIT_WRITER_WRITE_BITS_INLINE (8)
+__GST_BIT_WRITER_WRITE_BITS_INLINE (16)
+__GST_BIT_WRITER_WRITE_BITS_INLINE (32)
+__GST_BIT_WRITER_WRITE_BITS_INLINE (64)
+#undef __GST_BIT_WRITER_WRITE_BITS_INLINE
+
+static inline guint
+_gst_bit_writer_get_size_inline (const GstBitWriter * bitwriter)
+{
+  g_return_val_if_fail (bitwriter != NULL, 0);
+
+  return gst_bit_writer_get_size_unchecked (bitwriter);
+}
+
+static inline guint8 *
+_gst_bit_writer_get_data_inline (const GstBitWriter * bitwriter)
+{
+  g_return_val_if_fail (bitwriter != NULL, NULL);
+
+  return gst_bit_writer_get_data_unchecked (bitwriter);
+}
+
+static inline gboolean
+_gst_bit_writer_set_pos_inline (GstBitWriter * bitwriter, guint pos)
+{
+  g_return_val_if_fail (bitwriter != NULL, FALSE);
+  g_return_val_if_fail (pos <= bitwriter->bit_capacity, FALSE);
+
+  return gst_bit_writer_set_pos_unchecked (bitwriter, pos);
+}
+
+static inline guint
+_gst_bit_writer_get_remaining_inline (const GstBitWriter * bitwriter)
+{
+  g_return_val_if_fail (bitwriter != NULL, 0);
+  g_return_val_if_fail (bitwriter->bit_size < bitwriter->bit_capacity, 0);
+
+  return gst_bit_writer_get_remaining_unchecked (bitwriter);
+}
+
+static inline gboolean
+_gst_bit_writer_put_bytes_inline (GstBitWriter * bitwriter,
+    const guint8 * data, guint nbytes)
+{
+  g_return_val_if_fail (bitwriter != NULL, FALSE);
+  g_return_val_if_fail (data != NULL, FALSE);
+  g_return_val_if_fail (nbytes, FALSE);
+
+  if (!_gst_bit_writer_check_remaining (bitwriter, nbytes * 8))
+    return FALSE;
+
+  gst_bit_writer_put_bytes_unchecked (bitwriter, data, nbytes);
+  return TRUE;
+}
+
+static inline gboolean
+_gst_bit_writer_align_bytes_inline (GstBitWriter * bitwriter,
+    guint8 trailing_bit)
+{
+  g_return_val_if_fail (bitwriter != NULL, FALSE);
+  g_return_val_if_fail ((trailing_bit == 0 || trailing_bit == 1), FALSE);
+  g_return_val_if_fail (((bitwriter->bit_size + 7) & (~7)) <=
+      bitwriter->bit_capacity, FALSE);
+
+  gst_bit_writer_align_bytes_unchecked (bitwriter, trailing_bit);
+  return TRUE;
+}
+
+#ifndef GST_BIT_WRITER_DISABLE_INLINES
+#define gst_bit_writer_get_size(bitwriter) \
+    _gst_bit_writer_get_size_inline(bitwriter)
+#define gst_bit_writer_get_data(bitwriter) \
+    _gst_bit_writer_get_data_inline(bitwriter)
+#define gst_bit_writer_set_pos(bitwriter, pos) \
+    G_LIKELY (_gst_bit_writer_set_pos_inline (bitwriter, pos))
+#define gst_bit_writer_get_remaining(bitwriter) \
+    _gst_bit_writer_get_remaining_inline(bitwriter)
+
+#define gst_bit_writer_put_bits_uint8(bitwriter, value, nbits) \
+    G_LIKELY (_gst_bit_writer_put_bits_uint8_inline (bitwriter, value, nbits))
+#define gst_bit_writer_put_bits_uint16(bitwriter, value, nbits) \
+    G_LIKELY (_gst_bit_writer_put_bits_uint16_inline (bitwriter, value, nbits))
+#define gst_bit_writer_put_bits_uint32(bitwriter, value, nbits) \
+    G_LIKELY (_gst_bit_writer_put_bits_uint32_inline (bitwriter, value, nbits))
+#define gst_bit_writer_put_bits_uint64(bitwriter, value, nbits) \
+    G_LIKELY (_gst_bit_writer_put_bits_uint64_inline (bitwriter, value, nbits))
+
+#define gst_bit_writer_put_bytes(bitwriter, data, nbytes) \
+    G_LIKELY (_gst_bit_writer_put_bytes_inline (bitwriter, data, nbytes))
+
+#define gst_bit_writer_align_bytes(bitwriter, trailing_bit) \
+    G_LIKELY (_gst_bit_writer_align_bytes_inline(bitwriter, trailing_bit))
+#endif
+
+G_END_DECLS
+
+#endif /* GST_BIT_WRITER_H */
index a7a9435..bc2a926 100644 (file)
@@ -6,6 +6,7 @@ gst_base_sources = [
   'gstbasesrc.c',
   'gstbasetransform.c',
   'gstbitreader.c',
+  'gstbitwriter.c',
   'gstbytereader.c',
   'gstbytewriter.c',
   'gstcollectpads.c',
@@ -26,6 +27,7 @@ gst_base_headers = [
   'gstbasesrc.h',
   'gstbasetransform.h',
   'gstbitreader.h',
+  'gstbitwriter.h',
   'gstbytereader.h',
   'gstbytewriter.h',
   'gstcollectpads.h',
@@ -79,6 +81,7 @@ install_headers('base.h',
   'gstbasesrc.h',
   'gstbasetransform.h',
   'gstbitreader.h',
+  'gstbitwriter.h',
   'gstbytereader.h',
   'gstbytewriter.h',
   'gstcollectpads.h',
index 49cd755..0725298 100644 (file)
@@ -149,6 +149,27 @@ EXPORTS
        gst_bit_reader_set_pos
        gst_bit_reader_skip
        gst_bit_reader_skip_to_byte
+       gst_bit_writer_align_bytes
+       gst_bit_writer_free
+       gst_bit_writer_free_and_get_buffer
+       gst_bit_writer_free_and_get_data
+       gst_bit_writer_get_data
+       gst_bit_writer_get_size
+       gst_bit_writer_init
+       gst_bit_writer_init_with_data
+       gst_bit_writer_init_with_size
+       gst_bit_writer_new
+       gst_bit_writer_new_with_data
+       gst_bit_writer_new_with_size
+       gst_bit_writer_put_bits_uint16
+       gst_bit_writer_put_bits_uint32
+       gst_bit_writer_put_bits_uint64
+       gst_bit_writer_put_bits_uint8
+       gst_bit_writer_put_bytes
+       gst_bit_writer_reset
+       gst_bit_writer_reset_and_get_buffer
+       gst_bit_writer_reset_and_get_data
+       gst_bit_writer_set_pos
        gst_byte_reader_dup_data
        gst_byte_reader_dup_string_utf16
        gst_byte_reader_dup_string_utf32