/******************************************************************************
 *                                                                          
 * This software module was originally developed by 
 *
 * Robert Danielsen (Telenor / ACTS-MoMuSys). 	    	              	
 *
 * and edited by 
 *
 * Cor Quist (KPN / ACTS-MoMuSys).     			              	
 * Minhua Zhou (HHI / ACTS-MoMuSys).   	  	 	              	
 * Luis Ducla-Soares (IST / ACTS-MoMuSys)
 * Minhua Zhou (HHI / ACTS-MoMuSys)
 * Bob Eifrig (NextLevel Systems).     	           	   	
 * Michael Frater (UNSW)
 *
 * 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:	text_bits.c
 *
 * Author:	Telenor (tmn) 
 * Created:	
 *                                                                         
 * Description:	texture encoding   
 *
 * Notes: 	
 *
 * Modified:  	
 *      14.02.96 Robert Danielsen
 *	12.04.96 Cor Quist 
 *      21.04.96 Robert Danielsen: Reformatted. New headers.
 *	07.06.96 Robert Danielsen: Changed from using Encode to Putxxx
 *		 instead, based on new VLC encoding scheme.
 *      03.09.96 Cor Quist: removed OLDINTRADC flag, added intradc_pred_disable   *               variable.
 *	23.10.96 Robert Danielsen: Changed Bits_CountCoeff(), also changed
 *		 the name to MB_CodeCoeff().
 *      30.04.97 Luis Ducla-Soares: Added CodeCoeff_RVLC and made changes to
 *                                  MB_CodeCoeff() to allow error resilient 
 *                                  combined mode with data partitioning.
 *      04.01.98 Michael Frater: marker bit for DC coeffs longer than 8 bits
 *
 ***********************************************************HeaderEnd*********/

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

#include "momusys.h"
#include "text_defs.h"
#include "mom_bitstream_i.h"
#include "text_bits.h"
#include "putvlc.h"
#include "text_util.h"
#include "zigzag.h"		/* added, 14-NOV-1996 MW */
#include "max_level.h"          /* 3-mode esc */
 
/***********************************************************CommentBegin******
 *
 * -- MB_CodeCoeff -- Codes coefficients, does DC/AC prediction
 *
 * Author :
 *	Originally Bits_CountCoeff by Cor Quist (KPN),
 *	Name and contents changed by RobertDanielsen@nta.no
 *
 * Created :		
 *	23.10.96
 *
 * Purpose :		
 *	Codes coefficients, does DC/AC prediction
 * 
 * Arguments in : 	
 *	Int *qcoeff : quantized dct-coefficients
 * 	Int Mode : encoding mode
 * 	Int CBP : coded block pattern
 * 	Int ncoeffs : number of coefficients per block
 * 	Int x_pos : the horizontal position of the macroblock in the vop
 *      Int intra_dcpred_disable : disable the intradc prediction
 *	Int transp_pattern[]:	Describes which blocks are transparent
 *
 * Arguments in/out :	
 *	
 *
 * Arguments out :	
 *	Bits *bits : struct to count the number of texture bits 
 * 	Image *bitstream : output bitstream
 *
 * Return values :	
 *	
 *
 * Side effects :	
 *	
 *
 * Description :	
 *	The intradc prediction can be switched off by setting the variable
 *	intradc_pred_disable to '1'.
 *
 * See also :
 *	
 *
 * Modified :
 *     03-09-96 Cor Quist (KPN) added intra_dcpred_disable, removed OLDINTRADC
 *	10.09.96: Robert Danielsen: Added information about 8x8 block
 *			transparency, avoiding coding of transparent
 *			8x8 blocks and DC-prediction from these.
 *	23.10.96 Robert Danielsen: Many changes to implement DC/AC prediction
 *			and to simplify things
 *	06.11.96 Robert Danielsen: Added zigzag scanning.
 *	28.01.97 Robert Danielsen: Changed the zigzag-scanning.
 *      30.04.97 Luis Ducla-Soares: added to arguments to the function call.
 *                                  This allows to write the DC coeffs in a
 *                                  different bitstream in the error
 *                                  resilient mode. Changes to allow the use
 *                                  of RVLCs.
 *      04.08.97 Minhua Zhou: added switched
 *
 ***********************************************************CommentEnd********/
