/*****************************************************************************
 *
 * This software module was originally developed by
 *
 *   J. Ignacio Ronda (UPM-GTI / ACTS-MoMuSyS)
 *   Angel Pacheco (UPM-GTI / ACTS-MoMuSyS)
 *
 * and edited by
 *
 *   Robert Danielsen (Telenor / ACTS-MoMuSyS)
 *   Fernando Jaureguizar (UPM-GTI / ACTS-MoMuSyS)
 *   Claudia Billotet-Hoffmann (DTAG / ACTS-MoMuSyS)
 *   Ferran Marques (UPM / ACTS-MoMuSyS)
 *   Ulrike Pestel-Schiller (TUH / ACTS-MoMuSyS)
 *   Noel Brady (Teltec / ACTS-MoMuSyS)
 *   Luis Ducla Soares (IST / 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_util.c
 *
 * Author:      J. Ignacio Ronda / Angel Pacheco, UPM-GTI
 *
 * Created:     02.02.96
 *
 * Description: * Functions to perform an image with edge, a vop with both /
 *                Y and A planes with an edge, and to insert the Y and A
 *                planes of a vop into another one (no memory is allocated).
 *              * Function to perform interpolation.
 *              * Function to translate 8x8 and 16x16 motion vector (Float)
 *                Image's into other Image's with the final 8x8 and 16x16 motion
 *                vectors (given by the modes Image).
 *              * Function to choose the  MB mode.
 *              * Functions to compute SAD and other operation over MB's.
 *
 * Flags:       -D_PRINT_OUT_MV_   : prints a message if mv is outside
 *              -D_PRINT_TRANS_MV_ : prints a message if mv is transparent
 *
 * Modified:
 *      21.04.96 Robert Danielsen: Reformatted. New headers.
 *      02.07.96 Fernando Jaureguizar: Reformatted.
 *      30.08.96 Fernando Jaureguizar: inclusion of subsamp_alpha() 
 *               function, modified to allow MBM_BOUNDARY block 
 *               type
 *      22.10.96 Angel Pacheco: modification of the subsamp_alpha()
 *               fuction to allow both block-based and macroblock-based
 *               subsampling.
 *      28.11.96 Ferran Marques: integration changes of (22.10.96)
 *      06.03.97 Robert Danielsen: Improved the DIFF macro. Solution from
 *               Frank Bossen.
 *      21.05.97 Angel Pacheco: New find_pmvs() function, the same for
 *               prediction calculus in both encoder/decoder (modified
 *               from the old find_pmv() in mot_decode.c).
 *      16.06.97 Angel Pacheco: modified B_* defines to MBM_*.
 *               Added subsamp_alpha_with modes and SetRectAlphaDecisions
 *               functions (mods to unify the modes in enc/dec.
 *      18.07.97 Ulrike Pestel: Added remove_padding
 *      11.12.97 
 *
 ***********************************************************HeaderEnd*********/

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

#include <stdio.h>
#include "mom_structs.h"
#include "vm_common_defs.h"
#include "mom_image.h"
#include "mom_access.h"

#include "mot_util.h"
#include "mot_est.h"
#include "mot_comp.h"

/* ------------------------------------------------------------------------- */

/* Macro to compute the MB absolute error difference of the inside the shape */

static Int P_diff;
#define DIFF(a,v1,v2,idx) ((a[idx] != 0) ? (P_diff = (v1[idx]-v2[idx]), ABS(P_diff)) : 0)


/* #define DIFF(a,v1,v2,idx) ((a[idx]!=0) ? ABS(v1[idx]-v2[idx]) : 0) */

/* ------------------------------------------------------------------------- */

/***********************************************************CommentBegin******
 *
 * -- subsamp_alpha --
 *
 * Author :
 *      UPM-GTI - J. Ignacio Ronda / Angel Pacheco
 *
 * Created :
 *      02.02.96
 *
 * Purpose :
 *      generates an array with the alpha plane subsampled in MB/block
 *      pixel units. This array is used to see if the block/macroblock
 *      is:
 *         MBM_TRANSPARENT = all pixels are transparent (outside the shape)
 *         MBM_OPAQUE      = all pixels are not transparent (inside the shape)
 *         MBM_BOUNDARY    = transparent and not transparent pixels at the
 *                         same time (in the boundary of the shape)
 *
 * Arguments in :
 *      SInt   *alpha,      alpha plane data
 *      Int    br_width,    width of the alpha plane data
 *      Int    br_height,   height of the alpha plane data
 *
 * Arguments in/out :
 *
 *
 * Arguments out :
 *      SInt   *alpha_sub   subsampled alpha data
 *
 * Return values :
 *      none
 *
 * Side effects :
 *
 *
 * Description :
 *      It does not allocate memory for the subsampled array
 *
 * See also :
 *
 *
 * Modified :
 *      22.10.96 Angel Pacheco: added a parameter in subsamp_alpha() to perform
 *               the operation block or macroblock based.
 *
 ***********************************************************CommentEnd********/
 
Void
subsamp_alpha(
  SInt   *alpha,      /* <-- alpha plane data                     */
  Int    br_width,    /* <-- width of the alpha plane data        */
  Int    br_height,   /* <-- height  of the alpha plane data      */
  Int    block_based, /* <-- ==1/0 block/MB-based subsampling     */ 
  SInt   *alpha_sub   /* --> subsampled alpha data                */
  )
{
  Int   h, v;
  Int   br_h;
  Int   br_w;
  Int   size,cells;
 
  size=(block_based==1)?B_SIZE:MB_SIZE;
  br_h=br_height/size;
  br_w=br_width/size;
  cells=size*size;

  for (v=0;v<br_h;v++)
    for (h=0;h<br_w;h++)
      alpha_sub[v*br_w+h]=0;
 
  for (v=0;v<br_height;v++)
    for (h=0;h<br_width;h++)
      if (alpha[v*br_width+h])
        alpha_sub[(v/size)*br_w+(h/size)] ++;
 
  for (v=0;v<br_h;v++)
    for (h=0;h<br_w;h++)
      if (alpha_sub[v*br_w+h]==0)
        alpha_sub[v*br_w+h]=MBM_TRANSPARENT;
      else if (alpha_sub[v*br_w+h]==cells)    /* size x size */
        alpha_sub[v*br_w+h]=MBM_OPAQUE;
      else
        alpha_sub[v*br_w+h]=MBM_BOUNDARY;
}
 
/***********************************************************CommentBegin******
 *
 * -- subsamp_alpha_with_modes --
 *
 * Author :
 *      UPM-GTI - Angel Pacheco
 *
 * Created :
 *      16.06.97
 *
 * Purpose :
 *      generates an array with the alpha plane subsampled in block
 *      pixel units. This array is used to see if the block is:
 *         MBM_TRANSPARENT = all pixels are transparent (outside the shape)
 *         MBM_******      = "****" mode of the block.
 *
 * Arguments in :
 *      SInt   *alpha,      alpha plane data
 *      SInt   *modes,      macroblock modes data
 *      Int    br_width,    width of the alpha plane data
 *      Int    br_height,   height of the alpha plane data
 *
 * Arguments in/out :
 *
 *
 * Arguments out :
 *      SInt   *alpha_sub   subsampled alpha data
 *
 * Return values :
 *      none
 *
 * Side effects :
 *
 *
 * Description :
 *      It does not allocate memory for the subsampled array
 *
 * See also :
 *
 *
 * Modified :
 *      22.10.96 Angel Pacheco: added a parameter in subsamp_alpha() to perform
 *               the operation block or macroblock based.
 *
 ***********************************************************CommentEnd********/

