/*****************************************************************************
 *
 * This software module was originally developed by
 *
 *   J. Ignacio Ronda (UPM-GTI / ACTS-MoMuSys).
 *
 * and edited by
 *
 *   Angel Pacheco (UPM-GTI / ACTS-MoMuSys).
 *   Ulrike Pestel (TUH / ACTS-MoMuSys).
 *   Fernando Jaureguizar (UPM-GTI / ACTS-MoMuSys).
 *   Ferran  Marques (UPC / ACTS-MoMuSys).
 *   Cecile Dufour (LEP / 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_vop.c
 *
 * Author:      J. Ignacio Ronda / Angel Pacheco, UPM-GTI
 *
 * Created:     02.02.96
 *
 * Description: Compute the motion estimation over the data of a VOP
 *
 * Flags:       -D_DEBUG_MV_MOD_ : prints the resulting 16x16 / 8x8 motion
 *                                 vectors, and associated MB modes
 *              -D_DEBUG_TRANS_  : prints if a block/MB is transparent and
 *                                 his error
 *
 * Modified:
 *      21.04.96 Robert Danielsen: Reformatted. New headers.
 *      02.07.96 Fernando Jaureguizar: Reformatted.
 *      30.08.96 Fernando Jaureguizar: subsamp_alpha() modified to
 *               allow B_BOUNDARY block type and moved to mot_utils* files
 *      18.09.96 Fernando Jaureguizar: Now new B_TRANSP and MB_TRANSP defines
 *               are in mot_util.h. Their calls are modified.
 *      28.11.96 Ferran Marques: Integration of changes from (22.10.96)
 *      05.02.97 Angel Pacheco: deletion of the *pel_pos arrays (VM5.1)
 *               having the valid positions (padded pixels) in which
 *               the search for the motion vectors must be done (as VM4.x said).
 *      21.03.97 Cecile Dufour: added warp_param and padsprite for
 *               ONLINE_SPRITE add B_BOUNDARY and MB_BOUNDARY in mot_util.h
 *      14.05.97 Fernando Jaureguizar: new commentaries about new enlarged
 *               f_code range according to VM7.0
 *               Modification in MotionEstimatePicture() function to
 *               cope with enlarged f_code range.
 *      16.06.97 Angel Pacheco: unified the TRANSPARENT modes.
 *      01.08.97 Fernando Jaureguiza: canged the wrong name advanced
 *               by the correct one enable_8x8_mv.
 *      13.11.97 Fernando Jaureguizar: formating and new header.
 *      09.03.98 Fernando Jaureguizar: New formating. Deleted not used
 *               mode16 parameter in FullPelMotionEstMB()
 *
 ***********************************************************HeaderEnd*********/

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

#include "mot_util.h"
#include "mot_est.h"
#ifndef _WD_MODE_
#include "dynsprite_enc_util.h"
#endif

/***********************************************************CommentBegin******
 *
 * -- compute_Nb --
 *
 * Author :
 *      UPM-GTI - Angel Pacheco
 *
 * Created :
 *      24.4.96
 *
 * Purpose :
 *      compute the Nb (MBs pixels inside the shape) for all MBs
 *
 * 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 *MB_Nb      subsampled alpha Nb's
 *
 * Return values :
 *      none
 *
 * Side effects :
 *
 *
 * Description :
 *      It does not allocate memory for the Nb array
 *
 * See also :
 *
 *
 * Modified :
 *
 *
 ***********************************************************CommentEnd********/

static Void
compute_Nb(
  SInt   *alpha,    /* <-- alpha plane data                */
  Int    br_width,  /* <-- width of the alpha plane data   */
  Int    br_height, /* <-- height  of the alpha plane data */
  SInt   *MB_Nb     /* --> subsampled alpha Nb's           */
  )
{
  Int   h, v;
  Int   aux_hor=br_width/MB_SIZE,  /* width  in  Bs */
        aux_ver=br_height/MB_SIZE; /* height in  Bs */

  for (v=0;v<aux_ver;v++)
    for (h=0;h<aux_hor;h++)
      MB_Nb[v*aux_hor+h]=0;

  for (v=0;v<br_height;v++)
    for (h=0;h<br_width;h++)
      if (alpha[v*br_width+h]!=0)
        MB_Nb[(v/MB_SIZE)*aux_hor+(h/MB_SIZE)]++;

}

