入口函数:xMotionEstimation
基本思想:就是用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, UInt& ruiCost, Bool bBi )
{
UInt uiPartAddr;
Int iRoiWidth;
Int iRoiHeight;
TComMv cMvHalf, cMvQter;
TComMv cMvSrchRngLT;
TComMv cMvSrchRngRB;
TComYuv* pcYuv = pcYuvOrg;
// 搜索的范围
m_iSearchRange = m_aaiAdaptSR[eRefPicList][iRefIdxPred];
Int iSrchRng = ( bBi ? m_bipredSearchRange : m_iSearchRange );
// 取得搜索模式(其实是相邻像素的访问方式)
TComPattern* pcPatternKey = pcCU->getPattern ();
Double fWeight = 1.0;
pcCU->getPartIndexAndSize( iPartIdx, uiPartAddr, iRoiWidth, iRoiHeight );
// 是不是双向预测
if ( bBi )
{
TComYuv* pcYuvOther = &m_acYuvPred[1-(Int)eRefPicList];
pcYuv = &m_cYuvPredTemp;
pcYuvOrg->copyPartToPartYuv( pcYuv, uiPartAddr, iRoiWidth, iRoiHeight );
pcYuv->removeHighFreq( pcYuvOther, uiPartAddr, iRoiWidth, iRoiHeight );
fWeight = 0.5;
}
// Search key pattern initialization
pcPatternKey->initPattern( pcYuv->getLumaAddr( uiPartAddr ),
pcYuv->getCbAddr ( uiPartAddr ),
pcYuv->getCrAddr ( uiPartAddr ),
iRoiWidth,
iRoiHeight,
pcYuv->getStride(),
0, 0 );
// 参考帧的像素
Pel* piRefY = pcCU->getSlice()->getRefPic( eRefPicList, iRefIdxPred )->getPicYuvRec()->getLumaAddr( pcCU->getAddr(), pcCU->getZorderIdxInCU() + uiPartAddr );
Int iRefStride = pcCU->getSlice()->getRefPic( eRefPicList, iRefIdxPred )->getPicYuvRec()->getStride();
// 预测的MV
TComMv cMvPred = *pcMvPred;
// 设置运动估计的搜索范围
if ( bBi )
xSetSearchRange ( pcCU, rcMv , iSrchRng, cMvSrchRngLT, cMvSrchRngRB );
else
xSetSearchRange ( pcCU, cMvPred, iSrchRng, cMvSrchRngLT, cMvSrchRngRB );
// 取得率失真代价
m_pcRdCost->getMotionCost ( 1, 0 );
// 设置预测得到的MV
m_pcRdCost->setPredictor ( *pcMvPred );
m_pcRdCost->setCostScale ( 2 );
// 设置跟weighted prediction相关的参数
setWpScalingDistParam( pcCU, iRefIdxPred, eRefPicList );
// Do integer search
// 先进行整像素搜索,确定一个局部的最佳值
if ( !m_iFastSearch || bBi )
{
xPatternSearch ( pcPatternKey, piRefY, iRefStride, &cMvSrchRngLT, &cMvSrchRngRB, rcMv, ruiCost );
}
else
{
rcMv = *pcMvPred;
xPatternSearchFast ( pcCU, pcPatternKey, piRefY, iRefStride, &cMvSrchRngLT, &cMvSrchRngRB, rcMv, ruiCost );
}
m_pcRdCost->getMotionCost( 1, 0 );
m_pcRdCost->setCostScale ( 1 );
// 进行分像素搜索,以提高搜索的精度
xPatternSearchFracDIF( pcCU, pcPatternKey, piRefY, iRefStride, &rcMv, cMvHalf, cMvQter, ruiCost,bBi );
m_pcRdCost->setCostScale( 0 );
rcMv <<= 2; // 整像素
rcMv += (cMvHalf <<= 1); // 1/2像素
rcMv += cMvQter;// 1/4像素
UInt uiMvBits = m_pcRdCost->getBits( rcMv.getHor(), rcMv.getVer() );
ruiBits += uiMvBits;
ruiCost = (UInt)( floor( fWeight * ( (Double)ruiCost - (Double)m_pcRdCost->getCost( uiMvBits ) ) ) + (Double)m_pcRdCost->getCost( ruiBits ) );
}
其他的TZSerach算法以及具体的搜索步骤,以后再讲