/******************************************************************************
 *                                                                          
 * This software module was originally developed by 
 *
 * Cecile Dufour (LEP / ACTS-MoMuSys)
 *
 * and edited by 
 *
 *
 * 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: sprite_enc_piece.c
 *
 * Author :		
 *	Cecile Dufour (Philips LEP/ dufour@lep.research.philips.com)
 *
 * Created :		
 *	10-08.97
 *                                                                         
 * Description: routines for the encoding of sprite_pieces
 * -- InitForEncodeSprite: various initilizations for sprites (Static, Dyn., GMC) 
 * -- InitForEncodeStaticSprite: various initilizations for static sprites 
 * -- EncodeBasicSprite -- Encode as I_VOP a basic static sprite
 * -- EncodeSpritePiece -- Encode as I_VOP pieces of a low latency static sprite
 * -- BitstreamPutSpriteVopHeader -- Writes first fields of the sprite pieces header syntax
 * -- CheckSpriteTransmitMode -- First global check of the static SPRITE encoding
 * -- FindNextSpritePieceCoord --  Manages the encoding of the whole static sprite
 * -- BlockPSNR_Y -- Provides PSNR_Y value on macroblock basis
 *
 * Notes:  
 *
 * Modified:
 *      27.11.97  M. Eckert: Changes for independent frame type rate control
 *      16.01.98  M. Eckert: Changes depending on parameter-ctl-string 
 *
 *                          
 ***********************************************************HeaderEnd*********/

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

#include <math.h>
#include "vm_vop_code.h"
#include "vm_enc_defs.h"
#include "io_generic.h"
#include "mom_bitstream_i.h"
#include "mom_putbits.h"
#include "sprite_enc_piece.h"
#include "sprite_util.h"
#include "vm_compos.h"
#include "vm_config.h"
#include "mot_padding.h"
#include "vm_vop_bound.h"

/***********************************************************CommentBegin******
 *
 * -- InitForEncodeSprite -- Initialization for SPRITES (Static,dynmaic,GMC)
 *
 * Author :		
 *	Cecile Dufour (Philips LEP/ dufour@lep.research.philips.com)
 *
 * Created :		
 *	14-04.98
 *
 * Purpose :
 *	General Initializations		
 * 
 * Arguments in : 
 *	Vol_Config
 *
 * Arguments in/out :
 *	vol_config: the sprite attached to the vol_config, is updated	
 *
 * Arguments out :	
 *
 * Return values :	
 *
 * Side effects :	
 *
 * Description :	
 *
 * See also :
 *	vm_config.c
 *
 * Modified :		
 *
 ***********************************************************CommentEnd********/
Void
InitForEncodeSprite( VolConfig *vol_config)
	     
