Search::encodeResAndCalcRd[Skip/Inter]CU()

Search::encodeResAndCalcRdSkipCU()

/* Note: this function overwrites the RD cost variables of interMode, but leaves the sa8d cost unharmed 
   計算interMode爲skip mode時的rdcost

   過程:
		1.計算luma+chroma的distiortion
		2.計算skipFlag+mergeIdx的bits開銷,skip模式無殘差bits開銷。
		3.更新energe和rdcost
		4.保存熵編碼上下文
*/
void Search::encodeResAndCalcRdSkipCU(Mode& interMode)
{
	//取interMode的CUData
    CUData& cu = interMode.cu;
	//取interMode的reconYUV、fencYUV、predYUV
    Yuv* reconYuv = &interMode.reconYuv;
    const Yuv* fencYuv = interMode.fencYuv;
    Yuv* predYuv = &interMode.predYuv;
    X265_CHECK(!cu.isIntra(0), "intra CU not expected\n");
	//得到當前CU的深度
    uint32_t depth  = cu.m_cuDepth[0];

    // No residual coding : SKIP mode

	//設置CU爲skip
    cu.setPredModeSubParts(MODE_SKIP);
	//清空cbf
    cu.clearCbf();
    //設置TU深度
	cu.setTUDepthSubParts(0, 0, depth);
	//將interMode的預測YUV拷貝給recon
    reconYuv->copyFromYuv(interMode.predYuv);

    // 計算Luma的distortion
    int part = partitionFromLog2Size(cu.m_log2CUSize[0]);
    interMode.lumaDistortion = primitives.cu[part].sse_pp(fencYuv->m_buf[0], fencYuv->m_size, reconYuv->m_buf[0], reconYuv->m_size);
    interMode.distortion = interMode.lumaDistortion;
    // 若有色度,則累加上Chroma的distortion
    if (m_csp != X265_CSP_I400 && m_frame->m_fencPic->m_picCsp != X265_CSP_I400)
    {
        interMode.chromaDistortion = m_rdCost.scaleChromaDist(1, primitives.chroma[m_csp].cu[part].sse_pp(fencYuv->m_buf[1], fencYuv->m_csize, reconYuv->m_buf[1], reconYuv->m_csize));
        interMode.chromaDistortion += m_rdCost.scaleChromaDist(2, primitives.chroma[m_csp].cu[part].sse_pp(fencYuv->m_buf[2], fencYuv->m_csize, reconYuv->m_buf[2], reconYuv->m_csize));
        interMode.distortion += interMode.chromaDistortion;
    }
    cu.m_distortion[0] = interMode.distortion;
    
	//加載熵編碼上下文
	m_entropyCoder.load(m_rqt[depth].cur);
	//重置bits
    m_entropyCoder.resetBits();
    if (m_slice->m_pps->bTransquantBypassEnabled)
        m_entropyCoder.codeCUTransquantBypassFlag(cu.m_tqBypass[0]);
	//編碼skipFlag
    m_entropyCoder.codeSkipFlag(cu, 0);
	//得到skipFlag的bits開銷
    int skipFlagBits = m_entropyCoder.getNumberOfWrittenBits();
	//編碼merge備選集索引
    m_entropyCoder.codeMergeIndex(cu, 0);
	//得到merge備選集索引開銷
    interMode.mvBits = m_entropyCoder.getNumberOfWrittenBits() - skipFlagBits;
	//skip無係數開銷
    interMode.coeffBits = 0;
	//總開銷 = mv開銷 + merge備選集索引開銷
    interMode.totalBits = interMode.mvBits + skipFlagBits;
	//更新psy/ssim能量
    if (m_rdCost.m_psyRd)
        interMode.psyEnergy = m_rdCost.psyCost(part, fencYuv->m_buf[0], fencYuv->m_size, reconYuv->m_buf[0], reconYuv->m_size);
    else if(m_rdCost.m_ssimRd)
        interMode.ssimEnergy = m_quant.ssimDistortion(cu, fencYuv->m_buf[0], fencYuv->m_size, reconYuv->m_buf[0], reconYuv->m_size, cu.m_log2CUSize[0], TEXT_LUMA, 0);
	//更新殘差能量
    interMode.resEnergy = primitives.cu[part].sse_pp(fencYuv->m_buf[0], fencYuv->m_size, predYuv->m_buf[0], predYuv->m_size);
    //更新rdcost
	updateModeCost(interMode);
	//保持上下文
    m_entropyCoder.store(interMode.contexts);
}

