bits.c 9.93 KB
Newer Older
Tristan Matthews's avatar
Tristan Matthews committed
1
/* Copyright (C) 2002 Jean-Marc Valin
2
   File: speex_bits.c
jmvalin's avatar
jmvalin committed
3
4
5

   Handles bit packing/unpacking

jm's avatar
jm committed
6
7
8
   Redistribution and use in source and binary forms, with or without
   modification, are permitted provided that the following conditions
   are met:
Tristan Matthews's avatar
Tristan Matthews committed
9

jm's avatar
jm committed
10
11
   - Redistributions of source code must retain the above copyright
   notice, this list of conditions and the following disclaimer.
Tristan Matthews's avatar
Tristan Matthews committed
12

jm's avatar
jm committed
13
14
15
   - Redistributions in binary form must reproduce the above copyright
   notice, this list of conditions and the following disclaimer in the
   documentation and/or other materials provided with the distribution.
Tristan Matthews's avatar
Tristan Matthews committed
16

jm's avatar
jm committed
17
18
19
   - Neither the name of the Xiph.org Foundation nor the names of its
   contributors may be used to endorse or promote products derived from
   this software without specific prior written permission.
Tristan Matthews's avatar
Tristan Matthews committed
20

jm's avatar
jm committed
21
22
23
24
25
26
27
28
29
30
31
   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
jmvalin's avatar
jmvalin committed
32
33
34

*/

35
36
37
38
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

Ron's avatar
Ron committed
39
#include "speex/speex_bits.h"
jm's avatar
jm committed
40
#include "arch.h"
41
#include "os_support.h"
jmvalin's avatar
jmvalin committed
42

43
44
45
46
/* Maximum size of the bit-stream (for fixed-size allocation) */
#ifndef MAX_CHARS_PER_FRAME
#define MAX_CHARS_PER_FRAME (2000/BYTES_PER_CHAR)
#endif
47

48
EXPORT void speex_bits_init(SpeexBits *bits)
jmvalin's avatar
jmvalin committed
49
{
50
   bits->chars = (char*)speex_alloc(MAX_CHARS_PER_FRAME);
51
52
53
   if (!bits->chars)
      return;

54
   bits->buf_size = MAX_CHARS_PER_FRAME;
jmvalin's avatar
...    
jmvalin committed
55

56
   bits->owner=1;
57
58

   speex_bits_reset(bits);
jmvalin's avatar
...    
jmvalin committed
59
60
}

61
EXPORT void speex_bits_init_buffer(SpeexBits *bits, void *buff, int buf_size)
jmvalin's avatar
...    
jmvalin committed
62
{
63
   bits->chars = (char*)buff;
64
   bits->buf_size = buf_size;
jmvalin's avatar
...    
jmvalin committed
65

66
   bits->owner=0;
67
68

   speex_bits_reset(bits);
jmvalin's avatar
jmvalin committed
69
70
}

71
EXPORT void speex_bits_set_bit_buffer(SpeexBits *bits, void *buff, int buf_size)
72
73
74
75
76
77
78
79
80
81
{
   bits->chars = (char*)buff;
   bits->buf_size = buf_size;

   bits->owner=0;

   bits->nbBits=buf_size<<LOG2_BITS_PER_CHAR;
   bits->charPtr=0;
   bits->bitPtr=0;
   bits->overflow=0;
Tristan Matthews's avatar
Tristan Matthews committed
82

83
84
}

85
EXPORT void speex_bits_destroy(SpeexBits *bits)
jmvalin's avatar
jmvalin committed
86
{
87
   if (bits->owner)
88
      speex_free(bits->chars);
jmvalin's avatar
jmvalin committed
89
90
91
   /* Will do something once the allocation is dynamic */
}

92
EXPORT void speex_bits_reset(SpeexBits *bits)
jmvalin's avatar
jmvalin committed
93
{
94
   /* We only need to clear the first byte now */
95
   bits->chars[0]=0;
jmvalin's avatar
jmvalin committed
96
   bits->nbBits=0;
97
   bits->charPtr=0;
jmvalin's avatar
jmvalin committed
98
   bits->bitPtr=0;
99
   bits->overflow=0;
jmvalin's avatar
jmvalin committed
100
101
}

