/*****************************************************************************
 *                                                                          
 * This software module was originally developed by 
 *
 * J. Ignacio Ronda (UPM-GTI / ACTS-MoMuSys)
 *                                                                      
 * and edited by                                                        
 *
 * Martina Eckert (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_util.c
 *
 * Author:      J. Ignacio Ronda, UPM-GTI
 * Created:     18-06-97
 *                                                                         
 * Description: Utility functions
 *
 * Flags:       -D_RC_DEBUG_  -  RC debugging   
 *
 * Modified:
 *      13.11.97  Martina Eckert: Headers, comments, cleaning
 *	18.11.97  M.Wollborn: include unistd only for non-PC
 *
 ***********************************************************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"
#include "rc_mvo.h"

#define MAX_NUM_COEFS 5
#define MAX_NUM_DATA 100


/***********************************************************CommentBegin******
 *
 * -- rc_2ls_comp_q2 --
 *
 * Author : 
 *      J. Ignacio Ronda, UPM-GTI     
 *
 * Created :            
 *      18-06-97
 *
 * Purpose :
 *      LS adjustment of a function of two variables:
 *             y[i] = p1*x1[i]+p2*x2[i]
 *      The adjustment is numerically less precise than the one provided 
 *      by the function rc_2ls_comp_upm.
 *
 * Arguments in :       
 *          Double *y   -  rate / mad
 *          Double *x1  -  1/qp
 *          Int     n   -  Number of data 
 *
 * Arguments out :       
 *          Double *p1  -  model parameter 1
 *          Double *p2  -  model parameter 2
 *
 * Modified : 
 *
 *
 ***********************************************************CommentEnd********/

void rc_2ls_comp_q2(
                    Double *y,
                    Double *x1,
                    Int     n,  /* Number of data */
                    Double *p1,
                    Double *p2
                    )
{
   Int i, j, k;
   Double y1=0, x11=0, x12=0, x22=0;
   Double XtXinv[3][3], X[MAX_NUM_DATA][3], Y2[MAX_NUM_DATA],
      XtXinvXt[3][MAX_NUM_DATA];
   Double d=0.;
   Int different_qps=0;
   
#ifdef _RC_DEBUG_
   for (i=0; i<n; i++)
      fprintf(stdout, "rc_2ls_comp_q2: y[%d]=%f, x1[%d]=%f \n", i, y[i],
              i,  x1[i]);
#endif

   for (i=1; i<=n; i++)
   {
      X[i][1] = 1;
      X[i][2] = x1[i-1];
      Y2[i] = y[i-1]/x1[i-1];
#ifdef _RC_DEBUG_
      printf("X[%d][1]= %f  X[%d][2]= %f  Y2[%d]= %f\n", i, X[i][1], i, X[i][2],
             i, Y2[i]);
#endif
   }

   for (i=1; i<n; i++)
      if (x1[i] != x1[i-1])
      {
         different_qps=1;
         break;
      }

   for (i=1; i<=n; i++)
   {
      y1  += Y2[i]*X[i][1];
      x11 += X[i][1]*X[i][1];
      x12 += X[i][1]*X[i][2];
      x22 += X[i][2]*X[i][2];
   }

   printf("x11= %f  x12= %f  x22= %f\n",
          x11, x12, x22);

   if (different_qps)
   {
      d = x11*x22-x12*x12;
      XtXinv[1][1] =  x22/d;
      XtXinv[1][2] = -x12/d;
      XtXinv[2][1] = -x12/d;
      XtXinv[2][2] =  x11/d;
#ifdef _RC_DEBUG_
      printf("XtXinv[1][1]= %f  XtXinv[1][2]= %f  XtXinv[2][1]= %f  XtXinv[2][2]= %f\n",
             XtXinv[1][1], XtXinv[1][2], XtXinv[2][1], XtXinv[2][2]);
#endif
      if (d==0)
      {
         fprintf(stdout, "rc_2ls_comp_q2: Error: d==0\n");
         exit(1);
      }
      for (i=1; i<=2; i++)
         for (j=1; j<=n; j++)
         {
            XtXinvXt[i][j]=0;
            for (k=1; k<=2; k++)
               XtXinvXt[i][j] += XtXinv[i][k]*X[j][k];
            printf("XtXinvXt[%d][%d]= %f\n", i, j, XtXinvXt[i][j]);
         }
      *p1 = 0;
      *p2 = 0;
      for (k=1; k<=n; k++)
      {
         *p1 += XtXinvXt[1][k]*Y2[k];
         *p2 += XtXinvXt[2][k]*Y2[k];
      }
     
   }
   else /* All QPs are equal: First order approximation */
   {
      *p1 = y1/x11;
      *p2 = 0;
   }

   return;
}

