作者:66
(转载请注明出处)
还是参考HEVC_CJL的博客,理论都清楚,跟着他的进度看代码,感谢前辈的分享,他的代码里没有强滤波过程,在此我稍加补充。
原文链接:http://blog.csdn.net/hevc_cjl/article/category/1283611
分析initAdiPattern函数,其中调用了之前的fillReferenceSample函数。
initAdiPattern实现的功能如下,1.先按4x4块从左下到右上检测每个块是否可用。2.调用fillReferenceSample填充参考样点。3.参考样点的滤波,分了常规滤波和强滤波。另外,HEVC_CJL博客中最后uiWidth,uiHeigth标识错误了,经几次确认后,应该是uiWidth=2*uiCuWidth,uiHeith=2*uiCuHeigth。
具体过程见代码注释,肯定也有表述不完备的地方,请不吝赐教:
Void TComPattern::initAdiPattern( TComDataCU* pcCU, UInt uiZorderIdxInPart, UInt uiPartDepth, Int* piAdiBuf, Int iOrgBufStride, Int iOrgBufHeight, Bool& bAbove, Bool& bLeft, Bool bLMmode )
{
Pel* piRoiOrigin;//当前cu首地址
Int* piAdiTemp;
UInt uiCuWidth = pcCU->getWidth(0) >> uiPartDepth;//cu宽度,uiPartDepth为四叉树深度
UInt uiCuHeight = pcCU->getHeight(0)>> uiPartDepth;//cu高度
UInt uiCuWidth2 = uiCuWidth<<1;
UInt uiCuHeight2 = uiCuHeight<<1;
UInt uiWidth;//cu宽度
UInt uiHeight;//cu高度
Int iPicStride = pcCU->getPic()->getStride();//每次步进的距离
Int iUnitSize = 0;//4*4块
Int iNumUnitsInCu = 0;
Int iTotalUnits = 0;//总共包含的4*4块数量
Bool bNeighborFlags[4 * MAX_NUM_SPU_W + 1];//标记参考像素是否可用,4*16+1
Int iNumIntraNeighbor = 0;//可用的相邻块数
UInt uiPartIdxLT, uiPartIdxRT, uiPartIdxLB;//获取当前PU左上、右上、左下以4x4为单位的Zorder
pcCU->deriveLeftRightTopIdxAdi( uiPartIdxLT, uiPartIdxRT, uiZorderIdxInPart, uiPartDepth );
pcCU->deriveLeftBottomIdxAdi ( uiPartIdxLB, uiZorderIdxInPart, uiPartDepth );
iUnitSize = g_uiMaxCUWidth >> g_uiMaxCUDepth;//4x4
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 );//上,这个函数的\
四个参数解释分别为当前pu编号,开始参考像素块号,结束块号,标志数组当前的位置指针
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、uiHeight与uiCuWidth,uiCuHeight不一样
uiWidth=uiCuWidth2+1;//lefttop+above+rightabove
uiHeight=uiCuHeight2+1;//lefttop+left+leftbelow
//超出buf的长
if (((uiWidth<<2)>iOrgBufStride)||((uiHeight<<2)>iOrgBufHeight))
{
return;
}
piRoiOrigin = pcCU->getPic()->getPicYuvRec()->getLumaAddr(pcCU->getAddr(), pcCU->getZorderIdxInCU()+uiZorderIdxInPart);
piAdiTemp = piAdiBuf;
fillReferenceSamples (g_bitDepthY, 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 bufferbuf的大小
//piFilteredBuf1最终参考像素放置的buf
Int* piFilteredBuf1 = piAdiBuf + uiWH; // 1. filter buffer
Int* piFilteredBuf2 = piFilteredBuf1 + uiWH; // 2. filter buffer
//piFilterBuf中进行滤波计算
Int* piFilterBuf = piFilteredBuf2 + uiWH; // buffer for 2. filtering (sequential)
//此处存放经滤波后的值
Int* piFilterBufN = piFilterBuf + iBufSize; // buffer for 1. filtering (sequential)
//draft8.4.2.3Filtering process of neighbouring sample
Int l = 0;
//左下到右上
// left border from bottom to top
for (i = 0; i < uiCuHeight2; i++)//将处理后的参考样点值放到piFilterBuf中
{
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];
}
//判断是否进行强滤波
if (pcCU->getSlice()->getSPS()->getUseStrongIntraSmoothing())
{
Int blkSize = 32;//强滤波块大小限定值,需要大于32的块
Int bottomLeft = piFilterBuf[0];//左下角一个像素
Int topLeft = piFilterBuf[uiCuHeight2];//左上角像素
Int topRight = piFilterBuf[iBufSize-1];//右上角像素
Int threshold = 1 << (g_bitDepthY - 5);//强滤波判断阈值
//左下+左上-2*左中间<阈值
Bool bilinearLeft = abs(bottomLeft+topLeft-2*piFilterBuf[uiCuHeight]) < threshold;
//左上+右上-2*上中间<阈值
Bool bilinearAbove = abs(topLeft+topRight-2*piFilterBuf[uiCuHeight2+uiCuHeight]) < threshold;
//强滤波
if (uiCuWidth>=blkSize && (bilinearLeft && bilinearAbove))
{
Int shift = g_aucConvertToBit[uiCuWidth] + 3; // log2(uiCuHeight2)=log2(64)=6
piFilterBufN[0] = piFilterBuf[0];//复制左下
piFilterBufN[uiCuHeight2] = piFilterBuf[uiCuHeight2];//左上
piFilterBufN[iBufSize - 1] = piFilterBuf[iBufSize - 1];//右上
//滤波的权值与据本边界两顶点的距离有关
for (i = 1; i < uiCuHeight2; i++)//垂直方向滤波
{
//uiCuHeitht2 = (64-纵坐标)*左上+纵坐标*右上+32
piFilterBufN[i] = ((uiCuHeight2-i)*bottomLeft + i*topLeft + uiCuHeight) >> shift;
}
for (i = 1; i < uiCuWidth2; i++)//水平方向滤波
{
//同上
piFilterBufN[uiCuHeight2 + i] = ((uiCuWidth2-i)*topLeft + i*topRight + uiCuWidth) >> shift;
}
}
else
{
// 1. filtering with [1 2 1],常规滤波
piFilterBufN[0] = piFilterBuf[0];//左下最后一个的参考像素点
piFilterBufN[iBufSize - 1] = piFilterBuf[iBufSize - 1];//右上最后一个
for (i = 1; i < iBufSize - 1; i++)
{
piFilterBufN[i] = (piFilterBuf[i - 1] + 2 * piFilterBuf[i]+piFilterBuf[i + 1] + 2) >> 2;
}
}
}
else
{
//常规滤波,同上,注意代码结构,并非进行两次。
// 1. filtering with [1 2 1]
piFilterBufN[0] = piFilterBuf[0];
piFilterBufN[iBufSize - 1] = piFilterBuf[iBufSize - 1];
for (i = 1; i < iBufSize - 1; i++)
{
piFilterBufN[i] = (piFilterBuf[i - 1] + 2 * piFilterBuf[i]+piFilterBuf[i + 1] + 2) >> 2;
}
}
//滤波后的参考像素复制到piFilteredBuf1中
// fill 1. filter buffer with filtered values
l=0;
for (i = 0; i < uiCuHeight2; i++)//垂直方向,从下到上
{
piFilteredBuf1[uiWidth * (uiCuHeight2 - i)] = piFilterBufN[l++];
}
piFilteredBuf1[0] = piFilterBufN[l++];//左上顶点
for (i = 0; i < uiCuWidth2; i++)//水平方向
{
piFilteredBuf1[1 + i] = piFilterBufN[l++];
}
}
其实这个代码有些细节很有意思,应该设计到可移植性和以后的更新维护,有时间了研究一下。
(转载请务必注明出处)