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

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

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

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

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

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