[svn] / trunk / xvidcore / src / motion / motion_est.c Repository:
ViewVC logotype

Diff of /trunk/xvidcore/src/motion/motion_est.c

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

revision 430, Fri Sep 6 16:59:47 2002 UTC revision 1001, Sat May 3 10:05:55 2003 UTC
# Line 1  Line 1 
1  /*****************************************************************************  /**************************************************************************
2   *   *
3   *  XVID MPEG-4 VIDEO CODEC   *  XVID MPEG-4 VIDEO CODEC
4   *  - Motion Estimation module -   *      motion estimation
  *  
  *  Copyright(C) 2002 Christoph Lampert <gruel@web.de>  
  *  Copyright(C) 2002 Michael Militzer <michael@xvid.org>  
  *  Copyright(C) 2002 Edouard Gomez <ed.gomez@wanadoo.fr>  
  *  Copyright(C) 2002 chenm001 <chenm001@163.com>  
5   *   *
6   *  This program is an implementation of a part of one or more MPEG-4   *  This program is an implementation of a part of one or more MPEG-4
7   *  Video tools as specified in ISO/IEC 14496-2 standard.  Those intending   *  Video tools as specified in ISO/IEC 14496-2 standard.  Those intending
# Line 29  Line 24 
24   *   *
25   *  You should have received a copy of the GNU General Public License   *  You should have received a copy of the GNU General Public License
26   *  along with this program; if not, write to the Free Software   *  along with this program; if not, write to the Free Software
27   *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA   *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
28   *   *
29   *************************************************************************/   *************************************************************************/
30    
31  #include <assert.h>  #include <assert.h>
32  #include <stdio.h>  #include <stdio.h>
33  #include <stdlib.h>  #include <stdlib.h>
34    #include <string.h>     // memcpy
35    #include <math.h>       // lrint
36    
37  #include "../encoder.h"  #include "../encoder.h"
38  #include "../utils/mbfunctions.h"  #include "../utils/mbfunctions.h"
39  #include "../prediction/mbprediction.h"  #include "../prediction/mbprediction.h"
40  #include "../global.h"  #include "../global.h"
41  #include "../utils/timer.h"  #include "../utils/timer.h"
42    #include "../image/interpolate8x8.h"
43    #include "motion_est.h"
44  #include "motion.h"  #include "motion.h"
45  #include "sad.h"  #include "sad.h"
46    #include "../utils/emms.h"
47    #include "../dct/fdct.h"
48    
49    /*****************************************************************************
50     * Modified rounding tables -- declared in motion.h
51     * Original tables see ISO spec tables 7-6 -> 7-9
52     ****************************************************************************/
53    
54    const uint32_t roundtab[16] =
55    {0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2 };
56    
57    /* K = 4 */
58    const uint32_t roundtab_76[16] =
59    { 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1 };
60    
61    /* K = 2 */
62    const uint32_t roundtab_78[8] =
63    { 0, 0, 1, 1, 0, 0, 0, 1  };
64    
65    /* K = 1 */
66    const uint32_t roundtab_79[4] =
67    { 0, 1, 0, 0 };
68    
69    #define INITIAL_SKIP_THRESH     (10)
70    #define FINAL_SKIP_THRESH       (50)
71    #define MAX_SAD00_FOR_SKIP      (20)
72    #define MAX_CHROMA_SAD_FOR_SKIP (22)
73    
74    #define CHECK_CANDIDATE(X,Y,D) { \
75    CheckCandidate((X),(Y), (D), &iDirection, data ); }
76    
77  static int32_t lambda_vec16[32] =       /* rounded values for lambda param for weight of motion bits as in modified H.26L */  /*****************************************************************************
78  { 0, (int) (1.00235 + 0.5), (int) (1.15582 + 0.5), (int) (1.31976 + 0.5),   * Code
79                  (int) (1.49591 + 0.5), (int) (1.68601 + 0.5),   ****************************************************************************/
         (int) (1.89187 + 0.5), (int) (2.11542 + 0.5), (int) (2.35878 + 0.5),  
                 (int) (2.62429 + 0.5), (int) (2.91455 + 0.5),  
         (int) (3.23253 + 0.5), (int) (3.58158 + 0.5), (int) (3.96555 + 0.5),  
                 (int) (4.38887 + 0.5), (int) (4.85673 + 0.5),  
         (int) (5.37519 + 0.5), (int) (5.95144 + 0.5), (int) (6.59408 + 0.5),  
                 (int) (7.31349 + 0.5), (int) (8.12242 + 0.5),  
         (int) (9.03669 + 0.5), (int) (10.0763 + 0.5), (int) (11.2669 + 0.5),  
                 (int) (12.6426 + 0.5), (int) (14.2493 + 0.5),  
         (int) (16.1512 + 0.5), (int) (18.442 + 0.5), (int) (21.2656 + 0.5),  
                 (int) (24.8580 + 0.5), (int) (29.6436 + 0.5),  
         (int) (36.4949 + 0.5)  
 };  
   
 static int32_t *lambda_vec8 = lambda_vec16;     /* same table for INTER and INTER4V for now */  
   
   
   
 // mv.length table  
 static const uint32_t mvtab[33] = {  
         1, 2, 3, 4, 6, 7, 7, 7,  
         9, 9, 9, 10, 10, 10, 10, 10,  
         10, 10, 10, 10, 10, 10, 10, 10,  
         10, 11, 11, 11, 11, 11, 11, 12, 12  
 };  
   
80    
81  static __inline uint32_t  static __inline uint32_t
82  mv_bits(int32_t component,  d_mv_bits(int x, int y, const VECTOR pred, const uint32_t iFcode, const int qpel, const int rrv)
                 const uint32_t iFcode)  
83  {  {
84          if (component == 0)          int bits;
85                  return 1;          const int q = (1 << (iFcode - 1)) - 1;
86    
87            x <<= qpel;
88            y <<= qpel;
89            if (rrv) { x = RRV_MV_SCALEDOWN(x); y = RRV_MV_SCALEDOWN(y); }
90    
91            x -= pred.x;
92            bits = (x != 0 ? iFcode:0);
93            x = abs(x);
94            x += q;
95            x >>= (iFcode - 1);
96            bits += mvtab[x];
97    
98            y -= pred.y;
99            bits += (y != 0 ? iFcode:0);
100            y = abs(y);
101            y += q;
102            y >>= (iFcode - 1);
103            bits += mvtab[y];
104    
105            return bits;
106    }
107    
108    static int32_t ChromaSAD2(const int fx, const int fy, const int bx, const int by,
109                                                            const SearchData * const data)
110    {
111            int sad;
112            const uint32_t stride = data->iEdgedWidth/2;
113            uint8_t * f_refu = data->RefQ,
114                    * f_refv = data->RefQ + 8,
115                    * b_refu = data->RefQ + 16,
116                    * b_refv = data->RefQ + 24;
117            int offset = (fx>>1) + (fy>>1)*stride;
118    
119            switch (((fx & 1) << 1) | (fy & 1))     {
120                    case 0:
121                            f_refu = (uint8_t*)data->RefP[4] + offset;
122                            f_refv = (uint8_t*)data->RefP[5] + offset;
123                            break;
124                    case 1:
125                            interpolate8x8_halfpel_v(f_refu, data->RefP[4] + offset, stride, data->rounding);
126                            interpolate8x8_halfpel_v(f_refv, data->RefP[5] + offset, stride, data->rounding);
127                            break;
128                    case 2:
129                            interpolate8x8_halfpel_h(f_refu, data->RefP[4] + offset, stride, data->rounding);
130                            interpolate8x8_halfpel_h(f_refv, data->RefP[5] + offset, stride, data->rounding);
131                            break;
132                    default:
133                            interpolate8x8_halfpel_hv(f_refu, data->RefP[4] + offset, stride, data->rounding);
134                            interpolate8x8_halfpel_hv(f_refv, data->RefP[5] + offset, stride, data->rounding);
135                            break;
136            }
137    
138          if (component < 0)          offset = (bx>>1) + (by>>1)*stride;
139                  component = -component;          switch (((bx & 1) << 1) | (by & 1))     {
140                    case 0:
141                            b_refu = (uint8_t*)data->b_RefP[4] + offset;
142                            b_refv = (uint8_t*)data->b_RefP[5] + offset;
143                            break;
144                    case 1:
145                            interpolate8x8_halfpel_v(b_refu, data->b_RefP[4] + offset, stride, data->rounding);
146                            interpolate8x8_halfpel_v(b_refv, data->b_RefP[5] + offset, stride, data->rounding);
147                            break;
148                    case 2:
149                            interpolate8x8_halfpel_h(b_refu, data->b_RefP[4] + offset, stride, data->rounding);
150                            interpolate8x8_halfpel_h(b_refv, data->b_RefP[5] + offset, stride, data->rounding);
151                            break;
152                    default:
153                            interpolate8x8_halfpel_hv(b_refu, data->b_RefP[4] + offset, stride, data->rounding);
154                            interpolate8x8_halfpel_hv(b_refv, data->b_RefP[5] + offset, stride, data->rounding);
155                            break;
156            }
157    
158          if (iFcode == 1) {          sad = sad8bi(data->CurU, b_refu, f_refu, stride);
159                  if (component > 32)          sad += sad8bi(data->CurV, b_refv, f_refv, stride);
                         component = 32;  
160    
161                  return mvtab[component] + 1;          return sad;
162          }          }
163    
164          component += (1 << (iFcode - 1)) - 1;  static int32_t
165          component >>= (iFcode - 1);  ChromaSAD(const int dx, const int dy, const SearchData * const data)
166    {
167            int sad;
168            const uint32_t stride = data->iEdgedWidth/2;
169            int offset = (dx>>1) + (dy>>1)*stride;
170    
171          if (component > 32)          if (dx == data->temp[5] && dy == data->temp[6]) return data->temp[7]; //it has been checked recently
172                  component = 32;          data->temp[5] = dx; data->temp[6] = dy; // backup
173    
174          return mvtab[component] + 1 + iFcode - 1;          switch (((dx & 1) << 1) | (dy & 1))     {
175  }                  case 0:
176                            sad = sad8(data->CurU, data->RefP[4] + offset, stride);
177                            sad += sad8(data->CurV, data->RefP[5] + offset, stride);
178                            break;
179                    case 1:
180                            sad = sad8bi(data->CurU, data->RefP[4] + offset, data->RefP[4] + offset + stride, stride);
181                            sad += sad8bi(data->CurV, data->RefP[5] + offset, data->RefP[5] + offset + stride, stride);
182                            break;
183                    case 2:
184                            sad = sad8bi(data->CurU, data->RefP[4] + offset, data->RefP[4] + offset + 1, stride);
185                            sad += sad8bi(data->CurV, data->RefP[5] + offset, data->RefP[5] + offset + 1, stride);
186                            break;
187                    default:
188                            interpolate8x8_halfpel_hv(data->RefQ, data->RefP[4] + offset, stride, data->rounding);
189                            sad = sad8(data->CurU, data->RefQ, stride);
190    
191                            interpolate8x8_halfpel_hv(data->RefQ, data->RefP[5] + offset, stride, data->rounding);
192                            sad += sad8(data->CurV, data->RefQ, stride);
193                            break;
194            }
195            data->temp[7] = sad; //backup, part 2
196            return sad;
197    }
198    
199  static __inline uint32_t  static __inline const uint8_t *
200  calc_delta_16(const int32_t dx,  GetReferenceB(const int x, const int y, const uint32_t dir, const SearchData * const data)
                           const int32_t dy,  
                           const uint32_t iFcode,  
                           const uint32_t iQuant)  
201  {  {
202          return NEIGH_TEND_16X16 * lambda_vec16[iQuant] * (mv_bits(dx, iFcode) +  //      dir : 0 = forward, 1 = backward
203                                                                                                            mv_bits(dy, iFcode));          const uint8_t *const *const direction = ( dir == 0 ? data->RefP : data->b_RefP );
204            const int picture = ((x&1)<<1) | (y&1);
205            const int offset = (x>>1) + (y>>1)*data->iEdgedWidth;
206            return direction[picture] + offset;
207  }  }
208    
209  static __inline uint32_t  // this is a simpler copy of GetReferenceB, but as it's __inline anyway, we can keep the two separate
210  calc_delta_8(const int32_t dx,  static __inline const uint8_t *
211                           const int32_t dy,  GetReference(const int x, const int y, const SearchData * const data)
                          const uint32_t iFcode,  
                          const uint32_t iQuant)  
212  {  {
213          return NEIGH_TEND_8X8 * lambda_vec8[iQuant] * (mv_bits(dx, iFcode) +          const int picture = ((x&1)<<1) | (y&1);
214                                                                                                     mv_bits(dy, iFcode));          const int offset = (x>>1) + (y>>1)*data->iEdgedWidth;
215            return data->RefP[picture] + offset;
216  }  }
217    
218  bool  static uint8_t *
219  MotionEstimation(MBParam * const pParam,  Interpolate8x8qpel(const int x, const int y, const uint32_t block, const uint32_t dir, const SearchData * const data)
                                  FRAMEINFO * const current,  
                                  FRAMEINFO * const reference,  
                                  const IMAGE * const pRefH,  
                                  const IMAGE * const pRefV,  
                                  const IMAGE * const pRefHV,  
                                  const uint32_t iLimit)  
220  {  {
221          const uint32_t iWcount = pParam->mb_width;  // create or find a qpel-precision reference picture; return pointer to it
222          const uint32_t iHcount = pParam->mb_height;          uint8_t * Reference = data->RefQ + 16*dir;
223          MACROBLOCK *const pMBs = current->mbs;          const uint32_t iEdgedWidth = data->iEdgedWidth;
224          MACROBLOCK *const prevMBs = reference->mbs;          const uint32_t rounding = data->rounding;
225          const IMAGE *const pCurrent = &current->image;          const int halfpel_x = x/2;
226          const IMAGE *const pRef = &reference->image;          const int halfpel_y = y/2;
227            const uint8_t *ref1, *ref2, *ref3, *ref4;
228    
229          static const VECTOR zeroMV = { 0, 0 };          ref1 = GetReferenceB(halfpel_x, halfpel_y, dir, data);
230          VECTOR predMV;          ref1 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth;
231            switch( ((x&1)<<1) + (y&1) ) {
232            case 3: // x and y in qpel resolution - the "corners" (top left/right and
233                            // bottom left/right) during qpel refinement
234                    ref2 = GetReferenceB(halfpel_x, y - halfpel_y, dir, data);
235                    ref3 = GetReferenceB(x - halfpel_x, halfpel_y, dir, data);
236                    ref4 = GetReferenceB(x - halfpel_x, y - halfpel_y, dir, data);
237                    ref2 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth;
238                    ref3 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth;
239                    ref4 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth;
240                    interpolate8x8_avg4(Reference, ref1, ref2, ref3, ref4, iEdgedWidth, rounding);
241                    break;
242    
243          int32_t x, y;          case 1: // x halfpel, y qpel - top or bottom during qpel refinement
244          int32_t iIntra = 0;                  ref2 = GetReferenceB(halfpel_x, y - halfpel_y, dir, data);
245          VECTOR pmv;                  ref2 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth;
246                    interpolate8x8_avg2(Reference, ref1, ref2, iEdgedWidth, rounding, 8);
247                    break;
248    
249          if (sadInit)          case 2: // x qpel, y halfpel - left or right during qpel refinement
250                  (*sadInit) ();                  ref2 = GetReferenceB(x - halfpel_x, halfpel_y, dir, data);
251                    ref2 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth;
252                    interpolate8x8_avg2(Reference, ref1, ref2, iEdgedWidth, rounding, 8);
253                    break;
254    
255          for (y = 0; y < iHcount; y++)   {          default: // pure halfpel position
256                  for (x = 0; x < iWcount; x ++)  {                  return (uint8_t *) ref1;
257    
258                          MACROBLOCK *const pMB = &pMBs[x + y * iWcount];          }
259            return Reference;
260    }
261    
262                          if (pMB->mode == MODE_NOT_CODED)  static uint8_t *
263                                  continue;  Interpolate16x16qpel(const int x, const int y, const uint32_t dir, const SearchData * const data)
264    {
265    // create or find a qpel-precision reference picture; return pointer to it
266            uint8_t * Reference = data->RefQ + 16*dir;
267            const uint32_t iEdgedWidth = data->iEdgedWidth;
268            const uint32_t rounding = data->rounding;
269            const int halfpel_x = x/2;
270            const int halfpel_y = y/2;
271            const uint8_t *ref1, *ref2, *ref3, *ref4;
272    
273                          predMV = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 0);          ref1 = GetReferenceB(halfpel_x, halfpel_y, dir, data);
274            switch( ((x&1)<<1) + (y&1) ) {
275            case 3: // x and y in qpel resolution - the "corners" (top left/right and
276                            // bottom left/right) during qpel refinement
277                    ref2 = GetReferenceB(halfpel_x, y - halfpel_y, dir, data);
278                    ref3 = GetReferenceB(x - halfpel_x, halfpel_y, dir, data);
279                    ref4 = GetReferenceB(x - halfpel_x, y - halfpel_y, dir, data);
280                    interpolate8x8_avg4(Reference, ref1, ref2, ref3, ref4, iEdgedWidth, rounding);
281                    interpolate8x8_avg4(Reference+8, ref1+8, ref2+8, ref3+8, ref4+8, iEdgedWidth, rounding);
282                    interpolate8x8_avg4(Reference+8*iEdgedWidth, ref1+8*iEdgedWidth, ref2+8*iEdgedWidth, ref3+8*iEdgedWidth, ref4+8*iEdgedWidth, iEdgedWidth, rounding);
283                    interpolate8x8_avg4(Reference+8*iEdgedWidth+8, ref1+8*iEdgedWidth+8, ref2+8*iEdgedWidth+8, ref3+8*iEdgedWidth+8, ref4+8*iEdgedWidth+8, iEdgedWidth, rounding);
284                    break;
285    
286                          pMB->sad16 =          case 1: // x halfpel, y qpel - top or bottom during qpel refinement
287                                  SEARCH16(pRef->y, pRefH->y, pRefV->y, pRefHV->y, pCurrent,                  ref2 = GetReferenceB(halfpel_x, y - halfpel_y, dir, data);
288                                                   x, y, predMV.x, predMV.y, predMV.x, predMV.y,                  interpolate8x8_avg2(Reference, ref1, ref2, iEdgedWidth, rounding, 8);
289                                                   current->motion_flags, current->quant,                  interpolate8x8_avg2(Reference+8, ref1+8, ref2+8, iEdgedWidth, rounding, 8);
290                                                   current->fcode, pParam, pMBs, prevMBs, &pMB->mv16,                  interpolate8x8_avg2(Reference+8*iEdgedWidth, ref1+8*iEdgedWidth, ref2+8*iEdgedWidth, iEdgedWidth, rounding, 8);
291                                                   &pMB->pmvs[0]);                  interpolate8x8_avg2(Reference+8*iEdgedWidth+8, ref1+8*iEdgedWidth+8, ref2+8*iEdgedWidth+8, iEdgedWidth, rounding, 8);
292                    break;
293    
294                          if (0 < (pMB->sad16 - MV16_INTER_BIAS)) {          case 2: // x qpel, y halfpel - left or right during qpel refinement
295                                  int32_t deviation;                  ref2 = GetReferenceB(x - halfpel_x, halfpel_y, dir, data);
296                    interpolate8x8_avg2(Reference, ref1, ref2, iEdgedWidth, rounding, 8);
297                    interpolate8x8_avg2(Reference+8, ref1+8, ref2+8, iEdgedWidth, rounding, 8);
298                    interpolate8x8_avg2(Reference+8*iEdgedWidth, ref1+8*iEdgedWidth, ref2+8*iEdgedWidth, iEdgedWidth, rounding, 8);
299                    interpolate8x8_avg2(Reference+8*iEdgedWidth+8, ref1+8*iEdgedWidth+8, ref2+8*iEdgedWidth+8, iEdgedWidth, rounding, 8);
300                    break;
301    
302                                  deviation =          default: // pure halfpel position
303                                          dev16(pCurrent->y + x * 16 + y * 16 * pParam->edged_width,                  return (uint8_t *) ref1;
304                                                    pParam->edged_width);          }
305            return Reference;
306    }
307    
308                                  if (deviation < (pMB->sad16 - MV16_INTER_BIAS)) {  /* CHECK_CANDIATE FUNCTIONS START */
                                         pMB->mode = MODE_INTRA;  
                                         pMB->mv16 = pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] =  
                                                 pMB->mvs[3] = zeroMV;  
                                         pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] =  
                                                 pMB->sad8[3] = 0;  
309    
310                                          iIntra++;  static void
311                                          if (iIntra >= iLimit)  CheckCandidate16(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
312                                                  return 1;  {
313            int xc, yc;
314            const uint8_t * Reference;
315            VECTOR * current;
316            int32_t sad; uint32_t t;
317    
318                                          continue;          if ( (x > data->max_dx) || (x < data->min_dx)
319                                  }                  || (y > data->max_dy) || (y < data->min_dy) ) return;
                         }  
320    
321                          pmv = pMB->pmvs[0];          if (!data->qpel_precision) {
322                          if (current->global_flags & XVID_INTER4V)                  Reference = GetReference(x, y, data);
323                                  if ((!(current->global_flags & XVID_LUMIMASKING) ||                  current = data->currentMV;
324                                           pMB->dquant == NO_CHANGE)) {                  xc = x; yc = y;
325                                          int32_t sad8 = IMV16X16 * current->quant;          } else { // x and y are in 1/4 precision
326                    Reference = Interpolate16x16qpel(x, y, 0, data);
327                                          if (sad8 < pMB->sad16) {                  xc = x/2; yc = y/2; //for chroma sad
328                                                  sad8 += pMB->sad8[0] =                  current = data->currentQMV;
                                                         SEARCH8(pRef->y, pRefH->y, pRefV->y, pRefHV->y,  
                                                                         pCurrent, 2 * x, 2 * y,  
                                                                         pMB->mv16.x, pMB->mv16.y, predMV.x, predMV.y,  
                                                                         current->motion_flags,  
                                                                         current->quant, current->fcode, pParam,  
                                                                         pMBs, prevMBs, &pMB->mvs[0],  
                                                                         &pMB->pmvs[0]);  
                                         }  
                                         if (sad8 < pMB->sad16) {  
   
                                                 predMV = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 1);  
                                                 sad8 += pMB->sad8[1] =  
                                                         SEARCH8(pRef->y, pRefH->y, pRefV->y, pRefHV->y,  
                                                                         pCurrent, 2 * x + 1, 2 * y,  
                                                                         pMB->mv16.x, pMB->mv16.y, predMV.x, predMV.y,  
                                                                         current->motion_flags,  
                                                                         current->quant, current->fcode, pParam,  
                                                                         pMBs, prevMBs, &pMB->mvs[1],  
                                                                         &pMB->pmvs[1]);  
                                         }  
                                         if (sad8 < pMB->sad16) {  
                                                 predMV = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 2);  
                                                 sad8 += pMB->sad8[2] =  
                                                         SEARCH8(pRef->y, pRefH->y, pRefV->y, pRefHV->y,  
                                                                         pCurrent, 2 * x, 2 * y + 1,  
                                                                         pMB->mv16.x, pMB->mv16.y, predMV.x, predMV.y,  
                                                                         current->motion_flags,  
                                                                         current->quant, current->fcode, pParam,  
                                                                         pMBs, prevMBs, &pMB->mvs[2],  
                                                                         &pMB->pmvs[2]);  
                                         }  
                                         if (sad8 < pMB->sad16) {  
                                                 predMV = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 3);  
                                                 sad8 += pMB->sad8[3] =  
                                                         SEARCH8(pRef->y, pRefH->y, pRefV->y, pRefHV->y,  
                                                                         pCurrent, 2 * x + 1, 2 * y + 1,  
                                                                         pMB->mv16.x, pMB->mv16.y, predMV.x, predMV.y,  
                                                                         current->motion_flags,  
                                                                         current->quant, current->fcode, pParam,  
                                                                         pMBs, prevMBs,  
                                                                         &pMB->mvs[3],  
                                                                         &pMB->pmvs[3]);  
329                                          }                                          }
330    
331                                          /* decide: MODE_INTER or MODE_INTER4V          sad = sad16v(data->Cur, Reference, data->iEdgedWidth, data->temp + 1);
332                                             mpeg4:   if (sad8 < pMB->sad16 - nb/2+1) use_inter4v          t = d_mv_bits(x, y, data->predMV, data->iFcode, data->qpel^data->qpel_precision, 0);
                                          */  
333    
334                                          if (sad8 < pMB->sad16) {          sad += (data->lambda16 * t * sad)>>10;
335                                                  pMB->mode = MODE_INTER4V;          data->temp[1] += (data->lambda8 * t * (data->temp[1] + NEIGH_8X8_BIAS))>>10;
                                                 pMB->sad8[0] *= 4;  
                                                 pMB->sad8[1] *= 4;  
                                                 pMB->sad8[2] *= 4;  
                                                 pMB->sad8[3] *= 4;  
                                                 continue;  
                                         }  
336    
337                                  }          if (data->chroma) sad += ChromaSAD(     (xc >> 1) + roundtab_79[xc & 0x3],
338                                                                                    (yc >> 1) + roundtab_79[yc & 0x3], data);
339    
340                          pMB->mode = MODE_INTER;          if (sad < data->iMinSAD[0]) {
341                          pMB->pmvs[0] = pmv;     /* pMB->pmvs[1] = pMB->pmvs[2] = pMB->pmvs[3]  are not needed for INTER */                  data->iMinSAD[0] = sad;
342                          pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = pMB->mv16;                  current[0].x = x; current[0].y = y;
343                          pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] = pMB->sad8[3] =                  *dir = Direction;
                                 pMB->sad16;  
344                          }                          }
345    
346            if (data->temp[1] < data->iMinSAD[1]) {
347                    data->iMinSAD[1] = data->temp[1]; current[1].x = x; current[1].y = y; }
348            if (data->temp[2] < data->iMinSAD[2]) {
349                    data->iMinSAD[2] = data->temp[2]; current[2].x = x; current[2].y = y; }
350            if (data->temp[3] < data->iMinSAD[3]) {
351                    data->iMinSAD[3] = data->temp[3]; current[3].x = x; current[3].y = y; }
352            if (data->temp[4] < data->iMinSAD[4]) {
353                    data->iMinSAD[4] = data->temp[4]; current[4].x = x; current[4].y = y; }
354                          }                          }
355    
356          return 0;  static void
357    CheckCandidate8(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
358    {
359            int32_t sad; uint32_t t;
360            const uint8_t * Reference;
361            VECTOR * current;
362    
363            if ( (x > data->max_dx) || (x < data->min_dx)
364                    || (y > data->max_dy) || (y < data->min_dy) ) return;
365    
366            if (!data->qpel_precision) {
367                    Reference = GetReference(x, y, data);
368                    current = data->currentMV;
369            } else { // x and y are in 1/4 precision
370                    Reference = Interpolate8x8qpel(x, y, 0, 0, data);
371                    current = data->currentQMV;
372  }  }
373    
374            sad = sad8(data->Cur, Reference, data->iEdgedWidth);
375            t = d_mv_bits(x, y, data->predMV, data->iFcode, data->qpel^data->qpel_precision, 0);
376    
377  #define CHECK_MV16_ZERO {\          sad += (data->lambda8 * t * (sad+NEIGH_8X8_BIAS))>>10;
378    if ( (0 <= max_dx) && (0 >= min_dx) \  
379      && (0 <= max_dy) && (0 >= min_dy) ) \          if (sad < *(data->iMinSAD)) {
380    { \                  *(data->iMinSAD) = sad;
381      iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, 0, 0 , iEdgedWidth), iEdgedWidth, MV_MAX_ERROR); \                  current->x = x; current->y = y;
382      iSAD += calc_delta_16(-center_x, -center_y, (uint8_t)iFcode, iQuant);\                  *dir = Direction;
383      if (iSAD < iMinSAD) \          }
384      {  iMinSAD=iSAD; currMV->x=0; currMV->y=0; }  }     \  }
385  }  
386    static void
387  #define NOCHECK_MV16_CANDIDATE(X,Y) { \  CheckCandidate32(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
     iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, X, Y, iEdgedWidth),iEdgedWidth, iMinSAD); \  
     iSAD += calc_delta_16((X) - center_x, (Y) - center_y, (uint8_t)iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); } \  
 }  
   
 #define CHECK_MV16_CANDIDATE(X,Y) { \  
   if ( ((X) <= max_dx) && ((X) >= min_dx) \  
     && ((Y) <= max_dy) && ((Y) >= min_dy) ) \  
   { \  
     iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, X, Y, iEdgedWidth),iEdgedWidth, iMinSAD); \  
     iSAD += calc_delta_16((X) - center_x, (Y) - center_y, (uint8_t)iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); } } \  
 }  
   
 #define CHECK_MV16_CANDIDATE_DIR(X,Y,D) { \  
   if ( ((X) <= max_dx) && ((X) >= min_dx) \  
     && ((Y) <= max_dy) && ((Y) >= min_dy) ) \  
   { \  
     iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, X, Y, iEdgedWidth),iEdgedWidth, iMinSAD); \  
     iSAD += calc_delta_16((X) - center_x, (Y) - center_y, (uint8_t)iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iDirection=(D); } } \  
 }  
   
 #define CHECK_MV16_CANDIDATE_FOUND(X,Y,D) { \  
   if ( ((X) <= max_dx) && ((X) >= min_dx) \  
     && ((Y) <= max_dy) && ((Y) >= min_dy) ) \  
   { \  
     iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, X, Y, iEdgedWidth),iEdgedWidth, iMinSAD); \  
     iSAD += calc_delta_16((X) - center_x, (Y) - center_y, (uint8_t)iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iDirection=(D); iFound=0; } } \  
 }  
   
   
 #define CHECK_MV8_ZERO {\  
   iSAD = sad8( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 8, 0, 0 , iEdgedWidth), iEdgedWidth); \  
   iSAD += calc_delta_8(-center_x, -center_y, (uint8_t)iFcode, iQuant);\  
   if (iSAD < iMinSAD) \  
   { iMinSAD=iSAD; currMV->x=0; currMV->y=0; } \  
 }  
   
 #define NOCHECK_MV8_CANDIDATE(X,Y) \  
   { \  
     iSAD = sad8( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 8, (X), (Y), iEdgedWidth),iEdgedWidth); \  
     iSAD += calc_delta_8((X)-center_x, (Y)-center_y, (uint8_t)iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); } \  
 }  
   
 #define CHECK_MV8_CANDIDATE(X,Y) { \  
   if ( ((X) <= max_dx) && ((X) >= min_dx) \  
     && ((Y) <= max_dy) && ((Y) >= min_dy) ) \  
   { \  
     iSAD = sad8( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 8, (X), (Y), iEdgedWidth),iEdgedWidth); \  
     iSAD += calc_delta_8((X)-center_x, (Y)-center_y, (uint8_t)iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); } } \  
 }  
   
 #define CHECK_MV8_CANDIDATE_DIR(X,Y,D) { \  
   if ( ((X) <= max_dx) && ((X) >= min_dx) \  
     && ((Y) <= max_dy) && ((Y) >= min_dy) ) \  
   { \  
     iSAD = sad8( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 8, (X), (Y), iEdgedWidth),iEdgedWidth); \  
     iSAD += calc_delta_8((X)-center_x, (Y)-center_y, (uint8_t)iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iDirection=(D); } } \  
 }  
   
 #define CHECK_MV8_CANDIDATE_FOUND(X,Y,D) { \  
   if ( ((X) <= max_dx) && ((X) >= min_dx) \  
     && ((Y) <= max_dy) && ((Y) >= min_dy) ) \  
   { \  
     iSAD = sad8( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 8, (X), (Y), iEdgedWidth),iEdgedWidth); \  
     iSAD += calc_delta_8((X)-center_x, (Y)-center_y, (uint8_t)iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iDirection=(D); iFound=0; } } \  
 }  
   
 /* too slow and not fully functional at the moment */  
 /*  
 int32_t ZeroSearch16(  
                                         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 MotionFlags,  
                                         const uint32_t iQuant,  
                                         const uint32_t iFcode,  
                                         MBParam * const pParam,  
                                         const MACROBLOCK * const pMBs,  
                                         const MACROBLOCK * const prevMBs,  
                                         VECTOR * const currMV,  
                                         VECTOR * const currPMV)  
388  {  {
389          const int32_t iEdgedWidth = pParam->edged_width;          uint32_t t;
390          const uint8_t * cur = pCur->y + x*16 + y*16*iEdgedWidth;          const uint8_t * Reference;
         int32_t iSAD;  
         VECTOR pred;  
391    
392            if ( (!(x&1) && x !=0) || (!(y&1) && y !=0) || //non-zero even value
393                    (x > data->max_dx) || (x < data->min_dx)
394                    || (y > data->max_dy) || (y < data->min_dy) ) return;
395    
396          pred = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 0);          Reference = GetReference(x, y, data);
397            t = d_mv_bits(x, y, data->predMV, data->iFcode, 0, 1);
398    
399          iSAD = sad16( cur,          data->temp[0] = sad32v_c(data->Cur, Reference, data->iEdgedWidth, data->temp + 1);
                 get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, 0,0, iEdgedWidth),  
                 iEdgedWidth, MV_MAX_ERROR);  
         if (iSAD <= iQuant * 96)  
                 iSAD -= MV16_00_BIAS;  
400    
401          currMV->x = 0;          data->temp[0] += (data->lambda16 * t * data->temp[0]) >> 10;
402          currMV->y = 0;          data->temp[1] += (data->lambda8 * t * (data->temp[1] + NEIGH_8X8_BIAS))>>10;
         currPMV->x = -pred.x;  
         currPMV->y = -pred.y;  
403    
404          return iSAD;          if (data->temp[0] < data->iMinSAD[0]) {
405                    data->iMinSAD[0] = data->temp[0];
406                    data->currentMV[0].x = x; data->currentMV[0].y = y;
407                    *dir = Direction; }
408    
409            if (data->temp[1] < data->iMinSAD[1]) {
410                    data->iMinSAD[1] = data->temp[1]; data->currentMV[1].x = x; data->currentMV[1].y = y; }
411            if (data->temp[2] < data->iMinSAD[2]) {
412                    data->iMinSAD[2] = data->temp[2]; data->currentMV[2].x = x; data->currentMV[2].y = y; }
413            if (data->temp[3] < data->iMinSAD[3]) {
414                    data->iMinSAD[3] = data->temp[3]; data->currentMV[3].x = x; data->currentMV[3].y = y; }
415            if (data->temp[4] < data->iMinSAD[4]) {
416                    data->iMinSAD[4] = data->temp[4]; data->currentMV[4].x = x; data->currentMV[4].y = y; }
417  }  }
 */  
