/******************************************************************************
 *                                                                          
 * This software module was originally developed by 
 *
 * Noel O'Connor (TELTEC IRELAND / ACTS-MoMuSys).                   	
 *
 * and edited by  
 *
 * Aasmund Sandvand (Telenor / ACTS-MoMuSys). 	    	              	
 * J. Ignacio Ronda (UPM / ACTS-MoMuSys).   	  	              	
 * Cecile Dufour (LEP / ACTS-MoMuSys).     		              	
 * Sylvie Jeannin (LEP / ACTS-MoMuSys).     		              	
 * Minhua Zhou (HHI / ACTS-MoMuSys).   	  	 	              	
 * Fernando Jaureguizar (UPM / ACTS-MoMuSys).   	              	
 * Luis Ducla-Soares (IST / ACTS-MoMuSys).     	           	   	
 * Martina Eckert (UPM / ACTS-MoMuSys).   	  	              	
 * Noel Brady (TELTEC IRELAND / ACTS-MoMuSys).                   	
 * Michael Wollborn (TUH / ACTS-MoMuSys).   	  	               	
 * Ulrike Pestel (TUH / ACTS-MoMuSys).
 * Bob Eifrig (NextLevel Systems)
 * Michael Frater (UNSW)
 * Hung-Ju Lee (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
 *
 *****************************************************************************/




/***********************************************************HeaderBegin*******
 *                                                                         
 * File:        vm_enc_main.c
 *
 * Author:      Noel O'Connor Teltec Irl.
 * Created:     11-03-96
 *                                                                         
 * Description:
 *
 * Notes:
 *
 * Modified:
 *     21.04.96 Robert Danielsen: Reformatted. New headers.
 *     08.05.96 Noel O'Connor: New data structures for control
 *              file and config file parameters
 *     13.05.96 Bruno Loret: PowerPC input arguments
 *     07.06.96 Robert Danielsen: Replaced old huffman stuff with new.
 *              The low-level bitstream file is now opened and closed here.
 *              The file pointer is an external variable.
 *     30.07.96 Noel O'Connor: Changed entire high level structure
 *              for compliance with VM 3.0. The encoder now runs on a single
 *              Video Object (VO) but for multiple Video Object Layers (VOLs)
 *              For the time being only BASE layer coding is supported.
 *     23.09.96 Cor Quist: Added the MPEG-2 dct transform (fdctref)
 *     23.09.96 Noel O'Connor: Changed entire high level structure to allow
 *              coding of multiple VOs.
 *     26.11.96 Noel O'Connor: Changed main coding loop to allow coding
 *              of multiple VOs with different frame rates (which may or
 *              may not be related).
 *     14.01.97 Luis Ducla-Soares: enabled byte alignment for VOL_START_CODE
 *              in function CloseBitstreams() by removing
 *              comment arount NextStartCode() function call
 *     02.02.97 Aasmund Sandvand: Moved deblocking filter out of loop
 *     07.02.97 J. Ignacio Ronda: Modifcations to implement VM5 rate control
 *     20.02.97 Cecile Dufour: including STATIC sprite
 *     14-MAR-97 Jan De Lameillieure : integrated SA-DCT
 *     14-MAR-97 Minhua Zhou         : added B-VOPs  
 *     21.03.97 Cecile Dufour: including ONLINE sprite
 *     20.03.97 Fernando Jaureguizar: Modifications in the main loop to 
 *              solve some problems with last skipped frames of the sequence.
 *     23.04.97 M.Wollborn: MPEG quantization completely added
 *     04.05.97 Luis Ducla-Soares: added data_partitioning flag to the bitstream.
 *     13.05.97 Minhua Zhou : added advanced_prediction_disable and
 *                            Group_of_VOPs (GOV) 
 *     14.05.97 F. Jaureguizar: Modification of number of bits of fcodes in
 *               BitstreamPutVOLs(). From 2 bits to 3 bits.
 *     16-JUN-97 Jan De Lameillieure : integrated Kaup-SA-DCT
 *     04-JUL-97 Sylvie Jeannin : BUG VM7-970515-04 about TPS related memory problems
 *     07.07.97 Martina Eckert: Introduction of global rate control 
 *              functions and parameters
 *     18.07.97 Ulrike Pestel-Schiller: Spatial Scalability
 *     30.07.97 Fernando Jaureguizar: deleted some old_and_commented_out
 *              code concerning Rate Control (labelled as "RC2: comented out").
 *              Deleted RC_ExcludeIFrame() in CodeEnhVol().
 *              Added the Remove_Padding() for the U and V images also. (SpSc)
 *     04.08.97 Minhua Zhou: rename advanced_prediction_mode
 *     29.08.97 Osamu Sunohara(Sony): added new condition to select
 *              enhancement layer prediction type.
 *     05.09.97 Fernando Jaureguizar: added some FeeVop(). (SpSc-2)
 *     08.09.97	Cecile Dufour: static sprite_pieces encoded in the VOL header
 *     23.10.97 Minhua Zhou  : changed deblock_filter_disable to post_filter
 *                             _type
 *     04.01.98 Michael Frater: support for non-8-bit video
 *     16.01.97 Martina Eckert: Change reading of RC parameters from .ctl file.
 *                              Now they are extracted from one single string
 *
 *     20.01.98 Added the wavelet texture object layer code  
 ***********************************************************HeaderEnd*********/

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

#include <stdio.h>
#include <stdlib.h>
#include <string.h> 
#include "vm_config.h"
#include "momusys.h"
#include "mom_vop.h"
#include "mom_bitstream_i.h"
#include "mom_access.h"
#include "io_generic.h"
#include "putvlc.h"
#include "text_code_mb.h"
#include "vm_vop_code.h"
#include "vm_compos.h"
#include "vm_stats.h"
#include "mom_putbits.h"
#include "vm_enc_main.h"
#include "vm_vop_bound.h"
#include "mom_vol.h"
#include "mom_vo.h"
#include "mot_util.h"
#include "zigzag.h"
#include "post_filter.h"
#include "rc.h"
#include "tm5rc.h"

#ifndef _WD_MODE_
#include "sadct.h"
#include "sadct_kaup.h"
#endif

#include "sait_rc.h"
#include "mot_padding.h"
#include "do_bgc.h"
#include "sprite_util.h"
#include "sprite_enc_piece.h"
/* for spatial scalability (UPS) */
#include "vm_midproc.h"
/* end of ssp (UPS) */


#include "enhance_vop.h"
#include "bgc.h"

#include "alp_code_header.h"

/* 1197-2 SONY */
#ifdef _DEBUG_SPSC3_
static Int up_cnt = 0;
#endif 
/* 1197-2 */

/* VTC Begin ------------------------------------------ */
#include "interface.h"
/* VTC End   ------------------------------------------ */

#include "meitca_wrapper.h"

/* inserted by Mitsubishi & SAMSUNG AIT */
#include "rc_mvo.h"
extern RC_MVO rc_mvo;
Int 	FirstInterFrame = 1;
/* inserted by Mitsubishi & SAMSUNG AIT */


#if 0
Void
CodeEnhVol(Vol  *enh_layer,
           VolConfig *layer_config,
           Int  frame,
           Float time,
           Vol *prev_vol_store,
           Vol *rec_vol_store,
           Vol *base_vol_store,
           Vol *base_rec_vol_store,
           Vol *next_vol_store,
           Vol *next_rec_vol_store,
           Int TRB, Int TRD, 
           Int vo_id,    
           VOConfig *vo_config_list, /* UPM Global RC */
           Int rc_type,              /* UPM Global RC */
           Int rc_algorithm,              /* hjlee */
           Int *frame_type,          /* UPM Global RC */
           BitCount num_bits[MAX_NUM_VOS][MAX_NUM_VOLS]);

Void
BitstreamPutVOLs(VO *vo_list,BitCount num_bits[MAX_NUM_VOS][MAX_NUM_VOLS],
                        VOConfig *vo_config_list, Int rc_type);


Void
UpdateVolStore(Vop *update_vop,
                                        Int layer_id,
                                        Vol *vol_store);
VO *
InitVOStore(VO *list);

Vol *
InitVolStore(Vol *list);

Void
QuantAdjust (Int target_bitrate,
                                Int temp_ref,
                                Int end_time,
                                Int time_instant,
                                Int num_bits_used,
                                Int num_bits_prev,
                                Int *QP);

 
Void
InitBitstreams(VOConfig *list);

Void
CloseBitstreams(VOConfig *list);

Void
InitBitCounts(VOConfig *vo_cfg_list, 
                                Char *stats_file,
                                BitCount num_bits[MAX_NUM_VOS][MAX_NUM_VOLS]);

Void 
AverageBitCounts(BitCount num_bits[MAX_NUM_VOS][MAX_NUM_VOLS],
                                        VOConfig *vo_cfg_list);

Void
WriteCompositedImage(EncodeControl *enc_ctl,
                                                Int     frame,
                                                VO      *vo_store,
                                                Vop     *display_vop);


Float
GetNextCodedVO(VOConfig *list,
                        Int *vo_id,
                        Int *vol_id,
                        Int *finish);

#endif


/***********************************************************CommentBegin******
 *
 * -- main -- Main calling function of MoMuSys implementation of MPEG4 VM
 *
 * Author :             
 *      Noel O'Connor Teltec Irl.
 *
 * Created :            
 *      11-03-96
 *
 * Purpose :            
 *      Main calling function of MoMuSys implementation of MPEG4 VM
 * 
 * Arguments in :       
 *      See file "README_ENCODER"
 *
 * Arguments in/out :   
 *      See file "README_ENCODER"
 *
 * Arguments out :      
 *      See file "README_ENCODER"
 *
 * Return values :      
 *      none
 *
 * Side effects :       
 *      none
 *
 * Description :        
 *      See file "README_ENCODER"
 *
 * See also :
 *      See file "README_ENCODER"
 *
 * Modified :
 *     07.06.96 Robert Danielsen: Replaced old huffman stuff with new.
 *              The low-level bitstream file is now opened and closed here.
 *              The file pointer is an external variable.
 *     30.07.96 Noel O'Connor : Changed entire high level structure
 *              for compliance with VM 3.0. The encoder now runs on a single
 *              Video Object (VO) but for multiple Video Object Layers (VOLs)
 *              For the time being only BASE layer coding is supported.
 *     23.09.96 Cor Quist: Added the MPEG-2 dct transform (fdctref)
 *     23.09.96 Noel O'Connor: Changed the control and configuration s/w
 *              to allow for coding of multiple VOs.
 *     07.02.97 J. Ignacio Ronda: Added VM5_RATE_CONTROL initialization.
 *              UpdateVolConfigNextCodingTime() with new parameters
 *     20.03.97 Fernando Jaureguizar: Modifications in the main loop to 
 *              solve some problems with last skipped frames of the sequence.
 *     08.09.97 Cecile Dufour: BitstreamPutVOLs and PrintSession place changed
 *     27.11.97 M. Eckert: Changes for independent frame type rate control
 *
 ***********************************************************CommentEnd********/
 
