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
- HEVC代码学习7:xPatternSearchFracDIF函数
- HEVC代码学习2:TAppEncTop::encode函数
- HEVC代码学习3:TEncTop::encode函数
- HEVC代码学习8:xMotionEstimation函数
- HEVC代码学习9:getInterMergeCandidates函数
- HEVC代码学习11:xCompressCU函数
- HEVC代码学习12:xCheckRDCostInter函数
- HEVC代码学习13:predInterSearch函数
- HEVC代码学习14:motionCompensation函数
- HEVC代码学习15:AMVP相关函数
- HEVC代码学习20:xPatternSearchFast函数
- HEVC代码学习21:xTZSearch函数
- HEVC代码学习22:xTZSearchHelp函数
- HEVC代码学习23:xTZ8PointDiamondSearch函数
- HEVC代码学习24:encodeResAndCalcRdInterCU函数
- HEVC代码学习25:xDecompressCU函数
- HEVC代码学习27:calcRdCost函数
- HEVC代码学习28:setLambda函数
- 线段树,点更新查找
- <操作系统:精髓与设计原理> 虚拟内存
- Android中查看当前Activity是否销毁
- jquery获取隐藏元素的宽度高度
- Git与Github基础使用技巧之--添加远程库
- HEVC代码学习7:xPatternSearchFracDIF函数
- android GMS认证之testGoogleDuoPreloaded
- Lab1
- Unity 使用自定义资源(.asset)配置数据
- 机器学习----(Machine Learning)&深度学习(Deep Learning)资料(Chapter 1)
- Unity中的序列化数据丢失
- Jpa onetomany或者manytoone
- TortoiseSVN文件夹及文件图标不显示解决方法
- 机器学习----(Machine Learning)&深度学习(Deep Learning)资料(Chapter 2)