/* $Id: ztscan_enc.c,v 1.48 1998/03/16 20:36:02 hatrack Exp $ */
/****************************************************************************/
/*   MPEG4 Visual Texture Coding (VTC) Mode Software                        */
/*                                                                          */
/*   This software was 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)                                     */
/*                                                                          */
/*   and                                                                    */
/*                                                                          */
/*   Oki Electric Industry Co., Ltd.                                        */
/*   Zhixiong Wu    (sgo@hlabs.oki.co.jp)                                   */
/*   Yoshihiro Ueda (yueda@hlabs.oki.co.jp)                                 */
/*   Toshifumi Kanamaru (kanamaru@hlabs.oki.co.jp)                          */
/*                                                                          */
/* 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             */ 
/****************************************************************************/

/************************************************************/
/*     Sarnoff Very Low Bit Rate Still Image Coder          */
/*     Copyright 1995, 1996, 1997, 1998 Sarnoff Corporation */
/************************************************************/

/************************************************************/
/*  Filename: ztscan_enc.c                                  */
/*  Author: Bing-Bing Chai                                  */
/*  Date: Dec. 4, 1997                                      */
/*                                                          */
/*  Descriptions:                                           */
/*    This file contains the routines that performs         */
/*    zero tree scanning and entropy encoding.              */
/*                                                          */
/************************************************************/

#include <stdio.h>
#include <stdlib.h>
#ifndef WIN32
#include <unistd.h>
#endif
#include <ctype.h>
#include <string.h>
#include <math.h>

#include "startcode.h"
#include "dataStruct.h"
#include "states.h"
#include "globals.h"
#include "errorHandler.h"

#include "ac.h"
#include "bitpack.h"
#include "msg.h"
#include "ztscan.h"
#include "context.h"

/* definations related to arithmetic coding */
#define NUMCHAR_TYPE 4
#define NUMCHAR_SKIP_TYPE 2
#define ADAPT 1

/* Zeroth Order Model Filter - send NULL if first order (no zeroth order part)
 */
#define ZOMF(x) (mzte_codec.acm_order!=AC_MODEL_FIRST ? (x) : NULL)

/* local global variables */
static color=0,bit_stream_length;
static UChar *bitbuffer;
static COEFFINFO **coeffinfo;
static DATA **dc_coeff;
/* added by Z. Wu @ OKI for SA-prediction */
static Char **dc_mask;


/* arithmetic models related variables, refer to syntax for meaning */
static ac_encoder ace;
static ac_model acm_type, acm_vz, acm_vnz, acm_res, acm_root, acm_sign;
static ac_context acc_type, acc_vz, acc_vnz, acc_res, acc_root, acc_sign;

#ifdef _IMPLIED_SKIP_IZ_
static ac_model acm_skip_type;
static ac_context acc_skip_type;
#endif



/* functions defined in this file */
static Void cacll_encode();
static Void cachb_encode_SQ(SNR_IMAGE *snr_img);
static Void encode_pixel_SQ(Int h,Int w);
static Void  mag_sign_encode_SQ(Int h,Int w);
static Void cachb_encode_MQ(SNR_IMAGE *snr_image);
static Void encode_pixel_MQ(Int h,Int w);
static Void  mag_sign_encode_MQ(Int h,Int w);
static Void mark_ZTR_D(Int h,Int w);


/* The following functions assume that mzte_codec is a global variable */
extern WVT_CODEC mzte_codec;

#ifdef _CHECK_HI_LO_
extern File *acfp;
#endif

/*********************************************
  Initialize max frequency for each ac model
*********************************************/
Void init_acm_maxf_enc(){
  if(mzte_codec.acm_max_freq_chg ==0){
    acm_type.Max_frequency=acm_vz.Max_frequency=
      acm_vnz.Max_frequency=acm_res.Max_frequency=
      acm_root.Max_frequency=acm_sign.Max_frequency=16383;

#ifdef _IMPLIED_SKIP_IZ_
    acm_skip_type.Max_frequency=16383;
#endif
    return;
  }

  acm_type.Max_frequency=mzte_codec.acm_maxf[0];
#ifdef _IMPLIED_SKIP_IZ_
  acm_skip_type.Max_frequency=mzte_codec.acm_maxf[0];
#endif
  acm_vz.Max_frequency=mzte_codec.acm_maxf[1];
  acm_vnz.Max_frequency=mzte_codec.acm_maxf[2];
  acm_res.Max_frequency=mzte_codec.acm_maxf[3];
  acm_root.Max_frequency=mzte_codec.acm_maxf[4];
  acm_sign.Max_frequency=mzte_codec.acm_maxf[5];
}

