📄 motion_est.c
字号:
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 + -