在执行完xCheckRDCostMerge2N*2N函数完后,会执行此函数。FRUC包含两种技术,一种是模板匹配,一种是双边匹配。该计算的关键在于怎么推导MV,下次再看吧。
#if VCEG_AZ07_FRUC_MERGE
Void TEncCu::xCheckRDCostMerge2Nx2NFRUC( TComDataCU*& rpcBestCU, TComDataCU*& rpcTempCU , Bool *earlyDetectionSkipMode )
{
#if JVET_C0024_QTBT
UInt uiWIdx = g_aucConvertToBit[rpcBestCU->getWidth(0)];
UInt uiHIdx = g_aucConvertToBit[rpcBestCU->getHeight(0)];
#endif
UChar uhDepth = rpcTempCU->getDepth( 0 );
const UChar uhFRUCME[2] = { FRUC_MERGE_BILATERALMV , FRUC_MERGE_TEMPLATE };//双边匹配和模板匹配
#if VCEG_AZ06_IC
Bool bICFlag = rpcTempCU->getICFlag( 0 );
#endif
///循环两次,一次是双边匹配(时域),一次是模板匹配(空域)/
for( Int nME = 0 ; nME < 2 ; nME++ )
{
#if JVET_D0077_SAVE_LOAD_ENC_INFO
if( m_pcPredSearch->getSaveLoadTag(rpcBestCU->getZorderIdxInCtu(), uiWIdx, uiHIdx) == LOAD_ENC_INFO &&
uhFRUCME[nME] != m_pcPredSearch->getSaveLoadFrucMode( uiWIdx, uiHIdx ) )
{
continue;
}
#endif
#if !JVET_C0024_QTBT
rpcTempCU->setPartSizeSubParts( SIZE_2Nx2N, 0, uhDepth );
#endif//设置运动补偿参数
rpcTempCU->setPredModeSubParts( MODE_INTER, 0, uhDepth ); // interprets depth relative to LCU level
rpcTempCU->setCUTransquantBypassSubParts( false, 0, uhDepth );
rpcTempCU->setMergeFlagSubParts( true, 0, 0, uhDepth ); // interprets depth relative to LCU level
rpcTempCU->setMergeIndexSubParts( 0, 0, 0, uhDepth ); // interprets depth relative to LCU level
rpcTempCU->setFRUCMgrModeSubParts( uhFRUCME[nME] , 0 , 0 , uhDepth );
#if VCEG_AZ06_IC
rpcTempCU->setICFlagSubParts( bICFlag, 0, uhDepth );
#endif
Bool bAvailable = m_pcPredSearch->deriveFRUCMV( rpcTempCU , uhDepth , 0 , 0 ); //基于FRUC推导块的MV;
#if JVET_C0024_QTBT
m_pppcFRUCBufferCU[uiWIdx][uiHIdx]->copyPartFrom( rpcTempCU , 0 , uhDepth, rpcTempCU->getWidth(0), rpcTempCU->getHeight(0) );
#else
m_ppcFRUCBufferCU[uhDepth]->copyPartFrom( rpcTempCU , 0 , uhDepth );
#endif
if( bAvailable )//如果上面推导出来的MV可用
{
UInt iteration = 1 + !rpcTempCU->isLosslessCoded(0) ;//无损,则等于1,有损,则等于2;
//iteration开始,残差系数全为0迭代1次,否则2次//
for( UInt uiNoResidual = 0; uiNoResidual < iteration; uiNoResidual++ )
{
if( uiNoResidual > 0 )//第二次迭代;
{
#if JVET_C0024_QTBT
rpcTempCU->copyPartFrom( m_pppcFRUCBufferCU[uiWIdx][uiHIdx] , 0 , uhDepth, rpcTempCU->getWidth(0), rpcTempCU->getHeight(0) );
#else
rpcTempCU->copyPartFrom( m_ppcFRUCBufferCU[uhDepth] , 0 , uhDepth );
#endif
}
// do MC
#if JVET_C0024_QTBT
m_pcPredSearch->motionCompensation ( rpcTempCU, m_pppcPredYuvTemp[uiWIdx][uiHIdx] );//做运动补偿
#if COM16_C806_OBMC//进行重叠块运动补偿
m_pcPredSearch->subBlockOBMC( rpcTempCU, 0, m_pppcPredYuvTemp[uiWIdx][uiHIdx], m_pppcTmpYuv1[uiWIdx][uiHIdx], m_pppcTmpYuv2[uiWIdx][uiHIdx] );
#endif
// estimate residual and encode everything,估计残差并且编码所有数据,计算失真
m_pcPredSearch->encodeResAndCalcRdInterCU( rpcTempCU,
m_pppcOrigYuv [uiWIdx][uiHIdx],
m_pppcPredYuvTemp[uiWIdx][uiHIdx],
m_pppcResiYuvTemp[uiWIdx][uiHIdx],
m_pppcResiYuvBest[uiWIdx][uiHIdx],
m_pppcRecoYuvTemp[uiWIdx][uiHIdx],
(uiNoResidual? true:false)
#if COM16_C806_EMT
, rpcBestCU->getTotalCost()
#endif
);
#else
m_pcPredSearch->motionCompensation ( rpcTempCU, m_ppcPredYuvTemp[uhDepth] );
#if COM16_C806_OBMC
m_pcPredSearch->subBlockOBMC( rpcTempCU, 0, m_ppcPredYuvTemp[uhDepth], m_ppcTmpYuv1[uhDepth], m_ppcTmpYuv2[uhDepth] );
#endif
// 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)
#if COM16_C806_EMT
, rpcBestCU->getTotalCost()
#endif
);
#endif
if ( uiNoResidual == 0 && rpcTempCU->getQtRootCbf(0) == 0 )
{//在第一次迭代中,如果残差系数全为0,则不进行第二次迭代过程;
uiNoResidual++;
}
rpcTempCU->setSkipFlagSubParts( rpcTempCU->getQtRootCbf(0) == 0, 0, uhDepth );//设置SkipFlag;
Int orgQP = rpcTempCU->getQP( 0 );
xCheckDQP( rpcTempCU );
xCheckBestMode(rpcBestCU, rpcTempCU, uhDepth);
rpcTempCU->initEstData( uhDepth, orgQP, false );
}
//iteration结束///
}
}
循环结束,一次双边匹配,一次模板匹配/
}
#endif