Newer
Older

Karsten Suehring
committed
4001
4002
4003
4004
4005
4006
4007
4008
4009
4010
4011
4012
4013
4014
4015
4016
4017
4018
4019
4020
4021
4022
4023
4024
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;

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

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
4050
4051
4052
4053
4054
4055
4056
4057
4058
4059
4060
4061
4062
4063
4064
4065
4066
4067
4068
4069
4070
4071
4072
4073
4074
4075
4076
4077
4078
4079
4080
4081
4082
4083
4084
4085
4086
4087
4088
4089
4090
4091
4092
4093
4094
4095
4096
4097
4098
4099
4100
4101
4102
4103
4104
}
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
4342
4343
4344
4345
4346
4347
4348
4349
4350
4351
4352
4353
4354
4355
4356
4357
4358
4359
4360
4361
4362
4363
4364
4365
4366
4367
4368
4369
4370
4371
4372
4373
4374
4375
4376
4377
4378
4379
4380
4381
4382
4383
4384
4385
4386
4387
4388
4389
4390
4391
4392
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].changePrecisionAmvr( pu.cu->imv, MV_PRECISION_QUARTER);

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];
pu.mv[0].changePrecision(MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL);
#if JVET_N0334_MVCLIPPING
pu.mv[0].mvCliptoStorageBitDepth();
#endif

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].changePrecisionAmvr(pu.cu->imv, MV_PRECISION_QUARTER);

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];
pu.mv[1].changePrecision(MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL);
#if JVET_N0334_MVCLIPPING
pu.mv[1].mvCliptoStorageBitDepth();
#endif

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