418    
419  int32_t  static void
420  Diamond16_MainSearch(const uint8_t * const pRef,  CheckCandidate16no4v(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
421                                           const uint8_t * const pRefH,  {
422                                           const uint8_t * const pRefV,          int32_t sad, xc, yc;
423                                           const uint8_t * const pRefHV,          const uint8_t * Reference;
424                                           const uint8_t * const cur,          uint32_t t;
425                                           const int x,          VECTOR * current;
                                          const int y,  
                                    const int start_x,  
                                    const int start_y,  
                                    int iMinSAD,  
                                    VECTOR * const currMV,  
                                    const int center_x,  
                                    const int center_y,  
                                          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 iDirectionBackup;  
         int32_t iSAD;  
         VECTOR backupMV;  
   
         backupMV.x = start_x;  
         backupMV.y = start_y;  
   
 /* It's one search with full Diamond pattern, and only 3 of 4 for all following diamonds */  
   
         CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize, backupMV.y, 1);  
         CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize, backupMV.y, 2);  
         CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y - iDiamondSize, 3);  
         CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y + iDiamondSize, 4);  
426    
427          if (iDirection) {          if ( (x > data->max_dx) || ( x < data->min_dx)
428                  while (!iFound) {                  || (y > data->max_dy) || (y < data->min_dy) ) return;
429                          iFound = 1;  
430                          backupMV = *currMV;          if (data->rrv && (!(x&1) && x !=0) | (!(y&1) && y !=0) ) return; //non-zero even value
431                          iDirectionBackup = iDirection;  
432            if (data->qpel_precision) { // x and y are in 1/4 precision
433                          if (iDirectionBackup != 2)                  Reference = Interpolate16x16qpel(x, y, 0, data);
434                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,                  current = data->currentQMV;
435                                                                                     backupMV.y, 1);                  xc = x/2; yc = y/2;
                         if (iDirectionBackup != 1)  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                    backupMV.y, 2);  
                         if (iDirectionBackup != 4)  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x,  
                                                                                    backupMV.y - iDiamondSize, 3);  
                         if (iDirectionBackup != 3)  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x,  
                                                                                    backupMV.y + iDiamondSize, 4);  
                 }  
436          } else {          } else {
437                  currMV->x = start_x;                  Reference = GetReference(x, y, data);
438                  currMV->y = start_y;                  current = data->currentMV;
439          }                  xc = x; yc = y;
         return iMinSAD;  
440  }  }
441            t = d_mv_bits(x, y, data->predMV, data->iFcode,
442                                            data->qpel^data->qpel_precision, data->rrv);
443    
444  int32_t          sad = sad16(data->Cur, Reference, data->iEdgedWidth, 256*4096);
445  Square16_MainSearch(const uint8_t * const pRef,          sad += (data->lambda16 * t * sad)>>10;
                                         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,  
                                    const int start_x,  
                                    const int start_y,  
                                    int iMinSAD,  
                                    VECTOR * const currMV,  
                                    const int center_x,  
                                    const int center_y,  
                                         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 square search around given starting point, return SAD of best */  
   
         int32_t iDirection = 0;  
         int32_t iSAD;  
         VECTOR backupMV;  
   
         backupMV.x = start_x;  
         backupMV.y = start_y;  
   
 /* It's one search with full square pattern, and new parts for all following diamonds */  
   
 /*   new direction are extra, so 1-4 is normal diamond  
       537  
       1*2  
       648  
 */  
446    
447          CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize, backupMV.y, 1);          if (data->chroma) sad += ChromaSAD((xc >> 1) + roundtab_79[xc & 0x3],
448          CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize, backupMV.y, 2);                                                                                  (yc >> 1) + roundtab_79[yc & 0x3], data);
         CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y - iDiamondSize, 3);  
         CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y + iDiamondSize, 4);  
   
         CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize,  
                                                          backupMV.y - iDiamondSize, 5);  
         CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize,  
                                                          backupMV.y + iDiamondSize, 6);  
         CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize,  
                                                          backupMV.y - iDiamondSize, 7);  
         CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize,  
                                                          backupMV.y + iDiamondSize, 8);  
449    
450            if (sad < *(data->iMinSAD)) {
451                    *(data->iMinSAD) = sad;
452                    current->x = x; current->y = y;
453                    *dir = Direction;
454            }
455    }
456    
457          if (iDirection) {  static void
458                  while (!iFound) {  CheckCandidate32I(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
459                          iFound = 1;  {
460                          backupMV = *currMV;  // maximum speed - for P/B/I decision
461            int32_t sad;
462    
463                          switch (iDirection) {          if ( (x > data->max_dx) || (x < data->min_dx)
464                          case 1:                  || (y > data->max_dy) || (y < data->min_dy) ) return;
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                    backupMV.y, 1);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 5);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 break;  
                         case 2:  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y,  
                                                                                  2);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 6);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
                                 break;  
465    
466                          case 3:          sad = sad32v_c(data->Cur, data->RefP[0] + (x>>1) + (y>>1)*(data->iEdgedWidth),
467                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,                                          data->iEdgedWidth, data->temp+1);
                                                                                  4);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
                                 break;  
468    
469                          case 4:          if (sad < *(data->iMinSAD)) {
470                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize,                  *(data->iMinSAD) = sad;
471                                                                                   3);                  data->currentMV[0].x = x; data->currentMV[0].y = y;
472                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,                  *dir = Direction;
473                                                                                   backupMV.y - iDiamondSize, 5);          }
474                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,          if (data->temp[1] < data->iMinSAD[1]) {
475                                                                                   backupMV.y + iDiamondSize, 6);                  data->iMinSAD[1] = data->temp[1]; data->currentMV[1].x = x; data->currentMV[1].y = y; }
476                                  break;          if (data->temp[2] < data->iMinSAD[2]) {
477                    data->iMinSAD[2] = data->temp[2]; data->currentMV[2].x = x; data->currentMV[2].y = y; }
478                          case 5:          if (data->temp[3] < data->iMinSAD[3]) {
479                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize, backupMV.y,                  data->iMinSAD[3] = data->temp[3]; data->currentMV[3].x = x; data->currentMV[3].y = y; }
480                                                                                   1);          if (data->temp[4] < data->iMinSAD[4]) {
481                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize,                  data->iMinSAD[4] = data->temp[4]; data->currentMV[4].x = x; data->currentMV[4].y = y; }
                                                                                  3);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 5);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 6);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 break;  
   
                         case 6:  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y,  
                                                                                  2);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize,  
                                                                                  3);  
   
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 5);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 6);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
482    
483                                  break;  }
484    
485                          case 7:  static void
486                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  CheckCandidateInt(const int xf, const int yf, const int Direction, int * const dir, const SearchData * const data)
487                                                                                     backupMV.y, 1);  {
488                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,          int32_t sad, xb, yb, xcf, ycf, xcb, ycb;
489                                                                                   4);          uint32_t t;
490                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,          const uint8_t *ReferenceF, *ReferenceB;
491                                                                                   backupMV.y - iDiamondSize, 5);          VECTOR *current;
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
                                 break;  
492    
493                          case 8:          if ((xf > data->max_dx) || (xf < data->min_dx) ||
494                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y,                  (yf > data->max_dy) || (yf < data->min_dy))
495                                                                                   2);                  return;
496                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,  
497                                                                                   4);          if (!data->qpel_precision) {
498                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,                  ReferenceF = GetReference(xf, yf, data);
499                                                                                   backupMV.y + iDiamondSize, 6);                  xb = data->currentMV[1].x; yb = data->currentMV[1].y;
500                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,                  ReferenceB = GetReferenceB(xb, yb, 1, data);
501                                                                                   backupMV.y - iDiamondSize, 7);                  current = data->currentMV;
502                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,                  xcf = xf; ycf = yf;
503                                                                                   backupMV.y + iDiamondSize, 8);                  xcb = xb; ycb = yb;
                                 break;  
                         default:  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize, backupMV.y,  
                                                                                  1);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y,  
                                                                                  2);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize,  
                                                                                  3);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,  
                                                                                  4);  
   
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 5);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 6);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
                                 break;  
                         }  
                 }  
504          } else {          } else {
505                  currMV->x = start_x;                  ReferenceF = Interpolate16x16qpel(xf, yf, 0, data);
506                  currMV->y = start_y;                  xb = data->currentQMV[1].x; yb = data->currentQMV[1].y;
507          }                  current = data->currentQMV;
508          return iMinSAD;                  ReferenceB = Interpolate16x16qpel(xb, yb, 1, data);
509                    xcf = xf/2; ycf = yf/2;
510                    xcb = xb/2; ycb = yb/2;
511  }  }
512    
513            t = d_mv_bits(xf, yf, data->predMV, data->iFcode, data->qpel^data->qpel_precision, 0)
514                            + d_mv_bits(xb, yb, data->bpredMV, data->iFcode, data->qpel^data->qpel_precision, 0);
515    
516  int32_t          sad = sad16bi(data->Cur, ReferenceF, ReferenceB, data->iEdgedWidth);
517  Full16_MainSearch(const uint8_t * const pRef,          sad += (data->lambda16 * t * sad)>>10;
518                                    const uint8_t * const pRefH,  
519                                    const uint8_t * const pRefV,          if (data->chroma) sad += ChromaSAD2((xcf >> 1) + roundtab_79[xcf & 0x3],
520                                    const uint8_t * const pRefHV,                                                                                  (ycf >> 1) + roundtab_79[ycf & 0x3],
521                                    const uint8_t * const cur,                                                                                  (xcb >> 1) + roundtab_79[xcb & 0x3],
522                                    const int x,                                                                                  (ycb >> 1) + roundtab_79[ycb & 0x3], data);
                                   const int y,  
                                    const int start_x,  
                                    const int start_y,  
                                    int iMinSAD,  
                                    VECTOR * const currMV,  
                                    const int center_x,  
                                    const int center_y,  
                                   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)  
 {  
         int32_t iSAD;  
         int32_t dx, dy;  
         VECTOR backupMV;  
   
         backupMV.x = start_x;  
         backupMV.y = start_y;  
   
         for (dx = min_dx; dx <= max_dx; dx += iDiamondSize)  
                 for (dy = min_dy; dy <= max_dy; dy += iDiamondSize)  
                         NOCHECK_MV16_CANDIDATE(dx, dy);  
523    
524          return iMinSAD;          if (sad < *(data->iMinSAD)) {
525                    *(data->iMinSAD) = sad;
526                    current->x = xf; current->y = yf;
527                    *dir = Direction;
528            }
529  }  }
530    
531  int32_t  static void
532  AdvDiamond16_MainSearch(const uint8_t * const pRef,  CheckCandidateDirect(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
                                                 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,  
                                            int start_x,  
                                            int start_y,  
                                            int iMinSAD,  
                                            VECTOR * const currMV,  
                                            const int center_x,  
                                            const int center_y,  
                                                 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 iDirection)  
533  {  {
534            int32_t sad = 0, xcf = 0, ycf = 0, xcb = 0, ycb = 0;
535            uint32_t k;
536            const uint8_t *ReferenceF;
537            const uint8_t *ReferenceB;
538            VECTOR mvs, b_mvs;
539    
540          int32_t iSAD;          if (( x > 31) || ( x < -32) || ( y > 31) || (y < -32)) return;
   
 /* directions: 1 - left (x-1); 2 - right (x+1), 4 - up (y-1); 8 - down (y+1) */  
541    
542          if (iDirection) {          for (k = 0; k < 4; k++) {
543                  CHECK_MV16_CANDIDATE(start_x - iDiamondSize, start_y);                  mvs.x = data->directmvF[k].x + x;
544                  CHECK_MV16_CANDIDATE(start_x + iDiamondSize, start_y);                  b_mvs.x = ((x == 0) ?
545                  CHECK_MV16_CANDIDATE(start_x, start_y - iDiamondSize);                          data->directmvB[k].x
546                  CHECK_MV16_CANDIDATE(start_x, start_y + iDiamondSize);                          : mvs.x - data->referencemv[k].x);
547    
548                    mvs.y = data->directmvF[k].y + y;
549                    b_mvs.y = ((y == 0) ?
550                            data->directmvB[k].y
551                            : mvs.y - data->referencemv[k].y);
552    
553                    if ((mvs.x > data->max_dx)   || (mvs.x < data->min_dx)   ||
554                            (mvs.y > data->max_dy)   || (mvs.y < data->min_dy)   ||
555                            (b_mvs.x > data->max_dx) || (b_mvs.x < data->min_dx) ||
556                            (b_mvs.y > data->max_dy) || (b_mvs.y < data->min_dy) )
557                            return;
558    
559                    if (data->qpel) {
560                            xcf += mvs.x/2; ycf += mvs.y/2;
561                            xcb += b_mvs.x/2; ycb += b_mvs.y/2;
562          } else {          } else {
563                  int bDirection = 1 + 2 + 4 + 8;                          xcf += mvs.x; ycf += mvs.y;
564                            xcb += b_mvs.x; ycb += b_mvs.y;
565                  do {                          mvs.x *= 2; mvs.y *= 2; //we move to qpel precision anyway
566                          iDirection = 0;                          b_mvs.x *= 2; b_mvs.y *= 2;
567                          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)                  }
                                 CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize, start_y, 1);  
568    
569                          if (bDirection & 2)                  ReferenceF = Interpolate8x8qpel(mvs.x, mvs.y, k, 0, data);
570                                  CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize, start_y, 2);                  ReferenceB = Interpolate8x8qpel(b_mvs.x, b_mvs.y, k, 1, data);
571    
572                          if (bDirection & 4)                  sad += sad8bi(data->Cur + 8*(k&1) + 8*(k>>1)*(data->iEdgedWidth),
573                                  CHECK_MV16_CANDIDATE_DIR(start_x, start_y - iDiamondSize, 4);                                                  ReferenceF, ReferenceB, data->iEdgedWidth);
574                    if (sad > *(data->iMinSAD)) return;
575            }
576    
577                          if (bDirection & 8)          sad += (data->lambda16 * d_mv_bits(x, y, zeroMV, 1, 0, 0) * sad)>>10;
                                 CHECK_MV16_CANDIDATE_DIR(start_x, start_y + iDiamondSize, 8);  
578    
579                          /* now we're doing diagonal checks near our candidate */          if (data->chroma) sad += ChromaSAD2((xcf >> 3) + roundtab_76[xcf & 0xf],
580                                                                                    (ycf >> 3) + roundtab_76[ycf & 0xf],
581                                                                                    (xcb >> 3) + roundtab_76[xcb & 0xf],
582                                                                                    (ycb >> 3) + roundtab_76[ycb & 0xf], data);
583    
584                          if (iDirection)         //checking if anything found          if (sad < *(data->iMinSAD)) {
585                          {                  *(data->iMinSAD) = sad;
586                                  bDirection = iDirection;                  data->currentMV->x = x; data->currentMV->y = y;
587                                  iDirection = 0;                  *dir = Direction;
                                 start_x = currMV->x;  
                                 start_y = currMV->y;  
                                 if (bDirection & 3)     //our candidate is left or right  
                                 {  
                                         CHECK_MV16_CANDIDATE_DIR(start_x, start_y + iDiamondSize, 8);  
                                         CHECK_MV16_CANDIDATE_DIR(start_x, start_y - iDiamondSize, 4);  
                                 } else                  // what remains here is up or down  
                                 {  
                                         CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize, start_y, 2);  
                                         CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize, start_y, 1);  
588                                  }                                  }
   
                                 if (iDirection) {  
                                         bDirection += iDirection;  
                                         start_x = currMV->x;  
                                         start_y = currMV->y;  
589                                  }                                  }
590                          } else                          //about to quit, eh? not so fast....  
591    static void
592    CheckCandidateDirectno4v(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
593                          {                          {
594                                  switch (bDirection) {          int32_t sad, xcf, ycf, xcb, ycb;
595                                  case 2:          const uint8_t *ReferenceF;
596                                          CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,          const uint8_t *ReferenceB;
597                                                                                           start_y - iDiamondSize, 2 + 4);          VECTOR mvs, b_mvs;
                                         CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                          start_y + iDiamondSize, 2 + 8);  
                                         break;  
                                 case 1:  
598    
599                                          CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,          if (( x > 31) || ( x < -32) || ( y > 31) || (y < -32)) return;
600                                                                                           start_y - iDiamondSize, 1 + 4);  
601                                          CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,          mvs.x = data->directmvF[0].x + x;
602                                                                                           start_y + iDiamondSize, 1 + 8);          b_mvs.x = ((x == 0) ?
603                                          break;                  data->directmvB[0].x
604                                  case 2 + 4:                  : mvs.x - data->referencemv[0].x);
605                                          CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,  
606                                                                                           start_y - iDiamondSize, 1 + 4);          mvs.y = data->directmvF[0].y + y;
607                                          CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,          b_mvs.y = ((y == 0) ?
608                                                                                           start_y - iDiamondSize, 2 + 4);                  data->directmvB[0].y
609                                          CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,                  : mvs.y - data->referencemv[0].y);
610                                                                                           start_y + iDiamondSize, 2 + 8);  
611                                          break;          if ( (mvs.x > data->max_dx) || (mvs.x < data->min_dx)
612                                  case 4:                  || (mvs.y > data->max_dy) || (mvs.y < data->min_dy)
613                                          CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,                  || (b_mvs.x > data->max_dx) || (b_mvs.x < data->min_dx)
614                                                                                           start_y - iDiamondSize, 2 + 4);                  || (b_mvs.y > data->max_dy) || (b_mvs.y < data->min_dy) ) return;
615                                          CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,  
616                                                                                           start_y - iDiamondSize, 1 + 4);          if (data->qpel) {
617                                          break;                  xcf = 4*(mvs.x/2); ycf = 4*(mvs.y/2);
618                                  case 8:                  xcb = 4*(b_mvs.x/2); ycb = 4*(b_mvs.y/2);
619                                          CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,                  ReferenceF = Interpolate16x16qpel(mvs.x, mvs.y, 0, data);
620                                                                                           start_y + iDiamondSize, 2 + 8);                  ReferenceB = Interpolate16x16qpel(b_mvs.x, b_mvs.y, 1, data);
621                                          CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,          } else {
622                                                                                           start_y + iDiamondSize, 1 + 8);                  xcf = 4*mvs.x; ycf = 4*mvs.y;
623                                          break;                  xcb = 4*b_mvs.x; ycb = 4*b_mvs.y;
624                                  case 1 + 4:                  ReferenceF = GetReference(mvs.x, mvs.y, data);
625                                          CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,                  ReferenceB = GetReferenceB(b_mvs.x, b_mvs.y, 1, data);
                                                                                          start_y + iDiamondSize, 1 + 8);  
                                         CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                          start_y - iDiamondSize, 1 + 4);  
                                         CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                          start_y - iDiamondSize, 2 + 4);  
                                         break;  
                                 case 2 + 8:  
                                         CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                          start_y - iDiamondSize, 1 + 4);  
                                         CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                          start_y + iDiamondSize, 1 + 8);  
                                         CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                          start_y + iDiamondSize, 2 + 8);  
                                         break;  
                                 case 1 + 8:  
                                         CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                          start_y - iDiamondSize, 2 + 4);  
                                         CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                          start_y + iDiamondSize, 2 + 8);  
                                         CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                          start_y + iDiamondSize, 1 + 8);  
                                         break;  
                                 default:                //1+2+4+8 == we didn't find anything at all  
                                         CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                          start_y - iDiamondSize, 1 + 4);  
                                         CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                          start_y + iDiamondSize, 1 + 8);  
                                         CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                          start_y - iDiamondSize, 2 + 4);  
                                         CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                          start_y + iDiamondSize, 2 + 8);  
                                         break;  
                                 }  
                                 if (!iDirection)  
                                         break;          //ok, the end. really  
                                 else {  
                                         bDirection = iDirection;  
                                         start_x = currMV->x;  
                                         start_y = currMV->y;  
                                 }  
                         }  
626                  }                  }
627                  while (1);                              //forever  
628            sad = sad16bi(data->Cur, ReferenceF, ReferenceB, data->iEdgedWidth);
629            sad += (data->lambda16 * d_mv_bits(x, y, zeroMV, 1, 0, 0) * sad)>>10;
630    
631            if (data->chroma) sad += ChromaSAD2((xcf >> 3) + roundtab_76[xcf & 0xf],
632                                                                                    (ycf >> 3) + roundtab_76[ycf & 0xf],
633                                                                                    (xcb >> 3) + roundtab_76[xcb & 0xf],
634                                                                                    (ycb >> 3) + roundtab_76[ycb & 0xf], data);
635    
636            if (sad < *(data->iMinSAD)) {
637                    *(data->iMinSAD) = sad;
638                    data->currentMV->x = x; data->currentMV->y = y;
639                    *dir = Direction;
640          }          }
         return iMinSAD;  