Void MB_CodeCoeff(Bits* bits, Int *qcoeff,
		  Int Mode, Int CBP, Int ncoeffs, 
		  Int intra_dcpred_disable,
		  Image *DCbitstream,
		  Image *bitstream,
		  Int transp_pattern[], Int direction[],
		  Int error_res_disable,
		  Int reverse_vlc,
          Int switched,
          Int alternate_scan)
{
    Int i, m, coeff[64];
    Int *zz = alternate_scan ? zigzag_v : zigzag;
   	
    if (Mode == MODE_INTRA || Mode == MODE_INTRA_Q)
      {
	if (intra_dcpred_disable == 0)
	  { 
	    for (i = 0; i < 6; i++)
	      {
		if (i>3 || transp_pattern[i]!=1) /* Not transparent */
		  { 
            if (!alternate_scan) {
                switch (direction[i]) {
                    case 1: zz = zigzag_v; break;
                    case 2: zz = zigzag_h; break;
                    case 0: break;
                    default: fprintf(stderr, "MB_CodeCoeff(): Error in zigzag direction\n");
                        exit(-1);
                }
            }
		    /* Do the zigzag scanning of coefficients */
		    for (m = 0; m < 64; m++)
		    {
            *(coeff + zz[m]) = qcoeff[i*ncoeffs+m];
		    }

                if (switched==0) {
		  if (error_res_disable)
		    {
		      if (i < 4) 
			bits->Y += IntraDC_dpcm(coeff[0],1,bitstream);
		      else 
			bits->C += IntraDC_dpcm(coeff[0],0,bitstream);
		    }
		  else
		    {
		      if (i < 4) 
			bits->Y += IntraDC_dpcm(coeff[0],1,DCbitstream);
		      else 
			bits->C += IntraDC_dpcm(coeff[0],0,DCbitstream);
		    }
                  }

		    /* Code AC coeffs. dep. on block pattern MW 15-NOV-1996 */
		    if ((i==0 && CBP&32) || 
			(i==1 && CBP&16) ||
			(i==2 && CBP&8)  || 
			(i==3 && CBP&4)  ||
			(i==4 && CBP&2)  ||
			(i==5 && CBP&1)) 
		      {
			if (error_res_disable || ((!error_res_disable) && (!reverse_vlc)))
			  {
			    if (i < 4) 
			      bits->Y += CodeCoeff(1-switched,Mode, coeff,i,ncoeffs,bitstream);
			    else 
			      bits->C += CodeCoeff(1-switched,Mode, coeff,i,ncoeffs,
					     bitstream);
			  }
			else
			  {
			    if (i < 4)
			      bits->Y += CodeCoeff_RVLC(1-switched,Mode, coeff, i,
							ncoeffs, bitstream);
			    else
			      bits->C += CodeCoeff_RVLC(1-switched,Mode, coeff, i,
							ncoeffs, bitstream);
			  }
		      }
		  }
	      }
	  }
	else /* Without ACDC prediction */
	  {
	    for (i = 0; i < 6; i++) 
	      {
		if (i>3 || transp_pattern[i]!=1)  /* Not transparent */
		  {
		    /* Do the zigzag scanning of coefficients */
		    for (m = 0; m < 64; m++)
                *(coeff + zz[m]) = qcoeff[i*ncoeffs+m];

                  if (switched==0) {
		    if (error_res_disable)
		      {
			if (coeff[0] != 128) 
			  BitstreamPutBits(bitstream,(long)(coeff[0]),8L);
			else 
			  BitstreamPutBits(bitstream, 255L, 8L);
		      }
		    else
		      {
			if (coeff[0] != 128)
			  BitstreamPutBits(DCbitstream,(long)(coeff[0]),8L);
			else
			  BitstreamPutBits(DCbitstream,255L, 8L);
		      }
                			   
		    if (i < 4)
		      bits->Y += 8;
		    else
		      bits->C += 8;
                    }

		    if ((i==0 && CBP&32) || (i==1 && CBP&16) ||
			(i==2 && CBP&8) || (i==3 && CBP&4) ||
			(i==4 && CBP&2) || (i==5 && CBP&1)) 
		      {
			/* send coeff, not qcoeff !!! MW 07-11-96 */

			if (error_res_disable || ((!error_res_disable) && (!reverse_vlc)))
			  {
			    if (i < 4)
			      bits->Y += CodeCoeff(1-switched,Mode, coeff,i,ncoeffs,
						   bitstream);
			    else
			      bits->C += CodeCoeff(1-switched,Mode, coeff,i,ncoeffs,
						   bitstream);
			  }
			else
			  {
			    if (i < 4)
			      bits->Y += CodeCoeff_RVLC(1-switched,Mode, coeff, i,
							ncoeffs, bitstream);
			    else
			      bits->C += CodeCoeff_RVLC(1-switched,Mode, coeff, i,
							ncoeffs, bitstream);
			  }
			    
		      }
		  }
	      }
	  }
      }	  
    else 	/* inter block encoding */
      {
	for (i = 0; i < 6; i++) 
	  {
	    /* Do the zigzag scanning of coefficients */
	    for (m = 0; m < 64; m++)
             *(coeff + zz[m]) = qcoeff[i*ncoeffs+m];
	    if ((i==0 && CBP&32) || 
		(i==1 && CBP&16) ||
		(i==2 && CBP&8) || 
		(i==3 && CBP&4) ||
		(i==4 && CBP&2) ||
		(i==5 && CBP&1)) 
	      {
		if (error_res_disable || ((!error_res_disable) && (!reverse_vlc)))
		  {
		    if (i < 4)
		      bits->Y += CodeCoeff(0,Mode, coeff, i, ncoeffs, bitstream);
		    else
		      bits->C += CodeCoeff(0,Mode, coeff, i, ncoeffs, bitstream);
		  }
		else
		  {
		    if (i < 4)
		      bits->Y += CodeCoeff_RVLC(0,Mode, coeff, i, ncoeffs,
						bitstream);
		    else
		      bits->C += CodeCoeff_RVLC(0,Mode, coeff, i, ncoeffs,
						bitstream);
		  }
		    
	      }
	  }
      }
}

 
/***********************************************************CommentBegin******
 *
 * -- IntraDC_dpcm -- DPCM Encoding of INTRADC in case of Intra macroblocks
 *
 * Author : Cor Quist (KPN)		
 *	
 *
 * Created :		
 *	
 *
 * Purpose :		
 *	DPCM Encoding of INTRADC in case of Intra macroblocks
 * 
 * Arguments in : 	
 *	Int val : the difference value with respect to the previous
 *		INTRADC value
 * 	Int lum : indicates whether the block is a luminance block (lum=1) or 
 * 		a chrominance block ( lum = 0)
 *
 * Arguments in/out :	
 *	
 *
 * Arguments out :	
 *	Image* bitstream  : a pointer to the output bitstream
 *
 * Return values :	
 *	
 *
 * Side effects :	
 *	
 *
 * Description :	
 *	
 *
 * See also :
 *	
 *
 * Modified :		
 *	07.06.96: Robert Danielsen: Changed from using Encode to Putxxx
 *		instead, based on new VLC encoding scheme.
 *	
 *
 ***********************************************************CommentEnd********/

