(转载请注明出处)
候选列表的建立包括两部分,一个是Merge模式,一个是AMVP模式,因为这部分代码中涉及到了较多其他模块的参数,对新手读起来可能不容易理解,我尽力把我作为一个新手的理解过程表述出来,当然代码我看了好几遍才看懂,没办法,经验是个很重要的东西,没人带路,不走几遍哪来的经验。
先熟悉一下代码结构:
定位代码:
atrl+F查找encmain.cpp里的入口,从外到里的调用层次为:
①int main()->encode(),调了cTAppEncTop类里的encode()函数
②encode()->encode,调用了处理one frame 的函数m_cTEncTop.encode()
③encode->compressGOP,encode里获取源图片,计算image characteristics,最后调用编码GOP的m_cGOPEncoder.compressGOP()。
④compressGOP->precompressSlice->compressSlice与compressGOP->compressSlice,这里通过自带的注释先了解各大概。
⑤compressSlice->compressCU->xCompressCU,compressCU调用xCompressCU编码CU,xCompressCU还递归调用自身进行编码(这和CU的四叉树划分方式有关)。
⑥xCompressCU->xCheckRDCostInter,这里调用的xCheckRDCostInter主要就是完成inter预测的主要部分。
⑦xCheckRDCostInter->predInterSearch->xMergeEstimation->getInterMergeCandidates
直接定位到getInterMergeCandidate,这个是建立Merge使用的候选列表。
⑦xCheckRDCostInter -> predInterSearch -> xEstimateMvPredAMVP->fillMvpCand,这个建立是AMVP模式下的候选列表
另外,代码中,skip和merge的关系,可以这样理解,预测模式有三种:skip、Merge、AMVP,其中skip模式仅传输运动参数集索引,skip相当于merge模式在2Nx2N情况下的特例,单独在xCheckRDCostMerge2Nx2N中实现,其他全在xCheckRDCostInter中。
Merge候选列表的建立:
表格的而建立,先是获得当前PU地址,按左,上,右上,左下,左上的顺序依次将相邻PU的信息填入列表中。
处理左块,左块可用的条件:左块所在CU存在,与当前块一个ME,不是左右分割情况下的第二块,不是帧内预测模式。左块可用,将标志位设为true,并把左块dir(方向)和mv(距离)放到对应的矩阵。
如果当前Slice是B slice,还需要填充另一个mv到list1中。其他块的处理方式与左块无异,就是要注意一下:B1与A1mv相同,B1不用;B1与B0相同,B0不用。A0的mv不同于A1时,A0才可用。B2的mv不同于A1、B1时,B2才可用。
建立时域候选列表,先右下角再中部的顺序,再建立B帧用的建立组合列表,最后数目不够的时补零。
Void TComDataCU::getInterMergeCandidates( UInt uiAbsPartIdx, UInt uiPUIdx, TComMvField* pcMvFieldNeighbours, UChar* puhInterDirNeighbours, Int& numValidMergeCand, Int mrgCandIdx )
{//每次处理一个PU
UInt uiAbsPartAddr = m_uiAbsIdxInLCU + uiAbsPartIdx;//当前PU地址
Bool abCandIsInter[ MRG_MAX_NUM_CANDS ];//Merge最大候选数量为5
for( UInt ui = 0; ui < getSlice()->getMaxNumMergeCand(); ++ui )//MaxNumMergeCand = 5
{//初始化的一些工作
abCandIsInter[ui] = false;
pcMvFieldNeighbours[ ( ui << 1 ) ].setRefIdx(NOT_VALID);
pcMvFieldNeighbours[ ( ui << 1 ) + 1 ].setRefIdx(NOT_VALID);
}
numValidMergeCand = getSlice()->getMaxNumMergeCand();//可用候选数量
// compute the location of the current PU
Int xP, yP, nPSW, nPSH;
this->getPartPosition(uiPUIdx, xP, yP, nPSW, nPSH);//获得当前PU的位置和大小
Int iCount = 0;//!< 统计merge candidate的个数
UInt uiPartIdxLT, uiPartIdxRT, uiPartIdxLB;//!<分别标识左上、右上、左下
PartSize cCurPS = getPartitionSize( uiAbsPartIdx );//!<CU的分割模式
deriveLeftRightTopIdxGeneral( uiAbsPartIdx, uiPUIdx, uiPartIdxLT, uiPartIdxRT );
deriveLeftBottomIdxGeneral ( uiAbsPartIdx, uiPUIdx, uiPartIdxLB );
//lefti
UInt uiLeftPartIdx = 0;
TComDataCU* pcCULeft = 0;
pcCULeft = getPULeft( uiLeftPartIdx, uiPartIdxLB );//左
Bool isAvailableA1 = pcCULeft &&//A1是否可用
pcCULeft->isDiffMER(xP -1, yP+nPSH-1, xP, yP) &&//!<MER当前PU与其相邻PU不在同一个ME区域
!( uiPUIdx == 1 && (cCurPS == SIZE_Nx2N || cCurPS == SIZE_nLx2N || cCurPS == SIZE_nRx2N) ) &&//划分方式不为左右划分时的第二块
!pcCULeft->isIntra( uiLeftPartIdx ) ;//不是帧内预测
if ( isAvailableA1 )//!<A1可用
{
abCandIsInter[iCount] = true;//A1的标志位改为可用
// get Inter Dir帧间方向
puhInterDirNeighbours[iCount] = pcCULeft->getInterDir( uiLeftPartIdx );//!<inter dir分L0,L1,Bi
// get Mv from Left,将pcCULeft的MV存放到pcMvFieldNeighbours中
pcCULeft->getMvField( pcCULeft, uiLeftPartIdx, REF_PIC_LIST_0, pcMvFieldNeighbours[iCount<<1] );
if ( getSlice()->isInterB() )//B slice 存在两个mv,再存一个
{
pcCULeft->getMvField( pcCULeft, uiLeftPartIdx, REF_PIC_LIST_1, pcMvFieldNeighbours[(iCount<<1)+1] );
}
if ( mrgCandIdx == iCount )//候选数量如果等于mrgCandIdx就返回
{
return;
}
iCount ++;
}
// early termination
if (iCount == getSlice()->getMaxNumMergeCand())
{
return;
}
// above与上面处理A1的方式类似
UInt uiAbovePartIdx = 0;//同上一个,上方块的idx
TComDataCU* pcCUAbove = 0;//
pcCUAbove = getPUAbove( uiAbovePartIdx, uiPartIdxRT );//上方CU的地址
Bool isAvailableB1 = pcCUAbove &&//上方CU存在
pcCUAbove->isDiffMER(xP+nPSW-1, yP-1, xP, yP) &&//上放与当前在同一个ME块中
!( uiPUIdx == 1 && (cCurPS == SIZE_2NxN || cCurPS == SIZE_2NxnU || cCurPS == SIZE_2NxnD) ) &&//当前PU不是上下分割模式的第二个
!pcCUAbove->isIntra( uiAbovePartIdx );//不是帧内
if ( isAvailableB1 && (!isAvailableA1 || !pcCULeft->hasEqualMotion( uiLeftPartIdx, pcCUAbove, uiAbovePartIdx ) ) )//B1可用且A1存在时mv不同于A1
{
abCandIsInter[iCount] = true;
// get Inter Dir
puhInterDirNeighbours[iCount] = pcCUAbove->getInterDir( uiAbovePartIdx );
// get Mv from Left
pcCUAbove->getMvField( pcCUAbove, uiAbovePartIdx, REF_PIC_LIST_0, pcMvFieldNeighbours[iCount<<1] );
if ( getSlice()->isInterB() )
{
pcCUAbove->getMvField( pcCUAbove, uiAbovePartIdx, REF_PIC_LIST_1, pcMvFieldNeighbours[(iCount<<1)+1] );
}
if ( mrgCandIdx == iCount )
{
return;
}
iCount ++;
}
// early termination
if (iCount == getSlice()->getMaxNumMergeCand())
{
return;
}
// above right类似,一下不做说明
UInt uiAboveRightPartIdx = 0;
TComDataCU* pcCUAboveRight = 0;
pcCUAboveRight = getPUAboveRight( uiAboveRightPartIdx, uiPartIdxRT );
Bool isAvailableB0 = pcCUAboveRight &&
pcCUAboveRight->isDiffMER(xP+nPSW, yP-1, xP, yP) &&
!pcCUAboveRight->isIntra( uiAboveRightPartIdx );
if ( isAvailableB0 && ( !isAvailableB1 || !pcCUAbove->hasEqualMotion( uiAbovePartIdx, pcCUAboveRight, uiAboveRightPartIdx ) ) )//B1可用且B1不同于B0
{
abCandIsInter[iCount] = true;
// get Inter Dir
puhInterDirNeighbours[iCount] = pcCUAboveRight->getInterDir( uiAboveRightPartIdx );
// get Mv from Left
pcCUAboveRight->getMvField( pcCUAboveRight, uiAboveRightPartIdx, REF_PIC_LIST_0, pcMvFieldNeighbours[iCount<<1] );
if ( getSlice()->isInterB() )
{
pcCUAboveRight->getMvField( pcCUAboveRight, uiAboveRightPartIdx, REF_PIC_LIST_1, pcMvFieldNeighbours[(iCount<<1)+1] );
}
if ( mrgCandIdx == iCount )
{
return;
}
iCount ++;
}
// early termination
if (iCount == getSlice()->getMaxNumMergeCand())
{
return;
}
//left bottom左下
UInt uiLeftBottomPartIdx = 0;
TComDataCU* pcCULeftBottom = 0;
pcCULeftBottom = this->getPUBelowLeft( uiLeftBottomPartIdx, uiPartIdxLB );
Bool isAvailableA0 = pcCULeftBottom &&
pcCULeftBottom->isDiffMER(xP-1, yP+nPSH, xP, yP) &&
!pcCULeftBottom->isIntra( uiLeftBottomPartIdx ) ;
if ( isAvailableA0 && ( !isAvailableA1 || !pcCULeft->hasEqualMotion( uiLeftPartIdx, pcCULeftBottom, uiLeftBottomPartIdx ) ) )//!<A0可用且MV不同于A1
{
abCandIsInter[iCount] = true;
// get Inter Dir
puhInterDirNeighbours[iCount] = pcCULeftBottom->getInterDir( uiLeftBottomPartIdx );
// get Mv from Left
pcCULeftBottom->getMvField( pcCULeftBottom, uiLeftBottomPartIdx, REF_PIC_LIST_0, pcMvFieldNeighbours[iCount<<1] );
if ( getSlice()->isInterB() )
{
pcCULeftBottom->getMvField( pcCULeftBottom, uiLeftBottomPartIdx, REF_PIC_LIST_1, pcMvFieldNeighbours[(iCount<<1)+1] );
}
if ( mrgCandIdx == iCount )
{
return;
}
iCount ++;
}
// early termination
if (iCount == getSlice()->getMaxNumMergeCand())
{
return;
}
// above left
if( iCount < 4 )
{
UInt uiAboveLeftPartIdx = 0;
TComDataCU* pcCUAboveLeft = 0;
pcCUAboveLeft = getPUAboveLeft( uiAboveLeftPartIdx, uiAbsPartAddr );
Bool isAvailableB2 = pcCUAboveLeft &&
pcCUAboveLeft->isDiffMER(xP-1, yP-1, xP, yP) &&
!pcCUAboveLeft->isIntra( uiAboveLeftPartIdx );
if ( isAvailableB2 && ( !isAvailableA1 || !pcCULeft->hasEqualMotion( uiLeftPartIdx, pcCUAboveLeft, uiAboveLeftPartIdx ) )//B2与B1、A1的mv做比较
&& ( !isAvailableB1 || !pcCUAbove->hasEqualMotion( uiAbovePartIdx, pcCUAboveLeft, uiAboveLeftPartIdx ) ) )
{
abCandIsInter[iCount] = true;
// get Inter Dir
puhInterDirNeighbours[iCount] = pcCUAboveLeft->getInterDir( uiAboveLeftPartIdx );
// get Mv from Left
pcCUAboveLeft->getMvField( pcCUAboveLeft, uiAboveLeftPartIdx, REF_PIC_LIST_0, pcMvFieldNeighbours[iCount<<1] );
if ( getSlice()->isInterB() )
{
pcCUAboveLeft->getMvField( pcCUAboveLeft, uiAboveLeftPartIdx, REF_PIC_LIST_1, pcMvFieldNeighbours[(iCount<<1)+1] );
}
if ( mrgCandIdx == iCount )
{
return;
}
iCount ++;
}
}
// early termination
if (iCount == getSlice()->getMaxNumMergeCand()) //可用的merge candidates达到最大值,返回
{
return;
}
//2.时域候选列表
if ( getSlice()->getEnableTMVPFlag())//default is 1
{
//>> MTK colocated-RightBottom
UInt uiPartIdxRB;
Int uiLCUIdx = getAddr();
deriveRightBottomIdx( uiPUIdx, uiPartIdxRB ); //获取
UInt uiAbsPartIdxTmp = g_auiZscanToRaster[uiPartIdxRB];//转换扫描顺序
UInt uiNumPartInCUWidth = m_pcPic->getNumPartInWidth();//CU的宽度
TComMv cColMv;
Int iRefIdx;
if ( ( m_pcPic->getCU(m_uiCUAddr)->getCUPelX() + g_auiRasterToPelX[uiAbsPartIdxTmp] + m_pcPic->getMinCUWidth() ) >= m_pcSlice->getSPS()->getPicWidthInLumaSamples() ) // image boundary check
{
uiLCUIdx = -1;
}//横坐标超出图像边界
else if ( ( m_pcPic->getCU(m_uiCUAddr)->getCUPelY() + g_auiRasterToPelY[uiAbsPartIdxTmp] + m_pcPic->getMinCUHeight() ) >= m_pcSlice->getSPS()->getPicHeightInLumaSamples() )
{
uiLCUIdx = -1;
}//纵坐标超出图像边界
else
{
if ( ( uiAbsPartIdxTmp % uiNumPartInCUWidth < uiNumPartInCUWidth - 1 ) && // is not at the last column of LCU
( uiAbsPartIdxTmp / uiNumPartInCUWidth < m_pcPic->getNumPartInHeight() - 1 ) ) // is not at the last row of LCU
{
//不在LCU的最后一列且不在LCU的最后一行,SIZE_NxN的第一个PU
uiAbsPartAddr = g_auiRasterToZscan[ uiAbsPartIdxTmp + uiNumPartInCUWidth + 1 ];
uiLCUIdx = getAddr();//与当前pu属于相同cu
}
else if ( uiAbsPartIdxTmp % uiNumPartInCUWidth < uiNumPartInCUWidth - 1 ) // is not at the last column of LCU But is last row of LCU
{
//不在LCU的最后一列但在LCU的最后一行,SIZE_Nx2N的第1个PU,SIZE_NxN的第3个PU,SIZE_nLx2N的第1个PU,SIZE_nRx2N的第1个PU
uiAbsPartAddr = g_auiRasterToZscan[ (uiAbsPartIdxTmp + uiNumPartInCUWidth + 1) % m_pcPic->getNumPartInCU() ];
uiLCUIdx = -1 ;
}
else if ( uiAbsPartIdxTmp / uiNumPartInCUWidth < m_pcPic->getNumPartInHeight() - 1 ) // is not at the last row of LCU But is last column of LCU
{
//!<?不在LCU的最后一行但在LCU的最后一列,SIZE_2NxN的第1个PU,SIZE_NxN的第2个PU,SIZE_2NxnU的第1个PU,SIZE_2NxnD的第1个PU??
uiAbsPartAddr = g_auiRasterToZscan[ uiAbsPartIdxTmp + 1 ];
uiLCUIdx = getAddr() + 1;
}
else //is the right bottom corner of LCU
{
uiAbsPartAddr = 0;
uiLCUIdx = -1 ;
}
}
//3.中间部分的mv
iRefIdx = 0;
Bool bExistMV = false;
UInt uiPartIdxCenter;
UInt uiCurLCUIdx = getAddr();
Int dir = 0;
UInt uiArrayAddr = iCount;
xDeriveCenterIdx( uiPUIdx, uiPartIdxCenter );//!<根据uiPUIdx计算PU的中心地址uiPartIdxCenter
//获取colocated的经scaled过的mv。
bExistMV = uiLCUIdx >= 0 && xGetColMVP( REF_PIC_LIST_0, uiLCUIdx, uiAbsPartAddr, cColMv, iRefIdx );
if( bExistMV == false )//右下角MV不存在
{
bExistMV = xGetColMVP( REF_PIC_LIST_0, uiCurLCUIdx, uiPartIdxCenter, cColMv, iRefIdx );
}
if( bExistMV )
{//填充mv
dir |= 1;
pcMvFieldNeighbours[ 2 * uiArrayAddr ].setMvField( cColMv, iRefIdx );
}
//B slice有两个mv,还得再填一个
if ( getSlice()->isInterB() )
{
bExistMV = uiLCUIdx >= 0 && xGetColMVP( REF_PIC_LIST_1, uiLCUIdx, uiAbsPartAddr, cColMv, iRefIdx);
if( bExistMV == false )
{
bExistMV = xGetColMVP( REF_PIC_LIST_1, uiCurLCUIdx, uiPartIdxCenter, cColMv, iRefIdx );
}
if( bExistMV )
{
dir |= 2;
pcMvFieldNeighbours[ 2 * uiArrayAddr + 1 ].setMvField( cColMv, iRefIdx );
}
}
if (dir != 0)
{
puhInterDirNeighbours[uiArrayAddr] = dir;
abCandIsInter[uiArrayAddr] = true;
if ( mrgCandIdx == iCount )
{
return;
}
iCount++;
}
}
// early termination
if (iCount == getSlice()->getMaxNumMergeCand())
{
return;
}
UInt uiArrayAddr = iCount;
UInt uiCutoff = uiArrayAddr;
//B slice 要建立组合列表
if ( getSlice()->isInterB())
{//!<参考draft?Table?8-6?----?Specification?of?l0CandIdx?and?l1CandIdx
//建立组合列表
UInt uiPriorityList0[12] = {0 , 1, 0, 2, 1, 2, 0, 3, 1, 3, 2, 3};
UInt uiPriorityList1[12] = {1 , 0, 2, 0, 2, 1, 3, 0, 3, 1, 3, 2};
for (Int idx=0; idx<uiCutoff*(uiCutoff-1) && uiArrayAddr!= getSlice()->getMaxNumMergeCand(); idx++)
{
Int i = uiPriorityList0[idx]; Int j = uiPriorityList1[idx];
if (abCandIsInter[i] && abCandIsInter[j]&& (puhInterDirNeighbours[i]&0x1)&&(puhInterDirNeighbours[j]&0x2))
{
abCandIsInter[uiArrayAddr] = true;
puhInterDirNeighbours[uiArrayAddr] = 3;
// get Mv from cand[i] and cand[j]
pcMvFieldNeighbours[uiArrayAddr << 1].setMvField(pcMvFieldNeighbours[i<<1].getMv(), pcMvFieldNeighbours[i<<1].getRefIdx());
pcMvFieldNeighbours[( uiArrayAddr << 1 ) + 1].setMvField(pcMvFieldNeighbours[(j<<1)+1].getMv(), pcMvFieldNeighbours[(j<<1)+1].getRefIdx());
Int iRefPOCL0 = m_pcSlice->getRefPOC( REF_PIC_LIST_0, pcMvFieldNeighbours[(uiArrayAddr<<1)].getRefIdx() );
Int iRefPOCL1 = m_pcSlice->getRefPOC( REF_PIC_LIST_1, pcMvFieldNeighbours[(uiArrayAddr<<1)+1].getRefIdx() );
if (iRefPOCL0 == iRefPOCL1 && pcMvFieldNeighbours[(uiArrayAddr<<1)].getMv() == pcMvFieldNeighbours[(uiArrayAddr<<1)+1].getMv())
{
abCandIsInter[uiArrayAddr] = false;
}
else
{
uiArrayAddr++;
}
}
}
}
// early termination
if (uiArrayAddr == getSlice()->getMaxNumMergeCand())
{
return;
}
//当可用的merge?candidates数目仍小于预设值时,将余量均设置为零运动矢量
Int iNumRefIdx = (getSlice()->isInterB()) ?min(m_pcSlice->getNumRefIdx(REF_PIC_LIST_0), m_pcSlice->getNumRefIdx(REF_PIC_LIST_1)) : m_pcSlice->getNumRefIdx(REF_PIC_LIST_0);
Int r = 0;
Int refcnt = 0;
while (uiArrayAddr < getSlice()->getMaxNumMergeCand())
{
abCandIsInter[uiArrayAddr] = true;
puhInterDirNeighbours[uiArrayAddr] = 1;
pcMvFieldNeighbours[uiArrayAddr << 1].setMvField( TComMv(0, 0), r);
if ( getSlice()->isInterB() )
{
puhInterDirNeighbours[uiArrayAddr] = 3;
pcMvFieldNeighbours[(uiArrayAddr << 1) + 1].setMvField(TComMv(0, 0), r);//!<设置为零运动矢量
}
uiArrayAddr++;
if ( refcnt == iNumRefIdx - 1 )//!<达到参考帧列表的参考帧数
{
r = 0;
}
else
{
++r;
++refcnt;
}
}
numValidMergeCand = uiArrayAddr;
}
AMVP模式候选列表建立:
类似Merge。这里我感觉我有理解错误的地方。
Void TComDataCU::fillMvpCand ( UInt uiPartIdx, UInt uiPartAddr, RefPicList eRefPicList, Int iRefIdx, AMVPInfo* pInfo )
{
TComMv cMvPred;
Bool bAddedSmvp = false;
pInfo->iN = 0;
if (iRefIdx < 0)
{
return;
}
//AMVP模式下,候选列表长度为2,空域5个,时域2个,最后只留下2个
//-- Get Spatial MV
UInt uiPartIdxLT, uiPartIdxRT, uiPartIdxLB;
UInt uiNumPartInCUWidth = m_pcPic->getNumPartInWidth();
Bool bAdded = false;
deriveLeftRightTopIdx( uiPartIdx, uiPartIdxLT, uiPartIdxRT );
deriveLeftBottomIdx( uiPartIdx, uiPartIdxLB );
TComDataCU* tmpCU = NULL;
UInt idx;
tmpCU = getPUBelowLeft(idx, uiPartIdxLB);
bAddedSmvp = (tmpCU != NULL) && (tmpCU->getPredictionMode(idx) != MODE_INTRA);
if (!bAddedSmvp)
{
tmpCU = getPULeft(idx, uiPartIdxLB);
bAddedSmvp = (tmpCU != NULL) && (tmpCU->getPredictionMode(idx) != MODE_INTRA);
}
// Left predictor search
bAdded = xAddMVPCand( pInfo, eRefPicList, iRefIdx, uiPartIdxLB, MD_BELOW_LEFT);
if (!bAdded)//左下不行就换左
{
bAdded = xAddMVPCand( pInfo, eRefPicList, iRefIdx, uiPartIdxLB, MD_LEFT );
}
if(!bAdded)
{
bAdded = xAddMVPCandOrder( pInfo, eRefPicList, iRefIdx, uiPartIdxLB, MD_BELOW_LEFT);
if (!bAdded)
{
bAdded = xAddMVPCandOrder( pInfo, eRefPicList, iRefIdx, uiPartIdxLB, MD_LEFT );
}
}
// Above predictor search
bAdded = xAddMVPCand( pInfo, eRefPicList, iRefIdx, uiPartIdxRT, MD_ABOVE_RIGHT);
if (!bAdded)//同样,右上不行就换右
{
bAdded = xAddMVPCand( pInfo, eRefPicList, iRefIdx, uiPartIdxRT, MD_ABOVE);
}
if(!bAdded)
{
bAdded = xAddMVPCand( pInfo, eRefPicList, iRefIdx, uiPartIdxLT, MD_ABOVE_LEFT);
}
bAdded = bAddedSmvp;
if (pInfo->iN==2) bAdded = true;
if(!bAdded)
{
bAdded = xAddMVPCandOrder( pInfo, eRefPicList, iRefIdx, uiPartIdxRT, MD_ABOVE_RIGHT);
if (!bAdded)
{
bAdded = xAddMVPCandOrder( pInfo, eRefPicList, iRefIdx, uiPartIdxRT, MD_ABOVE);
}
if(!bAdded)//都不行换左上
{
bAdded = xAddMVPCandOrder( pInfo, eRefPicList, iRefIdx, uiPartIdxLT, MD_ABOVE_LEFT);
}
}
if ( pInfo->iN == 2 )
{
if ( pInfo->m_acMvCand[ 0 ] == pInfo->m_acMvCand[ 1 ] )
{
pInfo->iN = 1;
}
}
//时域候选列表的建立
if ( getSlice()->getEnableTMVPFlag() )
{
// Get Temporal Motion Predictor
Int iRefIdx_Col = iRefIdx;
TComMv cColMv;
UInt uiPartIdxRB;
UInt uiAbsPartIdx;
UInt uiAbsPartAddr;
Int uiLCUIdx = getAddr();
deriveRightBottomIdx( uiPartIdx, uiPartIdxRB );
uiAbsPartAddr = m_uiAbsIdxInLCU + uiPartAddr;
//---- co-located RightBottom Temporal Predictor (H) ---//
uiAbsPartIdx = g_auiZscanToRaster[uiPartIdxRB];
if ( ( m_pcPic->getCU(m_uiCUAddr)->getCUPelX() + g_auiRasterToPelX[uiAbsPartIdx] + m_pcPic->getMinCUWidth() ) >= m_pcSlice->getSPS()->getPicWidthInLumaSamples() ) // image boundary check
{
uiLCUIdx = -1;
}
else if ( ( m_pcPic->getCU(m_uiCUAddr)->getCUPelY() + g_auiRasterToPelY[uiAbsPartIdx] + m_pcPic->getMinCUHeight() ) >= m_pcSlice->getSPS()->getPicHeightInLumaSamples() )
{
uiLCUIdx = -1;
}
else
{
if ( ( uiAbsPartIdx % uiNumPartInCUWidth < uiNumPartInCUWidth - 1 ) && // is not at the last column of LCU
( uiAbsPartIdx / uiNumPartInCUWidth < m_pcPic->getNumPartInHeight() - 1 ) ) // is not at the last row of LCU
{
uiAbsPartAddr = g_auiRasterToZscan[ uiAbsPartIdx + uiNumPartInCUWidth + 1 ];
uiLCUIdx = getAddr();
}
else if ( uiAbsPartIdx % uiNumPartInCUWidth < uiNumPartInCUWidth - 1 ) // is not at the last column of LCU But is last row of LCU
{
uiAbsPartAddr = g_auiRasterToZscan[ (uiAbsPartIdx + uiNumPartInCUWidth + 1) % m_pcPic->getNumPartInCU() ];
uiLCUIdx = -1 ;
}
else if ( uiAbsPartIdx / uiNumPartInCUWidth < m_pcPic->getNumPartInHeight() - 1 ) // is not at the last row of LCU But is last column of LCU
{
uiAbsPartAddr = g_auiRasterToZscan[ uiAbsPartIdx + 1 ];
uiLCUIdx = getAddr() + 1;
}
else //is the right bottom corner of LCU
{
uiAbsPartAddr = 0;
uiLCUIdx = -1 ;
}
}
if ( uiLCUIdx >= 0 && xGetColMVP( eRefPicList, uiLCUIdx, uiAbsPartAddr, cColMv, iRefIdx_Col ) )
{
pInfo->m_acMvCand[pInfo->iN++] = cColMv;
}
else
{
UInt uiPartIdxCenter;
UInt uiCurLCUIdx = getAddr();
xDeriveCenterIdx( uiPartIdx, uiPartIdxCenter );
if (xGetColMVP( eRefPicList, uiCurLCUIdx, uiPartIdxCenter, cColMv, iRefIdx_Col ))
{
pInfo->m_acMvCand[pInfo->iN++] = cColMv;
}
}
//---- co-located RightBottom Temporal Predictor ---//
}
if (pInfo->iN > AMVP_MAX_NUM_CANDS)
{
pInfo->iN = AMVP_MAX_NUM_CANDS;
}
while (pInfo->iN < AMVP_MAX_NUM_CANDS)
{
pInfo->m_acMvCand[pInfo->iN].set(0,0);
pInfo->iN++;
}
return ;
}