/***********************************************************CommentBegin******
 *
 * -- rc_2ls_comp_upm --
 *
 * Author : 
 *      J. Ignacio Ronda, UPM-GTI     
 *
 * Created :            
 *      18-06-97
 *
 * Purpose :
 *      LS adjustment of a function of two variables:
 *             y[i] = p1*x1[i]+p2*x2[i]
 *      The adjustment is numerically more precise than the one 
 *      provided by the previous function.
 *
 * Arguments in :       
 *          Double *y   -  rate / mad
 *          Double *x1  -  1/qp
 *          Double *x2  -  1/(qp^2)
 *          Int     n   -  Number of data 
 *
 * Arguments out :       
 *          Double *p1  -  model parameter 1
 *          Double *p2  -  model parameter 2
 *
 * Modified : 
 *
 *
 ***********************************************************CommentEnd********/

void rc_2ls_comp_upm(
                     Double *y,
                     Double *x1,
                     Double *x2,
                     Int     n,  /* Number of data */
                     Double *p1,
                     Double *p2
                     )
{
   Int i;
   Double y1=0, y2=0, x11=0, x12=0, x22=0;
   Double d=0.;
   Int different_qps=0;

#ifdef _RC_DEBUG_
   for (i=0; i<n; i++)
      fprintf(stdout, "rc_2ls_comp_upm: y[%d]=%f, x1[%d]=%f, x2[%d]=%f\n", i, y[i],
              i,  x1[i], i, x2[i]);
#endif

   /* Default Model Parameters
      *p1 = 0;
      *p2 = 0;
      for (i=1; i <= n; i++)
      *p1 += y[i-1]/x1[i-1] / n;

      if (n==1)
      return;
   */

   for (i=1; i<n; i++)
      if (x1[i] != x1[i-1])
      {
         different_qps=1;
         break;
      }

   for (i=0; i<n; i++)
   {
      y1  += y[i]*x1[i];
      y2  += y[i]*x2[i];
      x11 += x1[i]*x1[i];
      x12 += x1[i]*x2[i];
      x22 += x2[i]*x2[i];
   }

   if (different_qps)
   {
      d = x11*x22-x12*x12;

#ifdef _RC_DEBUG_
      fprintf(stdout, "rc_2ls_comp_upm: x11= %f  x12= %f  x22= %f  y1= %f  y2= %f\n", x11, x12, x22, y1, y2);
      fprintf(stdout, "rc_2ls_comp_upm: d= %E\n", d);
#endif
      if (d==0)
      {
         fprintf(stdout, "rc_2ls_comp_upm: Error: d==0\n");
         exit(1);
      }
      *p1 = (y1*x22-y2*x12)/d;
      *p2 = (y2*x11-y1*x12)/d;
   }
   else /* All QPs are equal: First order approximation */
   {
      *p1 = y1/x11;
      *p2 = 0;
   }

return;
}

