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

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

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

trunk/xvidcore/src/motion/motion_est.c revision 430, Fri Sep 6 16:59:47 2002 UTC branches/dev-api-4/xvidcore/src/motion/motion_est.c revision 1022, Wed May 14 18:46:39 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;
                                   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)  
 {  
         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);  
518    
519          return iMinSAD;          if (data->chroma) sad += ChromaSAD2((xcf >> 1) + roundtab_79[xcf & 0x3],
520                                                                                    (ycf >> 1) + roundtab_79[ycf & 0x3],
521                                                                                    (xcb >> 1) + roundtab_79[xcb & 0x3],
522                                                                                    (ycb >> 1) + roundtab_79[ycb & 0x3], data);
523    
524            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    {
647    
648                                     const int f_start_x,          int16_t *in = data->dctSpace, *coeff = data->dctSpace + 64;
649                                     const int f_start_y,          int32_t bits = 0;
650                                     const int b_start_x,          VECTOR * current;
651                                     const int b_start_y,          const uint8_t * ptr;
652            int i, cbp = 0, t, xc, yc;
                                    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,  
653    
654                                          const int x,          if ( (x > data->max_dx) || (x < data->min_dx)
655                                          const int y,                  || (y > data->max_dy) || (y < data->min_dy) ) return;
656    
657            if (!data->qpel_precision) {
658                    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                                          const int TRB,          for(i = 0; i < 4; i++) {
668                                          const int TRD,                  int s = 8*((i&1) + (i>>1)*data->iEdgedWidth);
669                    transfer_8to16subro(in, data->Cur + s, ptr + s, data->iEdgedWidth);
670                    bits += data->temp[i] = Block_CalcBits(coeff, in, data->iQuant, data->quant_type, &cbp, i, 0);
671            }
672    
673                                      const int start_x,          bits += t = d_mv_bits(x, y, data->predMV, data->iFcode, data->qpel^data->qpel_precision, 0);
                                     const int start_y,  
674    
675                                      int iMinSAD,          bits += xvid_cbpy_tab[15-(cbp>>2)].len;
                                     VECTOR * const currMV,  
                                         const VECTOR * const directmv,  
676    
677                                      const int32_t min_dx,          if (bits >= data->iMinSAD[0]) return;
                                         const int32_t max_dx,  
                                         const int32_t min_dy,  
                                         const int32_t max_dy,  
678    
679                                          const int32_t iEdgedWidth,          //chroma
680                                          const int32_t iDiamondSize,          xc = (xc >> 1) + roundtab_79[xc & 0x3];
681            yc = (yc >> 1) + roundtab_79[yc & 0x3];
682    
683                                          const int32_t iQuant,          //chroma U
684                                          int iFound)          ptr = interpolate8x8_switch2(data->RefQ + 64, data->RefP[4], 0, 0, xc, yc,  data->iEdgedWidth/2, data->rounding);
685  {          transfer_8to16subro(in, ptr, data->CurU, data->iEdgedWidth/2);
686  /* Do a diamond search around given starting point, return SAD of best */          bits += Block_CalcBits(coeff, in, data->iQuant, data->quant_type, &cbp, 4, 0);
687            if (bits >= data->iMinSAD[0]) return;
688    
689          int32_t iSAD;          //chroma V
690            ptr = interpolate8x8_switch2(data->RefQ + 64, data->RefP[5], 0, 0, xc, yc,  data->iEdgedWidth/2, data->rounding);
691            transfer_8to16subro(in, ptr, data->CurV, data->iEdgedWidth/2);
692            bits += Block_CalcBits(coeff, in, data->iQuant, data->quant_type, &cbp, 5, 0);
693    
694          VECTOR backupMV;          bits += mcbpc_inter_tab[(MODE_INTER & 7) | ((cbp & 3) << 3)].len;
695    
696          currMV->x = start_x;          if (bits < data->iMinSAD[0]) {
697          currMV->y = start_y;                  data->iMinSAD[0] = bits;
698                    current[0].x = x; current[0].y = y;
699                    *dir = Direction;
700            }
701    
702  /* 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]) {
703                    data->iMinSAD[1] = data->temp[0] + t; current[1].x = x; current[1].y = y; }
704            if (data->temp[1] < data->iMinSAD[2]) {
705                    data->iMinSAD[2] = data->temp[1]; current[2].x = x; current[2].y = y; }
706            if (data->temp[2] < data->iMinSAD[3]) {
707                    data->iMinSAD[3] = data->temp[2]; current[3].x = x; current[3].y = y; }
708            if (data->temp[3] < data->iMinSAD[4]) {
709                    data->iMinSAD[4] = data->temp[3]; current[4].x = x; current[4].y = y; }
710    
711          do  }
712    static void
713    CheckCandidateBits8(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
714          {          {
                 iFound = 1;  
715    
716                  backupMV = *currMV;          int16_t *in = data->dctSpace, *coeff = data->dctSpace + 64;
717            int32_t bits;
718            VECTOR * current;
719            const uint8_t * ptr;
720            int cbp = 0;
721    
722                  CHECK_MV16_DIRECT_FOUND(backupMV.x - iDiamondSize, backupMV.y);          if ( (x > data->max_dx) || (x < data->min_dx)
723                  CHECK_MV16_DIRECT_FOUND(backupMV.x + iDiamondSize, backupMV.y);                  || (y > data->max_dy) || (y < data->min_dy) ) return;
                 CHECK_MV16_DIRECT_FOUND(backupMV.x, backupMV.y - iDiamondSize);  
                 CHECK_MV16_DIRECT_FOUND(backupMV.x, backupMV.y + iDiamondSize);  
724    
725          } while (!iFound);          if (!data->qpel_precision) {
726                    ptr = GetReference(x, y, data);
727                    current = data->currentMV;
728            } else { // x and y are in 1/4 precision
729                    ptr = Interpolate8x8qpel(x, y, 0, 0, data);
730                    current = data->currentQMV;
731            }
732    
733            transfer_8to16subro(in, data->Cur, ptr, data->iEdgedWidth);
734            bits = Block_CalcBits(coeff, in, data->iQuant, data->quant_type, &cbp, 5, 0);
735            bits += d_mv_bits(x, y, data->predMV, data->iFcode, data->qpel^data->qpel_precision, 0);
736    
737          return iMinSAD;          if (bits < data->iMinSAD[0]) {
738                    data->temp[0] = cbp;
739                    data->iMinSAD[0] = bits;
740                    current[0].x = x; current[0].y = y;
741                    *dir = Direction;
742            }
743  }  }
744    
745    /* CHECK_CANDIATE FUNCTIONS END */
746    
747  int32_t  /* MAINSEARCH FUNCTIONS START */
 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)  
 {  
748    
749          int32_t iSAD;  static void
750    AdvDiamondSearch(int x, int y, const SearchData * const data, int bDirection)
751    {
752    
753  /* directions: 1 - left (x-1); 2 - right (x+1), 4 - up (y-1); 8 - down (y+1) */  /* directions: 1 - left (x-1); 2 - right (x+1), 4 - up (y-1); 8 - down (y+1) */
754    
755          if (iDirection) {          int iDirection;
                 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;  
756    
757                  do {          for(;;) { //forever
758                          iDirection = 0;                          iDirection = 0;
759                          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)                  if (bDirection & 1) CHECK_CANDIDATE(x - iDiamondSize, y, 1);
760                                  CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize, start_y, 1);                  if (bDirection & 2) CHECK_CANDIDATE(x + iDiamondSize, y, 2);
761                    if (bDirection & 4) CHECK_CANDIDATE(x, y - iDiamondSize, 4);
762                          if (bDirection & 2)                  if (bDirection & 8) CHECK_CANDIDATE(x, y + iDiamondSize, 8);
                                 CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize, start_y, 2);  
   
                         if (bDirection & 4)  
                                 CHECK_MV8_CANDIDATE_DIR(start_x, start_y - iDiamondSize, 4);  
   
                         if (bDirection & 8)  
                                 CHECK_MV8_CANDIDATE_DIR(start_x, start_y + iDiamondSize, 8);  
763    
764                          /* now we're doing diagonal checks near our candidate */                          /* now we're doing diagonal checks near our candidate */
765    
766                          if (iDirection)         //checking if anything found                  if (iDirection) {               //if anything found
                         {  
767                                  bDirection = iDirection;                                  bDirection = iDirection;
768                                  iDirection = 0;                                  iDirection = 0;
769                                  start_x = currMV->x;                          x = data->currentMV->x; y = data->currentMV->y;
770                                  start_y = currMV->y;                          if (bDirection & 3) {   //our candidate is left or right
771                                  if (bDirection & 3)     //our candidate is left or right                                  CHECK_CANDIDATE(x, y + iDiamondSize, 8);
772                                  {                                  CHECK_CANDIDATE(x, y - iDiamondSize, 4);
773                                          CHECK_MV8_CANDIDATE_DIR(start_x, start_y + iDiamondSize, 8);                          } else {                        // what remains here is up or down
774                                          CHECK_MV8_CANDIDATE_DIR(start_x, start_y - iDiamondSize, 4);                                  CHECK_CANDIDATE(x + iDiamondSize, y, 2);
775                                  } 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);  
776                                  }                                  }
777    
778                                  if (iDirection) {                                  if (iDirection) {
779                                          bDirection += iDirection;                                          bDirection += iDirection;
780                                          start_x = currMV->x;                                  x = data->currentMV->x; y = data->currentMV->y;
                                         start_y = currMV->y;  
781                                  }                                  }
782                          } else                          //about to quit, eh? not so fast....                  } else {                                //about to quit, eh? not so fast....
                         {  
783                                  switch (bDirection) {                                  switch (bDirection) {
784                                  case 2:                                  case 2:
785                                          CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,                                  CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
786                                                                                          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);  
787                                          break;                                          break;
788                                  case 1:                                  case 1:
789                                          CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,                                  CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
790                                                                                          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);  
791                                          break;                                          break;
792                                  case 2 + 4:                                  case 2 + 4:
793                                          CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,                                  CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
794                                                                                          start_y - iDiamondSize, 1 + 4);                                  CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
795                                          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);  
796                                          break;                                          break;
797                                  case 4:                                  case 4:
798                                          CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,                                  CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
799                                                                                          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);  
800                                          break;                                          break;
801                                  case 8:                                  case 8:
802                                          CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,                                  CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
803                                                                                          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);  
804                                          break;                                          break;
805                                  case 1 + 4:                                  case 1 + 4:
806                                          CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,                                  CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
807                                                                                          start_y + iDiamondSize, 1 + 8);                                  CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
808                                          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);  
809                                          break;                                          break;
810                                  case 2 + 8:                                  case 2 + 8:
811                                          CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,                                  CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
812                                                                                          start_y - iDiamondSize, 1 + 4);                                  CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
813                                          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);  
814                                          break;                                          break;
815                                  case 1 + 8:                                  case 1 + 8:
816                                          CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,                                  CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
817                                                                                          start_y - iDiamondSize, 2 + 4);                                  CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
818                                          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);  
819                                          break;                                          break;
820                                  default:                //1+2+4+8 == we didn't find anything at all                                  default:                //1+2+4+8 == we didn't find anything at all
821                                          CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,                                  CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
822                                                                                          start_y - iDiamondSize, 1 + 4);                                  CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
823                                          CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,                                  CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
824                                                                                          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);  
825                                          break;                                          break;
826                                  }                                  }
827                                  if (!(iDirection))                          if (!iDirection) break;         //ok, the end. really
                                         break;          //ok, the end. really  
                                 else {  
828                                          bDirection = iDirection;                                          bDirection = iDirection;
829                                          start_x = currMV->x;                          x = data->currentMV->x; y = data->currentMV->y;
                                         start_y = currMV->y;  
830                                  }                                  }
831                          }                          }
832                  }                  }
                 while (1);                              //forever  
         }  
         return iMinSAD;  
 }  
833    
834    static void
835    SquareSearch(int x, int y, const SearchData * const data, int bDirection)
836    {
837            int iDirection;
838    
839  int32_t          do {
840  Full8_MainSearch(const uint8_t * const pRef,                  iDirection = 0;
841                                   const uint8_t * const pRefH,                  if (bDirection & 1) CHECK_CANDIDATE(x - iDiamondSize, y, 1+16+64);
842                                   const uint8_t * const pRefV,                  if (bDirection & 2) CHECK_CANDIDATE(x + iDiamondSize, y, 2+32+128);
843                                   const uint8_t * const pRefHV,                  if (bDirection & 4) CHECK_CANDIDATE(x, y - iDiamondSize, 4+16+32);
844                                   const uint8_t * const cur,                  if (bDirection & 8) CHECK_CANDIDATE(x, y + iDiamondSize, 8+64+128);
845                                   const int x,                  if (bDirection & 16) CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1+4+16+32+64);
846                                   const int y,                  if (bDirection & 32) CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2+4+16+32+128);
847                             const int start_x,                  if (bDirection & 64) CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1+8+16+64+128);
848                             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);  
849    
850          return iMinSAD;                  bDirection = iDirection;
851                    x = data->currentMV->x; y = data->currentMV->y;
852            } while (iDirection);
853  }  }
854    
855  Halfpel8_RefineFuncPtr Halfpel8_Refine;  static void
856    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)  
857  {  {
 /* Do a half-pel refinement (or rather a "smallest possible amount" refinement) */  
   
         int32_t iSAD;  
         VECTOR backupMV = *currMV;  
858    
859          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);  
   
         return iMinSAD;  
 }  
860    
861  #define PMV_HALFPEL16 (PMV_HALFPELDIAMOND16|PMV_HALFPELREFINE16)          int iDirection;
862    
863            do {
864                    iDirection = 0;
865                    if (bDirection & 1) CHECK_CANDIDATE(x - iDiamondSize, y, 1);
866                    if (bDirection & 2) CHECK_CANDIDATE(x + iDiamondSize, y, 2);
867                    if (bDirection & 4) CHECK_CANDIDATE(x, y - iDiamondSize, 4);
868                    if (bDirection & 8) CHECK_CANDIDATE(x, y + iDiamondSize, 8);
869    
870                    /* now we're doing diagonal checks near our candidate */
871    
872  int32_t                  if (iDirection) {               //checking if anything found
873  PMVfastSearch16(const uint8_t * const pRef,                          bDirection = iDirection;
874                                  const uint8_t * const pRefH,                          iDirection = 0;
875                                  const uint8_t * const pRefV,                          x = data->currentMV->x; y = data->currentMV->y;
876                                  const uint8_t * const pRefHV,                          if (bDirection & 3) {   //our candidate is left or right
877                                  const IMAGE * const pCur,                                  CHECK_CANDIDATE(x, y + iDiamondSize, 8);
878                                  const int x,                                  CHECK_CANDIDATE(x, y - iDiamondSize, 4);
879                                  const int y,                          } else {                        // what remains here is up or down
880                                  const int start_x,      /* start is searched first, so it should contain the most */                                  CHECK_CANDIDATE(x + iDiamondSize, y, 2);
881                                  const int start_y,  /* likely motion vector for this block */                                  CHECK_CANDIDATE(x - iDiamondSize, y, 1);
                                 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);  
882          }          }
883                            bDirection += iDirection;
884          /* because we might use something like IF (dx>max_dx) THEN dx=max_dx; */                          x = data->currentMV->x; y = data->currentMV->y;
885          //bPredEq = get_pmvdata(pMBs, x, y, iWcount, 0, pmv, psad);                  }
886          bPredEq = get_pmvdata2(pMBs, iWcount, 0, x, y, 0, pmv, psad);          }
887            while (iDirection);
         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;  
888          }          }
889    
890          iFound = 0;  /* MAINSEARCH FUNCTIONS END */
   
 /* 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;  
891    
892          if (!(MotionFlags & PMV_HALFPEL16)) {   /* This should NOT be necessary! */  static void
893                  currMV->x = EVEN(currMV->x);  SubpelRefine(const SearchData * const data)
894                  currMV->y = EVEN(currMV->y);  {
895          }  /* Do a half-pel or q-pel refinement */
896            const VECTOR centerMV = data->qpel_precision ? *data->currentQMV : *data->currentMV;
897            int iDirection; //only needed because macro expects it
898    
899          if (currMV->x > max_dx) {          CHECK_CANDIDATE(centerMV.x, centerMV.y - 1, 0);
900                  currMV->x = max_dx;          CHECK_CANDIDATE(centerMV.x + 1, centerMV.y - 1, 0);
901          }          CHECK_CANDIDATE(centerMV.x + 1, centerMV.y, 0);
902          if (currMV->x < min_dx) {          CHECK_CANDIDATE(centerMV.x + 1, centerMV.y + 1, 0);
903                  currMV->x = min_dx;          CHECK_CANDIDATE(centerMV.x, centerMV.y + 1, 0);
904          }          CHECK_CANDIDATE(centerMV.x - 1, centerMV.y + 1, 0);
905          if (currMV->y > max_dy) {          CHECK_CANDIDATE(centerMV.x - 1, centerMV.y, 0);
906                  currMV->y = max_dy;          CHECK_CANDIDATE(centerMV.x - 1, centerMV.y - 1, 0);
         }  
         if (currMV->y < min_dy) {  
                 currMV->y = min_dy;  
907          }          }
908    
909          iMinSAD =  static __inline int
910                  sad16(cur,  SkipDecisionP(const IMAGE * current, const IMAGE * reference,
911                            get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 16, currMV,                                                          const int x, const int y,
912                                                   iEdgedWidth), iEdgedWidth, MV_MAX_ERROR);                                                          const uint32_t stride, const uint32_t iQuant, int rrv)
         iMinSAD +=  
                 calc_delta_16(currMV->x - center_x, currMV->y - center_y,  
                                           (uint8_t) iFcode, iQuant);  
