/*****************************************************************************
 *
 * This software module was originally developed by
 *
 *   Michael Wollborn (TUH / ACTS-MoMuSyS)
 *   Sylvie Jeannin (Philips / ACTS-MoMuSyS)
 *
 * and edited by
 * 
 *   Ferran Marques (UPC / ACTS-MoMuSyS)
 *   Noel Brady (Teltec DCU / ACTS-MoMuSyS) 
 *   Robert Danielsen (Telenor / ACTS-MoMuSyS) 
 *   Aasmund Sandvand (Telenor / ACTS-MoMuSyS)     	                    
 *   Frederic Dufaux (Digital Equipment Corp.)        	                  
 *   Cecile Dufour (Philips LEP / ACTS-MoMuSys)        	                   
 *   Michael Frater (UNSW)
 *
 * 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_dec_main.c
 *
 * Author:	Michael Wollborn (TUH)
 * Created:	08-AUG-1996
 *                                                                         
 * Description: 
 *	Main modules necessary for decoding an MPEG-4 Video (ISO/IEC 14496-2)
 *      bitstream.
 *
 * Notes: 	
 *
 * Modified : 17-SEP-1996, M.Wollborn, included changes for the new MMR shape
 *			   decoding 
 *	      12-OCT-1996, F. Marques, to use the new names for access
 *			   functions introduced by N. O'connor 
 *            14-Jan-1997, Luis Ducla-Soares added byte alignment for
 *			   VOP_START_CODE
 *                         in function DecodeVol() and for VOL_START_CODE in
 *                         function DecodeVolHeader().
 *            02-Feb-1997, Aa. Sandvand, moved deblocking filter out of loop
 *	      04-Feb-1997, Noel O'Connor : removed all calls to assert()
 *	      07-Feb-1997, M.Wollborn: changed in order to treat skipped MBs
 *			   correctly
 *	      12.02.97 M.Wollborn: Changed to avoid double writing of last VOP
 *            15-APR-97 Jan De Lameillieure : added reading of the flag 
 *                                            'disable_sadct'
 *            15-APR-97 Jan De Lameillieure : added initialisation of SA-DCT
 *	23.04.97 Michael Wollborn: Added MPEG quantization stuff completely
 *      26.04.97 Luis Ducla Soares: Changes to allow error resilient
 *                                  decoding in the combined mode with
 *                                  data partitioning.      
 *	09.05.97 Minhua Zhou: added "DecodeGOV"
 *      14.05.97 F. Jaureguizar: Modification of number of bits of fcodes in
 *               DecodeVolHeader(). From 2 bits to 3 bits.
 *      20.06.97 M.Wollborn Extended trace mechanism for bitstream exchange
 *      07.07.97 A. Sandvand: Added support for random access
 *      24.07.97 Minhua Zhou: added B-VOPs in the decoder
 *	30.07.97 F. Jaureguizar: Integrated spatial scalability (SpSc)
 *      04.08.97 Minhua Zhou : renamed advanced_prediction_disable
 *      28.08.97 Osamu Sunohara(Sony): modified for spatial scalable coding
 *      15.09.97 A. Sandvand: Updated random access
 *      23.10.97 Minhua Zhou: changed deblock_filter_disable to 
 *                            post_filter_type
 *    03.01.97	Michael Frater: Support for non-8-bit video
 *
 ***********************************************************HeaderEnd*********/

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

#include <string.h>
#include "momusys.h"
#include "mom_bitstream_d.h"
#include "vm_compos.h"
#include "text_decode.h"
#include "mot_padding.h"
#include "io_generic.h"
#include "vm_dec_main.h"
#include "mom_vol.h"
#include "mom_access.h"
#include "mot_comp.h"
#include "zigzag.h"
#include "post_filter.h"
#include "mom_vo.h"
#include "combined_decode.h"
#include "vm_common_defs.h"
#include "sprite_util.h"
#include "sprite_dec_util.h"
#include "sprite_dec_piece.h"
#include "alp_dec_mom.h"
#include "alp_dec_header.h"
#include "text_quant_mat_def.h"
#include "interface.h"
#include "do_bgc.h" 
#include "scal_dec.h"


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


/*****
 *
 *    Scalability settings
 *
 *****/

Vop *base_output_vop[3];
Float display_framerate_TPS    = 0;
Int temporal_scalability       = 0,    /* 0 is off 1 is onn */
    TPS_base_count             = 0,
    last_base_decoding_time[3] = {-1, -1, -1},
    last_enh_decoding_time     = 0;

Int not_scalability = 1;

/*****
 *
 *    Set control for full-trace frames and default trace levels 
 *    for the other frames (1 - trace enabled, 0 - trace disabled)
 *
 *    Refer to the README file for more details.
 *
 *****/

/* Control for full-trace-frames */
#define FULL_TRACE_START	0
#define FULL_TRACE_END		30
#define FULL_TRACE_PERIOD	1

/* Default trace level settings */

/* Level 1 */
#define TRACE_LEVEL_1		1
#define	TRACE_VO_HEADER		1
#define	TRACE_VOL_HEADER	1
#define	TRACE_VOP_HEADER	1

/* Level 2 */
#define TRACE_LEVEL_2		1
#define	TRACE_MB_HEADER		1
#define	TRACE_MB_MOTION		1
#define	TRACE_MB_SHAPE		1
#define	TRACE_MB_TEXTURE        1

/* Level 3 */
#define TRACE_LEVEL_3			0
#define	TRACE_MB_SDATA		        0
#define	TRACE_MB_TDATA_BEFORE_IQ	0
#define	TRACE_MB_TDATA_AFTER_IQ		0
#define	TRACE_MB_TDATA_AFTER_IDCT	0
#define	TRACE_MB_TDATA_PREDICTED	0
#define	TRACE_MB_TDATA_RECONSTRUCTED	0


/***********************************************************CommentBegin******
 *
 * -- main -- Decodes an MPEG4 bitstream and composes the decoded VOPs
 *
 * Author :		
 *	Michael Wollborn (TUH)
 *
 * Created :		
 *	08-AUG-1996
 *
 * Purpose :		
 *	Handle the decoding of the MPEG-4 bitstream, and compose the decoded
 *	VOPs into a sequence with a given display rate, width and height.
 * 
 *
 * Arguments in : 	
 *	
 *
 * Arguments in/out :	
 *	
 *
 * Arguments out :	
 *	
 *
 * Return values :	
 *	
 *
 * Side effects :	
 *	
 *
 * Description :	
 *	
 *
 * See also :
 *	
 *
 * Modified : 
 *	27.11.96 - Noel O'Connor : Changed the variables "next_display_time" 
 *	and "time_between_two_frames" to Floats. Also added "intelligent" 
 *	rounding
 *	to avoid accumulation of Floating point errors.
 *	15.01.97 Robert Danielsen: Changed return type, added exit().
 *			Solution given by Paulo Nunes.
 *	12.02.97 M.Wollborn: Changed to avoid double writing of last VOP
 *	15-APR-97 Jan De Lameillieure : added initialisation of SA-DCT
 *      18.06.97 M.Wollborn: Added correct tracing mechanism
 *      07.07.97 A. Sandvand: Added support for random access
 *      24.07.97 Minhua Zhou: added B-VOPs in the decoder
 *      29.08.97 Osamu Sunohara: modified to make composit image exactly
 *                               in spatial scalable coding.
 *      15.09.97 A. Sandvand: Updated random access
 *      25.03.98 M.Wollborn: changes due to N2171, Cl. 2.1.9 (user data)
 *      29.03.98 M.Wollborn: cleaning of code, just editorial
 *
 ***********************************************************CommentEnd********/

Int main (Int argc, Char *argv[])
{
  Bitstream *stream[MAX_NUM_VOS][MAX_NUM_VOLS];
  Trace *trace[MAX_NUM_VOS][MAX_NUM_VOLS];
  Vol *display_vol_list[MAX_NUM_VOS];
  Vop *display_vop;
  
  Char bitstream_filename[MAX_NUM_VOS][MAX_NUM_VOLS][300], 
       trace_filename[MAX_NUM_VOS][MAX_NUM_VOLS][300],
       vol_user_data_filename[MAX_NUM_VOS][MAX_NUM_VOLS][300], /* N2171 */
       gov_user_data_filename[MAX_NUM_VOS][MAX_NUM_VOLS][300], /* N2171 */
       output_filename[4][300];

  Float display_framerate;         /* frames/s for display given by the user */

  Int display_width,		   /* width of images to be written to disk */
      display_height,		   /* height of images to be written to disk */
      number_of_vos,	           /* number of video objects */
      number_of_vols[MAX_NUM_VOS], /* number of layers for each VO*/  
      image_counter,		   /* Counter for output images */
      post_filter_type,            /* status of deblocking filter */
      bits_per_pixel,              /* Pixel depth of display */
      random_access_start_time,    /* starttime for decoding */
      stop_decoding_vol[MAX_NUM_VOS][MAX_NUM_VOLS],
      readen_bits[MAX_NUM_VOS][MAX_NUM_VOLS];	

  Float time_between_two_frames,   /* number of ms between 2 displ. frames */
	next_display_time;	   /* next absolute time for displ. a frame */

  Int i,j,k;

  /* VTC Begin -----------------------------------------------*/
  Int NoVOLflag = TRUE;
  Int num_VOLs=0;

  File *VTCfptr;
  Int  number_of_vtcs,
       vo,shape_width,shape_height,
       target_bitrate, 
       target_spatial_level, 
       target_snr_level;
  Char VTC_bitstream_filename[300], 
       VTC_output_filename[300], 
       VTC_shape_filename[300];
  /* VTC End -----------------------------------------------*/

  /* 1197-3 SONY */
  /* added by Sony 010997 */
  /*  Int not_scalability = 1;*/
  Vol *next_vol = NULL;
  /* 010997 */
  /* 1197-3 */
 
  /*****
   *
   *	Get the arguments from the user:
   *
   *	Number of VOs, layers for each VO and the filenames for the
   *	respective bitstreams (each VOL is stored in a separate bitstream).
   *
   *	Name and path of the output image sequence file(s) and display
   *	frame rate
   *
   *****/

  /* VTC Begin -----------------------------------------------*/
  VTCfptr = GetDecoderArguments (argc, argv, &number_of_vos, number_of_vols, 
                                 &number_of_vtcs, /* VTC */
                                 bitstream_filename, vol_user_data_filename,
				 gov_user_data_filename, output_filename, 
                                 &display_framerate,&display_width,
				 &display_height,
                                 &post_filter_type,&bits_per_pixel,
                                 &random_access_start_time);

  for (vo=0; vo<number_of_vtcs; vo++) 
    {
      GetVTCDecoderArguments (VTCfptr,
			      VTC_bitstream_filename, 
			      VTC_output_filename, 
			      VTC_shape_filename, 
			      &shape_width,
			      &shape_height,
			      &target_bitrate, 
			      &target_spatial_level,
			      &target_snr_level);
      VTC_Decode(VTC_bitstream_filename, 
		 VTC_output_filename,
		 VTC_shape_filename,
		 shape_width,
		 shape_height,
		 target_bitrate, 
		 target_spatial_level, 
		 target_snr_level);
    }
  
  fclose(VTCfptr);
  /* VTC End -----------------------------------------------*/

#if 0 /* Do we still really need this??? MW 28-MAR-1998 */
  for (i=0;i<number_of_vos;i++){
    num_VOLs = 0;

    for (j=0;j<number_of_vols[i];j++){

        num_VOLs++;
        NoVOLflag = FALSE;
    }
    number_of_vols[i] = num_VOLs;
  }

  if (NoVOLflag)   return 0;
#endif

  /*****
   *
   *	Allocate memory for the display_vop which is used for composition
   *	purposes
   *
   *****/
  display_vop = AllocVop(display_width,display_height);
  PutVopBitsPerPixel(bits_per_pixel, display_vop);

  /*****
   *
   *	Calculate the time between two frames to be displayed in ms
   *	(from display_frame_rate) and allocate the necessary VOL, bitstream
   *	and trace structures
   *
   *****/
  time_between_two_frames = (Float)1000 / display_framerate;

  /* for TPS */
  for (i=0; i<MAX_NUM_VOS; i++) 
    {
      bs_vo[i] = -1;
      for (k=0; k<MAX_NUM_VOLS; k++) 
	bs_vol[i][k] = -1;
    }
  /**/

  for(i=0; i<number_of_vos; i++)
    {
      /* for TPS */
      bs_vo[i] = i; /* This part needs to change when VO header is decoded. */
      /**/

      display_vol_list[i] = InitVolList(number_of_vols[i]);
      
      for(k=0; k<number_of_vols[i]; k++)
	{
	  stream[i][k] = BitstreamOpen(bitstream_filename[i][k]);
	  readen_bits[i][k] = 0;
	  stop_decoding_vol[i][k] = 0;

	  strcpy(trace_filename[i][k], bitstream_filename[i][k]);
	  strcat(trace_filename[i][k], ".dec_log");
	  
	  /*****
	   *
	   *    Trace capabilities. The settings by the users should be
	   *    done at the top of this file!
	   *
	   *    Please DO NOT MODIFY any values below here !
	   *
	   *****/
	  
#ifdef _DEBUG_
	  
	  trace[i][k] = allocate_trace_file(trace_filename[i][k], "w");
	  
	  trace[i][k]->counter              = 0; 
	  trace[i][k]->trace                = 0; 

	  /* Set frames for full trace (see README for details) */
	  trace[i][k]->full_trace_start     = FULL_TRACE_START; 
	  trace[i][k]->full_trace_end       = FULL_TRACE_END; 
	  trace[i][k]->full_trace_period    = FULL_TRACE_PERIOD; 

	  /* Set default trace levels (see README for details) */
	  
	  /* Level 1 data */
	  if(TRACE_LEVEL_1)
	    {
	      trace[i][k]->VO_header_def  = TRACE_VO_HEADER;
	      trace[i][k]->VOL_header_def = TRACE_VOL_HEADER;
	      trace[i][k]->VOP_header_def = TRACE_VOP_HEADER;
	    }
	  else
	    {
	      trace[i][k]->VO_header_def  = 0;
	      trace[i][k]->VOL_header_def = 0;
	      trace[i][k]->VOP_header_def = 0;
	    }
	  
	  /* Level 2 data */
	  if(TRACE_LEVEL_2)
	    {
	      trace[i][k]->MB_header_def  = TRACE_MB_HEADER;
	      trace[i][k]->MB_motion_def  = TRACE_MB_MOTION;
	      trace[i][k]->MB_shape_def   = TRACE_MB_SHAPE;
	      trace[i][k]->MB_texture_def = TRACE_MB_TEXTURE;
	    }
	  else
	    {
	      trace[i][k]->MB_header_def  = 0;
	      trace[i][k]->MB_motion_def  = 0;
	      trace[i][k]->MB_shape_def   = 0;
	      trace[i][k]->MB_texture_def = 0;
	    }
	  
	  /* Level 3 data */
	  if(TRACE_LEVEL_3)
	    {
	      trace[i][k]->MB_sdata_def               = TRACE_MB_SDATA;
	      trace[i][k]->MB_tdata_before_IQ_def     = TRACE_MB_TDATA_BEFORE_IQ;
	      trace[i][k]->MB_tdata_after_IQ_def      = TRACE_MB_TDATA_AFTER_IQ;
	      trace[i][k]->MB_tdata_after_IDCT_def    = TRACE_MB_TDATA_AFTER_IDCT;
	      trace[i][k]->MB_tdata_predicted_def     = TRACE_MB_TDATA_PREDICTED;
	      trace[i][k]->MB_tdata_reconstructed_def = TRACE_MB_TDATA_RECONSTRUCTED;
	    }
	  else
	    {
	      trace[i][k]->MB_sdata_def               = 0;
	      trace[i][k]->MB_tdata_before_IQ_def     = 0;
	      trace[i][k]->MB_tdata_after_IQ_def      = 0;
	      trace[i][k]->MB_tdata_after_IDCT_def    = 0;
	      trace[i][k]->MB_tdata_predicted_def     = 0;
	      trace[i][k]->MB_tdata_reconstructed_def = 0;
	    }
	  
#else
	  trace[i][k] = (Trace *) malloc( sizeof(Trace) );
	  
	  trace[i][k]->counter              = 0; 
	  trace[i][k]->trace                = 0; 
	  
	  /* Set frames for full trace (see README for details) */
	  trace[i][k]->full_trace_start     = 0; 
	  trace[i][k]->full_trace_end       = 0; 
	  trace[i][k]->full_trace_period    = 0; 
	  
	  /* Set default trace levels (see README for details) */
	  
	  /* Level 1 data */
	  trace[i][k]->VO_header_def  = 0;
	  trace[i][k]->VOL_header_def = 0;
	  trace[i][k]->VOP_header_def = 0;
	  
	  /* Level 2 data */
	  trace[i][k]->MB_header_def  = 0;
	  trace[i][k]->MB_motion_def  = 0;
	  trace[i][k]->MB_shape_def   = 0;
	  trace[i][k]->MB_texture_def = 0;
	  
	  /* Level 3 data */
	  trace[i][k]->MB_sdata_def               = 0;
	  trace[i][k]->MB_tdata_before_IQ_def     = 0;
	  trace[i][k]->MB_tdata_after_IQ_def      = 0;
	  trace[i][k]->MB_tdata_after_IDCT_def    = 0;
	  trace[i][k]->MB_tdata_predicted_def     = 0;
	  trace[i][k]->MB_tdata_reconstructed_def = 0;
	  
#endif

	}
      DecodeVolHeaderList(number_of_vols[i],stream[i],trace[i],
			  display_vol_list[i],readen_bits[i],i,
			  vol_user_data_filename[i]); /* N2171 user data */
    }

  /*****
   *
   *	Initializations
   *
   *****/

  /* Random access */
  if (random_access_start_time != 0)
    random_access_start_time = 
      ((Int)(random_access_start_time + 0.5*time_between_two_frames) / 
       (Int) time_between_two_frames) * time_between_two_frames;
  if (random_access_start_time != 0)
    printf("Adjusted random_access_start_time=%i\n",random_access_start_time);
  next_display_time = 0;
  
  /* Scalability */
  image_counter = 0;
  for(i = 0; i < 3 ; i++) 
    base_output_vop[i] = NULL;

  display_framerate_TPS = display_framerate;
  image_width  = display_width;
  image_height = display_height;

  strcpy( &comp_output_filename[ 0 ][ 0 ] , &output_filename[ 0 ][ 0 ] );
  strcpy( &comp_output_filename[ 1 ][ 0 ] , &output_filename[ 1 ][ 0 ] );
  strcpy( &comp_output_filename[ 2 ][ 0 ] , &output_filename[ 2 ][ 0 ] );
  strcpy( &comp_output_filename[ 3 ][ 0 ] , &output_filename[ 3 ][ 0 ] );

#ifndef _WD_MODE_
  
  /* SA-IDCT */
  Initialisations_for_SADCT();
  Initialisations_for_SADCT_Kaup();

#endif


  /* if random_access, find time_between_govs */
  if (random_access_start_time != 0)
    {
      next_display_time = random_access_start_time;
      for(i=0; i<number_of_vos; i++)
	FindStartGOV(number_of_vols[i],stream[i],trace[i],display_vol_list[i],
		     readen_bits[i],random_access_start_time);
    }

  /* added by Sony 010997 */
  for(i=0; i<number_of_vos; i++) 
    {
      next_vol = display_vol_list[i];
      for(k=0; k<number_of_vols[i]; k++) 
	{
	  if(GetVolScalability(next_vol))
	    not_scalability=0;
	  next_vol = GetVolNext(next_vol);
	}
      next_vol = NULL;
    }
  next_vol = NULL;
  /* 010997 */
  
  /*****
   *
   *	Process all bitstreams in parallel, i.e. up to the display time
   *	decode each VOL of each VO and compose then the respective
   *	image to be displayed out of all layers of all VOs. Then again
   *	decode each VOL of each VO up to the next display time etc.
   *
   *****/
  
  for(i=0; i<number_of_vos; i++)
    Check_TPS(number_of_vols[i],stream[i],trace[i],random_access_start_time,
	      display_vol_list[i]);

  while(!StopDecoding(number_of_vos,number_of_vols,stop_decoding_vol))
    {
       if (temporal_scalability)
	fprintf(stderr,"===( next [%d] )===\n",(Int)next_display_time);
      for(i=0; i<number_of_vos; i++)
	/* Modified due to N2171 Cl. 2.1.x (user data) MW 26-MAR-1998 */
	/* DecodeVolList(number_of_vols[i],stream[i],trace[i], */
	/* 	      next_display_time, random_access_start_time, */
	/* 	      display_vol_list[i],readen_bits[i], */
	/*            stop_decoding_vol[i], */
	/* 	      i,post_filter_type,); */
	DecodeVolList(number_of_vols[i],stream[i],trace[i],
		      next_display_time, random_access_start_time,
		      display_vol_list[i],readen_bits[i],stop_decoding_vol[i],
		      i,post_filter_type, gov_user_data_filename[i]);
      
      if (not_scalability) 
	{   
	  WriteOutputImage(number_of_vos,
			   display_vol_list,next_display_time,
			   random_access_start_time,display_vop,image_counter,
			   output_filename,post_filter_type,stop_decoding_vol);
	  image_counter++;
	}
    
      printf( "======================================\n");
      printf( "[%d]{curr_time}:%f ->" , image_counter, next_display_time );
      
      next_display_time += time_between_two_frames;
      /* next_display_time = RoundTime(next_display_time); */
    
      printf( "{next_time} = %f\n" , next_display_time );
    }
  
  /*****
   *
   *	Freeing of display_vop, VOLs, bitstream structures and trace files
   *
   *****/
  
  FreeVop(display_vop);
  
  for(i=0; i<number_of_vos; i++)
    {
      FreeVolList(display_vol_list[i]);
      
      for(k=0; k<number_of_vols[i]; k++)
	{
	  BitstreamClose(stream[i][k]);
#ifdef _DEBUG_
	  free_trace_file(trace[i][k]);
#endif
	}
    }
  
 
#ifndef _WD_MODE_
  Free_SADCT_Kaup(); 
  Free_SADCT();
#endif
  
  for (i=0;i<3;i++) 
    if (base_output_vop[i]!=NULL) FreeVop(base_output_vop[i]);
  if (temporal_scalability) 
    FreeShapeVop(); 
  
  exit(0);
}				/* main */





