libbpg/jctvc/TLibCommon/TComSampleAdaptiveOffset.cpp
2015-01-16 13:46:18 +01:00

724 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;
}
}
//! \}