/*****************************************************************************
 *                                                                          
 * This software module was developed by 
 *
 *  Anthony Vetro  (MITSUBISHI ELECTRIC ITA)
 *  Huifang Sun    (MITSUBISHI ELECTRIC ITA)
 *  Hung-Ju Lee    (Sarnoff Corporation)
 *  Tihao Chiang   (Sarnoff Corporation)
 *                                                      
 *
 * 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
 *
 *****************************************************************************/

/****************************************************************
  COPYRIGHT (1997)  MITSUBISHI ELECTRIC ITA
  ALL RIGHTS RESERVED
  MITSUBISHI PROPRIETARY INFORMATION
  PERMISSION IS GRANTED FOR USE WITHIN MPEG4 STANDARDIZATION PROCESS 
****************************************************************/

/**
 **  meitca_wrapper.c: 	rate control interface module
 **  Author: 		A. Vetro
 **
 **/

#include "momusys.h"
#include "mom_vop.h"
#include "vm_config.h"
#include "mom_vol.h"
#include "mom_structs.h"
#include "vm_stats.h"

#include "rc_mvo.h"
#include "rc2.h"
#include "meitca_wrapper.h"

extern RC_MVO rc_mvo;  

Int   START_RATE_CONTROL_MVO;          
Int   MAX_SLIDING_WINDOW_MVO ;         
Float PAST_PERCENT_MVO;                
Float SAFETY_MARGIN_MVO;                
Int   SKIP_MARGIN_MVO;                 
Int   MAX_QUANT_MVO;                   
Int   SKIP_TH;                         
Int   LB_QUANT;                        

Double rc_MAD[20];
Double rc_MAD_next[20];
Double rc_MMV[20];
Double rc_MMV_next[20];
Int rc_SIZE[20];
Int rc_SIZE_next[20];
Int    QSTEP[20];

static Int    rc_Q[20];
extern Int    FirstInterFrame;
extern Int    *first_time;
extern Int    *first_time_mv;
extern Double *Qlast;

static Int buffer_overflow = 0;
static Int buffer_underflow = 0;
static Int mvo_enabled = 0;

/***************************************************************************
  RCQ2_MVO_SET()
  ***************************************************************************/
Void RCQ2_MVO_SET(Int status)
{
  if (status==RCQ2_MVO_ENABLED)
    mvo_enabled = RCQ2_MVO_ENABLED; 
  else if (status==RCQ2_MVO_HVS)
    mvo_enabled = RCQ2_MVO_HVS; 
  else
    mvo_enabled = RCQ2_MVO_DISABLED; 
}

/***************************************************************************
  RCQ2_MVO_CHECK()
  ***************************************************************************/
Int  RCQ2_MVO_CHECK()
{
    return (mvo_enabled);
}

/***************************************************************************
  RCQ2_MVO_InitGlobal()
  ***************************************************************************/
Void RCQ2_MVO_InitGlobal(VOConfig *vo_config_list, EncodeControl *enc_ctl)
{
  VolConfig *vol_config;
  Int vo_id;
#ifdef _RC_DEBUG_
  FILE *fp;
#endif

  rc_mvo.numVOs = GetEncodeControlNumVOs(enc_ctl);
  vol_config = GetVOConfigLayers(vo_config_list);
  rc_init_global2 (0,GetVolConfigEndFrame(vol_config),
                  GetVolConfigFrameSkip(vol_config),
                  GetVolConfigBitrate(vol_config), 		  
		  rc_mvo.numVOs);

  for (vo_id=0; vo_id<rc_mvo.numVOs; vo_id++) {
	rc_MAD[vo_id] = 1.0;
	rc_Q[vo_id] = 15;
  }

  rc_default_parameters(rc_mvo.numVOs);

  if ((rc_mvo.numVOs == 1) && (RCQ2_MVO_CHECK()==RCQ2_MVO_HVS)) {
    fprintf(stdout,"SVO+HVS rate control is not supported yet !\n");
    fprintf(stderr,"SVO+HVS rate control is not supported yet !\n");
    exit(-1);
  }
#ifdef _RC_DEBUG_
  if((fp = fopen("buffer.dat","w"))==NULL) {
	printf("Error opening buffer.dat for writing\n\n");
	exit(1); }
  fclose(fp);
  printf("RCQ2_MVO_InitGlobal....\n"); /*getchar();*/
#endif /*_RC_DEBUG_*/
}

