HM编码器代码阅读(15)——运动估计ME

入口函数: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算法以及具体的搜索步骤,以后再讲

你可能感兴趣的:(C++,编码,h.265,HEVC)