1 /*****************************************************************************
2  * bits.c
3  *****************************************************************************
4  * Copyright (C) 2010-2017 L-SMASH project
5  *
6  * Authors: Takashi Hirata <silverfilain@gmail.com>
7  *
8  * Permission to use, copy, modify, and/or distribute this software for any
9  * purpose with or without fee is hereby granted, provided that the above
10  * copyright notice and this permission notice appear in all copies.
11  *
12  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19  *****************************************************************************/
20 
21 /* This file is available under an ISC license. */
22 
23 #include "internal.h" /* must be placed first */
24 
lsmash_bits_init(lsmash_bits_t * bits,lsmash_bs_t * bs)25 void lsmash_bits_init( lsmash_bits_t *bits, lsmash_bs_t *bs )
26 {
27     debug_if( !bits || !bs )
28         return;
29     bits->bs    = bs;
30     bits->store = 0;
31     bits->cache = 0;
32 }
33 
lsmash_bits_create(lsmash_bs_t * bs)34 lsmash_bits_t *lsmash_bits_create( lsmash_bs_t *bs )
35 {
36     debug_if( !bs )
37         return NULL;
38     lsmash_bits_t *bits = (lsmash_bits_t *)lsmash_malloc( sizeof(lsmash_bits_t) );
39     if( !bits )
40         return NULL;
41     lsmash_bits_init( bits, bs );
42     return bits;
43 }
44 
45 /* Must be used ONLY for bits struct created with isom_create_bits.
46  * Otherwise, just lsmash_free() the bits struct. */
lsmash_bits_cleanup(lsmash_bits_t * bits)47 void lsmash_bits_cleanup( lsmash_bits_t *bits )
48 {
49     debug_if( !bits )
50         return;
51     lsmash_free( bits );
52 }
53 
lsmash_bits_empty(lsmash_bits_t * bits)54 void lsmash_bits_empty( lsmash_bits_t *bits )
55 {
56     debug_if( !bits )
57         return;
58     lsmash_bs_empty( bits->bs );
59     bits->store = 0;
60     bits->cache = 0;
61 }
62 
63 #define BITS_IN_BYTE 8
lsmash_bits_put_align(lsmash_bits_t * bits)64 void lsmash_bits_put_align( lsmash_bits_t *bits )
65 {
66     debug_if( !bits )
67         return;
68     if( !bits->store )
69         return;
70     lsmash_bs_put_byte( bits->bs, bits->cache << ( BITS_IN_BYTE - bits->store ) );
71 }
72 
lsmash_bits_get_align(lsmash_bits_t * bits)73 void lsmash_bits_get_align( lsmash_bits_t *bits )
74 {
75     debug_if( !bits )
76         return;
77     bits->store = 0;
78     bits->cache = 0;
79 }
80 
81 /* we can change value's type to unsigned int for 64-bit operation if needed. */
lsmash_bits_mask_lsb8(uint32_t value,uint32_t width)82 static inline uint8_t lsmash_bits_mask_lsb8( uint32_t value, uint32_t width )
83 {
84     return (uint8_t)( value & ~( ~0U << width ) );
85 }
86 
lsmash_bits_put(lsmash_bits_t * bits,uint32_t width,uint64_t value)87 void lsmash_bits_put( lsmash_bits_t *bits, uint32_t width, uint64_t value )
88 {
89     debug_if( !bits || !width )
90         return;
91     if( bits->store )
92     {
93         if( bits->store + width < BITS_IN_BYTE )
94         {
95             /* cache can contain all of value's bits. */
96             bits->cache <<= width;
97             bits->cache |= lsmash_bits_mask_lsb8( value, width );
98             bits->store += width;
99             return;
100         }
101         /* flush cache with value's some leading bits. */
102         uint32_t free_bits = BITS_IN_BYTE - bits->store;
103         bits->cache <<= free_bits;
104         bits->cache |= lsmash_bits_mask_lsb8( value >> (width -= free_bits), free_bits );
105         lsmash_bs_put_byte( bits->bs, bits->cache );
106         bits->store = 0;
107         bits->cache = 0;
108     }
109     /* cache is empty here. */
110     /* byte unit operation. */
111     while( width > BITS_IN_BYTE )
112         lsmash_bs_put_byte( bits->bs, (uint8_t)(value >> (width -= BITS_IN_BYTE)) );
113     /* bit unit operation for residual. */
114     if( width )
115     {
116         bits->cache = lsmash_bits_mask_lsb8( value, width );
117         bits->store = width;
118     }
119 }
120 
lsmash_bits_get(lsmash_bits_t * bits,uint32_t width)121 uint64_t lsmash_bits_get( lsmash_bits_t *bits, uint32_t width )
122 {
123     debug_if( !bits || !width )
124         return 0;
125     uint64_t value = 0;
126     if( bits->store )
127     {
128         if( bits->store >= width )
129         {
130             /* cache contains all of bits required. */
131             bits->store -= width;
132             return lsmash_bits_mask_lsb8( bits->cache >> bits->store, width );
133         }
134         /* fill value's leading bits with cache's residual. */
135         value = lsmash_bits_mask_lsb8( bits->cache, bits->store );
136         width -= bits->store;
137         bits->store = 0;
138         bits->cache = 0;
139     }
140     /* cache is empty here. */
141     /* byte unit operation. */
142     while( width > BITS_IN_BYTE )
143     {
144         value <<= BITS_IN_BYTE;
145         width -= BITS_IN_BYTE;
146         value |= lsmash_bs_get_byte( bits->bs );
147     }
148     /* bit unit operation for residual. */
149     if( width )
150     {
151         bits->cache = lsmash_bs_get_byte( bits->bs );
152         bits->store = BITS_IN_BYTE - width;
153         value <<= width;
154         value |= lsmash_bits_mask_lsb8( bits->cache >> bits->store, width );
155     }
156     return value;
157 }
158 
lsmash_bits_export_data(lsmash_bits_t * bits,uint32_t * length)159 void *lsmash_bits_export_data( lsmash_bits_t *bits, uint32_t *length )
160 {
161     lsmash_bits_put_align( bits );
162     return lsmash_bs_export_data( bits->bs, length );
163 }
164 
lsmash_bits_import_data(lsmash_bits_t * bits,void * data,uint32_t length)165 int lsmash_bits_import_data( lsmash_bits_t *bits, void *data, uint32_t length )
166 {
167     return lsmash_bs_import_data( bits->bs, data, length );
168 }
169 
170 /****
171  bitstream with bytestream for adhoc operation
172 ****/
173 
lsmash_bits_adhoc_create()174 lsmash_bits_t *lsmash_bits_adhoc_create()
175 {
176     lsmash_bs_t *bs = lsmash_bs_create();
177     if( !bs )
178         return NULL;
179     lsmash_bits_t *bits = lsmash_bits_create( bs );
180     if( !bits )
181     {
182         lsmash_bs_cleanup( bs );
183         return NULL;
184     }
185     return bits;
186 }
187 
lsmash_bits_adhoc_cleanup(lsmash_bits_t * bits)188 void lsmash_bits_adhoc_cleanup( lsmash_bits_t *bits )
189 {
190     if( !bits )
191         return;
192     lsmash_bs_cleanup( bits->bs );
193     lsmash_bits_cleanup( bits );
194 }
195