Newer
Older
const PredictionUnit* puLeft = cs.getPURestricted(posLB.offset(-1, 0), pu, pu.chType);
const bool isAvailableA1 = puLeft && isDiffMER(pu.lumaPos(), posLB.offset(-1, 0), plevel) && pu.cu != puLeft->cu && CU::isInter(*puLeft->cu);
if (isAvailableA1)
{
miLeft = puLeft->getMotionInfo(posLB.offset(-1, 0));
if (!isAvailableB1 || (miAbove != miLeft))
{
// get Inter Dir
mrgCtx.interDirNeighbours[cnt] = miLeft.interDir;
mrgCtx.useAltHpelIf[cnt] = miLeft.useAltHpelIf;
mrgCtx.BcwIdx[cnt] = (mrgCtx.interDirNeighbours[cnt] == 3) ? puLeft->cu->BcwIdx : BCW_DEFAULT;
// get Mv from Left
mrgCtx.mvFieldNeighbours[cnt << 1].setMvField(miLeft.mv[0], miLeft.refIdx[0]);
if (slice.isInterB())
{
mrgCtx.mvFieldNeighbours[(cnt << 1) + 1].setMvField(miLeft.mv[1], miLeft.refIdx[1]);
}
{
return;
}
cnt++;
}
}

Karsten Suehring
committed
// early termination
if( cnt == maxNumMergeCand )
{
return;
}
// above right
const PredictionUnit *puAboveRight = cs.getPURestricted( posRT.offset( 1, -1 ), pu, pu.chType );
bool isAvailableB0 = puAboveRight && isDiffMER( pu.lumaPos(), posRT.offset(1, -1), plevel) && CU::isInter( *puAboveRight->cu );

Karsten Suehring
committed
if( isAvailableB0 )
{
miAboveRight = puAboveRight->getMotionInfo( posRT.offset( 1, -1 ) );
if( !isAvailableB1 || ( miAbove != miAboveRight ) )
{
// get Inter Dir
mrgCtx.interDirNeighbours[cnt] = miAboveRight.interDir;
mrgCtx.useAltHpelIf[cnt] = miAboveRight.useAltHpelIf;
// get Mv from Above-right
mrgCtx.BcwIdx[cnt] = (mrgCtx.interDirNeighbours[cnt] == 3) ? puAboveRight->cu->BcwIdx : BCW_DEFAULT;

Christian Helmrich
committed
mrgCtx.mvFieldNeighbours[cnt << 1].setMvField( miAboveRight.mv[0], miAboveRight.refIdx[0] );

Karsten Suehring
committed
if( slice.isInterB() )
{
mrgCtx.mvFieldNeighbours[( cnt << 1 ) + 1].setMvField( miAboveRight.mv[1], miAboveRight.refIdx[1] );
}

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 );

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 );

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;
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)

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)
&& ((!wp0[COMPONENT_Y].bPresentFlag) && (!wp0[COMPONENT_Cb].bPresentFlag) && (!wp0[COMPONENT_Cr].bPresentFlag) && (!wp1[COMPONENT_Y].bPresentFlag) && (!wp1[COMPONENT_Cb].bPresentFlag) && (!wp1[COMPONENT_Cr].bPresentFlag))
&& ( 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
{
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;
}
}
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
1430
1431
1432
1433
1434
1435
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));
}
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
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;
}
// 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;
}

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
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
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;
rcMv.clipToStorageBitDepth();

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;
rcMv.clipToStorageBitDepth();

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;
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
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
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
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
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
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
/** 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;
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)

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 )
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
{
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];