blob: 44450613c99e850147245d954cd5fe8269af8cbf [file] [log] [blame]
/*!
*************************************************************************************
* \file biariencode.c
*
* \brief
* Routines for binary arithmetic encoding
*
* \author
* Main contributors (see contributors.h for copyright, address and affiliation details)
* - Detlev Marpe <marpe@hhi.de>
* - Gabi Blaettermann <blaetter@hhi.de>
*************************************************************************************
*/
#include <stdlib.h>
#include <stdio.h>
#include "global.h"
#include "biariencode.h"
int binCount = 0;
/*!
************************************************************************
* Macro for writing bytes of code
***********************************************************************
*/
#define put_byte() { \
Ecodestrm[(*Ecodestrm_len)++] = Ebuffer; \
Ebits_to_go = 8; \
while (eep->C > 7) { \
eep->C-=8; \
eep->E++; \
} \
}
#define put_one_bit(b) { \
Ebuffer <<= 1; Ebuffer |= (b); \
if (--Ebits_to_go == 0) \
put_byte(); \
}
#define put_one_bit_plus_outstanding(b) { \
put_one_bit(b); \
while (Ebits_to_follow > 0) \
{ \
Ebits_to_follow--; \
put_one_bit(!(b)); \
} \
}
int pic_bin_count;
void reset_pic_bin_count(void)
{
pic_bin_count = 0;
}
int get_pic_bin_count(void)
{
return pic_bin_count;
}
/*!
************************************************************************
* \brief
* Allocates memory for the EncodingEnvironment struct
************************************************************************
*/
EncodingEnvironmentPtr arienco_create_encoding_environment(void)
{
EncodingEnvironmentPtr eep;
if ( (eep = (EncodingEnvironmentPtr) calloc(1,sizeof(EncodingEnvironment))) == NULL)
no_mem_exit("arienco_create_encoding_environment: eep");
return eep;
}
/*!
************************************************************************
* \brief
* Frees memory of the EncodingEnvironment struct
************************************************************************
*/
void arienco_delete_encoding_environment(EncodingEnvironmentPtr eep)
{
if (eep == NULL)
{
snprintf(errortext, ET_SIZE, "Error freeing eep (NULL pointer)");
error (errortext, 200);
}
else
free(eep);
}
/*!
************************************************************************
* \brief
* Initializes the EncodingEnvironment for the arithmetic coder
************************************************************************
*/
void arienco_start_encoding(EncodingEnvironmentPtr eep,
unsigned char *code_buffer,
int *code_len )
{
Elow = 0;
Ebits_to_follow = 0;
Ebuffer = 0;
Ebits_to_go = 9; // to swallow first redundant bit
Ecodestrm = code_buffer;
Ecodestrm_len = code_len;
Erange = HALF-2;
eep->C = 0;
eep->E = 0;
}
/*!
************************************************************************
* \brief
* Returns the number of currently written bits
************************************************************************
*/
int arienco_bits_written(EncodingEnvironmentPtr eep)
{
return (8 * (*Ecodestrm_len) + Ebits_to_follow + 8 - Ebits_to_go);
}
/*!
************************************************************************
* \brief
* Terminates the arithmetic codeword, writes stop bit and stuffing bytes (if any)
************************************************************************
*/
void arienco_done_encoding(EncodingEnvironmentPtr eep)
{
put_one_bit_plus_outstanding((unsigned char) ((Elow >> (B_BITS-1)) & 1));
put_one_bit((unsigned char) (Elow >> (B_BITS-2))&1);
put_one_bit((unsigned char) 1);
stats->bit_use_stuffingBits[img->type]+=(8-Ebits_to_go);
while (Ebits_to_go != 8)
put_one_bit(0);
pic_bin_count += eep->E*8 + eep->C; // no of processed bins
}
extern int cabac_encoding;
/*!
************************************************************************
* \brief
* Actually arithmetic encoding of one binary symbol by using
* the probability estimate of its associated context model
************************************************************************
*/
void biari_encode_symbol(EncodingEnvironmentPtr eep, signed short symbol, BiContextTypePtr bi_ct )
{
register unsigned int range = Erange;
register unsigned int low = Elow;
unsigned int rLPS = rLPS_table_64x4[bi_ct->state][(range>>6) & 3];
#if (2==TRACE)
if (cabac_encoding)
fprintf(p_trace, "%d 0x%04x %d %d\n", binCount++, Erange , bi_ct->state, bi_ct->MPS );
#endif
range -= rLPS;
bi_ct->count += cabac_encoding;
/* covers all cases where code does not bother to shift down symbol to be
* either 0 or 1, e.g. in some cases for cbp, mb_Type etc the code simply
* masks off the bit position and passes in the resulting value */
symbol = (short) (symbol != 0);
if (symbol != bi_ct->MPS)
{
low += range;
range = rLPS;
if (!bi_ct->state)
bi_ct->MPS = (unsigned char) (bi_ct->MPS ^ 0x01); // switch LPS if necessary
bi_ct->state = AC_next_state_LPS_64[bi_ct->state]; // next state
}
else
bi_ct->state = AC_next_state_MPS_64[bi_ct->state]; // next state
/* renormalisation */
while (range < QUARTER)
{
if (low >= HALF)
{
put_one_bit_plus_outstanding(1);
low -= HALF;
}
else if (low < QUARTER)
{
put_one_bit_plus_outstanding(0);
}
else
{
Ebits_to_follow++;
low -= QUARTER;
}
low <<= 1;
range <<= 1;
}
Erange = range;
Elow = low;
eep->C++;
}
/*!
************************************************************************
* \brief
* Arithmetic encoding of one binary symbol assuming
* a fixed prob. distribution with p(symbol) = 0.5
************************************************************************
*/
void biari_encode_symbol_eq_prob(EncodingEnvironmentPtr eep, signed short symbol)
{
register unsigned int low = (Elow<<1);
#if (2==TRACE)
extern int cabac_encoding;
if (cabac_encoding)
fprintf(p_trace, "%d 0x%04x\n", binCount++, Erange );
#endif
if (symbol != 0)
low += Erange;
/* renormalisation as for biari_encode_symbol;
note that low has already been doubled */
if (low >= ONE)
{
put_one_bit_plus_outstanding(1);
low -= ONE;
}
else
if (low < HALF)
{
put_one_bit_plus_outstanding(0);
}
else
{
Ebits_to_follow++;
low -= HALF;
}
Elow = low;
eep->C++;
}
/*!
************************************************************************
* \brief
* Arithmetic encoding for last symbol before termination
************************************************************************
*/
void biari_encode_symbol_final(EncodingEnvironmentPtr eep, signed short symbol)
{
register unsigned int range = Erange-2;
register unsigned int low = Elow;
#if (2==TRACE)
extern int cabac_encoding;
if (cabac_encoding)
fprintf(p_trace, "%d 0x%04x\n", binCount++, Erange);
#endif
if (symbol) {
low += range;
range = 2;
}
while (range < QUARTER)
{
if (low >= HALF)
{
put_one_bit_plus_outstanding(1);
low -= HALF;
}
else
if (low < QUARTER)
{
put_one_bit_plus_outstanding(0);
}
else
{
Ebits_to_follow++;
low -= QUARTER;
}
low <<= 1;
range <<= 1;
}
Erange = range;
Elow = low;
eep->C++;
}
/*!
************************************************************************
* \brief
* Initializes a given context with some pre-defined probability state
************************************************************************
*/
void biari_init_context (BiContextTypePtr ctx, const int* ini)
{
int pstate = iClip3 ( 1, 126, ((ini[0]* imax(0, img->currentSlice->qp)) >> 4) + ini[1]);
if ( pstate >= 64 )
{
ctx->state = (unsigned short) (pstate - 64);
ctx->MPS = 1;
}
else
{
ctx->state = (unsigned short) (63 - pstate);
ctx->MPS = 0;
}
ctx->count = 0;
}