www.pudn.com > encore50src.zip > mot_est_mb.c


 
/************************************************************************** 
 *                                                                        * 
 * This code is developed by Adam Li.  This software is an                * 
 * implementation of a part of one or more MPEG-4 Video tools as          * 
 * specified in ISO/IEC 14496-2 standard.  Those intending to use this    * 
 * software module in hardware or software products are advised that its  * 
 * use may infringe existing patents or copyrights, and any such use      * 
 * would be at such party's own risk.  The original developer of this     * 
 * software module and his/her company, and subsequent editors and their  * 
 * companies (including Project Mayo), will have no liability for use of  * 
 * this software or modifications or derivatives thereof.                 * 
 *                                                                        * 
 * Project Mayo gives users of the Codec a license to this software       * 
 * module or modifications thereof for use in hardware or software        * 
 * products claiming conformance to the MPEG-4 Video Standard as          * 
 * described in the Open DivX license.                                    * 
 *                                                                        * 
 * The complete Open DivX license can be found at                         * 
 * http://www.projectmayo.com/opendivx/license.php .                      * 
 *                                                                        * 
 **************************************************************************/ 
 
/************************************************************************** 
 * 
 *  mot_est_mb.c 
 * 
 *  Copyright (C) 2001  Project Mayo 
 * 
 *  Adam Li 
 * 
 *  DivX Advance Research Center  
 * 
 **************************************************************************/ 
 
/* This file contains some functions to do motion estimation and          */ 
/* for one MacroBlock in one pass.                                        */ 
/* Some codes of this project come from MoMuSys MPEG-4 implementation.    */ 
/* Please see seperate acknowledgement file for a list of contributors.   */ 
 
#include "mot_util.h" 
 
/* Obtaining if two floating point values are equal*/ 
#define ABSDOUBLE(x)   (((x) > 0.0001) ? (x) : (((x) < -0.0001) ? -(x): 0.0 )) 
#define ARE_EQUAL(x,y) ( (ABSDOUBLE((Float)(x)-(y))>0.1)?(0):(1) ) 
 
/* auxiliar define for indexing in MBMotionEstimation */ 
#define INDEX_BIG(x,y) ((x)+(y)*(vop_width)) 
#define INDEX_NOR(x,y) ((x)+(y)*(MB_SIZE)) 
 
/* ------------------------------------------------------------------------- */ 
 
/***********************************************************CommentBegin****** 
 * 
 * -- RangeInSearchArea -- computes the range of the search area 
 * 
 * Purpose : 
 *      computes the range of the search area for the predicted MV's 
 *      INSIDE the overlapped zone between reference and current vops 
 * 
 ***********************************************************CommentEnd********/ 
 
