/* 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 DecCu.cpp \brief CU decoder class */ #include "DecCu.h" #include "CommonLib/CrossCompPrediction.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_tmpStorageLCU = NULL; } 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_tmpStorageLCU == NULL) { m_tmpStorageLCU = new PelStorage; m_tmpStorageLCU->create(UnitArea(chromaFormatIDC, Area(0, 0, MAX_CU_SIZE, MAX_CU_SIZE))); } } void DecCu::destoryDecCuReshaprBuf() { if (m_tmpStorageLCU) { m_tmpStorageLCU->destroy(); delete m_tmpStorageLCU; m_tmpStorageLCU = NULL; } } // ==================================================================================================================== // Public member functions // ==================================================================================================================== void DecCu::decompressCtu( CodingStructure& cs, const UnitArea& ctuArea ) { const int maxNumChannelType = cs.pcv->chrFormat != CHROMA_400 && CS::isDualITree( cs ) ? 2 : 1; #if !JVET_P0400_REMOVE_SHARED_MERGE_LIST if (!cs.pcv->isEncoder) { m_shareStateDec = NO_SHARE; } bool sharePrepareCondition = ((!cs.pcv->isEncoder) && (!(cs.slice->isIntra()) || cs.slice->getSPS()->getIBCFlag())); #endif 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 = cs.slice->getSPS()->getMaxCUHeight() > 64 ? 64 : cs.slice->getSPS()->getMaxCUHeight(); if((currCU.Y().x % vSize) == 0 && (currCU.Y().y % vSize) == 0) { m_pcInterPred->resetVPDUforIBC(cs.pcv->chrFormat, cs.slice->getSPS()->getMaxCUHeight(), vSize, currCU.Y().x, currCU.Y().y); } } #if !JVET_P0400_REMOVE_SHARED_MERGE_LIST if(sharePrepareCondition) { if ((currCU.shareParentPos.x >= 0) && (!(currCU.shareParentPos.x == prevTmpPos.x && currCU.shareParentPos.y == prevTmpPos.y))) { m_shareStateDec = GEN_ON_SHARED_BOUND; } if (currCU.shareParentPos.x < 0) { m_shareStateDec = 0; } prevTmpPos = currCU.shareParentPos; } #endif if (currCU.predMode != MODE_INTRA && currCU.predMode != MODE_PLT && currCU.Y().valid()) { xDeriveCUMV(currCU); } 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; } if( CU::isLosslessCoded( currCU ) ) { xFillPCMBuffer( currCU ); } 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 uiChFinalMode = 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 && 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( uiChFinalMode ) ) { const PredictionUnit& pu = *tu.cu->firstPU; m_pcIntraPred->xGetLumaRecPixels( pu, area ); m_pcIntraPred->predIntraChromaLM( compID, piPred, pu, area, uiChFinalMode ); } else { if( PU::isMIP( pu, chType ) ) { m_pcIntraPred->initIntraMip( pu ); 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.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, CHANNEL_TYPE_LUMA, tu.blocks[tu.chType].pos()), recalcSize(tu.chromaFormat, tu.chType, CHANNEL_TYPE_LUMA, tu.blocks[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.getLmcsChromaResidualScaleFlag()) { piResi.scaleSignal(tu.getChromaAdj(), 0, tu.cu->cs->slice->clpRng(compID)); } if( isChroma(compID) && tu.compAlpha[compID] != 0 ) { CrossComponentPrediction::crossComponentPrediction( tu, compID, cs.getResiBuf( tu.Y() ), piResi, piResi, true ); } if( !tu.cu->ispMode || !isLuma( compID ) ) { cs.setDecomp( area ); } else if( tu.cu->ispMode && 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_tmpStorageLCU->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 ) ); #endif #if !KEEP_PRED_AND_RESI_SIGNALS 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::xReconIntraQT( CodingUnit &cu ) { if (CU::isPLT(cu)) { if (cu.isSepTree()) { if (cu.chType == CHANNEL_TYPE_LUMA) { xReconPLT(cu, COMPONENT_Y, 1); } if (cu.chromaFormat != CHROMA_400 && (cu.chType == CHANNEL_TYPE_CHROMA)) { xReconPLT(cu, COMPONENT_Cb, 2); } } else { xReconPLT(cu, COMPONENT_Y, 3); } return; } const uint32_t numChType = ::getNumberValidChannels( cu.chromaFormat ); for( uint32_t chType = CHANNEL_TYPE_LUMA; chType < numChType; chType++ ) { if( cu.blocks[chType].valid() ) { xIntraRecQT( cu, ChannelType( 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]) { Pel value; QpParam cQP(tu, (ComponentID)compID); #if JVET_P0460_PLT_TS_MIN_QP int qp = cQP.Qp(true); #else int qp = cQP.Qp(false); #endif 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 = Pel(ClipBD<int>(value, channelBitDepth)); picReco.at(x, y) = 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 = Pel(ClipBD<int>(value, channelBitDepth)); picReco.at(posXC, posYC) = 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 ) ); } } } } /** Function for filling the PCM buffer of a CU using its reconstructed sample array * \param pCU pointer to current CU * \param depth CU Depth */ void DecCu::xFillPCMBuffer(CodingUnit &cu) { for( auto &currTU : CU::traverseTUs( cu ) ) { for (const CompArea &area : currTU.blocks) { if( !area.valid() ) continue;; CPelBuf source = cu.cs->getRecoBuf(area); PelBuf destination = currTU.getPcmbuf(area.compID); destination.copyFrom(source); } } } #include "CommonLib/dtrace_buffer.h" void DecCu::xReconInter(CodingUnit &cu) { if( cu.triangle ) { const bool splitDir = cu.firstPU->triangleSplitDir; const uint8_t candIdx0 = cu.firstPU->triangleMergeIdx0; const uint8_t candIdx1 = cu.firstPU->triangleMergeIdx1; m_pcInterPred->motionCompensation4Triangle( cu, m_triangleMrgCtx, splitDir, candIdx0, candIdx1 ); PU::spanTriangleMotionInfo( *cu.firstPU, m_triangleMrgCtx, splitDir, candIdx0, candIdx1 ); } else { m_pcIntraPred->geneIntrainterPred(cu); // inter prediction CHECK(CU::isIBC(cu) && cu.firstPU->mhIntraFlag, "IBC and MHIntra cannot be used together"); CHECK(CU::isIBC(cu) && cu.affine, "IBC and Affine cannot be used together"); CHECK(CU::isIBC(cu) && cu.triangle, "IBC and triangle 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 = cu.Cb().valid(); if (luma && chroma) { m_pcInterPred->motionCompensation(cu); } else { m_pcInterPred->motionCompensation(cu, REF_PIC_LIST_0, luma, chroma); } } if (cu.Y().valid()) { const PredictionUnit &pu = *cu.firstPU; #if JVET_P0400_REMOVE_SHARED_MERGE_LIST bool isIbcSmallBlk = CU::isIBC(cu) && (cu.lwidth() * cu.lheight() <= 16); if (!cu.affine && !cu.triangle && !isIbcSmallBlk) #else bool isShare = ((CU::isIBC(cu) && (cu.shareParentSize.width != cu.Y().lumaSize().width || cu.shareParentSize.height != cu.Y().lumaSize().height)) ? true : false); if (!cu.affine && !cu.triangle && !isShare) #endif { MotionInfo mi = pu.getMotionInfo(); mi.GBiIdx = (mi.interDir == 3) ? cu.GBiIdx : GBI_DEFAULT; cu.cs->addMiToLut(CU::isIBC(cu) ? cu.cs->motionLut.lutIbc : cu.cs->motionLut.lut, mi ); } } if (cu.firstPU->mhIntraFlag) { if (cu.cs->slice->getLmcsEnabledFlag() && m_pcReshape->getCTUFlag()) { cu.cs->getPredBuf(*cu.firstPU).Y().rspSignal(m_pcReshape->getFwdLUT()); } m_pcIntraPred->geneWeightedPred(COMPONENT_Y, cu.cs->getPredBuf(*cu.firstPU).Y(), *cu.firstPU, m_pcIntraPred->getPredictorPtr2(COMPONENT_Y, 0)); #if JVET_P0641_REMOVE_2xN_CHROMA_INTRA if (cu.chromaSize().width > 2) { #endif m_pcIntraPred->geneWeightedPred(COMPONENT_Cb, cu.cs->getPredBuf(*cu.firstPU).Cb(), *cu.firstPU, m_pcIntraPred->getPredictorPtr2(COMPONENT_Cb, 0)); m_pcIntraPred->geneWeightedPred(COMPONENT_Cr, cu.cs->getPredBuf(*cu.firstPU).Cr(), *cu.firstPU, m_pcIntraPred->getPredictorPtr2(COMPONENT_Cr, 0)); #if JVET_P0641_REMOVE_2xN_CHROMA_INTRA } #endif } 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_tmpStorageLCU->getBuf(tmpArea); tmpPred.copyFrom(cs.getPredBuf(cu).get(COMPONENT_Y)); } #endif if (!cu.firstPU->mhIntraFlag && !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->mhIntraFlag && !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); const 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 { const 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 (slice.getLmcsEnabledFlag() && isChroma(compID) && (TU::getCbf(currTU, compID) || currTU.jointCbCr) && slice.getLmcsChromaResidualScaleFlag() && currTU.blocks[compID].width * currTU.blocks[compID].height > 4) { resiBuf.scaleSignal(currTU.getChromaAdj(), 0, currTU.cu->cs->slice->clpRng(compID)); } if( isChroma( compID ) && currTU.compAlpha[compID] != 0 ) { CrossComponentPrediction::crossComponentPrediction( currTU, compID, cs.getResiBuf( currTU.Y() ), resiBuf, resiBuf, true ); } } void DecCu::xDecodeInterTexture(CodingUnit &cu) { if( !cu.rootCbf ) { return; } const uint32_t uiNumVaildComp = getNumberValidComponents(cu.chromaFormat); 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.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::xDeriveCUMV( 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.mhIntraFlag == true, "invalid MHIntra"); if (pu.cs->sps->getSBTMVPEnabledFlag()) { Size bufSize = g_miScaling.scale(pu.lumaSize()); mrgCtx.subPuMvpMiBuf = MotionBuf(m_SubPuMiBuf, bufSize); } int fPosBaseIdx = pu.mmvdMergeIdx / MMVD_MAX_REFINE_NUM; #if !JVET_P0400_REMOVE_SHARED_MERGE_LIST pu.shareParentPos = cu.shareParentPos; pu.shareParentSize = cu.shareParentSize; #endif PU::getInterMergeCandidates(pu, mrgCtx, 1, fPosBaseIdx + 1); PU::getInterMMVDMergeCandidates(pu, mrgCtx, pu.mmvdMergeIdx ); mrgCtx.setMmvdMergeCandiInfo(pu, pu.mmvdMergeIdx); PU::spanMotionInfo(pu, mrgCtx); } else { { if( pu.cu->triangle ) { PU::getTriangleMergeCandidates( pu, m_triangleMrgCtx ); } 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->GBiIdx = affineMergeCtx.GBiIdx[pu.mergeIdx]; pu.mergeType = affineMergeCtx.mergeType[pu.mergeIdx]; if ( pu.mergeType == MRG_TYPE_SUBPU_ATMVP ) { pu.refIdx[0] = affineMergeCtx.mvFieldNeighbours[(pu.mergeIdx << 1) + 0][0].refIdx; pu.refIdx[1] = affineMergeCtx.mvFieldNeighbours[(pu.mergeIdx << 1) + 1][0].refIdx; } else { for( int i = 0; i < 2; ++i ) { if( pu.cs->slice->getNumRefIdx( RefPicList( i ) ) > 0 ) { MvField* mvField = affineMergeCtx.mvFieldNeighbours[(pu.mergeIdx << 1) + i]; pu.mvpIdx[i] = 0; pu.mvpNum[i] = 0; pu.mvd[i] = Mv(); PU::setAllAffineMvField( pu, mvField, RefPicList( i ) ); } } } PU::spanMotionInfo( pu, mrgCtx ); } else { #if !JVET_P0400_REMOVE_SHARED_MERGE_LIST pu.shareParentPos = cu.shareParentPos; pu.shareParentSize = cu.shareParentSize; #endif 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 !JVET_P0400_REMOVE_SHARED_MERGE_LIST pu.shareParentPos = cu.shareParentPos; pu.shareParentSize = cu.shareParentSize; #endif #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 mvp_idx = pu.mvpIdx[eRefList]; pu.mvpNum[eRefList] = affineAMVPInfo.numCand; // Mv mv[3]; CHECK( pu.refIdx[eRefList] < 0, "Unexpected negative refIdx." ); if (!cu.cs->pcv->isEncoder) { pu.mvdAffi[eRefList][0].changeAffinePrecAmvr2Internal(pu.cu->imv); pu.mvdAffi[eRefList][1].changeAffinePrecAmvr2Internal(pu.cu->imv); if (cu.affineType == AFFINEMODEL_6PARAM) { pu.mvdAffi[eRefList][2].changeAffinePrecAmvr2Internal(pu.cu->imv); } } Mv mvLT = affineAMVPInfo.mvCandLT[mvp_idx] + pu.mvdAffi[eRefList][0]; Mv mvRT = affineAMVPInfo.mvCandRT[mvp_idx] + pu.mvdAffi[eRefList][1]; mvRT += pu.mvdAffi[eRefList][0]; Mv mvLB; if ( cu.affineType == AFFINEMODEL_6PARAM ) { mvLB = affineAMVPInfo.mvCandLB[mvp_idx] + 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.cu->slice->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].mvCliptoStorageBitDepth(); } 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].mvCliptoStorageBitDepth(); } } } PU::spanMotionInfo( pu, mrgCtx ); } } if( !cu.triangle ) { 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."); } } } //! \}