Void
main(Int argc, Char *argv[])
{
  Char              control_file[100],
                    stats_file[100];
  EncodeControl     *enc_ctl;
  VOConfig          *vo_config_list,
                    *vo_config;
/* VTC Begin ------------------------------------------ */
  VTCConfig         *vtc_config_list,  /* VTC */
                    *vtc_config;
/* VTC End   ------------------------------------------ */

  VolConfig         *vol_config=NULL;
  BitCount          num_bits[MAX_NUM_VOS][MAX_NUM_VOLS];
  VO                *video_object_list = NULL,
                    *prev_vo_store,
                    *prev_rec_vo_store,
                    *next_vo_store,
                    *next_rec_vo_store,
/* 1197-2 SONY */
                    **B_org_vo_store=NULL,
/* 1197-2 */ 
                    **B_vo_store=NULL,
                    *vo,
                    *prev_vo,*next_vo,
                    *prev_rec_vo,*next_rec_vo;
  Vol               *vol,
                    *prev_vol,*next_vol,
                    *prev_rec_vol,*next_rec_vol,
                    *base_vol=NULL,*base_rec_vol=NULL; /*for spatial scal (UPS)*/   
  Vop               *display_vop;
 Float             time_instant,
                    start_time,
                    time_inc,
                    next_display_time;
  Int               finish = 0;
  Int               output_frame = 0,
                    num_out_frames,
                    frame,
                    vo_id,
                    vol_id; 
  Int               TRB,M=1,FIRST,current_frame_number=0;

  Float             end_time;           /* inserted by Mistubishi & SAMSUNG AIT */
  Int               tmp_frame, i;       /* inserted by Mistubishi & SAMSUNG AIT */
  Int               FirstIntraOrInter = 0;      /* inserted by Mistubishi & SAMSUNG AIT */

/* Global RC: */
  Int               rc_type, 
                    rc_algorithm, 
                    frame_type;
  Char             *rc_ctl_string;

  Float             old_time = 0.;
#ifndef NLSSTATS  
FILE              *fpstats_file;
#endif

  Float             ref_time_instant     = 0.0;
  Int               bgc_mode             = 0;
  Int               finish_base          = 0;
  Int               enhance_count        = 0;
  Int               temporal_scalability = 0;
  Int               enhancement_type     = 0;
  Int               FIRST_enhance        = 1;         
  Int               finish_enhance       = 0;
  Vop *base_vop_not_padding_for_bgc = NULL; /* base image for BGC which is not padding vop */
  Vop *enhance_vop[300];
  Vop *base_B_vop_TPS               = NULL;
  Vop *original_prev_base_vop       = NULL;
  
  /* for spatial scalability (UPS)*/
  Int               scalability;
  Int               spatial_scalability =0 ;	/*end of ssp (UPS)*/

  /* Put text, if necessary, explaining how to run the encoder software */
#ifndef __POWERPC__
        if(argc < 2)
        {
                printf("usage : %s control file <statistics file (optional)>\n",argv[0]);
                exit(1);
        }

        /* Process input arguments */
        strcpy(control_file, argv[1]);
                if(argc == 3)
                        strcpy(stats_file, argv[2]);
                else
                        strcpy(stats_file, DEFAULT_STATS_FILE); 

#else

                strcpy(control_file, "weather.ctl");
                strcpy(stats_file,"weather_enc.dat");
#endif


        /* Read control file parameters */
        enc_ctl = ReadEncoderControlFile(control_file);

        /* Open stats file file pointer */
        if((fpstats_file = fopen(stats_file,"w")) == NULL)
        {
                fprintf(stdout,"ERROR(main) : Cannot open %s\n",stats_file);
                exit(1);
        }
 

        /* Read config files for VOs */
        vo_config_list = ReadConfigFiles(enc_ctl); 

/* VTC Begin ------------------------------------------ */
       /* Read VTC config files for VOs */
        vtc_config_list = ReadVTCConfigFiles(enc_ctl); 
        vtc_config = vtc_config_list;  
        while (vtc_config != NULL) {
          
          VTC_Encode(vtc_config);

          vtc_config = GetVTCConfigNext (vtc_config);
        }
/* VTC End ------------------------------------------ */
 

        if (vo_config_list->layers == NULL)
          exit(0);


        /* Calculate some control parameters based on data read */
        InitControlParams(vo_config_list,enc_ctl);
        /* Put some text for user (to display and stats file) */
        PrintEncodeControl(enc_ctl,stdout);
        PrintEncodeControl(enc_ctl,fpstats_file); 
        fprintf(stdout,"Bit statistic file - %s\n\n",stats_file);

        /* Put some text for user (to display and stats file) */
        PrintVOConfigList(vo_config_list,stdout);
        PrintVOConfigList(vo_config_list,fpstats_file); 

      /* Set up list for input VOPs for each VO using control and config info. */               
        video_object_list = SetUpVOList(vo_config_list);

        /* Close stats file (will write to it incrmentally from now on */
#ifndef NLSSTATS
        fclose(fpstats_file);
#endif

        /* Initialise the VO stores with the VO list. */
        /* A VO store has a node for each VO. These nodes
                 then contain pointers to stores for the various VOLs */
        prev_vo_store = InitVOStore(video_object_list);
        prev_rec_vo_store = InitVOStore(video_object_list);
        
       /* Minhua Zhou: store next original and reconstructed VOs for B-VOPs */
        next_vo_store = InitVOStore(video_object_list);
        next_rec_vo_store = InitVOStore(video_object_list);

 

  /*
   *
   * Get ready to start a session 
   *
   */
#ifndef _WD_MODE_        
  /* Initialise SA-IDCT */
  Initialisations_for_SADCT();
  Initialisations_for_SADCT_Kaup();
#endif



        /* Initialize MPEG-2 DCT-transform (fdctref) */


        /* Allocate memory for the display vop */
        display_vop = AllocVop(GetEncodeControlDispSizeX(enc_ctl),
                        GetEncodeControlDispSizeY(enc_ctl));
	PutVopBitsPerPixel(GetEncodeControlDispBitsPerPixel(enc_ctl),display_vop);
        
        /* Open and initialise all bitstream files required */
        InitBitstreams(vo_config_list);
        
        /* Initialise bit counting structures */
        InitBitCounts(vo_config_list,stats_file,num_bits);

        /* Set up coding loop indices */
        start_time = GetEncodeControlStartTime(enc_ctl);
        time_instant = start_time;
        next_display_time = start_time;
        time_inc = GetEncodeControlTimeInc(enc_ctl);

        /* Initialise VM5_RATE_CONTROL */
        rc_type = GetEncodeControlRCType(enc_ctl); 
	/* 16.01. Read all control parameters in one string */
	rc_ctl_string = GetEncodeControlRCParam(enc_ctl);

        if (rc_type == VM5_RATE_CONTROL) {
	  RC_init_global(vo_config_list, rc_ctl_string, &rc_algorithm);
	  if (RCQ2_MVO_CHECK() >= RCQ2_MVO_ENABLED) {
	      RCQ2_MVO_InitGlobal(vo_config_list, enc_ctl);
	  }
	}
        else if (rc_type >= TM5_RATE_CONTROL) {
            for (vo_config = vo_config_list; vo_config != NULL; vo_config = vo_config->pnext) {
                for (vol_config = vo_config->layers; vol_config != NULL; vol_config = vol_config->pnext) {
                    vol_config->rcdata = tm5rc_init_seq(vol_config, rc_type);
                }
            }
        }

	scalability = CheckScalability(vo_config_list);
	if(scalability==1){
          if(CheckScalType(vo_config_list) == 0 || CheckScalType(vo_config_list) == 2)
	    temporal_scalability = 3;
	  else if(CheckScalType(vo_config_list) == 3)
	    temporal_scalability = 1;
	  else if(CheckScalType(vo_config_list) == 4)
	    temporal_scalability = 5;
	  else if(CheckScalType(vo_config_list) == 1 || CheckScalType(vo_config_list) == 2)
	    spatial_scalability =1;
	  
	  if(temporal_scalability != 0){
	    enhancement_type    = CheckEnhancementType(vo_config_list);
	    if(enhancement_type != 2){
	      fprintf(stderr,"BGC(ON)\n");
	        bgc_mode = 1;
	    }
	    else{
	      fprintf(stderr,"BGC(OFF)\n");
	      enhancement_type = 1;
	    }
	  }
	}

        /* Write VOL headers to bitstream */
        BitstreamPutVOLs(video_object_list,num_bits, vo_config_list, rc_type);

        /* Print Session start statistics to display and stats file */
#ifdef NLSSTATS
        DoPrintSessionStartStat(num_bits, video_object_list, fpstats_file);
        DoPrintSessionStartStat(num_bits, video_object_list, stdout);
#else
        PrintSessionStartStat(num_bits,video_object_list,STATS_FILE);
        PrintSessionStartStat(num_bits,video_object_list,DISPLAY);
#endif

        FIRST = 1;
          if (temporal_scalability != 0){
              FILE *fp_TMP;
              fprintf(stderr,"temporal scalability ON\n");

              base_vop_not_padding_for_bgc = AllocVop(GetEncodeControlDispSizeX(enc_ctl),
                                             GetEncodeControlDispSizeY(enc_ctl));
	      PutVopPrevTemp(NULL, base_vop_not_padding_for_bgc);
	      PutVopNextTemp(NULL, base_vop_not_padding_for_bgc);
	      {
	         Int i;
		 for(i = 0; i < 299; i++)
                     enhance_vop[i] = NULL;
              }
	      
              if(NULL == (fp_TMP = fopen(GetEncodeControlDispYFile(enc_ctl),"w"))){
                fprintf(stderr,"cannot open %s\n",GetEncodeControlDispYFile(enc_ctl));
                exit(1);
              }
              fclose(fp_TMP);
              if(NULL == (fp_TMP = fopen(GetEncodeControlDispUFile(enc_ctl),"w"))){
                fprintf(stderr,"cannot open %s\n",GetEncodeControlDispUFile(enc_ctl));
                exit(1);
              }
              fclose(fp_TMP);
              if(NULL == (fp_TMP = fopen(GetEncodeControlDispVFile(enc_ctl),"w"))){
                fprintf(stderr,"cannot open %s\n",GetEncodeControlDispVFile(enc_ctl));
                exit(1);
              }
              fclose(fp_TMP);
	      
   /***************************************
   <<<   temporal_scalability usage   >>>
   ***************************************
    temporal_scalability = 1  : Enhance vop is B_VOP_TYPE(1)
    temporal_scalability = 2  : Enhance vop is B_VOP_TYPE(2)
    temporal_scalability = 3  : Enhance vop is I_VOP or P_VOP
    temporal_scalability = 4  : Enhance vop is P_VOP in B_VOP_TYPE(1)
    temporal_scalability = 5  : Enhance vop is P_VOP in B_VOP_TYPE(2)
    
    ==================================================
    prediction_type = P_VOP(temporal_scalability = 3 )
    ==================================================
       temporal_scalability = 3,4 -> RefSelCode = 0 : forward (from E frame)
	                             RefSelCode = 1 : forward (from B frame) 
	                             RefSelCode = 2 : backward(from E frame)
    =======================
    prediction_type = B_VOP
    =======================
       temporal_scalability = 1   -> RefSelCode = 3 : B_TYPE(1)
       temporal_scalability = 2   -> RefSelCode = 1 : B_TYPE(2)
  **********************************************************************/
	      
 	      fprintf(stderr,"temporal_scalability MODE : ");
	      if(temporal_scalability == 3)
		  fprintf(stderr,"case0 : ");
	      else if(temporal_scalability == 1)
		  fprintf(stderr,"case1 : ");
	      else if(temporal_scalability == 5)
		  fprintf(stderr,"case2 : ");
	      else{
		  fprintf(stderr,"\n");
		  fprintf(stderr,"B_MODE for temporal_scalability is\n");
		  fprintf(stderr,"       3 : Enhance vop is B_VOP_TYPE(1)\n"); 
		  fprintf(stderr,"       4 : Enhance vop is B_VOP_TYPE(2)\n"); 
		  fprintf(stderr,"       0 : Enhance vop is I_VOP or P_VOP \n");
		  exit(-1);
	      } 
	      if(enhancement_type == 1)
		  fprintf(stderr,"Type 1\n");
	      else{
		  if(CheckArbitraryShape(vo_config_list))
		      fprintf(stderr,"Type 2\n");
		  else
		      fprintf(stderr,"Type 0\n");
	      }
		  
              base_B_vop_TPS = NULL; 
        }
  
       while(TRUE){
	 
	         if (RCQ2_MVO_CHECK() >= RCQ2_MVO_ENABLED) {
	            RCQ2_MVO_UpdateVOCount(vo_id);
	         }

                if(temporal_scalability == 0) 
                    time_instant = GetNextCodedVO(vo_config_list,&vo_id,&vol_id,&finish);
                 else
		    time_instant = GetNextCodedVO_TPS(vo_config_list,
						      &vo_id,  &vol_id,
						      &finish, &finish_base, &finish_enhance,
						      temporal_scalability);
            		

		/* if use P_VOP in B_VOP_TYPE(1) : TPS */
		if(temporal_scalability == 1 && finish_base == FINISHED)
                    temporal_scalability = 4; /* B_TYPE(1) : E frame's predictionmode change (B_VOP -> P_VOP) */

	         if (RCQ2_MVO_CHECK() >= RCQ2_MVO_ENABLED) {
		   ;
		 }
		 else {
#ifndef _RC_NO_SKIPPING_
		   if (rc_type == VM5_RATE_CONTROL && 
		       rc_algorithm != RC_ALGORITHM_Q2)
		     
		     if(time_instant != old_time) 
		     {
		       Int skip_frame;
		       old_time = time_instant;
		       
		       /* Update Global RC Buffer: */
		       
		       RC_UpdateBuffer(vo_config_list, num_bits);
		       do
		       {
			 skip_frame = RC_GlobalFrameSkipping(vo_config_list);
			 if (skip_frame)
			 {
			   time_instant = GetNextCodedVO(vo_config_list,&vo_id,&vol_id,&finish);
			 }
		       }while(skip_frame);
		     }
#endif		
		 }
		 
               /* Minhua Zhou: Compositor is changed for B-VOPs */
             
                if ((time_instant > next_display_time)||(finish==FINISHED))
                        {
                        num_out_frames = (Int)(RoundTime((time_instant - next_display_time)/
                                time_inc/(Float)M)+0.001);
                        if (!FIRST) 
                          for (TRB=1;TRB<M;TRB++)
                           for(frame = 0; frame < num_out_frames; frame++) 
                                {
                                if(temporal_scalability == 0)
                                WriteCompositedImage(enc_ctl,output_frame,B_vo_store[TRB-1],display_vop);
                                output_frame++;
                            }
                       for(frame = 0; frame < num_out_frames; frame++)
                                {
                                /* Put some text for user */
                                /* fprintf(stdout,
                                                "Writing composited frame for : %.3f <= time < %.3f\n",
                                                (float)next_display_time,
                                                RoundTime(next_display_time + time_inc)); */
                                if(temporal_scalability == 0)
                                WriteCompositedImage(enc_ctl,output_frame,next_rec_vo_store,display_vop);
                                output_frame++;
                             }
                 next_display_time = RoundTime(next_display_time + (Float)(M*num_out_frames)*time_inc);
                 /* put the next VOs to the previous VOs */
                    
                 if (FIRST) FIRST=0;
                }
                if(finish == FINISHED)
                        break;
                /* Put some text for user (display and stats file) */
#ifndef NLSSTATS
                PrintTimeStartStat(time_instant,stats_file,DISPLAY);
                PrintTimeStartStat(time_instant,stats_file,STATS_FILE);
#endif

                vo = GetVOById(video_object_list,vo_id);
                prev_vo = GetVOById(prev_vo_store,vo_id);
                prev_rec_vo = GetVOById(prev_rec_vo_store,vo_id);
                
                /* Minhua Zhou: for B-VOPs */
                next_vo = GetVOById(next_vo_store,vo_id);
                next_rec_vo = GetVOById(next_rec_vo_store,vo_id);

                vo_config = GetVOConfigById(vo_config_list,vo_id);
                vol_config = GetVolConfigById(GetVOConfigLayers(vo_config),vol_id);

                /* Put some text for user */
#ifndef NLSSTATS
                PrintVOTimeStartStat(num_bits,vo,DISPLAY);
                PrintVOTimeStartStat(num_bits,vo,STATS_FILE);
#endif

                vol = GetVolById(GetVOLayers(vo),vol_id);
                prev_vol = GetVolById(GetVOLayers(prev_vo),vol_id);
                prev_rec_vol = GetVolById(GetVOLayers(prev_rec_vo),vol_id);

                /* Minhua Zhou: for B-VOPs */
                next_vol = GetVolById(GetVOLayers(next_vo),vol_id);
                next_rec_vol = GetVolById(GetVOLayers(next_rec_vo),vol_id);
		

	/*  for spatial scalability (UPS)*/	
		
		/* modified 1197-2 SONY */
#ifdef _DEBUG_SPSC3_
		fprintf(stderr,"frame/skip = %d\n", vol_config->frame/GetVolConfigFrameSkip(vol_config));
#endif

                if( GetVolConfigScalability(vol_config)==1 && GetVolConfigScalType(vol_config)==1 )
		  {
		    int frame_skip_ratio = vol_config->frame / GetVolConfigFrameSkip(vol_config);
		    int ref_M = GetVolConfigM(GetVolConfigById(GetVOConfigLayers(vo_config),vol->ref_ident));
		    
		    if( (((frame_skip_ratio-1)%ref_M)==(ref_M-1))||(vol_config->frame==0))
		      {
#ifdef _DEBUG_SPSC3_
			fprintf(stderr,"UP=next\n");
#endif

                        base_vol     = GetVolById(GetVOLayers(next_vo),vol->ref_ident);
                        base_rec_vol = GetVolById(GetVOLayers(next_rec_vo),vol->ref_ident);
                      }
		    else
		      {
#ifdef _DEBUG_SPSC3_
			fprintf(stderr,"UP=B_vo");
			fprintf(stderr, "num== %d\n",(frame_skip_ratio-1)%ref_M);
#endif


			base_vol     = GetVolById(GetVOLayers( B_org_vo_store[(frame_skip_ratio-1)%ref_M]),vol->ref_ident);
			base_rec_vol = GetVolById(GetVOLayers(     B_vo_store[(frame_skip_ratio-1)%ref_M]),vol->ref_ident);
                    }
		  }
/* 1197-2 */

		
                /*Minhua Zhou: replace the prevs_vol with the next_vol 
		  for P-VOP coding */
		
		if(temporal_scalability == 0 || !GetVolScalability(vol)){
		    UpdateVolStore(GetVolVop(next_vol),     vol_id, prev_vol);
		    UpdateVolStore(GetVolVop(next_rec_vol), vol_id, prev_rec_vol);
		    
		    /* if use B_VOP : TPS */
		    if(!(temporal_scalability == 0 || temporal_scalability == 3) &&
		        GetVolVop(prev_vol) != NULL){
		        if(original_prev_base_vop != NULL){
			    FreeVop(original_prev_base_vop);
			    original_prev_base_vop = NULL;
                        }
			original_prev_base_vop = CloneVop_TMP(GetVolVop(prev_vol));
		    }
		}
                else{
		    if(temporal_scalability == 5 ||
		       temporal_scalability == 2 ||
		       !SkipVop(vol, vo_config, temporal_scalability)){
			UpdateVolStore(GetVolVop(next_vol),     vol_id, prev_vol);
		        UpdateVolStore(GetVolVop(next_rec_vol), vol_id, prev_rec_vol);
		    }
		    else if(current_frame_number != 0){
	                NotUpdateVolStore(GetVolVop(next_vol),     vol_id, prev_vol);
	                NotUpdateVolStore(GetVolVop(next_rec_vol), vol_id, prev_rec_vol);
	            }
	        }
		
		next_vol->pvop = NULL;
		next_rec_vol->pvop = NULL;
		
		current_frame_number=GetVolConfigFrame(vol_config);

		if((temporal_scalability == 5 || temporal_scalability == 2) &&
		   GetVolConfigScalability( vol_config ))
		    ChangeBaseImage_BGC(vo_config, base_vop_not_padding_for_bgc,
		                        &base_B_vop_TPS, vo_id, vol_id,
					current_frame_number,
					&original_prev_base_vop,
					finish_base);
		
		M = GetVolConfigM(vol_config);

/* modified 1197-2 SONY */
                if ((M-1)&&(B_vo_store==NULL)&&(B_org_vo_store==NULL)) {
                  B_org_vo_store = (VO**)calloc(M-1,sizeof(VO*));
                  B_vo_store     = (VO**)calloc(M-1,sizeof(VO*));
                  for (TRB=1;TRB<M;TRB++) {
                    B_org_vo_store[TRB-1] = InitVOStore(video_object_list);
                    B_vo_store[TRB-1]     = InitVOStore(video_object_list);
                  }
                }
/*		if ((M-1)&&(B_vo_store==NULL)) {
		  B_vo_store =(VO**)calloc(M-1,sizeof(VO*));
		  for (TRB=1;TRB<M;TRB++)
		    B_vo_store[TRB-1] = InitVOStore(video_object_list);
		    }
*/
/* 1197-2 */	       

            
	    if ( !GetVolConfigScalability( vol_config ) ){ 

		if (RCQ2_MVO_CHECK() >= RCQ2_MVO_ENABLED) {

#if 1
		  if (RCQ2_MVO_CHECK() >= RCQ2_MVO_HVS) {
		    if (FirstIntraOrInter == 0) 
		      SetFirstIntraQuantizer(vol, vol_config, 
					     current_frame_number, 0, rc_mvo.numVOs); 
		  }
#endif
		  FirstIntraOrInter = 1;
		  if (time_instant > (GetVolConfigTimeInc(vol_config))) 
		    FirstInterFrame = 0;	
  
		}
		CodeBaseVol(vol,
			    vol_config,
			    current_frame_number, 
			    time_instant,
			    prev_vol,
			    prev_rec_vol,
			    next_vol,
			    next_rec_vol,
			    0,M,                                                
			    vo_id,
			    vo_config_list, /* UPM Global RC */
			    rc_type,        /* UPM Global RC */
			    rc_algorithm,        /* hjlee */
			    &frame_type,
			    num_bits,      
/* 1197-2 SONY */
                            NULL,
/* 1197-2 */                        
			    NULL,
			    base_vop_not_padding_for_bgc,
			    temporal_scalability,
			    enhancement_type,
			    NULL);
                if(temporal_scalability != 0) ref_time_instant = time_instant;
	    }
	    /* if use I_VOP or P_VOP : TPS */
	    else if(finish_enhance != FINISHED &&
		    (temporal_scalability == 3 ||
		     temporal_scalability == 4 ||
		     temporal_scalability == 5)){
	       CodeEnhancementVol(vol,
		 		  vo_config,     
				  current_frame_number, 
				  time_instant,
				  prev_vo,       
				  prev_rec_vo,        
				  next_vo,       
				  next_rec_vo,
				  0,M,            /* M =2 */
				  vo_id,
				  vo_config_list, /* UPM Global RC */
				  rc_type,        /* UPM Global RC */
				  rc_algorithm,        /* hjlee */
				  &frame_type,
				  num_bits,
				  NULL,
				  enc_ctl,
			          base_vop_not_padding_for_bgc,
				  enhance_vop,
				  &enhance_count,
				  bgc_mode,
		                  temporal_scalability,
				  original_prev_base_vop,
				  finish_base);
	      if(temporal_scalability == 5 && GetVolVop(next_rec_vol) != NULL)
		   FIRST_enhance = 0;
	    }
	    else if(spatial_scalability) /*for ssp (UPS)*/
	      CodeEnhVol(vol,
			 vol_config,
			 current_frame_number, 
			 time_instant,
			 prev_vol,
			 prev_rec_vol,
			 base_vol,
			 base_rec_vol,
			 next_vol,
			 next_rec_vol,
			 0,1,                                                
			 vo_id,
			 vo_config_list, /* UPM Global RC */
			 rc_type,        /* UPM Global RC */
			 rc_algorithm,        /* hjlee */
			 &frame_type,
			 num_bits); /*end of ssp (UPS)*/	   

                if (!FIRST)
                for (TRB=1;TRB<M;TRB++) {
#ifndef NLSSTATS
                /* Put some text for user (display and stats file) */
                PrintTimeStartStat(time_instant-(M-TRB)*GetVolConfigTimeInc(vol_config),
                                   stats_file,DISPLAY);
                PrintTimeStartStat(time_instant-(M-TRB)*GetVolConfigTimeInc(vol_config),
                                       stats_file,STATS_FILE);
                fprintf(stdout,"Coding of B-VOP\n"); 
#endif

                if ( !GetVolConfigScalability( vol_config ) ) {
    CodeBaseVol(vol,
                vol_config,
                current_frame_number-
                (M-TRB)*GetVolConfigFrameSkip(vol_config),                                     
                time_instant-(M-TRB)*GetVolConfigTimeInc(vol_config),
                prev_vol,
                prev_rec_vol,
                next_vol,                      
                next_rec_vol,
                TRB,M,                                                
                vo_id,
                vo_config_list, /* UPM Global RC */
                rc_type,        /* UPM Global RC */
                rc_algorithm,        /* hjlee */
                &frame_type,
		num_bits,  
/* 1197-2 SONY */
                GetVolById(GetVOLayers(B_org_vo_store[TRB-1]),vol_id),
/* 1197-2 */
                GetVolById(GetVOLayers(B_vo_store[TRB-1]),vol_id),
                base_vop_not_padding_for_bgc,
                temporal_scalability,
                enhancement_type,
                &base_B_vop_TPS);
                        if(temporal_scalability)
			    ref_time_instant = time_instant-(M-TRB)*GetVolConfigTimeInc(vol_config);
                }
		else
		  fprintf(stdout,"\nERROR on .cfg with Scalabilty and ScalType settings\n");
            }
		
		/* if use B_VOP : TPS */
	        if(finish_enhance != FINISHED &&
		   GetVolConfigScalability( vol_config ) &&
		   ( (temporal_scalability == 1 && finish_base != FINISHED) ||
		     temporal_scalability == 2 )
		){
		    M = GetVolConfigFrameSkip(GetVolConfigById(GetVOConfigLayers(vo_config),
			GetVolConfigRefId(vol_config))) / GetVolConfigFrameSkip( vol_config );
                    if(temporal_scalability == 2 && M != 2){
		        fprintf(stderr,"\n-Error- now TPS_B(case2)is M = %d\n",M);
                        exit(-1);
                    }
		    if ((M-1)&&(B_vo_store==NULL)) {
		        B_vo_store =(VO**)calloc(M-1,sizeof(VO*));
		        for (TRB=1;TRB<M;TRB++)
		            B_vo_store[TRB-1] = InitVOStore(video_object_list);
		    }
		    for (TRB = 1; TRB < M; TRB++){
                        CodeEnhancementVol(vol,
                                           vo_config,     
                                           current_frame_number ,
                                           time_instant,
                                           prev_vo,       
                                           prev_rec_vo,        
                                           next_vo,       
                                           next_rec_vo,
                                           TRB,M,
                                           vo_id,
                                           vo_config_list, 
                                           rc_type,
					   rc_algorithm, /* hjlee */
                                           &frame_type,
                                           num_bits,
                                           GetVolById(GetVOLayers(B_vo_store[TRB-1]),vol_id),
                                           enc_ctl,
                                           base_vop_not_padding_for_bgc,
                                           enhance_vop,
                                           &enhance_count,
                                           bgc_mode,
                                           temporal_scalability,
                                           original_prev_base_vop,
                                           finish_base);
			if(TRB < M - 1){
			    current_frame_number =  GetVolConfigFrame(vol_config);
			    time_instant         += GetVolConfigTimeInc(vol_config);
       			    PutVolConfigNextCodingTime((Float)time_instant, vol_config);
		        }
		    }
		}/* B_VOP end : TPS */
		
		if(temporal_scalability == 5 && FIRST_enhance == 0)
		    temporal_scalability = 2;
		
	        if (temporal_scalability != 0)
	            BGCProcess(time_instant, ref_time_instant, 
                               vo_id,        vol_id,
                               vo_config,
                               next_rec_vo,
                               prev_rec_vo_store,
                               enc_ctl,
			       base_vop_not_padding_for_bgc,
                               enhance_vop,
                               &enhance_count,
                               bgc_mode,
			       temporal_scalability,
			       base_B_vop_TPS,
			       finish_base);
                if (temporal_scalability != 0 && GetVolConfigScalability(vol_config))
		    UpdateVolConfigNextCodingTimeEnhancement(vo_config, vol_id, temporal_scalability);
                /* Update the next coding time for this VOL */

		if (RCQ2_MVO_CHECK() >= RCQ2_MVO_ENABLED)
		{
		    end_time = GetVolConfigEndTime(vol_config);
            	    if (((time_instant - start_time) != 0) && 
			(time_instant < end_time)) 
		    {
                    	/***********************/
                    	/* POST-ENCODING STAGE */
                    	/***********************/
		      if(vo_id == rc_mvo.numVOs-1)
		      {
			/* Determine second order complexities for each VO */
			RCQ2_MVO_Update2OrderModel(num_bits, rc_mvo.numVOs);
			RCQ2_MVO_SkipControl(1, rc_mvo.numVOs);
			RCQ2_MVO_ResetBitCount(num_bits, rc_mvo.numVOs);
			
			/* execute any necessary frame skipping */
			for(i=0; i<rc_mvo.numVOs; i++)
			  while(vo_id==(rc_mvo.numVOs-1) && rc_mvo.skip[i]) 
			  {
			    vo_config = GetVOConfigById(vo_config_list,i);
			    vol_config = GetVolConfigById(GetVOConfigLayers(vo_config),0);
			    rc_mvo.skip[i]--;
			    rc_mvo.VBV_fullness -= rc_mvo.Bpp/rc_mvo.numVOs;
			    rc_mvo.numVOleft[i]--;
			    tmp_frame = GetVolConfigFrame(vol_config);
			    UpdateVolConfigNextCodingTime(vol_config, vo_id, vol_id, rc_type, rc_algorithm, frame_type);
			  }
		      }
            	    }
            	    else if((time_instant == start_time) && (vo_id == rc_mvo.numVOs-1)) 
		    {
		      RCQ2_MVO_ExcludeIFrame(num_bits, rc_mvo.numVOs);
		      RCQ2_MVO_ResetBitCount(num_bits, rc_mvo.numVOs);
            	    }
		    {
		      Float time_inc = GetVolConfigTimeInc(vol_config);
		      Float new_time = vol_config->next_coding_time;
		      new_time += time_inc*(Float)GetVolConfigM(vol_config);
		      new_time = RoundTime(new_time);
		      vol_config->next_coding_time = new_time;
		    }
		}
		/* inserted by Mistubishi & SAMSUNG AIT */
		else
                 UpdateVolConfigNextCodingTime(vol_config, vo_id, vol_id, rc_type, rc_algorithm, frame_type);               


		
        } /* End of while(TRUE) */


        /* Calculate average bit statistics */
        AverageBitCounts(num_bits,vo_config_list);
#ifdef NLSSTATS
        DoPrintSessionEndStat(num_bits, video_object_list, stdout);
        DoPrintSessionEndStat(num_bits, video_object_list, fpstats_file);
#else
        PrintSessionEndStat(num_bits,video_object_list,DISPLAY);
        PrintSessionEndStat(num_bits,video_object_list,STATS_FILE);
#endif

	if (RCQ2_MVO_CHECK() >= RCQ2_MVO_ENABLED)
	{
#ifdef _RC_DEBUG_
	    RCQ2_MVO_EndStats(rc_mvo.numVOs, num_bits);
#endif 
	}


  /* Close bit stream files */
        CloseBitstreams(vo_config_list);

  /*
   *
   * Deallocate all memory 
   *
   */
		
        if (rc_type == VM5_RATE_CONTROL)
	  RC_Free(vo_config_list, rc_algorithm);


        if (temporal_scalability != 0){
	    FreeEnhanceVop(enhance_vop, &enhance_count);
            if(base_vop_not_padding_for_bgc != NULL){
	        if (GetVopPrevTemp(base_vop_not_padding_for_bgc) != NULL) 
                    FreeVop(GetVopPrevTemp(base_vop_not_padding_for_bgc));
                if (GetVopNextTemp(base_vop_not_padding_for_bgc) != NULL) 
                    FreeVop(GetVopNextTemp(base_vop_not_padding_for_bgc));
                FreeVop(base_vop_not_padding_for_bgc);

		/* if use B_VOP : TPS */
		if(temporal_scalability != 3){
	            if(original_prev_base_vop != NULL)
		        FreeVop(original_prev_base_vop);
	            if(base_B_vop_TPS != NULL){
	                if(GetVopNextTemp(base_B_vop_TPS) != NULL){
	                    FreeVop(GetVopNextTemp(base_B_vop_TPS));
	                    PutVopNextTemp(NULL, base_B_vop_TPS);
	                }
	                FreeVop(base_B_vop_TPS);
	                base_B_vop_TPS = NULL;
	           }     
	        }
	    }
	 }


        /* VO i/p list */
        FreeVOList(video_object_list);

        /* VO storage lists */
        FreeVOList(prev_vo_store);
        FreeVOList(prev_rec_vo_store);

        FreeVOList(next_vo_store);
        FreeVOList(next_rec_vo_store);

/* 1197-2 SONY */
 /*** 12/10 SHARP */
  if (M-1) {
    for (TRB=1;TRB<M;TRB++) 
      FreeVOList(B_vo_store[TRB-1]);
    free(B_vo_store);
      
    if(B_org_vo_store!=NULL){
      for (TRB=1;TRB<M;TRB++) 
        FreeVOList(B_org_vo_store[TRB-1]);
      free(B_org_vo_store);
    }
  }
 /* 12/10 SHARP ***/
/* 1197-2 */
        /* Control Data Structure */
        FreeEncodeControl(enc_ctl);

        /* VO config data structures */
        FreeVOConfigList(vo_config_list);

        /* Display Vop */
        FreeVop(display_vop);
#ifndef _WD_MODE_  
        Free_SADCT_Kaup();
        Free_SADCT();
#endif

        exit(0);
}
      