102
EXPORT void speex_bits_rewind(SpeexBits *bits)
jmvalin's avatar
jmvalin committed
103
{
104
   bits->charPtr=0;
jmvalin's avatar
jmvalin committed
105
   bits->bitPtr=0;
106
   bits->overflow=0;
jmvalin's avatar
jmvalin committed
107
108
}

109
EXPORT void speex_bits_read_from(SpeexBits *bits, const char *chars, int len)
jmvalin's avatar
jmvalin committed
110
111
{
   int i;
112
113
   int nchars = len / BYTES_PER_CHAR;
   if (nchars > bits->buf_size)
jmvalin's avatar
jmvalin committed
114
   {
115
      speex_notify("Packet is larger than allocated buffer");
116
117
      if (bits->owner)
      {
118
         char *tmp = (char*)speex_realloc(bits->chars, nchars);
119
120
         if (tmp)
         {
121
            bits->buf_size=nchars;
122
            bits->chars=tmp;
123
         } else {
124
            nchars=bits->buf_size;
125
126
127
            speex_warning("Could not resize input buffer: truncating input");
         }
      } else {
128
         speex_warning("Do not own input buffer: truncating oversize input");
129
         nchars=bits->buf_size;
130
      }
jmvalin's avatar
jmvalin committed
131
   }
132
133
134
135
136
137
138
139
140
141
#if (BYTES_PER_CHAR==2)
/* Swap bytes to proper endian order (could be done externally) */
#define HTOLS(A) ((((A) >> 8)&0xff)|(((A) & 0xff)<<8))
#else
#define HTOLS(A) (A)
#endif
   for (i=0;i<nchars;i++)
      bits->chars[i]=HTOLS(chars[i]);

   bits->nbBits=nchars<<LOG2_BITS_PER_CHAR;
142
   bits->charPtr=0;
jmvalin's avatar
jmvalin committed
143
   bits->bitPtr=0;
144
   bits->overflow=0;
jmvalin's avatar
jmvalin committed
145
146
}

jm's avatar
jm committed
147
static void speex_bits_flush(SpeexBits *bits)
148
{
149
150
   int nchars = ((bits->nbBits+BITS_PER_CHAR-1)>>LOG2_BITS_PER_CHAR);
   if (bits->charPtr>0)
151
      SPEEX_MOVE(bits->chars, &bits->chars[bits->charPtr], nchars-bits->charPtr);
152
153
   bits->nbBits -= bits->charPtr<<LOG2_BITS_PER_CHAR;
   bits->charPtr=0;
154
155
}

156
EXPORT void speex_bits_read_whole_bytes(SpeexBits *bits, const char *chars, int nbytes)
157
158
{
   int i,pos;
159
   int nchars = nbytes/BYTES_PER_CHAR;
160

161
   if (((bits->nbBits+BITS_PER_CHAR-1)>>LOG2_BITS_PER_CHAR)+nchars > bits->buf_size)
162
   {
163
      /* Packet is larger than allocated buffer */
164
165
      if (bits->owner)
      {
166
         char *tmp = (char*)speex_realloc(bits->chars, (bits->nbBits>>LOG2_BITS_PER_CHAR)+nchars+1);
167
168
         if (tmp)
         {
169
170
            bits->buf_size=(bits->nbBits>>LOG2_BITS_PER_CHAR)+nchars+1;
            bits->chars=tmp;
171
         } else {
172
            nchars=bits->buf_size-(bits->nbBits>>LOG2_BITS_PER_CHAR)-1;
173
            speex_warning("Could not resize input buffer: truncating oversize input");
174
175
         }
      } else {
176
         speex_warning("Do not own input buffer: truncating oversize input");
177
         nchars=bits->buf_size;
178
179
180
      }
   }

181
   speex_bits_flush(bits);
182
183
   pos=bits->nbBits>>LOG2_BITS_PER_CHAR;
   for (i=0;i<nchars;i++)
184
      bits->chars[pos+i]=HTOLS(chars[i]);
185
   bits->nbBits+=nchars<<LOG2_BITS_PER_CHAR;
186
187
}

