/*****************************************************************************
 *
 * This software module was originally developed by
 *
 *   Robert Danielsen (Telenor / ACTS-MoMuSyS)
 *   Stefan Schultz (TUH / ACTS-MoMuSyS)
 *   Michael Wollborn (TUH / ACTS-MoMuSyS)
 *
 * and edited by
 * 
 *   Karl Lillevold (Telenor / ACTS-MoMuSyS)
 *   Cor Quist (KPN / ACTS-MoMuSyS)
 *   Jan De Lameillieure (HHI / 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) 1996
 *
 *****************************************************************************/

/***********************************************************HeaderBegin*******
 *                                                                         
 * File:	text_quant.c
 *
 * Authors:	Robert Danielsen, Telenor R&D, Norway 
 *		Stefan Schultz, Michael Wollborn (TUH)
 * Created:	
 *                                                                         
 * Description: 
 *
 * Notes: 	
 *
 * Modified:	Karl Lillevold, Telenor (tmn)
 *		Cor Quist -- 12-Apr-96	
 * 		21.04.96 Robert Danielsen: Reformatted. New headers.
 *		Jan De Lameillieure (HHI), 19-AUG-96 : corrected rounding of 
 *			intra-DC-coefficient
 *	10.09.96 Robert Danielsen: Added BlockQuant(), BlockDequant()	       
 *	21-APR-97 Jan De Lameillieure : removed Quant()	
 *	22-APR-97 Michael Wollborn: Added the functions for MPEG-like
 *		  quantization from the former file "text_quant_mpeg.c",
 *		  renamed "BlockQuant()" -> "BlockQuantH263()" and the
 *		  dequantization respectively       
 *
 ***********************************************************HeaderEnd*********/

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

#include <stdlib.h>
#include "text_defs.h"
#include "momusys.h"
#include "text_quant.h"
#include "text_util.h"		/* JDL 31-JUL-96 : because zz[] is needed */

/***********************************************************CommentBegin******
 *
 * -- cal_dc_scaler -- calculation of DC quantization scale according 
                      to the incoming Q and type; 
 *
 * Author : Minhua Zhou 		
 *	
 *
 * Created : 04.11.97		
 *	
 *
 * Purpose :		
 *
 * 
 * Arguments in : 	
 *   Int Qp 
 * Arguments in/out :	
 *	
 * Arguments out :	
 *
 * Return values :	
 *	 *
 * Side effects :	
 *	
 *
 * Description :	
 *	
 *
 * See also :
 *	
 *
 * Modified :		
 ***********************************************************CommentEnd********/


Int cal_dc_scaler (Int QP, Int type) {

 Int dc_scaler;
 if (type == 1)
    {
      if (QP > 0 && QP < 5) dc_scaler = 8;
      else if (QP > 4 && QP < 9) dc_scaler = 2 * QP;
      else if (QP > 8 && QP < 25) dc_scaler = QP + 8;
      else dc_scaler = 2 * QP - 16;
    }
  else
    {
      if (QP > 0 && QP < 5) dc_scaler = 8;
      else if (QP > 4 && QP < 25) dc_scaler = (QP + 13) / 2;
      else dc_scaler = QP - 6;
    }   
  return dc_scaler;
}


/***********************************************************CommentBegin******
 *
 * -- BlockQuantH263 -- 8x8 block level quantization
 *
 * Author :		
 *	Robert Danielsen, Telenor R&D, <Robert.Danielsen@nta.no>
 *
 * Created :		
 *	28.06.96
 *
 * Purpose :		
 *	8x8 block level quantization
 * 
 * Arguments in : 	
 *	Int *coeff	non-quantized coefficients
 *	Int QP		quantization parameter
 *	Int Mode	Macroblock coding mode
 *
 * Arguments in/out :	
 *
 * Arguments out :	
 *	Int *qcoeff	quantized coefficients
 *
 * Return values :	
 *	Void
 *
 * Side effects :	
 *
 * Description :	
 *
 * See also :
 *
 * Modified :		
 *	27.01.97 Robert Danielsen: Included rounding-fix for DC-coeff. Did
 *			it as in Quant() above. From the Berkeley team.
 *	27.02.97 Robert Danielsen: Changed to nonlinear quantization of
 *			Intra DC coefficients. Accoring to VM6 from Sevilla.
 *	22.04.97 Michael Wollborn: renamed to "BlockQuantH263()"
 *      25.03.98 M. Wollborn: modifications due to N2171 Cl. 2.2.14
 *
 ***********************************************************CommentEnd********/