Void                                                                            
subsamp_alpha_with_modes(
  SInt   *alpha,      /* <-- alpha plane data                     */
  SInt   *modes,      /* <-- macroblock modes data                */
  Int    br_width,    /* <-- width of the alpha plane data        */
  Int    br_height,   /* <-- height  of the alpha plane data      */
  SInt   *alpha_sub   /* --> subsampled alpha data                */
  )
{
  Int   h, v;
  Int   br_h;
  Int   br_w;
  Int   size,cells;
 
  size=B_SIZE;
  br_h=br_height/size;
  br_w=br_width/size;
  cells=size*size;
 
  for (v=0;v<br_h;v++)
    for (h=0;h<br_w;h++)
      alpha_sub[v*br_w+h]=0;
 
  for (v=0;v<br_height;v++)
    for (h=0;h<br_width;h++)
      if (alpha[v*br_width+h])
        alpha_sub[(v/size)*br_w+(h/size)] ++;
 
  for (v=0;v<br_h;v++)
    for (h=0;h<br_w;h++)
      if (alpha_sub[v*br_w+h]==0)
        alpha_sub[v*br_w+h]=MBM_TRANSPARENT;
      else if (alpha_sub[v*br_w+h]==cells)       /* 8 x 8        */
        alpha_sub[v*br_w+h]=modes[v/2*br_w/2+h/2]; /* MBM_OPAQUE   */
      else
        alpha_sub[v*br_w+h]=modes[v/2*br_w/2+h/2]; /* MBM_BOUNDARY */
}


/***********************************************************CommentBegin******
 *
 * -- MakeImageEdge -- Creates a SInt-Image with an edge from another SInt-Image
 *
 * Author :
 *      UPM-GTI - J. Ignacio Ronda / Angel Pacheco
 *
 * Created :
 *      02.02.96
 *
 * Purpose :
 *      Creates a SInt-Image with an edge from another SInt-Image
 *
 * Arguments in :
 *      Image   *ima,       SInt-Image
 *      Int     edge,       edge
 *
 * Arguments in/out :
 *      Image   *ima_edge   SInt-Image with an edge
 *
 * Arguments out :
 *
 *
 * Return values :
 *      none
 *
 * Side effects :
 *      1) It does not allocate memory for output SInt-Image
 *      2) It does assume the memory is zero initialized
 *
 * Description :
 *
 *
 * See also :
 *
 *
 * Modified :
 *
 *
 ***********************************************************CommentEnd********/

Void
MakeImageEdge(
   Image   *ima,     /* <-- SInt-Image (MxN)                                */
   Int     edge,     /* <-- edge                                            */
   Image   *ima_edge /* --> SInt-Image with an edge ((M+2*edge)*(N+2*edge)) */
   )
{
  SInt   *ima_data,
         *ima_data_edge;

  Int    i, j, w, h, width, height;

  /* copy data from alpha */
  ima_data_edge=(SInt*)GetImageData(ima_edge);
  ima_data=(SInt*)GetImageData(ima);

  w=(Int)GetImageSizeX(ima)+2*edge;
  h=(Int)GetImageSizeY(ima)+2*edge;


  height=(Int)GetImageSizeY(ima);
  width=(Int)GetImageSizeX(ima);
  for(j=0; j<height;j++)
    for(i=0; i<width;i++)
      ima_data_edge[(j+edge)*w + edge+i]=ima_data[j*width+i];

}
/***********************************************************CommentBegin******
 *
 * -- RemovePadding -- Creates a SInt-Image without padding of border width edge 
 *
 * Author :
 *      TUH - Ulrike Pestel-Schiller
 *
 * Created :
 *      23.07.97
 *
 * Purpose :
 *      Removes Padding
 *
 * Arguments in :
 *      Image   *ima,       SInt-Image
 *      Int     edge,       edge
 *
 * Arguments in/out :
 *      Image   *ima_edge   SInt-Image with an edge
 *
 * Arguments out :
 *
 *
 * Return values :
 *      none
 *
 * Side effects :
 *      1) It does not allocate memory for output SInt-Image
 *   
 * Description :
 *
 *
 * See also :
 *
 *
 * Modified :
 *
 *
 ***********************************************************CommentEnd********/

Void
Remove_Padding(
   Image   *ima_edge,     /* <-- SInt-Image (MxN)                   */
   Int     edge,     /* <-- edge                         */
   Image   *ima /* --> SInt-Image without an edge ((M-2*edge)*(N-2*edge)) */
   )
{
  SInt   *ima_data,
         *ima_data_edge;

  Int    i, j, w, h, width, height;


  /* copy data from alpha */
  ima_data_edge=(SInt*)GetImageData(ima_edge);
  ima_data=(SInt*)GetImageData(ima);

  w=(Int)GetImageSizeX(ima_edge)-2*edge;
  h=(Int)GetImageSizeY(ima_edge)-2*edge;

  height=(Int)GetImageSizeY(ima_edge);
  width=(Int)GetImageSizeX(ima_edge);
  for(j=0; j<h;j++)
    for(i=0; i<w;i++)
      ima_data[j*w+i]=ima_data_edge[(j+edge)*width + edge+i];

  return;
}

/***********************************************************CommentBegin******
 *
 * -- InterpolateImage -- Interpolates a complete  (SInt)image
 *
 * Author :
 *      Telenor - Karl.Lillevold@nta.no
 *
 * Created :
 *      07.02.95
 *
 * Purpose :
 *      Interpolates a complete  (SInt) image for easier half pel prediction
 *
 * Arguments in :
 *      Image   *input_image,    pointer to input image structure
 *
 * Arguments in/out :
 *
 *
 * Arguments out :
 *      Image   *output_image    pointer to interpolated image
 *
 * Return values :
 *      none
 *
 * Side effects :
 *      Allocates memory to interpolated image
 *
 * Description :
 *
 *
 * See also :
 *
 *
 * Modified :
 *      08.02.96 Claudia Billotet-Hoffmann
 *
 ***********************************************************CommentEnd********/

Void
InterpolateImage(
   Image   *input_image, /* <-- image to interpolate (SInt) */
   Image   *output_image, /* --> interpolated image (SInt)  */
   Int     rounding_control
   )
{
  SInt   *ii, *oo;
  Int    i, j;
  UInt   width, height;

  width = GetImageSizeX(input_image);
  height = GetImageSizeY(input_image);
  ii = (SInt*)GetImageData(output_image);
  oo = (SInt*)GetImageData(input_image);

  /* main image */
  for (j = 0; j < height-1; j++)
    {
    for (i = 0; i  < width-1; i++)
      {
      *(ii + (i<<1)) = *(oo + i);
      *(ii + (i<<1)+1) = (*(oo + i) + *(oo + i + 1) + 1- rounding_control)>>1;
      *(ii + (i<<1)+(width<<1)) = (*(oo + i) + *(oo + i + width) + 1-
                                   rounding_control)>>1;
      *(ii + (i<<1)+1+(width<<1)) = (*(oo+i) + *(oo+i+1) +
                                      *(oo+i+width) + *(oo+i+1+width) + 2-
                                        rounding_control)>>2;
      }
    /* last pels on each line */
    *(ii+ (width<<1) - 2) = *(oo + width - 1);
    *(ii+ (width<<1) - 1) = *(oo + width - 1);
    *(ii+ (width<<1)+ (width<<1)-2) = (*(oo+width-1)+*(oo+width+width-1)+1-
                                       rounding_control)>>1;
    *(ii+ (width<<1)+ (width<<1)-1) = (*(oo+width-1)+*(oo+width+width-1)+1-
                                       rounding_control)>>1;
    ii += (width<<2);
    oo += width;
    }

  /* last lines */
  for (i = 0; i < width-1; i++)
    {
    *(ii+ (i<<1)) = *(oo + i);
    *(ii+ (i<<1)+1) = (*(oo + i) + *(oo + i + 1) + 1- rounding_control)>>1;
    *(ii+ (width<<1)+ (i<<1)) = *(oo + i);
    *(ii+ (width<<1)+ (i<<1)+1) = (*(oo + i) + *(oo + i + 1) + 1-
                                   rounding_control)>>1;
    }

  /* bottom right corner pels */
  *(ii + (width<<1) - 2) = *(oo + width -1);
  *(ii + (width<<1) - 1) = *(oo + width -1);
  *(ii + (width<<2) - 2) = *(oo + width -1);
  *(ii + (width<<2) - 1) = *(oo + width -1);

  return;
}

