/*****************************************************************************
 *                                                                          
 * This software module was originally developed by 
 *
 * J. Ignacio Ronda (UPM-GTI / ACTS-MoMuSys)
 *                                                      
 * and edited by                                        
 *                                                      
 * Martina Eckert       (UPM-GTI / ACTS-MoMuSys)
 * Fernando Jaureguizar (UPM-GTI / 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) 1997
 *
 *****************************************************************************/

/***********************************************************HeaderBegin*******
 *                                                                         
 * File:        rc_q2data.c
 *
 * Author:      J. Ignacio Ronda, UPM-GTI
 * Created:     18-06-97
 *                                                                         
 * Description: Functions of Q2 data type
 *
 * Flags:       -D_RC_DEBUG_  -  RC debugging   
 *
 * Modified:
 *      16.10.97  Fernando Jaureguizar: Non decreased the numFrame in rcQ2_init()
 *                This is made now in RCQ2_ExcludeIFrame().
 *      13.11.97  M. Eckert: Headers, comments, cleaning
 *	18.11.97  M. Wollborn: include unistd only for non-PC
 *      27.11.97  M. Eckert: Changes for independent frame type control
 *
 ***********************************************************HeaderEnd*********/

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

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#if !defined(WIN32)
#  include <unistd.h>
#endif

#include <ctype.h>

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

#include "rc.h"

/***********************************************************CommentBegin******
 *
 * -- rcQ2_print --
 *
 * Author : 
 *      J. Ignacio Ronda, UPM-GTI     
 *
 * Created :            
 *      18-06-97
 *
 * Purpose :
 *      Type printing function
 *
 * Arguments in :       
 *      RCQ2_DATA   *rcc     -  Q2 RC data
 *      FILE        *file    -  Output file
 *      char        *prefix  -  Prefix for printouts
 *
 *
 * Modified : 
 *
 *
 ***********************************************************CommentEnd********/

void rcQ2_print(
                RCQ2_DATA *rcc, 
                FILE      *file, 
                char      *prefix
                )
{
  fprintf(file, "%s bit_rate=       %d\n", prefix, rcc->bit_rate);
  fprintf(file, "%s R=              %d\n", prefix, rcc->R);
  fprintf(file, "%s numFrame=       %d\n", prefix, rcc->numFrame);
  fprintf(file, "%s num_I_Frame=       %d\n", prefix, rcc->num_I_Frame);
  fprintf(file, "%s num_B_Frame=       %d\n", prefix, rcc->num_B_Frame);
  fprintf(file, "%s num_P_Frame=       %d\n", prefix, rcc->num_P_Frame);
  fprintf(file, "%s VBV_size=       %d\n", prefix, rcc->VBV_size);
  fprintf(file, "%s VBV_fullness=   %d\n", prefix, rcc->VBV_fullness);
  fprintf(file, "%s Bpp=            %f\n", prefix, rcc->Bpp);
  fprintf(file, "%s totalskipped=   %d\n", prefix, rcc->totalskipped);  fprintf(file, "%s skip=           %d\n", prefix, rcc->skip);
  fprintf(file, "%s codedFr=        %d\n", prefix, rcc->codedFr);
  fprintf(file, "%s dataNumber=     %d\n", prefix, rcc->dataNumber);
  fprintf(file, "%s headerBitCount= %d\n", prefix, rcc->headerBitCount);
  fprintf(file, "I-frames: \n");
  fprintf(file, "%s X1=             %f\n", prefix, rcc->X1[0]);
  fprintf(file, "%s X2=             %f\n", prefix, rcc->X2[0]);
  fprintf(file, "%s QPfirst=        %d\n", prefix, rcc->QPfirst[0]);
  fprintf(file, "P-frames: \n");
  fprintf(file, "%s X1=             %f\n", prefix, rcc->X1[1]);
  fprintf(file, "%s X2=             %f\n", prefix, rcc->X2[1]);
  fprintf(file, "%s QPfirst=        %d\n", prefix, rcc->QPfirst[1]);
  fprintf(file, "B-frames: \n");
  fprintf(file, "%s X1=             %f\n", prefix, rcc->X1[2]);
  fprintf(file, "%s X2=             %f\n", prefix, rcc->X2[2]);
  fprintf(file, "%s QPfirst=        %d\n", prefix, rcc->QPfirst[2]);
}

/***********************************************************CommentBegin******
 *
 * -- rcQ2_init --
 *
 * Author : 
 *      J. Ignacio Ronda, UPM-GTI     
 *
 * Created :            
 *      18-06-97
 *
 * Purpose :
 *      Initialization
 *
 * Arguments in :       
 *      RCQ2_DATA   *rcd         -  Q2 RC data
 *      Int         start        -  First input frame to process
 *      Int         end          -  Last input frame to process
 *      Int         intra_period -  # of frames between I frames +1
 *      Int         M            -  # of B frames between P frames +1
 *      Int         frame_inc    -  Frame temporal subsampling factor
 *      Float       frame_rate   -  Input frame rate (frames per second)
 *      Int         bit_rate     -  Individual bit-rate (bits per second) 
 *      Int         qp_first     -  QP to use the first time RC is employed  
 *      Int         VBV_size     -  Individual buffer size 
 *      Int         VBV_fullness -  Initial buffer occupancy 
 *
 * Modified : 
 *      16.10.97  F. Jaureguizar: Non decreased the numFrame in rcQ2_init()
 *                This is made now in RCQ2_ExcludeIFrame().
 *      27.11.97  M. Eckert: Changes for independent frame type control
 *      19.02.98  J. Ribas: Added a default low-delay 0.125 sec buffer 
 *                for VM8 macroblock rate control
 *
 ***********************************************************CommentEnd********/

void rcQ2_init(
               RCQ2_DATA  *rcd,
	       VolConfig *vol_config,
               Int *qp_first  /* QP to use the first time RC is employed */
               )
{
   Int   i, frame_inc, start, end, num_frames[3];
   Float frame_rate;

   start = GetVolConfigStartFrame(vol_config);
   end   = GetVolConfigEndFrame(vol_config);
   frame_rate = GetVolConfigFrameRate(vol_config);
   frame_inc  = GetVolConfigFrameSkip(vol_config);

   rcd->bits_P_ave = 0;

   rcd->alpha_I = 3;
   rcd->alpha_B = 0.5;
   rcd->bit_rate = GetVolConfigBitrate(vol_config);
   rcd->R = (Int) (rcd->bit_rate*(end-start+1)/(frame_rate*frame_inc));

   rc_count_frames(vol_config, num_frames, &rcd->numFrame);

   rcd->num_I_Frame = num_frames[0];
   rcd->num_P_Frame = num_frames[1];
   rcd->num_B_Frame = num_frames[2];

   /* Initialization of buffer: */

   /* ------------------------------------------ */
   /* SHARP_start                                */
   if (Q2MB_ACTIVE == RCQ2_MB_active(Q2MB_CHECK))
       {
       /* choosing a default 0.125 sec (low delay) buffer VM8 macroblock
          rate control */

       rcd->VBV_size = rcd->bit_rate/8;        
       rcd->VBV_fullness = rcd->bit_rate/16;     /* 0.5*rcc->VBV_size */

#ifdef _RC_DEBUG_
       fprintf(stdout,"rcQ2_init: using low-delay 125 milisec buffer for \n");
       fprintf(stdout,"           VM8 macroblock rate control. Buffer size: %d \n", 
               rcd->VBV_size);
#endif
       }
   else
     { 
       /* choosing a default 0.5 sec buffer for VM5 rate control */
       rcd->VBV_size = rcd->bit_rate/2;         /* 0.5 * rate */
       rcd->VBV_fullness = rcd->bit_rate/4;     /* 0.5*rcc->VBV_size */
     }
   /* SHARP_end                                  */
   /* ------------------------------------------ */
 
   rcd->Bpp = 0; 


   /* Initialization of model parameters: */

   if ((rcd->X1=(Double *)calloc(sizeof(Double),3))==0)
      error_exit("RC: ERROR: calloc rcd->X1\n");
   if ((rcd->X2=(Double *)calloc(sizeof(Double),3))==0)
      error_exit("RC: ERROR: calloc rcd->X2\n");
   for (i=0; i<3; i++){
      rcd->X1[i] = rcd->bit_rate*frame_inc/2; /* Initial value specified in VM, 
					    but only used if the first model 
					    updating is delayed (by setting 
					    START_MODEL_UPDATING > 1) */
      rcd->X2[i] = 0;
   }

   rcd->skip = 0;
   rcd->totalskipped = 0;
   rcd->codedFr = 0;
   rcd->dataNumber = 0;
   rcd->headerBitCount = 1500; /* ????? */

   if ((rcd->QPfirst=(Int *)calloc(sizeof(Int),3))==0)
      error_exit("RC: ERROR: calloc rcd->QPfirst\n");
   for (i=0; i<3; i++)
      rcd->QPfirst[i] = qp_first[i];

#ifdef _RC_DEBUG_
   rcQ2_print(rcd, stdout, "RC: RCQ2_INIT");
#endif
   fflush(stdout);
}


/***********************************************************CommentBegin******
 *
 * -- rcQ2_update --
 *
 * Author : 
 *      J. Ignacio Ronda, UPM-GTI     
 *
 * Created :            
 *      18-06-97
 *
 * Purpose :
 *      Updating after encoding of a frame
 *
 * Arguments in :       
 *      RCQ2_DATA   *rcc         -  Q2 RC data
 *      RC_HIST     *rch         -  RC history data
 *      Int         vopbits      -  number of bits needed to code frame
 *      Int         frame_type   -  I=0, P=1, B=2
 *
 * Modified : 
 *      27.11.97  M. Eckert: Changes for independent frame type control
 *
 ***********************************************************CommentEnd********/

void rcQ2_update(
		 RCQ2_DATA *rcc,
		 RC_HIST   *rch,
                 Int        vopbits,
		 Int        frame_type
                )
{
   rcc->R -= vopbits;
   rcc->numFrame --;
   
   if (frame_type == I_VOP) rcc->num_I_Frame --;
   else if (frame_type == B_VOP) rcc->num_B_Frame --;
   else if (frame_type == P_VOP) rcc->num_P_Frame --;
   else error_exit("ERROR: rcQ2_update for other frame than I,B,P ! \n");


   /* Update of alpha weights (assignation of individual bit amounts to 
      different frame types) */

   if (frame_type == P_VOP){
      rcc->bits_P_ave = rch_get_total_bits(rch)/rch_get_total_frames(rch);
      fprintf(stdout, "bits_P_ave = %.1f \n",rcc->bits_P_ave);
   }
   else
      if (rcc->bits_P_ave != 0) /* still no P-VOP coded */
	 if (frame_type == I_VOP){
	    rcc->alpha_I = rch_get_total_bits(rch)/rch_get_total_frames(rch)/
	       rcc->bits_P_ave;
	    fprintf(stdout, "alpha_I = %f \n",rcc->alpha_I);
	 }
	 else if (frame_type == B_VOP){
	    rcc->alpha_B = rch_get_total_bits(rch)/rch_get_total_frames(rch)/
	       rcc->bits_P_ave;
	    fprintf(stdout, "alpha_B = %f \n",rcc->alpha_B);
	 }
	 else 
	    error_exit("ERROR rcQ2_update: Unknown frame type! \n"); 
      else fprintf(stdout, "rcQ2_update: Still no alpha update \n");

   if (frame_type == I_VOP) /* recalculation of buffer-emptier Bpp */
      rcc->Bpp = rcc->R / (Int)( rcc->alpha_I * rcc->num_I_Frame
			    + rcc->alpha_B * rcc->num_B_Frame
			    + rcc->num_P_Frame);

   if (rcc->codedFr != 0)
      if (frame_type == P_VOP)
	 rcc->VBV_fullness += (Int)(vopbits-rcc->Bpp);
      else
	 if (frame_type == I_VOP)
	    rcc->VBV_fullness += (Int)(vopbits-(rcc->alpha_I*rcc->Bpp));
	 else if (frame_type == B_VOP)
	    rcc->VBV_fullness += (Int)(vopbits-(rcc->alpha_B*rcc->Bpp));
 
   rcc->codedFr ++;


#ifdef _RC_DEBUG_
   fprintf(stdout, "rcQ2_update: R= %.1f  numFrame= %d\n",
           (double)rcc->R, rcc->numFrame);
#endif
}

/*********************************************************** End of file ***/
