| |
| /*! |
| ************************************************************************************* |
| * \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; |
| } |
| |