Newer
Older

Karsten Suehring
committed
int default0Save1Load2 = 0;
singleDistTmpLuma = 0;
if( modeId == firstCheckId && ( sps.getUseLFNST() ? ( modeId != lastCheckId ) : ( nNumTransformCands > 1 ) ) )

Karsten Suehring
committed
{
default0Save1Load2 = 1;
}
else if (modeId != firstCheckId)
{
if( sps.getUseLFNST() && !cbfBestModeValid )
{
default0Save1Load2 = 1;
}
else
{
default0Save1Load2 = 2;
}

Karsten Suehring
committed
}
if( cu.ispMode )
{
default0Save1Load2 = 0;
}
if( sps.getUseLFNST() )
{
if( cu.mtsFlag )
{
if( moreProbMTSIdxFirst )
{
const ChannelType chType = toChannelType( COMPONENT_Y );
const CompArea& area = tu.blocks[ COMPONENT_Y ];
const PredictionUnit& pu = *cs.getPU( area.pos(), chType );
uint32_t uiIntraMode = pu.intraDir[ chType ];
if( transformIndex == 1 )
{
#if JVET_P0058_CHROMA_TS
tu.mtsIdx[COMPONENT_Y] = (uiIntraMode < 34) ? MTS_DST7_DCT8 : MTS_DCT8_DST7;
#else
tu.mtsIdx = ( uiIntraMode < 34 ) ? MTS_DST7_DCT8 : MTS_DCT8_DST7;
#if JVET_P0058_CHROMA_TS
tu.mtsIdx[COMPONENT_Y] = (uiIntraMode < 34) ? MTS_DCT8_DST7 : MTS_DST7_DCT8;
#else
tu.mtsIdx = ( uiIntraMode < 34 ) ? MTS_DCT8_DST7 : MTS_DST7_DCT8;
#if JVET_P0058_CHROMA_TS
tu.mtsIdx[COMPONENT_Y] = MTS_DST7_DST7 + transformIndex;
#else
tu.mtsIdx = MTS_DST7_DST7 + transformIndex;
#if JVET_P0058_CHROMA_TS
tu.mtsIdx[COMPONENT_Y] = MTS_DST7_DST7 + transformIndex;
#else
tu.mtsIdx = MTS_DST7_DST7 + transformIndex;
}
}
else
{
#if JVET_P0058_CHROMA_TS
tu.mtsIdx[COMPONENT_Y] = transformIndex;
#else
tu.mtsIdx = transformIndex;
3075
3076
3077
3078
3079
3080
3081
3082
3083
3084
3085
3086
3087
3088
3089
3090
3091
3092
3093
3094
3095
3096
3097
3098
3099
3100
3101
3102
3103
3104
3105
3106
3107
3108
3109
3110
3111
3112
3113
3114
3115
3116
}
if( !cu.mtsFlag && checkTransformSkip )
{
xIntraCodingTUBlock( tu, COMPONENT_Y, false, singleDistTmpLuma, default0Save1Load2, &numSig, modeId == 0 ? &trModes : nullptr, true );
if( modeId == 0 )
{
for( int i = 0; i < 2; i++ )
{
if( trModes[ i ].second )
{
lastCheckId = trModes[ i ].first;
}
}
}
}
else
{
xIntraCodingTUBlock( tu, COMPONENT_Y, false, singleDistTmpLuma, default0Save1Load2, &numSig );
}
}
else
{
if( nNumTransformCands > 1 )
{
xIntraCodingTUBlock( tu, COMPONENT_Y, false, singleDistTmpLuma, default0Save1Load2, &numSig, modeId == 0 ? &trModes : nullptr, true );
if( modeId == 0 )
{
for( int i = 0; i < nNumTransformCands; i++ )
{
if( trModes[ i ].second )
{
lastCheckId = trModes[ i ].first;
}
}
}
}
else
{
xIntraCodingTUBlock( tu, COMPONENT_Y, false, singleDistTmpLuma, default0Save1Load2, &numSig );
}
}

Karsten Suehring
committed
//----- determine rate and r-d cost -----
if( ( sps.getUseLFNST() ? ( modeId == lastCheckId && modeId != 0 && checkTransformSkip ) : ( trModes[ modeId ].first != 0 ) ) && !TU::getCbfAtDepth( tu, COMPONENT_Y, currDepth ) )

Karsten Suehring
committed
{
//In order not to code TS flag when cbf is zero, the case for TS with cbf being zero is forbidden.
singleCostTmp = MAX_DOUBLE;
}
else
{
if( cu.ispMode && m_pcRdCost->calcRdCost( csFull->fracBits, csFull->dist + singleDistTmpLuma ) > bestCostSoFar )
{
earlySkipISP = true;
}
else
{
singleTmpFracBits = xGetIntraFracBitsQT( *csFull, partitioner, true, false, subTuCounter, ispType );
}

Karsten Suehring
committed
singleCostTmp = m_pcRdCost->calcRdCost( singleTmpFracBits, singleDistTmpLuma );
}
Santiago de Luxán Hernández
committed
if ( !cu.ispMode && nNumTransformCands > 1 && modeId == firstCheckId )
{
bestDCT2cost = singleCostTmp;
}

Karsten Suehring
committed
if (singleCostTmp < dSingleCost)
{
dSingleCost = singleCostTmp;
uiSingleDistLuma = singleDistTmpLuma;
singleFracBits = singleTmpFracBits;
if( sps.getUseLFNST() )
bestModeId[ COMPONENT_Y ] = modeId;
cbfBestMode = TU::getCbfAtDepth( tu, COMPONENT_Y, currDepth );
cbfBestModeValid = true;
validReturnFull = true;
else
{
bestModeId[ COMPONENT_Y ] = trModes[ modeId ].first;
if( trModes[ modeId ].first == 0 )
{
cbfDCT2 = TU::getCbfAtDepth( tu, COMPONENT_Y, currDepth );
}
}

Karsten Suehring
committed
if( bestModeId[COMPONENT_Y] != lastCheckId )
{
saveCS.getPredBuf( tu.Y() ).copyFrom( csFull->getPredBuf( tu.Y() ) );
saveCS.getRecoBuf( tu.Y() ).copyFrom( csFull->getRecoBuf( tu.Y() ) );
if( keepResi )
{
saveCS.getResiBuf ( tu.Y() ).copyFrom( csFull->getResiBuf ( tu.Y() ) );
saveCS.getOrgResiBuf( tu.Y() ).copyFrom( csFull->getOrgResiBuf( tu.Y() ) );
}
tmpTU->copyComponentFrom( tu, COMPONENT_Y );
ctxBest = m_CABACEstimator->getCtx();
}
}
}
if( sps.getUseLFNST() && !validReturnFull )

Karsten Suehring
committed
{
csFull->cost = MAX_DOUBLE;

Karsten Suehring
committed
if( bCheckSplit )

Karsten Suehring
committed
{
ctxBest = m_CABACEstimator->getCtx();

Karsten Suehring
committed
}
}
else
{
if( bestModeId[COMPONENT_Y] != lastCheckId )
{
csFull->getPredBuf( tu.Y() ).copyFrom( saveCS.getPredBuf( tu.Y() ) );
csFull->getRecoBuf( tu.Y() ).copyFrom( saveCS.getRecoBuf( tu.Y() ) );

Karsten Suehring
committed
if( keepResi )
{
csFull->getResiBuf ( tu.Y() ).copyFrom( saveCS.getResiBuf ( tu.Y() ) );
csFull->getOrgResiBuf( tu.Y() ).copyFrom( saveCS.getOrgResiBuf( tu.Y() ) );
}

Karsten Suehring
committed
tu.copyComponentFrom( *tmpTU, COMPONENT_Y );
if( !bCheckSplit )
{
m_CABACEstimator->getCtx() = ctxBest;
}
}
else if( bCheckSplit )

Karsten Suehring
committed
{
ctxBest = m_CABACEstimator->getCtx();

Karsten Suehring
committed
}
csFull->cost += dSingleCost;
csFull->dist += uiSingleDistLuma;
csFull->fracBits += singleFracBits;
}

Karsten Suehring
committed
}
bool validReturnSplit = false;

Karsten Suehring
committed
if( bCheckSplit )
{
//----- store full entropy coding status, load original entropy coding status -----
if( bCheckFull )
{
m_CABACEstimator->getCtx() = ctxStart;
}
//----- code splitted block -----
csSplit->cost = 0;
bool uiSplitCbfLuma = false;
bool splitIsSelected = true;

Karsten Suehring
committed
{
partitioner.splitCurrArea( TU_MAX_TR_SPLIT, cs );
}
if( cu.ispMode )
{
partitioner.splitCurrArea( ispType, *csSplit );
}

Karsten Suehring
committed
do
{
bool tmpValidReturnSplit = xRecurIntraCodingLumaQT( *csSplit, partitioner, bestCostSoFar, subTuCounter, ispType, false, mtsCheckRangeFlag, mtsFirstCheckId, mtsLastCheckId );
subTuCounter += subTuCounter != -1 ? 1 : 0;
if( sps.getUseLFNST() && !tmpValidReturnSplit )
{
splitIsSelected = false;
break;
}

Karsten Suehring
committed
if( !cu.ispMode )
{
csSplit->setDecomp( partitioner.currArea().Y() );
}
else if( CU::isISPFirst( cu, partitioner.currArea().Y(), COMPONENT_Y ) )
{
csSplit->setDecomp( cu.Y() );
}

Karsten Suehring
committed
uiSplitCbfLuma |= TU::getCbfAtDepth( *csSplit->getTU( partitioner.currArea().lumaPos(), partitioner.chType, subTuCounter - 1 ), COMPONENT_Y, partitioner.currTrDepth );
if( cu.ispMode )
{
//exit condition if the accumulated cost is already larger than the best cost so far (no impact in RD performance)
if( csSplit->cost > bestCostSoFar )
{
earlySkipISP = true;
splitIsSelected = false;
break;
}
else
{
//more restrictive exit condition
bool tuIsDividedInRows = CU::divideTuInRows( cu );
int nSubPartitions = tuIsDividedInRows ? cu.lheight() >> floorLog2(cu.firstTU->lheight()) : cu.lwidth() >> floorLog2(cu.firstTU->lwidth());
Santiago de Luxán Hernández
committed
double threshold = nSubPartitions == 2 ? 0.95 : subTuCounter == 1 ? 0.83 : 0.91;
if( subTuCounter < nSubPartitions && csSplit->cost > bestCostSoFar*threshold )
{
earlySkipISP = true;
splitIsSelected = false;
break;
}
}
}

Karsten Suehring
committed
3287
3288
3289
3290
3291
3292
3293
3294
3295
3296
3297
3298
3299
3300
3301
3302
3303
3304
3305
3306
3307
} while( partitioner.nextPart( *csSplit ) );
partitioner.exitCurrSplit();
if( splitIsSelected )
{
for( auto &ptu : csSplit->tus )
{
if( currArea.Y().contains( ptu->Y() ) )
{
TU::setCbfAtDepth( *ptu, COMPONENT_Y, currDepth, uiSplitCbfLuma ? 1 : 0 );
}
}
//----- restore context states -----
m_CABACEstimator->getCtx() = ctxStart;
//----- determine rate and r-d cost -----
csSplit->fracBits = xGetIntraFracBitsQT( *csSplit, partitioner, true, false, cu.ispMode ? 0 : -1, ispType );

Karsten Suehring
committed
//--- update cost ---
csSplit->cost = m_pcRdCost->calcRdCost(csSplit->fracBits, csSplit->dist);
validReturnSplit = true;

Karsten Suehring
committed
}
}
bool retVal = false;

