今天来看xCheckRDCostMerge2Nx2N函数中提到的重要函数getInterMergeCandidates,其功能是创建merge候选列表,这里重点来看空域候选列表的建立。
首先来回忆一下merge的空域候选列表。merge候选列表长度为5,空域最多提供4个候选,按顺序依次遍历A1-B1-B0-A0-B2,选出4个候选填入候选列表。注意,空域最终可能提供的候选数量可能少于4个。
下面来看getInterMergeCandidates工作流程:
1.初始化准备工作。
2.建立空域候选列表,按顺序依次遍历A1-B1-B0-A0-B2位置PU,对每个位置进行以下操作,选出最多4个候选。
(1)检测是否有效
(2)若有效则写入候选列表记录其MV
(3)检测列表是否已满
3.建立时域候选列表。
4.为B Slice建立组合列表。
5.候选列表未满时,用0填充。
代码分析:
//! Construct a list of merging candidates 构造merge候选列表
Void TComDataCU::getInterMergeCandidates( UInt uiAbsPartIdx, UInt uiPUIdx, TComMvField* pcMvFieldNeighbours, UChar* puhInterDirNeighbours, Int& numValidMergeCand, Int mrgCandIdx )
{
/******************************************初始化准备工作**************************************/
UInt uiAbsPartAddr = m_absZIdxInCtu + uiAbsPartIdx; //当前CU的ZScan地址
Bool abCandIsInter[ MRG_MAX_NUM_CANDS ]; //MRG_MAX_NUM_CANDS最大候选数为5
for( UInt ui = 0; ui < getSlice()->getMaxNumMergeCand(); ++ui )
{
abCandIsInter[ui] = false;
pcMvFieldNeighbours[ ( ui << 1 ) ].setRefIdx(NOT_VALID);
pcMvFieldNeighbours[ ( ui << 1 ) + 1 ].setRefIdx(NOT_VALID);
}
numValidMergeCand = getSlice()->getMaxNumMergeCand(); //最大有效候选数为5
// compute the location of the current PU 计算当前PU的位置
Int xP, yP, nPSW, nPSH;
this->getPartPosition(uiPUIdx, xP, yP, nPSW, nPSH); //获取当前PU的索引、起始坐标、高和宽
Int iCount = 0;
UInt uiPartIdxLT, uiPartIdxRT, uiPartIdxLB;
PartSize cCurPS = getPartitionSize( uiAbsPartIdx ); //获取当前CU的分割模式
deriveLeftRightTopIdxGeneral( uiAbsPartIdx, uiPUIdx, uiPartIdxLT, uiPartIdxRT ); //左上右上块索引
deriveLeftBottomIdxGeneral( uiAbsPartIdx, uiPUIdx, uiPartIdxLB ); //左下块索引
/******************************************建立空域候选列表**************************************/
//left 左侧
UInt uiLeftPartIdx = 0;
TComDataCU* pcCULeft = 0;
pcCULeft = getPULeft( uiLeftPartIdx, uiPartIdxLB ); //获取左侧PU
//判断A1有效性
Bool isAvailableA1 = pcCULeft && //左侧PU是否有效
pcCULeft->isDiffMER(xP -1, yP+nPSH-1, xP, yP) && //左侧PU与当前PU是否在同一运动估计区域
!( uiPUIdx == 1 && (cCurPS == SIZE_Nx2N || cCurPS == SIZE_nLx2N || cCurPS == SIZE_nRx2N) ) && //分割模式判断
pcCULeft->isInter( uiLeftPartIdx ) ; //帧间预测是否有效
if ( isAvailableA1 ) //A1有效
{
abCandIsInter[iCount] = true;
// get Inter Dir
puhInterDirNeighbours[iCount] = pcCULeft->getInterDir( uiLeftPartIdx ); //获取帧间预测方向
// get Mv from Left
pcCULeft->getMvField( pcCULeft, uiLeftPartIdx, REF_PIC_LIST_0, pcMvFieldNeighbours[iCount<<1] ); //获取左侧PU list0的MV
if ( getSlice()->isInterB() ) //双向预测时,获取list1的MV
{
pcCULeft->getMvField( pcCULeft, uiLeftPartIdx, REF_PIC_LIST_1, pcMvFieldNeighbours[(iCount<<1)+1] );
}
if ( mrgCandIdx == iCount )
{
return;
}
iCount ++;
}
// early termination 达到最大候选数则退出
if (iCount == getSlice()->getMaxNumMergeCand())
{
return;
}
// above 上方
UInt uiAbovePartIdx</