xCompressCU
// 以下 do 循环开始遍历 m_ComprCUCtxList 中的测试模式(划分、模式、QP)
do
{
// 遍历分量,将 PLT 的相关变量填充
for (int i = compBegin; i < (compBegin + numComp); i++)
{
}
// 当前测试模式
EncTestMode currTestMode = m_modeCtrl->currTestMode();
// 当前测试模式的允许最大 cost
currTestMode.maxCostAllowed = maxCostAllowed;
// 若使用 DQP 且是 SepTree 且当前为色度分量
if (pps.getUseDQP() && partitioner.isSepTree(*tempCS) && isChroma( partitioner.chType ))
{
// 若对应亮度位置存在,则当前测试模式 QP 值设定为对应 bestCS 亮度位置的 QP 值
if (colLumaCu)
{
currTestMode.qp = colLumaCu->qp;
}
}
// 若当前 QG 可用,且使用亮度 delta QP 映射或(使用 perceptQPA,且不使用 rate control,且使用DQP)
if (partitioner.currQgEnable() && (.....
// 若当前测试模式的 QP 值有效,则更新 lambda
{
if (currTestMode.qp >= 0)
{
updateLambda (&slice, currTestMode.qp,
m_pcEncCfg->getWCGChromaQPControl().isEnabled(),
CS::isDualITree (*tempCS) || (partitioner.currDepth == 0));
}
}
// 若当前测试模式是 INTER
if( currTestMode.type == ETM_INTER_ME )
{
tempCS->bestCS = bestCS;
xCheckRDCostInterIMV(tempCS, bestCS, partitioner, currTestMode, bestIntPelCost);
tempCS->bestCS = nullptr;
}
// 若当前测试模式是 HASH INTER,则检查 HashInter 的 RD cost
else if (currTestMode.type == ETM_HASH_INTER)
{
xCheckRDCostHashInter( tempCS, bestCS, partitioner, currTestMode );
}
// 若当前测试模式是 AFFINE,则检查 Affine 的 RD cost
else if( currTestMode.type == ETM_AFFINE )
{
xCheckRDCostAffineMerge2Nx2N( tempCS, bestCS, partitioner, currTestMode );
}
// 若当前测试模式是 RECO_CACHED,则检查 Reuse Cached 的 RD cost
else if( currTestMode.type == ETM_RECO_CACHED )
{
xReuseCachedResult( tempCS, bestCS, partitioner );
}
// 若当前测试模式是 MERGE_SKIP,则检查 Merge 的 RD cost
else if( currTestMode.type == ETM_MERGE_SKIP )
{
xCheckRDCostMerge2Nx2N( tempCS, bestCS, partitioner, currTestMode );
CodingUnit* cu = bestCS->getCU(partitioner.chType);
// 若 bestCS 的 cu 不使用 skip,则不使用 mmvd(Merge mode with MVD)
if (cu)
cu->mmvdSkip = cu->skip == false ? false : cu->mmvdSkip;
}
// 若当前测试模式是 MERGE_GEO,则检查 Merge Geo 的 RD cost
else if( currTestMode.type == ETM_MERGE_GEO )
{
xCheckRDCostMergeGeo2Nx2N( tempCS, bestCS, partitioner, currTestMode );
}
// 若当前测试模式是 INTRA
else if( currTestMode.type == ETM_INTRA )
{
xCheckRDCostIntra(tempCS, bestCS, partitioner, currTestMode, false);
}
// 若当前测试模式是 PALETTE,则检查 PLT 的 RD cost
else if (currTestMode.type == ETM_PALETTE)
{
xCheckPLT( tempCS, bestCS, partitioner, currTestMode );
}
// 若当前测试模式是 IBC(Intra block copy),则检查 IBC 的 RD cost
else if (currTestMode.type == ETM_IBC)
{
xCheckRDCostIBCMode(tempCS, bestCS, partitioner, currTestMode);
}
// 若当前测试模式是 IBC_MERGE,则检查 IBC_MERGE 的 RD cost
else if (currTestMode.type == ETM_IBC_MERGE)
{
xCheckRDCostIBCModeMerge2Nx2N(tempCS, bestCS, partitioner, currTestMode);
}
// 若当前测试模式划分模式(ETM_SPLIT_QT、ETM_SPLIT_BT_H、ETM_SPLIT_BT_V、ETM_SPLIT_TT_H、ETM_SPLIT_TT_V)
else if( isModeSplit( currTestMode ) )
xCheckRDCostIntra
void EncCu::xCheckRDCostIntra( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &partitioner, const EncTestMode& encTestMode )
{
for( uint8_t emtCuFlag = 0; emtCuFlag <= considerEmtSecondPass; emtCuFlag++ )
{
tempCS->initStructData( encTestMode.qp, encTestMode.lossless ); //tempCS清空初始化
CodingUnit &cu = tempCS->addCU( CS::getArea( *tempCS, tempCS->area, partitioner.chType ), partitioner.chType );
//tempCS添加cu,初始化cu,用于帧内预测
partitioner.setCUData( cu );
cu.slice = tempCS->slice;
cu.tileIdx = tempCS->picture->tileMap->getTileIdxMap( tempCS->area.lumaPos() );
cu.skip = false;
cu.partSize = encTestMode.partSize;
cu.predMode = MODE_INTRA;
CU::addPUs( cu ); //cu添加pu
tempCS->interHad = interHad;
//1.亮度帧内预测
if( isLuma( partitioner.chType ) )
{
m_pcIntraSearch->estIntraPredLumaQT( cu, partitioner );//亮度帧内预测
// cu.firstPU
if (m_pcEncCfg->getUsePbIntraFast() && tempCS->dist == std::numeric_limits<Distortion>::max()
&& 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 ) ) //I帧且亮度色度不同划分时isDualITree为true
{
cu.cs->picture->getRecoBuf( cu.Y() ).copyFrom( cu.cs->getRecoBuf( COMPONENT_Y ) );
}
}
//注意:这里是!CS::isDualITree( *tempCS )
//2.色度帧内预测
if( tempCS->area.chromaFormat != CHROMA_400 && ( partitioner.chType == CHANNEL_TYPE_CHROMA || !CS::isDualITree( *tempCS ) ) )
{
m_pcIntraSearch->estIntraPredChromaQT( cu, partitioner ); //色度帧内预测
}
cu.rootCbf = false;
for( uint32_t t = 0; t < getNumberValidTBlocks( *cu.cs->pcv ); t++ )
{
cu.rootCbf |= cu.firstTU->cbf[t] != 0;
}
// 3.接下来计算编码比特数和失真,计算cost
m_CABACEstimator->resetBits();
if( pps.getTransquantBypassEnabledFlag() )
{
m_CABACEstimator->cu_transquant_bypass_flag( cu );
}
if( !cu.cs->slice->isIntra() && cu.Y().valid())
{
m_CABACEstimator->cu_skip_flag ( cu );
}
m_CABACEstimator->pred_mode ( cu );
#if JVET_L0283_MULTI_REF_LINE
m_CABACEstimator->extend_ref_line( cu );
#endif
m_CABACEstimator->cu_pred_data ( cu );
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); //cost
xEncodeDontSplit( *tempCS, partitioner );
xCheckDQP( *tempCS, partitioner );
// we save the cost of the modes for the first EMT pass
if( !emtCuFlag ) static_cast< double& >( cu.partSize == SIZE_2Nx2N ? costSize2Nx2NemtFirstPass : costSizeNxNemtFirstPass ) = tempCS->cost;
DTRACE_MODE_COST( *tempCS, m_pcRdCost->getLambda( true ) );
DTRACE_MODE_COST( *tempCS, m_pcRdCost->getLambda() );
xCheckBestMode( tempCS, bestCS, partitioner, encTestMode );
//将帧内最优模式的cost与bestCS的cost对比 //将最优模式存入bestCS
//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() )
{
}
} //for emtCuFlag
}
estIntraPredLumaQT
/******** 进入最终对RD候选列表中的模式进一步精选RDcost ********/
//遍历RD候选列表
for (int mode = isSecondColorSpace ? 0 : -2 * int(testBDPCM); mode < (int)uiRdModeList.size(); mode++)
{
......
// Mode loop RD候选模式的循环遍历结束,选出最优模式, 设置最优模式
//当前候选模式是否是ISP
cu.ispMode = uiOrgMode.ispMod;
//定义当前PU最优的亮度帧内预测模式
ModeInfo uiBestPUMode;
......
cu.ispMode = uiBestPUMode.ispMod;
cu.lfnstIdx = bestLfnstIdx;
if( validReturn )
{
//如果色彩转换
if (cu.colorTransform)
{
cs.useSubStructure(*csBest, partitioner.chType, pu, true, true, KEEP_PRED_AND_RESI_SIGNALS, KEEP_PRED_AND_RESI_SIGNALS, true);
}
else
{
cs.useSubStructure(*csBest, partitioner.chType, pu.singleChan(CHANNEL_TYPE_LUMA), true, true, KEEP_PRED_AND_RESI_SIGNALS,
KEEP_PRED_AND_RESI_SIGNALS, true);
}
}
csBest->releaseIntermediateData();
if( validReturn )
{
//=== update PU data ====
//更新PU数据
//auto &pu = *cu.firstPU;
cu.mipFlag = uiBestPUMode.mipFlg;
pu.mipTransposedFlag = uiBestPUMode.mipTrFlg;
pu.multiRefIdx = uiBestPUMode.mRefId;
pu.intraDir[ CHANNEL_TYPE_LUMA ] = uiBestPUMode.modeId;
//pu.intraDir[]=
cu.bdpcmMode = bestBDPCMMode;
if (cu.colorTransform)
{
CHECK(pu.intraDir[CHANNEL_TYPE_CHROMA] != DM_CHROMA_IDX, "chroma should use DM mode for adaptive color transform");
}
}
}
//===== reset context models =====
//重置上下文模型
m_CABACEstimator->getCtx() = ctxStart;
//bool validReturn = false;
//validReturn |= tmpValidReturn;
return validReturn;
}