/*****************************************************************************
 *                                                                          
 * This software module was originally developed 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_upm2.c
 *
 * Author:      Martina Eckert, UPM-GTI
 *
 * Created:     18-06-97
 *                                                                         
 * Description: UPM2 control functions
 *
 * Notes:       
 *
 * Flags:       -D_RC_DEBUG_  -  RC debugging   
 *
 * Modified:
 *      15.07.97 Martina Eckert: remove limitation of VO/VOL ID numbers.
 *      11.12.97 Martina Eckert: read RC Parameters from own struct RC_CFG_PARAM
 *      15.12.97 M. Eckert: New function get_rc_cfg_upm2
 *                          Introduction of "mode" for calculation of
 *                          distortion
 *      27.01.98 M. Eckert: Modifications in RC_UPM2_QuantAdjust()
 *      03.03.98 M. Eckert: Change bitrate form UInt to Int but convert it
 *                          to 0 for negative values
 *                                 
 ***********************************************************HeaderEnd*********/

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

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

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


#define MAX_DIFF 1E-3

static RC_HIST      rc_hist_upm[MAX_NUM_VOS][MAX_NUM_VOLS][3];  /* History of each VOL */
static RC_CFG_PARAM rc_cfg_upm[MAX_NUM_VOS][MAX_NUM_VOLS];   /* RC parameter */


/***********************************************************CommentBegin******
 *
 * -- find_dec --
 *
 * Author : 
 *      Martina Eckert, UPM-GTI     
 *
 * Created :            
 *      18-06-97
 *
 * Purpose :
 *      Recursive function to find the QP's if r_sum > R  
 * 
 * Arguments in :       
 *     Int    vo_id        - ID of current VO 
 *     Int    vol_id       - ID of current VOL
 *     Int    num_vols_tot - Number of VOPs 
 *     Int    p            - Position in priority list 
 *     LIST   pos[]        - Priority list 
 *     Int    q_min[][]    - qp which allows minimal distortion 
 *     Double R            - Number of bits 
 *     Int   (* rate)(RC_HIST *rch, Int vo_i, Int vol_i, 
 *      Int q, Double mad) - Rate functions 
 *     Double mad          - Current MAD 
 *     UInt   num_pels     - Number of pixels in object
 *     Double r_qp[][]     - Array of already known bit rates 
 *     Int    qp[][]       - --> Decisions 
 *     Int    frame_type   -  I=0, P=1, B=2
 *
 * Arguments in/out :   
 *      -
 *
 * Arguments out :      
 *      -
 *
 * Return values :      
 *     Double r_sum    -  Predicted bitrate for all VOs
 *
 * Side effects :       
 *      -
 *
 * Description :        
 *
 *
 * See also :
 *
 *
 * Modified :           
 *       05.12.97 M.Eckert: History parameter in rate and distortion functions
 *
 *
 ***********************************************************CommentEnd********/

