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