前言
前文x265预测入口说到,在X265中,根据事先设定的RDO级别会有不同优化级别的帧间预测函数,但大体流程上是一致的,无非是使用了提前终止的快速优化方法。本文以最高的RD级别对应的Analysis::compressInterCU_rd5_6为例讲解X265帧间预测的代码实现
帧间预测入口
代码如下:
SplitData Analysis::compressInterCU_rd5_6(const CUData& parentCTU, const CUGeom& cuGeom, int32_t qp)
{
......
bool bHEVCBlockAnalysis = (m_param->bAnalysisType == AVC_INFO && cuGeom.numPartitions > 16);
bool bRefineAVCAnalysis = (m_param->analysisReuseLevel == 7 && (m_modeFlag[0] || m_modeFlag[1]));
bool bNooffloading = !(m_param->bAnalysisType == AVC_INFO);
if (bHEVCBlockAnalysis || bRefineAVCAnalysis || bNooffloading)
{
......
/* Step 1. Evaluate Merge/Skip candidates for likely early-outs */
//计算当前CTU对应各个帧间预测模式代价
if ((mightNotSplit && !md.bestMode && !bCtuInfoCheck) ||
(m_param->bAnalysisType == AVC_INFO && m_param->analysisReuseLevel == 7 && (m_modeFlag[0] || m_modeFlag[1])))
{
......
checkMerge2Nx2N_rd5_6(md.pred[PRED_SKIP], md.pred[PRED_MERGE], cuGeom);//skip/merge模式帧间预测
......
checkInter_rd5_6(md.pred[PRED_2Nx2N], cuGeom, SIZE_2Nx2N, refMasks);//其它帧间预测模式
checkBestMode(md.pred[PRED_2Nx2N], cuGeom.depth);//挑选最佳模式
if (m_param->bEnableRecursionSkip && depth && m_modeDepth[depth - 1].bestMode)
skipRecursion = md.bestMode && !md.bestMode->cu.getQtRootCbf(0);
}
if (m_param->bAnalysisType == AVC_INFO && md.bestMode && cuGeom.numPartitions <= 16 && m_param->analysisReuseLevel == 7)
skipRecursion = true;
// estimate split cost
/* Step 2. Evaluate each of the 4 split sub-blocks in series */
//递归计算当前CU四叉树划分的下一深度帧间预测代价
if (mightSplit && !skipRecursion)
{
......
for (uint32_t subPartIdx = 0; subPartIdx < 4; subPartIdx++)
{
const CUGeom& childGeom = *(&cuGeom + cuGeom.childOffset + subPartIdx);
if (childGeom.flags & CUGeom::PRESENT)
{
......
splitData[subPartIdx] = compressInterCU_rd5_6(parentCTU, childGeom, nextQP);//递归计算,用splitData数组记录对应CU对应的代价
// Save best CU and pred data for this sub CU
......
}
else
{
splitCU->setEmptyPart(childGeom, subPartIdx);
}
}
......
}
/* If analysis mode is simple do not Evaluate other modes */
if (m_param->bAnalysisType == AVC_INFO && m_param->analysisReuseLevel == 7)
{
if (m_slice->m_sliceType == P_SLICE)
{
if (m_checkMergeAndSkipOnly[0])
skipModes = true;
}
else
{
if (m_checkMergeAndSkipOnly[0] && m_checkMergeAndSkipOnly[1])
skipModes = true;
}
}
/* Split CUs
* 0 1
* 2 3 */
allSplitRefs = splitData[0].splitRefs | splitData[1].splitRefs | splitData[2].splitRefs | splitData[3].splitRefs;
/* Step 3. Evaluate ME (2Nx2N, rect, amp) and intra modes at current depth */
//在当前深度对各种划分方式计算运动估计代价和帧内模式代价
if (mightNotSplit)
{
......
if (!skipModes)
{
......
if (m_slice->m_sliceType == B_SLICE)
{
md.pred[PRED_BIDIR].cu.initSubCU(parentCTU, cuGeom, qp);
checkBidir2Nx2N(md.pred[PRED_2Nx2N], md.pred[PRED_BIDIR], cuGeom);//B帧双向预测,2Nx2N
if (md.pred[PRED_BIDIR].sa8dCost < MAX_INT64)