/***********************************************************CommentBegin******
 *
 * -- rc_2ls_remove_out --
 *
 * Author : 
 *      J. Ignacio Ronda, UPM-GTI     
 *
 * Created :            
 *      18-06-97
 *
 * Purpose :
 *      Outlier data removing
 *
 * Arguments in :       
 *      Int     n   -  Number of data 
 *      Double  mad -  MAD
 *
 * Arguments in/out :       
 *      Double *y   -  rate / mad
 *      Double *x1  -  1/qp
 *      Double *x2  -  1/(qp^2)
 *      Double *p1  -  model parameter 1
 *      Double *p2  -  model parameter 2
 *
 * Modified : 
 *
 *
 ***********************************************************CommentEnd********/


void rc_2ls_remove_out(
                       Double *y,
                       Double *x1,
                       Double *x2,
                       Int    *n,
                       Double *p1,
                       Double *p2
                       )
{
   Int i, j;
   Double ec=0, sigma;

#ifdef _RC_DEBUG_
   fprintf(stdout, "RC: --> rc_2ls_remove_out: n= %d\n", *n);
#endif

   /* Sigma computation */
   for (i=0; i<*n; i++)
      ec += CUAD(y[i]-(*p1)*x1[i]-(*p2)*x2[i]);

   sigma=sqrt(ec/(*n));

#ifdef _RC_DEBUG_
   fprintf(stdout, "RC: rc_2ls_remove_out: sigma= %f \n", sigma);
#endif

   for (i=0,j=0; i<*n; i++)
   {
#ifdef _RC_DEBUG_
      fprintf(stdout, "RC: rc_2ls_remove_out: error[%d]: %E - %E = %E \n", i, y[i], (*p1)*x1[i]+(*p2)*x2[i], y[i]-(*p1)*x1[i]-(*p2)*x2[i]);
#endif
      if (ABS(y[i]-(*p1)*x1[i]-(*p2)*x2[i])<sigma
#ifndef _RC_VM_IMP_
          || i == 0
#endif
          )
      {
         y[j]=y[i];
         x1[j]=x1[i];
         x2[j]=x2[i];
         j++;
      }
   }
#ifdef _RC_DEBUG_
   fprintf(stdout, "RC: <-- rc_2ls_remove_out: Remaining %d data from %d\n", j, *n);
#endif

   *n=j;
}

/***********************************************************CommentBegin******
 *
 * -- error_exit --
 *
 * Author : 
 *      J. Ignacio Ronda, UPM-GTI     
 *
 * Created :            
 *      18-06-97
 *
 * Purpose :
 *      Print and exit function.
 *
 * Arguments in :       
 *      char *string  -  Exit string
 *
 * Modified : 
 *
 *
 ***********************************************************CommentEnd********/

void error_exit(
                char *string
                )
{
   fprintf(stdout, string);
   exit(1);
}

/***********************************************************CommentBegin******
 *
 * -- DSRC_compute_MAD --
 *
 * Author : 
 *      J. Ignacio Ronda, UPM-GTI     
 *
 * Created :            
 *      18-06-97
 *
 * Purpose :
 *      Print and exit function.
 *
 * Arguments in :       
 *      Vop    *error_vop  - Vop with error residue
 *      UInt   *pel_vop    - Vop with image data
 *
 * Modified : 
 *
 *
 ***********************************************************CommentEnd********/

Double DSRC_compute_MAD(
                        Vop  *error_vop, 
                        UInt *pel_vop
                        )
{
     SInt  *curr_in,
           *curr_end,
           *curr_a;
     Float *curr_fin,
           *curr_fend,
           *curr_fa;
     UInt   sxy_in;
     Double mad=0.0;
     Int    cnt=0;


    /* Calculate the MAD for the Multiple-VO case. */
     switch (GetImageType(error_vop->y_chan)) {
         case SHORT_TYPE:
            curr_in = GetImageIData(error_vop->y_chan);
            curr_a = GetImageIData(error_vop->a_chan);
            sxy_in = GetImageISize(error_vop->y_chan);
            curr_end = curr_in + sxy_in;
            cnt = 0;
            while (curr_in != curr_end)
              {
                if (*curr_a) {
                   mad += abs(*curr_in);
                   cnt++;
                }
                curr_in++;
                curr_a++;
              }
            mad /= cnt;     
            break;
         case FLOAT_TYPE:
            curr_fin = GetImageFData(error_vop->y_chan);
            curr_fa = GetImageFData(error_vop->a_chan);
            sxy_in = GetImageFSize(error_vop->y_chan);
            curr_fend = curr_fin + sxy_in;
            cnt = 0;
            while (curr_fin != curr_fend)
              {
                if (*curr_fa) {
                   mad += abs(*curr_fin);
                   cnt++;
                }
                curr_fin++;
                curr_fa++;
              }
            mad /= cnt;     
            break;
        default: break;
     }

     *pel_vop = cnt;

     return mad;
}


