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

📄 motion_est.c

📁 网络MPEG4IP流媒体开发源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
/************************************************************************** * *  Modifications: * *  02.04.2002 add EPZS(^2) as ME algorithm, use PMV_USESQUARES to choose between  *             EPZS and EPZS^2 *  08.02.2002 split up PMVfast into three routines: PMVFast, PMVFast_MainLoop *             PMVFast_Refine to support multiple searches with different start points *  07.01.2002 uv-block-based interpolation *  06.01.2002 INTER/INTRA-decision is now done before any SEARCH8 (speedup) *             changed INTER_BIAS to 150 (as suggested by suxen_drol) *             removed halfpel refinement step in PMVfastSearch8 + quality=5 *             added new quality mode = 6 which performs halfpel refinement *             filesize difference between quality 5 and 6 is smaller than 1% *             (Isibaar) *  31.12.2001 PMVfastSearch16 and PMVfastSearch8 (gruel) *  30.12.2001 get_range/MotionSearchX simplified; blue/green bug fix *  22.12.2001 commented best_point==99 check *  19.12.2001 modified get_range (purple bug fix) *  15.12.2001 moved pmv displacement from mbprediction *  02.12.2001 motion estimation/compensation split (Isibaar) *  16.11.2001 rewrote/tweaked search algorithms; pross@cs.rmit.edu.au *  10.11.2001 support for sad16/sad8 functions *  28.08.2001 reactivated MODE_INTER4V for EXT_MODE *  24.08.2001 removed MODE_INTER4V_Q, disabled MODE_INTER4V for EXT_MODE *  22.08.2001 added MODE_INTER4V_Q			 *  20.08.2001 added pragma to get rid of internal compiler error with VC6 *             idea by Cyril. Thanks. * *  Michael Militzer <isibaar@videocoding.de> * **************************************************************************/#include <assert.h>#include <stdio.h>#include <stdlib.h>#include "../encoder.h"#include "../utils/mbfunctions.h"#include "../prediction/mbprediction.h"#include "../global.h"#include "../utils/timer.h"#include "sad.h"// very large value#define MV_MAX_ERROR	(4096 * 256)// stop search if sdelta < THRESHOLD#define MV16_THRESHOLD	192#define MV8_THRESHOLD	56/* sad16(0,0) bias; mpeg4 spec suggests nb/2+1 *//* nb  = vop pixels * 2^(bpp-8) */#define MV16_00_BIAS	(128+1)/* INTER bias for INTER/INTRA decision; mpeg4 spec suggests 2*nb */#define INTER_BIAS	512/* Parameters which control inter/inter4v decision */#define IMV16X16			5/* vector map (vlc delta size) smoother parameters */#define NEIGH_TEND_16X16	2#define NEIGH_TEND_8X8		2// fast ((A)/2)*2#define EVEN(A)		(((A)<0?(A)+1:(A)) & ~1)#ifndef MIN#define MIN(X, Y) ((X)<(Y)?(X):(Y))#endif#ifndef MAX#define MAX(X, Y) ((X)>(Y)?(X):(Y))#endif#define ABS(X)    (((X)>0)?(X):-(X))#define SIGN(X)   (((X)>0)?1:-1)int32_t PMVfastSearch16(					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);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);int32_t PMVfastSearch8(					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);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);typedef int32_t (MainSearch16Func)(	const uint8_t * const pRef,	const uint8_t * const pRefH,	const uint8_t * const pRefV,	const uint8_t * const pRefHV,	const uint8_t * const cur,	const int x, const int y,	int32_t startx, int32_t starty,		int32_t iMinSAD,	VECTOR * const currMV,	const VECTOR * const pmv,	const int32_t min_dx, const int32_t max_dx, 	const int32_t min_dy, const int32_t max_dy,	const int32_t iEdgedWidth, 	const int32_t iDiamondSize, 	const int32_t iFcode,	const int32_t iQuant,	int iFound);typedef MainSearch16Func* MainSearch16FuncPtr;typedef int32_t (MainSearch8Func)(	const uint8_t * const pRef,	const uint8_t * const pRefH,	const uint8_t * const pRefV,	const uint8_t * const pRefHV,	const uint8_t * const cur,	const int x, const int y,	int32_t startx, int32_t starty,		int32_t iMinSAD,	VECTOR * const currMV,	const VECTOR * const pmv,	const int32_t min_dx, const int32_t max_dx, 	const int32_t min_dy, const int32_t max_dy,	const int32_t iEdgedWidth, 	const int32_t iDiamondSize, 	const int32_t iFcode,	const int32_t iQuant,	int iFound);typedef MainSearch8Func* MainSearch8FuncPtr;// mv.length tablestatic const uint32_t mvtab[33] = {    1,  2,  3,  4,  6,  7,  7,  7,    9,  9,  9,  10, 10, 10, 10, 10,    10, 10, 10, 10, 10, 10, 10, 10,    10, 11, 11, 11, 11, 11, 11, 12, 12};static __inline uint32_t mv_bits(int32_t component, const uint32_t iFcode){    if (component == 0)		return 1;    if (component < 0)		component = -component;    if (iFcode == 1)    {		if (component > 32)		    component = 32;		return mvtab[component] + 1;    }    component += (1 << (iFcode - 1)) - 1;    component >>= (iFcode - 1);    if (component > 32)		component = 32;    return mvtab[component] + 1 + iFcode - 1;}static __inline uint32_t calc_delta_16(const int32_t dx, const int32_t dy, const uint32_t iFcode){	return NEIGH_TEND_16X16 * (mv_bits(dx, iFcode) + mv_bits(dy, iFcode));}static __inline uint32_t calc_delta_8(const int32_t dx, const int32_t dy, const uint32_t iFcode){    return NEIGH_TEND_8X8 * (mv_bits(dx, iFcode) + mv_bits(dy, iFcode));}/* calculate the min/max range (in halfpixels)	relative to the _MACROBLOCK_ position*/static void __inline get_range(	int32_t * const min_dx, int32_t * const max_dx,	int32_t * const min_dy, int32_t * const max_dy,	const uint32_t x, const uint32_t y, 	const uint32_t block_sz,					// block dimension, 8 or 16	const uint32_t width, const uint32_t height,	const uint32_t fcode){	const int search_range = 32 << (fcode - 1);	const int high = search_range - 1;	const int low = -search_range;	// convert full-pixel measurements to half pixel	const int hp_width = 2 * width;	const int hp_height = 2 * height;	const int hp_edge = 2 * block_sz;	const int hp_x = 2 * (x) * block_sz;		// we need _right end_ of block, not x-coordinate	const int hp_y = 2 * (y) * block_sz;		// same for _bottom end_	*max_dx = MIN(high,	hp_width - hp_x);	*max_dy = MIN(high,	hp_height - hp_y);	*min_dx = MAX(low,	-(hp_edge + hp_x));	*min_dy = MAX(low,	-(hp_edge + hp_y));}/* * getref: calculate reference image pointer  * the decision to use interpolation h/v/hv or the normal image is * based on dx & dy. */static __inline const uint8_t * get_ref(	const uint8_t * const refn,	const uint8_t * const refh,	const uint8_t * const refv,	const uint8_t * const refhv,	const uint32_t x, const uint32_t y,	const uint32_t block,					// block dimension, 8 or 16	const int32_t dx, const int32_t dy,	const uint32_t stride){	switch ( ((dx&1)<<1) + (dy&1) )		// ((dx%2)?2:0)+((dy%2)?1:0)	{	case 0  : return refn + (x*block+dx/2) + (y*block+dy/2)*stride;	case 1  : return refv + (x*block+dx/2) + (y*block+(dy-1)/2)*stride;	case 2  : return refh + (x*block+(dx-1)/2) + (y*block+dy/2)*stride;	default : 	case 3  : return refhv + (x*block+(dx-1)/2) + (y*block+(dy-1)/2)*stride;	}}/* This is somehow a copy of get_ref, but with MV instead of X,Y */static __inline const uint8_t * get_ref_mv(	const uint8_t * const refn,	const uint8_t * const refh,	const uint8_t * const refv,	const uint8_t * const refhv,	const uint32_t x, const uint32_t y,	const uint32_t block,			// block dimension, 8 or 16	const VECTOR* mv,	// measured in half-pel!	const uint32_t stride){	switch ( (((mv->x)&1)<<1) + ((mv->y)&1) )	{	case 0  : return refn + (x*block+(mv->x)/2) + (y*block+(mv->y)/2)*stride;    	case 1  : return refv + (x*block+(mv->x)/2) + (y*block+((mv->y)-1)/2)*stride;	case 2  : return refh + (x*block+((mv->x)-1)/2) + (y*block+(mv->y)/2)*stride;	default : 	case 3  : return refhv + (x*block+((mv->x)-1)/2) + (y*block+((mv->y)-1)/2)*stride;	}}#ifndef SEARCH16#define SEARCH16	PMVfastSearch16//#define SEARCH16	FullSearch16//#define SEARCH16	EPZSSearch16#endif#ifndef SEARCH8#define SEARCH8		PMVfastSearch8//#define SEARCH8	EPZSSearch8#endifbool MotionEstimation(	MACROBLOCK * const pMBs,	MBParam * const pParam,	const IMAGE * const pRef,	const IMAGE * const pRefH,	const IMAGE * const pRefV,	const IMAGE * const pRefHV,	IMAGE * const pCurrent, 	const uint32_t iLimit){	const uint32_t iWcount = pParam->mb_width;	const uint32_t iHcount = pParam->mb_height; 	uint32_t i, j, iIntra = 0;	VECTOR mv16;	VECTOR pmv16;	int32_t sad8 = 0;	int32_t sad16;	int32_t deviation;	if (sadInit)		(*sadInit)();			// note: i==horizontal, j==vertical	for (i = 0; i < iHcount; i++)		for (j = 0; j < iWcount; j++)		{			MACROBLOCK *pMB = &pMBs[j + i * iWcount];			sad16 = SEARCH16(pRef->y, pRefH->y, pRefV->y, pRefHV->y, pCurrent, 					 j, i, pParam->motion_flags,					 pParam, pMBs, &mv16, &pmv16); 			pMB->sad16=sad16;			/* decide: MODE_INTER or MODE_INTRA 			   if (dev_intra < sad_inter - 2 * nb) use_intra			*/			deviation = dev16(pCurrent->y + j*16 + i*16*pParam->edged_width, pParam->edged_width);				if (deviation < (sad16 - INTER_BIAS))			{				pMB->mode = MODE_INTRA;				pMB->mvs[0].x = pMB->mvs[1].x = pMB->mvs[2].x = pMB->mvs[3].x = 0;				pMB->mvs[0].y = pMB->mvs[1].y = pMB->mvs[2].y = pMB->mvs[3].y = 0;				iIntra++;				if(iIntra >= iLimit)						return 1;				continue;			}			if (pParam->global_flags & XVID_INTER4V)			{				pMB->sad8[0] = SEARCH8(pRef->y, pRefH->y, pRefV->y, pRefHV->y, pCurrent, 						       2 * j, 2 * i, mv16.x, mv16.y, pParam->motion_flags, 						       pParam, pMBs, &pMB->mvs[0], &pMB->pmvs[0]); 				pMB->sad8[1] = SEARCH8(pRef->y, pRefH->y, pRefV->y, pRefHV->y, pCurrent, 						       2 * j + 1, 2 * i, mv16.x, mv16.y, pParam->motion_flags,						       pParam, pMBs, &pMB->mvs[1], &pMB->pmvs[1]); 				pMB->sad8[2] = SEARCH8(pRef->y, pRefH->y, pRefV->y, pRefHV->y, pCurrent, 						       2 * j, 2 * i + 1, mv16.x, mv16.y, pParam->motion_flags,						       pParam, pMBs, &pMB->mvs[2], &pMB->pmvs[2]); 							pMB->sad8[3] = SEARCH8(pRef->y, pRefH->y, pRefV->y, pRefHV->y, pCurrent, 						       2 * j + 1, 2 * i + 1, mv16.x, mv16.y, pParam->motion_flags,						       pParam, pMBs, &pMB->mvs[3], &pMB->pmvs[3]); 				sad8 = pMB->sad8[0] + pMB->sad8[1] + pMB->sad8[2] + pMB->sad8[3];			}    			/* decide: MODE_INTER or MODE_INTER4V 			   mpeg4:   if (sad8 < sad16 - nb/2+1) use_inter4v			*/			if (pMB->dquant == NO_CHANGE) {				if (((pParam->global_flags & XVID_INTER4V)==0) || 				    (sad16 < (sad8 + (int32_t)(IMV16X16 * pParam->quant)))) { 								sad8 = sad16;					pMB->mode = MODE_INTER;					pMB->mvs[0].x = pMB->mvs[1].x = pMB->mvs[2].x = pMB->mvs[3].x = mv16.x;					pMB->mvs[0].y = pMB->mvs[1].y = pMB->mvs[2].y = pMB->mvs[3].y = mv16.y;					pMB->pmvs[0].x = pmv16.x;					pMB->pmvs[0].y = pmv16.y;				}				else					pMB->mode = MODE_INTER4V;			}			else 			{				sad8 = sad16;				pMB->mode = MODE_INTER;				pMB->mvs[0].x = pMB->mvs[1].x = pMB->mvs[2].x = pMB->mvs[3].x = mv16.x;				pMB->mvs[0].y = pMB->mvs[1].y = pMB->mvs[2].y = pMB->mvs[3].y = mv16.y;				pMB->pmvs[0].x = pmv16.x;				pMB->pmvs[0].y = pmv16.y;			}		}	return 0;}#define MVzero(A) ( ((A).x)==(0) && ((A).y)==(0) )#define MVequal(A,B) ( ((A).x)==((B).x) && ((A).y)==((B).y) )#define CHECK_MV16_ZERO {\  if ( (0 <= max_dx) && (0 >= min_dx) \    && (0 <= max_dy) && (0 >= min_dy) ) \  { \    iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, 0, 0 , iEdgedWidth), iEdgedWidth, MV_MAX_ERROR); \    iSAD += calc_delta_16(-pmv[0].x, -pmv[0].y, (uint8_t)iFcode) * iQuant;\    if (iSAD <= iQuant * 96)	\   	iSAD -= MV16_00_BIAS; \    if (iSAD < iMinSAD) \    {  iMinSAD=iSAD; currMV->x=0; currMV->y=0; }  }	\}#define NOCHECK_MV16_CANDIDATE(X,Y) { \    iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, X, Y, iEdgedWidth),iEdgedWidth, iMinSAD); \    iSAD += calc_delta_16((X) - pmv[0].x, (Y) - pmv[0].y, (uint8_t)iFcode) * iQuant;\    if (iSAD < iMinSAD) \    {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); } \}#define CHECK_MV16_CANDIDATE(X,Y) { \  if ( ((X) <= max_dx) && ((X) >= min_dx) \    && ((Y) <= max_dy) && ((Y) >= min_dy) ) \  { \    iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, X, Y, iEdgedWidth),iEdgedWidth, iMinSAD); \    iSAD += calc_delta_16((X) - pmv[0].x, (Y) - pmv[0].y, (uint8_t)iFcode) * iQuant;\    if (iSAD < iMinSAD) \    {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); } } \}#define CHECK_MV16_CANDIDATE_DIR(X,Y,D) { \  if ( ((X) <= max_dx) && ((X) >= min_dx) \    && ((Y) <= max_dy) && ((Y) >= min_dy) ) \  { \    iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, X, Y, iEdgedWidth),iEdgedWidth, iMinSAD); \    iSAD += calc_delta_16((X) - pmv[0].x, (Y) - pmv[0].y, (uint8_t)iFcode) * iQuant;\    if (iSAD < iMinSAD) \    {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iDirection=(D); } } \}#define CHECK_MV16_CANDIDATE_FOUND(X,Y,D) { \  if ( ((X) <= max_dx) && ((X) >= min_dx) \    && ((Y) <= max_dy) && ((Y) >= min_dy) ) \  { \    iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, X, Y, iEdgedWidth),iEdgedWidth, iMinSAD); \    iSAD += calc_delta_16((X) - pmv[0].x, (Y) - pmv[0].y, (uint8_t)iFcode) * iQuant;\    if (iSAD < iMinSAD) \    {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iDirection=(D); iFound=0; } } \}#define CHECK_MV8_ZERO {\  iSAD = sad8( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 8, 0, 0 , iEdgedWidth), iEdgedWidth); \  iSAD += calc_delta_8(-pmv[0].x, -pmv[0].y, (uint8_t)iFcode) * iQuant;\  if (iSAD < iMinSAD) \  { iMinSAD=iSAD; currMV->x=0; currMV->y=0; } \}

⌨️ 快捷键说明

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