今天主要介绍帧内预测一个很重要的函数initAdiPattern,它的主要功能有三个,(1)检测当前PU的相邻样点包括左上、上、右上、左、左下邻域样点值的可用性,或者说检查这些点是否存在;(2)参考样点的替换过程,主要实现的是JCTVC-J1003即draft 8.4.4.2.2的内容,主要由函数fillReferenceSamples来完成,这个在之前的文章已经讨论过了;(3)相邻样点即参考样点的平滑滤波,主要实现draft 8.4.4.2.3的内容。话不多说,下面给出initAdiPattern的实现和我个人的一些注释,供大家参考。
- Void TComPattern::initAdiPattern( TComDataCU* pcCU, UInt uiZorderIdxInPart, UInt uiPartDepth, Int* piAdiBuf, Int iOrgBufStride, Int iOrgBufHeight, Bool& bAbove, Bool& bLeft, Bool bLMmode )
- {//! bLMmode is usually false
- Pel* piRoiOrigin;
- Int* piAdiTemp;
- UInt uiCuWidth = pcCU->getWidth(0) >> uiPartDepth; //!< CU的宽度
- UInt uiCuHeight = pcCU->getHeight(0)>> uiPartDepth; //!< CU的高度
- UInt uiCuWidth2 = uiCuWidth<<1;
- UInt uiCuHeight2 = uiCuHeight<<1;
- UInt uiWidth;
- UInt uiHeight;
- Int iPicStride = pcCU->getPic()->getStride();
- Int iUnitSize = 0;
- Int iNumUnitsInCu = 0;
- Int iTotalUnits = 0;
- Bool bNeighborFlags[4 * MAX_NUM_SPU_W + 1]; //!< 用于存放4个方向上的相邻样点值的可用性, 4 x 32 + 1
- Int iNumIntraNeighbor = 0; //!< 给可用邻块进行计数
-
- UInt uiPartIdxLT, uiPartIdxRT, uiPartIdxLB;
- //! 获取当前PU左上角LT,右上角RT以及左下角LB 以4x4块为单位的Zorder
- pcCU->deriveLeftRightTopIdxAdi( uiPartIdxLT, uiPartIdxRT, uiZorderIdxInPart, uiPartDepth );
- pcCU->deriveLeftBottomIdxAdi ( uiPartIdxLB, uiZorderIdxInPart, uiPartDepth );
-
- iUnitSize = g_uiMaxCUWidth >> g_uiMaxCUDepth;
- iNumUnitsInCu = uiCuWidth / iUnitSize;
- iTotalUnits = (iNumUnitsInCu << 2) + 1; // Top + RightTop + Left + LeftBottom + LeftTop = iNumUnitsInCu + iNumUnitsInCu + iNumUnitsInCu + iNumUnitsInCu + 1
- //! 扫描顺序是从左下到左上,再从左上到右上
- bNeighborFlags[iNumUnitsInCu*2] = isAboveLeftAvailable( pcCU, uiPartIdxLT );
- iNumIntraNeighbor += (Int)(bNeighborFlags[iNumUnitsInCu*2]);
- iNumIntraNeighbor += isAboveAvailable ( pcCU, uiPartIdxLT, uiPartIdxRT, bNeighborFlags+(iNumUnitsInCu*2)+1 );
- iNumIntraNeighbor += isAboveRightAvailable( pcCU, uiPartIdxLT, uiPartIdxRT, bNeighborFlags+(iNumUnitsInCu*3)+1 );
- iNumIntraNeighbor += isLeftAvailable ( pcCU, uiPartIdxLT, uiPartIdxLB, bNeighborFlags+(iNumUnitsInCu*2)-1 );
- iNumIntraNeighbor += isBelowLeftAvailable ( pcCU, uiPartIdxLT, uiPartIdxLB, bNeighborFlags+ iNumUnitsInCu -1 );
-
- bAbove = true;
- bLeft = true;
- uiWidth=uiCuWidth2+1;
- uiHeight=uiCuHeight2+1;
-
- if (((uiWidth<<2)>iOrgBufStride)||((uiHeight<<2)>iOrgBufHeight))
- {
- return;
- }
- //! piRoiOrigin指向当前PU左上角
- piRoiOrigin = pcCU->getPic()->getPicYuvRec()->getLumaAddr(pcCU->getAddr(), pcCU->getZorderIdxInCU()+uiZorderIdxInPart);
- piAdiTemp = piAdiBuf;
- fillReferenceSamples ( pcCU, piRoiOrigin, piAdiTemp, bNeighborFlags, iNumIntraNeighbor, iUnitSize, iNumUnitsInCu, iTotalUnits, uiCuWidth, uiCuHeight, uiWidth, uiHeight, iPicStride, bLMmode);
-
- Int i;
- // generate filtered intra prediction samples
- Int iBufSize = uiCuHeight2 + uiCuWidth2 + 1; // left and left above border + above and above right border + top left corner = length of 3. filter buffer
- UInt uiWH = uiWidth * uiHeight; // number of elements in one buffer
- //! 下面所进行的工作主要是对参考样点进行3抽头的滤波。piAdiBuf指向滤波前的参考样点的首地址,在滤波前,先将所有参考样点
- //! 拷贝到piFilterBuf指向的区域,经滤波后的样点值保存在piFilterBufN指向的区域,最终将滤波后的样点值拷贝到piFilterBuf1
- //! 值得一提的是,最终的结果是,piAdiBuf指向的区域是未经滤波的样点值,而piFilterBuf1指向的区域是经过滤波的样点值,
- //! 两者的地址相差uiWH = uiWidth * uiHeight = (uiCuWidth2 + 1) * (uiCuHeight2 + 1),这就解释了在进行真正的帧内预测时,
- //! 在需要滤波时,指向piAdiBuf的指针需要加上uiWH的偏移量
- Int* piFilteredBuf1 = piAdiBuf + uiWH; // 1. filter buffer
- Int* piFilteredBuf2 = piFilteredBuf1 + uiWH; // 2. filter buffer
- Int* piFilterBuf = piFilteredBuf2 + uiWH; // buffer for 2. filtering (sequential)
- Int* piFilterBufN = piFilterBuf + iBufSize; // buffer for 1. filtering (sequential) //!<存放的是参考样点经3抽头滤波后的值
- // draft 8.4.4.2.3 Filtering process of neighbouring samples
- Int l = 0;
- // left border from bottom to top
- for (i = 0; i < uiCuHeight2; i++)
- {
- piFilterBuf[l++] = piAdiTemp[uiWidth * (uiCuHeight2 - i)]; //!< 左边界,存储顺序为从下往上
- }
- // top left corner
- piFilterBuf[l++] = piAdiTemp[0]; //!< 左上边界
- // above border from left to right
- for (i=0; i < uiCuWidth2; i++)
- {
- piFilterBuf[l++] = piAdiTemp[1 + i]; //!<上边界,存储顺序为从左往右
- }
- // 1. filtering with [1 2 1]
- piFilterBufN[0] = piFilterBuf[0]; //!< 第1个点直接保存,不滤波
- piFilterBufN[iBufSize - 1] = piFilterBuf[iBufSize - 1]; //!< 最后一个点也直接保存,不滤波
- for (i = 1; i < iBufSize - 1; i++) //!< 对中间样点值进行3抽头[1 2 1] / 4 的平滑滤波
- {
- piFilterBufN[i] = (piFilterBuf[i - 1] + 2 * piFilterBuf[i]+piFilterBuf[i + 1] + 2) >> 2;
- }
- // fill 1. filter buffer with filtered values
- l=0;
- for (i = 0; i < uiCuHeight2; i++)
- {
- piFilteredBuf1[uiWidth * (uiCuHeight2 - i)] = piFilterBufN[l++]; // left border from bottom to top //!< 左边界
- }
- piFilteredBuf1[0] = piFilterBufN[l++]; //!< 左上边界
- for (i = 0; i < uiCuWidth2; i++)
- {
- piFilteredBuf1[1 + i] = piFilterBufN[l++]; // above border from left to right //!< 上边界
- }
- }
复制代码最后附上图,以帮助大家更好地理解代码,我就不对图多作解释了,相信大家对着代码能比较容易看明白的。 [img][/img]
(转载请注明出处。原文地址:http://blog.csdn.net/hevc_cjl/article/details/8184276) |