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