/***************************************************************************
  RCQ2_MVO_ComputeMAD()
  ***************************************************************************/
Void RCQ2_MVO_ComputeMAD(Vop *error_vop, Int vo_id)
{
     SInt  *curr_a_in,
	   *curr_y_in;
     Int    cnt,
	    pel_in,
	    dim_x, dim_y,
	    x, y;
     Double mad=0.0;
     Image *a_in, 
	   *y_in;

     y_in = GetVopY(error_vop);
     a_in = GetVopA(error_vop);

     dim_x = GetImageSizeX(y_in);
     dim_y = GetImageSizeY(y_in);

     curr_y_in = (SInt *)GetImageData(y_in);
     curr_a_in = (SInt *)GetImageData(a_in);

     pel_in=0; cnt=0;
     for(y=0; y<dim_y; y++)
     for(x=0; x<dim_x; x++)
     {
 	if(curr_a_in[pel_in]) {
 	    mad += abs(curr_y_in[pel_in]);
 	    cnt++;
 	}
 	pel_in++;
     }

     mad /= cnt;
     rc_MAD_next[vo_id] = mad;
     rc_MAD[vo_id] = mad;
     if(vo_id!=0)
	rc_MAD[vo_id] = rc_MAD_next[vo_id];
}

/***************************************************************************
  RCQ2_MVO_computeMMV()
  ***************************************************************************/
Void RCQ2_MVO_ComputeMMV(Image *mot_x, Image *mot_y, 
			 Int mv_w, Int mv_h, Int vo_id)
{
     Int    cnt, base,
	    x, y;
     Double mmv=0.0;
     Float  *data_x, *data_y;

     data_x = (Float*)GetImageData(mot_x);
     data_y = (Float*)GetImageData(mot_y);

     cnt=0;
     for(y=0; y<2*mv_h; y++)
     for(x=0; x<2*mv_w; x++)
     {
          base=y*mv_w+x;
 	  mmv += abs(data_x[base]);
	  mmv += abs(data_y[base]);
 	  cnt++;
     }
     mmv /= cnt;
     rc_MMV_next[vo_id] = mmv;
     rc_SIZE_next[vo_id] = mv_h*mv_w;
     if(vo_id!=0) {
     	rc_MMV[vo_id] = rc_MMV_next[vo_id];	
	rc_SIZE[vo_id] = rc_SIZE_next[vo_id];
     }

}


/***************************************************************************
  RCQ2_MVO_PreEncoding()
  ***************************************************************************/