Karsten Suehring
committed
if( csFull || csSplit )
{
if( !sps.getUseLFNST() || validReturnFull || validReturnSplit )

Karsten Suehring
committed
{
{
// otherwise this would've happened in useSubStructure
cs.picture->getRecoBuf( currArea.Y() ).copyFrom( cs.getRecoBuf( currArea.Y() ) );
cs.picture->getPredBuf( currArea.Y() ).copyFrom( cs.getPredBuf( currArea.Y() ) );
}

Karsten Suehring
committed
if( cu.ispMode && earlySkipISP )
{
cs.cost = MAX_DOUBLE;
}
else
{
cs.cost = m_pcRdCost->calcRdCost( cs.fracBits, cs.dist );
retVal = true;
}

Karsten Suehring
committed
}

Karsten Suehring
committed
}
ChromaCbfs IntraSearch::xRecurIntraChromaCodingQT( CodingStructure &cs, Partitioner& partitioner, const double bestCostSoFar, const PartSplit ispType )

Karsten Suehring
committed
{
UnitArea currArea = partitioner.currArea();
const bool keepResi = cs.sps->getUseLMChroma() || KEEP_PRED_AND_RESI_SIGNALS;

Karsten Suehring
committed
if( !currArea.Cb().valid() ) return ChromaCbfs( false );
TransformUnit &currTU = *cs.getTU( currArea.chromaPos(), CHANNEL_TYPE_CHROMA );
const PredictionUnit &pu = *cs.getPU( currArea.chromaPos(), CHANNEL_TYPE_CHROMA );
bool lumaUsesISP = false;

Karsten Suehring
committed
uint32_t currDepth = partitioner.currTrDepth;
const PPS &pps = *cs.pps;
ChromaCbfs cbfs ( false );
if (currDepth == currTU.depth)
{
if (!currArea.Cb().valid() || !currArea.Cr().valid())
{
return cbfs;
}
CodingStructure &saveCS = *m_pSaveCS[1];
saveCS.pcv = cs.pcv;
saveCS.picture = cs.picture;
saveCS.area.repositionTo( cs.area );
Adam Wieckowski
committed
saveCS.initStructData( MAX_INT, false, true );

Karsten Suehring
committed
if( !currTU.cu->isSepTree() && currTU.cu->ispMode )
{
saveCS.clearCUs();
CodingUnit& auxCU = saveCS.addCU( *currTU.cu, partitioner.chType );
auxCU.ispMode = currTU.cu->ispMode;
saveCS.sps = currTU.cs->sps;
saveCS.clearPUs();
saveCS.addPU( *currTU.cu->firstPU, partitioner.chType );
}

Karsten Suehring
committed
TransformUnit &tmpTU = saveCS.addTU(currArea, partitioner.chType);
cs.setDecomp(currArea.Cb(), true); // set in advance (required for Cb2/Cr2 in 4:2:2 video)
const unsigned numTBlocks = ::getNumberValidTBlocks( *cs.pcv );
CompArea& cbArea = currTU.blocks[COMPONENT_Cb];
CompArea& crArea = currTU.blocks[COMPONENT_Cr];
double bestCostCb = MAX_DOUBLE;
double bestCostCr = MAX_DOUBLE;
Distortion bestDistCb = 0;
Distortion bestDistCr = 0;
int maxModesTested = 0;
bool earlyExitISP = false;
TempCtx ctxStartTU( m_CtxCache );
TempCtx ctxStart ( m_CtxCache );
TempCtx ctxBest ( m_CtxCache );
ctxStartTU = m_CABACEstimator->getCtx();
currTU.jointCbCr = 0;
// Do predictions here to avoid repeating the "default0Save1Load2" stuff
int predMode = PU::getFinalIntraMode( pu, CHANNEL_TYPE_CHROMA );
PelBuf piPredCb = cs.getPredBuf(cbArea);
PelBuf piPredCr = cs.getPredBuf(crArea);
Alexey Filippov
committed
initIntraPatternChType( *currTU.cu, cbArea);
initIntraPatternChType( *currTU.cu, crArea);
if( PU::isLMCMode( predMode ) )
{
xGetLumaRecPixels( pu, cbArea );
predIntraChromaLM( COMPONENT_Cb, piPredCb, pu, cbArea, predMode );
predIntraChromaLM( COMPONENT_Cr, piPredCr, pu, crArea, predMode );
}
else
{
Alexey Filippov
committed
predIntraAng( COMPONENT_Cb, piPredCb, pu);
predIntraAng( COMPONENT_Cr, piPredCr, pu);

Karsten Suehring
committed
// determination of chroma residuals including reshaping and cross-component prediction
//----- get chroma residuals -----
PelBuf resiCb = cs.getResiBuf(cbArea);
PelBuf resiCr = cs.getResiBuf(crArea);
resiCb.copyFrom( cs.getOrgBuf (cbArea) );
resiCr.copyFrom( cs.getOrgBuf (crArea) );
resiCb.subtract( piPredCb );
resiCr.subtract( piPredCr );
//----- get reshape parameter ----
bool doReshaping = ( cs.slice->getLmcsEnabledFlag() && cs.slice->getLmcsChromaResidualScaleFlag()
&& (cs.slice->isIntra() || m_pcReshape->getCTUFlag()) && (cbArea.width * cbArea.height > 4) );
if( doReshaping )
{
const Area area = currTU.Y().valid() ? currTU.Y() : Area(recalcPosition(currTU.chromaFormat, currTU.chType, CHANNEL_TYPE_LUMA, currTU.blocks[currTU.chType].pos()), recalcSize(currTU.chromaFormat, currTU.chType, CHANNEL_TYPE_LUMA, currTU.blocks[currTU.chType].size()));
const CompArea &areaY = CompArea(COMPONENT_Y, currTU.chromaFormat, area);
int adj = m_pcReshape->calculateChromaAdjVpduNei(currTU, areaY);
3442
3443
3444
3445
3446
3447
3448
3449
3450
3451
3452
3453
3454
3455
3456
3457
3458
3459
3460
3461
3462
3463
3464
3465
3466
3467
3468
3469
3470
3471
3472
3473
3474
3475
3476
3477
3478
currTU.setChromaAdj(adj);
}
//----- get cross component prediction parameters -----
bool checkCrossComponentPrediction = PU::isChromaIntraModeCrossCheckMode( pu ) && pps.getPpsRangeExtension().getCrossComponentPredictionEnabledFlag() && TU::getCbf( currTU, COMPONENT_Y );
int compAlpha[MAX_NUM_COMPONENT] = { 0, 0, 0 };
if( checkCrossComponentPrediction )
{
compAlpha[COMPONENT_Cb] = xCalcCrossComponentPredictionAlpha( currTU, COMPONENT_Cb, m_pcEncCfg->getUseReconBasedCrossCPredictionEstimate() );
compAlpha[COMPONENT_Cr] = xCalcCrossComponentPredictionAlpha( currTU, COMPONENT_Cr, m_pcEncCfg->getUseReconBasedCrossCPredictionEstimate() );
if( compAlpha[COMPONENT_Cb] == 0 && compAlpha[COMPONENT_Cr] == 0 )
{
checkCrossComponentPrediction = false;
}
}
//===== store original residual signals (std and crossCompPred) =====
CompStorage orgResiCb[5], orgResiCr[5]; // 0:std, 1-3:jointCbCr (placeholder at this stage), 4:crossComp
for( int k = 0; k < (checkCrossComponentPrediction?5:1); k+=4 )
{
orgResiCb[k].create( cbArea );
orgResiCr[k].create( crArea );
if( k >= 4 ) {
CrossComponentPrediction::crossComponentPrediction( currTU, COMPONENT_Cb, cs.getResiBuf(currTU.Y()), resiCb, orgResiCb[k], false);
CrossComponentPrediction::crossComponentPrediction( currTU, COMPONENT_Cr, cs.getResiBuf(currTU.Y()), resiCr, orgResiCr[k], false);
} else {
orgResiCb[k].copyFrom( resiCb );
orgResiCr[k].copyFrom( resiCr );
}
if( doReshaping )
{
int cResScaleInv = currTU.getChromaAdj();
orgResiCb[k].scaleSignal( cResScaleInv, 1, currTU.cu->cs->slice->clpRng(COMPONENT_Cb) );
orgResiCr[k].scaleSignal( cResScaleInv, 1, currTU.cu->cs->slice->clpRng(COMPONENT_Cr) );
}
}

Karsten Suehring
committed
for( uint32_t c = COMPONENT_Cb; c < numTBlocks; c++)
{
const ComponentID compID = ComponentID(c);
const CompArea& area = currTU.blocks[compID];
double dSingleCost = MAX_DOUBLE;
int bestModeId = 0;
Distortion singleDistCTmp = 0;
double singleCostTmp = 0;
const int crossCPredictionModesToTest = checkCrossComponentPrediction ? 2 : 1;
#if JVET_P0058_CHROMA_TS
const bool tsAllowed = TU::isTSAllowed(currTU, compID) && (m_pcEncCfg->getUseChromaTS());
uint8_t nNumTransformCands = 1 + (tsAllowed ? 1 : 0); // DCT + TS = 2 tests
std::vector<TrMode> trModes;
trModes.push_back(TrMode(0, true)); // DCT2
if (tsAllowed)
{
trModes.push_back(TrMode(1, true));//TS
}
CHECK(!currTU.Cb().valid(), "Invalid TU");
#endif
#if JVET_P0058_CHROMA_TS
const int totalModesToTest = crossCPredictionModesToTest * nNumTransformCands;
bool cbfDCT2 = true;
#else
const bool isOneMode = false;
maxModesTested = totalModesToTest > maxModesTested ? totalModesToTest : maxModesTested;

Karsten Suehring
committed
int currModeId = 0;
int default0Save1Load2 = 0;
if (!isOneMode)
{
ctxStart = m_CABACEstimator->getCtx();
}
#if JVET_P0058_CHROMA_TS
for (int modeId = 0; modeId < nNumTransformCands; modeId++)
#endif

Karsten Suehring
committed
{
for (int crossCPredictionModeId = 0; crossCPredictionModeId < crossCPredictionModesToTest; crossCPredictionModeId++)
{
resiCb.copyFrom( orgResiCb[4*crossCPredictionModeId] );
resiCr.copyFrom( orgResiCr[4*crossCPredictionModeId] );
currTU.compAlpha [compID] = ( crossCPredictionModeId ? compAlpha[compID] : 0 );

Karsten Suehring
committed
#if JVET_P0058_CHROMA_TS
currTU.mtsIdx[compID] = trModes[modeId].first;
#endif

Karsten Suehring
committed
currModeId++;
const bool isFirstMode = (currModeId == 1);
const bool isLastMode = false; // Always store output to saveCS and tmpTU
#if JVET_P0058_CHROMA_TS
//if DCT2's cbf==0, skip ts search
if (!cbfDCT2 && trModes[modeId].first == MTS_SKIP)
{
break;
}
if (!trModes[modeId].second)
{
continue;
}
#endif

Karsten Suehring
committed
if (!isFirstMode) // if not first mode to be tested
{
m_CABACEstimator->getCtx() = ctxStart;
}
singleDistCTmp = 0;
#if JVET_P0058_CHROMA_TS
if (nNumTransformCands > 1)
{
xIntraCodingTUBlock(currTU, compID, crossCPredictionModeId != 0, singleDistCTmp, default0Save1Load2, nullptr, modeId == 0 ? &trModes : nullptr, true);
}
else
{
xIntraCodingTUBlock(currTU, compID, crossCPredictionModeId != 0, singleDistCTmp, default0Save1Load2);
}
#else

Karsten Suehring
committed
xIntraCodingTUBlock( currTU, compID, crossCPredictionModeId != 0, singleDistCTmp, default0Save1Load2 );

Karsten Suehring
committed
#if JVET_P0058_CHROMA_TS
if (((crossCPredictionModeId == 1) && (currTU.compAlpha[compID] == 0)) || ((currTU.mtsIdx[compID] == MTS_SKIP) && !TU::getCbf(currTU, compID))) //In order not to code TS flag when cbf is zero, the case for TS with cbf being zero is forbidden.
#else
if( ( ( crossCPredictionModeId == 1 ) && ( currTU.compAlpha[compID] == 0 ) ) ) //In order not to code TS flag when cbf is zero, the case for TS with cbf being zero is forbidden.

Karsten Suehring
committed
{
singleCostTmp = MAX_DOUBLE;
}
else if( lumaUsesISP && bestCostSoFar != MAX_DOUBLE && c == COMPONENT_Cb )
{
uint64_t fracBitsTmp = xGetIntraFracBitsQTSingleChromaComponent( cs, partitioner, ComponentID( c ) );
singleCostTmp = m_pcRdCost->calcRdCost( fracBitsTmp, singleDistCTmp );
if( isOneMode || ( !isOneMode && !isLastMode ) )
{
m_CABACEstimator->getCtx() = ctxStart;
}
}

Karsten Suehring
committed
else if( !isOneMode )
{
uint64_t fracBitsTmp = xGetIntraFracBitsQTChroma( currTU, compID );
singleCostTmp = m_pcRdCost->calcRdCost( fracBitsTmp, singleDistCTmp );
}
if( singleCostTmp < dSingleCost )
{
dSingleCost = singleCostTmp;
bestModeId = currModeId;
if ( c == COMPONENT_Cb )
{
bestCostCb = singleCostTmp;
bestDistCb = singleDistCTmp;
}
else
{
bestCostCr = singleCostTmp;
bestDistCr = singleDistCTmp;
}
#if JVET_P0058_CHROMA_TS
if (currTU.mtsIdx[compID] == MTS_DCT2_DCT2)
{
cbfDCT2 = TU::getCbfAtDepth(currTU, compID, currDepth);
}
#endif

Karsten Suehring
committed
if( !isLastMode )
{
#if KEEP_PRED_AND_RESI_SIGNALS
saveCS.getPredBuf (area).copyFrom(cs.getPredBuf (area));
saveCS.getOrgResiBuf(area).copyFrom(cs.getOrgResiBuf(area));
#endif
saveCS.getPredBuf (area).copyFrom(cs.getPredBuf (area));

Karsten Suehring
committed
if( keepResi )
{
saveCS.getResiBuf (area).copyFrom(cs.getResiBuf (area));
}
saveCS.getRecoBuf (area).copyFrom(cs.getRecoBuf (area));
tmpTU.copyComponentFrom(currTU, compID);
ctxBest = m_CABACEstimator->getCtx();
}
}
}
}
if( lumaUsesISP && dSingleCost > bestCostSoFar && c == COMPONENT_Cb )
{
//Luma + Cb cost is already larger than the best cost, so we don't need to test Cr
cs.dist = MAX_UINT;
m_CABACEstimator->getCtx() = ctxStart;
break;
//return cbfs;
}
// Done with one component of separate coding of Cr and Cb, just switch to the best Cb contexts if Cr coding is still to be done
if ( c == COMPONENT_Cb && bestModeId < totalModesToTest)
{
m_CABACEstimator->getCtx() = ctxBest;
currTU.copyComponentFrom(tmpTU, COMPONENT_Cb); // Cbf of Cb is needed to estimate cost for Cr Cbf
}
}
if ( !earlyExitISP )
{
// Test using joint chroma residual coding
double bestCostCbCr = bestCostCb + bestCostCr;
Distortion bestDistCbCr = bestDistCb + bestDistCr;
int bestJointCbCr = 0;
bool lastIsBest = false;
std::vector<int> jointCbfMasksToTest;
if ( cs.sps->getJointCbCrEnabledFlag() && (TU::getCbf(tmpTU, COMPONENT_Cb) || TU::getCbf(tmpTU, COMPONENT_Cr)))
jointCbfMasksToTest = m_pcTrQuant->selectICTCandidates(currTU, orgResiCb, orgResiCr);
}
for( int cbfMask : jointCbfMasksToTest )
currTU.jointCbCr = (uint8_t)cbfMask;
currTU.compAlpha[COMPONENT_Cb] = 0;
currTU.compAlpha[COMPONENT_Cr] = 0;
#if JVET_P0058_CHROMA_TS
// encoder bugfix: initialize mtsIdx for chroma under JointCbCrMode.
currTU.mtsIdx[COMPONENT_Cb] = currTU.mtsIdx[COMPONENT_Cr] = MTS_DCT2_DCT2;
#endif
m_CABACEstimator->getCtx() = ctxStartTU;
resiCb.copyFrom( orgResiCb[cbfMask] );
resiCr.copyFrom( orgResiCr[cbfMask] );
xIntraCodingTUBlock( currTU, COMPONENT_Cb, false, distTmp, 0 );
double costTmp = std::numeric_limits<double>::max();
if( distTmp < std::numeric_limits<Distortion>::max() )
{
uint64_t bits = xGetIntraFracBitsQTChroma( currTU, COMPONENT_Cb );
costTmp = m_pcRdCost->calcRdCost( bits, distTmp );
}
if( costTmp < bestCostCbCr )
{
bestCostCbCr = costTmp;
bestDistCbCr = distTmp;
3698
3699
3700
3701
3702
3703
3704
3705
3706
3707
3708
3709
3710
3711
3712
3713
3714
3715
3716
3717
3718
3719
3720
3721
3722
3723
3724
3725
bestJointCbCr = currTU.jointCbCr;
// store data
if( cbfMask != jointCbfMasksToTest.back() )
{
#if KEEP_PRED_AND_RESI_SIGNALS
saveCS.getOrgResiBuf(cbArea).copyFrom(cs.getOrgResiBuf(cbArea));
saveCS.getOrgResiBuf(crArea).copyFrom(cs.getOrgResiBuf(crArea));
#endif
saveCS.getPredBuf (cbArea).copyFrom(cs.getPredBuf (cbArea));
saveCS.getPredBuf (crArea).copyFrom(cs.getPredBuf (crArea));
if( keepResi )
{
saveCS.getResiBuf (cbArea).copyFrom(cs.getResiBuf (cbArea));
saveCS.getResiBuf (crArea).copyFrom(cs.getResiBuf (crArea));
}
saveCS.getRecoBuf (cbArea).copyFrom(cs.getRecoBuf (cbArea));
saveCS.getRecoBuf (crArea).copyFrom(cs.getRecoBuf (crArea));
tmpTU.copyComponentFrom(currTU, COMPONENT_Cb);
tmpTU.copyComponentFrom(currTU, COMPONENT_Cr);
ctxBest = m_CABACEstimator->getCtx();
}
else
{
lastIsBest = true;
}
// Retrieve the best CU data (unless it was the very last one tested)
if ( !( maxModesTested == 1 && jointCbfMasksToTest.empty() ) && !lastIsBest )
{
#if KEEP_PRED_AND_RESI_SIGNALS
cs.getPredBuf (cbArea).copyFrom(saveCS.getPredBuf (cbArea));
cs.getOrgResiBuf(cbArea).copyFrom(saveCS.getOrgResiBuf(cbArea));
cs.getPredBuf (crArea).copyFrom(saveCS.getPredBuf (crArea));
cs.getOrgResiBuf(crArea).copyFrom(saveCS.getOrgResiBuf(crArea));
#endif
cs.getPredBuf (cbArea).copyFrom(saveCS.getPredBuf (cbArea));
cs.getPredBuf (crArea).copyFrom(saveCS.getPredBuf (crArea));
if( keepResi )
{
cs.getResiBuf (cbArea).copyFrom(saveCS.getResiBuf (cbArea));
cs.getResiBuf (crArea).copyFrom(saveCS.getResiBuf (crArea));
}
cs.getRecoBuf (cbArea).copyFrom(saveCS.getRecoBuf (cbArea));
cs.getRecoBuf (crArea).copyFrom(saveCS.getRecoBuf (crArea));
currTU.copyComponentFrom(tmpTU, COMPONENT_Cb);
currTU.copyComponentFrom(tmpTU, COMPONENT_Cr);
m_CABACEstimator->getCtx() = ctxBest;
}
// Copy results to the picture structures
cs.picture->getRecoBuf(cbArea).copyFrom(cs.getRecoBuf(cbArea));
cs.picture->getRecoBuf(crArea).copyFrom(cs.getRecoBuf(crArea));
cs.picture->getPredBuf(cbArea).copyFrom(cs.getPredBuf(cbArea));
cs.picture->getPredBuf(crArea).copyFrom(cs.getPredBuf(crArea));
cbfs.cbf(COMPONENT_Cb) = TU::getCbf(currTU, COMPONENT_Cb);
cbfs.cbf(COMPONENT_Cr) = TU::getCbf(currTU, COMPONENT_Cr);
currTU.jointCbCr = ( (cbfs.cbf(COMPONENT_Cb) + cbfs.cbf(COMPONENT_Cr)) ? bestJointCbCr : 0 );

Karsten Suehring
committed
}
}
else
{
unsigned numValidTBlocks = ::getNumberValidTBlocks( *cs.pcv );
ChromaCbfs SplitCbfs ( false );
if( partitioner.canSplit( TU_MAX_TR_SPLIT, cs ) )
{
partitioner.splitCurrArea( TU_MAX_TR_SPLIT, cs );
}
else if( currTU.cu->ispMode )
{
partitioner.splitCurrArea( ispType, cs );
}

Karsten Suehring
committed
else
THROW( "Implicit TU split not available" );
do
{
ChromaCbfs subCbfs = xRecurIntraChromaCodingQT( cs, partitioner, bestCostSoFar, ispType );

Karsten Suehring
committed
for( uint32_t ch = COMPONENT_Cb; ch < numValidTBlocks; ch++ )
{
const ComponentID compID = ComponentID( ch );
SplitCbfs.cbf( compID ) |= subCbfs.cbf( compID );
}
} while( partitioner.nextPart( cs ) );
partitioner.exitCurrSplit();
if( lumaUsesISP && cs.dist == MAX_UINT )
{
return cbfs;
}

Karsten Suehring
committed
{
cbfs.Cb |= SplitCbfs.Cb;
cbfs.Cr |= SplitCbfs.Cr;
if( !lumaUsesISP )
{
for( auto &ptu : cs.tus )
{
if( currArea.Cb().contains( ptu->Cb() ) || ( !ptu->Cb().valid() && currArea.Y().contains( ptu->Y() ) ) )
{
TU::setCbfAtDepth( *ptu, COMPONENT_Cb, currDepth, SplitCbfs.Cb );
TU::setCbfAtDepth( *ptu, COMPONENT_Cr, currDepth, SplitCbfs.Cr );
}
}
}

Karsten Suehring
committed
}
}
return cbfs;
}
uint64_t IntraSearch::xFracModeBitsIntra(PredictionUnit &pu, const uint32_t &uiMode, const ChannelType &chType)
{
uint32_t orgMode = uiMode;

Karsten Suehring
committed
std::swap(orgMode, pu.intraDir[chType]);
m_CABACEstimator->resetBits();
if( isLuma( chType ) )
{
{
m_CABACEstimator->intra_luma_pred_mode(pu);
}

Karsten Suehring
committed
}
else
{
m_CABACEstimator->intra_chroma_pred_mode( pu );
}

Karsten Suehring
committed
std::swap(orgMode, pu.intraDir[chType]);
return m_CABACEstimator->getEstFracBits();
}
void IntraSearch::encPredIntraDPCM( const ComponentID &compID, PelBuf &pOrg, PelBuf &pDst, const uint32_t &uiDirMode )
{
CHECK( pOrg.buf == 0, "Encoder DPCM called without original buffer" );
const int srcStride = m_refBufferStride[compID];

Karsten Suehring
committed
CPelBuf pSrc = CPelBuf(getPredictorPtr(compID), srcStride, m_leftRefLength + 1);
// Sample Adaptive intra-Prediction (SAP)
if( uiDirMode == HOR_IDX )
{
// left column filled with reference samples, remaining columns filled with pOrg data
for( int y = 0; y < pDst.height; y++ )
{
pDst.at(0, y) = pSrc.at(1 + y, 1);

Karsten Suehring
committed
3866
3867
3868
3869
3870
3871
3872
3873
3874
3875
3876
3877
3878
3879
3880
3881
3882
3883
3884
3885
3886
3887
3888
3889
}
CPelBuf orgRest = pOrg.subBuf( 0, 0, pOrg.width - 1, pOrg.height );
PelBuf predRest = pDst.subBuf( 1, 0, pDst.width - 1, pDst.height );
predRest.copyFrom( orgRest );
}
else // VER_IDX
{
// top row filled with reference samples, remaining rows filled with pOrg data
for( int x = 0; x < pDst.width; x++ )
{
pDst.at( x, 0 ) = pSrc.at( 1 + x, 0 );
}
CPelBuf orgRest = pOrg.subBuf( 0, 0, pOrg.width, pOrg.height - 1 );
PelBuf predRest = pDst.subBuf( 0, 1, pDst.width, pDst.height - 1 );
predRest.copyFrom( orgRest );
}
}
bool IntraSearch::useDPCMForFirstPassIntraEstimation( const PredictionUnit &pu, const uint32_t &uiDirMode )
{
return CU::isRDPCMEnabled( *pu.cu ) && pu.cu->transQuantBypass && (uiDirMode == HOR_IDX || uiDirMode == VER_IDX);
}
template<typename T, size_t N>
void IntraSearch::reduceHadCandList(static_vector<T, N>& candModeList, static_vector<double, N>& candCostList, int& numModesForFullRD, const double thresholdHadCost, const double* mipHadCost, const PredictionUnit &pu, const bool fastMip)
{
const int maxCandPerType = numModesForFullRD >> 1;
static_vector<ModeInfo, FAST_UDI_MAX_RDMODE_NUM> tempRdModeList;
static_vector<double, FAST_UDI_MAX_RDMODE_NUM> tempCandCostList;
const double minCost = candCostList[0];
bool keepOneMip = candModeList.size() > numModesForFullRD;

Christian Helmrich
committed
int numConv = 0;
int numMip = 0;
for (int idx = 0; idx < candModeList.size() - (keepOneMip?0:1); idx++)
{
bool addMode = false;
addMode = (numConv < 3);
numConv += addMode ? 1:0;
addMode = ( numMip < maxCandPerType || (candCostList[idx] < thresholdHadCost * minCost) || keepOneMip );
keepOneMip = false;
numMip += addMode ? 1:0;
}
if( addMode )
{
tempCandCostList.push_back(candCostList[idx]);
}
}
if ((pu.lwidth() > 8 && pu.lheight() > 8))
{
// Sort MIP candidates by Hadamard cost
#if JVET_P0803_COMBINED_MIP_CLEANUP
const int transpOff = getNumModesMip( pu.Y() );
#else
const int transpOff = getNumModesMip(pu.Y()) / 2;
static_vector<uint8_t, FAST_UDI_MAX_RDMODE_NUM> sortedMipModes(0);
static_vector<double, FAST_UDI_MAX_RDMODE_NUM> sortedMipCost(0);
#if JVET_P0803_COMBINED_MIP_CLEANUP
for( uint8_t mode : { 0, 1, 2 } )
#else
{
uint8_t candMode = mode + uint8_t((mipHadCost[mode + transpOff] < mipHadCost[mode]) ? transpOff : 0);
updateCandList(candMode, mipHadCost[candMode], sortedMipModes, sortedMipCost, 3);
}
// Append MIP mode to RD mode list
const int modeListSize = int(tempRdModeList.size());
for (int idx = 0; idx < 3; idx++)
{
#if JVET_P0803_COMBINED_MIP_CLEANUP
const bool isTransposed = (sortedMipModes[idx] >= transpOff ? true : false);
const uint32_t mipIdx = (isTransposed ? sortedMipModes[idx] - transpOff : sortedMipModes[idx]);
const ModeInfo mipMode( true, isTransposed, 0, NOT_INTRA_SUBPARTITIONS, mipIdx );
#else
const ModeInfo mipMode(true, 0, NOT_INTRA_SUBPARTITIONS, sortedMipModes[idx]);
for (int modeListIdx = 0; modeListIdx < modeListSize; modeListIdx++)
3958
3959
3960
3961
3962
3963
3964
3965
3966
3967
3968
3969
3970
3971
3972
3973
3974
3975
3976
3977
3978
{
if (tempRdModeList[modeListIdx] == mipMode)
{
alreadyIncluded = true;
break;
}
}
if (!alreadyIncluded)
{
tempRdModeList.push_back(mipMode);
tempCandCostList.push_back(0);
if( fastMip ) break;
}
}
}
candModeList = tempRdModeList;
candCostList = tempCandCostList;
numModesForFullRD = int(candModeList.size());
}
// It decides which modes from the ISP lists can be full RD tested
void IntraSearch::xGetNextISPMode(ModeInfo& modeInfo, const ModeInfo* lastMode, const Size cuSize)
{
static_vector<ModeInfo, FAST_UDI_MAX_RDMODE_NUM>* rdModeLists[2] = { &m_ispCandListHor, &m_ispCandListVer };
ISPType nextISPcandSplitType;
auto& ispTestedModes = m_ispTestedModes;
const bool horSplitIsTerminated = ispTestedModes.splitIsFinished[HOR_INTRA_SUBPARTITIONS - 1];
const bool verSplitIsTerminated = ispTestedModes.splitIsFinished[VER_INTRA_SUBPARTITIONS - 1];
if (!horSplitIsTerminated && !verSplitIsTerminated)
{
nextISPcandSplitType = !lastMode ? HOR_INTRA_SUBPARTITIONS : lastMode->ispMod == HOR_INTRA_SUBPARTITIONS ? VER_INTRA_SUBPARTITIONS : HOR_INTRA_SUBPARTITIONS;
}
else if (!horSplitIsTerminated && verSplitIsTerminated)
{
nextISPcandSplitType = HOR_INTRA_SUBPARTITIONS;
}
else if (horSplitIsTerminated && !verSplitIsTerminated)
{
nextISPcandSplitType = VER_INTRA_SUBPARTITIONS;
}