欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

x265中compressIntraCU()分析(版本2.8)

程序员文章站 2022-07-07 11:59:06
...

一. 函数关系调用图: 

x265中compressIntraCU()分析(版本2.8)

二.  函数内容概括:

x265中compressIntraCU()分析(版本2.8)

三. 源码分析:

/*
 ========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作为返回值
}

 

相关标签: intra x265 HEVC