Skip to content
Snippets Groups Projects
IntraSearch.cpp 130 KiB
Newer Older
  • Learn to ignore specific revisions
  •   cs.dist     = 0;
      cs.fracBits = 0;
      cs.cost     = 0;
    
      cs.setDecomp(cs.area);
    
    Taoran Lu's avatar
    Taoran Lu committed
      cs.picture->getPredBuf(cs.area).copyFrom(cs.getPredBuf());
    
    }
    
    void IntraSearch::xEncPCM(CodingStructure &cs, Partitioner& partitioner, const ComponentID &compID)
    {
      TransformUnit &tu = *cs.getTU( partitioner.chType );
    
      const int  channelBitDepth = cs.sps->getBitDepth(toChannelType(compID));
      const uint32_t uiPCMBitDepth = cs.sps->getPCMBitDepth(toChannelType(compID));
    
      const int pcmShiftRight = (channelBitDepth - int(uiPCMBitDepth));
    
      CompArea  area    = tu.blocks[compID];
      PelBuf    pcmBuf  = tu.getPcmbuf  (compID);
      PelBuf    recBuf  = cs.getRecoBuf ( area );
      CPelBuf   orgBuf  = cs.getOrgBuf  ( area );
    
      CHECK(pcmShiftRight < 0, "Negative shift");
    
    Taoran Lu's avatar
    Taoran Lu committed
      CompArea      tmpArea(COMPONENT_Y, area.chromaFormat, Position(0, 0), area.size());
      PelBuf tempOrgBuf = m_tmpStorageLCU.getBuf(tmpArea);
      tempOrgBuf.copyFrom(orgBuf);
      if (cs.slice->getReshapeInfo().getUseSliceReshaper() && m_pcReshape->getCTUFlag() && compID == COMPONENT_Y)
      {
        tempOrgBuf.rspSignal(m_pcReshape->getFwdLUT());
      }
    
      for (uint32_t uiY = 0; uiY < pcmBuf.height; uiY++)
      {
        for (uint32_t uiX = 0; uiX < pcmBuf.width; uiX++)
        {
          // Encode
    
    Taoran Lu's avatar
    Taoran Lu committed
          pcmBuf.at(uiX, uiY) = tempOrgBuf.at(uiX, uiY) >> pcmShiftRight;
    
          // Reconstruction
          recBuf.at(uiX, uiY) = pcmBuf.at(uiX, uiY) << pcmShiftRight;
        }
      }
    }
    
    // -------------------------------------------------------------------------------------------------------------------
    // Intra search
    // -------------------------------------------------------------------------------------------------------------------
    
    
    void IntraSearch::xEncIntraHeader( CodingStructure &cs, Partitioner &partitioner, const bool &bLuma, const bool &bChroma, const int subTuIdx )
    
    {
      CodingUnit &cu = *cs.getCU( partitioner.chType );
    
      if (bLuma)
      {
    
        bool isFirst = cu.ispMode ? subTuIdx == 0 : partitioner.currArea().lumaPos() == cs.area.lumaPos();
    
    Yu Han's avatar
    Yu Han committed
          if ((!cs.slice->isIntra() || cs.slice->getSPS()->getIBCFlag())
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
            && cu.Y().valid()
    
          {
            if( cs.pps->getTransquantBypassEnabledFlag() )
            {
              m_CABACEstimator->cu_transquant_bypass_flag( cu );
            }
            m_CABACEstimator->cu_skip_flag( cu );
            m_CABACEstimator->pred_mode   ( cu );
          }
    
    #if JVET_N0413_RDPCM
          m_CABACEstimator->bdpcm_mode  ( cu, ComponentID(partitioner.chType) );
    #endif
    
    Karsten Suehring's avatar
    Karsten Suehring committed
          if( CU::isIntra(cu) )
    
            m_CABACEstimator->pcm_data( cu, partitioner );
    
    #if !JVET_N0217_MATRIX_INTRAPRED
    
          m_CABACEstimator->extend_ref_line(cu);
          m_CABACEstimator->isp_mode      ( cu );
    
        }
    
        PredictionUnit &pu = *cs.getPU(partitioner.currArea().lumaPos(), partitioner.chType);
    
        // luma prediction mode
    
    Karsten Suehring's avatar
    Karsten Suehring committed
        if (isFirst)
    
    Karsten Suehring's avatar
    Karsten Suehring committed
          if ( !cu.Y().valid())
            m_CABACEstimator->pred_mode( cu );
          m_CABACEstimator->intra_luma_pred_mode( pu );
    
        }
      }
    
      if (bChroma)
      {
        bool isFirst = partitioner.currArea().Cb().valid() && partitioner.currArea().chromaPos() == cs.area.chromaPos();
    
        PredictionUnit &pu = *cs.getPU( partitioner.currArea().chromaPos(), CHANNEL_TYPE_CHROMA );
    
    
    Karsten Suehring's avatar
    Karsten Suehring committed
        if( isFirst )
    
    Karsten Suehring's avatar
    Karsten Suehring committed
          m_CABACEstimator->intra_chroma_pred_mode( pu );
    
    void IntraSearch::xEncSubdivCbfQT( CodingStructure &cs, Partitioner &partitioner, const bool &bLuma, const bool &bChroma, const int subTuIdx, const PartSplit ispType )
    {
      const UnitArea &currArea = partitioner.currArea();
              int subTuCounter = subTuIdx;
      TransformUnit &currTU = *cs.getTU( currArea.blocks[partitioner.chType], partitioner.chType, subTuCounter );
      CodingUnit    &currCU = *currTU.cu;
    
      uint32_t currDepth           = partitioner.currTrDepth;
    
      const bool subdiv        = currTU.depth > currDepth;
    
      ComponentID compID = partitioner.chType == CHANNEL_TYPE_LUMA ? COMPONENT_Y : COMPONENT_Cb;
      const bool chromaCbfISP = currArea.blocks[COMPONENT_Cb].valid() && currCU.ispMode && !subdiv;
    
    Karsten Suehring's avatar
    Karsten Suehring committed
      if( partitioner.canSplit( TU_MAX_TR_SPLIT, cs ) )
    
    Karsten Suehring's avatar
    Karsten Suehring committed
        CHECK( !subdiv, "TU split implied" );
      }
      else
      {
    
        CHECK( subdiv && !currCU.ispMode && isLuma( compID ), "No TU subdivision is allowed with QTBT" );
      }
    
      if( bChroma && ( !currCU.ispMode || chromaCbfISP ) )
    
      {
        const uint32_t numberValidComponents = getNumberValidComponents(currArea.chromaFormat);
    
        const uint32_t cbfDepth = ( chromaCbfISP ? currDepth - 1 : currDepth );
    
    
        for (uint32_t ch = COMPONENT_Cb; ch < numberValidComponents; ch++)
        {
          const ComponentID compID = ComponentID(ch);
    
    
          if( currDepth == 0 || TU::getCbfAtDepth( currTU, compID, currDepth - 1 ) || chromaCbfISP )
    
          {
            const bool prevCbf = ( compID == COMPONENT_Cr ? TU::getCbfAtDepth( currTU, COMPONENT_Cb, currDepth ) : false );
    
            m_CABACEstimator->cbf_comp( cs, TU::getCbfAtDepth( currTU, compID, currDepth ), currArea.blocks[compID], cbfDepth, prevCbf );
    
    
          }
        }
      }
    
      if (subdiv)
      {
    
        if( partitioner.canSplit( TU_MAX_TR_SPLIT, cs ) )
        {
          partitioner.splitCurrArea( TU_MAX_TR_SPLIT, cs );
        }
    
        else if( currCU.ispMode && isLuma( compID ) )
        {
          partitioner.splitCurrArea( ispType, cs );
        }
    
          xEncSubdivCbfQT( cs, partitioner, bLuma, bChroma, subTuCounter, ispType );
          subTuCounter += subTuCounter != -1 ? 1 : 0;
    
        } while( partitioner.nextPart( cs ) );
    
        partitioner.exitCurrSplit();
      }
      else
      {
        //===== Cbfs =====
        if (bLuma)
        {
    
          bool previousCbf       = false;
          bool lastCbfIsInferred = false;
          if( ispType != TU_NO_ISP )
          {
            bool rootCbfSoFar = false;
            uint32_t nTus = currCU.ispMode == HOR_INTRA_SUBPARTITIONS ? currCU.lheight() >> g_aucLog2[currTU.lheight()] : currCU.lwidth() >> g_aucLog2[currTU.lwidth()];
            if( subTuCounter == nTus - 1 )
            {
              TransformUnit* tuPointer = currCU.firstTU;
              for( int tuIdx = 0; tuIdx < nTus - 1; tuIdx++ )
              {
                rootCbfSoFar |= TU::getCbfAtDepth( *tuPointer, COMPONENT_Y, currDepth );
                tuPointer = tuPointer->next;
              }
              if( !rootCbfSoFar )
              {
                lastCbfIsInferred = true;
              }
            }
            if( !lastCbfIsInferred )
            {
              previousCbf = TU::getPrevTuCbfAtDepth( currTU, COMPONENT_Y, partitioner.currTrDepth );
            }
          }
          if( !lastCbfIsInferred )
          {
            m_CABACEstimator->cbf_comp( cs, TU::getCbfAtDepth( currTU, COMPONENT_Y, currDepth ), currTU.Y(), currTU.depth, previousCbf, currCU.ispMode );
          }
    
    void IntraSearch::xEncCoeffQT( CodingStructure &cs, Partitioner &partitioner, const ComponentID compID, const int subTuIdx, const PartSplit ispType )
    
    {
      const UnitArea &currArea  = partitioner.currArea();
    
    
           int subTuCounter     = subTuIdx;
      TransformUnit &currTU     = *cs.getTU( currArea.blocks[partitioner.chType], partitioner.chType, subTuIdx );
    
      uint32_t      currDepth       = partitioner.currTrDepth;
      const bool subdiv         = currTU.depth > currDepth;
    
      if (subdiv)
      {
        if (partitioner.canSplit(TU_MAX_TR_SPLIT, cs))
        {
          partitioner.splitCurrArea(TU_MAX_TR_SPLIT, cs);
        }
    
        else if( currTU.cu->ispMode )
        {
          partitioner.splitCurrArea( ispType, cs );
        }
    
          xEncCoeffQT( cs, partitioner, compID, subTuCounter, ispType );
          subTuCounter += subTuCounter != -1 ? 1 : 0;
    
        } while( partitioner.nextPart( cs ) );
    
        partitioner.exitCurrSplit();
      }
      else
    
      if( currArea.blocks[compID].valid() )
      {
        if( TU::hasCrossCompPredInfo( currTU, compID ) )
        {
          m_CABACEstimator->cross_comp_pred( currTU, compID );
        }
        if( TU::getCbf( currTU, compID ) )
        {
          m_CABACEstimator->residual_coding( currTU, compID );
        }
      }
    }
    
    
    uint64_t IntraSearch::xGetIntraFracBitsQT( CodingStructure &cs, Partitioner &partitioner, const bool &bLuma, const bool &bChroma, const int subTuIdx, const PartSplit ispType )
    
      xEncIntraHeader( cs, partitioner, bLuma, bChroma, subTuIdx );
      xEncSubdivCbfQT( cs, partitioner, bLuma, bChroma, subTuIdx, ispType );
    
    
        xEncCoeffQT( cs, partitioner, COMPONENT_Y, subTuIdx, ispType );
    
        xEncCoeffQT( cs, partitioner, COMPONENT_Cb, subTuIdx, ispType );
        xEncCoeffQT( cs, partitioner, COMPONENT_Cr, subTuIdx, ispType );
      }
    
      uint64_t fracBits = m_CABACEstimator->getEstFracBits();
      return fracBits;
    }
    
    uint64_t IntraSearch::xGetIntraFracBitsQTSingleChromaComponent( CodingStructure &cs, Partitioner &partitioner, const ComponentID compID )
    {
      m_CABACEstimator->resetBits();
    
      if( compID == COMPONENT_Cb )
      {
    
        //intra mode coding
    
        PredictionUnit &pu = *cs.getPU( partitioner.currArea().lumaPos(), partitioner.chType );
        m_CABACEstimator->intra_chroma_pred_mode( pu );
        //xEncIntraHeader(cs, partitioner, false, true);
      }
      CHECK( partitioner.currTrDepth != 1, "error in the depth!" );
      const UnitArea &currArea = partitioner.currArea();
    
      TransformUnit &currTU = *cs.getTU( currArea.blocks[partitioner.chType], partitioner.chType );
    
      //cbf coding
      m_CABACEstimator->cbf_comp( cs, TU::getCbfAtDepth( currTU, compID, partitioner.currTrDepth ), currArea.blocks[compID], partitioner.currTrDepth - 1 );
      //coeffs coding and cross comp coding
      if( TU::hasCrossCompPredInfo( currTU, compID ) )
      {
        m_CABACEstimator->cross_comp_pred( currTU, compID );
      }
      if( TU::getCbf( currTU, compID ) )
      {
        m_CABACEstimator->residual_coding( currTU, compID );
    
      }
    
      uint64_t fracBits = m_CABACEstimator->getEstFracBits();
      return fracBits;
    }
    
    uint64_t IntraSearch::xGetIntraFracBitsQTChroma(TransformUnit& currTU, const ComponentID &compID)
    {
      m_CABACEstimator->resetBits();
    
      if( TU::hasCrossCompPredInfo( currTU, compID ) )
      {
        m_CABACEstimator->cross_comp_pred( currTU, compID );
      }
    
    
    #if JVET_N0054_JOINT_CHROMA
      // Include Cbf and jointCbCr flags here as we make decisions across components
      CodingStructure &cs = *currTU.cs;
    
      if ( currTU.jointCbCr )
      {
        if ( TU::getCbf( currTU, COMPONENT_Cb ) )
        {
          m_CABACEstimator->cbf_comp( cs, true, currTU.blocks[ COMPONENT_Cb ], currTU.depth, false );
          m_CABACEstimator->cbf_comp( cs, true, currTU.blocks[ COMPONENT_Cr ], currTU.depth, true );
          m_CABACEstimator->joint_cb_cr( currTU );
        }
        else
        {
          m_CABACEstimator->cbf_comp( cs, false, currTU.blocks[ COMPONENT_Cb ], currTU.depth, false );
          m_CABACEstimator->cbf_comp( cs, false, currTU.blocks[ COMPONENT_Cr ], currTU.depth, false );
        }
      }
      else
      {
        if ( compID == COMPONENT_Cb )
          m_CABACEstimator->cbf_comp( cs, TU::getCbf( currTU, compID ), currTU.blocks[ compID ], currTU.depth, false );
        else
          m_CABACEstimator->cbf_comp( cs, TU::getCbf( currTU, compID ), currTU.blocks[ compID ], currTU.depth, TU::getCbf( currTU, COMPONENT_Cb ) );
      }
    
      if( TU::getCbf( currTU, compID ) )
      {
        m_CABACEstimator->residual_coding( currTU, compID );
      }
    
      uint64_t fracBits = m_CABACEstimator->getEstFracBits();
      return fracBits;
    }
    
    
    Tung Nguyen's avatar
    Tung Nguyen committed
    void IntraSearch::xIntraCodingTUBlock(TransformUnit &tu, const ComponentID &compID, const bool &checkCrossCPrediction, Distortion& ruiDist, const int &default0Save1Load2, uint32_t* numSig, std::vector<TrMode>* trModes, const bool loadTr)
    
    {
      if (!tu.blocks[compID].valid())
      {
        return;
      }
    
      CodingStructure &cs                       = *tu.cs;
    
    #if JVET_N0671_RDCOST_FIX
      m_pcRdCost->setChromaFormat(cs.sps->getChromaFormatIdc());
    #endif
    
    
      const CompArea      &area                 = tu.blocks[compID];
      const SPS           &sps                  = *cs.sps;
      const PPS           &pps                  = *cs.pps;
    
      const ChannelType    chType               = toChannelType(compID);
      const int            bitDepth             = sps.getBitDepth(chType);
    
      PelBuf         piOrg                      = cs.getOrgBuf    (area);
      PelBuf         piPred                     = cs.getPredBuf   (area);
      PelBuf         piResi                     = cs.getResiBuf   (area);
      PelBuf         piOrgResi                  = cs.getOrgResiBuf(area);
      PelBuf         piReco                     = cs.getRecoBuf   (area);
    
      const PredictionUnit &pu                  = *cs.getPU(area.pos(), chType);
      const uint32_t           uiChFinalMode        = PU::getFinalIntraMode(pu, chType);
    
      const bool           bUseCrossCPrediction = pps.getPpsRangeExtension().getCrossComponentPredictionEnabledFlag() && isChroma( compID ) && PU::isChromaIntraModeCrossCheckMode( pu ) && checkCrossCPrediction;
      const bool           ccUseRecoResi        = m_pcEncCfg->getUseReconBasedCrossCPredictionEstimate();
    
    #if INCLUDE_ISP_CFG_FLAG
      const bool           ispSplitIsAllowed    = sps.getUseISP() && CU::canUseISPSplit( *tu.cu, compID );
    #else
    
      const bool           ispSplitIsAllowed    = CU::canUseISPSplit( *tu.cu, compID );
    
    #if JVET_N0054_JOINT_CHROMA
      bool jointCbCr = tu.jointCbCr && compID == COMPONENT_Cb;
    
      if ( compID == COMPONENT_Y )
      {
    #endif
    
      PelBuf sharedPredTS( m_pSharedPredTransformSkip[compID], area );
      if( default0Save1Load2 != 2 )
      {
    
    
        //===== get prediction signal =====
        if( compID != COMPONENT_Y && PU::isLMCMode( uiChFinalMode ) )
        {
          {
            xGetLumaRecPixels( pu, area );
          }
          predIntraChromaLM( compID, piPred, pu, area, uiChFinalMode );
        }
        else
        {
    
    #if JVET_N0217_MATRIX_INTRAPRED
          if( PU::isMIP( pu, chType ) )
          {
            predIntraMip( compID, piPred, pu );
          }
          else
          {
    #endif
    
    #if JVET_N0217_MATRIX_INTRAPRED
          }
    #endif
    
        }
    
    
        // save prediction
        if( default0Save1Load2 == 1 )
        {
          sharedPredTS.copyFrom( piPred );
        }
      }
      else
      {
        // load prediction
        piPred.copyFrom( sharedPredTS );
      }
    
    #if JVET_N0054_JOINT_CHROMA
      }
    #endif
    
    
    
      DTRACE( g_trace_ctx, D_PRED, "@(%4d,%4d) [%2dx%2d] IMode=%d\n", tu.lx(), tu.ly(), tu.lwidth(), tu.lheight(), uiChFinalMode );
      //DTRACE_PEL_BUF( D_PRED, piPred, tu, tu.cu->predMode, COMPONENT_Y );
    
    
    Taoran Lu's avatar
    Taoran Lu committed
      const Slice           &slice = *cs.slice;
    
    Taoran Lu's avatar
    Taoran Lu committed
      bool flag = slice.getReshapeInfo().getUseSliceReshaper() && (slice.isIntra() || (!slice.isIntra() && m_pcReshape->getCTUFlag()));
    
      if (flag && slice.getReshapeInfo().getSliceReshapeChromaAdj() && isChroma(compID))
    
    Taoran Lu's avatar
    Taoran Lu committed
      {
        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 );
        PelBuf piPredY;
        piPredY = cs.picture->getPredBuf(areaY);
        const Pel avgLuma = piPredY.computeAvg();
        int adj = m_pcReshape->calculateChromaAdj(avgLuma);
        tu.setChromaAdj(adj);
      }
    
      //===== get residual signal =====
      piResi.copyFrom( piOrg  );
    
    Taoran Lu's avatar
    Taoran Lu committed
      if (slice.getReshapeInfo().getUseSliceReshaper() && m_pcReshape->getCTUFlag() && compID==COMPONENT_Y)
      {
        CompArea      tmpArea(COMPONENT_Y, area.chromaFormat, Position(0, 0), area.size());
        PelBuf tmpPred = m_tmpStorageLCU.getBuf(tmpArea);
        tmpPred.copyFrom(piPred);
        piResi.rspSignal(m_pcReshape->getFwdLUT());
        piResi.subtract(tmpPred);
      }
      else
    
      piResi.subtract( piPred );
    
      if (pps.getPpsRangeExtension().getCrossComponentPredictionEnabledFlag() && isLuma(compID))
      {
        piOrgResi.copyFrom (piResi);
      }
    
      if (bUseCrossCPrediction)
      {
        if (xCalcCrossComponentPredictionAlpha(tu, compID, ccUseRecoResi) == 0)
        {
          return;
        }
        CrossComponentPrediction::crossComponentPrediction(tu, compID, cs.getResiBuf(tu.Y()), piResi, piResi, false);
      }
    
      //===== transform and quantization =====
      //--- init rate estimation arrays for RDOQ ---
      //--- transform and quantization           ---
      TCoeff uiAbsSum = 0;
    
      const QpParam cQP(tu, compID);
    
    #if RDOQ_CHROMA_LAMBDA
      m_pcTrQuant->selectLambda(compID);
    #endif
    
    
      flag =flag && (tu.blocks[compID].width*tu.blocks[compID].height > 4);
      if (flag && isChroma(compID) && slice.getReshapeInfo().getSliceReshapeChromaAdj() )
    
    Taoran Lu's avatar
    Taoran Lu committed
        int cResScaleInv = tu.getChromaAdj();
        double cResScale = round((double)(1 << CSCALE_FP_PREC) / (double)cResScaleInv);
        m_pcTrQuant->setLambda(m_pcTrQuant->getLambda() / (cResScale*cResScale));
    
    #if JVET_N0054_JOINT_CHROMA
        if ( !jointCbCr ) // Joint CbCr signal is to be scaled in the case of joint chroma
    #endif
    
    Taoran Lu's avatar
    Taoran Lu committed
        piResi.scaleSignal(cResScaleInv, 1, tu.cu->cs->slice->clpRng(compID));
    
    #if JVET_N0054_JOINT_CHROMA
      const CompArea &crArea = tu.blocks     [ COMPONENT_Cr ];
      PelBuf          crOrg  = cs.getOrgBuf  ( crArea );
      PelBuf          crPred = cs.getPredBuf ( crArea );
      PelBuf          crResi = cs.getResiBuf ( crArea );
      PelBuf          crReco = cs.getRecoBuf ( crArea );
    
      if ( jointCbCr )
      {
        // Get Cr prediction and residual
        crResi.copyFrom( crOrg  );
        crResi.subtract( crPred );
    
        // Create joint residual and store it for Cb component: jointResi = (cbResi - crResi)/2
        piResi.subtractAndHalve( crResi );
    
        // Scale the joint signal
        if ( flag && slice.getReshapeInfo().getSliceReshapeChromaAdj() )
          piResi.scaleSignal(tu.getChromaAdj(), 1, tu.cu->cs->slice->clpRng(compID));
    
        // Lambda is loosened for the joint mode with respect to single modes as the same residual is used for both chroma blocks
        m_pcTrQuant->setLambda( 0.60 * m_pcTrQuant->getLambda() );
      }
      else if ( isChroma(compID) && tu.cu->cs->slice->getSliceQp() > 18 )
        m_pcTrQuant->setLambda( 1.10 * m_pcTrQuant->getLambda() );
    #endif
    
      double diagRatio = 0, horVerRatio = 0;
    
    
    Tung Nguyen's avatar
    Tung Nguyen committed
      if( trModes )
      {
    
        m_pcTrQuant->transformNxN( tu, compID, cQP, trModes, CU::isIntra( *tu.cu ) ? m_pcEncCfg->getIntraMTSMaxCand() : m_pcEncCfg->getInterMTSMaxCand(), ispSplitIsAllowed ? &diagRatio : nullptr, ispSplitIsAllowed ? &horVerRatio : nullptr );
    
    Tung Nguyen's avatar
    Tung Nguyen committed
        tu.mtsIdx = trModes->at(0).first;
      }
    
      m_pcTrQuant->transformNxN( tu, compID, cQP, uiAbsSum, m_CABACEstimator->getCtx(), loadTr, &diagRatio, &horVerRatio );
    
    #if INCLUDE_ISP_CFG_FLAG
    
        if ( !tu.cu->ispMode && isLuma(compID) && ispSplitIsAllowed && tu.mtsIdx == MTS_DCT2_DCT2 && ispSplitIsAllowed )
    
      if ( !tu.cu->ispMode && isLuma(compID) && ispSplitIsAllowed && tu.mtsIdx == MTS_DCT2_DCT2 )
    
      {
        m_intraModeDiagRatio        .push_back(diagRatio);
        m_intraModeHorVerRatio      .push_back(horVerRatio);
        m_intraModeTestedNormalIntra.push_back((int)uiChFinalMode);
      }
    
    
    
      DTRACE( g_trace_ctx, D_TU_ABS_SUM, "%d: comp=%d, abssum=%d\n", DTRACE_GET_COUNTER( g_trace_ctx, D_TU_ABS_SUM ), compID, uiAbsSum );
    
    
      //--- inverse transform ---
      if (uiAbsSum > 0)
      {
        m_pcTrQuant->invTransformNxN(tu, compID, piResi, cQP);
      }
      else
      {
        piResi.fill(0);
      }
    
      //===== reconstruction =====
    
      if (flag && uiAbsSum > 0 && isChroma(compID) && slice.getReshapeInfo().getSliceReshapeChromaAdj() )
    
        piResi.scaleSignal(tu.getChromaAdj(), 0, tu.cu->cs->slice->clpRng(compID));
    
      if (bUseCrossCPrediction)
      {
        CrossComponentPrediction::crossComponentPrediction(tu, compID, cs.getResiBuf(tu.Y()), piResi, piResi, true);
      }
    
    
    Taoran Lu's avatar
    Taoran Lu committed
      if (slice.getReshapeInfo().getUseSliceReshaper() && m_pcReshape->getCTUFlag() && compID == COMPONENT_Y)
      {
        CompArea      tmpArea(COMPONENT_Y, area.chromaFormat, Position(0,0), area.size());
        PelBuf tmpPred = m_tmpStorageLCU.getBuf(tmpArea);
        tmpPred.copyFrom(piPred);
        piReco.reconstruct(tmpPred, piResi, cs.slice->clpRng(compID));
      }
    
      piReco.reconstruct(piPred, piResi, cs.slice->clpRng( compID ));
    
    
    #if JVET_N0054_JOINT_CHROMA
      if ( jointCbCr )
      {
        // Cr uses negative of the signalled Cb residual
        if (uiAbsSum > 0)
          crResi.copyAndNegate( piResi );
        else
          crResi.fill(0);
    
        tu.getCoeffs(COMPONENT_Cr).fill(0);
    
        // Set cbf also for Cr
        TU::setCbfAtDepth (tu, COMPONENT_Cr, tu.depth, uiAbsSum > 0 ? true : false);
    
        // Cr reconstruction and its contribution to the total error
        crReco.reconstruct(crPred, crResi, cs.slice->clpRng( COMPONENT_Cr ));
    
    #if WCG_EXT
        if ( m_pcEncCfg->getLumaLevelToDeltaQPMapping().isEnabled() ||
            (m_pcEncCfg->getReshaper()
             && slice.getReshapeInfo().getUseSliceReshaper()
             && (m_pcReshape->getCTUFlag() || (isChroma(compID) && m_pcEncCfg->getReshapeIntraCMD()))))
        {
          const CPelBuf orgLuma = cs.getOrgBuf( cs.area.blocks[COMPONENT_Y] );
          ruiDist += m_pcRdCost->getDistPart( crOrg, crReco, bitDepth, COMPONENT_Cr, DF_SSE_WTD, &orgLuma );
        }
        else
    #endif
        {
          ruiDist += m_pcRdCost->getDistPart( crOrg, crReco, bitDepth, COMPONENT_Cr, DF_SSE );
        }
      }
    #endif
    
    
    Taoran Lu's avatar
    Taoran Lu committed
      if (m_pcEncCfg->getLumaLevelToDeltaQPMapping().isEnabled() || (m_pcEncCfg->getReshaper()
        && slice.getReshapeInfo().getUseSliceReshaper() && (m_pcReshape->getCTUFlag() || (isChroma(compID) && m_pcEncCfg->getReshapeIntraCMD()))))
    
      {
        const CPelBuf orgLuma = cs.getOrgBuf( cs.area.blocks[COMPONENT_Y] );
    
    Taoran Lu's avatar
    Taoran Lu committed
        if (compID == COMPONENT_Y  && !(m_pcEncCfg->getLumaLevelToDeltaQPMapping().isEnabled()))
    
    Taoran Lu's avatar
    Taoran Lu committed
        {
          CompArea      tmpArea1(COMPONENT_Y, area.chromaFormat, Position(0, 0), area.size());
          PelBuf tmpRecLuma = m_tmpStorageLCU.getBuf(tmpArea1);
          tmpRecLuma.copyFrom(piReco);
          tmpRecLuma.rspSignal(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);
    
      }
      else
    #endif
      {
        ruiDist += m_pcRdCost->getDistPart( piOrg, piReco, bitDepth, compID, DF_SSE );
      }
    }
    
    
    #if JVET_N0193_LFNST
    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 )
    #else
    
    void IntraSearch::xRecurIntraCodingLumaQT( CodingStructure &cs, Partitioner &partitioner, const double bestCostSoFar, const int subTuIdx, const PartSplit ispType, const bool ispIsCurrentWinner )
    
    {
            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;
    
    #if JVET_N0193_LFNST
      const SPS &sps           = *cs.sps;
    #endif
    
      const PPS &pps           = *cs.pps;
      const bool keepResi      = pps.getPpsRangeExtension().getCrossComponentPredictionEnabledFlag() || KEEP_PRED_AND_RESI_SIGNALS;
      bool bCheckFull          = true;
      bool bCheckSplit         = false;
    
    Karsten Suehring's avatar
    Karsten Suehring committed
      bCheckFull               = !partitioner.canSplit( TU_MAX_TR_SPLIT, cs );
      bCheckSplit              = partitioner.canSplit( TU_MAX_TR_SPLIT, cs );
    
      if( cu.ispMode )
      {
        bCheckSplit = partitioner.canSplit( ispType, cs );
        bCheckFull = !bCheckSplit;
      }
    
    #if JVET_N0193_LFNST
      double     dSingleCost                        = MAX_DOUBLE;
      Distortion uiSingleDistLuma                   = 0;
      uint64_t   singleFracBits                     = 0;
      bool       checkTransformSkip                 = pps.getUseTransformSkip();
      int        bestModeId[ MAX_NUM_COMPONENT ]    = { 0, 0, 0 };
      uint8_t    nNumTransformCands                 = cu.mtsFlag ? 4 : 1;
      uint8_t    numTransformIndexCands             = nNumTransformCands;
    #else
    
    Tung Nguyen's avatar
    Tung Nguyen committed
      double     dSingleCost                        = MAX_DOUBLE;
      Distortion uiSingleDistLuma                   = 0;
      uint64_t   singleFracBits                     = 0;
      int        bestModeId[MAX_NUM_COMPONENT]      = { 0, 0, 0 };
    
    
      const TempCtx ctxStart  ( m_CtxCache, m_CABACEstimator->getCtx() );
      TempCtx       ctxBest   ( m_CtxCache );
    
      CodingStructure *csSplit = nullptr;
      CodingStructure *csFull  = nullptr;
    
      if( bCheckSplit )
      {
        csSplit = &cs;
      }
      else if( bCheckFull )
      {
        csFull = &cs;
      }
    
    
    #if JVET_N0193_LFNST
      bool validReturnFull = false;
    #endif
    
    
      if( bCheckFull )
      {
        csFull->cost = 0.0;
    
        TransformUnit &tu = csFull->addTU( CS::getArea( *csFull, currArea, partitioner.chType ), partitioner.chType );
        tu.depth = currDepth;
    
    
    #if JVET_N0193_LFNST
        const bool tsAllowed  = TU::isTSAllowed( tu, COMPONENT_Y );
        const bool mtsAllowed = TU::isMTSAllowed( tu, COMPONENT_Y );
        std::vector<TrMode> trModes;
    
        if( sps.getUseLFNST() )
        {
          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
        {
          nNumTransformCands = 1 + ( tsAllowed ? 1 : 0 ) + ( mtsAllowed ? 4 : 0 ); // DCT + TS + 4 MTS = 6 tests
    
          trModes.push_back( TrMode( 0, true ) ); //DCT2
          if( tsAllowed )
          {
            trModes.push_back( TrMode( 1, true ) );
          }
          if( mtsAllowed )
          {
            for( int i = 2; i < 6; i++ )
            {
              trModes.push_back( TrMode( i, true ) );
            }
          }
        }
    
        CHECK( !tu.Y().valid(), "Invalid TU" );
    #else
    
    Tung Nguyen's avatar
    Tung Nguyen committed
        const bool tsAllowed  = TU::isTSAllowed ( tu, COMPONENT_Y );
        const bool mtsAllowed = TU::isMTSAllowed( tu, COMPONENT_Y );
        uint8_t nNumTransformCands = 1 + ( tsAllowed ? 1 : 0 ) + ( mtsAllowed ? 4 : 0 ); // DCT + TS + 4 MTS = 6 tests
        std::vector<TrMode> trModes;
        trModes.push_back( TrMode( 0, true ) ); //DCT2
        if( tsAllowed )
        {
          trModes.push_back( TrMode( 1, true ) );
        }
        if( mtsAllowed )
        {
          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_N0193_LFNST
        int        firstCheckId      = ( sps.getUseLFNST() && mtsCheckRangeFlag && cu.mtsFlag ) ? mtsFirstCheckId : 0;
    #else
    
    #if JVET_N0193_LFNST
        //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;
    #else
    
    Tung Nguyen's avatar
    Tung Nguyen committed
        int       lastCheckId        = trModes[nNumTransformCands-1].first;
        bool isNotOnlyOneMode        = nNumTransformCands != 1;
    
    
        if( isNotOnlyOneMode )
        {
          saveCS.pcv     = cs.pcv;
          saveCS.picture = cs.picture;
          saveCS.area.repositionTo(cs.area);
          saveCS.clearTUs();
          tmpTU = &saveCS.addTU(currArea, partitioner.chType);
        }
    
    
    #if JVET_N0193_LFNST
        bool    cbfBestMode      = false;
        bool    cbfBestModeValid = false;
    #endif
    
    Tung Nguyen's avatar
    Tung Nguyen committed
        bool    cbfDCT2  = true;
    
        double threshold = m_pcEncCfg->getUseFastISP() && !cu.ispMode && ispIsCurrentWinner && nNumTransformCands > 1 ? 1 + 1.4 / sqrt( cu.lwidth() * cu.lheight() ) : 1;
    
    #if JVET_N0193_LFNST
        for( int modeId = firstCheckId; modeId <= ( sps.getUseLFNST() ? lastCheckId : ( nNumTransformCands - 1 ) ); modeId++ )
        {
          uint8_t transformIndex = modeId;
    
          if( sps.getUseLFNST() )
          {
            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( !cbfDCT2 || ( m_pcEncCfg->getUseTransformSkipFast() && bestModeId[ COMPONENT_Y ] == 1 ) )
            {
              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 != 0 && ( trModes[ modeId ].first != 1 || !tsAllowed ) && bestDCT2cost > bestCostSoFar * threshold )
            {
              continue;
            }
            tu.mtsIdx = trModes[ modeId ].first;
          }
    #else
    
    Tung Nguyen's avatar
    Tung Nguyen committed
        for( int modeId = firstCheckId; modeId < nNumTransformCands; modeId++ )
        {
          if( !cbfDCT2 || ( m_pcEncCfg->getUseTransformSkipFast() && bestModeId[COMPONENT_Y] == 1 ) )
          {
            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 != 0 && ( trModes[modeId].first != 1 || !tsAllowed ) && bestDCT2cost > bestCostSoFar * threshold )
    
    Tung Nguyen's avatar
    Tung Nguyen committed
          tu.mtsIdx = trModes[modeId].first;
    
    #if JVET_N0217_MATRIX_INTRAPRED
    
          //we compare the best cost for non lwip
    
          const double thresholdSkipMode = 1.0 + (1.4 / sqrt((double)(cu.lwidth() * cu.lheight())));
          if ( cu.mipFlag && tu.mtsIdx && m_bestCostNonMip != MAX_DOUBLE && m_bestCostNonMip * thresholdSkipMode < bestDCT2cost  )
          {
            continue;
          }
    #endif
    
    
          if ((modeId != firstCheckId) && isNotOnlyOneMode)
          {
            m_CABACEstimator->getCtx() = ctxStart;
          }
    
          int default0Save1Load2 = 0;
          singleDistTmpLuma = 0;
    
    
    #if JVET_N0193_LFNST
          if( modeId == firstCheckId && ( sps.getUseLFNST() ? ( modeId != lastCheckId ) : ( nNumTransformCands > 1 ) ) )
    #else
    
    Tung Nguyen's avatar
    Tung Nguyen committed
          if( modeId == firstCheckId && nNumTransformCands > 1 )
    
    #if JVET_N0193_LFNST
            if( sps.getUseLFNST() && !cbfBestModeValid )
            {
              default0Save1Load2 = 1;
            }
            else
            {
              default0Save1Load2 = 2;
            }
    #else
    
    #if JVET_N0193_LFNST
          if( sps.getUseLFNST() )
          {
            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 = ( uiIntraMode < 34 ) ? MTS_DST7_DCT8 : MTS_DCT8_DST7;
    
                else if( transformIndex == 2 )
    
                  tu.mtsIdx = ( uiIntraMode < 34 ) ? MTS_DCT8_DST7 : MTS_DST7_DCT8;
    
                  tu.mtsIdx = MTS_DST7_DST7 + transformIndex;
    
                tu.mtsIdx = MTS_DST7_DST7 + transformIndex;
    
              }
            }
            else
            {
              tu.mtsIdx = transformIndex;
            }
    
            if( !cu.mtsFlag && checkTransformSkip )
            {
              xIntraCodingTUBlock( tu, COMPONENT_Y, false, singleDistTmpLuma, default0Save1Load2, &numSig, modeId == 0 ? &trModes : nullptr, true );
              if( modeId == 0 )
              {
                for( int i = 0; i < 2; i++ )
                {
                  if( trModes[ i ].second )
                  {
                    lastCheckId = trModes[ i ].first;
                  }
                }
              }
            }
            else
            {
              xIntraCodingTUBlock( tu, COMPONENT_Y, false, singleDistTmpLuma, default0Save1Load2, &numSig );
            }
          }
          else
          {
            if( nNumTransformCands > 1 )
            {
              xIntraCodingTUBlock( tu, COMPONENT_Y, false, singleDistTmpLuma, default0Save1Load2, &numSig, modeId == 0 ? &trModes : nullptr, true );
              if( modeId == 0 )
              {
                for( int i = 0; i < nNumTransformCands; i++ )
                {
                  if( trModes[ i ].second )
                  {
                    lastCheckId = trModes[ i ].first;
                  }
                }
              }
            }
            else
            {
              xIntraCodingTUBlock( tu, COMPONENT_Y, false, singleDistTmpLuma, default0Save1Load2, &numSig );
            }
          }
    #else
    
    Tung Nguyen's avatar
    Tung Nguyen committed
          if( nNumTransformCands > 1 )
          {
            xIntraCodingTUBlock( tu, COMPONENT_Y, false, singleDistTmpLuma, default0Save1Load2, &numSig, modeId == 0 ? &trModes : nullptr, true );
            if( modeId == 0 )
            {
              for( int i = 0; i < nNumTransformCands; i++ )
              {
                if( trModes[i].second )
                {
                  lastCheckId = trModes[i].first;
                }
              }
            }
          }
          else
          {
            xIntraCodingTUBlock( tu, COMPONENT_Y, false, singleDistTmpLuma, default0Save1Load2, &numSig );
          }