Skip to content
Snippets Groups Projects
IntraSearch.cpp 483 KiB
Newer Older
  • Learn to ignore specific revisions
  •             ctxBest = m_CABACEstimator->getCtx();
              }
    
    
        if (!lastIsBest)
        {
          csFull->getResiBuf(cbArea).copyFrom(saveChromaCS.getResiBuf(cbArea));
          csFull->getResiBuf(crArea).copyFrom(saveChromaCS.getResiBuf(crArea));
          csFull->getRecoBuf(tu).copyFrom(saveChromaCS.getRecoBuf(tu));
          tu.copyComponentFrom(*tmpTU, COMPONENT_Cb);
          tu.copyComponentFrom(*tmpTU, COMPONENT_Cr);
    
          m_CABACEstimator->getCtx() = ctxBest;
        }
        tu.jointCbCr = bestJointCbCr;
    
    Seungwook Hong's avatar
    Seungwook Hong committed
    #if JVET_Z0118_GDR
        csFull->updateReconMotIPM(tu);
    #else
    
        csFull->picture->getRecoBuf(tu).copyFrom(csFull->getRecoBuf(tu));
    
    Seungwook Hong's avatar
    Seungwook Hong committed
    #endif
    
    
        csFull->dist += bestDistJointCbCr;
        csFull->fracBits += bestBitsJointCbCr;
        csFull->cost = m_pcRdCost->calcRdCost(csFull->fracBits, csFull->dist);
      }
    
      bool validReturnSplit = false;
      if (bCheckSplit)
      {
        if (partitioner.canSplit(TU_MAX_TR_SPLIT, *csSplit))
        {
          partitioner.splitCurrArea(TU_MAX_TR_SPLIT, *csSplit);
        }
    
        bool splitIsSelected = true;
        do
        {
          bool tmpValidReturnSplit = xRecurIntraCodingACTQT(*csSplit, partitioner, mtsCheckRangeFlag, mtsFirstCheckId, mtsLastCheckId, moreProbMTSIdxFirst);
    
    #if JVET_AH0103_LOW_DELAY_LFNST_NSPT
          if( spsIntraLfnstEnabled )
    #else
    
          if (sps.getUseLFNST())
    
          {
            if (!tmpValidReturnSplit)
            {
              splitIsSelected = false;
              break;
            }
          }
          else
          {
            CHECK(!tmpValidReturnSplit, "invalid RD of sub-TU partitions for ACT");
          }
        } while (partitioner.nextPart(*csSplit));
    
        partitioner.exitCurrSplit();
    
        if (splitIsSelected)
        {
          unsigned compCbf[3] = { 0, 0, 0 };
          for (auto &currTU : csSplit->traverseTUs(currArea, partitioner.chType))
          {
            for (unsigned ch = 0; ch < getNumberValidTBlocks(*csSplit->pcv); ch++)
            {
              compCbf[ch] |= (TU::getCbfAtDepth(currTU, ComponentID(ch), currDepth + 1) ? 1 : 0);
            }
          }
    
          for (auto &currTU : csSplit->traverseTUs(currArea, partitioner.chType))
          {
            TU::setCbfAtDepth(currTU, COMPONENT_Y, currDepth, compCbf[COMPONENT_Y]);
            TU::setCbfAtDepth(currTU, COMPONENT_Cb, currDepth, compCbf[COMPONENT_Cb]);
            TU::setCbfAtDepth(currTU, COMPONENT_Cr, currDepth, compCbf[COMPONENT_Cr]);
          }
    
          m_CABACEstimator->getCtx() = ctxStart;
          csSplit->fracBits = xGetIntraFracBitsQT(*csSplit, partitioner, true, true, -1, TU_NO_ISP);
          csSplit->cost = m_pcRdCost->calcRdCost(csSplit->fracBits, csSplit->dist);
    
          validReturnSplit = true;
        }
      }
    
      bool retVal = false;
      if (csFull || csSplit)
      {
    
    #if JVET_AH0103_LOW_DELAY_LFNST_NSPT
        if( spsIntraLfnstEnabled )
    #else
    
        if (sps.getUseLFNST())
    
        {
          if (validReturnFull || validReturnSplit)
          {
            retVal = true;
          }
        }
        else
        {
          CHECK(!validReturnFull && !validReturnSplit, "illegal TU optimization");
          retVal = true;
        }
      }
      return retVal;
    }
    
    
    ChromaCbfs IntraSearch::xRecurIntraChromaCodingQT( CodingStructure &cs, Partitioner& partitioner, const double bestCostSoFar, const PartSplit ispType 
    
    #if JVET_AB0143_CCCM_TS || JVET_AC0119_LM_CHROMA_FUSION
      , const PelUnitBuf& predStorage
    
    #if JVET_AD0208_IBC_ADAPT_FOR_CAM_CAPTURED_CONTENTS
      , InterPrediction* pcInterPred
    #endif
    
      const bool keepResi                 = cs.sps->getUseLMChroma() || KEEP_PRED_AND_RESI_SIGNALS;
    
      if( !currArea.Cb().valid() ) return ChromaCbfs( false );
    
      const Slice           &slice = *cs.slice;
    
    
      TransformUnit &currTU               = *cs.getTU( currArea.chromaPos(), CHANNEL_TYPE_CHROMA );
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #if JVET_AD0188_CCP_MERGE
      PredictionUnit &pu                  = *cs.getPU( currArea.chromaPos(), CHANNEL_TYPE_CHROMA );
    #else
    
      const PredictionUnit &pu            = *cs.getPU( currArea.chromaPos(), CHANNEL_TYPE_CHROMA );
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #endif
    
      uint32_t     currDepth                  = partitioner.currTrDepth;
      ChromaCbfs cbfs                     ( false );
    
      if (currDepth == currTU.depth)
      {
        if (!currArea.Cb().valid() || !currArea.Cr().valid())
        {
          return cbfs;
        }
    
        CodingStructure &saveCS = *m_pSaveCS[1];
        saveCS.pcv      = cs.pcv;
        saveCS.picture  = cs.picture;
    
    Seungwook Hong's avatar
    Seungwook Hong committed
    #if JVET_Z0118_GDR
        saveCS.m_pt = cs.m_pt;
    #endif
    
        saveCS.initStructData( MAX_INT, true );
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #if !INTRA_RM_SMALL_BLOCK_SIZE_CONSTRAINTS
    
        if( !currTU.cu->isSepTree() && currTU.cu->ispMode )
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #else
        if (!CS::isDualITree(cs) && currTU.cu->ispMode)
    #endif
    
        {
          saveCS.clearCUs();
          CodingUnit& auxCU = saveCS.addCU( *currTU.cu, partitioner.chType );
          auxCU.ispMode = currTU.cu->ispMode;
          saveCS.sps = currTU.cs->sps;
          saveCS.clearPUs();
          saveCS.addPU( *currTU.cu->firstPU, partitioner.chType );
        }
    
    
        TransformUnit &tmpTU = saveCS.addTU(currArea, partitioner.chType);
    
    
    #if !(JVET_AD0208_IBC_ADAPT_FOR_CAM_CAPTURED_CONTENTS && JVET_AC0071_DBV)
    
        cs.setDecomp(currArea.Cb(), true); // set in advance (required for Cb2/Cr2 in 4:2:2 video)
    
    
        const unsigned      numTBlocks  = ::getNumberValidTBlocks( *cs.pcv );
    
        CompArea&  cbArea         = currTU.blocks[COMPONENT_Cb];
        CompArea&  crArea         = currTU.blocks[COMPONENT_Cr];
        double     bestCostCb     = MAX_DOUBLE;
        double     bestCostCr     = MAX_DOUBLE;
        Distortion bestDistCb     = 0;
        Distortion bestDistCr     = 0;
        int        maxModesTested = 0;
        bool       earlyExitISP   = false;
    
    Vadim Seregin's avatar
    Vadim Seregin committed
        TempCtx ctxStartTU( m_ctxCache );
        TempCtx ctxStart  ( m_ctxCache );
        TempCtx ctxBest   ( m_ctxCache );
    
        ctxStartTU       = m_CABACEstimator->getCtx();
        currTU.jointCbCr = 0;
    
        // Do predictions here to avoid repeating the "default0Save1Load2" stuff
    
        int  predMode   = pu.cu->bdpcmModeChroma ? BDPCM_IDX : PU::getFinalIntraMode(pu, CHANNEL_TYPE_CHROMA);
    
    #if JVET_AD0208_IBC_ADAPT_FOR_CAM_CAPTURED_CONTENTS && JVET_AC0071_DBV
    
    #if JVET_AH0136_CHROMA_REORDERING
        if (!PU::isDbvMode(predMode) || pu.isChromaFusion > 0)
    #else
    
        {
          cs.setDecomp(currArea.Cb(), true); // set in advance (required for Cb2/Cr2 in 4:2:2 video)
        }
    #endif
    
    #if JVET_AH0136_CHROMA_REORDERING && JVET_AC0071_DBV
        if (pu.cs->sps->getUseChromaReordering() && PU::isDbvMode(predMode) && CS::isDualITree(cs))
        {
          pu.bv = pu.cu->bvs[predMode - DBV_CHROMA_IDX];
          pu.mv[0] = pu.cu->mvs[predMode - DBV_CHROMA_IDX];
          pu.cu->rribcFlipType = pu.cu->rribcTypes[predMode - DBV_CHROMA_IDX];
        }
    #endif
    
        PelBuf piPredCb = cs.getPredBuf(cbArea);
        PelBuf piPredCr = cs.getPredBuf(crArea);
    
        initIntraPatternChType( *currTU.cu, cbArea);
        initIntraPatternChType( *currTU.cu, crArea);
    
    #if JVET_AG0154_DECODER_DERIVED_CCP_FUSION	  
        if (pu.decoderDerivedCcpMode)
        {
          if (!predStorage.bufs.empty())
          {
            piPredCb.copyFrom(predStorage.Cb());
            piPredCr.copyFrom(predStorage.Cr());
          }
          else
          {
            if (pu.cccmFlag)
            {
              predIntraCCCM(pu, piPredCb, piPredCr, predMode);
            }
            else
            {
              CclmModel modelsCb, modelsCr;
              PU::ccpParamsToCclmModel(COMPONENT_Cb, pu.curCand, modelsCb);
              PU::ccpParamsToCclmModel(COMPONENT_Cr, pu.curCand, modelsCr);
              predIntraChromaLM(COMPONENT_Cb, piPredCb, pu, cbArea, predMode, false, &modelsCb);
              predIntraChromaLM(COMPONENT_Cr, piPredCr, pu, crArea, predMode, false, &modelsCr);
            }
            predDecoderDerivedIntraCCCMFusions(pu, piPredCb, piPredCr, m_decoderDerivedCcpList);
            PelBuf   predCb = m_ddCcpStorageTemp.Cb();
            PelBuf   predCr = m_ddCcpStorageTemp.Cr();
            predCb.copyFrom(piPredCb);
            predCr.copyFrom(piPredCr);
            firstTransformDdccp = false;
          }
        }
        else
    #endif
    
    #if JVET_AG0154_DECODER_DERIVED_CCP_FUSION
          if (pu.ddNonLocalCCPFusion > 0)
          {
            piPredCb.copyFrom(predStorage.Cb());
            piPredCr.copyFrom(predStorage.Cr());
          }
          else
          {
    #endif
    
          if (!predStorage.bufs.empty())
          {
            piPredCb.copyFrom(predStorage.Cb());
            piPredCr.copyFrom(predStorage.Cr());
          }
          else
          {
            predCCPCandidate(pu, piPredCb, piPredCr);
          }
    
    #if JVET_AG0154_DECODER_DERIVED_CCP_FUSION
          }
    #endif
    
    #if JVET_AD0120_LBCCP
        if (pu.ccInsideFilter && PU::isLMCMode( predMode ) && !predStorage.bufs.empty())
        {
            piPredCb.copyFrom(predStorage.Cb());
            piPredCr.copyFrom(predStorage.Cr());
        }
        else
    #endif
    
    Jani Lainema's avatar
    Jani Lainema committed
    #if JVET_AA0057_CCCM
        if( pu.cccmFlag )
        {
    
    #if JVET_AE0100_BVGCCCM
          if (pu.bvgCccmFlag)
          {
            xGetLumaRecPixels( pu, cbArea );
            predIntraCCCM( pu, piPredCb, piPredCr, predMode );
          }
          else
    #endif
    
    #if JVET_AB0143_CCCM_TS
    
          if (pu.cs->slice->isIntra() && !predStorage.bufs.empty())
    
            piPredCb.copyFrom(predStorage.Cb());
            piPredCr.copyFrom(predStorage.Cr());
    
          }
          else
          {
            predIntraCCCM(pu, piPredCb, piPredCr, predMode);
          }
    #else
    
    Jani Lainema's avatar
    Jani Lainema committed
          xGetLumaRecPixels( pu, cbArea );
          predIntraCCCM( pu, piPredCb, piPredCr, predMode );
    
    Jani Lainema's avatar
    Jani Lainema committed
        }
        else
    #endif
    
        if( PU::isLMCMode( predMode ) )
        {
          xGetLumaRecPixels( pu, cbArea );
          predIntraChromaLM( COMPONENT_Cb, piPredCb, pu, cbArea, predMode );
    
    #if JVET_AA0126_GLM && !JVET_AB0092_GLM_WITH_LUMA
    
    Che-Wei Kuo's avatar
    Che-Wei Kuo committed
          xGetLumaRecPixels( pu, crArea ); // generate GLM luma samples for Cr prediction
    #endif
    
          predIntraChromaLM( COMPONENT_Cr, piPredCr, pu, crArea, predMode );
        }
    
        else if (PU::isMIP(pu, CHANNEL_TYPE_CHROMA))
        {
          initIntraMip(pu, cbArea);
          predIntraMip(COMPONENT_Cb, piPredCb, pu);
    
          initIntraMip(pu, crArea);
          predIntraMip(COMPONENT_Cr, piPredCr, pu);
        }
    
    #if JVET_AC0119_LM_CHROMA_FUSION
    
          if (pu.cs->slice->isIntra() && pu.isChromaFusion && !predStorage.bufs.empty())
    
          {
            piPredCb.copyFrom(predStorage.Cb());
            piPredCr.copyFrom(predStorage.Cr());
          }
          else
          {
    #endif
    
    #if JVET_AH0136_CHROMA_REORDERING
          if (PU::isDbvMode(predMode))
    #else
    
          if (predMode == DBV_CHROMA_IDX)
    
            predIntraDbv(COMPONENT_Cb, piPredCb, pu
    #if JVET_AD0208_IBC_ADAPT_FOR_CAM_CAPTURED_CONTENTS
                                      , pcInterPred
    #endif
            );
            predIntraDbv(COMPONENT_Cr, piPredCr, pu
    #if JVET_AD0208_IBC_ADAPT_FOR_CAM_CAPTURED_CONTENTS
                                      , pcInterPred
    #endif
            );
    #if JVET_AD0208_IBC_ADAPT_FOR_CAM_CAPTURED_CONTENTS && JVET_AC0071_DBV
    
    #if JVET_AH0136_CHROMA_REORDERING
            if (pu.isChromaFusion == 0)
    #endif
    
            cs.setDecomp(currArea.Cb(), true); // set in advance (required for Cb2/Cr2 in 4:2:2 video)
    #endif
    
          predIntraAng( COMPONENT_Cb, piPredCb, pu);
          predIntraAng( COMPONENT_Cr, piPredCr, pu);
    
    #if JVET_Z0050_DIMD_CHROMA_FUSION
          if (pu.isChromaFusion)
          {
    
            geneChromaFusionPred(COMPONENT_Cb, piPredCb, pu
    #if JVET_AH0136_CHROMA_REORDERING
              , pcInterPred
    #endif
            );
            geneChromaFusionPred(COMPONENT_Cr, piPredCr, pu
    #if JVET_AH0136_CHROMA_REORDERING
              , pcInterPred
    #endif
            );
    
    #if JVET_AC0119_LM_CHROMA_FUSION
          }
    #endif
          }
    
        // determination of chroma residuals including reshaping and cross-component prediction
        //----- get chroma residuals -----
        PelBuf resiCb  = cs.getResiBuf(cbArea);
        PelBuf resiCr  = cs.getResiBuf(crArea);
    
    #if JVET_AC0071_DBV && JVET_AA0070_RRIBC
    
    #if JVET_AH0136_CHROMA_REORDERING
        if (PU::isDbvMode(predMode) && currTU.cu->rribcFlipType)
    #else
    
        if (predMode == DBV_CHROMA_IDX && currTU.cu->rribcFlipType)
    
        {
          resiCb.copyFrom(cs.getOrgBuf(cbArea));
          resiCr.copyFrom(cs.getOrgBuf(crArea));
          resiCb.flipSignal(currTU.cu->rribcFlipType == 1);
          resiCr.flipSignal(currTU.cu->rribcFlipType == 1);
          resiCb.subtract(piPredCb);
          resiCr.subtract(piPredCr);
        }
        else
        {
    #endif
    
        resiCb.copyFrom( cs.getOrgBuf (cbArea) );
        resiCr.copyFrom( cs.getOrgBuf (crArea) );
        resiCb.subtract( piPredCb );
        resiCr.subtract( piPredCr );
    
    #if JVET_AC0071_DBV && JVET_AA0070_RRIBC
        }
    #endif
    
        bool doReshaping = ( cs.slice->getLmcsEnabledFlag() && cs.picHeader->getLmcsChromaResidualScaleFlag()
                             && (cs.slice->isIntra() || m_pcReshape->getCTUFlag()) && (cbArea.width * cbArea.height > 4) );
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #if LMCS_CHROMA_CALC_CU
          const Area area = currTU.cu->Y().valid() ? currTU.cu->Y() : Area(recalcPosition(currTU.chromaFormat, currTU.chType, CHANNEL_TYPE_LUMA, currTU.cu->blocks[currTU.chType].pos()), recalcSize(currTU.chromaFormat, currTU.chType, CHANNEL_TYPE_LUMA, currTU.cu->blocks[currTU.chType].size()));
    #else
    
          const Area area = currTU.Y().valid() ? currTU.Y() : Area(recalcPosition(currTU.chromaFormat, currTU.chType, CHANNEL_TYPE_LUMA, currTU.blocks[currTU.chType].pos()), recalcSize(currTU.chromaFormat, currTU.chType, CHANNEL_TYPE_LUMA, currTU.blocks[currTU.chType].size()));
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #endif
    
          const CompArea &areaY = CompArea(COMPONENT_Y, currTU.chromaFormat, area);
          int adj = m_pcReshape->calculateChromaAdjVpduNei(currTU, areaY);
    
          currTU.setChromaAdj(adj);
        }
    
        //----- get cross component prediction parameters -----
    
        //===== store original residual signals =====
        CompStorage  orgResiCb[4], orgResiCr[4]; // 0:std, 1-3:jointCbCr (placeholder at this stage)
        orgResiCb[0].create( cbArea );
        orgResiCr[0].create( crArea );
        orgResiCb[0].copyFrom( resiCb );
        orgResiCr[0].copyFrom( resiCr );
        if( doReshaping )
        {
          int cResScaleInv = currTU.getChromaAdj();
          orgResiCb[0].scaleSignal( cResScaleInv, 1, currTU.cu->cs->slice->clpRng(COMPONENT_Cb) );
          orgResiCr[0].scaleSignal( cResScaleInv, 1, currTU.cu->cs->slice->clpRng(COMPONENT_Cr) );
        }
    
        for( uint32_t c = COMPONENT_Cb; c < numTBlocks; c++)
        {
          const ComponentID compID  = ComponentID(c);
          const CompArea&   area    = currTU.blocks[compID];
    
          double     dSingleCost    = MAX_DOUBLE;
          int        bestModeId     = 0;
          Distortion singleDistCTmp = 0;
          double     singleCostTmp  = 0;
    
          const bool tsAllowed = TU::isTSAllowed(currTU, compID) && m_pcEncCfg->getUseChromaTS() && !currTU.cu->lfnstIdx;
    
          uint8_t nNumTransformCands = 1 + (tsAllowed ? 1 : 0); // DCT + TS = 2 tests
          std::vector<TrMode> trModes;
    
          if (m_pcEncCfg->getCostMode() == COST_LOSSLESS_CODING && slice.isLossless())
    
          {
            nNumTransformCands = 1;
            CHECK(!tsAllowed && !currTU.cu->bdpcmModeChroma, "transform skip should be enabled for LS");
            if (currTU.cu->bdpcmModeChroma)
            {
              trModes.push_back(TrMode(0, true));
            }
            else
            {
              trModes.push_back(TrMode(1, true));
            }
          }
          else
          {
    
            trModes.push_back(TrMode(0, true));   // DCT2
    
            if (tsAllowed)
            {
              trModes.push_back(TrMode(1, true));   // TS
            }
    
          CHECK(!currTU.Cb().valid(), "Invalid TU");
    
    
          const int  totalModesToTest            = nNumTransformCands;
    
          bool cbfDCT2 = true;
    
          const bool isOneMode                   = false;
          maxModesTested                         = totalModesToTest > maxModesTested ? totalModesToTest : maxModesTested;
    
          int currModeId = 0;
          int default0Save1Load2 = 0;
    
          if (!isOneMode)
          {
            ctxStart = m_CABACEstimator->getCtx();
          }
    
    
          for (int modeId = 0; modeId < nNumTransformCands; modeId++)
    
            resiCb.copyFrom(orgResiCb[0]);
            resiCr.copyFrom(orgResiCr[0]);
            currTU.mtsIdx[compID] = currTU.cu->bdpcmModeChroma ? MTS_SKIP : trModes[modeId].first;
    
            const bool isFirstMode = (currModeId == 1);
            const bool isLastMode  = false;   // Always store output to saveCS and tmpTU
            if (!(m_pcEncCfg->getCostMode() == COST_LOSSLESS_CODING && slice.isLossless()))
            {
              // if DCT2's cbf==0, skip ts search
    
              if (!cbfDCT2 && trModes[modeId].first == MTS_SKIP)
              {
                  break;
              }
              if (!trModes[modeId].second)
              {
                  continue;
              }
    
            if (!isFirstMode)   // if not first mode to be tested
            {
              m_CABACEstimator->getCtx() = ctxStart;
            }
    
            singleDistCTmp = 0;
    
            if (nNumTransformCands > 1)
            {
              xIntraCodingTUBlock(currTU, compID, singleDistCTmp, default0Save1Load2, nullptr,
                                  modeId == 0 ? &trModes : nullptr, true);
            }
            else
            {
              xIntraCodingTUBlock(currTU, compID, singleDistCTmp, default0Save1Load2);
            }
    
            if (((currTU.mtsIdx[compID] == MTS_SKIP && !currTU.cu->bdpcmModeChroma)
                 && !TU::getCbf(currTU, compID)))   // In order not to code TS flag when cbf is zero, the case for TS with
                                                    // cbf being zero is forbidden.
            {
              if (m_pcEncCfg->getCostMode() != COST_LOSSLESS_CODING || !slice.isLossless())
    
                singleCostTmp = MAX_DOUBLE;
    
                uint64_t fracBitsTmp = xGetIntraFracBitsQTChroma(currTU, compID);
                singleCostTmp        = m_pcRdCost->calcRdCost(fracBitsTmp, singleDistCTmp);
    
            }
            else if (lumaUsesISP && bestCostSoFar != MAX_DOUBLE && c == COMPONENT_Cb)
            {
              uint64_t fracBitsTmp = xGetIntraFracBitsQTSingleChromaComponent(cs, partitioner, ComponentID(c));
              singleCostTmp        = m_pcRdCost->calcRdCost(fracBitsTmp, singleDistCTmp);
              if (isOneMode || (!isOneMode && !isLastMode))
    
                m_CABACEstimator->getCtx() = ctxStart;
    
            }
            else if (!isOneMode)
            {
              uint64_t fracBitsTmp = xGetIntraFracBitsQTChroma(currTU, compID);
              singleCostTmp        = m_pcRdCost->calcRdCost(fracBitsTmp, singleDistCTmp);
            }
    
            if (singleCostTmp < dSingleCost)
            {
              dSingleCost = singleCostTmp;
              bestModeId  = currModeId;
    
              if (c == COMPONENT_Cb)
    
                bestCostCb = singleCostTmp;
                bestDistCb = singleDistCTmp;
    
                bestCostCr = singleCostTmp;
                bestDistCr = singleDistCTmp;
    
              if (currTU.mtsIdx[compID] == MTS_DCT2_DCT2)
    
                cbfDCT2 = TU::getCbfAtDepth(currTU, compID, currDepth);
              }
    
                saveCS.getPredBuf(area).copyFrom(cs.getPredBuf(area));
                saveCS.getOrgResiBuf(area).copyFrom(cs.getOrgResiBuf(area));
    
    Taoran Lu's avatar
    Taoran Lu committed
    #endif
    
                saveCS.getPredBuf(area).copyFrom(cs.getPredBuf(area));
                if (keepResi)
                {
                  saveCS.getResiBuf(area).copyFrom(cs.getResiBuf(area));
                }
                saveCS.getRecoBuf(area).copyFrom(cs.getRecoBuf(area));
    
                tmpTU.copyComponentFrom(currTU, compID);
    
                ctxBest = m_CABACEstimator->getCtx();
    
          if( lumaUsesISP && dSingleCost > bestCostSoFar && c == COMPONENT_Cb )
          {
            //Luma + Cb cost is already larger than the best cost, so we don't need to test Cr
            cs.dist = MAX_UINT;
            m_CABACEstimator->getCtx() = ctxStart;
    
            earlyExitISP               = true;
    
          // Done with one component of separate coding of Cr and Cb, just switch to the best Cb contexts if Cr coding is still to be done
    
          if ((c == COMPONENT_Cb && bestModeId < totalModesToTest) || (c == COMPONENT_Cb && m_pcEncCfg->getCostMode() == COST_LOSSLESS_CODING && slice.isLossless()))
    
          {
            m_CABACEstimator->getCtx() = ctxBest;
    
            currTU.copyComponentFrom(tmpTU, COMPONENT_Cb); // Cbf of Cb is needed to estimate cost for Cr Cbf
          }
        }
    
        if ( !earlyExitISP )
        {
          // Test using joint chroma residual coding
          double     bestCostCbCr   = bestCostCb + bestCostCr;
          Distortion bestDistCbCr   = bestDistCb + bestDistCr;
          int        bestJointCbCr  = 0;
    
          std::vector<int>  jointCbfMasksToTest;
    
          if ( cs.sps->getJointCbCrEnabledFlag() && (TU::getCbf(tmpTU, COMPONENT_Cb) || TU::getCbf(tmpTU, COMPONENT_Cr)))
    
    Fangdong Chen's avatar
    Fangdong Chen committed
            jointCbfMasksToTest = m_pcTrQuant->selectICTCandidates(currTU, orgResiCb, orgResiCr);
    
          bool checkDCTOnly = (TU::getCbf(tmpTU, COMPONENT_Cb) && tmpTU.mtsIdx[COMPONENT_Cb] == MTS_DCT2_DCT2 && !TU::getCbf(tmpTU, COMPONENT_Cr)) ||
                              (TU::getCbf(tmpTU, COMPONENT_Cr) && tmpTU.mtsIdx[COMPONENT_Cr] == MTS_DCT2_DCT2 && !TU::getCbf(tmpTU, COMPONENT_Cb)) ||
                              (TU::getCbf(tmpTU, COMPONENT_Cb) && tmpTU.mtsIdx[COMPONENT_Cb] == MTS_DCT2_DCT2 && TU::getCbf(tmpTU, COMPONENT_Cr) && tmpTU.mtsIdx[COMPONENT_Cr] == MTS_DCT2_DCT2);
    
          bool checkTSOnly = (TU::getCbf(tmpTU, COMPONENT_Cb) && tmpTU.mtsIdx[COMPONENT_Cb] == MTS_SKIP && !TU::getCbf(tmpTU, COMPONENT_Cr)) ||
                             (TU::getCbf(tmpTU, COMPONENT_Cr) && tmpTU.mtsIdx[COMPONENT_Cr] == MTS_SKIP && !TU::getCbf(tmpTU, COMPONENT_Cb)) ||
                             (TU::getCbf(tmpTU, COMPONENT_Cb) && tmpTU.mtsIdx[COMPONENT_Cb] == MTS_SKIP && TU::getCbf(tmpTU, COMPONENT_Cr) && tmpTU.mtsIdx[COMPONENT_Cr] == MTS_SKIP);
    
          if (jointCbfMasksToTest.size() && currTU.cu->bdpcmModeChroma)
          {
            CHECK(!checkTSOnly || checkDCTOnly, "bdpcm only allows transform skip");
          }
    
          for( int cbfMask : jointCbfMasksToTest )
    
            currTU.jointCbCr               = (uint8_t)cbfMask;
    
            ComponentID codeCompId = ((currTU.jointCbCr >> 1) ? COMPONENT_Cb : COMPONENT_Cr);
            ComponentID otherCompId = ((codeCompId == COMPONENT_Cb) ? COMPONENT_Cr : COMPONENT_Cb);
    
            bool        tsAllowed = TU::isTSAllowed(currTU, codeCompId) && (m_pcEncCfg->getUseChromaTS()) && !currTU.cu->lfnstIdx;
    
            uint8_t     numTransformCands = 1 + (tsAllowed ? 1 : 0); // DCT + TS = 2 tests
            bool        cbfDCT2 = true;
    
            std::vector<TrMode> trModes;
            if (checkDCTOnly || checkTSOnly)
            {
              numTransformCands = 1;
            }
    
            if (!checkTSOnly || currTU.cu->bdpcmModeChroma)
            {
    
              trModes.push_back(TrMode(0, true)); // DCT2
    
            }
            if (tsAllowed && !checkDCTOnly)
            {
              trModes.push_back(TrMode(1, true));//TS
            }
            for (int modeId = 0; modeId < numTransformCands; modeId++)
            {
              if (modeId && !cbfDCT2)
              {
                continue;
              }
              if (!trModes[modeId].second)
              {
                continue;
              }
              Distortion distTmp = 0;
              currTU.mtsIdx[codeCompId] = currTU.cu->bdpcmModeChroma ? MTS_SKIP : trModes[modeId].first;
              currTU.mtsIdx[otherCompId] = MTS_DCT2_DCT2;
    
              m_CABACEstimator->getCtx() = ctxStartTU;
    
              resiCb.copyFrom(orgResiCb[cbfMask]);
              resiCr.copyFrom(orgResiCr[cbfMask]);
              if (numTransformCands > 1)
    
                xIntraCodingTUBlock(currTU, COMPONENT_Cb, distTmp, 0, nullptr, modeId == 0 ? &trModes : nullptr, true);
              }
              else
              {
                xIntraCodingTUBlock(currTU, COMPONENT_Cb, distTmp, 0);
              }
              double costTmp = std::numeric_limits<double>::max();
              if (distTmp < std::numeric_limits<Distortion>::max())
              {
                uint64_t bits = xGetIntraFracBitsQTChroma(currTU, COMPONENT_Cb);
                costTmp       = m_pcRdCost->calcRdCost(bits, distTmp);
                if (!currTU.mtsIdx[codeCompId])
                {
                  cbfDCT2 = true;
                }
              }
              else if (!currTU.mtsIdx[codeCompId])
              {
                cbfDCT2 = false;
    
              if (costTmp < bestCostCbCr)
    
                bestCostCbCr  = costTmp;
                bestDistCbCr  = distTmp;
                bestJointCbCr = currTU.jointCbCr;
    
                // store data
                {
    
    #if KEEP_PRED_AND_RESI_SIGNALS
    
                  saveCS.getOrgResiBuf(cbArea).copyFrom(cs.getOrgResiBuf(cbArea));
                  saveCS.getOrgResiBuf(crArea).copyFrom(cs.getOrgResiBuf(crArea));
    
                  saveCS.getPredBuf(cbArea).copyFrom(cs.getPredBuf(cbArea));
                  saveCS.getPredBuf(crArea).copyFrom(cs.getPredBuf(crArea));
                  if (keepResi)
                  {
                    saveCS.getResiBuf(cbArea).copyFrom(cs.getResiBuf(cbArea));
                    saveCS.getResiBuf(crArea).copyFrom(cs.getResiBuf(crArea));
                  }
                  saveCS.getRecoBuf(cbArea).copyFrom(cs.getRecoBuf(cbArea));
                  saveCS.getRecoBuf(crArea).copyFrom(cs.getRecoBuf(crArea));
    
                  tmpTU.copyComponentFrom(currTU, COMPONENT_Cb);
                  tmpTU.copyComponentFrom(currTU, COMPONENT_Cr);
    
                  ctxBest = m_CABACEstimator->getCtx();
                }
    
          // Retrieve the best CU data (unless it was the very last one tested)
          {
    #if KEEP_PRED_AND_RESI_SIGNALS
            cs.getPredBuf   (cbArea).copyFrom(saveCS.getPredBuf   (cbArea));
            cs.getOrgResiBuf(cbArea).copyFrom(saveCS.getOrgResiBuf(cbArea));
            cs.getPredBuf   (crArea).copyFrom(saveCS.getPredBuf   (crArea));
            cs.getOrgResiBuf(crArea).copyFrom(saveCS.getOrgResiBuf(crArea));
    #endif
            cs.getPredBuf   (cbArea).copyFrom(saveCS.getPredBuf   (cbArea));
            cs.getPredBuf   (crArea).copyFrom(saveCS.getPredBuf   (crArea));
    
            if( keepResi )
            {
              cs.getResiBuf (cbArea).copyFrom(saveCS.getResiBuf   (cbArea));
              cs.getResiBuf (crArea).copyFrom(saveCS.getResiBuf   (crArea));
            }
            cs.getRecoBuf   (cbArea).copyFrom(saveCS.getRecoBuf   (cbArea));
            cs.getRecoBuf   (crArea).copyFrom(saveCS.getRecoBuf   (crArea));
    
            currTU.copyComponentFrom(tmpTU, COMPONENT_Cb);
            currTU.copyComponentFrom(tmpTU, COMPONENT_Cr);
    
            m_CABACEstimator->getCtx() = ctxBest;
          }
    
          // Copy results to the picture structures
    
    Seungwook Hong's avatar
    Seungwook Hong committed
    #if JVET_Z0118_GDR
          cs.updateReconMotIPM(cbArea);
    #else
    
          cs.picture->getRecoBuf(cbArea).copyFrom(cs.getRecoBuf(cbArea));
    
    Seungwook Hong's avatar
    Seungwook Hong committed
    #endif
    
    #if JVET_Z0118_GDR
          cs.updateReconMotIPM(crArea);
    #else
    
          cs.picture->getRecoBuf(crArea).copyFrom(cs.getRecoBuf(crArea));
    
    Seungwook Hong's avatar
    Seungwook Hong committed
    #endif
    
          cs.picture->getPredBuf(cbArea).copyFrom(cs.getPredBuf(cbArea));
          cs.picture->getPredBuf(crArea).copyFrom(cs.getPredBuf(crArea));
    
          cbfs.cbf(COMPONENT_Cb) = TU::getCbf(currTU, COMPONENT_Cb);
          cbfs.cbf(COMPONENT_Cr) = TU::getCbf(currTU, COMPONENT_Cr);
    
          currTU.jointCbCr = ( (cbfs.cbf(COMPONENT_Cb) + cbfs.cbf(COMPONENT_Cr)) ? bestJointCbCr : 0 );
    
          cs.dist         += bestDistCbCr;
    
        }
      }
      else
      {
        unsigned    numValidTBlocks   = ::getNumberValidTBlocks( *cs.pcv );
        ChromaCbfs  SplitCbfs         ( false );
    
        if( partitioner.canSplit( TU_MAX_TR_SPLIT, cs ) )
        {
          partitioner.splitCurrArea( TU_MAX_TR_SPLIT, cs );
        }
    
        else if( currTU.cu->ispMode )
        {
          partitioner.splitCurrArea( ispType, cs );
        }
    
    #if JVET_AD0120_LBCCP
          ChromaCbfs subCbfs = xRecurIntraChromaCodingQT(cs, partitioner, bestCostSoFar, ispType, predStorage
    #if JVET_AD0208_IBC_ADAPT_FOR_CAM_CAPTURED_CONTENTS
                                                         , pcInterPred
    #endif
          );
    #else
          ChromaCbfs subCbfs = xRecurIntraChromaCodingQT(cs, partitioner, bestCostSoFar, ispType
    
    #if JVET_AD0208_IBC_ADAPT_FOR_CAM_CAPTURED_CONTENTS && (JVET_AB0143_CCCM_TS || JVET_AC0119_LM_CHROMA_FUSION)
    
    #endif
    #if JVET_AD0208_IBC_ADAPT_FOR_CAM_CAPTURED_CONTENTS
    
    
          for( uint32_t ch = COMPONENT_Cb; ch < numValidTBlocks; ch++ )
          {
            const ComponentID compID = ComponentID( ch );
            SplitCbfs.cbf( compID ) |= subCbfs.cbf( compID );
          }
        } while( partitioner.nextPart( cs ) );
    
        partitioner.exitCurrSplit();
    
    
        if( lumaUsesISP && cs.dist == MAX_UINT )
        {
          return cbfs;
        }
    
        cbfs.Cb |= SplitCbfs.Cb;
        cbfs.Cr |= SplitCbfs.Cr;
    
        if (!lumaUsesISP)
        {
          for (auto &ptu: cs.tus)
    
            if (currArea.Cb().contains(ptu->Cb()) || (!ptu->Cb().valid() && currArea.Y().contains(ptu->Y())))
    
              TU::setCbfAtDepth(*ptu, COMPONENT_Cb, currDepth, SplitCbfs.Cb);
              TU::setCbfAtDepth(*ptu, COMPONENT_Cr, currDepth, SplitCbfs.Cr);
    
        }
      }
    
      return cbfs;
    }
    
    uint64_t IntraSearch::xFracModeBitsIntra(PredictionUnit &pu, const uint32_t &uiMode, const ChannelType &chType)
    {
    
    Vadim Seregin's avatar
    Vadim Seregin committed
      uint8_t orgMode = uiMode;
    
    #if JVET_Y0065_GPM_INTRA
      if (!pu.ciipFlag && !pu.gpmIntraFlag)
    #else
    
      std::swap(orgMode, pu.intraDir[chType]);
    
      m_CABACEstimator->resetBits();
    
      if( isLuma( chType ) )
      {
    
    #if JVET_Y0065_GPM_INTRA
        if (!pu.ciipFlag && !pu.gpmIntraFlag)
    #else
    
          m_CABACEstimator->intra_luma_pred_mode(pu);
        }
    
    #if JVET_Y0065_GPM_INTRA
      if ( !pu.ciipFlag && !pu.gpmIntraFlag )
    #else
    
      std::swap(orgMode, pu.intraDir[chType]);
    
      return m_CABACEstimator->getEstFracBits();
    }
    
    
    void IntraSearch::sortRdModeListFirstColorSpace(ModeInfo mode, double cost, char bdpcmMode, ModeInfo* rdModeList, double* rdCostList, char* bdpcmModeList, int& candNum)
    {
      if (candNum == 0)
      {
        rdModeList[0] = mode;
        rdCostList[0] = cost;
        bdpcmModeList[0] = bdpcmMode;
        candNum++;
        return;
      }
    
      int insertPos = -1;
      for (int pos = candNum - 1; pos >= 0; pos--)
      {
        if (cost < rdCostList[pos])
        {
          insertPos = pos;
        }
      }
    
      if (insertPos >= 0)
      {
        for (int i = candNum - 1; i >= insertPos; i--)
        {
          rdModeList[i + 1] = rdModeList[i];
          rdCostList[i + 1] = rdCostList[i];
          bdpcmModeList[i + 1] = bdpcmModeList[i];
        }
        rdModeList[insertPos] = mode;
        rdCostList[insertPos] = cost;
        bdpcmModeList[insertPos] = bdpcmMode;
        candNum++;
      }
      else
      {
        rdModeList[candNum] = mode;
        rdCostList[candNum] = cost;
        bdpcmModeList[candNum] = bdpcmMode;
        candNum++;
      }
    
      CHECK(candNum > FAST_UDI_MAX_RDMODE_NUM, "exceed intra mode candidate list capacity");
    
      return;
    }
    
    void IntraSearch::invalidateBestRdModeFirstColorSpace()
    {
      int numSaveRdClass = 4 * NUM_LFNST_NUM_PER_SET * 2;
      int savedRdModeListSize = FAST_UDI_MAX_RDMODE_NUM;
    
      for (int i = 0; i < numSaveRdClass; i++)
      {
        m_numSavedRdModeFirstColorSpace[i] = 0;
        for (int j = 0; j < savedRdModeListSize; j++)
        {
    
          m_savedRdModeFirstColorSpace[i][j] = ModeInfo(false, false, 0, NOT_INTRA_SUBPARTITIONS, 0);
    
          m_savedBDPCMModeFirstColorSpace[i][j] = 0;
          m_savedRdCostFirstColorSpace[i][j] = MAX_DOUBLE;
        }
      }
    }
    
    template<typename T, size_t N>
    
    void IntraSearch::reduceHadCandList(static_vector<T, N>& candModeList, static_vector<double, N>& candCostList, int& numModesForFullRD, const double thresholdHadCost, const double* mipHadCost, const PredictionUnit &pu, const bool fastMip
    #if JVET_AB0157_TMRL
      , const double* tmrlCostList
    #endif
    
    #if JVET_AC0105_DIRECTIONAL_PLANAR
      , const double* dirPlanarCostList
    #endif
    
    {
      const int maxCandPerType = numModesForFullRD >> 1;
      static_vector<ModeInfo, FAST_UDI_MAX_RDMODE_NUM> tempRdModeList;
      static_vector<double, FAST_UDI_MAX_RDMODE_NUM> tempCandCostList;
      const double minCost = candCostList[0];
      bool keepOneMip = candModeList.size() > numModesForFullRD;
    
      int numConv = 0;
      int numMip = 0;
      for (int idx = 0; idx < candModeList.size() - (keepOneMip?0:1); idx++)
      {
        bool addMode = false;
    
    Philipp Merkle's avatar
    Philipp Merkle committed
        const ModeInfo& orgMode = candModeList[idx];
    
    Philipp Merkle's avatar
    Philipp Merkle committed
        if (!orgMode.mipFlg)
    
          addMode = (numConv < 3);
          numConv += addMode ? 1:0;
    
          addMode = ( numMip < maxCandPerType || (candCostList[idx] < thresholdHadCost * minCost) || keepOneMip );
          keepOneMip = false;
          numMip += addMode ? 1:0;
        }
        if( addMode )
        {
    
    Philipp Merkle's avatar
    Philipp Merkle committed
          tempRdModeList.push_back(orgMode);
    
          tempCandCostList.push_back(candCostList[idx]);
        }