推荐阅读
http://blog.csdn.net/nb_vol_1/article/details/51163625
http://blog.csdn.net/guoyaoyao1990/article/details/35339717

今天来学习HM中merge部分的代码,其入口函数为xCheckRDCostMerge2Nx2N。

这里需要注意的是,merge是借用空间邻近块的MV作为当前块的MV直接进行预测,不再进行运动估计。也就是说,对于merge是没有MVP的,直接得到的即为MV,不存在MVD。因此在merge模式下是没有运动估计的。

而这个被merge选到的MV由已编码的空间邻近块得到,不需要再进行传输了,只需要传输最优MV的候选列表索引即可。

xCheckRDCostMerge2Nx2N功能即为构造Merge候选列表,遍历列表进行运动补偿,通过比较RD cost,最终得到最优MV和最优模式信息。

工作流程如下:
1. 调用getInterMergeCandidates构造候选列表。
2. 遍历候选列表:
(1) 调用motionCompensation进行运动补偿。
(2) 调用encodeResAndCalcRdInterCU计算残差和RD cost
并进行编码。
(3) 比较选出最优MV和最优模式信息。

其中使用到的重要函数为getInterMergeCandidates(http://blog.csdn.net/lin453701006/article/details/78573347),motionCompensation(http://blog.csdn.net/lin453701006/article/details/72677630),encodeResAndCalcRdInterCU(http://blog.csdn.net/lin453701006/article/details/77249344)。

代码分析:

/** check RD costs for a CU block encoded with merge* \param rpcBestCU* \param rpcTempCU* \param earlyDetectionSkipMode*/
//计算2Nx2N块Merge下的RD代价
Void TEncCu::xCheckRDCostMerge2Nx2N( TComDataCU*& rpcBestCU, TComDataCU*& rpcTempCU DEBUG_STRING_FN_DECLARE(sDebug), Bool *earlyDetectionSkipMode )
{assert( rpcTempCU->getSlice()->getSliceType() != I_SLICE );       //检测非I帧if(getFastDeltaQp())      //快速deltaQP,默认关闭{return;   // never check merge in fast deltaqp mode}TComMvField  cMvFieldNeighbours[2 * MRG_MAX_NUM_CANDS]; // double length for mv of both lists 长度为2倍最大候选长度UChar uhInterDirNeighbours[MRG_MAX_NUM_CANDS];        Int numValidMergeCand = 0;const Bool bTransquantBypassFlag = rpcTempCU->getCUTransquantBypass(0);for( UInt ui = 0; ui < rpcTempCU->getSlice()->getMaxNumMergeCand(); ++ui ){uhInterDirNeighbours[ui] = 0;}UChar uhDepth = rpcTempCU->getDepth( 0 );     //获取当前深度rpcTempCU->setPartSizeSubParts( SIZE_2Nx2N, 0, uhDepth ); // interprets depth relative to CTU level 获取分块信息rpcTempCU->getInterMergeCandidates( 0, 0, cMvFieldNeighbours,uhInterDirNeighbours, numValidMergeCand );       //获取候选列表//构造候选列表Int mergeCandBuffer[MRG_MAX_NUM_CANDS];       for( UInt ui = 0; ui < numValidMergeCand; ++ui ){mergeCandBuffer[ui] = 0;}Bool bestIsSkip = false;UInt iteration;//默认为false,iteration = 2if ( rpcTempCU->isLosslessCoded(0)){iteration = 1;}else{iteration = 2;}DEBUG_STRING_NEW(bestStr)//遍历两次,第一次无残差编码,第二次对残差编码for( UInt uiNoResidual = 0; uiNoResidual < iteration; ++uiNoResidual ){for( UInt uiMergeCand = 0; uiMergeCand < numValidMergeCand; ++uiMergeCand ){ //当uiNoResidual==0或mergeCandBuffer[uiMergeCand]==0时成立if(!(uiNoResidual==1 && mergeCandBuffer[uiMergeCand]==1)){//当bestIsSkip为false或uiNoResidual==1时成立if( !(bestIsSkip && uiNoResidual == 0) )    {DEBUG_STRING_NEW(tmpStr)// set MC parameters 设置运动补偿参数rpcTempCU->setPredModeSubParts( MODE_INTER, 0, uhDepth ); // interprets depth relative to CTU levelrpcTempCU->setCUTransquantBypassSubParts( bTransquantBypassFlag, 0, uhDepth );rpcTempCU->setChromaQpAdjSubParts( bTransquantBypassFlag ? 0 : m_cuChromaQpOffsetIdxPlus1, 0, uhDepth );rpcTempCU->setPartSizeSubParts( SIZE_2Nx2N, 0, uhDepth ); // interprets depth relative to CTU levelrpcTempCU->setMergeFlagSubParts( true, 0, 0, uhDepth ); // interprets depth relative to CTU levelrpcTempCU->setMergeIndexSubParts( uiMergeCand, 0, 0, uhDepth ); // interprets depth relative to CTU levelrpcTempCU->setInterDirSubParts( uhInterDirNeighbours[uiMergeCand], 0, 0, uhDepth ); // interprets depth relative to CTU levelrpcTempCU->getCUMvField( REF_PIC_LIST_0 )->setAllMvField( cMvFieldNeighbours[0 + 2*uiMergeCand], SIZE_2Nx2N, 0, 0 ); // interprets depth relative to rpcTempCU levelrpcTempCU->getCUMvField( REF_PIC_LIST_1 )->setAllMvField( cMvFieldNeighbours[1 + 2*uiMergeCand], SIZE_2Nx2N, 0, 0 ); // interprets depth relative to rpcTempCU level// do MC 进行运动补偿m_pcPredSearch->motionCompensation ( rpcTempCU, m_ppcPredYuvTemp[uhDepth] );// estimate residual and encode everything 计算残差和RD cost,并进行编码。m_pcPredSearch->encodeResAndCalcRdInterCU( rpcTempCU,m_ppcOrigYuv    [uhDepth],m_ppcPredYuvTemp[uhDepth],m_ppcResiYuvTemp[uhDepth],m_ppcResiYuvBest[uhDepth],m_ppcRecoYuvTemp[uhDepth],(uiNoResidual != 0) DEBUG_STRING_PASS_INTO(tmpStr) );#if DEBUG_STRINGDebugInterPredResiReco(tmpStr, *(m_ppcPredYuvTemp[uhDepth]), *(m_ppcResiYuvBest[uhDepth]), *(m_ppcRecoYuvTemp[uhDepth]), DebugStringGetPredModeMask(rpcTempCU->getPredictionMode(0)));
#endif//第一次迭代时执行if ((uiNoResidual == 0) && (rpcTempCU->getQtRootCbf(0) == 0)){// If no residual when allowing for one, then set mark to not try case where residual is forced to 0mergeCandBuffer[uiMergeCand] = 1;}Int orgQP = rpcTempCU->getQP( 0 );xCheckDQP( rpcTempCU );xCheckBestMode(rpcBestCU, rpcTempCU, uhDepth DEBUG_STRING_PASS_INTO(bestStr) DEBUG_STRING_PASS_INTO(tmpStr));     //更新最优模式rpcTempCU->initEstData( uhDepth, orgQP, bTransquantBypassFlag );      //初始化预测参数if( m_pcEncCfg->getUseFastDecisionForMerge() && !bestIsSkip ){bestIsSkip = rpcBestCU->getQtRootCbf(0) == 0;}}}}//如果开启earlyDetectionSkip时,第一次迭代执行if(uiNoResidual == 0 && m_pcEncCfg->getUseEarlySkipDetection()){if(rpcBestCU->getQtRootCbf( 0 ) == 0){if( rpcBestCU->getMergeFlag( 0 )){*earlyDetectionSkipMode = true;}else if(m_pcEncCfg->getFastSearch() != SELECTIVE){Int absoulte_MV=0;for ( UInt uiRefListIdx = 0; uiRefListIdx < 2; uiRefListIdx++ ){if ( rpcBestCU->getSlice()->getNumRefIdx( RefPicList( uiRefListIdx ) ) > 0 ){TComCUMvField* pcCUMvField = rpcBestCU->getCUMvField(RefPicList( uiRefListIdx ));Int iHor = pcCUMvField->getMvd( 0 ).getAbsHor();Int iVer = pcCUMvField->getMvd( 0 ).getAbsVer();absoulte_MV+=iHor+iVer;}}if(absoulte_MV == 0){*earlyDetectionSkipMode = true;}}}}}DEBUG_STRING_APPEND(sDebug, bestStr)
}

HEVC代码学习31:xCheckRDCostMerge2Nx2N函数相关推荐

  1. HEVC代码学习:帧间预测——MVP过程中MV的获取、传递及存储

    作为一个视频编码小白,最近开始着手啃HEVC帧间预测的代码,想用博客记录一下自己的学习过程,也想与大家分享.交流一下. HEVC代码的学习主要是参考两位大神岳麓吹雪.NB_vol_1的博客以及HM参考 ...

  2. HEVC代码学习42:estIntraPredLumaQT函数

    在之前的 HEVC代码学习37:帧内预测代码整体学习 中已经提到,estIntraPredLumaQT是亮度帧内预测的入口函数,下面将对该函数进行详细学习. estIntraPredLumaQT中完成 ...

  3. HEVC代码学习39:decodeCtu和xDecodeCU函数

    在之前 HEVC代码学习38:decompressSlice函数 学习中提到,解码slice会遍历所有CTU,调用decodeCtu和decompressCtu解码每一个CTU.下面就来学习一下dec ...

  4. HEVC代码学习——帧间预测:预测MV获取(xEstimateMvPredAMVP、fillMVPCand)

    HEVC帧间预测在AMVP模式下是依靠xEstimateMvPredAMVP函数获取预测MV(MVP)的. 这部分内容的学习还可以参考这两篇博客: HEVC代码学习15:AMVP相关函数 HM编码器代 ...

  5. H.266代码学习:xEncodeCU函数

    之前在HEVC代码学习35:xEncodeCU函数中介绍过xEncodeCU函数,今天来看JEM中的xEncodeCU,其中难点在于QTBT编码结构. HM中使用compressCtu对每个CTU进行 ...

  6. H.266代码学习:estIntraPredLumaQT函数

    之前 HEVC代码学习42:estIntraPredLumaQT函数 对HM中的estIntraPredLumaQT函数进行了学习,下面将对JEM中的该函数进行学习. estIntraPredLuma ...

  7. H.266代码学习:xIntraCodingTUBlock函数

    今天来继续学习帧内编码的重要函数xIntraCodingTUBlock,上次 H.266代码学习:xRecurIntraCodingLumaQT函数 学习中提到,xIntraCodingTUBlock ...

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

    xCompressCU函数是用来进行CU划分(递归调用自身)以及模式选择. 首先调用m_modeCtrl->initCULevel函数初始化模式选择列表,由堆栈控制,将当前CU可以划分的模式(四 ...

  9. HEVC代码学习6:filterHor和filterVer函数

    帧间预测分为运动估计ME和运动补偿MV,其中用到了MV的亚像素搜索,需要使用filterHor和filterVer进行插值. 这里使用的是HM16,在之前版本中分为filterHorLuma.filt ...

  10. HEVC代码学习13:predInterSearch函数

    在上一章的xCheckRDCostInter学习中,我们知道了,进行帧间搜索的入口实际是predInterSearch,今天我们就来对他进行学习. 推荐看大神博客 http://blog.csdn.n ...

最新文章

  1. shutdown -s -t XXX
  2. Combiner合并案例
  3. java类同步,Java同步工具類(一)
  4. oracle for循环
  5. 在S/4HANA扩展字段的Available Fields列表里,看不到自己创建的扩展字段该怎么办
  6. Java Map集合
  7. 《Python编程从入门到实践》记录之第7章 用户输入(input)和while 循环总结(思维导图)
  8. spring boot 2.x 系列 —— spring boot 整合 kafka
  9. 数据湖就是坑人的新概念?那些挖坑的企业,后来都怎么样了
  10. java -jar vm参数_java相关:运行jar程序时添加vm参数的方法
  11. vue+sortable实现表格拖拽
  12. UDTF's are not supported outside the SELECT clause, nor nested in expressions (state=42000,code=1008
  13. 与商业经济有关的英语电影推荐:商学院学生必看的20部电影(图文)
  14. java小程序贪吃蛇代码_微信小程序Demo之贪食蛇
  15. python打开json文件_python怎么读json文件
  16. iOS10 新特性-新功能,以及ReplayKit库
  17. Flutter 开发中最实用的 Dart 语法知识
  18. 【题解】Leyni,罗莉和队列(树状数组)
  19. JS轮播图(点击切换、自动播放、悬停控制)
  20. 计算机冷门领域,毕业后很吃香的三大“冷门”专业!不比热门专业差,适合中等考生...

热门文章

  1. 五种常用的MySQL图形化管理工具
  2. 福利福利!20行代码教大家抓取斗鱼美女主播封面
  3. QTP 10.0 破解版下载安装超详细教程
  4. HarmoneyOS鸿蒙系统零代码编程入门
  5. 从Python.org下载Python安装包下载很慢
  6. 金格pdf打开服务器文件,金格插件解决方法.pdf
  7. CPT205-Computer Graphics
  8. windows下WDK创建免费的测试证书,并签名windows驱动文件(附带测试效果)
  9. 真正的云主机到底是什么样的?转发
  10. 热门手机刷锤子ROM什么样?