

/*****************************************************************************
 *
 * This software module was originally developed by
 *
 *   Robert Danielsen (Telenor / ACTS-MoMuSyS)
 *
 * and edited by
 * 
 *   Noel Brady (Teltec DCU / ACTS-MoMuSyS)        	                    
 *   Frederic Dufaux (Digital Equipment Corp.)        	                  
 *   Fernando Jaureguizar (UPM / ACTS-MoMuSyS)
 *   Cecile Dufour (Philips LEP / ACTS-MoMuSys)
 *   Minhua Zhou (HHI / ACTS-MoMuSys) 
 *   Bob Eifrig (NextLevel Systems)
 *
 * 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:	mot_comp.c
 *
 * Author:	Robert Danielsen <Robert.Danielsen@nta.no>
 * Created:	06.03.96
 *                                                                          
 * Description: Motion compensation functions for a Vop.
 *
 * Notes: 	
 *
 * Modified:	21.04.96 Robert Danielsen: Reformatted. New headers.
 *		28.05.96 Robert.Danielsen: Changed some naming, tidied up
 *			some functions. Changed from using tmn-style MODE
 *			defines to the same ones as in mot_est.h.
 *		28.11.96 Ferran Marques: modifications to introduce the
 *			new RepetitivePadding (22.10.96)
 *		20.12.96 Noel Brady: turned off the overlapped filtering when 
 *			 motion compensating binary alpha channels.
 * 	        04.02.97 Noel O'Connor: removed all calls to assert()
 *	        07-Feb-1997, M.Wollborn: changed in order to treat skipped MBs
 *			     correctly
 *		12-02-97 Cecile Dufour: inclusion for SPRITE (from F. Dufaux + 
R. Crinon)
 *		14-04-97  Minhua Zhou : Modifications for overlapped 
 *					motion compensation 
 *		09-05-97  Minhua Zhou : added unrestricted MC und solved
 *					BUG VM6-970425-02 
 *              13-05-97  Minhua Zhou : added obmc_disable 
 *    16.06.97 Angel Pacheco: unified the TRANSPARENT modes.
 *    01.08.97 Fernando Jaureguizar: added the printing of modes for
 *             B-VOPs in B_VopMotionCompensation(), like in
 *             VopMotionCompensate().   (SpSc)
 *    28.08.97 Osamu Sunohara(Sony): modified to set MV in spatial scalable
 *                                   enhancement B-VOP to zero
 *
 ***********************************************************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"
#include "sprite_util.h"
#include "vm_compos.h"
#ifndef _WD_MODE_
#include "sprite_globalpred.h"
#endif
#include "mot_est.h"

/* For correct rounding of chrominance vectors */
static Int roundtab4[] = {0,1,1,1};
static Int roundtab8[] = {0,0,1,1,1,1,1,2};
/*** 10/30 for TPS */
static Int roundtab12[] = {0,0,0,1,1,1,1,1,1,1,2,2}; 
/* 10/30 for TPS ***/
static Int roundtab16[] = {0,0,0,1,1,1,1,1,1,1,1,1,1,1,2,2};

/***********************************************************CommentBegin******
 *
 * -- VopMotionCompensate -- Motion compensation for one Vop
 *
 * Author :		
 *	Robert Danielsen <Robert.Danielsen@nta.no>
 *
 * Created :		
 *	05.03.96
 *
 * Purpose :		
 *	Motion compensation for one Vop
 * 
 * Arguments in : 	
 *	
 *
 * Arguments in/out :	
 *	Vop *rec_prev		Previous reconstructed Vop
 *	Image *mot_x		Motion vectors, x components
 *      Image *mot_y		Motion vectors, y components
 *	Image *MB_decisions	Macroblock modes
 *	Vop *comp		Vop to be filled with compensated data
 *      Int obmc_disable 
 *	Vop *sprite		Online sprite
 *	Sprite_motion *gmparam	Parameters for warping the vop from the sprite
 *
 * Arguments out :	
 *	
 *
 * Return values :	
 *	
 *
 * Side effects :	
 *	
 *
 * Description :	
 *	Always implements the extension of the Vop 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 :		
 *	06.02.96 Various developments. Robert Danielsen
 *	12.04.96 Changing types, updating header texts. Robert Danielsen
 *  	25.04.96 Added repetitive padding of reference vop. Noel Brady
 *	14.06.96 Robert Danielsen: Added passing of alpha-information to
 *		Compensate_Chroma. 
 *	04.09.96 Robert Danielsen: Added compensation of alpha-plane
 *  	20.12.96 NOEL BRADY: Removed compensation of alpha plane. See
 *		 AlphaMotionCompensate().
 *	07-Feb-1997, M.Wollborn: changed in order to treat skipped MBs
 *		     correctly
 *	12-02-97 Cecile Dufour : for sprite capabilities
 *	14-04-97  Minhua Zhou : Modifications for overlapped 
 *				motion compensation 
 *  19.11.97 Noel Brady: modified to handle kipped remote MBs correctly
 *  11.12.97 Bob Eifrig: added field motion compensation
 *
 ***********************************************************CommentEnd********/
Void
VopMotionCompensate (Vop *rec_prev,
		     Image *mot_x,
		     Image *mot_y,
		     Image *MB_decisions,
		     Image *alpha_decisions,
		     Vop *comp,
		     Int obmc_disable, 
		     Vop *sprite) 
		         
{
  Image	*pi;
  Vop* prev_recon=NULL;
  Vop* pr_edge=NULL;
  Int width = GetVopWidth(comp);
  Int height = GetVopHeight(comp);
  Int mode;
  Int mb_size = MB_SIZE;		
  Int i, j, x, y;
  Int edge, offset_x, offset_y, width_prev;
  SInt pred[16][16];
  SInt *prev_ipol;
  SInt overlap;	
  Int prev_x_min,prev_x_max,prev_y_min,prev_y_max;		

  Vop *mosaicvopedge = NULL;
  Image *padmos = NULL;
  SInt *spadmos = NULL;
  Int edgemos=0, offset_mos_i0=0, offset_mos_j0=0;
  Int sizex=0, sizey=0;
  Int br_x=0, br_y=0;      /* absolute ref of current vop */
  Int pbr_x, pbr_y;    /* absolute ref of prev vop */
  Int no_of_sprite_points=0;
  Int warpingaccuracy=0;
  Int imv, mvwidth = 2 * width / MB_SIZE;
  
for (j=0 ; j<16 ; j++)
for (i=0 ; i<16 ; i++)
  pred[j][i]=0;

#define ALP_COMP 0

#ifdef _DEBUG_
  /* Check MB-modes */
  fprintf (stdout, "Checking MB-modes...\n");
  for (i = 0; i < height/MB_SIZE; i++)
    {
      for (j = 0; j < width/MB_SIZE; j++)
	{
	  fprintf (stdout, "%d ", MB_decisions->data->s[i*width/MB_SIZE+j]);
	}
      fprintf (stdout, "\n");
    } 
  /* Check MB-modes */
 if (1)
 {
  fprintf (stdout, "Checking B-modes...\n");
  for (i = 0; i < height/B_SIZE; i++)
    {
      for (j = 0; j < width/B_SIZE; j++)
	{
	  fprintf (stdout, "%d ", alpha_decisions->data->s[i*width/B_SIZE+j]);
	}
      fprintf (stdout, "\n");
    } 
    }
#endif
  
  /* initialise the compensated vop */

  SetConstantImage (GetVopY (comp), 0);
  SetConstantImage (GetVopU (comp), 0);
  SetConstantImage (GetVopV (comp), 0);
    
  /* Extend and pad the reference Vop */
  
  /* Make padding witdh dependent on fcode; MW, 07-Feb-1997 */
  edge = 16;

  
  pr_edge = rec_prev;

  if (GetVopSpriteUsage(comp)==ONLINE_SPRITE)
	{
	SubsampleAlphaMap(GetVopA(sprite),GetVopAuv(sprite),1);

	edgemos = 16;
	offset_mos_i0 = - GetVopSpriteLeftEdge(rec_prev) + edgemos;
	offset_mos_j0 = - GetVopSpriteTopEdge(rec_prev) + edgemos;
	mosaicvopedge = AllocVop (GetVopWidth(sprite) + 2 * edgemos,
				  GetVopHeight(sprite) + 2 * edgemos);

	MakeImageEdge(GetVopY(sprite), edgemos, GetVopY(mosaicvopedge));
	MakeImageEdge(GetVopU(sprite), edgemos/2, GetVopU(mosaicvopedge));
	MakeImageEdge(GetVopV(sprite), edgemos/2, GetVopV(mosaicvopedge));
	MakeImageEdge(GetVopA(sprite), edgemos, GetVopA(mosaicvopedge)); 
	MakeImageEdge(GetVopAuv(sprite), edgemos/2, GetVopAuv(mosaicvopedge)); 

	mosaicvopedge->arbitrary_shape=1;

     	if(mosaicvopedge->arbitrary_shape==0)
		RepetitivePadding (0, mosaicvopedge);          /* YUV padding */
      	else
		MacroblockBasedPadding (GetVopA(mosaicvopedge), mosaicvopedge); 
/* YUV padding */

	padmos = GetVopY(mosaicvopedge);
	spadmos = (SInt *)GetImageData(padmos);

	sizex = GetImageSizeX(padmos);
	sizey = GetImageSizeY(padmos);
	br_x = GetVopHorSpatRef(comp);
	br_y = GetVopVerSpatRef(comp);
	pbr_x = GetVopHorSpatRef(rec_prev);
	pbr_y = GetVopVerSpatRef(rec_prev);

	no_of_sprite_points = GetVopNoOfSpritePoints(rec_prev);
	warpingaccuracy = GetVopWarpingAccuracy(rec_prev);
	}  

  if (GetVopSpriteUsage(comp)==GMC_SPRITE)
	{
	sizex = GetVopWidth(rec_prev);
	sizey = GetVopHeight(rec_prev);
	br_x = GetVopHorSpatRef(comp);
	br_y = GetVopVerSpatRef(comp);
	pbr_x = GetVopHorSpatRef(rec_prev);
	pbr_y = GetVopVerSpatRef(rec_prev);

	no_of_sprite_points = GetVopNoOfSpritePoints(rec_prev);
	warpingaccuracy = GetVopWarpingAccuracy(rec_prev);

	offset_mos_i0 = - pbr_x;
	offset_mos_j0 = - pbr_y;

	}  
 
   
  /* interpolate the Y component */

  pi = AllocImage(GetVopWidth(pr_edge)*2, GetVopHeight(pr_edge)*2, SHORT_TYPE);
  InterpolateImage(GetVopY(pr_edge), pi,GetVopRoundingType(comp));
    
  prev_ipol = (SInt *) GetImageData(pi) + GetImageSizeX(pi) * 2 * edge  
    + 2 * edge;

  /* The data pointers of prev_recon will point into the data
     areas of pr_edge */
  prev_recon = SallocVop ();

  PutVopY (GetVopY (pr_edge), prev_recon);
  PutVopU (GetVopU (pr_edge), prev_recon);
  PutVopV (GetVopV (pr_edge), prev_recon);

  prev_recon->y_chan->f += GetVopWidth(pr_edge) * edge + edge;
  prev_recon->u_chan->f += (GetVopWidth(pr_edge)/2) * (edge/2) 
    + (edge/2);
  prev_recon->v_chan->f += (GetVopWidth(pr_edge)/2) * (edge/2) 
    + (edge/2);
	

  /* 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 = GetVopHorSpatRef(comp) - GetVopHorSpatRef(rec_prev)-edge;
  offset_y = GetVopVerSpatRef(comp) - GetVopVerSpatRef(rec_prev)-edge;

  prev_ipol += GetImageSizeX(pi) * 2 * offset_y + 2 * offset_x;
  prev_recon->y_chan->f += GetVopWidth(pr_edge) * offset_y + offset_x;
  prev_recon->u_chan->f += (GetVopWidth(pr_edge)/2) * (offset_y/2) 
    + (offset_x/2);
  prev_recon->v_chan->f += (GetVopWidth(pr_edge)/2) * (offset_y/2) 
    + (offset_x/2);

  /* Do the motion compensation */
  
  width_prev = GetImageSizeX(GetVopY(pr_edge));

  prev_x_min = 2*GetVopHorSpatRef(rec_prev)-2*GetVopHorSpatRef(comp)+2*edge;
  prev_y_min = 2*GetVopVerSpatRef(rec_prev)-2*GetVopVerSpatRef(comp)+2*edge;
  prev_x_max = prev_x_min + 2*width_prev-4*edge;
  prev_y_max = prev_y_min + 2*GetImageSizeY(GetVopY(pr_edge))-4*edge; 


  /* First we have to set all 4 vectors equal for
     the MBM_INTER16 case. This could/should have
     been done before entering this routine. */

  for (i = 0; i < height/mb_size; i++)
  {
      for (j = 0; j < width/mb_size; j++)
      {
	  mode = ModeMB(MB_decisions, j, i);
          /*
           * Clip motion vectors. Note this clips the vector used in
           * B-vop direct mode too (is this reasonable?).
           */
          offset_x = MB_SIZE * j;
          offset_y = MB_SIZE * i;
          imv = 2 * (j + i * mvwidth);
          switch (mode) {

          case MBM_INTER16:

            if (GetVopInterlaced(comp)) {
              x = offset_x + ((Int)(2 * mot_x->data->f[imv]) >> 1);
              if (x < -MB_SIZE)
                  mot_x->data->f[imv] = - MB_SIZE - offset_x;
              if (x > width)
                  mot_x->data->f[imv] = width - offset_x;
              y = offset_y + ((Int)(2 * mot_y->data->f[imv]) >> 1);
              if (y < -MB_SIZE)
                  mot_y->data->f[imv] = - MB_SIZE - offset_y;
              if (y > height)
                  mot_y->data->f[imv] = height - offset_y;
              }

              mot_x->data->f[imv + 1] = mot_x->data->f[imv + mvwidth] =
                  mot_x->data->f[imv + mvwidth + 1] = mot_x->data->f[imv];
              mot_y->data->f[imv + 1] = mot_y->data->f[imv + mvwidth] =
                  mot_y->data->f[imv + mvwidth + 1] = mot_y->data->f[imv];
              break;
        
          case MBM_INTER8:

            if (GetVopInterlaced(comp))
            {
              x = offset_x + ((Int)(2 * mot_x->data->f[imv]) >> 1);
              if (x < -MB_SIZE)
                  mot_x->data->f[imv] = - MB_SIZE - offset_x;
              if (x > width)
                  mot_x->data->f[imv] = width - offset_x;
              y = offset_y + ((Int)(2 * mot_y->data->f[imv]) >> 1);
              if (y < -MB_SIZE)
                  mot_y->data->f[imv] = - MB_SIZE - offset_y;
              if (y > height)
                  mot_y->data->f[imv] = height - offset_y;

              imv++;
              x = offset_x + ((Int)(2 * mot_x->data->f[imv]) >> 1);
              if (x < -MB_SIZE)
                  mot_x->data->f[imv] = - MB_SIZE - offset_x;
              if (x > width)
                  mot_x->data->f[imv] = width - offset_x;
              y = offset_y + ((Int)(2 * mot_y->data->f[imv]) >> 1);
              if (y < -MB_SIZE)
                  mot_y->data->f[imv] = - MB_SIZE - offset_y;
              if (y > height)
                  mot_y->data->f[imv] = height - offset_y;

              imv += mvwidth;
              x = offset_x + ((Int)(2 * mot_x->data->f[imv]) >> 1);
              if (x < -MB_SIZE)
                  mot_x->data->f[imv] = - MB_SIZE - offset_x;
              if (x > width)
                  mot_x->data->f[imv] = width - offset_x;
              y = offset_y + ((Int)(2 * mot_y->data->f[imv]) >> 1);
              if (y < -MB_SIZE)
                  mot_y->data->f[imv] = - MB_SIZE - offset_y;
              if (y > height)
                  mot_y->data->f[imv] = height - offset_y;

              imv--;
              x = offset_x + ((Int)(2 * mot_x->data->f[imv]) >> 1);
              if (x < -MB_SIZE)
                  mot_x->data->f[imv] = - MB_SIZE - offset_x;
              if (x > width)
                  mot_x->data->f[imv] = width - offset_x;
              y = offset_y + ((Int)(2 * mot_y->data->f[imv]) >> 1);
              if (y < -MB_SIZE)
                  mot_y->data->f[imv] = - MB_SIZE - offset_y;
              if (y > height)
                  mot_y->data->f[imv] = height - offset_y;
            }
              break;

          case MBM_FIELD00:
          case MBM_FIELD01:
          case MBM_FIELD10:
          case MBM_FIELD11:
              x = offset_x + ((Int)(2 * mot_x->data->f[imv]) >> 1);
              if (x < -MB_SIZE)
                  mot_x->data->f[imv] = - MB_SIZE - offset_x;
              if (x > width)
                  mot_x->data->f[imv] = width - offset_x;
              y = offset_y + ((Int)(2 * mot_y->data->f[imv]) >> 1);
              if (y < -MB_SIZE)
                  mot_y->data->f[imv] = - MB_SIZE - offset_y;
              if (y > height)
                  mot_y->data->f[imv] = height - offset_y;
              mot_x->data->f[imv + mvwidth] = mot_x->data->f[imv];
              mot_y->data->f[imv + mvwidth] = mot_y->data->f[imv];

              imv++;
              x = offset_x + ((Int)(2 * mot_x->data->f[imv]) >> 1);
              if (x < -MB_SIZE)
                  mot_x->data->f[imv] = - MB_SIZE - offset_x;
              if (x > width)
                  mot_x->data->f[imv] = width - offset_x;
              y = offset_y + ((Int)(2 * mot_y->data->f[imv]) >> 1);
              if (y < -MB_SIZE)
                  mot_y->data->f[imv] = - MB_SIZE - offset_y;
              if (y > height)
                  mot_y->data->f[imv] = height - offset_y;
              mot_x->data->f[imv + mvwidth] = mot_x->data->f[imv];
              mot_y->data->f[imv + mvwidth] = mot_y->data->f[imv];
              break;
						default: break;
          }
      }
  }	    

#ifdef _DEBUG_  
  /* CHECK THE VECTORS */
  fprintf(stdout,"Spat(%d,%d)\n",GetVopHorSpatRef(comp),GetVopVerSpatRef(comp));
 
  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_INTER8 || mode == MBM_INTER16)
	  {
	      if (mode == MBM_INTER8)
		  fprintf(stdout, "mode(%d,%d) = MBM_INTER8\n",j,i);
	      else
		  fprintf(stdout, "mode(%d,%d) = MBM_INTER16\n",j,i);

	      fprintf(stdout, "X: %5.2f %5.2f %5.2f %5.2f  ",
		      mot_x->data->f[4*i*width/MB_SIZE+j*2],
		      mot_x->data->f[4*i*width/MB_SIZE+j*2+1],
		      mot_x->data->f[(2*i+1)*2*width/MB_SIZE+j*2],
		      mot_x->data->f[(2*i+1)*2*width/MB_SIZE+j*2+1]);
	      fprintf(stdout, "\n");
	      fprintf(stdout, "Y: %5.2f %5.2f %5.2f %5.2f  ",
		      mot_y->data->f[4*i*width/MB_SIZE+j*2],
		      mot_y->data->f[4*i*width/MB_SIZE+j*2+1],
		      mot_y->data->f[(2*i+1)*2*width/MB_SIZE+j*2],
		      mot_y->data->f[(2*i+1)*2*width/MB_SIZE+j*2+1]);


	  }
	  fprintf(stdout, "\n\n"); 
      }
  } 
