在之前的博客详细讲了一下目前VVC中的TPM技术的详细原理,其中涉及到了三角预测模式的单向Merge列表的构建,链接为:H.266/VVC相关技术学习笔记:帧间预测中的TPM技术(Triangle partition Mode) 本篇博客将这部分函数getTriangleMergeCandidates()的代码附上,本人加了基本的注释,如果有错误或者有疑问的地方可以私信我。
//这里是三角预测模式的Merge列表构建的地方,从普通的Merge列表中派生出来
void PU::getTriangleMergeCandidates( const PredictionUnit &pu, MergeCtx& triangleMrgCtx )
{
MergeCtx tmpMergeCtx;
const Slice &slice = *pu.cs->slice;
const uint32_t maxNumMergeCand = slice.getMaxNumMergeCand();//最大的Merge候选数量
triangleMrgCtx.numValidMergeCand = 0;
//三角Merge列表的长度为6,首先对其中的候选都进行初始化
for (int32_t i = 0; i < TRIANGLE_MAX_NUM_UNI_CANDS; i++)
{
triangleMrgCtx.GBiIdx[i] = GBI_DEFAULT;//双向预测权重
triangleMrgCtx.interDirNeighbours[i] = 0;//相邻块候选的预测方向:单向或者双向,1表示前向,2表示后向,3表示双向
triangleMrgCtx.mrgTypeNeighbours[i] = MRG_TYPE_DEFAULT_N;//Merge类型
triangleMrgCtx.mvFieldNeighbours[(i << 1)].refIdx = NOT_VALID;//候选的前向参考索引
triangleMrgCtx.mvFieldNeighbours[(i << 1) + 1].refIdx = NOT_VALID;//候选的后向参考索引
triangleMrgCtx.mvFieldNeighbours[(i << 1)].mv = Mv();//候选的前向MV
triangleMrgCtx.mvFieldNeighbours[(i << 1) + 1].mv = Mv();//候选的后向MV
#if JVET_O0057_ALTHPELIF
triangleMrgCtx.useAltHpelIf[i] = false;
#endif
}
//首先构造普通的长度为6的Merge列表
PU::getInterMergeCandidates(pu, tmpMergeCtx, 0);
//对Merge列表中的每一个候选进行遍历,选出满足条件的候选添加进三角的单向预测列表中
for (int32_t i = 0; i < maxNumMergeCand; i++)
{
int parity = i & 1;//奇偶性,判断每个候选的奇偶性,1为奇数,0为偶数
if (tmpMergeCtx.interDirNeighbours[i] & (0x01 + parity))//这里优先选出普通Merge列表偶数候选的前向MV给当前三角单向Merge候选
//或者优先选出普通Merge列表奇数候选的后向MV给当前三角单向Merge候选
{
triangleMrgCtx.interDirNeighbours[triangleMrgCtx.numValidMergeCand] = 1 + parity;//赋予三角merge候选对应的预测方向
triangleMrgCtx.mrgTypeNeighbours[triangleMrgCtx.numValidMergeCand] = MRG_TYPE_DEFAULT_N;
triangleMrgCtx.mvFieldNeighbours[(triangleMrgCtx.numValidMergeCand << 1) + !parity].mv = Mv(0, 0);
triangleMrgCtx.mvFieldNeighbours[(triangleMrgCtx.numValidMergeCand << 1) + parity].mv = tmpMergeCtx.mvFieldNeighbours[(i << 1) + parity].mv;
triangleMrgCtx.mvFieldNeighbours[(triangleMrgCtx.numValidMergeCand << 1) + !parity].refIdx = -1;
triangleMrgCtx.mvFieldNeighbours[(triangleMrgCtx.numValidMergeCand << 1) + parity].refIdx = tmpMergeCtx.mvFieldNeighbours[(i << 1) + parity].refIdx;
triangleMrgCtx.numValidMergeCand++;
if (triangleMrgCtx.numValidMergeCand == TRIANGLE_MAX_NUM_UNI_CANDS)
{
return;
}
continue;
}
if (tmpMergeCtx.interDirNeighbours[i] & (0x02 - parity))//若普通Merge列表偶数候选只有后向MV,则将其后向MV给当前三角单向Merge候选
//若普通Merge列表奇数候选只有前向MV,则将其前向MV给当前三角单向Merge候选
{
triangleMrgCtx.interDirNeighbours[triangleMrgCtx.numValidMergeCand] = 2 - parity;
triangleMrgCtx.mrgTypeNeighbours[triangleMrgCtx.numValidMergeCand] = MRG_TYPE_DEFAULT_N;
triangleMrgCtx.mvFieldNeighbours[(triangleMrgCtx.numValidMergeCand << 1) + !parity].mv = tmpMergeCtx.mvFieldNeighbours[(i << 1) + !parity].mv;
triangleMrgCtx.mvFieldNeighbours[(triangleMrgCtx.numValidMergeCand << 1) + parity].mv = Mv(0, 0);
triangleMrgCtx.mvFieldNeighbours[(triangleMrgCtx.numValidMergeCand << 1) + !parity].refIdx = tmpMergeCtx.mvFieldNeighbours[(i << 1) + !parity].refIdx;
triangleMrgCtx.mvFieldNeighbours[(triangleMrgCtx.numValidMergeCand << 1) + parity].refIdx = -1;
triangleMrgCtx.numValidMergeCand++;
if (triangleMrgCtx.numValidMergeCand == TRIANGLE_MAX_NUM_UNI_CANDS)
{
return;
}
}
}
}