lavfi: switch to AVFrame.
[FFMpeg-mirror/mplayer-patches.git] / libavcodec / motion_est_template.c
blob7228744756bd1f89ff59a26f54a7b9d8381faf68
1 /*
2 * Motion estimation
3 * Copyright (c) 2002-2004 Michael Niedermayer
5 * This file is part of Libav.
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.
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.
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
22 /**
23 * @file
24 * Motion estimation template.
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;\
38 #define CHECK_HALF_MV(dx, dy, x, y)\
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)\
47 static int hpel_motion_search(MpegEncContext * s,
48 int *mx_ptr, int *my_ptr, int dmin,
49 int src_index, int ref_index,
50 int size, int h)
52 MotionEstContext * const c= &s->me;
53 const int mx = *mx_ptr;
54 const int my = *my_ptr;
55 const int penalty_factor= c->sub_penalty_factor;
56 me_cmp_func cmp_sub, chroma_cmp_sub;
57 int bx=2*mx, by=2*my;
59 LOAD_COMMON
60 int flags= c->sub_flags;
62 //FIXME factorize
64 cmp_sub= s->dsp.me_sub_cmp[size];
65 chroma_cmp_sub= s->dsp.me_sub_cmp[size+1];
67 if(c->skip){ //FIXME move out of hpel?
68 *mx_ptr = 0;
69 *my_ptr = 0;
70 return dmin;
73 if(c->avctx->me_cmp != c->avctx->me_sub_cmp){
74 dmin= cmp(s, mx, my, 0, 0, size, h, ref_index, src_index, cmp_sub, chroma_cmp_sub, flags);
75 if(mx || my || size>0)
76 dmin += (mv_penalty[2*mx - pred_x] + mv_penalty[2*my - pred_y])*penalty_factor;
79 if (mx > xmin && mx < xmax &&
80 my > ymin && my < ymax) {
81 int d= dmin;
82 const int index= (my<<ME_MAP_SHIFT) + mx;
83 const int t= score_map[(index-(1<<ME_MAP_SHIFT))&(ME_MAP_SIZE-1)]
84 + (mv_penalty[bx - pred_x] + mv_penalty[by-2 - pred_y])*c->penalty_factor;
85 const int l= score_map[(index- 1 )&(ME_MAP_SIZE-1)]
86 + (mv_penalty[bx-2 - pred_x] + mv_penalty[by - pred_y])*c->penalty_factor;
87 const int r= score_map[(index+ 1 )&(ME_MAP_SIZE-1)]
88 + (mv_penalty[bx+2 - pred_x] + mv_penalty[by - pred_y])*c->penalty_factor;
89 const int b= score_map[(index+(1<<ME_MAP_SHIFT))&(ME_MAP_SIZE-1)]
90 + (mv_penalty[bx - pred_x] + mv_penalty[by+2 - pred_y])*c->penalty_factor;
92 unsigned key;
93 unsigned map_generation= c->map_generation;
94 #ifndef NDEBUG
95 uint32_t *map= c->map;
96 #endif
97 key= ((my-1)<<ME_MAP_MV_BITS) + (mx) + map_generation;
98 assert(map[(index-(1<<ME_MAP_SHIFT))&(ME_MAP_SIZE-1)] == key);
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)<<ME_MAP_MV_BITS) + (mx+1) + map_generation;
102 assert(map[(index+1)&(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 if(t<=b){
106 CHECK_HALF_MV(0, 1, mx ,my-1)
107 if(l<=r){
108 CHECK_HALF_MV(1, 1, mx-1, my-1)
109 if(t+r<=b+l){
110 CHECK_HALF_MV(1, 1, mx , my-1)
111 }else{
112 CHECK_HALF_MV(1, 1, mx-1, my )
114 CHECK_HALF_MV(1, 0, mx-1, my )
115 }else{
116 CHECK_HALF_MV(1, 1, mx , my-1)
117 if(t+l<=b+r){
118 CHECK_HALF_MV(1, 1, mx-1, my-1)
119 }else{
120 CHECK_HALF_MV(1, 1, mx , my )
122 CHECK_HALF_MV(1, 0, mx , my )
124 }else{
125 if(l<=r){
126 if(t+l<=b+r){
127 CHECK_HALF_MV(1, 1, mx-1, my-1)
128 }else{
129 CHECK_HALF_MV(1, 1, mx , my )
131 CHECK_HALF_MV(1, 0, mx-1, my)
132 CHECK_HALF_MV(1, 1, mx-1, my)
133 }else{
134 if(t+r<=b+l){
135 CHECK_HALF_MV(1, 1, mx , my-1)
136 }else{
137 CHECK_HALF_MV(1, 1, mx-1, my)
139 CHECK_HALF_MV(1, 0, mx , my)
140 CHECK_HALF_MV(1, 1, mx , my)
142 CHECK_HALF_MV(0, 1, mx , my)
144 assert(bx >= xmin*2 && bx <= xmax*2 && by >= ymin*2 && by <= ymax*2);
147 *mx_ptr = bx;
148 *my_ptr = by;
150 return dmin;
153 static int no_sub_motion_search(MpegEncContext * s,
154 int *mx_ptr, int *my_ptr, int dmin,
155 int src_index, int ref_index,
156 int size, int h)
158 (*mx_ptr)<<=1;
159 (*my_ptr)<<=1;
160 return dmin;
163 static inline int get_mb_score(MpegEncContext *s, int mx, int my,
164 int src_index, int ref_index, int size,
165 int h, int add_rate)
167 // const int check_luma= s->dsp.me_sub_cmp != s->dsp.mb_cmp;
168 MotionEstContext * const c= &s->me;
169 const int penalty_factor= c->mb_penalty_factor;
170 const int flags= c->mb_flags;
171 const int qpel= flags & FLAG_QPEL;
172 const int mask= 1+2*qpel;
173 me_cmp_func cmp_sub, chroma_cmp_sub;
174 int d;
176 LOAD_COMMON
178 //FIXME factorize
180 cmp_sub= s->dsp.mb_cmp[size];
181 chroma_cmp_sub= s->dsp.mb_cmp[size+1];
183 // assert(!c->skip);
184 // assert(c->avctx->me_sub_cmp != c->avctx->mb_cmp);
186 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);
187 //FIXME check cbp before adding penalty for (0,0) vector
188 if(add_rate && (mx || my || size>0))
189 d += (mv_penalty[mx - pred_x] + mv_penalty[my - pred_y])*penalty_factor;
191 return d;
194 int ff_get_mb_score(MpegEncContext *s, int mx, int my, int src_index,
195 int ref_index, int size, int h, int add_rate)
197 return get_mb_score(s, mx, my, src_index, ref_index, size, h, add_rate);
200 #define CHECK_QUARTER_MV(dx, dy, x, y)\
202 const int hx= 4*(x)+(dx);\
203 const int hy= 4*(y)+(dy);\
204 d= cmp_qpel(s, x, y, dx, dy, size, h, ref_index, src_index, cmpf, chroma_cmpf, flags);\
205 d += (mv_penalty[hx - pred_x] + mv_penalty[hy - pred_y])*penalty_factor;\
206 COPY3_IF_LT(dmin, d, bx, hx, by, hy)\
209 static int qpel_motion_search(MpegEncContext * s,
210 int *mx_ptr, int *my_ptr, int dmin,
211 int src_index, int ref_index,
212 int size, int h)
214 MotionEstContext * const c= &s->me;
215 const int mx = *mx_ptr;
216 const int my = *my_ptr;
217 const int penalty_factor= c->sub_penalty_factor;
218 const unsigned map_generation = c->map_generation;
219 const int subpel_quality= c->avctx->me_subpel_quality;
220 uint32_t *map= c->map;
221 me_cmp_func cmpf, chroma_cmpf;
222 me_cmp_func cmp_sub, chroma_cmp_sub;
224 LOAD_COMMON
225 int flags= c->sub_flags;
227 cmpf= s->dsp.me_cmp[size];
228 chroma_cmpf= s->dsp.me_cmp[size+1]; //factorize FIXME
229 //FIXME factorize
231 cmp_sub= s->dsp.me_sub_cmp[size];
232 chroma_cmp_sub= s->dsp.me_sub_cmp[size+1];
234 if(c->skip){ //FIXME somehow move up (benchmark)
235 *mx_ptr = 0;
236 *my_ptr = 0;
237 return dmin;
240 if(c->avctx->me_cmp != c->avctx->me_sub_cmp){
241 dmin= cmp(s, mx, my, 0, 0, size, h, ref_index, src_index, cmp_sub, chroma_cmp_sub, flags);
242 if(mx || my || size>0)
243 dmin += (mv_penalty[4*mx - pred_x] + mv_penalty[4*my - pred_y])*penalty_factor;
246 if (mx > xmin && mx < xmax &&
247 my > ymin && my < ymax) {
248 int bx=4*mx, by=4*my;
249 int d= dmin;
250 int i, nx, ny;
251 const int index= (my<<ME_MAP_SHIFT) + mx;
252 const int t= score_map[(index-(1<<ME_MAP_SHIFT) )&(ME_MAP_SIZE-1)];
253 const int l= score_map[(index- 1 )&(ME_MAP_SIZE-1)];
254 const int r= score_map[(index+ 1 )&(ME_MAP_SIZE-1)];
255 const int b= score_map[(index+(1<<ME_MAP_SHIFT) )&(ME_MAP_SIZE-1)];
256 const int c= score_map[(index )&(ME_MAP_SIZE-1)];
257 int best[8];
258 int best_pos[8][2];
260 memset(best, 64, sizeof(int)*8);
261 if(s->me.dia_size>=2){
262 const int tl= score_map[(index-(1<<ME_MAP_SHIFT)-1)&(ME_MAP_SIZE-1)];
263 const int bl= score_map[(index+(1<<ME_MAP_SHIFT)-1)&(ME_MAP_SIZE-1)];
264 const int tr= score_map[(index-(1<<ME_MAP_SHIFT)+1)&(ME_MAP_SIZE-1)];
265 const int br= score_map[(index+(1<<ME_MAP_SHIFT)+1)&(ME_MAP_SIZE-1)];
267 for(ny= -3; ny <= 3; ny++){
268 for(nx= -3; nx <= 3; nx++){
269 //FIXME this could overflow (unlikely though)
270 const int64_t t2= nx*nx*(tr + tl - 2*t) + 4*nx*(tr-tl) + 32*t;
271 const int64_t c2= nx*nx*( r + l - 2*c) + 4*nx*( r- l) + 32*c;
272 const int64_t b2= nx*nx*(br + bl - 2*b) + 4*nx*(br-bl) + 32*b;
273 int score= (ny*ny*(b2 + t2 - 2*c2) + 4*ny*(b2 - t2) + 32*c2 + 512)>>10;
274 int i;
276 if((nx&3)==0 && (ny&3)==0) continue;
278 score += (mv_penalty[4*mx + nx - pred_x] + mv_penalty[4*my + ny - pred_y])*penalty_factor;
280 // if(nx&1) score-=1024*c->penalty_factor;
281 // if(ny&1) score-=1024*c->penalty_factor;
283 for(i=0; i<8; i++){
284 if(score < best[i]){
285 memmove(&best[i+1], &best[i], sizeof(int)*(7-i));
286 memmove(&best_pos[i+1][0], &best_pos[i][0], sizeof(int)*2*(7-i));
287 best[i]= score;
288 best_pos[i][0]= nx + 4*mx;
289 best_pos[i][1]= ny + 4*my;
290 break;
295 }else{
296 int tl;
297 //FIXME this could overflow (unlikely though)
298 const int cx = 4*(r - l);
299 const int cx2= r + l - 2*c;
300 const int cy = 4*(b - t);
301 const int cy2= b + t - 2*c;
302 int cxy;
304 if(map[(index-(1<<ME_MAP_SHIFT)-1)&(ME_MAP_SIZE-1)] == (my<<ME_MAP_MV_BITS) + mx + map_generation && 0){ //FIXME
305 tl= score_map[(index-(1<<ME_MAP_SHIFT)-1)&(ME_MAP_SIZE-1)];
306 }else{
307 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
310 cxy= 2*tl + (cx + cy)/4 - (cx2 + cy2) - 2*c;
312 assert(16*cx2 + 4*cx + 32*c == 32*r);
313 assert(16*cx2 - 4*cx + 32*c == 32*l);
314 assert(16*cy2 + 4*cy + 32*c == 32*b);
315 assert(16*cy2 - 4*cy + 32*c == 32*t);
316 assert(16*cxy + 16*cy2 + 16*cx2 - 4*cy - 4*cx + 32*c == 32*tl);
318 for(ny= -3; ny <= 3; ny++){
319 for(nx= -3; nx <= 3; nx++){
320 //FIXME this could overflow (unlikely though)
321 int score= ny*nx*cxy + nx*nx*cx2 + ny*ny*cy2 + nx*cx + ny*cy + 32*c; //FIXME factor
322 int i;
324 if((nx&3)==0 && (ny&3)==0) continue;
326 score += 32*(mv_penalty[4*mx + nx - pred_x] + mv_penalty[4*my + ny - pred_y])*penalty_factor;
327 // if(nx&1) score-=32*c->penalty_factor;
328 // if(ny&1) score-=32*c->penalty_factor;
330 for(i=0; i<8; i++){
331 if(score < best[i]){
332 memmove(&best[i+1], &best[i], sizeof(int)*(7-i));
333 memmove(&best_pos[i+1][0], &best_pos[i][0], sizeof(int)*2*(7-i));
334 best[i]= score;
335 best_pos[i][0]= nx + 4*mx;
336 best_pos[i][1]= ny + 4*my;
337 break;
343 for(i=0; i<subpel_quality; i++){
344 nx= best_pos[i][0];
345 ny= best_pos[i][1];
346 CHECK_QUARTER_MV(nx&3, ny&3, nx>>2, ny>>2)
349 assert(bx >= xmin*4 && bx <= xmax*4 && by >= ymin*4 && by <= ymax*4);
351 *mx_ptr = bx;
352 *my_ptr = by;
353 }else{
354 *mx_ptr =4*mx;
355 *my_ptr =4*my;
358 return dmin;
362 #define CHECK_MV(x,y)\
364 const unsigned key = ((y)<<ME_MAP_MV_BITS) + (x) + map_generation;\
365 const int index= (((y)<<ME_MAP_SHIFT) + (x))&(ME_MAP_SIZE-1);\
366 assert((x) >= xmin);\
367 assert((x) <= xmax);\
368 assert((y) >= ymin);\
369 assert((y) <= ymax);\
370 if(map[index]!=key){\
371 d= cmp(s, x, y, 0, 0, size, h, ref_index, src_index, cmpf, chroma_cmpf, flags);\
372 map[index]= key;\
373 score_map[index]= d;\
374 d += (mv_penalty[((x)<<shift)-pred_x] + mv_penalty[((y)<<shift)-pred_y])*penalty_factor;\
375 COPY3_IF_LT(dmin, d, best[0], x, best[1], y)\
379 #define CHECK_CLIPPED_MV(ax,ay)\
381 const int Lx= ax;\
382 const int Ly= ay;\
383 const int Lx2= FFMAX(xmin, FFMIN(Lx, xmax));\
384 const int Ly2= FFMAX(ymin, FFMIN(Ly, ymax));\
385 CHECK_MV(Lx2, Ly2)\
388 #define CHECK_MV_DIR(x,y,new_dir)\
390 const unsigned key = ((y)<<ME_MAP_MV_BITS) + (x) + map_generation;\
391 const int index= (((y)<<ME_MAP_SHIFT) + (x))&(ME_MAP_SIZE-1);\
392 if(map[index]!=key){\
393 d= cmp(s, x, y, 0, 0, size, h, ref_index, src_index, cmpf, chroma_cmpf, flags);\
394 map[index]= key;\
395 score_map[index]= d;\
396 d += (mv_penalty[((x)<<shift)-pred_x] + mv_penalty[((y)<<shift)-pred_y])*penalty_factor;\
397 if(d<dmin){\
398 best[0]=x;\
399 best[1]=y;\
400 dmin=d;\
401 next_dir= new_dir;\
406 #define check(x,y,S,v)\
407 if( (x)<(xmin<<(S)) ) printf("%d %d %d %d %d xmin" #v, xmin, (x), (y), s->mb_x, s->mb_y);\
408 if( (x)>(xmax<<(S)) ) printf("%d %d %d %d %d xmax" #v, xmax, (x), (y), s->mb_x, s->mb_y);\
409 if( (y)<(ymin<<(S)) ) printf("%d %d %d %d %d ymin" #v, ymin, (x), (y), s->mb_x, s->mb_y);\
410 if( (y)>(ymax<<(S)) ) printf("%d %d %d %d %d ymax" #v, ymax, (x), (y), s->mb_x, s->mb_y);\
412 #define LOAD_COMMON2\
413 uint32_t *map= c->map;\
414 const int qpel= flags&FLAG_QPEL;\
415 const int shift= 1+qpel;\
417 static av_always_inline int small_diamond_search(MpegEncContext * s, int *best, int dmin,
418 int src_index, int ref_index, int const penalty_factor,
419 int size, int h, int flags)
421 MotionEstContext * const c= &s->me;
422 me_cmp_func cmpf, chroma_cmpf;
423 int next_dir=-1;
424 LOAD_COMMON
425 LOAD_COMMON2
426 unsigned map_generation = c->map_generation;
428 cmpf= s->dsp.me_cmp[size];
429 chroma_cmpf= s->dsp.me_cmp[size+1];
431 { /* ensure that the best point is in the MAP as h/qpel refinement needs it */
432 const unsigned key = (best[1]<<ME_MAP_MV_BITS) + best[0] + map_generation;
433 const int index= ((best[1]<<ME_MAP_SHIFT) + best[0])&(ME_MAP_SIZE-1);
434 if(map[index]!=key){ //this will be executed only very rarey
435 score_map[index]= cmp(s, best[0], best[1], 0, 0, size, h, ref_index, src_index, cmpf, chroma_cmpf, flags);
436 map[index]= key;
440 for(;;){
441 int d;
442 const int dir= next_dir;
443 const int x= best[0];
444 const int y= best[1];
445 next_dir=-1;
447 if(dir!=2 && x>xmin) CHECK_MV_DIR(x-1, y , 0)
448 if(dir!=3 && y>ymin) CHECK_MV_DIR(x , y-1, 1)
449 if(dir!=0 && x<xmax) CHECK_MV_DIR(x+1, y , 2)
450 if(dir!=1 && y<ymax) CHECK_MV_DIR(x , y+1, 3)
452 if(next_dir==-1){
453 return dmin;
458 static int funny_diamond_search(MpegEncContext * s, int *best, int dmin,
459 int src_index, int ref_index, int const penalty_factor,
460 int size, int h, int flags)
462 MotionEstContext * const c= &s->me;
463 me_cmp_func cmpf, chroma_cmpf;
464 int dia_size;
465 LOAD_COMMON
466 LOAD_COMMON2
467 unsigned map_generation = c->map_generation;
469 cmpf= s->dsp.me_cmp[size];
470 chroma_cmpf= s->dsp.me_cmp[size+1];
472 for(dia_size=1; dia_size<=4; dia_size++){
473 int dir;
474 const int x= best[0];
475 const int y= best[1];
477 if(dia_size&(dia_size-1)) continue;
479 if( x + dia_size > xmax
480 || x - dia_size < xmin
481 || y + dia_size > ymax
482 || y - dia_size < ymin)
483 continue;
485 for(dir= 0; dir<dia_size; dir+=2){
486 int d;
488 CHECK_MV(x + dir , y + dia_size - dir);
489 CHECK_MV(x + dia_size - dir, y - dir );
490 CHECK_MV(x - dir , y - dia_size + dir);
491 CHECK_MV(x - dia_size + dir, y + dir );
494 if(x!=best[0] || y!=best[1])
495 dia_size=0;
497 return dmin;
500 static int hex_search(MpegEncContext * s, int *best, int dmin,
501 int src_index, int ref_index, int const penalty_factor,
502 int size, int h, int flags, int dia_size)
504 MotionEstContext * const c= &s->me;
505 me_cmp_func cmpf, chroma_cmpf;
506 LOAD_COMMON
507 LOAD_COMMON2
508 unsigned map_generation = c->map_generation;
509 int x,y,d;
510 const int dec= dia_size & (dia_size-1);
512 cmpf= s->dsp.me_cmp[size];
513 chroma_cmpf= s->dsp.me_cmp[size+1];
515 for(;dia_size; dia_size= dec ? dia_size-1 : dia_size>>1){
517 x= best[0];
518 y= best[1];
520 CHECK_CLIPPED_MV(x -dia_size , y);
521 CHECK_CLIPPED_MV(x+ dia_size , y);
522 CHECK_CLIPPED_MV(x+( dia_size>>1), y+dia_size);
523 CHECK_CLIPPED_MV(x+( dia_size>>1), y-dia_size);
524 if(dia_size>1){
525 CHECK_CLIPPED_MV(x+(-dia_size>>1), y+dia_size);
526 CHECK_CLIPPED_MV(x+(-dia_size>>1), y-dia_size);
528 }while(best[0] != x || best[1] != y);
531 return dmin;
534 static int l2s_dia_search(MpegEncContext * s, int *best, int dmin,
535 int src_index, int ref_index, int const penalty_factor,
536 int size, int h, int flags)
538 MotionEstContext * const c= &s->me;
539 me_cmp_func cmpf, chroma_cmpf;
540 LOAD_COMMON
541 LOAD_COMMON2
542 unsigned map_generation = c->map_generation;
543 int x,y,i,d;
544 int dia_size= c->dia_size&0xFF;
545 const int dec= dia_size & (dia_size-1);
546 static const int hex[8][2]={{-2, 0}, {-1,-1}, { 0,-2}, { 1,-1},
547 { 2, 0}, { 1, 1}, { 0, 2}, {-1, 1}};
549 cmpf= s->dsp.me_cmp[size];
550 chroma_cmpf= s->dsp.me_cmp[size+1];
552 for(; dia_size; dia_size= dec ? dia_size-1 : dia_size>>1){
554 x= best[0];
555 y= best[1];
556 for(i=0; i<8; i++){
557 CHECK_CLIPPED_MV(x+hex[i][0]*dia_size, y+hex[i][1]*dia_size);
559 }while(best[0] != x || best[1] != y);
562 x= best[0];
563 y= best[1];
564 CHECK_CLIPPED_MV(x+1, y);
565 CHECK_CLIPPED_MV(x, y+1);
566 CHECK_CLIPPED_MV(x-1, y);
567 CHECK_CLIPPED_MV(x, y-1);
569 return dmin;
572 static int umh_search(MpegEncContext * s, int *best, int dmin,
573 int src_index, int ref_index, int const penalty_factor,
574 int size, int h, int flags)
576 MotionEstContext * const c= &s->me;
577 me_cmp_func cmpf, chroma_cmpf;
578 LOAD_COMMON
579 LOAD_COMMON2
580 unsigned map_generation = c->map_generation;
581 int x,y,x2,y2, i, j, d;
582 const int dia_size= c->dia_size&0xFE;
583 static const int hex[16][2]={{-4,-2}, {-4,-1}, {-4, 0}, {-4, 1}, {-4, 2},
584 { 4,-2}, { 4,-1}, { 4, 0}, { 4, 1}, { 4, 2},
585 {-2, 3}, { 0, 4}, { 2, 3},
586 {-2,-3}, { 0,-4}, { 2,-3},};
588 cmpf= s->dsp.me_cmp[size];
589 chroma_cmpf= s->dsp.me_cmp[size+1];
591 x= best[0];
592 y= best[1];
593 for(x2=FFMAX(x-dia_size+1, xmin); x2<=FFMIN(x+dia_size-1,xmax); x2+=2){
594 CHECK_MV(x2, y);
596 for(y2=FFMAX(y-dia_size/2+1, ymin); y2<=FFMIN(y+dia_size/2-1,ymax); y2+=2){
597 CHECK_MV(x, y2);
600 x= best[0];
601 y= best[1];
602 for(y2=FFMAX(y-2, ymin); y2<=FFMIN(y+2,ymax); y2++){
603 for(x2=FFMAX(x-2, xmin); x2<=FFMIN(x+2,xmax); x2++){
604 CHECK_MV(x2, y2);
608 //FIXME prevent the CLIP stuff
610 for(j=1; j<=dia_size/4; j++){
611 for(i=0; i<16; i++){
612 CHECK_CLIPPED_MV(x+hex[i][0]*j, y+hex[i][1]*j);
616 return hex_search(s, best, dmin, src_index, ref_index, penalty_factor, size, h, flags, 2);
619 static int full_search(MpegEncContext * s, int *best, int dmin,
620 int src_index, int ref_index, int const penalty_factor,
621 int size, int h, int flags)
623 MotionEstContext * const c= &s->me;
624 me_cmp_func cmpf, chroma_cmpf;
625 LOAD_COMMON
626 LOAD_COMMON2
627 unsigned map_generation = c->map_generation;
628 int x,y, d;
629 const int dia_size= c->dia_size&0xFF;
631 cmpf= s->dsp.me_cmp[size];
632 chroma_cmpf= s->dsp.me_cmp[size+1];
634 for(y=FFMAX(-dia_size, ymin); y<=FFMIN(dia_size,ymax); y++){
635 for(x=FFMAX(-dia_size, xmin); x<=FFMIN(dia_size,xmax); x++){
636 CHECK_MV(x, y);
640 x= best[0];
641 y= best[1];
642 d= dmin;
643 CHECK_CLIPPED_MV(x , y);
644 CHECK_CLIPPED_MV(x+1, y);
645 CHECK_CLIPPED_MV(x, y+1);
646 CHECK_CLIPPED_MV(x-1, y);
647 CHECK_CLIPPED_MV(x, y-1);
648 best[0]= x;
649 best[1]= y;
651 return d;
654 #define SAB_CHECK_MV(ax,ay)\
656 const unsigned key = ((ay)<<ME_MAP_MV_BITS) + (ax) + map_generation;\
657 const int index= (((ay)<<ME_MAP_SHIFT) + (ax))&(ME_MAP_SIZE-1);\
658 if(map[index]!=key){\
659 d= cmp(s, ax, ay, 0, 0, size, h, ref_index, src_index, cmpf, chroma_cmpf, flags);\
660 map[index]= key;\
661 score_map[index]= d;\
662 d += (mv_penalty[((ax)<<shift)-pred_x] + mv_penalty[((ay)<<shift)-pred_y])*penalty_factor;\
663 if(d < minima[minima_count-1].height){\
664 int j=0;\
666 while(d >= minima[j].height) j++;\
668 memmove(&minima [j+1], &minima [j], (minima_count - j - 1)*sizeof(Minima));\
670 minima[j].checked= 0;\
671 minima[j].height= d;\
672 minima[j].x= ax;\
673 minima[j].y= ay;\
675 i=-1;\
676 continue;\
681 #define MAX_SAB_SIZE ME_MAP_SIZE
682 static int sab_diamond_search(MpegEncContext * s, int *best, int dmin,
683 int src_index, int ref_index, int const penalty_factor,
684 int size, int h, int flags)
686 MotionEstContext * const c= &s->me;
687 me_cmp_func cmpf, chroma_cmpf;
688 Minima minima[MAX_SAB_SIZE];
689 const int minima_count= FFABS(c->dia_size);
690 int i, j;
691 LOAD_COMMON
692 LOAD_COMMON2
693 unsigned map_generation = c->map_generation;
695 cmpf= s->dsp.me_cmp[size];
696 chroma_cmpf= s->dsp.me_cmp[size+1];
698 /*Note j<MAX_SAB_SIZE is needed if MAX_SAB_SIZE < ME_MAP_SIZE as j can
699 become larger due to MVs overflowing their ME_MAP_MV_BITS bits space in map
701 for(j=i=0; i<ME_MAP_SIZE && j<MAX_SAB_SIZE; i++){
702 uint32_t key= map[i];
704 key += (1<<(ME_MAP_MV_BITS-1)) + (1<<(2*ME_MAP_MV_BITS-1));
706 if((key&((-1)<<(2*ME_MAP_MV_BITS))) != map_generation) continue;
708 minima[j].height= score_map[i];
709 minima[j].x= key & ((1<<ME_MAP_MV_BITS)-1); key>>=ME_MAP_MV_BITS;
710 minima[j].y= key & ((1<<ME_MAP_MV_BITS)-1);
711 minima[j].x-= (1<<(ME_MAP_MV_BITS-1));
712 minima[j].y-= (1<<(ME_MAP_MV_BITS-1));
714 // all entries in map should be in range except if the mv overflows their ME_MAP_MV_BITS bits space
715 if( minima[j].x > xmax || minima[j].x < xmin
716 || minima[j].y > ymax || minima[j].y < ymin)
717 continue;
719 minima[j].checked=0;
720 if(minima[j].x || minima[j].y)
721 minima[j].height+= (mv_penalty[((minima[j].x)<<shift)-pred_x] + mv_penalty[((minima[j].y)<<shift)-pred_y])*penalty_factor;
723 j++;
726 qsort(minima, j, sizeof(Minima), minima_cmp);
728 for(; j<minima_count; j++){
729 minima[j].height=256*256*256*64;
730 minima[j].checked=0;
731 minima[j].x= minima[j].y=0;
734 for(i=0; i<minima_count; i++){
735 const int x= minima[i].x;
736 const int y= minima[i].y;
737 int d;
739 if(minima[i].checked) continue;
741 if( x >= xmax || x <= xmin
742 || y >= ymax || y <= ymin)
743 continue;
745 SAB_CHECK_MV(x-1, y)
746 SAB_CHECK_MV(x+1, y)
747 SAB_CHECK_MV(x , y-1)
748 SAB_CHECK_MV(x , y+1)
750 minima[i].checked= 1;
753 best[0]= minima[0].x;
754 best[1]= minima[0].y;
755 dmin= minima[0].height;
757 if( best[0] < xmax && best[0] > xmin
758 && best[1] < ymax && best[1] > ymin){
759 int d;
760 //ensure that the refernece samples for hpel refinement are in the map
761 CHECK_MV(best[0]-1, best[1])
762 CHECK_MV(best[0]+1, best[1])
763 CHECK_MV(best[0], best[1]-1)
764 CHECK_MV(best[0], best[1]+1)
766 return dmin;
769 static int var_diamond_search(MpegEncContext * s, int *best, int dmin,
770 int src_index, int ref_index, int const penalty_factor,
771 int size, int h, int flags)
773 MotionEstContext * const c= &s->me;
774 me_cmp_func cmpf, chroma_cmpf;
775 int dia_size;
776 LOAD_COMMON
777 LOAD_COMMON2
778 unsigned map_generation = c->map_generation;
780 cmpf= s->dsp.me_cmp[size];
781 chroma_cmpf= s->dsp.me_cmp[size+1];
783 for(dia_size=1; dia_size<=c->dia_size; dia_size++){
784 int dir, start, end;
785 const int x= best[0];
786 const int y= best[1];
788 start= FFMAX(0, y + dia_size - ymax);
789 end = FFMIN(dia_size, xmax - x + 1);
790 for(dir= start; dir<end; dir++){
791 int d;
793 //check(x + dir,y + dia_size - dir,0, a0)
794 CHECK_MV(x + dir , y + dia_size - dir);
797 start= FFMAX(0, x + dia_size - xmax);
798 end = FFMIN(dia_size, y - ymin + 1);
799 for(dir= start; dir<end; dir++){
800 int d;
802 //check(x + dia_size - dir, y - dir,0, a1)
803 CHECK_MV(x + dia_size - dir, y - dir );
806 start= FFMAX(0, -y + dia_size + ymin );
807 end = FFMIN(dia_size, x - xmin + 1);
808 for(dir= start; dir<end; dir++){
809 int d;
811 //check(x - dir,y - dia_size + dir,0, a2)
812 CHECK_MV(x - dir , y - dia_size + dir);
815 start= FFMAX(0, -x + dia_size + xmin );
816 end = FFMIN(dia_size, ymax - y + 1);
817 for(dir= start; dir<end; dir++){
818 int d;
820 //check(x - dia_size + dir, y + dir,0, a3)
821 CHECK_MV(x - dia_size + dir, y + dir );
824 if(x!=best[0] || y!=best[1])
825 dia_size=0;
827 return dmin;
830 static av_always_inline int diamond_search(MpegEncContext * s, int *best, int dmin,
831 int src_index, int ref_index, int const penalty_factor,
832 int size, int h, int flags){
833 MotionEstContext * const c= &s->me;
834 if(c->dia_size==-1)
835 return funny_diamond_search(s, best, dmin, src_index, ref_index, penalty_factor, size, h, flags);
836 else if(c->dia_size<-1)
837 return sab_diamond_search(s, best, dmin, src_index, ref_index, penalty_factor, size, h, flags);
838 else if(c->dia_size<2)
839 return small_diamond_search(s, best, dmin, src_index, ref_index, penalty_factor, size, h, flags);
840 else if(c->dia_size>1024)
841 return full_search(s, best, dmin, src_index, ref_index, penalty_factor, size, h, flags);
842 else if(c->dia_size>768)
843 return umh_search(s, best, dmin, src_index, ref_index, penalty_factor, size, h, flags);
844 else if(c->dia_size>512)
845 return hex_search(s, best, dmin, src_index, ref_index, penalty_factor, size, h, flags, c->dia_size&0xFF);
846 else if(c->dia_size>256)
847 return l2s_dia_search(s, best, dmin, src_index, ref_index, penalty_factor, size, h, flags);
848 else
849 return var_diamond_search(s, best, dmin, src_index, ref_index, penalty_factor, size, h, flags);
853 @param P a list of candidate mvs to check before starting the
854 iterative search. If one of the candidates is close to the optimal mv, then
855 it takes fewer iterations. And it increases the chance that we find the
856 optimal mv.
858 static av_always_inline int epzs_motion_search_internal(MpegEncContext * s, int *mx_ptr, int *my_ptr,
859 int P[10][2], int src_index, int ref_index, int16_t (*last_mv)[2],
860 int ref_mv_scale, int flags, int size, int h)
862 MotionEstContext * const c= &s->me;
863 int best[2]={0, 0}; /**< x and y coordinates of the best motion vector.
864 i.e. the difference between the position of the
865 block currently being encoded and the position of
866 the block chosen to predict it from. */
867 int d; ///< the score (cmp + penalty) of any given mv
868 int dmin; /**< the best value of d, i.e. the score
869 corresponding to the mv stored in best[]. */
870 unsigned map_generation;
871 int penalty_factor;
872 const int ref_mv_stride= s->mb_stride; //pass as arg FIXME
873 const int ref_mv_xy= s->mb_x + s->mb_y*ref_mv_stride; //add to last_mv beforepassing FIXME
874 me_cmp_func cmpf, chroma_cmpf;
876 LOAD_COMMON
877 LOAD_COMMON2
879 if(c->pre_pass){
880 penalty_factor= c->pre_penalty_factor;
881 cmpf= s->dsp.me_pre_cmp[size];
882 chroma_cmpf= s->dsp.me_pre_cmp[size+1];
883 }else{
884 penalty_factor= c->penalty_factor;
885 cmpf= s->dsp.me_cmp[size];
886 chroma_cmpf= s->dsp.me_cmp[size+1];
889 map_generation= update_map_generation(c);
891 assert(cmpf);
892 dmin= cmp(s, 0, 0, 0, 0, size, h, ref_index, src_index, cmpf, chroma_cmpf, flags);
893 map[0]= map_generation;
894 score_map[0]= dmin;
896 //FIXME precalc first term below?
897 if((s->pict_type == AV_PICTURE_TYPE_B && !(c->flags & FLAG_DIRECT)) || s->flags&CODEC_FLAG_MV0)
898 dmin += (mv_penalty[pred_x] + mv_penalty[pred_y])*penalty_factor;
900 /* first line */
901 if (s->first_slice_line) {
902 CHECK_MV(P_LEFT[0]>>shift, P_LEFT[1]>>shift)
903 CHECK_CLIPPED_MV((last_mv[ref_mv_xy][0]*ref_mv_scale + (1<<15))>>16,
904 (last_mv[ref_mv_xy][1]*ref_mv_scale + (1<<15))>>16)
905 }else{
906 if(dmin<((h*h*s->avctx->mv0_threshold)>>8)
907 && ( P_LEFT[0] |P_LEFT[1]
908 |P_TOP[0] |P_TOP[1]
909 |P_TOPRIGHT[0]|P_TOPRIGHT[1])==0){
910 *mx_ptr= 0;
911 *my_ptr= 0;
912 c->skip=1;
913 return dmin;
915 CHECK_MV( P_MEDIAN[0] >>shift , P_MEDIAN[1] >>shift)
916 CHECK_CLIPPED_MV((P_MEDIAN[0]>>shift) , (P_MEDIAN[1]>>shift)-1)
917 CHECK_CLIPPED_MV((P_MEDIAN[0]>>shift) , (P_MEDIAN[1]>>shift)+1)
918 CHECK_CLIPPED_MV((P_MEDIAN[0]>>shift)-1, (P_MEDIAN[1]>>shift) )
919 CHECK_CLIPPED_MV((P_MEDIAN[0]>>shift)+1, (P_MEDIAN[1]>>shift) )
920 CHECK_CLIPPED_MV((last_mv[ref_mv_xy][0]*ref_mv_scale + (1<<15))>>16,
921 (last_mv[ref_mv_xy][1]*ref_mv_scale + (1<<15))>>16)
922 CHECK_MV(P_LEFT[0] >>shift, P_LEFT[1] >>shift)
923 CHECK_MV(P_TOP[0] >>shift, P_TOP[1] >>shift)
924 CHECK_MV(P_TOPRIGHT[0]>>shift, P_TOPRIGHT[1]>>shift)
926 if(dmin>h*h*4){
927 if(c->pre_pass){
928 CHECK_CLIPPED_MV((last_mv[ref_mv_xy-1][0]*ref_mv_scale + (1<<15))>>16,
929 (last_mv[ref_mv_xy-1][1]*ref_mv_scale + (1<<15))>>16)
930 if(!s->first_slice_line)
931 CHECK_CLIPPED_MV((last_mv[ref_mv_xy-ref_mv_stride][0]*ref_mv_scale + (1<<15))>>16,
932 (last_mv[ref_mv_xy-ref_mv_stride][1]*ref_mv_scale + (1<<15))>>16)
933 }else{
934 CHECK_CLIPPED_MV((last_mv[ref_mv_xy+1][0]*ref_mv_scale + (1<<15))>>16,
935 (last_mv[ref_mv_xy+1][1]*ref_mv_scale + (1<<15))>>16)
936 if(s->mb_y+1<s->end_mb_y) //FIXME replace at least with last_slice_line
937 CHECK_CLIPPED_MV((last_mv[ref_mv_xy+ref_mv_stride][0]*ref_mv_scale + (1<<15))>>16,
938 (last_mv[ref_mv_xy+ref_mv_stride][1]*ref_mv_scale + (1<<15))>>16)
942 if(c->avctx->last_predictor_count){
943 const int count= c->avctx->last_predictor_count;
944 const int xstart= FFMAX(0, s->mb_x - count);
945 const int ystart= FFMAX(0, s->mb_y - count);
946 const int xend= FFMIN(s->mb_width , s->mb_x + count + 1);
947 const int yend= FFMIN(s->mb_height, s->mb_y + count + 1);
948 int mb_y;
950 for(mb_y=ystart; mb_y<yend; mb_y++){
951 int mb_x;
952 for(mb_x=xstart; mb_x<xend; mb_x++){
953 const int xy= mb_x + 1 + (mb_y + 1)*ref_mv_stride;
954 int mx= (last_mv[xy][0]*ref_mv_scale + (1<<15))>>16;
955 int my= (last_mv[xy][1]*ref_mv_scale + (1<<15))>>16;
957 if(mx>xmax || mx<xmin || my>ymax || my<ymin) continue;
958 CHECK_MV(mx,my)
963 //check(best[0],best[1],0, b0)
964 dmin= diamond_search(s, best, dmin, src_index, ref_index, penalty_factor, size, h, flags);
966 //check(best[0],best[1],0, b1)
967 *mx_ptr= best[0];
968 *my_ptr= best[1];
970 return dmin;
973 //this function is dedicated to the braindamaged gcc
974 int ff_epzs_motion_search(MpegEncContext *s, int *mx_ptr, int *my_ptr,
975 int P[10][2], int src_index, int ref_index,
976 int16_t (*last_mv)[2], int ref_mv_scale,
977 int size, int h)
979 MotionEstContext * const c= &s->me;
980 //FIXME convert other functions in the same way if faster
981 if(c->flags==0 && h==16 && size==0){
982 return epzs_motion_search_internal(s, mx_ptr, my_ptr, P, src_index, ref_index, last_mv, ref_mv_scale, 0, 0, 16);
983 // case FLAG_QPEL:
984 // return epzs_motion_search_internal(s, mx_ptr, my_ptr, P, src_index, ref_index, last_mv, ref_mv_scale, FLAG_QPEL);
985 }else{
986 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 static int epzs_motion_search4(MpegEncContext * s,
991 int *mx_ptr, int *my_ptr, int P[10][2],
992 int src_index, int ref_index, int16_t (*last_mv)[2],
993 int ref_mv_scale)
995 MotionEstContext * const c= &s->me;
996 int best[2]={0, 0};
997 int d, dmin;
998 unsigned map_generation;
999 const int penalty_factor= c->penalty_factor;
1000 const int size=1;
1001 const int h=8;
1002 const int ref_mv_stride= s->mb_stride;
1003 const int ref_mv_xy= s->mb_x + s->mb_y *ref_mv_stride;
1004 me_cmp_func cmpf, chroma_cmpf;
1005 LOAD_COMMON
1006 int flags= c->flags;
1007 LOAD_COMMON2
1009 cmpf= s->dsp.me_cmp[size];
1010 chroma_cmpf= s->dsp.me_cmp[size+1];
1012 map_generation= update_map_generation(c);
1014 dmin = 1000000;
1016 /* first line */
1017 if (s->first_slice_line) {
1018 CHECK_MV(P_LEFT[0]>>shift, P_LEFT[1]>>shift)
1019 CHECK_CLIPPED_MV((last_mv[ref_mv_xy][0]*ref_mv_scale + (1<<15))>>16,
1020 (last_mv[ref_mv_xy][1]*ref_mv_scale + (1<<15))>>16)
1021 CHECK_MV(P_MV1[0]>>shift, P_MV1[1]>>shift)
1022 }else{
1023 CHECK_MV(P_MV1[0]>>shift, P_MV1[1]>>shift)
1024 //FIXME try some early stop
1025 CHECK_MV(P_MEDIAN[0]>>shift, P_MEDIAN[1]>>shift)
1026 CHECK_MV(P_LEFT[0]>>shift, P_LEFT[1]>>shift)
1027 CHECK_MV(P_TOP[0]>>shift, P_TOP[1]>>shift)
1028 CHECK_MV(P_TOPRIGHT[0]>>shift, P_TOPRIGHT[1]>>shift)
1029 CHECK_CLIPPED_MV((last_mv[ref_mv_xy][0]*ref_mv_scale + (1<<15))>>16,
1030 (last_mv[ref_mv_xy][1]*ref_mv_scale + (1<<15))>>16)
1032 if(dmin>64*4){
1033 CHECK_CLIPPED_MV((last_mv[ref_mv_xy+1][0]*ref_mv_scale + (1<<15))>>16,
1034 (last_mv[ref_mv_xy+1][1]*ref_mv_scale + (1<<15))>>16)
1035 if(s->mb_y+1<s->end_mb_y) //FIXME replace at least with last_slice_line
1036 CHECK_CLIPPED_MV((last_mv[ref_mv_xy+ref_mv_stride][0]*ref_mv_scale + (1<<15))>>16,
1037 (last_mv[ref_mv_xy+ref_mv_stride][1]*ref_mv_scale + (1<<15))>>16)
1040 dmin= diamond_search(s, best, dmin, src_index, ref_index, penalty_factor, size, h, flags);
1042 *mx_ptr= best[0];
1043 *my_ptr= best[1];
1045 return dmin;
1048 //try to merge with above FIXME (needs PSNR test)
1049 static int epzs_motion_search2(MpegEncContext * s,
1050 int *mx_ptr, int *my_ptr, int P[10][2],
1051 int src_index, int ref_index, int16_t (*last_mv)[2],
1052 int ref_mv_scale)
1054 MotionEstContext * const c= &s->me;
1055 int best[2]={0, 0};
1056 int d, dmin;
1057 unsigned map_generation;
1058 const int penalty_factor= c->penalty_factor;
1059 const int size=0; //FIXME pass as arg
1060 const int h=8;
1061 const int ref_mv_stride= s->mb_stride;
1062 const int ref_mv_xy= s->mb_x + s->mb_y *ref_mv_stride;
1063 me_cmp_func cmpf, chroma_cmpf;
1064 LOAD_COMMON
1065 int flags= c->flags;
1066 LOAD_COMMON2
1068 cmpf= s->dsp.me_cmp[size];
1069 chroma_cmpf= s->dsp.me_cmp[size+1];
1071 map_generation= update_map_generation(c);
1073 dmin = 1000000;
1075 /* first line */
1076 if (s->first_slice_line) {
1077 CHECK_MV(P_LEFT[0]>>shift, P_LEFT[1]>>shift)
1078 CHECK_CLIPPED_MV((last_mv[ref_mv_xy][0]*ref_mv_scale + (1<<15))>>16,
1079 (last_mv[ref_mv_xy][1]*ref_mv_scale + (1<<15))>>16)
1080 CHECK_MV(P_MV1[0]>>shift, P_MV1[1]>>shift)
1081 }else{
1082 CHECK_MV(P_MV1[0]>>shift, P_MV1[1]>>shift)
1083 //FIXME try some early stop
1084 CHECK_MV(P_MEDIAN[0]>>shift, P_MEDIAN[1]>>shift)
1085 CHECK_MV(P_LEFT[0]>>shift, P_LEFT[1]>>shift)
1086 CHECK_MV(P_TOP[0]>>shift, P_TOP[1]>>shift)
1087 CHECK_MV(P_TOPRIGHT[0]>>shift, P_TOPRIGHT[1]>>shift)
1088 CHECK_CLIPPED_MV((last_mv[ref_mv_xy][0]*ref_mv_scale + (1<<15))>>16,
1089 (last_mv[ref_mv_xy][1]*ref_mv_scale + (1<<15))>>16)
1091 if(dmin>64*4){
1092 CHECK_CLIPPED_MV((last_mv[ref_mv_xy+1][0]*ref_mv_scale + (1<<15))>>16,
1093 (last_mv[ref_mv_xy+1][1]*ref_mv_scale + (1<<15))>>16)
1094 if(s->mb_y+1<s->end_mb_y) //FIXME replace at least with last_slice_line
1095 CHECK_CLIPPED_MV((last_mv[ref_mv_xy+ref_mv_stride][0]*ref_mv_scale + (1<<15))>>16,
1096 (last_mv[ref_mv_xy+ref_mv_stride][1]*ref_mv_scale + (1<<15))>>16)
1099 dmin= diamond_search(s, best, dmin, src_index, ref_index, penalty_factor, size, h, flags);
1101 *mx_ptr= best[0];
1102 *my_ptr= best[1];
1104 return dmin;