From dd762eb49f8e04f9f6fee84d9a00265e0410798f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Sun, 3 Oct 2010 15:27:37 +0200 Subject: [PATCH] bitreader: Add inlined and unchecked versions of the important functions API: gst_bit_reader_skip_unchecked API: gst_bit_reader_skip_to_byte_unchecked API: gst_bit_reader_get_bits_uint16_unchecked API: gst_bit_reader_get_bits_uint32_unchecked API: gst_bit_reader_get_bits_uint64_unchecked API: gst_bit_reader_get_bits_uint8_unchecked API: gst_bit_reader_peek_bits_uint16_unchecked API: gst_bit_reader_peek_bits_uint32_unchecked API: gst_bit_reader_peek_bits_uint64_unchecked API: gst_bit_reader_peek_bits_uint8_unchecked This alone makes flacparse about 3 times faster. --- docs/libs/gstreamer-libs-sections.txt | 13 ++ libs/gst/base/Makefile.am | 3 +- libs/gst/base/gstbitreader-docs.h | 165 ++++++++++++++++++++ libs/gst/base/gstbitreader.c | 82 +--------- libs/gst/base/gstbitreader.h | 209 ++++++++++++++++++++++++++ tests/check/libs/bitreader.c | 8 +- 6 files changed, 401 insertions(+), 79 deletions(-) create mode 100644 libs/gst/base/gstbitreader-docs.h diff --git a/docs/libs/gstreamer-libs-sections.txt b/docs/libs/gstreamer-libs-sections.txt index 09d75f3085..540186a61a 100644 --- a/docs/libs/gstreamer-libs-sections.txt +++ b/docs/libs/gstreamer-libs-sections.txt @@ -377,6 +377,19 @@ gst_bit_reader_peek_bits_uint32 gst_bit_reader_peek_bits_uint64 gst_bit_reader_peek_bits_uint8 +gst_bit_reader_skip_unchecked +gst_bit_reader_skip_to_byte_unchecked + +gst_bit_reader_get_bits_uint16_unchecked +gst_bit_reader_get_bits_uint32_unchecked +gst_bit_reader_get_bits_uint64_unchecked +gst_bit_reader_get_bits_uint8_unchecked + +gst_bit_reader_peek_bits_uint16_unchecked +gst_bit_reader_peek_bits_uint32_unchecked +gst_bit_reader_peek_bits_uint64_unchecked +gst_bit_reader_peek_bits_uint8_unchecked + GST_BIT_READER diff --git a/libs/gst/base/Makefile.am b/libs/gst/base/Makefile.am index 8beb7cbd68..50709657e0 100644 --- a/libs/gst/base/Makefile.am +++ b/libs/gst/base/Makefile.am @@ -36,7 +36,8 @@ libgstbase_@GST_MAJORMINOR@include_HEADERS = \ gstdataqueue.h noinst_HEADERS = \ - gstbytereader-docs.h + gstbytereader-docs.h \ + gstbitreader-docs.h CLEANFILES = *.gcno *.gcda *.gcov diff --git a/libs/gst/base/gstbitreader-docs.h b/libs/gst/base/gstbitreader-docs.h new file mode 100644 index 0000000000..47a7b72b6c --- /dev/null +++ b/libs/gst/base/gstbitreader-docs.h @@ -0,0 +1,165 @@ +/* GStreamer bit reader dummy header for gtk-doc + * Copyright (C) 2010 Sebastian Dröge + * + * 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. + */ + +/* 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 gstbitreader.h. + */ + +#error "This header should never be included in code, it is only for gtk-doc" + +/** + * gst_bit_reader_skip_unchecked: + * @reader: a #GstBitReader instance + * @nbits: the number of bits to skip + * + * Skips @nbits bits of the #GstBitReader instance without checking if there + * are enough bits available in the bit reader. + * + * Returns: %TRUE if @nbits bits could be skipped, %FALSE otherwise. + * + * Since: 0.10.31 + */ +void gst_bit_reader_skip_unchecked (GstBitReader * reader, guint nbits); + +/** + * gst_bit_reader_skip_to_byte_unchecked: + * @reader: a #GstBitReader instance + * + * Skips until the next byte without checking if there are enough bits + * available in the bit reader. + * + * Returns: %TRUE if successful, %FALSE otherwise. + * + * Since: 0.10.31 + */ +void gst_bit_reader_skip_to_byte_unchecked (GstBitReader * reader); + +/** + * gst_bit_reader_get_bits_uint8_unchecked: + * @reader: a #GstBitReader instance + * @nbits: number of bits to read + * + * Read @nbits bits into @val and update the current position without + * checking if there are enough bits available in the bit reader. + * + * Returns: unsigned 8 bit integer with the bits. + * + * Since: 0.10.31 + */ +guint8 gst_bit_reader_peek_bits_uint8_unchecked (const GstBitReader *reader, guint nbits); + +/** + * gst_bit_reader_peek_bits_uint8_unchecked: + * @reader: a #GstBitReader instance + * @nbits: number of bits to read + * + * Read @nbits bits into @val but keep the current position without + * checking if there are enough bits available in the bit reader + * + * Returns: unsigned 8 bit integer with the bits. + * + * Since: 0.10.31 + */ +guint8 gst_bit_reader_get_bits_uint8_unchecked (GstBitReader *reader, guint nbits); + +/** + * gst_bit_reader_get_bits_uint16_unchecked: + * @reader: a #GstBitReader instance + * @nbits: number of bits to read + * + * Read @nbits bits into @val and update the current position without + * checking if there are enough bits available in the bit reader. + * + * Returns: unsigned 16 bit integer with the bits. + * + * Since: 0.10.31 + */ +guint16 gst_bit_reader_peek_bits_uint16_unchecked (const GstBitReader *reader, guint nbits); + +/** + * gst_bit_reader_peek_bits_uint16_unchecked: + * @reader: a #GstBitReader instance + * @nbits: number of bits to read + * + * Read @nbits bits into @val but keep the current position without + * checking if there are enough bits available in the bit reader + * + * Returns: unsigned 16 bit integer with the bits. + * + * Since: 0.10.31 + */ +guint16 gst_bit_reader_get_bits_uint16_unchecked (GstBitReader *reader, guint nbits); + +/** + * gst_bit_reader_get_bits_uint32_unchecked: + * @reader: a #GstBitReader instance + * @nbits: number of bits to read + * + * Read @nbits bits into @val and update the current position without + * checking if there are enough bits available in the bit reader. + * + * Returns: unsigned 32 bit integer with the bits. + * + * Since: 0.10.31 + */ +guint32 gst_bit_reader_peek_bits_uint32_unchecked (const GstBitReader *reader, guint nbits); + +/** + * gst_bit_reader_peek_bits_uint32_unchecked: + * @reader: a #GstBitReader instance + * @nbits: number of bits to read + * + * Read @nbits bits into @val but keep the current position without + * checking if there are enough bits available in the bit reader + * + * Returns: unsigned 32 bit integer with the bits. + * + * Since: 0.10.31 + */ +guint32 gst_bit_reader_get_bits_uint32_unchecked (GstBitReader *reader, guint nbits); + +/** + * gst_bit_reader_get_bits_uint64_unchecked: + * @reader: a #GstBitReader instance + * @nbits: number of bits to read + * + * Read @nbits bits into @val and update the current position without + * checking if there are enough bits available in the bit reader. + * + * Returns: unsigned 64 bit integer with the bits. + * + * Since: 0.10.31 + */ +guint64 gst_bit_reader_peek_bits_uint64_unchecked (const GstBitReader *reader, guint nbits); + +/** + * gst_bit_reader_peek_bits_uint16_unchecked: + * @reader: a #GstBitReader instance + * @nbits: number of bits to read + * + * Read @nbits bits into @val but keep the current position without + * checking if there are enough bits available in the bit reader + * + * Returns: unsigned 64 bit integer with the bits. + * + * Since: 0.10.31 + */ +guint64 gst_bit_reader_get_bits_uint64_unchecked (GstBitReader *reader, guint nbits); + diff --git a/libs/gst/base/gstbitreader.c b/libs/gst/base/gstbitreader.c index 64e9e3ff3e..1dd8979e42 100644 --- a/libs/gst/base/gstbitreader.c +++ b/libs/gst/base/gstbitreader.c @@ -22,6 +22,7 @@ #include "config.h" #endif +#define GST_BIT_READER_DISABLE_INLINES #include "gstbitreader.h" #include @@ -174,9 +175,7 @@ gst_bit_reader_set_pos (GstBitReader * reader, guint pos) guint gst_bit_reader_get_pos (const GstBitReader * reader) { - g_return_val_if_fail (reader != NULL, 0); - - return reader->byte * 8 + reader->bit; + return _gst_bit_reader_get_pos_inline (reader); } /** @@ -192,9 +191,7 @@ gst_bit_reader_get_pos (const GstBitReader * reader) 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); + return _gst_bit_reader_get_remaining_inline (reader); } /** @@ -210,9 +207,7 @@ gst_bit_reader_get_remaining (const GstBitReader * reader) guint gst_bit_reader_get_size (const GstBitReader * reader) { - g_return_val_if_fail (reader != NULL, 0); - - return reader->size * 8; + return _gst_bit_reader_get_size_inline (reader); } /** @@ -229,16 +224,7 @@ gst_bit_reader_get_size (const GstBitReader * reader) 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; + return _gst_bit_reader_skip_inline (reader, nbits); } /** @@ -254,17 +240,7 @@ gst_bit_reader_skip (GstBitReader * reader, guint nbits) 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; + return _gst_bit_reader_skip_to_byte_inline (reader); } /** @@ -375,55 +351,13 @@ gst_bit_reader_skip_to_byte (GstBitReader * reader) gboolean \ gst_bit_reader_peek_bits_uint##bits (const GstBitReader *reader, guint##bits *val, guint nbits) \ { \ - guint##bits ret = 0; \ - const guint8 *data; \ - guint byte, bit; \ - \ - g_return_val_if_fail (reader != NULL, FALSE); \ - g_return_val_if_fail (val != NULL, FALSE); \ - g_return_val_if_fail (nbits <= bits, FALSE); \ - \ - data = reader->data; \ - byte = reader->byte; \ - bit = reader->bit; \ - \ - if (byte * 8 + bit + nbits > reader->size * 8) \ - return FALSE; \ - \ - while (nbits > 0) { \ - guint toread = MIN (nbits, 8 - bit); \ - \ - ret <<= toread; \ - ret |= (data[byte] & (0xff >> bit)) >> (8 - toread - bit); \ - \ - bit += toread; \ - if (bit >= 8) { \ - byte++; \ - bit = 0; \ - } \ - nbits -= toread; \ - } \ - \ - *val = ret; \ - return TRUE; \ + return _gst_bit_reader_peek_bits_uint##bits##_inline (reader, val, nbits); \ } \ \ gboolean \ gst_bit_reader_get_bits_uint##bits (GstBitReader *reader, guint##bits *val, guint nbits) \ { \ - gboolean ret; \ - \ - ret = gst_bit_reader_peek_bits_uint##bits (reader, val, nbits); \ - \ - if (ret) { \ - reader->bit += nbits; \ - if (reader->bit >= 8) { \ - reader->byte += reader->bit / 8; \ - reader->bit = reader->bit % 8; \ - } \ - } \ - \ - return ret; \ + return _gst_bit_reader_get_bits_uint##bits##_inline (reader, val, nbits); \ } GST_BIT_READER_READ_BITS (8); diff --git a/libs/gst/base/gstbitreader.h b/libs/gst/base/gstbitreader.h index 6c4b1d7784..b5c3935e7e 100644 --- a/libs/gst/base/gstbitreader.h +++ b/libs/gst/base/gstbitreader.h @@ -100,6 +100,215 @@ gboolean gst_bit_reader_peek_bits_uint64 (const GstBitReader *reader, guint64 *v */ #define GST_BIT_READER_INIT_FROM_BUFFER(buffer) {GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer), 0, 0} +/* Unchecked variants */ + +static inline void +gst_bit_reader_skip_unchecked (GstBitReader * reader, guint nbits) +{ + reader->bit += nbits; + reader->byte += reader->bit / 8; + reader->bit = reader->bit % 8; +} + +static inline void +gst_bit_reader_skip_to_byte_unchecked (GstBitReader * reader) +{ + if (reader->bit) { + reader->bit = 0; + reader->byte++; + } +} + +#define __GST_BIT_READER_READ_BITS_UNCHECKED(bits) \ +static inline guint##bits \ +gst_bit_reader_peek_bits_uint##bits##_unchecked (const GstBitReader *reader, guint nbits) \ +{ \ + guint##bits ret = 0; \ + const guint8 *data; \ + guint byte, bit; \ + \ + data = reader->data; \ + byte = reader->byte; \ + bit = reader->bit; \ + \ + while (nbits > 0) { \ + guint toread = MIN (nbits, 8 - bit); \ + \ + ret <<= toread; \ + ret |= (data[byte] & (0xff >> bit)) >> (8 - toread - bit); \ + \ + bit += toread; \ + if (bit >= 8) { \ + byte++; \ + bit = 0; \ + } \ + nbits -= toread; \ + } \ + \ + return ret; \ +} \ +\ +static inline guint##bits \ +gst_bit_reader_get_bits_uint##bits##_unchecked (GstBitReader *reader, guint nbits) \ +{ \ + guint##bits ret; \ + \ + ret = gst_bit_reader_peek_bits_uint##bits##_unchecked (reader, nbits); \ + \ + gst_bit_reader_skip_unchecked (reader, nbits); \ + \ + return ret; \ +} + +__GST_BIT_READER_READ_BITS_UNCHECKED (8) +__GST_BIT_READER_READ_BITS_UNCHECKED (16) +__GST_BIT_READER_READ_BITS_UNCHECKED (32) +__GST_BIT_READER_READ_BITS_UNCHECKED (64) + +#undef __GST_BIT_READER_READ_BITS_UNCHECKED + +/* unchecked variants -- do not use */ + +static inline guint +_gst_bit_reader_get_size_unchecked (const GstBitReader * reader) +{ + return reader->size * 8; +} + +static inline guint +_gst_bit_reader_get_pos_unchecked (const GstBitReader * reader) +{ + return reader->byte * 8 + reader->bit; +} + +static inline guint +_gst_bit_reader_get_remaining_unchecked (const GstBitReader * reader) +{ + return reader->size * 8 - (reader->byte * 8 + reader->bit); +} + +/* inlined variants -- do not use directly */ +static inline guint +_gst_bit_reader_get_size_inline (const GstBitReader * reader) +{ + g_return_val_if_fail (reader != NULL, 0); + + return _gst_bit_reader_get_size_unchecked (reader); +} + +static inline guint +_gst_bit_reader_get_pos_inline (const GstBitReader * reader) +{ + g_return_val_if_fail (reader != NULL, 0); + + return _gst_bit_reader_get_pos_unchecked (reader); +} + +static inline guint +_gst_bit_reader_get_remaining_inline (const GstBitReader * reader) +{ + g_return_val_if_fail (reader != NULL, 0); + + return _gst_bit_reader_get_remaining_unchecked (reader); +} + +static inline gboolean +_gst_bit_reader_skip_inline (GstBitReader * reader, guint nbits) +{ + g_return_val_if_fail (reader != NULL, FALSE); + + if (_gst_bit_reader_get_remaining_unchecked (reader) < nbits) + return FALSE; + + gst_bit_reader_skip_unchecked (reader, nbits); + + return TRUE; +} + +static inline gboolean +_gst_bit_reader_skip_to_byte_inline (GstBitReader * reader) +{ + g_return_val_if_fail (reader != NULL, FALSE); + + if (reader->byte > reader->size) + return FALSE; + + gst_bit_reader_skip_to_byte_unchecked (reader); + + return TRUE; +} + +#define __GST_BIT_READER_READ_BITS_INLINE(bits) \ +static inline gboolean \ +_gst_bit_reader_get_bits_uint##bits##_inline (GstBitReader *reader, guint##bits *val, guint nbits) \ +{ \ + 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 (_gst_bit_reader_get_remaining_unchecked (reader) < nbits) \ + return FALSE; \ +\ + *val = gst_bit_reader_get_bits_uint##bits##_unchecked (reader, nbits); \ + return TRUE; \ +} \ +\ +static inline gboolean \ +_gst_bit_reader_peek_bits_uint##bits##_inline (const GstBitReader *reader, guint##bits *val, guint nbits) \ +{ \ + 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 (_gst_bit_reader_get_remaining_unchecked (reader) < nbits) \ + return FALSE; \ +\ + *val = gst_bit_reader_peek_bits_uint##bits##_unchecked (reader, nbits); \ + return TRUE; \ +} + +__GST_BIT_READER_READ_BITS_INLINE (8) +__GST_BIT_READER_READ_BITS_INLINE (16) +__GST_BIT_READER_READ_BITS_INLINE (32) +__GST_BIT_READER_READ_BITS_INLINE (64) + +#undef __GST_BIT_READER_READ_BITS_INLINE + +#ifndef GST_BIT_READER_DISABLE_INLINES + +#define gst_bit_reader_get_size(reader) \ + _gst_bit_reader_get_size_inline (reader) +#define gst_bit_reader_get_pos(reader) \ + _gst_bit_reader_get_pos_inline (reader) +#define gst_bit_reader_get_remaining(reader) \ + _gst_bit_reader_get_remaining_inline (reader) + +/* we use defines here so we can add the G_LIKELY() */ + +#define gst_bit_reader_skip(reader, nbits)\ + G_LIKELY (_gst_bit_reader_skip_inline(reader, nbits)) +#define gst_bit_reader_skip_to_byte(reader)\ + G_LIKELY (_gst_bit_reader_skip_to_byte_inline(reader)) + +#define gst_bit_reader_get_bits_uint8(reader, val, nbits) \ + G_LIKELY (_gst_bit_reader_get_bits_uint8_inline (reader, val, nbits)) +#define gst_bit_reader_get_bits_uint16(reader, val, nbits) \ + G_LIKELY (_gst_bit_reader_get_bits_uint16_inline (reader, val, nbits)) +#define gst_bit_reader_get_bits_uint32(reader, val, nbits) \ + G_LIKELY (_gst_bit_reader_get_bits_uint32_inline (reader, val, nbits)) +#define gst_bit_reader_get_bits_uint64(reader, val, nbits) \ + G_LIKELY (_gst_bit_reader_get_bits_uint64_inline (reader, val, nbits)) + +#define gst_bit_reader_peek_bits_uint8(reader, val, nbits) \ + G_LIKELY (_gst_bit_reader_peek_bits_uint8_inline (reader, val, nbits)) +#define gst_bit_reader_peek_bits_uint16(reader, val, nbits) \ + G_LIKELY (_gst_bit_reader_peek_bits_uint16_inline (reader, val, nbits)) +#define gst_bit_reader_peek_bits_uint32(reader, val, nbits) \ + G_LIKELY (_gst_bit_reader_peek_bits_uint32_inline (reader, val, nbits)) +#define gst_bit_reader_peek_bits_uint64(reader, val, nbits) \ + G_LIKELY (_gst_bit_reader_peek_bits_uint64_inline (reader, val, nbits)) +#endif + G_END_DECLS #endif /* __GST_BIT_READER_H__ */ diff --git a/tests/check/libs/bitreader.c b/tests/check/libs/bitreader.c index 3b9374282d..c3655c3895 100644 --- a/tests/check/libs/bitreader.c +++ b/tests/check/libs/bitreader.c @@ -112,10 +112,10 @@ GST_START_TEST (test_get_bits) 0xfe, 0xdc, 0xba, 0x09, 0x87, 0x65, 0x43, 0x21 }; GstBitReader reader = GST_BIT_READER_INIT (data, 16); - guint8 a; - guint16 b; - guint32 c; - guint64 d; + guint8 a = 0; + guint16 b = 0; + guint32 c = 0; + guint64 d = 0; /* 8 bit */ GET_CHECK (&reader, a, 8, 8, 0x12);