/*****************************************************************************
 *
 * This software module was originally developed by
 *
 *   Ryuji Kitaura  (Sharp Corporation)                                  
 *   Hisashi Saiga  (Sharp Corporation)                                  
 *   Tomoko Aono    (Sharp Corporation)                                  
 *   Hiroyuki Katata(Sharp Corporation)                                  
 *
 * and edited by
 * 
 *   Fernando Jaureguizar (UPM / ACTS-MoMuSyS)
 *
 * in the course of development of the MPEG-4 Video (ISO/IEC 14496-2) standard.
 * This software module is an implementation of a part of one or more MPEG-4
 * Video (ISO/IEC 14496-2) tools as specified by the MPEG-4 Video (ISO/IEC
 * 14496-2) standard.
 *
 * ISO/IEC gives users of the MPEG-4 Video (ISO/IEC 14496-2) standard free
 * license to this software module or modifications thereof for use in hardware
 * or software products claiming conformance to the MPEG-4 Video (ISO/IEC
 * 14496-2) standard.
 *
 * Those intending to use this software module in hardware or software products
 * are advised that its use may infringe existing patents. The original
 * developer of this software module and his/her company, the subsequent
 * editors and their companies, and ISO/IEC have no liability for use of this
 * software module or modifications thereof in an implementation. Copyright is
 * not released for non MPEG-4 Video (ISO/IEC 14496-2) Standard conforming
 * products.
 *
 * Sharp Corporation retains 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
 *
 *****************************************************************************/

/* All functions in this file were written by
   Hisashi Saiga & Ryuji Kitaura of Sharp Corporation, 1997
   utilizing existing subroutines and data structures.
*/

/***********************************************************HeaderBegin*******
 *
 * File:   scal_dec.c 
 *
 * Author:   Hisashi Saiga & Ryuji Kitaura  (Sharp Corporation)
 * Created:  00-xxx-1997
 *
 * Description:
 *   Originally created by the authors utilizing existing subroutines
 *   and data structures.
 *   The original file tpsdec.c had the modules necessary for decoding
 *   an MPEG-4 video VM7.0 bitstream with temporal scalability.
 *
 * Notes:
 *   Some parts of the original file have been modified to have in the same
 *   file the temporal and the spatial scalability.
 *   The main routine DecodeVopScalable() was created by Michael Wollborn (TUH)
 *   on 12-AUG-1996 as an empty function.
 *   This function was filled by two companies outside the ACTS-MoMuSys
 *   consortium; Sharp (temporal scalability) and Sony (spatial scalability
 *   integrated into MoMuSyS VM6 version on 26.May.97),
 *   but using the same function name.
 *   F. Jaureguizar from (UMC / ACTS-MoMuSyS) has integrated and modified both
 *   scalabilities in this DecodeVopScalable() function.
 *
 * Modified :
 *   30.07.97 F. Jaureguizar: integration of spatial scalability (SpSc)
 *            Some format modification to make the code more readeable.
 *   29.08.97 Osamu Sunohara(Sony): modified for spatial scalable coding
 *   05.09.97 F. Jaureguizar: deleted unnecessary "base_vop = SallocVop();"
 *            line in DecodeVopScalable()
 *
 *      23.10.97 Minhua Zhou: changed deblock_filter_disable to 
 *                            post_filter_type
 ***********************************************************HeaderEnd*********/

#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 <limits.h>
#include "scal_dec.h"    /*SpSc*/
#include "vm_midproc.h"  /*SpSc*/
#include "do_bgc.h"
#include "alp_dec_mom.h"
#include "alp_dec_header.h"

#ifdef _DEBUG_SPSC2_
static tmp_cnt = 0;
#endif

/* 1197-3 SONY */
#ifdef _DEBUG_SPSC3_
static Int dec_base_cnt = 0;
#endif
/* 1197-3 */

/* int prev_ref= -1;
int next_ref= -1; */
/***********************************************************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 :
 *   It is supposed the following returns in case of Spatial Scalability:
 *      GetVopRefSelCode(curr_vop)  = 3 for P_VOPs and 0 for B_VOPs.
 *      GetVopBackCom(curr_vop)     = 0 -- No Background composition
 *      GetVopEnhanceType(curr_vop) = 0 -- All base frame is enhanced
 *
 * See also :
 *
 *
 * Modified :
 *   00.??.97 Sharp Corp.: implementation of the temporal scalability.
 *   30.07.97 F. Jaureguizar: integration of the spatial scalability.
 *   29.08.97 Osamu Sunohara: modified for spatial scalable coding
 *   05.09.97 F. Jaureguizar: deleted unnecessary "base_vop = SallocVop();"
 *            line in DecodeVopScalable()
 *
 ***********************************************************CommentEnd********/

