基本思想:就是用TZSearch算法先进行整像素搜索,确定一个局部的最佳值,然后以这个最佳点为中心再进行精度更高的分像素搜索。
主要流程:
(1)首先计算搜索范围
(2)获取相邻块像素的访问方式(通过调用getPattern)
(3)计算当前CU(或者说PU)大小
(4)如果是B帧(使用双向预测),还要设置权重?
(5)访问方式的初始化
(6)得到参考帧
(7)根据预先获取的预测MV,设置搜索范围
(8)调用xPatternSearch进行整像素所搜,确定一个局部的最佳位置
(9)调用xPatternSearchFracDIF进行分像素搜索(1/2像素,1/4像素),提高搜索的精度
Void TEncSearch::xMotionEstimation( TComDataCU* pcCU, TComYuv* pcYuvOrg, Int iPartIdx, RefPicList eRefPicList, TComMv* pcMvPred, Int iRefIdxPred, TComMv& rcMv, UInt& ruiBits, Distortion& ruiCost, Bool bBi )
{
#if NH_MV
D_PRINT_INC_INDENT(g_traceModeCheck, "xMotionEstimation");
#endif
UInt uiPartAddr;
Int iRoiWidth;
Int iRoiHeight;
TComMv cMvHalf, cMvQter;
TComMv cMvSrchRngLT;
TComMv cMvSrchRngRB;
TComYuv* pcYuv = pcYuvOrg;
assert(eRefPicList < MAX_NUM_REF_LIST_ADAPT_SR && iRefIdxPred<Int(MAX_IDX_ADAPT_SR));
// 搜索的范围iSrchRng
m_iSearchRange = m_aaiAdaptSR[eRefPicList][iRefIdxPred];
Int iSrchRng = ( bBi ? m_bipredSearchRange : m_iSearchRange );
// 取得搜索模式(其实是相邻像素的访问方式)
TComPattern tmpPattern;
TComPattern* pcPatternKey = &tmpPattern;
Double fWeight = 1.0;
pcCU->getPartIndexAndSize( iPartIdx, uiPartAddr, iRoiWidth, iRoiHeight );
#if NH_3D_IC
Bool bICFlag = pcCU->getICFlag( uiPartAddr ) && ( pcCU->getSlice()->getViewIndex() != pcCU->getSlice()->getRefPic( eRefPicList, iRefIdxPred )->getViewIndex() );
pcPatternKey->setICFlag( bICFlag );
#endif
#if NH_3D_SDC_INTER
pcPatternKey->setSDCMRSADFlag( pcCU->getSlice()->getInterSdcFlag() );
#endif
if ( bBi ) // Bipredictive ME
{
TComYuv* pcYuvOther = &m_acYuvPred[1-(Int)eRefPicList];
pcYuv = &m_cYuvPredTemp;
pcYuvOrg->copyPartToPartYuv( pcYuv, uiPartAddr, iRoiWidth, iRoiHeight );
pcYuv->removeHighFreq( pcYuvOther, uiPartAddr, iRoiWidth, iRoiHeight, pcCU->getSlice()->getSPS()->getBitDepths().recon, m_pcEncCfg->getClipForBiPredMeEnabled() );
fWeight = 0.5;
}
m_cDistParam.bIsBiPred = bBi;
// Search key pattern initialization //!< 设置待搜索的PU的相关参数,首地址,宽度,高度,跨度等
pcPatternKey->initPattern( pcYuv->getAddr ( COMPONENT_Y, uiPartAddr ),
iRoiWidth,
iRoiHeight,
pcYuv->getStride(COMPONENT_Y),
pcCU->getSlice()->getSPS()->getBitDepth(CHANNEL_TYPE_LUMA) );
// 参考帧的像素
Pel* piRefY = pcCU->getSlice()->getRefPic( eRefPicList, iRefIdxPred )->getPicYuvRec()->getAddr( COMPONENT_Y, pcCU->getCtuRsAddr(), pcCU->getZorderIdxInCtu() + uiPartAddr );
Int iRefStride = pcCU->getSlice()->getRefPic( eRefPicList, iRefIdxPred )->getPicYuvRec()->getStride(COMPONENT_Y);
TComMv cMvPred = *pcMvPred;// 预测的MV
#if NH_MV
m_vertRestriction = m_pcEncCfg->getUseDisparitySearchRangeRestriction() && ( pcCU->getSlice()->getRefPic( eRefPicList, iRefIdxPred )->getPOC() == pcCU->getSlice()->getPOC() );
#endif
// 设置运动估计的搜索范围
if ( bBi )
{
xSetSearchRange ( pcCU, rcMv , iSrchRng, cMvSrchRngLT, cMvSrchRngRB );
}
else
{
xSetSearchRange ( pcCU, cMvPred, iSrchRng, cMvSrchRngLT, cMvSrchRngRB );
}
m_pcRdCost->selectMotionLambda( true, 0, pcCU->getCUTransquantBypass(uiPartAddr) );// Lambda
m_pcRdCost->setPredictor ( *pcMvPred );// 设置预测得到的MV
#if NH_3D_INTEGER_MV_DEPTH
if( pcCU->getSlice()->getIsDepth() )
{
m_pcRdCost->setCostScale ( 0 );
}
else
{
#endif
m_pcRdCost->setCostScale ( 2 );
#if NH_3D_INTEGER_MV_DEPTH
}
#endif
setWpScalingDistParam( pcCU, iRefIdxPred, eRefPicList );// 设置跟weighted prediction相关的参数
// Do integer search // 先进行整像素搜索,确定一个局部的最佳值
if ( (m_motionEstimationSearchMethod==MESEARCH_FULL) || bBi )
{
xPatternSearch ( pcPatternKey, piRefY, iRefStride, &cMvSrchRngLT, &cMvSrchRngRB, rcMv, ruiCost );//进行全局搜索
}
else
{
rcMv = *pcMvPred;
#if NH_MV_FIX_VERT_MV_REST
if ( m_vertRestriction )
{
if (rcMv.getVer() > cMvSrchRngRB.getVer()<<2)
{
rcMv.setVer(cMvSrchRngRB.getVer()<<2);
}
}
#endif
const TComMv *pIntegerMv2Nx2NPred=0;
if (pcCU->getPartitionSize(0) != SIZE_2Nx2N || pcCU->getDepth(0) != 0)
{
pIntegerMv2Nx2NPred = &(m_integerMv2Nx2N[eRefPicList][iRefIdxPred]);
}
xPatternSearchFast ( pcCU, pcPatternKey, piRefY, iRefStride, &cMvSrchRngLT, &cMvSrchRngRB, rcMv, ruiCost, pIntegerMv2Nx2NPred );
if (pcCU->getPartitionSize(0) == SIZE_2Nx2N)
{
m_integerMv2Nx2N[eRefPicList][iRefIdxPred] = rcMv;
}
}
m_pcRdCost->selectMotionLambda( true, 0, pcCU->getCUTransquantBypass(uiPartAddr) );
#if NH_3D_INTEGER_MV_DEPTH
if( ! pcCU->getSlice()->getIsDepth() )
{
#endif
m_pcRdCost->setCostScale ( 1 );
const Bool bIsLosslessCoded = pcCU->getCUTransquantBypass(uiPartAddr) != 0;
// 进行分像素搜索,以提高搜索的精度
xPatternSearchFracDIF( bIsLosslessCoded, pcPatternKey, piRefY, iRefStride, &rcMv, cMvHalf, cMvQter, ruiCost );
m_pcRdCost->setCostScale( 0 );
rcMv <<= 2;// 整像素
rcMv += (cMvHalf <<= 1);// 1/2像素
rcMv += cMvQter;// 1/4像素
#if NH_3D_INTEGER_MV_DEPTH
}
#endif
UInt uiMvBits = m_pcRdCost->getBitsOfVectorWithPredictor( rcMv.getHor(), rcMv.getVer() );
#if NH_3D_INTEGER_MV_DEPTH
if( pcCU->getSlice()->getIsDepth() )
{
ruiCost += m_pcRdCost->getCost( uiMvBits );
}
#endif
ruiBits += uiMvBits;
ruiCost = (Distortion)( floor( fWeight * ( (Double)ruiCost - (Double)m_pcRdCost->getCost( uiMvBits ) ) ) + (Double)m_pcRdCost->getCost( ruiBits ) );
#if NH_MV
D_PRINT_INDENT(g_traceRDCost, "ME Cost:" + n2s(ruiCost) );
D_DEC_INDENT ( g_traceModeCheck );
#endif
}