Void
BlockQuantH263 (Int *coeff, Int QP, Int mode, Int type, Int *qcoeff, Int maxDC)
{
  Int i;
  Int level;
  Int dc_scaler;

  MOMCHECK(QP > 0 && QP < 32);
  MOMCHECK(type == 1 || type == 2);
  dc_scaler = cal_dc_scaler(QP,type);
   
  if (QP)
    {
      if (mode == MODE_INTRA || mode == MODE_INTRA_Q)
	{ /* Intra */
	  qcoeff[0] = MAX(1,MIN(maxDC-1, (coeff[0] >= 0) ? (coeff[0] + dc_scaler/2)/dc_scaler
				      : (coeff[0] - dc_scaler/2) /dc_scaler)); /* rounding */

	  for (i = 1; i < 64; i++)
	    {
	      level = (ABS(coeff[i])) / (2*QP);
	      /* Modified due to N2171 Cl. 2.2.14 MW 25-MAR-1998 */
	      /* qcoeff[i] =  MIN(127,MAX(-127,SIGN(coeff[i]) * level)); */
	      qcoeff[i] =  MIN(2047,MAX(-2047,SIGN(coeff[i]) * level));
	    }
	}
      else
	{ /* non Intra */
	  for (i = 0; i < 64; i++)
	    {
	      level = (ABS(coeff[i])-QP/2)  / (2*QP);
	      /* Modified due to N2171 Cl. 2.2.14 MW 25-MAR-1998 */
	      /* qcoeff[i] = MIN(127,MAX(-127,SIGN(coeff[i]) * level)); */
	      qcoeff[i] = MIN(2047,MAX(-2047,SIGN(coeff[i]) * level));
	    }
	}
    }
  else
    {
      /* No quantizing.
	 Used only for testing. Bitstream will not be decodable 
	 whether clipping is performed or not */
      for (i = 0; i < 64; i++)
	{
	  qcoeff[i] = coeff[i];
	}
    }
  return;
}

/***********************************************************CommentBegin******
 *
 * -- BlockDequantH263 -- 8x8 block dequantization
 *
 * Author :		
 *	Robert Danielsen, Telenor R&D, <Robert.Danielsen@nta.no>
 *
 * Created :		
 *	28.06.96
 *
 * Purpose :		
 *	8x8 block dequantization
 * 
 * Arguments in : 	
 *	Int *qcoeff	quantized coefficients
 *	Int QP		quantization parameter
 *	Int mode	Macroblock coding mode
 *
 * Arguments in/out :	
 *
 * Arguments out :	
 *	Int *rcoeff	reconstructed (dequantized) coefficients
 *
 * Return values :	
 *	Void
 *
 * Side effects :	
 *	
 * Description :	
 *	
 * See also :
 *	
 * Modified :		
 *	27.02.97 Robert Danielsen: Changed to nonlinear quantization of
 *			Intra DC coefficients. Accoring to VM6 from Sevilla.
 *	22.04.97 Michael Wollborn: renamed to "BlockDequantH263()"
 *	
 ***********************************************************CommentEnd********/
Void
BlockDequantH263 (Int *qcoeff, Int QP, Int mode, Int type, Int *rcoeff)
{
  Int i;
  Int dc_scaler;
  
  if (QP)
    {
      for (i = 0; i < 64; i++)
	{
	  if (qcoeff[i])
	    {
	      if ((QP % 2) == 1)
		rcoeff[i] = QP * (2*ABS(qcoeff[i]) + 1);
	      else
		rcoeff[i] = QP * (2*ABS(qcoeff[i]) + 1) - 1;
	      rcoeff[i] = SIGN(qcoeff[i]) * rcoeff[i];
	    }
	  else
	    rcoeff[i] = 0;
	}
      if (mode == MODE_INTRA || mode == MODE_INTRA_Q) 
	{ /* Intra */

	    MOMCHECK(QP > 0 && QP < 32);
	    MOMCHECK(type == 1 || type == 2);

	    dc_scaler = cal_dc_scaler(QP,type);
  
	    rcoeff[0] = qcoeff[0] * dc_scaler;
	}
    }
  else
    {
      /* No quantizing at all */
      for (i = 0; i < 64; i++)
	{
	  rcoeff[i] = qcoeff[i];
	}

      if (mode == MODE_INTRA || mode == MODE_INTRA_Q) 
      { /* Intra */
      	rcoeff[0] = qcoeff[0]*8;
      }
    }
  for (i=0;i<64;i++)
      if (rcoeff[i]>2047) rcoeff[i]=2047;
       else if (rcoeff[i]<-2048) rcoeff[i]=-2048;

  return;
}