/******************************************************************/
/****************************  DC  ********************************/
/******************************************************************/

/*******************************************************/
/**************  Forward DC Prediction  ****************/
/*******************************************************/

/********************************************************
  Function Name
  -------------
  static DATA DC_pred_pix(int i, int j)

  Arguments
  ---------
  int i, int j: Index of wavelet coefficient (row, col)
  
  Description
  -----------
  DPCM prediction for a DC coefficient, refer to syntax
  for algorithm. 

  Functions Called
  ----------------
  None.

  Return Value
  ------------
    prediction for coeffinfo[i][j].quantized_value
********************************************************/ 
static DATA DC_pred_pix(Int i, Int j)
{
  /*  modified by Z. Wu @ OKI */
  Int pred_i, pred_j, pred_d;

  if ( i==0 || dc_mask[i-1][j] == 0 ) 
    pred_i = 0;
  else	
    pred_i = dc_coeff[i-1][j];

  if ( j==0 || dc_mask[i][j-1] == 0 ) 
    pred_j = 0;
  else 	
    pred_j = dc_coeff[i][j-1];

  if ( i==0 || j== 0 || dc_mask[i-1][j-1] == 0 )
    pred_d = 0;
  else
    pred_d = dc_coeff[i-1][j-1];
  
  if ( abs(pred_d-pred_j) < abs(pred_d-pred_i))	
    return(pred_i);
  else
    return(pred_j);

}



/*****************************************************
  Function Name
  -------------
  Void DC_predict()

  Arguments
  ---------
  None
  
  Description
  -----------
  control program for DC prediction

  Functions Called
  ----------------
  DC_pred_pix(i,j).

  Return Value
  ------------
  none
******************************************************/

static Void DC_predict(Int color)
{
  Int i,j,dc_h,dc_w,offset_dc,max_dc;

  dc_h=mzte_codec.dcHeight;
  dc_w=mzte_codec.dcWidth;

  dc_coeff=(DATA **)calloc(dc_h,sizeof(DATA *));
  for(i=0;i<dc_h;i++)
    dc_coeff[i]=(DATA *)calloc(dc_w,sizeof(DATA));

  dc_mask=(Char **)calloc(dc_h,sizeof(Char *));
  for(i=0;i<dc_h;i++)
    dc_mask[i]=(Char *)calloc(dc_w,sizeof(Char));


  coeffinfo=mzte_codec.SPlayer[color].coeffinfo;

  for(i=0;i<dc_h;i++)
    for(j=0;j<dc_w;j++) {
      dc_coeff[i][j]=coeffinfo[i][j].quantized_value;
      dc_mask [i][j]=coeffinfo[i][j].mask;
    }

  /* prediction */    
  offset_dc=0;
	
  for(i=0;i<dc_h;i++)
    for(j=0;j<dc_w;j++){
      if ( dc_mask[i][j] != 0 ) {
	if(offset_dc>(coeffinfo[i][j].quantized_value-=DC_pred_pix(i,j)))
	  offset_dc=coeffinfo[i][j].quantized_value;
      }
    }

  if(offset_dc>0)
    offset_dc=0;

  /* adjust coeff's by offset_dc */
  max_dc=0;
  for(i=0;i<dc_h;i++)
    for(j=0;j<dc_w;j++){
      if ( dc_mask[i][j] != 0 ) {
	coeffinfo[i][j].quantized_value -=offset_dc;
	/* find max_dc */
	if (max_dc<coeffinfo[i][j].quantized_value)
	  max_dc=coeffinfo[i][j].quantized_value;
      }
    }
    
  mzte_codec.offset_dc=offset_dc;
  mzte_codec.max_dc=max_dc;  /* hjlee */
  noteDebug("DC pred: offset=%d, max_dc=%d",
	    mzte_codec.offset_dc,mzte_codec.max_dc);  

  for(i=0;i<dc_h;i++) {
    free(dc_coeff[i]);
    free(dc_mask[i]);
  }
  free(dc_coeff);
  free(dc_mask);
}




