⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 motion_est.c

📁 MPEG-4编解码的实现(包括MPEG4视音频编解码)
💻 C
📖 第 1 页 / 共 4 页
字号:
	currPMV->x = currMV->x - pmv[0].x;
	currPMV->y = currMV->y - pmv[0].y;
	
	return iMinSAD;
}

int32_t EPZSSearch16(
					const uint8_t * const pRef,
					const uint8_t * const pRefH,
					const uint8_t * const pRefV,
					const uint8_t * const pRefHV,
					const IMAGE * const pCur,
					const int x, const int y,
					const uint32_t MotionFlags,
					const MBParam * const pParam,
					MACROBLOCK * const pMBs,
					VECTOR * const currMV,
					VECTOR * const currPMV)
{
        const uint32_t iWcount = pParam->mb_width;
        const uint32_t iHcount = pParam->mb_height;
	const int32_t iFcode = pParam->fixed_code;
	const int32_t iQuant = pParam->quant;

	const int32_t iWidth = pParam->width;
	const int32_t iHeight = pParam->height;
	const int32_t iEdgedWidth = pParam->edged_width; 

	const uint8_t * cur = pCur->y + x*16 + y*16*iEdgedWidth;

	int32_t min_dx;
	int32_t max_dx;
	int32_t min_dy;
	int32_t max_dy;
		
	VECTOR newMV;
	VECTOR backupMV;
	
	VECTOR pmv[4];
	int32_t psad[8];
	
	static MACROBLOCK * oldMBs = NULL; 
	MACROBLOCK * const pMB = pMBs + x + y * iWcount;
	MACROBLOCK * oldMB = NULL;

	static int32_t thresh2;
    	int32_t bPredEq;
    	int32_t iMinSAD,iSAD=9999;

	MainSearch16FuncPtr EPZSMainSearchPtr;

	if (oldMBs == NULL)
	{	oldMBs = (MACROBLOCK*) calloc(1,iWcount*iHcount*sizeof(MACROBLOCK));
		fprintf(stderr,"allocated %d bytes for oldMBs\n",iWcount*iHcount*sizeof(MACROBLOCK));
	}
	oldMB = oldMBs + x + y * iWcount;

/* Get maximum range */
	get_range(&min_dx, &max_dx, &min_dy, &max_dy,
			x, y, 16, iWidth, iHeight, iFcode);

/* we work with abs. MVs, not relative to prediction, so get_range is called relative to 0,0 */

	if (!(MotionFlags & PMV_HALFPEL16 ))
	{ min_dx = EVEN(min_dx);
	  max_dx = EVEN(max_dx);
	  min_dy = EVEN(min_dy);
	  max_dy = EVEN(max_dy); 
	}		/* because we might use something like IF (dx>max_dx) THEN dx=max_dx; */
		
	bPredEq  = get_pmvdata(pMBs, x, y, iWcount, 0, pmv, psad);

/* Step 4: Calculate SAD around the Median prediction. 
        MinSAD=SAD 
        If Motion Vector equal to Previous frame motion vector 
		and MinSAD<PrevFrmSAD goto Step 10. 
        If SAD<=256 goto Step 10. 
*/	

// Prepare for main loop 

	*currMV=pmv[0];		/* current best := median prediction */
	if (!(MotionFlags & PMV_HALFPEL16))
	{ 	
		currMV->x = EVEN(currMV->x);
		currMV->y = EVEN(currMV->y);
	}
	
	if (currMV->x > max_dx) 	
		currMV->x=max_dx;
	if (currMV->x < min_dx) 
		currMV->x=min_dx;
	if (currMV->y > max_dy) 
		currMV->y=max_dy;
	if (currMV->y < min_dy) 
		currMV->y=min_dy;

/***************** This is predictor SET A: only median prediction ******************/ 
	
	iMinSAD = sad16( cur, 
		get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 16, currMV, iEdgedWidth),
		iEdgedWidth, MV_MAX_ERROR);
  	iMinSAD += calc_delta_16(currMV->x-pmv[0].x, currMV->y-pmv[0].y, (uint8_t)iFcode) * iQuant;
	
// thresh1 is fixed to 256 
	if ( (iMinSAD < 256 ) || ( (MVequal(*currMV,pMB->mvs[0])) && (iMinSAD < pMB->sad16) ) )
		{
			if (MotionFlags & PMV_QUICKSTOP16) 
				goto EPZS16_Terminate_without_Refine;
			if (MotionFlags & PMV_EARLYSTOP16) 
				goto EPZS16_Terminate_with_Refine;
		}

/************** This is predictor SET B: (0,0), prev.frame MV, neighbours **************/ 

