您的位置:首页 > 其它

【HEVC】2、HM-16.7编码一个CU(帧内部分) 1.帧内预测相邻参考像素获取

2016-02-15 15:55 525 查看
HEVC帧内预测的35中预测模式是在PU基础上定义的,实际帧内预测的过程则以TU为单位。PU以四叉树划分TU,一个PU内所有TU共享同一种预测模式。帧内预测分3个步骤:

(1) 判断当前TU相邻像素点是否可用并做相应的处理

(2) 对参考像素进行滤波

(3) 根据滤波后的参考像素计算当前TU的预测像素值。

HM-16.7中fillReferenceSamples()主要实现第一个步骤,真正进行帧内预测之前,使用重建后的Yuv图像对当前PU的相邻样点进行赋值,为接下来进行的角度预测提供参考样点值,对应于draft 8.4.4.2.2的内容。主要过程是:

(1)如果所有相邻点均不可用,则参考样点值均被赋值为DC值;

iDCValue = 1 << (bitDepth - 1),对于8bit像素,该值为128。

(2)如果所有相邻点均可用,则参考样点值都会被赋值为重建Yuv图像中与其位置相同的样点值;

(3)如果不满足上述两个条件,则按照从左下往左上,从左上往右上的扫描顺序进行遍历,如果第一个点不可用,则使用下一个可用点对应的重建Yuv样点值对其进行赋值;对于除第一个点外的其它邻点,如果该点不可用,则使用它的前一个样点值进行赋值(前一个步骤保证了前一个样点值一定是存在的),直到遍历完毕。