/********************************************************
  Function Name
  -------------
  Void wavelet_dc_encode(Int c)


  Arguments
  ---------
  int c - color component.
  
  Description
  -----------
  Control program for encode DC information for one 
  color component.

  Functions Called
  ----------------
  None.
  DC_predict()
  put_param()
  cacll_encode()
  
  Return Value
  ------------
  None.

********************************************************/ 
Void wavelet_dc_encode(Int c)
{

  noteDetail("Encoding DC (wavelet_dc_encode)....");
  color=c;

  emit_bits((UShort)mzte_codec.mean[color], 8);
  put_param((UShort)mzte_codec.Qdc[color], 7);
  /* emit_bits(mzte_codec.Qdc[color], 8); */

  DC_predict(color);
  put_param(-mzte_codec.offset_dc,7);
  /* put_param(mzte_codec.max_dc,7); */
  put_param(mzte_codec.max_dc+mzte_codec.offset_dc,7);  /* hjlee */
  
#ifdef _CHECK_HI_LO_
  acfp=fopen("encode_hl.dat","w");
#endif

  cacll_encode();
  noteDetail("Completed encoding DC.");

#ifdef _CHECK_HI_LO_
  fclose(acfp);
#endif

}



/********************************************************
  Function Name
  -------------
  static Void cacll_encode()

  Arguments
  ---------
  None.

  
  Description
  -----------
  Encode DC information for one color component.

  Functions Called
  ----------------
  ac_encoder_init()
  ac_model_init()
  ac_encode_symbol()
  ac_model_done()
  ac_encoder_done()

  Return Value
  ------------
  None.

********************************************************/ 
static Void cacll_encode()
{
  Int dc_h, dc_w,i,j;

  dc_w=mzte_codec.dcWidth;
  dc_h=mzte_codec.dcHeight;

  /* init arithmetic coder */
  ac_encoder_init(&ace,NULL,bitbuffer);

  if (mzte_codec.acm_order!=AC_MODEL_FIRST)
    ac_model_init(&acm_vz,mzte_codec.max_dc+1,
		  NULL,ADAPT,1);
  if (mzte_codec.acm_order!=AC_MODEL_ZEROTH)
    initContext_VZ(&acc_vz, mzte_codec.max_dc+1);

  coeffinfo=mzte_codec.SPlayer[color].coeffinfo;
  for(i=0;i<dc_h;i++)
    for(j=0;j<dc_w;j++){

#ifdef _CHECK_HI_LO_
      fprintf(acfp,"%3d, %3d: %7d %7d\n",i,j,ace.high,ace.low);
#endif
	  if( coeffinfo[i][j].mask == 1) 
	  {
	      ac_encode_symbol(&ace,ZOMF(&acm_vz),contextToModel_VZ(&acc_vz),
                   coeffinfo[i][j].quantized_value);
	      updateContext_VZ(&acc_vz, coeffinfo[i][j].quantized_value);
	  }
    }

  /* close arithmetic coder */
  if (mzte_codec.acm_order!=AC_MODEL_FIRST)
    ac_model_done(&acm_vz);
  if (mzte_codec.acm_order!=AC_MODEL_ZEROTH)
    freeContext_VZ(&acc_vz);

  bit_stream_length=ac_encoder_done(&ace,&bitbuffer);
}



/*********************************************************************/
/*****************************  AC  **********************************/
/*************************  Single quant  ****************************/
/*********************************************************************/

