HM编码器代码阅读(43)——样点自适应补偿SAO(二)收集像素块的统计信息

收集像素块的统计信息



    在进行SAO之前,要对像素块的像素值进行归类,然后判断它们属于EO的那个种类或者BO的哪个边带



入口函数getStatistics



    getStatistics是收集像素统计信息的入口函数
    流程如下:
    1、遍历图像的每一个CTU
    2、对于每一个CTU,调用deriveLoopFilterBoundaryAvailibility,用来判断相邻CTU的有效性(是否存在)
    3、对于每个CTU的每一个颜色分量,调用getBlkStats,用来搜集该CTU中某个分量的像素的统计信息
    4、处理结束

/*
** 收集像素块的统计信息,用于判断像素属于EO的那个种类/BO的哪个边带
** 对整个图像进行处理,遍历图像的每一个CTU,对CTU的每一个分量,都调用 getBlkStats
*/
Void TEncSampleAdaptiveOffset::getStatistics(SAOStatData*** blkStats, TComPicYuv* orgYuv, TComPicYuv* srcYuv, TComPic* pPic
#if SAO_ENCODE_ALLOW_USE_PREDEBLOCK
	, Bool isCalculatePreDeblockSamples
#endif
	)
{
	Bool isLeftAvail,isRightAvail,isAboveAvail,isBelowAvail,isAboveLeftAvail,isAboveRightAvail,isBelowLeftAvail,isBelowRightAvail;

	for(Int ctu= 0; ctu < m_numCTUsPic; ctu++)
	{
		Int yPos   = (ctu / m_numCTUInWidth)*m_maxCUHeight;
		Int xPos   = (ctu % m_numCTUInWidth)*m_maxCUWidth;
		Int height = (yPos + m_maxCUHeight > m_picHeight)?(m_picHeight- yPos):m_maxCUHeight;
		Int width  = (xPos + m_maxCUWidth  > m_picWidth )?(m_picWidth - xPos):m_maxCUWidth;

		// 判断相邻CTU的有效性(是否存在)
		pPic->getPicSym()->deriveLoopFilterBoundaryAvailibility(ctu, isLeftAvail,isRightAvail,isAboveAvail,isBelowAvail,isAboveLeftAvail,isAboveRightAvail,isBelowLeftAvail,isBelowRightAvail);

		//NOTE: The number of skipped lines during gathering CTU statistics depends on the slice boundary availabilities.
		//For simplicity, here only picture boundaries are considered.

		isRightAvail      = (xPos + m_maxCUWidth  < m_picWidth );
		isBelowAvail      = (yPos + m_maxCUHeight < m_picHeight);
		isBelowRightAvail = (isRightAvail && isBelowAvail);
		isBelowLeftAvail  = ((xPos > 0) && (isBelowAvail));
		isAboveRightAvail = ((yPos > 0) && (isRightAvail));

		for(Int compIdx=0; compIdx< NUM_SAO_COMPONENTS; compIdx++)
		{
			Bool isLuma     = (compIdx == SAO_Y);
			Int  formatShift= isLuma?0:1;

			Int  srcStride = isLuma?srcYuv->getStride():srcYuv->getCStride();
			Pel* srcBlk    = getPicBuf(srcYuv, compIdx)+ (yPos >> formatShift)*srcStride+ (xPos >> formatShift);

			Int  orgStride  = isLuma?orgYuv->getStride():orgYuv->getCStride();
			Pel* orgBlk     = getPicBuf(orgYuv, compIdx)+ (yPos >> formatShift)*orgStride+ (xPos >> formatShift);

			// 搜集一个CTU中某个分量的像素的统计信息
			getBlkStats(compIdx, blkStats[ctu][compIdx]  
			, srcBlk, orgBlk, srcStride, orgStride, (width  >> formatShift), (height >> formatShift)
				, isLeftAvail,  isRightAvail, isAboveAvail, isBelowAvail, isAboveLeftAvail, isAboveRightAvail, isBelowLeftAvail, isBelowRightAvail
#if SAO_ENCODE_ALLOW_USE_PREDEBLOCK
				, isCalculatePreDeblockSamples
#endif
				);

		}
	}
}



判断相邻CTU的有效性


    deriveLoopFilterBoundaryAvailibility用于判断相邻CTU的有效性(是否存在),这是为了下一步的像素统计做准备

