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

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

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

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

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

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