Newer
Older

Karsten Suehring
committed
int iDMvHorX, iDMvHorY, iDMvVerX, iDMvVerY;
iDMvHorX = (mvRT - mvLT).getHor() << (shift - floorLog2(neiW));
iDMvHorY = (mvRT - mvLT).getVer() << (shift - floorLog2(neiW));
if ( puNeighbour->cu->affineType == AFFINEMODEL_6PARAM && !isTopCtuBoundary )

Karsten Suehring
committed
{
iDMvVerX = (mvLB - mvLT).getHor() << (shift - floorLog2(neiH));
iDMvVerY = (mvLB - mvLT).getVer() << (shift - floorLog2(neiH));

Karsten Suehring
committed
}
else
{
iDMvVerX = -iDMvHorY;
iDMvVerY = iDMvHorX;
}
int iMvScaleHor = mvLT.getHor() << shift;
int iMvScaleVer = mvLT.getVer() << shift;
int horTmp, verTmp;
// v0
horTmp = iMvScaleHor + iDMvHorX * (posCurX - posNeiX) + iDMvVerX * (posCurY - posNeiY);
verTmp = iMvScaleVer + iDMvHorY * (posCurX - posNeiX) + iDMvVerY * (posCurY - posNeiY);
roundAffineMv( horTmp, verTmp, shift );
rcMv[0].hor = horTmp;
rcMv[0].ver = verTmp;

Karsten Suehring
committed
// v1
horTmp = iMvScaleHor + iDMvHorX * (posCurX + curW - posNeiX) + iDMvVerX * (posCurY - posNeiY);
verTmp = iMvScaleVer + iDMvHorY * (posCurX + curW - posNeiX) + iDMvVerY * (posCurY - posNeiY);
roundAffineMv( horTmp, verTmp, shift );
rcMv[1].hor = horTmp;
rcMv[1].ver = verTmp;

