mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-18 15:51:11 +00:00
fb4fc8fc09
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
444 lines
11 KiB
C
444 lines
11 KiB
C
/*
|
|
* 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);
|
|
}
|