913    
         if ((iMinSAD < 256) ||  
                 ((MVequal(*currMV, prevMB->mvs[0])) &&  
                  ((int32_t) iMinSAD < prevMB->sad16))) {  
                 if (iMinSAD < 2 * iQuant)       // high chances for SKIP-mode  
914                  {                  {
915                          if (!MVzero(*currMV)) {          int offset = (x + y*stride)*8;
916                                  iMinSAD += MV16_00_BIAS;          if(!rrv) {
917                                  CHECK_MV16_ZERO;        // (0,0) saves space for letterboxed pictures                  uint32_t sadC = sad8(current->u + offset,
918                                  iMinSAD -= MV16_00_BIAS;                                                  reference->u + offset, stride);
919                    if (sadC > iQuant * MAX_CHROMA_SAD_FOR_SKIP) return 0;
920                    sadC += sad8(current->v + offset,
921                                                    reference->v + offset, stride);
922                    if (sadC > iQuant * MAX_CHROMA_SAD_FOR_SKIP) return 0;
923                    return 1;
924    
925            } else {
926                    uint32_t sadC = sad16(current->u + 2*offset,
927                                                    reference->u + 2*offset, stride, 256*4096);
928                    if (sadC > iQuant * MAX_CHROMA_SAD_FOR_SKIP*4) return 0;
929                    sadC += sad16(current->v + 2*offset,
930                                                    reference->v + 2*offset, stride, 256*4096);
931                    if (sadC > iQuant * MAX_CHROMA_SAD_FOR_SKIP*4) return 0;
932                    return 1;
933                          }                          }
934                  }                  }
935    
936                  if (MotionFlags & PMV_QUICKSTOP16)  static __inline void
937                          goto PMVfast16_Terminate_without_Refine;  SkipMacroblockP(MACROBLOCK *pMB, const int32_t sad)
938                  if (MotionFlags & PMV_EARLYSTOP16)  {
939                          goto PMVfast16_Terminate_with_Refine;          pMB->mode = MODE_NOT_CODED;
940            pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = zeroMV;
941            pMB->qmvs[0] = pMB->qmvs[1] = pMB->qmvs[2] = pMB->qmvs[3] = zeroMV;
942            pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] = pMB->sad8[3] = sad;
943          }          }
944    
945    static __inline void
946    ModeDecision(SearchData * const Data,
947                            MACROBLOCK * const pMB,
948                            const MACROBLOCK * const pMBs,
949                            const int x, const int y,
950                            const MBParam * const pParam,
951                            const uint32_t MotionFlags,
952                            const uint32_t VopFlags,
953                            const uint32_t VolFlags,
954                            const IMAGE * const pCurrent,
955                            const IMAGE * const pRef)
956    {
957            int mode = MODE_INTER;
958            int inter4v = (VopFlags & XVID_VOP_INTER4V) && (pMB->dquant == 0);
959            const uint32_t iQuant = pMB->quant;
960    
961            const int skip_possible = (!(VolFlags & XVID_VOL_GMC)) && (pMB->dquant == 0);
962    
963            if (!(VopFlags & XVID_VOP_MODEDECISION_BITS)) { //normal, fast, SAD-based mode decision
964                    int sad;
965                    int InterBias = MV16_INTER_BIAS;
966                    if (inter4v == 0 || Data->iMinSAD[0] < Data->iMinSAD[1] + Data->iMinSAD[2] +
967                            Data->iMinSAD[3] + Data->iMinSAD[4] + IMV16X16 * (int32_t)iQuant) {
968                            mode = MODE_INTER;
969                            sad = Data->iMinSAD[0];
970                    } else {
971                            mode = MODE_INTER4V;
972                            sad = Data->iMinSAD[1] + Data->iMinSAD[2] +
973                                                    Data->iMinSAD[3] + Data->iMinSAD[4] + IMV16X16 * (int32_t)iQuant;
974                            Data->iMinSAD[0] = sad;
975                    }
976    
977  /* Step 2 (lazy eval): Calculate Distance= |MedianMVX| + |MedianMVY| where MedianMV is the motion                  /* final skip decision, a.k.a. "the vector you found, really that good?" */
978     vector of the median.                  if (skip_possible && (pMB->sad16 < (int)iQuant * MAX_SAD00_FOR_SKIP))
979     If PredEq=1 and MVpredicted = Previous Frame MV, set Found=2                          if ( (100*sad)/(pMB->sad16+1) > FINAL_SKIP_THRESH)
980  */                                  if (Data->chroma || SkipDecisionP(pCurrent, pRef, x, y, Data->iEdgedWidth/2, iQuant, Data->rrv)) {
981                                            mode = MODE_NOT_CODED;
982          if ((bPredEq) && (MVequal(pmv[0], prevMB->mvs[0])))                                          sad = 0;
983                  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) || (bPredEq))  
                 iDiamondSize = 1;               // halfpel!  
         else  
                 iDiamondSize = 2;               // halfpel!  
984    
985          if (!(MotionFlags & PMV_HALFPELDIAMOND16))                  /* intra decision */
                 iDiamondSize *= 2;  
986    
987  /*                  if (iQuant > 8) InterBias += 100 * (iQuant - 8); // to make high quants work
988     Step 5: Calculate SAD for motion vectors taken from left block, top, top-right, and Previous frame block.                  if (y != 0)
989     Also calculate (0,0) but do not subtract offset.                          if ((pMB - pParam->mb_width)->mode == MODE_INTRA ) InterBias -= 80;
990     Let MinSAD be the smallest SAD up to this point.                  if (x != 0)
991     If MV is (0,0) subtract offset.                          if ((pMB - 1)->mode == MODE_INTRA ) InterBias -= 80;
 */  
992    
993  // (0,0) is always possible                  if (Data->chroma) InterBias += 50; // dev8(chroma) ???
994                    if (Data->rrv) InterBias *= 4;
995    
996          if (!MVzero(pmv[0]))                  if (InterBias < pMB->sad16) {
997                  CHECK_MV16_ZERO;                          int32_t deviation;
998                            if (!Data->rrv) deviation = dev16(Data->Cur, Data->iEdgedWidth);
999                            else deviation = dev16(Data->Cur, Data->iEdgedWidth) +
1000                                    dev16(Data->Cur+16, Data->iEdgedWidth) +
1001                                    dev16(Data->Cur + 16*Data->iEdgedWidth, Data->iEdgedWidth) +
1002                                    dev16(Data->Cur+16+16*Data->iEdgedWidth, Data->iEdgedWidth);
1003    
1004  // previous frame MV is always possible                          if (deviation < (sad - InterBias)) mode = MODE_INTRA;
1005                    }
1006    
1007          if (!MVzero(prevMB->mvs[0]))          } else { // BITS
                 if (!MVequal(prevMB->mvs[0], pmv[0]))  
                         CHECK_MV16_CANDIDATE(prevMB->mvs[0].x, prevMB->mvs[0].y);  
1008    
1009  // left neighbour, if allowed                  int bits, intra, i;
1010                    VECTOR backup[5], *v;
1011                    Data->iQuant = iQuant;
1012    
1013          if (!MVzero(pmv[1]))                  v = Data->qpel ? Data->currentQMV : Data->currentMV;
1014                  if (!MVequal(pmv[1], prevMB->mvs[0]))                  for (i = 0; i < 5; i++) {
1015                          if (!MVequal(pmv[1], pmv[0])) {                          Data->iMinSAD[i] = 256*4096;
1016                                  if (!(MotionFlags & PMV_HALFPEL16)) {                          backup[i] = v[i];
                                         pmv[1].x = EVEN(pmv[1].x);  
                                         pmv[1].y = EVEN(pmv[1].y);  
1017                                  }                                  }
1018    
1019                                  CHECK_MV16_CANDIDATE(pmv[1].x, pmv[1].y);                  bits = CountMBBitsInter(Data, pMBs, x, y, pParam, MotionFlags);
1020                          }                  if (bits == 0)
1021  // top neighbour, if allowed                          mode = MODE_INTER; // quick stop
1022          if (!MVzero(pmv[2]))                  else {
1023                  if (!MVequal(pmv[2], prevMB->mvs[0]))                          if (inter4v) {
1024                          if (!MVequal(pmv[2], pmv[0]))                                  int bits_inter4v = CountMBBitsInter4v(Data, pMB, pMBs, x, y, pParam, MotionFlags, backup);
1025                                  if (!MVequal(pmv[2], pmv[1])) {                                  if (bits_inter4v < bits) { Data->iMinSAD[0] = bits = bits_inter4v; mode = MODE_INTER4V; }
                                         if (!(MotionFlags & PMV_HALFPEL16)) {  
                                                 pmv[2].x = EVEN(pmv[2].x);  
                                                 pmv[2].y = EVEN(pmv[2].y);  
1026                                          }                                          }
                                         CHECK_MV16_CANDIDATE(pmv[2].x, pmv[2].y);  
1027    
1028  // top right neighbour, if allowed                          intra = CountMBBitsIntra(Data);
1029                                          if (!MVzero(pmv[3]))  
1030                                                  if (!MVequal(pmv[3], prevMB->mvs[0]))                          if (intra < bits) { *Data->iMinSAD = bits = intra; mode = MODE_INTRA; }
                                                         if (!MVequal(pmv[3], pmv[0]))  
                                                                 if (!MVequal(pmv[3], pmv[1]))  
                                                                         if (!MVequal(pmv[3], pmv[2])) {  
                                                                                 if (!(MotionFlags & PMV_HALFPEL16)) {  
                                                                                         pmv[3].x = EVEN(pmv[3].x);  
                                                                                         pmv[3].y = EVEN(pmv[3].y);  
                                                                                 }  
                                                                                 CHECK_MV16_CANDIDATE(pmv[3].x,  
                                                                                                                          pmv[3].y);  
1031                                                                          }                                                                          }
1032                                  }                                  }
1033    
1034          if ((MVzero(*currMV)) &&          if (Data->rrv) {
1035                  (!MVzero(pmv[0])) /* && (iMinSAD <= iQuant * 96) */ )                          Data->currentMV[0].x = RRV_MV_SCALEDOWN(Data->currentMV[0].x);
1036                  iMinSAD -= MV16_00_BIAS;                          Data->currentMV[0].y = RRV_MV_SCALEDOWN(Data->currentMV[0].y);
   
   
 /* 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;  
1037          }          }
1038    
1039            if (mode == MODE_INTER) {
1040                    pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = Data->currentMV[0];
1041                    pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] = pMB->sad8[3] = Data->iMinSAD[0];
1042    
1043  /************ (Diamond Search)  **************/                  if(Data->qpel) {
1044  /*                          pMB->qmvs[0] = pMB->qmvs[1]
1045     Step 7: Perform Diamond search, with either the small or large diamond.                                  = pMB->qmvs[2] = pMB->qmvs[3] = Data->currentQMV[0];
1046     If Found=2 only examine one Diamond pattern, and afterwards goto step 10                          pMB->pmvs[0].x = Data->currentQMV[0].x - Data->predMV.x;
1047     Step 8: If small diamond, iterate small diamond search pattern until motion vector lies in the center of the diamond.                          pMB->pmvs[0].y = Data->currentQMV[0].y - Data->predMV.y;
1048     If center then goto step 10.                  } else {
1049     Step 9: If large diamond, iterate large diamond search pattern until motion vector lies in the center.                          pMB->pmvs[0].x = Data->currentMV[0].x - Data->predMV.x;
1050     Refine by using small diamond and goto step 10.                          pMB->pmvs[0].y = Data->currentMV[0].y - Data->predMV.y;
 */  
   
         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;  
1051          }          }
1052    
1053          if (MotionFlags & PMV_EXTSEARCH16) {          } else if (mode == MODE_INTER4V)
1054  /* extended: search (up to) two more times: orignal prediction and (0,0) */                  pMB->sad16 = Data->iMinSAD[0];
1055            else // INTRA, NOT_CODED
1056                    SkipMacroblockP(pMB, 0);
1057    
1058                  if (!(MVequal(pmv[0], backupMV))) {          pMB->mode = mode;
                         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;  
                         }  
1059                  }                  }
1060    
1061                  if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {  bool
1062                          iSAD =  MotionEstimation(MBParam * const pParam,
1063                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, 0, 0,                                   FRAMEINFO * const current,
1064                                                                    iMinSAD, &newMV, center_x, center_y,                                   FRAMEINFO * const reference,
1065                                                                    min_dx, max_dx, min_dy, max_dy,                                   const IMAGE * const pRefH,
1066                                                                    iEdgedWidth, iDiamondSize, iFcode,                                   const IMAGE * const pRefV,
1067                                                                    iQuant, iFound);                                   const IMAGE * const pRefHV,
1068                                     const uint32_t iLimit)
1069    {
1070            MACROBLOCK *const pMBs = current->mbs;
1071            const IMAGE *const pCurrent = &current->image;
1072            const IMAGE *const pRef = &reference->image;
1073    
1074                          if (iSAD < iMinSAD) {          uint32_t mb_width = pParam->mb_width;
1075                                  *currMV = newMV;          uint32_t mb_height = pParam->mb_height;
1076                                  iMinSAD = iSAD;          const uint32_t iEdgedWidth = pParam->edged_width;
1077                          }          const uint32_t MotionFlags = MakeGoodMotionFlags(current->motion_flags, current->vop_flags, current->vol_flags);
1078    
1079            uint32_t x, y;
1080            uint32_t iIntra = 0;
1081            int32_t quant = current->quant, sad00;
1082            int skip_thresh = \
1083                    INITIAL_SKIP_THRESH * \
1084                    (current->vop_flags & XVID_VOP_REDUCED ? 4:1) * \
1085                    (current->vop_flags & XVID_VOP_MODEDECISION_BITS ? 2:1);
1086    
1087            // some pre-initialized thingies for SearchP
1088            int32_t temp[8];
1089            VECTOR currentMV[5];
1090            VECTOR currentQMV[5];
1091            int32_t iMinSAD[5];
1092            DECLARE_ALIGNED_MATRIX(dct_space, 2, 64, int16_t, CACHE_LINE);
1093            SearchData Data;
1094            memset(&Data, 0, sizeof(SearchData));
1095            Data.iEdgedWidth = iEdgedWidth;
1096            Data.currentMV = currentMV;
1097            Data.currentQMV = currentQMV;
1098            Data.iMinSAD = iMinSAD;
1099            Data.temp = temp;
1100            Data.iFcode = current->fcode;
1101            Data.rounding = pParam->m_rounding_type;
1102            Data.qpel = (current->vol_flags & XVID_VOL_QUARTERPEL ? 1:0);
1103            Data.chroma = MotionFlags & XVID_ME_CHROMA16;
1104            Data.rrv = (current->vop_flags & XVID_VOP_REDUCED ? 1:0);
1105            Data.dctSpace = dct_space;
1106            Data.quant_type = !(pParam->vol_flags & XVID_VOL_MPEGQUANT);
1107    
1108            if ((current->vop_flags & XVID_VOP_REDUCED)) {
1109                    mb_width = (pParam->width + 31) / 32;
1110                    mb_height = (pParam->height + 31) / 32;
1111                    Data.qpel = 0;
1112            }
1113    
1114            Data.RefQ = pRefV->u; // a good place, also used in MC (for similar purpose)
1115            if (sadInit) (*sadInit) ();
1116    
1117            for (y = 0; y < mb_height; y++) {
1118                    for (x = 0; x < mb_width; x++)  {
1119                            MACROBLOCK *pMB = &pMBs[x + y * pParam->mb_width];
1120    
1121                            if (!Data.rrv) pMB->sad16 =
1122                                    sad16v(pCurrent->y + (x + y * iEdgedWidth) * 16,
1123                                                            pRef->y + (x + y * iEdgedWidth) * 16,
1124                                                            pParam->edged_width, pMB->sad8 );
1125    
1126                            else pMB->sad16 =
1127                                    sad32v_c(pCurrent->y + (x + y * iEdgedWidth) * 32,
1128                                                            pRef->y + (x + y * iEdgedWidth) * 32,
1129                                                            pParam->edged_width, pMB->sad8 );
1130    
1131                            if (Data.chroma) {
1132                                    Data.temp[7] = sad8(pCurrent->u + x*8 + y*(iEdgedWidth/2)*8,
1133                                                                            pRef->u + x*8 + y*(iEdgedWidth/2)*8, iEdgedWidth/2)
1134                                                                    + sad8(pCurrent->v + (x + y*(iEdgedWidth/2))*8,
1135                                                                            pRef->v + (x + y*(iEdgedWidth/2))*8, iEdgedWidth/2);
1136                                    pMB->sad16 += Data.temp[7];
1137                            }
1138    
1139                            sad00 = pMB->sad16;
1140    
1141                            if (pMB->dquant != 0) {
1142                                    quant += DQtab[pMB->dquant];
1143                                    if (quant > 31) quant = 31;
1144                                    else if (quant < 1) quant = 1;
1145                            }
1146                            pMB->quant = quant;
1147    
1148    //initial skip decision
1149    /* no early skip for GMC (global vector = skip vector is unknown!)  */
1150                            if (!(current->vol_flags & XVID_VOL_GMC))       { /* no fast SKIP for S(GMC)-VOPs */
1151                                    if (pMB->dquant == 0 && sad00 < pMB->quant * skip_thresh)
1152                                            if (Data.chroma || SkipDecisionP(pCurrent, pRef, x, y, iEdgedWidth/2, pMB->quant, Data.rrv)) {
1153                                                    SkipMacroblockP(pMB, sad00);
1154                                                    continue;
1155                  }                  }
1156          }          }
1157    
1158  /*                          SearchP(pRef, pRefH->y, pRefV->y, pRefHV->y, pCurrent, x,
1159     Step 10:  The motion vector is chosen according to the block corresponding to MinSAD.                                          y, MotionFlags, current->vop_flags, current->vol_flags,
1160  */                                          &Data, pParam, pMBs, reference->mbs, pMB);
1161    
1162    PMVfast16_Terminate_with_Refine:                          ModeDecision(&Data, pMB, pMBs, x, y, pParam,
1163          if (MotionFlags & PMV_HALFPELREFINE16)  // perform final half-pel step                                                   MotionFlags, current->vop_flags, current->vol_flags,
1164                  iMinSAD =                                                   pCurrent, pRef);
                         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);  
1165    
1166    PMVfast16_Terminate_without_Refine:                          if (pMB->mode == MODE_INTRA)
1167          currPMV->x = currMV->x - center_x;                                  if (++iIntra > iLimit) return 1;
1168          currPMV->y = currMV->y - center_y;                  }
         return iMinSAD;  
1169  }  }
1170    
1171            if (current->vol_flags & XVID_VOL_GMC ) /* GMC only for S(GMC)-VOPs */
1172            {
1173                    current->warp = GlobalMotionEst( pMBs, pParam, current, reference, pRefH, pRefV, pRefHV);
1174            }
1175            return 0;
1176    }
1177    
1178    
1179    static __inline int
1180    make_mask(const VECTOR * const pmv, const int i)
1181    {
1182  int32_t          int mask = 255, j;
1183  Diamond8_MainSearch(const uint8_t * const pRef,          for (j = 0; j < i; j++) {
1184                                          const uint8_t * const pRefH,                  if (MVequal(pmv[i], pmv[j])) return 0; // same vector has been checked already
1185                                          const uint8_t * const pRefV,                  if (pmv[i].x == pmv[j].x) {
1186                                          const uint8_t * const pRefHV,                          if (pmv[i].y == pmv[j].y + iDiamondSize) mask &= ~4;
1187                                          const uint8_t * const cur,                          else if (pmv[i].y == pmv[j].y - iDiamondSize) mask &= ~8;
1188                                          const int x,                  } else
1189                                          const int y,                          if (pmv[i].y == pmv[j].y) {
1190                                          int32_t start_x,                                  if (pmv[i].x == pmv[j].x + iDiamondSize) mask &= ~1;
1191                                          int32_t start_y,                                  else if (pmv[i].x == pmv[j].x - iDiamondSize) mask &= ~2;
                                         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);  
   
         if (iDirection) {  
                 while (!iFound) {  
                         iFound = 1;  
                         backupMV = *currMV;     // since iDirection!=0, this is well defined!  
                         iDirectionBackup = iDirection;  
   
                         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);  
1192                  }                  }
         } else {  
                 currMV->x = start_x;  
                 currMV->y = start_y;  
1193          }          }
1194          return iMinSAD;          return mask;
1195  }  }
1196    
1197    static __inline void
1198    PreparePredictionsP(VECTOR * const pmv, int x, int y, int iWcount,
1199                            int iHcount, const MACROBLOCK * const prevMB, int rrv)
1200    {
1201    
1202    //this function depends on get_pmvdata which means that it sucks. It should get the predictions by itself
1203            if (rrv) { iWcount /= 2; iHcount /= 2; }
1204    
1205            if ( (y != 0) && (x < (iWcount-1)) ) {          // [5] top-right neighbour
1206                    pmv[5].x = EVEN(pmv[3].x);
1207                    pmv[5].y = EVEN(pmv[3].y);
1208            } else pmv[5].x = pmv[5].y = 0;
1209    
1210  int32_t          if (x != 0) { pmv[3].x = EVEN(pmv[1].x); pmv[3].y = EVEN(pmv[1].y); }// pmv[3] is left neighbour
1211  Square8_MainSearch(const uint8_t * const pRef,          else pmv[3].x = pmv[3].y = 0;
                                         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  
 */  
1212    
1213          CHECK_MV8_CANDIDATE_DIR(backupMV.x - iDiamondSize, backupMV.y, 1);          if (y != 0) { pmv[4].x = EVEN(pmv[2].x); pmv[4].y = EVEN(pmv[2].y); }// [4] top neighbour
1214          CHECK_MV8_CANDIDATE_DIR(backupMV.x + iDiamondSize, backupMV.y, 2);          else pmv[4].x = pmv[4].y = 0;
         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);  
1215    
1216            // [1] median prediction
1217            pmv[1].x = EVEN(pmv[0].x); pmv[1].y = EVEN(pmv[0].y);
1218    
1219          if (iDirection) {          pmv[0].x = pmv[0].y = 0; // [0] is zero; not used in the loop (checked before) but needed here for make_mask
                 while (!iFound) {  
                         iFound = 1;  
                         backupMV = *currMV;  
1220    
1221                          switch (iDirection) {          pmv[2].x = EVEN(prevMB->mvs[0].x); // [2] is last frame
1222                          case 1:          pmv[2].y = EVEN(prevMB->mvs[0].y);
                                 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;  
1223    
1224                          case 3:          if ((x < iWcount-1) && (y < iHcount-1)) {
1225                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,                  pmv[6].x = EVEN((prevMB+1+iWcount)->mvs[0].x); //[6] right-down neighbour in last frame
1226                                                                                   4);                  pmv[6].y = EVEN((prevMB+1+iWcount)->mvs[0].y);
1227                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,          } else pmv[6].x = pmv[6].y = 0;
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
                                 break;  
1228    
1229                          case 4:          if (rrv) {
1230                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize,                  int i;
1231                                                                                   3);                  for (i = 0; i < 7; i++) {
1232                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,                          pmv[i].x = RRV_MV_SCALEUP(pmv[i].x);
1233                                                                                   backupMV.y - iDiamondSize, 5);                          pmv[i].y = RRV_MV_SCALEUP(pmv[i].y);
                                 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);  
   
                                 break;  
   
                         case 7:  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                    backupMV.y, 1);  
                                 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, 7);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
                                 break;  
   
                         case 8:  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y,  
                                                                                  2);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,  
                                                                                  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;  
                         }  