Search::encodeResAndCalcRdInterCU()

/* encode residual and calculate rate-distortion for a CU block.
 * Note: this function overwrites the RD cost variables of interMode, but leaves the sa8d cost unharmed 
 * 爲CU編碼殘差並計算rdcost。該函數可能重寫rdcost,但不會改變sa8d cost 
  
	過程:
		1.取interMode的CUData、reconYUV、fencYUV、predYUV、resiYUV以及當前CU深度depth
		2.根據fencYUV和predYUV計算resiYUV,即resiYUV = fencYUV - predYUV
		3.加載熵編碼上下文
		4.對殘差resiYUV進行編碼並得到cost
		5.若不允許transform-quantization旁路,則計算cbf = 0時候的rdcost
			1.計算cbf = 0時候的distortion
			2.計算cbf = 0時候的bits
			3.根據distortion和bits得到cbf = 0時候的rdcost
			4.若cbf = 0時的rdcost<有殘差時候的rdcost,則設置cbf = 0
		6.若cbf != 0,也就是有殘差,則保存殘差數據
		7.編碼TransquantBypassFlag
		8.計算bits
			·若是skip,則bits = SkipFlag + MergeIndex
			·若非skip,則bits = SkipFlag + PredMode + PartSize + PredInfo + Coeff
		9.恢復reconYUV,即reconYUV = predYUV + resiYUV
		10.更新interMode的distortion
		11.更新interMode的energy、bits、rdcost
 */
