123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370 |
- /*
- * Copyright (c) 2011 Apple Inc. All rights reserved.
- *
- * @APPLE_APACHE_LICENSE_HEADER_START@
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * @APPLE_APACHE_LICENSE_HEADER_END@
- */
- /*
- File: ag_enc.c
-
- Contains: Adaptive Golomb encode routines.
- Copyright: (c) 2001-2011 Apple, Inc.
- */
- #include "aglib.h"
- #include "ALACBitUtilities.h"
- #include "EndianPortable.h"
- #include "ALACAudioTypes.h"
- #include <math.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #if __GNUC__ && TARGET_OS_MAC
- #if __POWERPC__
- #include <ppc_intrinsics.h>
- #else
- #include <libkern/OSByteOrder.h>
- #endif
- #endif
- #define CODE_TO_LONG_MAXBITS 32
- #define N_MAX_MEAN_CLAMP 0xffff
- #define N_MEAN_CLAMP_VAL 0xffff
- #define REPORT_VAL 40
- #if __GNUC__
- #define ALWAYS_INLINE __attribute__((always_inline))
- #else
- #define ALWAYS_INLINE
- #endif
- /* And on the subject of the CodeWarrior x86 compiler and inlining, I reworked a lot of this
- to help the compiler out. In many cases this required manual inlining or a macro. Sorry
- if it is ugly but the performance gains are well worth it.
- - WSK 5/19/04
- */
- // note: implementing this with some kind of "count leading zeros" assembly is a big performance win
- static inline int32_t lead( int32_t m )
- {
- long j;
- unsigned long c = (1ul << 31);
- for(j=0; j < 32; j++)
- {
- if((c & m) != 0)
- break;
- c >>= 1;
- }
- return (j);
- }
- #define arithmin(a, b) ((a) < (b) ? (a) : (b))
- static inline int32_t ALWAYS_INLINE lg3a( int32_t x)
- {
- int32_t result;
- x += 3;
- result = lead(x);
- return 31 - result;
- }
- static inline int32_t ALWAYS_INLINE abs_func( int32_t a )
- {
- // note: the CW PPC intrinsic __abs() turns into these instructions so no need to try and use it
- int32_t isneg = a >> 31;
- int32_t xorval = a ^ isneg;
- int32_t result = xorval-isneg;
-
- return result;
- }
- static inline uint32_t ALWAYS_INLINE read32bit( uint8_t * buffer )
- {
- // embedded CPUs typically can't read unaligned 32-bit words so just read the bytes
- uint32_t value;
-
- value = ((uint32_t)buffer[0] << 24) | ((uint32_t)buffer[1] << 16) |
- ((uint32_t)buffer[2] << 8) | (uint32_t)buffer[3];
- return value;
- }
- #if PRAGMA_MARK
- #pragma mark -
- #endif
- static inline int32_t dyn_code(int32_t m, int32_t k, int32_t n, uint32_t *outNumBits)
- {
- uint32_t div, mod, de;
- uint32_t numBits;
- uint32_t value;
- //Assert( n >= 0 );
- div = n/m;
- if(div >= MAX_PREFIX_16)
- {
- numBits = MAX_PREFIX_16 + MAX_DATATYPE_BITS_16;
- value = (((1<<MAX_PREFIX_16)-1)<<MAX_DATATYPE_BITS_16) + n;
- }
- else
- {
- mod = n%m;
- de = (mod == 0);
- numBits = div + k + 1 - de;
- value = (((1<<div)-1)<<(numBits-div)) + mod + 1 - de;
- // if coding this way is bigger than doing escape, then do escape
- if (numBits > MAX_PREFIX_16 + MAX_DATATYPE_BITS_16)
- {
- numBits = MAX_PREFIX_16 + MAX_DATATYPE_BITS_16;
- value = (((1<<MAX_PREFIX_16)-1)<<MAX_DATATYPE_BITS_16) + n;
- }
- }
-
- *outNumBits = numBits;
- return (int32_t) value;
- }
- static inline int32_t dyn_code_32bit(int32_t maxbits, uint32_t m, uint32_t k, uint32_t n, uint32_t *outNumBits, uint32_t *outValue, uint32_t *overflow, uint32_t *overflowbits)
- {
- uint32_t div, mod, de;
- uint32_t numBits;
- uint32_t value;
- int32_t didOverflow = 0;
- div = n/m;
- if (div < MAX_PREFIX_32)
- {
- mod = n - (m * div);
- de = (mod == 0);
- numBits = div + k + 1 - de;
- value = (((1<<div)-1)<<(numBits-div)) + mod + 1 - de;
- if (numBits > 25)
- goto codeasescape;
- }
- else
- {
- codeasescape:
- numBits = MAX_PREFIX_32;
- value = (((1<<MAX_PREFIX_32)-1));
- *overflow = n;
- *overflowbits = maxbits;
- didOverflow = 1;
- }
-
- *outNumBits = numBits;
- *outValue = value;
- return didOverflow;
- }
- static inline void ALWAYS_INLINE dyn_jam_noDeref(unsigned char *out, uint32_t bitPos, uint32_t numBits, uint32_t value)
- {
- uint32_t *i = (uint32_t *)(out + (bitPos >> 3));
- uint32_t mask;
- uint32_t curr;
- uint32_t shift;
- //Assert( numBits <= 32 );
- curr = *i;
- curr = Swap32NtoB( curr );
- shift = 32 - (bitPos & 7) - numBits;
- mask = ~0u >> (32 - numBits); // mask must be created in two steps to avoid compiler sequencing ambiguity
- mask <<= shift;
- value = (value << shift) & mask;
- value |= curr & ~mask;
-
- *i = Swap32BtoN( value );
- }
- static inline void ALWAYS_INLINE dyn_jam_noDeref_large(unsigned char *out, uint32_t bitPos, uint32_t numBits, uint32_t value)
- {
- uint32_t * i = (uint32_t *)(out + (bitPos>>3));
- uint32_t w;
- uint32_t curr;
- uint32_t mask;
- int32_t shiftvalue = (32 - (bitPos&7) - numBits);
-
- //Assert(numBits <= 32);
- curr = *i;
- curr = Swap32NtoB( curr );
- if (shiftvalue < 0)
- {
- uint8_t tailbyte;
- uint8_t *tailptr;
- w = value >> -shiftvalue;
- mask = ~0u >> -shiftvalue;
- w |= (curr & ~mask);
- tailptr = ((uint8_t *)i) + 4;
- tailbyte = (value << ((8+shiftvalue))) & 0xff;
- *tailptr = (uint8_t)tailbyte;
- }
- else
- {
- mask = ~0u >> (32 - numBits);
- mask <<= shiftvalue; // mask must be created in two steps to avoid compiler sequencing ambiguity
- w = (value << shiftvalue) & mask;
- w |= curr & ~mask;
- }
-
- *i = Swap32BtoN( w );
- }
- int32_t dyn_comp( AGParamRecPtr params, int32_t * pc, BitBuffer * bitstream, int32_t numSamples, int32_t bitSize, uint32_t * outNumBits )
- {
- unsigned char * out;
- uint32_t bitPos, startPos;
- uint32_t m, k, n, c, mz, nz;
- uint32_t numBits;
- uint32_t value;
- int32_t del, zmode;
- uint32_t overflow, overflowbits;
- int32_t status;
- // shadow the variables in params so there's not the dereferencing overhead
- uint32_t mb, pb, kb, wb;
- int32_t rowPos = 0;
- int32_t rowSize = params->sw;
- int32_t rowJump = (params->fw) - rowSize;
- int32_t * inPtr = pc;
- *outNumBits = 0;
- RequireAction( (bitSize >= 1) && (bitSize <= 32), return kALAC_ParamError; );
- out = bitstream->cur;
- startPos = bitstream->bitIndex;
- bitPos = startPos;
- mb = params->mb = params->mb0;
- pb = params->pb;
- kb = params->kb;
- wb = params->wb;
- zmode = 0;
- c=0;
- status = ALAC_noErr;
- while (c < numSamples)
- {
- m = mb >> QBSHIFT;
- k = lg3a(m);
- if ( k > kb)
- {
- k = kb;
- }
- m = (1<<k)-1;
- del = *inPtr++;
- rowPos++;
- n = (abs_func(del) << 1) - ((del >> 31) & 1) - zmode;
- //Assert( 32-lead(n) <= bitSize );
- if ( dyn_code_32bit(bitSize, m, k, n, &numBits, &value, &overflow, &overflowbits) )
- {
- dyn_jam_noDeref(out, bitPos, numBits, value);
- bitPos += numBits;
- dyn_jam_noDeref_large(out, bitPos, overflowbits, overflow);
- bitPos += overflowbits;
- }
- else
- {
- dyn_jam_noDeref(out, bitPos, numBits, value);
- bitPos += numBits;
- }
-
- c++;
- if ( rowPos >= rowSize)
- {
- rowPos = 0;
- inPtr += rowJump;
- }
- mb = pb * (n + zmode) + mb - ((pb *mb)>>QBSHIFT);
- // update mean tracking if it's overflowed
- if (n > N_MAX_MEAN_CLAMP)
- mb = N_MEAN_CLAMP_VAL;
- zmode = 0;
- RequireAction(c <= numSamples, status = kALAC_ParamError; goto Exit; );
- if (((mb << MMULSHIFT) < QB) && (c < numSamples))
- {
- zmode = 1;
- nz = 0;
- while(c<numSamples && *inPtr == 0)
- {
- /* Take care of wrap-around globals. */
- ++inPtr;
- ++nz;
- ++c;
- if ( ++rowPos >= rowSize)
- {
- rowPos = 0;
- inPtr += rowJump;
- }
- if(nz >= 65535)
- {
- zmode = 0;
- break;
- }
- }
- k = lead(mb) - BITOFF+((mb+MOFF)>>MDENSHIFT);
- mz = ((1<<k)-1) & wb;
- value = dyn_code(mz, k, nz, &numBits);
- dyn_jam_noDeref(out, bitPos, numBits, value);
- bitPos += numBits;
- mb = 0;
- }
- }
- *outNumBits = (bitPos - startPos);
- BitBufferAdvance( bitstream, *outNumBits );
- Exit:
- return status;
- }
|