Void fillReferenceSamples( const Int bitDepth,
#if O0043_BEST_EFFORT_DECODING
const Int bitDepthDelta,
#endif
const Pel* piRoiOrigin,
Pel* piIntraTemp,
const Bool* bNeighborFlags,
const Int iNumIntraNeighbor,
const Int unitWidth,
const Int unitHeight,
const Int iAboveUnits,
const Int iLeftUnits,
const UInt uiWidth,
const UInt uiHeight,
const Int iPicStride )
{
const Pel* piRoiTemp;//piRoiOrgin指向重建Yuv图像对应于当前PU所在位置的首地址,piRoiTemp用于指向所感兴趣的重建Yuv的位置
Int  i, j;
Int  iDCValue = 1 << (bitDepth - 1);//参考像素不可用时的填充值,8bit时候为128.
const Int iTotalUnits = iAboveUnits + iLeftUnits + 1; //+1 for top-left //以4个像素点为单位标记,其中左上角单独标记

if (iNumIntraNeighbor == 0) // all samples are not available
{
// Fill border with DC value
for (i=0; i<uiWidth; i++) //!< AboveLeft + Above + AboveRight
{
piIntraTemp[i] = iDCValue;
}
for (i=1; i<uiHeight; i++)//!< Left + BelowLeft
{
piIntraTemp[i*uiWidth] = iDCValue;
}
}
else if (iNumIntraNeighbor == iTotalUnits)// all samples are available
{
// Fill top-left border and top and top right with rec. samples
piRoiTemp = piRoiOrigin - iPicStride - 1; //!< AboveLeft

for (i=0; i<uiWidth; i++)
{
#if O0043_BEST_EFFORT_DECODING
piIntraTemp[i] = piRoiTemp[i] << bitDepthDelta;
#else
piIntraTemp[i] = piRoiTemp[i];
#endif
}

// Fill left and below left border with rec. samples
piRoiTemp = piRoiOrigin - 1;

for (i=1; i<uiHeight; i++)
{
#if O0043_BEST_EFFORT_DECODING
piIntraTemp[i*uiWidth] = (*(piRoiTemp)) << bitDepthDelta;
#else
piIntraTemp[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
//!< neighboring samples的总数
const Int  iTotalSamples = (iLeftUnits * unitHeight) + ((iAboveUnits + 1) * unitWidth);
Pel  piIntraLine[5 * MAX_CU_SIZE];
Pel  *piIntraLineTemp;//!<临时存储用于填充neighboring samples的样点值
const Bool *pbNeighborFlags;//保存以四个像素点为单位的可用性

// Initialize
for (i=0; i<iTotalSamples; i++)
{
piIntraLine[i] = iDCValue;
}

// Fill top-left sample
piRoiTemp = piRoiOrigin - iPicStride - 1;//!< 指向重建Yuv左上角
piIntraLineTemp = piIntraLine + (iLeftUnits * unitHeight);//!< piAdiLine的扫描顺序为左下到左上,再从左到右上
pbNeighborFlags = bNeighborFlags + iLeftUnits;//!< 标记neighbor可用性的数组同样移动至左上角
if (*pbNeighborFlags)//!< 如果左上角可用,则左上角4个像素点均赋值为重建Yuv左上角的样点值
{
#if O0043_BEST_EFFORT_DECODING
Pel topLeftVal=piRoiTemp[0] << bitDepthDelta;
#else
Pel topLeftVal=piRoiTemp[0];
#endif
for (i=0; i<unitWidth; i++)
{
piIntraLineTemp[i] = topLeftVal;
}
}

// Fill left & below-left samples (downwards)
piRoiTemp += iPicStride;//!< piRoiTemp指向重建Yuv的左边界
piIntraLineTemp--;//移动指针至左边界
pbNeighborFlags--;//移动指针至左边界

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

// Fill above & above-right samples (left-to-right) (each unit has "unitWidth" samples)
piRoiTemp = piRoiOrigin - iPicStride;//!< piRoiTemp 指向重建Yuv的上边界
// offset line buffer by iNumUints2*unitHeight (for left/below-left) + unitWidth (for above-left)
piIntraLineTemp = piIntraLine + (iLeftUnits * unitHeight) + unitWidth;
pbNeighborFlags = bNeighborFlags + iLeftUnits + 1;
for (j=0; j<iAboveUnits; j++) //!< 从左扫描至右上
{
if (*pbNeighborFlags)//如果可用
{
for (i=0; i<unitWidth; i++)//!< 每个4x4块里的4个样点分别被赋值为对应位置的重建Yuv的样点值
{
#if O0043_BEST_EFFORT_DECODING
piIntraLineTemp[i] = piRoiTemp[i] << bitDepthDelta;
#else
piIntraLineTemp[i] = piRoiTemp[i];
#endif
}
}
piRoiTemp += unitWidth;//!< 指针右移,实际是右移了4
piIntraLineTemp += unitWidth;//!< 指针右移,实际是右移了4
pbNeighborFlags++;//!< 指针右移,以4个像素点为单位标记可用性
}

// Pad reference samples when necessary
Int iCurrJnit = 0;
Pel  *piIntraLineCur   = piIntraLine;//!< 指向左下角(纵坐标最大的那个位置,即扫描起点)
const UInt piIntraLineTopRowOffset = 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++;
}
Pel *piIntraLineNext = piIntraLine + ((iNext < iLeftUnits) ? (iNext * unitHeight) : (piIntraLineTopRowOffset + (iNext * unitWidth)));
const Pel refSample = *piIntraLineNext;
// Pad unavailable samples with new value
Int iNextOrTop = std::min<Int>(iNext, iLeftUnits);
// fill left column
while (iCurrJnit < iNextOrTop) //!< 遍历所有neighboring samples
{
for (i=0; i<unitHeight; i++)
{
piIntraLineCur[i] = refSample;
}
piIntraLineCur += unitHeight;
iCurrJnit++;
}
// fill top row
while (iCurrJnit < iNext)
{
for (i=0; i<unitWidth; i++)
{
piIntraLineCur[i] = refSample;
}
piIntraLineCur += 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 = *(piIntraLineCur-1);
for (i=0; i<numSamplesInCurrUnit; i++)
{
piIntraLineCur[i] = refSample;
}
piIntraLineCur += numSamplesInCurrUnit;
iCurrJnit++;
}
}
else
{
piIntraLineCur += (iCurrJnit >= iLeftUnits) ? unitWidth : unitHeight;
iCurrJnit++;
}
}

// Copy processed samples

piIntraLineTemp = piIntraLine + uiHeight + unitWidth - 2;
// top left, top and top right samples
for (i=0; i<uiWidth; i++)
{
piIntraTemp[i] = piIntraLineTemp[i];
}

piIntraLineTemp = piIntraLine + uiHeight - 1;
for (i=1; i<uiHeight; i++)
{
piIntraTemp[i*uiWidth] = piIntraLineTemp[-i];
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: