Analysis::checkBidir2Nx2N()

/*
	基于perd2Nx2N的预测信息计算bidir的预测信息
	函数前提:必须先进行了pred2Nx2N的计算

	过程:
		1.若限制了bidir,或之前在计算pred2Nx2N模式中前后向bestME的cost存在MAX,则不进行bidir分析,返回bidir的sa8d和cost为MAX
		2.将pred2Nx2N中分析的前后向bestME作为bidir的先后向bestME
		3.将pred2Nx2N中分析的前后向ref、mvp、mvpIdx作为birir的前后向ref、mvp、mvpIdx
		4.初始化bidir的cost,并设置partSize=2Nx2N,predMode=Inter,dir=3,mergeFlag=false
		5.加载pred2Nx2N的前后向MV作为bidir的前后向MV,并计算mvd
		6.进行运动补偿
		7.计算predYUV的distortion
		8.计算bidir的bits开销,进而计算其sa8d开销
		9.检查bidir前后向MV是否存在非0向量,若存在则
			1.以0向量为中心,merange为范围重新设置搜索窗口
			2.检查mvp是否在搜索窗口内
		10.若bidir前后向MV存在非0向量,且重置搜索窗口后mvp都在搜索窗口内,则进行0向量检查
			1.计算0MV的distortion
				·若m_bChromaSa8d且有chroma
					1.设置运动估计最优向量为0MV
					2.进行运动补偿
					3.累计上色度和亮度的satd
				·否则
					1.取先后向参考帧co-located像素
					2.对前后向参考帧co-located像素进行均值计算,为0MV的bidir预测像素
					3.计算sa8d
			2.计算0MV的bits和cost
			3.基于0MV的cost,重新检查最优MVP
			4.重新计算0MV更新最优MVP后的bits和cost
		11.若0MV的cost小于之前bidir的cost,则更新其cost、mvd、mvdIdx、0mv,并重新进行运动补偿,否则恢复MV为原来pred2Nx2N的MV
*/
void Analysis::checkBidir2Nx2N(const Mode& inter2Nx2N, Mode& bidir2Nx2N, const CUGeom& cuGeom)
{
	//取bidir2Nx2N的CUdata作为输出
    CUData& cu = bidir2Nx2N.cu;

	//若限制了双向预测 || 2Nx2N前向开销MAX || 2Nx2N后向开销MAX
    if (cu.isBipredRestriction() || inter2Nx2N.bestME[0][0].cost == MAX_UINT || inter2Nx2N.bestME[0][1].cost == MAX_UINT)
    {
		//结束双向预测计算,输出其sa8d和rdcost为MAX
        bidir2Nx2N.sa8dCost = MAX_INT64;
        bidir2Nx2N.rdCost = MAX_INT64;
        return;
    }

	//取原始YUV
    const Yuv& fencYuv = *bidir2Nx2N.fencYuv;
    MV   mvzero(0, 0);
    int  partEnum = cuGeom.log2CUSize - 2;

	//将2Nx2N的前向最优ME作为bidir的前向最优,其后向最优ME作为bidir的后向最优
    bidir2Nx2N.bestME[0][0] = inter2Nx2N.bestME[0][0];
    bidir2Nx2N.bestME[0][1] = inter2Nx2N.bestME[0][1];

	//取bidir的前后向最优ref、mvp、mvpIdx
    MotionData* bestME = bidir2Nx2N.bestME[0];
    int ref0    = bestME[0].ref;
    MV  mvp0    = bestME[0].mvp;
    int mvpIdx0 = bestME[0].mvpIdx;
    int ref1    = bestME[1].ref;
    MV  mvp1    = bestME[1].mvp;
    int mvpIdx1 = bestME[1].mvpIdx;

	//初始化bidir的cost
    bidir2Nx2N.initCosts();
	//设置partSize为2Nx2N
    cu.setPartSizeSubParts(SIZE_2Nx2N);
	//设置predMode为inter
    cu.setPredModeSubParts(MODE_INTER);
	//设置预测方向为3,即双向
    cu.setPUInterDir(3, 0, 0);
	//设置前后向参考帧
    cu.setPURefIdx(0, (int8_t)ref0, 0, 0);
    cu.setPURefIdx(1, (int8_t)ref1, 0, 0);
	//设置前后向mvpIdx
    cu.m_mvpIdx[0][0] = (uint8_t)mvpIdx0;
    cu.m_mvpIdx[1][0] = (uint8_t)mvpIdx1;
	//置mergeFlag为false
    cu.m_mergeFlag[0] = 0;

    /* Estimate cost of BIDIR using best 2Nx2N L0 and L1 motion vectors */
	//设置前向MV及计算mvd
    cu.setPUMv(0, bestME[0].mv, 0, 0);
    cu.m_mvd[0][0] = bestME[0].mv - mvp0;
	//设置后向MV及计算mvd
    cu.setPUMv(1, bestME[1].mv, 0, 0);
    cu.m_mvd[1][0] = bestME[1].mv - mvp1;

	//构造PU
    PredictionUnit pu(cu, cuGeom, 0);
	//进行运动补偿
    motionCompensation(cu, pu, bidir2Nx2N.predYuv, true, m_bChromaSa8d && (m_csp != X265_CSP_I400 && m_frame->m_fencPic->m_picCsp != X265_CSP_I400));

	//计算predYUV的distortion
    int sa8d = primitives.cu[partEnum].sa8d(fencYuv.m_buf[0], fencYuv.m_size, bidir2Nx2N.predYuv.m_buf[0], bidir2Nx2N.predYuv.m_size);
    //若m_bChromaSa8d且有色度,则累加上chroma的distortion
	if (m_bChromaSa8d && (m_csp != X265_CSP_I400 && m_frame->m_fencPic->m_picCsp != X265_CSP_I400))
    {
        /* Add in chroma distortion */
        sa8d += primitives.chroma[m_csp].cu[partEnum].sa8d(fencYuv.m_buf[1], fencYuv.m_csize, bidir2Nx2N.predYuv.m_buf[1], bidir2Nx2N.predYuv.m_csize);
        sa8d += primitives.chroma[m_csp].cu[partEnum].sa8d(fencYuv.m_buf[2], fencYuv.m_csize, bidir2Nx2N.predYuv.m_buf[2], bidir2Nx2N.predYuv.m_csize);
    }

	//累计bits开销
    bidir2Nx2N.sa8dBits = bestME[0].bits + bestME[1].bits + m_listSelBits[2] - (m_listSelBits[0] + m_listSelBits[1]);
    
	//通过distortion和bits计算rdcost
	bidir2Nx2N.sa8dCost = sa8d + m_rdCost.getCost(bidir2Nx2N.sa8dBits);

	//前后向的MV是否存在非0向量
    bool bTryZero = bestME[0].mv.notZero() || bestME[1].mv.notZero();
    if (bTryZero)	//若存在非0向量
    {
        /* Do not try zero MV if unidir motion predictors are beyond
         * valid search area */
        MV mvmin, mvmax;
        int merange = X265_MAX(m_param->sourceWidth, m_param->sourceHeight);
		//以0向量为中心,merange为范围设置搜索窗口[mvmin,mvmax]
        setSearchRange(cu, mvzero, merange, mvmin, mvmax);
        mvmax.y += 2; // there is some pad for subpel refine
		//超分4倍后的搜索窗口
		mvmin <<= 2;
        mvmax <<= 2;
		//检查mvp是否超出了搜索窗口
        bTryZero &= bestME[0].mvp.checkRange(mvmin, mvmax);
        bTryZero &= bestME[1].mvp.checkRange(mvmin, mvmax);
    }
    if (bTryZero)	//若前后向MV存在非0向量,且mvp都在以0向量为中心的搜索窗口内
    {
        /* Estimate cost of BIDIR using coincident blocks */
        Yuv& tmpPredYuv = m_rqt[cuGeom.depth].tmpPredYuv;

        int zsa8d;

		//若m_bChromaSa8d且有色度
        if (m_bChromaSa8d && (m_csp != X265_CSP_I400 && m_frame->m_fencPic->m_picCsp != X265_CSP_I400))
        {
			//设置前后向量为0向量
            cu.m_mv[0][0] = mvzero;
            cu.m_mv[1][0] = mvzero;

			//进行亮度和色度的运动补偿
            motionCompensation(cu, pu, tmpPredYuv, true, true);
			//累计上亮度和色度的sa8d
            zsa8d  = primitives.cu[partEnum].sa8d(fencYuv.m_buf[0], fencYuv.m_size, tmpPredYuv.m_buf[0], tmpPredYuv.m_size);
            zsa8d += primitives.chroma[m_csp].cu[partEnum].sa8d(fencYuv.m_buf[1], fencYuv.m_csize, tmpPredYuv.m_buf[1], tmpPredYuv.m_csize);
            zsa8d += primitives.chroma[m_csp].cu[partEnum].sa8d(fencYuv.m_buf[2], fencYuv.m_csize, tmpPredYuv.m_buf[2], tmpPredYuv.m_csize);

        }
        else	//只有算亮度
        {
			//取前后参考帧的co-located像素,其实也就是0MV
            pixel *fref0 = m_slice->m_mref[0][ref0].getLumaAddr(pu.ctuAddr, pu.cuAbsPartIdx);
            pixel *fref1 = m_slice->m_mref[1][ref1].getLumaAddr(pu.ctuAddr, pu.cuAbsPartIdx);
            //计算refStride
			intptr_t refStride = m_slice->m_mref[0][0].lumaStride;
            //对前后参考像素进行均值计算,即为我们双向预测的预测像素
			primitives.pu[partEnum].pixelavg_pp[(tmpPredYuv.m_size % 64 == 0) && (refStride % 64 == 0)](tmpPredYuv.m_buf[0], tmpPredYuv.m_size, fref0, refStride, fref1, refStride, 32);
            //计算sa8d
			zsa8d = primitives.cu[partEnum].sa8d(fencYuv.m_buf[0], fencYuv.m_size, tmpPredYuv.m_buf[0], tmpPredYuv.m_size);
        }
		//计算前后帧间预测的bits开销
        uint32_t bits0 = bestME[0].bits - m_me.bitcost(bestME[0].mv, mvp0) + m_me.bitcost(mvzero, mvp0);
        uint32_t bits1 = bestME[1].bits - m_me.bitcost(bestME[1].mv, mvp1) + m_me.bitcost(mvzero, mvp1);
        //根据sa8d和bits开销计算0向量时候的MV
		uint32_t zcost = zsa8d + m_rdCost.getCost(bits0) + m_rdCost.getCost(bits1);

        /* refine MVP selection for zero mv, updates: mvp, mvpidx, bits, cost */
		//以运动估计最优向量为0向量为基准,重新检查前后向最优MVP
        mvp0 = checkBestMVP(inter2Nx2N.amvpCand[0][ref0], mvzero, mvpIdx0, bits0, zcost);
        mvp1 = checkBestMVP(inter2Nx2N.amvpCand[1][ref1], mvzero, mvpIdx1, bits1, zcost);

		//重新计算bits和cost
        uint32_t zbits = bits0 + bits1 + m_listSelBits[2] - (m_listSelBits[0] + m_listSelBits[1]);
        zcost = zsa8d + m_rdCost.getCost(zbits);

		//若0MV的cost < 之前计算的双向预测的cost,则将其更新为双向预测最优预测
        if (zcost < bidir2Nx2N.sa8dCost)
        {
			//更新bits和cost
            bidir2Nx2N.sa8dBits = zbits;
            bidir2Nx2N.sa8dCost = zcost;

			//更新前向MV、mvd及mvpIdx
            cu.setPUMv(0, mvzero, 0, 0);
            cu.m_mvd[0][0] = mvzero - mvp0;
            cu.m_mvpIdx[0][0] = (uint8_t)mvpIdx0;

			//更新后向MV、mvd及mvpIdx
            cu.setPUMv(1, mvzero, 0, 0);
            cu.m_mvd[1][0] = mvzero - mvp1;
            cu.m_mvpIdx[1][0] = (uint8_t)mvpIdx1;

			//若m_bChromaSa8d,则predYUV全拷贝
            if (m_bChromaSa8d) /* real MC was already performed */
                bidir2Nx2N.predYuv.copyFromYuv(tmpPredYuv);
            //非则进行运动补偿
			else
                motionCompensation(cu, pu, bidir2Nx2N.predYuv, true, m_csp != X265_CSP_I400 && m_frame->m_fencPic->m_picCsp != X265_CSP_I400);
        }
		//0MV的cost > 之前计算的双向预测的cost,则保存之前的数据不变,且恢复bestME的MV
        else if (m_bChromaSa8d && (m_csp != X265_CSP_I400 && m_frame->m_fencPic->m_picCsp != X265_CSP_I400))
        {
            /* recover overwritten motion vectors */
            cu.m_mv[0][0] = bestME[0].mv;
            cu.m_mv[1][0] = bestME[1].mv;
        }
    }
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值