/***********************************************************CommentBegin******
 *
 * -- MotionEstimatePicture -- Computes MV's and predictor errors
 *
 * Author :
 *      UPM-GTI - J. Ignacio Ronda / Angel Pacheco
 *
 * Created :
 *
 *
 * Purpose :
 *      Computes MV's (8x8 and 16x16) and predictor errors for the whole
 *      vop.
 *
 * Arguments in :
 *      Vop   *curr_vop     Y current VOP: vop_width x vop_height
 *      SInt  *prev_rec     Previous reconstructed luma
 *      SInt  *alpha        quantized alpha plane of current picture
 *      SInt  *prev         Y padd with edge
 *      SInt  *prev_ipol    Y interpolated (from pi)
 *      Int   prev_x        absolute horizontal position of the previous vop
 *      Int   prev_y        absolute vertical position of the previous vop
 *      Int   vop_width     horizontal previous vop dimension
 *      Int   vop_height    vertical previous vop dimension
 *      Image *padsprite    padded online sprite
 *      Vop   *sprite
 *      Int   no_of_sprite_points
 *      Int   warpingaccuracy
 *      Int   offset_pad_x  change corrdinates from padsprite to vop
 *      Int   offset_pad_y
 *      Int   enable_8x8_mv 8x8 MV (=1) or only 16x16 MV (=0)
 *      Int   edge          edge arround the reference vop
 *      Int   f_code        MV search range 1/2 pel: 1=32,2=64,...,7=2048
 *      Int   br_x          absolute horizontal position of the current vop
 *      Int   br_y          absolute vertical   position of the current vop
 *      Int   br_width      current bounding rectangule width
 *      Int   br_height     current bounding rectangle height
 *      Int   ref_sel_code  ref_select code for Scalability (UPS)
 *
 * Arguments in/out :
 *
 *
 * Arguments out :
 *      Float *mv16_w      predicted horizontal 16x16 MV (if approp.)
 *      Float *mv16_h      predicted vertical 16x16 MV   (if approp.)
 *      Float *mv8_w       predicted horizontal 8x8 MV   (if approp.)
 *      Float *mv8_h       predicted vertical 8x8 MV     (if approp.)
 *      Float *mvF_w       predicted horizontal field MV (if approp.)
 *      Float *mvF_h       predicted vertical field MV   (if approp.)
 *      SInt  *mode16      mode of the preditect motion vector
 *      SInt  *alpha_sub   sumsampled alpha plane
 *
 * Return values :
 *      none
 *
 * Side effects :
 *
 *
 * Description :
 *
 *
 * See also :
 *
 *
 * Modified :
 *      05.02.97 Angel Pacheco: deletion of the *pel_pos arrays (VM5.1)
 *               having the valid positions (padded pixels) in which the
 *               search for the motion vectors must be done (as VM4.x said).
 *      14.05.97 Fernando Jaureguizar: Modification to cope with enlarged f_code
 *               range (VM7.0).
 *      17.07.97 Ulrike Pestel: for scalability
 *      01.01.97 Fernando Jaureguizar: No 1/2 pel accuracy for (0;0) FW MV
 *               in spatial scalability (SpSc)
 *      11.12.97 Bob Eifrig: Added interlaced video support
 *
 ***********************************************************CommentEnd********/