static Void 
RangeInSearchArea( 
Int     i,										  /* <-- horizontal MBcoordinate in pixels               */ 
Int     j,										  /* <-- vertical MB coordinate in pixels                */ 
Int     block,									  /* <-- block position (0 16x16; 1-2-3-4 8x8)           */ 
Int     prev_x,									  /* <-- absolute horizontal position of the previous vop*/ 
Int     prev_y,									  /* <-- absolute vertical position of the previous vop  */ 
Int     vop_width,								  /* <-- horizontal vop dimension                        */ 
Int     vop_height,								  /* <-- vertical vop dimension                          */ 
Int     br_x,									  /* <-- absolute horizontal position of the current vop */ 
Int     br_y,									  /* <-- absolute vertical   position of the current vop */ 
Int     edge,									  /* <-- edge arround the reference vop                  */ 
Int     f_code,									  /* <-  MV search range 1/2 (or 1/4) pel: (0=16,) 1=32,2=64,...,7=2048 */ 
Float   *mv_x_min,								  /* <-- min horizontal range                            */ 
Float   *mv_x_max,								  /* <-- max horizontal range                            */ 
Float   *mv_y_min,								  /* <-- min vertical range                              */ 
Float   *mv_y_max,								  /* <-- max vertical range                              */ 
Int     *out									  /* --> the search area does not exist (the reference   */												  /*     and current BB does not overlap)                */ 
) 
{ 
	Int   dim_curr_x_max, 
		dim_curr_y_max, 
		dim_curr_x_min, 
		dim_curr_y_min; 
	Int   dim_prev_x_max, 
		dim_prev_y_max, 
		dim_prev_x_min, 
		dim_prev_y_min; 
	Int   mb_b_size, 
		block_x, 
		block_y; 
 
	*out=0; 
 
	switch (block) 
	{ 
		case 0:									  /* 8x8 or 16x16 block search */ 
			block_x=0;							  /*****************************/ 
			block_y=0;							  /** 1 2 ********  0  *********/ 
			mb_b_size=MB_SIZE;					  /** 3 4 ********     *********/ 
			break;								  /*****************************/ 
		case 1: 
			block_x=0; 
			block_y=0; 
			mb_b_size=B_SIZE; 
			break; 
		case 2: 
			block_x=B_SIZE; 
			block_y=0; 
			mb_b_size=B_SIZE; 
			break; 
		case 3: 
			block_x=0; 
			block_y=B_SIZE; 
			mb_b_size=B_SIZE; 
			break; 
		case 4: 
			block_x=B_SIZE; 
			block_y=B_SIZE; 
			mb_b_size=B_SIZE; 
			break; 
		default: 
			return; 
	} 
 
	/* min x/y */ 
	dim_curr_x_min=(Int)(br_x+i*MB_SIZE+*mv_x_min+block_x); 
	dim_curr_y_min=(Int)(br_y+j*MB_SIZE+*mv_y_min+block_y); 
	dim_prev_x_min=prev_x/*-edge*/; 
	dim_prev_y_min=prev_y/*-edge*/; 
 
	/* max x/y */ 
	/*the MB right-pixels inside */ 
	dim_curr_x_max=(Int)(br_x+i*MB_SIZE+*mv_x_max+mb_b_size+block_x); 
	/*the MB bottom-pixels inside */ 
	dim_curr_y_max=(Int)(br_y+j*MB_SIZE+*mv_y_max+mb_b_size+block_y); 
	dim_prev_x_max=prev_x+vop_width /*+edge*/; 
	dim_prev_y_max=prev_y+vop_height/*+edge*/; 
 
	/* range x/y min */ 
 
	if (dim_curr_x_min > dim_prev_x_max) 
	{ 
		*out=1; 
	} 
	else if(dim_curr_x_min < dim_prev_x_min) 
	{ 
		*mv_x_min = *mv_x_min + ( dim_prev_x_min - dim_curr_x_min ) ; 
	} 
 
	if(!(*out)) 
	{ 
		if (dim_curr_y_min > dim_prev_y_max) 
		{ 
			*out=1; 
		} 
		else if(dim_curr_y_min < dim_prev_y_min) 
		{ 
			*mv_y_min = *mv_y_min + ( dim_prev_y_min - dim_curr_y_min ) ; 
		} 
	} 
 
	/* range x/y max */ 
	if(!(*out)) 
	{ 
		if(dim_curr_x_max < dim_prev_x_min) 
		{ 
			*out=1; 
		} 
		if ((!(*out))&&(dim_curr_x_max > dim_prev_x_max)) 
		{ 
			*mv_x_max = *mv_x_max - ( dim_curr_x_max - dim_prev_x_max) ; 
		} 
	} 
 
	if(!(*out)) 
	{ 
		if(dim_curr_y_max < dim_prev_y_min) 
		{ 
			*out=1;								  /* already set */ 
		} 
		if ((!(*out))&&(dim_curr_y_max > dim_prev_y_max)) 
		{ 
			*mv_y_max = *mv_y_max - ( dim_curr_y_max - dim_prev_y_max) ; 
		} 
	} 
 
	if(*mv_x_min>*mv_x_max) 
	{ 
		*out=1; 
	} 
 
	if ( (!(*out)) && (*mv_y_min>*mv_y_max)) 
	{ 
		*out=1; 
	} 
 
	return; 
} 
 
 
/***********************************************************CommentBegin****** 
 * 
 * -- Obtain_Range -- computes the range of the search area 
 * 
 * Purpose : 
 *      computes the range of the search area for the predicted MV's 
 *      (it can be outside the overlapped zone between the reference 
 *      and current vops) 
 * 
 * Return values : 
 *      1 on success, 0 on error 
 * 
 ***********************************************************CommentEnd********/ 
 
static Int 
Obtain_Range( 
Int     f_code,									  /* <-- MV search range 1/2 (or 1/4 pel): (0=16,) 1=32,2=64,...,7=2048   */ 
Int     sr,										  /* <-- Serach range (radius)                           */ 
Int     type,									  /* <-- MBM_INTER16==16x16 search;	MBM_INTER8==8x8 search */ 
Float   pmv_x,									  /* <-- predicted horizontal motion vector              */ 
Float   pmv_y,									  /* <-- predicted horizontal motion vector              */ 
Float   *mv_x_min,								  /* --> min horizontal range                            */ 
Float   *mv_x_max,								  /* --> max horizontal range                            */ 
Float   *mv_y_min,								  /* --> min vertical range                              */ 
Float   *mv_y_max,								  /* --> max vertical range                              */ 
Int     quarter_pel								  /* <-- quarter pel flag (to allow f_code==0 without sprite) */ 
) 
{ 
	Int    error; 
 
	Float  aux_x_min, aux_y_min, 
		aux_x_max, aux_y_max; 
 
	Float  range; 
 
	error=0; 
 
	if ((f_code==0) && (!quarter_pel))		  /* for Low Latency Sprite */ 
	{ 
		*mv_x_min=0; 
		*mv_x_max=0; 
		*mv_y_min=0; 
		*mv_y_max=0; 
	} 
	else 
	{ 
		range = sr; 
 
		*mv_x_min=-range; *mv_x_max= range - 0.5f; 
 
		*mv_y_min=-range; *mv_y_max= range - 0.5f; 
	} 
 
	if (type==MBM_INTER8) 
	{ 
		aux_x_min=pmv_x - DEFAULT_8_WIN; 
		aux_y_min=pmv_y - DEFAULT_8_WIN; 
		aux_x_max=pmv_x + DEFAULT_8_WIN; 
		aux_y_max=pmv_y + DEFAULT_8_WIN; 
 
		if(*mv_x_min < aux_x_min) 
			*mv_x_min = aux_x_min; 
		if(*mv_y_min < aux_y_min) 
			*mv_y_min = aux_y_min; 
		if(*mv_x_max > aux_x_max) 
			*mv_x_max = aux_x_max; 
		if(*mv_y_max > aux_y_max) 
			*mv_y_max = aux_y_max; 
	} 
 
	if (error==1) 
		return(0); 
	else 
		return(1); 
} 
 
 
/***********************************************************CommentBegin****** 
 * 
 * -- MBMotionEstimation -- Computes INTEGER PRECISION MV's for a MB 
 * 
 * Purpose : 
 *      Computes INTEGER PRECISION MV's for a MB. Also returns 
 *      prediction errors. Requires the whole MVs data images to 
 *      obtain prediction for the current MV, which determines search 
 *      range 
 * 
 ***********************************************************CommentEnd********/ 
 
