xCheckRDCostMerge2Nx2N在xCompressCU函数中调用,用来测试Merge模式、mmvd模式以及CIIP模式。
首先由getInterMergeCandidates获取merge候选模式信息,存储于,mergeCtx。同时由merge列表获取MMVD模式的两个baseMV。
如果不进行fastMerge,则跳过SATD直接进行RDO选最优
fastMerge时,对7个merge候选模式进行SATD,分别进行MC获得pred像素,选取cost最小的4个merge候选;对于MMVD模式分别以这两个mv为中心进行4方向8步长的计算,得到最优的baseMV、方向和步长。CIIP模式则选择经过SATD之后的前4个merge模式,分别于帧内模式结合,选取最优的merge模式和帧内模式。
对RdModeList中的merge候选、MMVD模式以及CIIP模式,统一进行RDO选择最优。
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 ); //tempCS清空初始化
MergeCtx mergeCtx;
const SPS &sps = *tempCS->sps;
if( sps.getSpsNext().getUseSubPuMvp() )
{
Size bufSize = g_miScaling.scale( tempCS->area.lumaSize() );
mergeCtx.subPuMvpMiBuf = MotionBuf( m_SubPuMiBuf, bufSize );
}
#if JVET_L0124_L0208_TRIANGLE
setMergeBestSATDCost( MAX_DOUBLE );
#endif
{
// first get merge candidates
CodingUnit cu( tempCS->area ); //创建cu、pu用来获得merge列表
cu.cs = tempCS;
cu.partSize = SIZE_2Nx2N;
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;
PU::getInterMergeCandidates(pu, mergeCtx //获取merge列表,其中包含7个merge候选信息,存储于mergeCtx
#if JVET_L0054_MMVD
, 0
#endif
);
PU::restrictBiPredMergeCands(pu, mergeCtx);
#if JVET_L0054_MMVD
PU::getInterMMVDMergeCandidates(pu, mergeCtx); //MMVD选择merge列表的前两个候选,作为baseMV
#endif
}
bool candHasNoResidual[MRG_MAX_NUM_CANDS + MMVD_ADD_NUM]; //若merge模式没有resi,则为skip模式
for (uint32_t ui = 0; ui < MRG_MAX_NUM_CANDS + MMVD_ADD_NUM; ui++)
{
candHasNoResidual[ui] = false;
}
bool bestIsSkip = false;
bool bestIsMMVDSkip = true;
#if JVET_L0100_MULTI_HYPOTHESIS_INTRA
PelUnitBuf acMergeBuffer[MRG_MAX_NUM_CANDS]; //里面存储的是:merge列表里面候选模式0~6顺序排列的各模式的pred像素
#endif
PelUnitBuf acMergeRealBuffer[MMVD_MRG_MAX_RD_BUF_NUM];//存储RDModeList前7个mode的pred像素
PelUnitBuf * acMergeTempBuffer[MMVD_MRG_MAX_RD_NUM]; //acMergeTempBuffer中始终存储的是RDModeList前几个模式的pred像素
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); //如果不进行SATD,那么RdModeList中存放7+64个merge候选,直接进行最后的RDO
}
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;
}
}/////////////////////////////////////////////////////以上为初始化,并获取Merge列表
#if JVET_L0100_MULTI_HYPOTHESIS_INTRA
#if JVET_L0054_MMVD
static_vector<unsigned, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM> RdModeList2; // store the Intra mode for Intrainter
#else
static_vector<unsigned, MRG_MAX_NUM_CANDS> RdModeList2; // store the Intra mode for Intrainter
#endif
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;
}
#endif
#if JVET_L0100_MULTI_HYPOTHESIS_INTRA
if( m_pcEncCfg->getUseFastMerge() || isIntrainterEnabled) // FastMerge || CIIP
#else
if( m_pcEncCfg->getUseFastMerge() )
#endif
{
uiNumMrgSATDCand = NUM_MRG_SATD_CAND; //SATD粗选择后的merge候选数目,4
#if JVET_L0100_MULTI_HYPOTHESIS_INTRA
if (isIntrainterEnabled)
{
uiNumMrgSATDCand += 1; //4加一个CIIP模式
}
#endif
bestIsSkip = false;
if( auto blkCache = dynamic_cast< CacheBlkInfoCtrl* >( m_modeCtrl ) )
{
#if JVET_L0293_CPR
if (slice.getSPS()->getSpsNext().getCPRMode())
{
ComprCUCtx cuECtx = m_modeCtrl->getComprCUCtx();
bestIsSkip = blkCache->isSkip(tempCS->area) && cuECtx.bestCU;
}
else
#endif
bestIsSkip = blkCache->isSkip( tempCS->area );
#if JVET_L0054_MMVD
bestIsMMVDSkip = blkCache->isMMVDSkip(tempCS->area);
#endif
}
#if JVET_L0100_MULTI_HYPOTHESIS_INTRA
if (isIntrainterEnabled) // always perform low complexity check
{
bestIsSkip = false;
}
#endif
#if JVET_L0054_MMVD
static_vector<double, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM> candCostList; //存放SATD时得到的7+64个候选的cost
#else
static_vector<double, MRG_MAX_NUM_CANDS> candCostList;
#endif
// 1. Pass: get SATD-cost for selected candidates and reduce their count
if( !bestIsSkip ) //不是skip模式,对7+64个merge候选模式进行SATD粗选择
{
RdModeList.clear(); //RdModeList前面有压栈操作,这里清空
mrgTempBufSet = true;
const double sqrtLambdaForFirstPass = m_pcRdCost->getMotionLambda( encTestMode.lossless );
CodingUnit &cu = tempCS->addCU( tempCS->area, partitioner.chType ); //tempCS添加cu和pu
#if JVET_L0100_MULTI_HYPOTHESIS_INTRA
const double sqrtLambdaForFirstPassIntra = m_pcRdCost->getMotionLambda(cu.transQuantBypass) / double(1 << SCALE_BITS);
#endif
partitioner.setCUData( cu );
cu.slice = tempCS->slice;
#if HEVC_TILES_WPP
cu.tileIdx = tempCS->picture->tileMap->getTileIdxMap( tempCS->area.lumaPos() );
#endif
cu.skip = false;
#if JVET_L0054_MMVD
cu.mmvdSkip = false;
#endif
#if JVET_L0124_L0208_TRIANGLE
cu.triangle = false;
#endif
cu.partSize = SIZE_2Nx2N;
//cu.affine
cu.predMode = MODE_INTER;
//cu.LICFlag
cu.transQuantBypass = encTestMode.lossless;
cu.chromaQpAdj = cu.transQuantBypass ? 0 : m_cuChromaQpOffsetIdxPlus1;
cu.qp = encTestMode.qp;
//cu.emtFlag is set below
PredictionUnit &pu = tempCS->addPU( cu, partitioner.chType );
DistParam distParam;
const bool bUseHadamard= !encTestMode.lossless; //用来计算失真的pred像素存储在m_acMergeBuffer[0].Y()
//设置计算失真的类:distParam 的各项参数
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) );
#if JVET_L0293_CPR
uint32_t cprCand = 0;
uint32_t numValidMv = mergeCtx.numValidMergeCand;
#endif
for( uint32_t uiMergeCand = 0; uiMergeCand < mergeCtx.numValidMergeCand; uiMergeCand++ ) //Merge列表的loop,merge候选进行SATD
{
#if JVET_L0293_CPR
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())
{
cprCand++;
numValidMv--;
continue;
}
#endif
#if !JVET_L0054_MMVD
acMergeBuffer[uiMergeCand] = m_acMergeBuffer[uiMergeCand].getBuf( localUnitArea );
#endif
mergeCtx.setMergeInfo( pu, uiMergeCand );
PU::spanMotionInfo( pu, mergeCtx );
#if JVET_L0054_MMVD
distParam.cur = singleMergeTempBuffer->Y(); //MMVD模式中MC得到的pred像素存储在singleMergeTempBuffer->Y()中
m_pcInterSearch->motionCompensation(pu, *singleMergeTempBuffer); // MC
#if JVET_L0100_MULTI_HYPOTHESIS_INTRA
acMergeBuffer[uiMergeCand] = m_acRealMergeBuffer[uiMergeCand].getBuf(localUnitArea);
acMergeBuffer[uiMergeCand].copyFrom(*singleMergeTempBuffer); //acMergeBuffer存储merge列表0~6的pred像素,用于最后CIIP和普通merge的处理
#endif
#else
distParam.cur = acMergeBuffer[uiMergeCand].Y();
m_pcInterSearch->motionCompensation( pu, acMergeBuffer[uiMergeCand] );
#endif
if( mergeCtx.interDirNeighbours[uiMergeCand] == 3 && mergeCtx.mrgTypeNeighbours[uiMergeCand] == MRG_TYPE_DEFAULT_N )
{
mergeCtx.mvFieldNeighbours[2*uiMergeCand].mv = pu.mv[0]; //双向预测时
mergeCtx.mvFieldNeighbours[2*uiMergeCand+1].mv = pu.mv[1];
#if DMVR_JVET_LOW_LATENCY_K0217
refinedMvdL0[uiMergeCand] = pu.mvd[0];
#endif
}
Distortion uiSad = distParam.distFunc(distParam); //计算失真
uint32_t uiBitsCand = uiMergeCand + 1;
if( uiMergeCand == tempCS->slice->getMaxNumMergeCand() - 1 )
{
uiBitsCand--;
}
#if JVET_L0054_MMVD
uiBitsCand++; // for mmvd_flag
#endif
double cost = (double)uiSad + (double)uiBitsCand * sqrtLambdaForFirstPass; //cost
#if JVET_L0054_MMVD
insertPos = -1;
#if JVET_L0100_MULTI_HYPOTHESIS_INTRA //当前mode按cost大小顺序插入RdModeList
updateDoubleCandList(uiMergeCand, cost, RdModeList, candCostList, RdModeList2, (uint32_t)NUM_LUMA_MODE, uiNumMrgSATDCand, &insertPos);
#else
#if JVET_L0283_MULTI_REF_LINE
static_vector<int, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM> * nullList = nullptr;
#endif
updateCandList(uiMergeCand, cost, RdModeList, candCostList
#if JVET_L0283_MULTI_REF_LINE
, *nullList, -1
#endif
, uiNumMrgSATDCand, &insertPos);
#endif
if (insertPos != -1) //acMergeTempBuffer中始终存储的是RDModeList前几个模式的pred像素
{
if (insertPos == RdModeList.size() - 1)//若插入到vector的最后时,直接将MC得到的pred像素放到tempBuffer的最后一个
{
swap(singleMergeTempBuffer, acMergeTempBuffer[insertPos]);
}
else
{
for (uint32_t i = uint32_t(RdModeList.size()) - 1; i > insertPos; i--)
{
swap(acMergeTempBuffer[i - 1], acMergeTempBuffer[i]);
}
swap(singleMergeTempBuffer, acMergeTempBuffer[insertPos]);
}
}
#else
#if JVET_L0100_MULTI_HYPOTHESIS_INTRA
updateDoubleCandList(uiMergeCand, cost, RdModeList, candCostList, RdModeList2, (uint32_t)NUM_LUMA_MODE, uiNumMrgSATDCand);
#else
#if JVET_L0283_MULTI_REF_LINE
static_vector<int, MRG_MAX_NUM_CANDS> * nullList = nullptr;
#endif
updateCandList( uiMergeCand, cost, RdModeList, candCostList
#if JVET_L0283_MULTI_REF_LINE
, *nullList, -1
#endif
, uiNumMrgSATDCand );
#endif
#endif
#if JVET_L0293_CPR
CHECK(std::min(uiMergeCand + 1 - cprCand, uiNumMrgSATDCand) != RdModeList.size(), "");
#else
CHECK( std::min( uiMergeCand + 1, uiNumMrgSATDCand ) != RdModeList.size(), "" );
#endif
} //MergeCand 的loop结束,对Merge列表中的模式都进行了运动补偿,计算cost,排序
#if JVET_L0293_CPR
if (numValidMv < uiNumMrgSATDCand)
uiNumMrgSATDCand = numValidMv;
if (numValidMv == 0)
return;
#endif
#if JVET_L0100_MULTI_HYPOTHESIS_INTRA
if (isIntrainterEnabled) // CIIP
{
int numTestIntraMode = 4;
// prepare for Intra bits calculation
const TempCtx ctxStart(m_CtxCache, m_CABACEstimator->getCtx());
const TempCtx ctxStartIntraMode(m_CtxCache, SubCtx(Ctx::MHIntraPredMode, m_CABACEstimator->getCtx()));
// for Intrainter fast, recored the best intra mode during the first round for mrege 0
int bestMHIntraMode = -1;
double bestMHIntraCost = MAX_DOUBLE;
pu.mhIntraFlag = true;
// save the to-be-tested merge candidates
uint32_t MHIntraMergeCand[NUM_MRG_SATD_CAND];
#if JVET_L0293_CPR
for (uint32_t mergeCnt = 0; mergeCnt < std::min(NUM_MRG_SATD_CAND, (const int) uiNumMrgSATDCand); mergeCnt++)
#else
for (uint32_t mergeCnt = 0; mergeCnt < NUM_MRG_SATD_CAND; mergeCnt++)
#endif
{
MHIntraMergeCand[mergeCnt] = RdModeList[mergeCnt]; //CIIP的inter模式,取SATD后的前4个MergeMode
}
#if JVET_L0293_CPR
for (uint32_t mergeCnt = 0; mergeCnt < std::min( std::min(NUM_MRG_SATD_CAND, (const int)uiNumMrgSATDCand), 4); mergeCnt++)
#else
for (uint32_t mergeCnt = 0; mergeCnt < std::min(NUM_MRG_SATD_CAND, 4); mergeCnt++)
#endif //4个mergeMode loop,选最优
{
uint32_t mergeCand = MHIntraMergeCand[mergeCnt];
#if JVET_L0054_MMVD
acMergeBuffer[mergeCand] = m_acRealMergeBuffer[mergeCand].getBuf(localUnitArea);
#else
acMergeBuffer[mergeCand] = m_acMergeBuffer[mergeCand].getBuf(localUnitArea);
#endif
// estimate merge bits
uint32_t bitsCand = mergeCand + 1;
if (mergeCand == pu.cs->slice->getMaxNumMergeCand() - 1)
{
bitsCand--;
}
// first round
for (uint32_t intraCnt = 0; intraCnt < numTestIntraMode; intraCnt++) //4个帧内预测模式loop
{
pu.intraDir[0] = (intraCnt < 2) ? intraCnt : ((intraCnt == 2) ? HOR_IDX : VER_IDX);
// fast 2
if (mergeCnt > 0 && bestMHIntraMode != pu.intraDir[0]) //只对第一个merge模式执行全面的4个intra模式的check
{ //对于剩下的3个merge模式,只检查第一个merge模式中所选择的最优的那个intra模式
continue;
}
int narrowCase = PU::getNarrowShape(pu.lwidth(), pu.lheight());
if (narrowCase == 1 && pu.intraDir[0] == HOR_IDX) //W >> H
{
continue;
}
if (narrowCase == 2 && pu.intraDir[0] == VER_IDX) //H >> W
{
continue;
}
// generate intrainter Y prediction
//只对第一个merge执行4次intra预测,预测结果保存在m_pcIntraSearch->getPredictorPtr2(COMPONENT_Y, intraCnt),所以后面的3个merge模式直接取用,不用再预测
if (mergeCnt == 0)
{
bool isUseFilter = IntraPrediction::useFilteredIntraRefSamples(COMPONENT_Y, pu, true, pu);
m_pcIntraSearch->initIntraPatternChType(*pu.cu, pu.Y(), isUseFilter);
m_pcIntraSearch->predIntraAng(COMPONENT_Y, pu.cs->getPredBuf(pu).Y(), pu, isUseFilter);
m_pcIntraSearch->switchBuffer(pu, COMPONENT_Y, pu.cs->getPredBuf(pu).Y(), m_pcIntraSearch->getPredictorPtr2(COMPONENT_Y, intraCnt));
}
pu.cs->getPredBuf(pu).copyFrom(acMergeBuffer[mergeCand]); //pred像素copy入merge模式像素
m_pcIntraSearch->geneWeightedPred(COMPONENT_Y, pu.cs->getPredBuf(pu).Y(), pu, m_pcIntraSearch->getPredictorPtr2(COMPONENT_Y, intraCnt));
//CIIP模式中的intra和inter的加权平均
// calculate cost
distParam.cur = pu.cs->getPredBuf(pu).Y(); //此时pred存储的是intrainter加权像素
Distortion sadValue = distParam.distFunc(distParam); //计算失真和cost
m_CABACEstimator->getCtx() = SubCtx(Ctx::MHIntraPredMode, ctxStartIntraMode);
uint64_t fracModeBits = m_pcIntraSearch->xFracModeBitsIntra(pu, pu.intraDir[0], CHANNEL_TYPE_LUMA);
double cost = (double)sadValue + (double)(bitsCand + 1) * sqrtLambdaForFirstPass + (double)fracModeBits * sqrtLambdaForFirstPassIntra;
#if JVET_L0054_MMVD
insertPos = -1; //加入RDModeList时,mergeCand的基础上加了7+64,绕开普通merge和MMVD
updateDoubleCandList(mergeCand + MRG_MAX_NUM_CANDS + MMVD_ADD_NUM, cost, RdModeList, candCostList, RdModeList2, pu.intraDir[0], uiNumMrgSATDCand, &insertPos);
#else
updateDoubleCandList(mergeCand + MRG_MAX_NUM_CANDS + MRG_MAX_NUM_CANDS, cost, RdModeList, candCostList, RdModeList2, pu.intraDir[0], uiNumMrgSATDCand);
#endif
#if JVET_L0054_MMVD
if (insertPos != -1)
{
for (int i = int(RdModeList.size()) - 1; i > insertPos; i--)
{
swap(acMergeTempBuffer[i - 1], acMergeTempBuffer[i]);
}
swap(singleMergeTempBuffer, acMergeTempBuffer[insertPos]);
}
#endif
// fast 2 记录第一个merge模式中4个intra模式最优的那个
if (mergeCnt == 0 && cost < bestMHIntraCost)
{
bestMHIntraMode = pu.intraDir[0];
bestMHIntraCost = cost;
}
}
}
pu.mhIntraFlag = false;
m_CABACEstimator->getCtx() = ctxStart;
}
#endif
#if JVET_L0054_MMVD // MMVD
cu.mmvdSkip = true;
int tempNum = 0;
tempNum = MMVD_ADD_NUM;
bool allowDirection[4] = { true, true, true, true };
for (uint32_t mergeCand = mergeCtx.numValidMergeCand; mergeCand < mergeCtx.numValidMergeCand + tempNum; mergeCand++)
{ //64个mvd进行loop,选取最优的mvd
const int mmvdMergeCand = mergeCand - mergeCtx.numValidMergeCand;
int bitsBaseIdx = 0;
int bitsRefineStep = 0;
int bitsDirection = 2;
int bitsCand = 0;
int baseIdx;
int refineStep;
int direction;
baseIdx = mmvdMergeCand / MMVD_MAX_REFINE_NUM; //baseMV是第一个mergeMode还是第二个
refineStep = (mmvdMergeCand - (baseIdx * MMVD_MAX_REFINE_NUM)) / 4; //步长
direction = (mmvdMergeCand - baseIdx * MMVD_MAX_REFINE_NUM - refineStep * 4) % 4; //mvd的方向
if (refineStep == 0)
{
allowDirection[direction] = true;
}
if (allowDirection[direction] == false)
{
continue;
}
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
#if !JVET_L0054_MMVD
acMergeBuffer[mergeCand] = m_acMergeBuffer[mergeCand].getBuf(localUnitArea);
#endif
mergeCtx.setMmvdMergeCandiInfo(pu, mmvdMergeCand); //由mmvdMergeCand获取mvd,从而得到pu的motioninfo信息
PU::spanMotionInfo(pu, mergeCtx);
#if JVET_L0054_MMVD
distParam.cur = singleMergeTempBuffer->Y();
m_pcInterSearch->motionCompensation(pu, *singleMergeTempBuffer); //MC
#else
distParam.cur = acMergeBuffer[mergeCand].Y();
m_pcInterSearch->motionCompensation(pu, acMergeBuffer[mergeCand]);
#endif
Distortion uiSad = distParam.distFunc(distParam); //失真
#if !JVET_L0054_MMVD
uint32_t bitsCand = mergeCand + 1;
if (mergeCand == tempCS->slice->getMaxNumMergeCand() - 1)
{
bitsCand--;
}
#endif
double cost = (double)uiSad + (double)bitsCand * sqrtLambdaForFirstPass; //cost
#if JVET_L0054_MMVD
allowDirection[direction] = cost > 1.3 * candCostList[0] ? 0 : 1; //只要一个方向上的8个点中有一个不达标,该方向剩下的点就不用测了
#endif
#if JVET_L0054_MMVD
insertPos = -1;
#if JVET_L0100_MULTI_HYPOTHESIS_INTRA //MMVD插入RDModelList的模式是mergeCand,即7~71
updateDoubleCandList(mergeCand, cost, RdModeList, candCostList, RdModeList2, (uint32_t)NUM_LUMA_MODE, uiNumMrgSATDCand, &insertPos);
#else
#if JVET_L0283_MULTI_REF_LINE
static_vector<int, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM> * nullList = nullptr;
#endif
updateCandList(mergeCand, cost, RdModeList, candCostList
#if JVET_L0283_MULTI_REF_LINE
, *nullList, -1
#endif
, uiNumMrgSATDCand, &insertPos);
#endif
if (insertPos != -1)
{
for (int i = int(RdModeList.size()) - 1; i > insertPos; i--)
{
swap(acMergeTempBuffer[i - 1], acMergeTempBuffer[i]);
}
swap(singleMergeTempBuffer, acMergeTempBuffer[insertPos]);
}
#else
updateCandList(mergeCand, cost, RdModeList, candCostList, uiNumMrgSATDCand);
#endif
#if !JVET_L0054_MMVD
CHECK(std::min(mergeCand + 1, uiNumMrgSATDCand) != RdModeList.size(), "");
#endif
}
#endif
// 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;
}
}
#if JVET_L0124_L0208_TRIANGLE
setMergeBestSATDCost( candCostList[0] );
#endif
#if JVET_L0100_MULTI_HYPOTHESIS_INTRA
if (isIntrainterEnabled) // CIIP 帧内色度模式
{
pu.mhIntraFlag = true;
for (uint32_t mergeCnt = 0; mergeCnt < uiNumMrgSATDCand; mergeCnt++)
{
#if JVET_L0054_MMVD
if (RdModeList[mergeCnt] >= (MRG_MAX_NUM_CANDS + MMVD_ADD_NUM))
#else
if (RdModeList[mergeCnt] >= (MRG_MAX_NUM_CANDS + MRG_MAX_NUM_CANDS))
#endif
{
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); //Cb
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); //Cr
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));
}
}
pu.mhIntraFlag = false;
}
#endif
tempCS->initStructData( encTestMode.qp, encTestMode.lossless );
}
else // bestIsSkip = true
{
#if JVET_L0054_MMVD
if (bestIsMMVDSkip)
{
uiNumMrgSATDCand = mergeCtx.numValidMergeCand + MMVD_ADD_NUM;
}
else
{
uiNumMrgSATDCand = mergeCtx.numValidMergeCand;
}
#else
uiNumMrgSATDCand = mergeCtx.numValidMergeCand;
#endif
}
}
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]; //对RdModeList中的所有模式,进行计算选最优(普通merge CIIP和MMVD平等竞争)
#if JVET_L0293_CPR
#if JVET_L0054_MMVD
if(uiMergeCand < mergeCtx.numValidMergeCand)
#endif
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; //一些特殊情况,该模式跳过
}
#endif
#if JVET_L0100_MULTI_HYPOTHESIS_INTRA
#if JVET_L0054_MMVD
if (uiNoResidualPass != 0 && uiMergeCand >= (MRG_MAX_NUM_CANDS + MMVD_ADD_NUM)) // intrainter does not support skip mode
#else
if (uiNoResidualPass != 0 && uiMergeCand >= (MRG_MAX_NUM_CANDS + MRG_MAX_NUM_CANDS)) // intrainter does not support skip mode
#endif
{
#if JVET_L0054_MMVD
uiMergeCand -= (MRG_MAX_NUM_CANDS + MMVD_ADD_NUM); // for skip, map back to normal merge candidate idx and try RDO
#else
uiMergeCand -= (MRG_MAX_NUM_CANDS + MRG_MAX_NUM_CANDS); // for skip, map back to normal merge candidate idx and try RDO
#endif
if (isTestSkipMerge[uiMergeCand])
{
continue; //一些特殊情况,该模式跳过
}
}
#endif
#if JVET_L0054_MMVD
if (((uiNoResidualPass != 0) && candHasNoResidual[uiMrgHADIdx])
#else
if( ( (uiNoResidualPass != 0) && candHasNoResidual[uiMergeCand] )
#endif
|| ( (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;
#if JVET_L0054_MMVD
cu.mmvdSkip = false;
#endif
#if JVET_L0124_L0208_TRIANGLE
cu.triangle = false;
#endif
cu.partSize = SIZE_2Nx2N;
//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 );
//下面分CIIP、MMVD和普通merge三种情况分别对pu进行设置
#if JVET_L0100_MULTI_HYPOTHESIS_INTRA
#if JVET_L0054_MMVD // CIIP
if (uiNoResidualPass == 0 && uiMergeCand >= (MRG_MAX_NUM_CANDS + MMVD_ADD_NUM))
#else
if (uiNoResidualPass == 0 && uiMergeCand >= (MRG_MAX_NUM_CANDS + MRG_MAX_NUM_CANDS))
#endif
{
#if JVET_L0054_MMVD
uiMergeCand -= (MRG_MAX_NUM_CANDS + MMVD_ADD_NUM);
cu.mmvdSkip = false;
mergeCtx.setMergeInfo(pu, uiMergeCand);
#else
uiMergeCand -= (MRG_MAX_NUM_CANDS + MRG_MAX_NUM_CANDS);
#endif
pu.mhIntraFlag = true;
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;
}
#endif
#if JVET_L0054_MMVD
#if JVET_L0100_MULTI_HYPOTHESIS_INTRA // MMVD
else if (uiMergeCand >= mergeCtx.numValidMergeCand && uiMergeCand < MRG_MAX_NUM_CANDS + MMVD_ADD_NUM)
#else
if (uiMergeCand >= mergeCtx.numValidMergeCand)
#endif
{
cu.mmvdSkip = true;
mergeCtx.setMmvdMergeCandiInfo(pu, uiMergeCand - mergeCtx.numValidMergeCand);
}
else
{
cu.mmvdSkip = false; //普通merge
mergeCtx.setMergeInfo(pu, uiMergeCand);
}
#else
mergeCtx.setMergeInfo( pu, uiMergeCand );
#endif
PU::spanMotionInfo( pu, mergeCtx );
if( mrgTempBufSet ) //bestIsSkip为false时,mrgTempBufSet为true
{ //skip为false,表明已经进行过上面各种模式的pred像素的计算,所以不用下面else的MC
#if DMVR_JVET_LOW_LATENCY_K0217
pu.mvd[0] = refinedMvdL0[uiMergeCand];
#endif
#if JVET_L0100_MULTI_HYPOTHESIS_INTRA
if (pu.mhIntraFlag) //CIIP 分别对YUV的inter和inter加权平均,存入tempCS的predBuf
{
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
{
#if JVET_L0054_MMVD //MMVD只需在tempCS的predBuf中存储inter像素
if (uiNoResidualPass != 0 && uiMergeCand < mergeCtx.numValidMergeCand && RdModeList[uiMrgHADIdx] >= (MRG_MAX_NUM_CANDS + MMVD_ADD_NUM))
{
tempCS->getPredBuf().copyFrom(acMergeBuffer[uiMergeCand]); //普通merge
}
else
{
tempCS->getPredBuf().copyFrom(*acMergeTempBuffer[uiMrgHADIdx]); //MMVD
}
#else
tempCS->getPredBuf().copyFrom(acMergeBuffer[uiMergeCand]);
#endif
}
#else
#if JVET_L0054_MMVD
tempCS->getPredBuf().copyFrom(*acMergeTempBuffer[uiMrgHADIdx]);
#else
tempCS->getPredBuf().copyFrom( acMergeBuffer[ uiMergeCand ]);
#endif
#endif
}
else //如果上面执行的是skip模式,那么就需要MC来计算pred像素
{
m_pcInterSearch->motionCompensation( pu ); //MC,skip模式时才进行MC,由运动信息获取pred像素
}
#if JVET_L0100_MULTI_HYPOTHESIS_INTRA
#if JVET_L0054_MMVD
if (!cu.mmvdSkip && !pu.mhIntraFlag && uiNoResidualPass != 0)
#else
if (!pu.mhIntraFlag && uiNoResidualPass != 0)
#endif
{
CHECK(uiMergeCand >= mergeCtx.numValidMergeCand, "out of normal merge");
isTestSkipMerge[uiMergeCand] = true;
}
#endif
#if JVET_L0054_MMVD //由orig和pred像素信息,获得resi,可得到reco像素
//分别处理无残差的skip模式和merge模式,得到cost,最终xCheckBestMode将最优merge信息存储于bestCS
xEncodeInterResidual(tempCS, bestCS, partitioner, encTestMode, uiNoResidualPass
, NULL
, 1
, uiNoResidualPass == 0 ? &candHasNoResidual[uiMrgHADIdx] : NULL);
#else
xEncodeInterResidual( tempCS, bestCS, partitioner, encTestMode, uiNoResidualPass
, NULL
, 1
, uiNoResidualPass == 0 ? &candHasNoResidual[uiMergeCand] : NULL );
#endif
#if JVET_L0100_MULTI_HYPOTHESIS_INTRA
if( m_pcEncCfg->getUseFastDecisionForMerge() && !bestIsSkip && !pu.mhIntraFlag)
#else
if( m_pcEncCfg->getUseFastDecisionForMerge() && !bestIsSkip )
#endif
{
bestIsSkip = bestCS->getCU( partitioner.chType )->rootCbf == 0;
}
tempCS->initStructData( encTestMode.qp, encTestMode.lossless ); //tempCS清空初始化,进行下一个merge候选
}// end loop uiMrgHADIdx
if( uiNoResidualPass == 0 && m_pcEncCfg->getUseEarlySkipDetection() ) //判断skip模式
{
const CodingUnit &bestCU = *bestCS->getCU( partitioner.chType );
const PredictionUnit &bestPU = *bestCS->getPU( partitioner.chType );
if( bestCU.rootCbf == 0 )
{
if( bestPU.mergeFlag )
{
m_modeCtrl->setEarlySkipDetected(); //skip模式
}
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();
}
}
}
}
}
}
来源:CSDN
作者:矛盾统一
链接:https://blog.csdn.net/gq0323/article/details/103721213