Void
MotionEstimatePicture(
  Vop     *curr_vop,   /* <-- Current VOP                                  */
  SInt    *prev_rec,   /* <-- Previous reconstructed Y                     */
  SInt    *alpha,      /* <-- quantized alpha plane of current picture     */
  SInt    *prev,       /* <-- Original Y padd with edge                    */
  SInt    *prev_ipol,  /* <--  Y interpolated (from pi)                    */
  Int     prev_x,      /* <-- absolute horiz. position of previous vop     */
  Int     prev_y,      /* <-- absolute verti. position of  previous vop    */
  Int     vop_width,   /* <-- horizontal previous vop dimension            */
  Int     vop_height,  /* <-- vertical previous vop dimension              */
  /* Following parameters are ignored if _WD_MODE_ is defined */
  Image   *padsprite,  /* edged current online_sprite                      */
  Vop     *sprite,
  Int     no_of_sprite_points,
  Int     warpingaccuracy,
  Int     offset_pad_x,
  Int     offset_pad_y,
  /* End of ignored parameters when _WD_MODE_ is defined */
  Int     enable_8x8_mv,/* <-- 8x8 MV (=1) or only 16x16 MV (=0)            */
  Int     edge,        /* <-- edge arround the reference vop               */
  Int     f_code,      /* <-- MV search range 1/2 pel: 1=32,2=64,...,7=2048*/
  Int     br_x,        /* <-- absolute horiz. position of the current vop  */
  Int     br_y,        /* <-- absolute verti. position of the current vop  */
  Int     br_width,    /* <-- current bounding rectangule width            */
  Int     br_height,   /* <-- current bounding rectangle height            */
  Int     ref_sel_code,/* <-- ref_sel_code for scalability                 */
  Float   *mv16_w,     /* --> predicted horizontal 16x16 MV(if approp.)    */
  Float   *mv16_h,     /* --> predicted vertical 16x16 MV  (if approp.)    */
  Float   *mv8_w,      /* --> predicted horizontal 8x8 MV  (if approp.)    */
  Float   *mv8_h,      /* --> predicted vertical 8x8 MV    (if approp.)    */
  Float   *mvF_w,      /* --> predicted horizontal field MV  (if approp.)  */
  Float   *mvF_h,      /* --> predicted vertical field MV    (if approp.)  */
  SInt    *mode16,     /* --> mode of the preditect motion vector          */
  SInt    *alpha_sub   /* --> sumsampled alpha plane                       */
  )
{
  Int   i, j;
  Int   curr_mb[MB_SIZE][MB_SIZE],
        curr_mb_alpha[MB_SIZE][MB_SIZE];
  Int   sad8 = MV_MAX_ERROR,
        sadsprite = MV_MAX_ERROR,
        sad16;
  Int   imas_w,
        imas_h,
        Mode;
  Int   posmode,
        pos16,
        pos8;
  Int   min_error16,
        min_error8_0,
        min_error8_1,
        min_error8_2,
        min_error8_3;
#ifndef _WD_MODE_
  Int   min_errsprite;
#endif
  Int   min_errorF[4];
  SInt  *curr = (SInt *)GetImageData(GetVopY(curr_vop));
  Int   xoff, yoff;
  SInt  *MB_Nb; /* Nb's of each MB of the vop */
  /***************************************************************************
  array of flags, which contains for the MB and for each one of the 4 Blocks
  the following info sequentially:
    xm, 1 if the lower search (x axis) is completed (no 1/2 search can be done)
           0, do 1/2 search in the lower bound (x axis)
    xM, 1 if the upper search (x axis) is completed (no 1/2 search can be done)
           0, do 1/2 search in the upper bound (x axis)
    ym, 1 if the lower search (y axis) is completed (no 1/2 search can be done)
           0, do 1/2 search in the lower bound (y axis)
    yM, 1 if the upper search (y axis) is completed (no 1/2 search can be done)
           0, do 1/2 search in the upper bound (y axis)
  ***************************************************************************/
  SInt  *halfpelflags;
  Int   flag_static_sprite=0;

  if (f_code==0)
    flag_static_sprite = 1;

  imas_w=br_width/MB_SIZE;
  imas_h=br_height/MB_SIZE;

  /* Do motion estimation and store result in array */

  halfpelflags=(SInt*)malloc(5*4*sizeof(SInt));
  MB_Nb=(SInt*)malloc(imas_w*imas_h*sizeof(SInt));

  subsamp_alpha(alpha, br_width, br_height, 1 /* block-based */, alpha_sub);
  compute_Nb(alpha, br_width, br_height, MB_Nb);

  for ( j=0; j< (br_height/MB_SIZE); j++)
    for ( i=0; i< (br_width/MB_SIZE); i++)
      {
      /* Integer pel search */

      posmode =          j * imas_w +   i;
      pos16   = pos8 = 2*j*2*imas_w + 2*i;

      if(!MB_TRANSP(alpha_sub,br_width/B_SIZE,i,j,MBM_TRANSPARENT))
        {
        Mode = FullPelMotionEstMB(
             curr_vop, alpha, prev, alpha_sub, br_x, br_y,
             br_width, br_height, i, j, prev_x, prev_y, vop_width, vop_height,
             enable_8x8_mv, edge, f_code, MB_Nb, ref_sel_code,
             mv16_w, mv16_h, mv8_w, mv8_h, mvF_w, mvF_h, halfpelflags);

        /* Half pel search */

        /* 0==MBM_INTRA,1==MBM_INTER16||MBM_INTER8||MODE_SPRITE */
        /* f_code=0 corresponds to STATIC SPRITE */
        if ( Mode != 0)
          {
          if (ref_sel_code!=3) /*SpSc*/
            {
            FindMB( i*MB_SIZE, j*MB_SIZE, br_width, curr,  curr_mb);
            FindMB( i*MB_SIZE, j*MB_SIZE, br_width, alpha, curr_mb_alpha);
            FindHalfPel (i*MB_SIZE,j*MB_SIZE, prev_ipol,
                         &curr_mb[0][0], &curr_mb_alpha[0][0], 16, 0,
                         br_x-prev_x,br_y-prev_y,vop_width, vop_height,
                         edge, halfpelflags, MB_Nb[posmode],
                         &mv16_w[pos16], &mv16_h[pos16], &min_error16,
                         flag_static_sprite);

            /* sad16(0,0) already decreased by Nb/2+1 in FindHalfPel() */
            sad16 = min_error16;
            mode16[posmode] = MBM_INTER16;

            if (curr_vop->interlaced)
              {
              /* Do field halfpel refinement */

              xoff = i*MB_SIZE + br_x - prev_x;
              yoff = j*MB_SIZE + br_y - prev_y;

              /* cur=Top, ref=Top */
              FindHalfPelField(xoff, yoff, prev_rec,
                               &curr_mb[0][0], &curr_mb_alpha[0][0],
                               vop_width, vop_height, edge,
                               &mvF_w[pos16], &mvF_h[pos16], &min_errorF[0]);

              /* cur=Top, ref=Bot */
              FindHalfPelField(xoff, yoff, &prev_rec[vop_width + 2*edge],
                              &curr_mb[0][0], &curr_mb_alpha[0][0],
                              vop_width, vop_height, edge,
                              &mvF_w[pos16+1], &mvF_h[pos16+1], &min_errorF[1]);

              pos16 += 2*imas_w;
              /* cur=Bot, ref=Top */
              FindHalfPelField(xoff, yoff, prev_rec,
                               &curr_mb[1][0], &curr_mb_alpha[1][0],
                               vop_width, vop_height, edge,
                               &mvF_w[pos16], &mvF_h[pos16], &min_errorF[2]);

              /* cur=Bot, ref=Bot */
              FindHalfPelField(xoff, yoff, &prev_rec[vop_width + 2*edge],
                               &curr_mb[1][0], &curr_mb_alpha[1][0],
                               vop_width, vop_height, edge,
                               &mvF_w[pos16+1], &mvF_h[pos16+1],&min_errorF[3]);

              pos16 -= 2*imas_w;
              /* determine the best field MC mode */
              if (min_errorF[0] <= min_errorF[1])
                {
                sad16 = min_errorF[0];
                if (min_errorF[3] <= min_errorF[2])
                  {
                  sad16 += min_errorF[3];
                  Mode = MBM_FIELD01;
                  }
                else
                  {
                  sad16 += min_errorF[2];
                  Mode = MBM_FIELD00;
                  }
                }
              else
                {
                sad16 = min_errorF[1];
                if (min_errorF[3] <= min_errorF[2])
                  {
                  sad16 += min_errorF[3];
                  Mode = MBM_FIELD11;
                  }
                else
                  {
                  sad16 += min_errorF[2];
                  Mode = MBM_FIELD10;
                  }
                }
              sad16 += MB_Nb[posmode]/4 + 1;        /* Bias against field */
              if (min_error16 <= sad16)
                sad16 = min_error16;
              else
                mode16[posmode] = Mode;
              } /* interlaced */

#ifndef _WD_MODE_
            if (padsprite!=NULL)
              {
              MBGlobalME(curr, alpha, padsprite,
                         sprite,no_of_sprite_points, warpingaccuracy+1,
                         br_width, br_x, br_y, i, j,
                         offset_pad_x, offset_pad_y,&min_errsprite);
              sadsprite = min_errsprite  - (MB_Nb[posmode]/2 + 1);
              }
            else
#endif
              sadsprite =100000;  /* turn-off mosaic... */

            if (enable_8x8_mv)
              {
              /* fprintf(stderr,"enable_8x8_mv\n"); */
              if (!B_TRANSP(alpha_sub,br_width/B_SIZE,i,j,0,0,MBM_TRANSPARENT))
                FindHalfPel(i*MB_SIZE, j*MB_SIZE, prev_ipol,
                            &curr_mb[0][0], &curr_mb_alpha[0][0], 8, 0,
                            br_x-prev_x,br_y-prev_y, vop_width, vop_height,
                            edge, halfpelflags, 0, &mv8_w[pos8], &mv8_h[pos8],
                            &min_error8_0, flag_static_sprite);
              else
                {
                /* default value for transparent blocks */
                mv8_w[pos8]=mv8_h[pos8]=0.0;
                min_error8_0=0;
                }

              if (!B_TRANSP(alpha_sub,br_width/B_SIZE,i,j,1,0,MBM_TRANSPARENT))
                FindHalfPel(i*MB_SIZE, j*MB_SIZE, prev_ipol,
                            &curr_mb[0][8], &curr_mb_alpha[0][8], 8, 1,
                            br_x-prev_x,br_y-prev_y, vop_width,vop_height,
                            edge, halfpelflags,0,&mv8_w[pos8+1], &mv8_h[pos8+1],
                            &min_error8_1, flag_static_sprite);
              else
                {
                /* default value for transparent blocks */
                mv8_w[pos8+1]=mv8_h[pos8+1]=0.0;
                min_error8_1=0;
                }

              pos8+=2*imas_w;
              if (!B_TRANSP(alpha_sub,br_width/B_SIZE,i,j,0,1,MBM_TRANSPARENT))
                FindHalfPel(i*MB_SIZE, j*MB_SIZE, prev_ipol,
                           &curr_mb[8][0], &curr_mb_alpha[8][0], 8, 2,
                            br_x-prev_x,br_y-prev_y, vop_width,vop_height,
                            edge, halfpelflags, 0, &mv8_w[pos8], &mv8_h[pos8],
                            &min_error8_2, flag_static_sprite);
              else
                {
                /* default value for transparent blocks */
                mv8_w[pos8]=mv8_h[pos8]=0.0;
                min_error8_2=0;
                }

              if (!B_TRANSP(alpha_sub,br_width/B_SIZE,i,j,1,1,MBM_TRANSPARENT))
                FindHalfPel(i*MB_SIZE, j*MB_SIZE, prev_ipol,
                            &curr_mb[8][8], &curr_mb_alpha[8][8], 8, 3,
                            br_x-prev_x,br_y-prev_y, vop_width,vop_height,
                            edge, halfpelflags,0,&mv8_w[pos8+1], &mv8_h[pos8+1],
                            &min_error8_3, flag_static_sprite);
              else
                {
                /* default value for transparent blocks */
                mv8_w[pos8+1]=mv8_h[pos8+1]=0.0;
                min_error8_3=0;
                }

              sad8 = min_error8_0+min_error8_1+min_error8_2+min_error8_3;

              /* Choose 8x8 or 16x16 vectors */
              if ( (sad8 < (sad16 -(MB_Nb[posmode]/2+1))) &&
                   (sad8 < (sadsprite - (MB_Nb[posmode]/2+1))))
                mode16[posmode] = MBM_INTER8;
              else
                {
                /* sad16(0,0) was decreased by MB_Nb, now add it back */
                if (mv16_w[pos16]==0.0 && mv16_h[pos16]==0.0)
                  sad16 += MB_Nb[posmode]/2+1;

                if (sadsprite <= sad16)
                  {
                  mode16[posmode] = MBM_SPRITE;
                  /* set motion vectors to zero */
                  pos16   = pos8 = 2*j*2*imas_w + 2*i;
                  mv16_w[pos16]=0.0;
                  mv16_h[pos16]=0.0;
                  mv16_w[pos16+1]=0.0;
                  mv16_h[pos16+1]=0.0;
                  mv8_w[pos8]=0.0;
                  mv8_h[pos8]=0.0;
                  mv8_w[pos8+1]=0.0;
                  mv8_h[pos8+1]=0.0;
                  mvF_w[pos16]=0.0;
                  mvF_h[pos16]=0.0;
                  mvF_w[pos16+1]=0.0;
                  mvF_h[pos16+1]=0.0;

                  pos16+=2*imas_w;
                  pos8+=2*imas_w;
                  mv16_w[pos16]=0.0;
                  mv16_h[pos16]=0.0;
                  mv16_w[pos16+1]=0.0;
                  mv16_h[pos16+1]=0.0;
                  mv8_w[pos8]=0.0;
                  mv8_h[pos8]=0.0;
                  mv8_w[pos8+1]=0.0;
                  mv8_h[pos8+1]=0.0;
                  mvF_w[pos16]=0.0;
                  mvF_h[pos16]=0.0;
                  mvF_w[pos16+1]=0.0;
                  mvF_h[pos16+1]=0.0;
                  }
                /* Else Choose 16x16 vectors already set */
                }/* mode inter 8 */
              } /* of enable_8x8_mv mode */
            else /* non enable_8x8_mv */
              {
              /* Choose 16x16 vectors or sprite */
              /* sad16(0,0) was decreased by MB_Nb, now add it back */
              if ((mv16_w[pos16]==0.0) && (mv16_h[pos16]==0.0))
                sad16 += MB_Nb[posmode]/2+1;
              if (sadsprite <= sad16)
                {
                mode16[posmode] = MBM_SPRITE;
                /* set motion vectors to zero */
                pos16 = 2*j*2*imas_w + 2*i;
                mv16_w[pos16]=0.0;
                mv16_h[pos16]=0.0;
                mv16_w[pos16+1]=0.0;
                mv16_h[pos16+1]=0.0;
                mvF_w[pos16]=0.0;
                mvF_h[pos16]=0.0;
                mvF_w[pos16+1]=0.0;
                mvF_h[pos16+1]=0.0;

                pos16+=2*imas_w;
                mv16_w[pos16]=0.0;
                mv16_h[pos16]=0.0;
                mv16_w[pos16+1]=0.0;
                mv16_h[pos16+1]=0.0;
                mvF_w[pos16]=0.0;
                mvF_h[pos16]=0.0;
                mvF_w[pos16+1]=0.0;
                mvF_h[pos16+1]=0.0;
                }
              /* else chosse 16x16 vectors already set */
              }
            } /* non spatial scalability */ /*SpSc*/
          else
            mode16[posmode] = MBM_INTER16; /*SpSc*/
          } /* end of mode non zero */

        else  /* MV are set to zero in the calling code */
          {}
        }
      else /* transparent block */
        {
        mode16[posmode] = MBM_TRANSPARENT;
        }

#ifdef _DEBUG_TRANS_
      if(!MB_TRANSP(alpha_sub,br_width/B_SIZE,i,j,MBM_TRANSPARENT))
        {
        if(Mode!=0 )
          {
          if(sad8>=sad16)
            {
            fprintf(stderr,"MB(h,v)(%2d,%2d):\tMV(%f,%f) err=%d\n",i,j,
                    mv16_w[pos16],mv16_h[pos16],min_error16);
            fprintf(stderr,"MB mode = %d\n",mode16[posmode]);
            }
          else
            {
            fprintf(stderr,"MB(%d,%d)-mode 4\n",i,j);
            if (!B_TRANSP(alpha_sub,br_width/B_SIZE,i,j,0,0,MBM_TRANSPARENT))
              {
              fprintf(stderr,"B(0,0):\tMV(%f,%f) err=%d\n",mv8_w[pos8],
                      mv8_h[pos8],min_error8_0);
              }
            else
              fprintf(stderr,"B(0,0) TRANSP\n");

            if (!B_TRANSP(alpha_sub,br_width/B_SIZE,i,j,1,0,MBM_TRANSPARENT))
              {
              fprintf(stderr,"B(1,0):\tMV(%f,%f) err=%d\n",mv8_w[pos8+1],
                      mv8_h[pos8+1],min_error8_1);
              }
            else
              fprintf(stderr,"B(1,0) TRANSP\n");

            pos8+=2*imas_w;
            if (!B_TRANSP(alpha_sub,br_width/B_SIZE,i,j,0,1,MBM_TRANSPARENT))
              {
              fprintf(stderr,"B(0,1):\tMV(%f,%f) err=%d\n",mv8_w[pos8],
                      mv8_h[pos8],min_error8_2);
              }
            else
              fprintf(stderr,"B(0,1) TRANSP\n");

            if (!B_TRANSP(alpha_sub,br_width/B_SIZE,i,j,1,1,MBM_TRANSPARENT))
              {
              fprintf(stderr,"B(1,1):\tMV(%f,%f) err=%d\n",mv8_w[pos8+1],
                      mv8_h[pos8+1],min_error8_3);
              }
            else
              fprintf(stderr,"B(1,1) TRANSP\n");
            }
          }
        else
          fprintf(stderr,"MB(i,j)(%2d,%2d): mode 0\n",i,j);
        }
      else
        fprintf(stderr,"MB(h,v)(%2d,%2d):\tTRANSP-MV, mode 0\n",i,j);
#endif
      }

#ifdef _DEBUG_MV_MOD_

#define ABSDOUBLE(x) (((x) > 0.0001) ? (x) : (((x) < -0.0001) ? -(x): 0.0 ))

#define CHECK16(x,y,px,py,ran) \
 (((ABSDOUBLE(mv16_w[2*j*2*imas_w+2*i]    )<range) || \
   (ABSDOUBLE(mv16_h[2*j*2*imas_w+2*i]      )<range)) ?1 : 0)

/* Note,<=11 due to the maximum diference betwen mv16 and mv18 is:
 *    10  (window +/- 10 around mv16) plus
 *    1/2 (mv16 halfpel posible movement) plus
 *    1/2 (mv8  halfpel posible movement) equals
 *    11
 */

/* The macros sould be more corectly defined (11==WINDOW_W+1, etc), but
 * for this moment are enought
 */

#define CHECK81(x,y,px,py,ran) \
 (((ABSDOUBLE(mv8_w[2*j*2*imas_w+2*i]-mv16_w[2*j*2*imas_w+2*i])<=11) && \
   (ABSDOUBLE(mv8_h[2*j*2*imas_w+2*i]-mv16_h[2*j*2*imas_w+2*i])<=11))? 1 : 0)

#define CHECK82(x,y,px,py,ran) \
 (((ABSDOUBLE(mv8_w[2*j*2*imas_w+2*i+1]-mv16_w[2*j*2*imas_w+2*i])<=11) && \
   (ABSDOUBLE(mv8_h[2*j*2*imas_w+2*i+1]-mv16_h[2*j*2*imas_w+2*i])<=11))? 1:0)

#define CHECK83(x,y,px,py,ran) \
 (((ABSDOUBLE(mv8_w[(2*j+1)*2*imas_w+2*i]-mv16_w[2*j*2*imas_w+2*i])<=11) && \
   (ABSDOUBLE(mv8_h[(2*j+1)*2*imas_w+2*i]-mv16_h[2*j*2*imas_w+2*i])<=11))? 1:0)

#define CHECK84(x,y,px,py,ran) \
 (((ABSDOUBLE(mv8_w[(2*j+1)*2*imas_w+2*i+1]-mv16_w[2*j*2*imas_w+2*i])<=11) && \
   (ABSDOUBLE(mv8_h[(2*j+1)*2*imas_w+2*i+1]-mv16_h[2*j*2*imas_w+2*i])<=11))?1:0)

  fprintf(stdout,"Motion estimation\n");
  fprintf(stdout,"16x16 vectors:\n");

  for ( j = 0; j <imas_h ; j++)
    {
    for ( i = 0; i < imas_w; i++)
      {
      if ((mode16[j*imas_w + i] == 1)||(mode16[j*imas_w + i] ==4)) /* INTER */
        {
        Int range;

        range=(Int)pow(2.0,(double)(f_code+4)); /* Range in 1/2 pel units */
        if(CHECK16(mv16_w[2*j*2*imas_w+2*i],mv16_h[2*j*2*imas_w+2*i],
                   0.0,0.0,range))
          fprintf(stdout," (%+05.1f %+05.1f)",  mv16_w[2*j*2*imas_w+2*i],
                  mv16_h[2*j*2*imas_w+2*i]);
        else
          fprintf(stdout,"!#%+05.1f %+05.1f#",  mv16_w[2*j*2*imas_w+2*i],
                  mv16_h[2*j*2*imas_w+2*i]);
        }
      else
        fprintf(stdout," (   .     . )");
      }
    fprintf(stdout,"\n");
    }
  if (enable_8x8_mv)
    {
    Float pmv_x, pmv_y;
    fprintf(stdout,"8x8 vectors:\n\n");
    fprintf(stdout,"Block 0\n");
    for ( j = 0; j < imas_h; j++)
      {
      for ( i = 0; i < imas_w; i++)
        {
        pmv_x= mv16_w[2*j*2*imas_w+2*i];
        pmv_y= mv16_h[2*j*2*imas_w+2*i];
        if (mode16[j*imas_w + i] == 4) /* INTER8 */
          {
          if(CHECK81(mv8_w[2*j*2*imas_w+2*i],mv8_h[2*j*2*imas_w+2*i],
            pmv_x,pmv_y,10))
            fprintf(stdout," (%+05.1f %+05.1f)", mv8_w[2*j*2*imas_w+2*i],
                    mv8_h[2*j*2*imas_w+2*i]);
          else
            fprintf(stdout,"!#%+05.1f %+05.1f#", mv8_w[2*j*2*imas_w+2*i],
                    mv8_h[2*j*2*imas_w+2*i]);
          }
        else if(mode16[j*imas_w + i] == 1) /* INTER16, do not check it */
          fprintf(stdout," (%+05.1f %+05.1f)", mv8_w[2*j*2*imas_w+2*i],
                  mv8_h[2*j*2*imas_w+2*i]);
        else
          fprintf(stdout," (   .     . )");
        }
      fprintf(stdout,"\n");
      fprintf(stdout,"\n");
      }
    fprintf(stdout,"Block 1\n");
    for ( j = 0; j < imas_h; j++)
      {
      for ( i = 0; i < imas_w; i++)
        {
        pmv_x= mv16_w[2*j*2*imas_w+2*i];
        pmv_y= mv16_h[2*j*2*imas_w+2*i];
        if (mode16[j*imas_w + i] == 4) /* INTER8 */
          {
          if(CHECK82(mv8_w[2*j*2*imas_w+2*i+1],mv8_h[2*j*2*imas_w+2*i+1],
                     pmv_x,pmv_y,10))
            fprintf(stdout," (%+05.1f %+05.1f)", mv8_w[2*j*2*imas_w+2*i+1],
                    mv8_h[2*j*2*imas_w+2*i+1]);
          else
            fprintf(stdout,"!#%+05.1f %+05.1f#", mv8_w[2*j*2*imas_w+2*i+1],
                    mv8_h[2*j*2*imas_w+2*i+1]);
          }
        else if (mode16[j*imas_w + i] == 1) /* INTER16, do not check it */
          fprintf(stdout," (%+05.1f %+05.1f)", mv8_w[2*j*2*imas_w+2*i+1],
                  mv8_h[2*j*2*imas_w+2*i+1]);
        else
          fprintf(stdout," (   .     . )");
        }
      fprintf(stdout,"\n");
      fprintf(stdout,"\n");
      }
    fprintf(stdout,"Block 2\n");
    for ( j = 0; j < imas_h; j++)
      {
      for ( i = 0; i < imas_w; i++)
        {
        pmv_x= mv16_w[2*j*2*imas_w+2*i];
        pmv_y= mv16_h[2*j*2*imas_w+2*i];
        if (mode16[j*imas_w + i] == 4) /* INTER8 */
          {
          if(CHECK83(mv8_w[(2*j+1)*2*imas_w+2*i],mv8_h[(2*j+1)*2*imas_w+2*i],
                     pmv_x,pmv_y,10))
            fprintf(stdout," (%+05.1f %+05.1f)", mv8_w[(2*j+1)*2*imas_w+2*i],
                    mv8_h[(2*j+1)*2*imas_w+2*i]);
          else
            fprintf(stdout,"!#%+05.1f %+05.1f#", mv8_w[(2*j+1)*2*imas_w+2*i],
                    mv8_h[(2*j+1)*2*imas_w+2*i]);
          }
        else if (mode16[j*imas_w + i] == 1) /* INTER16, do not check it */
          fprintf(stdout," (%+05.1f %+05.1f)", mv8_w[(2*j+1)*2*imas_w+2*i],
                  mv8_h[(2*j+1)*2*imas_w+2*i]);
        else
          fprintf(stdout," (   .     . )");
        }
      fprintf(stdout,"\n");
      fprintf(stdout,"\n");
      }
    fprintf(stdout,"Block 3\n");
    for ( j = 0; j < imas_h; j++)
      {
      for ( i = 0; i < imas_w; i++)
        {
        pmv_x= mv16_w[2*j*2*imas_w+2*i];
        pmv_y= mv16_h[2*j*2*imas_w+2*i];
        if (mode16[j*imas_w + i] == 4) /* INTER8 */
          {
          if(CHECK84(mv8_w[(2*j+1)*2*imas_w+2*i+1],
                     mv8_h[(2*j+1)*2*imas_w+2*i+1], pmv_x,pmv_y,10))
            fprintf(stdout," (%+05.1f %+05.1f)", mv8_w[(2*j+1)*2*imas_w+2*i+1],
                    mv8_h[(2*j+1)*2*imas_w+2*i+1]);
          else
            fprintf(stdout,"!#%+05.1f %+05.1f#", mv8_w[(2*j+1)*2*imas_w+2*i+1],
                    mv8_h[(2*j+1)*2*imas_w+2*i+1]);
          }
        else if (mode16[j*imas_w + i] == 1) /* INTER16, do not check it */
          fprintf(stdout," (%+05.1f %+05.1f)", mv8_w[(2*j+1)*2*imas_w+2*i+1],
                  mv8_h[(2*j+1)*2*imas_w+2*i+1]);
        else
          fprintf(stdout," (   .     . )");
        }
      fprintf(stdout,"\n");
      fprintf(stdout,"\n");
      }
    }

  fprintf(stdout,"Modes:\n");

  for ( j = 0; j <imas_h ; j++)
    {
    for ( i = 0; i < imas_w; i++)
      {
      fprintf(stdout," %d ",mode16[j*imas_w+i]);
      }
    fprintf(stdout,"\n");
    }
#endif

  free((Char*)MB_Nb);
  free((Char*)halfpelflags);
  return;
}