641  }  }
642    
 #define CHECK_MV16_F_INTERPOL(X,Y) { \  
   if ( ((X) <= f_max_dx) && ((X) >= f_min_dx) \  
     && ((Y) <= f_max_dy) && ((Y) >= f_min_dy) ) \  
   { \  
     iSAD = sad16bi( cur, \  
                         get_ref(f_pRef, f_pRefH, f_pRefV, f_pRefHV, x, y, 16, X, Y, iEdgedWidth),       \  
                         get_ref(b_pRef, b_pRefH, b_pRefV, b_pRefHV, x, y, 16, b_currMV->x, b_currMV->y, iEdgedWidth),   \  
                         iEdgedWidth); \  
     iSAD += calc_delta_16((X) - f_center_x, (Y) - f_center_y, (uint8_t)f_iFcode, iQuant);\  
     iSAD += calc_delta_16(b_currMV->x - b_center_x, b_currMV->y - b_center_y, (uint8_t)b_iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; f_currMV->x=(X); f_currMV->y=(Y); } } \  
 }  
   
 #define CHECK_MV16_F_INTERPOL_FOUND(X,Y) { \  
   if ( ((X) <= f_max_dx) && ((X) >= f_min_dx) \  
     && ((Y) <= f_max_dy) && ((Y) >= f_min_dy) ) \  
   { \  
     iSAD = sad16bi( cur, \  
                         get_ref(f_pRef, f_pRefH, f_pRefV, f_pRefHV, x, y, 16, X, Y, iEdgedWidth),       \  
                         get_ref(b_pRef, b_pRefH, b_pRefV, b_pRefHV, x, y, 16, b_currMV->x, b_currMV->y, iEdgedWidth),   \  
                         iEdgedWidth); \  
     iSAD += calc_delta_16((X) - f_center_x, (Y) - f_center_y, (uint8_t)f_iFcode, iQuant);\  
     iSAD += calc_delta_16(b_currMV->x - b_center_x, b_currMV->y - b_center_y, (uint8_t)b_iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; f_currMV->x=(X); f_currMV->y=(Y); iFound=0;} } \  
 }  
   
 #define CHECK_MV16_B_INTERPOL(X,Y) { \  
   if ( ((X) <= b_max_dx) && ((X) >= b_min_dx) \  
     && ((Y) <= b_max_dy) && ((Y) >= b_min_dy) ) \  
   { \  
     iSAD = sad16bi( cur, \  
                         get_ref(f_pRef, f_pRefH, f_pRefV, f_pRefHV, x, y, 16, f_currMV->x, f_currMV->y, iEdgedWidth),   \  
                         get_ref(b_pRef, b_pRefH, b_pRefV, b_pRefHV, x, y, 16, X, Y, iEdgedWidth),       \  
                         iEdgedWidth); \  
     iSAD += calc_delta_16(f_currMV->x - f_center_x, f_currMV->y - f_center_y, (uint8_t)f_iFcode, iQuant);\  
     iSAD += calc_delta_16((X) - b_center_x, (Y) - b_center_y, (uint8_t)b_iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; b_currMV->x=(X); b_currMV->y=(Y); } } \  
 }  
   
 #define CHECK_MV16_B_INTERPOL_FOUND(X,Y) { \  
   if ( ((X) <= b_max_dx) && ((X) >= b_min_dx) \  
     && ((Y) <= b_max_dy) && ((Y) >= b_min_dy) ) \  
   { \  
     iSAD = sad16bi( cur, \  
                         get_ref(f_pRef, f_pRefH, f_pRefV, f_pRefHV, x, y, 16, f_currMV->x, f_currMV->y, iEdgedWidth),   \  
                         get_ref(b_pRef, b_pRefH, b_pRefV, b_pRefHV, x, y, 16, X, Y, iEdgedWidth),       \  
                         iEdgedWidth); \  
     iSAD += calc_delta_16(f_currMV->x - f_center_x, f_currMV->y - f_center_y, (uint8_t)f_iFcode, iQuant);\  
     iSAD += calc_delta_16((X) - b_center_x, (Y) - b_center_y, (uint8_t)b_iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; b_currMV->x=(X); b_currMV->y=(Y); iFound=0;} } \  
 }  
   
 int32_t  
 Diamond16_InterpolMainSearch(  
                                         const uint8_t * const f_pRef,  
                                          const uint8_t * const f_pRefH,  
                                          const uint8_t * const f_pRefV,  
                                          const uint8_t * const f_pRefHV,  
   
                                          const uint8_t * const cur,  
   
                                         const uint8_t * const b_pRef,  
                                          const uint8_t * const b_pRefH,  
                                          const uint8_t * const b_pRefV,  
                                          const uint8_t * const b_pRefHV,  
643    
644                                           const int x,  static void
645                                           const int y,  CheckCandidateBits16(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
646    {
                                    const int f_start_x,  
                                    const int f_start_y,  
                                    const int b_start_x,  
                                    const int b_start_y,  
   
                                    int iMinSAD,  
                                    VECTOR * const f_currMV,  
                                    VECTOR * const b_currMV,  
   
                                    const int f_center_x,  
                                    const int f_center_y,  
                                    const int b_center_x,  
                                    const int b_center_y,  
   
                                     const int32_t f_min_dx,  
                                         const int32_t f_max_dx,  
                                         const int32_t f_min_dy,  
                                         const int32_t f_max_dy,  
   
                                     const int32_t b_min_dx,  
                                         const int32_t b_max_dx,  
                                         const int32_t b_min_dy,  
                                         const int32_t b_max_dy,  
   
                                         const int32_t iEdgedWidth,  
                                         const int32_t iDiamondSize,  
   
                                         const int32_t f_iFcode,  
                                         const int32_t b_iFcode,  
   
                                         const int32_t iQuant,  
                                         int iFound)  
 {  
 /* Do a diamond search around given starting point, return SAD of best */  
   
         int32_t iSAD;  
   
         VECTOR f_backupMV;  
         VECTOR b_backupMV;  
   
         f_currMV->x = f_start_x;  
         f_currMV->y = f_start_y;  
         b_currMV->x = b_start_x;  
         b_currMV->y = b_start_y;  
   
         do  
         {  
                 iFound = 1;  
   
                 f_backupMV = *f_currMV;  
   
                 CHECK_MV16_F_INTERPOL_FOUND(f_backupMV.x - iDiamondSize, f_backupMV.y);  
                 CHECK_MV16_F_INTERPOL_FOUND(f_backupMV.x + iDiamondSize, f_backupMV.y);  
                 CHECK_MV16_F_INTERPOL_FOUND(f_backupMV.x, f_backupMV.y - iDiamondSize);  
                 CHECK_MV16_F_INTERPOL_FOUND(f_backupMV.x, f_backupMV.y + iDiamondSize);  
   
                 b_backupMV = *b_currMV;  
   
                 CHECK_MV16_B_INTERPOL_FOUND(b_backupMV.x - iDiamondSize, b_backupMV.y);  
                 CHECK_MV16_B_INTERPOL_FOUND(b_backupMV.x + iDiamondSize, b_backupMV.y);  
                 CHECK_MV16_B_INTERPOL_FOUND(b_backupMV.x, b_backupMV.y - iDiamondSize);  
                 CHECK_MV16_B_INTERPOL_FOUND(b_backupMV.x, b_backupMV.y + iDiamondSize);  
   
         } while (!iFound);  
   
         return iMinSAD;  
 }  
   
 /* Sorry, these MACROS really got too large... I'll turn them into function soon! */  
   
 #define CHECK_MV16_DIRECT_FOUND(X,Y) \  
         if ( (X)>=(-32) && (X)<=(31) && ((Y)>=-32) && ((Y)<=31) ) \  
         { int k;\  
         VECTOR mvs,b_mvs;       \  
         iSAD = 0;\  
         for (k = 0; k < 4; k++) {       \  
                                         mvs.x = (int32_t) ((TRB * directmv[k].x) / TRD + (X));          \  
                     b_mvs.x = (int32_t) (((X) == 0)                                                     \  
                                                                                 ? ((TRB - TRD) * directmv[k].x) / TRD   \  
                                             : mvs.x - directmv[k].x);                           \  
                                                                                                                                                                 \  
                     mvs.y = (int32_t) ((TRB * directmv[k].y) / TRD + (Y));              \  
                         b_mvs.y = (int32_t) (((Y) == 0)                                                         \  
                                                                                 ? ((TRB - TRD) * directmv[k].y) / TRD   \  
                                             : mvs.y - directmv[k].y);                           \  
                                                                                                                                                                 \  
   if ( (mvs.x <= max_dx) && (mvs.x >= min_dx) \  
     && (mvs.y <= max_dy) && (mvs.y >= min_dy)  \  
         && (b_mvs.x <= max_dx) && (b_mvs.x >= min_dx)  \  
     && (b_mvs.y <= max_dy) && (b_mvs.y >= min_dy) ) { \  
             iSAD += sad8bi( cur + 8*(k&1) + 8*(k>>1)*iEdgedWidth,                                                                                                       \  
                         get_ref(f_pRef, f_pRefH, f_pRefV, f_pRefHV, 2*x+(k&1), 2*y+(k>>1), 8, \  
                                         mvs.x, mvs.y, iEdgedWidth),                                                             \  
                         get_ref(b_pRef, b_pRefH, b_pRefV, b_pRefHV, 2*x+(k&1), 2*y+(k>>1), 8, \  
                                         b_mvs.x, b_mvs.y, iEdgedWidth),                                                         \  
                         iEdgedWidth); \  
                 }       \  
         else    \  
                 iSAD = 65535;   \  
         } \  
         iSAD += calc_delta_16((X),(Y), 1, iQuant);\  
         if (iSAD < iMinSAD) \  
             {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iFound=0; } \  
 }  
   
   
   
 int32_t  
 Diamond16_DirectMainSearch(  
                                         const uint8_t * const f_pRef,  
                                         const uint8_t * const f_pRefH,  
                                         const uint8_t * const f_pRefV,  
                                         const uint8_t * const f_pRefHV,  
   
                                         const uint8_t * const cur,  
   
                                         const uint8_t * const b_pRef,  
                                         const uint8_t * const b_pRefH,  
                                         const uint8_t * const b_pRefV,  
                                         const uint8_t * const b_pRefHV,  
647    
648                                          const int x,          int16_t *in = data->dctSpace, *coeff = data->dctSpace + 64;
649                                          const int y,          int32_t bits = 0, sum;
650            VECTOR * current;
651            const uint8_t * ptr;
652            int i, cbp = 0, t, xc, yc;
653    
654                                          const int TRB,          if ( (x > data->max_dx) || (x < data->min_dx)
655                                          const int TRD,                  || (y > data->max_dy) || (y < data->min_dy) ) return;
656    
657                                      const int start_x,          if (!data->qpel_precision) {
658                                      const int start_y,                  ptr = GetReference(x, y, data);
659                    current = data->currentMV;
660                    xc = x; yc = y;
661            } else { // x and y are in 1/4 precision
662                    ptr = Interpolate16x16qpel(x, y, 0, data);
663                    current = data->currentQMV;
664                    xc = x/2; yc = y/2;
665            }
666    
667                                      int iMinSAD,          for(i = 0; i < 4; i++) {
668                                      VECTOR * const currMV,                  int s = 8*((i&1) + (i>>1)*data->iEdgedWidth);
669                                          const VECTOR * const directmv,                  transfer_8to16subro(in, data->Cur + s, ptr + s, data->iEdgedWidth);
670                    fdct(in);
671                    if (data->lambda8 == 0) sum = quant_inter(coeff, in, data->lambda16);
672                    else sum = quant4_inter(coeff, in, data->lambda16);
673                    if (sum > 0) {
674                            cbp |= 1 << (5 - i);
675                            bits += data->temp[i] = CodeCoeffInter_CalcBits(coeff, scan_tables[0]);
676                    } else data->temp[i] = 0;
677            }
678    
679                                      const int32_t min_dx,          bits += t = d_mv_bits(x, y, data->predMV, data->iFcode, data->qpel^data->qpel_precision, 0);
                                         const int32_t max_dx,  
                                         const int32_t min_dy,  
                                         const int32_t max_dy,  
680    
681                                          const int32_t iEdgedWidth,          if (bits < data->iMinSAD[0]) { // there is still a chance, adding chroma
682                                          const int32_t iDiamondSize,                  xc = (xc >> 1) + roundtab_79[xc & 0x3];
683                    yc = (yc >> 1) + roundtab_79[yc & 0x3];
684    
685                                          const int32_t iQuant,                  //chroma U
686                                          int iFound)                  ptr = interpolate8x8_switch2(data->RefQ + 64, data->RefP[4], 0, 0, xc, yc,  data->iEdgedWidth/2, data->rounding);
687  {                  transfer_8to16subro(in, ptr, data->CurU, data->iEdgedWidth/2);
688  /* Do a diamond search around given starting point, return SAD of best */                  fdct(in);
689                    if (data->lambda8 == 0) sum = quant_inter(coeff, in, data->lambda16);
690                    else sum = quant4_inter(coeff, in, data->lambda16);
691                    if (sum > 0) {
692                            cbp |= 1 << (5 - 4);
693                            bits += CodeCoeffInter_CalcBits(coeff, scan_tables[0]);
694                    }
695    
696          int32_t iSAD;                  if (bits < data->iMinSAD[0]) {
697                            //chroma V
698                            ptr = interpolate8x8_switch2(data->RefQ + 64, data->RefP[5], 0, 0, xc, yc,  data->iEdgedWidth/2, data->rounding);
699                            transfer_8to16subro(in, ptr, data->CurV, data->iEdgedWidth/2);
700                            fdct(in);
701                            if (data->lambda8 == 0) sum = quant_inter(coeff, in, data->lambda16);
702                            else sum = quant4_inter(coeff, in, data->lambda16);
703                            if (sum > 0) {
704                                    cbp |= 1 << (5 - 5);
705                                    bits += CodeCoeffInter_CalcBits(coeff, scan_tables[0]);
706                            }
707                    }
708            }
709    
710          VECTOR backupMV;          bits += xvid_cbpy_tab[15-(cbp>>2)].len;
711            bits += mcbpc_inter_tab[(MODE_INTER & 7) | ((cbp & 3) << 3)].len;
712    
713          currMV->x = start_x;          if (bits < data->iMinSAD[0]) {
714          currMV->y = start_y;                  data->iMinSAD[0] = bits;
715                    current[0].x = x; current[0].y = y;
716                    *dir = Direction;
717            }
718    
719  /* It's one search with full Diamond pattern, and only 3 of 4 for all following diamonds */          if (data->temp[0] + t < data->iMinSAD[1]) {
720                    data->iMinSAD[1] = data->temp[0] + t; current[1].x = x; current[1].y = y; }
721            if (data->temp[1] < data->iMinSAD[2]) {
722                    data->iMinSAD[2] = data->temp[1]; current[2].x = x; current[2].y = y; }
723            if (data->temp[2] < data->iMinSAD[3]) {
724                    data->iMinSAD[3] = data->temp[2]; current[3].x = x; current[3].y = y; }
725            if (data->temp[3] < data->iMinSAD[4]) {
726                    data->iMinSAD[4] = data->temp[3]; current[4].x = x; current[4].y = y; }
727    
728          do  }
729    static void
730    CheckCandidateBits8(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
731          {          {
                 iFound = 1;  
   
                 backupMV = *currMV;  
732    
733                  CHECK_MV16_DIRECT_FOUND(backupMV.x - iDiamondSize, backupMV.y);          int16_t *in = data->dctSpace, *coeff = data->dctSpace + 64;
734                  CHECK_MV16_DIRECT_FOUND(backupMV.x + iDiamondSize, backupMV.y);          int32_t sum, bits;
735                  CHECK_MV16_DIRECT_FOUND(backupMV.x, backupMV.y - iDiamondSize);          VECTOR * current;
736                  CHECK_MV16_DIRECT_FOUND(backupMV.x, backupMV.y + iDiamondSize);          const uint8_t * ptr;
737            int cbp;
738    
739          } while (!iFound);          if ( (x > data->max_dx) || (x < data->min_dx)
740                    || (y > data->max_dy) || (y < data->min_dy) ) return;
741    
742          return iMinSAD;          if (!data->qpel_precision) {
743                    ptr = GetReference(x, y, data);
744                    current = data->currentMV;
745            } else { // x and y are in 1/4 precision
746                    ptr = Interpolate8x8qpel(x, y, 0, 0, data);
747                    current = data->currentQMV;
748  }  }
749    
750            transfer_8to16subro(in, data->Cur, ptr, data->iEdgedWidth);
751            fdct(in);
752            if (data->lambda8 == 0) sum = quant_inter(coeff, in, data->lambda16);
753            else sum = quant4_inter(coeff, in, data->lambda16);
754            if (sum > 0) {
755                    bits = CodeCoeffInter_CalcBits(coeff, scan_tables[0]);
756                    cbp = 1;
757            } else cbp = bits = 0;
758    
759  int32_t          bits += sum = d_mv_bits(x, y, data->predMV, data->iFcode, data->qpel^data->qpel_precision, 0);
 AdvDiamond8_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,  
                                            int start_x,  
                                            int start_y,  
                                            int iMinSAD,  
                                            VECTOR * const currMV,  
                                            const int center_x,  
                                            const int center_y,  
                                            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 iDirection)  
 {  
760    
761          int32_t iSAD;          if (bits < data->iMinSAD[0]) {
762                    data->temp[0] = cbp;
763                    data->iMinSAD[0] = bits;
764                    current[0].x = x; current[0].y = y;
765                    *dir = Direction;
766            }
767    }
768    
769  /* directions: 1 - left (x-1); 2 - right (x+1), 4 - up (y-1); 8 - down (y+1) */  /* CHECK_CANDIATE FUNCTIONS END */
770    
771          if (iDirection) {  /* MAINSEARCH FUNCTIONS START */
                 CHECK_MV8_CANDIDATE(start_x - iDiamondSize, start_y);  
                 CHECK_MV8_CANDIDATE(start_x + iDiamondSize, start_y);  
                 CHECK_MV8_CANDIDATE(start_x, start_y - iDiamondSize);  
                 CHECK_MV8_CANDIDATE(start_x, start_y + iDiamondSize);  
         } else {  
                 int bDirection = 1 + 2 + 4 + 8;  
772    
773                  do {  static void
774                          iDirection = 0;  AdvDiamondSearch(int x, int y, const SearchData * const data, int bDirection)
775                          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)  {
                                 CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize, start_y, 1);  
776    
777                          if (bDirection & 2)  /* directions: 1 - left (x-1); 2 - right (x+1), 4 - up (y-1); 8 - down (y+1) */
                                 CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize, start_y, 2);  
778    
779                          if (bDirection & 4)          int iDirection;
                                 CHECK_MV8_CANDIDATE_DIR(start_x, start_y - iDiamondSize, 4);  
780    
781                          if (bDirection & 8)          for(;;) { //forever
782                                  CHECK_MV8_CANDIDATE_DIR(start_x, start_y + iDiamondSize, 8);                  iDirection = 0;
783                    if (bDirection & 1) CHECK_CANDIDATE(x - iDiamondSize, y, 1);
784                    if (bDirection & 2) CHECK_CANDIDATE(x + iDiamondSize, y, 2);
785                    if (bDirection & 4) CHECK_CANDIDATE(x, y - iDiamondSize, 4);
786                    if (bDirection & 8) CHECK_CANDIDATE(x, y + iDiamondSize, 8);
787    
788                          /* now we're doing diagonal checks near our candidate */                          /* now we're doing diagonal checks near our candidate */
789    
790                          if (iDirection)         //checking if anything found                  if (iDirection) {               //if anything found
                         {  
791                                  bDirection = iDirection;                                  bDirection = iDirection;
792                                  iDirection = 0;                                  iDirection = 0;
793                                  start_x = currMV->x;                          x = data->currentMV->x; y = data->currentMV->y;
794                                  start_y = currMV->y;                          if (bDirection & 3) {   //our candidate is left or right
795                                  if (bDirection & 3)     //our candidate is left or right                                  CHECK_CANDIDATE(x, y + iDiamondSize, 8);
796                                  {                                  CHECK_CANDIDATE(x, y - iDiamondSize, 4);
797                                          CHECK_MV8_CANDIDATE_DIR(start_x, start_y + iDiamondSize, 8);                          } else {                        // what remains here is up or down
798                                          CHECK_MV8_CANDIDATE_DIR(start_x, start_y - iDiamondSize, 4);                                  CHECK_CANDIDATE(x + iDiamondSize, y, 2);
799                                  } else                  // what remains here is up or down                                  CHECK_CANDIDATE(x - iDiamondSize, y, 1);
                                 {  
                                         CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize, start_y, 2);  
                                         CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize, start_y, 1);  
800                                  }                                  }
801    
802                                  if (iDirection) {                                  if (iDirection) {
803                                          bDirection += iDirection;                                          bDirection += iDirection;
804                                          start_x = currMV->x;                                  x = data->currentMV->x; y = data->currentMV->y;
                                         start_y = currMV->y;  
805                                  }                                  }
806                          } else                          //about to quit, eh? not so fast....                  } else {                                //about to quit, eh? not so fast....
                         {  
807                                  switch (bDirection) {                                  switch (bDirection) {
808                                  case 2:                                  case 2:
809                                          CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,                                  CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
810                                                                                          start_y - iDiamondSize, 2 + 4);                                  CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
                                         CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                         start_y + iDiamondSize, 2 + 8);  
811                                          break;                                          break;
812                                  case 1:                                  case 1:
813                                          CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,                                  CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
814                                                                                          start_y - iDiamondSize, 1 + 4);                                  CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
                                         CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                         start_y + iDiamondSize, 1 + 8);  
815                                          break;                                          break;
816                                  case 2 + 4:                                  case 2 + 4:
817                                          CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,                                  CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
818                                                                                          start_y - iDiamondSize, 1 + 4);                                  CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
819                                          CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,                                  CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
                                                                                         start_y - iDiamondSize, 2 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                         start_y + iDiamondSize, 2 + 8);  
820                                          break;                                          break;
821                                  case 4:                                  case 4:
822                                          CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,                                  CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
823                                                                                          start_y - iDiamondSize, 2 + 4);                                  CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
                                         CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                         start_y - iDiamondSize, 1 + 4);  
824                                          break;                                          break;
825                                  case 8:                                  case 8:
826                                          CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,                                  CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
827                                                                                          start_y + iDiamondSize, 2 + 8);                                  CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
                                         CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                         start_y + iDiamondSize, 1 + 8);  
828                                          break;                                          break;
829                                  case 1 + 4:                                  case 1 + 4:
830                                          CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,                                  CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
831                                                                                          start_y + iDiamondSize, 1 + 8);                                  CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
832                                          CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,                                  CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
                                                                                         start_y - iDiamondSize, 1 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                         start_y - iDiamondSize, 2 + 4);  
833                                          break;                                          break;
834                                  case 2 + 8:                                  case 2 + 8:
835                                          CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,                                  CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
836                                                                                          start_y - iDiamondSize, 1 + 4);                                  CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
837                                          CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,                                  CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
                                                                                         start_y + iDiamondSize, 1 + 8);  
                                         CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                         start_y + iDiamondSize, 2 + 8);  
838                                          break;                                          break;
839                                  case 1 + 8:                                  case 1 + 8:
840                                          CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,                                  CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
841                                                                                          start_y - iDiamondSize, 2 + 4);                                  CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
842                                          CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,                                  CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
                                                                                         start_y + iDiamondSize, 2 + 8);  
                                         CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                         start_y + iDiamondSize, 1 + 8);  
843                                          break;                                          break;
844                                  default:                //1+2+4+8 == we didn't find anything at all                                  default:                //1+2+4+8 == we didn't find anything at all
845                                          CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,                                  CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
846                                                                                          start_y - iDiamondSize, 1 + 4);                                  CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
847                                          CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,                                  CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
848                                                                                          start_y + iDiamondSize, 1 + 8);                                  CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
                                         CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                         start_y - iDiamondSize, 2 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                         start_y + iDiamondSize, 2 + 8);  
849                                          break;                                          break;
850                                  }                                  }
851                                  if (!(iDirection))                          if (!iDirection) break;         //ok, the end. really
                                         break;          //ok, the end. really  
                                 else {  
852                                          bDirection = iDirection;                                          bDirection = iDirection;
853                                          start_x = currMV->x;                          x = data->currentMV->x; y = data->currentMV->y;
                                         start_y = currMV->y;  
854                                  }                                  }
855                          }                          }
856                  }                  }
                 while (1);                              //forever  
         }  
         return iMinSAD;  
 }  
857    
858    static void
859    SquareSearch(int x, int y, const SearchData * const data, int bDirection)
860    {
861            int iDirection;
862    
863  int32_t          do {
864  Full8_MainSearch(const uint8_t * const pRef,                  iDirection = 0;
865                                   const uint8_t * const pRefH,                  if (bDirection & 1) CHECK_CANDIDATE(x - iDiamondSize, y, 1+16+64);
866                                   const uint8_t * const pRefV,                  if (bDirection & 2) CHECK_CANDIDATE(x + iDiamondSize, y, 2+32+128);
867                                   const uint8_t * const pRefHV,                  if (bDirection & 4) CHECK_CANDIDATE(x, y - iDiamondSize, 4+16+32);
868                                   const uint8_t * const cur,                  if (bDirection & 8) CHECK_CANDIDATE(x, y + iDiamondSize, 8+64+128);
869                                   const int x,                  if (bDirection & 16) CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1+4+16+32+64);
870                                   const int y,                  if (bDirection & 32) CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2+4+16+32+128);
871                             const int start_x,                  if (bDirection & 64) CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1+8+16+64+128);
872                             const int start_y,                  if (bDirection & 128) CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2+8+32+64+128);
                            int iMinSAD,  
                            VECTOR * const currMV,  
                            const int center_x,  
                            const int center_y,  
                                  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)  
 {  
         int32_t iSAD;  
         int32_t dx, dy;  
         VECTOR backupMV;  
   
         backupMV.x = start_x;  
         backupMV.y = start_y;  
   
         for (dx = min_dx; dx <= max_dx; dx += iDiamondSize)  
                 for (dy = min_dy; dy <= max_dy; dy += iDiamondSize)  
                         NOCHECK_MV8_CANDIDATE(dx, dy);  
873    
874          return iMinSAD;                  bDirection = iDirection;
875                    x = data->currentMV->x; y = data->currentMV->y;
876            } while (iDirection);
877  }  }
878    
879  Halfpel8_RefineFuncPtr Halfpel8_Refine;  static void
880    DiamondSearch(int x, int y, const SearchData * const data, int bDirection)
 int32_t  
 Halfpel16_Refine(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 int center_x,  
                            const int center_y,  
                                  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)  
881  {  {
 /* Do a half-pel refinement (or rather a "smallest possible amount" refinement) */  
   
         int32_t iSAD;  
         VECTOR backupMV = *currMV;  
882    
883          CHECK_MV16_CANDIDATE(backupMV.x - 1, backupMV.y - 1);  /* directions: 1 - left (x-1); 2 - right (x+1), 4 - up (y-1); 8 - down (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);  
884    
885          return iMinSAD;          int iDirection;
 }  
886    
887  #define PMV_HALFPEL16 (PMV_HALFPELDIAMOND16|PMV_HALFPELREFINE16)          do {
888                    iDirection = 0;
889                    if (bDirection & 1) CHECK_CANDIDATE(x - iDiamondSize, y, 1);
890                    if (bDirection & 2) CHECK_CANDIDATE(x + iDiamondSize, y, 2);
891  int32_t                  if (bDirection & 4) CHECK_CANDIDATE(x, y - iDiamondSize, 4);
892  PMVfastSearch16(const uint8_t * const pRef,                  if (bDirection & 8) CHECK_CANDIDATE(x, y + iDiamondSize, 8);
                                 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,      /* start is searched first, so it should contain the most */  
                                 const int start_y,  /* likely motion vector for this block */  
                                 const int center_x,     /* center is from where length of MVs is measured */  
                                 const int center_y,  
                                 const uint32_t MotionFlags,  
                                 const uint32_t iQuant,  
                                 const uint32_t iFcode,  
                                 const MBParam * const pParam,  
                                 const MACROBLOCK * const pMBs,  
                                 const MACROBLOCK * const prevMBs,  
                                 VECTOR * const currMV,  
                                 VECTOR * const currPMV)  
 {  
         const uint32_t iWcount = pParam->mb_width;  
         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;  
   
         int32_t iFound;  
   
         VECTOR newMV;  
         VECTOR backupMV;                        /* just for PMVFAST */  
   
         VECTOR pmv[4];  
         int32_t psad[4];  
   
         MainSearch16FuncPtr MainSearchPtr;  
   
         const MACROBLOCK *const prevMB = prevMBs + x + y * iWcount;  
   
         int32_t threshA, threshB;  
         int32_t bPredEq;  
         int32_t iMinSAD, iSAD;  
   
 /* Get maximum range */  
         get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 16, iWidth, iHeight,  
                           iFcode);  
   
 /* we work with abs. MVs, not relative to prediction, so get_range is called relative to 0,0 */  
   
         if (!(MotionFlags & PMV_HALFPEL16)) {  
                 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; */  
         //bPredEq = get_pmvdata(pMBs, x, y, iWcount, 0, pmv, psad);  
         bPredEq = get_pmvdata2(pMBs, iWcount, 0, x, y, 0, pmv, psad);  
   
         if ((x == 0) && (y == 0)) {  
                 threshA = 512;  
                 threshB = 1024;  
         } else {  
                 threshA = psad[0];  
                 threshB = threshA + 256;  
                 if (threshA < 512)  
                         threshA = 512;  
                 if (threshA > 1024)  
                         threshA = 1024;  
                 if (threshB > 1792)  
                         threshB = 1792;  
         }  
   
         iFound = 0;  
   
 /* Step 4: Calculate SAD around the Median prediction.  
    MinSAD=SAD  
    If Motion Vector equal to Previous frame motion vector  
    and MinSAD<PrevFrmSAD goto Step 10.  
    If SAD<=256 goto Step 10.  
 */  
   
         currMV->x = start_x;  
         currMV->y = start_y;  
893    
894          if (!(MotionFlags & PMV_HALFPEL16)) {   /* This should NOT be necessary! */                  /* now we're doing diagonal checks near our candidate */
                 currMV->x = EVEN(currMV->x);  
                 currMV->y = EVEN(currMV->y);  
         }  
895    
896          if (currMV->x > max_dx) {                  if (iDirection) {               //checking if anything found
897                  currMV->x = max_dx;                          bDirection = iDirection;
898                            iDirection = 0;
899                            x = data->currentMV->x; y = data->currentMV->y;
900                            if (bDirection & 3) {   //our candidate is left or right
901                                    CHECK_CANDIDATE(x, y + iDiamondSize, 8);
902                                    CHECK_CANDIDATE(x, y - iDiamondSize, 4);
903                            } else {                        // what remains here is up or down
904                                    CHECK_CANDIDATE(x + iDiamondSize, y, 2);
905                                    CHECK_CANDIDATE(x - iDiamondSize, y, 1);
906          }          }
907          if (currMV->x < min_dx) {                          bDirection += iDirection;
908                  currMV->x = min_dx;                          x = data->currentMV->x; y = data->currentMV->y;
909          }          }
         if (currMV->y > max_dy) {  
                 currMV->y = max_dy;  
910          }          }
911          if (currMV->y < min_dy) {          while (iDirection);
                 currMV->y = min_dy;  
912          }          }
913    
914          iMinSAD =  /* MAINSEARCH FUNCTIONS END */
                 sad16(cur,  
                           get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 16, currMV,  
                                                  iEdgedWidth), iEdgedWidth, MV_MAX_ERROR);  
         iMinSAD +=  
                 calc_delta_16(currMV->x - center_x, currMV->y - center_y,  
                                           (uint8_t) iFcode, iQuant);  
915    
916          if ((iMinSAD < 256) ||  static void
917                  ((MVequal(*currMV, prevMB->mvs[0])) &&  SubpelRefine(const SearchData * const data)
                  ((int32_t) iMinSAD < prevMB->sad16))) {  
                 if (iMinSAD < 2 * iQuant)       // high chances for SKIP-mode  
918                  {                  {
919                          if (!MVzero(*currMV)) {  /* Do a half-pel or q-pel refinement */
920                                  iMinSAD += MV16_00_BIAS;          const VECTOR centerMV = data->qpel_precision ? *data->currentQMV : *data->currentMV;
921                                  CHECK_MV16_ZERO;        // (0,0) saves space for letterboxed pictures          int iDirection; //only needed because macro expects it
                                 iMinSAD -= MV16_00_BIAS;  
                         }  
                 }  
922    
923                  if (MotionFlags & PMV_QUICKSTOP16)          CHECK_CANDIDATE(centerMV.x, centerMV.y - 1, 0);
924                          goto PMVfast16_Terminate_without_Refine;          CHECK_CANDIDATE(centerMV.x + 1, centerMV.y - 1, 0);
925                  if (MotionFlags & PMV_EARLYSTOP16)          CHECK_CANDIDATE(centerMV.x + 1, centerMV.y, 0);
926                          goto PMVfast16_Terminate_with_Refine;          CHECK_CANDIDATE(centerMV.x + 1, centerMV.y + 1, 0);
927            CHECK_CANDIDATE(centerMV.x, centerMV.y + 1, 0);
928            CHECK_CANDIDATE(centerMV.x - 1, centerMV.y + 1, 0);
929            CHECK_CANDIDATE(centerMV.x - 1, centerMV.y, 0);
930            CHECK_CANDIDATE(centerMV.x - 1, centerMV.y - 1, 0);
931          }          }
932    
933    static __inline int
934    SkipDecisionP(const IMAGE * current, const IMAGE * reference,
935                                                            const int x, const int y,
936                                                            const uint32_t stride, const uint32_t iQuant, int rrv)
937    
938  /* Step 2 (lazy eval): Calculate Distance= |MedianMVX| + |MedianMVY| where MedianMV is the motion  {
939     vector of the median.          int offset = (x + y*stride)*8;
940     If PredEq=1 and MVpredicted = Previous Frame MV, set Found=2          if(!rrv) {
941  */                  uint32_t sadC = sad8(current->u + offset,
942                                                    reference->u + offset, stride);
943          if ((bPredEq) && (MVequal(pmv[0], prevMB->mvs[0])))                  if (sadC > iQuant * MAX_CHROMA_SAD_FOR_SKIP) return 0;
944                  iFound = 2;                  sadC += sad8(current->v + offset,
945                                                    reference->v + offset, stride);
946  /* Step 3 (lazy eval): If Distance>0 or thresb<1536 or PredEq=1 Select small Diamond Search.                  if (sadC > iQuant * MAX_CHROMA_SAD_FOR_SKIP) return 0;
947     Otherwise select large Diamond Search.                  return 1;
 */  
   
         if ((!MVzero(pmv[0])) || (threshB < 1536) || (bPredEq))  
                 iDiamondSize = 1;               // halfpel!  
         else  
                 iDiamondSize = 2;               // halfpel!  
   
         if (!(MotionFlags & PMV_HALFPELDIAMOND16))  
                 iDiamondSize *= 2;  
   
 /*  
    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.  
 */  
   
 // (0,0) is always possible  
   
         if (!MVzero(pmv[0]))  
                 CHECK_MV16_ZERO;  