/***********************************************************CommentBegin******
 *
 * -- rc_linear --
 *
 * Author : 
 *      J. Ignacio Ronda, UPM-GTI     
 *
 * Created :            
 *      18-06-97
 *
 * Purpose :
 *      LS adjustment of a linear function:
 *             y[i] = p1*x1[i]+p3
 *      in case of a non-decreasing model function in 
 *      the interval (x_min, x_max).
 *
 * Arguments in :       
 *      Double *y   -  rate / mad
 *      Double *x1  -  1/qp
 *      Double *x2  -  1/(qp^2)
 *      Int     n   -  Number of data 
 *
 * Arguments out :       
 *      Double *p1  -  model parameter 1
 *      Double *p2  -  model parameter 2
 *      Double *p3  -  model parameter 3
 *
 * Modified : 
 *
 *
 ***********************************************************CommentEnd********/

void rc_linear(
               Double *y,
               Double *x1,
               Double *x2,
               Int     n,  /* Number of data */
               Double *p1,
               Double *p2,
               Double *p3
               )
{
   Double sum[4], d;
   Int i;

#ifdef _RC_DEBUG_
   fprintf(stdout,"RC: Update with linear model \n");
#endif

   for (i=0; i<4; i++) sum[i] = 0.0;

   /* Calculation of sums: */

   for (i=0; i<n; i++)
   {
#ifdef _RC_DEBUG_
      fprintf(stdout,"x1[%d] = %f x2[%d] = %f y[%d] = %f \n",i, x1[i], i, x2[i],
 i, y[i]);
#endif
      sum[0] += x1[i] * y[i];
      sum[1] += x2[i];
      sum[2] += x1[i];
      sum[3] += y[i];
   }

   /* Solution of equations: */

   d = sum[1]*n - sum[2]*sum[2];
   if (d == 0.)
   {
      fprintf(stdout,"RC - Linear model: d=0. Model not changed! \n");
      return;
   }
   *p1 = (sum[0]*n - sum[2]*sum[3] ) / d;
   *p3 = (sum[0] - *p1 * sum[1]) / sum[2];

   *p2 = 0;

}

/***********************************************************CommentBegin******
 *
 * -- rc_decide --
 *
 * Author : 
 *      J. Ignacio Ronda, UPM-GTI     
 *
 * Created :            
 *      18-06-97
 *
 * Purpose :
 *      Checks whether function p1*x+p2*x^2 is non-decreasing in
 *      the interval (x_min, x_max).
 *
 * Arguments in :       
 *      Double p1    -  model parameter 1
 *      Double p2    -  model parameter 2
 *      Double x_min -  minimum qp
 *      Double x_max -  maximum qp
 *
 * Return values :      
 *     1 for model ok
 *     0 for model not ok      
 *
 * Modified : 
 *
 *
 ***********************************************************CommentEnd********/

Int rc_decide(
              Double p1,
              Double p2,
              Double x_min,
              Double x_max
              )
{
   Double p;
   
   if (p2 == 0)
     {
     if (p1 >= 0) return 1;
     else return 0;
     }
   else
     {
     p = -p1 / (2 * p2); /* p: point where derivative = 0 */

     if ((p<x_min && p2>0) || (p>x_max && p2<0))
        return 1;
     else
        return 0;
     }
}

