/******************************************************************************
 *                                                                          
 * This software module was originally developed by 
 *
 * Noel Brady (TELTEC IRELAND / ACTS-MoMuSys). 
 *
 * in the course of development of the MPEG-4 Video (ISO/IEC 14496-2) standard.
 * This software module is an implementation of a part of one or more MPEG-4 
 * Video (ISO/IEC 14496-2) tools as specified by the MPEG-4 Video (ISO/IEC 
 * 14496-2) standard. 
 *
 * ISO/IEC gives users of the MPEG-4 Video (ISO/IEC 14496-2) standard free 
 * license to this software module or modifications thereof for use in hardware
 * or software products claiming conformance to the MPEG-4 Video (ISO/IEC 
 * 14496-2) standard. 
 *
 * Those intending to use this software module in hardware or software products
 * are advised that its use may infringe existing patents. The original 
 * developer of this software module and his/her company, the subsequent 
 * editors and their companies, and ISO/IEC have no liability for use of this 
 * software module or modifications thereof in an implementation. Copyright is 
 * not released for non MPEG-4 Video (ISO/IEC 14496-2) standard conforming 
 * products. 
 *
 * ACTS-MoMuSys partners retain full right to use the code for his/her own 
 * purpose, assign or donate the code to a third party and to inhibit third 
 * parties from using the code for non MPEG-4 Video (ISO/IEC 14496-2) standard
 * conforming products. This copyright notice must be included in all copies or
 * derivative works. 
 *
 * Copyright (c) 1997
 *
 *****************************************************************************/



/***********************************************************HeaderBegin*******
 *                                                                         
 * File:	bin_ar_code.c
 *
 * Author:	Noel Brady Teltec Irl.
 *		Adapted from C++ source written by Frank Bossen, EPFL
 *
 * Created:	29-07-96
 *                                                                         
 * Description: 
 *		This file contains functions implementing a binary 
 *		arithmetic encoder and decoder.
 *
 * Notes: 	
 *
 * Modified:
 * 
 ***********************************************************HeaderEnd*********/

/************************    INCLUDE FILES    ********************************/

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "momusys.h"
#include "bin_ar_code.h"
#include "mom_bitstream_i.h"


/* encoding functions first */

/* START ENCODING A STREAM OF SYMBOLS */

Void StartArCoder(ArCoder *coder, Int error_res_disable) {
  coder->L = 0;
  coder->R = HALF-1;
  coder->bits_to_follow = 0;
  coder->first_bit = 1;
  coder->nonzero = 0;
	if (error_res_disable)
		{
  		coder->nzeros = MAXHEADING;
			coder->mh = MAXHEADING;
			coder->mm = MAXMIDDLE;
			coder->mt = MAXTRAILING;
		}
	else
		{
  		coder->nzeros = MAXHEADING_ER;
			coder->mh = MAXHEADING_ER;
			coder->mm = MAXMIDDLE_ER;
			coder->mt = MAXTRAILING_ER;
		}
}

/* FINISH ENCODING THE STREAM */

Void StopArCoder(ArCoder *coder, Image *bitstream) {
  Int a = (coder->L) >> (CODE_BITS-3);
  Int b = (coder->R + coder->L) >> (CODE_BITS-3);

  Int nbits, bits, i;

  if (b == 0)
    b = 8;

  if (b-a >= 4 || (b-a == 3 && a&1)) {
    nbits = 2;
    bits = (a>>1) + 1;
  }
  else {
    nbits = 3;
    bits = a + 1;
  }
  
  for (i = 1; i <= nbits; i++)
    BitPlusFollow(((bits >> (nbits-i)) & 1), coder, bitstream);
  
  if (coder->nzeros < coder->mm-coder->mt || coder->nonzero == 0) {
    BitPlusFollow(1, coder, bitstream);
  }
}

/* OUTPUT BITS PLUS FOLLOWING OPPOSITE BITS */

Void BitByItself(Int bit, ArCoder *coder, Image* bitstream) {
  BitstreamPutBit(bitstream,bit);			/* Output the bit */
  if (bit == 0) {
    coder->nzeros--;
    if (coder->nzeros == 0) {
      BitstreamPutBit(bitstream,1);
      coder->nonzero = 1;
      coder->nzeros = coder->mm;
    }
  }
  else {
    coder->nonzero = 1;
    coder->nzeros = coder->mm;
  }
}

Void BitPlusFollow(Int bit, ArCoder *coder, Image *bitstream)
{
  if (!coder->first_bit)
    BitByItself(bit, coder, bitstream);
  else
    coder->first_bit = 0;
  while ((coder->bits_to_follow) > 0) {
    BitByItself(!bit, coder, bitstream);
    coder->bits_to_follow -= 1;
  }
}


/* ENCODE A BINARY SYMBOL */

Void ArCodeSymbol(Int bit, USInt c0, ArCoder *coder, Image *bitstream) 
{
  Int c1 = (1<<16) - c0;
  
  Int LPS = (c0 > c1);
  USInt cLPS = (LPS) ? c1 : c0;
  
  UInt rLPS;
  
  rLPS = ((coder->R) >> 16) * cLPS;
  
  if (bit == LPS) {
    coder->L += coder->R - rLPS;
    coder->R = rLPS;
  }
  else
    coder->R -= rLPS;
  
  ENCODE_RENORMALISE(coder,bitstream);
}


Void ENCODE_RENORMALISE(ArCoder *coder, Image *bitstream) 
{
  while (coder->R < QUARTER) {					 
    if (coder->L >= HALF) {				 
      BitPlusFollow(1,coder,bitstream);		 
      coder->L -= HALF;			 
    }				 
    else 
      if (coder->L+coder->R <= HALF) BitPlusFollow(0,coder,bitstream);
      else {				 
	coder->bits_to_follow++;		 
	coder->L -= QUARTER;		 
      }				 
    coder->L += coder->L;				 
    coder->R += coder->R;				 
  }
}