Void  DecodeVopScalable(Bitstream **stream ,
                        Int vo_id ,
                        Trace *trace,
                        Vop *curr_vop ,
                        Vol *vol_list ,
                        Int post_filter_type)
{
  Vol        *ref_vol;
/* 1197-3 SONY*/
  Vol        *curr_vol;
/* 1197-3 SONY*/  
  
  Int        tmpvar;

  Int        vop_exist[ 2 ];
  Vop        *vop_list[ 2 ];
  Int        vop_display_time[ 2 ];
  Int        vol_id, nvol_id;
  Int        ref_vol_id, nref_vol_id;
  Int        *mvda;
  Vop        *file_vop;
  /*>SpSc*/
  Int        predic_type  = GetVopPredictionType(curr_vop);
  Int        ref_sel_code;
  Vop        *up_vop=NULL;
  Vop        *base_vop=NULL;
  Int        spatial_scalability = 0;
  Int        aux_width;
  Int        aux_height;
  Int        aux_hor_spat_ref;
  Int        aux_ver_spat_ref;

             
  /*SpSc<*/
#ifdef _DEBUG_SPSC_
  static Int count=0;
  Char       name[81];
#endif

/* 1197-3 SONY */
  Int curr_mtb, ref_prev_mtb, ref_next_mtb, ref_bvop_mtb =0;     /* modulo_time_base */
  Int curr_ti,  ref_prev_ti,  ref_next_ti,  ref_bvop_ti =0;      /* time_increment */
  Int ref_vop_flag;
/* 1197-3 */

/* SONY 070498 - start */
  Int tir_b, tir_e;
/* SONY 070498 - end */

  Vop   *ref_vop0 = NULL;
  Vop   *ref_vop1 = NULL;
  Vop   *tmp_vop  = NULL;

  nvol_id = GetVopId( curr_vop );
  vol_id = bs_vol[vo_id][nvol_id];

  /* 1197-3 SONY */
  curr_vol = GetVolById( vol_list , nvol_id );
  /* 1197-3 SONY */

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

    tmpvar = (Int) BitstreamReadBits( stream[ vol_id ] , 1 ,
        "load_backward_shape" , trace , CODE );
    PutVopLoadBackShape( tmpvar , curr_vop );
    if ( GetVopLoadBackShape( curr_vop ) )
      {
      Int   back_shape_width;
      Int   back_shape_height;
      Int   back_shape_hor_spat_ref;
      Int   back_shape_ver_spat_ref;
      Vop   *dup_back_shape_vop;
      Int   *for_mb_type;
      Int   *back_mb_type;

      back_shape_width = ( Int )BitstreamReadBits( stream[ vol_id ] , 13 ,
          "back_shape_width" , trace , NUM );
      back_shape_height = ( Int )BitstreamReadBits( stream[ vol_id ] , 13 ,
          "back_shape_height" , trace , NUM );
      back_shape_hor_spat_ref = (Int)BitstreamReadBits( stream[ vol_id ], 13 ,
          "back_shape_hor_spat_ref" , trace , NUM );
      tmpvar = (Int) BitstreamReadBits( stream[ vol_id ] , 1 ,
          "marker_bit" , trace , FLAG );
      back_shape_ver_spat_ref = (Int)BitstreamReadBits( stream[ vol_id ], 13 ,
          "back_shape_ver_spat_ref" , trace , NUM );
      if ( back_shape_vop != ( Vop * )NULL )
        {
        dup_back_shape_vop = CloneVop( back_shape_vop );
        FreeVop( back_shape_vop );
        }
      else
        dup_back_shape_vop = ( Vop * )NULL;
      if ( back_shape_width ==0 )
        {
        back_shape_vop = AllocVop( GetVopWidth( curr_vop ) ,GetVopHeight( curr_vop ) );
	PutVopErrorResDisable(GetVopErrorResDisable(curr_vop), back_shape_vop);
	PutVopChangeCRDisable(GetVopChangeCRDisable(curr_vop), back_shape_vop);
        PutVopShapeEffects(GetVopShapeEffects(curr_vop), back_shape_vop);
	SetConstantImage( GetVopA (back_shape_vop) , 0 );
        PutVopHorSpatRef( back_shape_hor_spat_ref , back_shape_vop );
        PutVopVerSpatRef( back_shape_ver_spat_ref , back_shape_vop );
        }
      else
        {
        back_shape_vop = AllocVop( back_shape_width , back_shape_height );
	PutVopErrorResDisable(GetVopErrorResDisable(curr_vop), back_shape_vop);
	PutVopChangeCRDisable(GetVopChangeCRDisable(curr_vop), back_shape_vop);
        PutVopShapeEffects(GetVopShapeEffects(curr_vop), back_shape_vop);
        PutVopHorSpatRef( back_shape_hor_spat_ref , back_shape_vop );
        PutVopVerSpatRef( back_shape_ver_spat_ref , back_shape_vop );
        back_mb_type = ( Int * )calloc( GetVopWidth( back_shape_vop ) /
                       MB_SIZE * GetVopHeight( back_shape_vop ) / MB_SIZE , sizeof(Int) );
        mvda = ( Int * )calloc( GetVopWidth( back_shape_vop ) /
               MB_SIZE * GetVopHeight( back_shape_vop ) / MB_SIZE , sizeof(Int) );
        PutVopPredictionType(INTRA_VOP,back_shape_vop);
	PutVopShape(BINARY_SHAPE_ONLY, back_shape_vop);
	
	DecodeVopCombinedShapeTextureIntra(stream[ vol_id ], vo_id, trace, back_shape_vop);

	free( back_mb_type );
        free( mvda );
        }
        tmpvar = (Int) BitstreamReadBits( stream[ vol_id ] , 1 ,
					 "load_forward_shape" , trace , CODE );
        PutVopLoadForShape( tmpvar , curr_vop );
        if ( GetVopLoadForShape( curr_vop ) )
          {
          Int   for_shape_width;
          Int   for_shape_height;
          Int   for_shape_hor_spat_ref;
          Int   for_shape_ver_spat_ref;

          for_shape_width = ( Int )BitstreamReadBits( stream[ vol_id ] , 13 ,
              "for_shape_width" , trace , NUM );
          for_shape_height = ( Int )BitstreamReadBits( stream[ vol_id ] , 13 ,
              "for_shape_height" , trace , NUM );
          for_shape_hor_spat_ref = (Int)BitstreamReadBits( stream[vol_id], 13 ,
              "for_shape_hor_spat_ref" , trace , NUM );
          tmpvar = (Int) BitstreamReadBits( stream[ vol_id ] , 1 ,
              "marker_bit" , trace , FLAG );
          for_shape_ver_spat_ref = (Int)BitstreamReadBits( stream[vol_id], 13 ,
              "for_shape_ver_spat_ref" , trace , NUM );
          if ( for_shape_vop != ( Vop * )NULL )
            FreeVop( for_shape_vop );
          if ( for_shape_width == 0 )
            {
            for_shape_vop = AllocVop( GetVopWidth( curr_vop ), GetVopHeight( curr_vop ) );
 	    PutVopErrorResDisable(GetVopErrorResDisable(curr_vop), for_shape_vop);
	    PutVopChangeCRDisable(GetVopChangeCRDisable(curr_vop), for_shape_vop);
            PutVopShapeEffects(GetVopShapeEffects(curr_vop), for_shape_vop);
            SetConstantImage( GetVopA( for_shape_vop ) , 0 );
            PutVopHorSpatRef( for_shape_hor_spat_ref , for_shape_vop );
            PutVopVerSpatRef( for_shape_ver_spat_ref , for_shape_vop );
            }
          else
            {
            for_shape_vop = AllocVop( for_shape_width , for_shape_height );
	    PutVopErrorResDisable(GetVopErrorResDisable(curr_vop), for_shape_vop);
	    PutVopChangeCRDisable(GetVopChangeCRDisable(curr_vop), for_shape_vop);
            PutVopShapeEffects(GetVopShapeEffects(curr_vop), for_shape_vop);
            PutVopHorSpatRef( for_shape_hor_spat_ref , for_shape_vop );
            PutVopVerSpatRef( for_shape_ver_spat_ref , for_shape_vop );
            for_mb_type = ( Int * )calloc( GetVopWidth( for_shape_vop ) /
			  MB_SIZE * GetVopHeight(for_shape_vop) / MB_SIZE , sizeof(Int) );
            mvda = ( Int * )calloc( GetVopWidth( for_shape_vop ) /
                   MB_SIZE * GetVopHeight(for_shape_vop) / MB_SIZE , sizeof(Int) );
            PutVopPredictionType(INTRA_VOP,for_shape_vop);
	    PutVopShape(BINARY_SHAPE_ONLY, for_shape_vop);
	    
	    DecodeVopCombinedShapeTextureIntra(stream[ vol_id ], vo_id, trace, for_shape_vop);
	    
            free( for_mb_type );
            free ( mvda );
            }
          }
        else
          {
          if ( for_shape_vop != ( Vop * )NULL )
            FreeVop( for_shape_vop );
          if ( dup_back_shape_vop != ( Vop * )NULL )
            for_shape_vop = CloneVop( dup_back_shape_vop );
          }
        if ( dup_back_shape_vop != ( Vop * )NULL )
          FreeVop( dup_back_shape_vop );
      }
    }
  else  /* No Background Composition */
    {   
    vop_list[ 0 ]  = ( Vop * )NULL;
    vop_list[ 1 ]  = ( Vop * )NULL;
    vop_exist[ 0 ] = vop_exist[ 1 ] = 0;
    }

  tmpvar = ( Int )BitstreamReadBits( stream[ vol_id ] , 2 ,
            "ref_select_code" , trace , CODE );
  PutVopRefSelCode( tmpvar , curr_vop );
  nref_vol_id = GetVopRefId( curr_vop );
  ref_vol_id = bs_vol[vo_id][nref_vol_id];
  ref_vol = GetVolById( vol_list , nref_vol_id );

  /*>SpSc*/
  ref_sel_code = GetVopRefSelCode(curr_vop);
  
  if ( (predic_type == P_VOP  &&  ref_sel_code == 3) ||
       (predic_type == B_VOP  &&  ref_sel_code == 0) )
    spatial_scalability = 1;
  
  if (spatial_scalability )
    {
#ifdef _DEBUG_SPSC_
    PrintVopInfo(curr_vop,"currA.1S");
    PrintVopInfo(GetVopNextTemp(curr_vop),"currA.1S->N");
    PrintVopInfo(GetVopPrevTemp(curr_vop),"currA.1S->P");
    sprintf(name,"A.1S%d",count);
    WriteVopDebug(curr_vop,name,name,name,0);

    PrintVopInfo(GetVolVop(ref_vol),"currA.1S-ref");
    PrintVopInfo(GetVopNextTemp(GetVolVop(ref_vol)),"currA.1S-ref->N");
    PrintVopInfo(GetVopPrevTemp(GetVolVop(ref_vol)),"currA.1S-ref->P");
    sprintf(name,"A.1S-ref%d",count);
    WriteVopDebug(GetVolVop(ref_vol),name,name,name,0);
#endif

/* 1197-3 SONY */
    curr_mtb = GetVopModTimeBase(curr_vop);
    curr_ti = GetVopTimeInc(curr_vop);
    ref_prev_mtb = GetVopModTimeBase(GetVopPrevTemp(GetVolVop(ref_vol)));
    ref_prev_ti  = GetVopTimeInc(GetVopPrevTemp(GetVolVop(ref_vol)));
    ref_next_mtb = GetVopModTimeBase(GetVopNextTemp(GetVolVop(ref_vol)));
    ref_next_ti  = GetVopTimeInc(GetVopNextTemp(GetVolVop(ref_vol)));
    if(GetVopBvopTemp(GetVolVop(ref_vol))!=NULL)
      {
	ref_bvop_mtb = GetVopModTimeBase(GetVopBvopTemp(GetVolVop(ref_vol)));
	ref_bvop_ti  = GetVopTimeInc(GetVopBvopTemp(GetVolVop(ref_vol)));
      }

/* SONY 070498 for Spatial Scalability */
    tir_b = GetVopTimeIncrementResolution(GetVolVop(ref_vol));
    tir_e = GetVopTimeIncrementResolution(curr_vop);

    if((ref_prev_mtb>=0)&&((curr_mtb*tir_e+curr_ti)==(ref_prev_mtb*tir_b+ref_prev_ti)))
      {
        base_vop = CloneVop_TMP(GetVopPrevTemp(GetVolVop(ref_vol)));
        ref_vop_flag = 0;
    } else if((ref_next_mtb>=0)&&((curr_mtb*tir_e+curr_ti)==(ref_next_mtb*tir_b+ref_next_ti)))
      {
        base_vop = CloneVop_TMP(GetVopNextTemp(GetVolVop(ref_vol)));
        ref_vop_flag = 1;
    } else if(GetVopBvopTemp(GetVolVop(ref_vol))!=NULL)
      {
        if((ref_bvop_mtb>=0)&&((curr_mtb*tir_e+curr_ti)==(ref_bvop_mtb*tir_b+ref_bvop_ti)))
          {
            base_vop = CloneVop_TMP(GetVopBvopTemp(GetVolVop(ref_vol)));
            ref_vop_flag = 2;
        } else
          {
            fprintf(stderr,"curr_time     : %d\n", curr_mtb*tir_e+curr_ti);
            fprintf(stderr,"ref_prev_time : %d\n", ref_prev_mtb*tir_b+ref_prev_ti);
            fprintf(stderr,"ref_next_time : %d\n", ref_next_mtb*tir_b+ref_next_ti);
            fprintf(stderr,"ref_bvop_time : %d\n", ref_bvop_mtb*tir_b+ref_bvop_ti);
            printf("ERROR: Base VOP for upsampling is not existing in the Ref. VOP\n");
            exit(-1);
          }
    } else {
            fprintf(stderr,"curr_time     : %d\n", curr_mtb*tir_e+curr_ti);
            fprintf(stderr,"ref_prev_time : %d\n", ref_prev_mtb*tir_b+ref_prev_ti);
            fprintf(stderr,"ref_next_time : %d\n", ref_next_mtb*tir_b+ref_next_ti);
            printf("ERROR: Base VOP for upsampling is not existing in the Ref. VOP\n");
            exit(-1);
    }
/* SONY 070498 */

#ifdef _DEBUG_SPSC3_
    if(ref_vop_flag==0) fprintf(stderr,"\nbase_vop is from prev_temp of ref VOL\n");
    if(ref_vop_flag==1) fprintf(stderr,"\nbase_vop is from next_temp of ref VOL\n");
    if(ref_vop_flag==2) fprintf(stderr,"\nbase_vop is from bvop_temp of ref VOL\n");
    if(dec_base_cnt==0) {
      WriteVopGeneric( base_vop, "D_base_vop", "D_base_vop", "D_base_vop",
                      "tmpppu", 0, IO_FORMAT, IO_OVERWRITE, 0);
    } else {
      WriteVopGeneric( base_vop, "D_base_vop", "D_base_vop", "D_base_vop",
                      "tmpppu", dec_base_cnt, IO_FORMAT, IO_APPEND, 0);
    }
    dec_base_cnt++;
#endif
/* 1197-3 */


#ifdef _DEBUG_SPSC_
    PrintVopInfo(base_vop,"base");
#endif
/*1197-3 SONY*/
    up_vop = Midproc(base_vop,curr_vol);
/*1197-3 SONY*/
    
#ifdef _DEBUG_SPSC_
    PrintVopInfo(up_vop,"up-0");
    sprintf(name,"Sup-0%d",count);
    WriteVopDebug(up_vop,name,"","",0);
#endif

    aux_width = GetVopWidth(up_vop);
    aux_height = GetVopHeight(up_vop);
    aux_hor_spat_ref = GetVopHorSpatRef(up_vop);
    aux_ver_spat_ref = GetVopVerSpatRef(up_vop);

/* 1197-3 SONY */
    if(ref_vop_flag==0)
      CopyVopNonImageField(GetVopPrevTemp(GetVolVop(ref_vol)),up_vop);
    if(ref_vop_flag==1)
      CopyVopNonImageField(GetVopNextTemp(GetVolVop(ref_vol)),up_vop);
    if(ref_vop_flag==2)
      CopyVopNonImageField(GetVopBvopTemp(GetVolVop(ref_vol)),up_vop);
/*
   CopyVopNonImageField(GetVopPrevTemp(GetVolVop(ref_vol)),up_vop);
*/
/* 1197-3 */

    PutVopWidth(aux_width, up_vop);
    PutVopHeight(aux_height,up_vop);
    PutVopHorSpatRef(aux_hor_spat_ref,up_vop);
    PutVopVerSpatRef(aux_ver_spat_ref,up_vop);

    FreeVop(GetVopNextTemp(up_vop));
    PutVopNextTemp(NULL,up_vop);

    FreeVop(GetVopPrevTemp(up_vop));
    PutVopPrevTemp(NULL,up_vop);

#ifdef _DEBUG_SPSC_
    PrintVopInfo(up_vop,"up-modif");
    sprintf(name,"Sup-modif%d",count);
    WriteVopDebug(up_vop,name,"","",0);
#endif

    VopPadding(up_vop);

#ifdef _DEBUG_SPSC_
    PrintVopInfo(up_vop,"up-padd");
    sprintf(name,"Sup-padd%d",count);
    WriteVopDebug(up_vop,name,"","",0);
#endif

    if (predic_type == P_VOP)
      {
      FreeVop(GetVopNextTemp(curr_vop));
      PutVopNextTemp(NULL,curr_vop);

      FreeVop(GetVopPrevTemp(curr_vop));
      PutVopPrevTemp(NULL,curr_vop);

#ifdef _DEBUG_SPSC_
      PrintVopInfo(curr_vop,"currA.2-p-S");
      PrintVopInfo(GetVopNextTemp(curr_vop),"currA.2-p-S->N");
      PrintVopInfo(GetVopPrevTemp(curr_vop),"currA.2-p-S->P");
#endif

      PutVopNextTemp(up_vop,curr_vop);
      }
    else if (predic_type == B_VOP)
      {
      /* FreeVop(GetVopNextTemp(curr_vop));*/
      FreeVop(GetVopPrevTemp(curr_vop));
      PutVopPrevTemp(NULL,curr_vop);

#ifdef _DEBUG_SPSC_
      PrintVopInfo(curr_vop,"currA.2-b-S");
      PrintVopInfo(GetVopNextTemp(curr_vop),"currA.2-b-S->N");
      PrintVopInfo(GetVopPrevTemp(curr_vop),"currA.2-b-S->P");
#endif

      /*PutVopPrevTemp(CloneVop_TMP(GetVopNextTemp(curr_vop)),curr_vop);*/
      PutVopPrevTemp(GetVopNextTemp(curr_vop),curr_vop);
      PutVopNextTemp(up_vop,curr_vop);
      }

#ifdef _DEBUG_SPSC_
    PrintVopInfo(curr_vop,"currA.3S");
    PrintVopInfo(GetVopNextTemp(curr_vop),"currA.3S->N");
    PrintVopInfo(GetVopPrevTemp(curr_vop),"currA.3S->P");
    sprintf(name,"A.3S%d",count);
    WriteVopDebug(curr_vop,name,name,name,0);

    count++;
#endif

    DecodeVopSpatScalable(stream[ vol_id ], vo_id, trace, curr_vop);

    FreeVop(base_vop);
    /* FreeVop(up_vop);*/
    }

  /*SpSc<*/
  
  if(temporal_scalability)
    search_vop_for_bgc(vop_list, vop_exist, curr_vop, vop_display_time);
  ref_sel_code = GetVopRefSelCode(curr_vop);
  
  /* for vop : prev.base vop */
  if ((predic_type==P_VOP && ref_sel_code==1)    /* for vop : prev.base vop */
      || (predic_type==B_VOP && (ref_sel_code==1 /* for vop : prev.enh vop and
						    back vop: prev.base vop */
      || ref_sel_code==3))) {                    /* for vop : prev.base vop and
						    back vop: next.base vop */
    /* The forward and backward prediction reference VOP belongs to the reference layer */
    if (vop_list[0]!=NULL)
        ref_vop0 = CloneVop(vop_list[0]);
    if (predic_type==B_VOP && vop_list[1]!=NULL)     
        ref_vop1 = CloneVop(vop_list[1]);
    SetRefVop(ref_vop0, ref_vop1, curr_vop); 
    
/*** 4/19 changed by sharp */
    if (GetVopEnhanceType(curr_vop) == 1){
      if (predic_type == P_VOP && ref_sel_code == 1)
        SetConstantImage( GetVopShapeMode (GetVopNextTemp(curr_vop)) , 3 );
      if (predic_type == B_VOP){
        SetConstantImage( GetVopShapeMode (GetVopNextTemp(curr_vop)) , 3 );
        if (ref_sel_code == 3)
          SetConstantImage( GetVopShapeMode (GetVopPrevTemp(curr_vop)) , 3 );
      }
    }
/* 4/19 changed by sharp ***/
  } /* End of predic_type == P_VOP && ref_select_code == 1 ... */

  if (!spatial_scalability) {/*SpSc*/
     DecodeVopNonScalable( stream[ vol_id ] , vo_id , trace , curr_vop );
  }