188
EXPORT int speex_bits_write(SpeexBits *bits, char *chars, int max_nbytes)
jmvalin's avatar
jmvalin committed
189
190
{
   int i;
191
192
   int max_nchars = max_nbytes/BYTES_PER_CHAR;
   int charPtr, bitPtr, nbBits;
193

194
195
   /* Insert terminator, but save the data so we can put it back after */
   bitPtr=bits->bitPtr;
196
   charPtr=bits->charPtr;
197
198
199
   nbBits=bits->nbBits;
   speex_bits_insert_terminator(bits);
   bits->bitPtr=bitPtr;
200
   bits->charPtr=charPtr;
201
   bits->nbBits=nbBits;
jm's avatar
oops...    
jm committed
202

203
204
   if (max_nchars > ((bits->nbBits+BITS_PER_CHAR-1)>>LOG2_BITS_PER_CHAR))
      max_nchars = ((bits->nbBits+BITS_PER_CHAR-1)>>LOG2_BITS_PER_CHAR);
205

206
207
208
   for (i=0;i<max_nchars;i++)
      chars[i]=HTOLS(bits->chars[i]);
   return max_nchars*BYTES_PER_CHAR;
jmvalin's avatar
jmvalin committed
209
210
}

211
EXPORT int speex_bits_write_whole_bytes(SpeexBits *bits, char *chars, int max_nbytes)
212
{
213
   int max_nchars = max_nbytes/BYTES_PER_CHAR;
214
   int i;
215
216
217
   if (max_nchars > ((bits->nbBits)>>LOG2_BITS_PER_CHAR))
      max_nchars = ((bits->nbBits)>>LOG2_BITS_PER_CHAR);
   for (i=0;i<max_nchars;i++)
218
219
      chars[i]=HTOLS(bits->chars[i]);

220
   if (bits->bitPtr>0)
221
      bits->chars[0]=bits->chars[max_nchars];
222
   else
223
224
225
226
      bits->chars[0]=0;
   bits->charPtr=0;
   bits->nbBits &= (BITS_PER_CHAR-1);
   return max_nchars*BYTES_PER_CHAR;
227
228
}

229
EXPORT void speex_bits_pack(SpeexBits *bits, int data, int nbBits)
jmvalin's avatar
jmvalin committed
230
{
jmvalin's avatar
jmvalin committed
231
   unsigned int d=data;
232

233
   if (bits->charPtr+((nbBits+bits->bitPtr)>>LOG2_BITS_PER_CHAR) >= bits->buf_size)
234
   {
235
      speex_notify("Buffer too small to pack bits");
236
237
      if (bits->owner)
      {
238
         int new_nchars = ((bits->buf_size+5)*3)>>1;
239
         char *tmp = (char*)speex_realloc(bits->chars, new_nchars);
240
241
         if (tmp)
         {
242
243
            bits->buf_size=new_nchars;
            bits->chars=tmp;
244
245
246
247
248
249
250
251
252
253
         } else {
            speex_warning("Could not resize input buffer: not packing");
            return;
         }
      } else {
         speex_warning("Do not own input buffer: not packing");
         return;
      }
   }

jmvalin's avatar
jmvalin committed
254
255
256
257
   while(nbBits)
   {
      int bit;
      bit = (d>>(nbBits-1))&1;
258
      bits->chars[bits->charPtr] |= bit<<(BITS_PER_CHAR-1-bits->bitPtr);
jmvalin's avatar
jmvalin committed
259
      bits->bitPtr++;
260

261
      if (bits->bitPtr==BITS_PER_CHAR)
jmvalin's avatar
jmvalin committed
262
263
      {
         bits->bitPtr=0;
264
265
         bits->charPtr++;
         bits->chars[bits->charPtr] = 0;
jmvalin's avatar
jmvalin committed
266
267
268
269
      }
      bits->nbBits++;
      nbBits--;
   }
jmvalin's avatar
jmvalin committed
270
271
}

272
EXPORT int speex_bits_unpack_signed(SpeexBits *bits, int nbBits)
jmvalin's avatar
jmvalin committed
273
{
274
   unsigned int d=speex_bits_unpack_unsigned(bits,nbBits);
jmvalin's avatar
jmvalin committed
275
276
277
278
279
280
   /* If number is negative */
   if (d>>(nbBits-1))
   {
      d |= (-1)<<nbBits;
   }
   return d;
jmvalin's avatar
jmvalin committed
281
282
}

