[svn] / branches / dev-api-4 / xvidcore / src / motion / motion_est.c Repository:
ViewVC logotype

Diff of /branches/dev-api-4/xvidcore/src/motion/motion_est.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 3, Fri Mar 8 02:46:11 2002 UTC revision 504, Sat Sep 21 11:59:22 2002 UTC
# Line 1  Line 1 
1  /**************************************************************************  /*****************************************************************************
2   *   *
3   *  Modifications:   *  XVID MPEG-4 VIDEO CODEC
4     *  - Motion Estimation module -
5   *   *
6   *  08.02.2002 split up PMVfast into three routines: PMVFast, PMVFast_MainLoop   *  Copyright(C) 2002 Christoph Lampert <gruel@web.de>
7   *             PMVFast_Refine to support multiple searches with different start points   *  Copyright(C) 2002 Michael Militzer <michael@xvid.org>
8   *      07.01.2002 uv-block-based interpolation   *  Copyright(C) 2002 Edouard Gomez <ed.gomez@wanadoo.fr>
  *  06.01.2002 INTER/INTRA-decision is now done before any SEARCH8 (speedup)  
  *                         changed INTER_BIAS to 150 (as suggested by suxen_drol)  
  *                         removed halfpel refinement step in PMVfastSearch8 + quality=5  
  *                         added new quality mode = 6 which performs halfpel refinement  
  *                         filesize difference between quality 5 and 6 is smaller than 1%  
  *             (Isibaar)  
  *  31.12.2001 PMVfastSearch16 and PMVfastSearch8 (gruel)  
  *      30.12.2001 get_range/MotionSearchX simplified; blue/green bug fix  
  *      22.12.2001 commented best_point==99 check  
  *      19.12.2001 modified get_range (purple bug fix)  
  *  15.12.2001 moved pmv displacement from mbprediction  
  *  02.12.2001 motion estimation/compensation split (Isibaar)  
  *      16.11.2001 rewrote/tweaked search algorithms; pross@cs.rmit.edu.au  
  *  10.11.2001 support for sad16/sad8 functions  
  *  28.08.2001 reactivated MODE_INTER4V for EXT_MODE  
  *  24.08.2001 removed MODE_INTER4V_Q, disabled MODE_INTER4V for EXT_MODE  
  *      22.08.2001 added MODE_INTER4V_Q  
  *  20.08.2001 added pragma to get rid of internal compiler error with VC6  
  *             idea by Cyril. Thanks.  
9   *   *
10   *  Michael Militzer <isibaar@videocoding.de>   *  This program is an implementation of a part of one or more MPEG-4
11     *  Video tools as specified in ISO/IEC 14496-2 standard.  Those intending
12     *  to use this software module in hardware or software products are
13     *  advised that its use may infringe existing patents or copyrights, and
14     *  any such use would be at such party's own risk.  The original
15     *  developer of this software module and his/her company, and subsequent
16     *  editors and their companies, will have no liability for use of this
17     *  software or modifications or derivatives thereof.
18   *   *
19   **************************************************************************/   *  This program is free software; you can redistribute it and/or modify
20     *  it under the terms of the GNU General Public License as published by
21     *  the Free Software Foundation; either version 2 of the License, or
22     *  (at your option) any later version.
23     *
24     *  This program is distributed in the hope that it will be useful,
25     *  but WITHOUT ANY WARRANTY; without even the implied warranty of
26     *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
27     *  GNU General Public License for more details.
28     *
29     *  You should have received a copy of the GNU General Public License
30     *  along with this program; if not, write to the Free Software
31     *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
32     *
33     *************************************************************************/
34    
35  #include <assert.h>  #include <assert.h>
36  #include <stdio.h>  #include <stdio.h>
37    #include <stdlib.h>
38    
39  #include "../encoder.h"  #include "../encoder.h"
40  #include "../utils/mbfunctions.h"  #include "../utils/mbfunctions.h"
41  #include "../prediction/mbprediction.h"  #include "../prediction/mbprediction.h"
42  #include "../global.h"  #include "../global.h"
43  #include "../utils/timer.h"  #include "../utils/timer.h"
44    #include "motion.h"
45  #include "sad.h"  #include "sad.h"
46    
 // very large value  
 #define MV_MAX_ERROR    (4096 * 256)  
   
 // stop search if sdelta < THRESHOLD  
 #define MV16_THRESHOLD  192  
 #define MV8_THRESHOLD   56  
   
 /* sad16(0,0) bias; mpeg4 spec suggests nb/2+1 */  
 /* nb  = vop pixels * 2^(bpp-8) */  
 #define MV16_00_BIAS    (128+1)  
   
 /* INTER bias for INTER/INTRA decision; mpeg4 spec suggests 2*nb */  
 #define INTER_BIAS      512  
   
 /* Parameters which control inter/inter4v decision */  
 #define IMV16X16                        5  
   
 /* vector map (vlc delta size) smoother parameters */  
 #define NEIGH_TEND_16X16        2  
 #define NEIGH_TEND_8X8          2  
   
   
 // fast ((A)/2)*2  
 #define EVEN(A)         (((A)<0?(A)+1:(A)) & ~1)  
   
   
 #define MIN(X, Y) ((X)<(Y)?(X):(Y))  
 #define MAX(X, Y) ((X)>(Y)?(X):(Y))  
 #define ABS(X) (((X)>0)?(X):-(X))  
 #define SIGN(X) (((X)>0)?1:-1)  
   
   
 int32_t PMVfastSearch8(  
                                         const uint8_t * const pRef,  
                                         const uint8_t * const pRefH,  
                                         const uint8_t * const pRefV,  
                                         const uint8_t * const pRefHV,  
                                         const IMAGE * const pCur,  
                                         const int x, const int y,  
                                         const int start_x, int start_y,  
                                         const uint32_t iQuality,  
                                         MBParam * const pParam,  
                                         MACROBLOCK * const pMBs,  
                                         VECTOR * const currMV,  
                                         VECTOR * const currPMV);  
   
 int32_t PMVfastSearch16(  
                                         const uint8_t * const pRef,  
                                         const uint8_t * const pRefH,  
                                         const uint8_t * const pRefV,  
                                         const uint8_t * const pRefHV,  
                                         const IMAGE * const pCur,  
                                         const int x, const int y,  
                                         const uint32_t iQuality,  
                                         MBParam * const pParam,  
                                         MACROBLOCK * const pMBs,  
                                         VECTOR * const currMV,  
                                         VECTOR * const currPMV);  
   
47    
48    
49  /* diamond search stuff  static int32_t lambda_vec16[32] =       /* rounded values for lambda param for weight of motion bits as in modified H.26L */
50     keep the the sequence in circular order (so optimization works)  { 0, (int) (1.00235 + 0.5), (int) (1.15582 + 0.5), (int) (1.31976 + 0.5),
51  */                  (int) (1.49591 + 0.5), (int) (1.68601 + 0.5),
52            (int) (1.89187 + 0.5), (int) (2.11542 + 0.5), (int) (2.35878 + 0.5),
53  typedef struct                  (int) (2.62429 + 0.5), (int) (2.91455 + 0.5),
54  {          (int) (3.23253 + 0.5), (int) (3.58158 + 0.5), (int) (3.96555 + 0.5),
55          int32_t dx;                  (int) (4.38887 + 0.5), (int) (4.85673 + 0.5),
56          int32_t dy;          (int) (5.37519 + 0.5), (int) (5.95144 + 0.5), (int) (6.59408 + 0.5),
57  }                  (int) (7.31349 + 0.5), (int) (8.12242 + 0.5),
58  DPOINT;          (int) (9.03669 + 0.5), (int) (10.0763 + 0.5), (int) (11.2669 + 0.5),
59                    (int) (12.6426 + 0.5), (int) (14.2493 + 0.5),
60            (int) (16.1512 + 0.5), (int) (18.442 + 0.5), (int) (21.2656 + 0.5),
61  static const DPOINT diamond_small[4] =                  (int) (24.8580 + 0.5), (int) (29.6436 + 0.5),
62  {          (int) (36.4949 + 0.5)
         {0, 1}, {1, 0}, {0, -1}, {-1, 0}  
63  };  };
64    
65    static int32_t *lambda_vec8 = lambda_vec16;     /* same table for INTER and INTER4V for now */
66    
 static const DPOINT diamond_large[8] =  
 {  
         {0, 2}, {1, 1}, {2, 0}, {1, -1}, {0, -2}, {-1, -1}, {-2, 0}, {-1, 1}  
 };  
67    
68    
69  // mv.length table  // mv.length table
# Line 133  Line 75 
75  };  };
76    
77    
78  static __inline uint32_t mv_bits(int32_t component, const uint32_t iFcode)  static __inline uint32_t
79    mv_bits(int32_t component,
80                    const uint32_t iFcode)
81  {  {
82      if (component == 0)      if (component == 0)
83                  return 1;                  return 1;
# Line 141  Line 85 
85      if (component < 0)      if (component < 0)
86                  component = -component;                  component = -component;
87    
88      if (iFcode == 1)          if (iFcode == 1) {
     {  
89                  if (component > 32)                  if (component > 32)
90                      component = 32;                      component = 32;
91    
# Line 159  Line 102 
102  }  }
103    
104    
105  static __inline uint32_t calc_delta_16(const int32_t dx, const int32_t dy, const uint32_t iFcode)  static __inline uint32_t
106  {  calc_delta_16(const int32_t dx,
107          return NEIGH_TEND_16X16 * (mv_bits(dx, iFcode) + mv_bits(dy, iFcode));                            const int32_t dy,
108  }                            const uint32_t iFcode,
109                              const uint32_t iQuant)
110  static __inline uint32_t calc_delta_8(const int32_t dx, const int32_t dy, const uint32_t iFcode)  {
111            return NEIGH_TEND_16X16 * lambda_vec16[iQuant] * (mv_bits(dx, iFcode) +
112  {                                                                                                            mv_bits(dy, iFcode));
113      return NEIGH_TEND_8X8 * (mv_bits(dx, iFcode) + mv_bits(dy, iFcode));  }
114  }  
115    static __inline uint32_t
116    calc_delta_8(const int32_t dx,
117                             const int32_t dy,
118                             const uint32_t iFcode,
119  /* calculate the min/max range (in halfpixels)                           const uint32_t iQuant)
120          relative to the _MACROBLOCK_ position  {
121  */          return NEIGH_TEND_8X8 * lambda_vec8[iQuant] * (mv_bits(dx, iFcode) +
122                                                                                                       mv_bits(dy, iFcode));
123  static void __inline get_range(  }
124                          int32_t * const min_dx, int32_t * const max_dx,  
125                          int32_t * const min_dy, int32_t * const max_dy,  bool
126                          const uint32_t x, const uint32_t y,  MotionEstimation(MBParam * const pParam,
127                          const uint32_t block_sz,                                        // block dimension, 8 or 16                                   FRAMEINFO * const current,
128                          const uint32_t width, const uint32_t height,                                   FRAMEINFO * const reference,
                         const uint32_t fcode)  
 {  
         const int search_range = 32 << (fcode - 1);  
     const int high = search_range - 1;  
     const int low = -search_range;  
   
         // convert full-pixel measurements to half pixel  
         const int hp_width = 2 * width;  
         const int hp_height = 2 * height;  
         const int hp_edge = 2 * block_sz;  
         const int hp_x = 2 * (x) * block_sz;            // we need _right end_ of block, not x-coordinate  
         const int hp_y = 2 * (y) * block_sz;            // same for _bottom end_  
   
     *max_dx = MIN(high, hp_width - hp_x);  
     *max_dy = MIN(high, hp_height - hp_y);  
     *min_dx = MAX(low,  -(hp_edge + hp_x));  
     *min_dy = MAX(low,  -(hp_edge + hp_y));  
 }  
   
   
 /* getref: calculate reference image pointer  
 the decision to use interpolation h/v/hv or the normal image is  
 based on dx & dy.  
 */  
   
 static __inline const uint8_t * get_ref(  
                                 const uint8_t * const refn,  
                                 const uint8_t * const refh,  
                                 const uint8_t * const refv,  
                                 const uint8_t * const refhv,  
                                 const uint32_t x, const uint32_t y,  
                                 const uint32_t block,                                   // block dimension, 8 or 16  
                                 const int32_t dx, const int32_t dy,  
                                 const uint32_t stride)  
 {  
         switch ( ((dx&1)<<1) + (dy&1) )         // ((dx%2)?2:0)+((dy%2)?1:0)  
     {  
         case 0 : return refn + (x*block+dx/2) + (y*block+dy/2)*stride;  
     case 1 : return refv + (x*block+dx/2) + (y*block+(dy-1)/2)*stride;  
         case 2 : return refh + (x*block+(dx-1)/2) + (y*block+dy/2)*stride;  
         default :  
         case 3 : return refhv + (x*block+(dx-1)/2) + (y*block+(dy-1)/2)*stride;  
         }  
 }  
   
   
 /* This is somehow a copy of get_ref, but with MV instead of X,Y */  
   
 static __inline const uint8_t * get_ref_mv(  
                                 const uint8_t * const refn,  
                                 const uint8_t * const refh,  
                                 const uint8_t * const refv,  
                                 const uint8_t * const refhv,  
                                 const uint32_t x, const uint32_t y,  
                                 const uint32_t block,                   // block dimension, 8 or 16  
                                 const VECTOR* mv,       // measured in half-pel!  
                                 const uint32_t stride)  
 {  
         switch ( (((mv->x)&1)<<1) + ((mv->y)&1) )  
     {  
         case 0 : return refn + (x*block+(mv->x)/2) + (y*block+(mv->y)/2)*stride;  
         case 1 : return refv + (x*block+(mv->x)/2) + (y*block+((mv->y)-1)/2)*stride;  
         case 2 : return refh + (x*block+((mv->x)-1)/2) + (y*block+(mv->y)/2)*stride;  
         default :  
         case 3 : return refhv + (x*block+((mv->x)-1)/2) + (y*block+((mv->y)-1)/2)*stride;  
         }  
 }  
   
 #ifndef SEARCH16  
 #define SEARCH16        PMVfastSearch16  
 #endif  
   
 #ifndef SEARCH8  
 #define SEARCH8         PMVfastSearch8  
 #endif  
   
 bool MotionEstimation(  
                         MACROBLOCK * const pMBs,  
                         MBParam * const pParam,  
                     const IMAGE * const pRef,  
129                          const IMAGE * const pRefH,                          const IMAGE * const pRefH,
130                      const IMAGE * const pRefV,                      const IMAGE * const pRefV,
131                          const IMAGE * const pRefHV,                          const IMAGE * const pRefHV,
                     IMAGE * const pCurrent,  
132                          const uint32_t iLimit)                          const uint32_t iLimit)
   
133  {  {
134      const uint32_t iWcount = pParam->mb_width;      const uint32_t iWcount = pParam->mb_width;
135      const uint32_t iHcount = pParam->mb_height;      const uint32_t iHcount = pParam->mb_height;
136            MACROBLOCK *const pMBs = current->mbs;
137            MACROBLOCK *const prevMBs = reference->mbs;
138            const IMAGE *const pCurrent = &current->image;
139            const IMAGE *const pRef = &reference->image;
140    
141          uint32_t i, j, iIntra = 0;          static const VECTOR zeroMV = { 0, 0 };
142            VECTOR predMV;
143    
144      VECTOR mv16;          uint32_t x, y;
145      VECTOR pmv16;          uint32_t iIntra = 0;
146            VECTOR pmv;
147    
148      int32_t sad8 = 0;          if (sadInit)
149      int32_t sad16;                  (*sadInit) ();
     int32_t deviation;  
150    
151          // note: i==horizontal, j==vertical          for (y = 0; y < iHcount; y++)   {
152      for (i = 0; i < iHcount; i++)                  for (x = 0; x < iWcount; x ++)  {
                 for (j = 0; j < iWcount; j++)  
                 {  
                         MACROBLOCK *pMB = &pMBs[j + i * iWcount];  
153    
154                          sad16 = SEARCH16(pRef->y, pRefH->y, pRefV->y, pRefHV->y, pCurrent,                          MACROBLOCK *const pMB = &pMBs[x + y * iWcount];
                                           j, i, pParam->motion_flags,  
                                           pParam, pMBs, &mv16, &pmv16);  
                         pMB->sad16=sad16;  
155    
156                            predMV = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 0);
157    
158                  /* decide: MODE_INTER or MODE_INTRA                          pMB->sad16 =
159                          if (dev_intra < sad_inter - 2 * nb) use_intra                                  SEARCH16(pRef->y, pRefH->y, pRefV->y, pRefHV->y, pCurrent,
160                  */                                                   x, y, predMV.x, predMV.y, predMV.x, predMV.y,
161                                                     current->motion_flags, current->quant,
162                                                     current->fcode, pParam, pMBs, prevMBs, &pMB->mv16,
163                                                     &pMB->pmvs[0]);
164    
165                            if (0 < (pMB->sad16 - MV16_INTER_BIAS)) {
166                                    int32_t deviation;
167    
168                  deviation = dev16(pCurrent->y + j*16 + i*16*pParam->edged_width, pParam->edged_width);                                  deviation =
169                                            dev16(pCurrent->y + x * 16 + y * 16 * pParam->edged_width,
170                                                      pParam->edged_width);
171    
172                  if (deviation < (sad16 - INTER_BIAS))                                  if (deviation < (pMB->sad16 - MV16_INTER_BIAS)) {
                 {  
173                          pMB->mode = MODE_INTRA;                          pMB->mode = MODE_INTRA;
174                          pMB->mvs[0].x = pMB->mvs[1].x = pMB->mvs[2].x = pMB->mvs[3].x = 0;                                          pMB->mv16 = pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] =
175                          pMB->mvs[0].y = pMB->mvs[1].y = pMB->mvs[2].y = pMB->mvs[3].y = 0;                                                  pMB->mvs[3] = zeroMV;
176                                            pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] =
177                                                    pMB->sad8[3] = 0;
178    
179                          iIntra++;                          iIntra++;
180                          if(iIntra >= iLimit)                          if(iIntra >= iLimit)
# Line 312  Line 182 
182    
183                          continue;                          continue;
184                  }                  }
   
                 if (pParam->global_flags & XVID_INTER4V)  
                 {  
                         pMB->sad8[0] = SEARCH8(pRef->y, pRefH->y, pRefV->y, pRefHV->y, pCurrent,  
                                         2 * j, 2 * i, mv16.x, mv16.y, pParam->motion_flags,  
                                         pParam, pMBs, &pMB->mvs[0], &pMB->pmvs[0]);  
   
                         pMB->sad8[1] = SEARCH8(pRef->y, pRefH->y, pRefV->y, pRefHV->y, pCurrent,  
                                         2 * j + 1, 2 * i, mv16.x, mv16.y, pParam->motion_flags,  
                                         pParam, pMBs, &pMB->mvs[1], &pMB->pmvs[1]);  
   
                         pMB->sad8[2] = SEARCH8(pRef->y, pRefH->y, pRefV->y, pRefHV->y, pCurrent,  
                                         2 * j, 2 * i + 1, mv16.x, mv16.y, pParam->motion_flags,  
                                         pParam, pMBs, &pMB->mvs[2], &pMB->pmvs[2]);  
   
                         pMB->sad8[3] = SEARCH8(pRef->y, pRefH->y, pRefV->y, pRefHV->y, pCurrent,  
                                         2 * j + 1, 2 * i + 1, mv16.x, mv16.y, pParam->motion_flags,  
                                         pParam, pMBs, &pMB->mvs[3], &pMB->pmvs[3]);  
   
                         sad8 = pMB->sad8[0] + pMB->sad8[1] + pMB->sad8[2] + pMB->sad8[3];  
185                  }                  }
186    
187                            pmv = pMB->pmvs[0];
188                            if (current->global_flags & XVID_INTER4V)
189                                    if ((!(current->global_flags & XVID_LUMIMASKING) ||
190                                             pMB->dquant == NO_CHANGE)) {
191                                            int32_t sad8 = IMV16X16 * current->quant;
192    
193                                            if (sad8 < pMB->sad16) {
194                                                    sad8 += pMB->sad8[0] =
195                                                            SEARCH8(pRef->y, pRefH->y, pRefV->y, pRefHV->y,
196                                                                            pCurrent, 2 * x, 2 * y,
197                                                                            pMB->mv16.x, pMB->mv16.y, predMV.x, predMV.y,
198                                                                            current->motion_flags,
199                                                                            current->quant, current->fcode, pParam,
200                                                                            pMBs, prevMBs, &pMB->mvs[0],
201                                                                            &pMB->pmvs[0]);
202                                            }
203                                            if (sad8 < pMB->sad16) {
204    
205                                                    predMV = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 1);
206                                                    sad8 += pMB->sad8[1] =
207                                                            SEARCH8(pRef->y, pRefH->y, pRefV->y, pRefHV->y,
208                                                                            pCurrent, 2 * x + 1, 2 * y,
209                                                                            pMB->mv16.x, pMB->mv16.y, predMV.x, predMV.y,
210                                                                            current->motion_flags,
211                                                                            current->quant, current->fcode, pParam,
212                                                                            pMBs, prevMBs, &pMB->mvs[1],
213                                                                            &pMB->pmvs[1]);
214                                            }
215                                            if (sad8 < pMB->sad16) {
216                                                    predMV = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 2);
217                                                    sad8 += pMB->sad8[2] =
218                                                            SEARCH8(pRef->y, pRefH->y, pRefV->y, pRefHV->y,
219                                                                            pCurrent, 2 * x, 2 * y + 1,
220                                                                            pMB->mv16.x, pMB->mv16.y, predMV.x, predMV.y,
221                                                                            current->motion_flags,
222                                                                            current->quant, current->fcode, pParam,
223                                                                            pMBs, prevMBs, &pMB->mvs[2],
224                                                                            &pMB->pmvs[2]);
225                                            }
226                                            if (sad8 < pMB->sad16) {
227                                                    predMV = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 3);
228                                                    sad8 += pMB->sad8[3] =
229                                                            SEARCH8(pRef->y, pRefH->y, pRefV->y, pRefHV->y,
230                                                                            pCurrent, 2 * x + 1, 2 * y + 1,
231                                                                            pMB->mv16.x, pMB->mv16.y, predMV.x, predMV.y,
232                                                                            current->motion_flags,
233                                                                            current->quant, current->fcode, pParam,
234                                                                            pMBs, prevMBs,
235                                                                            &pMB->mvs[3],
236                                                                            &pMB->pmvs[3]);
237                                            }
238    
239                  /* decide: MODE_INTER or MODE_INTER4V                  /* decide: MODE_INTER or MODE_INTER4V
240                          mpeg4:   if (sad8 < sad16 - nb/2+1) use_inter4v                                             mpeg4:   if (sad8 < pMB->sad16 - nb/2+1) use_inter4v
241                  */                  */
242    
243                  if (pMB->dquant == NO_CHANGE) {                                          if (sad8 < pMB->sad16) {
                         if (((pParam->global_flags & XVID_INTER4V)==0) ||  
                                 (sad16 < (sad8 + (int32_t)(IMV16X16 * pParam->quant)))) {  
   
                                 sad8 = sad16;  
                                 pMB->mode = MODE_INTER;  
                                 pMB->mvs[0].x = pMB->mvs[1].x = pMB->mvs[2].x = pMB->mvs[3].x = mv16.x;  
                                 pMB->mvs[0].y = pMB->mvs[1].y = pMB->mvs[2].y = pMB->mvs[3].y = mv16.y;  
                                 pMB->pmvs[0].x = pmv16.x;  
                                 pMB->pmvs[0].y = pmv16.y;  
                         }  
                         else  
244                                  pMB->mode = MODE_INTER4V;                                  pMB->mode = MODE_INTER4V;
245                                                    pMB->sad8[0] *= 4;
246                                                    pMB->sad8[1] *= 4;
247                                                    pMB->sad8[2] *= 4;
248                                                    pMB->sad8[3] *= 4;
249                                                    continue;
250                  }                  }
251                  else  
252                  {                                  }
253                          sad8 = sad16;  
254                          pMB->mode = MODE_INTER;                          pMB->mode = MODE_INTER;
255                          pMB->mvs[0].x = pMB->mvs[1].x = pMB->mvs[2].x = pMB->mvs[3].x = mv16.x;                          pMB->pmvs[0] = pmv;     /* pMB->pmvs[1] = pMB->pmvs[2] = pMB->pmvs[3]  are not needed for INTER */
256                          pMB->mvs[0].y = pMB->mvs[1].y = pMB->mvs[2].y = pMB->mvs[3].y = mv16.y;                          pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = pMB->mv16;
257                          pMB->pmvs[0].x = pmv16.x;                          pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] = pMB->sad8[3] =
258                          pMB->pmvs[0].y = pmv16.y;                                  pMB->sad16;
259                  }                  }
260          }          }
261    
262          return 0;          return 0;
263  }  }
264    
 #define MVzero(A) ( ((A).x)==(0) && ((A).y)==(0) )  
   
 #define MVequal(A,B) ( ((A).x)==((B).x) && ((A).y)==((B).y) )  
   