/***********************************************************CommentBegin******
 *
 * -- GetMotionImages --
 *
 * Author :
 *      UPM-GTI - J. Ignacio Ronda / Angel Pacheco
 *
 * Created :
 *      02.02.96
 *
 * Purpose :
 *      Translate the MVs data from the resulting separated four
 *      (Float) Images (16x16/8x8, X,Y) of the motion estimation process
 *      into two Images, which contain the 16x16 and 8x8 MVs
 *      values acording to the modes (MBM_INTRA, MBM_INTER16,
 *      MBM_INTER8, MBM_TRANSPARENT, MBM_OUT). It also
 *      makes a copy of imode16 (SInt-Image of modes).
 *
 * Arguments in :
 *      Image   *imv16_w,   16x16 horizontal MV Float-Image (MxN) (cuad.)
 *      Image   *imv16_h,   16x16 vertical MV Float-Image   (MxN) (cuad.)
 *      Image   *imv8_w,    8x8  horizontal MV Float-Image (MxN)
 *      Image   *imv8_h,    8x8  vertical MV Float-Image   (MxN)
 *      Image   *imode16,   SInt-Image of modes           (M/2xN/2)
 *
 * Arguments in/out :
 *
 *
 * Arguments out :
 *      Image   **mv_x,     horizontal MV Float-Image (MxN)
 *      Image   **mv_y,     vertical   MV Float-Image (MxN)
 *      Image   **mode,     SInt-Image of modes      (M/2xN/2)
 *
 * Return values :
 *      1 on success, -1 on error
 *
 * Side effects :
 *      It does allocate memory for output Float-Image's
 *
 * Description :
 *
 *
 * See also :
 *
 *
 * Modified :
 *      11.12.97  Bob Eifrig:  added code to convert the field motion vector
 *           images into the single MV image based on MBM_* constant
 *
 *
 ***********************************************************CommentEnd********/

Int
GetMotionImages(
   Image   *imv16_w, /* <-- 16x16 horiz. MV Float-Image (MxN) (cuad.)   */
   Image   *imv16_h, /* <-- 16x16 verti. MV Float-Image   (MxN) (cuad.) */
   Image   *imv8_w,  /* <-- 8x8  horizontal MV Float-Image  (MxN)       */
   Image   *imv8_h,  /* <-- 8x8  vertical MV Float-Image    (MxN)       */
   Image   *imvF_w,  /* <-- field horizontal MV Float-Image  (MxN)      */
   Image   *imvF_h,  /* <-- field vertical MV Float-Image    (MxN)      */
   Image   *imode16, /* <-- SInt-Image of modes            (M/2xN/2)    */
   Image   **mv_x,   /* --> horizontal MV Float-Image      (MxN)        */
   Image   **mv_y,   /* --> vertical   MV Float-Image      (MxN)        */
   Image   **mode    /* --> SInt-Image of modes           (M/2xN/2)     */
   )
{

  Int     i, j;
  Int     width, height,
          base;
  Float   val_x, val_y;
  Float   *data_x, *data_y,
          *mv16_w, *mv16_h,
          *mv8_w,  *mv8_h;
  SInt    *mode16,
          *data_mode;
  SInt    modo;
  Float   *mvF_w, *mvF_h;


  width=GetImageSizeX(imode16); height=GetImageSizeY(imode16);

  (*mode)=AllocImage(width,height,SHORT_TYPE);
  (*mv_x)=AllocImage(width*2,height*2,FLOAT_TYPE);
  (*mv_y)=AllocImage(width*2,height*2,FLOAT_TYPE);
  data_x = (Float*)GetImageData((*mv_x));
  data_y = (Float*)GetImageData((*mv_y));
  data_mode = (SInt*)GetImageData((*mode));
  mode16=(SInt*)GetImageData(imode16);
  mv16_w=(Float*)GetImageData(imv16_w);
  mv16_h=(Float*)GetImageData(imv16_h);
  mv8_w=(Float*)GetImageData(imv8_w);
  mv8_h=(Float*)GetImageData(imv8_h);
  mvF_w = (Float *)GetImageData(imvF_w);
  mvF_h = (Float *)GetImageData(imvF_h);


  for(j=0;j<height;j++)
    {
    for(i=0;i< width;i++)
      {
      modo=data_mode[j*width+i]=mode16[j*width+i];
      if ( modo==MBM_INTRA)      /*INTRA*/
        {
        base=2*j*2*width+2*i;
        data_x[base]=0.0;  data_x[base+1]=0.0;
        data_y[base]=0.0;  data_y[base+1]=0.0;
        base+=width*2;
        data_x[base]=0.0;  data_x[base+1]=0.0;
        data_y[base]=0.0;  data_y[base+1]=0.0;
        }
      else if(modo==MBM_INTER16) /*INTER 16*/
        {
        base=2*j*2*width+2*i;
        val_x=mv16_w[base];val_y=mv16_h[base];

        data_x[base]=val_x; data_x[base+1]=val_x;
        data_y[base]=val_y; data_y[base+1]=val_y;
        base+=width*2;
        data_x[base]=val_x; data_x[base+1]=val_x;
        data_y[base]=val_y; data_y[base+1]=val_y;
        }
      else if (modo==MBM_INTER8)  /*INTER4*8*/
        {
        base=2*j*2*width+2*i;

        data_x[base]   = mv8_w[base];
        data_y[base]   = mv8_h[base];
        data_x[base+1] = mv8_w[base+1];
        data_y[base+1] = mv8_h[base+1];
        base+=width*2;
        data_x[base]   = mv8_w[base];
        data_y[base]   = mv8_h[base];
        data_x[base+1] = mv8_w[base+1];
        data_y[base+1] = mv8_h[base+1];
        }
      else if ((modo >= MBM_FIELD00) && (modo <= MBM_FIELD11))
        {
        base=2*j*2*width+2*i;
        if ((modo - MBM_FIELD00) & 2) {
            data_x[base]   = mvF_w[base + 1];
            data_y[base]   = mvF_h[base + 1];
        } else {
            data_x[base]   = mvF_w[base];
            data_y[base]   = mvF_h[base];
        }
        if ((modo - MBM_FIELD00) & 1) {
            data_x[base + 1] = mvF_w[base + 2*width + 1];
            data_y[base + 1] = mvF_h[base + 2*width + 1];
        } else {
            data_x[base + 1] = mvF_w[base + 2*width];
            data_y[base + 1] = mvF_h[base + 2*width];
        }
      }
      else if (modo==MBM_TRANSPARENT)
        {
#ifdef _PRINT_TRANS_MV_
        fprintf(stderr,"MB(%d,%d) TRANSPARENT\n");
#endif
        ;
        }
      else if ( modo==MBM_SPRITE)      /*ONLINE SPRITE*/
        {
        base=2*j*2*width+2*i;
        data_x[base]=0.0;  data_x[base+1]=0.0;
        data_y[base]=0.0;  data_y[base+1]=0.0;
        base+=width*2;
        data_x[base]=0.0;  data_x[base+1]=0.0;
        data_y[base]=0.0;  data_y[base+1]=0.0;
        }
      else if (modo==MBM_OUT)
        {
#ifdef _PRINT_OUT_MV_
        fprintf(stderr,"MB(%d,%d) OUT\n");
#endif
        ;
        }
      else
        {
        fprintf(stderr,"Mode of motion vector is not allowed");
        return(-1);
        }
      }       /* end for*/
    }       /* end for*/

  return(1);
}

/***********************************************************CommentBegin******
 *
 * -- ChooseMode -- chooses coding mode INTRA/INTER dependig on the SAD values
 *
 * Author :
 *      Telenor - Karl.Lillevold@nta.no
 *
 * Created :
 *      30.11.94
 *
 * Purpose :
 *      chooses coding mode INTRA/INTER dependig on the SAD values
 *
 * Arguments in :
 *      SInt    *curr,     current Y values (not extended)
 *      SInt    *alpha,    quantized alpha plane of current picture
 *      Int     x_pos,     upper-left MB corner hor. coor.
 *      Int     y_pos,     upper-left MB corner ver. coor.
 *      SInt    *MB_Nb     subsampled alpha Nb's
 *      Int     min_SAD,   min SAD (from integer pel search)
 *      UInt    width      current Y picture width
 *
 * Arguments in/out :
 *
 *
 * Arguments out :
 *      none
 *
 * Return values :
 *      1 for INTER, 0 for INTRA
 *
 * Side effects :
 *
 *
 * Description :
 *
 *
 * See also :
 *
 *
 * Modified :
 *
 *
 ***********************************************************CommentEnd********/

Int
ChooseMode(
   SInt   *curr,   /* <-- current Y values (not extended)          */
   SInt   *alpha,  /* <-- quantized alpha plane of current picture */
   Int    x_pos,   /* <-- upper-left MB corner hor. coor.          */
   Int    y_pos,   /* <-- upper-left MB corner ver. coor.          */
   SInt   *MB_Nb,  /* --> subsampled alpha Nb's                    */
   Int    min_SAD, /* <-- min SAD (from integer pel search)        */
   UInt   width    /* <-- current Y picture width                  */
   )
{
  Int   i, j;
  Int   MB_mean = 0, A = 0;
  Int   y_off;

  for (j = 0; j < MB_SIZE; j++)
    {
    y_off = (y_pos + j) * width;
    for (i = 0; i < MB_SIZE; i++)
      {
      if( *(alpha+x_pos + i + y_off)!=0)
        MB_mean += *(curr + x_pos + i + y_off);
      }
    }

  MB_mean /= MB_Nb[y_pos/MB_SIZE*width/MB_SIZE+x_pos/MB_SIZE];

  for (j = 0; j < MB_SIZE; j++)
    {
    y_off = (y_pos + j) * width;
    for (i = 0; i < MB_SIZE; i++)
      {
      if( *(alpha+x_pos + i + y_off)!=0)
        A += ABS( *(curr + x_pos + i + y_off) - MB_mean );
      }
    }

  if (A < (min_SAD - 2*MB_Nb[y_pos/MB_SIZE*width/MB_SIZE+x_pos/MB_SIZE]))
    return 0;
  else
    return 1;
}

/***********************************************************CommentBegin******
 *
 * -- SAD_Macroblock -- obtains the SAD for a Macroblock
 *
 * Author :
 *      UPM-GTI - Angel Pacheco
 *
 * Created :
 *
 *
 * Purpose :
 *      obtains the SAD for a Macroblock
 *
 * Arguments in :
 *      SInt   *ii,          Pointer to the upper-left pel of first MB
 *      SInt   *act_block,   Id, second MB (width=16)
 *      SInt   *alpha,       Id, alpha values (width=16)
 *      UInt   h_length,     Width of first area
 *      Int    Min_FRAME     Minimum prediction error so far
 *
 * Arguments in/out :
 *
 *
 * Arguments out :
 *      none
 *
 * Return values :
 *      sad of the MB
 *
 * Side effects :
 *
 *
 * Description :
 *
 *
 * See also :
 *
 *
 * Modified :
 *
 *
 ***********************************************************CommentEnd********/

Int
SAD_Macroblock(
   SInt   *ii,        /* <-- Pointer to the upper-left pel of first MB */
   SInt   *act_block, /* <-- Id, second MB (width=16)                  */
   SInt   *alpha,     /* <-- Id, alpha values (width=16)               */
   UInt   h_length,   /* <-- Width of first area                       */
   Int    Min_FRAME   /* <-- Minimum prediction error so far           */
   )
{
  Int    i;
  Int    sad = 0;
  SInt   *kk;
  SInt   *kk_alpha;

  kk = act_block;
  kk_alpha = alpha;
  i = 16;
  while (i--)
    {
    sad += (DIFF(kk_alpha,ii,kk,0)+DIFF(kk_alpha,ii,kk,1)
            +DIFF(kk_alpha,ii,kk,2)+DIFF(kk_alpha,ii,kk,3)
            +DIFF(kk_alpha,ii,kk,4)+DIFF(kk_alpha,ii,kk,5)
            +DIFF(kk_alpha,ii,kk,6)+DIFF(kk_alpha,ii,kk,7)
            +DIFF(kk_alpha,ii,kk,8)+DIFF(kk_alpha,ii,kk,9)
            +DIFF(kk_alpha,ii,kk,10)+DIFF(kk_alpha,ii,kk,11)
            +DIFF(kk_alpha,ii,kk,12)+DIFF(kk_alpha,ii,kk,13)
            +DIFF(kk_alpha,ii,kk,14)+DIFF(kk_alpha,ii,kk,15)
            );

    ii += h_length;
    kk += 16;
    kk_alpha += 16;
    if (sad > Min_FRAME)
      return MV_MAX_ERROR;
    }

  return sad;
}

/***********************************************************CommentBegin******
 *
 * -- SAD_Block -- obtains the SAD for a Block
 *
 * Author :
 *      UPM-GTI - Angel Pacheco
 *
 * Created :
 *
 *
 * Purpose :
 *      obtains the SAD for a Block
 *
 * Arguments in :
 *      SInt   *ii,           First area
 *      SInt   *act_block,    Id. second MB (width=16)
 *      SInt   *alpha,        Id, alpha values (width=16)
 *      UInt   h_length,      Width of first area
 *      Int    min_sofar      Minimum prediction error so far
 *
 * Arguments in/out :
 *
 *
 * Arguments out :
 *      none
 *
 * Return values :
 *      sad of the Block
 *
 * Side effects :
 *
 *
 * Description :
 *
 *
 * See also :
 *
 *
 * Modified :
 *
 *
 ***********************************************************CommentEnd********/

Int
SAD_Block(
   SInt   *ii,         /* <-- First area                      */
   SInt   *act_block,  /* <-- Id. second MB (width=16)        */
   SInt   *alpha,      /* <-- Id, alpha values (width=16)     */
   UInt   h_length,    /* <-- Width of first area             */
   Int    min_sofar    /* <-- Minimum prediction error so far */
   )
{
  Int    i;
  Int    sad = 0;
  SInt   *kk;
  SInt   *kk_alpha;

  kk = act_block;
  kk_alpha = alpha;
  i = 8;
  while (i--)
    {
    sad += (DIFF(kk_alpha,ii,kk,0)+DIFF(kk_alpha,ii,kk,1)
            +DIFF(kk_alpha,ii,kk,2)+DIFF(kk_alpha,ii,kk,3)
            +DIFF(kk_alpha,ii,kk,4)+DIFF(kk_alpha,ii,kk,5)
            +DIFF(kk_alpha,ii,kk,6)+DIFF(kk_alpha,ii,kk,7)
            );

    ii += h_length;
    kk += 16;
    kk_alpha += 16;
    if (sad > min_sofar)
      return INT_MAX;
    }

  return sad;
}

