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