{
  Vop	*sprite, *bounded_sprite;
  Int	vop_has_content;
  Int	sprite_usage = GetVolConfigSpriteUsage(vol_config); 
  Int	sprite_shape = GetVolConfigSpriteShape(vol_config); 
  Int	sprite_left_edge = GetVolConfigSpriteLeftEdge(vol_config);
  Int	sprite_top_edge = GetVolConfigSpriteTopEdge(vol_config);
  Int	sprite_hdim = GetVolConfigSpriteHdim(vol_config);
  Int	sprite_vdim = GetVolConfigSpriteVdim(vol_config);
  Int	no_of_sprite_points = GetVolConfigNoOfSpritePoints(vol_config);
  TrajPoint	*ref_point_coord = NULL;
  Sprite_motion	*prev_warp_param=NULL;


if (no_of_sprite_points) 
	{
	ref_point_coord = (TrajPoint *) 
			emalloc(no_of_sprite_points*sizeof(TrajPoint));
	PutVolConfigRefPointCoord(ref_point_coord,vol_config);
	}

if (sprite_usage != GMC_SPRITE) 
           {
	  sprite = AllocVop(sprite_hdim ,sprite_vdim); 
	  
	  /* shape of sprite */
	  PutVopShape(sprite_shape,sprite);
	  if (sprite_shape == RECTANGULAR)
		SetConstantImage(GetVopA(sprite),BINARY_ALPHA);	
	  else
		if(sprite_shape == GREY_SCALE)
			PutVopBinaryShape(!BINARY,sprite);
		else
			PutVopBinaryShape(BINARY,sprite);
           }
          else
	      sprite = SallocVop(); 
			

	if (sprite_usage == STATIC_SPRITE)
		PutVolConfigWarpParamCounter(-1,vol_config);
	else
		{
		prev_warp_param = (Sprite_motion *) emalloc(sizeof(Sprite_motion));
		prev_warp_param->a1 = 1; 
		prev_warp_param->a2 = 0; 
		prev_warp_param->a3 = 0; 
		prev_warp_param->a4 = 0; 
		prev_warp_param->a5 = 1; 
		prev_warp_param->a6 = 0; 
		prev_warp_param->a7 = 0; 
		prev_warp_param->a8 = 0; 
		PutVolConfigPrevWarpParam(prev_warp_param,vol_config);
		PutVolConfigWarpParamCounter(0,vol_config);
		}

	if (sprite_usage == STATIC_SPRITE) 
		{
		ReadVopGeneric(GetVolConfigSpriteY(vol_config),
			GetVolConfigSpriteU(vol_config),
			GetVolConfigSpriteV(vol_config),
			GetVolConfigSpriteA(vol_config),
			0,
			IO_FORMAT,
			sprite);
				
  /* Need to extract bounded sprite from sprite read in from disk */
  /* Calc. width, height, horizontal/vertical spatial
     reference, shape of vop (REACTANGLE or ARBITRARY),
     and the type of alpha map (BINARY or NON-BINARY).
     Also extract relevant image data */

		if (sprite_shape == RECTANGULAR)
			SetConstantImage(GetVopA(sprite),BINARY_ALPHA);

		bounded_sprite = GetVopBounded(sprite,1,1,&vop_has_content);
		PutVolConfigSpriteHdim(GetVopWidth(bounded_sprite),vol_config);
		PutVolConfigSpriteVdim(GetVopHeight(bounded_sprite),vol_config);
		SubsampleAlphaMap(GetVopA(bounded_sprite),
					GetVopAuv(bounded_sprite),
					GetVopShape(bounded_sprite));
		FreeVop(sprite);
		PutVolConfigOriSprite(bounded_sprite, vol_config);

		sprite = AllocVop(GetVopWidth(bounded_sprite), 
						GetVopHeight(bounded_sprite));

		if ( GetVopHorSpatRef(bounded_sprite)>0)
			{
			sprite_left_edge += GetVopHorSpatRef(bounded_sprite);
  			PutVolConfigSpriteLeftEdge(sprite_left_edge,vol_config);
			}
		if ( GetVopVerSpatRef(bounded_sprite)>0)
			{
			sprite_top_edge += GetVopVerSpatRef(bounded_sprite);
  			PutVolConfigSpriteTopEdge(sprite_top_edge,vol_config);
			}

		PutVopHorSpatRef(0,sprite);
		PutVopVerSpatRef(0,sprite);
		PutVopSpriteLeftEdge(sprite_left_edge,sprite);
		PutVopSpriteTopEdge(sprite_top_edge,sprite);

		/* shape of sprite */
		PutVopShape(sprite_shape,sprite);
		if (sprite_shape == RECTANGULAR)
			SetConstantImage(GetVopA(sprite),BINARY_ALPHA);	
		else
  			{
			SetConstantImage(GetVopA(sprite),0);	
			if(sprite_shape == GREY_SCALE)
				PutVopBinaryShape(!BINARY,sprite);
			else
				PutVopBinaryShape(BINARY,sprite);
			}
		SetConstantImage(GetVopY(sprite),0); 
		SetConstantImage(GetVopU(sprite),0); 
		SetConstantImage(GetVopV(sprite),0);
		PutVolConfigSprite(sprite, vol_config);


	if (GetVolConfigLowLatencySpriteEnable(vol_config)==0)
		PutVolConfigCheckStaticSpritePrediction(0,vol_config);
	else
		PutVolConfigCheckStaticSpritePrediction(1,vol_config);
	PutVolConfigSpriteTransmitMode(PIECE, vol_config);
	} /* STATIC CASE */

} /* InitForEncodeSprite */

/***********************************************************CommentBegin******
 *
 * -- InitForEncodeLowLatencyStaticSprite -- Initialization for LL STATIC SPRITES
 *
 * Author :		
 *	Cecile Dufour (Philips LEP/ dufour@lep.research.philips.com)
 *
 * Created :		
 *	14-04.98
 *
 * Purpose :
 *	General Initializations		
 * 
 * Arguments in : 
 *	Vol_Config
 *
 * Arguments in/out :
 *	vol_config: arrays for low latency are initialized	
 *
 * Arguments out :	
 *
 * Return values :	
 *
 * Side effects :	
 *
 * Description :	
 *
 * See also :
 *	vm_config.c
 *
 * Modified :		
 *
 ***********************************************************CommentEnd********/
Void
InitForEncodeLowLatencyStaticSprite( VolConfig *vol_config)
	     