static Int find_dec(
                    Int    vo_id,    
                    Int    vol_id,   
                    Int    num_vols_tot,
                    Int    p,        
                    LIST   pos[],    
                    Int    q_min[][MAX_NUM_VOLS],  
                    Double R,        
                    Int   (* rate)(RC_HIST *rch,
				    Int vo_i, Int vol_i, Int q, Double mad,
				    Int frame_type), 
                    Double mad,      
                    UInt   num_pels, 
                    Double r_qp[][MAX_NUM_VOLS],   
                    Int    qp[][MAX_NUM_VOLS],
		    Int    frame_type
                    )
{
   Int    vo_i, vol_i, q, p1;
   Double r_sum;
   

   /* Search qp in full range [1..31] */
   for (q = q_min[pos[p].vo_id][pos[p].vol_id]; q <= MAX_QUANT; q++) 

   /* qp range control within the loop, search in range of last_qp+-5: */
      /* for (q = q_min[pos[p].vo_id][pos[p].vol_id]; 
        q <= max_qp(pos[p].vo_id,pos[p].vol_id); q++) */
   {

     if (q == rch_exclude_qp(&rc_hist_upm[pos[p].vo_id][pos[p].vol_id][frame_type]))
     {
       if (q != MAX_QUANT)
       {
#ifdef _RC_DEBUG_
	 printf("!!!! The last %d qp VOP (%d,%d) were equal, %d is excluded \n",
		QP_INC, pos[p].vo_id, pos[p].vol_id, q);
#endif
	 continue;
       }  /* A return value != 0 means to exclude this qp */
       else
       {
	 qp[pos[p].vo_id][pos[p].vol_id] = MAX_QUANT-1;
	 continue;
       }
     }

     qp[pos[p].vo_id][pos[p].vol_id] = q;
         
       if ( p == num_vols_tot-1) /* Process least important VOP */
       {
         r_sum = 0.;
         for (p1 = 0; p1 < num_vols_tot; p1++)  
         {
            vo_i = pos[p1].vo_id;
            vol_i = pos[p1].vol_id;
            r_qp[vo_i][vol_i] = 
               (Double) (*rate)(&rc_hist_upm[vo_i][vol_i][frame_type], 
				vo_i, vol_i, qp[vo_i][vol_i], mad, frame_type);
	    if (r_qp[vo_i][vol_i] < 0) r_qp[vo_i][vol_i] = 0;
            r_sum += r_qp[vo_i][vol_i];
         }

         if (r_sum <= R)
         {

#ifdef _RC_DEBUG_
            fprintf(stdout,"VOP %d,%d (%d.in list) set to qp = %d, r = %f \n",
                    pos[p].vo_id, pos[p].vol_id, p, 
                    qp[pos[p].vo_id][pos[p].vol_id], 
                    r_qp[pos[p].vo_id][pos[p].vol_id]);
#endif
            return 0;
         }
          
       }
       else if ( (p <= num_vols_tot-1) && (p >= 0) )
       {
         if (find_dec(vo_id, vol_id, num_vols_tot,
                      p+1, pos, q_min, R, 
                      rate, mad, num_pels, 
                      r_qp, qp, frame_type) == 0)
	   return 0; 
       }
     
   }

   return 1;
}



/***********************************************************CommentBegin******
 *
 * -- PriorityOptimization --
 *
 * Author : 
 *      Martina Eckert, UPM-GTI     
 *
 * Created :            
 *      18-06-97
 *
 * Purpose :
 *      Calculates a distribution of the global target bitrate between the
 *      different VOs under the constraint to assure a minimum quality for
 *      the most important VO. If possible it is tried to obtain the same 
 *      quality for the rest of VOs according to its importance (position 
 *      in list). The position is provided by the user with the alpha values. 
 * 
 * Arguments in :       
 *     Int    vo_id      -  ID of current VO 
 *     Int    vol_id     -  ID of current VOL 
 *     Int    num_vols_tot - Number of VOPs 
 *     Double R          -  Global target bit rate
 *     Int   (* rate)(RC_HIST *rch, Int vo_i, Int vol_i, Int q, Double mad, Int frame_type)
 *                       - Rate functions 
 *     Double (* dist)(RC_HIST *rch, Int vo_i, Int vol_i, Int q, Int mode, Int frame_type)
 *                       - Distortion functions 
 *     Double mad        -  MAD 
 *     UInt   num_pels   -  Number of pixels in object 
 *     LIST   pos[]      -  Priority list 
 *     Double psnr_min   -  Maximal allowed distortion of first VOP in list 
 *     Int    qp[][]     -  --> Decisions 
 *     Int    mode       -  0 = calculation of distortion per pixel,
 *                          1 = calculation of total distortion 
 *     Int    frame_type -  I=0, P=1, B=2
 *
 * Arguments in/out :   
 *      -
 *
 * Arguments out :      
 *      -
 *
 * Return values :      
 *     Double r_sum    -  Predicted bitrate for all VOs
 *
 * Side effects :       
 *      -
 *
 * Description :        
 *
 *
 * See also :
 *
 *
 * Modified :           
 *       05.12.97 M.Eckert: History parameter in rate and distortion functions
 *
 *
 ***********************************************************CommentEnd********/

static Double PriorityOptimization(
                                   Int    vo_id,                             
                                   Int    vol_id,                            
                                   Int    num_vols_tot,          
                                   Double R,                                 
                                   Int   (* rate)(RC_HIST *rch,
						   Int vo_i, Int vol_i, 
                                                   Int q, Double mad,
						   Int frame_type),
                                   Double (* dist)(RC_HIST *rch,
						   Int vo_i, Int vol_i, 
                                                   Int q, Int mode,
						   Int frame_type),
                                   Double mad,                               
                                   UInt   num_pels,                          
                                   LIST   pos[],                             
                                   Double psnr_min,                          
                                   Int    qp[][MAX_NUM_VOLS],
				   Int    mode,
				   Int    frame_type
                                   )