1234                  }                  }
         } else {  
                 currMV->x = start_x;  
                 currMV->y = start_y;  
1235          }          }
         return iMinSAD;  
1236  }  }
1237    
1238    static void
1239    SearchP(const IMAGE * const pRef,
   
   
 int32_t  
 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);  
   
         return iMinSAD;  
 }  
   
   
 #define PMV_HALFPEL8 (PMV_HALFPELDIAMOND8|PMV_HALFPELREFINE8)  
   
 int32_t  
 PMVfastSearch8(const uint8_t * const pRef,  
1240                             const uint8_t * const pRefH,                             const uint8_t * const pRefH,
1241                             const uint8_t * const pRefV,                             const uint8_t * const pRefV,
1242                             const uint8_t * const pRefHV,                             const uint8_t * const pRefHV,
1243                             const IMAGE * const pCur,                             const IMAGE * const pCur,
1244                             const int x,                             const int x,
1245                             const int y,                             const int y,
                            const int start_x,  
                            const int start_y,  
                                 const int center_x,  
                                 const int center_y,  
1246                             const uint32_t MotionFlags,                             const uint32_t MotionFlags,
1247                             const uint32_t iQuant,                  const uint32_t VopFlags,
1248                             const uint32_t iFcode,                  const uint32_t VolFlags,
1249                    SearchData * const Data,
1250                             const MBParam * const pParam,                             const MBParam * const pParam,
1251                             const MACROBLOCK * const pMBs,                             const MACROBLOCK * const pMBs,
1252                             const MACROBLOCK * const prevMBs,                             const MACROBLOCK * const prevMBs,
1253                             VECTOR * const currMV,                  MACROBLOCK * const pMB)
                            VECTOR * const currPMV)  
1254  {  {
         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;  
1255    
1256          const uint8_t *cur = pCur->y + x * 8 + y * 8 * iEdgedWidth;          int i, iDirection = 255, mask, threshA;
1257            VECTOR pmv[7];
1258          int32_t iDiamondSize;          int inter4v = (VopFlags & XVID_VOP_INTER4V) && (pMB->dquant == 0);
1259    
1260            get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
1261                                                    pParam->width, pParam->height, Data->iFcode - Data->qpel, 0, Data->rrv);
1262    
1263            get_pmvdata2(pMBs, pParam->mb_width, 0, x, y, 0, pmv, Data->temp);
1264    
1265            Data->temp[5] = Data->temp[6] = 0; // chroma-sad cache
1266            i = Data->rrv ? 2 : 1;
1267            Data->Cur = pCur->y + (x + y * Data->iEdgedWidth) * 16*i;
1268            Data->CurV = pCur->v + (x + y * (Data->iEdgedWidth/2)) * 8*i;
1269            Data->CurU = pCur->u + (x + y * (Data->iEdgedWidth/2)) * 8*i;
1270    
1271            Data->RefP[0] = pRef->y + (x + Data->iEdgedWidth*y) * 16*i;
1272            Data->RefP[2] = pRefH + (x + Data->iEdgedWidth*y) * 16*i;
1273            Data->RefP[1] = pRefV + (x + Data->iEdgedWidth*y) * 16*i;
1274            Data->RefP[3] = pRefHV + (x + Data->iEdgedWidth*y) * 16*i;
1275            Data->RefP[4] = pRef->u + (x + y * (Data->iEdgedWidth/2)) * 8*i;
1276            Data->RefP[5] = pRef->v + (x + y * (Data->iEdgedWidth/2)) * 8*i;
1277    
1278            Data->lambda16 = lambda_vec16[pMB->quant];
1279            Data->lambda8 = lambda_vec8[pMB->quant];
1280            Data->qpel_precision = 0;
1281    
1282            memset(Data->currentMV, 0, 5*sizeof(VECTOR));
1283    
1284            if (Data->qpel) Data->predMV = get_qpmv2(pMBs, pParam->mb_width, 0, x, y, 0);
1285            else Data->predMV = pmv[0];
1286    
1287            i = d_mv_bits(0, 0, Data->predMV, Data->iFcode, 0, 0);
1288            Data->iMinSAD[0] = pMB->sad16 + ((Data->lambda16 * i * pMB->sad16)>>10);
1289            Data->iMinSAD[1] = pMB->sad8[0] + ((Data->lambda8 * i * (pMB->sad8[0]+NEIGH_8X8_BIAS)) >> 10);
1290            Data->iMinSAD[2] = pMB->sad8[1];
1291            Data->iMinSAD[3] = pMB->sad8[2];
1292            Data->iMinSAD[4] = pMB->sad8[3];
1293    
1294            if ((!(VopFlags & XVID_VOP_MODEDECISION_BITS)) || (x | y)) {
1295                    threshA = Data->temp[0]; // that's where we keep this SAD atm
1296                    if (threshA < 512) threshA = 512;
1297                    else if (threshA > 1024) threshA = 1024;
1298            } else
1299                    threshA = 512;
1300    
1301          int32_t min_dx;          PreparePredictionsP(pmv, x, y, pParam->mb_width, pParam->mb_height,
1302          int32_t max_dx;                                          prevMBs + x + y * pParam->mb_width, Data->rrv);
         int32_t min_dy;  
         int32_t max_dy;  
1303    
1304          VECTOR pmv[4];          if (!Data->rrv) {
1305          int32_t psad[4];                  if (inter4v | Data->chroma) CheckCandidate = CheckCandidate16;
1306          VECTOR newMV;                          else CheckCandidate = CheckCandidate16no4v; //for extra speed
1307          VECTOR backupMV;          } else CheckCandidate = CheckCandidate32;
1308          VECTOR startMV;  
1309    /* main loop. checking all predictions (but first, which is 0,0 and has been checked in MotionEstimation())*/
1310    
1311            for (i = 1; i < 7; i++) {
1312                    if (!(mask = make_mask(pmv, i)) ) continue;
1313                    CheckCandidate(pmv[i].x, pmv[i].y, mask, &iDirection, Data);
1314                    if (Data->iMinSAD[0] <= threshA) break;
1315            }
1316    
1317            if ((Data->iMinSAD[0] <= threshA) ||
1318                            (MVequal(Data->currentMV[0], (prevMBs+x+y*pParam->mb_width)->mvs[0]) &&
1319                            (Data->iMinSAD[0] < (prevMBs+x+y*pParam->mb_width)->sad16)))
1320                    inter4v = 0;
1321            else {
1322    
1323  //  const MACROBLOCK * const pMB = pMBs + (x>>1) + (y>>1) * iWcount;                  MainSearchFunc * MainSearchPtr;
1324          const MACROBLOCK *const prevMB = prevMBs + (x >> 1) + (y >> 1) * iWcount;                  if (MotionFlags & XVID_ME_USESQUARES16) MainSearchPtr = SquareSearch;
1325                    else if (MotionFlags & XVID_ME_ADVANCEDDIAMOND16) MainSearchPtr = AdvDiamondSearch;
1326                            else MainSearchPtr = DiamondSearch;
1327    
1328           int32_t threshA, threshB;                  MainSearchPtr(Data->currentMV->x, Data->currentMV->y, Data, iDirection);
         int32_t iFound, bPredEq;  
         int32_t iMinSAD, iSAD;  
1329    
1330          int32_t iSubBlock = (y & 1) + (y & 1) + (x & 1);  /* extended search, diamond starting in 0,0 and in prediction.
1331            note that this search is/might be done in halfpel positions,
1332            which makes it more different than the diamond above */
1333    
1334          MainSearch8FuncPtr MainSearchPtr;                  if (MotionFlags & XVID_ME_EXTSEARCH16) {
1335                            int32_t bSAD;
1336                            VECTOR startMV = Data->predMV, backupMV = Data->currentMV[0];
1337                            if (Data->rrv) {
1338                                    startMV.x = RRV_MV_SCALEUP(startMV.x);
1339                                    startMV.y = RRV_MV_SCALEUP(startMV.y);
1340                            }
1341                            if (!(MVequal(startMV, backupMV))) {
1342                                    bSAD = Data->iMinSAD[0]; Data->iMinSAD[0] = MV_MAX_ERROR;
1343    
1344          /* Init variables */                                  CheckCandidate(startMV.x, startMV.y, 255, &iDirection, Data);
1345          startMV.x = start_x;                                  MainSearchPtr(startMV.x, startMV.y, Data, 255);
1346          startMV.y = start_y;                                  if (bSAD < Data->iMinSAD[0]) {
1347                                            Data->currentMV[0] = backupMV;
1348                                            Data->iMinSAD[0] = bSAD; }
1349                            }
1350    
1351          /* Get maximum range */                          backupMV = Data->currentMV[0];
1352          get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 8, iWidth, iHeight,                          startMV.x = startMV.y = 1;
1353                            iFcode);                          if (!(MVequal(startMV, backupMV))) {
1354                                    bSAD = Data->iMinSAD[0]; Data->iMinSAD[0] = MV_MAX_ERROR;
1355    
1356          if (!(MotionFlags & PMV_HALFPELDIAMOND8)) {                                  CheckCandidate(startMV.x, startMV.y, 255, &iDirection, Data);
1357                  min_dx = EVEN(min_dx);                                  MainSearchPtr(startMV.x, startMV.y, Data, 255);
1358                  max_dx = EVEN(max_dx);                                  if (bSAD < Data->iMinSAD[0]) {
1359                  min_dy = EVEN(min_dy);                                          Data->currentMV[0] = backupMV;
1360                  max_dy = EVEN(max_dy);                                          Data->iMinSAD[0] = bSAD; }
1361                            }
1362                    }
1363          }          }
1364    
1365          /* because we might use IF (dx>max_dx) THEN dx=max_dx; */          if (MotionFlags & XVID_ME_HALFPELREFINE16)
1366          //bPredEq = get_pmvdata(pMBs, (x >> 1), (y >> 1), iWcount, iSubBlock, pmv, psad);                          SubpelRefine(Data);
         bPredEq = get_pmvdata2(pMBs, iWcount, 0, (x >> 1), (y >> 1), iSubBlock, pmv, psad);  
1367    
1368          if ((x == 0) && (y == 0)) {          for(i = 0; i < 5; i++) {
1369                  threshA = 512 / 4;                  Data->currentQMV[i].x = 2 * Data->currentMV[i].x; // initialize qpel vectors
1370                  threshB = 1024 / 4;                  Data->currentQMV[i].y = 2 * Data->currentMV[i].y;
1371            }
1372    
1373          } else {          if (MotionFlags & XVID_ME_QUARTERPELREFINE16) {
                 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.  
 */  
1374    
1375                    get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
1376                                    pParam->width, pParam->height, Data->iFcode, 1, 0);
1377                    Data->qpel_precision = 1;
1378                    SubpelRefine(Data);
1379            }
1380    
1381  // Prepare for main loop          if ((!(VopFlags & XVID_VOP_MODEDECISION_BITS)) && (Data->iMinSAD[0] < (int32_t)pMB->quant * 30))
1382                    inter4v = 0;
1383    
1384    if (MotionFlags & PMV_USESQUARES8)          if (inter4v) {
1385        MainSearchPtr = Square8_MainSearch;                  SearchData Data8;
1386    else                  memcpy(&Data8, Data, sizeof(SearchData)); //quick copy of common data
1387    
1388          if (MotionFlags & PMV_ADVANCEDDIAMOND8)                  Search8(Data, 2*x, 2*y, MotionFlags, pParam, pMB, pMBs, 0, &Data8);
1389                  MainSearchPtr = AdvDiamond8_MainSearch;                  Search8(Data, 2*x + 1, 2*y, MotionFlags, pParam, pMB, pMBs, 1, &Data8);
1390          else                  Search8(Data, 2*x, 2*y + 1, MotionFlags, pParam, pMB, pMBs, 2, &Data8);
1391                  MainSearchPtr = Diamond8_MainSearch;                  Search8(Data, 2*x + 1, 2*y + 1, MotionFlags, pParam, pMB, pMBs, 3, &Data8);
1392    
1393                    if ((Data->chroma) && (!(VopFlags & XVID_VOP_MODEDECISION_BITS))) {
1394                            // chroma is only used for comparsion to INTER. if the comparsion will be done in BITS domain, there is no reason to compute it
1395                            int sumx = 0, sumy = 0;
1396    
1397          *currMV = startMV;                          if (Data->qpel)
1398                                    for (i = 1; i < 5; i++) {
1399                                            sumx += Data->currentQMV[i].x/2;
1400                                            sumy += Data->currentQMV[i].y/2;
1401                                    }
1402                            else
1403                                    for (i = 1; i < 5; i++) {
1404                                            sumx += Data->currentMV[i].x;
1405                                            sumy += Data->currentMV[i].y;
1406                                    }
1407    
1408          iMinSAD =                          Data->iMinSAD[1] += ChromaSAD(  (sumx >> 3) + roundtab_76[sumx & 0xf],
1409                  sad8(cur,                                                                                          (sumy >> 3) + roundtab_76[sumy & 0xf], Data);
1410                           get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 8, currMV,                  }
1411                                                  iEdgedWidth), iEdgedWidth);          } else Data->iMinSAD[1] = 4096*256;
1412          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  
 */  
1413    
1414          if ((bPredEq) && (MVequal(pmv[0], prevMB->mvs[iSubBlock])))  static void
1415                  iFound = 2;  Search8(const SearchData * const OldData,
1416                    const int x, const int y,
1417                    const uint32_t MotionFlags,
1418                    const MBParam * const pParam,
1419                    MACROBLOCK * const pMB,
1420                    const MACROBLOCK * const pMBs,
1421                    const int block,
1422                    SearchData * const Data)
1423    {
1424            int i = 0;
1425            Data->iMinSAD = OldData->iMinSAD + 1 + block;
1426            Data->currentMV = OldData->currentMV + 1 + block;
1427            Data->currentQMV = OldData->currentQMV + 1 + block;
1428    
1429            if(Data->qpel) {
1430                    Data->predMV = get_qpmv2(pMBs, pParam->mb_width, 0, x/2, y/2, block);
1431                    if (block != 0) i = d_mv_bits(  Data->currentQMV->x, Data->currentQMV->y,
1432                                                                                    Data->predMV, Data->iFcode, 0, 0);
1433            } else {
1434                    Data->predMV = get_pmv2(pMBs, pParam->mb_width, 0, x/2, y/2, block);
1435                    if (block != 0) i = d_mv_bits(  Data->currentMV->x, Data->currentMV->y,
1436                                                                                    Data->predMV, Data->iFcode, 0, Data->rrv);
1437            }
1438    
1439  /* Step 3 (lazy eval): If Distance>0 or thresb<1536 or PredEq=1 Select small Diamond Search.          *(Data->iMinSAD) += (Data->lambda8 * i * (*Data->iMinSAD + NEIGH_8X8_BIAS))>>10;
    Otherwise select large Diamond Search.  
 */  
1440    
1441          if ((!MVzero(pmv[0])) || (threshB < 1536 / 4) || (bPredEq))          if (MotionFlags & (XVID_ME_EXTSEARCH8|XVID_ME_HALFPELREFINE8|XVID_ME_QUARTERPELREFINE8)) {
                 iDiamondSize = 1;               // 1 halfpel!  
         else  
                 iDiamondSize = 2;               // 2 halfpel = 1 full pixel!  
1442    
1443          if (!(MotionFlags & PMV_HALFPELDIAMOND8))                  if (Data->rrv) i = 16; else i = 8;
                 iDiamondSize *= 2;  
1444    
1445                    Data->RefP[0] = OldData->RefP[0] + i * ((block&1) + Data->iEdgedWidth*(block>>1));
1446                    Data->RefP[1] = OldData->RefP[1] + i * ((block&1) + Data->iEdgedWidth*(block>>1));
1447                    Data->RefP[2] = OldData->RefP[2] + i * ((block&1) + Data->iEdgedWidth*(block>>1));
1448                    Data->RefP[3] = OldData->RefP[3] + i * ((block&1) + Data->iEdgedWidth*(block>>1));
1449    
1450  /*                  Data->Cur = OldData->Cur + i * ((block&1) + Data->iEdgedWidth*(block>>1));
1451     Step 5: Calculate SAD for motion vectors taken from left block, top, top-right, and Previous frame block.                  Data->qpel_precision = 0;
    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.  
 */  
1452    
1453  // the median prediction might be even better than mv16                  get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 8,
1454                                            pParam->width, pParam->height, Data->iFcode - Data->qpel, 0, Data->rrv);
1455    
1456          if (!MVequal(pmv[0], startMV))                  if (!Data->rrv) CheckCandidate = CheckCandidate8;
1457                  CHECK_MV8_CANDIDATE(center_x, center_y);                  else CheckCandidate = CheckCandidate16no4v;
1458    
1459  // (0,0) if needed                  if (MotionFlags & XVID_ME_EXTSEARCH8 && (!(MotionFlags & XVID_ME_EXTSEARCH_BITS))) {
1460          if (!MVzero(pmv[0]))                          int32_t temp_sad = *(Data->iMinSAD); // store current MinSAD
                 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;  
1461    
1462                            MainSearchFunc *MainSearchPtr;
1463                            if (MotionFlags & XVID_ME_USESQUARES8) MainSearchPtr = SquareSearch;
1464                                    else if (MotionFlags & XVID_ME_ADVANCEDDIAMOND8) MainSearchPtr = AdvDiamondSearch;
1465                                            else MainSearchPtr = DiamondSearch;
1466    
1467  /* Step 6: If MinSAD <= thresa goto Step 10.                          MainSearchPtr(Data->currentMV->x, Data->currentMV->y, Data, 255);
    If Motion Vector equal to Previous frame motion vector and MinSAD<PrevFrmSAD goto Step 10.  
 */  
1468    
1469          if ((iMinSAD <= threshA) ||                          if(*(Data->iMinSAD) < temp_sad) {
1470                  (MVequal(*currMV, prevMB->mvs[iSubBlock]) &&                                          Data->currentQMV->x = 2 * Data->currentMV->x; // update our qpel vector
1471                   ((int32_t) iMinSAD < prevMB->sad8[iSubBlock]))) {                                          Data->currentQMV->y = 2 * Data->currentMV->y;
1472                  if (MotionFlags & PMV_QUICKSTOP16)                          }
1473                          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.  
 */  
1474    
1475          backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */                  if (MotionFlags & XVID_ME_HALFPELREFINE8) {
1476                            int32_t temp_sad = *(Data->iMinSAD); // store current MinSAD
1477    
1478  /* default: use best prediction as starting point for one call of PMVfast_MainSearch */                          SubpelRefine(Data); // perform halfpel refine of current best vector
         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);  
1479    
1480          if (iSAD < iMinSAD) {                          if(*(Data->iMinSAD) < temp_sad) { // we have found a better match
1481                  *currMV = newMV;                                  Data->currentQMV->x = 2 * Data->currentMV->x; // update our qpel vector
1482                  iMinSAD = iSAD;                                  Data->currentQMV->y = 2 * Data->currentMV->y;
1483                            }
1484          }          }
1485    
1486          if (MotionFlags & PMV_EXTSEARCH8) {                  if (Data->qpel && MotionFlags & XVID_ME_QUARTERPELREFINE8) {
1487  /* extended: search (up to) two more times: orignal prediction and (0,0) */                                  Data->qpel_precision = 1;
1488                                    get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 8,
1489                  if (!(MVequal(pmv[0], backupMV))) {                                          pParam->width, pParam->height, Data->iFcode, 1, 0);
1490                          iSAD =                                  SubpelRefine(Data);
                                 (*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;  
1491                          }                          }
1492                  }                  }
1493    
1494                  if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {          if (Data->rrv) {
1495                          iSAD =                          Data->currentMV->x = RRV_MV_SCALEDOWN(Data->currentMV->x);
1496                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, 0, 0,                          Data->currentMV->y = RRV_MV_SCALEDOWN(Data->currentMV->y);
1497                                                                    iMinSAD, &newMV, center_x, center_y, min_dx, max_dx, min_dy,          }
                                                                   max_dy, iEdgedWidth, iDiamondSize, iFcode,  
                                                                   iQuant, iFound);  
