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

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

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