📄 motion_est.c
字号:
{
currMV->y=min_dy;
}
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;
if ( (iMinSAD < 256 ) || ( (MVequal(*currMV,pMB->mvs[0])) && (iMinSAD < pMB->sad16) ) )
{
if (MotionFlags & PMV_QUICKSTOP16)
goto PMVfast16_Terminate_without_Refine;
if (MotionFlags & PMV_EARLYSTOP16)
goto PMVfast16_Terminate_with_Refine;
}
/*
Step 5: Calculate SAD for motion vectors taken from left block, top, top-right, and Previous frame block.
Also calculate (0,0) but do not subtract offset.
Let MinSAD be the smallest SAD up to this point.
If MV is (0,0) subtract offset. ******** WHAT'S THIS 'OFFSET' ??? ***********
*/
// (0,0) is always possible
CHECK_MV16_ZERO;
// previous frame MV is always possible
CHECK_MV16_CANDIDATE(pMB->mvs[0].x,pMB->mvs[0].y);
// 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);
}
}
/* Step 6: If MinSAD <= thresa goto Step 10.
If Motion Vector equal to Previous frame motion vector and MinSAD<PrevFrmSAD goto Step 10.
*/
if ( (iMinSAD <= threshA) || ( MVequal(*currMV,pMB->mvs[0]) && (iMinSAD < pMB->sad16) ) )
{
if (MotionFlags & PMV_QUICKSTOP16)
goto PMVfast16_Terminate_without_Refine;
if (MotionFlags & PMV_EARLYSTOP16)
goto PMVfast16_Terminate_with_Refine;
}
/************ (Diamond Search) **************/
/*
Step 7: Perform Diamond search, with either the small or large diamond.
If Found=2 only examine one Diamond pattern, and afterwards goto step 10
Step 8: If small diamond, iterate small diamond search pattern until motion vector lies in the center of the diamond.
If center then goto step 10.
Step 9: If large diamond, iterate large diamond search pattern until motion vector lies in the center.
Refine by using small diamond and goto step 10.
*/
backupMV = *currMV; /* save best prediction, actually only for EXTSEARCH */
/* default: use best prediction as starting point for one call of PMVfast_MainSearch */
iSAD = Diamond16_MainSearch(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, iFound);
if (iSAD < iMinSAD)
{
*currMV = newMV;
iMinSAD = iSAD;
}
if (MotionFlags & PMV_EXTSEARCH16)
{
/* extended: search (up to) two more times: orignal prediction and (0,0) */
if (!(MVequal(pmv[0],backupMV)) )
{ iSAD = Diamond16_MainSearch(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, iFound);
if (iSAD < iMinSAD)
{
*currMV = newMV;
iMinSAD = iSAD;
}
}
if ( (!(MVzero(pmv[0]))) && (!(MVzero(backupMV))) )
{ iSAD = Diamond16_MainSearch(pRef, pRefH, pRefV, pRefHV, cur,
x, y,
0, 0, iMinSAD, &newMV,
pmv, min_dx, max_dx, min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode, iQuant, iFound);
if (iSAD < iMinSAD)
{
*currMV = newMV;
iMinSAD = iSAD;
}
}
}
/*
Step 10: The motion vector is chosen according to the block corresponding to MinSAD.
*/
PMVfast16_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);
PMVfast16_Terminate_without_Refine:
currPMV->x = currMV->x - pmv[0].x;
currPMV->y = currMV->y - pmv[0].y;
return iMinSAD;
}
int32_t Diamond8_MainSearch(
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)
{
/* Do a diamond search around given starting point, return SAD of best */
int32_t iDirection=0;
int32_t iSAD;
VECTOR backupMV;
backupMV.x = startx;
backupMV.y = starty;
/* It's one search with full Diamond pattern, and only 3 of 4 for all following diamonds */
CHECK_MV8_CANDIDATE_DIR(backupMV.x-iDiamondSize,backupMV.y,1);
CHECK_MV8_CANDIDATE_DIR(backupMV.x+iDiamondSize,backupMV.y,2);
CHECK_MV8_CANDIDATE_DIR(backupMV.x,backupMV.y-iDiamondSize,3);
CHECK_MV8_CANDIDATE_DIR(backupMV.x,backupMV.y+iDiamondSize,4);
if (iDirection)
while (!iFound)
{
iFound = 1;
backupMV=*currMV; // since iDirection!=0, this is well defined!
if ( iDirection != 2)
CHECK_MV8_CANDIDATE_FOUND(backupMV.x-iDiamondSize,backupMV.y,1);
if ( iDirection != 1)
CHECK_MV8_CANDIDATE_FOUND(backupMV.x+iDiamondSize,backupMV.y,2);
if ( iDirection != 4)
CHECK_MV8_CANDIDATE_FOUND(backupMV.x,backupMV.y-iDiamondSize,3);
if ( iDirection != 3)
CHECK_MV8_CANDIDATE_FOUND(backupMV.x,backupMV.y+iDiamondSize,4);
}
else
{
currMV->x = startx;
currMV->y = starty;
}
return iMinSAD;
}
int32_t Halfpel8_Refine(
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,
VECTOR * const currMV,
int32_t iMinSAD,
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 iFcode,
const int32_t iQuant,
const int32_t iEdgedWidth)
{
/* Do a half-pel refinement (or rather a "smallest possible amount" refinement) */
int32_t iSAD;
VECTOR backupMV = *currMV;
CHECK_MV8_CANDIDATE(backupMV.x-1,backupMV.y-1);
CHECK_MV8_CANDIDATE(backupMV.x ,backupMV.y-1);
CHECK_MV8_CANDIDATE(backupMV.x+1,backupMV.y-1);
CHECK_MV8_CANDIDATE(backupMV.x-1,backupMV.y);
CHECK_MV8_CANDIDATE(backupMV.x+1,backupMV.y);
CHECK_MV8_CANDIDATE(backupMV.x-1,backupMV.y+1);
CHECK_MV8_CANDIDATE(backupMV.x ,backupMV.y+1);
CHECK_MV8_CANDIDATE(backupMV.x+1,backupMV.y+1);
return iMinSAD;
}
#define PMV_HALFPEL8 (PMV_HALFPELDIAMOND8|PMV_HALFPELREFINE8)
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)
{
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;
int32_t min_dx;
int32_t max_dx;
int32_t min_dy;
int32_t max_dy;
VECTOR pmv[4];
int32_t psad[4];
VECTOR newMV;
VECTOR backupMV;
MACROBLOCK * const pMB = pMBs + (x>>1) + (y>>1) * iWcount;
static int32_t threshA,threshB;
int32_t iFound,bPredEq;
int32_t iMinSAD,iSAD;
int32_t iSubBlock = ((y&1)<<1) + (x&1);
/* 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 range is relative to 0,0 */
if (!(MotionFlags & PMV_HALFPELDIAMOND8 ))
{ min_dx = EVEN(min_dx);
max_dx = EVEN(max_dx);
min_dy = EVEN(min_dy);
max_dy = EVEN(max_dy);
} /* because we might use IF (dx>max_dx) THEN dx=max_dx; */
bPredEq = get_pmvdata(pMBs, (x>>1), (y>>1), iWcount, iSubBlock, pmv, psad);
if ((x==0) && (y==0) )
{
threshA = 512/4;
threshB = 1024/4;
}
else
{
threshA = psad[0]/4; /* good estimate */
threshB = threshA+256/4;
if (threshA< 512/4) threshA = 512/4;
if (threshA>1024/4) threshA = 1024/4;
if (threshB>1792/4) threshB = 1792/4;
}
iFound=0;
/* Step 2: Calculate Distance= |MedianMVX| + |MedianMVY| where MedianMV is the motion
vector of the median.
If PredEq=1 and MVpredicted = Previous Frame MV, set Found=2
*/
if ((bPredEq) && (MVequal(pmv[0],pMB->mvs[iSubBlock]) ) )
iFound=2;
/* Step 3: If Distance>0 or thresb<1536 or PredEq=1 Select small Diamond Search.
Otherwise select large Diamond Search.
*/
if ( (pmv[0].x != 0) || (pmv[0].y != 0) || (threshB<1536/4) || (bPredEq) )
iDiamondSize=1; // 1 halfpel!
else
iDiamondSize=2; // 2 halfpel = 1 full pixel!
if (!(MotionFlags & PMV_HALFPELDIAMOND8) )
iDiamondSize*=2;
/* 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->x=start_x; /* start with mv16 */
currMV->y=start_y;
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;
if ( (iMinSAD < 256/4 ) || ( (MVequal(*currMV,pMB->mvs[iSubBlock])) && (iMinSAD < pMB->sad8[iSubBlock]) ) )
{
if (MotionFlags & PMV_QUICKSTOP16)
goto PMVfast8_Terminate_without_Refine;
if (MotionFlags & PMV_EARLYSTOP16)
goto PMVfast8_Terminate_with_Refine;
}
/*
Step 5: Calculate SAD for motion vectors taken from left block, top, top-right, and Previous frame block.
Also calculate (0,0) but do not subtract offset.
Let MinSAD be the smallest SAD up to this point.
If MV is (0,0) subtract offset. ******** WHAT'S THIS 'OFFSET' ??? ***********
*/
// the prediction might be even better than mv16
CHECK_MV8_CANDIDATE(pmv[0].x,pmv[0].y);
// (0,0) is always possible
CHECK_MV8_ZERO;
// previous frame MV is always possible
CHECK_MV8_CANDIDATE(pMB->mvs[iSubBlock].x,pMB->mvs[iSubBlock].y);
// left neighbour, if allowed
if (psad[1] != MV_MAX_ERROR)
{
if (!(MotionFlags & PMV_HALFPEL8 ))
{ pmv[1].x = EVEN(pmv[1].x);
pmv[1].y = EVEN(pmv[1].y);
}
CHECK_MV8_CANDIDATE(pmv[1].x,pmv[1].y);
}
// top neighbour, if allowed
if (psad[2] != MV_MAX_ERROR)
{
if (!(MotionFlags & PMV_HALFPEL8 ))
{ pmv[2].x = EVEN(pmv[2].x);
pmv[2].y = EVEN(pmv[2].y);
}
CHECK_MV8_CANDIDATE(pmv[2].x,pmv[2].y);
// top right neighbour, if allowed
if (psad[3] != MV_MAX_ERROR)
{
if (!(MotionFlags & PMV_HALFPEL8 ))
{ pmv[3].x = EVEN(pmv[3].x);
pmv[3].y = EVEN(pmv[3].y);
}
CHECK_MV8_CANDIDATE(pmv[3].x,pmv[3].y);
}
}
/* Step 6: If MinSAD <= thresa goto Step 10.
If Motion Vector equal to Previous frame motion vector and MinSAD<PrevFrmSAD goto Step 10.
*/
if ( (iMinSAD <= threshA) || ( MVequal(*currMV,pMB->mvs[iSubBlock]) && (iMinSAD < pMB->sad8[iSubBlock]) ) )
{
if (MotionFlags & PMV_QUICKSTOP16)
goto PMVfast8_Terminate_without_Refine;
if (MotionFlags & PMV_EARLYSTOP16)
goto PMVfast8_Terminate_with_Refine;
}
/************ (Diamond Search) **************/
/*
Step 7: Perform Diamond search, with either the small or large diamond.
If Found=2 only examine one Diamond pattern, and afterwards goto step 10
Step 8: If small diamond, iterate small diamond search pattern until motion vector lies in the center of the diamond.
If center then goto step 10.
Step 9: If large diamond, iterate large diamond search pattern until motion vector lies in the center.
Refine by using small diamond and goto step 10.
*/
backupMV = *currMV; /* save best prediction, actually only for EXTSEARCH */
/* default: use best prediction as starting point for one call of PMVfast_MainSearch */
iSAD = Diamond8_MainSearch(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, iFound);
if (iSAD < iMinSAD)
{
*currMV = newMV;
iMinSAD = iSAD;
}
if (MotionFlags & PMV_EXTSEARCH8)
{
/* extended: search (up to) two more times: orignal prediction and (0,0) */
if (!(MVequal(pmv[0],backupMV)) )
{ iSAD = Diamond16_MainSearch(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, iFound);
if (iSAD < iMinSAD)
{
*currMV = newMV;
iMinSAD = iSAD;
}
}
if ( (!(MVzero(pmv[0]))) && (!(MVzero(backupMV))) )
{ iSAD = Diamond16_MainSearch(pRef, pRefH, pRefV, pRefHV, cur,
x, y,
0, 0, iMinSAD, &newMV,
pmv, min_dx, max_dx, min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode, iQuant, iFound);
if (iSAD < iMinSAD)
{
*currMV = newMV;
iMinSAD = iSAD;
}
}
}
/* Step 10: The motion vector is chosen according to the block corresponding to MinSAD.
By performing an optional local half-pixel search, we can refine this result even further.
*/
PMVfast8_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);
PMVfast8_Terminate_without_Refine:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -