xCheckRDCostAffineMerge2Nx2N函数中调用getAffineMergeCand来获取AffineMerge候选列表。
AffineMerge候选列表的类:
class AffineMergeCtx //AffineMerge候选列表的类
{
//...
public:
MvField mvFieldNeighbours[AFFINE_MRG_MAX_NUM_CANDS << 1][3]; // double length for mv of both lists 5组3控制点
unsigned char interDirNeighbours[AFFINE_MRG_MAX_NUM_CANDS]; //AffineMerge候选列表长度为5
EAffineModel affineType[AFFINE_MRG_MAX_NUM_CANDS]; //4参数、6参数
#if JVET_L0646_GBI
uint8_t GBiIdx[AFFINE_MRG_MAX_NUM_CANDS];
#endif
int numValidMergeCand;
int maxNumMergeCand;
#if JVET_L0369_SUBBLOCK_MERGE
MergeCtx *mrgCtx; //这个merge候选列表是为了获取ATMVP模式给Affine的候选
MergeType mergeType[AFFINE_MRG_MAX_NUM_CANDS]; //具体看getAffineMergeCand函数中
#endif
};
getAffineMergeCand的函数流程,构建Affine_Merge候选列表:
前半部分类似merge列表构造过程,首先将相邻块运动信息存入mrgCtx,方便SbTMVP模式获取偏移mv的执行;
后半部分构造Affine_Merge列表过程和L1002中描述相同;
affMrgCtx添加的第一个候选,就是SbTMVP候选;
之后添加:继承的Affine候选、构造的Affine候选、0。
void PU::getAffineMergeCand( const PredictionUnit &pu, AffineMergeCtx& affMrgCtx, const int mrgCandIdx )
{
const CodingStructure &cs = *pu.cs;
const Slice &slice = *pu.cs->slice;
const uint32_t maxNumAffineMergeCand = slice.getMaxNumAffineMergeCand();
for ( int i = 0; i < maxNumAffineMergeCand; i++ ) //Affine候选列表初始化
{
for ( int mvNum = 0; mvNum < 3; mvNum++ ) //3控制点
{
affMrgCtx.mvFieldNeighbours[(i << 1) + 0][mvNum].setMvField( Mv(), -1 );
affMrgCtx.mvFieldNeighbours[(i << 1) + 1][mvNum].setMvField( Mv(), -1 );
}
affMrgCtx.interDirNeighbours[i] = 0;
affMrgCtx.affineType[i] = AFFINEMODEL_4PARAM; //初始化为4参数Affine
#if JVET_L0369_SUBBLOCK_MERGE
affMrgCtx.mergeType[i] = MRG_TYPE_DEFAULT_N;
#endif
#if JVET_L0646_GBI
affMrgCtx.GBiIdx[i] = GBI_DEFAULT;
#endif
}
affMrgCtx.numValidMergeCand = 0;
affMrgCtx.maxNumMergeCand = maxNumAffineMergeCand;
#if JVET_L0369_SUBBLOCK_MERGE ///> insert ATMVP candidate //首先添加SbTMVP模式给Affine的候选
#if JVET_L0293_CPR
bool enableSubPuMvp = slice.getSPS()->getSpsNext().getUseSubPuMvp() && !(slice.getPOC() == slice.getRefPic(REF_PIC_LIST_0, 0)->getPOC() && slice.isIRAP());
#else
bool enableSubPuMvp = slice.getSPS()->getSpsNext().getUseSubPuMvp();
#endif
bool isAvailableSubPu = false;
if ( enableSubPuMvp && slice.getEnableTMVPFlag() ) //SbTMVP
{
#if JVET_L0293_CPR
int cntCPR = 0;
#endif
MergeCtx mrgCtx = *affMrgCtx.mrgCtx; //Affine候选列表类中的merge列表
bool tmpLICFlag = false;
CHECK( mrgCtx.subPuMvpMiBuf.area() == 0 || !mrgCtx.subPuMvpMiBuf.buf, "Buffer not initialized" );
mrgCtx.subPuMvpMiBuf.fill( MotionInfo() );
int pos = 0;
// Get spatial MV
const Position posCurRT = pu.Y().topRight(); //首先mrgCtx中存入相邻块的运动信息
const Position posCurLB = pu.Y().bottomLeft();
MotionInfo miAbove, miLeft, miAboveRight, miBelowLeft;
//这里的过程和merge模式时基本一致
//left 左
const PredictionUnit* puLeft = cs.getPURestricted( posCurLB.offset( -1, 0 ), pu, pu.chType );
const bool isAvailableA1 = puLeft && isDiffMER( pu, *puLeft ) && pu.cu != puLeft->cu && CU::isInter( *puLeft->cu );
if ( isAvailableA1 )
{
miLeft = puLeft->getMotionInfo( posCurLB.offset( -1, 0 ) );
// get Inter Dir
mrgCtx.interDirNeighbours[pos] = miLeft.interDir;
// get Mv from Left
#if JVET_L0293_CPR
if (puLeft->cu->cpr)
{
cntCPR++;
}
#endif
mrgCtx.mvFieldNeighbours[pos << 1].setMvField( miLeft.mv[0], miLeft.refIdx[0] );
if ( slice.isInterB() )
{
mrgCtx.mvFieldNeighbours[(pos << 1) + 1].setMvField( miLeft.mv[1], miLeft.refIdx[1] );
}
pos++;
}
// above 上
const PredictionUnit *puAbove = cs.getPURestricted