#endif	  
  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 || 
        ((mode >= MBM_FIELD00) && (mode <= MBM_FIELD11)) ||
		mode == MBM_SPRITE ||
		mode == MBM_SKIPPED) 
	    {		
	      x = j * mb_size;
	      y = i * mb_size;
				
        if (mode == MBM_INTER8 || mode == MBM_INTER16 
							|| mode == MBM_SKIPPED) 
{
    
                       		  /* Do overlapped motion compensation 8x8 */

		  /* Do Y-component first */
			overlap = (obmc_disable)?0:1;
				
                
	/* Minhua Zhou 14.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,
				    prev_ipol, &pred[0][0], 0, width,
				    width_prev, mb_size,overlap);
			  GetPred_Advanced (x, y, 
                                    prev_x_min,prev_y_min,prev_x_max,prev_y_max,
  				    mot_x, mot_y, MB_decisions,
				    alpha_decisions,
				    prev_ipol, &pred[0][8], 1, width,
				    width_prev, mb_size, overlap);
 			  GetPred_Advanced (x, y, 
                                    prev_x_min,prev_y_min,prev_x_max,prev_y_max,
                                    mot_x, mot_y, MB_decisions,
			            alpha_decisions,
				    prev_ipol, &pred[8][0], 2, width,
				    width_prev, mb_size, overlap);
         	 	 GetPred_Advanced (x, y, 
                                    prev_x_min,prev_y_min,prev_x_max,prev_y_max,
                                    mot_x, mot_y, MB_decisions,
			            alpha_decisions,
				    prev_ipol, &pred[8][8], 3, width,
				    width_prev, mb_size, overlap);
		  PutMB (x, y, pred, comp->y_chan, width, mb_size); 

		}
        else if ((mode >= MBM_FIELD00) && (mode <= MBM_FIELD11)) {
            GetPred_Field(j, i, mot_x, mot_y, edge, rec_prev->y_chan,
                comp->y_chan, mode - MBM_FIELD00, comp->rounding_type);
        }
 	      else if (/* mode == MBM_SKIPPED  
		       && */GetVopSpriteUsage(comp) != ONLINE_SPRITE 
		       && GetVopSpriteUsage(comp) != GMC_SPRITE) 
		{		
		  /* Do default motion compensation 16x16 */
		  GetPred_Default (x, y, mot_x, mot_y, prev_ipol, &pred[0],
			    width, width_prev, mb_size);
		  PutMB (x, y, pred, comp->y_chan, width, mb_size); 

		}	  
#ifndef _WD_MODE_	  
	      else if ( (mode==MBM_SPRITE || mode == MBM_SKIPPED)
		       && (GetVopSpriteUsage(comp) == ONLINE_SPRITE) )
		    {
		      FindGlobalPred (x, y, br_x, br_y, 
				      sprite, spadmos,
		      		      offset_mos_i0,offset_mos_j0, 
				      &pred[0], mb_size, sizex, sizey,
				      no_of_sprite_points, warpingaccuracy);  
		      PutMB (x, y, pred, comp->y_chan, width, mb_size); 
		    }
	      else if ( (mode==MBM_SPRITE || mode == MBM_SKIPPED)
		       && (GetVopSpriteUsage(comp) == GMC_SPRITE) )
		    {

		      FindGlobalPred (x, y, br_x, br_y, 
				      sprite, 
				      (SInt*) GetImageData(GetVopY(rec_prev)),
		      		      offset_mos_i0,offset_mos_j0, 
				      &pred[0], mb_size, sizex, sizey,
				      no_of_sprite_points, warpingaccuracy);  
		      PutMB (x, y, pred, comp->y_chan, width, mb_size); 
		    }
#endif
	      else
		{
		  /* Incorrect mode, give error message */
		  printf("VopMotionCompensate: Incorrect motion mode %d\n",
			 (int)mode);
		}
	    }               
	}
    }

  /* Do the Chrominance compensation */
  Compensate_Chroma (width_prev, mb_size, prev_recon, mot_x, mot_y,
                     prev_x_min/4,prev_y_min/4,prev_x_max/4,prev_y_max/4,
  		     mosaicvopedge, offset_mos_i0,offset_mos_j0, br_x, br_y,
		     sprite, no_of_sprite_points, warpingaccuracy,
		     MB_decisions, alpha_decisions, comp, edge);

  FreeImage (pi);
  SfreeVop (prev_recon);  
if (GetVopSpriteUsage(comp)==ONLINE_SPRITE)
	FreeVop(mosaicvopedge);
}

Void Equalise1MVMBs(Image *MB_decisions, Image *mot_x, Image *mot_y)
{
	Int width = GetImageSizeX(MB_decisions),
			height = GetImageSizeY(MB_decisions),
			i,j;
	
	SInt mode;
					
  for (i = 0; i < height; i++)
  {
      for (j = 0; j < width; j++)
      {
	  mode = ModeMB(MB_decisions, j, i);
	  if (mode == MBM_INTER16)
	  {
	      mot_x->data->f[4*i*width+j*2+1] =
		  mot_x->data->f[4*i*width+j*2];
	      mot_x->data->f[(2*i+1)*2*width+j*2] =
		  mot_x->data->f[4*i*width+j*2];
	      mot_x->data->f[(2*i+1)*2*width+j*2+1] =
		  mot_x->data->f[4*i*width+j*2]; 

	      mot_y->data->f[4*i*width+j*2+1] =
		  mot_y->data->f[4*i*width+j*2]; 
	      mot_y->data->f[(2*i+1)*2*width+j*2] =
		  mot_y->data->f[4*i*width+j*2]; 
	      mot_y->data->f[(2*i+1)*2*width+j*2+1] =
		  mot_y->data->f[4*i*width+j*2]; 
	  }
      }
  }	    
}


Void MotionCompensateMB(
							Vop *rec_prev,
							Image *pi,
							Image *mot_x,
							Image *mot_y,
							Int	j,
							Int i,
							Int 
advanced_prediction_disable,
							Image *alpha_decisions, 
							Image *MB_decisions,
							Vop *comp)
{
	Vop *pr_edge;

  Int width = GetVopWidth(comp);

  SInt pred[16][16];

	SInt *prev_ipol,
				*prev_u,
				*prev_v;

	Int x,y,overlap,edge, offset_x, offset_y, width_prev, mb_size=MB_SIZE;

  Int prev_x_min,prev_x_max,prev_y_min,prev_y_max;	

	SInt mode;	

  Int dx=0, dy=0;
  Int cols;
  Int xsum, ysum, divider;

  Int bmode;
  
  SInt *alpha;
  Float *xvec;
  Float *yvec;

for (y=0 ; y<16 ; y++)
for (x=0 ; x<16 ; x++)
  pred[j][i]=0;

  edge = 16;
  
  pr_edge = rec_prev;

  prev_ipol = (SInt *) GetImageData(pi) + GetImageSizeX(pi) * 2 * edge  
    + 2 * edge;

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

	prev_u = (SInt *) GetImageData(GetVopU(pr_edge));
	prev_v = (SInt *) GetImageData(GetVopV(pr_edge));

  prev_u += (GetVopWidth(pr_edge)/2) * (edge/2) 
    + (edge/2);
  prev_v += (GetVopWidth(pr_edge)/2) * (edge/2) 
    + (edge/2);

  /* 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 = GetVopHorSpatRef(comp) - GetVopHorSpatRef(rec_prev)-edge;
  offset_y = GetVopVerSpatRef(comp) - GetVopVerSpatRef(rec_prev)-edge;

  prev_ipol += GetImageSizeX(pi) * 2 * offset_y + 2 * offset_x;

  prev_u += (GetVopWidth(pr_edge)/2) * (offset_y/2) 
    + (offset_x/2);
  prev_v += (GetVopWidth(pr_edge)/2) * (offset_y/2) 
    + (offset_x/2);

  /* Do the motion compensation */
  
  width_prev = GetImageSizeX(GetVopY(pr_edge));

  prev_x_min = 2*GetVopHorSpatRef(rec_prev)-2*GetVopHorSpatRef(comp)+2*edge;
  prev_y_min = 2*GetVopVerSpatRef(rec_prev)-2*GetVopVerSpatRef(comp)+2*edge;
  prev_x_max = prev_x_min + 2*width_prev-4*edge;
  prev_y_max = prev_y_min + 2*GetImageSizeY(GetVopY(pr_edge))-4*edge; 


	mode = ModeMB(MB_decisions, j, i);


	if (mode == MBM_INTER16 || mode == MBM_INTER8 || 
		mode == MBM_SPRITE || mode == MBM_SKIPPED) 
		{		
			x = j * mb_size;
			y = i * mb_size;
				
			if (mode == MBM_INTER8 || mode == MBM_INTER16
							|| mode== MBM_SKIPPED) 
				{
		  		/* Do overlapped motion compensation 8x8 */

		  		/* Do Y-component first */
					overlap = 
(advanced_prediction_disable)?0:1;
                
					/* Minhua Zhou 14.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,
				   	 				
prev_ipol, &pred[0][0], 0, width,
				    				width_prev, 
mb_size,overlap);
			  	GetPred_Advanced (x, y, 
              			prev_x_min,prev_y_min,prev_x_max,prev_y_max,
  				    			mot_x, mot_y, 
MB_decisions,
				    				alpha_decisions,
				    				prev_ipol, 
&pred[0][8], 1, width,
				    				width_prev, 
mb_size, overlap);
 			  	GetPred_Advanced (x, y, 
                    prev_x_min,prev_y_min,prev_x_max,prev_y_max,
                    mot_x, mot_y, MB_decisions,
			            	alpha_decisions,
				    				prev_ipol, 
&pred[8][0], 2, width,
				    				width_prev, 
mb_size, overlap);
					GetPred_Advanced (x, y, 
                    prev_x_min,prev_y_min,prev_x_max,prev_y_max,
                    mot_x, mot_y, MB_decisions,
			            	alpha_decisions,
				    				prev_ipol, 
&pred[8][8], 3, width,
				    				width_prev, 
mb_size, overlap);
		  		PutMB (x, y, pred, comp->y_chan, width, 
mb_size); 

				}
			else if (/* mode == MBM_SKIPPED &&  */
	      		GetVopSpriteUsage(comp) != ONLINE_SPRITE) 
				{		
		  		/* Do default motion compensation 16x16 */
		  		GetPred_Default (x, y, mot_x, mot_y, prev_ipol, 
&pred[0],
			    						width, 
width_prev, mb_size);
		  		PutMB (x, y, pred, comp->y_chan, width, 
mb_size); 
				}	  
			else
				{
		  		/* Incorrect mode, give error message */
	printf("VopMotionCompensate: Incorrect motion mode %d\n",(int)mode);
				}
		}

  xvec = (Float *) GetImageData (mot_x);
  yvec = (Float *) GetImageData (mot_y);
  
  alpha = (SInt *) GetImageData (alpha_decisions);
  
  cols = width/mb_size;

	  /* 16 by 16 vectors or skipped MBs */
	  if (MB_decisions->data->s[i*cols+j] == MBM_INTER16 ||
	      MB_decisions->data->s[i*cols+j] == MBM_SKIPPED)
	    {
	      dx = 2 * xvec[(i*2)*cols*2+j*2];
	      dy = 2 * yvec[(i*2)*cols*2+j*2];
	      dx = ( dx % 4 == 0 ? dx >> 1 : (dx>>1)|1 );
	      dy = ( dy % 4 == 0 ? dy >> 1 : (dy>>1)|1 );
	      GetPred_Chroma1 (j*mb_size, i*mb_size, dx, dy, prev_u, prev_v,
			      comp, width, width_prev,
            prev_x_min/4,prev_y_min/4,prev_x_max/4,prev_y_max/4);
	    }
	  /* 8 by 8 vectors */
	  else if (MB_decisions->data->s[i*cols+j] == MBM_INTER8)
	    {
	      divider = xsum = ysum = 0;
	      bmode = alpha[i*4*cols+2*j];
	      if (bmode == 1 || bmode == 3 || bmode == 4 || bmode == 5)
		{
		  xsum += 2 * xvec[(i*2)*cols*2+j*2];
		  ysum += 2 * yvec[(i*2)*cols*2+j*2];
		  divider++;
		}

	      bmode = alpha[i*4*cols+2*j+1];
	      if (bmode == 1 || bmode == 3 || bmode == 4 || bmode == 5)
		{
		  xsum += 2 * xvec[(i*2)*cols*2+j*2+1];
		  ysum += 2 * yvec[(i*2)*cols*2+j*2+1];
		  divider++;
		}

	      bmode = alpha[(i*2+1)*2*cols+2*j];
	      if (bmode == 1 || bmode == 3 || bmode == 4 || bmode == 5)
		{
		  xsum += 2 * xvec[(i*2+1)*cols*2+j*2];
		  ysum += 2 * yvec[(i*2+1)*cols*2+j*2];
		  divider++;
		}

	      bmode = alpha[(i*2+1)*2*cols+2*j+1];
	      if (bmode == 1 || bmode == 3 || bmode == 4 || bmode == 5)
		{
		  xsum += 2 * xvec[(i*2+1)*cols*2+j*2+1];
		  ysum += 2 * yvec[(i*2+1)*cols*2+j*2+1];
		  divider++;
		}

	      switch (divider)
		{
		case 1:
		  dx = SIGN (xsum) * (roundtab4[ABS (xsum) % 4]
				     + (ABS (xsum) / 4) * 2);
		  dy = SIGN (ysum) * (roundtab4[ABS (ysum) % 4]
				     + (ABS (ysum) / 4) * 2);
		  break;
		case 2:
		  dx = SIGN (xsum) * (roundtab8[ABS (xsum) % 8]
				     + (ABS (xsum) / 8) * 2);
		  dy = SIGN (ysum) * (roundtab8[ABS (ysum) % 8]
				     + (ABS (ysum) / 8) * 2);
		  break;
		case 3:
		  dx = SIGN (xsum) * (roundtab12[ABS (xsum) % 12]
				     + (ABS (xsum) / 12) * 2);
		  dy = SIGN (ysum) * (roundtab12[ABS (ysum) % 12]
				     + (ABS (ysum) / 12) * 2);
		  break;
		case 4:
		  dx = SIGN (xsum) * (roundtab16[ABS (xsum) % 16]
				     + (ABS (xsum) / 16) * 2);
		  dy = SIGN (ysum) * (roundtab16[ABS (ysum) % 16]
				     + (ABS (ysum) / 16) * 2);
		  break;
		default:
		  fprintf (stderr, "Error in Compensate_Chroma (): No blocks inside the Vop for this macroblock %d,%d\n", (int)j, (int)i);
		  exit (-1);
		  break;
		}
	      GetPred_Chroma1 (j*mb_size, i*mb_size, dx, dy, prev_u, prev_v,
			      comp, width, 
width_prev,prev_x_min/4,prev_y_min/4,prev_x_max/4,prev_y_max/4);
	    }

#ifdef _DEBUG_  
	  mode = ModeMB(MB_decisions, j, i);
	  if (mode == MBM_INTER8 || mode == MBM_INTER16)
	  {
	      if (mode == MBM_INTER8)
		  fprintf(stdout, "mode(%d,%d) = MBM_INTER8\n",j,i);
	      else
		  fprintf(stdout, "mode(%d,%d) = MBM_INTER16\n",j,i);

	      fprintf(stdout, "X: %5.2f %5.2f %5.2f %5.2f  ",
		      mot_x->data->f[4*i*width/MB_SIZE+j*2],
		      mot_x->data->f[4*i*width/MB_SIZE+j*2+1],
		      mot_x->data->f[(2*i+1)*2*width/MB_SIZE+j*2],
		      mot_x->data->f[(2*i+1)*2*width/MB_SIZE+j*2+1]);
	      fprintf(stdout, "\n");
	      fprintf(stdout, "Y: %5.2f %5.2f %5.2f %5.2f  ",
		      mot_y->data->f[4*i*width/MB_SIZE+j*2],
		      mot_y->data->f[4*i*width/MB_SIZE+j*2+1],
		      mot_y->data->f[(2*i+1)*2*width/MB_SIZE+j*2],
		      mot_y->data->f[(2*i+1)*2*width/MB_SIZE+j*2+1]);


	  }
	  fprintf(stdout, "\n\n"); 
#endif
}

Void FillErrorMB(Vop *curr, Vop *rec_curr, Vop *pred, Vop *error, Int i, Int j)
{
	Image *currMB = AllocImage(MB_SIZE,MB_SIZE,SHORT_TYPE),
				*predMB = AllocSameImage(currMB),
				*errorMB = AllocSameImage(currMB),
 				*currCMB = 
AllocImage(MB_SIZE/2,MB_SIZE/2,SHORT_TYPE),
				*predCMB = AllocSameImage(currCMB),
				*errorCMB = AllocSameImage(currCMB);

	GetSubImage(GetVopY(curr),currMB,i*MB_SIZE,j*MB_SIZE);
	GetSubImage(GetVopY(pred),predMB,i*MB_SIZE,j*MB_SIZE);
	SubImage(currMB,predMB,errorMB);
	PutSubImage(GetVopY(error),errorMB,i*MB_SIZE,j*MB_SIZE);

	FreeImage(currMB);
	FreeImage(predMB);
	FreeImage(errorMB);

	GetSubImage(GetVopU(curr),currCMB,i*MB_SIZE/2,j*MB_SIZE/2);
	GetSubImage(GetVopU(pred),predCMB,i*MB_SIZE/2,j*MB_SIZE/2);
	SubImage(currCMB,predCMB,errorCMB);
	PutSubImage(GetVopU(error),errorCMB,i*MB_SIZE/2,j*MB_SIZE/2);

	GetSubImage(GetVopV(curr),currCMB,i*MB_SIZE/2,j*MB_SIZE/2);
	GetSubImage(GetVopV(pred),predCMB,i*MB_SIZE/2,j*MB_SIZE/2);
	SubImage(currCMB,predCMB,errorCMB);
	PutSubImage(GetVopV(error),errorCMB,i*MB_SIZE/2,j*MB_SIZE/2);
	FreeImage(currCMB);
	FreeImage(predCMB);
	FreeImage(errorCMB);
}

