libs: add generic bitstream writer.

GstBitWriter provides a bit writer that can write any number of bits
to a pre-allocated memory buffer. Helper functions are also provided
to write any number of bits from 8, 16, 32 and 64 bit variables.

Signed-off-by: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
This commit is contained in:
Wind Yuan 2013-07-29 15:41:23 +08:00 committed by Gwenole Beauchesne
parent 02e174c8bc
commit 99947d0592
6 changed files with 685 additions and 1 deletions

View file

@ -775,6 +775,7 @@ debian.upstream/libgstvaapi-x11.install.in
ext/Makefile
gst-libs/Makefile
gst-libs/gst/Makefile
gst-libs/gst/base/Makefile
gst-libs/gst/codecparsers/Makefile
gst-libs/gst/vaapi/Makefile
gst-libs/gst/video/Makefile

View file

@ -1,4 +1,4 @@
SUBDIRS = codecparsers video vaapi
SUBDIRS = base codecparsers video vaapi
# Extra clean files so that maintainer-clean removes *everything*
MAINTAINERCLEANFILES = Makefile.in $(gen_headers)

View file

@ -0,0 +1,43 @@
noinst_LTLIBRARIES = \
libgstvaapi-baseutils.la \
$(NULL)
source_c = \
gstbitwriter.c \
$(NULL)
source_h = \
gstbitwriter.h \
$(NULL)
libgstvaapi_baseutils_cflags = \
-DGST_USE_UNSTABLE_API \
-I$(top_srcdir)/gst-libs \
-I$(top_builddir)/gst-libs \
$(GST_BASE_CFLAGS) \
$(GST_CFLAGS) \
$(NULL)
libgstvaapi_baseutils_libs = \
$(GST_BASE_LIBS) \
$(GST_LIBS) \
$(NULL)
nodist_libgstvaapi_baseutils_la_SOURCES = \
$(source_c) \
$(NULL)
libgstvaapi_baseutils_la_CFLAGS = \
$(libgstvaapi_baseutils_cflags) \
$(NULL)
libgstvaapi_baseutils_la_LIBADD = \
$(libgstvaapi_baseutils_libs) \
$(NULL)
libgstvaapi_baseutils_la_LDFLAGS = \
$(GST_ALL_LDFLAGS) \
$(NULL)
# Extra clean files so that maintainer-clean removes *everything*
MAINTAINERCLEANFILES = Makefile.in

View file