/***********************************************************CommentBegin******
 *
 * -- rc_get_ctl_parameters --
 *
 * Author : 
 *      M. Eckert, UPM-GTI     
 *
 * Created :            
 *      12-12-97
 *
 * Purpose :
 *      Reads the RC parameters from input strings from .ctl file
 *      needed for RC_init_global. (All except rc_type which is
 *      used before and extracted by GetEncodeControlRCType).
 *
 * Arguments in :       
 *      Char *rc_ctl_string  -  RC parameter string 
 *
 * Arguments out :       
 *  	Int  rc_algorithm     - RC algorithm 
 *	Int  rc_rate_model    - RC rate model
 *	Int  rc_dist_model    - RC distortion model
 *	Int  R_target         - Global target rate 
 *	Int  glob_buffer_size - Global buffer size 
 *	Int  mode             - Mode for distortion model
 *
 *
 * Modified : 
 *      19.02.98  Jordi Ribas: added call to activate Q2 VM8 macroblock rate control
 *
 ***********************************************************CommentEnd********/

Void rc_init_ctl_parameters(
			  Char *rc_ctl_string,
			  Int  *rc_algorithm,
			  Int  *rc_rate_model,
			  Int  *rc_dist_model,
			  Int  *R_target,
			  Int  *glob_buffer_size,
			  Int  *mode
			  )
{

   Int p=0;
   Char *string[6], sep_char[2], dummy[1000];

   sep_char[0]='|';

   /* ----------- */
   /* SHARP_start */

   /* If sep_char had only one char, strtok below crashes */
   sep_char[1]='\0';

   /* SHARP_end   */
   /* ----------- */

   printf("input string: %s \n",rc_ctl_string);
   strcpy(dummy, rc_ctl_string); /* Ojo, chapuza del 19.01.98 por fallo en la memoria!? */

#ifdef _RC_DEBUG_
   printf("input string: %s \n",dummy);
#endif

   if ((string[0] = strtok(dummy, sep_char)) == NULL)
     error_exit("ERROR rc_get_ctl_parameters: No parameters for RC selected! \n");

   /*** First parameter: ***/

   /* rc_algorithm: */
   if (*string[0] == '*'){
      fprintf(stdout,"RC - WARNING: No algorithm selected, set to 1 - UPM1 \n");
      *rc_algorithm = 1; /* default */
   }
   else
      sscanf(string[0],"%d",rc_algorithm);
   if (*rc_algorithm < 0 || *rc_algorithm > 2){
      *rc_algorithm = 1; /* default */
      fprintf(stdout,"RC - WARNING: Value for algorithm not allowed, set to %d - UPM%d \n",
	     *rc_algorithm, *rc_algorithm);
   }
#ifdef _RC_DEBUG_
   printf("string[%d]= %s\n",0,string[0]);
#endif


   /*** Loop for rest: ***/

   for (p = 1; p < 6; p++)
   {
#ifdef _RC_DEBUG_
      printf("Read string[%d] \n",p);
#endif
      if ((string[p] = strtok(NULL, sep_char)) == NULL)
	 string[p] = "*";

#ifdef _RC_DEBUG_
      printf("string[%d]= %s\n",p,string[p]);
#endif

   }

   /* ----------- */
   /* SHARP_start */

   /* This is a new parameter combination for indicating Q2 rate control with
      macroblock layer. Before, if string[0] was "0", the other parameters
      in the ctl file did not mean anything */
   
   if ((*string[0] == '0') && (*string[1] == '1'))   
     RCQ2_MB_active(Q2MB_ACTIVE);
   else 
     RCQ2_MB_active(Q2MB_INACTIVE);

   /* MVO RC -------------------------------------- */
   if ((*string[0] == '0') && (*string[1] == '2'))   
     RCQ2_MVO_SET(RCQ2_MVO_ENABLED);
   else if  ((*string[0] == '0') && (*string[1] == '3'))  
     RCQ2_MVO_SET(RCQ2_MVO_HVS);
   else
     RCQ2_MVO_SET(RCQ2_MVO_DISABLED);

   /* SHARP_end   */
   /* ----------- */


   /* rc_rate_model */
   if (*string[1] == '*'){
      *rc_rate_model = 1; /* default */
      fprintf(stdout,"RC - WARNING: No rate_model selected, set to %d - UPM \n", 
	      *rc_rate_model);
   }
   else
      sscanf(string[1],"%d",rc_rate_model);
   if (*rc_rate_model < 0 || *rc_rate_model > 1){
       *rc_rate_model = 1; /* default */
      fprintf(stdout,"RC - WARNING: Value for rate_model not allowed, set to %d - UPM \n",
	     *rc_rate_model);
   }
   if (*rc_algorithm == 0 && *rc_rate_model != 0)
      *rc_rate_model = 0; 
   if ((*rc_algorithm == 1 || *rc_algorithm == 2) && *rc_rate_model == 0)
      *rc_rate_model = 1; 
   
   /* rc_dist_model */
   if (*string[2] == '*'){
      *rc_dist_model = 1; /* default */
      fprintf(stdout,"RC - WARNING: Value for dist_model not allowed, set to %d - UPM \n",
	     *rc_dist_model);
   }
   else
      sscanf(string[2],"%d",rc_dist_model);
   if (*rc_dist_model < 0 || *rc_dist_model > 2){
      *rc_dist_model = 1; /* default */
      fprintf(stdout,"RC - WARNING: Value for dist_model not allowed, set to %d - UPM \n",
	     *rc_dist_model);
   }
   if (*rc_algorithm == 0 && *rc_dist_model != 0)
      *rc_dist_model = 0; 
   if ((*rc_algorithm == 1 || *rc_algorithm == 2) && *rc_dist_model == 0)
      *rc_dist_model = 1; 

   /* R_target */
   if (*string[3] == '*'){
      *R_target = 256000; /* default */
      fprintf(stdout,"RC - WARNING: No target rate specified, set to %d \n",*R_target);
   }
   else
      sscanf(string[3],"%d",R_target);

   /* glob_buffer_size */
   if (*string[4] == '*'){
      *glob_buffer_size = *R_target/2; /* default */
      fprintf(stdout,"RC - WARNING: No global buffer size specified, set to %d \n",*glob_buffer_size);
   }
   else
      sscanf(string[4],"%d",glob_buffer_size);

   /* mode */
   if (*string[5] == '*'){
      *mode = 0; /* default */
      fprintf(stdout,"RC - WARNING: No mode for distortion model specified, set to %d \n",*mode);
   }
   else
      sscanf(string[5],"%d",mode);
   if (*mode < 0 || *mode > 1){
      *mode = 0; /* default */
      fprintf(stdout,"RC - WARNING: Value for mode not allowed, set to %d \n", *mode);
   }

}


