/******************************************************************************
 *                                                                          
 * This software module was originally developed by 
 *
 * Cecile Dufour (LEP / ACTS-MoMuSys)
 * Frederic Dufaux (Digital Equipment Corp.)
 *
 * 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_util.c
 *
 * Authors:	Frederic Dufaux, Cecile Dufour
 * Created:	06/20/96
 *                                                                         
 * Description: routines for sprite encoding (STATIC/ DYNAMIC)
 * -- ReadWarpingParameters 
 * -- OLDReadWarpingParameters
 * -- EncodeSpriteTraj
 * -- Get_Index_Motion_Vector
 * -- encode_brightness_change_factor
 * -- MakeTrajectories
 * -- MakeDiffTraj
 *			
 * Notes: 	
 *
 * Modified:	
 * 
 ***********************************************************HeaderEnd*********/

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

#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include "mom_bitstream_i.h"
#include "mot_util.h"
#include "sprite_enc_util.h"
#include "sprite_util.h"

#include <math.h>

typedef struct
{
  U_Int code; /* right justified */
  Int len;
} VLCsprite_table;

static VLCsprite_table traj_sprite_tab[15] =
	{
  	{0,2}, {2,3}, {3,3}, {4,3}, 
	{5,3}, {6,3}, {14,4}, {30,5}, 
	{62,6}, {126,7}, {254,8}, {510,9},
	{1022,10},{2046,11},{4094,12}
	};
	
static VLCsprite_table sprite_brightness_change_factor_tab[5] =
	{
  	{0,0}, {2,2}, {6,3}, {14,4}, {15,4}
	};	




/***********************************************************CommentBegin******
 *
 * -- ReadWarpingParameters -- read global motion parameters
 *
 * Author :		
 *	Cecile Dufour (Philips LEP/ dufour@lep.research.philips.com)
 *	Frederic Dufaux (Digital Equipment Corporation/ dufaux@crl.dec.com)
 *
 * Created :		
 *	06/20/96
 *
 * Purpose :		
 *      reading the ouput from the off-line global motion estimation
 *
 * Arguments in : a pointer on a structure of parameters
 *                a pointer on the file to write in
 * 
 * Arguments in / out : 
 *
 * Return values :	
 * 
 * Side effects :	
 *	
 * Description : 
 *
 * See also :
 *
 * Modified :		
 *	
 *
 *
 ***********************************************************CommentEnd********/

Sprite_motion *
ReadWarpingParameters (Int no_of_sprite_points, Int warp_param_counter, Char *warp_filename)
{
Double temp;
Int   i,j;
File *pf;
Sprite_motion	*warp_param;

  printf("\t\tReading global motion parameters\n"); 

  warp_param = (Sprite_motion *) emalloc(sizeof(Sprite_motion)); 

  switch(no_of_sprite_points) {

    case 0:    /* stationary */
      warp_param->a1 = 1.0;
      warp_param->a2 = 0.0;
      warp_param->a3 = 0.0;
      warp_param->a4 = 0.0;
      warp_param->a5 = 1.0;
      warp_param->a6 = 0.0; 
      warp_param->a7 = 0.0;
      warp_param->a8 = 0.0;
    break;
    
    case 1: /* translation */   
    case 2: /* zoom, scaling, rotation */   
    case 3: /* affine */   
    case 4: /* perspective */   

      if ( (pf = fopen(warp_filename,"r"))==NULL)
       		{
		printf(" unable to open warping parameters filen %s\n",warp_filename);
		exit(0);
		}
		
/* go to the correct place to start reading */
      for (i=0; i<warp_param_counter; i++)
		for (j=0; j<8; j++)
			fscanf(pf,"%lf",&temp);

      fscanf(pf,"%lf",&temp);
      warp_param->a1 = temp;

      fscanf(pf,"%lf",&temp);
      warp_param->a2 = temp;

      fscanf(pf,"%lf",&temp);
      warp_param->a3 = temp;

      fscanf(pf,"%lf",&temp);
      warp_param->a4 = temp; 

      fscanf(pf,"%lf",&temp);
      warp_param->a5 = temp;

      fscanf(pf,"%lf",&temp);
      warp_param->a6 = temp;
      
      fscanf(pf,"%lf",&temp);
      warp_param->a7 = temp;
      
      fscanf(pf,"%lf",&temp);
      warp_param->a8 = temp;

      /* close globalme param file */
      fclose(pf);
      
      break;
      
    default:
      printf("ERROR: Unsupported nb of sprite points\n");
      exit(1);
      break;
    }
return(warp_param);

}