void Search::encodeResAndCalcRdInterCU(Mode& interMode, const CUGeom& cuGeom)
{
    ProfileCUScope(interMode.cu, interRDOElapsedTime[cuGeom.depth], countInterRDO[cuGeom.depth]);

	//取interMode的cu
    CUData& cu = interMode.cu;
	//取interMode的recon、pred、enc YUV
    Yuv* reconYuv = &interMode.reconYuv;
    Yuv* predYuv = &interMode.predYuv;
	const Yuv* fencYuv = interMode.fencYuv;
	//取當前CU的depth
    uint32_t depth = cuGeom.depth;
	//取殘差YUV
    ShortYuv* resiYuv = &m_rqt[depth].tmpResiYuv;

    X265_CHECK(!cu.isIntra(0), "intra CU not expected\n");

    uint32_t log2CUSize = cuGeom.log2CUSize;
    int sizeIdx = log2CUSize - 2;

	//計算殘差YUV,即resiYuv = fencYuv - predYuv
    resiYuv->subtract(*fencYuv, *predYuv, log2CUSize, m_frame->m_fencPic->m_picCsp);

    uint32_t tuDepthRange[2];
    cu.getInterTUQtDepthRange(tuDepthRange, 0);

	//加載熵編碼上下文
    m_entropyCoder.load(m_rqt[depth].cur);

    if ((m_limitTU & X265_TU_LIMIT_DFS) && !(m_limitTU & X265_TU_LIMIT_NEIGH))
        m_maxTUDepth = -1;
    else if (m_limitTU & X265_TU_LIMIT_BFS)
        memset(&m_cacheTU, 0, sizeof(TUInfoCache));

	/*
		計算殘差值並得到cost
	*/
    Cost costs;
    if (m_limitTU & X265_TU_LIMIT_NEIGH)
    {
        /* Save and reload maxTUDepth to avoid changing of maxTUDepth between modes */
        int32_t tempDepth = m_maxTUDepth;
        if (m_maxTUDepth != -1)
        {
            uint32_t splitFlag = interMode.cu.m_partSize[0] != SIZE_2Nx2N;
            uint32_t minSize = tuDepthRange[0];
            uint32_t maxSize = tuDepthRange[1];
            maxSize = X265_MIN(maxSize, cuGeom.log2CUSize - splitFlag);
            m_maxTUDepth = x265_clip3(cuGeom.log2CUSize - maxSize, cuGeom.log2CUSize - minSize, (uint32_t)m_maxTUDepth);
        }
        estimateResidualQT(interMode, cuGeom, 0, 0, *resiYuv, costs, tuDepthRange);
        m_maxTUDepth = tempDepth;
    }
    else
        estimateResidualQT(interMode, cuGeom, 0, 0, *resiYuv, costs, tuDepthRange);

	//是否旁路transform和quantization,即無損編碼
    uint32_t tqBypass = cu.m_tqBypass[0];
	//若不旁路,則有損
    if (!tqBypass)
    {
		/*
			計算cbf = 0時候的distortion
		*/
        sse_t cbf0Dist = primitives.cu[sizeIdx].sse_pp(fencYuv->m_buf[0], fencYuv->m_size, predYuv->m_buf[0], predYuv->m_size);
        //若有色度,則累加chroma的失真
		if (m_csp != X265_CSP_I400 && m_frame->m_fencPic->m_picCsp != X265_CSP_I400)
        {
            cbf0Dist += m_rdCost.scaleChromaDist(1, primitives.chroma[m_csp].cu[sizeIdx].sse_pp(fencYuv->m_buf[1], predYuv->m_csize, predYuv->m_buf[1], predYuv->m_csize));
            cbf0Dist += m_rdCost.scaleChromaDist(2, primitives.chroma[m_csp].cu[sizeIdx].sse_pp(fencYuv->m_buf[2], predYuv->m_csize, predYuv->m_buf[2], predYuv->m_csize));
        }

        /* Consider the RD cost of not signaling any residual 
			計算cbf = 0時候的bits開銷	*/
		//加載熵編碼上下文
        m_entropyCoder.load(m_rqt[depth].cur);
		//重置bits
        m_entropyCoder.resetBits();
		//cbf爲0時,進行編碼
        m_entropyCoder.codeQtRootCbfZero();
		//得到cbf爲0時的bits開銷
        uint32_t cbf0Bits = m_entropyCoder.getNumberOfWrittenBits();

		/*
			根據distortion和bits計算energy和rdcost
		*/
        uint32_t cbf0Energy; uint64_t cbf0Cost;
        if (m_rdCost.m_psyRd)
        {
            cbf0Energy = m_rdCost.psyCost(log2CUSize - 2, fencYuv->m_buf[0], fencYuv->m_size, predYuv->m_buf[0], predYuv->m_size);
            cbf0Cost = m_rdCost.calcPsyRdCost(cbf0Dist, cbf0Bits, cbf0Energy);
        }
        else if(m_rdCost.m_ssimRd)
        {
            cbf0Energy = m_quant.ssimDistortion(cu, fencYuv->m_buf[0], fencYuv->m_size, predYuv->m_buf[0], predYuv->m_size, log2CUSize, TEXT_LUMA, 0);
            cbf0Cost = m_rdCost.calcSsimRdCost(cbf0Dist, cbf0Bits, cbf0Energy);
        }
        else
            cbf0Cost = m_rdCost.calcRdCost(cbf0Dist, cbf0Bits);

		//若cbf = 0時候的rdcost < 有殘差的rdcost,則cbf置0
        if (cbf0Cost < costs.rdcost)
        {
            cu.clearCbf();
            cu.setTUDepthSubParts(0, 0, depth);
        }
    }

	//若cbf!=0,則保存殘差數據
    if (cu.getQtRootCbf(0))
        saveResidualQTData(cu, *resiYuv, 0, 0);

    /* calculate signal bits for inter/merge/skip coded CU */
	//加載熵編碼上下文
    m_entropyCoder.load(m_rqt[depth].cur);
	//重置bits
    m_entropyCoder.resetBits();
    if (m_slice->m_pps->bTransquantBypassEnabled)
        m_entropyCoder.codeCUTransquantBypassFlag(tqBypass);

	/*
		計算bits
	*/
    uint32_t coeffBits, bits, mvBits;
	//若是merge,且2Nx2N,且CBF = 0,則是skip模式
    if (cu.m_mergeFlag[0] && cu.m_partSize[0] == SIZE_2Nx2N && !cu.getQtRootCbf(0))
    {
		//設置爲skip模式
        cu.setPredModeSubParts(MODE_SKIP);

        /* Merge/Skip */
        coeffBits = mvBits = 0;
		//編碼skipFlag
        m_entropyCoder.codeSkipFlag(cu, 0);
        //得到skipFlag的bits開銷
		int skipFlagBits = m_entropyCoder.getNumberOfWrittenBits();
        //編碼mergeIdx
		m_entropyCoder.codeMergeIndex(cu, 0);
        //得到mergeIdx的bits開銷
		mvBits = m_entropyCoder.getNumberOfWrittenBits() - skipFlagBits;
		//總計skip模式下的bits總開銷
        bits = mvBits + skipFlagBits;
    }
	//若非skip模式下
    else
    {
		//編碼skipFlag
        m_entropyCoder.codeSkipFlag(cu, 0);
        //得到skipFlag的bits開銷
		int skipFlagBits = m_entropyCoder.getNumberOfWrittenBits();
		//編碼PredMode
        m_entropyCoder.codePredMode(cu.m_predMode[0]);
        //編碼partSize
		m_entropyCoder.codePartSize(cu, 0, cuGeom.depth);
		//編碼PredInfo
        m_entropyCoder.codePredInfo(cu, 0);
		//得到PredMode/partSize/PredInfo的bits總開銷
        mvBits = m_entropyCoder.getNumberOfWrittenBits() - skipFlagBits;

		//是否DQP
        bool bCodeDQP = m_slice->m_pps->bUseDQP;
		//編碼coeff
        m_entropyCoder.codeCoeff(cu, 0, bCodeDQP, tuDepthRange);
        //得到coeff的bits開銷
		bits = m_entropyCoder.getNumberOfWrittenBits();
        coeffBits = bits - mvBits - skipFlagBits;
    }
	//保存熵編碼上下文
    m_entropyCoder.store(interMode.contexts);

	/*
		得到reconYUV,用於後續計算distortion
	*/
    if (cu.getQtRootCbf(0)) //若有cbf,則reconYUV = predYUV+resiYUV
        reconYuv->addClip(*predYuv, *resiYuv, log2CUSize, m_frame->m_fencPic->m_picCsp);
    else //若無cbf,則reconYUV = predYUV
        reconYuv->copyFromYuv(*predYuv);

    /* 
	   update with clipped distortion and cost (qp estimation loop uses unclipped values)
       記錄luma和chroma的distortion
	 */
	//記錄interMode的Luma最優distortion
	sse_t bestLumaDist = primitives.cu[sizeIdx].sse_pp(fencYuv->m_buf[0], fencYuv->m_size, reconYuv->m_buf[0], reconYuv->m_size);
    interMode.distortion = bestLumaDist;
    //若有色度,則記錄interMode的chroma最優distortion
	if (m_csp != X265_CSP_I400 && m_frame->m_fencPic->m_picCsp != X265_CSP_I400)
    {
        sse_t bestChromaDist = m_rdCost.scaleChromaDist(1, primitives.chroma[m_csp].cu[sizeIdx].sse_pp(fencYuv->m_buf[1], fencYuv->m_csize, reconYuv->m_buf[1], reconYuv->m_csize));
        bestChromaDist += m_rdCost.scaleChromaDist(2, primitives.chroma[m_csp].cu[sizeIdx].sse_pp(fencYuv->m_buf[2], fencYuv->m_csize, reconYuv->m_buf[2], reconYuv->m_csize));
        interMode.chromaDistortion = bestChromaDist;
        interMode.distortion += bestChromaDist;
    }

	//記錄energy
    if (m_rdCost.m_psyRd)
        interMode.psyEnergy = m_rdCost.psyCost(sizeIdx, fencYuv->m_buf[0], fencYuv->m_size, reconYuv->m_buf[0], reconYuv->m_size);
    else if(m_rdCost.m_ssimRd)
        interMode.ssimEnergy = m_quant.ssimDistortion(cu, fencYuv->m_buf[0], fencYuv->m_size, reconYuv->m_buf[0], reconYuv->m_size, cu.m_log2CUSize[0], TEXT_LUMA, 0);
    interMode.resEnergy = primitives.cu[sizeIdx].sse_pp(fencYuv->m_buf[0], fencYuv->m_size, predYuv->m_buf[0], predYuv->m_size);
    
	/*
		記錄interMode的totalBits/lumaDistortion/coeffBits/mvBits/distortion
	*/
	interMode.totalBits = bits;
    interMode.lumaDistortion = bestLumaDist;
    interMode.coeffBits = coeffBits;
    interMode.mvBits = mvBits;
    cu.m_distortion[0] = interMode.distortion;

	//更新interMode的rdcost
    updateModeCost(interMode);
    checkDQP(interMode, cuGeom);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章