// previous frame MV 
	CHECK_MV16_CANDIDATE(pMB->mvs[0].x,pMB->mvs[0].y);

// set threshhold based on Min of Prediction and SAD of collocated block
// CHECK_MV16 always uses iSAD for the SAD of last vector to check, so now iSAD is what we want

	if ((x==0) && (y==0) )
	{
		thresh2 =  512;
	}
	else
	{
/* T_k = 1.2 * MIN(SAD_top,SAD_left,SAD_topleft,SAD_coll) +128;   [Tourapis, 2002] */

		thresh2 = MIN(psad[0],iSAD)*6/5 + 128;	
	}

// MV=(0,0) is often a good choice

	CHECK_MV16_ZERO;

	
// left neighbour, if allowed
	if (x != 0) 
	{
		if (!(MotionFlags & PMV_HALFPEL16 ))
		{	pmv[1].x = EVEN(pmv[1].x);
			pmv[1].y = EVEN(pmv[1].y);
		}
		CHECK_MV16_CANDIDATE(pmv[1].x,pmv[1].y);		
	}

// top neighbour, if allowed
	if (y != 0)
	{	
		if (!(MotionFlags & PMV_HALFPEL16 ))
		{	pmv[2].x = EVEN(pmv[2].x);
			pmv[2].y = EVEN(pmv[2].y);
		}
		CHECK_MV16_CANDIDATE(pmv[2].x,pmv[2].y);
	
// top right neighbour, if allowed
		if (x != (iWcount-1))
		{
			if (!(MotionFlags & PMV_HALFPEL16 ))
			{	pmv[3].x = EVEN(pmv[3].x);
				pmv[3].y = EVEN(pmv[3].y);
			}
			CHECK_MV16_CANDIDATE(pmv[3].x,pmv[3].y);
		}
	}

/* Terminate if MinSAD <= T_2 
   Terminate if MV[t] == MV[t-1] and MinSAD[t] <= MinSAD[t-1] 
*/

	if ( (iMinSAD <= thresh2) 
		|| ( MVequal(*currMV,pMB->mvs[0]) && (iMinSAD <= pMB->sad16) ) )
		{	
			if (MotionFlags & PMV_QUICKSTOP16) 
				goto EPZS16_Terminate_without_Refine;
			if (MotionFlags & PMV_EARLYSTOP16) 
				goto EPZS16_Terminate_with_Refine;
		}

/***** predictor SET C: acceleration MV (new!), neighbours in prev. frame(new!) ****/

	backupMV = pMB->mvs[0]; 		// last MV
	backupMV.x += (pMB->mvs[0].x - oldMB->mvs[0].x );	// acceleration X
	backupMV.y += (pMB->mvs[0].y - oldMB->mvs[0].y );	// acceleration Y 

	CHECK_MV16_CANDIDATE(backupMV.x,backupMV.y);	

// left neighbour
	if (x != 0)  
		CHECK_MV16_CANDIDATE((oldMB-1)->mvs[0].x,oldMB->mvs[0].y);		

// top neighbour 
	if (y != 0)
		CHECK_MV16_CANDIDATE((oldMB-iWcount)->mvs[0].x,oldMB->mvs[0].y);		

// right neighbour, if allowed (this value is not written yet, so take it from   pMB->mvs 

	if (x != iWcount-1)
		CHECK_MV16_CANDIDATE((pMB+1)->mvs[0].x,oldMB->mvs[0].y);		

// bottom neighbour, dito
	if (y != iHcount-1)
		CHECK_MV16_CANDIDATE((pMB+iWcount)->mvs[0].x,oldMB->mvs[0].y);		

/* Terminate if MinSAD <= T_3 (here T_3 = T_2)  */
	if (iMinSAD <= thresh2)
		{	
			if (MotionFlags & PMV_QUICKSTOP16) 
				goto EPZS16_Terminate_without_Refine;
			if (MotionFlags & PMV_EARLYSTOP16) 
				goto EPZS16_Terminate_with_Refine;
		}

/************ (if Diamond Search)  **************/

	backupMV = *currMV; /* save best prediction, actually only for EXTSEARCH */