/***********************************************************CommentBegin******
 *
 * -- OLDReadWarpingParameters -- read global motion parameters
 *
 * Author :		
 *	Cecile Dufour (Philips LEP/ dufour@lep.research.philips.com)
 *	Frederic Dufaux (Digital Equipment Corporation/ dufaux@crl.dec.com)
 *
 * Created :		
 *	06/20/96
 *
 * Purpose :		
 *      reading the ouput from the off-line global motion estimation
 *	opposed to the precedding one: depends on the input format:
 *	the preceeding reading takes always 8 parameters into account.
 *	OLDReadWarpingParameters has "cases".
 * Arguments in : a pointer on a structure of parameters
 *                a pointer on the file to write in
 * 
 * Arguments in / out : 
 *
 * Return values :	
 *  
 * Side effects :	
 *	
 * Description : 
 *
 * See also :
 *
 * Modified :		
 *
 ***********************************************************CommentEnd********/

Sprite_motion *
OLDReadWarpingParameters (Int no_of_sprite_points, Int warp_param_counter, Char *warp_filename)
{
Double temp;
Int   i,j;
File *pf;
Sprite_motion	*warp_param;

  printf("\t\tReading global motion parameters\n"); 

  warp_param = (Sprite_motion *) emalloc(sizeof(Sprite_motion)); 

  switch(no_of_sprite_points) {

    case 0:    /* stationary */
      warp_param->a1 = 1.0;
      warp_param->a2 = 0.0;
      warp_param->a3 = 0.0;
      warp_param->a4 = 0.0;
      warp_param->a5 = 1.0;
      warp_param->a6 = 0.0; 
      warp_param->a7 = 0.0;
      warp_param->a8 = 0.0;
    break;
    
    case 1:    /* translation */
       if ( (pf = fopen(warp_filename,"r"))==NULL)
       		{
		printf(" unable to open warping parameters filen %s\n",warp_filename);
		exit(0);
		}
      
/* go to the correct place to start reading */
      for (i=0; i<warp_param_counter; i++)
		for (j=0; j<2; j++)
	  		fscanf(pf,"%lf",&temp);

      warp_param->a1 = 1;
      warp_param->a2 = 0;

      fscanf(pf,"%lf",&temp);
      warp_param->a3 = temp;

      warp_param->a4 = 0;
      warp_param->a5 = 1;

      fscanf(pf,"%lf",&temp);
      warp_param->a6 = temp;

      warp_param->a7 = 0.0;
      warp_param->a8 = 0.0;

      /* close globalme param file */
      fclose(pf);
      
    break;
      
       case 2:    /* zoom, scaling, rotation */
       if ( (pf = fopen(warp_filename,"r"))==NULL)
       		{
		printf(" unable to open warping parameters filen %s\n",warp_filename);
		exit(0);
		}
      
/* go to the correct place to start reading */
      for (i=0; i<warp_param_counter; i++)
		for (j=0; j<4; j++)
	  		fscanf(pf,"%lf",&temp);

      fscanf(pf,"%lf",&temp);
      warp_param->a1 = temp;

      fscanf(pf,"%lf",&temp);
      warp_param->a2 = temp;

      fscanf(pf,"%lf",&temp);
      warp_param->a3 = temp;

      warp_param->a4 = - warp_param->a2;
      warp_param->a5 =  warp_param->a1;

      fscanf(pf,"%lf",&temp);
      warp_param->a6 = temp;

      warp_param->a7 = 0.0;
      warp_param->a8 = 0.0;

      /* close globalme param file */
      fclose(pf);
      
    break;
      
    case 3:    /* affine */
       if ( (pf = fopen(warp_filename,"r"))==NULL)
       		{
		printf(" unable to open warping parameters filen %s\n",warp_filename);
		exit(0);
		}
      
/* go to the correct place to start reading */
      for (i=0; i<warp_param_counter; i++)
		for (j=0; j<6; j++)
	  		fscanf(pf,"%lf",&temp);

      fscanf(pf,"%lf",&temp);
      warp_param->a1 = temp;

      fscanf(pf,"%lf",&temp);
      warp_param->a2 = temp;

      fscanf(pf,"%lf",&temp);
      warp_param->a3 = temp;

      fscanf(pf,"%lf",&temp);
      warp_param->a4 = temp;

      fscanf(pf,"%lf",&temp);
      warp_param->a5 = temp;

      fscanf(pf,"%lf",&temp);
      warp_param->a6 = temp;

      warp_param->a7 = 0.0;
      warp_param->a8 = 0.0;

      /* close globalme param file */
      fclose(pf);

      break;
      
    case 4:    /* perspective */
       if ( (pf = fopen(warp_filename,"r"))==NULL)
       		{
		printf(" unable to open warping parameters filen %s\n",warp_filename);
		exit(0);
		}
		
/* go to the correct place to start reading */
      for (i=0; i<warp_param_counter; i++)
		for (j=0; j<8; j++)
			fscanf(pf,"%lf",&temp);

      fscanf(pf,"%lf",&temp);
      warp_param->a1 = temp;

      fscanf(pf,"%lf",&temp);
      warp_param->a2 = temp;

      fscanf(pf,"%lf",&temp);
      warp_param->a3 = temp;

      fscanf(pf,"%lf",&temp);
      warp_param->a4 = temp; 

      fscanf(pf,"%lf",&temp);
      warp_param->a5 = temp;

      fscanf(pf,"%lf",&temp);
      warp_param->a6 = temp;
      
      fscanf(pf,"%lf",&temp);
      warp_param->a7 = temp;
      
      fscanf(pf,"%lf",&temp);
      warp_param->a8 = temp;

      /* close globalme param file */
      fclose(pf);
      
      break;
      
    default:
      printf("ERROR: Unsupported nb of sprite points\n");
      exit(1);
      break;
    }
return(warp_param);

}