{
  Int	*tab_transmit=NULL;
  SInt	*tab_QP_store=NULL;
  Int	*tab_DQUANT_store=NULL;
  Int	mb_x, mb_y, numblocks_x, numblocks_y ;


numblocks_x = (GetVolConfigSpriteHdim(vol_config)/16); 
numblocks_y = (GetVolConfigSpriteVdim(vol_config)/16);

tab_transmit = (Int *)malloc(numblocks_x*numblocks_y * sizeof(Int));
tab_QP_store = (SInt  *)calloc(numblocks_x*numblocks_y, sizeof(SInt));
tab_DQUANT_store = (Int  *)calloc(numblocks_x*numblocks_y, sizeof(Int));
PutVolConfigSpriteTabTransmit(tab_transmit, vol_config);
PutVolConfigSpriteTabQPStore(tab_QP_store, vol_config);
PutVolConfigSpriteTabDQUANTStore(tab_DQUANT_store, vol_config);

for (mb_y=0 ; mb_y<numblocks_y ; mb_y++ )
for (mb_x=0 ; mb_x<numblocks_x ; mb_x++ )
	tab_transmit[mb_y*numblocks_x+mb_x] = NON_TRANSMIT_BLOCK;



} /* InitForEncodeStaticSprite */

/***********************************************************CommentBegin******
 *
 * -- EncodeBasicSprite -- Encode as I_VOP a basic static sprite
 *
 * Author :		
 *	Cecile Dufour (Philips LEP/ dufour@lep.research.philips.com)
 *
 * Created :		
 *	10-08.97
 *
 * Purpose :		
 *	This function:  * calls the writing of the sprite header syntax
 *				(calls BitstreamPutSpritePieceHeader)
 *			* encode as I_VOP the basic static sprite
 *				(calls VopProcess)	
 * 
 * Arguments in : 
 *	Vol_Config
 *	vo_id, vol_id: current vo and vol id	
 *	num_bits: records the number of bits neccessary
 *	vo_config_list (required in VopProcess)
 *	rc_type : required for regulation
 *
 * Arguments in/out :
 *	rec_sprite: the sprite attached to the vol_config, is updated	
 *
 * Arguments out :	
 *
 * Return values :	
 *
 * Side effects :	
 *
 * Description :	
 *	The piece vop header (start_code, vop_ID, etc.) is first
 *	called, then vop_process for I_VOP encoding
 *
 * See also :
 *	BitstreamPutVOLs
 *
 * Modified :		
 *      27.11.97  M. Eckert: Changes for independent frame type rate control
 *	14.04.98  C. Dufour: Changes to cope with basic sprite syntax
 *
 ***********************************************************CommentEnd********/
Void
EncodeBasicSprite( VolConfig *vol_config,
                       Int vo_id, 
                       Int vol_id,
                       BitCount num_bits[MAX_NUM_VOS][MAX_NUM_VOLS],
                       VOConfig *vo_config_list,
                       Int rc_type)
	     
{
  Vop		*ori_sprite, *rec_sprite;
  Vop		*ori_sprite_piece, *rec_sprite_piece;

/* Set up reconstructed vop */
rec_sprite = GetVolConfigSprite(vol_config);
ori_sprite = GetVolConfigOriSprite(vol_config);
PutVopPredictionType(I_VOP, ori_sprite);

/* Write Vop Header bitstream to disk */
	num_bits[vo_id][vol_id].sprite_piece = 0;


ori_sprite_piece = AllocVop(GetVolConfigSpriteHdim(vol_config),GetVolConfigSpriteVdim(vol_config));
CopyVopNonImageField(rec_sprite,ori_sprite_piece);
PutVopWidth(GetVolConfigSpriteHdim(vol_config), ori_sprite_piece);
PutVopHeight(GetVolConfigSpriteVdim(vol_config),  ori_sprite_piece);
PutVopHorSpatRef(0, ori_sprite_piece);
PutVopVerSpatRef(0, ori_sprite_piece);
PutVopShape(GetVopShape(ori_sprite), ori_sprite_piece);
PutVopBinaryShape(GetVopBinaryShape(ori_sprite),ori_sprite_piece);
PutVopPredictionType(I_VOP, ori_sprite_piece);
GetSpritePieceInSprite( ori_sprite_piece, ori_sprite, 0,0);

fprintf(stdout,"\t\tIntra Quantizer : %d\n", GetVolConfigIntraQuantizer(vol_config));
      rec_sprite_piece = VopProcess( ori_sprite_piece,
      					NULL, /* prev_vop */
					NULL, /* prev_rec_vop */
					NULL, /* next_vop */
					NULL, /* next_rec_vop */
					0,    /* time */
					vol_config,
					1,    /* vop_has_content */
					vo_id, 
					0,0, /* TRB, TRD */
					vo_config_list,
					rc_type,
				        0, /* rc_algorithm, hjlee */
					num_bits,
					NULL, /* no_padding_vop */
					0);    /* temporal scalability */

PutSpritePieceInSprite( rec_sprite_piece, rec_sprite, 0,0);

PutVolConfigCheckStaticSpritePrediction(1,vol_config);
				
FreeVop(ori_sprite_piece);
FreeVop(rec_sprite_piece);

} /* EncodeBasicSprite */

