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