/****************************************************************************/
/*   MPEG4 Visual Texture Coding (VTC) Mode Software                        */
/*                                                                          */
/*   This software was jointly developed by                                 */
/*   Sarnoff Coporation                   and    Texas Instruments          */
/*   Iraj Sodagar   (iraj@sarnoff.com)           Jie Liang (liang@ti.com)   */
/*   Hung-Ju Lee    (hjlee@sarnoff.com)                                     */
/*   Paul Hatrack   (hatrack@sarnoff.com)                                   */
/*   Shipeng Li     (shipeng@sarnoff.com)                                   */
/*   Bing-Bing Chai (bchai@sarnoff.com)                                     */
/*                                                                          */
/* In the course of development of the MPEG-4 standard. This software       */
/* module is an implementation of a part of one or more MPEG-4 tools as     */
/* specified by the MPEG-4 standard.                                        */
/*                                                                          */
/* The copyright of this software belongs to ISO/IEC. ISO/IEC gives use     */
/* of the MPEG-4 standard free license to use this  software module or      */
/* modifications thereof for hardware or software products claiming         */
/* conformance to the MPEG-4 standard.                                      */
/*                                                                          */
/* Those intending to use this software module in hardware or software      */
/* products are advised that use may infringe existing  patents. The        */
/* original developers of this software module and their companies, the     */
/* subsequent editors and their companies, and ISO/IEC have no liability    */
/* and ISO/IEC have no liability for use of this software module or         */
/* modification thereof in an implementation.                               */
/*                                                                          */
/* Permission is granted to MPEG memebers to use, copy, modify,             */
/* and distribute the software modules ( or portions thereof )              */
/* for standardization activity within ISO/IEC JTC1/SC29/WG11.              */
/*                                                                          */
/* Copyright (C) 1998  Sarnoff Coporation  and Texas Instruments            */ 
/****************************************************************************/

/****************************************************************************/
/*     Texas Instruments Predictive Embedded Zerotree (PEZW) Image Codec    */
/*     Copyright 1996, 1997, 1998 Texas Instruments	      		    */
/****************************************************************************/


#include <stdio.h>
#include <stdlib.h>
#include "momusys.h"
#include "PEZW_ac.h"
#include "PEZW_zerotree.h"

#define Code_value_bits 16

#define Top_value (((LInt)1<<Code_value_bits)-1)
#define First_qtr (Top_value/4+1)
#define Half	  (2*First_qtr)
#define Third_qtr (3*First_qtr)

static Void output_bit (Ac_encoder *, Int);
static Void bit_plus_follow (Ac_encoder *, Int);
static Int input_bit (Ac_decoder *);
static Void update_model (Ac_model *, Int);

#define error(m)                                           \
do  {                                                         \
  fflush (stdout);                                            \
  fprintf (stderr, "%s:%d: error: ", __FILE__, __LINE__);     \
  fprintf (stderr, m);                                        \
  fprintf (stderr, "\n");                                     \
  exit (1);                                                   \
}  while (0)

#define check(b,m)                                         \
do  {                                                         \
  if (b)                                                      \
    error (m);                                                \
}  while (0)

static Void
output_bit (Ac_encoder *ace, Int bit)
{
  ace->buffer <<=1;
  if (bit)
	  ace->buffer |= 0x01; 

  ace->bits_to_go -= 1;
  ace->total_bits += 1;
  if (ace->bits_to_go==0)  {
    if (ace->fp)
      putc (ace->buffer, ace->fp);
    else
      putc_buffer (ace->buffer, &ace->stream);

    ace->bits_to_go = 8;
	ace->buffer = 0;
  }

  return;
}

static Void
bit_plus_follow (Ac_encoder *ace, Int bit)
{
  output_bit (ace, bit);
  while (ace->fbits > 0)  {
    output_bit (ace, !bit);
    ace->fbits -= 1;
  }

  return;
}

static Int
input_bit (Ac_decoder *acd)
{
  Int t;

  if (acd->bits_to_go==0)  {
    if (acd->fp)
	acd->buffer = getc (acd->fp);
    else
	acd->buffer = getc_buffer(&acd->stream);

    acd->bits_to_go = 8;
  }

  t = ((acd->buffer&0x80)>0);
  acd->buffer <<=1; 

  acd->bits_to_go -= 1;

  return t;
}