/********************************************************
  Function Name
  -------------
  Void wavelet_higher_bands_encode_SQ(int c)

  Arguments
  ---------
  int c - color component.
  
  Description
  -----------
  Control program for encoding AC information for one 
  color component. Single quant mode.

  Functions Called
  ----------------
  put_param()
  cachb_encode_SQ()

  Return Value
  ------------
  None.

********************************************************/ 
Void wavelet_higher_bands_encode_SQ(Int c)
{
  SNR_IMAGE *snr_image;

  noteDetail("Encoding AC (wavelet_higher_bands_encode_SQ)....");
  color =c;
  snr_image=&(mzte_codec.SPlayer[color].SNRlayer.snr_image);

  /* header info */
  put_param(snr_image->root_max,7);
  emit_bits(MARKER_BIT, 1);
  put_param(snr_image->valz_max,7);
  put_param(snr_image->valnz_max,7);

  cachb_encode_SQ(snr_image);
  noteDetail("Completed encoding AC.");
}


static Int height,width;

/********************************************************
  Function Name
  -------------
  static Void cachb_encode_SQ(SNR_IMAGE *snr_img)

  Arguments
  ---------
  SNR_IMAGE *snr_img - structure containing one color
                       component of an SNR image
  Description
  -----------
  Encode AC information for one color component. 
  Single quant mode, tree-depth scan

  Functions Called
  ----------------
  ac_encoder_init()
  ac_model_init()
  encode_pixel_SQ()
  ac_model_done()
  ac_encoder_done()

  Return Value
  ------------
  None.

********************************************************/ 
static Void cachb_encode_SQ(SNR_IMAGE *snr_img)
{
  Int h,w,dc_h,dc_w,dc_h2,dc_w2;

  dc_h=mzte_codec.dcHeight;
  dc_w=mzte_codec.dcWidth;
  dc_h2=dc_h<<1;
  dc_w2=dc_w<<1;
  height=mzte_codec.Image[color].height;
  width=mzte_codec.Image[color].width;

  /* init arithmetic coder */
  ac_encoder_init(&ace,NULL,bitbuffer);

  if (mzte_codec.acm_order!=AC_MODEL_FIRST)
  {
    ac_model_init(&acm_type,NUMCHAR_TYPE,NULL,ADAPT,1);
    if (snr_img->root_max)
      ac_model_init(&acm_root,snr_img->root_max,NULL,ADAPT,1);
    ac_model_init(&acm_vz,snr_img->valz_max+1,NULL,ADAPT,1);
    if (snr_img->valnz_max)
      ac_model_init(&acm_vnz,snr_img->valnz_max,NULL,ADAPT,1);
    ac_model_init(&acm_sign,2,NULL,ADAPT,1);
  }
  if (mzte_codec.acm_order!=AC_MODEL_ZEROTH)
  {
    initContext_Type(&acc_type, NUMCHAR_TYPE);
    if (snr_img->root_max)
      initContext_Root(&acc_root, snr_img->root_max);
    initContext_VZ(&acc_vz, snr_img->valz_max+1);
    if (snr_img->valnz_max)
      initContext_VNZ(&acc_vnz, snr_img->valnz_max);
    initContext_Sign(&acc_sign, 2);
  }

  coeffinfo=mzte_codec.SPlayer[color].coeffinfo;

  
  for(h=0;h<dc_h;h++)
    for(w=dc_w;w<dc_w2;w++){
      encode_pixel_SQ(h,w);           /* LH */
      encode_pixel_SQ(h+dc_h,w-dc_w); /* HL */
      encode_pixel_SQ(h+dc_h,w);      /* HH */
    }

  
  /* close arithmetic coder */
  if (mzte_codec.acm_order!=AC_MODEL_FIRST)
  {
    ac_model_done(&acm_type);
    if (snr_img->root_max)
      ac_model_done(&acm_root);
    ac_model_done(&acm_vz);
    if (snr_img->valnz_max)
      ac_model_done(&acm_vnz);
    ac_model_done(&acm_sign);
  }
  if (mzte_codec.acm_order!=AC_MODEL_ZEROTH)
  {
    freeContext_Type(&acc_type);
    if (snr_img->root_max)
      freeContext_Root(&acc_root);
    freeContext_VZ(&acc_vz);
    if (snr_img->valnz_max)
      freeContext_VNZ(&acc_vnz);
    freeContext_Sign(&acc_sign);
  }

  bit_stream_length=ac_encoder_done(&ace,&bitbuffer);
}