948    
949  // previous frame MV is always possible          } else {
950                    uint32_t sadC = sad16(current->u + 2*offset,
951                                                    reference->u + 2*offset, stride, 256*4096);
952                    if (sadC > iQuant * MAX_CHROMA_SAD_FOR_SKIP*4) return 0;
953                    sadC += sad16(current->v + 2*offset,
954                                                    reference->v + 2*offset, stride, 256*4096);
955                    if (sadC > iQuant * MAX_CHROMA_SAD_FOR_SKIP*4) return 0;
956                    return 1;
957            }
958    }
959    
960          if (!MVzero(prevMB->mvs[0]))  static __inline void
961                  if (!MVequal(prevMB->mvs[0], pmv[0]))  SkipMacroblockP(MACROBLOCK *pMB, const int32_t sad)
962                          CHECK_MV16_CANDIDATE(prevMB->mvs[0].x, prevMB->mvs[0].y);  {
963            pMB->mode = MODE_NOT_CODED;
964            pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = zeroMV;
965            pMB->qmvs[0] = pMB->qmvs[1] = pMB->qmvs[2] = pMB->qmvs[3] = zeroMV;
966            pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] = pMB->sad8[3] = sad;
967    }
968    
969  // left neighbour, if allowed  bool
970    MotionEstimation(MBParam * const pParam,
971                                    FRAMEINFO * const current,
972                                    FRAMEINFO * const reference,
973                                    const IMAGE * const pRefH,
974                                    const IMAGE * const pRefV,
975                                    const IMAGE * const pRefHV,
976                                    const uint32_t iLimit)
977    {
978            MACROBLOCK *const pMBs = current->mbs;
979            const IMAGE *const pCurrent = &current->image;
980            const IMAGE *const pRef = &reference->image;
981    
982          if (!MVzero(pmv[1]))          uint32_t mb_width = pParam->mb_width;
983                  if (!MVequal(pmv[1], prevMB->mvs[0]))          uint32_t mb_height = pParam->mb_height;
984                          if (!MVequal(pmv[1], pmv[0])) {          const uint32_t iEdgedWidth = pParam->edged_width;
985                                  if (!(MotionFlags & PMV_HALFPEL16)) {          const uint32_t MotionFlags = MakeGoodMotionFlags(current->motion_flags, current->global_flags);
986                                          pmv[1].x = EVEN(pmv[1].x);  
987                                          pmv[1].y = EVEN(pmv[1].y);          uint32_t x, y;
988            uint32_t iIntra = 0;
989            int32_t quant = current->quant, sad00;
990            int skip_thresh = INITIAL_SKIP_THRESH *
991                    (current->global_flags & XVID_REDUCED ? 4:1) *
992                    (current->global_flags & XVID_MODEDECISION_BITS ? 2:1);
993    
994            // some pre-initialized thingies for SearchP
995            int32_t temp[8];
996            VECTOR currentMV[5];
997            VECTOR currentQMV[5];
998            int32_t iMinSAD[5];
999            DECLARE_ALIGNED_MATRIX(dct_space, 2, 64, int16_t, CACHE_LINE);
1000            SearchData Data;
1001            memset(&Data, 0, sizeof(SearchData));
1002            Data.iEdgedWidth = iEdgedWidth;
1003            Data.currentMV = currentMV;
1004            Data.currentQMV = currentQMV;
1005            Data.iMinSAD = iMinSAD;
1006            Data.temp = temp;
1007            Data.iFcode = current->fcode;
1008            Data.rounding = pParam->m_rounding_type;
1009            Data.qpel = pParam->m_quarterpel;
1010            Data.chroma = MotionFlags & PMV_CHROMA16;
1011            Data.rrv = current->global_flags & XVID_REDUCED;
1012            Data.dctSpace = dct_space;
1013    
1014            if ((current->global_flags & XVID_REDUCED)) {
1015                    mb_width = (pParam->width + 31) / 32;
1016                    mb_height = (pParam->height + 31) / 32;
1017                    Data.qpel = 0;
1018            }
1019    
1020            Data.RefQ = pRefV->u; // a good place, also used in MC (for similar purpose)
1021            if (sadInit) (*sadInit) ();
1022    
1023            for (y = 0; y < mb_height; y++) {
1024                    for (x = 0; x < mb_width; x++)  {
1025                            MACROBLOCK *pMB = &pMBs[x + y * pParam->mb_width];
1026    
1027                            if (!Data.rrv) pMB->sad16 =
1028                                    sad16v(pCurrent->y + (x + y * iEdgedWidth) * 16,
1029                                                            pRef->y + (x + y * iEdgedWidth) * 16,
1030                                                            pParam->edged_width, pMB->sad8 );
1031    
1032                            else pMB->sad16 =
1033                                    sad32v_c(pCurrent->y + (x + y * iEdgedWidth) * 32,
1034                                                            pRef->y + (x + y * iEdgedWidth) * 32,
1035                                                            pParam->edged_width, pMB->sad8 );
1036    
1037                            if (Data.chroma) {
1038                                    Data.temp[7] = sad8(pCurrent->u + x*8 + y*(iEdgedWidth/2)*8,
1039                                                                            pRef->u + x*8 + y*(iEdgedWidth/2)*8, iEdgedWidth/2)
1040                                                                    + sad8(pCurrent->v + (x + y*(iEdgedWidth/2))*8,
1041                                                                            pRef->v + (x + y*(iEdgedWidth/2))*8, iEdgedWidth/2);
1042                                    pMB->sad16 += Data.temp[7];
1043                                  }                                  }
1044    
1045                                  CHECK_MV16_CANDIDATE(pmv[1].x, pmv[1].y);                          sad00 = pMB->sad16;
                         }  
 // top neighbour, if allowed  
         if (!MVzero(pmv[2]))  
                 if (!MVequal(pmv[2], prevMB->mvs[0]))  
                         if (!MVequal(pmv[2], pmv[0]))  
                                 if (!MVequal(pmv[2], pmv[1])) {  
                                         if (!(MotionFlags & PMV_HALFPEL16)) {  
                                                 pmv[2].x = EVEN(pmv[2].x);  
                                                 pmv[2].y = EVEN(pmv[2].y);  
                                         }  
                                         CHECK_MV16_CANDIDATE(pmv[2].x, pmv[2].y);  
1046    
1047  // top right neighbour, if allowed                          if (!(current->global_flags & XVID_LUMIMASKING)) {
1048                                          if (!MVzero(pmv[3]))                                  pMB->dquant = NO_CHANGE;
1049                                                  if (!MVequal(pmv[3], prevMB->mvs[0]))                          } else {
1050                                                          if (!MVequal(pmv[3], pmv[0]))                                  if (pMB->dquant != NO_CHANGE) {
1051                                                                  if (!MVequal(pmv[3], pmv[1]))                                          quant += DQtab[pMB->dquant];
1052                                                                          if (!MVequal(pmv[3], pmv[2])) {                                          if (quant > 31) quant = 31;
1053                                                                                  if (!(MotionFlags & PMV_HALFPEL16)) {                                          else if (quant < 1) quant = 1;
                                                                                         pmv[3].x = EVEN(pmv[3].x);  
                                                                                         pmv[3].y = EVEN(pmv[3].y);  
1054                                                                                  }                                                                                  }
                                                                                 CHECK_MV16_CANDIDATE(pmv[3].x,  
                                                                                                                          pmv[3].y);  
1055                                                                          }                                                                          }
1056                            pMB->quant = current->quant;
1057    
1058    //initial skip decision
1059    /* no early skip for GMC (global vector = skip vector is unknown!)  */
1060                            if (!(current->global_flags & XVID_GMC))        { /* no fast SKIP for S(GMC)-VOPs */
1061                                    if (pMB->dquant == NO_CHANGE && sad00 < pMB->quant * skip_thresh)
1062                                            if (Data.chroma || SkipDecisionP(pCurrent, pRef, x, y, iEdgedWidth/2, pMB->quant, Data.rrv)) {
1063                                                    SkipMacroblockP(pMB, sad00);
1064                                                    continue;
1065                                  }                                  }
   
         if ((MVzero(*currMV)) &&  
                 (!MVzero(pmv[0])) /* && (iMinSAD <= iQuant * 96) */ )  
                 iMinSAD -= MV16_00_BIAS;  
   
   
 /* Step 6: If MinSAD <= thresa goto Step 10.  
    If Motion Vector equal to Previous frame motion vector and MinSAD<PrevFrmSAD goto Step 10.  
 */  
   
         if ((iMinSAD <= threshA) ||  
                 (MVequal(*currMV, prevMB->mvs[0]) &&  
                  ((int32_t) iMinSAD < prevMB->sad16))) {  
                 if (MotionFlags & PMV_QUICKSTOP16)  
                         goto PMVfast16_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto PMVfast16_Terminate_with_Refine;  
1066          }          }
1067    
1068                            SearchP(pRef, pRefH->y, pRefV->y, pRefHV->y, pCurrent, x,
1069                                                    y, MotionFlags, current->global_flags, pMB->quant,
1070                                                    &Data, pParam, pMBs, reference->mbs,
1071                                                    current->global_flags & XVID_INTER4V, pMB);
1072    
1073  /************ (Diamond Search)  **************/  /* final skip decision, a.k.a. "the vector you found, really that good?" */
1074  /*                          if (!(current->global_flags & XVID_GMC || current->global_flags & XVID_MODEDECISION_BITS)) {
1075     Step 7: Perform Diamond search, with either the small or large diamond.                                  if ( pMB->dquant == NO_CHANGE && sad00 < pMB->quant * MAX_SAD00_FOR_SKIP) {
1076     If Found=2 only examine one Diamond pattern, and afterwards goto step 10                                          if ( (100*pMB->sad16)/(sad00+1) > FINAL_SKIP_THRESH * (Data.rrv ? 4:1) )
1077     Step 8: If small diamond, iterate small diamond search pattern until motion vector lies in the center of the diamond.                                                  if (Data.chroma || SkipDecisionP(pCurrent, pRef, x, y, iEdgedWidth/2, pMB->quant, Data.rrv))
1078     If center then goto step 10.                                                          SkipMacroblockP(pMB, sad00);
1079     Step 9: If large diamond, iterate large diamond search pattern until motion vector lies in the center.                                  }
1080     Refine by using small diamond and goto step 10.                          }
1081  */                          if (pMB->mode == MODE_INTRA)
1082                                    if (++iIntra > iLimit) return 1;
1083          if (MotionFlags & PMV_USESQUARES16)                  }
                 MainSearchPtr = Square16_MainSearch;  
         else if (MotionFlags & PMV_ADVANCEDDIAMOND16)  
                 MainSearchPtr = AdvDiamond16_MainSearch;  
         else  
                 MainSearchPtr = Diamond16_MainSearch;  
   
         backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */  
   
   
 /* default: use best prediction as starting point for one call of PMVfast_MainSearch */  
         iSAD =  
                 (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,  
                                                   currMV->x, currMV->y, iMinSAD, &newMV, center_x, center_y,  
                                                   min_dx, max_dx,  
                                                   min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode,  
                                                   iQuant, iFound);  
   
         if (iSAD < iMinSAD) {  
                 *currMV = newMV;  
                 iMinSAD = iSAD;  
1084          }          }
1085    
1086          if (MotionFlags & PMV_EXTSEARCH16) {          if (current->global_flags & XVID_GMC )  /* GMC only for S(GMC)-VOPs */
1087  /* extended: search (up to) two more times: orignal prediction and (0,0) */          {
1088                    current->warp = GlobalMotionEst( pMBs, pParam, current, reference, pRefH, pRefV, pRefHV);
                 if (!(MVequal(pmv[0], backupMV))) {  
                         iSAD =  
                                 (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,  
                                                                   center_x, center_y, iMinSAD, &newMV, center_x, center_y,  
                                                                   min_dx, max_dx, min_dy, max_dy, iEdgedWidth,  
                                                                   iDiamondSize, iFcode, iQuant, iFound);  
   
                         if (iSAD < iMinSAD) {  
                                 *currMV = newMV;  
                                 iMinSAD = iSAD;  
1089                          }                          }
1090            return 0;
1091                  }                  }
1092    
                 if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {  
                         iSAD =  
                                 (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, 0, 0,  
                                                                   iMinSAD, &newMV, center_x, center_y,  
                                                                   min_dx, max_dx, min_dy, max_dy,  
                                                                   iEdgedWidth, iDiamondSize, iFcode,  
                                                                   iQuant, iFound);  
1093    
1094                          if (iSAD < iMinSAD) {  static __inline int
1095                                  *currMV = newMV;  make_mask(const VECTOR * const pmv, const int i)
1096                                  iMinSAD = iSAD;  {
1097            int mask = 255, j;
1098            for (j = 0; j < i; j++) {
1099                    if (MVequal(pmv[i], pmv[j])) return 0; // same vector has been checked already
1100                    if (pmv[i].x == pmv[j].x) {
1101                            if (pmv[i].y == pmv[j].y + iDiamondSize) mask &= ~4;
1102                            else if (pmv[i].y == pmv[j].y - iDiamondSize) mask &= ~8;
1103                    } else
1104                            if (pmv[i].y == pmv[j].y) {
1105                                    if (pmv[i].x == pmv[j].x + iDiamondSize) mask &= ~1;
1106                                    else if (pmv[i].x == pmv[j].x - iDiamondSize) mask &= ~2;
1107                          }                          }
1108                  }                  }
1109            return mask;
1110          }          }
1111    
1112  /*  static __inline void
1113     Step 10:  The motion vector is chosen according to the block corresponding to MinSAD.  PreparePredictionsP(VECTOR * const pmv, int x, int y, int iWcount,
1114  */                          int iHcount, const MACROBLOCK * const prevMB, int rrv)
1115    {
1116    
1117    PMVfast16_Terminate_with_Refine:  //this function depends on get_pmvdata which means that it sucks. It should get the predictions by itself
1118          if (MotionFlags & PMV_HALFPELREFINE16)  // perform final half-pel step          if (rrv) { iWcount /= 2; iHcount /= 2; }
                 iMinSAD =  
                         Halfpel16_Refine(pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV,  
                                                          iMinSAD, center_x, center_y, min_dx, max_dx, min_dy, max_dy,  
                                                          iFcode, iQuant, iEdgedWidth);  
1119    
1120    PMVfast16_Terminate_without_Refine:          if ( (y != 0) && (x < (iWcount-1)) ) {          // [5] top-right neighbour
1121          currPMV->x = currMV->x - center_x;                  pmv[5].x = EVEN(pmv[3].x);
1122          currPMV->y = currMV->y - center_y;                  pmv[5].y = EVEN(pmv[3].y);
1123          return iMinSAD;          } else pmv[5].x = pmv[5].y = 0;
 }  
1124    
1125            if (x != 0) { pmv[3].x = EVEN(pmv[1].x); pmv[3].y = EVEN(pmv[1].y); }// pmv[3] is left neighbour
1126            else pmv[3].x = pmv[3].y = 0;
1127    
1128            if (y != 0) { pmv[4].x = EVEN(pmv[2].x); pmv[4].y = EVEN(pmv[2].y); }// [4] top neighbour
1129            else pmv[4].x = pmv[4].y = 0;
1130    
1131            // [1] median prediction
1132            pmv[1].x = EVEN(pmv[0].x); pmv[1].y = EVEN(pmv[0].y);
1133    
1134            pmv[0].x = pmv[0].y = 0; // [0] is zero; not used in the loop (checked before) but needed here for make_mask
1135    
1136            pmv[2].x = EVEN(prevMB->mvs[0].x); // [2] is last frame
1137            pmv[2].y = EVEN(prevMB->mvs[0].y);
1138    
1139  int32_t          if ((x < iWcount-1) && (y < iHcount-1)) {
1140  Diamond8_MainSearch(const uint8_t * const pRef,                  pmv[6].x = EVEN((prevMB+1+iWcount)->mvs[0].x); //[6] right-down neighbour in last frame
1141                                          const uint8_t * const pRefH,                  pmv[6].y = EVEN((prevMB+1+iWcount)->mvs[0].y);
1142                                          const uint8_t * const pRefV,          } else pmv[6].x = pmv[6].y = 0;
                                         const uint8_t * const pRefHV,  
                                         const uint8_t * const cur,  
                                         const int x,  
                                         const int y,  
                                         int32_t start_x,  
                                         int32_t start_y,  
                                         int32_t iMinSAD,  
                                         VECTOR * const currMV,  
                                    const int center_x,  
                                    const int center_y,  
                                         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 iDirectionBackup;  
         int32_t iSAD;  
         VECTOR backupMV;  
   
         backupMV.x = start_x;  
         backupMV.y = start_y;  
   
 /* 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);  
1143    
1144          if (iDirection) {          if (rrv) {
1145                  while (!iFound) {                  int i;
1146                          iFound = 1;                  for (i = 0; i < 7; i++) {
1147                          backupMV = *currMV;     // since iDirection!=0, this is well defined!                          pmv[i].x = RRV_MV_SCALEUP(pmv[i].x);
1148                          iDirectionBackup = iDirection;                          pmv[i].y = RRV_MV_SCALEUP(pmv[i].y);
   
                         if (iDirectionBackup != 2)  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                   backupMV.y, 1);  
                         if (iDirectionBackup != 1)  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                   backupMV.y, 2);  
                         if (iDirectionBackup != 4)  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x,  
                                                                                   backupMV.y - iDiamondSize, 3);  
                         if (iDirectionBackup != 3)  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x,  
                                                                                   backupMV.y + iDiamondSize, 4);  
1149                  }                  }
         } else {  
                 currMV->x = start_x;  
                 currMV->y = start_y;  
1150          }          }
         return iMinSAD;  
1151  }  }
1152    
1153    static int
1154    ModeDecision(const uint32_t iQuant, SearchData * const Data,
1155                    int inter4v,
1156                    MACROBLOCK * const pMB,
1157                    const MACROBLOCK * const pMBs,
1158                    const int x, const int y,
1159                    const MBParam * const pParam,
1160                    const uint32_t MotionFlags,
1161                    const uint32_t GlobalFlags)
1162    {
1163    
1164            int mode = MODE_INTER;
1165    
1166            if (!(GlobalFlags & XVID_MODEDECISION_BITS)) { //normal, fast, SAD-based mode decision
1167                    int sad;
1168                    int InterBias = MV16_INTER_BIAS;
1169                    if (inter4v == 0 || Data->iMinSAD[0] < Data->iMinSAD[1] + Data->iMinSAD[2] +
1170                            Data->iMinSAD[3] + Data->iMinSAD[4] + IMV16X16 * (int32_t)iQuant) {
1171                            mode = MODE_INTER;
1172                            sad = Data->iMinSAD[0];
1173                    } else {
1174                            mode = MODE_INTER4V;
1175                            sad = Data->iMinSAD[1] + Data->iMinSAD[2] +
1176                                                    Data->iMinSAD[3] + Data->iMinSAD[4] + IMV16X16 * (int32_t)iQuant;
1177                            Data->iMinSAD[0] = sad;
1178                    }
1179    
1180  int32_t                  /* intra decision */
 Square8_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 start_x,  
                                         int32_t start_y,  
                                         int32_t iMinSAD,  
                                         VECTOR * const currMV,  
                                    const int center_x,  
                                    const int center_y,  
                                         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 square search around given starting point, return SAD of best */  
   
         int32_t iDirection = 0;  
         int32_t iSAD;  
         VECTOR backupMV;  
   
         backupMV.x = start_x;  
         backupMV.y = start_y;  
   
 /* It's one search with full square pattern, and new parts for all following diamonds */  
   
 /*   new direction are extra, so 1-4 is normal diamond  
       537  
       1*2  
       648  
 */  
   
         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);  
   
         CHECK_MV8_CANDIDATE_DIR(backupMV.x - iDiamondSize,  
                                                          backupMV.y - iDiamondSize, 5);  
         CHECK_MV8_CANDIDATE_DIR(backupMV.x - iDiamondSize,  
                                                          backupMV.y + iDiamondSize, 6);  
         CHECK_MV8_CANDIDATE_DIR(backupMV.x + iDiamondSize,  
                                                          backupMV.y - iDiamondSize, 7);  
         CHECK_MV8_CANDIDATE_DIR(backupMV.x + iDiamondSize,  
                                                          backupMV.y + iDiamondSize, 8);  
   
1181    
1182          if (iDirection) {                  if (iQuant > 8) InterBias += 100 * (iQuant - 8); // to make high quants work
1183                  while (!iFound) {                  if (y != 0)
1184                          iFound = 1;                          if ((pMB - pParam->mb_width)->mode == MODE_INTRA ) InterBias -= 80;
1185                          backupMV = *currMV;                  if (x != 0)
1186                            if ((pMB - 1)->mode == MODE_INTRA ) InterBias -= 80;
1187    
1188                          switch (iDirection) {                  if (Data->chroma) InterBias += 50; // to compensate bigger SAD
1189                          case 1:                  if (Data->rrv) InterBias *= 4;
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                    backupMV.y, 1);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 5);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 break;  
                         case 2:  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y,  
                                                                                  2);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 6);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
                                 break;  
1190    
1191                          case 3:                  if (InterBias < pMB->sad16) {
1192                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,                          int32_t deviation;
1193                                                                                   4);                          if (!Data->rrv) deviation = dev16(Data->Cur, Data->iEdgedWidth);
1194                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,                          else deviation = dev16(Data->Cur, Data->iEdgedWidth) +
1195                                                                                   backupMV.y - iDiamondSize, 7);                                  dev16(Data->Cur+8, Data->iEdgedWidth) +
1196                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,                                  dev16(Data->Cur + 8*Data->iEdgedWidth, Data->iEdgedWidth) +
1197                                                                                   backupMV.y + iDiamondSize, 8);                                  dev16(Data->Cur+8+8*Data->iEdgedWidth, Data->iEdgedWidth);
                                 break;  
1198    
1199                          case 4:                          if (deviation < (sad - InterBias)) return MODE_INTRA;
1200                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize,                  }
1201                                                                                   3);                  return mode;
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 5);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 6);  
                                 break;  
   
                         case 5:  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize, backupMV.y,  
                                                                                  1);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize,  
                                                                                  3);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 5);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 6);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 break;  
   
                         case 6:  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y,  
                                                                                  2);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize,  
                                                                                  3);  
   
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 5);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 6);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
1202    
1203                                  break;          } else {
1204    
1205                          case 7:                  int bits, intra, i;
1206                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,                  VECTOR backup[5], *v;
1207                                                                                     backupMV.y, 1);                  Data->lambda16 = iQuant;
1208                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,                  Data->lambda8 = pParam->m_quant_type;
                                                                                  4);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 5);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
                                 break;  
1209    
1210                          case 8:                  v = Data->qpel ? Data->currentQMV : Data->currentMV;
1211                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y,                  for (i = 0; i < 5; i++) {
1212                                                                                   2);                          Data->iMinSAD[i] = 256*4096;
1213                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,                          backup[i] = v[i];
                                                                                  4);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 6);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
                                 break;  
                         default:  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize, backupMV.y,  
                                                                                  1);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y,  
                                                                                  2);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize,  
                                                                                  3);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,  
                                                                                  4);  
   
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 5);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 6);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
                                 break;  
                         }  
1214                  }                  }
         } else {  
                 currMV->x = start_x;  
                 currMV->y = start_y;  
         }  
         return iMinSAD;  
 }  
   
1215    
1216                    bits = CountMBBitsInter(Data, pMBs, x, y, pParam, MotionFlags);
1217                    if (bits == 0) return MODE_INTER; // quick stop
1218    
1219                    if (inter4v) {
1220                            int bits_inter4v = CountMBBitsInter4v(Data, pMB, pMBs, x, y, pParam, MotionFlags, backup);
1221                            if (bits_inter4v < bits) { Data->iMinSAD[0] = bits = bits_inter4v; mode = MODE_INTER4V; }
1222                    }
1223    
1224                    intra = CountMBBitsIntra(Data);
1225    
1226  int32_t                  if (intra < bits) { *Data->iMinSAD = bits = intra; return MODE_INTRA; }
 Halfpel8_Refine_c(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 int center_x,  
                            const int center_y,  
                                 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) */  
   
         int32_t iSAD;  
         VECTOR backupMV = *currMV;  
   
         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);  
         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);  
1227    
1228          return iMinSAD;                  return mode;
1229            }
1230  }  }
1231    
1232    static void
1233  #define PMV_HALFPEL8 (PMV_HALFPELDIAMOND8|PMV_HALFPELREFINE8)  SearchP(const IMAGE * const pRef,
   
 int32_t  
 PMVfastSearch8(const uint8_t * const pRef,  
1234                             const uint8_t * const pRefH,                             const uint8_t * const pRefH,
1235                             const uint8_t * const pRefV,                             const uint8_t * const pRefV,
1236                             const uint8_t * const pRefHV,                             const uint8_t * const pRefHV,
1237                             const IMAGE * const pCur,                             const IMAGE * const pCur,
1238                             const int x,                             const int x,
1239                             const int y,                             const int y,
                            const int start_x,  
                            const int start_y,  
                                 const int center_x,  
                                 const int center_y,  
1240                             const uint32_t MotionFlags,                             const uint32_t MotionFlags,
1241                    const uint32_t GlobalFlags,
1242                             const uint32_t iQuant,                             const uint32_t iQuant,
1243                             const uint32_t iFcode,                  SearchData * const Data,
1244                             const MBParam * const pParam,                             const MBParam * const pParam,
1245                             const MACROBLOCK * const pMBs,                             const MACROBLOCK * const pMBs,
1246                             const MACROBLOCK * const prevMBs,                             const MACROBLOCK * const prevMBs,
1247                             VECTOR * const currMV,                  int inter4v,
1248                             VECTOR * const currPMV)                  MACROBLOCK * const pMB)
1249  {  {
         const uint32_t iWcount = pParam->mb_width;  
         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 * 8 + y * 8 * iEdgedWidth;  
   
         int32_t iDiamondSize;  
   
         int32_t min_dx;  
         int32_t max_dx;  
         int32_t min_dy;  
         int32_t max_dy;  
1250    
1251          VECTOR pmv[4];          int i, iDirection = 255, mask, threshA;
1252          int32_t psad[4];          VECTOR pmv[7];
         VECTOR newMV;  
         VECTOR backupMV;  
         VECTOR startMV;  
1253    
1254  //  const MACROBLOCK * const pMB = pMBs + (x>>1) + (y>>1) * iWcount;          get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
1255          const MACROBLOCK *const prevMB = prevMBs + (x >> 1) + (y >> 1) * iWcount;                                                  pParam->width, pParam->height, Data->iFcode - Data->qpel, 0, Data->rrv);
1256    
1257           int32_t threshA, threshB;          get_pmvdata2(pMBs, pParam->mb_width, 0, x, y, 0, pmv, Data->temp);
1258          int32_t iFound, bPredEq;  
1259          int32_t iMinSAD, iSAD;          Data->temp[5] = Data->temp[6] = 0; // chroma-sad cache
1260            i = Data->rrv ? 2 : 1;
1261          int32_t iSubBlock = (y & 1) + (y & 1) + (x & 1);          Data->Cur = pCur->y + (x + y * Data->iEdgedWidth) * 16*i;
1262            Data->CurV = pCur->v + (x + y * (Data->iEdgedWidth/2)) * 8*i;
1263            Data->CurU = pCur->u + (x + y * (Data->iEdgedWidth/2)) * 8*i;
1264    
1265            Data->RefP[0] = pRef->y + (x + Data->iEdgedWidth*y) * 16*i;
1266            Data->RefP[2] = pRefH + (x + Data->iEdgedWidth*y) * 16*i;
1267            Data->RefP[1] = pRefV + (x + Data->iEdgedWidth*y) * 16*i;
1268            Data->RefP[3] = pRefHV + (x + Data->iEdgedWidth*y) * 16*i;
1269            Data->RefP[4] = pRef->u + (x + y * (Data->iEdgedWidth/2)) * 8*i;
1270            Data->RefP[5] = pRef->v + (x + y * (Data->iEdgedWidth/2)) * 8*i;
1271    
1272            Data->lambda16 = lambda_vec16[iQuant];
1273            Data->lambda8 = lambda_vec8[iQuant];
1274            Data->qpel_precision = 0;
1275    
1276            if (pMB->dquant != NO_CHANGE) inter4v = 0;
1277    
1278            memset(Data->currentMV, 0, 5*sizeof(VECTOR));
1279    
1280            if (Data->qpel) Data->predMV = get_qpmv2(pMBs, pParam->mb_width, 0, x, y, 0);
1281            else Data->predMV = pmv[0];
1282    
1283            i = d_mv_bits(0, 0, Data->predMV, Data->iFcode, 0, 0);
1284            Data->iMinSAD[0] = pMB->sad16 + ((Data->lambda16 * i * pMB->sad16)>>10);
1285            Data->iMinSAD[1] = pMB->sad8[0] + ((Data->lambda8 * i * (pMB->sad8[0]+NEIGH_8X8_BIAS)) >> 10);
1286            Data->iMinSAD[2] = pMB->sad8[1];
1287            Data->iMinSAD[3] = pMB->sad8[2];
1288            Data->iMinSAD[4] = pMB->sad8[3];
1289    
1290            if ((!(GlobalFlags & XVID_MODEDECISION_BITS)) || (x | y)) {
1291                    threshA = Data->temp[0]; // that's where we keep this SAD atm
1292                    if (threshA < 512) threshA = 512;
1293                    else if (threshA > 1024) threshA = 1024;
1294            } else
1295                    threshA = 512;
1296    
1297          MainSearch8FuncPtr MainSearchPtr;          PreparePredictionsP(pmv, x, y, pParam->mb_width, pParam->mb_height,
1298                                            prevMBs + x + y * pParam->mb_width, Data->rrv);
1299    
1300          /* Init variables */          if (!Data->rrv) {
1301          startMV.x = start_x;                  if (inter4v | Data->chroma) CheckCandidate = CheckCandidate16;
1302          startMV.y = start_y;                          else CheckCandidate = CheckCandidate16no4v; //for extra speed
1303            } else CheckCandidate = CheckCandidate32;
1304    
1305    /* main loop. checking all predictions (but first, which is 0,0 and has been checked in MotionEstimation())*/
1306    
1307            for (i = 1; i < 7; i++) {
1308                    if (!(mask = make_mask(pmv, i)) ) continue;
1309                    CheckCandidate(pmv[i].x, pmv[i].y, mask, &iDirection, Data);
1310                    if (Data->iMinSAD[0] <= threshA) break;
1311            }
1312    
1313            if ((Data->iMinSAD[0] <= threshA) ||
1314                            (MVequal(Data->currentMV[0], (prevMBs+x+y*pParam->mb_width)->mvs[0]) &&
1315                            (Data->iMinSAD[0] < (prevMBs+x+y*pParam->mb_width)->sad16))) {
1316                    if (!(GlobalFlags & XVID_MODEDECISION_BITS)) inter4v = 0;       }
1317            else {
1318    
1319          /* Get maximum range */                  MainSearchFunc * MainSearchPtr;
1320          get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 8, iWidth, iHeight,                  if (MotionFlags & PMV_USESQUARES16) MainSearchPtr = SquareSearch;
1321                            iFcode);                  else if (MotionFlags & PMV_ADVANCEDDIAMOND16) MainSearchPtr = AdvDiamondSearch;
1322                            else MainSearchPtr = DiamondSearch;
1323    
1324                    MainSearchPtr(Data->currentMV->x, Data->currentMV->y, Data, iDirection);
1325    
1326    /* extended search, diamond starting in 0,0 and in prediction.
1327            note that this search is/might be done in halfpel positions,
1328            which makes it more different than the diamond above */
1329    
1330          if (!(MotionFlags & PMV_HALFPELDIAMOND8)) {                  if (MotionFlags & PMV_EXTSEARCH16) {
1331                  min_dx = EVEN(min_dx);                          int32_t bSAD;
1332                  max_dx = EVEN(max_dx);                          VECTOR startMV = Data->predMV, backupMV = Data->currentMV[0];
1333                  min_dy = EVEN(min_dy);                          if (Data->rrv) {
1334                  max_dy = EVEN(max_dy);                                  startMV.x = RRV_MV_SCALEUP(startMV.x);
1335                                    startMV.y = RRV_MV_SCALEUP(startMV.y);
1336          }          }
1337                            if (!(MVequal(startMV, backupMV))) {
1338                                    bSAD = Data->iMinSAD[0]; Data->iMinSAD[0] = MV_MAX_ERROR;
1339    
1340          /* because we might use IF (dx>max_dx) THEN dx=max_dx; */                                  CheckCandidate(startMV.x, startMV.y, 255, &iDirection, Data);
1341          //bPredEq = get_pmvdata(pMBs, (x >> 1), (y >> 1), iWcount, iSubBlock, pmv, psad);                                  MainSearchPtr(startMV.x, startMV.y, Data, 255);
1342          bPredEq = get_pmvdata2(pMBs, iWcount, 0, (x >> 1), (y >> 1), iSubBlock, pmv, psad);                                  if (bSAD < Data->iMinSAD[0]) {
1343                                            Data->currentMV[0] = backupMV;
1344          if ((x == 0) && (y == 0)) {                                          Data->iMinSAD[0] = bSAD; }
1345                  threshA = 512 / 4;                          }
                 threshB = 1024 / 4;  
   
         } else {  
                 threshA = psad[0] / 4;  /* good estimate? */  
                 threshB = threshA + 256 / 4;  
                 if (threshA < 512 / 4)  
                         threshA = 512 / 4;  
                 if (threshA > 1024 / 4)  
                         threshA = 1024 / 4;  
                 if (threshB > 1792 / 4)  
                         threshB = 1792 / 4;  
         }  
   
         iFound = 0;  
   
 /* Step 4: Calculate SAD around the Median prediction.  
    MinSAD=SAD  
    If Motion Vector equal to Previous frame motion vector  
    and MinSAD<PrevFrmSAD goto Step 10.  
    If SAD<=256 goto Step 10.  
 */  
   
   
 // Prepare for main loop  
   
   if (MotionFlags & PMV_USESQUARES8)  
       MainSearchPtr = Square8_MainSearch;  
   else  
   
         if (MotionFlags & PMV_ADVANCEDDIAMOND8)  
                 MainSearchPtr = AdvDiamond8_MainSearch;  
         else  
                 MainSearchPtr = Diamond8_MainSearch;  
   
   
         *currMV = startMV;  
   
         iMinSAD =  
                 sad8(cur,  
                          get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 8, currMV,  
                                                 iEdgedWidth), iEdgedWidth);  
         iMinSAD +=  
                 calc_delta_8(currMV->x - center_x, currMV->y - center_y,  
                                          (uint8_t) iFcode, iQuant);  
   
         if ((iMinSAD < 256 / 4) || ((MVequal(*currMV, prevMB->mvs[iSubBlock]))  
                                                                 && ((int32_t) iMinSAD <  
                                                                         prevMB->sad8[iSubBlock]))) {  
                 if (MotionFlags & PMV_QUICKSTOP16)  
                         goto PMVfast8_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto PMVfast8_Terminate_with_Refine;  
         }  
   
 /* Step 2 (lazy eval): 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], prevMB->mvs[iSubBlock])))  
                 iFound = 2;  
   
 /* Step 3 (lazy eval): If Distance>0 or thresb<1536 or PredEq=1 Select small Diamond Search.  
    Otherwise select large Diamond Search.  
 */  
   
         if ((!MVzero(pmv[0])) || (threshB < 1536 / 4) || (bPredEq))  
                 iDiamondSize = 1;               // 1 halfpel!  
         else  
                 iDiamondSize = 2;               // 2 halfpel = 1 full pixel!  
   
         if (!(MotionFlags & PMV_HALFPELDIAMOND8))  
                 iDiamondSize *= 2;  
1346    
1347                            backupMV = Data->currentMV[0];
1348                            startMV.x = startMV.y = 1;
1349                            if (!(MVequal(startMV, backupMV))) {
1350                                    bSAD = Data->iMinSAD[0]; Data->iMinSAD[0] = MV_MAX_ERROR;
1351    
1352  /*                                  CheckCandidate(startMV.x, startMV.y, 255, &iDirection, Data);
1353     Step 5: Calculate SAD for motion vectors taken from left block, top, top-right, and Previous frame block.                                  MainSearchPtr(startMV.x, startMV.y, Data, 255);
1354     Also calculate (0,0) but do not subtract offset.                                  if (bSAD < Data->iMinSAD[0]) {
1355     Let MinSAD be the smallest SAD up to this point.                                          Data->currentMV[0] = backupMV;
1356     If MV is (0,0) subtract offset.                                          Data->iMinSAD[0] = bSAD; }
1357  */                          }
1358                    }
1359            }
1360    
1361  // the median prediction might be even better than mv16          if (MotionFlags & PMV_HALFPELREFINE16)
1362                    SubpelRefine(Data);
1363    
1364          if (!MVequal(pmv[0], startMV))          for(i = 0; i < 5; i++) {
1365                  CHECK_MV8_CANDIDATE(center_x, center_y);                  Data->currentQMV[i].x = 2 * Data->currentMV[i].x; // initialize qpel vectors
1366                    Data->currentQMV[i].y = 2 * Data->currentMV[i].y;
1367            }
1368    
1369  // (0,0) if needed          if (MotionFlags & PMV_QUARTERPELREFINE16) {
         if (!MVzero(pmv[0]))  
                 if (!MVzero(startMV))  
                         CHECK_MV8_ZERO;  
   
 // previous frame MV if needed  
         if (!MVzero(prevMB->mvs[iSubBlock]))  
                 if (!MVequal(prevMB->mvs[iSubBlock], startMV))  
                         if (!MVequal(prevMB->mvs[iSubBlock], pmv[0]))  
                                 CHECK_MV8_CANDIDATE(prevMB->mvs[iSubBlock].x,  
                                                                         prevMB->mvs[iSubBlock].y);  
   
         if ((iMinSAD <= threshA) ||  
                 (MVequal(*currMV, prevMB->mvs[iSubBlock]) &&  
                  ((int32_t) iMinSAD < prevMB->sad8[iSubBlock]))) {  
                 if (MotionFlags & PMV_QUICKSTOP16)  
                         goto PMVfast8_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto PMVfast8_Terminate_with_Refine;  
         }  
   
 // left neighbour, if allowed and needed  
         if (!MVzero(pmv[1]))  
                 if (!MVequal(pmv[1], startMV))  
                         if (!MVequal(pmv[1], prevMB->mvs[iSubBlock]))  
                                 if (!MVequal(pmv[1], pmv[0])) {  
                                         if (!(MotionFlags & PMV_HALFPEL8)) {  
                                                 pmv[1].x = EVEN(pmv[1].x);  
                                                 pmv[1].y = EVEN(pmv[1].y);  
                                         }  
                                         CHECK_MV8_CANDIDATE(pmv[1].x, pmv[1].y);  
                                 }  
 // top neighbour, if allowed and needed  
         if (!MVzero(pmv[2]))  
                 if (!MVequal(pmv[2], startMV))  
                         if (!MVequal(pmv[2], prevMB->mvs[iSubBlock]))  
                                 if (!MVequal(pmv[2], pmv[0]))  
                                         if (!MVequal(pmv[2], pmv[1])) {  
                                                 if (!(MotionFlags & PMV_HALFPEL8)) {  
                                                         pmv[2].x = EVEN(pmv[2].x);  
                                                         pmv[2].y = EVEN(pmv[2].y);  
                                                 }  
                                                 CHECK_MV8_CANDIDATE(pmv[2].x, pmv[2].y);  
   
 // top right neighbour, if allowed and needed  
                                                 if (!MVzero(pmv[3]))  
                                                         if (!MVequal(pmv[3], startMV))  
                                                                 if (!MVequal(pmv[3], prevMB->mvs[iSubBlock]))  
                                                                         if (!MVequal(pmv[3], pmv[0]))  
                                                                                 if (!MVequal(pmv[3], pmv[1]))  
                                                                                         if (!MVequal(pmv[3], pmv[2])) {  
                                                                                                 if (!  
                                                                                                         (MotionFlags &  
                                                                                                          PMV_HALFPEL8)) {  
                                                                                                         pmv[3].x = EVEN(pmv[3].x);  
                                                                                                         pmv[3].y = EVEN(pmv[3].y);  
                                                                                                 }  
                                                                                                 CHECK_MV8_CANDIDATE(pmv[3].x,  
                                                                                                                                         pmv[3].y);  
                                                                                         }  
                                         }  
   
         if ((MVzero(*currMV)) &&  
                 (!MVzero(pmv[0])) /* && (iMinSAD <= iQuant * 96) */ )  
                 iMinSAD -= MV8_00_BIAS;  