/***********************************************************CommentBegin******
 *
 * -- CodeBaseVol -- High level coding function for BASE layer
 *
 * Author :             
 *      Noel O'Connor Teltec Irl.
 *
 * Created :            
 *      30-06-96
 *
 * Purpose :            
 *      This function reads in the next Vop to be coded for the BASE
 *      layer, sets up pointers to the required previous and 
 *      reconstructed Vops, calls the coding function for the Vop
 * updates the layer store, and writes the coded Vop to
 *      disk if required.
 *
 * Arguments in :       
 *      Vol *base_layer - pointer to base layer Vol structure
 *      VolConfig *layer_config - pointer to config structure for BASE
 *      Int     frame - frame containing Vop to be read from disk
 *      Int time - current coding time instant
 * Int vo_id - current VO Id
 *
 * Arguments in/out :   
 *      Vol *prev_vol_store - store of previous original layers
 *      Vol *rec_vol_store - store of previous reconstructed layers
 *      BitCount num_bits[][] - array of BitCount structures 
 *
 * Arguments out :      
 *      none
 *
 * Return values :      
 *      none
 *
 * Side effects :       
 *      none
 *
 * Description :        
 *      -
 *
 * See also :
 *      -
 *
 * Modified :           
 *      23.09.96 Noel O'Connor : small changes to allow coding of
 *               multiplt VOs.
 *      09.12.96 F. Marques: to introduce the change proposed by C. Billotet
 *          with respect to the computation of "output_frame" 
 *      15.01.97 Robert Danielsen: Updating with NULL Vop for disappearing
 *          Vop's. Fixed by Noel O'Connor.
 *      21.01.97 Added fix for bug VM4-970110-03 by Noel O'Connor.
 * 04.02.97 Noel O'Connor: cmods. for non-unique VOL Ids
 * 07.02.97 J. Ignacio Ronda: Added VM5_RATE_CONTROL 
 * 11.03.97 Minhua Zhou     : Added B_VOPs  
 * 15.05.97 Minhua Zhou     : Solved BUG VM7-970515-01 concerning VM5 Rate control
 *                            in the case of empty VOPs  
 *     04-JUL-97 Sylvie Jeannin : BUG VM7-970515-04 about TPS related memory problems
 * 08.09.97 Cecile Dufour: remove the I_VOP encoding of the static sprite
 * 04.02.98 M.Eckert: Solved bug concerning write empty VOPs, MoMuSys-VCD-V09-980126
 *
 ***********************************************************CommentEnd********/