/*
** 判断相邻CTU的有效性(是否存在)
*/
Void TComPicSym::deriveLoopFilterBoundaryAvailibility(Int ctu,
	Bool& isLeftAvail,
	Bool& isRightAvail,
	Bool& isAboveAvail,
	Bool& isBelowAvail,
	Bool& isAboveLeftAvail,
	Bool& isAboveRightAvail,
	Bool& isBelowLeftAvail,
	Bool& isBelowRightAvail
	)
{

	isLeftAvail      = (ctu % m_uiWidthInCU != 0);
	isRightAvail     = (ctu % m_uiWidthInCU != m_uiWidthInCU-1);
	isAboveAvail     = (ctu >= m_uiWidthInCU );
	isBelowAvail     = (ctu <  m_uiNumCUsInFrame - m_uiWidthInCU);
	isAboveLeftAvail = (isAboveAvail && isLeftAvail);
	isAboveRightAvail= (isAboveAvail && isRightAvail);
	isBelowLeftAvail = (isBelowAvail && isLeftAvail);
	isBelowRightAvail= (isBelowAvail && isRightAvail);

	Bool isLoopFiltAcrossTilePPS = getCU(ctu)->getSlice()->getPPS()->getLoopFilterAcrossTilesEnabledFlag();

	{
		TComDataCU* ctuCurr  = getCU(ctu);
		TComDataCU* ctuLeft  = isLeftAvail ?getCU(ctu-1):NULL;
		TComDataCU* ctuRight = isRightAvail?getCU(ctu+1):NULL;
		TComDataCU* ctuAbove = isAboveAvail?getCU(ctu-m_uiWidthInCU):NULL;
		TComDataCU* ctuBelow = isBelowAvail?getCU(ctu+m_uiWidthInCU):NULL;
		TComDataCU* ctuAboveLeft  = isAboveLeftAvail ? getCU(ctu-m_uiWidthInCU-1):NULL;
		TComDataCU* ctuAboveRigtht= isAboveRightAvail? getCU(ctu-m_uiWidthInCU+1):NULL;
		TComDataCU* ctuBelowLeft  = isBelowLeftAvail ? getCU(ctu+m_uiWidthInCU-1):NULL;
		TComDataCU* ctuBelowRight = isBelowRightAvail? getCU(ctu+m_uiWidthInCU+1):NULL;

		{
			//left
			if(ctuLeft != NULL)
			{
				isLeftAvail = (ctuCurr->getSlice()->getSliceCurStartCUAddr() != ctuLeft->getSlice()->getSliceCurStartCUAddr())?ctuCurr->getSlice()->getLFCrossSliceBoundaryFlag():true;
			}
			//above
			if(ctuAbove != NULL)
			{
				isAboveAvail = (ctuCurr->getSlice()->getSliceCurStartCUAddr() != ctuAbove->getSlice()->getSliceCurStartCUAddr())?ctuCurr->getSlice()->getLFCrossSliceBoundaryFlag():true;
			}
			//right
			if(ctuRight != NULL)
			{
				isRightAvail = (ctuCurr->getSlice()->getSliceCurStartCUAddr() != ctuRight->getSlice()->getSliceCurStartCUAddr())?ctuRight->getSlice()->getLFCrossSliceBoundaryFlag():true;
			}
			//below
			if(ctuBelow != NULL)
			{
				isBelowAvail = (ctuCurr->getSlice()->getSliceCurStartCUAddr() != ctuBelow->getSlice()->getSliceCurStartCUAddr())?ctuBelow->getSlice()->getLFCrossSliceBoundaryFlag():true;
			}
			//above-left
			if(ctuAboveLeft != NULL)
			{
				isAboveLeftAvail = (ctuCurr->getSlice()->getSliceCurStartCUAddr() != ctuAboveLeft->getSlice()->getSliceCurStartCUAddr())?ctuCurr->getSlice()->getLFCrossSliceBoundaryFlag():true;
			}
			//below-right
			if(ctuBelowRight != NULL)
			{
				isBelowRightAvail = (ctuCurr->getSlice()->getSliceCurStartCUAddr() != ctuBelowRight->getSlice()->getSliceCurStartCUAddr())?ctuBelowRight->getSlice()->getLFCrossSliceBoundaryFlag():true;
			}


			//above-right
			if(ctuAboveRigtht != NULL)
			{
				Int curSliceStartEncOrder  = ctuCurr->getSlice()->getSliceCurStartCUAddr();
				Int aboveRigthtSliceStartEncOrder = ctuAboveRigtht->getSlice()->getSliceCurStartCUAddr();

				isAboveRightAvail = (curSliceStartEncOrder == aboveRigthtSliceStartEncOrder)?(true):
					(
					(curSliceStartEncOrder > aboveRigthtSliceStartEncOrder)?(ctuCurr->getSlice()->getLFCrossSliceBoundaryFlag())
					:(ctuAboveRigtht->getSlice()->getLFCrossSliceBoundaryFlag())
					);          
			}
			//below-left
			if(ctuBelowLeft != NULL)
			{
				Int curSliceStartEncOrder  = ctuCurr->getSlice()->getSliceCurStartCUAddr();
				Int belowLeftSliceStartEncOrder = ctuBelowLeft->getSlice()->getSliceCurStartCUAddr();

				isBelowLeftAvail = (curSliceStartEncOrder == belowLeftSliceStartEncOrder)?(true):
					(
					(curSliceStartEncOrder > belowLeftSliceStartEncOrder)?(ctuCurr->getSlice()->getLFCrossSliceBoundaryFlag())
					:(ctuBelowLeft->getSlice()->getLFCrossSliceBoundaryFlag())
					);
			}        
		}

		if(!isLoopFiltAcrossTilePPS)
		{      
			isLeftAvail      = (!isLeftAvail      ) ?false:(getTileIdxMap( ctuLeft->getAddr()         ) == getTileIdxMap( ctu ));
			isAboveAvail     = (!isAboveAvail     ) ?false:(getTileIdxMap( ctuAbove->getAddr()        ) == getTileIdxMap( ctu ));
			isRightAvail     = (!isRightAvail     ) ?false:(getTileIdxMap( ctuRight->getAddr()        ) == getTileIdxMap( ctu ));
			isBelowAvail     = (!isBelowAvail     ) ?false:(getTileIdxMap( ctuBelow->getAddr()        ) == getTileIdxMap( ctu ));
			isAboveLeftAvail = (!isAboveLeftAvail ) ?false:(getTileIdxMap( ctuAboveLeft->getAddr()    ) == getTileIdxMap( ctu ));
			isAboveRightAvail= (!isAboveRightAvail) ?false:(getTileIdxMap( ctuAboveRigtht->getAddr()  ) == getTileIdxMap( ctu ));
			isBelowLeftAvail = (!isBelowLeftAvail ) ?false:(getTileIdxMap( ctuBelowLeft->getAddr()    ) == getTileIdxMap( ctu ));
			isBelowRightAvail= (!isBelowRightAvail) ?false:(getTileIdxMap( ctuBelowRight->getAddr()   ) == getTileIdxMap( ctu ));
		}
	}

}



搜集一个CTU分量的像素的统计信息


    getBlkStats用来搜集一个CTU中某个分量的像素的统计信息
    流程如下:
    1、遍历SAO除了merge之外的所有模式:SAO_TYPE_EO_0、SAO_TYPE_EO_90、SAO_TYPE_EO_135、SAO_TYPE_EO_45、SAO_TYPE_BO
    2、对于每一个SAO模式,都统计该模式下像素的信息
    3、最后的统计信息存放在SAOStatData中

/*
** 搜集一个CTU中某个分量的像素的统计信息
** 遍历SAO除了merge之外的所有类型:
** SAO_TYPE_EO_0 ,
** SAO_TYPE_EO_90,
** SAO_TYPE_EO_135,
** SAO_TYPE_EO_45,
** SAO_TYPE_BO 
** 对于每一种类型,都搜集像素的统计信息
** 最后的统计信息存放在SAOStatData中
*/
Void TEncSampleAdaptiveOffset::getBlkStats(Int compIdx, SAOStatData* statsDataTypes  
	, Pel* srcBlk, Pel* orgBlk, Int srcStride, Int orgStride, Int width, Int height
	, Bool isLeftAvail,  Bool isRightAvail, Bool isAboveAvail, Bool isBelowAvail, Bool isAboveLeftAvail, Bool isAboveRightAvail, Bool isBelowLeftAvail, Bool isBelowRightAvail
#if SAO_ENCODE_ALLOW_USE_PREDEBLOCK
	, Bool isCalculatePreDeblockSamples
#endif
	)
{
	if(m_lineBufWidth != m_maxCUWidth)
	{
		m_lineBufWidth = m_maxCUWidth;

		if (m_signLineBuf1) delete[] m_signLineBuf1; m_signLineBuf1 = NULL;
		m_signLineBuf1 = new Char[m_lineBufWidth+1]; 

		if (m_signLineBuf2) delete[] m_signLineBuf2; m_signLineBuf2 = NULL;
		m_signLineBuf2 = new Char[m_lineBufWidth+1];
	}

	Int x,y, startX, startY, endX, endY, edgeType, firstLineStartX, firstLineEndX;
	Char signLeft, signRight, signDown;
	Int64 *diff, *count;
	Pel *srcLine, *orgLine;
	Int* skipLinesR = m_skipLinesR[compIdx];
	Int* skipLinesB = m_skipLinesB[compIdx];

	for(Int typeIdx=0; typeIdx< NUM_SAO_NEW_TYPES; typeIdx++)
	{
		SAOStatData& statsData= statsDataTypes[typeIdx];
		statsData.reset();

		srcLine = srcBlk;
		orgLine = orgBlk;
		diff    = statsData.diff;
		count   = statsData.count;
		switch(typeIdx)
		{
		case SAO_TYPE_EO_0:
			{
				diff +=2;
				count+=2;
				endY   = (isBelowAvail) ? (height - skipLinesB[typeIdx]) : height;
#if SAO_ENCODE_ALLOW_USE_PREDEBLOCK
				startX = (!isCalculatePreDeblockSamples) ? (isLeftAvail  ? 0 : 1)
					: (isRightAvail ? (width - skipLinesR[typeIdx]) : (width - 1))
					;
#else
				startX = isLeftAvail ? 0 : 1;
#endif
#if SAO_ENCODE_ALLOW_USE_PREDEBLOCK
				endX   = (!isCalculatePreDeblockSamples) ? (isRightAvail ? (width - skipLinesR[typeIdx]) : (width - 1))
					: (isRightAvail ? width : (width - 1))
					;
#else
				endX   = isRightAvail ? (width - skipLinesR[typeIdx]): (width - 1);
#endif
				for (y=0; y<endY; y++)
				{
#if SAO_SGN_FUNC
					signLeft = (Char)sgn(srcLine[startX] - srcLine[startX-1]);
#else
					signLeft = (Char)m_sign[srcLine[startX] - srcLine[startX-1]];
#endif
					for (x=startX; x<endX; x++)
					{
#if SAO_SGN_FUNC
						signRight =  (Char)sgn(srcLine[x] - srcLine[x+1]);
#else
						signRight =  (Char)m_sign[srcLine[x] - srcLine[x+1]]; 
#endif
						edgeType  =  signRight + signLeft;
						signLeft  = -signRight;

						diff [edgeType] += (orgLine[x] - srcLine[x]);
						count[edgeType] ++;
					}
					srcLine  += srcStride;
					orgLine  += orgStride;
				}
#if SAO_ENCODE_ALLOW_USE_PREDEBLOCK
				if(isCalculatePreDeblockSamples)
				{
					if(isBelowAvail)
					{
						startX = isLeftAvail  ? 0 : 1;
						endX   = isRightAvail ? width : (width -1);

						for(y=0; y<skipLinesB[typeIdx]; y++)
						{
#if SAO_SGN_FUNC
							signLeft = (Char)sgn(srcLine[startX] - srcLine[startX-1]);
#else
							signLeft = (Char)m_sign[srcLine[startX] - srcLine[startX-1]];
#endif
							for (x=startX; x<endX; x++)
							{
#if SAO_SGN_FUNC
								signRight =  (Char)sgn(srcLine[x] - srcLine[x+1]);
#else
								signRight =  (Char)m_sign[srcLine[x] - srcLine[x+1]];
#endif
								edgeType  =  signRight + signLeft;
								signLeft  = -signRight;

								diff [edgeType] += (orgLine[x] - srcLine[x]);
								count[edgeType] ++;
							}
							srcLine  += srcStride;
							orgLine  += orgStride;
						}
					}
				}
#endif
			}
			break;
		case SAO_TYPE_EO_90:
			// 代码省略...
			break;
		case SAO_TYPE_EO_135:
			// 代码省略...
			break;
		case SAO_TYPE_EO_45:
			// 代码省略...
			break;
		case SAO_TYPE_BO:
			// 代码省略...
			break;
		default:
			{
				printf("Not a supported SAO types\n");
				assert(0);
				exit(-1);
			}
		}
	}
}






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值