Skip to content
Snippets Groups Projects
IntraSearch.cpp 565 KiB
Newer Older
  • Learn to ignore specific revisions
  •       tmpRecChroma.copyFrom(piReco);
        }
    
    Vadim Seregin's avatar
    Vadim Seregin committed
      //===== update distortion =====
    #if WCG_EXT
      
    
        if (m_pcEncCfg->getLumaLevelToDeltaQPMapping().isEnabled() || (m_pcEncCfg->getLmcs()
    
    Vadim Seregin's avatar
    Vadim Seregin committed
          && slice.getLmcsEnabledFlag() && (m_pcReshape->getCTUFlag() || (isChroma(compID) && m_pcEncCfg->getReshapeIntraCMD()))))
        {
    
        
          const CPelBuf orgLuma = cs.getOrgBuf( cs.area.blocks[COMPONENT_Y] );
    
          if( isLuma( compID) )
    
    Vadim Seregin's avatar
    Vadim Seregin committed
          {
            if(!(m_pcEncCfg->getLumaLevelToDeltaQPMapping().isEnabled()))
            {
    
              tmpRecLuma.rspSignal(m_pcReshape->getInvLUT());
    
    Vadim Seregin's avatar
    Vadim Seregin committed
            }
    
    #if JVET_AF0112_BIF_DYNAMIC_SCALING
            bool applyBIF = pps.getUseBIF() && m_bilateralFilter->getApplyBIF(tu, compID);
    #else
            bool applyBIF = pps.getUseBIF() /*&& (uiAbsSum > 0)*/ && tu.cu->qp > 17 && 128 > std::max(tu.lumaSize().width, tu.lumaSize().height);
    #endif
            if(applyBIF)
    
    Vadim Seregin's avatar
    Vadim Seregin committed
            {
    
              CompArea compArea = tu.blocks[compID];
              PelBuf recIPredBuf = cs.slice->getPic()->getRecoBuf(compArea);
              if(!(m_pcEncCfg->getLumaLevelToDeltaQPMapping().isEnabled()))
              {
    
                m_bilateralFilter->bilateralFilterRDOdiamond5x5( compID, tmpRecLuma, tmpRecLuma, tmpRecLuma, tu.cu->qp, recIPredBuf, cs.slice->clpRng( compID ), tu, true, true, &m_pcReshape->getInvLUT() );
    
                std::vector<Pel> invLUT;
    
                m_bilateralFilter->bilateralFilterRDOdiamond5x5( compID, tmpRecLuma, tmpRecLuma, tmpRecLuma, tu.cu->qp, recIPredBuf, cs.slice->clpRng( compID ), tu, true, false, &invLUT );
    
            ruiDist += m_pcRdCost->getDistPart(piOrg, tmpRecLuma, sps.getBitDepth(toChannelType(compID)), compID, DF_SSE_WTD, &orgLuma);
    
    Vadim Seregin's avatar
    Vadim Seregin committed
          {
    
    #if JVET_X0071_CHROMA_BILATERAL_FILTER
    
    #if JVET_AF0112_BIF_DYNAMIC_SCALING
            bool applyChromaBIF = pps.getUseChromaBIF() && m_bilateralFilter->getApplyBIF(tu, compID);
    #else
            bool applyChromaBIF = pps.getUseChromaBIF() && tu.cu->qp > 17;
    #endif
            if(applyChromaBIF)
    
              CompArea compArea = tu.blocks[compID];
              PelBuf recIPredBuf = cs.slice->getPic()->getRecoBuf(compArea);
    
              m_bilateralFilter->bilateralFilterRDOdiamond5x5( compID, tmpRecChroma, tmpRecChroma, tmpRecChroma, tu.cu->qp, recIPredBuf, cs.slice->clpRng(compID), tu, true );
    
            ruiDist += m_pcRdCost->getDistPart(piOrg, tmpRecChroma, bitDepth, compID, DF_SSE_WTD, &orgLuma);
    #else
            ruiDist += m_pcRdCost->getDistPart(piOrg, piReco, bitDepth, compID, DF_SSE_WTD, &orgLuma);
    #endif
            if( jointCbCr )
    
    #if JVET_X0071_CHROMA_BILATERAL_FILTER
              if(compID == COMPONENT_Cr)
              {
                ruiDist += m_pcRdCost->getDistPart(crOrg, tmpRecChroma, bitDepth, COMPONENT_Cr, DF_SSE_WTD, &orgLuma);
              }
              else
              {
                ruiDist += m_pcRdCost->getDistPart(crOrg, crReco, bitDepth, COMPONENT_Cr, DF_SSE_WTD, &orgLuma);
              }
    
              ruiDist += m_pcRdCost->getDistPart(crOrg, crReco, bitDepth, COMPONENT_Cr, DF_SSE_WTD, &orgLuma);
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #endif
        {
    
          if(isLuma(compID))
    
    Vadim Seregin's avatar
    Vadim Seregin committed
          {
    
    #if JVET_AF0112_BIF_DYNAMIC_SCALING
            bool applyBIF = pps.getUseBIF() && m_bilateralFilter->getApplyBIF(tu, compID);
    #else
            bool applyBIF = pps.getUseBIF() /*&& (uiAbsSum > 0)*/ && tu.cu->qp > 17 && 128 > std::max(tu.lumaSize().width, tu.lumaSize().height);
    #endif
            if(applyBIF)
    
            {
              CompArea compArea = tu.blocks[compID];
              PelBuf recIPredBuf = cs.slice->getPic()->getRecoBuf(compArea);
    
              std::vector<Pel> invLUT;
    
              m_bilateralFilter->bilateralFilterRDOdiamond5x5( compID, tmpRecLuma, tmpRecLuma, tmpRecLuma, tu.cu->qp, recIPredBuf, cs.slice->clpRng( compID ), tu, true, false, &invLUT );
    
    Vadim Seregin's avatar
    Vadim Seregin committed
          
    
            ruiDist += m_pcRdCost->getDistPart( piOrg, tmpRecLuma, bitDepth, compID, DF_SSE );
    
    Vadim Seregin's avatar
    Vadim Seregin committed
          {
    
    #if JVET_X0071_CHROMA_BILATERAL_FILTER
    
    #if JVET_AF0112_BIF_DYNAMIC_SCALING
            bool applyChromaBIF = pps.getUseChromaBIF() && m_bilateralFilter->getApplyBIF(tu, compID);
    #else
            bool applyChromaBIF = pps.getUseChromaBIF() && isChroma(compID) && (tu.cu->qp > 17);
    #endif
            if (applyChromaBIF)
    
              CompArea compArea = tu.blocks[compID];
              PelBuf recIPredBuf = cs.slice->getPic()->getRecoBuf(compArea);
    
              m_bilateralFilter->bilateralFilterRDOdiamond5x5( compID, tmpRecChroma, tmpRecChroma, tmpRecChroma, tu.cu->qp, recIPredBuf, cs.slice->clpRng(compID), tu, true );
    
            ruiDist += m_pcRdCost->getDistPart( piOrg, tmpRecChroma, bitDepth, compID, DF_SSE );
    #else
            ruiDist += m_pcRdCost->getDistPart( piOrg, piReco, bitDepth, compID, DF_SSE );
    #endif
            if( jointCbCr )
    
    #if JVET_X0071_CHROMA_BILATERAL_FILTER
              if(compID == COMPONENT_Cr)
              {
                ruiDist += m_pcRdCost->getDistPart( crOrg, tmpRecChroma, bitDepth, COMPONENT_Cr, DF_SSE );
              }
              else
              {
                ruiDist += m_pcRdCost->getDistPart( crOrg, crReco, bitDepth, COMPONENT_Cr, DF_SSE );
              }
    
              ruiDist += m_pcRdCost->getDistPart( crOrg, crReco, bitDepth, COMPONENT_Cr, DF_SSE );
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #else
    
    #if JVET_X0071_CHROMA_BILATERAL_FILTER
        CompArea tmpArea2(compID, area.chromaFormat, Position(0, 0), area.size());
        PelBuf tmpRecChroma;
        if(isChroma(compID))
        {
    
          tmpRecChroma = m_tmpStorageLCU.getBuf(tmpArea2);
          tmpRecChroma.copyFrom(piReco);
    
        }
    #if WCG_EXT
        if (m_pcEncCfg->getLumaLevelToDeltaQPMapping().isEnabled() || (m_pcEncCfg->getLmcs() && slice.getLmcsEnabledFlag() && (m_pcReshape->getCTUFlag() || (isChroma(compID) && m_pcEncCfg->getReshapeIntraCMD()))))
        {
    
          const CPelBuf orgLuma = cs.getOrgBuf( cs.area.blocks[COMPONENT_Y] );
          if(isLuma(compID))
          {
            if (compID == COMPONENT_Y  && !(m_pcEncCfg->getLumaLevelToDeltaQPMapping().isEnabled()))
    
              CompArea      tmpArea1(COMPONENT_Y, area.chromaFormat, Position(0, 0), area.size());
              PelBuf tmpRecLuma = m_tmpStorageLCU.getBuf(tmpArea1);
              tmpRecLuma.rspSignal( piReco, m_pcReshape->getInvLUT() );
              ruiDist += m_pcRdCost->getDistPart(piOrg, tmpRecLuma, sps.getBitDepth(toChannelType(compID)), compID, DF_SSE_WTD, &orgLuma);
    
              ruiDist += m_pcRdCost->getDistPart(piOrg, piReco, bitDepth, compID, DF_SSE_WTD, &orgLuma);
              if( jointCbCr )
              {
                ruiDist += m_pcRdCost->getDistPart(crOrg, crReco, bitDepth, COMPONENT_Cr, DF_SSE_WTD, &orgLuma);
              }
            }
          }
          else
          {
    
    #if JVET_AF0112_BIF_DYNAMIC_SCALING
            bool applyChromaBIF = pps.getUseChromaBIF() && m_bilateralFilter->getApplyBIF(tu, compID);
    #else
            bool applyChromaBIF = pps.getUseChromaBIF() && tu.cu->qp > 17;
    #endif
            if (applyChromaBIF)
    
            {
              CompArea compArea = tu.blocks[compID];
              PelBuf recIPredBuf = cs.slice->getPic()->getRecoBuf(compArea);
    
              m_bilateralFilter->bilateralFilterRDOdiamond5x5( compID, tmpRecChroma, tmpRecChroma, tmpRecChroma, tu.cu->qp, recIPredBuf, cs.slice->clpRng(compID), tu, true );
    
            ruiDist += m_pcRdCost->getDistPart(piOrg, tmpRecChroma, bitDepth, compID, DF_SSE_WTD, &orgLuma);
            if( jointCbCr )
            {
              if(compID == COMPONENT_Cr)
              {
                ruiDist += m_pcRdCost->getDistPart(crOrg, tmpRecChroma, bitDepth, COMPONENT_Cr, DF_SSE_WTD, &orgLuma);
              }
              else
              {
                ruiDist += m_pcRdCost->getDistPart(crOrg, crReco, bitDepth, COMPONENT_Cr, DF_SSE_WTD, &orgLuma);
              }
            }
          }
    
          if(isLuma(compID))
          {
            ruiDist += m_pcRdCost->getDistPart( piOrg, piReco, bitDepth, compID, DF_SSE );
          }
          else
          {
    
    #if JVET_AF0112_BIF_DYNAMIC_SCALING
            bool applyChromaBIF = pps.getUseChromaBIF() && m_bilateralFilter->getApplyBIF(tu, compID);
    #else
            bool applyChromaBIF = pps.getUseChromaBIF() && tu.cu->qp > 17;
    #endif
            if (applyChromaBIF)
    
              CompArea compArea = tu.blocks[compID];
              PelBuf recIPredBuf = cs.slice->getPic()->getRecoBuf(compArea);
    
              m_bilateralFilter->bilateralFilterRDOdiamond5x5( compID, tmpRecChroma, tmpRecChroma, tmpRecChroma, tu.cu->qp, recIPredBuf, cs.slice->clpRng(compID), tu, true );
    
            ruiDist += m_pcRdCost->getDistPart( piOrg, tmpRecChroma, bitDepth, compID, DF_SSE );
          }
          if( jointCbCr )
          {
            if(compID == COMPONENT_Cr)
            {
              ruiDist += m_pcRdCost->getDistPart( crOrg, tmpRecChroma, bitDepth, COMPONENT_Cr, DF_SSE );
    
              ruiDist += m_pcRdCost->getDistPart( crOrg, crReco, bitDepth, COMPONENT_Cr, DF_SSE );
    
        if (m_pcEncCfg->getLumaLevelToDeltaQPMapping().isEnabled() || (m_pcEncCfg->getLmcs()
          && slice.getLmcsEnabledFlag() && (m_pcReshape->getCTUFlag() || (isChroma(compID) && m_pcEncCfg->getReshapeIntraCMD()))))
    
          const CPelBuf orgLuma = cs.getOrgBuf( cs.area.blocks[COMPONENT_Y] );
          if (compID == COMPONENT_Y  && !(m_pcEncCfg->getLumaLevelToDeltaQPMapping().isEnabled()))
          {
            CompArea      tmpArea1(COMPONENT_Y, area.chromaFormat, Position(0, 0), area.size());
            PelBuf tmpRecLuma = m_tmpStorageLCU.getBuf(tmpArea1);
            tmpRecLuma.rspSignal( piReco, m_pcReshape->getInvLUT() );
            ruiDist += m_pcRdCost->getDistPart(piOrg, tmpRecLuma, sps.getBitDepth(toChannelType(compID)), compID, DF_SSE_WTD, &orgLuma);
          }
          else
          {
            ruiDist += m_pcRdCost->getDistPart(piOrg, piReco, bitDepth, compID, DF_SSE_WTD, &orgLuma);
            if( jointCbCr )
            {
              ruiDist += m_pcRdCost->getDistPart(crOrg, crReco, bitDepth, COMPONENT_Cr, DF_SSE_WTD, &orgLuma);
            }
          }
    
          ruiDist += m_pcRdCost->getDistPart( piOrg, piReco, bitDepth, compID, DF_SSE );
    
            ruiDist += m_pcRdCost->getDistPart( crOrg, crReco, bitDepth, COMPONENT_Cr, DF_SSE );
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #endif
    
    #if INTRA_TRANS_ENC_OPT && SIGN_PREDICTION
    
    void IntraSearch::xIntraCodingACTTUBlock(TransformUnit &tu, const ComponentID &compID, Distortion& ruiDist, std::vector<TrMode>* trModes, const bool loadTr)
    {
      if (!tu.blocks[compID].valid())
      {
        CHECK(1, "tu does not exist");
      }
    
      CodingStructure     &cs = *tu.cs;
      const SPS           &sps = *cs.sps;
      const Slice         &slice = *cs.slice;
      const CompArea      &area = tu.blocks[compID];
      const CompArea &crArea = tu.blocks[COMPONENT_Cr];
    
      PelBuf              piOrgResi = cs.getOrgResiBuf(area);
      PelBuf              piResi = cs.getResiBuf(area);
      PelBuf              crOrgResi = cs.getOrgResiBuf(crArea);
      PelBuf              crResi = cs.getResiBuf(crArea);
      TCoeff              uiAbsSum = 0;
    
      CHECK(tu.jointCbCr && compID == COMPONENT_Cr, "wrong combination of compID and jointCbCr");
      bool jointCbCr = tu.jointCbCr && compID == COMPONENT_Cb;
    
      m_pcRdCost->setChromaFormat(cs.sps->getChromaFormatIdc());
    
      if (m_pcEncCfg->getCostMode() != COST_LOSSLESS_CODING || !slice.isLossless())
    
      m_pcTrQuant->lambdaAdjustColorTrans(true);
    
      if (jointCbCr)
      {
        ComponentID compIdCode = (tu.jointCbCr >> 1 ? COMPONENT_Cb : COMPONENT_Cr);
        m_pcTrQuant->selectLambda(compIdCode);
      }
      else
      {
        m_pcTrQuant->selectLambda(compID);
      }
    
    
      bool flag = slice.getLmcsEnabledFlag() && (slice.isIntra() || (!slice.isIntra() && m_pcReshape->getCTUFlag())) && (tu.blocks[compID].width*tu.blocks[compID].height > 4);
    
      if (flag && isChroma(compID) && slice.getPicHeader()->getLmcsChromaResidualScaleFlag())
    
      {
        int    cResScaleInv = tu.getChromaAdj();
        double cResScale = (double)(1 << CSCALE_FP_PREC) / (double)cResScaleInv;
        m_pcTrQuant->setLambda(m_pcTrQuant->getLambda() / (cResScale*cResScale));
      }
    
      if (jointCbCr)
      {
        // Lambda is loosened for the joint mode with respect to single modes as the same residual is used for both chroma blocks
        const int    absIct = abs(TU::getICTMode(tu));
        const double lfact = (absIct == 1 || absIct == 3 ? 0.8 : 0.5);
        m_pcTrQuant->setLambda(lfact * m_pcTrQuant->getLambda());
      }
      if (sps.getJointCbCrEnabledFlag() && isChroma(compID) && (slice.getSliceQp() > 18))
      {
        m_pcTrQuant->setLambda(1.3 * m_pcTrQuant->getLambda());
      }
    
      if (isLuma(compID))
      {
        QpParam cQP(tu, compID);
    
        if (trModes)
        {
          m_pcTrQuant->transformNxN(tu, compID, cQP, trModes, m_pcEncCfg->getMTSIntraMaxCand());
          tu.mtsIdx[compID] = trModes->at(0).first;
        }
    
        if (!(m_pcEncCfg->getCostMode() == COST_LOSSLESS_CODING && slice.isLossless() && tu.mtsIdx[compID] == 0) || tu.cu->bdpcmMode != 0)
    
        {
          m_pcTrQuant->transformNxN(tu, compID, cQP, uiAbsSum, m_CABACEstimator->getCtx(), loadTr);
        }
    
        if ((m_pcEncCfg->getCostMode() == COST_LOSSLESS_CODING && slice.isLossless() && tu.mtsIdx[compID] == 0) && tu.cu->bdpcmMode == 0)
    
        {
          uiAbsSum = 0;
          tu.getCoeffs(compID).fill(0);
          TU::setCbfAtDepth(tu, compID, tu.depth, 0);
        }
    
    
        if (uiAbsSum > 0)
        {
          m_pcTrQuant->invTransformNxN(tu, compID, piResi, cQP);
        }
        else
        {
          piResi.fill(0);
        }
      }
      else
      {
        int         codedCbfMask = 0;
        ComponentID codeCompId = (tu.jointCbCr ? (tu.jointCbCr >> 1 ? COMPONENT_Cb : COMPONENT_Cr) : compID);
        QpParam qpCbCr(tu, codeCompId);
    
        if (tu.jointCbCr)
        {
          ComponentID otherCompId = (codeCompId == COMPONENT_Cr ? COMPONENT_Cb : COMPONENT_Cr);
          tu.getCoeffs(otherCompId).fill(0);
          TU::setCbfAtDepth(tu, otherCompId, tu.depth, false);
        }
    
        PelBuf& codeResi = (codeCompId == COMPONENT_Cr ? crResi : piResi);
        uiAbsSum = 0;
    
        if (trModes)
        {
          m_pcTrQuant->transformNxN(tu, codeCompId, qpCbCr, trModes, m_pcEncCfg->getMTSIntraMaxCand());
          tu.mtsIdx[codeCompId] = trModes->at(0).first;
          if (tu.jointCbCr)
          {
            tu.mtsIdx[(codeCompId == COMPONENT_Cr) ? COMPONENT_Cb : COMPONENT_Cr] = MTS_DCT2_DCT2;
          }
        }
    
        if (!(m_pcEncCfg->getCostMode() == COST_LOSSLESS_CODING && slice.isLossless() && tu.mtsIdx[codeCompId] == 0) || tu.cu->bdpcmModeChroma != 0)
    
        {
          m_pcTrQuant->transformNxN(tu, codeCompId, qpCbCr, uiAbsSum, m_CABACEstimator->getCtx(), loadTr);
        }
    
        if (uiAbsSum > 0)
        {
          m_pcTrQuant->invTransformNxN(tu, codeCompId, codeResi, qpCbCr);
          codedCbfMask += (codeCompId == COMPONENT_Cb ? 2 : 1);
        }
        else
        {
          codeResi.fill(0);
        }
    
        if (tu.jointCbCr)
        {
          if (tu.jointCbCr == 3 && codedCbfMask == 2)
          {
            codedCbfMask = 3;
            TU::setCbfAtDepth(tu, COMPONENT_Cr, tu.depth, true);
          }
          if (tu.jointCbCr != codedCbfMask)
          {
            ruiDist = std::numeric_limits<Distortion>::max();
    
            if (m_pcEncCfg->getCostMode() != COST_LOSSLESS_CODING || !slice.isLossless())
    
            m_pcTrQuant->lambdaAdjustColorTrans(false);
            return;
          }
          m_pcTrQuant->invTransformICT(tu, piResi, crResi);
          uiAbsSum = codedCbfMask;
        }
      }
    
    
      if (flag && uiAbsSum > 0 && isChroma(compID) && slice.getPicHeader()->getLmcsChromaResidualScaleFlag())
    
      {
        piResi.scaleSignal(tu.getChromaAdj(), 0, slice.clpRng(compID));
        if (jointCbCr)
        {
          crResi.scaleSignal(tu.getChromaAdj(), 0, slice.clpRng(COMPONENT_Cr));
        }
      }
    
      if (m_pcEncCfg->getCostMode() != COST_LOSSLESS_CODING || !slice.isLossless())
    
      m_pcTrQuant->lambdaAdjustColorTrans(false);
    
      ruiDist += m_pcRdCost->getDistPart(piOrgResi, piResi, sps.getBitDepth(toChannelType(compID)), compID, DF_SSE);
      if (jointCbCr)
      {
        ruiDist += m_pcRdCost->getDistPart(crOrgResi, crResi, sps.getBitDepth(toChannelType(COMPONENT_Cr)), COMPONENT_Cr, DF_SSE);
      }
    }
    
    
    bool IntraSearch::xIntraCodingLumaISP(CodingStructure& cs, Partitioner& partitioner, const double bestCostSoFar)
    {
      int               subTuCounter = 0;
      const CodingUnit& cu = *cs.getCU(partitioner.currArea().lumaPos(), partitioner.chType);
      bool              earlySkipISP = false;
    
    Santiago de Luxán Hernández's avatar
    Santiago de Luxán Hernández committed
      bool              splitCbfLuma = false;
    
      const PartSplit   ispType = CU::getISPType(cu, COMPONENT_Y);
    
      cs.cost = 0;
    
      partitioner.splitCurrArea(ispType, cs);
    
    
      CUCtx cuCtx;
      cuCtx.isDQPCoded = true;
      cuCtx.isChromaQpAdjCoded = true;
    
    
      do   // subpartitions loop
      {
        uint32_t   numSig = 0;
        Distortion singleDistTmpLuma = 0;
        uint64_t   singleTmpFracBits = 0;
        double     singleCostTmp = 0;
    
        TransformUnit& tu = cs.addTU(CS::getArea(cs, partitioner.currArea(), partitioner.chType), partitioner.chType);
        tu.depth = partitioner.currTrDepth;
    
        // Encode TU
    
        xIntraCodingTUBlock(tu, COMPONENT_Y, singleDistTmpLuma, 0, &numSig);
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    
    #if SIGN_PREDICTION
    
    Seungwook Hong's avatar
    Seungwook Hong committed
    #if JVET_Z0118_GDR
        cs.updateReconMotIPM(partitioner.currArea());
    #else
    
    Vadim Seregin's avatar
    Vadim Seregin committed
        cs.picture->getRecoBuf( partitioner.currArea() ).copyFrom( cs.getRecoBuf( partitioner.currArea() ) );
    
    Seungwook Hong's avatar
    Seungwook Hong committed
    #endif
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #endif
    
    
        if (singleDistTmpLuma == MAX_INT)   // all zero CBF skip
        {
          earlySkipISP = true;
          partitioner.exitCurrSplit();
          cs.cost = MAX_DOUBLE;
          return false;
        }
    
    
        if (m_pcRdCost->calcRdCost(cs.fracBits, cs.dist + singleDistTmpLuma) > bestCostSoFar)
    
          // The accumulated cost + distortion is already larger than the best cost so far, so it is not necessary to
          // calculate the rate
          earlySkipISP = true;
        }
        else
        {
          singleTmpFracBits = xGetIntraFracBitsQT(cs, partitioner, true, false, subTuCounter, ispType, &cuCtx);
    
        singleCostTmp = m_pcRdCost->calcRdCost(singleTmpFracBits, singleDistTmpLuma);
    
    
        cs.cost += singleCostTmp;
        cs.dist += singleDistTmpLuma;
        cs.fracBits += singleTmpFracBits;
    
        subTuCounter++;
    
    
    Santiago de Luxán Hernández's avatar
    Santiago de Luxán Hernández committed
        splitCbfLuma |= TU::getCbfAtDepth(*cs.getTU(partitioner.currArea().lumaPos(), partitioner.chType, subTuCounter - 1), COMPONENT_Y, partitioner.currTrDepth);
    
        int nSubPartitions = m_ispTestedModes[cu.lfnstIdx].numTotalParts[cu.ispMode - 1];
    
        if (subTuCounter < nSubPartitions)
        {
          // exit condition if the accumulated cost is already larger than the best cost so far (no impact in RD performance)
          if (cs.cost > bestCostSoFar)
          {
            earlySkipISP = true;
            break;
          }
          else if (subTuCounter < nSubPartitions)
          {
            // more restrictive exit condition
            double threshold = nSubPartitions == 2 ? 0.95 : subTuCounter == 1 ? 0.83 : 0.91;
            if (subTuCounter < nSubPartitions && cs.cost > bestCostSoFar * threshold)
            {
              earlySkipISP = true;
              break;
            }
          }
        }
      } while (partitioner.nextPart(cs));   // subpartitions loop
    
      partitioner.exitCurrSplit();
      const UnitArea& currArea = partitioner.currArea();
      const uint32_t  currDepth = partitioner.currTrDepth;
    
      if (earlySkipISP)
      {
        cs.cost = MAX_DOUBLE;
      }
      else
      {
        cs.cost = m_pcRdCost->calcRdCost(cs.fracBits, cs.dist);
        // The cost check is necessary here again to avoid superfluous operations if the maximum number of coded subpartitions was reached and yet ISP did not win
        if (cs.cost < bestCostSoFar)
        {
          cs.setDecomp(cu.Y());
    
    Seungwook Hong's avatar
    Seungwook Hong committed
    #if JVET_Z0118_GDR
          cs.updateReconMotIPM(currArea.Y());
    #else
    
          cs.picture->getRecoBuf(currArea.Y()).copyFrom(cs.getRecoBuf(currArea.Y()));
    
    Seungwook Hong's avatar
    Seungwook Hong committed
    #endif
    
    
          for (auto& ptu : cs.tus)
          {
            if (currArea.Y().contains(ptu->Y()))
            {
    
    Santiago de Luxán Hernández's avatar
    Santiago de Luxán Hernández committed
              TU::setCbfAtDepth(*ptu, COMPONENT_Y, currDepth, splitCbfLuma ? 1 : 0);
    
    bool IntraSearch::xRecurIntraCodingLumaQT( CodingStructure &cs, Partitioner &partitioner, const double bestCostSoFar, const int subTuIdx, const PartSplit ispType, const bool ispIsCurrentWinner, bool mtsCheckRangeFlag, int mtsFirstCheckId, int mtsLastCheckId, bool moreProbMTSIdxFirst 
    #if JVET_AG0136_INTRA_TMP_LIC
                                              , InterPrediction* pcInterPred
    #endif
    )
    
    {
            int   subTuCounter = subTuIdx;
      const UnitArea &currArea = partitioner.currArea();
      const CodingUnit     &cu = *cs.getCU( currArea.lumaPos(), partitioner.chType );
            bool  earlySkipISP = false;
    
    Tung Nguyen's avatar
    Tung Nguyen committed
      uint32_t currDepth       = partitioner.currTrDepth;
    
      const SPS &sps           = *cs.sps;
    
      bCheckFull               = !partitioner.canSplit( TU_MAX_TR_SPLIT, cs
    #if JVET_AI0087_BTCUS_RESTRICTION
        , false, false
    #endif
      );
      bCheckSplit              = partitioner.canSplit( TU_MAX_TR_SPLIT, cs
    #if JVET_AI0087_BTCUS_RESTRICTION
        , false, false
    #endif
      );
    
      const Slice           &slice = *cs.slice;
    
        bCheckSplit = partitioner.canSplit( ispType, cs 
    #if JVET_AI0087_BTCUS_RESTRICTION
          , false, false
    #endif
        );
    
      double     dSingleCost                        = MAX_DOUBLE;
      Distortion uiSingleDistLuma                   = 0;
      uint64_t   singleFracBits                     = 0;
    
      bool       checkTransformSkip                 = sps.getTransformSkipEnabledFlag();
    
      int        bestModeId[ MAX_NUM_COMPONENT ]    = { 0, 0, 0 };
      uint8_t    nNumTransformCands                 = cu.mtsFlag ? 4 : 1;
      uint8_t    numTransformIndexCands             = nNumTransformCands;
    
    Vadim Seregin's avatar
    Vadim Seregin committed
      const TempCtx ctxStart  ( m_ctxCache, m_CABACEstimator->getCtx() );
      TempCtx       ctxBest   ( m_ctxCache );
    
    
      CodingStructure *csSplit = nullptr;
      CodingStructure *csFull  = nullptr;
    
    
      CUCtx cuCtx;
      cuCtx.isDQPCoded = true;
      cuCtx.isChromaQpAdjCoded = true;
    
    
      bool validReturnFull = false;
    
    #if JVET_AH0103_LOW_DELAY_LFNST_NSPT
      bool spsIntraLfnstEnabled = ( ( slice.getSliceType() == I_SLICE && sps.getUseIntraLFNSTISlice() ) ||
                                    ( slice.getSliceType() != I_SLICE && sps.getUseIntraLFNSTPBSlice() ) );
    #endif
    
      if( bCheckFull )
      {
        csFull->cost = 0.0;
    
        TransformUnit &tu = csFull->addTU( CS::getArea( *csFull, currArea, partitioner.chType ), partitioner.chType );
        tu.depth = currDepth;
    
    
        const bool tsAllowed  = TU::isTSAllowed( tu, COMPONENT_Y );
    
        const bool mtsAllowed = CU::isMTSAllowed( cu, COMPONENT_Y );
    
    #if JVET_AH0103_LOW_DELAY_LFNST_NSPT
        if( spsIntraLfnstEnabled )
    #else
    
        {
          checkTransformSkip &= tsAllowed;
          checkTransformSkip &= !cu.mtsFlag;
          checkTransformSkip &= !cu.lfnstIdx;
    
          if( !cu.mtsFlag && checkTransformSkip )
          {
            trModes.push_back( TrMode( 0, true ) ); //DCT2
            trModes.push_back( TrMode( 1, true ) ); //TS
          }
        }
        else
        {
    
    #if JVET_Y0142_ADAPT_INTRA_MTS
          nNumTransformCands = 1 + (tsAllowed ? 1 : 0) + (mtsAllowed ? 6 : 0); // DCT + TS + 6 MTS = 8 tests
    #else
    
          nNumTransformCands = 1 + ( tsAllowed ? 1 : 0 ) + ( mtsAllowed ? 4 : 0 ); // DCT + TS + 4 MTS = 6 tests
    
          if (m_pcEncCfg->getCostMode() == COST_LOSSLESS_CODING && slice.isLossless())
    
          {
            nNumTransformCands = 1;
            CHECK(!tsAllowed && !cu.bdpcmMode, "transform skip should be enabled for LS");
            if (cu.bdpcmMode)
            {
              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));
            }
            if (mtsAllowed)
            {
    
    #if JVET_Y0142_ADAPT_INTRA_MTS
              for (int i = 2; i < 8; i++)
    #else
    
              for (int i = 2; i < 6; i++)
    
              {
                trModes.push_back(TrMode(i, true));
              }
    
        }
    
        CHECK( !tu.Y().valid(), "Invalid TU" );
    
    
        CodingStructure &saveCS = *m_pSaveCS[0];
    
        TransformUnit *tmpTU = nullptr;
    
        Distortion singleDistTmpLuma = 0;
        uint64_t     singleTmpFracBits = 0;
        double     singleCostTmp     = 0;
    
    #if JVET_AH0103_LOW_DELAY_LFNST_NSPT
        int        firstCheckId      = ( spsIntraLfnstEnabled && mtsCheckRangeFlag && cu.mtsFlag ) ? mtsFirstCheckId : 0;
    
        //we add the MTS candidates to the loop. TransformSkip will still be the last one to be checked (when modeId == lastCheckId) as long as checkTransformSkip is true
        int        lastCheckId       = spsIntraLfnstEnabled ? ( ( mtsCheckRangeFlag && cu.mtsFlag ) ? ( mtsLastCheckId + ( int ) checkTransformSkip ) : ( numTransformIndexCands - ( firstCheckId + 1 ) + ( int ) checkTransformSkip ) ) :
                                       trModes[ nNumTransformCands - 1 ].first;
        bool isNotOnlyOneMode        = spsIntraLfnstEnabled ? lastCheckId != firstCheckId : nNumTransformCands != 1;
    #else
    
        int        firstCheckId      = ( sps.getUseLFNST() && mtsCheckRangeFlag && cu.mtsFlag ) ? mtsFirstCheckId : 0;
    
        //we add the MTS candidates to the loop. TransformSkip will still be the last one to be checked (when modeId == lastCheckId) as long as checkTransformSkip is true
        int        lastCheckId       = sps.getUseLFNST() ? ( ( mtsCheckRangeFlag && cu.mtsFlag ) ? ( mtsLastCheckId + ( int ) checkTransformSkip ) : ( numTransformIndexCands - ( firstCheckId + 1 ) + ( int ) checkTransformSkip ) ) :
                                       trModes[ nNumTransformCands - 1 ].first;
        bool isNotOnlyOneMode        = sps.getUseLFNST() ? lastCheckId != firstCheckId : nNumTransformCands != 1;
    
    
        if( isNotOnlyOneMode )
        {
          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.area.repositionTo(cs.area);
          saveCS.clearTUs();
          tmpTU = &saveCS.addTU(currArea, partitioner.chType);
        }
    
    
        bool    cbfBestMode      = false;
        bool    cbfBestModeValid = false;
    
    Tung Nguyen's avatar
    Tung Nguyen committed
        bool    cbfDCT2  = true;
    
    #if JVET_W0103_INTRA_MTS
    
    #if JVET_AH0103_LOW_DELAY_LFNST_NSPT
        if( spsIntraLfnstEnabled && cu.mtsFlag )
    #else
    
        if (sps.getUseLFNST() && cu.mtsFlag)
    
          xSelectAMTForFullRD(tu
    #if JVET_AG0136_INTRA_TMP_LIC
            , pcInterPred
    #endif
          );
    
        double threshold = m_pcEncCfg->getUseFastISP() && !cu.ispMode && ispIsCurrentWinner && nNumTransformCands > 1 ? 1 + 1.4 / sqrt( cu.lwidth() * cu.lheight() ) : 1;
    
    #if JVET_AH0103_LOW_DELAY_LFNST_NSPT
        for( int modeId = firstCheckId; modeId <= ( spsIntraLfnstEnabled ? lastCheckId : ( nNumTransformCands - 1 ) ); modeId++ )
    #else
    
        for( int modeId = firstCheckId; modeId <= ( sps.getUseLFNST() ? lastCheckId : ( nNumTransformCands - 1 ) ); modeId++ )
    
        {
          uint8_t transformIndex = modeId;
    
    #if JVET_W0103_INTRA_MTS
    
    #if JVET_AH0103_LOW_DELAY_LFNST_NSPT
          if( spsIntraLfnstEnabled && cu.mtsFlag )
    #else
    
          if (sps.getUseLFNST() && cu.mtsFlag)
    
            if (modeId >= m_numCandAMTForFullRD)
            {
              continue;
            }
            transformIndex = m_testAMTForFullRD[modeId];
    
    #if JVET_Y0142_ADAPT_INTRA_MTS
          m_validMTSReturn = true;
    #endif
    
    #if JVET_AH0103_LOW_DELAY_LFNST_NSPT
          if( spsIntraLfnstEnabled )
    #else
    
          {
            if( ( transformIndex < lastCheckId ) || ( ( transformIndex == lastCheckId ) && !checkTransformSkip ) ) //we avoid this if the mode is transformSkip
            {
              // Skip checking other transform candidates if zero CBF is encountered and it is the best transform so far
              if( m_pcEncCfg->getUseFastLFNST() && transformIndex && !cbfBestMode && cbfBestModeValid )
              {
                continue;
              }
            }
          }
          else
          {
    
            if (!(m_pcEncCfg->getCostMode() == COST_LOSSLESS_CODING && slice.isLossless()))
    
              if (!cbfDCT2 || (m_pcEncCfg->getUseTransformSkipFast() && bestModeId[COMPONENT_Y] == MTS_SKIP))
              {
                break;
              }
              if (!trModes[modeId].second)
              {
                continue;
              }
              // we compare the DCT-II cost against the best ISP cost so far (except for TS)
              if (m_pcEncCfg->getUseFastISP() && !cu.ispMode && ispIsCurrentWinner && trModes[modeId].first != MTS_DCT2_DCT2
                  && (trModes[modeId].first != MTS_SKIP || !tsAllowed) && bestDCT2cost > bestCostSoFar * threshold)
              {
                continue;
              }
    
            tu.mtsIdx[COMPONENT_Y] = trModes[modeId].first;
    
          if ((modeId != firstCheckId) && isNotOnlyOneMode)
          {
            m_CABACEstimator->getCtx() = ctxStart;
          }
    
          int default0Save1Load2 = 0;
          singleDistTmpLuma = 0;
    
    
    #if JVET_AH0103_LOW_DELAY_LFNST_NSPT
          if( modeId == firstCheckId && ( spsIntraLfnstEnabled ? ( modeId != lastCheckId ) : ( nNumTransformCands > 1 ) ) )
    #else
    
          if( modeId == firstCheckId && ( sps.getUseLFNST() ? ( modeId != lastCheckId ) : ( nNumTransformCands > 1 ) ) )
    
    #if JVET_AH0103_LOW_DELAY_LFNST_NSPT
            if( spsIntraLfnstEnabled && !cbfBestModeValid )
    #else
    
            if( sps.getUseLFNST() && !cbfBestModeValid )
    
            {
              default0Save1Load2 = 1;
            }
            else
            {
              default0Save1Load2 = 2;
            }
    
    #if JVET_AH0103_LOW_DELAY_LFNST_NSPT
          if( spsIntraLfnstEnabled )
    #else
    
          {
            if( cu.mtsFlag )
            {
              if( moreProbMTSIdxFirst )
              {
                const ChannelType     chType      = toChannelType( COMPONENT_Y );
                const CompArea&       area        = tu.blocks[ COMPONENT_Y ];
                const PredictionUnit& pu          = *cs.getPU( area.pos(), chType );
                uint32_t              uiIntraMode = pu.intraDir[ chType ];
    
                if( transformIndex == 1 )
                {
    
                  tu.mtsIdx[COMPONENT_Y] = (uiIntraMode < 34) ? MTS_DST7_DCT8 : MTS_DCT8_DST7;
    
                else if( transformIndex == 2 )
    
                  tu.mtsIdx[COMPONENT_Y] = (uiIntraMode < 34) ? MTS_DCT8_DST7 : MTS_DST7_DCT8;
    
                  tu.mtsIdx[COMPONENT_Y] = MTS_DST7_DST7 + transformIndex;
    
                tu.mtsIdx[COMPONENT_Y] = MTS_DST7_DST7 + transformIndex;
    
              tu.mtsIdx[COMPONENT_Y] = transformIndex;
    
            }
    
            if( !cu.mtsFlag && checkTransformSkip )
            {
    
              xIntraCodingTUBlock( tu, COMPONENT_Y, singleDistTmpLuma, default0Save1Load2, &numSig, modeId == 0 ? &trModes : nullptr, true 
    #if JVET_AG0136_INTRA_TMP_LIC
                , pcInterPred
    #endif
              );
    
              if( modeId == 0 )
              {
                for( int i = 0; i < 2; i++ )
                {
                  if( trModes[ i ].second )
                  {
                    lastCheckId = trModes[ i ].first;
                  }
                }
              }
            }
    
    #if JVET_W0103_INTRA_MTS
            else if (cu.mtsFlag)
            {
    
              xIntraCodingTUBlock(tu, COMPONENT_Y, singleDistTmpLuma, 2, &numSig, nullptr, true
    #if JVET_AG0136_INTRA_TMP_LIC
                , pcInterPred
    #endif
              );
    
              xIntraCodingTUBlock( tu, COMPONENT_Y, singleDistTmpLuma, default0Save1Load2, &numSig 
    #if JVET_AG0136_INTRA_TMP_LIC
                , nullptr, false, pcInterPred
    #endif
              );
    
              xIntraCodingTUBlock( tu, COMPONENT_Y, singleDistTmpLuma, default0Save1Load2, &numSig, modeId == 0 ? &trModes : nullptr, true 
    #if JVET_AG0136_INTRA_TMP_LIC
                , pcInterPred
    #endif
              );
    
              if( modeId == 0 )
              {
                for( int i = 0; i < nNumTransformCands; i++ )
                {
                  if( trModes[ i ].second )
                  {
                    lastCheckId = trModes[ i ].first;
                  }
                }
              }
            }
            else
            {
    
              xIntraCodingTUBlock( tu, COMPONENT_Y, singleDistTmpLuma, default0Save1Load2, &numSig 
    #if JVET_AG0136_INTRA_TMP_LIC
                , nullptr, false, pcInterPred
    #endif
              );
    
    #if JVET_Y0142_ADAPT_INTRA_MTS
          cuCtx.mtsCoeffAbsSum = 0;
    #endif
    
          cuCtx.mtsLastScanPos = false;
    
    #if INTRA_TRANS_ENC_OPT
          cuCtx.lfnstLastScanPos = false;
    #endif
    
    #if JVET_AH0103_LOW_DELAY_LFNST_NSPT
          if( ( spsIntraLfnstEnabled ? ( modeId == lastCheckId && modeId != 0 && checkTransformSkip ) : ( trModes[ modeId ].first != 0 ) ) && !TU::getCbfAtDepth( tu, COMPONENT_Y, currDepth ) )
    #else
    
          if( ( sps.getUseLFNST() ? ( modeId == lastCheckId && modeId != 0 && checkTransformSkip ) : ( trModes[ modeId ].first != 0 ) ) && !TU::getCbfAtDepth( tu, COMPONENT_Y, currDepth ) )
    
          {
            //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;
            }
    
            else
            {
              singleTmpFracBits = xGetIntraFracBitsQT(*csFull, partitioner, true, false, subTuCounter, ispType, &cuCtx);
              singleCostTmp = m_pcRdCost->calcRdCost(singleTmpFracBits, singleDistTmpLuma);
            }
    
            if( cu.ispMode && m_pcRdCost->calcRdCost( csFull->fracBits, csFull->dist + singleDistTmpLuma ) > bestCostSoFar )
            {
              earlySkipISP = true;
            }
            else
            {
    
    #if JVET_Y0142_ADAPT_INTRA_MTS
              if (tu.mtsIdx[COMPONENT_Y] > MTS_SKIP && !m_validMTSReturn)
              {
                singleTmpFracBits = 0;
              }
              else
              {
                singleTmpFracBits = xGetIntraFracBitsQT(*csFull, partitioner, true, false, subTuCounter, ispType, &cuCtx);
              }
    #else
    
              singleTmpFracBits = xGetIntraFracBitsQT( *csFull, partitioner, true, false, subTuCounter, ispType, &cuCtx );
    
            if (tu.mtsIdx[COMPONENT_Y] > MTS_SKIP)
            {
    
    #if JVET_Y0142_ADAPT_INTRA_MTS
              if(!m_validMTSReturn)
    #else