/***********************************************************CommentBegin******
 *
 * -- SAD_Field16x8 -- obtains the SAD for a 16x8 field of a Macroblock
 *
 * Author :
 *          Bob Eifrig
 *
 * Created :
 *          20-jan-97
 *
 * Purpose :
 *      obtains the SAD for a 16x8 field of a macroblock
 *
 * Arguments in :
 *      SInt   *ii,          Pointer to the upper-left pel of reference MB
 *      SInt   *act_block,   Ptr to current MB (width=16)
 *      SInt   *alpha,       Ptr to current MB alpha values (width=16)
 *      UInt   h_length,     Width of first area
 *      Int    Min_FRAME     Minimum prediction error so far
 *
 * Arguments in/out :
 *
 *
 * Arguments out :
 *      none
 *
 * Return values :
 *      sad of the MB field
 *
 * Side effects :
 *
 *
 * Description :
 *
 *
 * See also :
 *
 *
 * Modified :
 *
 *
 ***********************************************************CommentEnd********/
 
Int
SAD_Field16x8(
   SInt   *ii,        /* <-- Pointer to the upper-left pel of first MB */
   SInt   *act_block, /* <-- Id, second MB (width=16)                  */
   SInt   *alpha,     /* <-- Id, alpha values (width=16)               */
   UInt   h_length,   /* <-- Width of first area                       */
   Int    Min_FIELD   /* <-- Minimum prediction error so far           */
   )
{
  Int    i;
  Int    sad = 0;
  SInt   *kk;
  SInt   *kk_alpha;
 
  kk = act_block;
  kk_alpha = alpha;
  i = MB_SIZE/2;
  h_length *= 2;
  while (i--)
    {
    sad += ( DIFF(kk_alpha,ii,kk, 0)+DIFF(kk_alpha,ii,kk, 1)
            +DIFF(kk_alpha,ii,kk, 2)+DIFF(kk_alpha,ii,kk, 3)
            +DIFF(kk_alpha,ii,kk, 4)+DIFF(kk_alpha,ii,kk, 5)
            +DIFF(kk_alpha,ii,kk, 6)+DIFF(kk_alpha,ii,kk, 7)
            +DIFF(kk_alpha,ii,kk, 8)+DIFF(kk_alpha,ii,kk, 9)
            +DIFF(kk_alpha,ii,kk,10)+DIFF(kk_alpha,ii,kk,11)
            +DIFF(kk_alpha,ii,kk,12)+DIFF(kk_alpha,ii,kk,13)
            +DIFF(kk_alpha,ii,kk,14)+DIFF(kk_alpha,ii,kk,15));
 
    ii += h_length;
    kk += 2*MB_SIZE;
    kk_alpha += 2*MB_SIZE;
    if (sad > Min_FIELD)
      return MV_MAX_ERROR;
    }
  return sad;
}

/***********************************************************CommentBegin******
 *
 * -- LoadArea -- fills array with a image-data
 *
 * Author :
 *
 *
 * Created :
 *
 *
 * Purpose :
 *      fills array with a image-data
 *
 * Arguments in :
 *      SInt   *im,       pointer to image
 *      Int    x,         horizontal pos
 *      Int    y,         vertical   pos
 *      Int    x_size,    width of array
 *      Int    y_size,    height of array
 *      Int    lx         width of the image data
 *
 * Arguments in/out :
 *
 *
 * Arguments out :
 *      none
 *
 * Return values :
 *      Pointer to the filled array
 *
 * Side effects :
 *      allocates memory for the array that must be freed
 *
 * Description :
 *
 *
 * See also :
 *
 *
 * Modified :
 *
 *
 ***********************************************************CommentEnd********/

SInt  *
LoadArea(
   SInt   *im,       /* <-- pointer to image         */
   Int    x,         /* <-- horizontal pos           */
   Int    y,         /* <-- vertical  pos            */
   Int    x_size,    /* <-- width of array           */
   Int    y_size,    /* <-- height of array          */
   Int    lx         /* <-- width of the image data  */
   )
{
  SInt   *res = (SInt *)malloc(sizeof(SInt)*x_size*y_size);
  SInt   *in;
  SInt   *out;
  Int    i = x_size;
  Int    j = y_size;

  in = im + (y*lx) + x;
  out = res;

  while (j--)
    {
    while (i--)
      *out++ = *in++;
    i = x_size;
    in += lx - x_size;
    }

  return res;
}

/***********************************************************CommentBegin******
 *
 * -- SetArea -- fills a image-data with an array 
 *
 * Author : 
 *      UPM-GTI - Angel Pacheco
 *
 * Created :
 *
 *
 * Purpose :
 *      fills a image-data with an array
 *
 * Arguments in :
 *      SInt   *block     pointer to array
 *      Int    x,         horizontal pos
 *      Int    y,         vertical   pos
 *      Int    x_size,    width of array
 *      Int    y_size,    height of array
 *      Int    lx         width of the image data
 *
 * Arguments in/out :
 *
 *
 * Arguments out :
 *      SInt   *im,       pointer to image
 *
 * Return values :
 *      none
 *
 * Side effects :
 *      
 *
 * Description :
 *
 *
 * See also :
 *
 *
 * Modified :
 *
 *
 ***********************************************************CommentEnd********/

Void
SetArea(
   SInt   *block,    /* <-- pointer to array         */  
   Int    x,         /* <-- horizontal pos in image  */  
   Int    y,         /* <-- vertical  pos in image   */  
   Int    x_size,    /* <-- width of array           */  
   Int    y_size,    /* <-- height of array          */  
   Int    lx,        /* <-- width of the image data  */
   SInt   *im        /* --> pointer to image         */  
   )
{
  SInt   *in;
  SInt   *out;
  Int    i = x_size;
  Int    j = y_size;
 
  in  = block;
  out = im + (y*lx) + x;
 
  while (j--)
    {
    while (i--)
      *out++ = *in++;
    i = x_size;
    out += lx - x_size;
    }
}


/***********************************************************CommentBegin******
 *
 * -- FindMB -- Picks out one MB from picture
 *
 * Author :
 *      Telenor - Karl Olav Lillevold
 *
 * Created :
 *      19.01.93
 *
 * Purpose :
 *      Picks out one MB from picture
 *
 * Arguments in :
 *      Int    x,         horizontal position of MB
 *      Int    y,         vertical   position of MB
 *      UInt   width,     width of the image data
 *      SInt   *image,    image data
 *
 * Arguments in/out :
 *      Int MB[16][16]    filled array
 *
 * Arguments out :
 *
 *
 * Return values :
 *      none
 *
 * Side effects :
 *      fills array with MB data
 *
 * Description :
 *
 *
 * See also :
 *
 *
 * Modified :
 *
 *
 ***********************************************************CommentEnd********/

Void
FindMB(
   Int     x,          /* <-- horizontal position of MB */
   Int     y,          /* <-- vertical   position of MB */
   UInt    width,      /* <-- width of the image data   */
   SInt    *image,     /* <-- image data                */
   Int     MB[16][16]  /* --> filled array              */
   )
{
  Int            n;
  register Int   m;

  for (n = 0; n < MB_SIZE; n++)
    for (m = 0; m < MB_SIZE; m++)
      MB[n][m] = *(image + x+m + (y+n)*width);
}