1498    
1499                          if (iSAD < iMinSAD) {          if(Data->qpel) {
1500                                  *currMV = newMV;                  pMB->pmvs[block].x = Data->currentQMV->x - Data->predMV.x;
1501                                  iMinSAD = iSAD;                  pMB->pmvs[block].y = Data->currentQMV->y - Data->predMV.y;
1502                    pMB->qmvs[block] = *Data->currentQMV;
1503            } else {
1504                    pMB->pmvs[block].x = Data->currentMV->x - Data->predMV.x;
1505                    pMB->pmvs[block].y = Data->currentMV->y - Data->predMV.y;
1506                          }                          }
1507    
1508            pMB->mvs[block] = *Data->currentMV;
1509            pMB->sad8[block] = 4 * *Data->iMinSAD;
1510                  }                  }
1511    
1512    /* motion estimation for B-frames */
1513    
1514    static __inline VECTOR
1515    ChoosePred(const MACROBLOCK * const pMB, const uint32_t mode)
1516    {
1517    /* the stupidiest function ever */
1518            return (mode == MODE_FORWARD ? pMB->mvs[0] : pMB->b_mvs[0]);
1519          }          }
1520    
1521  /* Step 10: The motion vector is chosen according to the block corresponding to MinSAD.  static void __inline
1522     By performing an optional local half-pixel search, we can refine this result even further.  PreparePredictionsBF(VECTOR * const pmv, const int x, const int y,
1523  */                                                          const uint32_t iWcount,
1524                                                            const MACROBLOCK * const pMB,
1525                                                            const uint32_t mode_curr)
1526    {
1527    
1528    PMVfast8_Terminate_with_Refine:          // [0] is prediction
1529          if (MotionFlags & PMV_HALFPELREFINE8)   // perform final half-pel step          pmv[0].x = EVEN(pmv[0].x); pmv[0].y = EVEN(pmv[0].y);
                 iMinSAD =  
                         Halfpel8_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);  
1530    
1531            pmv[1].x = pmv[1].y = 0; // [1] is zero
1532    
1533    PMVfast8_Terminate_without_Refine:          pmv[2] = ChoosePred(pMB, mode_curr);
1534          currPMV->x = currMV->x - center_x;          pmv[2].x = EVEN(pmv[2].x); pmv[2].y = EVEN(pmv[2].y);
         currPMV->y = currMV->y - center_y;  
1535    
1536          return iMinSAD;          if ((y != 0)&&(x != (int)(iWcount+1))) {                        // [3] top-right neighbour
1537                    pmv[3] = ChoosePred(pMB+1-iWcount, mode_curr);
1538                    pmv[3].x = EVEN(pmv[3].x); pmv[3].y = EVEN(pmv[3].y);
1539            } else pmv[3].x = pmv[3].y = 0;
1540    
1541            if (y != 0) {
1542                    pmv[4] = ChoosePred(pMB-iWcount, mode_curr);
1543                    pmv[4].x = EVEN(pmv[4].x); pmv[4].y = EVEN(pmv[4].y);
1544            } else pmv[4].x = pmv[4].y = 0;
1545    
1546            if (x != 0) {
1547                    pmv[5] = ChoosePred(pMB-1, mode_curr);
1548                    pmv[5].x = EVEN(pmv[5].x); pmv[5].y = EVEN(pmv[5].y);
1549            } else pmv[5].x = pmv[5].y = 0;
1550    
1551            if (x != 0 && y != 0) {
1552                    pmv[6] = ChoosePred(pMB-1-iWcount, mode_curr);
1553                    pmv[6].x = EVEN(pmv[6].x); pmv[6].y = EVEN(pmv[6].y);
1554            } else pmv[6].x = pmv[6].y = 0;
1555  }  }
1556    
1557  int32_t  
1558  EPZSSearch16(const uint8_t * const pRef,  /* search backward or forward */
1559    static void
1560    SearchBF(       const IMAGE * const pRef,
1561                           const uint8_t * const pRefH,                           const uint8_t * const pRefH,
1562                           const uint8_t * const pRefV,                           const uint8_t * const pRefV,
1563                           const uint8_t * const pRefHV,                           const uint8_t * const pRefHV,
1564                           const IMAGE * const pCur,                           const IMAGE * const pCur,
1565                           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,  
1566                           const uint32_t MotionFlags,                           const uint32_t MotionFlags,
                          const uint32_t iQuant,  
1567                           const uint32_t iFcode,                           const uint32_t iFcode,
1568                           const MBParam * const pParam,                           const MBParam * const pParam,
1569                           const MACROBLOCK * const pMBs,                          MACROBLOCK * const pMB,
1570                           const MACROBLOCK * const prevMBs,                          const VECTOR * const predMV,
1571                           VECTOR * const currMV,                          int32_t * const best_sad,
1572                           VECTOR * const currPMV)                          const int32_t mode_current,
1573                            SearchData * const Data)
1574  {  {
         const uint32_t iWcount = pParam->mb_width;  
         const uint32_t iHcount = pParam->mb_height;  
   
         const int32_t iWidth = pParam->width;  
         const int32_t iHeight = pParam->height;  
         const int32_t iEdgedWidth = pParam->edged_width;  
1575    
1576          const uint8_t *cur = pCur->y + x * 16 + y * 16 * iEdgedWidth;          int i, iDirection = 255, mask;
1577            VECTOR pmv[7];
1578            MainSearchFunc *MainSearchPtr;
1579            *Data->iMinSAD = MV_MAX_ERROR;
1580            Data->iFcode = iFcode;
1581            Data->qpel_precision = 0;
1582            Data->temp[5] = Data->temp[6] = Data->temp[7] = 256*4096; // reset chroma-sad cache
1583    
1584          int32_t min_dx;          Data->RefP[0] = pRef->y + (x + Data->iEdgedWidth*y) * 16;
1585          int32_t max_dx;          Data->RefP[2] = pRefH + (x + Data->iEdgedWidth*y) * 16;
1586          int32_t min_dy;          Data->RefP[1] = pRefV + (x + Data->iEdgedWidth*y) * 16;
1587          int32_t max_dy;          Data->RefP[3] = pRefHV + (x + Data->iEdgedWidth*y) * 16;
1588            Data->RefP[4] = pRef->u + (x + y * (Data->iEdgedWidth/2)) * 8;
1589            Data->RefP[5] = pRef->v + (x + y * (Data->iEdgedWidth/2)) * 8;
1590    
1591          VECTOR newMV;          Data->predMV = *predMV;
         VECTOR backupMV;  
1592    
1593          VECTOR pmv[4];          get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
1594          int32_t psad[8];                                  pParam->width, pParam->height, iFcode - Data->qpel, 0, 0);
1595    
1596          static MACROBLOCK *oldMBs = NULL;          pmv[0] = Data->predMV;
1597            if (Data->qpel) { pmv[0].x /= 2; pmv[0].y /= 2; }
1598    
1599  //  const MACROBLOCK * const pMB = pMBs + x + y * iWcount;          PreparePredictionsBF(pmv, x, y, pParam->mb_width, pMB, mode_current);
         const MACROBLOCK *const prevMB = prevMBs + x + y * iWcount;  
         MACROBLOCK *oldMB = NULL;  
1600    
1601           int32_t thresh2;          Data->currentMV->x = Data->currentMV->y = 0;
1602          int32_t bPredEq;          CheckCandidate = CheckCandidate16no4v;
         int32_t iMinSAD, iSAD = 9999;  
1603    
1604          MainSearch16FuncPtr MainSearchPtr;  // main loop. checking all predictions
1605            for (i = 0; i < 7; i++) {
1606          if (oldMBs == NULL) {                  if (!(mask = make_mask(pmv, i)) ) continue;
1607                  oldMBs = (MACROBLOCK *) calloc(iWcount * iHcount, sizeof(MACROBLOCK));                  CheckCandidate16no4v(pmv[i].x, pmv[i].y, mask, &iDirection, Data);
 //      fprintf(stderr,"allocated %d bytes for oldMBs\n",iWcount*iHcount*sizeof(MACROBLOCK));  
1608          }          }
         oldMB = oldMBs + x + y * iWcount;  
   
 /* Get maximum range */  
         get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 16, iWidth, iHeight,  
                           iFcode);  
1609    
1610          if (!(MotionFlags & PMV_HALFPEL16)) {          if (MotionFlags & XVID_ME_USESQUARES16) MainSearchPtr = SquareSearch;
1611                  min_dx = EVEN(min_dx);          else if (MotionFlags & XVID_ME_ADVANCEDDIAMOND16) MainSearchPtr = AdvDiamondSearch;
1612                  max_dx = EVEN(max_dx);                  else MainSearchPtr = DiamondSearch;
                 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);  
1613    
1614  /* Step 4: Calculate SAD around the Median prediction.          MainSearchPtr(Data->currentMV->x, Data->currentMV->y, Data, iDirection);
         MinSAD=SAD  
         If Motion Vector equal to Previous frame motion vector  
                 and MinSAD<PrevFrmSAD goto Step 10.  
         If SAD<=256 goto Step 10.  
 */  
1615    
1616  // Prepare for main loop          SubpelRefine(Data);
1617    
1618          currMV->x = start_x;          if (Data->qpel && *Data->iMinSAD < *best_sad + 300) {
1619          currMV->y = start_y;                  Data->currentQMV->x = 2*Data->currentMV->x;
1620                    Data->currentQMV->y = 2*Data->currentMV->y;
1621          if (!(MotionFlags & PMV_HALFPEL16)) {                  Data->qpel_precision = 1;
1622                  currMV->x = EVEN(currMV->x);                  get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
1623                  currMV->y = EVEN(currMV->y);                                          pParam->width, pParam->height, iFcode, 1, 0);
1624          }                  SubpelRefine(Data);
1625            }
         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 **************/  
1626    
1627  // previous frame MV  // three bits are needed to code backward mode. four for forward
         CHECK_MV16_CANDIDATE(prevMB->mvs[0].x, prevMB->mvs[0].y);  
1628    
1629  // set threshhold based on Min of Prediction and SAD of collocated block          if (mode_current == MODE_FORWARD) *Data->iMinSAD += 4 * Data->lambda16;
1630  // CHECK_MV16 always uses iSAD for the SAD of last vector to check, so now iSAD is what we want          else *Data->iMinSAD += 3 * Data->lambda16;
1631    
1632          if ((x == 0) && (y == 0)) {          if (*Data->iMinSAD < *best_sad) {
1633                  thresh2 = 512;                  *best_sad = *Data->iMinSAD;
1634                    pMB->mode = mode_current;
1635                    if (Data->qpel) {
1636                            pMB->pmvs[0].x = Data->currentQMV->x - predMV->x;
1637                            pMB->pmvs[0].y = Data->currentQMV->y - predMV->y;
1638                            if (mode_current == MODE_FORWARD)
1639                                    pMB->qmvs[0] = *Data->currentQMV;
1640                            else
1641                                    pMB->b_qmvs[0] = *Data->currentQMV;
1642          } else {          } else {
1643  /* T_k = 1.2 * MIN(SAD_top,SAD_left,SAD_topleft,SAD_coll) +128;   [Tourapis, 2002] */                          pMB->pmvs[0].x = Data->currentMV->x - predMV->x;
1644                            pMB->pmvs[0].y = Data->currentMV->y - predMV->y;
1645                  thresh2 = MIN(psad[0], iSAD) * 6 / 5 + 128;                  }
1646                    if (mode_current == MODE_FORWARD) pMB->mvs[0] = *Data->currentMV;
1647                    else pMB->b_mvs[0] = *Data->currentMV;
1648          }          }
1649    
1650  // MV=(0,0) is often a good choice          if (mode_current == MODE_FORWARD) *(Data->currentMV+2) = *Data->currentMV;
1651            else *(Data->currentMV+1) = *Data->currentMV; //we store currmv for interpolate search
1652          CHECK_MV16_ZERO;  }
1653    
1654    static void
1655    SkipDecisionB(const IMAGE * const pCur,
1656                                    const IMAGE * const f_Ref,
1657                                    const IMAGE * const b_Ref,
1658                                    MACROBLOCK * const pMB,
1659                                    const uint32_t x, const uint32_t y,
1660                                    const SearchData * const Data)
1661    {
1662            int dx = 0, dy = 0, b_dx = 0, b_dy = 0;
1663            int32_t sum;
1664            const int div = 1 + Data->qpel;
1665            int k;
1666            const uint32_t stride = Data->iEdgedWidth/2;
1667    //this is not full chroma compensation, only it's fullpel approximation. should work though
1668    
1669  // left neighbour, if allowed          for (k = 0; k < 4; k++) {
1670          if (x != 0) {                  dy += Data->directmvF[k].y / div;
1671                  if (!(MotionFlags & PMV_HALFPEL16)) {                  dx += Data->directmvF[k].x / div;
1672                          pmv[1].x = EVEN(pmv[1].x);                  b_dy += Data->directmvB[k].y / div;
1673                          pmv[1].y = EVEN(pmv[1].y);                  b_dx += Data->directmvB[k].x / div;
1674                  }          }
1675                  CHECK_MV16_CANDIDATE(pmv[1].x, pmv[1].y);  
1676          }          dy = (dy >> 3) + roundtab_76[dy & 0xf];
1677  // top neighbour, if allowed          dx = (dx >> 3) + roundtab_76[dx & 0xf];
1678          if (y != 0) {          b_dy = (b_dy >> 3) + roundtab_76[b_dy & 0xf];
1679                  if (!(MotionFlags & PMV_HALFPEL16)) {          b_dx = (b_dx >> 3) + roundtab_76[b_dx & 0xf];
1680                          pmv[2].x = EVEN(pmv[2].x);  
1681                          pmv[2].y = EVEN(pmv[2].y);          sum = sad8bi(pCur->u + 8 * x + 8 * y * stride,
1682                  }                                          f_Ref->u + (y*8 + dy/2) * stride + x*8 + dx/2,
1683                  CHECK_MV16_CANDIDATE(pmv[2].x, pmv[2].y);                                          b_Ref->u + (y*8 + b_dy/2) * stride + x*8 + b_dx/2,
1684                                            stride);
1685    
1686            if (sum >= 2 * MAX_CHROMA_SAD_FOR_SKIP * pMB->quant) return; //no skip
1687    
1688            sum += sad8bi(pCur->v + 8*x + 8 * y * stride,
1689                                            f_Ref->v + (y*8 + dy/2) * stride + x*8 + dx/2,
1690                                            b_Ref->v + (y*8 + b_dy/2) * stride + x*8 + b_dx/2,
1691                                            stride);
1692    
1693  // top right neighbour, if allowed          if (sum < 2 * MAX_CHROMA_SAD_FOR_SKIP * pMB->quant) {
1694                  if ((uint32_t) x != (iWcount - 1)) {                  pMB->mode = MODE_DIRECT_NONE_MV; //skipped
1695                          if (!(MotionFlags & PMV_HALFPEL16)) {                  for (k = 0; k < 4; k++) {
1696                                  pmv[3].x = EVEN(pmv[3].x);                          pMB->qmvs[k] = pMB->mvs[k];
1697                                  pmv[3].y = EVEN(pmv[3].y);                          pMB->b_qmvs[k] = pMB->b_mvs[k];
                         }  
                         CHECK_MV16_CANDIDATE(pmv[3].x, pmv[3].y);  
1698                  }                  }
1699          }          }
   
 /* Terminate if MinSAD <= T_2  
    Terminate if MV[t] == MV[t-1] and MinSAD[t] <= MinSAD[t-1]  
 */  
   
         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;  
