在xCheckRDCostMerge2N*2N执行完,如果m_useEarlySkipDetection==false,则继续执行xCheckRDCostInter函数。(如果m_useEarlySkipDetection==true,则此函数在帧间的最开始执行)
#if AMP_MRG
Void TEncCu::xCheckRDCostInter( TComDataCU*& rpcBestCU, TComDataCU*& rpcTempCU, PartSize ePartSize DEBUG_STRING_FN_DECLARE(sDebug), Bool bUseMRG
#if VCEG_AZ07_IMV
#if JVET_E0076_MULTI_PEL_MVD
, UChar bIMV , TComDataCU * pcCUInfo2Reuse
#else
, Bool bIMV , TComDataCU * pcCUInfo2Reuse
#endif
#endif
)
#else
Void TEncCu::xCheckRDCostInter( TComDataCU*& rpcBestCU, TComDataCU*& rpcTempCU, PartSize ePartSize
#if VCEG_AZ07_IMV
, Bool bIMV , TComDataCU * pcCUInfo2Reuse
#endif
)
#endif
{
#if JVET_C0024_QTBT
UInt uiWIdx = g_aucConvertToBit[rpcBestCU->getWidth(0)];
UInt uiHIdx = g_aucConvertToBit[rpcBestCU->getHeight(0)];
#endif
DEBUG_STRING_NEW(sTest)
if(getFastDeltaQp()) //快速deltaQP模式,只有在2Nx2N的帧间模式中使用;
{
const TComSPS &sps=*(rpcTempCU->getSlice()->getSPS());
#if JVET_C0024_QTBT
const UInt fastDeltaQPCuMaxSize = Clip3(sps.getMinQTSize(rpcBestCU->getSlice()->getSliceType(), rpcBestCU->getTextType()), sps.getCTUSize(), 32u);
#else
const UInt fastDeltaQPCuMaxSize = Clip3(sps.getMaxCUHeight()>>(sps.getLog2DiffMaxMinCodingBlockSize()), sps.getMaxCUHeight(), 32u);
#endif
if(ePartSize != SIZE_2Nx2N || rpcTempCU->getWidth( 0 ) > fastDeltaQPCuMaxSize)
{
return; // only check necessary 2Nx2N Inter in fast deltaqp mode
}
}
// prior to this, rpcTempCU will have just been reset using rpcTempCU->initEstData( uiDepth, iQP, bIsLosslessMode );
UChar uhDepth = rpcTempCU->getDepth( 0 );
#if COM16_C806_LARGE_CTU && !JVET_C0024_QTBT
if( m_pcEncCfg->getUseFastLCTU() )
{
if( ePartSize != SIZE_2Nx2N && rpcTempCU->getWidth( 0 ) > 64 )
{
rpcTempCU->getTotalCost() = MAX_DOUBLE / 4;
rpcTempCU->getTotalDistortion() = MAX_INT;
xCheckBestMode(rpcBestCU, rpcTempCU, uhDepth);
return;
}
}
#endif
#if !JVET_C0024_QTBT
rpcTempCU->setPartSizeSubParts ( ePartSize, 0, uhDepth );
#endif
rpcTempCU->setPredModeSubParts ( MODE_INTER, 0, uhDepth );//初始化预测模式为帧间;
rpcTempCU->setChromaQpAdjSubParts( rpcTempCU->getCUTransquantBypass(0) ? 0 : m_cuChromaQpOffsetIdxPlus1, 0, uhDepth );//设置色度QP自适应标记
#if COM16_C806_OBMC
rpcTempCU->setOBMCFlagSubParts( true, 0, uhDepth );//初始化OBMC flag;
#endif
#if VCEG_AZ06_IC
Bool bICFlag = rpcTempCU->getICFlag( 0 );//得到局部光照补偿标记;
#endif
#if VCEG_AZ07_IMV
rpcTempCU->setiMVFlagSubParts( bIMV, 0, uhDepth );//初始化IMV的flag;
if( bIMV && pcCUInfo2Reuse != NULL )//bIMV,局部自适应运动矢量分辨率且重复使用的信息不为空;
{
// reuse the motion info from pcCUInfo2Reuse,从pcCUInfo2Reuse中重复使用运动信息;
#if JVET_C0024_QTBT
rpcTempCU->copyPartFrom( pcCUInfo2Reuse , 0 , uhDepth, rpcTempCU->getWidth(0), rpcTempCU->getHeight(0) );//把pcCUInfo2Reuse存储的信息复制给TempCU;
#else
assert( pcCUInfo2Reuse->getPartitionSize( 0 ) == ePartSize );
rpcTempCU->copyPartFrom( pcCUInfo2Reuse , 0 , uhDepth );
#endif
rpcTempCU->setiMVFlagSubParts( bIMV , 0 , uhDepth );//设置imv的标记;
rpcTempCU->resetMVDandMV2Int( true
#if VCEG_AZ07_FRUC_MERGE
, m_pcPredSearch
#endif
);
#if VCEG_AZ06_IC
bICFlag = rpcTempCU->getICFlag( 0 );//得到局部光照补偿标记;
#endif
if( !rpcTempCU->hasSubCUNonZeroMVd() )//没有非0MVD,即MVD全为0,则退出;
{
return;
}
else//有非零MVD,则做运动补偿
{
#if JVET_C0024_QTBT
m_pcPredSearch->motionCompensation( rpcTempCU , m_pppcPredYuvTemp[uiWIdx][uiHIdx] );//运动补偿
#if COM16_C806_OBMC //OBMC,重叠块运动补偿,JEM中新加的;
m_pppcPredYuvTemp[uiWIdx][uiHIdx]->copyToPartYuv( m_pppcPredYuvWoOBMC[uiWIdx][uiHIdx] , 0 );
rpcTempCU->setOBMCFlagSubParts( true, 0, uhDepth );//设置OBMC的标记
m_pcPredSearch->subBlockOBMC( rpcTempCU, 0, m_pppcPredYuvTemp[uiWIdx][uiHIdx], m_pppcTmpYuv1[uiWIdx][uiHIdx], m_pppcTmpYuv2[uiWIdx][uiHIdx] );//重叠块运动补偿
#endif
#else
m_pcPredSearch->motionCompensation( rpcTempCU , m_ppcPredYuvTemp[uhDepth] );
#if COM16_C806_OBMC
m_ppcPredYuvTemp[uhDepth]->copyToPartYuv( m_ppcPredYuvWoOBMC[uhDepth] , 0 );
rpcTempCU->setOBMCFlagSubParts( true, 0, uhDepth );
m_pcPredSearch->subBlockOBMC( rpcTempCU, 0, m_ppcPredYuvTemp[uhDepth], m_ppcTmpYuv1[uhDepth], m_ppcTmpYuv2[uhDepth] );
#endif
#endif
}
}
else//bIMV==false || pcCUInfo2Reuse == NULL
{
#endif
#if AMP_MRG
#if !JVET_C0024_QTBT
rpcTempCU->setMergeAMP (true);
#endif
#if COM16_C806_OBMC
#if JVET_C0024_QTBT//predInterSearch的主要工作是运动估计和运动补偿;
m_pcPredSearch->predInterSearch ( rpcTempCU, m_pppcOrigYuv[uiWIdx][uiHIdx], m_pppcPredYuvTemp[uiWIdx][uiHIdx], m_pppcResiYuvTemp[uiWIdx][uiHIdx], m_pppcRecoYuvTemp[uiWIdx][uiHIdx], m_pppcPredYuvWoOBMC[uiWIdx][uiHIdx], m_pppcTmpYuv1[uiWIdx][uiHIdx], m_pppcTmpYuv2[uiWIdx][uiHIdx], false, bUseMRG );
#else
m_pcPredSearch->predInterSearch ( rpcTempCU, m_ppcOrigYuv[uhDepth], m_ppcPredYuvTemp[uhDepth], m_ppcResiYuvTemp[uhDepth], m_ppcRecoYuvTemp[uhDepth], m_ppcPredYuvWoOBMC[uhDepth], m_ppcTmpYuv1[uhDepth], m_ppcTmpYuv2[uhDepth], false, bUseMRG );
#endif
#else
#if JVET_C0024_QTBT
m_pcPredSearch->predInterSearch ( rpcTempCU, m_pppcOrigYuv[uiWIdx][uiHIdx], m_pppcPredYuvTemp[uiWIdx][uiHIdx], m_pppcResiYuvTemp[uiWIdx][uiHIdx], m_pppcRecoYuvTemp[uiWIdx][uiHIdx] , false, bUseMRG );
#else
m_pcPredSearch->predInterSearch ( rpcTempCU, m_ppcOrigYuv[uhDepth], m_ppcPredYuvTemp[uhDepth], m_ppcResiYuvTemp[uhDepth], m_ppcRecoYuvTemp[uhDepth] DEBUG_STRING_PASS_INTO(sTest), false, bUseMRG );
#endif
#endif
#else
#if COM16_C806_OBMC
m_pcPredSearch->predInterSearch ( rpcTempCU, m_ppcOrigYuv[uhDepth], m_ppcPredYuvTemp[uhDepth], m_ppcResiYuvTemp[uhDepth], m_ppcRecoYuvTemp[uhDepth], m_ppcPredYuvWoOBMC[uhDepth], m_ppcTmpYuv1[uhDepth], m_ppcTmpYuv2[uhDepth] );
#else
m_pcPredSearch->predInterSearch ( rpcTempCU, m_ppcOrigYuv[uhDepth], m_ppcPredYuvTemp[uhDepth], m_ppcResiYuvTemp[uhDepth], m_ppcRecoYuvTemp[uhDepth] );
#endif
#endif
#if AMP_MRG && !JVET_C0024_QTBT
if ( !rpcTempCU->getMergeAMP() )
{
return;
}
#endif
#if VCEG_AZ07_IMV
if( bIMV )
{
if( !rpcTempCU->hasSubCUNonZeroMVd() )//没有非零MVD,就返回;
{
return;
}
}
}
#endif
#if COM16_C806_OBMC
#if JVET_C0024_QTBT
m_pppcTempCUWoOBMC[uiWIdx][uiHIdx]->initEstData( uhDepth, rpcTempCU->getQP( 0 ), rpcTempCU->getCUTransquantBypass( 0 ) );
m_pppcTempCUWoOBMC[uiWIdx][uiHIdx]->copyPartFrom( rpcTempCU, 0, uhDepth, rpcTempCU->getWidth(0), rpcTempCU->getHeight(0) );
#else
m_ppcTempCUWoOBMC[uhDepth]->initEstData( uhDepth, rpcTempCU->getQP( 0 ), rpcTempCU->getCUTransquantBypass( 0 ) );
m_ppcTempCUWoOBMC[uhDepth]->copyPartFrom( rpcTempCU, 0, uhDepth );
#endif
Bool bCheckOBMC[2] = { true , true };
bCheckOBMC[0] = rpcTempCU->isOBMCFlagCoded( 0 ); // check OBMC off only when the flag is to be coded
if( !rpcTempCU->getSlice()->getSPS()->getOBMC() )//不使用OBMC
{
bCheckOBMC[1] = false; bCheckOBMC[0] = true;
}
else if( rpcTempCU->isOBMCFlagCoded( 0 ) )
{
const Double dOBMCThOn = 0.0;
const Double dOBMCThOff = 1.0;
#if JVET_C0024_QTBT
UInt uiSADOBMCOff = m_pppcOrigYuv[uiWIdx][uiHIdx]->sadLuma( m_pppcPredYuvWoOBMC[uiWIdx][uiHIdx] );//计算亮度分量的SAD;
UInt uiSADOBMCOn = m_pppcOrigYuv[uiWIdx][uiHIdx]->sadLuma( m_pppcPredYuvTemp[uiWIdx][uiHIdx] );
#else
UInt uiSADOBMCOff = m_ppcOrigYuv[uhDepth]->sadLuma( m_ppcPredYuvWoOBMC[uhDepth] );
UInt uiSADOBMCOn = m_ppcOrigYuv[uhDepth]->sadLuma( m_ppcPredYuvTemp[uhDepth] );
#endif
// OBMC off
bCheckOBMC[0] = uiSADOBMCOff * dOBMCThOff < uiSADOBMCOn;//如果OBMC off的SAD小于OBMC on的SAD,则bCheckOBMC[0]为true;
// OBMC on
bCheckOBMC[1] = !bCheckOBMC[0] || uiSADOBMCOn * dOBMCThOn < uiSADOBMCOff;// bCheckOBMC[0]为false或者如果OBMC off的SAD大于OBMC on的SAD,则bCheckOBMC[1]为true;
}
循环两次,第一次不执行OBMC,第二次执行OBMC//
for( Int nOBMC = 1 ; nOBMC >= 0 ; nOBMC-- )
{
if( !bCheckOBMC[nOBMC] )//如果bCheckOBMC[1]是false,即不执行OBMC,所以跳出
{
continue;
}
#if JVET_C0024_QTBT
rpcTempCU->copyPartFrom( m_pppcTempCUWoOBMC[uiWIdx][uiHIdx], 0, uhDepth, rpcTempCU->getWidth(0), rpcTempCU->getHeight(0) );
if (nOBMC == 0)
m_pppcPredYuvWoOBMC[uiWIdx][uiHIdx]->copyToPartYuv(m_pppcPredYuvTemp[uiWIdx][uiHIdx], 0);
#else
rpcTempCU->copyPartFrom( m_ppcTempCUWoOBMC[uhDepth], 0, uhDepth );
if (nOBMC == 0)
m_ppcPredYuvWoOBMC[uhDepth]->copyToPartYuv(m_ppcPredYuvTemp[uhDepth], 0);
#endif
rpcTempCU->setOBMCFlagSubParts( ( Bool )nOBMC , 0 , uhDepth );//用nOBMC初始化OBMC标记,所以只有bCheckOBMC[1]==1时OBMCFlag才为true;
#endif
#if VCEG_AZ06_IC
rpcTempCU->setICFlagSubParts( bICFlag, 0, uhDepth );//初始化局部光照补偿的标记;
#endif
#if JVET_C0024_QTBT//编码残差并计算率失真代价;
m_pcPredSearch->encodeResAndCalcRdInterCU( rpcTempCU, m_pppcOrigYuv[uiWIdx][uiHIdx],
m_pppcPredYuvTemp[uiWIdx][uiHIdx], m_pppcResiYuvTemp[uiWIdx][uiHIdx], m_pppcResiYuvBest[uiWIdx][uiHIdx], m_pppcRecoYuvTemp[uiWIdx][uiHIdx], false
#else
m_pcPredSearch->encodeResAndCalcRdInterCU( rpcTempCU, m_ppcOrigYuv[uhDepth],
m_ppcPredYuvTemp[uhDepth], m_ppcResiYuvTemp[uhDepth], m_ppcResiYuvBest[uhDepth], m_ppcRecoYuvTemp[uhDepth], false
#endif
#if COM16_C806_EMT
, rpcBestCU->getTotalCost()
#endif
DEBUG_STRING_PASS_INTO(sTest)
);
rpcTempCU->getTotalCost() = m_pcRdCost->calcRdCost( rpcTempCU->getTotalBits(), rpcTempCU->getTotalDistortion() );//计算总的率失真代价;
#if VCEG_AZ07_IMV
#if !JVET_C0024_QTBT
if( rpcTempCU->getiMVFlag( 0 ) == 0 )
{
if( rpcTempCU->getTotalCost() < m_ppcTempCUIMVCache[ePartSize][uhDepth]->getTotalCost() )
{
SModeCand tmpCand;
tmpCand.eInterPartSize = ePartSize;
tmpCand.bUseMrg = bUseMRG;
tmpCand.dRDCost = rpcTempCU->getTotalCost();
m_ppcTempCUIMVCache[ePartSize][uhDepth]->copyPartFrom( rpcTempCU , 0 , uhDepth );
m_ppcTempCUIMVCache[ePartSize][uhDepth]->getTotalCost() = tmpCand.dRDCost;
tmpCand.pcCUMode = m_ppcTempCUIMVCache[ePartSize][uhDepth];
m_setInterCand.insert( tmpCand );
}
}
#endif
#endif
#if JVET_E0076_MULTI_PEL_MVD//指的是多精度MVD
if (rpcTempCU->getTotalCost() < m_dBestMvDPelCost[rpcTempCU->getiMVFlag(0)])//如果当前CU的总代价小于最优MVD精度的代价
{
m_dBestMvDPelCost[rpcTempCU->getiMVFlag(0)] = rpcTempCU->getTotalCost();//把最优MVD精度代价更新为当前CU的代价;
}
#endif
#if DEBUG_STRING
DebugInterPredResiReco(sTest, *(m_ppcPredYuvTemp[uhDepth]), *(m_ppcResiYuvBest[uhDepth]), *(m_ppcRecoYuvTemp[uhDepth]), DebugStringGetPredModeMask(rpcTempCU->getPredictionMode(0)));
#endif
#if JVET_C0024_DELTA_QP_FIX && COM16_C806_OBMC
Int orgQP = rpcTempCU->getQP( 0 );
#endif
xCheckDQP( rpcTempCU );
xCheckBestMode(rpcBestCU, rpcTempCU, uhDepth DEBUG_STRING_PASS_INTO(sDebug) DEBUG_STRING_PASS_INTO(sTest));
#if COM16_C806_OBMC
#if JVET_C0024_DELTA_QP_FIX
rpcTempCU->initEstData( uhDepth, orgQP, rpcTempCU->getCUTransquantBypass( 0 ) );//重新初始化TempCU;
#else
rpcTempCU->initEstData( uhDepth, rpcTempCU->getQP( 0 ), rpcTempCU->getCUTransquantBypass( 0 ) );
#endif
}
/OBMC循环结束/
#endif
}