/***********************************************************CommentBegin******
 *
 * --  EncodeSpriteTraj
 *
 * Author :		
 *	Frederic Dufaux (Digital Equipment Corporation/ dufaux@crl.dec.com)
 *	Cecile Dufour, (Philips LEP/ dufour@lep.research.philips.com)
 *
 *
 * Created :		
 *	30-01-97
 *
 * Purpose :  write trajectory to BitStream
 *	
 * 
 * Arguments in : a pointer on a structure of parameters
 *                a pointer on the file to write in
 * 
 * Arguments in / out : 
 *
 * Return values :	
 * 
 * Side effects :	
 *	
 *
 * Description : 
 *
 * See also :
 *
 * Modified :		
 *	
 *
 ***********************************************************CommentEnd********/


Void 
EncodeSpriteTraj(TrajPoint *difftraj ,Image *buffer, Int nb_ref_points, Int sprite_usage)
{
Int index,i,id[8];
UInt resu;


/* write in an integer index */ 
for (i=0 ; i<nb_ref_points ; i++)
	{
	id[2*i]   = difftraj[i].x;
	id[2*i+1] = difftraj[i].y;
	}


for (i=0 ; i<2*nb_ref_points ; i++)
	{
	index=Get_Index_Motion_Vector(id[i]);
	if (index>14) printf(" In EncodeSpriteTraj: index > 14\n");
	if (id[i]<0)
		resu=~(-id[i]);
	else
		resu=(UInt)(id[i]);
	
	BitstreamPutBits(buffer,traj_sprite_tab[index].code,traj_sprite_tab[index].len);
	BitstreamPutBits(buffer,resu,index);
	}

}

/***********************************************************CommentBegin******
 *
 * --  Get_Index_Motion_Vector()
 *
 * Author :		
 *	Olivier Fidaire, (Philips LEP)
 *
 * Created :		
 *	16-10-96
 *
 * Purpose :  get the index in the vlctable (sprite_tab) for the motion vector 
 *	
 * Arguments in : 
 * 
 * Arguments in / out : 
 *
 * Return values :	
 *  
 * Side effects :	
 *
 * Description : 
 *
 * See also :
 *
 * Modified : 17-10-97 Cecile Dufour: rewrote the function		
 *	
 *
 ***********************************************************CommentEnd********/

Int Get_Index_Motion_Vector(Int value)
{
Int abs_value, index, val_index, ok;

abs_value = ABS(value);
index=14;
val_index = 8192;
ok=1;

if (abs_value>16383)
	index=15;
else
if (abs_value==0)
	index=0;
else
	do
	{
	if (abs_value&val_index)
		ok=0;
	else
		{
		index--;
		val_index>>=1;
		}
	}while (ok);

return(index);
}


