收集像素块的统计信息
在进行SAO之前,要对像素块的像素值进行归类,然后判断它们属于EO的那个种类或者BO的哪个边带
入口函数getStatistics
getStatistics是收集像素统计信息的入口函数
流程如下:
1、遍历图像的每一个CTU
2、对于每一个CTU,调用deriveLoopFilterBoundaryAvailibility,用来判断相邻CTU的有效性(是否存在)
3、对于每个CTU的每一个颜色分量,调用getBlkStats,用来搜集该CTU中某个分量的像素的统计信息
4、处理结束
/*
** 收集像素块的统计信息,用于判断像素属于EO的那个种类/BO的哪个边带
** 对整个图像进行处理,遍历图像的每一个CTU,对CTU的每一个分量,都调用 getBlkStats
*/
Void TEncSampleAdaptiveOffset::getStatistics(SAOStatData*** blkStats, TComPicYuv* orgYuv, TComPicYuv* srcYuv, TComPic* pPic
#if SAO_ENCODE_ALLOW_USE_PREDEBLOCK
, Bool isCalculatePreDeblockSamples
#endif
)
{
Bool isLeftAvail,isRightAvail,isAboveAvail,isBelowAvail,isAboveLeftAvail,isAboveRightAvail,isBelowLeftAvail,isBelowRightAvail;
for(Int ctu= 0; ctu < m_numCTUsPic; ctu++)
{
Int yPos = (ctu / m_numCTUInWidth)*m_maxCUHeight;
Int xPos = (ctu % m_numCTUInWidth)*m_maxCUWidth;
Int height = (yPos + m_maxCUHeight > m_picHeight)?(m_picHeight- yPos):m_maxCUHeight;
Int width = (xPos + m_maxCUWidth > m_picWidth )?(m_picWidth - xPos):m_maxCUWidth;
// 判断相邻CTU的有效性(是否存在)
pPic->getPicSym()->deriveLoopFilterBoundaryAvailibility(ctu, isLeftAvail,isRightAvail,isAboveAvail,isBelowAvail,isAboveLeftAvail,isAboveRightAvail,isBelowLeftAvail,isBelowRightAvail);
//NOTE: The number of skipped lines during gathering CTU statistics depends on the slice boundary availabilities.
//For simplicity, here only picture boundaries are considered.
isRightAvail = (xPos + m_maxCUWidth < m_picWidth );
isBelowAvail = (yPos + m_maxCUHeight < m_picHeight);
isBelowRightAvail = (isRightAvail && isBelowAvail);
isBelowLeftAvail = ((xPos > 0) && (isBelowAvail));
isAboveRightAvail = ((yPos > 0) && (isRightAvail));
for(Int compIdx=0; compIdx< NUM_SAO_COMPONENTS; compIdx++)
{
Bool isLuma = (compIdx == SAO_Y);
Int formatShift= isLuma?0:1;
Int srcStride = isLuma?srcYuv->getStride():srcYuv->getCStride();
Pel* srcBlk = getPicBuf(srcYuv, compIdx)+ (yPos >> formatShift)*srcStride+ (xPos >> formatShift);
Int orgStride = isLuma?orgYuv->getStride():orgYuv->getCStride();
Pel* orgBlk = getPicBuf(orgYuv, compIdx)+ (yPos >> formatShift)*orgStride+ (xPos >> formatShift);
// 搜集一个CTU中某个分量的像素的统计信息
getBlkStats(compIdx, blkStats[ctu][compIdx]
, srcBlk, orgBlk, srcStride, orgStride, (width >> formatShift), (height >> formatShift)
, isLeftAvail, isRightAvail, isAboveAvail, isBelowAvail, isAboveLeftAvail, isAboveRightAvail, isBelowLeftAvail, isBelowRightAvail
#if SAO_ENCODE_ALLOW_USE_PREDEBLOCK
, isCalculatePreDeblockSamples
#endif
);
}
}
}
判断相邻CTU的有效性
deriveLoopFilterBoundaryAvailibility用于判断相邻CTU的有效性(是否存在),这是为了下一步的像素统计做准备
/*
** 判断相邻CTU的有效性(是否存在)
*/
Void TComPicSym::deriveLoopFilterBoundaryAvailibility(Int ctu,
Bool& isLeftAvail,
Bool& isRightAvail,
Bool& isAboveAvail,
Bool& isBelowAvail,
Bool& isAboveLeftAvail,
Bool& isAboveRightAvail,
Bool& isBelowLeftAvail,
Bool& isBelowRightAvail
)
{
isLeftAvail = (ctu % m_uiWidthInCU != 0);
isRightAvail = (ctu % m_uiWidthInCU != m_uiWidthInCU-1);
isAboveAvail = (ctu >= m_uiWidthInCU );
isBelowAvail = (ctu < m_uiNumCUsInFrame - m_uiWidthInCU);
isAboveLeftAvail = (isAboveAvail && isLeftAvail);
isAboveRightAvail= (isAboveAvail && isRightAvail);
isBelowLeftAvail = (isBelowAvail && isLeftAvail);
isBelowRightAvail= (isBelowAvail && isRightAvail);
Bool isLoopFiltAcrossTilePPS = getCU(ctu)->getSlice()->getPPS()->getLoopFilterAcrossTilesEnabledFlag();
{
TComDataCU* ctuCurr = getCU(ctu);
TComDataCU* ctuLeft = isLeftAvail ?getCU(ctu-1):NULL;
TComDataCU* ctuRight = isRightAvail?getCU(ctu+1):NULL;
TComDataCU* ctuAbove = isAboveAvail?getCU(ctu-m_uiWidthInCU):NULL;
TComDataCU* ctuBelow = isBelowAvail?getCU(ctu+m_uiWidthInCU):NULL;
TComDataCU* ctuAboveLeft = isAboveLeftAvail ? getCU(ctu-m_uiWidthInCU-1):NULL;
TComDataCU* ctuAboveRigtht= isAboveRightAvail? getCU(ctu-m_uiWidthInCU+1):NULL;
TComDataCU* ctuBelowLeft = isBelowLeftAvail ? getCU(ctu+m_uiWidthInCU-1):NULL;
TComDataCU* ctuBelowRight = isBelowRightAvail? getCU(ctu+m_uiWidthInCU+1):NULL;
{
//left
if(ctuLeft != NULL)
{
isLeftAvail = (ctuCurr->getSlice()->getSliceCurStartCUAddr() != ctuLeft->getSlice()->getSliceCurStartCUAddr())?ctuCurr->getSlice()->getLFCrossSliceBoundaryFlag():true;
}
//above
if(ctuAbove != NULL)
{
isAboveAvail = (ctuCurr->getSlice()->getSliceCurStartCUAddr() != ctuAbove->getSlice()->getSliceCurStartCUAddr())?ctuCurr->getSlice()->getLFCrossSliceBoundaryFlag():true;
}
//right
if(ctuRight != NULL)
{
isRightAvail = (ctuCurr->getSlice()->getSliceCurStartCUAddr() != ctuRight->getSlice()->getSliceCurStartCUAddr())?ctuRight->getSlice()->getLFCrossSliceBoundaryFlag():true;
}
//below
if(ctuBelow != NULL)
{
isBelowAvail = (ctuCurr->getSlice()->getSliceCurStartCUAddr() != ctuBelow->getSlice()->getSliceCurStartCUAddr())?ctuBelow->getSlice()->getLFCrossSliceBoundaryFlag():true;
}
//above-left
if(ctuAboveLeft != NULL)
{
isAboveLeftAvail = (ctuCurr->getSlice()->getSliceCurStartCUAddr() != ctuAboveLeft->getSlice()->getSliceCurStartCUAddr())?ctuCurr->getSlice()->getLFCrossSliceBoundaryFlag():true;
}
//below-right
if(ctuBelowRight != NULL)
{
isBelowRightAvail = (ctuCurr->getSlice()->getSliceCurStartCUAddr() != ctuBelowRight->getSlice()->getSliceCurStartCUAddr())?ctuBelowRight->getSlice()->getLFCrossSliceBoundaryFlag():true;
}
//above-right
if(ctuAboveRigtht != NULL)
{
Int curSliceStartEncOrder = ctuCurr->getSlice()->getSliceCurStartCUAddr();
Int aboveRigthtSliceStartEncOrder = ctuAboveRigtht->getSlice()->getSliceCurStartCUAddr();
isAboveRightAvail = (curSliceStartEncOrder == aboveRigthtSliceStartEncOrder)?(true):
(
(curSliceStartEncOrder > aboveRigthtSliceStartEncOrder)?(ctuCurr->getSlice()->getLFCrossSliceBoundaryFlag())
:(ctuAboveRigtht->getSlice()->getLFCrossSliceBoundaryFlag())
);
}
//below-left
if(ctuBelowLeft != NULL)
{
Int curSliceStartEncOrder = ctuCurr->getSlice()->getSliceCurStartCUAddr();
Int belowLeftSliceStartEncOrder = ctuBelowLeft->getSlice()->getSliceCurStartCUAddr();
isBelowLeftAvail = (curSliceStartEncOrder == belowLeftSliceStartEncOrder)?(true):
(
(curSliceStartEncOrder > belowLeftSliceStartEncOrder)?(ctuCurr->getSlice()->getLFCrossSliceBoundaryFlag())
:(ctuBelowLeft->getSlice()->getLFCrossSliceBoundaryFlag())
);
}
}
if(!isLoopFiltAcrossTilePPS)
{
isLeftAvail = (!isLeftAvail ) ?false:(getTileIdxMap( ctuLeft->getAddr() ) == getTileIdxMap( ctu ));
isAboveAvail = (!isAboveAvail ) ?false:(getTileIdxMap( ctuAbove->getAddr() ) == getTileIdxMap( ctu ));
isRightAvail = (!isRightAvail ) ?false:(getTileIdxMap( ctuRight->getAddr() ) == getTileIdxMap( ctu ));
isBelowAvail = (!isBelowAvail ) ?false:(getTileIdxMap( ctuBelow->getAddr() ) == getTileIdxMap( ctu ));
isAboveLeftAvail = (!isAboveLeftAvail ) ?false:(getTileIdxMap( ctuAboveLeft->getAddr() ) == getTileIdxMap( ctu ));
isAboveRightAvail= (!isAboveRightAvail) ?false:(getTileIdxMap( ctuAboveRigtht->getAddr() ) == getTileIdxMap( ctu ));
isBelowLeftAvail = (!isBelowLeftAvail ) ?false:(getTileIdxMap( ctuBelowLeft->getAddr() ) == getTileIdxMap( ctu ));
isBelowRightAvail= (!isBelowRightAvail) ?false:(getTileIdxMap( ctuBelowRight->getAddr() ) == getTileIdxMap( ctu ));
}
}
}
搜集一个CTU分量的像素的统计信息
getBlkStats用来搜集一个CTU中某个分量的像素的统计信息
流程如下:
1、遍历SAO除了merge之外的所有模式:SAO_TYPE_EO_0、SAO_TYPE_EO_90、SAO_TYPE_EO_135、SAO_TYPE_EO_45、SAO_TYPE_BO
2、对于每一个SAO模式,都统计该模式下像素的信息
3、最后的统计信息存放在SAOStatData中
/*
** 搜集一个CTU中某个分量的像素的统计信息
** 遍历SAO除了merge之外的所有类型:
** SAO_TYPE_EO_0 ,
** SAO_TYPE_EO_90,
** SAO_TYPE_EO_135,
** SAO_TYPE_EO_45,
** SAO_TYPE_BO
** 对于每一种类型,都搜集像素的统计信息
** 最后的统计信息存放在SAOStatData中
*/
Void TEncSampleAdaptiveOffset::getBlkStats(Int compIdx, SAOStatData* statsDataTypes
, Pel* srcBlk, Pel* orgBlk, Int srcStride, Int orgStride, Int width, Int height
, Bool isLeftAvail, Bool isRightAvail, Bool isAboveAvail, Bool isBelowAvail, Bool isAboveLeftAvail, Bool isAboveRightAvail, Bool isBelowLeftAvail, Bool isBelowRightAvail
#if SAO_ENCODE_ALLOW_USE_PREDEBLOCK
, Bool isCalculatePreDeblockSamples
#endif
)
{
if(m_lineBufWidth != m_maxCUWidth)
{
m_lineBufWidth = m_maxCUWidth;
if (m_signLineBuf1) delete[] m_signLineBuf1; m_signLineBuf1 = NULL;
m_signLineBuf1 = new Char[m_lineBufWidth+1];
if (m_signLineBuf2) delete[] m_signLineBuf2; m_signLineBuf2 = NULL;
m_signLineBuf2 = new Char[m_lineBufWidth+1];
}
Int x,y, startX, startY, endX, endY, edgeType, firstLineStartX, firstLineEndX;
Char signLeft, signRight, signDown;
Int64 *diff, *count;
Pel *srcLine, *orgLine;
Int* skipLinesR = m_skipLinesR[compIdx];
Int* skipLinesB = m_skipLinesB[compIdx];
for(Int typeIdx=0; typeIdx< NUM_SAO_NEW_TYPES; typeIdx++)
{
SAOStatData& statsData= statsDataTypes[typeIdx];
statsData.reset();
srcLine = srcBlk;
orgLine = orgBlk;
diff = statsData.diff;
count = statsData.count;
switch(typeIdx)
{
case SAO_TYPE_EO_0:
{
diff +=2;
count+=2;
endY = (isBelowAvail) ? (height - skipLinesB[typeIdx]) : height;
#if SAO_ENCODE_ALLOW_USE_PREDEBLOCK
startX = (!isCalculatePreDeblockSamples) ? (isLeftAvail ? 0 : 1)
: (isRightAvail ? (width - skipLinesR[typeIdx]) : (width - 1))
;
#else
startX = isLeftAvail ? 0 : 1;
#endif
#if SAO_ENCODE_ALLOW_USE_PREDEBLOCK
endX = (!isCalculatePreDeblockSamples) ? (isRightAvail ? (width - skipLinesR[typeIdx]) : (width - 1))
: (isRightAvail ? width : (width - 1))
;
#else
endX = isRightAvail ? (width - skipLinesR[typeIdx]): (width - 1);
#endif
for (y=0; y<endY; y++)
{
#if SAO_SGN_FUNC
signLeft = (Char)sgn(srcLine[startX] - srcLine[startX-1]);
#else
signLeft = (Char)m_sign[srcLine[startX] - srcLine[startX-1]];
#endif
for (x=startX; x<endX; x++)
{
#if SAO_SGN_FUNC
signRight = (Char)sgn(srcLine[x] - srcLine[x+1]);
#else
signRight = (Char)m_sign[srcLine[x] - srcLine[x+1]];
#endif
edgeType = signRight + signLeft;
signLeft = -signRight;
diff [edgeType] += (orgLine[x] - srcLine[x]);
count[edgeType] ++;
}
srcLine += srcStride;
orgLine += orgStride;
}
#if SAO_ENCODE_ALLOW_USE_PREDEBLOCK
if(isCalculatePreDeblockSamples)
{
if(isBelowAvail)
{
startX = isLeftAvail ? 0 : 1;
endX = isRightAvail ? width : (width -1);
for(y=0; y<skipLinesB[typeIdx]; y++)
{
#if SAO_SGN_FUNC
signLeft = (Char)sgn(srcLine[startX] - srcLine[startX-1]);
#else
signLeft = (Char)m_sign[srcLine[startX] - srcLine[startX-1]];
#endif
for (x=startX; x<endX; x++)
{
#if SAO_SGN_FUNC
signRight = (Char)sgn(srcLine[x] - srcLine[x+1]);
#else
signRight = (Char)m_sign[srcLine[x] - srcLine[x+1]];
#endif
edgeType = signRight + signLeft;
signLeft = -signRight;
diff [edgeType] += (orgLine[x] - srcLine[x]);
count[edgeType] ++;
}
srcLine += srcStride;
orgLine += orgStride;
}
}
}
#endif
}
break;
case SAO_TYPE_EO_90:
// 代码省略...
break;
case SAO_TYPE_EO_135:
// 代码省略...
break;
case SAO_TYPE_EO_45:
// 代码省略...
break;
case SAO_TYPE_BO:
// 代码省略...
break;
default:
{
printf("Not a supported SAO types\n");
assert(0);
exit(-1);
}
}
}
}