/***********************************************************CommentBegin******
 *
 * -- find_pmvs --
 *
 * Author :
 *      UPM-GTI - Angel Pacheco
 *
 * Created :
 *      13.03.97
 *
 * Purpose :
 *      Makes the motion vectors prediction for block 'block' (0 = whole MB)
 *
 * Arguments in :
 *      Image  *mot_x,             x-motion vector field
 *      Image  *mot_y,             y-motion vector field
 *      Image  *MB_decisions,      MB modes
 *      Image  *B_decisions,       field with number of vectors per MB
 *      Int    x,                  xpos of the MB in multiples of 16
 *      Int    y,                  ypos of the MB in multiples of 16
 *      Int    block,              block number (0 if one vector per MB,
 *                                 1..4 else)
 *      Int    transparent_value,  value of the transparency (0=enc, 2=dec)
 *
 * Arguments out :
 *      Int    *error_flag         set if an error occured
 *      Int    *mvx                hor predicted motion vector [half-pels units]
 *      Int    *mvy                ver predicted motion vector [half-pels units]
 *
 * Return values :
 *
 *
 * Side effects :
 *
 *
 * Description :
 *             
 *             
 * Notes :
 *      This function was in the mot_decode.c file, but was rewriten and
 *      included in thif file to unify teh predictors in both encoder and
 *      decoder.
 *
 * See also :
 *
 *
 * Modified :
 *      21.05.97 Angel Pacheco: modified to predict both coordinates.
 *      24.09.97 Noel Brady: modified to be compatible with MS/MEI 
 *               interpretations.
 *      11.12.97 Bob Eifrig: Calculate PMVs when one or more adjancent
 *               MBs are field motion compensated.
 *
 ***********************************************************CommentEnd********/

Void   /* MVP/Noel */
find_pmvs(
   Image  *mot_x,       /* x-motion vector field                             */
   Image  *mot_y,       /* y-motion vector field                             */
   Image  *MB_decisions,/* MB modes                                          */
   Image  *B_decisions, /* field with number of vectors per MB               */
   Int    x,            /* xpos of the MB in multiples of 16 (hor coord)     */
   Int    y,            /* ypos of the MB in multiples of 16 (ver coord)     */
   Int    block,        /* block number (0 if one vector per MB, 1..4 else)  */
   Int    transparent_value, /* value of the transparency (0=enc, 2=dec)     */
   Int    *error_flag,       /* set if an error occured                      */
   Int    *mvx,     /* hor predicted motion vector [ in half-pixels units ]  */
   Int    *mvy      /* ver predicted motion vector [ in half-pixels units ]  */
   )
{
  Float   p1x,p2x,p3x;
  Float   p1y,p2y,p3y;
  Int     xin1, xin2, xin3;
  Int     yin1, yin2, yin3;
  Int     vec1, vec2, vec3;
  Int     rule1, rule2, rule3;
  Short   *dcsn_data = (Short *) GetImageData(B_decisions);
  Float   *motxdata = (Float *) GetImageData(mot_x);
  Float   *motydata = (Float *) GetImageData(mot_y);
  Int     xB = GetImageSizeX(B_decisions);
  Int     xM = GetImageSizeX(mot_x);
  Int     mb_mode, sum;

  /* In a previous version, a MB vector (block = 0) was predicted the same way
     as block 1, which is the most likely interpretation of the VM.

     Therefore, if we have advanced pred. mode, and if all MBs around have
     only one 16x16 vector each, we chose the appropiate block as if these
     MBs have 4 vectors.

     This different prediction affects only 16x16 vectors of MBs with
     transparent blocks.
 
     In the current version, we choose for the 16x16 mode the first
     non-transparent block in the surrounding MBs
  */
 
  switch (block)
    {
    case 0:
      vec1 = 1 ; yin1 = y  ; xin1 = x-1;
      vec2 = 2 ; yin2 = y-1; xin2 = x;
      vec3 = 2 ; yin3 = y-1; xin3 = x+1;
      break;
    case 1:
      vec1 = 1 ; yin1 = y  ; xin1 = x-1;
      vec2 = 2 ; yin2 = y-1; xin2 = x;
      vec3 = 2 ; yin3 = y-1; xin3 = x+1;
      break;
    case 2:
      vec1 = 0 ; yin1 = y  ; xin1 = x;
      vec2 = 3 ; yin2 = y-1; xin2 = x;
      vec3 = 2 ; yin3 = y-1; xin3 = x+1;
      break;
    case 3:
      vec1 = 3 ; yin1 = y  ; xin1 = x-1;
      vec2 = 0 ; yin2 = y  ; xin2 = x;
      vec3 = 1 ; yin3 = y  ; xin3 = x;
      break;
    case 4:
      vec1 = 2 ; yin1 = y  ; xin1 = x;
      vec2 = 0 ; yin2 = y  ; xin2 = x;
      vec3 = 1 ; yin3 = y  ; xin3 = x;
      break;
    default:
      printf("Illegal block number in find_pmv (mot_decode.c)");
      *error_flag = 1;
      *mvx=*mvy=0;
      return ;
    }

  if (block==0)
    {
    /* according to the motion encoding, we must choose a first non-transparent
       block in the surrounding MBs (16-mode)
     */

    if (x>0 && ValidCandidateMVP(x,y,xin1,yin1,vec1,xB,transparent_value,
        MB_decisions,dcsn_data))
      rule1 = 0; 
    else
      rule1 = 1;
 
    if (y>0 && ValidCandidateMVP(x,y,xin2,yin2,vec2,xB,transparent_value,
        MB_decisions,dcsn_data))
      rule2 = 0;
    else
      rule2 = 1;
 
    if ((x != xB/2 -1) && 
        (y>0) && ValidCandidateMVP(x,y,xin3,yin3,vec3,xB,transparent_value,
                                   MB_decisions,dcsn_data))
      rule3 = 0;
    else
      rule3 = 1;
    }
 
  else
    {
    /* check borders for single blocks (advanced mode) */
    /* rule 1 */
    if (((block == 1 || block == 3) && (x == 0))  ||     /* left border */
                       /* left block/MB is transparent */
        (!ValidCandidateMVP(x,y,xin1,yin1,vec1,xB,transparent_value,
                            MB_decisions,dcsn_data)))
      rule1 = 1;
    else
      rule1 = 0;
 
    /* rule 2 */
    if (((block == 1 || block == 2) && (y == 0))  ||     /* top border */
                       /* top block/MB is transparent */
        (!ValidCandidateMVP(x,y,xin2,yin2,vec2,xB,transparent_value,
                            MB_decisions,dcsn_data)))
      rule2 = 1;
    else
      rule2 = 0;
 
    /* rule 3 */
    if (((block == 1 || block == 2) && (x == xB/2 -1 || y == 0)) ||
        /* right & top border */
                       /* right block/MB is transparent */
        (!ValidCandidateMVP(x,y,xin3,yin3,vec3,xB,transparent_value,
                            MB_decisions,dcsn_data)))
      rule3 = 1;
    else
      rule3 = 0;
 
    }
                                    
  if (rule1 )
    {
    p1x = p1y = 0;
    }
  else if (((mb_mode = ModeMB(MB_decisions,xin1,yin1)) >= MBM_FIELD00) && (mb_mode <= MBM_FIELD11)) {
    sum = 2*(BV(motxdata, xM, xin1, yin1, 0, 0) + BV(motxdata, xM, xin1, yin1, 1, 0));
    p1x = 0.5 * ((sum & 3) ? ((sum | 2) >> 1) : (sum >> 1));
    sum = 2*(BV(motydata, xM, xin1, yin1, 0, 0) + BV(motydata, xM, xin1, yin1, 1, 0));
    p1y = 0.5 * ((sum & 3) ? ((sum | 2) >> 1) : (sum >> 1));
  } else {
    p1x = BV(motxdata, xM, xin1, yin1, vec1&0x1, vec1>>1 );
    p1y = BV(motydata, xM, xin1, yin1, vec1&0x1, vec1>>1 );
  }

  if (rule2)
    {
    p2x = p2y = 0 ;
    }
  else if (((mb_mode = ModeMB(MB_decisions,xin2,yin2)) >= MBM_FIELD00) && (mb_mode <= MBM_FIELD11)) {
    sum = 2*(BV(motxdata, xM, xin2, yin2, 0, 0) + BV(motxdata, xM, xin2, yin2, 1, 0));
    p2x = 0.5 * ((sum & 3) ? ((sum | 2) >> 1) : (sum >> 1));
    sum = 2*(BV(motydata, xM, xin2, yin2, 0, 0) + BV(motydata, xM, xin2, yin2, 1, 0));
    p2y = 0.5 * ((sum & 3) ? ((sum | 2) >> 1) : (sum >> 1));
  } else {
    p2x = BV(motxdata, xM, xin2, yin2, vec2&0x1, vec2>>1 );
    p2y = BV(motydata, xM, xin2, yin2, vec2&0x1, vec2>>1 );
  }

  if (rule3 )
    {
    p3x = p3y =0;
    }
  else if (((mb_mode = ModeMB(MB_decisions,xin3,yin3)) >= MBM_FIELD00) && (mb_mode <= MBM_FIELD11)) {
    sum = 2*(BV(motxdata, xM, xin3, yin3, 0, 0) + BV(motxdata, xM, xin3, yin3, 1, 0));
    p3x = 0.5 * ((sum & 3) ? ((sum | 2) >> 1) : (sum >> 1));
    sum = 2*(BV(motydata, xM, xin3, yin3, 0, 0) + BV(motydata, xM, xin3, yin3, 1, 0));
    p3y = 0.5 * ((sum & 3) ? ((sum | 2) >> 1) : (sum >> 1));
  } else {
    p3x = BV(motxdata, xM, xin3, yin3, vec3&0x1, vec3>>1 );
    p3y = BV(motydata, xM, xin3, yin3, vec3&0x1, vec3>>1 );
  }

  if (rule1 && rule2 && rule3 )
    {
    /* all MBs are outside the VOP */
    *mvx=*mvy=0;
    }
  else if (rule1+rule2+rule3 == 2)
    {
    /* two of three are zero */
    *mvx=(Int) 2*(p1x+p2x+p3x);
    *mvy=(Int) 2*(p1y+p2y+p3y);
    }
  else
    {
    *mvx=(Int)(2*(p1x+p2x+p3x-MAX(p1x,MAX(p2x,p3x))-MIN(p1x,MIN(p2x,p3x))));
    *mvy=(Int)(2*(p1y+p2y+p3y-MAX(p1y,MAX(p2y,p3y))-MIN(p1y,MIN(p2y,p3y))));
    }
  
  return;
}

/***********************************************************CommentBegin******
 *
 * -- find_pmvsErrRes --
 *
 * Author :
 *      IST - Luis Ducla Soares - lds@lx.it.pt
 *
 * Created :
 *      23.09.97
 *
 * Purpose :
 *      Makes the motion vectors prediction for block 'block' (0 = whole MB)
 *      in the error resilient mode.
 *
 * Arguments in :
 *      Image  *mot_x,             x-motion vector field
 *      Image  *mot_y,             y-motion vector field
 *      Image  *MB_decisions,      modes for MBs
 *      Image  *B_decisions,       field with number of vectors per MB
 *      Int    x,                  xpos of the MB in multiples of 16
 *      Int    y,                  ypos of the MB in multiples of 16
 *      Int    block,              block number (0 if one vector per MB,
 *                                 1..4 else)
 *      Int    transparent_value,  value of the transparency (0=enc, 2=dec)
 *
 * Arguments out :
 *      Int    *error_flag         set if an error occured
 *      Int    *mvx                hor predicted motion vector [half-pels units]
 *      Int    *mvy                ver predicted motion vector [half-pels units]
 *      Int    **slice_nb
 *
 * Return values :
 *
 * Side effects :
 *
 *
 * Description :
 *             
 *             
 * Notes :
 *      This function was in the mot_decode.c file, but was rewriten and
 *      included in thif file to unify teh predictors in both encoder and
 *      decoder.
 *
 * See also :
 *      Is directly derived from find_pmvs() above.
 *
 * Modified :
 *      21.05.97 Angel Pacheco: modified to predict both coordinates.
 *			1.12.97 Noel Brady: modified the prediction for error resilient shape.
 *	25.03.98 M.Wollborn: Modified due to N2171 Cl. 2.5.4
 *
 ***********************************************************CommentEnd********/

