Newer
Older

Karsten Suehring
committed
{
return;
}
cnt++;
}
}
// early termination
if( cnt == maxNumMergeCand )
{
return;
}
//left bottom
const PredictionUnit *puLeftBottom = cs.getPURestricted( posLB.offset( -1, 1 ), pu, pu.chType );
bool isAvailableA0 = puLeftBottom && isDiffMER( pu.lumaPos(), posLB.offset(-1, 1), plevel) && CU::isInter( *puLeftBottom->cu );
#else

Karsten Suehring
committed
bool isAvailableA0 = puLeftBottom && isDiffMER( pu, *puLeftBottom ) && CU::isInter( *puLeftBottom->cu );

Karsten Suehring
committed
if( isAvailableA0 )
{
miBelowLeft = puLeftBottom->getMotionInfo( posLB.offset( -1, 1 ) );
if( !isAvailableA1 || ( miBelowLeft != miLeft ) )
{
// get Inter Dir
mrgCtx.interDirNeighbours[cnt] = miBelowLeft.interDir;
mrgCtx.useAltHpelIf[cnt] = miBelowLeft.useAltHpelIf;
mrgCtx.BcwIdx[cnt] = (mrgCtx.interDirNeighbours[cnt] == 3) ? puLeftBottom->cu->BcwIdx : BCW_DEFAULT;

Karsten Suehring
committed
// get Mv from Bottom-Left
mrgCtx.mvFieldNeighbours[cnt << 1].setMvField( miBelowLeft.mv[0], miBelowLeft.refIdx[0] );
if( slice.isInterB() )
{
mrgCtx.mvFieldNeighbours[( cnt << 1 ) + 1].setMvField( miBelowLeft.mv[1], miBelowLeft.refIdx[1] );
}

Karsten Suehring
committed
{
return;
}
cnt++;
}
}
// early termination
if( cnt == maxNumMergeCand )
{
return;
}
// above left
if ( cnt < 4 )

Karsten Suehring
committed
{
const PredictionUnit *puAboveLeft = cs.getPURestricted( posLT.offset( -1, -1 ), pu, pu.chType );
bool isAvailableB2 = puAboveLeft && isDiffMER( pu.lumaPos(), posLT.offset(-1, -1), plevel ) && CU::isInter( *puAboveLeft->cu );
#else

Karsten Suehring
committed
bool isAvailableB2 = puAboveLeft && isDiffMER( pu, *puAboveLeft ) && CU::isInter( *puAboveLeft->cu );

Karsten Suehring
committed
if( isAvailableB2 )
{
miAboveLeft = puAboveLeft->getMotionInfo( posLT.offset( -1, -1 ) );
if( ( !isAvailableA1 || ( miLeft != miAboveLeft ) ) && ( !isAvailableB1 || ( miAbove != miAboveLeft ) ) )
{
// get Inter Dir
mrgCtx.interDirNeighbours[cnt] = miAboveLeft.interDir;
mrgCtx.useAltHpelIf[cnt] = miAboveLeft.useAltHpelIf;
mrgCtx.BcwIdx[cnt] = (mrgCtx.interDirNeighbours[cnt] == 3) ? puAboveLeft->cu->BcwIdx : BCW_DEFAULT;

Karsten Suehring
committed
// get Mv from Above-Left
mrgCtx.mvFieldNeighbours[cnt << 1].setMvField( miAboveLeft.mv[0], miAboveLeft.refIdx[0] );
if( slice.isInterB() )
{
mrgCtx.mvFieldNeighbours[( cnt << 1 ) + 1].setMvField( miAboveLeft.mv[1], miAboveLeft.refIdx[1] );
}

Karsten Suehring
committed
{
return;
}
cnt++;
}
}
}
// early termination
if (cnt == maxNumMergeCand)
{
return;
}
if (slice.getPicHeader()->getEnableTMVPFlag() && (pu.lumaSize().width + pu.lumaSize().height > 12))