{
   Int     vo_i, vol_i, vo_i1, vol_i1, p, p1, q, stop_flag, loop;
   Int     q_min[MAX_NUM_VOS][MAX_NUM_VOLS], qp_prev;
   Double  r_qp[MAX_NUM_VOS][MAX_NUM_VOLS], d_qp[MAX_NUM_VOS][MAX_NUM_VOLS];
   Double  r_sum = 0., D_max;
   Double  d_fin, psnr_fin;         


   /* Calculate maximal distortion */
   D_max = 255. / pow (10., psnr_min/20.); /* with PSNR=10*log10(255/D_max) */
   

   fprintf(stdout,"Global RC: VOP [%d,%d] has got highest priority, \n \
it's minimal quality should be %f dB \n (intern distortion value %f) \n", 
           pos[0].vo_id, pos[0].vol_id, psnr_min, D_max);
   fflush(stdout);


   /* Search for qp[n] which garantees dn <= D_max: */
   
   for (p = 0; p < num_vols_tot; p++) 
   {    
     vo_i = pos[p].vo_id;
     vol_i = pos[p].vol_id;

     if (rch_proc_stat(&rc_hist_upm[vo_i][vol_i][frame_type]) != 0){ /* still not processed */

       /* Search qp in full range [1..31]: */
       for (q = MAX_QUANT; q >= MIN_QUANT; q--)
      
       /* qp range control within the loop, search in range of last_qp+-5: */
       /* for (q = rch_max_qp(&rc_hist_upm[vo_i][vol_i][frame_type]); q >= rch_min_qp(&rc_hist_upm[vo_i][vol_i][frame_type]); q--)*/
       {
	 if (q != rch_exclude_qp(&rc_hist_upm[vo_i][vol_i][frame_type])){
	   r_qp[vo_i][vol_i] = (Double) (*rate)(&rc_hist_upm[vo_i][vol_i][frame_type],
						vo_i, vol_i, q, mad, frame_type);
	   if (r_qp[vo_i][vol_i] < 0) r_qp[vo_i][vol_i] = 0;

	   d_qp[vo_i][vol_i] = (*dist)(&rc_hist_upm[vo_i][vol_i][frame_type],
				       vo_i, vol_i, q, mode, frame_type);
	   
	   q_min[vo_i][vol_i] = qp[vo_i][vol_i] = q;
	 
	   if (d_qp[vo_i][vol_i] <= D_max) break;
	 }
       }
     }
     else
     {
       q_min[vo_i][vol_i] = qp[vo_i][vol_i] = rch_get_last_qp(&rc_hist_upm[vo_i][vol_i][frame_type]);
       r_qp[vo_i][vol_i] = (Double) (*rate)(&rc_hist_upm[vo_i][vol_i][frame_type],
					    vo_i, vol_i, qp[vo_i][vol_i], mad, frame_type);
       if (r_qp[vo_i][vol_i] < 0) r_qp[vo_i][vol_i] = 0;
     }

     r_sum += r_qp[vo_i][vol_i];


#ifdef _RC_DEBUG_
     fprintf(stdout,"d[%d][%d] = %f, r[%d][%d] = %f with qp[%d][%d] = %d \n", 
	     vo_i, vol_i, d_qp[vo_i][vol_i], 
	     vo_i, vol_i, r_qp[vo_i][vol_i], 
	     vo_i, vol_i, qp[vo_i][vol_i]);
     fflush(stdout);
#endif
   }


/*  If r_sum > R global, 
 *        increase d(pos(n-1)) (distortion of least important VOP) and then 
 *        d(pos(n-2)), d(pos(n-3))...d(pos(0)) 
 *  else 
 *        decrease d(pos(0)) (distortion of most important VOP) and then 
 *        d(pos(1)), d(pos(2)) ... d(pos(n-1)) 
 */
   
   loop = 0;

   if (r_sum > R)
   {
#ifdef _RC_DEBUG_
      fprintf(stdout,"r_sum > R global!\n");fflush(stdout); 
#endif
      find_dec(vo_id, vol_id, num_vols_tot,
               0, pos, q_min, R, 
               rate, mad, num_pels, 
               r_qp, qp, frame_type);
   }
   else
   {
     while (loop < 2)
     {
       stop_flag = FALSE;

#ifdef _RC_DEBUG_
       fprintf(stdout,"r_sum <= R global \n");fflush(stdout);
#endif


       for (p = 0; p < num_vols_tot; p++)
       {
	 vo_i = pos[p].vo_id;
	 vol_i = pos[p].vol_id;

	 if (rch_proc_stat(&rc_hist_upm[vo_i][vol_i][frame_type]) != 0){ 
	   if ((dist(&rc_hist_upm[vo_i][vol_i][frame_type],
		     vo_i, vol_i, q_min[vo_i][vol_i], mode,
		     frame_type) > D_max) || (loop != 0))
	   {
	     /* decrease d[pos_p] */
#ifdef _RC_DEBUG_
	     fprintf(stdout,"Increase rate of VOP[%d,%d]\n",
		     vo_i, vol_i); 
	     fflush(stdout);
#endif
	    
	     for (q = q_min[vo_i][vol_i]; q >= MIN_QUANT; q--) 
	       /*for (q = q_min[vo_i][vol_i]; q >= rch_min_qp(&rc_hist_upm[vo_i][vol_i][frame_type]); q--) */
	     {         

	        if (q == rch_exclude_qp(&rc_hist_upm[vo_i][vol_i][frame_type])){
#ifdef _RC_DEBUG_
		 printf("!!!! The last %d qp VOP (%d,%d) were equal, %d is excluded \n",
			QP_INC, vo_i, vol_i, q);
#endif
		 continue;
	       }  /* A return value != 0 means to exclude this qp */

	       qp_prev = qp[vo_i][vol_i];
	       qp[vo_i][vol_i] = q;
	       r_sum = 0;
	       for (p1 = 0; p1 < num_vols_tot; p1++)
	       {
		 vo_i1 = pos[p1].vo_id;
		 vol_i1 = pos[p1].vol_id;

		 r_qp[vo_i1][vol_i1] = 
		   (Double) (*rate)(&rc_hist_upm[vo_i1][vol_i1][frame_type], vo_i1, vol_i1, 
				    qp[vo_i1][vol_i1], mad, frame_type);
		 if (r_qp[vo_i1][vol_i1] < 0) r_qp[vo_i1][vol_i1] = 0;
		 r_sum += r_qp[vo_i1][vol_i1];
		 
	       }
	       printf(">>>>>> R_sum = %f \n", r_sum);
	       if (r_sum > R) 
	       { 
		 stop_flag = TRUE; 
		 loop++;
		 qp[vo_i][vol_i] = qp_prev; 
		 r_qp[vo_i][vol_i] = 
		   (Double) (*rate)(&rc_hist_upm[vo_i][vol_i][frame_type], 
				    vo_i, vol_i, qp[vo_i][vol_i], mad, frame_type);
		 if (r_qp[vo_i][vol_i] < 0) r_qp[vo_i][vol_i] = 0;
		 break;
	       }
	      
	       if ((dist(&rc_hist_upm[vo_i][vol_i][frame_type],
			 vo_i, vol_i, qp[vo_i][vol_i], mode,
			 frame_type) <= D_max) && (loop== 0)){
		 printf("desired distval for VO %d,%d reached\n",vo_i, vol_i);
		 break;}
	     }
	   }/* if */
	 } /* if */

	 if (stop_flag) break; /* stop for */
	 if (p == num_vols_tot-1) loop++;
	
       } /* for */
     } /* while */
   } /* else */
   
   /* Finally obtained distortion / PSNR value for most important VO: */

   if (vo_id == pos[0].vo_id && vol_id == pos[0].vol_id)
   {
      d_fin = dist(&rc_hist_upm[pos[0].vo_id][pos[0].vol_id][frame_type],
		   pos[0].vo_id, 
                   pos[0].vol_id, 
                   qp[pos[0].vo_id][pos[0].vol_id], 
		   mode,
		   frame_type);
      psnr_fin = 20 * log10 (255.0 / d_fin);

#ifdef _RC_DEBUG_
      WRITE_FLOAT("distor_script", psnr_fin);
#endif

      if (d_fin > D_max)
      { 
         fprintf(stdout,"Global RC - WARNING! PSNR = %f dB of VOP [%d,%d] can \
not be fulfilled! (estimation: %f dB)\n",
                 psnr_min, pos[0].vo_id, pos[0].vol_id, psnr_fin);
         fflush(stdout);
      }
   }


   r_sum = 0.;

   for (p = 0; p < num_vols_tot; p++)
   {
      vo_i = pos[p].vo_id;
      vol_i = pos[p].vol_id;
      r_sum +=  r_qp[vo_i][vol_i];

#ifdef _RC_DEBUG_
      fprintf(stdout,"d[%d][%d] = %f, r[%d][%d] = %f with qp[%d][%d] = %d \n",
              vo_i, vol_i, 
	      dist(&rc_hist_upm[vo_i][vol_i][frame_type], vo_i, vol_i, 
		   qp[vo_i][vol_i], mode, frame_type), 
              vo_i, vol_i, r_qp[vo_i][vol_i], 
              vo_i, vol_i, qp[vo_i][vol_i]);
      fflush(stdout);
#endif
   }


#ifdef _RC_DEBUG_
   fprintf(stdout,"r_sum = %f \n",r_sum); fflush(stdout);
#endif


   return r_sum;
  
}