/***********************************************************CommentBegin******
 *
 * -- FullPelMotionEstMB -- Computes MV's and predictor errors
 *
 * Author :
 *      Bob Eifrig
 *      General Instrument
 *
 * Created :
 *
 *
 * Purpose :
 *      To obtain full-pel motion vectors and make the Intra/Inter decision
 *
 * Arguments in :
 *      Vol *vol           the VOL structure
 *      Int i, j           Macroblock coordinates
 *      SInt *ref          Reference picture
 *      SInt *alpha_sub    Subsampled alpha
 *      SInt *MB_Nb        Non-transparent pels per MB
 *
 * Arguments out :
 *      Float   *mv16   16x16 motion vector
 *      Float   *mvF    Four field motion vectors
 *      Float   *mv8    Four 8x8 block motion vectors
 *
 * Return values :
 *      none
 *
 * Side effects :
 *
 *
 * Description :
 *
 *
 * See also :
 *
 *
 * Modified :
 *
 *
 ***********************************************************CommentEnd********/

Int
FullPelMotionEstMB(
   Vop     *curr_vop,
   SInt    *alpha,
   SInt    *prev,
   SInt    *alpha_sub,
   Int     br_x,
   Int     br_y,
   Int     br_width,
   Int     br_height,
   Int     i,
   Int     j,
   Int     prev_x,
   Int     prev_y,
   Int     vop_width,
   Int     vop_height,
   Int     enable_8x8_mv,
   Int     edge,
   Int     f_code,
   SInt    *MB_Nb,
   Int     ref_sel_code,
   Float   *mv16_w,
   Float   *mv16_h,
   Float   *mv8_w,
   Float   *mv8_h,
   Float   *mvF_w,
   Float   *mvF_h,
   SInt    *halfpelflags)
{
  Char   line[256];
  Int    iv16[2], ivF[8], iv8[8], mbx, mby, interflag;
  Int    k, min_error, imv, imv_width;
  Int    xmin, xmax, ymin, ymax;

  imv_width = 2*vop_width/MB_SIZE;
  imv = 2*i + 2*imv_width*j;
  if (curr_vop->mvfileusage == 1)
    {
    if (fgets(line, sizeof line, curr_vop->mvfile) == NULL)
      {
      fprintf(stderr, "EOF on %s\n", curr_vop->mvfilename);
      exit(1);
      }
    (*curr_vop->mvlinenop)++;
    if (sscanf(line,
               "%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d",
               &mbx, &mby, &interflag, &iv16[0], &iv16[1],
               &ivF[0], &ivF[1], &ivF[2], &ivF[3], &ivF[4],
               &ivF[5], &ivF[6], &ivF[7],
               &iv8[0], &iv8[1], &iv8[2], &iv8[3], &iv8[4],
               &iv8[5], &iv8[6], &iv8[7]) != 21)
      {
      fprintf(stderr, "Bad format on %s:%d\n",
              curr_vop->mvfilename, *curr_vop->mvlinenop);
      exit(1);
      }
    if ((mbx != i) || (mby != j))
      {
      fprintf(stderr, "Exepected MB (%d %d), got (%d %d)\n",
              i, j, mbx, mby);
      exit(1);
      }

    xmin = -((i*MB_SIZE + edge) << 1);
    xmax =  ((GetVopWidth(curr_vop)  - i*MB_SIZE + MB_SIZE - edge) << 1);
    ymin = -((j*MB_SIZE + edge) << 1);
    ymax =  ((GetVopHeight(curr_vop) - j*MB_SIZE + MB_SIZE - edge) << 1);

    if (iv16[0] < xmin)
      iv16[0] = xmin;
    if (iv16[0] > xmax)
      iv16[0] = xmax;
    if (iv16[1] < ymin)
      iv16[1] = ymin;
    if (iv16[1] > ymax)
      iv16[1] = ymax;

    for (k = 0; k < 8; k += 2)
      {
      if (ivF[0] < xmin)
        ivF[0] = xmin;
      if (ivF[0] > xmax)
        ivF[0] = xmax;
      if (ivF[1] < ymin)
        ivF[1] = ymin;
      if (ivF[1] > ymax)
        ivF[1] = ymax;
      }

    if (iv8[0] <  xmin)
      iv8[0] =  xmin;
    if (iv8[0] > (xmax + MB_SIZE))
      iv8[0] = (xmax + MB_SIZE);

    if (iv8[1] <  ymin)
      iv8[1] =  ymin;
    if (iv8[1] > (ymax + MB_SIZE))
      iv8[1] = (ymax + MB_SIZE);

    if (iv8[2] < (xmin - MB_SIZE))
      iv8[2] = (xmin - MB_SIZE);
    if (iv8[2] >  xmax)
      iv8[2] =  xmax;

    if (iv8[3] <  ymin)
      iv8[3] =  ymin;
    if (iv8[3] > (ymax + MB_SIZE))
      iv8[3] = (ymax + MB_SIZE);

    if (iv8[4] <  xmin)
      iv8[4] =  xmin;
    if (iv8[4] > (xmax + MB_SIZE))
      iv8[4] = (xmax + MB_SIZE);

    if (iv8[5] < (ymin - MB_SIZE))
      iv8[5] = (ymin - MB_SIZE);
    if (iv8[5] >  ymax)
      iv8[5] =  ymax;

    if (iv8[6] < (xmin - MB_SIZE))
      iv8[6] = (xmin - MB_SIZE);
    if (iv8[6] >  xmax)
      iv8[6] =  xmax;

    if (iv8[7] < (ymin - MB_SIZE))
      iv8[7] = (ymin - MB_SIZE);
    if (iv8[7] >  ymax)
      iv8[7] =  ymax;

    mv16_w += imv;
    mv16_h += imv;
    mv8_w  += imv;
    mv8_h  += imv;
    mvF_w  += imv;
    mvF_h  += imv;

    mv16_w[0] = mv16_w[1] = mv16_w[imv_width] = mv16_w[imv_width] =
                (Float)(0.5 * iv16[0]);
    mv16_h[0] = mv16_h[1] = mv16_h[imv_width] = mv16_h[imv_width] =
                (Float)(0.5 * iv16[1]);

    mvF_w[0]             = (Float)(0.5 * ivF[0]);
    mvF_h[0]             = (Float)(0.5 * ivF[1]);
    mvF_w[1]             = (Float)(0.5 * ivF[2]);
    mvF_h[1]             = (Float)(0.5 * ivF[3]);
    mvF_w[imv_width    ] = (Float)(0.5 * ivF[4]);
    mvF_h[imv_width]     = (Float)(0.5 * ivF[5]);
    mvF_w[imv_width + 1] = (Float)(0.5 * ivF[6]);
    mvF_h[imv_width + 1] = (Float)(0.5 * ivF[7]);
    mv8_w[0]             = (Float)(0.5 * iv8[0]);
    mv8_h[0]             = (Float)(0.5 * iv8[1]);
    mv8_w[1]             = (Float)(0.5 * iv8[2]);
    mv8_h[1]             = (Float)(0.5 * iv8[3]);
    mv8_w[imv_width    ] = (Float)(0.5 * iv8[4]);
    mv8_h[imv_width]     = (Float)(0.5 * iv8[5]);
    mv8_w[imv_width + 1] = (Float)(0.5 * iv8[6]);
    mv8_h[imv_width + 1] = (Float)(0.5 * iv8[7]);
    }
  else
    {
    MBMotionEstimation(curr_vop, alpha, prev, alpha_sub, br_x, br_y,
                       br_width, i, j, prev_x, prev_y,
                       vop_width, vop_height, enable_8x8_mv, edge,
                       f_code, MB_Nb, ref_sel_code, mv16_w, mv16_h,
                       mv8_w, mv8_h, mvF_w, mvF_h, &min_error, halfpelflags);

    /* Inter/Intra decision */
    interflag = ChooseMode((SInt *)GetImageData(GetVopY(curr_vop)),
    alpha,i*MB_SIZE,j*MB_SIZE, MB_Nb, min_error, br_width);

    /* Write MVs to file */
    if (curr_vop->mvfileusage == 2) {
      mv16_w += imv; mv16_h += imv;
      mv8_w  += imv; mv8_h  += imv;
      mvF_w  += imv; mvF_h  += imv;
      fprintf(curr_vop->mvfile,
                "%3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d\n",
              i, j, interflag,
              (int)(2*mv16_w[0]),          (int)(2*mv16_h[0]),
              (int)(2*mvF_w[0]),           (int)(2*mvF_h[0]),
              (int)(2*mvF_w[1]),           (int)(2*mvF_h[1]),
              (int)(2*mvF_w[imv_width]),   (int)(2*mvF_h[imv_width]),
              (int)(2*mvF_w[imv_width+1]), (int)(2*mvF_h[imv_width+1]),
              (int)(2*mv8_w[0]),           (int)(2*mv8_h[0]),
              (int)(2*mv8_w[1]),           (int)(2*mv8_h[0]),
              (int)(2*mv8_w[imv_width]),   (int)(2*mv8_h[imv_width]),
              (int)(2*mv8_w[imv_width+1]), (int)(2*mv8_h[imv_width+1]));
      (*curr_vop->mvlinenop)++;
      }
    }
  return(interflag);
}
