/*
========Analysed by: yangxin
========Date: 2018.8
========Function: compressItraCU()函数,帧内模式分析 full analysis for an I-slice CU
========
*/
uint64_t Analysis::compressIntraCU(const CUData& parentCTU, const CUGeom& cuGeom, int32_t qp)
{
uint32_t depth = cuGeom.depth;//--CU的几何结构的深度,深度值范围[0,3]
ModeDepth& md = m_modeDepth[depth];//--
md.bestMode = NULL;
bool mightSplit = !(cuGeom.flags & CUGeom::LEAF);//----为ture非叶子节点,还需要继续分裂
bool mightNotSplit = !(cuGeom.flags & CUGeom::SPLIT_MANDATORY);//---为ture,!(CU split is mandatory if CU is inside frame and can be split)
bool bAlreadyDecided = m_param->intraRefine != 4 && parentCTU.m_lumaIntraDir[cuGeom.absPartIdx] != (uint8_t)ALL_IDX;//--
bool bDecidedDepth = m_param->intraRefine != 4 && parentCTU.m_cuDepth[cuGeom.absPartIdx] == depth;
int split = 0;
if (m_param->intraRefine && m_param->intraRefine != 4)//--帧内精细化且不等于4
{
split = m_param->scaleFactor && ((cuGeom.log2CUSize == (uint32_t)(g_log2Size[m_param->minCUSize] + 1)) && bDecidedDepth);
if (cuGeom.log2CUSize == (uint32_t)(g_log2Size[m_param->minCUSize]) && !bDecidedDepth)
bAlreadyDecided = false;
}
if (bAlreadyDecided)//--已经决策确定的模式
{
if (bDecidedDepth)//--已经确定的深度
{
Mode& mode = md.pred[0];
md.bestMode = &mode;
mode.cu.initSubCU(parentCTU, cuGeom, qp);//---initialize Sub partition
bool reuseModes = !((m_param->intraRefine == 3) ||
(m_param->intraRefine == 2 && parentCTU.m_lumaIntraDir[cuGeom.absPartIdx] > DC_IDX));//--intraRefine=0/1
if (reuseModes)
{
memcpy(mode.cu.m_lumaIntraDir, parentCTU.m_lumaIntraDir + cuGeom.absPartIdx, cuGeom.numPartitions);
memcpy(mode.cu.m_chromaIntraDir, parentCTU.m_chromaIntraDir + cuGeom.absPartIdx, cuGeom.numPartitions);
}
checkIntra(mode, cuGeom, (PartSize)parentCTU.m_partSize[cuGeom.absPartIdx]);//-- full RD search of intra modes
if (m_bTryLossless)
tryLossless(cuGeom);//--无损编码
if (mightSplit)
addSplitFlagCost(*md.bestMode, cuGeom.depth);//--add the RD cost of coding a split flag (0 or 1) to the given mode
}
}
else if (cuGeom.log2CUSize != MAX_LOG2_CU_SIZE && mightNotSplit)//---不需要再分裂,则不需要递归调用
{
md.pred[PRED_INTRA].cu.initSubCU(parentCTU, cuGeom, qp);//---initialize Sub partition
checkIntra(md.pred[PRED_INTRA], cuGeom, SIZE_2Nx2N);//===intra 2Nx2N模式
checkBestMode(md.pred[PRED_INTRA], depth);
if (cuGeom.log2CUSize == 3 && m_slice->m_sps->quadtreeTULog2MinSize < 3)//==CU的尺寸是8x8,即最小的CU对应的预测单元是NxN
{
md.pred[PRED_INTRA_NxN].cu.initSubCU(parentCTU, cuGeom, qp);//---initialize Sub partition
checkIntra(md.pred[PRED_INTRA_NxN], cuGeom, SIZE_NxN);//===intra NxN模式
checkBestMode(md.pred[PRED_INTRA_NxN], depth);//---check whether current mode is the new best
}
if (m_bTryLossless)
tryLossless(cuGeom);
if (mightSplit)
addSplitFlagCost(*md.bestMode, cuGeom.depth);
}
// stop recursion if we reach the depth of previous analysis decision//--达到先前分析决策的深度就停止递归
mightSplit &= !(bAlreadyDecided && bDecidedDepth) || split; //-- a = a &(!(b&&c)||d)
if (mightSplit)//继续分裂
{
Mode* splitPred = &md.pred[PRED_SPLIT];
splitPred->initCosts();
CUData* splitCU = &splitPred->cu;
splitCU->initSubCU(parentCTU, cuGeom, qp);//--initialize Sub partition 4 x sub CU
uint32_t nextDepth = depth + 1;
ModeDepth& nd = m_modeDepth[nextDepth];
invalidateContexts(nextDepth);
Entropy* nextContext = &m_rqt[depth].cur;
int32_t nextQP = qp;
uint64_t curCost = 0;
int skipSplitCheck = 0;
for (uint32_t subPartIdx = 0; subPartIdx < 4; subPartIdx++)//---循环每个子CU,执行相同操作
{
const CUGeom& childGeom = *(&cuGeom + cuGeom.childOffset + subPartIdx);
if (childGeom.flags & CUGeom::PRESENT)
{
m_modeDepth[0].fencYuv.copyPartToYuv(nd.fencYuv, childGeom.absPartIdx);
m_rqt[nextDepth].cur.load(*nextContext);
if (m_slice->m_pps->bUseDQP && nextDepth <= m_slice->m_pps->maxCuDQPDepth)
nextQP = setLambdaFromQP(parentCTU, calculateQpforCuSize(parentCTU, childGeom));
if (m_param->bEnableSplitRdSkip)//--Enable skipping split RD analysis when sum of split CU rdCost larger than none split CU rdCost for Intra CU
{
curCost += compressIntraCU(parentCTU, childGeom, nextQP);//==递归调用
if (m_modeDepth[depth].bestMode && curCost > m_modeDepth[depth].bestMode->rdCost)
{
skipSplitCheck = 1;
break;
}
}
else
compressIntraCU(parentCTU, childGeom, nextQP);//==递归调用
// Save best CU and pred data for this sub CU //--对当前子CU保存最佳CU和预测数据
splitCU->copyPartFrom(nd.bestMode->cu, childGeom, subPartIdx);//--Copy the results of a sub-part (split) CU to the parent CU
splitPred->addSubCosts(*nd.bestMode);//--
//--Copy Small YUV buffer to the part of other Big YUV buffer
nd.bestMode->reconYuv.copyToPartYuv(splitPred->reconYuv, childGeom.numPartitions * subPartIdx);
nextContext = &nd.bestMode->contexts;
}
else
{
/* record the depth of this non-present sub-CU */
splitCU->setEmptyPart(childGeom, subPartIdx);//--记录下这个非当前子CU的深度
/* Set depth of non-present CU to 0 to ensure that correct CU is fetched as reference to code deltaQP */
if (bAlreadyDecided)
memset(parentCTU.m_cuDepth + childGeom.absPartIdx, 0, childGeom.numPartitions);//--将非当前CU的所有4X4的深度都置0
}
}
if (!skipSplitCheck)
{
nextContext->store(splitPred->contexts);
if (mightNotSplit)
addSplitFlagCost(*splitPred, cuGeom.depth);
else
updateModeCost(*splitPred);
checkDQPForSplitPred(*splitPred, cuGeom);//---检测 deltas QP(残差QP)
checkBestMode(*splitPred, depth);//---check whether current mode is the new best
}
}
if (m_param->bEnableRdRefine && depth <= m_slice->m_pps->maxCuDQPDepth)//--只有在rd5\6才开启率失真精细化,默认关闭
{
int cuIdx = (cuGeom.childOffset - 1) / 3;
cacheCost[cuIdx] = md.bestMode->rdCost;
}
if ((m_limitTU & X265_TU_LIMIT_NEIGH) && cuGeom.log2CUSize >= 4)//--log2CUSize范围是[3,6],对应的TU深度
{
CUData* ctu = md.bestMode->cu.m_encData->getPicCTU(parentCTU.m_cuAddr);//--
int8_t maxTUDepth = -1;
for (uint32_t i = 0; i < cuGeom.numPartitions; i++)
maxTUDepth = X265_MAX(maxTUDepth, md.bestMode->cu.m_tuDepth[i]);
ctu->m_refTuDepth[cuGeom.geomRecurId] = maxTUDepth;//--TU depth of CU at depths 0, 1 and 2
}
/* Copy best data to encData CTU and recon */
md.bestMode->cu.copyToPic(depth);//--- Copy completed predicted CU to CTU in picture
if (md.bestMode != &md.pred[PRED_SPLIT])
md.bestMode->reconYuv.copyToPicYuv(*m_frame->m_reconPic, parentCTU.m_cuAddr, cuGeom.absPartIdx);//-- Copy YUV buffer to picture buffer
return md.bestMode->rdCost;//--最好模式的cost作为返回值
}