Newer
Older
3004
3005
3006
3007
3008
3009
3010
3011
3012
3013
3014
3015
3016
3017
3018
3019
3020
3021
3022
3023
3024
3025
3026
3027
3028
3029
3030
3031
3032
3033
}
int candHasNoResidual[MRG_MAX_NUM_CANDS];
for (unsigned int ui = 0; ui < mergeCtx.numValidMergeCand; ui++)
{
candHasNoResidual[ui] = 0;
}
bool bestIsSkip = false;
unsigned numMrgSATDCand = mergeCtx.numValidMergeCand;
static_vector<unsigned, MRG_MAX_NUM_CANDS> RdModeList(MRG_MAX_NUM_CANDS);
for (unsigned i = 0; i < MRG_MAX_NUM_CANDS; i++)
{
RdModeList[i] = i;
}
//{
static_vector<double, MRG_MAX_NUM_CANDS> candCostList(MRG_MAX_NUM_CANDS, MAX_DOUBLE);
// 1. Pass: get SATD-cost for selected candidates and reduce their count
{
const double sqrtLambdaForFirstPass = m_pcRdCost->getMotionLambda(encTestMode.lossless);
CodingUnit &cu = tempCS->addCU(CS::getArea(*tempCS, tempCS->area, (const ChannelType)partitioner.chType), (const ChannelType)partitioner.chType);
partitioner.setCUData(cu);
cu.slice = tempCS->slice;
#if HEVC_TILES_WPP
cu.tileIdx = tempCS->picture->tileMap->getTileIdxMap(tempCS->area.lumaPos());
#endif
cu.skip = false;
cu.transQuantBypass = encTestMode.lossless;
cu.chromaQpAdj = cu.transQuantBypass ? 0 : m_cuChromaQpOffsetIdxPlus1;
cu.qp = encTestMode.qp;
cu.mmvdSkip = false;
cu.triangle = false;
DistParam distParam;
const bool bUseHadamard = !encTestMode.lossless;
PredictionUnit &pu = tempCS->addPU(cu, partitioner.chType); //tempCS->addPU(cu);
pu.mmvdMergeFlag = false;
Picture* refPic = pu.cu->slice->getPic();
const CPelBuf refBuf = refPic->getRecoBuf(pu.blocks[COMPONENT_Y]);
const Pel* piRefSrch = refBuf.buf;
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;
}
3070
3071
3072
3073
3074
3075
3076
3077
3078
3079
3080
3081
3082
3083
3084
3085
3086
3087
3088
3089
3090
3091
3092
3093
3094
3095
3096
3097
3098
3099
3100
3101
3102
3103
3104
3105
3106
3107
3108
3109
3110
3111
3112
3113
3114
3115
3116
3117
3118
3119
3120
3121
3122
3123
3124
3125
3126
3127
3128
3129
3130
3131
3132
3133
3134
3135
3136
3137
3138
mergeCtx.setMergeInfo(pu, mergeCand); // set bv info in merge mode
const int cuPelX = pu.Y().x;
const int cuPelY = pu.Y().y;
int roiWidth = pu.lwidth();
int roiHeight = pu.lheight();
const int picWidth = pu.cs->slice->getSPS()->getPicWidthInLumaSamples();
const int picHeight = pu.cs->slice->getSPS()->getPicHeightInLumaSamples();
const unsigned int lcuWidth = pu.cs->slice->getSPS()->getMaxCUWidth();
int xPred = pu.bv.getHor();
int yPred = pu.bv.getVer();
if (!PU::isBlockVectorValid(pu, cuPelX, cuPelY, roiWidth, roiHeight, picWidth, picHeight, 0, 0, xPred, yPred, lcuWidth)) // not valid bv derived
{
numValidBv--;
continue;
}
PU::spanMotionInfo(pu, mergeCtx);
distParam.cur.buf = piRefSrch + refStride * yPred + xPred;
Distortion sad = distParam.distFunc(distParam);
unsigned int bitsCand = mergeCand + 1;
if (mergeCand == tempCS->slice->getMaxNumMergeCand() - 1)
{
bitsCand--;
}
double cost = (double)sad + (double)bitsCand * sqrtLambdaForFirstPass;
static_vector<int, MRG_MAX_NUM_CANDS> * nullList = nullptr;
updateCandList(mergeCand, cost, RdModeList, candCostList
, *nullList, -1
, numMrgSATDCand);
}
// Try to limit number of candidates using SATD-costs
if (numValidBv)
{
numMrgSATDCand = numValidBv;
for (unsigned int i = 1; i < numValidBv; i++)
{
if (candCostList[i] > MRG_FAST_RATIO*candCostList[0])
{
numMrgSATDCand = i;
break;
}
}
}
else
{
tempCS->dist = 0;
tempCS->fracBits = 0;
tempCS->cost = MAX_DOUBLE;
tempCS->initStructData(encTestMode.qp, encTestMode.lossless);
return;
}
tempCS->initStructData(encTestMode.qp, encTestMode.lossless);
}
//}
const unsigned int iteration = encTestMode.lossless ? 1 : 2;
// 2. Pass: check candidates using full RD test
for (unsigned int numResidualPass = 0; numResidualPass < iteration; numResidualPass++)
{
for (unsigned int mrgHADIdx = 0; mrgHADIdx < numMrgSATDCand; mrgHADIdx++)
{
unsigned int mergeCand = RdModeList[mrgHADIdx];
if (mergeCtx.interDirNeighbours[mergeCand] != 1)
{
continue;
}
if (tempCS->slice->getRefPic(REF_PIC_LIST_0, mergeCtx.mvFieldNeighbours[mergeCand << 1].refIdx)->getPOC() != tempCS->slice->getPOC())
{
continue;
}
if (!(numResidualPass == 1 && candHasNoResidual[mergeCand] == 1))
{
if (!(bestIsSkip && (numResidualPass == 0)))
{
unsigned char considerEmtSecondPass = 0;
bool skipSecondEmtPass = true;
bool hasResidual[2] = { false, false };
double emtCost[2] = { MAX_DOUBLE, MAX_DOUBLE };
// CU-level optimization
for (unsigned char emtCuFlag = 0; emtCuFlag <= considerEmtSecondPass; emtCuFlag++)
{
if (m_pcEncCfg->getFastInterEMT() && emtCuFlag && skipSecondEmtPass)
{
continue;
}
// first get merge candidates
CodingUnit &cu = tempCS->addCU(CS::getArea(*tempCS, tempCS->area, (const ChannelType)partitioner.chType), (const ChannelType)partitioner.chType);
partitioner.setCUData(cu);
cu.slice = tempCS->slice;
#if HEVC_TILES_WPP
cu.tileIdx = tempCS->picture->tileMap->getTileIdxMap(tempCS->area.lumaPos());
#endif
cu.skip = false;
cu.transQuantBypass = encTestMode.lossless;
cu.chromaQpAdj = cu.transQuantBypass ? 0 : m_cuChromaQpOffsetIdxPlus1;
cu.qp = encTestMode.qp;
PredictionUnit &pu = tempCS->addPU(cu, partitioner.chType);// tempCS->addPU(cu);
pu.intraDir[0] = DC_IDX; // set intra pred for ibc block
pu.intraDir[1] = PLANAR_IDX; // set intra pred for ibc block
cu.mmvdSkip = false;
pu.mmvdMergeFlag = false;
cu.triangle = false;
mergeCtx.setMergeInfo(pu, mergeCand);
PU::spanMotionInfo(pu, mergeCtx);
assert(mergeCtx.mrgTypeNeighbours[mergeCand] == MRG_TYPE_IBC); // should be IBC candidate at this round
const bool chroma = !(CS::isDualITree(*tempCS));
// MC
m_pcInterSearch->motionCompensation(pu,REF_PIC_LIST_0, true, chroma);
m_CABACEstimator->getCtx() = m_CurrCtx->start;
m_pcInterSearch->encodeResAndCalcRdInterCU(*tempCS, partitioner, (numResidualPass != 0), true, chroma);
xEncodeDontSplit(*tempCS, partitioner);
if (tempCS->pps->getUseDQP() && (partitioner.currDepth) <= tempCS->pps->getMaxCuDQPDepth())
{
xCheckDQP(*tempCS, partitioner);
}
hasResidual[emtCuFlag] = cu.rootCbf;
emtCost[emtCuFlag] = tempCS->cost;
DTRACE_MODE_COST(*tempCS, m_pcRdCost->getLambda());
xCheckBestMode(tempCS, bestCS, partitioner, encTestMode);
tempCS->initStructData(encTestMode.qp, encTestMode.lossless);
}
if (numResidualPass == 0 && (emtCost[0] <= emtCost[1] ? !hasResidual[0] : !hasResidual[1]))
{
// If no residual when allowing for one, then set mark to not try case where residual is forced to 0
candHasNoResidual[mergeCand] = 1;
}
if (m_pcEncCfg->getUseFastDecisionForMerge() && !bestIsSkip)
{
if (bestCS->getCU(partitioner.chType) == NULL)
bestIsSkip = 0;
else
bestIsSkip = bestCS->getCU(partitioner.chType)->rootCbf == 0;
}
}
}
}
}
}
void EncCu::xCheckRDCostIBCMode(CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &partitioner, const EncTestMode& encTestMode)
if (tempCS->area.lwidth() > IBC_MAX_CAND_SIZE || tempCS->area.lheight() > IBC_MAX_CAND_SIZE) // currently only check 32x32 and below block for ibc merge/skip
{
return;
}
tempCS->initStructData(encTestMode.qp, encTestMode.lossless);
CodingUnit &cu = tempCS->addCU(CS::getArea(*tempCS, tempCS->area, partitioner.chType), partitioner.chType);
partitioner.setCUData(cu);
cu.slice = tempCS->slice;
#if HEVC_TILES_WPP
cu.tileIdx = tempCS->picture->tileMap->getTileIdxMap(tempCS->area.lumaPos());
#endif
cu.skip = false;
cu.transQuantBypass = encTestMode.lossless;
cu.chromaQpAdj = cu.transQuantBypass ? 0 : m_cuChromaQpOffsetIdxPlus1;
cu.qp = encTestMode.qp;
cu.imv = 0;
CU::addPUs(cu);
PredictionUnit& pu = *cu.firstPU;
cu.mmvdSkip = false;
pu.mmvdMergeFlag = false;
pu.intraDir[0] = DC_IDX; // set intra pred for ibc block
pu.intraDir[1] = PLANAR_IDX; // set intra pred for ibc block
#if JVET_M0483_IBC
pu.refIdx[REF_PIC_LIST_0] = MAX_NUM_REF; // last idx in the list
pu.refIdx[REF_PIC_LIST_0] = pu.cs->slice->getNumRefIdx(REF_PIC_LIST_0) - 1; // last idx in the list
bool bValid = m_pcInterSearch->predIBCSearch(cu, partitioner, m_ctuIbcSearchRangeX, m_ctuIbcSearchRangeY, m_ibcHashMap);
if (bValid)
{
PU::spanMotionInfo(pu);
const bool chroma = !(CS::isDualITree(*tempCS));
// MC
m_pcInterSearch->motionCompensation(pu, REF_PIC_LIST_0, true, chroma);
double bestCost = bestCS->cost;
unsigned char considerEmtSecondPass = 0;
bool skipSecondEmtPass = true;
double emtFirstPassCost = MAX_DOUBLE;
// CU-level optimization
for (unsigned char emtCuFlag = 0; emtCuFlag <= considerEmtSecondPass; emtCuFlag++)
{
if (m_pcEncCfg->getFastInterEMT() && emtCuFlag && skipSecondEmtPass)
{
continue;
}
tempCS->getCU(tempCS->chType)->emtFlag = emtCuFlag;
m_pcInterSearch->encodeResAndCalcRdInterCU(*tempCS, partitioner, false, true, chroma);
if (m_pcEncCfg->getFastInterEMT())
{
emtFirstPassCost = (!emtCuFlag) ? tempCS->cost : emtFirstPassCost;
}
xEncodeDontSplit(*tempCS, partitioner);
if (tempCS->pps->getUseDQP() && (partitioner.currDepth) <= tempCS->pps->getMaxCuDQPDepth())
{
xCheckDQP(*tempCS, partitioner);
}
DTRACE_MODE_COST(*tempCS, m_pcRdCost->getLambda());
xCheckBestMode(tempCS, bestCS, partitioner, encTestMode);
3345
3346
3347
3348
3349
3350
3351
3352
3353
3354
3355
3356
3357
3358
3359
3360
3361
3362
3363
3364
3365
3366
3367
3368
3369
3370
3371
3372
//now we check whether the second pass should be skipped or not
if (!emtCuFlag && considerEmtSecondPass)
{
static const double thresholdToSkipEmtSecondPass = 1.1; // Skip checking EMT transforms
if (m_pcEncCfg->getFastInterEMT() && (!cu.firstTU->cbf[COMPONENT_Y] || emtFirstPassCost > bestCost * thresholdToSkipEmtSecondPass))
{
skipSecondEmtPass = true;
}
else //EMT will be checked
{
if (bestCost == bestCS->cost) //The first EMT pass didn't become the bestCS, so we clear the TUs generated
{
tempCS->clearTUs();
}
else
{
tempCS->initStructData(bestCS->currQP[bestCS->chType], bestCS->isLossless);
tempCS->copyStructure(*bestCS, partitioner.chType);
tempCS->getPredBuf().copyFrom(bestCS->getPredBuf());
}
//we need to restart the distortion for the new tempCS, the bit count and the cost
tempCS->dist = 0;
tempCS->fracBits = 0;
tempCS->cost = MAX_DOUBLE;
}
}
}
} // bValid
else
{
tempCS->dist = 0;
tempCS->fracBits = 0;
tempCS->cost = MAX_DOUBLE;
}
}
else
{
bool success = true;
// chroma tree, reuse luma bv at minimal block level
// enabled search only when each chroma sub-block has a BV from its luma sub-block
assert(tempCS->getIbcLumaCoverage(pu.Cb()) == IBC_LUMA_COVERAGE_FULL);
3391
3392
3393
3394
3395
3396
3397
3398
3399
3400
3401
3402
3403
3404
3405
3406
3407
3408
3409
3410
3411
3412
3413
3414
3415
3416
3417
3418
3419
3420
3421
3422
3423
3424
// check if each BV for the chroma sub-block is valid
//static const UInt unitArea = MIN_PU_SIZE * MIN_PU_SIZE;
const CompArea lumaArea = CompArea(COMPONENT_Y, pu.chromaFormat, pu.Cb().lumaPos(), recalcSize(pu.chromaFormat, CHANNEL_TYPE_CHROMA, CHANNEL_TYPE_LUMA, pu.Cb().size()));
PredictionUnit subPu;
subPu.cs = pu.cs;
subPu.cu = pu.cu;
const ComponentID compID = COMPONENT_Cb; // use Cb to represent both Cb and CR, as their structures are the same
int shiftHor = ::getComponentScaleX(compID, pu.chromaFormat);
int shiftVer = ::getComponentScaleY(compID, pu.chromaFormat);
//const ChromaFormat chFmt = pu.chromaFormat;
for (int y = lumaArea.y; y < lumaArea.y + lumaArea.height; y += MIN_PU_SIZE)
{
for (int x = lumaArea.x; x < lumaArea.x + lumaArea.width; x += MIN_PU_SIZE)
{
const MotionInfo &curMi = pu.cs->picture->cs->getMotionInfo(Position{ x, y });
subPu.UnitArea::operator=(UnitArea(pu.chromaFormat, Area(x, y, MIN_PU_SIZE, MIN_PU_SIZE)));
Position offsetRef = subPu.blocks[compID].pos().offset((curMi.bv.getHor() >> shiftHor), (curMi.bv.getVer() >> shiftVer));
Position refEndPos(offsetRef.x + subPu.blocks[compID].size().width - 1, offsetRef.y + subPu.blocks[compID].size().height - 1 );
if (!subPu.cs->isDecomp(refEndPos, toChannelType(compID)) || !subPu.cs->isDecomp(offsetRef, toChannelType(compID))) // ref block is not yet available for this chroma sub-block
{
success = false;
break;
}
}
if (!success)
break;
}
////////////////////////////////////////////////////////////////////////////
if (success)
{
m_pcInterSearch->motionCompensation(pu, REF_PIC_LIST_0, false, true); // luma=0, chroma=1
m_pcInterSearch->encodeResAndCalcRdInterCU(*tempCS, partitioner, false, false, true);
xEncodeDontSplit(*tempCS, partitioner);
xCheckDQP(*tempCS, partitioner);
DTRACE_MODE_COST(*tempCS, m_pcRdCost->getLambda());
xCheckBestMode(tempCS, bestCS, partitioner, encTestMode);
}
else
{
tempCS->dist = 0;
tempCS->fracBits = 0;
tempCS->cost = MAX_DOUBLE;
}
}
}
//////////////////////////////////////////////////////////////////////////////////////////////

Karsten Suehring
committed
void EncCu::xCheckRDCostInter( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &partitioner, const EncTestMode& encTestMode )
{
tempCS->initStructData( encTestMode.qp, encTestMode.lossless );
3452
3453
3454
3455
3456
3457
3458
3459
3460
3461
3462
3463
3464
3465
3466
3467
3468
3469
3470
3471
3472
3473
3474
3475
3476
3477
3478
3479
3480
3481
3482
3483
3484
3485
3486
3487
3488
3489
3490
3491
3492
3493
3494
3495
3496
m_pcInterSearch->setAffineModeSelected(false);
if( tempCS->slice->getCheckLDC() )
{
m_bestGbiCost[0] = m_bestGbiCost[1] = std::numeric_limits<double>::max();
m_bestGbiIdx[0] = m_bestGbiIdx[1] = -1;
}
m_pcInterSearch->resetBufferedUniMotions();
int gbiLoopNum = (tempCS->slice->isInterB() ? GBI_NUM : 1);
gbiLoopNum = (tempCS->sps->getSpsNext().getUseGBi() ? gbiLoopNum : 1);
if( tempCS->area.lwidth() * tempCS->area.lheight() < GBI_SIZE_CONSTRAINT )
{
gbiLoopNum = 1;
}
double curBestCost = bestCS->cost;
double equGBiCost = MAX_DOUBLE;
for( int gbiLoopIdx = 0; gbiLoopIdx < gbiLoopNum; gbiLoopIdx++ )
{
if( m_pcEncCfg->getUseGBiFast() )
{
auto blkCache = dynamic_cast< CacheBlkInfoCtrl* >(m_modeCtrl);
if( blkCache )
{
bool isBestInter = blkCache->getInter(bestCS->area);
uint8_t bestGBiIdx = blkCache->getGbiIdx(bestCS->area);
if( isBestInter && g_GbiSearchOrder[gbiLoopIdx] != GBI_DEFAULT && g_GbiSearchOrder[gbiLoopIdx] != bestGBiIdx )
{
continue;
}
}
}
if( !tempCS->slice->getCheckLDC() )
{
if( gbiLoopIdx != 0 && gbiLoopIdx != 3 && gbiLoopIdx != 4 )
{
continue;
}
}

Karsten Suehring
committed
CodingUnit &cu = tempCS->addCU( tempCS->area, partitioner.chType );
partitioner.setCUData( cu );
cu.slice = tempCS->slice;
#if HEVC_TILES_WPP
cu.tileIdx = tempCS->picture->tileMap->getTileIdxMap( tempCS->area.lumaPos() );
#endif
cu.skip = false;
cu.mmvdSkip = false;

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

Karsten Suehring
committed
m_pcInterSearch->predInterSearch( cu, partitioner );
const unsigned wIdx = gp_sizeIdxInfo->idxFrom( tempCS->area.lwidth () );
gbiIdx = CU::getValidGbiIdx(cu);
if( testGbi && gbiIdx == GBI_DEFAULT ) // Enabled GBi but the search results is uni.
{
tempCS->initStructData(encTestMode.qp, encTestMode.lossless);
continue;
}
CHECK(!(testGbi || (!testGbi && gbiIdx == GBI_DEFAULT)), " !( bTestGbi || (!bTestGbi && gbiIdx == GBI_DEFAULT ) )");
bool isEqualUni = false;
if( m_pcEncCfg->getUseGBiFast() )
{
if( cu.firstPU->interDir != 3 && testGbi == 0 )
{
isEqualUni = true;
}
}
#if JVET_M0464_UNI_MTS
xEncodeInterResidual( tempCS, bestCS, partitioner, encTestMode, 0
, m_pImvTempCS ? m_pImvTempCS[wIdx] : NULL
, 0
, &equGBiCost
#else
xEncodeInterResidual( tempCS, bestCS, partitioner, encTestMode, 0
, 1
, 0
);
3553
3554
3555
3556
3557
3558
3559
3560
3561
3562
3563
3564
3565
3566
3567
3568
3569
3570
3571
3572
3573
3574
3575
3576
if( g_GbiSearchOrder[gbiLoopIdx] == GBI_DEFAULT )
m_pcInterSearch->setAffineModeSelected((bestCS->cus.front()->affine && !(bestCS->cus.front()->firstPU->mergeFlag)));
tempCS->initStructData(encTestMode.qp, encTestMode.lossless);
double skipTH = MAX_DOUBLE;
skipTH = (m_pcEncCfg->getUseGBiFast() ? 1.05 : MAX_DOUBLE);
if( equGBiCost > curBestCost * skipTH )
{
break;
}
if( m_pcEncCfg->getUseGBiFast() )
{
if( isEqualUni == true && m_pcEncCfg->getIntraPeriod() == -1 )
{
break;
}
}
if( g_GbiSearchOrder[gbiLoopIdx] == GBI_DEFAULT && xIsGBiSkip(cu) && m_pcEncCfg->getUseGBiFast() )
{
break;
}
} // for( UChar gbiLoopIdx = 0; gbiLoopIdx < gbiLoopNum; gbiLoopIdx++ )

Karsten Suehring
committed
}
bool EncCu::xCheckRDCostInterIMV( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &partitioner, const EncTestMode& encTestMode )
{
int iIMV = int( ( encTestMode.opts & ETO_IMV ) >> ETO_IMV_SHIFT );
m_pcInterSearch->setAffineModeSelected(false);

Karsten Suehring
committed
// Only int-Pel, 4-Pel and fast 4-Pel allowed
CHECK( iIMV != 1 && iIMV != 2 && iIMV != 3, "Unsupported IMV Mode" );
// Fast 4-Pel Mode
EncTestMode encTestModeBase = encTestMode; // copy for clearing non-IMV options
encTestModeBase.opts = EncTestModeOpts( encTestModeBase.opts & ETO_IMV ); // clear non-IMV options (is that intended?)
tempCS->initStructData( encTestMode.qp, encTestMode.lossless );
CodingStructure* pcCUInfo2Reuse = nullptr;
m_pcInterSearch->resetBufferedUniMotions();
int gbiLoopNum = (tempCS->slice->isInterB() ? GBI_NUM : 1);
gbiLoopNum = (pcCUInfo2Reuse != NULL ? 1 : gbiLoopNum);
gbiLoopNum = (tempCS->slice->getSPS()->getSpsNext().getUseGBi() ? gbiLoopNum : 1);
if( tempCS->area.lwidth() * tempCS->area.lheight() < GBI_SIZE_CONSTRAINT )
{
gbiLoopNum = 1;
}
#if JVET_M0246_AFFINE_AMVR
bool validMode = false;
#endif
3611
3612
3613
3614
3615
3616
3617
3618
3619
3620
3621
3622
3623
3624
3625
3626
3627
3628
3629
3630
3631
3632
3633
3634
3635
3636
3637
3638
3639
3640
3641
3642
3643
3644
3645
double curBestCost = bestCS->cost;
double equGBiCost = MAX_DOUBLE;
for( int gbiLoopIdx = 0; gbiLoopIdx < gbiLoopNum; gbiLoopIdx++ )
{
if( m_pcEncCfg->getUseGBiFast() )
{
auto blkCache = dynamic_cast< CacheBlkInfoCtrl* >(m_modeCtrl);
if( blkCache )
{
bool isBestInter = blkCache->getInter(bestCS->area);
uint8_t bestGBiIdx = blkCache->getGbiIdx(bestCS->area);
if( isBestInter && g_GbiSearchOrder[gbiLoopIdx] != GBI_DEFAULT && g_GbiSearchOrder[gbiLoopIdx] != bestGBiIdx )
{
continue;
}
}
}
if( !tempCS->slice->getCheckLDC() )
{
if( gbiLoopIdx != 0 && gbiLoopIdx != 3 && gbiLoopIdx != 4 )
{
continue;
}
}
if( m_pcEncCfg->getUseGBiFast() && tempCS->slice->getCheckLDC() && g_GbiSearchOrder[gbiLoopIdx] != GBI_DEFAULT
&& (m_bestGbiIdx[0] >= 0 && g_GbiSearchOrder[gbiLoopIdx] != m_bestGbiIdx[0])
&& (m_bestGbiIdx[1] >= 0 && g_GbiSearchOrder[gbiLoopIdx] != m_bestGbiIdx[1]))
{
continue;
}

Karsten Suehring
committed
CodingUnit &cu = ( pcCUInfo2Reuse != nullptr ) ? *tempCS->getCU( partitioner.chType ) : tempCS->addCU( tempCS->area, partitioner.chType );
if( pcCUInfo2Reuse == nullptr )
{
partitioner.setCUData( cu );
cu.slice = tempCS->slice;
#if HEVC_TILES_WPP
cu.tileIdx = tempCS->picture->tileMap->getTileIdxMap( tempCS->area.lumaPos() );
#endif
cu.skip = false;
cu.mmvdSkip = false;

Karsten Suehring
committed
//cu.affine
cu.predMode = MODE_INTER;
cu.transQuantBypass = encTestMode.lossless;
cu.chromaQpAdj = cu.transQuantBypass ? 0 : m_cuChromaQpOffsetIdxPlus1;
cu.qp = encTestMode.qp;
CU::addPUs( cu );
}
else
{
CHECK( cu.skip, "Mismatch" );
CHECK( cu.qtDepth != partitioner.currQtDepth, "Mismatch" );
CHECK( cu.btDepth != partitioner.currBtDepth, "Mismatch" );
CHECK( cu.mtDepth != partitioner.currMtDepth, "Mismatch" );
CHECK( cu.depth != partitioner.currDepth, "Mismatch" );
}
cu.imv = iIMV > 1 ? 2 : 1;

Karsten Suehring
committed
cu.emtFlag = false;

Karsten Suehring
committed
bool testGbi;
uint8_t gbiIdx;
#if JVET_M0246_AFFINE_AMVR
bool affineAmvrEanbledFlag = cu.slice->getSPS()->getAffineAmvrEnabledFlag();
#endif

Karsten Suehring
committed
if( pcCUInfo2Reuse != nullptr )
{
// reuse the motion info from pcCUInfo2Reuse
CU::resetMVDandMV2Int( cu, m_pcInterSearch );
CHECK(cu.GBiIdx < 0 || cu.GBiIdx >= GBI_NUM, "cu.GBiIdx < 0 || cu.GBiIdx >= GBI_NUM");
gbiIdx = CU::getValidGbiIdx(cu);
testGbi = (gbiIdx != GBI_DEFAULT);
#if JVET_M0246_AFFINE_AMVR
if ( !CU::hasSubCUNonZeroMVd( cu ) && !CU::hasSubCUNonZeroAffineMVd( cu ) )
#else

Karsten Suehring
committed
if( !CU::hasSubCUNonZeroMVd( cu ) )

Karsten Suehring
committed
{
if (m_modeCtrl->useModeResult(encTestModeBase, tempCS, partitioner))
{
std::swap(tempCS, bestCS);
// store temp best CI for next CU coding
m_CurrCtx->best = m_CABACEstimator->getCtx();
}
#if JVET_M0246_AFFINE_AMVR
if ( affineAmvrEanbledFlag )
{
tempCS->initStructData( encTestMode.qp, encTestMode.lossless );
continue;
}
else
{
return false;
}
#else

Karsten Suehring
committed
return false;

Karsten Suehring
committed
}
else
{
m_pcInterSearch->motionCompensation( cu );
}
}
else
{
cu.GBiIdx = g_GbiSearchOrder[gbiLoopIdx];
gbiIdx = cu.GBiIdx;
testGbi = (gbiIdx != GBI_DEFAULT);
#if JVET_M0246_AFFINE_AMVR
cu.firstPU->interDir = 10;
#endif

Karsten Suehring
committed
m_pcInterSearch->predInterSearch( cu, partitioner );
#if JVET_M0246_AFFINE_AMVR
if ( cu.firstPU->interDir <= 3 )
{
gbiIdx = CU::getValidGbiIdx(cu);
}
else
{
return false;
}
#else
gbiIdx = CU::getValidGbiIdx(cu);

Karsten Suehring
committed
}
if( testGbi && gbiIdx == GBI_DEFAULT ) // Enabled GBi but the search results is uni.
{
tempCS->initStructData(encTestMode.qp, encTestMode.lossless);
continue;
}
CHECK(!(testGbi || (!testGbi && gbiIdx == GBI_DEFAULT)), " !( bTestGbi || (!bTestGbi && gbiIdx == GBI_DEFAULT ) )");
bool isEqualUni = false;
if( m_pcEncCfg->getUseGBiFast() )
{
if( cu.firstPU->interDir != 3 && testGbi == 0 )
{
isEqualUni = true;
}
}
#if JVET_M0246_AFFINE_AMVR
if ( !CU::hasSubCUNonZeroMVd( cu ) && !CU::hasSubCUNonZeroAffineMVd( cu ) )
#else

Karsten Suehring
committed
if( !CU::hasSubCUNonZeroMVd( cu ) )

Karsten Suehring
committed
{
if (m_modeCtrl->useModeResult(encTestModeBase, tempCS, partitioner))
{
std::swap(tempCS, bestCS);
// store temp best CI for next CU coding
m_CurrCtx->best = m_CABACEstimator->getCtx();
}
#if JVET_M0246_AFFINE_AMVR
if ( affineAmvrEanbledFlag )
{
tempCS->initStructData( encTestMode.qp, encTestMode.lossless );
continue;
}
else
{
return false;
}
#else

Karsten Suehring
committed
return false;

Karsten Suehring
committed
}
#if JVET_M0464_UNI_MTS
xEncodeInterResidual( tempCS, bestCS, partitioner, encTestModeBase, 0
, NULL
, 0
, &equGBiCost
#else
xEncodeInterResidual( tempCS, bestCS, partitioner, encTestModeBase, 0
, NULL
, true
, 0

Karsten Suehring
committed
tempCS->initStructData(encTestMode.qp, encTestMode.lossless);
double skipTH = MAX_DOUBLE;
skipTH = (m_pcEncCfg->getUseGBiFast() ? 1.05 : MAX_DOUBLE);
if( equGBiCost > curBestCost * skipTH )
{
break;
}
if( m_pcEncCfg->getUseGBiFast() )
{
if( isEqualUni == true && m_pcEncCfg->getIntraPeriod() == -1 )
{
break;
}
}
if( g_GbiSearchOrder[gbiLoopIdx] == GBI_DEFAULT && xIsGBiSkip(cu) && m_pcEncCfg->getUseGBiFast() )
{
break;
}
#if JVET_M0246_AFFINE_AMVR
validMode = true;
#endif
} // for( UChar gbiLoopIdx = 0; gbiLoopIdx < gbiLoopNum; gbiLoopIdx++ )
#if JVET_M0246_AFFINE_AMVR
return tempCS->slice->getSPS()->getAffineAmvrEnabledFlag() ? validMode : true;
#else

Karsten Suehring
committed
return true;

Karsten Suehring
committed
}
#if JVET_M0464_UNI_MTS
void EncCu::xEncodeInterResidual( CodingStructure *&tempCS
, CodingStructure *&bestCS
, Partitioner &partitioner
, const EncTestMode& encTestMode
, int residualPass
, CodingStructure* imvCS
, bool* bestHasNonResi
, double* equGBiCost
#else
void EncCu::xEncodeInterResidual( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &partitioner, const EncTestMode& encTestMode, int residualPass
, CodingStructure* imvCS
, int emtMode
, bool* bestHasNonResi

Karsten Suehring
committed
{
if( residualPass == 1 && encTestMode.lossless )
{
return;
}
CodingUnit* cu = tempCS->getCU( partitioner.chType );
double bestCostInternal = MAX_DOUBLE;
double bestCost = bestCS->cost;
const SPS& sps = *tempCS->sps;
const int maxSizeEMT = EMT_INTER_MAX_CU_WITH_QTBT;
bool swapped = false; // avoid unwanted data copy
bool reloadCU = false;
const bool considerEmtSecondPass = emtMode && sps.getSpsNext().getUseInterEMT() && partitioner.currArea().lwidth() <= maxSizeEMT && partitioner.currArea().lheight() <= maxSizeEMT;
int minEMTMode = 0;
int maxEMTMode = (considerEmtSecondPass?1:0);

Karsten Suehring
committed
// Not allow very big |MVd| to avoid CABAC crash caused by too large MVd. Normally no impact on coding performance.
const int maxMvd = 1 << 15;
const PredictionUnit& pu = *cu->firstPU;
if (!cu->affine)
{
if ((pu.refIdx[0] >= 0 && (pu.mvd[0].getAbsHor() >= maxMvd || pu.mvd[0].getAbsVer() >= maxMvd))
|| (pu.refIdx[1] >= 0 && (pu.mvd[1].getAbsHor() >= maxMvd || pu.mvd[1].getAbsVer() >= maxMvd)))
{
return;
}
}
Xiang Li
committed
else
{
for (int refList = 0; refList < NUM_REF_PIC_LIST_01; refList++)
{
if (pu.refIdx[refList] >= 0)
{
for (int ctrlP = 1 + (cu->affineType == AFFINEMODEL_6PARAM); ctrlP >= 0; ctrlP--)
{
if (pu.mvdAffi[refList][ctrlP].getAbsHor() >= maxMvd || pu.mvdAffi[refList][ctrlP].getAbsVer() >= maxMvd)
{
return;
}
}
}
}
}
if( emtMode == 2 )
{
minEMTMode = maxEMTMode = (cu->emtFlag?1:0);
}

Karsten Suehring
committed
for( int curEmtMode = minEMTMode; curEmtMode <= maxEMTMode; curEmtMode++ )

Karsten Suehring
committed
{
3917
3918
3919
3920
3921
3922
3923
3924
3925
3926
3927
3928
3929
3930
3931
3932
3933
3934
3935
3936
3937
3938
3939
3940
3941
3942
3943
3944
3945
if( reloadCU )
{
if( bestCost == bestCS->cost ) //The first EMT pass didn't become the bestCS, so we clear the TUs generated
{
tempCS->clearTUs();
}
else if( false == swapped )
{
tempCS->initStructData( encTestMode.qp, encTestMode.lossless );
tempCS->copyStructure( *bestCS, partitioner.chType );
tempCS->getPredBuf().copyFrom( bestCS->getPredBuf() );
bestCost = bestCS->cost;
cu = tempCS->getCU( partitioner.chType );
swapped = true;
}
else
{
tempCS->clearTUs();
bestCost = bestCS->cost;
cu = tempCS->getCU( partitioner.chType );
}
//we need to restart the distortion for the new tempCS, the bit count and the cost
tempCS->dist = 0;
tempCS->fracBits = 0;
tempCS->cost = MAX_DOUBLE;
}
reloadCU = true; // enable cu reloading

Karsten Suehring
committed
cu->skip = false;
cu->emtFlag = curEmtMode;

Karsten Suehring
committed
const bool skipResidual = residualPass == 1;
m_pcInterSearch->encodeResAndCalcRdInterCU( *tempCS, partitioner, skipResidual );
xEncodeDontSplit( *tempCS, partitioner );
xCheckDQP( *tempCS, partitioner );
3958
3959
3960
3961
3962
3963
3964
3965
3966
3967
3968
3969
3970
3971
3972
3973
3974
3975
3976
3977
3978
3979
3980
3981
3982
3983
3984
3985
3986
if( ETM_INTER_ME == encTestMode.type )
{
if( equGBiCost != NULL )
{
if( tempCS->cost < (*equGBiCost) && cu->GBiIdx == GBI_DEFAULT )
{
(*equGBiCost) = tempCS->cost;
}
}
else
{
CHECK(equGBiCost == NULL, "equGBiCost == NULL");
}
if( tempCS->slice->getCheckLDC() && !cu->imv && cu->GBiIdx != GBI_DEFAULT && tempCS->cost < m_bestGbiCost[1] )
{
if( tempCS->cost < m_bestGbiCost[0] )
{
m_bestGbiCost[1] = m_bestGbiCost[0];
m_bestGbiCost[0] = tempCS->cost;
m_bestGbiIdx[1] = m_bestGbiIdx[0];
m_bestGbiIdx[0] = cu->GBiIdx;
}
else
{
m_bestGbiCost[1] = tempCS->cost;
m_bestGbiIdx[1] = cu->GBiIdx;
}
}
}
double emtFirstPassCost = tempCS->cost;

Karsten Suehring
committed
if( imvCS && (tempCS->cost < imvCS->cost) )
{
if( imvCS->cost != MAX_DOUBLE )
{
imvCS->initStructData( encTestMode.qp, encTestMode.lossless );
}
imvCS->copyStructure( *tempCS, partitioner.chType );
}
if( NULL != bestHasNonResi && (bestCostInternal > tempCS->cost) )
{