1370    
1371                    get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
1372                                    pParam->width, pParam->height, Data->iFcode, 1, 0);
1373                    Data->qpel_precision = 1;
1374                    SubpelRefine(Data);
1375            }
1376    
1377  /* Step 6: If MinSAD <= thresa goto Step 10.          if ((!(GlobalFlags & XVID_MODEDECISION_BITS)) && (Data->iMinSAD[0] < (int32_t)iQuant * 30)) inter4v = 0;
    If Motion Vector equal to Previous frame motion vector and MinSAD<PrevFrmSAD goto Step 10.  
 */  
1378    
1379          if ((iMinSAD <= threshA) ||          if (inter4v) {
1380                  (MVequal(*currMV, prevMB->mvs[iSubBlock]) &&                  SearchData Data8;
1381                   ((int32_t) iMinSAD < prevMB->sad8[iSubBlock]))) {                  memcpy(&Data8, Data, sizeof(SearchData)); //quick copy of common data
                 if (MotionFlags & PMV_QUICKSTOP16)  
                         goto PMVfast8_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto PMVfast8_Terminate_with_Refine;  
         }  
   
 /************ (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.  
 */  
1382    
1383          backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */                  Search8(Data, 2*x, 2*y, MotionFlags, pParam, pMB, pMBs, 0, &Data8);
1384                    Search8(Data, 2*x + 1, 2*y, MotionFlags, pParam, pMB, pMBs, 1, &Data8);
1385                    Search8(Data, 2*x, 2*y + 1, MotionFlags, pParam, pMB, pMBs, 2, &Data8);
1386                    Search8(Data, 2*x + 1, 2*y + 1, MotionFlags, pParam, pMB, pMBs, 3, &Data8);
1387    
1388  /* default: use best prediction as starting point for one call of PMVfast_MainSearch */                  if ((Data->chroma) && (!(GlobalFlags & XVID_MODEDECISION_BITS))) {
1389          iSAD =                          // chroma is only used for comparsion to INTER. if the comparsion will be done in BITS domain, there is no reason to compute it
1390                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV->x,                          int sumx = 0, sumy = 0;
1391                                                    currMV->y, iMinSAD, &newMV, center_x, center_y, min_dx, max_dx,                          const int div = Data->qpel ? 2 : 1;
1392                                                    min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode,                          const VECTOR * const mv = Data->qpel ? pMB->qmvs : pMB->mvs;
                                                   iQuant, iFound);  
1393    
1394          if (iSAD < iMinSAD) {                          for (i = 0; i < 4; i++) {
1395                  *currMV = newMV;                                  sumx += mv[i].x / div;
1396                  iMinSAD = iSAD;                                  sumy += mv[i].y / div;
1397          }          }
1398    
1399          if (MotionFlags & PMV_EXTSEARCH8) {                          Data->iMinSAD[1] += ChromaSAD(  (sumx >> 3) + roundtab_76[sumx & 0xf],
1400  /* extended: search (up to) two more times: orignal prediction and (0,0) */                                                                                          (sumy >> 3) + roundtab_76[sumy & 0xf], Data);
   
                 if (!(MVequal(pmv[0], backupMV))) {  
                         iSAD =  
                                 (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,  
                                                                   pmv[0].x, pmv[0].y, iMinSAD, &newMV, center_x, center_y,  
                                                                   min_dx, max_dx, min_dy, max_dy, iEdgedWidth,  
                                                                   iDiamondSize, iFcode, iQuant, iFound);  
   
                         if (iSAD < iMinSAD) {  
                                 *currMV = newMV;  
                                 iMinSAD = iSAD;  
1401                          }                          }
1402                  }                  }
1403    
1404                  if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {          inter4v = ModeDecision(iQuant, Data, inter4v, pMB, pMBs, x, y, pParam, MotionFlags, GlobalFlags);
                         iSAD =  
                                 (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, 0, 0,  
                                                                   iMinSAD, &newMV, center_x, center_y, min_dx, max_dx, min_dy,  
                                                                   max_dy, iEdgedWidth, iDiamondSize, iFcode,  
                                                                   iQuant, iFound);  
1405    
1406                          if (iSAD < iMinSAD) {          if (Data->rrv) {
1407                                  *currMV = newMV;                          Data->currentMV[0].x = RRV_MV_SCALEDOWN(Data->currentMV[0].x);
1408                                  iMinSAD = iSAD;                          Data->currentMV[0].y = RRV_MV_SCALEDOWN(Data->currentMV[0].y);
                         }  
1409                  }                  }
         }  
   
 /* Step 10: The motion vector is chosen according to the block corresponding to MinSAD.  
    By performing an optional local half-pixel search, we can refine this result even further.  
 */  
1410    
1411    PMVfast8_Terminate_with_Refine:          if (inter4v == MODE_INTER) {
1412          if (MotionFlags & PMV_HALFPELREFINE8)   // perform final half-pel step                  pMB->mode = MODE_INTER;
1413                  iMinSAD =                  pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = Data->currentMV[0];
1414                          Halfpel8_Refine(pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV,                  pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] = pMB->sad8[3] = Data->iMinSAD[0];
                                                         iMinSAD, center_x, center_y, min_dx, max_dx, min_dy, max_dy,  
                                                         iFcode, iQuant, iEdgedWidth);  
1415    
1416                    if(Data->qpel) {
1417                            pMB->qmvs[0] = pMB->qmvs[1]
1418                                    = pMB->qmvs[2] = pMB->qmvs[3] = Data->currentQMV[0];
1419                            pMB->pmvs[0].x = Data->currentQMV[0].x - Data->predMV.x;
1420                            pMB->pmvs[0].y = Data->currentQMV[0].y - Data->predMV.y;
1421                    } else {
1422                            pMB->pmvs[0].x = Data->currentMV[0].x - Data->predMV.x;
1423                            pMB->pmvs[0].y = Data->currentMV[0].y - Data->predMV.y;
1424                    }
1425    
1426    PMVfast8_Terminate_without_Refine:          } else if (inter4v == MODE_INTER4V) {
1427          currPMV->x = currMV->x - center_x;                  pMB->mode = MODE_INTER4V;
1428          currPMV->y = currMV->y - center_y;                  pMB->sad16 = Data->iMinSAD[0];
1429            } else { // INTRA mode
1430                    SkipMacroblockP(pMB, 0); // not skip, but similar enough
1431                    pMB->mode = MODE_INTRA;
1432            }
1433    
         return iMinSAD;  
1434  }  }
1435    
1436  int32_t  static void
1437  EPZSSearch16(const uint8_t * const pRef,  Search8(const SearchData * const OldData,
1438                           const uint8_t * const pRefH,                  const int x, const int y,
                          const uint8_t * const pRefV,  
                          const uint8_t * const pRefHV,  
                          const IMAGE * const pCur,  
                          const int x,  
                          const int y,  
                         const int start_x,  
                         const int start_y,  
                         const int center_x,  
                         const int center_y,  
1439                           const uint32_t MotionFlags,                           const uint32_t MotionFlags,
                          const uint32_t iQuant,  
                          const uint32_t iFcode,  
1440                           const MBParam * const pParam,                           const MBParam * const pParam,
1441                    MACROBLOCK * const pMB,
1442                           const MACROBLOCK * const pMBs,                           const MACROBLOCK * const pMBs,
1443                           const MACROBLOCK * const prevMBs,                  const int block,
1444                           VECTOR * const currMV,                  SearchData * const Data)
                          VECTOR * const currPMV)  
1445  {  {
1446          const uint32_t iWcount = pParam->mb_width;          int i = 0;
1447          const uint32_t iHcount = pParam->mb_height;          Data->iMinSAD = OldData->iMinSAD + 1 + block;
1448            Data->currentMV = OldData->currentMV + 1 + block;
1449            Data->currentQMV = OldData->currentQMV + 1 + block;
1450    
1451            if(Data->qpel) {
1452                    Data->predMV = get_qpmv2(pMBs, pParam->mb_width, 0, x/2, y/2, block);
1453                    if (block != 0) i = d_mv_bits(  Data->currentQMV->x, Data->currentQMV->y,
1454                                                                                    Data->predMV, Data->iFcode, 0, 0);
1455            } else {
1456                    Data->predMV = get_pmv2(pMBs, pParam->mb_width, 0, x/2, y/2, block);
1457                    if (block != 0) i = d_mv_bits(  Data->currentMV->x, Data->currentMV->y,
1458                                                                                    Data->predMV, Data->iFcode, 0, Data->rrv);
1459            }
1460    
1461          const int32_t iWidth = pParam->width;          *(Data->iMinSAD) += (Data->lambda8 * i * (*Data->iMinSAD + NEIGH_8X8_BIAS))>>10;
         const int32_t iHeight = pParam->height;  
         const int32_t iEdgedWidth = pParam->edged_width;  
1462    
1463          const uint8_t *cur = pCur->y + x * 16 + y * 16 * iEdgedWidth;          if (MotionFlags & (PMV_EXTSEARCH8|PMV_HALFPELREFINE8|PMV_QUARTERPELREFINE8)) {
1464    
1465          int32_t min_dx;                  if (Data->rrv) i = 16; else i = 8;
         int32_t max_dx;  
         int32_t min_dy;  
         int32_t max_dy;  
1466    
1467          VECTOR newMV;                  Data->RefP[0] = OldData->RefP[0] + i * ((block&1) + Data->iEdgedWidth*(block>>1));
1468          VECTOR backupMV;                  Data->RefP[1] = OldData->RefP[1] + i * ((block&1) + Data->iEdgedWidth*(block>>1));
1469                    Data->RefP[2] = OldData->RefP[2] + i * ((block&1) + Data->iEdgedWidth*(block>>1));
1470                    Data->RefP[3] = OldData->RefP[3] + i * ((block&1) + Data->iEdgedWidth*(block>>1));
1471    
1472          VECTOR pmv[4];                  Data->Cur = OldData->Cur + i * ((block&1) + Data->iEdgedWidth*(block>>1));
1473          int32_t psad[8];                  Data->qpel_precision = 0;
1474    
1475          static MACROBLOCK *oldMBs = NULL;                  get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 8,
1476                                            pParam->width, pParam->height, Data->iFcode - Data->qpel, 0, Data->rrv);
1477    
1478  //  const MACROBLOCK * const pMB = pMBs + x + y * iWcount;                  if (!Data->rrv) CheckCandidate = CheckCandidate8;
1479          const MACROBLOCK *const prevMB = prevMBs + x + y * iWcount;                  else CheckCandidate = CheckCandidate16no4v;
         MACROBLOCK *oldMB = NULL;  
1480    
1481           int32_t thresh2;                  if (MotionFlags & PMV_EXTSEARCH8 && (!(MotionFlags & EXTSEARCH_BITS))) {
1482          int32_t bPredEq;                          int32_t temp_sad = *(Data->iMinSAD); // store current MinSAD
         int32_t iMinSAD, iSAD = 9999;  
1483    
1484          MainSearch16FuncPtr MainSearchPtr;                          MainSearchFunc *MainSearchPtr;
1485                            if (MotionFlags & PMV_USESQUARES8) MainSearchPtr = SquareSearch;
1486                                    else if (MotionFlags & PMV_ADVANCEDDIAMOND8) MainSearchPtr = AdvDiamondSearch;
1487                                            else MainSearchPtr = DiamondSearch;
1488    
1489          if (oldMBs == NULL) {                          MainSearchPtr(Data->currentMV->x, Data->currentMV->y, Data, 255);
                 oldMBs = (MACROBLOCK *) calloc(iWcount * iHcount, sizeof(MACROBLOCK));  
 //      fprintf(stderr,"allocated %d bytes for oldMBs\n",iWcount*iHcount*sizeof(MACROBLOCK));  
         }  
         oldMB = oldMBs + x + y * iWcount;  
1490    
1491  /* Get maximum range */                          if(*(Data->iMinSAD) < temp_sad) {
1492          get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 16, iWidth, iHeight,                                          Data->currentQMV->x = 2 * Data->currentMV->x; // update our qpel vector
1493                            iFcode);                                          Data->currentQMV->y = 2 * Data->currentMV->y;
   
         if (!(MotionFlags & PMV_HALFPEL16)) {  
                 min_dx = EVEN(min_dx);  
                 max_dx = EVEN(max_dx);  
                 min_dy = EVEN(min_dy);  
                 max_dy = EVEN(max_dy);  
1494          }          }
         /* because we might use something like IF (dx>max_dx) THEN dx=max_dx; */  
         //bPredEq = get_pmvdata(pMBs, x, y, iWcount, 0, pmv, psad);  
         bPredEq = get_pmvdata2(pMBs, iWcount, 0, x, y, 0, pmv, psad);  
   
 /* Step 4: Calculate SAD around the Median prediction.  
         MinSAD=SAD  
         If Motion Vector equal to Previous frame motion vector  
                 and MinSAD<PrevFrmSAD goto Step 10.  
         If SAD<=256 goto Step 10.  
 */  
   
 // Prepare for main loop  
   
         currMV->x = start_x;  
         currMV->y = start_y;  
   
         if (!(MotionFlags & PMV_HALFPEL16)) {  
                 currMV->x = EVEN(currMV->x);  
                 currMV->y = EVEN(currMV->y);  
         }  
   
         if (currMV->x > max_dx)  
                 currMV->x = max_dx;  
         if (currMV->x < min_dx)  
                 currMV->x = min_dx;  
         if (currMV->y > max_dy)  
                 currMV->y = max_dy;  
         if (currMV->y < min_dy)  
                 currMV->y = min_dy;  
   
 /***************** This is predictor SET A: only median prediction ******************/  
   
         iMinSAD =  
                 sad16(cur,  
                           get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 16, currMV,  
                                                  iEdgedWidth), iEdgedWidth, MV_MAX_ERROR);  
         iMinSAD +=  
                 calc_delta_16(currMV->x - center_x, currMV->y - center_y,  
                                           (uint8_t) iFcode, iQuant);  
   
 // thresh1 is fixed to 256  
         if ((iMinSAD < 256) ||  
                 ((MVequal(*currMV, prevMB->mvs[0])) &&  
                  ((int32_t) iMinSAD < prevMB->sad16))) {  
                 if (MotionFlags & PMV_QUICKSTOP16)  
                         goto EPZS16_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto EPZS16_Terminate_with_Refine;  
         }  
   
 /************** This is predictor SET B: (0,0), prev.frame MV, neighbours **************/  
   
 // previous frame MV  
         CHECK_MV16_CANDIDATE(prevMB->mvs[0].x, prevMB->mvs[0].y);  
   
 // set threshhold based on Min of Prediction and SAD of collocated block  
 // CHECK_MV16 always uses iSAD for the SAD of last vector to check, so now iSAD is what we want  
   
         if ((x == 0) && (y == 0)) {  
                 thresh2 = 512;  
         } else {  
 /* T_k = 1.2 * MIN(SAD_top,SAD_left,SAD_topleft,SAD_coll) +128;   [Tourapis, 2002] */  
   
                 thresh2 = MIN(psad[0], iSAD) * 6 / 5 + 128;  
1495          }          }
1496    
1497  // MV=(0,0) is often a good choice                  if (MotionFlags & PMV_HALFPELREFINE8) {
1498                            int32_t temp_sad = *(Data->iMinSAD); // store current MinSAD
         CHECK_MV16_ZERO;  
1499    
1500                            SubpelRefine(Data); // perform halfpel refine of current best vector
1501    
1502  // left neighbour, if allowed                          if(*(Data->iMinSAD) < temp_sad) { // we have found a better match
1503          if (x != 0) {                                  Data->currentQMV->x = 2 * Data->currentMV->x; // update our qpel vector
1504                  if (!(MotionFlags & PMV_HALFPEL16)) {                                  Data->currentQMV->y = 2 * Data->currentMV->y;
                         pmv[1].x = EVEN(pmv[1].x);  
                         pmv[1].y = EVEN(pmv[1].y);  
                 }  
                 CHECK_MV16_CANDIDATE(pmv[1].x, pmv[1].y);  
1505          }          }
 // top neighbour, if allowed  
         if (y != 0) {  
                 if (!(MotionFlags & PMV_HALFPEL16)) {  
                         pmv[2].x = EVEN(pmv[2].x);  
                         pmv[2].y = EVEN(pmv[2].y);  
1506                  }                  }
                 CHECK_MV16_CANDIDATE(pmv[2].x, pmv[2].y);  
1507    
1508  // top right neighbour, if allowed                  if (Data->qpel && MotionFlags & PMV_QUARTERPELREFINE8) {
1509                  if ((uint32_t) x != (iWcount - 1)) {                                  Data->qpel_precision = 1;
1510                          if (!(MotionFlags & PMV_HALFPEL16)) {                                  get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 8,
1511                                  pmv[3].x = EVEN(pmv[3].x);                                          pParam->width, pParam->height, Data->iFcode, 1, 0);
1512                                  pmv[3].y = EVEN(pmv[3].y);                                  SubpelRefine(Data);
                         }  
                         CHECK_MV16_CANDIDATE(pmv[3].x, pmv[3].y);  
1513                  }                  }
1514          }          }
1515    
1516  /* Terminate if MinSAD <= T_2          if (Data->rrv) {
1517     Terminate if MV[t] == MV[t-1] and MinSAD[t] <= MinSAD[t-1]                          Data->currentMV->x = RRV_MV_SCALEDOWN(Data->currentMV->x);
1518  */                          Data->currentMV->y = RRV_MV_SCALEDOWN(Data->currentMV->y);
   
         if ((iMinSAD <= thresh2)  
                 || (MVequal(*currMV, prevMB->mvs[0]) &&  
                         ((int32_t) iMinSAD <= prevMB->sad16))) {  
                 if (MotionFlags & PMV_QUICKSTOP16)  
                         goto EPZS16_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto EPZS16_Terminate_with_Refine;  
1519          }          }
1520    
1521  /***** predictor SET C: acceleration MV (new!), neighbours in prev. frame(new!) ****/          if(Data->qpel) {
1522                    pMB->pmvs[block].x = Data->currentQMV->x - Data->predMV.x;
1523          backupMV = prevMB->mvs[0];      // collocated MV                  pMB->pmvs[block].y = Data->currentQMV->y - Data->predMV.y;
1524          backupMV.x += (prevMB->mvs[0].x - oldMB->mvs[0].x);     // acceleration X                  pMB->qmvs[block] = *Data->currentQMV;
1525          backupMV.y += (prevMB->mvs[0].y - oldMB->mvs[0].y);     // acceleration Y          } else {
1526                    pMB->pmvs[block].x = Data->currentMV->x - Data->predMV.x;
1527          CHECK_MV16_CANDIDATE(backupMV.x, backupMV.y);                  pMB->pmvs[block].y = Data->currentMV->y - Data->predMV.y;
   
 // left neighbour  
         if (x != 0)  
                 CHECK_MV16_CANDIDATE((prevMB - 1)->mvs[0].x, (prevMB - 1)->mvs[0].y);  
   
 // top neighbour  
         if (y != 0)  
                 CHECK_MV16_CANDIDATE((prevMB - iWcount)->mvs[0].x,  
                                                          (prevMB - iWcount)->mvs[0].y);  
   
 // right neighbour, if allowed (this value is not written yet, so take it from   pMB->mvs  
   
         if ((uint32_t) x != iWcount - 1)  
                 CHECK_MV16_CANDIDATE((prevMB + 1)->mvs[0].x, (prevMB + 1)->mvs[0].y);  
   
 // bottom neighbour, dito  
         if ((uint32_t) y != iHcount - 1)  
                 CHECK_MV16_CANDIDATE((prevMB + iWcount)->mvs[0].x,  
                                                          (prevMB + iWcount)->mvs[0].y);  
   
 /* Terminate if MinSAD <= T_3 (here T_3 = T_2)  */  
         if (iMinSAD <= thresh2) {  
                 if (MotionFlags & PMV_QUICKSTOP16)  
                         goto EPZS16_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto EPZS16_Terminate_with_Refine;  
1528          }          }
1529    
1530  /************ (if Diamond Search)  **************/          pMB->mvs[block] = *Data->currentMV;
1531            pMB->sad8[block] = 4 * *Data->iMinSAD;
         backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */  
   
         if (MotionFlags & PMV_USESQUARES16)  
                 MainSearchPtr = Square16_MainSearch;  
         else  
          if (MotionFlags & PMV_ADVANCEDDIAMOND16)  
                 MainSearchPtr = AdvDiamond16_MainSearch;  
         else  
                 MainSearchPtr = Diamond16_MainSearch;  
   
 /* default: use best prediction as starting point for one call of PMVfast_MainSearch */  
   
         iSAD =  
                 (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV->x,  
                                                   currMV->y, iMinSAD, &newMV, center_x, center_y, min_dx, max_dx,  
                                                   min_dy, max_dy, iEdgedWidth, 2, iFcode, iQuant, 0);  
   
         if (iSAD < iMinSAD) {  
                 *currMV = newMV;  
                 iMinSAD = iSAD;  
1532          }          }
1533    
1534    /* motion estimation for B-frames */
1535    
1536          if (MotionFlags & PMV_EXTSEARCH16) {  static __inline VECTOR
1537  /* extended mode: search (up to) two more times: orignal prediction and (0,0) */  ChoosePred(const MACROBLOCK * const pMB, const uint32_t mode)
1538    {
1539                  if (!(MVequal(pmv[0], backupMV))) {  /* the stupidiest function ever */
1540                          iSAD =          return (mode == MODE_FORWARD ? pMB->mvs[0] : pMB->b_mvs[0]);
                                 (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,  
                                                                   pmv[0].x, pmv[0].y, iMinSAD, &newMV, center_x, center_y,  
                                                                   min_dx, max_dx, min_dy, max_dy, iEdgedWidth,  
                                                                   2, iFcode, iQuant, 0);  
                 }  
   
                 if (iSAD < iMinSAD) {  
                         *currMV = newMV;  
                         iMinSAD = iSAD;  
1541                  }                  }
1542    
1543                  if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {  static void __inline
1544                          iSAD =  PreparePredictionsBF(VECTOR * const pmv, const int x, const int y,
1545                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, 0, 0,                                                          const uint32_t iWcount,
1546                                                                    iMinSAD, &newMV, center_x, center_y, min_dx, max_dx, min_dy,                                                          const MACROBLOCK * const pMB,
1547                                                                    max_dy, iEdgedWidth, 2, iFcode, iQuant, 0);                                                          const uint32_t mode_curr)
1548    {
                         if (iSAD < iMinSAD) {  
                                 *currMV = newMV;  
                                 iMinSAD = iSAD;  
                         }  
                 }  
         }  
1549    
1550  /***************        Choose best MV found     **************/          // [0] is prediction
1551            pmv[0].x = EVEN(pmv[0].x); pmv[0].y = EVEN(pmv[0].y);
1552    
1553    EPZS16_Terminate_with_Refine:          pmv[1].x = pmv[1].y = 0; // [1] is zero
         if (MotionFlags & PMV_HALFPELREFINE16)  // perform final half-pel step  
                 iMinSAD =  
                         Halfpel16_Refine(pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV,  
                                                          iMinSAD, center_x, center_y, min_dx, max_dx, min_dy, max_dy,  
                                                          iFcode, iQuant, iEdgedWidth);  
1554    
1555    EPZS16_Terminate_without_Refine:          pmv[2] = ChoosePred(pMB, mode_curr);
1556            pmv[2].x = EVEN(pmv[2].x); pmv[2].y = EVEN(pmv[2].y);
1557    
1558          *oldMB = *prevMB;          if ((y != 0)&&(x != (int)(iWcount+1))) {                        // [3] top-right neighbour
1559                    pmv[3] = ChoosePred(pMB+1-iWcount, mode_curr);
1560                    pmv[3].x = EVEN(pmv[3].x); pmv[3].y = EVEN(pmv[3].y);
1561            } else pmv[3].x = pmv[3].y = 0;
1562    
1563          currPMV->x = currMV->x - center_x;          if (y != 0) {
1564          currPMV->y = currMV->y - center_y;                  pmv[4] = ChoosePred(pMB-iWcount, mode_curr);
1565          return iMinSAD;                  pmv[4].x = EVEN(pmv[4].x); pmv[4].y = EVEN(pmv[4].y);
1566            } else pmv[4].x = pmv[4].y = 0;
1567    
1568            if (x != 0) {
1569                    pmv[5] = ChoosePred(pMB-1, mode_curr);
1570                    pmv[5].x = EVEN(pmv[5].x); pmv[5].y = EVEN(pmv[5].y);
1571            } else pmv[5].x = pmv[5].y = 0;
1572    
1573            if (x != 0 && y != 0) {
1574                    pmv[6] = ChoosePred(pMB-1-iWcount, mode_curr);
1575                    pmv[6].x = EVEN(pmv[6].x); pmv[6].y = EVEN(pmv[6].y);
1576            } else pmv[6].x = pmv[6].y = 0;
1577  }  }
1578    
1579    
1580  int32_t  /* search backward or forward */
1581  EPZSSearch8(const uint8_t * const pRef,  static void
1582    SearchBF(       const IMAGE * const pRef,
1583                          const uint8_t * const pRefH,                          const uint8_t * const pRefH,
1584                          const uint8_t * const pRefV,                          const uint8_t * const pRefV,
1585                          const uint8_t * const pRefHV,                          const uint8_t * const pRefHV,
1586                          const IMAGE * const pCur,                          const IMAGE * const pCur,
1587                          const int x,                          const int x, const int y,
                         const int y,  
                         const int start_x,  
                         const int start_y,  
                         const int center_x,  
                         const int center_y,  
1588                          const uint32_t MotionFlags,                          const uint32_t MotionFlags,
                         const uint32_t iQuant,  
1589                          const uint32_t iFcode,                          const uint32_t iFcode,
1590                          const MBParam * const pParam,                          const MBParam * const pParam,
1591                          const MACROBLOCK * const pMBs,                          MACROBLOCK * const pMB,
1592                          const MACROBLOCK * const prevMBs,                          const VECTOR * const predMV,
1593                          VECTOR * const currMV,                          int32_t * const best_sad,
1594                          VECTOR * const currPMV)                          const int32_t mode_current,
1595                            SearchData * const Data)
1596  {  {
 /* Please not that EPZS might not be a good choice for 8x8-block motion search ! */  
   
         const uint32_t iWcount = pParam->mb_width;  
         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 * 8 + y * 8 * iEdgedWidth;  
1597    
1598          int32_t iDiamondSize = 1;          int i, iDirection = 255, mask;
1599            VECTOR pmv[7];
1600            MainSearchFunc *MainSearchPtr;
1601            *Data->iMinSAD = MV_MAX_ERROR;
1602            Data->iFcode = iFcode;
1603            Data->qpel_precision = 0;
1604            Data->temp[5] = Data->temp[6] = Data->temp[7] = 256*4096; // reset chroma-sad cache
1605    
1606          int32_t min_dx;          Data->RefP[0] = pRef->y + (x + Data->iEdgedWidth*y) * 16;
1607          int32_t max_dx;          Data->RefP[2] = pRefH + (x + Data->iEdgedWidth*y) * 16;
1608          int32_t min_dy;          Data->RefP[1] = pRefV + (x + Data->iEdgedWidth*y) * 16;
1609          int32_t max_dy;          Data->RefP[3] = pRefHV + (x + Data->iEdgedWidth*y) * 16;
1610            Data->RefP[4] = pRef->u + (x + y * (Data->iEdgedWidth/2)) * 8;
1611            Data->RefP[5] = pRef->v + (x + y * (Data->iEdgedWidth/2)) * 8;
1612    
1613          VECTOR newMV;          Data->predMV = *predMV;
         VECTOR backupMV;  
1614    
1615          VECTOR pmv[4];          get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
1616          int32_t psad[8];                                  pParam->width, pParam->height, iFcode - Data->qpel, 0, 0);
1617    
1618          const int32_t iSubBlock = ((y & 1) << 1) + (x & 1);          pmv[0] = Data->predMV;
1619            if (Data->qpel) { pmv[0].x /= 2; pmv[0].y /= 2; }
1620    
1621  //  const MACROBLOCK * const pMB = pMBs + (x>>1) + (y>>1) * iWcount;          PreparePredictionsBF(pmv, x, y, pParam->mb_width, pMB, mode_current);
         const MACROBLOCK *const prevMB = prevMBs + (x >> 1) + (y >> 1) * iWcount;  
1622    
1623          int32_t bPredEq;          Data->currentMV->x = Data->currentMV->y = 0;
1624          int32_t iMinSAD, iSAD = 9999;          CheckCandidate = CheckCandidate16no4v;
1625    
1626          MainSearch8FuncPtr MainSearchPtr;  // main loop. checking all predictions
1627            for (i = 0; i < 7; i++) {
1628  /* Get maximum range */                  if (!(mask = make_mask(pmv, i)) ) continue;
1629          get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 8, iWidth, iHeight,                  CheckCandidate16no4v(pmv[i].x, pmv[i].y, mask, &iDirection, Data);
                           iFcode);  
   
 /* we work with abs. MVs, not relative to prediction, so get_range is called relative to 0,0 */  
   
         if (!(MotionFlags & PMV_HALFPEL8)) {  
                 min_dx = EVEN(min_dx);  
                 max_dx = EVEN(max_dx);  
                 min_dy = EVEN(min_dy);  
                 max_dy = EVEN(max_dy);  
1630          }          }
         /* because we might use something like IF (dx>max_dx) THEN dx=max_dx; */  
         //bPredEq = get_pmvdata(pMBs, x >> 1, y >> 1, iWcount, iSubBlock, pmv[0].x, pmv[0].y, psad);  
         bPredEq = get_pmvdata2(pMBs, iWcount, 0, x >> 1, y >> 1, iSubBlock, pmv, psad);  
   
