FFmpeg
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
motion_est_template.c
Go to the documentation of this file.
1 /*
2  * Motion estimation
3  * Copyright (c) 2002-2004 Michael Niedermayer
4  *
5  * This file is part of FFmpeg.
6  *
7  * FFmpeg is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * FFmpeg is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with FFmpeg; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21 
22 /**
23  * @file
24  * Motion estimation template.
25  */
26 
27 #include "mpegvideo.h"
28 
29 //Let us hope gcc will remove the unused vars ...(gcc 3.2.2 seems to do it ...)
30 #define LOAD_COMMON\
31  uint32_t av_unused * const score_map= c->score_map;\
32  const int av_unused xmin= c->xmin;\
33  const int av_unused ymin= c->ymin;\
34  const int av_unused xmax= c->xmax;\
35  const int av_unused ymax= c->ymax;\
36  uint8_t *mv_penalty= c->current_mv_penalty;\
37  const int pred_x= c->pred_x;\
38  const int pred_y= c->pred_y;\
39 
40 #define CHECK_HALF_MV(dx, dy, x, y)\
41 {\
42  const int hx= 2*(x)+(dx);\
43  const int hy= 2*(y)+(dy);\
44  d= cmp_hpel(s, x, y, dx, dy, size, h, ref_index, src_index, cmp_sub, chroma_cmp_sub, flags);\
45  d += (mv_penalty[hx - pred_x] + mv_penalty[hy - pred_y])*penalty_factor;\
46  COPY3_IF_LT(dmin, d, bx, hx, by, hy)\
47 }
48 
50  int *mx_ptr, int *my_ptr, int dmin,
51  int src_index, int ref_index,
52  int size, int h)
53 {
54  MotionEstContext * const c= &s->me;
55  const int mx = *mx_ptr;
56  const int my = *my_ptr;
57  const int penalty_factor= c->sub_penalty_factor;
58  me_cmp_func cmp_sub, chroma_cmp_sub;
59  int bx=2*mx, by=2*my;
60 
62  int flags= c->sub_flags;
63 
64  //FIXME factorize
65 
66  cmp_sub = s->mecc.me_sub_cmp[size];
67  chroma_cmp_sub = s->mecc.me_sub_cmp[size + 1];
68 
69  if(c->skip){ //FIXME move out of hpel?
70  *mx_ptr = 0;
71  *my_ptr = 0;
72  return dmin;
73  }
74 
75  if(c->avctx->me_cmp != c->avctx->me_sub_cmp){
76  dmin= cmp(s, mx, my, 0, 0, size, h, ref_index, src_index, cmp_sub, chroma_cmp_sub, flags);
77  if(mx || my || size>0)
78  dmin += (mv_penalty[2*mx - pred_x] + mv_penalty[2*my - pred_y])*penalty_factor;
79  }
80 
81  if (mx > xmin && mx < xmax &&
82  my > ymin && my < ymax) {
83  int d= dmin;
84  const int index= (my<<ME_MAP_SHIFT) + mx;
85  const int t= score_map[(index-(1<<ME_MAP_SHIFT))&(ME_MAP_SIZE-1)]
86  + (mv_penalty[bx - pred_x] + mv_penalty[by-2 - pred_y])*c->penalty_factor;
87  const int l= score_map[(index- 1 )&(ME_MAP_SIZE-1)]
88  + (mv_penalty[bx-2 - pred_x] + mv_penalty[by - pred_y])*c->penalty_factor;
89  const int r= score_map[(index+ 1 )&(ME_MAP_SIZE-1)]
90  + (mv_penalty[bx+2 - pred_x] + mv_penalty[by - pred_y])*c->penalty_factor;
91  const int b= score_map[(index+(1<<ME_MAP_SHIFT))&(ME_MAP_SIZE-1)]
92  + (mv_penalty[bx - pred_x] + mv_penalty[by+2 - pred_y])*c->penalty_factor;
93 
94 #if defined(ASSERT_LEVEL) && ASSERT_LEVEL > 1
95  unsigned key;
96  unsigned map_generation= c->map_generation;
97  key= ((my-1)<<ME_MAP_MV_BITS) + (mx) + map_generation;
98  av_assert2(c->map[(index-(1<<ME_MAP_SHIFT))&(ME_MAP_SIZE-1)] == key);
99  key= ((my+1)<<ME_MAP_MV_BITS) + (mx) + map_generation;
100  av_assert2(c->map[(index+(1<<ME_MAP_SHIFT))&(ME_MAP_SIZE-1)] == key);
101  key= ((my)<<ME_MAP_MV_BITS) + (mx+1) + map_generation;
102  av_assert2(c->map[(index+1)&(ME_MAP_SIZE-1)] == key);
103  key= ((my)<<ME_MAP_MV_BITS) + (mx-1) + map_generation;
104  av_assert2(c->map[(index-1)&(ME_MAP_SIZE-1)] == key);
105 #endif
106  if(t<=b){
107  CHECK_HALF_MV(0, 1, mx ,my-1)
108  if(l<=r){
109  CHECK_HALF_MV(1, 1, mx-1, my-1)
110  if(t+r<=b+l){
111  CHECK_HALF_MV(1, 1, mx , my-1)
112  }else{
113  CHECK_HALF_MV(1, 1, mx-1, my )
114  }
115  CHECK_HALF_MV(1, 0, mx-1, my )
116  }else{
117  CHECK_HALF_MV(1, 1, mx , my-1)
118  if(t+l<=b+r){
119  CHECK_HALF_MV(1, 1, mx-1, my-1)
120  }else{
121  CHECK_HALF_MV(1, 1, mx , my )
122  }
123  CHECK_HALF_MV(1, 0, mx , my )
124  }
125  }else{
126  if(l<=r){
127  if(t+l<=b+r){
128  CHECK_HALF_MV(1, 1, mx-1, my-1)
129  }else{
130  CHECK_HALF_MV(1, 1, mx , my )
131  }
132  CHECK_HALF_MV(1, 0, mx-1, my)
133  CHECK_HALF_MV(1, 1, mx-1, my)
134  }else{
135  if(t+r<=b+l){
136  CHECK_HALF_MV(1, 1, mx , my-1)
137  }else{
138  CHECK_HALF_MV(1, 1, mx-1, my)
139  }
140  CHECK_HALF_MV(1, 0, mx , my)
141  CHECK_HALF_MV(1, 1, mx , my)
142  }
143  CHECK_HALF_MV(0, 1, mx , my)
144  }
145  av_assert2(bx >= xmin*2 && bx <= xmax*2 && by >= ymin*2 && by <= ymax*2);
146  }
147 
148  *mx_ptr = bx;
149  *my_ptr = by;
150 
151  return dmin;
152 }
153 
155  int *mx_ptr, int *my_ptr, int dmin,
156  int src_index, int ref_index,
157  int size, int h)
158 {
159  (*mx_ptr)<<=1;
160  (*my_ptr)<<=1;
161  return dmin;
162 }
163 
164 static inline int get_mb_score(MpegEncContext *s, int mx, int my,
165  int src_index, int ref_index, int size,
166  int h, int add_rate)
167 {
168  MotionEstContext * const c= &s->me;
169  const int penalty_factor= c->mb_penalty_factor;
170  const int flags= c->mb_flags;
171  const int qpel= flags & FLAG_QPEL;
172  const int mask= 1+2*qpel;
173  me_cmp_func cmp_sub, chroma_cmp_sub;
174  int d;
175 
177 
178  //FIXME factorize
179 
180  cmp_sub = s->mecc.mb_cmp[size];
181  chroma_cmp_sub = s->mecc.mb_cmp[size + 1];
182 
183  d= cmp(s, mx>>(qpel+1), my>>(qpel+1), mx&mask, my&mask, size, h, ref_index, src_index, cmp_sub, chroma_cmp_sub, flags);
184  //FIXME check cbp before adding penalty for (0,0) vector
185  if(add_rate && (mx || my || size>0))
186  d += (mv_penalty[mx - pred_x] + mv_penalty[my - pred_y])*penalty_factor;
187 
188  return d;
189 }
190 
191 int ff_get_mb_score(MpegEncContext *s, int mx, int my, int src_index,
192  int ref_index, int size, int h, int add_rate)
193 {
194  return get_mb_score(s, mx, my, src_index, ref_index, size, h, add_rate);
195 }
196 
197 #define CHECK_QUARTER_MV(dx, dy, x, y)\
198 {\
199  const int hx= 4*(x)+(dx);\
200  const int hy= 4*(y)+(dy);\
201  d= cmp_qpel(s, x, y, dx, dy, size, h, ref_index, src_index, cmpf, chroma_cmpf, flags);\
202  d += (mv_penalty[hx - pred_x] + mv_penalty[hy - pred_y])*penalty_factor;\
203  COPY3_IF_LT(dmin, d, bx, hx, by, hy)\
204 }
205 
207  int *mx_ptr, int *my_ptr, int dmin,
208  int src_index, int ref_index,
209  int size, int h)
210 {
211  MotionEstContext * const c= &s->me;
212  const int mx = *mx_ptr;
213  const int my = *my_ptr;
214  const int penalty_factor= c->sub_penalty_factor;
215  const unsigned map_generation = c->map_generation;
216  const int subpel_quality= c->avctx->me_subpel_quality;
217  uint32_t *map= c->map;
218  me_cmp_func cmpf, chroma_cmpf;
219  me_cmp_func cmp_sub, chroma_cmp_sub;
220 
222  int flags= c->sub_flags;
223 
224  cmpf = s->mecc.me_cmp[size];
225  chroma_cmpf = s->mecc.me_cmp[size + 1]; // FIXME: factorize
226  //FIXME factorize
227 
228  cmp_sub = s->mecc.me_sub_cmp[size];
229  chroma_cmp_sub = s->mecc.me_sub_cmp[size + 1];
230 
231  if(c->skip){ //FIXME somehow move up (benchmark)
232  *mx_ptr = 0;
233  *my_ptr = 0;
234  return dmin;
235  }
236 
237  if(c->avctx->me_cmp != c->avctx->me_sub_cmp){
238  dmin= cmp(s, mx, my, 0, 0, size, h, ref_index, src_index, cmp_sub, chroma_cmp_sub, flags);
239  if(mx || my || size>0)
240  dmin += (mv_penalty[4*mx - pred_x] + mv_penalty[4*my - pred_y])*penalty_factor;
241  }
242 
243  if (mx > xmin && mx < xmax &&
244  my > ymin && my < ymax) {
245  int bx=4*mx, by=4*my;
246  int d= dmin;
247  int i, nx, ny;
248  const int index= (my<<ME_MAP_SHIFT) + mx;
249  const int t= score_map[(index-(1<<ME_MAP_SHIFT) )&(ME_MAP_SIZE-1)];
250  const int l= score_map[(index- 1 )&(ME_MAP_SIZE-1)];
251  const int r= score_map[(index+ 1 )&(ME_MAP_SIZE-1)];
252  const int b= score_map[(index+(1<<ME_MAP_SHIFT) )&(ME_MAP_SIZE-1)];
253  const int c= score_map[(index )&(ME_MAP_SIZE-1)];
254  int best[8];
255  int best_pos[8][2];
256 
257  memset(best, 64, sizeof(int)*8);
258  if(s->me.dia_size>=2){
259  const int tl= score_map[(index-(1<<ME_MAP_SHIFT)-1)&(ME_MAP_SIZE-1)];
260  const int bl= score_map[(index+(1<<ME_MAP_SHIFT)-1)&(ME_MAP_SIZE-1)];
261  const int tr= score_map[(index-(1<<ME_MAP_SHIFT)+1)&(ME_MAP_SIZE-1)];
262  const int br= score_map[(index+(1<<ME_MAP_SHIFT)+1)&(ME_MAP_SIZE-1)];
263 
264  for(ny= -3; ny <= 3; ny++){
265  for(nx= -3; nx <= 3; nx++){
266  //FIXME this could overflow (unlikely though)
267  const int64_t t2= nx*nx*(tr + tl - 2*t) + 4*nx*(tr-tl) + 32*t;
268  const int64_t c2= nx*nx*( r + l - 2*c) + 4*nx*( r- l) + 32*c;
269  const int64_t b2= nx*nx*(br + bl - 2*b) + 4*nx*(br-bl) + 32*b;
270  int score= (ny*ny*(b2 + t2 - 2*c2) + 4*ny*(b2 - t2) + 32*c2 + 512)>>10;
271  int i;
272 
273  if((nx&3)==0 && (ny&3)==0) continue;
274 
275  score += (mv_penalty[4*mx + nx - pred_x] + mv_penalty[4*my + ny - pred_y])*penalty_factor;
276 
277 // if(nx&1) score-=1024*c->penalty_factor;
278 // if(ny&1) score-=1024*c->penalty_factor;
279 
280  for(i=0; i<8; i++){
281  if(score < best[i]){
282  memmove(&best[i+1], &best[i], sizeof(int)*(7-i));
283  memmove(&best_pos[i+1][0], &best_pos[i][0], sizeof(int)*2*(7-i));
284  best[i]= score;
285  best_pos[i][0]= nx + 4*mx;
286  best_pos[i][1]= ny + 4*my;
287  break;
288  }
289  }
290  }
291  }
292  }else{
293  int tl;
294  //FIXME this could overflow (unlikely though)
295  const int cx = 4*(r - l);
296  const int cx2= r + l - 2*c;
297  const int cy = 4*(b - t);
298  const int cy2= b + t - 2*c;
299  int cxy;
300 
301  if(map[(index-(1<<ME_MAP_SHIFT)-1)&(ME_MAP_SIZE-1)] == (my<<ME_MAP_MV_BITS) + mx + map_generation && 0){ //FIXME
302  tl= score_map[(index-(1<<ME_MAP_SHIFT)-1)&(ME_MAP_SIZE-1)];
303  }else{
304  tl= cmp(s, mx-1, my-1, 0, 0, size, h, ref_index, src_index, cmpf, chroma_cmpf, flags);//FIXME wrong if chroma me is different
305  }
306 
307  cxy= 2*tl + (cx + cy)/4 - (cx2 + cy2) - 2*c;
308 
309  av_assert2(16*cx2 + 4*cx + 32*c == 32*r);
310  av_assert2(16*cx2 - 4*cx + 32*c == 32*l);
311  av_assert2(16*cy2 + 4*cy + 32*c == 32*b);
312  av_assert2(16*cy2 - 4*cy + 32*c == 32*t);
313  av_assert2(16*cxy + 16*cy2 + 16*cx2 - 4*cy - 4*cx + 32*c == 32*tl);
314 
315  for(ny= -3; ny <= 3; ny++){
316  for(nx= -3; nx <= 3; nx++){
317  //FIXME this could overflow (unlikely though)
318  int score= ny*nx*cxy + nx*nx*cx2 + ny*ny*cy2 + nx*cx + ny*cy + 32*c; //FIXME factor
319  int i;
320 
321  if((nx&3)==0 && (ny&3)==0) continue;
322 
323  score += 32*(mv_penalty[4*mx + nx - pred_x] + mv_penalty[4*my + ny - pred_y])*penalty_factor;
324 // if(nx&1) score-=32*c->penalty_factor;
325  // if(ny&1) score-=32*c->penalty_factor;
326 
327  for(i=0; i<8; i++){
328  if(score < best[i]){
329  memmove(&best[i+1], &best[i], sizeof(int)*(7-i));
330  memmove(&best_pos[i+1][0], &best_pos[i][0], sizeof(int)*2*(7-i));
331  best[i]= score;
332  best_pos[i][0]= nx + 4*mx;
333  best_pos[i][1]= ny + 4*my;
334  break;
335  }
336  }
337  }
338  }
339  }
340  for(i=0; i<subpel_quality; i++){
341  nx= best_pos[i][0];
342  ny= best_pos[i][1];
343  CHECK_QUARTER_MV(nx&3, ny&3, nx>>2, ny>>2)
344  }
345 
346  av_assert2(bx >= xmin*4 && bx <= xmax*4 && by >= ymin*4 && by <= ymax*4);
347 
348  *mx_ptr = bx;
349  *my_ptr = by;
350  }else{
351  *mx_ptr =4*mx;
352  *my_ptr =4*my;
353  }
354 
355  return dmin;
356 }
357 
358 
359 #define CHECK_MV(x,y)\
360 {\
361  const unsigned key = ((y)<<ME_MAP_MV_BITS) + (x) + map_generation;\
362  const int index= (((y)<<ME_MAP_SHIFT) + (x))&(ME_MAP_SIZE-1);\
363  av_assert2((x) >= xmin);\
364  av_assert2((x) <= xmax);\
365  av_assert2((y) >= ymin);\
366  av_assert2((y) <= ymax);\
367  if(map[index]!=key){\
368  d= cmp(s, x, y, 0, 0, size, h, ref_index, src_index, cmpf, chroma_cmpf, flags);\
369  map[index]= key;\
370  score_map[index]= d;\
371  d += (mv_penalty[((x)<<shift)-pred_x] + mv_penalty[((y)<<shift)-pred_y])*penalty_factor;\
372  COPY3_IF_LT(dmin, d, best[0], x, best[1], y)\
373  }\
374 }
375 
376 #define CHECK_CLIPPED_MV(ax,ay)\
377 {\
378  const int Lx= ax;\
379  const int Ly= ay;\
380  const int Lx2= FFMAX(xmin, FFMIN(Lx, xmax));\
381  const int Ly2= FFMAX(ymin, FFMIN(Ly, ymax));\
382  CHECK_MV(Lx2, Ly2)\
383 }
384 
385 #define CHECK_MV_DIR(x,y,new_dir)\
386 {\
387  const unsigned key = ((y)<<ME_MAP_MV_BITS) + (x) + map_generation;\
388  const int index= (((y)<<ME_MAP_SHIFT) + (x))&(ME_MAP_SIZE-1);\
389  if(map[index]!=key){\
390  d= cmp(s, x, y, 0, 0, size, h, ref_index, src_index, cmpf, chroma_cmpf, flags);\
391  map[index]= key;\
392  score_map[index]= d;\
393  d += (mv_penalty[((x)<<shift)-pred_x] + mv_penalty[((y)<<shift)-pred_y])*penalty_factor;\
394  if(d<dmin){\
395  best[0]=x;\
396  best[1]=y;\
397  dmin=d;\
398  next_dir= new_dir;\
399  }\
400  }\
401 }
402 
403 #define check(x,y,S,v)\
404 if( (x)<(xmin<<(S)) ) av_log(NULL, AV_LOG_ERROR, "%d %d %d %d %d xmin" #v, xmin, (x), (y), s->mb_x, s->mb_y);\
405 if( (x)>(xmax<<(S)) ) av_log(NULL, AV_LOG_ERROR, "%d %d %d %d %d xmax" #v, xmax, (x), (y), s->mb_x, s->mb_y);\
406 if( (y)<(ymin<<(S)) ) av_log(NULL, AV_LOG_ERROR, "%d %d %d %d %d ymin" #v, ymin, (x), (y), s->mb_x, s->mb_y);\
407 if( (y)>(ymax<<(S)) ) av_log(NULL, AV_LOG_ERROR, "%d %d %d %d %d ymax" #v, ymax, (x), (y), s->mb_x, s->mb_y);\
408 
409 #define LOAD_COMMON2\
410  uint32_t *map= c->map;\
411  const int qpel= flags&FLAG_QPEL;\
412  const int shift= 1+qpel;\
413 
414 static av_always_inline int small_diamond_search(MpegEncContext * s, int *best, int dmin,
415  int src_index, int ref_index, int const penalty_factor,
416  int size, int h, int flags)
417 {
418  MotionEstContext * const c= &s->me;
419  me_cmp_func cmpf, chroma_cmpf;
420  int next_dir=-1;
423  unsigned map_generation = c->map_generation;
424 
425  cmpf = s->mecc.me_cmp[size];
426  chroma_cmpf = s->mecc.me_cmp[size + 1];
427 
428  { /* ensure that the best point is in the MAP as h/qpel refinement needs it */
429  const unsigned key = (best[1]<<ME_MAP_MV_BITS) + best[0] + map_generation;
430  const int index= ((best[1]<<ME_MAP_SHIFT) + best[0])&(ME_MAP_SIZE-1);
431  if(map[index]!=key){ //this will be executed only very rarey
432  score_map[index]= cmp(s, best[0], best[1], 0, 0, size, h, ref_index, src_index, cmpf, chroma_cmpf, flags);
433  map[index]= key;
434  }
435  }
436 
437  for(;;){
438  int d;
439  const int dir= next_dir;
440  const int x= best[0];
441  const int y= best[1];
442  next_dir=-1;
443 
444  if(dir!=2 && x>xmin) CHECK_MV_DIR(x-1, y , 0)
445  if(dir!=3 && y>ymin) CHECK_MV_DIR(x , y-1, 1)
446  if(dir!=0 && x<xmax) CHECK_MV_DIR(x+1, y , 2)
447  if(dir!=1 && y<ymax) CHECK_MV_DIR(x , y+1, 3)
448 
449  if(next_dir==-1){
450  return dmin;
451  }
452  }
453 }
454 
455 static int funny_diamond_search(MpegEncContext * s, int *best, int dmin,
456  int src_index, int ref_index, int const penalty_factor,
457  int size, int h, int flags)
458 {
459  MotionEstContext * const c= &s->me;
460  me_cmp_func cmpf, chroma_cmpf;
461  int dia_size;
464  unsigned map_generation = c->map_generation;
465 
466  cmpf = s->mecc.me_cmp[size];
467  chroma_cmpf = s->mecc.me_cmp[size + 1];
468 
469  for(dia_size=1; dia_size<=4; dia_size++){
470  int dir;
471  const int x= best[0];
472  const int y= best[1];
473 
474  if(dia_size&(dia_size-1)) continue;
475 
476  if( x + dia_size > xmax
477  || x - dia_size < xmin
478  || y + dia_size > ymax
479  || y - dia_size < ymin)
480  continue;
481 
482  for(dir= 0; dir<dia_size; dir+=2){
483  int d;
484 
485  CHECK_MV(x + dir , y + dia_size - dir);
486  CHECK_MV(x + dia_size - dir, y - dir );
487  CHECK_MV(x - dir , y - dia_size + dir);
488  CHECK_MV(x - dia_size + dir, y + dir );
489  }
490 
491  if(x!=best[0] || y!=best[1])
492  dia_size=0;
493  }
494  return dmin;
495 }
496 
497 static int hex_search(MpegEncContext * s, int *best, int dmin,
498  int src_index, int ref_index, int const penalty_factor,
499  int size, int h, int flags, int dia_size)
500 {
501  MotionEstContext * const c= &s->me;
502  me_cmp_func cmpf, chroma_cmpf;
505  unsigned map_generation = c->map_generation;
506  int x,y,d;
507  const int dec= dia_size & (dia_size-1);
508 
509  cmpf = s->mecc.me_cmp[size];
510  chroma_cmpf = s->mecc.me_cmp[size + 1];
511 
512  for(;dia_size; dia_size= dec ? dia_size-1 : dia_size>>1){
513  do{
514  x= best[0];
515  y= best[1];
516 
517  CHECK_CLIPPED_MV(x -dia_size , y);
518  CHECK_CLIPPED_MV(x+ dia_size , y);
519  CHECK_CLIPPED_MV(x+( dia_size>>1), y+dia_size);
520  CHECK_CLIPPED_MV(x+( dia_size>>1), y-dia_size);
521  if(dia_size>1){
522  CHECK_CLIPPED_MV(x+(-dia_size>>1), y+dia_size);
523  CHECK_CLIPPED_MV(x+(-dia_size>>1), y-dia_size);
524  }
525  }while(best[0] != x || best[1] != y);
526  }
527 
528  return dmin;
529 }
530 
531 static int l2s_dia_search(MpegEncContext * s, int *best, int dmin,
532  int src_index, int ref_index, int const penalty_factor,
533  int size, int h, int flags)
534 {
535  MotionEstContext * const c= &s->me;
536  me_cmp_func cmpf, chroma_cmpf;
539  unsigned map_generation = c->map_generation;
540  int x,y,i,d;
541  int dia_size= c->dia_size&0xFF;
542  const int dec= dia_size & (dia_size-1);
543  static const int hex[8][2]={{-2, 0}, {-1,-1}, { 0,-2}, { 1,-1},
544  { 2, 0}, { 1, 1}, { 0, 2}, {-1, 1}};
545 
546  cmpf = s->mecc.me_cmp[size];
547  chroma_cmpf = s->mecc.me_cmp[size + 1];
548 
549  for(; dia_size; dia_size= dec ? dia_size-1 : dia_size>>1){
550  do{
551  x= best[0];
552  y= best[1];
553  for(i=0; i<8; i++){
554  CHECK_CLIPPED_MV(x+hex[i][0]*dia_size, y+hex[i][1]*dia_size);
555  }
556  }while(best[0] != x || best[1] != y);
557  }
558 
559  x= best[0];
560  y= best[1];
561  CHECK_CLIPPED_MV(x+1, y);
562  CHECK_CLIPPED_MV(x, y+1);
563  CHECK_CLIPPED_MV(x-1, y);
564  CHECK_CLIPPED_MV(x, y-1);
565 
566  return dmin;
567 }
568 
569 static int umh_search(MpegEncContext * s, int *best, int dmin,
570  int src_index, int ref_index, int const penalty_factor,
571  int size, int h, int flags)
572 {
573  MotionEstContext * const c= &s->me;
574  me_cmp_func cmpf, chroma_cmpf;
577  unsigned map_generation = c->map_generation;
578  int x,y,x2,y2, i, j, d;
579  const int dia_size= c->dia_size&0xFE;
580  static const int hex[16][2]={{-4,-2}, {-4,-1}, {-4, 0}, {-4, 1}, {-4, 2},
581  { 4,-2}, { 4,-1}, { 4, 0}, { 4, 1}, { 4, 2},
582  {-2, 3}, { 0, 4}, { 2, 3},
583  {-2,-3}, { 0,-4}, { 2,-3},};
584 
585  cmpf = s->mecc.me_cmp[size];
586  chroma_cmpf = s->mecc.me_cmp[size + 1];
587 
588  x= best[0];
589  y= best[1];
590  for(x2=FFMAX(x-dia_size+1, xmin); x2<=FFMIN(x+dia_size-1,xmax); x2+=2){
591  CHECK_MV(x2, y);
592  }
593  for(y2=FFMAX(y-dia_size/2+1, ymin); y2<=FFMIN(y+dia_size/2-1,ymax); y2+=2){
594  CHECK_MV(x, y2);
595  }
596 
597  x= best[0];
598  y= best[1];
599  for(y2=FFMAX(y-2, ymin); y2<=FFMIN(y+2,ymax); y2++){
600  for(x2=FFMAX(x-2, xmin); x2<=FFMIN(x+2,xmax); x2++){
601  CHECK_MV(x2, y2);
602  }
603  }
604 
605 //FIXME prevent the CLIP stuff
606 
607  for(j=1; j<=dia_size/4; j++){
608  for(i=0; i<16; i++){
609  CHECK_CLIPPED_MV(x+hex[i][0]*j, y+hex[i][1]*j);
610  }
611  }
612 
613  return hex_search(s, best, dmin, src_index, ref_index, penalty_factor, size, h, flags, 2);
614 }
615 
616 static int full_search(MpegEncContext * s, int *best, int dmin,
617  int src_index, int ref_index, int const penalty_factor,
618  int size, int h, int flags)
619 {
620  MotionEstContext * const c= &s->me;
621  me_cmp_func cmpf, chroma_cmpf;
624  unsigned map_generation = c->map_generation;
625  int x,y, d;
626  const int dia_size= c->dia_size&0xFF;
627 
628  cmpf = s->mecc.me_cmp[size];
629  chroma_cmpf = s->mecc.me_cmp[size + 1];
630 
631  for(y=FFMAX(-dia_size, ymin); y<=FFMIN(dia_size,ymax); y++){
632  for(x=FFMAX(-dia_size, xmin); x<=FFMIN(dia_size,xmax); x++){
633  CHECK_MV(x, y);
634  }
635  }
636 
637  x= best[0];
638  y= best[1];
639  d= dmin;
640  CHECK_CLIPPED_MV(x , y);
641  CHECK_CLIPPED_MV(x+1, y);
642  CHECK_CLIPPED_MV(x, y+1);
643  CHECK_CLIPPED_MV(x-1, y);
644  CHECK_CLIPPED_MV(x, y-1);
645  best[0]= x;
646  best[1]= y;
647 
648  return d;
649 }
650 
651 #define SAB_CHECK_MV(ax,ay)\
652 {\
653  const unsigned key = ((ay)<<ME_MAP_MV_BITS) + (ax) + map_generation;\
654  const int index= (((ay)<<ME_MAP_SHIFT) + (ax))&(ME_MAP_SIZE-1);\
655  if(map[index]!=key){\
656  d= cmp(s, ax, ay, 0, 0, size, h, ref_index, src_index, cmpf, chroma_cmpf, flags);\
657  map[index]= key;\
658  score_map[index]= d;\
659  d += (mv_penalty[((ax)<<shift)-pred_x] + mv_penalty[((ay)<<shift)-pred_y])*penalty_factor;\
660  if(d < minima[minima_count-1].height){\
661  int j=0;\
662  \
663  while(d >= minima[j].height) j++;\
664 \
665  memmove(&minima [j+1], &minima [j], (minima_count - j - 1)*sizeof(Minima));\
666 \
667  minima[j].checked= 0;\
668  minima[j].height= d;\
669  minima[j].x= ax;\
670  minima[j].y= ay;\
671  \
672  i=-1;\
673  continue;\
674  }\
675  }\
676 }
677 
678 #define MAX_SAB_SIZE ME_MAP_SIZE
679 static int sab_diamond_search(MpegEncContext * s, int *best, int dmin,
680  int src_index, int ref_index, int const penalty_factor,
681  int size, int h, int flags)
682 {
683  MotionEstContext * const c= &s->me;
684  me_cmp_func cmpf, chroma_cmpf;
685  Minima minima[MAX_SAB_SIZE];
686  const int minima_count= FFABS(c->dia_size);
687  int i, j;
690  unsigned map_generation = c->map_generation;
691 
692  av_assert1(minima_count <= MAX_SAB_SIZE);
693 
694  cmpf = s->mecc.me_cmp[size];
695  chroma_cmpf = s->mecc.me_cmp[size + 1];
696 
697  /*Note j<MAX_SAB_SIZE is needed if MAX_SAB_SIZE < ME_MAP_SIZE as j can
698  become larger due to MVs overflowing their ME_MAP_MV_BITS bits space in map
699  */
700  for(j=i=0; i<ME_MAP_SIZE && j<MAX_SAB_SIZE; i++){
701  uint32_t key= map[i];
702 
703  key += (1<<(ME_MAP_MV_BITS-1)) + (1<<(2*ME_MAP_MV_BITS-1));
704 
705  if((key&((-1)<<(2*ME_MAP_MV_BITS))) != map_generation) continue;
706 
707  minima[j].height= score_map[i];
708  minima[j].x= key & ((1<<ME_MAP_MV_BITS)-1); key>>=ME_MAP_MV_BITS;
709  minima[j].y= key & ((1<<ME_MAP_MV_BITS)-1);
710  minima[j].x-= (1<<(ME_MAP_MV_BITS-1));
711  minima[j].y-= (1<<(ME_MAP_MV_BITS-1));
712 
713  // all entries in map should be in range except if the mv overflows their ME_MAP_MV_BITS bits space
714  if( minima[j].x > xmax || minima[j].x < xmin
715  || minima[j].y > ymax || minima[j].y < ymin)
716  continue;
717 
718  minima[j].checked=0;
719  if(minima[j].x || minima[j].y)
720  minima[j].height+= (mv_penalty[((minima[j].x)<<shift)-pred_x] + mv_penalty[((minima[j].y)<<shift)-pred_y])*penalty_factor;
721 
722  j++;
723  }
724 
725  qsort(minima, j, sizeof(Minima), minima_cmp);
726 
727  for(; j<minima_count; j++){
728  minima[j].height=256*256*256*64;
729  minima[j].checked=0;
730  minima[j].x= minima[j].y=0;
731  }
732 
733  for(i=0; i<minima_count; i++){
734  const int x= minima[i].x;
735  const int y= minima[i].y;
736  int d;
737 
738  if(minima[i].checked) continue;
739 
740  if( x >= xmax || x <= xmin
741  || y >= ymax || y <= ymin)
742  continue;
743 
744  SAB_CHECK_MV(x-1, y)
745  SAB_CHECK_MV(x+1, y)
746  SAB_CHECK_MV(x , y-1)
747  SAB_CHECK_MV(x , y+1)
748 
749  minima[i].checked= 1;
750  }
751 
752  best[0]= minima[0].x;
753  best[1]= minima[0].y;
754  dmin= minima[0].height;
755 
756  if( best[0] < xmax && best[0] > xmin
757  && best[1] < ymax && best[1] > ymin){
758  int d;
759  //ensure that the refernece samples for hpel refinement are in the map
760  CHECK_MV(best[0]-1, best[1])
761  CHECK_MV(best[0]+1, best[1])
762  CHECK_MV(best[0], best[1]-1)
763  CHECK_MV(best[0], best[1]+1)
764  }
765  return dmin;
766 }
767 
768 static int var_diamond_search(MpegEncContext * s, int *best, int dmin,
769  int src_index, int ref_index, int const penalty_factor,
770  int size, int h, int flags)
771 {
772  MotionEstContext * const c= &s->me;
773  me_cmp_func cmpf, chroma_cmpf;
774  int dia_size;
777  unsigned map_generation = c->map_generation;
778 
779  cmpf = s->mecc.me_cmp[size];
780  chroma_cmpf = s->mecc.me_cmp[size + 1];
781 
782  for(dia_size=1; dia_size<=c->dia_size; dia_size++){
783  int dir, start, end;
784  const int x= best[0];
785  const int y= best[1];
786 
787  start= FFMAX(0, y + dia_size - ymax);
788  end = FFMIN(dia_size, xmax - x + 1);
789  for(dir= start; dir<end; dir++){
790  int d;
791 
792 //check(x + dir,y + dia_size - dir,0, a0)
793  CHECK_MV(x + dir , y + dia_size - dir);
794  }
795 
796  start= FFMAX(0, x + dia_size - xmax);
797  end = FFMIN(dia_size, y - ymin + 1);
798  for(dir= start; dir<end; dir++){
799  int d;
800 
801 //check(x + dia_size - dir, y - dir,0, a1)
802  CHECK_MV(x + dia_size - dir, y - dir );
803  }
804 
805  start= FFMAX(0, -y + dia_size + ymin );
806  end = FFMIN(dia_size, x - xmin + 1);
807  for(dir= start; dir<end; dir++){
808  int d;
809 
810 //check(x - dir,y - dia_size + dir,0, a2)
811  CHECK_MV(x - dir , y - dia_size + dir);
812  }
813 
814  start= FFMAX(0, -x + dia_size + xmin );
815  end = FFMIN(dia_size, ymax - y + 1);
816  for(dir= start; dir<end; dir++){
817  int d;
818 
819 //check(x - dia_size + dir, y + dir,0, a3)
820  CHECK_MV(x - dia_size + dir, y + dir );
821  }
822 
823  if(x!=best[0] || y!=best[1])
824  dia_size=0;
825  }
826  return dmin;
827 }
828 
829 static av_always_inline int diamond_search(MpegEncContext * s, int *best, int dmin,
830  int src_index, int ref_index, int const penalty_factor,
831  int size, int h, int flags){
832  MotionEstContext * const c= &s->me;
833  if(c->dia_size==-1)
834  return funny_diamond_search(s, best, dmin, src_index, ref_index, penalty_factor, size, h, flags);
835  else if(c->dia_size<-1)
836  return sab_diamond_search(s, best, dmin, src_index, ref_index, penalty_factor, size, h, flags);
837  else if(c->dia_size<2)
838  return small_diamond_search(s, best, dmin, src_index, ref_index, penalty_factor, size, h, flags);
839  else if(c->dia_size>1024)
840  return full_search(s, best, dmin, src_index, ref_index, penalty_factor, size, h, flags);
841  else if(c->dia_size>768)
842  return umh_search(s, best, dmin, src_index, ref_index, penalty_factor, size, h, flags);
843  else if(c->dia_size>512)
844  return hex_search(s, best, dmin, src_index, ref_index, penalty_factor, size, h, flags, c->dia_size&0xFF);
845  else if(c->dia_size>256)
846  return l2s_dia_search(s, best, dmin, src_index, ref_index, penalty_factor, size, h, flags);
847  else
848  return var_diamond_search(s, best, dmin, src_index, ref_index, penalty_factor, size, h, flags);
849 }
850 
851 /**
852  @param P a list of candidate mvs to check before starting the
853  iterative search. If one of the candidates is close to the optimal mv, then
854  it takes fewer iterations. And it increases the chance that we find the
855  optimal mv.
856  */
857 static av_always_inline int epzs_motion_search_internal(MpegEncContext * s, int *mx_ptr, int *my_ptr,
858  int P[10][2], int src_index, int ref_index, int16_t (*last_mv)[2],
859  int ref_mv_scale, int flags, int size, int h)
860 {
861  MotionEstContext * const c= &s->me;
862  int best[2]={0, 0}; /**< x and y coordinates of the best motion vector.
863  i.e. the difference between the position of the
864  block currently being encoded and the position of
865  the block chosen to predict it from. */
866  int d; ///< the score (cmp + penalty) of any given mv
867  int dmin; /**< the best value of d, i.e. the score
868  corresponding to the mv stored in best[]. */
869  unsigned map_generation;
870  int penalty_factor;
871  const int ref_mv_stride= s->mb_stride; //pass as arg FIXME
872  const int ref_mv_xy= s->mb_x + s->mb_y*ref_mv_stride; //add to last_mv beforepassing FIXME
873  me_cmp_func cmpf, chroma_cmpf;
874 
877 
878  if(c->pre_pass){
879  penalty_factor= c->pre_penalty_factor;
880  cmpf = s->mecc.me_pre_cmp[size];
881  chroma_cmpf = s->mecc.me_pre_cmp[size + 1];
882  }else{
883  penalty_factor= c->penalty_factor;
884  cmpf = s->mecc.me_cmp[size];
885  chroma_cmpf = s->mecc.me_cmp[size + 1];
886  }
887 
888  map_generation= update_map_generation(c);
889 
890  av_assert2(cmpf);
891  dmin= cmp(s, 0, 0, 0, 0, size, h, ref_index, src_index, cmpf, chroma_cmpf, flags);
892  map[0]= map_generation;
893  score_map[0]= dmin;
894 
895  //FIXME precalc first term below?
896  if ((s->pict_type == AV_PICTURE_TYPE_B && !(c->flags & FLAG_DIRECT)) ||
898  dmin += (mv_penalty[pred_x] + mv_penalty[pred_y])*penalty_factor;
899 
900  /* first line */
901  if (s->first_slice_line) {
902  CHECK_MV(P_LEFT[0]>>shift, P_LEFT[1]>>shift)
903  CHECK_CLIPPED_MV((last_mv[ref_mv_xy][0]*ref_mv_scale + (1<<15))>>16,
904  (last_mv[ref_mv_xy][1]*ref_mv_scale + (1<<15))>>16)
905  }else{
906  if(dmin<((h*h*s->avctx->mv0_threshold)>>8)
907  && ( P_LEFT[0] |P_LEFT[1]
908  |P_TOP[0] |P_TOP[1]
909  |P_TOPRIGHT[0]|P_TOPRIGHT[1])==0){
910  *mx_ptr= 0;
911  *my_ptr= 0;
912  c->skip=1;
913  return dmin;
914  }
915  CHECK_MV( P_MEDIAN[0] >>shift , P_MEDIAN[1] >>shift)
916  CHECK_CLIPPED_MV((P_MEDIAN[0]>>shift) , (P_MEDIAN[1]>>shift)-1)
917  CHECK_CLIPPED_MV((P_MEDIAN[0]>>shift) , (P_MEDIAN[1]>>shift)+1)
918  CHECK_CLIPPED_MV((P_MEDIAN[0]>>shift)-1, (P_MEDIAN[1]>>shift) )
919  CHECK_CLIPPED_MV((P_MEDIAN[0]>>shift)+1, (P_MEDIAN[1]>>shift) )
920  CHECK_CLIPPED_MV((last_mv[ref_mv_xy][0]*ref_mv_scale + (1<<15))>>16,
921  (last_mv[ref_mv_xy][1]*ref_mv_scale + (1<<15))>>16)
922  CHECK_MV(P_LEFT[0] >>shift, P_LEFT[1] >>shift)
923  CHECK_MV(P_TOP[0] >>shift, P_TOP[1] >>shift)
925  }
926  if(dmin>h*h*4){
927  if(c->pre_pass){
928  CHECK_CLIPPED_MV((last_mv[ref_mv_xy-1][0]*ref_mv_scale + (1<<15))>>16,
929  (last_mv[ref_mv_xy-1][1]*ref_mv_scale + (1<<15))>>16)
930  if(!s->first_slice_line)
931  CHECK_CLIPPED_MV((last_mv[ref_mv_xy-ref_mv_stride][0]*ref_mv_scale + (1<<15))>>16,
932  (last_mv[ref_mv_xy-ref_mv_stride][1]*ref_mv_scale + (1<<15))>>16)
933  }else{
934  CHECK_CLIPPED_MV((last_mv[ref_mv_xy+1][0]*ref_mv_scale + (1<<15))>>16,
935  (last_mv[ref_mv_xy+1][1]*ref_mv_scale + (1<<15))>>16)
936  if(s->mb_y+1<s->end_mb_y) //FIXME replace at least with last_slice_line
937  CHECK_CLIPPED_MV((last_mv[ref_mv_xy+ref_mv_stride][0]*ref_mv_scale + (1<<15))>>16,
938  (last_mv[ref_mv_xy+ref_mv_stride][1]*ref_mv_scale + (1<<15))>>16)
939  }
940  }
941 
942  if(c->avctx->last_predictor_count){
943  const int count= c->avctx->last_predictor_count;
944  const int xstart= FFMAX(0, s->mb_x - count);
945  const int ystart= FFMAX(0, s->mb_y - count);
946  const int xend= FFMIN(s->mb_width , s->mb_x + count + 1);
947  const int yend= FFMIN(s->mb_height, s->mb_y + count + 1);
948  int mb_y;
949 
950  for(mb_y=ystart; mb_y<yend; mb_y++){
951  int mb_x;
952  for(mb_x=xstart; mb_x<xend; mb_x++){
953  const int xy= mb_x + 1 + (mb_y + 1)*ref_mv_stride;
954  int mx= (last_mv[xy][0]*ref_mv_scale + (1<<15))>>16;
955  int my= (last_mv[xy][1]*ref_mv_scale + (1<<15))>>16;
956 
957  if(mx>xmax || mx<xmin || my>ymax || my<ymin) continue;
958  CHECK_MV(mx,my)
959  }
960  }
961  }
962 
963 //check(best[0],best[1],0, b0)
964  dmin= diamond_search(s, best, dmin, src_index, ref_index, penalty_factor, size, h, flags);
965 
966 //check(best[0],best[1],0, b1)
967  *mx_ptr= best[0];
968  *my_ptr= best[1];
969 
970  return dmin;
971 }
972 
973 //this function is dedicated to the braindamaged gcc
974 int ff_epzs_motion_search(MpegEncContext *s, int *mx_ptr, int *my_ptr,
975  int P[10][2], int src_index, int ref_index,
976  int16_t (*last_mv)[2], int ref_mv_scale,
977  int size, int h)
978 {
979  MotionEstContext * const c= &s->me;
980 //FIXME convert other functions in the same way if faster
981  if(c->flags==0 && h==16 && size==0){
982  return epzs_motion_search_internal(s, mx_ptr, my_ptr, P, src_index, ref_index, last_mv, ref_mv_scale, 0, 0, 16);
983 // case FLAG_QPEL:
984 // return epzs_motion_search_internal(s, mx_ptr, my_ptr, P, src_index, ref_index, last_mv, ref_mv_scale, FLAG_QPEL);
985  }else{
986  return epzs_motion_search_internal(s, mx_ptr, my_ptr, P, src_index, ref_index, last_mv, ref_mv_scale, c->flags, size, h);
987  }
988 }
989 
991  int *mx_ptr, int *my_ptr, int P[10][2],
992  int src_index, int ref_index, int16_t (*last_mv)[2],
993  int ref_mv_scale)
994 {
995  MotionEstContext * const c= &s->me;
996  int best[2]={0, 0};
997  int d, dmin;
998  unsigned map_generation;
999  const int penalty_factor= c->penalty_factor;
1000  const int size=1;
1001  const int h=8;
1002  const int ref_mv_stride= s->mb_stride;
1003  const int ref_mv_xy= s->mb_x + s->mb_y *ref_mv_stride;
1004  me_cmp_func cmpf, chroma_cmpf;
1005  LOAD_COMMON
1006  int flags= c->flags;
1007  LOAD_COMMON2
1008 
1009  cmpf = s->mecc.me_cmp[size];
1010  chroma_cmpf = s->mecc.me_cmp[size + 1];
1011 
1012  map_generation= update_map_generation(c);
1013 
1014  dmin = 1000000;
1015 
1016  /* first line */
1017  if (s->first_slice_line) {
1018  CHECK_MV(P_LEFT[0]>>shift, P_LEFT[1]>>shift)
1019  CHECK_CLIPPED_MV((last_mv[ref_mv_xy][0]*ref_mv_scale + (1<<15))>>16,
1020  (last_mv[ref_mv_xy][1]*ref_mv_scale + (1<<15))>>16)
1021  CHECK_MV(P_MV1[0]>>shift, P_MV1[1]>>shift)
1022  }else{
1023  CHECK_MV(P_MV1[0]>>shift, P_MV1[1]>>shift)
1024  //FIXME try some early stop
1026  CHECK_MV(P_LEFT[0]>>shift, P_LEFT[1]>>shift)
1027  CHECK_MV(P_TOP[0]>>shift, P_TOP[1]>>shift)
1029  CHECK_CLIPPED_MV((last_mv[ref_mv_xy][0]*ref_mv_scale + (1<<15))>>16,
1030  (last_mv[ref_mv_xy][1]*ref_mv_scale + (1<<15))>>16)
1031  }
1032  if(dmin>64*4){
1033  CHECK_CLIPPED_MV((last_mv[ref_mv_xy+1][0]*ref_mv_scale + (1<<15))>>16,
1034  (last_mv[ref_mv_xy+1][1]*ref_mv_scale + (1<<15))>>16)
1035  if(s->mb_y+1<s->end_mb_y) //FIXME replace at least with last_slice_line
1036  CHECK_CLIPPED_MV((last_mv[ref_mv_xy+ref_mv_stride][0]*ref_mv_scale + (1<<15))>>16,
1037  (last_mv[ref_mv_xy+ref_mv_stride][1]*ref_mv_scale + (1<<15))>>16)
1038  }
1039 
1040  dmin= diamond_search(s, best, dmin, src_index, ref_index, penalty_factor, size, h, flags);
1041 
1042  *mx_ptr= best[0];
1043  *my_ptr= best[1];
1044 
1045  return dmin;
1046 }
1047 
1048 //try to merge with above FIXME (needs PSNR test)
1050  int *mx_ptr, int *my_ptr, int P[10][2],
1051  int src_index, int ref_index, int16_t (*last_mv)[2],
1052  int ref_mv_scale)
1053 {
1054  MotionEstContext * const c= &s->me;
1055  int best[2]={0, 0};
1056  int d, dmin;
1057  unsigned map_generation;
1058  const int penalty_factor= c->penalty_factor;
1059  const int size=0; //FIXME pass as arg
1060  const int h=8;
1061  const int ref_mv_stride= s->mb_stride;
1062  const int ref_mv_xy= s->mb_x + s->mb_y *ref_mv_stride;
1063  me_cmp_func cmpf, chroma_cmpf;
1064  LOAD_COMMON
1065  int flags= c->flags;
1066  LOAD_COMMON2
1067 
1068  cmpf = s->mecc.me_cmp[size];
1069  chroma_cmpf = s->mecc.me_cmp[size + 1];
1070 
1071  map_generation= update_map_generation(c);
1072 
1073  dmin = 1000000;
1074 
1075  /* first line */
1076  if (s->first_slice_line) {
1077  CHECK_MV(P_LEFT[0]>>shift, P_LEFT[1]>>shift)
1078  CHECK_CLIPPED_MV((last_mv[ref_mv_xy][0]*ref_mv_scale + (1<<15))>>16,
1079  (last_mv[ref_mv_xy][1]*ref_mv_scale + (1<<15))>>16)
1080  CHECK_MV(P_MV1[0]>>shift, P_MV1[1]>>shift)
1081  }else{
1082  CHECK_MV(P_MV1[0]>>shift, P_MV1[1]>>shift)
1083  //FIXME try some early stop
1085  CHECK_MV(P_LEFT[0]>>shift, P_LEFT[1]>>shift)
1086  CHECK_MV(P_TOP[0]>>shift, P_TOP[1]>>shift)
1088  CHECK_CLIPPED_MV((last_mv[ref_mv_xy][0]*ref_mv_scale + (1<<15))>>16,
1089  (last_mv[ref_mv_xy][1]*ref_mv_scale + (1<<15))>>16)
1090  }
1091  if(dmin>64*4){
1092  CHECK_CLIPPED_MV((last_mv[ref_mv_xy+1][0]*ref_mv_scale + (1<<15))>>16,
1093  (last_mv[ref_mv_xy+1][1]*ref_mv_scale + (1<<15))>>16)
1094  if(s->mb_y+1<s->end_mb_y) //FIXME replace at least with last_slice_line
1095  CHECK_CLIPPED_MV((last_mv[ref_mv_xy+ref_mv_stride][0]*ref_mv_scale + (1<<15))>>16,
1096  (last_mv[ref_mv_xy+ref_mv_stride][1]*ref_mv_scale + (1<<15))>>16)
1097  }
1098 
1099  dmin= diamond_search(s, best, dmin, src_index, ref_index, penalty_factor, size, h, flags);
1100 
1101  *mx_ptr= best[0];
1102  *my_ptr= best[1];
1103 
1104  return dmin;
1105 }