Newer
Older

Karsten Suehring
committed
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
const bool doParallel = !m_pcEncCfg->getForceSingleSplitThread();
#if _MSC_VER && ENABLE_WPP_PARALLELISM
#pragma omp parallel for schedule(dynamic,1) num_threads(NUM_SPLIT_THREADS_IF_MSVC) if(doParallel)
#else
omp_set_num_threads( m_pcEncCfg->getNumSplitThreads() );
#pragma omp parallel for schedule(dynamic,1) if(doParallel)
#endif
for( int jId = 1; jId <= numJobs; jId++ )
{
// thread start
#if ENABLE_WPP_PARALLELISM
picture->scheduler.setWppThreadId( wppTId );
#endif
picture->scheduler.setSplitThreadId();
picture->scheduler.setSplitJobId( jId );
Partitioner* jobPartitioner = PartitionerFactory::get( *tempCS->slice );
EncCu* jobCuEnc = m_pcEncLib->getCuEncoder( picture->scheduler.getSplitDataId( jId ) );
auto* jobBlkCache = dynamic_cast<CacheBlkInfoCtrl*>( jobCuEnc->m_modeCtrl );
jobPartitioner->copyState( partitioner );
jobCuEnc ->copyState( this, *jobPartitioner, currArea, true );
if( jobBlkCache )
{
jobBlkCache->tick();
}
CodingStructure *&jobBest = jobCuEnc->m_pBestCS[wIdx][hIdx];
CodingStructure *&jobTemp = jobCuEnc->m_pTempCS[wIdx][hIdx];
jobUsed[jId] = true;
jobCuEnc->xCompressCU( jobTemp, jobBest, *jobPartitioner );
delete jobPartitioner;
picture->scheduler.setSplitJobId( 0 );
// thread stop
}
picture->scheduler.setSplitThreadId( 0 );
int bestJId = 0;
double bestCost = bestCS->cost;
for( int jId = 1; jId <= numJobs; jId++ )
{
EncCu* jobCuEnc = m_pcEncLib->getCuEncoder( picture->scheduler.getSplitDataId( jId ) );
if( jobUsed[jId] && jobCuEnc->m_pBestCS[wIdx][hIdx]->cost < bestCost )
{
bestCost = jobCuEnc->m_pBestCS[wIdx][hIdx]->cost;
bestJId = jId;
}
}
if( bestJId > 0 )
{
copyState( m_pcEncLib->getCuEncoder( picture->scheduler.getSplitDataId( bestJId ) ), partitioner, currArea, false );
m_CurrCtx->best = m_CABACEstimator->getCtx();
tempCS = m_pTempCS[wIdx][hIdx];
bestCS = m_pBestCS[wIdx][hIdx];
}
const int bitDepthY = tempCS->sps->getBitDepth( CH_L );
const UnitArea clipdArea = clipArea( currArea, *picture );
CHECK( calcCheckSum( picture->getRecoBuf( clipdArea.Y() ), bitDepthY ) != calcCheckSum( bestCS->getRecoBuf( clipdArea.Y() ), bitDepthY ), "Data copied incorrectly!" );
picture->finishParallelPart( currArea );
if( auto *blkCache = dynamic_cast<CacheBlkInfoCtrl*>( m_modeCtrl ) )
{
for( int jId = 1; jId <= numJobs; jId++ )
{
if( !jobUsed[jId] || jId == bestJId ) continue;
auto *jobBlkCache = dynamic_cast<CacheBlkInfoCtrl*>( m_pcEncLib->getCuEncoder( picture->scheduler.getSplitDataId( jId ) )->m_modeCtrl );
CHECK( !jobBlkCache, "If own mode controller has blk info cache capability so should all other mode controllers!" );
blkCache->CacheBlkInfoCtrl::copyState( *jobBlkCache, partitioner.currArea() );
}
blkCache->tick();
}
}
void EncCu::copyState( EncCu* other, Partitioner& partitioner, const UnitArea& currArea, const bool isDist )
{
const unsigned wIdx = gp_sizeIdxInfo->idxFrom( partitioner.currArea().lwidth () );
const unsigned hIdx = gp_sizeIdxInfo->idxFrom( partitioner.currArea().lheight() );
if( isDist )
{
other->m_pBestCS[wIdx][hIdx]->initSubStructure( *m_pBestCS[wIdx][hIdx], partitioner.chType, partitioner.currArea(), false );
other->m_pTempCS[wIdx][hIdx]->initSubStructure( *m_pTempCS[wIdx][hIdx], partitioner.chType, partitioner.currArea(), false );
}
else
{
CodingStructure* dst = m_pBestCS[wIdx][hIdx];
const CodingStructure *src = other->m_pBestCS[wIdx][hIdx];
bool keepResi = KEEP_PRED_AND_RESI_SIGNALS;
dst->useSubStructure( *src, partitioner.chType, currArea, KEEP_PRED_AND_RESI_SIGNALS, true, keepResi, keepResi );
dst->cost = src->cost;
dst->dist = src->dist;
dst->fracBits = src->fracBits;
dst->features = src->features;
}
if( isDist )
{
m_CurrCtx = m_CtxBuffer.data();
}
m_pcInterSearch->copyState( *other->m_pcInterSearch );
m_modeCtrl ->copyState( *other->m_modeCtrl, partitioner.currArea() );
m_pcRdCost ->copyState( *other->m_pcRdCost );
m_pcTrQuant ->copyState( *other->m_pcTrQuant );
m_CABACEstimator->getCtx() = other->m_CABACEstimator->getCtx();
}
#endif
void EncCu::xCheckModeSplit(CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &partitioner, const EncTestMode& encTestMode
, LutMotionCand* &tempMotCandLUTs
, LutMotionCand* &bestMotCandLUTs
, UnitArea parArea
)

Karsten Suehring
committed
{
const int qp = encTestMode.qp;
const PPS &pps = *tempCS->pps;
const Slice &slice = *tempCS->slice;
const bool bIsLosslessMode = false; // False at this level. Next level down may set it to true.
const int oldPrevQp = tempCS->prevQP[partitioner.chType];
const uint32_t currDepth = partitioner.currDepth;
const unsigned wParIdx = gp_sizeIdxInfo->idxFrom(parArea.lwidth());
const unsigned hParIdx = gp_sizeIdxInfo->idxFrom(parArea.lheight());
tempCS->slice->copyMotionLUTs(tempMotCandLUTs, m_pSplitTempMotLUTs[wParIdx][hParIdx]);

Karsten Suehring
committed
const PartSplit split = getPartSplit( encTestMode );
CHECK( split == CU_DONT_SPLIT, "No proper split provided!" );
tempCS->initStructData( qp, bIsLosslessMode );
m_CABACEstimator->getCtx() = m_CurrCtx->start;
const TempCtx ctxStartSP( m_CtxCache, SubCtx( Ctx::SplitFlag, m_CABACEstimator->getCtx() ) );
#if JVET_M0421_SPLIT_SIG
const TempCtx ctxStartQt( m_CtxCache, SubCtx( Ctx::SplitQtFlag, m_CABACEstimator->getCtx() ) );
const TempCtx ctxStartHv( m_CtxCache, SubCtx( Ctx::SplitHvFlag, m_CABACEstimator->getCtx() ) );
const TempCtx ctxStart12( m_CtxCache, SubCtx( Ctx::Split12Flag, m_CABACEstimator->getCtx() ) );
#else
const TempCtx ctxStartBT( m_CtxCache, SubCtx( Ctx::BTSplitFlag, m_CABACEstimator->getCtx() ) );

Karsten Suehring
committed

Karsten Suehring
committed
#if JVET_M0421_SPLIT_SIG
m_CABACEstimator->split_cu_mode( split, *tempCS, partitioner );
#else
if( partitioner.getImplicitSplit( *tempCS ) != CU_QUAD_SPLIT )
{
if( partitioner.canSplit( CU_QUAD_SPLIT, *tempCS ) )

Karsten Suehring
committed
{
m_CABACEstimator->split_cu_flag( split == CU_QUAD_SPLIT, *tempCS, partitioner );
}
if( split != CU_QUAD_SPLIT )
{
m_CABACEstimator->split_cu_mode_mt( split, *tempCS, partitioner );

Karsten Suehring
committed
}

Karsten Suehring
committed
const double factor = ( tempCS->currQP[partitioner.chType] > 30 ? 1.1 : 1.075 );
const double cost = m_pcRdCost->calcRdCost( uint64_t( m_CABACEstimator->getEstFracBits() + ( ( bestCS->fracBits ) / factor ) ), Distortion( bestCS->dist / factor ) );

Karsten Suehring
committed
m_CABACEstimator->getCtx() = SubCtx( Ctx::SplitFlag, ctxStartSP );
#if JVET_M0421_SPLIT_SIG
m_CABACEstimator->getCtx() = SubCtx( Ctx::SplitQtFlag, ctxStartQt );
m_CABACEstimator->getCtx() = SubCtx( Ctx::SplitHvFlag, ctxStartHv );
m_CABACEstimator->getCtx() = SubCtx( Ctx::Split12Flag, ctxStart12 );
#else
m_CABACEstimator->getCtx() = SubCtx( Ctx::BTSplitFlag, ctxStartBT );

Karsten Suehring
committed
if( cost > bestCS->cost )
{
xCheckBestMode( tempCS, bestCS, partitioner, encTestMode );
return;

Karsten Suehring
committed
}
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
#if JVET_M0170_MRG_SHARELIST
if (!slice.isIntra()
&& tempCS->chType == CHANNEL_TYPE_LUMA
)
{
tempCS->slice->copyMotionLUTs(tempMotCandLUTs, tempCS->slice->getMotionLUTs());
}
int startShareThisLevel = 0;
const uint32_t uiLPelX = tempCS->area.Y().lumaPos().x;
const uint32_t uiTPelY = tempCS->area.Y().lumaPos().y;
int splitRatio = 1;
CHECK(!(split == CU_QUAD_SPLIT || split == CU_HORZ_SPLIT || split == CU_VERT_SPLIT
|| split == CU_TRIH_SPLIT || split == CU_TRIV_SPLIT), "invalid split type");
splitRatio = (split == CU_HORZ_SPLIT || split == CU_VERT_SPLIT) ? 1 : 2;
bool isOneChildSmall = ((tempCS->area.lwidth())*(tempCS->area.lheight()) >> splitRatio) < MRG_SHARELIST_SHARSIZE;
if ((((tempCS->area.lwidth())*(tempCS->area.lheight())) > (MRG_SHARELIST_SHARSIZE * 1)))
{
m_shareState = NO_SHARE;
}
if (m_shareState == NO_SHARE)//init state
{
if (isOneChildSmall)
{
m_shareState = GEN_ON_SHARED_BOUND;//share start state
startShareThisLevel = 1;
}
}
if ((m_shareState == GEN_ON_SHARED_BOUND) && (!slice.isIntra()))
{
#if JVET_M0170_MRG_SHARELIST
tempCS->slice->copyMotionLUTs(tempCS->slice->getMotionLUTs(), tempCS->slice->m_MotionCandLuTsBkup);
m_shareBndPosX = uiLPelX;
m_shareBndPosY = uiTPelY;
m_shareBndSizeW = tempCS->area.lwidth();
m_shareBndSizeH = tempCS->area.lheight();
m_shareState = SHARING;
#endif
}
m_pcInterSearch->setShareState(m_shareState);
setShareStateDec(m_shareState);
#endif

Karsten Suehring
committed
partitioner.splitCurrArea( split, *tempCS );
m_CurrCtx++;
tempCS->getRecoBuf().fill( 0 );
#if JVET_M0427_INLOOP_RESHAPER
tempCS->getPredBuf().fill(0);
#endif
AffineMVInfo tmpMVInfo;
bool isAffMVInfoSaved;
m_pcInterSearch->savePrevAffMVInfo(0, tmpMVInfo, isAffMVInfoSaved);

Karsten Suehring
committed
do
{
const auto &subCUArea = partitioner.currArea();
if( tempCS->picture->Y().contains( subCUArea.lumaPos() ) )
{
const unsigned wIdx = gp_sizeIdxInfo->idxFrom( subCUArea.lwidth () );
const unsigned hIdx = gp_sizeIdxInfo->idxFrom( subCUArea.lheight() );
CodingStructure *tempSubCS = m_pTempCS[wIdx][hIdx];
CodingStructure *bestSubCS = m_pBestCS[wIdx][hIdx];
tempCS->initSubStructure( *tempSubCS, partitioner.chType, subCUArea, false );
tempCS->initSubStructure( *bestSubCS, partitioner.chType, subCUArea, false );
LutMotionCand *tempSubMotCandLUTs = m_pTempMotLUTs[wIdx][hIdx];
LutMotionCand *bestSubMotCandLUTs = m_pBestMotLUTs[wIdx][hIdx];
if (tempCS->chType == CHANNEL_TYPE_LUMA)
{
tempCS->slice->copyMotionLUTs(tempMotCandLUTs, tempSubMotCandLUTs);
tempCS->slice->copyMotionLUTs(tempMotCandLUTs, bestSubMotCandLUTs);
}
#if JVET_M0170_MRG_SHARELIST
tempSubCS->sharedBndPos.x = (m_shareState == SHARING) ? m_shareBndPosX : tempSubCS->area.Y().lumaPos().x;
tempSubCS->sharedBndPos.y = (m_shareState == SHARING) ? m_shareBndPosY : tempSubCS->area.Y().lumaPos().y;
tempSubCS->sharedBndSize.width = (m_shareState == SHARING) ? m_shareBndSizeW : tempSubCS->area.lwidth();
tempSubCS->sharedBndSize.height = (m_shareState == SHARING) ? m_shareBndSizeH : tempSubCS->area.lheight();
bestSubCS->sharedBndPos.x = (m_shareState == SHARING) ? m_shareBndPosX : tempSubCS->area.Y().lumaPos().x;
bestSubCS->sharedBndPos.y = (m_shareState == SHARING) ? m_shareBndPosY : tempSubCS->area.Y().lumaPos().y;
bestSubCS->sharedBndSize.width = (m_shareState == SHARING) ? m_shareBndSizeW : tempSubCS->area.lwidth();
bestSubCS->sharedBndSize.height = (m_shareState == SHARING) ? m_shareBndSizeH : tempSubCS->area.lheight();
#endif
xCompressCU( tempSubCS, bestSubCS, partitioner
, tempSubMotCandLUTs
, bestSubMotCandLUTs
);

Karsten Suehring
committed
if( bestSubCS->cost == MAX_DOUBLE )
{
CHECK( split == CU_QUAD_SPLIT, "Split decision reusing cannot skip quad split" );
tempCS->cost = MAX_DOUBLE;
m_CurrCtx--;
partitioner.exitCurrSplit();

Karsten Suehring
committed
xCheckBestMode( tempCS, bestCS, partitioner, encTestMode );
{
std::swap(tempMotCandLUTs, bestMotCandLUTs);
}

Karsten Suehring
committed
return;
}
bool keepResi = KEEP_PRED_AND_RESI_SIGNALS;
tempCS->useSubStructure( *bestSubCS, partitioner.chType, CS::getArea( *tempCS, subCUArea, partitioner.chType ), KEEP_PRED_AND_RESI_SIGNALS, true, keepResi, keepResi );
tempCS->slice->copyMotionLUTs(bestSubMotCandLUTs, tempMotCandLUTs);

Karsten Suehring
committed
if(currDepth < pps.getMaxCuDQPDepth())
{
tempCS->prevQP[partitioner.chType] = bestSubCS->prevQP[partitioner.chType];
}
tempSubCS->releaseIntermediateData();
bestSubCS->releaseIntermediateData();
}
} while( partitioner.nextPart( *tempCS ) );
partitioner.exitCurrSplit();
#if JVET_M0170_MRG_SHARELIST
if (startShareThisLevel == 1)
{
m_shareState = NO_SHARE;
m_pcInterSearch->setShareState(m_shareState);
setShareStateDec(m_shareState);
}
#endif

Karsten Suehring
committed
m_CurrCtx--;
// Finally, generate split-signaling bits for RD-cost check
const PartSplit implicitSplit = partitioner.getImplicitSplit( *tempCS );
{
bool enforceQT = implicitSplit == CU_QUAD_SPLIT;
#if HM_QTBT_REPRODUCE_FAST_LCTU_BUG
// LARGE CTU bug

Karsten Suehring
committed
{
unsigned minDepth = 0;
unsigned maxDepth = g_aucLog2[tempCS->sps->getCTUSize()] - g_aucLog2[tempCS->sps->getMinQTSize(slice.getSliceType(), partitioner.chType)];

Karsten Suehring
committed
if( auto ad = dynamic_cast<AdaptiveDepthPartitioner*>( &partitioner ) )
{
ad->setMaxMinDepth( minDepth, maxDepth, *tempCS );
}
if( minDepth > partitioner.currQtDepth )
{
// enforce QT
enforceQT = true;
}
}
#endif
if( !enforceQT )
{
m_CABACEstimator->resetBits();
#if JVET_M0421_SPLIT_SIG
m_CABACEstimator->split_cu_mode( split, *tempCS, partitioner );
#else

Karsten Suehring
committed
if( partitioner.canSplit( CU_QUAD_SPLIT, *tempCS ) )
{
m_CABACEstimator->split_cu_flag( split == CU_QUAD_SPLIT, *tempCS, partitioner );
}
if( split != CU_QUAD_SPLIT )
{
m_CABACEstimator->split_cu_mode_mt( split, *tempCS, partitioner );
}

Karsten Suehring
committed
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
tempCS->fracBits += m_CABACEstimator->getEstFracBits(); // split bits
}
}
tempCS->cost = m_pcRdCost->calcRdCost( tempCS->fracBits, tempCS->dist );
// Check Delta QP bits for splitted structure
xCheckDQP( *tempCS, partitioner, true );
// If the configuration being tested exceeds the maximum number of bytes for a slice / slice-segment, then
// a proper RD evaluation cannot be performed. Therefore, termination of the
// slice/slice-segment must be made prior to this CTU.
// This can be achieved by forcing the decision to be that of the rpcTempCU.
// The exception is each slice / slice-segment must have at least one CTU.
if (bestCS->cost != MAX_DOUBLE)
{
#if HEVC_TILES_WPP
const TileMap& tileMap = *tempCS->picture->tileMap;
#endif
#if HEVC_TILES_WPP || HEVC_DEPENDENT_SLICES
const uint32_t CtuAddr = CU::getCtuAddr( *bestCS->getCU( partitioner.chType ) );
#endif
const bool isEndOfSlice = slice.getSliceMode() == FIXED_NUMBER_OF_BYTES
&& ((slice.getSliceBits() + CS::getEstBits(*bestCS)) > slice.getSliceArgument() << 3)
#if HEVC_TILES_WPP
&& CtuAddr != tileMap.getCtuTsToRsAddrMap(slice.getSliceCurStartCtuTsAddr())
#endif
#if HEVC_DEPENDENT_SLICES
&& CtuAddr != tileMap.getCtuTsToRsAddrMap(slice.getSliceSegmentCurStartCtuTsAddr());
#else
;
#endif
#if HEVC_DEPENDENT_SLICES
const bool isEndOfSliceSegment = slice.getSliceSegmentMode() == FIXED_NUMBER_OF_BYTES
&& ((slice.getSliceSegmentBits() + CS::getEstBits(*bestCS)) > slice.getSliceSegmentArgument() << 3)
&& CtuAddr != tileMap.getCtuTsToRsAddrMap(slice.getSliceSegmentCurStartCtuTsAddr());
// Do not need to check slice condition for slice-segment since a slice-segment is a subset of a slice.
if (isEndOfSlice || isEndOfSliceSegment)
#else
if(isEndOfSlice)
#endif
{
bestCS->cost = MAX_DOUBLE;
}
}
// RD check for sub partitioned coding structure.

Karsten Suehring
committed
xCheckBestMode( tempCS, bestCS, partitioner, encTestMode );
if (isAffMVInfoSaved)
m_pcInterSearch->addAffMVInfo(tmpMVInfo);
if (!slice.isIntra()
&& tempCS->chType == CHANNEL_TYPE_LUMA
)
{
std::swap(tempMotCandLUTs, bestMotCandLUTs);
}
tempCS->slice->copyMotionLUTs(m_pSplitTempMotLUTs[wParIdx][hParIdx], tempMotCandLUTs);
}

Karsten Suehring
committed
tempCS->releaseIntermediateData();
tempCS->prevQP[partitioner.chType] = oldPrevQp;
}
void EncCu::xCheckRDCostIntra( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &partitioner, const EncTestMode& encTestMode )
{

Karsten Suehring
committed
double bestInterCost = m_modeCtrl->getBestInterCost();
double costSize2Nx2NemtFirstPass = m_modeCtrl->getEmtSize2Nx2NFirstPassCost();
bool skipSecondEmtPass = m_modeCtrl->getSkipSecondEMTPass();
const SPS &sps = *tempCS->sps;
#endif
const PPS &pps = *tempCS->pps;
#if !JVET_M0464_UNI_MTS

Karsten Suehring
committed
const CodingUnit *bestCU = bestCS->getCU( partitioner.chType );
const int maxSizeEMT = EMT_INTRA_MAX_CU_WITH_QTBT;

Karsten Suehring
committed
uint8_t considerEmtSecondPass = ( sps.getSpsNext().getUseIntraEMT() && isLuma( partitioner.chType ) && partitioner.currArea().lwidth() <= maxSizeEMT && partitioner.currArea().lheight() <= maxSizeEMT ) ? 1 : 0;

Karsten Suehring
committed
#if JVET_M0102_INTRA_SUBPARTITIONS
bool useIntraSubPartitions = false;
double maxCostAllowedForChroma = MAX_DOUBLE;
#if JVET_M0464_UNI_MTS
const CodingUnit *bestCU = bestCS->getCU( partitioner.chType );
#endif
#endif

Karsten Suehring
committed
Distortion interHad = m_modeCtrl->getInterHad();

Karsten Suehring
committed
for( uint8_t emtCuFlag = 0; emtCuFlag <= considerEmtSecondPass; emtCuFlag++ )
{
//Possible early EMT tests interruptions
//2) Second EMT pass. This "if clause" is necessary because of the NSST and PDPC "for loops".
if( emtCuFlag && skipSecondEmtPass )
{
continue;
}
//3) if interHad is 0, only try further modes if some intra mode was already better than inter
if( m_pcEncCfg->getUsePbIntraFast() && !tempCS->slice->isIntra() && bestCU && CU::isInter( *bestCS->getCU( partitioner.chType ) ) && interHad == 0 )
{
continue;
}

Karsten Suehring
committed
tempCS->initStructData( encTestMode.qp, encTestMode.lossless );
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.mmvdSkip = false;

Karsten Suehring
committed
cu.predMode = MODE_INTRA;
cu.transQuantBypass = encTestMode.lossless;
cu.chromaQpAdj = cu.transQuantBypass ? 0 : m_cuChromaQpOffsetIdxPlus1;
cu.qp = encTestMode.qp;
//cu.ipcm = false;

Karsten Suehring
committed
cu.emtFlag = emtCuFlag;
#if JVET_M0102_INTRA_SUBPARTITIONS
cu.ispMode = NOT_INTRA_SUBPARTITIONS;
#endif

Karsten Suehring
committed
CU::addPUs( cu );
tempCS->interHad = interHad;
if( isLuma( partitioner.chType ) )
{
#if JVET_M0102_INTRA_SUBPARTITIONS
//the Intra SubPartitions mode uses the value of the best cost so far (luma if it is the fast version) to avoid test non-necessary lines
const double bestCostSoFar = CS::isDualITree( *tempCS ) ? m_modeCtrl->getBestCostWithoutSplitFlags() : bestCU && bestCU->predMode == MODE_INTRA ? bestCS->lumaCost : bestCS->cost;
m_pcIntraSearch->estIntraPredLumaQT( cu, partitioner, bestCostSoFar );
useIntraSubPartitions = cu.ispMode != NOT_INTRA_SUBPARTITIONS;
if( !CS::isDualITree( *tempCS ) )
{
tempCS->lumaCost = m_pcRdCost->calcRdCost( tempCS->fracBits, tempCS->dist );
if( useIntraSubPartitions )
{
//the difference between the best cost so far and the current luma cost is stored to avoid testing the Cr component if the cost of luma + Cb is larger than the best cost
maxCostAllowedForChroma = bestCS->cost < MAX_DOUBLE ? bestCS->cost - tempCS->lumaCost : MAX_DOUBLE;
}
}
#else

Karsten Suehring
committed
m_pcIntraSearch->estIntraPredLumaQT( cu, partitioner );

Karsten Suehring
committed
if (m_pcEncCfg->getUsePbIntraFast() && tempCS->dist == std::numeric_limits<Distortion>::max()
&& tempCS->interHad == 0)
{
interHad = 0;
// JEM assumes only perfect reconstructions can from now on beat the inter mode
m_modeCtrl->enforceInterHad( 0 );

Karsten Suehring
committed
continue;

Karsten Suehring
committed
}
if( !CS::isDualITree( *tempCS ) )
{
cu.cs->picture->getRecoBuf( cu.Y() ).copyFrom( cu.cs->getRecoBuf( COMPONENT_Y ) );
#if JVET_M0427_INLOOP_RESHAPER
cu.cs->picture->getPredBuf(cu.Y()).copyFrom(cu.cs->getPredBuf(COMPONENT_Y));
#endif

Karsten Suehring
committed
}
}
if( tempCS->area.chromaFormat != CHROMA_400 && ( partitioner.chType == CHANNEL_TYPE_CHROMA || !CS::isDualITree( *tempCS ) ) )
{
#if JVET_M0102_INTRA_SUBPARTITIONS
TUIntraSubPartitioner subTuPartitioner( partitioner );
m_pcIntraSearch->estIntraPredChromaQT( cu, ( !useIntraSubPartitions || ( CS::isDualITree( *cu.cs ) && !isLuma( CHANNEL_TYPE_CHROMA ) ) ) ? partitioner : subTuPartitioner, maxCostAllowedForChroma );
if( useIntraSubPartitions && !cu.ispMode )
{
//At this point the temp cost is larger than the best cost. Therefore, we can already skip the remaining calculations
#if JVET_M0464_UNI_MTS
return;
#else
continue;
#endif
}
#else

Karsten Suehring
committed
m_pcIntraSearch->estIntraPredChromaQT( cu, partitioner );

Karsten Suehring
committed
}
cu.rootCbf = false;
for( uint32_t t = 0; t < getNumberValidTBlocks( *cu.cs->pcv ); t++ )
{
cu.rootCbf |= cu.firstTU->cbf[t] != 0;
}
// Get total bits for current mode: encode CU
m_CABACEstimator->resetBits();
if( pps.getTransquantBypassEnabledFlag() )
{
m_CABACEstimator->cu_transquant_bypass_flag( cu );
}
if( !cu.cs->slice->isIntra()

Karsten Suehring
committed
{
m_CABACEstimator->cu_skip_flag ( cu );
}
m_CABACEstimator->pred_mode ( cu );
m_CABACEstimator->extend_ref_line( cu );
#if JVET_M0102_INTRA_SUBPARTITIONS
m_CABACEstimator->isp_mode ( cu );
#endif

Karsten Suehring
committed
m_CABACEstimator->cu_pred_data ( cu );
m_CABACEstimator->pcm_data ( cu, partitioner );

Karsten Suehring
committed
// Encode Coefficients
CUCtx cuCtx;
cuCtx.isDQPCoded = true;
cuCtx.isChromaQpAdjCoded = true;
m_CABACEstimator->cu_residual( cu, partitioner, cuCtx );
tempCS->fracBits = m_CABACEstimator->getEstFracBits();
tempCS->cost = m_pcRdCost->calcRdCost(tempCS->fracBits, tempCS->dist);
#if JVET_M0102_INTRA_SUBPARTITIONS
#if !JVET_M0464_UNI_MTS
double bestIspCost = cu.ispMode ? CS::isDualITree(*tempCS) ? tempCS->cost : tempCS->lumaCost : MAX_DOUBLE;
#endif
const double tmpCostWithoutSplitFlags = tempCS->cost;
#endif

Karsten Suehring
committed
xEncodeDontSplit( *tempCS, partitioner );
xCheckDQP( *tempCS, partitioner );
#if JVET_M0102_INTRA_SUBPARTITIONS
if( tempCS->cost < bestCS->cost )
{
m_modeCtrl->setBestCostWithoutSplitFlags( tmpCostWithoutSplitFlags );
}
#endif

Karsten Suehring
committed
// we save the cost of the modes for the first EMT pass
if( !emtCuFlag ) static_cast< double& >( costSize2Nx2NemtFirstPass ) = tempCS->cost;

Karsten Suehring
committed
#if WCG_EXT
DTRACE_MODE_COST( *tempCS, m_pcRdCost->getLambda( true ) );
#else
DTRACE_MODE_COST( *tempCS, m_pcRdCost->getLambda() );
#endif
xCheckBestMode( tempCS, bestCS, partitioner, encTestMode );
#if JVET_M0102_INTRA_SUBPARTITIONS
//we decide to skip the second emt pass or not according to the ISP results
if (considerEmtSecondPass && cu.ispMode && !emtCuFlag && tempCS->slice->isIntra())
{
double bestCostDct2NoIsp = m_modeCtrl->getEmtFirstPassNoIspCost();
CHECKD(bestCostDct2NoIsp <= bestIspCost, "wrong cost!");
double nSamples = (double)(cu.lwidth() << g_aucLog2[cu.lheight()]);
double threshold = 1 + 1.4 / sqrt(nSamples);
if (bestCostDct2NoIsp > bestIspCost*threshold)
{
skipSecondEmtPass = true;
m_modeCtrl->setSkipSecondEMTPass(true);
break;
}
}
#endif

Karsten Suehring
committed
//now we check whether the second pass of SIZE_2Nx2N and the whole Intra SIZE_NxN should be skipped or not
if( !emtCuFlag && !tempCS->slice->isIntra() && bestCU && bestCU->predMode != MODE_INTRA && m_pcEncCfg->getFastInterEMT() )

Karsten Suehring
committed
{
const double thEmtInterFastSkipIntra = 1.4; // Skip checking Intra if "2Nx2N using DCT2" is worse than best Inter mode
if( costSize2Nx2NemtFirstPass > thEmtInterFastSkipIntra * bestInterCost )
{
skipSecondEmtPass = true;
m_modeCtrl->setSkipSecondEMTPass( true );
break;
}
}

Karsten Suehring
committed
} //for emtCuFlag
}
void EncCu::xCheckIntraPCM(CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &partitioner, const EncTestMode& encTestMode )
{
tempCS->initStructData( encTestMode.qp, encTestMode.lossless );
CodingUnit &cu = tempCS->addCU( CS::getArea( *tempCS, tempCS->area, partitioner.chType ), partitioner.chType );

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;

Karsten Suehring
committed
cu.predMode = MODE_INTRA;
cu.transQuantBypass = encTestMode.lossless;
cu.chromaQpAdj = cu.transQuantBypass ? 0 : m_cuChromaQpOffsetIdxPlus1;
cu.qp = encTestMode.qp;
cu.ipcm = true;
tempCS->addPU( CS::getArea( *tempCS, tempCS->area, partitioner.chType ), partitioner.chType );
tempCS->addTU( CS::getArea( *tempCS, tempCS->area, partitioner.chType ), partitioner.chType );

Karsten Suehring
committed
m_pcIntraSearch->IPCMSearch(*tempCS, partitioner);
m_CABACEstimator->getCtx() = m_CurrCtx->start;
m_CABACEstimator->resetBits();
if( tempCS->pps->getTransquantBypassEnabledFlag() )
{
m_CABACEstimator->cu_transquant_bypass_flag( cu );
}
if( !cu.cs->slice->isIntra()

Karsten Suehring
committed
{
m_CABACEstimator->cu_skip_flag ( cu );
}
m_CABACEstimator->pred_mode ( cu );
m_CABACEstimator->pcm_data ( cu, partitioner );

Karsten Suehring
committed
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
tempCS->fracBits = m_CABACEstimator->getEstFracBits();
tempCS->cost = m_pcRdCost->calcRdCost(tempCS->fracBits, tempCS->dist);
xEncodeDontSplit( *tempCS, partitioner );
xCheckDQP( *tempCS, partitioner );
#if WCG_EXT
DTRACE_MODE_COST( *tempCS, m_pcRdCost->getLambda( true ) );
#else
DTRACE_MODE_COST( *tempCS, m_pcRdCost->getLambda() );
#endif
xCheckBestMode( tempCS, bestCS, partitioner, encTestMode );
}
void EncCu::xCheckDQP( CodingStructure& cs, Partitioner& partitioner, bool bKeepCtx )
{
CHECK( bKeepCtx && cs.cus.size() <= 1 && partitioner.getImplicitSplit( cs ) == CU_DONT_SPLIT, "bKeepCtx should only be set in split case" );
CHECK( !bKeepCtx && cs.cus.size() > 1, "bKeepCtx should never be set for non-split case" );
if( !cs.pps->getUseDQP() )
{
return;
}

Christian Helmrich
committed
if (CS::isDualITree(cs) && isChroma(partitioner.chType))
{
return;
}

Karsten Suehring
committed
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
if( bKeepCtx && partitioner.currDepth != cs.pps->getMaxCuDQPDepth() )
{
return;
}
if( !bKeepCtx && partitioner.currDepth > cs.pps->getMaxCuDQPDepth() )
{
return;
}
CodingUnit* cuFirst = cs.getCU( partitioner.chType );
CHECK( !cuFirst, "No CU available" );
bool hasResidual = false;
for( const auto &cu : cs.cus )
{
if( cu->rootCbf )
{
hasResidual = true;
break;
}
}
int predQP = CU::predictQP( *cuFirst, cs.prevQP[partitioner.chType] );
if( hasResidual )
{
TempCtx ctxTemp( m_CtxCache );
if( !bKeepCtx ) ctxTemp = SubCtx( Ctx::DeltaQP, m_CABACEstimator->getCtx() );
m_CABACEstimator->resetBits();
m_CABACEstimator->cu_qp_delta( *cuFirst, predQP, cuFirst->qp );
cs.fracBits += m_CABACEstimator->getEstFracBits(); // dQP bits
cs.cost = m_pcRdCost->calcRdCost(cs.fracBits, cs.dist);
if( !bKeepCtx ) m_CABACEstimator->getCtx() = SubCtx( Ctx::DeltaQP, ctxTemp );
// NOTE: reset QPs for CUs without residuals up to first coded CU
for( const auto &cu : cs.cus )
{
if( cu->rootCbf )
{
break;
}
cu->qp = predQP;
}
}
else
{
// No residuals: reset CU QP to predicted value
for( const auto &cu : cs.cus )
{
cu->qp = predQP;
}
}
}
void EncCu::xFillPCMBuffer( CodingUnit &cu )
{
const ChromaFormat format = cu.chromaFormat;
const uint32_t numberValidComponents = getNumberValidComponents(format);
for( auto &tu : CU::traverseTUs( cu ) )
{
for( uint32_t ch = 0; ch < numberValidComponents; ch++ )
{
const ComponentID compID = ComponentID( ch );
const CompArea &compArea = tu.blocks[ compID ];
const CPelBuf source = tu.cs->getOrgBuf( compArea );
PelBuf destination = tu.getPcmbuf( compID );
destination.copyFrom( source );
}
}
}
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
#if JVET_M0253_HASH_ME
void EncCu::xCheckRDCostHashInter( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &partitioner, const EncTestMode& encTestMode )
{
bool isPerfectMatch = false;
tempCS->initStructData(encTestMode.qp, encTestMode.lossless);
m_pcInterSearch->resetBufferedUniMotions();
m_pcInterSearch->setAffineModeSelected(false);
CodingUnit &cu = tempCS->addCU(tempCS->area, partitioner.chType);
partitioner.setCUData(cu);
cu.slice = tempCS->slice;
cu.skip = false;
cu.predMode = MODE_INTER;
cu.transQuantBypass = encTestMode.lossless;
cu.chromaQpAdj = cu.transQuantBypass ? 0 : m_cuChromaQpOffsetIdxPlus1;
cu.qp = encTestMode.qp;
cu.ibc = false;
CU::addPUs(cu);
cu.mmvdSkip = false;
cu.firstPU->mmvdMergeFlag = false;
if (m_pcInterSearch->predInterHashSearch(cu, partitioner, isPerfectMatch))
{
const unsigned wIdx = gp_sizeIdxInfo->idxFrom(tempCS->area.lwidth());
double equGBiCost = MAX_DOUBLE;
#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
, m_pImvTempCS ? m_pImvTempCS[wIdx] : NULL
, 1
, 0
, &equGBiCost
#endif
);
}
tempCS->initStructData(encTestMode.qp, encTestMode.lossless);

Karsten Suehring
committed
if (cu.lwidth() != 64)
{
isPerfectMatch = false;
}
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.getSpsNext().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 ) )
{
{
ComprCUCtx cuECtx = m_modeCtrl->getComprCUCtx();
bestIsSkip = blkCache->isSkip(tempCS->area) && cuECtx.bestCU;