265    
266  #define CHECK_MV16_ZERO {\  #define CHECK_MV16_ZERO {\
267    if ( (0 <= max_dx) && (0 >= min_dx) \    if ( (0 <= max_dx) && (0 >= min_dx) \
268      && (0 <= max_dy) && (0 >= min_dy) ) \      && (0 <= max_dy) && (0 >= min_dy) ) \
269    { \    { \
270      iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, 0, 0 , iEdgedWidth), iEdgedWidth, MV_MAX_ERROR); \      iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, 0, 0 , iEdgedWidth), iEdgedWidth, MV_MAX_ERROR); \
271      iSAD += calc_delta_16(-pmv[0].x, -pmv[0].y, (uint8_t)iFcode) * iQuant;\      iSAD += calc_delta_16(-center_x, -center_y, (uint8_t)iFcode, iQuant);\
     if (iSAD <= iQuant * 96)    \  
         iSAD -= MV16_00_BIAS; \  
272      if (iSAD < iMinSAD) \      if (iSAD < iMinSAD) \
273      {  iMinSAD=iSAD; currMV->x=0; currMV->y=0; }  }     \      {  iMinSAD=iSAD; currMV->x=0; currMV->y=0; }  }     \
274  }  }
275    
276    #define NOCHECK_MV16_CANDIDATE(X,Y) { \
277        iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, X, Y, iEdgedWidth),iEdgedWidth, iMinSAD); \
278        iSAD += calc_delta_16((X) - center_x, (Y) - center_y, (uint8_t)iFcode, iQuant);\
279        if (iSAD < iMinSAD) \
280        {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); } \
281    }
282    
283  #define CHECK_MV16_CANDIDATE(X,Y) { \  #define CHECK_MV16_CANDIDATE(X,Y) { \
284    if ( ((X) <= max_dx) && ((X) >= min_dx) \    if ( ((X) <= max_dx) && ((X) >= min_dx) \
285      && ((Y) <= max_dy) && ((Y) >= min_dy) ) \      && ((Y) <= max_dy) && ((Y) >= min_dy) ) \
286    { \    { \
287      iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, X, Y, iEdgedWidth),iEdgedWidth, iMinSAD); \      iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, X, Y, iEdgedWidth),iEdgedWidth, iMinSAD); \
288      iSAD += calc_delta_16((X) - pmv[0].x, (Y) - pmv[0].y, (uint8_t)iFcode) * iQuant;\      iSAD += calc_delta_16((X) - center_x, (Y) - center_y, (uint8_t)iFcode, iQuant);\
289      if (iSAD < iMinSAD) \      if (iSAD < iMinSAD) \
290      {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); } } \      {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); } } \
291  }  }
# Line 400  Line 295 
295      && ((Y) <= max_dy) && ((Y) >= min_dy) ) \      && ((Y) <= max_dy) && ((Y) >= min_dy) ) \
296    { \    { \
297      iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, X, Y, iEdgedWidth),iEdgedWidth, iMinSAD); \      iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, X, Y, iEdgedWidth),iEdgedWidth, iMinSAD); \
298      iSAD += calc_delta_16((X) - pmv[0].x, (Y) - pmv[0].y, (uint8_t)iFcode) * iQuant;\      iSAD += calc_delta_16((X) - center_x, (Y) - center_y, (uint8_t)iFcode, iQuant);\
299      if (iSAD < iMinSAD) \      if (iSAD < iMinSAD) \
300      {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iDirection=(D); } } \      {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iDirection=(D); } } \
301  }  }
# Line 410  Line 305 
305      && ((Y) <= max_dy) && ((Y) >= min_dy) ) \      && ((Y) <= max_dy) && ((Y) >= min_dy) ) \
306    { \    { \
307      iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, X, Y, iEdgedWidth),iEdgedWidth, iMinSAD); \      iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, X, Y, iEdgedWidth),iEdgedWidth, iMinSAD); \
308      iSAD += calc_delta_16((X) - pmv[0].x, (Y) - pmv[0].y, (uint8_t)iFcode) * iQuant;\      iSAD += calc_delta_16((X) - center_x, (Y) - center_y, (uint8_t)iFcode, iQuant);\
309      if (iSAD < iMinSAD) \      if (iSAD < iMinSAD) \
310      {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iDirection=(D); iFound=0; } } \      {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iDirection=(D); iFound=0; } } \
311  }  }
# Line 418  Line 313 
313    
314  #define CHECK_MV8_ZERO {\  #define CHECK_MV8_ZERO {\
315    iSAD = sad8( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 8, 0, 0 , iEdgedWidth), iEdgedWidth); \    iSAD = sad8( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 8, 0, 0 , iEdgedWidth), iEdgedWidth); \
316    iSAD += calc_delta_8(-pmv[0].x, -pmv[0].y, (uint8_t)iFcode) * iQuant;\    iSAD += calc_delta_8(-center_x, -center_y, (uint8_t)iFcode, iQuant);\
317    if (iSAD < iMinSAD) \    if (iSAD < iMinSAD) \
318    { iMinSAD=iSAD; currMV->x=0; currMV->y=0; } \    { iMinSAD=iSAD; currMV->x=0; currMV->y=0; } \
319  }  }
320    
321    #define NOCHECK_MV8_CANDIDATE(X,Y) \
322      { \
323        iSAD = sad8( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 8, (X), (Y), iEdgedWidth),iEdgedWidth); \
324        iSAD += calc_delta_8((X)-center_x, (Y)-center_y, (uint8_t)iFcode, iQuant);\
325        if (iSAD < iMinSAD) \
326        {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); } \
327    }
328    
329  #define CHECK_MV8_CANDIDATE(X,Y) { \  #define CHECK_MV8_CANDIDATE(X,Y) { \
330    if ( ((X) <= max_dx) && ((X) >= min_dx) \    if ( ((X) <= max_dx) && ((X) >= min_dx) \
331      && ((Y) <= max_dy) && ((Y) >= min_dy) ) \      && ((Y) <= max_dy) && ((Y) >= min_dy) ) \
332    { \    { \
333      iSAD = sad8( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 8, (X), (Y), iEdgedWidth),iEdgedWidth); \      iSAD = sad8( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 8, (X), (Y), iEdgedWidth),iEdgedWidth); \
334      iSAD += calc_delta_8((X)-pmv[0].x, (Y)-pmv[0].y, (uint8_t)iFcode) * iQuant;\      iSAD += calc_delta_8((X)-center_x, (Y)-center_y, (uint8_t)iFcode, iQuant);\
335      if (iSAD < iMinSAD) \      if (iSAD < iMinSAD) \
336      {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); } } \      {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); } } \
337  }  }
# Line 439  Line 341 
341      && ((Y) <= max_dy) && ((Y) >= min_dy) ) \      && ((Y) <= max_dy) && ((Y) >= min_dy) ) \
342    { \    { \
343      iSAD = sad8( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 8, (X), (Y), iEdgedWidth),iEdgedWidth); \      iSAD = sad8( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 8, (X), (Y), iEdgedWidth),iEdgedWidth); \
344      iSAD += calc_delta_8((X)-pmv[0].x, (Y)-pmv[0].y, (uint8_t)iFcode) * iQuant;\      iSAD += calc_delta_8((X)-center_x, (Y)-center_y, (uint8_t)iFcode, iQuant);\
345      if (iSAD < iMinSAD) \      if (iSAD < iMinSAD) \
346      {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iDirection=(D); } } \      {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iDirection=(D); } } \
347  }  }
# Line 449  Line 351 
351      && ((Y) <= max_dy) && ((Y) >= min_dy) ) \      && ((Y) <= max_dy) && ((Y) >= min_dy) ) \
352    { \    { \
353      iSAD = sad8( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 8, (X), (Y), iEdgedWidth),iEdgedWidth); \      iSAD = sad8( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 8, (X), (Y), iEdgedWidth),iEdgedWidth); \
354      iSAD += calc_delta_8((X)-pmv[0].x, (Y)-pmv[0].y, (uint8_t)iFcode) * iQuant;\      iSAD += calc_delta_8((X)-center_x, (Y)-center_y, (uint8_t)iFcode, iQuant);\
355      if (iSAD < iMinSAD) \      if (iSAD < iMinSAD) \
356      {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iDirection=(D); iFound=0; } } \      {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iDirection=(D); iFound=0; } } \
357  }  }
358    
359    #if 0
360  /* too slow and not fully functional at the moment */  /* too slow and not fully functional at the moment */
 /*  
361  int32_t ZeroSearch16(  int32_t ZeroSearch16(
362                                          const uint8_t * const pRef,                                          const uint8_t * const pRef,
363                                          const uint8_t * const pRefH,                                          const uint8_t * const pRefH,
# Line 464  Line 366 
366                                          const IMAGE * const pCur,                                          const IMAGE * const pCur,
367                                          const int x, const int y,                                          const int x, const int y,
368                                          const uint32_t MotionFlags,                                          const uint32_t MotionFlags,
369                                            const uint32_t iQuant,
370                                            const uint32_t iFcode,
371                                          MBParam * const pParam,                                          MBParam * const pParam,
372                                          MACROBLOCK * const pMBs,                                          const MACROBLOCK * const pMBs,
373                                            const MACROBLOCK * const prevMBs,
374                                          VECTOR * const currMV,                                          VECTOR * const currMV,
375                                          VECTOR * const currPMV)                                          VECTOR * const currPMV)
376  {  {
377          const int32_t iEdgedWidth = pParam->edged_width;          const int32_t iEdgedWidth = pParam->edged_width;
         const int32_t iQuant = pParam->quant;  
378          const uint8_t * cur = pCur->y + x*16 + y*16*iEdgedWidth;          const uint8_t * cur = pCur->y + x*16 + y*16*iEdgedWidth;
379          int32_t iSAD;          int32_t iSAD;
380          int32_t pred_x,pred_y;          VECTOR pred;
381    
382    
383          get_pmv(pMBs, x, y, pParam->mb_width, 0, &pred_x, &pred_y);          pred = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 0);
384    
385          iSAD = sad16( cur,          iSAD = sad16( cur,
386                  get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, 0,0, iEdgedWidth),                  get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, 0,0, iEdgedWidth),
# Line 485  Line 390 
390    
391          currMV->x = 0;          currMV->x = 0;
392          currMV->y = 0;          currMV->y = 0;
393          currPMV->x = -pred_x;          currPMV->x = -pred.x;
394          currPMV->y = -pred_y;          currPMV->y = -pred.y;
395    
396          return iSAD;          return iSAD;
397    
398  }  }
399  */  #endif /* 0 */
400    
401  int32_t PMVfastSearch16_MainSearch(  int32_t
402                                          const uint8_t * const pRef,  Diamond16_MainSearch(const uint8_t * const pRef,
403                                          const uint8_t * const pRefH,                                          const uint8_t * const pRefH,
404                                          const uint8_t * const pRefV,                                          const uint8_t * const pRefV,
405                                          const uint8_t * const pRefHV,                                          const uint8_t * const pRefHV,
406                                          const uint8_t * const cur,                                          const uint8_t * const cur,
407                                          const int x, const int y,                                           const int x,
408                                          int32_t startx, int32_t starty,                                           const int y,
409                                          int32_t iMinSAD,                                           const int start_x,
410                                             const int start_y,
411                                             int iMinSAD,
412                                          VECTOR * const currMV,                                          VECTOR * const currMV,
413                                          const VECTOR * const pmv,                                           const int center_x,
414                                          const int32_t min_dx, const int32_t max_dx,                                           const int center_y,
415                                          const int32_t min_dy, const int32_t max_dy,                                           const int32_t min_dx,
416                                             const int32_t max_dx,
417                                             const int32_t min_dy,
418                                             const int32_t max_dy,
419                                          const int32_t iEdgedWidth,                                          const int32_t iEdgedWidth,
420                                          const int32_t iDiamondSize,                                          const int32_t iDiamondSize,
421                                          const int32_t iFcode,                                          const int32_t iFcode,
# Line 515  Line 425 
425  /* Do a diamond search around given starting point, return SAD of best */  /* Do a diamond search around given starting point, return SAD of best */
426    
427          int32_t iDirection=0;          int32_t iDirection=0;
428            int32_t iDirectionBackup;
429          int32_t iSAD;          int32_t iSAD;
430          VECTOR backupMV;          VECTOR backupMV;
431          backupMV.x = startx;  
432          backupMV.y = starty;          backupMV.x = start_x;
433            backupMV.y = start_y;
434    
435  /* It's one search with full Diamond pattern, and only 3 of 4 for all following diamonds */  /* It's one search with full Diamond pattern, and only 3 of 4 for all following diamonds */
436    
# Line 527  Line 439 
439          CHECK_MV16_CANDIDATE_DIR(backupMV.x,backupMV.y-iDiamondSize,3);          CHECK_MV16_CANDIDATE_DIR(backupMV.x,backupMV.y-iDiamondSize,3);
440          CHECK_MV16_CANDIDATE_DIR(backupMV.x,backupMV.y+iDiamondSize,4);          CHECK_MV16_CANDIDATE_DIR(backupMV.x,backupMV.y+iDiamondSize,4);
441    
442          if (iDirection)          if (iDirection) {
443                  while (!iFound)                  while (!iFound) {
                 {  
444                          iFound = 1;                          iFound = 1;
445                          backupMV=*currMV;                          backupMV=*currMV;
446                            iDirectionBackup = iDirection;
447    
448                          if ( iDirection != 2)                          if (iDirectionBackup != 2)
449                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x-iDiamondSize,backupMV.y,1);                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,
450                          if ( iDirection != 1)                                                                                     backupMV.y, 1);
451                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x+iDiamondSize,backupMV.y,2);                          if (iDirectionBackup != 1)
452                          if ( iDirection != 4)                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,
453                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x,backupMV.y-iDiamondSize,3);                                                                                     backupMV.y, 2);
454                          if ( iDirection != 3)                          if (iDirectionBackup != 4)
455                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x,backupMV.y+iDiamondSize,4);                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x,
456                                                                                       backupMV.y - iDiamondSize, 3);
457                            if (iDirectionBackup != 3)
458                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x,
459                                                                                       backupMV.y + iDiamondSize, 4);
460                  }                  }
461          else          } else {
462                  {                  currMV->x = start_x;
463                          currMV->x = startx;                  currMV->y = start_y;
                         currMV->y = starty;  
464                  }                  }
465          return iMinSAD;          return iMinSAD;
466  }  }
467    
468  int32_t PMVfastSearch16_Refine(  int32_t
469                                          const uint8_t * const pRef,  Square16_MainSearch(const uint8_t * const pRef,
470                                          const uint8_t * const pRefH,                                          const uint8_t * const pRefH,
471                                          const uint8_t * const pRefV,                                          const uint8_t * const pRefV,
472                                          const uint8_t * const pRefHV,                                          const uint8_t * const pRefHV,
473                                          const uint8_t * const cur,                                          const uint8_t * const cur,
474                                          const int x, const int y,                                          const int x,
475                                            const int y,
476                                            const int start_x,
477                                            const int start_y,
478                                            int iMinSAD,
479                                          VECTOR * const currMV,                                          VECTOR * const currMV,
480                                          int32_t iMinSAD,                                          const int center_x,
481                                          const VECTOR * const pmv,                                          const int center_y,
482                                          const int32_t min_dx, const int32_t max_dx,                                          const int32_t min_dx,
483                                          const int32_t min_dy, const int32_t max_dy,                                          const int32_t max_dx,
484                                            const int32_t min_dy,
485                                            const int32_t max_dy,
486                                            const int32_t iEdgedWidth,
487                                            const int32_t iDiamondSize,
488                                          const int32_t iFcode,                                          const int32_t iFcode,
489                                          const int32_t iQuant,                                          const int32_t iQuant,
490                                          const int32_t iEdgedWidth)                                          int iFound)
491  {  {
492  /* Do a half-pel refinement (or rather a "smallest possible amount" refinement) */  /* Do a square search around given starting point, return SAD of best */
493    
494            int32_t iDirection = 0;
495          int32_t iSAD;          int32_t iSAD;
496          VECTOR backupMV = *currMV;          VECTOR backupMV;
497    
498            backupMV.x = start_x;
499            backupMV.y = start_y;
500    
501    /* It's one search with full square pattern, and new parts for all following diamonds */
502    
503    /*   new direction are extra, so 1-4 is normal diamond
504          537
505          1*2
506          648
507    */
508    
509            CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize, backupMV.y, 1);
510            CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize, backupMV.y, 2);
511            CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y - iDiamondSize, 3);
512            CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y + iDiamondSize, 4);
513    
514            CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize,
515                                                             backupMV.y - iDiamondSize, 5);
516            CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize,
517                                                             backupMV.y + iDiamondSize, 6);
518            CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize,
519                                                             backupMV.y - iDiamondSize, 7);
520            CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize,
521                                                             backupMV.y + iDiamondSize, 8);
522    
         CHECK_MV16_CANDIDATE(backupMV.x-1,backupMV.y-1);  
         CHECK_MV16_CANDIDATE(backupMV.x  ,backupMV.y-1);  
         CHECK_MV16_CANDIDATE(backupMV.x+1,backupMV.y-1);  
         CHECK_MV16_CANDIDATE(backupMV.x-1,backupMV.y);  
         CHECK_MV16_CANDIDATE(backupMV.x+1,backupMV.y);  
         CHECK_MV16_CANDIDATE(backupMV.x-1,backupMV.y+1);  
         CHECK_MV16_CANDIDATE(backupMV.x  ,backupMV.y+1);  
         CHECK_MV16_CANDIDATE(backupMV.x+1,backupMV.y+1);  
