上一次我们学习了运动估计中使用的插值滤波器函数,这次来看具体的分像素差值函数xPatternSearchFracDIF。
在运动估计中,首先进行整像素的搜索,确定一个最优MV,然后在进行分像素搜索,得到以1/4为单位的MV。其分像素搜索通过xPatternSearchFracDIF函数实现,代码如下,主要功能是对Y分量进行亚像素搜索。首先进行1/2像素插值,然后进行1/4像素插值,最终得到以1/4为单位的MV。
Void TEncSearch::xPatternSearchFracDIF(
Bool bIsLosslessCoded,
TComPattern* pcPatternKey,
Pel* piRefY,
Int iRefStride,
TComMv* pcMvInt,
TComMv& rcMvHalf,
TComMv& rcMvQter,
Distortion& ruiCost
)
{
// Reference pattern initialization (integer scale)
TComPattern cPatternRoi;
Int iOffset = pcMvInt->getHor() + pcMvInt->getVer() * iRefStride; //MV_Hor + MV_Ver * Block_width
cPatternRoi.initPattern(piRefY + iOffset,
pcPatternKey->getROIYWidth(),
pcPatternKey->getROIYHeight(),
iRefStride,
pcPatternKey->getBitDepthY());
// Half-pel refinement
xExtDIFUpSamplingH ( &cPatternRoi ); //1/2像素插值
rcMvHalf = *pcMvInt; rcMvHalf <<= 1; // for mv-cost
TComMv baseRefMv(0, 0);
ruiCost = xPatternRefinement( pcPatternKey, baseRefMv, 2, rcMvHalf, !bIsLosslessCoded ); //计算以1/2单位的MV的代价
m_pcRdCost->setCostScale( 0 );
xExtDIFUpSamplingQ ( &cPatternRoi, rcMvHalf ); //1/4像素插值
baseRefMv = rcMvHalf;
baseRefMv <<= 1;
rcMvQter = *pcMvInt; rcMvQter <<= 1; // for mv-cost
rcMvQter += rcMvHalf; rcMvQter <<= 1;
ruiCost = xPatternRefinement( pcPatternKey, baseRefMv, 1, rcMvQter, !bIsLosslessCoded ); //计算以1/4单位的MV的代价
}
xExtDIFUpSamplingH为1/2像素插值,得到以1/2为单位的MV。
Void TEncSearch::xExtDIFUpSamplingH( TComPattern* pattern )
{
Int width = pattern->getROIYWidth();
Int height = pattern->getROIYHeight();
Int srcStride = pattern->getPatternLStride();
Int intStride = m_filteredBlockTmp[0].getStride(COMPONENT_Y); //m_iWidth
Int dstStride = m_filteredBlock[0][0].getStride(COMPONENT_Y); //m_iWidth
Pel *intPtr;
Pel *dstPtr;
Int filterSize = NTAPS_LUMA; //8
Int halfFilterSize = (filterSize>>1); //4
Pel *srcPtr = pattern->getROIY() - halfFilterSize*srcStride - 1;
const ChromaFormat chFmt = m_filteredBlock[0][0].getChromaFormat(); //色度格式
m_if.filterHor(COMPONENT_Y, srcPtr, srcStride, m_filteredBlockTmp[0].getAddr(COMPONENT_Y), intStride, width+1, height+filterSize, 0, false, chFmt, pattern->getBitDepthY()); //水平整像素插值,结果存储在m_filteredBlockTmp[0]中
m_if.filterHor(COMPONENT_Y, srcPtr, srcStride, m_filteredBlockTmp[2].getAddr(COMPONENT_Y), intStride, width+1, height+filterSize, 2, false, chFmt, pattern->getBitDepthY()); //水平1/2像素插值,结果存储在m_filteredBlockTmp[2]中
intPtr = m_filteredBlockTmp[0].getAddr(COMPONENT_Y) + halfFilterSize * intStride + 1;
dstPtr = m_filteredBlock[0][0].getAddr(COMPONENT_Y);
m_if.filterVer(COMPONENT_Y, intPtr, intStride, dstPtr, dstStride, width+0, height+0, 0, false, true, chFmt, pattern->getBitDepthY()); //水平整像素插值后的Y做垂直方向整像素插值,结果存储在m_filteredBlock[0][0]中
intPtr = m_filteredBlockTmp[0].getAddr(COMPONENT_Y) + (halfFilterSize-1) * intStride + 1;
dstPtr = m_filteredBlock[2][0].getAddr(COMPONENT_Y);
m_if.filterVer(COMPONENT_Y, intPtr, intStride, dstPtr, dstStride, width+0, height+1, 2, false, true, chFmt, pattern->getBitDepthY()); //水平整像素插值后的Y做垂直方向1/2像素插值,结果存储在m_filteredBlock[2][0]中
intPtr = m_filteredBlockTmp[2].getAddr(COMPONENT_Y) + halfFilterSize * intStride;
dstPtr = m_filteredBlock[0][2].getAddr(COMPONENT_Y);
m_if.filterVer(COMPONENT_Y, intPtr, intStride, dstPtr, dstStride, width+1, height+0, 0, false, true, chFmt, pattern->getBitDepthY()); //水平1/2像素插值后的Y做垂直方向整像素插值,结果存储在m_filteredBlock[0][2]中
intPtr = m_filteredBlockTmp[2].getAddr(COMPONENT_Y) + (halfFilterSize-1) * intStride;
dstPtr = m_filteredBlock[2][2].getAddr(COMPONENT_Y);
m_if.filterVer(COMPONENT_Y, intPtr, intStride, dstPtr, dstStride, width+1, height+1, 2, false, true, chFmt, pattern->getBitDepthY()); //水平1/2像素插值后的Y做垂直方向1/2像素插值,结果存储在m_filteredBlock[2][2]中
}
xExtDIFUpSamplingQ为1/4像素插值,得到以1/4为单位的MV。
Void TEncSearch::xExtDIFUpSamplingQ( TComPattern* pattern, TComMv halfPelRef )
{
Int width = pattern->getROIYWidth();
Int height = pattern->getROIYHeight();
Int srcStride = pattern->getPatternLStride();
Pel *srcPtr;
Int intStride = m_filteredBlockTmp[0].getStride(COMPONENT_Y);
Int dstStride = m_filteredBlock[0][0].getStride(COMPONENT_Y);
Pel *intPtr;
Pel *dstPtr;
Int filterSize = NTAPS_LUMA; //8
Int halfFilterSize = (filterSize>>1); //4
Int extHeight = (halfPelRef.getVer() == 0) ? height + filterSize : height + filterSize-1;
const ChromaFormat chFmt = m_filteredBlock[0][0].getChromaFormat();
// Horizontal filter 1/4
srcPtr = pattern->getROIY() - halfFilterSize * srcStride - 1;
intPtr = m_filteredBlockTmp[1].getAddr(COMPONENT_Y); //将1/4位置像素存储在m_filteredBlockTmp[1]中
if (halfPelRef.getVer() > 0)
{
srcPtr += srcStride;
}
if (halfPelRef.getHor() >= 0)
{
srcPtr += 1;
}
m_if.filterHor(COMPONENT_Y, srcPtr, srcStride, intPtr, intStride, width, extHeight, 1, false, chFmt, pattern->getBitDepthY()); //水平1/4像素插值
// Horizontal filter 3/4
srcPtr = pattern->getROIY() - halfFilterSize*srcStride - 1;
intPtr = m_filteredBlockTmp[3].getAddr(COMPONENT_Y); //将3/4位置像素存储在m_filteredBlockTmp[3]中
if (halfPelRef.getVer() > 0)
{
srcPtr += srcStride;
}
if (halfPelRef.getHor() > 0)
{
srcPtr += 1;
}
m_if.filterHor(COMPONENT_Y, srcPtr, srcStride, intPtr, intStride, width, extHeight, 3, false, chFmt, pattern->getBitDepthY()); //水平3/4像素插值
// Generate @ 1,1
intPtr = m_filteredBlockTmp[1].getAddr(COMPONENT_Y) + (halfFilterSize-1) * intStride;
dstPtr = m_filteredBlock[1][1].getAddr(COMPONENT_Y);
if (halfPelRef.getVer() == 0)
{
intPtr += intStride;
}
m_if.filterVer(COMPONENT_Y, intPtr, intStride, dstPtr, dstStride, width, height, 1, false, true, chFmt, pattern->getBitDepthY()); //水平1/4像素插值后的Y分量做垂直1/4像素插值,结果存储在m_filteredBlock[1][1]中
// Generate @ 3,1
intPtr = m_filteredBlockTmp[1].getAddr(COMPONENT_Y) + (halfFilterSize-1) * intStride;
dstPtr = m_filteredBlock[3][1].getAddr(COMPONENT_Y);
m_if.filterVer(COMPONENT_Y, intPtr, intStride, dstPtr, dstStride, width, height, 3, false, true, chFmt, pattern->getBitDepthY()); //水平1/4像素插值后的Y分量做垂直3/4像素插值,结果存储在m_filteredBlock[3][1]中
if (halfPelRef.getVer() != 0)
{
// Generate @ 2,1
intPtr = m_filteredBlockTmp[1].getAddr(COMPONENT_Y) + (halfFilterSize-1) * intStride;
dstPtr = m_filteredBlock[2][1].getAddr(COMPONENT_Y);
if (halfPelRef.getVer() == 0)
{
intPtr += intStride;
}
m_if.filterVer(COMPONENT_Y, intPtr, intStride, dstPtr, dstStride, width, height, 2, false, true, chFmt, pattern->getBitDepthY()); //水平1/4像素插值后的Y分量做垂直1/2像素插值,结果存储在m_filteredBlock[2][1]中
// Generate @ 2,3
intPtr = m_filteredBlockTmp[3].getAddr(COMPONENT_Y) + (halfFilterSize-1) * intStride;
dstPtr = m_filteredBlock[2][3].getAddr(COMPONENT_Y);
if (halfPelRef.getVer() == 0)
{
intPtr += intStride;
}
m_if.filterVer(COMPONENT_Y, intPtr, intStride, dstPtr, dstStride, width, height, 2, false, true, chFmt, pattern->getBitDepthY()); //水平3/4像素插值后的Y分量做垂直1/2像素插值,结果存储在m_filteredBlock[2][3]中
}
else
{
// Generate @ 0,1
intPtr = m_filteredBlockTmp[1].getAddr(COMPONENT_Y) + halfFilterSize * intStride;
dstPtr = m_filteredBlock[0][1].getAddr(COMPONENT_Y);
m_if.filterVer(COMPONENT_Y, intPtr, intStride, dstPtr, dstStride, width, height, 0, false, true, chFmt, pattern->getBitDepthY()); //水平1/4像素插值后的Y分量做垂直整像素插值,结果存储在m_filteredBlock[0][1]中
// Generate @ 0,3
intPtr = m_filteredBlockTmp[3].getAddr(COMPONENT_Y) + halfFilterSize * intStride;
dstPtr = m_filteredBlock[0][3].getAddr(COMPONENT_Y);
m_if.filterVer(COMPONENT_Y, intPtr, intStride, dstPtr, dstStride, width, height, 0, false, true, chFmt, pattern->getBitDepthY()); //水平3/4像素插值后的Y分量做垂直整像素插值,结果存储在m_filteredBlock[0][3]中
}
if (halfPelRef.getHor() != 0)
{
// Generate @ 1,2
intPtr = m_filteredBlockTmp[2].getAddr(COMPONENT_Y) + (halfFilterSize-1) * intStride;
dstPtr = m_filteredBlock[1][2].getAddr(COMPONENT_Y);
if (halfPelRef.getHor() > 0)
{
intPtr += 1;
}
if (halfPelRef.getVer() >= 0)
{
intPtr += intStride;
}
m_if.filterVer(COMPONENT_Y, intPtr, intStride, dstPtr, dstStride, width, height, 1, false, true, chFmt, pattern->getBitDepthY()); //水平1/2像素插值后的Y分量做垂直1/4像素插值,结果存储在m_filteredBlock[1][2]中
// Generate @ 3,2
intPtr = m_filteredBlockTmp[2].getAddr(COMPONENT_Y) + (halfFilterSize-1) * intStride;
dstPtr = m_filteredBlock[3][2].getAddr(COMPONENT_Y);
if (halfPelRef.getHor() > 0)
{
intPtr += 1;
}
if (halfPelRef.getVer() > 0)
{
intPtr += intStride;
}
m_if.filterVer(COMPONENT_Y, intPtr, intStride, dstPtr, dstStride, width, height, 3, false, true, chFmt, pattern->getBitDepthY()); //水平1/2像素插值后的Y分量做垂直3/4像素插值,结果存储在m_filteredBlock[3][2]中
}
else
{
// Generate @ 1,0
intPtr = m_filteredBlockTmp[0].getAddr(COMPONENT_Y) + (halfFilterSize-1) * intStride + 1;
dstPtr = m_filteredBlock[1][0].getAddr(COMPONENT_Y);
if (halfPelRef.getVer() >= 0)
{
intPtr += intStride;
}
m_if.filterVer(COMPONENT_Y, intPtr, intStride, dstPtr, dstStride, width, height, 1, false, true, chFmt, pattern->getBitDepthY()); //水平整像素插值后的Y分量做垂直1/4像素插值,结果存储在m_filteredBlock[1][0]中
// Generate @ 3,0
intPtr = m_filteredBlockTmp[0].getAddr(COMPONENT_Y) + (halfFilterSize-1) * intStride + 1;
dstPtr = m_filteredBlock[3][0].getAddr(COMPONENT_Y);
if (halfPelRef.getVer() > 0)
{
intPtr += intStride;
}
m_if.filterVer(COMPONENT_Y, intPtr, intStride, dstPtr, dstStride, width, height, 3, false, true, chFmt, pattern->getBitDepthY()); //水平整像素插值后的Y分量做垂直3/4像素插值,结果存储在m_filteredBlock[3][0]中
}
// Generate @ 1,3
intPtr = m_filteredBlockTmp[3].getAddr(COMPONENT_Y) + (halfFilterSize-1) * intStride;
dstPtr = m_filteredBlock[1][3].getAddr(COMPONENT_Y);
if (halfPelRef.getVer() == 0)
{
intPtr += intStride;
}
m_if.filterVer(COMPONENT_Y, intPtr, intStride, dstPtr, dstStride, width, height, 1, false, true, chFmt, pattern->getBitDepthY()); //水平3/4像素插值后的Y分量做垂直1/4像素插值,结果存储在m_filteredBlock[1][3]中
// Generate @ 3,3
intPtr = m_filteredBlockTmp[3].getAddr(COMPONENT_Y) + (halfFilterSize-1) * intStride;
dstPtr = m_filteredBlock[3][3].getAddr(COMPONENT_Y);
m_if.filterVer(COMPONENT_Y, intPtr, intStride, dstPtr, dstStride, width, height, 3, false, true, chFmt, pattern->getBitDepthY()); //水平3/4像素插值后的Y分量做垂直3/4像素插值,结果存储在m_filteredBlock[3][3]中
}
xPatternRefinement用来计算失真,用来选择最优的MV精度。
Distortion TEncSearch::xPatternRefinement( TComPattern* pcPatternKey, //待搜索PU
TComMv baseRefMv, //1/2像素时为(0,0),1/4像素时为rcMvHalf
Int iFrac, TComMv& rcMvFrac, //1/2像素时为rcMvHalf,1/4像素时为rcMvQter
Bool bAllowUseOfHadamard
)
{
Distortion uiDist;
Distortion uiDistBest = std::numeric_limits ::max();
UInt uiDirecBest = 0;
Pel* piRefPos;
Int iRefStride = m_filteredBlock[0][0].getStride(COMPONENT_Y);
//初始化失真参数
m_pcRdCost->setDistParam( pcPatternKey, m_filteredBlock[0][0].getAddr(COMPONENT_Y), iRefStride, 1, m_cDistParam, m_pcEncCfg->getUseHADME() && bAllowUseOfHadamard );
const TComMv* pcMvRefine = (iFrac == 2 ? s_acMvRefineH : s_acMvRefineQ); //搜索邻域的偏移量
for (UInt i = 0; i < 9; i++)
{
TComMv cMvTest = pcMvRefine[i];
cMvTest += baseRefMv; //偏移后的MV
Int horVal = cMvTest.getHor() * iFrac;
Int verVal = cMvTest.getVer() * iFrac;
piRefPos = m_filteredBlock[ verVal & 3 ][ horVal & 3 ].getAddr(COMPONENT_Y); //为了都取正值
if ( horVal == 2 && ( verVal & 1 ) == 0 )
{
piRefPos += 1;
}
if ( ( horVal & 1 ) == 0 && verVal == 2 )
{
piRefPos += iRefStride;
}
cMvTest = pcMvRefine[i];
cMvTest += rcMvFrac;
setDistParamComp(COMPONENT_Y);
m_cDistParam.pCur = piRefPos;
m_cDistParam.bitDepth = pcPatternKey->getBitDepthY();
uiDist = m_cDistParam.DistFunc( &m_cDistParam ); //获取失真
uiDist += m_pcRdCost->getCost( cMvTest.getHor(), cMvTest.getVer() ); //加偏移之后的失真
if ( uiDist < uiDistBest )
{
uiDistBest = uiDist;
uiDirecBest = i; //最优的偏移的索引
}
}
rcMvFrac = pcMvRefine[uiDirecBest];
return uiDistBest;
}