r955: Fix the Diffkey icon.
[cinelerra_cv.git] / quicktime / encore50 / mot_est_mb.c
blob1b4177f43d4a25b5e873ea90a4043723c09fabf6
2 /**************************************************************************
3 * *
4 * This code is developed by Adam Li. This software is an *
5 * implementation of a part of one or more MPEG-4 Video tools as *
6 * specified in ISO/IEC 14496-2 standard. Those intending to use this *
7 * software module in hardware or software products are advised that its *
8 * use may infringe existing patents or copyrights, and any such use *
9 * would be at such party's own risk. The original developer of this *
10 * software module and his/her company, and subsequent editors and their *
11 * companies (including Project Mayo), will have no liability for use of *
12 * this software or modifications or derivatives thereof. *
13 * *
14 * Project Mayo gives users of the Codec a license to this software *
15 * module or modifications thereof for use in hardware or software *
16 * products claiming conformance to the MPEG-4 Video Standard as *
17 * described in the Open DivX license. *
18 * *
19 * The complete Open DivX license can be found at *
20 * http://www.projectmayo.com/opendivx/license.php . *
21 * *
22 **************************************************************************/
24 /**************************************************************************
26 * mot_est_mb.c
28 * Copyright (C) 2001 Project Mayo
30 * Adam Li
32 * DivX Advance Research Center <darc@projectmayo.com>
34 **************************************************************************/
36 /* This file contains some functions to do motion estimation and */
37 /* for one MacroBlock in one pass. */
38 /* Some codes of this project come from MoMuSys MPEG-4 implementation. */
39 /* Please see seperate acknowledgement file for a list of contributors. */
41 #include "mot_util.h"
43 /* Obtaining if two floating point values are equal*/
44 #define ABSDOUBLE(x) (((x) > 0.0001) ? (x) : (((x) < -0.0001) ? -(x): 0.0 ))
45 #define ARE_EQUAL(x,y) ( (ABSDOUBLE((Float)(x)-(y))>0.1)?(0):(1) )
47 /* auxiliar define for indexing in MBMotionEstimation */
48 #define INDEX_BIG(x,y) ((x)+(y)*(vop_width))
49 #define INDEX_NOR(x,y) ((x)+(y)*(MB_SIZE))
51 /* ------------------------------------------------------------------------- */
53 /***********************************************************CommentBegin******
55 * -- RangeInSearchArea -- computes the range of the search area
57 * Purpose :
58 * computes the range of the search area for the predicted MV's
59 * INSIDE the overlapped zone between reference and current vops
61 ***********************************************************CommentEnd********/
63 static Void
64 RangeInSearchArea(
65 Int i, /* <-- horizontal MBcoordinate in pixels */
66 Int j, /* <-- vertical MB coordinate in pixels */
67 Int block, /* <-- block position (0 16x16; 1-2-3-4 8x8) */
68 Int prev_x, /* <-- absolute horizontal position of the previous vop*/
69 Int prev_y, /* <-- absolute vertical position of the previous vop */
70 Int vop_width, /* <-- horizontal vop dimension */
71 Int vop_height, /* <-- vertical vop dimension */
72 Int br_x, /* <-- absolute horizontal position of the current vop */
73 Int br_y, /* <-- absolute vertical position of the current vop */
74 Int edge, /* <-- edge arround the reference vop */
75 Int f_code, /* <- MV search range 1/2 (or 1/4) pel: (0=16,) 1=32,2=64,...,7=2048 */
76 Float *mv_x_min, /* <-- min horizontal range */
77 Float *mv_x_max, /* <-- max horizontal range */
78 Float *mv_y_min, /* <-- min vertical range */
79 Float *mv_y_max, /* <-- max vertical range */
80 Int *out /* --> the search area does not exist (the reference */ /* and current BB does not overlap) */
83 Int dim_curr_x_max,
84 dim_curr_y_max,
85 dim_curr_x_min,
86 dim_curr_y_min;
87 Int dim_prev_x_max,
88 dim_prev_y_max,
89 dim_prev_x_min,
90 dim_prev_y_min;
91 Int mb_b_size,
92 block_x,
93 block_y;
95 *out=0;
97 switch (block)
99 case 0: /* 8x8 or 16x16 block search */
100 block_x=0; /*****************************/
101 block_y=0; /** 1 2 ******** 0 *********/
102 mb_b_size=MB_SIZE; /** 3 4 ******** *********/
103 break; /*****************************/
104 case 1:
105 block_x=0;
106 block_y=0;
107 mb_b_size=B_SIZE;
108 break;
109 case 2:
110 block_x=B_SIZE;
111 block_y=0;
112 mb_b_size=B_SIZE;
113 break;
114 case 3:
115 block_x=0;
116 block_y=B_SIZE;
117 mb_b_size=B_SIZE;
118 break;
119 case 4:
120 block_x=B_SIZE;
121 block_y=B_SIZE;
122 mb_b_size=B_SIZE;
123 break;
124 default:
125 return;
128 /* min x/y */
129 dim_curr_x_min=(Int)(br_x+i*MB_SIZE+*mv_x_min+block_x);
130 dim_curr_y_min=(Int)(br_y+j*MB_SIZE+*mv_y_min+block_y);
131 dim_prev_x_min=prev_x/*-edge*/;
132 dim_prev_y_min=prev_y/*-edge*/;
134 /* max x/y */
135 /*the MB right-pixels inside */
136 dim_curr_x_max=(Int)(br_x+i*MB_SIZE+*mv_x_max+mb_b_size+block_x);
137 /*the MB bottom-pixels inside */
138 dim_curr_y_max=(Int)(br_y+j*MB_SIZE+*mv_y_max+mb_b_size+block_y);
139 dim_prev_x_max=prev_x+vop_width /*+edge*/;
140 dim_prev_y_max=prev_y+vop_height/*+edge*/;
142 /* range x/y min */
144 if (dim_curr_x_min > dim_prev_x_max)
146 *out=1;
148 else if(dim_curr_x_min < dim_prev_x_min)
150 *mv_x_min = *mv_x_min + ( dim_prev_x_min - dim_curr_x_min ) ;
153 if(!(*out))
155 if (dim_curr_y_min > dim_prev_y_max)
157 *out=1;
159 else if(dim_curr_y_min < dim_prev_y_min)
161 *mv_y_min = *mv_y_min + ( dim_prev_y_min - dim_curr_y_min ) ;
165 /* range x/y max */
166 if(!(*out))
168 if(dim_curr_x_max < dim_prev_x_min)
170 *out=1;
172 if ((!(*out))&&(dim_curr_x_max > dim_prev_x_max))
174 *mv_x_max = *mv_x_max - ( dim_curr_x_max - dim_prev_x_max) ;
178 if(!(*out))
180 if(dim_curr_y_max < dim_prev_y_min)
182 *out=1; /* already set */
184 if ((!(*out))&&(dim_curr_y_max > dim_prev_y_max))
186 *mv_y_max = *mv_y_max - ( dim_curr_y_max - dim_prev_y_max) ;
190 if(*mv_x_min>*mv_x_max)
192 *out=1;
195 if ( (!(*out)) && (*mv_y_min>*mv_y_max))
197 *out=1;
200 return;
204 /***********************************************************CommentBegin******
206 * -- Obtain_Range -- computes the range of the search area
208 * Purpose :
209 * computes the range of the search area for the predicted MV's
210 * (it can be outside the overlapped zone between the reference
211 * and current vops)
213 * Return values :
214 * 1 on success, 0 on error
216 ***********************************************************CommentEnd********/
218 static Int
219 Obtain_Range(
220 Int f_code, /* <-- MV search range 1/2 (or 1/4 pel): (0=16,) 1=32,2=64,...,7=2048 */
221 Int sr, /* <-- Serach range (radius) */
222 Int type, /* <-- MBM_INTER16==16x16 search; MBM_INTER8==8x8 search */
223 Float pmv_x, /* <-- predicted horizontal motion vector */
224 Float pmv_y, /* <-- predicted horizontal motion vector */
225 Float *mv_x_min, /* --> min horizontal range */
226 Float *mv_x_max, /* --> max horizontal range */
227 Float *mv_y_min, /* --> min vertical range */
228 Float *mv_y_max, /* --> max vertical range */
229 Int quarter_pel /* <-- quarter pel flag (to allow f_code==0 without sprite) */
232 Int error;
234 Float aux_x_min, aux_y_min,
235 aux_x_max, aux_y_max;
237 Float range;
239 error=0;
241 if ((f_code==0) && (!quarter_pel)) /* for Low Latency Sprite */
243 *mv_x_min=0;
244 *mv_x_max=0;
245 *mv_y_min=0;
246 *mv_y_max=0;
248 else
250 range = sr;
252 *mv_x_min=-range; *mv_x_max= range - 0.5f;
254 *mv_y_min=-range; *mv_y_max= range - 0.5f;
257 if (type==MBM_INTER8)
259 aux_x_min=pmv_x - DEFAULT_8_WIN;
260 aux_y_min=pmv_y - DEFAULT_8_WIN;
261 aux_x_max=pmv_x + DEFAULT_8_WIN;
262 aux_y_max=pmv_y + DEFAULT_8_WIN;
264 if(*mv_x_min < aux_x_min)
265 *mv_x_min = aux_x_min;
266 if(*mv_y_min < aux_y_min)
267 *mv_y_min = aux_y_min;
268 if(*mv_x_max > aux_x_max)
269 *mv_x_max = aux_x_max;
270 if(*mv_y_max > aux_y_max)
271 *mv_y_max = aux_y_max;
274 if (error==1)
275 return(0);
276 else
277 return(1);
281 /***********************************************************CommentBegin******
283 * -- MBMotionEstimation -- Computes INTEGER PRECISION MV's for a MB
285 * Purpose :
286 * Computes INTEGER PRECISION MV's for a MB. Also returns
287 * prediction errors. Requires the whole MVs data images to
288 * obtain prediction for the current MV, which determines search
289 * range
291 ***********************************************************CommentEnd********/
293 Void
294 MBMotionEstimation(
295 SInt *curr, /* <-- Current vop pointer */
296 SInt *prev, /* <-- extended reference picture */
297 Int br_x, /* <-- horizontal bounding rectangle coordinate */
298 Int br_y, /* <-- vertical bounding rectangle coordinate */
299 Int br_width, /* <-- bounding rectangule width */
300 Int i, /* <-- horizontal MBcoordinate in pixels */
301 Int j, /* <-- vertical MB coordinate in pixels */
302 Int prev_x, /* <-- absolute horiz. position of previous vop */
303 Int prev_y, /* <-- absolute verti. position of previous vop */
304 Int vop_width, /* <-- horizontal vop dimension */
305 Int vop_height, /* <-- vertical vop dimension */
306 Int enable_8x8_mv, /* <-- 8x8 MV (=1) or only 16x16 MV (=0) */
307 Int edge, /* <-- edge */
308 Int f_code, /* <-- MV search range 1/2 (or 1/4) pel: (0=16,) 1=32,2=64,...,7=2048*/
309 Int sr, /* <-- search range (corresponds to f_code) UB 990215*/
310 Float hint_mv_w, /* <-- hint seed for horizontal MV */
311 Float hint_mv_h, /* <-- hint seed for vertical MV */
312 Float *mv16_w, /* --> predicted horizontal 16x16 MV(if approp.) */
313 Float *mv16_h, /* --> predicted vertical 16x16 MV (if approp.) */
314 Float *mv8_w, /* --> predicted horizontal 8x8 MV (if approp.) */
315 Float *mv8_h, /* --> predicted vertical 8x8 MV (if approp.) */
316 Int *min_error, /* --> Minimum prediction error */
317 SInt *flags
320 Int x, y;
321 Int sad, sad_min=MV_MAX_ERROR;
322 Int mv_x, mv_y;
323 Int block;
324 Float pmv_x, pmv_y;
325 SInt act_block[MB_SIZE*MB_SIZE];
327 Float mv_x_min, mv_x_max,
328 mv_y_min, mv_y_max;
329 Int int_mv_x_min=0, int_mv_x_max=0,
330 int_mv_y_min=0, int_mv_y_max=0;
332 Int pos16, pos8;
333 Int mvm_width = br_width/MB_SIZE;
335 Int x_curr = i*MB_SIZE,
336 y_curr = j*MB_SIZE;
337 Int hb,vb;
338 Int out;
340 Int rel_ori_x;
341 Int rel_ori_y;
343 Int min_error16, min_error8 = 0;
344 // SInt *curr = (SInt *)GetImageData(GetVopY(curr_vop));
345 #ifndef _FULL_SEARCH_ /* PIH (NTU) Fast ME 08/08/99 */
346 typedef struct
348 Int x;
349 Int y;
350 SInt start_nmbr;
351 } DPoint;
353 typedef struct
355 DPoint point[8];
356 } Diamond;
358 SInt d_type=1,stop_flag=0,pt_nmbr=0,check_pts,total_check_pts=8,mot_dirn=0;
359 Int d_centre_x=0,d_centre_y=0,check_pt_x,check_pt_y;
360 Diamond diamond[2]=
363 { {0,1,0}, {1,0,0}, {0,-1,0}, {-1,0,0} }
367 { {0,2,6}, {1,1,0}, {2,0,0}, {1,-1,2},
368 {0,-2,2}, {-1,-1,4}, {-2,0,4}, {-1,1,6} }
371 #endif
373 d_centre_x = (int)hint_mv_w;
374 d_centre_y = (int)hint_mv_h;
376 rel_ori_x=br_x-prev_x;
377 rel_ori_y=br_y-prev_y;
379 /* Load act_block */
381 LoadArea(curr, x_curr,y_curr,MB_SIZE,MB_SIZE,br_width, act_block);
383 /* Compute 16x16 integer MVs */
385 /* Obtain range */
387 Obtain_Range (f_code, sr, MBM_INTER16, /* UB 990215 added search range */
388 0.0, 0.0, &mv_x_min, &mv_x_max,
389 /*UB 990215 added quarter pel support */
390 &mv_y_min, &mv_y_max, 0/*GetVopQuarterPel(curr_vop)*/);
392 RangeInSearchArea (i,j,0, prev_x, prev_y, vop_width, vop_height,
393 br_x, br_y, edge,f_code, &mv_x_min, &mv_x_max,
394 /*UB 990215 added quarter pel support */
395 &mv_y_min, &mv_y_max,&out);
397 /* Compute */
399 if(!out)
401 int_mv_x_min=(int)ceil((double)mv_x_min);
402 int_mv_y_min=(int)ceil((double)mv_y_min);
403 int_mv_x_max=(int)floor((double)mv_x_max);
404 int_mv_y_max=(int)floor((double)mv_y_max);
405 flags[0]=ARE_EQUAL(int_mv_x_min,mv_x_min);
406 flags[1]=ARE_EQUAL(int_mv_x_max,mv_x_max);
407 flags[2]=ARE_EQUAL(int_mv_y_min,mv_y_min);
408 flags[3]=ARE_EQUAL(int_mv_y_max,mv_y_max);
410 sad_min=MV_MAX_ERROR;
411 mv_x = mv_y = 2000; /* A very large MV */
413 #ifdef _FULL_SEARCH_ /* PIH (NTU) 08/08/99 */
414 for (y=int_mv_y_min; y<=int_mv_y_max; y++)
415 for (x=int_mv_x_min; x<=int_mv_x_max; x++)
417 if (x==0 && y==0)
418 sad=SAD_Macroblock(prev+INDEX_BIG(x_curr+rel_ori_x,
419 y_curr+rel_ori_y), act_block,
420 (vop_width/*+2*edge*/), MV_MAX_ERROR)
421 - (128 + 1);
422 else
423 sad=SAD_Macroblock(prev+INDEX_BIG(x_curr+x+rel_ori_x,
424 y_curr+y+rel_ori_y), act_block,
425 (vop_width/*+2*edge*/), sad_min);
427 if (sad<sad_min)
429 sad_min=sad;
430 mv_x=x;
431 mv_y=y;
433 else if (sad==sad_min)
434 if((ABS(x)+ABS(y)) < (ABS(mv_x)+ABS(mv_y)))
436 sad_min=sad;
437 mv_x=x;
438 mv_y=y;
440 } /*for*/
441 #else /* PIH (NTU) Fast ME 08/08/99 */
442 sad = SAD_Macroblock(prev+INDEX_BIG(x_curr+rel_ori_x,
443 y_curr+rel_ori_y), act_block, (vop_width/*+2*edge*/), MV_MAX_ERROR)
444 - (128 + 1);
445 if (sad<sad_min)
447 sad_min=sad;
448 mv_x = mv_y = 0;
452 check_pts=total_check_pts;
456 check_pt_x = diamond[d_type].point[pt_nmbr].x + d_centre_x;
457 check_pt_y = diamond[d_type].point[pt_nmbr].y + d_centre_y;
459 /* Restrict the search to the searching window ; Note: This constraint can be removed */
460 if ( check_pt_x < int_mv_x_min || check_pt_x > int_mv_x_max || check_pt_y < int_mv_y_min || check_pt_y > int_mv_y_max)
462 sad = MV_MAX_ERROR;
464 else
466 sad=SAD_Macroblock(prev+INDEX_BIG(x_curr+check_pt_x+rel_ori_x,
467 y_curr+check_pt_y+rel_ori_y), act_block,
468 (vop_width/*+2*edge*/), sad_min);
469 #ifdef _SAD_EXHAUS_
470 fprintf(stdout,"+o+ [%2d,%2d] sad16(%3d,%3d)=%4d\n",i,j,x,y,sad);
471 #endif
473 if (sad<sad_min)
475 sad_min=sad;
476 mv_x=check_pt_x;
477 mv_y=check_pt_y;
478 mot_dirn=pt_nmbr;
480 else if (sad==sad_min)
481 if((ABS(check_pt_x)+ABS(check_pt_y)) < (ABS(mv_x)+ABS(mv_y)))
483 sad_min=sad;
484 mv_x=check_pt_x;
485 mv_y=check_pt_y;
486 mot_dirn=pt_nmbr;
489 pt_nmbr+=1;
490 if((pt_nmbr)>= 8) pt_nmbr-=8;
491 check_pts-=1;
493 while(check_pts>0);
495 if( d_type == 0)
497 stop_flag = 1;
500 else
502 if( (mv_x == d_centre_x) && (mv_y == d_centre_y) )
504 d_type=0;
505 pt_nmbr=0;
506 total_check_pts = 4;
508 else
510 if((mv_x==d_centre_x) ||(mv_y==d_centre_y))
511 total_check_pts=5;
512 else
513 total_check_pts=3;
514 pt_nmbr=diamond[d_type].point[mot_dirn].start_nmbr;
515 d_centre_x = mv_x;
516 d_centre_y = mv_y;
521 while(stop_flag!=1);
522 #endif
524 flags[0]=flags[0] && (mv_x==int_mv_x_min);
525 flags[1]=flags[1] && (mv_x==int_mv_x_max);
526 flags[2]=flags[2] && (mv_y==int_mv_y_min);
527 flags[3]=flags[3] && (mv_y==int_mv_y_max);
529 else
531 mv_x=mv_y=0;
532 sad_min=MV_MAX_ERROR;
535 /* Store result */
537 out |=((mv_x==2000)||(mv_y==2000));
538 if(out)
540 mv_x=mv_y=0;
541 sad_min=MV_MAX_ERROR;
544 pos16=2*j*2*mvm_width + 2*i;
545 mv16_w[pos16]= mv_x; mv16_h[pos16]= mv_y;
546 mv16_w[pos16+1]= mv_x; mv16_h[pos16+1]= mv_y;
547 pos16+=2*mvm_width;
548 mv16_w[pos16]= mv_x; mv16_h[pos16]= mv_y;
549 mv16_w[pos16+1]= mv_x; mv16_h[pos16+1]= mv_y;
550 min_error16 = sad_min;
552 *min_error = min_error16;
554 /* Compute 8x8 MVs */
556 if(enable_8x8_mv==1)
558 if(!out)
560 for (block=0;block<4;block++)
562 /* Obtain range */
563 if(block==0)
565 hb=vb=0;
567 else if (block==1)
569 hb=1;vb=0;
571 else if (block==2)
573 hb=0;vb=1;
575 else
577 hb=vb=1;
580 /* VM 2.*: restrict the search range based on the current 16x16 MV
581 * inside a window around it
584 pmv_x=mv16_w[pos16]; pmv_y=mv16_h[pos16];
586 /* UB 990215 added search range */
587 Obtain_Range(f_code, sr, MBM_INTER8,
588 pmv_x, pmv_y, &mv_x_min,
589 /*UB 990215 added quarter pel support */
590 &mv_x_max, &mv_y_min, &mv_y_max, 0 /*GetVopQuarterPel(curr_vop)*/);
592 RangeInSearchArea(i,j, block+1, prev_x, prev_y,
593 vop_width, vop_height, br_x, br_y, edge,f_code,
594 /*UB 990215 added quarter pel support */
595 &mv_x_min, &mv_x_max, &mv_y_min,&mv_y_max,&out);
597 if(!out)
599 int_mv_x_min=(int)ceil((double)mv_x_min);
600 int_mv_y_min=(int)ceil((double)mv_y_min);
601 int_mv_x_max=(int)floor((double)mv_x_max);
602 int_mv_y_max=(int)floor((double)mv_y_max);
603 flags[4+block*4]=ARE_EQUAL(int_mv_x_min,mv_x_min);
604 flags[4+block*4+1]=ARE_EQUAL(int_mv_x_max,mv_x_max);
605 flags[4+block*4+2]=ARE_EQUAL(int_mv_y_min,mv_y_min);
606 flags[4+block*4+3]=ARE_EQUAL(int_mv_y_max,mv_y_max);
608 sad_min=MV_MAX_ERROR;
609 mv_x = mv_y = 2000; /* A very large MV */
611 for (y=int_mv_y_min; y<=int_mv_y_max; y++)
612 for (x=int_mv_x_min; x<=int_mv_x_max; x++)
614 sad=SAD_Block(prev+
615 INDEX_BIG(x_curr + x + 8*(block==1||block==3)+rel_ori_x,
616 y_curr + y + 8*(block==2||block==3)+rel_ori_y),
617 act_block+INDEX_NOR(8*(block==1||block==3),
618 8*(block==2||block==3)),
619 (vop_width /*+2*edge*/), sad_min);
621 if (sad<sad_min)
623 sad_min=sad;
624 mv_x=x;
625 mv_y=y;
627 else if (sad==sad_min)
628 if((ABS(x)+ABS(y)) < (ABS(mv_x)+ABS(mv_y)))
630 sad_min=sad;
631 mv_x=x;
632 mv_y=y;
634 } /*for*/
636 flags[4+block*4] = flags[4+block*4] && (mv_x==int_mv_x_min);
637 flags[4+block*4+1] = flags[4+block*4+1] && (mv_x==int_mv_x_max);
638 flags[4+block*4+2] = flags[4+block*4+2] && (mv_y==int_mv_y_min);
639 flags[4+block*4+3] = flags[4+block*4+3] && (mv_y==int_mv_y_max);
641 else
643 mv_x=mv_y=0;
644 sad_min=MV_MAX_ERROR;
645 /* punish the OUTER blocks with MV_MAX_ERROR in order to
646 be INTRA CODED */
649 /* Store result */
651 if(block==0)
653 pos8=2*j*2*mvm_width + 2*i;
654 min_error8 += sad_min;
656 else if (block==1)
658 pos8=2*j*2*mvm_width + 2*i+1;
659 min_error8 += sad_min;
661 else if (block==2)
663 pos8=(2*j+1)*2*mvm_width + 2*i;
664 min_error8 += sad_min;
666 else
668 pos8=(2*j+1)*2*mvm_width + 2*i+1;
669 min_error8 += sad_min;
672 /* Store result: absolute coordinates (note that in restricted mode
673 pmv is (0,0)) */
674 mv8_w[pos8]=mv_x;
675 mv8_h[pos8]=mv_y;
676 } /*for block*/
678 if (min_error8 < *min_error)
679 *min_error = min_error8;
681 else
682 { /* all the four blocks are out */
683 pos8=2*j*2*mvm_width + 2*i; mv8_w[pos8]=mv8_h[pos8]=0.0;
684 pos8=2*j*2*mvm_width + 2*i+1; mv8_w[pos8]=mv8_h[pos8]=0.0;
685 pos8=(2*j+1)*2*mvm_width + 2*i; mv8_w[pos8]=mv8_h[pos8]=0.0;
686 pos8=(2*j+1)*2*mvm_width + 2*i+1;mv8_w[pos8]=mv8_h[pos8]=0.0;
687 min_error8 = MV_MAX_ERROR;
689 } /* enable_8x8_mv*/
694 /***********************************************************CommentBegin******
696 * -- FindSubPel -- Computes MV with half-pixel accurary
698 * Purpose :
699 * Computes MV with sub-pixel accurary for a 16x16 or 8x8 block
701 * Description :
702 * 1) The preference for the 16x16 null motion vector must be applied
703 * again (now, the SAD is recomputed for the recontructed interpolated
704 * reference)
706 ***********************************************************CommentEnd********/
708 Void
709 FindSubPel(
710 Int x, /* <-- horizontal block coordinate in pixels */
711 Int y, /* <-- vertical blocl coordinate in pixels */
712 SInt *prev, /* <-- interpolated reference vop */
713 SInt *curr, /* <-- current block */
714 Int bs_x, /* <-- hor. block size (8/16) */
715 Int bs_y, /* <-- vert. block size (8/16) */
716 Int comp, /* <-- block position in MB (0,1,2,3) */
717 Int rel_x, /* <-- relative horiz. position between curr & prev vops*/
718 Int rel_y, /* <-- relative verti. position between curr & prev vops*/
719 Int pels, /* <-- vop width */
720 Int lines, /* <-- vop height */
721 Int edge, /* <-- edge */
722 SInt *flags, /* <-- flags */
723 SInt *curr_comp_mb, /* <-> motion compensated current mb */
724 Float *mvx, /* <-> horizontal motion vector */
725 Float *mvy, /* <-> vertical motion vector */
726 Int *min_error /* --> prediction error */
729 static PixPoint search[9] =
731 {0, 0}, {-1, -1}, {0, -1}, {1, -1},
732 {-1, 0}, {1, 0}, {-1, 1}, {0, 1}, {1, 1}
734 /* searching map
735 1 2 3
736 4 0 5
737 6 7 8
740 Int i, m, n;
741 Int new_x, new_y,
742 lx, size_x; /* MW QPEL 07-JUL-1998 */
743 Int min_pos;
744 Int AE, AE_min;
745 Int flag_pos;
746 SInt *pRef, *pComp;
748 int flag_search[9] = {1, 1, 1, 1, 1, 1, 1, 1, 1};
750 Int SubDimension = 2;
752 lx = 2*(pels /*+ 2*edge*/);
754 new_x = (Int)((x + *mvx + rel_x)*(SubDimension));
755 new_y = (Int)((y + *mvy + rel_y)*(SubDimension));
756 new_x += ((comp&1)<<3)*SubDimension;
757 new_y += ((comp&2)<<2)*SubDimension;
759 size_x=16;
761 /** in 1-pixel search we check if we are inside the range; so don't check
762 it again
765 /* avoids trying outside the reference image */
766 /* we also check with flags if we are inside */
767 /* search range (1==don't make 1/x search by */
768 /* this side */
770 if (bs_x==8)
771 flag_pos=4+comp*4;
772 else /* ==16*/
773 flag_pos=0;
775 if (((new_x/SubDimension) <= 0/*-edge*/) || *(flags+flag_pos)) {
776 flag_search[1] = flag_search[4] = flag_search[6] = 0;
777 } else if (((new_x/SubDimension) >= (pels - bs_x /*+ edge*/)) || *(flags+flag_pos+1)) {
778 flag_search[3] = flag_search[5] = flag_search[8] = 0;
781 if (((new_y/SubDimension) <= 0/*-edge*/) || *(flags+flag_pos+2)) {
782 flag_search[1] = flag_search[2] = flag_search[3] = 0;
783 } else if (((new_y/SubDimension) >= (lines- bs_y /*+ edge*/)) || *(flags+flag_pos+3)) {
784 flag_search[6] = flag_search[7] = flag_search[8] = 0;
787 AE_min = MV_MAX_ERROR;
788 min_pos = 0;
789 for (i = 0; i < 9; i++)
791 if (flag_search[i])
793 AE = 0;
794 /* estimate on the already interpolated half-pel image */
795 pRef = prev + new_x + search[i].x + (new_y + search[i].y) * lx;
796 pComp = curr;
798 n = bs_y;
799 while (n--) {
800 m = bs_x;
804 while (m--) {
805 AE += abs((Int)*pRef - (Int)*pComp);
806 pRef += 2;
807 pComp ++;
814 pRef += 2 * lx - 2 * bs_x;
815 pComp += size_x - bs_x;
818 if (i==0 && bs_y==16 && *mvx==0 && *mvy==0)
819 AE -= (128 + 1);
821 if (AE < AE_min)
823 AE_min = AE;
824 min_pos = i;
827 /* else don't look outside the reference */
830 /* Store optimal values */
831 *min_error = AE_min;
832 *mvx += ((Float)search[min_pos].x)/(Float)(SubDimension);
833 *mvy += ((Float)search[min_pos].y)/(Float)(SubDimension);
835 // generate comp mb data for the minimum point
836 pRef = prev + new_x + search[min_pos].x + (new_y + search[min_pos].y) * lx;
837 pComp = curr_comp_mb;
839 n = bs_y;
840 while (n--) {
841 m = bs_x;
842 while (m--) {
843 *(pComp ++) = *pRef;
844 pRef += 2;
846 pRef += 2 * lx - 2 * bs_x;
847 pComp += 16 - bs_x;
850 return;