523    
524            if (iDirection) {
525                    while (!iFound) {
526                            iFound = 1;
527                            backupMV = *currMV;
528    
529                            switch (iDirection) {
530                            case 1:
531                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,
532                                                                                       backupMV.y, 1);
533                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,
534                                                                                     backupMV.y - iDiamondSize, 5);
535                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,
536                                                                                     backupMV.y - iDiamondSize, 7);
537                                    break;
538                            case 2:
539                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y,
540                                                                                     2);
541                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,
542                                                                                     backupMV.y + iDiamondSize, 6);
543                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,
544                                                                                     backupMV.y + iDiamondSize, 8);
545                                    break;
546    
547                            case 3:
548                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,
549                                                                                     4);
550                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,
551                                                                                     backupMV.y - iDiamondSize, 7);
552                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,
553                                                                                     backupMV.y + iDiamondSize, 8);
554                                    break;
555    
556                            case 4:
557                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize,
558                                                                                     3);
559                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,
560                                                                                     backupMV.y - iDiamondSize, 5);
561                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,
562                                                                                     backupMV.y + iDiamondSize, 6);
563                                    break;
564    
565                            case 5:
566                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize, backupMV.y,
567                                                                                     1);
568                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize,
569                                                                                     3);
570                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,
571                                                                                     backupMV.y - iDiamondSize, 5);
572                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,
573                                                                                     backupMV.y + iDiamondSize, 6);
574                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,
575                                                                                     backupMV.y - iDiamondSize, 7);
576                                    break;
577    
578                            case 6:
579                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y,
580                                                                                     2);
581                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize,
582                                                                                     3);
583    
584                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,
585                                                                                     backupMV.y - iDiamondSize, 5);
586                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,
587                                                                                     backupMV.y + iDiamondSize, 6);
588                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,
589                                                                                     backupMV.y + iDiamondSize, 8);
590    
591                                    break;
592    
593                            case 7:
594                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,
595                                                                                       backupMV.y, 1);
596                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,
597                                                                                     4);
598                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,
599                                                                                     backupMV.y - iDiamondSize, 5);
600                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,
601                                                                                     backupMV.y - iDiamondSize, 7);
602                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,
603                                                                                     backupMV.y + iDiamondSize, 8);
604                                    break;
605    
606                            case 8:
607                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y,
608                                                                                     2);
609                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,
610                                                                                     4);
611                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,
612                                                                                     backupMV.y + iDiamondSize, 6);
613                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,
614                                                                                     backupMV.y - iDiamondSize, 7);
615                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,
616                                                                                     backupMV.y + iDiamondSize, 8);
617                                    break;
618                            default:
619                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize, backupMV.y,
620                                                                                     1);
621                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y,
622                                                                                     2);
623                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize,
624                                                                                     3);
625                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,
626                                                                                     4);
627    
628                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,
629                                                                                     backupMV.y - iDiamondSize, 5);
630                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,
631                                                                                     backupMV.y + iDiamondSize, 6);
632                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,
633                                                                                     backupMV.y - iDiamondSize, 7);
634                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,
635                                                                                     backupMV.y + iDiamondSize, 8);
636                                    break;
637                            }
638                    }
639            } else {
640                    currMV->x = start_x;
641                    currMV->y = start_y;
642            }
643          return iMinSAD;          return iMinSAD;
644  }  }
645    
 #define PMV_HALFPEL16 (PMV_HALFPELDIAMOND16|PMV_HALFPELREFINE16)  
646    
647  int32_t PMVfastSearch16(  int32_t
648                                          const uint8_t * const pRef,  Full16_MainSearch(const uint8_t * const pRef,
649                                          const uint8_t * const pRefH,                                          const uint8_t * const pRefH,
650                                          const uint8_t * const pRefV,                                          const uint8_t * const pRefV,
651                                          const uint8_t * const pRefHV,                                          const uint8_t * const pRefHV,
652                                          const IMAGE * const pCur,                                    const uint8_t * const cur,
653                                          const int x, const int y,                                    const int x,
654                                          const uint32_t MotionFlags,                                    const int y,
655                                          MBParam * const pParam,                                    const int start_x,
656                                          MACROBLOCK * const pMBs,                                    const int start_y,
657                                      int iMinSAD,
658                                          VECTOR * const currMV,                                          VECTOR * const currMV,
659                                          VECTOR * const currPMV)                                    const int center_x,
660                                      const int center_y,
661                                      const int32_t min_dx,
662                                      const int32_t max_dx,
663                                      const int32_t min_dy,
664                                      const int32_t max_dy,
665                                      const int32_t iEdgedWidth,
666                                      const int32_t iDiamondSize,
667                                      const int32_t iFcode,
668                                      const int32_t iQuant,
669                                      int iFound)
670  {  {
671          const uint32_t iWcount = pParam->mb_width;          int32_t iSAD;
672          const int32_t iFcode = pParam->fixed_code;          int32_t dx, dy;
673          const int32_t iQuant = pParam->quant;          VECTOR backupMV;
         const int32_t iWidth = pParam->width;  
         const int32_t iHeight = pParam->height;  
         const int32_t iEdgedWidth = pParam->edged_width;  
   
         const uint8_t * cur = pCur->y + x*16 + y*16*iEdgedWidth;  
   
         int32_t iDiamondSize;  
   
         int32_t min_dx;  
         int32_t max_dx;  
         int32_t min_dy;  
         int32_t max_dy;  
674    
675          int32_t iFound;          backupMV.x = start_x;
676            backupMV.y = start_y;
677    
678          VECTOR newMV;          for (dx = min_dx; dx <= max_dx; dx += iDiamondSize)
679          VECTOR backupMV;        /* just for PMVFAST */                  for (dy = min_dy; dy <= max_dy; dy += iDiamondSize)
680                            NOCHECK_MV16_CANDIDATE(dx, dy);
681    
682          VECTOR pmv[4];          return iMinSAD;
683          int32_t psad[4];  }
684    
685          MACROBLOCK * const pMB = pMBs + x + y * iWcount;  int32_t
686    AdvDiamond16_MainSearch(const uint8_t * const pRef,
687                                                    const uint8_t * const pRefH,
688                                                    const uint8_t * const pRefV,
689                                                    const uint8_t * const pRefHV,
690                                                    const uint8_t * const cur,
691                                                    const int x,
692                                                    const int y,
693                                                    const int start_xi,
694                                                    const int start_yi,
695                                                    int iMinSAD,
696                                                    VECTOR * const currMV,
697                                                    const int center_x,
698                                                    const int center_y,
699                                                    const int32_t min_dx,
700                                                    const int32_t max_dx,
701                                                    const int32_t min_dy,
702                                                    const int32_t max_dy,
703                                                    const int32_t iEdgedWidth,
704                                                    const int32_t iDiamondSize,
705                                                    const int32_t iFcode,
706                                                    const int32_t iQuant,
707                                                    int iDirection)
708    {
709    
710          static int32_t threshA,threshB;          int32_t iSAD;
711          int32_t bPredEq;          int start_x = start_xi, start_y = start_yi;
         int32_t iMinSAD,iSAD;  
712    
713  /* Get maximum range */  /* directions: 1 - left (x-1); 2 - right (x+1), 4 - up (y-1); 8 - down (y+1) */
         get_range(&min_dx, &max_dx, &min_dy, &max_dy,  
                         x, y, 16, iWidth, iHeight, iFcode);  
714    
715  /* we work with abs. MVs, not relative to prediction, so get_range is called relative to 0,0 */          if (iDirection) {
716                    CHECK_MV16_CANDIDATE(start_x - iDiamondSize, start_y);
717                    CHECK_MV16_CANDIDATE(start_x + iDiamondSize, start_y);
718                    CHECK_MV16_CANDIDATE(start_x, start_y - iDiamondSize);
719                    CHECK_MV16_CANDIDATE(start_x, start_y + iDiamondSize);
720            } else {
721                    int bDirection = 1 + 2 + 4 + 8;
722    
723                    do {
724                            iDirection = 0;
725                            if (bDirection & 1)     //we only want to check left if we came from the right (our last motion was to the left, up-left or down-left)
726                                    CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize, start_y, 1);
727    
728                            if (bDirection & 2)
729                                    CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize, start_y, 2);
730    
731                            if (bDirection & 4)
732                                    CHECK_MV16_CANDIDATE_DIR(start_x, start_y - iDiamondSize, 4);
733    
734                            if (bDirection & 8)
735                                    CHECK_MV16_CANDIDATE_DIR(start_x, start_y + iDiamondSize, 8);
736    
737                            /* now we're doing diagonal checks near our candidate */
738    
739                            if (iDirection)         //checking if anything found
740                            {
741                                    bDirection = iDirection;
742                                    iDirection = 0;
743                                    start_x = currMV->x;
744                                    start_y = currMV->y;
745                                    if (bDirection & 3)     //our candidate is left or right
746                                    {
747                                            CHECK_MV16_CANDIDATE_DIR(start_x, start_y + iDiamondSize, 8);
748                                            CHECK_MV16_CANDIDATE_DIR(start_x, start_y - iDiamondSize, 4);
749                                    } else                  // what remains here is up or down
750                                    {
751                                            CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize, start_y, 2);
752                                            CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize, start_y, 1);
753                                    }
754    
755                                    if (iDirection) {
756                                            bDirection += iDirection;
757                                            start_x = currMV->x;
758                                            start_y = currMV->y;
759                                    }
760                            } else                          //about to quit, eh? not so fast....
761                            {
762                                    switch (bDirection) {
763                                    case 2:
764                                            CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,
765                                                                                             start_y - iDiamondSize, 2 + 4);
766                                            CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,
767                                                                                             start_y + iDiamondSize, 2 + 8);
768                                            break;
769                                    case 1:
770    
771                                            CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,
772                                                                                             start_y - iDiamondSize, 1 + 4);
773                                            CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,
774                                                                                             start_y + iDiamondSize, 1 + 8);
775                                            break;
776                                    case 2 + 4:
777                                            CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,
778                                                                                             start_y - iDiamondSize, 1 + 4);
779                                            CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,
780                                                                                             start_y - iDiamondSize, 2 + 4);
781                                            CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,
782                                                                                             start_y + iDiamondSize, 2 + 8);
783                                            break;
784                                    case 4:
785                                            CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,
786                                                                                             start_y - iDiamondSize, 2 + 4);
787                                            CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,
788                                                                                             start_y - iDiamondSize, 1 + 4);
789                                            break;
790                                    case 8:
791                                            CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,
792                                                                                             start_y + iDiamondSize, 2 + 8);
793                                            CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,
794                                                                                             start_y + iDiamondSize, 1 + 8);
795                                            break;
796                                    case 1 + 4:
797                                            CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,
798                                                                                             start_y + iDiamondSize, 1 + 8);
799                                            CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,
800                                                                                             start_y - iDiamondSize, 1 + 4);
801                                            CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,
802                                                                                             start_y - iDiamondSize, 2 + 4);
803                                            break;
804                                    case 2 + 8:
805                                            CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,
806                                                                                             start_y - iDiamondSize, 1 + 4);
807                                            CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,
808                                                                                             start_y + iDiamondSize, 1 + 8);
809                                            CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,
810                                                                                             start_y + iDiamondSize, 2 + 8);
811                                            break;
812                                    case 1 + 8:
813                                            CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,
814                                                                                             start_y - iDiamondSize, 2 + 4);
815                                            CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,
816                                                                                             start_y + iDiamondSize, 2 + 8);
817                                            CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,
818                                                                                             start_y + iDiamondSize, 1 + 8);
819                                            break;
820                                    default:                //1+2+4+8 == we didn't find anything at all
821                                            CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,
822                                                                                             start_y - iDiamondSize, 1 + 4);
823                                            CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,
824                                                                                             start_y + iDiamondSize, 1 + 8);
825                                            CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,
826                                                                                             start_y - iDiamondSize, 2 + 4);
827                                            CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,
828                                                                                             start_y + iDiamondSize, 2 + 8);
829                                            break;
830                                    }
831                                    if (!iDirection)
832                                            break;          //ok, the end. really
833                                    else {
834                                            bDirection = iDirection;
835                                            start_x = currMV->x;
836                                            start_y = currMV->y;
837                                    }
838                            }
839                    }
840                    while (1);                              //forever
841            }
842    
843          if (!(MotionFlags & PMV_HALFPEL16 ))          return iMinSAD;
844          { min_dx = EVEN(min_dx);  }
           max_dx = EVEN(max_dx);  
           min_dy = EVEN(min_dy);  
           max_dy = EVEN(max_dy);  
         }               /* because we might use something like IF (dx>max_dx) THEN dx=max_dx; */  
845    
846    /* Disabled bframe specific code */
847    #if 0
848    
849          bPredEq  = get_pmvdata(pMBs, x, y, iWcount, 0, pmv, psad);  #define CHECK_MV16_F_INTERPOL(X,Y) { \
850      if ( ((X) <= f_max_dx) && ((X) >= f_min_dx) \
851        && ((Y) <= f_max_dy) && ((Y) >= f_min_dy) ) \
852      { \
853        iSAD = sad16bi( cur, \
854                            get_ref(f_pRef, f_pRefH, f_pRefV, f_pRefHV, x, y, 16, X, Y, iEdgedWidth),       \
855                            get_ref(b_pRef, b_pRefH, b_pRefV, b_pRefHV, x, y, 16, b_currMV->x, b_currMV->y, iEdgedWidth),   \
856                            iEdgedWidth); \
857        iSAD += calc_delta_16((X) - f_center_x, (Y) - f_center_y, (uint8_t)f_iFcode, iQuant);\
858        iSAD += calc_delta_16(b_currMV->x - b_center_x, b_currMV->y - b_center_y, (uint8_t)b_iFcode, iQuant);\
859        if (iSAD < iMinSAD) \
860        {  iMinSAD=iSAD; f_currMV->x=(X); f_currMV->y=(Y); } } \
861    }
862    
863          if ((x==0) && (y==0) )  #define CHECK_MV16_F_INTERPOL_FOUND(X,Y) { \
864          {    if ( ((X) <= f_max_dx) && ((X) >= f_min_dx) \
865                  threshA =  512;      && ((Y) <= f_max_dy) && ((Y) >= f_min_dy) ) \
866                  threshB = 1024;    { \
867        iSAD = sad16bi( cur, \
868                            get_ref(f_pRef, f_pRefH, f_pRefV, f_pRefHV, x, y, 16, X, Y, iEdgedWidth),       \
869                            get_ref(b_pRef, b_pRefH, b_pRefV, b_pRefHV, x, y, 16, b_currMV->x, b_currMV->y, iEdgedWidth),   \
870                            iEdgedWidth); \
871        iSAD += calc_delta_16((X) - f_center_x, (Y) - f_center_y, (uint8_t)f_iFcode, iQuant);\
872        iSAD += calc_delta_16(b_currMV->x - b_center_x, b_currMV->y - b_center_y, (uint8_t)b_iFcode, iQuant);\
873        if (iSAD < iMinSAD) \
874        {  iMinSAD=iSAD; f_currMV->x=(X); f_currMV->y=(Y); iFound=0;} } \
875    }
876    
877    #define CHECK_MV16_B_INTERPOL(X,Y) { \
878      if ( ((X) <= b_max_dx) && ((X) >= b_min_dx) \
879        && ((Y) <= b_max_dy) && ((Y) >= b_min_dy) ) \
880      { \
881        iSAD = sad16bi( cur, \
882                            get_ref(f_pRef, f_pRefH, f_pRefV, f_pRefHV, x, y, 16, f_currMV->x, f_currMV->y, iEdgedWidth),   \
883                            get_ref(b_pRef, b_pRefH, b_pRefV, b_pRefHV, x, y, 16, X, Y, iEdgedWidth),       \
884                            iEdgedWidth); \
885        iSAD += calc_delta_16(f_currMV->x - f_center_x, f_currMV->y - f_center_y, (uint8_t)f_iFcode, iQuant);\
886        iSAD += calc_delta_16((X) - b_center_x, (Y) - b_center_y, (uint8_t)b_iFcode, iQuant);\
887        if (iSAD < iMinSAD) \
888        {  iMinSAD=iSAD; b_currMV->x=(X); b_currMV->y=(Y); } } \
889          }          }
890          else  
891          {  #define CHECK_MV16_B_INTERPOL_FOUND(X,Y) { \
892                  threshA = psad[0];    if ( ((X) <= b_max_dx) && ((X) >= b_min_dx) \
893                  threshB = threshA+256;      && ((Y) <= b_max_dy) && ((Y) >= b_min_dy) ) \
894                  if (threshA< 512) threshA =  512;    { \
895                  if (threshA>1024) threshA = 1024;      iSAD = sad16bi( cur, \
896                  if (threshB>1792) threshB = 1792;                          get_ref(f_pRef, f_pRefH, f_pRefV, f_pRefHV, x, y, 16, f_currMV->x, f_currMV->y, iEdgedWidth),   \
897                            get_ref(b_pRef, b_pRefH, b_pRefV, b_pRefHV, x, y, 16, X, Y, iEdgedWidth),       \
898                            iEdgedWidth); \
899        iSAD += calc_delta_16(f_currMV->x - f_center_x, f_currMV->y - f_center_y, (uint8_t)f_iFcode, iQuant);\
900        iSAD += calc_delta_16((X) - b_center_x, (Y) - b_center_y, (uint8_t)b_iFcode, iQuant);\
901        if (iSAD < iMinSAD) \
902        {  iMinSAD=iSAD; b_currMV->x=(X); b_currMV->y=(Y); iFound=0;} } \
903          }          }
904    
         iFound=0;  
905    
906  /* Step 2: Calculate Distance= |MedianMVX| + |MedianMVY| where MedianMV is the motion  int32_t
907          vector of the median.  Diamond16_InterpolMainSearch(const uint8_t * const f_pRef,
908          If PredEq=1 and MVpredicted = Previous Frame MV, set Found=2                                                           const uint8_t * const f_pRefH,
909  */                                                           const uint8_t * const f_pRefV,
910                                                             const uint8_t * const f_pRefHV,
911    
912          if ((bPredEq) && (MVequal(pmv[0],pMB->mvs[0]) ) )                                                           const uint8_t * const cur,
                 iFound=2;  
913    
914  /* Step 3: If Distance>0 or thresb<1536 or PredEq=1 Select small Diamond Search.                                                           const uint8_t * const b_pRef,
915          Otherwise select large Diamond Search.                                                           const uint8_t * const b_pRefH,
916  */                                                           const uint8_t * const b_pRefV,
917                                                             const uint8_t * const b_pRefHV,
918    
919                                                             const int x,
920                                                             const int y,
921    
922                                                             const int f_start_x,
923                                                             const int f_start_y,
924                                                             const int b_start_x,
925                                                             const int b_start_y,
926    
927                                                             int iMinSAD,
928                                                             VECTOR * const f_currMV,
929                                                             VECTOR * const b_currMV,
930    
931                                                             const int f_center_x,
932                                                             const int f_center_y,
933                                                             const int b_center_x,
934                                                             const int b_center_y,
935    
936                                                             const int32_t f_min_dx,
937                                                             const int32_t f_max_dx,
938                                                             const int32_t f_min_dy,
939                                                             const int32_t f_max_dy,
940    
941                                                             const int32_t b_min_dx,
942                                                             const int32_t b_max_dx,
943                                                             const int32_t b_min_dy,
944                                                             const int32_t b_max_dy,
945    
946          if ( (pmv[0].x != 0) || (pmv[0].y != 0) || (threshB<1536) || (bPredEq) )                                                           const int32_t iEdgedWidth,
947                  iDiamondSize=1; // halfpel!                                                           const int32_t iDiamondSize,
         else  
                 iDiamondSize=2; // halfpel!  
