CUData::getInterMergeCandidates()/getNeighbourMV()

空间merge备选集

必要,5选4,B2替补
在这里插入图片描述
在这里插入图片描述

时间merge备选集

可选,2选1,C3替补
在这里插入图片描述

CUData::getInterMergeCandidates()

CUData::getInterMergeCandidates()构造当前PU的merge备选集

/* Construct list of merging candidates, returns count 
   构造merge备选集列表,返回备选集个数
   
   备选集方案:
	   ·空域必须,时域可选,空域优先级>时域
	   ·空域5选4,即空域中aboveLeft作为空域备选,若left/leftBottow/above/aboveRight存在不可使用则尝试使用aboveLeft
	   ·时域2选1,优先选用rightBottow,若rightBottow不可用则尝试用center
	   ·若是Bslice,则需要进行列表组合
	   ·若备选集不足最大备选集数量(默认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;
}

CUData::getNeighbourMV()

为当前PU构建相邻MV备选集

/* Constructs a list of candidates for AMVP, and a larger list of motion candidates 
	为当前PU构建MV备选集到neighbours[0~5]中,其中0~4是空域,5是时域

	原则:
		·空域必选,五个都要加载
		·时域可选,优先加载co-rightBottom,若co-rightBottom无效则加载co-center
		
	过程:
		1.得到当前PU的相邻LeftBottom/LeftTop/RightTop的PU索引
		2.载入五个空域备选MV到neighbours[0~4]中
		3.若开启了时域MVP,则计算时域备选MV
			1.得到当前PU的相邻co-rightBottom的PU索引
			2.载入co-rightBottom的MV到neighbours[5]中,若rightBottom不可用则载入co-center
*/
void CUData::getNeighbourMV(uint32_t puIdx, uint32_t absPartIdx, InterNeighbourMV* neighbours) const
{
    // Set the temporal neighbour to unavailable by default.
	// 先初始化空域MVP不可用
    neighbours[MD_COLLOCATED].unifiedRef = -1;

	//得到LeftBottom的PU索引
    uint32_t partIdxLT, partIdxRT, partIdxLB = deriveLeftBottomIdx(puIdx);
	//得到LeftTop和RightTop的PU索引
    deriveLeftRightTopIdx(puIdx, partIdxLT, partIdxRT);

    // Load the spatial MVs. 分别加载left/belowLeft/aboveLeft/aboveRight/above的MV
    getInterNeighbourMV(neighbours + MD_BELOW_LEFT, partIdxLB, MD_BELOW_LEFT);
    getInterNeighbourMV(neighbours + MD_LEFT,       partIdxLB, MD_LEFT);
    getInterNeighbourMV(neighbours + MD_ABOVE_RIGHT,partIdxRT, MD_ABOVE_RIGHT);
    getInterNeighbourMV(neighbours + MD_ABOVE,      partIdxRT, MD_ABOVE);
    getInterNeighbourMV(neighbours + MD_ABOVE_LEFT, partIdxLT, MD_ABOVE_LEFT);

	//若允空间MVP
    if (m_slice->m_sps->bTemporalMVPEnabled)
    {
        uint32_t absPartAddr = m_absIdxInCTU + absPartIdx;
		//得到rightBottom的PU索引
        uint32_t partIdxRB = deriveRightBottomIdx(puIdx);

        // co-located RightBottom temporal predictor (H)
        int ctuIdx = -1;

        // image boundary check 若当前CTU
        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-rightBottom是否在CTU的最后一列
            bool bNotLastCol = lessThanCol(absPartIdxRB, numUnits - 1); // is not at the last column of CTU
            //co-rightBottom是否在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)
                absPartAddr = g_rasterToZscan[(absPartIdxRB + 1) & (numUnits - 1)];
            //不在最后一行
			else if (bNotLastRow)
            {
                absPartAddr = g_rasterToZscan[absPartIdxRB + RASTER_SIZE - numUnits + 1];
                ctuIdx = m_cuAddr + 1;
            }
			//在最后一列 && 最后一行 => 在CTU最右下角
            else // is the right bottom corner of CTU
                absPartAddr = 0;
        }

		//若无法得到co-rightBottom的MV,则尝试co-center的MV
        if (!(ctuIdx >= 0 && getCollocatedMV(ctuIdx, absPartAddr, neighbours + MD_COLLOCATED)))
        {
			//得到co-center的索引
            uint32_t partIdxCenter =  deriveCenterIdx(puIdx);
            uint32_t curCTUIdx = m_cuAddr;
			//加载co-center的mv
            getCollocatedMV(curCTUIdx, partIdxCenter, neighbours + MD_COLLOCATED);
        }
    }
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值