/***********************************************************CommentBegin******
 *
 * -- PutMB -- Puts a MB prediction into the compensated image 
 *
 * Author :		
 *	Robert Danielsen <Robert.Danielsen@nta.no>
 *
 * Created :		
 *	06.03.96
 *
 * Purpose :		
 *	Puts a MB prediction into the compensated image 
 * 
 * Arguments in : 	
 *	
 *
 * Arguments in/out :	
 *	
 *
 * Arguments out :	
 *	
 *
 * Return values :	
 *	
 *
 * Side effects :	
 *	
 *
 * Description :	
 *	
 *
 * See also :
 *	
 *
 * Modified :		
 *	
 *
 ***********************************************************CommentEnd********/

Void
PutMB (Int x,
       Int y,
       SInt pred[][16],
       Image *comp_image,
       Int width,
       Int mb_size)
{
  Int m, n;

  for (m = 0; m < mb_size; m++)
    for (n = 0; n < mb_size; n++)
      comp_image->f[(y+m)*width+x+n] = (SInt) pred[m][n];
}

/***********************************************************CommentBegin******
 *
 * -- Compensate_Chroma -- Does motion compensation for chrominance components
 *
 * Author :		
 *	Robert Danielsen <Robert.Danielsen@nta.no>
 *
 * Created :		
 *	06.03.96
 *
 * Purpose :		
 *	Does motion compensation for chrominance components
 * 
 * Arguments in : 	
 *	Int width_prev		Width of previous Vop instance
 *	Int mb_size		Macroblock size (usually 16)
 *	Vop mosaic		Online sprite pointer
 *	Int offset_i0, 
 *	Int offset_j0 		Change coordinates between sprite and VOP 
 *
 * Arguments in/out :	
 *	Vop *prev_image		Previous reconstructed image
 *	Image *mot_x		Motion vectors, x component
 *	Image *mot_y		Motion vectors, y component
 *	Image *MB_decisions	Macroblock modes
 *
 * Arguments out :	
 *	Vop *comp_Vop		Vop to be filled with compensated data
 *
 * Return values :	
 *	
 *
 * Side effects :	
 *	
 *
 * Description :	
 *	
 *
 * See also :
 *	
 *
 * Modified :		
 *	25.04.96 Added extra parameter 'width_prev' to allow operation
 *		when the compensated vop and the reference vop are of different
 *						sizes. Noel Brady.
 *	28.05.96 Robert Danielsen: Removed half_pel variable. Doubling the
 *		float vector directly instead.
 *	14.06.96: Robert Danielsen: Added alpha_information for correct
 *		calculation of the chroma vector in advanced motion mode.
 *		Also did a workaround for the mismatch in encoder and decoder
 *		macroblock and block modes.
 *	07-Feb-1997, M.Wollborn: changed in order to treat skipped MBs
 *		     correctly 
 *  11.12.97  Bob Eifrig  Added field motion compensation
 *
 ***********************************************************CommentEnd********/

Void
Compensate_Chroma (Int width_prev,
		   Int mb_size,
		   Vop *prev_image,
		   Image *mot_x,
		   Image *mot_y,
Int prev_x_min,Int prev_y_min,Int prev_x_max,Int prev_y_max,
		   Vop *mosaicvop,
		   Int offset_i0,
		   Int offset_j0,
		   Int br_x, Int br_y,
		   Vop *sprite,
		   Int no_of_sprite_points, 
		   Int warpingaccuracy,
		   Image *MB_decisions,
		   Image *alpha_decisions,
		   Vop *comp_Vop,
           Int edge)
{

  struct mvector {
    Int x;
    Int y;
  };

  Int i, j;
  Int dx=0, dy=0;
  Int cols;
  Int xsum, ysum, divider;

  Int bmode;
  
  SInt *alpha;
  Float *xvec;
  Float *yvec;
  
  Int width = GetVopWidth (comp_Vop);
  Int height = GetVopHeight (comp_Vop);

  xvec = (Float *) GetImageData (mot_x);
  yvec = (Float *) GetImageData (mot_y);
  
  alpha = (SInt *) GetImageData (alpha_decisions);
  
  cols = width/mb_size;
  
  for (i = 0; i < height/mb_size; i++)
    {
      for (j = 0; j < cols; j++)
	{

	  /* 16 by 16 vectors or skipped MBs */
	  if (MB_decisions->data->s[i*cols+j] == MBM_INTER16 ||
	      MB_decisions->data->s[i*cols+j] == MBM_SKIPPED)
	    {
	      dx = 2 * xvec[(i*2)*cols*2+j*2];
	      dy = 2 * yvec[(i*2)*cols*2+j*2];
	      dx = ( dx % 4 == 0 ? dx >> 1 : (dx>>1)|1 );
	      dy = ( dy % 4 == 0 ? dy >> 1 : (dy>>1)|1 );
	      GetPred_Chroma (j*mb_size, i*mb_size, dx, dy, prev_image,
			      comp_Vop, width, width_prev,
                              prev_x_min,prev_y_min,prev_x_max,prev_y_max);
	    }
        else if ((MB_decisions->data->s[i*cols+j] >= MBM_FIELD00) &&
                   (MB_decisions->data->s[i*cols+j] <= MBM_FIELD11)) {
                GetPred_Field_Chroma(j,i,xvec,yvec,prev_image,comp_Vop,
                    MB_decisions->data->s[i*cols+j]-MBM_FIELD00, edge);

        }
#ifndef _WD_MODE_
	  else
	    if (MB_decisions->data->s[i*cols+j] == MBM_SPRITE
		&& GetVopSpriteUsage(comp_Vop) == ONLINE_SPRITE)
	      {
		FindGlobalChromPred (j*mb_size, i*mb_size, br_x, br_y,
				     offset_i0, offset_j0, 
				     sprite,
				     no_of_sprite_points, warpingaccuracy,
				     mosaicvop, 
				     comp_Vop, width); 
	      }
	  else
	    if (MB_decisions->data->s[i*cols+j] == MBM_SPRITE
		&& GetVopSpriteUsage(comp_Vop) == GMC_SPRITE)
	      {
		FindGlobalChromPred (j*mb_size, i*mb_size, br_x, br_y,
				     offset_i0, offset_j0, 
				     sprite,
				     no_of_sprite_points, warpingaccuracy,
				     prev_image, 
				     comp_Vop, width); 
	      }
#endif
	  /* 8 by 8 vectors */
	  else if (MB_decisions->data->s[i*cols+j] == MBM_INTER8)
	    {
	      divider = xsum = ysum = 0;
	      bmode = alpha[i*4*cols+2*j];
	      if (bmode == 1 || bmode == 3 || bmode == 4 || bmode == 5)
		{
		  xsum += 2 * xvec[(i*2)*cols*2+j*2];
		  ysum += 2 * yvec[(i*2)*cols*2+j*2];
		  divider++;
		}

	      bmode = alpha[i*4*cols+2*j+1];
	      if (bmode == 1 || bmode == 3 || bmode == 4 || bmode == 5)
		{
		  xsum += 2 * xvec[(i*2)*cols*2+j*2+1];
		  ysum += 2 * yvec[(i*2)*cols*2+j*2+1];
		  divider++;
		}

	      bmode = alpha[(i*2+1)*2*cols+2*j];
	      if (bmode == 1 || bmode == 3 || bmode == 4 || bmode == 5)
		{
		  xsum += 2 * xvec[(i*2+1)*cols*2+j*2];
		  ysum += 2 * yvec[(i*2+1)*cols*2+j*2];
		  divider++;
		}

	      bmode = alpha[(i*2+1)*2*cols+2*j+1];
	      if (bmode == 1 || bmode == 3 || bmode == 4 || bmode == 5)
		{
		  xsum += 2 * xvec[(i*2+1)*cols*2+j*2+1];
		  ysum += 2 * yvec[(i*2+1)*cols*2+j*2+1];
		  divider++;
		}

	      switch (divider)
		{
		case 1:
		  dx = SIGN (xsum) * (roundtab4[ABS (xsum) % 4]
				     + (ABS (xsum) / 4) * 2);
		  dy = SIGN (ysum) * (roundtab4[ABS (ysum) % 4]
				     + (ABS (ysum) / 4) * 2);
		  break;
		case 2:
		  dx = SIGN (xsum) * (roundtab8[ABS (xsum) % 8]
				     + (ABS (xsum) / 8) * 2);
		  dy = SIGN (ysum) * (roundtab8[ABS (ysum) % 8]
				     + (ABS (ysum) / 8) * 2);
		  break;
		case 3:
		  dx = SIGN (xsum) * (roundtab12[ABS (xsum) % 12]
				     + (ABS (xsum) / 12) * 2);
		  dy = SIGN (ysum) * (roundtab12[ABS (ysum) % 12]
				     + (ABS (ysum) / 12) * 2);
		  break;
		case 4:
		  dx = SIGN (xsum) * (roundtab16[ABS (xsum) % 16]
				     + (ABS (xsum) / 16) * 2);
		  dy = SIGN (ysum) * (roundtab16[ABS (ysum) % 16]
				     + (ABS (ysum) / 16) * 2);
		  break;
		default:
		  fprintf (stderr, "Error in Compensate_Chroma (): No blocks inside the Vop for this macroblock %d,%d\n", (int)j, (int)i);
		  exit (-1);
		  break;
		}
	      GetPred_Chroma (j*mb_size, i*mb_size, dx, dy, prev_image,
			      comp_Vop, width, 
width_prev,prev_x_min,prev_y_min,prev_x_max,prev_y_max);
	    }
	}
    }
}  

/***********************************************************CommentBegin******
 *
 * -- ModeMB -- Get the MB mode 
 *
 * Author :		
 *	Noel Brady 
 *
 * Created :		
 *	
 *
 * Purpose :		
 *	Get the MB mode 
 * 
 * Arguments in : 	
 *	
 *
 * Arguments in/out :	
 *	
 *
 * Arguments out :	
 *	
 *
 * Return values :	
 *	
 *
 * Side effects :	
 *	
 *
 * Description :	
 *	
 *
 * See also :
 *	
 *
 * Modified :		
 *	
 *
 ***********************************************************CommentEnd********/

SInt ModeMB (Image *MB_decision, Int i, Int j)
{
  Int	width = MB_decision->x;
  SInt	*p = (SInt *)GetImageData(MB_decision);

  return p[width*j+i];
}

/***********************************************************CommentBegin******
 *
 * unrestricted_MC 
 *
 * Author :		
 *	Minhua Zhou 
 *
 * Created :		
 *	06.05.97
 *
 * Purpose :		
 *	To make unrestricted MC 
 *       
 * 
 * Arguments in : 	
 *	
 *
 * Arguments in/out :	
 *	
 *
 * Arguments out :	
 *	
 *
 * Return values :	
 *	
 *
 * Side effects :	
 *	
 *
 * Description :	
 *	
 *
 * See also :
 *	
 *
 * Modified :		
 *	
 *
 ***********************************************************CommentEnd********/
Int unrestricted_MC(Int x,Int y, Int npix,
                           Int prev_x_min,Int prev_y_min,
                           Int prev_x_max, Int prev_y_max) {
   
       if (x < prev_x_min) x = prev_x_min;
        else if (x >=prev_x_max-1) x = prev_x_max-2;
       if (y < prev_y_min) y = prev_y_min;
        else if (y >=prev_y_max-1) y = prev_y_max-2;
        return(x+y*npix);
   }

Int unrestricted_MC_chro(Int x,Int y, Int npix,
                           Int prev_x_min,Int prev_y_min,
                           Int prev_x_max, Int prev_y_max) {
   
       if (x < prev_x_min) x = prev_x_min;
        else if (x >=prev_x_max) x = prev_x_max-1;
       if (y < prev_y_min) y = prev_y_min;
        else if (y >=prev_y_max) y = prev_y_max-1;
        return(x+y*npix);
   }


/***********************************************************CommentBegin******
 *
 * -- GetPred_Advanced -- Performs overlapped block motion compensation
 *
 * Author :		
 *	Robert Danielsen <Robert.Danielsen@nta.no>
 *	Based on the correesponding function in the
 *	Telenor H.263 software by Karl Olav Lillevold.
 *
 * Created :		
 *	11.02.96 
 *
 * Purpose :		
 *	Performs overlapped block motion compensation for an 8x8
 *	block of the given macroblock.
 *	This is conditional on the macroblock coding modes.
 * 
 * Arguments in : 	
 *	Int x,y  - the address of top-left corner pixel of the MB
 *	Int prev_x_min,  
 *	Int prev_y_min,
 *	Int prev_x_max,
 *	Int prev_y_max, reference area
 *	Image *mot_x,mot_y  - images storing the floating point
 *		motion vectors for each block.
 *	Image *MB_decisions  - image storing the MB modes.
 *	SInt *prev  - pointer into the previous intepolated image.
 *	SInt comp  - number to indicate which block of the MB is
 *		to be processed.
 *		MB = 0 1
 *		     2 3
 *	Int width  - width of the current image/vop e.g 176,352.
 *	Int width_prev  - width of the previous image/vop (not the interpolated
 *											
 image/vop
 *	SInt mb_size  - the MB width/height e.g. 16. 
 *  SInt overlap - a flag which can be used to disable the overlapped 
 *										
filtering
 *
 * Arguments in/out :	
 *	
 *
 * Arguments out :	
 *	SInt *pred  - array of size 64 for storing the
 *		prediction block	
 *
 * Return values :	
 *	none
 *
 * Side effects :	
 *	
 *
 * Description :	
 *	
 *
 * See also :
 *	
 *
 * Modified :		
 *	12.04.96 Descriptive text from Noel Brady.
 *  	25.04.96 Extra parameter 'width_prev' added to enable operation when
 *			current and previous images/vops are not the same size.
 *	28.05.96 Robert Danielsen: Removed half_pel variable, doubling the
 *		float vector directly instead.
 *		Changed 'xmb' to 'xmb+1' in assignment of r8.
 *	10.06.96 Robert Danielsen: Included more correct treatment of
 *		surrounding Intra and Transparent macroblocks.
 *	14.06.96 Robert Danielsen: Workaround for mismatch in encoder
 *		and decoder macroblock and block modes.
 *      14.04.97 Minhua Zhou: Corrections of remote vector selections 
 *                (top/left/right/bottom) for overlapped MC 
 *	06.05.97 Minhua Zhou: added "unstricted motion compensation" of VM7.0
 *      06.05.97 Minhua zhou: BUG VM6-970425-02 solved
 *			19.11.97 Noel Brady: modified to handle kipped remote 
MBs correctly
 *  11.12.97 Bob Eifrig Added code to compute the rounded average of field
 *      motion vectors if an adjanct MB is field predicted.
 ***********************************************************CommentEnd********/