static Void
update_model (Ac_model *acm, Int sym)
{
  Int i;

  if (acm->cfreq[0]==acm->Max_frequency)  {
    Int cum = 0;
    acm->cfreq[acm->nsym] = 0;
    for (i = acm->nsym-1; i>=0; i--)  {
      acm->freq[i] = (acm->freq[i] + 1) / 2;
      cum += acm->freq[i];
      acm->cfreq[i] = cum;
    }
  }

  acm->freq[sym] += 1;
  for (i=sym; i>=0; i--)
    acm->cfreq[i] += 1;

  return;
}

Void
Ac_encoder_init (Ac_encoder *ace, UChar *fn, Int IsStream)
{
  if (IsStream){
      ace->stream = fn;
      ace->fp = NULL;
  }
  else if (fn)  {
    ace->fp = fopen ((Char *)fn, "w");
    check (!ace->fp, "arithmetic encoder could not open file");
  }  
  else  {
    ace->fp = NULL;
  }

  ace->bits_to_go = 8;

  ace->low = 0;
  ace->high = Top_value;
  ace->fbits = 0;
  ace->buffer = 0;

  ace->total_bits = 0;

  return;
}

Void
Ac_encoder_done (Ac_encoder *ace)
{
  ace->fbits += 1;
  if (ace->low < First_qtr)
    bit_plus_follow (ace, 0);
  else
    bit_plus_follow (ace, 1);
  if (ace->fp){
    putc (ace->buffer >> ace->bits_to_go, ace->fp);
    fclose (ace->fp);
  }
 
  /* else if (ace->bits_to_go <8)
      putc_buffer (ace->buffer >> ace->bits_to_go, &ace->stream); */

  else if (ace->bits_to_go <8)
      putc_buffer (ace->buffer << ace->bits_to_go, &ace->stream);
	

  if (DEBUG_ZTR_DEC_BS)
    fprintf(stdout, "bits to go: %d  last byte: %d\n",
	    ace->bits_to_go, *(ace->stream-1));
      
  return;
}

/* NEW */
Void
Ac_decoder_open (Ac_decoder *acd, UChar *fn, Int IsStream)
{
  if (IsStream){
      acd->stream = fn;
      acd->fp = NULL;
  }
  else {
      acd->fp = fopen ((Char *)fn, "r");
      check (!acd->fp, "arithmetic decoder could not open file");
  }
 
  return;
}
/* NEW */

Void
Ac_decoder_init (Ac_decoder *acd, UChar *fn)
{
  Int i;

  acd->bits_to_go = 0;
  acd->garbage_bits = 0;

  acd->value = 0;
  for (i=1; i<=Code_value_bits; i++)  {
    acd->value = 2*acd->value + input_bit(acd);
  }
  acd->low = 0;
  acd->high = Top_value;

  return;
}

Void
Ac_decoder_done (Ac_decoder *acd)
{
  fclose (acd->fp);

  return;
}

Void
Ac_model_init (Ac_model *acm, Int nsym, Int *ifreq, Int Max_freq, Int adapt)
{
  Int i;

  acm->nsym = nsym;
  acm->freq = (Int *) (Void *) calloc (nsym, sizeof (Int));
  check (!acm->freq, "arithmetic coder model allocation failure");
  acm->cfreq = (Int *) (Void *) calloc (nsym+1, sizeof (Int));
  check (!acm->cfreq, "arithmetic coder model allocation failure");
  acm->Max_frequency = Max_freq;
  acm->adapt = adapt;

  if (ifreq)  {
    acm->cfreq[acm->nsym] = 0;
    for (i=acm->nsym-1; i>=0; i--)  {
      acm->freq[i] = ifreq[i];
      acm->cfreq[i] = acm->cfreq[i+1] + acm->freq[i];
    }


  if (acm->cfreq[0] > acm->Max_frequency)  {
    Int cum = 0;
    acm->cfreq[acm->nsym] = 0;
    for (i = acm->nsym-1; i>=0; i--)  {
      acm->freq[i] = (acm->freq[i] + 1) / 2;
      cum += acm->freq[i];
      acm->cfreq[i] = cum;
    }
  }

    if (acm->cfreq[0] > acm->Max_frequency)
      error ("arithmetic coder model max frequency exceeded");
  }  else  {
    for (i=0; i<acm->nsym; i++) {
      acm->freq[i] = 1;
      acm->cfreq[i] = acm->nsym - i;
    }
    acm->cfreq[acm->nsym] = 0;
  }

  return;
}

