]> git.sesse.net Git - ffmpeg/blob - libavcodec/motion_est_template.c
Merge commit 'fa8fcab1e0d31074c0644c4ac5194474c6c26415'
[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 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)) ) printf("%d %d %d %d %d xmin" #v, xmin, (x), (y), s->mb_x, s->mb_y);\
404 if( (x)>(xmax<<(S)) ) printf("%d %d %d %d %d xmax" #v, xmax, (x), (y), s->mb_x, s->mb_y);\
405 if( (y)<(ymin<<(S)) ) printf("%d %d %d %d %d ymin" #v, ymin, (x), (y), s->mb_x, s->mb_y);\
406 if( (y)>(ymax<<(S)) ) printf("%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     cmpf= s->dsp.me_cmp[size];
692     chroma_cmpf= s->dsp.me_cmp[size+1];
693
694     /*Note j<MAX_SAB_SIZE is needed if MAX_SAB_SIZE < ME_MAP_SIZE as j can
695       become larger due to MVs overflowing their ME_MAP_MV_BITS bits space in map
696      */
697     for(j=i=0; i<ME_MAP_SIZE && j<MAX_SAB_SIZE; i++){
698         uint32_t key= map[i];
699
700         key += (1<<(ME_MAP_MV_BITS-1)) + (1<<(2*ME_MAP_MV_BITS-1));
701
702         if((key&((-1)<<(2*ME_MAP_MV_BITS))) != map_generation) continue;
703
704         minima[j].height= score_map[i];
705         minima[j].x= key & ((1<<ME_MAP_MV_BITS)-1); key>>=ME_MAP_MV_BITS;
706         minima[j].y= key & ((1<<ME_MAP_MV_BITS)-1);
707         minima[j].x-= (1<<(ME_MAP_MV_BITS-1));
708         minima[j].y-= (1<<(ME_MAP_MV_BITS-1));
709
710         // all entries in map should be in range except if the mv overflows their ME_MAP_MV_BITS bits space
711         if(   minima[j].x > xmax || minima[j].x < xmin
712            || minima[j].y > ymax || minima[j].y < ymin)
713             continue;
714
715         minima[j].checked=0;
716         if(minima[j].x || minima[j].y)
717             minima[j].height+= (mv_penalty[((minima[j].x)<<shift)-pred_x] + mv_penalty[((minima[j].y)<<shift)-pred_y])*penalty_factor;
718
719         j++;
720     }
721
722     qsort(minima, j, sizeof(Minima), minima_cmp);
723
724     for(; j<minima_count; j++){
725         minima[j].height=256*256*256*64;
726         minima[j].checked=0;
727         minima[j].x= minima[j].y=0;
728     }
729
730     for(i=0; i<minima_count; i++){
731         const int x= minima[i].x;
732         const int y= minima[i].y;
733         int d;
734
735         if(minima[i].checked) continue;
736
737         if(   x >= xmax || x <= xmin
738            || y >= ymax || y <= ymin)
739            continue;
740
741         SAB_CHECK_MV(x-1, y)
742         SAB_CHECK_MV(x+1, y)
743         SAB_CHECK_MV(x  , y-1)
744         SAB_CHECK_MV(x  , y+1)
745
746         minima[i].checked= 1;
747     }
748
749     best[0]= minima[0].x;
750     best[1]= minima[0].y;
751     dmin= minima[0].height;
752
753     if(   best[0] < xmax && best[0] > xmin
754        && best[1] < ymax && best[1] > ymin){
755         int d;
756         //ensure that the refernece samples for hpel refinement are in the map
757         CHECK_MV(best[0]-1, best[1])
758         CHECK_MV(best[0]+1, best[1])
759         CHECK_MV(best[0], best[1]-1)
760         CHECK_MV(best[0], best[1]+1)
761     }
762     return dmin;
763 }
764
765 static int var_diamond_search(MpegEncContext * s, int *best, int dmin,
766                                        int src_index, int ref_index, int const penalty_factor,
767                                        int size, int h, int flags)
768 {
769     MotionEstContext * const c= &s->me;
770     me_cmp_func cmpf, chroma_cmpf;
771     int dia_size;
772     LOAD_COMMON
773     LOAD_COMMON2
774     unsigned map_generation = c->map_generation;
775
776     cmpf= s->dsp.me_cmp[size];
777     chroma_cmpf= s->dsp.me_cmp[size+1];
778
779     for(dia_size=1; dia_size<=c->dia_size; dia_size++){
780         int dir, start, end;
781         const int x= best[0];
782         const int y= best[1];
783
784         start= FFMAX(0, y + dia_size - ymax);
785         end  = FFMIN(dia_size, xmax - x + 1);
786         for(dir= start; dir<end; dir++){
787             int d;
788
789 //check(x + dir,y + dia_size - dir,0, a0)
790             CHECK_MV(x + dir           , y + dia_size - dir);
791         }
792
793         start= FFMAX(0, x + dia_size - xmax);
794         end  = FFMIN(dia_size, y - ymin + 1);
795         for(dir= start; dir<end; dir++){
796             int d;
797
798 //check(x + dia_size - dir, y - dir,0, a1)
799             CHECK_MV(x + dia_size - dir, y - dir           );
800         }
801
802         start= FFMAX(0, -y + dia_size + ymin );
803         end  = FFMIN(dia_size, x - xmin + 1);
804         for(dir= start; dir<end; dir++){
805             int d;
806
807 //check(x - dir,y - dia_size + dir,0, a2)
808             CHECK_MV(x - dir           , y - dia_size + dir);
809         }
810
811         start= FFMAX(0, -x + dia_size + xmin );
812         end  = FFMIN(dia_size, ymax - y + 1);
813         for(dir= start; dir<end; dir++){
814             int d;
815
816 //check(x - dia_size + dir, y + dir,0, a3)
817             CHECK_MV(x - dia_size + dir, y + dir           );
818         }
819
820         if(x!=best[0] || y!=best[1])
821             dia_size=0;
822     }
823     return dmin;
824 }
825
826 static av_always_inline int diamond_search(MpegEncContext * s, int *best, int dmin,
827                                        int src_index, int ref_index, int const penalty_factor,
828                                        int size, int h, int flags){
829     MotionEstContext * const c= &s->me;
830     if(c->dia_size==-1)
831         return funny_diamond_search(s, best, dmin, src_index, ref_index, penalty_factor, size, h, flags);
832     else if(c->dia_size<-1)
833         return   sab_diamond_search(s, best, dmin, src_index, ref_index, penalty_factor, size, h, flags);
834     else if(c->dia_size<2)
835         return small_diamond_search(s, best, dmin, src_index, ref_index, penalty_factor, size, h, flags);
836     else if(c->dia_size>1024)
837         return          full_search(s, best, dmin, src_index, ref_index, penalty_factor, size, h, flags);
838     else if(c->dia_size>768)
839         return           umh_search(s, best, dmin, src_index, ref_index, penalty_factor, size, h, flags);
840     else if(c->dia_size>512)
841         return           hex_search(s, best, dmin, src_index, ref_index, penalty_factor, size, h, flags, c->dia_size&0xFF);
842     else if(c->dia_size>256)
843         return       l2s_dia_search(s, best, dmin, src_index, ref_index, penalty_factor, size, h, flags);
844     else
845         return   var_diamond_search(s, best, dmin, src_index, ref_index, penalty_factor, size, h, flags);
846 }
847
848 /**
849    @param P a list of candidate mvs to check before starting the
850    iterative search. If one of the candidates is close to the optimal mv, then
851    it takes fewer iterations. And it increases the chance that we find the
852    optimal mv.
853  */
854 static av_always_inline int epzs_motion_search_internal(MpegEncContext * s, int *mx_ptr, int *my_ptr,
855                              int P[10][2], int src_index, int ref_index, int16_t (*last_mv)[2],
856                              int ref_mv_scale, int flags, int size, int h)
857 {
858     MotionEstContext * const c= &s->me;
859     int best[2]={0, 0};      /**< x and y coordinates of the best motion vector.
860                                i.e. the difference between the position of the
861                                block currently being encoded and the position of
862                                the block chosen to predict it from. */
863     int d;                   ///< the score (cmp + penalty) of any given mv
864     int dmin;                /**< the best value of d, i.e. the score
865                                corresponding to the mv stored in best[]. */
866     unsigned map_generation;
867     int penalty_factor;
868     const int ref_mv_stride= s->mb_stride; //pass as arg  FIXME
869     const int ref_mv_xy= s->mb_x + s->mb_y*ref_mv_stride; //add to last_mv beforepassing FIXME
870     me_cmp_func cmpf, chroma_cmpf;
871
872     LOAD_COMMON
873     LOAD_COMMON2
874
875     if(c->pre_pass){
876         penalty_factor= c->pre_penalty_factor;
877         cmpf= s->dsp.me_pre_cmp[size];
878         chroma_cmpf= s->dsp.me_pre_cmp[size+1];
879     }else{
880         penalty_factor= c->penalty_factor;
881         cmpf= s->dsp.me_cmp[size];
882         chroma_cmpf= s->dsp.me_cmp[size+1];
883     }
884
885     map_generation= update_map_generation(c);
886
887     av_assert2(cmpf);
888     dmin= cmp(s, 0, 0, 0, 0, size, h, ref_index, src_index, cmpf, chroma_cmpf, flags);
889     map[0]= map_generation;
890     score_map[0]= dmin;
891
892     //FIXME precalc first term below?
893     if((s->pict_type == AV_PICTURE_TYPE_B && !(c->flags & FLAG_DIRECT)) || s->flags&CODEC_FLAG_MV0)
894         dmin += (mv_penalty[pred_x] + mv_penalty[pred_y])*penalty_factor;
895
896     /* first line */
897     if (s->first_slice_line) {
898         CHECK_MV(P_LEFT[0]>>shift, P_LEFT[1]>>shift)
899         CHECK_CLIPPED_MV((last_mv[ref_mv_xy][0]*ref_mv_scale + (1<<15))>>16,
900                         (last_mv[ref_mv_xy][1]*ref_mv_scale + (1<<15))>>16)
901     }else{
902         if(dmin<((h*h*s->avctx->mv0_threshold)>>8)
903                     && ( P_LEFT[0]    |P_LEFT[1]
904                         |P_TOP[0]     |P_TOP[1]
905                         |P_TOPRIGHT[0]|P_TOPRIGHT[1])==0){
906             *mx_ptr= 0;
907             *my_ptr= 0;
908             c->skip=1;
909             return dmin;
910         }
911         CHECK_MV(    P_MEDIAN[0] >>shift ,    P_MEDIAN[1] >>shift)
912         CHECK_CLIPPED_MV((P_MEDIAN[0]>>shift)  , (P_MEDIAN[1]>>shift)-1)
913         CHECK_CLIPPED_MV((P_MEDIAN[0]>>shift)  , (P_MEDIAN[1]>>shift)+1)
914         CHECK_CLIPPED_MV((P_MEDIAN[0]>>shift)-1, (P_MEDIAN[1]>>shift)  )
915         CHECK_CLIPPED_MV((P_MEDIAN[0]>>shift)+1, (P_MEDIAN[1]>>shift)  )
916         CHECK_CLIPPED_MV((last_mv[ref_mv_xy][0]*ref_mv_scale + (1<<15))>>16,
917                         (last_mv[ref_mv_xy][1]*ref_mv_scale + (1<<15))>>16)
918         CHECK_MV(P_LEFT[0]    >>shift, P_LEFT[1]    >>shift)
919         CHECK_MV(P_TOP[0]     >>shift, P_TOP[1]     >>shift)
920         CHECK_MV(P_TOPRIGHT[0]>>shift, P_TOPRIGHT[1]>>shift)
921     }
922     if(dmin>h*h*4){
923         if(c->pre_pass){
924             CHECK_CLIPPED_MV((last_mv[ref_mv_xy-1][0]*ref_mv_scale + (1<<15))>>16,
925                             (last_mv[ref_mv_xy-1][1]*ref_mv_scale + (1<<15))>>16)
926             if(!s->first_slice_line)
927                 CHECK_CLIPPED_MV((last_mv[ref_mv_xy-ref_mv_stride][0]*ref_mv_scale + (1<<15))>>16,
928                                 (last_mv[ref_mv_xy-ref_mv_stride][1]*ref_mv_scale + (1<<15))>>16)
929         }else{
930             CHECK_CLIPPED_MV((last_mv[ref_mv_xy+1][0]*ref_mv_scale + (1<<15))>>16,
931                             (last_mv[ref_mv_xy+1][1]*ref_mv_scale + (1<<15))>>16)
932             if(s->mb_y+1<s->end_mb_y)  //FIXME replace at least with last_slice_line
933                 CHECK_CLIPPED_MV((last_mv[ref_mv_xy+ref_mv_stride][0]*ref_mv_scale + (1<<15))>>16,
934                                 (last_mv[ref_mv_xy+ref_mv_stride][1]*ref_mv_scale + (1<<15))>>16)
935         }
936     }
937
938     if(c->avctx->last_predictor_count){
939         const int count= c->avctx->last_predictor_count;
940         const int xstart= FFMAX(0, s->mb_x - count);
941         const int ystart= FFMAX(0, s->mb_y - count);
942         const int xend= FFMIN(s->mb_width , s->mb_x + count + 1);
943         const int yend= FFMIN(s->mb_height, s->mb_y + count + 1);
944         int mb_y;
945
946         for(mb_y=ystart; mb_y<yend; mb_y++){
947             int mb_x;
948             for(mb_x=xstart; mb_x<xend; mb_x++){
949                 const int xy= mb_x + 1 + (mb_y + 1)*ref_mv_stride;
950                 int mx= (last_mv[xy][0]*ref_mv_scale + (1<<15))>>16;
951                 int my= (last_mv[xy][1]*ref_mv_scale + (1<<15))>>16;
952
953                 if(mx>xmax || mx<xmin || my>ymax || my<ymin) continue;
954                 CHECK_MV(mx,my)
955             }
956         }
957     }
958
959 //check(best[0],best[1],0, b0)
960     dmin= diamond_search(s, best, dmin, src_index, ref_index, penalty_factor, size, h, flags);
961
962 //check(best[0],best[1],0, b1)
963     *mx_ptr= best[0];
964     *my_ptr= best[1];
965
966     return dmin;
967 }
968
969 //this function is dedicated to the braindamaged gcc
970 int ff_epzs_motion_search(MpegEncContext *s, int *mx_ptr, int *my_ptr,
971                           int P[10][2], int src_index, int ref_index,
972                           int16_t (*last_mv)[2], int ref_mv_scale,
973                           int size, int h)
974 {
975     MotionEstContext * const c= &s->me;
976 //FIXME convert other functions in the same way if faster
977     if(c->flags==0 && h==16 && size==0){
978         return epzs_motion_search_internal(s, mx_ptr, my_ptr, P, src_index, ref_index, last_mv, ref_mv_scale, 0, 0, 16);
979 //    case FLAG_QPEL:
980 //        return epzs_motion_search_internal(s, mx_ptr, my_ptr, P, src_index, ref_index, last_mv, ref_mv_scale, FLAG_QPEL);
981     }else{
982         return epzs_motion_search_internal(s, mx_ptr, my_ptr, P, src_index, ref_index, last_mv, ref_mv_scale, c->flags, size, h);
983     }
984 }
985
986 static int epzs_motion_search4(MpegEncContext * s,
987                              int *mx_ptr, int *my_ptr, int P[10][2],
988                              int src_index, int ref_index, int16_t (*last_mv)[2],
989                              int ref_mv_scale)
990 {
991     MotionEstContext * const c= &s->me;
992     int best[2]={0, 0};
993     int d, dmin;
994     unsigned map_generation;
995     const int penalty_factor= c->penalty_factor;
996     const int size=1;
997     const int h=8;
998     const int ref_mv_stride= s->mb_stride;
999     const int ref_mv_xy= s->mb_x + s->mb_y *ref_mv_stride;
1000     me_cmp_func cmpf, chroma_cmpf;
1001     LOAD_COMMON
1002     int flags= c->flags;
1003     LOAD_COMMON2
1004
1005     cmpf= s->dsp.me_cmp[size];
1006     chroma_cmpf= s->dsp.me_cmp[size+1];
1007
1008     map_generation= update_map_generation(c);
1009
1010     dmin = 1000000;
1011
1012     /* first line */
1013     if (s->first_slice_line) {
1014         CHECK_MV(P_LEFT[0]>>shift, P_LEFT[1]>>shift)
1015         CHECK_CLIPPED_MV((last_mv[ref_mv_xy][0]*ref_mv_scale + (1<<15))>>16,
1016                         (last_mv[ref_mv_xy][1]*ref_mv_scale + (1<<15))>>16)
1017         CHECK_MV(P_MV1[0]>>shift, P_MV1[1]>>shift)
1018     }else{
1019         CHECK_MV(P_MV1[0]>>shift, P_MV1[1]>>shift)
1020         //FIXME try some early stop
1021         CHECK_MV(P_MEDIAN[0]>>shift, P_MEDIAN[1]>>shift)
1022         CHECK_MV(P_LEFT[0]>>shift, P_LEFT[1]>>shift)
1023         CHECK_MV(P_TOP[0]>>shift, P_TOP[1]>>shift)
1024         CHECK_MV(P_TOPRIGHT[0]>>shift, P_TOPRIGHT[1]>>shift)
1025         CHECK_CLIPPED_MV((last_mv[ref_mv_xy][0]*ref_mv_scale + (1<<15))>>16,
1026                         (last_mv[ref_mv_xy][1]*ref_mv_scale + (1<<15))>>16)
1027     }
1028     if(dmin>64*4){
1029         CHECK_CLIPPED_MV((last_mv[ref_mv_xy+1][0]*ref_mv_scale + (1<<15))>>16,
1030                         (last_mv[ref_mv_xy+1][1]*ref_mv_scale + (1<<15))>>16)
1031         if(s->mb_y+1<s->end_mb_y)  //FIXME replace at least with last_slice_line
1032             CHECK_CLIPPED_MV((last_mv[ref_mv_xy+ref_mv_stride][0]*ref_mv_scale + (1<<15))>>16,
1033                             (last_mv[ref_mv_xy+ref_mv_stride][1]*ref_mv_scale + (1<<15))>>16)
1034     }
1035
1036     dmin= diamond_search(s, best, dmin, src_index, ref_index, penalty_factor, size, h, flags);
1037
1038     *mx_ptr= best[0];
1039     *my_ptr= best[1];
1040
1041     return dmin;
1042 }
1043
1044 //try to merge with above FIXME (needs PSNR test)
1045 static int epzs_motion_search2(MpegEncContext * s,
1046                              int *mx_ptr, int *my_ptr, int P[10][2],
1047                              int src_index, int ref_index, int16_t (*last_mv)[2],
1048                              int ref_mv_scale)
1049 {
1050     MotionEstContext * const c= &s->me;
1051     int best[2]={0, 0};
1052     int d, dmin;
1053     unsigned map_generation;
1054     const int penalty_factor= c->penalty_factor;
1055     const int size=0; //FIXME pass as arg
1056     const int h=8;
1057     const int ref_mv_stride= s->mb_stride;
1058     const int ref_mv_xy= s->mb_x + s->mb_y *ref_mv_stride;
1059     me_cmp_func cmpf, chroma_cmpf;
1060     LOAD_COMMON
1061     int flags= c->flags;
1062     LOAD_COMMON2
1063
1064     cmpf= s->dsp.me_cmp[size];
1065     chroma_cmpf= s->dsp.me_cmp[size+1];
1066
1067     map_generation= update_map_generation(c);
1068
1069     dmin = 1000000;
1070
1071     /* first line */
1072     if (s->first_slice_line) {
1073         CHECK_MV(P_LEFT[0]>>shift, P_LEFT[1]>>shift)
1074         CHECK_CLIPPED_MV((last_mv[ref_mv_xy][0]*ref_mv_scale + (1<<15))>>16,
1075                         (last_mv[ref_mv_xy][1]*ref_mv_scale + (1<<15))>>16)
1076         CHECK_MV(P_MV1[0]>>shift, P_MV1[1]>>shift)
1077     }else{
1078         CHECK_MV(P_MV1[0]>>shift, P_MV1[1]>>shift)
1079         //FIXME try some early stop
1080         CHECK_MV(P_MEDIAN[0]>>shift, P_MEDIAN[1]>>shift)
1081         CHECK_MV(P_LEFT[0]>>shift, P_LEFT[1]>>shift)
1082         CHECK_MV(P_TOP[0]>>shift, P_TOP[1]>>shift)
1083         CHECK_MV(P_TOPRIGHT[0]>>shift, P_TOPRIGHT[1]>>shift)
1084         CHECK_CLIPPED_MV((last_mv[ref_mv_xy][0]*ref_mv_scale + (1<<15))>>16,
1085                         (last_mv[ref_mv_xy][1]*ref_mv_scale + (1<<15))>>16)
1086     }
1087     if(dmin>64*4){
1088         CHECK_CLIPPED_MV((last_mv[ref_mv_xy+1][0]*ref_mv_scale + (1<<15))>>16,
1089                         (last_mv[ref_mv_xy+1][1]*ref_mv_scale + (1<<15))>>16)
1090         if(s->mb_y+1<s->end_mb_y)  //FIXME replace at least with last_slice_line
1091             CHECK_CLIPPED_MV((last_mv[ref_mv_xy+ref_mv_stride][0]*ref_mv_scale + (1<<15))>>16,
1092                             (last_mv[ref_mv_xy+ref_mv_stride][1]*ref_mv_scale + (1<<15))>>16)
1093     }
1094
1095     dmin= diamond_search(s, best, dmin, src_index, ref_index, penalty_factor, size, h, flags);
1096
1097     *mx_ptr= best[0];
1098     *my_ptr= best[1];
1099
1100     return dmin;
1101 }