1700          }          }
1701    
1702  /***** predictor SET C: acceleration MV (new!), neighbours in prev. frame(new!) ****/  static __inline uint32_t
1703    SearchDirect(const IMAGE * const f_Ref,
1704          backupMV = prevMB->mvs[0];      // collocated MV                                  const uint8_t * const f_RefH,
1705          backupMV.x += (prevMB->mvs[0].x - oldMB->mvs[0].x);     // acceleration X                                  const uint8_t * const f_RefV,
1706          backupMV.y += (prevMB->mvs[0].y - oldMB->mvs[0].y);     // acceleration Y                                  const uint8_t * const f_RefHV,
1707                                    const IMAGE * const b_Ref,
1708          CHECK_MV16_CANDIDATE(backupMV.x, backupMV.y);                                  const uint8_t * const b_RefH,
1709                                    const uint8_t * const b_RefV,
1710  // left neighbour                                  const uint8_t * const b_RefHV,
1711          if (x != 0)                                  const IMAGE * const pCur,
1712                  CHECK_MV16_CANDIDATE((prevMB - 1)->mvs[0].x, (prevMB - 1)->mvs[0].y);                                  const int x, const int y,
1713                                    const uint32_t MotionFlags,
1714  // top neighbour                                  const int32_t TRB, const int32_t TRD,
1715          if (y != 0)                                  const MBParam * const pParam,
1716                  CHECK_MV16_CANDIDATE((prevMB - iWcount)->mvs[0].x,                                  MACROBLOCK * const pMB,
1717                                                           (prevMB - iWcount)->mvs[0].y);                                  const MACROBLOCK * const b_mb,
1718                                    int32_t * const best_sad,
1719                                    SearchData * const Data)
1720    
1721    {
1722            int32_t skip_sad;
1723            int k = (x + Data->iEdgedWidth*y) * 16;
1724            MainSearchFunc *MainSearchPtr;
1725    
1726            *Data->iMinSAD = 256*4096;
1727            Data->RefP[0] = f_Ref->y + k;
1728            Data->RefP[2] = f_RefH + k;
1729            Data->RefP[1] = f_RefV + k;
1730            Data->RefP[3] = f_RefHV + k;
1731            Data->b_RefP[0] = b_Ref->y + k;
1732            Data->b_RefP[2] = b_RefH + k;
1733            Data->b_RefP[1] = b_RefV + k;
1734            Data->b_RefP[3] = b_RefHV + k;
1735            Data->RefP[4] = f_Ref->u + (x + (Data->iEdgedWidth/2) * y) * 8;
1736            Data->RefP[5] = f_Ref->v + (x + (Data->iEdgedWidth/2) * y) * 8;
1737            Data->b_RefP[4] = b_Ref->u + (x + (Data->iEdgedWidth/2) * y) * 8;
1738            Data->b_RefP[5] = b_Ref->v + (x + (Data->iEdgedWidth/2) * y) * 8;
1739    
1740            k = Data->qpel ? 4 : 2;
1741            Data->max_dx = k * (pParam->width - x * 16);
1742            Data->max_dy = k * (pParam->height - y * 16);
1743            Data->min_dx = -k * (16 + x * 16);
1744            Data->min_dy = -k * (16 + y * 16);
1745    
1746  // right neighbour, if allowed (this value is not written yet, so take it from   pMB->mvs          Data->referencemv = Data->qpel ? b_mb->qmvs : b_mb->mvs;
1747            Data->qpel_precision = 0;
1748    
1749          if ((uint32_t) x != iWcount - 1)          for (k = 0; k < 4; k++) {
1750                  CHECK_MV16_CANDIDATE((prevMB + 1)->mvs[0].x, (prevMB + 1)->mvs[0].y);                  pMB->mvs[k].x = Data->directmvF[k].x = ((TRB * Data->referencemv[k].x) / TRD);
1751                    pMB->b_mvs[k].x = Data->directmvB[k].x = ((TRB - TRD) * Data->referencemv[k].x) / TRD;
1752                    pMB->mvs[k].y = Data->directmvF[k].y = ((TRB * Data->referencemv[k].y) / TRD);
1753                    pMB->b_mvs[k].y = Data->directmvB[k].y = ((TRB - TRD) * Data->referencemv[k].y) / TRD;
1754    
1755  // bottom neighbour, dito                  if ( (pMB->b_mvs[k].x > Data->max_dx) | (pMB->b_mvs[k].x < Data->min_dx)
1756          if ((uint32_t) y != iHcount - 1)                          | (pMB->b_mvs[k].y > Data->max_dy) | (pMB->b_mvs[k].y < Data->min_dy) ) {
                 CHECK_MV16_CANDIDATE((prevMB + iWcount)->mvs[0].x,  
                                                          (prevMB + iWcount)->mvs[0].y);  
1757    
1758  /* Terminate if MinSAD <= T_3 (here T_3 = T_2)  */                          *best_sad = 256*4096; // in that case, we won't use direct mode
1759          if (iMinSAD <= thresh2) {                          pMB->mode = MODE_DIRECT; // just to make sure it doesn't say "MODE_DIRECT_NONE_MV"
1760                  if (MotionFlags & PMV_QUICKSTOP16)                          pMB->b_mvs[0].x = pMB->b_mvs[0].y = 0;
1761                          goto EPZS16_Terminate_without_Refine;                          return 256*4096;
1762                  if (MotionFlags & PMV_EARLYSTOP16)                  }
1763                          goto EPZS16_Terminate_with_Refine;                  if (b_mb->mode != MODE_INTER4V) {
1764                            pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = pMB->mvs[0];
1765                            pMB->b_mvs[1] = pMB->b_mvs[2] = pMB->b_mvs[3] = pMB->b_mvs[0];
1766                            Data->directmvF[1] = Data->directmvF[2] = Data->directmvF[3] = Data->directmvF[0];
1767                            Data->directmvB[1] = Data->directmvB[2] = Data->directmvB[3] = Data->directmvB[0];
1768                            break;
1769          }          }
   
 /************ (if Diamond Search)  **************/  
   
         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;  
1770          }          }
1771    
1772            CheckCandidate = b_mb->mode == MODE_INTER4V ? CheckCandidateDirect : CheckCandidateDirectno4v;
1773    
1774          if (MotionFlags & PMV_EXTSEARCH16) {          CheckCandidate(0, 0, 255, &k, Data);
 /* extended mode: search (up to) two more times: orignal prediction and (0,0) */  
1775    
1776                  if (!(MVequal(pmv[0], backupMV))) {  // initial (fast) skip decision
1777                          iSAD =          if (*Data->iMinSAD < pMB->quant * INITIAL_SKIP_THRESH * (2 + Data->chroma?1:0)) {
1778                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,                  //possible skip
1779                                                                    pmv[0].x, pmv[0].y, iMinSAD, &newMV, center_x, center_y,                  if (Data->chroma) {
1780                                                                    min_dx, max_dx, min_dy, max_dy, iEdgedWidth,                          pMB->mode = MODE_DIRECT_NONE_MV;
1781                                                                    2, iFcode, iQuant, 0);                          return *Data->iMinSAD; // skip.
1782                    } else {
1783                            SkipDecisionB(pCur, f_Ref, b_Ref, pMB, x, y, Data);
1784                            if (pMB->mode == MODE_DIRECT_NONE_MV) return *Data->iMinSAD; // skip.
1785                  }                  }
   
                 if (iSAD < iMinSAD) {  
                         *currMV = newMV;  
                         iMinSAD = iSAD;  
1786                  }                  }
1787    
1788                  if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {          *Data->iMinSAD += Data->lambda16;
1789                          iSAD =          skip_sad = *Data->iMinSAD;
                                 (*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, 2, iFcode, iQuant, 0);  
1790    
1791                          if (iSAD < iMinSAD) {  //      DIRECT MODE DELTA VECTOR SEARCH.
1792                                  *currMV = newMV;  //      This has to be made more effective, but at the moment I'm happy it's running at all
                                 iMinSAD = iSAD;  
                         }  
                 }  
         }  
1793    
1794  /***************        Choose best MV found     **************/          if (MotionFlags & XVID_ME_USESQUARES16) MainSearchPtr = SquareSearch;
1795                    else if (MotionFlags & XVID_ME_ADVANCEDDIAMOND16) MainSearchPtr = AdvDiamondSearch;
1796                            else MainSearchPtr = DiamondSearch;
1797    
1798    EPZS16_Terminate_with_Refine:          MainSearchPtr(0, 0, Data, 255);
         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);  
1799    
1800    EPZS16_Terminate_without_Refine:          SubpelRefine(Data);
1801    
1802          *oldMB = *prevMB;          *best_sad = *Data->iMinSAD;
1803    
1804          currPMV->x = currMV->x - center_x;          if (Data->qpel || b_mb->mode == MODE_INTER4V) pMB->mode = MODE_DIRECT;
1805          currPMV->y = currMV->y - center_y;          else pMB->mode = MODE_DIRECT_NO4V; //for faster compensation
         return iMinSAD;  
 }  
1806    
1807            pMB->pmvs[3] = *Data->currentMV;
1808    
1809  int32_t          for (k = 0; k < 4; k++) {
1810  EPZSSearch8(const uint8_t * const pRef,                  pMB->mvs[k].x = Data->directmvF[k].x + Data->currentMV->x;
1811                          const uint8_t * const pRefH,                  pMB->b_mvs[k].x = (     (Data->currentMV->x == 0)
1812                          const uint8_t * const pRefV,                                                          ? Data->directmvB[k].x
1813                          const uint8_t * const pRefHV,                                                          :pMB->mvs[k].x - Data->referencemv[k].x);
1814                    pMB->mvs[k].y = (Data->directmvF[k].y + Data->currentMV->y);
1815                    pMB->b_mvs[k].y = ((Data->currentMV->y == 0)
1816                                                            ? Data->directmvB[k].y
1817                                                            : pMB->mvs[k].y - Data->referencemv[k].y);
1818                    if (Data->qpel) {
1819                            pMB->qmvs[k].x = pMB->mvs[k].x; pMB->mvs[k].x /= 2;
1820                            pMB->b_qmvs[k].x = pMB->b_mvs[k].x; pMB->b_mvs[k].x /= 2;
1821                            pMB->qmvs[k].y = pMB->mvs[k].y; pMB->mvs[k].y /= 2;
1822                            pMB->b_qmvs[k].y = pMB->b_mvs[k].y; pMB->b_mvs[k].y /= 2;
1823                    }
1824    
1825                    if (b_mb->mode != MODE_INTER4V) {
1826                            pMB->mvs[3] = pMB->mvs[2] = pMB->mvs[1] = pMB->mvs[0];
1827                            pMB->b_mvs[3] = pMB->b_mvs[2] = pMB->b_mvs[1] = pMB->b_mvs[0];
1828                            pMB->qmvs[3] = pMB->qmvs[2] = pMB->qmvs[1] = pMB->qmvs[0];
1829                            pMB->b_qmvs[3] = pMB->b_qmvs[2] = pMB->b_qmvs[1] = pMB->b_qmvs[0];
1830                            break;
1831                    }
1832            }
1833            return skip_sad;
1834    }
1835    
1836    static void
1837    SearchInterpolate(const IMAGE * const f_Ref,
1838                                    const uint8_t * const f_RefH,
1839                                    const uint8_t * const f_RefV,
1840                                    const uint8_t * const f_RefHV,
1841                                    const IMAGE * const b_Ref,
1842                                    const uint8_t * const b_RefH,
1843                                    const uint8_t * const b_RefV,
1844                                    const uint8_t * const b_RefHV,
1845                          const IMAGE * const pCur,                          const IMAGE * const pCur,
1846                          const int x,                                  const int x, const int y,
1847                          const int y,                                  const uint32_t fcode,
1848                          const int start_x,                                  const uint32_t bcode,
                         const int start_y,  
                         const int center_x,  
                         const int center_y,  
1849                          const uint32_t MotionFlags,                          const uint32_t MotionFlags,
                         const uint32_t iQuant,  
                         const uint32_t iFcode,  
1850                          const MBParam * const pParam,                          const MBParam * const pParam,
1851                          const MACROBLOCK * const pMBs,                                  const VECTOR * const f_predMV,
1852                          const MACROBLOCK * const prevMBs,                                  const VECTOR * const b_predMV,
1853                          VECTOR * const currMV,                                  MACROBLOCK * const pMB,
1854                          VECTOR * const currPMV)                                  int32_t * const best_sad,
1855  {                                  SearchData * const fData)
 /* 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;  
1856    
1857          int32_t iDiamondSize = 1;  {
   
         int32_t min_dx;  
         int32_t max_dx;  
         int32_t min_dy;  
         int32_t max_dy;  
   
         VECTOR newMV;  
         VECTOR backupMV;  
   
         VECTOR pmv[4];  
         int32_t psad[8];  
   
         const int32_t iSubBlock = ((y & 1) << 1) + (x & 1);  
   
 //  const MACROBLOCK * const pMB = pMBs + (x>>1) + (y>>1) * iWcount;  
         const MACROBLOCK *const prevMB = prevMBs + (x >> 1) + (y >> 1) * iWcount;  
   
         int32_t bPredEq;  
         int32_t iMinSAD, iSAD = 9999;  
   
         MainSearch8FuncPtr MainSearchPtr;  
1858    
1859  /* Get maximum range */          int iDirection, i, j;
1860          get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 8, iWidth, iHeight,          SearchData bData;
1861                            iFcode);  
1862            fData->qpel_precision = 0;
1863            memcpy(&bData, fData, sizeof(SearchData)); //quick copy of common data
1864            *fData->iMinSAD = 4096*256;
1865            bData.currentMV++; bData.currentQMV++;
1866            fData->iFcode = bData.bFcode = fcode; fData->bFcode = bData.iFcode = bcode;
1867    
1868            i = (x + y * fData->iEdgedWidth) * 16;
1869    
1870            bData.b_RefP[0] = fData->RefP[0] = f_Ref->y + i;
1871            bData.b_RefP[2] = fData->RefP[2] = f_RefH + i;
1872            bData.b_RefP[1] = fData->RefP[1] = f_RefV + i;
1873            bData.b_RefP[3] = fData->RefP[3] = f_RefHV + i;
1874            bData.RefP[0] = fData->b_RefP[0] = b_Ref->y + i;
1875            bData.RefP[2] = fData->b_RefP[2] = b_RefH + i;
1876            bData.RefP[1] = fData->b_RefP[1] = b_RefV + i;
1877            bData.RefP[3] = fData->b_RefP[3] = b_RefHV + i;
1878            bData.b_RefP[4] = fData->RefP[4] = f_Ref->u + (x + (fData->iEdgedWidth/2) * y) * 8;
1879            bData.b_RefP[5] = fData->RefP[5] = f_Ref->v + (x + (fData->iEdgedWidth/2) * y) * 8;
1880            bData.RefP[4] = fData->b_RefP[4] = b_Ref->u + (x + (fData->iEdgedWidth/2) * y) * 8;
1881            bData.RefP[5] = fData->b_RefP[5] = b_Ref->v + (x + (fData->iEdgedWidth/2) * y) * 8;
1882    
1883            bData.bpredMV = fData->predMV = *f_predMV;
1884            fData->bpredMV = bData.predMV = *b_predMV;
1885            fData->currentMV[0] = fData->currentMV[2];
1886    
1887            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);
1888            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);
1889    
1890            if (fData->currentMV[0].x > fData->max_dx) fData->currentMV[0].x = fData->max_dx;
1891            if (fData->currentMV[0].x < fData->min_dx) fData->currentMV[0].x = fData->min_dx;
1892            if (fData->currentMV[0].y > fData->max_dy) fData->currentMV[0].y = fData->max_dy;
1893            if (fData->currentMV[0].y < fData->min_dy) fData->currentMV[0].y = fData->min_dy;
1894    
1895            if (fData->currentMV[1].x > bData.max_dx) fData->currentMV[1].x = bData.max_dx;
1896            if (fData->currentMV[1].x < bData.min_dx) fData->currentMV[1].x = bData.min_dx;
1897            if (fData->currentMV[1].y > bData.max_dy) fData->currentMV[1].y = bData.max_dy;
1898            if (fData->currentMV[1].y < bData.min_dy) fData->currentMV[1].y = bData.min_dy;
1899    
1900  /* we work with abs. MVs, not relative to prediction, so get_range is called relative to 0,0 */          CheckCandidateInt(fData->currentMV[0].x, fData->currentMV[0].y, 255, &iDirection, fData);
1901    
1902          if (!(MotionFlags & PMV_HALFPEL8)) {  //diamond
1903                  min_dx = EVEN(min_dx);          do {
1904                  max_dx = EVEN(max_dx);                  iDirection = 255;
1905                  min_dy = EVEN(min_dy);                  // forward MV moves
1906                  max_dy = EVEN(max_dy);                  i = fData->currentMV[0].x; j = fData->currentMV[0].y;
1907    
1908                    CheckCandidateInt(i + 1, j, 0, &iDirection, fData);
1909                    CheckCandidateInt(i, j + 1, 0, &iDirection, fData);
1910                    CheckCandidateInt(i - 1, j, 0, &iDirection, fData);
1911                    CheckCandidateInt(i, j - 1, 0, &iDirection, fData);
1912    
1913                    // backward MV moves
1914                    i = fData->currentMV[1].x; j = fData->currentMV[1].y;
1915                    fData->currentMV[2] = fData->currentMV[0];
1916                    CheckCandidateInt(i + 1, j, 0, &iDirection, &bData);
1917                    CheckCandidateInt(i, j + 1, 0, &iDirection, &bData);
1918                    CheckCandidateInt(i - 1, j, 0, &iDirection, &bData);
1919                    CheckCandidateInt(i, j - 1, 0, &iDirection, &bData);
1920    
1921            } while (!(iDirection));
1922    
1923    //qpel refinement
1924            if (fData->qpel) {
1925                    if (*fData->iMinSAD > *best_sad + 500) return;
1926                    CheckCandidate = CheckCandidateInt;
1927                    fData->qpel_precision = bData.qpel_precision = 1;
1928                    get_range(&fData->min_dx, &fData->max_dx, &fData->min_dy, &fData->max_dy, x, y, 16, pParam->width, pParam->height, fcode, 1, 0);
1929                    get_range(&bData.min_dx, &bData.max_dx, &bData.min_dy, &bData.max_dy, x, y, 16, pParam->width, pParam->height, bcode, 1, 0);
1930                    fData->currentQMV[2].x = fData->currentQMV[0].x = 2 * fData->currentMV[0].x;
1931                    fData->currentQMV[2].y = fData->currentQMV[0].y = 2 * fData->currentMV[0].y;
1932                    fData->currentQMV[1].x = 2 * fData->currentMV[1].x;
1933                    fData->currentQMV[1].y = 2 * fData->currentMV[1].y;
1934                    SubpelRefine(fData);
1935                    if (*fData->iMinSAD > *best_sad + 300) return;
1936                    fData->currentQMV[2] = fData->currentQMV[0];
1937                    SubpelRefine(&bData);
1938            }
1939    
1940            *fData->iMinSAD += (2+3) * fData->lambda16; // two bits are needed to code interpolate mode.
1941    
1942            if (*fData->iMinSAD < *best_sad) {
1943                    *best_sad = *fData->iMinSAD;
1944                    pMB->mvs[0] = fData->currentMV[0];
1945                    pMB->b_mvs[0] = fData->currentMV[1];
1946                    pMB->mode = MODE_INTERPOLATE;
1947                    if (fData->qpel) {
1948                            pMB->qmvs[0] = fData->currentQMV[0];
1949                            pMB->b_qmvs[0] = fData->currentQMV[1];
1950                            pMB->pmvs[1].x = pMB->qmvs[0].x - f_predMV->x;
1951                            pMB->pmvs[1].y = pMB->qmvs[0].y - f_predMV->y;
1952                            pMB->pmvs[0].x = pMB->b_qmvs[0].x - b_predMV->x;
1953                            pMB->pmvs[0].y = pMB->b_qmvs[0].y - b_predMV->y;
1954                    } else {
1955                            pMB->pmvs[1].x = pMB->mvs[0].x - f_predMV->x;
1956                            pMB->pmvs[1].y = pMB->mvs[0].y - f_predMV->y;
1957                            pMB->pmvs[0].x = pMB->b_mvs[0].x - b_predMV->x;
1958                            pMB->pmvs[0].y = pMB->b_mvs[0].y - b_predMV->y;
1959                    }
1960            }
1961          }          }
         /* 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);  
   
   
 /* 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  
1962    
1963    void
1964    MotionEstimationBVOP(MBParam * const pParam,
1965                                             FRAMEINFO * const frame,
1966                                             const int32_t time_bp,
1967                                             const int32_t time_pp,
1968                                             // forward (past) reference
1969                                             const MACROBLOCK * const f_mbs,
1970                                             const IMAGE * const f_ref,
1971                                             const IMAGE * const f_refH,
1972                                             const IMAGE * const f_refV,
1973                                             const IMAGE * const f_refHV,
1974                                             // backward (future) reference
1975                                             const FRAMEINFO * const b_reference,
1976                                             const IMAGE * const b_ref,
1977                                             const IMAGE * const b_refH,
1978                                             const IMAGE * const b_refV,
1979                                             const IMAGE * const b_refHV)
1980    {
1981            uint32_t i, j;
1982            int32_t best_sad;
1983            uint32_t skip_sad;
1984            int f_count = 0, b_count = 0, i_count = 0, d_count = 0, n_count = 0;
1985            const MACROBLOCK * const b_mbs = b_reference->mbs;
1986    
1987          if (!(MotionFlags & PMV_HALFPEL8)) {          VECTOR f_predMV, b_predMV;      /* there is no prediction for direct mode*/
                 currMV->x = EVEN(currMV->x);  
                 currMV->y = EVEN(currMV->y);  
         }  