Void RCQ2_MVO_PreEncoding(Vop *curr, Int vo_id)
{
  Int target_curr=0, target_buff=0;
  Int i, T, numVOs;
  Double Q;

  RCQ2_MVO_ComputeMAD(curr, vo_id);
 
  if(first_time[vo_id]) {
     Q=GetVopIntraQuantizer(curr);
     Qlast[vo_id] = Q;
     first_time[vo_id] = 0;
     rc_Q[vo_id] = (Int)Q;
#ifdef _RC_DEBUG_
     printf("GetVopIntraQuantizer Q = %f\n", Q);
#endif /*_RC_DEBUG_*/
  }
  else if(vo_id==0) {

#ifdef _RC_DEBUG_
     printf("\n\nBegin Q2 Rate Control {pre-encoding}:\n");
     printf("------------------------------------\n\n");
#endif /*_RC_DEBUG_*/
    
     numVOs = rc_mvo.numVOs;
     for(i=0; i<numVOs; i++)
	InitialTargetEstimate((Float)rc_MAD[i], i, numVOs); 

     AdjustDistribParams(numVOs);
     T = JointBuffer(numVOs);
     TargetDistribution(T, numVOs);

     for(i=0; i<numVOs; i++) {
	
	target_buff += rc_mvo.T[i];
	QuantCalculate(&Q, &rc_mvo.T[i], rc_mvo.headerBitCount[i], 
		(Double)rc_MAD[i], i, numVOs);

	target_curr += rc_mvo.T[i]; 

#ifdef _RC_DEBUG_
	printf("  ForVO%1d : old_Q = %2d, new_Q = %2d, ", i, (Int)Qlast[i], (Int)Q); 
#endif /*_RC_DEBUG_*/
 	rc_Q[i] = (Int)Q;
 	QSTEP[i] = (Int)Q;
	PutVopQuantizerVO(rc_Q[i], i);
	QuantAccumulate(rc_Q[i], i);
	Qlast[i] = Q;
#ifdef _RC_DEBUG_
  	printf("RCQ2_MVO_PreEncoding (vo_id=%3d) ==> %3d\n", i, rc_Q[i]);
#endif /*_RC_DEBUG_*/

    }

#ifdef _RC_DEBUG_
     printf("\ntotal target approx = %d\n", target_curr);
     printf("\nEnd Q2 Rate Control {pre-encoding}\n\n"); 
#endif /*_RC_DEBUG_*/
  }
  
#ifdef _RC_DEBUG_
  printf("\nQ2_Rate_Control : rc_MAD = %f, rc_Q = %d\n\n",rc_MAD[vo_id],rc_Q[vo_id]);
#endif /*_RC_DEBUG_*/

}

/***************************************************************************
  RCQ2_MVO_ShapeControl()
  ***************************************************************************/
Void RCQ2_MVO_ShapeControl(VolConfig *vol_config)
{

 /* set alpha threshold for shape coding */
 if(LOW_MODE){
	current_alpha_level = Min(ALPHA_MAX, current_alpha_level+ALPHA_INC);
	PutVolConfigAlphaTh(current_alpha_level,vol_config);
 }
 else {
	current_alpha_level = Max(current_alpha_level-ALPHA_DEC, ALPHA_MIN); 
	PutVolConfigAlphaTh(current_alpha_level,vol_config);
 }
 
}

/***************************************************************************
  RCQ2_MVO_UpdateVOCount()
  ***************************************************************************/
Void RCQ2_MVO_UpdateVOCount(Int vo_id)
{
  rc_mvo.codedVO[vo_id]++;
}

/***************************************************************************
  RCQ2_MVO_ExcludeIFrame()
  ***************************************************************************/
Void RCQ2_MVO_ExcludeIFrame(BitCount num_bits[MAX_NUM_VOS][MAX_NUM_VOLS], 
			    Int numVOs)
{
  Int vo_id;
  Int vol_id=0; /* Assume VOL ID is 0 */

  for(vo_id=0; vo_id<numVOs; vo_id++)
	rc_mvo.R -= num_bits[vo_id][vol_id].vop;

  /* Assume all VO coded with same rate */
  rc_mvo.Bpp = rc_mvo.R / (rc_mvo.numVOleft[0]+1);
#ifdef _RC_DEBUG_
  printf("rc_mvo.R = %ld, rc_mvo.Bpp = %f\n", rc_mvo.R, rc_mvo.Bpp); /*getchar();*/
#endif /*_RC_DEBUG_*/

}

/***************************************************************************
  RCQ2_MVO_Update2OrderModel()
  ***************************************************************************/
