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

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

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

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

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

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