Int 
IntraDC_dpcm(Int val, Int lum, Image *bitstream)
{
    Int n_bits;
    Int absval, size = 0;
	
    absval = ( val <0)?-val:val; 	/* abs(val) */
	
  
    /* compute dct_dc_size */
	
    size = 0;
    while(absval)
    {
	absval>>=1;
	size++;
    }
	
    if (lum)
    {	/* luminance */
	n_bits = PutDCsize_lum (size, bitstream);
    }
    else
    {	/* chrominance */
	n_bits = PutDCsize_chrom (size, bitstream);
    }
	
    if ( size != 0 )
    {
	if (val>=0)
	{
	    ;
	}
	else
	{
	    absval = -val; /* set to "-val" MW 14-NOV-1996 */
	    val = (absval ^( (int)pow(2.0,(double)size)-1) );
	}
	BitstreamPutBits(bitstream, (long)(val), (long)(size));
	n_bits += size;

	if (size > 8)
	  BitstreamPutBits(bitstream, (long)1, (long)1);
    }
	
    return n_bits;	/* # bits for intra_dc dpcm */
	
}

/***********************************************************CommentBegin******
 *
 * -- CodeCoeff -- VLC encoding of quantized DCT coefficients
 *
 * Author :		
 *	
 *
 * Created :		
 *	
 *
 * Purpose :		
 *	VLC encoding of quantized DCT coefficients, except for 
 *      INTRADC in case of Intra macroblocks
 *	Used by Bits_CountCoeff
 * 
 * Arguments in : 	
 *	Int Mode : encoding mode
 * 	Int *qcoeff: pointer to quantized dct coefficients
 * 	Int block : number of the block in the macroblock (0-5)
 * 	Int ncoeffs : the number of coefficients per block
 *
 * Arguments in/out :	
 *	
 *
 * Arguments out :	
 *	Image *bitstream : pointer to the output bitstream
 *
 * Return values :	
 *	Int bits : number of bits added to the bitstream (?)
 *
 * Side effects :	
 *	
 *
 * Description :	
 *	
 *
 * See also :
 *	
 *
 * Modified :		
 *	07.06.96: Robert Danielsen: Changed from using Encode to Putxxx
 *		instead, based on new VLC encoding scheme.
 *	28.11.96: Robert Danielsen: Fixed bug reported by Luis Ducla-Soares,
 *			to use the higher levels of the INTRA-VLC.
 *	15.01.97 Robert Danielsen: Update of if-clause to avoid unneccesary
 *			running of PutCoeff_Inter/Intra for last coefficient.
 *			This was found by Luis Ducla-Soares.
 *	27.02.97 Robert Danielsen: Changed to using Intra VLC-tables for
 *			Intra chrominance blocks. For VM6 from Sevilla.
 *      27.07.97 C.S. Boon: Add in 3-mode escape
 *      04.08.97 Minhua Zhou: added j_start
 *      25.03.98 M.Wollborn: Modifications due to N2171 Cl. 2.2.14 
 *
 ***********************************************************CommentEnd********/