/********************************************************
  Function Name
  -------------
  static Void encode_pixel_SQ(int h,int w)

  Arguments
  ---------
  int h,int w - position of a pixel in height and width
  
  Description
  -----------
  Encoding the type and/or value of a coefficient, a
  recursive function.

  Functions Called
  ----------------
  mag_sign_encode_SQ()
  ac_encode_symbol()
  encode_pixel_SQ()

  Return Value
  ------------
  None.

********************************************************/ 
static Void encode_pixel_SQ(Int h,Int w)
{
  Int i,j;
  UChar zt_type;


  /* code leave coefficients, value only, no type */
  if(coeffinfo[h][w].state == S_LEAF){
#ifdef _SHAPE_ /* skip out-node */
    if(coeffinfo[h][w].mask == 1) 
#endif
      mag_sign_encode_SQ(h,w);
    return;
  }
 
  /* code zerotree symbol */
#ifdef _SHAPE_ /* skip out-node */
  if(coeffinfo[h][w].mask == 1) 
#endif
  {
    ac_encode_symbol(&ace,ZOMF(&acm_type),contextToModel_Type(&acc_type),
		     zt_type=coeffinfo[h][w].type);
    updateContext_Type(&acc_type, zt_type);
  }
#ifdef _SHAPE_
  else
    zt_type=coeffinfo[h][w].type;
#endif
  /* code magnitude and sign */
  /* For Arbitrary-Shape, out-node will always has zero coefficient,
     so only IZ or ZTR may be the zt_type -- SL*/

  switch(zt_type){
    case IZ : 
      break; /* will code the four children */
    case VZTR:
      mag_sign_encode_SQ(h,w);
    case ZTR:
#ifdef _SHAPE_
      if(coeffinfo[h][w].mask != 1) /* TBE for four children of out-node */ 
	break;
      else
#endif
     {
#ifdef _WRITE_COEFF_MAP_
      mark_ZTR_D(h,w);  /* not necessary, only for checking purpose */
#endif /*_WRITE_COEFF_MAP_*/
      return;
      }
    case VAL:
      mag_sign_encode_SQ(h,w);
      break;
    default: 
      errorHandler("invalid zerotree symbol in single quant encode");
  }

  /* scan children */
  i=h<<1; j=w<<1;
  encode_pixel_SQ(i,j);
  encode_pixel_SQ(i,j+1);
  encode_pixel_SQ(i+1,j);
  encode_pixel_SQ(i+1,j+1);
}


     
/********************************************************
  Function Name
  -------------
  static Void  mag_sign_encode_SQ(int h,int w)

  Arguments
  ---------
  int h,int w - position of a pixel

  Description
  -----------
  Encode the value of a coefficient.

  Functions Called
  ----------------
  ac_encode_symbol()

  Return Value
  ------------
  None.

********************************************************/ 
static Void  mag_sign_encode_SQ(Int h,Int w)
{
  Int val,v_sign;

  if((val=coeffinfo[h][w].quantized_value)>0)
    v_sign=0;
  else{
    val=-val;
    v_sign=1;
  }
  
  switch(stateToProbModel[coeffinfo[h][w].state]){    
    case ACM_ROOT:
      ac_encode_symbol(&ace,ZOMF(&acm_root),contextToModel_Root(&acc_root),
		       val-1);
      updateContext_Root(&acc_root, val-1);
      break;
    case ACM_VALNZ:
      ac_encode_symbol(&ace,ZOMF(&acm_vnz),contextToModel_VNZ(&acc_vnz),val-1);
      updateContext_VNZ(&acc_vnz, val-1);
      break;
    case ACM_VALZ:
      ac_encode_symbol(&ace,ZOMF(&acm_vz),contextToModel_VZ(&acc_vz),val);
      updateContext_VZ(&acc_vz, val);
      if(val==0)
        return;
      break;
    default:
      errorHandler("not a valid magnitude type in encode_pixel_SQ");
  }
  ac_encode_symbol(&ace,ZOMF(&acm_sign),contextToModel_Sign(&acc_sign),v_sign);
  updateContext_Sign(&acc_sign, v_sign);
}