1988    
1989          if (currMV->x > max_dx)          const int32_t TRB = time_pp - time_bp;
1990                  currMV->x = max_dx;          const int32_t TRD = time_pp;
         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;  
1991    
1992  /***************** This is predictor SET A: only median prediction ******************/  // some pre-inintialized data for the rest of the search
1993    
1994            SearchData Data;
1995            int32_t iMinSAD;
1996            VECTOR currentMV[3];
1997            VECTOR currentQMV[3];
1998            int32_t temp[8];
1999            memset(&Data, 0, sizeof(SearchData));
2000            Data.iEdgedWidth = pParam->edged_width;
2001            Data.currentMV = currentMV; Data.currentQMV = currentQMV;
2002            Data.iMinSAD = &iMinSAD;
2003            Data.lambda16 = lambda_vec16[frame->quant];
2004            Data.qpel = pParam->vol_flags & XVID_VOL_QUARTERPEL;
2005            Data.rounding = 0;
2006            Data.chroma = frame->motion_flags & XVID_ME_CHROMA8;
2007            Data.temp = temp;
2008    
2009          iMinSAD =          Data.RefQ = f_refV->u; // a good place, also used in MC (for similar purpose)
2010                  sad8(cur,          // note: i==horizontal, j==vertical
2011                           get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 8, currMV,          for (j = 0; j < pParam->mb_height; j++) {
                                                 iEdgedWidth), iEdgedWidth);  
         iMinSAD +=  
                 calc_delta_8(currMV->x - center_x, currMV->y - center_y,  
                                          (uint8_t) iFcode, iQuant);  
2012    
2013                    f_predMV = b_predMV = zeroMV;   /* prediction is reset at left boundary */
2014    
2015  // thresh1 is fixed to 256                  for (i = 0; i < pParam->mb_width; i++) {
2016          if (iMinSAD < 256 / 4) {                          MACROBLOCK * const pMB = frame->mbs + i + j * pParam->mb_width;
2017                  if (MotionFlags & PMV_QUICKSTOP8)                          const MACROBLOCK * const b_mb = b_mbs + i + j * pParam->mb_width;
2018                          goto EPZS8_Terminate_without_Refine;  
2019                  if (MotionFlags & PMV_EARLYSTOP8)  /* special case, if collocated block is SKIPed in P-VOP: encoding is forward (0,0), cpb=0 without further ado */
2020                          goto EPZS8_Terminate_with_Refine;                          if (b_reference->coding_type != S_VOP)
2021                                    if (b_mb->mode == MODE_NOT_CODED) {
2022                                            pMB->mode = MODE_NOT_CODED;
2023                                            continue;
2024          }          }
2025    
2026  /************** This is predictor SET B: (0,0), prev.frame MV, neighbours **************/                          Data.Cur = frame->image.y + (j * Data.iEdgedWidth + i) * 16;
2027                            Data.CurU = frame->image.u + (j * Data.iEdgedWidth/2 + i) * 8;
2028                            Data.CurV = frame->image.v + (j * Data.iEdgedWidth/2 + i) * 8;
2029                            pMB->quant = frame->quant;
2030    
2031    /* direct search comes first, because it (1) checks for SKIP-mode
2032            and (2) sets very good predictions for forward and backward search */
2033                            skip_sad = SearchDirect(f_ref, f_refH->y, f_refV->y, f_refHV->y,
2034                                                                            b_ref, b_refH->y, b_refV->y, b_refHV->y,
2035                                                                            &frame->image,
2036                                                                            i, j,
2037                                                                            frame->motion_flags,
2038                                                                            TRB, TRD,
2039                                                                            pParam,
2040                                                                            pMB, b_mb,
2041                                                                            &best_sad,
2042                                                                            &Data);
2043    
2044                            if (pMB->mode == MODE_DIRECT_NONE_MV) { n_count++; continue; }
2045    
2046  // MV=(0,0) is often a good choice                          // forward search
2047          CHECK_MV8_ZERO;                          SearchBF(f_ref, f_refH->y, f_refV->y, f_refHV->y,
2048                                                    &frame->image, i, j,
2049                                                    frame->motion_flags,
2050                                                    frame->fcode, pParam,
2051                                                    pMB, &f_predMV, &best_sad,
2052                                                    MODE_FORWARD, &Data);
2053    
2054  // previous frame MV                          // backward search
2055          CHECK_MV8_CANDIDATE(prevMB->mvs[iSubBlock].x, prevMB->mvs[iSubBlock].y);                          SearchBF(b_ref, b_refH->y, b_refV->y, b_refHV->y,
2056                                                    &frame->image, i, j,
2057                                                    frame->motion_flags,
2058                                                    frame->bcode, pParam,
2059                                                    pMB, &b_predMV, &best_sad,
2060                                                    MODE_BACKWARD, &Data);
2061    
2062                            // interpolate search comes last, because it uses data from forward and backward as prediction
2063                            SearchInterpolate(f_ref, f_refH->y, f_refV->y, f_refHV->y,
2064                                                    b_ref, b_refH->y, b_refV->y, b_refHV->y,
2065                                                    &frame->image,
2066                                                    i, j,
2067                                                    frame->fcode, frame->bcode,
2068                                                    frame->motion_flags,
2069                                                    pParam,
2070                                                    &f_predMV, &b_predMV,
2071                                                    pMB, &best_sad,
2072                                                    &Data);
2073    
2074    // final skip decision
2075                            if ( (skip_sad < frame->quant * MAX_SAD00_FOR_SKIP * 2)
2076                                            && ((100*best_sad)/(skip_sad+1) > FINAL_SKIP_THRESH) )
2077                                    SkipDecisionB(&frame->image, f_ref, b_ref, pMB, i, j, &Data);
2078    
2079  // left neighbour, if allowed                          switch (pMB->mode) {
2080          if (psad[1] != MV_MAX_ERROR) {                                  case MODE_FORWARD:
2081                  if (!(MotionFlags & PMV_HALFPEL8)) {                                          f_count++;
2082                          pmv[1].x = EVEN(pmv[1].x);                                          f_predMV = Data.qpel ? pMB->qmvs[0] : pMB->mvs[0];
2083                          pmv[1].y = EVEN(pmv[1].y);                                          break;
2084                  }                                  case MODE_BACKWARD:
2085                  CHECK_MV8_CANDIDATE(pmv[1].x, pmv[1].y);                                          b_count++;
2086          }                                          b_predMV = Data.qpel ? pMB->b_qmvs[0] : pMB->b_mvs[0];
2087  // top neighbour, if allowed                                          break;
2088          if (psad[2] != MV_MAX_ERROR) {                                  case MODE_INTERPOLATE:
2089                  if (!(MotionFlags & PMV_HALFPEL8)) {                                          i_count++;
2090                          pmv[2].x = EVEN(pmv[2].x);                                          f_predMV = Data.qpel ? pMB->qmvs[0] : pMB->mvs[0];
2091                          pmv[2].y = EVEN(pmv[2].y);                                          b_predMV = Data.qpel ? pMB->b_qmvs[0] : pMB->b_mvs[0];
2092                                            break;
2093                                    case MODE_DIRECT:
2094                                    case MODE_DIRECT_NO4V:
2095                                            d_count++;
2096                                    default:
2097                                            break;
2098                  }                  }
                 CHECK_MV8_CANDIDATE(pmv[2].x, pmv[2].y);  
   
 // top right neighbour, if allowed  
                 if (psad[3] != MV_MAX_ERROR) {  
                         if (!(MotionFlags & PMV_HALFPEL8)) {  
                                 pmv[3].x = EVEN(pmv[3].x);  
                                 pmv[3].y = EVEN(pmv[3].y);  
2099                          }                          }
                         CHECK_MV8_CANDIDATE(pmv[3].x, pmv[3].y);  
2100                  }                  }
2101          }          }
2102    
2103  /*  // this bias is zero anyway, at the moment!  static __inline void
2104    MEanalyzeMB (   const uint8_t * const pRef,
2105                                    const uint8_t * const pCur,
2106                                    const int x,
2107                                    const int y,
2108                                    const MBParam * const pParam,
2109                                    MACROBLOCK * const pMBs,
2110                                    SearchData * const Data)
2111    {
2112    
2113          if ( (MVzero(*currMV)) && (!MVzero(pmv[0])) ) // && (iMinSAD <= iQuant * 96)          int i, mask;
2114                  iMinSAD -= MV8_00_BIAS;          int quarterpel = (pParam->vol_flags & XVID_VOL_QUARTERPEL)? 1: 0;
2115            VECTOR pmv[3];
2116            MACROBLOCK * const pMB = &pMBs[x + y * pParam->mb_width];
2117    
2118  */          for (i = 0; i < 5; i++) Data->iMinSAD[i] = MV_MAX_ERROR;
2119    
2120  /* Terminate if MinSAD <= T_2          //median is only used as prediction. it doesn't have to be real
2121     Terminate if MV[t] == MV[t-1] and MinSAD[t] <= MinSAD[t-1]          if (x == 1 && y == 1) Data->predMV.x = Data->predMV.y = 0;
2122  */          else
2123                    if (x == 1) //left macroblock does not have any vector now
2124                            Data->predMV = (pMB - pParam->mb_width)->mvs[0]; // top instead of median
2125                    else if (y == 1) // top macroblock doesn't have it's vector
2126                            Data->predMV = (pMB - 1)->mvs[0]; // left instead of median
2127                            else Data->predMV = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 0); //else median
2128    
2129          if (iMinSAD < 512 / 4) {        /* T_2 == 512/4 hardcoded */          get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
2130                  if (MotionFlags & PMV_QUICKSTOP8)          pParam->width, pParam->height, Data->iFcode - quarterpel, 0, 0);
                         goto EPZS8_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP8)  
                         goto EPZS8_Terminate_with_Refine;  
         }  
2131    
2132  /************ (Diamond Search)  **************/          Data->Cur = pCur + (x + y * pParam->edged_width) * 16;
2133            Data->RefP[0] = pRef + (x + y * pParam->edged_width) * 16;
2134    
2135          backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */          pmv[1].x = EVEN(pMB->mvs[0].x);
2136            pmv[1].y = EVEN(pMB->mvs[0].y);
2137            pmv[2].x = EVEN(Data->predMV.x);
2138            pmv[2].y = EVEN(Data->predMV.y);
2139            pmv[0].x = pmv[0].y = 0;
2140    
2141          if (!(MotionFlags & PMV_HALFPELDIAMOND8))          CheckCandidate32I(0, 0, 255, &i, Data);
                 iDiamondSize *= 2;  
2142    
2143  /* default: use best prediction as starting point for one call of EPZS_MainSearch */          if (*Data->iMinSAD > 4 * MAX_SAD00_FOR_SKIP) {
2144    
2145  // there is no EPZS^2 for inter4v at the moment                  if (!(mask = make_mask(pmv, 1)))
2146                            CheckCandidate32I(pmv[1].x, pmv[1].y, mask, &i, Data);
2147                    if (!(mask = make_mask(pmv, 2)))
2148                            CheckCandidate32I(pmv[2].x, pmv[2].y, mask, &i, Data);
2149    
2150    if (MotionFlags & PMV_USESQUARES8)                  if (*Data->iMinSAD > 4 * MAX_SAD00_FOR_SKIP) // diamond only if needed
2151        MainSearchPtr = Square8_MainSearch;                          DiamondSearch(Data->currentMV->x, Data->currentMV->y, Data, i);
2152    else          }
2153    
2154          if (MotionFlags & PMV_ADVANCEDDIAMOND8)          for (i = 0; i < 4; i++) {
2155                  MainSearchPtr = AdvDiamond8_MainSearch;                  MACROBLOCK * MB = &pMBs[x + (i&1) + (y+(i>>1)) * pParam->mb_width];
2156          else                  MB->mvs[0] = MB->mvs[1] = MB->mvs[2] = MB->mvs[3] = Data->currentMV[i];
2157                  MainSearchPtr = Diamond8_MainSearch;                  MB->mode = MODE_INTER;
2158                    MB->sad16 = Data->iMinSAD[i+1];
2159            }
2160    }
2161    
2162          iSAD =  #define INTRA_THRESH    1800
2163                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV->x,  #define INTER_THRESH    1200
                                                   currMV->y, iMinSAD, &newMV, center_x, center_y, min_dx, max_dx,  
                                                   min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode,  
                                                   iQuant, 0);  
2164    
2165    int
2166    MEanalysis(     const IMAGE * const pRef,
2167                            const FRAMEINFO * const Current,
2168                            const MBParam * const pParam,
2169                            const int maxIntra, //maximum number if non-I frames
2170                            const int intraCount, //number of non-I frames after last I frame; 0 if we force P/B frame
2171                            const int bCount,  // number of B frames in a row
2172                            const int b_thresh)
2173    {
2174            uint32_t x, y, intra = 0;
2175            int sSAD = 0;
2176            MACROBLOCK * const pMBs = Current->mbs;
2177            const IMAGE * const pCurrent = &Current->image;
2178            int IntraThresh = INTRA_THRESH, InterThresh = INTER_THRESH + 10*b_thresh;
2179            int s = 0, blocks = 0;
2180    
2181            int32_t iMinSAD[5], temp[5];
2182            VECTOR currentMV[5];
2183            SearchData Data;
2184            Data.iEdgedWidth = pParam->edged_width;
2185            Data.currentMV = currentMV;
2186            Data.iMinSAD = iMinSAD;
2187            Data.iFcode = Current->fcode;
2188            Data.temp = temp;
2189            CheckCandidate = CheckCandidate32I;
2190    
2191          if (iSAD < iMinSAD) {          if (intraCount != 0 && intraCount < 10) // we're right after an I frame
2192                  *currMV = newMV;                  IntraThresh += 15 * (intraCount - 10) * (intraCount - 10);
2193                  iMinSAD = iSAD;          else
2194          }                  if ( 5*(maxIntra - intraCount) < maxIntra) // we're close to maximum. 2 sec when max is 10 sec
2195                            IntraThresh -= (IntraThresh * (maxIntra - 8*(maxIntra - intraCount)))/maxIntra;
2196    
2197          if (MotionFlags & PMV_EXTSEARCH8) {          InterThresh -= (350 - 8*b_thresh) * bCount;
2198  /* extended mode: search (up to) two more times: orignal prediction and (0,0) */          if (InterThresh < 300 + 5*b_thresh) InterThresh = 300 + 5*b_thresh;
2199    
2200                  if (!(MVequal(pmv[0], backupMV))) {          if (sadInit) (*sadInit) ();
                         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, 0);  
2201    
2202                          if (iSAD < iMinSAD) {          for (y = 1; y < pParam->mb_height-1; y += 2) {
2203                                  *currMV = newMV;                  for (x = 1; x < pParam->mb_width-1; x += 2) {
2204                                  iMinSAD = iSAD;                          int i;
2205                            blocks += 4;
2206    
2207                            if (bCount == 0) pMBs[x + y * pParam->mb_width].mvs[0] = zeroMV;
2208                            else { //extrapolation of the vector found for last frame
2209                                    pMBs[x + y * pParam->mb_width].mvs[0].x =
2210                                            (pMBs[x + y * pParam->mb_width].mvs[0].x * (bCount+1) ) / bCount;
2211                                    pMBs[x + y * pParam->mb_width].mvs[0].y =
2212                                            (pMBs[x + y * pParam->mb_width].mvs[0].y * (bCount+1) ) / bCount;
2213                            }
2214    
2215                            MEanalyzeMB(pRef->y, pCurrent->y, x, y, pParam, pMBs, &Data);
2216    
2217                            for (i = 0; i < 4; i++) {
2218                                    int dev;
2219                                    MACROBLOCK *pMB = &pMBs[x+(i&1) + (y+(i>>1)) * pParam->mb_width];
2220                                    if (pMB->sad16 > IntraThresh) {
2221                                            dev = dev16(pCurrent->y + (x + (i&1) + (y + (i>>1)) * pParam->edged_width) * 16,
2222                                                                            pParam->edged_width);
2223                                            if (dev + IntraThresh < pMB->sad16) {
2224                                                    pMB->mode = MODE_INTRA;
2225                                                    if (++intra > ((pParam->mb_height-2)*(pParam->mb_width-2))/2) return I_VOP;
2226                          }                          }
2227                  }                  }
2228                                    if (pMB->mvs[0].x == 0 && pMB->mvs[0].y == 0) s++;
2229    
2230                  if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {                                  sSAD += pMB->sad16;
                         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);  
   
                         if (iSAD < iMinSAD) {  
                                 *currMV = newMV;  
                                 iMinSAD = iSAD;  
2231                          }                          }
2232                  }                  }
2233          }          }
2234    
2235  /***************        Choose best MV found     **************/          sSAD /= blocks;
2236            s = (10*s) / blocks;
   EPZS8_Terminate_with_Refine:  
         if (MotionFlags & PMV_HALFPELREFINE8)   // perform final half-pel step  
                 iMinSAD =  
                         Halfpel8_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);  