Void
GetPred_Advanced (Int x,
		  Int y,
		  Int prev_x_min,  /* Added by Minhua Zhou 14.04.97 */
		  Int prev_y_min,
		  Int prev_x_max,
		  Int prev_y_max,
		  Image *mot_x,
		  Image *mot_y,
		  Image *MB_decisions, 
                  Image *alpha_decisions,
		  SInt* prev,
		  SInt* pred,
		  SInt comp,
		  Int width,
		  Int width_prev, 
		  SInt mb_size,
			SInt overlap)
{
  struct mvector {
    Int x;
    Int y;
  };

  Int m, n;
  Int pc,pt,pb,pr,pl;
  Int nxc,nxt,nxb,nxr,nxl;
  Int nyc,nyt,nyb,nyr,nyl;
  Int xit,xib,xir,xil;
  Int yit,yib,yir,yil;
  Int vecc,vect,vecb,vecr,vecl;
  Int c8,t8,l8,r8;
  Int xmb, ymb, lx;
  struct mvector fc, ft, fb, fr, fl;
  Int cols, a, b, i, j;

  /* In the following variable names, the letters c,t,b,r and l stand for
     center, top, bottom, right and left. This reflects the overlapped
     compensation process. */
  
  Int Mc[8][8] = {
    {4,5,5,5,5,5,5,4},
    {5,5,5,5,5,5,5,5},
    {5,5,6,6,6,6,5,5},
    {5,5,6,6,6,6,5,5},
    {5,5,6,6,6,6,5,5},
    {5,5,6,6,6,6,5,5},
    {5,5,5,5,5,5,5,5},
    {4,5,5,5,5,5,5,4},
  };
  Int Mt[8][8] = {
    {2,2,2,2,2,2,2,2},
    {1,1,2,2,2,2,1,1},
    {1,1,1,1,1,1,1,1},
    {1,1,1,1,1,1,1,1},
    {0,0,0,0,0,0,0,0},
    {0,0,0,0,0,0,0,0},
    {0,0,0,0,0,0,0,0},
    {0,0,0,0,0,0,0,0},
  };
  Int Mb[8][8] = {
    {0,0,0,0,0,0,0,0},
    {0,0,0,0,0,0,0,0},
    {0,0,0,0,0,0,0,0},
    {0,0,0,0,0,0,0,0},
    {1,1,1,1,1,1,1,1},
    {1,1,1,1,1,1,1,1},
    {1,1,2,2,2,2,1,1},
    {2,2,2,2,2,2,2,2},
  };
  Int Mr[8][8] = {
    {0,0,0,0,1,1,1,2},
    {0,0,0,0,1,1,2,2},
    {0,0,0,0,1,1,2,2},
    {0,0,0,0,1,1,2,2},
    {0,0,0,0,1,1,2,2},
    {0,0,0,0,1,1,2,2},
    {0,0,0,0,1,1,2,2},
    {0,0,0,0,1,1,1,2},
  };
  Int Ml[8][8] = {
    {2,1,1,1,0,0,0,0},
    {2,2,1,1,0,0,0,0},
    {2,2,1,1,0,0,0,0},
    {2,2,1,1,0,0,0,0},
    {2,2,1,1,0,0,0,0},
    {2,2,1,1,0,0,0,0},
    {2,2,1,1,0,0,0,0},
    {2,1,1,1,0,0,0,0},
  };

  xmb = x/mb_size;
  ymb = y/mb_size;

  cols = width/mb_size;

  lx = width_prev;

  if(!((xmb >= 0) && (ymb >= 0)))
	{
		fprintf(stderr,"ERROR : xmb < 0 or ymb <0\n");
		exit(1);
	}
  
  c8 = t8 = l8 = r8 = 0;

  /* Set flags for the center, top, left and right positions to indicate
     whether they contain 8x8 vectors or not. */

  /* Center */
  switch (MB_decisions->data->s[ymb*cols+xmb])
    {
    case MBM_INTER8:
      c8 = 2; break;
    case MBM_INTER16:
      c8 = 2; break;
    case MBM_SKIPPED:
      c8 = 2; break;
    default:
      /* Should always be in Inter-mode for the block to be coded in
	 advanced mode. */
      fprintf (stderr, "Error, non-inter MB in GetPred_Advanced ()\n");
      exit (-1);
      break;
    }

  /* A workaround for the difference in the assignation of transparent
     mode on encoder and decoder is that I take both MBM_TRANSPARENT
     (which equals 2) and the number 6 (which is transparent for decoder)
     to mean the same below. */

  /* Top */
  if (ymb > 0)
    {
      switch (MB_decisions->data->s[(ymb-1)*cols+xmb])
	{
	case MBM_INTRA:
	  t8 = 1; break;
	case MBM_TRANSPARENT:
	  t8 = 1; break;
	case 6:
	  t8 = 2; break;
	case MBM_INTER8:
	  t8 = 2; break;
	case MBM_INTER16:
	  t8 = 2; break;
    case MBM_FIELD00:
    case MBM_FIELD01:
    case MBM_FIELD10:
    case MBM_FIELD11:
      t8 = 3; break;
	default:
	  t8 = 0; break;
	}
    }
  else
    {
      t8 = 1;
    }


  /* Left */
  if (xmb > 0)
    {
      switch (MB_decisions->data->s[ymb*cols+xmb-1])
	{
	case MBM_INTRA:
	  l8 = 1; break;
	case MBM_TRANSPARENT:
	  l8 = 1; break;
	case 6:
	  l8 = 2; break;
	case MBM_INTER8:
	  l8 = 2; break;
	case MBM_INTER16:
	  l8 = 2; break;
    case MBM_FIELD00:
    case MBM_FIELD01:
    case MBM_FIELD10:
    case MBM_FIELD11:
      l8 = 3; break;
	default:
	  l8 = 0; break;
	}
    }
  else
    {
      l8 = 1;
    }

  /* Right */
  if (xmb < (cols - 1))
    {
      switch (MB_decisions->data->s[ymb*cols+xmb+1])
	{
	case MBM_INTRA:
	  r8 = 1; break;
	case MBM_TRANSPARENT:
	  r8 = 1; break;
	case 6:
	  r8 = 2; break;
	case MBM_INTER8:
	  r8 = 2; break;
	case MBM_INTER16:
	  r8 = 2; break;
    case MBM_FIELD00:
    case MBM_FIELD01:
    case MBM_FIELD10:
    case MBM_FIELD11:
      r8 = 3; break;
	default:
	  r8 = 0; break;
	}
    }
  else
    {
      r8 = 1;
    }

  /* Find the correct positions to get the vectors from for the
     surrounding blocks. (Which 8x8 vector in a 16x16 block etc.) */

  vecc = comp;			/* Central position same as comp */
  
  switch (comp)
    {
    case 0:
      /* Top */
      if (t8 == 0)
	{
	  vect = 0;
	  yit = ymb-1; xit = xmb;
	}
      else if (t8 == 1)
	{
	  vect = vecc;
	  yit = ymb; xit = xmb;
	}
      else
	{
	  vect = 2;
	  yit = ymb-1; xit = xmb;
	}
      
      /* Bottom */
      if (c8 == 0)
	vecb = 0;
      else if (c8 == 1)
	vecb = vecc;
      else
	vecb = 2;
      yib = ymb   ; xib = xmb;

      /* Left */
      if (l8 == 0)
	{
	  vecl = 0;
	  yil = ymb   ; xil = xmb-1;
	}
      else if (l8 == 1)
	{
	  vecl = vecc;
	  yil = ymb   ; xil = xmb;
	}
      else
	{
	  vecl = 1;
	  yil = ymb   ; xil = xmb-1;
	}

      /* Right */
      if (c8 == 0)
	vecr = 0;
      else if (c8 == 1)
	vecr = vecc;
      else
	vecr = 1;
      yir = ymb   ; xir = xmb;
      r8 = c8;
      break;

    case 1:
      /* Top */
      if (t8 == 0)
	{
	  vect = 0;
	  yit = ymb-1 ; xit = xmb;
	}
      else if (t8 == 1)
	{
	  vect = vecc;
	  yit = ymb; xit = xmb;
	}
      else
	{
	  vect = 3;
	  yit = ymb-1 ; xit = xmb;
	}

      /* Bottom */
      if (c8 == 0)
	vecb = 0;
      else if (c8 == 1)
	vecb = vecc;
      else
	vecb = 3;
      yib = ymb   ; xib = xmb;

      /* Left */
      if (c8 == 0)
	vecl = 0;
      else if (c8 == 1)
	vecl = vecc;
      else
	vecl = 0;
      yil = ymb   ; xil = xmb;
      l8 = c8;

      /* Right */
      if (r8 == 0)
	{
	  vecr = 0;
	  yir = ymb   ; xir = xmb+1;
	}
      else if (r8 == 1)
	{
	  vecr = vecc;
	  yir = ymb   ; xir = xmb;
	}
      else
	{
	  vecr = 0;
	  yir = ymb   ; xir = xmb+1;
	}
      break;

    case 2:
      /* Top */
      if (c8 == 0)
	vect = 0;
      else if (c8 == 1)
	vect = vecc;
      else
	vect = 0;
      yit = ymb ; xit = xmb;
      t8 = c8;

      /* Bottom */
      if (c8 == 0)
	vecb = 0;
      else if (c8 == 1)
	vecb = vecc;
      else
	vecb = 2;
      yib = ymb   ; xib = xmb;

      /* Left */
      if (l8 == 0)
	{
	  vecl = 0;
	  yil = ymb   ; xil = xmb-1;
	}
      else if (l8 == 1)
	{
	  vecl = vecc;
	  yil = ymb   ; xil = xmb;
	}
      else
	{
	  vecl = 3;
	  yil = ymb   ; xil = xmb-1;
	}

      /* Right */
      if (c8 == 0)
	vecr = 0;
      else if (c8 == 1)
	vecr = vecc;
      else
	vecr = 3;
      yir = ymb   ; xir = xmb;
      r8 = c8;
      break;

    case 3:
      /* Top */
      if (c8 == 0)
	vect = 0;
      else if (c8 == 1)
	vect = vecc;
      else
	vect = 1;
      yit = ymb ; xit = xmb;
      t8 = c8;

      /* Bottom */
      if (c8 == 0)
	vecb = 0;
      else if (c8 == 1)
	vecb = vecc;
      else
	vecb = 3;
      yib = ymb   ; xib = xmb;

      /* Left */
      if (c8 == 0)
	vecl = 0;
      else if (c8 == 1)
	vecl = vecc;
      else
	vecl = 2;
      yil = ymb   ; xil = xmb;
      l8 = c8;

      /* Right */
      if (r8 == 0)
	{
	  vecr = 0;
	  yir = ymb   ; xir = xmb+1;
	}
      else if (r8 == 1)
	{
	  vecr = vecc;
	  yir = ymb   ; xir = xmb;
	}
      else
	{
	  vecr = 2;
	  yir = ymb   ; xir = xmb+1;
	}
      break;

    default:
      fprintf(stderr,"Illegal block number in GetPred_Advanced (pred.c)\n");
      exit(1);
      break;
    }

  /* Get the correct vector components from the surrounding blocks,
     to be used for the overlapped compensation calculation.
     The 8x8 vector to get depends on the positions found above. */

  /* Center position first */
  i = ymb;
  j = xmb;

  switch (vecc)
    {
    case 0: a = 0; b = 0; break;
    case 1: a = 0; b = 1; break;
    case 2: a = 1; b = 0; break;
    case 3: a = 1; b = 1; break;
    default:
      fprintf (stderr, "Error in GetPred_Advanced. Exiting...\n");
      exit (-1);
    }

/* Minhua ZHOU (HHI) 14.04.97  ; Angel Pacheco (UPM): 09:06:97 */
if ((alpha_decisions->data->s[(i*2+a)*cols*2+j*2+b]==0)||
    (alpha_decisions->data->s[(i*2+a)*cols*2+j*2+b]==MBM_TRANSPARENT)) 
       return;
 

  fc.x = 2 * mot_x->data->f[(i*2+a)*cols*2+j*2+b];
  fc.y = 2 * mot_y->data->f[(i*2+a)*cols*2+j*2+b];

  /* Top */
  i = yit;
  j = xit;

  switch (vect)
    {
    case 0: a = 0; b = 0; break;
    case 1: a = 0; b = 1; break;
    case 2: a = 1; b = 0; break;
    case 3: a = 1; b = 1; break;
    default: fprintf (stderr, "Error in GetPred_Advanced. Exiting...\n"); exit 
(-1);
    }
	
 
  /* Minhua ZHOU (HHI) 14.04.97  Angel Pacheco (UPM) 09.06.97 */
  if((alpha_decisions->data->s[(i*2+a)*cols*2+j*2+b]!=0)&&
     (alpha_decisions->data->s[(i*2+a)*cols*2+j*2+b]!=MBM_TRANSPARENT)) {
    if (t8 == 3) {              /* Neighbor is interlaced; average two field 
vectors */
        ft.x = 2 * (mot_x->data->f[4*i*cols + 2*j] + mot_x->data->f[4*i*cols + 
2*j + 1]);
        ft.y = 2 * (mot_y->data->f[4*i*cols + 2*j] + mot_y->data->f[4*i*cols + 
2*j + 1]);
        ft.x = (ft.x & 3) ? ((ft.x | 2) >> 1) : (ft.x >> 1);
        ft.y = (ft.y & 3) ? ((ft.y | 2) >> 1) : (ft.y >> 1);
    } else {
        ft.x = 2 * mot_x->data->f[(i*2+a)*cols*2+j*2+b];
        ft.y = 2 * mot_y->data->f[(i*2+a)*cols*2+j*2+b];
    }
  } else {
    ft.x = fc.x;
    ft.y = fc.y;
  } 
 
  /* Bottom */
  i = yib;
  j = xib;

  switch (vecb)
    {
    case 0: a = 0; b = 0; break;
    case 1: a = 0; b = 1; break;
    case 2: a = 1; b = 0; break;
    case 3: a = 1; b = 1; break;
    default: fprintf (stderr, "Error in GetPred_Advanced. Exiting...\n"); exit 
(-1);
    }
  /* Minhua ZHOU (HHI) 14.04.97  Angel Pacheco (UPM) 09.06.97 */
   if ((alpha_decisions->data->s[(i*2+a)*cols*2+j*2+b]!=0)&&
       (alpha_decisions->data->s[(i*2+a)*cols*2+j*2+b]!=MBM_TRANSPARENT)){
    fb.x = 2 * mot_x->data->f[(i*2+a)*cols*2+j*2+b];
    fb.y = 2 * mot_y->data->f[(i*2+a)*cols*2+j*2+b];
  } else {
    fb.x = fc.x;
    fb.y = fc.y;
  } 
  
  /* Right */
  i = yir;
  j = xir;
  
  switch (vecr)
    {
    case 0: a = 0; b = 0; break;
    case 1: a = 0; b = 1; break;
    case 2: a = 1; b = 0; break;
    case 3: a = 1; b = 1; break;
    default: fprintf (stderr, "Error in GetPred_Advanced. Exiting...\n"); exit 
(-1);
    }
  /* Minhua ZHOU (HHI) 14.04.97  Angel Pacheco (UPM) 09.06.97 */
   if ((alpha_decisions->data->s[(i*2+a)*cols*2+j*2+b]!=0)&&
       (alpha_decisions->data->s[(i*2+a)*cols*2+j*2+b]!=MBM_TRANSPARENT)) {
    if (r8 == 3) {              /* Neighbor is interlaced; average two field 
vectors */
        fr.x = 2 * (mot_x->data->f[4*i*cols + 2*j] + mot_x->data->f[4*i*cols + 
2*j + 1]);
        fr.y = 2 * (mot_y->data->f[4*i*cols + 2*j] + mot_y->data->f[4*i*cols + 
2*j + 1]);
        fr.x = (fr.x & 3) ? ((fr.x | 2) >> 1) : (fr.x >> 1);
        fr.y = (fr.y & 3) ? ((fr.y | 2) >> 1) : (fr.y >> 1);
    } else {
        fr.x = 2 * mot_x->data->f[(i*2+a)*cols*2+j*2+b];
        fr.y = 2 * mot_y->data->f[(i*2+a)*cols*2+j*2+b];
    }
  } else {
    fr.x = fc.x;
    fr.y = fc.y;
  } 
  /* Left */
  i = yil;
  j = xil;

  switch (vecl)
    {
    case 0: a = 0; b = 0; break;
    case 1: a = 0; b = 1; break;
    case 2: a = 1; b = 0; break;
    case 3: a = 1; b = 1; break;
    default: fprintf (stderr, "Error in GetPred_Advanced. Exiting...\n"); exit 
(-1);
    }
 /* Minhua ZHOU (HHI) 14.04.97 Angel Pacheco (UPM) 09.06.97 */
   if ((alpha_decisions->data->s[(i*2+a)*cols*2+j*2+b]!=0)&&
       (alpha_decisions->data->s[(i*2+a)*cols*2+j*2+b]!=MBM_TRANSPARENT)) {
    if (l8 == 3) {              /* Neighbor is interlaced; average two field 
vectors */
        fl.x = 2 * (mot_x->data->f[4*i*cols + 2*j] + mot_x->data->f[4*i*cols + 
2*j + 1]);
        fl.y = 2 * (mot_y->data->f[4*i*cols + 2*j] + mot_y->data->f[4*i*cols + 
2*j + 1]);
        fl.x = (fl.x & 3) ? ((fl.x | 2) >> 1) : (fl.x >> 1);
        fl.y = (fl.y & 3) ? ((fl.y | 2) >> 1) : (fl.y >> 1);
    } else {
        fl.x = 2 * mot_x->data->f[(i*2+a)*cols*2+j*2+b];
        fl.y = 2 * mot_y->data->f[(i*2+a)*cols*2+j*2+b];
    }
  } else {
    fl.x = fc.x;
    fl.y = fc.y;
  } 
  /* Set the initial positions for the vectors
     (center, top, bottom, right, left) */
  
  nxc = 2*x + ((comp&1)<<4); nyc = 2*y + ((comp&2)<<3);
  nxt = nxb = nxr = nxl = nxc;
  nyt = nyb = nyr = nyl = nyc;


  /* Now add the vector components to the initial positions to get the
     target positions */
  
  nxc += fc.x; nyc += fc.y;
  nxt += ft.x; nyt += ft.y;
  nxb += fb.x; nyb += fb.y;
  nxr += fr.x; nyr += fr.y;
  nxl += fl.x; nyl += fl.y;
 
   /* Calculate and fill in the prediction data for this 8x8 block */
  
  for (n = 0; n < 8; n++)
    {
      for (m = 0; m < 8; m++)
	{
	  /* Find interpolated pixel-values corresponding to the
	     central and surrounding positions. Use the weighting tables. */
		if (overlap) 
                 /* changed by Minhua Zhou 14.04.1997 */
		     {
                        if (Mc[n][m]) 
	  			pc = *(prev + unrestricted_MC(nxc+2*m,nyc + 
2*n,lx*2, 			
				       
prev_x_min,prev_y_min,prev_x_max,prev_y_max)) * Mc[n][m];
                                 else pc =0;
                        if (Mt[n][m])
	  			pt = *(prev + unrestricted_MC(nxt+2*m,nyt + 
2*n,lx*2, 			
				       
prev_x_min,prev_y_min,prev_x_max,prev_y_max)) * Mt[n][m];
                                 else pt =0;
                        if (Mb[n][m]) 
	  			pb = *(prev + unrestricted_MC(nxb+2*m,nyb + 
2*n,lx*2, 			
				       
prev_x_min,prev_y_min,prev_x_max,prev_y_max)) * Mb[n][m];
                                 else pb =0;
                        if (Mr[n][m])
	  			pr = *(prev + unrestricted_MC(nxr+2*m,nyr + 
2*n,lx*2, 			
				       
prev_x_min,prev_y_min,prev_x_max,prev_y_max)) * Mr[n][m];
                                 else pr =0;
                        if (Ml[n][m])
	  			pl = *(prev + unrestricted_MC(nxl+2*m,nyl + 
2*n,lx*2, 			
				       
prev_x_min,prev_y_min,prev_x_max,prev_y_max)) * Ml[n][m];
                                 else pl =0;
 	  	/* Calculate the overlapped compensated values based on the
	  	   above weighted values. Fill pred with these. */
	  	*(pred + m + n * mb_size) = (pc+pt+pb+pr+pl+4)>>3;
			}
		else *(pred + m + n * mb_size) = 
                                      *(prev + unrestricted_MC(nxc+2*m,nyc + 
2*n,lx*2, 			
				       
prev_x_min,prev_y_min,prev_x_max,prev_y_max));
	}	
    }
  return;
}


/***********************************************************CommentBegin******
 *
 * -- GetPred_Default -- Find the prediction block
 *
 * Author :		
 *	Karl.Lillevold@nta.no
 *
 * Created :		
 *	930126
 *
 * Purpose :		
 *	Find the prediction block
 * 
 * Arguments in : 	
 *	position, vector, array for prediction
 *	pointer to previous interpolated luminance,
 *
 * Arguments in/out :	
 *	
 *
 * Arguments out :	
 *	
 *
 * Return values :	
 *	
 *
 * Side effects :	
 *	fills array with prediction
 *
 * Description :	
 *	
 *
 * See also :
 *	
 *
 * Modified :		
 *	950208    Mod: Karl.Lillevold@nta.no
 *	960502	Modified to Momusys-structures. Robert Danielsen
 *
 ***********************************************************CommentEnd********/

Void
GetPred_Default (Int x, Int y, Image *mot_x, Image *mot_y, SInt *prev, 
	  SInt pred[][16], Int width, Int width_prev, Int mb_size)
{
  Int m, n;
  Int new_x, new_y;			/* MC pel position in half-pixels */
  Int lx;
  Int cols;
  Int mx, my;
  Float	dx_hp,dy_hp;		/* MV in half-pixels */


  lx = width_prev;

  mx = x / mb_size;
  my = y / mb_size;
  
  cols = width / mb_size;
  
  dx_hp = mot_x->data->f[my*2*cols*2 + mx*2] * 2;
  dy_hp = mot_y->data->f[my*2*cols*2 + mx*2] * 2;

  new_x = 2*x + dx_hp;
  new_y = 2*y + dy_hp;

  /* Fill pred. data */
  for (n = 0; n < mb_size; n++)
    {
      for (m = 0; m < mb_size; m++)
	{
	  /* Find interpolated pixel-value */
	  pred[n][m] = *(prev + (new_x + 2*m) + (new_y + 2*n)*2*lx);
	}	
    }
  return;
}

