Newer
Older
3001
3002
3003
3004
3005
3006
3007
3008
3009
3010
3011
3012
3013
3014
3015
3016
3017
3018
3019
3020
3021
3022
3023
3024
3025
3026
3027
3028
3029
3030
3031
3032
3033
3034
3035
3036
3037
3038
3039
{
npu[num++] = puAbove;
return num;
}
const PredictionUnit *puAboveLeft = pu.cs->getPURestricted( posLT.offset( -1, -1 ), pu, pu.chType );
if ( puAboveLeft && puAboveLeft->cu->affine
&& puAboveLeft->mergeType == MRG_TYPE_DEFAULT_N
)
{
npu[num++] = puAboveLeft;
return num;
}
return num;
}
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++ )
{
for ( int mvNum = 0; mvNum < 3; mvNum++ )
{
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;
affMrgCtx.mergeType[i] = MRG_TYPE_DEFAULT_N;
affMrgCtx.GBiIdx[i] = GBI_DEFAULT;
}
affMrgCtx.numValidMergeCand = 0;
affMrgCtx.maxNumMergeCand = maxNumAffineMergeCand;
bool enableSubPuMvp = slice.getSPS()->getSBTMVPEnabledFlag() && !(slice.getPOC() == slice.getRefPic(REF_PIC_LIST_0, 0)->getPOC() && slice.isIRAP());
bool isAvailableSubPu = false;
if ( enableSubPuMvp && slice.getEnableTMVPFlag() )
{
MergeCtx mrgCtx = *affMrgCtx.mrgCtx;
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 posCurLB = pu.Y().bottomLeft();
MotionInfo miLeft;
3054
3055
3056
3057
3058
3059
3060
3061
3062
3063
3064
3065
3066
3067
3068
3069
3070
3071
3072
3073
3074
3075
3076
3077
3078
3079
3080
3081
3082
3083
3084
3085
3086
3087
3088
3089
3090
3091
3092
3093
3094
3095
3096
3097
3098
3099
3100
3101
3102
3103
3104
//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
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++;
}
mrgCtx.numValidMergeCand = pos;
isAvailableSubPu = getInterMergeSubPuMvpCand( pu, mrgCtx, tmpLICFlag, pos
, 0
);
if ( isAvailableSubPu )
{
for ( int mvNum = 0; mvNum < 3; mvNum++ )
{
affMrgCtx.mvFieldNeighbours[(affMrgCtx.numValidMergeCand << 1) + 0][mvNum].setMvField( mrgCtx.mvFieldNeighbours[(pos << 1) + 0].mv, mrgCtx.mvFieldNeighbours[(pos << 1) + 0].refIdx );
affMrgCtx.mvFieldNeighbours[(affMrgCtx.numValidMergeCand << 1) + 1][mvNum].setMvField( mrgCtx.mvFieldNeighbours[(pos << 1) + 1].mv, mrgCtx.mvFieldNeighbours[(pos << 1) + 1].refIdx );
}
affMrgCtx.interDirNeighbours[affMrgCtx.numValidMergeCand] = mrgCtx.interDirNeighbours[pos];
affMrgCtx.affineType[affMrgCtx.numValidMergeCand] = AFFINE_MODEL_NUM;
affMrgCtx.mergeType[affMrgCtx.numValidMergeCand] = MRG_TYPE_SUBPU_ATMVP;
if ( affMrgCtx.numValidMergeCand == mrgCandIdx )
{
return;
}
affMrgCtx.numValidMergeCand++;
// early termination
if ( affMrgCtx.numValidMergeCand == maxNumAffineMergeCand )
{
return;
}
}
}
if ( slice.getSPS()->getUseAffine() )
3106
3107
3108
3109
3110
3111
3112
3113
3114
3115
3116
3117
3118
3119
3120
3121
3122
3123
3124
3125
3126
3127
3128
3129
3130
3131
3132
3133
3134
3135
3136
{
///> Start: inherited affine candidates
const PredictionUnit* npu[5];
int numAffNeighLeft = getAvailableAffineNeighboursForLeftPredictor( pu, npu );
int numAffNeigh = getAvailableAffineNeighboursForAbovePredictor( pu, npu, numAffNeighLeft );
for ( int idx = 0; idx < numAffNeigh; idx++ )
{
// derive Mv from Neigh affine PU
Mv cMv[2][3];
const PredictionUnit* puNeigh = npu[idx];
pu.cu->affineType = puNeigh->cu->affineType;
if ( puNeigh->interDir != 2 )
{
xInheritedAffineMv( pu, puNeigh, REF_PIC_LIST_0, cMv[0] );
}
if ( slice.isInterB() )
{
if ( puNeigh->interDir != 1 )
{
xInheritedAffineMv( pu, puNeigh, REF_PIC_LIST_1, cMv[1] );
}
}
for ( int mvNum = 0; mvNum < 3; mvNum++ )
{
affMrgCtx.mvFieldNeighbours[(affMrgCtx.numValidMergeCand << 1) + 0][mvNum].setMvField( cMv[0][mvNum], puNeigh->refIdx[0] );
affMrgCtx.mvFieldNeighbours[(affMrgCtx.numValidMergeCand << 1) + 1][mvNum].setMvField( cMv[1][mvNum], puNeigh->refIdx[1] );
}
affMrgCtx.interDirNeighbours[affMrgCtx.numValidMergeCand] = puNeigh->interDir;
affMrgCtx.affineType[affMrgCtx.numValidMergeCand] = (EAffineModel)(puNeigh->cu->affineType);
affMrgCtx.GBiIdx[affMrgCtx.numValidMergeCand] = puNeigh->cu->GBiIdx;

Karsten Suehring
committed
if ( affMrgCtx.numValidMergeCand == mrgCandIdx )
{
return;
}
// early termination
affMrgCtx.numValidMergeCand++;
if ( affMrgCtx.numValidMergeCand == maxNumAffineMergeCand )
{
return;
}
}
///> End: inherited affine candidates
///> Start: Constructed affine candidates
{
MotionInfo mi[4];
bool isAvailable[4] = { false };
int8_t neighGbi[4] = { GBI_DEFAULT, GBI_DEFAULT, GBI_DEFAULT, GBI_DEFAULT };
// control point: LT B2->B3->A2
const Position posLT[3] = { pu.Y().topLeft().offset( -1, -1 ), pu.Y().topLeft().offset( 0, -1 ), pu.Y().topLeft().offset( -1, 0 ) };
for ( int i = 0; i < 3; i++ )
{
const Position pos = posLT[i];
const PredictionUnit* puNeigh = cs.getPURestricted( pos, pu, pu.chType );
isAvailable[0] = true;
mi[0] = puNeigh->getMotionInfo( pos );
neighGbi[0] = puNeigh->cu->GBiIdx;
break;
}
}
// control point: RT B1->B0
const Position posRT[2] = { pu.Y().topRight().offset( 0, -1 ), pu.Y().topRight().offset( 1, -1 ) };
for ( int i = 0; i < 2; i++ )
{
const Position pos = posRT[i];
const PredictionUnit* puNeigh = cs.getPURestricted( pos, pu, pu.chType );
if ( puNeigh && CU::isInter( *puNeigh->cu )
isAvailable[1] = true;
mi[1] = puNeigh->getMotionInfo( pos );
neighGbi[1] = puNeigh->cu->GBiIdx;
break;
}
}
// control point: LB A1->A0
const Position posLB[2] = { pu.Y().bottomLeft().offset( -1, 0 ), pu.Y().bottomLeft().offset( -1, 1 ) };
for ( int i = 0; i < 2; i++ )
{
const Position pos = posLB[i];
const PredictionUnit* puNeigh = cs.getPURestricted( pos, pu, pu.chType );
if ( puNeigh && CU::isInter( *puNeigh->cu )
isAvailable[2] = true;
mi[2] = puNeigh->getMotionInfo( pos );
neighGbi[2] = puNeigh->cu->GBiIdx;
break;
}
}
// control point: RB
if ( slice.getEnableTMVPFlag() )
{
//>> MTK colocated-RightBottom
// offset the pos to be sure to "point" to the same position the uiAbsPartIdx would've pointed to
Position posRB = pu.Y().bottomRight().offset( -3, -3 );
const PreCalcValues& pcv = *cs.pcv;
Position posC0;
bool C0Avail = false;
if ( ((posRB.x + pcv.minCUWidth) < pcv.lumaWidth) && ((posRB.y + pcv.minCUHeight) < pcv.lumaHeight) )
{
int posYInCtu = posRB.y & pcv.maxCUHeightMask;
if (posYInCtu + 4 < pcv.maxCUHeight)
posC0 = posRB.offset(4, 4);
C0Avail = true;
}
}
Mv cColMv;
int refIdx = 0;
bool bExistMV = C0Avail && getColocatedMVP( pu, REF_PIC_LIST_0, posC0, cColMv, refIdx );
if ( bExistMV )
{
mi[3].mv[0] = cColMv;
mi[3].refIdx[0] = refIdx;
mi[3].interDir = 1;
isAvailable[3] = true;
}
if ( slice.isInterB() )
{
bExistMV = C0Avail && getColocatedMVP( pu, REF_PIC_LIST_1, posC0, cColMv, refIdx );
if ( bExistMV )
{
mi[3].mv[1] = cColMv;
mi[3].refIdx[1] = refIdx;
mi[3].interDir |= 2;
isAvailable[3] = true;
}
}
}
//------------------- insert model -------------------//
int order[6] = { 0, 1, 2, 3, 4, 5 };
int modelNum = 6;
int model[6][4] = {
{ 0, 1, 2 }, // 0: LT, RT, LB
{ 0, 1, 3 }, // 1: LT, RT, RB
{ 0, 2, 3 }, // 2: LT, LB, RB
{ 1, 2, 3 }, // 3: RT, LB, RB
{ 0, 1 }, // 4: LT, RT
{ 0, 2 }, // 5: LT, LB
};
int verNum[6] = { 3, 3, 3, 3, 2, 2 };
int startIdx = pu.cs->sps->getUseAffineType() ? 0 : 4;
for ( int idx = startIdx; idx < modelNum; idx++ )
{
int modelIdx = order[idx];
getAffineControlPointCand(pu, mi, neighGbi, isAvailable, model[modelIdx], modelIdx, verNum[modelIdx], affMrgCtx);
3273
3274
3275
3276
3277
3278
3279
3280
3281
3282
3283
3284
3285
3286
3287
3288
3289
3290
3291
3292
3293
3294
3295
3296
3297
3298
3299
3300
3301
3302
3303
3304
3305
3306
3307
if ( affMrgCtx.numValidMergeCand != 0 && affMrgCtx.numValidMergeCand - 1 == mrgCandIdx )
{
return;
}
// early termination
if ( affMrgCtx.numValidMergeCand == maxNumAffineMergeCand )
{
return;
}
}
}
///> End: Constructed affine candidates
}
///> zero padding
int cnt = affMrgCtx.numValidMergeCand;
while ( cnt < maxNumAffineMergeCand )
{
for ( int mvNum = 0; mvNum < 3; mvNum++ )
{
affMrgCtx.mvFieldNeighbours[(cnt << 1) + 0][mvNum].setMvField( Mv( 0, 0 ), 0 );
}
affMrgCtx.interDirNeighbours[cnt] = 1;
if ( slice.isInterB() )
{
for ( int mvNum = 0; mvNum < 3; mvNum++ )
{
affMrgCtx.mvFieldNeighbours[(cnt << 1) + 1][mvNum].setMvField( Mv( 0, 0 ), 0 );
}
affMrgCtx.interDirNeighbours[cnt] = 3;
}
affMrgCtx.affineType[cnt] = AFFINEMODEL_4PARAM;
{
return;
}

Karsten Suehring
committed
void PU::setAllAffineMvField( PredictionUnit &pu, MvField *mvField, RefPicList eRefList )
{
// Set Mv
Mv mv[3];
for ( int i = 0; i < 3; i++ )
{
mv[i] = mvField[i].mv;
}
setAllAffineMv( pu, mv[0], mv[1], mv[2], eRefList );
// Set RefIdx
CHECK( mvField[0].refIdx != mvField[1].refIdx || mvField[0].refIdx != mvField[2].refIdx, "Affine mv corners don't have the same refIdx." );
pu.refIdx[eRefList] = mvField[0].refIdx;
}
void PU::setAllAffineMv(PredictionUnit& pu, Mv affLT, Mv affRT, Mv affLB, RefPicList eRefList, bool clipCPMVs)

Karsten Suehring
committed
{
int width = pu.Y().width;
int shift = MAX_CU_DEPTH;
if (clipCPMVs)
{
affLT.mvCliptoStorageBitDepth();
affRT.mvCliptoStorageBitDepth();
if (pu.cu->affineType == AFFINEMODEL_6PARAM)
{
affLB.mvCliptoStorageBitDepth();
}
}

Karsten Suehring
committed
3345
3346
3347
3348
3349
3350
3351
3352
3353
3354
3355
3356
3357
3358
3359
3360
3361
3362
3363
3364
3365
3366
3367
3368
3369
int deltaMvHorX, deltaMvHorY, deltaMvVerX, deltaMvVerY;
deltaMvHorX = (affRT - affLT).getHor() << (shift - g_aucLog2[width]);
deltaMvHorY = (affRT - affLT).getVer() << (shift - g_aucLog2[width]);
int height = pu.Y().height;
if ( pu.cu->affineType == AFFINEMODEL_6PARAM )
{
deltaMvVerX = (affLB - affLT).getHor() << (shift - g_aucLog2[height]);
deltaMvVerY = (affLB - affLT).getVer() << (shift - g_aucLog2[height]);
}
else
{
deltaMvVerX = -deltaMvHorY;
deltaMvVerY = deltaMvHorX;
}
int mvScaleHor = affLT.getHor() << shift;
int mvScaleVer = affLT.getVer() << shift;
int blockWidth = AFFINE_MIN_BLOCK_SIZE;
int blockHeight = AFFINE_MIN_BLOCK_SIZE;
const int halfBW = blockWidth >> 1;
const int halfBH = blockHeight >> 1;
MotionBuf mb = pu.getMotionBuf();
int mvScaleTmpHor, mvScaleTmpVer;
const bool subblkMVSpreadOverLimit = InterPrediction::isSubblockVectorSpreadOverLimit( deltaMvHorX, deltaMvHorY, deltaMvVerX, deltaMvVerY, pu.interDir );

Karsten Suehring
committed
for ( int h = 0; h < pu.Y().height; h += blockHeight )
{
for ( int w = 0; w < pu.Y().width; w += blockWidth )
{
if ( !subblkMVSpreadOverLimit )
{
mvScaleTmpHor = mvScaleHor + deltaMvHorX * (halfBW + w) + deltaMvVerX * (halfBH + h);
mvScaleTmpVer = mvScaleVer + deltaMvHorY * (halfBW + w) + deltaMvVerY * (halfBH + h);
}
else
{
mvScaleTmpHor = mvScaleHor + deltaMvHorX * ( pu.Y().width >> 1 ) + deltaMvVerX * ( pu.Y().height >> 1 );
mvScaleTmpVer = mvScaleVer + deltaMvHorY * ( pu.Y().width >> 1 ) + deltaMvVerY * ( pu.Y().height >> 1 );
}

Karsten Suehring
committed
roundAffineMv( mvScaleTmpHor, mvScaleTmpVer, shift );
Mv curMv(mvScaleTmpHor, mvScaleTmpVer);
curMv.clipToStorageBitDepth();

Karsten Suehring
committed
for ( int y = (h >> MIN_CU_LOG2); y < ((h + blockHeight) >> MIN_CU_LOG2); y++ )
{
Huanbang Chen
committed
for ( int x = (w >> MIN_CU_LOG2); x < ((w + blockWidth) >> MIN_CU_LOG2); x++ )

Karsten Suehring
committed
{

Karsten Suehring
committed
}
}
}
}
pu.mvAffi[eRefList][0] = affLT;
pu.mvAffi[eRefList][1] = affRT;
pu.mvAffi[eRefList][2] = affLB;

Karsten Suehring
committed
3403
3404
3405
3406
3407
3408
3409
3410
3411
3412
3413
3414
3415
3416
3417
3418
3419
3420
3421
3422
3423
3424
3425
3426
3427
3428
3429
3430
3431
3432
3433
3434
3435
3436
3437
3438
3439
3440
3441
3442
3443
3444
3445
3446
3447
3448
3449
3450
3451
3452
3453
3454
3455
3456
3457
}
static bool deriveScaledMotionTemporal( const Slice& slice,
const Position& colPos,
const Picture* pColPic,
const RefPicList eCurrRefPicList,
Mv& cColMv,
const RefPicList eFetchRefPicList)
{
const MotionInfo &mi = pColPic->cs->getMotionInfo(colPos);
const Slice *pColSlice = nullptr;
for (const auto &pSlice : pColPic->slices)
{
if (pSlice->getIndependentSliceIdx() == mi.sliceIdx)
{
pColSlice = pSlice;
break;
}
}
CHECK(pColSlice == nullptr, "Couldn't find the colocated slice");
int iColPOC, iColRefPOC, iCurrPOC, iCurrRefPOC, iScale;
bool bAllowMirrorMV = true;
RefPicList eColRefPicList = slice.getCheckLDC() ? eCurrRefPicList : RefPicList(1 - eFetchRefPicList);
if (pColPic == slice.getRefPic(RefPicList(slice.isInterB() ? 1 - slice.getColFromL0Flag() : 0), slice.getColRefIdx()))
{
eColRefPicList = eCurrRefPicList; //67 -> disable, 64 -> enable
bAllowMirrorMV = false;
}
// Although it might make sense to keep the unavailable motion field per direction still be unavailable, I made the MV prediction the same way as in TMVP
// So there is an interaction between MV0 and MV1 of the corresponding blocks identified by TV.
// Grab motion and do necessary scaling.{{
iCurrPOC = slice.getPOC();
int iColRefIdx = mi.refIdx[eColRefPicList];
if (iColRefIdx < 0 && (slice.getCheckLDC() || bAllowMirrorMV))
{
eColRefPicList = RefPicList(1 - eColRefPicList);
iColRefIdx = mi.refIdx[eColRefPicList];
if (iColRefIdx < 0)
{
return false;
}
}
if (iColRefIdx >= 0 && slice.getNumRefIdx(eCurrRefPicList) > 0)
{
iColPOC = pColSlice->getPOC();
iColRefPOC = pColSlice->getRefPOC(eColRefPicList, iColRefIdx);

Karsten Suehring
committed
///////////////////////////////////////////////////////////////
// Set the target reference index to 0, may be changed later //
///////////////////////////////////////////////////////////////
iCurrRefPOC = slice.getRefPic(eCurrRefPicList, 0)->getPOC();
// Scale the vector.
cColMv = mi.mv[eColRefPicList];
cColMv.setHor(roundMvComp(cColMv.getHor()));
cColMv.setVer(roundMvComp(cColMv.getVer()));

Karsten Suehring
committed
//pcMvFieldSP[2*iPartition + eCurrRefPicList].getMv();
// Assume always short-term for now
iScale = xGetDistScaleFactor(iCurrPOC, iCurrRefPOC, iColPOC, iColRefPOC);
if (iScale != 4096)
{
cColMv = cColMv.scaleMv(iScale);
}
return true;
}
return false;
}
void clipColPos(int& posX, int& posY, const PredictionUnit& pu)
{
Position puPos = pu.lumaPos();
int log2CtuSize = g_aucLog2[pu.cs->sps->getCTUSize()];
int ctuX = ((puPos.x >> log2CtuSize) << log2CtuSize);
int ctuY = ((puPos.y >> log2CtuSize) << log2CtuSize);
int horMax = std::min((int)pu.cs->sps->getPicWidthInLumaSamples() - 1, ctuX + (int)pu.cs->sps->getCTUSize() + 3);
int horMin = std::max((int)0, ctuX);
int verMax = std::min((int)pu.cs->sps->getPicHeightInLumaSamples() - 1, ctuY + (int)pu.cs->sps->getCTUSize() - 1);
int verMin = std::max((int)0, ctuY);
posX = std::min(horMax, std::max(horMin, posX));
posY = std::min(verMax, std::max(verMin, posY));
}

Karsten Suehring
committed
bool PU::getInterMergeSubPuMvpCand(const PredictionUnit &pu, MergeCtx& mrgCtx, bool& LICFlag, const int count
, int mmvdList

Karsten Suehring
committed
{
const Slice &slice = *pu.cs->slice;
const unsigned scale = 4 * std::max<int>(1, 4 * AMVP_DECIMATION_FACTOR / 4);
const unsigned mask = ~(scale - 1);
const Picture *pColPic = slice.getRefPic(RefPicList(slice.isInterB() ? 1 - slice.getColFromL0Flag() : 0), slice.getColRefIdx());
Mv cTMv;
RefPicList fetchRefPicList = RefPicList(slice.isInterB() ? 1 - slice.getColFromL0Flag() : 0);
bool terminate = false;
for (unsigned currRefListId = 0; currRefListId < (slice.getSliceType() == B_SLICE ? 2 : 1) && !terminate; currRefListId++)
{
if ( count )
{
RefPicList currRefPicList = RefPicList(slice.getCheckLDC() ? (slice.getColFromL0Flag() ? currRefListId : 1 - currRefListId) : currRefListId);
if ((mrgCtx.interDirNeighbours[0] & (1 << currRefPicList)) && slice.getRefPic(currRefPicList, mrgCtx.mvFieldNeighbours[0 * 2 + currRefPicList].refIdx) == pColPic)
{
cTMv = mrgCtx.mvFieldNeighbours[0 * 2 + currRefPicList].mv;
terminate = true;
fetchRefPicList = currRefPicList;
break;
}
}

Karsten Suehring
committed
}
///////////////////////////////////////////////////////////////////////
//////// GET Initial Temporal Vector ////////
///////////////////////////////////////////////////////////////////////
int mvPrec = MV_FRACTIONAL_BITS_INTERNAL;

Karsten Suehring
committed
Mv cTempVector = cTMv;
bool tempLICFlag = false;
// compute the location of the current PU
Position puPos = pu.lumaPos();
Size puSize = pu.lumaSize();
int numPartLine = std::max(puSize.width >> ATMVP_SUB_BLOCK_SIZE, 1u);
int numPartCol = std::max(puSize.height >> ATMVP_SUB_BLOCK_SIZE, 1u);
int puHeight = numPartCol == 1 ? puSize.height : 1 << ATMVP_SUB_BLOCK_SIZE;
int puWidth = numPartLine == 1 ? puSize.width : 1 << ATMVP_SUB_BLOCK_SIZE;

Karsten Suehring
committed
Mv cColMv;
// use coldir.
bool bBSlice = slice.isInterB();
Position centerPos;
bool found = false;
cTempVector = cTMv;
int tempX = cTempVector.getHor() >> mvPrec;
int tempY = cTempVector.getVer() >> mvPrec;
centerPos.x = puPos.x + (puSize.width >> 1) + tempX;
centerPos.y = puPos.y + (puSize.height >> 1) + tempY;
clipColPos(centerPos.x, centerPos.y, pu);

Karsten Suehring
committed
centerPos = Position{ PosType(centerPos.x & mask), PosType(centerPos.y & mask) };
// derivation of center motion parameters from the collocated CU
const MotionInfo &mi = pColPic->cs->getMotionInfo(centerPos);

Karsten Suehring
committed
{
mrgCtx.interDirNeighbours[count] = 0;

Karsten Suehring
committed
for (unsigned currRefListId = 0; currRefListId < (bBSlice ? 2 : 1); currRefListId++)
{
RefPicList currRefPicList = RefPicList(currRefListId);
if (deriveScaledMotionTemporal(slice, centerPos, pColPic, currRefPicList, cColMv, fetchRefPicList))
{
// set as default, for further motion vector field spanning
mrgCtx.mvFieldNeighbours[(count << 1) + currRefListId].setMvField(cColMv, 0);
mrgCtx.interDirNeighbours[count] |= (1 << currRefListId);
LICFlag = tempLICFlag;
mrgCtx.GBiIdx[count] = GBI_DEFAULT;

Karsten Suehring
committed
found = true;
}
else
{
mrgCtx.mvFieldNeighbours[(count << 1) + currRefListId].setMvField(Mv(), NOT_VALID);
mrgCtx.interDirNeighbours[count] &= ~(1 << currRefListId);
}
}
}
if (!found)
{
return false;
}
if (mmvdList != 1)
{
int xOff = (puWidth >> 1) + tempX;
int yOff = (puHeight >> 1) + tempY;

Karsten Suehring
committed
MotionBuf& mb = mrgCtx.subPuMvpMiBuf;
const bool isBiPred = isBipredRestriction(pu);
for (int y = puPos.y; y < puPos.y + puSize.height; y += puHeight)
{
for (int x = puPos.x; x < puPos.x + puSize.width; x += puWidth)
{
Position colPos{ x + xOff, y + yOff };
clipColPos(colPos.x, colPos.y, pu);

Karsten Suehring
committed
colPos = Position{ PosType(colPos.x & mask), PosType(colPos.y & mask) };
const MotionInfo &colMi = pColPic->cs->getMotionInfo(colPos);
MotionInfo mi;

Karsten Suehring
committed
mi.isInter = true;
mi.sliceIdx = slice.getIndependentSliceIdx();
mi.isIBCmot = false;
if (colMi.isInter && colMi.isIBCmot == false)

Karsten Suehring
committed
{
for (unsigned currRefListId = 0; currRefListId < (bBSlice ? 2 : 1); currRefListId++)
{
RefPicList currRefPicList = RefPicList(currRefListId);
if (deriveScaledMotionTemporal(slice, colPos, pColPic, currRefPicList, cColMv, fetchRefPicList))
{
mi.refIdx[currRefListId] = 0;
mi.mv[currRefListId] = cColMv;

Karsten Suehring
committed
}
}
if (!found)
{
mi.mv[0] = mrgCtx.mvFieldNeighbours[(count << 1) + 0].mv;
mi.mv[1] = mrgCtx.mvFieldNeighbours[(count << 1) + 1].mv;
mi.refIdx[0] = mrgCtx.mvFieldNeighbours[(count << 1) + 0].refIdx;
mi.refIdx[1] = mrgCtx.mvFieldNeighbours[(count << 1) + 1].refIdx;

Karsten Suehring
committed
}
mi.interDir = (mi.refIdx[0] != -1 ? 1 : 0) + (mi.refIdx[1] != -1 ? 2 : 0);
if (isBiPred && mi.interDir == 3)
{
mi.interDir = 1;
mi.mv[1] = Mv();
mi.refIdx[1] = NOT_VALID;
}
mb.subBuf(g_miScaling.scale(Position{ x, y } -pu.lumaPos()), g_miScaling.scale(Size(puWidth, puHeight))).fill(mi);
}
}

Karsten Suehring
committed
return true;
}
void PU::spanMotionInfo( PredictionUnit &pu, const MergeCtx &mrgCtx )
{
MotionBuf mb = pu.getMotionBuf();
if( !pu.mergeFlag || pu.mergeType == MRG_TYPE_DEFAULT_N

Karsten Suehring
committed
{
MotionInfo mi;
mi.isInter = !CU::isIntra(*pu.cu);
mi.isIBCmot = CU::isIBC(*pu.cu);

Karsten Suehring
committed
mi.sliceIdx = pu.cu->slice->getIndependentSliceIdx();
if( mi.isInter )
{
mi.interDir = pu.interDir;
for( int i = 0; i < NUM_REF_PIC_LIST_01; i++ )
{
mi.mv[i] = pu.mv[i];
mi.refIdx[i] = pu.refIdx[i];
}

Karsten Suehring
committed
}
if( pu.cu->affine )
{
for( int y = 0; y < mb.height; y++ )
{
for( int x = 0; x < mb.width; x++ )
{
MotionInfo &dest = mb.at( x, y );
dest.isInter = mi.isInter;

Karsten Suehring
committed
3695
3696
3697
3698
3699
3700
3701
3702
3703
3704
3705
3706
3707
3708
3709
3710
3711
3712
3713
3714
3715
3716
3717
3718
3719
3720
3721
3722
3723
3724
3725
3726
3727
3728
3729
3730
3731
3732
3733
3734
3735
3736
3737
3738
3739
3740
3741
3742
3743
3744
3745
dest.interDir = mi.interDir;
dest.sliceIdx = mi.sliceIdx;
for( int i = 0; i < NUM_REF_PIC_LIST_01; i++ )
{
if( mi.refIdx[i] == -1 )
{
dest.mv[i] = Mv();
}
dest.refIdx[i] = mi.refIdx[i];
}
}
}
}
else
{
mb.fill( mi );
}
}
else if (pu.mergeType == MRG_TYPE_SUBPU_ATMVP)
{
CHECK(mrgCtx.subPuMvpMiBuf.area() == 0 || !mrgCtx.subPuMvpMiBuf.buf, "Buffer not initialized");
mb.copyFrom(mrgCtx.subPuMvpMiBuf);
}
else
{
if( isBipredRestriction( pu ) )
{
for( int y = 0; y < mb.height; y++ )
{
for( int x = 0; x < mb.width; x++ )
{
MotionInfo &mi = mb.at( x, y );
if( mi.interDir == 3 )
{
mi.interDir = 1;
mi.mv [1] = Mv();
mi.refIdx[1] = NOT_VALID;
}
}
}
}
}
}
void PU::applyImv( PredictionUnit& pu, MergeCtx &mrgCtx, InterPrediction *interPred )
{
if( !pu.mergeFlag )
{
if( pu.interDir != 2 /* PRED_L1 */ )
{
pu.mvd[0].changeTransPrecAmvr2Internal(pu.cu->imv);

Karsten Suehring
committed
unsigned mvp_idx = pu.mvpIdx[0];
AMVPInfo amvpInfo;

Karsten Suehring
committed
PU::fillMvpCand(pu, REF_PIC_LIST_0, pu.refIdx[0], amvpInfo);
pu.mvpNum[0] = amvpInfo.numCand;
pu.mvpIdx[0] = mvp_idx;
pu.mv [0] = amvpInfo.mvCand[mvp_idx] + pu.mvd[0];

Karsten Suehring
committed
}
if (pu.interDir != 1 /* PRED_L0 */)
{
if( !( pu.cu->cs->slice->getMvdL1ZeroFlag() && pu.interDir == 3 ) && pu.cu->imv )/* PRED_BI */
{
pu.mvd[1].changeTransPrecAmvr2Internal(pu.cu->imv);

Karsten Suehring
committed
}
unsigned mvp_idx = pu.mvpIdx[1];
AMVPInfo amvpInfo;
PU::fillMvpCand(pu, REF_PIC_LIST_1, pu.refIdx[1], amvpInfo);
pu.mvpNum[1] = amvpInfo.numCand;
pu.mvpIdx[1] = mvp_idx;
pu.mv [1] = amvpInfo.mvCand[mvp_idx] + pu.mvd[1];

Karsten Suehring
committed
}
}
else
{
// this function is never called for merge
THROW("unexpected");
PU::getInterMergeCandidates ( pu, mrgCtx

Karsten Suehring
committed
3783
3784
3785
3786
3787
3788
3789
3790
3791
3792
3793
3794
3795
3796
3797
3798
3799
3800
3801
3802
3803
3804
mrgCtx.setMergeInfo( pu, pu.mergeIdx );
}
PU::spanMotionInfo( pu, mrgCtx );
}
bool PU::isBiPredFromDifferentDir( const PredictionUnit& pu )
{
if ( pu.refIdx[0] >= 0 && pu.refIdx[1] >= 0 )
{
const int iPOC0 = pu.cu->slice->getRefPOC( REF_PIC_LIST_0, pu.refIdx[0] );
const int iPOC1 = pu.cu->slice->getRefPOC( REF_PIC_LIST_1, pu.refIdx[1] );
const int iPOC = pu.cu->slice->getPOC();
if ( (iPOC - iPOC0)*(iPOC - iPOC1) < 0 )
{
return true;
}
}
return false;
}
bool PU::isBiPredFromDifferentDirEqDistPoc(const PredictionUnit& pu)
{
if (pu.refIdx[0] >= 0 && pu.refIdx[1] >= 0)
{
const int poc0 = pu.cu->slice->getRefPOC(REF_PIC_LIST_0, pu.refIdx[0]);
const int poc1 = pu.cu->slice->getRefPOC(REF_PIC_LIST_1, pu.refIdx[1]);
const int poc = pu.cu->slice->getPOC();
if ((poc - poc0)*(poc - poc1) < 0)
{
return true;
}
}
}
return false;
}

Karsten Suehring
committed
void PU::restrictBiPredMergeCands( const PredictionUnit &pu, MergeCtx& mergeCtx )
{
if( PU::isBipredRestriction( pu ) )
{
for( uint32_t mergeCand = 0; mergeCand < mergeCtx.numValidMergeCand; ++mergeCand )
{
if( mergeCtx.interDirNeighbours[ mergeCand ] == 3 )
{
mergeCtx.interDirNeighbours[ mergeCand ] = 1;
mergeCtx.mvFieldNeighbours[( mergeCand << 1 ) + 1].setMvField( Mv( 0, 0 ), -1 );
mergeCtx.GBiIdx[mergeCand] = GBI_DEFAULT;

Karsten Suehring
committed
}
}
}
}
void PU::restrictBiPredMergeCandsOne(PredictionUnit &pu)
{
if (PU::isBipredRestriction(pu))
{
if (pu.interDir == 3)
{
pu.interDir = 1;
pu.refIdx[1] = -1;
pu.mv[1] = Mv(0, 0);
pu.cu->GBiIdx = GBI_DEFAULT;
}
}
}
void PU::getTriangleMergeCandidates( const PredictionUnit &pu, MergeCtx& triangleMrgCtx )
3854
3855
3856
3857
3858
3859
3860
3861
3862
3863
3864
3865
3866
3867
3868
3869
3870
3871
3872
3873
3874
3875
3876
3877
3878
3879
3880
3881
3882
3883
3884
3885
3886
3887
3888
3889
3890
3891
3892
3893
3894
3895
3896
3897
3898
3899
3900
3901
3902
3903
3904
3905
3906
3907
MergeCtx tmpMergeCtx;
const Slice &slice = *pu.cs->slice;
const uint32_t maxNumMergeCand = slice.getMaxNumMergeCand();
triangleMrgCtx.numValidMergeCand = 0;
for (int32_t i = 0; i < TRIANGLE_MAX_NUM_UNI_CANDS; i++)
{
triangleMrgCtx.GBiIdx[i] = GBI_DEFAULT;
triangleMrgCtx.interDirNeighbours[i] = 0;
triangleMrgCtx.mrgTypeNeighbours[i] = MRG_TYPE_DEFAULT_N;
triangleMrgCtx.mvFieldNeighbours[(i << 1)].refIdx = NOT_VALID;
triangleMrgCtx.mvFieldNeighbours[(i << 1) + 1].refIdx = NOT_VALID;
triangleMrgCtx.mvFieldNeighbours[(i << 1)].mv = Mv();
triangleMrgCtx.mvFieldNeighbours[(i << 1) + 1].mv = Mv();
}
PU::getInterMergeCandidates(pu, tmpMergeCtx, 0);
for (int32_t i = 0; i < maxNumMergeCand; i++)
{
int parity = i & 1;
if (tmpMergeCtx.interDirNeighbours[i] & (0x01 + parity))
{
triangleMrgCtx.interDirNeighbours[triangleMrgCtx.numValidMergeCand] = 1 + parity;
triangleMrgCtx.mrgTypeNeighbours[triangleMrgCtx.numValidMergeCand] = MRG_TYPE_DEFAULT_N;
triangleMrgCtx.mvFieldNeighbours[(triangleMrgCtx.numValidMergeCand << 1) + !parity].mv = Mv(0, 0);
triangleMrgCtx.mvFieldNeighbours[(triangleMrgCtx.numValidMergeCand << 1) + parity].mv = tmpMergeCtx.mvFieldNeighbours[(i << 1) + parity].mv;
triangleMrgCtx.mvFieldNeighbours[(triangleMrgCtx.numValidMergeCand << 1) + !parity].refIdx = -1;
triangleMrgCtx.mvFieldNeighbours[(triangleMrgCtx.numValidMergeCand << 1) + parity].refIdx = tmpMergeCtx.mvFieldNeighbours[(i << 1) + parity].refIdx;
triangleMrgCtx.numValidMergeCand++;
if (triangleMrgCtx.numValidMergeCand == TRIANGLE_MAX_NUM_UNI_CANDS)
{
return;
}
continue;
}
if (tmpMergeCtx.interDirNeighbours[i] & (0x02 - parity))
{
triangleMrgCtx.interDirNeighbours[triangleMrgCtx.numValidMergeCand] = 2 - parity;
triangleMrgCtx.mrgTypeNeighbours[triangleMrgCtx.numValidMergeCand] = MRG_TYPE_DEFAULT_N;
triangleMrgCtx.mvFieldNeighbours[(triangleMrgCtx.numValidMergeCand << 1) + !parity].mv = tmpMergeCtx.mvFieldNeighbours[(i << 1) + !parity].mv;
triangleMrgCtx.mvFieldNeighbours[(triangleMrgCtx.numValidMergeCand << 1) + parity].mv = Mv(0, 0);
triangleMrgCtx.mvFieldNeighbours[(triangleMrgCtx.numValidMergeCand << 1) + !parity].refIdx = tmpMergeCtx.mvFieldNeighbours[(i << 1) + !parity].refIdx;
triangleMrgCtx.mvFieldNeighbours[(triangleMrgCtx.numValidMergeCand << 1) + parity].refIdx = -1;
triangleMrgCtx.numValidMergeCand++;
if (triangleMrgCtx.numValidMergeCand == TRIANGLE_MAX_NUM_UNI_CANDS)
{
return;
}
}
}
bool PU::isUniqueTriangleCandidates( const PredictionUnit &pu, MergeCtx& triangleMrgCtx )
int newCand = triangleMrgCtx.numValidMergeCand;
for( int32_t i = 0; i < newCand; i++ )
{
int32_t predFlagCur = triangleMrgCtx.interDirNeighbours[i] == 1 ? 0 : 1;
int32_t predFlagNew = triangleMrgCtx.interDirNeighbours[newCand] == 1 ? 0 : 1;
int32_t refPicPocCur = pu.cs->slice->getRefPOC( (RefPicList)predFlagCur, triangleMrgCtx.mvFieldNeighbours[(i << 1) + predFlagCur].refIdx );
int32_t refPicPocNew = pu.cs->slice->getRefPOC( (RefPicList)predFlagNew, triangleMrgCtx.mvFieldNeighbours[(newCand << 1) + predFlagNew].refIdx);
if( refPicPocCur == refPicPocNew && triangleMrgCtx.mvFieldNeighbours[(i << 1) + predFlagCur].mv == triangleMrgCtx.mvFieldNeighbours[(newCand << 1) + predFlagNew].mv )
{
return false;
}
}
void PU::spanTriangleMotionInfo( PredictionUnit &pu, MergeCtx &triangleMrgCtx, const bool splitDir, const uint8_t candIdx0, const uint8_t candIdx1 )
pu.triangleSplitDir = splitDir;
pu.triangleMergeIdx0 = candIdx0;
pu.triangleMergeIdx1 = candIdx1;
MotionBuf mb = pu.getMotionBuf();
biMv.sliceIdx = pu.cs->slice->getIndependentSliceIdx();
if( triangleMrgCtx.interDirNeighbours[candIdx0] == 1 && triangleMrgCtx.interDirNeighbours[candIdx1] == 2 )
biMv.interDir = 3;
biMv.mv[0] = triangleMrgCtx.mvFieldNeighbours[ candIdx0 << 1 ].mv;
biMv.mv[1] = triangleMrgCtx.mvFieldNeighbours[(candIdx1 << 1) + 1].mv;
biMv.refIdx[0] = triangleMrgCtx.mvFieldNeighbours[ candIdx0 << 1 ].refIdx;
biMv.refIdx[1] = triangleMrgCtx.mvFieldNeighbours[(candIdx1 << 1) + 1].refIdx;
else if( triangleMrgCtx.interDirNeighbours[candIdx0] == 2 && triangleMrgCtx.interDirNeighbours[candIdx1] == 1 )
biMv.interDir = 3;
biMv.mv[0] = triangleMrgCtx.mvFieldNeighbours[ candIdx1 << 1 ].mv;
biMv.mv[1] = triangleMrgCtx.mvFieldNeighbours[(candIdx0 << 1) + 1].mv;
biMv.refIdx[0] = triangleMrgCtx.mvFieldNeighbours[ candIdx1 << 1 ].refIdx;
biMv.refIdx[1] = triangleMrgCtx.mvFieldNeighbours[(candIdx0 << 1) + 1].refIdx;
else if( triangleMrgCtx.interDirNeighbours[candIdx0] == 1 && triangleMrgCtx.interDirNeighbours[candIdx1] == 1 )
int32_t refIdx = mappingRefPic( pu, pu.cs->slice->getRefPOC( REF_PIC_LIST_0, triangleMrgCtx.mvFieldNeighbours[candIdx1 << 1].refIdx ), REF_PIC_LIST_1 );
if( refIdx != -1 )
{
biMv.interDir = 3;
biMv.mv[0] = triangleMrgCtx.mvFieldNeighbours[candIdx0 << 1].mv;
biMv.mv[1] = triangleMrgCtx.mvFieldNeighbours[candIdx1 << 1].mv;
biMv.refIdx[0] = triangleMrgCtx.mvFieldNeighbours[candIdx0 << 1].refIdx;
biMv.refIdx[1] = refIdx;
}
else
{
refIdx = mappingRefPic( pu, pu.cs->slice->getRefPOC( REF_PIC_LIST_0, triangleMrgCtx.mvFieldNeighbours[candIdx0 << 1].refIdx), REF_PIC_LIST_1 );
biMv.interDir = ( refIdx != -1 ) ? 3 : 1;
biMv.mv[0] = ( refIdx != -1 ) ? triangleMrgCtx.mvFieldNeighbours[candIdx1 << 1].mv : triangleMrgCtx.mvFieldNeighbours[candIdx0 << 1].mv;
biMv.mv[1] = ( refIdx != -1 ) ? triangleMrgCtx.mvFieldNeighbours[candIdx0 << 1].mv : Mv(0, 0);
biMv.refIdx[0] = ( refIdx != -1 ) ? triangleMrgCtx.mvFieldNeighbours[candIdx1 << 1].refIdx : triangleMrgCtx.mvFieldNeighbours[candIdx0 << 1].refIdx;
biMv.refIdx[1] = ( refIdx != -1 ) ? refIdx : -1;
else if( triangleMrgCtx.interDirNeighbours[candIdx0] == 2 && triangleMrgCtx.interDirNeighbours[candIdx1] == 2 )
int32_t refIdx = mappingRefPic( pu, pu.cs->slice->getRefPOC( REF_PIC_LIST_1, triangleMrgCtx.mvFieldNeighbours[(candIdx1 << 1) + 1].refIdx ), REF_PIC_LIST_0 );
if( refIdx != -1 )
{
biMv.interDir = 3;
biMv.mv[0] = triangleMrgCtx.mvFieldNeighbours[(candIdx1 << 1) + 1].mv;
biMv.mv[1] = triangleMrgCtx.mvFieldNeighbours[(candIdx0 << 1) + 1].mv;
biMv.refIdx[0] = refIdx;
biMv.refIdx[1] = triangleMrgCtx.mvFieldNeighbours[(candIdx0 << 1) + 1].refIdx;
}
else
{
refIdx = mappingRefPic( pu, pu.cs->slice->getRefPOC( REF_PIC_LIST_1, triangleMrgCtx.mvFieldNeighbours[(candIdx0 << 1) + 1].refIdx ), REF_PIC_LIST_0 );
biMv.interDir = ( refIdx != -1 ) ? 3 : 2;
biMv.mv[0] = ( refIdx != -1 ) ? triangleMrgCtx.mvFieldNeighbours[(candIdx0 << 1) + 1].mv : Mv(0, 0);
biMv.mv[1] = ( refIdx != -1 ) ? triangleMrgCtx.mvFieldNeighbours[(candIdx1 << 1) + 1].mv : triangleMrgCtx.mvFieldNeighbours[(candIdx0 << 1) + 1].mv;
biMv.refIdx[0] = ( refIdx != -1 ) ? refIdx : -1;
biMv.refIdx[1] = ( refIdx != -1 ) ? triangleMrgCtx.mvFieldNeighbours[(candIdx1 << 1) + 1].refIdx : triangleMrgCtx.mvFieldNeighbours[(candIdx0 << 1) + 1].refIdx;
int32_t idxW = (int32_t)(g_aucLog2[pu.lwidth() ] - MIN_CU_LOG2);
int32_t idxH = (int32_t)(g_aucLog2[pu.lheight()] - MIN_CU_LOG2);
for( int32_t y = 0; y < mb.height; y++ )