• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  gstbitwriter.h - bitstream writer
3  *
4  *  Copyright (C) 2013 Intel Corporation
5  *  Copyright (C) 2018 Igalia, S. L.
6  *
7  *  This library is free software; you can redistribute it and/or
8  *  modify it under the terms of the GNU Lesser General Public License
9  *  as published by the Free Software Foundation; either version 2.1
10  *  of the License, or (at your option) any later version.
11  *
12  *  This library is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  *  Lesser General Public License for more details.
16  *
17  *  You should have received a copy of the GNU Lesser General Public
18  *  License along with this library; if not, write to the Free
19  *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20  *  Boston, MA 02110-1301 USA
21  */
22 
23 #ifndef GST_BIT_WRITER_H
24 #define GST_BIT_WRITER_H
25 
26 #include <gst/gst.h>
27 #include <gst/base/base-prelude.h>
28 
29 #include <string.h>
30 
31 G_BEGIN_DECLS
32 
33 #define GST_BIT_WRITER_DATA(writer)     ((writer)->data)
34 #define GST_BIT_WRITER_BIT_SIZE(writer) ((writer)->bit_size)
35 #define GST_BIT_WRITER(writer)          ((GstBitWriter *) (writer))
36 
37 typedef struct _GstBitWriter GstBitWriter;
38 
39 /**
40  * GstBitWriter:
41  * @data: Allocated @data for bit writer to write
42  * @bit_size: Size of written @data in bits
43  *
44  * A bit writer instance.
45  *
46  * Since: 1.16
47  */
48 struct _GstBitWriter
49 {
50   guint8 *data;
51   guint bit_size;
52 
53   /*< private >*/
54   guint bit_capacity; /* Capacity of the allocated data */
55   gboolean auto_grow; /* Whether space can auto grow */
56   gboolean owned;
57   gpointer _gst_reserved[GST_PADDING];
58 };
59 
60 GST_BASE_API
61 GstBitWriter *  gst_bit_writer_new              (void) G_GNUC_MALLOC;
62 
63 GST_BASE_API
64 GstBitWriter *  gst_bit_writer_new_with_size    (guint32 size, gboolean fixed) G_GNUC_MALLOC;
65 
66 GST_BASE_API
67 GstBitWriter *  gst_bit_writer_new_with_data    (guint8 *data, guint size,
68 						 gboolean initialized) G_GNUC_MALLOC;
69 
70 GST_BASE_API
71 void            gst_bit_writer_free             (GstBitWriter *bitwriter);
72 
73 GST_BASE_API
74 guint8 *        gst_bit_writer_free_and_get_data (GstBitWriter *bitwriter);
75 
76 GST_BASE_API
77 GstBuffer *     gst_bit_writer_free_and_get_buffer (GstBitWriter *bitwriter);
78 
79 GST_BASE_API
80 void            gst_bit_writer_init             (GstBitWriter *bitwriter);
81 
82 GST_BASE_API
83 void            gst_bit_writer_init_with_size   (GstBitWriter *bitwriter,
84 						 guint32 size, gboolean fixed);
85 
86 GST_BASE_API
87 void            gst_bit_writer_init_with_data   (GstBitWriter *bitwriter,  guint8 *data,
88 						 guint size, gboolean initialized);
89 
90 GST_BASE_API
91 void            gst_bit_writer_reset            (GstBitWriter *bitwriter);
92 
93 GST_BASE_API
94 guint8 *        gst_bit_writer_reset_and_get_data (GstBitWriter *bitwriter);
95 
96 GST_BASE_API
97 GstBuffer *     gst_bit_writer_reset_and_get_buffer (GstBitWriter *bitwriter);
98 
99 GST_BASE_API
100 guint           gst_bit_writer_get_size         (const GstBitWriter *bitwriter);
101 
102 GST_BASE_API
103 guint8 *        gst_bit_writer_get_data         (const GstBitWriter *bitwriter);
104 
105 GST_BASE_API
106 gboolean        gst_bit_writer_set_pos          (GstBitWriter *bitwriter, guint pos);
107 
108 GST_BASE_API
109 guint           gst_bit_writer_get_remaining    (const GstBitWriter *bitwriter);
110 
111 GST_BASE_API
112 gboolean        gst_bit_writer_put_bits_uint8   (GstBitWriter *bitwriter, guint8 value,
113 						 guint nbits);
114 
115 GST_BASE_API
116 gboolean        gst_bit_writer_put_bits_uint16  (GstBitWriter *bitwriter, guint16 value,
117 						 guint nbits);
118 
119 GST_BASE_API
120 gboolean        gst_bit_writer_put_bits_uint32  (GstBitWriter *bitwriter, guint32 value,
121 						 guint nbits);
122 
123 GST_BASE_API
124 gboolean        gst_bit_writer_put_bits_uint64  (GstBitWriter *bitwriter, guint64 value,
125 						 guint nbits);
126 
127 GST_BASE_API
128 gboolean        gst_bit_writer_put_bytes        (GstBitWriter *bitwriter, const guint8 *data,
129 						 guint nbytes);
130 
131 GST_BASE_API
132 gboolean        gst_bit_writer_align_bytes      (GstBitWriter *bitwriter, guint8 trailing_bit);
133 
134 static const guint8 _gst_bit_writer_bit_filling_mask[9] = {
135     0x00, 0x01, 0x03, 0x07,
136     0x0F, 0x1F, 0x3F, 0x7F,
137     0xFF
138 };
139 
140 /* Aligned to 256 bytes */
141 #define __GST_BITS_WRITER_ALIGNMENT_MASK 2047
142 #define __GST_BITS_WRITER_ALIGNED(bitsize)                   \
143     (((bitsize) + __GST_BITS_WRITER_ALIGNMENT_MASK)&(~__GST_BITS_WRITER_ALIGNMENT_MASK))
144 
145 static inline gboolean
_gst_bit_writer_check_remaining(GstBitWriter * bitwriter,guint32 bits)146 _gst_bit_writer_check_remaining (GstBitWriter * bitwriter, guint32 bits)
147 {
148   guint32 new_bit_size = bits + bitwriter->bit_size;
149   guint32 clear_pos;
150 
151   g_assert (bitwriter->bit_size <= bitwriter->bit_capacity);
152   if (new_bit_size <= bitwriter->bit_capacity)
153     return TRUE;
154 
155   if (!bitwriter->auto_grow)
156     return FALSE;
157 
158   /* auto grow space */
159   new_bit_size = __GST_BITS_WRITER_ALIGNED (new_bit_size);
160   g_assert (new_bit_size
161       && ((new_bit_size & __GST_BITS_WRITER_ALIGNMENT_MASK) == 0));
162   clear_pos = ((bitwriter->bit_size + 7) >> 3);
163   bitwriter->data = (guint8 *) g_realloc (bitwriter->data, (new_bit_size >> 3));
164   memset (bitwriter->data + clear_pos, 0, (new_bit_size >> 3) - clear_pos);
165   bitwriter->bit_capacity = new_bit_size;
166   return TRUE;
167 }
168 
169 #undef __GST_BITS_WRITER_ALIGNMENT_MASK
170 #undef __GST_BITS_WRITER_ALIGNED
171 
172 #define __GST_BIT_WRITER_WRITE_BITS_UNCHECKED(bits) \
173 static inline void \
174 gst_bit_writer_put_bits_uint##bits##_unchecked( \
175     GstBitWriter *bitwriter, \
176     guint##bits value, \
177     guint nbits \
178 ) \
179 { \
180     guint byte_pos, bit_offset; \
181     guint8  *cur_byte; \
182     guint fill_bits; \
183     \
184     byte_pos = (bitwriter->bit_size >> 3); \
185     bit_offset = (bitwriter->bit_size & 0x07); \
186     cur_byte = bitwriter->data + byte_pos; \
187     g_assert (nbits <= bits); \
188     g_assert( bit_offset < 8 && \
189             bitwriter->bit_size <= bitwriter->bit_capacity); \
190     \
191     while (nbits) { \
192         fill_bits = ((8 - bit_offset) < nbits ? (8 - bit_offset) : nbits); \
193         nbits -= fill_bits; \
194         bitwriter->bit_size += fill_bits; \
195         \
196         *cur_byte |= (((value >> nbits) & _gst_bit_writer_bit_filling_mask[fill_bits]) \
197                       << (8 - bit_offset - fill_bits)); \
198         ++cur_byte; \
199         bit_offset = 0; \
200     } \
201     g_assert(cur_byte <= \
202            (bitwriter->data + (bitwriter->bit_capacity >> 3))); \
203 }
204 
205 __GST_BIT_WRITER_WRITE_BITS_UNCHECKED (8)
206 __GST_BIT_WRITER_WRITE_BITS_UNCHECKED (16)
207 __GST_BIT_WRITER_WRITE_BITS_UNCHECKED (32)
208 __GST_BIT_WRITER_WRITE_BITS_UNCHECKED (64)
209 #undef __GST_BIT_WRITER_WRITE_BITS_UNCHECKED
210 
211 static inline guint
gst_bit_writer_get_size_unchecked(const GstBitWriter * bitwriter)212 gst_bit_writer_get_size_unchecked (const GstBitWriter * bitwriter)
213 {
214   return GST_BIT_WRITER_BIT_SIZE (bitwriter);
215 }
216 
217 static inline guint8 *
gst_bit_writer_get_data_unchecked(const GstBitWriter * bitwriter)218 gst_bit_writer_get_data_unchecked (const GstBitWriter * bitwriter)
219 {
220   return GST_BIT_WRITER_DATA (bitwriter);
221 }
222 
223 static inline gboolean
gst_bit_writer_set_pos_unchecked(GstBitWriter * bitwriter,guint pos)224 gst_bit_writer_set_pos_unchecked (GstBitWriter * bitwriter, guint pos)
225 {
226   GST_BIT_WRITER_BIT_SIZE (bitwriter) = pos;
227   return TRUE;
228 }
229 
230 static inline guint
gst_bit_writer_get_remaining_unchecked(const GstBitWriter * bitwriter)231 gst_bit_writer_get_remaining_unchecked (const GstBitWriter * bitwriter)
232 {
233   return bitwriter->bit_capacity - bitwriter->bit_size;
234 }
235 
236 static inline void
gst_bit_writer_put_bytes_unchecked(GstBitWriter * bitwriter,const guint8 * data,guint nbytes)237 gst_bit_writer_put_bytes_unchecked (GstBitWriter * bitwriter,
238     const guint8 * data, guint nbytes)
239 {
240   if ((bitwriter->bit_size & 0x07) == 0) {
241     memcpy (&bitwriter->data[bitwriter->bit_size >> 3], data, nbytes);
242     bitwriter->bit_size += (nbytes << 3);
243   } else {
244     g_assert (0);
245     while (nbytes) {
246       gst_bit_writer_put_bits_uint8_unchecked (bitwriter, *data, 8);
247       --nbytes;
248       ++data;
249     }
250   }
251 }
252 
253 static inline void
gst_bit_writer_align_bytes_unchecked(GstBitWriter * bitwriter,guint8 trailing_bit)254 gst_bit_writer_align_bytes_unchecked (GstBitWriter * bitwriter,
255     guint8 trailing_bit)
256 {
257   guint32 bit_offset, bit_left;
258   guint8 value = 0;
259 
260   bit_offset = (bitwriter->bit_size & 0x07);
261   if (!bit_offset)
262     return;
263 
264   bit_left = 8 - bit_offset;
265   if (trailing_bit)
266     value = _gst_bit_writer_bit_filling_mask[bit_left];
267   gst_bit_writer_put_bits_uint8_unchecked (bitwriter, value, bit_left);
268 }
269 
270 #define __GST_BIT_WRITER_WRITE_BITS_INLINE(bits) \
271 static inline gboolean \
272 _gst_bit_writer_put_bits_uint##bits##_inline( \
273     GstBitWriter *bitwriter, \
274     guint##bits value, \
275     guint nbits \
276 ) \
277 { \
278     g_return_val_if_fail(bitwriter != NULL, FALSE); \
279     g_return_val_if_fail(nbits != 0, FALSE); \
280     g_return_val_if_fail(nbits <= bits, FALSE); \
281     \
282     if (!_gst_bit_writer_check_remaining(bitwriter, nbits)) \
283         return FALSE; \
284     gst_bit_writer_put_bits_uint##bits##_unchecked(bitwriter, value, nbits); \
285     return TRUE; \
286 }
287 
288 __GST_BIT_WRITER_WRITE_BITS_INLINE (8)
289 __GST_BIT_WRITER_WRITE_BITS_INLINE (16)
290 __GST_BIT_WRITER_WRITE_BITS_INLINE (32)
291 __GST_BIT_WRITER_WRITE_BITS_INLINE (64)
292 #undef __GST_BIT_WRITER_WRITE_BITS_INLINE
293 
294 static inline guint
_gst_bit_writer_get_size_inline(const GstBitWriter * bitwriter)295 _gst_bit_writer_get_size_inline (const GstBitWriter * bitwriter)
296 {
297   g_return_val_if_fail (bitwriter != NULL, 0);
298 
299   return gst_bit_writer_get_size_unchecked (bitwriter);
300 }
301 
302 static inline guint8 *
_gst_bit_writer_get_data_inline(const GstBitWriter * bitwriter)303 _gst_bit_writer_get_data_inline (const GstBitWriter * bitwriter)
304 {
305   g_return_val_if_fail (bitwriter != NULL, NULL);
306 
307   return gst_bit_writer_get_data_unchecked (bitwriter);
308 }
309 
310 static inline gboolean
_gst_bit_writer_set_pos_inline(GstBitWriter * bitwriter,guint pos)311 _gst_bit_writer_set_pos_inline (GstBitWriter * bitwriter, guint pos)
312 {
313   g_return_val_if_fail (bitwriter != NULL, FALSE);
314   g_return_val_if_fail (pos <= bitwriter->bit_capacity, FALSE);
315 
316   return gst_bit_writer_set_pos_unchecked (bitwriter, pos);
317 }
318 
319 static inline guint
_gst_bit_writer_get_remaining_inline(const GstBitWriter * bitwriter)320 _gst_bit_writer_get_remaining_inline (const GstBitWriter * bitwriter)
321 {
322   g_return_val_if_fail (bitwriter != NULL, 0);
323   g_return_val_if_fail (bitwriter->bit_size < bitwriter->bit_capacity, 0);
324 
325   return gst_bit_writer_get_remaining_unchecked (bitwriter);
326 }
327 
328 static inline gboolean
_gst_bit_writer_put_bytes_inline(GstBitWriter * bitwriter,const guint8 * data,guint nbytes)329 _gst_bit_writer_put_bytes_inline (GstBitWriter * bitwriter,
330     const guint8 * data, guint nbytes)
331 {
332   g_return_val_if_fail (bitwriter != NULL, FALSE);
333   g_return_val_if_fail (data != NULL, FALSE);
334   g_return_val_if_fail (nbytes, FALSE);
335 
336   if (!_gst_bit_writer_check_remaining (bitwriter, nbytes * 8))
337     return FALSE;
338 
339   gst_bit_writer_put_bytes_unchecked (bitwriter, data, nbytes);
340   return TRUE;
341 }
342 
343 static inline gboolean
_gst_bit_writer_align_bytes_inline(GstBitWriter * bitwriter,guint8 trailing_bit)344 _gst_bit_writer_align_bytes_inline (GstBitWriter * bitwriter,
345     guint8 trailing_bit)
346 {
347   g_return_val_if_fail (bitwriter != NULL, FALSE);
348   g_return_val_if_fail ((trailing_bit == 0 || trailing_bit == 1), FALSE);
349   g_return_val_if_fail (((bitwriter->bit_size + 7) & (~7)) <=
350       bitwriter->bit_capacity, FALSE);
351 
352   gst_bit_writer_align_bytes_unchecked (bitwriter, trailing_bit);
353   return TRUE;
354 }
355 
356 #ifndef GST_BIT_WRITER_DISABLE_INLINES
357 #define gst_bit_writer_get_size(bitwriter) \
358     _gst_bit_writer_get_size_inline(bitwriter)
359 #define gst_bit_writer_get_data(bitwriter) \
360     _gst_bit_writer_get_data_inline(bitwriter)
361 #define gst_bit_writer_set_pos(bitwriter, pos) \
362     G_LIKELY (_gst_bit_writer_set_pos_inline (bitwriter, pos))
363 #define gst_bit_writer_get_remaining(bitwriter) \
364     _gst_bit_writer_get_remaining_inline(bitwriter)
365 
366 #define gst_bit_writer_put_bits_uint8(bitwriter, value, nbits) \
367     G_LIKELY (_gst_bit_writer_put_bits_uint8_inline (bitwriter, value, nbits))
368 #define gst_bit_writer_put_bits_uint16(bitwriter, value, nbits) \
369     G_LIKELY (_gst_bit_writer_put_bits_uint16_inline (bitwriter, value, nbits))
370 #define gst_bit_writer_put_bits_uint32(bitwriter, value, nbits) \
371     G_LIKELY (_gst_bit_writer_put_bits_uint32_inline (bitwriter, value, nbits))
372 #define gst_bit_writer_put_bits_uint64(bitwriter, value, nbits) \
373     G_LIKELY (_gst_bit_writer_put_bits_uint64_inline (bitwriter, value, nbits))
374 
375 #define gst_bit_writer_put_bytes(bitwriter, data, nbytes) \
376     G_LIKELY (_gst_bit_writer_put_bytes_inline (bitwriter, data, nbytes))
377 
378 #define gst_bit_writer_align_bytes(bitwriter, trailing_bit) \
379     G_LIKELY (_gst_bit_writer_align_bytes_inline(bitwriter, trailing_bit))
380 #endif
381 
382 G_END_DECLS
383 
384 #endif /* GST_BIT_WRITER_H */
385