1631    
1632  /* Step 4: Calculate SAD around the Median prediction.          if (MotionFlags & PMV_USESQUARES16) MainSearchPtr = SquareSearch;
1633          MinSAD=SAD          else if (MotionFlags & PMV_ADVANCEDDIAMOND16) MainSearchPtr = AdvDiamondSearch;
1634          If Motion Vector equal to Previous frame motion vector                  else MainSearchPtr = DiamondSearch;
                 and MinSAD<PrevFrmSAD goto Step 10.  
         If SAD<=256 goto Step 10.  
 */  
1635    
1636  // Prepare for main loop          MainSearchPtr(Data->currentMV->x, Data->currentMV->y, Data, iDirection);
1637    
1638            SubpelRefine(Data);
1639    
1640          if (!(MotionFlags & PMV_HALFPEL8)) {          if (Data->qpel && *Data->iMinSAD < *best_sad + 300) {
1641                  currMV->x = EVEN(currMV->x);                  Data->currentQMV->x = 2*Data->currentMV->x;
1642                  currMV->y = EVEN(currMV->y);                  Data->currentQMV->y = 2*Data->currentMV->y;
1643                    Data->qpel_precision = 1;
1644                    get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
1645                                            pParam->width, pParam->height, iFcode, 1, 0);
1646                    SubpelRefine(Data);
1647          }          }
1648    
1649          if (currMV->x > max_dx)  // three bits are needed to code backward mode. four for forward
                 currMV->x = max_dx;  
         if (currMV->x < min_dx)  
                 currMV->x = min_dx;  
         if (currMV->y > max_dy)  
                 currMV->y = max_dy;  
         if (currMV->y < min_dy)  
                 currMV->y = min_dy;  
1650    
1651  /***************** This is predictor SET A: only median prediction ******************/          if (mode_current == MODE_FORWARD) *Data->iMinSAD += 4 * Data->lambda16;
1652            else *Data->iMinSAD += 3 * Data->lambda16;
1653    
1654            if (*Data->iMinSAD < *best_sad) {
1655                    *best_sad = *Data->iMinSAD;
1656                    pMB->mode = mode_current;
1657                    if (Data->qpel) {
1658                            pMB->pmvs[0].x = Data->currentQMV->x - predMV->x;
1659                            pMB->pmvs[0].y = Data->currentQMV->y - predMV->y;
1660                            if (mode_current == MODE_FORWARD)
1661                                    pMB->qmvs[0] = *Data->currentQMV;
1662                            else
1663                                    pMB->b_qmvs[0] = *Data->currentQMV;
1664                    } else {
1665                            pMB->pmvs[0].x = Data->currentMV->x - predMV->x;
1666                            pMB->pmvs[0].y = Data->currentMV->y - predMV->y;
1667                    }
1668                    if (mode_current == MODE_FORWARD) pMB->mvs[0] = *Data->currentMV;
1669                    else pMB->b_mvs[0] = *Data->currentMV;
1670            }
1671    
1672          iMinSAD =          if (mode_current == MODE_FORWARD) *(Data->currentMV+2) = *Data->currentMV;
1673                  sad8(cur,          else *(Data->currentMV+1) = *Data->currentMV; //we store currmv for interpolate search
1674                           get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 8, currMV,  }
1675                                                  iEdgedWidth), iEdgedWidth);  
1676          iMinSAD +=  static void
1677                  calc_delta_8(currMV->x - center_x, currMV->y - center_y,  SkipDecisionB(const IMAGE * const pCur,
1678                                           (uint8_t) iFcode, iQuant);                                  const IMAGE * const f_Ref,
1679                                    const IMAGE * const b_Ref,
1680                                    MACROBLOCK * const pMB,
1681                                    const uint32_t x, const uint32_t y,
1682                                    const SearchData * const Data)
1683    {
1684            int dx = 0, dy = 0, b_dx = 0, b_dy = 0;
1685            int32_t sum;
1686            const int div = 1 + Data->qpel;
1687            int k;
1688            const uint32_t stride = Data->iEdgedWidth/2;
1689    //this is not full chroma compensation, only it's fullpel approximation. should work though
1690    
1691            for (k = 0; k < 4; k++) {
1692                    dy += Data->directmvF[k].y / div;
1693                    dx += Data->directmvF[k].x / div;
1694                    b_dy += Data->directmvB[k].y / div;
1695                    b_dx += Data->directmvB[k].x / div;
1696            }
1697    
1698            dy = (dy >> 3) + roundtab_76[dy & 0xf];
1699            dx = (dx >> 3) + roundtab_76[dx & 0xf];
1700            b_dy = (b_dy >> 3) + roundtab_76[b_dy & 0xf];
1701            b_dx = (b_dx >> 3) + roundtab_76[b_dx & 0xf];
1702    
1703            sum = sad8bi(pCur->u + 8 * x + 8 * y * stride,
1704                                            f_Ref->u + (y*8 + dy/2) * stride + x*8 + dx/2,
1705                                            b_Ref->u + (y*8 + b_dy/2) * stride + x*8 + b_dx/2,
1706                                            stride);
1707    
1708            if (sum >= 2 * MAX_CHROMA_SAD_FOR_SKIP * pMB->quant) return; //no skip
1709    
1710            sum += sad8bi(pCur->v + 8*x + 8 * y * stride,
1711                                            f_Ref->v + (y*8 + dy/2) * stride + x*8 + dx/2,
1712                                            b_Ref->v + (y*8 + b_dy/2) * stride + x*8 + b_dx/2,
1713                                            stride);
1714    
1715  // thresh1 is fixed to 256          if (sum < 2 * MAX_CHROMA_SAD_FOR_SKIP * pMB->quant) {
1716          if (iMinSAD < 256 / 4) {                  pMB->mode = MODE_DIRECT_NONE_MV; //skipped
1717                  if (MotionFlags & PMV_QUICKSTOP8)                  for (k = 0; k < 4; k++) {
1718                          goto EPZS8_Terminate_without_Refine;                          pMB->qmvs[k] = pMB->mvs[k];
1719                  if (MotionFlags & PMV_EARLYSTOP8)                          pMB->b_qmvs[k] = pMB->b_mvs[k];
1720                          goto EPZS8_Terminate_with_Refine;                  }
1721            }
1722          }          }
1723    
1724  /************** This is predictor SET B: (0,0), prev.frame MV, neighbours **************/  static __inline uint32_t
1725    SearchDirect(const IMAGE * const f_Ref,
1726                                    const uint8_t * const f_RefH,
1727                                    const uint8_t * const f_RefV,
1728                                    const uint8_t * const f_RefHV,
1729                                    const IMAGE * const b_Ref,
1730                                    const uint8_t * const b_RefH,
1731                                    const uint8_t * const b_RefV,
1732                                    const uint8_t * const b_RefHV,
1733                                    const IMAGE * const pCur,
1734                                    const int x, const int y,
1735                                    const uint32_t MotionFlags,
1736                                    const int32_t TRB, const int32_t TRD,
1737                                    const MBParam * const pParam,
1738                                    MACROBLOCK * const pMB,
1739                                    const MACROBLOCK * const b_mb,
1740                                    int32_t * const best_sad,
1741                                    SearchData * const Data)
1742    
1743    {
1744            int32_t skip_sad;
1745            int k = (x + Data->iEdgedWidth*y) * 16;
1746            MainSearchFunc *MainSearchPtr;
1747    
1748            *Data->iMinSAD = 256*4096;
1749            Data->RefP[0] = f_Ref->y + k;
1750            Data->RefP[2] = f_RefH + k;
1751            Data->RefP[1] = f_RefV + k;
1752            Data->RefP[3] = f_RefHV + k;
1753            Data->b_RefP[0] = b_Ref->y + k;
1754            Data->b_RefP[2] = b_RefH + k;
1755            Data->b_RefP[1] = b_RefV + k;
1756            Data->b_RefP[3] = b_RefHV + k;
1757            Data->RefP[4] = f_Ref->u + (x + (Data->iEdgedWidth/2) * y) * 8;
1758            Data->RefP[5] = f_Ref->v + (x + (Data->iEdgedWidth/2) * y) * 8;
1759            Data->b_RefP[4] = b_Ref->u + (x + (Data->iEdgedWidth/2) * y) * 8;
1760            Data->b_RefP[5] = b_Ref->v + (x + (Data->iEdgedWidth/2) * y) * 8;
1761    
1762            k = Data->qpel ? 4 : 2;
1763            Data->max_dx = k * (pParam->width - x * 16);
1764            Data->max_dy = k * (pParam->height - y * 16);
1765            Data->min_dx = -k * (16 + x * 16);
1766            Data->min_dy = -k * (16 + y * 16);
1767    
1768            Data->referencemv = Data->qpel ? b_mb->qmvs : b_mb->mvs;
1769            Data->qpel_precision = 0;
1770    
1771  // MV=(0,0) is often a good choice          for (k = 0; k < 4; k++) {
1772          CHECK_MV8_ZERO;                  pMB->mvs[k].x = Data->directmvF[k].x = ((TRB * Data->referencemv[k].x) / TRD);
1773                    pMB->b_mvs[k].x = Data->directmvB[k].x = ((TRB - TRD) * Data->referencemv[k].x) / TRD;
1774                    pMB->mvs[k].y = Data->directmvF[k].y = ((TRB * Data->referencemv[k].y) / TRD);
1775                    pMB->b_mvs[k].y = Data->directmvB[k].y = ((TRB - TRD) * Data->referencemv[k].y) / TRD;
1776    
1777  // previous frame MV                  if ( (pMB->b_mvs[k].x > Data->max_dx) | (pMB->b_mvs[k].x < Data->min_dx)
1778          CHECK_MV8_CANDIDATE(prevMB->mvs[iSubBlock].x, prevMB->mvs[iSubBlock].y);                          | (pMB->b_mvs[k].y > Data->max_dy) | (pMB->b_mvs[k].y < Data->min_dy) ) {
1779    
1780  // left neighbour, if allowed                          *best_sad = 256*4096; // in that case, we won't use direct mode
1781          if (psad[1] != MV_MAX_ERROR) {                          pMB->mode = MODE_DIRECT; // just to make sure it doesn't say "MODE_DIRECT_NONE_MV"
1782                  if (!(MotionFlags & PMV_HALFPEL8)) {                          pMB->b_mvs[0].x = pMB->b_mvs[0].y = 0;
1783                          pmv[1].x = EVEN(pmv[1].x);                          return 256*4096;
                         pmv[1].y = EVEN(pmv[1].y);  
1784                  }                  }
1785                  CHECK_MV8_CANDIDATE(pmv[1].x, pmv[1].y);                  if (b_mb->mode != MODE_INTER4V) {
1786                            pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = pMB->mvs[0];
1787                            pMB->b_mvs[1] = pMB->b_mvs[2] = pMB->b_mvs[3] = pMB->b_mvs[0];
1788                            Data->directmvF[1] = Data->directmvF[2] = Data->directmvF[3] = Data->directmvF[0];
1789                            Data->directmvB[1] = Data->directmvB[2] = Data->directmvB[3] = Data->directmvB[0];
1790                            break;
1791          }          }
 // top neighbour, if allowed  
         if (psad[2] != MV_MAX_ERROR) {  
                 if (!(MotionFlags & PMV_HALFPEL8)) {  
                         pmv[2].x = EVEN(pmv[2].x);  
                         pmv[2].y = EVEN(pmv[2].y);  
1792                  }                  }
                 CHECK_MV8_CANDIDATE(pmv[2].x, pmv[2].y);  
1793    
1794  // top right neighbour, if allowed          CheckCandidate = b_mb->mode == MODE_INTER4V ? CheckCandidateDirect : CheckCandidateDirectno4v;
1795                  if (psad[3] != MV_MAX_ERROR) {  
1796                          if (!(MotionFlags & PMV_HALFPEL8)) {          CheckCandidate(0, 0, 255, &k, Data);
1797                                  pmv[3].x = EVEN(pmv[3].x);  
1798                                  pmv[3].y = EVEN(pmv[3].y);  // initial (fast) skip decision
1799                          }          if (*Data->iMinSAD < pMB->quant * INITIAL_SKIP_THRESH * (2 + Data->chroma?1:0)) {
1800                          CHECK_MV8_CANDIDATE(pmv[3].x, pmv[3].y);                  //possible skip
1801                    if (Data->chroma) {
1802                            pMB->mode = MODE_DIRECT_NONE_MV;
1803                            return *Data->iMinSAD; // skip.
1804                    } else {
1805                            SkipDecisionB(pCur, f_Ref, b_Ref, pMB, x, y, Data);
1806                            if (pMB->mode == MODE_DIRECT_NONE_MV) return *Data->iMinSAD; // skip.
1807                  }                  }
1808          }          }
1809    
1810  /*  // this bias is zero anyway, at the moment!          *Data->iMinSAD += Data->lambda16;
1811            skip_sad = *Data->iMinSAD;
1812    
1813          if ( (MVzero(*currMV)) && (!MVzero(pmv[0])) ) // && (iMinSAD <= iQuant * 96)  //      DIRECT MODE DELTA VECTOR SEARCH.
1814                  iMinSAD -= MV8_00_BIAS;  //      This has to be made more effective, but at the moment I'm happy it's running at all
1815    
1816  */          if (MotionFlags & PMV_USESQUARES16) MainSearchPtr = SquareSearch;
1817                    else if (MotionFlags & PMV_ADVANCEDDIAMOND16) MainSearchPtr = AdvDiamondSearch;
1818                            else MainSearchPtr = DiamondSearch;
1819    
1820  /* Terminate if MinSAD <= T_2          MainSearchPtr(0, 0, Data, 255);
    Terminate if MV[t] == MV[t-1] and MinSAD[t] <= MinSAD[t-1]  
 */  
1821    
1822          if (iMinSAD < 512 / 4) {        /* T_2 == 512/4 hardcoded */          SubpelRefine(Data);
1823                  if (MotionFlags & PMV_QUICKSTOP8)  
1824                          goto EPZS8_Terminate_without_Refine;          *best_sad = *Data->iMinSAD;
                 if (MotionFlags & PMV_EARLYSTOP8)  
                         goto EPZS8_Terminate_with_Refine;  
         }  
1825    
1826  /************ (Diamond Search)  **************/          if (Data->qpel || b_mb->mode == MODE_INTER4V) pMB->mode = MODE_DIRECT;
1827            else pMB->mode = MODE_DIRECT_NO4V; //for faster compensation
1828    
1829          backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */          pMB->pmvs[3] = *Data->currentMV;
1830    
1831          if (!(MotionFlags & PMV_HALFPELDIAMOND8))          for (k = 0; k < 4; k++) {
1832                  iDiamondSize *= 2;                  pMB->mvs[k].x = Data->directmvF[k].x + Data->currentMV->x;
1833                    pMB->b_mvs[k].x = (     (Data->currentMV->x == 0)
1834                                                            ? Data->directmvB[k].x
1835                                                            :pMB->mvs[k].x - Data->referencemv[k].x);
1836                    pMB->mvs[k].y = (Data->directmvF[k].y + Data->currentMV->y);
1837                    pMB->b_mvs[k].y = ((Data->currentMV->y == 0)
1838                                                            ? Data->directmvB[k].y
1839                                                            : pMB->mvs[k].y - Data->referencemv[k].y);
1840                    if (Data->qpel) {
1841                            pMB->qmvs[k].x = pMB->mvs[k].x; pMB->mvs[k].x /= 2;
1842                            pMB->b_qmvs[k].x = pMB->b_mvs[k].x; pMB->b_mvs[k].x /= 2;
1843                            pMB->qmvs[k].y = pMB->mvs[k].y; pMB->mvs[k].y /= 2;
1844                            pMB->b_qmvs[k].y = pMB->b_mvs[k].y; pMB->b_mvs[k].y /= 2;
1845                    }
1846    
1847                    if (b_mb->mode != MODE_INTER4V) {
1848                            pMB->mvs[3] = pMB->mvs[2] = pMB->mvs[1] = pMB->mvs[0];
1849                            pMB->b_mvs[3] = pMB->b_mvs[2] = pMB->b_mvs[1] = pMB->b_mvs[0];
1850                            pMB->qmvs[3] = pMB->qmvs[2] = pMB->qmvs[1] = pMB->qmvs[0];
1851                            pMB->b_qmvs[3] = pMB->b_qmvs[2] = pMB->b_qmvs[1] = pMB->b_qmvs[0];
1852                            break;
1853                    }
1854            }
1855            return skip_sad;
1856    }
1857    
1858    static void
1859    SearchInterpolate(const IMAGE * const f_Ref,
1860                                    const uint8_t * const f_RefH,
1861                                    const uint8_t * const f_RefV,
1862                                    const uint8_t * const f_RefHV,
1863                                    const IMAGE * const b_Ref,
1864                                    const uint8_t * const b_RefH,
1865                                    const uint8_t * const b_RefV,
1866                                    const uint8_t * const b_RefHV,
1867                                    const IMAGE * const pCur,
1868                                    const int x, const int y,
1869                                    const uint32_t fcode,
1870                                    const uint32_t bcode,
1871                                    const uint32_t MotionFlags,
1872                                    const MBParam * const pParam,
1873                                    const VECTOR * const f_predMV,
1874                                    const VECTOR * const b_predMV,
1875                                    MACROBLOCK * const pMB,
1876                                    int32_t * const best_sad,
1877                                    SearchData * const fData)
1878    
1879  /* default: use best prediction as starting point for one call of EPZS_MainSearch */  {
1880    
1881  // there is no EPZS^2 for inter4v at the moment          int iDirection, i, j;
1882            SearchData bData;
1883    
1884            fData->qpel_precision = 0;
1885            memcpy(&bData, fData, sizeof(SearchData)); //quick copy of common data
1886            *fData->iMinSAD = 4096*256;
1887            bData.currentMV++; bData.currentQMV++;
1888            fData->iFcode = bData.bFcode = fcode; fData->bFcode = bData.iFcode = bcode;
1889    
1890            i = (x + y * fData->iEdgedWidth) * 16;
1891    
1892            bData.b_RefP[0] = fData->RefP[0] = f_Ref->y + i;
1893            bData.b_RefP[2] = fData->RefP[2] = f_RefH + i;
1894            bData.b_RefP[1] = fData->RefP[1] = f_RefV + i;
1895            bData.b_RefP[3] = fData->RefP[3] = f_RefHV + i;
1896            bData.RefP[0] = fData->b_RefP[0] = b_Ref->y + i;
1897            bData.RefP[2] = fData->b_RefP[2] = b_RefH + i;
1898            bData.RefP[1] = fData->b_RefP[1] = b_RefV + i;
1899            bData.RefP[3] = fData->b_RefP[3] = b_RefHV + i;
1900            bData.b_RefP[4] = fData->RefP[4] = f_Ref->u + (x + (fData->iEdgedWidth/2) * y) * 8;
1901            bData.b_RefP[5] = fData->RefP[5] = f_Ref->v + (x + (fData->iEdgedWidth/2) * y) * 8;
1902            bData.RefP[4] = fData->b_RefP[4] = b_Ref->u + (x + (fData->iEdgedWidth/2) * y) * 8;
1903            bData.RefP[5] = fData->b_RefP[5] = b_Ref->v + (x + (fData->iEdgedWidth/2) * y) * 8;
1904    
1905            bData.bpredMV = fData->predMV = *f_predMV;
1906            fData->bpredMV = bData.predMV = *b_predMV;
1907            fData->currentMV[0] = fData->currentMV[2];
1908    
1909            get_range(&fData->min_dx, &fData->max_dx, &fData->min_dy, &fData->max_dy, x, y, 16, pParam->width, pParam->height, fcode - fData->qpel, 0, 0);
1910            get_range(&bData.min_dx, &bData.max_dx, &bData.min_dy, &bData.max_dy, x, y, 16, pParam->width, pParam->height, bcode - fData->qpel, 0, 0);
1911    
1912            if (fData->currentMV[0].x > fData->max_dx) fData->currentMV[0].x = fData->max_dx;
1913            if (fData->currentMV[0].x < fData->min_dx) fData->currentMV[0].x = fData->min_dx;
1914            if (fData->currentMV[0].y > fData->max_dy) fData->currentMV[0].y = fData->max_dy;
1915            if (fData->currentMV[0].y < fData->min_dy) fData->currentMV[0].y = fData->min_dy;
1916    
1917            if (fData->currentMV[1].x > bData.max_dx) fData->currentMV[1].x = bData.max_dx;
1918            if (fData->currentMV[1].x < bData.min_dx) fData->currentMV[1].x = bData.min_dx;
1919            if (fData->currentMV[1].y > bData.max_dy) fData->currentMV[1].y = bData.max_dy;
1920            if (fData->currentMV[1].y < bData.min_dy) fData->currentMV[1].y = bData.min_dy;
1921    
1922    if (MotionFlags & PMV_USESQUARES8)          CheckCandidateInt(fData->currentMV[0].x, fData->currentMV[0].y, 255, &iDirection, fData);
       MainSearchPtr = Square8_MainSearch;  
   else  
1923    
1924          if (MotionFlags & PMV_ADVANCEDDIAMOND8)  //diamond
1925                  MainSearchPtr = AdvDiamond8_MainSearch;          do {
1926          else                  iDirection = 255;
1927                  MainSearchPtr = Diamond8_MainSearch;                  // forward MV moves
1928                    i = fData->currentMV[0].x; j = fData->currentMV[0].y;
1929    
1930                    CheckCandidateInt(i + 1, j, 0, &iDirection, fData);
1931                    CheckCandidateInt(i, j + 1, 0, &iDirection, fData);
1932                    CheckCandidateInt(i - 1, j, 0, &iDirection, fData);
1933                    CheckCandidateInt(i, j - 1, 0, &iDirection, fData);
1934    
1935                    // backward MV moves
1936                    i = fData->currentMV[1].x; j = fData->currentMV[1].y;
1937                    fData->currentMV[2] = fData->currentMV[0];
1938                    CheckCandidateInt(i + 1, j, 0, &iDirection, &bData);
1939                    CheckCandidateInt(i, j + 1, 0, &iDirection, &bData);
1940                    CheckCandidateInt(i - 1, j, 0, &iDirection, &bData);
1941                    CheckCandidateInt(i, j - 1, 0, &iDirection, &bData);
1942    
1943            } while (!(iDirection));
1944    
1945    //qpel refinement
1946            if (fData->qpel) {
1947                    if (*fData->iMinSAD > *best_sad + 500) return;
1948                    CheckCandidate = CheckCandidateInt;
1949                    fData->qpel_precision = bData.qpel_precision = 1;
1950                    get_range(&fData->min_dx, &fData->max_dx, &fData->min_dy, &fData->max_dy, x, y, 16, pParam->width, pParam->height, fcode, 1, 0);
1951                    get_range(&bData.min_dx, &bData.max_dx, &bData.min_dy, &bData.max_dy, x, y, 16, pParam->width, pParam->height, bcode, 1, 0);
1952                    fData->currentQMV[2].x = fData->currentQMV[0].x = 2 * fData->currentMV[0].x;
1953                    fData->currentQMV[2].y = fData->currentQMV[0].y = 2 * fData->currentMV[0].y;
1954                    fData->currentQMV[1].x = 2 * fData->currentMV[1].x;
1955                    fData->currentQMV[1].y = 2 * fData->currentMV[1].y;
1956                    SubpelRefine(fData);
1957                    if (*fData->iMinSAD > *best_sad + 300) return;
1958                    fData->currentQMV[2] = fData->currentQMV[0];
1959                    SubpelRefine(&bData);
1960            }
1961    
1962            *fData->iMinSAD += (2+3) * fData->lambda16; // two bits are needed to code interpolate mode.
1963    
1964            if (*fData->iMinSAD < *best_sad) {
1965                    *best_sad = *fData->iMinSAD;
1966                    pMB->mvs[0] = fData->currentMV[0];
1967                    pMB->b_mvs[0] = fData->currentMV[1];
1968                    pMB->mode = MODE_INTERPOLATE;
1969                    if (fData->qpel) {
1970                            pMB->qmvs[0] = fData->currentQMV[0];
1971                            pMB->b_qmvs[0] = fData->currentQMV[1];
1972                            pMB->pmvs[1].x = pMB->qmvs[0].x - f_predMV->x;
1973                            pMB->pmvs[1].y = pMB->qmvs[0].y - f_predMV->y;
1974                            pMB->pmvs[0].x = pMB->b_qmvs[0].x - b_predMV->x;
1975                            pMB->pmvs[0].y = pMB->b_qmvs[0].y - b_predMV->y;
1976                    } else {
1977                            pMB->pmvs[1].x = pMB->mvs[0].x - f_predMV->x;
1978                            pMB->pmvs[1].y = pMB->mvs[0].y - f_predMV->y;
1979                            pMB->pmvs[0].x = pMB->b_mvs[0].x - b_predMV->x;
1980                            pMB->pmvs[0].y = pMB->b_mvs[0].y - b_predMV->y;
1981                    }
1982            }
1983    }
1984    
1985          iSAD =  void
1986                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV->x,  MotionEstimationBVOP(MBParam * const pParam,
1987                                                    currMV->y, iMinSAD, &newMV, center_x, center_y, min_dx, max_dx,                                          FRAMEINFO * const frame,
1988                                                    min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode,                                          const int32_t time_bp,
1989                                                    iQuant, 0);                                          const int32_t time_pp,
1990                                            // forward (past) reference
1991                                            const MACROBLOCK * const f_mbs,
1992                                            const IMAGE * const f_ref,
1993                                            const IMAGE * const f_refH,
1994                                            const IMAGE * const f_refV,
1995                                            const IMAGE * const f_refHV,
1996                                            // backward (future) reference
1997                                            const FRAMEINFO * const b_reference,
1998                                            const IMAGE * const b_ref,
1999                                            const IMAGE * const b_refH,
2000                                            const IMAGE * const b_refV,
2001                                            const IMAGE * const b_refHV)
2002    {
2003            uint32_t i, j;
2004            int32_t best_sad;
2005            uint32_t skip_sad;
2006            int f_count = 0, b_count = 0, i_count = 0, d_count = 0, n_count = 0;
2007            const MACROBLOCK * const b_mbs = b_reference->mbs;
2008    
2009            VECTOR f_predMV, b_predMV;      /* there is no prediction for direct mode*/
2010    
2011          if (iSAD < iMinSAD) {          const int32_t TRB = time_pp - time_bp;
2012                  *currMV = newMV;          const int32_t TRD = time_pp;
                 iMinSAD = iSAD;  
         }  
2013    
2014          if (MotionFlags & PMV_EXTSEARCH8) {  // some pre-inintialized data for the rest of the search
 /* extended mode: search (up to) two more times: orignal prediction and (0,0) */  
2015    
2016                  if (!(MVequal(pmv[0], backupMV))) {          SearchData Data;
2017                          iSAD =          int32_t iMinSAD;
2018                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,          VECTOR currentMV[3];
2019                                                                    pmv[0].x, pmv[0].y, iMinSAD, &newMV, center_x, center_y,          VECTOR currentQMV[3];
2020                                                                    min_dx, max_dx, min_dy, max_dy, iEdgedWidth,          int32_t temp[8];
2021                                                                    iDiamondSize, iFcode, iQuant, 0);          memset(&Data, 0, sizeof(SearchData));
2022            Data.iEdgedWidth = pParam->edged_width;
2023            Data.currentMV = currentMV; Data.currentQMV = currentQMV;
2024            Data.iMinSAD = &iMinSAD;
2025            Data.lambda16 = lambda_vec16[frame->quant];
2026            Data.qpel = pParam->m_quarterpel;
2027            Data.rounding = 0;
2028            Data.chroma = frame->motion_flags & PMV_CHROMA8;
2029            Data.temp = temp;
2030    
2031                          if (iSAD < iMinSAD) {          Data.RefQ = f_refV->u; // a good place, also used in MC (for similar purpose)
2032                                  *currMV = newMV;          // note: i==horizontal, j==vertical
2033                                  iMinSAD = iSAD;          for (j = 0; j < pParam->mb_height; j++) {
                         }  
                 }  
2034    
2035                  if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {                  f_predMV = b_predMV = zeroMV;   /* prediction is reset at left boundary */
                         iSAD =  
                                 (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, 0, 0,  
                                                                   iMinSAD, &newMV, center_x, center_y, min_dx, max_dx, min_dy,  
                                                                   max_dy, iEdgedWidth, iDiamondSize, iFcode,  
                                                                   iQuant, 0);  
2036    
2037                          if (iSAD < iMinSAD) {                  for (i = 0; i < pParam->mb_width; i++) {
2038                                  *currMV = newMV;                          MACROBLOCK * const pMB = frame->mbs + i + j * pParam->mb_width;
2039                                  iMinSAD = iSAD;                          const MACROBLOCK * const b_mb = b_mbs + i + j * pParam->mb_width;
2040                          }  
2041                  }  /* special case, if collocated block is SKIPed in P-VOP: encoding is forward (0,0), cpb=0 without further ado */
2042                            if (b_reference->coding_type != S_VOP)
2043                                    if (b_mb->mode == MODE_NOT_CODED) {
2044                                            pMB->mode = MODE_NOT_CODED;
2045                                            continue;
2046          }          }
2047    
2048  /***************        Choose best MV found     **************/                          Data.Cur = frame->image.y + (j * Data.iEdgedWidth + i) * 16;
2049                            Data.CurU = frame->image.u + (j * Data.iEdgedWidth/2 + i) * 8;
2050    EPZS8_Terminate_with_Refine:                          Data.CurV = frame->image.v + (j * Data.iEdgedWidth/2 + i) * 8;
2051          if (MotionFlags & PMV_HALFPELREFINE8)   // perform final half-pel step                          pMB->quant = frame->quant;
2052                  iMinSAD =  
2053                          Halfpel8_Refine(pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV,  /* direct search comes first, because it (1) checks for SKIP-mode
2054                                                          iMinSAD, center_x, center_y, min_dx, max_dx, min_dy, max_dy,          and (2) sets very good predictions for forward and backward search */
2055                                                          iFcode, iQuant, iEdgedWidth);                          skip_sad = SearchDirect(f_ref, f_refH->y, f_refV->y, f_refHV->y,
2056                                                                            b_ref, b_refH->y, b_refV->y, b_refHV->y,
2057                                                                            &frame->image,
2058                                                                            i, j,
2059                                                                            frame->motion_flags,
2060                                                                            TRB, TRD,
2061                                                                            pParam,
2062                                                                            pMB, b_mb,
2063                                                                            &best_sad,
2064                                                                            &Data);
2065    
2066    EPZS8_Terminate_without_Refine:                          if (pMB->mode == MODE_DIRECT_NONE_MV) { n_count++; continue; }
2067    
2068          currPMV->x = currMV->x - center_x;                          // forward search
2069          currPMV->y = currMV->y - center_y;                          SearchBF(f_ref, f_refH->y, f_refV->y, f_refHV->y,
2070          return iMinSAD;                                                  &frame->image, i, j,
2071  }                                                  frame->motion_flags,
2072                                                    frame->fcode, pParam,
2073                                                    pMB, &f_predMV, &best_sad,
2074                                                    MODE_FORWARD, &Data);
2075    
2076                            // backward search
2077                            SearchBF(b_ref, b_refH->y, b_refV->y, b_refHV->y,
2078                                                    &frame->image, i, j,
2079                                                    frame->motion_flags,
2080                                                    frame->bcode, pParam,
2081                                                    pMB, &b_predMV, &best_sad,
2082                                                    MODE_BACKWARD, &Data);
2083    
2084                            // interpolate search comes last, because it uses data from forward and backward as prediction
2085                            SearchInterpolate(f_ref, f_refH->y, f_refV->y, f_refHV->y,
2086                                                    b_ref, b_refH->y, b_refV->y, b_refHV->y,
2087                                                    &frame->image,
2088                                                    i, j,
2089                                                    frame->fcode, frame->bcode,
2090                                                    frame->motion_flags,
2091                                                    pParam,
2092                                                    &f_predMV, &b_predMV,
2093                                                    pMB, &best_sad,
2094                                                    &Data);
2095    
2096    // final skip decision
2097                            if ( (skip_sad < frame->quant * MAX_SAD00_FOR_SKIP * 2)
2098                                            && ((100*best_sad)/(skip_sad+1) > FINAL_SKIP_THRESH) )
2099                                    SkipDecisionB(&frame->image, f_ref, b_ref, pMB, i, j, &Data);
2100    
2101                            switch (pMB->mode) {
2102                                    case MODE_FORWARD:
2103                                            f_count++;
2104                                            f_predMV = Data.qpel ? pMB->qmvs[0] : pMB->mvs[0];
2105                                            break;
2106                                    case MODE_BACKWARD:
2107                                            b_count++;
2108                                            b_predMV = Data.qpel ? pMB->b_qmvs[0] : pMB->b_mvs[0];
2109                                            break;
2110                                    case MODE_INTERPOLATE:
2111                                            i_count++;
2112                                            f_predMV = Data.qpel ? pMB->qmvs[0] : pMB->mvs[0];
2113                                            b_predMV = Data.qpel ? pMB->b_qmvs[0] : pMB->b_mvs[0];
2114                                            break;
2115                                    case MODE_DIRECT:
2116                                    case MODE_DIRECT_NO4V:
2117                                            d_count++;
2118                                    default:
2119                                            break;
2120                            }
2121                    }
2122            }
2123    }
2124    
2125  int32_t  static __inline void
2126  PMVfastIntSearch16(const uint8_t * const pRef,  MEanalyzeMB (   const uint8_t * const pRef,
2127                                  const uint8_t * const pRefH,                                  const uint8_t * const pCur,
                                 const uint8_t * const pRefV,  
                                 const uint8_t * const pRefHV,  
                                 const IMAGE * const pCur,  
2128                                  const int x,                                  const int x,
2129                                  const int y,                                  const int y,
                                 const int start_x,              /* start should be most likely vector */  
                                 const int start_y,  
                                 const int center_x,             /* center is from where length of MVs is measured */  
                                 const int center_y,  
                                 const uint32_t MotionFlags,  
                                 const uint32_t iQuant,  
                                 const uint32_t iFcode,  
2130                                  const MBParam * const pParam,                                  const MBParam * const pParam,
2131                                  const MACROBLOCK * const pMBs,                                  MACROBLOCK * const pMBs,
2132                                  const MACROBLOCK * const prevMBs,                                  SearchData * const Data)
                                 VECTOR * const currMV,  
                                 VECTOR * const currPMV)  