/* new */
Void
Ac_model_save (Ac_model *acm, Int *ifreq)
{
  Int i;

  for (i=acm->nsym-1; i>=0; i--)  {
    ifreq[i] = acm->freq[i];
  }

  return;
}

Void
Ac_model_done (Ac_model *acm)
{
  acm->nsym = 0;
  free (acm->freq);
  acm->freq = NULL;
  free (acm->cfreq);
  acm->cfreq = NULL;

  return;
}

LInt
Ac_encoder_bits (Ac_encoder *ace)
{
  return ace->total_bits;
}

Void
Ac_encode_symbol (Ac_encoder *ace, Ac_model *acm, Int sym)
{
  LInt range;
 
  check (sym<0||sym>=acm->nsym, "symbol out of range");

#ifdef AC_DEBUG
  printf(" %d ", sym);
#endif

  range = (LInt)(ace->high-ace->low)+1;
  ace->high = ace->low + (range*acm->cfreq[sym])/acm->cfreq[0]-1;
  ace->low = ace->low + (range*acm->cfreq[sym+1])/acm->cfreq[0];

  for (;;)  {
    if (ace->high<Half)  {
      bit_plus_follow (ace, 0);
    }  else if (ace->low>=Half)  {
      bit_plus_follow (ace, 1);
      ace->low -= Half;
      ace->high -= Half;
    }  else if (ace->low>=First_qtr && ace->high<Third_qtr)  {
      ace->fbits += 1;
      ace->low -= First_qtr;
      ace->high -= First_qtr;
    }  else
      break;
    ace->low = 2*ace->low;
    ace->high = 2*ace->high+1;
  }

  if (acm->adapt)
    update_model (acm, sym);

  return;
}

Int
Ac_decode_symbol (Ac_decoder *acd, Ac_model *acm)
{
  LInt range;
  Int cum;
  Int sym;

  range = (LInt)(acd->high-acd->low)+1;
  cum = (((LInt)(acd->value-acd->low)+1)*acm->cfreq[0]-1)/range;

  for (sym = 0; acm->cfreq[sym+1]>cum; sym++)
    /* do nothing */ ;

  check (sym<0||sym>=acm->nsym, "symbol out of range");

  acd->high = acd->low + (range*acm->cfreq[sym])/acm->cfreq[0]-1;
  acd->low = acd->low +  (range*acm->cfreq[sym+1])/acm->cfreq[0];

  for (;;)  {
    if (acd->high<Half)  {
      /* do nothing */
    }  else if (acd->low>=Half)  {
      acd->value -= Half;
      acd->low -= Half;
      acd->high -= Half;
    }  else if (acd->low>=First_qtr && acd->high<Third_qtr)  {
      acd->value -= First_qtr;
      acd->low -= First_qtr;
      acd->high -= First_qtr;
    }  else
      break;
    acd->low = 2*acd->low;
    acd->high = 2*acd->high+1;
    acd->value = 2*acd->value + input_bit(acd);
  }

  if (acm->adapt)
    update_model (acm, sym);

#ifdef AC_DEBUG
  printf(" %d ", sym);
#endif

  return sym;
}

Int getc_buffer (UChar **stream)
{
   Int output;
   
   output = **stream;
   (*stream)++;

   return(output);
}

Void  putc_buffer (Int input, UChar **stream)
{
    **stream = (UChar ) input;
    (*stream)++;
}


/* adjust decoder buffer pointer to the right byte */
 
Void AC_decoder_buffer_adjust (Ac_decoder *acd)
{
  if (DEBUG_ZTR_DEC_BS)
    fprintf(stdout, "bits to go: %d \n",acd->bits_to_go);

  if (acd->bits_to_go>1)
    acd->stream--;
  
  acd->stream--;

  return;
}


Void AC_free_model (Ac_model *acm)
{
  free(acm->freq);
  free(acm->cfreq);
}