Void
CodeBaseVol(Vol *base_layer,
            VolConfig *layer_config,
            Int frame,
            Float time,
            Vol *prev_vol_store,
            Vol *rec_vol_store,
            Vol *next_vol_store,
            Vol *next_rec_vol_store,
            Int TRB, Int TRD, 
            Int vo_id,    
            VOConfig *vo_config_list, /* UPM Global RC */
            Int rc_type,              /* UPM Global RC */
            Int rc_algorithm,              /* hjlee  */
            Int *frame_type,         /* UPM Global RC */
            BitCount num_bits[MAX_NUM_VOS][MAX_NUM_VOLS],
	    /* 1197-2 SONY */
            Vol *B_org_vol_store,
	    /* 1197-2 */        
            Vol *B_vol_store,
	    Vop *base_vop_not_padding_for_bgc,
            Int temporal_scalability,
            Int enhancement_type,
	    Vop **base_B_vop_TPS)
{
        Vol             *prev_base,
                                *rec_base;

        Vop             *curr_vop_in,
                                *curr_vop_bb,
                                *prev_vop,
                                *rec_vop,
                                *rec_curr=NULL;

        Int             shape,
                                vop_has_content,
                                vol_id,
                                vop_type,
                                output_frame;
        Vop       *no_padding_vop    = NULL,
                  *no_padding_sprite = NULL;
        /* Variables required for rate control */
        Int             vop_quantizer,
                                temp_ref,
                                target_bitrate,
                                end_time;


#ifdef _RC_DEBUG_
        Char bit_file_name[15], psnr_file_name[15], qp_file_name[15];
#endif

        vol_id = GetVolId(base_layer);

#ifdef _RC_DEBUG_
  sprintf(bit_file_name,"bits_%d_%d.b",vo_id,vol_id);
  sprintf(psnr_file_name,"psnr_%d_%d.b",vo_id,vol_id);
  sprintf(qp_file_name,"qp_%d_%d.b",vo_id,vol_id);
#endif 

	if  ( (GetVolConfigSpriteUsage(layer_config)==STATIC_SPRITE)&&
			( GetVolConfigWarpParamCounter(layer_config)==-1))
		{
		PutVolConfigWarpParamCounter(0,layer_config);
		}  /* CASE I_VOP OF SPRITE STATIC */

#ifndef NLSSTATS
        /* Put some text for user (DISPLAY and STATS FILE) */
        PrintVolTimeStartStat(num_bits,vo_id,vol_id,frame,DISPLAY);
        PrintVolTimeStartStat(num_bits,vo_id,vol_id,frame,STATS_FILE);
#endif

        /* BASE VOLs are always first in the list */
        prev_base = prev_vol_store;
        rec_base = rec_vol_store;

        /* Get Previous and Reconstructed previous VOPs if they exist */
        prev_vop = GetVolVop(prev_base);
        rec_vop = GetVolVop(rec_base);  

        curr_vop_in = GetVolVop(base_layer);
        

        ReadVopGeneric(GetVolConfigY(layer_config),
                        GetVolConfigU(layer_config),
                        GetVolConfigV(layer_config),
                        GetVolConfigA(layer_config),
                        frame,
                        IO_FORMAT,
                        curr_vop_in);
        
        /* Disable shape coding if required */
        shape = GetVolConfigShape(layer_config);

        PutVopShape(shape,curr_vop_in);
        if (shape == RECTANGULAR)
                SetConstantImage(GetVopA(curr_vop_in),BINARY_ALPHA);    
        else
                if(shape == GREY_SCALE)
                        PutVopBinaryShape(!BINARY,curr_vop_in);
                else
                        PutVopBinaryShape(BINARY,curr_vop_in);


        
  /* Need to extract bounded vop from vop read in from disk */
  /* Calc. width, height, horizontal/vertical spatial
     reference, shape of vop (REACTANGLE or ARBITRARY),
     and the type of alpha map (BINARY or NON-BINARY).
     Also extract relevant image data */

        curr_vop_bb = GetVopBounded(curr_vop_in,1,1,&vop_has_content);
        curr_vop_bb->frame = frame;

        /* Get RateControl type */
        /* Changed to GetEncodeControlRCType(enc_ctl) in Main: */
        /* rc_type = GetVolConfigRateControl(layer_config); */

        /* Get RateControl type */
        /* Changed to GetEncodeControlRCType(enc_ctl) in Main: */
        /* rc_type = GetVolConfigRateControl(layer_config); */

        if(temporal_scalability != 0 && vop_has_content)
          no_padding_vop = AllocVop(GetVopWidth(curr_vop_bb),GetVopHeight(curr_vop_bb));
        PutVopRefSelCode(-1,curr_vop_bb);  
	rec_curr = VopProcess(curr_vop_bb,
                              prev_vop,
                              rec_vop,
                              GetVolVop(next_vol_store), 
                              GetVolVop(next_rec_vol_store), 
                              time,
                              layer_config,
                              vop_has_content,
                              vo_id,TRB,TRD, 
                              vo_config_list, /* UPM Global RC */
                              rc_type,        /* UPM Global RC */
			      rc_algorithm,  /* hjlee */
                              num_bits,
                              no_padding_vop,
                              temporal_scalability);

/**/

        if(temporal_scalability != 0 && vop_has_content){
	    SaveBaseImage_BGC(layer_config,
			      no_padding_vop,
			      base_vop_not_padding_for_bgc,
			      rec_vop,
			      enhancement_type,
			      GetVopPredictionType(curr_vop_bb),
			      curr_vop_bb,
			      &(*base_B_vop_TPS),
			      temporal_scalability);/* 4/19 changed by SHARP */
	     PrintEncodeProcess_TPS(GetVopScalability(curr_vop_bb),
			            GetVopPredictionType(curr_vop_bb),
			            GetVolConfigFrameBack(layer_config),
				    GetVolConfigFrameSkip(layer_config));
	}
	
	*frame_type = GetVopPredictionType(curr_vop_bb);
	
        if (vop_has_content) {  /* added Minhua Zhou 15-05-97 */

        if (rc_type == VM5_RATE_CONTROL)
        {
#if 0
	   if (( (prev_vop==NULL)||(GetVopWidth(prev_vop)==0) || 
		 (GetVopPredictionType(curr_vop_bb) == I_VOP) ) && 
	       (rc_algorithm != RC_ALGORITHM_Q2))

	      RC_ExcludeIFrame(vo_id, vol_id, num_bits[vo_id][vol_id].vop);

/* UPM Global RC */
            else
#endif
            {
	       Int num_bits_header;	       /* ME - 26.09.97 */

	       if (RCQ2_MVO_CHECK() >= RCQ2_MVO_ENABLED)
		 ;
	       else {
		 num_bits_header = num_bits[vo_id][vol_id].vop
		   - num_bits[vo_id][vol_id].mot_shape_text;
		 
		 RC_UpdateModel(vo_id, vol_id,
				num_bits[vo_id][vol_id].vop,
				num_bits_header,
				num_bits[vo_id][vol_id].psnr_y,
				GetVopPredictionType(curr_vop_bb));	
	       }
            }

#if 0
            /* RC2: adding combined mode rate control */
            DSRC_Update2OrderModel(vo_id, vol_id,
                                       num_bits[vol_id][vol_id].vop, 0, 1);
#endif
        }
        }

        /* Update the VOL stores with coded vop and the original vop */
        
        vop_type = GetVopPredictionType(curr_vop_bb);
 
#ifdef _RC_DEBUG_
	if (vop_type == I_VOP)
	   WRITE_INT_INT(qp_file_name, frame, GetVopIntraQuantizer(curr_vop_bb))
	else if (vop_type == B_VOP)
	   WRITE_INT_INT(qp_file_name, frame, GetVopBQuantizer(curr_vop_bb))
	else if (vop_type == P_VOP)
	   WRITE_INT_INT(qp_file_name, frame, GetVopQuantizer(curr_vop_bb))
	else 
	   error_exit("ERROR CodeBaseVol: Unknown frame type!\n");
#endif

        if (vop_has_content)
	  {       
/* 1197-2 SONY */
	    if (B_vol_store==NULL&&B_org_vol_store==NULL) {
	      UpdateVolStore(curr_vop_bb,vol_id,next_vol_store);
	      UpdateVolStore(rec_curr,vol_id,next_rec_vol_store);
	    }
            else {
              UpdateVolStore(curr_vop_bb,vol_id,B_org_vol_store);
              UpdateVolStore(rec_curr,vol_id,B_vol_store);
            }
/*		      else {
                             UpdateVolStore(rec_curr,vol_id,B_vol_store);
                             FreeVop(curr_vop_bb);
                            }
*/
/* 1197-2 */


             }

        /* If the VOP is empty but the previous VOP exists, then the VO
            has disappeared. In this case the VOL stores are updated with
            a NULL VOP so that the disappearing VO is not composited
            onto the ouput display image - NOC 14/01/97 */
        else if((!vop_has_content) && (prev_vop != NULL))
                {
                      if (B_vol_store==NULL) {
                            UpdateVolStore(NULL,vol_id,next_vol_store);
                            UpdateVolStore(NULL,vol_id,next_rec_vol_store);
                           } else UpdateVolStore(NULL,vol_id,B_vol_store);
          }

        output_frame = (Int) (time*GetVolConfigFrameRate(layer_config)/1000. + .5);

        if ((rc_type == VM4_RATE_CONTROL)&&(vop_has_content)) /* modified by Minhua Zhou 15-05-97 */    
                {
                end_time = GetVolConfigEndTime(layer_config);
        
                if (((time - GetVolConfigStartTime(layer_config)) != 0) &&
                        (time < end_time))
                        {

                        vop_quantizer = GetVolConfigQuantizer(layer_config);
                        target_bitrate = GetVolConfigBitrate(layer_config);
                        temp_ref = 1000 / GetVolConfigFrameRate(layer_config);
          
                        QuantAdjust (target_bitrate,
                                        temp_ref,
                                        end_time,
                                        time,
                                        num_bits[vo_id][vol_id].average,
                                        num_bits[vo_id][vol_id].vop,
                                        &vop_quantizer);
                        fprintf(stdout, ">>>>> New quantizer= %d\n", (int)vop_quantizer);
          
                        PutVolConfigQuantizer(vop_quantizer,layer_config);
                        }
                }

        /* Write the coded vop to disk if required */
        if (GetVolConfigWriteCoded(layer_config)&&(vop_has_content)) {/* modified by M.Eckert, 04.02.98 */
           if (((TRD>1)&&TRB)|| (TRD==1) ||(prev_vop==NULL))
                        WriteCodedVopToDisk(rec_curr,
                                GetVolConfigCodedY(layer_config),
                                GetVolConfigCodedU(layer_config),
                                GetVolConfigCodedV(layer_config),
                                GetVolConfigCodedA(layer_config),
                                output_frame,
                                GetVolConfigDiskSeqX(layer_config),
                                GetVolConfigDiskSeqY(layer_config),
                                GetVolConfigShape(layer_config),
                                vop_has_content);
             if ((TRD>1)&&(TRB==TRD-1))    /* next P-VOP */
                        WriteCodedVopToDisk(GetVolVop(next_rec_vol_store),
                                GetVolConfigCodedY(layer_config),
                                GetVolConfigCodedU(layer_config),
                                GetVolConfigCodedV(layer_config),
                                GetVolConfigCodedA(layer_config),
                                output_frame,
                                GetVolConfigDiskSeqX(layer_config),
                                GetVolConfigDiskSeqY(layer_config),
                                GetVolConfigShape(layer_config),
                                vop_has_content);
    
             }
        /* Put some text for user */
#ifdef NLSSTATS
        NLSPrintVolTimeEndStat(&num_bits[vo_id][vol_id], rec_curr, time, stdout);
        NLSPrintVolTimeEndStat(&num_bits[vo_id][vol_id], rec_curr, time, fpstats_file);
#else
        PrintVolTimeEndStat(num_bits,vo_id,vol_id,vop_type,DISPLAY);
        PrintVolTimeEndStat(num_bits,vo_id,vol_id,vop_type,STATS_FILE);
#endif

#ifdef _RC_DEBUG_
	WRITE_INT_INT(bit_file_name, frame, num_bits[vo_id][vol_id].vop);
	WRITE_INT_FLOAT(psnr_file_name, frame, num_bits[vo_id][vol_id].psnr_y);
#endif


	if (RCQ2_MVO_CHECK() >= RCQ2_MVO_ENABLED) 
	  ;
	else {
	  /* Reset bit counts for the next time this VOL is coded */
	  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].sprite_piece = 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; -> set 0 in RC_UpdateBuffer! */
	}

        /* Increment occurrence counter for this VOL */
        num_bits[vo_id][vol_id].occurrence++;
      
      if(temporal_scalability != 0){
        if(no_padding_vop != NULL)
                 FreeVop(no_padding_vop);
        if(no_padding_sprite != NULL)
                 FreeVop(no_padding_sprite);
      }

	return;
}

/***********************************************************CommentBegin******
 *
 * -- CodeEnhVol -- High level coding function for ENHANCEMENT layer
 *
 * Author :		
 *	Ulrike Pestel-Schiller based on CodeBaseVol (970714)
 *
 * Created :		
 *	16-07-97
 *
 * Purpose :		
 *	This function reads in the next Vop to be coded for the ENHANCEMENT
 *	layer, sets up pointers to the required previous and 
 *	reconstructed Vops, calls the coding function for the Vop
 * updates the layer store, and writes the coded Vop to
 *	disk if required.
 *
 * Arguments in : 	
 *	Vol *enh_layer - pointer to enh layer Vol structure
 *	VolConfig *layer_config - pointer to config structure for BASE
 *	Int	frame - frame containing Vop to be read from disk
 *	Int time - current coding time instant
 * Int vo_id - current VO Id
 *
 * Arguments in/out :	
 *	Vol *prev_vol_store - store of previous original layers
 *	Vol *rec_vol_store - store of previous reconstructed layers
 *	BitCount num_bits[][] - array of BitCount structures 
 *
 * Arguments out :	
 *	none
 *
 * Return values :	
 *	none
 *
 * Side effects :	
 *	none
 *
 * Description :	
 *	-
 *
 * See also :
 *	-
 *
 * Modified :		
 *   30.07.97 Fernando Jaureguizar: commented by #ifdef 0 the code concerning
 *            to RC_ExcludeIFrame(), because this is the enhancement layer
 *   29.08.97 Osamu Sunohara: added new condition to select enhancement layer
 *                            prediction type
 *   05.09.97 Fernando Jaureguizar: added some FeeVop(). (SpSc-2)
 *
 ***********************************************************CommentEnd********/ 