2133  {  {
         const uint32_t iWcount = pParam->mb_width;  
         const int32_t iWidth = pParam->width;  
         const int32_t iHeight = pParam->height;  
         const int32_t iEdgedWidth = pParam->edged_width;  
2134    
2135          const uint8_t *cur = pCur->y + x * 16 + y * 16 * iEdgedWidth;          int i, mask;
2136          const VECTOR zeroMV = { 0, 0 };          VECTOR pmv[3];
2137            MACROBLOCK * const pMB = &pMBs[x + y * pParam->mb_width];
2138    
2139          int32_t iDiamondSize;          for (i = 0; i < 5; i++) Data->iMinSAD[i] = MV_MAX_ERROR;
2140    
2141          int32_t min_dx;          //median is only used as prediction. it doesn't have to be real
2142          int32_t max_dx;          if (x == 1 && y == 1) Data->predMV.x = Data->predMV.y = 0;
2143          int32_t min_dy;          else
2144          int32_t max_dy;                  if (x == 1) //left macroblock does not have any vector now
2145                            Data->predMV = (pMB - pParam->mb_width)->mvs[0]; // top instead of median
2146          int32_t iFound;                  else if (y == 1) // top macroblock doesn't have it's vector
2147                            Data->predMV = (pMB - 1)->mvs[0]; // left instead of median
2148                            else Data->predMV = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 0); //else median
2149    
2150          VECTOR newMV;          get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
2151          VECTOR backupMV;                                  pParam->width, pParam->height, Data->iFcode - pParam->m_quarterpel, 0, 0);
2152    
2153          VECTOR pmv[4];          Data->Cur = pCur + (x + y * pParam->edged_width) * 16;
2154          int32_t psad[4];          Data->RefP[0] = pRef + (x + y * pParam->edged_width) * 16;
2155    
2156          MainSearch16FuncPtr MainSearchPtr;          pmv[1].x = EVEN(pMB->mvs[0].x);
2157            pmv[1].y = EVEN(pMB->mvs[0].y);
2158            pmv[2].x = EVEN(Data->predMV.x);
2159            pmv[2].y = EVEN(Data->predMV.y);
2160            pmv[0].x = pmv[0].y = 0;
2161    
2162          const MACROBLOCK *const prevMB = prevMBs + x + y * iWcount;          CheckCandidate32I(0, 0, 255, &i, Data);
         MACROBLOCK *const pMB = pMBs + x + y * iWcount;  
2163    
2164          int32_t threshA, threshB;          if (*Data->iMinSAD > 4 * MAX_SAD00_FOR_SKIP) {
         int32_t bPredEq;  
         int32_t iMinSAD, iSAD;  
2165    
2166                    if (!(mask = make_mask(pmv, 1)))
2167                            CheckCandidate32I(pmv[1].x, pmv[1].y, mask, &i, Data);
2168                    if (!(mask = make_mask(pmv, 2)))
2169                            CheckCandidate32I(pmv[2].x, pmv[2].y, mask, &i, Data);
2170    
2171  /* Get maximum range */                  if (*Data->iMinSAD > 4 * MAX_SAD00_FOR_SKIP) // diamond only if needed
2172          get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 16, iWidth, iHeight,                          DiamondSearch(Data->currentMV->x, Data->currentMV->y, Data, i);
2173                            iFcode);          }
2174    
2175  /* we work with abs. MVs, not relative to prediction, so get_range is called relative to 0,0 */          for (i = 0; i < 4; i++) {
2176                    MACROBLOCK * MB = &pMBs[x + (i&1) + (y+(i>>1)) * pParam->mb_width];
2177                    MB->mvs[0] = MB->mvs[1] = MB->mvs[2] = MB->mvs[3] = Data->currentMV[i];
2178                    MB->mode = MODE_INTER;
2179                    MB->sad16 = Data->iMinSAD[i+1];
2180            }
2181    }
2182    
2183          if ((x == 0) && (y == 0)) {  #define INTRA_THRESH    1800
2184                  threshA = 512;  #define INTER_THRESH    1200
                 threshB = 1024;  
2185    
2186                  bPredEq = 0;  int
2187                  psad[0] = psad[1] = psad[2] = psad[3] = 0;  MEanalysis(     const IMAGE * const pRef,
2188                  *currMV = pmv[0] = pmv[1] = pmv[2] = pmv[3] = zeroMV;                          const FRAMEINFO * const Current,
2189                            const MBParam * const pParam,
2190                            const int maxIntra, //maximum number if non-I frames
2191                            const int intraCount, //number of non-I frames after last I frame; 0 if we force P/B frame
2192                            const int bCount,  // number of B frames in a row
2193                            const int b_thresh)
2194    {
2195            uint32_t x, y, intra = 0;
2196            int sSAD = 0;
2197            MACROBLOCK * const pMBs = Current->mbs;
2198            const IMAGE * const pCurrent = &Current->image;
2199            int IntraThresh = INTRA_THRESH, InterThresh = INTER_THRESH + 10*b_thresh;
2200            int s = 0, blocks = 0;
2201    
2202            int32_t iMinSAD[5], temp[5];
2203            VECTOR currentMV[5];
2204            SearchData Data;
2205            Data.iEdgedWidth = pParam->edged_width;
2206            Data.currentMV = currentMV;
2207            Data.iMinSAD = iMinSAD;
2208            Data.iFcode = Current->fcode;
2209            Data.temp = temp;
2210            CheckCandidate = CheckCandidate32I;
2211    
2212          } else {          if (intraCount != 0 && intraCount < 10) // we're right after an I frame
2213                    IntraThresh += 15 * (intraCount - 10) * (intraCount - 10);
2214            else
2215                    if ( 5*(maxIntra - intraCount) < maxIntra) // we're close to maximum. 2 sec when max is 10 sec
2216                            IntraThresh -= (IntraThresh * (maxIntra - 8*(maxIntra - intraCount)))/maxIntra;
2217    
2218                  bPredEq = get_ipmvdata(pMBs, iWcount, 0, x, y, 0, pmv, psad);          InterThresh -= (350 - 8*b_thresh) * bCount;
2219            if (InterThresh < 300 + 5*b_thresh) InterThresh = 300 + 5*b_thresh;
2220    
2221                  threshA = psad[0];          if (sadInit) (*sadInit) ();
                 threshB = threshA + 256;  
                 if (threshA < 512)  
                         threshA = 512;  
                 if (threshA > 1024)  
                         threshA = 1024;  
                 if (threshB > 1792)  
                         threshB = 1792;  
2222    
2223                  *currMV = pmv[0];                       /* current best := prediction */          for (y = 1; y < pParam->mb_height-1; y += 2) {
2224                    for (x = 1; x < pParam->mb_width-1; x += 2) {
2225                            int i;
2226                            blocks += 4;
2227    
2228                            if (bCount == 0) pMBs[x + y * pParam->mb_width].mvs[0] = zeroMV;
2229                            else { //extrapolation of the vector found for last frame
2230                                    pMBs[x + y * pParam->mb_width].mvs[0].x =
2231                                            (pMBs[x + y * pParam->mb_width].mvs[0].x * (bCount+1) ) / bCount;
2232                                    pMBs[x + y * pParam->mb_width].mvs[0].y =
2233                                            (pMBs[x + y * pParam->mb_width].mvs[0].y * (bCount+1) ) / bCount;
2234                            }
2235    
2236                            MEanalyzeMB(pRef->y, pCurrent->y, x, y, pParam, pMBs, &Data);
2237    
2238                            for (i = 0; i < 4; i++) {
2239                                    int dev;
2240                                    MACROBLOCK *pMB = &pMBs[x+(i&1) + (y+(i>>1)) * pParam->mb_width];
2241                                    if (pMB->sad16 > IntraThresh) {
2242                                            dev = dev16(pCurrent->y + (x + (i&1) + (y + (i>>1)) * pParam->edged_width) * 16,
2243                                                                            pParam->edged_width);
2244                                            if (dev + IntraThresh < pMB->sad16) {
2245                                                    pMB->mode = MODE_INTRA;
2246                                                    if (++intra > ((pParam->mb_height-2)*(pParam->mb_width-2))/2) return I_VOP;
2247          }          }
   
         iFound = 0;  
   
 /* Step 4: Calculate SAD around the Median prediction.  
    MinSAD=SAD  
    If Motion Vector equal to Previous frame motion vector  
    and MinSAD<PrevFrmSAD goto Step 10.  
    If SAD<=256 goto Step 10.  
 */  
   
         if (currMV->x > max_dx) {  
                 currMV->x = EVEN(max_dx);  
2248          }          }
2249          if (currMV->x < min_dx) {                                  if (pMB->mvs[0].x == 0 && pMB->mvs[0].y == 0) s++;
2250                  currMV->x = EVEN(min_dx);  
2251                                    sSAD += pMB->sad16;
2252          }          }
         if (currMV->y > max_dy) {  
                 currMV->y = EVEN(max_dy);  
2253          }          }
         if (currMV->y < min_dy) {  
                 currMV->y = EVEN(min_dy);  
2254          }          }
2255    
2256          iMinSAD =          sSAD /= blocks;
2257                  sad16(cur,          s = (10*s) / blocks;
                           get_iref_mv(pRef, x, y, 16, currMV,  
                                                  iEdgedWidth), iEdgedWidth, MV_MAX_ERROR);  
         iMinSAD +=  
                 calc_delta_16(currMV->x - center_x, currMV->y - center_y,  
                                           (uint8_t) iFcode, iQuant);  
2258    
2259          if ((iMinSAD < 256) ||          if (s > 4) sSAD += (s - 2) * (60 - 2*b_thresh); //static block - looks bad when in bframe...
                 ((MVequal(*currMV, prevMB->i_mvs[0])) &&  
                  ((int32_t) iMinSAD < prevMB->i_sad16))) {  
                 if (iMinSAD < 2 * iQuant)       // high chances for SKIP-mode  
                 {  
                         if (!MVzero(*currMV)) {  
                                 iMinSAD += MV16_00_BIAS;  
                                 CHECK_MV16_ZERO;        // (0,0) saves space for letterboxed pictures  
                                 iMinSAD -= MV16_00_BIAS;  
                         }  
                 }  
2260    
2261                  if (MotionFlags & PMV_EARLYSTOP16)          if (sSAD > InterThresh ) return P_VOP;
2262                          goto PMVfastInt16_Terminate_with_Refine;          emms();
2263            return B_VOP;
2264          }          }
2265    
2266    
2267  /* Step 2 (lazy eval): Calculate Distance= |MedianMVX| + |MedianMVY| where MedianMV is the motion  static WARPPOINTS
2268     vector of the median.  GlobalMotionEst(const MACROBLOCK * const pMBs,
2269     If PredEq=1 and MVpredicted = Previous Frame MV, set Found=2                                  const MBParam * const pParam,
2270  */                                  const FRAMEINFO * const current,
2271                                    const FRAMEINFO * const reference,
2272          if ((bPredEq) && (MVequal(pmv[0], prevMB->i_mvs[0])))                                  const IMAGE * const pRefH,
2273                  iFound = 2;                                  const IMAGE * const pRefV,
2274                                    const IMAGE * const pRefHV      )
2275    {
2276    
2277  /* Step 3 (lazy eval): If Distance>0 or thresb<1536 or PredEq=1 Select small Diamond Search.          const int deltax=8;             // upper bound for difference between a MV and it's neighbour MVs
2278     Otherwise select large Diamond Search.          const int deltay=8;
2279  */          const int grad=512;             // lower bound for deviation in MB
2280    
2281          if ((!MVzero(pmv[0])) || (threshB < 1536) || (bPredEq))          WARPPOINTS gmc;
                 iDiamondSize = 2;               // halfpel units!  
         else  
                 iDiamondSize = 4;               // halfpel units!  
2282    
2283  /*          uint32_t mx, my;
    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.  
 */  
2284    
2285  // (0,0) is often a good choice          int MBh = pParam->mb_height;
2286            int MBw = pParam->mb_width;
2287    
2288          if (!MVzero(pmv[0]))          int *MBmask= calloc(MBh*MBw,sizeof(int));
2289                  CHECK_MV16_ZERO;          double DtimesF[4] = { 0.,0., 0., 0. };
2290            double sol[4] = { 0., 0., 0., 0. };
2291            double a,b,c,n,denom;
2292            double meanx,meany;
2293            int num,oldnum;
2294    
2295  // previous frame MV is always possible          if (!MBmask) {  fprintf(stderr,"Mem error\n");
2296                                            gmc.duv[0].x= gmc.duv[0].y =
2297                                                    gmc.duv[1].x= gmc.duv[1].y =
2298                                                    gmc.duv[2].x= gmc.duv[2].y = 0;
2299                                            return gmc; }
2300    
2301          if (!MVzero(prevMB->i_mvs[0]))  // filter mask of all blocks
                 if (!MVequal(prevMB->i_mvs[0], pmv[0]))  
                         CHECK_MV16_CANDIDATE(prevMB->i_mvs[0].x, prevMB->i_mvs[0].y);  
   
 // left neighbour, if allowed  
   
         if (!MVzero(pmv[1]))  
                 if (!MVequal(pmv[1], prevMB->i_mvs[0]))  
                         if (!MVequal(pmv[1], pmv[0]))  
                                 CHECK_MV16_CANDIDATE(pmv[1].x, pmv[1].y);  
   
 // top neighbour, if allowed  
         if (!MVzero(pmv[2]))  
                 if (!MVequal(pmv[2], prevMB->i_mvs[0]))  
                         if (!MVequal(pmv[2], pmv[0]))  
                                 if (!MVequal(pmv[2], pmv[1]))  
                                         CHECK_MV16_CANDIDATE(pmv[2].x, pmv[2].y);  
   
 // top right neighbour, if allowed  
                                         if (!MVzero(pmv[3]))  
                                                 if (!MVequal(pmv[3], prevMB->i_mvs[0]))  
                                                         if (!MVequal(pmv[3], pmv[0]))  
                                                                 if (!MVequal(pmv[3], pmv[1]))  
                                                                         if (!MVequal(pmv[3], pmv[2]))  
                                                                                 CHECK_MV16_CANDIDATE(pmv[3].x,  
                                                                                                                          pmv[3].y);  
   
         if ((MVzero(*currMV)) &&  
                 (!MVzero(pmv[0])) /* && (iMinSAD <= iQuant * 96) */ )  
                 iMinSAD -= MV16_00_BIAS;  
2302    
2303            for (my = 1; my < (uint32_t)MBh-1; my++)
2304            for (mx = 1; mx < (uint32_t)MBw-1; mx++)
2305            {
2306                    const int mbnum = mx + my * MBw;
2307                    const MACROBLOCK *pMB = &pMBs[mbnum];
2308                    const VECTOR mv = pMB->mvs[0];
2309    
2310  /* Step 6: If MinSAD <= thresa goto Step 10.                  if (pMB->mode == MODE_INTRA || pMB->mode == MODE_NOT_CODED)
2311     If Motion Vector equal to Previous frame motion vector and MinSAD<PrevFrmSAD goto Step 10.                          continue;
 */  
2312    
2313          if ((iMinSAD <= threshA) ||                  if ( ( (abs(mv.x -   (pMB-1)->mvs[0].x) < deltax) && (abs(mv.y -   (pMB-1)->mvs[0].y) < deltay) )
2314                  (MVequal(*currMV, prevMB->i_mvs[0]) &&                  &&   ( (abs(mv.x -   (pMB+1)->mvs[0].x) < deltax) && (abs(mv.y -   (pMB+1)->mvs[0].y) < deltay) )
2315                   ((int32_t) iMinSAD < prevMB->i_sad16))) {                  &&   ( (abs(mv.x - (pMB-MBw)->mvs[0].x) < deltax) && (abs(mv.y - (pMB-MBw)->mvs[0].y) < deltay) )
2316                    &&   ( (abs(mv.x - (pMB+MBw)->mvs[0].x) < deltax) && (abs(mv.y - (pMB+MBw)->mvs[0].y) < deltay) ) )
2317                  if (MotionFlags & PMV_EARLYSTOP16)                          MBmask[mbnum]=1;
                         goto PMVfastInt16_Terminate_with_Refine;  
2318          }          }
2319    
2320            for (my = 1; my < (uint32_t)MBh-1; my++)
2321            for (mx = 1; mx < (uint32_t)MBw-1; mx++)
2322            {
2323                    const uint8_t *const pCur = current->image.y + 16*my*pParam->edged_width + 16*mx;
2324    
2325  /************ (Diamond Search)  **************/                  const int mbnum = mx + my * MBw;
2326  /*                  if (!MBmask[mbnum])
2327     Step 7: Perform Diamond search, with either the small or large diamond.                          continue;
    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.  
 */  
   
         if (MotionFlags & PMV_USESQUARES16)  
                 MainSearchPtr = Square16_MainSearch;  
         else if (MotionFlags & PMV_ADVANCEDDIAMOND16)  
                 MainSearchPtr = AdvDiamond16_MainSearch;  
         else  
                 MainSearchPtr = Diamond16_MainSearch;  
2328    
2329          backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */                  if (sad16 ( pCur, pCur+1 , pParam->edged_width, 65536) <= (uint32_t)grad )
2330                            MBmask[mbnum] = 0;
2331                    if (sad16 ( pCur, pCur+pParam->edged_width, pParam->edged_width, 65536) <= (uint32_t)grad )
2332                            MBmask[mbnum] = 0;
2333    
2334            }
2335    
2336  /* default: use best prediction as starting point for one call of PMVfast_MainSearch */          emms();
         iSAD =  
                 (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV->x,  
                                                   currMV->y, iMinSAD, &newMV, center_x, center_y, min_dx, max_dx,  
                                                   min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode,  
                                                   iQuant, iFound);  
2337    
2338          if (iSAD < iMinSAD) {          do {            /* until convergence */
                 *currMV = newMV;  
                 iMinSAD = iSAD;  
         }  
2339    
2340          if (MotionFlags & PMV_EXTSEARCH16) {          a = b = c = n = 0;
2341  /* extended: search (up to) two more times: orignal prediction and (0,0) */          DtimesF[0] = DtimesF[1] = DtimesF[2] = DtimesF[3] = 0.;
2342            for (my = 0; my < (uint32_t)MBh; my++)
2343                    for (mx = 0; mx < (uint32_t)MBw; mx++)
2344                    {
2345                            const int mbnum = mx + my * MBw;
2346                            const MACROBLOCK *pMB = &pMBs[mbnum];
2347                            const VECTOR mv = pMB->mvs[0];
2348    
2349                  if (!(MVequal(pmv[0], backupMV))) {                          if (!MBmask[mbnum])
2350                          iSAD =                                  continue;
                                 (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,  
                                                                   pmv[0].x, pmv[0].y, iMinSAD, &newMV, center_x, center_y,  
                                                                   min_dx, max_dx, min_dy, max_dy, iEdgedWidth,  
                                                                   iDiamondSize, iFcode, iQuant, iFound);  
2351    
2352                          if (iSAD < iMinSAD) {                          n++;
2353                                  *currMV = newMV;                          a += 16*mx+8;
2354                                  iMinSAD = iSAD;                          b += 16*my+8;
2355                          }                          c += (16*mx+8)*(16*mx+8)+(16*my+8)*(16*my+8);
2356                  }  
2357                            DtimesF[0] += (double)mv.x;
2358                            DtimesF[1] += (double)mv.x*(16*mx+8) + (double)mv.y*(16*my+8);
2359                            DtimesF[2] += (double)mv.x*(16*my+8) - (double)mv.y*(16*mx+8);
2360                            DtimesF[3] += (double)mv.y;
2361                    }
2362    
2363            denom = a*a+b*b-c*n;
2364    
2365    /* Solve the system:    sol = (D'*E*D)^{-1} D'*E*F   */
2366    /* D'*E*F has been calculated in the same loop as matrix */
2367    
2368            sol[0] = -c*DtimesF[0] + a*DtimesF[1] + b*DtimesF[2];
2369            sol[1] =  a*DtimesF[0] - n*DtimesF[1]                           + b*DtimesF[3];
2370            sol[2] =  b*DtimesF[0]                          - n*DtimesF[2] - a*DtimesF[3];
2371            sol[3] =                                 b*DtimesF[1] - a*DtimesF[2] - c*DtimesF[3];
2372    
2373            sol[0] /= denom;
2374            sol[1] /= denom;
2375            sol[2] /= denom;
2376            sol[3] /= denom;
2377    
2378            meanx = meany = 0.;
2379            oldnum = 0;
2380            for (my = 0; my < (uint32_t)MBh; my++)
2381                    for (mx = 0; mx < (uint32_t)MBw; mx++)
2382                    {
2383                            const int mbnum = mx + my * MBw;
2384                            const MACROBLOCK *pMB = &pMBs[mbnum];
2385                            const VECTOR mv = pMB->mvs[0];
2386    
2387                  if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {                          if (!MBmask[mbnum])
2388                          iSAD =                                  continue;
                                 (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, 0, 0,  
                                                                   iMinSAD, &newMV, center_x, center_y, min_dx, max_dx, min_dy,  
                                                                   max_dy, iEdgedWidth, iDiamondSize, iFcode,  
                                                                   iQuant, iFound);  
2389    
2390                          if (iSAD < iMinSAD) {                          oldnum++;
2391                                  *currMV = newMV;                          meanx += fabs(( sol[0] + (16*mx+8)*sol[1] + (16*my+8)*sol[2] ) - mv.x );
2392                                  iMinSAD = iSAD;                          meany += fabs(( sol[3] - (16*mx+8)*sol[2] + (16*my+8)*sol[1] ) - mv.y );
                         }  
2393                  }                  }
         }  
   
 /*  
    Step 10:  The motion vector is chosen according to the block corresponding to MinSAD.  
 */  
2394    
2395  PMVfastInt16_Terminate_with_Refine:          if (4*meanx > oldnum)   /* better fit than 0.25 is useless */
2396                    meanx /= oldnum;
2397            else
2398                    meanx = 0.25;
2399    
2400          pMB->i_mvs[0] = pMB->i_mvs[1] = pMB->i_mvs[2] = pMB->i_mvs[3] = pMB->i_mv16 = *currMV;          if (4*meany > oldnum)
2401          pMB->i_sad8[0] = pMB->i_sad8[1] = pMB->i_sad8[2] = pMB->i_sad8[3] = pMB->i_sad16 = iMinSAD;                  meany /= oldnum;
2402            else
2403                    meany = 0.25;
2404    
2405          if (MotionFlags & PMV_HALFPELREFINE16)  // perform final half-pel step  /*      fprintf(stderr,"sol = (%8.5f, %8.5f, %8.5f, %8.5f)\n",sol[0],sol[1],sol[2],sol[3]);
2406                  iMinSAD =          fprintf(stderr,"meanx = %8.5f  meany = %8.5f   %d\n",meanx,meany, oldnum);
2407                          Halfpel16_Refine(pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV,  */
2408                                                           iMinSAD, center_x, center_y, min_dx, max_dx, min_dy, max_dy,          num = 0;
2409                                                           iFcode, iQuant, iEdgedWidth);          for (my = 0; my < (uint32_t)MBh; my++)
2410                    for (mx = 0; mx < (uint32_t)MBw; mx++)
2411                    {
2412                            const int mbnum = mx + my * MBw;
2413                            const MACROBLOCK *pMB = &pMBs[mbnum];
2414                            const VECTOR mv = pMB->mvs[0];
2415    
2416          pmv[0] = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 0);          // get _REAL_ prediction (halfpel possible)                          if (!MBmask[mbnum])
2417                                    continue;
2418    
2419  PMVfastInt16_Terminate_without_Refine:                          if  ( ( fabs(( sol[0] + (16*mx+8)*sol[1] + (16*my+8)*sol[2] ) - mv.x ) > meanx )
2420          currPMV->x = currMV->x - center_x;                                  || ( fabs(( sol[3] - (16*mx+8)*sol[2] + (16*my+8)*sol[1] ) - mv.y ) > meany ) )
2421          currPMV->y = currMV->y - center_y;                                  MBmask[mbnum]=0;
2422          return iMinSAD;                          else
2423                                    num++;
2424  }  }
2425    
2426            } while ( (oldnum != num) && (num>=4) );
2427    
2428            if (num < 4)
 /* ***********************************************************  
         bvop motion estimation  
 ***************************************************************/  
   
 void  
 MotionEstimationBVOP(MBParam * const pParam,  
                                          FRAMEINFO * const frame,  
                                          const int32_t time_bp,  
                                          const int32_t time_pp,  
                                          // forward (past) reference  
                                          const MACROBLOCK * const f_mbs,  
                                          const IMAGE * const f_ref,  
                                          const IMAGE * const f_refH,  
                                          const IMAGE * const f_refV,  
                                          const IMAGE * const f_refHV,  
                                          // backward (future) reference  
                                          const MACROBLOCK * const b_mbs,  
                                          const IMAGE * const b_ref,  
                                          const IMAGE * const b_refH,  
                                          const IMAGE * const b_refV,  
                                          const IMAGE * const b_refHV)  