Int CodeCoeff(Int j_start, Int Mode, Int qcoeff[], Int block, Int ncoeffs, Image *bitstream)
{
    Int j, bits;
    Int prev_run, run, prev_level, level, first;
    Int prev_ind, ind, prev_s, s, length;

    run = bits = 0;
    first = 1;
    prev_run = prev_level = prev_ind = level = s = prev_s = ind = 0;
  
    for (j = j_start; j< ncoeffs; j++)
    {
	/* The INTRADC encoding for INTRA Macroblocks is done in 
	   Bits_CountCoeff */
      
	{
	    /* do not enter this part for INTRADC coding for INTRA macro-
	       blocks */
	  
	    /* encode AC coeff */
	  
	    s = 0;
	  
	    /* Increment run if coeff is zero */
	  
	    if ((level = qcoeff[j]) == 0)
	    {
		run++;
	    }
	    else
	    {
		/* code run & level and count bits */
	  
		if (level < 0)
		{
		    s = 1;
		    level = -level;
		}
	  
		ind = level | run<<4;
		ind = ind | 0<<12; /* Not last coeff */
	  
		if (!first)
		{
		    /* Encode the previous ind */
	      
		    if ((prev_run < 64) &&
			(((prev_level < 13) && (Mode != MODE_INTRA &&
					       Mode != MODE_INTRA_Q))
			|| ((prev_level < 28) && (Mode == MODE_INTRA ||
						  Mode == MODE_INTRA_Q))))
			{
			    /* Separate tables for Intra luminance blocks */
			    if (Mode == MODE_INTRA || Mode == MODE_INTRA_Q)
			    {
				length = PutCoeff_Intra(prev_run, prev_level,
							0, bitstream);
			    }
			    else
			    {
				length = PutCoeff_Inter(prev_run, prev_level,
							0, bitstream);
			    }
			}
		    else
			length = 0;

		    /* First escape mode. Level offset */
		    if (length == 0) {

		      if ( prev_run < 64 ) {

			/* subtraction of Max level, last = 0 */
			int level_minus_max;

			if (Mode == MODE_INTRA || Mode == MODE_INTRA_Q)
			  level_minus_max = prev_level - 
			                    intra_max_level[0][prev_run];
			else 
			  level_minus_max = prev_level - 
			                    inter_max_level[0][prev_run];

			if (  ( (level_minus_max < 13) && (Mode != MODE_INTRA && Mode != MODE_INTRA_Q) ) || 
			      ( (level_minus_max < 28) && (Mode == MODE_INTRA || Mode == MODE_INTRA_Q) ) ) 
			  {
			    /* Separate tables for Intra luminance blocks */
			    if (Mode == MODE_INTRA || Mode == MODE_INTRA_Q) {
			      length = PutLevelCoeff_Intra(prev_run, level_minus_max, 0, bitstream);
			    } else {
			      length = PutLevelCoeff_Inter(prev_run, level_minus_max, 0, bitstream);
			    }
			} else
			  length = 0;
		      }
		      else length = 0;
		    }


		    /* Second escape mode. Run offset */
		    if (length == 0) { 
		      if ( ((prev_level < 13) && (Mode != MODE_INTRA && Mode != MODE_INTRA_Q)) || 
			  ((prev_level < 28) && (Mode == MODE_INTRA || Mode == MODE_INTRA_Q)) )
			{

			  /* subtraction of Max Run, last = 0 */
			  int run_minus_max;

			  if (prev_level == 0) {
			    fprintf (stdout, "ERROR(CodeCoeff-second esc): level is %d\n", prev_level);
			    exit(-1);
			  }

			  if (Mode == MODE_INTRA || Mode == MODE_INTRA_Q)
			    run_minus_max = prev_run - (intra_max_run0[prev_level]+1);
			  else 
			    run_minus_max = prev_run - (inter_max_run0[prev_level]+1);
			  
			  if (run_minus_max < 64)  /* boon 120697 */
			    {
			      /* Separate tables for Intra luminance blocks */
			      if (Mode == MODE_INTRA || Mode == MODE_INTRA_Q) {
				length = PutRunCoeff_Intra(run_minus_max, prev_level, 0, bitstream);
			      } else {
				length = PutRunCoeff_Inter(run_minus_max, prev_level, 0, bitstream);
			      }
			  } else
			    length = 0;
			} 
		      else length = 0;
		    }
		    
		    /* Third escape mode. FLC */
		    if (length == 0)
		    {  /* Escape coding */
		  
			if (prev_s == 1)
			{
			  /* Modified due to N2171 Cl. 2.2.14 MW 25-MAR-1998 */
			  /* prev_level = (prev_level^0xff)+1; */
			  prev_level = (prev_level^0xfff)+1;
			}
			BitstreamPutBits(bitstream, 3L, 7L); 
			BitstreamPutBits(bitstream, 3L, 2L); /* boon */
		  
			BitstreamPutBits(bitstream, 0L, 1L); /* last */
			BitstreamPutBits(bitstream, (long)(prev_run), 6L);
			
			/* Modified due to N2171 Cl. 2.2.14 MW 25-MAR-1998 */
			/* BitstreamPutBits(bitstream, (long)(prev_level), 8L); */
			/* bits += 24; */
			BitstreamPutBits(bitstream, (long)(prev_level), 12L);
			bits += 28; /* boon */
		    }
		    else
		    {
			BitstreamPutBits(bitstream, (long)(prev_s), 1L);
			bits += length + 1;
		    }
		}
	  
		prev_run = run; prev_s = s;
		prev_level = level; prev_ind = ind;
	  
		run = first = 0;
	    }
	}
    }
  
    /* Encode the last coeff */
  
    if (!first)
    {
	prev_ind = prev_ind | 1<<12;   /* last coeff */
      
	if ((prev_run < 64) &&
	    (((prev_level < 4) && (Mode != MODE_INTRA &&
				  Mode != MODE_INTRA_Q))
	    || ((prev_level < 9) && ((Mode == MODE_INTRA) ||
				     (Mode == MODE_INTRA_Q)))))
	{
	    /* Separate tables for Intra luminance blocks */
	    if (Mode == MODE_INTRA || Mode == MODE_INTRA_Q)
	    {
		length = PutCoeff_Intra(prev_run, prev_level, 1,
					bitstream);
	    }
	    else
	    {
		length = PutCoeff_Inter(prev_run, prev_level, 1,
					bitstream);
	    }
	}
	else
	    length = 0;
      
	/* First escape mode. Level offset */
	if (length == 0) {
	  if ( prev_run < 64 ) {

	    /* subtraction of Max level, last = 0 */
	    int level_minus_max;
	
	    if (Mode == MODE_INTRA || Mode == MODE_INTRA_Q)
	      level_minus_max = prev_level - intra_max_level[1][prev_run];
	    else 
	      level_minus_max = prev_level - inter_max_level[1][prev_run];

	    if (  ( (level_minus_max < 4) && (Mode != MODE_INTRA && Mode != MODE_INTRA_Q) ) || 
		( (level_minus_max < 9) && (Mode == MODE_INTRA || Mode == MODE_INTRA_Q) ) ) 
	      {
		/* Separate tables for Intra luminance blocks */
		if (Mode == MODE_INTRA || Mode == MODE_INTRA_Q) {
		  length = PutLevelCoeff_Intra(prev_run, level_minus_max, 1, bitstream);
		} else {
		  length = PutLevelCoeff_Inter(prev_run, level_minus_max, 1, bitstream);
		}
	    } else
	      length = 0;
	  }
	  else length = 0;
	}

	/* Second escape mode. Run offset */
	if (length == 0) { 
	  if (((prev_level < 4) && (Mode != MODE_INTRA && Mode != MODE_INTRA_Q))|| 
	      ((prev_level < 9) && (Mode == MODE_INTRA || Mode == MODE_INTRA_Q)) )
	    {
	  
	      /* subtraction of Max Run, last = 1 */
	      int run_minus_max;

	      if (prev_level == 0) {
		fprintf (stdout, "ERROR(CodeCoeff-second esc): level is %d\n", prev_level);
		exit(-1);
	      }
	  
	      if (Mode == MODE_INTRA || Mode == MODE_INTRA_Q)
		run_minus_max = prev_run - (intra_max_run1[prev_level]+1);
	      else 
		run_minus_max = prev_run - (inter_max_run1[prev_level]+1);

	      if (run_minus_max < 64)  /* boon 120697 */
		{
		  /* Separate tables for Intra luminance blocks */
		  if (Mode == MODE_INTRA || Mode == MODE_INTRA_Q) {
		    length = PutRunCoeff_Intra(run_minus_max, prev_level, 1, bitstream);
		  } else {
		    length = PutRunCoeff_Inter(run_minus_max, prev_level, 1, bitstream);
		  }
	      } else
		length = 0;
	    } 
	  else length = 0;
	}

	/* Third escape mode. FLC */
	if (length == 0)
	{  /* Escape coding */
	  
	    if (prev_s == 1)
	    {
	      /* Modified due to N2171 Cl. 2.2.14 MW 25-MAR-1998 */
	      /* prev_level = (prev_level^0xff)+1; */
	      prev_level = (prev_level^0xfff)+1;
	    }
	    BitstreamPutBits(bitstream, 3L, 7L); 
	    BitstreamPutBits(bitstream, 3L, 2L); /* boon */
	  
	    BitstreamPutBits(bitstream, 1L, 1L); /* last */
	    BitstreamPutBits(bitstream, (long)(prev_run), 6L);
	    
	    /* Modified due to N2171 Cl. 2.2.14 MW 25-MAR-1998 */
	    /* BitstreamPutBits(bitstream, (long)(prev_level), 8L); */
	    /* bits += 24; */
	    BitstreamPutBits(bitstream, (long)(prev_level), 12L);
	    bits += 28; /* boon */

	}
	else
	{
	    BitstreamPutBits(bitstream, (long)(prev_s), 1L);
	    bits += length + 1;
	}
    }
  
    return bits;
}