/* 1197-1 SONY */
  if(!spatial_scalability)
/* 1197-1 */
  if (predic_type == B_VOP) {
    if (GetVopNextTemp(curr_vop) != NULL)
      FreeVop(GetVopNextTemp(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);
    VopPadding(GetVopNextTemp(curr_vop));
  } 
  if ( GetVopBackComp( curr_vop ) )
    {
    CopyAlpha( for_shape_vop , vop_list[ 0 ] );
    if ( vop_exist[ 1 ] )
      CopyAlpha( back_shape_vop , vop_list[ 1 ] );
    else
      CopyAlpha( back_shape_vop , vop_list[ 0 ] );
   }
  
  /* for type 2 & 0 & 3 */
  if ( GetVopBackComp( curr_vop ) == 0 ){   
      if (GetVopEnhanceType( curr_vop ) == 1) {
	Vop *enh_vop, *local_vop;
	file_vop  = AllocVop( image_width , image_height );
	local_vop = PostFilter_TPS(vop_list[0], post_filter_type, image_width , image_height);
	enh_vop   = PostFilter_TPS(curr_vop,    post_filter_type, image_width , image_height);
	do_bgc(enh_vop,
	       local_vop,
	       local_vop,
               file_vop ,
               CalcTime(curr_vop),
               vop_display_time[ 0 ],
               vop_display_time[ 0 ]);
	FreeVop( local_vop );
	FreeVop( enh_vop );
      }
      else
        file_vop = PostFilter_TPS(curr_vop, post_filter_type, image_width , image_height);
  }
/* 4/9 for TPS (SHARP) ***/
  /* for type 1 */
  else
    {
    if ( vop_exist[ 1 ] == 0 )
      {
      Vop   *local, *base0;
      file_vop = AllocVop( image_width , image_height );
      /* for deblock */
      local = PostFilter_TPS( curr_vop,      post_filter_type, image_width , image_height);
      base0 = PostFilter_TPS( vop_list[ 0 ], post_filter_type, image_width , image_height);
      PutVopShape( 1 , base0 ); 
      do_bgc(local ,
             base0 ,
             base0 ,
             file_vop ,
             CalcTime(curr_vop),
             vop_display_time[ 0 ],
             vop_display_time[ 0 ]);
      FreeVop(local);
      FreeVop(base0);
      }
    else
      {
      Vop   *local, *base0, *base1;
      file_vop = AllocVop( image_width , image_height );
      /* for deblock */
      local = PostFilter_TPS( curr_vop,      post_filter_type, image_width , image_height);
      base0 = PostFilter_TPS( vop_list[ 0 ], post_filter_type, image_width , image_height);
      base1 = PostFilter_TPS( vop_list[ 1 ], post_filter_type, image_width , image_height);
      PutVopShape( 1 , base0 ); 
      PutVopShape( 1 , base1 ); 
      do_bgc(local ,
             base0 ,
             base1 ,
             file_vop ,
             CalcTime(curr_vop),
             vop_display_time[ 0 ],
             vop_display_time[ 1 ]);
      FreeVop(local);
      FreeVop(base0);
      FreeVop(base1);
      }
    }
  if ( GetVopWidth( curr_vop ) != 0 )
    {
    static Int first = 1;
    /* modified for spatial scalable coding by Sony 290897 */
    if(spatial_scalability)
      {
	static Int spsc_count=0;
	if(spsc_count==0)
	  WriteVopGeneric( file_vop , comp_output_filename[ 0 ] ,
			  comp_output_filename[ 1 ] , comp_output_filename[ 2 ] ,
			  comp_output_filename[ 3 ] , spsc_count,
			  IO_FORMAT , IO_OVERWRITE ,FALSE );
	else
	  WriteVopGeneric( file_vop , comp_output_filename[ 0 ] ,
			  comp_output_filename[ 1 ] , comp_output_filename[ 2 ] ,
			  comp_output_filename[ 3 ] , spsc_count,
			  IO_FORMAT , IO_APPEND ,FALSE );
	spsc_count++;
    } else {
    if (!temporal_scalability && first)
	WriteVopGeneric( file_vop , comp_output_filename[ 0 ] ,
			comp_output_filename[ 1 ] , comp_output_filename[ 2 ] ,
			comp_output_filename[ 3 ] , CalcFrameNumber(curr_vop),
			IO_FORMAT , IO_OVERWRITE ,FALSE );
      else
	WriteVopGeneric( file_vop , comp_output_filename[ 0 ] ,
			comp_output_filename[ 1 ] , comp_output_filename[ 2 ] ,
			comp_output_filename[ 3 ] , CalcFrameNumber(curr_vop),
			IO_FORMAT , IO_APPEND ,FALSE );
    }
/* 290897 */
    
    if(temporal_scalability)
        fprintf(stderr,"[E]frame[%d] Write ENHANCE\n",CalcFrameNumber(curr_vop));
/*#endif*/
    first = 0;
    }

  FreeVop( file_vop );
  
  if ( vop_exist[ 0 ] != 0 ){
      if ( GetVopNextTemp( vop_list[ 0 ] ) != ( Vop * )NULL )
          FreeVop(GetVopNextTemp( vop_list[ 0 ] ));
      if(vop_list[ 0 ] != ( Vop * )NULL)
          FreeVop( vop_list[ 0 ] );
  }
  if ( vop_exist[ 1 ] ){
      if ( GetVopNextTemp( vop_list[ 1 ] ) != ( Vop * )NULL )
          FreeVop(GetVopNextTemp( vop_list[ 1 ] ));
      if(vop_list[ 1 ] != ( Vop * )NULL)
          FreeVop( vop_list[ 1 ] );
  }

  return;
}

