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