Void 
MBMotionEstimation( 
SInt    *curr,								  /* <-- Current vop pointer                          */ 
SInt    *prev,									  /* <-- extended reference picture                   */ 
Int     br_x,									  /* <-- horizontal bounding rectangle coordinate     */ 
Int     br_y,									  /* <-- vertical bounding rectangle coordinate       */ 
Int     br_width,								  /* <-- bounding rectangule width                    */ 
Int     i,										  /* <-- horizontal MBcoordinate in pixels            */ 
Int     j,										  /* <-- vertical MB coordinate in pixels             */ 
Int     prev_x,									  /* <-- absolute horiz. position of previous vop     */ 
Int     prev_y,									  /* <-- absolute verti. position of previous vop     */ 
Int     vop_width,								  /* <-- horizontal vop dimension                     */ 
Int     vop_height,								  /* <-- vertical vop dimension                       */ 
Int     enable_8x8_mv,							  /* <-- 8x8 MV (=1) or only 16x16 MV (=0)            */ 
Int     edge,									  /* <-- edge                                         */ 
Int     f_code,									  /* <-- MV search range 1/2 (or 1/4) pel: (0=16,) 1=32,2=64,...,7=2048*/ 
Int     sr,										  /* <-- search range (corresponds to f_code) UB 990215*/ 
Float	hint_mv_w,                                /* <-- hint seed for horizontal MV                  */ 
Float	hint_mv_h,                                /* <-- hint seed for vertical MV                    */ 
Float   *mv16_w,								  /* --> predicted horizontal 16x16 MV(if approp.)    */ 
Float   *mv16_h,								  /* --> predicted vertical 16x16 MV  (if approp.)    */ 
Float   *mv8_w,									  /* --> predicted horizontal 8x8 MV  (if approp.)    */ 
Float   *mv8_h,									  /* --> predicted vertical 8x8 MV    (if approp.)    */ 
Int     *min_error,								  /* --> Minimum prediction error                     */ 
SInt    *flags 
) 
{ 
	Int     x, y; 
	Int     sad, sad_min=MV_MAX_ERROR; 
	Int     mv_x, mv_y; 
	Int     block; 
	Float   pmv_x, pmv_y; 
	SInt	act_block[MB_SIZE*MB_SIZE]; 
 
	Float   mv_x_min, mv_x_max, 
		mv_y_min, mv_y_max; 
	Int     int_mv_x_min=0, int_mv_x_max=0, 
		int_mv_y_min=0, int_mv_y_max=0; 
 
	Int     pos16, pos8; 
	Int     mvm_width   = br_width/MB_SIZE; 
 
	Int     x_curr      = i*MB_SIZE, 
		y_curr      = j*MB_SIZE; 
	Int     hb,vb; 
	Int     out; 
 
	Int     rel_ori_x; 
	Int     rel_ori_y; 
 
	Int     min_error16, min_error8 = 0; 
//	SInt    *curr = (SInt *)GetImageData(GetVopY(curr_vop)); 
	#ifndef _FULL_SEARCH_						  /* PIH (NTU) Fast ME 08/08/99 */ 
	typedef struct 
	{ 
		Int x; 
		Int y; 
		SInt start_nmbr; 
	} DPoint; 
 
	typedef struct 
	{ 
		DPoint point[8]; 
	} Diamond; 
 
	SInt d_type=1,stop_flag=0,pt_nmbr=0,check_pts,total_check_pts=8,mot_dirn=0; 
	Int d_centre_x=0,d_centre_y=0,check_pt_x,check_pt_y; 
	Diamond diamond[2]= 
	{ 
		{ 
			{	{0,1,0},	{1,0,0},	{0,-1,0},	{-1,0,0}	} 
		} 
		, 
		{ 
			{	{0,2,6},	{1,1,0},	{2,0,0},	{1,-1,2}, 
				{0,-2,2},	{-1,-1,4},	{-2,0,4},	{-1,1,6}	} 
		} 
	}; 
	#endif 
 
	d_centre_x = (int)hint_mv_w; 
	d_centre_y = (int)hint_mv_h; 
 
	rel_ori_x=br_x-prev_x; 
	rel_ori_y=br_y-prev_y; 
 
	/* Load act_block */ 
	 
	LoadArea(curr, x_curr,y_curr,MB_SIZE,MB_SIZE,br_width, act_block); 
 
	/* Compute 16x16 integer MVs */ 
 
	/* Obtain range */ 
 
	Obtain_Range (f_code, sr, MBM_INTER16,		  /* UB 990215 added search range */ 
		0.0, 0.0, &mv_x_min, &mv_x_max, 
												  /*UB 990215 added quarter pel support */ 
		&mv_y_min, &mv_y_max, 0/*GetVopQuarterPel(curr_vop)*/); 
 
	RangeInSearchArea (i,j,0, prev_x, prev_y, vop_width, vop_height, 
		br_x, br_y, edge,f_code, &mv_x_min, &mv_x_max, 
												  /*UB 990215 added quarter pel support */ 
		&mv_y_min, &mv_y_max,&out); 
 
	/* Compute */ 
 
	if(!out) 
	{ 
		int_mv_x_min=(int)ceil((double)mv_x_min); 
		int_mv_y_min=(int)ceil((double)mv_y_min); 
		int_mv_x_max=(int)floor((double)mv_x_max); 
		int_mv_y_max=(int)floor((double)mv_y_max); 
		flags[0]=ARE_EQUAL(int_mv_x_min,mv_x_min); 
		flags[1]=ARE_EQUAL(int_mv_x_max,mv_x_max); 
		flags[2]=ARE_EQUAL(int_mv_y_min,mv_y_min); 
		flags[3]=ARE_EQUAL(int_mv_y_max,mv_y_max); 
 
		sad_min=MV_MAX_ERROR; 
		mv_x = mv_y = 2000;						  /* A very large MV */ 
 
		#ifdef _FULL_SEARCH_				  /* PIH (NTU)  08/08/99 */ 
		for (y=int_mv_y_min; y<=int_mv_y_max; y++) 
			for (x=int_mv_x_min; x<=int_mv_x_max; x++) 
		{ 
			if (x==0 && y==0) 
					sad=SAD_Macroblock(prev+INDEX_BIG(x_curr+rel_ori_x, 
					y_curr+rel_ori_y), act_block,  
					(vop_width/*+2*edge*/), MV_MAX_ERROR) 
					- (128 + 1); 
			else 
				sad=SAD_Macroblock(prev+INDEX_BIG(x_curr+x+rel_ori_x, 
					y_curr+y+rel_ori_y), act_block,  
					(vop_width/*+2*edge*/), sad_min); 
 
			if (sad int_mv_x_max || check_pt_y < int_mv_y_min || check_pt_y > int_mv_y_max) 
				{ 
					sad = MV_MAX_ERROR; 
				} 
				else 
				{ 
					sad=SAD_Macroblock(prev+INDEX_BIG(x_curr+check_pt_x+rel_ori_x, 
						y_curr+check_pt_y+rel_ori_y), act_block,  
						(vop_width/*+2*edge*/), sad_min); 
					#ifdef _SAD_EXHAUS_ 
					fprintf(stdout,"+o+ [%2d,%2d] sad16(%3d,%3d)=%4d\n",i,j,x,y,sad); 
					#endif 
				} 
				if (sad= 8) pt_nmbr-=8; 
				check_pts-=1; 
			} 
			while(check_pts>0); 
 
			if( d_type == 0) 
			{ 
				stop_flag = 1; 
 
			} 
			else 
			{ 
				if( (mv_x == d_centre_x) && (mv_y == d_centre_y) ) 
				{ 
					d_type=0; 
					pt_nmbr=0; 
					total_check_pts = 4; 
				} 
				else 
				{ 
					if((mv_x==d_centre_x) ||(mv_y==d_centre_y)) 
						total_check_pts=5; 
					else 
						total_check_pts=3; 
					pt_nmbr=diamond[d_type].point[mot_dirn].start_nmbr; 
					d_centre_x = mv_x; 
					d_centre_y = mv_y; 
 
				} 
			} 
		} 
		while(stop_flag!=1); 
		#endif 
 
		flags[0]=flags[0] && (mv_x==int_mv_x_min); 
		flags[1]=flags[1] && (mv_x==int_mv_x_max); 
		flags[2]=flags[2] && (mv_y==int_mv_y_min); 
		flags[3]=flags[3] && (mv_y==int_mv_y_max); 
	} 
	else 
	{ 
		mv_x=mv_y=0; 
		sad_min=MV_MAX_ERROR; 
	} 
 
	/* Store result */ 
 
	out |=((mv_x==2000)||(mv_y==2000)); 
	if(out) 
	{ 
		mv_x=mv_y=0; 
		sad_min=MV_MAX_ERROR; 
	} 
 
	pos16=2*j*2*mvm_width + 2*i; 
	mv16_w[pos16]=   mv_x; mv16_h[pos16]=   mv_y; 
	mv16_w[pos16+1]= mv_x; mv16_h[pos16+1]= mv_y; 
	pos16+=2*mvm_width; 
	mv16_w[pos16]=   mv_x; mv16_h[pos16]=   mv_y; 
	mv16_w[pos16+1]= mv_x; mv16_h[pos16+1]= mv_y; 
	min_error16 = sad_min; 
 
	*min_error = min_error16; 
 
	/* Compute 8x8 MVs */ 
 
	if(enable_8x8_mv==1) 
	{ 
		if(!out) 
		{ 
			for (block=0;block<4;block++) 
			{ 
				/* Obtain range */ 
				if(block==0) 
				{ 
					hb=vb=0; 
				} 
				else if (block==1) 
				{ 
					hb=1;vb=0; 
				} 
				else if (block==2) 
				{ 
					hb=0;vb=1; 
				} 
				else 
				{ 
					hb=vb=1; 
				} 
 
				/* VM 2.*: restrict the search range based on the current 16x16 MV 
				 *         inside a window around it 
				 */ 
 
				pmv_x=mv16_w[pos16]; pmv_y=mv16_h[pos16]; 
 
											  /* UB 990215 added search range */ 
				Obtain_Range(f_code, sr, MBM_INTER8, 
					pmv_x, pmv_y, &mv_x_min, 
											  /*UB 990215 added quarter pel support */ 
					&mv_x_max, &mv_y_min, &mv_y_max, 0 /*GetVopQuarterPel(curr_vop)*/); 
 
				RangeInSearchArea(i,j, block+1, prev_x, prev_y, 
					vop_width, vop_height, br_x, br_y, edge,f_code, 
											  /*UB 990215 added quarter pel support */ 
					&mv_x_min, &mv_x_max, &mv_y_min,&mv_y_max,&out); 
 
				if(!out) 
				{ 
					int_mv_x_min=(int)ceil((double)mv_x_min); 
					int_mv_y_min=(int)ceil((double)mv_y_min); 
					int_mv_x_max=(int)floor((double)mv_x_max); 
					int_mv_y_max=(int)floor((double)mv_y_max); 
					flags[4+block*4]=ARE_EQUAL(int_mv_x_min,mv_x_min); 
					flags[4+block*4+1]=ARE_EQUAL(int_mv_x_max,mv_x_max); 
					flags[4+block*4+2]=ARE_EQUAL(int_mv_y_min,mv_y_min); 
					flags[4+block*4+3]=ARE_EQUAL(int_mv_y_max,mv_y_max); 
 
					sad_min=MV_MAX_ERROR; 
					mv_x = mv_y = 2000;		  /* A very large MV */ 
 
					for (y=int_mv_y_min; y<=int_mv_y_max; y++) 
						for (x=int_mv_x_min; x<=int_mv_x_max; x++) 
					{ 
						sad=SAD_Block(prev+ 
							INDEX_BIG(x_curr + x + 8*(block==1||block==3)+rel_ori_x, 
							y_curr + y + 8*(block==2||block==3)+rel_ori_y), 
							act_block+INDEX_NOR(8*(block==1||block==3), 
							8*(block==2||block==3)), 
							(vop_width /*+2*edge*/), sad_min); 
 
						if (sad motion compensated current mb                    */ 
Float  *mvx,									  /* <-> horizontal motion vector                         */ 
Float  *mvy,									  /* <-> vertical motion vector                           */ 
Int    *min_error								  /* --> prediction error                                 */ 
) 
{ 
	static PixPoint	search[9] =  
	{	 
		{0, 0}, {-1, -1}, {0, -1}, {1, -1}, 
		{-1, 0}, {1, 0}, {-1, 1}, {0, 1}, {1, 1} 
	}; 
	/* searching map 
		1 2 3 
		4 0 5 
		6 7 8 
	*/ 
 
	Int			i, m, n; 
	Int			new_x, new_y, 
				lx, size_x;								  /* MW QPEL 07-JUL-1998 */ 
	Int			min_pos; 
	Int			AE, AE_min; 
	Int			flag_pos; 
	SInt		*pRef, *pComp; 
 
	int flag_search[9] = {1, 1, 1, 1, 1, 1, 1, 1, 1}; 
 
	Int SubDimension = 2; 
 
	lx = 2*(pels /*+ 2*edge*/); 
 
	new_x = (Int)((x + *mvx + rel_x)*(SubDimension)); 
	new_y = (Int)((y + *mvy + rel_y)*(SubDimension)); 
	new_x += ((comp&1)<<3)*SubDimension; 
	new_y += ((comp&2)<<2)*SubDimension; 
 
	size_x=16; 
 
	/** in 1-pixel search we check if we are inside the range; so don't check 
		it again 
	**/ 
 
	/* avoids trying outside the reference image */ 
	/* we also check with flags if we are inside */ 
	/* search range (1==don't make 1/x search by */ 
	/* this side                                 */ 
 
	if (bs_x==8)								   
		flag_pos=4+comp*4; 
	else										  /* ==16*/ 
		flag_pos=0; 
 
	if (((new_x/SubDimension) <= 0/*-edge*/) || *(flags+flag_pos)) { 
		flag_search[1] = flag_search[4] = flag_search[6] = 0; 
	} else if  (((new_x/SubDimension) >= (pels - bs_x /*+ edge*/)) || *(flags+flag_pos+1)) { 
		flag_search[3] = flag_search[5] = flag_search[8] = 0; 
	}; 
 
	if (((new_y/SubDimension) <= 0/*-edge*/) || *(flags+flag_pos+2)) { 
		flag_search[1] = flag_search[2] = flag_search[3] = 0; 
	} else if  (((new_y/SubDimension) >= (lines- bs_y /*+ edge*/)) || *(flags+flag_pos+3)) { 
		flag_search[6] = flag_search[7] = flag_search[8] = 0; 
	}; 
 
	AE_min = MV_MAX_ERROR; 
	min_pos = 0; 
	for (i = 0; i < 9; i++) 
	{ 
		if (flag_search[i]) 
		{ 
			AE = 0; 
			/* estimate on the already interpolated half-pel image */ 
			pRef = prev + new_x + search[i].x + (new_y + search[i].y) * lx; 
			pComp = curr; 
 
			n = bs_y; 
			while (n--) { 
				m = bs_x; 
				while (m--) { 
					AE += abs((Int)*pRef - (Int)*pComp); 
					pRef += 2; 
					pComp ++; 
				} 
				pRef += 2 * lx - 2 * bs_x; 
				pComp += size_x - bs_x; 
			} 
 
			if (i==0 && bs_y==16 && *mvx==0 && *mvy==0) 
				AE -= (128 + 1); 
 
			if (AE < AE_min) 
			{ 
				AE_min = AE; 
				min_pos = i; 
			} 
		} 
		/* else don't look outside the reference */ 
	} 
 
	/* Store optimal values */ 
	*min_error = AE_min; 
	*mvx += ((Float)search[min_pos].x)/(Float)(SubDimension); 
	*mvy += ((Float)search[min_pos].y)/(Float)(SubDimension); 
 
	// generate comp mb data for the minimum point 
	pRef = prev + new_x + search[min_pos].x + (new_y + search[min_pos].y) * lx; 
	pComp = curr_comp_mb; 
 
	n = bs_y; 
	while (n--) { 
		m = bs_x; 
		while (m--) { 
			*(pComp ++) = *pRef; 
			pRef += 2; 
		} 
		pRef += 2 * lx - 2 * bs_x; 
		pComp += 16 - bs_x; 
	} 
 
	return; 
}