/***********************************************************CommentBegin******
 *
 * -- GetBitstreamPosition -- Get the position of the next input on the file
 *                associated with the bitstream
 *
 * Author :
 *      Hisashi Saiga (SHARP)
 *
 * Created :
 *   25-FEB-1997
 *
 *
 * Purpose :
 *   Get the position of the next input on the file
 *   associated with the bitstream
 *
 *
 * Arguments in :
 *   int      offset0     offset
 *
 * Arguments in/out :
 *   long      *stream    the bitstream
 *
 *
 * Arguments out :
 *
 *
 * Return values :
 *
 *
 * Side effects :
 *
 *
 * Description :
 *
 *
 * See also :
 *
 *
 * Modified :
 *
 *
 ***********************************************************CommentEnd********/

Int   GetBitstreamPosition(
    Int *offset0 ,
    Bitstream *stream0 )
{
   FILE   *fp0;

   fp0 = stream0 -> fptr;
   *offset0 = ftell( fp0 );
   /* I don't know what value ftell() returns on error */
   return( 0 );
}

/***********************************************************CommentBegin******
 *
 * -- SeekBitstream -- Seek the file associated with the bitstream
 *
 * Author :
 *      Hisashi Saiga (SHARP)
 *
 * Created :
 *   25-FEB-1997
 *
 * Purpose :
 *   Seek the file associated with the bitstream
 *
 * Arguments in :
 *   long      offset0      offset
 *   Bitstream   *stream    a bitstream that contains the original status
 * Arguments in/out :
 *
 *
 * Arguments out :
 *
 *
 * Return values :
 *
 *
 * Side effects :
 *
 *
 * Description :
 *
 *
 * See also :
 *
 *
 * Modified :
 *
 *
 ***********************************************************CommentEnd********/