/*********************************************************************/
/******************************  AC  *********************************/
/**************************  Multi quant  ****************************/
/*********************************************************************/

/********************************************************
  Function Name
  -------------
  Void wavelet_higher_bands_encode_MQ(SNR_IMAGE *snr_image,int c)

  Arguments
  ---------
  SNR_IMAGE *snr_image - structure containing one color
                         component of an SNR image
  int c - color component.
  
  Description
  -----------
  Control program for encoding AC information for one 
  color component. Multi quant mode.

  Functions Called
  ----------------
  put_param()
  cachb_encode_MQ()

  Return Value
  ------------
  None.

********************************************************/ 
Void wavelet_higher_bands_encode_MQ(SNR_IMAGE *snr_image,Int c)
{
  noteDetail("Encoding AC (wavelet_higher_bands_encode_MQ)....");
  /* header info */
  put_param(snr_image->root_max,7);
  emit_bits(MARKER_BIT, 1);
  put_param(snr_image->valz_max,7);
  put_param(snr_image->valnz_max,7);
  color=c;
  coeffinfo=mzte_codec.SPlayer[color].coeffinfo;

  cachb_encode_MQ(snr_image);
}



/********************************************************
  Function Name
  -------------
  static Void mark_ZTR_D(int h,int w)

  Arguments
  ---------
  int h,int w - position of a pixel

  
  Description
  -----------
  Mark the coefficient at (h,w) and its descendents as
  zerotree descendents. 

  Functions Called
  ----------------
  mark_ZTR_D()


  Return Value
  ------------
  None.

********************************************************/ 
static Void mark_ZTR_D(Int h,Int w)
{
  Int i,j;

  i=h<<1; j=w<<1;

  if(i<height && j<width){
    coeffinfo[i][j].type     = ZTR_D;
    coeffinfo[i+1][j].type   = ZTR_D; 
    coeffinfo[i][j+1].type   = ZTR_D; 
    coeffinfo[i+1][j+1].type = ZTR_D; 
    mark_ZTR_D(i,j);
    mark_ZTR_D(i+1,j);
    mark_ZTR_D(i,j+1);
    mark_ZTR_D(i+1,j+1);
  }
}