Void RCQ2_MVO_Update2OrderModel(BitCount num_bits[MAX_NUM_VOS][MAX_NUM_VOLS], Int numVOs)
{
  Int vopbits, vopheader;
  Int vo_id;
  Float afloat;
#if 0
  Void AdjustRateParams (Int, Int, Int);
  Void setTargetModelVO (Float, Float, Float, Float, Int);
#endif

  Int vol_id=0;
#ifdef _RC_DEBUG_
  FILE *fp;
#endif
  
#ifdef _RC_DEBUG_
 printf("Begin MVO Rate Control {post-encoding}:\n");
  printf("-------------------------------------\n\n");
#endif /*_RC_DEBUG_*/


  for(vo_id=0; vo_id<numVOs; vo_id++) {
   afloat = (Float)rc_Q[vo_id];
    vopbits = num_bits[vo_id][vol_id].vop;
    vopheader = num_bits[vo_id][vol_id].shape + num_bits[vo_id][vol_id].syntax +
      num_bits[vo_id][vol_id].motion;  /* modifoied by hjlee */
#ifdef _RC_DEBUG_
   printf("vopbits = %d, vopheader = %d, texture = %ld\n", vopbits, vopheader, num_bits[vo_id][vol_id].texture);
#endif /*_RC_DEBUG_*/

    AdjustRateParams (vopbits, vopheader, vo_id);
    setTargetModelVO (afloat, 
		     		(Float)vopbits, 
		    		(Float)vopheader,
				(Float)rc_MAD[vo_id], 
				vo_id);
#ifdef _RC_DEBUG_
    printf("  --> X1(%d) = %f\n",vo_id,rc_mvo.X1[vo_id]);
    printf("  --> X2(%d) = %f\n",vo_id,rc_mvo.X2[vo_id]);
#endif /*_RC_DEBUG_*/
  }
  
  rc_mvo.VBV_fullness -= rc_mvo.Bpp;
#ifdef _RC_DEBUG_
  printf ("  Buffer occupancy: %d bits (%d bytes) = %6.2f%% of buffer.\n\n", 
	  (Int) ceil (rc_mvo.VBV_fullness), 
	  ((Int) ceil (rc_mvo.VBV_fullness) + 7) /8, 
	  rc_mvo.VBV_fullness * 100.0 / rc_mvo.VBV_size);
#endif /*_RC_DEBUG_*/

  if (rc_mvo.VBV_fullness > rc_mvo.VBV_size) {
    buffer_overflow ++;
#ifdef _RC_DEBUG_
    fprintf(stdout,"Warning: buffer overflow \n");
#endif /*_RC_DEBUG_*/
  }
  else if (rc_mvo.VBV_fullness < 0.0) {
    buffer_underflow ++;
#ifdef _RC_DEBUG_
    fprintf(stdout,"Warning: buffer underflow \n");
#endif /*_RC_DEBUG_*/
  }

#ifdef _RC_DEBUG_
  if((fp = fopen("buffer.dat","a"))==NULL) {
	printf("Error opening buffer.dat for writing\n\n");
	exit(1); }
  fprintf(fp,"%6.2f\n", rc_mvo.VBV_fullness * 100.0 / rc_mvo.VBV_size);
  printf("%6.2f\n", rc_mvo.VBV_fullness * 100.0 / rc_mvo.VBV_size);
  fclose(fp);
#endif /*_RC_DEBUG_*/

}

/***************************************************************************
  RCQ2_MVO_SkipControl()
  ***************************************************************************/