/* default: use best prediction as starting point for one call of PMVfast_MainSearch */

	if (MotionFlags & PMV_USESQUARES16)
		EPZSMainSearchPtr = Square16_MainSearch;
	else
		EPZSMainSearchPtr = Diamond16_MainSearch;

	iSAD = (*EPZSMainSearchPtr)(pRef, pRefH, pRefV, pRefHV, cur,
			x, y, 
			currMV->x, currMV->y, iMinSAD, &newMV, pmv, min_dx, max_dx, min_dy, max_dy, iEdgedWidth, 
			2, iFcode, iQuant, 0);
	
	if (iSAD < iMinSAD) 
	{
		*currMV = newMV;
		iMinSAD = iSAD;
	}


	if (MotionFlags & PMV_EXTSEARCH16)
	{
/* extended mode: search (up to) two more times: orignal prediction and (0,0) */

		if (!(MVequal(pmv[0],backupMV)) )
		{ 	
			iSAD = (*EPZSMainSearchPtr)(pRef, pRefH, pRefV, pRefHV, cur,
				x, y, 
				pmv[0].x, pmv[0].y, iMinSAD, &newMV, 
				pmv, min_dx, max_dx, min_dy, max_dy, iEdgedWidth, 2, iFcode, iQuant, 0);
		}
			
		if (iSAD < iMinSAD) 
		{
			*currMV = newMV;
			iMinSAD = iSAD;
		}
	
		if ( (!(MVzero(pmv[0]))) && (!(MVzero(backupMV))) )
		{ 	
			iSAD = (*EPZSMainSearchPtr)(pRef, pRefH, pRefV, pRefHV, cur,
				x, y, 
			0, 0, iMinSAD, &newMV, 
			pmv, min_dx, max_dx, min_dy, max_dy, iEdgedWidth, /*iDiamondSize*/ 2, iFcode, iQuant, 0);
		
			if (iSAD < iMinSAD) 
			{
				*currMV = newMV;
				iMinSAD = iSAD;
			}
		}
	}

/*************** 	Choose best MV found     **************/

EPZS16_Terminate_with_Refine:
	if (MotionFlags & PMV_HALFPELREFINE16) 		// perform final half-pel step 
		iMinSAD = Halfpel16_Refine( pRef, pRefH, pRefV, pRefHV, cur,
				x, y,
				currMV, iMinSAD, 
				pmv, min_dx, max_dx, min_dy, max_dy, iFcode, iQuant, iEdgedWidth);

EPZS16_Terminate_without_Refine:

	*oldMB = *pMB;
	
	currPMV->x = currMV->x - pmv[0].x;
	currPMV->y = currMV->y - pmv[0].y;
	return iMinSAD;
}


int32_t EPZSSearch8(
					const uint8_t * const pRef,
					const uint8_t * const pRefH,
					const uint8_t * const pRefV,
					const uint8_t * const pRefHV,
					const IMAGE * const pCur,
					const int x, const int y,
					const int start_x, int start_y,
					const uint32_t MotionFlags,
					const MBParam * const pParam,
					MACROBLOCK * const pMBs,
					VECTOR * const currMV,
					VECTOR * const currPMV)
{
        const uint32_t iWcount = pParam->mb_width;
	const int32_t iFcode = pParam->fixed_code;
	const int32_t iQuant = pParam->quant;

	const int32_t iWidth = pParam->width;
	const int32_t iHeight = pParam->height;
	const int32_t iEdgedWidth = pParam->edged_width; 

	const uint8_t * cur = pCur->y + x*8 + y*8*iEdgedWidth;

	int32_t iDiamondSize=1;
	
	int32_t min_dx;
	int32_t max_dx;
	int32_t min_dy;
	int32_t max_dy;
		
	VECTOR newMV;
	VECTOR backupMV;
	
	VECTOR pmv[4];
	int32_t psad[8];

	const	int32_t iSubBlock = ((y&1)<<1) + (x&1);
	
	MACROBLOCK * const pMB = pMBs + (x>>1) + (y>>1) * iWcount;

    	int32_t bPredEq;
    	int32_t iMinSAD,iSAD=9999;

	MainSearch8FuncPtr EPZSMainSearchPtr;

/* Get maximum range */
	get_range(&min_dx, &max_dx, &min_dy, &max_dy,
			x, y, 8, iWidth, iHeight, iFcode);

/* we work with abs. MVs, not relative to prediction, so get_range is called relative to 0,0 */

	if (!(MotionFlags & PMV_HALFPEL8 ))
	{ min_dx = EVEN(min_dx);
	  max_dx = EVEN(max_dx);
	  min_dy = EVEN(min_dy);
	  max_dy = EVEN(max_dy); 
	}		/* because we might use something like IF (dx>max_dx) THEN dx=max_dx; */
		
	bPredEq  = get_pmvdata(pMBs, x>>1, y>>1, iWcount, iSubBlock, pmv, psad);


/* Step 4: Calculate SAD around the Median prediction. 
        MinSAD=SAD 
        If Motion Vector equal to Previous frame motion vector 
		and MinSAD<PrevFrmSAD goto Step 10. 
        If SAD<=256 goto Step 10. 
*/

// Prepare for main loop 

	
	if (!(MotionFlags & PMV_HALFPEL8))
	{ 	
		currMV->x = EVEN(currMV->x);
		currMV->y = EVEN(currMV->y);
	}
	
	if (currMV->x > max_dx) 	
		currMV->x=max_dx;
	if (currMV->x < min_dx) 
		currMV->x=min_dx;
	if (currMV->y > max_dy) 
		currMV->y=max_dy;
	if (currMV->y < min_dy) 
		currMV->y=min_dy;

/***************** This is predictor SET A: only median prediction ******************/ 

	
	iMinSAD = sad8( cur, 
		get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 8, currMV, iEdgedWidth),
		iEdgedWidth);
  	iMinSAD += calc_delta_8(currMV->x-pmv[0].x, currMV->y-pmv[0].y, (uint8_t)iFcode) * iQuant;

	
