Newer
Older
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
3030
3031
3032
3033
3034
3035
3036
3037
3038
3039
3040
3041
3042
3043
3044
3045
3046
3047
3048
3049
3050
3051
3052
3053
3054
3055
3056
3057
3058
3059
3060
3061
3062
3063
3064
3065
3066
3067
3068
3069
3070
3071
3072
3073
3074
3075
3076
3077
3078
3079
3080
3081
3082
3083
3084
3085
3086
3087
3088
3089
3090
3091
3092
3093
3094
3095
3096
3097
3098
3099
3100
3101
3102
3103
3104
3105
3106
3107
3108
3109
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
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
3142
3143
3144
3145
3146
3147
3148
3149
3150
3151
3152
3153
3154
3155
3156
3157
3158
3159
3160
3161
3162
3163
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
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
3218
3219
3220
3221
3222
3223
3224
3225
3226
3227
3228
3229
3230
3231
{
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 JVET_M0445_MCTS
if( m_pcEncCfg->getMCTSEncConstraint() && ( !( MCTSHelper::checkMvBufferForMCTSConstraint( *cu.firstPU ) ) ) )
{
// Do not use this mode
tempCS->initStructData( encTestMode.qp, encTestMode.lossless );
return;
}
#endif
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) );
3254
3255
3256
3257
3258
3259
3260
3261
3262
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
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
);
3353
3354
3355
3356
3357
3358
3359
3360
3361
3362
3363
3364
3365
3366
3367
3368
3369
3370
3371
3372
3373
3374
3375
3376
3377
3378
3379
3380
3381
3382
}
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;
}
3431
3432
3433
3434
3435
3436
3437
3438
3439
3440
3441
3442
3443
3444
3445
3446
3447
3448
3449
3450
3451
3452
3453
3454
3455
3456
3457
3458
3459
3460
3461
3462
3463
3464
3465
3466
3467
3468
3469
3470
3471
3472
3473
3474
3475
3476
3477
3478
3479
3480
3481
3482
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);
3748
3749
3750
3751
3752
3753
3754
3755
3756
3757
3758
3759
3760
3761
3762
3763
3764
3765
3766
3767
3768
3769
3770
3771
3772
3773
//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);
3800
3801
3802
3803
3804
3805
3806
3807
3808
3809
3810
3811
3812
3813
3814
3815
3816
3817
3818
3819
3820
3821
3822
3823
3824
3825
3826
3827
3828
3829
3830
3831
3832
3833
// 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
3896
3897
3898
3899
3900
3901
3902
3903
3904
3905
3906
3907
3908
3909
3910
3911
3912
3913
3914
3915
3916
3917
3918
3919
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;
cu.mmvdSkip = false;

Karsten Suehring
committed
//cu.affine
cu.predMode = MODE_INTER;
cu.transQuantBypass = encTestMode.lossless;
cu.chromaQpAdj = cu.transQuantBypass ? 0 : m_cuChromaQpOffsetIdxPlus1;
cu.qp = encTestMode.qp;
CU::addPUs( cu );
cu.GBiIdx = g_GbiSearchOrder[gbiLoopIdx];
uint8_t gbiIdx = cu.GBiIdx;
bool testGbi = (gbiIdx != GBI_DEFAULT);

Karsten Suehring
committed
m_pcInterSearch->predInterSearch( cu, partitioner );
const unsigned wIdx = gp_sizeIdxInfo->idxFrom( tempCS->area.lwidth () );
gbiIdx = CU::getValidGbiIdx(cu);
if( testGbi && gbiIdx == GBI_DEFAULT ) // Enabled GBi but the search results is uni.
{
tempCS->initStructData(encTestMode.qp, encTestMode.lossless);
continue;
}
CHECK(!(testGbi || (!testGbi && gbiIdx == GBI_DEFAULT)), " !( bTestGbi || (!bTestGbi && gbiIdx == GBI_DEFAULT ) )");
bool isEqualUni = false;
if( m_pcEncCfg->getUseGBiFast() )
{
if( cu.firstPU->interDir != 3 && testGbi == 0 )
{
isEqualUni = true;
}
}
#if JVET_M0464_UNI_MTS
xEncodeInterResidual( tempCS, bestCS, partitioner, encTestMode, 0
, m_pImvTempCS ? m_pImvTempCS[wIdx] : NULL
, 0
, &equGBiCost
#else
xEncodeInterResidual( tempCS, bestCS, partitioner, encTestMode, 0
, 1
, 0
);
3976
3977
3978
3979
3980
3981
3982
3983
3984
3985
3986
3987
3988
3989
3990
3991
3992
3993
3994
3995
3996
3997
3998
3999
if( g_GbiSearchOrder[gbiLoopIdx] == GBI_DEFAULT )
m_pcInterSearch->setAffineModeSelected((bestCS->cus.front()->affine && !(bestCS->cus.front()->firstPU->mergeFlag)));
tempCS->initStructData(encTestMode.qp, encTestMode.lossless);
double skipTH = MAX_DOUBLE;
skipTH = (m_pcEncCfg->getUseGBiFast() ? 1.05 : MAX_DOUBLE);
if( equGBiCost > curBestCost * skipTH )
{
break;
}
if( m_pcEncCfg->getUseGBiFast() )
{
if( isEqualUni == true && m_pcEncCfg->getIntraPeriod() == -1 )
{
break;
}
}
if( g_GbiSearchOrder[gbiLoopIdx] == GBI_DEFAULT && xIsGBiSkip(cu) && m_pcEncCfg->getUseGBiFast() )
{
break;
}
} // for( UChar gbiLoopIdx = 0; gbiLoopIdx < gbiLoopNum; gbiLoopIdx++ )