/***********************************************************CommentBegin******
 *
 * -- GetPred_Field -- Find the prediction block
 *
 * Author :
 *  Bob Eifrig
 *
 * Created :
 *  21-jan-97
 *
 * Purpose :
 *  Find the prediction for a field
 *
 * Arguments in :
 *  position, vector, array for prediction
 *  pointer to previous interpolated luminance,
 *
 * Arguments in/out :
 *
 *
 * Arguments out :
 *
 *
 * Return values :
 *
 *
 * Side effects :
 *  fills array with prediction
 *
 * Description :
 *
 *
 * See also :
 *
 *
 * Modified :
 *
 ***********************************************************CommentEnd********/
 
Void
GetPred_Field(Int mbx, Int mby, Image *mot_x, Image *mot_y, Int edge,
      Image *ref, Image *pred, Int how, Int rounding_control)
{
    Int code, k, dx, dy, x, y, round;
    Int rwidth, pwidth, rwidth2, pwidth2;
    SInt *pRef, *pPred;
    Float *mvx, *mvy;
 
    k = 2*mbx + 2*mby*GetImageSizeX(mot_x);
    mvx = (Float *)GetImageData(mot_x) + k;
    mvy = (Float *)GetImageData(mot_y) + k;
 
    mbx *= MB_SIZE;
    mby *= MB_SIZE;
 
    pwidth  = GetImageSizeX(pred);
    pwidth2 = pwidth << 1;
    rwidth  = GetImageSizeX(ref);
    rwidth2 = rwidth << 1;
 
    /*
     * Motion compensate the top field
     */
 
    dx = (Int)(2*mvx[0]);
    dy = (Int)(2*mvy[0]);
    if (dy & 1)
       fprintf(stderr, "Top Field MV[%d %d] (ref=%s) Y is odd: %d\n",
            mbx, mby, (how & 2) ? "Bot" : "Top", dy);
    code = (dx & 1) | (dy & 2);
    dx >>= 1;
    dy = (dy >> 1) & ~1;
    if (how & 2) dy++;
 
    pPred = (SInt *)GetImageData(pred) + mbx + mby*pwidth;
 
    pRef = (SInt *)GetImageData(ref) +
        (mbx + dx + edge) + (mby + dy + edge) * rwidth;
 
    switch (code) {
 
    case 0:                                         /* no interp */
        for (y = 0; y < MB_SIZE; y += 2) {
          for (x = 0; x < MB_SIZE; x++)
            pPred[x] = pRef[x];
          pPred += pwidth2;
          pRef  += rwidth2;
        }
        break;
 
    case 1:                                         /* horizontal interp */
        round = 1 - rounding_control;
        for (y = 0; y < MB_SIZE; y += 2) {
          for (x = 0; x < MB_SIZE; x++)
            pPred[x] = (pRef[x] + pRef[x + 1] + round) >> 1;
          pPred += pwidth2;
          pRef  += rwidth2;
        }
        break;
 
    case 2:                                         /* vertical interp */
        round = 1 - rounding_control;
        for (y = 0; y < MB_SIZE; y += 2) {
          for (x = 0; x < MB_SIZE; x++)
            pPred[x] = (pRef[x] + pRef[x + rwidth2] + round) >> 1;
          pPred += pwidth2;
          pRef  += rwidth2;
        }
        break;
 
    case 3:                                         /* horiz & vert interp */
        round = 2 - rounding_control;
        for (y = 0; y < MB_SIZE; y += 2) {
          for (x = 0; x < MB_SIZE; x++)
            pPred[x] = (pRef[x] + pRef[x + 1] +
                pRef[x + rwidth2] + pRef[x + rwidth2 + 1] + round) >> 2;
          pPred += pwidth2;
          pRef  += rwidth2;
        }
        break;
    }
 
    /*
     * Motion compensate the bottom field
     */
 
    dx = (Int)(2*mvx[1]);
    dy = (Int)(2*mvy[1]);
    if (dy & 1)
       fprintf(stderr, "Bottom Field MV[%d %d] (ref=%s) Y is odd: %d\n",
            mbx, mby, (how & 1) ? "Bot" : "Top", dy);
    code = (dx & 1) | (dy & 2);
    dx >>= 1;
    dy = (dy >> 1) & ~1;
    if (how & 1) dy++;
 
    pPred = (SInt *)GetImageData(pred) + mbx + (mby + 1)*pwidth;
 
    pRef = (SInt *) GetImageData(ref) +
        (mbx + dx + edge) + (mby + dy + edge)*rwidth;
 
    switch (code) {
 
    case 0:                                         /* no interp */
        for (y = 0; y < MB_SIZE; y += 2) {
            for (x = 0; x < MB_SIZE; x++)
                pPred[x] = pRef[x];
            pPred += pwidth2;
            pRef  += rwidth2;
        }
        break;
 
    case 1:                                         /* horizontal interp */
        round = 1 - rounding_control;
        for (y = 0; y < MB_SIZE; y += 2) {
          for (x = 0; x < MB_SIZE; x++)
            pPred[x] = (pRef[x] + pRef[x + 1] + round) >> 1;
            pPred += pwidth2;
            pRef  += rwidth2;
        }
        break;
 
    case 2:                                         /* vertical interp */
        round = 1 - rounding_control;
        for (y = 0; y < MB_SIZE; y += 2) {
          for (x = 0; x < MB_SIZE; x++)
            pPred[x] = (pRef[x] + pRef[x + rwidth2] + round) >> 1;
          pPred += pwidth2;
          pRef  += rwidth2;
        }
        break;
 
    case 3:                                         /* horiz & vert interp */
        round = 2 - rounding_control;
        for (y = 0; y < MB_SIZE; y += 2) {
          for (x = 0; x < MB_SIZE; x++)
            pPred[x] = (pRef[x] + pRef[x + 1] +
                pRef[x + rwidth2] + pRef[x + rwidth2 + 1] + round) >> 2;
            pPred += pwidth2;
            pRef  += rwidth2;
        }
        break;
    }
}

/***********************************************************CommentBegin******
 *
 * -- GetPred_Chroma -- Predicts chrominance macroblock 
 *
 * Author :		
 *	Robert Danielsen <Robert.Danielsen@nta.no>
 *
 * Created :		
 *	11.02.96, based on tmn-function
 *	930211, original author Karl.Lillevold@nta.no
 *
 * Purpose :		
 *	Does the chrominance prediction for P-frames
 * 
 * Arguments in : 	
 *	current position in image,
 *	motionvectors,
 *	pointers to compensated and previous Vops,
 *	width of the compensated Vop
 *  width of the previous/reference Vop
 *
 * Arguments in/out :	
 *	
 *
 * Arguments out :	
 *	
 *
 * Return values :	
 *	
 *
 * Side effects :	
 *	
 *
 * Description :	
 *	Based on rutine from tmn-software (Karl Olav Lillevold)
 *
 * See also :
 *	
 *
 * Modified :28.08.97 Minhua Zhou: added unrestricted MC in Chrominance			
 *	
 *
 ***********************************************************CommentEnd********/

Void
GetPred_Chroma (Int x_curr,
	       Int y_curr,
	       Int dx,
	       Int dy,
	       Vop *prev,
	       Vop *comp_Vop,
	       Int width,
	       Int width_prev,
               Int prev_x_min,
               Int prev_y_min,
               Int prev_x_max,
               Int prev_y_max)
{
  Int m,n;

  Int x, y, ofx, ofy, lx;
  Int xint, yint;
  Int xh, yh;
  Int rounding_control;
  Int index1,index2,index3,index4;

  lx = width_prev/2;

  x = x_curr>>1;
  y = y_curr>>1;

  xint = dx>>1;
  xh = dx & 1;
  yint = dy>>1;
  yh = dy & 1;
  rounding_control = GetVopRoundingType(comp_Vop);

  if (!xh && !yh)
    {
      for (n = 0; n < 8; n++)
	{
	  for (m = 0; m < 8; m++)
	    {
	      ofx = x + xint + m;
	      ofy = y + yint + n;
              index1 = unrestricted_MC_chro(ofx,ofy,lx,prev_x_min,
                                  prev_y_min,prev_x_max,prev_y_max);
              comp_Vop->v_chan->f[(y+n)*width/2+x+m] 
		= *(prev->v_chan->f+ index1);
              comp_Vop->u_chan->f[(y+n)*width/2+x+m]
		= *(prev->u_chan->f+index1);
	    }
	}
    }
  else if (!xh && yh)
    {
      for (n = 0; n < 8; n++)
	{
	  for (m = 0; m < 8; m++)
	    {
	      ofx = x + xint + m;
	      ofy = y + yint + n;
              index1 =  unrestricted_MC_chro(ofx,ofy,lx,prev_x_min,
                                  prev_y_min,prev_x_max,prev_y_max);
              index2 =  unrestricted_MC_chro(ofx,ofy+yh,lx,prev_x_min,
                                  prev_y_min,prev_x_max,prev_y_max);

	      comp_Vop->v_chan->f[(y+n)*width/2+x+m]
		= (*(prev->v_chan->f+index1) +
		   *(prev->v_chan->f+index2) + 1- rounding_control)>>1;

	      comp_Vop->u_chan->f[(y+n)*width/2+x+m]
		= (*(prev->u_chan->f+index1) +
		   *(prev->u_chan->f+index2) + 1- rounding_control)>>1;
	    }
	}
    }
  else if (xh && !yh)
    {
      for (n = 0; n < 8; n++)
	{
	  for (m = 0; m < 8; m++)
	    {
	      ofx = x + xint + m;
	      ofy = y + yint + n;
              index1 =  unrestricted_MC_chro(ofx,ofy,lx,prev_x_min,
                                  prev_y_min,prev_x_max,prev_y_max);
              index2 =  unrestricted_MC_chro(ofx+xh,ofy,lx,prev_x_min,
                                  prev_y_min,prev_x_max,prev_y_max);

	      comp_Vop->v_chan->f[(y+n)*width/2+x+m]
		= (*(prev->v_chan->f+index1) +
		   *(prev->v_chan->f+index2) + 1- rounding_control)>>1;

	      comp_Vop->u_chan->f[(y+n)*width/2+x+m]
		= (*(prev->u_chan->f+index1) +
		   *(prev->u_chan->f+index2) + 1- rounding_control)>>1;
	    }
	}
    }
  else
    { /* xh && yh */
      for (n = 0; n < 8; n++)
	{
	  for (m = 0; m < 8; m++)
	    {
	      ofx = x + xint + m;
	      ofy = y + yint + n;
              index1 =  unrestricted_MC_chro(ofx,ofy,lx,prev_x_min,
                                  prev_y_min,prev_x_max,prev_y_max);
              index2 =  unrestricted_MC_chro(ofx+xh,ofy,lx,prev_x_min,
                                  prev_y_min,prev_x_max,prev_y_max);
              index3 =  unrestricted_MC_chro(ofx,ofy+yh,lx,prev_x_min,
                                  prev_y_min,prev_x_max,prev_y_max);
              index4 =  unrestricted_MC_chro(ofx+xh,ofy+yh,lx,prev_x_min,
                                  prev_y_min,prev_x_max,prev_y_max);


	      comp_Vop->v_chan->f[(y+n)*width/2+x+m]
		= (*(prev->v_chan->f+index1)+
		   *(prev->v_chan->f+index2)+
		   *(prev->v_chan->f+index3)+
		   *(prev->v_chan->f+index4)+
		   2- rounding_control)>>2;

	      comp_Vop->u_chan->f[(y+n)*width/2+x+m]
		= (*(prev->u_chan->f+index1)+
		   *(prev->u_chan->f+index2)+
		   *(prev->u_chan->f+index3)+
		   *(prev->u_chan->f+index4)+
		   2- rounding_control)>>2;
	    }
	}
    }
  return;
}

Void
GetPred_Chroma1 (Int x_curr,
	       Int y_curr,
	       Int dx,
	       Int dy,
	       SInt *prev_u,
	       SInt *prev_v,
				 Vop *comp_Vop,
	       Int width,
	       Int width_prev,
               Int prev_x_min,
               Int prev_y_min,
               Int prev_x_max,
               Int prev_y_max)
{
  Int m,n;

  Int x, y, ofx, ofy, lx;
  Int xint, yint;
  Int xh, yh;
  Int rounding_control;
  Int index1,index2,index3,index4;

  lx = width_prev/2;

  x = x_curr>>1;
  y = y_curr>>1;

  xint = dx>>1;
  xh = dx & 1;
  yint = dy>>1;
  yh = dy & 1;
  rounding_control = GetVopRoundingType(comp_Vop);

  if (!xh && !yh)
    {
      for (n = 0; n < 8; n++)
	{
	  for (m = 0; m < 8; m++)
	    {
	      ofx = x + xint + m;
	      ofy = y + yint + n;
              index1 = unrestricted_MC_chro(ofx,ofy,lx,prev_x_min,
                                  prev_y_min,prev_x_max,prev_y_max);
              comp_Vop->v_chan->f[(y+n)*width/2+x+m] 
		= *(prev_v + index1);
              comp_Vop->u_chan->f[(y+n)*width/2+x+m]
		= *(prev_u + index1);
	    }
	}
    }
  else if (!xh && yh)
    {
      for (n = 0; n < 8; n++)
	{
	  for (m = 0; m < 8; m++)
	    {
	      ofx = x + xint + m;
	      ofy = y + yint + n;
              index1 =  unrestricted_MC_chro(ofx,ofy,lx,prev_x_min,
                                  prev_y_min,prev_x_max,prev_y_max);
              index2 =  unrestricted_MC_chro(ofx,ofy+yh,lx,prev_x_min,
                                  prev_y_min,prev_x_max,prev_y_max);

	      comp_Vop->v_chan->f[(y+n)*width/2+x+m]
		= (*(prev_v+index1) +
		   *(prev_v+index2) + 1- rounding_control)>>1;

	      comp_Vop->u_chan->f[(y+n)*width/2+x+m]
		= (*(prev_u+index1) +
		   *(prev_u+index2) + 1- rounding_control)>>1;
	    }
	}
    }
  else if (xh && !yh)
    {
      for (n = 0; n < 8; n++)
	{
	  for (m = 0; m < 8; m++)
	    {
	      ofx = x + xint + m;
	      ofy = y + yint + n;
              index1 =  unrestricted_MC_chro(ofx,ofy,lx,prev_x_min,
                                  prev_y_min,prev_x_max,prev_y_max);
              index2 =  unrestricted_MC_chro(ofx+xh,ofy,lx,prev_x_min,
                                  prev_y_min,prev_x_max,prev_y_max);

	      comp_Vop->v_chan->f[(y+n)*width/2+x+m]
		= (*(prev_v+index1) +
		   *(prev_v+index2) + 1- rounding_control)>>1;

	      comp_Vop->u_chan->f[(y+n)*width/2+x+m]
		= (*(prev_u+index1) +
		   *(prev_u+index2) + 1- rounding_control)>>1;
	    }
	}
    }
  else
    { /* xh && yh */
      for (n = 0; n < 8; n++)
	{
	  for (m = 0; m < 8; m++)
	    {
	      ofx = x + xint + m;
	      ofy = y + yint + n;
              index1 =  unrestricted_MC_chro(ofx,ofy,lx,prev_x_min,
                                  prev_y_min,prev_x_max,prev_y_max);
              index2 =  unrestricted_MC_chro(ofx+xh,ofy,lx,prev_x_min,
                                  prev_y_min,prev_x_max,prev_y_max);
              index3 =  unrestricted_MC_chro(ofx,ofy+yh,lx,prev_x_min,
                                  prev_y_min,prev_x_max,prev_y_max);
              index4 =  unrestricted_MC_chro(ofx+xh,ofy+yh,lx,prev_x_min,
                                  prev_y_min,prev_x_max,prev_y_max);


	      comp_Vop->v_chan->f[(y+n)*width/2+x+m]
		= (*(prev_v+index1)+
		   *(prev_v+index2)+
		   *(prev_v+index3)+
		   *(prev_v+index4)+
		   2- rounding_control)>>2;

	      comp_Vop->u_chan->f[(y+n)*width/2+x+m]
		= (*(prev_u+index1)+
		   *(prev_u+index2)+
		   *(prev_u+index3)+
		   *(prev_u+index4)+
		   2- rounding_control)>>2;
	    }
	}
    }
  return;
}

/***********************************************************CommentBegin******
 *
 * -- GetPred_Field_Chroma -- Find the prediction block
 *
 * Author :
 *  Bob Eifrig
 *
 * Created :
 *  21-jan-97
 *
 * Purpose :
 *  Find the chrominance prediction for a field
 *
 * Arguments in :
 *  Macroblock coordinates,
 *  motion vector,
 *  reference images,
 *  perimeter expansion value
 *  reference field selection code
 *
 * Arguments in/out :
 *
 *
 * Arguments out :
 *  chrominace prediction block the component images
 *
 * Return values :
 *
 *
 * Side effects :
 *
 * Description :
 *
 *
 * See also :
 *
 *
 * Modified :
 *
 ***********************************************************CommentEnd********/
 