Void
CodeEnhVol(Vol	*enh_layer,
	   VolConfig *layer_config,
	   Int	frame,
	   Float time,
	   Vol *prev_vol_store,
	   Vol *rec_vol_store,
	   Vol *base_vol_store,
	   Vol *base_rec_vol_store,
	   Vol *next_vol_store,
	   Vol *next_rec_vol_store,
	   Int TRB, Int TRD, 
	   Int vo_id,    
	   VOConfig *vo_config_list, /* UPM Global RC */
	   Int rc_type,              /* UPM Global RC */
	   Int rc_algorithm,              /* hjlee */
           Int *frame_type,          /* UPM Global RC */
	   BitCount num_bits[MAX_NUM_VOS][MAX_NUM_VOLS])
{
  Vol	*prev_vol,*prev_rec_vol,*base_vol,*base_rec_vol,*enh_vol;

  Vop	*curr_vop_in=NULL,
        *curr_vop_bb=NULL,
	*prev_vop=NULL,
	*prev_rec_vop=NULL,
  	*base_vop=NULL,
	*base_rec_vop=NULL,
  	*base_vop_padd=NULL,
	*base_rec_vop_padd=NULL,
        *up_vop=NULL,
	*up_rec_vop=NULL,
        *rec_curr=NULL,
        *no_padding_vop=NULL;
  
  Int	shape,
	vop_has_content,
	vol_id,
	vop_type,
	output_frame;
  Int   aux_width,
    aux_height,
    aux_hor_spat_ref ,
    aux_ver_spat_ref ; 

 
	/* Variables required for rate control */
  Int		
	  vop_quantizer,
	  temp_ref,
	  target_bitrate,
	  end_time;
	
#ifdef _RC_DEBUG_
  Char bit_file_name[15], psnr_file_name[15];
#endif 
	
  vol_id = GetVolId(enh_layer);
  	
#ifdef _RC_DEBUG_
  sprintf(bit_file_name,"bits_%d_%d.b",vo_id,vol_id);
  sprintf(psnr_file_name,"psnr_%d_%d.b",vo_id,vol_id);
#endif 
	

  /* Put some text for user (DISPLAY and STATS FILE) */
#ifndef NLSSTATS
  PrintVolTimeStartStat(num_bits,vo_id,vol_id,frame,DISPLAY);
  PrintVolTimeStartStat(num_bits,vo_id,vol_id,frame,STATS_FILE);
#endif 
	
  prev_vol     = prev_vol_store;
  prev_rec_vol = rec_vol_store;
  base_vol     = base_vol_store;
  base_rec_vol = base_rec_vol_store;
  enh_vol      = enh_layer;

  /* Get Previous and Reconstructed previous VOPs if they exist */
  prev_vop       = GetVolVop(prev_vol);
  prev_rec_vop   = GetVolVop(prev_rec_vol);
  base_vop_padd       = GetVolVop(base_vol);
  base_rec_vop_padd   = GetVolVop(base_rec_vol);		  
  curr_vop_in = GetVolVop(enh_vol);
  curr_vop_in->scalability = enh_layer->scalability;
	
  ReadVopGeneric(GetVolConfigY(layer_config),
		 GetVolConfigU(layer_config),
		 GetVolConfigV(layer_config),
		 GetVolConfigA(layer_config),
		 frame,
		 IO_FORMAT,
		 curr_vop_in);
	
  /* Disable shape coding if required */
  shape = GetVolConfigShape(layer_config);
	
  PutVopShape(shape,curr_vop_in);
  if (shape == RECTANGULAR)
    SetConstantImage(GetVopA(curr_vop_in),BINARY_ALPHA);	
  else
    if(shape == GREY_SCALE)
      PutVopBinaryShape(!BINARY,curr_vop_in);
    else
      PutVopBinaryShape(BINARY,curr_vop_in);
	
	
	
  /* Need to extract bounded vop from vop read in from disk */
  /* Calc. width, height, horizontal/vertical spatial
     reference, shape of vop (REACTANGLE or ARBITRARY),
     and the type of alpha map (BINARY or NON-BINARY).
     Also extract relevant image data */
	
  curr_vop_bb = GetVopBounded(curr_vop_in,1,1,&vop_has_content);
	
  /* Get RateControl type */
  /* Changed to GetEncodeControlRCType(enc_ctl) in Main: */
  /* rc_type = GetVolConfigRateControl(layer_config); */
	
  /*Unpadding of base layer(UPS)*/

  /*   shape rectangular in this VM */

 /* changed by Minhua Zhou on 24.09.97 */
if(GetVopPredictionType(base_rec_vop_padd) != B_VOP) {
   base_rec_vop = CloneVop_TMP(base_rec_vop_padd);
   base_vop = CloneVop_TMP(base_vop_padd);
  } else {
   base_rec_vop = CloneVop(base_rec_vop_padd);
   base_vop = CloneVop(base_vop_padd);
 }

/* 1197-2 SONY */
#ifdef _DEBUG_SPSC3_
  if(up_cnt==0) {
    WriteVopGeneric( base_rec_vop, "E_base_rec_vop", "E_base_rec_vop", "E_base_rec_vop",
                    "tmpppu", 0, IO_FORMAT, IO_OVERWRITE, 0);
  } else {
    WriteVopGeneric( base_rec_vop, "E_base_rec_vop", "E_base_rec_vop", "E_base_rec_vop",
                    "tmpppu", up_cnt, IO_FORMAT, IO_APPEND, 0);
  }
  up_cnt++;
#endif
/* 1197-2 */  

  /*Midprocessor for spatial scal (UPS)   */
  /*1197-3 SONY*/
  up_rec_vop=Midproc(base_rec_vop,enh_layer); 
  up_vop=Midproc(base_vop,enh_layer); 
  /*1197-3 SONY*/
    aux_width = GetVopWidth(up_vop);
    aux_height = GetVopHeight(up_vop);
    aux_hor_spat_ref = GetVopHorSpatRef(up_vop);
    aux_ver_spat_ref = GetVopVerSpatRef(up_vop);
    CopyVopNonImageField(base_vop_padd,up_vop);
    PutVopWidth(aux_width, up_vop);
    PutVopHeight(aux_height,up_vop);
    PutVopHorSpatRef(aux_hor_spat_ref,up_vop);
    PutVopVerSpatRef(aux_ver_spat_ref,up_vop);
    CopyVopNonImageField(base_rec_vop_padd,up_rec_vop);
    PutVopWidth(aux_width, up_rec_vop);
    PutVopHeight(aux_height,up_rec_vop);
    PutVopHorSpatRef(aux_hor_spat_ref,up_rec_vop);
    PutVopVerSpatRef(aux_ver_spat_ref,up_rec_vop);

  FreeVop(base_rec_vop); /*SpSc-2*/
  FreeVop(base_vop); /*SpSc-2*/
  VopPadding(up_rec_vop);
  VopPadding(up_vop);

  /*statistics of upsampled data*/
 
  /* modified by Sony 290897 */ 
  if ( ( (prev_vop != 0) &&
      ((layer_config->frame - layer_config->start_frame - layer_config->frame_skip)
       %(layer_config->frame_skip * layer_config->intra_period)!=0) )
      && (GetVolConfigEnhPredType(layer_config)!=1)/* <-added by Sony 290897*/ )
  /* 290897 */
    {
      /* B-VOP Spatial scalability*/
      
      PutVopPredictionType(B_VOP,curr_vop_bb);
      PutVopRefSelCode(0,curr_vop_bb);		
      PutVopForTempRef(-1,curr_vop_bb);
      PutVopBackTempRef(-1,curr_vop_bb);
      rec_curr = VopProcess(curr_vop_bb,
			    prev_vop,
			    prev_rec_vop,
			    up_vop,
			    up_rec_vop,
			    time,
			    layer_config,
			    vop_has_content,
			    vo_id,TRB,TRD,
			    vo_config_list,
			    rc_type, 
            		    rc_algorithm, /* hjlee */
			    num_bits,
			    no_padding_vop,
			    0);
    }
  else
    {
      /* P-VOP   Spatial Scalability*/

      PutVopPredictionType(P_VOP,curr_vop_bb);
      PutVopRefSelCode(3,curr_vop_bb);  
      PutVopForTempRef(-1,curr_vop_bb);
      rec_curr = VopProcess(curr_vop_bb,
			    up_vop,
			    up_rec_vop,
			    GetVolVop(next_vol_store), 
			    GetVolVop(next_rec_vol_store), 
			    time,
			    layer_config,
			    vop_has_content,
			    vo_id,TRB,TRD, 
			    vo_config_list,
			    rc_type,  
			    rc_algorithm, /* hjlee */
			    num_bits,
			    no_padding_vop,
			    0);	
    }
  FreeVop(up_rec_vop);
  FreeVop(up_vop); /*SpSc-2*/
  
  *frame_type = GetVopPredictionType(curr_vop_bb);
  
  if (vop_has_content) {  /* added Minhua Zhou 15-05-97 */
    
    if (rc_type == VM5_RATE_CONTROL)
      {
#if 0
	if ((prev_vop==NULL)||(GetVopWidth(prev_vop)==0)) /* Minhua Zhou 15-05-97 */
	  RC_ExcludeIFrame(vo_id, vol_id, num_bits[vo_id][vol_id].vop);
	
	/* UPM Global RC */
	else
#endif
	{
	   Int num_bits_header;	       /* ME - 26.09.97 */


	      num_bits_header = num_bits[vo_id][vol_id].vop
		 - num_bits[vo_id][vol_id].mot_shape_text;
	   
	   RC_UpdateModel(vo_id, vol_id,
			  num_bits[vo_id][vol_id].vop,
			  num_bits_header,
			  num_bits[vo_id][vol_id].psnr_y,
			  GetVopPredictionType(curr_vop_bb));


	}	
#if 0
	/* RC2: adding combined mode rate control */
		DSRC_Update2OrderModel(vo_id, vol_id,
				       num_bits[vol_id][vol_id].vop, 0,	1);
#endif
      }
  }
  
  /* Update the VOL stores with coded vop and the original vop */
        
  if (vop_has_content)
    {	
      UpdateVolStore(curr_vop_bb,vol_id,next_vol_store);
      UpdateVolStore(rec_curr,vol_id,next_rec_vol_store);
    }
	
  /* If the VOP is empty but the previous VOP exists, then the VO
     has disappeared. In this case the VOL stores are updated with
     a NULL VOP so that the disappearing VO is not composited
     onto the ouput display image - NOC 14/01/97 */
  else if((!vop_has_content) && (prev_vop != NULL))
	  {
	    UpdateVolStore(NULL,vol_id,next_vol_store);
	    UpdateVolStore(NULL,vol_id,next_rec_vol_store);
  	  }
  
  output_frame = (Int) (time*GetVolConfigFrameRate(layer_config)/1000. + .5);
  
  if ((rc_type == VM4_RATE_CONTROL)&&(vop_has_content)) /* modified by Minhua Zhou 15-05-97 */	
    {
      end_time = GetVolConfigEndTime(layer_config);
      
      if (((time - GetVolConfigStartTime(layer_config)) != 0) &&
	  (time < end_time))
	{
	  
	  vop_quantizer = GetVolConfigQuantizer(layer_config);
	  target_bitrate = GetVolConfigBitrate(layer_config);
	  temp_ref = 1000 / GetVolConfigFrameRate(layer_config);
	  
	  QuantAdjust (target_bitrate,
		       temp_ref,
		       end_time,
		       time,
		       num_bits[vo_id][vol_id].average,
		       num_bits[vo_id][vol_id].vop,
		       &vop_quantizer);
	  fprintf(stdout, ">>>>> New quantizer= %d\n", (int)vop_quantizer);
	  
	  PutVolConfigQuantizer(vop_quantizer,layer_config);
	}
    }
	
	/* Write the coded vop to disk if required */
	if (GetVolConfigWriteCoded(layer_config)) {
	  if (((TRD>1)&&TRB)|| (TRD==1) ||(prev_vop==NULL))
	    WriteCodedVopToDisk(rec_curr,
				GetVolConfigCodedY(layer_config),
				GetVolConfigCodedU(layer_config),
				GetVolConfigCodedV(layer_config),
				GetVolConfigCodedA(layer_config),
				output_frame,
				GetVolConfigDiskSeqX(layer_config),
				GetVolConfigDiskSeqY(layer_config),
				GetVolConfigShape(layer_config),
				vop_has_content);
	  if ((TRD>1)&&(TRB==TRD-1))    /* next P-VOP */
	    WriteCodedVopToDisk(GetVolVop(next_rec_vol_store),
				GetVolConfigCodedY(layer_config),
				GetVolConfigCodedU(layer_config),
				GetVolConfigCodedV(layer_config),
				GetVolConfigCodedA(layer_config),
				output_frame,
				GetVolConfigDiskSeqX(layer_config),
				GetVolConfigDiskSeqY(layer_config),
				GetVolConfigShape(layer_config),
				vop_has_content);
	  
	}
	/* Put some text for user */
	vop_type = GetVopPredictionType(curr_vop_bb);

#ifdef NLSSTATS
        NLSPrintVolTimeEndStat(&num_bits[vo_id][vol_id], rec_curr, time, stdout);
        NLSPrintVolTimeEndStat(&num_bits[vo_id][vol_id], rec_curr, time, fpstats_file);
#else
        PrintVolTimeEndStat(num_bits,vo_id,vol_id,vop_type,DISPLAY);
        PrintVolTimeEndStat(num_bits,vo_id,vol_id,vop_type,STATS_FILE);
#endif
	
#ifdef _RC_DEBUG_
	WRITE_INT_INT(bit_file_name, frame, num_bits[vo_id][vol_id].vop);
	WRITE_INT_FLOAT(bit_file_name, frame, num_bits[vo_id][vol_id].psnr_y);
#endif
	
	/* Reset bit counts for the next time this VOL is coded */
	   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;
	
	/* Increment occurrence counter for this VOL */
	num_bits[vo_id][vol_id].occurrence++;	
	
	return;
}

