1/*
2Copyright (c) 2012, Broadcom Europe Ltd
3All rights reserved.
4
5Redistribution and use in source and binary forms, with or without
6modification, are permitted provided that the following conditions are met:
7 * Redistributions of source code must retain the above copyright
8 notice, this list of conditions and the following disclaimer.
9 * Redistributions in binary form must reproduce the above copyright
10 notice, this list of conditions and the following disclaimer in the
11 documentation and/or other materials provided with the distribution.
12 * Neither the name of the copyright holder nor the
13 names of its contributors may be used to endorse or promote products
14 derived from this software without specific prior written permission.
15
16THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
20DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26*/
27
28#include "containers/core/containers_bits.h"
29#include "containers/core/containers_common.h"
30
31#ifdef ENABLE_CONTAINERS_LOG_FORMAT
32#include "containers/core/containers_logging.h"
33#endif
34
35/******************************************************************************
36Defines and constants.
37******************************************************************************/
38
39#ifdef ENABLE_CONTAINERS_LOG_FORMAT
40/** String used for indentation. If more spaces are needed, just add them. */
41#define INDENT_SPACES_STRING "> "
42#define INDENT_SPACES_LENGTH (sizeof(INDENT_SPACES_STRING) - 1)
43#endif /* ENABLE_CONTAINERS_LOG_FORMAT */
44
45/******************************************************************************
46Type definitions
47******************************************************************************/
48
49/******************************************************************************
50Function prototypes
51******************************************************************************/
52
53/******************************************************************************
54Local Functions
55******************************************************************************/
56
57#ifdef ENABLE_CONTAINERS_LOG_FORMAT
58
59/**************************************************************************//**
60 * Returns a string that indicates whether the bit stream is valid or not.
61 *
62 * \pre bit_stream is not NULL.
63 *
64 * \param bit_stream The bit stream object.
65 * \return A string indicating the validity of the stream.
66 */
67static const char * vc_container_bits_valid_str( VC_CONTAINER_BITS_T *bit_stream )
68{
69 return vc_container_bits_valid(bit_stream) ? "" : " - stream invalid";
70}
71
72/**************************************************************************//**
73 * Returns a string of spaces the length of which is determined by the
74 * parameter.
75 * The length is limited to a certain size, above which a greater than symbol
76 * prefixes the maximum number of spaces.
77 *
78 * \param length The required length of the string.
79 * \return A string indicating the validity of the stream.
80 */
81static const char * vc_container_bits_indent_str(uint32_t length)
82{
83 uint32_t str_length = length;
84
85 if (str_length > INDENT_SPACES_LENGTH)
86 str_length = INDENT_SPACES_LENGTH;
87
88 return INDENT_SPACES_STRING + (INDENT_SPACES_LENGTH - str_length);
89}
90
91#endif /* ENABLE_CONTAINERS_LOG_FORMAT */
92
93/**************************************************************************//**
94 * Returns the number of consecutive zero bits in the stream.
95 * the zero bits are terminated either by a one bit, or the end of the stream.
96 * In the former case, the zero bits and the terminating one bit are removed
97 * from the stream.
98 * In the latter case, the stream becomes invalid. The stream also becomes
99 * invalid if there are not as many bits after the one bit as zero bits before
100 * it.
101 * If the stream is already or becomes invalid, zero is returned.
102 *
103 * \pre bit_stream is not NULL.
104 *
105 * \param bit_stream The bit stream object.
106 * \return The number of consecutive zero bits, or zero if the stream is
107 * invalid.
108 */
109static uint32_t vc_container_bits_get_leading_zero_bits( VC_CONTAINER_BITS_T *bit_stream )
110{
111 uint32_t leading_zero_bits;
112 uint32_t bits_left = vc_container_bits_available(bit_stream);
113 uint32_t bits;
114 uint8_t mask, current_byte;
115
116 if (!bits_left)
117 return vc_container_bits_invalidate(bit_stream);
118
119 /* Cache 'bits' field to avoid repeated pointer access */
120 bits = bit_stream->bits;
121 if (bits)
122 {
123 current_byte = *bit_stream->buffer;
124 mask = 1 << (bits - 1);
125 } else {
126 /* Initialize variables to placate the compiler */
127 current_byte = 0;
128 mask = 0;
129 }
130
131 /* Scan for the first one bit, counting the number of zeroes. This gives the
132 * number of further bits after the one that are part of the value. See
133 * section 9.1 of ITU-T REC H.264 201003 for more details. */
134
135 for (leading_zero_bits = 0; leading_zero_bits < bits_left; leading_zero_bits++)
136 {
137 if (!bits)
138 {
139 if (!bit_stream->bytes)
140 return vc_container_bits_invalidate(bit_stream);
141 bit_stream->bytes--;
142 current_byte = *(++bit_stream->buffer);
143 bits = 8;
144 mask = 0x80;
145 }
146
147 bits--;
148 bits_left--;
149 if (current_byte & mask)
150 break; /* Found the marker bit */
151
152 mask >>= 1;
153 }
154
155 /* Check enough bits are left in the stream for the value. */
156 if (leading_zero_bits > bits_left)
157 return vc_container_bits_invalidate(bit_stream);
158
159 /* Return cached value of bits to the stream */
160 bit_stream->bits = bits;
161
162 return leading_zero_bits;
163}
164
165/*****************************************************************************
166Functions exported as part of the bit stream API
167 *****************************************************************************/
168
169/*****************************************************************************/
170void vc_container_bits_init(VC_CONTAINER_BITS_T *bit_stream,
171 const uint8_t *buffer,
172 uint32_t available)
173{
174 vc_container_assert(buffer && (buffer != (const uint8_t *)1));
175
176 /* Start with buffer pointing at the previous byte with no bits available
177 * to make the mathematics easier */
178 bit_stream->buffer = buffer - 1;
179 bit_stream->bytes = available;
180 bit_stream->bits = 0;
181}
182
183/*****************************************************************************/
184uint32_t vc_container_bits_invalidate( VC_CONTAINER_BITS_T *bit_stream )
185{
186 bit_stream->buffer = NULL;
187 return 0;
188}
189
190/*****************************************************************************/
191bool vc_container_bits_valid(VC_CONTAINER_BITS_T *bit_stream)
192{
193 return (bit_stream->buffer != NULL);
194}
195
196/*****************************************************************************/
197void vc_container_bits_reset(VC_CONTAINER_BITS_T *bit_stream)
198{
199 bit_stream->bytes = 0;
200 bit_stream->bits = 0;
201}
202
203/*****************************************************************************/
204const uint8_t *vc_container_bits_current_pointer(const VC_CONTAINER_BITS_T *bit_stream)
205{
206 const uint8_t *buffer = bit_stream->buffer;
207
208 /* Only valid on byte boundaries, where buffer pointer has not been moved yet */
209 vc_container_assert(!bit_stream->bits);
210
211 return buffer ? (buffer + 1) : NULL;
212}
213
214/*****************************************************************************/
215void vc_container_bits_copy_stream(VC_CONTAINER_BITS_T *dst,
216 const VC_CONTAINER_BITS_T *src)
217{
218 memcpy(dst, src, sizeof(VC_CONTAINER_BITS_T));
219}
220
221/*****************************************************************************/
222uint32_t vc_container_bits_available(const VC_CONTAINER_BITS_T *bit_stream)
223{
224 if (!bit_stream->buffer)
225 return 0;
226 return (bit_stream->bytes << 3) + bit_stream->bits;
227}
228
229/*****************************************************************************/
230uint32_t vc_container_bits_bytes_available(const VC_CONTAINER_BITS_T *bit_stream)
231{
232 if (!bit_stream->buffer)
233 return 0;
234
235 vc_container_assert(!bit_stream->bits);
236
237 return vc_container_bits_available(bit_stream) >> 3;
238}
239
240/*****************************************************************************/
241void vc_container_bits_skip(VC_CONTAINER_BITS_T *bit_stream,
242 uint32_t bits_to_skip)
243{
244 uint32_t have_bits;
245 uint32_t new_bytes;
246
247 have_bits = vc_container_bits_available(bit_stream);
248 if (have_bits < bits_to_skip)
249 {
250 vc_container_bits_invalidate(bit_stream);
251 return;
252 }
253
254 have_bits -= bits_to_skip;
255 new_bytes = have_bits >> 3;
256 bit_stream->bits = have_bits & 7;
257 bit_stream->buffer += (bit_stream->bytes - new_bytes);
258 bit_stream->bytes = new_bytes;
259}
260
261/*****************************************************************************/
262void vc_container_bits_skip_bytes(VC_CONTAINER_BITS_T *bit_stream,
263 uint32_t bytes_to_skip)
264{
265 /* Only valid on byte boundaries */
266 vc_container_assert(!bit_stream->bits);
267
268 vc_container_bits_skip(bit_stream, bytes_to_skip << 3);
269}
270
271/*****************************************************************************/
272void vc_container_bits_reduce_bytes(VC_CONTAINER_BITS_T *bit_stream,
273 uint32_t bytes_to_reduce)
274{
275 if (bit_stream->bytes >= bytes_to_reduce)
276 bit_stream->bytes -= bytes_to_reduce;
277 else
278 vc_container_bits_invalidate(bit_stream);
279}
280
281/*****************************************************************************/
282void vc_container_bits_copy_bytes(VC_CONTAINER_BITS_T *bit_stream,
283 uint32_t bytes_to_copy,
284 uint8_t *dst)
285{
286 vc_container_assert(!bit_stream->bits);
287
288 if (bit_stream->bytes < bytes_to_copy)
289 {
290 /* Not enough data */
291 vc_container_bits_invalidate(bit_stream);
292 return;
293 }
294
295 /* When the number of bits is zero, the next byte to take is at buffer + 1 */
296 memcpy(dst, bit_stream->buffer + 1, bytes_to_copy);
297 bit_stream->buffer += bytes_to_copy;
298 bit_stream->bytes -= bytes_to_copy;
299}
300
301/*****************************************************************************/
302uint32_t vc_container_bits_read_u32(VC_CONTAINER_BITS_T *bit_stream,
303 uint32_t value_bits)
304{
305 uint32_t value = 0;
306 uint32_t needed = value_bits;
307 uint32_t bits;
308
309 vc_container_assert(value_bits <= 32);
310
311 if (needed > vc_container_bits_available(bit_stream))
312 return vc_container_bits_invalidate(bit_stream);
313
314 bits = bit_stream->bits;
315 while (needed)
316 {
317 uint32_t take;
318
319 if (!bits)
320 {
321 bit_stream->bytes--;
322 bit_stream->buffer++;
323 bits = 8;
324 }
325
326 take = bits;
327 if (needed < take) take = needed;
328
329 bits -= take;
330 needed -= take;
331
332 value <<= take;
333 if (take == 8)
334 value |= *bit_stream->buffer; /* optimize whole byte case */
335 else
336 value |= (*bit_stream->buffer >> bits) & ((1 << take) - 1);
337 }
338
339 bit_stream->bits = bits;
340 return value;
341}
342
343/*****************************************************************************/
344void vc_container_bits_skip_exp_golomb(VC_CONTAINER_BITS_T *bit_stream)
345{
346 vc_container_bits_skip(bit_stream, vc_container_bits_get_leading_zero_bits(bit_stream));
347}
348
349/*****************************************************************************/
350uint32_t vc_container_bits_read_u32_exp_golomb(VC_CONTAINER_BITS_T *bit_stream)
351{
352 uint32_t leading_zero_bits;
353 uint32_t codeNum;
354
355 leading_zero_bits = vc_container_bits_get_leading_zero_bits(bit_stream);
356
357 /* Anything bigger than 32 bits is definitely overflow */
358 if (leading_zero_bits > 32)
359 return vc_container_bits_invalidate(bit_stream);
360
361 codeNum = vc_container_bits_read_u32(bit_stream, leading_zero_bits);
362
363 if (leading_zero_bits == 32)
364 {
365 /* If codeNum is non-zero, it would need 33 bits, so is also overflow */
366 if (codeNum)
367 return vc_container_bits_invalidate(bit_stream);
368
369 return 0xFFFFFFFF;
370 }
371
372 return codeNum + (1 << leading_zero_bits) - 1;
373}
374
375/*****************************************************************************/
376int32_t vc_container_bits_read_s32_exp_golomb(VC_CONTAINER_BITS_T *bit_stream)
377{
378 uint32_t uval;
379
380 uval = vc_container_bits_read_u32_exp_golomb(bit_stream);
381
382 /* The signed Exp-Golomb code 0xFFFFFFFF cannot be represented as a signed 32-bit
383 * integer, because it should be one larger than the largest positive value. */
384 if (uval == 0xFFFFFFFF)
385 return vc_container_bits_invalidate(bit_stream);
386
387 /* Definition of conversion is
388 * s = ((-1)^(u + 1)) * Ceil(u / 2)
389 * where '^' is power, but this should be equivalent */
390 return ((int32_t)((uval & 1) << 1) - 1) * (int32_t)((uval >> 1) + (uval & 1));
391}
392
393#ifdef ENABLE_CONTAINERS_LOG_FORMAT
394
395/*****************************************************************************/
396void vc_container_bits_log(VC_CONTAINER_T *p_ctx,
397 uint32_t indent,
398 const char *txt,
399 VC_CONTAINER_BITS_T *bit_stream,
400 VC_CONTAINER_BITS_LOG_OP_T op,
401 uint32_t length)
402{
403 const char *valid_str = vc_container_bits_valid_str(bit_stream);
404 const char *indent_str = vc_container_bits_indent_str(indent);
405
406 switch (op)
407 {
408 case VC_CONTAINER_BITS_LOG_SKIP:
409 vc_container_log(p_ctx, VC_CONTAINER_LOG_FORMAT, "%s%s: %u bits skipped%s", indent_str, txt, length, valid_str);
410 break;
411 case VC_CONTAINER_BITS_LOG_SKIP_BYTES:
412 vc_container_log(p_ctx, VC_CONTAINER_LOG_FORMAT, "%s%s: %u bytes skipped%s", indent_str, txt, length, valid_str);
413 break;
414 case VC_CONTAINER_BITS_LOG_COPY_BYTES:
415 vc_container_log(p_ctx, VC_CONTAINER_LOG_FORMAT, "%s%s: %u bytes copied%s", indent_str, txt, length, valid_str);
416 break;
417 case VC_CONTAINER_BITS_LOG_REDUCE_BYTES:
418 vc_container_log(p_ctx, VC_CONTAINER_LOG_FORMAT, "%s%s: %u bytes reduced%s", indent_str, txt, length, valid_str);
419 break;
420 case VC_CONTAINER_BITS_LOG_EG_SKIP:
421 vc_container_log(p_ctx, VC_CONTAINER_LOG_FORMAT, "%s%s: Exp-Golomb value skipped%s", indent_str, txt, valid_str);
422 break;
423 default:
424 /* Unexpected operation. Check bit stream logging macros */
425 vc_container_assert(0);
426 }
427}
428
429/*****************************************************************************/
430uint32_t vc_container_bits_log_u32(VC_CONTAINER_T *p_ctx,
431 uint32_t indent,
432 const char *txt,
433 VC_CONTAINER_BITS_T *bit_stream,
434 VC_CONTAINER_BITS_LOG_OP_T op,
435 uint32_t length,
436 uint32_t value)
437{
438 const char *valid_str = vc_container_bits_valid_str(bit_stream);
439 const char *indent_str = vc_container_bits_indent_str(indent);
440
441 switch (op)
442 {
443 case VC_CONTAINER_BITS_LOG_U8:
444 vc_container_log(p_ctx, VC_CONTAINER_LOG_FORMAT, "%s%s: 0x%02x (%u) in %u bits%s", indent_str, txt, value, value, length, valid_str);
445 break;
446 case VC_CONTAINER_BITS_LOG_U16:
447 vc_container_log(p_ctx, VC_CONTAINER_LOG_FORMAT, "%s%s: 0x%04x (%u) in %u bits%s", indent_str, txt, value, value, length, valid_str);
448 break;
449 case VC_CONTAINER_BITS_LOG_U32:
450 vc_container_log(p_ctx, VC_CONTAINER_LOG_FORMAT, "%s%s: 0x%08x (%u) in %u bits%s", indent_str, txt, value, value, length, valid_str);
451 break;
452 case VC_CONTAINER_BITS_LOG_EG_U32:
453 vc_container_log(p_ctx, VC_CONTAINER_LOG_FORMAT, "%s%s: 0x%08x (%u) unsigned Exp-Golomb%s", indent_str, txt, value, value, valid_str);
454 break;
455 default:
456 /* Unexpected operation. Check bit stream logging macros */
457 vc_container_assert(0);
458 }
459
460 return value;
461}
462
463/*****************************************************************************/
464int32_t vc_container_bits_log_s32(VC_CONTAINER_T *p_ctx,
465 uint32_t indent,
466 const char *txt,
467 VC_CONTAINER_BITS_T *bit_stream,
468 VC_CONTAINER_BITS_LOG_OP_T op,
469 uint32_t length,
470 int32_t value)
471{
472 const char *valid_str = vc_container_bits_valid_str(bit_stream);
473 const char *indent_str = vc_container_bits_indent_str(indent);
474
475 VC_CONTAINER_PARAM_UNUSED(length);
476
477 switch (op)
478 {
479 case VC_CONTAINER_BITS_LOG_EG_S32:
480 vc_container_log(p_ctx, VC_CONTAINER_LOG_FORMAT, "%s%s: 0x%08x (%d) signed Exp-Golomb%s", indent_str, txt, value, value, valid_str);
481 break;
482 default:
483 /* Unexpected operation. Check bit stream logging macros */
484 vc_container_assert(0);
485 }
486
487 return value;
488}
489
490#endif /* ENABLE_CONTAINERS_LOG_FORMAT */
491