HEVC帧内预测之参考像素的填充代码详析(一)
程序员文章站
2022-03-17 14:58:27
...
作者:66
(转载请注明出处)
fillReferenceSamples( )//填充参考像素值
帧内预测用到的函数大概有十几个,先来看fillRerenceSamples( )。
iNumIntraNeighbor标识参考像素可用块数,以iUnitSize块长为单位。
分三种情况,1.像素全部可用,往相应位置填;2.像素部分可用,不可用的填默认值;3.像素不可用,全部填默认值;
在像素全部不可用时,代码不按一个一个像素复制,而是划分为iUnitSize大小的块,长宽都按多少个块长为单位,目前不了解为什么这么设置,在后面的分析中会了解。
Void TComPattern::fillReferenceSamples(Int bitDepth, Pel* piRoiOrigin, Int* piAdiTemp,
Bool* bNeighborFlags, Int iNumIntraNeighbor, Int iUnitSize, Int iNumUnitsInCu, Int
iTotalUnits, UInt uiCuWidth, UInt uiCuHeight, UInt uiWidth, UInt uiHeight, Int iPicStride,
Bool bLMmode )
{
Pel* piRoiTemp;
Int i, j;
Int iDCValue = 1 << (bitDepth - 1);//8bit像素为128,10bit像素为512
if (iNumIntraNeighbor == 0)//相邻的参考像素不可用
{
// Fill border with DC value
for (i=0; i<uiWidth; i++)//unsigned int
{
piAdiTemp[i] = iDCValue;//上方
}
for (i=1; i<uiHeight; i++)
{
piAdiTemp[i*uiWidth] = iDCValue;//左边界(不包括左上顶点)
}
}
else if (iNumIntraNeighbor == iTotalUnits)//相邻参考像素全部可用
{
// Fill top-left border with rec. samples
piRoiTemp = piRoiOrigin - iPicStride - 1;//指向左上点
piAdiTemp[0] = piRoiTemp[0];
// Fill left border with rec. samples
piRoiTemp = piRoiOrigin - 1;//左边界第一个
if (bLMmode)//默认为false
{
piRoiTemp --; // move to the second left column
}
for (i=0; i<uiCuHeight; i++)
{
piAdiTemp[(1+i)*uiWidth] = piRoiTemp[0];
piRoiTemp += iPicStride;//每次往下移一行
}
// Fill below left border with rec. samples
for (i=0; i<uiCuHeight; i++)
{
piAdiTemp[(1+uiCuHeight+i)*uiWidth] = piRoiTemp[0];
piRoiTemp += iPicStride;
}
// Fill top border with rec. samples
piRoiTemp = piRoiOrigin - iPicStride;
for (i=0; i<uiCuWidth; i++)
{
piAdiTemp[1+i] = piRoiTemp[i];
}
// Fill top right border with rec. samples
piRoiTemp = piRoiOrigin - iPicStride + uiCuWidth;
for (i=0; i<uiCuWidth; i++)
{
piAdiTemp[1+uiCuWidth+i] = piRoiTemp[i];
}
}
else // reference samples are partially available
{
Int iNumUnits2 = iNumUnitsInCu<<1;//两个块边长的长度
Int iTotalSamples = iTotalUnits*iUnitSize;//iUnitSize块大小,iTotalUnits为当前pu包
含的块
Pel piAdiLine[5 * MAX_CU_SIZE];//临时存储参考像素值
Pel *piAdiLineTemp; //pi中当前指针
Bool *pbNeighborFlags;//标记是否可用
Int iNext, iCurr;
Pel piRef = 0;
// Initialize先全部设为DC默认值
for (i=0; i<iTotalSamples; i++)
{
piAdiLine[i] = iDCValue;//全设置为默认值
}
//这里参考像素临时存在piAdiLine中,顺序为从左下依次到右上
// Fill top-left sample
piRoiTemp = piRoiOrigin - iPicStride - 1;
piAdiLineTemp = piAdiLine + (iNumUnits2*iUnitSize);//指向该存储左上点的位置
pbNeighborFlags = bNeighborFlags + iNumUnits2;//移到左上像素点的标志位
if (*pbNeighborFlags)//左上可用
{
piAdiLineTemp[0] = piRoiTemp[0];
for (i=1; i<iUnitSize; i++)//这里左上像素占了iUnitSize个位置,?为什么这样,估
计和后面用有关。
{
piAdiLineTemp[i] = piAdiLineTemp[0];
}
}
// Fill left & below-left samples
piRoiTemp += iPicStride;//下移
if (bLMmode)
{
piRoiTemp --; // move the second left column
}
piAdiLineTemp--;
pbNeighborFlags--;
for (j=0; j<iNumUnits2; j++)//按块
{
if (*pbNeighborFlags)//每次标记一个块的像素
{
for (i=0; i<iUnitSize; i++)
{
piAdiLineTemp[-i] = piRoiTemp[i*iPicStride];
}
}
piRoiTemp += iUnitSize*iPicStride;
piAdiLineTemp -= iUnitSize;
pbNeighborFlags--;
}
// Fill above & above-right samples
piRoiTemp = piRoiOrigin - iPicStride;
piAdiLineTemp = piAdiLine + ((iNumUnits2+1)*iUnitSize);
pbNeighborFlags = bNeighborFlags + iNumUnits2 + 1;
for (j=0; j<iNumUnits2; j++)
{
if (*pbNeighborFlags)
{
for (i=0; i<iUnitSize; i++)
{
piAdiLineTemp[i] = piRoiTemp[i];
}
}
piRoiTemp += iUnitSize;
piAdiLineTemp += iUnitSize;
pbNeighborFlags++;
}
// Pad reference samples when necessary
iCurr = 0;
iNext = 1;
piAdiLineTemp = piAdiLine;//临时矩阵开始处,指向参考像素左下角
while (iCurr < iTotalUnits)
{
if (!bNeighborFlags[iCurr])//第iCurr组参考像素不可用
{
if(iCurr == 0)//第一组
{
while (iNext < iTotalUnits && !bNeighborFlags[iNext])//iCurr下一组iNext组参考
像素不可用
{
iNext++;
}
piRef = piAdiLine[iNext*iUnitSize];//临时存储遇到可用的第一个像素
// Pad unavailable samples with new value
while (iCurr < iNext)//之前找到的不可用全部用第一个可用像素填充
{
for (i=0; i<iUnitSize; i++)
{
piAdiLineTemp[i] = piRef;
}
piAdiLineTemp += iUnitSize;
iCurr++;
}
}
else
{
piRef = piAdiLine[iCurr*iUnitSize-1];//用上一组可用像素的最后一个填充
for (i=0; i<iUnitSize; i++)
{
piAdiLineTemp[i] = piRef;
}
piAdiLineTemp += iUnitSize;
iCurr++;
}
}
else//当前组可用,不做任何处理。
{
piAdiLineTemp += iUnitSize;
iCurr++;
}
}
// Copy processed samples
piAdiLineTemp = piAdiLine + uiHeight + iUnitSize - 2;//复制左上、上、右上
for (i=0; i<uiWidth; i++)
{
piAdiTemp[i] = piAdiLineTemp[i];
}
piAdiLineTemp = piAdiLine + uiHeight - 1;
for (i=1; i<uiHeight; i++)//复制左、左下
{
piAdiTemp[i*uiWidth] = piAdiLineTemp[-i];
}
}
}