estIntraPredLumaQT进行帧内亮度模式的预测,在67种帧内亮度模式中,获取帧内亮度模式的最优模式。
首先进行SATD粗选择,对HEVC中的35种角度模式进行SATD选择;
再分别对SATD所选择的角度模式的左右两种角度模式(即模式号±1),进行再一次的SATD;
然后进行MRL模式的检测;
再添加亮度的MPM模式;
最后对列表中的帧内亮度模式进行RDO,分别调用xRecurIntraCodingLumaQT函数,选择最优帧内亮度模式。
void IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner )
{
CodingStructure &cs = *cu.cs;
const SPS &sps = *cs.sps;
const uint32_t uiWidthBit = cs.pcv->rectCUs ? g_aucLog2[partitioner.currArea().lwidth() ] : CU::getIntraSizeIdx(cu);
const uint32_t uiHeightBit = g_aucLog2[partitioner.currArea().lheight()];
// Lambda calculation at equivalent Qp of 4 is recommended because at that Qp, the quantization divisor is 1.
const double sqrtLambdaForFirstPass = m_pcRdCost->getMotionLambda(cu.transQuantBypass) / double(1 << SCALE_BITS);
//===== loop over partitions =====
const TempCtx ctxStart ( m_CtxCache, m_CABACEstimator->getCtx() );
const TempCtx ctxStartIntraMode ( m_CtxCache, SubCtx( Ctx::IPredMode[CHANNEL_TYPE_LUMA], m_CABACEstimator->getCtx() ) );
#if JVET_L0100_MULTI_HYPOTHESIS_INTRA
const TempCtx ctxStartMHIntraMode ( m_CtxCache, SubCtx( Ctx::MHIntraPredMode, m_CABACEstimator->getCtx() ) );
#endif
#if JVET_L0283_MULTI_REF_LINE
const TempCtx ctxStartMrlIdx ( m_CtxCache, SubCtx( Ctx::MultiRefLineIdx, m_CABACEstimator->getCtx() ) );
#endif
CHECK( !cu.firstPU, "CU has no PUs" );
const bool keepResi = cs.pps->getPpsRangeExtension().getCrossComponentPredictionEnabledFlag() || KEEP_PRED_AND_RESI_SIGNALS;
uint32_t extraModes = 0; // add two extra modes, which would be used after uiMode <= DC_IDX is removed for cu.nsstIdx == 3
const int width = partitioner.currArea().lwidth();
const int height = partitioner.currArea().lheight();
// Marking EMT usage for faster EMT
// 0: EMT is either not applicable for current CU (cuWidth > EMT_INTRA_MAX_CU or cuHeight > EMT_INTRA_MAX_CU), not active in the config file or the fast decision algorithm is not used in this case
// 1: EMT fast algorithm can be applied for the current CU, and the DCT2 is being checked
// 2: EMT is being checked for current CU. Stored results of DCT2 can be utilized for speedup
uint8_t emtUsageFlag = 0;
const int maxSizeEMT = cs.pcv->noRQT ? EMT_INTRA_MAX_CU_WITH_QTBT : EMT_INTRA_MAX_CU;
if( width <= maxSizeEMT && height <= maxSizeEMT && sps.getSpsNext().getUseIntraEMT() )
{
emtUsageFlag = cu.emtFlag == 1 ? 2 : 1;
}
bool isAllIntra = m_pcEncCfg->getIntraPeriod() == 1;
if( cs.pcv->rectCUs )
{
if( width * height < 64 && !isAllIntra )
{
emtUsageFlag = 0; //this forces the recalculation of the candidates list. Why is this necessary? (to be checked)
}
}
static_vector<uint32_t, FAST_UDI_MAX_RDMODE_NUM> uiHadModeList;
static_vector<double, FAST_UDI_MAX_RDMODE_NUM> CandCostList;
static_vector<double, FAST_UDI_MAX_RDMODE_NUM> CandHadList;
#if JVET_L0283_MULTI_REF_LINE
static_vector<int, FAST_UDI_MAX_RDMODE_NUM> extendRefList; //MRL
static_vector<int, FAST_UDI_MAX_RDMODE_NUM>* nullList = NULL;
#endif
auto &pu = *cu.firstPU;
int puIndex = 0;
{
CandHadList.clear();
CandCostList.clear();
uiHadModeList.clear();
#if JVET_L0283_MULTI_REF_LINE
extendRefList.clear();
#endif
CHECK(pu.cu != &cu, "PU is not contained in the CU"); /以上为各种数据的初始化
//===== determine set of modes to be tested (using prediction signal only) =====
int numModesAvailable = NUM_LUMA_MODE; // total number of Intra modes 67种帧内模式
static_vector< uint32_t, FAST_UDI_MAX_RDMODE_NUM > uiRdModeList;
int numModesForFullRD = 3; //numModesForFullRD为最后进行帧内模式RDO的模式数
if( cs.pcv->rectCUs )
{
numModesForFullRD = g_aucIntraModeNumFast_UseMPM_2D[uiWidthBit - MIN_CU_LOG2][uiHeightBit - MIN_CU_LOG2];
}
else
{
numModesForFullRD = m_pcEncCfg->getFastUDIUseMPMEnabled() ? g_aucIntraModeNumFast_UseMPM[uiWidthBit] : g_aucIntraModeNumFast_NotUseMPM[uiWidthBit];
numModesForFullRD -= 1;
}
#if INTRA_FULL_SEARCH
numModesForFullRD = numModesAvailable;
#endif
if( emtUsageFlag != 2 )
{
// this should always be true 一般均为true
CHECK( !pu.Y().valid(), "PU is not valid" );
#if JVET_L0283_MULTI_REF_LINE
bool isFirstLineOfCtu = (