1/* Copyright (C) 2002 Jean-Marc Valin 2 File: speex_bits.c 3 4 Handles bit packing/unpacking 5 6 Redistribution and use in source and binary forms, with or without 7 modification, are permitted provided that the following conditions 8 are met: 9 10 - Redistributions of source code must retain the above copyright 11 notice, this list of conditions and the following disclaimer. 12 13 - Redistributions in binary form must reproduce the above copyright 14 notice, this list of conditions and the following disclaimer in the 15 documentation and/or other materials provided with the distribution. 16 17 - Neither the name of the Xiph.org Foundation nor the names of its 18 contributors may be used to endorse or promote products derived from 19 this software without specific prior written permission. 20 21 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR 25 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 26 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 27 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 28 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 29 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 30 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 31 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 33*/ 34 35#ifdef HAVE_CONFIG_H 36#include "config.h" 37#endif 38 39#include <speex/speex_bits.h> 40#include "arch.h" 41#include "os_support.h" 42 43/* Maximum size of the bit-stream (for fixed-size allocation) */ 44#ifndef MAX_CHARS_PER_FRAME 45#define MAX_CHARS_PER_FRAME (2000/BYTES_PER_CHAR) 46#endif 47 48EXPORT void speex_bits_init(SpeexBits *bits) 49{ 50 bits->chars = (char*)speex_alloc(MAX_CHARS_PER_FRAME); 51 if (!bits->chars) 52 return; 53 54 bits->buf_size = MAX_CHARS_PER_FRAME; 55 56 bits->owner=1; 57 58 speex_bits_reset(bits); 59} 60 61EXPORT void speex_bits_init_buffer(SpeexBits *bits, void *buff, int buf_size) 62{ 63 bits->chars = (char*)buff; 64 bits->buf_size = buf_size; 65 66 bits->owner=0; 67 68 speex_bits_reset(bits); 69} 70 71EXPORT void speex_bits_set_bit_buffer(SpeexBits *bits, void *buff, int buf_size) 72{ 73 bits->chars = (char*)buff; 74 bits->buf_size = buf_size; 75 76 bits->owner=0; 77 78 bits->nbBits=buf_size<<LOG2_BITS_PER_CHAR; 79 bits->charPtr=0; 80 bits->bitPtr=0; 81 bits->overflow=0; 82 83} 84 85EXPORT void speex_bits_destroy(SpeexBits *bits) 86{ 87 if (bits->owner) 88 speex_free(bits->chars); 89 /* Will do something once the allocation is dynamic */ 90} 91 92EXPORT void speex_bits_reset(SpeexBits *bits) 93{ 94 /* We only need to clear the first byte now */ 95 bits->chars[0]=0; 96 bits->nbBits=0; 97 bits->charPtr=0; 98 bits->bitPtr=0; 99 bits->overflow=0; 100} 101 102EXPORT void speex_bits_rewind(SpeexBits *bits) 103{ 104 bits->charPtr=0; 105 bits->bitPtr=0; 106 bits->overflow=0; 107} 108 109EXPORT void speex_bits_read_from(SpeexBits *bits, char *chars, int len) 110{ 111 int i; 112 int nchars = len / BYTES_PER_CHAR; 113 if (nchars > bits->buf_size) 114 { 115 speex_notify("Packet is larger than allocated buffer"); 116 if (bits->owner) 117 { 118 char *tmp = (char*)speex_realloc(bits->chars, nchars); 119 if (tmp) 120 { 121 bits->buf_size=nchars; 122 bits->chars=tmp; 123 } else { 124 nchars=bits->buf_size; 125 speex_warning("Could not resize input buffer: truncating input"); 126 } 127 } else { 128 speex_warning("Do not own input buffer: truncating oversize input"); 129 nchars=bits->buf_size; 130 } 131 } 132#if (BYTES_PER_CHAR==2) 133/* Swap bytes to proper endian order (could be done externally) */ 134#define HTOLS(A) ((((A) >> 8)&0xff)|(((A) & 0xff)<<8)) 135#else 136#define HTOLS(A) (A) 137#endif 138 for (i=0;i<nchars;i++) 139 bits->chars[i]=HTOLS(chars[i]); 140 141 bits->nbBits=nchars<<LOG2_BITS_PER_CHAR; 142 bits->charPtr=0; 143 bits->bitPtr=0; 144 bits->overflow=0; 145} 146 147static void speex_bits_flush(SpeexBits *bits) 148{ 149 int nchars = ((bits->nbBits+BITS_PER_CHAR-1)>>LOG2_BITS_PER_CHAR); 150 if (bits->charPtr>0) 151 SPEEX_MOVE(bits->chars, &bits->chars[bits->charPtr], nchars-bits->charPtr); 152 bits->nbBits -= bits->charPtr<<LOG2_BITS_PER_CHAR; 153 bits->charPtr=0; 154} 155 156EXPORT void speex_bits_read_whole_bytes(SpeexBits *bits, 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 if (bits->owner) 165 { 166 char *tmp = (char*)speex_realloc(bits->chars, (bits->nbBits>>LOG2_BITS_PER_CHAR)+nchars+1); 167 if (tmp) 168 { 169 bits->buf_size=(bits->nbBits>>LOG2_BITS_PER_CHAR)+nchars+1; 170 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 pos=bits->nbBits>>LOG2_BITS_PER_CHAR; 183 for (i=0;i<nchars;i++) 184 bits->chars[pos+i]=HTOLS(chars[i]); 185 bits->nbBits+=nchars<<LOG2_BITS_PER_CHAR; 186} 187 188EXPORT int speex_bits_write(SpeexBits *bits, char *chars, int max_nbytes) 189{ 190 int i; 191 int max_nchars = max_nbytes/BYTES_PER_CHAR; 192 int charPtr, bitPtr, nbBits; 193 194 /* Insert terminator, but save the data so we can put it back after */ 195 bitPtr=bits->bitPtr; 196 charPtr=bits->charPtr; 197 nbBits=bits->nbBits; 198 speex_bits_insert_terminator(bits); 199 bits->bitPtr=bitPtr; 200 bits->charPtr=charPtr; 201 bits->nbBits=nbBits; 202 203 if (max_nchars > ((bits->nbBits+BITS_PER_CHAR-1)>>LOG2_BITS_PER_CHAR)) 204 max_nchars = ((bits->nbBits+BITS_PER_CHAR-1)>>LOG2_BITS_PER_CHAR); 205 206 for (i=0;i<max_nchars;i++) 207 chars[i]=HTOLS(bits->chars[i]); 208 return max_nchars*BYTES_PER_CHAR; 209} 210 211EXPORT 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 if (max_nchars > ((bits->nbBits)>>LOG2_BITS_PER_CHAR)) 216 max_nchars = ((bits->nbBits)>>LOG2_BITS_PER_CHAR); 217 for (i=0;i<max_nchars;i++) 218 chars[i]=HTOLS(bits->chars[i]); 219 220 if (bits->bitPtr>0) 221 bits->chars[0]=bits->chars[max_nchars]; 222 else 223 bits->chars[0]=0; 224 bits->charPtr=0; 225 bits->nbBits &= (BITS_PER_CHAR-1); 226 return max_nchars*BYTES_PER_CHAR; 227} 228 229EXPORT void speex_bits_pack(SpeexBits *bits, int data, int nbBits) 230{ 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 if (bits->owner) 237 { 238 int new_nchars = ((bits->buf_size+5)*3)>>1; 239 char *tmp = (char*)speex_realloc(bits->chars, new_nchars); 240 if (tmp) 241 { 242 bits->buf_size=new_nchars; 243 bits->chars=tmp; 244 } else { 245 speex_warning("Could not resize input buffer: not packing"); 246 return; 247 } 248 } else { 249 speex_warning("Do not own input buffer: not packing"); 250 return; 251 } 252 } 253 254 while(nbBits) 255 { 256 int bit; 257 bit = (d>>(nbBits-1))&1; 258 bits->chars[bits->charPtr] |= bit<<(BITS_PER_CHAR-1-bits->bitPtr); 259 bits->bitPtr++; 260 261 if (bits->bitPtr==BITS_PER_CHAR) 262 { 263 bits->bitPtr=0; 264 bits->charPtr++; 265 bits->chars[bits->charPtr] = 0; 266 } 267 bits->nbBits++; 268 nbBits--; 269 } 270} 271 272EXPORT int speex_bits_unpack_signed(SpeexBits *bits, int nbBits) 273{ 274 unsigned int d=speex_bits_unpack_unsigned(bits,nbBits); 275 /* If number is negative */ 276 if (d>>(nbBits-1)) 277 { 278 d |= (-1)<<nbBits; 279 } 280 return d; 281} 282 283EXPORT unsigned int speex_bits_unpack_unsigned(SpeexBits *bits, int nbBits) 284{ 285 unsigned int d=0; 286 if ((bits->charPtr<<LOG2_BITS_PER_CHAR)+bits->bitPtr+nbBits>bits->nbBits) 287 bits->overflow=1; 288 if (bits->overflow) 289 return 0; 290 while(nbBits) 291 { 292 d<<=1; 293 d |= (bits->chars[bits->charPtr]>>(BITS_PER_CHAR-1 - bits->bitPtr))&1; 294 bits->bitPtr++; 295 if (bits->bitPtr==BITS_PER_CHAR) 296 { 297 bits->bitPtr=0; 298 bits->charPtr++; 299 } 300 nbBits--; 301 } 302 return d; 303} 304 305EXPORT unsigned int speex_bits_peek_unsigned(SpeexBits *bits, int nbBits) 306{ 307 unsigned int d=0; 308 int bitPtr, charPtr; 309 char *chars; 310 311 if ((bits->charPtr<<LOG2_BITS_PER_CHAR)+bits->bitPtr+nbBits>bits->nbBits) 312 bits->overflow=1; 313 if (bits->overflow) 314 return 0; 315 316 bitPtr=bits->bitPtr; 317 charPtr=bits->charPtr; 318 chars = bits->chars; 319 while(nbBits) 320 { 321 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 nbBits--; 330 } 331 return d; 332} 333 334EXPORT int speex_bits_peek(SpeexBits *bits) 335{ 336 if ((bits->charPtr<<LOG2_BITS_PER_CHAR)+bits->bitPtr+1>bits->nbBits) 337 bits->overflow=1; 338 if (bits->overflow) 339 return 0; 340 return (bits->chars[bits->charPtr]>>(BITS_PER_CHAR-1 - bits->bitPtr))&1; 341} 342 343EXPORT 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 bits->overflow=1; 347 return; 348 } 349 bits->charPtr += (bits->bitPtr+n) >> LOG2_BITS_PER_CHAR; /* divide by BITS_PER_CHAR */ 350 bits->bitPtr = (bits->bitPtr+n) & (BITS_PER_CHAR-1); /* modulo by BITS_PER_CHAR */ 351} 352 353EXPORT int speex_bits_remaining(SpeexBits *bits) 354{ 355 if (bits->overflow) 356 return -1; 357 else 358 return bits->nbBits-((bits->charPtr<<LOG2_BITS_PER_CHAR)+bits->bitPtr); 359} 360 361EXPORT int speex_bits_nbytes(SpeexBits *bits) 362{ 363 return ((bits->nbBits+BITS_PER_CHAR-1)>>LOG2_BITS_PER_CHAR); 364} 365 366EXPORT void speex_bits_insert_terminator(SpeexBits *bits) 367{ 368 if (bits->bitPtr) 369 speex_bits_pack(bits, 0, 1); 370 while (bits->bitPtr) 371 speex_bits_pack(bits, 1, 1); 372} 373