/***********************************************************CommentBegin******
 *
 * -- brightness_change_factor_encode --  
 *
 * Author :		
 *	Cecile Dufour, (Philips LEP/ dufour@lep.research.philips.com)
 *
 * Created :		
 *	08/12/97
 *
 * Purpose :		
 *      encoding of the brightness change factor for sprite
 *
 * Arguments in : 
 * 
 * Arguments in / out : 
 *
 * Return values :	
 * 
 * Side effects :	
 *	
 *
 * Description : 
 *
 * See also :
 *
 * Modified : 17-10-97 Cecile Dufour: rewrote the function		
 *
 ***********************************************************CommentEnd********/
Float 
encode_brightness_change_factor (Float brightness_change_factor ,Image *buffer)
 
{
Float rec_factor;
Int   L, index, length;
UInt resu;

rec_factor = brightness_change_factor;

/* clipping value */
if (rec_factor<0.0)  rec_factor = 0.0;
if (rec_factor>17.48) rec_factor = 17.48;

rec_factor -=1;
rec_factor *= 100;
L = float_to_int(rec_factor);
if (L==0) printf(" brightness factor equal to 1!\n");
rec_factor = L/100.0;
rec_factor+=1;

if (L>-17&&L<17) 
	{
	index = 0;
	length = 5;
	if (L<0) 	L-=15;
	else		L+=15;
	}
else
if (L>-49&&L<49) 
	{
	index = 1;
	length = 6;
	if (L<0) 	L-=15;
	else		L+=15;
	}
else
if (L>-113&&L<113) 
	{
	index = 2;
	length = 7;
	if (L<0) 	L-=15;
	else		L+=15;
	}
else
if (L<625) 
	{
	index = 3;
	length = 10;
	L -= 113;
	}
else
	{
	index = 4;
	length = 11;
	L -= 625;
	}

if (L<0)
	resu = ~(-L);
else
	resu = (UInt)L;
	
BitstreamPutBits(buffer,
		sprite_brightness_change_factor_tab[index].code,
		sprite_brightness_change_factor_tab[index].len);
BitstreamPutBits(buffer,resu,length);

return(rec_factor);

}

/***********************************************************CommentBegin******
 *
 * -- MakeTrajectories -- make trajectories and quantize motion parameters
 *
 * Author :		
 *	Frederic Dufaux (Digital Equipment Corporation/ dufaux@crl.dec.com)
 *
 * Created :		
 *	10/30/96
 *
 * Purpose :		
 *
 * Arguments in : 
 * 
 * Arguments in / out : 
 *
 * Return values :	
 * 
 * Side effects :	
 *	
 * Description : 
 *
 * See also :
 *
 * Modified : 17-10-97 Cecile Dufour: rewrote the function		
 *
 ***********************************************************CommentEnd********/

TrajPoint *
MakeTrajectories (Sprite_motion *warp_param, Int no_of_sprite_points, 
					TrajPoint *ref_point_coord/*, TrajPoint *half_traj*/)
{
Double	denom, nom_x, nom_y;   
Int 	spriteorvop_point_coord_x,spriteorvop_point_coord_y;
TrajPoint 	*traj_point_coord;
Int i;


traj_point_coord = (TrajPoint *) emalloc(no_of_sprite_points*sizeof(TrajPoint)); 

printf("\t\tPerforming sprite trajectories\n"); 

for (i=0; i<no_of_sprite_points; i++) 
	{
/*if (MomusysSprite)
	{*/
	denom = warp_param->a7 * ref_point_coord[i].x +
		warp_param->a8 * ref_point_coord[i].y 
		+ 1; 
	nom_x = warp_param->a1 * ref_point_coord[i].x + 
		warp_param->a2 * ref_point_coord[i].y +
		warp_param->a3; 
	nom_y = warp_param->a4 * ref_point_coord[i].x + 
		warp_param->a5 * ref_point_coord[i].y +
		warp_param->a6;

/* coordinates in the sprite or vop corresponding to the reference points (quantized to half-pel) */

	spriteorvop_point_coord_x = float_to_int2( 2*nom_x/denom);
	spriteorvop_point_coord_y = float_to_int2( 2*nom_y/denom);
/*	}
else if (MicrosoftSprite)
	{
	spriteorvop_point_coord_x = float_to_int2( 2*half_traj[i].x);
	spriteorvop_point_coord_y = float_to_int2( 2*half_traj[i].y);
	}*/

/* motion vectors according to Sec. 3.9.5.1.4 */

	traj_point_coord[i].x =  spriteorvop_point_coord_x - 2*ref_point_coord[i].x;
	traj_point_coord[i].y =  spriteorvop_point_coord_y - 2*ref_point_coord[i].y;

      }
	
return (traj_point_coord);

}