Karsten Suehring
committed
{
//>> 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 );

Karsten Suehring
committed
const PreCalcValues& pcv = *cs.pcv;
Position posC0;
Position posC1 = pu.Y().center();

Karsten Suehring
committed
bool C0Avail = false;
#if JVET_O1143_MV_ACROSS_SUBPIC_BOUNDARY
bool boundaryCond = ((posRB.x + pcv.minCUWidth) < pcv.lumaWidth) && ((posRB.y + pcv.minCUHeight) < pcv.lumaHeight);
const SubPic& curSubPic = pu.cs->slice->getPPS()->getSubPicFromPos(pu.lumaPos());
if (curSubPic.getTreatedAsPicFlag())
{
boundaryCond = ((posRB.x + pcv.minCUWidth) <= curSubPic.getSubPicRight() &&
(posRB.y + pcv.minCUHeight) <= curSubPic.getSubPicBottom());
}
if (boundaryCond)
#else

Karsten Suehring
committed
if (((posRB.x + pcv.minCUWidth) < pcv.lumaWidth) && ((posRB.y + pcv.minCUHeight) < pcv.lumaHeight))
#endif

Karsten Suehring
committed
{
int posYInCtu = posRB.y & pcv.maxCUHeightMask;
if (posYInCtu + 4 < pcv.maxCUHeight)

Karsten Suehring
committed
{
posC0 = posRB.offset(4, 4);
C0Avail = true;

Karsten Suehring
committed
}
}
Mv cColMv;
int iRefIdx = 0;
int dir = 0;
unsigned uiArrayAddr = cnt;
bool bExistMV = ( C0Avail && getColocatedMVP(pu, REF_PIC_LIST_0, posC0, cColMv, iRefIdx, false ) )
|| getColocatedMVP( pu, REF_PIC_LIST_0, posC1, cColMv, iRefIdx, false );

Karsten Suehring
committed
if (bExistMV)
{
dir |= 1;
mrgCtx.mvFieldNeighbours[2 * uiArrayAddr].setMvField(cColMv, iRefIdx);
}
if (slice.isInterB())
{
bExistMV = ( C0Avail && getColocatedMVP(pu, REF_PIC_LIST_1, posC0, cColMv, iRefIdx, false ) )
|| getColocatedMVP( pu, REF_PIC_LIST_1, posC1, cColMv, iRefIdx, false );

Karsten Suehring
committed
if (bExistMV)
{
dir |= 2;
mrgCtx.mvFieldNeighbours[2 * uiArrayAddr + 1].setMvField(cColMv, iRefIdx);
}
}
if( dir != 0 )
{
bool addTMvp = true;

Karsten Suehring
committed
if( addTMvp )
{
mrgCtx.interDirNeighbours[uiArrayAddr] = dir;
mrgCtx.BcwIdx[uiArrayAddr] = BCW_DEFAULT;
mrgCtx.useAltHpelIf[uiArrayAddr] = false;

Karsten Suehring
committed
{
return;
}
cnt++;
}
}
}
// early termination
if (cnt == maxNumMergeCand)
{
return;
}
int maxNumMergeCandMin1 = maxNumMergeCand - 1;
if (cnt != maxNumMergeCandMin1)
{
bool bFound = addMergeHMVPCand(cs, mrgCtx, mrgCandIdx, maxNumMergeCandMin1, cnt
, isAvailableA1, miLeft, isAvailableB1, miAbove
if (bFound)
{
return;
}
}
Yuling Hsiao
committed
// pairwise-average candidates
{
Yuling Hsiao
committed
{
mrgCtx.mvFieldNeighbours[cnt * 2].setMvField( Mv( 0, 0 ), NOT_VALID );
mrgCtx.mvFieldNeighbours[cnt * 2 + 1].setMvField( Mv( 0, 0 ), NOT_VALID );
// calculate average MV for L0 and L1 seperately
unsigned char interDir = 0;
mrgCtx.useAltHpelIf[cnt] = (mrgCtx.useAltHpelIf[0] == mrgCtx.useAltHpelIf[1]) ? mrgCtx.useAltHpelIf[0] : false;
Yuling Hsiao
committed
for( int refListId = 0; refListId < (slice.isInterB() ? 2 : 1); refListId++ )
{
Anish Tamse
committed
const short refIdxI = mrgCtx.mvFieldNeighbours[0 * 2 + refListId].refIdx;
const short refIdxJ = mrgCtx.mvFieldNeighbours[1 * 2 + refListId].refIdx;
Yuling Hsiao
committed
// both MVs are invalid, skip
if( (refIdxI == NOT_VALID) && (refIdxJ == NOT_VALID) )
{
continue;
}
interDir += 1 << refListId;
// both MVs are valid, average these two MVs
if( (refIdxI != NOT_VALID) && (refIdxJ != NOT_VALID) )
{
Anish Tamse
committed
const Mv& MvI = mrgCtx.mvFieldNeighbours[0 * 2 + refListId].mv;
const Mv& MvJ = mrgCtx.mvFieldNeighbours[1 * 2 + refListId].mv;
Yuling Hsiao
committed
// average two MVs
Mv avgMv = MvI;
avgMv += MvJ;
Yuling Hsiao
committed
mrgCtx.mvFieldNeighbours[cnt * 2 + refListId].setMvField( avgMv, refIdxI );
}
// only one MV is valid, take the only one MV
else if( refIdxI != NOT_VALID )
{
Anish Tamse
committed
Mv singleMv = mrgCtx.mvFieldNeighbours[0 * 2 + refListId].mv;
Yuling Hsiao
committed
mrgCtx.mvFieldNeighbours[cnt * 2 + refListId].setMvField( singleMv, refIdxI );
}
else if( refIdxJ != NOT_VALID )
{
Anish Tamse
committed
Mv singleMv = mrgCtx.mvFieldNeighbours[1 * 2 + refListId].mv;
Yuling Hsiao
committed
mrgCtx.mvFieldNeighbours[cnt * 2 + refListId].setMvField( singleMv, refIdxJ );
}
}
mrgCtx.interDirNeighbours[cnt] = interDir;
if( interDir > 0 )
{
cnt++;
}
}
// early termination
if( cnt == maxNumMergeCand )
{
return;
}
}

Karsten Suehring
committed
uint32_t uiArrayAddr = cnt;
int iNumRefIdx = slice.isInterB() ? std::min(slice.getNumRefIdx(REF_PIC_LIST_0), slice.getNumRefIdx(REF_PIC_LIST_1)) : slice.getNumRefIdx(REF_PIC_LIST_0);
int r = 0;
int refcnt = 0;
while (uiArrayAddr < maxNumMergeCand)
{
mrgCtx.interDirNeighbours [uiArrayAddr ] = 1;
mrgCtx.BcwIdx [uiArrayAddr ] = BCW_DEFAULT;

Karsten Suehring
committed
mrgCtx.mvFieldNeighbours [uiArrayAddr << 1].setMvField(Mv(0, 0), r);
mrgCtx.useAltHpelIf[uiArrayAddr] = false;

Karsten Suehring
committed
if (slice.isInterB())
{
mrgCtx.interDirNeighbours [ uiArrayAddr ] = 3;
mrgCtx.mvFieldNeighbours [(uiArrayAddr << 1) + 1].setMvField(Mv(0, 0), r);
}
if ( mrgCtx.interDirNeighbours[uiArrayAddr] == 1 && pu.cs->slice->getRefPic(REF_PIC_LIST_0, mrgCtx.mvFieldNeighbours[uiArrayAddr << 1].refIdx)->getPOC() == pu.cs->slice->getPOC())
{
mrgCtx.mrgTypeNeighbours[uiArrayAddr] = MRG_TYPE_IBC;

Karsten Suehring
committed
uiArrayAddr++;
if (refcnt == iNumRefIdx - 1)
{
r = 0;
}
else
{
++r;
++refcnt;
}
}
mrgCtx.numValidMergeCand = uiArrayAddr;
}
bool PU::checkDMVRCondition(const PredictionUnit& pu)
{
WPScalingParam *wp0;
WPScalingParam *wp1;
int refIdx0 = pu.refIdx[REF_PIC_LIST_0];
int refIdx1 = pu.refIdx[REF_PIC_LIST_1];
pu.cu->slice->getWpScaling(REF_PIC_LIST_0, refIdx0, wp0);
pu.cu->slice->getWpScaling(REF_PIC_LIST_1, refIdx1, wp1);

Xuewei Meng
committed
if (pu.cs->sps->getUseDMVR() && (!pu.cs->picHeader->getDisDmvrFlag()))
{
return pu.mergeFlag
&& pu.mergeType == MRG_TYPE_DEFAULT_N
&& !pu.cu->affine
&& !pu.mmvdMergeFlag
&& !pu.cu->mmvdSkip
&& PU::isBiPredFromDifferentDirEqDistPoc(pu)
&& (pu.lheight() >= 8)
&& (pu.lwidth() >= 8)
&& ((pu.lheight() * pu.lwidth()) >= 128)
&& (pu.cu->BcwIdx == BCW_DEFAULT)
#if JVET_Q0128_DMVR_BDOF_ENABLING_CONDITION
&& ((!wp0[COMPONENT_Y].bPresentFlag) && (!wp0[COMPONENT_Cb].bPresentFlag) && (!wp0[COMPONENT_Cr].bPresentFlag) && (!wp1[COMPONENT_Y].bPresentFlag) && (!wp1[COMPONENT_Cb].bPresentFlag) && (!wp1[COMPONENT_Cr].bPresentFlag))
#else
Takeshi Chujoh
committed
&& ((!wp0[COMPONENT_Y].bPresentFlag) && (!wp1[COMPONENT_Y].bPresentFlag))
#if JVET_Q0487_SCALING_WINDOW_ISSUES
&& ( refIdx0 < 0 ? true : (pu.cu->slice->getRefPic( REF_PIC_LIST_0, refIdx0 )->isRefScaled( pu.cs->pps ) == false) )
&& ( refIdx1 < 0 ? true : (pu.cu->slice->getRefPic( REF_PIC_LIST_1, refIdx1 )->isRefScaled( pu.cs->pps ) == false) )
#else
&& ( refIdx0 < 0 ? true : pu.cu->slice->getScalingRatio( REF_PIC_LIST_0, refIdx0 ) == SCALE_1X ) && ( refIdx1 < 0 ? true : pu.cu->slice->getScalingRatio( REF_PIC_LIST_1, refIdx1 ) == SCALE_1X )
;
}
else
{
return false;
}
}

Karsten Suehring
committed
static int xGetDistScaleFactor(const int &iCurrPOC, const int &iCurrRefPOC, const int &iColPOC, const int &iColRefPOC)
{
int iDiffPocD = iColPOC - iColRefPOC;
int iDiffPocB = iCurrPOC - iCurrRefPOC;
if (iDiffPocD == iDiffPocB)
{
return 4096;
}
else
{
int iTDB = Clip3(-128, 127, iDiffPocB);
int iTDD = Clip3(-128, 127, iDiffPocD);
int iX = (0x4000 + abs(iTDD / 2)) / iTDD;
int iScale = Clip3(-4096, 4095, (iTDB * iX + 32) >> 6);
return iScale;
}
}
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
int convertMvFixedToFloat(int32_t val)
{
int sign = val >> 31;
int scale = floorLog2((val ^ sign) | MV_MANTISSA_UPPER_LIMIT) - (MV_MANTISSA_BITCOUNT - 1);
int exponent;
int mantissa;
if (scale >= 0)
{
int round = (1 << scale) >> 1;
int n = (val + round) >> scale;
exponent = scale + ((n ^ sign) >> (MV_MANTISSA_BITCOUNT - 1));
mantissa = (n & MV_MANTISSA_UPPER_LIMIT) | (sign << (MV_MANTISSA_BITCOUNT - 1));
}
else
{
exponent = 0;
mantissa = val;
}
return exponent | (mantissa << MV_EXPONENT_BITCOUNT);
}
int convertMvFloatToFixed(int val)
{
int exponent = val & MV_EXPONENT_MASK;
int mantissa = val >> MV_EXPONENT_BITCOUNT;
return exponent == 0 ? mantissa : (mantissa ^ MV_MANTISSA_LIMIT) << (exponent - 1);
}
int roundMvComp(int x)
{
return convertMvFloatToFixed(convertMvFixedToFloat(x));
}
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
int PU::getDistScaleFactor(const int &currPOC, const int &currRefPOC, const int &colPOC, const int &colRefPOC)
{
return xGetDistScaleFactor(currPOC, currRefPOC, colPOC, colRefPOC);
}
void PU::getInterMMVDMergeCandidates(const PredictionUnit &pu, MergeCtx& mrgCtx, const int& mrgCandIdx)
{
int refIdxList0, refIdxList1;
int k;
int currBaseNum = 0;
const uint16_t maxNumMergeCand = mrgCtx.numValidMergeCand;
for (k = 0; k < maxNumMergeCand; k++)
{
if (mrgCtx.mrgTypeNeighbours[k] == MRG_TYPE_DEFAULT_N)
{
refIdxList0 = mrgCtx.mvFieldNeighbours[(k << 1)].refIdx;
refIdxList1 = mrgCtx.mvFieldNeighbours[(k << 1) + 1].refIdx;
if ((refIdxList0 >= 0) && (refIdxList1 >= 0))
{
mrgCtx.mmvdBaseMv[currBaseNum][0] = mrgCtx.mvFieldNeighbours[(k << 1)];
mrgCtx.mmvdBaseMv[currBaseNum][1] = mrgCtx.mvFieldNeighbours[(k << 1) + 1];
}
else if (refIdxList0 >= 0)
{
mrgCtx.mmvdBaseMv[currBaseNum][0] = mrgCtx.mvFieldNeighbours[(k << 1)];
mrgCtx.mmvdBaseMv[currBaseNum][1] = MvField(Mv(0, 0), -1);
}
else if (refIdxList1 >= 0)
{
mrgCtx.mmvdBaseMv[currBaseNum][0] = MvField(Mv(0, 0), -1);
mrgCtx.mmvdBaseMv[currBaseNum][1] = mrgCtx.mvFieldNeighbours[(k << 1) + 1];
}
mrgCtx.mmvdUseAltHpelIf[currBaseNum] = mrgCtx.useAltHpelIf[k];

Karsten Suehring
committed
currBaseNum++;
if (currBaseNum == MMVD_BASE_MV_NUM)
break;
}
}
}
bool PU::getColocatedMVP(const PredictionUnit &pu, const RefPicList &eRefPicList, const Position &_pos, Mv& rcMv, const int &refIdx, bool sbFlag)

Karsten Suehring
committed
{
// don't perform MV compression when generally disabled or subPuMvp is used
const unsigned scale = 4 * std::max<int>(1, 4 * AMVP_DECIMATION_FACTOR / 4);

Karsten Suehring
committed
const unsigned mask = ~( scale - 1 );
const Position pos = Position{ PosType( _pos.x & mask ), PosType( _pos.y & mask ) };
const Slice &slice = *pu.cs->slice;
// use coldir.
const Picture* const pColPic = slice.getRefPic(RefPicList(slice.isInterB() ? 1 - slice.getColFromL0Flag() : 0), slice.getColRefIdx());
if( !pColPic )
{
return false;
}
#if JVET_O1143_MV_ACROSS_SUBPIC_BOUNDARY
// Check the position of colocated block is within a subpicture
const SubPic &curSubPic = pu.cs->slice->getPPS()->getSubPicFromPos(pu.lumaPos());
if (curSubPic.getTreatedAsPicFlag())
{
if (!curSubPic.isContainingPos(pos))
return false;
}
#endif

Karsten Suehring
committed
RefPicList eColRefPicList = slice.getCheckLDC() ? eRefPicList : RefPicList(slice.getColFromL0Flag());
const MotionInfo& mi = pColPic->cs->getMotionInfo( pos );
if( !mi.isInter )
{
return false;
}
if (mi.isIBCmot)
{
return false;
}
if (CU::isIBC(*pu.cu))

Karsten Suehring
committed
int iColRefIdx = mi.refIdx[eColRefPicList];
if (sbFlag && !slice.getCheckLDC())

Karsten Suehring
committed
{

Karsten Suehring
committed
iColRefIdx = mi.refIdx[eColRefPicList];
if (iColRefIdx < 0)
{
return false;
}
}
else
{
if (iColRefIdx < 0)
{
eColRefPicList = RefPicList(1 - eColRefPicList);
iColRefIdx = mi.refIdx[eColRefPicList];
if (iColRefIdx < 0)
{
return false;
}
}
}

Karsten Suehring
committed
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
const Slice *pColSlice = nullptr;
for( const auto s : pColPic->slices )
{
if( s->getIndependentSliceIdx() == mi.sliceIdx )
{
pColSlice = s;
break;
}
}
CHECK( pColSlice == nullptr, "Slice segment not found" );
const Slice &colSlice = *pColSlice;
const bool bIsCurrRefLongTerm = slice.getRefPic(eRefPicList, refIdx)->longTerm;
const bool bIsColRefLongTerm = colSlice.getIsUsedAsLongTerm(eColRefPicList, iColRefIdx);
if (bIsCurrRefLongTerm != bIsColRefLongTerm)
{
return false;
}
// Scale the vector.
Mv cColMv = mi.mv[eColRefPicList];
cColMv.setHor(roundMvComp(cColMv.getHor()));
cColMv.setVer(roundMvComp(cColMv.getVer()));

Karsten Suehring
committed
if (bIsCurrRefLongTerm /*|| bIsColRefLongTerm*/)
{
rcMv = cColMv;
#if JVET_Q0483_CLIP_TMVP
rcMv.clipToStorageBitDepth();
#endif

Karsten Suehring
committed
}
else
{
const int currPOC = slice.getPOC();
const int colPOC = colSlice.getPOC();
const int colRefPOC = colSlice.getRefPOC(eColRefPicList, iColRefIdx);
const int currRefPOC = slice.getRefPic(eRefPicList, refIdx)->getPOC();
const int distscale = xGetDistScaleFactor(currPOC, currRefPOC, colPOC, colRefPOC);
if (distscale == 4096)
{
rcMv = cColMv;
#if JVET_Q0483_CLIP_TMVP
rcMv.clipToStorageBitDepth();
#endif

Karsten Suehring
committed
}
else
{
rcMv = cColMv.scaleMv(distscale);
}
}
return true;
}
bool PU::isDiffMER(const Position &pos1, const Position &pos2, const unsigned plevel)
{
const unsigned xN = pos1.x;
const unsigned yN = pos1.y;
const unsigned xP = pos2.x;
const unsigned yP = pos2.y;
if ((xN >> plevel) != (xP >> plevel))
{
return true;
}
if ((yN >> plevel) != (yP >> plevel))
{
return true;

Karsten Suehring
committed
bool PU::isDiffMER(const PredictionUnit &pu1, const PredictionUnit &pu2)
{
const unsigned xN = pu1.lumaPos().x;
const unsigned yN = pu1.lumaPos().y;
const unsigned xP = pu2.lumaPos().x;
const unsigned yP = pu2.lumaPos().y;

Karsten Suehring
committed
{
return true;
}

Karsten Suehring
committed
{
return true;
}
return false;
}
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
bool PU::isAddNeighborMv(const Mv& currMv, Mv* neighborMvs, int numNeighborMv)
{
bool existed = false;
for (uint32_t cand = 0; cand < numNeighborMv && !existed; cand++)
{
if (currMv == neighborMvs[cand])
{
existed = true;
}
}
if (!existed)
{
return true;
}
else
{
return false;
}
}
void PU::getIbcMVPsEncOnly(PredictionUnit &pu, Mv* mvPred, int& nbPred)
const PreCalcValues &pcv = *pu.cs->pcv;
const int cuWidth = pu.blocks[COMPONENT_Y].width;
const int cuHeight = pu.blocks[COMPONENT_Y].height;
const int log2UnitWidth = floorLog2(pcv.minCUWidth);
const int log2UnitHeight = floorLog2(pcv.minCUHeight);
const int totalAboveUnits = (cuWidth >> log2UnitWidth) + 1;
const int totalLeftUnits = (cuHeight >> log2UnitHeight) + 1;
nbPred = 0;
Position posLT = pu.Y().topLeft();
// above-left
const PredictionUnit *aboveLeftPU = pu.cs->getPURestricted(posLT.offset(-1, -1), pu, CHANNEL_TYPE_LUMA);
if (aboveLeftPU && CU::isIBC(*aboveLeftPU->cu))
{
if (isAddNeighborMv(aboveLeftPU->bv, mvPred, nbPred))
{
mvPred[nbPred++] = aboveLeftPU->bv;
}
}
// above neighbors
for (uint32_t dx = 0; dx < totalAboveUnits && nbPred < IBC_NUM_CANDIDATES; dx++)
{
const PredictionUnit* tmpPU = pu.cs->getPURestricted(posLT.offset((dx << log2UnitWidth), -1), pu, CHANNEL_TYPE_LUMA);
if (tmpPU && CU::isIBC(*tmpPU->cu))
{
if (isAddNeighborMv(tmpPU->bv, mvPred, nbPred))
{
mvPred[nbPred++] = tmpPU->bv;
}
}
}
// left neighbors
for (uint32_t dy = 0; dy < totalLeftUnits && nbPred < IBC_NUM_CANDIDATES; dy++)
{
const PredictionUnit* tmpPU = pu.cs->getPURestricted(posLT.offset(-1, (dy << log2UnitHeight)), pu, CHANNEL_TYPE_LUMA);
if (tmpPU && CU::isIBC(*tmpPU->cu))
{
if (isAddNeighborMv(tmpPU->bv, mvPred, nbPred))
{
mvPred[nbPred++] = tmpPU->bv;
}
}
}
size_t numAvaiCandInLUT = pu.cs->motionLut.lutIbc.size();
for (uint32_t cand = 0; cand < numAvaiCandInLUT && nbPred < IBC_NUM_CANDIDATES; cand++)
{
MotionInfo neibMi = pu.cs->motionLut.lutIbc[cand];
if (isAddNeighborMv(neibMi.bv, mvPred, nbPred))
{
mvPred[nbPred++] = neibMi.bv;
}
}

Karsten Suehring
committed
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
bool isBvCandDerived[IBC_NUM_CANDIDATES];
::memset(isBvCandDerived, false, IBC_NUM_CANDIDATES);
int curNbPred = nbPred;
if (curNbPred < IBC_NUM_CANDIDATES)
{
do
{
curNbPred = nbPred;
for (uint32_t idx = 0; idx < curNbPred && nbPred < IBC_NUM_CANDIDATES; idx++)
{
if (!isBvCandDerived[idx])
{
Mv derivedBv;
if (getDerivedBV(pu, mvPred[idx], derivedBv))
{
if (isAddNeighborMv(derivedBv, mvPred, nbPred))
{
mvPred[nbPred++] = derivedBv;
}
}
isBvCandDerived[idx] = true;
}
}
} while (nbPred > curNbPred && nbPred < IBC_NUM_CANDIDATES);
}
}
bool PU::getDerivedBV(PredictionUnit &pu, const Mv& currentMv, Mv& derivedMv)
{
int cuPelX = pu.lumaPos().x;
int cuPelY = pu.lumaPos().y;
int rX = cuPelX + currentMv.getHor();
int rY = cuPelY + currentMv.getVer();
int offsetX = currentMv.getHor();
int offsetY = currentMv.getVer();
if( rX < 0 || rY < 0 || rX >= pu.cs->slice->getPPS()->getPicWidthInLumaSamples() || rY >= pu.cs->slice->getPPS()->getPicHeightInLumaSamples() )
{
return false;
}
const PredictionUnit *neibRefPU = NULL;
neibRefPU = pu.cs->getPURestricted(pu.lumaPos().offset(offsetX, offsetY), pu, CHANNEL_TYPE_LUMA);
bool isIBC = (neibRefPU) ? CU::isIBC(*neibRefPU->cu) : 0;
{
derivedMv = neibRefPU->bv;
derivedMv += currentMv;
}
* Constructs a list of candidates for IBC AMVP (See specification, section "Derivation process for motion vector predictor candidates")
*/
void PU::fillIBCMvpCand(PredictionUnit &pu, AMVPInfo &amvpInfo)
{
AMVPInfo *pInfo = &amvpInfo;
pInfo->numCand = 0;
MergeCtx mergeCtx;
PU::getIBCMergeCandidates(pu, mergeCtx, AMVP_MAX_NUM_CANDS - 1);
int candIdx = 0;
while (pInfo->numCand < AMVP_MAX_NUM_CANDS)
{
pInfo->mvCand[pInfo->numCand] = mergeCtx.mvFieldNeighbours[(candIdx << 1) + 0].mv;;
pInfo->numCand++;
candIdx++;
}

Karsten Suehring
committed
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
/** Constructs a list of candidates for AMVP (See specification, section "Derivation process for motion vector predictor candidates")
* \param uiPartIdx
* \param uiPartAddr
* \param eRefPicList
* \param iRefIdx
* \param pInfo
*/
void PU::fillMvpCand(PredictionUnit &pu, const RefPicList &eRefPicList, const int &refIdx, AMVPInfo &amvpInfo)
{
CodingStructure &cs = *pu.cs;
AMVPInfo *pInfo = &amvpInfo;
pInfo->numCand = 0;
if (refIdx < 0)
{
return;
}
//-- Get Spatial MV
Position posLT = pu.Y().topLeft();
Position posRT = pu.Y().topRight();
Position posLB = pu.Y().bottomLeft();
{
bool bAdded = addMVPCandUnscaled( pu, eRefPicList, refIdx, posLB, MD_BELOW_LEFT, *pInfo );
if( !bAdded )
{
bAdded = addMVPCandUnscaled( pu, eRefPicList, refIdx, posLB, MD_LEFT, *pInfo );
}
}
// Above predictor search
{
bool bAdded = addMVPCandUnscaled( pu, eRefPicList, refIdx, posRT, MD_ABOVE_RIGHT, *pInfo );
if( !bAdded )
{
bAdded = addMVPCandUnscaled( pu, eRefPicList, refIdx, posRT, MD_ABOVE, *pInfo );
if( !bAdded )
{
addMVPCandUnscaled( pu, eRefPicList, refIdx, posLT, MD_ABOVE_LEFT, *pInfo );
}
}
}
for( int i = 0; i < pInfo->numCand; i++ )
{
pInfo->mvCand[i].roundTransPrecInternal2Amvr(pu.cu->imv);
}

Karsten Suehring
committed
if( pInfo->numCand == 2 )
{
if( pInfo->mvCand[0] == pInfo->mvCand[1] )
{
pInfo->numCand = 1;
}
}
if (cs.picHeader->getEnableTMVPFlag() && pInfo->numCand < AMVP_MAX_NUM_CANDS && (pu.lumaSize().width + pu.lumaSize().height > 12))

Karsten Suehring
committed
{
// Get Temporal Motion Predictor
const int refIdx_Col = refIdx;
Position posRB = pu.Y().bottomRight().offset(-3, -3);
const PreCalcValues& pcv = *cs.pcv;
Position posC0;
bool C0Avail = false;
Position posC1 = pu.Y().center();
Mv cColMv;
#if JVET_O1143_MV_ACROSS_SUBPIC_BOUNDARY
bool boundaryCond = ((posRB.x + pcv.minCUWidth) < pcv.lumaWidth) && ((posRB.y + pcv.minCUHeight) < pcv.lumaHeight);
const SubPic &curSubPic = pu.cs->slice->getPPS()->getSubPicFromPos(pu.lumaPos());
if (curSubPic.getTreatedAsPicFlag())
{
boundaryCond = ((posRB.x + pcv.minCUWidth) <= curSubPic.getSubPicRight() &&
(posRB.y + pcv.minCUHeight) <= curSubPic.getSubPicBottom());
}
if (boundaryCond)
#else

Karsten Suehring
committed
if( ( ( posRB.x + pcv.minCUWidth ) < pcv.lumaWidth ) && ( ( posRB.y + pcv.minCUHeight ) < pcv.lumaHeight ) )
#endif

Karsten Suehring
committed
{
int posYInCtu = posRB.y & pcv.maxCUHeightMask;
if (posYInCtu + 4 < pcv.maxCUHeight)

Karsten Suehring
committed
{
posC0 = posRB.offset(4, 4);
C0Avail = true;
}
}
if ( ( C0Avail && getColocatedMVP( pu, eRefPicList, posC0, cColMv, refIdx_Col, false ) ) || getColocatedMVP( pu, eRefPicList, posC1, cColMv, refIdx_Col, false ) )

Karsten Suehring
committed
{
pInfo->mvCand[pInfo->numCand++] = cColMv;

Karsten Suehring
committed
}
}
if (pInfo->numCand < AMVP_MAX_NUM_CANDS)
{
const int currRefPOC = cs.slice->getRefPic(eRefPicList, refIdx)->getPOC();
addAMVPHMVPCand(pu, eRefPicList, currRefPOC, *pInfo);

Karsten Suehring
committed
if (pInfo->numCand > AMVP_MAX_NUM_CANDS)
{
pInfo->numCand = AMVP_MAX_NUM_CANDS;
}
while (pInfo->numCand < AMVP_MAX_NUM_CANDS)
{
pInfo->mvCand[pInfo->numCand] = Mv( 0, 0 );
pInfo->numCand++;
}

Karsten Suehring
committed
{

Karsten Suehring
committed
}
}
bool PU::addAffineMVPCandUnscaled( const PredictionUnit &pu, const RefPicList &refPicList, const int &refIdx, const Position &pos, const MvpDir &dir, AffineAMVPInfo &affiAMVPInfo )
{
CodingStructure &cs = *pu.cs;
const PredictionUnit *neibPU = NULL;
Position neibPos;

Karsten Suehring
committed
switch ( dir )
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
{
case MD_LEFT:
neibPos = pos.offset( -1, 0 );
break;
case MD_ABOVE:
neibPos = pos.offset( 0, -1 );
break;
case MD_ABOVE_RIGHT:
neibPos = pos.offset( 1, -1 );
break;
case MD_BELOW_LEFT:
neibPos = pos.offset( -1, 1 );
break;
case MD_ABOVE_LEFT:
neibPos = pos.offset( -1, -1 );
break;
default:
break;
}
neibPU = cs.getPURestricted( neibPos, pu, pu.chType );
if ( neibPU == NULL || !CU::isInter( *neibPU->cu ) || !neibPU->cu->affine
|| neibPU->mergeType != MRG_TYPE_DEFAULT_N
)
{
return false;
}
Mv outputAffineMv[3];
const MotionInfo& neibMi = neibPU->getMotionInfo( neibPos );
const int currRefPOC = cs.slice->getRefPic( refPicList, refIdx )->getPOC();
const RefPicList refPicList2nd = (refPicList == REF_PIC_LIST_0) ? REF_PIC_LIST_1 : REF_PIC_LIST_0;
for ( int predictorSource = 0; predictorSource < 2; predictorSource++ ) // examine the indicated reference picture list, then if not available, examine the other list.
{
const RefPicList eRefPicListIndex = (predictorSource == 0) ? refPicList : refPicList2nd;
const int neibRefIdx = neibMi.refIdx[eRefPicListIndex];
if ( ((neibPU->interDir & (eRefPicListIndex + 1)) == 0) || pu.cu->slice->getRefPOC( eRefPicListIndex, neibRefIdx ) != currRefPOC )
{
continue;
}
xInheritedAffineMv( pu, neibPU, eRefPicListIndex, outputAffineMv );
outputAffineMv[0].roundAffinePrecInternal2Amvr(pu.cu->imv);
outputAffineMv[1].roundAffinePrecInternal2Amvr(pu.cu->imv);
affiAMVPInfo.mvCandLT[affiAMVPInfo.numCand] = outputAffineMv[0];
affiAMVPInfo.mvCandRT[affiAMVPInfo.numCand] = outputAffineMv[1];
if ( pu.cu->affineType == AFFINEMODEL_6PARAM )
{
outputAffineMv[2].roundAffinePrecInternal2Amvr(pu.cu->imv);
affiAMVPInfo.mvCandLB[affiAMVPInfo.numCand] = outputAffineMv[2];
}
affiAMVPInfo.numCand++;
return true;
}
return false;
}

Karsten Suehring
committed
void PU::xInheritedAffineMv( const PredictionUnit &pu, const PredictionUnit* puNeighbour, RefPicList eRefPicList, Mv rcMv[3] )
{
int posNeiX = puNeighbour->Y().pos().x;
int posNeiY = puNeighbour->Y().pos().y;
int posCurX = pu.Y().pos().x;
int posCurY = pu.Y().pos().y;
int neiW = puNeighbour->Y().width;
int curW = pu.Y().width;
int neiH = puNeighbour->Y().height;
int curH = pu.Y().height;

Karsten Suehring
committed
Mv mvLT, mvRT, mvLB;
mvLT = puNeighbour->mvAffi[eRefPicList][0];
mvRT = puNeighbour->mvAffi[eRefPicList][1];
mvLB = puNeighbour->mvAffi[eRefPicList][2];
bool isTopCtuBoundary = false;
if ( (posNeiY + neiH) % pu.cs->sps->getCTUSize() == 0 && (posNeiY + neiH) == posCurY )
{
// use bottom-left and bottom-right sub-block MVs for inheritance
const Position posRB = puNeighbour->Y().bottomRight();
const Position posLB = puNeighbour->Y().bottomLeft();
mvLT = puNeighbour->getMotionInfo( posLB ).mv[eRefPicList];
mvRT = puNeighbour->getMotionInfo( posRB ).mv[eRefPicList];
posNeiY += neiH;
isTopCtuBoundary = true;

Karsten Suehring
committed
int shift = MAX_CU_DEPTH;
int iDMvHorX, iDMvHorY, iDMvVerX, iDMvVerY;