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