HEVC代码学习7:xPatternSearchFracDIF函数

来源:互联网 发布:83式武警军服淘宝 编辑:程序博客网 时间:2024/06/03 09:24

上一次我们学习了运动估计中使用的插值滤波器函数,这次来看具体的分像素差值函数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<Distortion>::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;}
1 0
原创粉丝点击