/***********************************************************CommentBegin******
 *
 * -- RC_UPM2_QuantAdjust --
 *
 * Author : 
 *      Martina Eckert, UPM-GTI     
 *
 * Created :            
 *      18-06-97
 *
 * Purpose :
 *      Gets alpha values and min_psnr and starts the 2. UPM control algorithm
 *      for global rate distribution with the selected prediction model.
 *      Returns QP for current VO.
 * 
 * Arguments in :       
 *      Int    vo_id          -  VO Id
 *      Int    vol_id         -  VOL Id
 *      VOConfig *vo_list     -  To read rc-parameters
 *      Double R              -  Global target bitrate 
 *      Double mad            -  Current MAD
 *      UInt   num_pels       -  Current number of pixels in VO
 *      Int    rc_rate_model  -  Used rate prediction model
 *      Int    rc_dist_model  -  Used distortion prediction model
 *      Int    mode           -  0 = calculation of distortion per pixel,
 *                               1 = calculation of total distortion 
 *      Int    frame_type     -  I=0, P=1, B=2
 *
 * Arguments in/out :   
 *      -
 *
 * Arguments out :      
 *      -
 *
 * Return values :      
 *      Int    qp       - Quantization parameter for current VO
 *
 * Side effects :       
 *      -
 *
 * Description :        
 *
 *
 * See also :
 *      File "README"
 *
 * Modified :       
 *       05.12.97 M.Eckert: History parameter in rate and distortion functions,
 *                          move set_process_flag from rc_upm_model.c to here
 *       15.12.97 M.Eckert: Introduction of "mode" for calculation of
 *                          distortion
 *       27.01.98 M.Eckert: Modification of QP for first frame
 *
 ***********************************************************CommentEnd********/