/***********************************************************CommentBegin******
 *
 * -- EncodeSpritePiece -- Encode as I_VOP pieces of a low latency static sprite
 *
 * Author :		
 *	Cecile Dufour (Philips LEP/ dufour@lep.research.philips.com)
 *
 * Created :		
 *	10-08.97
 *
 * Purpose :		
 *	This function:  * calls the writing of a sprite piece header syntax
 *				(calls BitstreamPutSpritePieceHeader)
 *			* encode as I_VOP the different pieces of a static sprite
 *				(calls VopProcess)	
 * 
 * Arguments in : 
 *	Vol_Config
 *	vo_id, vol_id: current vo and vol id	
 *	piece_width, piece_height: size of the sprite_piece (expressed divided by 16)
 *	piece_xoffset, piece_yoffset: location in the sprite of the sprite piece (idem)
 *	num_bits: records the number of bits neccessary
 *	vo_config_list (required in VopProcess)
 *	rc_type : required for regulation
 *
 * Arguments in/out :
 *	rec_sprite: the sprite attached to the vol_config, is updated	
 *
 * Arguments out :	
 *
 * Return values :	
 *
 * Side effects :	
 *
 * Description :	
 *	The piece vop header (size and position in MB number) is first
 *	called, then vop_process is performed addressing
 *	different mode: update or piece, encoded as I_VOP or P_VOP
 *	respectively. Note: no shape is encoded in update pieces.
 *
 * See also :
 *	BitstreamPutVopHeader
 *
 * Modified :		
 *      27.11.97  M. Eckert: Changes for independent frame type rate control
 *
 ***********************************************************CommentEnd********/

Void
EncodeSpritePiece( VolConfig *vol_config,
                   Int vo_id, 
                   Int vol_id,
                   Int piece_width,
                   Int piece_height,
                   Int piece_xoffset,
                   Int piece_yoffset,
                   BitCount num_bits[MAX_NUM_VOS][MAX_NUM_VOLS],
                   VOConfig *vo_config_list,
                   Int rc_type)
	     
