VVC在HEVC的基礎上增加了很多新的幀間預測工具,在VTM5裏新增的幀間預測工具如下:
-
Extended merge prediction
-
Merge mode with MVD (MMVD)
-
AMVP mode with symmetric MVD signalling
-
Affine motion compensated prediction
-
Subblock-based temporal motion vector prediction (SbTMVP)
-
Adaptive motion vector resolution (AMVR)
-
Motion field storage: 1/16th luma sample MV storage and 8x8 motion field compression
-
Bi-prediction with CU-level weight (BCW)
-
Bi-directional optical flow (BDOF)
-
Decoder side motion vector refinement (DMVR)
-
Triangle partition prediction
-
Combined inter and intra prediction (CIIP)
在接下來的系列文章中將分別介紹這些工具,本文將介紹第一個幀間預測工具擴展的merge模式(Extended merge prediction)
1、擴展的merge模式(Extended merge prediction)
merge是在HEVC中新提出的一種MV預測技術,利用時域或空域相鄰塊的MV對當前塊MV進行預測。HEVC中merge模式會爲當前PU建立一個MV候選列表,列表中有5個候選MV,通過遍歷這5個MV,計算率失真代價最小的MV作爲當前PU的MV(不存在MVD)。在碼流中只需傳輸最優MV在列表中的索引即可。
HEVC中merge利用時域或空域相鄰塊構建MV列表,且列表中只有5個候選MV。VVC對此進行了擴展,候選列表merge list中最多可以有6個候選MV,候選MV有5種類型,順序如下。
-
Spatial MVP from spatial neighbour CUs 相鄰塊的空域MVP
-
Temporal MVP from collocated CUs 同位塊的時域MVP
-
History-based MVP from an FIFO table 基於歷史信息構建的FIFO表的MVP
-
Pairwise average MVP 成對的平均MVP
-
Zero MVs. 0向量
1.1、空域候選列表構建
空域候選列表建立方式和HEVC一樣。如下圖A0,A1,B0,B1,B2是當前CU空域鄰近塊。VVC中空域最多提供4個候選MV。即最多使用這5個候選塊中的4個候選塊的運動信息,候選列表按照A1->B1->B0->A0->B2的順序建立,其中B2是替補,只有前4個有一個或多個不存在時(例如不再同一個slice或tile或使用幀內編碼)纔將B2加入候選列表。當候選列表加入A1後,後面新加入候選項時要進行冗餘性檢查以免新加入的候選項的運動信息和已有項的相同。爲了減少計算複雜度,冗餘性檢查時不會和已有的每一項進行比較,只比下圖中較箭頭連接的項。
1.2、時域候選列表構建
時域候選列表建立方式和HEVC一樣。與空域情形不同,時域候選列表不能直接使用候選塊的運動信息,需要根據位置關係進行相應比例伸縮。如下圖所示,curr_CU是當前CU,col_CU是其同位CU,tb是當前圖像與參考圖像的距離(用POC度量),td是同位圖像與其參考圖像的距離。則候選MV計算如下:
curMV=(td/tb)*colMV
VVC中時域最多提供1個候選MV。如下圖C0位置的候選MV由其同位CU的MV伸縮得到,如果C0的同位CU不能用,則用C1的同位CU代替。
1.3、History-based merge candidates derivation
history-based MVP (HMVP)的merge候選項在空域候選和時域候選之後加入merge list。HMVP候選項來自於一個FIFO的表,這個表是通過已編碼塊的運動信息構建的。每到新的一行CTU時這個表就要重置(清空)。每遇到一個幀間編碼的CU(非子塊)時,它相關的運動信息會加到這個表的最後一項成爲一個新的HMVP候選項。
在VTM5中,HMVP表大小爲6。每當插入一個新的候選項時,首先進行冗餘性檢查即檢查待插入項的運動信息和表中已有項的運動信息是否相同,如果不相同則按FIFO規則插入,如果相同則將相同的HMVP從表中移除,其後所有項向前移動一位。
HMVP表構建好後就可以將其中的HMVP候選項插入merge list,對HMVP表中的候選項從後向前依次進行冗餘性檢查(即檢查該項和merge list中的空域、時域候選項運動信息是否相同),檢查通過即插入merge list。
爲了減少冗餘性檢查的操作進行了以下簡化操作:
-
用於構建merge list的HMVP候選項數量設爲(N<=4)?M:(8-N),其中N表示merge list中已有項的數目,M表示HMVP表中候選項數目。
-
一旦merge list中候選項數目達到最大允許候選項數減1(即6-1=5),則停止從HMVP生成merge候選項過程。
1.4、Pair-wise average merge candidates derivation
逐對平均候選項是指對merge list裏的已有候選項按照預定義的組隊關係計算平均值,預定義的組隊關係爲{(0, 1), (0, 2), (1, 2), (0, 3), (1, 3), (2, 3)},數字代表候選項在merge list裏的索引。L0和L1的平均向量分別單獨計算,如果兩個向量在某個列表裏都有效則即使它們指向不同的參考圖像也計算它們的平均,如果只有一個向量在某個列表裏有效則直接使用它,如果某個列表沒有有效運動向量則該列表無效。
如果計算完平均候選項後merge list還未填滿,則用0向量填充。
2、總結
以上便是merge list的構建過程,merge list長度爲6,首先尋找空域候選項(最多4個),然後時域候選項(最多1個),然後基於歷史信息的候選項,然後是平均候選項,如果merge list還未填滿則用0向量填充。在上面的過程中如果merge list填滿則不進行後面的步驟。
VVC的merge list構建與HEVC最大的不同就是HEVC中的merge list只含空域候選項和時域候選項。
當前CU的merge list構建完畢後,遍歷它的6個候選項進行率失真代價計算,選擇率失真代價最小的候選項直接作爲當前CU的MV。
merge list構建的代碼如下,對應位置處有註釋
void PU::getInterMergeCandidates( const PredictionUnit &pu, MergeCtx& mrgCtx,
int mmvdList,
const int& mrgCandIdx )
{
const CodingStructure &cs = *pu.cs;
const Slice &slice = *pu.cs->slice;
const uint32_t maxNumMergeCand = slice.getMaxNumMergeCand();
const bool canFastExit = pu.cs->pps->getLog2ParallelMergeLevelMinus2() == 0;
#if !JVET_L0090_PAIR_AVG
// this variable is unused if remove HEVC combined candidates
bool isCandInter[MRG_MAX_NUM_CANDS];
#endif
for (uint32_t ui = 0; ui < maxNumMergeCand; ++ui)
{
#if !JVET_L0090_PAIR_AVG
isCandInter[ui] = false;
#endif
mrgCtx.GBiIdx[ui] = GBI_DEFAULT;
mrgCtx.interDirNeighbours[ui] = 0;
mrgCtx.mrgTypeNeighbours [ui] = MRG_TYPE_DEFAULT_N;
mrgCtx.mvFieldNeighbours[(ui << 1) ].refIdx = NOT_VALID;
mrgCtx.mvFieldNeighbours[(ui << 1) + 1].refIdx = NOT_VALID;
}
mrgCtx.numValidMergeCand = maxNumMergeCand;
// compute the location of the current PU
int cnt = 0;
#if JVET_N0266_SMALL_BLOCKS
const Position posLT = pu.Y().topLeft();
const Position posRT = pu.Y().topRight();
const Position posLB = pu.Y().bottomLeft();
#else
const Position posLT = pu.shareParentPos;
const Position posRT = pu.shareParentPos.offset(pu.shareParentSize.width - 1, 0);
const Position posLB = pu.shareParentPos.offset(0, pu.shareParentSize.height - 1);
#endif
MotionInfo miAbove, miLeft, miAboveLeft, miAboveRight, miBelowLeft;
//left
const PredictionUnit* puLeft = cs.getPURestricted( posLB.offset( -1, 0 ), pu, pu.chType );
const bool isAvailableA1 = puLeft && isDiffMER( pu, *puLeft ) && pu.cu != puLeft->cu && CU::isInter( *puLeft->cu );
//!<A1塊,左側的塊
if( isAvailableA1 )
{
miLeft = puLeft->getMotionInfo( posLB.offset(-1, 0) );
#if !JVET_L0090_PAIR_AVG
isCandInter[cnt] = true;
#endif
// get Inter Dir
mrgCtx.interDirNeighbours[cnt] = miLeft.interDir;
mrgCtx.GBiIdx[cnt] = (mrgCtx.interDirNeighbours[cnt] == 3) ? puLeft->cu->GBiIdx : GBI_DEFAULT;
// get Mv from Left
mrgCtx.mvFieldNeighbours[cnt << 1].setMvField(miLeft.mv[0], miLeft.refIdx[0]);
if (slice.isInterB())
{
mrgCtx.mvFieldNeighbours[(cnt << 1) + 1].setMvField(miLeft.mv[1], miLeft.refIdx[1]);
}
if (mrgCandIdx == cnt && canFastExit)
{
return;
}
cnt++;
}
// early termination
if (cnt == maxNumMergeCand)
{
return;
}
// above
const PredictionUnit *puAbove = cs.getPURestricted( posRT.offset( 0, -1 ), pu, pu.chType );
bool isAvailableB1 = puAbove && isDiffMER( pu, *puAbove ) && pu.cu != puAbove->cu && CU::isInter( *puAbove->cu );
//!<B1塊,右側的塊
if( isAvailableB1 )
{
miAbove = puAbove->getMotionInfo( posRT.offset( 0, -1 ) );
//!<冗餘性檢查,B1只和A1比較
if( !isAvailableA1 || ( miAbove != miLeft ) )
{
#if !JVET_L0090_PAIR_AVG
isCandInter[cnt] = true;
#endif
// get Inter Dir
mrgCtx.interDirNeighbours[cnt] = miAbove.interDir;
// get Mv from Above
mrgCtx.GBiIdx[cnt] = (mrgCtx.interDirNeighbours[cnt] == 3) ? puAbove->cu->GBiIdx : GBI_DEFAULT;
mrgCtx.mvFieldNeighbours[cnt << 1].setMvField( miAbove.mv[0], miAbove.refIdx[0] );
if( slice.isInterB() )
{
mrgCtx.mvFieldNeighbours[( cnt << 1 ) + 1].setMvField( miAbove.mv[1], miAbove.refIdx[1] );
}
if (mrgCandIdx == cnt && canFastExit)
{
return;
}
cnt++;
}
}
// early termination
if( cnt == maxNumMergeCand )
{
return;
}
int spatialCandPos = cnt;
// above right
const PredictionUnit *puAboveRight = cs.getPURestricted( posRT.offset( 1, -1 ), pu, pu.chType );
bool isAvailableB0 = puAboveRight && isDiffMER( pu, *puAboveRight ) && CU::isInter( *puAboveRight->cu );
//!<B0塊,右上角的塊
if( isAvailableB0 )
{
miAboveRight = puAboveRight->getMotionInfo( posRT.offset( 1, -1 ) );
#if HM_JEM_MERGE_CANDS
if( ( !isAvailableB1 || ( miAbove != miAboveRight ) ) && ( !isAvailableA1 || ( miLeft != miAboveRight ) ) )
#else//!<冗餘性檢查,B0只和B1比較
if( !isAvailableB1 || ( miAbove != miAboveRight ) )
#endif
{
#if !JVET_L0090_PAIR_AVG
isCandInter[cnt] = true;
#endif
// get Inter Dir
mrgCtx.interDirNeighbours[cnt] = miAboveRight.interDir;
// get Mv from Above-right
mrgCtx.GBiIdx[cnt] = (mrgCtx.interDirNeighbours[cnt] == 3) ? puAboveRight->cu->GBiIdx : GBI_DEFAULT;
mrgCtx.mvFieldNeighbours[cnt << 1].setMvField( miAboveRight.mv[0], miAboveRight.refIdx[0] );
if( slice.isInterB() )
{
mrgCtx.mvFieldNeighbours[( cnt << 1 ) + 1].setMvField( miAboveRight.mv[1], miAboveRight.refIdx[1] );
}
if (mrgCandIdx == cnt && canFastExit)
{
return;
}
cnt++;
}
}
// early termination
if( cnt == maxNumMergeCand )
{
return;
}
//left bottom
const PredictionUnit *puLeftBottom = cs.getPURestricted( posLB.offset( -1, 1 ), pu, pu.chType );
bool isAvailableA0 = puLeftBottom && isDiffMER( pu, *puLeftBottom ) && CU::isInter( *puLeftBottom->cu );
//!<A0塊,左下角塊
if( isAvailableA0 )
{
miBelowLeft = puLeftBottom->getMotionInfo( posLB.offset( -1, 1 ) );
#if HM_JEM_MERGE_CANDS
if( ( !isAvailableA1 || ( miBelowLeft != miLeft ) ) && ( !isAvailableB1 || ( miBelowLeft != miAbove ) ) && ( !isAvailableB0 || ( miBelowLeft != miAboveRight ) ) )
#else//!<冗餘性檢查,A0只和A1比較
if( !isAvailableA1 || ( miBelowLeft != miLeft ) )
#endif
{
#if !JVET_L0090_PAIR_AVG
isCandInter[cnt] = true;
#endif
// get Inter Dir
mrgCtx.interDirNeighbours[cnt] = miBelowLeft.interDir;
mrgCtx.GBiIdx[cnt] = (mrgCtx.interDirNeighbours[cnt] == 3) ? puLeftBottom->cu->GBiIdx : GBI_DEFAULT;
// get Mv from Bottom-Left
mrgCtx.mvFieldNeighbours[cnt << 1].setMvField( miBelowLeft.mv[0], miBelowLeft.refIdx[0] );
if( slice.isInterB() )
{
mrgCtx.mvFieldNeighbours[( cnt << 1 ) + 1].setMvField( miBelowLeft.mv[1], miBelowLeft.refIdx[1] );
}
if (mrgCandIdx == cnt && canFastExit)
{
return;
}
cnt++;
}
}
// early termination
if( cnt == maxNumMergeCand )
{
return;
}
//!<B2左上角塊,只有空域候選項不夠4時才考慮
// above left
if ( cnt < 4 )
{
const PredictionUnit *puAboveLeft = cs.getPURestricted( posLT.offset( -1, -1 ), pu, pu.chType );
bool isAvailableB2 = puAboveLeft && isDiffMER( pu, *puAboveLeft ) && CU::isInter( *puAboveLeft->cu );
if( isAvailableB2 )
{
miAboveLeft = puAboveLeft->getMotionInfo( posLT.offset( -1, -1 ) );
#if HM_JEM_MERGE_CANDS
if( ( !isAvailableA1 || ( miLeft != miAboveLeft ) ) && ( !isAvailableB1 || ( miAbove != miAboveLeft ) ) && ( !isAvailableA0 || ( miBelowLeft != miAboveLeft ) ) && ( !isAvailableB0 || ( miAboveRight != miAboveLeft ) ) )
#else//!<冗餘性檢查,B2和A1、B1比較
if( ( !isAvailableA1 || ( miLeft != miAboveLeft ) ) && ( !isAvailableB1 || ( miAbove != miAboveLeft ) ) )
#endif
{
#if !JVET_L0090_PAIR_AVG
isCandInter[cnt] = true;
#endif
// get Inter Dir
mrgCtx.interDirNeighbours[cnt] = miAboveLeft.interDir;
mrgCtx.GBiIdx[cnt] = (mrgCtx.interDirNeighbours[cnt] == 3) ? puAboveLeft->cu->GBiIdx : GBI_DEFAULT;
// get Mv from Above-Left
mrgCtx.mvFieldNeighbours[cnt << 1].setMvField( miAboveLeft.mv[0], miAboveLeft.refIdx[0] );
if( slice.isInterB() )
{
mrgCtx.mvFieldNeighbours[( cnt << 1 ) + 1].setMvField( miAboveLeft.mv[1], miAboveLeft.refIdx[1] );
}
if (mrgCandIdx == cnt && canFastExit)
{
return;
}
cnt++;
}
}
}
// early termination
if (cnt == maxNumMergeCand)
{
return;
}
#if JVET_N0213_TMVP_REMOVAL
if (slice.getEnableTMVPFlag() && (pu.lumaSize().width + pu.lumaSize().height > 12))
#else
if (slice.getEnableTMVPFlag())
#endif
{
//>> MTK colocated-RightBottom
// offset the pos to be sure to "point" to the same position the uiAbsPartIdx would've pointed to
#if JVET_N0266_SMALL_BLOCKS
Position posRB = pu.Y().bottomRight().offset( -3, -3 );
#else
Position posRB = pu.shareParentPos.offset(pu.shareParentSize.width-3, pu.shareParentSize.height - 3);
#endif
const PreCalcValues& pcv = *cs.pcv;
Position posC0;
#if JVET_N0266_SMALL_BLOCKS
Position posC1 = pu.Y().center();
#else
Position posC1 = pu.shareParentPos.offset((pu.shareParentSize.width/2), (pu.shareParentSize.height/2));
#endif
bool C0Avail = false;
#if !JVET_N0266_SMALL_BLOCKS
bool C1Avail = (posC1.x < pcv.lumaWidth) && (posC1.y < pcv.lumaHeight);
#endif
if (((posRB.x + pcv.minCUWidth) < pcv.lumaWidth) && ((posRB.y + pcv.minCUHeight) < pcv.lumaHeight))
{
{
Position posInCtu( posRB.x & pcv.maxCUWidthMask, posRB.y & pcv.maxCUHeightMask );
if( ( posInCtu.x + 4 < pcv.maxCUWidth ) && // is not at the last column of CTU
( posInCtu.y + 4 < pcv.maxCUHeight ) ) // is not at the last row of CTU
{
posC0 = posRB.offset( 4, 4 );
C0Avail = true;
}
else if( posInCtu.x + 4 < pcv.maxCUWidth ) // is not at the last column of CTU But is last row of CTU
{
posC0 = posRB.offset( 4, 4 );
// in the reference the CTU address is not set - thus probably resulting in no using this C0 possibility
}
else if( posInCtu.y + 4 < pcv.maxCUHeight ) // is not at the last row of CTU But is last column of CTU
{
posC0 = posRB.offset( 4, 4 );
C0Avail = true;
}
else //is the right bottom corner of CTU
{
posC0 = posRB.offset( 4, 4 );
// same as for last column but not last row
}
}
}
//!<時域MV候選項
Mv cColMv;
int iRefIdx = 0;
int dir = 0;
unsigned uiArrayAddr = cnt;
bool bExistMV = ( C0Avail && getColocatedMVP(pu, REF_PIC_LIST_0, posC0, cColMv, iRefIdx ) ) //!<獲得伸縮後的同位MV
#if JVET_N0266_SMALL_BLOCKS
|| getColocatedMVP( pu, REF_PIC_LIST_0, posC1, cColMv, iRefIdx );
#else
|| ( C1Avail && getColocatedMVP(pu, REF_PIC_LIST_0, posC1, cColMv, iRefIdx ));
#endif
if (bExistMV)
{
dir |= 1;
mrgCtx.mvFieldNeighbours[2 * uiArrayAddr].setMvField(cColMv, iRefIdx);
}
if (slice.isInterB())
{
bExistMV = ( C0Avail && getColocatedMVP(pu, REF_PIC_LIST_1, posC0, cColMv, iRefIdx ) )
#if JVET_N0266_SMALL_BLOCKS
|| getColocatedMVP( pu, REF_PIC_LIST_1, posC1, cColMv, iRefIdx );
#else
|| (C1Avail && getColocatedMVP(pu, REF_PIC_LIST_1, posC1, cColMv, iRefIdx ) );
#endif
if (bExistMV)
{
dir |= 2;
mrgCtx.mvFieldNeighbours[2 * uiArrayAddr + 1].setMvField(cColMv, iRefIdx);
}
}
if( dir != 0 )
{
bool addTMvp = true;
#if HM_JEM_MERGE_CANDS
int iSpanCand = cnt;
for( int i = 0; i < iSpanCand; i++ )
{
if( mrgCtx.interDirNeighbours[ i ] == dir &&
mrgCtx.mvFieldNeighbours [ i << 1 ] == mrgCtx.mvFieldNeighbours[ uiArrayAddr << 1 ] &&
mrgCtx.mvFieldNeighbours [( i << 1 ) + 1] == mrgCtx.mvFieldNeighbours[( uiArrayAddr << 1 ) + 1] )
{
addTMvp = false;
}
}
#endif
if( addTMvp )
{
mrgCtx.interDirNeighbours[uiArrayAddr] = dir;
#if !JVET_L0090_PAIR_AVG
isCandInter [uiArrayAddr] = true;
#endif
mrgCtx.GBiIdx[uiArrayAddr] = GBI_DEFAULT;
if (mrgCandIdx == cnt && canFastExit)
{
return;
}
cnt++;
}
}
}
// early termination
if (cnt == maxNumMergeCand)
{
return;
}
//!<最大候選數量減1,HMVP
int maxNumMergeCandMin1 = maxNumMergeCand - 1;
if (cnt != maxNumMergeCandMin1)
{
bool isAvailableSubPu = false;
unsigned subPuMvpPos = 0;
#if JVET_L0090_PAIR_AVG
#if JVET_N0266_SMALL_BLOCKS
bool isShared = false;
#else
bool isShared = ((pu.Y().lumaSize().width != pu.shareParentSize.width) || (pu.Y().lumaSize().height != pu.shareParentSize.height));
#endif //!<添加HMVP
bool bFound = addMergeHMVPCand(cs, mrgCtx, canFastExit
, mrgCandIdx
, maxNumMergeCandMin1, cnt
, spatialCandPos
, isAvailableSubPu, subPuMvpPos
, CU::isIBC(*pu.cu)
, isShared
);
#else
bool bFound = addMergeHMVPCand(slice, mrgCtx, isCandInter, canFastExit
, (mmvdList != 0 && mrgCandIdx != -1) ? (const int)mrgCandIdxIBC : mrgCandIdx
, maxNumMergeCandMin1, cnt, cnt, isAvailableSubPu, subPuMvpPos
, mmvdList
);
#endif
if (bFound)
{
return;
}
}
#if JVET_L0090_PAIR_AVG
// pairwise-average candidates
{
//!<平均MV
if (cnt > 1 && cnt < maxNumMergeCand)
{
mrgCtx.mvFieldNeighbours[cnt * 2].setMvField( Mv( 0, 0 ), NOT_VALID );
mrgCtx.mvFieldNeighbours[cnt * 2 + 1].setMvField( Mv( 0, 0 ), NOT_VALID );
// calculate average MV for L0 and L1 seperately
unsigned char interDir = 0;
//!<兩個列表分別計算平均向量
for( int refListId = 0; refListId < (slice.isInterB() ? 2 : 1); refListId++ )
{
const short refIdxI = mrgCtx.mvFieldNeighbours[0 * 2 + refListId].refIdx;
const short refIdxJ = mrgCtx.mvFieldNeighbours[1 * 2 + refListId].refIdx;
//!<兩個向量都無效的情況
// both MVs are invalid, skip
if( (refIdxI == NOT_VALID) && (refIdxJ == NOT_VALID) )
{
continue;
}
//!<兩個向量都有效的情況
interDir += 1 << refListId;
// both MVs are valid, average these two MVs
if( (refIdxI != NOT_VALID) && (refIdxJ != NOT_VALID) )
{
const Mv& MvI = mrgCtx.mvFieldNeighbours[0 * 2 + refListId].mv;
const Mv& MvJ = mrgCtx.mvFieldNeighbours[1 * 2 + refListId].mv;
//!<求平均,通過移位實現
// average two MVs
Mv avgMv = MvI;
avgMv += MvJ;
roundAffineMv(avgMv.hor, avgMv.ver, 1);
mrgCtx.mvFieldNeighbours[cnt * 2 + refListId].setMvField( avgMv, refIdxI );
}//!<只有一個向量有效的情況
// only one MV is valid, take the only one MV
else if( refIdxI != NOT_VALID )
{
Mv singleMv = mrgCtx.mvFieldNeighbours[0 * 2 + refListId].mv;
mrgCtx.mvFieldNeighbours[cnt * 2 + refListId].setMvField( singleMv, refIdxI );
}
else if( refIdxJ != NOT_VALID )
{
Mv singleMv = mrgCtx.mvFieldNeighbours[1 * 2 + refListId].mv;
mrgCtx.mvFieldNeighbours[cnt * 2 + refListId].setMvField( singleMv, refIdxJ );
}
}
mrgCtx.interDirNeighbours[cnt] = interDir;
if( interDir > 0 )
{
cnt++;
}
}
// early termination
if( cnt == maxNumMergeCand )
{
return;
}
}
#endif
uint32_t uiArrayAddr = cnt;
#if !JVET_L0090_PAIR_AVG
uint32_t uiCutoff = std::min( uiArrayAddr, 3u );
if (slice.isInterB())
{
static const uint32_t NUM_PRIORITY_LIST = 12;
static const uint32_t uiPriorityList0[NUM_PRIORITY_LIST] = { 0 , 1, 0, 2, 1, 2, 0, 3, 1, 3, 2, 3 };
static const uint32_t uiPriorityList1[NUM_PRIORITY_LIST] = { 1 , 0, 2, 0, 2, 1, 3, 0, 3, 1, 3, 2 };
for (int idx = 0; idx < uiCutoff * (uiCutoff - 1) && uiArrayAddr != maxNumMergeCand; idx++)
{
CHECK( idx >= NUM_PRIORITY_LIST, "Invalid priority list number" );
int i = uiPriorityList0[idx];
int j = uiPriorityList1[idx];
if (isCandInter[i] && isCandInter[j] && (mrgCtx.interDirNeighbours[i] & 0x1) && (mrgCtx.interDirNeighbours[j] & 0x2))
{
isCandInter[uiArrayAddr] = true;
mrgCtx.interDirNeighbours[uiArrayAddr] = 3;
mrgCtx.GBiIdx[uiArrayAddr] = ((mrgCtx.interDirNeighbours[uiArrayAddr] == 3)) ? CU::deriveGbiIdx(mrgCtx.GBiIdx[i], mrgCtx.GBiIdx[j]) : GBI_DEFAULT;
// get Mv from cand[i] and cand[j]
mrgCtx.mvFieldNeighbours[ uiArrayAddr << 1 ].setMvField(mrgCtx.mvFieldNeighbours[ i << 1 ].mv, mrgCtx.mvFieldNeighbours[ i << 1 ].refIdx);
mrgCtx.mvFieldNeighbours[(uiArrayAddr << 1) + 1].setMvField(mrgCtx.mvFieldNeighbours[(j << 1) + 1].mv, mrgCtx.mvFieldNeighbours[(j << 1) + 1].refIdx);
int iRefPOCL0 = slice.getRefPOC(REF_PIC_LIST_0, mrgCtx.mvFieldNeighbours[(uiArrayAddr << 1) ].refIdx);
int iRefPOCL1 = slice.getRefPOC(REF_PIC_LIST_1, mrgCtx.mvFieldNeighbours[(uiArrayAddr << 1) + 1].refIdx);
if( iRefPOCL0 == iRefPOCL1 && mrgCtx.mvFieldNeighbours[( uiArrayAddr << 1 )].mv == mrgCtx.mvFieldNeighbours[( uiArrayAddr << 1 ) + 1].mv )
{
isCandInter[uiArrayAddr] = false;
}
else
{
uiArrayAddr++;
}
}
}
}
// early termination
if (uiArrayAddr == maxNumMergeCand)
{
return;
}
#endif
int iNumRefIdx = slice.isInterB() ? std::min(slice.getNumRefIdx(REF_PIC_LIST_0), slice.getNumRefIdx(REF_PIC_LIST_1)) : slice.getNumRefIdx(REF_PIC_LIST_0);
int r = 0;
int refcnt = 0;
while (uiArrayAddr < maxNumMergeCand)
{
#if !JVET_L0090_PAIR_AVG
isCandInter [uiArrayAddr ] = true;
#endif
mrgCtx.interDirNeighbours [uiArrayAddr ] = 1;
mrgCtx.GBiIdx [uiArrayAddr ] = GBI_DEFAULT;
mrgCtx.mvFieldNeighbours [uiArrayAddr << 1].setMvField(Mv(0, 0), r); //!<填充0向量
if (slice.isInterB())
{
mrgCtx.interDirNeighbours [ uiArrayAddr ] = 3;
mrgCtx.mvFieldNeighbours [(uiArrayAddr << 1) + 1].setMvField(Mv(0, 0), r);
}
if ( mrgCtx.interDirNeighbours[uiArrayAddr] == 1 && pu.cs->slice->getRefPic(REF_PIC_LIST_0, mrgCtx.mvFieldNeighbours[uiArrayAddr << 1].refIdx)->getPOC() == pu.cs->slice->getPOC())
{
mrgCtx.mrgTypeNeighbours[uiArrayAddr] = MRG_TYPE_IBC;
}
uiArrayAddr++;
if (refcnt == iNumRefIdx - 1)
{
r = 0;
}
else
{
++r;
++refcnt;
}
}
mrgCtx.numValidMergeCand = uiArrayAddr;
}
參考
JVET-N1002
JVET-L0266
JVET-L0090
感興趣的請關注微信公衆號Video Coding