/***********************************************************CommentBegin******
 *
 * -- GetDecoderArguments -- Gets from the user needed arguments for 
 *			     decoding & display  
 *
 * Author :		
 *	Sylvie Jeannin (LEP)
 *
 * Created :		
 *	11-Mar-96
 *
 * Purpose :		
 *	Get from the user needed arguments for decoding & display.
 *
 * 
 * Arguments in : 	
 *	Int   argc,		 as usual (coming from main).
 *	Char *argv[],		 as usual (coming from main).
 *
 *
 * Arguments in/out :	
 * 	Int *number_of_vos		number of video objects
 *	Int number_of_vols[]   		number of layers per video objects
 *	Char bitstream_filename[][][]	filenames for the respective bitstreams
 *	Char output_filename[][]	names of output files for Y, U and V
 *	Char user_data_filename [][]    names of files to write received user 
 *                                      data (N2171)
 *	Float *display_frame_rate		frame rate for output sequence
 *      Int *post_filter_type     status of deblock filter
 *      Int *random_access_start_time
 *
 *
 * Arguments out :	
 *	
 *
 * Return values :	
 *	
 *
 * Side effects :	
 *	
 *
 * Description :	
 *	
 *
 * See also :
 *	
 *
 * Modified : 08.08.96 - M. Wollborn: changed for high level syntax in order
 *				      to be compliant with VM3.0
 *            31.01.97 Aa. Sandvand: Added post_filter_type
 *            07.07.97 A. Sandvand: Added random_access_start_time
 *            03.01.98 M. Frater: Support for non-8-bit video
 *	      25.03.98 M.Wollborn: included argument for user data files 
 *                                 (N2171)
 *
 ***********************************************************CommentEnd********/
File *GetDecoderArguments (Int argc, Char *argv[], 
			   Int *number_of_vos, 
			   Int number_of_vols[], 
                           Int *number_of_vtcs,  /* VTC */
			   Char bitstream_filename[][MAX_NUM_VOLS][300], 
			   Char vol_user_data_filename[][MAX_NUM_VOLS][300], /* N2171 */
			   Char gov_user_data_filename[][MAX_NUM_VOLS][300], /* N2171 */
			   Char output_filename[][300],
			   Float *display_framerate,
			   Int *display_width,
			   Int *display_height,
			   Int *post_filter_type,
			   Int *bits_per_pixel,
			   Int *random_access_start_time
                           )
{
  Char config_filename[300],garbage[80];
  File *fd;
  Int i,k;
  
  /*****
   *
   *	The parameters have to be read in by a configuration file
   *
   *****/
  if(argc == 2)
    strcpy(config_filename,argv[1]);
  else
    {
      (Void) printf("Usage: vm_dec.exe control_file\n");
      exit(1);
    }
  
  /*****
   *
   *	Read the decoder configuration file
   *
   *****/
  if((fd = fopen(config_filename,"r")) == NULL)
    {
      printf("Error: Control file <<%s>> not found\n",config_filename);
      exit(1);
    }
  
  /* Number of video objects */
  fscanf(fd,"%d",number_of_vos);
  fgets(garbage,80,fd);
  
  /* Number of video object layers per VO */
  for(i=0; i<*number_of_vos; i++)
    {
      fscanf(fd,"%d",&number_of_vols[i]);
      fgets(garbage,80,fd);
      
      /* Name of bitstream files for each VOL of each VO */
      for(k=0; k<number_of_vols[i]; k++)
	{
	  fscanf(fd,"%s", (Char *)&bitstream_filename[i][k]);
	  fgets(garbage,80,fd);
	}
      
      /* Name of output file for user data  on VOL level for each VOL of each VO */
      for(k=0; k<number_of_vols[i]; k++)
	{
	  fscanf(fd,"%s", (Char *)&vol_user_data_filename[i][k]);
	  fgets(garbage,80,fd);
	} 
      
      /* Name of output file for user data  on GOV level for each VOL of each VO */
      for(k=0; k<number_of_vols[i]; k++)
	{
	  fscanf(fd,"%s", (Char *)&gov_user_data_filename[i][k]);
	  fgets(garbage,80,fd);
	} 
    } 
  
  /* Name of output filenames for Y, U and V components */
  for(i=0; i<4; i++)
    {
      fscanf(fd,"%s", (Char *)&output_filename[i]);
      fgets(garbage,80,fd);
    }
  
  /* Display framerate */
  fscanf(fd,"%f",display_framerate);
  fgets(garbage,80,fd);
  
  /* Display width */
  fscanf(fd,"%d",display_width);
  fgets(garbage,80,fd);

  /* Display height */
  fscanf(fd,"%d",display_height);
  fgets(garbage,80,fd);

  /* post_filter_type */
  fscanf(fd,"%d",post_filter_type);
  fgets(garbage,80,fd);

  /* display pixel depth */
  fscanf(fd,"%d",bits_per_pixel);
  fgets(garbage,80,fd);

  /* random_access_start_time */
  fscanf(fd,"%d",random_access_start_time);
  fgets(garbage,80,fd);

  /* Number of VTC objects */
  fscanf(fd,"%d",number_of_vtcs);
  fgets(garbage,80,fd);

  return fd;  /* VTC */
} 			/* GetDecoderArguments */



/* VTC Begin -----------------------------------------------*/
Void GetVTCDecoderArguments (File *fd,
                              Char VTC_bitstream_filename[], 
                              Char VTC_output_filename[], 
                              Char VTC_shape_filename[], 
                              Int *shape_width,
                              Int *shape_height,
                              Int *target_bitrate, 
                              Int *target_spatial_level,
                              Int *target_snr_level)
{
  Char garbage[80];
                                          
  fscanf(fd,"%s", VTC_bitstream_filename);
  fgets(garbage,80,fd);

  fscanf(fd,"%s", VTC_output_filename);
  fgets(garbage,80,fd);

  fscanf(fd,"%d",shape_width);
  fgets(garbage,80,fd);

  fscanf(fd,"%d",shape_height);
  fgets(garbage,80,fd);

  fscanf(fd,"%d",target_bitrate);
  fgets(garbage,80,fd);

  fscanf(fd,"%d",target_spatial_level);
  fgets(garbage,80,fd);

  fscanf(fd,"%d",target_snr_level);
  fgets(garbage,80,fd);

}
/* VTC End -----------------------------------------------*/





/***********************************************************CommentBegin******
 *
 * -- InitVolList -- Initialize a list of video object layers for one VO 
 *
 * Author :		
 *      Michael Wollborn (TUH)
 *
 * Created :		
 *	08-AUG-1996
 *
 * Purpose :
 *	Initialize a list of layers for a specific video object. Within
 *	each VOL two VOPs are "salloced" in temporal list, one for the
 *	previous reconstructed VOP which is required for decoding of
 *	P-VOPs and one for the current VOP to be decoded.
 *
 * 
 * Arguments in : 	
 *	Int number_of_vols	number of layers for the video object
 *
 *
 * Arguments in/out :	
 *
 *
 * Arguments out :	
 *	
 *
 * Return values :
 *	Vol *vol_list		pointer to list of layers for video object
 *	
 *
 * Side effects :	
 *	
 *
 * Description :	
 *	
 *
 * See also :
 *	
 *
 * Modified :
 *	
 *
 ***********************************************************CommentEnd********/

Vol *InitVolList(Int number_of_vols)
{
  Vol *vol_list,*next_vol;
  Vop *vop1,*vop2;
  Int i;

  /*****
   *
   *	Initialize as many VOLs as necessary
   *
   *****/
  if(number_of_vols > 0)
    {
    vol_list = SallocVol();
    
    vop1 = SallocVop();
    PutVolVop(vop1,vol_list);
    
    vop2 = SallocVop();
    PutVopWidth(0,vop2);
    vop2->mod_time_base=-1;
    PutVopNextTemp(vop2,vop1);

    vop2 = SallocVop();
    PutVopWidth(0,vop2);
    vop2->mod_time_base=-1;
    PutVopPrevTemp(vop2,vop1);

    /* 1197-3 SONY */
    PutVopBvopTemp( NULL, vop1);
    /* 1197-3 */

    next_vol = vol_list;
    
    for(i=1; i<number_of_vols; i++)
      {
	PutVolNext(SallocVol(),next_vol);
	next_vol = GetVolNext(next_vol);
	
	vop1 = SallocVop();
	PutVolVop(vop1,next_vol);
	
	vop2 = SallocVop();
	vop2->mod_time_base=-1;
	PutVopWidth(0,vop2);
	
	PutVopNextTemp(vop2,vop1);
	
	vop2 = SallocVop();
	vop2->mod_time_base=-1;
	PutVopWidth(0,vop2);
	
	PutVopPrevTemp(vop2,vop1);
	
	/* 1197-3 SONY */
	PutVopBvopTemp( NULL, vop1);
	/* 1197-3 */
	
      }
    
    return(vol_list);
    }
  else
    return(NULL);
}





/***********************************************************CommentBegin******
 *
 * -- DecodeVolHeaderList -- Decode the headers for a list of VOLs for one VO 
 *
 * Author :		
 *      Michael Wollborn (TUH)
 *
 * Created :		
 *	08-AUG-1996
 *
 * Purpose :
 *	Decode the headers for a list of VOLs for a specific VO from given
 *	bitstreams. The bitstream for each layer is given in a separate file
 *
 * 
 * Arguments in : 	
 *	Int number_of_vols	number of layers for the video object
 *	Bitstream *stream[]	Pointer list to the bitstreams
 *	Trace *trace[]		Trace information for each layer
 *
 *
 * Arguments in/out :	
 *	Vol *vol_list	concat. list of layers for video object
 *	Int readen_bits[]	Readen bits for each layer
 *
 *
 * Arguments out :	
 *	
 *
 * Return values :	
 *	
 *
 * Side effects :	
 *	
 *
 * Description :	
 *	
 *
 * See also :
 *	
 *
 * Modified :	25.03.98 M.Wollborn: N2171 user data
 *	
 *
 ***********************************************************CommentEnd********/

Void DecodeVolHeaderList(Int number_of_vols, Bitstream *stream[], 
			 Trace *trace[], Vol *vol_list, Int readen_bits[],
			 Int vo_id, Char vol_user_data_filename[][300])
{
  Vol *next_vol;
  Int i;
  
  /*****
   *
   *	Decode the header for each VOL for the current VO
   *	(allocate first dummy VOP if non-rectangular shape)
   *
   *****/
  next_vol = vol_list;
  
  for(i=0; i<number_of_vols; i++)
    {
      DecodeVolHeader(stream[i],trace[i],next_vol,&readen_bits[i],vo_id,i,
		      vol_user_data_filename[i]); /* N2171 user data */
      if(GetVolShape(next_vol) == 0)
	AllocVopChannels(GetVolVop(next_vol),GetVolWidth(next_vol),
			 GetVolHeight(next_vol));
      else
	AllocVopChannels(GetVolVop(next_vol),2,2);
      
      next_vol = GetVolNext(next_vol);
    }
  
  return;
}





/***********************************************************CommentBegin******
 *
 * -- DecodeVolHeader -- Decode the header of a VOL
 *
 * Author :		
 *      Michael Wollborn (TUH)
 *
 * Created :		
 *	08-AUG-1996
 *
 * Purpose :
 *	Decode the header of a VOL
 *
 * 
 * Arguments in : 	
 *	Bitstream *stream	Pointer to the bitstream
 *	Trace *trace		Trace information for VOL
 *
 *
 * Arguments in/out :	
 *	Vol *next_vol		video object layer to be decoded
 *	Int *readen_bits	Readen bits for VOL
 *
 *
 * Arguments out :	
 *	
 *
 * Return values :	
 *	
 *
 * Side effects :	
 *	
 *
 * Description :	
 *	
 *
 * See also :
 *	
 *
 * Modified : Noel Brady 14-10-96
 *			Code added to read 
 *			error_resilient_disable,
 *			intra_acdc_disable,
 *			deblocking_filter_disable.
 *            14.01.97 Luis Ducla-Soares: added byte alignment for
 *			VOL_START_CODE
 *                      (call to function BitstreamByteAlign() )	
 *	28.01.97 Robert Danielsen: Small change to zigzag-scan
 *	23.04.97 Michael Wollborn: Added MPEG quantization stuff completely
 *      26.04.97 Luis Ducla Soares: Changes to allow error resilient
 *                                  decoding in the combined mode with
 *                                  data partitioning.
 * 12.05.97 Minhua Zhou: added "not_8_bit", "advanced_prediction_disable", etc.
 * 14.05.97 F. Jaureguizar: Modification of number of bits of fcodes, from
 *          2 bits to 3 bits (according to VM7.0).
 *    18.08.97 Minhua Zhou: added video_object_start_code
 * 18.06.97 M.Wollborn: Added correct trace mechanism
 * 09.07.97 A. Sandvand added storing of VO Id in VOL structure
 * 04.08.97 Minhua Zhou: removed f_codes in the VOL  
 * 05.08.97 Minuua Zhou: added sadct_disable
 * 06.08.97 Noel Brady: added mods for BINARY_SHAPE_ONLY mode
 * 07.08.97 Minhua Zhou: changed quant. matrix decoding
 * 08.09.97 Cecile Dufour: added 
 * 23.03.98 Michael Wollborn: moved "random_accessible_vol" due to N2171, 
 *                            Clause 2.1.7
 *
 ***********************************************************CommentEnd********/