2429  {  {
2430          const int mb_width = pParam->mb_width;                  gmc.duv[0].x= gmc.duv[0].y= gmc.duv[1].x= gmc.duv[1].y= gmc.duv[2].x= gmc.duv[2].y=0;
2431          const int mb_height = pParam->mb_height;          } else {
         const int edged_width = pParam->edged_width;  
   
         const int32_t iWidth = pParam->width;  
         const int32_t iHeight = pParam->height;  
2432    
2433          int i, j, k;                  gmc.duv[0].x=(int)(sol[0]+0.5);
2434                    gmc.duv[0].y=(int)(sol[3]+0.5);
2435    
2436          static const VECTOR zeroMV={0,0};                  gmc.duv[1].x=(int)(sol[1]*pParam->width+0.5);
2437                    gmc.duv[1].y=(int)(-sol[2]*pParam->width+0.5);
2438    
2439          int f_sad16;    /* forward (as usual) search */                  gmc.duv[2].x=0;
2440          int b_sad16;    /* backward (only in b-frames) search */                  gmc.duv[2].y=0;
2441          int i_sad16;    /* interpolated (both direction, b-frames only) */          }
2442          int d_sad16;    /* direct mode (assume almost linear motion) */  //      fprintf(stderr,"wp1 = ( %4d, %4d)  wp2 = ( %4d, %4d) \n", gmc.duv[0].x, gmc.duv[0].y, gmc.duv[1].x, gmc.duv[1].y);
2443    
2444          int best_sad;          free(MBmask);
2445    
2446          VECTOR f_predMV, b_predMV;      /* there is no prediction for direct mode*/          return gmc;
2447          VECTOR f_interpolMV, b_interpolMV;  }
         VECTOR pmv_dontcare;  
2448    
2449          int min_dx, max_dx, min_dy, max_dy;  // functions which perform BITS-based search/bitcount
         int f_min_dx, f_max_dx, f_min_dy, f_max_dy;  
         int b_min_dx, b_max_dx, b_min_dy, b_max_dy;  
   
         int f_count=0;  
         int b_count=0;  
         int i_count=0;  
         int d_count=0;  
2450    
2451          const int64_t TRB = (int32_t)time_pp - (int32_t)time_bp;  static int
2452      const int64_t TRD = (int32_t)time_pp;  CountMBBitsInter(SearchData * const Data,
2453                                    const MACROBLOCK * const pMBs, const int x, const int y,
2454                                    const MBParam * const pParam,
2455                                    const uint32_t MotionFlags)
2456    {
2457            int i, iDirection;
2458            int32_t bsad[5];
2459    
2460          // fprintf(stderr,"TRB = %lld  TRD = %lld  time_bp =%d time_pp =%d\n\n",TRB,TRD,time_bp,time_pp);          CheckCandidate = CheckCandidateBits16;
         // note: i==horizontal, j==vertical  
         for (j = 0; j < mb_height; j++) {  
2461    
2462                  f_predMV = zeroMV;      /* prediction is reset at left boundary */          if (Data->qpel) {
2463                  b_predMV = zeroMV;                  for(i = 0; i < 5; i++) {
2464                            Data->currentMV[i].x = Data->currentQMV[i].x/2;
2465                            Data->currentMV[i].y = Data->currentQMV[i].y/2;
2466                    }
2467                    Data->qpel_precision = 1;
2468                    CheckCandidateBits16(Data->currentQMV[0].x, Data->currentQMV[0].y, 255, &iDirection, Data);
2469    
2470                  for (i = 0; i < mb_width; i++) {                  //checking if this vector is perfect. if it is, we stop.
2471                          MACROBLOCK *mb = &frame->mbs[i + j * mb_width];                  if (Data->temp[0] == 0 && Data->temp[1] == 0 && Data->temp[2] == 0 && Data->temp[3] == 0)
2472                          const MACROBLOCK *f_mb = &f_mbs[i + j * mb_width];                          return 0; //quick stop
                         const MACROBLOCK *b_mb = &b_mbs[i + j * mb_width];  
2473    
2474                          mb->deltamv=zeroMV;                  if (MotionFlags & (HALFPELREFINE16_BITS | EXTSEARCH_BITS)) { //we have to prepare for halfpixel-precision search
2475                            for(i = 0; i < 5; i++) bsad[i] = Data->iMinSAD[i];
2476                            get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
2477                                                    pParam->width, pParam->height, Data->iFcode - Data->qpel, 0, Data->rrv);
2478                            Data->qpel_precision = 0;
2479                            if (Data->currentQMV->x & 1 || Data->currentQMV->y & 1)
2480                                    CheckCandidateBits16(Data->currentMV[0].x, Data->currentMV[0].y, 255, &iDirection, Data);
2481                    }
2482    
2483  /* special case, if collocated block is SKIPed: encoding is forward (0,0), cpb=0 without further ado */          } else { // not qpel
2484    
2485                          if (b_mb->mode == MODE_INTER && b_mb->cbp == 0 &&                  CheckCandidateBits16(Data->currentMV[0].x, Data->currentMV[0].y, 255, &iDirection, Data);
2486                                  b_mb->mvs[0].x == 0 && b_mb->mvs[0].y == 0) {                  //checking if this vector is perfect. if it is, we stop.
2487                                  mb->mode = MODE_NOT_CODED;                  if (Data->temp[0] == 0 && Data->temp[1] == 0 && Data->temp[2] == 0 && Data->temp[3] == 0) {
2488                                  mb->b_mvs[0] = mb->mvs[0] = zeroMV;                          return 0; //inter
2489                                  continue;                  }
2490                          }                          }
2491    
2492                          if (b_mb->mode == MODE_INTER4V)          if (MotionFlags&EXTSEARCH_BITS) SquareSearch(Data->currentMV->x, Data->currentMV->y, Data, iDirection);
                         {  
                                 d_sad16 = 0;  
                         /* same method of scaling as in decoder.c, so we copy from there */  
                     for (k = 0; k < 4; k++) {  
2493    
2494                                          mb->directmv[k] = b_mb->mvs[k];          if (MotionFlags&HALFPELREFINE16_BITS) SubpelRefine(Data);
2495    
2496                                          mb->mvs[k].x = (int32_t) ((TRB * mb->directmv[k].x) / TRD + mb->deltamv.x);          if (Data->qpel) {
2497                      mb->b_mvs[k].x = (int32_t) ((mb->deltamv.x == 0)                  if (MotionFlags&(EXTSEARCH_BITS | HALFPELREFINE16_BITS)) { // there was halfpel-precision search
2498                                                                                  ? ((TRB - TRD) * mb->directmv[k].x) / TRD                          for(i = 0; i < 5; i++) if (bsad[i] > Data->iMinSAD[i]) {
2499                                              : mb->mvs[k].x - mb->directmv[k].x);                                  Data->currentQMV[i].x = 2 * Data->currentMV[i].x; // we have found a better match
2500                                    Data->currentQMV[i].y = 2 * Data->currentMV[i].y;
                     mb->mvs[k].y = (int32_t) ((TRB * mb->directmv[k].y) / TRD + mb->deltamv.y);  
                         mb->b_mvs[k].y = (int32_t) ((mb->deltamv.y == 0)  
                                                                                 ? ((TRB - TRD) * mb->directmv[k].y) / TRD  
                                             : mb->mvs[k].y - mb->directmv[k].y);  
   
                                         d_sad16 +=  
                                                 sad8bi(frame->image.y + (2*i+(k&1))*8 + (2*j+(k>>1))*8*edged_width,  
                                                   get_ref_mv(f_ref->y, f_refH->y, f_refV->y, f_refHV->y,  
                                                                 (2*i+(k&1)), (2*j+(k>>1)), 8, &mb->mvs[k], edged_width),  
                                                   get_ref_mv(b_ref->y, b_refH->y, b_refV->y, b_refHV->y,  
                                                                 (2*i+(k&1)), (2*j+(k>>1)), 8, &mb->b_mvs[k], edged_width),  
                                                   edged_width);  
                                 }  
2501                          }                          }
                         else  
                         {  
                                 mb->directmv[3] = mb->directmv[2] = mb->directmv[1] =  
                                         mb->directmv[0] = b_mb->mvs[0];  
2502    
2503                                  mb->mvs[0].x = (int32_t) ((TRB * mb->directmv[0].x) / TRD + mb->deltamv.x);                          // preparing for qpel-precision search
2504                      mb->b_mvs[0].x = (int32_t) ((mb->deltamv.x == 0)                          Data->qpel_precision = 1;
2505                                                                          ? ((TRB - TRD) * mb->directmv[0].x) / TRD                          get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
2506                                      : mb->mvs[0].x - mb->directmv[0].x);                                          pParam->width, pParam->height, Data->iFcode, 1, 0);
2507                    }
2508                      mb->mvs[0].y = (int32_t) ((TRB * mb->directmv[0].y) / TRD + mb->deltamv.y);                  if (MotionFlags&QUARTERPELREFINE16_BITS) SubpelRefine(Data);
2509                  mb->b_mvs[0].y = (int32_t) ((mb->directmv[0].y == 0)          }
                                                                         ? ((TRB - TRD) * mb->directmv[0].y) / TRD  
                                     : mb->mvs[0].y - mb->directmv[0].y);  
   
                                 d_sad16 = sad16bi(frame->image.y + i * 16 + j * 16 * edged_width,  
                                                   get_ref_mv(f_ref->y, f_refH->y, f_refV->y, f_refHV->y,  
                                                                 i, j, 16, &mb->mvs[0], edged_width),  
                                                   get_ref_mv(b_ref->y, b_refH->y, b_refV->y, b_refHV->y,  
                                                                 i, j, 16, &mb->b_mvs[0], edged_width),  
                                                   edged_width);  
2510    
2511            if (MotionFlags&CHECKPREDICTION_BITS) { //let's check vector equal to prediction
2512                    VECTOR * v = Data->qpel ? Data->currentQMV : Data->currentMV;
2513                    if (!(Data->predMV.x == v->x && Data->predMV.y == v->y))
2514                            CheckCandidateBits16(Data->predMV.x, Data->predMV.y, 255, &iDirection, Data);
2515            }
2516            return Data->iMinSAD[0];
2517              }              }
                     d_sad16 += calc_delta_16(mb->deltamv.x, mb->deltamv.y, 1, frame->quant);  
2518    
                         // forward search  
                         f_sad16 = SEARCH16(f_ref->y, f_refH->y, f_refV->y, f_refHV->y,  
                                                 &frame->image, i, j,  
                                                 mb->mvs[0].x, mb->mvs[0].y,                     /* start point f_directMV */  
                                                 f_predMV.x, f_predMV.y,                         /* center is f-prediction */  
                                                 frame->motion_flags,  
                                                 frame->quant, frame->fcode, pParam,  
                                                 f_mbs, f_mbs,  
                                                 &mb->mvs[0], &pmv_dontcare);  
2519    
2520    static int
2521    CountMBBitsInter4v(const SearchData * const Data,
2522                                            MACROBLOCK * const pMB, const MACROBLOCK * const pMBs,
2523                                            const int x, const int y,
2524                                            const MBParam * const pParam, const uint32_t MotionFlags,
2525                                            const VECTOR * const backup)
2526    {
2527    
2528                          // backward search          int cbp = 0, bits = 0, t = 0, i, iDirection;
2529                          b_sad16 = SEARCH16(b_ref->y, b_refH->y, b_refV->y, b_refHV->y,          SearchData Data2, *Data8 = &Data2;
2530                                                  &frame->image, i, j,          int sumx = 0, sumy = 0;
2531                                                  mb->b_mvs[0].x, mb->b_mvs[0].y,         /* start point b_directMV */          int16_t *in = Data->dctSpace, *coeff = Data->dctSpace + 64;
2532                                                  b_predMV.x, b_predMV.y,                         /* center is b-prediction */  
2533                                                  frame->motion_flags,          memcpy(Data8, Data, sizeof(SearchData));
2534                                                  frame->quant, frame->bcode, pParam,          CheckCandidate = CheckCandidateBits8;
2535                                                  b_mbs, b_mbs,  
2536                                                  &mb->b_mvs[0], &pmv_dontcare);          for (i = 0; i < 4; i++) {
2537                    Data8->iMinSAD = Data->iMinSAD + i + 1;
2538                          i_sad16 =                  Data8->currentMV = Data->currentMV + i + 1;
2539                                  sad16bi(frame->image.y + i * 16 + j * 16 * edged_width,                  Data8->currentQMV = Data->currentQMV + i + 1;
2540                                                    get_ref_mv(f_ref->y, f_refH->y, f_refV->y, f_refHV->y,                  Data8->Cur = Data->Cur + 8*((i&1) + (i>>1)*Data->iEdgedWidth);
2541                                                                  i, j, 16, &mb->mvs[0], edged_width),                  Data8->RefP[0] = Data->RefP[0] + 8*((i&1) + (i>>1)*Data->iEdgedWidth);
2542                                                    get_ref_mv(b_ref->y, b_refH->y, b_refV->y, b_refHV->y,                  Data8->RefP[2] = Data->RefP[2] + 8*((i&1) + (i>>1)*Data->iEdgedWidth);
2543                                                                  i, j, 16, &mb->b_mvs[0], edged_width),                  Data8->RefP[1] = Data->RefP[1] + 8*((i&1) + (i>>1)*Data->iEdgedWidth);
2544                                                    edged_width);                  Data8->RefP[3] = Data->RefP[3] + 8*((i&1) + (i>>1)*Data->iEdgedWidth);
2545                      i_sad16 += calc_delta_16(mb->mvs[0].x-f_predMV.x, mb->mvs[0].y-f_predMV.y,  
2546                                                                  frame->fcode, frame->quant);                  if(Data->qpel) {
2547                      i_sad16 += calc_delta_16(mb->b_mvs[0].x-b_predMV.x, mb->b_mvs[0].y-b_predMV.y,                          Data8->predMV = get_qpmv2(pMBs, pParam->mb_width, 0, x, y, i);
2548                                                                  frame->bcode, frame->quant);                          if (i != 0)     t = d_mv_bits(  Data8->currentQMV->x, Data8->currentQMV->y,
2549                                                                                    Data8->predMV, Data8->iFcode, 0, 0);
                         get_range(&f_min_dx, &f_max_dx, &f_min_dy, &f_max_dy, i, j, 16, iWidth, iHeight,  
                           frame->fcode);  
                         get_range(&b_min_dx, &b_max_dx, &b_min_dy, &b_max_dy, i, j, 16, iWidth, iHeight,  
                           frame->bcode);  
   
 /* Interpolated MC motion vector search, this is tedious and more complicated because there are  
    two values for everything, always one for backward and one for forward ME. Still, we don't gain  
    much from this search, maybe it should simply be skipped and simply current i_sad16 value used  
    as "optimal". */  
   
                         i_sad16 = Diamond16_InterpolMainSearch(  
                                                 f_ref->y, f_refH->y, f_refV->y, f_refHV->y,  
                                                 frame->image.y + i * 16 + j * 16 * edged_width,  
                                                 b_ref->y, b_refH->y, b_refV->y, b_refHV->y,  
                                                 i, j,  
                                                 mb->mvs[0].x, mb->mvs[0].y,  
                                                 mb->b_mvs[0].x, mb->b_mvs[0].y,  
                                                 i_sad16,  
                                                 &f_interpolMV, &b_interpolMV,  
                                                 f_predMV.x, f_predMV.y, b_predMV.x, b_predMV.y,  
                                                 f_min_dx, f_max_dx, f_min_dy, f_max_dy,  
                                                 b_min_dx, b_max_dx, b_min_dy, b_max_dy,  
                                                 edged_width,  2,  
                                                 frame->fcode, frame->bcode,frame->quant,0);  
   
                         i_sad16 = Diamond16_InterpolMainSearch(  
                                                 f_ref->y, f_refH->y, f_refV->y, f_refHV->y,  
                                                 frame->image.y + i * 16 + j * 16 * edged_width,  
                                                 b_ref->y, b_refH->y, b_refV->y, b_refHV->y,  
                                                 i, j,  
                                                 f_interpolMV.x, f_interpolMV.y,  
                                                 b_interpolMV.x, b_interpolMV.y,  
                                                 i_sad16,  
                                                 &f_interpolMV, &b_interpolMV,  
                                                 f_predMV.x, f_predMV.y, b_predMV.x, b_predMV.y,  
                                                 f_min_dx, f_max_dx, f_min_dy, f_max_dy,  
                                                 b_min_dx, b_max_dx, b_min_dy, b_max_dy,  
                                                 edged_width,  1,  
                                                 frame->fcode, frame->bcode,frame->quant,0);             // equiv to halfpel refine  
   
   
 /*  DIRECT MODE DELTA VECTOR SEARCH.  
     This has to be made more effective, but at the moment I'm happy it's running at all */  
   
 /* There are two range restrictions for direct mode: deltaMV is limited to [-32,31] in halfpel units, and  
    absolute vector must not lie outside of image dimensions. Constraint one is dealt with by CHECK_MV16_DIRECT  
    and for constraint two we need distance to boundary. This is done by get_range very large fcode (hack!) */  
   
                         get_range(&min_dx, &max_dx, &min_dy, &max_dy, i, j, 16, iWidth, iHeight, 19);  
   
                         d_sad16 = Diamond16_DirectMainSearch(  
                                                 f_ref->y, f_refH->y, f_refV->y, f_refHV->y,  
                                                 frame->image.y + i*16 + j*16*edged_width,  
                                                 b_ref->y, b_refH->y, b_refV->y, b_refHV->y,  
                                                 i, j,  
                                                 TRB,TRD,  
                                                 0,0,  
                                                 d_sad16,  
                                                 &mb->deltamv,  
                                                 mb->directmv, // this has to be pre-initialized with b_mb->mvs[]  
                                         min_dx, max_dx, min_dy, max_dy,  
                                                 edged_width, 2, frame->quant, 0);  
   
                         d_sad16 = Diamond16_DirectMainSearch(  
                                                 f_ref->y, f_refH->y, f_refV->y, f_refHV->y,  
                                                 frame->image.y + i*16 + j*16*edged_width,  
                                                 b_ref->y, b_refH->y, b_refV->y, b_refHV->y,  
                                                 i, j,  
                                                 TRB,TRD,  
                                                 mb->deltamv.x, mb->deltamv.y,  
                                                 d_sad16,  
                                                 &mb->deltamv,  
                                                 mb->directmv, // this has to be pre-initialized with b_mb->mvs[]  
                                         min_dx, max_dx, min_dy, max_dy,  
                                                 edged_width, 1, frame->quant, 0);               // equiv to halfpel refine  
   
   
 //                      i_sad16 = 65535;                /* remove the comment to disable any of the MODEs */  
 //                      f_sad16 = 65535;  
 //                      b_sad16 = 65535;  
 //                      d_sad16 = 65535;  
   
                         if (f_sad16 < b_sad16) {  
                                 best_sad = f_sad16;  
                                 mb->mode = MODE_FORWARD;  
2550                          } else {                          } else {
2551                                  best_sad = b_sad16;                          Data8->predMV = get_pmv2(pMBs, pParam->mb_width, 0, x, y, i);
2552                                  mb->mode = MODE_BACKWARD;                          if (i != 0)     t = d_mv_bits(  Data8->currentMV->x, Data8->currentMV->y,
2553                                                                                    Data8->predMV, Data8->iFcode, 0, 0);
2554                          }                          }
2555    
2556                          if (i_sad16 < best_sad) {                  get_range(&Data8->min_dx, &Data8->max_dx, &Data8->min_dy, &Data8->max_dy, 2*x + (i&1), 2*y + (i>>1), 8,
2557                                  best_sad = i_sad16;                                          pParam->width, pParam->height, Data8->iFcode, Data8->qpel, 0);
                                 mb->mode = MODE_INTERPOLATE;  
                         }  
2558    
2559                          if (d_sad16 < best_sad) {                  *Data8->iMinSAD += t;
2560    
2561                                  if (b_mb->mode == MODE_INTER4V)                  Data8->qpel_precision = Data8->qpel;
2562                    // checking the vector which has been found by SAD-based 8x8 search (if it's different than the one found so far)
2563                                  {                                  {
2564                            VECTOR *v = Data8->qpel ? Data8->currentQMV : Data8->currentMV;
2565                            if (!( (v->x == backup[i+1].x) && (v->y == backup[i+1].y) ))
2566                                    CheckCandidateBits8(backup[i+1].x, backup[i+1].y, 255, &iDirection, Data8);
2567                    }
2568    
2569                                  /* how to calc vectors is defined in standard. mvs[] and b_mvs[] are only for motion compensation */                  if (Data8->qpel) {
2570                                  /* for the bitstream, the value mb->deltamv is read directly */                          if (MotionFlags&HALFPELREFINE8_BITS || (MotionFlags&PMV_EXTSEARCH8 && MotionFlags&EXTSEARCH_BITS)) { // halfpixel motion search follows
2571                                    int32_t s = *Data8->iMinSAD;
2572                                    Data8->currentMV->x = Data8->currentQMV->x/2;
2573                                    Data8->currentMV->y = Data8->currentQMV->y/2;
2574                                    Data8->qpel_precision = 0;
2575                                    get_range(&Data8->min_dx, &Data8->max_dx, &Data8->min_dy, &Data8->max_dy, 2*x + (i&1), 2*y + (i>>1), 8,
2576                                                            pParam->width, pParam->height, Data8->iFcode - 1, 0, 0);
2577    
2578                              for (k = 0; k < 4; k++) {                                  if (Data8->currentQMV->x & 1 || Data8->currentQMV->y & 1)
2579                                            CheckCandidateBits8(Data8->currentMV->x, Data8->currentMV->y, 255, &iDirection, Data8);
2580    
2581                                                  mb->mvs[k].x = (int32_t) ((TRB * mb->directmv[k].x) / TRD + mb->deltamv.x);                                  if (MotionFlags & PMV_EXTSEARCH8 && MotionFlags & EXTSEARCH_BITS)
2582                              mb->b_mvs[k].x = (int32_t) ((mb->deltamv.x == 0)                                          SquareSearch(Data8->currentMV->x, Data8->currentMV->x, Data8, 255);
                                                                                         ? ((TRB - TRD) * mb->directmv[k].x) / TRD  
                                                     : mb->mvs[k].x - mb->directmv[k].x);  
   
                             mb->mvs[k].y = (int32_t) ((TRB * mb->directmv[k].y) / TRD + mb->deltamv.y);  
                         mb->b_mvs[k].y = (int32_t) ((mb->deltamv.y == 0)  
                                                                                         ? ((TRB - TRD) * mb->directmv[k].y) / TRD  
                                             : mb->mvs[k].y - mb->directmv[k].y);  
                                         }  
                                 }  
                                 else  
                                 {  
                                         mb->mvs[0].x = (int32_t) ((TRB * mb->directmv[0].x) / TRD + mb->deltamv.x);  
2583    
2584                      mb->b_mvs[0].x = (int32_t) ((mb->deltamv.x == 0)                                  if (MotionFlags & HALFPELREFINE8_BITS) SubpelRefine(Data8);
                                                                                 ? ((TRB - TRD) * mb->directmv[0].x) / TRD  
                                         : mb->mvs[0].x - mb->directmv[0].x);  
2585    
2586                              mb->mvs[0].y = (int32_t) ((TRB * mb->directmv[0].y) / TRD + mb->deltamv.y);                                  if(s > *Data8->iMinSAD) { //we have found a better match
2587                                            Data8->currentQMV->x = 2*Data8->currentMV->x;
2588                                            Data8->currentQMV->y = 2*Data8->currentMV->y;
2589                                    }
2590    
2591                          mb->b_mvs[0].y = (int32_t) ((mb->deltamv.y == 0)                                  Data8->qpel_precision = 1;
2592                                                                                  ? ((TRB - TRD) * mb->directmv[0].y) / TRD                                  get_range(&Data8->min_dx, &Data8->max_dx, &Data8->min_dy, &Data8->max_dy, 2*x + (i&1), 2*y + (i>>1), 8,
2593                                              : mb->mvs[0].y - mb->directmv[0].y);                                                          pParam->width, pParam->height, Data8->iFcode, 1, 0);
2594    
                                         mb->mvs[3] = mb->mvs[2] = mb->mvs[1] = mb->mvs[0];  
                                         mb->b_mvs[3] = mb->b_mvs[2] = mb->b_mvs[1] = mb->b_mvs[0];  
2595                  }                  }
2596                            if (MotionFlags & QUARTERPELREFINE8_BITS) SubpelRefine(Data8);
2597    
2598                    } else // not qpel
2599                            if (MotionFlags & HALFPELREFINE8_BITS) SubpelRefine(Data8); //halfpel mode, halfpel refinement
2600    
2601                                  best_sad = d_sad16;                  //checking vector equal to predicion
2602                                  mb->mode = MODE_DIRECT;                  if (i != 0 && MotionFlags & CHECKPREDICTION_BITS) {
2603                            const VECTOR * v = Data->qpel ? Data8->currentQMV : Data8->currentMV;
2604                            if (!(Data8->predMV.x == v->x && Data8->predMV.y == v->y))
2605                                    CheckCandidateBits8(Data8->predMV.x, Data8->predMV.y, 255, &iDirection, Data8);
2606                          }                          }
2607    
2608                          switch (mb->mode)                  bits += *Data8->iMinSAD;
2609                          {                  if (bits >= Data->iMinSAD[0]) break; // no chances for INTER4V
                                 case MODE_FORWARD:  
                                         f_count++;  
                                         f_predMV = mb->mvs[0];  
                                         break;  
                                 case MODE_BACKWARD:  
                                         b_count++;  
                                         b_predMV = mb->b_mvs[0];  
2610    
2611                                          break;                  // MB structures for INTER4V mode; we have to set them here, we don't have predictor anywhere else
2612                                  case MODE_INTERPOLATE:                  if(Data->qpel) {
2613                                          i_count++;                          pMB->pmvs[i].x = Data8->currentQMV->x - Data8->predMV.x;
2614                                          mb->mvs[0] = f_interpolMV;                          pMB->pmvs[i].y = Data8->currentQMV->y - Data8->predMV.y;
2615                                          mb->b_mvs[0] = b_interpolMV;                          pMB->qmvs[i] = *Data8->currentQMV;
2616                                          f_predMV = mb->mvs[0];                          sumx += Data8->currentQMV->x/2;
2617                                          b_predMV = mb->b_mvs[0];                          sumy += Data8->currentQMV->y/2;
2618                                          break;                  } else {
2619                                  case MODE_DIRECT:                          pMB->pmvs[i].x = Data8->currentMV->x - Data8->predMV.x;
2620                                          d_count++;                          pMB->pmvs[i].y = Data8->currentMV->y - Data8->predMV.y;
2621                                          break;                          sumx += Data8->currentMV->x;
2622                                  default:                          sumy += Data8->currentMV->y;
2623                                          break;                  }
2624                          }                  pMB->mvs[i] = *Data8->currentMV;
2625                    pMB->sad8[i] = 4 * *Data8->iMinSAD;
2626                    if (Data8->temp[0]) cbp |= 1 << (5 - i);
2627            }
2628    
2629            if (bits < *Data->iMinSAD) { // there is still a chance for inter4v mode. let's check chroma
2630                    const uint8_t * ptr;
2631                    sumx = (sumx >> 3) + roundtab_76[sumx & 0xf];
2632                    sumy = (sumy >> 3) + roundtab_76[sumy & 0xf];
2633    
2634                    //chroma U
2635                    ptr = interpolate8x8_switch2(Data->RefQ + 64, Data->RefP[4], 0, 0, sumx, sumy, Data->iEdgedWidth/2, Data->rounding);
2636                    transfer_8to16subro(in, Data->CurU, ptr, Data->iEdgedWidth/2);
2637                    fdct(in);
2638                    if (Data->lambda8 == 0) i = quant_inter(coeff, in, Data->lambda16);
2639                    else i = quant4_inter(coeff, in, Data->lambda16);
2640                    if (i > 0) {
2641                            bits += CodeCoeffInter_CalcBits(coeff, scan_tables[0]);
2642                            cbp |= 1 << (5 - 4);
2643                    }
2644    
2645                    if (bits < *Data->iMinSAD) { // still possible
2646                            //chroma V
2647                            ptr = interpolate8x8_switch2(Data->RefQ + 64, Data->RefP[5], 0, 0, sumx, sumy, Data->iEdgedWidth/2, Data->rounding);
2648                            transfer_8to16subro(in, Data->CurV, ptr, Data->iEdgedWidth/2);
2649                            fdct(in);
2650                            if (Data->lambda8 == 0) i = quant_inter(coeff, in, Data->lambda16);
2651                            else i = quant4_inter(coeff, in, Data->lambda16);
2652                            if (i > 0) {
2653                                    bits += CodeCoeffInter_CalcBits(coeff, scan_tables[0]);
2654                                    cbp |= 1 << (5 - 5);
2655                            }
2656                            bits += xvid_cbpy_tab[15-(cbp>>2)].len;
2657                            bits += mcbpc_inter_tab[(MODE_INTER4V & 7) | ((cbp & 3) << 3)].len;
2658                    }
2659            }
2660    
2661            return bits;
2662    }
2663    
2664    
2665    static int
2666    CountMBBitsIntra(const SearchData * const Data)
2667    {
2668            int bits = 1; //this one is ac/dc prediction flag. always 1.
2669            int cbp = 0, i, t, dc = 1024, b_dc;
2670            const uint32_t iQuant = Data->lambda16;
2671            int16_t *in = Data->dctSpace, * coeff = Data->dctSpace + 64;
2672            uint32_t iDcScaler = get_dc_scaler(iQuant, 1);;
2673    
2674            for(i = 0; i < 4; i++) {
2675                    int s = 8*((i&1) + (i>>1)*Data->iEdgedWidth);
2676                    transfer_8to16copy(in, Data->Cur + s, Data->iEdgedWidth);
2677                    fdct(in);
2678                    b_dc = in[0];
2679                    in[0] -= dc;
2680                    dc = b_dc;
2681                    if (Data->lambda8 == 0) quant_intra(coeff, in, iQuant, iDcScaler);
2682                    else quant4_intra(coeff, in, iQuant, iDcScaler);
2683    
2684                    bits += t = CodeCoeffIntra_CalcBits(coeff, scan_tables[0]) + dcy_tab[coeff[0] + 255].len;;
2685                    Data->temp[i] = t;
2686                    if (t != 0)  cbp |= 1 << (5 - i);
2687                    if (bits >= Data->iMinSAD[0]) break;
2688            }
2689    
2690            if (bits < Data->iMinSAD[0]) { // INTRA still looks good, let's add chroma
2691                    iDcScaler = get_dc_scaler(iQuant, 0);
2692                    //chroma U
2693                    transfer_8to16copy(in, Data->CurU, Data->iEdgedWidth/2);
2694                    fdct(in);
2695                    in[0] -= 1024;
2696                    if (Data->lambda8 == 0) quant_intra(coeff, in, iQuant, iDcScaler);
2697                    else quant4_intra(coeff, in, iQuant, iDcScaler);
2698    
2699                    bits += t = CodeCoeffIntra_CalcBits(coeff, scan_tables[0]) + dcc_tab[coeff[0] + 255].len;
2700                    if (t != 0) cbp |= 1 << (5 - 4);
2701    
2702                    if (bits < Data->iMinSAD[0]) {
2703                            //chroma V
2704                            transfer_8to16copy(in, Data->CurV, Data->iEdgedWidth/2);
2705                            fdct(in);
2706                            in[0] -= 1024;
2707                            if (Data->lambda8 == 0) quant_intra(coeff, in, iQuant, iDcScaler);
2708                            else quant4_intra(coeff, in, iQuant, iDcScaler);
2709    
2710                            bits += t = CodeCoeffIntra_CalcBits(coeff, scan_tables[0]) + dcc_tab[coeff[0] + 255].len;
2711                            if (t != 0) cbp |= 1 << (5 - 5);
2712    
2713                            bits += xvid_cbpy_tab[cbp>>2].len;
2714                            bits += mcbpc_inter_tab[(MODE_INTRA & 7) | ((cbp & 3) << 3)].len;
2715                  }                  }
2716          }          }
2717            return bits;
 #ifdef _DEBUG_BFRAME_STAT  
         fprintf(stderr,"B-Stat: F: %04d   B: %04d   I: %04d  D: %04d\n",  
                                 f_count,b_count,i_count,d_count);  
 #endif  
   
2718  }  }

Legend:
Removed from v.430  
changed lines
  Added in v.1001

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