热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

H.266/VVC代码学习:xMotionEstimation函数

xMotionEstimation函数是常规AMVP模式运动估计(MotionEstimation)的入口函数。运动估计就是从参考帧中在一定搜索范围中寻

xMotionEstimation函数是常规AMVP模式运动估计(Motion Estimation)的入口函数。运动估计就是从参考帧中在一定搜索范围中寻找与当前块最匹配的块(SAD最小)作为当前块的预测值,其中匹配块和当前块的相对位移称为运动矢量(Motion Vector)。

xMotionEstimation函数功能是以AMVP模式的最佳预测MV为起点,进行运动估计,在参考帧中搜索最佳MV。函数的基本流程如下:

  • 初始化IntTZSearchStruct,确定模板像素(原始像素)和参考像素(参考帧的重建像素)
  • 根据搜素类型,使用不同的搜索方法(全搜索或者TZ搜索方法)确定整像素精度MV
  • 根据cu的imv类型,对上一步得到的整像素MV进行细化
    • imv为IMV_OFF或者IMV_HPEL时,进行亚像素搜索,通过插值,搜索匹配,得到1/2像素精度和1/4像素精度的MV
    • 否则,对整像素和4像素精度的MV进行细化

整像素搜索的入口函数是xPatternSearch和xPatternSearchFast。xPatternSearch进行的是全局搜索,xPatternSearchFast进行的是快速算法,一般情况下使用的是xPatternSearchFast。

xPatternSearchFast将会使用TZ search,进行菱形搜素搜索,得到一个最优的整像素MV。

亚像素搜索的入口函数是xPatternSearchFracDIF,可以分为插值和搜索两个部分。插值分为1/2像素插值xExtDIFUpSamplingH和1/4像素插值xExtDIFUpSamplingQ,使用插值滤波器得到亚像素位置的参考块。xPatternRefinement是在以前一步得到的最优MV指向的像素为中心的3x3的像素块中,搜索计算RD cost,找最优匹配块,进一步计算最优MV。

其中IntTZSearchStruct在搜索过程中很重要,包括许多运动估计过程的关键数据:

