/** 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<NDBFBlockInfo>& 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<endY; y++) { for (x=0; x< width; x++) { signDown = xSign(pRec[x] - pRec[x+stride]); //!< 取 p - n1 的符号 edgeType = signDown + m_iUpBuff1[x] + 2; m_iUpBuff1[x] = -signDown; //!< -signDown相当于是下一行的 p - n0 的符号,保存下来 stats[m_auiEoTable[edgeType]] += (pOrg[x] - pRec[x]); count[m_auiEoTable[edgeType]] ++; } pOrg += stride; pRec += stride; } //---------- Edge offset 2--------------// stats = ppStats[SAO_EO_2]; count = ppCount[SAO_EO_2]; pOrg = pOrgStart; pRec = pRecStart; posShift= stride + 1; startX = (pbBorderAvail[SGU_L]) ? 0 : 1 ; endX = (pbBorderAvail[SGU_R]) ? width : (width-1); //prepare 2nd line upper sign pRec += stride; for (x=startX; x< endX+1; x++) //!< 先计算第二行的 p - n0 的符号,并保存下来 { m_iUpBuff1[x] = xSign(pRec[x] - pRec[x- posShift]); } //1st line pRec -= stride; //!< 回到第一行 if(pbBorderAvail[SGU_TL]) //!< Top Left available { x= 0; edgeType = xSign(pRec[x] - pRec[x- posShift]) - m_iUpBuff1[x+1] + 2; //!< -m_iUpBuff1[x+1]是因为第二行的p - n0相当于第一行的n1 - p,且第二行的x+1的位置才是第一行的x位置 stats[m_auiEoTable[edgeType]] += (pOrg[x] - pRec[x]); count[m_auiEoTable[edgeType]] ++; } if(pbBorderAvail[SGU_T]) //!< Top available { for(x= 1; x< endX; x++) { edgeType = xSign(pRec[x] - pRec[x- posShift]) - m_iUpBuff1[x+1] + 2; stats[m_auiEoTable[edgeType]] += (pOrg[x] - pRec[x]); count[m_auiEoTable[edgeType]] ++; } } pRec += stride; pOrg += stride; //middle lines for (y= 1; y< height-1; y++) //!< 除了第一行和最后一行的行 { for (x=startX; x<endX; x++) { signDown1 = xSign(pRec[x] - pRec[x+ posShift]) ; //!< 取 p - n1 的符号 edgeType = signDown1 + m_iUpBuff1[x] + 2; //!< 此时m_iUpBuff1[x]正好就是p - n0 的符号 stats[m_auiEoTable[edgeType]] += (pOrg[x] - pRec[x]); count[m_auiEoTable[edgeType]] ++; m_iUpBufft[x+1] = -signDown1; //!< 当前行的p - n1相当于下一行的p - n0 的相反数,且当前行的x,对应于下一行的x+1 } m_iUpBufft[startX] = xSign(pRec[stride+startX] - pRec[startX-1]); //!< 取startX位置的p - n0的符号 //!< m_iUpBuff1与m_iUpBufft交换,交换完成后,m_iUpBuff1将保存的是下一行的p - n0的符号 ipSwap = m_iUpBuff1; m_iUpBuff1 = m_iUpBufft; m_iUpBufft = ipSwap; pRec += stride; pOrg += stride; } //last line if(pbBorderAvail[SGU_B]) //!< 最后一行,Bottom available { for(x= startX; x< width-1; x++) { edgeType = xSign(pRec[x] - pRec[x+ posShift]) + m_iUpBuff1[x] + 2; //!< 此时m_iUpBuff1保存的就是最后一行的p - n0的符号 stats[m_auiEoTable[edgeType]] += (pOrg[x] - pRec[x]); count[m_auiEoTable[edgeType]] ++; } } if(pbBorderAvail[SGU_BR]) //!< Bottom Right available { x= width -1; edgeType = xSign(pRec[x] - pRec[x+ posShift]) + m_iUpBuff1[x] + 2; stats[m_auiEoTable[edgeType]] += (pOrg[x] - pRec[x]); count[m_auiEoTable[edgeType]] ++; } //---------- Edge offset 3--------------// stats = ppStats[SAO_EO_3]; count = ppCount[SAO_EO_3]; pOrg = pOrgStart; pRec = pRecStart; posShift = stride - 1; startX = (pbBorderAvail[SGU_L]) ? 0 : 1; endX = (pbBorderAvail[SGU_R]) ? width : (width -1); //prepare 2nd line upper sign pRec += stride; for (x=startX-1; x< endX; x++) //!< 先算第二行的p - n0的符号并保存到m_iUpBuff1中 { m_iUpBuff1[x] = xSign(pRec[x] - pRec[x- posShift]); } //first line pRec -= stride; //!< 回到第一行 if(pbBorderAvail[SGU_T]) //!< Top available { for(x= startX; x< width -1; x++) { edgeType = xSign(pRec[x] - pRec[x- posShift]) -m_iUpBuff1[x-1] + 2;//!< -m_iUpBuff1[x-1]是因为第二行的p - n0相当于第一行的n1 - p,且第二行的x-1的位置才是第一行的x位置 stats[m_auiEoTable[edgeType]] += (pOrg[x] - pRec[x]); count[m_auiEoTable[edgeType]] ++; } } if(pbBorderAvail[SGU_TR]) //!< Top Right available { x= width-1; edgeType = xSign(pRec[x] - pRec[x- posShift]) -m_iUpBuff1[x-1] + 2; stats[m_auiEoTable[edgeType]] += (pOrg[x] - pRec[x]); count[m_auiEoTable[edgeType]] ++; } pRec += stride; pOrg += stride; //middle lines for (y= 1; y< height-1; y++) //!< 除第一行和最后一行的行 { for(x= startX; x< endX; x++) { signDown1 = xSign(pRec[x] - pRec[x+ posShift]) ; edgeType = signDown1 + m_iUpBuff1[x] + 2; //!< 此时m_iUpBuff1就是当前行的p - n0的符号 stats[m_auiEoTable[edgeType]] += (pOrg[x] - pRec[x]); count[m_auiEoTable[edgeType]] ++; m_iUpBuff1[x-1] = -signDown1; //!< 当前行的p - n1相当于下一行的p - n0 的相反数,且当前行的x,对应于下一行的x-1 } m_iUpBuff1[endX-1] = xSign(pRec[endX-1 + stride] - pRec[endX]); //!< 保存下一行endX-1处的p - n0的符号 pRec += stride; pOrg += stride; } //last line if(pbBorderAvail[SGU_BL]) //!< Bottom Left available { x= 0; edgeType = xSign(pRec[x] - pRec[x+ posShift]) + m_iUpBuff1[x] + 2; //!< 此时m_iUpBuff1正好保存的是最后一行的x位置的p - n0的符号 stats[m_auiEoTable[edgeType]] += (pOrg[x] - pRec[x]); count[m_auiEoTable[edgeType]] ++; } if(pbBorderAvail[SGU_B]) //!< Bottom available { for(x= 1; x< endX; x++) { edgeType = xSign(pRec[x] - pRec[x+ posShift]) + m_iUpBuff1[x] + 2; stats[m_auiEoTable[edgeType]] += (pOrg[x] - pRec[x]); count[m_auiEoTable[edgeType]] ++; } } }