Void DecodeVolHeader(Bitstream *stream, Trace *trace, Vol *curr_vol, 
		     Int *readen_bits, Int vo_id, Int file_vol_id,
		     Char vol_user_data_filename[]) /* N2171 */
{
  Int tmpvar,i,*qmat,j, res;
  Vop	*sprite=NULL;
  TrajPoint *tmp_ref_point_coord=NULL;
  
  /*****
   *
   *    Set trace level for VO header
   *
   *****/
  if(trace->full_trace_period < 0)
    trace->trace = 1;
  else
    trace->trace = trace->VO_header_def;

  TraceBreakLine(trace);

  /*****
   *
   *	Read the VOL header enries from the bitstream
   *
   *****/

  /* vol_start_code (VOL_START_CODE_LENGTH bits) */

#ifdef _WD_MODE_
  tmpvar = (Int) BitstreamReadBits(stream,28,
				   "vo_start_code",trace,CODE);
  tmpvar = (Int) BitstreamReadBits(stream,4,
				   "vo_id",trace,CODE);
#else
  tmpvar = (Int) BitstreamReadBits(stream,27,
				   "vo_start_code",trace,CODE);
  tmpvar = (Int) BitstreamReadBits(stream,5,
				   "vo_id",trace,CODE);
#endif
  
  *readen_bits +=32;
  PutVolVOId(tmpvar,curr_vol);
  
  /*****
   *
   *    Set trace level for VOL header
   *
   *****/
  if(trace->full_trace_period < 0)
    trace->trace = 1;
  else
    trace->trace = trace->VOL_header_def;

  TraceBreakLine(trace);
  
  tmpvar = (Int) BitstreamReadBits(stream,VOL_START_CODE_LENGTH,
				   "vol_start_code",trace,CODE);
  *readen_bits += VOL_START_CODE_LENGTH;
  
  if(tmpvar != VOL_START_CODE)
    {
      printf ("Bitstream does not start with VOL_START_CODE\n");
      exit (1);
    }
  
  /* vol_id (4 bits) */
  tmpvar = (Int) BitstreamReadBits(stream,4,"vol_id",trace,CODE);
  *readen_bits += 4;
  PutVolId(tmpvar,curr_vol);
  
  /* for TPS */
  bs_vol[vo_id][tmpvar] = file_vol_id;
  
  /* Included due to N2171, Clause 2.1.7 MW 23-MAR-1998 */
  tmpvar = (Int) BitstreamReadBits(stream,1,"random_accessible_vol",
				   trace,FLAG);
  *readen_bits += 1;
  PutVolRandomAccessibleVol(tmpvar,curr_vol);
  
  tmpvar = (Int) BitstreamReadBits(stream,1,"is_object_layer_identifier",trace,CODE);
  *readen_bits +=1;
  PutVolIsObjectLayerIdentifier(tmpvar,curr_vol);
  if (GetVolIsObjectLayerIdentifier(curr_vol)) 
    {
      tmpvar = (Int) BitstreamReadBits(stream,4,"visual_object_layer_verid",
				       trace,CODE);
      PutVolVisualObjectLayerVerid(tmpvar,curr_vol);
      *readen_bits +=4;
      tmpvar = (Int) BitstreamReadBits(stream,3,"visual_object_layer_priority"
				       ,trace,CODE);
      PutVolVisualObjectLayerPriority(tmpvar,curr_vol);
      *readen_bits +=3;
    } 
  
  tmpvar = (Int) BitstreamReadBits(stream,1,"vol_control_parameters",
				   trace,CODE);
  PutVolVolControlParameters(tmpvar,curr_vol);
  *readen_bits +=1;
  
  /* vol_shape (2 bits) */
  tmpvar = (Int) BitstreamReadBits(stream,2,"vol_shape",trace,CODE);
  *readen_bits += 2;
  
#ifdef _WD_MODE_               
  if (tmpvar == 2) tmpvar++;   
#endif                                     
  
  PutVolShape(tmpvar,curr_vol);
  
  tmpvar = (Int) BitstreamReadBits(stream,15,"time_increment_resolution",
				   trace,NUM);
  PutVolTimeIncrementResolution(tmpvar,curr_vol);
  *readen_bits +=15;
  
  tmpvar = (Int) BitstreamReadBits(stream,1,"fixed_vop_rate",trace,CODE);
  PutVolFixedVopRate(tmpvar,curr_vol);
  *readen_bits +=1;
  
  if (GetVolShape(curr_vol) != BINARY_SHAPE_ONLY)  /* BSO_NOEL */ 
    {
      if(GetVolShape(curr_vol) == 0)
	{
	  BitstreamReadBits(stream,1,"marker_bit",trace,FLAG);
	  *readen_bits += 1;
	  
	  /* vol_width (13 bits) */
	  tmpvar = (Int) BitstreamReadBits(stream,13,"vol_width",trace,NUM);
	  *readen_bits += 13;
	  PutVolWidth(tmpvar,curr_vol);
	  
	  BitstreamReadBits(stream,1,"marker_bit",trace,FLAG);
	  *readen_bits += 1;
	  
	  /* vol_height (13 bits) */
	  tmpvar = (Int) BitstreamReadBits(stream,13,"vol_height",trace,NUM);
	  *readen_bits += 13;
	  PutVolHeight(tmpvar,curr_vol);
	}
      
      tmpvar = (Int) BitstreamReadBits(stream,1,"OBMC_disable",trace,NUM);
      *readen_bits += 1;
      PutVolOBMCDisable(tmpvar,curr_vol); 
      
#ifndef _WD_MODE_ 
      /* vol_shape_effects */
      tmpvar = (Int) BitstreamReadBits(stream,4,"shape_effects",trace,NUM);
      *readen_bits += 4;
      if(tmpvar != NO_SHAPE_EFFECTS)
	{
	  printf("ERROR SHAPE EFFECTS not supported\n");
	  exit(0);
	}
#endif
      
#ifdef _WD_MODE_
      /* vol_sprite_usage (1 bits) */
      tmpvar = (Int) BitstreamReadBits(stream,1,"vol_sprite_usage",trace,CODE);
      *readen_bits += 1;
#else
      /* vol_sprite_usage (2 bits) */
      tmpvar = (Int) BitstreamReadBits(stream,2,"vol_sprite_usage",trace,CODE);
      *readen_bits += 2;
#endif

      PutVolSpriteUsage(tmpvar,curr_vol);
      
      if (GetVolSpriteUsage(curr_vol) != SPRITE_NOT_USED)
	{
	  if( GetVolSpriteUsage(curr_vol) == STATIC_SPRITE||
	      GetVolSpriteUsage(curr_vol) == ONLINE_SPRITE)
	    {
	      /* sprite_hdim (13 bits) */
	      tmpvar = (Int) BitstreamReadBits(stream,13,"vol_sprite_hdim",
					       trace,NUM);
	      *readen_bits += 13;
	      PutVolSpriteHdim(tmpvar,curr_vol);
	      
	      BitstreamReadBits(stream,1,"marker_bit",trace,FLAG);
	      *readen_bits += 1;
	      
	      /* sprite_vdim (13 bits) */
	      tmpvar = (Int) BitstreamReadBits(stream,13,"vol_sprite_vdim",
					       trace,NUM);
	      *readen_bits += 13;
	      PutVolSpriteVdim(tmpvar,curr_vol);
	      
	      BitstreamReadBits(stream,1,"marker_bit",trace,FLAG);
	      *readen_bits += 1;
	      
	      /* sprite_left_edge (13 bits) */
	      tmpvar = (Int) BitstreamReadBits(stream,13,
					       "vol_sprite_left_edge",
					       trace,NUM);
	      *readen_bits += 13;
	      if (tmpvar>4095) tmpvar -= 8192; 
	      PutVolSpriteLeftEdge(tmpvar,curr_vol);
	      
	      BitstreamReadBits(stream,1,"marker_bit",trace,FLAG);
	      *readen_bits += 1;
	      
	      /* sprite_top_edge (13 bits) */
	      tmpvar = (Int) BitstreamReadBits(stream,13,"vol_sprite_top_edge",
					       trace,NUM);
	      *readen_bits += 13;
	      if (tmpvar>4095) tmpvar -= 8192; 
	      PutVolSpriteTopEdge(tmpvar,curr_vol);
	      
	      BitstreamReadBits(stream,1,"marker_bit",trace,FLAG);
	      *readen_bits += 1;
	    }
	  else	/* GMC SPRITE */
	    {
	      PutVolSpriteHdim(16,curr_vol);
	      PutVolSpriteVdim(16,curr_vol);
	      PutVolSpriteLeftEdge(0,curr_vol);
	      PutVolSpriteTopEdge(0,curr_vol);
	    }
	  
	  /* no_of_sprite_points (6 bits) */
	  tmpvar = (Int) BitstreamReadBits(stream,6,"vol_no_of_sprite_points",
					   trace,NUM);
	  *readen_bits += 6;
	  PutVolNoOfSpritePoints(tmpvar,curr_vol);
	  
	  if (GetVolNoOfSpritePoints(curr_vol))
	    {
	      tmp_ref_point_coord = (TrajPoint *) emalloc(GetVolNoOfSpritePoints(curr_vol)*sizeof(TrajPoint)); 
	      PutVolRefPointCoord(tmp_ref_point_coord,curr_vol);
	    }
      
	  /* warping accuracy (2 bit) */
	  tmpvar = (Int) BitstreamReadBits(stream,2,
					   "warping_accuracy_in_sprite",
					   trace,NUM);
	  *readen_bits += 2;
	  PutVolWarpingAccuracy(tmpvar,curr_vol);
	  
	  /* brightness_change_in_sprite (1 bit) */
	  tmpvar = (Int) BitstreamReadBits(stream,1,
					   "vol_brightness_change_in_sprite",
					   trace,FLAG);
	  *readen_bits += 1;
	  PutVolBrightnessChangeInSprite(tmpvar,curr_vol);
	  
	  /* Basic or low latency sprite (1 bit) */
	  tmpvar = (Int) BitstreamReadBits(stream,1,
					   "vol_low_latency_sprite_enable",
					   trace,FLAG);
	  *readen_bits += 1;
	  PutVolLowLatencySpriteEnable(tmpvar,curr_vol);
	  
	  res = GetVolSpriteHdim(curr_vol)%16;
	  if (res>0) PutVolSpriteHdim(GetVolSpriteHdim(curr_vol)+
				      16-res,curr_vol);    
	  res = GetVolSpriteVdim(curr_vol)%16;
	  if (res>0) PutVolSpriteVdim(GetVolSpriteVdim(curr_vol)+
				      16-res,curr_vol); 
	  
	  sprite = AllocVop(GetVolSpriteHdim(curr_vol),
			    GetVolSpriteVdim(curr_vol));
	  PutVolSprite(sprite,curr_vol);
	  PutVopSpriteUsage(GetVolSpriteUsage(curr_vol), sprite);
	  PutVopShape(GetVolShape(curr_vol),sprite);
	  SetConstantImage(GetVopY(sprite),128); 
	  SetConstantImage(GetVopU(sprite),0); 
	  SetConstantImage(GetVopV(sprite),0); 
	  SetConstantImage(GetVopA(sprite),0);    
	  PutVolSpriteTransmitMode(PIECE, curr_vol);
	  if (GetVolLowLatencySpriteEnable(curr_vol))
	  	InitForDecodeLowLatencyStaticSprite(curr_vol);
	  
	} /* Sprite_usage != SPRITE_NOT_USED */
      
#ifndef _WD_MODE_ 
      /* sadct disable */
      if (GetVolShape(curr_vol)!=0) 
	{
	  tmpvar = (Int) BitstreamReadBits(stream,1,"vol_sadct_disable",
					   trace,FLAG);
	  *readen_bits +=1;
	  PutVolSADCTDisable(tmpvar,curr_vol);
	} 
      else  
	PutVolSADCTDisable(1,curr_vol);
#else
      PutVolSADCTDisable(1,curr_vol);
#endif
      
      /* not_8_bit */
      tmpvar = (Int) BitstreamReadBits(stream,1,"not_8_bit",trace,FLAG);
      *readen_bits += 1;
      if (tmpvar == 1) 
	{
	  tmpvar = (Int) BitstreamReadBits(stream,4,"quant_precision",
					   trace,CODE);
	  *readen_bits += 4;
	  PutVolQuantPrecision(tmpvar,curr_vol);
	  tmpvar = (Int) BitstreamReadBits(stream,4,"bits_per_pixel",
					   trace,CODE);
	  *readen_bits += 4;
	  PutVolBitsPerPixel(tmpvar,curr_vol);
	}
      else 
	{
	  PutVolQuantPrecision(5,curr_vol);
	  PutVolBitsPerPixel(8,curr_vol);
	}
      
      /* vol_quant_type (1 bit) */
      tmpvar = (Int) BitstreamReadBits(stream,1,"vol_quant_type",trace,FLAG);
      *readen_bits += 1;
      PutVolQuantType(tmpvar,curr_vol);
      
      /* Added MPEG quantization stuff completely, 23-APR-1997 MW */
      if(GetVolQuantType(curr_vol))
	{
	  /* load_intra_quant_mat (1 bit) */
	  tmpvar = (Int) BitstreamReadBits(stream,1,"load_intra_quant_mat",
					   trace,FLAG);
	  *readen_bits += 1;
	  PutVolLoadIntraQuantMat(tmpvar,curr_vol);
	  
	  qmat = GetVolIntraQuantMat(curr_vol);
	  
	  if(GetVolLoadIntraQuantMat(curr_vol))
	    {
	      /* intra_quant_mat (8*64 bits) */
	      i=0;
	      do {
		tmpvar = BitstreamReadBits(stream,8,"intra_quant_mat",
					   trace,NUM);
		qmat[*(zigzag_i+i)] = tmpvar;
		*readen_bits +=8;
	      } while ((qmat[*(zigzag_i+i)]!=0)&&(++i<64));
	     
	      for (j=i;j<64;j++)
	        qmat[*(zigzag_i+j)]=qmat[*(zigzag_i+i-1)];
	    }
	  else
	    {
	      for(i=0; i<64; i++)
	        qmat[i] = mpeg_iqmat_def[i];
	    }
	  
	  /* load_nonintra_quant_mat (1 bit) */
	  tmpvar = (Int) BitstreamReadBits(stream,1,"load_nonintra_quant_mat",
					   trace,FLAG);
	  *readen_bits += 1;
	  
	  PutVolLoadNonintraQuantMat(tmpvar,curr_vol);
	  
	  qmat = GetVolNonintraQuantMat(curr_vol);
	  
	  if(GetVolLoadNonintraQuantMat(curr_vol))
	    {
	      /* nonintra_quant_mat (8*64 bits) */
	      i=0;
	      do {
		tmpvar = BitstreamReadBits(stream,8,"nonintra_quant_mat",trace,NUM);
		qmat[*(zigzag_i+i)] = tmpvar;
		*readen_bits +=8;
	      } while ((qmat[*(zigzag_i+i)]!=0)&&(++i<64));
	      
	      for (j=i;j<64;j++)
	        qmat[*(zigzag_i+j)]=qmat[*(zigzag_i+i-1)];
	    }
	  else
	    {
	      for(i=0; i<64; i++)
	        qmat[i] = mpeg_nqmat_def[i];
	    }
	  
#ifndef _WD_MODE_
	  if(GetVolShape(curr_vol) == 2) /* GRAYLEVEL SHAPE */
	    {
	      /* disable_gray_quant_update (1 bit) */
	      tmpvar = (Int) BitstreamReadBits(stream,1,
					       "disable_gray_quant_update",
					       trace,FLAG);
	      *readen_bits += 1;
	      PutVolDisableGrayQuantUpdate(tmpvar,curr_vol);
	      
	      /* load_gray_intra_quant_mat (1 bit) */
	      tmpvar = (Int) BitstreamReadBits(stream,1,
					       "load_gray_intra_quant_mat",
					       trace,FLAG);
	      *readen_bits += 1;
	      PutVolLoadGrayIntraQuantMat(tmpvar,curr_vol);
	      
	      qmat = GetVolGrayIntraQuantMat(curr_vol);
	      
	      if(GetVolLoadGrayIntraQuantMat(curr_vol))
		{
		  /* gray_intra_quant_mat (8*64 bits) */
		  i=0;
		  do {
		    tmpvar = BitstreamReadBits(stream,8,
					       "gray_intra_quant_mat",
					       trace,NUM);
		    qmat[*(zigzag_i+i)] = tmpvar;
		    *readen_bits +=8;
		  } while ((qmat[*(zigzag_i+i)]!=0)&&(++i<64));
		  
		  for (j=i;j<64;j++)
		    qmat[*(zigzag_i+j)]=qmat[*(zigzag_i+i-1)];
		}
	      
	      else
		{
		  for(i=0; i<64; i++)
		    qmat[i] = mpeg_giqmat_def[i];
		}
	      
	      /* load_gray_nonintra_quant_mat (1 bit) */
	      tmpvar = (Int) BitstreamReadBits(stream,1,
					       "load_gray_nonintra_quant_mat",
					       trace,FLAG);
	      *readen_bits += 1;
	      
	      PutVolLoadGrayNonintraQuantMat(tmpvar,curr_vol);
	      
	      qmat = GetVolGrayNonintraQuantMat(curr_vol);
	      
	      if(GetVolLoadGrayNonintraQuantMat(curr_vol))
		{
		  /* gray_nonintra_quant_mat (8*64 bits) */
		  i=0;
		  do {
		    tmpvar = BitstreamReadBits(stream,8,
					       "gray_nonintra_quant_mat",
					       trace,NUM);
		    qmat[*(zigzag_i+i)] = tmpvar;
		    *readen_bits +=8;
		  } while ((qmat[*(zigzag_i+i)]!=0)&&(++i<64));
		  
		  for (j=i;j<64;j++)
		    qmat[*(zigzag_i+j)]=qmat[*(zigzag_i+i-1)];
		}
	      else
		{
		  for(i=0; i<64; i++)
		    qmat[i] = mpeg_gnqmat_def[i];
		}
	    }
#endif
	}
      
      /* complexity_estimation_disable */
      tmpvar = (Int) BitstreamReadBits(stream,1,
				       "complexity_estimation_disable",
				       trace,FLAG);
      *readen_bits += 1;
      PutVolComplexityEstimationDisable(tmpvar,curr_vol);
      if (tmpvar!=1) 
	{
	  printf("complexity_estimation_enable is not supported yet\n");
	  exit(-1);
	}
      
      /* Modified due to N2171 Cl. 2.5.1/14 MW 27-MAR-1998 */
      /* error_resilient_disable (1 bit) */
      /* tmpvar = (Int) BitstreamReadBits(stream,1,"error_resilient_disable", */
      /* 				       trace,FLAG); */
      /* *readen_bits += 1; */
      /* PutVolErrorResDisable(tmpvar,curr_vol); */
      
      /* if (!tmpvar)  */
      /* 	{ */
      /* 	  printf("Decoding in Error Resilient Mode\n"); */
      
      tmpvar = (Int) BitstreamReadBits(stream,1,"data_partitioning_enable",
				       trace,FLAG);
      *readen_bits += 1;
      PutVolDataPartEnable(tmpvar,curr_vol);
      
      if (GetVolDataPartEnable(curr_vol))
	{
	  printf("Using Data Partitioning.\n");
	  tmpvar = (Int) BitstreamReadBits(stream,1,"reversible_vlc_enable",
					   trace,FLAG);
	  *readen_bits += 1;
	  PutVolReverseVlc(tmpvar,curr_vol);
	  
	  if (GetVolReverseVlc(curr_vol))
	    printf("Using Reversible VLC.\n");
	  
	  /* Enable error resilience only if data partitioning is used */
	  /* for the time being MW 28-MAR-1998                         */    
	  PutVolErrorResDisable(0,curr_vol);
	}	  
      else
	{
	  printf("Using the neither Data Partitioning nor RVLC.\n");
	  /* Disable error resilience if no data partitioning is used */
	  /* for the time being MW 28-MAR-1998                         */    
	  PutVolErrorResDisable(1,curr_vol);
	}

      /*     } */
      /*   else  */
      /* printf("Decoding in Non-Error Resilient Mode\n"); */
    
#ifndef _WD_MODE_ 
      /* intra_acdcpred_disable (1 bit) */
      tmpvar = (Int) BitstreamReadBits(stream,1,"dcac_prediction_disable",
				       trace,FLAG);

      PutVolACDCPredDisable(tmpvar,curr_vol);
      *readen_bits += 1;
#else
      PutVolACDCPredDisable(0,curr_vol);
#endif
  
      if (!GetVolACDCPredDisable(curr_vol)) 
        printf("ACDC Prediction ENABLED\n");
      else 
        printf("INTRA ACDC Prediction Turned OFF\n");

      /* scalability (1 bit) */
      tmpvar = (Int) BitstreamReadBits(stream,1,"scalability",
				       trace,FLAG);
      *readen_bits += 1;
      PutVolScalability(tmpvar,curr_vol);
      
      if(GetVolScalability(curr_vol))
	{
	  /* ref_layer_id (4 bits) */
	  tmpvar = (Int) BitstreamReadBits(stream,4,"ref_layer_id",
					   trace,CODE);
	  *readen_bits += 4;
	  PutVolRefId(tmpvar,curr_vol);
	  
	  /* ref_layer_sampling_direc (1 bits) */
	  tmpvar = (Int) BitstreamReadBits(stream,1,"ref_layer_sampling_direc",
					   trace,FLAG);
	  *readen_bits += 1;
	  PutVolRefSampDir(tmpvar,curr_vol);
	  
	  /* hor_sampling_factor_n (5 bits) */
	  tmpvar = (Int) BitstreamReadBits(stream,5,"hor_sampling_factor_n",
					   trace,NUM);
	  *readen_bits += 5;
	  PutVolHorSampN(tmpvar,curr_vol);
	  
	  /* hor_sampling_factor_m (5 bits) */
	  tmpvar = (Int) BitstreamReadBits(stream,5,"hor_sampling_factor_m",
					   trace,NUM);
	  *readen_bits += 5;
	  PutVolHorSampM(tmpvar,curr_vol);
	  
	  /* ver_sampling_factor_n (5 bits) */
	  tmpvar = (Int) BitstreamReadBits(stream,5,"ver_sampling_factor_n",
					   trace,NUM);
	  *readen_bits += 5;
	  PutVolVerSampN(tmpvar,curr_vol);
	  
	  /* ver_sampling_factor_m (5 bits) */
	  tmpvar = (Int) BitstreamReadBits(stream,5,"ver_sampling_factor_m",
					   trace,NUM);
	  *readen_bits += 5;
	  PutVolVerSampM(tmpvar,curr_vol);
	  
	  /* enhancement_type (1 bit) */
	  tmpvar = (Int) BitstreamReadBits(stream,1,"enhancement_type",
					   trace,FLAG);
	  *readen_bits += 1;
	  PutVolEnhanceType(tmpvar,curr_vol);
	}

      /* Removed due to N2171, Clause 2.1.7 MW 23-MAR-1998 */
      /* tmpvar = (Int) BitstreamReadBits(stream,1,"random_accessible_vol", */
      /* 				     trace,FLAG); */
      /* *readen_bits += 1; */
      /* PutVolRandomAccessibleVol(tmpvar,curr_vol); */

      BitstreamByteAlign(stream);
      
      /* Included due to N2171, Cl. 2.1.9 MW 25-MAR-1998 */
      tmpvar = (Int) BitstreamShowBits(stream,USER_DATA_START_CODE_LENGTH);
      if (tmpvar == USER_DATA_START_CODE) 
        *readen_bits += GetUserDataFromBitstream(stream,trace,
						 vol_user_data_filename);
      
      if( GetVolSpriteUsage(curr_vol) == STATIC_SPRITE )
  	{
	  PutVolHeaderToVop(curr_vol, sprite);
	  PutVopWidth(GetVolSpriteHdim(curr_vol),sprite);
	  PutVopHeight(GetVolSpriteVdim(curr_vol),sprite);			
	  if (GetVolLowLatencySpriteEnable(curr_vol)==0)
	  	{		
	  	DecodeBasicSprite(stream, curr_vol, vo_id, trace, readen_bits);
	  	PutVolSpriteTransmitMode(STOP, curr_vol);
	  	}
	}	/* CASE STATIC_SPRITE */
    } /* BSO_NOEL */
  else  
    { 
      /* Modified due to N2171 Cl. 2.5.1/14 MW 27-MAR-1998 */
      /* error_resilient_disable (1 bit) */
      /* tmpvar = (Int) BitstreamReadBits(stream,1,"error_resilient_disable", */
      /* 				  trace,FLAG); */
      /* *readen_bits += 1; */
      /* PutVolErrorResDisable(tmpvar,curr_vol); */  /* BSO_NOEL */
      BitstreamByteAlign(stream);

      /* Included due to N2171, Cl. 2.1.9 MW 25-MAR-1998 */
      tmpvar = (Int) BitstreamShowBits(stream,USER_DATA_START_CODE_LENGTH);
      if (tmpvar == USER_DATA_START_CODE) 
        *readen_bits += GetUserDataFromBitstream(stream,trace,
						 vol_user_data_filename);
    }
  
  return;
}



