Newer
Older
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);
distParam.cur = singleMergeTempBuffer->Y();
LI JINGYA
committed
#if JVET_M0823_MMVD_ENCOPT
pu.mmvdEncOptMode = (refineStep > 2 ? 2 : 1);
#endif
m_pcInterSearch->motionCompensation(pu, *singleMergeTempBuffer);
LI JINGYA
committed
#if JVET_M0823_MMVD_ENCOPT
pu.mmvdEncOptMode = 0;
#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
}
}
const uint32_t iteration = encTestMode.lossless ? 1 : 2;
// 2. Pass: check candidates using full RD test
for( uint32_t uiNoResidualPass = 0; uiNoResidualPass < iteration; uiNoResidualPass++ )
{
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( mrgTempBufSet )
{
{
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());
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
{
m_pcInterSearch->motionCompensation( pu );
}
if (!cu.mmvdSkip && !pu.mhIntraFlag && uiNoResidualPass != 0)
{
CHECK(uiMergeCand >= mergeCtx.numValidMergeCand, "out of normal merge");
isTestSkipMerge[uiMergeCand] = true;
}
#if JVET_M0464_UNI_MTS
xEncodeInterResidual( tempCS, bestCS, partitioner, encTestMode, uiNoResidualPass, NULL, uiNoResidualPass == 0 ? &candHasNoResidual[uiMrgHADIdx] : NULL );
#else
xEncodeInterResidual(tempCS, bestCS, partitioner, encTestMode, uiNoResidualPass
, NULL
, 1
, uiNoResidualPass == 0 ? &candHasNoResidual[uiMrgHADIdx] : NULL);
if( m_pcEncCfg->getUseFastDecisionForMerge() && !bestIsSkip && !pu.mhIntraFlag)

Karsten Suehring
committed
2279
2280
2281
2282
2283
2284
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
{
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();
}
}
}
}
}
}
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 );
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 );
}
{
const uint8_t iteration = encTestMode.lossless ? 1 : 2;
for( uint8_t noResidualPass = 0; noResidualPass < iteration; noResidualPass++ )
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;
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);
}
}
}

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;
}
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
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654
2655
2656
2657
2658
2659
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
2692
2693
2694
2695
2696
2697
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
2733
2734
2735
2736
2737
2738
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748
2749
2750
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> * nullList = nullptr;
updateCandList( uiMergeCand, cost, RdModeList, candCostList
, *nullList, -1
, uiNumMrgSATDCand );
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
2775
2776
2777
2778
2779
2780
2781
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
2817
2818
2819
2820
2821
2822
2823
2824
2825
2826
2827
2828
2829
2830
2831
2832
2833
2834
2835
2836
2837
2838
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++ )
{
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) );
2844
2845
2846
2847
2848
2849
2850
2851
2852
2853
2854
2855
2856
2857
2858
2859
2860
2861
2862
2863
2864
2865
2866
2867
2868
2869
2870
2871
2872
2873
2874
2875
2876
2877
2878
2879
2880
2881
2882
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();
}
}
}
}
}

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.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;
cu.mmvdSkip = false;
pu.mmvdMergeFlag = false;
cu.triangle = false;
#if JVET_M0170_MRG_SHARELIST
pu.shareParentPos = tempCS->sharedBndPos;
pu.shareParentSize = tempCS->sharedBndSize;
#endif
2926
2927
2928
2929
2930
2931
2932
2933
2934
2935
2936
2937
2938
2939
2940
2941
2942
2943
2944
2945
2946
2947
2948
2949
2950
2951
2952
2953
2954
2955
2956
2957
2958
2959
PU::getInterMergeCandidates(pu, mergeCtx
, 0
);
}
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.predMode = MODE_INTER;
2961
2962
2963
2964
2965
2966
2967
2968
2969
2970
2971
2972
2973
2974
2975
2976
2977
2978
2979
2980
2981
2982
2983
2984
2985
2986
2987
2988
2989
2990
2991
2992
2993
2994
2995
2996
2997
2998
2999
3000
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;
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;
}
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