948    
949          if (!(MotionFlags & PMV_HALFPELDIAMOND16) )                                                           const int32_t f_iFcode,
950                  iDiamondSize*=2;                                                           const int32_t b_iFcode,
951    
952  /* Step 4: Calculate SAD around the Median prediction.                                                           const int32_t iQuant,
953          MinSAD=SAD                                                           int iFound)
954          If Motion Vector equal to Previous frame motion vector  {
955                  and MinSAD<PrevFrmSAD goto Step 10.  /* Do a diamond search around given starting point, return SAD of best */
956    
957            int32_t iSAD;
958    
959            VECTOR f_backupMV;
960            VECTOR b_backupMV;
961    
962            f_currMV->x = f_start_x;
963            f_currMV->y = f_start_y;
964            b_currMV->x = b_start_x;
965            b_currMV->y = b_start_y;
966    
967            do
968            {
969                    iFound = 1;
970    
971                    f_backupMV = *f_currMV;
972    
973                    CHECK_MV16_F_INTERPOL_FOUND(f_backupMV.x - iDiamondSize, f_backupMV.y);
974                    CHECK_MV16_F_INTERPOL_FOUND(f_backupMV.x + iDiamondSize, f_backupMV.y);
975                    CHECK_MV16_F_INTERPOL_FOUND(f_backupMV.x, f_backupMV.y - iDiamondSize);
976                    CHECK_MV16_F_INTERPOL_FOUND(f_backupMV.x, f_backupMV.y + iDiamondSize);
977    
978                    b_backupMV = *b_currMV;
979    
980                    CHECK_MV16_B_INTERPOL_FOUND(b_backupMV.x - iDiamondSize, b_backupMV.y);
981                    CHECK_MV16_B_INTERPOL_FOUND(b_backupMV.x + iDiamondSize, b_backupMV.y);
982                    CHECK_MV16_B_INTERPOL_FOUND(b_backupMV.x, b_backupMV.y - iDiamondSize);
983                    CHECK_MV16_B_INTERPOL_FOUND(b_backupMV.x, b_backupMV.y + iDiamondSize);
984    
985            } while (!iFound);
986    
987            return iMinSAD;
988    }
989    
990    /* Sorry, these MACROS really got too large... I'll turn them into function soon! */
991    
992    #define CHECK_MV16_DIRECT_FOUND(X,Y) \
993            if ( (X)>=(-32) && (X)<=(31) && ((Y)>=-32) && ((Y)<=31) ) \
994            { int k;\
995            VECTOR mvs,b_mvs;       \
996            iSAD = 0;\
997            for (k = 0; k < 4; k++) {       \
998                                            mvs.x = (int32_t) ((TRB * directmv[k].x) / TRD + (X));          \
999                        b_mvs.x = (int32_t) (((X) == 0)                                                     \
1000                                                                                    ? ((TRB - TRD) * directmv[k].x) / TRD   \
1001                                                : mvs.x - directmv[k].x);                           \
1002                                                                                                                                                                    \
1003                        mvs.y = (int32_t) ((TRB * directmv[k].y) / TRD + (Y));              \
1004                            b_mvs.y = (int32_t) (((Y) == 0)                                                         \
1005                                                                                    ? ((TRB - TRD) * directmv[k].y) / TRD   \
1006                                                : mvs.y - directmv[k].y);                           \
1007                                                                                                                                                                    \
1008      if ( (mvs.x <= max_dx) && (mvs.x >= min_dx) \
1009        && (mvs.y <= max_dy) && (mvs.y >= min_dy)  \
1010            && (b_mvs.x <= max_dx) && (b_mvs.x >= min_dx)  \
1011        && (b_mvs.y <= max_dy) && (b_mvs.y >= min_dy) ) { \
1012                iSAD += sad8bi( cur + 8*(k&1) + 8*(k>>1)*iEdgedWidth,                                                                                                       \
1013                            get_ref(f_pRef, f_pRefH, f_pRefV, f_pRefHV, 2*x+(k&1), 2*y+(k>>1), 8, \
1014                                            mvs.x, mvs.y, iEdgedWidth),                                                             \
1015                            get_ref(b_pRef, b_pRefH, b_pRefV, b_pRefHV, 2*x+(k&1), 2*y+(k>>1), 8, \
1016                                            b_mvs.x, b_mvs.y, iEdgedWidth),                                                         \
1017                            iEdgedWidth); \
1018                    }       \
1019            else    \
1020                    iSAD = 65535;   \
1021            } \
1022            iSAD += calc_delta_16((X),(Y), 1, iQuant);\
1023            if (iSAD < iMinSAD) \
1024                {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iFound=0; } \
1025    }
1026    
1027    
1028    
1029    int32_t
1030    Diamond16_DirectMainSearch(
1031                                            const uint8_t * const f_pRef,
1032                                            const uint8_t * const f_pRefH,
1033                                            const uint8_t * const f_pRefV,
1034                                            const uint8_t * const f_pRefHV,
1035    
1036                                            const uint8_t * const cur,
1037    
1038                                            const uint8_t * const b_pRef,
1039                                            const uint8_t * const b_pRefH,
1040                                            const uint8_t * const b_pRefV,
1041                                            const uint8_t * const b_pRefHV,
1042    
1043                                            const int x,
1044                                            const int y,
1045    
1046                                            const int TRB,
1047                                            const int TRD,
1048    
1049                                        const int start_x,
1050                                        const int start_y,
1051    
1052                                        int iMinSAD,
1053                                        VECTOR * const currMV,
1054                                            const VECTOR * const directmv,
1055    
1056                                        const int32_t min_dx,
1057                                            const int32_t max_dx,
1058                                            const int32_t min_dy,
1059                                            const int32_t max_dy,
1060    
1061                                            const int32_t iEdgedWidth,
1062                                            const int32_t iDiamondSize,
1063    
1064                                            const int32_t iQuant,
1065                                            int iFound)
1066    {
1067    /* Do a diamond search around given starting point, return SAD of best */
1068    
1069            int32_t iSAD;
1070    
1071            VECTOR backupMV;
1072    
1073            currMV->x = start_x;
1074            currMV->y = start_y;
1075    
1076    /* It's one search with full Diamond pattern, and only 3 of 4 for all following diamonds */
1077    
1078            do
1079            {
1080                    iFound = 1;
1081    
1082                    backupMV = *currMV;
1083    
1084                    CHECK_MV16_DIRECT_FOUND(backupMV.x - iDiamondSize, backupMV.y);
1085                    CHECK_MV16_DIRECT_FOUND(backupMV.x + iDiamondSize, backupMV.y);
1086                    CHECK_MV16_DIRECT_FOUND(backupMV.x, backupMV.y - iDiamondSize);
1087                    CHECK_MV16_DIRECT_FOUND(backupMV.x, backupMV.y + iDiamondSize);
1088    
1089            } while (!iFound);
1090    
1091            return iMinSAD;
1092    }
1093    
1094    #endif /* 0 */
1095    
1096    int32_t
1097    AdvDiamond8_MainSearch(const uint8_t * const pRef,
1098                                               const uint8_t * const pRefH,
1099                                               const uint8_t * const pRefV,
1100                                               const uint8_t * const pRefHV,
1101                                               const uint8_t * const cur,
1102                                               const int x,
1103                                               const int y,
1104                                               const int start_xi,
1105                                               const int start_yi,
1106                                               int iMinSAD,
1107                                               VECTOR * const currMV,
1108                                               const int center_x,
1109                                               const int center_y,
1110                                               const int32_t min_dx,
1111                                               const int32_t max_dx,
1112                                               const int32_t min_dy,
1113                                               const int32_t max_dy,
1114                                               const int32_t iEdgedWidth,
1115                                               const int32_t iDiamondSize,
1116                                               const int32_t iFcode,
1117                                               const int32_t iQuant,
1118                                               int iDirection)
1119    {
1120    
1121            int32_t iSAD;
1122            int start_x = start_xi, start_y = start_yi;
1123    
1124    /* directions: 1 - left (x-1); 2 - right (x+1), 4 - up (y-1); 8 - down (y+1) */
1125    
1126            if (iDirection) {
1127                    CHECK_MV8_CANDIDATE(start_x - iDiamondSize, start_y);
1128                    CHECK_MV8_CANDIDATE(start_x + iDiamondSize, start_y);
1129                    CHECK_MV8_CANDIDATE(start_x, start_y - iDiamondSize);
1130                    CHECK_MV8_CANDIDATE(start_x, start_y + iDiamondSize);
1131            } else {
1132                    int bDirection = 1 + 2 + 4 + 8;
1133    
1134                    do {
1135                            iDirection = 0;
1136                            if (bDirection & 1)     //we only want to check left if we came from the right (our last motion was to the left, up-left or down-left)
1137                                    CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize, start_y, 1);
1138    
1139                            if (bDirection & 2)
1140                                    CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize, start_y, 2);
1141    
1142                            if (bDirection & 4)
1143                                    CHECK_MV8_CANDIDATE_DIR(start_x, start_y - iDiamondSize, 4);
1144    
1145                            if (bDirection & 8)
1146                                    CHECK_MV8_CANDIDATE_DIR(start_x, start_y + iDiamondSize, 8);
1147    
1148                            /* now we're doing diagonal checks near our candidate */
1149    
1150                            if (iDirection)         //checking if anything found
1151                            {
1152                                    bDirection = iDirection;
1153                                    iDirection = 0;
1154                                    start_x = currMV->x;
1155                                    start_y = currMV->y;
1156                                    if (bDirection & 3)     //our candidate is left or right
1157                                    {
1158                                            CHECK_MV8_CANDIDATE_DIR(start_x, start_y + iDiamondSize, 8);
1159                                            CHECK_MV8_CANDIDATE_DIR(start_x, start_y - iDiamondSize, 4);
1160                                    } else                  // what remains here is up or down
1161                                    {
1162                                            CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize, start_y, 2);
1163                                            CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize, start_y, 1);
1164                                    }
1165    
1166                                    if (iDirection) {
1167                                            bDirection += iDirection;
1168                                            start_x = currMV->x;
1169                                            start_y = currMV->y;
1170                                    }
1171                            } else                          //about to quit, eh? not so fast....
1172                            {
1173                                    switch (bDirection) {
1174                                    case 2:
1175                                            CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,
1176                                                                                            start_y - iDiamondSize, 2 + 4);
1177                                            CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,
1178                                                                                            start_y + iDiamondSize, 2 + 8);
1179                                            break;
1180                                    case 1:
1181                                            CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,
1182                                                                                            start_y - iDiamondSize, 1 + 4);
1183                                            CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,
1184                                                                                            start_y + iDiamondSize, 1 + 8);
1185                                            break;
1186                                    case 2 + 4:
1187                                            CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,
1188                                                                                            start_y - iDiamondSize, 1 + 4);
1189                                            CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,
1190                                                                                            start_y - iDiamondSize, 2 + 4);
1191                                            CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,
1192                                                                                            start_y + iDiamondSize, 2 + 8);
1193                                            break;
1194                                    case 4:
1195                                            CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,
1196                                                                                            start_y - iDiamondSize, 2 + 4);
1197                                            CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,
1198                                                                                            start_y - iDiamondSize, 1 + 4);
1199                                            break;
1200                                    case 8:
1201                                            CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,
1202                                                                                            start_y + iDiamondSize, 2 + 8);
1203                                            CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,
1204                                                                                            start_y + iDiamondSize, 1 + 8);
1205                                            break;
1206                                    case 1 + 4:
1207                                            CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,
1208                                                                                            start_y + iDiamondSize, 1 + 8);
1209                                            CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,
1210                                                                                            start_y - iDiamondSize, 1 + 4);
1211                                            CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,
1212                                                                                            start_y - iDiamondSize, 2 + 4);
1213                                            break;
1214                                    case 2 + 8:
1215                                            CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,
1216                                                                                            start_y - iDiamondSize, 1 + 4);
1217                                            CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,
1218                                                                                            start_y + iDiamondSize, 1 + 8);
1219                                            CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,
1220                                                                                            start_y + iDiamondSize, 2 + 8);
1221                                            break;
1222                                    case 1 + 8:
1223                                            CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,
1224                                                                                            start_y - iDiamondSize, 2 + 4);
1225                                            CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,
1226                                                                                            start_y + iDiamondSize, 2 + 8);
1227                                            CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,
1228                                                                                            start_y + iDiamondSize, 1 + 8);
1229                                            break;
1230                                    default:                //1+2+4+8 == we didn't find anything at all
1231                                            CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,
1232                                                                                            start_y - iDiamondSize, 1 + 4);
1233                                            CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,
1234                                                                                            start_y + iDiamondSize, 1 + 8);
1235                                            CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,
1236                                                                                            start_y - iDiamondSize, 2 + 4);
1237                                            CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,
1238                                                                                            start_y + iDiamondSize, 2 + 8);
1239                                            break;
1240                                    }
1241                                    if (!(iDirection))
1242                                            break;          //ok, the end. really
1243                                    else {
1244                                            bDirection = iDirection;
1245                                            start_x = currMV->x;
1246                                            start_y = currMV->y;
1247                                    }
1248                            }
1249                    }
1250                    while (1);                              //forever
1251            }
1252            return iMinSAD;
1253    }
1254    
1255    
1256    int32_t
1257    Full8_MainSearch(const uint8_t * const pRef,
1258                                     const uint8_t * const pRefH,
1259                                     const uint8_t * const pRefV,
1260                                     const uint8_t * const pRefHV,
1261                                     const uint8_t * const cur,
1262                                     const int x,
1263                                     const int y,
1264                               const int start_x,
1265                               const int start_y,
1266                               int iMinSAD,
1267                               VECTOR * const currMV,
1268                               const int center_x,
1269                               const int center_y,
1270                                     const int32_t min_dx,
1271                                     const int32_t max_dx,
1272                                     const int32_t min_dy,
1273                                     const int32_t max_dy,
1274                                     const int32_t iEdgedWidth,
1275                                     const int32_t iDiamondSize,
1276                                     const int32_t iFcode,
1277                                     const int32_t iQuant,
1278                                     int iFound)
1279    {
1280            int32_t iSAD;
1281            int32_t dx, dy;
1282            VECTOR backupMV;
1283    
1284            backupMV.x = start_x;
1285            backupMV.y = start_y;
1286    
1287            for (dx = min_dx; dx <= max_dx; dx += iDiamondSize)
1288                    for (dy = min_dy; dy <= max_dy; dy += iDiamondSize)
1289                            NOCHECK_MV8_CANDIDATE(dx, dy);
1290    
1291            return iMinSAD;
1292    }
1293    
1294    Halfpel8_RefineFuncPtr Halfpel8_Refine;
1295    
1296    int32_t
1297    Halfpel16_Refine(const uint8_t * const pRef,
1298                                     const uint8_t * const pRefH,
1299                                     const uint8_t * const pRefV,
1300                                     const uint8_t * const pRefHV,
1301                                     const uint8_t * const cur,
1302                                     const int x,
1303                                     const int y,
1304                                     VECTOR * const currMV,
1305                                     int32_t iMinSAD,
1306                               const int center_x,
1307                               const int center_y,
1308                                     const int32_t min_dx,
1309                                     const int32_t max_dx,
1310                                     const int32_t min_dy,
1311                                     const int32_t max_dy,
1312                                     const int32_t iFcode,
1313                                     const int32_t iQuant,
1314                                     const int32_t iEdgedWidth)
1315    {
1316    /* Do a half-pel refinement (or rather a "smallest possible amount" refinement) */
1317    
1318            int32_t iSAD;
1319            VECTOR backupMV = *currMV;
1320    
1321            CHECK_MV16_CANDIDATE(backupMV.x - 1, backupMV.y - 1);
1322            CHECK_MV16_CANDIDATE(backupMV.x, backupMV.y - 1);
1323            CHECK_MV16_CANDIDATE(backupMV.x + 1, backupMV.y - 1);
1324            CHECK_MV16_CANDIDATE(backupMV.x - 1, backupMV.y);
1325            CHECK_MV16_CANDIDATE(backupMV.x + 1, backupMV.y);
1326            CHECK_MV16_CANDIDATE(backupMV.x - 1, backupMV.y + 1);
1327            CHECK_MV16_CANDIDATE(backupMV.x, backupMV.y + 1);
1328            CHECK_MV16_CANDIDATE(backupMV.x + 1, backupMV.y + 1);
1329    
1330            return iMinSAD;
1331    }
1332    
1333    #define PMV_HALFPEL16 (PMV_HALFPELDIAMOND16|PMV_HALFPELREFINE16)
1334    
1335    
1336    
1337    int32_t
1338    PMVfastSearch16(const uint8_t * const pRef,
1339                                    const uint8_t * const pRefH,
1340                                    const uint8_t * const pRefV,
1341                                    const uint8_t * const pRefHV,
1342                                    const IMAGE * const pCur,
1343                                    const int x,
1344                                    const int y,
1345                                    const int start_x,      /* start is searched first, so it should contain the most */
1346                                    const int start_y,  /* likely motion vector for this block */
1347                                    const int center_x,     /* center is from where length of MVs is measured */
1348                                    const int center_y,
1349                                    const uint32_t MotionFlags,
1350                                    const uint32_t iQuant,
1351                                    const uint32_t iFcode,
1352                                    const MBParam * const pParam,
1353                                    const MACROBLOCK * const pMBs,
1354                                    const MACROBLOCK * const prevMBs,
1355                                    VECTOR * const currMV,
1356                                    VECTOR * const currPMV)
1357    {
1358            const uint32_t iWcount = pParam->mb_width;
1359            const int32_t iWidth = pParam->width;
1360            const int32_t iHeight = pParam->height;
1361            const int32_t iEdgedWidth = pParam->edged_width;
1362    
1363            const uint8_t *cur = pCur->y + x * 16 + y * 16 * iEdgedWidth;
1364    
1365            int32_t iDiamondSize;
1366    
1367            int32_t min_dx;
1368            int32_t max_dx;
1369            int32_t min_dy;
1370            int32_t max_dy;
1371    
1372            int32_t iFound;
1373    
1374            VECTOR newMV;
1375            VECTOR backupMV;                        /* just for PMVFAST */
1376    
1377            VECTOR pmv[4];
1378            int32_t psad[4];
1379    
1380            MainSearch16FuncPtr MainSearchPtr;
1381    
1382            const MACROBLOCK *const prevMB = prevMBs + x + y * iWcount;
1383    
1384            int32_t threshA, threshB;
1385            int32_t bPredEq;
1386            int32_t iMinSAD, iSAD;
1387    
1388    /* Get maximum range */
1389            get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 16, iWidth, iHeight,
1390                              iFcode);
1391    
1392    /* we work with abs. MVs, not relative to prediction, so get_range is called relative to 0,0 */
1393    
1394            if (!(MotionFlags & PMV_HALFPEL16)) {
1395                    min_dx = EVEN(min_dx);
1396                    max_dx = EVEN(max_dx);
1397                    min_dy = EVEN(min_dy);
1398                    max_dy = EVEN(max_dy);
1399            }
1400    
1401            /* because we might use something like IF (dx>max_dx) THEN dx=max_dx; */
1402            bPredEq = get_pmvdata2(pMBs, iWcount, 0, x, y, 0, pmv, psad);
1403    
1404            if ((x == 0) && (y == 0)) {
1405                    threshA = 512;
1406                    threshB = 1024;
1407            } else {
1408                    threshA = psad[0];
1409                    threshB = threshA + 256;
1410                    if (threshA < 512)
1411                            threshA = 512;
1412                    if (threshA > 1024)
1413                            threshA = 1024;
1414                    if (threshB > 1792)
1415                            threshB = 1792;
1416            }
1417    
1418            iFound = 0;
1419    
1420    /* Step 4: Calculate SAD around the Median prediction.
1421       MinSAD=SAD
1422       If Motion Vector equal to Previous frame motion vector
1423       and MinSAD<PrevFrmSAD goto Step 10.
1424       If SAD<=256 goto Step 10.
1425    */
1426    
1427            currMV->x = start_x;
1428            currMV->y = start_y;
1429    
1430            if (!(MotionFlags & PMV_HALFPEL16)) {   /* This should NOT be necessary! */
1431                    currMV->x = EVEN(currMV->x);
1432                    currMV->y = EVEN(currMV->y);
1433            }
1434    
1435            if (currMV->x > max_dx) {
1436                    currMV->x = max_dx;
1437            }
1438            if (currMV->x < min_dx) {
1439                    currMV->x = min_dx;
1440            }
1441            if (currMV->y > max_dy) {
1442                    currMV->y = max_dy;
1443            }
1444            if (currMV->y < min_dy) {
1445                    currMV->y = min_dy;
1446            }
1447    
1448            iMinSAD =
1449                    sad16(cur,
1450                              get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 16, currMV,
1451                                                     iEdgedWidth), iEdgedWidth, MV_MAX_ERROR);
1452            iMinSAD +=
1453                    calc_delta_16(currMV->x - center_x, currMV->y - center_y,
1454                                              (uint8_t) iFcode, iQuant);
1455    
1456            if ((iMinSAD < 256) ||
1457                    ((MVequal(*currMV, prevMB->mvs[0])) &&
1458                     ((int32_t) iMinSAD < prevMB->sad16))) {
1459                    if (iMinSAD < (int)(2 * iQuant))        // high chances for SKIP-mode
1460                    {
1461                            if (!MVzero(*currMV)) {
1462                                    iMinSAD += MV16_00_BIAS;
1463                                    CHECK_MV16_ZERO;        // (0,0) saves space for letterboxed pictures
1464                                    iMinSAD -= MV16_00_BIAS;
1465                            }
1466                    }
1467    
1468                    if (MotionFlags & PMV_QUICKSTOP16)
1469                            goto PMVfast16_Terminate_without_Refine;
1470                    if (MotionFlags & PMV_EARLYSTOP16)
1471                            goto PMVfast16_Terminate_with_Refine;
1472            }
1473    
1474    
1475    /* Step 2 (lazy eval): Calculate Distance= |MedianMVX| + |MedianMVY| where MedianMV is the motion
1476       vector of the median.
1477       If PredEq=1 and MVpredicted = Previous Frame MV, set Found=2
1478    */
1479    
1480            if ((bPredEq) && (MVequal(pmv[0], prevMB->mvs[0])))
1481                    iFound = 2;
1482    
1483    /* Step 3 (lazy eval): If Distance>0 or thresb<1536 or PredEq=1 Select small Diamond Search.
1484       Otherwise select large Diamond Search.
1485    */
1486    
1487            if ((!MVzero(pmv[0])) || (threshB < 1536) || (bPredEq))
1488                    iDiamondSize = 1;               // halfpel!
1489            else
1490                    iDiamondSize = 2;               // halfpel!
1491    
1492            if (!(MotionFlags & PMV_HALFPELDIAMOND16))
1493                    iDiamondSize *= 2;
1494    
1495    /*
1496       Step 5: Calculate SAD for motion vectors taken from left block, top, top-right, and Previous frame block.
1497       Also calculate (0,0) but do not subtract offset.
1498       Let MinSAD be the smallest SAD up to this point.
1499       If MV is (0,0) subtract offset.
1500    */
1501    
1502    // (0,0) is always possible
1503    
1504            if (!MVzero(pmv[0]))
1505                    CHECK_MV16_ZERO;
1506    
1507    // previous frame MV is always possible
1508    
1509            if (!MVzero(prevMB->mvs[0]))
1510                    if (!MVequal(prevMB->mvs[0], pmv[0]))
1511                            CHECK_MV16_CANDIDATE(prevMB->mvs[0].x, prevMB->mvs[0].y);
1512    
1513    // left neighbour, if allowed
1514    
1515            if (!MVzero(pmv[1]))
1516                    if (!MVequal(pmv[1], prevMB->mvs[0]))
1517                            if (!MVequal(pmv[1], pmv[0])) {
1518                                    if (!(MotionFlags & PMV_HALFPEL16)) {
1519                                            pmv[1].x = EVEN(pmv[1].x);
1520                                            pmv[1].y = EVEN(pmv[1].y);
1521                                    }
1522    
1523                                    CHECK_MV16_CANDIDATE(pmv[1].x, pmv[1].y);
1524                            }
1525    // top neighbour, if allowed
1526            if (!MVzero(pmv[2]))
1527                    if (!MVequal(pmv[2], prevMB->mvs[0]))
1528                            if (!MVequal(pmv[2], pmv[0]))
1529                                    if (!MVequal(pmv[2], pmv[1])) {
1530                                            if (!(MotionFlags & PMV_HALFPEL16)) {
1531                                                    pmv[2].x = EVEN(pmv[2].x);
1532                                                    pmv[2].y = EVEN(pmv[2].y);
1533                                            }
1534                                            CHECK_MV16_CANDIDATE(pmv[2].x, pmv[2].y);
1535    
1536    // top right neighbour, if allowed
1537                                            if (!MVzero(pmv[3]))
1538                                                    if (!MVequal(pmv[3], prevMB->mvs[0]))
1539                                                            if (!MVequal(pmv[3], pmv[0]))
1540                                                                    if (!MVequal(pmv[3], pmv[1]))
1541                                                                            if (!MVequal(pmv[3], pmv[2])) {
1542                                                                                    if (!(MotionFlags & PMV_HALFPEL16)) {
1543                                                                                            pmv[3].x = EVEN(pmv[3].x);
1544                                                                                            pmv[3].y = EVEN(pmv[3].y);
1545                                                                                    }
1546                                                                                    CHECK_MV16_CANDIDATE(pmv[3].x,
1547                                                                                                                             pmv[3].y);
1548                                                                            }
1549                                    }
1550    
1551            if ((MVzero(*currMV)) &&
1552                    (!MVzero(pmv[0])) /* && (iMinSAD <= iQuant * 96) */ )
1553                    iMinSAD -= MV16_00_BIAS;
1554    
1555    
1556    /* Step 6: If MinSAD <= thresa goto Step 10.
1557       If Motion Vector equal to Previous frame motion vector and MinSAD<PrevFrmSAD goto Step 10.
1558    */
1559    
1560            if ((iMinSAD <= threshA) ||
1561                    (MVequal(*currMV, prevMB->mvs[0]) &&
1562                     ((int32_t) iMinSAD < prevMB->sad16))) {
1563                    if (MotionFlags & PMV_QUICKSTOP16)
1564                            goto PMVfast16_Terminate_without_Refine;
1565                    if (MotionFlags & PMV_EARLYSTOP16)
1566                            goto PMVfast16_Terminate_with_Refine;
1567            }
1568    
1569    
1570    /************ (Diamond Search)  **************/
1571    /*
1572       Step 7: Perform Diamond search, with either the small or large diamond.
1573       If Found=2 only examine one Diamond pattern, and afterwards goto step 10
1574       Step 8: If small diamond, iterate small diamond search pattern until motion vector lies in the center of the diamond.
1575       If center then goto step 10.
1576       Step 9: If large diamond, iterate large diamond search pattern until motion vector lies in the center.
1577       Refine by using small diamond and goto step 10.
1578    */
1579    
1580            if (MotionFlags & PMV_USESQUARES16)
1581                    MainSearchPtr = Square16_MainSearch;
1582            else if (MotionFlags & PMV_ADVANCEDDIAMOND16)
1583                    MainSearchPtr = AdvDiamond16_MainSearch;
1584            else
1585                    MainSearchPtr = Diamond16_MainSearch;
1586    
1587            backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */
1588    
1589    
1590    /* default: use best prediction as starting point for one call of PMVfast_MainSearch */
1591            iSAD =
1592                    (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,
1593                                                      currMV->x, currMV->y, iMinSAD, &newMV, center_x, center_y,
1594                                                      min_dx, max_dx,
1595                                                      min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode,
1596                                                      iQuant, iFound);
1597    
1598            if (iSAD < iMinSAD) {
1599                    *currMV = newMV;
1600                    iMinSAD = iSAD;
1601            }
1602    
1603            if (MotionFlags & PMV_EXTSEARCH16) {
1604    /* extended: search (up to) two more times: orignal prediction and (0,0) */
1605    
1606                    if (!(MVequal(pmv[0], backupMV))) {
1607                            iSAD =
1608                                    (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,
1609                                                                      center_x, center_y, iMinSAD, &newMV, center_x, center_y,
1610                                                                      min_dx, max_dx, min_dy, max_dy, iEdgedWidth,
1611                                                                      iDiamondSize, iFcode, iQuant, iFound);
1612    
1613                            if (iSAD < iMinSAD) {
1614                                    *currMV = newMV;
1615                                    iMinSAD = iSAD;
1616                            }
1617                    }
1618    
1619                    if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {
1620                            iSAD =
1621                                    (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, 0, 0,
1622                                                                      iMinSAD, &newMV, center_x, center_y,
1623                                                                      min_dx, max_dx, min_dy, max_dy,
1624                                                                      iEdgedWidth, iDiamondSize, iFcode,
1625                                                                      iQuant, iFound);
1626    
1627                            if (iSAD < iMinSAD) {
1628                                    *currMV = newMV;
1629                                    iMinSAD = iSAD;
1630                            }
1631                    }
1632            }
1633    
1634    /*
1635       Step 10:  The motion vector is chosen according to the block corresponding to MinSAD.
1636    */
1637    
1638      PMVfast16_Terminate_with_Refine:
1639            if (MotionFlags & PMV_HALFPELREFINE16)  // perform final half-pel step
1640                    iMinSAD =
1641                            Halfpel16_Refine(pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV,
1642                                                             iMinSAD, center_x, center_y, min_dx, max_dx, min_dy, max_dy,
1643                                                             iFcode, iQuant, iEdgedWidth);
1644    
1645      PMVfast16_Terminate_without_Refine:
1646            currPMV->x = currMV->x - center_x;
1647            currPMV->y = currMV->y - center_y;
1648            return iMinSAD;
1649    }
1650    
1651    
1652    
1653    
1654    
1655    
1656    int32_t
1657    Diamond8_MainSearch(const uint8_t * const pRef,
1658                                            const uint8_t * const pRefH,
1659                                            const uint8_t * const pRefV,
1660                                            const uint8_t * const pRefHV,
1661                                            const uint8_t * const cur,
1662                                            const int x,
1663                                            const int y,
1664                                            const int32_t start_x,
1665                                            const int32_t start_y,
1666                                            int32_t iMinSAD,
1667                                            VECTOR * const currMV,
1668                                            const int center_x,
1669                                            const int center_y,
1670                                            const int32_t min_dx,
1671                                            const int32_t max_dx,
1672                                            const int32_t min_dy,
1673                                            const int32_t max_dy,
1674                                            const int32_t iEdgedWidth,
1675                                            const int32_t iDiamondSize,
1676                                            const int32_t iFcode,
1677                                            const int32_t iQuant,
1678                                            int iFound)
1679    {
1680    /* Do a diamond search around given starting point, return SAD of best */
1681    
1682            int32_t iDirection = 0;
1683            int32_t iDirectionBackup;
1684            int32_t iSAD;
1685            VECTOR backupMV;
1686    
1687            backupMV.x = start_x;
1688            backupMV.y = start_y;
1689    
1690    /* It's one search with full Diamond pattern, and only 3 of 4 for all following diamonds */
1691    
1692            CHECK_MV8_CANDIDATE_DIR(backupMV.x - iDiamondSize, backupMV.y, 1);
1693            CHECK_MV8_CANDIDATE_DIR(backupMV.x + iDiamondSize, backupMV.y, 2);
1694            CHECK_MV8_CANDIDATE_DIR(backupMV.x, backupMV.y - iDiamondSize, 3);
1695            CHECK_MV8_CANDIDATE_DIR(backupMV.x, backupMV.y + iDiamondSize, 4);
1696    
1697            if (iDirection) {
1698                    while (!iFound) {
1699                            iFound = 1;
1700                            backupMV = *currMV;     // since iDirection!=0, this is well defined!
1701                            iDirectionBackup = iDirection;
1702    
1703                            if (iDirectionBackup != 2)
1704                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,
1705                                                                                      backupMV.y, 1);
1706                            if (iDirectionBackup != 1)
1707                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,
1708                                                                                      backupMV.y, 2);
1709                            if (iDirectionBackup != 4)
1710                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x,
1711                                                                                      backupMV.y - iDiamondSize, 3);
1712                            if (iDirectionBackup != 3)
1713                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x,
1714                                                                                      backupMV.y + iDiamondSize, 4);
1715                    }
1716            } else {
1717                    currMV->x = start_x;
1718                    currMV->y = start_y;
1719            }
1720            return iMinSAD;
1721    }
1722    
1723    
1724    
1725    
1726    int32_t
1727    Square8_MainSearch(const uint8_t * const pRef,
1728                                       const uint8_t * const pRefH,
1729                                       const uint8_t * const pRefV,
1730                                       const uint8_t * const pRefHV,
1731                                       const uint8_t * const cur,
1732                                       const int x,
1733                                       const int y,
1734                                       const int32_t start_x,
1735                                       const int32_t start_y,
1736                                       int32_t iMinSAD,
1737                                       VECTOR * const currMV,
1738                                       const int center_x,
1739                                       const int center_y,
1740                                       const int32_t min_dx,
1741                                       const int32_t max_dx,
1742                                       const int32_t min_dy,
1743                                       const int32_t max_dy,
1744                                       const int32_t iEdgedWidth,
1745                                       const int32_t iDiamondSize,
1746                                       const int32_t iFcode,
1747                                       const int32_t iQuant,
1748                                       int iFound)
1749    {
1750    /* Do a square search around given starting point, return SAD of best */
1751    
1752            int32_t iDirection = 0;
1753            int32_t iSAD;
1754            VECTOR backupMV;
1755    
1756            backupMV.x = start_x;
1757            backupMV.y = start_y;
1758    
1759    /* It's one search with full square pattern, and new parts for all following diamonds */
1760    
1761    /*   new direction are extra, so 1-4 is normal diamond
1762          537
1763          1*2
1764          648
1765    */
1766    
1767            CHECK_MV8_CANDIDATE_DIR(backupMV.x - iDiamondSize, backupMV.y, 1);
1768            CHECK_MV8_CANDIDATE_DIR(backupMV.x + iDiamondSize, backupMV.y, 2);
1769            CHECK_MV8_CANDIDATE_DIR(backupMV.x, backupMV.y - iDiamondSize, 3);
1770            CHECK_MV8_CANDIDATE_DIR(backupMV.x, backupMV.y + iDiamondSize, 4);
1771    
1772            CHECK_MV8_CANDIDATE_DIR(backupMV.x - iDiamondSize,
1773                                                             backupMV.y - iDiamondSize, 5);
1774            CHECK_MV8_CANDIDATE_DIR(backupMV.x - iDiamondSize,
1775                                                             backupMV.y + iDiamondSize, 6);
1776            CHECK_MV8_CANDIDATE_DIR(backupMV.x + iDiamondSize,
1777                                                             backupMV.y - iDiamondSize, 7);
1778            CHECK_MV8_CANDIDATE_DIR(backupMV.x + iDiamondSize,
1779                                                             backupMV.y + iDiamondSize, 8);
1780    
1781    
1782            if (iDirection) {
1783                    while (!iFound) {
1784                            iFound = 1;
1785                            backupMV = *currMV;
1786    
1787                            switch (iDirection) {
1788                            case 1:
1789                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,
1790                                                                                       backupMV.y, 1);
1791                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,
1792                                                                                     backupMV.y - iDiamondSize, 5);
1793                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,
1794                                                                                     backupMV.y - iDiamondSize, 7);
1795                                    break;
1796                            case 2:
1797                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y,
1798                                                                                     2);
1799                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,
1800                                                                                     backupMV.y + iDiamondSize, 6);
1801                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,
1802                                                                                     backupMV.y + iDiamondSize, 8);
1803                                    break;
1804    
1805                            case 3:
1806                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,
1807                                                                                     4);
1808                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,
1809                                                                                     backupMV.y - iDiamondSize, 7);
1810                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,
1811                                                                                     backupMV.y + iDiamondSize, 8);
1812                                    break;
1813    
1814                            case 4:
1815                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize,
1816                                                                                     3);
1817                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,
1818                                                                                     backupMV.y - iDiamondSize, 5);
1819                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,
1820                                                                                     backupMV.y + iDiamondSize, 6);
1821                                    break;
1822    
1823                            case 5:
1824                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize, backupMV.y,
1825                                                                                     1);
1826                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize,
1827                                                                                     3);
1828                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,
1829                                                                                     backupMV.y - iDiamondSize, 5);
1830                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,
1831                                                                                     backupMV.y + iDiamondSize, 6);
1832                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,
1833                                                                                     backupMV.y - iDiamondSize, 7);
1834                                    break;
1835    
1836                            case 6:
1837                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y,
1838                                                                                     2);
1839                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize,
1840                                                                                     3);
1841    
1842                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,
1843                                                                                     backupMV.y - iDiamondSize, 5);
1844                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,
1845                                                                                     backupMV.y + iDiamondSize, 6);
1846                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,
1847                                                                                     backupMV.y + iDiamondSize, 8);
1848    
1849                                    break;
1850    
1851                            case 7:
1852                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,
1853                                                                                       backupMV.y, 1);
1854                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,
1855                                                                                     4);
1856                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,
1857                                                                                     backupMV.y - iDiamondSize, 5);
1858                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,
1859                                                                                     backupMV.y - iDiamondSize, 7);
1860                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,
1861                                                                                     backupMV.y + iDiamondSize, 8);
1862                                    break;
1863    
1864                            case 8:
1865                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y,
1866                                                                                     2);
1867                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,
1868                                                                                     4);
1869                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,
1870                                                                                     backupMV.y + iDiamondSize, 6);
1871                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,
1872                                                                                     backupMV.y - iDiamondSize, 7);
1873                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,
1874                                                                                     backupMV.y + iDiamondSize, 8);
1875                                    break;
1876                            default:
1877                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize, backupMV.y,
1878                                                                                     1);
1879                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y,
1880                                                                                     2);
1881                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize,
1882                                                                                     3);
1883                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,
1884                                                                                     4);
1885    
1886                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,
1887                                                                                     backupMV.y - iDiamondSize, 5);
1888                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,
1889                                                                                     backupMV.y + iDiamondSize, 6);
1890                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,
1891                                                                                     backupMV.y - iDiamondSize, 7);
1892                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,
1893                                                                                     backupMV.y + iDiamondSize, 8);
1894                                    break;
1895                            }
1896                    }
1897            } else {
1898                    currMV->x = start_x;
1899                    currMV->y = start_y;
1900            }
1901            return iMinSAD;
1902    }
1903    
1904    
1905    
1906    
1907    
1908    int32_t
1909    Halfpel8_Refine_c(const uint8_t * const pRef,
1910                                      const uint8_t * const pRefH,
1911                                      const uint8_t * const pRefV,
1912                                      const uint8_t * const pRefHV,
1913                                      const uint8_t * const cur,
1914                                      const int x,
1915                                      const int y,
1916                                      VECTOR * const currMV,
1917                                      int32_t iMinSAD,
1918                                      const int center_x,
1919                                      const int center_y,
1920                                      const int32_t min_dx,
1921                                      const int32_t max_dx,
1922                                      const int32_t min_dy,
1923                                      const int32_t max_dy,
1924                                      const int32_t iFcode,
1925                                      const int32_t iQuant,
1926                                      const int32_t iEdgedWidth)
1927    {
1928    /* Do a half-pel refinement (or rather a "smallest possible amount" refinement) */
1929    
1930            int32_t iSAD;
1931            VECTOR backupMV = *currMV;
1932    
1933            CHECK_MV8_CANDIDATE(backupMV.x - 1, backupMV.y - 1);
1934            CHECK_MV8_CANDIDATE(backupMV.x, backupMV.y - 1);
1935            CHECK_MV8_CANDIDATE(backupMV.x + 1, backupMV.y - 1);
1936            CHECK_MV8_CANDIDATE(backupMV.x - 1, backupMV.y);
1937            CHECK_MV8_CANDIDATE(backupMV.x + 1, backupMV.y);
1938            CHECK_MV8_CANDIDATE(backupMV.x - 1, backupMV.y + 1);
1939            CHECK_MV8_CANDIDATE(backupMV.x, backupMV.y + 1);
1940            CHECK_MV8_CANDIDATE(backupMV.x + 1, backupMV.y + 1);
1941    
1942            return iMinSAD;
1943    }
1944    
1945    
1946    #define PMV_HALFPEL8 (PMV_HALFPELDIAMOND8|PMV_HALFPELREFINE8)
1947    
1948    int32_t
1949    PMVfastSearch8(const uint8_t * const pRef,
1950                               const uint8_t * const pRefH,
1951                               const uint8_t * const pRefV,
1952                               const uint8_t * const pRefHV,
1953                               const IMAGE * const pCur,
1954                               const int x,
1955                               const int y,
1956                               const int start_x,
1957                               const int start_y,
1958                                    const int center_x,
1959                                    const int center_y,
1960                               const uint32_t MotionFlags,
1961                               const uint32_t iQuant,
1962                               const uint32_t iFcode,
1963                               const MBParam * const pParam,
1964                               const MACROBLOCK * const pMBs,
1965                               const MACROBLOCK * const prevMBs,
1966                               VECTOR * const currMV,
1967                               VECTOR * const currPMV)
1968    {
1969            const uint32_t iWcount = pParam->mb_width;
1970            const int32_t iWidth = pParam->width;
1971            const int32_t iHeight = pParam->height;
1972            const int32_t iEdgedWidth = pParam->edged_width;
1973    
1974            const uint8_t *cur = pCur->y + x * 8 + y * 8 * iEdgedWidth;
1975    
1976            int32_t iDiamondSize;
1977    
1978            int32_t min_dx;
1979            int32_t max_dx;
1980            int32_t min_dy;
1981            int32_t max_dy;
1982    
1983            VECTOR pmv[4];
1984            int32_t psad[4];
1985            VECTOR newMV;
1986            VECTOR backupMV;
1987            VECTOR startMV;
1988    
1989    //  const MACROBLOCK * const pMB = pMBs + (x>>1) + (y>>1) * iWcount;
1990            const MACROBLOCK *const prevMB = prevMBs + (x >> 1) + (y >> 1) * iWcount;
1991    
1992             int32_t threshA, threshB;
1993            int32_t iFound, bPredEq;
1994            int32_t iMinSAD, iSAD;
1995    
1996            int32_t iSubBlock = (y & 1) + (y & 1) + (x & 1);
1997    
1998            MainSearch8FuncPtr MainSearchPtr;
1999    
2000            /* Init variables */
2001            startMV.x = start_x;
2002            startMV.y = start_y;
2003    
2004            /* Get maximum range */
2005            get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 8, iWidth, iHeight,
2006                              iFcode);
2007    
2008            if (!(MotionFlags & PMV_HALFPELDIAMOND8)) {
2009                    min_dx = EVEN(min_dx);
2010                    max_dx = EVEN(max_dx);
2011                    min_dy = EVEN(min_dy);
2012                    max_dy = EVEN(max_dy);
2013            }
2014    
2015            /* because we might use IF (dx>max_dx) THEN dx=max_dx; */
2016            bPredEq = get_pmvdata2(pMBs, iWcount, 0, (x >> 1), (y >> 1), iSubBlock, pmv, psad);
2017    
2018            if ((x == 0) && (y == 0)) {
2019                    threshA = 512 / 4;
2020                    threshB = 1024 / 4;
2021    
2022            } else {
2023                    threshA = psad[0] / 4;  /* good estimate? */
2024                    threshB = threshA + 256 / 4;
2025                    if (threshA < 512 / 4)
2026                            threshA = 512 / 4;
2027                    if (threshA > 1024 / 4)
2028                            threshA = 1024 / 4;
2029                    if (threshB > 1792 / 4)
2030                            threshB = 1792 / 4;
2031            }
2032    
2033            iFound = 0;
2034    
2035    /* Step 4: Calculate SAD around the Median prediction.
2036       MinSAD=SAD
2037       If Motion Vector equal to Previous frame motion vector
2038       and MinSAD<PrevFrmSAD goto Step 10.
2039          If SAD<=256 goto Step 10.          If SAD<=256 goto Step 10.
2040  */  */
2041    
2042    
2043  // Prepare for main loop  // Prepare for main loop
2044    
2045          *currMV=pmv[0];         /* current best := prediction */    if (MotionFlags & PMV_USESQUARES8)
2046          if (!(MotionFlags & PMV_HALFPEL16 ))        MainSearchPtr = Square8_MainSearch;
2047          {       /* This should NOT be necessary! */    else
2048    
2049            if (MotionFlags & PMV_ADVANCEDDIAMOND8)
2050                    MainSearchPtr = AdvDiamond8_MainSearch;
2051            else
2052                    MainSearchPtr = Diamond8_MainSearch;
2053    
2054    
2055            *currMV = startMV;
2056    
2057            iMinSAD =
2058                    sad8(cur,
2059                             get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 8, currMV,
2060                                                    iEdgedWidth), iEdgedWidth);
2061            iMinSAD +=
2062                    calc_delta_8(currMV->x - center_x, currMV->y - center_y,
2063                                             (uint8_t) iFcode, iQuant);
2064    
2065            if ((iMinSAD < 256 / 4) || ((MVequal(*currMV, prevMB->mvs[iSubBlock]))
2066                                                                    && ((int32_t) iMinSAD <
2067                                                                            prevMB->sad8[iSubBlock]))) {
2068                    if (MotionFlags & PMV_QUICKSTOP16)
2069                            goto PMVfast8_Terminate_without_Refine;
2070                    if (MotionFlags & PMV_EARLYSTOP16)
2071                            goto PMVfast8_Terminate_with_Refine;
2072            }
2073    
2074    /* Step 2 (lazy eval): Calculate Distance= |MedianMVX| + |MedianMVY| where MedianMV is the motion
2075       vector of the median.
2076       If PredEq=1 and MVpredicted = Previous Frame MV, set Found=2
2077    */
2078    
2079            if ((bPredEq) && (MVequal(pmv[0], prevMB->mvs[iSubBlock])))
2080                    iFound = 2;
2081    
2082    /* Step 3 (lazy eval): If Distance>0 or thresb<1536 or PredEq=1 Select small Diamond Search.
2083       Otherwise select large Diamond Search.
2084    */
2085    
2086            if ((!MVzero(pmv[0])) || (threshB < 1536 / 4) || (bPredEq))
2087                    iDiamondSize = 1;               // 1 halfpel!
2088            else
2089                    iDiamondSize = 2;               // 2 halfpel = 1 full pixel!
2090    
2091            if (!(MotionFlags & PMV_HALFPELDIAMOND8))
2092                    iDiamondSize *= 2;
2093    
2094    
2095    /*
2096       Step 5: Calculate SAD for motion vectors taken from left block, top, top-right, and Previous frame block.
2097       Also calculate (0,0) but do not subtract offset.
2098       Let MinSAD be the smallest SAD up to this point.
2099       If MV is (0,0) subtract offset.
2100    */
2101    
2102    // the median prediction might be even better than mv16
2103    
2104            if (!MVequal(pmv[0], startMV))
2105                    CHECK_MV8_CANDIDATE(center_x, center_y);
2106    
2107    // (0,0) if needed
2108            if (!MVzero(pmv[0]))
2109                    if (!MVzero(startMV))
2110                            CHECK_MV8_ZERO;
2111    
2112    // previous frame MV if needed
2113            if (!MVzero(prevMB->mvs[iSubBlock]))
2114                    if (!MVequal(prevMB->mvs[iSubBlock], startMV))
2115                            if (!MVequal(prevMB->mvs[iSubBlock], pmv[0]))
2116                                    CHECK_MV8_CANDIDATE(prevMB->mvs[iSubBlock].x,
2117                                                                            prevMB->mvs[iSubBlock].y);
2118    
2119            if ((iMinSAD <= threshA) ||
2120                    (MVequal(*currMV, prevMB->mvs[iSubBlock]) &&
2121                     ((int32_t) iMinSAD < prevMB->sad8[iSubBlock]))) {
2122                    if (MotionFlags & PMV_QUICKSTOP16)
2123                            goto PMVfast8_Terminate_without_Refine;
2124                    if (MotionFlags & PMV_EARLYSTOP16)
2125                            goto PMVfast8_Terminate_with_Refine;
2126            }
2127    
2128    // left neighbour, if allowed and needed
2129            if (!MVzero(pmv[1]))
2130                    if (!MVequal(pmv[1], startMV))
2131                            if (!MVequal(pmv[1], prevMB->mvs[iSubBlock]))
2132                                    if (!MVequal(pmv[1], pmv[0])) {
2133                                            if (!(MotionFlags & PMV_HALFPEL8)) {
2134                                                    pmv[1].x = EVEN(pmv[1].x);
2135                                                    pmv[1].y = EVEN(pmv[1].y);
2136                                            }
2137                                            CHECK_MV8_CANDIDATE(pmv[1].x, pmv[1].y);
2138                                    }
2139    // top neighbour, if allowed and needed
2140            if (!MVzero(pmv[2]))
2141                    if (!MVequal(pmv[2], startMV))
2142                            if (!MVequal(pmv[2], prevMB->mvs[iSubBlock]))
2143                                    if (!MVequal(pmv[2], pmv[0]))
2144                                            if (!MVequal(pmv[2], pmv[1])) {
2145                                                    if (!(MotionFlags & PMV_HALFPEL8)) {
2146                                                            pmv[2].x = EVEN(pmv[2].x);
2147                                                            pmv[2].y = EVEN(pmv[2].y);
2148                                                    }
2149                                                    CHECK_MV8_CANDIDATE(pmv[2].x, pmv[2].y);
2150    
2151    // top right neighbour, if allowed and needed
2152                                                    if (!MVzero(pmv[3]))
2153                                                            if (!MVequal(pmv[3], startMV))
2154                                                                    if (!MVequal(pmv[3], prevMB->mvs[iSubBlock]))
2155                                                                            if (!MVequal(pmv[3], pmv[0]))
2156                                                                                    if (!MVequal(pmv[3], pmv[1]))
2157                                                                                            if (!MVequal(pmv[3], pmv[2])) {
2158                                                                                                    if (!
2159                                                                                                            (MotionFlags &
2160                                                                                                             PMV_HALFPEL8)) {
2161                                                                                                            pmv[3].x = EVEN(pmv[3].x);
2162                                                                                                            pmv[3].y = EVEN(pmv[3].y);
2163                                                                                                    }
2164                                                                                                    CHECK_MV8_CANDIDATE(pmv[3].x,
2165                                                                                                                                            pmv[3].y);
2166                                                                                            }
2167                                            }
2168    
2169            if ((MVzero(*currMV)) &&
2170                    (!MVzero(pmv[0])) /* && (iMinSAD <= iQuant * 96) */ )
2171                    iMinSAD -= MV8_00_BIAS;
2172    
2173    
2174    /* Step 6: If MinSAD <= thresa goto Step 10.
2175       If Motion Vector equal to Previous frame motion vector and MinSAD<PrevFrmSAD goto Step 10.
2176    */
2177    
2178            if ((iMinSAD <= threshA) ||
2179                    (MVequal(*currMV, prevMB->mvs[iSubBlock]) &&
2180                     ((int32_t) iMinSAD < prevMB->sad8[iSubBlock]))) {
2181                    if (MotionFlags & PMV_QUICKSTOP16)
2182                            goto PMVfast8_Terminate_without_Refine;
2183                    if (MotionFlags & PMV_EARLYSTOP16)
2184                            goto PMVfast8_Terminate_with_Refine;
2185            }
2186    
2187    /************ (Diamond Search)  **************/
2188    /*
2189       Step 7: Perform Diamond search, with either the small or large diamond.
2190       If Found=2 only examine one Diamond pattern, and afterwards goto step 10
2191       Step 8: If small diamond, iterate small diamond search pattern until motion vector lies in the center of the diamond.
2192       If center then goto step 10.
2193       Step 9: If large diamond, iterate large diamond search pattern until motion vector lies in the center.
2194       Refine by using small diamond and goto step 10.
2195    */
2196    
2197            backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */
2198    
2199    /* default: use best prediction as starting point for one call of PMVfast_MainSearch */
2200            iSAD =
2201                    (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV->x,
2202                                                      currMV->y, iMinSAD, &newMV, center_x, center_y, min_dx, max_dx,
2203                                                      min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode,
2204                                                      iQuant, iFound);
2205    
2206            if (iSAD < iMinSAD) {
2207                    *currMV = newMV;
2208                    iMinSAD = iSAD;
2209            }
2210    
2211            if (MotionFlags & PMV_EXTSEARCH8) {
2212    /* extended: search (up to) two more times: orignal prediction and (0,0) */
2213    
2214                    if (!(MVequal(pmv[0], backupMV))) {
2215                            iSAD =
2216                                    (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,
2217                                                                      pmv[0].x, pmv[0].y, iMinSAD, &newMV, center_x, center_y,
2218                                                                      min_dx, max_dx, min_dy, max_dy, iEdgedWidth,
2219                                                                      iDiamondSize, iFcode, iQuant, iFound);
2220    
2221                            if (iSAD < iMinSAD) {
2222                                    *currMV = newMV;
2223                                    iMinSAD = iSAD;
2224                            }
2225                    }
2226    
2227                    if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {
2228                            iSAD =
2229                                    (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, 0, 0,
2230                                                                      iMinSAD, &newMV, center_x, center_y, min_dx, max_dx, min_dy,
2231                                                                      max_dy, iEdgedWidth, iDiamondSize, iFcode,
2232                                                                      iQuant, iFound);
2233    
2234                            if (iSAD < iMinSAD) {
2235                                    *currMV = newMV;
2236                                    iMinSAD = iSAD;
2237                            }
2238                    }
2239            }
2240    
2241    /* Step 10: The motion vector is chosen according to the block corresponding to MinSAD.
2242       By performing an optional local half-pixel search, we can refine this result even further.
2243    */
2244    
2245      PMVfast8_Terminate_with_Refine:
2246            if (MotionFlags & PMV_HALFPELREFINE8)   // perform final half-pel step
2247                    iMinSAD =
2248                            Halfpel8_Refine(pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV,
2249                                                            iMinSAD, center_x, center_y, min_dx, max_dx, min_dy, max_dy,
2250                                                            iFcode, iQuant, iEdgedWidth);
2251    
2252    
2253      PMVfast8_Terminate_without_Refine:
2254            currPMV->x = currMV->x - center_x;
2255            currPMV->y = currMV->y - center_y;
2256    
2257            return iMinSAD;
2258    }
2259    
2260    int32_t
2261    EPZSSearch16(const uint8_t * const pRef,
2262                             const uint8_t * const pRefH,
2263                             const uint8_t * const pRefV,
2264                             const uint8_t * const pRefHV,
2265                             const IMAGE * const pCur,
2266                             const int x,
2267                             const int y,
2268                            const int start_x,
2269                            const int start_y,
2270                            const int center_x,
2271                            const int center_y,
2272                             const uint32_t MotionFlags,
2273                             const uint32_t iQuant,
2274                             const uint32_t iFcode,
2275                             const MBParam * const pParam,
2276                             const MACROBLOCK * const pMBs,
2277                             const MACROBLOCK * const prevMBs,
2278                             VECTOR * const currMV,
2279                             VECTOR * const currPMV)
2280    {
2281            const uint32_t iWcount = pParam->mb_width;
2282            const uint32_t iHcount = pParam->mb_height;
2283    
2284            const int32_t iWidth = pParam->width;
2285            const int32_t iHeight = pParam->height;
2286            const int32_t iEdgedWidth = pParam->edged_width;
2287    
2288            const uint8_t *cur = pCur->y + x * 16 + y * 16 * iEdgedWidth;
2289    
2290            int32_t min_dx;
2291            int32_t max_dx;
2292            int32_t min_dy;
2293            int32_t max_dy;
2294    
2295            VECTOR newMV;
2296            VECTOR backupMV;
2297    
2298            VECTOR pmv[4];
2299            int32_t psad[8];
2300    
2301            static MACROBLOCK *oldMBs = NULL;
2302    
2303    //  const MACROBLOCK * const pMB = pMBs + x + y * iWcount;
2304            const MACROBLOCK *const prevMB = prevMBs + x + y * iWcount;
2305            MACROBLOCK *oldMB = NULL;
2306    
2307             int32_t thresh2;
2308            int32_t bPredEq;
2309            int32_t iMinSAD, iSAD = 9999;
2310    
2311            MainSearch16FuncPtr MainSearchPtr;
2312    
2313            if (oldMBs == NULL) {
2314                    oldMBs = (MACROBLOCK *) calloc(iWcount * iHcount, sizeof(MACROBLOCK));
2315    //      fprintf(stderr,"allocated %d bytes for oldMBs\n",iWcount*iHcount*sizeof(MACROBLOCK));
2316            }
2317            oldMB = oldMBs + x + y * iWcount;
2318    
2319    /* Get maximum range */
2320            get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 16, iWidth, iHeight,
2321                              iFcode);
2322    
2323            if (!(MotionFlags & PMV_HALFPEL16)) {
2324                    min_dx = EVEN(min_dx);
2325                    max_dx = EVEN(max_dx);
2326                    min_dy = EVEN(min_dy);
2327                    max_dy = EVEN(max_dy);
2328            }
2329            /* because we might use something like IF (dx>max_dx) THEN dx=max_dx; */
2330            bPredEq = get_pmvdata2(pMBs, iWcount, 0, x, y, 0, pmv, psad);
2331    
2332    /* Step 4: Calculate SAD around the Median prediction.
2333            MinSAD=SAD
2334            If Motion Vector equal to Previous frame motion vector
2335                    and MinSAD<PrevFrmSAD goto Step 10.
2336            If SAD<=256 goto Step 10.
2337    */
2338    
2339    // Prepare for main loop
2340    
2341            currMV->x = start_x;
2342            currMV->y = start_y;
2343    
2344            if (!(MotionFlags & PMV_HALFPEL16)) {
2345                  currMV->x = EVEN(currMV->x);                  currMV->x = EVEN(currMV->x);
2346                  currMV->y = EVEN(currMV->y);                  currMV->y = EVEN(currMV->y);
2347          }          }
2348    
2349          if (currMV->x > max_dx)          if (currMV->x > max_dx)
                 {  
2350                          currMV->x=max_dx;                          currMV->x=max_dx;
                 }  