{
  Vop		*ori_sprite, *rec_sprite;
  Vop		*ori_sprite_piece=NULL, *rec_sprite_piece=NULL;
  Vop		*prev_sprite_piece=NULL;
  Int 		*tab_transmit, *tab_piece_transmit;
  SInt		*tab_QP_store, *tab_piece_QP_store;
  Int		*tab_DQUANT_store, *tab_piece_DQUANT_store;
  Int		numblocks_x, numblocks_y, mb_x, mb_y;
  Int		prediction_type;
  Float		BlockSNR;
  Int		val_prev;
  Int		piece_quant;

tab_transmit = GetVolConfigSpriteTabTransmit(vol_config);
tab_QP_store = GetVolConfigSpriteTabQPStore(vol_config);
tab_DQUANT_store = GetVolConfigSpriteTabDQUANTStore(vol_config);
numblocks_x = GetVolConfigSpriteHdim(vol_config)/16;
numblocks_y = GetVolConfigSpriteVdim(vol_config)/16;

/* Set up reconstructed vop */
rec_sprite = GetVolConfigSprite(vol_config);
ori_sprite = GetVolConfigOriSprite(vol_config);

if (GetVolConfigSpriteTransmitMode(vol_config)==UPDATE)
  prediction_type = SPRITE_UPDATE;
else
  prediction_type = SPRITE_PIECE;

	

if (GetVolConfigSpriteTransmitMode(vol_config)==UPDATE)
	piece_quant = GetVolConfigQuantizer(vol_config);
else
	piece_quant = GetVolConfigIntraQuantizer(vol_config);


/* Write Vop Header bitstream to disk */
num_bits[vo_id][vol_id].sprite_piece = BitstreamPutSpritePieceHeader(vo_id,vol_id,
						piece_quant,
						piece_width,
						piece_height,
						piece_xoffset,
						piece_yoffset);

ori_sprite_piece = AllocVop(piece_width*16, piece_height*16);
CopyVopNonImageField(rec_sprite,ori_sprite_piece);
PutVopHorSpatRef(0, ori_sprite_piece);
PutVopVerSpatRef(0, ori_sprite_piece);
PutVopWidth(piece_width*16,ori_sprite_piece);
PutVopHeight(piece_height*16,ori_sprite_piece);
PutVopShape(GetVopShape(ori_sprite), ori_sprite_piece);
PutVopBinaryShape(GetVopBinaryShape(ori_sprite),ori_sprite_piece);
PutVopPredictionType(prediction_type, ori_sprite_piece);

tab_piece_transmit = tab_transmit+piece_yoffset*numblocks_x+piece_xoffset;
tab_piece_QP_store = tab_QP_store+piece_yoffset*numblocks_x+piece_xoffset;
tab_piece_DQUANT_store = tab_DQUANT_store+piece_yoffset*numblocks_x+piece_xoffset;
PutVopSpriteTabTransmit(tab_piece_transmit,ori_sprite_piece);
PutVopSpriteTabQPStore(tab_piece_QP_store,ori_sprite_piece);
PutVopSpriteTabDQUANTStore(tab_piece_DQUANT_store,ori_sprite_piece);


GetSpritePieceInSprite( ori_sprite_piece, ori_sprite, piece_xoffset*16, piece_yoffset*16);

if (GetVolConfigSpriteTransmitMode(vol_config)==UPDATE)
  {
  prev_sprite_piece = AllocVop(piece_width*16, piece_height*16);
  PutVopHorSpatRef(0, prev_sprite_piece);
  PutVopVerSpatRef(0, prev_sprite_piece);
  PutVopShape(GetVopShape(ori_sprite), prev_sprite_piece);
  PutVopBinaryShape(GetVopBinaryShape(ori_sprite),prev_sprite_piece);
  GetSpritePieceInSprite( prev_sprite_piece, rec_sprite, piece_xoffset*16, piece_yoffset*16);
  PutVolConfigQuantizer(piece_quant,vol_config);
  VopPadding(prev_sprite_piece);
  }
else /* PIECE */
  PutVolConfigIntraQuantizer(piece_quant, vol_config);

PutVolConfigCheckStaticSpritePrediction(0,vol_config);

if (GetVolConfigSpriteTransmitMode(vol_config)==UPDATE)
	fprintf(stdout,"\t\tInter Quantizer : %d\n", piece_quant);
else
	fprintf(stdout,"\t\tIntra Quantizer : %d\n", piece_quant);
	
      rec_sprite_piece = VopProcess( ori_sprite_piece,
      					prev_sprite_piece, /* prev_vop */
					prev_sprite_piece, /* prev_rec_vop */
					NULL, /* next_vop */
					NULL, /* next_rec_vop */
					0,    /* time */
					vol_config,
					1,    /* vop_has_content */
					vo_id, 
					0,0, /* TRB, TRD */
					vo_config_list,
					rc_type,
				        0, /* rc_algorithm, hjlee */
					num_bits,
					NULL, /* no_padding_vop */
					0);    /* temporal scalability */

if  (prediction_type == SPRITE_PIECE)
	prediction_type = I_VOP;
if  (prediction_type == SPRITE_UPDATE)
	prediction_type = P_VOP;


PutSpritePieceInSprite2( rec_sprite_piece, rec_sprite, 
		piece_xoffset*16, piece_yoffset*16, tab_transmit, prediction_type);

for (mb_y = piece_yoffset ; mb_y < piece_yoffset+piece_height ; mb_y++)
for (mb_x = piece_xoffset ; mb_x < piece_xoffset+piece_width  ; mb_x++)
	{
	BlockSNR = BlockPSNR_Y(mb_x-piece_xoffset,mb_y-piece_yoffset,ori_sprite_piece ,rec_sprite_piece);
	val_prev = tab_transmit[mb_y*numblocks_x+mb_x];
	if (prediction_type==I_VOP)
	  if (tab_transmit[mb_y*numblocks_x+mb_x]==1)
	    if (BlockSNR<GetVolConfigSpriteSNRthreshold(vol_config))
		tab_transmit[mb_y*numblocks_x+mb_x] = BLOCK_UPDATE_TO_TRANSMIT;
	    else
		tab_transmit[mb_y*numblocks_x+mb_x] = BLOCK_TRANSMIT_END;
	if (prediction_type==P_VOP)
	if (tab_transmit[mb_y*numblocks_x+mb_x]==BLOCK_UPDATE_TO_TRANSMIT&&val_prev==BLOCK_UPDATE_TO_TRANSMIT)
		tab_transmit[mb_y*numblocks_x+mb_x] = BLOCK_TRANSMIT_END;
/*	  if (BlockSNR<GetVolConfigSpriteSNRthreshold(vol_config))
		tab_transmit[mb_y*numblocks_x+mb_x] = BLOCK_UPDATE_TO_TRANSMIT;
	    else
		tab_transmit[mb_y*numblocks_x+mb_x] = BLOCK_TRANSMIT_END;*/
	
	}

FreeVop(ori_sprite_piece);
FreeVop(rec_sprite_piece);
if (GetVolConfigSpriteTransmitMode(vol_config)==UPDATE)
  FreeVop(prev_sprite_piece);
PutVolConfigCheckStaticSpritePrediction(1,vol_config);

} /* EncodeSpritePiece() */