2237    
2238    EPZS8_Terminate_without_Refine:          if (s > 4) sSAD += (s - 2) * (60 - 2*b_thresh); //static block - looks bad when in bframe...
2239    
2240          currPMV->x = currMV->x - center_x;          if (sSAD > InterThresh ) return P_VOP;
2241          currPMV->y = currMV->y - center_y;          emms();
2242          return iMinSAD;          return B_VOP;
2243  }  }
2244    
2245    
2246    static WARPPOINTS
2247  int32_t  GlobalMotionEst(const MACROBLOCK * const pMBs,
 PMVfastIntSearch16(const uint8_t * const pRef,  
                                 const uint8_t * const pRefH,  
                                 const uint8_t * const pRefV,  
                                 const uint8_t * const pRefHV,  
                                 const IMAGE * const pCur,  
                                 const int x,  
                                 const int y,  
                                 const int start_x,              /* 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,  
2248                                  const MBParam * const pParam,                                  const MBParam * const pParam,
2249                                  const MACROBLOCK * const pMBs,                                  const FRAMEINFO * const current,
2250                                  const MACROBLOCK * const prevMBs,                                  const FRAMEINFO * const reference,
2251                                  VECTOR * const currMV,                                  const IMAGE * const pRefH,
2252                                  VECTOR * const currPMV)                                  const IMAGE * const pRefV,
2253                                    const IMAGE * const pRefHV      )
2254  {  {
         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;  
         const VECTOR zeroMV = { 0, 0 };  
   
         int32_t iDiamondSize;  
   
         int32_t min_dx;  
         int32_t max_dx;  
         int32_t min_dy;  
         int32_t max_dy;  
   
         int32_t iFound;  
2255    
2256          VECTOR newMV;          const int deltax=8;             // upper bound for difference between a MV and it's neighbour MVs
2257          VECTOR backupMV;          const int deltay=8;
2258            const int grad=512;             // lower bound for deviation in MB
2259    
2260          VECTOR pmv[4];          WARPPOINTS gmc;
         int32_t psad[4];  
2261    
2262          MainSearch16FuncPtr MainSearchPtr;          uint32_t mx, my;
2263    
2264          const MACROBLOCK *const prevMB = prevMBs + x + y * iWcount;          int MBh = pParam->mb_height;
2265          MACROBLOCK *const pMB = pMBs + x + y * iWcount;          int MBw = pParam->mb_width;
2266    
2267          int32_t threshA, threshB;          int *MBmask= calloc(MBh*MBw,sizeof(int));
2268          int32_t bPredEq;          double DtimesF[4] = { 0.,0., 0., 0. };
2269          int32_t iMinSAD, iSAD;          double sol[4] = { 0., 0., 0., 0. };
2270            double a,b,c,n,denom;
2271            double meanx,meany;
2272            int num,oldnum;
2273    
2274            if (!MBmask) {  fprintf(stderr,"Mem error\n");
2275                                            gmc.duv[0].x= gmc.duv[0].y =
2276                                                    gmc.duv[1].x= gmc.duv[1].y =
2277                                                    gmc.duv[2].x= gmc.duv[2].y = 0;
2278                                            return gmc; }
2279    
2280  /* Get maximum range */  // filter mask of all blocks
         get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 16, iWidth, iHeight,  
                           iFcode);  
2281    
2282  /* we work with abs. MVs, not relative to prediction, so get_range is called relative to 0,0 */          for (my = 1; my < (uint32_t)MBh-1; my++)
2283            for (mx = 1; mx < (uint32_t)MBw-1; mx++)
2284            {
2285                    const int mbnum = mx + my * MBw;
2286                    const MACROBLOCK *pMB = &pMBs[mbnum];
2287                    const VECTOR mv = pMB->mvs[0];
2288    
2289          if ((x == 0) && (y == 0)) {                  if (pMB->mode == MODE_INTRA || pMB->mode == MODE_NOT_CODED)
2290                  threshA = 512;                          continue;
                 threshB = 1024;  
2291    
2292                  bPredEq = 0;                  if ( ( (abs(mv.x -   (pMB-1)->mvs[0].x) < deltax) && (abs(mv.y -   (pMB-1)->mvs[0].y) < deltay) )
2293                  psad[0] = psad[1] = psad[2] = psad[3] = 0;                  &&   ( (abs(mv.x -   (pMB+1)->mvs[0].x) < deltax) && (abs(mv.y -   (pMB+1)->mvs[0].y) < deltay) )
2294                  *currMV = pmv[0] = pmv[1] = pmv[2] = pmv[3] = zeroMV;                  &&   ( (abs(mv.x - (pMB-MBw)->mvs[0].x) < deltax) && (abs(mv.y - (pMB-MBw)->mvs[0].y) < deltay) )
2295                    &&   ( (abs(mv.x - (pMB+MBw)->mvs[0].x) < deltax) && (abs(mv.y - (pMB+MBw)->mvs[0].y) < deltay) ) )
2296                            MBmask[mbnum]=1;
2297            }
2298    
2299          } else {          for (my = 1; my < (uint32_t)MBh-1; my++)
2300            for (mx = 1; mx < (uint32_t)MBw-1; mx++)
2301            {
2302                    const uint8_t *const pCur = current->image.y + 16*my*pParam->edged_width + 16*mx;
2303    
2304                  bPredEq = get_ipmvdata(pMBs, iWcount, 0, x, y, 0, pmv, psad);                  const int mbnum = mx + my * MBw;
2305                    if (!MBmask[mbnum])
2306                            continue;
2307    
2308                  threshA = psad[0];                  if (sad16 ( pCur, pCur+1 , pParam->edged_width, 65536) <= (uint32_t)grad )
2309                  threshB = threshA + 256;                          MBmask[mbnum] = 0;
2310                  if (threshA < 512)                  if (sad16 ( pCur, pCur+pParam->edged_width, pParam->edged_width, 65536) <= (uint32_t)grad )
2311                          threshA = 512;                          MBmask[mbnum] = 0;
                 if (threshA > 1024)  
                         threshA = 1024;  
                 if (threshB > 1792)  
                         threshB = 1792;  
2312    
                 *currMV = pmv[0];                       /* current best := prediction */  
2313          }          }
2314    
2315          iFound = 0;          emms();
2316    
2317  /* Step 4: Calculate SAD around the Median prediction.          do {            /* until convergence */
    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);  
         }  
         if (currMV->x < min_dx) {  
                 currMV->x = EVEN(min_dx);  
         }  
         if (currMV->y > max_dy) {  
                 currMV->y = EVEN(max_dy);  
         }  
         if (currMV->y < min_dy) {  
                 currMV->y = EVEN(min_dy);  
         }  
2318    
2319          iMinSAD =          a = b = c = n = 0;
2320                  sad16(cur,          DtimesF[0] = DtimesF[1] = DtimesF[2] = DtimesF[3] = 0.;
2321                            get_iref_mv(pRef, x, y, 16, currMV,          for (my = 0; my < (uint32_t)MBh; my++)
2322                                                   iEdgedWidth), iEdgedWidth, MV_MAX_ERROR);                  for (mx = 0; mx < (uint32_t)MBw; mx++)
         iMinSAD +=  
                 calc_delta_16(currMV->x - center_x, currMV->y - center_y,  
                                           (uint8_t) iFcode, iQuant);  
   
         if ((iMinSAD < 256) ||  
                 ((MVequal(*currMV, prevMB->i_mvs[0])) &&  
                  ((int32_t) iMinSAD < prevMB->i_sad16))) {  
                 if (iMinSAD < 2 * iQuant)       // high chances for SKIP-mode  
2323                  {                  {
2324                          if (!MVzero(*currMV)) {                          const int mbnum = mx + my * MBw;
2325                                  iMinSAD += MV16_00_BIAS;                          const MACROBLOCK *pMB = &pMBs[mbnum];
2326                                  CHECK_MV16_ZERO;        // (0,0) saves space for letterboxed pictures                          const VECTOR mv = pMB->mvs[0];
                                 iMinSAD -= MV16_00_BIAS;  
                         }  
                 }  
2327    
2328                  if (MotionFlags & PMV_EARLYSTOP16)                          if (!MBmask[mbnum])
2329                          goto PMVfastInt16_Terminate_with_Refine;                                  continue;
         }  
2330    
2331                            n++;
2332                            a += 16*mx+8;
2333                            b += 16*my+8;
2334                            c += (16*mx+8)*(16*mx+8)+(16*my+8)*(16*my+8);
2335    
2336                            DtimesF[0] += (double)mv.x;
2337                            DtimesF[1] += (double)mv.x*(16*mx+8) + (double)mv.y*(16*my+8);
2338                            DtimesF[2] += (double)mv.x*(16*my+8) - (double)mv.y*(16*mx+8);
2339                            DtimesF[3] += (double)mv.y;
2340                    }
2341    
2342            denom = a*a+b*b-c*n;
2343    
2344    /* Solve the system:    sol = (D'*E*D)^{-1} D'*E*F   */
2345    /* D'*E*F has been calculated in the same loop as matrix */
2346    
2347            sol[0] = -c*DtimesF[0] + a*DtimesF[1] + b*DtimesF[2];
2348            sol[1] =  a*DtimesF[0] - n*DtimesF[1]                + b*DtimesF[3];
2349            sol[2] =  b*DtimesF[0]                - n*DtimesF[2] - a*DtimesF[3];
2350            sol[3] =                 b*DtimesF[1] - a*DtimesF[2] - c*DtimesF[3];
2351    
2352            sol[0] /= denom;
2353            sol[1] /= denom;
2354            sol[2] /= denom;
2355            sol[3] /= denom;
2356    
2357            meanx = meany = 0.;
2358            oldnum = 0;
2359            for (my = 0; my < (uint32_t)MBh; my++)
2360                    for (mx = 0; mx < (uint32_t)MBw; mx++)
2361                    {
2362                            const int mbnum = mx + my * MBw;
2363                            const MACROBLOCK *pMB = &pMBs[mbnum];
2364                            const VECTOR mv = pMB->mvs[0];
2365    
2366  /* Step 2 (lazy eval): Calculate Distance= |MedianMVX| + |MedianMVY| where MedianMV is the motion                          if (!MBmask[mbnum])
2367     vector of the median.                                  continue;
    If PredEq=1 and MVpredicted = Previous Frame MV, set Found=2  
 */  
2368    
2369          if ((bPredEq) && (MVequal(pmv[0], prevMB->i_mvs[0])))                          oldnum++;
2370                  iFound = 2;                          meanx += fabs(( sol[0] + (16*mx+8)*sol[1] + (16*my+8)*sol[2] ) - mv.x );
2371                            meany += fabs(( sol[3] - (16*mx+8)*sol[2] + (16*my+8)*sol[1] ) - mv.y );
2372                    }
2373    
2374  /* Step 3 (lazy eval): If Distance>0 or thresb<1536 or PredEq=1 Select small Diamond Search.          if (4*meanx > oldnum)   /* better fit than 0.25 is useless */
2375     Otherwise select large Diamond Search.                  meanx /= oldnum;
2376  */          else
2377                    meanx = 0.25;
2378    
2379          if ((!MVzero(pmv[0])) || (threshB < 1536) || (bPredEq))          if (4*meany > oldnum)
2380                  iDiamondSize = 2;               // halfpel units!                  meany /= oldnum;
2381          else          else
2382                  iDiamondSize = 4;               // halfpel units!                  meany = 0.25;
2383    
2384  /*  /*      fprintf(stderr,"sol = (%8.5f, %8.5f, %8.5f, %8.5f)\n",sol[0],sol[1],sol[2],sol[3]);
2385     Step 5: Calculate SAD for motion vectors taken from left block, top, top-right, and Previous frame block.          fprintf(stderr,"meanx = %8.5f  meany = %8.5f   %d\n",meanx,meany, oldnum);
    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.  
2386  */  */
2387            num = 0;
2388            for (my = 0; my < (uint32_t)MBh; my++)
2389                    for (mx = 0; mx < (uint32_t)MBw; mx++)
2390                    {
2391                            const int mbnum = mx + my * MBw;
2392                            const MACROBLOCK *pMB = &pMBs[mbnum];
2393                            const VECTOR mv = pMB->mvs[0];
2394    
2395  // (0,0) is often a good choice                          if (!MBmask[mbnum])
2396                                    continue;
2397    
2398          if (!MVzero(pmv[0]))                          if  ( ( fabs(( sol[0] + (16*mx+8)*sol[1] + (16*my+8)*sol[2] ) - mv.x ) > meanx )
2399                  CHECK_MV16_ZERO;                                  || ( fabs(( sol[3] - (16*mx+8)*sol[2] + (16*my+8)*sol[1] ) - mv.y ) > meany ) )
2400                                    MBmask[mbnum]=0;
2401                            else
2402                                    num++;
2403                    }
2404    
2405  // previous frame MV is always possible          } while ( (oldnum != num) && (num>=4) );
2406    
2407          if (!MVzero(prevMB->i_mvs[0]))          if (num < 4)
2408                  if (!MVequal(prevMB->i_mvs[0], pmv[0]))          {
2409                          CHECK_MV16_CANDIDATE(prevMB->i_mvs[0].x, prevMB->i_mvs[0].y);                  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;
2410            } else {
 // 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;  
2411    
2412                    gmc.duv[0].x=(int)(sol[0]+0.5);
2413                    gmc.duv[0].y=(int)(sol[3]+0.5);
2414    
2415  /* Step 6: If MinSAD <= thresa goto Step 10.                  gmc.duv[1].x=(int)(sol[1]*pParam->width+0.5);
2416     If Motion Vector equal to Previous frame motion vector and MinSAD<PrevFrmSAD goto Step 10.                  gmc.duv[1].y=(int)(-sol[2]*pParam->width+0.5);
 */  
2417    
2418          if ((iMinSAD <= threshA) ||                  gmc.duv[2].x=0;
2419                  (MVequal(*currMV, prevMB->i_mvs[0]) &&                  gmc.duv[2].y=0;
                  ((int32_t) iMinSAD < prevMB->i_sad16))) {  
   
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto PMVfastInt16_Terminate_with_Refine;  
2420          }          }
2421    //      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);
2422    
2423            free(MBmask);
2424    
2425  /************ (Diamond Search)  **************/          return gmc;
2426  /*  }
    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.  
 */  
   
         if (MotionFlags & PMV_USESQUARES16)  
                 MainSearchPtr = Square16_MainSearch;  
         else if (MotionFlags & PMV_ADVANCEDDIAMOND16)  
                 MainSearchPtr = AdvDiamond16_MainSearch;  
         else  
                 MainSearchPtr = Diamond16_MainSearch;  
2427    
2428          backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */  // functions which perform BITS-based search/bitcount
2429    
2430    static int
2431    CountMBBitsInter(SearchData * const Data,
2432                                    const MACROBLOCK * const pMBs, const int x, const int y,
2433                                    const MBParam * const pParam,
2434                                    const uint32_t MotionFlags)
2435    {
2436            int i, iDirection;
2437            int32_t bsad[5];
2438    
2439  /* default: use best prediction as starting point for one call of PMVfast_MainSearch */          CheckCandidate = CheckCandidateBits16;
         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);  
2440    
2441          if (iSAD < iMinSAD) {          if (Data->qpel) {
2442                  *currMV = newMV;                  for(i = 0; i < 5; i++) {
2443                  iMinSAD = iSAD;                          Data->currentMV[i].x = Data->currentQMV[i].x/2;
2444                            Data->currentMV[i].y = Data->currentQMV[i].y/2;
2445          }          }
2446                    Data->qpel_precision = 1;
2447                    CheckCandidateBits16(Data->currentQMV[0].x, Data->currentQMV[0].y, 255, &iDirection, Data);
2448    
2449          if (MotionFlags & PMV_EXTSEARCH16) {                  //checking if this vector is perfect. if it is, we stop.
2450  /* extended: search (up to) two more times: orignal prediction and (0,0) */                  if (Data->temp[0] == 0 && Data->temp[1] == 0 && Data->temp[2] == 0 && Data->temp[3] == 0)
2451                            return 0; //quick stop
2452    
2453                  if (!(MVequal(pmv[0], backupMV))) {                  if (MotionFlags & (XVID_ME_HALFPELREFINE16_BITS | XVID_ME_EXTSEARCH_BITS)) { //we have to prepare for halfpixel-precision search
2454                          iSAD =                          for(i = 0; i < 5; i++) bsad[i] = Data->iMinSAD[i];
2455                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,                          get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
2456                                                                    pmv[0].x, pmv[0].y, iMinSAD, &newMV, center_x, center_y,                                                  pParam->width, pParam->height, Data->iFcode - Data->qpel, 0, Data->rrv);
2457                                                                    min_dx, max_dx, min_dy, max_dy, iEdgedWidth,                          Data->qpel_precision = 0;
2458                                                                    iDiamondSize, iFcode, iQuant, iFound);                          if (Data->currentQMV->x & 1 || Data->currentQMV->y & 1)
2459                                    CheckCandidateBits16(Data->currentMV[0].x, Data->currentMV[0].y, 255, &iDirection, Data);
                         if (iSAD < iMinSAD) {  
                                 *currMV = newMV;  
                                 iMinSAD = iSAD;  
                         }  
2460                  }                  }
2461    
2462                  if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {          } else { // not qpel
                         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);  
2463    
2464                          if (iSAD < iMinSAD) {                  CheckCandidateBits16(Data->currentMV[0].x, Data->currentMV[0].y, 255, &iDirection, Data);
2465                                  *currMV = newMV;                  //checking if this vector is perfect. if it is, we stop.
2466                                  iMinSAD = iSAD;                  if (Data->temp[0] == 0 && Data->temp[1] == 0 && Data->temp[2] == 0 && Data->temp[3] == 0) {
2467                            return 0; //inter
2468                          }                          }
2469                  }                  }
         }  
   
 /*  
    Step 10:  The motion vector is chosen according to the block corresponding to MinSAD.  
 */  
   
 PMVfastInt16_Terminate_with_Refine:  
2470    
2471          pMB->i_mvs[0] = pMB->i_mvs[1] = pMB->i_mvs[2] = pMB->i_mvs[3] = pMB->i_mv16 = *currMV;          if (MotionFlags&XVID_ME_EXTSEARCH_BITS) SquareSearch(Data->currentMV->x, Data->currentMV->y, Data, iDirection);
         pMB->i_sad8[0] = pMB->i_sad8[1] = pMB->i_sad8[2] = pMB->i_sad8[3] = pMB->i_sad16 = iMinSAD;  
2472    
2473          if (MotionFlags & PMV_HALFPELREFINE16)  // perform final half-pel step          if (MotionFlags&XVID_ME_HALFPELREFINE16_BITS) SubpelRefine(Data);
                 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);  
2474    
2475          pmv[0] = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 0);          // get _REAL_ prediction (halfpel possible)          if (Data->qpel) {
2476                    if (MotionFlags&(XVID_ME_EXTSEARCH_BITS | XVID_ME_HALFPELREFINE16_BITS)) { // there was halfpel-precision search
2477  PMVfastInt16_Terminate_without_Refine:                          for(i = 0; i < 5; i++) if (bsad[i] > Data->iMinSAD[i]) {
2478          currPMV->x = currMV->x - center_x;                                  Data->currentQMV[i].x = 2 * Data->currentMV[i].x; // we have found a better match
2479          currPMV->y = currMV->y - center_y;                                  Data->currentQMV[i].y = 2 * Data->currentMV[i].y;
         return iMinSAD;  
2480  }  }
2481    
2482                            // preparing for qpel-precision search
2483                            Data->qpel_precision = 1;
2484                            get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
2485                                            pParam->width, pParam->height, Data->iFcode, 1, 0);
2486                    }
2487                    if (MotionFlags&XVID_ME_QUARTERPELREFINE16_BITS) SubpelRefine(Data);
2488            }
2489    
2490            if (MotionFlags&XVID_ME_CHECKPREDICTION_BITS) { //let's check vector equal to prediction
2491                    VECTOR * v = Data->qpel ? Data->currentQMV : Data->currentMV;
2492                    if (!(Data->predMV.x == v->x && Data->predMV.y == v->y))
2493                            CheckCandidateBits16(Data->predMV.x, Data->predMV.y, 255, &iDirection, Data);
2494            }
2495            return Data->iMinSAD[0];
2496    }
2497    
 /* ***********************************************************  
         bvop motion estimation  
 ***************************************************************/  