2351          if (currMV->x < min_dx)          if (currMV->x < min_dx)
                 {  
2352                          currMV->x=min_dx;                          currMV->x=min_dx;
                 }  
2353          if (currMV->y > max_dy)          if (currMV->y > max_dy)
                 {  
2354                          currMV->y=max_dy;                          currMV->y=max_dy;
                 }  
2355          if (currMV->y < min_dy)          if (currMV->y < min_dy)
                 {  
2356                          currMV->y=min_dy;                          currMV->y=min_dy;
2357    
2358    /***************** This is predictor SET A: only median prediction ******************/
2359    
2360            iMinSAD =
2361                    sad16(cur,
2362                              get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 16, currMV,
2363                                                     iEdgedWidth), iEdgedWidth, MV_MAX_ERROR);
2364            iMinSAD +=
2365                    calc_delta_16(currMV->x - center_x, currMV->y - center_y,
2366                                              (uint8_t) iFcode, iQuant);
2367    
2368    // thresh1 is fixed to 256
2369            if ((iMinSAD < 256) ||
2370                    ((MVequal(*currMV, prevMB->mvs[0])) &&
2371                     ((int32_t) iMinSAD < prevMB->sad16))) {
2372                    if (MotionFlags & PMV_QUICKSTOP16)
2373                            goto EPZS16_Terminate_without_Refine;
2374                    if (MotionFlags & PMV_EARLYSTOP16)
2375                            goto EPZS16_Terminate_with_Refine;
2376            }
2377    
2378    /************** This is predictor SET B: (0,0), prev.frame MV, neighbours **************/
2379    
2380    // previous frame MV
2381            CHECK_MV16_CANDIDATE(prevMB->mvs[0].x, prevMB->mvs[0].y);
2382    
2383    // set threshhold based on Min of Prediction and SAD of collocated block
2384    // CHECK_MV16 always uses iSAD for the SAD of last vector to check, so now iSAD is what we want
2385    
2386            if ((x == 0) && (y == 0)) {
2387                    thresh2 = 512;
2388            } else {
2389    /* T_k = 1.2 * MIN(SAD_top,SAD_left,SAD_topleft,SAD_coll) +128;   [Tourapis, 2002] */
2390    
2391                    thresh2 = MIN(psad[0], iSAD) * 6 / 5 + 128;
2392            }
2393    
2394    // MV=(0,0) is often a good choice
2395    
2396            CHECK_MV16_ZERO;
2397    
2398    
2399    // left neighbour, if allowed
2400            if (x != 0) {
2401                    if (!(MotionFlags & PMV_HALFPEL16)) {
2402                            pmv[1].x = EVEN(pmv[1].x);
2403                            pmv[1].y = EVEN(pmv[1].y);
2404                    }
2405                    CHECK_MV16_CANDIDATE(pmv[1].x, pmv[1].y);
2406            }
2407    // top neighbour, if allowed
2408            if (y != 0) {
2409                    if (!(MotionFlags & PMV_HALFPEL16)) {
2410                            pmv[2].x = EVEN(pmv[2].x);
2411                            pmv[2].y = EVEN(pmv[2].y);
2412                    }
2413                    CHECK_MV16_CANDIDATE(pmv[2].x, pmv[2].y);
2414    
2415    // top right neighbour, if allowed
2416                    if ((uint32_t) x != (iWcount - 1)) {
2417                            if (!(MotionFlags & PMV_HALFPEL16)) {
2418                                    pmv[3].x = EVEN(pmv[3].x);
2419                                    pmv[3].y = EVEN(pmv[3].y);
2420                            }
2421                            CHECK_MV16_CANDIDATE(pmv[3].x, pmv[3].y);
2422                    }
2423            }
2424    
2425    /* Terminate if MinSAD <= T_2
2426       Terminate if MV[t] == MV[t-1] and MinSAD[t] <= MinSAD[t-1]
2427    */
2428    
2429            if ((iMinSAD <= thresh2)
2430                    || (MVequal(*currMV, prevMB->mvs[0]) &&
2431                            ((int32_t) iMinSAD <= prevMB->sad16))) {
2432                    if (MotionFlags & PMV_QUICKSTOP16)
2433                            goto EPZS16_Terminate_without_Refine;
2434                    if (MotionFlags & PMV_EARLYSTOP16)
2435                            goto EPZS16_Terminate_with_Refine;
2436            }
2437    
2438    /***** predictor SET C: acceleration MV (new!), neighbours in prev. frame(new!) ****/
2439    
2440            backupMV = prevMB->mvs[0];      // collocated MV
2441            backupMV.x += (prevMB->mvs[0].x - oldMB->mvs[0].x);     // acceleration X
2442            backupMV.y += (prevMB->mvs[0].y - oldMB->mvs[0].y);     // acceleration Y
2443    
2444            CHECK_MV16_CANDIDATE(backupMV.x, backupMV.y);
2445    
2446    // left neighbour
2447            if (x != 0)
2448                    CHECK_MV16_CANDIDATE((prevMB - 1)->mvs[0].x, (prevMB - 1)->mvs[0].y);
2449    
2450    // top neighbour
2451            if (y != 0)
2452                    CHECK_MV16_CANDIDATE((prevMB - iWcount)->mvs[0].x,
2453                                                             (prevMB - iWcount)->mvs[0].y);
2454    
2455    // right neighbour, if allowed (this value is not written yet, so take it from   pMB->mvs
2456    
2457            if ((uint32_t) x != iWcount - 1)
2458                    CHECK_MV16_CANDIDATE((prevMB + 1)->mvs[0].x, (prevMB + 1)->mvs[0].y);
2459    
2460    // bottom neighbour, dito
2461            if ((uint32_t) y != iHcount - 1)
2462                    CHECK_MV16_CANDIDATE((prevMB + iWcount)->mvs[0].x,
2463                                                             (prevMB + iWcount)->mvs[0].y);
2464    
2465    /* Terminate if MinSAD <= T_3 (here T_3 = T_2)  */
2466            if (iMinSAD <= thresh2) {
2467                    if (MotionFlags & PMV_QUICKSTOP16)
2468                            goto EPZS16_Terminate_without_Refine;
2469                    if (MotionFlags & PMV_EARLYSTOP16)
2470                            goto EPZS16_Terminate_with_Refine;
2471            }
2472    
2473    /************ (if Diamond Search)  **************/
2474    
2475            backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */
2476    
2477            if (MotionFlags & PMV_USESQUARES16)
2478                    MainSearchPtr = Square16_MainSearch;
2479            else
2480             if (MotionFlags & PMV_ADVANCEDDIAMOND16)
2481                    MainSearchPtr = AdvDiamond16_MainSearch;
2482            else
2483                    MainSearchPtr = Diamond16_MainSearch;
2484    
2485    /* default: use best prediction as starting point for one call of PMVfast_MainSearch */
2486    
2487            iSAD =
2488                    (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV->x,
2489                                                      currMV->y, iMinSAD, &newMV, center_x, center_y, min_dx, max_dx,
2490                                                      min_dy, max_dy, iEdgedWidth, 2, iFcode, iQuant, 0);
2491    
2492            if (iSAD < iMinSAD) {
2493                    *currMV = newMV;
2494                    iMinSAD = iSAD;
2495            }
2496    
2497    
2498            if (MotionFlags & PMV_EXTSEARCH16) {
2499    /* extended mode: search (up to) two more times: orignal prediction and (0,0) */
2500    
2501                    if (!(MVequal(pmv[0], backupMV))) {
2502                            iSAD =
2503                                    (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,
2504                                                                      pmv[0].x, pmv[0].y, iMinSAD, &newMV, center_x, center_y,
2505                                                                      min_dx, max_dx, min_dy, max_dy, iEdgedWidth,
2506                                                                      2, iFcode, iQuant, 0);
2507                    }
2508    
2509                    if (iSAD < iMinSAD) {
2510                            *currMV = newMV;
2511                            iMinSAD = iSAD;
2512                    }
2513    
2514                    if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {
2515                            iSAD =
2516                                    (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, 0, 0,
2517                                                                      iMinSAD, &newMV, center_x, center_y, min_dx, max_dx, min_dy,
2518                                                                      max_dy, iEdgedWidth, 2, iFcode, iQuant, 0);
2519    
2520                            if (iSAD < iMinSAD) {
2521                                    *currMV = newMV;
2522                                    iMinSAD = iSAD;
2523                            }
2524                    }
2525            }
2526    
2527    /***************        Choose best MV found     **************/
2528    
2529      EPZS16_Terminate_with_Refine:
2530            if (MotionFlags & PMV_HALFPELREFINE16)  // perform final half-pel step
2531                    iMinSAD =
2532                            Halfpel16_Refine(pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV,
2533                                                             iMinSAD, center_x, center_y, min_dx, max_dx, min_dy, max_dy,
2534                                                             iFcode, iQuant, iEdgedWidth);
2535    
2536      EPZS16_Terminate_without_Refine:
2537    
2538            *oldMB = *prevMB;
2539    
2540            currPMV->x = currMV->x - center_x;
2541            currPMV->y = currMV->y - center_y;
2542            return iMinSAD;
2543    }
2544    
2545    
2546    int32_t
2547    EPZSSearch8(const uint8_t * const pRef,
2548                            const uint8_t * const pRefH,
2549                            const uint8_t * const pRefV,
2550                            const uint8_t * const pRefHV,
2551                            const IMAGE * const pCur,
2552                            const int x,
2553                            const int y,
2554                            const int start_x,
2555                            const int start_y,
2556                            const int center_x,
2557                            const int center_y,
2558                            const uint32_t MotionFlags,
2559                            const uint32_t iQuant,
2560                            const uint32_t iFcode,
2561                            const MBParam * const pParam,
2562                            const MACROBLOCK * const pMBs,
2563                            const MACROBLOCK * const prevMBs,
2564                            VECTOR * const currMV,
2565                            VECTOR * const currPMV)
2566    {
2567    /* Please not that EPZS might not be a good choice for 8x8-block motion search ! */
2568    
2569            const uint32_t iWcount = pParam->mb_width;
2570            const int32_t iWidth = pParam->width;
2571            const int32_t iHeight = pParam->height;
2572            const int32_t iEdgedWidth = pParam->edged_width;
2573    
2574            const uint8_t *cur = pCur->y + x * 8 + y * 8 * iEdgedWidth;
2575    
2576            int32_t iDiamondSize = 1;
2577    
2578            int32_t min_dx;
2579            int32_t max_dx;
2580            int32_t min_dy;
2581            int32_t max_dy;
2582    
2583            VECTOR newMV;
2584            VECTOR backupMV;
2585    
2586            VECTOR pmv[4];
2587            int32_t psad[8];
2588    
2589            const int32_t iSubBlock = ((y & 1) << 1) + (x & 1);
2590    
2591    //  const MACROBLOCK * const pMB = pMBs + (x>>1) + (y>>1) * iWcount;
2592            const MACROBLOCK *const prevMB = prevMBs + (x >> 1) + (y >> 1) * iWcount;
2593    
2594            int32_t bPredEq;
2595            int32_t iMinSAD, iSAD = 9999;
2596    
2597            MainSearch8FuncPtr MainSearchPtr;
2598    
2599    /* Get maximum range */
2600            get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 8, iWidth, iHeight,
2601                              iFcode);
2602    
2603    /* we work with abs. MVs, not relative to prediction, so get_range is called relative to 0,0 */
2604    
2605            if (!(MotionFlags & PMV_HALFPEL8)) {
2606                    min_dx = EVEN(min_dx);
2607                    max_dx = EVEN(max_dx);
2608                    min_dy = EVEN(min_dy);
2609                    max_dy = EVEN(max_dy);
2610            }
2611            /* because we might use something like IF (dx>max_dx) THEN dx=max_dx; */
2612            bPredEq = get_pmvdata2(pMBs, iWcount, 0, x >> 1, y >> 1, iSubBlock, pmv, psad);
2613    
2614    
2615    /* Step 4: Calculate SAD around the Median prediction.
2616            MinSAD=SAD
2617            If Motion Vector equal to Previous frame motion vector
2618                    and MinSAD<PrevFrmSAD goto Step 10.
2619            If SAD<=256 goto Step 10.
2620    */
2621    
2622    // Prepare for main loop
2623    
2624    
2625            if (!(MotionFlags & PMV_HALFPEL8)) {
2626                    currMV->x = EVEN(currMV->x);
2627                    currMV->y = EVEN(currMV->y);
2628                  }                  }
2629    
2630          iMinSAD = sad16( cur,          if (currMV->x > max_dx)
2631                  get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 16, currMV, iEdgedWidth),                  currMV->x = max_dx;
2632                  iEdgedWidth, MV_MAX_ERROR);          if (currMV->x < min_dx)
2633          iMinSAD += calc_delta_16(currMV->x-pmv[0].x, currMV->y-pmv[0].y, (uint8_t)iFcode) * iQuant;                  currMV->x = min_dx;
2634            if (currMV->y > max_dy)
2635                    currMV->y = max_dy;
2636            if (currMV->y < min_dy)
2637                    currMV->y = min_dy;
2638    
2639    /***************** This is predictor SET A: only median prediction ******************/
2640    
2641    
2642            iMinSAD =
2643                    sad8(cur,
2644                             get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 8, currMV,
2645                                                    iEdgedWidth), iEdgedWidth);
2646            iMinSAD +=
2647                    calc_delta_8(currMV->x - center_x, currMV->y - center_y,
2648                                             (uint8_t) iFcode, iQuant);
2649    
         if ( (iMinSAD < 256 ) || ( (MVequal(*currMV,pMB->mvs[0])) && (iMinSAD < pMB->sad16) ) )  
                 {  
2650    
2651                          if (MotionFlags & PMV_QUICKSTOP16)  // thresh1 is fixed to 256
2652                                  goto step10b;          if (iMinSAD < 256 / 4) {
2653                          if (MotionFlags & PMV_EARLYSTOP16)                  if (MotionFlags & PMV_QUICKSTOP8)
2654                                  goto step10;                          goto EPZS8_Terminate_without_Refine;
2655                    if (MotionFlags & PMV_EARLYSTOP8)
2656                            goto EPZS8_Terminate_with_Refine;
2657                  }                  }
2658    
2659  /*  /************** This is predictor SET B: (0,0), prev.frame MV, neighbours **************/
 Step 5: Calculate SAD for motion vectors taken from left block, top, top-right, and Previous frame block.  
         Also calculate (0,0) but do not subtract offset.  
         Let MinSAD be the smallest SAD up to this point.  
         If MV is (0,0) subtract offset. ******** WHAT'S THIS 'OFFSET' ??? ***********  
 */  
