/*****************************************************************************
 *
 * This software module was originally developed by
 *
 *   Robert Danielsen (Telenor / 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.
 *
 * 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) 1996
 *
 *****************************************************************************/


/***********************************************************HeaderBegin*******
 *                                                                         
 * File:	mot_comp_image.c
 *
 * Author:	Robert Danielsen <Robert.Danielsen@nta.no>
 * Created:	07.09.96
 *                                                                         
 * Description: Motion compensation functions for an Image
 *
 * Notes: 	modified by Noel O'Connor 04.02.97 - removed #include <assert.h>
 *
 ***********************************************************HeaderEnd*********/

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

#include <stdlib.h>
#include <stdio.h>
#include "momusys.h"
#include "mot_comp.h"
#include "vm_common_defs.h"
#include "mot_util.h"
#include "io_generic.h"
#include "mot_padding.h"
#include "vm_vop_bound.h"

/***********************************************************CommentBegin******
 *
 * -- ImageMotionCompensate -- Motion compensation for one Image
 *
 * Author :		
 *	Robert Danielsen <Robert.Danielsen@nta.no>
 *
 * Created :		
 *	06.09.96
 *
 * Purpose :		
 *	Motion compensation for one Image
 * 
 * Arguments in : 	
 *	
 *
 * Arguments in/out :	
 *	Image *rec_prev		Previous reconstructed Image
 *	Image *mot_x		Motion vectors, x components
 *      Image *mot_y		Motion vectors, y components
 *	Image *MB_decisions	Macroblock modes
 *	Image *alpha_decisions	Subsampled Alpha plane
 *	Image *comp		Image to be filled with compensated data
 *
 * Arguments out :	
 *	
 *
 * Return values :	
 *	
 *
 * Side effects :	
 *	
 *
 * Description :	
 *	Always implements the extension of the Image to allow unrestricted
 *	MVs if necessary.
 *	The motion vectors are always ordered in an Image structure,
 *	one entry for each 8x8 block. A 16x16 vector is repeated 4 times.
 *	structure is used for this.
 *	The MB_decisions are ordered in an Image-structure, one entry for
 *	each Macroblock.
 *
 * See also :
 *
 * Modified : 14.04.97 Minhua Zhou	
 *      added alpha_decisions to make a right compensation.	
 *
 ***********************************************************CommentEnd********/

Void
ImageMotionCompensate (Image *rec_prev,
		       Image *mot_x,
		       Image *mot_y,
		       Image *MB_decisions,
			Image *alpha_decisions,
		       Image *comp)
{
  Image	*api;

  Image *prev_recon=NULL;
  Image *pr_edge=NULL;
  Int prev_x_min,prev_x_max,prev_y_min,prev_y_max;
  Int width = comp->x;
  Int height = comp->y;
  Int mode;
  Int mb_size = MB_SIZE;		
  Int i, j, x, y;
  Int edge, offset_x, offset_y, width_prev,height_prev;

  SInt apred[16][16];
  SInt *aprev_ipol;

  /* Initialise the Image to be compensated */

  SetConstantImage (comp, 0);
    
  /* Extend the reference Image */
  
  edge = 16;		/* Padding width */

  pr_edge = AllocImage (GetImageSizeX (rec_prev) + 2 * edge,
			GetImageSizeY (rec_prev) + 2 * edge,
			SHORT_TYPE);
    
  MakeImageEdge (rec_prev, edge, pr_edge);

  /* interpolate the alpha component */

  api = AllocImage (GetImageSizeX (pr_edge) * 2,
		    GetImageSizeY (pr_edge) * 2,
		    SHORT_TYPE);

  InterpolateImage (pr_edge, api,0);
    
  aprev_ipol = (SInt *) GetImageData (api) + GetImageSizeX (api) * 2 * edge 
    + 2 * edge;

  /* The data pointers of prev_recon will point into the data
     areas of pr_edge */

  prev_recon = pr_edge;
	
  prev_recon->f += GetImageSizeX (pr_edge) * edge + edge;

  /* Compensate for the offset in spatial references
     between comp and rec_prev. This is done offseting the pointers
     into the MC routines and hence tricking them.
     */

  offset_x = 0;
  offset_y = 0;
  
  aprev_ipol += GetImageSizeX (api) * 2 * offset_y + 2 * offset_x;
 
  prev_recon->f += GetImageSizeX (pr_edge) * offset_y + offset_x;

  /* Do the motion compensation */
  
  width_prev = GetImageSizeX (pr_edge);
  height_prev = GetImageSizeY(pr_edge);
  prev_x_min = -2 * edge;
  prev_y_min = -2 * edge;
  prev_x_max = prev_x_min + 2*width_prev;
  prev_y_max = prev_y_min + 2*height_prev;


   for (i = 0; i < height/mb_size; i++)
    {
      for (j = 0; j < width/mb_size; j++)
	{
	  mode = ModeMB(MB_decisions, j, i);
	  if (mode == MBM_INTER16 || mode == MBM_INTER8) 
	    {		
	      x = j * mb_size;
	      y = i * mb_size;
				
	      if (mode == MBM_INTER8)
		{
		  /* Do overlapped motion compensation 8x8 */
                  /* Minhua Zhou 10.04.97 Added alpha_decisions */
		  GetPred_Advanced (x, y, 
                                    prev_x_min,prev_y_min,prev_x_max,prev_y_max,
				    mot_x, mot_y, MB_decisions,
				    alpha_decisions,
				    aprev_ipol, &apred[0][0], 0, width,
				    width_prev, mb_size, 1);
		  GetPred_Advanced (x, y,
                                    prev_x_min,prev_y_min,prev_x_max,prev_y_max,
 				    mot_x, mot_y, MB_decisions,
			            alpha_decisions,
				    aprev_ipol, &apred[0][8], 1, width,
				    width_prev, mb_size, 1);
     		  GetPred_Advanced (x, y,
                                    prev_x_min,prev_y_min,prev_x_max,prev_y_max,
				    mot_x, mot_y, MB_decisions,
			            alpha_decisions,
				    aprev_ipol, &apred[8][0], 2, width,
				    width_prev, mb_size, 1);
		  GetPred_Advanced (x, y, 
                                    prev_x_min,prev_y_min,prev_x_max,prev_y_max,
				    mot_x, mot_y, MB_decisions,
				   alpha_decisions,
				    aprev_ipol, &apred[8][8], 3, width,
				    width_prev, mb_size, 1);
		  PutMB (x, y, apred, comp, width, mb_size); 
		}
	      else 
		{		
		  /* Do default motion compensation 16x16 */
		  GetPred_Default (x, y, mot_x, mot_y, aprev_ipol, &apred[0],
			    width, width_prev, mb_size);
		  PutMB (x, y, apred, comp, width, mb_size); 
		}	  
	    }
	}
    }
  FreeImage (api);
  FreeImage (pr_edge);
}
