代碼所在網址:
https://jvet.hhi.fraunhofer.de/svn/svn_VVCSoftware_BMS/
這些只是自己初步的學習,若有問題煩請更正,共同進步~
幀內預測的相關內容在函數xCheckRDCostIntra()中
該函數下調用了亮度預測函數及色度預測函數:estIntraPredLumaQT()及estIntraPredLumaQT()
兩個函數及其調用函數分析見:
https://blog.csdn.net/yolo_life/article/details/81673741
void EncCu::xCheckRDCostIntra( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &partitioner, const EncTestMode& encTestMode )
{
#if JEM_TOOLS
double bestInterCost = m_modeCtrl->getBestInterCost();
#endif
#if JEM_TOOLS
#if HEVC_USE_PART_SIZE
bool isAllIntra = m_pcEncCfg->getIntraPeriod() == 1;
#endif
#endif
#if JEM_TOOLS
//AMT第一個通道
double costSize2Nx2NemtFirstPass = m_modeCtrl->getEmtSize2Nx2NFirstPassCost();
double costSizeNxNemtFirstPass = MAX_DOUBLE;
bool skipSecondEmtPass = m_modeCtrl->getSkipSecondEMTPass();
#endif
#if JEM_TOOLS
auto slsCtrl = dynamic_cast<SaveLoadEncInfoCtrl*>( m_modeCtrl );
const SPS &sps = *tempCS->sps;
#endif
const PPS &pps = *tempCS->pps;
const CodingUnit *bestCU = bestCS->getCU( partitioner.chType );
#if JEM_TOOLS
//NSST索引
const int nsstIdx = ( encTestMode.opts & ETO_NSST ) >> ETO_NSST_SHIFT;
#endif
#if JEM_TOOLS
const bool usePDPC = ( encTestMode.opts & ETO_PDPC ) != 0;
#endif
#if JEM_TOOLS
const int maxSizeEMT = pps.pcv->noRQT ? EMT_INTRA_MAX_CU_WITH_QTBT : EMT_INTRA_MAX_CU;
#endif
#if JEM_TOOLS
#if HM_EMT_NSST_AS_IN_JEM
//判斷是幀內編碼的寬高均<=maxSizeEMT的亮度塊,是則使用AMT的第二通道,值爲1,表示使用AMT;不是則爲0,不使用AMT
UChar considerEmtSecondPass = ( sps.getSpsNext().getUseIntraEMT() && isLuma( partitioner.chType ) && partitioner.currArea().lwidth() <= maxSizeEMT && partitioner.currArea().lheight() <= maxSizeEMT ) ? 1 : 0;
#else
UChar considerEmtSecondPass = ( sps.getSpsNext().getUseIntraEMT() && isLuma( partitioner.chType ) && partitioner.currArea().lwidth() <= maxSizeEMT && partitioner.currArea().lheight() <= maxSizeEMT && nsstIdx == 0 ) ? 1 : 0;
#endif
CHECK( usePDPC && sps.getSpsNext().isPlanarPDPC(), "PDPC cannot be on with Planar-PDPC" );
#endif
Distortion interHad = m_modeCtrl->getInterHad();
#if JEM_TOOLS//AMT相關循環
for( UChar emtCuFlag = 0; emtCuFlag <= considerEmtSecondPass; emtCuFlag++ )
#else
for( UChar numPasses = 0; numPasses < 1; numPasses++ )
#endif
{
#if JEM_TOOLS
//Possible early EMT tests interruptions //AMT早期中斷判斷
//1) saveLoadTag code for EMT
if( sps.getSpsNext().getUseQTBT() && slsCtrl && m_pcEncCfg->getUseSaveLoadEncInfo() )
{
if( m_pcEncCfg->getIntraEMT() && LOAD_ENC_INFO == slsCtrl->getSaveLoadTag( tempCS->area ) && ( emtCuFlag > 0 ) != slsCtrl->getSaveLoadEmtCuFlag( tempCS->area ) )
{
continue;
}
}
//2) Second EMT pass. This "if clause" is necessary because of the NSST and PDPC "for loops".
if( emtCuFlag && skipSecondEmtPass )
{
continue;
}
#endif
//3) if interHad is 0, only try further modes if some intra mode was already better than inter
if( m_pcEncCfg->getUsePbIntraFast() && !tempCS->slice->isIntra() && bestCU && CU::isInter( *bestCS->getCU( partitioner.chType ) ) && interHad == 0 )
{
continue;
}
//************************************************ 初始化
tempCS->initStructData( encTestMode.qp, encTestMode.lossless );
CodingUnit &cu = tempCS->addCU( CS::getArea( *tempCS, tempCS->area, partitioner.chType ), partitioner.chType );
partitioner.setCUData( cu );
cu.slice = tempCS->slice;
#if HEVC_TILES_WPP
cu.tileIdx = tempCS->picture->tileMap->getTileIdxMap( tempCS->area.lumaPos() );
#endif
cu.skip = false;
cu.partSize = encTestMode.partSize;
cu.predMode = MODE_INTRA;
cu.transQuantBypass = encTestMode.lossless;
#if JEM_TOOLS
cu.pdpc = usePDPC;
#endif
cu.chromaQpAdj = cu.transQuantBypass ? 0 : m_cuChromaQpOffsetIdxPlus1;
cu.qp = encTestMode.qp;
//cu.ipcm = false;
#if JEM_TOOLS
cu.nsstIdx = nsstIdx;
cu.emtFlag = emtCuFlag;
#endif
CU::addPUs( cu );
tempCS->interHad = interHad;
//************************************************ 亮度幀內預測
if( isLuma( partitioner.chType ) )
{
m_pcIntraSearch->estIntraPredLumaQT( cu, partitioner );//入口函數
if( m_pcEncCfg->getUsePbIntraFast() && tempCS->dist == MAX_UINT && tempCS->interHad == 0 )
{
interHad = 0;
// JEM assumes only perfect reconstructions can from now on beat the inter mode
m_modeCtrl->enforceInterHad( 0 );
continue;
}
if( !CS::isDualITree( *tempCS ) )//isDualITree:I幀下的亮度色度分離樹判斷,爲真表示分離樹
{
cu.cs->picture->getRecoBuf( cu.Y() ).copyFrom( cu.cs->getRecoBuf( COMPONENT_Y ) );
}
}
//************************************************ 色度幀內預測
if( tempCS->area.chromaFormat != CHROMA_400 && ( partitioner.chType == CHANNEL_TYPE_CHROMA || !CS::isDualITree( *tempCS ) ) )
{
m_pcIntraSearch->estIntraPredChromaQT( cu, partitioner );
}
cu.rootCbf = false;
for( UInt t = 0; t < getNumberValidTBlocks( *cu.cs->pcv ); t++ )
{
cu.rootCbf |= cu.firstTU->cbf[t] != 0;
}
//************************************************ Get total bits for current mode: encode CU
m_CABACEstimator->resetBits();
if( pps.getTransquantBypassEnabledFlag() )
{ //編碼變換量化旁路情況下的標誌(旁路意味着殘差直接賦值給變換系數)
m_CABACEstimator->cu_transquant_bypass_flag( cu );
}
if( !cu.cs->slice->isIntra() )
{ //編碼非幀內下的skip標誌
m_CABACEstimator->cu_skip_flag ( cu );
}
//編碼預測模式
m_CABACEstimator->pred_mode ( cu );
#if JEM_TOOLS
//編碼PDPC標誌
m_CABACEstimator->pdpc_flag ( cu );
#endif
#if HEVC_USE_PART_SIZE //默認flase
m_CABACEstimator->part_mode ( cu );
#endif
//編碼CU預測數據(包括:幀內:亮度預測模式+色度預測模式;PU;IMV模式;OBMC標誌;LIC標誌)
m_CABACEstimator->cu_pred_data ( cu );
//編碼PCM數據
m_CABACEstimator->pcm_data ( cu );
//************************************************ Encode Coefficients
CUCtx cuCtx;
cuCtx.isDQPCoded = true;
cuCtx.isChromaQpAdjCoded = true;
m_CABACEstimator->cu_residual( cu, partitioner, cuCtx );//變換系數編碼
tempCS->fracBits = m_CABACEstimator->getEstFracBits();
tempCS->cost = m_pcRdCost->calcRdCost(tempCS->fracBits, tempCS->dist);
#if !HM_POSTPONE_SPLIT_BITS //宏爲真,默認不進入下一個函數
xEncodeDontSplit( *tempCS, partitioner );
#endif
//************************************************ deltaQP檢測
xCheckDQP( *tempCS, partitioner );
#if JEM_TOOLS
//************************************************ Check if secondary transform (NSST) is too expensive
const int nonZeroCoeffThr = CS::isDualITree( *tempCS ) ? ( isLuma( partitioner.chType ) ? NSST_SIG_NZ_LUMA : NSST_SIG_NZ_CHROMA ) : NSST_SIG_NZ_LUMA + NSST_SIG_NZ_CHROMA;
if( nsstIdx && tempCS->pcv->noRQT && cuCtx.numNonZeroCoeffNonTs <= nonZeroCoeffThr )
{
Bool isMDIS = false;
if( sps.getSpsNext().isPlanarPDPC() )
{
CHECK( CU::getNumPUs( cu ) > 1, "PLanarPDPC: encoder MDIS condition not defined for multi PU" );
const PredictionUnit* pu = cu.firstPU;
isMDIS = IntraPrediction::useFilteredIntraRefSamples( COMPONENT_Y, *pu, true, *pu );
#if HM_MDIS_AS_IN_JEM
if( pu->intraDir[0] == PLANAR_IDX ) { isMDIS |= IntraPrediction::getPlanarMDISCondition( *pu ); }
#endif
}
if( cuCtx.numNonZeroCoeffNonTs > 0 || isMDIS )
{
tempCS->cost = MAX_DOUBLE;
}
}
if( nsstIdx && !tempCS->pcv->noRQT && cu.rootCbf == 0 )
{
tempCS->cost = MAX_DOUBLE;
}
#endif
#if JEM_TOOLS
//************************************************保存了第一個AMT通道模式的代價
if( !emtCuFlag ) static_cast< double& >( cu.partSize == SIZE_2Nx2N ? costSize2Nx2NemtFirstPass : costSizeNxNemtFirstPass ) = tempCS->cost;
#endif
#if WCG_EXT
DTRACE_MODE_COST( *tempCS, m_pcRdCost->getLambda( true ) );
#else
DTRACE_MODE_COST( *tempCS, m_pcRdCost->getLambda() );
#endif
//************************************************ 最優模式的檢測及設置
xCheckBestMode( tempCS, bestCS, partitioner, encTestMode );
#if JEM_TOOLS
//************************************************ now we check whether the second pass of SIZE_2Nx2N and the whole Intra SIZE_NxN should be skipped or not
if( !emtCuFlag && !tempCS->slice->isIntra() && bestCU && bestCU->predMode != MODE_INTRA && cu.partSize == SIZE_2Nx2N && m_pcEncCfg->getFastInterEMT() && ( m_pcEncCfg->getUseSaveLoadEncInfo() ? ( bestInterCost < MAX_DOUBLE ) : true ) )
{
const double thEmtInterFastSkipIntra = 1.4; // Skip checking Intra if "2Nx2N using DCT2" is worse than best Inter mode
if( costSize2Nx2NemtFirstPass > thEmtInterFastSkipIntra * bestInterCost )
//對應AMT中跳過第二個通道的相關判斷操作
{
skipSecondEmtPass = true;
m_modeCtrl->setSkipSecondEMTPass( true );
break;
}
}
#if HEVC_USE_PART_SIZE //默認flase
//now we check whether the second pass of EMT with SIZE_NxN should be skipped or not
if( !emtCuFlag && isAllIntra && cu.partSize == SIZE_NxN && m_pcEncCfg->getFastIntraEMT() )
{
costSize2Nx2NemtFirstPass = m_modeCtrl->getEmtSize2Nx2NFirstPassCost();
const double thEmtIntraFastSkipNxN = 1.2; // Skip checking "NxN using EMT" if "NxN using DCT2" is worse than "2Nx2N using DCT2"
if( costSizeNxNemtFirstPass > thEmtIntraFastSkipNxN * costSize2Nx2NemtFirstPass )
{
break;
}
}
#endif
#endif
} //for emtCuFlag
}