/***********************************************************CommentBegin******
 *
 * -- BlockQuantMPEG -- Quantize DCT-coefficients MPEG-like
 *
 * Author :		
 *	Stefan Schultz, TUH
 *
 * Created :		
 *	
 *
 * Purpose :		
 *	Quantize DCT-coefficients using definable quant. matrix
 * 
 * Arguments in : 	
 *	Int *coeff : pointer to dct-coefficients
 * 	Int QP : quantizer step ( 1 - 31)
 * 	mode : Macroblock encoding mode
 *
 * Arguments in/out :	
 *	Int *qcoeff : pointer to quantized coefficients
 *
 * Arguments out :	
 *	
 *
 * Return values :	
 *	
 *
 * Side effects :	
 *	
 *
 * Description :	
 *	
 *
 * See also :
 *	
 *
 * Modified :
 *	31-JUL-96 Jan De Lameillieure (HHI) : corrected MPEG-1/-2 inverse 
 *	quantisationby doing zigzag of elements of weighting matrices
 *
 *	19-AUG-96 Jan De Lameillieure (HHI) : corrected rounding in 
 *	MPEG-1/-2 quantisation
 *
 *	14-NOV-1996, M.Wollborn: Removed zigzag-stuff, snce that is now
 *	from VM4.0 done directly before encoding and after decoding of
 *	the DCT coefficients
 *	27.02.97 Robert Danielsen: Changed to nonlinear quantization of
 *			Intra DC coefficients. Accoring to VM6 from Sevilla.
 *      25.03.98 M. Wollborn: modifications due to N2171 Cl. 2.2.14
 *
 ***********************************************************CommentEnd********/
 
Void
BlockQuantMPEG (Int *coeff, Int QP, Int mode, Int type, Int *qmat, Int *qcoeff, Int maxDC)
{
  Int i;
  Int ac1, ac2, ac3, p=3, q=4;
  Int dc_scaler;

  MOMCHECK(QP > 0 && QP < 32);
  MOMCHECK(type == 1 || type == 2);

  dc_scaler = cal_dc_scaler(QP,type);  
  if (QP)
    {
      if (mode == MODE_INTRA || mode == MODE_INTRA_Q)
	{ /* Intra */
	  /* corrected rounding ; JDL 19-AUG-96 */
	  qcoeff[0] = MAX(1,MIN(maxDC-1, (coeff[0] >= 0) ?
				(coeff[0]+dc_scaler/2)/dc_scaler : 
				(coeff[0]-dc_scaler/2)/dc_scaler));

	  for (i = 1; i < 64; i++)
	    {
	      /* added zz[] (JDL 31-JUL-96) */
	      /* added corrected rounding (JDL 19-AUG-96) */
	      /* removed zz[] (MW 14-NOV-1996 */
	      ac1 = (16*coeff[i] + ((coeff[i]>0) ? 1 : (-1))*qmat[i]/2) 
		     / qmat[i];

	      ac2 = MAX(-2048, MIN(2047, ac1));

	      /* corrected rounding ; JDL 19-AUG-96 */
	      ac3 = ( ac2 + SIGN0(ac2)*((p*QP + (q/2))/q) )/(2*QP);	

	      /* Modified due to N2171 Cl. 2.2.14 MW 25-MAR-1998 */
	      /* qcoeff[i] =  MIN(127, MAX(-127, ac3)); */
	      qcoeff[i] =  MIN(2047, MAX(-2047, ac3));
	    }
	}
      else
	{ /* non Intra */
	  for (i = 0; i < 64; i++)
	    {
	      /* added zz[] (JDL 31-JUL-96) */
	      /* added corrected rounding (JDL 19-AUG-96) */
	      /* removed zz[] (MW 14-NOV-1996 */
	      ac1 = (16*coeff[i] + ((coeff[i]>0) ? 1 : (-1))*qmat[i]/2) 
		     / qmat[i]; 

	      ac2 = ac1/(2*QP);

	      /* Modified due to N2171 Cl. 2.2.14 MW 25-MAR-1998 */
	      /* qcoeff[i] =  MIN(127, MAX(-127, ac2)); */
	      qcoeff[i] =  MIN(2047, MAX(-2047, ac2));
	    }
	}
    }
  else
    {
      /* No quantizing.
	 Used only for testing. Bitstream will not be decodable 
	 whether clipping is performed or not */
      for (i = 0; i < 64; i++)
	{
	  qcoeff[i] = coeff[i];
	}
    }

  return;
}

