基于模板匹配的Merge候选列表的自适应重排序(Adaptive reordering of merge candidates with template matching, ARMC)技术是使用模板匹配的方法对Merge列表进行重排序,通过重排序,可以将更准确的Merge候选项放在Merge列表的前面,从而可以降低Merge索引的编码比特。
ARMC-TM应用于常规Merge模式、模板匹配(TM) Merge模式和Affine Merge模式(不包括 SbTMVP 候选)。 对于 TM Merge模式,Merge候选项在模板搜素细化过程之前重新排序。
具体地,在构建Merge候选列表后,Merge候选被分成若干subGroups。 subgroup大小设置为5(Affine Merge模式时为3)。每个subgroup中的Merge候选根据基于模板匹配代价值从小到大重新排序。 为简化起见,不重新排序最后一个子组中的Merge候选项。
其中,模板匹配代价是通过当前块的模板样本与该模板对应的参考样本之间的绝对差(SAD)之和来衡量的。 该模板包括与当前块相邻的一组重建样本。 模板的参考样本通过当前块的运动信息进行运动补偿得到的。模板的宽度(对于左模板)或者高度(对于上模板)为1。
当Merge候选项使用双向预测时, Merge候选项的模板的参考样本也是通过双向预测生成的,如下图所示。
对于基于子块的Merge候选(如Affine),模板的参考样本是根据子块的运动信息得到的子模板拼接成的。对于子块大小等于Wsub*Hsub的,上面的模板包括几个大小为Wsub×1的子模板,左边的模板包括几个大小为1×Hsub的子模板。 如下图所示,利用当前块的第一行第一列子块的运动信息进行运动补偿得到每个子模板的参考样本。
相关代码:
adjustInterMergeCandidates函数用于常规Merge模式、模板匹配(TM) Merge模式候选列表的重排序,代码及相关注释如下:
// mrgCtx 表示Merge的上下文
// 编码端 mrgCandIdx = -1,表示需要遍历Merge候选列表的全部
// 解码端mrgCandIdx = pu.mergeIdx,表示根据Merge索引找出相对应的Merge候选项
void InterPrediction::adjustInterMergeCandidates(PredictionUnit &pu, MergeCtx& mrgCtx, int mrgCandIdx)
{
// 初始化候选列表及其代价,二维:第一维是子组,第二维是每个子组的候选项
uint32_t RdCandList[MRG_MAX_NUM_CANDS][MRG_MAX_NUM_CANDS];
Distortion candCostList[MRG_MAX_NUM_CANDS][MRG_MAX_NUM_CANDS];
for (uint32_t i = 0; i < MRG_MAX_NUM_CANDS; i++)
{
for (uint32_t j = 0; j < MRG_MAX_NUM_CANDS; j++)
{
RdCandList[i][j] = j;
candCostList[i][j] = MAX_UINT;
}
}
Distortion uiCost;
DistParam cDistParam;
cDistParam.applyWeight = false;
/*const SPS &sps = *pu.cs->sps;
Position puPos = pu.lumaPos();*/
int nWidth = pu.lumaSize().width;
int nHeight = pu.lumaSize().height;
// 判断当前模板区域是否可用,如果左侧模板区域和上侧模板区域均不可用,则返回FALSE
if (!xAMLGetCurBlkTemplate(pu, nWidth, nHeight))
{
return;
}
#if JVET_X0049_ADAPT_DMVR
uint8_t origMergeIdx = pu.mergeIdx;
#endif
for (uint32_t uiMergeCand = ((mrgCandIdx < 0) ? 0 : (mrgCandIdx / ADAPTIVE_SUB_GROUP_SIZE)*ADAPTIVE_SUB_GROUP_SIZE); uiMergeCand < (((mrgCandIdx < 0) || ((mrgCandIdx / ADAPTIVE_SUB_GROUP_SIZE + 1)*ADAPTIVE_SUB_GROUP_SIZE > mrgCtx.numValidMergeCand)) ? mrgCtx.numValidMergeCand : ((mrgCandIdx / ADAPTIVE_SUB_GROUP_SIZE + 1)*ADAPTIVE_SUB_GROUP_SIZE)); ++uiMergeCand)
{
bool firstGroup = (uiMergeCand / ADAPTIVE_SUB_GROUP_SIZE) == 0 ? true : false; // 是否是第一个子组
// 是否是最后一个子组
bool lastGroup = ((uiMergeCand / ADAPTIVE_SUB_GROUP_SIZE + 1)*ADAPTIVE_SUB_GROUP_SIZE >= mrgCtx.numValidMergeCand) ? true : false;
if (lastGroup && !firstGroup)
{
break; // 对于最后一个子组不进行重排
}
uiCost = 0;
mrgCtx.setMergeInfo(pu, uiMergeCand); // 根据Merge索引设置pu的运动信息
PU::spanMotionInfo(pu, mrgCtx);
PelUnitBuf pcBufPredRefTop = (PelUnitBuf(pu.chromaFormat, PelBuf(m_acYuvRefAMLTemplate[0][0], nWidth, AML_MERGE_TEMPLATE_SIZE)));
PelUnitBuf pcBufPredCurTop = (PelUnitBuf(pu.chromaFormat, PelBuf(m_acYuvCurAMLTemplate[0][0], nWidth, AML_MERGE_TEMPLATE_SIZE)));
PelUnitBuf pcBufPredRefLeft = (PelUnitBuf(pu.chromaFormat, PelBuf(m_acYuvRefAMLTemplate[1][0], AML_MERGE_TEMPLATE_SIZE, nHeight)));
PelUnitBuf pcBufPredCurLeft = (PelUnitBuf(pu.chromaFormat, PelBuf(m_acYuvCurAMLTemplate[1][0], AML_MERGE_TEMPLATE_SIZE, nHeight)));
getBlkAMLRefTemplate(pu, pcBufPredRefTop, pcBufPredRefLeft); // 获取参考模板
// 计算当前模板和参考模板之间的cost
if (m_bAMLTemplateAvailabe[0])
{
m_pcRdCost->setDistParam(cDistParam, pcBufPredCurTop.Y(), pcBufPredRefTop.Y(), pu.cs->sps->getBitDepth(CHANNEL_TYPE_LUMA), COMPONENT_Y, false);
uiCost += cDistParam.distFunc(cDistParam);
}
if (m_bAMLTemplateAvailabe[1])
{
m_pcRdCost->setDistParam(cDistParam, pcBufPredCurLeft.Y(), pcBufPredRefLeft.Y(), pu.cs->sps->getBitDepth(CHANNEL_TYPE_LUMA), COMPONENT_Y, false);
uiCost += cDistParam.distFunc(cDistParam);
}
// 更新每个子组列表,根据Cost将每个子组进行排序
updateCandList(uiMergeCand, uiCost, ADAPTIVE_SUB_GROUP_SIZE, RdCandList[uiMergeCand / ADAPTIVE_SUB_GROUP_SIZE], candCostList[uiMergeCand / ADAPTIVE_SUB_GROUP_SIZE]);
}
#if JVET_X0049_ADAPT_DMVR
pu.mergeIdx = origMergeIdx;
#else
pu.mergeIdx = mrgCandIdx; //restore the merge index
#endif
// 按照子组列表的顺序更新Merge候选列表
updateCandInfo(mrgCtx, RdCandList
, mrgCandIdx
);
}
adjustAffineMergeCandidates函数用于Affine Merge模式候选列表的重新排序,代码及注释如下:
void InterPrediction::adjustAffineMergeCandidates(PredictionUnit &pu, AffineMergeCtx& affMrgCtx, int mrgCandIdx)
{
// 初始化Affine候选代价列表
uint32_t RdCandList[AFFINE_MRG_MAX_NUM_CANDS][AFFINE_MRG_MAX_NUM_CANDS];
Distortion candCostList[AFFINE_MRG_MAX_NUM_CANDS][AFFINE_MRG_MAX_NUM_CANDS];
for (uint32_t i = 0; i < AFFINE_MRG_MAX_NUM_CANDS; i++)
{
for (uint32_t j = 0; j < AFFINE_MRG_MAX_NUM_CANDS; j++)
{
RdCandList[i][j] = j;
candCostList[i][j] = MAX_UINT;
}
}
Distortion uiCost;
DistParam cDistParam;
cDistParam.applyWeight = false;
int nWidth = pu.lumaSize().width;
int nHeight = pu.lumaSize().height;
// 获取当前模板
if (!xAMLGetCurBlkTemplate(pu, nWidth, nHeight))
{
return;
}
for (uint32_t uiMergeCand = ((mrgCandIdx < 0) ? 0 : (mrgCandIdx / ADAPTIVE_AFFINE_SUB_GROUP_SIZE)*ADAPTIVE_AFFINE_SUB_GROUP_SIZE); uiMergeCand < (((mrgCandIdx < 0) || ((mrgCandIdx / ADAPTIVE_AFFINE_SUB_GROUP_SIZE + 1)*ADAPTIVE_AFFINE_SUB_GROUP_SIZE > affMrgCtx.maxNumMergeCand)) ? affMrgCtx.maxNumMergeCand : ((mrgCandIdx / ADAPTIVE_AFFINE_SUB_GROUP_SIZE + 1)*ADAPTIVE_AFFINE_SUB_GROUP_SIZE)); ++uiMergeCand)
{
bool firstGroup = (uiMergeCand / ADAPTIVE_AFFINE_SUB_GROUP_SIZE) == 0 ? true : false; // 是否是第一个子组
// 是否是最后一个子组
bool lastGroup = ((uiMergeCand / ADAPTIVE_AFFINE_SUB_GROUP_SIZE + 1)*ADAPTIVE_AFFINE_SUB_GROUP_SIZE >= affMrgCtx.maxNumMergeCand) ? true : false;
if (lastGroup && !firstGroup) // 对于最后一个子组不进行重排
{
break;
}
uiCost = 0;
// set merge information
pu.interDir = affMrgCtx.interDirNeighbours[uiMergeCand];
pu.mergeFlag = true;
pu.regularMergeFlag = false;
pu.mergeIdx = uiMergeCand;
pu.cu->affine = true;
pu.cu->affineType = affMrgCtx.affineType[uiMergeCand];
#if AFFINE_MMVD
pu.afMmvdFlag = false;
#endif
pu.cu->BcwIdx = affMrgCtx.BcwIdx[uiMergeCand];
#if INTER_LIC
pu.cu->LICFlag = affMrgCtx.LICFlags[uiMergeCand];
#endif
pu.mergeType = affMrgCtx.mergeType[uiMergeCand];
if (pu.mergeType == MRG_TYPE_SUBPU_ATMVP) // SbTMVP
{
pu.refIdx[0] = affMrgCtx.mvFieldNeighbours[(uiMergeCand << 1) + 0][0].refIdx;
pu.refIdx[1] = affMrgCtx.mvFieldNeighbours[(uiMergeCand << 1) + 1][0].refIdx;
PU::spanMotionInfo(pu, *affMrgCtx.mrgCtx);
}
else // Affine
{
for (uint32_t refList = 0; refList < NUM_REF_PIC_LIST_01; refList++)
{
for (int i = 0; i < 3; i++)
{
pu.mvAffi[refList][i] = affMrgCtx.mvFieldNeighbours[(uiMergeCand << 1) + refList][i].mv;
}
pu.refIdx[refList] = affMrgCtx.mvFieldNeighbours[(uiMergeCand << 1) + refList][0].refIdx;
}
PelUnitBuf pcBufPredRefTop = (PelUnitBuf(pu.chromaFormat, PelBuf(m_acYuvRefAMLTemplate[0][0], nWidth, AML_MERGE_TEMPLATE_SIZE)));
PelUnitBuf pcBufPredCurTop = (PelUnitBuf(pu.chromaFormat, PelBuf(m_acYuvCurAMLTemplate[0][0], nWidth, AML_MERGE_TEMPLATE_SIZE)));
PelUnitBuf pcBufPredRefLeft = (PelUnitBuf(pu.chromaFormat, PelBuf(m_acYuvRefAMLTemplate[1][0], AML_MERGE_TEMPLATE_SIZE, nHeight)));
PelUnitBuf pcBufPredCurLeft = (PelUnitBuf(pu.chromaFormat, PelBuf(m_acYuvCurAMLTemplate[1][0], AML_MERGE_TEMPLATE_SIZE, nHeight)));
#if RPR_ENABLE
bool bRefIsRescaled = false;
for (uint32_t refList = 0; refList < NUM_REF_PIC_LIST_01; refList++)
{
const RefPicList eRefPicList = refList ? REF_PIC_LIST_1 : REF_PIC_LIST_0;
bRefIsRescaled |= (pu.refIdx[refList] >= 0) ? pu.cu->slice->getRefPic(eRefPicList, pu.refIdx[refList])->isRefScaled(pu.cs->pps) : false;
}
if ( !bRefIsRescaled )
{
#endif
// 获取参考模板
getAffAMLRefTemplate(pu, pcBufPredRefTop, pcBufPredRefLeft);
if (m_bAMLTemplateAvailabe[0])
{
m_pcRdCost->setDistParam(cDistParam, pcBufPredCurTop.Y(), pcBufPredRefTop.Y(), pu.cs->sps->getBitDepth(CHANNEL_TYPE_LUMA), COMPONENT_Y, false);
uiCost += cDistParam.distFunc(cDistParam);
}
if (m_bAMLTemplateAvailabe[1])
{
m_pcRdCost->setDistParam(cDistParam, pcBufPredCurLeft.Y(), pcBufPredRefLeft.Y(), pu.cs->sps->getBitDepth(CHANNEL_TYPE_LUMA), COMPONENT_Y, false);
uiCost += cDistParam.distFunc(cDistParam);
}
#if RPR_ENABLE
}
#endif
}
updateCandList(uiMergeCand, uiCost, ADAPTIVE_AFFINE_SUB_GROUP_SIZE, RdCandList[uiMergeCand / ADAPTIVE_AFFINE_SUB_GROUP_SIZE], candCostList[uiMergeCand / ADAPTIVE_AFFINE_SUB_GROUP_SIZE]);
}
pu.mergeIdx = mrgCandIdx; //restore the merge index
updateAffineCandInfo(pu, affMrgCtx, RdCandList
, mrgCandIdx
);
}
xAMLGetCurBlkTemplate函数用于判断当前块的相邻模板是否可用,如果可用则获取相应的模板样本。
bool InterPrediction::xAMLGetCurBlkTemplate(PredictionUnit& pu, int nCurBlkWidth, int nCurBlkHeight)
{
// 判断当前块左侧模板和上侧模板是否可用
m_bAMLTemplateAvailabe[0] = xAMLIsTopTempAvailable(pu);
m_bAMLTemplateAvailabe[1] = xAMLIsLeftTempAvailable(pu);
if (!m_bAMLTemplateAvailabe[0] && !m_bAMLTemplateAvailabe[1])
{
return false;
}
// 获取当前块左侧模板和上侧模板区域重建像素
/* const int lumaShift = 2 + MV_FRACTIONAL_BITS_DIFF;
const int horShift = (lumaShift + ::getComponentScaleX(COMPONENT_Y, pu.chromaFormat));
const int verShift = (lumaShift + ::getComponentScaleY(COMPONENT_Y, pu.chromaFormat));*/
const Picture& currPic = *pu.cs->picture;
const CPelBuf recBuf = currPic.getRecoBuf(pu.cs->picture->blocks[COMPONENT_Y]);
std::vector<Pel>& invLUT = m_pcReshape->getInvLUT();
if (m_bAMLTemplateAvailabe[0])
{
// 根据位置定位到相邻区域
const Pel* rec = recBuf.bufAt(pu.blocks[COMPONENT_Y].pos().offset(0, -AML_MERGE_TEMPLATE_SIZE));
// 将重建像素存储在m_acYuvCurAMLTemplate中
PelBuf pcYBuf = PelBuf(m_acYuvCurAMLTemplate[0][0], nCurBlkWidth, AML_MERGE_TEMPLATE_SIZE);
Pel* pcY = pcYBuf.bufAt(0, 0);
for (int k = 0; k < nCurBlkWidth; k++)
{
for (int l = 0; l < AML_MERGE_TEMPLATE_SIZE; l++)
{
int recVal = rec[k + l * recBuf.stride];
if (m_pcReshape->getSliceReshaperInfo().getUseSliceReshaper() && m_pcReshape->getCTUFlag())
{
recVal = invLUT[recVal];
}
pcY[k + l * nCurBlkWidth] = recVal;
}
}
}
if (m_bAMLTemplateAvailabe[1])
{
PelBuf pcYBuf = PelBuf(m_acYuvCurAMLTemplate[1][0], AML_MERGE_TEMPLATE_SIZE, nCurBlkHeight);
Pel* pcY = pcYBuf.bufAt(0, 0);
const Pel* rec = recBuf.bufAt(pu.blocks[COMPONENT_Y].pos().offset(-AML_MERGE_TEMPLATE_SIZE, 0));
for (int k = 0; k < nCurBlkHeight; k++)
{
for (int l = 0; l < AML_MERGE_TEMPLATE_SIZE; l++)
{
int recVal = rec[recBuf.stride * k + l];
if (m_pcReshape->getSliceReshaperInfo().getUseSliceReshaper() && m_pcReshape->getCTUFlag())
{
recVal = invLUT[recVal];
}
pcY[AML_MERGE_TEMPLATE_SIZE * k + l] = recVal;
}
}
}
return true;
}
getBlkAMLRefTemplate函数用于常规Merge模式和TM Merge模式参考模板的生成,代码及注释如下:
void InterPrediction::getBlkAMLRefTemplate(PredictionUnit &pu, PelUnitBuf &pcBufPredRefTop, PelUnitBuf &pcBufPredRefLeft)
{
Mv mvCurr;
const int lumaShift = 2 + MV_FRACTIONAL_BITS_DIFF; // 1/16像素精度
const int horShift = (lumaShift + ::getComponentScaleX(COMPONENT_Y, pu.chromaFormat));
const int verShift = (lumaShift + ::getComponentScaleY(COMPONENT_Y, pu.chromaFormat));
if (xCheckIdenticalMotion(pu)) // 单向预测
{
mvCurr = pu.mv[0]; // 当前PU的MV
/*const int horIntMv = (mvCurr.getHor() + ((1 << horShift) >> 1)) >> horShift;
const int verIntMv = (mvCurr.getVer() + ((1 << verShift) >> 1)) >> verShift;
Mv subPelMv(horIntMv << horShift, verIntMv << verShift);*/
Mv subPelMv = mvCurr;
clipMv(mvCurr, pu.lumaPos(), pu.lumaSize(), *pu.cs->sps, *pu.cs->pps);
CHECK(pu.refIdx[0] < 0, "invalid ref idx");
if (m_bAMLTemplateAvailabe[0]) // 上侧模板可用
{
Mv mvTop(0, -(AML_MERGE_TEMPLATE_SIZE << verShift));
mvTop += subPelMv; // 将当前PU的MV加上模板的偏移
clipMv(mvTop, pu.lumaPos(), pu.lumaSize(), *pu.cs->sps, *pu.cs->pps);
#if RPR_ENABLE
const Picture* picRef = pu.cu->slice->getRefPic(REF_PIC_LIST_0, pu.refIdx[0])->unscaledPic; // 参考帧
const std::pair<int, int>& scalingRatio = pu.cu->slice->getScalingRatio(REF_PIC_LIST_0, pu.refIdx[0]);
#if INTER_LIC
xPredInterBlk( COMPONENT_Y, pu, picRef, mvTop, pcBufPredRefTop,
false, pu.cu->slice->clpRng( COMPONENT_Y ), false, false, scalingRatio, 0, 0, false, NULL, 0, true, true, mvCurr );
#else
xPredInterBlk( COMPONENT_Y, pu, picRef, mvTop, pcBufPredRefTop,
false, pu.cu->slice->clpRng( COMPONENT_Y ), false, false, scalingRatio, 0, 0, false, NULL, 0, true );
#endif
#else
#if INTER_LIC
xPredInterBlk( COMPONENT_Y, pu, pu.cu->slice->getRefPic( REF_PIC_LIST_0, pu.refIdx[0] ), mvTop, pcBufPredRefTop,
false, pu.cu->slice->clpRng( COMPONENT_Y ), false, false, SCALE_1X, 0, 0, false, NULL, 0, true, true,
mvCurr );
#else
xPredInterBlk( COMPONENT_Y, pu, pu.cu->slice->getRefPic( REF_PIC_LIST_0, pu.refIdx[0] ), mvTop, pcBufPredRefTop,
false, pu.cu->slice->clpRng( COMPONENT_Y ), false, false, SCALE_1X, 0, 0, false, NULL, 0, true );
#endif
#endif
}
if (m_bAMLTemplateAvailabe[1]) // 左侧模板可用
{
Mv mvLeft(-(AML_MERGE_TEMPLATE_SIZE << horShift), 0); // 模板与当前Pu的偏移 1/16像素精度
mvLeft += subPelMv; // 将当前Pu的mv加上模板的偏移
clipMv(mvLeft, pu.lumaPos(), pu.lumaSize(), *pu.cs->sps, *pu.cs->pps);
#if RPR_ENABLE
const Picture* picRef = pu.cu->slice->getRefPic(REF_PIC_LIST_0, pu.refIdx[0])->unscaledPic;
const std::pair<int, int>& scalingRatio = pu.cu->slice->getScalingRatio(REF_PIC_LIST_0, pu.refIdx[0]);
#if INTER_LIC
xPredInterBlk( COMPONENT_Y, pu, picRef, mvLeft, pcBufPredRefLeft,
false, pu.cu->slice->clpRng( COMPONENT_Y ), false, false, scalingRatio, 0, 0, false, NULL, 0, true, true, mvCurr );
#else
xPredInterBlk( COMPONENT_Y, pu, picRef, mvLeft, pcBufPredRefLeft,
false, pu.cu->slice->clpRng( COMPONENT_Y ), false, false, scalingRatio, 0, 0, false, NULL, 0, true );
#endif
#else
#if INTER_LIC
xPredInterBlk( COMPONENT_Y, pu, pu.cu->slice->getRefPic( REF_PIC_LIST_0, pu.refIdx[0] ), mvLeft, pcBufPredRefLeft,
false, pu.cu->slice->clpRng( COMPONENT_Y ), false, false, SCALE_1X, 0, 0, false, NULL, 0, true, true,
mvCurr );
#else
xPredInterBlk( COMPONENT_Y, pu, pu.cu->slice->getRefPic( REF_PIC_LIST_0, pu.refIdx[0] ), mvLeft, pcBufPredRefLeft,
false, pu.cu->slice->clpRng( COMPONENT_Y ), false, false, SCALE_1X, 0, 0, false, NULL, 0, true );
#endif
#endif
}
}
else // 双向预测
{
// 先分别进行两个方向的单向预测
for (uint32_t refList = 0; refList < NUM_REF_PIC_LIST_01; refList++)
{
if (pu.refIdx[refList] < 0)
{
continue;
}
RefPicList eRefPicList = (refList ? REF_PIC_LIST_1 : REF_PIC_LIST_0);
CHECK(pu.refIdx[refList] >= pu.cu->slice->getNumRefIdx(eRefPicList), "Invalid reference index");
m_iRefListIdx = refList;
mvCurr = pu.mv[refList];
/*const int horIntMv = (mvCurr.getHor() + ((1 << horShift) >> 1)) >> horShift;
const int verIntMv = (mvCurr.getVer() + ((1 << verShift) >> 1)) >> verShift;
Mv subPelMv(horIntMv << horShift, verIntMv << verShift);*/
Mv subPelMv = mvCurr;
clipMv(mvCurr, pu.lumaPos(), pu.lumaSize(), *pu.cs->sps, *pu.cs->pps);
if (m_bAMLTemplateAvailabe[0])
{
Mv mvTop(0, -(AML_MERGE_TEMPLATE_SIZE << verShift));
mvTop += subPelMv;
clipMv(mvTop, pu.lumaPos(), pu.lumaSize(), *pu.cs->sps, *pu.cs->pps);
PelUnitBuf pcMbBuf =
PelUnitBuf(pu.chromaFormat, PelBuf(m_acYuvRefAboveTemplate[refList][0], pcBufPredRefTop.Y()));
if (pu.refIdx[0] >= 0 && pu.refIdx[1] >= 0)
{
#if RPR_ENABLE
const Picture* picRef = pu.cu->slice->getRefPic(eRefPicList, pu.refIdx[refList])->unscaledPic;
const std::pair<int, int>& scalingRatio = pu.cu->slice->getScalingRatio(eRefPicList, pu.refIdx[refList]);
#if INTER_LIC
xPredInterBlk( COMPONENT_Y, pu, picRef, mvTop, pcMbBuf, true,
pu.cu->slice->clpRng( COMPONENT_Y ), false, false, scalingRatio, 0, 0, false, NULL, 0, true, true, mvCurr );
#else
xPredInterBlk( COMPONENT_Y, pu, picRef, mvTop, pcMbBuf, true,
pu.cu->slice->clpRng( COMPONENT_Y ), false, false, scalingRatio, 0, 0, false, NULL, 0, true );
#endif
#else
#if INTER_LIC
xPredInterBlk( COMPONENT_Y, pu, pu.cu->slice->getRefPic( eRefPicList, pu.refIdx[refList] ), mvTop, pcMbBuf, true,
pu.cu->slice->clpRng( COMPONENT_Y ), false, false, SCALE_1X, 0, 0, false, NULL, 0, true, true,
mvCurr );
#else
xPredInterBlk( COMPONENT_Y, pu, pu.cu->slice->getRefPic( eRefPicList, pu.refIdx[refList] ), mvTop, pcMbBuf, true,
pu.cu->slice->clpRng( COMPONENT_Y ), false, false, SCALE_1X, 0, 0, false, NULL, 0, true );
#endif
#endif
}
else
{
#if RPR_ENABLE
const Picture* picRef = pu.cu->slice->getRefPic(eRefPicList, pu.refIdx[refList])->unscaledPic;
const std::pair<int, int>& scalingRatio = pu.cu->slice->getScalingRatio(eRefPicList, pu.refIdx[refList]);
#if INTER_LIC
xPredInterBlk( COMPONENT_Y, pu, picRef, mvTop, pcMbBuf,
false, pu.cu->slice->clpRng( COMPONENT_Y ), false, false, scalingRatio, 0, 0, false, NULL, 0, true, true, mvCurr );
#else
xPredInterBlk( COMPONENT_Y, pu, picRef, mvTop, pcMbBuf,
false, pu.cu->slice->clpRng( COMPONENT_Y ), false, false, scalingRatio, 0, 0, false, NULL, 0, true );
#endif
#else
#if INTER_LIC
xPredInterBlk( COMPONENT_Y, pu, pu.cu->slice->getRefPic( eRefPicList, pu.refIdx[refList] ), mvTop, pcMbBuf,
false, pu.cu->slice->clpRng( COMPONENT_Y ), false, false, SCALE_1X, 0, 0, false, NULL, 0, true, true, mvCurr );
#else
xPredInterBlk( COMPONENT_Y, pu, pu.cu->slice->getRefPic( eRefPicList, pu.refIdx[refList] ), mvTop, pcMbBuf,
false, pu.cu->slice->clpRng( COMPONENT_Y ), false, false, SCALE_1X, 0, 0, false, NULL, 0, true );
#endif
#endif
}
}
if (m_bAMLTemplateAvailabe[1])
{
Mv mvLeft(-(AML_MERGE_TEMPLATE_SIZE << horShift), 0);
mvLeft += subPelMv;
clipMv(mvLeft, pu.lumaPos(), pu.lumaSize(), *pu.cs->sps, *pu.cs->pps);
PelUnitBuf pcMbBuf =
PelUnitBuf(pu.chromaFormat, PelBuf(m_acYuvRefLeftTemplate[refList][0], pcBufPredRefLeft.Y()));
if (pu.refIdx[0] >= 0 && pu.refIdx[1] >= 0)
{
#if RPR_ENABLE
const Picture* picRef = pu.cu->slice->getRefPic(eRefPicList, pu.refIdx[refList])->unscaledPic;
const std::pair<int, int>& scalingRatio = pu.cu->slice->getScalingRatio( eRefPicList, pu.refIdx[refList] );
#if INTER_LIC
xPredInterBlk( COMPONENT_Y, pu, picRef, mvLeft, pcMbBuf,
true, pu.cu->slice->clpRng( COMPONENT_Y ), false, false, scalingRatio, 0, 0, false, NULL, 0, true, true, mvCurr );
#else
xPredInterBlk( COMPONENT_Y, pu, picRef, mvLeft, pcMbBuf,
true, pu.cu->slice->clpRng( COMPONENT_Y ), false, false, scalingRatio, 0, 0, false, NULL, 0, true );
#endif
#else
#if INTER_LIC
xPredInterBlk(COMPONENT_Y, pu, pu.cu->slice->getRefPic(eRefPicList, pu.refIdx[refList]), mvLeft, pcMbBuf,
true, pu.cu->slice->clpRng(COMPONENT_Y), false, false, SCALE_1X, 0, 0, false, NULL, 0, true, true, mvCurr);
#else
xPredInterBlk(COMPONENT_Y, pu, pu.cu->slice->getRefPic(eRefPicList, pu.refIdx[refList]), mvLeft, pcMbBuf,
true, pu.cu->slice->clpRng(COMPONENT_Y), false, false, SCALE_1X, 0, 0, false, NULL, 0, true);
#endif
#endif
}
else
{
#if RPR_ENABLE
const Picture* picRef = pu.cu->slice->getRefPic(eRefPicList, pu.refIdx[refList])->unscaledPic;
const std::pair<int, int>& scalingRatio = pu.cu->slice->getScalingRatio(eRefPicList, pu.refIdx[refList]);
#if INTER_LIC
xPredInterBlk( COMPONENT_Y, pu, picRef, mvLeft, pcMbBuf,
false, pu.cu->slice->clpRng( COMPONENT_Y ), false, false, scalingRatio, 0, 0, false, NULL, 0, true, true, mvCurr );
#else
xPredInterBlk( COMPONENT_Y, pu, picRef, mvLeft, pcMbBuf,
false, pu.cu->slice->clpRng( COMPONENT_Y ), false, false, scalingRatio, 0, 0, false, NULL, 0, true );
#endif
#else
#if INTER_LIC
xPredInterBlk( COMPONENT_Y, pu, pu.cu->slice->getRefPic( eRefPicList, pu.refIdx[refList] ), mvLeft, pcMbBuf,
false, pu.cu->slice->clpRng( COMPONENT_Y ), false, false, SCALE_1X, 0, 0, false, NULL, 0, true, true, mvCurr );
#else
xPredInterBlk( COMPONENT_Y, pu, pu.cu->slice->getRefPic( eRefPicList, pu.refIdx[refList] ), mvLeft, pcMbBuf,
false, pu.cu->slice->clpRng( COMPONENT_Y ), false, false, SCALE_1X, 0, 0, false, NULL, 0, true );
#endif
#endif
}
}
}
// 双向加权预测
if (m_bAMLTemplateAvailabe[0])
{
CPelUnitBuf srcPred0 = CPelUnitBuf(pu.chromaFormat, PelBuf(m_acYuvRefAboveTemplate[0][0], pcBufPredRefTop.Y()));
CPelUnitBuf srcPred1 = CPelUnitBuf(pu.chromaFormat, PelBuf(m_acYuvRefAboveTemplate[1][0], pcBufPredRefTop.Y()));
xWeightedAverageY(pu, srcPred0, srcPred1, pcBufPredRefTop, pu.cu->slice->getSPS()->getBitDepths(),
pu.cu->slice->clpRngs());
}
if (m_bAMLTemplateAvailabe[1])
{
CPelUnitBuf srcPred0 = CPelUnitBuf(pu.chromaFormat, PelBuf(m_acYuvRefLeftTemplate[0][0], pcBufPredRefLeft.Y()));
CPelUnitBuf srcPred1 = CPelUnitBuf(pu.chromaFormat, PelBuf(m_acYuvRefLeftTemplate[1][0], pcBufPredRefLeft.Y()));
xWeightedAverageY(pu, srcPred0, srcPred1, pcBufPredRefLeft, pu.cu->slice->getSPS()->getBitDepths(),
pu.cu->slice->clpRngs());
}
}
}
getAffAMLRefTemplate函数用于Affine模式时获取参考模板的样本
void InterPrediction::getAffAMLRefTemplate(PredictionUnit &pu, PelUnitBuf &pcBufPredRefTop, PelUnitBuf &pcBufPredRefLeft)
{
#if INTER_LIC
int LICshift[2] = { 0 };
int scale[2] = { 0 };
int offset[2] = { 0 };
#endif
const int bitDepth = pu.cs->sps->getBitDepth(CHANNEL_TYPE_LUMA);
if (xCheckIdenticalMotion(pu)) // 单向预测
{
Pel * refLeftTemplate = m_acYuvRefAMLTemplate[1][0]; // 左参考模板
Pel * refAboveTemplate = m_acYuvRefAMLTemplate[0][0]; // 上参考模板
int numTemplate[2] = { 0, 0 }; // 0:Above, 1:Left 模板像素数
const RefPicList eRefPicList = REF_PIC_LIST_0;
// MC获取各个边界子块的参考模板
xPredAffineTpl(pu, eRefPicList, numTemplate, refLeftTemplate, refAboveTemplate);
#if INTER_LIC
if (pu.cu->LICFlag)
{
Pel *recLeftTemplate = m_acYuvCurAMLTemplate[1][0];
Pel *recAboveTemplate = m_acYuvCurAMLTemplate[0][0];
xGetLICParamGeneral(*pu.cu, COMPONENT_Y, numTemplate, refLeftTemplate, refAboveTemplate, recLeftTemplate,
recAboveTemplate, LICshift[0], scale[0], offset[0]);
if (m_bAMLTemplateAvailabe[0])
{
PelBuf & dstBuf = pcBufPredRefTop.bufs[0];
const ClpRng &clpRng = pu.cu->cs->slice->clpRng(COMPONENT_Y);
dstBuf.linearTransform(scale[0], LICshift[0], offset[0], true, clpRng);
}
if (m_bAMLTemplateAvailabe[1])
{
PelBuf & dstBuf = pcBufPredRefLeft.bufs[0];
const ClpRng &clpRng = pu.cu->cs->slice->clpRng(COMPONENT_Y);
dstBuf.linearTransform(scale[0], LICshift[0], offset[0], true, clpRng);
}
}
#endif
}
else // 双向
{
for (uint32_t refList = 0; refList < NUM_REF_PIC_LIST_01; refList++)
{
if (pu.refIdx[refList] < 0)
{
continue;
}
RefPicList eRefPicList = (refList ? REF_PIC_LIST_1 : REF_PIC_LIST_0);
CHECK(pu.refIdx[refList] >= pu.cu->slice->getNumRefIdx(eRefPicList), "Invalid reference index");
Pel *refLeftTemplate = m_acYuvRefLeftTemplate[refList][0];
Pel *refAboveTemplate = m_acYuvRefAboveTemplate[refList][0];
int numTemplate[2] = { 0, 0 }; // 0:Above, 1:Left
xPredAffineTpl(pu, eRefPicList, numTemplate, refLeftTemplate, refAboveTemplate);
#if INTER_LIC
if (pu.cu->LICFlag)
{
Pel *recLeftTemplate = m_acYuvCurAMLTemplate[1][0];
Pel *recAboveTemplate = m_acYuvCurAMLTemplate[0][0];
xGetLICParamGeneral(*pu.cu, COMPONENT_Y, numTemplate, refLeftTemplate, refAboveTemplate, recLeftTemplate,
recAboveTemplate, LICshift[refList], scale[refList], offset[refList]);
}
#endif
}
if (m_bAMLTemplateAvailabe[0])
{
PelUnitBuf srcPred[2];
srcPred[0] = PelUnitBuf(pu.chromaFormat, PelBuf(m_acYuvRefAboveTemplate[0][0], pcBufPredRefTop.Y()));
srcPred[1] = PelUnitBuf(pu.chromaFormat, PelBuf(m_acYuvRefAboveTemplate[1][0], pcBufPredRefTop.Y()));
#if INTER_LIC
if (pu.cu->LICFlag)
{
for (int i = 0; i < 2; i++)
{
if (pu.refIdx[i] >= 0)
{
PelBuf & dstBuf = srcPred[i].bufs[0];
const ClpRng &clpRng = pu.cu->cs->slice->clpRng(COMPONENT_Y);
dstBuf.linearTransform(scale[i], LICshift[i], offset[i], true, clpRng);
}
}
}
#endif
const int iRefIdx0 = pu.refIdx[0];
const int iRefIdx1 = pu.refIdx[1];
if (iRefIdx0 >= 0 && iRefIdx1 >= 0)
{
for (int i = 0; i < 2; i++)
{
PelBuf & dstBuf = srcPred[i].bufs[0];
const int biShift = IF_INTERNAL_PREC - bitDepth;
const Pel biOffset = -IF_INTERNAL_OFFS;
ClpRng clpRngDummy;
dstBuf.linearTransform(1, -biShift, biOffset, false, clpRngDummy);
}
}
xWeightedAverageY(pu, srcPred[0], srcPred[1], pcBufPredRefTop, pu.cu->slice->getSPS()->getBitDepths(),
pu.cu->slice->clpRngs());
}
if (m_bAMLTemplateAvailabe[1])
{
PelUnitBuf srcPred[2];
srcPred[0] = PelUnitBuf(pu.chromaFormat, PelBuf(m_acYuvRefLeftTemplate[0][0], pcBufPredRefLeft.Y()));
srcPred[1] = PelUnitBuf(pu.chromaFormat, PelBuf(m_acYuvRefLeftTemplate[1][0], pcBufPredRefLeft.Y()));
#if INTER_LIC
if (pu.cu->LICFlag)
{
for (int i = 0; i < 2; i++)
{
if (pu.refIdx[i] >= 0)
{
PelBuf & dstBuf = srcPred[i].bufs[0];
const ClpRng &clpRng = pu.cu->cs->slice->clpRng(COMPONENT_Y);
dstBuf.linearTransform(scale[i], LICshift[i], offset[i], true, clpRng);
}
}
}
#endif
const int iRefIdx0 = pu.refIdx[0];
const int iRefIdx1 = pu.refIdx[1];
if (iRefIdx0 >= 0 && iRefIdx1 >= 0)
{
for (int i = 0; i < 2; i++)
{
PelBuf & dstBuf = srcPred[i].bufs[0];
const int biShift = IF_INTERNAL_PREC - bitDepth;
const Pel biOffset = -IF_INTERNAL_OFFS;
ClpRng clpRngDummy;
dstBuf.linearTransform(1, -biShift, biOffset, false, clpRngDummy);
}
}
xWeightedAverageY(pu, srcPred[0], srcPred[1], pcBufPredRefLeft, pu.cu->slice->getSPS()->getBitDepths(),
pu.cu->slice->clpRngs());
}
}
}