/***********************************************************CommentBegin******
 *
 * -- BitstreamPutVols -- Write VOL bitstreams to disk
 *
 * Author :             
 *      Noel O'Connor Teltec Irl.
 *
 * Created :            
 *      30-06-96
 *
 * Purpose :            
 *      Writes the VOLs to disk for all layers in the coding process.
 * 
 * Arguments in :       
 *      VO *list - Pointer to linked list of VOs which contains the VOLs
 *      whose syntax fields are to be written to disk
 *      
 * Arguments in/out :   
 *      BitCount num_bits - structure for the number of bits written to disk
 *
 * Arguments out :      
 *      none
 *
 * Return values :      
 *      none 
 *
 * Side effects :       
 *      none
 *
 * Description :        
 *      -
 *
 * See also :
 *      -
 *
 * Modified :           
 *      21.01.97 Added bytealignment fix by Luis
 *      28.01.97 Robert Danielsen: Small change in zigzag-scan
 * 26.02.97 Noel O'Connor: added shape_effects to bitstream
 *     23.04.97 M.Wollborn: MPEG quantization completely added
 *     26.04.97 Luis Ducla-Soares: Added data_partitioning flag to the bitstream.
 *     12.05.97 Minhua Zhou: added "not_8_bit", "advanced_prediction_disable", etc. 
 * 14.05.97 F. Jaureguizar: Modification of BitstreamPutBits() calls for
 *    FCode's . From 2 bits to 3 bits (VM7.0).
 *    18.07.97 Minhua Zhou: added video_object_start_code
 *    04.08.97 Minhua Zhou: removed f_codes from VOL 
 *    05.08.97 Minhua Zhou: added sadct_disable
 *    06.08.97 Noel Brady: Binary Shape Only switches out several irrelevant
 *		fields in the VOL header
 *    11.08.97 Minhua Zhou: changed quant. matrix coding
 *    12.08.97 Minhua Zhou: added time_increment_resolution
 *    08.09.97 Cecile Dufour: added input arguments: vo_config_list and rc_type
 *				to encode sprite_pieces
 *    05.11.97 Minhua Zhou:   added flags according to CD
 *    23.03.98 Michael Wollborn: moved "random_accessible_vol" due to N2171, Clause 2.1.7
 *                               included user_data() due to N2171, Clause 2.1.9
 *    26.03.98 Michael Wollborn: changes due to N2171, Clause 2.5.1/14
 *
 ***********************************************************CommentEnd********/
 
Void
BitstreamPutVOLs(VO *vo_list,BitCount num_bits[MAX_NUM_VOS][MAX_NUM_VOLS],
		 VOConfig *vo_config_list, Int rc_type)
{
  VO                    *vo;
  
  Vol           *layer;
  
  Image         *header_bitstream;
  
  Int           i, j,vol_id, vo_id, tmp_val;
  VOConfig	*vo_config;
  VolConfig	*vol_config;
  Int *qmat;
  
  vo = vo_list;
  
  while(vo != NULL)
    {
      vo_id = GetVOId(vo);
      vo_config = GetVOConfigById(vo_config_list,vo_id);
      
      layer = GetVOLayers(vo);
      
      while(layer != NULL)
        {
          /* Get VOL Id as index for accessing bitstreams and bit counts */
          vol_id = GetVolId(layer);
 	  vol_config = GetVolConfigById(GetVOConfigLayers(vo_config),vol_id);
	  
          /* Set up intermediate integer level data structure */
	  
          header_bitstream = BitstreamInit();
          
          /* 
           *
           * Write all syntax fields in VOL header to data structure
           *
           */
#ifdef  _WD_MODE_
          BitstreamPutBits(header_bitstream,VO_START_CODE,
                           28);
          BitstreamPutBits(header_bitstream,vo_id,
                           4);
#else
	  
          BitstreamPutBits(header_bitstream,VO_START_CODE,
                           27);
          BitstreamPutBits(header_bitstream,vo_id,
                           5);
#endif
	  
          

          BitstreamPutBits(header_bitstream,VOL_START_CODE,
                           VOL_START_CODE_LENGTH);
          BitstreamPutBits(header_bitstream,GetVolId(layer),4);

	  /* Included due to N2171, Clause 2.1.7 MW 23-MAR-1998 */
	  PutVolRandomAccessibleVol(0,layer);
	  BitstreamPutBits(header_bitstream,GetVolRandomAccessibleVol(layer),1);

          PutVolIsObjectLayerIdentifier(0,layer);
          BitstreamPutBits(header_bitstream,GetVolIsObjectLayerIdentifier(layer),1);
          if (GetVolIsObjectLayerIdentifier(layer)) {
            BitstreamPutBits(header_bitstream, GetVolVisualObjectLayerVerid(layer), 4);
	    BitstreamPutBits(header_bitstream, GetVolVisualObjectLayerPriority(layer), 3);
          } 
	  
          PutVolVolControlParameters(0,layer);
          BitstreamPutBits(header_bitstream,GetVolVolControlParameters(layer),1);
                          
#ifdef _WD_MODE_
	  if (GetVolShape(layer) == BINARY_SHAPE_ONLY) 
	    BitstreamPutBits(header_bitstream,2,2);
	  else
	    {
	      if (GetVolShape(layer) == 2)
		{
		  printf("Grey level shape coding not supported in WD\n");
		  exit(-1);
		}
	      else
	        BitstreamPutBits(header_bitstream,GetVolShape(layer),2);
	    }
#else

	  BitstreamPutBits(header_bitstream,GetVolShape(layer),2);

#endif  
        
	  BitstreamPutBits(header_bitstream,GetVolTimeIncrementResolution(layer),15);
	  PutVolFixedVopRate(0,layer);
	  BitstreamPutBits(header_bitstream, GetVolFixedVopRate(layer), 1);
	  
	  if (GetVolShape(layer) != BINARY_SHAPE_ONLY) {/* BSO_NOEL */
	    
	    if(GetVolShape(layer) == RECTANGULAR)
	      {
		BitstreamPutBits(header_bitstream,1,1);
		BitstreamPutBits(header_bitstream,GetVolWidth(layer),13);
		BitstreamPutBits(header_bitstream,1,1);
		BitstreamPutBits(header_bitstream,GetVolHeight(layer),13);
	      }
	    
	    BitstreamPutBits(header_bitstream,GetVolOBMCDisable(layer),1);
	    
#ifndef _WD_MODE_
	    BitstreamPutBits(header_bitstream,GetVolShapeEffects(layer),4);
#endif


#ifdef _WD_MODE_
	    if (GetVolSpriteUsage(layer) == STATIC_SPRITE 
		|| GetVolSpriteUsage(layer) == SPRITE_NOT_USED ) 
	      BitstreamPutBits(header_bitstream,GetVolSpriteUsage(layer),1);
	    else
	      {
		printf("ONLINE and GMC SPRITE not supported in WD\n");
		exit(-1);
	      }
#else
	    BitstreamPutBits(header_bitstream,GetVolSpriteUsage(layer),2);
#endif
	    if( GetVolSpriteUsage(layer) != SPRITE_NOT_USED )
	      {
                if( GetVolSpriteUsage(layer) == STATIC_SPRITE||
		    GetVolSpriteUsage(layer) == ONLINE_SPRITE)
		  {
		    BitstreamPutBits(header_bitstream, GetVolSpriteHdim(layer), 13);
		    BitstreamPutBits(header_bitstream,1,1);
		    BitstreamPutBits(header_bitstream, GetVolSpriteVdim(layer), 13);
		    BitstreamPutBits(header_bitstream,1,1);
		    tmp_val = GetVolSpriteLeftEdge(layer);
		    if (tmp_val<0) 
		      tmp_val +=8192; /* 2 complemented for signed int */
		    BitstreamPutBits(header_bitstream, tmp_val, 13);
		    BitstreamPutBits(header_bitstream,1,1);
		    tmp_val = GetVolSpriteTopEdge(layer);
		    if (tmp_val<0) 
		      tmp_val +=8192; /* 2 complemented for signed int */
		    BitstreamPutBits(header_bitstream, tmp_val, 13);
		    BitstreamPutBits(header_bitstream,1,1);
		  }
			
              	BitstreamPutBits(header_bitstream, GetVolNoOfSpritePoints(layer), 6);
              	BitstreamPutBits(header_bitstream, GetVolWarpingAccuracy(layer), 2);
              	BitstreamPutBits(header_bitstream, GetVolBrightnessChangeInSprite(layer), 1);
		BitstreamPutBits(header_bitstream, GetVolLowLatencySpriteEnable(layer), 1);
		
	      }

#ifndef _WD_MODE_
	    if (GetVolShape(layer)!=0) 
	      BitstreamPutBits(header_bitstream,GetVolSADCTDisable(layer),1);
#endif
	    
	    BitstreamPutBits(header_bitstream,GetVolNot8Bit(layer),1);
	    if (GetVolNot8Bit(layer)) {
	      BitstreamPutBits(header_bitstream,GetVolQuantPrecision(layer),4);
	      BitstreamPutBits(header_bitstream,GetVolBitsPerPixel(layer),4);
	    } 
	    
	    BitstreamPutBits(header_bitstream,GetVolQuantType(layer),1);
	    
	    /* Changed stuff for MPEG quantization (23-APR-1997, MW) */
	    if (GetVolQuantType(layer))
	      {
		BitstreamPutBits(header_bitstream,
				 GetVolLoadIntraQuantMat(layer),1);
		if(GetVolLoadIntraQuantMat(layer)) {
		  qmat = GetVolIntraQuantMat(layer);
		  for (j=63;j>=1;j--) 
		  if (qmat[*(zigzag_i+j)]!=qmat[*(zigzag_i+j-1)]) 
		    break;
		  if ((j==1)&&(qmat[*(zigzag_i+j)]==qmat[*(zigzag_i+j-1)]))
		    j=0;   
		  for(i=0; i<j+1; i++)      	              		
		    BitstreamPutBits(header_bitstream,qmat[*(zigzag_i+i)],8);
		  if (j<63) 
		    BitstreamPutBits(header_bitstream,0,8);
		}

		BitstreamPutBits(header_bitstream,
				 GetVolLoadNonintraQuantMat(layer),1);
		if(GetVolLoadNonintraQuantMat(layer)) {
		  qmat = GetVolNonintraQuantMat(layer); 
		  for (j=63;j>=1;j--) 
		  if (qmat[*(zigzag_i+j)]!=qmat[*(zigzag_i+j-1)]) 
		    break;
		  if ((j==1)&&(qmat[*(zigzag_i+j)]==qmat[*(zigzag_i+j-1)]))
		    j=0;   
		  for(i=0; i<j+1; i++)      	              		
		    BitstreamPutBits(header_bitstream,qmat[*(zigzag_i+i)],8);
		  if (j<63) 
		    BitstreamPutBits(header_bitstream,0,8);
		}
		
#ifndef _WD_MODE_
		
		/* Stuff for graylevel shape (23-APR-1997 MW) */
		if(GetVolShape(layer) == GREY_SCALE)
		  {
		    BitstreamPutBits(header_bitstream,
				     GetVolDisableGrayQuantUpdate(layer),1); 
		    
		    BitstreamPutBits(header_bitstream,
				     GetVolLoadGrayIntraQuantMat(layer),1);
		    if(GetVolLoadGrayIntraQuantMat(layer)) {
		      qmat = GetVolGrayIntraQuantMat(layer);
		      for (j=63;j>=1;j--) 
		       if (qmat[*(zigzag_i+j)]!=qmat[*(zigzag_i+j-1)]) 
		         break;
		      if ((j==1)&&(qmat[*(zigzag_i+j)]==qmat[*(zigzag_i+j-1)]))
		        j=0;   
		      for(i=0; i<j+1; i++)      	              		
		        BitstreamPutBits(header_bitstream,qmat[*(zigzag_i+i)],8);
		      if (j<63) BitstreamPutBits(header_bitstream,0,8);
		    }
		    
		    BitstreamPutBits(header_bitstream,
				     GetVolLoadGrayNonintraQuantMat(layer),1);
		    if(GetVolLoadGrayNonintraQuantMat(layer)) {
		      qmat = GetVolGrayNonintraQuantMat(layer);
		      for (j=63;j>=1;j--) 
		        if (qmat[*(zigzag_i+j)]!=qmat[*(zigzag_i+j-1)]) 
			  break;
		      if ((j==1)&&(qmat[*(zigzag_i+j)]==qmat[*(zigzag_i+j-1)]))
		        j=0;   
		      for(i=0; i<j+1; i++)      	              		
		        BitstreamPutBits(header_bitstream,qmat[*(zigzag_i+i)],8);
		      if (j<63) 
		        BitstreamPutBits(header_bitstream,0,8);
		    }
		  }
#endif
	      }


	    /* added by Minhua Zhou,complexity_estimation_disable */
	    PutVolComplexityEstimationDisable(1,layer);
	    BitstreamPutBits(header_bitstream,GetVolComplexityEstimationDisable(layer),1);
	    
	    /* Modified due to N2171 Cl. 2.5.1/14 MW 26-MAR-1998 */
	    /* BitstreamPutBits(header_bitstream,GetVolErrorResDisable(layer),1); */
	    /* if(!GetVolErrorResDisable(layer)) */
	    /*   { */
	    /*     BitstreamPutBits(header_bitstream,GetVolDataPartEnable(layer),1); */
	    /*     BitstreamPutBits(header_bitstream,GetVolReverseVlc(layer),1); */
	    /*   } */

	    BitstreamPutBits(header_bitstream,GetVolDataPartEnable(layer),1);
	    
	    if(GetVolDataPartEnable(layer))
	      BitstreamPutBits(header_bitstream,GetVolReverseVlc(layer),1);
	    else if(GetVolReverseVlc(layer))
	      {
		printf("WARNING: RVLCs can only be used if data partitioning is enabled\n");
		printf("WARNING: RVLCs will not be used!!!\n");
		PutVolReverseVlc(0,layer);
	      }

#ifndef _WD_MODE_          
	    BitstreamPutBits(header_bitstream,GetVolACDCPredDisable(layer),1);
#else
	    PutVolACDCPredDisable(0,layer); /* AC/DC prediction is always enabled */
#endif
	    BitstreamPutBits(header_bitstream,GetVolScalability(layer),1);
	    
	    if(GetVolScalability(layer))
	      {
		BitstreamPutBits(header_bitstream,GetVolRefId(layer),4);
		BitstreamPutBits(header_bitstream,GetVolRefSampDir(layer),1);
		BitstreamPutBits(header_bitstream,GetVolHorSampN(layer),5);
		BitstreamPutBits(header_bitstream,GetVolHorSampM(layer),5);
		BitstreamPutBits(header_bitstream,GetVolVerSampN(layer),5);
		BitstreamPutBits(header_bitstream,GetVolVerSampM(layer),5);
		if(GetVolEnhanceType(layer)==2)
		  PutVolEnhanceType(1,layer);
		BitstreamPutBits(header_bitstream,GetVolEnhanceType(layer),1);
	      }

	    /* Removed due to N2171, Clause 2.1.7 MW 23-MAR-1998 */
	    /* PutVolRandomAccessibleVol(0,layer); */
	    /* BitstreamPutBits(header_bitstream,GetVolRandomAccessibleVol(layer),1); */
	    
	    /*
	     *
	     * Write intermediate bitstream data structure to disk
	     *
	     */
	    
	    num_bits[vo_id][vol_id].vol += BitstreamPut(header_bitstream,vo_id,vol_id);
	    /* No longer require the intermediate data structure */
	    BitstreamFree(header_bitstream);
	    /* should this also be counted ??? -> YES/MW 23-MAR-1998 */
	    num_bits[vo_id][vol_id].vol += NextStartCode(vo_id,vol_id);
	    
	    /* Included for user data due to N2171, Cl. 2.1.9 MW 23-MAR-1998 */
	    if(GetVolConfigIsUserDataInVol(vol_config))
	      num_bits[vo_id][vol_id].vol += PutUserDataToBitstream(
		GetVolConfigUserDataInVolFile(vol_config),vo_id,vol_id);

	    if( GetVolSpriteUsage(layer) == STATIC_SPRITE&&
	    			GetVolLowLatencySpriteEnable(layer)==0)
	      {
		EncodeBasicSprite(vol_config,
				      vo_id, vol_id,
				      num_bits,
				      vo_config_list,
				      rc_type);
		num_bits[vo_id][vol_id].vol += num_bits[vo_id][vol_id].sprite_piece;
		PutVolConfigSpriteTransmitMode(STOP, vol_config);
	      }
	  } /* BSO_NOEL */
	  
	  else /* BINARY SHAPE ONLY */
	    {
	      BitstreamPutBits(header_bitstream,GetVolErrorResDisable(layer),1);
	      num_bits[vo_id][vol_id].vol += BitstreamPut(header_bitstream,vo_id,vol_id);
	      /* No longer require the intermediate data structure */
	      BitstreamFree(header_bitstream);
	      NextStartCode(vo_id,vol_id);
	      
	      /* Included for user data due to N2171, Cl. 2.1.9 MW 23-MAR-1998 */
	      if(GetVolConfigIsUserDataInVol(vol_config))
	        num_bits[vo_id][vol_id].vol += PutUserDataToBitstream(
		  GetVolConfigUserDataInVolFile(vol_config),vo_id,vol_id);
	    } 
	  
          layer = GetVolNext(layer);
        }
      
      vo = GetVONext(vo);
    }
  
  return;
}