/***********************************************************CommentBegin******
 *
 * -- MakeDiffTraj -- to encode trajectories differentially
 *
 * Author :		
 *	Frederic Dufaux (Digital Equipment Corporation/ dufaux@crl.dec.com)
 *
 * Created :		
 *	10/30/96
 *
 * Purpose :		
 *
 * Arguments in : 
 * 
 * Arguments in / out : 
 *
 * Return values :	
 *  
 * Side effects :	
 *	
 * Description : 
 *
 * See also :
 *
 * Modified : 
 *		
 ***********************************************************CommentEnd********/


TrajPoint *
MakeDiffTraj (Int no_of_sprite_points, TrajPoint *traj)
{
Int i;
TrajPoint	*difftraj;
difftraj = (TrajPoint *) emalloc(no_of_sprite_points*sizeof(TrajPoint)); 

difftraj[0].x = traj[0].x;
difftraj[0].y = traj[0].y;

for (i=1; i<MIN(no_of_sprite_points,3); i++)
  	{
	difftraj[i].x = traj[i].x - traj[0].x;
	difftraj[i].y = traj[i].y - traj[0].y;
	}
if (no_of_sprite_points==4)
  	{
	difftraj[3].x = traj[3].x - traj[2].x - traj[1].x + traj[0].x;
	difftraj[3].y = traj[3].y - traj[2].y - traj[1].y + traj[0].y;
	}
	
return (difftraj);
}
/***********************************************************CommentBegin******
 *
 * -- ReadDiffTraj -- read diff trajectories (Microsoft input 
 * Author :		
 *	Cecile Dufour (Philips LEP/ dufour@lep.research.philips.com)
 *
 * Created :		
 *	19/01/98
 *
 * Purpose :		
 *      reading the ouput from the off-line global motion estimation
 *
 * Arguments in : a pointer on a structure of parameters
 *                a pointer on the file to write in
 * 
 * Arguments in / out : 
 *
 * Return values :	
 * 
 * Side effects :	
 *	
 * Description : 
 *
 * See also :
 *
 * Modified :		
 *	
 *
 *
 ***********************************************************CommentEnd********/

TrajPoint *
ReadHalfTraj (Int no_of_sprite_points, Int warp_param_counter, Char *warp_filename)
{
Double temp;
Int   uti;
Int   i,j;
File *pf;
TrajPoint	*traj_point_coord=NULL;
Char		garbage[201];


  switch(no_of_sprite_points) {

    case 0:    /* stationary */
    break;
    
    case 1: /* translation */   
    case 2: /* zoom, scaling, rotation */   
    case 3: /* affine */   
    case 4: /* perspective */   

    traj_point_coord = (TrajPoint *) emalloc(no_of_sprite_points*sizeof(TrajPoint)); 
    printf("\t\tReading Microsoft sprite trajectories\n"); 

    if ( (pf = fopen(warp_filename,"r"))==NULL)
       		{
		printf(" unable to open warping parameters filen %s\n",warp_filename);
		exit(0);
		}
		
/* go to the correct place to start reading */
fgets(garbage,201,pf);
fgets(garbage,201,pf);

      for (i=0; i<warp_param_counter; i++)
		fgets(garbage,201,pf);

/* start reading */
for (i=0 ; i<4 ; i++)	uti = getc(pf);
for (j=0; j<no_of_sprite_points; j++)
	{
	fscanf(pf,"%lf",&temp);
	traj_point_coord[j].x= temp;

	fscanf(pf,"%lf",&temp);
	traj_point_coord[j].y= temp;

      	}

      /* close globalme param file */
      fclose(pf);
      
      break;
      
    default:
      printf("ERROR: Unsupported nb of sprite points\n");
      exit(1);
      break;
    }
	
return (traj_point_coord);

}




	

