blob: f1eb5ae8f75e5fddec6160985667f3bc51e2af54 [file] [log] [blame]
/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
/*
* arith_routinshist.c
*
* This C file contains arithmetic encoding and decoding.
*
*/
#include "arith_routins.h"
/****************************************************************************
* WebRtcIsacfix_EncHistMulti(...)
*
* Encode the histogram interval
*
* Input:
* - streamData : in-/output struct containing bitstream
* - data : data vector
* - cdf : array of cdf arrays
* - lenData : data vector length
*
* Return value : 0 if ok
* <0 if error detected
*/
int WebRtcIsacfix_EncHistMulti(Bitstr_enc *streamData,
const int16_t *data,
const uint16_t *const *cdf,
const int16_t lenData)
{
uint32_t W_lower;
uint32_t W_upper;
uint32_t W_upper_LSB;
uint32_t W_upper_MSB;
uint16_t *streamPtr;
uint16_t negCarry;
uint16_t *maxStreamPtr;
uint16_t *streamPtrCarry;
uint32_t cdfLo;
uint32_t cdfHi;
int k;
/* point to beginning of stream buffer
* and set maximum streamPtr value */
streamPtr = streamData->stream + streamData->stream_index;
maxStreamPtr = streamData->stream + STREAM_MAXW16_60MS - 1;
W_upper = streamData->W_upper;
for (k = lenData; k > 0; k--)
{
/* fetch cdf_lower and cdf_upper from cdf tables */
cdfLo = (uint32_t) *(*cdf + (uint32_t)*data);
cdfHi = (uint32_t) *(*cdf++ + (uint32_t)*data++ + 1);
/* update interval */
W_upper_LSB = W_upper & 0x0000FFFF;
W_upper_MSB = W_upper >> 16;
W_lower = WEBRTC_SPL_UMUL(W_upper_MSB, cdfLo);
W_lower += ((W_upper_LSB * cdfLo) >> 16);
W_upper = WEBRTC_SPL_UMUL(W_upper_MSB, cdfHi);
W_upper += ((W_upper_LSB * cdfHi) >> 16);
/* shift interval such that it begins at zero */
W_upper -= ++W_lower;
/* add integer to bitstream */
streamData->streamval += W_lower;
/* handle carry */
if (streamData->streamval < W_lower)
{
/* propagate carry */
streamPtrCarry = streamPtr;
if (streamData->full == 0) {
negCarry = *streamPtrCarry;
negCarry += 0x0100;
*streamPtrCarry = negCarry;
while (!(negCarry))
{
negCarry = *--streamPtrCarry;
negCarry++;
*streamPtrCarry = negCarry;
}
} else {
while ( !(++(*--streamPtrCarry)) );
}
}
/* renormalize interval, store most significant byte of streamval and update streamval
* W_upper < 2^24 */
while ( !(W_upper & 0xFF000000) )
{
W_upper <<= 8;
if (streamData->full == 0) {
*streamPtr++ += (uint16_t)(streamData->streamval >> 24);
streamData->full = 1;
} else {
*streamPtr = (uint16_t)((streamData->streamval >> 24) << 8);
streamData->full = 0;
}
if( streamPtr > maxStreamPtr ) {
return -ISAC_DISALLOWED_BITSTREAM_LENGTH;
}
streamData->streamval <<= 8;
}
}
/* calculate new stream_index */
streamData->stream_index = streamPtr - streamData->stream;
streamData->W_upper = W_upper;
return 0;
}
/****************************************************************************
* WebRtcIsacfix_DecHistBisectMulti(...)
*
* Function to decode more symbols from the arithmetic bytestream, using
* method of bisection cdf tables should be of size 2^k-1 (which corresponds
* to an alphabet size of 2^k-2)
*
* Input:
* - streamData : in-/output struct containing bitstream
* - cdf : array of cdf arrays
* - cdfSize : array of cdf table sizes+1 (power of two: 2^k)
* - lenData : data vector length
*
* Output:
* - data : data vector
*
* Return value : number of bytes in the stream
* <0 if error detected
*/
int16_t WebRtcIsacfix_DecHistBisectMulti(int16_t *data,
Bitstr_dec *streamData,
const uint16_t *const *cdf,
const uint16_t *cdfSize,
const int16_t lenData)
{
uint32_t W_lower = 0;
uint32_t W_upper;
uint32_t W_tmp;
uint32_t W_upper_LSB;
uint32_t W_upper_MSB;
uint32_t streamval;
const uint16_t *streamPtr;
const uint16_t *cdfPtr;
int16_t sizeTmp;
int k;
streamPtr = streamData->stream + streamData->stream_index;
W_upper = streamData->W_upper;
/* Error check: should not be possible in normal operation */
if (W_upper == 0) {
return -2;
}
/* first time decoder is called for this stream */
if (streamData->stream_index == 0)
{
/* read first word from bytestream */
streamval = (uint32_t)*streamPtr++ << 16;
streamval |= *streamPtr++;
} else {
streamval = streamData->streamval;
}
for (k = lenData; k > 0; k--)
{
/* find the integer *data for which streamval lies in [W_lower+1, W_upper] */
W_upper_LSB = W_upper & 0x0000FFFF;
W_upper_MSB = W_upper >> 16;
/* start halfway the cdf range */
sizeTmp = *cdfSize++ / 2;
cdfPtr = *cdf + (sizeTmp - 1);
/* method of bisection */
for ( ;; )
{
W_tmp = WEBRTC_SPL_UMUL_32_16(W_upper_MSB, *cdfPtr);
W_tmp += (W_upper_LSB * (*cdfPtr)) >> 16;
sizeTmp /= 2;
if (sizeTmp == 0) {
break;
}
if (streamval > W_tmp)
{
W_lower = W_tmp;
cdfPtr += sizeTmp;
} else {
W_upper = W_tmp;
cdfPtr -= sizeTmp;
}
}
if (streamval > W_tmp)
{
W_lower = W_tmp;
*data++ = cdfPtr - *cdf++;
} else {
W_upper = W_tmp;
*data++ = cdfPtr - *cdf++ - 1;
}
/* shift interval to start at zero */
W_upper -= ++W_lower;
/* add integer to bitstream */
streamval -= W_lower;
/* renormalize interval and update streamval */
/* W_upper < 2^24 */
while ( !(W_upper & 0xFF000000) )
{
/* read next byte from stream */
if (streamData->full == 0) {
streamval = (streamval << 8) | (*streamPtr++ & 0x00FF);
streamData->full = 1;
} else {
streamval = (streamval << 8) | (*streamPtr >> 8);
streamData->full = 0;
}
W_upper <<= 8;
}
/* Error check: should not be possible in normal operation */
if (W_upper == 0) {
return -2;
}
}
streamData->stream_index = streamPtr - streamData->stream;
streamData->W_upper = W_upper;
streamData->streamval = streamval;
if ( W_upper > 0x01FFFFFF ) {
return (streamData->stream_index*2 - 3 + !streamData->full);
} else {
return (streamData->stream_index*2 - 2 + !streamData->full);
}
}
/****************************************************************************
* WebRtcIsacfix_DecHistOneStepMulti(...)
*
* Function to decode more symbols from the arithmetic bytestream, taking
* single step up or down at a time.
* cdf tables can be of arbitrary size, but large tables may take a lot of
* iterations.
*
* Input:
* - streamData : in-/output struct containing bitstream
* - cdf : array of cdf arrays
* - initIndex : vector of initial cdf table search entries
* - lenData : data vector length
*
* Output:
* - data : data vector
*
* Return value : number of bytes in original stream
* <0 if error detected
*/
int16_t WebRtcIsacfix_DecHistOneStepMulti(int16_t *data,
Bitstr_dec *streamData,
const uint16_t *const *cdf,
const uint16_t *initIndex,
const int16_t lenData)
{
uint32_t W_lower;
uint32_t W_upper;
uint32_t W_tmp;
uint32_t W_upper_LSB;
uint32_t W_upper_MSB;
uint32_t streamval;
const uint16_t *streamPtr;
const uint16_t *cdfPtr;
int k;
streamPtr = streamData->stream + streamData->stream_index;
W_upper = streamData->W_upper;
/* Error check: Should not be possible in normal operation */
if (W_upper == 0) {
return -2;
}
/* Check if it is the first time decoder is called for this stream */
if (streamData->stream_index == 0)
{
/* read first word from bytestream */
streamval = (uint32_t)(*streamPtr++) << 16;
streamval |= *streamPtr++;
} else {
streamval = streamData->streamval;
}
for (k = lenData; k > 0; k--)
{
/* find the integer *data for which streamval lies in [W_lower+1, W_upper] */
W_upper_LSB = W_upper & 0x0000FFFF;
W_upper_MSB = WEBRTC_SPL_RSHIFT_U32(W_upper, 16);
/* start at the specified table entry */
cdfPtr = *cdf + (*initIndex++);
W_tmp = WEBRTC_SPL_UMUL_32_16(W_upper_MSB, *cdfPtr);
W_tmp += (W_upper_LSB * (*cdfPtr)) >> 16;
if (streamval > W_tmp)
{
for ( ;; )
{
W_lower = W_tmp;
/* range check */
if (cdfPtr[0] == 65535) {
return -3;
}
W_tmp = WEBRTC_SPL_UMUL_32_16(W_upper_MSB, *++cdfPtr);
W_tmp += (W_upper_LSB * (*cdfPtr)) >> 16;
if (streamval <= W_tmp) {
break;
}
}
W_upper = W_tmp;
*data++ = cdfPtr - *cdf++ - 1;
} else {
for ( ;; )
{
W_upper = W_tmp;
--cdfPtr;
/* range check */
if (cdfPtr < *cdf) {
return -3;
}
W_tmp = WEBRTC_SPL_UMUL_32_16(W_upper_MSB, *cdfPtr);
W_tmp += (W_upper_LSB * (*cdfPtr)) >> 16;
if (streamval > W_tmp) {
break;
}
}
W_lower = W_tmp;
*data++ = cdfPtr - *cdf++;
}
/* shift interval to start at zero */
W_upper -= ++W_lower;
/* add integer to bitstream */
streamval -= W_lower;
/* renormalize interval and update streamval */
/* W_upper < 2^24 */
while ( !(W_upper & 0xFF000000) )
{
/* read next byte from stream */
if (streamData->full == 0) {
streamval = (streamval << 8) | (*streamPtr++ & 0x00FF);
streamData->full = 1;
} else {
streamval = (streamval << 8) | (*streamPtr >> 8);
streamData->full = 0;
}
W_upper <<= 8;
}
}
streamData->stream_index = streamPtr - streamData->stream;
streamData->W_upper = W_upper;
streamData->streamval = streamval;
/* find number of bytes in original stream (determined by current interval width) */
if ( W_upper > 0x01FFFFFF ) {
return (streamData->stream_index*2 - 3 + !streamData->full);
} else {
return (streamData->stream_index*2 - 2 + !streamData->full);
}
}