本文将对实现merge模式的主函数xCheckRDCostMerge2Nx2N进行分析,方便理清merge模式的整个过程。之前的一篇分析了getInterMergeCandidates的具体实现,还有两个比较重要的函数motionCompensation和encodeResAndCalcRdInterCU,将留在后面陆续进行分析,但是根据它们的命名就不难猜出它们的作用,而且事实也是这样,因此对理解merge模式的整个过程没有影响,可以暂时不用去细究具体实现。下面仍然以贴代码及注释的方式来进行分析:
Void TEncCu::xCheckRDCostMerge2Nx2N( TComDataCU*& rpcBestCU, TComDataCU*& rpcTempCU, Bool *earlyDetectionSkipMode ) { assert( rpcTempCU->getSlice()->getSliceType() != I_SLICE ); TComMvField cMvFieldNeighbours[MRG_MAX_NUM_CANDS << 1]; // double length for mv of both lists UChar uhInterDirNeighbours[MRG_MAX_NUM_CANDS]; Int numValidMergeCand = 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 LCU level rpcTempCU->setCUTransquantBypassSubParts( m_pcEncCfg->getCUTransquantBypassFlagValue(), 0, uhDepth ); rpcTempCU->getInterMergeCandidates( 0, 0, cMvFieldNeighbours,uhInterDirNeighbours, numValidMergeCand ); //! 创建一个merging candidates的列表 Int mergeCandBuffer[MRG_MAX_NUM_CANDS]; for( UInt ui = 0; ui < rpcTempCU->getSlice()->getMaxNumMergeCand(); ++ui ) { mergeCandBuffer[ui] = 0; }
Bool bestIsSkip = false;
UInt iteration; if ( rpcTempCU->isLosslessCoded(0)) //!< 默认为false { iteration = 1; } else { iteration = 2; }
for( UInt uiNoResidual = 0; uiNoResidual < iteration; ++uiNoResidual ) { for( UInt uiMergeCand = 0; uiMergeCand < numValidMergeCand; ++uiMergeCand ) //!< 遍历所有merging candidates { { if(!(uiNoResidual==1 && mergeCandBuffer[uiMergeCand]==1)) //!< uiNoResidual等于0或者mergeCandBuffer[uiMergeCand]等于0时条件成立 {
if( !(bestIsSkip && uiNoResidual == 0) ) //!< bestIsSkip等于false或者uiNoResidual等于1时条件成立 { // set MC parameters rpcTempCU->setPredModeSubParts( MODE_INTER, 0, uhDepth ); // interprets depth relative to LCU level rpcTempCU->setCUTransquantBypassSubParts( m_pcEncCfg->getCUTransquantBypassFlagValue(), 0, uhDepth ); rpcTempCU->setPartSizeSubParts( SIZE_2Nx2N, 0, uhDepth ); // interprets depth relative to LCU level rpcTempCU->setMergeFlagSubParts( true, 0, 0, uhDepth ); // interprets depth relative to LCU level rpcTempCU->setMergeIndexSubParts( uiMergeCand, 0, 0, uhDepth ); // interprets depth relative to LCU level rpcTempCU->setInterDirSubParts( uhInterDirNeighbours[uiMergeCand], 0, 0, uhDepth ); // interprets depth relative to LCU level rpcTempCU->getCUMvField( REF_PIC_LIST_0 )->setAllMvField( cMvFieldNeighbours[0 + 2*uiMergeCand], SIZE_2Nx2N, 0, 0 ); // interprets depth relative to rpcTempCU level rpcTempCU->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 m_pcPredSearch->encodeResAndCalcRdInterCU( rpcTempCU, m_ppcOrigYuv [uhDepth], m_ppcPredYuvTemp[uhDepth], m_ppcResiYuvTemp[uhDepth], m_ppcResiYuvBest[uhDepth], m_ppcRecoYuvTemp[uhDepth], (uiNoResidual? true:false)); //!< 对残差进行编码并计算RDCost
if(uiNoResidual==0) { if(rpcTempCU->getQtRootCbf(0) == 0) //!< CBF为0,说明变换系数全为0 { mergeCandBuffer[uiMergeCand] = 1; } }
rpcTempCU->setSkipFlagSubParts( rpcTempCU->getQtRootCbf(0) == 0, 0, uhDepth ); Int orgQP = rpcTempCU->getQP( 0 ); xCheckDQP( rpcTempCU ); xCheckBestMode(rpcBestCU, rpcTempCU, uhDepth); //!< 更新最佳模式 rpcTempCU->initEstData( uhDepth, orgQP ); //!< 重新初始化预测参数,为下一次预测做准备
if( m_pcEncCfg->getUseFastDecisionForMerge() && !bestIsSkip ) //!< m_useFastDecisionForMerge默认为true { bestIsSkip = rpcBestCU->getQtRootCbf(0) == 0; }
}//!< if( !(bestIsSkip && uiNoResidual == 0) ) }//!< if(!(uiNoResidual==1 && mergeCandBuffer[uiMergeCand]==1)) }//!< }//!< for( UInt uiMergeCand = 0; uiMergeCand < numValidMergeCand; ++uiMergeCand )
if(uiNoResidual == 0 && m_pcEncCfg->getUseEarlySkipDetection()) //!< 第一次对merging candidates迭代后 { if(rpcBestCU->getQtRootCbf( 0 ) == 0) //!< earlyDetectionSkip 算法 { if( rpcBestCU->getMergeFlag( 0 )) { *earlyDetectionSkipMode = true; } else { 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; } }//!< else }//!< if(rpcBestCU->getQtRootCbf( 0 ) == 0) }//!< if(uiNoResidual == 0 && m_pcEncCfg->getUseEarlySkipDetection()) }//!< for( UInt uiNoResidual = 0; uiNoResidual < iteration; ++uiNoResidual ) }