/***********************************************************CommentBegin******
 *
 * -- rc_count_frames --
 *
 * Author : 
 *      M. Eckert, UPM-GTI     
 *
 * Created :            
 *      6-2-98
 *
 * Purpose :
 *      Calculates number of frames for each type for individual 
 *      B,I,P target rate calculation.
 *
 * Arguments in :       
 *	     VolConfig *vol_config - list of VOL
 *
 * Arguments out :       
 *	     Int       *num_frames -   number of frames for each type 
 *                                     (0=I, 1=P, 2=B)
 *	     Int       *tot_frames -   total number of frames in sequence
 *
 *
 * Modified : 
 *
 *
 ***********************************************************CommentEnd********/

Void rc_count_frames(
		     VolConfig *vol_config,
		     Int       *num_frames,
		     Int       *tot_frames
		     )
{
  Int   rest1, IF, all_frames;
  Int   start, end, M, IP, frame_inc;

  start = GetVolConfigStartFrame(vol_config);
  end   = GetVolConfigEndFrame(vol_config);
  M     = GetVolConfigM(vol_config);
  IP    = GetVolConfigIntraPeriod(vol_config);
  frame_inc  = GetVolConfigFrameSkip(vol_config);

#ifdef _RC_DEBUG_
  Int   rest2;
#endif

  all_frames = (end-start+frame_inc)/frame_inc;
  *tot_frames = all_frames;

  IF = M * IP; /* IF-1 = Number of P+B frames between I frames */

#ifdef _RC_DEBUG_
  printf("RC-BIP ---> IF = %d \n",IF);
#endif

  /* Counting of B, I, P frames: */

  rest1 = all_frames % IF;

#ifdef _RC_DEBUG_

  rest2 = (rest1-1) % M;
  printf("rest1 = %d, rest2 = %d  \n", rest1, rest2);
  if (rest1 == 1)
    printf("Last frame = I-frame \n");
  else if (rest2 == 0) 
      printf("Last frame = P-frame \n");
  else  
    printf("Last frame = B-frame \n");

  if (rest1 == 0)
    rest2 = (IF-1)%M;

  printf("%d useless B-frames at the end! \n", rest2);
#endif

/* I frames: */
  num_frames[0] = (Int)ceil((float)all_frames / IF); 

/* P frames: */
  if (rest1) 
    num_frames[1] = (Int)(floor((IF - 1) / M) * (num_frames[0]-1)+(rest1-1)/M);
  else  
    num_frames[1] = (Int)(floor((IF - 1) / M) * num_frames[0]);

/* B frames: */
  num_frames[2] = all_frames - num_frames[1] - num_frames[0];
  
  printf("%d I, %d P, %d B \n",num_frames[0],num_frames[1],num_frames[2]);

  return;

}
/***********************************************************CommentBegin******
 *
 * -- rc_get_ActFrameType --
 *
 * Author : 
 *      M. Eckert, UPM-GTI     
 *
 * Created :            
 *      9-2-98
 *
 * Purpose :
 *      Reads the RC parameters from input strings from .ctl file
 *      needed for RC_init_global. (All except rc_type which is
 *      used before and extracted by GetEncodeControlRCType).
 *
 * Arguments in :       
 *	     VolConfig *vol_config - list of VOL
 *
 * Arguments out :       
 *
 *
 * Modified : 
 *
 *
 ***********************************************************CommentEnd********/

