/*
基于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;
}
}
}
“相关推荐”对你有帮助么?
-
非常没帮助
-
没帮助
-
一般
-
有帮助
-
非常有帮助
提交