1 /*
2 Copyright (c) 2012, Broadcom Europe Ltd
3 All rights reserved.
4 
5 Redistribution and use in source and binary forms, with or without
6 modification, 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 
16 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
20 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 ON 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
25 SOFTWARE, 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 /******************************************************************************
36 Defines 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 /******************************************************************************
46 Type definitions
47 ******************************************************************************/
48 
49 /******************************************************************************
50 Function prototypes
51 ******************************************************************************/
52 
53 /******************************************************************************
54 Local 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  */
vc_container_bits_valid_str(VC_CONTAINER_BITS_T * bit_stream)67 static 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  */
vc_container_bits_indent_str(uint32_t length)81 static 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  */
vc_container_bits_get_leading_zero_bits(VC_CONTAINER_BITS_T * bit_stream)109 static 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 /*****************************************************************************
166 Functions exported as part of the bit stream API
167  *****************************************************************************/
168 
169 /*****************************************************************************/
vc_container_bits_init(VC_CONTAINER_BITS_T * bit_stream,const uint8_t * buffer,uint32_t available)170 void 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 /*****************************************************************************/
vc_container_bits_invalidate(VC_CONTAINER_BITS_T * bit_stream)184 uint32_t vc_container_bits_invalidate( VC_CONTAINER_BITS_T *bit_stream )
185 {
186    bit_stream->buffer = NULL;
187    return 0;
188 }
189 
190 /*****************************************************************************/
vc_container_bits_valid(VC_CONTAINER_BITS_T * bit_stream)191 bool vc_container_bits_valid(VC_CONTAINER_BITS_T *bit_stream)
192 {
193    return (bit_stream->buffer != NULL);
194 }
195 
196 /*****************************************************************************/
vc_container_bits_reset(VC_CONTAINER_BITS_T * bit_stream)197 void vc_container_bits_reset(VC_CONTAINER_BITS_T *bit_stream)
198 {
199    bit_stream->bytes = 0;
200    bit_stream->bits = 0;
201 }
202 
203 /*****************************************************************************/
vc_container_bits_current_pointer(const VC_CONTAINER_BITS_T * bit_stream)204 const 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 /*****************************************************************************/
vc_container_bits_copy_stream(VC_CONTAINER_BITS_T * dst,const VC_CONTAINER_BITS_T * src)215 void 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 /*****************************************************************************/
vc_container_bits_available(const VC_CONTAINER_BITS_T * bit_stream)222 uint32_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 /*****************************************************************************/
vc_container_bits_bytes_available(const VC_CONTAINER_BITS_T * bit_stream)230 uint32_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 /*****************************************************************************/
vc_container_bits_skip(VC_CONTAINER_BITS_T * bit_stream,uint32_t bits_to_skip)241 void 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 /*****************************************************************************/
vc_container_bits_skip_bytes(VC_CONTAINER_BITS_T * bit_stream,uint32_t bytes_to_skip)262 void 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 /*****************************************************************************/
vc_container_bits_reduce_bytes(VC_CONTAINER_BITS_T * bit_stream,uint32_t bytes_to_reduce)272 void 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 /*****************************************************************************/
vc_container_bits_copy_bytes(VC_CONTAINER_BITS_T * bit_stream,uint32_t bytes_to_copy,uint8_t * dst)282 void 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 /*****************************************************************************/
vc_container_bits_read_u32(VC_CONTAINER_BITS_T * bit_stream,uint32_t value_bits)302 uint32_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 /*****************************************************************************/
vc_container_bits_skip_exp_golomb(VC_CONTAINER_BITS_T * bit_stream)344 void 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 /*****************************************************************************/
vc_container_bits_read_u32_exp_golomb(VC_CONTAINER_BITS_T * bit_stream)350 uint32_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 /*****************************************************************************/
vc_container_bits_read_s32_exp_golomb(VC_CONTAINER_BITS_T * bit_stream)376 int32_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 /*****************************************************************************/
vc_container_bits_log(VC_CONTAINER_T * p_ctx,uint32_t indent,const char * txt,VC_CONTAINER_BITS_T * bit_stream,VC_CONTAINER_BITS_LOG_OP_T op,uint32_t length)396 void 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 /*****************************************************************************/
vc_container_bits_log_u32(VC_CONTAINER_T * p_ctx,uint32_t indent,const char * txt,VC_CONTAINER_BITS_T * bit_stream,VC_CONTAINER_BITS_LOG_OP_T op,uint32_t length,uint32_t value)430 uint32_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 /*****************************************************************************/
vc_container_bits_log_s32(VC_CONTAINER_T * p_ctx,uint32_t indent,const char * txt,VC_CONTAINER_BITS_T * bit_stream,VC_CONTAINER_BITS_LOG_OP_T op,uint32_t length,int32_t value)464 int32_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