Int   SeekBitstream(
    Int offset0 ,
    Bitstream *stream0 )
{
   FILE   *fp0;

   fp0 = stream0 -> fptr;
   if ( fseek( fp0 , ( long )offset0 , 0 ) == -1 ) return( 1 );
   else return( 0 );
}

/***********************************************************CommentBegin******
 *
 * -- clone_bitstream -- Clones a bitstream???
 *
 * Author :
 *   SHARP???
 *
 * Created :
 *   ???
 *
 * Purpose :
 *  ???
 *
 ***********************************************************CommentEnd********/
 
Bitstream   *clone_bitstream(
    Bitstream *stream0 )
{
   Bitstream   *stream1;

   stream1 = ( Bitstream * )malloc ( sizeof( Bitstream ) );
   if ( stream1 == NULL ) return( NULL );
   memcpy( stream1 , stream0 , sizeof( Bitstream ) );
   /* Do not stop here; there is some more to do. */
   stream1 -> rdptr = stream1 -> rdbfr + ( stream0 -> rdptr -
                      &( stream0 -> rdbfr[ 0 ] ) );
   return( stream1 );
}

/*>SpSc*/
/***********************************************************CommentBegin******
 *
 * -- DecodeVopSpatScalable -- Decodes the VOP information from the bitstream
 *    in spatial scalable mode
 *
 * Author :
 *   Fernando Jaureguizar (UPM)
 *
 * Created :
 *   30-JUL-1997
 *
 * Purpose :
 *    Decode the vop information from the bitstream in spatial scalable mode
 *
 * Arguments in :
 *   Bitstream *stream   pointer on the decoder bitstream structure,
 *                       should be at the right position.
 *   Int vo_id           video object id number
 *   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********/

Void DecodeVopSpatScalable(
    Bitstream *stream,
    Int vo_id,
    Trace *trace,
    Vop *curr_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;
  Int    vol_id = GetVopId(curr_vop);

  /*****
   *
   *  Free image channels of VOP and allocate the image channels
   *  for the new sizes (only necessary if arbitrary shape)
   *
   *****/

  if(GetVopShape(curr_vop))
    {
    fprintf(stderr,"Can't decode Spatial Scalability with Objects\n");
    exit(1);
    }

  /*****
   *
   *  Set local parameters and allocate local memory
   *
   *****/

  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));

  SetConstantImage(MB_mot_decis,0);
  SetConstantImage(mot_x,0);
  SetConstantImage(mot_y,0);
 
  /*****
   *
   *  Do combined or separate decoding
   *
   *****/


    if(GetVopShape(curr_vop)==0)
      {
      SetConstantImage(GetVopA(curr_vop),255);
      SetConstantImage(GetVopAuv(curr_vop),255);
      }
    if(GetVopErrorResDisable(curr_vop))
      {


	
#ifdef _DEBUG_SPSC2_
      if(tmp_cnt==0) {
        WriteVopGeneric( GetVopNextTemp(curr_vop), "Dnext_vop", "Dnext_vop", "Dnext_vop",
                        "tmpppu", 0, IO_FORMAT, IO_OVERWRITE, 0);
      } else {
        WriteVopGeneric( GetVopNextTemp(curr_vop), "Dnext_vop", "Dnext_vop", "Dnext_vop",
                        "tmpppu", tmp_cnt, IO_FORMAT, IO_APPEND, 0);
      }
      tmp_cnt++;
#endif


      
    
	DecodeVopCombMotionShapeTexture(stream,vo_id,trace,curr_vop);

/* 05.12.1997 Minhua Zhou: to avoid crash in SSP, meanwhile keep the
   TPS be unchanged. Originally pointed out by Fernando */
      }
    else
      {
      fprintf(stderr,"Can't decode Spatial Scalability with Error Resil.\n");
      exit(1);
      }
 
  /*****
   *
   *  Free local memory and return
   *
   *****/
  free((Char *)mb_type);

  FreeImage(MB_mot_decis);
  FreeImage(B_mot_decis);
  FreeImage(mot_x);
  FreeImage(mot_y);

  return;
}