/***********************************************************CommentBegin******
 *
 * -- UpdateVolStore -- Updates the store of Vols
 *
 * Author :             
 *      Noel O'Connor Teltec Irl.
 *
 * Created :            
 *      30-06-96
 *
 * Purpose :            
 * Given the most recent occurrence of a Vop this function
 *      updates the relevant layer in the VOL store with the
 *      new VOP. The old VOP in the store is freed.
 *
 * Arguments in :       
 *      Vop *update_vop - vop to be placed in store
 *      Int layer_id - Id of layer to be updated with i/p Vop
 *      
 * Arguments in/out :   
 *      Vol     *vol_store - linked list of Vols which acts a memory.
 *
 * Arguments out :      
 *      none
 *
 * Return values :      
 *      none
 *
 * Side effects :       
 *      none
 *
 * Description :        
 *      -
 *
 * See also :
 *      -
 *
 * Modified :           
 *
 *      
 *
 ***********************************************************CommentEnd********/
Void
UpdateVolStore(Vop *update_vop,
                                        Int layer_id,
                                        Vol *vol_store)
{
        Vol             *replace_vol;
        
        Vop             *replace_vop;

        /* Get VOL whose VOP is to be updated */
        replace_vol = GetVolById(vol_store,layer_id);

        /* Get VOP to be replaced */
        replace_vop = GetVolVop(replace_vol);

        /* Check if VOP to be replaced exists or not */
        if(replace_vop == NULL)
                PutVolVop(update_vop,replace_vol);

        else
                {
                FreeVop(replace_vop);
                PutVolVop(update_vop,replace_vol);
                }

        return;
}
                


/***********************************************************CommentBegin******
 *
 * -- InitVOStore -- Initialises the store of VOs
 *
 * Author :             
 *      Noel O'Connor Teltec Irl.
 *
 * Created :            
 *      23-09-96
 *
 * Purpose :            
 *      Initialises a store of VOs by setting up a linked list which is
 *      exactly the same as the input list of VOs (this is the list that
 *      i/p Vops are read into) except that the Vops in the Vols of the
 *      store are not allocated
 *
 * Arguments in :       
 *      VO *list - list of VOs. This is usually a list of VOs in which
 *      the Vops are allocated with the dimensions of the source seq. on disk.
 *      It is used as an input buffer for the Vops from disk. The store is
 *      initialised by simply copying this linked list apart from the 
 *      Vop field.
 *
 * Arguments in/out :   
 *  none
 *
 * Arguments out :      
 *      none
 *
 * Return values :      
 *      VO *store - initialised VO store.
 *
 * Side effects :       
 *      none
 *
 * Description :        
 *      -
 *
 * See also :
 *      -
 *
 * Modified :           
 *      -
 *      
 *
 ***********************************************************CommentEnd********/
VO *
InitVOStore(VO *list)
{
        VO      *store = NULL,
                        *vo,
                        *node;

        Vol     *vol_list,
                        *node_vol_list;

        vo = list;

        while(vo != NULL)
                {
                node = SallocVO();

                PutVOId(GetVOId(vo),node);

                vol_list = GetVOLayers(vo);

                node_vol_list = InitVolStore(vol_list);

                PutVOLayers(node_vol_list,node);

                if(store == NULL)
                        store = node;
                else
                        AddVOToList(node,store);

                vo = GetVONext(vo);
                }

        return(store);
}



/***********************************************************CommentBegin******
 *
 * -- InitVolStore -- Initialises the store of Vols
 *
 * Author :             
 *      Noel O'Connor Teltec Irl.
 *
 * Created :            
 *      30-06-96
 *
 * Purpose :            
 *      Initialises a store of Vols by setting up a linked list which is
 *      exactly the same as the input list of Vols (this is the list that
 *      i/p Vops are read into) except that the Vops in the Vol store are
 *      not allocated
 *
 * Arguments in :       
 *      Vol *list - list of Vols. This is usually a list of Vols in which
 *      the Vops are allocated with the dimensions of the source seq. on disk.
 *      It is used as an input buffer for the Vops from disk. The store is
 *      initialised by simply copying this linked list apart from the 
 *      Vop field.
 *
 * Arguments in/out :   
 * none
 *
 * Arguments out :      
 *      none
 *
 * Return values :      
 *      Vol *store - initialised VOL store.
 *
 * Side effects :       
 *      none
 *
 * Description :        
 *      -
 *
 * See also :
 *      -
 *
 * Modified :           
 *      -
 *      
 *
 ***********************************************************CommentEnd********/
Vol *
InitVolStore(Vol *list)
{
        Vol     *store = NULL,
                        *layer,
                        *node;

        layer = list;

        while(layer != NULL)
                {
                node = SallocVol();

                CopyVolSyntax(layer,node);

                if(store == NULL)
                        store = node;
                else
                        AddVolToList(node,store);

                layer = GetVolNext(layer);
                }

        return(store);
}


/***********************************************************CommentBegin******
 *
 * -- QuantAdjust -- desc
 *
 * Author :             
 *      Robert Danielsen
 *
 * Created :            
 *      29.04.96
 *
 * Purpose :            
 *      Adjust vop quantization parameter, according to method
 *      described in document Momusys/WG2-0040.
 * 
 * Arguments in :       
 *      Int target_bitrate      Target bitrate from config file
 *      Int temp_ref    Vop temp ref
 *      Int end_time    Vop end time
 *      Int time_instant        Current vop time instant
 *      Int num_bits_used       Total bits used so far for vop
 *  Int num_bits_prev   Bits used for last time instant
 *
 * Arguments in/out :   
 *      Int *QP                 Quantization parameter (Inter) to be adjusted
 *
 * Arguments out :      
 *      none
 *
 * Return values :      
 *      none
 *
 * Side effects :       
 *      Adjusts QP
 *
 * Description :        
 *      Adjusts QP according to the following rule: Calculate the number
 *      of bits available per frame for the rest of the sequence. Check
 *      if the last coded frame was more than 15% of this average. If it
 *      was, adjust QP.
 *
 * See also :
 *      -
 *
 * Modified :
 *     20-SEP-1996, M.Wollborn, Changed the code wtih respect to
 *                         the new main routines of VM3.1. The times are now
 *                         all given in milliseconds, not longer in absolute
 *                         frame numbers as in VM2.2 software. Thus this module
 *                         is not compatible with the old software!!!
 *
 ***********************************************************CommentEnd********/

Void
QuantAdjust (Int target_bitrate,
                                Int temp_ref,
                                Int end_time,
                                Int time_instant,
                                Int num_bits_used,
                                Int num_bits_prev,
                                Int *QP)
{
  Float         average;                /* Average bits/frame for remaining frames */
  Int                   dQP;                    /* Step size for change */
  Float         total_bits;     /* Could be calculated before this function */

  total_bits = 1.0 * target_bitrate * (end_time + temp_ref) / 1000;
  average    = 1.0 * (total_bits - num_bits_used)
                   / (end_time - time_instant) * temp_ref;

  fprintf(stdout,"\nRate control:");
  fprintf(stdout,"\n-------------\n");
  
  fprintf(stdout,"\nframe length: %d ms/frame", (int)temp_ref);
  fprintf(stdout,"\nend time:     %d ms", (int)end_time);
  fprintf(stdout,"\ncurrent time: %d ms\n", (int)time_instant);

  fprintf(stdout,"\ntarget bitrate:         %d bit/s", (int)target_bitrate);
  fprintf(stdout,"\ntotal bits available:   %.2f bit",total_bits);
  fprintf(stdout,"\ntotal bits used:        %d bit", (int)num_bits_used);
  fprintf(stdout,"\nbits for prev. frame:   %d bit/frame\n",
          (int)num_bits_prev);
  fprintf(stdout,"\naverage bits available: %.2f bit/frame\n",average);

  fprintf(stdout,"\nold QP: %d", (int)(*QP));

  dQP = MAX (1, *QP * 0.1);     /* Larger steps than 1 possible */

  if (num_bits_prev > (Int)(average * 1.15))
    {
    *QP = MIN (31, *QP + dQP);
    }
  if (num_bits_prev < (Int)(average / 1.15))
    {
    *QP = MAX (1, *QP - dQP);
    }

  fprintf(stdout,"\nnew QP: %d\n", (int)(*QP));
  fprintf(stdout,"\nEnd of rate control\n\n\n");
  
  return;
}

/***********************************************************CommentBegin******
 *
 * -- InitBitstreams() -- Open and initialise bitstream files
 *
 * Author :             
 *      Noel O'Connor Teltec Irl.
 *
 * Created :            
 *      28-08-96
 *
 * Purpose :            
 *      Open and initialises all bitstream files required in the encoding
 *      process. The names of these files have been read in from the video object
 *      config files on disk. They are stored in a linked list of
 *      VolConfig structures, for each VO. Each VO to be coded has
 *      a linked list associated with it. The VO config information itself
 *      is stored in a linked list of VOConfig structures. The bitstream file 
 *      pointers are stored in an array
 *      (size = MAX_NUM_VOLS) and initialised in this function by VOL id.
 *      Thus from now on in the software, to write bits for a particular layer,
 *      one simply has to pass the vol_id as an argument to the bit writing
 *      function (BitstreamPutBits()).
 * 
 * Arguments in :       
 *      VOConfig *list - linked list of VOConfig structures
 *      
 * Arguments in/out :   
 *      none
 *
 * Arguments out :      
 *      none
 *
 * Return values :      
 *      none 
 *
 * Side effects :       
 *      none
 *
 * Description :
 *      -
 *
 * See also :
 *      InitBits(), CloseBitstreams(), BitstreamPutBits(), PutBits()
 *
 * Modified :           
 *     04.02.97 Noel O'Connor: mods for non unique VOl Ids 
 *      
 *
 ***********************************************************CommentEnd********/
 
Void
InitBitstreams(VOConfig *list)
{
        VOConfig                *vo_config;

        VolConfig       *vol_config;

        Int                     vo_id,vol_id;

        Char                    *bitstream_file_name;

        vo_config = list;

        while(vo_config != NULL)
                {
                vo_id = GetVOConfigId(vo_config);

                vol_config = GetVOConfigLayers(vo_config);

                while(vol_config != NULL)
                        {
                        vol_id = GetVolConfigId(vol_config);

                        bitstream_file_name = GetVolConfigBitstream(vol_config);

                        bitstream[vo_id][vol_id] = fopen (bitstream_file_name,"wb");
                        if(bitstream[vo_id][vol_id] == NULL)
                                {
                                fprintf(stderr,"Unable to open %s\n",bitstream_file_name);
                                exit(-1);
                                }

                        InitBits(vo_id,vol_id);

                        vol_config = GetVolConfigNext(vol_config);
                        }

                vo_config = GetVOConfigNext(vo_config);
                }

        return;
}

/***********************************************************CommentBegin******
 *
 * -- CloseBitstreams() -- Closes all bitstream files
 *
 * Author :             
 *      Noel O'Connor Teltec Irl.
 *
 * Created :            
 *      28-08-96
 *
 * Purpose :            
 *      This function  closes any open bitstream files (incl. padding with
 *      1's to byte boundary).
 * 
 * Arguments in :       
 *      VOConfig *list - linked list of VO1Config structures (incl. file names
 *      and VOL ids).
 *      
 * Arguments in/out :   
 *      none
 *
 * Arguments out :      
 *      none
 *
 * Return values :      
 *      none 
 *
 * Side effects :       
 *      none
 *
 * Description :        
 *      -
 *
 * See also :
 *      NextStartCode(), InitBitstreams()
 *
 * Modified :           
 *     14.01.97 Luis Ducla-Soares: enabled byte alignment for VOL_START_CODE    
 *              by removing comment around NextStartCode() function call.
 *          21.01.97 Removed the NextStartCode line. Done elsewhere. Fix by Luis.
 *     04.02.97 Noel O'Connor: mods for non unique VOl Ids 
 *
 ***********************************************************CommentEnd********/

Void
CloseBitstreams(VOConfig *list)
{
        VOConfig                *vo_config;

        VolConfig       *vol_config;

        Int                     vo_id,vol_id;

        vo_config = list;

        while(vo_config != NULL)
                {
                vo_id = GetVOConfigId(vo_config);

                vol_config = GetVOConfigLayers(vo_config);

                while(vol_config != NULL)
                        {
                        vol_id = GetVolConfigId(vol_config);
                        
                        CloseBits(vo_id,vol_id); 

                        fclose(bitstream[vo_id][vol_id]);

                        vol_config = GetVolConfigNext(vol_config);
                        }

                vo_config = GetVOConfigNext(vo_config);
                }

        return;
}

/***********************************************************CommentBegin******
 *
 * -- InitBitCounts -- Initialise all required BitCount structures
 *
 * Author :             
 *      Noel O'Connor Teltec Irl.
 *
 * Created :            
 *      23-09-96
 *
 * Purpose :            
 *      This function initialises all required BitCount structures (i.e. sets
 *      all fields to zero and copies in the name of the stats file). The
 *      structures are stored in an array and accessed by VOL Id.
 * 
 * Arguments in :       
 *      VOConfig *vo_cfg_list - linked list of VOConfig structures (incl. VOL Ids)
 *      Char *stats_file - name of statistics file on disk
 *      
 * Arguments in/out :   
 *      none
 *
 * Arguments out :      
 *      BitCount num_bits[] - Initialised array of BitCount structures. 
 *
 * Return values :      
 *      none 
 *
 * Side effects :       
 *      none
 *
 * Description :        
 *      -
 *
 * See also :
 *      
 *
 * Modified :           
 *     04.02.97 Noel O'Connor : modified to deal with unique VOL Ids
 *     08.09.97 Cecile Dufour: added sprite_piece=0
 *      
 *
 ***********************************************************CommentEnd********/
Void
InitBitCounts(VOConfig *vo_cfg_list, 
                                Char *stats_file,
                                BitCount num_bits[MAX_NUM_VOS][MAX_NUM_VOLS])
{
        VOConfig                *vo_cfg;

        VolConfig       *vol_cfg;

        Int                     vo_id,
                                        vol_id,
                                        sep_mot_shape_text;

        vo_cfg = vo_cfg_list;

        while(vo_cfg != NULL)
                {
                vo_id = GetVOConfigId(vo_cfg);

                vol_cfg = GetVOConfigLayers(vo_cfg);
                
                while(vol_cfg != NULL)
                        {
                        vol_id = GetVolConfigId(vol_cfg);
                        sep_mot_shape_text = 0;
#ifndef NLSSTATS
                        strcpy(num_bits[vo_id][vol_id].stats_file,stats_file);
#endif
                        num_bits[vo_id][vol_id].sep_mot_shape_text = sep_mot_shape_text;
                        num_bits[vo_id][vol_id].vol = 0;
                        num_bits[vo_id][vol_id].time = 0;
                        num_bits[vo_id][vol_id].vop = 0;
                        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].sprite_piece = 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].psnr_y = 0;
                        num_bits[vo_id][vol_id].psnr_u = 0;
                        num_bits[vo_id][vol_id].psnr_v = 0;
                        num_bits[vo_id][vol_id].psnr_y_ave = 0;
                        num_bits[vo_id][vol_id].psnr_u_ave = 0;
                        num_bits[vo_id][vol_id].psnr_v_ave = 0;
                        num_bits[vo_id][vol_id].average = 0; 
			num_bits[vo_id][vol_id].average_shape = 0; 
                        num_bits[vo_id][vol_id].occurrence = 0;

                        vol_cfg = GetVolConfigNext(vol_cfg);
                        }

                vo_cfg = GetVOConfigNext(vo_cfg);       
                }

        return;
}