Karsten Suehring
committed
4436
4437
4438
4439
4440
4441
4442
4443
4444
4445
4446
4447
4448
4449
4450
4451
4452
4453
4454
4455
4456
4457
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 )
{
const CodingStructure &cs = *pu.cs;
const Slice &slice = *pu.cs->slice;
const int32_t maxNumMergeCand = TRIANGLE_MAX_NUM_UNI_CANDS;
for( int32_t i = 0; i < maxNumMergeCand; i++ )
{
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();
MotionInfo candidate[TRIANGLE_MAX_NUM_CANDS_MEM];
int32_t candCount = 0;
const Position posLT = pu.Y().topLeft();
const Position posRT = pu.Y().topRight();
const Position posLB = pu.Y().bottomLeft();
MotionInfo miAbove, miLeft, miAboveLeft, miAboveRight, miBelowLeft;
//left
const PredictionUnit* puLeft = cs.getPURestricted( posLB.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( posLB.offset(-1, 0) );
candidate[candCount].isInter = true;
candidate[candCount].interDir = miLeft.interDir;
candidate[candCount].mv[0] = miLeft.mv[0];
candidate[candCount].mv[1] = miLeft.mv[1];
candidate[candCount].refIdx[0] = miLeft.refIdx[0];
candidate[candCount].refIdx[1] = miLeft.refIdx[1];
candCount++;
}
// above
const PredictionUnit *puAbove = cs.getPURestricted( posRT.offset( 0, -1 ), pu, pu.chType );
bool isAvailableB1 = puAbove && isDiffMER( pu, *puAbove ) && pu.cu != puAbove->cu && CU::isInter( *puAbove->cu )
;
if( isAvailableB1 )
{
miAbove = puAbove->getMotionInfo( posRT.offset( 0, -1 ) );
if( !isAvailableA1 || ( miAbove != miLeft ) )
{
candidate[candCount].isInter = true;
candidate[candCount].interDir = miAbove.interDir;
candidate[candCount].mv[0] = miAbove.mv[0];
candidate[candCount].mv[1] = miAbove.mv[1];
candidate[candCount].refIdx[0] = miAbove.refIdx[0];
candidate[candCount].refIdx[1] = miAbove.refIdx[1];
candCount++;
// above right
const PredictionUnit *puAboveRight = cs.getPURestricted( posRT.offset( 1, -1 ), pu, pu.chType );
bool isAvailableB0 = puAboveRight && isDiffMER( pu, *puAboveRight ) && CU::isInter( *puAboveRight->cu )
;
if( isAvailableB0 )
{
miAboveRight = puAboveRight->getMotionInfo( posRT.offset( 1, -1 ) );
if( ( !isAvailableB1 || ( miAbove != miAboveRight ) ) && ( !isAvailableA1 || ( miLeft != miAboveRight ) ) )
{
candidate[candCount].isInter = true;
candidate[candCount].interDir = miAboveRight.interDir;
candidate[candCount].mv[0] = miAboveRight.mv[0];
candidate[candCount].mv[1] = miAboveRight.mv[1];
candidate[candCount].refIdx[0] = miAboveRight.refIdx[0];
candidate[candCount].refIdx[1] = miAboveRight.refIdx[1];
candCount++;
//left bottom
const PredictionUnit *puLeftBottom = cs.getPURestricted( posLB.offset( -1, 1 ), pu, pu.chType );
bool isAvailableA0 = puLeftBottom && isDiffMER( pu, *puLeftBottom ) && CU::isInter( *puLeftBottom->cu )
;
if( isAvailableA0 )
{
miBelowLeft = puLeftBottom->getMotionInfo( posLB.offset( -1, 1 ) );
if( ( !isAvailableA1 || ( miBelowLeft != miLeft ) ) && ( !isAvailableB1 || ( miBelowLeft != miAbove ) ) && ( !isAvailableB0 || ( miBelowLeft != miAboveRight ) ) )
{
candidate[candCount].isInter = true;
candidate[candCount].interDir = miBelowLeft.interDir;
candidate[candCount].mv[0] = miBelowLeft.mv[0];
candidate[candCount].mv[1] = miBelowLeft.mv[1];
candidate[candCount].refIdx[0] = miBelowLeft.refIdx[0];
candidate[candCount].refIdx[1] = miBelowLeft.refIdx[1];
candCount++;
}
}
// above left
const PredictionUnit *puAboveLeft = cs.getPURestricted( posLT.offset( -1, -1 ), pu, pu.chType );
bool isAvailableB2 = puAboveLeft && isDiffMER( pu, *puAboveLeft ) && CU::isInter( *puAboveLeft->cu )
;
if( isAvailableB2 )
{
miAboveLeft = puAboveLeft->getMotionInfo( posLT.offset( -1, -1 ) );
if( ( !isAvailableA1 || ( miLeft != miAboveLeft ) ) && ( !isAvailableB1 || ( miAbove != miAboveLeft ) ) && ( !isAvailableA0 || ( miBelowLeft != miAboveLeft ) ) && ( !isAvailableB0 || ( miAboveRight != miAboveLeft ) ) )
{
candidate[candCount].isInter = true;
candidate[candCount].interDir = miAboveLeft.interDir;
candidate[candCount].mv[0] = miAboveLeft.mv[0];
candidate[candCount].mv[1] = miAboveLeft.mv[1];
candidate[candCount].refIdx[0] = miAboveLeft.refIdx[0];
candidate[candCount].refIdx[1] = miAboveLeft.refIdx[1];
candCount++;
if( slice.getEnableTMVPFlag() )
{
Position posRB = pu.Y().bottomRight().offset(-3, -3);
const PreCalcValues& pcv = *cs.pcv;
Position posC0;
Position posC1 = pu.Y().center();
#if !JVET_N0266_SMALL_BLOCKS
bool isAvailableC1 = (posC1.x < pcv.lumaWidth) && (posC1.y < pcv.lumaHeight);
#endif
if (((posRB.x + pcv.minCUWidth) < pcv.lumaWidth) && ((posRB.y + pcv.minCUHeight) < pcv.lumaHeight))
{
Position posInCtu( posRB.x & pcv.maxCUWidthMask, posRB.y & pcv.maxCUHeightMask );
if( ( posInCtu.x + 4 < pcv.maxCUWidth ) && // is not at the last column of CTU
( posInCtu.y + 4 < pcv.maxCUHeight ) ) // is not at the last row of CTU
{
posC0 = posRB.offset( 4, 4 );
}
else if( posInCtu.x + 4 < pcv.maxCUWidth ) // is not at the last column of CTU But is last row of CTU
{
posC0 = posRB.offset( 4, 4 );
// in the reference the CTU address is not set - thus probably resulting in no using this C0 possibility
}
else if( posInCtu.y + 4 < pcv.maxCUHeight ) // is not at the last row of CTU But is last column of CTU
{
posC0 = posRB.offset( 4, 4 );
}
else //is the right bottom corner of CTU
{
posC0 = posRB.offset( 4, 4 );
// same as for last column but not last row
}
}
// C0
Mv cColMv;
int32_t refIdx = 0;
bool existMV = ( isAvailableC0 && getColocatedMVP( pu, REF_PIC_LIST_0, posC0, cColMv, refIdx ) );
MotionInfo temporalMv;
temporalMv.interDir = 0;
if( existMV )
temporalMv.isInter = true;
temporalMv.interDir |= 1;
temporalMv.mv[0] = cColMv;
temporalMv.refIdx[0] = refIdx;
existMV = ( isAvailableC0 && getColocatedMVP( pu, REF_PIC_LIST_1, posC0, cColMv, refIdx ) );
if( existMV )
temporalMv.interDir |= 2;
temporalMv.mv[1] = cColMv;
temporalMv.refIdx[1] = refIdx;
candidate[candCount].isInter = true;
candidate[candCount].interDir = temporalMv.interDir;
candidate[candCount].mv[0] = temporalMv.mv[0];
candidate[candCount].mv[1] = temporalMv.mv[1];
candidate[candCount].refIdx[0] = temporalMv.refIdx[0];
candidate[candCount].refIdx[1] = temporalMv.refIdx[1];
candCount++;
#if JVET_N0266_SMALL_BLOCKS
existMV = getColocatedMVP( pu, REF_PIC_LIST_0, posC1, cColMv, refIdx );
#else
existMV = isAvailableC1 && getColocatedMVP(pu, REF_PIC_LIST_0, posC1, cColMv, refIdx );
#endif
temporalMv.isInter = true;
temporalMv.interDir |= 1;
temporalMv.mv[0] = cColMv;
temporalMv.refIdx[0] = refIdx;
#if JVET_N0266_SMALL_BLOCKS
existMV = getColocatedMVP( pu, REF_PIC_LIST_1, posC1, cColMv, refIdx );
#else
existMV = isAvailableC1 && getColocatedMVP(pu, REF_PIC_LIST_1, posC1, cColMv, refIdx );
#endif
temporalMv.interDir |= 2;
temporalMv.mv[1] = cColMv;
temporalMv.refIdx[1] = refIdx;
candidate[candCount].isInter = true;
candidate[candCount].interDir = temporalMv.interDir;
candidate[candCount].mv[0] = temporalMv.mv[0];
candidate[candCount].mv[1] = temporalMv.mv[1];
candidate[candCount].refIdx[0] = temporalMv.refIdx[0];
candidate[candCount].refIdx[1] = temporalMv.refIdx[1];
candCount++;
}
// put uni-prediction candidate to the triangle candidate list
for( int32_t i = 0; i < candCount; i++ )
if( candidate[i].interDir != 3 )
{
triangleMrgCtx.interDirNeighbours[triangleMrgCtx.numValidMergeCand] = candidate[i].interDir;
triangleMrgCtx.mrgTypeNeighbours [triangleMrgCtx.numValidMergeCand] = MRG_TYPE_DEFAULT_N;
triangleMrgCtx.mvFieldNeighbours [(triangleMrgCtx.numValidMergeCand << 1) ].mv = candidate[i].mv[0];
triangleMrgCtx.mvFieldNeighbours [(triangleMrgCtx.numValidMergeCand << 1) + 1].mv = candidate[i].mv[1];
triangleMrgCtx.mvFieldNeighbours [(triangleMrgCtx.numValidMergeCand << 1) ].refIdx = candidate[i].refIdx[0];
triangleMrgCtx.mvFieldNeighbours [(triangleMrgCtx.numValidMergeCand << 1) + 1].refIdx = candidate[i].refIdx[1];
triangleMrgCtx.numValidMergeCand += isUniqueTriangleCandidates(pu, triangleMrgCtx);
if( triangleMrgCtx.numValidMergeCand == TRIANGLE_MAX_NUM_UNI_CANDS )
{
return;
}
}
}
// put L0 mv of bi-prediction candidate to the triangle candidate list
for( int32_t i = 0; i < candCount; i++ )
triangleMrgCtx.interDirNeighbours[triangleMrgCtx.numValidMergeCand] = 1;
triangleMrgCtx.mrgTypeNeighbours [triangleMrgCtx.numValidMergeCand] = MRG_TYPE_DEFAULT_N;
triangleMrgCtx.mvFieldNeighbours [(triangleMrgCtx.numValidMergeCand << 1) ].mv = candidate[i].mv[0];
triangleMrgCtx.mvFieldNeighbours [(triangleMrgCtx.numValidMergeCand << 1) + 1].mv = Mv(0, 0);
triangleMrgCtx.mvFieldNeighbours [(triangleMrgCtx.numValidMergeCand << 1) ].refIdx = candidate[i].refIdx[0];
triangleMrgCtx.mvFieldNeighbours [(triangleMrgCtx.numValidMergeCand << 1) + 1].refIdx = -1;
triangleMrgCtx.numValidMergeCand += isUniqueTriangleCandidates(pu, triangleMrgCtx);
if( triangleMrgCtx.numValidMergeCand == TRIANGLE_MAX_NUM_UNI_CANDS )
{
return;
}
}
}
// put L1 mv of bi-prediction candidate to the triangle candidate list
for( int32_t i = 0; i < candCount; i++ )
triangleMrgCtx.interDirNeighbours[triangleMrgCtx.numValidMergeCand] = 2;
triangleMrgCtx.mrgTypeNeighbours [triangleMrgCtx.numValidMergeCand] = MRG_TYPE_DEFAULT_N;
triangleMrgCtx.mvFieldNeighbours [(triangleMrgCtx.numValidMergeCand << 1) ].mv = Mv(0, 0);
triangleMrgCtx.mvFieldNeighbours [(triangleMrgCtx.numValidMergeCand << 1) + 1].mv = candidate[i].mv[1];
triangleMrgCtx.mvFieldNeighbours [(triangleMrgCtx.numValidMergeCand << 1) ].refIdx = -1;
triangleMrgCtx.mvFieldNeighbours [(triangleMrgCtx.numValidMergeCand << 1) + 1].refIdx = candidate[i].refIdx[1];
triangleMrgCtx.numValidMergeCand += isUniqueTriangleCandidates(pu, triangleMrgCtx);
if( triangleMrgCtx.numValidMergeCand == TRIANGLE_MAX_NUM_UNI_CANDS )
{
return;
}
}
}
// put average of L0 and L1 mvs of bi-prediction candidate to the triangle candidate list
for( int32_t i = 0; i < candCount; i++ )
int32_t curPicPoc = slice.getPOC();
int32_t refPicPocL0 = slice.getRefPOC(REF_PIC_LIST_0, candidate[i].refIdx[0]);
int32_t refPicPocL1 = slice.getRefPOC(REF_PIC_LIST_1, candidate[i].refIdx[1]);
Mv aveMv = candidate[i].mv[1];
int32_t distscale = xGetDistScaleFactor( curPicPoc, refPicPocL0, curPicPoc, refPicPocL1 );
if( distscale != 4096 )
{
aveMv = aveMv.scaleMv( distscale ); // scaling to L0
}
aveMv = aveMv + candidate[i].mv[0];
roundAffineMv(aveMv.hor, aveMv.ver, 1);
triangleMrgCtx.interDirNeighbours[triangleMrgCtx.numValidMergeCand] = 1;
triangleMrgCtx.mrgTypeNeighbours [triangleMrgCtx.numValidMergeCand] = MRG_TYPE_DEFAULT_N;
triangleMrgCtx.mvFieldNeighbours [(triangleMrgCtx.numValidMergeCand << 1) ].mv = aveMv;
triangleMrgCtx.mvFieldNeighbours [(triangleMrgCtx.numValidMergeCand << 1) + 1].mv = Mv(0, 0);
triangleMrgCtx.mvFieldNeighbours [(triangleMrgCtx.numValidMergeCand << 1) ].refIdx = candidate[i].refIdx[0];
triangleMrgCtx.mvFieldNeighbours [(triangleMrgCtx.numValidMergeCand << 1) + 1].refIdx = -1;
triangleMrgCtx.numValidMergeCand += isUniqueTriangleCandidates(pu, triangleMrgCtx);
if( triangleMrgCtx.numValidMergeCand == TRIANGLE_MAX_NUM_UNI_CANDS )
{
return;
}
}
// fill with Mv(0, 0)
int32_t numRefIdx = std::min( slice.getNumRefIdx(REF_PIC_LIST_0), slice.getNumRefIdx(REF_PIC_LIST_1) );
int32_t cnt = 0;
while( triangleMrgCtx.numValidMergeCand < TRIANGLE_MAX_NUM_UNI_CANDS )
triangleMrgCtx.interDirNeighbours[triangleMrgCtx.numValidMergeCand] = 1;
triangleMrgCtx.mvFieldNeighbours[triangleMrgCtx.numValidMergeCand << 1].setMvField(Mv(0, 0), cnt);
triangleMrgCtx.mvFieldNeighbours[(triangleMrgCtx.numValidMergeCand << 1) + 1].refIdx = NOT_VALID;
triangleMrgCtx.mvFieldNeighbours[(triangleMrgCtx.numValidMergeCand << 1) + 1].mv = Mv();
if( triangleMrgCtx.numValidMergeCand == TRIANGLE_MAX_NUM_UNI_CANDS )
{
return;
}
triangleMrgCtx.interDirNeighbours[triangleMrgCtx.numValidMergeCand] = 2;
triangleMrgCtx.mvFieldNeighbours [(triangleMrgCtx.numValidMergeCand << 1) + 1 ].setMvField(Mv(0, 0), cnt);
triangleMrgCtx.mvFieldNeighbours[triangleMrgCtx.numValidMergeCand << 1].refIdx = NOT_VALID;
triangleMrgCtx.mvFieldNeighbours[triangleMrgCtx.numValidMergeCand << 1].mv = Mv();
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++ )
{
for( int32_t x = 0; x < mb.width; x++ )
{
if( g_triangleMvStorage[splitDir][idxH][idxW][y][x] == 2 )
{
mb.at( x, y ).isInter = true;
mb.at( x, y ).interDir = biMv.interDir;
mb.at( x, y ).refIdx[0] = biMv.refIdx[0];
mb.at( x, y ).refIdx[1] = biMv.refIdx[1];
mb.at( x, y ).mv [0] = biMv.mv [0];
mb.at( x, y ).mv [1] = biMv.mv [1];
mb.at( x, y ).sliceIdx = biMv.sliceIdx;
else if( g_triangleMvStorage[splitDir][idxH][idxW][y][x] == 0 )
{
mb.at( x, y ).isInter = true;
mb.at( x, y ).interDir = triangleMrgCtx.interDirNeighbours[candIdx0];
mb.at( x, y ).refIdx[0] = triangleMrgCtx.mvFieldNeighbours[ candIdx0 << 1 ].refIdx;
mb.at( x, y ).refIdx[1] = triangleMrgCtx.mvFieldNeighbours[(candIdx0 << 1) + 1].refIdx;
mb.at( x, y ).mv [0] = triangleMrgCtx.mvFieldNeighbours[ candIdx0 << 1 ].mv;
mb.at( x, y ).mv [1] = triangleMrgCtx.mvFieldNeighbours[(candIdx0 << 1) + 1].mv;
mb.at( x, y ).sliceIdx = biMv.sliceIdx;
}
else
{
mb.at( x, y ).isInter = true;
mb.at( x, y ).interDir = triangleMrgCtx.interDirNeighbours[candIdx1];
mb.at( x, y ).refIdx[0] = triangleMrgCtx.mvFieldNeighbours[ candIdx1 << 1 ].refIdx;
mb.at( x, y ).refIdx[1] = triangleMrgCtx.mvFieldNeighbours[(candIdx1 << 1) + 1].refIdx;
mb.at( x, y ).mv [0] = triangleMrgCtx.mvFieldNeighbours[ candIdx1 << 1 ].mv;
mb.at( x, y ).mv [1] = triangleMrgCtx.mvFieldNeighbours[(candIdx1 << 1) + 1].mv;
mb.at( x, y ).sliceIdx = biMv.sliceIdx;
}
}
}
}
int32_t PU::mappingRefPic( const PredictionUnit &pu, int32_t refPicPoc, bool targetRefPicList )
{
int32_t numRefIdx = pu.cs->slice->getNumRefIdx( (RefPicList)targetRefPicList );
for( int32_t i = 0; i < numRefIdx; i++ )
{
if( pu.cs->slice->getRefPOC( (RefPicList)targetRefPicList, i ) == refPicPoc )
{
return i;
}
}
return -1;
}

Karsten Suehring
committed
void CU::resetMVDandMV2Int( CodingUnit& cu, InterPrediction *interPred )
{
for( auto &pu : CU::traversePUs( cu ) )
{
MergeCtx mrgCtx;