/***********************************************************CommentBegin******
 *
 * -- CheckBaseVop
 *
 * Author :		
 *      Ryuji KITAURA (SHARP)
 *
***********************************************************CommentBegin******/
Int
CheckBaseVop(Vop *curr_vop)
{
  Int vop_id;
  Int ref_vop_id;
  Int scalability;
  Int base;

  scalability = GetVopScalability( curr_vop );
  ref_vop_id  = GetVopRefId( curr_vop );
  vop_id      = GetVopId( curr_vop );

  if(scalability == 0)
       base = 1;
  else base = 0;

  return(base);
}


/***********************************************************CommentBegin******
 *
 * -- SetRefVop
 *
 * Author :		
 *      Ryuji KITAURA (SHARP)
 *
 * Modified: 18.9.97 T. Aono(Sharp): Simplify by removing malloc and free in some part
 *
***********************************************************CommentBegin******/
Void
SetRefVop(Vop *ref_vop0, Vop *ref_vop1, Vop *curr_vop)
{
  Int ref_sel_code, predic_type;

  ref_sel_code = GetVopRefSelCode( curr_vop );
  predic_type  = GetVopPredictionType( curr_vop );

  /* Padding for reference vop ( BASE vop ) */
  if (ref_vop0 != NULL) {
      PutVopNextTemp(NULL, ref_vop0);
      PutVopPrevTemp(NULL, ref_vop0);
      PutVopShape( GetVopShape(curr_vop) , ref_vop0 ); 
      VopPadding(ref_vop0);
  }
  if (ref_vop1 != NULL) {
      PutVopNextTemp(NULL, ref_vop1);
      PutVopPrevTemp(NULL, ref_vop1);
      PutVopShape( GetVopShape(curr_vop) , ref_vop1 ); 
      VopPadding(ref_vop1);
  }

  /* PrevTemp Free */
  if(GetVopPrevTemp(curr_vop) != NULL){
      FreeVop(GetVopPrevTemp(curr_vop));
      PutVopPrevTemp(NULL, curr_vop);
  }

  /* for enhance frame only I or P picture */ 
  if ( predic_type == P_VOP && ref_sel_code == 1 ) {
      if(GetVopNextTemp(curr_vop) !=  NULL){
          FreeVop(GetVopNextTemp(curr_vop));
          PutVopNextTemp(NULL, curr_vop);
      }
      PutVopNextTemp( ref_vop0 , curr_vop );
  }
  /* for enhance frame B picture */ 
  else if ( predic_type == B_VOP ) {
      if ( ref_sel_code == 3 ) {
	  PutVopPrevTemp( ref_vop0 , curr_vop );
          if( GetVopNextTemp(curr_vop) !=  NULL){
	      FreeVop(GetVopNextTemp(curr_vop));
	      PutVopNextTemp(NULL, curr_vop);
          }
          PutVopNextTemp( ref_vop1 , curr_vop );
      }
      else if ( ref_sel_code == 1 ) {
          PutVopPrevTemp(GetVopNextTemp(curr_vop),curr_vop);
          PutVopNextTemp( ref_vop0 , curr_vop );

          if (ref_vop1!=NULL) {
	      FreeVop(ref_vop1);
	      ref_vop1=NULL;
          }
      }
  }
  return;
}

/***********************************************************CommentBegin******
 *
 * -- LastTimeInput
 *
 * Author :		
 *      Ryuji KITAURA (SHARP)
 *
***********************************************************CommentBegin******/
Void
LastTimeInput(Vop *curr_vop)
{
 if(CheckBaseVop(curr_vop)){
    if(last_base_decoding_time[0] < 0 || last_base_decoding_time[2] < 0) {
      last_base_decoding_time[0] = last_base_decoding_time[2];
      last_base_decoding_time[2] = CalcVopDisplayTime( curr_vop );
    }
    else{
      Int predic_type = GetVopPredictionType(curr_vop);
      if (last_base_decoding_time[1] < 0 && predic_type==B_VOP)
	last_base_decoding_time[1] = CalcVopDisplayTime( curr_vop );
      else {
	if (last_base_decoding_time[1] < 0) {
	  last_base_decoding_time[0] = last_base_decoding_time[2];
	  last_base_decoding_time[2] = CalcVopDisplayTime( curr_vop );
	}
	else {
	  last_base_decoding_time[0] = last_base_decoding_time[1];
	  last_base_decoding_time[1] = last_base_decoding_time[2];
	  if (predic_type!=B_VOP)
	    last_base_decoding_time[2] = CalcVopDisplayTime( curr_vop );
	  else
	    last_base_decoding_time[1] = CalcVopDisplayTime( curr_vop );
	}
      }
    }
  }
  else 
    last_enh_decoding_time = CalcVopDisplayTime( curr_vop );

}
/***********************************************************CommentBegin******
 *
 * -- BASEImageInput
 *
 * Author :		
 *      Ryuji KITAURA (SHARP)
 *
***********************************************************CommentBegin******/
void
BASEImageInput(Vop *curr_vop, Vop *base_output_vop[3])
{
  Int i, j=0, fg, time[3], min;

  i=0; fg=0; min=10000000;
  while (base_output_vop[i]!=NULL && i<3) i++; 
  if (i<3) j=i;
  else {
    for (i=0;i<3;i++) {
      time[i]=CalcVopDisplayTime(base_output_vop[i]);
      if (time[i]<min) {
	min=time[i];
	j=i;
      }
    }
    FreeVop(base_output_vop[j]);
    base_output_vop[j] = NULL;
  }
  base_output_vop[j]=CloneVop(curr_vop);
  TPS_base_count=j;
}


/***********************************************************CommentBegin******
 *
 * -- WriteOutputImage_TPS_for_base
 *
 * Author :		
 *      Ryuji KITAURA (SHARP)
 *
***********************************************************CommentBegin******/
Void
WriteOutputImage_TPS_for_base(Vop *base_output_vop[3],
			      Float next_display_time,
			      Int post_filter_type,
			      Int base_flag,
			      Int stop_decoding_vol[],
			      Int number_of_vols)
{
  Vop *file_vop = NULL;
  Int i;
  Int frame = -1,
      next_display_frame = TimetoFrameNumeber(next_display_time);
  Int end = 1;

  if(base_flag){
    for(i = 0; i < 3 ; i++){
      if(base_output_vop[i] != NULL){
        frame = CalcFrameNumber(base_output_vop[i]);
        if( frame == next_display_frame && GetVopWidth( base_output_vop[i] ) != 0){
	  fprintf(stderr,"   Write BASE[%d]\n",frame);
	  file_vop = PostFilter_TPS(base_output_vop[i], post_filter_type,
         			    image_width , image_height);
          WriteVopGeneric(file_vop,
			  comp_output_filename[ 0 ] ,
			  comp_output_filename[ 1 ] ,
			  comp_output_filename[ 2 ] ,
			  comp_output_filename[ 3 ] ,
			  frame,
			  IO_FORMAT , IO_APPEND ,FALSE );
          FreeVop(file_vop);
          i = 3;
	}
      }
    }
  }
  else{
    for (i = 0 ;i < number_of_vols;i++)
      if(stop_decoding_vol[i] == 0)
        end = 0;
  
    if(end == 1){
      for(i = 0; i < 3 ; i++){
        if(base_output_vop[i] != NULL){
          frame = CalcFrameNumber(base_output_vop[i]);
          if( frame > next_display_frame && GetVopWidth( base_output_vop[i] ) != 0){
	    fprintf(stderr,"oooWrite BASE[%d]\n",frame);
	    file_vop = PostFilter_TPS(base_output_vop[i], post_filter_type,
         	  		      image_width , image_height);
            WriteVopGeneric(file_vop,
			    comp_output_filename[ 0 ] ,
			    comp_output_filename[ 1 ] ,
			    comp_output_filename[ 2 ] ,
			    comp_output_filename[ 3 ] ,
			    frame,
			    IO_FORMAT , IO_APPEND ,FALSE );
            FreeVop(file_vop);
            i = 3;
	  }
        }
      }
    }
  }
  return;
 }
