Newer
Older
partitioner.setCUData(cu);
cu.slice = tempCS->slice;
#if HEVC_TILES_WPP
cu.tileIdx = tempCS->picture->tileMap->getTileIdxMap( tempCS->area.lumaPos() );
#endif
cu.skip = false;
cu.predMode = MODE_INTER;
cu.transQuantBypass = encTestMode.lossless;
cu.chromaQpAdj = cu.transQuantBypass ? 0 : m_cuChromaQpOffsetIdxPlus1;
cu.qp = encTestMode.qp;
cu.triangle = true;
cu.mmvdSkip = false;
cu.GBiIdx = GBI_DEFAULT;
PredictionUnit &pu = tempCS->addPU(cu, partitioner.chType);
#if JVET_M0883_TRIANGLE_SIGNALING
pu.triangleSplitDir = splitDir;
pu.triangleMergeIdx0 = candIdx0;
pu.triangleMergeIdx1 = candIdx1;
#else
#endif
pu.mergeFlag = true;
#if JVET_M0883_TRIANGLE_SIGNALING
PU::spanTriangleMotionInfo(pu, triangleMrgCtx, splitDir, candIdx0, candIdx1 );
#else
PU::spanTriangleMotionInfo(pu, triangleMrgCtx, mergeCand, splitDir, candIdx0, candIdx1 );
#endif
tempCS->getPredBuf().copyFrom( triangleWeightedBuffer[mergeCand] );
}
else
{
triangleBuffer[candIdx0] = m_acMergeBuffer[candIdx0].getBuf( localUnitArea );
triangleBuffer[candIdx1] = m_acMergeBuffer[candIdx1].getBuf( localUnitArea );
PelUnitBuf predBuf = tempCS->getPredBuf();
#if JVET_M0328_KEEP_ONE_WEIGHT_GROUP
m_pcInterSearch->weightedTriangleBlk( pu, splitDir, MAX_NUM_CHANNEL_TYPE, predBuf, triangleBuffer[candIdx0], triangleBuffer[candIdx1] );
#else
m_pcInterSearch->weightedTriangleBlk( pu, PU::getTriangleWeights(pu, triangleMrgCtx, candIdx0, candIdx1), splitDir, MAX_NUM_CHANNEL_TYPE, predBuf, triangleBuffer[candIdx0], triangleBuffer[candIdx1] );
#if JVET_M0464_UNI_MTS
xEncodeInterResidual( tempCS, bestCS, partitioner, encTestMode, noResidualPass, NULL, ( noResidualPass == 0 ? &trianglecandHasNoResidual[mergeCand] : NULL ) );
#else
xEncodeInterResidual( tempCS, bestCS, partitioner, encTestMode, noResidualPass, NULL, true, ( (noResidualPass == 0 ) ? &trianglecandHasNoResidual[mergeCand] : NULL ) );
if (m_pcEncCfg->getUseFastDecisionForMerge() && !bestIsSkip)
{
bestIsSkip = bestCS->getCU(partitioner.chType)->rootCbf == 0;
}
tempCS->initStructData(encTestMode.qp, encTestMode.lossless);
#if JVET_M0428_ENC_DB_OPT
if ( m_bestModeUpdated && bestCS->cost != MAX_DOUBLE )

Karsten Suehring
committed
void EncCu::xCheckRDCostAffineMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &partitioner, const EncTestMode& encTestMode )
{
if( m_modeCtrl->getFastDeltaQp() )
{
return;
}
if ( bestCS->area.lumaSize().width < 8 || bestCS->area.lumaSize().height < 8 )
{
return;
}
#if JVET_M0428_ENC_DB_OPT
m_bestModeUpdated = tempCS->useDbCost = bestCS->useDbCost = false;
#endif
const Slice &slice = *tempCS->slice;
CHECK( slice.getSliceType() == I_SLICE, "Affine Merge modes not available for I-slices" );
tempCS->initStructData( encTestMode.qp, encTestMode.lossless );
AffineMergeCtx affineMergeCtx;
const SPS &sps = *tempCS->sps;
MergeCtx mrgCtx;
if ( sps.getSBTMVPEnabledFlag() )
{
Size bufSize = g_miScaling.scale( tempCS->area.lumaSize() );
mrgCtx.subPuMvpMiBuf = MotionBuf( m_SubPuMiBuf, bufSize );
affineMergeCtx.mrgCtx = &mrgCtx;
}
{
// first get merge candidates
CodingUnit cu( tempCS->area );
cu.cs = tempCS;
cu.predMode = MODE_INTER;
cu.slice = tempCS->slice;
#if HEVC_TILES_WPP
cu.tileIdx = tempCS->picture->tileMap->getTileIdxMap( tempCS->area.lumaPos() );
#endif
3110
3111
3112
3113
3114
3115
3116
3117
3118
3119
3120
3121
3122
3123
3124
3125
3126
3127
3128
3129
3130
3131
3132
3133
3134
3135
3136
3137
3138
3139
3140
3141
3142
3143
3144
3145
3146
3147
3148
3149
3150
3151
3152
3153
3154
3155
3156
3157
3158
3159
3160
3161
3162
3163
3164
3165
3166
3167
3168
3169
3170
3171
3172
3173
3174
3175
3176
3177
3178
3179
3180
3181
3182
3183
3184
3185
3186
3187
3188
3189
3190
3191
3192
3193
3194
3195
3196
3197
3198
3199
3200
3201
3202
3203
3204
3205
3206
3207
3208
3209
3210
3211
3212
3213
3214
3215
3216
3217
PredictionUnit pu( tempCS->area );
pu.cu = &cu;
pu.cs = tempCS;
PU::getAffineMergeCand( pu, affineMergeCtx );
if ( affineMergeCtx.numValidMergeCand <= 0 )
{
return;
}
}
bool candHasNoResidual[AFFINE_MRG_MAX_NUM_CANDS];
for ( uint32_t ui = 0; ui < affineMergeCtx.numValidMergeCand; ui++ )
{
candHasNoResidual[ui] = false;
}
bool bestIsSkip = false;
uint32_t uiNumMrgSATDCand = affineMergeCtx.numValidMergeCand;
PelUnitBuf acMergeBuffer[AFFINE_MRG_MAX_NUM_CANDS];
static_vector<uint32_t, AFFINE_MRG_MAX_NUM_CANDS> RdModeList;
bool mrgTempBufSet = false;
for ( uint32_t i = 0; i < AFFINE_MRG_MAX_NUM_CANDS; i++ )
{
RdModeList.push_back( i );
}
if ( m_pcEncCfg->getUseFastMerge() )
{
uiNumMrgSATDCand = std::min( NUM_AFF_MRG_SATD_CAND, affineMergeCtx.numValidMergeCand );
bestIsSkip = false;
if ( auto blkCache = dynamic_cast<CacheBlkInfoCtrl*>(m_modeCtrl) )
{
bestIsSkip = blkCache->isSkip( tempCS->area );
}
static_vector<double, AFFINE_MRG_MAX_NUM_CANDS> candCostList;
// 1. Pass: get SATD-cost for selected candidates and reduce their count
if ( !bestIsSkip )
{
RdModeList.clear();
mrgTempBufSet = true;
const double sqrtLambdaForFirstPass = m_pcRdCost->getMotionLambda( encTestMode.lossless );
CodingUnit &cu = tempCS->addCU( tempCS->area, partitioner.chType );
partitioner.setCUData( cu );
cu.slice = tempCS->slice;
#if HEVC_TILES_WPP
cu.tileIdx = tempCS->picture->tileMap->getTileIdxMap( tempCS->area.lumaPos() );
#endif
cu.skip = false;
cu.affine = true;
cu.predMode = MODE_INTER;
cu.transQuantBypass = encTestMode.lossless;
cu.chromaQpAdj = cu.transQuantBypass ? 0 : m_cuChromaQpOffsetIdxPlus1;
cu.qp = encTestMode.qp;
PredictionUnit &pu = tempCS->addPU( cu, partitioner.chType );
DistParam distParam;
const bool bUseHadamard = !encTestMode.lossless;
m_pcRdCost->setDistParam( distParam, tempCS->getOrgBuf().Y(), m_acMergeBuffer[0].Y(), sps.getBitDepth( CHANNEL_TYPE_LUMA ), COMPONENT_Y, bUseHadamard );
const UnitArea localUnitArea( tempCS->area.chromaFormat, Area( 0, 0, tempCS->area.Y().width, tempCS->area.Y().height ) );
for ( uint32_t uiMergeCand = 0; uiMergeCand < affineMergeCtx.numValidMergeCand; uiMergeCand++ )
{
acMergeBuffer[uiMergeCand] = m_acMergeBuffer[uiMergeCand].getBuf( localUnitArea );
// set merge information
pu.interDir = affineMergeCtx.interDirNeighbours[uiMergeCand];
pu.mergeFlag = true;
pu.mergeIdx = uiMergeCand;
cu.affineType = affineMergeCtx.affineType[uiMergeCand];
cu.GBiIdx = affineMergeCtx.GBiIdx[uiMergeCand];
pu.mergeType = affineMergeCtx.mergeType[uiMergeCand];
if ( pu.mergeType == MRG_TYPE_SUBPU_ATMVP )
{
pu.refIdx[0] = affineMergeCtx.mvFieldNeighbours[(uiMergeCand << 1) + 0][0].refIdx;
pu.refIdx[1] = affineMergeCtx.mvFieldNeighbours[(uiMergeCand << 1) + 1][0].refIdx;
PU::spanMotionInfo( pu, mrgCtx );
}
else
{
PU::setAllAffineMvField( pu, affineMergeCtx.mvFieldNeighbours[(uiMergeCand << 1) + 0], REF_PIC_LIST_0 );
PU::setAllAffineMvField( pu, affineMergeCtx.mvFieldNeighbours[(uiMergeCand << 1) + 1], REF_PIC_LIST_1 );
PU::spanMotionInfo( pu );
}
distParam.cur = acMergeBuffer[uiMergeCand].Y();
m_pcInterSearch->motionCompensation( pu, acMergeBuffer[uiMergeCand] );
Distortion uiSad = distParam.distFunc( distParam );
uint32_t uiBitsCand = uiMergeCand + 1;
if ( uiMergeCand == tempCS->slice->getMaxNumAffineMergeCand() - 1 )
{
uiBitsCand--;
}
double cost = (double)uiSad + (double)uiBitsCand * sqrtLambdaForFirstPass;
static_vector<int, AFFINE_MRG_MAX_NUM_CANDS> emptyList;
updateCandList( uiMergeCand, cost, RdModeList, candCostList
3222
3223
3224
3225
3226
3227
3228
3229
3230
3231
3232
3233
3234
3235
3236
3237
3238
3239
3240
3241
3242
3243
CHECK( std::min( uiMergeCand + 1, uiNumMrgSATDCand ) != RdModeList.size(), "" );
}
// Try to limit number of candidates using SATD-costs
for ( uint32_t i = 1; i < uiNumMrgSATDCand; i++ )
{
if ( candCostList[i] > MRG_FAST_RATIO * candCostList[0] )
{
uiNumMrgSATDCand = i;
break;
}
}
tempCS->initStructData( encTestMode.qp, encTestMode.lossless );
}
else
{
uiNumMrgSATDCand = affineMergeCtx.numValidMergeCand;
}
}
const uint32_t iteration = encTestMode.lossless ? 1 : 2;
// 2. Pass: check candidates using full RD test
for ( uint32_t uiNoResidualPass = 0; uiNoResidualPass < iteration; uiNoResidualPass++ )
#else
uint32_t iteration;
uint32_t iterationBegin = m_modeCtrl->getIsHashPerfectMatch() ? 1 : 0;
if (encTestMode.lossless)
{
iteration = 1;
iterationBegin = 0;
}
else
{
iteration = 2;
}
for (uint32_t uiNoResidualPass = iterationBegin; uiNoResidualPass < iteration; ++uiNoResidualPass)
#endif
3263
3264
3265
3266
3267
3268
3269
3270
3271
3272
3273
3274
3275
3276
3277
3278
3279
3280
3281
3282
3283
3284
3285
3286
3287
3288
3289
3290
3291
3292
3293
3294
3295
3296
3297
3298
3299
3300
3301
3302
3303
3304
3305
3306
3307
3308
3309
3310
3311
3312
3313
3314
3315
3316
3317
3318
3319
3320
{
for ( uint32_t uiMrgHADIdx = 0; uiMrgHADIdx < uiNumMrgSATDCand; uiMrgHADIdx++ )
{
uint32_t uiMergeCand = RdModeList[uiMrgHADIdx];
if ( ((uiNoResidualPass != 0) && candHasNoResidual[uiMergeCand])
|| ((uiNoResidualPass == 0) && bestIsSkip) )
{
continue;
}
// first get merge candidates
CodingUnit &cu = tempCS->addCU( tempCS->area, partitioner.chType );
partitioner.setCUData( cu );
cu.slice = tempCS->slice;
#if HEVC_TILES_WPP
cu.tileIdx = tempCS->picture->tileMap->getTileIdxMap( tempCS->area.lumaPos() );
#endif
cu.skip = false;
cu.affine = true;
cu.predMode = MODE_INTER;
cu.transQuantBypass = encTestMode.lossless;
cu.chromaQpAdj = cu.transQuantBypass ? 0 : m_cuChromaQpOffsetIdxPlus1;
cu.qp = encTestMode.qp;
PredictionUnit &pu = tempCS->addPU( cu, partitioner.chType );
// set merge information
pu.mergeFlag = true;
pu.mergeIdx = uiMergeCand;
pu.interDir = affineMergeCtx.interDirNeighbours[uiMergeCand];
cu.affineType = affineMergeCtx.affineType[uiMergeCand];
cu.GBiIdx = affineMergeCtx.GBiIdx[uiMergeCand];
pu.mergeType = affineMergeCtx.mergeType[uiMergeCand];
if ( pu.mergeType == MRG_TYPE_SUBPU_ATMVP )
{
pu.refIdx[0] = affineMergeCtx.mvFieldNeighbours[(uiMergeCand << 1) + 0][0].refIdx;
pu.refIdx[1] = affineMergeCtx.mvFieldNeighbours[(uiMergeCand << 1) + 1][0].refIdx;
PU::spanMotionInfo( pu, mrgCtx );
}
else
{
PU::setAllAffineMvField( pu, affineMergeCtx.mvFieldNeighbours[(uiMergeCand << 1) + 0], REF_PIC_LIST_0 );
PU::setAllAffineMvField( pu, affineMergeCtx.mvFieldNeighbours[(uiMergeCand << 1) + 1], REF_PIC_LIST_1 );
PU::spanMotionInfo( pu );
}
if ( mrgTempBufSet )
{
tempCS->getPredBuf().copyFrom( acMergeBuffer[uiMergeCand] );
}
else
{
m_pcInterSearch->motionCompensation( pu );
}
#if JVET_M0464_UNI_MTS
xEncodeInterResidual( tempCS, bestCS, partitioner, encTestMode, uiNoResidualPass, NULL, ( uiNoResidualPass == 0 ? &candHasNoResidual[uiMergeCand] : NULL ) );
#else
xEncodeInterResidual( tempCS, bestCS, partitioner, encTestMode, uiNoResidualPass, NULL, true, ((uiNoResidualPass == 0) ? &candHasNoResidual[uiMergeCand] : NULL) );
3326
3327
3328
3329
3330
3331
3332
3333
3334
3335
3336
3337
3338
3339
3340
3341
3342
3343
3344
3345
3346
3347
3348
3349
3350
3351
3352
3353
3354
3355
3356
3357
3358
3359
3360
3361
3362
3363
3364
if ( m_pcEncCfg->getUseFastDecisionForMerge() && !bestIsSkip )
{
bestIsSkip = bestCS->getCU( partitioner.chType )->rootCbf == 0;
}
tempCS->initStructData( encTestMode.qp, encTestMode.lossless );
}// end loop uiMrgHADIdx
if ( uiNoResidualPass == 0 && m_pcEncCfg->getUseEarlySkipDetection() )
{
const CodingUnit &bestCU = *bestCS->getCU( partitioner.chType );
const PredictionUnit &bestPU = *bestCS->getPU( partitioner.chType );
if ( bestCU.rootCbf == 0 )
{
if ( bestPU.mergeFlag )
{
m_modeCtrl->setEarlySkipDetected();
}
else if ( m_pcEncCfg->getMotionEstimationSearchMethod() != MESEARCH_SELECTIVE )
{
int absolute_MV = 0;
for ( uint32_t uiRefListIdx = 0; uiRefListIdx < 2; uiRefListIdx++ )
{
if ( slice.getNumRefIdx( RefPicList( uiRefListIdx ) ) > 0 )
{
absolute_MV += bestPU.mvd[uiRefListIdx].getAbsHor() + bestPU.mvd[uiRefListIdx].getAbsVer();
}
}
if ( absolute_MV == 0 )
{
m_modeCtrl->setEarlySkipDetected();
}
}
}
}
}
if ( m_bestModeUpdated && bestCS->cost != MAX_DOUBLE )
{
xCalDebCost( *bestCS, partitioner );
}

Karsten Suehring
committed
}
//////////////////////////////////////////////////////////////////////////////////////////////
// ibc merge/skip mode check
void EncCu::xCheckRDCostIBCModeMerge2Nx2N(CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &partitioner, const EncTestMode& encTestMode)
assert(tempCS->chType != CHANNEL_TYPE_CHROMA); // chroma IBC is derived
if (tempCS->area.lwidth() > IBC_MAX_CAND_SIZE || tempCS->area.lheight() > IBC_MAX_CAND_SIZE) // currently only check 32x32 and below block for ibc merge/skip
{
return;
}
const SPS &sps = *tempCS->sps;
tempCS->initStructData(encTestMode.qp, encTestMode.lossless);
MergeCtx mergeCtx;
{
Size bufSize = g_miScaling.scale(tempCS->area.lumaSize());
mergeCtx.subPuMvpMiBuf = MotionBuf(m_SubPuMiBuf, bufSize);
}
{
// first get merge candidates
CodingUnit cu(tempCS->area);
cu.cs = tempCS;
cu.slice = tempCS->slice;
#if HEVC_TILES_WPP
cu.tileIdx = tempCS->picture->tileMap->getTileIdxMap(tempCS->area.lumaPos());
#endif
PredictionUnit pu(tempCS->area);
pu.cu = &cu;
pu.cs = tempCS;
cu.mmvdSkip = false;
pu.mmvdMergeFlag = false;
cu.triangle = false;
#if JVET_M0170_MRG_SHARELIST
pu.shareParentPos = tempCS->sharedBndPos;
pu.shareParentSize = tempCS->sharedBndSize;
#endif
PU::getIBCMergeCandidates(pu, mergeCtx);
#else
PU::getInterMergeCandidates(pu, mergeCtx
, 0
);
3425
3426
3427
3428
3429
3430
3431
3432
3433
3434
3435
3436
3437
3438
3439
3440
3441
3442
3443
3444
3445
3446
3447
3448
3449
3450
3451
3452
3453
3454
}
int candHasNoResidual[MRG_MAX_NUM_CANDS];
for (unsigned int ui = 0; ui < mergeCtx.numValidMergeCand; ui++)
{
candHasNoResidual[ui] = 0;
}
bool bestIsSkip = false;
unsigned numMrgSATDCand = mergeCtx.numValidMergeCand;
static_vector<unsigned, MRG_MAX_NUM_CANDS> RdModeList(MRG_MAX_NUM_CANDS);
for (unsigned i = 0; i < MRG_MAX_NUM_CANDS; i++)
{
RdModeList[i] = i;
}
//{
static_vector<double, MRG_MAX_NUM_CANDS> candCostList(MRG_MAX_NUM_CANDS, MAX_DOUBLE);
// 1. Pass: get SATD-cost for selected candidates and reduce their count
{
const double sqrtLambdaForFirstPass = m_pcRdCost->getMotionLambda(encTestMode.lossless);
CodingUnit &cu = tempCS->addCU(CS::getArea(*tempCS, tempCS->area, (const ChannelType)partitioner.chType), (const ChannelType)partitioner.chType);
partitioner.setCUData(cu);
cu.slice = tempCS->slice;
#if HEVC_TILES_WPP
cu.tileIdx = tempCS->picture->tileMap->getTileIdxMap(tempCS->area.lumaPos());
#endif
cu.skip = false;
cu.transQuantBypass = encTestMode.lossless;
cu.chromaQpAdj = cu.transQuantBypass ? 0 : m_cuChromaQpOffsetIdxPlus1;
cu.qp = encTestMode.qp;
cu.mmvdSkip = false;
cu.triangle = false;
DistParam distParam;
const bool bUseHadamard = !encTestMode.lossless;
PredictionUnit &pu = tempCS->addPU(cu, partitioner.chType); //tempCS->addPU(cu);
pu.mmvdMergeFlag = false;
Picture* refPic = pu.cu->slice->getPic();
const CPelBuf refBuf = refPic->getRecoBuf(pu.blocks[COMPONENT_Y]);
const Pel* piRefSrch = refBuf.buf;
#if JVET_M0427_INLOOP_RESHAPER
if (tempCS->slice->getReshapeInfo().getUseSliceReshaper() && m_pcReshape->getCTUFlag())
{
const CompArea &area = cu.blocks[COMPONENT_Y];
CompArea tmpArea(COMPONENT_Y, area.chromaFormat, Position(0, 0), area.size());
PelBuf tmpLuma = m_tmpStorageLCU->getBuf(tmpArea);
tmpLuma.copyFrom(tempCS->getOrgBuf().Y());
tmpLuma.rspSignal(m_pcReshape->getFwdLUT());
m_pcRdCost->setDistParam(distParam, tmpLuma, refBuf, sps.getBitDepth(CHANNEL_TYPE_LUMA), COMPONENT_Y, bUseHadamard);
}
else
#endif
m_pcRdCost->setDistParam(distParam, tempCS->getOrgBuf().Y(), refBuf, sps.getBitDepth(CHANNEL_TYPE_LUMA), COMPONENT_Y, bUseHadamard);
int refStride = refBuf.stride;
const UnitArea localUnitArea(tempCS->area.chromaFormat, Area(0, 0, tempCS->area.Y().width, tempCS->area.Y().height));
int numValidBv = mergeCtx.numValidMergeCand;
for (unsigned int mergeCand = 0; mergeCand < mergeCtx.numValidMergeCand; mergeCand++)
{
if (mergeCtx.interDirNeighbours[mergeCand] != 1)
{
numValidBv--;
continue;
}
if (tempCS->slice->getRefPic(REF_PIC_LIST_0, mergeCtx.mvFieldNeighbours[mergeCand << 1].refIdx)->getPOC() != tempCS->slice->getPOC())
{
numValidBv--;
continue;
}
3503
3504
3505
3506
3507
3508
3509
3510
3511
3512
3513
3514
3515
3516
3517
3518
3519
3520
3521
3522
3523
3524
3525
3526
3527
3528
3529
3530
3531
3532
3533
3534
3535
3536
3537
3538
3539
3540
3541
3542
3543
3544
3545
3546
3547
3548
3549
3550
3551
3552
3553
3554
mergeCtx.setMergeInfo(pu, mergeCand); // set bv info in merge mode
const int cuPelX = pu.Y().x;
const int cuPelY = pu.Y().y;
int roiWidth = pu.lwidth();
int roiHeight = pu.lheight();
const int picWidth = pu.cs->slice->getSPS()->getPicWidthInLumaSamples();
const int picHeight = pu.cs->slice->getSPS()->getPicHeightInLumaSamples();
const unsigned int lcuWidth = pu.cs->slice->getSPS()->getMaxCUWidth();
int xPred = pu.bv.getHor();
int yPred = pu.bv.getVer();
if (!PU::isBlockVectorValid(pu, cuPelX, cuPelY, roiWidth, roiHeight, picWidth, picHeight, 0, 0, xPred, yPred, lcuWidth)) // not valid bv derived
{
numValidBv--;
continue;
}
PU::spanMotionInfo(pu, mergeCtx);
distParam.cur.buf = piRefSrch + refStride * yPred + xPred;
Distortion sad = distParam.distFunc(distParam);
unsigned int bitsCand = mergeCand + 1;
if (mergeCand == tempCS->slice->getMaxNumMergeCand() - 1)
{
bitsCand--;
}
double cost = (double)sad + (double)bitsCand * sqrtLambdaForFirstPass;
static_vector<int, MRG_MAX_NUM_CANDS> * nullList = nullptr;
updateCandList(mergeCand, cost, RdModeList, candCostList
, *nullList, -1
, numMrgSATDCand);
}
// Try to limit number of candidates using SATD-costs
if (numValidBv)
{
numMrgSATDCand = numValidBv;
for (unsigned int i = 1; i < numValidBv; i++)
{
if (candCostList[i] > MRG_FAST_RATIO*candCostList[0])
{
numMrgSATDCand = i;
break;
}
}
}
else
{
tempCS->dist = 0;
tempCS->fracBits = 0;
tempCS->cost = MAX_DOUBLE;
tempCS->initStructData(encTestMode.qp, encTestMode.lossless);
return;
}
tempCS->initStructData(encTestMode.qp, encTestMode.lossless);
}
//}
const unsigned int iteration = encTestMode.lossless ? 1 : 2;
#if JVET_M0428_ENC_DB_OPT
m_bestModeUpdated = tempCS->useDbCost = bestCS->useDbCost = false;
#endif
// 2. Pass: check candidates using full RD test
for (unsigned int numResidualPass = 0; numResidualPass < iteration; numResidualPass++)
{
for (unsigned int mrgHADIdx = 0; mrgHADIdx < numMrgSATDCand; mrgHADIdx++)
{
unsigned int mergeCand = RdModeList[mrgHADIdx];
if (mergeCtx.interDirNeighbours[mergeCand] != 1)
{
continue;
}
if (tempCS->slice->getRefPic(REF_PIC_LIST_0, mergeCtx.mvFieldNeighbours[mergeCand << 1].refIdx)->getPOC() != tempCS->slice->getPOC())
{
continue;
}
if (!(numResidualPass == 1 && candHasNoResidual[mergeCand] == 1))
{
if (!(bestIsSkip && (numResidualPass == 0)))
{
unsigned char considerEmtSecondPass = 0;
bool skipSecondEmtPass = true;
bool hasResidual[2] = { false, false };
double emtCost[2] = { MAX_DOUBLE, MAX_DOUBLE };
// CU-level optimization
for (unsigned char emtCuFlag = 0; emtCuFlag <= considerEmtSecondPass; emtCuFlag++)
{
if (m_pcEncCfg->getFastInterEMT() && emtCuFlag && skipSecondEmtPass)
{
continue;
}
// first get merge candidates
CodingUnit &cu = tempCS->addCU(CS::getArea(*tempCS, tempCS->area, (const ChannelType)partitioner.chType), (const ChannelType)partitioner.chType);
partitioner.setCUData(cu);
cu.slice = tempCS->slice;
#if HEVC_TILES_WPP
cu.tileIdx = tempCS->picture->tileMap->getTileIdxMap(tempCS->area.lumaPos());
#endif
cu.skip = false;
cu.transQuantBypass = encTestMode.lossless;
cu.chromaQpAdj = cu.transQuantBypass ? 0 : m_cuChromaQpOffsetIdxPlus1;
cu.qp = encTestMode.qp;
Yin Zhao
committed
#if JVET_M0140_SBT
cu.sbtInfo = 0;
#endif
PredictionUnit &pu = tempCS->addPU(cu, partitioner.chType);// tempCS->addPU(cu);
pu.intraDir[0] = DC_IDX; // set intra pred for ibc block
pu.intraDir[1] = PLANAR_IDX; // set intra pred for ibc block
cu.mmvdSkip = false;
pu.mmvdMergeFlag = false;
cu.triangle = false;
mergeCtx.setMergeInfo(pu, mergeCand);
PU::spanMotionInfo(pu, mergeCtx);
assert(mergeCtx.mrgTypeNeighbours[mergeCand] == MRG_TYPE_IBC); // should be IBC candidate at this round
const bool chroma = !(CS::isDualITree(*tempCS));
// MC
m_pcInterSearch->motionCompensation(pu,REF_PIC_LIST_0, true, chroma);
m_CABACEstimator->getCtx() = m_CurrCtx->start;
m_pcInterSearch->encodeResAndCalcRdInterCU(*tempCS, partitioner, (numResidualPass != 0), true, chroma);
xEncodeDontSplit(*tempCS, partitioner);

Christian Helmrich
committed
#if ENABLE_QPA_SUB_CTU
xCheckDQP (*tempCS, partitioner);
#else
// this if-check is redundant
if (tempCS->pps->getUseDQP() && (partitioner.currDepth) <= tempCS->pps->getMaxCuDQPDepth())
{
xCheckDQP(*tempCS, partitioner);
}

Christian Helmrich
committed
#endif
hasResidual[emtCuFlag] = cu.rootCbf;
emtCost[emtCuFlag] = tempCS->cost;
DTRACE_MODE_COST(*tempCS, m_pcRdCost->getLambda());
xCheckBestMode(tempCS, bestCS, partitioner, encTestMode);
tempCS->initStructData(encTestMode.qp, encTestMode.lossless);
}
if (numResidualPass == 0 && (emtCost[0] <= emtCost[1] ? !hasResidual[0] : !hasResidual[1]))
{
// If no residual when allowing for one, then set mark to not try case where residual is forced to 0
candHasNoResidual[mergeCand] = 1;
}
if (m_pcEncCfg->getUseFastDecisionForMerge() && !bestIsSkip)
{
if (bestCS->getCU(partitioner.chType) == NULL)
bestIsSkip = 0;
else
bestIsSkip = bestCS->getCU(partitioner.chType)->rootCbf == 0;
}
}
}
}
}
#if JVET_M0428_ENC_DB_OPT
if ( m_bestModeUpdated && bestCS->cost != MAX_DOUBLE )
void EncCu::xCheckRDCostIBCMode(CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &partitioner, const EncTestMode& encTestMode)
if (tempCS->area.lwidth() > IBC_MAX_CAND_SIZE || tempCS->area.lheight() > IBC_MAX_CAND_SIZE) // currently only check 32x32 and below block for ibc merge/skip
{
return;
}
tempCS->initStructData(encTestMode.qp, encTestMode.lossless);
#if JVET_M0428_ENC_DB_OPT
m_bestModeUpdated = tempCS->useDbCost = bestCS->useDbCost = false;
#endif
CodingUnit &cu = tempCS->addCU(CS::getArea(*tempCS, tempCS->area, partitioner.chType), partitioner.chType);
partitioner.setCUData(cu);
cu.slice = tempCS->slice;
#if HEVC_TILES_WPP
cu.tileIdx = tempCS->picture->tileMap->getTileIdxMap(tempCS->area.lumaPos());
#endif
cu.skip = false;
cu.transQuantBypass = encTestMode.lossless;
cu.chromaQpAdj = cu.transQuantBypass ? 0 : m_cuChromaQpOffsetIdxPlus1;
cu.qp = encTestMode.qp;
Yin Zhao
committed
#if JVET_M0140_SBT
cu.sbtInfo = 0;
#endif
#if JVET_M0428_ENC_DB_OPT
m_bestModeUpdated = tempCS->useDbCost = bestCS->useDbCost = false;
#endif
PredictionUnit& pu = *cu.firstPU;
cu.mmvdSkip = false;
pu.mmvdMergeFlag = false;
pu.intraDir[0] = DC_IDX; // set intra pred for ibc block
pu.intraDir[1] = PLANAR_IDX; // set intra pred for ibc block
pu.refIdx[REF_PIC_LIST_0] = MAX_NUM_REF; // last idx in the list
pu.refIdx[REF_PIC_LIST_0] = pu.cs->slice->getNumRefIdx(REF_PIC_LIST_0) - 1; // last idx in the list
bool bValid = m_pcInterSearch->predIBCSearch(cu, partitioner, m_ctuIbcSearchRangeX, m_ctuIbcSearchRangeY, m_ibcHashMap);
if (bValid)
{
PU::spanMotionInfo(pu);
const bool chroma = !(CS::isDualITree(*tempCS));
// MC
m_pcInterSearch->motionCompensation(pu, REF_PIC_LIST_0, true, chroma);
double bestCost = bestCS->cost;
unsigned char considerEmtSecondPass = 0;
bool skipSecondEmtPass = true;
double emtFirstPassCost = MAX_DOUBLE;
// CU-level optimization
for (unsigned char emtCuFlag = 0; emtCuFlag <= considerEmtSecondPass; emtCuFlag++)
{
if (m_pcEncCfg->getFastInterEMT() && emtCuFlag && skipSecondEmtPass)
{
continue;
}
tempCS->getCU(tempCS->chType)->emtFlag = emtCuFlag;
m_pcInterSearch->encodeResAndCalcRdInterCU(*tempCS, partitioner, false, true, chroma);
if (m_pcEncCfg->getFastInterEMT())
{
emtFirstPassCost = (!emtCuFlag) ? tempCS->cost : emtFirstPassCost;
}

Christian Helmrich
committed
#if ENABLE_QPA_SUB_CTU
xCheckDQP (*tempCS, partitioner);
#else
// this if-check is redundant
if (tempCS->pps->getUseDQP() && (partitioner.currDepth) <= tempCS->pps->getMaxCuDQPDepth())
{
xCheckDQP(*tempCS, partitioner);
}

Christian Helmrich
committed
#endif
#if JVET_M0428_ENC_DB_OPT
tempCS->useDbCost = m_pcEncCfg->getUseEncDbOpt();
if ( m_bestModeUpdated )
DTRACE_MODE_COST(*tempCS, m_pcRdCost->getLambda());
xCheckBestMode(tempCS, bestCS, partitioner, encTestMode);
3820
3821
3822
3823
3824
3825
3826
3827
3828
3829
3830
3831
3832
3833
3834
3835
3836
3837
3838
3839
3840
3841
3842
3843
3844
3845
//now we check whether the second pass should be skipped or not
if (!emtCuFlag && considerEmtSecondPass)
{
static const double thresholdToSkipEmtSecondPass = 1.1; // Skip checking EMT transforms
if (m_pcEncCfg->getFastInterEMT() && (!cu.firstTU->cbf[COMPONENT_Y] || emtFirstPassCost > bestCost * thresholdToSkipEmtSecondPass))
{
skipSecondEmtPass = true;
}
else //EMT will be checked
{
if (bestCost == bestCS->cost) //The first EMT pass didn't become the bestCS, so we clear the TUs generated
{
tempCS->clearTUs();
}
else
{
tempCS->initStructData(bestCS->currQP[bestCS->chType], bestCS->isLossless);
tempCS->copyStructure(*bestCS, partitioner.chType);
tempCS->getPredBuf().copyFrom(bestCS->getPredBuf());
}
//we need to restart the distortion for the new tempCS, the bit count and the cost
tempCS->dist = 0;
tempCS->fracBits = 0;
tempCS->cost = MAX_DOUBLE;
}
} // bValid
else
{
tempCS->dist = 0;
tempCS->fracBits = 0;
tempCS->cost = MAX_DOUBLE;
else
{
bool success = true;
// chroma tree, reuse luma bv at minimal block level
// enabled search only when each chroma sub-block has a BV from its luma sub-block
assert(tempCS->getIbcLumaCoverage(pu.Cb()) == IBC_LUMA_COVERAGE_FULL);
3872
3873
3874
3875
3876
3877
3878
3879
3880
3881
3882
3883
3884
3885
3886
3887
3888
3889
3890
3891
3892
3893
3894
3895
3896
3897
3898
3899
3900
3901
3902
3903
3904
3905
// check if each BV for the chroma sub-block is valid
//static const UInt unitArea = MIN_PU_SIZE * MIN_PU_SIZE;
const CompArea lumaArea = CompArea(COMPONENT_Y, pu.chromaFormat, pu.Cb().lumaPos(), recalcSize(pu.chromaFormat, CHANNEL_TYPE_CHROMA, CHANNEL_TYPE_LUMA, pu.Cb().size()));
PredictionUnit subPu;
subPu.cs = pu.cs;
subPu.cu = pu.cu;
const ComponentID compID = COMPONENT_Cb; // use Cb to represent both Cb and CR, as their structures are the same
int shiftHor = ::getComponentScaleX(compID, pu.chromaFormat);
int shiftVer = ::getComponentScaleY(compID, pu.chromaFormat);
//const ChromaFormat chFmt = pu.chromaFormat;
for (int y = lumaArea.y; y < lumaArea.y + lumaArea.height; y += MIN_PU_SIZE)
{
for (int x = lumaArea.x; x < lumaArea.x + lumaArea.width; x += MIN_PU_SIZE)
{
const MotionInfo &curMi = pu.cs->picture->cs->getMotionInfo(Position{ x, y });
subPu.UnitArea::operator=(UnitArea(pu.chromaFormat, Area(x, y, MIN_PU_SIZE, MIN_PU_SIZE)));
Position offsetRef = subPu.blocks[compID].pos().offset((curMi.bv.getHor() >> shiftHor), (curMi.bv.getVer() >> shiftVer));
Position refEndPos(offsetRef.x + subPu.blocks[compID].size().width - 1, offsetRef.y + subPu.blocks[compID].size().height - 1 );
if (!subPu.cs->isDecomp(refEndPos, toChannelType(compID)) || !subPu.cs->isDecomp(offsetRef, toChannelType(compID))) // ref block is not yet available for this chroma sub-block
{
success = false;
break;
}
}
if (!success)
break;
}
////////////////////////////////////////////////////////////////////////////
if (success)
{
m_pcInterSearch->motionCompensation(pu, REF_PIC_LIST_0, false, true); // luma=0, chroma=1
m_pcInterSearch->encodeResAndCalcRdInterCU(*tempCS, partitioner, false, false, true);
xEncodeDontSplit(*tempCS, partitioner);
xCheckDQP(*tempCS, partitioner);
#if JVET_M0428_ENC_DB_OPT
tempCS->useDbCost = m_pcEncCfg->getUseEncDbOpt();
if ( m_bestModeUpdated )
{
xCalDebCost( *tempCS, partitioner );
}
DTRACE_MODE_COST(*tempCS, m_pcRdCost->getLambda());
xCheckBestMode(tempCS, bestCS, partitioner, encTestMode);
}
else
{
tempCS->dist = 0;
tempCS->fracBits = 0;
tempCS->cost = MAX_DOUBLE;
//////////////////////////////////////////////////////////////////////////////////////////////

Karsten Suehring
committed
void EncCu::xCheckRDCostInter( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &partitioner, const EncTestMode& encTestMode )
{
tempCS->initStructData( encTestMode.qp, encTestMode.lossless );
m_pcInterSearch->setAffineModeSelected(false);
if( tempCS->slice->getCheckLDC() )
{
m_bestGbiCost[0] = m_bestGbiCost[1] = std::numeric_limits<double>::max();
m_bestGbiIdx[0] = m_bestGbiIdx[1] = -1;
}
m_pcInterSearch->resetBufferedUniMotions();
int gbiLoopNum = (tempCS->slice->isInterB() ? GBI_NUM : 1);
gbiLoopNum = (tempCS->sps->getUseGBi() ? gbiLoopNum : 1);
if( tempCS->area.lwidth() * tempCS->area.lheight() < GBI_SIZE_CONSTRAINT )
{
gbiLoopNum = 1;
}
double curBestCost = bestCS->cost;
double equGBiCost = MAX_DOUBLE;
#if JVET_M0428_ENC_DB_OPT
m_bestModeUpdated = tempCS->useDbCost = bestCS->useDbCost = false;
#endif
3968
3969
3970
3971
3972
3973
3974
3975
3976
3977
3978
3979
3980
3981
3982
3983
3984
3985
3986
3987
3988
3989
3990
3991
for( int gbiLoopIdx = 0; gbiLoopIdx < gbiLoopNum; gbiLoopIdx++ )
{
if( m_pcEncCfg->getUseGBiFast() )
{
auto blkCache = dynamic_cast< CacheBlkInfoCtrl* >(m_modeCtrl);
if( blkCache )
{
bool isBestInter = blkCache->getInter(bestCS->area);
uint8_t bestGBiIdx = blkCache->getGbiIdx(bestCS->area);
if( isBestInter && g_GbiSearchOrder[gbiLoopIdx] != GBI_DEFAULT && g_GbiSearchOrder[gbiLoopIdx] != bestGBiIdx )
{
continue;
}
}
}
if( !tempCS->slice->getCheckLDC() )
{
if( gbiLoopIdx != 0 && gbiLoopIdx != 3 && gbiLoopIdx != 4 )
{
continue;
}
}

Karsten Suehring
committed
CodingUnit &cu = tempCS->addCU( tempCS->area, partitioner.chType );
partitioner.setCUData( cu );
cu.slice = tempCS->slice;
#if HEVC_TILES_WPP
cu.tileIdx = tempCS->picture->tileMap->getTileIdxMap( tempCS->area.lumaPos() );
#endif
cu.skip = false;