Void
find_pmvsErrRes(
   Image  *mot_x,       /* x-motion vector field                             */
   Image  *mot_y,       /* y-motion vector field                             */
   Image  *MB_decisions,/* modes for MBs */
   Image  *B_decisions, /* field with number of vectors per MB               */
   Int    x,            /* xpos of the MB in multiples of 16 (hor coord)     */
   Int    y,            /* ypos of the MB in multiples of 16 (ver coord)     */
   Int    block,        /* block number (0 if one vector per MB, 1..4 else)  */
   Int    transparent_value, /* value of the transparency (0=enc, 2=dec)     */
   Int    *error_flag,       /* set if an error occured                      */
   Int    *mvx,     /* hor predicted motion vector [ in half-pixels units ]  */
   Int    *mvy,     /* ver predicted motion vector [ in half-pixels units ]  */
   Int    **slice_nb,
	 Int 		arbitrary_shape
   )
{
  Float   p1x,p2x,p3x;
  Float   p1y,p2y,p3y;
  Int     xin1, xin2, xin3;
  Int     yin1, yin2, yin3;
  Int     vec1, vec2, vec3;
  Int     rule1, rule2, rule3;
  Short   *dcsn_data = (Short *) GetImageData(B_decisions);
  Float   *motxdata = (Float *) GetImageData(mot_x);
  Float   *motydata = (Float *) GetImageData(mot_y);
  Int     xB = GetImageSizeX(B_decisions);
  Int     xM = GetImageSizeX(mot_x);


  /* In a previous version, a MB vector (block = 0) was predicted the same way
     as block 1, which is the most likely interpretation of the VM.

     Therefore, if we have advanced pred. mode, and if all MBs around have
     only one 16x16 vector each, we chose the appropiate block as if these
     MBs have 4 vectors.

     This different prediction affects only 16x16 vectors of MBs with
     transparent blocks.
 
     In the current version, we choose for the 16x16 mode the first
     non-transparent block in the surrounding MBs
  */
 
  switch (block)
    {
    case 0:
      vec1 = 1 ; yin1 = y  ; xin1 = x-1;
      vec2 = 2 ; yin2 = y-1; xin2 = x;
      vec3 = 2 ; yin3 = y-1; xin3 = x+1;
      break;
    case 1:
      vec1 = 1 ; yin1 = y  ; xin1 = x-1;
      vec2 = 2 ; yin2 = y-1; xin2 = x;
      vec3 = 2 ; yin3 = y-1; xin3 = x+1;
      break;
    case 2:
      vec1 = 0 ; yin1 = y  ; xin1 = x;
      vec2 = 3 ; yin2 = y-1; xin2 = x;
      vec3 = 2 ; yin3 = y-1; xin3 = x+1;
      break;
    case 3:
      vec1 = 3 ; yin1 = y  ; xin1 = x-1;
      vec2 = 0 ; yin2 = y  ; xin2 = x;
      vec3 = 1 ; yin3 = y  ; xin3 = x;
      break;
    case 4:
      vec1 = 2 ; yin1 = y  ; xin1 = x;
      vec2 = 0 ; yin2 = y  ; xin2 = x;
      vec3 = 1 ; yin3 = y  ; xin3 = x;
      break;
    default:
      printf("Illegal block number in find_pmv (mot_decode.c)");
      *error_flag = 1;
      *mvx=*mvy=0;
      return ;
    }

  if (block==0)
    {
    /* according to the motion encoding, we must choose a first non-transparent
       block in the surrounding MBs (16-mode)
     */
 
    if (x>0 && ValidCandidateMVP(x,y,xin1,yin1,vec1,xB,transparent_value
                                 ,MB_decisions,dcsn_data) 
        && slice_nb[x][y]==slice_nb[x-1][y])
      rule1 = 0;
    else
      rule1 = 1;
 
    if (y>0 && ValidCandidateMVP(x,y,xin2,yin2,vec2,xB,transparent_value
                                 ,MB_decisions,dcsn_data) 
        && slice_nb[x][y]==slice_nb[x][y-1])
      rule2 = 0;
    else
      rule2 = 1;
 
    if ((x != xB/2 -1) && (y>0) &&                                     
        ValidCandidateMVP(x,y,xin3,yin3,vec3,xB,transparent_value
                          ,MB_decisions,dcsn_data) 
        && slice_nb[x][y]==slice_nb[x+1][y-1])
      rule3 = 0;
    else
      rule3 = 1;
    }
 
  else
    {
    /* check borders for single blocks (advanced mode) */
    /* rule 1 */
    if (((block == 1 || block == 3) &&
        (x == 0 || slice_nb[x][y]!=slice_nb[x-1][y])) ||     /* left border */
                       /* left block/MB is transparent */
       (!ValidCandidateMVP(x,y,xin1,yin1,vec1,xB,transparent_value
                           ,MB_decisions,dcsn_data)))
      rule1 = 1;
    else
      rule1 = 0;
 
    /* rule 2 */
    if (((block == 1 || block == 2) &&
        (y == 0 || slice_nb[x][y]!=slice_nb[x][y-1]))  ||     /* top border */
                       /* top block/MB is transparent */
       (!ValidCandidateMVP(x,y,xin2,yin2,vec2,xB,transparent_value
                           ,MB_decisions,dcsn_data)))
      rule2 = 1;
    else
      rule2 = 0;
 
    /* rule 3 */
    if (((block == 1 || block == 2) &&
        (x == xB/2-1 || y == 0 || slice_nb[x][y]!=slice_nb[x+1][y-1])) ||
        /* right & top border */
                       /* right block/MB is transparent */
        (!ValidCandidateMVP(x,y,xin3,yin3,vec3,xB,transparent_value
                            ,MB_decisions,dcsn_data)))
      rule3 = 1;
    else
      rule3 = 0;
 
    }

  if (rule1)
    {
    p1x = p1y = 0;
    }
  else
    {
    p1x = BV(motxdata, xM, xin1, yin1, vec1&0x1, vec1>>1 );
    p1y = BV(motydata, xM, xin1, yin1, vec1&0x1, vec1>>1 );
    }

  if (rule2)
    {

      /* Modified due to N2171 Cl. 2.5.4 MW 25-MAR-1998 */
      /* if (block==3 || (arbitrary_shape!=0)) */
      /*   p2x = p2y = 0; */
      /* else  */
      /*   { */
      /*     p2x = p1y; */
      /*     p2y = p1y; */
      /*   } */
      
      p2x = p2y = 0;

    }
  else
    {
    p2x = BV(motxdata, xM, xin2, yin2, vec2&0x1, vec2>>1 );
    p2y = BV(motydata, xM, xin2, yin2, vec2&0x1, vec2>>1 );
    }

  if (rule3)
    {
    p3x = p3y =0;
    }
  else
    {
    p3x = BV(motxdata, xM, xin3, yin3, vec3&0x1, vec3>>1 );
    p3y = BV(motydata, xM, xin3, yin3, vec3&0x1, vec3>>1 );
    }

  /* Modified due to N2171 Cl. 2.5.4 MW 25-MAR-1998 */
  /* if (rule2 && (arbitrary_shape==0)) */
  /*   { */
  /*   *mvx = (Int)(2*p1x); */
  /*   *mvy = (Int)(2*p1y); */
  /*   } */
  /* else if (rule1 && rule2 && rule3 ) */

  if (rule1 && rule2 && rule3 )
    {
    /* all MBs are outside the VOP */
    *mvx=*mvy=0;
    }
  else if (rule1+rule2+rule3 == 2)
    {
    /* two of three are zero */
    *mvx=(Int) 2*(p1x+p2x+p3x);
    *mvy=(Int) 2*(p1y+p2y+p3y);
    }
  else
    {
    *mvx=(Int)(2*(p1x+p2x+p3x-MAX(p1x,MAX(p2x,p3x))-MIN(p1x,MIN(p2x,p3x))));
    *mvy=(Int)(2*(p1y+p2y+p3y-MAX(p1y,MAX(p2y,p3y))-MIN(p1y,MIN(p2y,p3y))));
    }

  return;
}

/***********************************************************CommentBegin******
 *
 * -- ValidCandidateMVP --
 *
 * Author :
 *      
 *
 * Created :
 *      
 *
 * Purpose :
 *      
 *
 * Arguments in :
 *
 *
 * Arguments out :
 *
 *
 * Return values :
 *
 *
 * Side effects :
 *
 *
 * Description :
 *
 *
 * Notes :
 *
 *
 * See also :
 *
 *
 * Modified :
 *
 *
 ***********************************************************CommentEnd********/

Int
ValidCandidateMVP(
   Int   x,
   Int   y,
   Int   xin,    /* VPT/Minhua */
   Int   yin, 
   Int   vec, 
   Int   xB,
   Int   transparent_value, 
   Image *MB_decisions, 
   SInt  *dcsn_data
   )
{


  if ((x!=xin)||(y!=yin))
    {
    if (MB_TRANSP(dcsn_data, xB, xin, yin, transparent_value))
      return 0;
    else
      return 1;
    }
  else
    {
    if (B_TRANSP(dcsn_data, xB, xin, yin, vec&0x1, vec>>1, transparent_value))
      return 0;
    else
      return 1;
     }

 
  return 1;
}                                    

/***********************************************************CommentBegin******
 *
 * -- SetRectAlphaDecisions --
 *
 * Author :
 *      UPM-GTI - Angel Pacheco
 *
 * Created :
 *      16.06.97 
 *
 * Purpose :
 *      Generates an array with the alpha plane subsampled in block
 *      pixel units. This array is used to see if the block is:
 *         MBM_TRANSPARENT = all pixels are transparent (outside the shape)
 *         MBM_******      = "****" mode of the block.
 *      This function is the same as subsamp_alpha_with_modes function, being
 *      the alpha_plane rectangular.
 *
 * Arguments in :
 *       SInt*     pMB_decisions,      macroblock modes
 *       Int       size_x,             horizontal dimension
 *       Int       size_y,             vertical dimension 
 *
 * Arguments in/out :
 *       SInt*     palpha_decisions    (rectangular) alpha with modes
 *                                     (block units)
 * Arguments out :
 *
 *
 * Return values :
 *      none
 *
 * Side effects :
 *
 *
 * Description :
 *      It does not allocate memory for the output array
 *
 * See also :
 *
 *
 * Modified :
 *
 *
 ***********************************************************CommentEnd********/

Void
SetRectAlphaDecisions(
   SInt* pMB_decisions,   /* Macroblock modes                             */
   Int   size_x,          /* horizontal dimension                         */
   Int   size_y,          /* vertical dimension                           */
   SInt* palpha_decisions /* (rectangular) alpha with modes (block units) */
   )
{
  int i,j;

  for(j=0;j<size_y;j++)
    for(i=0;i<size_x;i++)
      palpha_decisions[j*size_x+i]=pMB_decisions[j/2*size_x/2+i/2];
}