Int RC_UPM2_QuantAdjust(
                        Int    vo_id, 
                        Int    vol_id,
                        VOConfig *vo_list, 
                        Double R,          
                        Double mad,        
                        UInt   num_pels,   
                        Int    rc_rate_model,
                        Int    rc_dist_model,
			Int    mode,
			Int    frame_type
                       )
                        
{

   VOConfig  *curr_vo;
   VolConfig *curr_vol;
   Int   (* rate_model) (RC_HIST*, Int, Int, Int, Double, Int) = NULL;
   Double (* dist_model) (RC_HIST*, Int, Int, Int, Int, Int) = NULL;
   RC_CFG_PARAM *rc_cfg = &rc_cfg_upm[vo_id][vol_id];

   /* Arrays including data of all VOPs: */

   Int    qp[MAX_NUM_VOS][MAX_NUM_VOLS];       /* QPs */
   Double alpha[MAX_NUM_VOS*MAX_NUM_VOLS];    /* Table of ordinal numbers 
						 for priority list */
   Float  psnr_min[MAX_NUM_VOS*MAX_NUM_VOLS]; /* Minimal assured qualities of 
                                                 VOLs */
   LIST   pos[MAX_NUM_VOS*MAX_NUM_VOLS];       /* Priority list */

   Short   vo_i, vol_i, id_vol[MAX_NUM_VOS*MAX_NUM_VOLS],
           id_vo[MAX_NUM_VOS*MAX_NUM_VOLS];   /* Counter */
   Int     i, j, i_min=0, num_vols_tot;
   Int     first_vo, first_vol;
   Double  alpha_min, psnr_thresh=0;   /* PSNR value to reach for the most 
                                        important VOL */


#ifdef _RC_DEBUG_
   Short   last_vo, last_vol;
   Double  r_tot;                    /* ---> Totally achieved bit-rate */
#endif

   /* Set process flags for global control: */

   curr_vo = vo_list;
   first_vo = GetVOConfigId(curr_vo);
   curr_vol =  GetVOConfigLayers(curr_vo);
   first_vol = GetVolConfigId(curr_vol);
   
   if (vo_id == first_vo && vol_id == first_vol)
      while(curr_vo != NULL)
      {
	 vo_i = GetVOConfigId(curr_vo);
	 curr_vol = GetVOConfigLayers(curr_vo);
	 while(curr_vol != NULL)
	 {
	    vol_i = GetVolConfigId(curr_vol);
	    rch_set_process_flag(&rc_hist_upm[vo_i][vol_i][frame_type], 2);    /* Status of all VOs: 
									unprocessed */
	    curr_vol = GetVolConfigNext(curr_vol);
	 }
	 curr_vo = GetVOConfigNext(curr_vo);
      }

   /* Set process flag for currently processed VO */

   rch_set_process_flag(&rc_hist_upm[vo_id][vol_id][frame_type], 1);   /*  VOL = [vo_id,vol_id] is 
							       currently processed */

   for(vo_i = 0; vo_i < MAX_NUM_VOS; vo_i++)
      for(vol_i = 0; vol_i < MAX_NUM_VOLS; vol_i++)
      {
         qp[vo_i][vol_i]                     = 0;
         alpha[vo_i*MAX_NUM_VOLS+vol_i]      = -1.;
         psnr_min[vo_i*MAX_NUM_VOLS+vol_i]   = 0.;
         pos[vo_i*MAX_NUM_VOLS+vol_i].vo_id  = 999;
         pos[vo_i*MAX_NUM_VOLS+vol_i].vol_id = 999;
      }

#ifdef _RC_DEBUG_
   fprintf(stdout,"Global target rate: %f \n\n",R); fflush(stdout); 
#endif

   rch_store(&rc_hist_upm[vo_id][vol_id][frame_type], (Int)num_pels, mad);
 
   if (first_frame(&rc_hist_upm[vo_id][vol_id][frame_type])) 
     {
     /* Code  all VOs of first frame with initial qp: */
     qp[vo_id][vol_id] = rc_upm_get_QPfirst(rc_cfg, frame_type);

     }
  
   else 
   {
      /* Calculate QPs of optimal global distribution of target bit rate: */

      i = 0;
      curr_vo = vo_list;
      while(curr_vo != NULL)
      {
         curr_vol =  GetVOConfigLayers(curr_vo);
         while(curr_vol != NULL)
         {
            id_vo[i] = GetVOConfigId(curr_vo);
            id_vol[i] = GetVolConfigId(curr_vol);
            alpha[i] = rc_get_RCParam(&rc_cfg_upm[id_vo[i]][id_vol[i]], 0);
            psnr_min[i] = rc_get_RCParam(&rc_cfg_upm[id_vo[i]][id_vol[i]], 1);
            curr_vol = GetVolConfigNext(curr_vol);
            i++; 
         }
         curr_vo = GetVOConfigNext(curr_vo);
      }

      num_vols_tot = i;
#ifdef _RC_DEBUG_
      last_vo = id_vo[i];
      last_vol = id_vol[i];
#endif

      for(j = 0; j < num_vols_tot; j++)
      {
         alpha_min = 1E99;
         for(i = 0; i < num_vols_tot; i++)
            if (alpha[i] < alpha_min)
            {
               alpha_min = alpha[i];
               i_min = i;
            }
         pos[j].vo_id = id_vo[i_min];
         pos[j].vol_id = id_vol[i_min];
#ifdef _RC_DEBUG_
         fprintf(stdout,"%d, %d on position %d \n",pos[j].vo_id,pos[j].vol_id,j);
#endif
         if (j==0) psnr_thresh = psnr_min[i_min];
         alpha[i_min] = 1E99;
         i_min = 0;
      }


      switch (rc_rate_model) 
         {
         case RC_MODEL_UPM1:
         case RC_MODEL_UPM2:
            rate_model = RC_UPM_pred_bits;
            break; 
         default:
            error_exit("RC_UPM1_QuantAdjust: Error: Mode not supported\n");
         }     

      switch (rc_dist_model) 
         {
         case RC_MODEL_UPM1:
         case RC_MODEL_UPM2:
            dist_model = RC_UPM_pred_dist;
            break; 
         default:
            error_exit("RC_UPM1_QuantAdjust: Error: Mode not supported\n");
         }     

#ifdef _RC_DEBUG_
      r_tot = PriorityOptimization(vo_id, vol_id, 
                                   num_vols_tot, R,
                                   rate_model, dist_model, 
                                   mad, num_pels, 
                                   pos, psnr_thresh, 
                                   qp, mode, frame_type); 
#else
     PriorityOptimization(vo_id, vol_id, 
			  num_vols_tot, R,
			  rate_model, dist_model, 
			  mad, num_pels, 
			  pos, psnr_thresh, 
			  qp, mode, frame_type); 
#endif
   }
   
#ifdef _RC_DEBUG_

   if (vo_id == last_vo && vol_id == last_vol)
      WRITE_INT("rate_script",r_tot);


#endif


   /* Suppress great deviation of qp if search range [1..31]:*/
   /*
   qp[vo_id][vol_id] = rch_qp_range_control(&rc_hist_upm[vo_id][vol_id][frame_type], qp[vo_id][vol_id]);
   */
   
   
   rch_store_qp_before(&rc_hist_upm[vo_id][vol_id][frame_type], qp[vo_id][vol_id]);


#ifdef _RC_DEBUG_
   curr_vo = vo_list;
   while(curr_vo != NULL)
   {
      vo_i = GetVOConfigId(curr_vo);
      curr_vol = GetVOConfigLayers(curr_vo);
      while(curr_vol != NULL)
      {
         vol_i = GetVolConfigId(curr_vol);
         fprintf(stdout,"qp[%d][%d] = %d \n",vo_i, vol_i, qp[vo_i][vol_i]); 
         fflush(stdout);
         curr_vol = GetVolConfigNext(curr_vol);
      }
      curr_vo = GetVOConfigNext(curr_vo);
   }
#endif

   rch_set_process_flag(&rc_hist_upm[vo_id][vol_id][frame_type], 0);   /*  VOL = [vo_id,vol_id] has 
						 been finished */
   return qp[vo_id][vol_id];
}

