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

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

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