Forked from
ECM / ECM
6060 commits behind the upstream repository.
-
Frank Bossen authored
fix ticket #173: reshaper interaction with PCM See merge request !298
Frank Bossen authoredfix ticket #173: reshaper interaction with PCM See merge request !298
SampleAdaptiveOffset.cpp 24.49 KiB
/* 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-2019, 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 SampleAdaptiveOffset.cpp
\brief sample adaptive offset class
*/
#include "SampleAdaptiveOffset.h"
#include "UnitTools.h"
#include "UnitPartitioner.h"
#include "CodingStructure.h"
#include "CommonLib/dtrace_codingstruct.h"
#include "CommonLib/dtrace_buffer.h"
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
//! \ingroup CommonLib
//! \{
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;
}
SampleAdaptiveOffset::SampleAdaptiveOffset()
{
}
SampleAdaptiveOffset::~SampleAdaptiveOffset()
{
destroy();
m_signLineBuf1.clear();
m_signLineBuf2.clear();
}
void SampleAdaptiveOffset::create( int picWidth, int picHeight, ChromaFormat format, uint32_t maxCUWidth, uint32_t maxCUHeight, uint32_t maxCUDepth, uint32_t lumaBitShift, uint32_t chromaBitShift )
{
//temporary picture buffer
UnitArea picArea(format, Area(0, 0, picWidth, picHeight));
m_tempBuf.destroy();
m_tempBuf.create( picArea );
//bit-depth related
for(int compIdx = 0; compIdx < MAX_NUM_COMPONENT; compIdx++)
{
m_offsetStepLog2 [compIdx] = isLuma(ComponentID(compIdx))? lumaBitShift : chromaBitShift;
}
m_numberOfComponents = getNumberValidComponents(format);
}
void SampleAdaptiveOffset::destroy()
{
m_tempBuf.destroy();
}
void SampleAdaptiveOffset::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]);
}
CHECK(dstOffsets[SAO_CLASS_EO_PLAIN] != 0, "EO offset is not '0'"); //keep EO plain offset as zero
}
}
int SampleAdaptiveOffset::getMergeList(CodingStructure& cs, int ctuRsAddr, SAOBlkParam* blkParams, SAOBlkParam* mergeList[NUM_SAO_MERGE_TYPES])
{
const PreCalcValues& pcv = *cs.pcv;
int ctuX = ctuRsAddr % pcv.widthInCtus;
int ctuY = ctuRsAddr / pcv.widthInCtus;
const CodingUnit& cu = *cs.getCU(Position(ctuX*pcv.maxCUWidth, ctuY*pcv.maxCUHeight), CH_L);
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- pcv.widthInCtus;
if(cs.getCURestricted(Position(ctuX*pcv.maxCUWidth, (ctuY-1)*pcv.maxCUHeight), cu, cu.chType))
{
mergeCandidate = &(blkParams[mergedCTUPos]);
}
}
}
break;
case SAO_MERGE_LEFT:
{
if(ctuX > 0)
{
mergedCTUPos = ctuRsAddr- 1;
if(cs.getCURestricted(Position((ctuX-1)*pcv.maxCUWidth, ctuY*pcv.maxCUHeight), cu, cu.chType))
{
mergeCandidate = &(blkParams[mergedCTUPos]);
}
}
}
break;
default:
{
THROW("not a supported merge type");
}
}
mergeList[mergeType]=mergeCandidate;
if (mergeCandidate != NULL)
{
numValidMergeCandidates++;
}
}
return numValidMergeCandidates;
}
void SampleAdaptiveOffset::reconstructBlkSAOParam(SAOBlkParam& recParam, SAOBlkParam* mergeList[NUM_SAO_MERGE_TYPES])
{
const int numberOfComponents = m_numberOfComponents;
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];
CHECK(mergeTarget == NULL, "Merge target does not exist");
offsetParam = (*mergeTarget)[component];
}
break;
default:
{
THROW("Not a supported mode");
}
}
}
}
void SampleAdaptiveOffset::xReconstructBlkSAOParams(CodingStructure& cs, SAOBlkParam* saoBlkParams)
{
for(uint32_t compIdx = 0; compIdx < MAX_NUM_COMPONENT; compIdx++)
{
m_picSAOEnabled[compIdx] = false;
}
const uint32_t numberOfComponents = getNumberValidComponents(cs.pcv->chrFormat);
for(int ctuRsAddr=0; ctuRsAddr< cs.pcv->sizeInCtus; ctuRsAddr++)
{
SAOBlkParam* mergeList[NUM_SAO_MERGE_TYPES] = { NULL };
getMergeList(cs, ctuRsAddr, saoBlkParams, mergeList);
reconstructBlkSAOParam(saoBlkParams[ctuRsAddr], mergeList);
for(uint32_t compIdx = 0; compIdx < numberOfComponents; compIdx++)
{
if(saoBlkParams[ctuRsAddr][compIdx].modeIdc != SAO_MODE_OFF)
{
m_picSAOEnabled[compIdx] = true;
}
}
}
}
void SampleAdaptiveOffset::offsetBlock(const int channelBitDepth, const ClpRng& clpRng, int typeIdx, int* offset
, const 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)
{
int x,y, startX, startY, endX, endY, edgeType;
int firstLineStartX, firstLineEndX, lastLineStartX, lastLineEndX;
int8_t signLeft, signRight, signDown;
const 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 = (int8_t)sgn(srcLine[startX] - srcLine[startX-1]);
for (x=startX; x< endX; x++)
{
signRight = (int8_t)sgn(srcLine[x] - srcLine[x+1]);
edgeType = signRight + signLeft;
signLeft = -signRight;
resLine[x] = ClipPel<int>( srcLine[x] + offset[edgeType], clpRng);
}
srcLine += srcStride;
resLine += resStride;
}
}
break;
case SAO_TYPE_EO_90:
{
offset += 2;
int8_t *signUpLine = &m_signLineBuf1[0];
startY = isAboveAvail ? 0 : 1;
endY = isBelowAvail ? height : height-1;
if (!isAboveAvail)
{
srcLine += srcStride;
resLine += resStride;
}
const Pel* srcLineAbove= srcLine- srcStride;
for (x=0; x< width; x++)
{
signUpLine[x] = (int8_t)sgn(srcLine[x] - srcLineAbove[x]);
}
const Pel* srcLineBelow;
for (y=startY; y<endY; y++)
{
srcLineBelow= srcLine+ srcStride;
for (x=0; x< width; x++)
{
signDown = (int8_t)sgn(srcLine[x] - srcLineBelow[x]);
edgeType = signDown + signUpLine[x];
signUpLine[x]= -signDown;
resLine[x] = ClipPel<int>(srcLine[x] + offset[edgeType], clpRng);
}
srcLine += srcStride;
resLine += resStride;
}
}
break;
case SAO_TYPE_EO_135:
{
offset += 2;
int8_t *signUpLine, *signDownLine, *signTmpLine;
signUpLine = &m_signLineBuf1[0];
signDownLine= &m_signLineBuf2[0];
startX = isLeftAvail ? 0 : 1 ;
endX = isRightAvail ? width : (width-1);
//prepare 2nd line's upper sign
const Pel* srcLineBelow= srcLine+ srcStride;
for (x=startX; x< endX+1; x++)
{
signUpLine[x] = (int8_t)sgn(srcLineBelow[x] - srcLine[x- 1]);
}
//1st line
const 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] = ClipPel<int>( srcLine[x] + offset[edgeType], clpRng);
}
srcLine += srcStride;
resLine += resStride;
//middle lines
for (y= 1; y< height-1; y++)
{
srcLineBelow= srcLine+ srcStride;
for (x=startX; x<endX; x++)
{
signDown = (int8_t)sgn(srcLine[x] - srcLineBelow[x+ 1]);
edgeType = signDown + signUpLine[x];
resLine[x] = ClipPel<int>( srcLine[x] + offset[edgeType], clpRng);
signDownLine[x+1] = -signDown;
}
signDownLine[startX] = (int8_t)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] = ClipPel<int>( srcLine[x] + offset[edgeType], clpRng);
}
}
break;
case SAO_TYPE_EO_45:
{
offset += 2;
int8_t *signUpLine = &m_signLineBuf1[1];
startX = isLeftAvail ? 0 : 1;
endX = isRightAvail ? width : (width -1);
//prepare 2nd line upper sign
const Pel* srcLineBelow= srcLine+ srcStride;
for (x=startX-1; x< endX; x++)
{
signUpLine[x] = (int8_t)sgn(srcLineBelow[x] - srcLine[x+1]);
}
//first line
const 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] = ClipPel<int>(srcLine[x] + offset[edgeType], clpRng);
}
srcLine += srcStride;
resLine += resStride;
//middle lines
for (y= 1; y< height-1; y++)
{
srcLineBelow= srcLine+ srcStride;
for(x= startX; x< endX; x++)
{
signDown = (int8_t)sgn(srcLine[x] - srcLineBelow[x-1]);
edgeType = signDown + signUpLine[x];
resLine[x] = ClipPel<int>(srcLine[x] + offset[edgeType], clpRng);
signUpLine[x-1] = -signDown;
}
signUpLine[endX-1] = (int8_t)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] = ClipPel<int>(srcLine[x] + offset[edgeType], clpRng);
}
}
break;
case SAO_TYPE_BO:
{
const int shiftBits = channelBitDepth - NUM_SAO_BO_CLASSES_LOG2;
for (y=0; y< height; y++)
{
for (x=0; x< width; x++)
{
resLine[x] = ClipPel<int>(srcLine[x] + offset[srcLine[x] >> shiftBits], clpRng );
}
srcLine += srcStride;
resLine += resStride;
}
}
break;
default:
{
THROW("Not a supported SAO types\n");
}
}
}
void SampleAdaptiveOffset::offsetCTU( const UnitArea& area, const CPelUnitBuf& src, PelUnitBuf& res, SAOBlkParam& saoblkParam, CodingStructure& cs)
{
const uint32_t numberOfComponents = getNumberValidComponents( area.chromaFormat );
bool bAllOff=true;
for( uint32_t compIdx = 0; compIdx < numberOfComponents; compIdx++)
{
if (saoblkParam[compIdx].modeIdc != SAO_MODE_OFF)
{
bAllOff=false;
}
}
if (bAllOff)
{
return;
}
bool isLeftAvail, isRightAvail, isAboveAvail, isBelowAvail, isAboveLeftAvail, isAboveRightAvail, isBelowLeftAvail, isBelowRightAvail;
//block boundary availability
deriveLoopFilterBoundaryAvailibility(cs, area.Y(), isLeftAvail,isRightAvail,isAboveAvail,isBelowAvail,isAboveLeftAvail,isAboveRightAvail,isBelowLeftAvail,isBelowRightAvail);
const size_t lineBufferSize = area.Y().width + 1;
if (m_signLineBuf1.size() < lineBufferSize)
{
m_signLineBuf1.resize(lineBufferSize);
m_signLineBuf2.resize(lineBufferSize);
}
for(int compIdx = 0; compIdx < numberOfComponents; compIdx++)
{
const ComponentID compID = ComponentID(compIdx);
const CompArea& compArea = area.block(compID);
SAOOffset& ctbOffset = saoblkParam[compIdx];
if(ctbOffset.modeIdc != SAO_MODE_OFF)
{
int srcStride = src.get(compID).stride;
const Pel* srcBlk = src.get(compID).bufAt(compArea);
int resStride = res.get(compID).stride;
Pel* resBlk = res.get(compID).bufAt(compArea);
offsetBlock( cs.sps->getBitDepth(toChannelType(compID)),
cs.slice->clpRng(compID),
ctbOffset.typeIdc, ctbOffset.offset
, srcBlk, resBlk, srcStride, resStride, compArea.width, compArea.height
, isLeftAvail, isRightAvail
, isAboveAvail, isBelowAvail
, isAboveLeftAvail, isAboveRightAvail
, isBelowLeftAvail, isBelowRightAvail
);
}
} //compIdx
}
void SampleAdaptiveOffset::SAOProcess( CodingStructure& cs, SAOBlkParam* saoBlkParams
)
{
CHECK(!saoBlkParams, "No parameters present");
xReconstructBlkSAOParams(cs, saoBlkParams);
const uint32_t numberOfComponents = getNumberValidComponents(cs.area.chromaFormat);
bool bAllDisabled = true;
for (uint32_t compIdx = 0; compIdx < numberOfComponents; compIdx++)
{
if (m_picSAOEnabled[compIdx])
{
bAllDisabled = false;
}
}
if (bAllDisabled)
{
return;
}
const PreCalcValues& pcv = *cs.pcv;
PelUnitBuf rec = cs.getRecoBuf();
m_tempBuf.copyFrom( rec );
int ctuRsAddr = 0;
for( uint32_t yPos = 0; yPos < pcv.lumaHeight; yPos += pcv.maxCUHeight )
{
for( uint32_t xPos = 0; xPos < pcv.lumaWidth; xPos += pcv.maxCUWidth )
{
const uint32_t width = (xPos + pcv.maxCUWidth > pcv.lumaWidth) ? (pcv.lumaWidth - xPos) : pcv.maxCUWidth;
const uint32_t height = (yPos + pcv.maxCUHeight > pcv.lumaHeight) ? (pcv.lumaHeight - yPos) : pcv.maxCUHeight;
const UnitArea area( cs.area.chromaFormat, Area(xPos , yPos, width, height) );
offsetCTU( area, m_tempBuf, rec, cs.picture->getSAO()[ctuRsAddr], cs);
ctuRsAddr++;
}
}
DTRACE_UPDATE(g_trace_ctx, (std::make_pair("poc", cs.slice->getPOC())));
DTRACE_PIC_COMP(D_REC_CB_LUMA_SAO, cs, cs.getRecoBuf(), COMPONENT_Y);
DTRACE_PIC_COMP(D_REC_CB_CHROMA_SAO, cs, cs.getRecoBuf(), COMPONENT_Cb);
DTRACE_PIC_COMP(D_REC_CB_CHROMA_SAO, cs, cs.getRecoBuf(), COMPONENT_Cr);
DTRACE ( g_trace_ctx, D_CRC, "SAO" );
DTRACE_CRC( g_trace_ctx, D_CRC, cs, cs.getRecoBuf() );
xPCMLFDisableProcess(cs);
}
void SampleAdaptiveOffset::xPCMLFDisableProcess(CodingStructure& cs)
{
const PreCalcValues& pcv = *cs.pcv;
const bool bPCMFilter = (cs.sps->getPCMEnabledFlag() && cs.sps->getPCMFilterDisableFlag()) ? true : false;
if( bPCMFilter || cs.pps->getTransquantBypassEnabledFlag() )
{
for( uint32_t yPos = 0; yPos < pcv.lumaHeight; yPos += pcv.maxCUHeight )
{
for( uint32_t xPos = 0; xPos < pcv.lumaWidth; xPos += pcv.maxCUWidth )
{
UnitArea ctuArea( cs.area.chromaFormat, Area( xPos, yPos, pcv.maxCUWidth, pcv.maxCUHeight ) );
// CU-based deblocking
xPCMCURestoration(cs, ctuArea);
}
}
}
}
void SampleAdaptiveOffset::xPCMCURestoration(CodingStructure& cs, const UnitArea &ctuArea)
{
const SPS& sps = *cs.sps;
#if JVET_M0277_FIX_PCM_DISABLEFILTER
uint32_t numComponents = CS::isDualITree(cs) ? 1 : m_numberOfComponents;
#endif
for( auto &cu : cs.traverseCUs( ctuArea, CH_L ) )
{
// restore PCM samples
if( ( cu.ipcm && sps.getPCMFilterDisableFlag() ) || CU::isLosslessCoded( cu ) )
{
#if !JVET_M0277_FIX_PCM_DISABLEFILTER
const uint32_t numComponents = m_numberOfComponents;
#endif
for( uint32_t comp = 0; comp < numComponents; comp++ )
{
xPCMSampleRestoration( cu, ComponentID( comp ) );
}
}
}
#if JVET_M0277_FIX_PCM_DISABLEFILTER
numComponents = m_numberOfComponents;
if (CS::isDualITree(cs) && numComponents)
{
for (auto &cu : cs.traverseCUs(ctuArea, CH_C))
{
// restore PCM samples
if ((cu.ipcm && sps.getPCMFilterDisableFlag()) || CU::isLosslessCoded(cu))
{
for (uint32_t comp = 1; comp < numComponents; comp++)
{
xPCMSampleRestoration(cu, ComponentID(comp));
}
}
}
}
#endif
}
void SampleAdaptiveOffset::xPCMSampleRestoration(CodingUnit& cu, const ComponentID compID)
{
const CompArea& ca = cu.block(compID);
if( CU::isLosslessCoded( cu ) && !cu.ipcm )
{
for( auto &currTU : CU::traverseTUs( cu ) )
{
const CPelBuf& pcmBuf = currTU.getPcmbuf( compID );
PelBuf dstBuf = cu.cs->getRecoBuf( currTU.block(compID) );
dstBuf.copyFrom( pcmBuf );
#if JVET_M0427_INLOOP_RESHAPER
if (cu.slice->getReshapeInfo().getUseSliceReshaper() && isLuma(compID))
{
dstBuf.rspSignal(m_pcReshape->getInvLUT());
}
#endif
}
return;
}
const TransformUnit& tu = *cu.firstTU; CHECK( cu.firstTU != cu.lastTU, "Multiple TUs present in a PCM CU" );
const CPelBuf& pcmBuf = tu.getPcmbuf( compID );
PelBuf dstBuf = cu.cs->getRecoBuf( ca );
const SPS &sps = *cu.cs->sps;
const uint32_t uiPcmLeftShiftBit = sps.getBitDepth(toChannelType(compID)) - sps.getPCMBitDepth(toChannelType(compID));
for (uint32_t y = 0; y < ca.height; y++)
{
for (uint32_t x = 0; x < ca.width; x++)
{
dstBuf.at(x,y) = (pcmBuf.at(x,y) << uiPcmLeftShiftBit);
}
}
#if JVET_M0427_INLOOP_RESHAPER
if (cu.slice->getReshapeInfo().getUseSliceReshaper() && isLuma(compID))
{
dstBuf.rspSignal(m_pcReshape->getInvLUT());
}
#endif
}
void SampleAdaptiveOffset::deriveLoopFilterBoundaryAvailibility(CodingStructure& cs, const Position &pos,
bool& isLeftAvail,
bool& isRightAvail,
bool& isAboveAvail,
bool& isBelowAvail,
bool& isAboveLeftAvail,
bool& isAboveRightAvail,
bool& isBelowLeftAvail,
bool& isBelowRightAvail
) const
{
const int width = cs.pcv->maxCUWidth;
const int height = cs.pcv->maxCUHeight;
const CodingUnit* cuCurr = cs.getCU(pos, CH_L);
const CodingUnit* cuLeft = cs.getCU(pos.offset(-width, 0), CH_L);
const CodingUnit* cuRight = cs.getCU(pos.offset(width, 0), CH_L);
const CodingUnit* cuAbove = cs.getCU(pos.offset(0, -height), CH_L);
const CodingUnit* cuBelow = cs.getCU(pos.offset(0, height), CH_L);
const CodingUnit* cuAboveLeft = cs.getCU(pos.offset(-width, -height), CH_L);
const CodingUnit* cuAboveRight = cs.getCU(pos.offset(width, -height), CH_L);
const CodingUnit* cuBelowLeft = cs.getCU(pos.offset(-width, height), CH_L);
const CodingUnit* cuBelowRight = cs.getCU(pos.offset(width, height), CH_L);
// check cross slice flags
{
//left
isLeftAvail = (cuLeft != NULL) ? ( !CU::isSameSlice(*cuCurr, *cuLeft) ? cuCurr->slice->getLFCrossSliceBoundaryFlag() : true ) : false;
//above
isAboveAvail = (cuAbove != NULL) ? ( !CU::isSameSlice(*cuCurr, *cuAbove) ? cuCurr->slice->getLFCrossSliceBoundaryFlag() : true ) : false;
//right
isRightAvail = (cuRight != NULL) ? ( !CU::isSameSlice(*cuCurr, *cuRight) ? cuRight->slice->getLFCrossSliceBoundaryFlag() : true ) : false;
//below
isBelowAvail = (cuBelow != NULL) ? ( !CU::isSameSlice(*cuCurr, *cuBelow) ? cuBelow->slice->getLFCrossSliceBoundaryFlag() : true ) : false;
//above-left
isAboveLeftAvail = (cuAboveLeft != NULL) ? ( !CU::isSameSlice(*cuCurr, *cuAboveLeft) ? cuCurr->slice->getLFCrossSliceBoundaryFlag() : true ) : false;
//below-right
isBelowRightAvail = (cuBelowRight != NULL) ? ( !CU::isSameSlice(*cuCurr, *cuBelowRight) ? cuBelowRight->slice->getLFCrossSliceBoundaryFlag() : true ) : false;
//above-right
isAboveRightAvail = false;
if (cuAboveRight != NULL)
{
const bool bLFCrossSliceBoundaryFlag = (cuCurr->slice->getSliceCurStartCtuTsAddr() > cuAboveRight->slice->getSliceCurStartCtuTsAddr()) ? cuCurr->slice->getLFCrossSliceBoundaryFlag() : cuAboveRight->slice->getLFCrossSliceBoundaryFlag();
isAboveRightAvail = ( !CU::isSameSlice(*cuCurr, *cuAboveRight) ) ? bLFCrossSliceBoundaryFlag : true;
}
//below-left
isBelowLeftAvail = false;
if (cuBelowLeft != NULL)
{
const bool bLFCrossSliceBoundaryFlag = (cuCurr->slice->getSliceCurStartCtuTsAddr() > cuBelowLeft->slice->getSliceCurStartCtuTsAddr()) ? cuCurr->slice->getLFCrossSliceBoundaryFlag() : cuBelowLeft->slice->getLFCrossSliceBoundaryFlag();
isBelowLeftAvail = ( !CU::isSameSlice(*cuCurr, *cuBelowLeft) ) ? bLFCrossSliceBoundaryFlag : true;
}
}
#if HEVC_TILES_WPP
// check cross tile flags
const bool isLoopFilterAcrossTilePPS = cs.pps->getLoopFilterAcrossTilesEnabledFlag();
if (!isLoopFilterAcrossTilePPS)
{
isLeftAvail = (!isLeftAvail) ? false : CU::isSameTile(*cuCurr, *cuLeft);
isAboveAvail = (!isAboveAvail) ? false : CU::isSameTile(*cuCurr, *cuAbove);
isRightAvail = (!isRightAvail) ? false : CU::isSameTile(*cuCurr, *cuRight);
isBelowAvail = (!isBelowAvail) ? false : CU::isSameTile(*cuCurr, *cuBelow);
isAboveLeftAvail = (!isAboveLeftAvail) ? false : CU::isSameTile(*cuCurr, *cuAboveLeft);
isAboveRightAvail = (!isAboveRightAvail) ? false : CU::isSameTile(*cuCurr, *cuAboveRight);
isBelowLeftAvail = (!isBelowLeftAvail) ? false : CU::isSameTile(*cuCurr, *cuBelowLeft);
isBelowRightAvail = (!isBelowRightAvail) ? false : CU::isSameTile(*cuCurr, *cuBelowRight);
}
#endif
}
//! \}