xCheckRDCostMerge2Nx2N函数是用来选出Merge/Skip模式中最佳的候选MV,根据常规Merge模式、带有运动矢量差的Merge模式(MMVD)以及CIIP模式产生的预测值和原始值得SATD Cost,选出最佳的运动信息。
主要分为以下过程:
① 获取Merge模式候选列表
首先通过getInterMergeCandidates函数和getInterMMVDMergeCandidates函数分别获取常规Merge模式和MMVD模式的候选列表,常规Merge的候选列表推导参考:扩展的Merge模式(Extended merge prediction),MMVD模式的候选列表推导参考:带有运动矢量差的Merge技术(Merge mode with MVD)
② 初始化RD选择的模式信息列表
模式信息的定义如下,包括Merge候选模式的索引,是否是常规Merge模式、MMVD模式、CIIP模式。
struct ModeInfo
{
uint32_t mergeCand;
bool isRegularMerge;
bool isMMVD;
bool isCIIP;
ModeInfo() : mergeCand(0), isRegularMerge(false), isMMVD(false), isCIIP(false) {}
ModeInfo(const uint32_t mergeCand, const bool isRegularMerge, const bool isMMVD, const bool isCIIP) :
mergeCand(mergeCand), isRegularMerge(isRegularMerge), isMMVD(isMMVD), isCIIP(isCIIP) {}
};
总的可用候选模式数目为可用常规Merge候选数目+MMVD候选数目。
// 总的可用候选数目为:可用常规Merge候选数目+MMVD候选数目
const int candNum = mergeCtx.numValidMergeCand + (tempCS->sps->getUseMMVD() ? std::min<int>(MMVD_BASE_MV_NUM, mergeCtx.numValidMergeCand) * MMVD_MAX_REFINE_NUM : 0);
将候选Merge模式信息加入到RD模式列表RdModeList中
③缩减进行RD Cost细选的模式数
如果开启快速Merge模式选择或者CIIP模式可用,则缩减进行RD Cost细选的模式数
该步骤是通过计算候选Merge模式的预测值和原始值得SAD以及预测模式的比特数,减少后续进行细选的模式数(此时不需要对残差进行变换量化)
先获取当前块在缓存中的最佳编码模式(此处不太懂???),根据其最佳模式缩减细选模式数 uiNumMrgSATDCand
1、如果最佳模式不是Skip模式,根据候选模式的SATD Cost减少细选模式数
遍历常规Merge候选模式,进行运动补偿获得相应预测值,并使用DMVR对其MV进行细化,根据预测值的亮度分量计算SAD,并根据SAD和预测模式的比特数计算RD Cost,更新RD模式列表,将代价小的模式移到列表前面
如果CIIP模式可用,则遍历RD模式列表中的前几个模式(最多遍历4个模式),计算CIIP预测像素,并计算失真SAD和模式比特数R,计算RD Cost,更新RD模式列表,将代价小的模式移动到列表前面
遍历MMVD候选模式,进行运动补偿获得相应预测值,根据预测值的亮度分量计算SAD,并根据SAD和预测模式的比特数计算RD Cost,更新RD模式列表,将代价小的模式移到列表前面
根据候选代价列表缩减细选模式数目:如果第i个模式代价 > 第一个模式的代价*MRG_FAST_RATIO(1.25),则将uiNumMrgSATDCand设置为i
2、如果最佳模式是MMVD Skip模式,则进行细选的模式数为可用常规Merge模式数+MMVD模式数
3、否则(如果最佳模式是Skip模式),进行细选的模式数为可用常规Merge模式
④ 遍历候选模式列表,细选
首先,分为两次迭代,第一次迭代表示常规Merge模式,第二次迭代表示Skip模式(即跳过残差编码)。在每次迭代中:遍历缩减后的RD模式列表,对预测残差进行变换、量化,计算RD Cost选出最佳模式
初始化,判断当前候选是三种Merge模式中的哪一种,为相应的模式做预测的准备;如果符合DMVR的条件,则将MV设置为细化后的MV,然后去求出当前PU对应Merge模式的预测值。
- 对于CIIP模式,进行三个分量的加权操作
- 对于MMVD模式,重新计算MMVD模式预测值(通过MC);
- 对于常规Merge模式,直接拷贝上面已经计算好的预测值,因为在上面已经对regular模式下的MV细化过了。
调用xEncodeInterResidual()函数,编码当前Merge候选模式的残差,并在该函数中完成HAD的比较,最终选出HAD最小的那个Merge模式。
代码及注释如下;
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 );
MergeCtx mergeCtx;
const SPS &sps = *tempCS->sps;
if (sps.getSbTMVPEnabledFlag())
{
Size bufSize = g_miScaling.scale( tempCS->area.lumaSize() );
mergeCtx.subPuMvpMiBuf = MotionBuf( m_SubPuMiBuf, bufSize );
}
Mv refinedMvdL0[MAX_NUM_PARTS_IN_CTU][MRG_MAX_NUM_CANDS];
setMergeBestSATDCost( MAX_DOUBLE ); //设置最佳Merge模式的RD Cost为MAX_DOUBLE
{
// first get merge candidates 首先获得Merge候选列表
CodingUnit cu( tempCS->area );
cu.cs = tempCS;
cu.predMode = MODE_INTER;
cu.slice = tempCS->slice;
cu.tileIdx = tempCS->pps->getTileIdx( tempCS->area.lumaPos() );
PredictionUnit pu( tempCS->area );
pu.cu = &cu;
pu.cs = tempCS;
PU::getInterMergeCandidates(pu, mergeCtx
, 0
); //获得常规Merge获选列表
PU::getInterMMVDMergeCandidates(pu, mergeCtx);//获得MMVD Merge候选列表
pu.regularMergeFlag = true;
}
bool candHasNoResidual[MRG_MAX_NUM_CANDS + MMVD_ADD_NUM]; //没有残差的候选模式 总数是6(Merge) + 64(MMVD Merge)
for (uint32_t ui = 0; ui < MRG_MAX_NUM_CANDS + MMVD_ADD_NUM; ui++)
{
candHasNoResidual[ui] = false;
}
bool bestIsSkip = false;//最佳模式是Skip模式
bool bestIsMMVDSkip = true;//最佳模式是MMVD Skip模式
PelUnitBuf acMergeBuffer[MRG_MAX_NUM_CANDS];//存储常规Merge模式预测像素
PelUnitBuf acMergeTmpBuffer[MRG_MAX_NUM_CANDS];//用来存储常规Merge模式预测像素的临时空间
PelUnitBuf acMergeRealBuffer[MMVD_MRG_MAX_RD_BUF_NUM];
PelUnitBuf * acMergeTempBuffer[MMVD_MRG_MAX_RD_NUM];//用来存储MMVD Merge模式的临时空间
PelUnitBuf * singleMergeTempBuffer;
int insertPos;
// 进行SATD Cost计算的模式数目,初始化为可用常规Merge数目+64,后面会缩减
unsigned uiNumMrgSATDCand = mergeCtx.numValidMergeCand + MMVD_ADD_NUM;
struct ModeInfo
{
uint32_t mergeCand;
bool isRegularMerge;
bool isMMVD;
bool isCIIP;
ModeInfo() : mergeCand(0), isRegularMerge(false), isMMVD(false), isCIIP(false) {}
ModeInfo(const uint32_t mergeCand, const bool isRegularMerge, const bool isMMVD, const bool isCIIP) :
mergeCand(mergeCand), isRegularMerge(isRegularMerge), isMMVD(isMMVD), isCIIP(isCIIP) {}
};
static_vector<ModeInfo, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM> RdModeList; //RD模式列表 6+64,保存模式信息
bool mrgTempBufSet = false;
// 总的可用候选数目为:可用常规Merge候选数目+MMVD候选数目
const int candNum = mergeCtx.numValidMergeCand + (tempCS->sps->getUseMMVD() ? std::min<int>(MMVD_BASE_MV_NUM, mergeCtx.numValidMergeCand) * MMVD_MAX_REFINE_NUM : 0);
// 遍历全部可用候选模式,将其加入到RD模式列表中
for (int i = 0; i < candNum; i++)
{
if (i < mergeCtx.numValidMergeCand)
{
RdModeList.push_back(ModeInfo(i, true, false, false)); //添加常规候选模式
}
else
{
// 添加MMVD模式
RdModeList.push_back(ModeInfo(std::min(MMVD_ADD_NUM, i - mergeCtx.numValidMergeCand), false, true, false));
}
}
// 初始化一个和当前CU相同大小的区域
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;
}
}
bool isIntrainterEnabled = sps.getUseCiip(); //帧内帧间联合编码使用标志
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 记录Merge候选对象是否尝试了Skip模式
for (uint32_t idx = 0; idx < MRG_MAX_NUM_CANDS; idx++)
{
isTestSkipMerge[idx] = false;
}
if( m_pcEncCfg->getUseFastMerge() || isIntrainterEnabled) //快速Merge模式或者CIIP模式可用
{
uiNumMrgSATDCand = NUM_MRG_SATD_CAND; //SATD候选模式数:4
if (isIntrainterEnabled)
{
uiNumMrgSATDCand += 1; //增加一个CIIP模式
}
bestIsSkip = false;
if( auto blkCache = dynamic_cast< CacheBlkInfoCtrl* >( m_modeCtrl ) )
{
if (slice.getSPS()->getIBCFlag())
{
ComprCUCtx cuECtx = m_modeCtrl->getComprCUCtx();
bestIsSkip = blkCache->isSkip(tempCS->area) && cuECtx.bestCU;
}
else
bestIsSkip = blkCache->isSkip( tempCS->area );
bestIsMMVDSkip = blkCache->isMMVDSkip(tempCS->area);
}
if (isIntrainterEnabled) // always perform low complexity check 始终执行低复杂性检查
{
bestIsSkip = false;
}
static_vector<double, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM> candCostList; //候选代价列表,保存RD Cost
// 1. Pass: get SATD-cost for selected candidates and reduce their count
// 1. Pass:获得所选候选模式的SATD-Cost,并减少其数量
if( !bestIsSkip )//如果最佳模式不是Skip模式
{
RdModeList.clear();
mrgTempBufSet = true;
const TempCtx ctxStart(m_CtxCache, m_CABACEstimator->getCtx());
CodingUnit &cu = tempCS->addCU( tempCS->area, partitioner.chType );
const double sqrtLambdaForFirstPassIntra = m_pcRdCost->getMotionLambda( ) * FRAC_BITS_SCALE;
partitioner.setCUData( cu );
cu.slice = tempCS->slice;
cu.tileIdx = tempCS->pps->getTileIdx( tempCS->area.lumaPos() );
cu.skip = false;
cu.mmvdSkip = false;
cu.geoFlag = false;
//cu.affine
cu.predMode = MODE_INTER;
//cu.LICFlag
cu.chromaQpAdj = m_cuChromaQpOffsetIdxPlus1;
cu.qp = encTestMode.qp;
//cu.emtFlag is set below
PredictionUnit &pu = tempCS->addPU( cu, partitioner.chType );
DistParam distParam;
const bool bUseHadamard = !tempCS->slice->getDisableSATDForRD(); //使用哈达玛变换
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) );
// 遍历常规可用Merge候选项,计算SAD并更新候选列表
for( uint32_t uiMergeCand = 0; uiMergeCand < mergeCtx.numValidMergeCand; uiMergeCand++ )
{
mergeCtx.setMergeInfo( pu, uiMergeCand );
PU::spanMotionInfo( pu, mergeCtx );
pu.mvRefine = true;
distParam.cur = singleMergeTempBuffer->Y();
acMergeTmpBuffer[uiMergeCand] = m_acMergeTmpBuffer[uiMergeCand].getBuf(localUnitArea);
// 运动补偿
m_pcInterSearch->motionCompensation(pu, *singleMergeTempBuffer, REF_PIC_LIST_X, true, true, &(acMergeTmpBuffer[uiMergeCand]));
acMergeBuffer[uiMergeCand] = m_acRealMergeBuffer[uiMergeCand].getBuf(localUnitArea);
acMergeBuffer[uiMergeCand].copyFrom(*singleMergeTempBuffer);
pu.mvRefine = false;
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];
{
int dx, dy, i, j, num = 0;
dy = std::min<int>(pu.lumaSize().height, DMVR_SUBCU_HEIGHT);
dx = std::min<int>(pu.lumaSize().width, DMVR_SUBCU_WIDTH);
if (PU::checkDMVRCondition(pu))
{
for (i = 0; i < (pu.lumaSize().height); i += dy)
{
for (j = 0; j < (pu.lumaSize().width); j += dx)
{
refinedMvdL0[num][uiMergeCand] = pu.mvdL0SubPu[num];
num++;
}
}
}
}
}
Distortion uiSad = distParam.distFunc(distParam); //计算SAD
m_CABACEstimator->getCtx() = ctxStart;
uint64_t fracBits = m_pcInterSearch->xCalcPuMeBits(pu);
double cost = (double)uiSad + (double)fracBits * sqrtLambdaForFirstPassIntra; //计算Cost
insertPos = -1;
// 更新代价列表
updateCandList(ModeInfo(uiMergeCand, true, false, false), cost, RdModeList, candCostList, uiNumMrgSATDCand, &insertPos);
if (insertPos != -1)
{
if (insertPos == RdModeList.size() - 1)
{
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]);
}
}
CHECK(std::min(uiMergeCand + 1, uiNumMrgSATDCand) != RdModeList.size(), "");
} // for( uint32_t uiMergeCand = 0; uiMergeCand < mergeCtx.numValidMergeCand; uiMergeCand++ )
if (isIntrainterEnabled) //CIIP模式可用
{
// prepare for Intra bits calculation
pu.ciipFlag = true;
// save the to-be-tested merge candidates 保存要测试的CIIP候选模式
uint32_t CiipMergeCand[NUM_MRG_SATD_CAND];
for (uint32_t mergeCnt = 0; mergeCnt < std::min(NUM_MRG_SATD_CAND, (const int)mergeCtx.numValidMergeCand); mergeCnt++)
{
CiipMergeCand[mergeCnt] = RdModeList[mergeCnt].mergeCand;
}
// 遍历CIIP模式需要测试的候选Merge模式
for (uint32_t mergeCnt = 0; mergeCnt < std::min(std::min(NUM_MRG_SATD_CAND, (const int)mergeCtx.numValidMergeCand), 4); mergeCnt++)
{
uint32_t mergeCand = CiipMergeCand[mergeCnt];
acMergeTmpBuffer[mergeCand] = m_acMergeTmpBuffer[mergeCand].getBuf(localUnitArea);
// estimate merge bits 估计Merge 的bit数
mergeCtx.setMergeInfo(pu, mergeCand);
// first round
pu.intraDir[0] = PLANAR_IDX;//帧内用Planar模式
uint32_t intraCnt = 0;
// generate intrainter Y prediction 产生帧内帧间联合预测像素
if (mergeCnt == 0)
{//仅在第一个Merge候选模式计算一次Planar预测像素
m_pcIntraSearch->initIntraPatternChType(*pu.cu, pu.Y());
m_pcIntraSearch->predIntraAng(COMPONENT_Y, pu.cs->getPredBuf(pu).Y(), pu);
m_pcIntraSearch->switchBuffer(pu, COMPONENT_Y, pu.cs->getPredBuf(pu).Y(), m_pcIntraSearch->getPredictorPtr2(COMPONENT_Y, intraCnt));
}
pu.cs->getPredBuf(pu).copyFrom(acMergeTmpBuffer[mergeCand]); //加载相应Merge模式产生的帧间预测像素
if (pu.cs->slice->getLmcsEnabledFlag() && m_pcReshape->getCTUFlag())
{
pu.cs->getPredBuf(pu).Y().rspSignal(m_pcReshape->getFwdLUT());
}
// 计算CIIP预测像素
m_pcIntraSearch->geneWeightedPred(COMPONENT_Y, pu.cs->getPredBuf(pu).Y(), pu, m_pcIntraSearch->getPredictorPtr2(COMPONENT_Y, intraCnt));
// calculate cost 计算Cost
if (pu.cs->slice->getLmcsEnabledFlag() && m_pcReshape->getCTUFlag())
{
pu.cs->getPredBuf(pu).Y().rspSignal(m_pcReshape->getInvLUT());
}
distParam.cur = pu.cs->getPredBuf(pu).Y();
Distortion sadValue = distParam.distFunc(distParam);
if (pu.cs->slice->getLmcsEnabledFlag() && m_pcReshape->getCTUFlag())
{
pu.cs->getPredBuf(pu).Y().rspSignal(m_pcReshape->getFwdLUT());
}
m_CABACEstimator->getCtx() = ctxStart;
pu.regularMergeFlag = false;
uint64_t fracBits = m_pcInterSearch->xCalcPuMeBits(pu);
double cost = (double)sadValue + (double)fracBits * sqrtLambdaForFirstPassIntra;
insertPos = -1;
// 更新候选模式列表
updateCandList(ModeInfo(mergeCand, false, false, true), cost, RdModeList, candCostList, uiNumMrgSATDCand, &insertPos);
if (insertPos != -1)
{
for (int i = int(RdModeList.size()) - 1; i > insertPos; i--)
{
swap(acMergeTempBuffer[i - 1], acMergeTempBuffer[i]);
}
swap(singleMergeTempBuffer, acMergeTempBuffer[insertPos]);
}
}
pu.ciipFlag = false;
}// if (isIntrainterEnabled) CIIP模式
if ( pu.cs->sps->getUseMMVD() ) //使用MMVD模式,这里选出最优的MMVD的Merge候选(初始MV+搜索方向+搜索步长)
{
cu.mmvdSkip = true;
pu.regularMergeFlag = true; //普通Merge列表依旧可用,因为初始的MV还是要从普通Merge中获取
const int tempNum = (mergeCtx.numValidMergeCand > 1) ? MMVD_ADD_NUM : MMVD_ADD_NUM >> 1;
//对MMVD候选循环遍历,由于每个初始MV共有4种搜索方向,8种搜索步长,即每个初始MV产生32种细化MV
for (int mmvdMergeCand = 0; mmvdMergeCand < tempNum; mmvdMergeCand++)
{
int baseIdx = mmvdMergeCand / MMVD_MAX_REFINE_NUM;//初始MV索引,要么0 要么1(这里就是两个初始MV的起点,每个初始MV有32种4*8的步长+方向的组合)
int refineStep = (mmvdMergeCand - (baseIdx * MMVD_MAX_REFINE_NUM)) / 4;//表示8种步长
if (refineStep >= m_pcEncCfg->getMmvdDisNum())
continue;
//设置MMVD候选的信息,得到每个扩展MV具体的搜索初始点以及每个方向以及对应的步长
mergeCtx.setMmvdMergeCandiInfo(pu, mmvdMergeCand);
PU::spanMotionInfo(pu, mergeCtx);
pu.mvRefine = true;
distParam.cur = singleMergeTempBuffer->Y();
pu.mmvdEncOptMode = (refineStep > 2 ? 2 : 1);
CHECK(!pu.mmvdMergeFlag, "MMVD merge should be set");
// Don't do chroma MC here
//MMVD的Merge候选运动补偿计算预测值
m_pcInterSearch->motionCompensation(pu, *singleMergeTempBuffer, REF_PIC_LIST_X, true, false);
pu.mmvdEncOptMode = 0;
pu.mvRefine = false;
Distortion uiSad = distParam.distFunc(distParam);//失真函数
m_CABACEstimator->getCtx() = ctxStart;
uint64_t fracBits = m_pcInterSearch->xCalcPuMeBits(pu);//计算码率
double cost = (double)uiSad + (double)fracBits * sqrtLambdaForFirstPassIntra;//计算RD Cost
insertPos = -1;
//更新候选列表
updateCandList(ModeInfo(mmvdMergeCand, false, true, false), cost, RdModeList, candCostList, uiNumMrgSATDCand, &insertPos);
if (insertPos != -1)
{
for (int i = int(RdModeList.size()) - 1; i > insertPos; i--)
{
swap(acMergeTempBuffer[i - 1], acMergeTempBuffer[i]);
}
swap(singleMergeTempBuffer, acMergeTempBuffer[insertPos]);
}
}
} // MMVD
// Try to limit number of candidates using SATD-costs
// 尽量限制使用SATD-Cost的模式数
// 如果某个模式的Cost大于候选列表中的第一个模式的Cost*1.25,则后面的模式不再进行SATD-Cost计算
for( uint32_t i = 1; i < uiNumMrgSATDCand; i++ )
{
if( candCostList[i] > MRG_FAST_RATIO * candCostList[0] )
{
uiNumMrgSATDCand = i;
break;
}
}
setMergeBestSATDCost( candCostList[0] ); //设置Merge模式的最佳SATD Cost
if (isIntrainterEnabled && isChromaEnabled(pu.cs->pcv->chrFormat))//CIIP模式可用且存在色度分量
{
pu.ciipFlag = true;
for (uint32_t mergeCnt = 0; mergeCnt < uiNumMrgSATDCand; mergeCnt++)
{
if (RdModeList[mergeCnt].isCIIP) //对候选列表中的CIIP模式计算色度分量的Planar预测像素
{
pu.intraDir[0] = PLANAR_IDX;
pu.intraDir[1] = DM_CHROMA_IDX;
if (pu.chromaSize().width == 2)
continue;
uint32_t bufIdx = 0;
m_pcIntraSearch->initIntraPatternChType(*pu.cu, pu.Cb());
m_pcIntraSearch->predIntraAng(COMPONENT_Cb, pu.cs->getPredBuf(pu).Cb(), pu);
m_pcIntraSearch->switchBuffer(pu, COMPONENT_Cb, pu.cs->getPredBuf(pu).Cb(), m_pcIntraSearch->getPredictorPtr2(COMPONENT_Cb, bufIdx));
m_pcIntraSearch->initIntraPatternChType(*pu.cu, pu.Cr());
m_pcIntraSearch->predIntraAng(COMPONENT_Cr, pu.cs->getPredBuf(pu).Cr(), pu);
m_pcIntraSearch->switchBuffer(pu, COMPONENT_Cr, pu.cs->getPredBuf(pu).Cr(), m_pcIntraSearch->getPredictorPtr2(COMPONENT_Cr, bufIdx));
}
}
pu.ciipFlag = false;
}
tempCS->initStructData( encTestMode.qp );
m_CABACEstimator->getCtx() = ctxStart;
}
else
{
if (bestIsMMVDSkip) //如果最佳的模式是MMVD Skip模式
{
uiNumMrgSATDCand = mergeCtx.numValidMergeCand + ((mergeCtx.numValidMergeCand > 1) ? MMVD_ADD_NUM : MMVD_ADD_NUM >> 1);
}
else // 最佳模式是Skip模式
{
uiNumMrgSATDCand = mergeCtx.numValidMergeCand;
}
}
}
m_bestModeUpdated = tempCS->useDbCost = bestCS->useDbCost = false;
uint32_t iteration;
uint32_t iterationBegin = 0;
iteration = 2;
// 两次迭代,一次是Skip模式跳过残差编码;另一次是常规Merge模式
for (uint32_t uiNoResidualPass = iterationBegin; uiNoResidualPass < iteration; ++uiNoResidualPass)
{
// 遍历SATD个候选Merge模式
for( uint32_t uiMrgHADIdx = 0; uiMrgHADIdx < uiNumMrgSATDCand; uiMrgHADIdx++ )
{
uint32_t uiMergeCand = RdModeList[uiMrgHADIdx].mergeCand;//当前HAD列表中对应的Merge候选模式
if (uiNoResidualPass != 0 && RdModeList[uiMrgHADIdx].isCIIP) // intrainter does not support skip mode CIIP不支持Skip模式
{
if (isTestSkipMerge[uiMergeCand])
{
continue;
}
}
if (((uiNoResidualPass != 0) && candHasNoResidual[uiMrgHADIdx])
|| ( (uiNoResidualPass == 0) && bestIsSkip ) )
{
continue;
}
// first get merge candidates 首先获得Merge候选对象
CodingUnit &cu = tempCS->addCU( tempCS->area, partitioner.chType );
partitioner.setCUData( cu );
cu.slice = tempCS->slice;
cu.tileIdx = tempCS->pps->getTileIdx( tempCS->area.lumaPos() );
cu.skip = false;
cu.mmvdSkip = false;
cu.geoFlag = false;
//cu.affine
cu.predMode = MODE_INTER;
//cu.LICFlag
cu.chromaQpAdj = m_cuChromaQpOffsetIdxPlus1;
cu.qp = encTestMode.qp;
PredictionUnit &pu = tempCS->addPU( cu, partitioner.chType );
// 常规Merge模式并且是CIIP模式
if (uiNoResidualPass == 0 && RdModeList[uiMrgHADIdx].isCIIP)
{
cu.mmvdSkip = false;
mergeCtx.setMergeInfo(pu, uiMergeCand);
pu.ciipFlag = true;
pu.regularMergeFlag = false;
pu.intraDir[0] = PLANAR_IDX;
CHECK(pu.intraDir[0]<0 || pu.intraDir[0]>(NUM_LUMA_MODE - 1), "out of intra mode");
pu.intraDir[1] = DM_CHROMA_IDX;
}
else if (RdModeList[uiMrgHADIdx].isMMVD) //待测模式是MMVD模式
{
cu.mmvdSkip = true;
pu.regularMergeFlag = true;
mergeCtx.setMmvdMergeCandiInfo(pu, uiMergeCand);//设置MMVD候选信息
}
else //常规merge模式
{
cu.mmvdSkip = false;
pu.regularMergeFlag = true;
mergeCtx.setMergeInfo(pu, uiMergeCand); //设置Merge模式信息
}
PU::spanMotionInfo( pu, mergeCtx );
if( m_pcEncCfg->getMCTSEncConstraint() )
{
bool isDMVR = PU::checkDMVRCondition( pu );
if( ( isDMVR && MCTSHelper::isRefBlockAtRestrictedTileBoundary( pu ) ) || ( !isDMVR && !( MCTSHelper::checkMvBufferForMCTSConstraint( pu ) ) ) )
{
// Do not use this mode
tempCS->initStructData( encTestMode.qp );
continue;
}
}
if( mrgTempBufSet ) //设置Merge预测的临时Buffer
{
{
int dx, dy, i, j, num = 0;
dy = std::min<int>(pu.lumaSize().height, DMVR_SUBCU_HEIGHT);
dx = std::min<int>(pu.lumaSize().width, DMVR_SUBCU_WIDTH);
if (PU::checkDMVRCondition(pu)) //检查DMVR条件
{
for (i = 0; i < (pu.lumaSize().height); i += dy)
{
for (j = 0; j < (pu.lumaSize().width); j += dx)
{
pu.mvdL0SubPu[num] = refinedMvdL0[num][uiMergeCand];
num++;
}
}
}
}
if (pu.ciipFlag) //CIIP模式
{
uint32_t bufIdx = 0;
PelBuf tmpBuf = tempCS->getPredBuf(pu).Y(); //将预测值存储到tmpBuf中
tmpBuf.copyFrom(acMergeTmpBuffer[uiMergeCand].Y());
if (pu.cs->slice->getLmcsEnabledFlag() && m_pcReshape->getCTUFlag())
{
tmpBuf.rspSignal(m_pcReshape->getFwdLUT());
}
// 获得加权预测值
m_pcIntraSearch->geneWeightedPred(COMPONENT_Y, tmpBuf, pu, m_pcIntraSearch->getPredictorPtr2(COMPONENT_Y, bufIdx));
if (isChromaEnabled(pu.chromaFormat))
{
if (pu.chromaSize().width > 2)
{
tmpBuf = tempCS->getPredBuf(pu).Cb();
tmpBuf.copyFrom(acMergeTmpBuffer[uiMergeCand].Cb());
m_pcIntraSearch->geneWeightedPred(COMPONENT_Cb, tmpBuf, pu, m_pcIntraSearch->getPredictorPtr2(COMPONENT_Cb, bufIdx));
tmpBuf = tempCS->getPredBuf(pu).Cr();
tmpBuf.copyFrom(acMergeTmpBuffer[uiMergeCand].Cr());
m_pcIntraSearch->geneWeightedPred(COMPONENT_Cr, tmpBuf, pu, m_pcIntraSearch->getPredictorPtr2(COMPONENT_Cr, bufIdx));
}
else
{
tmpBuf = tempCS->getPredBuf(pu).Cb();
tmpBuf.copyFrom(acMergeTmpBuffer[uiMergeCand].Cb());
tmpBuf = tempCS->getPredBuf(pu).Cr();
tmpBuf.copyFrom(acMergeTmpBuffer[uiMergeCand].Cr());
}
}
} //pu.ciipFlag
else
{
if (RdModeList[uiMrgHADIdx].isMMVD) //MMVD模式
{
pu.mmvdEncOptMode = 0;
m_pcInterSearch->motionCompensation(pu); //运动补偿
}
else if (uiNoResidualPass != 0 && RdModeList[uiMrgHADIdx].isCIIP)
{
tempCS->getPredBuf().copyFrom(acMergeBuffer[uiMergeCand]);
}
else
{
tempCS->getPredBuf().copyFrom(*acMergeTempBuffer[uiMrgHADIdx]);
}
}
} // if (mrgTempBufSet)
else
{
pu.mvRefine = true;
m_pcInterSearch->motionCompensation( pu ); //运动补偿
pu.mvRefine = false;
}
if (!cu.mmvdSkip && !pu.ciipFlag && uiNoResidualPass != 0)
{
CHECK(uiMergeCand >= mergeCtx.numValidMergeCand, "out of normal merge");
isTestSkipMerge[uiMergeCand] = true; //对该Merge模式检查了Skip模式
}
// 编码残差
xEncodeInterResidual( tempCS, bestCS, partitioner, encTestMode, uiNoResidualPass, uiNoResidualPass == 0 ? &candHasNoResidual[uiMrgHADIdx] : NULL );
if( m_pcEncCfg->getUseFastDecisionForMerge() && !bestIsSkip && !pu.ciipFlag)
{
bestIsSkip = !bestCS->cus.empty() && bestCS->getCU( partitioner.chType )->rootCbf == 0;
}
tempCS->initStructData( encTestMode.qp );
}// end loop uiMrgHADIdx
if( uiNoResidualPass == 0 && m_pcEncCfg->getUseEarlySkipDetection() )
{
const CodingUnit &bestCU = *bestCS->getCU( partitioner.chType );
const PredictionUnit &bestPU = *bestCS->getPU( partitioner.chType );
if( bestCU.rootCbf == 0 )
{
if( bestPU.mergeFlag )
{
m_modeCtrl->setEarlySkipDetected();
}
else if( m_pcEncCfg->getMotionEstimationSearchMethod() != MESEARCH_SELECTIVE )
{
int absolute_MV = 0;
for( uint32_t uiRefListIdx = 0; uiRefListIdx < 2; uiRefListIdx++ )
{
if( slice.getNumRefIdx( RefPicList( uiRefListIdx ) ) > 0 )
{
absolute_MV += bestPU.mvd[uiRefListIdx].getAbsHor() + bestPU.mvd[uiRefListIdx].getAbsVer();
}
}
if( absolute_MV == 0 )
{
m_modeCtrl->setEarlySkipDetected();
}
}
}
}
}
if ( m_bestModeUpdated && bestCS->cost != MAX_DOUBLE )
{
xCalDebCost( *bestCS, partitioner );
}
}