void
GetPred_Field_Chroma(Int mbx, Int mby, Float *xvec, Float *yvec, Vop *ref,
             Vop *pred, Int how, Int edge)
{
    Int x, y, dx, dy, k, code, round;
    SInt *pURef, *pUPred, *pVRef, *pVPred;
    Int rwidth, rwidth2, pwidth, pwidth2;
 
    pwidth = GetImageSizeX(pred->u_chan);
    pwidth2 = pwidth << 1;
    rwidth = GetImageSizeX(ref->u_chan);
    rwidth2 = rwidth << 1;
 
    k = 2*mbx + 4*mby*pwidth2/MB_SIZE;
    xvec += k;
    yvec += k;
 
    mbx *= MB_SIZE/2;
    mby *= MB_SIZE/2;
 
    /*
     * Motion compensate the top chroma field
     */
 
    dx = (Int)(2*xvec[0]);      /* half luma pel units */
    dy = (Int)(2*yvec[0]);
 
    dx = ((dx & 3) ? ((dx >> 1) | 1) : (dx >> 1)) + edge;
    dy = ((dy & 6) ? ((dy >> 1) | 2) : (dy >> 1)) + edge;
    code = (dx & 1) | (dy & 2);
    dx >>= 1;
    dy = (dy >> 1) & ~1;
    if (how & 2) dy++;
 
    k = mbx + mby * pwidth;
    pUPred = (SInt *)GetImageData(pred->u_chan) + k;
    pVPred = (SInt *)GetImageData(pred->v_chan) + k;
 
    k = (mbx + dx) + (mby + dy) * rwidth;
    pURef = (SInt *)GetImageData(ref->u_chan) + k;
    pVRef = (SInt *)GetImageData(ref->v_chan) + k;
 
    switch (code) {
 
    case 0:                                         /* no interp */
        for (y = 0; y < MB_SIZE/2; y += 2) {
          for (x = 0; x < MB_SIZE/2; x++) {
            pUPred[x] = pURef[x];
            pVPred[x] = pVRef[x];
          }
          pUPred += pwidth2;
          pVPred += pwidth2;
          pURef  += rwidth2;
          pVRef  += rwidth2;
        }
        break;
 
    case 1:                                         /* horizontal interp */
        round = 1 - pred->rounding_type;
        for (y = 0; y < MB_SIZE/2; y += 2) {
          for (x = 0; x < MB_SIZE/2; x++) {
            pUPred[x] = (pURef[x] + pURef[x + 1] + round) >> 1;
            pVPred[x] = (pVRef[x] + pVRef[x + 1] + round) >> 1;
          }
          pUPred += pwidth2;
          pVPred += pwidth2;
          pURef  += rwidth2;
          pVRef  += rwidth2;
        }
        break;
 
    case 2:                                         /* vertical interp */
        round = 1 - pred->rounding_type;
        for (y = 0; y < MB_SIZE/2; y += 2) {
          for (x = 0; x < MB_SIZE/2; x++) {
            pUPred[x] = (pURef[x] + pURef[x + rwidth2] + round) >> 1;
            pVPred[x] = (pVRef[x] + pVRef[x + rwidth2] + round) >> 1;
          }
          pUPred += pwidth2;
          pVPred += pwidth2;
          pURef  += rwidth2;
          pVRef  += rwidth2;
        }
        break;
 
    case 3:                                         /* horiz & vert interp */
        round = 2 - pred->rounding_type;
        for (y = 0; y < MB_SIZE/2; y += 2) {
          for (x = 0; x < MB_SIZE/2; x++) {
            pUPred[x] = (pURef[x] + pURef[x + 1] +
                 pURef[x + rwidth2] +
                 pURef[x + rwidth2 + 1] + round) >> 2;
            pVPred[x] = (pVRef[x] + pVRef[x + 1] +
                 pVRef[x + rwidth2] +
                 pVRef[x + rwidth2 + 1] + round) >> 2;
            }
            pUPred += pwidth2;
            pVPred += pwidth2;
            pURef  += rwidth2;
            pVRef  += rwidth2;
        }
        break;
    }
 
    /*
     * Motion compensate the bottom chroma field
     */
 
    dx = (Int)(2*xvec[1]);
    dy = (Int)(2*yvec[1]);
 
    dx = ((dx & 3) ? ((dx >> 1) | 1) : (dx >> 1)) + edge;
    dy = ((dy & 6) ? ((dy >> 1) | 2) : (dy >> 1)) + edge;
    code = (dx & 1) | (dy & 2);
    dx >>= 1;
    dy = (dy >> 1) & ~1;
    if (how & 1) dy++;
 
    k = mbx + (mby + 1) * pwidth;
    pUPred = (SInt *)GetImageData(pred->u_chan) + k;
    pVPred = (SInt *)GetImageData(pred->v_chan) + k;
 
    k = (mbx + dx) + (mby + dy) * rwidth;
    pURef = (SInt *)GetImageData(ref->u_chan) + k;
    pVRef = (SInt *)GetImageData(ref->v_chan) + k;
 
    switch (code) {

    case 0:                                         /* no interp */
        for (y = 0; y < MB_SIZE/2; y += 2) {
            for (x = 0; x < MB_SIZE/2; x++) {
                pUPred[x] = pURef[x];
                pVPred[x] = pVRef[x];
            }
            pUPred += pwidth2;
            pVPred += pwidth2;
            pURef  += rwidth2;
            pVRef  += rwidth2;
        }
        break;
 
    case 1:                                         /* horizontal interp */
        round = 1 - pred->rounding_type;
        for (y = 0; y < MB_SIZE/2; y += 2) {
          for (x = 0; x < MB_SIZE/2; x++) {
            pUPred[x] = (pURef[x] + pURef[x + 1] + round) >> 1;
            pVPred[x] = (pVRef[x] + pVRef[x + 1] + round) >> 1;
          }
          pUPred += pwidth2;
          pVPred += pwidth2;
          pURef  += rwidth2;
          pVRef  += rwidth2;
        }
        break;
 
    case 2:                                         /* vertical interp */
        round = 1 - pred->rounding_type;
        for (y = 0; y < MB_SIZE/2; y += 2) {
          for (x = 0; x < MB_SIZE/2; x++) {
            pUPred[x] = (pURef[x] + pURef[x + rwidth2] + round) >> 1;
            pVPred[x] = (pVRef[x] + pVRef[x + rwidth2] + round) >> 1;
          }
          pUPred += pwidth2;
          pVPred += pwidth2;
          pURef  += rwidth2;
          pVRef  += rwidth2;
        }
        break;
 
    case 3:                                         /* horiz & vert interp */
        round = 2 - pred->rounding_type;
        for (y = 0; y < MB_SIZE/2; y += 2) {
          for (x = 0; x < MB_SIZE/2; x++) {
            pUPred[x] = (pURef[x] + pURef[x + 1] +
                 pURef[x + rwidth2] +
                 pURef[x + rwidth2 + 1] + round) >> 2;
            pVPred[x] = (pVRef[x] + pVRef[x + 1] +
                 pVRef[x + rwidth2] +
                 pVRef[x + rwidth2 + 1] + round) >> 2;
          }
          pUPred += pwidth2;
          pVPred += pwidth2;
          pURef  += rwidth2;
          pVRef  += rwidth2;
        }
        break;
    }
}

/***********************************************************CommentBegin******
 *  ----  B_VopMotionCompensation ---- Motion compensation for a B-VOP
 *
 * Author :
 *   HHI -- Minhua Zhou
 *
 * Created :
 *   07.03.97
 *
 * Purpose :
 *   Generation of motion-compensated prediction for a B-VOP 
 *
 * Arguments in :
 *   Vop *prev_rec_vop, previous reconstructed VOP
 *   Vop *next_rec_vop, next reconstructed VOP
 *   Image *mot_xi,  horizontal MV coordinates for the B-VOP
 *   Image   *mot_yi,  vertical MV coordinates for the B-VOP
 *   Image *mot_x_Pi, horizontal MV coordinates for the next P-VOP
 *   Image *mot_y_Pi, vertical MV coordinates for the next P-VOP
 *   Image  *modei,  MB prediction modes(forward/backward/interpolative/direct) 
 *   Image  *sub_alphai, sub-sampled alpha plane of the current VOP
 *   Int TRB,  forward temporal distance
 *   Int TRD,  temporal distance between two consecutive P-VOPs
 *  Arguments in/out :
 *
 *
 * Arguments out :
 *   Vop *comp   motion-compensated prediction for the B_VOP
 *
 * Return values :
 *   none
 *
 * Side effects :
 *
 *
 * Description :
 *   The defintion of "co-located macroblock" is not clear in the current VM6.0,
 *   Here, if a block of the co-located macroblock is transparent or
 *   INTRA-coded, the corresponding motion vector for direct mode are set to
 *   zero and the direct mode is still enabled !!!!
 *
 * See also :
 *
 *
 * Modified :
 *   01.08.97 Fernando Jaureguizar: added the printing of modes for
 *            B-VOPs in B_VopMotionCompensation(), like in
 *            VopMotionCompensate().   (SpSc)
 *   28.08.97 Osamu Sunohara: modified to set MV in spatial scalable
 *                            enhancement B-VOP to zero
 *   11.12.97 Bob Eifrig: added code for field motion compensation and
 *            interlaced direct mode.
 *
 ************************************************************CommentEnd********/            
Void  B_VopMotionCompensation(
      Vop *curr,
      Vop *prev_rec_vop,
      Vop *next_rec_vop,
      Image *mot_xi,
      Image *mot_yi,
      Image *mot_x_Pi,
      Image *mot_y_Pi,
      Image *mode_Pi,
      Image *modei,
      Image *sub_alphai,
      Int TRB,Int TRD,
      Vop *comp)
{
 Vop *prev_rec_vop_padded,*next_rec_vop_padded;
  Int curr_vop_width = GetVopWidth(comp);
  Int curr_vop_height = GetVopHeight(comp);
  Int i,j,MB_num_x,MB_num_y;


           
  /* Padding of VOPs */
  prev_rec_vop_padded = prev_rec_vop;
  next_rec_vop_padded = next_rec_vop;


/*  Motion Compensation for B-VOPs */

   MB_num_x=curr_vop_width/16;
   MB_num_y=curr_vop_height/16;
   
for (i=0;i<MB_num_y;i++) 
  for (j=0;j<MB_num_x;j++) 
    B_MotionCompensateMB(
			j,
			i,
      curr,
      prev_rec_vop_padded,
      next_rec_vop_padded,
      mot_xi,
      mot_yi,
      mot_x_Pi,
      mot_y_Pi,
      mode_Pi,
      modei,
      sub_alphai,
      TRB,
      TRD,
      comp);


     }
       

