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

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

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