/***********************************************************CommentBegin******
 *
 * -- AverageBitCounts -- Calculate averages for all relevant BitCount
 *                      steuctures
 *
 * Author :             
 *      Noel O'Connor Teltec Irl.
 *
 * Created :            
 *      23-09-96
 *
 * Purpose :            
 *      This function calculates average bit statistics (and average PSNRs)
 *      for each VOL's BitCount structure. The BitCount structures are stored
 *      in an array and accessed by VOL Id.
 * 
 * Arguments in :       
 *      num_bits[] - array of BitCount structures
 *      VOConfig  *vo_cfg_list - linked list of VOConfig structures (incl. 
 *                      VOL Ids.
 *
 * Arguments in/out :   
 *      none
 *
 * Arguments out :      
 *      none
 *
 * Return values :      
 *      none 
 *
 * Side effects :       
 *      none
 *
 * Description :        
 *      
 *
 * See also :
 *      
 *
 * Modified :           
 *
 *      
 *
 ***********************************************************CommentEnd********/

Void 
AverageBitCounts(BitCount num_bits[MAX_NUM_VOS][MAX_NUM_VOLS],
                                        VOConfig *vo_cfg_list)
{
        VOConfig                *vo_cfg;

        VolConfig       *vol_cfg;

        Int                     vo_id,vol_id;

        vo_cfg = vo_cfg_list;

        while(vo_cfg != NULL)
                {
                vo_id = GetVOConfigId(vo_cfg);

                vol_cfg = GetVOConfigLayers(vo_cfg);

                while(vol_cfg != NULL)
                        {
                        vol_id = GetVolConfigId(vol_cfg);

                        num_bits[vo_id][vol_id].average = num_bits[vo_id][vol_id].average/num_bits[vo_id][vol_id].occurrence;

                        num_bits[vo_id][vol_id].average_shape = num_bits[vo_id][vol_id].average_shape/num_bits[vo_id][vol_id].occurrence;

                        num_bits[vo_id][vol_id].psnr_y_ave = num_bits[vo_id][vol_id].psnr_y_ave/num_bits[vo_id][vol_id].occurrence;
                        num_bits[vo_id][vol_id].psnr_u_ave = num_bits[vo_id][vol_id].psnr_u_ave/num_bits[vo_id][vol_id].occurrence;
                        num_bits[vo_id][vol_id].psnr_v_ave = num_bits[vo_id][vol_id].psnr_v_ave/num_bits[vo_id][vol_id].occurrence;

                        vol_cfg = GetVolConfigNext(vol_cfg);
                        }

                vo_cfg = GetVOConfigNext(vo_cfg);
                }

        return;
}

/***********************************************************CommentBegin******
 *
 * -- WriteCompositedImage -- Writes composited image to disk
 *
 * Author :             
 *      Noel O'Connor Teltec Irl.
 *
 * Created :            
 *      23-09-96
 *
 * Purpose :            
 *      This is a "psuedo" compositor. It simply takes each coded VOP in the
 *      VO store and blends them recursively onto a display VOP.
 * 
 * Arguments in :       
 *      EncodeControl *enc_ctl - pointer ot encoder control structure (incl.
 *                               display file name s on disk).
 *      Int frame - output frame number
 *      VO *vo_store - linked list of VOs (incl. most recently coded VOPs). 
 *      
 * Arguments in/out :   
 *      Vop     *display_vop - pointer to the (allocated) display vop.
 *
 * Arguments out :      
 *      none
 *
 * Return values :      
 *      none 
 *
 * Side effects :       
 *      none
 *
 * Description :        
 *      -
 *
 * See also :
 *      mini *
 * Modified : 
 *     31.01.97 Aasmund Sandvand: Added deblock filtering
 *		 06.08.97 Noel Brady:  For VOPs, having only shape information, a default
 *		 constant YUV colur is used i.e. 255,0,0
 *
 *      
 *
 ***********************************************************CommentEnd********/
Void
WriteCompositedImage(EncodeControl *enc_ctl,
                                                Int     frame,
                                                VO      *vo_store,
                                                Vop     *display_vop)
{
        VO              *vo;

        Vol     *base_layer;

        Vop     *vop, *filter_vop;

        /* Display VOP to grey */
        SetConstantImage(GetVopA(display_vop),0);
        SetConstantImage(GetVopY(display_vop),0);
        SetConstantImage(GetVopU(display_vop),128);
        SetConstantImage(GetVopV(display_vop),128);

        vo = vo_store;

        while(vo != NULL)
                {
                /* Only composite BASE layer */
                base_layer = GetVOLayers(vo);

                /* Get VOP to blend */
                vop = GetVolVop(base_layer);

                /* Check that this Vop actually exists. It may not if the
                         Vol is not active yet */
                if(vop != NULL)
                        {
                    
                    /* "Borrowed" the following from Michael Wolburn's complementary 
                       function in the decoder */
                                        
                    /*****
                     *
                     *    For rectangular VOPs set the alph-plane again to "255"
                     *    as a workaround, since it is modified by incorrect motion
                     *    compensation (without padding)
                     *
                     *****/
                        if(GetVopShape(vop) == 0)
                      SetConstantImage(GetVopA(vop),255);

										if (GetVopShape(vop) == BINARY_SHAPE_ONLY) /* BSO_NOEL */
											{
												SetConstantImage(GetVopY(vop),255);
												SetConstantImage(GetVopU(vop),0);
												SetConstantImage(GetVopV(vop),0);
											}

                    /*****
                     *
                     *    If the VOP is empty (i.e. arbitrary shape and width=height=0
                     *    then don't display it (this is not compliant with the VM yet,
                     *    since it is not specified how to tell that a VOP has
                     *     disappeared)
                     *    else create list of all VOPs to be displayed
                     *
                     *****/
                        if(GetVopShape(vop)!=0 && GetVopWidth(vop)==0)
                      continue;
                    else
                                {
                      if(GetEncodeControlPostFilterType(enc_ctl)==0)
                                        BlendVops(vop, display_vop);
                      else
                                        {
 if (GetImageSizeX(GetVopQP(vop))==GetVopWidth(vop)/16)
                                        filter_vop=CloneVop(vop);
                                     else filter_vop =CloneVop_TMP(vop); 
                                        PostFilter(filter_vop,
                                       GetEncodeControlPostFilterType(enc_ctl));
                                        BlendVops(filter_vop, display_vop);
                                        FreeVop(filter_vop);
                                        }
                                }
                        }
                vo = GetVONext(vo);
                }

        if(frame == 0)
          WriteVopGeneric(display_vop,
                          GetEncodeControlDispYFile(enc_ctl),
                          GetEncodeControlDispUFile(enc_ctl),
                          GetEncodeControlDispVFile(enc_ctl),
                          GetEncodeControlDispYFile(enc_ctl),
                          frame,
                          IO_FORMAT,
                          IO_OVERWRITE,
                          FALSE);
        else
          WriteVopGeneric(display_vop,
                          GetEncodeControlDispYFile(enc_ctl),
                          GetEncodeControlDispUFile(enc_ctl),
                          GetEncodeControlDispVFile(enc_ctl),
                          GetEncodeControlDispYFile(enc_ctl),
                          frame,
                          IO_FORMAT,
                          IO_APPEND,
                          FALSE);

        return;
}

/***********************************************************CommentBegin******
 *
 * -- GetNextCodedVO() -- Returns info on next VO to be coded 
 *
 * Author :             
 *      Noel O'Connor Teltec Irl.
 *
 * Created :            
 *      20-11-96
 *
 * Purpose :            
 *      Given a linked list of configuration information for the VOs in a session
 * this function decides what is the next VO to be coded. It does this by
 * searching for the VO with the smallest "next_coding_time" (this is a field
 * in each VOL's configuration inofrmation which is updated by the VOL's
 * time_inc/temporal reference each an instance of the VOL is coded). 
 * The time at which the next VOL should be
 * coded is returned along with the VOL and VO Id.
 * 
 * Arguments in :       
 *       VOConfig *list - linked list of VOConfig information 
 *      
 * Arguments in/out :   
 *       
 *
 * Arguments out :      
 *       Int    *vo_id - id of required VO
 *       Int  *vol_id - id of required VOL
 *
 * Return values :      
 *      
 *
 * Side effects :       
 *      none
 *
 * Description :        
 *      -
 *
 * See also :
 *      
 *
 * Modified :           
 *     20.03.97 Fernando Jaureguizar: New finish parameter to return the
 *              finish flag here instead of using the function return which
 *              gives the time_instant.
 *     27.05.97 Paulo Nunes: modified first_pass
 *
 ***********************************************************CommentEnd********/

Float
GetNextCodedVO(VOConfig *list,
                        Int *vo_id,
                        Int *vol_id,
                        Int *finish)
{
        VOConfig        *curr_vo;

        VolConfig       *curr_vol;
/* 1197-2 SONY */
	VolConfig       *curr_vol_list;
/* 1197-2 */

        Float           min_time=0,
                                next_coding_time,
                                time_to_end,
                                end_time,
                                max_end_time = -1;

        Int             first_pass = 1;
        
        curr_vo = list;

    while( curr_vo != NULL )
    {
	curr_vol_list =   /* 1197 SONY */
        curr_vol = GetVOConfigLayers(curr_vo);

        while(curr_vol != NULL)
        {
            next_coding_time = GetVolConfigNextCodingTime(curr_vol);
            end_time = GetVolConfigEndTime(curr_vol);
             if (first_pass)
            {
                *vo_id = GetVOConfigId(curr_vo);         
                *vol_id = GetVolConfigId(curr_vol);      
                min_time = next_coding_time;
                if(next_coding_time <= end_time)
                  first_pass = 0;
            }
                        
           if(max_end_time < end_time)
                max_end_time = end_time;
                        
            if(next_coding_time < min_time)
            {
                if(next_coding_time <= end_time)
                {
/* 1197-2 SONY */
                  if(  GetVolConfigScalability(curr_vol)==0 ||
                     ( GetVolConfigScalability(curr_vol)==1 && GetVolConfigScalType(curr_vol)==0 ) ||
                     (
                       GetVolConfigScalability(curr_vol)==1 && GetVolConfigScalType(curr_vol)==1 &&
/* SONY 070498 - start */
                      ( ((GetVolConfigById(curr_vol_list,GetVolConfigRefId(curr_vol)))->frame)
                       !=(curr_vol->frame+(GetVolConfigM( GetVolConfigById( curr_vol_list, GetVolConfigRefId( curr_vol ) ))-1)*GetVolConfigFrameSkip(curr_vol)) )
/* SONY 070498 - end */
                     )
                    )   
                    {
                      *vo_id = GetVOConfigId(curr_vo);
                      *vol_id = GetVolConfigId(curr_vol);
                      min_time = next_coding_time;
                    }
/*
                    *vo_id = GetVOConfigId(curr_vo);
                    *vol_id = GetVolConfigId(curr_vol);
                    min_time = next_coding_time;
*/
/* 1197-2 */
                }
                else
                {
                    /* Special case for last vop */
                    time_to_end = next_coding_time - end_time;
                    if(time_to_end < 0.001)
                    {
/* 1197-2 SONY */
                  if(  GetVolConfigScalability(curr_vol)==0 ||
                     ( GetVolConfigScalability(curr_vol)==1 && GetVolConfigScalType(curr_vol)==0 ) ||
                     (
                       GetVolConfigScalability(curr_vol)==1 && GetVolConfigScalType(curr_vol)==1 &&
/* SONY 070498 - start */
                      ( ((GetVolConfigById(curr_vol_list,GetVolConfigRefId(curr_vol)))->frame)
                       !=(curr_vol->frame+(GetVolConfigM( GetVolConfigById( curr_vol_list, GetVolConfigRefId( curr_vol ) ))-1)*GetVolConfigFrameSkip(curr_vol)) )
/* SONY 070498 - end */
                     )
                    )   
                    {
                      *vo_id = GetVOConfigId(curr_vo);
                      *vol_id = GetVolConfigId(curr_vol);
                      min_time = next_coding_time;
                    }
/*
                        *vo_id = GetVOConfigId(curr_vo);
                        *vol_id = GetVolConfigId(curr_vol);
                        min_time = next_coding_time;
*/
/* 1197-2 */
                    }
                }
            }
            curr_vol = GetVolConfigNext(curr_vol);
        }

        curr_vo = GetVOConfigNext(curr_vo);
    }

    if(min_time > max_end_time)
        *finish = FINISHED;
    else
        *finish = 0;
      return(min_time);

}






/***********************************************************CommentBegin******
 *
 * -- PutUserDataToBitstream() -- writes user data from file into bitstream
 *
 * Author :             
 *      Michael Wollborn, University of Hannover
 *
 * Created :            
 *      23-03-98
 *
 * Purpose :
 *	This function writes the user data from a file on disk into the bitstream.
 * 
 * Arguments in :       
 *	VolConfig *vol_config - VOL config information
 *
 * Arguments in/out :   
 *	Image *header_bitstream - intermediate bitstream for VOL header
 *
 * Arguments out :      
 *
 * Return values :      
 *      
 *
 * Side effects :       
 *      none
 *
 * Description :        
 *      -
 *
 * See also :
 *      
 *
 * Modified :           
 *
 ***********************************************************CommentEnd********/

Int
PutUserDataToBitstream(Char *filename, Int vo_id, Int vol_id)
{
  Int filesize=0;

  Image *header_bitstream;
  FILE *ud_file;
  Byte *data;

  Int i;

  /* Check if file is there */
  if((ud_file = fopen(filename,"rb")) == NULL)
    {
      fprintf(stderr,"ERROR(PutUserDataToBitstream): unable to open %s\n",
	      filename);
      exit(1);
    }

  /* Init intermediate data structure */
  header_bitstream = BitstreamInit();

  /* Check size of file (ftell() gives size in Bytes!) */
  fseek(ud_file,0L,SEEK_END);
  filesize = ftell(ud_file);
  rewind(ud_file);

  /* Allocate sufficient memory */
  data = (Byte *)malloc((filesize) * sizeof(Byte));

  /* Load user data */
  fread(data,1,(filesize),ud_file);

  /* Write user_data_start_code and user data */
  BitstreamPutBits(header_bitstream,USER_DATA_START_CODE,USER_DATA_START_CODE_LENGTH);

  for(i=0; i<filesize; i++)
    BitstreamPutBits(header_bitstream, data[i], 8);

  /* Write to real bitstream plus next_start_code() */
  BitstreamPut(header_bitstream,vo_id,vol_id);
  filesize += NextStartCode(vo_id,vol_id);

  /* Free memory, close file and return number of bits written*/
  BitstreamFree(header_bitstream);
  free((Char *) data);
  fclose(ud_file);
  return(filesize);
}