/***********************************************************CommentBegin******
 *
 * -- ret_rch_upm2 --
 *
 * Author : 
 *      Martina Eckert, UPM-GTI     
 *
 * Created :            
 *      05.12.97
 *
 * Purpose :
 *      Access to history data from other files
 *
 * Arguments in :       
 *      Int    vo_id   -  VO Id
 *      Int    vol_id  -  VOL Id
 *
 * Arguments in/out :   
 *      -
 *
 * Arguments out :      
 *      -
 *
 * Return values :      
 *      RC_HIST  *rch  - History data array  
 *
 *
 * Modified : 
 *
 *
 ***********************************************************CommentEnd********/
RC_HIST *get_rch_upm2(
		      Int  vo_id,
		      Int  vol_id,
		      Int  frame_type
		      )
{

return &rc_hist_upm[vo_id][vol_id][frame_type];

}

/***********************************************************CommentBegin******
 *
 * -- get_rc_cfg_upm2 --
 *
 * Author : 
 *      Martina Eckert, UPM-GTI     
 *
 * Created :            
 *      15.12.97
 *
 * Purpose :
 *      Access to history data from other files
 *
 * Arguments in :       
 *      Int    vo_id   -  VO Id
 *      Int    vol_id  -  VOL Id
 *
 * Arguments in/out :   
 *      -
 *
 * Arguments out :      
 *      -
 *
 * Return values :      
 *      RC_CFG_PARAM  *rc_cfg  - Configuration data (model parameters)
 *
 *
 * Modified : 
 *
 *
 ***********************************************************CommentEnd********/

RC_CFG_PARAM *get_rc_cfg_upm2(
			      Int  vo_id,
			      Int  vol_id
			      )
{

   return &rc_cfg_upm[vo_id][vol_id];

}

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