Void RCQ2_MVO_SkipControl(Int doskip, Int numVOs)
{
  Int vo_id;
  Int occupancy;
  Int i, hdr_tot=0, last_tot=0;

  for(i=0; i<numVOs; i++) {
	hdr_tot += rc_mvo.headerBitCount[i];
	last_tot += rc_mvo.S[i];
  }

  /* Only "frame" skipping is employed	  */
  /* VOs can not be skipped independently */

 if (doskip) {
     occupancy = (rc_mvo.VBV_fullness+last_tot-rc_mvo.Bpp)*100/rc_mvo.VBV_size;
     while ((occupancy > SKIP_MARGIN_MVO) && 
	    (rc_mvo.numVOleft[0] > rc_mvo.skip[0])) {

           rc_mvo.skip[0]++;
           rc_mvo.totalskipped[0]++;
	   occupancy -=  rc_mvo.Bpp*100/rc_mvo.VBV_size;
     }
  }

#ifdef _RC_DEBUG_

  printf("  N_skip_pre : %d\n", rc_mvo.preskip[0]);
  printf("  N_skip_post: %d\n", rc_mvo.skip[0]);
  printf("  ----------------\n"); 
#endif /*_RC_DEBUG_*/

  rc_mvo.skip[0] += rc_mvo.preskip[0];
#ifdef _RC_DEBUG_
  printf("  Total skip : %d\n\n", rc_mvo.skip[0]);
#endif /*_RC_DEBUG_*/

  rc_mvo.totalskipped[0] += rc_mvo.preskip[0];
  for(vo_id=0; vo_id<numVOs; vo_id++) {
	rc_mvo.skip[vo_id] = rc_mvo.skip[0];
	rc_mvo.totalskipped[vo_id] = rc_mvo.totalskipped[0];
	rc_mvo.preskip[vo_id] = rc_mvo.preskip[0];
  }
  rc_mvo.preskip[0] = 0;

  /* Determine mode of operation */
  if(rc_mvo.skip[0] > SKIP_TH)
	LOW_MODE = 1;
  else 
	LOW_MODE = 0;
	
#ifdef _RC_DEBUG_
  printf("End Q2 Rate Control {post-encoding}\n\n");
#endif /*_RC_DEBUG_*/

}

/***************************************************************************
  RCQ2_MVO_ResetBitCounts()
  ***************************************************************************/
Void RCQ2_MVO_ResetBitCount(BitCount num_bits[MAX_NUM_VOS][MAX_NUM_VOLS], Int numVOs)
{
  Int vo_id;
  Int vol_id = 0;

  for(vo_id=0; vo_id<numVOs; vo_id++) {
	num_bits[vo_id][vol_id].syntax = 0;
	num_bits[vo_id][vol_id].shape = 0;
	num_bits[vo_id][vol_id].texture = 0;
	num_bits[vo_id][vol_id].motion = 0;
	num_bits[vo_id][vol_id].mot_shape_text = 0;
	num_bits[vo_id][vol_id].vop = 0;
  }
#ifdef _RC_DEBUG_
  printf("RCQ2_MVO_ResetBitCount -- num_bits all clear\n"); 
#endif /*_RC_DEBUG_*/
}

/***************************************************************************
  RCQ2_MVO_WriteRepeat()
  ***************************************************************************/
Int RCQ2_MVO_WriteRepeat(Int vo_id)
{
   return (rc_mvo.skip[vo_id]);
}

/***************************************************************************
  RCQ2_MVO_EndStats()
  ***************************************************************************/
Void RCQ2_MVO_EndStats(Int numVOs, BitCount num_bits[MAX_NUM_VOS][MAX_NUM_VOLS])
{
  Int i;
  FILE *fp;
  LInt total=0;

  fp = fopen("stats.mvo","w");

  for(i=0; i<numVOs; i++) {
	fprintf(fp,"\nVO%d\n", i);
  	PrintAverageQuant(i,fp);
	fprintf(fp,"  Average PSNR: %5.2f\n",num_bits[i][0].psnr_y_ave);
	fprintf(fp,"  Num Coded: %d\n",rc_mvo.codedVO[i]+((i==0)?0:1));
	total += num_bits[i][0].vol;
  }
  fprintf(fp,"\nTotal bits used: %ld\n",total);
  fprintf(fp,"buffer overflows:%d  underflow:%d\n",
          buffer_overflow, buffer_underflow);
  fclose(fp);

}