2498    
2499  void  static int
2500  MotionEstimationBVOP(MBParam * const pParam,  CountMBBitsInter4v(const SearchData * const Data,
2501                                           FRAMEINFO * const frame,                                          MACROBLOCK * const pMB, const MACROBLOCK * const pMBs,
2502                                           const int32_t time_bp,                                          const int x, const int y,
2503                                           const int32_t time_pp,                                          const MBParam * const pParam, const uint32_t MotionFlags,
2504                                           // forward (past) reference                                          const VECTOR * const backup)
                                          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)  
2505  {  {
         const int mb_width = pParam->mb_width;  
         const int mb_height = pParam->mb_height;  
         const int edged_width = pParam->edged_width;  
2506    
2507          const int32_t iWidth = pParam->width;          int cbp = 0, bits = 0, t = 0, i, iDirection;
2508          const int32_t iHeight = pParam->height;          SearchData Data2, *Data8 = &Data2;
2509            int sumx = 0, sumy = 0;
2510            int16_t *in = Data->dctSpace, *coeff = Data->dctSpace + 64;
2511            uint8_t * ptr;
2512    
2513            memcpy(Data8, Data, sizeof(SearchData));
2514            CheckCandidate = CheckCandidateBits8;
2515    
2516            for (i = 0; i < 4; i++) { //for all luma blocks
2517    
2518                    Data8->iMinSAD = Data->iMinSAD + i + 1;
2519                    Data8->currentMV = Data->currentMV + i + 1;
2520                    Data8->currentQMV = Data->currentQMV + i + 1;
2521                    Data8->Cur = Data->Cur + 8*((i&1) + (i>>1)*Data->iEdgedWidth);
2522                    Data8->RefP[0] = Data->RefP[0] + 8*((i&1) + (i>>1)*Data->iEdgedWidth);
2523                    Data8->RefP[2] = Data->RefP[2] + 8*((i&1) + (i>>1)*Data->iEdgedWidth);
2524                    Data8->RefP[1] = Data->RefP[1] + 8*((i&1) + (i>>1)*Data->iEdgedWidth);
2525                    Data8->RefP[3] = Data->RefP[3] + 8*((i&1) + (i>>1)*Data->iEdgedWidth);
2526    
2527                    if(Data->qpel) {
2528                            Data8->predMV = get_qpmv2(pMBs, pParam->mb_width, 0, x, y, i);
2529                            if (i != 0)     t = d_mv_bits(  Data8->currentQMV->x, Data8->currentQMV->y,
2530                                                                                    Data8->predMV, Data8->iFcode, 0, 0);
2531                    } else {
2532                            Data8->predMV = get_pmv2(pMBs, pParam->mb_width, 0, x, y, i);
2533                            if (i != 0)     t = d_mv_bits(  Data8->currentMV->x, Data8->currentMV->y,
2534                                                                                    Data8->predMV, Data8->iFcode, 0, 0);
2535                    }
2536    
2537          int i, j, k;                  get_range(&Data8->min_dx, &Data8->max_dx, &Data8->min_dy, &Data8->max_dy, 2*x + (i&1), 2*y + (i>>1), 8,
2538                                            pParam->width, pParam->height, Data8->iFcode, Data8->qpel, 0);
2539    
2540          static const VECTOR zeroMV={0,0};                  *Data8->iMinSAD += t;
2541    
2542          int f_sad16;    /* forward (as usual) search */                  Data8->qpel_precision = Data8->qpel;
2543          int b_sad16;    /* backward (only in b-frames) search */                  // checking the vector which has been found by SAD-based 8x8 search (if it's different than the one found so far)
2544          int i_sad16;    /* interpolated (both direction, b-frames only) */                  {
2545          int d_sad16;    /* direct mode (assume almost linear motion) */                          VECTOR *v = Data8->qpel ? Data8->currentQMV : Data8->currentMV;
2546                            if (!MVequal (*v, backup[i+1]) )
2547                                    CheckCandidateBits8(backup[i+1].x, backup[i+1].y, 255, &iDirection, Data8);
2548                    }
2549    
2550          int best_sad;                  if (Data8->qpel) {
2551                            if (MotionFlags&XVID_ME_HALFPELREFINE8_BITS || (MotionFlags&XVID_ME_EXTSEARCH8 && MotionFlags&XVID_ME_EXTSEARCH_BITS)) { // halfpixel motion search follows
2552                                    int32_t s = *Data8->iMinSAD;
2553                                    Data8->currentMV->x = Data8->currentQMV->x/2;
2554                                    Data8->currentMV->y = Data8->currentQMV->y/2;
2555                                    Data8->qpel_precision = 0;
2556                                    get_range(&Data8->min_dx, &Data8->max_dx, &Data8->min_dy, &Data8->max_dy, 2*x + (i&1), 2*y + (i>>1), 8,
2557                                                            pParam->width, pParam->height, Data8->iFcode - 1, 0, 0);
2558    
2559          VECTOR f_predMV, b_predMV;      /* there is no prediction for direct mode*/                                  if (Data8->currentQMV->x & 1 || Data8->currentQMV->y & 1)
2560          VECTOR f_interpolMV, b_interpolMV;                                          CheckCandidateBits8(Data8->currentMV->x, Data8->currentMV->y, 255, &iDirection, Data8);
         VECTOR pmv_dontcare;  
2561    
2562          int min_dx, max_dx, min_dy, max_dy;                                  if (MotionFlags & XVID_ME_EXTSEARCH8 && MotionFlags & XVID_ME_EXTSEARCH_BITS)
2563          int f_min_dx, f_max_dx, f_min_dy, f_max_dy;                                          SquareSearch(Data8->currentMV->x, Data8->currentMV->x, Data8, 255);
         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;  
2564    
2565          const int64_t TRB = (int32_t)time_pp - (int32_t)time_bp;                                  if (MotionFlags & XVID_ME_HALFPELREFINE8_BITS)
2566      const int64_t TRD = (int32_t)time_pp;                                          SubpelRefine(Data8);
2567    
2568          // fprintf(stderr,"TRB = %lld  TRD = %lld  time_bp =%d time_pp =%d\n\n",TRB,TRD,time_bp,time_pp);                                  if(s > *Data8->iMinSAD) { //we have found a better match
2569          // note: i==horizontal, j==vertical                                          Data8->currentQMV->x = 2*Data8->currentMV->x;
2570          for (j = 0; j < mb_height; j++) {                                          Data8->currentQMV->y = 2*Data8->currentMV->y;
2571                                    }
2572    
2573                  f_predMV = zeroMV;      /* prediction is reset at left boundary */                                  Data8->qpel_precision = 1;
2574                  b_predMV = zeroMV;                                  get_range(&Data8->min_dx, &Data8->max_dx, &Data8->min_dy, &Data8->max_dy, 2*x + (i&1), 2*y + (i>>1), 8,
2575                                                            pParam->width, pParam->height, Data8->iFcode, 1, 0);
2576    
2577                  for (i = 0; i < mb_width; i++) {                          }
2578                          MACROBLOCK *mb = &frame->mbs[i + j * mb_width];                          if (MotionFlags & XVID_ME_QUARTERPELREFINE8_BITS) SubpelRefine(Data8);
                         const MACROBLOCK *f_mb = &f_mbs[i + j * mb_width];  
                         const MACROBLOCK *b_mb = &b_mbs[i + j * mb_width];  
2579    
2580                          mb->deltamv=zeroMV;                  } else { // not qpel
2581    
2582  /* special case, if collocated block is SKIPed: encoding is forward (0,0), cpb=0 without further ado */                          if (MotionFlags & XVID_ME_EXTSEARCH8 && MotionFlags & XVID_ME_EXTSEARCH_BITS) //extsearch
2583                                    SquareSearch(Data8->currentMV->x, Data8->currentMV->x, Data8, 255);
2584    
2585                          if (b_mb->mode == MODE_INTER && b_mb->cbp == 0 &&                          if (MotionFlags & XVID_ME_HALFPELREFINE8_BITS)
2586                                  b_mb->mvs[0].x == 0 && b_mb->mvs[0].y == 0) {                                  SubpelRefine(Data8); //halfpel refinement
                                 mb->mode = MODE_NOT_CODED;  
                                 mb->b_mvs[0] = mb->mvs[0] = zeroMV;  
                                 continue;  
2587                          }                          }
2588    
2589                          if (b_mb->mode == MODE_INTER4V)                  //checking vector equal to predicion
2590                          {                  if (i != 0 && MotionFlags & XVID_ME_CHECKPREDICTION_BITS) {
2591                                  d_sad16 = 0;                          const VECTOR * v = Data->qpel ? Data8->currentQMV : Data8->currentMV;
2592                          /* same method of scaling as in decoder.c, so we copy from there */                          if (!MVequal(*v, Data8->predMV))
2593                      for (k = 0; k < 4; k++) {                                  CheckCandidateBits8(Data8->predMV.x, Data8->predMV.y, 255, &iDirection, Data8);
2594                    }
2595    
2596                                          mb->directmv[k] = b_mb->mvs[k];                  bits += *Data8->iMinSAD;
2597                    if (bits >= Data->iMinSAD[0]) return bits; // no chances for INTER4V
2598    
2599                                          mb->mvs[k].x = (int32_t) ((TRB * mb->directmv[k].x) / TRD + mb->deltamv.x);                  // MB structures for INTER4V mode; we have to set them here, we don't have predictor anywhere else
2600                      mb->b_mvs[k].x = (int32_t) ((mb->deltamv.x == 0)                  if(Data->qpel) {
2601                                                                                  ? ((TRB - TRD) * mb->directmv[k].x) / TRD                          pMB->pmvs[i].x = Data8->currentQMV->x - Data8->predMV.x;
2602                                              : mb->mvs[k].x - mb->directmv[k].x);                          pMB->pmvs[i].y = Data8->currentQMV->y - Data8->predMV.y;
2603                            pMB->qmvs[i] = *Data8->currentQMV;
2604                      mb->mvs[k].y = (int32_t) ((TRB * mb->directmv[k].y) / TRD + mb->deltamv.y);                          sumx += Data8->currentQMV->x/2;
2605                          mb->b_mvs[k].y = (int32_t) ((mb->deltamv.y == 0)                          sumy += Data8->currentQMV->y/2;
2606                                                                                  ? ((TRB - TRD) * mb->directmv[k].y) / TRD                  } else {
2607                                              : mb->mvs[k].y - mb->directmv[k].y);                          pMB->pmvs[i].x = Data8->currentMV->x - Data8->predMV.x;
2608                            pMB->pmvs[i].y = Data8->currentMV->y - Data8->predMV.y;
2609                                          d_sad16 +=                          sumx += Data8->currentMV->x;
2610                                                  sad8bi(frame->image.y + (2*i+(k&1))*8 + (2*j+(k>>1))*8*edged_width,                          sumy += Data8->currentMV->y;
                                                   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);  
                                 }  
2611                          }                          }
2612                          else                  pMB->mvs[i] = *Data8->currentMV;
2613                          {                  pMB->sad8[i] = 4 * *Data8->iMinSAD;
2614                                  mb->directmv[3] = mb->directmv[2] = mb->directmv[1] =                  if (Data8->temp[0]) cbp |= 1 << (5 - i);
                                         mb->directmv[0] = b_mb->mvs[0];  
2615    
2616                                  mb->mvs[0].x = (int32_t) ((TRB * mb->directmv[0].x) / TRD + mb->deltamv.x);          } // /for all luma blocks
                     mb->b_mvs[0].x = (int32_t) ((mb->deltamv.x == 0)  
                                                                         ? ((TRB - TRD) * mb->directmv[0].x) / TRD  
                                     : mb->mvs[0].x - mb->directmv[0].x);  
   
                     mb->mvs[0].y = (int32_t) ((TRB * mb->directmv[0].y) / TRD + mb->deltamv.y);  
                 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);  
2617    
2618              }          bits += xvid_cbpy_tab[15-(cbp>>2)].len;
                     d_sad16 += calc_delta_16(mb->deltamv.x, mb->deltamv.y, 1, frame->quant);  
2619    
2620                          // forward search          // let's check chroma
2621                          f_sad16 = SEARCH16(f_ref->y, f_refH->y, f_refV->y, f_refHV->y,          sumx = (sumx >> 3) + roundtab_76[sumx & 0xf];
2622                                                  &frame->image, i, j,          sumy = (sumy >> 3) + roundtab_76[sumy & 0xf];
                                                 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);  
2623    
2624            //chroma U
2625            ptr = interpolate8x8_switch2(Data->RefQ + 64, Data->RefP[4], 0, 0, sumx, sumy, Data->iEdgedWidth/2, Data->rounding);
2626            transfer_8to16subro(in, Data->CurU, ptr, Data->iEdgedWidth/2);
2627            bits += Block_CalcBits(coeff, in, Data->iQuant, Data->quant_type, &cbp, 4, 0);
2628    
2629                          // backward search          if (bits >= *Data->iMinSAD) return bits;
2630                          b_sad16 = SEARCH16(b_ref->y, b_refH->y, b_refV->y, b_refHV->y,  
2631                                                  &frame->image, i, j,          //chroma V
2632                                                  mb->b_mvs[0].x, mb->b_mvs[0].y,         /* start point b_directMV */          ptr = interpolate8x8_switch2(Data->RefQ + 64, Data->RefP[5], 0, 0, sumx, sumy, Data->iEdgedWidth/2, Data->rounding);
2633                                                  b_predMV.x, b_predMV.y,                         /* center is b-prediction */          transfer_8to16subro(in, Data->CurV, ptr, Data->iEdgedWidth/2);
2634                                                  frame->motion_flags,          bits += Block_CalcBits(coeff, in, Data->iQuant, Data->quant_type, &cbp, 5, 0);
                                                 frame->quant, frame->bcode, pParam,  
                                                 b_mbs, b_mbs,  
                                                 &mb->b_mvs[0], &pmv_dontcare);  
   
                         i_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);  
                     i_sad16 += calc_delta_16(mb->mvs[0].x-f_predMV.x, mb->mvs[0].y-f_predMV.y,  
                                                                 frame->fcode, frame->quant);  
                     i_sad16 += calc_delta_16(mb->b_mvs[0].x-b_predMV.x, mb->b_mvs[0].y-b_predMV.y,  
                                                                 frame->bcode, frame->quant);  
   
                         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;  
                         } else {  
                                 best_sad = b_sad16;  
                                 mb->mode = MODE_BACKWARD;  
                         }  
2635    
2636                          if (i_sad16 < best_sad) {          bits += mcbpc_inter_tab[(MODE_INTER4V & 7) | ((cbp & 3) << 3)].len;
2637                                  best_sad = i_sad16;  
2638                                  mb->mode = MODE_INTERPOLATE;          return bits;
2639                          }                          }
2640    
                         if (d_sad16 < best_sad) {  
2641    
2642                                  if (b_mb->mode == MODE_INTER4V)  static int
2643    CountMBBitsIntra(const SearchData * const Data)
2644                                  {                                  {
2645            int bits = 1; //this one is ac/dc prediction flag. always 1.
2646            int cbp = 0, i, t, dc = 1024, b_dc;
2647            int16_t *in = Data->dctSpace, * coeff = Data->dctSpace + 64;
2648            uint32_t iDcScaler = get_dc_scaler(Data->iQuant, 1);
2649    
2650                                  /* how to calc vectors is defined in standard. mvs[] and b_mvs[] are only for motion compensation */          for(i = 0; i < 4; i++) {
2651                                  /* for the bitstream, the value mb->deltamv is read directly */                  int s = 8*((i&1) + (i>>1)*Data->iEdgedWidth);
2652                    transfer_8to16copy(in, Data->Cur + s, Data->iEdgedWidth);
2653                              for (k = 0; k < 4; k++) {                  fdct(in);
2654                    b_dc = in[0];
2655                    in[0] -= dc;
2656                    dc = b_dc;
2657                    if (Data->quant_type == 0) quant_intra(coeff, in, Data->iQuant, iDcScaler);
2658                    else quant4_intra(coeff, in, Data->iQuant, iDcScaler);
2659    
2660                                                  mb->mvs[k].x = (int32_t) ((TRB * mb->directmv[k].x) / TRD + mb->deltamv.x);                  bits += t = CodeCoeffIntra_CalcBits(coeff, scan_tables[0]) + dcy_tab[coeff[0] + 255].len;
2661                              mb->b_mvs[k].x = (int32_t) ((mb->deltamv.x == 0)                  Data->temp[i] = t;
2662                                                                                          ? ((TRB - TRD) * mb->directmv[k].x) / TRD                  if (t != 0)  cbp |= 1 << (5 - i);
2663                                                      : mb->mvs[k].x - mb->directmv[k].x);                  if (bits >= Data->iMinSAD[0]) return bits;
   
                             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);  
                                         }  
2664                                  }                                  }
                                 else  
                                 {  
                                         mb->mvs[0].x = (int32_t) ((TRB * mb->directmv[0].x) / TRD + mb->deltamv.x);  
2665    
2666                      mb->b_mvs[0].x = (int32_t) ((mb->deltamv.x == 0)          bits += xvid_cbpy_tab[cbp>>2].len;
                                                                                 ? ((TRB - TRD) * mb->directmv[0].x) / TRD  
                                         : mb->mvs[0].x - mb->directmv[0].x);  
2667    
2668                              mb->mvs[0].y = (int32_t) ((TRB * mb->directmv[0].y) / TRD + mb->deltamv.y);          iDcScaler = get_dc_scaler(Data->iQuant, 0);
2669    
2670                          mb->b_mvs[0].y = (int32_t) ((mb->deltamv.y == 0)          //chroma U
2671                                                                                  ? ((TRB - TRD) * mb->directmv[0].y) / TRD          transfer_8to16copy(in, Data->CurU, Data->iEdgedWidth/2);
2672                                              : mb->mvs[0].y - mb->directmv[0].y);          fdct(in);
2673            in[0] -= 1024;
2674            if (Data->quant_type == 0) quant_intra(coeff, in, Data->iQuant, iDcScaler);
2675            else quant4_intra(coeff, in, Data->iQuant, iDcScaler);
2676    
2677                                          mb->mvs[3] = mb->mvs[2] = mb->mvs[1] = mb->mvs[0];          bits += t = CodeCoeffIntra_CalcBits(coeff, scan_tables[0]) + dcc_tab[coeff[0] + 255].len;
2678                                          mb->b_mvs[3] = mb->b_mvs[2] = mb->b_mvs[1] = mb->b_mvs[0];          if (t != 0) cbp |= 1 << (5 - 4);
                 }  
2679    
2680                                  best_sad = d_sad16;          if (bits >= Data->iMinSAD[0]) return bits;
                                 mb->mode = MODE_DIRECT;  
                         }  
2681    
2682                          switch (mb->mode)          //chroma V
2683                          {          transfer_8to16copy(in, Data->CurV, Data->iEdgedWidth/2);
2684                                  case MODE_FORWARD:          fdct(in);
2685                                          f_count++;          in[0] -= 1024;
2686                                          f_predMV = mb->mvs[0];          if (Data->quant_type == 0) quant_intra(coeff, in, Data->iQuant, iDcScaler);
2687                                          break;          else quant4_intra(coeff, in, Data->iQuant, iDcScaler);
                                 case MODE_BACKWARD:  
                                         b_count++;  
                                         b_predMV = mb->b_mvs[0];  
2688    
2689                                          break;          bits += t = CodeCoeffIntra_CalcBits(coeff, scan_tables[0]) + dcc_tab[coeff[0] + 255].len;
2690                                  case MODE_INTERPOLATE:          if (t != 0) cbp |= 1 << (5 - 5);
                                         i_count++;  
                                         mb->mvs[0] = f_interpolMV;  
                                         mb->b_mvs[0] = b_interpolMV;  
                                         f_predMV = mb->mvs[0];  
                                         b_predMV = mb->b_mvs[0];  
                                         break;  
                                 case MODE_DIRECT:  
                                         d_count++;  
                                         break;  
                                 default:  
                                         break;  
                         }  
   
                 }  
         }  
2691    
2692  #ifdef _DEBUG_BFRAME_STAT          bits += mcbpc_inter_tab[(MODE_INTRA & 7) | ((cbp & 3) << 3)].len;
         fprintf(stderr,"B-Stat: F: %04d   B: %04d   I: %04d  D: %04d\n",  
                                 f_count,b_count,i_count,d_count);  
 #endif  
2693    
2694            return bits;
2695  }  }

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

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