/* 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-2023, 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 DecCu.cpp \brief CU decoder class */ #include "DecCu.h" #include "CommonLib/InterPrediction.h" #include "CommonLib/IntraPrediction.h" #include "CommonLib/Picture.h" #include "CommonLib/UnitTools.h" #include "CommonLib/dtrace_buffer.h" #if RExt__DECODER_DEBUG_TOOL_STATISTICS #include "CommonLib/CodingStatistics.h" #endif #if K0149_BLOCK_STATISTICS #include "CommonLib/ChromaFormat.h" #include "CommonLib/dtrace_blockstatistics.h" #endif //! \ingroup DecoderLib //! \{ // ==================================================================================================================== // Constructor / destructor / create / destroy // ==================================================================================================================== DecCu::DecCu() : m_tmpStorageCtu(nullptr) {} DecCu::~DecCu() { } void DecCu::init( TrQuant* pcTrQuant, IntraPrediction* pcIntra, InterPrediction* pcInter) { m_pcTrQuant = pcTrQuant; m_pcIntraPred = pcIntra; m_pcInterPred = pcInter; } void DecCu::initDecCuReshaper(Reshape* pcReshape, ChromaFormat chromaFormatIdc) { m_pcReshape = pcReshape; if (m_tmpStorageCtu == nullptr) { m_tmpStorageCtu = new PelStorage; m_tmpStorageCtu->create(UnitArea(chromaFormatIdc, Area(0, 0, MAX_CU_SIZE, MAX_CU_SIZE))); } } void DecCu::destoryDecCuReshaprBuf() { if (m_tmpStorageCtu) { m_tmpStorageCtu->destroy(); delete m_tmpStorageCtu; m_tmpStorageCtu = nullptr; } } // ==================================================================================================================== // Public member functions // ==================================================================================================================== void DecCu::decompressCtu( CodingStructure& cs, const UnitArea& ctuArea ) { const int maxNumChannelType = isChromaEnabled(cs.pcv->chrFormat) && CS::isDualITree(cs) ? 2 : 1; if (cs.resetIBCBuffer) { m_pcInterPred->resetIBCBuffer(cs.pcv->chrFormat, cs.slice->getSPS()->getMaxCUHeight()); cs.resetIBCBuffer = false; } for( int ch = 0; ch < maxNumChannelType; ch++ ) { const ChannelType chType = ChannelType( ch ); Position prevTmpPos; prevTmpPos.x = -1; prevTmpPos.y = -1; for( auto &currCU : cs.traverseCUs( CS::getArea( cs, ctuArea, chType ), chType ) ) { if(currCU.Y().valid()) { const int vSize = std::min(VPDU_SIZE, cs.slice->getSPS()->getMaxCUHeight()); if((currCU.Y().x % vSize) == 0 && (currCU.Y().y % vSize) == 0) { for(int x = currCU.Y().x; x < currCU.Y().x + currCU.Y().width; x += vSize) { for(int y = currCU.Y().y; y < currCU.Y().y + currCU.Y().height; y += vSize) { m_pcInterPred->resetVPDUforIBC(cs.pcv->chrFormat, cs.slice->getSPS()->getMaxCUHeight(), vSize, x + IBC_BUFFER_SIZE / cs.slice->getSPS()->getMaxCUHeight() / 2, y); } } } } if (!CU::isIntra(currCU) && !CU::isPLT(currCU) && currCU.Y().valid()) { xDeriveCuMvs(currCU); #if K0149_BLOCK_STATISTICS if(currCU.geoFlag) { storeGeoMergeCtx(m_geoMrgCtx); } #endif } switch( currCU.predMode ) { case MODE_INTER: case MODE_IBC: xReconInter( currCU ); break; case MODE_PLT: case MODE_INTRA: xReconIntraQT( currCU ); break; default: THROW( "Invalid prediction mode" ); break; } m_pcInterPred->xFillIBCBuffer(currCU); DTRACE_BLOCK_REC( cs.picture->getRecoBuf( currCU ), currCU, currCU.predMode ); } } #if K0149_BLOCK_STATISTICS getAndStoreBlockStatistics(cs, ctuArea); #endif } // ==================================================================================================================== // Protected member functions // ==================================================================================================================== void DecCu::xIntraRecBlk( TransformUnit& tu, const ComponentID compID ) { if( !tu.blocks[ compID ].valid() ) { return; } CodingStructure &cs = *tu.cs; const CompArea &area = tu.blocks[compID]; const ChannelType chType = toChannelType( compID ); PelBuf piPred = cs.getPredBuf( area ); const PredictionUnit &pu = *tu.cs->getPU( area.pos(), chType ); const uint32_t chFinalMode = PU::getFinalIntraMode(pu, chType); PelBuf pReco = cs.getRecoBuf(area); //===== init availability pattern ===== bool predRegDiffFromTB = CU::isPredRegDiffFromTB(*tu.cu, compID); bool firstTBInPredReg = CU::isFirstTBInPredReg(*tu.cu, compID, area); CompArea areaPredReg(COMPONENT_Y, tu.chromaFormat, area); if (tu.cu->ispMode != ISPType::NONE && isLuma(compID)) { if (predRegDiffFromTB) { if (firstTBInPredReg) { CU::adjustPredArea(areaPredReg); m_pcIntraPred->initIntraPatternChTypeISP(*tu.cu, areaPredReg, pReco); } } else { m_pcIntraPred->initIntraPatternChTypeISP(*tu.cu, area, pReco); } } else { m_pcIntraPred->initIntraPatternChType(*tu.cu, area); } //===== get prediction signal ===== if (compID != COMPONENT_Y && PU::isLMCMode(chFinalMode)) { const PredictionUnit& pu = *tu.cu->firstPU; m_pcIntraPred->xGetLumaRecPixels( pu, area ); m_pcIntraPred->predIntraChromaLM(compID, piPred, pu, area, chFinalMode); } else { if( PU::isMIP( pu, chType ) ) { m_pcIntraPred->initIntraMip( pu, area ); m_pcIntraPred->predIntraMip( compID, piPred, pu ); } else { if (predRegDiffFromTB) { if (firstTBInPredReg) { PelBuf piPredReg = cs.getPredBuf(areaPredReg); m_pcIntraPred->predIntraAng(compID, piPredReg, pu); } } else { m_pcIntraPred->predIntraAng(compID, piPred, pu); } } } const Slice &slice = *cs.slice; bool flag = slice.getLmcsEnabledFlag() && (slice.isIntra() || (!slice.isIntra() && m_pcReshape->getCTUFlag())); if (flag && slice.getPicHeader()->getLmcsChromaResidualScaleFlag() && (compID != COMPONENT_Y) && (tu.cbf[COMPONENT_Cb] || tu.cbf[COMPONENT_Cr])) { const Area area = tu.Y().valid() ? tu.Y() : Area(recalcPosition(tu.chromaFormat, tu.chType, ChannelType::LUMA, tu.block(tu.chType).pos()), recalcSize(tu.chromaFormat, tu.chType, ChannelType::LUMA, tu.block(tu.chType).size())); const CompArea &areaY = CompArea(COMPONENT_Y, tu.chromaFormat, area); int adj = m_pcReshape->calculateChromaAdjVpduNei(tu, areaY); tu.setChromaAdj(adj); } //===== inverse transform ===== PelBuf piResi = cs.getResiBuf( area ); const QpParam cQP( tu, compID ); if( tu.jointCbCr && isChroma(compID) ) { if( compID == COMPONENT_Cb ) { PelBuf resiCr = cs.getResiBuf( tu.blocks[ COMPONENT_Cr ] ); if( tu.jointCbCr >> 1 ) { m_pcTrQuant->invTransformNxN( tu, COMPONENT_Cb, piResi, cQP ); } else { const QpParam qpCr( tu, COMPONENT_Cr ); m_pcTrQuant->invTransformNxN( tu, COMPONENT_Cr, resiCr, qpCr ); } m_pcTrQuant->invTransformICT( tu, piResi, resiCr ); } } else if (TU::getCbf(tu, compID)) { m_pcTrQuant->invTransformNxN( tu, compID, piResi, cQP ); } else { piResi.fill( 0 ); } //===== reconstruction ===== flag = flag && (tu.blocks[compID].width*tu.blocks[compID].height > 4); if (flag && (TU::getCbf(tu, compID) || tu.jointCbCr) && isChroma(compID) && slice.getPicHeader()->getLmcsChromaResidualScaleFlag()) { piResi.scaleSignal(tu.getChromaAdj(), 0, tu.cu->cs->slice->clpRng(compID)); } if (tu.cu->ispMode == ISPType::NONE || !isLuma(compID)) { cs.setDecomp( area ); } else if (tu.cu->ispMode != ISPType::NONE && isLuma(compID) && CU::isISPFirst(*tu.cu, tu.blocks[compID], compID)) { cs.setDecomp( tu.cu->blocks[compID] ); } #if REUSE_CU_RESULTS CompArea tmpArea(COMPONENT_Y, area.chromaFormat, Position(0, 0), area.size()); PelBuf tmpPred; #endif if (slice.getLmcsEnabledFlag() && (m_pcReshape->getCTUFlag() || slice.isIntra()) && compID == COMPONENT_Y) { #if REUSE_CU_RESULTS tmpPred = m_tmpStorageCtu->getBuf(tmpArea); tmpPred.copyFrom(piPred); #endif } #if KEEP_PRED_AND_RESI_SIGNALS pReco.reconstruct( piPred, piResi, tu.cu->cs->slice->clpRng( compID ) ); #else piPred.reconstruct(piPred, piResi, tu.cu->cs->slice->clpRng(compID)); pReco.copyFrom( piPred ); #endif if (slice.getLmcsEnabledFlag() && (m_pcReshape->getCTUFlag() || slice.isIntra()) && compID == COMPONENT_Y) { #if REUSE_CU_RESULTS piPred.copyFrom(tmpPred); #endif } #if REUSE_CU_RESULTS if( cs.pcv->isEncoder ) { cs.picture->getRecoBuf( area ).copyFrom( pReco ); cs.picture->getPredBuf(area).copyFrom(piPred); } #endif } void DecCu::xIntraRecACTBlk(TransformUnit& tu) { CodingStructure &cs = *tu.cs; const PredictionUnit &pu = *tu.cs->getPU(tu.blocks[COMPONENT_Y], ChannelType::LUMA); const Slice &slice = *cs.slice; CHECK(!tu.Y().valid() || !tu.Cb().valid() || !tu.Cr().valid(), "Invalid TU"); CHECK(&pu != tu.cu->firstPU, "wrong PU fetch"); CHECK(tu.cu->ispMode != ISPType::NONE, "adaptive color transform cannot be applied to ISP"); CHECK(pu.intraDir[ChannelType::CHROMA] != DM_CHROMA_IDX, "chroma should use DM mode for adaptive color transform"); bool flag = slice.getLmcsEnabledFlag() && (slice.isIntra() || (!slice.isIntra() && m_pcReshape->getCTUFlag())); if (flag && slice.getPicHeader()->getLmcsChromaResidualScaleFlag()) { const Area area = tu.Y().valid() ? tu.Y() : Area(recalcPosition(tu.chromaFormat, tu.chType, ChannelType::LUMA, tu.block(tu.chType).pos()), recalcSize(tu.chromaFormat, tu.chType, ChannelType::LUMA, tu.block(tu.chType).size())); const CompArea &areaY = CompArea(COMPONENT_Y, tu.chromaFormat, area); int adj = m_pcReshape->calculateChromaAdjVpduNei(tu, areaY); tu.setChromaAdj(adj); } for (int i = 0; i < getNumberValidComponents(tu.chromaFormat); i++) { ComponentID compID = (ComponentID)i; const CompArea &area = tu.blocks[compID]; const ChannelType chType = toChannelType(compID); PelBuf piPred = cs.getPredBuf(area); m_pcIntraPred->initIntraPatternChType(*tu.cu, area); if (PU::isMIP(pu, chType)) { m_pcIntraPred->initIntraMip(pu, area); m_pcIntraPred->predIntraMip(compID, piPred, pu); } else { m_pcIntraPred->predIntraAng(compID, piPred, pu); } PelBuf piResi = cs.getResiBuf(area); QpParam cQP(tu, compID); if (tu.jointCbCr && isChroma(compID)) { if (compID == COMPONENT_Cb) { PelBuf resiCr = cs.getResiBuf(tu.blocks[COMPONENT_Cr]); if (tu.jointCbCr >> 1) { m_pcTrQuant->invTransformNxN(tu, COMPONENT_Cb, piResi, cQP); } else { QpParam qpCr(tu, COMPONENT_Cr); m_pcTrQuant->invTransformNxN(tu, COMPONENT_Cr, resiCr, qpCr); } m_pcTrQuant->invTransformICT(tu, piResi, resiCr); } } else { if (TU::getCbf(tu, compID)) { m_pcTrQuant->invTransformNxN(tu, compID, piResi, cQP); } else { piResi.fill(0); } } cs.setDecomp(area); } cs.getResiBuf(tu).colorSpaceConvert(cs.getResiBuf(tu), false, tu.cu->cs->slice->clpRng(COMPONENT_Y)); for (int i = 0; i < getNumberValidComponents(tu.chromaFormat); i++) { ComponentID compID = (ComponentID)i; const CompArea &area = tu.blocks[compID]; PelBuf piPred = cs.getPredBuf(area); PelBuf piResi = cs.getResiBuf(area); PelBuf piReco = cs.getRecoBuf(area); PelBuf tmpPred; if (slice.getLmcsEnabledFlag() && (m_pcReshape->getCTUFlag() || slice.isIntra()) && compID == COMPONENT_Y) { CompArea tmpArea(COMPONENT_Y, area.chromaFormat, Position(0, 0), area.size()); tmpPred = m_tmpStorageCtu->getBuf(tmpArea); tmpPred.copyFrom(piPred); } if (flag && isChroma(compID) && (tu.blocks[compID].width*tu.blocks[compID].height > 4) && slice.getPicHeader()->getLmcsChromaResidualScaleFlag()) { piResi.scaleSignal(tu.getChromaAdj(), 0, tu.cu->cs->slice->clpRng(compID)); } piPred.reconstruct(piPred, piResi, tu.cu->cs->slice->clpRng(compID)); piReco.copyFrom(piPred); if (slice.getLmcsEnabledFlag() && (m_pcReshape->getCTUFlag() || slice.isIntra()) && compID == COMPONENT_Y) { piPred.copyFrom(tmpPred); } if (cs.pcv->isEncoder) { cs.picture->getRecoBuf(area).copyFrom(piReco); cs.picture->getPredBuf(area).copyFrom(piPred); } } } void DecCu::xReconIntraQT( CodingUnit &cu ) { if (CU::isPLT(cu)) { if (cu.isSepTree()) { if (isLuma(cu.chType)) { xReconPLT(cu, COMPONENT_Y, 1); } if (isChromaEnabled(cu.chromaFormat) && cu.chType == ChannelType::CHROMA) { xReconPLT(cu, COMPONENT_Cb, 2); } } else { xReconPLT(cu, COMPONENT_Y, getNumberValidComponents(cu.chromaFormat)); } return; } if (cu.colorTransform) { xIntraRecACTQT(cu); } else { for (auto chType = ChannelType::LUMA; chType <= ::getLastChannel(cu.chromaFormat); chType++) { if (cu.block(chType).valid()) { xIntraRecQT(cu, chType); } } } } void DecCu::xReconPLT(CodingUnit &cu, ComponentID compBegin, uint32_t numComp) { const SPS& sps = *(cu.cs->sps); TransformUnit& tu = *cu.firstTU; PelBuf curPLTIdx = tu.getcurPLTIdx(compBegin); uint32_t height = cu.block(compBegin).height; uint32_t width = cu.block(compBegin).width; //recon. pixels uint32_t scaleX = getComponentScaleX(COMPONENT_Cb, sps.getChromaFormatIdc()); uint32_t scaleY = getComponentScaleY(COMPONENT_Cb, sps.getChromaFormatIdc()); for (uint32_t y = 0; y < height; y++) { for (uint32_t x = 0; x < width; x++) { for (uint32_t compID = compBegin; compID < (compBegin + numComp); compID++) { const int channelBitDepth = cu.cs->sps->getBitDepth(toChannelType((ComponentID)compID)); const CompArea &area = cu.blocks[compID]; PelBuf picReco = cu.cs->getRecoBuf(area); PLTescapeBuf escapeValue = tu.getescapeValue((ComponentID)compID); if (curPLTIdx.at(x, y) == cu.curPLTSize[compBegin]) { TCoeff value; QpParam cQP(tu, (ComponentID)compID); int qp = cQP.Qp(true); int qpRem = qp % 6; int qpPer = qp / 6; if (compBegin != COMPONENT_Y || compID == COMPONENT_Y) { int invquantiserRightShift = IQUANT_SHIFT; int add = 1 << (invquantiserRightShift - 1); value = ((((escapeValue.at(x, y)*g_invQuantScales[0][qpRem]) << qpPer) + add) >> invquantiserRightShift); value = ClipBD(value, channelBitDepth); picReco.at(x, y) = Pel(value); } else if (compBegin == COMPONENT_Y && compID != COMPONENT_Y && y % (1 << scaleY) == 0 && x % (1 << scaleX) == 0) { uint32_t posYC = y >> scaleY; uint32_t posXC = x >> scaleX; int invquantiserRightShift = IQUANT_SHIFT; int add = 1 << (invquantiserRightShift - 1); value = ((((escapeValue.at(posXC, posYC)*g_invQuantScales[0][qpRem]) << qpPer) + add) >> invquantiserRightShift); value = ClipBD(value, channelBitDepth); picReco.at(posXC, posYC) = Pel(value); } } else { uint32_t curIdx = curPLTIdx.at(x, y); if (compBegin != COMPONENT_Y || compID == COMPONENT_Y) { picReco.at(x, y) = cu.curPLT[compID][curIdx]; } else if (compBegin == COMPONENT_Y && compID != COMPONENT_Y && y % (1 << scaleY) == 0 && x % (1 << scaleX) == 0) { uint32_t posYC = y >> scaleY; uint32_t posXC = x >> scaleX; picReco.at(posXC, posYC) = cu.curPLT[compID][curIdx]; } } } } } for (uint32_t compID = compBegin; compID < (compBegin + numComp); compID++) { const CompArea &area = cu.blocks[compID]; PelBuf picReco = cu.cs->getRecoBuf(area); cu.cs->picture->getRecoBuf(area).copyFrom(picReco); cu.cs->setDecomp(area); } } /** Function for deriving reconstructed PU/CU chroma samples with QTree structure * \param pcRecoYuv pointer to reconstructed sample arrays * \param pcPredYuv pointer to prediction sample arrays * \param pcResiYuv pointer to residue sample arrays * \param chType texture channel type (luma/chroma) * \param rTu reference to transform data * \ This function derives reconstructed PU/CU chroma samples with QTree recursive structure */ void DecCu::xIntraRecQT(CodingUnit &cu, const ChannelType chType) { for( auto &currTU : CU::traverseTUs( cu ) ) { if( isLuma( chType ) ) { xIntraRecBlk( currTU, COMPONENT_Y ); } else { const uint32_t numValidComp = getNumberValidComponents( cu.chromaFormat ); for( uint32_t compID = COMPONENT_Cb; compID < numValidComp; compID++ ) { xIntraRecBlk( currTU, ComponentID( compID ) ); } } } } void DecCu::xIntraRecACTQT(CodingUnit &cu) { for (auto &currTU : CU::traverseTUs(cu)) { xIntraRecACTBlk(currTU); } } #include "CommonLib/dtrace_buffer.h" void DecCu::xReconInter(CodingUnit &cu) { if( cu.geoFlag ) { m_pcInterPred->motionCompensationGeo( cu, m_geoMrgCtx ); PU::spanGeoMotionInfo(*cu.firstPU, m_geoMrgCtx, cu.firstPU->geoSplitDir, cu.firstPU->geoMergeIdx); } else { m_pcIntraPred->geneIntrainterPred(cu); // inter prediction CHECK(CU::isIBC(cu) && cu.firstPU->ciipFlag, "IBC and Ciip cannot be used together"); CHECK(CU::isIBC(cu) && cu.affine, "IBC and Affine cannot be used together"); CHECK(CU::isIBC(cu) && cu.geoFlag, "IBC and geo cannot be used together"); CHECK(CU::isIBC(cu) && cu.firstPU->mmvdMergeFlag, "IBC and MMVD cannot be used together"); const bool luma = cu.Y().valid(); const bool chroma = isChromaEnabled(cu.chromaFormat) && cu.Cb().valid(); if (luma && (chroma || !isChromaEnabled(cu.chromaFormat))) { m_pcInterPred->motionCompensateCu(cu, REF_PIC_LIST_X, true, true); } else { m_pcInterPred->motionCompensateCu(cu, REF_PIC_LIST_0, luma, chroma); } } if (cu.Y().valid()) { CU::saveMotionForHmvp(cu); } if (cu.firstPU->ciipFlag) { if (cu.cs->slice->getLmcsEnabledFlag() && m_pcReshape->getCTUFlag()) { cu.cs->getPredBuf(*cu.firstPU).Y().rspSignal(m_pcReshape->getFwdLUT()); } m_pcIntraPred->geneWeightedPred(cu.cs->getPredBuf(*cu.firstPU).Y(), *cu.firstPU, m_pcIntraPred->getPredictorPtr2(COMPONENT_Y, 0)); if (isChromaEnabled(cu.chromaFormat) && cu.chromaSize().width > 2) { m_pcIntraPred->geneWeightedPred(cu.cs->getPredBuf(*cu.firstPU).Cb(), *cu.firstPU, m_pcIntraPred->getPredictorPtr2(COMPONENT_Cb, 0)); m_pcIntraPred->geneWeightedPred(cu.cs->getPredBuf(*cu.firstPU).Cr(), *cu.firstPU, m_pcIntraPred->getPredictorPtr2(COMPONENT_Cr, 0)); } } DTRACE ( g_trace_ctx, D_TMP, "pred " ); DTRACE_CRC( g_trace_ctx, D_TMP, *cu.cs, cu.cs->getPredBuf( cu ), &cu.Y() ); // inter recon xDecodeInterTexture(cu); // clip for only non-zero cbf case CodingStructure &cs = *cu.cs; if (cu.rootCbf) { #if REUSE_CU_RESULTS const CompArea &area = cu.blocks[COMPONENT_Y]; CompArea tmpArea(COMPONENT_Y, area.chromaFormat, Position(0, 0), area.size()); PelBuf tmpPred; #endif if (cs.slice->getLmcsEnabledFlag() && m_pcReshape->getCTUFlag()) { #if REUSE_CU_RESULTS if (cs.pcv->isEncoder) { tmpPred = m_tmpStorageCtu->getBuf(tmpArea); tmpPred.copyFrom(cs.getPredBuf(cu).get(COMPONENT_Y)); } #endif if (!cu.firstPU->ciipFlag && !CU::isIBC(cu)) { cs.getPredBuf(cu).get(COMPONENT_Y).rspSignal(m_pcReshape->getFwdLUT()); } } #if KEEP_PRED_AND_RESI_SIGNALS cs.getRecoBuf( cu ).reconstruct( cs.getPredBuf( cu ), cs.getResiBuf( cu ), cs.slice->clpRngs() ); #else cs.getResiBuf( cu ).reconstruct( cs.getPredBuf( cu ), cs.getResiBuf( cu ), cs.slice->clpRngs() ); cs.getRecoBuf( cu ).copyFrom ( cs.getResiBuf( cu ) ); #endif if (cs.slice->getLmcsEnabledFlag() && m_pcReshape->getCTUFlag()) { #if REUSE_CU_RESULTS if (cs.pcv->isEncoder) { cs.getPredBuf(cu).get(COMPONENT_Y).copyFrom(tmpPred); } #endif } } else { cs.getRecoBuf(cu).copyClip(cs.getPredBuf(cu), cs.slice->clpRngs()); if (cs.slice->getLmcsEnabledFlag() && m_pcReshape->getCTUFlag() && !cu.firstPU->ciipFlag && !CU::isIBC(cu)) { cs.getRecoBuf(cu).get(COMPONENT_Y).rspSignal(m_pcReshape->getFwdLUT()); } } DTRACE ( g_trace_ctx, D_TMP, "reco " ); DTRACE_CRC( g_trace_ctx, D_TMP, *cu.cs, cu.cs->getRecoBuf( cu ), &cu.Y() ); cs.setDecomp(cu); } void DecCu::xDecodeInterTU( TransformUnit & currTU, const ComponentID compID ) { if (!currTU.blocks[compID].valid()) { return; } const CompArea &area = currTU.blocks[compID]; CodingStructure& cs = *currTU.cs; //===== inverse transform ===== PelBuf resiBuf = cs.getResiBuf(area); QpParam cQP(currTU, compID); if( currTU.jointCbCr && isChroma(compID) ) { if( compID == COMPONENT_Cb ) { PelBuf resiCr = cs.getResiBuf( currTU.blocks[ COMPONENT_Cr ] ); if( currTU.jointCbCr >> 1 ) { m_pcTrQuant->invTransformNxN( currTU, COMPONENT_Cb, resiBuf, cQP ); } else { QpParam qpCr(currTU, COMPONENT_Cr); m_pcTrQuant->invTransformNxN( currTU, COMPONENT_Cr, resiCr, qpCr ); } m_pcTrQuant->invTransformICT( currTU, resiBuf, resiCr ); } } else if (TU::getCbf(currTU, compID)) { m_pcTrQuant->invTransformNxN( currTU, compID, resiBuf, cQP ); } else { resiBuf.fill( 0 ); } //===== reconstruction ===== const Slice &slice = *cs.slice; if (!currTU.cu->colorTransform && slice.getLmcsEnabledFlag() && isChroma(compID) && (TU::getCbf(currTU, compID) || currTU.jointCbCr) && slice.getPicHeader()->getLmcsChromaResidualScaleFlag() && currTU.blocks[compID].width * currTU.blocks[compID].height > 4) { resiBuf.scaleSignal(currTU.getChromaAdj(), 0, currTU.cu->cs->slice->clpRng(compID)); } } void DecCu::xDecodeInterTexture(CodingUnit &cu) { if( !cu.rootCbf ) { return; } const uint32_t uiNumVaildComp = getNumberValidComponents(cu.chromaFormat); if (cu.colorTransform) { CodingStructure &cs = *cu.cs; const Slice &slice = *cs.slice; for (auto& currTU : CU::traverseTUs(cu)) { for (uint32_t ch = 0; ch < uiNumVaildComp; ch++) { const ComponentID compID = ComponentID(ch); if (slice.getLmcsEnabledFlag() && slice.getPicHeader()->getLmcsChromaResidualScaleFlag() && (compID == COMPONENT_Y)) { const CompArea &areaY = currTU.blocks[COMPONENT_Y]; int adj = m_pcReshape->calculateChromaAdjVpduNei(currTU, areaY); currTU.setChromaAdj(adj); } xDecodeInterTU(currTU, compID); } cs.getResiBuf(currTU).colorSpaceConvert(cs.getResiBuf(currTU), false, cu.cs->slice->clpRng(COMPONENT_Y)); if (slice.getLmcsEnabledFlag() && slice.getPicHeader()->getLmcsChromaResidualScaleFlag() && currTU.blocks[COMPONENT_Cb].width * currTU.blocks[COMPONENT_Cb].height > 4) { cs.getResiBuf(currTU.blocks[COMPONENT_Cb]).scaleSignal(currTU.getChromaAdj(), 0, currTU.cu->cs->slice->clpRng(COMPONENT_Cb)); cs.getResiBuf(currTU.blocks[COMPONENT_Cr]).scaleSignal(currTU.getChromaAdj(), 0, currTU.cu->cs->slice->clpRng(COMPONENT_Cr)); } } } else { for (uint32_t ch = 0; ch < uiNumVaildComp; ch++) { const ComponentID compID = ComponentID(ch); for (auto &currTU: CU::traverseTUs(cu)) { CodingStructure &cs = *cu.cs; const Slice &slice = *cs.slice; if (slice.getLmcsEnabledFlag() && slice.getPicHeader()->getLmcsChromaResidualScaleFlag() && (compID == COMPONENT_Y) && (currTU.cbf[COMPONENT_Cb] || currTU.cbf[COMPONENT_Cr])) { const CompArea &areaY = currTU.blocks[COMPONENT_Y]; int adj = m_pcReshape->calculateChromaAdjVpduNei(currTU, areaY); currTU.setChromaAdj(adj); } xDecodeInterTU(currTU, compID); } } } } void DecCu::xDeriveCuMvs(CodingUnit &cu) { for( auto &pu : CU::traversePUs( cu ) ) { MergeCtx mrgCtx; #if RExt__DECODER_DEBUG_TOOL_STATISTICS if( pu.cu->affine ) { CodingStatistics::IncrementStatisticTool( CodingStatisticsClassType{ STATS__TOOL_AFF, pu.Y().width, pu.Y().height } ); } #endif if( pu.mergeFlag ) { if (pu.mmvdMergeFlag || pu.cu->mmvdSkip) { CHECK(pu.ciipFlag, "invalid Ciip"); if (pu.cs->sps->getSbTMVPEnabledFlag()) { Size bufSize = g_miScaling.scale(pu.lumaSize()); mrgCtx.subPuMvpMiBuf = MotionBuf(m_SubPuMiBuf, bufSize); } PU::getInterMergeCandidates(pu, mrgCtx, 1, pu.mmvdMergeIdx.pos.baseIdx + 1); PU::getInterMMVDMergeCandidates(pu, mrgCtx); mrgCtx.setMmvdMergeCandiInfo(pu, pu.mmvdMergeIdx); PU::spanMotionInfo(pu, mrgCtx); } else { if( pu.cu->geoFlag ) { PU::getGeoMergeCandidates( pu, m_geoMrgCtx ); } else if (pu.cu->affine) { AffineMergeCtx affineMergeCtx; if (pu.cs->sps->getSbTMVPEnabledFlag()) { Size bufSize = g_miScaling.scale(pu.lumaSize()); mrgCtx.subPuMvpMiBuf = MotionBuf(m_SubPuMiBuf, bufSize); affineMergeCtx.mrgCtx = &mrgCtx; } PU::getAffineMergeCand(pu, affineMergeCtx, pu.mergeIdx); pu.interDir = affineMergeCtx.interDirNeighbours[pu.mergeIdx]; pu.cu->affineType = affineMergeCtx.affineType[pu.mergeIdx]; pu.cu->bcwIdx = affineMergeCtx.bcwIdx[pu.mergeIdx]; pu.mergeType = affineMergeCtx.mergeType[pu.mergeIdx]; if (pu.mergeType == MergeType::SUBPU_ATMVP) { pu.refIdx[0] = affineMergeCtx.mvFieldNeighbours[pu.mergeIdx][0][0].refIdx; pu.refIdx[1] = affineMergeCtx.mvFieldNeighbours[pu.mergeIdx][0][1].refIdx; } else { for (const auto l: { REF_PIC_LIST_0, REF_PIC_LIST_1 }) { if (pu.cs->slice->getNumRefIdx(l) > 0) { auto &mvField = affineMergeCtx.mvFieldNeighbours[pu.mergeIdx]; pu.mvpIdx[l] = 0; pu.mvpNum[l] = 0; pu.mvd[l] = Mv(); PU::setAllAffineMvField(pu, mvField, l); } } } PU::spanMotionInfo(pu, mrgCtx); } else { if (CU::isIBC(*pu.cu)) { PU::getIBCMergeCandidates(pu, mrgCtx, pu.mergeIdx); } else { PU::getInterMergeCandidates(pu, mrgCtx, 0, pu.mergeIdx); } mrgCtx.setMergeInfo(pu, pu.mergeIdx); PU::spanMotionInfo(pu, mrgCtx); } } } else { #if REUSE_CU_RESULTS if ( cu.imv && !pu.cu->affine && !cu.cs->pcv->isEncoder ) #else if (cu.imv && !pu.cu->affine) #endif { PU::applyImv(pu, mrgCtx, m_pcInterPred); } else { if( pu.cu->affine ) { for ( uint32_t uiRefListIdx = 0; uiRefListIdx < 2; uiRefListIdx++ ) { RefPicList eRefList = RefPicList( uiRefListIdx ); if ( pu.cs->slice->getNumRefIdx( eRefList ) > 0 && ( pu.interDir & ( 1 << uiRefListIdx ) ) ) { AffineAMVPInfo affineAMVPInfo; PU::fillAffineMvpCand( pu, eRefList, pu.refIdx[eRefList], affineAMVPInfo ); const unsigned mvpIdx = pu.mvpIdx[eRefList]; pu.mvpNum[eRefList] = affineAMVPInfo.numCand; // Mv mv[3]; CHECK( pu.refIdx[eRefList] < 0, "Unexpected negative refIdx." ); if (!cu.cs->pcv->isEncoder) { for (int i = 0; i < cu.getNumAffineMvs(); i++) { pu.mvdAffi[eRefList][i].changeAffinePrecAmvr2Internal(pu.cu->imv); } } Mv mvLT = affineAMVPInfo.mvCandLT[mvpIdx] + pu.mvdAffi[eRefList][0]; Mv mvRT = affineAMVPInfo.mvCandRT[mvpIdx] + pu.mvdAffi[eRefList][1]; mvRT += pu.mvdAffi[eRefList][0]; Mv mvLB; if (cu.affineType == AffineModel::_6_PARAMS) { mvLB = affineAMVPInfo.mvCandLB[mvpIdx] + pu.mvdAffi[eRefList][2]; mvLB += pu.mvdAffi[eRefList][0]; } PU::setAllAffineMv(pu, mvLT, mvRT, mvLB, eRefList, true); } } } else if (CU::isIBC(*pu.cu) && pu.interDir == 1) { AMVPInfo amvpInfo; PU::fillIBCMvpCand(pu, amvpInfo); pu.mvpNum[REF_PIC_LIST_0] = amvpInfo.numCand; Mv mvd = pu.mvd[REF_PIC_LIST_0]; #if REUSE_CU_RESULTS if (!cu.cs->pcv->isEncoder) #endif { mvd.changeIbcPrecAmvr2Internal(pu.cu->imv); } if (pu.cs->sps->getMaxNumIBCMergeCand() == 1) { CHECK( pu.mvpIdx[REF_PIC_LIST_0], "mvpIdx for IBC mode should be 0" ); } pu.mv[REF_PIC_LIST_0] = amvpInfo.mvCand[pu.mvpIdx[REF_PIC_LIST_0]] + mvd; pu.mv[REF_PIC_LIST_0].foldToStorageBitDepth(); } else { for ( uint32_t uiRefListIdx = 0; uiRefListIdx < 2; uiRefListIdx++ ) { RefPicList eRefList = RefPicList( uiRefListIdx ); if ((pu.cs->slice->getNumRefIdx(eRefList) > 0 || (eRefList == REF_PIC_LIST_0 && CU::isIBC(*pu.cu))) && (pu.interDir & (1 << uiRefListIdx))) { AMVPInfo amvpInfo; PU::fillMvpCand(pu, eRefList, pu.refIdx[eRefList], amvpInfo); pu.mvpNum [eRefList] = amvpInfo.numCand; if (!cu.cs->pcv->isEncoder) { pu.mvd[eRefList].changeTransPrecAmvr2Internal(pu.cu->imv); } pu.mv[eRefList] = amvpInfo.mvCand[pu.mvpIdx[eRefList]] + pu.mvd[eRefList]; pu.mv[eRefList].foldToStorageBitDepth(); } } } PU::spanMotionInfo( pu, mrgCtx ); } } if( !cu.geoFlag ) { if( g_mctsDecCheckEnabled && !MCTSHelper::checkMvBufferForMCTSConstraint( pu, true ) ) { printf( "DECODER: pu motion vector across tile boundaries (%d,%d,%d,%d)\n", pu.lx(), pu.ly(), pu.lwidth(), pu.lheight() ); } } if (CU::isIBC(cu)) { const int cuPelX = pu.Y().x; const int cuPelY = pu.Y().y; int roiWidth = pu.lwidth(); int roiHeight = pu.lheight(); const unsigned int lcuWidth = pu.cs->slice->getSPS()->getMaxCUWidth(); int xPred = pu.mv[0].getHor() >> MV_FRACTIONAL_BITS_INTERNAL; int yPred = pu.mv[0].getVer() >> MV_FRACTIONAL_BITS_INTERNAL; CHECK(!m_pcInterPred->isLumaBvValid(lcuWidth, cuPelX, cuPelY, roiWidth, roiHeight, xPred, yPred), "invalid block vector for IBC detected."); } } } //! \}