@ -0,0 +1,278 @@
/*
* gstbitwriter.c - bitstream writer
*
* 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
*/
#define GST_BIT_WRITER_DISABLE_INLINES
#include "gstbitwriter.h"
/**
* gst_bit_writer_init:
* @bitwriter: a #GstBitWriter instance
* @reserved_bits: reserved bits to allocate data
*
* Initializes a #GstBitWriter instance and allocate @reserved_bits
* data inside.
*
* Cleanup function: gst_bit_writer_clear
*/
void
gst_bit_writer_init (GstBitWriter * bitwriter, guint32 reserved_bits)
{
bitwriter->bit_size = 0;
bitwriter->data = NULL;
bitwriter->bit_capacity = 0;
bitwriter->auto_grow = TRUE;
if (reserved_bits)
_gst_bit_writer_check_space (bitwriter, reserved_bits);
}
/**
* gst_bit_writer_init_fill:
* @bitwriter: a #GstBitWriter instance
* @data: allocated data
* @bits: size of allocated @data in bits
*
* Initializes a #GstBitWriter instance with alocated @data and @bit outside.
*
* Cleanup function: gst_bit_writer_clear
*/
void
gst_bit_writer_init_fill (GstBitWriter * bitwriter, guint8 * data, guint bits)
{
bitwriter->bit_size = 0;
bitwriter->data = data;
bitwriter->bit_capacity = bits;
bitwriter->auto_grow = FALSE;
}
/**
* gst_bit_writer_clear:
* @bitwriter: a #GstBitWriter instance
* @free_data: flag to free #GstBitWriter allocated data
*
* Clear a #GstBitWriter instance and destroy allocated data inside
* if @free_data is %TRUE.
*/
void
gst_bit_writer_clear (GstBitWriter * bitwriter, gboolean free_data)
{
if (bitwriter->auto_grow && bitwriter->data && free_data)
g_free (bitwriter->data);
bitwriter->data = NULL;
bitwriter->bit_size = 0;
bitwriter->bit_capacity = 0;
}
/**
* gst_bit_writer_new:
* @bitwriter: a #GstBitWriter instance
* @reserved_bits: reserved bits to allocate data
*
* Create a #GstBitWriter instance and allocate @reserved_bits data inside.
*
* Free-function: gst_bit_writer_free
*
* Returns: a new #GstBitWriter instance
*/
GstBitWriter *
gst_bit_writer_new (guint32 reserved_bits)
{
GstBitWriter *ret = g_slice_new0 (GstBitWriter);
gst_bit_writer_init (ret, reserved_bits);
return ret;
}
/**
* gst_bit_writer_new_fill:
* @bitwriter: a #GstBitWriter instance
* @data: allocated data
* @bits: size of allocated @data in bits
*
* Create a #GstBitWriter instance with allocated @data and @bit outside.
*
* Free-function: gst_bit_writer_free
*
* Returns: a new #GstBitWriter instance
*/
GstBitWriter *
gst_bit_writer_new_fill (guint8 * data, guint bits)
{
GstBitWriter *ret = g_slice_new0 (GstBitWriter);
gst_bit_writer_init_fill (ret, data, bits);
return ret;
}
/**
* gst_bit_writer_free:
* @bitwriter: a #GstBitWriter instance
* @free_data: flag to free @data which is allocated inside
*
* Clear a #GstBitWriter instance and destroy allocated data inside if
* @free_data is %TRUE
*/
void
gst_bit_writer_free (GstBitWriter * writer, gboolean free_data)
{
g_return_if_fail (writer != NULL);
gst_bit_writer_clear (writer, free_data);
g_slice_free (GstBitWriter, writer);
}
/**
* 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 (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 (GstBitWriter * bitwriter)
{
return _gst_bit_writer_get_data_inline (bitwriter);
}
/**
* gst_bit_writer_get_data:
* @bitwriter: a #GstBitWriter instance
* @pos: new position of data end
*
* 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.
*/
#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
/**
* 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);
}

View file

@ -0,0 +1,361 @@
/*
* gstbitwriter.h - bitstream writer
*
* 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
*/
#ifndef GST_BIT_WRITER_H
#define GST_BIT_WRITER_H
#include <gst/gst.h>
#include <string.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
*
* A bit writer instance.
*/
struct _GstBitWriter
{
guint8 *data;
guint bit_size;
/*< private >*/
guint bit_capacity;
gboolean auto_grow;
gpointer _gst_reserved[GST_PADDING];
};
GstBitWriter *
gst_bit_writer_new (guint32 reserved_bits) G_GNUC_MALLOC;
GstBitWriter *
gst_bit_writer_new_fill (guint8 * data, guint bits) G_GNUC_MALLOC;
void
gst_bit_writer_free (GstBitWriter * writer, gboolean free_data);
void
gst_bit_writer_init (GstBitWriter * bitwriter, guint32 reserved_bits);
void
gst_bit_writer_init_fill (GstBitWriter * bitwriter, guint8 * data, guint bits);
void
gst_bit_writer_clear (GstBitWriter * bitwriter, gboolean free_data);
guint
gst_bit_writer_get_size (GstBitWriter * bitwriter);
guint8 *
gst_bit_writer_get_data (GstBitWriter * bitwriter);
gboolean
gst_bit_writer_set_pos (GstBitWriter * bitwriter, guint pos);
guint
gst_bit_writer_get_space (GstBitWriter * bitwriter);
gboolean
gst_bit_writer_put_bits_uint8 (GstBitWriter * bitwriter,
guint8 value, guint nbits);
gboolean
gst_bit_writer_put_bits_uint16 (GstBitWriter * bitwriter,
guint16 value, guint nbits);
gboolean
gst_bit_writer_put_bits_uint32 (GstBitWriter * bitwriter,
guint32 value, guint nbits);
gboolean
gst_bit_writer_put_bits_uint64 (GstBitWriter * bitwriter,
guint64 value, guint nbits);
gboolean
gst_bit_writer_put_bytes (GstBitWriter * bitwriter, const guint8 * data,
guint nbytes);
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_space (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 (GstBitWriter * bitwriter)
{
return GST_BIT_WRITER_BIT_SIZE (bitwriter);
}
static inline guint8 *
gst_bit_writer_get_data_unchecked (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_space_unchecked (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_space(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 (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 (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_space_inline (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_space_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_space (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_space(bitwriter) \
_gst_bit_writer_get_space_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 */

View file

@ -39,6 +39,7 @@ libgstvaapi_libs = \
$(GST_VIDEO_LIBS) \
$(GST_CODEC_PARSERS_LIBS) \
$(LIBVA_LIBS) \
$(top_builddir)/gst-libs/gst/base/libgstvaapi-baseutils.la \
$(top_builddir)/gst-libs/gst/video/libgstvaapi-videoutils.la \
$(top_builddir)/gst-libs/gst/codecparsers/libgstvaapi-codecparsers.la