/********************************************************
  Function Name
  -------------
  static Void cachb_encode_MQ(SNR_IMAGE *snr_img)

  Arguments
  ---------
  SNR_IMAGE *snr_img - structure containing one color
                       component of an SNR image 
  Description
  -----------
  Encode AC information for one color component. 
  Multiple quant, bandwise scan.

  Functions Called
  ----------------
  ac_encoder_init()
  ac_model_init()
  clear_ZTR_D();
  encode_pixel_MQ()
  ac_model_done()
  ac_encoder_done()

  Return Value
  ------------
  None.

********************************************************/ 
static Void cachb_encode_MQ(SNR_IMAGE *snr_image)
{
  Int h,w,ac_h,ac_w,ac_h2,ac_w2;

  /* ac_h, ac_w init */
  ac_h=mzte_codec.dcHeight;
  ac_w=mzte_codec.dcWidth;
  ac_h2=ac_h<<1;
  ac_w2=ac_w<<1;
  height=mzte_codec.SPlayer[color].height;
  width=mzte_codec.SPlayer[color].width;

  /* init arithmetic coder */
  ac_encoder_init(&ace,NULL,bitbuffer);

  if (mzte_codec.acm_order!=AC_MODEL_FIRST)
  {
    ac_model_init(&acm_type,NUMCHAR_TYPE,NULL,ADAPT,1);
#ifdef _IMPLIED_SKIP_IZ_
    ac_model_init(&acm_skip_type,NUMCHAR_SKIP_TYPE,NULL,ADAPT,1);
#endif
    if (snr_image->root_max)
      ac_model_init(&acm_root,snr_image->root_max,NULL,ADAPT,1);
    ac_model_init(&acm_vz,snr_image->valz_max+1,NULL,ADAPT,1);
    if (snr_image->valnz_max)
      ac_model_init(&acm_vnz,snr_image->valnz_max,NULL,ADAPT,1);
    ac_model_init(&acm_res,snr_image->residual_max+1,NULL,ADAPT,1);
    ac_model_init(&acm_sign,2,NULL,ADAPT,1);
  }
  if (mzte_codec.acm_order!=AC_MODEL_ZEROTH)
  {
    initContext_Type(&acc_type, NUMCHAR_TYPE);
#ifdef _IMPLIED_SKIP_IZ_
    initContext_SkipType(&acc_skip_type, NUMCHAR_SKIP_TYPE);
#endif
    if (snr_image->root_max)
      initContext_Root(&acc_root, snr_image->root_max);
    initContext_VZ(&acc_vz, snr_image->valz_max+1);
    if (snr_image->valnz_max)
      initContext_VNZ(&acc_vnz, snr_image->valnz_max);
    initContext_Res(&acc_res, snr_image->residual_max+1);
    initContext_Sign(&acc_sign, 2);
  }
  
  /* clear the ZTR_D type from the previous pass */
  clear_ZTR_D();


  /* scan each coefficients in the spatial layer */
  while(ac_h2<=height && ac_w2<=width){

    /* LH */
    for(h=0;h<ac_h;h++)
      for(w=ac_w;w<ac_w2;w++)
        encode_pixel_MQ(h,w);

    /* HL */
    for(h=ac_h;h<ac_h2;h++)
      for(w=0;w<ac_w;w++)
        encode_pixel_MQ(h,w);

    /* HH */
    for(h=ac_h;h<ac_h2;h++)
      for(w=ac_w;w<ac_w2;w++)
        encode_pixel_MQ(h,w);

    /* update ranges */
    ac_h=ac_h2;
    ac_w=ac_w2;
    ac_w2<<=1;
    ac_h2 <<=1;
  }

  /* close arithmetic coder */
  if (mzte_codec.acm_order!=AC_MODEL_FIRST)
  {
    ac_model_done(&acm_type);
#ifdef _IMPLIED_SKIP_IZ_
    ac_model_done(&acm_skip_type);
#endif
    if (snr_image->root_max)
      ac_model_done(&acm_root);
    ac_model_done(&acm_vz);
    if (snr_image->valnz_max)
      ac_model_done(&acm_vnz);
    ac_model_done(&acm_res);
    ac_model_done(&acm_sign);
  }
  if (mzte_codec.acm_order!=AC_MODEL_ZEROTH)
  {
    freeContext_Type(&acc_type);
#ifdef _IMPLIED_SKIP_IZ_
    freeContext_SkipType(&acc_skip_type);
#endif
    if (snr_image->root_max)
      freeContext_Root(&acc_root);
    freeContext_VZ(&acc_vz);
    if (snr_image->valnz_max)
      freeContext_VNZ(&acc_vnz);
    freeContext_Res(&acc_res);
    freeContext_Sign(&acc_sign);
  }

  bit_stream_length=ac_encoder_done(&ace,&bitbuffer);
}