/***********************************************************CommentBegin******
 *
 * -- DecodeVolList -- Decode a list of video object layers for one VO 
 *
 * Author :		
 *      Michael Wollborn (TUH)
 *
 * Created :		
 *	08-AUG-1996
 *
 * Purpose :
 *	Decode a list of layers for a specific video object from given
 *	bitstreams. The bitstream for each layer is given in a separate file
 *
 * 
 * Arguments in : 	
 *	Int number_of_vols	number of layers for the video object
 *	Bitstream *stream[]	 Pointer list to the bitstreams
 *	Trace *trace[]		 Trace information for each layer
 *	Int next_display_time	next time a frame is displayed
 *  Int random_access_start_time
 *
 *
 * Arguments in/out :	
 *	Vol *vol_list	         concatenated list of layers for video object
 *	Int readen_bits[]	 Readen bits for each layer
 *	Int stop_decoding_vol[]  Flag to indicate end of all bitstreams
 *
 *
 * Arguments out :	
 *	
 *
 * Return values :	
 *	
 *
 * Side effects :	
 *	
 *
 * Description :	
 *	
 *
 * See also :
 *	
 *
 * Modified : 07.07.97: A. Sandvand: Added support for Random Access
 *	
 *
 ***********************************************************CommentEnd********/

Void DecodeVolList(Int number_of_vols, Bitstream *stream[], Trace *trace[], 
		   Float next_display_time, Int random_access_start_time,
		   Vol *vol_list, Int readen_bits[], 
		   Int stop_decoding_vol[], Int vo_id, Int post_filter_type,
		   Char gov_user_data_filename[][300])
{
  Vol *next_vol;
  Int k;

  /*****
   *
   *	Decode each layer for the current object until the time is
   *	come to display the next frame
   *
   *****/
  next_vol = vol_list;
  
  for(k=0; k<number_of_vols; k++)
    {
      if(stop_decoding_vol[k] == 0)
	DecodeVol(stream,trace[k],next_display_time,random_access_start_time,
		  next_vol,&readen_bits[k],
		  &stop_decoding_vol[k],vo_id,vol_list,post_filter_type,
		  gov_user_data_filename[k]);
      if(temporal_scalability)
	  WriteOutputImage_TPS_for_base(base_output_vop,
					next_display_time,
					post_filter_type,
					!GetVolScalability(next_vol),
					stop_decoding_vol,
					number_of_vols);
      next_vol = GetVolNext(next_vol);
    }
}





/***********************************************************CommentBegin******
 *
 * -- DecodeVol -- Decode a video object layer
 *
 * Author :		
 *      Michael Wollborn (TUH)
 *
 * Created :		
 *	08-AUG-1996
 *
 * Purpose :
 *	Decode a video object layer
 *
 * 
 * Arguments in : 	
 *	Bitstream *stream	Pointer to the bitstream
 *	Trace *trace		Trace information for VOL
 *	Int next_display_time	next time a frame is displayed
 *      Int random_access_start_time
 *
 *
 * Arguments in/out :	
 *	Vol *next_vol		video object layer to be decoded
 *	Int *readen_bits	Readen bits for VOL
 *	Int *stop_decoding_vol	Flag to indicate end of all bitstreams
 *
 *
 * Arguments out :	
 *	
 *
 * Return values :	
 *	
 *
 * Side effects :	
 *	
 *
 * Description :	
 *	
 *
 * See also :
 *	
 *
 * Modified : 
 *  	14.01.97 Luis Ducla-Soares: added byte alignment for VOP_START_CODE 
 *	                   (call to function BitstreamByteAlign() )
 *
 *	10.02.97 M.Wollborn: changed code in order to avoid problems with
 *		             different VO and display frame rates
 *	09.05.97 Minhua Zhou: added "DecodeGOV"
 *      07.07.97: A. Sandvand: Added support for Random Access
 *      24.07.97 Minhua Zhou:  Modified decoding control due to  B-VOPs 
 *      15.9.97 A. Sandvand: Updated Random Access implementation
 *      25.03.98 M.Wollborn: Modifications due to N2171 Cl. 2.1.9 user data
 ***********************************************************CommentEnd********/

Void DecodeVol(Bitstream **stream, Trace *trace, Float next_display_time_in, 
	       Int random_access_start_time,
	       Vol *curr_vol, Int *readen_bits, Int *stop_decoding_vol,
	       Int vo_id, Vol *vol_list, Int post_filter_type, 
	       Char gov_user_data_filename[])
{
  Int tmpvar,vop_display_time;
  Int prev_vop_display_time;
  Int next_display_time;
  Vop *curr_vop;
  Int vol_id, nvol_id;
  Int enh_decoding_flag = 0;
  
  nvol_id = GetVolId( curr_vol );
  vol_id  = bs_vol[vo_id][nvol_id];

  /*****
   *
   *	Decode all VOPs from the current VOL until the next frame
   *	has to be displayed
   *
   *****/
  curr_vop = GetVolVop(curr_vol);
  PutVolHeaderToVop(curr_vol,curr_vop);
  next_display_time=(Int)(0.001+next_display_time_in/1000.0
                     *(Double)GetVopTimeIncrementResolution(curr_vop));
  if(next_display_time_in == random_access_start_time)
    vop_display_time = prev_vop_display_time=-1;
  else 
    {
      vop_display_time = CalcVopDisplayTime(curr_vop);
      prev_vop_display_time=CalcVopDisplayTime(GetVopPrevTemp(curr_vop));
    }
          
  while (DecodeTimeControl(stream[vol_id],
			   vop_display_time,
			   prev_vop_display_time,
			   next_display_time,
			   *stop_decoding_vol,
			   curr_vop,
			   random_access_start_time,
			   next_display_time_in,
			   &enh_decoding_flag,
			   trace))
    {
      printf("display_time=%d,prev_time=%d,vop_time=%d\n",next_display_time,
	     prev_vop_display_time,vop_display_time);
      
      tmpvar = (Int) BitstreamShowBits(stream[ vol_id ],VOP_START_CODE_LENGTH);
      if (tmpvar == GROUP_START_CODE) 
	
	/* Modified due to N2171, Cl. 2.1.9 MW 25-MAR-1998 */
        DecodeGOV(stream[ vol_id ],trace,curr_vop,readen_bits,
		  gov_user_data_filename);
      
      else if(tmpvar == VOP_START_CODE)
	{
	  DecodeVop(stream,     vo_id,      trace,
		    curr_vop,   readen_bits,
		    vol_list,   next_display_time,
		    post_filter_type);
	  
	  if (GetVolSpriteUsage(curr_vol) == STATIC_SPRITE) 
	    PutVolSpriteTransmitMode(GetVopSpriteTransmitMode(curr_vop),
				     curr_vol);
	  
	  if(temporal_scalability && CheckBaseVop(curr_vop) && 
	     GetVopWidth( curr_vop ) != 0 )
	    BASEImageInput(curr_vop, base_output_vop); /* Input base's Image to buffer */
	  
	  vop_display_time      = CalcVopDisplayTime(curr_vop);
	  prev_vop_display_time = CalcVopDisplayTime(GetVopPrevTemp(curr_vop));
	  
	  if (GetVolSpriteUsage(curr_vol) == GMC_SPRITE) 
	    {
	      FreeVop(GetVolSprite(curr_vol));
	      PutVolSprite(CloneVop(curr_vop),curr_vol);
	      PutVolSpriteHdim(GetVopWidth(curr_vop),curr_vol);
	      PutVolSpriteVdim(GetVopHeight(curr_vop),curr_vol);
	    }
	  
	}   
      else
	*stop_decoding_vol = 1;
    }
  
  return;
}





/***********************************************************CommentBegin******
 *
 * -- StopDecoding -- Checks if all bitstreams are decoded
 *
 * Author :		
 *      Michael Wollborn (TUH)
 *
 * Created :		
 *	08-AUG-1996
 *
 * Purpose :
 *	Check if all bitstreams of all VOLs are fully decoded
 *
 * 
 * Arguments in : 
 *	Int number_of_vos		Number of video objects
 *	Int number_of_vols[]		List with number of VOLs per VO	
 *	Int stop_decoding_vol[][] 	List with end info for all bitstreams
 *
 *
 * Arguments in/out :	
 *
 *
 * Arguments out :	
 *	
 *
 * Return values :	
 *	Int stop_decoding	flag which indicates if the decoding should
 *				stop (1) or not (0)
 *	
 *
 * Side effects :	
 *	
 *
 * Description :	
 *	
 *
 * See also :
 *	
 *
 * Modified : 
 *	
 *
 ***********************************************************CommentEnd********/

Int StopDecoding(Int number_of_vos, Int number_of_vols[], 
		 Int stop_decoding_vol[][MAX_NUM_VOLS])
{
  Int i,k;

  /*****
   *
   *	Check all entries in the field for stopped bitstreams
   *
   *****/
  for(i=0; i<number_of_vos; i++)
    for(k=0; k<number_of_vols[i]; k++)
      if(stop_decoding_vol[i][k] == 0)
	return(0);
  
  return(1);
}





/***********************************************************CommentBegin******
 *
 * -- DecodeGOV -- Decodes the Group of VOPs from bitstream
 *
 * Author :		
 *	Minhua Zhou (HHI)
 *
 * Created :		
 *	05-05-1997
 *
 * Purpose :		

 * 
 *
 * Arguments in : 	
 *	Bitstream *stream,	pointer on the decoder bitstream structure,
 *				should be at the right position.
 *	Trace *trace		pointer to trace information
 *
 *
 * Arguments in/out :	
 *	Vop *curr_vop,		pointer on considered vop - the previous VOP
 *				can be accessed by the structure of the current
 *				VOP (GetVopNextTemp())
 *	Int *readen_bits	pointer to value of up to now readen_bits
 *
 *
 * Arguments out :	
 *	
 *
 * Return values :	
 *	
 *
 * Side effects :	

 *
 * Description :	
 *	
 *
 * See also :
 *	
 *
 * Modified : 07.07.97 A. Sandvand: Added printing of GOV contents
 *            24.07.97 Minhua Zhou: modified the time base
 *	      25.03.98 M.Wollborn: Included reception of user data due to N2171
 *
 ***********************************************************CommentEnd********/


Void DecodeGOV(Bitstream *stream, Trace *trace, Vop *curr_vop, 
	       Int *readen_bits,
	       Char gov_user_data_filename[]) 
{
  Int tmpvar,time_s;
  Int time, closed_gov, broken_link;
  fprintf(stdout,"VO_%i, VOL_%i: Receiving GOV: {",
	  GetVopVOId(curr_vop),GetVopId(curr_vop));
  
  /* group_start_code (32 bits) */
  tmpvar = (Int) BitstreamReadBits(stream,32,
				   "group_start_code",trace,CODE);
  
  if(tmpvar != GROUP_START_CODE)
    {
      printf ("\nBitstream does not start with GROUP_START_CODE\n");
      exit (1);
    }
  tmpvar = (Int) BitstreamReadBits(stream,5,
				   "Hour",trace,NUM);
  time_s= tmpvar*3600;
  fprintf(stdout,"%i:",tmpvar);
  
  tmpvar = (Int) BitstreamReadBits(stream,6,
				   "Minute",trace,NUM);
  time_s += tmpvar*60;
  fprintf(stdout,"%i:",tmpvar);
  tmpvar = (Int) BitstreamReadBits(stream,1,
				   "Marker_bit",trace,NUM);
  
  tmpvar = (Int) BitstreamReadBits(stream,6,
				   "Second",trace,NUM);
  time_s += tmpvar;
  fprintf(stdout,"%i}",tmpvar);
  tmpvar = (Int) BitstreamReadBits(stream,1,
				   "closed_gov",trace,NUM);
  closed_gov= tmpvar;
  
  if (tmpvar == 1)
    fprintf(stdout,", closed_gov");
  tmpvar = (Int) BitstreamReadBits(stream,1,
				   "broken_link",trace,NUM);
  broken_link = tmpvar;   
  
  if (tmpvar == 1)
    fprintf(stdout,", broken_link");
  *readen_bits += 52;
  fprintf(stdout,"\n");
  
  /* added by SONY 980212 */ 
  if ((closed_gov == 0)&&(broken_link == 1))
    {
      fprintf(stderr,"closed_gov = 0\nbroken_link = 1\n");
      exit(0);
    }
  /* 980212 */
  
  BitstreamByteAlign(stream);
  
  /* Included due to N2171, Cl. 2.1.9 MW 25-MAR-1998 */
  tmpvar = (Int) BitstreamShowBits(stream,USER_DATA_START_CODE_LENGTH);
  if (tmpvar == USER_DATA_START_CODE) 
    *readen_bits += GetUserDataFromBitstream(stream,trace,
					     gov_user_data_filename);
  
  if (GetVopPrevTemp(curr_vop)!=NULL) 
    {
      time=CalcVopDisplayTime(GetVopPrevTemp(curr_vop));
      PutVopModTimeBase(time_s, GetVopPrevTemp(curr_vop));
      time-=time_s*GetVopTimeIncrementResolution(curr_vop);
      PutVopTimeInc(time,GetVopPrevTemp(curr_vop));
    } 
  
  if (GetVopNextTemp(curr_vop)!=NULL) 
    {
      time=CalcVopDisplayTime(GetVopNextTemp(curr_vop));
      PutVopModTimeBase(time_s, GetVopNextTemp(curr_vop));
      time-=time_s*GetVopTimeIncrementResolution(curr_vop);
      PutVopTimeInc(time,GetVopNextTemp(curr_vop));
    }
  
} 





