/*****************************************************************************
 *
 * This software module was originally developed by
 *
 *   Noel Brady (TELTEC IRELAND / ACTS-MoMuSys)
 *   Frank Bossen (EPFL)
 *
 * 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_decode.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_decode.h"
#include "mom_bitstream_d.h"

Void StartArDecoder(ArDecoder *decoder, Int error_res_disable, 
		    Bitstream *bitstream, Int *error_flag) {
  Int	i,j;
  
  decoder->V = 0;
  if (error_res_disable)
		{
  		decoder->nzerosf = MAXHEADING;
			decoder->mh = MAXHEADING;
			decoder->mm = MAXMIDDLE;
			decoder->mt = MAXTRAILING;
		}
	else 
		{
  		decoder->nzerosf = MAXHEADING_ER;
			decoder->mh = MAXHEADING_ER;
			decoder->mm = MAXMIDDLE_ER;
			decoder->mt = MAXTRAILING_ER;
		}
  decoder->extrabits = 0;

	/* fill the pipe while detecting and skipping any stuffed bits */

  for (i = 1; i<CODE_BITS; i++) {

   	j=BitstreamLookAheadBit(bitstream,i+decoder->extrabits); 
    decoder->V += decoder->V + j;
    if (j == 0) {
      decoder->nzerosf--;
      if (decoder->nzerosf == 0) {
	decoder->extrabits++;
	decoder->nzerosf = decoder->mm;
      }
    }
    else
      decoder->nzerosf = decoder->mm;
  }

	/* initialise the fields of the decoder */
  decoder->L = 0;
  decoder->R = HALF - 1;
	decoder->bits_to_follow = 0;
  decoder->arpipe = decoder->V;

	/* reset the fields used for bit stuffing detection */
  decoder->nzeros = decoder->mh;
  decoder->nonzero = 0;  
}

  
Void StopArDecoder(ArDecoder *decoder, Bitstream *bitstream, Trace *trace,
		   Int *error_flag) {
  Int a = decoder->L >> (CODE_BITS-3);
  Int b = (decoder->R + decoder->L) >> (CODE_BITS-3);

  Int nbits,i;

  if (b == 0) {
    b = 8;
  }
  if (b-a >= 4 || (b-a == 3 && a&1))
    nbits = 2;
  else
    nbits = 3;

  for (i = 1; i <= nbits-1; i++)
    AddNextInputBit(bitstream, decoder, trace, error_flag);	
  
  if (decoder->nzeros < decoder->mm-decoder->mt || decoder->nonzero == 0) {

		/* 	if the code ended with an illegal sequence of zeros or
				if no 1's have been encountered then it is assumed that a
      	bit has been stuffed -> skip it 
		*/

    i = BitstreamReadBits(bitstream,1,"BAC Stuffing", trace, CODE);
   
    if (i==0) {
      printf("BAC error 2\n");
      *error_flag = 1;        
    }
  }
}


Void AddNextInputBit(Bitstream *bitstream, ArDecoder *decoder, Trace *trace,
		     Int *error_flag) {
  Int i;

	/* detect cases where bits have been stuffed */

  if (((decoder->arpipe >> (CODE_BITS-2))&1) == 0) 
		{
    	decoder->nzeros--;

    	if (decoder->nzeros == 0) 
				{

				/* flush/skip one bit when a stuffed bit is detected */

      		BitstreamReadBits(bitstream,1,"BAC", trace, CODE);
  		i = BitstreamReadBits(bitstream,1,"BAC Stuffing", trace, CODE);
		if (i==0) 
		  {
		    printf("BAC error 1\n");
		    *error_flag = 1;
		    return; 
		  }
	      		decoder->extrabits--;
      		decoder->nzeros = decoder->mm;
      		decoder->nonzero = 1;
    		}
			else
  			BitstreamReadBits(bitstream,1,"BAC", trace, CODE);
  	}
  else 
		{
  		BitstreamReadBits(bitstream,1,"BAC", trace, CODE);
    	decoder->nzeros = decoder->mm;
    	decoder->nonzero = 1;
  	}


  i = (Int) BitstreamLookAheadBit(bitstream, CODE_BITS-1+decoder->extrabits);

  decoder->V += decoder->V + i;
  decoder->arpipe += decoder->arpipe + i;

  if (i == 0) {
    decoder->nzerosf--;
    if (decoder->nzerosf == 0) {
      decoder->nzerosf = decoder->mm;
      decoder->extrabits++;
    }
  }
  else
    decoder->nzerosf = decoder->mm;
}

Int ArDecodeSymbol(USInt c0, ArDecoder *decoder, Bitstream *bitstream, Trace
		   *trace, Int *error_flag) 
{
	Int bit;

	Int c1 = (1<<16) - c0;

	Int LPS = c0 > c1;
	Int cLPS = LPS ? c1 : c0;
	UInt rLPS;

	rLPS = ((decoder->R) >> 16) * cLPS;

	if ((decoder->V - decoder->L) >= (decoder->R - rLPS)) {
		bit = LPS;
		decoder->L += decoder->R - rLPS;
		decoder->R = rLPS;
	}
 	else {
		bit = (1-LPS);
		decoder->R -= rLPS;
	}

	DECODE_RENORMALISE(decoder,bitstream,trace, error_flag);

	return(bit);
}



Void DECODE_RENORMALISE(ArDecoder *decoder, Bitstream *bitstream, Trace
			*trace, Int *error_flag) 
{
	while (decoder->R < QUARTER) 
		{					
			if (decoder->L >= HALF) 
				{				
					decoder->V -= HALF;			
					decoder->L -= HALF;			
					decoder->bits_to_follow = 0;	
      	}				
      else 
				if (decoder->L + decoder->R <= HALF) decoder->bits_to_follow = 0;	
      else 
				{				
					decoder->V -= QUARTER;		
					decoder->L -= QUARTER;		
					(decoder->bits_to_follow)++;		
      	}				
      decoder->L += decoder->L;				
      decoder->R += decoder->R;				
      AddNextInputBit(bitstream, decoder,trace, error_flag);		
    }
}
