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

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

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

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

Legend:
Removed from v.1.45  
changed lines
  Added in v.1.72

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