/***********************************************************CommentBegin******
 *
 * -- CodeCoeff_RVLC -- RVLC encoding of quantized DCT coefficients
 *
 * Author :		
 *	Luis Ducla-Soares (IST) - lds@lx.it.pt
 *
 * Created :		
 *    30.04.97	
 *
 * Purpose :		
 *	RVLC encoding of quantized DCT coefficients, except for 
 *      INTRADC in case of Intra macroblocks
 * 
 * Arguments in : 	
 *	Int Mode : encoding mode
 * 	Int *qcoeff: pointer to quantized dct coefficients
 * 	Int block : number of the block in the macroblock (0-5)
 * 	Int ncoeffs : the number of coefficients per block
 *
 * Arguments in/out :	
 *	
 *
 * Arguments out :	
 *	Image *bitstream : pointer to the output bitstream
 *
 * Return values :	
 *	Int bits : number of bits added to the bitstream (?)
 *
 * Side effects :	
 *	
 *
 * Description : based on CodeCoeff().	
 *	
 *
 * See also :
 *	
 *
 * Modified :		
 *
 ***********************************************************CommentEnd********/

Int CodeCoeff_RVLC(Int j_start, Int Mode, Int qcoeff[], Int block, Int ncoeffs, Image *bitstream)
{
    Int j, bits;
    Int prev_run, run, prev_level, level, first;
    Int prev_ind, ind, prev_s, s, length;

    run = bits = 0;
    first = 1;
    prev_run = prev_level = prev_ind = level = s = prev_s = ind = 0;
  
    for (j = j_start; j< ncoeffs; j++)
    {
	/* The INTRADC encoding for INTRA Macroblocks is done in 
	   Bits_CountCoeff */
      
		{
	    /* do not enter this part for INTRADC coding for INTRA macro-
	       blocks */
	  
	    /* encode AC coeff */
	  
	    s = 0;
	  
	    /* Increment run if coeff is zero */
	  
	    if ((level = qcoeff[j]) == 0)
	    {
		run++;
	    }
	    else
	    {
		/* code run & level and count bits */
	  
		if (level < 0)
		{
		    s = 1;
		    level = -level;
		}
	  
		ind = level | run<<4;
		ind = ind | 0<<12; /* Not last coeff */
		if (!first)
		{
		    /* Encode the previous ind */
	      
		    if (prev_level  < 28 && prev_run < 39) 
			/* Separate tables for Intra luminance blocks */
			if (Mode == MODE_INTRA || Mode == MODE_INTRA_Q)
			   {
			    length = PutCoeff_Intra_RVLC(prev_run, prev_level, 0,
							 bitstream);
			  }
			else {
			  length = PutCoeff_Inter_RVLC(prev_run, prev_level, 0,
						       bitstream);
			}
		    else
			length = 0;
	    				
		    if (length == 0)
		    {  /* Escape coding */
		  


		      	BitstreamPutBits(bitstream, 1L, 5L); 
		  
			BitstreamPutBits(bitstream, 0L, 1L);
		  
			BitstreamPutBits(bitstream, 
					 (long)(prev_run), 6L);
		  
			BitstreamPutBits(bitstream, 
					 (long)(prev_level), 7L);
			
			BitstreamPutBits(bitstream, 0L, 4L);
			
			BitstreamPutBits(bitstream,
					 (long)(prev_s),1L);
		
		  
			bits += 24;
		    }
		    else
		    {
			BitstreamPutBits(bitstream, 
					 (long)(prev_s), 1L);
			bits += length + 1;
		    }
		}
	  
		prev_run = run; prev_s = s;
		prev_level = level; prev_ind = ind;
	  
		run = first = 0;
	    }
	}
    }
  
    /* Encode the last coeff */
  
    if (!first)
    {
	prev_ind = prev_ind | 1<<12;   /* last coeff */
      
	if (prev_level  < 5 && prev_run < 45) 
	    /* Separate tables for Intra luminance blocks */
	if (Mode == MODE_INTRA || Mode == MODE_INTRA_Q)
			  	      {
		length = PutCoeff_Intra_RVLC(prev_run, prev_level, 1,
					     bitstream);
	      }
	    else {
		length = PutCoeff_Inter_RVLC(prev_run, prev_level, 1,
					bitstream);
	    }
	else
	    length = 0;
      
	if (length == 0)
	{  /* Escape coding */
	 
		  
      	    BitstreamPutBits(bitstream, 1L, 5L); 
	  
	    BitstreamPutBits(bitstream, 1L, 1L);
	  
	    BitstreamPutBits(bitstream, (long)(prev_run), 6L);
	  
	    BitstreamPutBits(bitstream, (long)(prev_level), 7L);

	    BitstreamPutBits(bitstream, 0L, 4L);
	    
	    BitstreamPutBits(bitstream, (long)(prev_s), 1L);
	    	  
	    bits += 24;

	}
	else
	{
	    BitstreamPutBits(bitstream, (long)(prev_s), 1L);
	    bits += length + 1;
	}
    }
  
    return bits;
}


/***********************************************************CommentBegin******
 *
 * -- Bits_Reset -- To reset the structure bits
 *
 * Author : Telenor - TMN5		
 *	
 *
 * Created :		
 *	
 *
 * Purpose :		
 *	To reset the structure bits, used for counting the number 
 * 	of texture bits
 * 
 * Arguments in : 	
 *	Bits* bits : a pointer to the struct Bits
 *
 * Arguments in/out :	
 *	
 *
 * Arguments out :	
 *	
 *
 * Return values :	
 *	
 *
 * Side effects :	
 *	
 *
 * Description :	
 *	
 *
 * See also :
 *	
 *
 * Modified : Cor Quist (KPN) 11-June-1996		
 *	25.10.96 Robert Danielsen: Added ACpred_flag.
 *  11.12.97 Bob Eifrig:  Use of memset() so number &
 *                        name of fields is irrelevent
 *
 ***********************************************************CommentEnd********/

void 
Bits_Reset (Bits *bits)
{
  memset(bits, 0, sizeof(Bits));
}