Void  B_MotionCompensateMB(
			Int j,
			Int i,
      Vop *curr,
      Vop *prev_rec_vop,
      Vop *next_rec_vop,
      Image *mot_xi,
      Image *mot_yi,
      Image *mot_x_Pi,
      Image *mot_y_Pi,
      Image *mode_Pi,
      Image *modei,
      Image *sub_alphai,
      Int TRB,Int TRD,
      Vop *comp)
{
 Vop *prev_rec_vop_padded,*next_rec_vop_padded;
  Int curr_vop_width = GetVopWidth(comp);
  Int curr_vop_height = GetVopHeight(comp);
  Int k,l,col,row,count,MB_num_x,MB_num_y;
  SInt MVD_x,MVD_y,vx,vy,vx_f,vy_f,vx_b,vy_b;
  SInt pred_for[6*64],pred_back[6*64];
  Int yoff, coff, ewidth=0, pmode, trb_field=0, trd_field=0;
  static int frame_period = 0x7fffffff;     /* a big number */
  SInt sign[4],vx_P[4],vy_P[4],Mode;
  Float *mot_x,*mot_y,*mot_x_P,*mot_y_P;
  SInt  *mode,*sub_alpha,*mode_P;

/* added to set MV in spatial scalable enhancement B-VOP to zero */
/*                                      by Sony 280897 */
  Float MV_x,MV_y;
  Int  spatial_scalability=0;
/* 280897 */

  Int edge=16,index; 
  mot_x = (Float *)GetImageData(mot_xi);
  mot_y = (Float *)GetImageData(mot_yi);
  mot_x_P = (Float *)GetImageData(mot_x_Pi);
  mot_y_P = (Float *)GetImageData(mot_y_Pi);
  mode = (SInt *)GetImageData(modei);
  mode_P = (SInt *)GetImageData(mode_Pi);
  sub_alpha = (SInt *)GetImageData(sub_alphai);

  if (GetVopInterlaced(curr)) {
      ewidth = 2*edge + curr_vop_width;
      if (TRB < frame_period)
          frame_period = TRB;
      trb_field = 2 * (Int)((TRB + 0.5 * frame_period) / frame_period);
      trd_field = 2 * (Int)((TRD + 0.5 * frame_period) / frame_period);
      if ((trb_field <= 0) || (trd_field <= 0) || (trd_field <= trb_field)) {
          fprintf(stderr, "Negative times: trd=%d, trb=%d\n", trd_field, 
trb_field);
          exit(1);
      }
  }

  /*>SpSc*/
/* added to set spatial scalability flag by Sony 280897 */
 if(GetVopScalability(curr) == 1 &&
    GetVopRefSelCode(curr) == 0){
   spatial_scalability = 1;
 }
/* 280897 */

  /* Padding of VOPs */
  prev_rec_vop_padded = prev_rec_vop;
  next_rec_vop_padded = next_rec_vop;

  
/*  Motion Compensation for B-VOPs */

  MB_num_x=curr_vop_width/16;
  MB_num_y=curr_vop_height/16;
  
  row=i*16;
  col = j*16;
  Mode= mode[i*MB_num_x+j];
  index = 4*i*MB_num_x+j+j;
   
  switch (Mode) {
    case -1:    /* Transparent */
               break;
    case 0 :    /* forward  */
    case 4 :
               halfpel_motion_compensation (
                         (SInt*)GetImageData(GetVopY(prev_rec_vop_padded)),
                         (SInt)(2.0*mot_x[index]),(SInt)(2.0*mot_y[index]),
                         
col+comp->hor_spat_ref-prev_rec_vop_padded->hor_spat_ref,
                         
row+comp->ver_spat_ref-prev_rec_vop_padded->ver_spat_ref,
                         
GetVopWidth(prev_rec_vop_padded),GetVopHeight(prev_rec_vop_padded),
                         16,16,2,0,edge,pred_for);
 	        Putblock(col, row, pred_for, comp->y_chan,curr_vop_width,16);
 
                halfpel_motion_compensation (
                         (SInt*)GetImageData(GetVopU(prev_rec_vop_padded)),
                         (SInt)(2.0*mot_x[index]),(SInt)(2.0*mot_y[index]),
                         
(col+comp->hor_spat_ref-prev_rec_vop_padded->hor_spat_ref)/2,
                         
(row+comp->ver_spat_ref-prev_rec_vop_padded->ver_spat_ref)/2,
                         
GetVopWidth(prev_rec_vop_padded)/2,GetVopHeight(prev_rec_vop_padded)/2,
                         8,8,4,0,edge/2,pred_for);
 	        Putblock(col/2, row/2, pred_for, 
comp->u_chan,curr_vop_width/2,8); 

                halfpel_motion_compensation (
                         (SInt*)GetImageData(GetVopV(prev_rec_vop_padded)),
                         (SInt)(2.0*mot_x[index]),(SInt)(2.0*mot_y[index]),
                         
(col+comp->hor_spat_ref-prev_rec_vop_padded->hor_spat_ref)/2,
                         
(row+comp->ver_spat_ref-prev_rec_vop_padded->ver_spat_ref)/2,
                         
GetVopWidth(prev_rec_vop_padded)/2,GetVopHeight(prev_rec_vop_padded)/2,
                         8,8,4,0,edge/2,pred_for);
 	        Putblock(col/2, row/2, pred_for, 
comp->v_chan,curr_vop_width/2,8); 
                break;

       case 1 :    /* backward  */
/* added to set MV to zero by Sony 280897 */
         if(spatial_scalability){
           MV_x = 0.0;MV_y=0.0;
         }else{
           MV_x = mot_x[index+1];
           MV_y = mot_y[index+1];          
         }
/* 280897 */
               halfpel_motion_compensation (
                         (SInt*)GetImageData(GetVopY(next_rec_vop_padded)),
                         (SInt)(2.0*MV_x),(SInt)(2.0*MV_y),                /* 
<-modified!! */
                         
col+comp->hor_spat_ref-next_rec_vop_padded->hor_spat_ref,
                         
row+comp->ver_spat_ref-next_rec_vop_padded->ver_spat_ref,
                         
GetVopWidth(next_rec_vop_padded),GetVopHeight(next_rec_vop_padded),
                         16,16,2,0,edge,pred_back);
 	        Putblock(col, row, pred_back, comp->y_chan,curr_vop_width,16);
 
                halfpel_motion_compensation (
                         (SInt*)GetImageData(GetVopU(next_rec_vop_padded)),
                         (SInt)(2.0*MV_x),(SInt)(2.0*MV_y),                /* 
<-modified!! */
                         
(col+comp->hor_spat_ref-next_rec_vop_padded->hor_spat_ref)/2,
                         
(row+comp->ver_spat_ref-next_rec_vop_padded->ver_spat_ref)/2,
                         
GetVopWidth(next_rec_vop_padded)/2,GetVopHeight(next_rec_vop_padded)/2,
                         8,8,4,0,edge/2,pred_back);
 	        Putblock(col/2, row/2, pred_back, 
comp->u_chan,curr_vop_width/2,8); 

                halfpel_motion_compensation (
                         (SInt*)GetImageData(GetVopV(next_rec_vop_padded)),
                         (SInt)(2.0*MV_x),(SInt)(2.0*MV_y),                /* 
<-modified!! */
                         
(col+comp->hor_spat_ref-next_rec_vop_padded->hor_spat_ref)/2,
                         
(row+comp->ver_spat_ref-next_rec_vop_padded->ver_spat_ref)/2,
                         
GetVopWidth(next_rec_vop_padded)/2,GetVopHeight(next_rec_vop_padded)/2,
                         8,8,4,0,edge/2,pred_back);
 	        Putblock(col/2, row/2, pred_back, 
comp->v_chan,curr_vop_width/2,8); 
                break;
     case 2 :   /* interpolative */
/* added to set MV to zero by Sony 280897 */
       if(spatial_scalability){
           MV_x = 0.0;MV_y=0.0;
         }else{
           MV_x = mot_x[index+1];
           MV_y = mot_y[index+1]; 
           }
/* 280897 */ 
               halfpel_motion_compensation (
                         (SInt*)GetImageData(GetVopY(prev_rec_vop_padded)),
                         (SInt)(2.0*mot_x[index]),(SInt)(2.0*mot_y[index]),
                         
col+comp->hor_spat_ref-prev_rec_vop_padded->hor_spat_ref,
                         
row+comp->ver_spat_ref-prev_rec_vop_padded->ver_spat_ref,
                         
GetVopWidth(prev_rec_vop_padded),GetVopHeight(prev_rec_vop_padded),
                         16,16,2,0,edge,pred_for);
               halfpel_motion_compensation (
                         (SInt*)GetImageData(GetVopY(next_rec_vop_padded)),
                         (SInt)(2.0*MV_x),(SInt)(2.0*MV_y),                /* 
<-modified!! */
                         
col+comp->hor_spat_ref-next_rec_vop_padded->hor_spat_ref,
                         
row+comp->ver_spat_ref-next_rec_vop_padded->ver_spat_ref,
                         
GetVopWidth(next_rec_vop_padded),GetVopHeight(next_rec_vop_padded),
                         16,16,2,0,edge,pred_back);
               for (k=0;k<256;k++) pred_for[k] = 
(pred_for[k]+pred_back[k]+1)>>1;
 	       Putblock(col, row, pred_for, comp->y_chan,curr_vop_width,16);
 
               halfpel_motion_compensation (
                         (SInt*)GetImageData(GetVopU(prev_rec_vop_padded)),
                         (SInt)(2.0*mot_x[index]),(SInt)(2.0*mot_y[index]),
                         
(col+comp->hor_spat_ref-prev_rec_vop_padded->hor_spat_ref)/2,
                         
(row+comp->ver_spat_ref-prev_rec_vop_padded->ver_spat_ref)/2,
                         
GetVopWidth(prev_rec_vop_padded)/2,GetVopHeight(prev_rec_vop_padded)/2,
                         8,8,4,0,edge/2,pred_for);
                halfpel_motion_compensation (
                         (SInt*)GetImageData(GetVopU(next_rec_vop_padded)),
                         (SInt)(2.0*MV_x),(SInt)(2.0*MV_y),                /* 
<-modified!! */
                         
(col+comp->hor_spat_ref-next_rec_vop_padded->hor_spat_ref)/2,
                         
(row+comp->ver_spat_ref-next_rec_vop_padded->ver_spat_ref)/2,
                         
GetVopWidth(next_rec_vop_padded)/2,GetVopHeight(next_rec_vop_padded)/2,
                         8,8,4,0,edge/2,pred_back);
                for (k=0;k<64;k++) pred_for[k] = 
(pred_for[k]+pred_back[k]+1)>>1;
 	        Putblock(col/2, row/2, pred_for, 
comp->u_chan,curr_vop_width/2,8); 

               halfpel_motion_compensation (
                         (SInt*)GetImageData(GetVopV(prev_rec_vop_padded)),
                         (SInt)(2.0*mot_x[index]),(SInt)(2.0*mot_y[index]),
                         
(col+comp->hor_spat_ref-prev_rec_vop_padded->hor_spat_ref)/2,
                         
(row+comp->ver_spat_ref-prev_rec_vop_padded->ver_spat_ref)/2,
                         
GetVopWidth(prev_rec_vop_padded)/2,GetVopHeight(prev_rec_vop_padded)/2,
                         8,8,4,0,edge/2,pred_for);
                halfpel_motion_compensation (
                         (SInt*)GetImageData(GetVopV(next_rec_vop_padded)),
                         (SInt)(2.0*MV_x),(SInt)(2.0*MV_y),                /* 
<-modified!! */
                         
(col+comp->hor_spat_ref-next_rec_vop_padded->hor_spat_ref)/2,
                         
(row+comp->ver_spat_ref-next_rec_vop_padded->ver_spat_ref)/2,
                         
GetVopWidth(next_rec_vop_padded)/2,GetVopHeight(next_rec_vop_padded)/2,
                         8,8,4,0,edge/2,pred_back);
                for (k=0;k<64;k++) pred_for[k] = 
(pred_for[k]+pred_back[k]+1)>>1;
 	        Putblock(col/2, row/2, pred_for, 
comp->v_chan,curr_vop_width/2,8); 
              break;
  case 3:    /*  direct mode */
             pmode = serach_for_vectors_of_co_located_MB
                              (mot_x_P,mot_y_P,mode_P,
                               
col/*+comp->hor_spat_ref-next_rec_vop_padded->hor_spat_ref-edge*/,
                               
row/*+comp->ver_spat_ref-next_rec_vop_padded->ver_spat_ref-edge*/,
                               GetVopWidth(next_rec_vop_padded)-2*edge,
                               GetVopHeight(next_rec_vop_padded)-2*edge,
                               vx_P,vy_P);

                  MVD_x = (SInt)(2.0*mot_x[index+2*MB_num_x+1]);
                  MVD_y = (SInt)(2.0*mot_y[index+2*MB_num_x+1]);
              if ((pmode >= MBM_FIELD00) && (pmode <= MBM_FIELD11)) {
                    static char dtrt[] = {  0, 0,  1, 1, 0, 0, -1, -1 };
                    static char dtrb[] = { -1, 0, -1, 0, 1, 0,  1,  0 };
                    SInt ftx, fty, btx, bty, trbt, trdt;
                    SInt fbx, fby, bbx, bby, trbb, trdb;
                    Int code = pmode - MBM_FIELD00;

                    if (GetVopTopFieldFirst(curr)) code += 4;
                    trdt = trd_field + dtrt[code];
                    trbt = trb_field + dtrt[code];
                    trdb = trd_field + dtrb[code];
                    trbb = trb_field + dtrb[code];

                    /* Find MVs for the top field */
                    ftx = (SInt)((trbt * vx_P[0]) / trdt + MVD_x);
                    fty = (SInt)((trbt * vy_P[0]) / trdt + MVD_y);
                    btx = MVD_x ? (ftx - vx_P[0]) : (SInt)(((trbt - trdt) * 
vx_P[0]) / trdt);
                    bty = MVD_y ? (fty - vy_P[0]) : (SInt)(((trbt - trdt) * 
vy_P[0]) / trdt);
                    ClipMV(col, row, curr_vop_width, curr_vop_height, edge, 
&ftx, &fty);
                    ClipMV(col, row, curr_vop_width, curr_vop_height, edge, 
&btx, &bty);

                    /* Find MVs for the bottom field */
                    fbx = (SInt)((trbb * vx_P[1]) / trdb + MVD_x);
                    fby = (SInt)((trbb * vy_P[1]) / trdb + MVD_y);
                    bbx = MVD_x ? (fbx - vx_P[1]) : (SInt)(((trbb - trdb) * 
vx_P[1]) / trdb);
                    bby = MVD_y ? (fby - vy_P[1]) : (SInt)(((trbb - trdb) * 
vy_P[1]) / trdb);
                    ClipMV(col, row, curr_vop_width, curr_vop_height, edge, 
&fbx, &fby);
                    ClipMV(col, row, curr_vop_width, curr_vop_height, edge, 
&bbx, &bby);
                    
                    yoff =  (col + edge) + (row + edge) *  ewidth;
                    coff = ((col + edge) + (row + edge) * (ewidth >> 1)) >> 1;

                    /* Obtain the forward and backward parts of the top field */
                    BMBFieldMotComp(
                        (SInt *)GetImageData(GetVopY(prev_rec_vop_padded)) + 
yoff,
                        (SInt *)GetImageData(GetVopU(prev_rec_vop_padded)) + 
coff,
                        (SInt *)GetImageData(GetVopV(prev_rec_vop_padded)) + 
coff,
                        pred_for,  ewidth, 0, code & 2, ftx, fty);
                    BMBFieldMotComp(
                        (SInt *)GetImageData(GetVopY(next_rec_vop_padded)) + 
yoff,
                        (SInt *)GetImageData(GetVopU(next_rec_vop_padded)) + 
coff,
                        (SInt *)GetImageData(GetVopV(next_rec_vop_padded)) + 
coff,
                        pred_back, ewidth, 0, 0,        btx, bty);

                    /* Obtain the forward and backward parts of the bottom field 
*/
                    BMBFieldMotComp(
                        (SInt *)GetImageData(GetVopY(prev_rec_vop_padded)) + 
yoff,
                        (SInt *)GetImageData(GetVopU(prev_rec_vop_padded)) + 
coff,
                        (SInt *)GetImageData(GetVopV(prev_rec_vop_padded)) + 
coff,
                        pred_for,  ewidth, 1, code & 1, fbx, fby);
                    BMBFieldMotComp(
                        (SInt *)GetImageData(GetVopY(next_rec_vop_padded)) + 
yoff,
                        (SInt *)GetImageData(GetVopU(next_rec_vop_padded)) + 
coff,
                        (SInt *)GetImageData(GetVopV(next_rec_vop_padded)) + 
coff,
                        pred_back, ewidth, 1, 1,        bbx, bby);
                    /*
                     * Average forward and backward predictions
                     */
                    for (k = 0; k < 6*B_SIZE*B_SIZE; k++)
                        pred_for[k] = (pred_for[k] + pred_back[k] + 1) >> 1;
                    
                    Putblock(col,      row,      &pred_for[0*64], comp->y_chan, 
curr_vop_width,      MB_SIZE);
                    Putblock(col >> 1, row >> 1, &pred_for[4*64], comp->u_chan, 
curr_vop_width >> 1,  B_SIZE);
                    Putblock(col >> 1, row >> 1, &pred_for[5*64], comp->v_chan, 
curr_vop_width >> 1,  B_SIZE);
                    break;
              }

                  vx_f=vy_f=vx_b=vy_b=count=0;
                  sign[0] = sub_alpha[index];
                  sign[1] = sub_alpha[index+1];
                  sign[2] = sub_alpha[index+2*MB_num_x];
                  sign[3] = sub_alpha[index+1+2*MB_num_x];

               for (k=0;k<4;k++) if (sign[k]!=MBM_TRANSPARENT) {
                  count+=4; 
                  vx = (TRB*vx_P[k])/TRD+ MVD_x;
                  vy = (TRB*vy_P[k])/TRD+ MVD_y;

                  vx_f+=vx; vy_f+=vy; 
                  halfpel_motion_compensation (
                         (SInt*)GetImageData(GetVopY(prev_rec_vop_padded)),
                         vx,vy,
                         
col+comp->hor_spat_ref-prev_rec_vop_padded->hor_spat_ref+(k%2)*8,
                         
row+comp->ver_spat_ref-prev_rec_vop_padded->ver_spat_ref+(k/2)*8,
                         
GetVopWidth(prev_rec_vop_padded),GetVopHeight(prev_rec_vop_padded),
                         8,8,2,0,edge,pred_for);
                  vx = (MVD_x)? vx-vx_P[k]:((TRB-TRD)*vx_P[k])/TRD;
                  vy = (MVD_y)? vy-vy_P[k]:((TRB-TRD)*vy_P[k])/TRD;

                  vx_b += vx; vy_b +=vy;
                  halfpel_motion_compensation (
                         (SInt*)GetImageData(GetVopY(next_rec_vop_padded)),
                         vx,vy,                         	 
                         
col+comp->hor_spat_ref-next_rec_vop_padded->hor_spat_ref+(k%2)*8,
                         
row+comp->ver_spat_ref-next_rec_vop_padded->ver_spat_ref+(k/2)*8,
                         
GetVopWidth(next_rec_vop_padded),GetVopHeight(next_rec_vop_padded),
                         8,8,2,0,edge,pred_back);
               for (l=0;l<64;l++) pred_for[l] = (pred_for[l]+pred_back[l]+1)>>1;
 	       Putblock(col+(k%2)*8, row+(k/2)*8, pred_for, 
comp->y_chan,curr_vop_width,8);
               }

               halfpel_motion_compensation (
                         (SInt*)GetImageData(GetVopU(prev_rec_vop_padded)),
                         vx_f,vy_f,
                         
(col+comp->hor_spat_ref-prev_rec_vop_padded->hor_spat_ref)/2,
                         
(row+comp->ver_spat_ref-prev_rec_vop_padded->ver_spat_ref)/2,
                         
GetVopWidth(prev_rec_vop_padded)/2,GetVopHeight(prev_rec_vop_padded)/2,
                         8,8,count,0,edge/2,pred_for);
                halfpel_motion_compensation (
                         (SInt*)GetImageData(GetVopU(next_rec_vop_padded)),
                         vx_b,vy_b,
                         
(col+comp->hor_spat_ref-next_rec_vop_padded->hor_spat_ref)/2,
                         
(row+comp->ver_spat_ref-next_rec_vop_padded->ver_spat_ref)/2,
                         
GetVopWidth(next_rec_vop_padded)/2,GetVopHeight(next_rec_vop_padded)/2,
                         8,8,count,0,edge/2,pred_back);
                for (k=0;k<64;k++) pred_for[k] = 
(pred_for[k]+pred_back[k]+1)>>1;
 	        Putblock(col/2, row/2, pred_for, 
comp->u_chan,curr_vop_width/2,8); 

              halfpel_motion_compensation (
                         (SInt*)GetImageData(GetVopV(prev_rec_vop_padded)),
                         vx_f,vy_f,
                         
(col+comp->hor_spat_ref-prev_rec_vop_padded->hor_spat_ref)/2,
                         
(row+comp->ver_spat_ref-prev_rec_vop_padded->ver_spat_ref)/2,
                         
GetVopWidth(prev_rec_vop_padded)/2,GetVopHeight(prev_rec_vop_padded)/2,
                         8,8,count,0,edge/2,pred_for);
                halfpel_motion_compensation (
                         (SInt*)GetImageData(GetVopV(next_rec_vop_padded)),
                         vx_b,vy_b,
                         
(col+comp->hor_spat_ref-next_rec_vop_padded->hor_spat_ref)/2,
                         
(row+comp->ver_spat_ref-next_rec_vop_padded->ver_spat_ref)/2,
                         
GetVopWidth(next_rec_vop_padded)/2,GetVopHeight(next_rec_vop_padded)/2,
                         8,8,count,0,edge/2,pred_back);
                for (k=0;k<64;k++) pred_for[k] = 
(pred_for[k]+pred_back[k]+1)>>1;
 	        Putblock(col/2, row/2, pred_for, 
comp->v_chan,curr_vop_width/2,8); 
              break;

         case MBM_B_FWDFLD:
         case MBM_B_FWDFLD | MBM_B_FWDTOP:
         case MBM_B_FWDFLD | MBM_B_FWDBOT:
         case MBM_B_FWDFLD | MBM_B_FWDTOP | MBM_B_FWDBOT:
             yoff =  (col + edge) + (row + edge) *  ewidth;
             coff = ((col + edge) + (row + edge) * (ewidth >> 1)) >> 1;
             vx = 2.0 * mot_x[index];
             vy = 2.0 * mot_y[index];
             ClipMV(col, row, curr_vop_width, curr_vop_height, edge, &vx, &vy);
             BMBFieldMotComp(
                (SInt *)GetImageData(GetVopY(prev_rec_vop_padded)) + yoff,
                (SInt *)GetImageData(GetVopU(prev_rec_vop_padded)) + coff,
                (SInt *)GetImageData(GetVopV(prev_rec_vop_padded)) + coff,
                pred_for, ewidth, 0, Mode & MBM_B_FWDTOP, vx, vy);
             vx = 2.0 * mot_x[index+1];
             vy = 2.0 * mot_y[index+1];
             ClipMV(col, row, curr_vop_width, curr_vop_height, edge, &vx, &vy);
             BMBFieldMotComp(
                (SInt *)GetImageData(GetVopY(prev_rec_vop_padded)) + yoff,
                (SInt *)GetImageData(GetVopU(prev_rec_vop_padded)) + coff,
                (SInt *)GetImageData(GetVopV(prev_rec_vop_padded)) + coff,
                pred_for, ewidth, 1, Mode & MBM_B_FWDBOT, vx, vy);

             Putblock(col,      row,      &pred_for[0*64], comp->y_chan, 
curr_vop_width,      MB_SIZE);
             Putblock(col >> 1, row >> 1, &pred_for[4*64], comp->u_chan, 
curr_vop_width >> 1,  B_SIZE);
             Putblock(col >> 1, row >> 1, &pred_for[5*64], comp->v_chan, 
curr_vop_width >> 1,  B_SIZE);
             break;
        
         case MBM_B_BAKFLD:
         case MBM_B_BAKFLD | MBM_B_BAKTOP:
         case MBM_B_BAKFLD | MBM_B_BAKBOT:
         case MBM_B_BAKFLD | MBM_B_BAKTOP | MBM_B_BAKBOT:
             yoff =  (col + edge) + (row + edge) *  ewidth;
             coff = ((col + edge) + (row + edge) * (ewidth >> 1)) >> 1;
             index += 2*MB_num_x;
             vx = 2.0 * mot_x[index];
             vy = 2.0 * mot_y[index];
             ClipMV(col, row, curr_vop_width, curr_vop_height, edge, &vx, &vy);
             BMBFieldMotComp(
                (SInt *)GetImageData(GetVopY(next_rec_vop_padded)) + yoff,
                (SInt *)GetImageData(GetVopU(next_rec_vop_padded)) + coff,
                (SInt *)GetImageData(GetVopV(next_rec_vop_padded)) + coff,
                pred_back, ewidth, 0, Mode & MBM_B_BAKTOP, vx, vy);
             vx = 2.0 * mot_x[index+1];
             vy = 2.0 * mot_y[index+1];
             ClipMV(col, row, curr_vop_width, curr_vop_height, edge, &vx, &vy);
             BMBFieldMotComp(
                (SInt *)GetImageData(GetVopY(next_rec_vop_padded)) + yoff,
                (SInt *)GetImageData(GetVopU(next_rec_vop_padded)) + coff,
                (SInt *)GetImageData(GetVopV(next_rec_vop_padded)) + coff,
                pred_back, ewidth, 1, Mode & MBM_B_BAKBOT, vx, vy);

             Putblock(col,      row,      &pred_back[0*64], comp->y_chan, 
curr_vop_width,      MB_SIZE);
             Putblock(col >> 1, row >> 1, &pred_back[4*64], comp->u_chan, 
curr_vop_width >> 1,  B_SIZE);
             Putblock(col >> 1, row >> 1, &pred_back[5*64], comp->v_chan, 
curr_vop_width >> 1,  B_SIZE);
             break;

         case MBM_B_AVEFLD+0x00: case MBM_B_AVEFLD+0x10: case MBM_B_AVEFLD+0x20: 
case MBM_B_AVEFLD+0x30:
         case MBM_B_AVEFLD+0x40: case MBM_B_AVEFLD+0x50: case MBM_B_AVEFLD+0x60: 
case MBM_B_AVEFLD+0x70:
         case MBM_B_AVEFLD+0x80: case MBM_B_AVEFLD+0x90: case MBM_B_AVEFLD+0xa0: 
case MBM_B_AVEFLD+0xb0:
         case MBM_B_AVEFLD+0xc0: case MBM_B_AVEFLD+0xd0: case MBM_B_AVEFLD+0xe0: 
case MBM_B_AVEFLD+0xf0:
             yoff =  (col + edge) + (row + edge) *  ewidth;
             coff = ((col + edge) + (row + edge) * (ewidth >> 1)) >> 1;
             vx = 2.0 * mot_x[index];
             vy = 2.0 * mot_y[index];
             ClipMV(col, row, curr_vop_width, curr_vop_height, edge, &vx, &vy);
             BMBFieldMotComp(
                (SInt *)GetImageData(GetVopY(prev_rec_vop_padded)) + yoff,
                (SInt *)GetImageData(GetVopU(prev_rec_vop_padded)) + coff,
                (SInt *)GetImageData(GetVopV(prev_rec_vop_padded)) + coff,
                pred_for, ewidth, 0, Mode & MBM_B_FWDTOP, vx, vy);
             vx = 2.0 * mot_x[index + 1];
             vy = 2.0 * mot_y[index + 1];
             ClipMV(col, row, curr_vop_width, curr_vop_height, edge, &vx, &vy);
             BMBFieldMotComp(
                (SInt *)GetImageData(GetVopY(prev_rec_vop_padded)) + yoff,
                (SInt *)GetImageData(GetVopU(prev_rec_vop_padded)) + coff,
                (SInt *)GetImageData(GetVopV(prev_rec_vop_padded)) + coff,
                pred_for, ewidth, 1, Mode & MBM_B_FWDBOT, vx, vy);
             index += 2*MB_num_x;
             vx = 2.0 * mot_x[index];
             vy = 2.0 * mot_y[index];
             ClipMV(col, row, curr_vop_width, curr_vop_height, edge, &vx, &vy);
             BMBFieldMotComp(
                (SInt *)GetImageData(GetVopY(next_rec_vop_padded)) + yoff,
                (SInt *)GetImageData(GetVopU(next_rec_vop_padded)) + coff,
                (SInt *)GetImageData(GetVopV(next_rec_vop_padded)) + coff,
                pred_back, ewidth, 0, Mode & MBM_B_BAKTOP, vx, vy);
             vx = 2.0 * mot_x[index + 1];
             vy = 2.0 * mot_y[index + 1];
             ClipMV(col, row, curr_vop_width, curr_vop_height, edge, &vx, &vy);
             BMBFieldMotComp(
                (SInt *)GetImageData(GetVopY(next_rec_vop_padded)) + yoff,
                (SInt *)GetImageData(GetVopU(next_rec_vop_padded)) + coff,
                (SInt *)GetImageData(GetVopV(next_rec_vop_padded)) + coff,
                pred_back, ewidth, 1, Mode & MBM_B_BAKBOT, vx, vy);

             for (k = 0; k < 6*64; k++)
                 pred_for[k] = (pred_for[k] + pred_back[k] + 1) >> 1;

             Putblock(col,      row,      &pred_for[0*64], comp->y_chan, 
curr_vop_width,      MB_SIZE);
             Putblock(col >> 1, row >> 1, &pred_for[4*64], comp->u_chan, 
curr_vop_width >> 1,  B_SIZE);
             Putblock(col >> 1, row >> 1, &pred_for[5*64], comp->v_chan, 
curr_vop_width >> 1,  B_SIZE);
             break;

         default: break;
       }
        
     }