typedef struct{SearchRange searchRange; //搜素范围const CPelBuf* pcPatternKey;//匹配模板像素,origconst Pel* piRefY;//搜索区域的像素,即参考帧像素int iRefStride;//搜索区域像素的strideint iBestX;int iBestY;//搜索范围内的最佳匹配点uint32_t uiBestRound;uint32_t uiBestDistance;//搜索点距起点的距离Distortion uiBestSad;//匹配失真uint8_t ucPointNr;//搜索点相对于起始点的位置的标号int subShiftMode;//搜索模式unsigned imvShift;bool useAltHpelIf;bool inCtuSearch;bool zeroMV;} IntTZSearchStruct;

代码及注释如下:

/*
* eRefPicList 表示当前参考帧是前向参考帧还是后向参考帧
* rcMvPred是当前参考帧通过AMVP候选列表中得到的最优的MVP,作为运动估计的起点
* iRefIdxPred表示当前参考帧在参考帧列表中的索引
* rcMV是运动搜索后的最佳MV
*/
void InterSearch::xMotionEstimation(PredictionUnit& pu, PelUnitBuf& origBuf, RefPicList eRefPicList, Mv& rcMvPred, int iRefIdxPred, Mv& rcMv, int& riMVPIdx, uint32_t& ruiBits, Distortion& ruiCost, const AMVPInfo& amvpInfo, bool bBi)
{if( pu.cu->cs->sps->getUseBcw() && pu.cu->BcwIdx !&#61; BCW_DEFAULT && !bBi && xReadBufferedUniMv(pu, eRefPicList, iRefIdxPred, rcMvPred, rcMv, ruiBits, ruiCost) ){return;}Mv cMvHalf, cMvQter; //1/2精度和1/4精度mvCHECK(eRefPicList >&#61; MAX_NUM_REF_LIST_ADAPT_SR || iRefIdxPred>&#61;int(MAX_IDX_ADAPT_SR), "Invalid reference picture list");m_iSearchRange &#61; m_aaiAdaptSR[eRefPicList][iRefIdxPred];int iSrchRng &#61; (bBi ? m_bipredSearchRange : m_iSearchRange); //搜索范围double fWeight &#61; 1.0;PelUnitBuf origBufTmp &#61; m_tmpStorageLCU.getBuf( UnitAreaRelative(*pu.cu, pu) );PelUnitBuf* pBuf &#61; &origBuf; //当前PU的原始像素if(bBi) // Bi-predictive ME 双向预测中的运动估计{// NOTE: Other buf contains predicted signal from another direction// 注&#xff1a;其他buf包含来自另一方向的预测信号PelUnitBuf otherBuf &#61; m_tmpPredStorage[1 - (int)eRefPicList].getBuf( UnitAreaRelative(*pu.cu, pu ));origBufTmp.copyFrom(origBuf); //用另外一个方向的像素对origBuf进行高频滤波origBufTmp.removeHighFreq( otherBuf, m_pcEncCfg->getClipForBiPredMeEnabled(), pu.cu->slice->clpRngs(),getBcwWeight( pu.cu->BcwIdx, eRefPicList ));pBuf &#61; &origBufTmp; //高频滤波后的origBuf&#xff0c;作为IntTZSearchStruct的标准模板像素fWeight &#61; xGetMEDistortionWeight( pu.cu->BcwIdx, eRefPicList );}m_cDistParam.isBiPred &#61; bBi; //是否为双向预测// Search key pattern initialization 搜索关键模式初始化CPelBuf tmpPattern &#61; pBuf->Y();CPelBuf* pcPatternKey &#61; &tmpPattern; // //原始像素作为我们要匹配的像素m_lumaClpRng &#61; pu.cs->slice->clpRng( COMPONENT_Y );bool wrap &#61; pu.cu->slice->getRefPic(eRefPicList, iRefIdxPred)->isWrapAroundEnabled( pu.cs->pps );// 参考帧的重建像素CPelBuf buf &#61; pu.cu->slice->getRefPic(eRefPicList, iRefIdxPred)->getRecoBuf(pu.blocks[COMPONENT_Y], wrap); IntTZSearchStruct cStruct; //初始化搜索数据cStruct.pcPatternKey &#61; pcPatternKey; // 标准模板像素cStruct.iRefStride &#61; buf.stride; //搜索区域的像素的stride cStruct.piRefY &#61; buf.buf; //搜索区域的像素buf起始指针点cStruct.imvShift &#61; pu.cu->imv &#61;&#61; IMV_HPEL ? 1 : (pu.cu->imv <<1); //MV精度cStruct.useAltHpelIf &#61; pu.cu->imv &#61;&#61; IMV_HPEL;cStruct.inCtuSearch &#61; false;cStruct.zeroMV &#61; false;{if (m_useCompositeRef && pu.cs->slice->getRefPic(eRefPicList, iRefIdxPred)->longTerm){cStruct.inCtuSearch &#61; true;}}auto blkCache &#61; dynamic_cast( m_modeCtrl );bool bQTBTMV &#61; false;bool bQTBTMV2 &#61; false;Mv cIntMv;if( !bBi ){bool bValid &#61; blkCache && blkCache->getMv( pu, eRefPicList, iRefIdxPred, cIntMv );if( bValid ){bQTBTMV2 &#61; true;cIntMv.changePrecision( MV_PRECISION_INT, MV_PRECISION_INTERNAL);}}Mv predQuarter &#61; rcMvPred;predQuarter.changePrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER);m_pcRdCost->setPredictor( predQuarter );m_pcRdCost->setCostScale(2);{setWpScalingDistParam(iRefIdxPred, eRefPicList, pu.cu->slice);}m_currRefPicList &#61; eRefPicList;m_currRefPicIndex &#61; iRefIdxPred;m_skipFracME &#61; false;// Do integer search 执行整数搜索if( ( m_motionEstimationSearchMethod &#61;&#61; MESEARCH_FULL ) || bBi || bQTBTMV ) //全搜索{cStruct.subShiftMode &#61; m_pcEncCfg->getFastInterSearchMode() &#61;&#61; FASTINTERSEARCH_MODE1 || m_pcEncCfg->getFastInterSearchMode() &#61;&#61; FASTINTERSEARCH_MODE3 ? 2 : 0;m_pcRdCost->setDistParam(m_cDistParam, *cStruct.pcPatternKey, cStruct.piRefY, cStruct.iRefStride, m_lumaClpRng.bd, COMPONENT_Y, cStruct.subShiftMode);Mv bestInitMv &#61; (bBi ? rcMv : rcMvPred); //初始MV&#xff0c;ME搜索起点Mv cTmpMv &#61; bestInitMv;clipMv( cTmpMv, pu.cu->lumaPos(), pu.cu->lumaSize(), *pu.cs->sps, *pu.cs->pps );cTmpMv.changePrecision(MV_PRECISION_INTERNAL, MV_PRECISION_INT);m_cDistParam.cur.buf &#61; cStruct.piRefY &#43; (cTmpMv.ver * cStruct.iRefStride) &#43; cTmpMv.hor; //在搜索区域移动到搜索起点Distortion uiBestSad &#61; m_cDistParam.distFunc(m_cDistParam);uiBestSad &#43;&#61; m_pcRdCost->getCostOfVectorWithPredictor(cTmpMv.hor, cTmpMv.ver, cStruct.imvShift);for (int i &#61; 0; i uniMvs[eRefPicList][iRefIdxPred] &#61;&#61; prevMvInfo->uniMvs[eRefPicList][iRefIdxPred]){break;}}if (j uniMvs[eRefPicList][iRefIdxPred];clipMv( cTmpMv, pu.cu->lumaPos(), pu.cu->lumaSize(), *pu.cs->sps, *pu.cs->pps );cTmpMv.changePrecision(MV_PRECISION_INTERNAL, MV_PRECISION_INT);m_cDistParam.cur.buf &#61; cStruct.piRefY &#43; (cTmpMv.ver * cStruct.iRefStride) &#43; cTmpMv.hor;Distortion uiSad &#61; m_cDistParam.distFunc(m_cDistParam);uiSad &#43;&#61; m_pcRdCost->getCostOfVectorWithPredictor(cTmpMv.hor, cTmpMv.ver, cStruct.imvShift);if (uiSad uniMvs[eRefPicList][iRefIdxPred];m_cDistParam.maximumDistortionForEarlyExit &#61; uiSad;}}if( !bQTBTMV ){xSetSearchRange(pu, bestInitMv, iSrchRng, cStruct.searchRange, cStruct); //设置搜索范围}xPatternSearch( cStruct, rcMv, ruiCost); //模式搜索&#xff0c;在搜索范围内寻找最佳MV}else if( bQTBTMV2 ){rcMv &#61; cIntMv;cStruct.subShiftMode &#61; ( !m_pcEncCfg->getRestrictMESampling() && m_pcEncCfg->getMotionEstimationSearchMethod() &#61;&#61; MESEARCH_SELECTIVE ) ? 1 :( m_pcEncCfg->getFastInterSearchMode() &#61;&#61; FASTINTERSEARCH_MODE1 || m_pcEncCfg->getFastInterSearchMode() &#61;&#61; FASTINTERSEARCH_MODE3 ) ? 2 : 0;xTZSearch(pu, eRefPicList, iRefIdxPred, cStruct, rcMv, ruiCost, NULL, false, true); //TZ搜索}else{//一般整数mv的ME就在这里//搜索模式不同&#xff0c;subShiftMode不同&#xff0c;MESEARCH_SELECTIVE选择搜索可减少复杂性&#xff0c;通过亚采样像素匹配搜索cStruct.subShiftMode &#61; ( !m_pcEncCfg->getRestrictMESampling() && m_pcEncCfg->getMotionEstimationSearchMethod() &#61;&#61; MESEARCH_SELECTIVE ) ? 1 :( m_pcEncCfg->getFastInterSearchMode() &#61;&#61; FASTINTERSEARCH_MODE1 || m_pcEncCfg->getFastInterSearchMode() &#61;&#61; FASTINTERSEARCH_MODE3 ) ? 2 : 0;rcMv &#61; rcMvPred;const Mv *pIntegerMv2Nx2NPred &#61; 0;//快速搜索匹配&#xff0c;以AMVP最优的预测MV为起点&#xff0c;得到整数mvxPatternSearchFast(pu, eRefPicList, iRefIdxPred, cStruct, rcMv, ruiCost, pIntegerMv2Nx2NPred);if( blkCache ){blkCache->setMv( pu.cs->area, eRefPicList, iRefIdxPred, rcMv );}else{m_integerMv2Nx2N[eRefPicList][iRefIdxPred] &#61; rcMv;}}DTRACE( g_trace_ctx, D_ME, "%d %d %d :MECostFPel: %d,%d,%dx%d, %d", DTRACE_GET_COUNTER( g_trace_ctx, D_ME ), pu.cu->slice->getPOC(), 0, ( int ) eRefPicList, ( int ) bBi, pu.Y().x, pu.Y().y, pu.Y().width, pu.Y().height, ruiCost );// sub-pel refinement for sub-pel resolution 用于亚像素分辨率的亚像素细化if ( pu.cu->imv &#61;&#61; 0 || pu.cu->imv &#61;&#61; IMV_HPEL ){if( m_pcEncCfg->getMCTSEncConstraint() ){Area curTileAreaSubPelRestricted &#61; pu.cs->picture->mctsInfo.getTileAreaSubPelRestricted( pu );// Area adjustment, because subpel refinement is going to (x-1;y-1) directioncurTileAreaSubPelRestricted.x &#43;&#61; 1;curTileAreaSubPelRestricted.y &#43;&#61; 1;curTileAreaSubPelRestricted.width -&#61; 1;curTileAreaSubPelRestricted.height -&#61; 1;if( ! MCTSHelper::checkMvIsNotInRestrictedArea( pu, rcMv, curTileAreaSubPelRestricted, MV_PRECISION_INT ) ){MCTSHelper::clipMvToArea( rcMv, pu.Y(), curTileAreaSubPelRestricted, *pu.cs->sps, 0 );}}// 亚像素搜索。插值&#xff0c;搜索匹配&#xff0c;基于整数mv得到半像素和1/4像素mvxPatternSearchFracDIF( pu, eRefPicList, iRefIdxPred, cStruct, rcMv, cMvHalf, cMvQter, ruiCost );m_pcRdCost->setCostScale( 0 );rcMv <<&#61; 2;rcMv &#43;&#61; ( cMvHalf <<&#61; 1 );rcMv &#43;&#61; cMvQter; //最终得到1/4像素精度的mvuint32_t uiMvBits &#61; m_pcRdCost->getBitsOfVectorWithPredictor( rcMv.getHor(), rcMv.getVer(), cStruct.imvShift );ruiBits &#43;&#61; uiMvBits;ruiCost &#61; ( Distortion ) ( floor( fWeight * ( ( double ) ruiCost - ( double ) m_pcRdCost->getCost( uiMvBits ) ) ) &#43; ( double ) m_pcRdCost->getCost( ruiBits ) );rcMv.changePrecision(MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL);}else // integer refinement for integer-pel and 4-pel resolution 整数像素和4像素分辨率的整数细化{rcMv.changePrecision(MV_PRECISION_INT, MV_PRECISION_INTERNAL);xPatternSearchIntRefine( pu, cStruct, rcMv, rcMvPred, riMVPIdx, ruiBits, ruiCost, amvpInfo, fWeight);}DTRACE(g_trace_ctx, D_ME, " MECost: %6d (%d) MV:%d,%d\n", (int)eRefPicList, (int)bBi, ruiCost, ruiBits, rcMv.getHor() <<2, rcMv.getVer() <<2);
}


推荐阅读
  • 1、概念共享内存:共享内存是进程间通信中最简单的方式之一。共享内存允许两个或更多进程访问同一块内存,就如同malloc()函数向不同进程返回了指向同一个 ... [详细]
  • 一、如果使用默认的1521端口,让实例自动注册到该监听上,那么local_listener无需设置,listener.ora文件按照正常方 ... [详细]
  • http://segmentfault.com/a/1190000000440293?page=1#c-1190000000440293-1050000000449039这是博主原帖 ... [详细]
  • 一、域名解析记录说明记录类型A:用来指定域名的IPv4地址(如:8.8.8.8),如果需要将域名指向一个IP ... [详细]
  • PNG在IE6下透明问题的解决办法
    2019独角兽企业重金招聘Python工程师标准做Web开发的朋友一定都知道PNG是一个相当不错的图片格式,但是这个好的格式却在IE6时代造成了麻烦࿰ ... [详细]
  • IPVlan 详解
    文章目录简介Ipvlan2同节点Ns互通Ns内与宿主机通信第三种方法Ns到节点外部结论Ipvlan31.同节点Ns互通Ns内与宿主机通信Ns内到外部网络总结源码分析ipvlan收包 ... [详细]
  • 接上文http:blog.itpub.net29254281viewspace-1318239领导让开发同学鼓捣一个可配置化的后台.又回到了原来的问题如果要灵活,很多参数要 ... [详细]
  • TLB 缓存延迟刷新漏洞 CVE201818281 解析 ... [详细]
  • 如何实现Percona Mysql Galera多读写集群的部署
    本篇文章给大家主要讲的是关于如何实现PerconaMysqlGalera多读写集群的部署的内容,感兴趣的话就一起来看看这篇文章吧,相信看完如何实现PerconaMysq ... [详细]
  • 为什么需要有应用层缓冲区?muduo网络库使用IO复用,并且文件描述符使用非阻塞模式,如果使用阻塞模式那么read、write就会阻塞在 ... [详细]
  • Logistic回归主要针对输入的数据是多个,输出则是有限的数值型,多为2个分类。涉及到以下方面:1.输出yw0+w1*x1+w2*x2+..(x1,x2,是样本的 ... [详细]
  • 1、背景-在项目的实施过程中,由于有dev环境和pro环境,这时会有两个redis集群,但是部分数据从甲方的三方数据库中获取存入生产环境的redis集群中,为了方便测试和数据校验, ... [详细]
  • 大数据学习环境安装关于防火墙​centos7使用的是firewalld,centos之前使用的是iptablesCentOS7关闭防火墙查看防火墙状态sudosy ... [详细]
  • JavaScript语言自身只有字符串数据类型,没有二进制数据类型。但在处理像TCP流或文件流时,必须使用到二进制数据。因此在Node.js中&#x ... [详细]
  • 问题描述查看matplotlib版本信息的方法总结问题描述在使用matplotlib画violinplot这个图形的时候报错了。出现了下面的错误提示:Attrib ... [详细]
author-avatar
Cindere丷lla_茹满
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有