【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样点值对其进行赋值;对于除第一个点外的其它邻点,如果该点不可用,则使用它的前一个样点值进行赋值(前一个步骤保证了前一个样点值一定是存在的),直到遍历完毕。
(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]; } } }
相关文章推荐
- ElasticSearch学习-centos下安装
- jqGrid标题行与第一行之间有很大空白的问题解决。
- IOS 如何获取汉字字符串的拼音
- iOS学习随笔
- NDK错误总结
- Python学习路程day3
- web版源码管理软件SCM-Manager安装配置
- 【JSTL】--JSTL表达式:c:set,c:if,c:choose,--drp214
- PHP的Yii框架入门使用教程
- linux(centos7) 用户和组
- Json学习--简单创建
- 如何理解handler.postDelayed方法的用途与意义?
- ubuntu vim终端编辑命令小结,方便以后查找
- 心跳包机制
- HDU1048——史上最难的题
- 多个国内安卓模拟器的认识
- sheet
- leetcode(284) Peeking Iterator
- iOS学习路线
- 在项目中根据配置文件路径生成File对象的方法