/***********************************************************CommentBegin******
 *
 * -- BitstreamPutSpriteVopHeader -- 
 *
 * Author :		
 *	Cecile Dufour (Philips LEP/ dufour@lep.research.philips.com)
 *
 * Created :		
 *	10-08-97
 *
 * Purpose :		
 *	Writes first fields of the sprite pieces header syntax 
 * Arguments in : 	
 *			vo_id, vol_id
 *			vop_quant
 *			piece_width,
 *			piece_height,
 *			piece_xoffset,
 *			piece_yoffset
 *
 * Arguments in/out :	
 *
 * Arguments out :	
 *
 * Return values :	
 *	UInt num_bits - number of bits written
 *
 * Side effects :	
 *
 * Description :	
 *	The vop header (all piece_*) is first
 *	written to an intermediate integer level bitstream data structure.
 *	This intermediate bitstream data structure is then written to disk.
 *
 * See also :
 *	mom_bitstream.c
 *
 * Modified :		
 *
 ***********************************************************CommentEnd********/
 
UInt
BitstreamPutSpritePieceHeader(Int vo_id,
					Int vol_id,
					Int vop_quant,
					Int piece_width,
					Int piece_height,
					Int piece_xoffset,
					Int piece_yoffset)
{
	Image	*buffer;
	UInt	num_bits;
	
	/* Set up intermediate integer level data structure */
	buffer = BitstreamInit();
	
	/* 
	 *
	 * Write all syntax fields in vop header to data structure
	 *
	 */
	BitstreamPutBits(buffer,vop_quant,5);
	BitstreamPutBits(buffer,piece_width,9); 
	BitstreamPutBits(buffer,piece_height,9); 
	BitstreamPutBits(buffer,1,1);  /* Marker Bit */
	BitstreamPutBits(buffer,piece_xoffset,9); 
	BitstreamPutBits(buffer,piece_yoffset,9); 

	/*
	 *
	 * Write intermediate bitstream data structure to disk
	 *
	 */
	num_bits = BitstreamPut(buffer,vo_id, vol_id);

	/* No longer require the intermediate data structure */
	BitstreamFree(buffer);
	
	return(num_bits);
}

/***********************************************************CommentBegin******
 *
 * -- CheckSpriteTransmitMode -- 
 *
 * Author :		
 *	Cecile Dufour (Philips LEP/ dufour@lep.research.philips.com)
 *
 * Created :		
 *	10-08-97
 *
 * Purpose : global check of the static SPRITE encoding		
 * 
 * Arguments in : 	
 *
 * Arguments in/out :	
 *
 * Arguments out :	
 *
 * Return values :	
 *	Either STOP, PAUSE or UPDATE 
 *
 * Side effects :	
 *
 * Description :	
 *
 * See also :
 *
 * Modified :		
 *
 ***********************************************************CommentEnd********/


Void
CheckSpriteTransmitMode(VolConfig *vol_config)

{
Int	*tab_transmit;
Int	numblocks_x, numblocks_y;
Int	MB_nb_X, MB_nb_Y;
Int	state_return;


numblocks_x = GetVolConfigSpriteHdim(vol_config)/16;
numblocks_y = GetVolConfigSpriteVdim(vol_config)/16;

tab_transmit = GetVolConfigSpriteTabTransmit(vol_config);

state_return = STOP;
for (MB_nb_Y=0 ; MB_nb_Y<numblocks_y ; MB_nb_Y++ )
for (MB_nb_X=0 ; MB_nb_X<numblocks_x ; MB_nb_X++ )
	if (tab_transmit[MB_nb_Y*numblocks_x+MB_nb_X]!=BLOCK_TRANSMIT_END)
		{
/*		state_return = PAUSE;*/
		state_return = GetVolConfigSpriteTransmitMode(vol_config);
		break;
		}

PutVolConfigSpriteTransmitMode(state_return, vol_config);
if (state_return==STOP) printf("Transmit Mode = STOP\n");
}

/***********************************************************CommentBegin******
 *
 * -- FindNextSpritePieceCoord -- 
 *
 * Author :		
 *	Cecile Dufour (Philips LEP/ dufour@lep.research.philips.com)
 *
 * Created :		
 *	10-08-97
 *
 * Purpose :		
 *	Manages PIECE/UPDATE/PAUSE and STOP fields for sprite pieces
 * 
 * Arguments in : 	
 *
 * Arguments in/out :	
 *
 * Arguments out :	
 *
 * Return values :	
 *	size and location of the sprite piece to transmit
 *	Also, gives the types of piece, either PAUSE, UPDATE, or PIECE 
 *
 * Side effects :	
 *
 * Description :
 *
 * See also :
 *
 * Modified :		
 *
 ***********************************************************CommentEnd********/