/***********************************************************CommentBegin******
 *
 * -- DecodeVopHeader -- Decodes the VOPheader information from the bitstream
 *
 * Author :		
 *	Cecile Dufour (Philips LEP/ ACTS MoMuSys)
 *
 * Created :		
 *	14-Nov-1997
 *
 * Purpose :		
 *	 Decode the vop headerinformation from the bitstream.
 * 
 *
 * Arguments in : 	
 *	Bitstream *stream,	pointer on the decoder bitstream structure,
 *				should be at the right position.
 *	Trace *trace		pointer to trace information
 *
 *
 * Arguments in/out :	
 *	Vop *curr_vop,		pointer on considered vop - the previous VOP
 *				can be accessed by the structure of the current
 *				VOP (GetVopNextTemp())
 *	Int *readen_bits	pointer to value of up to now readen_bits
 *
 *
 * Arguments out :	
 *	
 *
 * Return values :	
 *	
 *
 * Side effects :	
 *
 *
 * Description :	
 *	
 *
 * See also :
 *	
 *
 * Modified : 
 *	This routine has been created by the splitting of the previous routine 
 *	DecodeVop: this previous routine contained both the reading of the header
 *	for each vop, and the call for further decoding.
 *	DecodeVopHeader has be created becasue it is called in the routine
 *	DecodeBasicSprite used in the STATIC SPRITE case
 *
 *      28.03.98 M.Wollborn: Modifications due to N2171 Cl. 2.5.14
 *
 ***********************************************************CommentEnd********/
   


/* CLEANING UNTIL HERE ON 29-MAR-1998 MW */



Int DecodeVopHeader(Bitstream *stream, Int vo_id, Trace *trace, Vop *curr_vop, 
	       Int *readen_bits)
{
  Vop *tmp_vop;
  Int tmpvar;
  Int i,bits;
  Int time_base0;
  Int time_base=0; 
  TrajPoint	*traj=NULL, *difftraj=NULL;
  Float	brightness_factor;
  Int res;
  TrajPoint	*tmp_refpoint=NULL;
  
#ifdef _DEBUG_SPSC_
  static Int count;
  Char name[81];
#endif
  
  Int prev_prediction_mode = -1;
  static Int prev_time_base=0;
  
  /*****
   *
   *    Disable tracing for time preview 
   *
   *****/
  trace->trace = 0;
  
  /*****
   *
   *    Set trace level for VOP header
   *
   *****/
  if(trace->full_trace_period < 0)
    trace->trace = 1;
  else
    trace->trace = trace->VOP_header_def;

  TraceBreakLine(trace);

  /*****
   *
   *	Free the forelast VOP and copy the current (which is now the previous
   *	VOP) into the right place of the structure
   *
   *****/
  

  /*****
   *
   *	Read the VOP header from the bitstream
   *
   *****/
  /* vop_start_code (VOP_START_CODE_LENGTH bits) */
  tmpvar = (Int) BitstreamReadBits(stream,VOP_START_CODE_LENGTH,
				   "vop_start_code",trace,CODE);

  *readen_bits += VOP_START_CODE_LENGTH;

  if(tmpvar != VOP_START_CODE)
    {
    printf ("Bitstream does not start with VOP_START_CODE\n");
    exit (1);
    }

  prev_prediction_mode = GetVopPredictionType(curr_vop);
 
  /* vop_prediction_type (2 bits) */
  tmpvar = (Int) BitstreamReadBits(stream,2,"vop_prediction_type",trace,CODE);
  *readen_bits += 2;
  PutVopPredictionType(tmpvar,curr_vop);

  /* modulo_time_base (? bits) */
  tmpvar = (Int) BitstreamReadBits(stream,1,"modulo_time_base",trace,FLAG);
  *readen_bits += 1;
  
  while(tmpvar == 1)
    {
      tmpvar = (Int) BitstreamReadBits(stream,1,"modulo_time_base",trace,FLAG);
      *readen_bits += 1;
      time_base++;
    }
  
  /* marker_bit (1 bit) */
  tmpvar = (Int) BitstreamReadBits(stream,1,"marker_bit",trace,FLAG);
  *readen_bits += 1;

  /* vop_time_increment (1-15 bits) */
  bits = ceil(log((double)GetVopTimeIncrementResolution(curr_vop))/log(2.0));
  if (bits<1) 
    bits=1;
  
  tmpvar = (Int) BitstreamReadBits(stream,bits,"vop_time_increment",trace,NUM); 
  *readen_bits += bits;
  PutVopTimeInc(tmpvar, curr_vop );
  
  if (GetVopSpriteUsage(curr_vop)!= STATIC_SPRITE||
      GetVopPredictionType(curr_vop)==SPRITE_VOP)
    if (GetVopPredictionType(curr_vop)==B_VOP) 
      {
	if (temporal_scalability && GetVopScalability( curr_vop ))
	  time_base0=prev_time_base;
/* SONY 070498 for Spatial Scalability */
	else if (GetVopScalability( curr_vop ))
/* SONY 070498 */
	  time_base0=prev_time_base;
	else
	  time_base0=GetVopModTimeBase(GetVopPrevTemp(curr_vop));
	
	if (time_base0<0) 
	  time_base0=0;  
       
	PutVopModTimeBase(time_base0+time_base,curr_vop);
      }
    else 
      {
        if(temporal_scalability && GetVopScalability( curr_vop ) &&
	   prev_prediction_mode == B_VOP)
	  time_base0 = 0;
/* SONY 070498 for Spatial Scalability */
	else if(GetVopScalability(curr_vop)) 
/* SONY 070498 */
	  time_base0 = prev_time_base;
	else
	  time_base0=GetVopModTimeBase(GetVopNextTemp(curr_vop));
        
	if (time_base0<0) 
	  time_base0=0;  
        
	PutVopModTimeBase(time_base0+time_base,curr_vop);
	
/* SONY 070498 for Spatial Scalability */
	if (GetVopScalability( curr_vop ))
/* SONY 070498 */
	  prev_time_base=GetVopModTimeBase(curr_vop);
      }
  
  if(temporal_scalability) LastTimeInput(curr_vop);
  
  /* BSO_NOEL */
  
  /* marker_bit (1 bit) */
  tmpvar = (Int) BitstreamReadBits(stream,1,"marker_bit",trace,FLAG);
  *readen_bits += 1;
  
  
  tmpvar = (Int) BitstreamReadBits(stream,1,"vop_coded",trace,NUM);
  if (tmpvar==0) 
    {
      PutVopWidth(0,curr_vop);
      PutVopHeight(0,curr_vop);
      PutVopCoded(0,curr_vop);
      BitstreamByteAlign(stream);
      printf("Empty Vop decoded\n");
      
      if(temporal_scalability)
	SetBGCImage(curr_vop);
      
      if (GetVopSpriteUsage(curr_vop)!= STATIC_SPRITE||
	  GetVopPredictionType(curr_vop)==SPRITE_VOP)
        if (GetVopPredictionType(curr_vop)!=B_VOP) 
	  {
	    if (GetVopPrevTemp(curr_vop)!=NULL)
	    FreeVop(GetVopPrevTemp(curr_vop));
	    PutVopPrevTemp(GetVopNextTemp(curr_vop),curr_vop);
	    PutVopNextTemp(NULL,curr_vop);

	    if (GetVopWidth(GetVopPrevTemp(curr_vop))!=0) 
	      {
		tmp_vop = CloneVop(GetVopPrevTemp(curr_vop)); 
		
		PutVopNextTemp(tmp_vop,curr_vop);
		PutVopModTimeBase(GetVopModTimeBase(curr_vop),GetVopNextTemp(curr_vop));
		PutVopTimeInc(GetVopTimeInc(curr_vop),GetVopNextTemp(curr_vop));
		PutVopCoded(GetVopCoded(curr_vop),GetVopNextTemp(curr_vop));
		
	      } 
	    else 
	      {
		tmp_vop = SallocVop(); 
		CopyVopNonImageField(curr_vop,tmp_vop);
		PutVopNextTemp(tmp_vop,curr_vop);
	      }
	  }
      
      return(0);
    } 

  PutVopCoded(1,curr_vop);

  /* set default value for shape_coding_type */
  if (GetVopPredictionType(curr_vop) == I_VOP) 		
    PutVopShapeCodingType(0,curr_vop);
  else 
    PutVopShapeCodingType(1,curr_vop);

  if (GetVopShape(curr_vop) != BINARY_SHAPE_ONLY) /* BSO_NOEL */
    {
  
      /* BEGINNING OF ROUNDING TYPE */
      /* get vop_rounding_type */
      if ( GetVopPredictionType(curr_vop)==P_VOP ||
	   ( GetVopSpriteUsage(curr_vop) != STATIC_SPRITE &&
	     GetVopPredictionType(curr_vop)==SPRITE_VOP))
	{
	  tmpvar = (Int) BitstreamReadBits(stream,1,
					   "vop_rounding_type",trace,NUM);
	  *readen_bits += 1;
	  PutVopRoundingType(tmpvar,curr_vop);
	}
      else
        PutVopRoundingType(0,curr_vop);
      /* END OF  ROUNDING TYPE */
      
    } /* BSO_NOEL */
  
  if(GetVopShape(curr_vop) != 0)
    {
  if (!(GetVopSpriteUsage(curr_vop)==STATIC_SPRITE&&GetVopPredictionType(curr_vop)==I_VOP))
    {
      /* vop_width (13 bits) */
      tmpvar = (Int) BitstreamReadBits(stream,13,"vop_width",trace,NUM);
      *readen_bits += 13;
      PutVopWidth(tmpvar,curr_vop);
    
      if (tmpvar==0) {
	if(temporal_scalability)
	  SetBGCImage(curr_vop);
	return(0);
      }

      /* marker_bit (1 bit) */
      tmpvar = (Int) BitstreamReadBits(stream,1,"marker_bit",trace,FLAG);
      *readen_bits += 1;
    
      /* vop_height (13 bits) */
      tmpvar = (Int) BitstreamReadBits(stream,13,"vop_height",trace,NUM);
      *readen_bits += 13;
      PutVopHeight(tmpvar,curr_vop);

#ifdef _WD_MODE_
      /* marker_bit (1 bit) */
      tmpvar = (Int) BitstreamReadBits(stream,1,"marker_bit",trace,FLAG);
      *readen_bits += 1;
#endif
    
      /* vop_horizontal_mc_spatial_ref (13 bits) */
      tmpvar = (Int) BitstreamReadBits(stream,13,"vop_horizontal_mc_spatial_ref",
				       trace,NUM);
      *readen_bits += 13;

      /* Revised by C. Dufour 12/12/97 for low-latency*/
      if (GetVopSpriteUsage(curr_vop)== STATIC_SPRITE &&
	  GetVopPredictionType(curr_vop)==I_VOP)
	{
          if (tmpvar>4095) tmpvar -= 8192;
          tmpvar -= GetVopSpriteLeftEdge(curr_vop);
	}
      /* End Revision */

      PutVopHorSpatRef(tmpvar,curr_vop);
      
      /* marker_bit (1 bit) */
      tmpvar = (Int) BitstreamReadBits(stream,1,"marker_bit",trace,FLAG);
      *readen_bits += 1;

      /* vop_vertical_mc_spatial_ref (13 bits) */
      tmpvar = (Int) BitstreamReadBits(stream,13,"vop_vertical_mc_spatial_ref",
				       trace,NUM);
      *readen_bits += 13;
      
      /* Revised by C. Dufour 12/12/97 for low-latency*/
      if (GetVopSpriteUsage(curr_vop)== STATIC_SPRITE &&
	  GetVopPredictionType(curr_vop)==I_VOP)
	{
          if (tmpvar>4095) tmpvar -= 8192;
          tmpvar -= GetVopSpriteTopEdge(curr_vop);
	}
      /* End Revision */

      PutVopVerSpatRef(tmpvar,curr_vop);
      }
      else
      {
      PutVopWidth(GetVopSpriteHdim(curr_vop),curr_vop);
      PutVopHeight(GetVopSpriteVdim(curr_vop),curr_vop);
      PutVopHorSpatRef(0,curr_vop);
      PutVopVerSpatRef(0,curr_vop);
      }/* of STATIC_SPRITE and first I_VOP */
      
      if(GetVopScalability(curr_vop)==1 && GetVopEnhanceType(curr_vop)==1)
	{
	  /* background_composition (1 bit) */
	  tmpvar = (Int) BitstreamReadBits(stream,1,"background_composition",
					   trace,FLAG);
	  *readen_bits += 1;
	  PutVopBackComp(tmpvar,curr_vop);
	}
      else 
        PutVopBackComp(0,curr_vop);

#ifndef _WD_MODE_
      /* VOP_CR */
      tmpvar = (Int) BitstreamReadBits(stream,1,"VOP_CR",trace,NUM);
      *readen_bits += 1;
#endif

      /* change_CR_disable */
      tmpvar = (Int) BitstreamReadBits(stream,1,"change_CR_disable",trace,FLAG);
      PutVopChangeCRDisable(tmpvar,curr_vop);
      *readen_bits += 1;

      /* constant_alpha */
      tmpvar = (Int) BitstreamReadBits(stream,1,"vop_constant_alpha",trace,FLAG);
      PutVopConstantAlpha(tmpvar,curr_vop);
      *readen_bits += 1;
      if (GetVopConstantAlpha(curr_vop)) 
	{
	  tmpvar = (Int) BitstreamReadBits(stream,8,"vop_constant_alpha_value",trace,NUM);
	  PutVopConstantAlphaValue(tmpvar,curr_vop);
	  *readen_bits += 8;
	}
    }
  
  if (GetVopShape(curr_vop) != BINARY_SHAPE_ONLY)  /* BSO_NOEL */
    { 
      tmpvar = (Int) BitstreamReadBits(stream,3,"intra_dc_vlc_thr",trace,CODE);
      *readen_bits += 3;
      PutVopIntraDCVlcThr(tmpvar,curr_vop);

      tmpvar = (Int) BitstreamReadBits(stream,1,"interlaced",trace,CODE);
      *readen_bits += 1;
      PutVopInterlaced(tmpvar,curr_vop);
      
      if (GetVopInterlaced(curr_vop)) 
	{
	  tmpvar = (Int) BitstreamReadBits(stream,1,"top_field_first",trace,CODE);
	  *readen_bits += 1;
	  PutVopTopFieldFirst(tmpvar,curr_vop);

	  tmpvar = (Int) BitstreamReadBits(stream,1,"alternate_scan",trace,CODE);
	  *readen_bits += 1;
	  PutVopAlternateScan(tmpvar,curr_vop);
	}
    }

  if ( (GetVopSpriteUsage(curr_vop) != SPRITE_NOT_USED)&&
       (GetVopPredictionType(curr_vop)==SPRITE_VOP) )
    {
      if(GetVopNoOfSpritePoints(curr_vop) > 0) 
	{
	  /* decode the differentially encoded trajectories */
	  difftraj = DecodeSpriteTraj(stream,trace, GetVopNoOfSpritePoints(curr_vop),
				      GetVopSpriteUsage(curr_vop)); 
	  traj = AddTraj( GetVopNoOfSpritePoints(curr_vop), difftraj);
	  PutVopTrajPointCoord(traj,curr_vop);
	  PutVopTrajPointCoord(traj,GetVopSprite(curr_vop));
	  
	  tmp_refpoint = GetVopRefPointCoord(curr_vop);
	  for (i=0 ; i<GetVopNoOfSpritePoints(curr_vop); i++)
	    {
	      tmp_refpoint[i].x = 
		GetVopHorSpatRef(curr_vop)+(i%2)*GetVopWidth(curr_vop);
	      tmp_refpoint[i].y = 
		GetVopVerSpatRef(curr_vop)+(i>>1)*GetVopHeight(curr_vop);
	    }
	  free(difftraj);
	}
      
      if(GetVopBrightnessChangeInSprite(curr_vop)) 
        brightness_factor = decode_brightness_change_factor(stream, trace, readen_bits);
      else
        brightness_factor = 1;

      PutVopBrightnessChangeFactor(brightness_factor, curr_vop);
      if(GetVopSpriteUsage(curr_vop) == STATIC_SPRITE)
	{
	  printf("Start SPRITE VOP (STATIC OFF-LINE CASE) decoding\n");
	  if (GetVopSpriteTransmitMode(curr_vop)!=STOP)
	    do
	      {
		/* sprite transmit mode (2 bits) */
		tmpvar = (Int) BitstreamReadBits(stream,2,"sprite_transmit_mode",trace,CODE);
		*readen_bits += 2;
		PutVopSpriteTransmitMode(tmpvar, curr_vop);
		
		if (GetVopSpriteTransmitMode(curr_vop)==PIECE ||
		    GetVopSpriteTransmitMode(curr_vop)==UPDATE)
		DecodeSpritePiece(stream, curr_vop, vo_id, trace, readen_bits);
	      } while (GetVopSpriteTransmitMode(curr_vop)!=STOP &&
		       GetVopSpriteTransmitMode(curr_vop)!=PAUSE);
				    
	  FreeVopChannels(curr_vop);
	  
	  res = GetVopWidth(curr_vop)%16;
	  if (res>0) 
	    PutVopWidth(GetVopWidth(curr_vop)+16-res,curr_vop);    

	  res = GetVopHeight(curr_vop)%16;
	  if (res>0) 
	    PutVopHeight(GetVopHeight(curr_vop)+16-res,curr_vop);    
 
	  AllocVopChannels(curr_vop,
			   GetVopWidth(curr_vop), GetVopHeight(curr_vop));
	  Compute_SpriteVop(curr_vop);

	  if(GetVopNoOfSpritePoints(curr_vop) > 0)
	    free(traj);
		
	  if (GetVopPrevTemp(curr_vop)!=NULL) 
	    FreeVop(GetVopPrevTemp(curr_vop));
		
	  PutVopPrevTemp(GetVopNextTemp(curr_vop),curr_vop);
	  PutVopNextTemp(NULL,curr_vop);

	  tmp_vop =CloneVop(curr_vop);
	  if (GetVopPrevTemp(tmp_vop)!=NULL)
	    FreeVop(GetVopPrevTemp(tmp_vop));
		
	  PutVopPrevTemp(NULL,tmp_vop);  
	  PutVopNextTemp(tmp_vop,curr_vop);
	  
	  BitstreamByteAlign(stream); 
	  return(0);
	} /* END STATIC CASE */
		
      if(GetVopSpriteUsage(curr_vop) == ONLINE_SPRITE)
	{
	  /* blend_fact (8 bits) */
	  tmpvar = (Int) BitstreamReadBits(stream,8,"blend_fact",trace,NUM);
	  *readen_bits += 8;
	  PutVopBlendFact(tmpvar,curr_vop);
	}
    }  /* SPRITE_USAGE!=SPRITE_NOT_USED */

  if (GetVopShape(curr_vop) != BINARY_SHAPE_ONLY)  /* BSO_NOEL */
    { 
      /* vop_quant (5 bits) */
      tmpvar = (Int) BitstreamReadBits(stream,GetVopQuantPrecision(curr_vop),
				       "vop_quant",trace,NUM);
      *readen_bits += GetVopQuantPrecision(curr_vop);
      PutVopQuantizer(tmpvar,curr_vop);
  
      /* added by Minhua Zhou: 04.08.97 */
      if (GetVopPredictionType(curr_vop)!=I_VOP) 
	{
	  tmpvar = (Int) BitstreamReadBits(stream,3,"vop_fcode_for",trace,NUM); 
	  *readen_bits += 3;
	  PutVopFCodeFor(tmpvar,curr_vop);
	}

      if (GetVopPredictionType(curr_vop)==B_VOP) 
	{
	  tmpvar = (Int) BitstreamReadBits(stream,3,"vop_fcode_back",trace,NUM); 
	  *readen_bits += 3;
	  PutVopFCodeBack(tmpvar,curr_vop);
	}
	
      if (!GetVopScalability(curr_vop))
      /* Modified due to N2171 Cl. 2.5.14 MW 28-MAR-1998 */
      /*   if (!GetVopErrorResDisable(curr_vop)) */
        if (GetVopShape(curr_vop) && GetVopPredictionType(curr_vop)!=I_VOP)
	  {
	    tmpvar = (Int) BitstreamReadBits(stream,1,
					     "vop_shape_coding_type",trace,FLAG);
	    PutVopShapeCodingType(tmpvar,curr_vop);
	  }
    } /* BSO_NOEL */
  
  return(1);
}





	
/***********************************************************CommentBegin******
 *
 * -- DecodeVop -- Decodes the VOP information from the bitstream
 *
 * Author :		
 *	Michael Wollborn (TUH)
 *
 * Created :		
 *	12-AUG-1996
 *
 * Purpose :		
 *	 Decode the vop information from the bitstream.
 * 
 *
 * Arguments in : 	
 *	Bitstream *stream,	pointer on the decoder bitstream structure,
 *				should be at the right position.
 *	Trace *trace		pointer to trace information
 *
 *
 * Arguments in/out :	
 *	Vop *curr_vop,		pointer on considered vop - the previous VOP
 *				can be accessed by the structure of the current
 *				VOP (GetVopNextTemp())
 *	Int *readen_bits	pointer to value of up to now readen_bits
 *
 *
 * Arguments out :	
 *	
 *
 * Return values :	
 *	
 *
 * Side effects :	
 *	At the start of the module, the previous VOP is the current VOP.
 *	It is then copied to the next temporal one, which is the forelast
 *	VOP and which is freed. Then the VOP to be decoded is written into
 *	the current VOP.
 *
 *
 * Description :	
 *	
 *
 * See also :
 *	
 *
 * Modified : 28.10.96 Aasmund.Sandvand@fou.telenor.no: added support for
 *                     deblock filter
 * 	12.02.97 Aasmund Sanvand: Removed deblocking filter. Now done
 *			as post-processing.       
 *      15-APR-97 Jan De Lameillieure : added reading of the flag 'disable_sadct'
 *      07.07.97 Noel Brady: Added decoding of VOP_CR and change_CR_disable
 *      15-05-97 Minhua Zhou: added GOV and syntax changes
 *      18.06.97 M.Wollborn: Added correct trace mechanism
 *      24.07.97 Minhua Zhou: decoded non-B-VOPs are first padded,
 *                            then stored.
 *      04.08.97 Minhua Zhou: added f_code in the VOP layer
 *			      added intra_dc_vlc_thr
 *      05.08.97 Minhua Zhou added vop_coded, removed sadct_disable
 *			06.08.97 Noel Brady: added mods for BINARY_SHAPE_ONLY
 *      28.08.97 Osamu Sunohara: modified for spatial scalable coding
 *      09.10.97 Minhua Zhou: added Vop_coded to deal with empty VOPs
 ***********************************************************CommentEnd********/
   