Void Putblock(Int x,
       Int y,
       SInt *pred,
       Image *comp_image,
       Int width,
       Int mb_size)
{
  Int m, n;

  for (m = 0; m < mb_size; m++)
    for (n = 0; n < mb_size; n++)
      comp_image->f[(y+m)*width+x+n] = (SInt) pred[m*mb_size+n];
}
          





/***********************************************************CommentBegin******
 *   --- halfpel_motion_compensation ---
 * -- Motion Compensation (forward/backward) for a block
 *
 * Author :
 *      HHI -- Minhua Zhou
 *
 * Created :
 *      05.03.97
 *
 * Purpose :
 *     block-based motion compensation
 *
 * Arguments in :
 *   SInt *ref,		padded reference picture (luminance/chrominance/alpha)
 *   SInt vx_hpel,	horizontal component of MV		
 *   SInt vy_hpel,	vertical component of MV
 *   Int offset_x,	horizontal spatial offset
 *   Int offset_y,	vertical spatial offset
 *   Int npix,		horizontal resolution of the reference picture
 *   Int bksize_x,	block size (horizontal)
 *   Int bksize_y,	block size (vertical)
 *   Int div,		vector accuarcy (2/4/8/12/16)
  * Arguments in/out :
 *
 *
 * Arguments out :
 *   SInt *pred_blk	prediction block
 *
 * Return values :
 *      none
 *
 * Side effects :
 *
 *
 * Description :
 *           
 *
 *
 * See also :
 *
 *
 * Modified :
 *
  ***********************************************************CommentEnd********/

 
Void halfpel_motion_compensation (
    SInt *ref,
    Int vx_hpel,
    Int vy_hpel,
    Int offset_x,
    Int offset_y,
    Int npix, Int nlin,
    Int bksize_x,
    Int bksize_y,
    Int div,
    Int rounding_control,
    Int edge,
    SInt *pred_blk
  ) {   
    Int k,l,vxmod2,vymod2,vx0,vy0,vx,vy;
    static Int pel_pos[4][16]={
                              {0,1,1,1},
                              {0,0,1,1,1,1,1,2},
                              {0,0,0,1,1,1,1,1,1,1,2,2},
                              {0,0,0,1,1,1,1,1,1,1,1,1,1,1,2,2}
                             };
    
    Int index,index1,offset;
    Int row0,col0,row1,col1,row2,col2,col3,out_of_reference_vop;
    Int nlin1,npix1;
    nlin1 = nlin-edge;
    npix1 = npix-edge;
    vx=vx_hpel;vy=vy_hpel;
    vxmod2=vx%div;vymod2=vy%div;
    vx0=vx/div;vy0=vy/div;
    if (vxmod2<0) {vx0--;vxmod2+=div;}
    if (vymod2<0) {vy0--;vymod2+=div;}
    
    if (div>2) {
       div=(div>>2)-1; 
       vxmod2=pel_pos[div][vxmod2];
       if (vxmod2==2) {vx0++;vxmod2=0;}
       vymod2=pel_pos[div][vymod2];
       if (vymod2==2) {vy0++;vymod2=0;}
     }

   


    row0 = offset_y+vy0; col0 = offset_x+vx0;

    out_of_reference_vop = 
(row0<edge)||(col0<edge)||(row0+bksize_y+vymod2>=nlin1)
                           ||(col0+bksize_x+vxmod2>=npix1);
   

   if (out_of_reference_vop ==0) {
    offset=row0*npix+col0;
    if ((vxmod2)&&(vymod2))
       for (k=0;k<bksize_y;k++)
         for (l=0;l<bksize_x;l++) {
            index=k*bksize_x+l;
            index1=k*npix+l+offset;
            
pred_blk[index]=(ref[index1]+ref[index1+1]+ref[index1+npix]+ref[index1+npix+1]+2
-rounding_control)>>2;
        } else if (vxmod2)
       for (k=0;k<bksize_y;k++)
         for (l=0;l<bksize_x;l++) {
            index=k*bksize_x+l;
            index1=k*npix+l+offset;
            pred_blk[index]=(ref[index1]+ref[index1+1]+1-rounding_control)>>1;
        } else if (vymod2)
      for (k=0;k<bksize_y;k++)
         for (l=0;l<bksize_x;l++) {
            index=k*bksize_x+l;
            index1=k*npix+l+offset;
            
pred_blk[index]=(ref[index1]+ref[index1+npix]+1-rounding_control)>>1;
        } else 
           for (k=0;k<bksize_y;k++)
            for (l=0;l<bksize_x;l++) {
            index=k*bksize_x+l;
            index1=k*npix+l+offset;
            pred_blk[index]=ref[index1];
        }
    } else {
 if ((vxmod2)&&(vymod2))
       for (k=0;k<bksize_y;k++)
         for (l=0;l<bksize_x;l++) {
            index=k*bksize_x+l;
            row1 = row0+k;
            col1 = col0+l;
            row2 = row1;
            col2 = col1;
            if (row2<edge) row2=edge;else if (row2>=nlin1) row2=nlin1-1;
            if (col2<edge) col2=edge;else if (col2>=npix1) col2=npix1-1;
            col3 =col2;
            pred_blk[index] = ref[row2*npix+col2];
            col2 = col1+1;
            if (col2<edge) col2=edge;else if (col2>=npix1) col2=npix1-1;
            pred_blk[index] += ref[row2*npix+col2];
            row2 = row1+1;
            if (row2<edge) row2=edge;else if (row2>=nlin1) row2=nlin1-1; 
            pred_blk[index] += ref[row2*npix+col2]+ref[row2*npix+col3];
            pred_blk[index] = (pred_blk[index]+2-rounding_control)>>2;  
      } else if (vxmod2)
       for (k=0;k<bksize_y;k++)
         for (l=0;l<bksize_x;l++) {
            index=k*bksize_x+l;
            row2 = row0+k;
            col2=col1 = col0+l;
            if (row2<edge) row2=edge;else if (row2>=nlin1) row2=nlin1-1;
            if (col2<edge) col2=edge;else if (col2>=npix1) col2=npix1-1;
            pred_blk[index] = ref[row2*npix+col2];
            col2 = col1+1;
            if (col2<edge) col2=edge;else if (col2>=npix1) col2=npix1-1;
            pred_blk[index] += ref[row2*npix+col2];
            pred_blk[index]=(pred_blk[index]+1-rounding_control)>>1;

        } else if (vymod2)
      for (k=0;k<bksize_y;k++)
         for (l=0;l<bksize_x;l++) {
            index=k*bksize_x+l;
             row2=row1= row0+k;
             col2 = col0+l;
            if (row2<edge) row2=edge;else if (row2>=nlin1) row2=nlin1-1;
            if (col2<edge) col2=edge;else if (col2>=npix1) col2=npix1-1;
            pred_blk[index] = ref[row2*npix+col2];
            row2 = row1+1;
            if (row2<edge) row2=edge;else if (row2>=nlin1) row2=nlin1-1;
            pred_blk[index] += ref[row2*npix+col2];
            pred_blk[index]=(pred_blk[index]+1-rounding_control)>>1;
        } else 
           for (k=0;k<bksize_y;k++)
            for (l=0;l<bksize_x;l++) {
            index=k*bksize_x+l;
            row2 = row0 + k;
            col2 = col0 +l;
            if (row2<edge) row2=edge;else if (row2>=nlin1) row2=nlin1-1;
            if (col2<edge) col2=edge;else if (col2>=npix1) col2=npix1-1;
            pred_blk[index] = ref[row2*npix+col2];
        }
    }

   }

/***********************************************************CommentBegin******
 * --- serach_for_vectors_of_co_located_MB ---
 * -- Search for the motion vectors of the co-located MB 
      for the current MB of B-VOPs
 *
 * Author :
 *      HHI -- Minhua Zhou
 *
 * Created :
 *      05.03.97
 *
 * Purpose :
 *      produce the motion vectors of the co-located MB
 *
 * Arguments in :
 *         Float *mot_x_P,	vector field of the next P-VOP (horizontal components)
 *         Float *mot_y_P,	vector field of the next P-VOP (vertical components)
 *         Int col,		horizontal coordinate of the co-located MB
 *         Int row,		vertical coordinate of the co-located MB
 *         Int npix,		horizontal resolution of the next P-VOP (before padding)
 *         Int nlin,		vertical resolution of the next P-VOP (before padding)
 * Arguments in/out :
 *
 *
 * Arguments out :
 *        SInt *vx_P,		horizontal coordinates of MVs of the co-located MB
 *        SInt *vy_P,		vertical coordinates of MVs of the co-located MB
 
 * Return values :
 *      none
 *
 * Side effects :
 *
 *
 * Description :
 *
 *
 * See also :
 *
 *
 * Modified :
 *
  ***********************************************************CommentEnd********/

 Int serach_for_vectors_of_co_located_MB(
          Float *mot_x_P,
          Float *mot_y_P,
          SInt  *mode_P,
          Int col,
          Int row,
          Int npix,
          Int nlin,
          SInt *vx_P,
          SInt *vy_P
         )
     {
       Int k,mode,mbk_x,mbk_y,mbk_x0,mbk_y0;
       mbk_x = npix/16;
       mbk_y = nlin/16;   
       for (k=0;k<4;k++) vx_P[k]=vy_P[k]=0;
       if ((mot_y_P==NULL)||(mot_x_P==NULL))
        return MBM_TRANSPARENT;
        mbk_x0 = (col+8)>>4;
        mbk_y0 = (row+8)>>4;
       if ((mbk_x0<0)||(mbk_x0>=mbk_x)||(mbk_y0<0)||(mbk_y0>=mbk_y))
           return MBM_INTER16;
       mode = mode_P[mbk_y0*mbk_x + mbk_x0];
       if (mode==MBM_INTRA) return MBM_INTER16;
         else if (mode==MBM_SKIPPED) return MBM_SKIPPED;
          else if (mode==MBM_TRANSPARENT) return MBM_INTER16;
        
       vx_P[0] = (SInt) (2.0*mot_x_P[2*mbk_y0*2*mbk_x+2*mbk_x0]);
       vy_P[0] = (SInt) (2.0*mot_y_P[2*mbk_y0*2*mbk_x+2*mbk_x0]);

       vx_P[1] = (SInt) (2.0*mot_x_P[2*mbk_y0*2*mbk_x+2*mbk_x0+1]);
       vy_P[1] = (SInt) (2.0*mot_y_P[2*mbk_y0*2*mbk_x+2*mbk_x0+1]);

       vx_P[2] = (SInt) (2.0*mot_x_P[(2*mbk_y0+1)*2*mbk_x+2*mbk_x0]);
       vy_P[2] = (SInt) (2.0*mot_y_P[(2*mbk_y0+1)*2*mbk_x+2*mbk_x0]);

       vx_P[3] = (SInt) (2.0*mot_x_P[(2*mbk_y0+1)*2*mbk_x+2*mbk_x0+1]);
       vy_P[3] = (SInt) (2.0*mot_y_P[(2*mbk_y0+1)*2*mbk_x+2*mbk_x0+1]);
       return mode;
   
     }                                   
 


   
Void reorgnization(SInt *mask16) {
             SInt i,j,k,l;
             SInt buf[256];
             for (i=0;i<8;i++)
               for (j=0;j<8;j++) {
                 k=i*16+j;
                 l = i*8+j;
                 buf[l] = mask16[k];
                 buf[l+64] = mask16[k+8];
                 buf[l+128] = mask16[k+128];
                 buf[l+192] = mask16[k+136];
              }
            for (i=0;i<256;i++)
            mask16[i]=buf[i];
         }      



/***********************************************************CommentBegin******
 *
 * -- BMBFieldMotComp -- Find the prediction block
 *
 * Author :
 *  Bob Eifrig
 *
 * Created :
 *  21-jan-97
 *
 * Purpose :
 *    BMBFieldMotComp() motion compensates all components of the current
 *    macroblock with respect to one motion vector.  The actions are
 *    controlled by curfld & reffld:
 *
 * Arguments in :
 *  Macroblock coordinates,
 *  motion vector,
 *  reference images,
 *  perimeter expansion value
 *  reference field selection code
 *
 * Arguments in/out :
 *   Pointers to the upper left corner of the prediction macroblock in the 
 *      reference VOP.
 *   Half-pel luminace montion vector
 *   Flags:
 *      curfld  reffld
 *        -1      X         Frame motion compensation
 *         0      0         Field motion compensation: cur=top ref=top
 *         0     !0         Field motion compensation: cur=top ref=bot
 *         1      0         Field motion compensation: cur=bot ref=top
 *         1     !0         Field motion compensation: cur=bot ref=bot
 *
 * Arguments out :
 *   motion compensated macroblock
 *
 * Return values :
 *
 *
 * Side effects :
 *
 * Description :
 *
 *
 * See also :
 *
 *
 * Modified :
 *
 ***********************************************************CommentEnd********/

Void
BMBFieldMotComp(SInt *ry, SInt *ru, SInt *rv, SInt *out,
    Int width, Int curfld, Int reffld, SInt dx, SInt dy)
{

    if (curfld < 0) {
        /*
         * Frame motion compensation
         */
        MotCompBRegion(ry, width, out, MB_SIZE,
            MB_SIZE, MB_SIZE, dx, dy);
        dx = (dx & 3) ? ((dx >> 1) | 1) : (dx >> 1);
        dy = (dy & 3) ? ((dy >> 1) | 1) : (dy >> 1);
        MotCompBRegion(ru, width >> 1, &out[4*B_SIZE*B_SIZE], B_SIZE,
            B_SIZE, B_SIZE, dx, dy);
        MotCompBRegion(rv, width >> 1, &out[5*B_SIZE*B_SIZE], B_SIZE,
            B_SIZE, B_SIZE, dx, dy);
        return;
    }
    /*
     * Field motion compensation
     */
    if (reffld) {
        ry += width;
        ru += width >> 1;
        rv += width >> 1;
    }
    curfld <<= 4;
    MotCompBRegion(ry, width, out + curfld, MB_SIZE,
        MB_SIZE, MB_SIZE + 1, dx, dy);
    dx = (dx & 3) ? ((dx >> 1) | 1) : (dx >> 1);
    dy = (dy & 6) ? ((dy >> 1) | 2) : (dy >> 1);
    curfld >>= 1;
    MotCompBRegion(ru, width >> 1, &out[4*B_SIZE*B_SIZE] + curfld, B_SIZE,
        B_SIZE, B_SIZE + 1, dx, dy);
    MotCompBRegion(rv, width >> 1, &out[5*B_SIZE*B_SIZE] + curfld, B_SIZE,
        B_SIZE, B_SIZE + 1, dx, dy);
}

/*
 * MotCompRegion() returns a half-pel motion compensated block
 */

Void
MotCompBRegion(SInt *sp, Int sw,    /* Source pointer & image width */
           SInt *dp, Int dw,    /* Destination pointer & image width */
           Int w, Int h,        /* width & height (h odd ==> field) */
           Int dx, Int dy)      /* half pel motion vector (frame coord) */
{
    Int code, x, y = sw;

    code = dx & 1;
    if (h & 1) {
        h >>= 1;
        code |= (dy & 2);
        dy &= ~3;
        sw <<= 1;
        dw <<= 1;
    } else
        if (dy & 1) code |= 2;

    sp += (dx >> 1) + y * (dy >> 1);

    switch (code) {

    case 0:                                 /* no interpolation */
        for (y = 0; y < h; y++) {
            for (x = 0; x < w; x++)
                dp[x] = sp[x];
            dp += dw;
            sp += sw;
        }
        break;

    case 1:                                 /* horizontal interp */
        for (y = 0; y < h; y++) {
            for (x = 0; x < w; x++)
                dp[x] = (sp[x] + sp[x+1] + 1) >> 1;
            dp += dw;
            sp += sw;
        }
        break;

    case 2:                                 /* vertical interp */
        for (y = 0; y < h; y++) {
            for (x = 0; x < w; x++)
                dp[x] = (sp[x] + sp[x+sw] + 1) >> 1;
            dp += dw;
            sp += sw;
        }
        break;

    case 3:                                 /* vert & horiz interp */
        for (y = 0; y < h; y++) {
            for (x = 0; x < w; x++)
                dp[x] = (sp[x] + sp[x+1] + sp[x+sw] + sp[x+sw+1] + 2) >> 2;
            dp += dw;
            sp += sw;
        }
        break;
    }
}



/***********************************************************CommentBegin******
 *
 * -- ClipMV -- Limit a motion vector to edge pixel beyond reference VOP
 *
 * Author :
 *  Bob Eifrig
 *
 * Created :
 *  12-dec-97
 *
 * Purpose :
 *  If the decoder receivies a MV extending beyond the 'edge' pixel perimeter of
 *  the reference VOP, it is clipped coordinate wise.
 *
 * Arguments in :
 *  Macroblock coordinates,
 *  VOP dimensions
 *  edge padding width
 *
 * Arguments in/out :
 *  The motion vector (half pel coordinates)
 *
 * Return values :
 *
 *
 * Side effects :
 *
 * Description :
 *
 *
 * See also :
 *
 *
 * Modified :
 *
 ***********************************************************CommentEnd********/

Void
ClipMV(Int x, Int y, Int width, Int height, Int edge, SInt *mvxp, SInt *mvyp)
{
    Int mvx = 2*x + *mvxp;
    Int mvy = 2*y + *mvyp;
    Int edge2 = 2*edge;

    width  = 2*width + edge2 - 2*MB_SIZE;
    height = 2*height + edge2 - 2*MB_SIZE;
    if (mvx < -edge2)
        *mvxp = -edge2 - 2*x;
    else if (mvx > width)
        *mvxp = width - 2*x;
    if (mvy < -edge2)
        *mvyp = -edge2 - 2*y;
    else if (mvy > height)
        *mvyp = height - 2*y;
}
  
           