Void
FindNextSpritePieceCoord(Vop *vop, VolConfig *vol_config,
				Int *piece_width,
				Int *piece_height,
				Int *piece_xoffset,
				Int *piece_yoffset)
{
Int	*tab_transmit;
Int	first_time;
Int	numblocks_x, numblocks_y;
Int	MB_nb_X, MB_nb_Y, start_X, start_Y;
Int	min_MB_X, max_MB_X, min_MB_Y, max_MB_Y;
Int	state_return;
Int	MB_nb_X_min, MB_nb_X_max, MB_nb_Y_min, MB_nb_Y_max;

Int 	i,j, ii, jj, u,v;
Sprite_motion *warp_param;
Vop	*sprite;
Double	NX, NY, X, Y;
Int	posX[2][2], posY[2][2];

warp_param = GetVopWarpParam(vop);
sprite = GetVopSprite(vop);
numblocks_x = GetVopSpriteHdim(vop)/16;
numblocks_y = GetVopSpriteVdim(vop)/16;
*piece_width = *piece_height = *piece_xoffset = *piece_yoffset = 0;


CheckSpriteTransmitMode(vol_config);

if (GetVolConfigSpriteTransmitMode(vol_config)!=STOP)
{

tab_transmit = GetVolConfigSpriteTabTransmit(vol_config);
state_return = PAUSE;

/*NEED TO COMPUTE THE POSITION OF THE FOUR CORNERS */
for (j=0, v=0 ; j<GetVopHeight(vop) ; j+=GetVopHeight(vop)-1, v++)
for (i=0, u=0 ; i<GetVopWidth(vop)  ; i+=GetVopWidth(vop) -1, u++) 
	{
	ii = i+GetVopHorSpatRef(vop);
	jj = j+GetVopVerSpatRef(vop);

	X = (warp_param->a1*(Double)ii + warp_param->a2*(Double)jj+warp_param->a3)/
      		(warp_param->a7*(Double)ii + warp_param->a8*(Double)jj+1);
	Y = (warp_param->a4*(Double)ii + warp_param->a5*(Double)jj+warp_param->a6)/
      		(warp_param->a7*(Double)ii + warp_param->a8*(Double)jj+1);
			
	X-= GetVopHorSpatRef(sprite);
	Y-= GetVopVerSpatRef(sprite);
	X -= GetVopSpriteLeftEdge(sprite);
	Y -= GetVopSpriteTopEdge(sprite);

	NX = floor(X);
	NY = floor(Y);
	NX -= (1-u*2);
	NY -= (1-v*2);	

	MB_nb_X = NX/16; MB_nb_X = MAX(0,MB_nb_X); MB_nb_X = MIN(numblocks_x-1,MB_nb_X);	
	MB_nb_Y = NY/16; MB_nb_Y = MAX(0,MB_nb_Y); MB_nb_Y = MIN(numblocks_y-1,MB_nb_Y);	
	posX[v][u] = MB_nb_X;
	posY[v][u] = MB_nb_Y;
	}
	
/* SEARCHING FOR THE BOUNDING BOX OF THE AREA */
min_MB_X = numblocks_x+1;	max_MB_X = -1;
min_MB_Y = numblocks_y+1;	max_MB_Y = -1;	
for (v=0 ; v<2 ; v++)
for (u=0 ; u<2 ; u++)
	{
	min_MB_X = MIN(min_MB_X, posX[v][u]);
	max_MB_X = MAX(max_MB_X, posX[v][u]);
	min_MB_Y = MIN(min_MB_Y, posY[v][u]);
	max_MB_Y = MAX(max_MB_Y, posY[v][u]);
	}
	
max_MB_X +=1;
max_MB_Y +=1; /* TO ACCOUNT FOR THE FLOOR FUNCTION */

MB_nb_X_min = numblocks_x+1;	MB_nb_X_max = -1;
MB_nb_Y_min = numblocks_y+1;	MB_nb_Y_max = -1;
first_time = 1;	

for (MB_nb_Y = min_MB_Y ; MB_nb_Y < max_MB_Y ; MB_nb_Y++ )
for (MB_nb_X = min_MB_X ; MB_nb_X < max_MB_X ; MB_nb_X++ )
	if (tab_transmit[MB_nb_Y*numblocks_x+MB_nb_X]==NON_TRANSMIT_BLOCK)
		{
		if (first_time)
			{
			start_X = MB_nb_X;
			start_Y = MB_nb_Y;
			first_time = 0;
			state_return = PIECE;
			}
		if (MB_nb_X<MB_nb_X_min) MB_nb_X_min = MB_nb_X;
		if (MB_nb_X>MB_nb_X_max) MB_nb_X_max = MB_nb_X;
		if (MB_nb_Y<MB_nb_Y_min) MB_nb_Y_min = MB_nb_Y;
		if (MB_nb_Y>MB_nb_Y_max) MB_nb_Y_max = MB_nb_Y;
		tab_transmit[MB_nb_Y*numblocks_x+MB_nb_X]=BLOCK_PIECE_TO_TRANSMIT;
		}

if (state_return==PIECE)
	{
	*piece_width =  MB_nb_X_max - MB_nb_X_min+1;
	*piece_height = MB_nb_Y_max - MB_nb_Y_min+1;
	*piece_xoffset = MB_nb_X_min;
	*piece_yoffset = MB_nb_Y_min;
	}
else
/*if (GetVolConfigSpriteTransmitMode(vol_config)!=UPDATE)*/
{
first_time = 1;	
for (MB_nb_Y = min_MB_Y ; MB_nb_Y < max_MB_Y ; MB_nb_Y++ )
for (MB_nb_X = min_MB_X ; MB_nb_X < max_MB_X ; MB_nb_X++ )
	if (tab_transmit[MB_nb_Y*numblocks_x+MB_nb_X]==BLOCK_UPDATE_TO_TRANSMIT)
		{
		if (first_time)
			{
			start_X = MB_nb_X;
			start_Y = MB_nb_Y;
			first_time = 0;
			state_return = UPDATE;
			}
		if (MB_nb_X<MB_nb_X_min) MB_nb_X_min = MB_nb_X;
		if (MB_nb_X>MB_nb_X_max) MB_nb_X_max = MB_nb_X;
		if (MB_nb_Y<MB_nb_Y_min) MB_nb_Y_min = MB_nb_Y;
		if (MB_nb_Y>MB_nb_Y_max) MB_nb_Y_max = MB_nb_Y;
		}
if (state_return==UPDATE)
	{
	*piece_width =  MB_nb_X_max - MB_nb_X_min+1;
	*piece_height = MB_nb_Y_max - MB_nb_Y_min+1;
	*piece_xoffset = MB_nb_X_min;
	*piece_yoffset = MB_nb_Y_min;
	}
}

/*state_return = PAUSE;*/ /* no UPDATE PIECES for the moment */	
		
PutVolConfigSpriteTransmitMode(state_return, vol_config);

} /* if STOP */

}
/***********************************************************CommentBegin******
 *
 * -- BlockPSNR_Y -- provides the SNR value for a block
 *
 * Author :		
 *	Cecile Dufour (Philips LEP/ dufour@lep.research.philips.com)
 *
 * Created :		
 *	3-10-97
 *
 * Purpose :		
 *	To manage UPDATE PIECES
 * 
 * Arguments in : 
 *		original and reconstructed vop
 *		position of the block (in macroblock number)	
 *
 * Arguments in/out :	
 *
 * Arguments out :	
 *
 * Return values :	
 *	Masked SNR value for the block
 *
 * Side effects :	
 *
 * Description :	
 *
 * See also :
 *
 * Modified :		
 *
 ***********************************************************CommentEnd********/