// thresh1 is fixed to 256 
	if (iMinSAD < 256/4 )
		{
			if (MotionFlags & PMV_QUICKSTOP8) 
				goto EPZS8_Terminate_without_Refine;
			if (MotionFlags & PMV_EARLYSTOP8) 
				goto EPZS8_Terminate_with_Refine;
		}

/************** This is predictor SET B: (0,0), prev.frame MV, neighbours **************/ 

// previous frame MV 
	CHECK_MV8_CANDIDATE(pMB->mvs[0].x,pMB->mvs[0].y);

// MV=(0,0) is often a good choice

	CHECK_MV8_ZERO;

/* Terminate if MinSAD <= T_2 
   Terminate if MV[t] == MV[t-1] and MinSAD[t] <= MinSAD[t-1] 
*/

	if (iMinSAD < 512/4) 	/* T_2 == 512/4 hardcoded */
		{
			if (MotionFlags & PMV_QUICKSTOP8) 
				goto EPZS8_Terminate_without_Refine;
			if (MotionFlags & PMV_EARLYSTOP8) 
				goto EPZS8_Terminate_with_Refine;
		}

/************ (if Diamond Search)  **************/

	backupMV = *currMV; /* save best prediction, actually only for EXTSEARCH */

	if (!(MotionFlags & PMV_HALFPELDIAMOND8))
		iDiamondSize *= 2;
		
/* default: use best prediction as starting point for one call of PMVfast_MainSearch */

//	if (MotionFlags & PMV_USESQUARES8)
//		EPZSMainSearchPtr = Square8_MainSearch;
//	else
		EPZSMainSearchPtr = Diamond8_MainSearch;
		
	iSAD = (*EPZSMainSearchPtr)(pRef, pRefH, pRefV, pRefHV, cur,
		x, y, 
		currMV->x, currMV->y, iMinSAD, &newMV, 
		pmv, min_dx, max_dx, min_dy, max_dy, iEdgedWidth, 
		iDiamondSize, iFcode, iQuant, 00);

	
	if (iSAD < iMinSAD) 
	{
		*currMV = newMV;
		iMinSAD = iSAD;
	}

	if (MotionFlags & PMV_EXTSEARCH8)
	{
/* extended mode: search (up to) two more times: orignal prediction and (0,0) */

		if (!(MVequal(pmv[0],backupMV)) )
		{ 	
			iSAD = (*EPZSMainSearchPtr)(pRef, pRefH, pRefV, pRefHV, cur,
				x, y, 
			pmv[0].x, pmv[0].y, iMinSAD, &newMV, 
			pmv, min_dx, max_dx, min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode, iQuant, 0);
		
			if (iSAD < iMinSAD) 
			{
				*currMV = newMV;
				iMinSAD = iSAD;
			}
		}

		if ( (!(MVzero(pmv[0]))) && (!(MVzero(backupMV))) )
		{ 	
			iSAD = (*EPZSMainSearchPtr)(pRef, pRefH, pRefV, pRefHV, cur,
				x, y, 
			0, 0, iMinSAD, &newMV, 
			pmv, min_dx, max_dx, min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode, iQuant, 0);
		
			if (iSAD < iMinSAD) 
			{
				*currMV = newMV;
				iMinSAD = iSAD;
			}
		}
	}

/*************** 	Choose best MV found     **************/

EPZS8_Terminate_with_Refine:
	if (MotionFlags & PMV_HALFPELREFINE8) 		// perform final half-pel step 
		iMinSAD = Halfpel8_Refine( pRef, pRefH, pRefV, pRefHV, cur,
				x, y,
				currMV, iMinSAD, 
				pmv, min_dx, max_dx, min_dy, max_dy, iFcode, iQuant, iEdgedWidth);

EPZS8_Terminate_without_Refine:

	currPMV->x = currMV->x - pmv[0].x;
	currPMV->y = currMV->y - pmv[0].y;
	return iMinSAD;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -