Newer
Older
m_modeCtrl->setIsHashPerfectMatch(isPerfectMatch);
}
#endif

Karsten Suehring
committed
void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &partitioner, const EncTestMode& encTestMode )
{
const Slice &slice = *tempCS->slice;
CHECK( slice.getSliceType() == I_SLICE, "Merge modes not available for I-slices" );
tempCS->initStructData( encTestMode.qp, encTestMode.lossless );
MergeCtx mergeCtx;
const SPS &sps = *tempCS->sps;
if( sps.getSBTMVPEnabledFlag() )

Karsten Suehring
committed
{
Size bufSize = g_miScaling.scale( tempCS->area.lumaSize() );
mergeCtx.subPuMvpMiBuf = MotionBuf( m_SubPuMiBuf, bufSize );
}
#if JVET_M0147_DMVR
Mv refinedMvdL0[MAX_NUM_PARTS_IN_CTU][MRG_MAX_NUM_CANDS];
#endif
setMergeBestSATDCost( MAX_DOUBLE );

Karsten Suehring
committed
{
// 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
PredictionUnit pu( tempCS->area );
pu.cu = &cu;
pu.cs = tempCS;
#if JVET_M0170_MRG_SHARELIST
pu.shareParentPos = tempCS->sharedBndPos;
pu.shareParentSize = tempCS->sharedBndSize;
#endif
PU::getInterMergeCandidates(pu, mergeCtx
, 0
);
PU::restrictBiPredMergeCands(pu, mergeCtx);
PU::getInterMMVDMergeCandidates(pu, mergeCtx);

Karsten Suehring
committed
}
bool candHasNoResidual[MRG_MAX_NUM_CANDS + MMVD_ADD_NUM];
for (uint32_t ui = 0; ui < MRG_MAX_NUM_CANDS + MMVD_ADD_NUM; ui++)
{
candHasNoResidual[ui] = false;
}

Karsten Suehring
committed
bool bestIsSkip = false;
bool bestIsMMVDSkip = true;
PelUnitBuf acMergeBuffer[MRG_MAX_NUM_CANDS];
PelUnitBuf acMergeRealBuffer[MMVD_MRG_MAX_RD_BUF_NUM];
PelUnitBuf * acMergeTempBuffer[MMVD_MRG_MAX_RD_NUM];
PelUnitBuf * singleMergeTempBuffer;
int insertPos;
unsigned uiNumMrgSATDCand = mergeCtx.numValidMergeCand + MMVD_ADD_NUM;
static_vector<unsigned, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM> RdModeList;
bool mrgTempBufSet = false;
for (unsigned i = 0; i < MRG_MAX_NUM_CANDS + MMVD_ADD_NUM; i++)
{
RdModeList.push_back(i);
}

Karsten Suehring
committed
const UnitArea localUnitArea(tempCS->area.chromaFormat, Area(0, 0, tempCS->area.Y().width, tempCS->area.Y().height));
for (unsigned i = 0; i < MMVD_MRG_MAX_RD_BUF_NUM; i++)
{
acMergeRealBuffer[i] = m_acMergeBuffer[i].getBuf(localUnitArea);
if (i < MMVD_MRG_MAX_RD_NUM)
{
acMergeTempBuffer[i] = acMergeRealBuffer + i;
}
else
{
singleMergeTempBuffer = acMergeRealBuffer + i;
}
}
static_vector<unsigned, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM> RdModeList2; // store the Intra mode for Intrainter
RdModeList2.clear();
bool isIntrainterEnabled = sps.getUseMHIntra();
if (bestCS->area.lwidth() * bestCS->area.lheight() < 64 || bestCS->area.lwidth() >= MAX_CU_SIZE || bestCS->area.lheight() >= MAX_CU_SIZE)
{
isIntrainterEnabled = false;
}
bool isTestSkipMerge[MRG_MAX_NUM_CANDS]; // record if the merge candidate has tried skip mode
for (uint32_t idx = 0; idx < MRG_MAX_NUM_CANDS; idx++)
{
isTestSkipMerge[idx] = false;
}
if( m_pcEncCfg->getUseFastMerge() || isIntrainterEnabled)

Karsten Suehring
committed
{
uiNumMrgSATDCand = NUM_MRG_SATD_CAND;
if (isIntrainterEnabled)
{
uiNumMrgSATDCand += 1;
}

Karsten Suehring
committed
bestIsSkip = false;
if( auto blkCache = dynamic_cast< CacheBlkInfoCtrl* >( m_modeCtrl ) )
{
#if JVET_M0483_IBC
if (slice.getSPS()->getIBCFlag())
#else
if (slice.getSPS()->getIBCMode())
{
ComprCUCtx cuECtx = m_modeCtrl->getComprCUCtx();
bestIsSkip = blkCache->isSkip(tempCS->area) && cuECtx.bestCU;
}
else

Karsten Suehring
committed
bestIsSkip = blkCache->isSkip( tempCS->area );
bestIsMMVDSkip = blkCache->isMMVDSkip(tempCS->area);

Karsten Suehring
committed
}
if (isIntrainterEnabled) // always perform low complexity check
{
bestIsSkip = false;
}
static_vector<double, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM> candCostList;

Karsten Suehring
committed
// 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 );
const double sqrtLambdaForFirstPassIntra = m_pcRdCost->getMotionLambda(cu.transQuantBypass) / double(1 << SCALE_BITS);

Karsten Suehring
committed
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;
cu.triangle = false;

Karsten Suehring
committed
//cu.affine
cu.predMode = MODE_INTER;
//cu.LICFlag
cu.transQuantBypass = encTestMode.lossless;
cu.chromaQpAdj = cu.transQuantBypass ? 0 : m_cuChromaQpOffsetIdxPlus1;
cu.qp = encTestMode.qp;
//cu.emtFlag is set below
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) );

Karsten Suehring
committed
for( uint32_t uiMergeCand = 0; uiMergeCand < mergeCtx.numValidMergeCand; uiMergeCand++ )
{
if ((mergeCtx.interDirNeighbours[uiMergeCand] == 1 || mergeCtx.interDirNeighbours[uiMergeCand] == 3) && tempCS->slice->getRefPic(REF_PIC_LIST_0, mergeCtx.mvFieldNeighbours[uiMergeCand << 1].refIdx)->getPOC() == tempCS->slice->getPOC())
{

Karsten Suehring
committed
mergeCtx.setMergeInfo( pu, uiMergeCand );
PU::spanMotionInfo( pu, mergeCtx );
#if JVET_M0147_DMVR
pu.mvRefine = true;
#endif
distParam.cur = singleMergeTempBuffer->Y();
m_pcInterSearch->motionCompensation(pu, *singleMergeTempBuffer);
acMergeBuffer[uiMergeCand] = m_acRealMergeBuffer[uiMergeCand].getBuf(localUnitArea);
acMergeBuffer[uiMergeCand].copyFrom(*singleMergeTempBuffer);
#if JVET_M0147_DMVR
pu.mvRefine = false;
#endif

Karsten Suehring
committed
if( mergeCtx.interDirNeighbours[uiMergeCand] == 3 && mergeCtx.mrgTypeNeighbours[uiMergeCand] == MRG_TYPE_DEFAULT_N )
{
mergeCtx.mvFieldNeighbours[2*uiMergeCand].mv = pu.mv[0];
mergeCtx.mvFieldNeighbours[2*uiMergeCand+1].mv = pu.mv[1];
#if JVET_M0147_DMVR
{
int dx, dy, i, j, num = 0;
dy = std::min<int>(pu.lumaSize().height, DMVR_SUBCU_HEIGHT);
dx = std::min<int>(pu.lumaSize().width, DMVR_SUBCU_WIDTH);
if (PU::checkDMVRCondition(pu))
{
for (i = 0; i < (pu.lumaSize().height); i += dy)
{
for (j = 0; j < (pu.lumaSize().width); j += dx)
{
refinedMvdL0[num][uiMergeCand] = pu.mvdL0SubPu[num];
num++;
}
}
}
}
#endif

Karsten Suehring
committed
}
Distortion uiSad = distParam.distFunc(distParam);
uint32_t uiBitsCand = uiMergeCand + 1;
if( uiMergeCand == tempCS->slice->getMaxNumMergeCand() - 1 )
{
uiBitsCand--;
}
uiBitsCand++; // for mmvd_flag

Karsten Suehring
committed
double cost = (double)uiSad + (double)uiBitsCand * sqrtLambdaForFirstPass;
insertPos = -1;
updateDoubleCandList(uiMergeCand, cost, RdModeList, candCostList, RdModeList2, (uint32_t)NUM_LUMA_MODE, uiNumMrgSATDCand, &insertPos);
if (insertPos != -1)
{
if (insertPos == RdModeList.size() - 1)
{
swap(singleMergeTempBuffer, acMergeTempBuffer[insertPos]);
}
else
{
for (uint32_t i = uint32_t(RdModeList.size()) - 1; i > insertPos; i--)
{
swap(acMergeTempBuffer[i - 1], acMergeTempBuffer[i]);
}
swap(singleMergeTempBuffer, acMergeTempBuffer[insertPos]);
}
}
CHECK(std::min(uiMergeCand + 1 - ibcCand, uiNumMrgSATDCand) != RdModeList.size(), "");
#else
CHECK(std::min(uiMergeCand + 1, uiNumMrgSATDCand) != RdModeList.size(), "");
#endif

Karsten Suehring
committed
}
if (numValidMv < uiNumMrgSATDCand)
uiNumMrgSATDCand = numValidMv;
if (numValidMv == 0)
return;
if (isIntrainterEnabled)
{
int numTestIntraMode = 4;
// prepare for Intra bits calculation
const TempCtx ctxStart(m_CtxCache, m_CABACEstimator->getCtx());
const TempCtx ctxStartIntraMode(m_CtxCache, SubCtx(Ctx::MHIntraPredMode, m_CABACEstimator->getCtx()));
// for Intrainter fast, recored the best intra mode during the first round for mrege 0
int bestMHIntraMode = -1;
double bestMHIntraCost = MAX_DOUBLE;
// save the to-be-tested merge candidates
uint32_t MHIntraMergeCand[NUM_MRG_SATD_CAND];
for (uint32_t mergeCnt = 0; mergeCnt < std::min(NUM_MRG_SATD_CAND, (const int) uiNumMrgSATDCand); mergeCnt++)
for (uint32_t mergeCnt = 0; mergeCnt < std::min(NUM_MRG_SATD_CAND, (const int)mergeCtx.numValidMergeCand); mergeCnt++)
{
MHIntraMergeCand[mergeCnt] = RdModeList[mergeCnt];
}
for (uint32_t mergeCnt = 0; mergeCnt < std::min( std::min(NUM_MRG_SATD_CAND, (const int)uiNumMrgSATDCand), 4); mergeCnt++)
for (uint32_t mergeCnt = 0; mergeCnt < std::min(std::min(NUM_MRG_SATD_CAND, (const int)mergeCtx.numValidMergeCand), 4); mergeCnt++)
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
{
uint32_t mergeCand = MHIntraMergeCand[mergeCnt];
acMergeBuffer[mergeCand] = m_acRealMergeBuffer[mergeCand].getBuf(localUnitArea);
// estimate merge bits
uint32_t bitsCand = mergeCand + 1;
if (mergeCand == pu.cs->slice->getMaxNumMergeCand() - 1)
{
bitsCand--;
}
// first round
for (uint32_t intraCnt = 0; intraCnt < numTestIntraMode; intraCnt++)
{
pu.intraDir[0] = (intraCnt < 2) ? intraCnt : ((intraCnt == 2) ? HOR_IDX : VER_IDX);
// fast 2
if (mergeCnt > 0 && bestMHIntraMode != pu.intraDir[0])
{
continue;
}
int narrowCase = PU::getNarrowShape(pu.lwidth(), pu.lheight());
if (narrowCase == 1 && pu.intraDir[0] == HOR_IDX)
{
continue;
}
if (narrowCase == 2 && pu.intraDir[0] == VER_IDX)
{
continue;
}
// generate intrainter Y prediction
if (mergeCnt == 0)
{
bool isUseFilter = IntraPrediction::useFilteredIntraRefSamples(COMPONENT_Y, pu, true, pu);
m_pcIntraSearch->initIntraPatternChType(*pu.cu, pu.Y(), isUseFilter);
m_pcIntraSearch->predIntraAng(COMPONENT_Y, pu.cs->getPredBuf(pu).Y(), pu, isUseFilter);
m_pcIntraSearch->switchBuffer(pu, COMPONENT_Y, pu.cs->getPredBuf(pu).Y(), m_pcIntraSearch->getPredictorPtr2(COMPONENT_Y, intraCnt));
}
pu.cs->getPredBuf(pu).copyFrom(acMergeBuffer[mergeCand]);
#if JVET_M0427_INLOOP_RESHAPER
if (pu.cs->slice->getReshapeInfo().getUseSliceReshaper() && m_pcReshape->getCTUFlag())
{
pu.cs->getPredBuf(pu).Y().rspSignal(m_pcReshape->getFwdLUT());
}
#endif
m_pcIntraSearch->geneWeightedPred(COMPONENT_Y, pu.cs->getPredBuf(pu).Y(), pu, m_pcIntraSearch->getPredictorPtr2(COMPONENT_Y, intraCnt));
// calculate cost
#if JVET_M0427_INLOOP_RESHAPER
if (pu.cs->slice->getReshapeInfo().getUseSliceReshaper() && m_pcReshape->getCTUFlag())
{
pu.cs->getPredBuf(pu).Y().rspSignal(m_pcReshape->getInvLUT());
}
#endif
distParam.cur = pu.cs->getPredBuf(pu).Y();
Distortion sadValue = distParam.distFunc(distParam);
if (pu.cs->slice->getReshapeInfo().getUseSliceReshaper() && m_pcReshape->getCTUFlag())
{
pu.cs->getPredBuf(pu).Y().rspSignal(m_pcReshape->getFwdLUT());
}
#endif
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
m_CABACEstimator->getCtx() = SubCtx(Ctx::MHIntraPredMode, ctxStartIntraMode);
uint64_t fracModeBits = m_pcIntraSearch->xFracModeBitsIntra(pu, pu.intraDir[0], CHANNEL_TYPE_LUMA);
double cost = (double)sadValue + (double)(bitsCand + 1) * sqrtLambdaForFirstPass + (double)fracModeBits * sqrtLambdaForFirstPassIntra;
insertPos = -1;
updateDoubleCandList(mergeCand + MRG_MAX_NUM_CANDS + MMVD_ADD_NUM, cost, RdModeList, candCostList, RdModeList2, pu.intraDir[0], uiNumMrgSATDCand, &insertPos);
if (insertPos != -1)
{
for (int i = int(RdModeList.size()) - 1; i > insertPos; i--)
{
swap(acMergeTempBuffer[i - 1], acMergeTempBuffer[i]);
}
swap(singleMergeTempBuffer, acMergeTempBuffer[insertPos]);
}
// fast 2
if (mergeCnt == 0 && cost < bestMHIntraCost)
{
bestMHIntraMode = pu.intraDir[0];
bestMHIntraCost = cost;
}
}
}
m_CABACEstimator->getCtx() = ctxStart;
}
cu.mmvdSkip = true;
int tempNum = 0;
tempNum = MMVD_ADD_NUM;
LI JINGYA
committed
#if !JVET_M0823_MMVD_ENCOPT
bool allowDirection[4] = { true, true, true, true };
LI JINGYA
committed
#endif
for (uint32_t mergeCand = mergeCtx.numValidMergeCand; mergeCand < mergeCtx.numValidMergeCand + tempNum; mergeCand++)
{
const int mmvdMergeCand = mergeCand - mergeCtx.numValidMergeCand;
int bitsBaseIdx = 0;
int bitsRefineStep = 0;
int bitsDirection = 2;
int bitsCand = 0;
int baseIdx;
int refineStep;
LI JINGYA
committed
#if !JVET_M0823_MMVD_ENCOPT
int direction;
LI JINGYA
committed
#endif
baseIdx = mmvdMergeCand / MMVD_MAX_REFINE_NUM;
refineStep = (mmvdMergeCand - (baseIdx * MMVD_MAX_REFINE_NUM)) / 4;
LI JINGYA
committed
#if !JVET_M0823_MMVD_ENCOPT
direction = (mmvdMergeCand - baseIdx * MMVD_MAX_REFINE_NUM - refineStep * 4) % 4;
if (refineStep == 0)
{
allowDirection[direction] = true;
}
if (allowDirection[direction] == false)
{
continue;
}
LI JINGYA
committed
#endif
bitsBaseIdx = baseIdx + 1;
if (baseIdx == MMVD_BASE_MV_NUM - 1)
{
bitsBaseIdx--;
}
bitsRefineStep = refineStep + 1;
if (refineStep == MMVD_REFINE_STEP - 1)
{
bitsRefineStep--;
}
bitsCand = bitsBaseIdx + bitsRefineStep + bitsDirection;
bitsCand++; // for mmvd_flag
mergeCtx.setMmvdMergeCandiInfo(pu, mmvdMergeCand);
PU::spanMotionInfo(pu, mergeCtx);
#if JVET_M0147_DMVR
pu.mvRefine = true;
#endif
distParam.cur = singleMergeTempBuffer->Y();
LI JINGYA
committed
#if JVET_M0823_MMVD_ENCOPT
pu.mmvdEncOptMode = (refineStep > 2 ? 2 : 1);
CHECK(!pu.mmvdMergeFlag, "MMVD merge should be set");
// Don't do chroma MC here
m_pcInterSearch->motionCompensation(pu, *singleMergeTempBuffer, REF_PIC_LIST_X, true, false);
LI JINGYA
committed
pu.mmvdEncOptMode = 0;
#else
m_pcInterSearch->motionCompensation(pu, *singleMergeTempBuffer);
#endif
#if JVET_M0147_DMVR // store the refined MV
pu.mvRefine = false;
LI JINGYA
committed
#endif
Distortion uiSad = distParam.distFunc(distParam);
double cost = (double)uiSad + (double)bitsCand * sqrtLambdaForFirstPass;
LI JINGYA
committed
#if !JVET_M0823_MMVD_ENCOPT
allowDirection[direction] = cost > 1.3 * candCostList[0] ? 0 : 1;
LI JINGYA
committed
#endif
insertPos = -1;
updateDoubleCandList(mergeCand, cost, RdModeList, candCostList, RdModeList2, (uint32_t)NUM_LUMA_MODE, uiNumMrgSATDCand, &insertPos);
if (insertPos != -1)
{
for (int i = int(RdModeList.size()) - 1; i > insertPos; i--)
{
swap(acMergeTempBuffer[i - 1], acMergeTempBuffer[i]);
}
swap(singleMergeTempBuffer, acMergeTempBuffer[insertPos]);
}
}

Karsten Suehring
committed
// 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;
}
}
setMergeBestSATDCost( candCostList[0] );
if (isIntrainterEnabled)
{
for (uint32_t mergeCnt = 0; mergeCnt < uiNumMrgSATDCand; mergeCnt++)
{
if (RdModeList[mergeCnt] >= (MRG_MAX_NUM_CANDS + MMVD_ADD_NUM))
{
pu.intraDir[0] = RdModeList2[mergeCnt];
pu.intraDir[1] = DM_CHROMA_IDX;
uint32_t bufIdx = (pu.intraDir[0] > 1) ? (pu.intraDir[0] == HOR_IDX ? 2 : 3) : pu.intraDir[0];
bool isUseFilter = IntraPrediction::useFilteredIntraRefSamples(COMPONENT_Cb, pu, true, pu);
m_pcIntraSearch->initIntraPatternChType(*pu.cu, pu.Cb(), isUseFilter);
m_pcIntraSearch->predIntraAng(COMPONENT_Cb, pu.cs->getPredBuf(pu).Cb(), pu, isUseFilter);
m_pcIntraSearch->switchBuffer(pu, COMPONENT_Cb, pu.cs->getPredBuf(pu).Cb(), m_pcIntraSearch->getPredictorPtr2(COMPONENT_Cb, bufIdx));
isUseFilter = IntraPrediction::useFilteredIntraRefSamples(COMPONENT_Cr, pu, true, pu);
m_pcIntraSearch->initIntraPatternChType(*pu.cu, pu.Cr(), isUseFilter);
m_pcIntraSearch->predIntraAng(COMPONENT_Cr, pu.cs->getPredBuf(pu).Cr(), pu, isUseFilter);
m_pcIntraSearch->switchBuffer(pu, COMPONENT_Cr, pu.cs->getPredBuf(pu).Cr(), m_pcIntraSearch->getPredictorPtr2(COMPONENT_Cr, bufIdx));
}
}

Karsten Suehring
committed
tempCS->initStructData( encTestMode.qp, encTestMode.lossless );
}
else
{
if (bestIsMMVDSkip)
{
uiNumMrgSATDCand = mergeCtx.numValidMergeCand + MMVD_ADD_NUM;
}
else
{
uiNumMrgSATDCand = mergeCtx.numValidMergeCand;
}

Karsten Suehring
committed
}
}
#if JVET_M0428_ENC_DB_OPT
m_bestModeUpdated = tempCS->useDbCost = bestCS->useDbCost = false;
#endif

Karsten Suehring
committed
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

Karsten Suehring
committed
{
for( uint32_t uiMrgHADIdx = 0; uiMrgHADIdx < uiNumMrgSATDCand; uiMrgHADIdx++ )
{
uint32_t uiMergeCand = RdModeList[uiMrgHADIdx];
if(uiMergeCand < mergeCtx.numValidMergeCand)
if ((mergeCtx.interDirNeighbours[uiMergeCand] == 1 || mergeCtx.interDirNeighbours[uiMergeCand] == 3) && tempCS->slice->getRefPic(REF_PIC_LIST_0, mergeCtx.mvFieldNeighbours[uiMergeCand << 1].refIdx)->getPOC() == tempCS->slice->getPOC())
{
continue;
}
if (uiNoResidualPass != 0 && uiMergeCand >= (MRG_MAX_NUM_CANDS + MMVD_ADD_NUM)) // intrainter does not support skip mode
{
uiMergeCand -= (MRG_MAX_NUM_CANDS + MMVD_ADD_NUM); // for skip, map back to normal merge candidate idx and try RDO
if (isTestSkipMerge[uiMergeCand])
{
continue;
}
}
if (((uiNoResidualPass != 0) && candHasNoResidual[uiMrgHADIdx])

Karsten Suehring
committed
|| ( (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.mmvdSkip = false;
cu.triangle = false;

Karsten Suehring
committed
//cu.affine
cu.predMode = MODE_INTER;
//cu.LICFlag
cu.transQuantBypass = encTestMode.lossless;
cu.chromaQpAdj = cu.transQuantBypass ? 0 : m_cuChromaQpOffsetIdxPlus1;
cu.qp = encTestMode.qp;
PredictionUnit &pu = tempCS->addPU( cu, partitioner.chType );
if (uiNoResidualPass == 0 && uiMergeCand >= (MRG_MAX_NUM_CANDS + MMVD_ADD_NUM))
{
uiMergeCand -= (MRG_MAX_NUM_CANDS + MMVD_ADD_NUM);
cu.mmvdSkip = false;
mergeCtx.setMergeInfo(pu, uiMergeCand);
pu.intraDir[0] = RdModeList2[uiMrgHADIdx];
CHECK(pu.intraDir[0]<0 || pu.intraDir[0]>(NUM_LUMA_MODE - 1), "out of intra mode");
pu.intraDir[1] = DM_CHROMA_IDX;
}
else if (uiMergeCand >= mergeCtx.numValidMergeCand && uiMergeCand < MRG_MAX_NUM_CANDS + MMVD_ADD_NUM)
{
cu.mmvdSkip = true;
mergeCtx.setMmvdMergeCandiInfo(pu, uiMergeCand - mergeCtx.numValidMergeCand);
}
else
{
cu.mmvdSkip = false;
mergeCtx.setMergeInfo(pu, uiMergeCand);
}

Karsten Suehring
committed
PU::spanMotionInfo( pu, mergeCtx );
#if JVET_M0445_MCTS && JVET_M0147_DMVR
if( m_pcEncCfg->getMCTSEncConstraint() )
bool isDMVR = PU::checkDMVRCondition( pu );
if( ( isDMVR && MCTSHelper::isRefBlockAtRestrictedTileBoundary( pu ) ) || ( !isDMVR && !( MCTSHelper::checkMvBufferForMCTSConstraint( pu ) ) ) )
{
// Do not use this mode
tempCS->initStructData( encTestMode.qp, encTestMode.lossless );
continue;
}

Karsten Suehring
committed
if( mrgTempBufSet )
{
#if JVET_M0147_DMVR
{
int dx, dy, i, j, num = 0;
dy = std::min<int>(pu.lumaSize().height, DMVR_SUBCU_HEIGHT);
dx = std::min<int>(pu.lumaSize().width, DMVR_SUBCU_WIDTH);
if (PU::checkDMVRCondition(pu))
{
for (i = 0; i < (pu.lumaSize().height); i += dy)
{
for (j = 0; j < (pu.lumaSize().width); j += dx)
{
pu.mvdL0SubPu[num] = refinedMvdL0[num][uiMergeCand];
num++;
}
}
}
}
#endif
{
uint32_t bufIdx = (pu.intraDir[0] > 1) ? (pu.intraDir[0] == HOR_IDX ? 2 : 3) : pu.intraDir[0];
PelBuf tmpBuf = tempCS->getPredBuf(pu).Y();
tmpBuf.copyFrom(acMergeBuffer[uiMergeCand].Y());
#if JVET_M0427_INLOOP_RESHAPER
if (pu.cs->slice->getReshapeInfo().getUseSliceReshaper() && m_pcReshape->getCTUFlag())
{
tmpBuf.rspSignal(m_pcReshape->getFwdLUT());
}
#endif
m_pcIntraSearch->geneWeightedPred(COMPONENT_Y, tmpBuf, pu, m_pcIntraSearch->getPredictorPtr2(COMPONENT_Y, bufIdx));
tmpBuf = tempCS->getPredBuf(pu).Cb();
tmpBuf.copyFrom(acMergeBuffer[uiMergeCand].Cb());
m_pcIntraSearch->geneWeightedPred(COMPONENT_Cb, tmpBuf, pu, m_pcIntraSearch->getPredictorPtr2(COMPONENT_Cb, bufIdx));
tmpBuf = tempCS->getPredBuf(pu).Cr();
tmpBuf.copyFrom(acMergeBuffer[uiMergeCand].Cr());
m_pcIntraSearch->geneWeightedPred(COMPONENT_Cr, tmpBuf, pu, m_pcIntraSearch->getPredictorPtr2(COMPONENT_Cr, bufIdx));
}
else
{
LI JINGYA
committed
#if JVET_M0823_MMVD_ENCOPT
if (uiMergeCand >= mergeCtx.numValidMergeCand && uiMergeCand < MRG_MAX_NUM_CANDS + MMVD_ADD_NUM) {
pu.mmvdEncOptMode = 0;
m_pcInterSearch->motionCompensation(pu);
}
else
#endif
if (uiNoResidualPass != 0 && uiMergeCand < mergeCtx.numValidMergeCand && RdModeList[uiMrgHADIdx] >= (MRG_MAX_NUM_CANDS + MMVD_ADD_NUM))
{
tempCS->getPredBuf().copyFrom(acMergeBuffer[uiMergeCand]);
}
else
{
tempCS->getPredBuf().copyFrom(*acMergeTempBuffer[uiMrgHADIdx]);
}
}

Karsten Suehring
committed
}
else
{
#if JVET_M0147_DMVR
pu.mvRefine = true;
#endif

Karsten Suehring
committed
m_pcInterSearch->motionCompensation( pu );
#if JVET_M0147_DMVR
pu.mvRefine = false;

Karsten Suehring
committed
}
if (!cu.mmvdSkip && !pu.mhIntraFlag && uiNoResidualPass != 0)
{
CHECK(uiMergeCand >= mergeCtx.numValidMergeCand, "out of normal merge");
isTestSkipMerge[uiMergeCand] = true;
}
xEncodeInterResidual( tempCS, bestCS, partitioner, encTestMode, uiNoResidualPass, uiNoResidualPass == 0 ? &candHasNoResidual[uiMrgHADIdx] : NULL );
xEncodeInterResidual(tempCS, bestCS, partitioner, encTestMode, uiNoResidualPass
, 1
, uiNoResidualPass == 0 ? &candHasNoResidual[uiMrgHADIdx] : NULL);
if( m_pcEncCfg->getUseFastDecisionForMerge() && !bestIsSkip && !pu.mhIntraFlag)

Karsten Suehring
committed
{
#if JVET_M0445_MCTS
bestIsSkip = !bestCS->cus.empty() && bestCS->getCU( partitioner.chType )->rootCbf == 0;
#else

Karsten Suehring
committed
bestIsSkip = bestCS->getCU( partitioner.chType )->rootCbf == 0;

Karsten Suehring
committed
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
2725
2726
2727
2728
2729
2730
2731
2732
}
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 JVET_M0428_ENC_DB_OPT
if ( m_bestModeUpdated && bestCS->cost != MAX_DOUBLE )

Karsten Suehring
committed
}
void EncCu::xCheckRDCostMergeTriangle2Nx2N( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &partitioner, const EncTestMode& encTestMode )
{
const Slice &slice = *tempCS->slice;
const SPS &sps = *tempCS->sps;
CHECK( slice.getSliceType() != B_SLICE, "Triangle mode is only applied to B-slices" );
tempCS->initStructData( encTestMode.qp, encTestMode.lossless );
bool trianglecandHasNoResidual[TRIANGLE_MAX_NUM_CANDS];
for( int mergeCand = 0; mergeCand < TRIANGLE_MAX_NUM_CANDS; mergeCand++ )
bool bestIsSkip;
CodingUnit* cuTemp = bestCS->getCU(partitioner.chType);
if (cuTemp)
bestIsSkip = m_pcEncCfg->getUseFastDecisionForMerge() ? bestCS->getCU(partitioner.chType)->rootCbf == 0 : false;
else
bestIsSkip = false;
uint8_t numTriangleCandidate = TRIANGLE_MAX_NUM_CANDS;
uint8_t triangleNumMrgSATDCand = TRIANGLE_MAX_NUM_SATD_CANDS;
PelUnitBuf triangleBuffer[TRIANGLE_MAX_NUM_UNI_CANDS];
PelUnitBuf triangleWeightedBuffer[TRIANGLE_MAX_NUM_CANDS];
static_vector<uint8_t, TRIANGLE_MAX_NUM_CANDS> triangleRdModeList;
static_vector<double, TRIANGLE_MAX_NUM_CANDS> tianglecandCostList;
if( auto blkCache = dynamic_cast< CacheBlkInfoCtrl* >( m_modeCtrl ) )
{
bestIsSkip |= blkCache->isSkip( tempCS->area );
}
DistParam distParam;
const bool useHadamard = !encTestMode.lossless;
m_pcRdCost->setDistParam( distParam, tempCS->getOrgBuf().Y(), m_acMergeBuffer[0].Y(), sps.getBitDepth( CHANNEL_TYPE_LUMA ), COMPONENT_Y, useHadamard );
const UnitArea localUnitArea( tempCS->area.chromaFormat, Area( 0, 0, tempCS->area.Y().width, tempCS->area.Y().height) );
const double sqrtLambdaForFirstPass = m_pcRdCost->getMotionLambda(encTestMode.lossless);
{
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
cu.triangle = true;
cu.mmvdSkip = false;
cu.GBiIdx = GBI_DEFAULT;
PredictionUnit pu( tempCS->area );
pu.cu = &cu;
pu.cs = tempCS;
PU::getTriangleMergeCandidates( pu, triangleMrgCtx );
for( uint8_t mergeCand = 0; mergeCand < TRIANGLE_MAX_NUM_UNI_CANDS; mergeCand++ )
triangleBuffer[mergeCand] = m_acMergeBuffer[mergeCand].getBuf(localUnitArea);
triangleMrgCtx.setMergeInfo( pu, mergeCand );
PU::spanMotionInfo( pu, triangleMrgCtx );
#if JVET_M0445_MCTS
if( m_pcEncCfg->getMCTSEncConstraint() && ( !( MCTSHelper::checkMvBufferForMCTSConstraint( pu ) ) ) )
{
// Do not use this mode
tempCS->initStructData( encTestMode.qp, encTestMode.lossless );
return;
}
m_pcInterSearch->motionCompensation( pu, triangleBuffer[mergeCand] );
bool tempBufSet = bestIsSkip ? false : true;
triangleNumMrgSATDCand = bestIsSkip ? TRIANGLE_MAX_NUM_CANDS : TRIANGLE_MAX_NUM_SATD_CANDS;
if( bestIsSkip )
{
for( uint8_t i = 0; i < TRIANGLE_MAX_NUM_CANDS; i++ )
{
}
}
else
{
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.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( abs(g_aucLog2[cu.lwidth()] - g_aucLog2[cu.lheight()]) >= 2 )
}
else
{
for( uint8_t mergeCand = 0; mergeCand < numTriangleCandidate; mergeCand++ )
#if JVET_M0883_TRIANGLE_SIGNALING
bool splitDir = m_triangleModeTest[mergeCand].m_splitDir;
uint8_t candIdx0 = m_triangleModeTest[mergeCand].m_candIdx0;
uint8_t candIdx1 = m_triangleModeTest[mergeCand].m_candIdx1;
#else
bool splitDir = g_triangleCombination[mergeCand][0];
uint8_t candIdx0 = g_triangleCombination[mergeCand][1];
uint8_t candIdx1 = g_triangleCombination[mergeCand][2];
#endif
#if JVET_M0883_TRIANGLE_SIGNALING
pu.triangleSplitDir = splitDir;
pu.triangleMergeIdx0 = candIdx0;
pu.triangleMergeIdx1 = candIdx1;
#else
#endif
pu.mergeFlag = true;
triangleWeightedBuffer[mergeCand] = m_acTriangleWeightedBuffer[mergeCand].getBuf( localUnitArea );
triangleBuffer[candIdx0] = m_acMergeBuffer[candIdx0].getBuf( localUnitArea );
triangleBuffer[candIdx1] = m_acMergeBuffer[candIdx1].getBuf( localUnitArea );
#if JVET_M0328_KEEP_ONE_WEIGHT_GROUP
m_pcInterSearch->weightedTriangleBlk( pu, splitDir, CHANNEL_TYPE_LUMA, triangleWeightedBuffer[mergeCand], triangleBuffer[candIdx0], triangleBuffer[candIdx1] );
#else
m_pcInterSearch->weightedTriangleBlk( pu, PU::getTriangleWeights(pu, triangleMrgCtx, candIdx0, candIdx1), splitDir, CHANNEL_TYPE_LUMA, triangleWeightedBuffer[mergeCand], triangleBuffer[candIdx0], triangleBuffer[candIdx1] );
distParam.cur = triangleWeightedBuffer[mergeCand].Y();
Distortion uiSad = distParam.distFunc( distParam );
#if JVET_M0883_TRIANGLE_SIGNALING
uint32_t uiBitsCand = m_triangleIdxBins[splitDir][candIdx0][candIdx1];
#else
uint32_t uiBitsCand = g_triangleIdxBins[mergeCand];
#endif
double cost = (double)uiSad + (double)uiBitsCand * sqrtLambdaForFirstPass;
static_vector<int, TRIANGLE_MAX_NUM_CANDS> * nullList = nullptr;
updateCandList( mergeCand, cost, triangleRdModeList, tianglecandCostList
, *nullList, -1
, triangleNumMrgSATDCand );
// limit number of candidates using SATD-costs
for( uint8_t i = 0; i < triangleNumMrgSATDCand; i++ )
if( tianglecandCostList[i] > MRG_FAST_RATIO * tianglecandCostList[0] || tianglecandCostList[i] > getMergeBestSATDCost() )
break;
}
}
// perform chroma weighting process
for( uint8_t i = 0; i < triangleNumMrgSATDCand; i++ )
#if JVET_M0883_TRIANGLE_SIGNALING
bool splitDir = m_triangleModeTest[mergeCand].m_splitDir;
uint8_t candIdx0 = m_triangleModeTest[mergeCand].m_candIdx0;
uint8_t candIdx1 = m_triangleModeTest[mergeCand].m_candIdx1;
#else
bool splitDir = g_triangleCombination[mergeCand][0];
uint8_t candIdx0 = g_triangleCombination[mergeCand][1];
uint8_t candIdx1 = g_triangleCombination[mergeCand][2];
#endif
#if JVET_M0883_TRIANGLE_SIGNALING
pu.triangleSplitDir = splitDir;
pu.triangleMergeIdx0 = candIdx0;
pu.triangleMergeIdx1 = candIdx1;
#else
#endif
pu.mergeFlag = true;
#if JVET_M0328_KEEP_ONE_WEIGHT_GROUP
m_pcInterSearch->weightedTriangleBlk( pu, splitDir, CHANNEL_TYPE_CHROMA, triangleWeightedBuffer[mergeCand], triangleBuffer[candIdx0], triangleBuffer[candIdx1] );
#else
m_pcInterSearch->weightedTriangleBlk( pu, PU::getTriangleWeights(pu, triangleMrgCtx, candIdx0, candIdx1), splitDir, CHANNEL_TYPE_CHROMA, triangleWeightedBuffer[mergeCand], triangleBuffer[candIdx0], triangleBuffer[candIdx1] );
}
tempCS->initStructData( encTestMode.qp, encTestMode.lossless );
}
#if JVET_M0428_ENC_DB_OPT
m_bestModeUpdated = tempCS->useDbCost = bestCS->useDbCost = false;
#endif
const uint8_t iteration = encTestMode.lossless ? 1 : 2;
for( uint8_t noResidualPass = 0; noResidualPass < iteration; noResidualPass++ )
#else
uint8_t iteration;
uint8_t iterationBegin = m_modeCtrl->getIsHashPerfectMatch() ? 1 : 0;
if (encTestMode.lossless)
{
iteration = 1;
iterationBegin = 0;
}
else
{
iteration = 2;
}
for (uint8_t noResidualPass = iterationBegin; noResidualPass < iteration; ++noResidualPass)
#endif
for( uint8_t mrgHADIdx = 0; mrgHADIdx < triangleNumMrgSATDCand; mrgHADIdx++ )
uint8_t mergeCand = triangleRdModeList[mrgHADIdx];
if ( ( (noResidualPass != 0) && trianglecandHasNoResidual[mergeCand] )
|| ( (noResidualPass == 0) && bestIsSkip ) )
{
continue;
}
#if JVET_M0883_TRIANGLE_SIGNALING
bool splitDir = m_triangleModeTest[mergeCand].m_splitDir;
uint8_t candIdx0 = m_triangleModeTest[mergeCand].m_candIdx0;
uint8_t candIdx1 = m_triangleModeTest[mergeCand].m_candIdx1;
#else
bool splitDir = g_triangleCombination[mergeCand][0];
uint8_t candIdx0 = g_triangleCombination[mergeCand][1];
uint8_t candIdx1 = g_triangleCombination[mergeCand][2];
#endif
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.predMode = MODE_INTER;
cu.transQuantBypass = encTestMode.lossless;
cu.chromaQpAdj = cu.transQuantBypass ? 0 : m_cuChromaQpOffsetIdxPlus1;
cu.qp = encTestMode.qp;
cu.triangle = true;