www.pudn.com > henclib263.rar > mot_est.cxx


/* 
* mot_est.cxx 
* 
* implementation for functions which is used for motion estimation. 
* 
* Copyright (c) 2002-2004 Li Chun-lin(li_chunlin@263.net) 
* 
* This program is free software; you can redistribute it and/or 
* modify it under the terms of the GNU General Public License 
* as published by the Free Software Foundation; either version 2 
* of the License, or (at your option) any later version. 
*  
* This program is distributed in the hope that it will be useful, 
* but WITHOUT ANY WARRANTY; without even the implied warranty of 
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
* GNU General Public License for more details. 
 
* You should have received a copy of the GNU General Public License 
* along with this program; if not, write to the Free Software 
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA. 
*/ 
#include  
#include  
#include  
#include "../include/mot_est.h" 
 
#ifdef  __cplusplus 
extern "C" { 
#endif 
 
 
#define MAX_SAD       99999    //!< MAX_SAD   
#define PREF_NULL_VEC 100      //!< according to tmn 
#define PREF_16_VEC   200      //!< according to tmn 
 
//#define PRINTMV 
 
extern int SpiralX[6561]; 
extern int SpiralY[6561]; 
 
//!MVFAST STRUCTURE 
typedef struct  { 
	int x; 
	int y; 
	int iStartNmbr;	 
	   } DPOINT; 
//!MVFAST STRUCTURE        
typedef struct   { 
	   int   no_check_pts; 
	   DPOINT dpoint[8]; 
       } DIAMOND; 
//!MVFAST DATA USED 
static DIAMOND diamond[3]={ 
	{4,{{0,1,3},{1,0,0},{0,-1,1},{-1,0,2}}}, 
	{8,{{0,2,6},{1,1,0},{2,0,0},{1,-1,2},{0,-2,2},{-1,-1,4},{-2,0,4},{-1,1,6}}}, 
	{3,{{0,0,0},{0,0,0,},{0,0,0}}} 
}; 
//!MVFAST STRUCTURE 
enum {SDiamond, LDiamond, MotAdaptPat} dType;   
 
/*! 
******************************************************************************* 
* 
*   Name:          interpolate_lum 
*   Description:   make interpolated lum image for 1/2 pel mv search 
*   Input:           
*   Output:         
*   Side effect:   fill the buffer for interpolated image(encoder->prev_ipol)  
*   Optimization:  NO 
*   Last modified: 2002/11/21 
* 
*******************************************************************************/ 
void interpolate_lum(H263VencStatus *encoder) 
{ 
	int width  = encoder->mv_outside_frame ? encoder->pels+32 : encoder->pels; 
	int height = encoder->mv_outside_frame ? encoder->lines+32: encoder->lines; 
	unsigned char *oo = encoder->mv_outside_frame ? (encoder->frame_buf[encoder->ref_index]).pLum-width*16-16 : (encoder->frame_buf[encoder->ref_index]).pLum; 
	unsigned char *ii = encoder->mv_outside_frame ? encoder->prev_ipol-width*64-32 : encoder->prev_ipol; 
	int i, j; 
	 
 
	if (encoder->PTYPE == INTER) 
	{	 
		/* for forward mv search */ 
		oo = encoder->mv_outside_frame ? (encoder->frame_buf[encoder->ref_index]).pLum-width*16-16 : (encoder->frame_buf[encoder->ref_index]).pLum; 
		ii = encoder->mv_outside_frame ? encoder->prev_ipol-width*64-32 : encoder->prev_ipol; 
		 
	} 
	else if (encoder->PTYPE == B_IMG) 
	{ 
		/* for backward mv search */ 
		// it is always permitted that MVs be across the picture boundary 
		oo = encoder->frame_buf[encoder->zero_index].pLum - width*16 - 16; 
		ii = encoder->next_ipol - width*64 - 32; 
	} 
	else 
	{ 
		printf("error in interplating picture"); 
		exit(-1); 
	} 
	/* main image */ 
	for (j = 0; j < height-1; j++)  
	{ 
		for (i = 0; i  < width-1; i++)  
		{ 
			*(ii + (i<<1)) = *(oo + i); 
			*(ii + (i<<1)+1) = (*(oo + i) + *(oo + i + 1) + 1)>>1; 
			*(ii + (i<<1)+(width<<1)) = (*(oo + i) + *(oo + i + width) + 1)>>1; 
			*(ii + (i<<1)+1+(width<<1)) = (*(oo+i) + *(oo+i+1) +  
				*(oo+i+width) + *(oo+i+1+width) + 2)>>2; 
		} 
		/* last pels on each line */ 
		*(ii+ (width<<1) - 2) = *(oo + width - 1); 
		*(ii+ (width<<1) - 1) = *(oo + width - 1); 
		*(ii+ (width<<1)+ (width<<1)-2) = (*(oo+width-1)+*(oo+width+width-1)+1)>>1; 
		*(ii+ (width<<1)+ (width<<1)-1) = (*(oo+width-1)+*(oo+width+width-1)+1)>>1; 
		ii += (width<<2); 
		oo += width; 
	} 
	 
	/* last lines */ 
	for (i = 0; i < width-1; i++)  
	{ 
		*(ii+ (i<<1)) = *(oo + i);     
		*(ii+ (i<<1)+1) = (*(oo + i) + *(oo + i + 1) + 1)>>1; 
		*(ii+ (width<<1)+ (i<<1)) = *(oo + i);     
		*(ii+ (width<<1)+ (i<<1)+1) = (*(oo + i) + *(oo + i + 1) + 1)>>1; 
		 
	} 
	 
	/* bottom right corner pels */ 
	*(ii + (width<<1) - 2) = *(oo + width -1); 
	*(ii + (width<<1) - 1) = *(oo + width -1); 
	*(ii + (width<<2) - 2) = *(oo + width -1); 
	*(ii + (width<<2) - 1) = *(oo + width -1); 
 
} 
 
 
 
/*! 
******************************************************************************* 
* 
*   Name:          grabVec 
*   Description:   refine best motion vectors and choose best mode for all mbs 
*                  of one picture 
*   Input:         the pointer of encoder strcture and MC structure 
*   Output:        MV(in MC structure) 
*   Last modified: 2002/11/21 
* 
*******************************************************************************/ 
void grabVec(H263VencStatus *encoder, MCParam *MC, int BACKWARD) 
{ 
	int i, j; 
	int pix_x, pix_y; 
	int pix_x_8, pix_y_8; 
	int block; 
	int x_center, y_center; 
	int sad_gate = 512; 
	void (*mv_search) (H263VencStatus*, MCParam*, int, int, int, int);  //!< search functions 
// added by lcl on 2003/2/26, parameter for calculation of SAD 
	int lx1 = encoder->pels; 
	int lx2 = encoder->mv_outside_frame ? encoder->pels+32 : encoder->pels; 
	unsigned char *p1 = (encoder->frameToEncode).pLum ; 
 
	if (encoder->PTYPE == B_IMG) 
	{ 
		p1 = (encoder->BPicture[encoder->B_count]).pLum; 
	}	 
	//! choose search method 
	if (0 == MC->method) 
	{ 
		mv_search = mv_search_fs; 
	} 
	else if(1 == MC->method) 
	{ 
		mv_search = mv_search_dmd; 
	} 
	else 
	{ 
		printf("Invalid MV search method"); 
		exit(-1); 
	} 
 
    /*! main loop */ 
	for (pix_y = 0, i = 0; pix_y < encoder->lines; pix_y+=16, i++) 
	{ 
		for (pix_x = 0, j = 0; pix_x < encoder->pels; pix_x+=16, j++) 
		{ 
			if (!BACKWARD) 
			{   
				/* Forward MV search(for both P frames and B frames). */ 
				 
				MC->mv = MC->mv_frame[0][i+1][j+1];     //!< assign a pointer for current mv 
				//! check zero point ahead of searching 
				(MC->mv)->x = 0; 
				(MC->mv)->y = 0; 
				(MC->mv)->min_sad = me_sad_a(lx1, lx2, pix_x, pix_y, pix_x, pix_y, p1, 
					                              encoder->frame_buf[encoder->ref_index].pLum, 
                                                  MAX_SAD, 16) - PREF_NULL_VEC; 
			//	(MC->mv)->min_sad = me_sad_a(encoder, pix_x, pix_y, pix_x, pix_y, MAX_SAD, 16, 0) - PREF_NULL_VEC; 
				if ((MC->mv)->min_sad > sad_gate) 
				{ 
					mv_search(encoder, MC, pix_x, pix_y, 16, BACKWARD);  //!< search integer mv (predictor of mv not used) 
				} 
				findhalfpel(encoder, MC, pix_x, pix_y, 16, BACKWARD); 
				 
				//! 8x8 block Search(only for P frames). 
				if (encoder->use4mv && (encoder->PTYPE!=B_IMG)) 
				{ 
					for (block = 0; block < 4; block++) 
					{ 
						pix_x_8 = pix_x+((block&1)<<3); 
						pix_y_8 = pix_y+((block&2)<<2); 
						MC->mv = MC->mv_frame[block+1][i+1][j+1];   //!< assign a pointer 
						// decide searching center  
						x_center = MC->mv_frame[0][i+1][j+1]->x; 
						y_center = MC->mv_frame[0][i+1][j+1]->y; 
						if (x_center > 15 - MC->search_range_8x8) { x_center =  15 - MC->search_range_8x8; } 
						if (y_center > 15 - MC->search_range_8x8) { y_center =  15 - MC->search_range_8x8; } 
						if (x_center < -15 + MC->search_range_8x8) { x_center =  -15 + MC->search_range_8x8; } 
						if (y_center < -15 + MC->search_range_8x8) { y_center =  -15 + MC->search_range_8x8; } 
						// do pre-search check 
						(MC->mv)->x = x_center; 
						(MC->mv)->y = y_center; 
						(MC->mv)->min_sad = me_sad_a(lx1, lx2, pix_x_8, pix_y_8, pix_x_8+x_center, pix_y_8+y_center, p1, 
							                              encoder->frame_buf[encoder->ref_index].pLum, MAX_SAD, 8); 
			//			(MC->mv)->min_sad = me_sad_a(encoder, pix_x_8, pix_y_8, pix_x_8+x_center, pix_y_8+y_center, MAX_SAD, 8, 0); 
						if((MC->mv)->min_sad > sad_gate/4) 
						{ 
							mv_search(encoder, MC, pix_x_8, pix_y_8, 8, BACKWARD); 
						} 
						findhalfpel(encoder, MC, pix_x_8, pix_y_8, 8, BACKWARD); 
					} 
				} 
			} 
			else 
			{ 
				/*! Backward MV Search(only for B frames). */ 
 
				if (encoder->PTYPE == B_IMG) 
				{ 
					MC->mv = MC->mv_frame[5][i+1][j+1];         //!< assign a pointer 
					// check zero point ahead of searching 
					(MC->mv)->x = 0; 
					(MC->mv)->y = 0; 
                    (MC->mv)->min_sad = me_sad_a(lx1, lx2, pix_x, pix_y, pix_x, pix_y, p1, 
						                              encoder->frame_buf[encoder->zero_index].pLum, 
													  MAX_SAD, 16) - PREF_NULL_VEC; 
				//	(MC->mv)->min_sad = me_sad_a(encoder, pix_x, pix_y, pix_x, pix_y, MAX_SAD, 16, 1) - PREF_NULL_VEC; 
					if ((MC->mv)->min_sad > sad_gate) 
					{ 
						mv_search(encoder, MC, pix_x, pix_y, 16, BACKWARD);  //!< search integer mv (predictor of mv not used) 
					} 
					findhalfpel(encoder, MC, pix_x, pix_y, 16, BACKWARD); 
				} 
			} 
			/* Choose mode(only for P frames, prediction mode of B frames  
			   will be decided outside).        */ 
			if (encoder->PTYPE != B_IMG)     
			{ 
				choose_mode(encoder, MC, pix_x, pix_y); 
			} 
#ifdef PRINTMV 
			printmv(encoder, MC, i, j, BACKWARD); 
#endif 
		} 
#ifdef PRINTMV 
		printf("\n"); 
#endif 
	} 
} 
 
 
/*! 
******************************************************************************* 
* 
*   Name:          mv_search_fs 
*   Description:   find best integer motion vector for a block(Full Search) 
*   Input:         position of current block 
*                  current lum image and reference lum image 
*   Output:        integer MV value 
*   Last modified: 2002/12/17 by lcl 
* 
*******************************************************************************/ 
void mv_search_fs(H263VencStatus *encoder, MCParam *MC, int curr_x, int curr_y, int blocksize, int BACKWARD) 
{ 
	int iMinSAD = (MC->mv)->min_sad; 
	int iCurrSAD; 
	int i; 
	int iXCheckPt; 
	int iYCheckPt; 
	int iCenterX = curr_x + (MC->mv)->x; 
	int iCenterY = curr_y + (MC->mv)->y; 
    int iXDest = iCenterX; 
	int iYDest = iCenterY; 
	int search_range = (8 == blocksize ? MC->search_range_8x8 : MC->search_range);  
	int iNbr = (2*search_range + 1) * (2*search_range + 1); 
	int mv_out; 
// added by lcl on 2003/2/22, parameter for calculation of SAD 
	int lx1 = encoder->pels; 
	int lx2 = encoder->mv_outside_frame ? encoder->pels+32 : encoder->pels; 
	int index = BACKWARD ? encoder->zero_index : encoder->ref_index; 
	unsigned char *p1 = (encoder->frameToEncode).pLum ; 
	unsigned char *p2 = (encoder->frame_buf[index]).pLum ; 
 
	if (encoder->PTYPE == B_IMG) 
	{ 
		mv_out = 1; 
		p1 = (encoder->BPicture[encoder->B_count]).pLum; 
	} 
	else 
	{ 
		mv_out = encoder->annex.Advanced_Prediction || encoder->annex.Deblocking_Filter; 
	} 
 
	for (i = 1; i < iNbr; i++) 
	{ 
		iXCheckPt = iCenterX + SpiralX[i]; 
		iYCheckPt = iCenterY + SpiralY[i]; 
 
		if ( (iXCheckPt<0||iYCheckPt<0|| 
			  iXCheckPt>encoder->pels - blocksize || 
			  iYCheckPt>encoder->lines - blocksize) 
		    && !mv_out) 
            continue; 
		 
		//iCurrSAD = me_sad_a(encoder, curr_x, curr_y, iXCheckPt, iYCheckPt, iMinSAD, blocksize, BACKWARD); 
		iCurrSAD = me_sad_a(lx1, lx2, curr_x, curr_y, iXCheckPt, iYCheckPt, p1, p2, iMinSAD, blocksize); 
		if (iCurrSAD >= iMinSAD) 
		    continue; 
		 
		iMinSAD= iCurrSAD; 
		iXDest = iXCheckPt; 
    	iYDest = iYCheckPt; 
	} 
	(MC->mv)->x = iXDest-curr_x; 
	(MC->mv)->y = iYDest-curr_y; 
	(MC->mv)->min_sad = iMinSAD; 
} 
 
/*! 
******************************************************************************* 
* 
*   Name:          mv_search_dmd 
*   Description:   find best integer motion vector for a block(Noval Diomand Search) 
*   Input:         position of current block 
*                  current lum image and reference lum image 
*   Output:        integer MV value 
*   Last modified: 2002/12/17 by lcl 
* 
*******************************************************************************/ 
void mv_search_dmd(H263VencStatus *encoder, MCParam *MC, int curr_x, int curr_y, int blocksize, int BACKWARD) 
{ 
	int iMinSAD=(MC->mv)->min_sad; 
	int mbDiff; 
    int iTotalCheckPts, iCheckPts, iMotDirn=0, iPtNmbr=0; 
    int MOTION_ACTIVITY; 
    int stopFlag=0, stopDiamondMotion=0; 
    int dXCentre=curr_x + (MC->mv)->x; 
	int dYCentre=curr_y + (MC->mv)->y; 
    int iXDest=dXCentre; 
	int iYDest=dYCentre; 
	int iXCheckPt, iYCheckPt; 
	int dType; 
	int L1=1, L2=2, L3=4; 
	int LMotion = 0; 
	int block = 0; 
	int mb_x = curr_x/16; 
	int mb_y = curr_y/16; 
	int vec_x; 
	int vec_y; 
	int search_range = (8 == blocksize) ? MC->search_range_8x8 : MC->search_range; 
	int mv_out; 
// added by lcl on 2003/2/22, parameter for calculation of SAD 
	int lx1 = encoder->pels; 
	int lx2 = encoder->mv_outside_frame ? encoder->pels+32 : encoder->pels; 
	int index = BACKWARD ? encoder->zero_index : encoder->ref_index; 
	unsigned char *p1 = (encoder->frameToEncode).pLum ; 
	unsigned char *p2 = (encoder->frame_buf[index]).pLum ; 
 
	if (encoder->PTYPE == B_IMG) 
	{ 
		mv_out = 1; 
		p1 = (encoder->BPicture[encoder->B_count]).pLum; 
	} 
	else 
	{ 
		mv_out = encoder->annex.Advanced_Prediction || encoder->annex.Deblocking_Filter; 
	} 
 
//! assign neighborhood MVs as points of diamond[2], which is MotAdaptPat 
	FindNbrMV(MC->mv_frame, block, 0, mb_x, mb_y, &vec_x, &vec_y, BACKWARD);  //!< left 
	diamond[2].dpoint[0].x = vec_x - (MC->mv)->x; 
	diamond[2].dpoint[0].y = vec_y - (MC->mv)->y; 
	FindNbrMV(MC->mv_frame, block, 1, mb_x, mb_y, &vec_x, &vec_y, BACKWARD);  //!< up 
	diamond[2].dpoint[1].x = vec_x - (MC->mv)->x; 
	diamond[2].dpoint[1].y = vec_y - (MC->mv)->y; 
	FindNbrMV(MC->mv_frame, block, 2, mb_x, mb_y, &vec_x, &vec_y, BACKWARD);	//!< up-right  
	diamond[2].dpoint[2].x = vec_x - (MC->mv)->x; 
	diamond[2].dpoint[2].y = vec_y - (MC->mv)->y; 
//! compute motion activity 
	MOTION_ACTIVITY = max(abs(diamond[2].dpoint[0].x)+abs(diamond[2].dpoint[0].y) , max( abs(diamond[2].dpoint[1].x)+abs(diamond[2].dpoint[1].y)  , abs(diamond[2].dpoint[2].x)+abs(diamond[2].dpoint[2].y)) ); 
 
	if (MOTION_ACTIVITY > L3) 
		LMotion = 1;             //!> detect large motion 
	dType=(MOTION_ACTIVITY > L2) ? MotAdaptPat : ((MOTION_ACTIVITY > L1) ? LDiamond : SDiamond); 
	iTotalCheckPts=diamond[dType].no_check_pts; 
 
			  while(stopFlag!=1) 
			  { 
				  iCheckPts=iTotalCheckPts; 
				  do 
				  { 
					iXCheckPt=diamond[dType].dpoint[iPtNmbr].x+dXCentre; 
					iYCheckPt=diamond[dType].dpoint[iPtNmbr].y+dYCentre; 
					 
 
	            	if ( (iXCheckPt < 0||iYCheckPt < 0|| 
		            	  iXCheckPt > (encoder->pels - blocksize)|| 
		             	  iYCheckPt > (encoder->lines - blocksize)) 
					   && !mv_out) 
					   goto NEXT_POSITION; 
					if ( (iXCheckPt-curr_x) < -search_range|| 
						(iXCheckPt-curr_x) > search_range|| 
 		                (iYCheckPt-curr_y) < -search_range|| 
						(iYCheckPt-curr_y) > search_range) 
						goto NEXT_POSITION;   //!< skip this check point 
					else 
					{ 
 
		                mbDiff = me_sad_a(lx1, lx2, curr_x, curr_y, iXCheckPt, iYCheckPt, p1, p2, iMinSAD, blocksize);                        
						if (mbDiff < iMinSAD) 
						{ 
							iMinSAD= mbDiff; 
							iXDest = iXCheckPt; 
							iYDest = iYCheckPt; 
							iMotDirn=iPtNmbr; 
						} 
					} 
NEXT_POSITION: 
					iPtNmbr+=1; 
					iPtNmbr=(dType==LDiamond) ? iPtNmbr % diamond[LDiamond].no_check_pts : iPtNmbr % diamond[SDiamond].no_check_pts; 
					iCheckPts-=1; 
				  }while(iCheckPts>0); 
 
				  if(dType==MotAdaptPat) 
				  { 
					  dType = LMotion?LDiamond:SDiamond; //!> if large motion, Large Diamond used 
					  iPtNmbr=0; 
					  iTotalCheckPts=diamond[dType].no_check_pts; 
				  } 
				  else 
				  { 
					  if((iXDest==dXCentre)&&(iYDest==dYCentre)) 
						  stopDiamondMotion=1; 
					  else 
					  { 
						  iTotalCheckPts=(((iXDest==dXCentre) || (iYDest==dYCentre))&&(dType==LDiamond)) ? 5 :3; 
						  iPtNmbr=diamond[dType].dpoint[iMotDirn].iStartNmbr; 
					  } 
				  } 
				  if(stopDiamondMotion) 
				  { 
					  if(dType==LDiamond) 
					  { 
						    dType = SDiamond; 
						    iPtNmbr = 0; 
						    iTotalCheckPts = diamond[dType].no_check_pts; 
					  } 
					  else 
						  stopFlag=1; 
				  } 
				  dXCentre=iXDest; 
				  dYCentre=iYDest; 
			  } 
	(MC->mv)->x = iXDest - curr_x; 
	(MC->mv)->y = iYDest - curr_y; 
	(MC->mv)->min_sad = iMinSAD; 
} 
/*! 
******************************************************************************* 
* 
*   Name:          findhalfpel 
*   Description:   find best motion vectors in half resolution 
*   Input:         position of current block  
*                  current lum image and interpolated reference lum image 
*   Output:        half MV value 
*   Last modified: 2002/11/23 by lcl 
* 
*******************************************************************************/ 
void findhalfpel(H263VencStatus *encoder, MCParam *MC, int x, int y, int blocksize, int BACKWARD) 
{ 
	int iXPos[9] = {0, -1, 0, 1, -1, 1, -1, 0, 1}; 
	int iYPos[9] = {0, -1, -1, -1, 0, 0, 1, 1, 1}; 
	int iMinSAD, iCurrSAD; 
	int iCenterX; 
	int iCenterY; 
	int iCheckPtX; 
	int iCheckPtY; 
	int iPoint, iBestPt; 
	int mv_out; 
// added by lcl on 2003/2/22, parameter for calculation of SAD 
	int lx1 = encoder->pels; 
	int lx2 = encoder->mv_outside_frame ? encoder->pels*2+64 : encoder->pels*2; 
	unsigned char *ipol = BACKWARD ? encoder->next_ipol : encoder->prev_ipol; 
	unsigned char *p1 = (encoder->frameToEncode).pLum; 
	unsigned char *p2 = ipol; 
	if (encoder->PTYPE == B_IMG) 
	{ 
		mv_out = 1; 
		p1 = (encoder->BPicture[encoder->B_count]).pLum; 
	} 
	else 
	{ 
		mv_out = encoder->annex.Advanced_Prediction || encoder->annex.Deblocking_Filter; 
	} 
	 
	iBestPt = 0; 
    iMinSAD = (MC->mv)->min_sad; 
	iCenterX = (x + (MC->mv)->x)<<1; 
	iCenterY = (y + (MC->mv)->y)<<1; 
 
	for (iPoint = 1; iPoint < 9; iPoint++) 
	{ 
 
		iCheckPtX = iCenterX + iXPos[iPoint];   //!< Current absolute X position in the reference pic 
		iCheckPtY = iCenterY + iYPos[iPoint];   //!< Current absolute Y position in the reference pic 
 
		if ( (iCheckPtX<0 || 
			  iCheckPtY<0 || 
			  iCheckPtX>(encoder->pels - blocksize)*2 ||  //!< keep in agreement with h.263 coder 
			  iCheckPtY>(encoder->lines - blocksize)*2)   //!< should be considered later 
		   && !mv_out)              
            continue; 
        iCurrSAD = me_sad_b(lx1, lx2, x, y, iCheckPtX, iCheckPtY, p1, p2, iMinSAD, blocksize); 
		if (iCurrSAD >= iMinSAD) 
			continue; 
		iMinSAD = iCurrSAD; 
		iBestPt = iPoint; 
	} 
	(MC->mv)->x_half = iXPos[iBestPt]; 
	(MC->mv)->y_half = iYPos[iBestPt]; 
	(MC->mv)->min_sad = iMinSAD; 
} 
/*! 
******************************************************************************* 
* 
*   Name:          zeroVec 
*   Description:    
*   Input:          
*   Output:         
*   Last modified: 2002/11/23 by lcl 
* 
*******************************************************************************/ 
void zeroVec(MotionVector *MV) 
{ 
	MV->x = 0; 
	MV->y = 0; 
	MV->x_half = 0; 
	MV->y_half = 0; 
} 
 
/*! 
******************************************************************************* 
* 
*   Name:          me_sad_a16 
*   Description:   compute sad for integer pel motion search 
*   Input:         current lum image and reference lum image 
*                  position of current block in current image 
*                  position of reference block in reference image 
*   Output:        sad returned 
*   Optimization:  sadmmx.cpp 
*   Last modified: 2003/02/20 by lcl 
* 
*******************************************************************************/ 
int me_sad_a(int lx1, int lx2, int x1, int y1, int x2,  int y2,  
			 unsigned char *P1, unsigned char *P2,   
			 int sad_last, int blocksize) 
{ 
	int i, j; 
	int sad = 0; 
	unsigned char *p1 = P1 + y1*lx1 + x1; 
	unsigned char *p2 = P2 + y2*lx2 +x2 ; 
 
	for(i = 0; i < blocksize; i++) 
	{ 
		for(j = 0; j < blocksize; j+=4) 
		{ 
			sad+=absm(p1[j] - p2[j]); 
			sad+=absm(p1[j+1] - p2[j+1]); 
			sad+=absm(p1[j+2] - p2[j+2]); 
			sad+=absm(p1[j+3] - p2[j+3]); 
			if (sad > sad_last) 
				return MAX_SAD; 
		} 
		p1+=lx1; 
		p2+=lx2; 
	} 
	return sad; 
} 
/*! 
******************************************************************************* 
* 
*   Name:          me_sad_b    
*   Description:   compute sad for half pel motion search 
*   Input:         current lum image, interpolated image derived from reference frame 
*                  position of current block in current lum image, 
*                  position of reference block in interpolated reference image 
*   Output:        sad returned 
*   Optimization:  sadmmx.cpp 
*   Last modified: 2002/12/17 by lcl 
* 
*******************************************************************************/ 
int me_sad_b(int lx1, int lx2,  int x1, int y1, int x2,  int y2,  
			 unsigned char *P1, unsigned char *P2, 
			 int sad_last, int blocksize) 
{ 
	int i, j, k; 
	int sad = 0; 
	unsigned char *p1 = P1 + y1*lx1 + x1; 
	unsigned char *p2 = P2 + y2*lx2 + x2 ; 
 
	for(i = 0; i < blocksize; i++) 
	{ 
		for(j = 0, k = 0; j < blocksize; j+=4, k+=8) 
		{ 
			sad+=absm(p1[j] - p2[k]); 
			sad+=absm(p1[j+1] - p2[k+2]); 
			sad+=absm(p1[j+2] - p2[k+4]); 
			sad+=absm(p1[j+3] - p2[k+6]); 
			if (sad > sad_last) 
				return MAX_SAD; 
		} 
		p1+=lx1; 
		p2+=lx2*2; 
	} 
	return sad; 
} 
 
/*! 
******************************************************************************* 
* 
*   Name:          Choose_mode      
*   Description:   Choose INTRA or INTER 
*   Input:         Position of current MB, sad value derived from motion estimation 
*   Output:         
*   Side effect:   If the mode is INTRA, set current mv zero 
*   Author:        Modified from tmn1.7 by lcl 
*   Last modified: 2002/11/23 by lcl 
* 
*******************************************************************************/ 
void choose_mode(H263VencStatus *encoder, MCParam *MC, int x_pos, int y_pos) 
{ 
	int i,j; 
	int MB_mean = 0, A = 0; 
	int y_off; 
	unsigned char *curr = encoder->frameToEncode.pLum; 
	int mb_size = 16; 
	int lines = y_pos/mb_size; 
	int pels = x_pos/mb_size; 
	int sad16, sad8; 
	int min_sad; 
	 
	sad16 = MC->mv_frame[0][lines+1][pels+1]->min_sad; 
	sad8  = !encoder->use4mv ? MAX_SAD : 
	MC->mv_frame[1][lines+1][pels+1]->min_sad+ 
		MC->mv_frame[2][lines+1][pels+1]->min_sad+ 
		MC->mv_frame[3][lines+1][pels+1]->min_sad+ 
		MC->mv_frame[4][lines+1][pels+1]->min_sad+ PREF_16_VEC; 
	 
	if (sad8 < sad16) 
	{ 
		MC->mv_frame[0][lines+1][pels+1]->Mode = MODE_INTER4V; 
	} 
	else 
	{ 
		MC->mv_frame[0][lines+1][pels+1]->Mode = MODE_INTER; 
	} 
	min_sad = sad8 < sad16 ? sad8 : sad16; 
	 
	for (j = 0; j < mb_size; j++)  
	{ 
		y_off = (y_pos + j) * encoder->pels; 
		for (i = 0; i < mb_size; i++)  
		{   
			MB_mean += *(curr + x_pos + i + y_off); 
		} 
	} 
	MB_mean /= (mb_size * mb_size); 
	 
	for (j = 0; j < mb_size; j++)  
	{ 
		y_off = (y_pos + j) * encoder->pels; 
		for (i = 0; i < mb_size; i++)  
		{ 
			A += abs( *(curr + x_pos + i + y_off) - MB_mean ); 
		} 
	} 
	if (A < (min_sad - 500))  
	{ 
		zeroVec(MC->mv_frame[0][lines+1][pels+1]); 
		(MC->mv_frame[0][lines+1][pels+1])->Mode = MODE_INTRA; 
	} 
} 
 
/*! 
******************************************************************************* 
* 
*   Name:           
*   Description:    
*   Input:          
*   Output:         
*   Last modified:  
* 
*******************************************************************************/ 
int ZeroVector(MotionVector *mv) 
{ 
	if(0 == mv->x && 0 == mv->y && 0 == mv->x_half && 0 == mv->y_half) 
	{ 
		return 1; 
	} 
	else 
	{ 
		return 0; 
	} 
} 
 
 
/*! 
******************************************************************************* 
* 
*   Name:           
*   Description:    
*   Input:          
*   Output:         
*   Last modified:  
* 
*******************************************************************************/ 
void FindNbrMV(MotionVector *MV[6][MBR+1][MBC+2], int block, int index,  
			   int mb_x, int mb_y, int *vec_x, int *vec_y, int BACKWARD) 
{ 
	int p[3]; 
	int xin1, xin2, xin3; 
	int yin1, yin2, yin3; 
	int vec1, vec2, vec3; 
	int l8, o8, or8; 
	 
 
	if (!BACKWARD) 
	{ 
		l8 = o8 = or8 = 0; 
		if (MV[0][mb_y+1][mb_x]->Mode == MODE_INTER4V) 
		{ 
			l8 = 1; 
		} 
		 
		if (MV[0][mb_y][mb_x+1]->Mode == MODE_INTER4V) 
		{ 
			o8 = 1; 
		} 
		 
		if (MV[0][mb_y][mb_x+2]->Mode == MODE_INTER4V) 
		{ 
			or8 = 1; 
		} 
		 
		 
		switch (block)  
		{ 
		case 0:  
			vec1 = (l8 ? 2 : 0) ; yin1 = mb_y  ; xin1 = mb_x-1; 
			vec2 = (o8 ? 3 : 0) ; yin2 = mb_y-1; xin2 = mb_x; 
			vec3 = (or8? 3 : 0) ; yin3 = mb_y-1; xin3 = mb_x+1; 
			break; 
		case 1: 
			vec1 = (l8 ? 2 : 0) ; yin1 = mb_y  ; xin1 = mb_x-1; 
			vec2 = (o8 ? 3 : 0) ; yin2 = mb_y-1; xin2 = mb_x; 
			vec3 = (or8? 3 : 0) ; yin3 = mb_y-1; xin3 = mb_x+1; 
			break; 
		case 2: 
			vec1 = 1            ; yin1 = mb_y  ; xin1 = mb_x; 
			vec2 = (o8 ? 4 : 0) ; yin2 = mb_y-1; xin2 = mb_x; 
			vec3 = (or8? 3 : 0) ; yin3 = mb_y-1; xin3 = mb_x+1; 
			break; 
		case 3: 
			vec1 = (l8 ? 4 : 0) ; yin1 = mb_y  ; xin1 = mb_x-1; 
			vec2 = 1            ; yin2 = mb_y  ; xin2 = mb_x; 
			vec3 = 2            ; yin3 = mb_y  ; xin3 = mb_x; 
			break; 
		case 4: 
			vec1 = 3            ; yin1 = mb_y  ; xin1 = mb_x; 
			vec2 = 1            ; yin2 = mb_y  ; xin2 = mb_x; 
			vec3 = 2            ; yin3 = mb_y  ; xin3 = mb_x; 
			break; 
		} 
	} 
	else 
	{ 
		vec1 = vec2 = vec3 = 5; 
		yin1 = mb_y  ; xin1 = mb_x-1; 
		yin2 = mb_y-1; xin2 = mb_x; 
		yin3 = mb_y-1; xin3 = mb_x+1; 
	} 
 
	p[0] = MV[vec1][yin1+1][xin1+1]->x; 
	p[1] = mb_y > 0 ? MV[vec2][yin2+1][xin2+1]->x : 0; 
	p[2] = mb_y > 0 ? MV[vec3][yin3+1][xin3+1]->x : 0; 
	*vec_x = p[index]; 
	p[0] = MV[vec1][yin1+1][xin1+1]->y; 
	p[1] = mb_y > 0 ? MV[vec2][yin2+1][xin2+1]->y : 0; 
	p[2] = mb_y > 0 ? MV[vec3][yin3+1][xin3+1]->y : 0; 
    *vec_y = p[index];	 
}  
 
/*! 
******************************************************************************* 
* 
*   Name:           
*   Description:    
*   Input:          
*   Output:         
*   Last modified:  
* 
*******************************************************************************/ 
void printmv(H263VencStatus *encoder, MCParam *MC, int r, int c, int BACKWARD) 
{ 
	if (!BACKWARD) 
	{ 
		printf("(%d, %d)", MC->mv_frame[0][r+1][c+1]->x, MC->mv_frame[0][r+1][c+1]->y); 
		printf("(%d, %d)", MC->mv_frame[0][r+1][c+1]->x_half, MC->mv_frame[0][r+1][c+1]->y_half); 
		printf("%d", MC->mv_frame[0][r+1][c+1]->min_sad); 
		if(encoder->use4mv) 
		{ 
			printf("-"); 
			printf("(%d, %d)", MC->mv_frame[1][r+1][c+1]->x, MC->mv_frame[1][r+1][c+1]->y); 
			printf("(%d, %d)", MC->mv_frame[1][r+1][c+1]->x_half, MC->mv_frame[1][r+1][c+1]->y_half); 
			printf("&"); 
			printf("(%d, %d)", MC->mv_frame[2][r+1][c+1]->x, MC->mv_frame[2][r+1][c+1]->y); 
			printf("(%d, %d)", MC->mv_frame[2][r+1][c+1]->x_half, MC->mv_frame[2][r+1][c+1]->y_half); 
			printf("&"); 
			printf("(%d, %d)", MC->mv_frame[3][r+1][c+1]->x, MC->mv_frame[3][r+1][c+1]->y); 
			printf("(%d, %d)", MC->mv_frame[3][r+1][c+1]->x_half, MC->mv_frame[3][r+1][c+1]->y_half); 
			printf("&"); 
			printf("(%d, %d)", MC->mv_frame[4][r+1][c+1]->x, MC->mv_frame[4][r+1][c+1]->y); 
			printf("(%d, %d)", MC->mv_frame[4][r+1][c+1]->x_half, MC->mv_frame[4][r+1][c+1]->y_half); 
			printf("%d",  MC->mv_frame[1][r+1][c+1]->min_sad+MC->mv_frame[2][r+1][c+1]->min_sad+ 
				MC->mv_frame[3][r+1][c+1]->min_sad+MC->mv_frame[4][r+1][c+1]->min_sad); 
		} 
		printf("\n"); 
	} 
	else  
	{ 
		printf("Backward MV: "); 
		printf("(%d, %d)", MC->mv_frame[5][r+1][c+1]->x, MC->mv_frame[5][r+1][c+1]->y); 
		printf("(%d, %d)", MC->mv_frame[5][r+1][c+1]->x_half, MC->mv_frame[5][r+1][c+1]->y_half); 
		printf("%d", MC->mv_frame[5][r+1][c+1]->min_sad); 
		printf("\n"); 
	} 
} 
 
/*! 
******************************************************************************* 
* 
*   Name:          saveVec 
*   Description:   Save vectors for B frames to compute MVs in direct mode 
*   Input:          
*   Output:         
*   Last modified: 2003/1/8 
* 
*******************************************************************************/ 
void saveVec(MCParam *MC, int lines, int pels) 
{ 
	int i, j, k; 
 
	for (i = 0; i < lines; i++) 
	{ 
		for (j = 0; j < pels; j++) 
		{ 
			if (MC->mv_frame[0][i+1][j+1]->Mode == MODE_INTER4V) 
			{ 
				MC->mv_lastframe[0][i][j]->Mode = MC->mv_frame[0][i+1][j+1]->Mode; 
				for (k = 0; k < 5; k++) 
				{ 
					MC->mv_lastframe[k][i][j]->x = MC->mv_frame[k][i+1][j+1]->x; 
					MC->mv_lastframe[k][i][j]->y = MC->mv_frame[k][i+1][j+1]->y; 
					MC->mv_lastframe[k][i][j]->x_half = MC->mv_frame[k][i+1][j+1]->x_half; 
					MC->mv_lastframe[k][i][j]->y_half = MC->mv_frame[k][i+1][j+1]->y_half; 
					MC->mv_lastframe[k][i][j]->Mode = MC->mv_frame[k][i+1][j+1]->Mode; 
					MC->mv_lastframe[k][i][j]->min_sad = MC->mv_frame[k][i+1][j+1]->min_sad; 
				} 
			} 
			else 
			{ 
				MC->mv_lastframe[0][i][j]->x = MC->mv_frame[0][i+1][j+1]->x; 
				MC->mv_lastframe[0][i][j]->y = MC->mv_frame[0][i+1][j+1]->y; 
				MC->mv_lastframe[0][i][j]->x_half = MC->mv_frame[0][i+1][j+1]->x_half; 
				MC->mv_lastframe[0][i][j]->y_half = MC->mv_frame[0][i+1][j+1]->y_half; 
				MC->mv_lastframe[0][i][j]->Mode = MC->mv_frame[0][i+1][j+1]->Mode; 
				MC->mv_lastframe[0][i][j]->min_sad = MC->mv_frame[0][i+1][j+1]->min_sad; 
			} 
		} 
	} 
} 
 
#ifdef  __cplusplus 
} 
#endif