2660    
 // (0,0) is always possible  
2661    
2662          CHECK_MV16_ZERO;  // MV=(0,0) is often a good choice
2663            CHECK_MV8_ZERO;
2664    
2665  // previous frame MV is always possible  // previous frame MV
2666          CHECK_MV16_CANDIDATE(pMB->mvs[0].x,pMB->mvs[0].y);          CHECK_MV8_CANDIDATE(prevMB->mvs[iSubBlock].x, prevMB->mvs[iSubBlock].y);
2667    
2668  // left neighbour, if allowed  // left neighbour, if allowed
2669          if (x != 0)          if (psad[1] != MV_MAX_ERROR) {
2670          {                  if (!(MotionFlags & PMV_HALFPEL8)) {
2671                  if (!(MotionFlags & PMV_HALFPEL16 ))                          pmv[1].x = EVEN(pmv[1].x);
                 {       pmv[1].x = EVEN(pmv[1].x);  
2672                          pmv[1].y = EVEN(pmv[1].y);                          pmv[1].y = EVEN(pmv[1].y);
2673                  }                  }
2674                  CHECK_MV16_CANDIDATE(pmv[1].x,pmv[1].y);                  CHECK_MV8_CANDIDATE(pmv[1].x, pmv[1].y);
2675          }          }
   