Karsten Suehring
committed
// v2
if ( pu.cu->affineType == AFFINEMODEL_6PARAM )
{
horTmp = iMvScaleHor + iDMvHorX * (posCurX - posNeiX) + iDMvVerX * (posCurY + curH - posNeiY);
verTmp = iMvScaleVer + iDMvHorY * (posCurX - posNeiX) + iDMvVerY * (posCurY + curH - posNeiY);
roundAffineMv( horTmp, verTmp, shift );
rcMv[2].hor = horTmp;
rcMv[2].ver = verTmp;

Karsten Suehring
committed
}
}
void PU::fillAffineMvpCand(PredictionUnit &pu, const RefPicList &eRefPicList, const int &refIdx, AffineAMVPInfo &affiAMVPInfo)
{
affiAMVPInfo.numCand = 0;
if (refIdx < 0)
{
return;
}
// insert inherited affine candidates
Mv outputAffineMv[3];
Position posLT = pu.Y().topLeft();
Position posRT = pu.Y().topRight();
Position posLB = pu.Y().bottomLeft();
if ( !addAffineMVPCandUnscaled( pu, eRefPicList, refIdx, posLB, MD_BELOW_LEFT, affiAMVPInfo ) )
{
addAffineMVPCandUnscaled( pu, eRefPicList, refIdx, posLB, MD_LEFT, affiAMVPInfo );
}
// check above neighbor
if ( !addAffineMVPCandUnscaled( pu, eRefPicList, refIdx, posRT, MD_ABOVE_RIGHT, affiAMVPInfo ) )
{
if ( !addAffineMVPCandUnscaled( pu, eRefPicList, refIdx, posRT, MD_ABOVE, affiAMVPInfo ) )
{
addAffineMVPCandUnscaled( pu, eRefPicList, refIdx, posLT, MD_ABOVE_LEFT, affiAMVPInfo );
}
}

Karsten Suehring
committed
if ( affiAMVPInfo.numCand >= AMVP_MAX_NUM_CANDS )
{
for (int i = 0; i < affiAMVPInfo.numCand; i++)
{
affiAMVPInfo.mvCandLT[i].roundAffinePrecInternal2Amvr(pu.cu->imv);
affiAMVPInfo.mvCandRT[i].roundAffinePrecInternal2Amvr(pu.cu->imv);
affiAMVPInfo.mvCandLB[i].roundAffinePrecInternal2Amvr(pu.cu->imv);

Karsten Suehring
committed
return;
}
// insert constructed affine candidates
int cornerMVPattern = 0;
//------------------- V0 (START) -------------------//
AMVPInfo amvpInfo0;
amvpInfo0.numCand = 0;
// A->C: Above Left, Above, Left
addMVPCandUnscaled( pu, eRefPicList, refIdx, posLT, MD_ABOVE_LEFT, amvpInfo0 );

Karsten Suehring
committed
if ( amvpInfo0.numCand < 1 )
{
addMVPCandUnscaled( pu, eRefPicList, refIdx, posLT, MD_ABOVE, amvpInfo0 );

Karsten Suehring
committed
}
if ( amvpInfo0.numCand < 1 )
{
addMVPCandUnscaled( pu, eRefPicList, refIdx, posLT, MD_LEFT, amvpInfo0 );

Karsten Suehring
committed
}
cornerMVPattern = cornerMVPattern | amvpInfo0.numCand;
//------------------- V1 (START) -------------------//
AMVPInfo amvpInfo1;
amvpInfo1.numCand = 0;
// D->E: Above, Above Right
addMVPCandUnscaled( pu, eRefPicList, refIdx, posRT, MD_ABOVE, amvpInfo1 );

Karsten Suehring
committed
if ( amvpInfo1.numCand < 1 )
{
addMVPCandUnscaled( pu, eRefPicList, refIdx, posRT, MD_ABOVE_RIGHT, amvpInfo1 );

Karsten Suehring
committed
}
cornerMVPattern = cornerMVPattern | (amvpInfo1.numCand << 1);
//------------------- V2 (START) -------------------//
AMVPInfo amvpInfo2;
amvpInfo2.numCand = 0;
// F->G: Left, Below Left
addMVPCandUnscaled( pu, eRefPicList, refIdx, posLB, MD_LEFT, amvpInfo2 );

Karsten Suehring
committed
if ( amvpInfo2.numCand < 1 )
{
addMVPCandUnscaled( pu, eRefPicList, refIdx, posLB, MD_BELOW_LEFT, amvpInfo2 );

Karsten Suehring
committed
}
cornerMVPattern = cornerMVPattern | (amvpInfo2.numCand << 2);
outputAffineMv[0] = amvpInfo0.mvCand[0];
outputAffineMv[1] = amvpInfo1.mvCand[0];
outputAffineMv[2] = amvpInfo2.mvCand[0];
outputAffineMv[0].roundAffinePrecInternal2Amvr(pu.cu->imv);
outputAffineMv[1].roundAffinePrecInternal2Amvr(pu.cu->imv);
outputAffineMv[2].roundAffinePrecInternal2Amvr(pu.cu->imv);

Karsten Suehring
committed
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
if ( cornerMVPattern == 7 || (cornerMVPattern == 3 && pu.cu->affineType == AFFINEMODEL_4PARAM) )
{
affiAMVPInfo.mvCandLT[affiAMVPInfo.numCand] = outputAffineMv[0];
affiAMVPInfo.mvCandRT[affiAMVPInfo.numCand] = outputAffineMv[1];
affiAMVPInfo.mvCandLB[affiAMVPInfo.numCand] = outputAffineMv[2];
affiAMVPInfo.numCand++;
}
if ( affiAMVPInfo.numCand < 2 )
{
// check corner MVs
for ( int i = 2; i >= 0 && affiAMVPInfo.numCand < AMVP_MAX_NUM_CANDS; i-- )
{
if ( cornerMVPattern & (1 << i) ) // MV i exist
{
affiAMVPInfo.mvCandLT[affiAMVPInfo.numCand] = outputAffineMv[i];
affiAMVPInfo.mvCandRT[affiAMVPInfo.numCand] = outputAffineMv[i];
affiAMVPInfo.mvCandLB[affiAMVPInfo.numCand] = outputAffineMv[i];
affiAMVPInfo.numCand++;
}
}
// Get Temporal Motion Predictor
if ( affiAMVPInfo.numCand < 2 && pu.cs->slice->getEnableTMVPFlag() )
{
const int refIdxCol = refIdx;
Position posRB = pu.Y().bottomRight().offset( -3, -3 );
const PreCalcValues& pcv = *pu.cs->pcv;
Position posC0;
bool C0Avail = false;
Position posC1 = pu.Y().center();
Mv cColMv;
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;
}
}
if ( ( C0Avail && getColocatedMVP( pu, eRefPicList, posC0, cColMv, refIdxCol, false ) ) || getColocatedMVP( pu, eRefPicList, posC1, cColMv, refIdxCol, false ) )
cColMv.roundAffinePrecInternal2Amvr(pu.cu->imv);
affiAMVPInfo.mvCandLT[affiAMVPInfo.numCand] = cColMv;
affiAMVPInfo.mvCandRT[affiAMVPInfo.numCand] = cColMv;
affiAMVPInfo.mvCandLB[affiAMVPInfo.numCand] = cColMv;
affiAMVPInfo.numCand++;
}
}
if ( affiAMVPInfo.numCand < 2 )
{
// add zero MV
for ( int i = affiAMVPInfo.numCand; i < AMVP_MAX_NUM_CANDS; i++ )
{
affiAMVPInfo.mvCandLT[affiAMVPInfo.numCand].setZero();
affiAMVPInfo.mvCandRT[affiAMVPInfo.numCand].setZero();
affiAMVPInfo.mvCandLB[affiAMVPInfo.numCand].setZero();
affiAMVPInfo.numCand++;
}
}
}
for (int i = 0; i < affiAMVPInfo.numCand; i++)
{
affiAMVPInfo.mvCandLT[i].roundAffinePrecInternal2Amvr(pu.cu->imv);
affiAMVPInfo.mvCandRT[i].roundAffinePrecInternal2Amvr(pu.cu->imv);
affiAMVPInfo.mvCandLB[i].roundAffinePrecInternal2Amvr(pu.cu->imv);

Karsten Suehring
committed
}
bool PU::addMVPCandUnscaled( const PredictionUnit &pu, const RefPicList &eRefPicList, const int &iRefIdx, const Position &pos, const MvpDir &eDir, AMVPInfo &info )

Karsten Suehring
committed
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
{
CodingStructure &cs = *pu.cs;
const PredictionUnit *neibPU = NULL;
Position neibPos;
switch (eDir)
{
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 ) )
{
return false;
}
const MotionInfo& neibMi = neibPU->getMotionInfo( neibPos );
const int currRefPOC = cs.slice->getRefPic( eRefPicList, iRefIdx )->getPOC();
const RefPicList eRefPicList2nd = ( eRefPicList == 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 ) ? eRefPicList : eRefPicList2nd;
const int neibRefIdx = neibMi.refIdx[eRefPicListIndex];
if( neibRefIdx >= 0 && currRefPOC == cs.slice->getRefPOC( eRefPicListIndex, neibRefIdx ) )
{
info.mvCand[info.numCand++] = neibMi.mv[eRefPicListIndex];
return true;

Karsten Suehring
committed
}
}
return false;
}
void PU::addAMVPHMVPCand(const PredictionUnit &pu, const RefPicList eRefPicList, const RefPicList eRefPicList2nd, const int currRefPOC, AMVPInfo &info, uint8_t imv)
{
const Slice &slice = *(*pu.cs).slice;
MotionInfo neibMi;
auto &lut = CU::isIBC(*pu.cu) ? pu.cs->motionLut.lutIbc : pu.cs->motionLut.lut;
int num_avai_candInLUT = (int) lut.size();
int num_allowedCand = std::min(MAX_NUM_HMVP_AVMPCANDS, num_avai_candInLUT);
for (int mrgIdx = 1; mrgIdx <= num_allowedCand; mrgIdx++)
{
if (info.numCand >= AMVP_MAX_NUM_CANDS)
{
return;
}
for (int predictorSource = 0; predictorSource < 2; predictorSource++)
{
const RefPicList eRefPicListIndex = (predictorSource == 0) ? eRefPicList : eRefPicList2nd;
const int neibRefIdx = neibMi.refIdx[eRefPicListIndex];
if (neibRefIdx >= 0 && (CU::isIBC(*pu.cu) || (currRefPOC == slice.getRefPOC(eRefPicListIndex, neibRefIdx))))
{
Mv pmv = neibMi.mv[eRefPicListIndex];
info.mvCand[info.numCand++] = pmv;
if (info.numCand >= AMVP_MAX_NUM_CANDS)
{
return;
}

Karsten Suehring
committed
bool PU::isBipredRestriction(const PredictionUnit &pu)
{
if(pu.cu->lumaSize().width == 4 && pu.cu->lumaSize().height ==4 )
{
return true;
}
/* disable bi-prediction for 4x8/8x4 */
if ( pu.cu->lumaSize().width + pu.cu->lumaSize().height == 12 )
{
return true;
}

Karsten Suehring
committed
return false;
}
void PU::getAffineControlPointCand(const PredictionUnit &pu, MotionInfo mi[4], bool isAvailable[4], int verIdx[4], int8_t gbiIdx, int modelIdx, int verNum, AffineMergeCtx& affMrgType)
{
int cuW = pu.Y().width;
int cuH = pu.Y().height;
int vx, vy;
int shift = MAX_CU_DEPTH;
int shiftHtoW = shift + floorLog2(cuW) - floorLog2(cuH);
// motion info
Mv cMv[2][4];
int refIdx[2] = { -1, -1 };
int dir = 0;
EAffineModel curType = (verNum == 2) ? AFFINEMODEL_4PARAM : AFFINEMODEL_6PARAM;

Karsten Suehring
committed
if ( verNum == 2 )
{
int idx0 = verIdx[0], idx1 = verIdx[1];
if ( !isAvailable[idx0] || !isAvailable[idx1] )
{
return;
}
for ( int l = 0; l < 2; l++ )
{
if ( mi[idx0].refIdx[l] >= 0 && mi[idx1].refIdx[l] >= 0 )
{
// check same refidx and different mv
if ( mi[idx0].refIdx[l] == mi[idx1].refIdx[l])
{
dir |= (l + 1);
refIdx[l] = mi[idx0].refIdx[l];
}
}
}
}
else if ( verNum == 3 )
{
int idx0 = verIdx[0], idx1 = verIdx[1], idx2 = verIdx[2];
if ( !isAvailable[idx0] || !isAvailable[idx1] || !isAvailable[idx2] )
{
return;
}
for ( int l = 0; l < 2; l++ )
{
if ( mi[idx0].refIdx[l] >= 0 && mi[idx1].refIdx[l] >= 0 && mi[idx2].refIdx[l] >= 0 )
{
// check same refidx and different mv
if ( mi[idx0].refIdx[l] == mi[idx1].refIdx[l] && mi[idx0].refIdx[l] == mi[idx2].refIdx[l])
{
dir |= (l + 1);
refIdx[l] = mi[idx0].refIdx[l];
}
}
}
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
}
if ( dir == 0 )
{
return;
}
for ( int l = 0; l < 2; l++ )
{
if ( dir & (l + 1) )
{
for ( int i = 0; i < verNum; i++ )
{
cMv[l][verIdx[i]] = mi[verIdx[i]].mv[l];
}
// convert to LT, RT[, [LB]]
switch ( modelIdx )
{
case 0: // 0 : LT, RT, LB
break;
case 1: // 1 : LT, RT, RB
cMv[l][2].hor = cMv[l][3].hor + cMv[l][0].hor - cMv[l][1].hor;
cMv[l][2].ver = cMv[l][3].ver + cMv[l][0].ver - cMv[l][1].ver;
break;
case 2: // 2 : LT, LB, RB
cMv[l][1].hor = cMv[l][3].hor + cMv[l][0].hor - cMv[l][2].hor;
cMv[l][1].ver = cMv[l][3].ver + cMv[l][0].ver - cMv[l][2].ver;
break;
case 3: // 3 : RT, LB, RB
cMv[l][0].hor = cMv[l][1].hor + cMv[l][2].hor - cMv[l][3].hor;
cMv[l][0].ver = cMv[l][1].ver + cMv[l][2].ver - cMv[l][3].ver;
break;
case 4: // 4 : LT, RT
break;
case 5: // 5 : LT, LB
vx = (cMv[l][0].hor << shift) + ((cMv[l][2].ver - cMv[l][0].ver) << shiftHtoW);
vy = (cMv[l][0].ver << shift) - ((cMv[l][2].hor - cMv[l][0].hor) << shiftHtoW);
roundAffineMv( vx, vy, shift );
cMv[l][1].set( vx, vy );
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
break;
default:
CHECK( 1, "Invalid model index!\n" );
break;
}
}
else
{
for ( int i = 0; i < 4; i++ )
{
cMv[l][i].hor = 0;
cMv[l][i].ver = 0;
}
}
}
for ( int i = 0; i < 3; i++ )
{
affMrgType.mvFieldNeighbours[(affMrgType.numValidMergeCand << 1) + 0][i].mv = cMv[0][i];
affMrgType.mvFieldNeighbours[(affMrgType.numValidMergeCand << 1) + 0][i].refIdx = refIdx[0];
affMrgType.mvFieldNeighbours[(affMrgType.numValidMergeCand << 1) + 1][i].mv = cMv[1][i];
affMrgType.mvFieldNeighbours[(affMrgType.numValidMergeCand << 1) + 1][i].refIdx = refIdx[1];
}
affMrgType.interDirNeighbours[affMrgType.numValidMergeCand] = dir;
affMrgType.affineType[affMrgType.numValidMergeCand] = curType;
Naeri Park
committed
affMrgType.GBiIdx[affMrgType.numValidMergeCand] = (dir == 3) ? gbiIdx : GBI_DEFAULT;
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
affMrgType.numValidMergeCand++;
return;
}
const int getAvailableAffineNeighboursForLeftPredictor( const PredictionUnit &pu, const PredictionUnit* npu[] )
{
const Position posLB = pu.Y().bottomLeft();
int num = 0;
const PredictionUnit *puLeftBottom = pu.cs->getPURestricted( posLB.offset( -1, 1 ), pu, pu.chType );
if ( puLeftBottom && puLeftBottom->cu->affine
&& puLeftBottom->mergeType == MRG_TYPE_DEFAULT_N
)
{
npu[num++] = puLeftBottom;
return num;
}
const PredictionUnit* puLeft = pu.cs->getPURestricted( posLB.offset( -1, 0 ), pu, pu.chType );
if ( puLeft && puLeft->cu->affine
&& puLeft->mergeType == MRG_TYPE_DEFAULT_N
)
{
npu[num++] = puLeft;
return num;
}
return num;
}
const int getAvailableAffineNeighboursForAbovePredictor( const PredictionUnit &pu, const PredictionUnit* npu[], int numAffNeighLeft )
{
const Position posLT = pu.Y().topLeft();
const Position posRT = pu.Y().topRight();
int num = numAffNeighLeft;
const PredictionUnit* puAboveRight = pu.cs->getPURestricted( posRT.offset( 1, -1 ), pu, pu.chType );
if ( puAboveRight && puAboveRight->cu->affine
&& puAboveRight->mergeType == MRG_TYPE_DEFAULT_N
)
{
npu[num++] = puAboveRight;
return num;
}
const PredictionUnit* puAbove = pu.cs->getPURestricted( posRT.offset( 0, -1 ), pu, pu.chType );
if ( puAbove && puAbove->cu->affine
&& puAbove->mergeType == MRG_TYPE_DEFAULT_N
)
{
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;
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
2607
2608
2609
2610
2611
2612
2613
//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() )
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
{
///> 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[2] = { 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 );
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, false );
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, false );
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, isAvailable, model[modelIdx], ((modelIdx == 3) ? neighGbi[1] : neighGbi[0]), modelIdx, verNum[modelIdx], affMrgCtx);
2782
2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2809
2810
2811
2812
2813
2814
2815
2816
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
int deltaMvHorX, deltaMvHorY, deltaMvVerX, deltaMvVerY;
deltaMvHorX = (affRT - affLT).getHor() << (shift - floorLog2(width));
deltaMvHorY = (affRT - affLT).getVer() << (shift - floorLog2(width));

Karsten Suehring
committed
int height = pu.Y().height;
if ( pu.cu->affineType == AFFINEMODEL_6PARAM )
{
deltaMvVerX = (affLB - affLT).getHor() << (shift - floorLog2(height));
deltaMvVerY = (affLB - affLT).getVer() << (shift - floorLog2(height));

Karsten Suehring
committed
}
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
}
void clipColPos(int& posX, int& posY, const PredictionUnit& pu)
{
Position puPos = pu.lumaPos();
int log2CtuSize = floorLog2(pu.cs->sps->getCTUSize());
int ctuX = ((puPos.x >> log2CtuSize) << log2CtuSize);
int ctuY = ((puPos.y >> log2CtuSize) << log2CtuSize);
int horMax = std::min( (int)pu.cs->pps->getPicWidthInLumaSamples() - 1, ctuX + (int)pu.cs->sps->getCTUSize() + 3 );
int horMin = std::max((int)0, ctuX);
int verMax = std::min( (int)pu.cs->pps->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;
if ( count )
{
if ( (mrgCtx.interDirNeighbours[0] & (1 << REF_PIC_LIST_0)) && slice.getRefPic( REF_PIC_LIST_0, mrgCtx.mvFieldNeighbours[REF_PIC_LIST_0].refIdx ) == pColPic )
{
cTMv = mrgCtx.mvFieldNeighbours[REF_PIC_LIST_0].mv;
}
else if ( slice.isInterB() && (mrgCtx.interDirNeighbours[0] & (1 << REF_PIC_LIST_1)) && slice.getRefPic( REF_PIC_LIST_1, mrgCtx.mvFieldNeighbours[REF_PIC_LIST_1].refIdx ) == pColPic )
{
cTMv = mrgCtx.mvFieldNeighbours[REF_PIC_LIST_1].mv;
}
}

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;

Karsten Suehring
committed
// use coldir.
bool bBSlice = slice.isInterB();
Position centerPos;
bool found = false;
cTempVector = cTMv;
#if JVET_P0385_UNIFIED_MV_ROUNDING
cTempVector.changePrecision(MV_PRECISION_SIXTEENTH, MV_PRECISION_INT);
int tempX = cTempVector.getHor();
int tempY = cTempVector.getVer();
#else
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);