Void DecodeVop(Bitstream **stream, Int vo_id, Trace *trace, Vop *curr_vop, 
	       Int *readen_bits, Vol *vol_list, Int next_display_time,
	       Int post_filter_type)
{
  Vop *tmp_vop;
  Int num_pixels;
  Int num_lines;
  Int MB_width;
  Int MB_height;
  TrajPoint	*traj=NULL;
  Int ok;

#ifdef _DEBUG_SPSC_
  static Int count;
  Char name[81];
#endif
 

  Int vol_id, nvol_id;

  /*****
   *
   *    Disable tracing for time preview 
   *
   *****/
  trace->trace = 0;

  nvol_id = GetVopId( curr_vop );
  vol_id = bs_vol[vo_id][nvol_id];
 
  /*****
   *
   *    Set trace level for VOP header
   *
   *****/
  if(trace->full_trace_period < 0)
    trace->trace = 1;
  else
    trace->trace = trace->VOP_header_def;

  TraceBreakLine(trace);

  /*****
   *
   *	Free the forelast VOP and copy the current (which is now the previous
   *	VOP) into the right place of the structure
   *
   *****/

  
ok = DecodeVopHeader(stream[vol_id], vo_id, trace, curr_vop, readen_bits);

if (ok==0) return;
  		
 
  num_pixels = GetVopWidth(curr_vop);
  num_lines = GetVopHeight(curr_vop);


  MB_width = num_pixels / 16;
  MB_height = num_lines /16;

  /*****
   *
   *	Set the trace levels to the required values (either full or
   *    user-defined, see README for details)
   *
   *****/
  if(trace->full_trace_period < 0)
    {
      SetTraceLevelsFull(trace);
    }
  else if(trace->full_trace_period > 0 &&
	  trace->counter>=trace->full_trace_start &&
	  trace->counter<=trace->full_trace_end)
    {
      if((trace->counter - trace->full_trace_start) % trace->full_trace_period)
        SetTraceLevelsDefault(trace);
      else
        SetTraceLevelsFull(trace);
    }
  else
    {
      SetTraceLevelsDefaultZero(trace);
    }
  trace->counter++;

  TraceBreakLine(trace);

#ifdef _DEBUG_SPSC_
  PrintVopInfo(curr_vop,"currA_vop");
  PrintVopInfo(GetVopNextTemp(curr_vop),"currA_vop->N");
  PrintVopInfo(GetVopPrevTemp(curr_vop),"currA_vop->P");
  sprintf(name,"A_vop%d",count);
  WriteVopDebug(curr_vop,name,name,name,0);
#endif

  /*****
   *
   *	Do scalable or non-scalable decoding of the current VOP
   *
   *****/
  
  if(GetVopScalability(curr_vop) == 0) 
    DecodeVopNonScalable(stream[ vol_id ],vo_id,trace,curr_vop);
  else 
    DecodeVopScalable(stream,vo_id,trace,curr_vop,vol_list,post_filter_type);

  if(temporal_scalability && CheckBaseVop(curr_vop))
    fprintf(stderr,"[B]frame[%d]\n",CalcFrameNumber(curr_vop));

  if ( (GetVopSpriteUsage(curr_vop) != SPRITE_NOT_USED)&&
  			(GetVopPredictionType(curr_vop)==SPRITE_VOP) )
	{
	if(GetVopNoOfSpritePoints(curr_vop) > 0)
		free(traj);
	}

#ifdef _DEBUG_SPSC_
  PrintVopInfo(curr_vop,"currB_vop");
  PrintVopInfo(GetVopNextTemp(curr_vop),"currB_vop->N");
  PrintVopInfo(GetVopPrevTemp(curr_vop),"currB_vop->P");
  sprintf(name,"B_vop%d",count);
  WriteVopDebug(curr_vop,name,name,name,0);
#endif

/* added by Minhua Zhou */

  if (GetVopPredictionType(curr_vop)!=B_VOP
/* added for SpSc by Sony 280897 */
    ||(GetVopPredictionType(curr_vop)==B_VOP&&
       GetVopScalability(curr_vop)&&
       GetVopRefSelCode(curr_vop)==0)
/* 280897 */
    ) { 
    if (GetVopPrevTemp(curr_vop)!=NULL) 
      FreeVop(GetVopPrevTemp(curr_vop));
    PutVopPrevTemp(GetVopNextTemp(curr_vop),curr_vop);
    PutVopNextTemp(NULL,curr_vop);

    tmp_vop =CloneVop(curr_vop);
    if (GetVopPrevTemp(tmp_vop)!=NULL)
      FreeVop(GetVopPrevTemp(tmp_vop));
    PutVopPrevTemp(NULL,tmp_vop);  

/* 1197-3 SONY */
    if(GetVopBvopTemp(tmp_vop)!=NULL)
      FreeVop(GetVopBvopTemp(tmp_vop));
    PutVopBvopTemp(NULL,tmp_vop);
/* 1197-3 */

    PutVopNextTemp(tmp_vop,curr_vop);
    VopPadding(GetVopNextTemp(curr_vop));
  }
  
/* 1197-3 SONY */  
  else if(!not_scalability&&!temporal_scalability) {
    
    if( GetVopBvopTemp(curr_vop) != NULL )
      FreeVop( GetVopBvopTemp(curr_vop) );
    PutVopBvopTemp(NULL,curr_vop);

    tmp_vop = CloneVop( curr_vop);
    if(GetVopPrevTemp(tmp_vop)!=NULL)
      FreeVop(GetVopPrevTemp(tmp_vop));
    PutVopPrevTemp(NULL,tmp_vop);
    if(GetVopNextTemp(tmp_vop)!=NULL)
      FreeVop(GetVopNextTemp(tmp_vop));
    PutVopNextTemp(NULL,tmp_vop);
    
    PutVopBvopTemp( tmp_vop, curr_vop);
    VopPadding( GetVopBvopTemp(curr_vop));
    
  }
/* 1197-3 */



 
  
#ifdef _DEBUG_SPSC_
  PrintVopInfo(curr_vop,"currC_vop");
  PrintVopInfo(GetVopNextTemp(curr_vop),"currC_vop->N");
  PrintVopInfo(GetVopPrevTemp(curr_vop),"currC_vop->P");
  sprintf(name,"C_vop%d",count);
  WriteVopDebug(curr_vop,name,name,name,0);

  count++;
#endif
  BitstreamByteAlign(stream[ vol_id ]); 
  return;
}





/***********************************************************CommentBegin******
 *
 * -- DecodeVopScalable -- Decodes the VOP information from the bitstream
 *			   in scalable mode
 *
 * Author :		
 *	Michael Wollborn (TUH)
 *
 * Created :		
 *	12-AUG-1996
 *
 * Purpose :		
 *	 Decode the vop information from the bitstream in scalable mode
 * 
 *
 * Arguments in : 	
 *	Bitstream *stream,	pointer on the decoder bitstream structure,
 *				should be at the right position.
 *	Trace *trace		pointer to trace information
 *
 *
 * Arguments in/out :	
 *	Vop *curr_vop,		pointer on considered vop - the previous VOP
 *				can be accessed by the structure of the current
 *				VOP (GetVopNextTemp())
 *
 * Arguments out :	
 *	
 *
 * Return values :	
 *	
 *
 * Side effects :	
 *
 *
 * Description :	
 *	
 *
 * See also :
 *	
 *
 * Modified :		
 *	
 *
 ***********************************************************CommentEnd********/


/***********************************************************CommentBegin******
 *
 * -- DecodeVopNonScalable -- Decodes the VOP information from the bitstream
 *			      in non-scalable mode
 *
 * Author :		
 *	Michael Wollborn (TUH)
 *
 * Created :		
 *	12-AUG-1996
 *
 * Purpose :		
 *	 Decode the vop information from the bitstream.
 * 
 *
 * Arguments in : 	
 *	Bitstream *stream,	pointer on the decoder bitstream structure,
 *				should be at the right position.
 *	Trace *trace		pointer to trace information
 *
 *
 * Arguments in/out :	
 *	Vop *curr_vop,		pointer on considered vop - the previous VOP
 *				can be accessed by the structure of the current
 *				VOP (GetVopNextTemp())
 *
 * Arguments out :	
 *	
 *
 * Return values :	
 *	
 *
 * Side effects :	
 *	At the start of the module, the previous VOP is the current VOP.
 *	It is then copied to the next temporal one, which is the forelast
 *	VOP and which is freed. Then the VOP to be decoded is written into
 *	the current VOP.
 *
 *
 * Description :	
 *	
 *
 * See also :
 *	
 *
 * Modified : 17-SEP-1996, M.Wollborn, introduced some changes for new
 *			   shape decoding		
 *	23.10.96 Robert Danielsen: Passing QP to lower functions for
 *			DCAC prediction
 *	27.12.96 Noel Brady: modifications to allow INTER shape decoding
 *			     in separate mode.
 *      22-Jan-97 Jan De Lameillieure : deallocate AB_first_MMR_values only 
 *		                        for separate mode ! 
 *	07-Feb-1997, M.Wollborn: changed in order to treat skipped MBs
 *			         correctly
 *      26.04.97 Luis Ducla Soares: Changes to allow error resilient
 *                                  decoding in the combined mode with
 *                                  data partitioning.
 *  14.10.97 Noel Brady: ChangeMBType2 is not called when the decoded VOP
 *													is a B-VOP
 *
 ***********************************************************CommentEnd********/

Void DecodeVopNonScalable(Bitstream *stream, Int vo_id, Trace *trace, Vop *curr_vop)
{
  Vop *tmp_vop;

  Image *MB_mot_decis,*B_mot_decis,*mot_x,*mot_y;

  Int MB_in_width,MB_in_height,B_in_width,B_in_height;
  Int *mb_type,*mvda;
  Int vol_id = GetVopId(curr_vop);

  Vop *sprite=NULL;
  
  if ( (GetVopSpriteUsage(curr_vop)!=SPRITE_NOT_USED)&&
       (GetVopPredictionType(curr_vop)==SPRITE_VOP) )
    sprite = GetVopSprite(curr_vop);

  /*****
   *
   *	Free image channels of VOP and allocate the image channels
   *	for the new sizes (only necessary if arbitrary shape)
   *
   *****/
  if (GetVopSpriteUsage(curr_vop)!=STATIC_SPRITE)
  if(GetVopShape(curr_vop))
    {
    FreeVopChannels(curr_vop);
    AllocVopChannels(curr_vop,GetVopWidth(curr_vop),GetVopHeight(curr_vop));
    }

  /*****
   *
   *	Set local parameters and allocate local memory
   *
   *****/
  tmp_vop = AllocVop(GetVopWidth(curr_vop),GetVopHeight(curr_vop));

  MB_in_width  = GetVopWidth(curr_vop)  / MB_SIZE;
  MB_in_height = GetVopHeight(curr_vop) / MB_SIZE;
  B_in_width   = 2 * MB_in_width;
  B_in_height  = 2 * MB_in_height;

  MB_mot_decis = AllocImage((UInt) MB_in_width,(UInt) MB_in_height,SHORT_TYPE);
  B_mot_decis = AllocImage ((UInt) B_in_width,(UInt) B_in_height,SHORT_TYPE);
  mot_x = AllocImage((UInt) B_in_width,(UInt) B_in_height,FLOAT_TYPE);
  mot_y = AllocImage((UInt) B_in_width,(UInt) B_in_height,FLOAT_TYPE);

  mb_type = (Int *)calloc((MB_in_width*MB_in_height), sizeof(Int));
  mvda = (Int *)calloc((MB_in_width*MB_in_height), sizeof(Int));

  SetConstantImage(MB_mot_decis,MBM_TRANSPARENT);

  /*****
   *
   *	Do combined or separate decoding
   *
   *****/

  if (GetVopShape(curr_vop)==0) 
    {
      SetConstantImage(GetVopA(curr_vop),255);
      SetConstantImage(GetVopAuv(curr_vop),255);
    }
  
  if (GetVopErrorResDisable(curr_vop))
      DecodeVopCombMotionShapeTexture(stream,vo_id,trace,curr_vop);
  else
      DecodeVopMotionShapeTextureErrRes(stream,vo_id,trace,curr_vop);
      
  /*****
   *
   *	Free local memory and return
   *
   *****/
  free((Int *)mvda);
  free((Int *)mb_type);
  
  FreeVop(tmp_vop);
  
  FreeImage(MB_mot_decis);
  FreeImage(B_mot_decis);
  FreeImage(mot_x);
  FreeImage(mot_y);
  
  return;
}






/***********************************************************CommentBegin******
 *
 * -- PutVolHeaderToVop -- Puts the relevant information of the VOL to the VOP
 *
 * Author :		
 *      Michael Wollborn (TUH)
 *
 * Created :		
 *	08-AUG-1996
 *
 * Purpose :
 *	Put the relevant information of the VOL to the VOP structure, since
 *	the low level decoding modules need these informations
 *
 * 
 * Arguments in : 	
 *	Vol *curr_vol	current VOL
 *
 *
 * Arguments in/out :	
 *	Vop *curr_vop	current VOP
 *
 *
 * Arguments out :	
 *	
 *
 * Return values :	
 *	
 *
 * Side effects :	
 *	
 *
 * Description :	
 *	
 *
 * See also :
 *	
 *
 * Modified :   23.12.96: F. Marques introducing the changes reported by
 * 		Noel Brady.
 *		23.04.97 Michael Wollborn: Changes for MPEG quant. stuff
 *              26.04.97 Luis Ducla-Soares: Changes for data partitioning mode.
 *              13.05.97 Minhua Zhou : added OBMCDisable	
 *              10.07.97 A. Sandvand: added VOId copying
 *              12.08.97 Minhua Zhou: added time_increment_resolution
 *              04.11.97 Minhua Zhou: added flags accroding to CD
 *
 ***********************************************************CommentEnd********/

Void PutVolHeaderToVop(Vol *vol, Vop *vop)
{
  Int i,*qmat_vol,*qmat_vop;
  
  /*****
   *
   *	Copy all relevant info
   *
   *****/
  PutVopVOId(GetVolVOId(vol),vop);
  PutVopId(GetVolId(vol),vop);
  PutVopShape(i=GetVolShape(vol),vop);
 
PutVopIsObjectLayerIdentifier(GetVolIsObjectLayerIdentifier(vol),vop);
PutVopVisualObjectLayerVerid(GetVolVisualObjectLayerVerid(vol),vop); 
PutVopVisualObjectLayerPriority(GetVolVisualObjectLayerPriority(vol),vop);
PutVopVolControlParameters(GetVolVolControlParameters(vol),vop); 
PutVopFixedVopRate(GetVolFixedVopRate(vol),vop); 
PutVopQuantPrecision(GetVolQuantPrecision(vol),vop);
PutVopBitsPerPixel(GetVolBitsPerPixel(vol),vop);
PutVopComplexityEstimationDisable(GetVolComplexityEstimationDisable(vol),vop);
PutVopRandomAccessibleVol(GetVolRandomAccessibleVol(vol),vop);


  if (i==2) PutVopBinaryShape(!BINARY_SHAPE,vop);
  else PutVopBinaryShape(BINARY_SHAPE,vop);

  
  if(GetVolShape(vol) == 0)
    {
    PutVopWidth(GetVolWidth(vol),vop);
    PutVopHeight(GetVolHeight(vol),vop);
    }

  PutVopSADCTDisable(GetVolSADCTDisable(vol),vop);
  PutVopQuantType(GetVolQuantType(vol),vop);
  PutVopOBMCDisable(GetVolOBMCDisable(vol),vop);
  PutVopQuantPrecision(GetVolQuantPrecision(vol),vop);
  PutVopBitsPerPixel(GetVolBitsPerPixel(vol),vop);

  if(GetVolQuantType(vol))
    {
      PutVopLoadIntraQuantMat(GetVolLoadIntraQuantMat(vol),vop);
      
      qmat_vol = GetVolIntraQuantMat(vol);
      qmat_vop = GetVopIntraQuantMat(vop);

      for(i=0; i<64; i++)
        qmat_vop[i] = qmat_vol[i];

      PutVopLoadNonintraQuantMat(GetVolLoadNonintraQuantMat(vol),vop);
      
      qmat_vol = GetVolNonintraQuantMat(vol);
      qmat_vop = GetVopNonintraQuantMat(vop);

      for(i=0; i<64; i++)
        qmat_vop[i] = qmat_vol[i];

      if(GetVolShape(vol) == 2) /* Gray level shape */
	{
	  PutVopDisableGrayQuantUpdate(GetVolDisableGrayQuantUpdate(vol),vop);

	  PutVopLoadGrayIntraQuantMat(GetVolLoadGrayIntraQuantMat(vol),vop);
      
	  qmat_vol = GetVolGrayIntraQuantMat(vol);
	  qmat_vop = GetVopGrayIntraQuantMat(vop);
	  
	  for(i=0; i<64; i++)
	    qmat_vop[i] = qmat_vol[i];

	  PutVopLoadGrayNonintraQuantMat(GetVolLoadGrayNonintraQuantMat(vol),
					 vop);
	  
	  qmat_vol = GetVolGrayNonintraQuantMat(vol);
	  qmat_vop = GetVopGrayNonintraQuantMat(vop);
	  
	  for(i=0; i<64; i++)
	    qmat_vop[i] = qmat_vol[i];
	}
    }

  PutVopErrorResDisable(GetVolErrorResDisable(vol),vop);
  PutVopDataPartEnable(GetVolDataPartEnable(vol),vop);
  PutVopReverseVlc(GetVolReverseVlc(vol),vop);
  PutVopIntraACDCPredDisable(GetVolACDCPredDisable(vol),vop);
  PutVopScalability(GetVolScalability(vol),vop);
  PutVopTimeIncrementResolution(GetVolTimeIncrementResolution(vol),vop);


  if(GetVolScalability(vol))
    {
    PutVopRefId(GetVolRefId(vol),vop);
    PutVopRefSampDir(GetVolRefSampDir(vol),vop);
    PutVopHorSampN(GetVolHorSampN(vol),vop);
    PutVopHorSampM(GetVolHorSampM(vol),vop);
    PutVopVerSampN(GetVolVerSampN(vol),vop);
    PutVopVerSampM(GetVolVerSampM(vol),vop);
    PutVopEnhanceType(GetVolEnhanceType(vol),vop);
    }

    PutVopSpriteUsage(GetVolSpriteUsage(vol),vop);
    if (GetVolSpriteUsage(vol) != SPRITE_NOT_USED) 
	{
	PutVopSpriteHdim(GetVolSpriteHdim(vol),vop);
	PutVopSpriteVdim(GetVolSpriteVdim(vol),vop);
	PutVopSpriteLeftEdge(GetVolSpriteLeftEdge(vol),vop);
	PutVopSpriteTopEdge(GetVolSpriteTopEdge(vol),vop);
	PutVopNoOfSpritePoints(GetVolNoOfSpritePoints(vol),vop);
	PutVopSprite(GetVolSprite(vol),vop);
	if(GetVolNoOfSpritePoints(vol) > 0) {
	  PutVopRefPointCoord(GetVolRefPointCoord(vol),vop);
	  PutVopRefPointCoord(GetVolRefPointCoord(vol),GetVopSprite(vop));
	}
	if(GetVolShape(vol) == 0)
	  {
	    PutVopHorSpatRef(0,vop);
	    PutVopVerSpatRef(0,vop);
	  }	
	PutVopBrightnessChangeInSprite(GetVolBrightnessChangeInSprite(vol),vop);
	PutVopLowLatencySpriteEnable(GetVolLowLatencySpriteEnable(vol),vop);
	PutVopWarpingAccuracy(GetVolWarpingAccuracy(vol),vop);
	PutVopSpriteTransmitMode(GetVolSpriteTransmitMode(vol),vop);
	PutVopSpriteTabTransmit(GetVolSpriteTabTransmit(vol),vop);
	PutVopSpriteTabAmbType(GetVolSpriteTabAmbType(vol),vop);
	PutVopSpriteTabMvda(GetVolSpriteTabMvda(vol),vop);
	PutVopSpriteTabQPStore(GetVolSpriteTabQPStore(vol),vop);
	PutVopSpriteTabDCStore(GetVolSpriteTabDCStore(vol),vop);
	}
  return;
}





/***********************************************************CommentBegin******
 *
 * -- WriteOutputImage -- writes all VOLs to an output image
 *
 * Author :		
 *      Michael Wollborn (TUH)
 *
  * Created :		
 *	15-AUG-1996
 *
 * Purpose :
 *	Writes the respective VOP for each active VOL to an output image.
 *	Therefore in each VOP of each VOL two VOPs can be accessed which
 *	are successive in time. Either the most recent VOP has exactly the
 *	same display time as the current local time, then this VOP is
 *	displayed. Otherwise, if one VOP has a later display time and the
 *	other an earlier display time, the earlier VOP is displayed. If the
 *	display time of both VOPs is earlier than the current local time, the
 *	respective VOP is not displayed at all, since then it is assumed that
 *	the VO has disappeared from the scene.
 *
 * 
 * Arguments in : 	
 *	Vol *vol_list[]  	  List of VOLs to be displayed
 *	Int local_time		  Local time base, i.e. time of actual display
 *  Int random_access_start_time_in
 *	Int image_counter	  Counter for the output image
 *	Char output_filename[][]  Name of the output file for the composed
 *				  image sequence
 *      Int post_filter_type  status of deblock filtering
 *	Int stop_decoding_vol[][] 	List with end info for all bitstreams
 *
 *
 * Arguments in/out :	
 *
 *
 * Arguments out :	
 *	
 *
 * Return values :	
 *	
 *
 * Side effects :	
 *	
 *
 * Description :	
 *	
 *
 * See also :
 *	
 *
 * Modified : 
 *	21.01.97 Robert Danielsen: Changed 127 to 128 for initialization
 *			of display_vop. Fix by Noel/Paulo.
 *      31.01.97 Aasmund Sandvand: Added deblock filtering
 *	12.02.97 M.Wollborn: Changed to avoid double writing of last VOP
 *      07.07.97 A. Sandvand: Modified to support Random Access
 *      24.07.97 Minhua Zhou: Modified to support B-VOPs
 *		 06.08.97 Noel Brady:  For VOPs, having only shape information, a default
 *											constant YUV colur is used i.e. 255,0,0
 *      09.10.97 Minhua Zhou: added Vop_coded to deal with empty VOPs
 *
 ***********************************************************CommentEnd********/

Void WriteOutputImage(Int number_of_vos,
		      Vol *vol_list[], Float local_time_in, 
		      Int random_access_start_time_in,Vop *display_vop, Int image_counter, 
		      Char output_filename[][300], Int post_filter_type,
		      Int stop_decoding_vol[][MAX_NUM_VOLS])
{
  Vop *local_vop, *filter_vop;
  Int vop_time,i;
  Int time_dis1,time_dis2,time_dis3,time_min;
  Int local_time =0, random_access_start_time =0 ;

  /*****
   *
   *	Set the display VOP to grey (A=0, Y=0, U=V=128)
   *
   *****/
  SetConstantImage(GetVopA(display_vop),0);
  SetConstantImage(GetVopY(display_vop),0);
  SetConstantImage(GetVopU(display_vop),128);
  SetConstantImage(GetVopV(display_vop),128);
  
  /*****
   *
   *	The general policy for composing the VOs is the following:
   *
   *	Nor spatial neither temporal scalability is supported yet.
   *	The VOs are composed in an order derived by their appearance
   *	in the configuration file. The first VO appearing their has the
   *	highest priority, i.e. it is displaye in front of all other VOs
   *	and so forth. With respect to the local time base, the currently
   *	decoded VOP of a VOL is only displayed if its time pointer is lower
   *	or equal to the local time; otherwise the previously decoded VOP
   *	is displayed at this time instance.
   *
   *****/
  for(i=0; i<number_of_vos; i++)
    {
      /*****
       *
       *	  Display only VOs whose coding has not stopped yet
       *	  (implemented only for the base layer at the moment)
       *	  (M.Wollborn, 12.02.1997)
       *
       *****/
      
      if(stop_decoding_vol[i][0] <2)
	{
	  /*****
	   *
	   *    Get he current VOP of the current VOL (only base VOL is processed
	   *    in the current implementation) and check the time stamp
	   *
	   *****/

	    if (stop_decoding_vol[i][0]==1) stop_decoding_vol[i][0]=2;
	    local_vop = GetVolVop(vol_list[i]);
	    local_time = (Int)(0.001+local_time_in/1000.0*
			       (Double)GetVopTimeIncrementResolution(local_vop));
	    random_access_start_time = (Int)(0.001+random_access_start_time_in/1000.0*
                        (Double)GetVopTimeIncrementResolution(local_vop));
        vop_time = CalcVopDisplayTime(local_vop);
	    time_dis1=abs(vop_time-local_time);
	    vop_time = CalcVopDisplayTime(GetVopNextTemp(local_vop));
	    time_dis2=abs(vop_time-local_time);
	    if (GetVopScalability(local_vop)==0) {
	      vop_time = CalcVopDisplayTime(GetVopPrevTemp(local_vop));
	      time_dis3=abs(vop_time-local_time);
	    } else time_dis3=time_dis1+1;
	    time_min=time_dis1;
	    if (time_min>time_dis3) time_min=time_dis3;
	    if (time_min>time_dis2) time_min=time_dis2;
	    if (time_min==time_dis2) 
	      local_vop =GetVopNextTemp(local_vop);
	    else if (time_min==time_dis3) 
	      local_vop =GetVopPrevTemp(local_vop);
	    
	    
	    
	    
	    
	    /*****
	     *
	     *    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(local_vop) == 0) 
	       SetConstantImage(GetVopA(local_vop),255);*/ 
	    
	    if (GetVopShape(local_vop) == BINARY_SHAPE_ONLY) /* BSO_NOEL */
	      {
		SetConstantImage(GetVopY(local_vop),255);
		SetConstantImage(GetVopU(local_vop),0);
		SetConstantImage(GetVopV(local_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(local_vop)!=0 && GetVopCoded(local_vop)==0)
	      /* Modified by Michael Wollborn */
	      continue;
	    else
	      {
		if(post_filter_type==0)
		  BlendVops(local_vop, display_vop);
		else
		  {
                    if (GetImageSizeX(GetVopQP(local_vop)) == GetVopWidth(local_vop)/16 ||
		        GetVopPredictionType(local_vop) == B_VOP)
		         filter_vop = CloneVop(local_vop);
		    else
		         filter_vop = CloneVop_TMP(local_vop); 
		    PostFilter(filter_vop,post_filter_type);
		    BlendVops(filter_vop, display_vop);
		    FreeVop(filter_vop);
		  }
		
	      }
	}
    }
  
  /*****
   *
   *    Write composited display_vop to disk
   *
   *****/

  if(local_time == random_access_start_time)
    WriteVopGeneric(display_vop,output_filename[0],output_filename[1],
		    output_filename[2],output_filename[3],image_counter,
		    IO_FORMAT,IO_OVERWRITE,FALSE);
  else
    WriteVopGeneric(display_vop,output_filename[0],output_filename[1],
		    output_filename[2],output_filename[3],image_counter,
		    IO_FORMAT,IO_APPEND,FALSE);

  return;
}





/***********************************************************CommentBegin******
 *
 * -- DecodeVopCombMotionShapeTexture -- decode VOP in combined mode
 *
 * Author :		
 *      Michael Wollborn (TUH)
 *
 * Created :		
 *	16-AUG-1996
 *
 * Purpose :
 *	Decodes the VOP in the combined motion/shape/texture mode
 *
 * 
 * Arguments in : 
 *	Bitstream *stream	bitstream to decode
 *	Trace *trace		trace information
 *
 *
 * Arguments in/out :	
 *	Vop *curr_vop		curent VOP to be decoded	
 *
 * Arguments out :	
 *	
 *
 * Return values :	
 *	
 *
 * Side effects :	
 *	
 *
 * Description :	
 *	
 *
 * See also :
 *	
 *
 * Modified : 
 *     JDL introduced DecodeVopCombinedShapeTextureIntra (18-Jan-97)
 *     JDL added DecodeVopCombinedMotionShapeTextureInter (19-Jan-97)
 *     24.07.97 Minhua Zhou: added mot_x_p,mot_y_P to support B-VOPs
 *                           added B-VOP decoding
 *	
 *
 ***********************************************************CommentEnd********/

Void DecodeVopCombMotionShapeTexture(Bitstream *stream, Int vo_id,
			Trace *trace, Vop *curr_vop)
{

 ImageF	*mot_x,
    *mot_y;
 Image *MB_decisions;
  
  static ImageF *mot_x_P[MAX_NUM_VOS][MAX_NUM_VOLS], 
    *mot_y_P[MAX_NUM_VOS][MAX_NUM_VOLS];
  static Image *MB_decisions_P[MAX_NUM_VOS][MAX_NUM_VOLS];
  Int vol_id,nvol_id;
  nvol_id = GetVopId( curr_vop );
  vol_id = bs_vol[vo_id][nvol_id];

  

  if(GetVopPredictionType(curr_vop) == INTRA_VOP)
       DecodeVopCombinedShapeTextureIntra(stream, vo_id, trace, curr_vop);
			     
#ifndef _WD_MODE_			     
	if (GetVopSpriteUsage(curr_vop) == ONLINE_SPRITE)
		{
		InitOnLineSprite(GetVopSprite(curr_vop),curr_vop);
		InitOnLineSpriteChroma(GetVopSprite(curr_vop),curr_vop);

		WriteVopGeneric(GetVopSprite(curr_vop),
				"sprite_dec.yuv",
				"sprite_dec.yuv",
				"sprite_dec.yuv",
				"sprite_dec.y",
				0,IO_FORMAT,IO_OVERWRITE,1); 
		}
#endif

	
  else if (GetVopPredictionType(curr_vop) != B_VOP)
  	{
	DecodeVopCombinedMotionShapeTextureInter(stream, vo_id, trace, curr_vop,&mot_x,&mot_y,&MB_decisions);

#ifndef _WD_MODE_			     
	if (GetVopSpriteUsage(curr_vop) == ONLINE_SPRITE)
		{
		UpdateOnLineSprite(GetVopSprite(curr_vop),curr_vop);

		WriteVopGeneric(GetVopSprite(curr_vop),
				"sprite_dec.yuv",
				"sprite_dec.yuv",
				"sprite_dec.yuv",
				"sprite_dec.y",
				0,IO_FORMAT,IO_APPEND,1); 
		}
#endif

	}
   else {
     Int nref_vol_id, ref_vol_id;
     ImageF *base_mot_x_P, *base_mot_y_P, *base_MB_decisions_P;

     if (GetVopScalability(curr_vop)==1) {
       nref_vol_id=GetVopRefId(curr_vop);
       ref_vol_id=bs_vol[vo_id][nref_vol_id];
       base_mot_x_P=AllocSameImage(mot_x_P[vo_id][ref_vol_id]);
       base_mot_y_P=AllocSameImage(mot_y_P[vo_id][ref_vol_id]);
       base_MB_decisions_P=AllocSameImage(MB_decisions_P[vo_id][ref_vol_id]);
       CopyImage(mot_x_P[vo_id][ref_vol_id],base_mot_x_P);
       CopyImage(mot_y_P[vo_id][ref_vol_id],base_mot_y_P);
       CopyImage(MB_decisions_P[vo_id][ref_vol_id],base_MB_decisions_P);
       B_DecodeVopCombinedMotionShapeTextureInter(stream,vo_id,trace,curr_vop,
         base_mot_x_P,base_mot_y_P,base_MB_decisions_P);
       FreeImage(base_mot_x_P);
       FreeImage(base_mot_y_P);
       FreeImage(base_MB_decisions_P);
     }
     else 
      B_DecodeVopCombinedMotionShapeTextureInter(stream,vo_id,trace,curr_vop,
      mot_x_P[vo_id][vol_id],mot_y_P[vo_id][vol_id],MB_decisions_P[vo_id][vol_id]);
     
   }

 /* Deallocate memory for motion vectors and MB modes */
	    if (GetVopPredictionType(curr_vop)!=B_VOP) {
	      if (mot_x_P[vo_id][vol_id]!=NULL) FreeImage(mot_x_P[vo_id][vol_id]);
	      if (mot_y_P[vo_id][vol_id]!=NULL) FreeImage(mot_y_P[vo_id][vol_id]);
              if (MB_decisions_P[vo_id][vol_id]!=NULL) FreeImage(MB_decisions_P[vo_id][vol_id]);     
              if (GetVopPredictionType(curr_vop)==I_VOP) {
                mot_x_P[vo_id][vol_id]=AllocImage(GetVopWidth (curr_vop)/8,GetVopHeight (curr_vop)/8,FLOAT_TYPE);
                mot_y_P[vo_id][vol_id]=AllocImage(GetVopWidth (curr_vop)/8,GetVopHeight (curr_vop)/8,FLOAT_TYPE);
                SetConstantImage (mot_x_P[vo_id][vol_id],+0.0);
                SetConstantImage (mot_y_P[vo_id][vol_id],+0.0);
                MB_decisions_P[vo_id][vol_id]=AllocImage(GetVopWidth (curr_vop)/16,GetVopHeight (curr_vop)/16,SHORT_TYPE);
                SetConstantImage (MB_decisions_P[vo_id][vol_id],0); /* MBM_INTRA */
                } else {
	           mot_x_P[vo_id][vol_id] = mot_x;
	           mot_y_P[vo_id][vol_id] = mot_y;
                   MB_decisions_P[vo_id][vol_id]=MB_decisions;
                  }
	    } 


  return;
}


/***********************************************************CommentBegin******
 *
 * -- DecodeVopMotionShapeTextureErrRes -- decode VOP in combined error
 *                                             resilient mode with data partitioning.
 *
 * Author :		
 *      Luis Ducla-Soares (IST) - lds@lx.it.pt
 *
 * Created :		
 *	28.04.97
 *
 * Purpose :
 *	Decodes the VOP in the error resilient combined motion/shape/texture
 *      mode with data partitioning.
 *
 * 
 * Arguments in : 
 *	Bitstream *stream	bitstream to decode
 *	Trace *trace		trace information
 *
 *
 * Arguments in/out :	
 *	Vop *curr_vop		curent VOP to be decoded	
 *
 * Arguments out :	
 *	
 *
 * Return values :	
 *	
 *
 * Side effects :	
 *	
 *
 * Description :based on DecodeVopCombMotionShapeTexture().
 *	
 *
 * See also :
 *	
 *
 * Modified : 
 *	09.12.97 Luis Ducla-Soares: changed the name of the function from
 *                                  DecodeVopCombMotionShapeTextureErrRes to
 *                                  DecodeVopMotionShapeTextureErrRes.
 *      09.12.97 Luis Ducla-Soares: modifications to allow B-VOPs.
 *
 ***********************************************************CommentEnd********/

Void DecodeVopMotionShapeTextureErrRes(Bitstream *stream, Int vo_id,
				       Trace *trace, Vop *curr_vop)
{

  ImageF	*mot_x, *mot_y;
  Image *MB_decisions;
  
  static ImageF *mot_x_P[MAX_NUM_VOS][MAX_NUM_VOLS], 
    *mot_y_P[MAX_NUM_VOS][MAX_NUM_VOLS];
  static Image *MB_decisions_P[MAX_NUM_VOS][MAX_NUM_VOLS];
  Int vol_id,nvol_id;
  nvol_id = GetVopId( curr_vop );
  vol_id = bs_vol[vo_id][nvol_id];
  
  if(GetVopPredictionType(curr_vop) == INTRA_VOP)
    {
      if (GetVopDataPartEnable(curr_vop) 
	  && (GetVopShape(curr_vop) != BINARY_SHAPE_ONLY) )
	{
	  /* this is the same function as in the separate mode */
	  DecodeVopDataPartitioningIntraErrRes(stream, vo_id,
					       trace, curr_vop);
	}
      else
	DecodeVopCombinedShapeTextureIntraErrRes(stream,vo_id,
						 trace,curr_vop);
      
#ifndef _WD_MODE_			     
      if (GetVopSpriteUsage(curr_vop) == ONLINE_SPRITE)
	{
	  InitOnLineSprite(GetVopSprite(curr_vop),curr_vop);
	  InitOnLineSpriteChroma(GetVopSprite(curr_vop),curr_vop);
	  
	  WriteVopGeneric(GetVopSprite(curr_vop),
			  "sprite_dec.yuv",
			  "sprite_dec.yuv",
			  "sprite_dec.yuv",
			  "sprite_dec.y",
			  0,IO_FORMAT,IO_OVERWRITE,1); 
	}
#endif
      
    }
  else if (GetVopPredictionType(curr_vop) == P_VOP)
    {
      if (GetVopDataPartEnable(curr_vop))
	DecodeVopDataPartitioningInterErrRes(stream, vo_id,
					     trace, curr_vop,
					     &mot_x, &mot_y,
					     &MB_decisions);
      else
	DecodeVopCombinedMotionShapeTextureInterErrRes(stream, vo_id, 
						       trace,
						       curr_vop,
						       &mot_x, &mot_y,
						       &MB_decisions);
      
      
#ifndef _WD_MODE_			     
      if (GetVopSpriteUsage(curr_vop) == ONLINE_SPRITE)
	{
	  UpdateOnLineSprite(GetVopSprite(curr_vop),curr_vop);
	  
	  		WriteVopGeneric(GetVopSprite(curr_vop),
			"sprite_dec.yuv",
				"sprite_dec.yuv",
				"sprite_dec.yuv",
				"sprite_dec.y",
				0,IO_FORMAT,IO_APPEND,1);
	}
#endif
      
    }
  else
    {
      B_DecodeVopCombinedMotionShapeTextureInterErrRes(stream,vo_id,trace,curr_vop,
						       mot_x_P[vo_id][vol_id],
						       mot_y_P[vo_id][vol_id],
						       MB_decisions_P[vo_id][vol_id]);
      
    }

 /* Deallocate memory for motion vectors and MB modes */
  if (GetVopPredictionType(curr_vop)!=B_VOP) {
    if (mot_x_P[vo_id][vol_id]!=NULL) FreeImage(mot_x_P[vo_id][vol_id]);
    if (mot_y_P[vo_id][vol_id]!=NULL) FreeImage(mot_y_P[vo_id][vol_id]);
    if (MB_decisions_P[vo_id][vol_id]!=NULL) FreeImage(MB_decisions_P[vo_id][vol_id]);     
    if (GetVopPredictionType(curr_vop)==I_VOP) {
      mot_x_P[vo_id][vol_id]=AllocImage(GetVopWidth (curr_vop)/8,GetVopHeight (curr_vop)/8,FLOAT_TYPE);
      mot_y_P[vo_id][vol_id]=AllocImage(GetVopWidth (curr_vop)/8,GetVopHeight (curr_vop)/8,FLOAT_TYPE);
      SetConstantImage (mot_x_P[vo_id][vol_id],+0.0);
      SetConstantImage (mot_y_P[vo_id][vol_id],+0.0);
      MB_decisions_P[vo_id][vol_id]=AllocImage(GetVopWidth (curr_vop)/16,GetVopHeight (curr_vop)/16,SHORT_TYPE);
      SetConstantImage (MB_decisions_P[vo_id][vol_id],0); /* MBM_INTRA */
    } else {
      mot_x_P[vo_id][vol_id] = mot_x;
      mot_y_P[vo_id][vol_id] = mot_y;
      MB_decisions_P[vo_id][vol_id]=MB_decisions;
    }
  } 
  
  return;
}


/***********************************************************CommentBegin******
 *
 * -- FindStartGOV -- 
 *
 * Author :  Aasmund Sandvand (Telenor)
 *
 * Created : 15.09.97	
 *
 * Purpose : To locate first GOV after random_access_start_time	
 * 
 *
 * Arguments in : 	
 *      Int number_of_vols   number_of_vols for this VO
 *      Vol *vol_list[]
 *
 * Arguments in/out :	
 *  Bitstream *stream[]      Array of bitstreams for this VO
 *	Int *readen_bits[]	pointer to value of up to now readen_bits
 *	Trace *trace[]		pointer to trace information
 *  Int random_access_start_time
 *
 *
 * Arguments out :	
 *	
 *
 * Return values :	
 *	
 *
 * Side effects :	
 *
 * Description :	
 *	
 *
 * See also :
 *	
 *
 * Modified : 
 *
 *
 ***********************************************************CommentEnd********/

Void FindStartGOV(Int number_of_vols,Bitstream *stream[], 
				  Trace *trace[],Vol *vol_list, Int readen_bits[], Int random_access_start_time)
{
	Int time,broken_link,closed_gov;
	Int k,vo_id, vol_id;
	Vol *next_vol;
	Bitstream *tmp_stream = NULL;
	Bitstream *tmp_stream2 = NULL;
	Int OK = 0;
	Int offset,offset2;
	
	next_vol = vol_list;
	vo_id = GetVolVOId(next_vol);
	for(k=0; k<number_of_vols; k++){
		vol_id = GetVolId(next_vol);
		tmp_stream=clone_bitstream(stream[k]);
		tmp_stream2=clone_bitstream(stream[k]);
		GetBitstreamPosition(&offset, stream[k]);
		GetBitstreamPosition(&offset2, stream[k]);
		OK=0;
		while(!OK){
			/* search for next GROUP_START_CODE */
			while (BitstreamShowBits(tmp_stream, VOP_START_CODE_LENGTH) != GROUP_START_CODE) {
				BitstreamFlushBits(tmp_stream, 8);
			}
			GetBitstreamPosition(&offset2, tmp_stream);
			tmp_stream2=clone_bitstream(tmp_stream);
			ReadGOV(&time, &closed_gov, &broken_link, tmp_stream,trace[k],&readen_bits[k]);
			if(closed_gov!=1){
				printf("\n*** ERROR: VO_%i, VOL_%i: Random Access: GOV is not followed by I-VOP\n",vo_id,vol_id);
				exit(1);
			}
			if(time<= random_access_start_time/1000){
				stream[k]=clone_bitstream(tmp_stream2);
				offset=offset2;
			}
			else
				OK=1;
		}/*while(!OK)*/
		
		SeekBitstream(offset,stream[k]);
		
		next_vol = GetVolNext(next_vol);
	}/*for k..*/
	free(tmp_stream);
	free(tmp_stream2);
}



/***********************************************************CommentBegin******
 *
 * -- ReadGOV -- Read and return GOV information 
 *
 * Author :  Aasmund Sandvand (Telenor)
 *
 * Created : 07.07.97	
 *
 * Purpose :		
 * 
 *
 * Arguments in : Bitstream *stream
 *
 *
 * Arguments in/out :Int *time
 *                   Int *closed_gov
 *                   Int *broken_link 
 *                   Trace *trace
 *                   Int *readen_bits
 *		
 *
 *
 * Arguments out : 
 *
 * Return values :	
 *	
 *
 * Side effects :  
 *
 * Description :	
 *	
 *
 * See also :
 *	
 *
 * Modified :	25.03.98 M.Wollborn: Modified due to N2171 Cl. 2.1.9 (user data)
 *
 *
 ***********************************************************CommentEnd********/


Void ReadGOV(Int *time, Int *closed_gov, Int *broken_link,
	     Bitstream *stream, Trace *trace, Int *readen_bits)
{
   Int tmpvar,time_s; 
  tmpvar = (Int) BitstreamReadBits(stream,32,"ReadGOV: group_start_code",trace,CODE);
  if (tmpvar!= GROUP_START_CODE){
    printf("\n*** ERROR: ReadGOV: This is no GOV\n");
    exit(1);
  }
  tmpvar = (Int) BitstreamReadBits(stream,5, "ReadGOV: Hour",trace,NUM);
   time_s= tmpvar*3600;
   tmpvar = (Int) BitstreamReadBits(stream,6, "ReadGOV: Minute",trace,NUM);
   time_s += tmpvar*60;
   tmpvar = (Int) BitstreamReadBits(stream,1,"ReadGOV: Marker_bit",trace,NUM);
   tmpvar = (Int) BitstreamReadBits(stream,6,"ReadGOV: Second",trace,NUM);
   time_s += tmpvar;
   *time=time_s;
   tmpvar = (Int) BitstreamReadBits(stream,1, "ReadGOV: closed_gov",trace,NUM);
   *closed_gov=tmpvar;
   tmpvar = (Int) BitstreamReadBits(stream,1, "ReadGOV: broken_link",trace,NUM);
   *broken_link=tmpvar;
   *readen_bits += 52;
   BitstreamByteAlign(stream);

   /* Included due to N2171 Cl. 2.1.9 (user data) MW 25-MAR-1998 */
   tmpvar = (Int) BitstreamShowBits(stream,USER_DATA_START_CODE_LENGTH);
   if (tmpvar == USER_DATA_START_CODE) 
     *readen_bits += GetUserDataFromBitstream(stream,trace,NULL);

}

/***********************************************************CommentBegin******
 *
 * -- DecodeTimeControl
 *
 * Author :  Ryuji Kitaura (sharp)
 *
 ********************************************************************/
Int DecodeTimeControl(Bitstream *stream,
		      Int vop_display_time,
		      Int prev_vop_display_time,
	              Int next_display_time,
		      Int stop_decoding_vol,
                      Vop *curr_vop,
		      Int random_access_start_time,
		      Float next_display_time_in,
		      Int *enh_decoding_flag,
		      Trace *trace)
{
  Int decode_start_flag=0;
  Int predic_type;
  Int time;
  static Int prev_predic_type;
  
  static Int base_resolution = 1,
             enh_resolution  = 1;

  
  if (stop_decoding_vol == 0) {
    if(!temporal_scalability){
      predic_type = GetVopPredictionType(curr_vop);
      if(prev_vop_display_time < next_display_time
	 && (vop_display_time < next_display_time || predic_type != B_VOP))
	decode_start_flag = 1;
    }
    else{    
      if(CheckBaseVop(curr_vop)){ /* base_time */
	base_resolution = GetVopTimeIncrementResolution(curr_vop);
	if(last_base_decoding_time[0] < 0 || last_base_decoding_time[2] < 0)
	  decode_start_flag = 1;
	else {
	  predic_type=preview_vop_header(stream,trace);
	  if (predic_type== -1)
	    return(1);
	  
          time = (last_enh_decoding_time + 1) * base_resolution / enh_resolution;
	  
  
	  if (last_base_decoding_time[1]<0) { /* no B_VOP */
	    if (predic_type==B_VOP) {
	      decode_start_flag = 1;
	      prev_predic_type=B_VOP;
	    }
	    else {
	      if(time==last_base_decoding_time[2])
		decode_start_flag = 1;
	      else decode_start_flag = 0;
	    }
	  }
	  
	  else { /* B_VOP+P_VOP */
	    if( last_enh_decoding_time < 0                                                        ||
	        (predic_type==B_VOP && prev_predic_type==P_VOP)                                   ||
	       ((predic_type==I_VOP || predic_type==P_VOP) && time == last_base_decoding_time[2]) ||
	        (predic_type==B_VOP                        && time == last_base_decoding_time[1])    ){ 
	      decode_start_flag = 1;
	      prev_predic_type  = predic_type;
	    }
	    else decode_start_flag = 0;
	  }
	}
      }
      else { /* enhance_time */
          enh_resolution = GetVopTimeIncrementResolution(curr_vop);
	  if((Int)(last_base_decoding_time[0] * enh_resolution / base_resolution ) == next_display_time ||
	     (Int)(last_base_decoding_time[1] * enh_resolution / base_resolution ) == next_display_time ||
	     (Int)(last_base_decoding_time[2] * enh_resolution / base_resolution ) == next_display_time )
	    decode_start_flag = 0;
	  else if(!*enh_decoding_flag){
	    decode_start_flag = 1;
	    *enh_decoding_flag = 1;
	  }
	  else decode_start_flag = 0; 
      }
    }
  }
  else decode_start_flag = 0;
  
  return(decode_start_flag);
}

Int IsSOLlayer(char *bitstream_filename)
{
  FILE *stream;
  Int  IsSOLflag=TRUE;
  Int  len = VOL_START_CODE_LENGTH;
  UInt StartCode=0;

  stream = fopen(bitstream_filename, "rb");

  /* skip the VO_START_CODE and VO_ID */
  if (VO_HEADER_LENGTH%8 != 0){
    fprintf(stderr, "\nError:VOL Start Code should be byte aligned");
    exit(-1);
  }
  fseek(stream, VO_HEADER_LENGTH/8, SEEK_SET);

  while(len>8){
    StartCode += getc(stream);
    StartCode <<= 8;
    len -= 8;
  }
  StartCode +=  getc(stream);
  StartCode >>= (8-len);

  if (StartCode == VOL_START_CODE)
    IsSOLflag = FALSE;

  fclose(stream);

  return IsSOLflag;
}







/***********************************************************CommentBegin******
 *
 * -- GetUserDataFromBitstream() -- writes user data from file into bitstream
 *
 * Author :             
 *      Michael Wollborn, University of Hannover
 *
 * Created :            
 *      23-03-98
 *
 * Purpose :
 *	This function reads the user data from a the bitstream to a given file.
 * 
 * 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
GetUserDataFromBitstream(Bitstream *stream, Trace *trace, Char *filename)
{
  Int filesize=0, tmpvar;

  FILE *ud_file;
  Byte data;
  
  /* Create output file for user data */
  if(filename != NULL)
    {
      if((ud_file = fopen(filename,"wb")) == NULL)
	{
	  fprintf(stderr,"ERROR(GetUserDataToBitstream): unable to open %s\n",
		  filename);
	  exit(1);
	}
    }

  /* Read USER_DATA_START_CODE from bitstream */
  tmpvar = (Int)BitstreamReadBits(stream,USER_DATA_START_CODE_LENGTH,
				  "GetUserDataFromBitstream",trace,NUM);

  /* Read user data from bitstream until next start code */
  while((tmpvar = (Int)0x00ffffff & (Int)BitstreamShowBits(stream,START_CODE_PREFIX_LENGTH+8))
	  != START_CODE_PREFIX)
    {
      data = (Byte) BitstreamReadBits(stream,8,"User data",trace,NUM);

      if(filename != NULL)
        filesize += fwrite(&data,1,1,ud_file);
    }
  BitstreamByteAlign(stream);

  /* Close file and return number of bits written*/
  if(filename != NULL)
    fclose(ud_file);

  return(filesize*3);
}