2676  // top neighbour, if allowed  // top neighbour, if allowed
2677          if (y != 0)          if (psad[2] != MV_MAX_ERROR) {
2678          {                  if (!(MotionFlags & PMV_HALFPEL8)) {
2679                  if (!(MotionFlags & PMV_HALFPEL16 ))                          pmv[2].x = EVEN(pmv[2].x);
                 {       pmv[2].x = EVEN(pmv[2].x);  
2680                          pmv[2].y = EVEN(pmv[2].y);                          pmv[2].y = EVEN(pmv[2].y);
2681                  }                  }
2682                  CHECK_MV16_CANDIDATE(pmv[2].x,pmv[2].y);                  CHECK_MV8_CANDIDATE(pmv[2].x, pmv[2].y);
2683    
2684  // top right neighbour, if allowed  // top right neighbour, if allowed
2685                  if (x != (iWcount-1))                  if (psad[3] != MV_MAX_ERROR) {
2686                  {                          if (!(MotionFlags & PMV_HALFPEL8)) {
2687                          if (!(MotionFlags & PMV_HALFPEL16 ))                                  pmv[3].x = EVEN(pmv[3].x);
                         {       pmv[3].x = EVEN(pmv[3].x);  
2688                                  pmv[3].y = EVEN(pmv[3].y);                                  pmv[3].y = EVEN(pmv[3].y);
2689                          }                          }
2690                          CHECK_MV16_CANDIDATE(pmv[3].x,pmv[3].y);                          CHECK_MV8_CANDIDATE(pmv[3].x, pmv[3].y);
2691                  }                  }
2692          }          }
2693    
2694  /* Step 6: If MinSAD <= thresa goto Step 10.  /*  // this bias is zero anyway, at the moment!
2695     If Motion Vector equal to Previous frame motion vector and MinSAD<PrevFrmSAD goto Step 10.  
2696            if ( (MVzero(*currMV)) && (!MVzero(pmv[0])) ) // && (iMinSAD <= iQuant * 96)
2697                    iMinSAD -= MV8_00_BIAS;
2698    
2699  */  */
2700    
2701          if ( (iMinSAD <= threshA) || ( MVequal(*currMV,pMB->mvs[0]) && (iMinSAD < pMB->sad16) ) )  /* Terminate if MinSAD <= T_2
2702                  {     Terminate if MV[t] == MV[t-1] and MinSAD[t] <= MinSAD[t-1]
2703                          if (MotionFlags & PMV_QUICKSTOP16)  */
                                 goto step10b;  
                         if (MotionFlags & PMV_EARLYSTOP16)  
                                 goto step10;  
                 }  
2704    
2705            if (iMinSAD < 512 / 4) {        /* T_2 == 512/4 hardcoded */
2706                    if (MotionFlags & PMV_QUICKSTOP8)
2707                            goto EPZS8_Terminate_without_Refine;
2708                    if (MotionFlags & PMV_EARLYSTOP8)
2709                            goto EPZS8_Terminate_with_Refine;
2710            }
2711    
2712  /************ (Diamond Search)  **************/  /************ (Diamond Search)  **************/
 /*  
 Step 7: Perform Diamond search, with either the small or large diamond.  
         If Found=2 only examine one Diamond pattern, and afterwards goto step 10  
 Step 8: If small diamond, iterate small diamond search pattern until motion vector lies in the center of the diamond.  
         If center then goto step 10.  
 Step 9: If large diamond, iterate large diamond search pattern until motion vector lies in the center.  
         Refine by using small diamond and goto step 10.  
 */  
2713    
2714          backupMV = *currMV; /* save best prediction, actually only for EXTSEARCH */          backupMV = *currMV; /* save best prediction, actually only for EXTSEARCH */
2715    
2716  /* default: use best prediction as starting point for one call of PMVfast_MainSearch */          if (!(MotionFlags & PMV_HALFPELDIAMOND8))
2717          iSAD = PMVfastSearch16_MainSearch(pRef, pRefH, pRefV, pRefHV, cur,                  iDiamondSize *= 2;
                 x, y,  
                 currMV->x, currMV->y, iMinSAD, &newMV,  
                 pmv, min_dx, max_dx, min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode, iQuant, iFound);  
2718    
2719          if (iSAD < iMinSAD)  /* default: use best prediction as starting point for one call of EPZS_MainSearch */
         {  
                 *currMV = newMV;  
                 iMinSAD = iSAD;  
         }  
2720    
2721          if (MotionFlags & PMV_EXTSEARCH16)  // there is no EPZS^2 for inter4v at the moment
         {  
 /* extended: search (up to) two more times: orignal prediction and (0,0) */  
2722    
2723                  if (!(MVequal(pmv[0],backupMV)) )    if (MotionFlags & PMV_USESQUARES8)
2724                  {       iSAD = PMVfastSearch16_MainSearch(pRef, pRefH, pRefV, pRefHV, cur,        MainSearchPtr = Square8_MainSearch;
2725                                  x, y,    else
                         pmv[0].x, pmv[0].y, iMinSAD, &newMV,  
                         pmv, min_dx, max_dx, min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode, iQuant, iFound);  
2726    
2727                          if (iSAD < iMinSAD)          if (MotionFlags & PMV_ADVANCEDDIAMOND8)
2728                          {                  MainSearchPtr = AdvDiamond8_MainSearch;
2729            else
2730                    MainSearchPtr = Diamond8_MainSearch;
2731    
2732            iSAD =
2733                    (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV->x,
2734                                                      currMV->y, iMinSAD, &newMV, center_x, center_y, min_dx, max_dx,
2735                                                      min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode,
2736                                                      iQuant, 0);
2737    
2738    
2739            if (iSAD < iMinSAD) {
2740                                  *currMV = newMV;                                  *currMV = newMV;
2741                                  iMinSAD = iSAD;                                  iMinSAD = iSAD;
2742                          }                          }
                 }  
2743    
2744                  if ( (!(MVzero(pmv[0]))) && (!(MVzero(backupMV))) )          if (MotionFlags & PMV_EXTSEARCH8) {
2745                  {       iSAD = PMVfastSearch16_MainSearch(pRef, pRefH, pRefV, pRefHV, cur,  /* extended mode: search (up to) two more times: orignal prediction and (0,0) */
                                 x, y,  
                         0, 0, iMinSAD, &newMV,  
                         pmv, min_dx, max_dx, min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode, iQuant, iFound);  
2746    
2747                          if (iSAD < iMinSAD)                  if (!(MVequal(pmv[0], backupMV))) {
2748                          {                          iSAD =
2749                                    (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,
2750                                                                      pmv[0].x, pmv[0].y, iMinSAD, &newMV, center_x, center_y,
2751                                                                      min_dx, max_dx, min_dy, max_dy, iEdgedWidth,
2752                                                                      iDiamondSize, iFcode, iQuant, 0);
2753    
2754                            if (iSAD < iMinSAD) {
2755                                  *currMV = newMV;                                  *currMV = newMV;
2756                                  iMinSAD = iSAD;                                  iMinSAD = iSAD;
2757                          }                          }
2758                  }                  }
         }  
   
 /*  
         Step 10:  The motion vector is chosen according to the block corresponding to MinSAD.  
 */  
   
 step10:  
         if (MotionFlags & PMV_HALFPELREFINE16)          // perform final half-pel step  
                 iMinSAD = PMVfastSearch16_Refine( pRef, pRefH, pRefV, pRefHV, cur,  
                                 x, y,  
                                 currMV, iMinSAD,  
                                 pmv, min_dx, max_dx, min_dy, max_dy, iFcode, iQuant, iEdgedWidth);  
   
 step10b:  
         currPMV->x = currMV->x - pmv[0].x;  
         currPMV->y = currMV->y - pmv[0].y;  
         return iMinSAD;  
 }  
   
   
   
   
   
   
 int32_t PMVfastSearch8_MainSearch(  
                                         const uint8_t * const pRef,  
                                         const uint8_t * const pRefH,  
                                         const uint8_t * const pRefV,  
                                         const uint8_t * const pRefHV,  
                                         const uint8_t * const cur,  
                                         const int x, const int y,  
                                         int32_t startx, int32_t starty,  
                                         int32_t iMinSAD,  
                                         VECTOR * const currMV,  
                                         const VECTOR * const pmv,  
                                         const int32_t min_dx, const int32_t max_dx,  
                                         const int32_t min_dy, const int32_t max_dy,  
                                         const int32_t iEdgedWidth,  
                                         const int32_t iDiamondSize,  
                                         const int32_t iFcode,  
                                         const int32_t iQuant,  
                                         int iFound)  
 {  
 /* Do a diamond search around given starting point, return SAD of best */  
   
         int32_t iDirection=0;  
         int32_t iSAD;  
         VECTOR backupMV;  
         backupMV.x = startx;  
         backupMV.y = starty;  
   
 /* It's one search with full Diamond pattern, and only 3 of 4 for all following diamonds */  
   
         CHECK_MV8_CANDIDATE_DIR(backupMV.x-iDiamondSize,backupMV.y,1);  
         CHECK_MV8_CANDIDATE_DIR(backupMV.x+iDiamondSize,backupMV.y,2);  
         CHECK_MV8_CANDIDATE_DIR(backupMV.x,backupMV.y-iDiamondSize,3);  
         CHECK_MV8_CANDIDATE_DIR(backupMV.x,backupMV.y+iDiamondSize,4);  
2759    
2760          if (iDirection)                  if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {
2761                  while (!iFound)                          iSAD =
2762                  {                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, 0, 0,
2763                          iFound = 1;                                                                    iMinSAD, &newMV, center_x, center_y, min_dx, max_dx, min_dy,
2764                          backupMV=*currMV;       // since iDirection!=0, this is well defined!                                                                    max_dy, iEdgedWidth, iDiamondSize, iFcode,
2765                                                                      iQuant, 0);
2766    
2767                          if ( iDirection != 2)                          if (iSAD < iMinSAD) {
2768                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x-iDiamondSize,backupMV.y,1);                                  *currMV = newMV;
2769                          if ( iDirection != 1)                                  iMinSAD = iSAD;
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x+iDiamondSize,backupMV.y,2);  
                         if ( iDirection != 4)  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x,backupMV.y-iDiamondSize,3);  
                         if ( iDirection != 3)  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x,backupMV.y+iDiamondSize,4);  
2770                  }                  }
         else  
                 {  
                         currMV->x = startx;  
                         currMV->y = starty;  
2771                  }                  }
         return iMinSAD;  
