📄 motion_est.c
字号:
{ const uint32_t iWcount = pParam->mb_width; 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; VECTOR startMV;/* const MACROBLOCK * const pMB = pMBs + (x>>1) + (y>>1) * iWcount; */ const MACROBLOCK *const prevMB = prevMBs + (x >> 1) + (y >> 1) * iWcount; int32_t threshA, threshB; int32_t iFound, bPredEq; int32_t iMinSAD, iSAD; int32_t iSubBlock = (y & 1) + (y & 1) + (x & 1); MainSearch8FuncPtr MainSearchPtr; /* Init variables */ startMV.x = start_x; startMV.y = start_y; /* Get maximum range */ get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 8, iWidth, iHeight, iFcode); 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_pmvdata2(pMBs, iWcount, 0, (x >> 1), (y >> 1), 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 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_USESQUARES8) MainSearchPtr = Square8_MainSearch; else if (MotionFlags & PMV_ADVANCEDDIAMOND8) MainSearchPtr = AdvDiamond8_MainSearch; else MainSearchPtr = Diamond8_MainSearch; *currMV = startMV; iMinSAD = sad8(cur, get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 8, currMV, iEdgedWidth), iEdgedWidth); iMinSAD += calc_delta_8(currMV->x - center_x, currMV->y - center_y, (uint8_t) iFcode, iQuant); if ((iMinSAD < 256 / 4) || ((MVequal(*currMV, prevMB->mvs[iSubBlock])) && ((int32_t) iMinSAD < prevMB->sad8[iSubBlock]))) { if (MotionFlags & PMV_QUICKSTOP16) goto PMVfast8_Terminate_without_Refine; if (MotionFlags & PMV_EARLYSTOP16) goto PMVfast8_Terminate_with_Refine; }/* Step 2 (lazy eval): 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], prevMB->mvs[iSubBlock]))) iFound = 2;/* Step 3 (lazy eval): If Distance>0 or thresb<1536 or PredEq=1 Select small Diamond Search. Otherwise select large Diamond Search. */ if ((!MVzero(pmv[0])) || (threshB < 1536 / 4) || (bPredEq)) iDiamondSize = 1; /* 1 halfpel! */ else iDiamondSize = 2; /* 2 halfpel = 1 full pixel! */ if (!(MotionFlags & PMV_HALFPELDIAMOND8)) iDiamondSize *= 2;/* 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. *//* the median prediction might be even better than mv16 */ if (!MVequal(pmv[0], startMV)) CHECK_MV8_CANDIDATE(center_x, center_y);/* (0,0) if needed */ if (!MVzero(pmv[0])) if (!MVzero(startMV)) CHECK_MV8_ZERO;/* previous frame MV if needed */ if (!MVzero(prevMB->mvs[iSubBlock])) if (!MVequal(prevMB->mvs[iSubBlock], startMV)) if (!MVequal(prevMB->mvs[iSubBlock], pmv[0])) CHECK_MV8_CANDIDATE(prevMB->mvs[iSubBlock].x, prevMB->mvs[iSubBlock].y); if ((iMinSAD <= threshA) || (MVequal(*currMV, prevMB->mvs[iSubBlock]) && ((int32_t) iMinSAD < prevMB->sad8[iSubBlock]))) { if (MotionFlags & PMV_QUICKSTOP16) goto PMVfast8_Terminate_without_Refine; if (MotionFlags & PMV_EARLYSTOP16) goto PMVfast8_Terminate_with_Refine; }/* left neighbour, if allowed and needed */ if (!MVzero(pmv[1])) if (!MVequal(pmv[1], startMV)) if (!MVequal(pmv[1], prevMB->mvs[iSubBlock])) if (!MVequal(pmv[1], pmv[0])) { 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 and needed */ if (!MVzero(pmv[2])) if (!MVequal(pmv[2], startMV)) if (!MVequal(pmv[2], prevMB->mvs[iSubBlock])) if (!MVequal(pmv[2], pmv[0])) if (!MVequal(pmv[2], pmv[1])) { 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 and needed */ if (!MVzero(pmv[3])) if (!MVequal(pmv[3], startMV)) if (!MVequal(pmv[3], prevMB->mvs[iSubBlock])) if (!MVequal(pmv[3], pmv[0])) if (!MVequal(pmv[3], pmv[1])) if (!MVequal(pmv[3], pmv[2])) { 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); } } if ((MVzero(*currMV)) && (!MVzero(pmv[0])) /* && (iMinSAD <= iQuant * 96) */ ) iMinSAD -= MV8_00_BIAS;/* 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, prevMB->mvs[iSubBlock]) && ((int32_t) iMinSAD < prevMB->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 = (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV->x, currMV->y, iMinSAD, &newMV, center_x, center_y, 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 = (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, pmv[0].x, pmv[0].y, iMinSAD, &newMV, center_x, center_y, 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 = (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, 0, 0, iMinSAD, &newMV, center_x, center_y, 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, center_x, center_y, min_dx, max_dx, min_dy, max_dy, iFcode, iQuant, iEdgedWidth); PMVfast8_Terminate_without_Refine: currPMV->x = currMV->x - center_x; currPMV->y = currMV->y - center_y; return iMinSAD;}int32_tEPZSSearch16(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, const int start_y, const int center_x, const int center_y, const uint32_t MotionFlags, const uint32_t iQuant, const uint32_t iFcode, const MBParam * const pParam, const MACROBLOCK * const pMBs, const MACROBLOCK * const prevMBs, VECTOR * const currMV, VECTOR * const currPMV){ const uint32_t iWcount = pParam->mb_width; const uint32_t iHcount = pParam->mb_height; 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;/* const MACROBLOCK * const pMB = pMBs + x + y * iWcount; */ const MACROBLOCK *const prevMB = prevMBs + x + y * iWcount; MACROBLOCK *oldMB = NULL; int32_t thresh2; int32_t bPredEq; int32_t iMinSAD, iSAD = 9999; MainSearch16FuncPtr MainSearchPtr; if (oldMBs == NULL) { oldMBs = (MACROBLOCK *) calloc(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); 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_pmvdata2(pMBs, iWcount, 0, x, y, 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->x = start_x; currMV->y = start_y; 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 - center_x, currMV->y - center_y, (uint8_t) iFcode, iQuant);/* thresh1 is fixed to 256 */ if ((iMinSAD < 256) || ((MVequal(*currMV, prevMB->mvs[0])) && ((int32_t) iMinSAD < prevMB->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(prevMB->mvs[0].x, prevMB->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 neigh
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -