Multiple reference line (MRL) intra prediction
H.266/VVC中,进行帧内预测时,允许使用多参考行。在下图中,描绘4条参考行的示例,其中Segment A和Segment F不是由重建像素获得的,而是分别用Segment B和Segment E最近的像素填充获得的。
在HEVC中只允许使用使用参考行0,在VVC中,除了可以使用参考行0,还可以使用参考行1、2(MRL),还可以使用参考行1、3(MRL)。这是因为在索引号为0~3的参考行中,索引号为0和1的参考像素行与当前预测单元中的像素距离相对较近,有较高的相关性,因此需要保留。索引为3的参考像素行与当前预测单元的距离相对较远,可以提供较为不同的参考像素,而索引为2的参考像素行,很难提供额外的参考像素信息。
所选的参考行索引号mrl_idx需要放入码流传到解码端。对于mrl_idx>0的情况,只使用MPM列表中的后5种模式并且只需要传输MPM的索引号(即使用MRL模式时候仅使用MPM列表中的5个预测模式进行预测,不包括Planar模式)。在传输时mrl_idx要在帧内模式编码之前,并且当mrl_idx非零时,帧内预测模式不包括Planar和DC模式。
当处理CTU的第一行时,禁止使用MRL,以防止在当前CTU行之外使用扩展的参考样本。并且,当使用MRL时,禁止使用PDPC技术。
对于MRL模式,非零参考行的DC模式中DC值的推导与参考行索引0的推导一致。MRL需要用CTU存储3条相邻的亮度参考行来生成预测。
交叉分量线性模型(CCLM)工具还需要3条相邻的亮度参考行作为其下采样滤波器。使用相同3行的MLR的定义与CCLM对齐,以减少解码器的存储需求。
在进行帧内RDO的时候,会遍历不同的参考行索引和MPM列表中的模式,并选出最有可能的几种模式加入到模式列表中。
pu.multiRefIdx = 1;
const int numMPMs = NUM_MOST_PROBABLE_MODES;
unsigned multiRefMPM[numMPMs];
PU::getIntraMPMs(pu, multiRefMPM);
for (int mRefNum = 1; mRefNum < numOfPassesExtendRef; mRefNum++)
{
int multiRefIdx = MULTI_REF_LINE_IDX[mRefNum];
pu.multiRefIdx = multiRefIdx;
{
initIntraPatternChType(cu, pu.Y(), true);
}
for (int x = 1; x < numMPMs; x++)
{
uint32_t mode = multiRefMPM[x];
{
pu.intraDir[0] = mode;
initPredIntraParams(pu, pu.Y(), sps);
predIntraAng(COMPONENT_Y, piPred, pu);
// Use the min between SAD and SATD as the cost criterion
// SAD is scaled by 2 to align with the scaling of HAD
Distortion minSadHad =
std::min(distParamSad.distFunc(distParamSad) * 2, distParamHad.distFunc(distParamHad));
// NB xFracModeBitsIntra will not affect the mode for chroma that may have already been pre-estimated.
m_CABACEstimator->getCtx() = SubCtx(Ctx::MipFlag, ctxStartMipFlag);
m_CABACEstimator->getCtx() = SubCtx(Ctx::ISPMode, ctxStartIspMode);
m_CABACEstimator->getCtx() = SubCtx(Ctx::IntraLumaPlanarFlag, ctxStartPlanarFlag);
m_CABACEstimator->getCtx() = SubCtx(Ctx::IntraLumaMpmFlag, ctxStartIntraMode);
m_CABACEstimator->getCtx() = SubCtx(Ctx::MultiRefLineIdx, ctxStartMrlIdx);
uint64_t fracModeBits = xFracModeBitsIntra(pu, mode, CHANNEL_TYPE_LUMA);
double cost = (double) minSadHad + (double) fracModeBits * sqrtLambdaForFirstPass;
updateCandList(ModeInfo(false, false, multiRefIdx, NOT_INTRA_SUBPARTITIONS, mode), cost, uiRdModeList,
CandCostList, numModesForFullRD);
updateCandList(ModeInfo(false, false, multiRefIdx, NOT_INTRA_SUBPARTITIONS, mode), double(minSadHad),
uiHadModeList, CandHadList, numHadCand);
}
}
}