/********************************************************
  Function Name
  -------------
  static Void encode_pixel_MQ(int h,int w)

  Arguments
  ---------
  int h,int w - position of a pixel in height and width
  
  Description
  -----------
  Encoding the type and/or value of a coefficient, a
  recursive function, multi quant mode.

  Functions Called
  ----------------
  ac_encode_symbol()
  mark_ZTR_D()
  mag_sign_encode_MQ()
 
  Return Value
  ------------
  None.

********************************************************/ 
static Void encode_pixel_MQ(Int h,Int w)
{
  Int zt_type;

#ifdef _CHECK_HI_LO_
  fprintf(acfp,"%3d, %3d: %7d %7d\n",h,w,ace.high,ace.low);
#endif

  /* zerotree descendent */
  if(coeffinfo[h][w].type==ZTR_D)
    return;

  /* encode zero tree symbol */
  
  if (coeffinfo[h][w].state == S_LEAF || coeffinfo[h][w].state == S_RLEAF
      || (coeffinfo[h][w].state == S_RVAL && coeffinfo[h][w].skip==0))
  {
    zt_type = VAL;

#ifdef _WRITE_COEFF_MAP_
    if (coeffinfo[h][w].state == S_RVAL && coeffinfo[h][w].skip==0) 
      coeffinfo[h][w].type = VAL;
#endif /*_WRITE_COEFF_MAP_*/
  }

  else
  {
    zt_type=coeffinfo[h][w].type;
#ifdef _SHAPE_
    if(coeffinfo[h][w].mask==1) /* skip out-node */  
#endif
    {

#ifdef _IMPLIED_SKIP_IZ_
      if (coeffinfo[h][w].skip==SKIP_IZ)
        zt_type=coeffinfo[h][w].type=IZ;
      else if (coeffinfo[h][w].skip)
      {
        ac_encode_symbol(&ace,ZOMF(&acm_skip_type),
                         contextToModel_SkipType(&acc_skip_type),
                         (zt_type==IZ)?IZ:(ZTR-1));
        updateContext_SkipType(&acc_skip_type, zt_type);
      }
      else
#endif

      {
	ac_encode_symbol(&ace,ZOMF(&acm_type),contextToModel_Type(&acc_type),
			 zt_type);
	updateContext_Type(&acc_type, zt_type);
      }
    }
  }


  /* mark ztr_d and encode magnitudes */
  switch(zt_type){
    case ZTR:
#ifdef _SHAPE_
      if(coeffinfo[h][w].mask==1) /* mark ZTR-D for in-node root */
#endif
      mark_ZTR_D(h,w);
    case IZ:
      return;
    case VZTR:
      mark_ZTR_D(h,w);
    case VAL:
    case VLEAF:
    case ZLEAF:
#ifdef _SHAPE_
      if(coeffinfo[h][w].mask==1) /* only code for in-node*/
#endif
      mag_sign_encode_MQ(h,w);
      break;
    default:
      errorHandler("Invalid type in multi quant decoding.");     
  }

}




        
/********************************************************
  Function Name
  -------------
  static Void  mag_sign_encode_MQ(Int h,int w)

  Arguments
  ---------
  int h,int w - position of a pixel

  Description
  -----------
  Encode the value of a coefficient.

  Functions Called
  ----------------
  ac_encode_symbol()

  Return Value
  ------------
  None.

********************************************************/ 
 static Void  mag_sign_encode_MQ(Int h,Int w)
{
  Int val,v_sign,ac_model;

  if(coeffinfo[h][w].skip)
    return;

  ac_model=stateToProbModel[coeffinfo[h][w].state];

  if((val=coeffinfo[h][w].quantized_value)>=0)
    v_sign=0;
  else{
    val=-val;
    v_sign=1;
  }
  
  /* code magnitude */
  switch(ac_model){
    case ACM_ROOT:  /* smallest three AC bands */
      ac_encode_symbol(&ace,ZOMF(&acm_root),contextToModel_Root(&acc_root),
		       val-1);
      updateContext_Root(&acc_root, val-1);
      break;
    case ACM_VALNZ:
      ac_encode_symbol(&ace,ZOMF(&acm_vnz),contextToModel_VNZ(&acc_vnz),val-1);
      updateContext_VNZ(&acc_vnz, val-1);
      break;
    case ACM_VALZ:     /* leaf */
      ac_encode_symbol(&ace,ZOMF(&acm_vz),contextToModel_VZ(&acc_vz),val);
      updateContext_VZ(&acc_vz, val);     
      if(val == 0)
        return;
     break;
    case ACM_RESID:  /* refinement, no sign */
      ac_encode_symbol(&ace,ZOMF(&acm_res),contextToModel_Res(&acc_res),val);
      updateContext_Res(&acc_res, val);
      return;
    default:
      errorHandler("In coefficient (%d,%d). Invalid model (=%d) in "
		   "encode_pixel_MQ.",h,w,ac_model);
  }
  
  ac_encode_symbol(&ace,ZOMF(&acm_sign),contextToModel_Sign(&acc_sign),v_sign);
  updateContext_Res(&acc_sign, v_sign);
}