2772  }  }
2773    
2774  int32_t PMVfastSearch8_Refine(  /***************        Choose best MV found     **************/
                                         const uint8_t * const pRef,  
                                         const uint8_t * const pRefH,  
                                         const uint8_t * const pRefV,  
                                         const uint8_t * const pRefHV,  
                                         const uint8_t * const cur,  
                                         const int x, const int y,  
                                         VECTOR * const currMV,  
                                         int32_t iMinSAD,  
                                         const VECTOR * const pmv,  
                                         const int32_t min_dx, const int32_t max_dx,  
                                         const int32_t min_dy, const int32_t max_dy,  
                                         const int32_t iFcode,  
                                         const int32_t iQuant,  
                                         const int32_t iEdgedWidth)  
 {  
 /* Do a half-pel refinement (or rather a "smallest possible amount" refinement) */  
2775    
2776          int32_t iSAD;    EPZS8_Terminate_with_Refine:
2777          VECTOR backupMV = *currMV;          if (MotionFlags & PMV_HALFPELREFINE8)   // perform final half-pel step
2778                    iMinSAD =
2779                            Halfpel8_Refine(pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV,
2780                                                            iMinSAD, center_x, center_y, min_dx, max_dx, min_dy, max_dy,
2781                                                            iFcode, iQuant, iEdgedWidth);
2782    
2783          CHECK_MV8_CANDIDATE(backupMV.x-1,backupMV.y-1);    EPZS8_Terminate_without_Refine:
         CHECK_MV8_CANDIDATE(backupMV.x  ,backupMV.y-1);  
         CHECK_MV8_CANDIDATE(backupMV.x+1,backupMV.y-1);  
         CHECK_MV8_CANDIDATE(backupMV.x-1,backupMV.y);  
         CHECK_MV8_CANDIDATE(backupMV.x+1,backupMV.y);  
         CHECK_MV8_CANDIDATE(backupMV.x-1,backupMV.y+1);  
         CHECK_MV8_CANDIDATE(backupMV.x  ,backupMV.y+1);  
         CHECK_MV8_CANDIDATE(backupMV.x+1,backupMV.y+1);  
2784    
2785            currPMV->x = currMV->x - center_x;
2786            currPMV->y = currMV->y - center_y;
2787          return iMinSAD;          return iMinSAD;
2788  }  }
2789    
2790    
2791  #define PMV_HALFPEL8 (PMV_HALFPELDIAMOND8|PMV_HALFPELREFINE8)  /* Disabled bframe specific code */
2792    # if 0
2793  int32_t PMVfastSearch8(  int32_t
2794                                          const uint8_t * const pRef,  PMVfastIntSearch16(const uint8_t * const pRef,
2795                                          const uint8_t * const pRefH,                                          const uint8_t * const pRefH,
2796                                          const uint8_t * const pRefV,                                          const uint8_t * const pRefV,
2797                                          const uint8_t * const pRefHV,                                          const uint8_t * const pRefHV,
2798                                          const IMAGE * const pCur,                                          const IMAGE * const pCur,
2799                                          const int x, const int y,                                  const int x,
2800                                          const int start_x, int start_y,                                  const int y,
2801                                    const int start_x,              /* start should be most likely vector */
2802                                    const int start_y,
2803                                    const int center_x,             /* center is from where length of MVs is measured */
2804                                    const int center_y,
2805                                          const uint32_t MotionFlags,                                          const uint32_t MotionFlags,
2806                                          MBParam * const pParam,                                  const uint32_t iQuant,
2807                                          MACROBLOCK * const pMBs,                                  const uint32_t iFcode,
2808                                    const MBParam * const pParam,
2809                                    const MACROBLOCK * const pMBs,
2810                                    const MACROBLOCK * const prevMBs,
2811                                          VECTOR * const currMV,                                          VECTOR * const currMV,
2812                                          VECTOR * const currPMV)                                          VECTOR * const currPMV)
2813  {  {
2814          const uint32_t iWcount = pParam->mb_width;          const uint32_t iWcount = pParam->mb_width;
   
         const int32_t iFcode = pParam->fixed_code;  
         const int32_t iQuant = pParam->quant;  
2815          const int32_t iWidth = pParam->width;          const int32_t iWidth = pParam->width;
2816          const int32_t iHeight = pParam->height;          const int32_t iHeight = pParam->height;
2817          const int32_t iEdgedWidth = pParam->edged_width;          const int32_t iEdgedWidth = pParam->edged_width;
2818    
2819          const uint8_t * cur = pCur->y + x*8 + y*8*iEdgedWidth;          const uint8_t *cur = pCur->y + x * 16 + y * 16 * iEdgedWidth;
2820            const VECTOR zeroMV = { 0, 0 };
2821    
2822          int32_t iDiamondSize;          int32_t iDiamondSize;
2823    
# Line 987  Line 2826 
2826          int32_t min_dy;          int32_t min_dy;
2827          int32_t max_dy;          int32_t max_dy;
2828    
2829          VECTOR pmv[4];          int32_t iFound;
2830          int32_t psad[4];  
2831          VECTOR newMV;          VECTOR newMV;
2832          VECTOR backupMV;          VECTOR backupMV;
2833    
2834          MACROBLOCK * const pMB = pMBs + (x>>1) + (y>>1) * iWcount;          VECTOR pmv[4];
2835            int32_t psad[4];
2836    
2837            MainSearch16FuncPtr MainSearchPtr;
2838    
2839          static int32_t threshA,threshB;          MACROBLOCK *const prevMB = (MACROBLOCK *const)prevMBs + x + y * iWcount;
2840          int32_t iFound,bPredEq;          MACROBLOCK *const pMB = (MACROBLOCK *const)(pMBs + x + y * iWcount);
2841    
2842            int32_t threshA, threshB;
2843            int32_t bPredEq;
2844          int32_t iMinSAD,iSAD;          int32_t iMinSAD,iSAD;
2845    
         int32_t iSubBlock = ((y&1)<<1) + (x&1);  
2846    
2847  /* Get maximum range */  /* Get maximum range */
2848      get_range(&min_dx, &max_dx, &min_dy, &max_dy,          get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 16, iWidth, iHeight,
2849                          x, y, 8, iWidth, iHeight, iFcode);                            iFcode);
2850    
2851  /* we work with abs. MVs, not relative to prediction, so range is relative to 0,0 */  /* we work with abs. MVs, not relative to prediction, so get_range is called relative to 0,0 */
2852    
2853          if (!(MotionFlags & PMV_HALFPELDIAMOND8 ))          if ((x == 0) && (y == 0)) {
2854          { min_dx = EVEN(min_dx);                  threshA = 512;
2855            max_dx = EVEN(max_dx);                  threshB = 1024;
           min_dy = EVEN(min_dy);  
           max_dy = EVEN(max_dy);  
         }               /* because we might use IF (dx>max_dx) THEN dx=max_dx; */  
2856    
2857                    bPredEq = 0;
2858                    psad[0] = psad[1] = psad[2] = psad[3] = 0;
2859                    *currMV = pmv[0] = pmv[1] = pmv[2] = pmv[3] = zeroMV;
2860    
2861          bPredEq  = get_pmvdata(pMBs, (x>>1), (y>>1), iWcount, iSubBlock, pmv, psad);          } else {
2862    
2863          if ((x==0) && (y==0) )                  bPredEq = get_ipmvdata(pMBs, iWcount, 0, x, y, 0, pmv, psad);
         {  
                 threshA =  512/4;  
                 threshB = 1024/4;  
2864    
2865          }                  threshA = psad[0];
2866          else                  threshB = threshA + 256;
2867          {                  if (threshA < 512)
2868                  threshA = psad[0]/4;                    /* good estimate */                          threshA = 512;
2869                  threshB = threshA+256/4;                  if (threshA > 1024)
2870                  if (threshA< 512/4) threshA =  512/4;                          threshA = 1024;
2871                  if (threshA>1024/4) threshA = 1024/4;                  if (threshB > 1792)
2872                  if (threshB>1792/4) threshB = 1792/4;                          threshB = 1792;
2873    
2874                    *currMV = pmv[0];                       /* current best := prediction */
2875          }          }
2876    
2877          iFound=0;          iFound=0;
2878    
 /* Step 2: Calculate Distance= |MedianMVX| + |MedianMVY| where MedianMV is the motion  
         vector of the median.  
         If PredEq=1 and MVpredicted = Previous Frame MV, set Found=2  
 */  
   
         if ((bPredEq) && (MVequal(pmv[0],pMB->mvs[iSubBlock]) ) )  
                 iFound=2;  
   
 /* Step 3: If Distance>0 or thresb<1536 or PredEq=1 Select small Diamond Search.  
         Otherwise select large Diamond Search.  
 */  
   
         if ( (pmv[0].x != 0) || (pmv[0].y != 0) || (threshB<1536/4) || (bPredEq) )  
                 iDiamondSize=1; // 1 halfpel!  
         else  
                 iDiamondSize=2; // 2 halfpel = 1 full pixel!  
   
         if (!(MotionFlags & PMV_HALFPELDIAMOND8) )  
                 iDiamondSize*=2;  
   
2879  /* Step 4: Calculate SAD around the Median prediction.  /* Step 4: Calculate SAD around the Median prediction.
2880          MinSAD=SAD          MinSAD=SAD
2881          If Motion Vector equal to Previous frame motion vector          If Motion Vector equal to Previous frame motion vector
# Line 1060  Line 2883 
2883          If SAD<=256 goto Step 10.          If SAD<=256 goto Step 10.
2884  */  */
2885    
2886            if (currMV->x > max_dx) {
2887                    currMV->x = EVEN(max_dx);
2888            }
2889            if (currMV->x < min_dx) {
2890                    currMV->x = EVEN(min_dx);
2891            }
2892            if (currMV->y > max_dy) {
2893                    currMV->y = EVEN(max_dy);
2894            }
2895            if (currMV->y < min_dy) {
2896                    currMV->y = EVEN(min_dy);
2897            }
2898    
2899            iMinSAD =
2900                    sad16(cur,
2901                              get_iref_mv(pRef, x, y, 16, currMV,
2902                                                     iEdgedWidth), iEdgedWidth, MV_MAX_ERROR);
2903            iMinSAD +=
2904                    calc_delta_16(currMV->x - center_x, currMV->y - center_y,
2905                                              (uint8_t) iFcode, iQuant);
2906    
2907            if ((iMinSAD < 256) ||
2908                    ((MVequal(*currMV, prevMB->i_mvs[0])) &&
2909                     ((int32_t) iMinSAD < prevMB->i_sad16))) {
2910                    if (iMinSAD < (int)(2 * iQuant))        // high chances for SKIP-mode
2911                    {
2912                            if (!MVzero(*currMV)) {
2913                                    iMinSAD += MV16_00_BIAS;
2914                                    CHECK_MV16_ZERO;        // (0,0) saves space for letterboxed pictures
2915                                    iMinSAD -= MV16_00_BIAS;
2916                            }
2917                    }
2918    
2919                    if (MotionFlags & PMV_EARLYSTOP16)
2920                            goto PMVfastInt16_Terminate_with_Refine;
2921            }
2922    
 // Prepare for main loop  
2923    
2924          currMV->x=start_x;              /* start with mv16 */  /* Step 2 (lazy eval): Calculate Distance= |MedianMVX| + |MedianMVY| where MedianMV is the motion
2925          currMV->y=start_y;     vector of the median.
2926       If PredEq=1 and MVpredicted = Previous Frame MV, set Found=2
2927    */
2928    
2929          iMinSAD = sad8( cur,          if ((bPredEq) && (MVequal(pmv[0], prevMB->i_mvs[0])))
2930                  get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 8, currMV, iEdgedWidth),                  iFound = 2;
                 iEdgedWidth);  
         iMinSAD += calc_delta_8(currMV->x - pmv[0].x, currMV->y - pmv[0].y, (uint8_t)iFcode) * iQuant;  
2931    
2932          if ( (iMinSAD < 256/4 ) || ( (MVequal(*currMV,pMB->mvs[iSubBlock])) && (iMinSAD < pMB->sad8[iSubBlock]) ) )  /* Step 3 (lazy eval): If Distance>0 or thresb<1536 or PredEq=1 Select small Diamond Search.
2933                  {     Otherwise select large Diamond Search.
2934                          if (MotionFlags & PMV_QUICKSTOP8)  */
2935                                  goto step10_8b;  
2936                          if (MotionFlags & PMV_EARLYSTOP8)          if ((!MVzero(pmv[0])) || (threshB < 1536) || (bPredEq))
2937                                  goto step10_8;                  iDiamondSize = 2;               // halfpel units!
2938                  }          else
2939                    iDiamondSize = 4;               // halfpel units!
2940    
2941  /*  /*
2942  Step 5: Calculate SAD for motion vectors taken from left block, top, top-right, and Previous frame block.  Step 5: Calculate SAD for motion vectors taken from left block, top, top-right, and Previous frame block.
2943          Also calculate (0,0) but do not subtract offset.          Also calculate (0,0) but do not subtract offset.
2944          Let MinSAD be the smallest SAD up to this point.          Let MinSAD be the smallest SAD up to this point.
2945          If MV is (0,0) subtract offset. ******** WHAT'S THIS 'OFFSET' ??? ***********     If MV is (0,0) subtract offset.
2946  */  */
2947    
2948  // the prediction might be even better than mv16  // (0,0) is often a good choice
         CHECK_MV8_CANDIDATE(pmv[0].x,pmv[0].y);  
2949    
2950  // (0,0) is always possible          if (!MVzero(pmv[0]))
2951          CHECK_MV8_ZERO;                  CHECK_MV16_ZERO;
2952    
2953  // previous frame MV is always possible  // previous frame MV is always possible
2954          CHECK_MV8_CANDIDATE(pMB->mvs[iSubBlock].x,pMB->mvs[iSubBlock].y);  
2955            if (!MVzero(prevMB->i_mvs[0]))
2956                    if (!MVequal(prevMB->i_mvs[0], pmv[0]))
2957                            CHECK_MV16_CANDIDATE(prevMB->i_mvs[0].x, prevMB->i_mvs[0].y);
2958    
2959  // left neighbour, if allowed  // left neighbour, if allowed
2960          if (psad[1] != MV_MAX_ERROR)  
2961          {          if (!MVzero(pmv[1]))
2962                  if (!(MotionFlags & PMV_HALFPEL8 ))                  if (!MVequal(pmv[1], prevMB->i_mvs[0]))
2963                  {       pmv[1].x = EVEN(pmv[1].x);                          if (!MVequal(pmv[1], pmv[0]))
2964                          pmv[1].y = EVEN(pmv[1].y);                                  CHECK_MV16_CANDIDATE(pmv[1].x, pmv[1].y);
                 }  
                 CHECK_MV8_CANDIDATE(pmv[1].x,pmv[1].y);  
         }  
2965    
2966  // top neighbour, if allowed  // top neighbour, if allowed
2967          if (psad[2] != MV_MAX_ERROR)          if (!MVzero(pmv[2]))
2968          {                  if (!MVequal(pmv[2], prevMB->i_mvs[0]))
2969                  if (!(MotionFlags & PMV_HALFPEL8 ))                          if (!MVequal(pmv[2], pmv[0]))
2970                  {       pmv[2].x = EVEN(pmv[2].x);                                  if (!MVequal(pmv[2], pmv[1]))
2971                          pmv[2].y = EVEN(pmv[2].y);                                          CHECK_MV16_CANDIDATE(pmv[2].x, pmv[2].y);
                 }  
                 CHECK_MV8_CANDIDATE(pmv[2].x,pmv[2].y);  
2972    
2973  // top right neighbour, if allowed  // top right neighbour, if allowed
2974                  if (psad[3] != MV_MAX_ERROR)                                          if (!MVzero(pmv[3]))
2975                  {                                                  if (!MVequal(pmv[3], prevMB->i_mvs[0]))
2976                  if (!(MotionFlags & PMV_HALFPEL8 ))                                                          if (!MVequal(pmv[3], pmv[0]))
2977                  {       pmv[3].x = EVEN(pmv[3].x);                                                                  if (!MVequal(pmv[3], pmv[1]))
2978                          pmv[3].y = EVEN(pmv[3].y);                                                                          if (!MVequal(pmv[3], pmv[2]))
2979                  }                                                                                  CHECK_MV16_CANDIDATE(pmv[3].x,
2980                          CHECK_MV8_CANDIDATE(pmv[3].x,pmv[3].y);                                                                                                                           pmv[3].y);
2981                  }  
2982          }          if ((MVzero(*currMV)) &&
2983                    (!MVzero(pmv[0])) /* && (iMinSAD <= iQuant * 96) */ )
2984                    iMinSAD -= MV16_00_BIAS;
2985    
2986    
2987  /* Step 6: If MinSAD <= thresa goto Step 10.  /* Step 6: If MinSAD <= thresa goto Step 10.
2988     If Motion Vector equal to Previous frame motion vector and MinSAD<PrevFrmSAD goto Step 10.     If Motion Vector equal to Previous frame motion vector and MinSAD<PrevFrmSAD goto Step 10.
2989  */  */
2990    
2991          if ( (iMinSAD <= threshA) || ( MVequal(*currMV,pMB->mvs[iSubBlock]) && (iMinSAD < pMB->sad8[iSubBlock]) ) )          if ((iMinSAD <= threshA) ||
2992                  {                  (MVequal(*currMV, prevMB->i_mvs[0]) &&
2993                          if (MotionFlags & PMV_QUICKSTOP8)                   ((int32_t) iMinSAD < prevMB->i_sad16))) {
2994                                  goto step10_8b;  
2995                          if (MotionFlags & PMV_EARLYSTOP8)                  if (MotionFlags & PMV_EARLYSTOP16)
2996                                  goto step10_8;                          goto PMVfastInt16_Terminate_with_Refine;
2997                  }                  }
2998    
2999    
3000  /************ (Diamond Search)  **************/  /************ (Diamond Search)  **************/
3001  /*  /*
3002  Step 7: Perform Diamond search, with either the small or large diamond.  Step 7: Perform Diamond search, with either the small or large diamond.
# Line 1147  Line 3007 
3007          Refine by using small diamond and goto step 10.          Refine by using small diamond and goto step 10.
3008  */  */
3009    
3010            if (MotionFlags & PMV_USESQUARES16)
3011                    MainSearchPtr = Square16_MainSearch;
3012            else if (MotionFlags & PMV_ADVANCEDDIAMOND16)
3013                    MainSearchPtr = AdvDiamond16_MainSearch;
3014            else
3015                    MainSearchPtr = Diamond16_MainSearch;
3016    
3017          backupMV = *currMV; /* save best prediction, actually only for EXTSEARCH */          backupMV = *currMV; /* save best prediction, actually only for EXTSEARCH */
3018    
3019    
3020  /* default: use best prediction as starting point for one call of PMVfast_MainSearch */  /* default: use best prediction as starting point for one call of PMVfast_MainSearch */
3021          iSAD = PMVfastSearch8_MainSearch(pRef, pRefH, pRefV, pRefHV, cur,          iSAD =
3022                  x, y,                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV->x,
3023                  currMV->x, currMV->y, iMinSAD, &newMV,                                                    currMV->y, iMinSAD, &newMV, center_x, center_y, min_dx, max_dx,
3024                  pmv, min_dx, max_dx, min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode, iQuant, iFound);                                                    min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode,
3025                                                      iQuant, iFound);
3026    
3027          if (iSAD < iMinSAD)          if (iSAD < iMinSAD) {
         {  
3028                  *currMV = newMV;                  *currMV = newMV;
3029                  iMinSAD = iSAD;                  iMinSAD = iSAD;
3030          }          }
3031    
3032          if (MotionFlags & PMV_EXTSEARCH8)          if (MotionFlags & PMV_EXTSEARCH16) {
         {  
3033  /* extended: search (up to) two more times: orignal prediction and (0,0) */  /* extended: search (up to) two more times: orignal prediction and (0,0) */
3034    
3035                  if (!(MVequal(pmv[0],backupMV)) )                  if (!(MVequal(pmv[0], backupMV))) {
3036                  {       iSAD = PMVfastSearch16_MainSearch(pRef, pRefH, pRefV, pRefHV, cur,                          iSAD =
3037                                  x, y,                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,
3038                          pmv[0].x, pmv[0].y, iMinSAD, &newMV,                                                                    pmv[0].x, pmv[0].y, iMinSAD, &newMV, center_x, center_y,
3039                          pmv, min_dx, max_dx, min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode, iQuant, iFound);                                                                    min_dx, max_dx, min_dy, max_dy, iEdgedWidth,
3040                                                                      iDiamondSize, iFcode, iQuant, iFound);
3041    
3042                          if (iSAD < iMinSAD)                          if (iSAD < iMinSAD) {
                         {  
3043                                  *currMV = newMV;                                  *currMV = newMV;
3044                                  iMinSAD = iSAD;                                  iMinSAD = iSAD;
3045                          }                          }
3046                  }                  }
3047    
3048                  if ( (!(MVzero(pmv[0]))) && (!(MVzero(backupMV))) )                  if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {
3049                  {       iSAD = PMVfastSearch16_MainSearch(pRef, pRefH, pRefV, pRefHV, cur,                          iSAD =
3050                                  x, y,                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, 0, 0,
3051                          0, 0, iMinSAD, &newMV,                                                                    iMinSAD, &newMV, center_x, center_y, min_dx, max_dx, min_dy,
3052                          pmv, min_dx, max_dx, min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode, iQuant, iFound);                                                                    max_dy, iEdgedWidth, iDiamondSize, iFcode,
3053                                                                      iQuant, iFound);
3054    
3055                          if (iSAD < iMinSAD)                          if (iSAD < iMinSAD) {
                         {  
3056                                  *currMV = newMV;                                  *currMV = newMV;
3057                                  iMinSAD = iSAD;                                  iMinSAD = iSAD;
3058                          }                          }
3059                  }                  }
3060          }          }
3061    
3062  /* Step 10: The motion vector is chosen according to the block corresponding to MinSAD.  /*
3063           By performing an optional local half-pixel search, we can refine this result even further.     Step 10:  The motion vector is chosen according to the block corresponding to MinSAD.
3064  */  */
3065    
3066  step10_8:  PMVfastInt16_Terminate_with_Refine:
         if (MotionFlags & PMV_HALFPELREFINE8)           // perform final half-pel step  
                 iMinSAD = PMVfastSearch8_Refine( pRef, pRefH, pRefV, pRefHV, cur,  
                                 x, y,  
                                 currMV, iMinSAD,  
                                 pmv, min_dx, max_dx, min_dy, max_dy, iFcode, iQuant, iEdgedWidth);  
3067    
3068  step10_8b:          pMB->i_mvs[0] = pMB->i_mvs[1] = pMB->i_mvs[2] = pMB->i_mvs[3] = pMB->i_mv16 = *currMV;
3069            pMB->i_sad8[0] = pMB->i_sad8[1] = pMB->i_sad8[2] = pMB->i_sad8[3] = pMB->i_sad16 = iMinSAD;
3070    
3071            if (MotionFlags & PMV_HALFPELREFINE16)  // perform final half-pel step
3072                    iMinSAD =
3073                            Halfpel16_Refine(pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV,
3074                                                             iMinSAD, center_x, center_y, min_dx, max_dx, min_dy, max_dy,
3075                                                             iFcode, iQuant, iEdgedWidth);
3076    
3077          currPMV->x = currMV->x - pmv[0].x;          pmv[0] = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 0);          // get _REAL_ prediction (halfpel possible)
         currPMV->y = currMV->y - pmv[0].y;  
3078    
3079            currPMV->x = currMV->x - center_x;
3080            currPMV->y = currMV->y - center_y;
3081          return iMinSAD;          return iMinSAD;
3082  }  }
3083    #endif /* 0 */

Legend:
Removed from v.3  
changed lines
  Added in v.504

No admin address has been configured
ViewVC Help
Powered by ViewVC 1.0.4