xCheckRDCostMerge2Nx2N函数,构建mv候选列表,对每一个mv进行运动补偿,得到预测块后通过sad/satd计算rdcost,放入RdModeList和candCostList中,放入时有排序操作,csot最小的在最前面。开启CIIP时,根据候选列表中的前4个mv,利用mv的预测块与该块帧内预测的预测块加权生成新的预测块,计算rdcost,放入列表中。开启MMVD模式时根据候选列表中的前两个mv构建64个新的mv,计算rdcost,放入列表中。过程中有缩减列表长度等操作。最后会对所有模式在进行两轮细选,计算rdcost决策最优。
1.构建mv候选列表
包含了空域,时域,HMVP等候选,设定特定的长度,这里是6,如果数量不够 ,用零mv填补。
2. MMVD模式
MMVD模式,对于Merge候选列表中的前两个MV,分别从四个方向,8个offset偏移值,得到64个新的mv。
该模式编码时编码在merge候选列表中的索引值,搜索方向以及搜索步长。
3.CIIP模式
CIIP模式,利用帧内预测块与帧间预测块的加权得到新的预测块
代码注释如下:
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 GDR_ENABLED
bool isEncodeGdrClean = false;
CodingStructure *cs;
#endif
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 );
{
// first get merge candidates
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;
// 构建merge候选列表,空域,时域,HMVP,补零,得到的候选mv存储在mergeCtx中
PU::getInterMergeCandidates(pu, mergeCtx, 0);
// 根据两个baseMV,进行进一步搜索,与普通merge列表mv和CCIP的mv竞争
PU::getInterMMVDMergeCandidates(pu, mergeCtx);
pu.regularMergeFlag = true;
#if GDR_ENABLED
cs = pu.cs;
isEncodeGdrClean = cs->sps->getGDREnabledFlag() && cs->pcv->isEncoder && ((cs->picHeader->getInGdrInterval() && cs->isClean(pu.Y().topRight(), CHANNEL_TYPE_LUMA)) || (cs->picHeader->getNumVerVirtualBoundaries() == 0));
#endif
}
bool candHasNoResidual[MRG_MAX_NUM_CANDS + MMVD_ADD_NUM];
for (uint32_t ui = 0; ui < MRG_MAX_NUM_CANDS + MMVD_ADD_NUM; ui++)
{
candHasNoResidual[ui] = false;
}
bool bestIsSkip = false;
bool bestIsMMVDSkip = true;
PelUnitBuf acMergeBuffer[MRG_MAX_NUM_CANDS]; // 保存所有merge候选运动补偿出来的预测块的buffer
PelUnitBuf acMergeTmpBuffer[MRG_MAX_NUM_CANDS];
PelUnitBuf acMergeRealBuffer[MMVD_MRG_MAX_RD_BUF_NUM]; //保存所有merge候选运动补偿后对真实值的预测值
PelUnitBuf *acMergeTempBuffer[MMVD_MRG_MAX_RD_NUM];
PelUnitBuf *singleMergeTempBuffer; //单merge候选列表预测值缓存
int insertPos;
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;
bool mrgTempBufSet = false;
const int candNum = mergeCtx.numValidMergeCand + (tempCS->sps->getUseMMVD() ? std::min<int>(MMVD_BASE_MV_NUM, mergeCtx.numValidMergeCand) * MMVD_MAX_REFINE_NUM : 0);
for (int i = 0; i < candNum; i++)
{
if (i < mergeCtx.numValidMergeCand)
{
RdModeList.push_back(ModeInfo(i, true, false, false));
}
else
{
RdModeList.push_back(ModeInfo(std::min(MMVD_ADD_NUM, i - mergeCtx.numValidMergeCand), false, true, false));
}
}
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
for (uint32_t idx = 0; idx < MRG_MAX_NUM_CANDS; idx++)
{
isTestSkipMerge[idx] = false;
}
// 缩减进行RDCost细选的模式数
if( m_pcEncCfg->getUseFastMerge() || isIntrainterEnabled)
{
uiNumMrgSATDCand = NUM_MRG_SATD_CAND;
if (isIntrainterEnabled)
{
uiNumMrgSATDCand += 1;
}
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;
}
// 简化版rdcost列表
static_vector<double, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM> candCostList;
// 1. Pass: get SATD-cost for selected candidates and reduce their count
if( !bestIsSkip )
{
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.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候选项,计算SATD并更新候选列表
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);
// 运动补偿,根据pu中的mv生成预测块,存放在singleMergeTempBuffer中
m_pcInterSearch->motionCompensation(pu, *singleMergeTempBuffer, REF_PIC_LIST_X, true, true, &(acMergeTmpBuffer[uiMergeCand]));
acMergeBuffer[uiMergeCand] = m_acRealMergeBuffer[uiMergeCand].getBuf(localUnitArea);
acMergeBuffer[uiMergeCand].copyFrom(*singleMergeTempBuffer);
// mv是否可以细化
pu.mvRefine = false;
if (mergeCtx.interDirNeighbours[uiMergeCand] == 3)
{
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);
// 判断是否能进行DMVR
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);
m_CABACEstimator->getCtx() = ctxStart;
uint64_t fracBits = m_pcInterSearch->xCalcPuMeBits(pu);
double cost = (double)uiSad + (double)fracBits * sqrtLambdaForFirstPassIntra;
insertPos = -1;
#if GDR_ENABLED
// Non-RD cost for regular merge
if (isEncodeGdrClean)
{
bool isSolid = true;
bool isValid = true;
if (mergeCtx.mvFieldNeighbours[(uiMergeCand << 1) + 0].refIdx >= 0)
{
Mv mv = mergeCtx.mvFieldNeighbours[(uiMergeCand << 1) + 0].mv;
int ridx = mergeCtx.mvFieldNeighbours[(uiMergeCand << 1) + 0].refIdx;
mergeCtx.mvValid[(uiMergeCand << 1) + 0] = cs->isClean(pu.Y().bottomRight(), mv, REF_PIC_LIST_0, ridx);
isSolid = isSolid && mergeCtx.mvSolid[(uiMergeCand << 1) + 0];
isValid = isValid && mergeCtx.mvValid[(uiMergeCand << 1) + 0];
}
if (mergeCtx.mvFieldNeighbours[(uiMergeCand << 1) + 1].refIdx >= 0) \
{
Mv mv = mergeCtx.mvFieldNeighbours[(uiMergeCand << 1) + 1].mv;
int ridx = mergeCtx.mvFieldNeighbours[(uiMergeCand << 1) + 1].refIdx;
mergeCtx.mvValid[(uiMergeCand << 1) + 1] = cs->isClean(pu.Y().bottomRight(), mv, REF_PIC_LIST_1, ridx);
isSolid = isSolid && mergeCtx.mvSolid[(uiMergeCand << 1) + 1];
isValid = isValid && mergeCtx.mvValid[(uiMergeCand << 1) + 1];
}
if (!isValid || !isSolid)
{
cost = MAX_DOUBLE;
}
}
#endif
// 更新候选列表,cost按大小顺序插入到对应位置,会返回插入位置insertPos
updateCandList(ModeInfo(uiMergeCand, true, false, false), cost, RdModeList, candCostList, uiNumMrgSATDCand, &insertPos);
// acMergeTempBuffer是一个指针数组,指向了acMergeRealBuffer,里面按cost顺序存储了各个模式的预测块buffer
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]);
}
}
#if !GDR_ENABLED
CHECK(std::min(uiMergeCand + 1, uiNumMrgSATDCand) != RdModeList.size(), "");
#endif
}
// 利用前四个模式判断CIIP是否可以更优
if (isIntrainterEnabled)
{
// prepare for Intra bits calculation
pu.ciipFlag = true;
// save the to-be-tested merge candidates
uint32_t CiipMergeCand[NUM_MRG_SATD_CAND];
// CIIP利用前四个mv
for (uint32_t mergeCnt = 0; mergeCnt < std::min(NUM_MRG_SATD_CAND, (const int)mergeCtx.numValidMergeCand); mergeCnt++)
{
// 这个mergeCand是index,可从上面updateCandList看明白
CiipMergeCand[mergeCnt] = RdModeList[mergeCnt].mergeCand;
}
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
mergeCtx.setMergeInfo(pu, mergeCand);
// first round
pu.intraDir[0] = PLANAR_IDX;
uint32_t intraCnt = 0;
// generate intrainter Y prediction
if (mergeCnt == 0)
{
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]);
if (pu.cs->slice->getLmcsEnabledFlag() && m_pcReshape->getCTUFlag())
{
pu.cs->getPredBuf(pu).Y().rspSignal(m_pcReshape->getFwdLUT());
}
m_pcIntraSearch->geneWeightedPred(COMPONENT_Y, pu.cs->getPredBuf(pu).Y(), pu, m_pcIntraSearch->getPredictorPtr2(COMPONENT_Y, intraCnt));
// calculate 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;
#if GDR_ENABLED
// Non-RD cost for CIIP merge
if (isEncodeGdrClean)
{
bool isSolid = true;
bool isValid = true;
if (mergeCtx.mvFieldNeighbours[(mergeCand << 1) + 0].refIdx >= 0)
{
Mv mv = mergeCtx.mvFieldNeighbours[(mergeCand << 1) + 0].mv;
int ridx = mergeCtx.mvFieldNeighbours[(mergeCand << 1) + 0].refIdx;
mergeCtx.mvValid[(mergeCand << 1) + 0] = cs->isClean(pu.Y().bottomRight(), mv, REF_PIC_LIST_0, ridx);
isSolid = isSolid && mergeCtx.mvSolid[(mergeCand << 1) + 0];
isValid = isValid && mergeCtx.mvValid[(mergeCand << 1) + 0];
}
if (mergeCtx.mvFieldNeighbours[(mergeCand << 1) + 1].refIdx >= 0)
{
Mv mv = mergeCtx.mvFieldNeighbours[(mergeCand << 1) + 1].mv;
int ridx = mergeCtx.mvFieldNeighbours[(mergeCand << 1) + 1].refIdx;
mergeCtx.mvValid[(mergeCand << 1) + 1] = cs->isClean(pu.Y().bottomRight(), mv, REF_PIC_LIST_1, ridx);
isSolid = isSolid && mergeCtx.mvSolid[(mergeCand << 1) + 1];
isValid = isValid && mergeCtx.mvValid[(mergeCand << 1) + 1];
}
if (!isValid || !isSolid)
{
cost = MAX_DOUBLE;
}
}
#endif
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;
}
//计算64个新的mv的预测块,并计算satd,更新到候选列表中
if ( pu.cs->sps->getUseMMVD() )
{
cu.mmvdSkip = true;
pu.regularMergeFlag = true;
const int tempNum = (mergeCtx.numValidMergeCand > 1) ? MMVD_ADD_NUM : MMVD_ADD_NUM >> 1;
for (int mmvdMergeCand = 0; mmvdMergeCand < tempNum; mmvdMergeCand++)
{
int baseIdx = mmvdMergeCand / MMVD_MAX_REFINE_NUM;
// 四个方向,每个方向8个offset值,refineStep可以表示哪一个offset值
int refineStep = (mmvdMergeCand - (baseIdx * MMVD_MAX_REFINE_NUM)) / 4;
if (refineStep >= m_pcEncCfg->getMmvdDisNum())
{
continue;
}
#if GDR_ENABLED
if (isEncodeGdrClean)
{
pu.mvSolid[REF_PIC_LIST_0] = true;
pu.mvSolid[REF_PIC_LIST_1] = true;
pu.mvValid[REF_PIC_LIST_0] = true;
pu.mvValid[REF_PIC_LIST_1] = true;
}
#endif
// 根据mmvdMergeCand,设置偏移得到新的mv,赋值到pu中
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
m_pcInterSearch->motionCompensation(pu, *singleMergeTempBuffer, REF_PIC_LIST_X, true, false, nullptr);
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;
insertPos = -1;
#if GDR_ENABLED
if (isEncodeGdrClean)
{
bool isSolid = true;
bool isValid = true;
if (pu.refIdx[0] >= 0)
{
isSolid = isSolid && pu.mvSolid[0];
isValid = isValid && pu.mvValid[0];
}
if (pu.refIdx[1] >= 0)
{
isSolid = isSolid && pu.mvSolid[1];
isValid = isValid && pu.mvValid[1];
}
if (!isSolid || !isValid)
{
cost = MAX_DOUBLE;
}
}
#endif
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]);
}
}
}
// 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;
}
}
setMergeBestSATDCost( candCostList[0] );
if (isIntrainterEnabled && isChromaEnabled(pu.cs->pcv->chrFormat))
{
pu.ciipFlag = true;
for (uint32_t mergeCnt = 0; mergeCnt < uiNumMrgSATDCand; mergeCnt++)
{
if (RdModeList[mergeCnt].isCIIP)
{
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)
{
uiNumMrgSATDCand = mergeCtx.numValidMergeCand + ((mergeCtx.numValidMergeCand > 1) ? MMVD_ADD_NUM : MMVD_ADD_NUM >> 1);
}
else
{
uiNumMrgSATDCand = mergeCtx.numValidMergeCand;
}
}
}
m_bestModeUpdated = tempCS->useDbCost = bestCS->useDbCost = false;
uint32_t iteration;
uint32_t iterationBegin = 0;
iteration = 2;
// 两轮迭代,第一轮是不开启skip下的,第二轮是开启skip下的
for (uint32_t uiNoResidualPass = iterationBegin; uiNoResidualPass < iteration; ++uiNoResidualPass)
{
// 遍历粗选的模式,进行细选
for( uint32_t uiMrgHADIdx = 0; uiMrgHADIdx < uiNumMrgSATDCand; uiMrgHADIdx++ )
{
uint32_t uiMergeCand = RdModeList[uiMrgHADIdx].mergeCand;
if (uiNoResidualPass != 0 && RdModeList[uiMrgHADIdx].isCIIP) // intrainter does not support skip mode
{
if (isTestSkipMerge[uiMergeCand])
{
continue;
}
}
if (((uiNoResidualPass != 0) && candHasNoResidual[uiMrgHADIdx])
|| ( (uiNoResidualPass == 0) && bestIsSkip ) )
{
continue;
}
// first get merge candidates
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.chromaQpAdj = m_cuChromaQpOffsetIdxPlus1;
cu.qp = encTestMode.qp;
PredictionUnit &pu = tempCS->addPU( cu, partitioner.chType );
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)
{
cu.mmvdSkip = true;
pu.regularMergeFlag = true;
mergeCtx.setMmvdMergeCandiInfo(pu, uiMergeCand);
}
else
{
cu.mmvdSkip = false;
pu.regularMergeFlag = true;
mergeCtx.setMergeInfo(pu, uiMergeCand);
}
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 )
{
{
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)
{
pu.mvdL0SubPu[num] = refinedMvdL0[num][uiMergeCand];
num++;
}
}
}
}
// 这里的代码是要根据候选的不同的模式,分别计算其预测值
if (pu.ciipFlag)
{
uint32_t bufIdx = 0;
// 这里理解为,tmpBuf是AreaBuf类型结构体,里面有一个指针和一个stride
// 这里直接等于,表示指针还是指向了tempCS里面的东西,所以改变这个tempBuf里面的指针所在地方的数值,就是改变tempCS里面的东西
// copyfrom只是往这块内存里初始化一堆值或者是分配一块内存
// 所以可以解释执行完geneWeightedPred就结束了,因为相当于tempCS->getPredBuf(pu).Y()里面的buf指向的位置的数已经改了
PelBuf tmpBuf = tempCS->getPredBuf(pu).Y();
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());
}
}
}
else
{
if (RdModeList[uiMrgHADIdx].isMMVD)
{
pu.mmvdEncOptMode = 0;
m_pcInterSearch->motionCompensatePu(pu, REF_PIC_LIST_X, true, true);
}
else if (uiNoResidualPass != 0 && RdModeList[uiMrgHADIdx].isCIIP)
{
tempCS->getPredBuf().copyFrom(acMergeBuffer[uiMergeCand]);
}
else
{
tempCS->getPredBuf().copyFrom(*acMergeTempBuffer[uiMrgHADIdx]);
}
}
}
else
{
pu.mvRefine = true;
m_pcInterSearch->motionCompensatePu(pu, REF_PIC_LIST_X, true, true);
pu.mvRefine = false;
}
if (!cu.mmvdSkip && !pu.ciipFlag && uiNoResidualPass != 0)
{
CHECK(uiMergeCand >= mergeCtx.numValidMergeCand, "out of normal merge");
isTestSkipMerge[uiMergeCand] = true;
}
#if GDR_ENABLED
if (isEncodeGdrClean)
{
bool isSolid = true;
bool isValid = true;
if (pu.refIdx[0] >= 0)
{
isSolid = isSolid && pu.mvSolid[0];
isValid = isValid && pu.mvValid[0];
}
if (pu.refIdx[1] >= 0)
{
isSolid = isSolid && pu.mvSolid[1];
isValid = isValid && pu.mvValid[1];
}
if (isSolid && isValid)
{
// 残差编码,找到最优的预测模式,计算rdcost
xEncodeInterResidual(tempCS, bestCS, partitioner, encTestMode, uiNoResidualPass,
uiNoResidualPass == 0 ? &candHasNoResidual[uiMrgHADIdx] : nullptr);
}
}
else
{
xEncodeInterResidual(tempCS, bestCS, partitioner, encTestMode, uiNoResidualPass,
uiNoResidualPass == 0 ? &candHasNoResidual[uiMrgHADIdx] : nullptr);
}
#else
xEncodeInterResidual(tempCS, bestCS, partitioner, encTestMode, uiNoResidualPass,
uiNoResidualPass == 0 ? &candHasNoResidual[uiMrgHADIdx] : nullptr);
#endif
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 );
}
}