/***********************************************************CommentBegin******
 *
 * -- BlockDequantMPEG -- Dequantize DCT coefficients MPEG-like
 *
 * Author :		
 *	Stefan Schultz, TUH
 *
 * Created :		
 *	
 *
 * Purpose :		
 *	Dequant_mpegizer for quantized dct-coefficients
 * 
 * Arguments in : 	
 *	Int *qcoeff : pointer to quantized coefficients
 * 	Int QP : quantizer step 
 * 	Int mode : macroblock encoding mode
 *
 * Arguments in/out :	
 *	Int *rcoeff : pointer to reconstructed coefficients
 *
 * Arguments out :	
 *	
 *
 * Return values :	
 *	
 *
 * Side effects :	
 *	
 *
 * Description :	
 *	
 *
 * See also :
 *	
 *
 * Modified :		
 *	31-JUL-96 Jan De Lameillieure (HHI) : corrected MPEG-1/-2 inverse 
 *	quantisation by doing zigzag of elements of weighting matrices
 *
 *	14-NOV-1996, M.Wollborn: Removed zigzag-stuff, snce that is now
 *	from VM4.0 done directly before encoding and after decoding of
 *	the DCT coefficients
 *	27.02.97 Robert Danielsen: Changed to nonlinear quantization of
 *			Intra DC coefficients. Accoring to VM6 from Sevilla.
 *      04.08.97 Minhua Zhou: added "mismatch control"
 *	
 ***********************************************************CommentEnd********/

Void
BlockDequantMPEG (Int *qcoeff, Int QP, Int mode, Int type, Int *qmat, 
		  Int *rcoeff)
{
  Int i;
  Int dc_scaler,sum;
  
  if (QP)
    {
      if (mode == MODE_INTRA || mode == MODE_INTRA_Q)
	{ /* Intra */
	  MOMCHECK(QP > 0 && QP < 32);
	  MOMCHECK(type == 1 || type == 2);

	 dc_scaler = cal_dc_scaler(QP,type);
	  rcoeff[0] = qcoeff[0]*dc_scaler;

	  for (i = 1; i < 64; i++)
	    {
	      if (qcoeff[i]) {
		  /* added zz[] ; JDL 31-JUL-96 */
		  /* removed zz[], (14-NOV-1996, MW) */
	        rcoeff[i] = (qcoeff[i]*qmat[i]*QP*2)/16;
                if (rcoeff[i]>2047) rcoeff[i]=2047;
                  else if (rcoeff[i]<-2048) rcoeff[i]=-2048;
               }  	
	      else
	        rcoeff[i] = 0;
	    }
	}
      else
        { /* non intra */
	  for (i = 0; i < 64; i++)
	    {
	      if (qcoeff[i]) {
	        /* added zz[] ; JDL 31-JUL-96 */
	        /* removed zz[], (14-NOV-1996, MW) */
	        rcoeff[i]=(((qcoeff[i]*2)+SIGN0(qcoeff[i]))
			   *qmat[i]*QP)/16; 
                if (rcoeff[i]>2047) rcoeff[i]=2047;
                  else if (rcoeff[i]<-2048) rcoeff[i]=-2048;
               }
	      else
	        rcoeff[i] = 0;
	    }
	}
    }
  else
    {
      /* No quantizing at all */
      for (i = 0; i < 64; i++)
	{
	  rcoeff[i] = qcoeff[i];
	}
    }




/* added by Minhua Zhou, 04.08.1997 Mismatch Control */
  sum =0;
  for (i=0;i<64;i++) sum+=abs(rcoeff[i]);
  if (sum) {
    sum=0;
    for (i=0;i<64;i++) sum+=rcoeff[i];
     if ((sum&0x1)==0) rcoeff[63]+=((rcoeff[63]&0x1)?-1:1); 
  }
    

  return;
}