283
EXPORT unsigned int speex_bits_unpack_unsigned(SpeexBits *bits, int nbBits)
jmvalin's avatar
jmvalin committed
284
{
jmvalin's avatar
jmvalin committed
285
   unsigned int d=0;
286
   if ((bits->charPtr<<LOG2_BITS_PER_CHAR)+bits->bitPtr+nbBits>bits->nbBits)
287
288
289
      bits->overflow=1;
   if (bits->overflow)
      return 0;
jmvalin's avatar
jmvalin committed
290
291
292
   while(nbBits)
   {
      d<<=1;
293
      d |= (bits->chars[bits->charPtr]>>(BITS_PER_CHAR-1 - bits->bitPtr))&1;
jmvalin's avatar
jmvalin committed
294
      bits->bitPtr++;
295
      if (bits->bitPtr==BITS_PER_CHAR)
jmvalin's avatar
jmvalin committed
296
297
      {
         bits->bitPtr=0;
298
         bits->charPtr++;
jmvalin's avatar
jmvalin committed
299
300
301
302
      }
      nbBits--;
   }
   return d;
jmvalin's avatar
jmvalin committed
303
}
jmvalin's avatar
jmvalin committed
304

305
EXPORT unsigned int speex_bits_peek_unsigned(SpeexBits *bits, int nbBits)
306
307
{
   unsigned int d=0;
308
309
   int bitPtr, charPtr;
   char *chars;
310

311
   if ((bits->charPtr<<LOG2_BITS_PER_CHAR)+bits->bitPtr+nbBits>bits->nbBits)
312
313
314
315
     bits->overflow=1;
   if (bits->overflow)
      return 0;

316
   bitPtr=bits->bitPtr;
317
318
   charPtr=bits->charPtr;
   chars = bits->chars;
319
320
321
   while(nbBits)
   {
      d<<=1;
322
      d |= (chars[charPtr]>>(BITS_PER_CHAR-1 - bitPtr))&1;
323
      bitPtr++;
324
      if (bitPtr==BITS_PER_CHAR)
325
326
      {
         bitPtr=0;
327
         charPtr++;
328
329
330
331
332
333
      }
      nbBits--;
   }
   return d;
}

334
EXPORT int speex_bits_peek(SpeexBits *bits)
335
{
336
   if ((bits->charPtr<<LOG2_BITS_PER_CHAR)+bits->bitPtr+1>bits->nbBits)
337
338
339
      bits->overflow=1;
   if (bits->overflow)
      return 0;
340
   return (bits->chars[bits->charPtr]>>(BITS_PER_CHAR-1 - bits->bitPtr))&1;
341
342
}

343
EXPORT void speex_bits_advance(SpeexBits *bits, int n)
344
{
345
    if (((bits->charPtr<<LOG2_BITS_PER_CHAR)+bits->bitPtr+n>bits->nbBits) || bits->overflow){
346
347
      bits->overflow=1;
      return;
348
    }
349
350
   bits->charPtr += (bits->bitPtr+n) >> LOG2_BITS_PER_CHAR; /* divide by BITS_PER_CHAR */
   bits->bitPtr = (bits->bitPtr+n) & (BITS_PER_CHAR-1);       /* modulo by BITS_PER_CHAR */
351
352
}

353
EXPORT int speex_bits_remaining(SpeexBits *bits)
354
355
356
357
{
   if (bits->overflow)
      return -1;
   else
358
      return bits->nbBits-((bits->charPtr<<LOG2_BITS_PER_CHAR)+bits->bitPtr);
359
360
}

361
EXPORT int speex_bits_nbytes(SpeexBits *bits)
jmvalin's avatar
jmvalin committed
362
{
363
   return ((bits->nbBits+BITS_PER_CHAR-1)>>LOG2_BITS_PER_CHAR);
jmvalin's avatar
jmvalin committed
364
}
365

366
EXPORT void speex_bits_insert_terminator(SpeexBits *bits)
367
{
368
   if (bits->bitPtr)
369
      speex_bits_pack(bits, 0, 1);
370
   while (bits->bitPtr)
371
372
      speex_bits_pack(bits, 1, 1);
}