CUData::getInterMergeCandidates()
程序员文章站
2022-07-07 12:28:52
...
CUData::getInterMergeCandidates()构造当前PU的merge备选集
空间merge备选集
必要,5选4,B2替补
时间merge备选集
可选,2选1,C3替补
/* Construct list of merging candidates, returns count
构造merge备选集列表,返回备选集个数
备选集方案:
1.空域必须,时域可选,空域优先级>时域
2.空域5选4,即空域中aboveLeft作为空域备选,若left/leftBottow/above/aboveRight存在不可使用则尝试使用aboveLeft
3.时域2选1,优先选用rightBottow,若rightBottow不可用则尝试用center
4.若是Bslice,则需要进行列表组合
5.若备选集不足最大备选集数量(默认5),则剩余不足的备选集(0,0)填补
过程:
1.初始化所有备选集
2.得到当前PU的位置以及大小
3.计算空域备选集
1.计算left的备选集
2.计算above的备选集
3.计算aboveRight的备选集
4.计算leftBottom的备选集
5.若left/above/aboveRight/leftBottom存在不可用,则计算aboveLeft进行替补
4.若开启时域MVP,则计算时域备选集
1.计算co-rightBottom的备选集
2.若co-rightBottom不可用,则计算co-center进行替补
5.若是Bslice,则进行列表组合
6.若备选集不足maxNumMergeCand,则对不足的备选集进行0填补
7.返回备选集数量
*/
uint32_t CUData::getInterMergeCandidates(uint32_t absPartIdx, uint32_t puIdx, MVField(*candMvField)[2], uint8_t* candDir) const
{
uint32_t absPartAddr = m_absIdxInCTU + absPartIdx;
const bool isInterB = m_slice->isInterB();
//最大允许备选集数量
const uint32_t maxNumMergeCand = m_slice->m_maxNumMergeCand;
//初始化maxNumMergeCand个备选集的前后向MV和refIdx
for (uint32_t i = 0; i < maxNumMergeCand; ++i)
{
candMvField[i][0].mv = 0;
candMvField[i][1].mv = 0;
candMvField[i][0].refIdx = REF_NOT_VALID;
candMvField[i][1].refIdx = REF_NOT_VALID;
}
/* calculate the location of upper-left corner pixel and size of the current PU */
//当前PU左上角像素位置
int xP, yP;
//当前PU的长宽size
int nPSW, nPSH;
//当前CU的size
int cuSize = 1 << m_log2CUSize[0];
int partMode = m_partSize[0];
//计算当前PU的长宽
int tmp = partTable[partMode][puIdx][0];
nPSW = ((tmp >> 4) * cuSize) >> 2;
nPSH = ((tmp & 0xF) * cuSize) >> 2;
//计算当前PU左上角像素的位置
tmp = partTable[partMode][puIdx][1];
xP = ((tmp >> 4) * cuSize) >> 2;
yP = ((tmp & 0xF) * cuSize) >> 2;
//记录可用merge备选数量
uint32_t count = 0;
//得到当前PU左下PU的索引partIdxLB
uint32_t partIdxLT, partIdxRT, partIdxLB = deriveLeftBottomIdx(puIdx);
//当前PU的size
PartSize curPS = (PartSize)m_partSize[absPartIdx];
/*
left
-------------
| |
| |
----| |
|xxx| |
-----------------
*/
uint32_t leftPartIdx = 0;
//得到当前CU左边的CU:cuLeft
const CUData* cuLeft = getPULeft(leftPartIdx, partIdxLB);
/* 若存在cuLeft && 当前CU与cuLeft在不同merge区域
&& 当前PS不是竖着来的右边块(竖着来的右边块,备选集中无cuLeft) && cuLeft是inter块 */
bool isAvailableA1 = cuLeft &&
cuLeft->isDiffMER(xP - 1, yP + nPSH - 1, xP, yP) &&
!(puIdx == 1 && (curPS == SIZE_Nx2N || curPS == SIZE_nLx2N || curPS == SIZE_nRx2N)) &&
cuLeft->isInter(leftPartIdx);
//culeft可用,则拷贝cuLeft的mv信息作为merge备选
if (isAvailableA1)
{
// get Inter Dir 拷贝dir
candDir[count] = cuLeft->m_interDir[leftPartIdx];
// get Mv from Left 拷贝前向mv
cuLeft->getMvField(cuLeft, leftPartIdx, 0, candMvField[count][0]);
//若是Bslice,拷贝后向mv
if (isInterB)
cuLeft->getMvField(cuLeft, leftPartIdx, 1, candMvField[count][1]);
//达到maxNumMergeCand则return
if (++count == maxNumMergeCand)
return maxNumMergeCand;
}
//得到当前PU左上和右上的PU索引partIdxLT、partIdxRT
deriveLeftRightTopIdx(puIdx, partIdxLT, partIdxRT);
/*
above
-----
|xxx|
-------------
| |
| |
| |
| |
-------------
*/
uint32_t abovePartIdx = 0;
//得到当前CU上边的CU:cuAbove
const CUData* cuAbove = getPUAbove(abovePartIdx, partIdxRT);
/* 存在cuAbove && cuAbove与当前PU不在同一merge区域 &&
当前PU不是横着来的下面块(横着来的下面块,备选集无cuAbove) && cuAbove是inter块 */
bool isAvailableB1 = cuAbove &&
cuAbove->isDiffMER(xP + nPSW - 1, yP - 1, xP, yP) &&
!(puIdx == 1 && (curPS == SIZE_2NxN || curPS == SIZE_2NxnU || curPS == SIZE_2NxnD)) &&
cuAbove->isInter(abovePartIdx);
//cuAbove可用 && (cuLeft不可用 || cuLeft可用但其MV与cuLeft不同),为了防止备选集相同而造成不必要的浪费
if (isAvailableB1 && (!isAvailableA1 || !cuLeft->hasEqualMotion(leftPartIdx, *cuAbove, abovePartIdx)))
{
// get Inter Dir 拷贝dir
candDir[count] = cuAbove->m_interDir[abovePartIdx];
// get Mv from Left 拷贝前向MV
cuAbove->getMvField(cuAbove, abovePartIdx, 0, candMvField[count][0]);
if (isInterB) //若Bslice,则拷贝后向MV
cuAbove->getMvField(cuAbove, abovePartIdx, 1, candMvField[count][1]);
//若达到maxNumMergeCand则return
if (++count == maxNumMergeCand)
return maxNumMergeCand;
}
/*
above right
-----
|xxx|
-----------------
| |
| |
| |
| |
-------------
*/
uint32_t aboveRightPartIdx = 0;
//得到当前PU右上角的PU:cuAboveRight
const CUData* cuAboveRight = getPUAboveRight(aboveRightPartIdx, partIdxRT);
/* 存在cuAboveRight && cuAboveRight和当前PU不再同一merge区域 &&
cuAboveRight是inter块 */
bool isAvailableB0 = cuAboveRight &&
cuAboveRight->isDiffMER(xP + nPSW, yP - 1, xP, yP) &&
cuAboveRight->isInter(aboveRightPartIdx);
//cuAboveRight可用 && (cuAbove不可用 || cuAbove和cuAboveRight的MV不相等)
if (isAvailableB0 && (!isAvailableB1 || !cuAbove->hasEqualMotion(abovePartIdx, *cuAboveRight, aboveRightPartIdx)))
{
// get Inter Dir 拷贝dir
candDir[count] = cuAboveRight->m_interDir[aboveRightPartIdx];
// get Mv from Left 拷贝前向mv
cuAboveRight->getMvField(cuAboveRight, aboveRightPartIdx, 0, candMvField[count][0]);
if (isInterB) //若Bslice,拷贝后向mv
cuAboveRight->getMvField(cuAboveRight, aboveRightPartIdx, 1, candMvField[count][1]);
//备选数量达到maxNumMergeCand,返回
if (++count == maxNumMergeCand)
return maxNumMergeCand;
}
/*
left bottom
-------------
| |
| |
| |
| |
-----------------
|xxx|
-----
*/
uint32_t leftBottomPartIdx = 0;
//当前PU的左下PU:cuLeftBottom
const CUData* cuLeftBottom = this->getPUBelowLeft(leftBottomPartIdx, partIdxLB);
/* 存在cuLeftBottom && cuLeftBottom和当前PU不再同一merge区域 &&
cuLeftBottom是inter块 */
bool isAvailableA0 = cuLeftBottom &&
cuLeftBottom->isDiffMER(xP - 1, yP + nPSH, xP, yP) &&
cuLeftBottom->isInter(leftBottomPartIdx);
//cuLeftBottom可用 && (cuLeft不可用 || cuLeft和cuLeftBottom的MV不相等)
if (isAvailableA0 && (!isAvailableA1 || !cuLeft->hasEqualMotion(leftPartIdx, *cuLeftBottom, leftBottomPartIdx)))
{
// get Inter Dir 拷贝dir
candDir[count] = cuLeftBottom->m_interDir[leftBottomPartIdx];
// get Mv from Left 拷贝前向mv
cuLeftBottom->getMvField(cuLeftBottom, leftBottomPartIdx, 0, candMvField[count][0]);
if (isInterB) //若Bslice,拷贝后向mv
cuLeftBottom->getMvField(cuLeftBottom, leftBottomPartIdx, 1, candMvField[count][1]);
//备选数量达到maxNumMergeCand,返回
if (++count == maxNumMergeCand)
return maxNumMergeCand;
}
/*
above left
-----
|xxx|
-----------------
| |
| |
| |
| |
-------------
*/
if (count < 4) //若left/leftBottow/above/aboveRight存在不可用,则aboveLeft用来替补
{
uint32_t aboveLeftPartIdx = 0;
//当前PU的左上PU:cuAboveLeft
const CUData* cuAboveLeft = getPUAboveLeft(aboveLeftPartIdx, absPartAddr);
/* 存在cuAboveLeft && cuAboveLeft和当前PU不再同一merge区域 &&
cuLeftBottom是inter块 */
bool isAvailableB2 = cuAboveLeft &&
cuAboveLeft->isDiffMER(xP - 1, yP - 1, xP, yP) &&
cuAboveLeft->isInter(aboveLeftPartIdx);
/* cuAboveLeft可用 &&
(cuLeft不可用 || cuLeft和cuAboveLeft的MV不相等) &&
(cuAbove不可用 || cuAbove和cuAboveLeft的MV不相等) */
if (isAvailableB2 && (!isAvailableA1 || !cuLeft->hasEqualMotion(leftPartIdx, *cuAboveLeft, aboveLeftPartIdx))
&& (!isAvailableB1 || !cuAbove->hasEqualMotion(abovePartIdx, *cuAboveLeft, aboveLeftPartIdx)))
{
// get Inter Dir 拷贝dir
candDir[count] = cuAboveLeft->m_interDir[aboveLeftPartIdx];
// get Mv from Left 拷贝前向mv
cuAboveLeft->getMvField(cuAboveLeft, aboveLeftPartIdx, 0, candMvField[count][0]);
if (isInterB) //若Bslice,拷贝后向mv
cuAboveLeft->getMvField(cuAboveLeft, aboveLeftPartIdx, 1, candMvField[count][1]);
//备选数量达到maxNumMergeCand,返回
if (++count == maxNumMergeCand)
return maxNumMergeCand;
}
}
/*
到这里已经完成全部 left/leftBottow/above/aboveRight/aboveLeft 备选集生成
下面若允许时间MVP,则继续添加时间备选集
从这里可以看出空间MVP优先级高于时间MVP,且空间MVP必要,时间MVP不必要
*/
/*
进行空间的备选集生成
*/
if (m_slice->m_sps->bTemporalMVPEnabled) //若允许空间mv pred
{
//得到当前PU右下角PU的idx:co-cuRightBottom
uint32_t partIdxRB = deriveRightBottomIdx(puIdx);
MV colmv;
int ctuIdx = -1;
// image boundary check
if (m_encData->getPicCTU(m_cuAddr)->m_cuPelX + g_zscanToPelX[partIdxRB] + UNIT_SIZE < m_slice->m_sps->picWidthInLumaSamples &&
m_encData->getPicCTU(m_cuAddr)->m_cuPelY + g_zscanToPelY[partIdxRB] + UNIT_SIZE < m_slice->m_sps->picHeightInLumaSamples)
{
uint32_t absPartIdxRB = g_zscanToRaster[partIdxRB];
uint32_t numUnits = s_numPartInCUSize;
//co-cuRightBottom是否在CTU的最后一列
bool bNotLastCol = lessThanCol(absPartIdxRB, numUnits - 1); // is not at the last column of CTU
//co-cuRightBottom是否在CTU的最后一行
bool bNotLastRow = lessThanRow(absPartIdxRB, numUnits - 1); // is not at the last row of CTU
if (bNotLastCol && bNotLastRow) //即不在最后一列,又不在最后一行
{
absPartAddr = g_rasterToZscan[absPartIdxRB + RASTER_SIZE + 1];
ctuIdx = m_cuAddr;
}
else if (bNotLastCol) //不在CTU最后一列
absPartAddr = g_rasterToZscan[(absPartIdxRB + 1) & (numUnits - 1)];
else if (bNotLastRow) //不在CTU最后一行
{
absPartAddr = g_rasterToZscan[absPartIdxRB + RASTER_SIZE - numUnits + 1];
ctuIdx = m_cuAddr + 1;
}
else // is the right bottom corner of CTU 在CTU右下角
absPartAddr = 0;
}
//参考列表个数
int maxList = isInterB ? 2 : 1;
int dir = 0, refIdx = 0;
//遍历前向/后向参考列表
for (int list = 0; list < maxList; list++)
{
/* co-cuRightBottom
-------------
| |
| |
| |
| |
-----------------
|xxx|
-----
*/
//得到co-cuRightBottom的MV
bool bExistMV = ctuIdx >= 0 && getColMVP(colmv, refIdx, list, ctuIdx, absPartAddr);
//co-cuRightBottom的MV不可用,则尝试使用co-center替代
if (!bExistMV)
{
/* co-center
-------------
| | |
| | |
-------------
| |__| |
| | |
-------------
*/
//得到co-center的idx
uint32_t partIdxCenter = deriveCenterIdx(puIdx);
//得到co-center的MV
bExistMV = getColMVP(colmv, refIdx, list, m_cuAddr, partIdxCenter);
}
//若存在co-located MV,可能是co-cuRightBottow的,可能是co-center的
if (bExistMV)
{
//将dir/mv/refIdx添加进备选集
dir |= (1 << list);
candMvField[count][list].mv = colmv;
candMvField[count][list].refIdx = refIdx;
}
}
//若dir!=0,则说明有可用的空间MVP,将dir添加进备选集,count++
if (dir != 0)
{
candDir[count] = (uint8_t)dir;
//备选数量达到maxNumMergeCand,返回
if (++count == maxNumMergeCand)
return maxNumMergeCand;
}
}//end of if (m_slice->m_sps->bTemporalMVPEnabled),空间MVP备选集结束
/*
若是Bslice,则需要对前四个备选集进行两两组合
*/
if (isInterB)
{
const uint32_t cutoff = count * (count - 1);
uint32_t priorityList0 = 0xEDC984; // { 0, 1, 0, 2, 1, 2, 0, 3, 1, 3, 2, 3 }
uint32_t priorityList1 = 0xB73621; // { 1, 0, 2, 0, 2, 1, 3, 0, 3, 1, 3, 2 }
for (uint32_t idx = 0; idx < cutoff; idx++, priorityList0 >>= 2, priorityList1 >>= 2)
{
int i = priorityList0 & 3;
int j = priorityList1 & 3;
//备选集i有前向MV && 备选集j有后向MV
if ((candDir[i] & 0x1) && (candDir[j] & 0x2))
{
// get Mv from cand[i] and cand[j] 取前向后向refIdx即其所在的帧POC
int refIdxL0 = candMvField[i][0].refIdx;
int refIdxL1 = candMvField[j][1].refIdx;
int refPOCL0 = m_slice->m_refPOCList[0][refIdxL0];
int refPOCL1 = m_slice->m_refPOCList[1][refIdxL1];
//若候选MV对的MV不相同,且不在同一帧,则记录下当前组合备选集
if (!(refPOCL0 == refPOCL1 && candMvField[i][0].mv == candMvField[j][1].mv))
{
candMvField[count][0].mv = candMvField[i][0].mv;
candMvField[count][0].refIdx = refIdxL0;
candMvField[count][1].mv = candMvField[j][1].mv;
candMvField[count][1].refIdx = refIdxL1;
candDir[count] = 3;
//备选数量达到maxNumMergeCand,返回
if (++count == maxNumMergeCand)
return maxNumMergeCand;
}
}
}
} //end of if (isInterB)
/*
当备选集数目不足maxNumMergeCand,则进行(0,0)填补
*/
int numRefIdx = (isInterB) ? X265_MIN(m_slice->m_numRefIdx[0], m_slice->m_numRefIdx[1]) : m_slice->m_numRefIdx[0];
int r = 0;
int refcnt = 0;
while (count < maxNumMergeCand)
{
candDir[count] = 1;
candMvField[count][0].mv.word = 0;
candMvField[count][0].refIdx = r;
if (isInterB)
{
candDir[count] = 3;
candMvField[count][1].mv.word = 0;
candMvField[count][1].refIdx = r;
}
count++;
if (refcnt == numRefIdx - 1)
r = 0;
else
{
++r;
++refcnt;
}
}
//返回当前备选集的数量
return count;
}
上一篇: 去方块滤波