Int rc_get_ActFrameType(
			VolConfig *vol_config,
			Int       frame
			)
{
  Int frame_type, M, IP, IF, rest1, rest2, my_frame;

  my_frame = get_num_frames();
  frame = my_frame;
  /*  frameno = GetVolConfigFrame(vol_config); dont use! increments!  number of actually processed frame */
  M     = GetVolConfigM(vol_config);  /* M-1 = number of B between I/P */
  IP    = GetVolConfigIntraPeriod(vol_config); /* IP-1 = number of P between I */
  IF    = M*IP;    /* IF-1 = Number of P+B between I */


  /*  frame++;*/
  if (M == 1) /* no B frames */
  {
    /*
    printf("Actual frame number this Vol: %d \n",frame);
    printf("Actual frame number totally: %d \n",my_frame);
    */
    rest1 = frame % IP;
    if (rest1 == 0) frame_type = 0; /* I frame */
    else frame_type = 1;            /* P frame */
  }
  else
  {
    frame++;
    /*
    printf("Actual frame number: %d \n",frame);
    */
    rest1 = frame % M;
    rest2 = frame % IF;

  if (rest1 == 0)  frame_type = 2;  /* B frame */
  else if (rest1 == 1)
    if (rest2 == 1) frame_type = 0; /* I frame */
    else frame_type = 1;            /* P frame */
  else 
    frame_type = 2;                 /* B frame */
  }

 return frame_type;
}

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