Float BlockPSNR_Y(Int pos_x, Int pos_y, Vop *ori_vop,Vop *rec_vop)
{
SInt 	*py_ori, *py_rec;
SInt 	*pa_ori, *pa_rec;
SInt 	inc;
Int	size_x_ori, size_y_ori;
Int	size_x_rec, size_y_rec;
UInt	sum, nb_occ, i, j;
Float	mse, psnr;

size_x_ori = GetVopWidth(ori_vop); size_y_ori = GetVopHeight(ori_vop);
size_x_rec = GetVopWidth(rec_vop); size_y_rec = GetVopHeight(rec_vop);

if (size_x_ori!=size_x_rec||size_y_ori!=size_y_rec)
	{
	printf(" In BlockPSNR_Y (vm_enc/src/sprite_enc_piece.c) INCOMPATIBLE SIZES\n");
	printf(" 	ORI : %d %d  and REC : %d %d\n",
				size_x_ori, size_y_ori,size_x_rec, size_y_rec);
	exit(0);
	}

py_ori = (SInt *)GetImageData(GetVopY(ori_vop))+(pos_y*16)*size_x_ori+(pos_x*16);
pa_ori = (SInt *)GetImageData(GetVopA(ori_vop))+(pos_y*16)*size_x_ori+(pos_x*16);
py_rec = (SInt *)GetImageData(GetVopY(rec_vop))+(pos_y*16)*size_x_ori+(pos_x*16);
pa_rec = (SInt *)GetImageData(GetVopA(rec_vop))+(pos_y*16)*size_x_ori+(pos_x*16);

inc = size_x_ori-16;
nb_occ=0;
sum = 0;

for (j=0 ; j<16 ; j++, py_ori+=inc, py_rec+=inc, pa_ori+=inc, pa_rec+=inc)
for (i=0 ; i<16 ; i++, py_ori++, py_rec++, pa_ori++, pa_rec++)
	if ((*pa_ori)==255&&(*pa_rec)==255)
		{
		sum += (*py_ori- *py_rec) * (*py_ori- *py_rec);
		nb_occ++;
		}

if (nb_occ>0)
	{
	mse = ((Float) sum)/(Float)nb_occ;
	psnr = 20*log10(((Float)255.0)/sqrt(mse));
	}
else 	psnr = 100;

return(psnr);

}

