xCompressCU是一个递归函数,对于每一个CU,该函数都会被调用,主要是计算当前CU编码之后代价,然后再计算当前CU的每一个子CU编码后的代价,和当前CU的编码代价相比较,用来决定是否对当前CU进行分割。这个函数太复杂啦,继续慢慢学习吧。
Void TEncCu::xCompressCU( TComDataCU*& rpcBestCU, TComDataCU*& rpcTempCU, const UInt uiDepth, UInt uiWidth, UInt uiHeight, UInt uiBTSplitMode DEBUG_STRING_FN_DECLARE(sDebug_), UInt uiSplitConstrain )
#else
Void TEncCu::xCompressCU( TComDataCU*& rpcBestCU, TComDataCU*& rpcTempCU, const UInt uiDepth DEBUG_STRING_FN_DECLARE(sDebug_), PartSize eParentPartSize )
#endif
#else
Void TEncCu::xCompressCU( TComDataCU*& rpcBestCU, TComDataCU*& rpcTempCU, const UInt uiDepth )
#endif
{
//每个深度的预测用的都是temp,预测完后跟best比较并交换。best保留作为当前深度的预测数据,
//而temp再次初始化。在下一深度的子CU预测中用的是subtemp,每预测完一个子CU,就跟subbest比较交换,
//再把subbest的数据复制到已经初始化的temp的相应位置。当temp获取完子CU的subbest的数据后,
//就代表了整个下一深度的数据,这时再与代表当前深度数据的best比较交换;
#if JVET_C0024_BT_RMV_REDUNDANT
rpcBestCU->setSplitConstrain( uiSplitConstrain );
rpcTempCU->setSplitConstrain( uiSplitConstrain );
Bool bQTreeValid = false;
#endif
TComPic* pcPic = rpcBestCU->getPic();
DEBUG_STRING_NEW(sDebug)
const TComPPS &pps=*(rpcTempCU->getSlice()->getPPS());
const TComSPS &sps=*(rpcTempCU->getSlice()->getSPS());
#if JVET_C0024_QTBT
// These are only used if getFastDeltaQp() is true,32;
const UInt fastDeltaQPCuMaxSize = Clip3(sps.getMinQTSize(rpcBestCU->getSlice()->getSliceType(), rpcBestCU->getTextType())
, sps.getCTUSize(), 32u);
#else
// These are only used if getFastDeltaQp() is true
const UInt fastDeltaQPCuMaxSize = Clip3(sps.getMaxCUHeight()>>sps.getLog2DiffMaxMinCodingBlockSize(), sps.getMaxCUHeight(), 32u);
#endif
// get Original YUV data from picture
#if JVET_C0024_QTBT
UInt uiWidthIdx = g_aucConvertToBit[rpcTempCU->getWidth(0)];//=5;
UInt uiHeightIdx = g_aucConvertToBit[rpcTempCU->getHeight(0)];//=5;
//从图像中复制原始YUV数据;
m_pppcOrigYuv[uiWidthIdx][uiHeightIdx]->copyFromPicYuv( pcPic->getPicYuvOrg(), rpcBestCU->getCtuRsAddr(), rpcBestCU->getZorderIdxInCtu() );
UInt uiPelXInCTU = rpcBestCU->getCUPelX() - rpcBestCU->getPic()->getCtu(rpcBestCU->getCtuRsAddr())->getCUPelX();
UInt uiPelYInCTU = rpcBestCU->getCUPelY() - rpcBestCU->getPic()->getCtu(rpcBestCU->getCtuRsAddr())->getCUPelY();
rpcBestCU->getPic()->setCodedBlkInCTU(false, uiPelXInCTU>> MIN_CU_LOG2, uiPelYInCTU>> MIN_CU_LOG2, uiWidth>> MIN_CU_LOG2, uiHeight>> MIN_CU_LOG2 );
#else
m_ppcOrigYuv[uiDepth]->copyFromPicYuv( pcPic->getPicYuvOrg(), rpcBestCU->getCtuRsAddr(), rpcBestCU->getZorderIdxInCtu() );
#endif
// variable for Cbf fast mode PU decision
#if !JVET_C0024_QTBT
Bool doNotBlockPu = true;
#endif
Bool earlyDetectionSkipMode = false;
//获取当前最优CU的范围;
const UInt uiLPelX = rpcBestCU->getCUPelX();//左边的像素,0;
const UInt uiRPelX = uiLPelX + rpcBestCU->getWidth(0) - 1;//最右边的像素,127;
const UInt uiTPelY = rpcBestCU->getCUPelY();//上边的像素,0;
const UInt uiBPelY = uiTPelY + rpcBestCU->getHeight(0) - 1;//最下边的像素,127;
#if !JVET_C0024_QTBT
const UInt uiWidth = rpcBestCU->getWidth(0);
#endif
#if JVET_C0024_DELTA_QP_FIX
UInt uiQTWidth = sps.getCTUSize()>>uiDepth;//四叉树的宽度,128;
UInt uiQTHeight = sps.getCTUSize()>>uiDepth;//四叉树的高度,128;
UInt uiBTDepth = g_aucConvertToBit[uiQTWidth]-g_aucConvertToBit[uiWidth] + g_aucConvertToBit[uiQTHeight]-g_aucConvertToBit[uiHeight];//二叉树深度;
const UInt uiQTBTDepth = (uiDepth<<1) + uiBTDepth;//QTBT的深度是四叉树的深度加二叉树的深度;
const UInt uiMaxDQPDepthQTBT = pps.getMaxCuDQPDepth() << 1;
#endif
#if JVET_D0077_SAVE_LOAD_ENC_INFO
Bool bUseSaveLoad = m_pcEncCfg->getUseSaveLoadEncInfo() && uiWidthIdx > 0 && uiHeightIdx > 0;
Bool bUseSaveLoadSplitDecision = bUseSaveLoad && m_pcEncCfg->getUseSaveLoadSplitDecision();
#if COM16_C1046_PDPC_INTRA && !JVET_G0104_PLANAR_PDPC
ChannelType eChannelType = rpcBestCU->getTextType();
#endif
UInt uiZorderIdx = rpcBestCU->getZorderIdxInCtu();//当前最优CU在CTU中以Z扫描顺序的索引;
#endif
Int iBaseQP = xComputeQP( rpcBestCU, uiDepth );//计算QP,量化步长;
Int iMinQP;
Int iMaxQP;
Bool isAddLowestQP = false;
#if COM16_C806_EMT
Double dBestInterCost = MAX_DOUBLE;
Bool bEarlySkipIntra = false;
#if !JVET_C0024_QTBT
Bool bAllIntra = (m_pcEncCfg->getIntraPeriod()==1);
Double dIntra2Nx2NCost = MAX_DOUBLE;
#endif
#if !JVET_C0024_QTBT
Double dIntraNxNCost = MAX_DOUBLE;
#endif
#endif
#if JVET_C0024_DELTA_QP_FIX
const Char lastCodedQP = rpcBestCU->getCodedQP();
#endif
#if JVET_E0076_MULTI_PEL_MVD
m_dBestMvDPelCost[0] = m_dBestMvDPelCost[1] = m_dBestMvDPelCost[2] = MAX_DOUBLE/2;
#endif
const UInt numberValidComponents = rpcBestCU->getPic()->getNumberValidComponents();//3;
#if VCEG_AZ08_INTER_KLT
g_bEnableCheck = false;
#endif
/////////////////////////////////////////设置最大的QP和最小的QP/////////////////////////////////////////
#if JVET_C0024_DELTA_QP_FIX
if( uiQTBTDepth <= uiMaxDQPDepthQTBT )
#else
if( uiDepth <= pps.getMaxCuDQPDepth() )
#endif
{
Int idQP = m_pcEncCfg->getMaxDeltaQP();
iMinQP = Clip3( -sps.getQpBDOffset(CHANNEL_TYPE_LUMA), MAX_QP, iBaseQP-idQP );
iMaxQP = Clip3( -sps.getQpBDOffset(CHANNEL_TYPE_LUMA), MAX_QP, iBaseQP+idQP );
#if JVET_C0024_DELTA_QP_FIX
if( pps.getUseDQP() )
{
UInt uiCurrPartIdxInCtu = rpcBestCU->getZorderIdxInCtu();
rpcBestCU->setQuPartIdx( uiCurrPartIdxInCtu );
rpcTempCU->setQuPartIdx( uiCurrPartIdxInCtu );
rpcBestCU->setQuLastCodedQP( lastCodedQP );
rpcTempCU->setQuLastCodedQP( lastCodedQP );
}
#endif
}
else
{
iMinQP = rpcTempCU->getQP(0);
iMaxQP = rpcTempCU->getQP(0);
}
#if WCG_LUMA_DQP_CM_SCALE
Int targetQP = iBaseQP;
if (m_pcEncCfg->getUseLumaDeltaQp() )
{
if (uiQTBTDepth <= uiMaxDQPDepthQTBT)
{
m_LumaQPOffset = calculateLumaDQP(rpcTempCU, 0, m_pppcOrigYuv[uiWidthIdx][uiHeightIdx]); // keep using the same m_QP_LUMA_OFFSET in the same LCU
}
targetQP = Clip3(-sps.getQpBDOffset(CHANNEL_TYPE_LUMA), MAX_QP, iBaseQP - m_LumaQPOffset); // targetQP is used for control lambda,32;
iMinQP = targetQP;
iMaxQP = iMinQP; // make it same as MinQP to force encode choose the modified QP
}
#endif
if ( m_pcEncCfg->getUseRateCtrl() )
{
iMinQP = m_pcRateCtrl->getRCQP();
iMaxQP = m_pcRateCtrl->getRCQP();
}
// transquant-bypass (TQB) processing loop variable initialisation ---
const Int lowestQP = iMinQP; // For TQB, use this QP which is the lowest non TQB QP tested (rather than QP'=0) - that way delta QPs are smaller, and TQB can be tested at all CU levels.
if ( (pps.getTransquantBypassEnableFlag()) )
{
isAddLowestQP = true; // mark that the first iteration is to cost TQB mode.
iMinQP = iMinQP - 1; // increase loop variable range by 1, to allow testing of TQB mode along with other QPs
if ( m_pcEncCfg->getCUTransquantBypassFlagForceValue() )
{
iMaxQP = iMinQP;
}
}
#if VCEG_AZ06_IC
Bool bICEnabled = rpcTempCU->getSlice()->getApplyIC();
#if JVET_C0024_QTBT
#if VCEG_AZ06_IC_SPEEDUP
if (uiWidth * uiHeight <= 32 )
{
bICEnabled = false;
}
#endif
#endif
#endif
TComSlice * pcSlice = rpcTempCU->getPic()->getSlice(rpcTempCU->getPic()->getCurrSliceIdx());
#if COM16_C806_LARGE_CTU
#if JVET_C0024_QTBT//ucMaxDepth=4;
UChar ucMinDepth = 0 , ucMaxDepth = g_aucConvertToBit[pcSlice->getSPS()->getCTUSize()]
- g_aucConvertToBit[pcSlice->getSPS()->getMinQTSize(pcSlice->getSliceType(), rpcTempCU->getTextType())];
#else
UChar ucMinDepth = 0 , ucMaxDepth = ( UChar )pcSlice->getSPS()->getLog2DiffMaxMinCodingBlockSize();
#endif
if( m_pcEncCfg->getUseFastLCTU() )//enable fast method for large CTU;
{
rpcTempCU->getMaxMinCUDepth( ucMinDepth , ucMaxDepth , rpcTempCU->getZorderIdxInCtu() );
}
#endif
#if JVET_C0024_QTBT
Bool bBoundary = !( uiRPelX < sps.getPicWidthInLumaSamples() && uiBPelY < sps.getPicHeightInLumaSamples() );//判断当前CU是否在图像边界;
#else
const Bool bBoundary = !( uiRPelX < sps.getPicWidthInLumaSamples() && uiBPelY < sps.getPicHeightInLumaSamples() );
#endif
#if JVET_C0024_QTBT
Bool bForceQT = uiWidth > MAX_TU_SIZE;
if( bForceQT )
{
assert(uiWidth == uiHeight);
}
#endif
#if JVET_D0077_SAVE_LOAD_ENC_INFO
UChar saveLoadTag = m_pcPredSearch->getSaveLoadTag( uiZorderIdx, uiWidthIdx, uiHeightIdx );
UChar saveLoadSplit = ( (bUseSaveLoadSplitDecision && saveLoadTag == LOAD_ENC_INFO) ? m_pcPredSearch->getSaveLoadSplit(uiWidthIdx, uiHeightIdx) : 0 );
Double dCostTempBest = MAX_DOUBLE;//最优的临时代价;
Double dNonSplitCost = MAX_DOUBLE;//不分割的代价;
Double dHorSplitCost = MAX_DOUBLE;//水平分割的代价;
Double dVerSplitCost = MAX_DOUBLE;//垂直分割的代价;
#endif
if (!bBoundary
#if COM16_C806_LARGE_CTU
&& ucMinDepth <= uiDepth
#endif
#if JVET_C0024_QTBT
&& !bForceQT
#endif
#if JVET_D0077_SAVE_LOAD_ENC_INFO
&& !(saveLoadSplit & 0x01)
#endif
)
{
#if JVET_D0077_FAST_EXT
Bool bPrevSameBlockIsIntra = rpcBestCU->getPic()->getIntra(rpcBestCU->getZorderIdxInCtu(), uiWidth, uiHeight);
Bool bPrevSameBlockIsSkip = rpcBestCU->getPic()->getSkiped(rpcBestCU->getZorderIdxInCtu(), uiWidth, uiHeight);
#endif
//////////从最小的QP到最大的QP遍历每一个QP,对每一个QP执行下面的操作(目的是选出最优的QP)/////////
for (Int iQP = iMinQP; iQP <= iMaxQP; iQP++)
{
const Bool bIsLosslessMode = isAddLowestQP && (iQP == iMinQP);
if (bIsLosslessMode)//判断是否为无损模式,若是无损,则QP设置为最低值;
{
iQP = lowestQP;
}
#if WCG_LUMA_DQP_CM_SCALE
if (m_pcEncCfg->getUseLumaDeltaQp() && (uiQTBTDepth <= uiMaxDQPDepthQTBT))
{
getSliceEncoder()->updateLambda(pcSlice, targetQP);
}
#endif
m_cuChromaQpOffsetIdxPlus1 = 0;
if (pcSlice->getUseChromaQpAdj())
{
/* Pre-estimation of chroma QP based on input block activity may be performed
* here, using for example m_ppcOrigYuv[uiDepth] */
/* To exercise the current code, the index used for adjustment is based on
* block position
*/
#if JVET_C0024_QTBT
Int lgMinCuSize = g_aucConvertToBit[sps.getMinQTSize(pcSlice->getSliceType(), rpcBestCU->getTextType())] + MIN_CU_LOG2 +
std::max(0, g_aucConvertToBit[sps.getCTUSize()] - g_aucConvertToBit[sps.getMinQTSize(pcSlice->getSliceType(), rpcBestCU->getTextType())] - Int(pps.getPpsRangeExtension().getDiffCuChromaQpOffsetDepth()));
#else
Int lgMinCuSize = sps.getLog2MinCodingBlockSize() +
std::max(0, sps.getLog2DiffMaxMinCodingBlockSize() - Int(pps.getPpsRangeExtension().getDiffCuChromaQpOffsetDepth()));
#endif
m_cuChromaQpOffsetIdxPlus1 = ((uiLPelX >> lgMinCuSize) + (uiTPelY >> lgMinCuSize)) % (pps.getPpsRangeExtension().getChromaQpOffsetListLen() + 1);
}
//初始化当前CU的数据;
rpcTempCU->initEstData(uiDepth, iQP, bIsLosslessMode);
#if VCEG_AZ07_IMV && !JVET_C0024_QTBT
m_setInterCand.clear();
for (Int n = 0; n < NUMBER_OF_PART_SIZES; n++)
{
#if JVET_C0024_QTBT
m_pppcTempCUIMVCache[n][uiWidthIdx][uiHeightIdx]->initEstData(uiDepth, iQP, bIsLosslessMode);
#else
m_ppcTempCUIMVCache[n][uiDepth]->initEstData(uiDepth, iQP, bIsLosslessMode);
#endif
}
#endif
/////////////////////////////////////////帧间模式选择//////////////////////////////////////////////////
// do inter modes, SKIP and 2Nx2N
if (rpcBestCU->getSlice()->getSliceType() != I_SLICE)//不是I_SLICE,即不进行帧内预测;
{
#if JVET_D0077_SAVE_LOAD_ENC_INFO
#if VCEG_AZ07_FRUC_MERGE
Bool bFastSkipFruc = (saveLoadTag == LOAD_ENC_INFO && 0 == m_pcPredSearch->getSaveLoadFrucMode(uiWidthIdx, uiHeightIdx));
#endif
#if VCEG_AZ07_IMV
Bool bFastSkipIMV = (saveLoadTag == LOAD_ENC_INFO && (!m_pcPredSearch->getSaveLoadIMVFlag(uiWidthIdx, uiHeightIdx) || m_pcPredSearch->getSaveLoadMergeFlag(uiWidthIdx, uiHeightIdx)));
#endif
Bool bFastSkipInter = (saveLoadTag == LOAD_ENC_INFO && m_pcPredSearch->getSaveLoadMergeFlag(uiWidthIdx, uiHeightIdx));
#if COM16_C1016_AFFINE
Bool bFastSkipAffine = (saveLoadTag == LOAD_ENC_INFO && !m_pcPredSearch->getSaveLoadAffineFlag(uiWidthIdx, uiHeightIdx));
#endif
#endif
#if VCEG_AZ06_IC
for (UInt uiICId = 0; uiICId < (bICEnabled ? 2 : 1); uiICId++)
{
Bool bICFlag = uiICId ? true : false;
#endif
// 2Nx2N
if (m_pcEncCfg->getUseEarlySkipDetection()) //使用earlyDetectionSkipMode;
{
#if VCEG_AZ06_IC
rpcTempCU->setICFlagSubParts(bICFlag, 0, uiDepth);
#endif ////比较已有最佳模式与2N*2N Inter算出的TempRDcost的大小;
xCheckRDCostInter(rpcBestCU, rpcTempCU, SIZE_2Nx2N DEBUG_STRING_PASS_INTO(sDebug));
rpcTempCU->initEstData(uiDepth, iQP, bIsLosslessMode);//by Competition for inter_2Nx2N
}
// SKIP
#if VCEG_AZ06_IC
if (!bICFlag)
{
#endif
#if COM16_C1016_AFFINE
#if JVET_D0077_FAST_EXT
if (rpcTempCU->getSlice()->getSPS()->getUseAffine() && !bPrevSameBlockIsIntra
#if JVET_D0077_SAVE_LOAD_ENC_INFO
&& !bFastSkipAffine
#endif
)
#else
if (rpcTempCU->getSlice()->getSPS()->getUseAffine())
#endif
{//比较已有最佳模式与AffineMerge2Nx2N算出的tempRDcost的大小;
xCheckRDCostAffineMerge2Nx2N(rpcBestCU, rpcTempCU);//H.266新加的技术;
rpcTempCU->initEstData(uiDepth, iQP, bIsLosslessMode);
}
#endif
//比较已有最佳模式与Merge2N*2N算出的TempRdcost大小;
xCheckRDCostMerge2Nx2N(rpcBestCU, rpcTempCU DEBUG_STRING_PASS_INTO(sDebug), &earlyDetectionSkipMode);//by Merge for inter_2Nx2N
rpcTempCU->initEstData(uiDepth, iQP, bIsLosslessMode);
#if VCEG_AZ06_IC
}
#endif
#if VCEG_AZ07_FRUC_MERGE
#if JVET_D0077_FAST_EXT
if (rpcTempCU->getSlice()->getSPS()->getUseFRUCMgrMode() && !bPrevSameBlockIsIntra
#if JVET_D0077_SAVE_LOAD_ENC_INFO
&& !bFastSkipFruc
#endif
)
#else
if (rpcTempCU->getSlice()->getSPS()->getUseFRUCMgrMode())
#endif
{
#if VCEG_AZ06_IC
rpcTempCU->setICFlagSubParts(bICFlag, 0, uiDepth);
#endif //比较已有最佳模式与Merge2N*2NFRUC的TempRDcost的大小;
xCheckRDCostMerge2Nx2NFRUC(rpcBestCU, rpcTempCU, &earlyDetectionSkipMode);//也是H.266里新加的;
rpcTempCU->initEstData(uiDepth, iQP, bIsLosslessMode);
}
#endif
#if JVET_C0024_QTBT
#if JVET_D0077_FAST_EXT
if (!m_pcEncCfg->getUseEarlySkipDetection() && !bPrevSameBlockIsSkip && !bPrevSameBlockIsIntra
#if JVET_D0077_SAVE_LOAD_ENC_INFO
&& !bFastSkipInter
#if VCEG_AZ06_IC
&& !(saveLoadTag == LOAD_ENC_INFO && bICFlag != m_pcPredSearch->getSaveLoadICFlag(uiWidthIdx, uiHeightIdx))
#endif
#endif
#else
if (!m_pcEncCfg->getUseEarlySkipDetection() && !rpcBestCU->getPic()->getSkiped(rpcBestCU->getZorderIdxInCtu(), uiWidth, uiHeight)
&& !rpcBestCU->getPic()->getIntra(rpcBestCU->getZorderIdxInCtu(), uiWidth, uiHeight)
#endif
)
#else
if (!m_pcEncCfg->getUseEarlySkipDetection())
#endif
{
// 2Nx2N, NxN
#if VCEG_AZ06_IC
rpcTempCU->setICFlagSubParts(bICFlag, 0, uiDepth);
#endif //比较已有最佳模式与2N*2N Inter的TempRDcost的大小;
xCheckRDCostInter(rpcBestCU, rpcTempCU, SIZE_2Nx2N DEBUG_STRING_PASS_INTO(sDebug));
rpcTempCU->initEstData(uiDepth, iQP, bIsLosslessMode);
#if !JVET_C0024_QTBT
if (m_pcEncCfg->getUseCbfFastMode())
{
doNotBlockPu = rpcBestCU->getQtRootCbf(0) != 0;
}
#endif
}
#if VCEG_AZ06_IC
}
#endif
#if VCEG_AZ07_IMV && JVET_D0077_SAVE_LOAD_ENC_INFO
#if JVET_D0077_FAST_EXT
if (m_pcEncCfg->getIMV() && !rpcBestCU->getSlice()->isIntra() && !bPrevSameBlockIsIntra && !bPrevSameBlockIsSkip
#if JVET_D0077_SAVE_LOAD_ENC_INFO
&& !bFastSkipIMV
#endif
)
#else
if (m_pcEncCfg->getIMV() && !rpcBestCU->getSlice()->isIntra())
#endif
{
#if JVET_E0076_MULTI_PEL_MVD
for (UChar iMv = 1; iMv < 3; iMv++)
{
if (iMv == 2 && m_dBestMvDPelCost[0] * 1.06 < m_dBestMvDPelCost[1])
{
break;
}
#if VCEG_AZ06_IC
for (UInt uiICId = 0; uiICId < (bICEnabled ? 2 : 1); uiICId++)
{
Bool bICFlag = uiICId ? true : false;
#if JVET_D0077_SAVE_LOAD_ENC_INFO
if (saveLoadTag == LOAD_ENC_INFO && bICFlag != m_pcPredSearch->getSaveLoadICFlag(uiWidthIdx, uiHeightIdx))
{
continue;
}
#endif
rpcTempCU->setICFlagSubParts(bICFlag, 0, uiDepth);
#endif
xCheckRDCostInter(rpcBestCU, rpcTempCU, SIZE_2Nx2N, false, iMv);
rpcTempCU->initEstData(uiDepth, iQP, bIsLosslessMode);
#if VCEG_AZ06_IC
}
#endif
}
#else
// always check SIZE_2Nx2N
#if VCEG_AZ06_IC
for (UInt uiICId = 0; uiICId < (bICEnabled ? 2 : 1); uiICId++)
{
Bool bICFlag = uiICId ? true : false;
#if JVET_D0077_SAVE_LOAD_ENC_INFO
if (saveLoadTag == LOAD_ENC_INFO && bICFlag != m_pcPredSearch->getSaveLoadICFlag(uiWidthIdx, uiHeightIdx))
{
continue;
}
#endif
rpcTempCU->setICFlagSubParts(bICFlag, 0, uiDepth);
#endif
xCheckRDCostInter(rpcBestCU, rpcTempCU, SIZE_2Nx2N, false, true);
rpcTempCU->initEstData(uiDepth, iQP, bIsLosslessMode);
#if VCEG_AZ06_IC
}
#endif
#endif
}
#endif
}
if (bIsLosslessMode) // Restore loop variable if lossless mode was searched.
{
iQP = iMinQP;
}
}
//////////////////////////////////////QP循环结束////////////////////////////////////////////////////
#if VCEG_AZ06_IC
#if !JVET_C0024_QTBT
Bool bTestICNon2Nx2N = bICEnabled && rpcBestCU->getICFlag(0);
#if VCEG_AZ06_IC_SPEEDUP
bTestICNon2Nx2N = false;
#endif
#endif
#endif
//=========================earlyDetectionSkipMode==========================
if (!earlyDetectionSkipMode)
{
// 在实际的处理过程当中,对LCU的划分都是以4x4大小的块进行划分的,
//这是为了处理方便,然后以Z扫描的方式进行扫描,这也是为了方便递归;
////////////////////////从最小QP到最大QP遍历每一个QP,执行下面步骤,选出一个最优QP////////////////////
for (Int iQP = iMinQP; iQP <= iMaxQP; iQP++)
{
const Bool bIsLosslessMode = isAddLowestQP && (iQP == iMinQP); // If lossless, then iQP is irrelevant for subsequent modules.
if (bIsLosslessMode)//判断是否为无损模式;
{
iQP = lowestQP;
}
//初始化当前CU的数据;
rpcTempCU->initEstData(uiDepth, iQP, bIsLosslessMode);
//==============帧内模式选择==============================
// do normal intra modes
// speedup for inter frames
Double intraCost = 0.0;
#if COM16_C806_EMT
if (rpcBestCU->getSlice()->getSliceType() != I_SLICE && m_pcEncCfg->getUseFastInterEMT())
{
dBestInterCost = rpcBestCU->getTotalCost();
}
#endif
//如果帧内的类型是I_SLICE,则进行帧内模式选择;
if ((rpcBestCU->getSlice()->getSliceType() == I_SLICE) ||
#if JVET_C0024_QTBT
((!m_pcEncCfg->getDisableIntraPUsInInterSlices()) && (!rpcBestCU->getPic()->getInter(rpcBestCU->getZorderIdxInCtu(), uiWidth, uiHeight)) && (
#else
((!m_pcEncCfg->getDisableIntraPUsInInterSlices()) && (
#endif
(rpcBestCU->getCbf(0, COMPONENT_Y) != 0) ||
((rpcBestCU->getCbf(0, COMPONENT_Cb) != 0) && (numberValidComponents > COMPONENT_Cb)) ||
((rpcBestCU->getCbf(0, COMPONENT_Cr) != 0) && (numberValidComponents > COMPONENT_Cr)) // avoid very complex intra if it is unlikely
)))
{
#if VCEG_AZ05_ROT_TR || VCEG_AZ05_INTRA_MPI || COM16_C1044_NSST || COM16_C1046_PDPC_INTRA
Int bNonZeroCoeff = 0;
#endif
#if VCEG_AZ05_INTRA_MPI
Char iMPIidx = 0; Char iNumberOfPassesMPI = 2;
if (rpcTempCU->getSlice()->getSliceType() != I_SLICE) iNumberOfPassesMPI = 2;
if (!rpcTempCU->getSlice()->getSPS()->getUseMPI()) iNumberOfPassesMPI = 1;
#if JVET_C0024_QTBT
if (isChroma(rpcBestCU->getTextType()))
{
iNumberOfPassesMPI = 1;
}
#endif
#endif
#if JVET_C0024_PBINTRA_FAST
rpcTempCU->getInterHAD() = MAX_UINT;
if (rpcBestCU->getPredictionMode(0) == MODE_INTER && !rpcBestCU->getSlice()->isIntra())
{
// redundant MC process to make sure that m_pppcPredYuvBest has the correct moiton compensation prediction data
#if JVET_E0052_DMVR
m_pcPredSearch->motionCompensation(rpcBestCU, m_pppcPredYuvBest[uiWidthIdx][uiHeightIdx], false);
#if COM16_C806_OBMC
m_pcPredSearch->subBlockOBMC(rpcBestCU, 0, m_pppcPredYuvBest[uiWidthIdx][uiHeightIdx], m_pppcTmpYuv1[uiWidthIdx][uiHeightIdx], m_pppcTmpYuv2[uiWidthIdx][uiHeightIdx], false);
#endif
#else
m_pcPredSearch->motionCompensation(rpcBestCU, m_pppcPredYuvBest[uiWidthIdx][uiHeightIdx]);
#if COM16_C806_OBMC
m_pcPredSearch->subBlockOBMC(rpcBestCU, 0, m_pppcPredYuvBest[uiWidthIdx][uiHeightIdx], m_pppcTmpYuv1[uiWidthIdx][uiHeightIdx], m_pppcTmpYuv2[uiWidthIdx][uiHeightIdx]);
#endif
#endif
DistParam distParam;
const Bool bUseHadamard = rpcTempCU->getCUTransquantBypass(0) == 0;
m_pcRdCost->setDistParam(distParam, rpcTempCU->getSlice()->getSPS()->getBitDepth(CHANNEL_TYPE_LUMA), m_pppcOrigYuv[uiWidthIdx][uiHeightIdx]->getAddr(COMPONENT_Y)
, m_pppcOrigYuv[uiWidthIdx][uiHeightIdx]->getStride(COMPONENT_Y)
, m_pppcPredYuvBest[uiWidthIdx][uiHeightIdx]->getAddr(COMPONENT_Y), m_pppcPredYuvBest[uiWidthIdx][uiHeightIdx]->getStride(COMPONENT_Y)
, rpcTempCU->getWidth(0), rpcTempCU->getHeight(0), bUseHadamard);
distParam.bApplyWeight = false;
UInt uiSad = distParam.DistFunc(&distParam);
rpcTempCU->getInterHAD() = uiSad;
}
#endif
#if COM16_C1046_PDPC_INTRA && !JVET_G0104_PLANAR_PDPC
Char iPDPCidx = 0; Char iNumberOfPassesPDPC = 2;
if (rpcTempCU->getSlice()->getSliceType() != I_SLICE) iNumberOfPassesPDPC = 2;
if (!rpcTempCU->getSlice()->getSPS()->getUsePDPC()) iNumberOfPassesPDPC = 1;
#if JVET_C0024_QTBT
if (isChroma(rpcBestCU->getTextType()))
{
iNumberOfPassesPDPC = 1;
}
#endif
#endif
#if VCEG_AZ05_ROT_TR || COM16_C1044_NSST
Char iROTidx = 0; Char iNumberOfPassesROT = 4;
#if JVET_C0024_QTBT
if (isChroma(rpcBestCU->getTextType()) && !(uiWidth >= 8 && uiHeight >= 8))
{
iNumberOfPassesROT = 1;
}
#endif
#if COM16_C1044_NSST
if (!rpcTempCU->getSlice()->getSPS()->getUseNSST()) iNumberOfPassesROT = 1;
#else
if (!rpcTempCU->getSlice()->getSPS()->getUseROT()) iNumberOfPassesROT = 1;
#endif
/////////////////////////////此for循环由此开始,执行4次xCheckRDcostIntra循环////////////////////////////
for (iROTidx = 0; iROTidx < iNumberOfPassesROT; iROTidx++)
{
#if JVET_D0077_SAVE_LOAD_ENC_INFO
if (saveLoadTag == LOAD_ENC_INFO && iROTidx && iROTidx != m_pcPredSearch->getSaveLoadRotIdx(uiWidthIdx, uiHeightIdx))
{
continue;
}
#endif
#endif
#if VCEG_AZ05_INTRA_MPI
#if VCEG_AZ05_ROT_TR || COM16_C1044_NSST
if (iROTidx) iNumberOfPassesMPI = 1;
#endif
for (iMPIidx = 0; iMPIidx < iNumberOfPassesMPI; iMPIidx++)
{
#endif
#if COM16_C1046_PDPC_INTRA && !JVET_G0104_PLANAR_PDPC
#if VCEG_AZ05_ROT_TR || COM16_C1044_NSST
if (iROTidx) iNumberOfPassesPDPC = 1;
#endif
for (iPDPCidx = 0; iPDPCidx < iNumberOfPassesPDPC; iPDPCidx++)
{
#if JVET_D0077_SAVE_LOAD_ENC_INFO
if (CHANNEL_TYPE_LUMA == eChannelType && saveLoadTag == LOAD_ENC_INFO && iPDPCidx != m_pcPredSearch->getSaveLoadPdpcIdx(uiWidthIdx, uiHeightIdx))
{
continue;
}
#endif
#endif
#if COM16_C806_EMT
#if JVET_C0024_QTBT
UChar ucEmtUsage = (uiWidth > EMT_INTRA_MAX_CU || uiHeight > EMT_INTRA_MAX_CU || (rpcTempCU->getSlice()->getSPS()->getUseIntraEMT() == 0) || isChroma(rpcBestCU->getTextType())) ? 1 : 2;
#else
UChar ucEmtUsage = ((rpcTempCU->getWidth(0) > EMT_INTRA_MAX_CU) || (rpcTempCU->getSlice()->getSPS()->getUseIntraEMT() == 0)) ? 1 : 2;
#endif
//////////////////////////EMT使用次数//////////////////////////////////////////
for (UChar ucCuFlag = 0; ucCuFlag < ucEmtUsage; ucCuFlag++)
{
#if JVET_D0077_SAVE_LOAD_ENC_INFO
if (saveLoadTag == LOAD_ENC_INFO && /*ucCuFlag && */ucCuFlag != m_pcPredSearch->getSaveLoadEmtFlag(uiWidthIdx, uiHeightIdx))
{
continue;
}
#endif
if (ucCuFlag && bEarlySkipIntra && m_pcEncCfg->getUseFastInterEMT())
{
continue;
}
rpcTempCU->setEmtCuFlagSubParts(ucCuFlag, 0, uiDepth);
#if VCEG_AZ05_INTRA_MPI
rpcTempCU->setMPIIdxSubParts(iMPIidx, 0, uiDepth);
#endif
#if COM16_C1046_PDPC_INTRA && !JVET_G0104_PLANAR_PDPC
rpcTempCU->setPDPCIdxSubParts(iPDPCidx, 0, uiDepth);
#endif
#if VCEG_AZ05_ROT_TR || COM16_C1044_NSST
#if JVET_C0024_QTBT
rpcTempCU->setROTIdxSubParts(rpcTempCU->getTextType(), iROTidx, 0, uiDepth);
if (!rpcTempCU->getSlice()->isIntra())
{
rpcTempCU->setROTIdxSubParts(CHANNEL_TYPE_CHROMA, iROTidx, 0, uiDepth);
}
#else
rpcTempCU->setROTIdxSubParts(iROTidx, 0, uiDepth);
#endif
#endif
#if JVET_C0024_PBINTRA_FAST
if (rpcBestCU->getPredictionMode(0) == MODE_INTER && !rpcBestCU->getSlice()->isIntra())
{
if (rpcTempCU->getInterHAD() == 0)
{
continue; //has calculated the best intra HAD much larger than that of inter; so skip intra mode RDO
}
}
#endif
//比较已有最佳模式与2Nx2N Intra的TempRDcost的大小;
xCheckRDCostIntra(rpcBestCU, rpcTempCU, intraCost, SIZE_2Nx2N DEBUG_STRING_PASS_INTO(sDebug)
#if VCEG_AZ05_ROT_TR || VCEG_AZ05_INTRA_MPI || COM16_C1044_NSST || COM16_C1046_PDPC_INTRA
, bNonZeroCoeff
#endif
);
if (!ucCuFlag && !rpcBestCU->isIntra(0) && m_pcEncCfg->getUseFastInterEMT()
#if JVET_D0077_SAVE_LOAD_ENC_INFO
&& dBestInterCost < MAX_DOUBLE
#endif
)
{
static const Double thEmtInterFastSkipIntra = 1.4; // Skip checking Intra if "2Nx2N using DCT2" is worse than best Inter mode
if (rpcTempCU->getTotalCost() > thEmtInterFastSkipIntra*dBestInterCost)
{
bEarlySkipIntra = true;
}
}
if (!ucCuFlag && m_pcEncCfg->getUseFastIntraEMT())
{
#if JVET_C0024_QTBT
//dIntra2Nx2NCost = rpcBestCU->isIntra(0) ? rpcBestCU->getTotalCost() : rpcTempCU->getTotalCost();
#else
dIntra2Nx2NCost = (rpcBestCU->isIntra(0) && rpcBestCU->getPartitionSize(0) == SIZE_2Nx2N) ? rpcBestCU->getTotalCost() : rpcTempCU->getTotalCost();
#endif
}
rpcTempCU->initEstData(uiDepth, iQP, bIsLosslessMode);
}
////////////////////////EMTUsage循环结束/////////////////////////////////
#if VCEG_AZ05_ROT_TR || COM16_C1044_NSST
if (rpcBestCU->isIntra(0) && !bNonZeroCoeff) break;
//if (bNonZeroCoeff>rpcTempCU->getWidth(0)*rpcTempCU->getHeight(0) && rpcTempCU->getSlice()->getSliceType() == I_SLICE) break;
}
//////////////////////////////////iNumberOfPassesROT循环在这里结束////////////////////////////////////
// test PCM,尝试PCM模式;
if (sps.getUsePCM()//PCM模式,在该模式下,编码器直接传输一个CU的像素值,而不经过预测,变换等其他操作;
&& rpcTempCU->getWidth(0) <= (1 << sps.getPCMLog2MaxSize())
&& rpcTempCU->getWidth(0) >= (1 << sps.getPCMLog2MinSize()))
{
UInt uiRawBits = getTotalBits(rpcBestCU->getWidth(0), rpcBestCU->getHeight(0), rpcBestCU->getPic()->getChromaFormat(), sps.getBitDepths().recon);
UInt uiBestBits = rpcBestCU->getTotalBits();
if ((uiBestBits > uiRawBits) || (rpcBestCU->getTotalCost() > m_pcRdCost->calcRdCost(uiRawBits, 0)))
{//比较已有最佳模式与PCM算出的TempRDcost的大小;
xCheckIntraPCM(rpcBestCU, rpcTempCU);
rpcTempCU->initEstData(uiDepth, iQP, bIsLosslessMode);
}
}
if (bIsLosslessMode) // Restore loop variable if lossless mode was searched.
{
iQP = iMinQP;
}
}
/////////////////////////////////遍历QP结束//////////////////////////////////////////////
}
//===============earlyDetectionSkipMode条件判断结束=======================
#if VCEG_AZ08_INTER_KLT
#if VCEG_AZ08_USE_KLT
if (sps.getUseInterKLT())//JEM中新加的;
{
#endif
if (!rpcBestCU->isIntra(0) && rpcBestCU->getQtRootCbf(0) != 0)
{
//Only check from the best modes for speeding up
g_bEnableCheck = true;
Int iQP = rpcBestCU->getQP(0);
#if JVET_C0024_QTBT
xCheckRDCostInterKLT(rpcBestCU, rpcTempCU, SIZE_2Nx2N);//JEM里新加的技术;
#else
PartSize eSize = rpcBestCU->getPartitionSize(0);
xCheckRDCostInterKLT(rpcBestCU, rpcTempCU, eSize);
#endif
rpcTempCU->initEstData(uiDepth, iQP, false);
}
#if VCEG_AZ08_USE_KLT
}
#endif
#endif
#if JVET_C0024_QTBT
if (rpcBestCU->getTotalCost() < MAX_DOUBLE - 1)
#else
if (rpcBestCU->getTotalCost() != MAX_DOUBLE)
#endif
{
#if JVET_C0024_QTBT
m_pcRDGoOnSbacCoder->load(m_ppppcRDSbacCoder[uiWidthIdx][uiHeightIdx][CI_NEXT_BEST]);
#else
m_pcRDGoOnSbacCoder->load(m_pppcRDSbacCoder[uiDepth][CI_NEXT_BEST]);
#endif
m_pcEntropyCoder->resetBits();//重置熵编码器的比特数;
#if JVET_C0024_QTBT
if (uiBTSplitMode == 0)
{
#endif
m_pcEntropyCoder->encodeSplitFlag(rpcBestCU, 0, uiDepth, true);//编码split标志;
#if JVET_C0024_QTBT
}
#if JVET_C0024_SPS_MAX_BT_DEPTH
UInt uiMaxBTD = pcSlice->isIntra() ? (isLuma(rpcTempCU->getTextType()) ? sps.getMaxBTDepthISliceL() : sps.getMaxBTDepthISliceC()) : sps.getMaxBTDepth();
#else
UInt uiMaxBTD = pcSlice->isIntra() ? (isLuma(rpcTempCU->getTextType()) ? MAX_BT_DEPTH : MAX_BT_DEPTH_C) : MAX_BT_DEPTH_INTER;
#endif
#if JVET_C0024_SPS_MAX_BT_SIZE
UInt uiMaxBTSize = pcSlice->isIntra() ? (isLuma(rpcTempCU->getTextType()) ? sps.getMaxBTSizeISliceL() : sps.getMaxBTSizeISliceC()) : sps.getMaxBTSize();
#else
UInt uiMaxBTSize = isLuma(rpcTempCU->getTextType()) ? pcSlice->getMaxBTSize() : MAX_BT_SIZE_C;
#endif
UInt uiMinBTSize = pcSlice->isIntra() ? (isLuma(rpcTempCU->getTextType()) ? MIN_BT_SIZE : MIN_BT_SIZE_C) : MIN_BT_SIZE_INTER;
if (rpcBestCU->getWidth(0) <= uiMaxBTSize && rpcBestCU->getHeight(0) <= uiMaxBTSize
&& (rpcBestCU->getWidth(0) > uiMinBTSize || rpcBestCU->getHeight(0) > uiMinBTSize)
&& rpcBestCU->getBTDepth(0) < uiMaxBTD)
{
m_pcEntropyCoder->encodeBTSplitMode(rpcBestCU, 0, rpcBestCU->getWidth(0), rpcBestCU->getHeight(0), true);
}
#endif//统计总的比特数,二进制数和总的率失真代价;
rpcBestCU->getTotalBits() += m_pcEntropyCoder->getNumberOfWrittenBits(); // split bits
rpcBestCU->getTotalBins() += ((TEncBinCABAC *)((TEncSbac*)m_pcEntropyCoder->m_pcEntropyCoderIf)->getEncBinIf())->getBinsCoded();
rpcBestCU->getTotalCost() = m_pcRdCost->calcRdCost(rpcBestCU->getTotalBits(), rpcBestCU->getTotalDistortion());
#if JVET_C0024_QTBT
m_pcRDGoOnSbacCoder->store(m_ppppcRDSbacCoder[uiWidthIdx][uiHeightIdx][CI_NEXT_BEST]);
#else
m_pcRDGoOnSbacCoder->store(m_pppcRDSbacCoder[uiDepth][CI_NEXT_BEST]);
#endif
#if JVET_D0077_SAVE_LOAD_ENC_INFO
if (saveLoadTag == SAVE_ENC_INFO)
{
#if COM16_C806_EMT
m_pcPredSearch->setSaveLoadEmtFlag(uiWidthIdx, uiHeightIdx, rpcBestCU->getEmtCuFlag(0));
m_pcPredSearch->setSaveLoadEmtIdx(uiWidthIdx, uiHeightIdx, rpcBestCU->getEmtTuIdx(0));
#endif
#if VCEG_AZ05_ROT_TR || COM16_C1044_NSST
m_pcPredSearch->setSaveLoadRotIdx(uiWidthIdx, uiHeightIdx, rpcBestCU->getROTIdx(rpcBestCU->getTextType(), 0));
#endif
#if COM16_C1046_PDPC_INTRA && !JVET_G0104_PLANAR_PDPC
m_pcPredSearch->setSaveLoadPdpcIdx(uiWidthIdx, uiHeightIdx, rpcBestCU->getPDPCIdx(0));
#endif
if (!rpcBestCU->isIntra(0))
{
#if VCEG_AZ07_FRUC_MERGE
m_pcPredSearch->setSaveLoadFrucMode(uiWidthIdx, uiHeightIdx, rpcBestCU->getFRUCMgrMode(0));
#endif
#if VCEG_AZ07_IMV
m_pcPredSearch->setSaveLoadIMVFlag(uiWidthIdx, uiHeightIdx, rpcBestCU->getiMVFlag(0));
#endif
#if VCEG_AZ06_IC
m_pcPredSearch->setSaveLoadICFlag(uiWidthIdx, uiHeightIdx, rpcBestCU->getICFlag(0));
#endif
m_pcPredSearch->setSaveLoadMergeFlag(uiWidthIdx, uiHeightIdx, rpcBestCU->getMergeFlag(0));
#if COM16_C1016_AFFINE
m_pcPredSearch->setSaveLoadAffineFlag(uiWidthIdx, uiHeightIdx, rpcBestCU->getAffineFlag(0));
#endif
m_pcPredSearch->setSaveLoadInterDir(uiWidthIdx, uiHeightIdx, rpcBestCU->getInterDir(0));
}
dNonSplitCost = dCostTempBest = rpcBestCU->getTotalCost();
m_pcPredSearch->setSaveLoadTag(uiZorderIdx, uiWidthIdx, uiHeightIdx, LOAD_ENC_INFO);
}
#endif
}
#if JVET_C0024_DELTA_QP_FIX
if (pps.getUseDQP())
{
rpcBestCU->setCodedQP(rpcBestCU->getQP(0));
}
#endif
}
#if JVET_C0024_QTBT && COM16_C806_LARGE_CTU
if (ucMinDepth > uiDepth)
{
bBoundary = true; //to force not to try BT split. JCA
}
#endif
// copy original YUV samples to PCM buffer
if( rpcBestCU->getTotalCost()!=MAX_DOUBLE && rpcBestCU->isLosslessCoded(0) && (rpcBestCU->getIPCMFlag(0) == false))
{
#if JVET_C0024_QTBT
xFillPCMBuffer(rpcBestCU, m_pppcOrigYuv[uiWidthIdx][uiHeightIdx]);
#else
xFillPCMBuffer(rpcBestCU, m_ppcOrigYuv[uiDepth]);
#endif
}
#if JVET_C0024_DELTA_QP_FIX
if( uiQTBTDepth == uiMaxDQPDepthQTBT )
#else
if( uiDepth == pps.getMaxCuDQPDepth() )
#endif
{
Int idQP = m_pcEncCfg->getMaxDeltaQP();
iMinQP = Clip3( -sps.getQpBDOffset(CHANNEL_TYPE_LUMA), MAX_QP, iBaseQP-idQP );
iMaxQP = Clip3( -sps.getQpBDOffset(CHANNEL_TYPE_LUMA), MAX_QP, iBaseQP+idQP );
}
#if JVET_C0024_DELTA_QP_FIX
else if( uiQTBTDepth < uiMaxDQPDepthQTBT )
#else
else if( uiDepth < pps.getMaxCuDQPDepth() )
#endif
{
iMinQP = iBaseQP;
iMaxQP = iBaseQP;
}
else
{
const Int iStartQP = rpcTempCU->getQP(0);
iMinQP = iStartQP;
iMaxQP = iStartQP;
}
if ( m_pcEncCfg->getUseRateCtrl() )
{
iMinQP = m_pcRateCtrl->getRCQP();
iMaxQP = m_pcRateCtrl->getRCQP();
}
if ( m_pcEncCfg->getCUTransquantBypassFlagForceValue() )
{
iMaxQP = iMinQP; // If all TUs are forced into using transquant bypass, do not loop here.
}
const Bool bSubBranch = bBoundary ||
#if COM16_C806_LARGE_CTU
( !( m_pcEncCfg->getUseEarlyCU() && rpcBestCU->getTotalCost()!=MAX_DOUBLE && rpcBestCU->isSkipped(0) ) && ( !m_pcEncCfg->getUseFastLCTU() || uiDepth < ucMaxDepth ) );
#else
!( m_pcEncCfg->getUseEarlyCU() && rpcBestCU->getTotalCost()!=MAX_DOUBLE && rpcBestCU->isSkipped(0) );
#endif
#if JVET_C0024_BT_RMV_REDUNDANT
bQTreeValid = false;
if( uiBTSplitMode == 0 )// 如果二叉树水平分割模式为0(水平分割);
{
UInt uiMinQTSize = sps.getMinQTSize(rpcBestCU->getSlice()->getSliceType(), rpcBestCU->getTextType());
bQTreeValid = ( uiWidth>=2*uiMinQTSize );
}
Bool bBTHorRmvEnable = false;
Bool bBTVerRmvEnable = false;
if (rpcBestCU->getSlice()->getSliceType() != I_SLICE)
{
bBTHorRmvEnable = true;
bBTVerRmvEnable = bQTreeValid;
}
#endif
#if JVET_C0024_QTBT
Bool bQTSplit = bSubBranch && uiBTSplitMode==0 && (!getFastDeltaQp() || uiWidth > fastDeltaQPCuMaxSize || bBoundary);
if (bQTSplit)//四叉树分割;
{
assert(uiWidth==uiHeight);
}
bQTSplit = bQTSplit && (uiWidth>sps.getMinQTSize(pcSlice->getSliceType(), rpcBestCU->getTextType()) || bBoundary);
if (!bBoundary && rpcBestCU->isSkipped(0))
{
rpcBestCU->getPic()->setSkiped(rpcBestCU->getZorderIdxInCtu(), uiWidth, uiHeight, true);
}
if (!bBoundary && rpcBestCU->getPredictionMode(0)==MODE_INTER)
{
rpcBestCU->getPic()->setInter(rpcBestCU->getZorderIdxInCtu(), uiWidth, uiHeight, true);
}
else if (!bBoundary && rpcBestCU->getPredictionMode(0)==MODE_INTRA)
{
rpcBestCU->getPic()->setIntra(rpcBestCU->getZorderIdxInCtu(), uiWidth, uiHeight, true);
}
#if !JVET_C0024_DELTA_QP_FIX
UInt uiQTWidth = sps.getCTUSize()>>uiDepth;
UInt uiQTHeight = sps.getCTUSize()>>uiDepth;
UInt uiBTDepth = g_aucConvertToBit[uiQTWidth]-g_aucConvertToBit[uiWidth] + g_aucConvertToBit[uiQTHeight]-g_aucConvertToBit[uiHeight];
#endif
#if JVET_C0024_SPS_MAX_BT_DEPTH
UInt uiMaxBTD = pcSlice->isIntra() ? (isLuma(rpcTempCU->getTextType())?sps.getMaxBTDepthISliceL():sps.getMaxBTDepthISliceC()): sps.getMaxBTDepth();
#else
UInt uiMaxBTD = pcSlice->isIntra() ? (isLuma(rpcTempCU->getTextType())?MAX_BT_DEPTH:MAX_BT_DEPTH_C): MAX_BT_DEPTH_INTER;
#endif
#if JVET_C0024_SPS_MAX_BT_SIZE
UInt uiMaxBTSize = pcSlice->isIntra() ? (isLuma(rpcTempCU->getTextType())?sps.getMaxBTSizeISliceL():sps.getMaxBTSizeISliceC()): sps.getMaxBTSize();
#else
UInt uiMaxBTSize = isLuma(rpcTempCU->getTextType()) ? pcSlice->getMaxBTSize(): MAX_BT_SIZE_C;//32;
#endif
UInt uiMinBTSize = pcSlice->isIntra() ? (isLuma(rpcTempCU->getTextType())?MIN_BT_SIZE:MIN_BT_SIZE_C): MIN_BT_SIZE_INTER;
Bool bTestHorSplit = (!bBoundary && uiHeight>uiMinBTSize
&& uiWidth<=uiMaxBTSize && uiHeight<=uiMaxBTSize && uiBTDepthuiMinBTSize
&& uiWidth<=uiMaxBTSize && uiHeight<=uiMaxBTSize && uiBTDepthgetSkipFlag(0) && (bTestHorSplit || bTestVerSplit) && uiBTDepth >= ((pcSlice->getPictureDistance() <= PICTURE_DISTANCE_TH) ? FAST_SKIP_DEPTH : SKIP_DEPTH))
#else
if (rpcBestCU->getSkipFlag(0) && (bTestHorSplit || bTestVerSplit) && uiBTDepth>=SKIP_DEPTH)
#endif
{
bTestHorSplit = bTestVerSplit = bQTSplit = false;
}
#if JVET_C0024_BT_RMV_REDUNDANT
if( uiSplitConstrain == 1 )
{
bTestHorSplit = false;
}
if( uiSplitConstrain == 2 )
{
bTestVerSplit = false;
}
#endif
#if JVET_D0077_SAVE_LOAD_ENC_INFO
if( bUseSaveLoad )
{
m_pcPredSearch->setSaveLoadTag( uiZorderIdx, uiWidthIdx-1, uiHeightIdx-1, SAVE_ENC_INFO );
}
#endif
#if JVET_D0077_SAVE_LOAD_ENC_INFO
if( bUseSaveLoadSplitDecision && saveLoadTag == LOAD_ENC_INFO )
{
if( bTestHorSplit && (saveLoadSplit & 0x02) )
{
bTestHorSplit = false;
}
if( bTestVerSplit && (saveLoadSplit & 0x04) )
{
bTestVerSplit = false;
}
}
#endif
//////////////////////////水平二叉树划分//////////////////////////////////////////////////////
if (bTestHorSplit) //如果要进行二叉树水平划分;
{
// further split
//================遍历每一个QP,执行下面步骤,选取最优的QP=====================
for (Int iQP=iMinQP; iQP<=iMaxQP; iQP++)
{
const Bool bIsLosslessMode = false; // False at this level. Next level down may set it to true.
//以4*4的方式初始化临时CU;
rpcTempCU->initEstData( uiDepth, iQP, bIsLosslessMode );
UChar uhNextDepth = uiDepth;
UInt uiBTWidthIdx = g_aucConvertToBit[uiWidth];
UInt uiBTHeightIdx = g_aucConvertToBit[uiHeight>>1];
TComDataCU* pcSubBestPartCU = m_pppcBestCU[uiBTWidthIdx][uiBTHeightIdx];//对子最佳CU进行初始化;
TComDataCU* pcSubTempPartCU = m_pppcTempCU[uiBTWidthIdx][uiBTHeightIdx];//对子临时CU进行初始化;
rpcTempCU->setBTSplitModeSubParts(1, 0, uiWidth, uiHeight);
#if JVET_C0024_BT_RMV_REDUNDANT
uiSplitConstrain = 0;
#endif
#if JVET_C0024_DELTA_QP_FIX
if( pps.getUseDQP() ) // inherit quantization group info. from parent CU.
{
pcSubBestPartCU->initSubBT( rpcTempCU, 0, uiDepth, uiWidth, uiHeight>>1, 1, iQP );
pcSubTempPartCU->initSubBT( rpcTempCU, 0, uiDepth, uiWidth, uiHeight>>1, 1, iQP ); // clear sub partition datas or init.
pcSubBestPartCU->setCodedQP( lastCodedQP );
pcSubTempPartCU->setCodedQP( lastCodedQP );
pcSubBestPartCU->setQuPartIdx( rpcTempCU->getQuPartIdx() );
pcSubTempPartCU->setQuPartIdx( rpcTempCU->getQuPartIdx() );
pcSubBestPartCU->setQuLastCodedQP( rpcTempCU->getQuLastCodedQP() );
pcSubTempPartCU->setQuLastCodedQP( rpcTempCU->getQuLastCodedQP() );
}
#endif
////////////////////遍历子CU///////////////////////////////
for ( UInt uiPartUnitIdx = 0; uiPartUnitIdx < 2; uiPartUnitIdx++ )//等于2是因为进行了二叉树划分;
{
//子CU的最佳CU,初始化,以4*4的方式初始化;
pcSubBestPartCU->initSubBT( rpcTempCU, uiPartUnitIdx, uiDepth, uiWidth, uiHeight>>1, 1, iQP );
pcSubTempPartCU->initSubBT( rpcTempCU, uiPartUnitIdx, uiDepth, uiWidth, uiHeight>>1, 1, iQP ); // clear sub partition datas or init.
#if VCEG_AZ07_IMV && !JVET_C0024_QTBT
for( Int size = 0 ; size < NUMBER_OF_PART_SIZES ; size++ )
{
m_pppcTempCUIMVCache[size][uiBTWidthIdx][uiBTHeightIdx]->initSubBT( rpcTempCU, uiPartUnitIdx, uiDepth, uiWidth, uiHeight>>1, 1, iQP );
}
#endif
#if COM16_C806_OBMC
m_pppcTempCUWoOBMC[uiBTWidthIdx][uiBTHeightIdx]->initSubBT( rpcTempCU, uiPartUnitIdx, uiDepth, uiWidth, uiHeight>>1, 1, iQP ); // clear sub partition datas or init.
#endif
#if VCEG_AZ07_FRUC_MERGE
m_pppcFRUCBufferCU[uiBTWidthIdx][uiBTHeightIdx]->initSubBT( rpcTempCU, uiPartUnitIdx, uiDepth, uiWidth, uiHeight>>1, 1, iQP );
#endif
if(( pcSubBestPartCU->getCUPelX() < pcSlice->getSPS()->getPicWidthInLumaSamples() ) && ( pcSubBestPartCU->getCUPelY() < pcSlice->getSPS()->getPicHeightInLumaSamples() ) )
{
if ( 0 == uiPartUnitIdx) //initialize RD with previous depth buffer
{
m_ppppcRDSbacCoder[uiWidthIdx][uiHeightIdx-1][CI_CURR_BEST]->load(m_ppppcRDSbacCoder[uiWidthIdx][uiHeightIdx][CI_CURR_BEST]);
}
else
{
m_ppppcRDSbacCoder[uiWidthIdx][uiHeightIdx-1][CI_CURR_BEST]->load(m_ppppcRDSbacCoder[uiWidthIdx][uiHeightIdx-1][CI_NEXT_BEST]);
}
#if JVET_C0024_BT_RMV_REDUNDANT//对子CU递归调用xCompressCU;
xCompressCU( pcSubBestPartCU, pcSubTempPartCU, uiDepth, uiWidth, uiHeight>>1, pcSubBestPartCU->getBTSplitMode(0), uiSplitConstrain );
if( uiPartUnitIdx == 0 && pcSubBestPartCU->getBTSplitModeForBTDepth(0, uiBTDepth+1) == 2 && bBTHorRmvEnable )
{
uiSplitConstrain = 2;
}
#else
xCompressCU( pcSubBestPartCU, pcSubTempPartCU, uiDepth, uiWidth, uiHeight>>1, pcSubBestPartCU->getBTSplitMode(0) );
#endif //将子CU的最佳预测数据复制到TempCU中;
rpcTempCU->copyPartFrom( pcSubBestPartCU, uiPartUnitIdx, uhNextDepth, uiWidth, uiHeight>>1 ); // Keep best part data to current temporary data.
#if JVET_C0024_DELTA_QP_FIX
if( pps.getUseDQP() ) // update coded QP
{
rpcTempCU->setCodedQP( pcSubBestPartCU->getCodedQP() );
pcSubBestPartCU->setCodedQP( rpcTempCU->getCodedQP() );
pcSubTempPartCU->setCodedQP( rpcTempCU->getCodedQP() );
}
#endif
xCopyYuv2Tmp( pcSubBestPartCU->getZorderIdxInCtu()-rpcTempCU->getZorderIdxInCtu(), uiWidth, uiHeight, 1 );
}
}
m_pcRDGoOnSbacCoder->load(m_ppppcRDSbacCoder[uiWidthIdx][uiHeightIdx-1][CI_NEXT_BEST]);
m_pcEntropyCoder->resetBits();//重置熵编码器的比特数;
if (uiBTSplitMode==0 )
{
m_pcEntropyCoder->encodeSplitFlag( rpcTempCU, 0, uiDepth, true );
}
m_pcEntropyCoder->encodeBTSplitMode(rpcTempCU, 0, uiWidth, uiHeight, true);
//统计当前CU的总的比特数,二进制数和率失真代价;
rpcTempCU->getTotalBits() += m_pcEntropyCoder->getNumberOfWrittenBits(); // split bits
rpcTempCU->getTotalBins() += ((TEncBinCABAC *)((TEncSbac*)m_pcEntropyCoder->m_pcEntropyCoderIf)->getEncBinIf())->getBinsCoded();
rpcTempCU->getTotalCost() = m_pcRdCost->calcRdCost( rpcTempCU->getTotalBits(), rpcTempCU->getTotalDistortion() );
#if JVET_D0077_SAVE_LOAD_ENC_INFO
if( rpcTempCU->getTotalCost() < dHorSplitCost )
{
dHorSplitCost = rpcTempCU->getTotalCost();
}
#endif
#if JVET_C0024_DELTA_QP_FIX
if( uiQTBTDepth == uiMaxDQPDepthQTBT && pps.getUseDQP())
{
Bool foundNonZeroCbf = false;
UInt uiFirstNonZeroPartIdx = 0;
rpcTempCU->setQPSubCUs( rpcTempCU->getRefQP( 0 ), 0, uiDepth, uiWidth, uiHeight, uiFirstNonZeroPartIdx, foundNonZeroCbf );
if ( foundNonZeroCbf )
{
m_pcEntropyCoder->resetBits();
m_pcEntropyCoder->encodeQP( rpcTempCU, uiFirstNonZeroPartIdx, false );
rpcTempCU->getTotalBits() += m_pcEntropyCoder->getNumberOfWrittenBits(); // dQP bits
rpcTempCU->getTotalBins() += ((TEncBinCABAC *)((TEncSbac*)m_pcEntropyCoder->m_pcEntropyCoderIf)->getEncBinIf())->getBinsCoded();
rpcTempCU->getTotalCost() = m_pcRdCost->calcRdCost( rpcTempCU->getTotalBits(), rpcTempCU->getTotalDistortion() );
}
else
{
rpcTempCU->setQPSubParts( rpcTempCU->getRefQP( 0 ), 0, uiWidth, uiHeight ); // set QP to default QP
#if JVET_C0024_DELTA_QP_FIX
if( pps.getUseDQP() ) // update coded QP
{
rpcTempCU->setCodedQP( rpcTempCU->getQP( 0 ) );
}
#endif
}
}
#endif
m_pcRDGoOnSbacCoder->store(m_ppppcRDSbacCoder[uiWidthIdx][uiHeightIdx][CI_TEMP_BEST]);
if (rpcBestCU->getTotalCost()!=MAX_DOUBLE)
{
//是否是slice的末尾;
const Bool isEndOfSlice = pcSlice->getSliceMode()==FIXED_NUMBER_OF_BYTES
&& ((pcSlice->getSliceBits()+rpcBestCU->getTotalBits())>pcSlice->getSliceArgument()<<3)
&& rpcBestCU->getCtuRsAddr() != pcPic->getPicSym()->getCtuTsToRsAddrMap(pcSlice->getSliceCurStartCtuTsAddr())
&& rpcBestCU->getCtuRsAddr() != pcPic->getPicSym()->getCtuTsToRsAddrMap(pcSlice->getSliceSegmentCurStartCtuTsAddr());
//是否是slice segment的末尾;
const Bool isEndOfSliceSegment = pcSlice->getSliceSegmentMode()==FIXED_NUMBER_OF_BYTES
&& ((pcSlice->getSliceSegmentBits()+rpcBestCU->getTotalBits()) > pcSlice->getSliceSegmentArgument()<<3)
&& rpcBestCU->getCtuRsAddr() != pcPic->getPicSym()->getCtuTsToRsAddrMap(pcSlice->getSliceSegmentCurStartCtuTsAddr());
// Do not need to check slice condition for slice-segment since a slice-segment is a subset of a slice.
if(isEndOfSlice||isEndOfSliceSegment)//如果是slice或者是slice segment的末尾;
{
rpcBestCU->getTotalCost()=MAX_DOUBLE;
}
}
//调用此函数选择最好的模式;
xCheckBestMode( rpcBestCU, rpcTempCU, uiDepth, uiWidth, uiHeight);
rpcTempCU->initEstData( uiDepth, iQP, bIsLosslessMode, uiWidth, uiHeight, uiBTSplitMode );
rpcBestCU->getPic()->setCodedBlkInCTU(false, uiPelXInCTU>> MIN_CU_LOG2, uiPelYInCTU>> MIN_CU_LOG2, uiWidth>> MIN_CU_LOG2, uiHeight>> MIN_CU_LOG2 );
rpcBestCU->getPic()->addCodedAreaInCTU(-(Int)uiWidth*uiHeight);
}
//===============QP遍历结束=================================
#if JVET_D0077_SAVE_LOAD_ENC_INFO
if( dCostTempBest > dHorSplitCost )
{
dCostTempBest = dHorSplitCost;
}
#endif
}
/////////////////////////////水平二叉树划分结束//////////////////////////////////////////////////////
//for encoder speedup,如果满足这些条件,则不需要再进行四叉树划分和二叉树垂直划分;
if (bTestHorSplit && rpcBestCU->isSkipped(0) && rpcBestCU->getBTDepth(0)==uiBTDepth && uiBTDepth>=SKIPHORNOVERQT_DEPTH_TH)
{
bTestVerSplit = bQTSplit = false;
}
if (bTestVerSplit) //如果要进行二叉树垂直划分;
{
// further split
//========从最小QP到最大QP遍历每一个QP,执行下面的步骤,选取最优QP=================
for (Int iQP=iMinQP; iQP<=iMaxQP; iQP++)
{
const Bool bIsLosslessMode = false; // False at this level. Next level down may set it to true.
rpcTempCU->initEstData( uiDepth, iQP, bIsLosslessMode );
UChar uhNextDepth = uiDepth;
UInt uiBTWidthIdx = g_aucConvertToBit[uiWidth>>1];
UInt uiBTHeightIdx = g_aucConvertToBit[uiHeight];
TComDataCU* pcSubBestPartCU = m_pppcBestCU[uiBTWidthIdx][uiBTHeightIdx];
TComDataCU* pcSubTempPartCU = m_pppcTempCU[uiBTWidthIdx][uiBTHeightIdx];
rpcTempCU->setBTSplitModeSubParts(2, 0, uiWidth, uiHeight);
#if JVET_C0024_BT_RMV_REDUNDANT
uiSplitConstrain = 0;
#endif
#if JVET_C0024_DELTA_QP_FIX // inherit quantization group info. from parent CU.
if( pps.getUseDQP() )
{
pcSubBestPartCU->initSubBT( rpcTempCU, 0, uiDepth, uiWidth>>1, uiHeight, 2, iQP );
pcSubTempPartCU->initSubBT( rpcTempCU, 0, uiDepth, uiWidth>>1, uiHeight, 2, iQP ); // clear sub partition datas or init.
pcSubBestPartCU->setCodedQP( lastCodedQP );
pcSubTempPartCU->setCodedQP( lastCodedQP );
pcSubBestPartCU->setQuPartIdx( rpcTempCU->getQuPartIdx() );
pcSubTempPartCU->setQuPartIdx( rpcTempCU->getQuPartIdx() );
pcSubBestPartCU->setQuLastCodedQP( rpcTempCU->getQuLastCodedQP() );
pcSubTempPartCU->setQuLastCodedQP( rpcTempCU->getQuLastCodedQP() );
}
#endif
for ( UInt uiPartUnitIdx = 0; uiPartUnitIdx < 2; uiPartUnitIdx++ )//二叉树划分划分为两个子CU;
{
pcSubBestPartCU->initSubBT( rpcTempCU, uiPartUnitIdx, uiDepth, uiWidth>>1, uiHeight, 2, iQP );
pcSubTempPartCU->initSubBT( rpcTempCU, uiPartUnitIdx, uiDepth, uiWidth>>1, uiHeight, 2, iQP ); // clear sub partition datas or init.
#if VCEG_AZ07_IMV && !JVET_C0024_QTBT
for( Int size = 0 ; size < NUMBER_OF_PART_SIZES ; size++ )
{
m_pppcTempCUIMVCache[size][uiBTWidthIdx][uiBTHeightIdx]->initSubBT( rpcTempCU, uiPartUnitIdx, uiDepth, uiWidth>>1, uiHeight, 2, iQP );
}
#endif
#if COM16_C806_OBMC
m_pppcTempCUWoOBMC[uiBTWidthIdx][uiBTHeightIdx]->initSubBT( rpcTempCU, uiPartUnitIdx, uiDepth, uiWidth>>1, uiHeight, 2, iQP ); // clear sub partition datas or init.
#endif
#if VCEG_AZ07_FRUC_MERGE
m_pppcFRUCBufferCU[uiBTWidthIdx][uiBTHeightIdx]->initSubBT( rpcTempCU, uiPartUnitIdx, uiDepth, uiWidth>>1, uiHeight, 2, iQP );
#endif
if(( pcSubBestPartCU->getCUPelX() < pcSlice->getSPS()->getPicWidthInLumaSamples() ) && ( pcSubBestPartCU->getCUPelY() < pcSlice->getSPS()->getPicHeightInLumaSamples() ) )
{
if ( 0 == uiPartUnitIdx) //initialize RD with previous depth buffer
{
m_ppppcRDSbacCoder[uiWidthIdx-1][uiHeightIdx][CI_CURR_BEST]->load(m_ppppcRDSbacCoder[uiWidthIdx][uiHeightIdx][CI_CURR_BEST]);
}
else
{
m_ppppcRDSbacCoder[uiWidthIdx-1][uiHeightIdx][CI_CURR_BEST]->load(m_ppppcRDSbacCoder[uiWidthIdx-1][uiHeightIdx][CI_NEXT_BEST]);
}
#if JVET_C0024_BT_RMV_REDUNDANT
xCompressCU( pcSubBestPartCU, pcSubTempPartCU, uiDepth, uiWidth>>1, uiHeight, pcSubBestPartCU->getBTSplitMode(0), uiSplitConstrain );
if( uiPartUnitIdx == 0 && pcSubBestPartCU->getBTSplitModeForBTDepth(0, uiBTDepth+1) == 1 && bBTVerRmvEnable )
{
uiSplitConstrain = 1;
}
#else
xCompressCU( pcSubBestPartCU, pcSubTempPartCU, uiDepth, uiWidth>>1, uiHeight, pcSubBestPartCU->getBTSplitMode(0) );
#endif
rpcTempCU->copyPartFrom( pcSubBestPartCU, uiPartUnitIdx, uhNextDepth, uiWidth>>1, uiHeight ); // Keep best part data to current temporary data.
#if JVET_C0024_DELTA_QP_FIX
if( pps.getUseDQP() ) // update coded QP
{
rpcTempCU->setCodedQP( pcSubBestPartCU->getCodedQP() );
pcSubBestPartCU->setCodedQP( rpcTempCU->getCodedQP() );
pcSubTempPartCU->setCodedQP( rpcTempCU->getCodedQP() );
}
#endif
xCopyYuv2Tmp( pcSubBestPartCU->getZorderIdxInCtu()-rpcTempCU->getZorderIdxInCtu(), uiWidth, uiHeight, 2 );
}
}
m_pcRDGoOnSbacCoder->load(m_ppppcRDSbacCoder[uiWidthIdx-1][uiHeightIdx][CI_NEXT_BEST]);
m_pcEntropyCoder->resetBits();
if (uiBTSplitMode==0 )
{
m_pcEntropyCoder->encodeSplitFlag( rpcTempCU, 0, uiDepth, true );
}
m_pcEntropyCoder->encodeBTSplitMode(rpcTempCU, 0, uiWidth, uiHeight, true);
rpcTempCU->getTotalBits() += m_pcEntropyCoder->getNumberOfWrittenBits(); // split bits
rpcTempCU->getTotalBins() += ((TEncBinCABAC *)((TEncSbac*)m_pcEntropyCoder->m_pcEntropyCoderIf)->getEncBinIf())->getBinsCoded();
rpcTempCU->getTotalCost() = m_pcRdCost->calcRdCost( rpcTempCU->getTotalBits(), rpcTempCU->getTotalDistortion() );
#if JVET_D0077_SAVE_LOAD_ENC_INFO
if( rpcTempCU->getTotalCost() < dVerSplitCost )
{
dVerSplitCost = rpcTempCU->getTotalCost();
}
#endif
#if JVET_C0024_DELTA_QP_FIX
if( uiQTBTDepth == uiMaxDQPDepthQTBT && pps.getUseDQP())
{
Bool foundNonZeroCbf = false;
UInt uiFirstNonZeroPartIdx = 0;
rpcTempCU->setQPSubCUs( rpcTempCU->getRefQP( 0 ), 0, uiDepth, uiWidth, uiHeight, uiFirstNonZeroPartIdx, foundNonZeroCbf );
if ( foundNonZeroCbf )
{
m_pcEntropyCoder->resetBits();
m_pcEntropyCoder->encodeQP( rpcTempCU, uiFirstNonZeroPartIdx, false );
rpcTempCU->getTotalBits() += m_pcEntropyCoder->getNumberOfWrittenBits(); // dQP bits
rpcTempCU->getTotalBins() += ((TEncBinCABAC *)((TEncSbac*)m_pcEntropyCoder->m_pcEntropyCoderIf)->getEncBinIf())->getBinsCoded();
rpcTempCU->getTotalCost() = m_pcRdCost->calcRdCost( rpcTempCU->getTotalBits(), rpcTempCU->getTotalDistortion() );
}
else
{
rpcTempCU->setQPSubParts( rpcTempCU->getRefQP( 0 ), 0, uiWidth, uiHeight ); // set QP to default QP
#if JVET_C0024_DELTA_QP_FIX
if( pps.getUseDQP() ) // update coded QP
{
rpcTempCU->setCodedQP( rpcTempCU->getQP( 0 ) );
}
#endif
}
}
#endif
m_pcRDGoOnSbacCoder->store(m_ppppcRDSbacCoder[uiWidthIdx][uiHeightIdx][CI_TEMP_BEST]);
if (rpcBestCU->getTotalCost()!=MAX_DOUBLE)
{
const Bool isEndOfSlice = pcSlice->getSliceMode()==FIXED_NUMBER_OF_BYTES
&& ((pcSlice->getSliceBits()+rpcBestCU->getTotalBits())>pcSlice->getSliceArgument()<<3)
&& rpcBestCU->getCtuRsAddr() != pcPic->getPicSym()->getCtuTsToRsAddrMap(pcSlice->getSliceCurStartCtuTsAddr())
&& rpcBestCU->getCtuRsAddr() != pcPic->getPicSym()->getCtuTsToRsAddrMap(pcSlice->getSliceSegmentCurStartCtuTsAddr());
const Bool isEndOfSliceSegment = pcSlice->getSliceSegmentMode()==FIXED_NUMBER_OF_BYTES
&& ((pcSlice->getSliceSegmentBits()+rpcBestCU->getTotalBits()) > pcSlice->getSliceSegmentArgument()<<3)
&& rpcBestCU->getCtuRsAddr() != pcPic->getPicSym()->getCtuTsToRsAddrMap(pcSlice->getSliceSegmentCurStartCtuTsAddr());
// Do not need to check slice condition for slice-segment since a slice-segment is a subset of a slice.
if(isEndOfSlice||isEndOfSliceSegment)
{
rpcBestCU->getTotalCost()=MAX_DOUBLE;
}
}
xCheckBestMode( rpcBestCU, rpcTempCU, uiDepth, uiWidth, uiHeight);
rpcTempCU->initEstData( uiDepth, iQP, bIsLosslessMode, uiWidth, uiHeight, uiBTSplitMode );
rpcBestCU->getPic()->setCodedBlkInCTU(false, uiPelXInCTU>> MIN_CU_LOG2, uiPelYInCTU>> MIN_CU_LOG2, uiWidth>> MIN_CU_LOG2, uiHeight>> MIN_CU_LOG2 );
rpcBestCU->getPic()->addCodedAreaInCTU(-(Int)uiWidth*uiHeight);
}
//==================QP遍历结束===============================
#if JVET_D0077_SAVE_LOAD_ENC_INFO
if( dCostTempBest > dVerSplitCost )
{
dCostTempBest = dVerSplitCost;
}
#endif
}
//////////////////////////////二叉树垂直划分结束////////////////////////////////////////////////
UInt uiZorderBR = g_auiRasterToZscan[((uiHeight>> MIN_CU_LOG2)-1) * (sps.getCTUSize()>> MIN_CU_LOG2) + (uiWidth>> MIN_CU_LOG2)-1]; //bottom-right part.
//如果满足这些条件,则不进行四叉树划分;
if (bQTSplit && ((rpcBestCU->getBTDepth(0)==0 && uiMaxBTD>=(rpcBestCU->getSlice()->isIntra() ? 3: 2) )
|| (rpcBestCU->getBTDepth(0)==1 && rpcBestCU->getBTDepth(uiZorderBR)==1 && uiMaxBTD>=(rpcBestCU->getSlice()->isIntra()? 4: 3)))
&& bTestHorSplit && bTestVerSplit )
{
bQTSplit = false;
}
#endif
////////////////////////////////四叉树划分过程////////////////////////////////////////////////////
#if JVET_C0024_QTBT
if( bQTSplit)//如果要进行四叉树划分;
#else
if( bSubBranch && uiDepth < sps.getLog2DiffMaxMinCodingBlockSize() && (!getFastDeltaQp() || uiWidth > fastDeltaQPCuMaxSize || bBoundary))
#endif
{
// further split
//=========从最小QP到最大QP遍历每一个QP,执行下面的步骤,选取最优QP================
for (Int iQP=iMinQP; iQP<=iMaxQP; iQP++)
{
const Bool bIsLosslessMode = false; // False at this level. Next level down may set it to true.
rpcTempCU->initEstData( uiDepth, iQP, bIsLosslessMode );
UChar uhNextDepth = uiDepth+1;
#if JVET_C0024_QTBT
UInt uiQTWidthIdx = g_aucConvertToBit[uiWidth>>1]; //4;
UInt uiQTHeightIdx = g_aucConvertToBit[uiHeight>>1];//4;
TComDataCU* pcSubBestPartCU = m_pppcBestCU[uiQTWidthIdx][uiQTHeightIdx];
TComDataCU* pcSubTempPartCU = m_pppcTempCU[uiQTWidthIdx][uiQTHeightIdx];
#else
TComDataCU* pcSubBestPartCU = m_ppcBestCU[uhNextDepth];
TComDataCU* pcSubTempPartCU = m_ppcTempCU[uhNextDepth];
#endif
DEBUG_STRING_NEW(sTempDebug)
#if JVET_C0024_DELTA_QP_FIX // inherit quantization group info. from parent CU.
if( pps.getUseDQP() )
{
pcSubBestPartCU->initSubCU( rpcTempCU, 0, uhNextDepth, iQP ); // clear sub partition datas or init.
pcSubTempPartCU->initSubCU( rpcTempCU, 0, uhNextDepth, iQP ); // clear sub partition datas or init.
pcSubBestPartCU->setCodedQP( lastCodedQP );
pcSubTempPartCU->setCodedQP( lastCodedQP );
pcSubBestPartCU->setQuPartIdx( rpcTempCU->getQuPartIdx() );
pcSubTempPartCU->setQuPartIdx( rpcTempCU->getQuPartIdx() );
pcSubBestPartCU->setQuLastCodedQP( rpcTempCU->getQuLastCodedQP() );
pcSubTempPartCU->setQuLastCodedQP( rpcTempCU->getQuLastCodedQP() );
}
#endif
for ( UInt uiPartUnitIdx = 0; uiPartUnitIdx < 4; uiPartUnitIdx++ )//四叉树划分划分为4个子CU;
{//初始化最优划分的子CU;
pcSubBestPartCU->initSubCU( rpcTempCU, uiPartUnitIdx, uhNextDepth, iQP ); // clear sub partition datas or init.
//初始化当前的子CU;
pcSubTempPartCU->initSubCU( rpcTempCU, uiPartUnitIdx, uhNextDepth, iQP ); // clear sub partition datas or init.
#if VCEG_AZ07_IMV && !JVET_C0024_QTBT
for( Int size = 0 ; size < NUMBER_OF_PART_SIZES ; size++ )
{
#if JVET_C0024_QTBT
m_pppcTempCUIMVCache[size][uiQTWidthIdx][uiQTHeightIdx]->initSubCU( rpcTempCU, uiPartUnitIdx, uhNextDepth, iQP );
#else
m_ppcTempCUIMVCache[size][uhNextDepth]->initSubCU( rpcTempCU, uiPartUnitIdx, uhNextDepth, iQP );
#endif
}
#endif
#if COM16_C806_OBMC
#if JVET_C0024_QTBT
m_pppcTempCUWoOBMC[uiQTWidthIdx][uiQTHeightIdx]->initSubCU( rpcTempCU, uiPartUnitIdx, uhNextDepth, iQP ); // clear sub partition datas or init.
#else
m_ppcTempCUWoOBMC[uhNextDepth]->initSubCU( rpcTempCU, uiPartUnitIdx, uhNextDepth, iQP ); // clear sub partition datas or init.
#endif
#endif
#if VCEG_AZ07_FRUC_MERGE
#if JVET_C0024_QTBT
m_pppcFRUCBufferCU[uiQTWidthIdx][uiQTHeightIdx]->initSubCU( rpcTempCU, uiPartUnitIdx, uhNextDepth, iQP );
#else
m_ppcFRUCBufferCU[uhNextDepth]->initSubCU( rpcTempCU, uiPartUnitIdx, uhNextDepth, iQP );
#endif
#endif
if( ( pcSubBestPartCU->getCUPelX() < sps.getPicWidthInLumaSamples() ) && ( pcSubBestPartCU->getCUPelY() < sps.getPicHeightInLumaSamples() ) )
{
#if JVET_C0024_QTBT
if ( 0 == uiPartUnitIdx) //initialize RD with previous depth buffer
{
m_ppppcRDSbacCoder[uiQTWidthIdx][uiQTHeightIdx][CI_CURR_BEST]->load(m_ppppcRDSbacCoder[uiWidthIdx][uiHeightIdx][CI_CURR_BEST]);
}
else
{
m_ppppcRDSbacCoder[uiQTWidthIdx][uiQTHeightIdx][CI_CURR_BEST]->load(m_ppppcRDSbacCoder[uiQTWidthIdx][uiQTHeightIdx][CI_NEXT_BEST]);
}
#else
if ( 0 == uiPartUnitIdx) //initialize RD with previous depth buffer
{
m_pppcRDSbacCoder[uhNextDepth][CI_CURR_BEST]->load(m_pppcRDSbacCoder[uiDepth][CI_CURR_BEST]);
}
else
{
m_pppcRDSbacCoder[uhNextDepth][CI_CURR_BEST]->load(m_pppcRDSbacCoder[uhNextDepth][CI_NEXT_BEST]);
}
#endif
#if AMP_ENC_SPEEDUP
DEBUG_STRING_NEW(sChild)
#if JVET_C0024_QTBT//对每个子CU调用xCompressCU;
xCompressCU( pcSubBestPartCU, pcSubTempPartCU, uhNextDepth, uiWidth>>1, uiHeight>>1 DEBUG_STRING_PASS_INTO(sChild), SIZE_2Nx2N );
#else
if ( !(rpcBestCU->getTotalCost()!=MAX_DOUBLE && rpcBestCU->isInter(0)) )
{
xCompressCU( pcSubBestPartCU, pcSubTempPartCU, uhNextDepth DEBUG_STRING_PASS_INTO(sChild), NUMBER_OF_PART_SIZES );
}
else
{
xCompressCU( pcSubBestPartCU, pcSubTempPartCU, uhNextDepth DEBUG_STRING_PASS_INTO(sChild), rpcBestCU->getPartitionSize(0) );
}
#endif
DEBUG_STRING_APPEND(sTempDebug, sChild)
#else
xCompressCU( pcSubBestPartCU, pcSubTempPartCU, uhNextDepth );
#endif
#if JVET_C0024_QTBT
rpcTempCU->copyPartFrom( pcSubBestPartCU, uiPartUnitIdx, uhNextDepth, uiWidth>>1, uiHeight>>1 ); // Keep best part data to current temporary data.
#if JVET_C0024_DELTA_QP_FIX
if( pps.getUseDQP() ) // update coded QP
{
rpcTempCU->setCodedQP( pcSubBestPartCU->getCodedQP() );
pcSubBestPartCU->setCodedQP( rpcTempCU->getCodedQP() );
pcSubTempPartCU->setCodedQP( rpcTempCU->getCodedQP() );
}
#endif
assert(pcSubBestPartCU->getTotalNumPart()*uiPartUnitIdx == pcSubBestPartCU->getZorderIdxInCtu()-rpcTempCU->getZorderIdxInCtu());
xCopyYuv2Tmp( pcSubBestPartCU->getTotalNumPart()*uiPartUnitIdx, uiWidth, uiHeight );
#else
rpcTempCU->copyPartFrom( pcSubBestPartCU, uiPartUnitIdx, uhNextDepth ); // Keep best part data to current temporary data.
xCopyYuv2Tmp( pcSubBestPartCU->getTotalNumPart()*uiPartUnitIdx, uhNextDepth );
#endif
}
else
{
#if JVET_C0024_QTBT
pcSubBestPartCU->copyToPic( uhNextDepth, uiWidth>>1, uiHeight>>1 );
rpcTempCU->copyPartFrom( pcSubBestPartCU, uiPartUnitIdx, uhNextDepth, uiWidth>>1, uiHeight>>1 );
rpcBestCU->getPic()->addCodedAreaInCTU(uiWidth*uiHeight>>2);
#else
pcSubBestPartCU->copyToPic( uhNextDepth );
rpcTempCU->copyPartFrom( pcSubBestPartCU, uiPartUnitIdx, uhNextDepth );
#endif
}
}
#if JVET_C0024_QTBT
m_pcRDGoOnSbacCoder->load(m_ppppcRDSbacCoder[uiQTWidthIdx][uiQTHeightIdx][CI_NEXT_BEST]);
#else
m_pcRDGoOnSbacCoder->load(m_pppcRDSbacCoder[uhNextDepth][CI_NEXT_BEST]);
#endif
if( !bBoundary )
{
m_pcEntropyCoder->resetBits();
#if JVET_C0024_QTBT
if( !bForceQT )
#endif
m_pcEntropyCoder->encodeSplitFlag( rpcTempCU, 0, uiDepth, true );
rpcTempCU->getTotalBits() += m_pcEntropyCoder->getNumberOfWrittenBits(); // split bits
rpcTempCU->getTotalBins() += ((TEncBinCABAC *)((TEncSbac*)m_pcEntropyCoder->m_pcEntropyCoderIf)->getEncBinIf())->getBinsCoded();
}
rpcTempCU->getTotalCost() = m_pcRdCost->calcRdCost( rpcTempCU->getTotalBits(), rpcTempCU->getTotalDistortion() );
#if JVET_C0024_DELTA_QP_FIX
if( uiQTBTDepth == uiMaxDQPDepthQTBT && pps.getUseDQP())
#else
if( uiDepth == pps.getMaxCuDQPDepth() && pps.getUseDQP())
#endif
{
Bool hasResidual = false;
for( UInt uiBlkIdx = 0; uiBlkIdx < rpcTempCU->getTotalNumPart(); uiBlkIdx ++)
{
#if JVET_C0024_DELTA_QP_FIX
if( rpcTempCU->getSlice()->isIntra() )
{
if( rpcTempCU->getTextType() == CHANNEL_TYPE_LUMA )
{
if( rpcTempCU->getCbf(uiBlkIdx, COMPONENT_Y) )
{
hasResidual = true;
}
}
else
{
if( (rpcTempCU->getCbf(uiBlkIdx, COMPONENT_Cb) && (numberValidComponents > COMPONENT_Cb)) ||
(rpcTempCU->getCbf(uiBlkIdx, COMPONENT_Cr) && (numberValidComponents > COMPONENT_Cr)) )
{
hasResidual = true;
}
}
}
else
#endif
if( ( rpcTempCU->getCbf(uiBlkIdx, COMPONENT_Y)
|| (rpcTempCU->getCbf(uiBlkIdx, COMPONENT_Cb) && (numberValidComponents > COMPONENT_Cb))
|| (rpcTempCU->getCbf(uiBlkIdx, COMPONENT_Cr) && (numberValidComponents > COMPONENT_Cr)) ) )
{
hasResidual = true;
break;
}
}
if ( hasResidual )
{
#if JVET_C0024_DELTA_QP_FIX
Bool foundNonZeroCbf = false;
UInt uiFirstNonZeroPartIdx = 0;
rpcTempCU->setQPSubCUs( rpcTempCU->getRefQP( 0 ), 0, uiDepth, uiWidth, uiHeight, uiFirstNonZeroPartIdx, foundNonZeroCbf );
m_pcEntropyCoder->resetBits();
m_pcEntropyCoder->encodeQP( rpcTempCU, uiFirstNonZeroPartIdx, false );
rpcTempCU->getTotalBits() += m_pcEntropyCoder->getNumberOfWrittenBits(); // dQP bits
rpcTempCU->getTotalBins() += ((TEncBinCABAC *)((TEncSbac*)m_pcEntropyCoder->m_pcEntropyCoderIf)->getEncBinIf())->getBinsCoded();
rpcTempCU->getTotalCost() = m_pcRdCost->calcRdCost( rpcTempCU->getTotalBits(), rpcTempCU->getTotalDistortion() );
#else
m_pcEntropyCoder->resetBits();
m_pcEntropyCoder->encodeQP( rpcTempCU, 0, false );
rpcTempCU->getTotalBits() += m_pcEntropyCoder->getNumberOfWrittenBits(); // dQP bits
rpcTempCU->getTotalBins() += ((TEncBinCABAC *)((TEncSbac*)m_pcEntropyCoder->m_pcEntropyCoderIf)->getEncBinIf())->getBinsCoded();
rpcTempCU->getTotalCost() = m_pcRdCost->calcRdCost( rpcTempCU->getTotalBits(), rpcTempCU->getTotalDistortion() );
Bool foundNonZeroCbf = false;
rpcTempCU->setQPSubCUs( rpcTempCU->getRefQP( 0 ), 0, uiDepth, foundNonZeroCbf );
#endif
assert( foundNonZeroCbf );
}
else
{
#if JVET_C0024_DELTA_QP_FIX
rpcTempCU->setQPSubParts( rpcTempCU->getRefQP( 0 ), 0, uiWidth, uiHeight ); // set QP to default QP
#else
rpcTempCU->setQPSubParts( rpcTempCU->getRefQP( 0 ), 0, uiDepth ); // set QP to default QP
#endif
#if JVET_C0024_DELTA_QP_FIX
if( pps.getUseDQP() ) // update coded QP
{
rpcTempCU->setCodedQP( rpcTempCU->getQP( 0 ) );
}
#endif
}
}
#if JVET_C0024_QTBT
m_pcRDGoOnSbacCoder->store(m_ppppcRDSbacCoder[uiWidthIdx][uiHeightIdx][CI_TEMP_BEST]);
#else
m_pcRDGoOnSbacCoder->store(m_pppcRDSbacCoder[uiDepth][CI_TEMP_BEST]);
#endif
// If the configuration being tested exceeds the maximum number of bytes for a slice / slice-segment, then
// a proper RD evaluation cannot be performed. Therefore, termination of the
// slice/slice-segment must be made prior to this CTU.
// This can be achieved by forcing the decision to be that of the rpcTempCU.
// The exception is each slice / slice-segment must have at least one CTU.
//如果正在测试的配置超过了片/片段的最大字节数,则无法执行正确的RD评估。
//因此,必须在该CTU之前终止切片/切片段。这可以通过强制该判决为rpcTempCU来实现。
//例外是每个切片/切片段必须至少具有一个CTU。
if (rpcBestCU->getTotalCost()!=MAX_DOUBLE)
{
const Bool isEndOfSlice = pcSlice->getSliceMode()==FIXED_NUMBER_OF_BYTES
&& ((pcSlice->getSliceBits()+rpcBestCU->getTotalBits())>pcSlice->getSliceArgument()<<3)
&& rpcBestCU->getCtuRsAddr() != pcPic->getPicSym()->getCtuTsToRsAddrMap(pcSlice->getSliceCurStartCtuTsAddr())
&& rpcBestCU->getCtuRsAddr() != pcPic->getPicSym()->getCtuTsToRsAddrMap(pcSlice->getSliceSegmentCurStartCtuTsAddr());
const Bool isEndOfSliceSegment = pcSlice->getSliceSegmentMode()==FIXED_NUMBER_OF_BYTES
&& ((pcSlice->getSliceSegmentBits()+rpcBestCU->getTotalBits()) > pcSlice->getSliceSegmentArgument()<<3)
&& rpcBestCU->getCtuRsAddr() != pcPic->getPicSym()->getCtuTsToRsAddrMap(pcSlice->getSliceSegmentCurStartCtuTsAddr());
// Do not need to check slice condition for slice-segment since a slice-segment is a subset of a slice.
if(isEndOfSlice||isEndOfSliceSegment)
{
rpcBestCU->getTotalCost()=MAX_DOUBLE;
}
}
#if JVET_C0024_QTBT
//比较当前块的代价和划分成子块的总代价;
xCheckBestMode( rpcBestCU, rpcTempCU, uiDepth, uiWidth, uiHeight DEBUG_STRING_PASS_INTO(sDebug) DEBUG_STRING_PASS_INTO(sTempDebug) DEBUG_STRING_PASS_INTO(false) ); // RD compare current larger prediction
rpcBestCU->getPic()->setCodedBlkInCTU(false, uiPelXInCTU>>MIN_CU_LOG2, uiPelYInCTU>>MIN_CU_LOG2, uiWidth>>MIN_CU_LOG2, uiHeight>>MIN_CU_LOG2 );
rpcBestCU->getPic()->addCodedAreaInCTU(-(Int)uiWidth*uiHeight);
#else
xCheckBestMode( rpcBestCU, rpcTempCU, uiDepth DEBUG_STRING_PASS_INTO(sDebug) DEBUG_STRING_PASS_INTO(sTempDebug) DEBUG_STRING_PASS_INTO(false) ); // RD compare current larger prediction
#endif
// with sub partitioned prediction.
}
//=================QP循环遍历结束===================================
DEBUG_STRING_APPEND(sDebug_, sDebug);
#if JVET_C0024_QTBT
rpcBestCU->copyToPic(uiDepth, uiWidth, uiHeight); // Copy Best data to Picture for next partition prediction.
rpcBestCU->getPic()->setCodedBlkInCTU(true, uiPelXInCTU>>MIN_CU_LOG2, uiPelYInCTU>>MIN_CU_LOG2, uiWidth>>MIN_CU_LOG2, uiHeight>>MIN_CU_LOG2 );
rpcBestCU->getPic()->addCodedAreaInCTU(uiWidth*uiHeight);
xCopyYuv2Pic( rpcBestCU->getPic(), rpcBestCU->getCtuRsAddr(), rpcBestCU->getZorderIdxInCtu(), uiDepth, uiDepth, uiWidth, uiHeight ); // Copy Yuv data to picture Yuv
#else
rpcBestCU->copyToPic(uiDepth); // Copy Best data to Picture for next partition prediction.
xCopyYuv2Pic( rpcBestCU->getPic(), rpcBestCU->getCtuRsAddr(), rpcBestCU->getZorderIdxInCtu(), uiDepth, uiDepth ); // Copy Yuv data to picture Yuv
#endif
#if JVET_D0077_SAVE_LOAD_ENC_INFO
if( bUseSaveLoad )
{
m_pcPredSearch->setSaveLoadTag( MAX_UINT, uiWidthIdx - 1, uiHeightIdx - 1, SAVE_LOAD_INIT );
}
if( bUseSaveLoadSplitDecision && saveLoadTag == SAVE_ENC_INFO )
{
UChar c = 0;
Double TH = JVET_D0077_SPLIT_DECISION_COST_SCALE * dCostTempBest;
if( dNonSplitCost > TH )
{
c = c | 0x01;
}
if( dHorSplitCost > TH )
{
c = c | 0x02;
}
if( dVerSplitCost > TH )
{
c = c | 0x04;
}
m_pcPredSearch->setSaveLoadSplit(uiWidthIdx, uiHeightIdx, c);
}
#endif
if (bBoundary)
{
return;
}
// Assert if Best prediction mode is NONE
// Selected mode's RD-cost must be not MAX_DOUBLE.
#if !JVET_C0024_QTBT
assert( rpcBestCU->getPartitionSize ( 0 ) != NUMBER_OF_PART_SIZES );
assert( rpcBestCU->getPredictionMode( 0 ) != NUMBER_OF_PREDICTION_MODES );
assert( rpcBestCU->getTotalCost ( ) != MAX_DOUBLE );
#endif
}
//////////////////////////////四叉树划分结束//////////////////////////////////////////////////
}