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