HEVC学习-帧内预测(1)-fillReferenceSamples()函数

本文章主要参考:https://blog.csdn.net/m0_37579288/article/details/79094596
https://blog.csdn.net/HEVC_CJL/article/details/8175721

在这里插入图片描述

在这里插入图片描述

//fillReferenceSamples这个函数,它主要功能是在真正进行帧内预测之前,使用重建后的Yuv图像对当前PU的相邻样点进行赋值,为接下来进行的角度预测提供参考样点值。
//****************************************************************
//****************************************************************
//****************************************************************
#if RExt__O0043_BEST_EFFORT_DECODING//0(默认值)=禁用与最佳译码相关的代码,1 =启用与最佳译码相关的代码[仅在解码端]。
Void fillReferenceSamples(const Int bitDepth, const Int bitDepthDelta, TComDataCU* pcCU, const Pel* piRoiOrigin, Pel* piAdiTemp, const Bool* bNeighborFlags,
#else
Void fillReferenceSamples(const Int bitDepth, TComDataCU* pcCU, const Pel* piRoiOrigin, Pel* piAdiTemp, const Bool* bNeighborFlags,
#endif
	const Int iNumIntraNeighbor, const Int unitWidth, const Int unitHeight, const Int iAboveUnits, const Int iLeftUnits,
	const UInt uiCuWidth, const UInt uiCuHeight, const UInt uiWidth, const UInt uiHeight, const Int iPicStride,
	const ChannelType chType, const ChromaFormat chFmt)// piRoiOrgin指向重建Yuv图像对应于当前PU所在位置的首地址,piRoiTemp用于指向所感兴趣的重建Yuv的位置,piAdiTemp指向当前PU所在位置
{
	// NOTE: RExt - This function has been modified for increased flexibility as part of the Square TU 4:2:2 implementation注意:作为Square TU 4:2:2实现的一部分,为了增加灵活性,对这个函数进行了修改
	const Pel* piRoiTemp;
	Int  i, j;
	Int  iDCValue = 1 << (bitDepth - 1);//固定填充值DC
	const Int iTotalUnits = iAboveUnits + iLeftUnits + 1; //+1 for top-left**定义总的单元数=上方单元数+左侧单元数+1(左上方的一个单元)

	if (iNumIntraNeighbor == 0)//如果所有的区域均不可用,则用固定值DC进行填充
	{
		// Fill border with DC value
		for (i = 0; i<uiWidth; i++)//对上方+左上方单元进行填充
		{
			piAdiTemp[i] = iDCValue;
		}
		for (i = 1; i<uiHeight; i++)//对左侧单元进行填充
		{
			piAdiTemp[i*uiWidth] = iDCValue;
		}
	}
	else if (iNumIntraNeighbor == iTotalUnits)//如果所有的相邻参考像素均可用,则参考样点值都会被赋值为重建Yuv图像中与其位置相同的样点值
		//(因为在解码端需要对残差进行处理,因此用作处理的像素必须也是反量化变换得来的,为了与解码端同步,不能直接使用原来像素值)
	{
		// Fill top-left border and top and top right with rec. samples用重建样本值填充左上角、顶部和右上角
		piRoiTemp = piRoiOrigin - iPicStride - 1;//指向左上角像素块,piRoiOrigin - iPicStride指向当前像素的上一行对应像素,再-1即可指向左上角像素

		for (i = 0; i<uiWidth; i++)//循环进行像素的替代工作
		{
#if RExt__O0043_BEST_EFFORT_DECODING
			piAdiTemp[i] = piRoiTemp[i] << bitDepthDelta;
#else
			piAdiTemp[i] = piRoiTemp[i];//将重建YUV像素值赋给当前像素值
#endif
		}

		// Fill left and below left border with rec. samples用重建样本值填充左侧和左下
		piRoiTemp = piRoiOrigin - 1;//指向左侧第一个像素块

		for (i = 1; i<uiHeight; i++)
		{
#if RExt__O0043_BEST_EFFORT_DECODING
			piAdiTemp[i*uiWidth] = (*(piRoiTemp)) << bitDepthDelta;
#else
			piAdiTemp[i*uiWidth] = *(piRoiTemp);//把对应重建YUV像素值赋给当前像素
#endif
			piRoiTemp += iPicStride;//对应的YUV重建像素进行换行
		}
	}
	else // reference samples are partially available参考像素部分可用
	{
		// all above units have "unitWidth" samples each, all left/below-left units have "unitHeight" samples each上面所有的单元都有“单位宽度”的样本,左边/左边以下的单元都有“单位宽度”的样本
		const Int  iTotalSamples = (iLeftUnits * unitHeight) + ((iAboveUnits + 1) * unitWidth);//iTotalSamples为邻域样本的总数
		Pel  piAdiLine[5 * MAX_CU_SIZE];//!<临时存储用于填充neighboring samples的样点值
		Pel  *piAdiLineTemp; //当前指针
		const Bool *pbNeighborFlags;//标记是否可用


		// Initialize初始化-对新建的数组使用固定值DC进行初始化
		for (i = 0; i<iTotalSamples; i++)
		{
			piAdiLine[i] = iDCValue;
		}

		// Fill top-left sample填充左上的样本
		piRoiTemp = piRoiOrigin - iPicStride - 1;//指向重建左上的样值
		piAdiLineTemp = piAdiLine + (iLeftUnits * unitHeight);// piAdiLine的扫描顺序为左下到左上,再从左到右上,因此piAdiLine的初始值就是左下的最后一个样值
		pbNeighborFlags = bNeighborFlags + iLeftUnits;///!< 标记neighbor可用性的数组同样移动至左上角
		if (*pbNeighborFlags)//!< 如果左上角可用,则左上角4个像素点均赋值为重建Yuv左上角的样点值
		{
#if RExt__O0043_BEST_EFFORT_DECODING
			Pel topLeftVal = piRoiTemp[0] << bitDepthDelta;
#else
			Pel topLeftVal = piRoiTemp[0];//把重建后的左上样本值赋给中间变量
#endif
			for (i = 0; i<unitWidth; i++)
			{
				piAdiLineTemp[i] = topLeftVal;//把中间变量赋给左上角样值的每一个像素
			}
		}

		// Fill left & below-left samples (downwards)
		piRoiTemp += iPicStride; //!< piRoiTemp指向重建Yuv的左边界,左侧第一个样值
		piAdiLineTemp--;//!< 移动指针置左边界,左侧第一个样值
		pbNeighborFlags--;//!< 移动指针置左边界,左侧第一个样值

		for (j = 0; j<iLeftUnits; j++)//从左往左下扫描,如果可用,
		{
			if (*pbNeighborFlags)
			{
				for (i = 0; i<unitHeight; i++)
				{
#if RExt__O0043_BEST_EFFORT_DECODING
					piAdiLineTemp[-i] = piRoiTemp[i*iPicStride] << bitDepthDelta;
#else
					piAdiLineTemp[-i] = piRoiTemp[i*iPicStride];//!< 每个4x4块里的4个样点分别被赋值为对应位置的重建Yuv的样点值
#endif
				}
			}
			piRoiTemp += unitHeight * iPicStride;//!< 指针挪到下一个行(以4x4块为单位,即实际上下移了4行)
			piAdiLineTemp -= unitHeight;//!< 指针下移
			pbNeighborFlags--;//!< 指针下移
		}

		// Fill above & above-right samples (left-to-right) (each unit has "unitWidth" samples)填充上和右上的样值(从左到右)
		piRoiTemp = piRoiOrigin - iPicStride;//指向重建样值的上方第一个样值
		// offset line buffer by iNumUints2*unitHeight (for left/below-left) + unitWidth (for above-left)
		piAdiLineTemp = piAdiLine + (iLeftUnits * unitHeight) + unitWidth;//指向上边界,第一个样值
		pbNeighborFlags = bNeighborFlags + iLeftUnits + 1;//指向上边界,第一个样值
		for (j = 0; j<iAboveUnits; j++)//!< 从左扫描至右上
		{
			if (*pbNeighborFlags)
			{
				for (i = 0; i<unitWidth; i++)
				{
#if RExt__O0043_BEST_EFFORT_DECODING
					piAdiLineTemp[i] = piRoiTemp[i] << bitDepthDelta;
#else
					piAdiLineTemp[i] = piRoiTemp[i];//!< 每个4x4块里的4个样点分别被赋值为对应位置的重建Yuv的样点值
#endif
				}
			}
			piRoiTemp += unitWidth;//指针右移(以4x4块为单位,即实际向右移了4列)
			piAdiLineTemp += unitWidth;//指针右移
			pbNeighborFlags++;//指针右移
		}

		// Pad reference samples when necessary当必要的时候填充参考样值
		Int iCurrJnit = 0;//当前样值点个数计数器
		Pel  *piAdiLineCur = piAdiLine; //!< 指向左下角(纵坐标最大的那个位置,即扫描起点)
		const UInt piAdiLineTopRowOffset = iLeftUnits * (unitHeight - unitWidth);

		if (!bNeighborFlags[0])//如果该点不可用
		{
			// very bottom unit of bottom-left; at least one unit will be valid.左下角的最底部样值;至少有一个单元是有效的。
			{
				Int   iNext = 1;
				while (iNext < iTotalUnits && !bNeighborFlags[iNext])//找到第一个可用点(iNext小于总共的单元个数并且iNext位置的样点为不可用,iNext++)
				{
					iNext++;
				}
				Pel *piAdiLineNext = piAdiLine + ((iNext < iLeftUnits) ? (iNext * unitHeight) : (piAdiLineTopRowOffset + (iNext * unitWidth)));//指向第一个可用点
				const Pel refSample = *piAdiLineNext;//将第一个可用点的值赋给中间变量
				// Pad unavailable samples with new value将新的样本值填充至不可用的样本值
				Int iNextOrTop = std::min<Int>(iNext, iLeftUnits);//判断当前可用样值在左侧还是上方
				// fill left column填充左侧样本值
				while (iCurrJnit < iNextOrTop)//首先用中间变量对左侧的不可用的样值进行赋值
				{
					for (i = 0; i<unitHeight; i++)
					{
						piAdiLineCur[i] = refSample;
					}
					piAdiLineCur += unitHeight;
					iCurrJnit++;
				}
				// fill top row填充上方样本值
				while (iCurrJnit < iNext)//然后用中间变量对上方的不可用的样值进行赋值,直到可用的样值
				{
					for (i = 0; i<unitWidth; i++)
					{
						piAdiLineCur[i] = refSample;
					}
					piAdiLineCur += unitWidth;
					iCurrJnit++;
				}
			}
		}

		// pad all other reference samples.填充其他所有参考样值(第一个可用样点之后的样点值)
		while (iCurrJnit < iTotalUnits)//还未将所有的样点值遍历完
		{
			if (!bNeighborFlags[iCurrJnit]) // samples not available样值不可用
			{
				{
					const Int numSamplesInCurrUnit = (iCurrJnit >= iLeftUnits) ? unitWidth : unitHeight;//判断改样点值是否位于左侧
					const Pel refSample = *(piAdiLineCur - 1);//将上一个可用样点值的值赋给中间变量
					for (i = 0; i<numSamplesInCurrUnit; i++)
					{
						piAdiLineCur[i] = refSample;//将中间变量的值赋给当前样点值
					}
					piAdiLineCur += numSamplesInCurrUnit;
					iCurrJnit++;
				}
			}
			else
			{
				piAdiLineCur += (iCurrJnit >= iLeftUnits) ? unitWidth : unitHeight;
				iCurrJnit++;
			}
		}

		// Copy processed samples复制结果样值

		piAdiLineTemp = piAdiLine + uiHeight + unitWidth - 2;//!< piAdiLineTemp = (piAdiLine + 128) + 3,跳过之前对左上角扩充的3个像素点
		// top left, top and top right samples
		for (i = 0; i<uiWidth; i++)
		{
			piAdiTemp[i] = piAdiLineTemp[i]; //!< 将最终结果拷贝到左上、上、右上边界
		}

		piAdiLineTemp = piAdiLine + uiHeight - 1;//!< uiHeight = uiCUHeight2 + 1
		for (i = 1; i<uiHeight; i++)
		{
			piAdiTemp[i*uiWidth] = piAdiLineTemp[-i];//!< 将最终结果拷贝到左和左下边界,!< piAdiLineTemp下标为-i是因为赋值方向与实际存储方向是相反的
		}
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值