📄 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 + -