/***********************************************************CommentBegin******
 *
 * -- Check_TPS
 *
 * Author :		
 *      Ryuji KITAURA (SHARP)
 *
 * Modified: 15.9.97 A. Sandvand: Removed variables for Random Access
 * Modified: 16.9.97 T. Aono(Sharp): Add argument "random_access_start_time"
 *
***********************************************************CommentBegin******/
Void
Check_TPS(Int number_of_vols,
		 Bitstream *stream[],
		 Trace *trace[],
		 Int random_access_start_time,
		 Vol *vol_list)
	       
{

  Vol *next_vol;
  Int k;
  next_vol = vol_list;

  for(k=0; k<number_of_vols; k++){
      if(!temporal_scalability)
        Check_TPS_decode(stream[k],
		         next_vol,
		         random_access_start_time,
		         trace[k],
			 k);
      next_vol = GetVolNext(next_vol);
  }
}

/***********************************************************CommentBegin******
 *
 * -- Check_TPS_decode
 *
 * Author :		
 *      Ryuji KITAURA (SHARP)
 *
 * Modified: 15.9.97 A. Sandvand: Removed variables for Random Access
 * Modified: 16.9.97 T. Aono(Sharp): Add argument "random_access_start_time"
 *                                   Simplify by removing malloc and free in some part
***********************************************************CommentBegin******/
Void
Check_TPS_decode(Bitstream *stream,
		 Vol *next_vol,
		 Int random_access_start_time,
		 Trace *trace,
		 Int nvol_id)
	       
{
  Bitstream *ref_stream;
  
  Vop *tmp_vop;
  Int tmpvar;
  Int time_base = 0;
  Int time_inc  = 0;
  Int readen_bits;
  FILE *fp_TMP;
  Int bits;
  static Int start_time[MAX_NUM_VOLS][2];
  Int t0;
  Int offset;
 
  tmp_vop        = CloneVop(GetVolVop(next_vol));
  ref_stream     = clone_bitstream(stream);
  GetBitstreamPosition(&offset,stream);  	 
  tmpvar         = (Int) BitstreamShowBits(ref_stream,VOP_START_CODE_LENGTH);
  
  if (tmpvar == GROUP_START_CODE) {
    /* Modified due to N2171 Cl. 2.1.9 MW 07-APR-1998 */
    /* DecodeGOV(ref_stream,trace,tmp_vop, &readen_bits); */
    DecodeGOV(ref_stream,trace,tmp_vop, &readen_bits, NULL);
    tmpvar = (Int) BitstreamShowBits(ref_stream,VOP_START_CODE_LENGTH);
  }
  if(tmpvar == VOP_START_CODE) {
    tmpvar = (Int) BitstreamReadBits(ref_stream,VOP_START_CODE_LENGTH,"vop_start_code",trace,CODE);
    tmpvar = (Int) BitstreamReadBits(ref_stream,2,"vop_prediction_type",trace,FLAG);
    tmpvar = (Int) BitstreamReadBits(ref_stream,1,"modulo_time_base",trace,FLAG);
	  
    while(tmpvar == 1){
      tmpvar = (Int) BitstreamReadBits(ref_stream,1,"modulo_time_base",trace,FLAG);
      time_base++;
    }

   /* marker_bit (1 bit) */
    tmpvar = (Int) BitstreamReadBits(ref_stream,1,"marker_bit",trace,FLAG);

    bits = ceil(log((double)GetVolTimeIncrementResolution(next_vol))/log(2.0));
    if (bits<1) bits=1;
  
    time_inc = (Int) BitstreamReadBits(ref_stream,bits,"vop_time_increment",trace,NUM); 
  }

  t0=GetVopModTimeBase(tmp_vop);
  if (t0<0) t0=0;
  time_base=time_base+t0;
  start_time[nvol_id][0]=time_base;
  start_time[nvol_id][1]=time_inc;
  if(nvol_id!=0 && (start_time[nvol_id][0]!=start_time[nvol_id-1][0] ||
		    start_time[nvol_id][1]!=start_time[nvol_id-1][1])) {
    fprintf(stderr,"temporal_scalability is ON\n");
    temporal_scalability = 1;
    if(NULL == (fp_TMP = fopen(comp_output_filename[ 0 ],"w"))){
      fprintf(stderr,"cannot open %s\n",comp_output_filename[ 0 ]);
      exit(1);
    }
    fclose(fp_TMP);
    if(NULL == (fp_TMP = fopen(comp_output_filename[ 1 ],"w"))){
      fprintf(stderr,"cannot open %s\n",comp_output_filename[ 1 ]);
      exit(1);
    }
    fclose(fp_TMP);
    if(NULL == (fp_TMP = fopen(comp_output_filename[ 2 ],"w"))){
      fprintf(stderr,"cannot open %s\n",comp_output_filename[ 2 ]);
      exit(1);
    }
    fclose(fp_TMP);
    if(NULL == (fp_TMP = fopen(comp_output_filename[ 3 ],"w"))){
      fprintf(stderr,"cannot open %s\n",comp_output_filename[ 3 ]);
      exit(1);
    }
    fclose(fp_TMP);
  }
  
  FreeVop(tmp_vop);
  SeekBitstream(offset,stream);  	 
  free(ref_stream);
  return;
}
/***********************************************************CommentBegin******
 *
 * -- CalcFrameNumber
 *
 * Author :		
 *      Ryuji KITAURA (SHARP)
 *
***********************************************************CommentBegin******/
Int
CalcFrameNumber(Vop *curr_vop)
{
  Float display_time = CalcTime(curr_vop);
  return(TimetoFrameNumeber(display_time));
}
/***********************************************************CommentBegin******
 *
 * -- CalcTime
 *
 * Author :		
 *      Ryuji KITAURA (SHARP)
 *
***********************************************************CommentBegin******/
Float
CalcTime(Vop *curr_vop)
{
  Int modulo_time_base = GetVopModTimeBase(curr_vop);
  Float time_increment = GetVopTimeInc(curr_vop),
        display_time;
  display_time = modulo_time_base*1000 + time_increment*1000.0/(double)GetVopTimeIncrementResolution(curr_vop);
  return(display_time);
}
/***********************************************************CommentBegin******
 *
 * -- TimetoFrameNumeber
 *
 * Author :		
 *      Ryuji KITAURA (SHARP)
 *
***********************************************************CommentBegin******/
Int
TimetoFrameNumeber(Float display_time)
{
  Int frame;
  Int display_time_int = (Int)(display_time * 1000.0);
  Int Time_TPS_int     = (Int)(1000.0/display_framerate_TPS * 1000.0);
  frame = (Int)( display_time_int / Time_TPS_int);  
  return(frame);
}
/***********************************************************CommentBegin******
 *
 * -- SetBGCImage
 *
 * Author :		
 *      Ryuji KITAURA (SHARP)
 *
***********************************************************CommentBegin******/
Void
SetBGCImage(Vop *curr_vop)
{
  Vop *tmp_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);
            tmp_vop = CloneVop(curr_vop);
            if (GetVopPrevTemp(tmp_vop)!=NULL)
                FreeVop(GetVopPrevTemp(tmp_vop));
            PutVopPrevTemp(NULL,tmp_vop);
            PutVopNextTemp(tmp_vop,curr_vop);
  }
  if(CheckBaseVop(curr_vop))
      fprintf(stderr,"[B]frame[%d] NOT decoding\n",CalcFrameNumber(curr_vop));
  else
      fprintf(stderr,"[E]frame[%d] NOT decoding\n",CalcFrameNumber(curr_vop));
}     
/***********************************************************CommentBegin******
 *
 * -- search_vop_for_bgc
 *
 * Author :		
 *      Tomoko Aono (SHARP)
 *
***********************************************************CommentBegin******/
Void 
search_vop_for_bgc(Vop *vop_list[],
		   Int vop_exist[],
		   Vop *curr_vop,
		   Int vop_display_time[])
{
  Int time_ref[3], time[3], dtime_f[3], dtime_b[3],
      time_enh, i, k, kk[2], minf, minb;
  Int count   = 0,
      bgcfor  = 0,  
      bgcback = 0,
      kfor    = 0,
      kback   = 0;
  
  vop_exist[0] = vop_exist[1] = 0;
  
  for (i = 0; i < 3 ; i++) {
    if (base_output_vop[i] != NULL) {
      time_ref[i] = CalcVopDisplayTime(base_output_vop[i]); 
      time[i]     = (Int)(0.001 + time_ref[i] * 1000.0 /
		    (Double)GetVopTimeIncrementResolution(base_output_vop[i]));
      time_ref[i] *= (Int)( ((Double)GetVopTimeIncrementResolution(curr_vop) / 
		     (Double)GetVopTimeIncrementResolution(base_output_vop[i])));
      count++;
    }
    else{
      time_ref[i] = -1;
      time[i]     = -1;
    }
  }
  
  time_enh = CalcVopDisplayTime(curr_vop); 
  time_enh = (Int)(0.001+time_enh*1000.0/(Double)GetVopTimeIncrementResolution(curr_vop));
  if (count == 0) { /* no base vop exists. */
    printf("error base vop for bgc! : scale_dec.c\n");
    return;
  }
  else if (count == 1) { /* 1 base vop exists! */
    for (i = 0;i < 3; i++)
      if (time[i] != -1) {
	if (time[i] < time_enh) {
	  kfor = i;
	  bgcfor = 1;
	}
	break;
      }
    if (bgcfor == 0) {
      printf("error base vop for bgc! : scale_dec.c\n");
      return;
    }
  }
  else if (count == 2) { /* 2 base vop exists! */
    for (i = 0; i < 3; i++) {
      if (time[i] != -1) {
	if (time[i] < time_enh)      bgcfor++;
	else if (time[i] > time_enh) bgcback++;
      }
    }
    if (bgcfor == 0) printf("error base vop for bgc! : scale_dec.c\n");
    else if (bgcfor == 1) { /* base->enh->base */
      for (i = 0; i < 3; i++) {
	if (time[i] != -1) {
	  if (time[i] < time_enh)      kfor  = i;
	  else if (time[i] > time_enh) kback = i;
	}
      }
    }
    else if (bgcfor == 2) { /* base->enh */
      k = 0;
      for (i = 0; i < 3; i++)
	if (time[i]!= -1)
	  kk[k++] = i;
      if (time[kk[0]] >= time[kk[1]])   kfor = kk[0];
      else if (time[kk[0]]<time[kk[1]]) kfor = kk[1];
    }
  }
  else { /* 3 base exists! */
    for (i = 0; i < 3; i++) {
      dtime_f[i] = time_enh - time[i];
      dtime_b[i] = time[i]  - time_enh;
    }
    minf = 100000;
    minb = 100000;
    for (i = 0; i < 3; i++) {
      if (dtime_f[i] > 0 && dtime_f[i] < minf) {
	minf = dtime_f[i];
	kfor = i;
	bgcfor++;
      }
      else if (dtime_b[i] > 0 && dtime_b[i] < minb) {
	minb  = dtime_b[i];
	kback = i;
	bgcback++;
      }
    }
  }
  vop_list[0] = NULL;
  vop_list[1] = NULL; 
  if (bgcfor != 0) {
    vop_list[0]         = CloneVop(base_output_vop[kfor]);
    vop_display_time[0] = time[kfor];
/*    prev_ref            = time_ref[kfor]; */
    vop_exist[0]        = 1;
  }
  if (bgcback != 0) {
    vop_list[1]         = CloneVop(base_output_vop[kback]);
    vop_display_time[1] = time[kback];
/*    next_ref            = time_ref[kback];  */
    vop_exist[1]        = 1;
  }
  return;
}


/***********************************************************CommentBegin******
 *
 * -- preview_gov_header
 *
 * Author :		
 *      Tomoko Aono (SHARP)
 *
***********************************************************CommentBegin******/
Void preview_gov_header(Bitstream *stream, Trace *trace) {
  Int tmpvar;

  tmpvar = (Int) BitstreamReadBits(stream,32,"group_start_code",trace,CODE);
  tmpvar = (Int) BitstreamReadBits(stream,5,"Hour",trace,NUM);
  tmpvar = (Int) BitstreamReadBits(stream,6,"Minute",trace,NUM);
  tmpvar = (Int) BitstreamReadBits(stream,1,"Marker_bit",trace,NUM);
  tmpvar = (Int) BitstreamReadBits(stream,6,"Second",trace,NUM);
  tmpvar = (Int) BitstreamReadBits(stream,1,"closed_gov",trace,NUM);
  tmpvar = (Int) BitstreamReadBits(stream,1,"broken_link",trace,NUM);
  return;
 } 

/***********************************************************CommentBegin******
 *
 * -- preview_vop_header
 *
 * Author :		
 *      Tomoko Aono (SHARP)
 *
***********************************************************CommentBegin******/
Int preview_vop_header(Bitstream *stream, Trace *trace)
{
  Bitstream *ref_stream;
  Int tmpvar;
  Int offset;
  
  ref_stream = clone_bitstream(stream);
  GetBitstreamPosition(&offset,stream);  	 
  	 
  tmpvar = (Int) BitstreamShowBits(ref_stream,VOP_START_CODE_LENGTH);
  if (tmpvar == GROUP_START_CODE) {
    preview_gov_header(ref_stream,trace);
    tmpvar = (Int) BitstreamShowBits(ref_stream,VOP_START_CODE_LENGTH);
  }  
  if (tmpvar == VOP_START_CODE) {
    tmpvar=(Int)BitstreamReadBits(ref_stream,VOP_START_CODE_LENGTH,"vop_start_code",trace,CODE);
    tmpvar=(Int)BitstreamReadBits(ref_stream,2,"vop_prediction_type",trace,FLAG);
  }
  else tmpvar= -1;
  SeekBitstream(offset,stream);  	 
  free(ref_stream);
  return(tmpvar);
}
/***********************************************************CommentBegin******
 *
 * -- FreeShapeVop
 *
 * Author :		
 *      Ryuji KITAURA (SHARP)
 *
 * Modified: 18.9.97 T. Aono(Sharp): Simplify by removing malloc and free in some part
 *
***********************************************************CommentBegin******/
Void FreeShapeVop()
{
  if ( back_shape_vop != ( Vop * )NULL ) FreeVop( back_shape_vop );
  if ( for_shape_vop  != ( Vop * )NULL ) FreeVop( for_shape_vop );
}
