725 lines
22 KiB
C++
725 lines
22 KiB
C++
|
/* The copyright in this software is being made available under the BSD
|
||
|
* License, included below. This software may be subject to other third party
|
||
|
* and contributor rights, including patent rights, and no such rights are
|
||
|
* granted under this license.
|
||
|
*
|
||
|
* Copyright (c) 2010-2014, ITU/ISO/IEC
|
||
|
* All rights reserved.
|
||
|
*
|
||
|
* Redistribution and use in source and binary forms, with or without
|
||
|
* modification, are permitted provided that the following conditions are met:
|
||
|
*
|
||
|
* * Redistributions of source code must retain the above copyright notice,
|
||
|
* this list of conditions and the following disclaimer.
|
||
|
* * Redistributions in binary form must reproduce the above copyright notice,
|
||
|
* this list of conditions and the following disclaimer in the documentation
|
||
|
* and/or other materials provided with the distribution.
|
||
|
* * Neither the name of the ITU/ISO/IEC nor the names of its contributors may
|
||
|
* be used to endorse or promote products derived from this software without
|
||
|
* specific prior written permission.
|
||
|
*
|
||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
|
||
|
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||
|
* THE POSSIBILITY OF SUCH DAMAGE.
|
||
|
*/
|
||
|
|
||
|
/** \file TComSampleAdaptiveOffset.cpp
|
||
|
\brief sample adaptive offset class
|
||
|
*/
|
||
|
|
||
|
#include "TComSampleAdaptiveOffset.h"
|
||
|
#include <string.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <stdio.h>
|
||
|
#include <math.h>
|
||
|
|
||
|
//! \ingroup TLibCommon
|
||
|
//! \{
|
||
|
|
||
|
UInt g_saoMaxOffsetQVal[MAX_NUM_COMPONENT];
|
||
|
|
||
|
SAOOffset::SAOOffset()
|
||
|
{
|
||
|
reset();
|
||
|
}
|
||
|
|
||
|
SAOOffset::~SAOOffset()
|
||
|
{
|
||
|
|
||
|
}
|
||
|
|
||
|
Void SAOOffset::reset()
|
||
|
{
|
||
|
modeIdc = SAO_MODE_OFF;
|
||
|
typeIdc = -1;
|
||
|
typeAuxInfo = -1;
|
||
|
::memset(offset, 0, sizeof(Int)* MAX_NUM_SAO_CLASSES);
|
||
|
}
|
||
|
|
||
|
const SAOOffset& SAOOffset::operator= (const SAOOffset& src)
|
||
|
{
|
||
|
modeIdc = src.modeIdc;
|
||
|
typeIdc = src.typeIdc;
|
||
|
typeAuxInfo = src.typeAuxInfo;
|
||
|
::memcpy(offset, src.offset, sizeof(Int)* MAX_NUM_SAO_CLASSES);
|
||
|
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
|
||
|
SAOBlkParam::SAOBlkParam()
|
||
|
{
|
||
|
reset();
|
||
|
}
|
||
|
|
||
|
SAOBlkParam::~SAOBlkParam()
|
||
|
{
|
||
|
|
||
|
}
|
||
|
|
||
|
Void SAOBlkParam::reset()
|
||
|
{
|
||
|
for(Int compIdx = 0; compIdx < MAX_NUM_COMPONENT; compIdx++)
|
||
|
{
|
||
|
offsetParam[compIdx].reset();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
const SAOBlkParam& SAOBlkParam::operator= (const SAOBlkParam& src)
|
||
|
{
|
||
|
for(Int compIdx = 0; compIdx < MAX_NUM_COMPONENT; compIdx++)
|
||
|
{
|
||
|
offsetParam[compIdx] = src.offsetParam[compIdx];
|
||
|
}
|
||
|
return *this;
|
||
|
|
||
|
}
|
||
|
|
||
|
TComSampleAdaptiveOffset::TComSampleAdaptiveOffset()
|
||
|
{
|
||
|
m_tempPicYuv = NULL;
|
||
|
m_lineBufWidth = 0;
|
||
|
m_signLineBuf1 = NULL;
|
||
|
m_signLineBuf2 = NULL;
|
||
|
}
|
||
|
|
||
|
|
||
|
TComSampleAdaptiveOffset::~TComSampleAdaptiveOffset()
|
||
|
{
|
||
|
destroy();
|
||
|
|
||
|
if (m_signLineBuf1) delete[] m_signLineBuf1; m_signLineBuf1 = NULL;
|
||
|
if (m_signLineBuf2) delete[] m_signLineBuf2; m_signLineBuf2 = NULL;
|
||
|
}
|
||
|
|
||
|
Void TComSampleAdaptiveOffset::create( Int picWidth, Int picHeight, ChromaFormat format, UInt maxCUWidth, UInt maxCUHeight, UInt maxCUDepth, UInt lumaBitShift, UInt chromaBitShift )
|
||
|
{
|
||
|
destroy();
|
||
|
|
||
|
m_picWidth = picWidth;
|
||
|
m_picHeight = picHeight;
|
||
|
m_chromaFormatIDC = format;
|
||
|
m_maxCUWidth = maxCUWidth;
|
||
|
m_maxCUHeight = maxCUHeight;
|
||
|
|
||
|
m_numCTUInWidth = (m_picWidth/m_maxCUWidth) + ((m_picWidth % m_maxCUWidth)?1:0);
|
||
|
m_numCTUInHeight = (m_picHeight/m_maxCUHeight) + ((m_picHeight % m_maxCUHeight)?1:0);
|
||
|
m_numCTUsPic = m_numCTUInHeight*m_numCTUInWidth;
|
||
|
|
||
|
//temporary picture buffer
|
||
|
if ( !m_tempPicYuv )
|
||
|
{
|
||
|
m_tempPicYuv = new TComPicYuv;
|
||
|
m_tempPicYuv->create( m_picWidth, m_picHeight, m_chromaFormatIDC, m_maxCUWidth, m_maxCUHeight, maxCUDepth );
|
||
|
}
|
||
|
|
||
|
//bit-depth related
|
||
|
for(Int compIdx = 0; compIdx < MAX_NUM_COMPONENT; compIdx++)
|
||
|
{
|
||
|
Int bitDepthSample = g_bitDepth[toChannelType(ComponentID(compIdx))];
|
||
|
m_offsetStepLog2 [compIdx] = isLuma(ComponentID(compIdx))? lumaBitShift : chromaBitShift;
|
||
|
g_saoMaxOffsetQVal[compIdx] = (1<<(min(bitDepthSample,MAX_SAO_TRUNCATED_BITDEPTH)-5))-1; //Table 9-32, inclusive
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Void TComSampleAdaptiveOffset::destroy()
|
||
|
{
|
||
|
if ( m_tempPicYuv )
|
||
|
{
|
||
|
m_tempPicYuv->destroy();
|
||
|
delete m_tempPicYuv;
|
||
|
m_tempPicYuv = NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Void TComSampleAdaptiveOffset::invertQuantOffsets(ComponentID compIdx, Int typeIdc, Int typeAuxInfo, Int* dstOffsets, Int* srcOffsets)
|
||
|
{
|
||
|
Int codedOffset[MAX_NUM_SAO_CLASSES];
|
||
|
|
||
|
::memcpy(codedOffset, srcOffsets, sizeof(Int)*MAX_NUM_SAO_CLASSES);
|
||
|
::memset(dstOffsets, 0, sizeof(Int)*MAX_NUM_SAO_CLASSES);
|
||
|
|
||
|
if(typeIdc == SAO_TYPE_START_BO)
|
||
|
{
|
||
|
for(Int i=0; i< 4; i++)
|
||
|
{
|
||
|
dstOffsets[(typeAuxInfo+ i)%NUM_SAO_BO_CLASSES] = codedOffset[(typeAuxInfo+ i)%NUM_SAO_BO_CLASSES]*(1<<m_offsetStepLog2[compIdx]);
|
||
|
}
|
||
|
}
|
||
|
else //EO
|
||
|
{
|
||
|
for(Int i=0; i< NUM_SAO_EO_CLASSES; i++)
|
||
|
{
|
||
|
dstOffsets[i] = codedOffset[i] *(1<<m_offsetStepLog2[compIdx]);
|
||
|
}
|
||
|
assert(dstOffsets[SAO_CLASS_EO_PLAIN] == 0); //keep EO plain offset as zero
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
Int TComSampleAdaptiveOffset::getMergeList(TComPic* pic, Int ctuRsAddr, SAOBlkParam* blkParams, SAOBlkParam* mergeList[NUM_SAO_MERGE_TYPES])
|
||
|
{
|
||
|
Int ctuX = ctuRsAddr % m_numCTUInWidth;
|
||
|
Int ctuY = ctuRsAddr / m_numCTUInWidth;
|
||
|
Int mergedCTUPos;
|
||
|
Int numValidMergeCandidates = 0;
|
||
|
|
||
|
for(Int mergeType=0; mergeType< NUM_SAO_MERGE_TYPES; mergeType++)
|
||
|
{
|
||
|
SAOBlkParam* mergeCandidate = NULL;
|
||
|
|
||
|
switch(mergeType)
|
||
|
{
|
||
|
case SAO_MERGE_ABOVE:
|
||
|
{
|
||
|
if(ctuY > 0)
|
||
|
{
|
||
|
mergedCTUPos = ctuRsAddr- m_numCTUInWidth;
|
||
|
if( pic->getSAOMergeAvailability(ctuRsAddr, mergedCTUPos) )
|
||
|
{
|
||
|
mergeCandidate = &(blkParams[mergedCTUPos]);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case SAO_MERGE_LEFT:
|
||
|
{
|
||
|
if(ctuX > 0)
|
||
|
{
|
||
|
mergedCTUPos = ctuRsAddr- 1;
|
||
|
if( pic->getSAOMergeAvailability(ctuRsAddr, mergedCTUPos) )
|
||
|
{
|
||
|
mergeCandidate = &(blkParams[mergedCTUPos]);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
default:
|
||
|
{
|
||
|
printf("not a supported merge type");
|
||
|
assert(0);
|
||
|
exit(-1);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
mergeList[mergeType]=mergeCandidate;
|
||
|
if (mergeCandidate != NULL)
|
||
|
{
|
||
|
numValidMergeCandidates++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return numValidMergeCandidates;
|
||
|
}
|
||
|
|
||
|
|
||
|
Void TComSampleAdaptiveOffset::reconstructBlkSAOParam(SAOBlkParam& recParam, SAOBlkParam* mergeList[NUM_SAO_MERGE_TYPES])
|
||
|
{
|
||
|
const Int numberOfComponents = getNumberValidComponents(m_chromaFormatIDC);
|
||
|
for(Int compIdx = 0; compIdx < numberOfComponents; compIdx++)
|
||
|
{
|
||
|
const ComponentID component = ComponentID(compIdx);
|
||
|
SAOOffset& offsetParam = recParam[component];
|
||
|
|
||
|
if(offsetParam.modeIdc == SAO_MODE_OFF)
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
switch(offsetParam.modeIdc)
|
||
|
{
|
||
|
case SAO_MODE_NEW:
|
||
|
{
|
||
|
invertQuantOffsets(component, offsetParam.typeIdc, offsetParam.typeAuxInfo, offsetParam.offset, offsetParam.offset);
|
||
|
}
|
||
|
break;
|
||
|
case SAO_MODE_MERGE:
|
||
|
{
|
||
|
SAOBlkParam* mergeTarget = mergeList[offsetParam.typeIdc];
|
||
|
assert(mergeTarget != NULL);
|
||
|
|
||
|
offsetParam = (*mergeTarget)[component];
|
||
|
}
|
||
|
break;
|
||
|
default:
|
||
|
{
|
||
|
printf("Not a supported mode");
|
||
|
assert(0);
|
||
|
exit(-1);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Void TComSampleAdaptiveOffset::reconstructBlkSAOParams(TComPic* pic, SAOBlkParam* saoBlkParams)
|
||
|
{
|
||
|
for(Int compIdx = 0; compIdx < MAX_NUM_COMPONENT; compIdx++)
|
||
|
{
|
||
|
m_picSAOEnabled[compIdx] = false;
|
||
|
}
|
||
|
|
||
|
const Int numberOfComponents = getNumberValidComponents(m_chromaFormatIDC);
|
||
|
|
||
|
for(Int ctuRsAddr=0; ctuRsAddr< m_numCTUsPic; ctuRsAddr++)
|
||
|
{
|
||
|
SAOBlkParam* mergeList[NUM_SAO_MERGE_TYPES] = { NULL };
|
||
|
getMergeList(pic, ctuRsAddr, saoBlkParams, mergeList);
|
||
|
|
||
|
reconstructBlkSAOParam(saoBlkParams[ctuRsAddr], mergeList);
|
||
|
|
||
|
for(Int compIdx = 0; compIdx < numberOfComponents; compIdx++)
|
||
|
{
|
||
|
if(saoBlkParams[ctuRsAddr][compIdx].modeIdc != SAO_MODE_OFF)
|
||
|
{
|
||
|
m_picSAOEnabled[compIdx] = true;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
Void TComSampleAdaptiveOffset::offsetBlock(ComponentID compIdx, Int typeIdx, Int* offset
|
||
|
, Pel* srcBlk, Pel* resBlk, Int srcStride, Int resStride, Int width, Int height
|
||
|
, Bool isLeftAvail, Bool isRightAvail, Bool isAboveAvail, Bool isBelowAvail, Bool isAboveLeftAvail, Bool isAboveRightAvail, Bool isBelowLeftAvail, Bool isBelowRightAvail)
|
||
|
{
|
||
|
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];
|
||
|
}
|
||
|
|
||
|
const Int maxSampleValueIncl = (1<< g_bitDepth[toChannelType(compIdx)] )-1;
|
||
|
|
||
|
Int x,y, startX, startY, endX, endY, edgeType;
|
||
|
Int firstLineStartX, firstLineEndX, lastLineStartX, lastLineEndX;
|
||
|
Char signLeft, signRight, signDown;
|
||
|
|
||
|
Pel* srcLine = srcBlk;
|
||
|
Pel* resLine = resBlk;
|
||
|
|
||
|
switch(typeIdx)
|
||
|
{
|
||
|
case SAO_TYPE_EO_0:
|
||
|
{
|
||
|
offset += 2;
|
||
|
startX = isLeftAvail ? 0 : 1;
|
||
|
endX = isRightAvail ? width : (width -1);
|
||
|
for (y=0; y< height; y++)
|
||
|
{
|
||
|
signLeft = (Char)sgn(srcLine[startX] - srcLine[startX-1]);
|
||
|
for (x=startX; x< endX; x++)
|
||
|
{
|
||
|
signRight = (Char)sgn(srcLine[x] - srcLine[x+1]);
|
||
|
edgeType = signRight + signLeft;
|
||
|
signLeft = -signRight;
|
||
|
|
||
|
resLine[x] = Clip3<Int>(0, maxSampleValueIncl, srcLine[x] + offset[edgeType]);
|
||
|
}
|
||
|
srcLine += srcStride;
|
||
|
resLine += resStride;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
break;
|
||
|
case SAO_TYPE_EO_90:
|
||
|
{
|
||
|
offset += 2;
|
||
|
Char *signUpLine = m_signLineBuf1;
|
||
|
|
||
|
startY = isAboveAvail ? 0 : 1;
|
||
|
endY = isBelowAvail ? height : height-1;
|
||
|
if (!isAboveAvail)
|
||
|
{
|
||
|
srcLine += srcStride;
|
||
|
resLine += resStride;
|
||
|
}
|
||
|
|
||
|
Pel* srcLineAbove= srcLine- srcStride;
|
||
|
for (x=0; x< width; x++)
|
||
|
{
|
||
|
signUpLine[x] = (Char)sgn(srcLine[x] - srcLineAbove[x]);
|
||
|
}
|
||
|
|
||
|
Pel* srcLineBelow;
|
||
|
for (y=startY; y<endY; y++)
|
||
|
{
|
||
|
srcLineBelow= srcLine+ srcStride;
|
||
|
|
||
|
for (x=0; x< width; x++)
|
||
|
{
|
||
|
signDown = (Char)sgn(srcLine[x] - srcLineBelow[x]);
|
||
|
edgeType = signDown + signUpLine[x];
|
||
|
signUpLine[x]= -signDown;
|
||
|
|
||
|
resLine[x] = Clip3<Int>(0, maxSampleValueIncl, srcLine[x] + offset[edgeType]);
|
||
|
}
|
||
|
srcLine += srcStride;
|
||
|
resLine += resStride;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
break;
|
||
|
case SAO_TYPE_EO_135:
|
||
|
{
|
||
|
offset += 2;
|
||
|
Char *signUpLine, *signDownLine, *signTmpLine;
|
||
|
|
||
|
signUpLine = m_signLineBuf1;
|
||
|
signDownLine= m_signLineBuf2;
|
||
|
|
||
|
startX = isLeftAvail ? 0 : 1 ;
|
||
|
endX = isRightAvail ? width : (width-1);
|
||
|
|
||
|
//prepare 2nd line's upper sign
|
||
|
Pel* srcLineBelow= srcLine+ srcStride;
|
||
|
for (x=startX; x< endX+1; x++)
|
||
|
{
|
||
|
signUpLine[x] = (Char)sgn(srcLineBelow[x] - srcLine[x- 1]);
|
||
|
}
|
||
|
|
||
|
//1st line
|
||
|
Pel* srcLineAbove= srcLine- srcStride;
|
||
|
firstLineStartX = isAboveLeftAvail ? 0 : 1;
|
||
|
firstLineEndX = isAboveAvail? endX: 1;
|
||
|
for(x= firstLineStartX; x< firstLineEndX; x++)
|
||
|
{
|
||
|
edgeType = sgn(srcLine[x] - srcLineAbove[x- 1]) - signUpLine[x+1];
|
||
|
|
||
|
resLine[x] = Clip3<Int>(0, maxSampleValueIncl, srcLine[x] + offset[edgeType]);
|
||
|
}
|
||
|
srcLine += srcStride;
|
||
|
resLine += resStride;
|
||
|
|
||
|
|
||
|
//middle lines
|
||
|
for (y= 1; y< height-1; y++)
|
||
|
{
|
||
|
srcLineBelow= srcLine+ srcStride;
|
||
|
|
||
|
for (x=startX; x<endX; x++)
|
||
|
{
|
||
|
signDown = (Char)sgn(srcLine[x] - srcLineBelow[x+ 1]);
|
||
|
edgeType = signDown + signUpLine[x];
|
||
|
resLine[x] = Clip3<Int>(0, maxSampleValueIncl, srcLine[x] + offset[edgeType]);
|
||
|
|
||
|
signDownLine[x+1] = -signDown;
|
||
|
}
|
||
|
signDownLine[startX] = (Char)sgn(srcLineBelow[startX] - srcLine[startX-1]);
|
||
|
|
||
|
signTmpLine = signUpLine;
|
||
|
signUpLine = signDownLine;
|
||
|
signDownLine = signTmpLine;
|
||
|
|
||
|
srcLine += srcStride;
|
||
|
resLine += resStride;
|
||
|
}
|
||
|
|
||
|
//last line
|
||
|
srcLineBelow= srcLine+ srcStride;
|
||
|
lastLineStartX = isBelowAvail ? startX : (width -1);
|
||
|
lastLineEndX = isBelowRightAvail ? width : (width -1);
|
||
|
for(x= lastLineStartX; x< lastLineEndX; x++)
|
||
|
{
|
||
|
edgeType = sgn(srcLine[x] - srcLineBelow[x+ 1]) + signUpLine[x];
|
||
|
resLine[x] = Clip3<Int>(0, maxSampleValueIncl, srcLine[x] + offset[edgeType]);
|
||
|
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case SAO_TYPE_EO_45:
|
||
|
{
|
||
|
offset += 2;
|
||
|
Char *signUpLine = m_signLineBuf1+1;
|
||
|
|
||
|
startX = isLeftAvail ? 0 : 1;
|
||
|
endX = isRightAvail ? width : (width -1);
|
||
|
|
||
|
//prepare 2nd line upper sign
|
||
|
Pel* srcLineBelow= srcLine+ srcStride;
|
||
|
for (x=startX-1; x< endX; x++)
|
||
|
{
|
||
|
signUpLine[x] = (Char)sgn(srcLineBelow[x] - srcLine[x+1]);
|
||
|
}
|
||
|
|
||
|
|
||
|
//first line
|
||
|
Pel* srcLineAbove= srcLine- srcStride;
|
||
|
firstLineStartX = isAboveAvail ? startX : (width -1 );
|
||
|
firstLineEndX = isAboveRightAvail ? width : (width-1);
|
||
|
for(x= firstLineStartX; x< firstLineEndX; x++)
|
||
|
{
|
||
|
edgeType = sgn(srcLine[x] - srcLineAbove[x+1]) -signUpLine[x-1];
|
||
|
resLine[x] = Clip3<Int>(0, maxSampleValueIncl, srcLine[x] + offset[edgeType]);
|
||
|
}
|
||
|
srcLine += srcStride;
|
||
|
resLine += resStride;
|
||
|
|
||
|
//middle lines
|
||
|
for (y= 1; y< height-1; y++)
|
||
|
{
|
||
|
srcLineBelow= srcLine+ srcStride;
|
||
|
|
||
|
for(x= startX; x< endX; x++)
|
||
|
{
|
||
|
signDown = (Char)sgn(srcLine[x] - srcLineBelow[x-1]);
|
||
|
edgeType = signDown + signUpLine[x];
|
||
|
resLine[x] = Clip3<Int>(0, maxSampleValueIncl, srcLine[x] + offset[edgeType]);
|
||
|
signUpLine[x-1] = -signDown;
|
||
|
}
|
||
|
signUpLine[endX-1] = (Char)sgn(srcLineBelow[endX-1] - srcLine[endX]);
|
||
|
srcLine += srcStride;
|
||
|
resLine += resStride;
|
||
|
}
|
||
|
|
||
|
//last line
|
||
|
srcLineBelow= srcLine+ srcStride;
|
||
|
lastLineStartX = isBelowLeftAvail ? 0 : 1;
|
||
|
lastLineEndX = isBelowAvail ? endX : 1;
|
||
|
for(x= lastLineStartX; x< lastLineEndX; x++)
|
||
|
{
|
||
|
edgeType = sgn(srcLine[x] - srcLineBelow[x-1]) + signUpLine[x];
|
||
|
resLine[x] = Clip3<Int>(0, maxSampleValueIncl, srcLine[x] + offset[edgeType]);
|
||
|
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case SAO_TYPE_BO:
|
||
|
{
|
||
|
const Int shiftBits = g_bitDepth[toChannelType(compIdx)] - NUM_SAO_BO_CLASSES_LOG2;
|
||
|
for (y=0; y< height; y++)
|
||
|
{
|
||
|
for (x=0; x< width; x++)
|
||
|
{
|
||
|
resLine[x] = Clip3<Int>(0, maxSampleValueIncl, srcLine[x] + offset[srcLine[x] >> shiftBits] );
|
||
|
}
|
||
|
srcLine += srcStride;
|
||
|
resLine += resStride;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
default:
|
||
|
{
|
||
|
printf("Not a supported SAO types\n");
|
||
|
assert(0);
|
||
|
exit(-1);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Void TComSampleAdaptiveOffset::offsetCTU(Int ctuRsAddr, TComPicYuv* srcYuv, TComPicYuv* resYuv, SAOBlkParam& saoblkParam, TComPic* pPic)
|
||
|
{
|
||
|
Bool isLeftAvail,isRightAvail,isAboveAvail,isBelowAvail,isAboveLeftAvail,isAboveRightAvail,isBelowLeftAvail,isBelowRightAvail;
|
||
|
|
||
|
const Int numberOfComponents = getNumberValidComponents(m_chromaFormatIDC);
|
||
|
Bool bAllOff=true;
|
||
|
for(Int compIdx = 0; compIdx < numberOfComponents; compIdx++)
|
||
|
{
|
||
|
if (saoblkParam[compIdx].modeIdc != SAO_MODE_OFF) bAllOff=false;
|
||
|
}
|
||
|
if (bAllOff) return;
|
||
|
|
||
|
//block boundary availability
|
||
|
pPic->getPicSym()->deriveLoopFilterBoundaryAvailibility(ctuRsAddr, isLeftAvail,isRightAvail,isAboveAvail,isBelowAvail,isAboveLeftAvail,isAboveRightAvail,isBelowLeftAvail,isBelowRightAvail);
|
||
|
|
||
|
Int yPos = (ctuRsAddr / m_numCTUInWidth)*m_maxCUHeight;
|
||
|
Int xPos = (ctuRsAddr % 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;
|
||
|
|
||
|
for(Int compIdx = 0; compIdx < numberOfComponents; compIdx++)
|
||
|
{
|
||
|
const ComponentID component = ComponentID(compIdx);
|
||
|
SAOOffset& ctbOffset = saoblkParam[compIdx];
|
||
|
|
||
|
if(ctbOffset.modeIdc != SAO_MODE_OFF)
|
||
|
{
|
||
|
const UInt componentScaleX = getComponentScaleX(component, pPic->getChromaFormat());
|
||
|
const UInt componentScaleY = getComponentScaleY(component, pPic->getChromaFormat());
|
||
|
|
||
|
Int blkWidth = (width >> componentScaleX);
|
||
|
Int blkHeight = (height >> componentScaleY);
|
||
|
Int blkXPos = (xPos >> componentScaleX);
|
||
|
Int blkYPos = (yPos >> componentScaleY);
|
||
|
|
||
|
Int srcStride = srcYuv->getStride(component);
|
||
|
Pel* srcBlk = srcYuv->getAddr(component) + blkYPos*srcStride + blkXPos;
|
||
|
|
||
|
Int resStride = resYuv->getStride(component);
|
||
|
Pel* resBlk = resYuv->getAddr(component) + blkYPos*resStride + blkXPos;
|
||
|
|
||
|
offsetBlock( component, ctbOffset.typeIdc, ctbOffset.offset
|
||
|
, srcBlk, resBlk, srcStride, resStride, blkWidth, blkHeight
|
||
|
, isLeftAvail, isRightAvail
|
||
|
, isAboveAvail, isBelowAvail
|
||
|
, isAboveLeftAvail, isAboveRightAvail
|
||
|
, isBelowLeftAvail, isBelowRightAvail
|
||
|
);
|
||
|
}
|
||
|
} //compIdx
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
Void TComSampleAdaptiveOffset::SAOProcess(TComPic* pDecPic)
|
||
|
{
|
||
|
const Int numberOfComponents = getNumberValidComponents(m_chromaFormatIDC);
|
||
|
Bool bAllDisabled=true;
|
||
|
for(Int compIdx = 0; compIdx < numberOfComponents; compIdx++)
|
||
|
{
|
||
|
if (m_picSAOEnabled[compIdx]) bAllDisabled=false;
|
||
|
}
|
||
|
if (bAllDisabled) return;
|
||
|
|
||
|
TComPicYuv* resYuv = pDecPic->getPicYuvRec();
|
||
|
TComPicYuv* srcYuv = m_tempPicYuv;
|
||
|
resYuv->copyToPic(srcYuv);
|
||
|
for(Int ctuRsAddr= 0; ctuRsAddr < m_numCTUsPic; ctuRsAddr++)
|
||
|
{
|
||
|
offsetCTU(ctuRsAddr, srcYuv, resYuv, (pDecPic->getPicSym()->getSAOBlkParam())[ctuRsAddr], pDecPic);
|
||
|
} //ctu
|
||
|
}
|
||
|
|
||
|
|
||
|
/** PCM LF disable process.
|
||
|
* \param pcPic picture (TComPic) pointer
|
||
|
* \returns Void
|
||
|
*
|
||
|
* \note Replace filtered sample values of PCM mode blocks with the transmitted and reconstructed ones.
|
||
|
*/
|
||
|
Void TComSampleAdaptiveOffset::PCMLFDisableProcess (TComPic* pcPic)
|
||
|
{
|
||
|
xPCMRestoration(pcPic);
|
||
|
}
|
||
|
|
||
|
/** Picture-level PCM restoration.
|
||
|
* \param pcPic picture (TComPic) pointer
|
||
|
* \returns Void
|
||
|
*/
|
||
|
Void TComSampleAdaptiveOffset::xPCMRestoration(TComPic* pcPic)
|
||
|
{
|
||
|
Bool bPCMFilter = (pcPic->getSlice(0)->getSPS()->getUsePCM() && pcPic->getSlice(0)->getSPS()->getPCMFilterDisableFlag())? true : false;
|
||
|
|
||
|
if(bPCMFilter || pcPic->getSlice(0)->getPPS()->getTransquantBypassEnableFlag())
|
||
|
{
|
||
|
for( UInt ctuRsAddr = 0; ctuRsAddr < pcPic->getNumberOfCtusInFrame() ; ctuRsAddr++ )
|
||
|
{
|
||
|
TComDataCU* pcCU = pcPic->getCtu(ctuRsAddr);
|
||
|
|
||
|
xPCMCURestoration(pcCU, 0, 0);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/** PCM CU restoration.
|
||
|
* \param pcCU pointer to current CU
|
||
|
* \param uiAbsPartIdx part index
|
||
|
* \param uiDepth CU depth
|
||
|
* \returns Void
|
||
|
*/
|
||
|
Void TComSampleAdaptiveOffset::xPCMCURestoration ( TComDataCU* pcCU, UInt uiAbsZorderIdx, UInt uiDepth )
|
||
|
{
|
||
|
TComPic* pcPic = pcCU->getPic();
|
||
|
UInt uiCurNumParts = pcPic->getNumPartitionsInCtu() >> (uiDepth<<1);
|
||
|
UInt uiQNumParts = uiCurNumParts>>2;
|
||
|
|
||
|
// go to sub-CU
|
||
|
if( pcCU->getDepth(uiAbsZorderIdx) > uiDepth )
|
||
|
{
|
||
|
for ( UInt uiPartIdx = 0; uiPartIdx < 4; uiPartIdx++, uiAbsZorderIdx+=uiQNumParts )
|
||
|
{
|
||
|
UInt uiLPelX = pcCU->getCUPelX() + g_auiRasterToPelX[ g_auiZscanToRaster[uiAbsZorderIdx] ];
|
||
|
UInt uiTPelY = pcCU->getCUPelY() + g_auiRasterToPelY[ g_auiZscanToRaster[uiAbsZorderIdx] ];
|
||
|
if( ( uiLPelX < pcCU->getSlice()->getSPS()->getPicWidthInLumaSamples() ) && ( uiTPelY < pcCU->getSlice()->getSPS()->getPicHeightInLumaSamples() ) )
|
||
|
xPCMCURestoration( pcCU, uiAbsZorderIdx, uiDepth+1 );
|
||
|
}
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// restore PCM samples
|
||
|
if ((pcCU->getIPCMFlag(uiAbsZorderIdx)&& pcPic->getSlice(0)->getSPS()->getPCMFilterDisableFlag()) || pcCU->isLosslessCoded( uiAbsZorderIdx))
|
||
|
{
|
||
|
const UInt numComponents=pcPic->getNumberValidComponents();
|
||
|
for(UInt comp=0; comp<numComponents; comp++)
|
||
|
{
|
||
|
xPCMSampleRestoration (pcCU, uiAbsZorderIdx, uiDepth, ComponentID(comp));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/** PCM sample restoration.
|
||
|
* \param pcCU pointer to current CU
|
||
|
* \param uiAbsPartIdx part index
|
||
|
* \param uiDepth CU depth
|
||
|
* \param ttText texture component type
|
||
|
* \returns Void
|
||
|
*/
|
||
|
Void TComSampleAdaptiveOffset::xPCMSampleRestoration (TComDataCU* pcCU, UInt uiAbsZorderIdx, UInt uiDepth, const ComponentID compID)
|
||
|
{
|
||
|
TComPicYuv* pcPicYuvRec = pcCU->getPic()->getPicYuvRec();
|
||
|
UInt uiPcmLeftShiftBit;
|
||
|
const UInt uiMinCoeffSize = pcCU->getPic()->getMinCUWidth()*pcCU->getPic()->getMinCUHeight();
|
||
|
const UInt csx=pcPicYuvRec->getComponentScaleX(compID);
|
||
|
const UInt csy=pcPicYuvRec->getComponentScaleY(compID);
|
||
|
const UInt uiOffset = (uiMinCoeffSize*uiAbsZorderIdx)>>(csx+csy);
|
||
|
|
||
|
Pel *piSrc = pcPicYuvRec->getAddr(compID, pcCU->getCtuRsAddr(), uiAbsZorderIdx);
|
||
|
const Pel *piPcm = pcCU->getPCMSample(compID) + uiOffset;
|
||
|
const UInt uiStride = pcPicYuvRec->getStride(compID);
|
||
|
const UInt uiWidth = ((g_uiMaxCUWidth >> uiDepth) >> csx);
|
||
|
const UInt uiHeight = ((g_uiMaxCUWidth >> uiDepth) >> csy);
|
||
|
|
||
|
if ( pcCU->isLosslessCoded(uiAbsZorderIdx) && !pcCU->getIPCMFlag(uiAbsZorderIdx) )
|
||
|
{
|
||
|
uiPcmLeftShiftBit = 0;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
uiPcmLeftShiftBit = g_bitDepth[toChannelType(compID)] - pcCU->getSlice()->getSPS()->getPCMBitDepth(toChannelType(compID));
|
||
|
}
|
||
|
|
||
|
for(UInt uiY = 0; uiY < uiHeight; uiY++ )
|
||
|
{
|
||
|
for(UInt uiX = 0; uiX < uiWidth; uiX++ )
|
||
|
{
|
||
|
piSrc[uiX] = (piPcm[uiX] << uiPcmLeftShiftBit);
|
||
|
}
|
||
|
piPcm += uiWidth;
|
||
|
piSrc += uiStride;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//! \}
|