/** Calculate SAO statistics for current LCU
* \param iAddr, iPartIdx, iYCbCr
*/
Void TEncSampleAdaptiveOffset::calcSaoStatsCu(Int iAddr, Int iPartIdx, Int iYCbCr)
{
if(!m_bUseNIF) //!< true for performing non-cross slice boundary ALF
{
calcSaoStatsCuOrg( iAddr, iPartIdx, iYCbCr);
}
else
{
Int64** ppStats = m_iOffsetOrg[iPartIdx]; //!< [MAX_NUM_SAO_PART][MAX_NUM_SAO_TYPE][MAX_NUM_SAO_CLASS] ??
Int64** ppCount = m_iCount [iPartIdx]; //!< [MAX_NUM_SAO_PART][MAX_NUM_SAO_TYPE][MAX_NUM_SAO_CLASS]
//parameters
Int isChroma = (iYCbCr != 0)? 1:0;
Int stride = (iYCbCr != 0)?(m_pcPic->getCStride()):(m_pcPic->getStride());
Pel* pPicOrg = getPicYuvAddr (m_pcPic->getPicYuvOrg(), iYCbCr);
Pel* pPicRec = getPicYuvAddr(m_pcYuvTmp, iYCbCr);
std::vector& vFilterBlocks = *(m_pcPic->getCU(iAddr)->getNDBFilterBlocks());
//variables
UInt xPos, yPos, width, height;
Bool* pbBorderAvail;
UInt posOffset;
for(Int i=0; i< vFilterBlocks.size(); i++)
{
xPos = vFilterBlocks[i].posX >> isChroma;
yPos = vFilterBlocks[i].posY >> isChroma;
width = vFilterBlocks[i].width >> isChroma;
height = vFilterBlocks[i].height >> isChroma;
pbBorderAvail = vFilterBlocks[i].isBorderAvailable;
posOffset = (yPos* stride) + xPos;
//! 对ppStats,ppCount赋值,分别计算出对应滤波模式下原始像素与重建像素之间的差值,重建值对应的classIdx的统计值
calcSaoStatsBlock(pPicRec+ posOffset, pPicOrg+ posOffset, stride, ppStats, ppCount,width, height, pbBorderAvail, iYCbCr);
}
}
}
/** Calculate SAO statistics for non-cross-slice or non-cross-tile processing
* \param pRecStart to-be-filtered block buffer pointer
* \param pOrgStart original block buffer pointer
* \param stride picture buffer stride
* \param ppStat statistics buffer
* \param ppCount counter buffer
* \param width block width
* \param height block height
* \param pbBorderAvail availabilities of block border pixels
*/
Void TEncSampleAdaptiveOffset::calcSaoStatsBlock( Pel* pRecStart, Pel* pOrgStart, Int stride, Int64** ppStats, Int64** ppCount, UInt width, UInt height, Bool* pbBorderAvail, Int iYCbCr)
{
Int64 *stats, *count;
Int classIdx, posShift, startX, endX, startY, endY, signLeft,signRight,signDown,signDown1;
Pel *pOrg, *pRec;
UInt edgeType;
Int x, y;
Pel *pTableBo = (iYCbCr==0)?m_lumaTableBo:m_chromaTableBo; //!< band offset 的索引表,共32个bands
//--------- Band offset-----------//
stats = ppStats[SAO_BO];
count = ppCount[SAO_BO];
pOrg = pOrgStart;
pRec = pRecStart;
for (y=0; y< height; y++)
{
for (x=0; x< width; x++)
{
classIdx = pTableBo[pRec[x]]; //!< classIdx即查表得到的band对应的序号值(1~32)
if (classIdx)
{
stats[classIdx] += (pOrg[x] - pRec[x]); //!< 对原始像素与重建像素的差值求和
count[classIdx] ++; //!< 对应classIdx的统计值加1
}
}
pOrg += stride;
pRec += stride;
}
//---------- Edge offset 0--------------//
stats = ppStats[SAO_EO_0];
count = ppCount[SAO_EO_0];
pOrg = pOrgStart;
pRec = pRecStart;
//!< 设置起始点和终点
startX = (pbBorderAvail[SGU_L]) ? 0 : 1;
endX = (pbBorderAvail[SGU_R]) ? width : (width -1);
for (y=0; y< height; y++)
{
signLeft = xSign(pRec[startX] - pRec[startX-1]); //!< 取 p - n0 的符号
for (x=startX; x< endX; x++)
{
signRight = xSign(pRec[x] - pRec[x+1]); //!< 取 p - n1 的符号
edgeType = signRight + signLeft + 2; //!< 计算符号类型,用于下面通过查表的方式确定EdgeIdx
signLeft = -signRight;
/*
const UInt TComSampleAdaptiveOffset::m_auiEoTable[9] =
{
1, //0
2, //1
0, //2
3, //3
4, //4
0, //5
0, //6
0, //7
0
};
*/
stats[m_auiEoTable[edgeType]] += (pOrg[x] - pRec[x]); //!< 通过查表可以确定出真正的EdgeIdx,从而把统计值保存到对应的类型中去
count[m_auiEoTable[edgeType]] ++;
}
pRec += stride;
pOrg += stride;
}
//---------- Edge offset 1--------------//
stats = ppStats[SAO_EO_1];
count = ppCount[SAO_EO_1];
pOrg = pOrgStart;
pRec = pRecStart;
startY = (pbBorderAvail[SGU_T]) ? 0 : 1;
endY = (pbBorderAvail[SGU_B]) ? height : height-1;
if (!pbBorderAvail[SGU_T]) //!< 如果上邻行不可用,则下移一行
{
pRec += stride;
pOrg += stride;
}
for (x=0; x< width; x++) //!< 先计算第一行与其上一行的差值
{
m_iUpBuff1[x] = xSign(pRec[x] - pRec[x-stride]); //!< 保存整一行 p - n0 的符号
}
for (y=startY; y