📄 motion_est.c
字号:
#define NOCHECK_MV8_CANDIDATE(X,Y) \
{ \
iSAD = sad8( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 8, (X), (Y), iEdgedWidth),iEdgedWidth); \
iSAD += calc_delta_8((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_MV8_CANDIDATE(X,Y) { \
if ( ((X) <= max_dx) && ((X) >= min_dx) \
&& ((Y) <= max_dy) && ((Y) >= min_dy) ) \
{ \
iSAD = sad8( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 8, (X), (Y), iEdgedWidth),iEdgedWidth); \
iSAD += calc_delta_8((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_MV8_CANDIDATE_DIR(X,Y,D) { \
if ( ((X) <= max_dx) && ((X) >= min_dx) \
&& ((Y) <= max_dy) && ((Y) >= min_dy) ) \
{ \
iSAD = sad8( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 8, (X), (Y), iEdgedWidth),iEdgedWidth); \
iSAD += calc_delta_8((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_MV8_CANDIDATE_FOUND(X,Y,D) { \
if ( ((X) <= max_dx) && ((X) >= min_dx) \
&& ((Y) <= max_dy) && ((Y) >= min_dy) ) \
{ \
iSAD = sad8( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 8, (X), (Y), iEdgedWidth),iEdgedWidth); \
iSAD += calc_delta_8((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; } } \
}
/* too slow and not fully functional at the moment */
/*
int32_t ZeroSearch16(
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,
MBParam * const pParam,
MACROBLOCK * const pMBs,
VECTOR * const currMV,
VECTOR * const currPMV)
{
const int32_t iEdgedWidth = pParam->edged_width;
const int32_t iQuant = pParam->quant;
const uint8_t * cur = pCur->y + x*16 + y*16*iEdgedWidth;
int32_t iSAD;
int32_t pred_x,pred_y;
get_pmv(pMBs, x, y, pParam->mb_width, 0, &pred_x, &pred_y);
iSAD = sad16( cur,
get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, 0,0, iEdgedWidth),
iEdgedWidth, MV_MAX_ERROR);
if (iSAD <= iQuant * 96)
iSAD -= MV16_00_BIAS;
currMV->x = 0;
currMV->y = 0;
currPMV->x = -pred_x;
currPMV->y = -pred_y;
return iSAD;
}
*/
int32_t Diamond16_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_MV16_CANDIDATE_DIR(backupMV.x-iDiamondSize,backupMV.y,1);
CHECK_MV16_CANDIDATE_DIR(backupMV.x+iDiamondSize,backupMV.y,2);
CHECK_MV16_CANDIDATE_DIR(backupMV.x,backupMV.y-iDiamondSize,3);
CHECK_MV16_CANDIDATE_DIR(backupMV.x,backupMV.y+iDiamondSize,4);
if (iDirection)
while (!iFound)
{
iFound = 1;
backupMV=*currMV;
if ( iDirection != 2)
CHECK_MV16_CANDIDATE_FOUND(backupMV.x-iDiamondSize,backupMV.y,1);
if ( iDirection != 1)
CHECK_MV16_CANDIDATE_FOUND(backupMV.x+iDiamondSize,backupMV.y,2);
if ( iDirection != 4)
CHECK_MV16_CANDIDATE_FOUND(backupMV.x,backupMV.y-iDiamondSize,3);
if ( iDirection != 3)
CHECK_MV16_CANDIDATE_FOUND(backupMV.x,backupMV.y+iDiamondSize,4);
}
else
{
currMV->x = startx;
currMV->y = starty;
}
return iMinSAD;
}
int32_t Square16_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 square 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 square pattern, and new parts for all following diamonds */
/* new direction are extra, so 1-4 is normal diamond
537
1*2
648
*/
CHECK_MV16_CANDIDATE_DIR(backupMV.x-iDiamondSize,backupMV.y,1);
CHECK_MV16_CANDIDATE_DIR(backupMV.x+iDiamondSize,backupMV.y,2);
CHECK_MV16_CANDIDATE_DIR(backupMV.x,backupMV.y-iDiamondSize,3);
CHECK_MV16_CANDIDATE_DIR(backupMV.x,backupMV.y+iDiamondSize,4);
CHECK_MV16_CANDIDATE_DIR(backupMV.x-iDiamondSize,backupMV.y-iDiamondSize,5);
CHECK_MV16_CANDIDATE_DIR(backupMV.x-iDiamondSize,backupMV.y+iDiamondSize,6);
CHECK_MV16_CANDIDATE_DIR(backupMV.x+iDiamondSize,backupMV.y-iDiamondSize,7);
CHECK_MV16_CANDIDATE_DIR(backupMV.x+iDiamondSize,backupMV.y+iDiamondSize,8);
if (iDirection)
while (!iFound)
{
iFound = 1;
backupMV=*currMV;
switch (iDirection)
{
case 1:
CHECK_MV16_CANDIDATE_FOUND(backupMV.x-iDiamondSize,backupMV.y,1);
CHECK_MV16_CANDIDATE_DIR(backupMV.x-iDiamondSize,backupMV.y-iDiamondSize,5);
CHECK_MV16_CANDIDATE_DIR(backupMV.x+iDiamondSize,backupMV.y-iDiamondSize,7);
break;
case 2:
CHECK_MV16_CANDIDATE_DIR(backupMV.x+iDiamondSize,backupMV.y,2);
CHECK_MV16_CANDIDATE_DIR(backupMV.x-iDiamondSize,backupMV.y+iDiamondSize,6);
CHECK_MV16_CANDIDATE_DIR(backupMV.x+iDiamondSize,backupMV.y+iDiamondSize,8);
break;
case 3:
CHECK_MV16_CANDIDATE_DIR(backupMV.x,backupMV.y+iDiamondSize,4);
CHECK_MV16_CANDIDATE_DIR(backupMV.x+iDiamondSize,backupMV.y-iDiamondSize,7);
CHECK_MV16_CANDIDATE_DIR(backupMV.x+iDiamondSize,backupMV.y+iDiamondSize,8);
break;
case 4:
CHECK_MV16_CANDIDATE_DIR(backupMV.x,backupMV.y-iDiamondSize,3);
CHECK_MV16_CANDIDATE_DIR(backupMV.x-iDiamondSize,backupMV.y-iDiamondSize,5);
CHECK_MV16_CANDIDATE_DIR(backupMV.x-iDiamondSize,backupMV.y+iDiamondSize,6);
break;
case 5:
CHECK_MV16_CANDIDATE_DIR(backupMV.x-iDiamondSize,backupMV.y,1);
CHECK_MV16_CANDIDATE_DIR(backupMV.x,backupMV.y-iDiamondSize,3);
CHECK_MV16_CANDIDATE_DIR(backupMV.x-iDiamondSize,backupMV.y-iDiamondSize,5);
CHECK_MV16_CANDIDATE_DIR(backupMV.x-iDiamondSize,backupMV.y+iDiamondSize,6);
CHECK_MV16_CANDIDATE_DIR(backupMV.x+iDiamondSize,backupMV.y-iDiamondSize,7);
break;
case 6:
CHECK_MV16_CANDIDATE_DIR(backupMV.x+iDiamondSize,backupMV.y,2);
CHECK_MV16_CANDIDATE_DIR(backupMV.x,backupMV.y-iDiamondSize,3);
CHECK_MV16_CANDIDATE_DIR(backupMV.x-iDiamondSize,backupMV.y-iDiamondSize,5);
CHECK_MV16_CANDIDATE_DIR(backupMV.x-iDiamondSize,backupMV.y+iDiamondSize,6);
CHECK_MV16_CANDIDATE_DIR(backupMV.x+iDiamondSize,backupMV.y+iDiamondSize,8);
break;
case 7:
CHECK_MV16_CANDIDATE_FOUND(backupMV.x-iDiamondSize,backupMV.y,1);
CHECK_MV16_CANDIDATE_DIR(backupMV.x,backupMV.y+iDiamondSize,4);
CHECK_MV16_CANDIDATE_DIR(backupMV.x-iDiamondSize,backupMV.y-iDiamondSize,5);
CHECK_MV16_CANDIDATE_DIR(backupMV.x+iDiamondSize,backupMV.y-iDiamondSize,7);
CHECK_MV16_CANDIDATE_DIR(backupMV.x+iDiamondSize,backupMV.y+iDiamondSize,8);
break;
case 8:
CHECK_MV16_CANDIDATE_DIR(backupMV.x+iDiamondSize,backupMV.y,2);
CHECK_MV16_CANDIDATE_DIR(backupMV.x,backupMV.y+iDiamondSize,4);
CHECK_MV16_CANDIDATE_DIR(backupMV.x-iDiamondSize,backupMV.y+iDiamondSize,6);
CHECK_MV16_CANDIDATE_DIR(backupMV.x+iDiamondSize,backupMV.y-iDiamondSize,7);
CHECK_MV16_CANDIDATE_DIR(backupMV.x+iDiamondSize,backupMV.y+iDiamondSize,8);
break;
default:
CHECK_MV16_CANDIDATE_DIR(backupMV.x-iDiamondSize,backupMV.y,1);
CHECK_MV16_CANDIDATE_DIR(backupMV.x+iDiamondSize,backupMV.y,2);
CHECK_MV16_CANDIDATE_DIR(backupMV.x,backupMV.y-iDiamondSize,3);
CHECK_MV16_CANDIDATE_DIR(backupMV.x,backupMV.y+iDiamondSize,4);
CHECK_MV16_CANDIDATE_DIR(backupMV.x-iDiamondSize,backupMV.y-iDiamondSize,5);
CHECK_MV16_CANDIDATE_DIR(backupMV.x-iDiamondSize,backupMV.y+iDiamondSize,6);
CHECK_MV16_CANDIDATE_DIR(backupMV.x+iDiamondSize,backupMV.y-iDiamondSize,7);
CHECK_MV16_CANDIDATE_DIR(backupMV.x+iDiamondSize,backupMV.y+iDiamondSize,8);
break;
}
}
else
{
currMV->x = startx;
currMV->y = starty;
}
return iMinSAD;
}
int32_t Full16_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)
{
int32_t iSAD;
int32_t dx,dy;
VECTOR backupMV;
backupMV.x = startx;
backupMV.y = starty;
for (dx = min_dx; dx<=max_dx; dx+=iDiamondSize)
for (dy = min_dy; dy<= max_dy; dy+=iDiamondSize)
NOCHECK_MV16_CANDIDATE(dx,dy);
return iMinSAD;
}
int32_t Full8_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)
{
int32_t iSAD;
int32_t dx,dy;
VECTOR backupMV;
backupMV.x = startx;
backupMV.y = starty;
for (dx = min_dx; dx<=max_dx; dx+=iDiamondSize)
for (dy = min_dy; dy<= max_dy; dy+=iDiamondSize)
NOCHECK_MV8_CANDIDATE(dx,dy);
return iMinSAD;
}
int32_t Halfpel16_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_MV16_CANDIDATE(backupMV.x-1,backupMV.y-1);
CHECK_MV16_CANDIDATE(backupMV.x ,backupMV.y-1);
CHECK_MV16_CANDIDATE(backupMV.x+1,backupMV.y-1);
CHECK_MV16_CANDIDATE(backupMV.x-1,backupMV.y);
CHECK_MV16_CANDIDATE(backupMV.x+1,backupMV.y);
CHECK_MV16_CANDIDATE(backupMV.x-1,backupMV.y+1);
CHECK_MV16_CANDIDATE(backupMV.x ,backupMV.y+1);
CHECK_MV16_CANDIDATE(backupMV.x+1,backupMV.y+1);
return iMinSAD;
}
#define PMV_HALFPEL16 (PMV_HALFPELDIAMOND16|PMV_HALFPELREFINE16)
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)
{
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*16 + y*16*iEdgedWidth;
int32_t iDiamondSize;
int32_t min_dx;
int32_t max_dx;
int32_t min_dy;
int32_t max_dy;
int32_t iFound;
VECTOR newMV;
VECTOR backupMV; /* just for PMVFAST */
VECTOR pmv[4];
int32_t psad[4];
MACROBLOCK * const pMB = pMBs + x + y * iWcount;
static int32_t threshA,threshB;
int32_t bPredEq;
int32_t iMinSAD,iSAD;
/* 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);
if ((x==0) && (y==0) )
{
threshA = 512;
threshB = 1024;
}
else
{
threshA = psad[0];
threshB = threshA+256;
if (threshA< 512) threshA = 512;
if (threshA>1024) threshA = 1024;
if (threshB>1792) threshB = 1792;
}
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[0]) ) )
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) || (bPredEq) )
iDiamondSize=1; // halfpel!
else
iDiamondSize=2; // halfpel!
if (!(MotionFlags & PMV_HALFPELDIAMOND16) )
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=pmv[0]; /* current best := prediction */
if (!(MotionFlags & PMV_HALFPEL16 ))
{ /* This should NOT be necessary! */
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)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -