Skip to content
Snippets Groups Projects
IntraSearch.cpp 233 KiB
Newer Older
  • Learn to ignore specific revisions
  •   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 )
    
          m_CABACEstimator->bdpcm_mode( cu, ComponentID(CHANNEL_TYPE_CHROMA) );
    
    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;
    
    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)
      {
        const bool chromaCbfISP = currArea.blocks[COMPONENT_Cb].valid() && currCU.ispMode && !subdiv;
        if ( !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 );
        }
    
        {
          THROW("Cannot perform an implicit split!");
        }
    
          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() >> floorLog2(currTU.lheight()) : currCU.lwidth() >> floorLog2(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, CUCtx* cuCtx )
    
    {
      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, cuCtx );
    
          subTuCounter += subTuCounter != -1 ? 1 : 0;
    
        } while( partitioner.nextPart( cs ) );
    
        partitioner.exitCurrSplit();
      }
      else
      {
    
        if (currArea.blocks[compID].valid())
    
          if (compID == COMPONENT_Cr)
    
            const int cbfMask = (TU::getCbf(currTU, COMPONENT_Cb) ? 2 : 0) + (TU::getCbf(currTU, COMPONENT_Cr) ? 1 : 0);
            m_CABACEstimator->joint_cb_cr(currTU, cbfMask);
          }
          if (TU::getCbf(currTU, compID))
          {
            if (isLuma(compID))
            {
              m_CABACEstimator->residual_coding(currTU, compID, cuCtx);
              m_CABACEstimator->mts_idx(*currTU.cu, cuCtx);
            }
            else
            {
              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, CUCtx* cuCtx )
    
      xEncIntraHeader( cs, partitioner, bLuma, bChroma, subTuIdx );
      xEncSubdivCbfQT( cs, partitioner, bLuma, bChroma, subTuIdx, ispType );
    
    
        xEncCoeffQT( cs, partitioner, COMPONENT_Y, subTuIdx, ispType, cuCtx );
    
        xEncCoeffQT( cs, partitioner, COMPONENT_Cb, subTuIdx, ispType );
        xEncCoeffQT( cs, partitioner, COMPONENT_Cr, subTuIdx, ispType );
      }
    
    
      CodingUnit& cu = *cs.getCU(partitioner.chType);
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #if !INTRA_RM_SMALL_BLOCK_SIZE_CONSTRAINTS
    
      if ( cuCtx && bLuma && cu.isSepTree() && ( !cu.ispMode || ( cu.lfnstIdx && subTuIdx == 0 ) || ( !cu.lfnstIdx && subTuIdx == m_ispTestedModes[cu.lfnstIdx].numTotalParts[cu.ispMode - 1] - 1 ) ) )
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #else
      if (cuCtx && bLuma && CS::isDualITree(cs) && (!cu.ispMode || (cu.lfnstIdx && subTuIdx == 0) || (!cu.lfnstIdx && subTuIdx == m_ispTestedModes[cu.lfnstIdx].numTotalParts[cu.ispMode - 1] - 1)))
    #endif
    
      {
        m_CABACEstimator->residual_lfnst_mode(cu, *cuCtx);
      }
    
    
      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
    
      const bool prevCbf = ( compID == COMPONENT_Cr ? TU::getCbfAtDepth( currTU, COMPONENT_Cb, partitioner.currTrDepth ) : false );
      m_CABACEstimator->cbf_comp( cs, TU::getCbfAtDepth( currTU, compID, partitioner.currTrDepth ), currArea.blocks[compID], partitioner.currTrDepth - 1, prevCbf );
    
      //coeffs coding and cross comp coding
      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();
    
      // Include Cbf and jointCbCr flags here as we make decisions across components
      CodingStructure &cs = *currTU.cs;
    
      if ( currTU.jointCbCr )
      {
    
        const int cbfMask = ( TU::getCbf( currTU, COMPONENT_Cb ) ? 2 : 0 ) + ( TU::getCbf( currTU, COMPONENT_Cr ) ? 1 : 0 );
        m_CABACEstimator->cbf_comp( cs, cbfMask>>1, currTU.blocks[ COMPONENT_Cb ], currTU.depth, false );
        m_CABACEstimator->cbf_comp( cs, cbfMask &1, currTU.blocks[ COMPONENT_Cr ], currTU.depth, cbfMask>>1 );
        if( cbfMask )
    
          m_CABACEstimator->joint_cb_cr( currTU, cbfMask );
    
          m_CABACEstimator->residual_coding( currTU, COMPONENT_Cb );
    
          m_CABACEstimator->residual_coding( currTU, COMPONENT_Cr );
    
      }
      else
      {
        if ( compID == COMPONENT_Cb )
    
          m_CABACEstimator->cbf_comp( cs, TU::getCbf( currTU, compID ), currTU.blocks[ compID ], currTU.depth, false );
    
        {
          const bool cbCbf    = TU::getCbf( currTU, COMPONENT_Cb );
          const bool crCbf    = TU::getCbf( currTU, compID );
          const int  cbfMask  = ( cbCbf ? 2 : 0 ) + ( crCbf ? 1 : 0 );
          m_CABACEstimator->cbf_comp( cs, crCbf, currTU.blocks[ compID ], currTU.depth, cbCbf );
          m_CABACEstimator->joint_cb_cr( currTU, cbfMask );
        }
    
      if( !currTU.jointCbCr && TU::getCbf( currTU, compID ) )
    
      {
        m_CABACEstimator->residual_coding( currTU, compID );
      }
    
      uint64_t fracBits = m_CABACEstimator->getEstFracBits();
      return fracBits;
    }
    
    
    void IntraSearch::xIntraCodingTUBlock(TransformUnit &tu, const ComponentID &compID, 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;
    
      m_pcRdCost->setChromaFormat(cs.sps->getChromaFormatIdc());
    
    
      const CompArea      &area                 = tu.blocks[compID];
      const SPS           &sps                  = *cs.sps;
    
    #if JVET_V0094_BILATERAL_FILTER
    
    Vadim Seregin's avatar
    Vadim Seregin committed
      const PPS           &pps                  = *cs.pps;
    #endif
    
    
      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         piReco                     = cs.getRecoBuf   (area);
    
      const PredictionUnit &pu                  = *cs.getPU(area.pos(), chType);
      const uint32_t           uiChFinalMode        = PU::getFinalIntraMode(pu, chType);
    
      //===== init availability pattern =====
    
      CHECK( tu.jointCbCr && compID == COMPONENT_Cr, "wrong combination of compID and jointCbCr" );
    
      bool jointCbCr = tu.jointCbCr && compID == COMPONENT_Cb;
    
        PelBuf sharedPredTS( m_pSharedPredTransformSkip[compID], area );
        if( default0Save1Load2 != 2 )
    
          bool predRegDiffFromTB = CU::isPredRegDiffFromTB(*tu.cu, compID);
          bool firstTBInPredReg = CU::isFirstTBInPredReg(*tu.cu, compID, area);
          CompArea areaPredReg(COMPONENT_Y, tu.chromaFormat, area);
          if (tu.cu->ispMode && isLuma(compID))
    
              if (firstTBInPredReg)
              {
                CU::adjustPredArea(areaPredReg);
                initIntraPatternChTypeISP(*tu.cu, areaPredReg, piReco);
              }
    
              initIntraPatternChTypeISP(*tu.cu, area, piReco);
    
    
          //===== get prediction signal =====
          if(compID != COMPONENT_Y && !tu.cu->bdpcmModeChroma && PU::isLMCMode(uiChFinalMode))
    
            xGetLumaRecPixels( pu, area );
            predIntraChromaLM( compID, piPred, pu, area, uiChFinalMode );
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #if JVET_V0130_INTRA_TMP
            if( PU::isTmp( pu, chType ) )
            {
              int foundCandiNum;
              m_pcTrQuant->getTargetTemplate( tu.cu, pu.lwidth(), pu.lheight() );
              m_pcTrQuant->candidateSearchIntra( tu.cu, pu.lwidth(), pu.lheight() );
              m_pcTrQuant->generateTMPrediction( piPred.buf, piPred.stride, pu.lwidth(), pu.lheight(), foundCandiNum );
              CHECK( foundCandiNum < 1, "" );
            }
            else if( PU::isMIP( pu, chType ) )
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #else
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #endif
    
              initIntraMip( pu, area );
              predIntraMip( compID, piPred, pu );
            }
            else
            {
              if (predRegDiffFromTB)
              {
                if (firstTBInPredReg)
                {
                  PelBuf piPredReg = cs.getPredBuf(areaPredReg);
                  predIntraAng(compID, piPredReg, pu);
                }
              }
              else
    
          // save prediction
          if( default0Save1Load2 == 1 )
          {
            sharedPredTS.copyFrom( piPred );
          }
        }
        else
    
          // load prediction
          piPred.copyFrom( sharedPredTS );
    
        }
      }
    
    
      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;
    
      bool flag = slice.getLmcsEnabledFlag() && (slice.isIntra() || (!slice.isIntra() && m_pcReshape->getCTUFlag()));
    
        //===== get residual signal =====
        piResi.copyFrom( piOrg  );
    
        if (slice.getLmcsEnabledFlag() && m_pcReshape->getCTUFlag() && compID == COMPONENT_Y)
    
    Vadim Seregin's avatar
    Vadim Seregin committed
          piResi.rspSignal( m_pcReshape->getFwdLUT() );
          piResi.subtract( piPred );
    
    
      //===== 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);
    
    Brian Heng's avatar
    Brian Heng committed
      if (flag && isChroma(compID) && slice.getPicHeader()->getLmcsChromaResidualScaleFlag() )
    
    Taoran Lu's avatar
    Taoran Lu committed
        int cResScaleInv = tu.getChromaAdj();
    
        double cResScale = (double)(1 << CSCALE_FP_PREC) / (double)cResScaleInv;
    
    Taoran Lu's avatar
    Taoran Lu committed
        m_pcTrQuant->setLambda(m_pcTrQuant->getLambda() / (cResScale*cResScale));
    
      PelBuf          crOrg;
      PelBuf          crPred;
      PelBuf          crResi;
      PelBuf          crReco;
    
      if (isChroma(compID))
      {
        const CompArea &crArea = tu.blocks[ COMPONENT_Cr ];
        crOrg  = cs.getOrgBuf  ( crArea );
        crPred = cs.getPredBuf ( crArea );
        crResi = cs.getResiBuf ( crArea );
        crReco = cs.getRecoBuf ( crArea );
      }
    
      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) && (tu.cu->cs->slice->getSliceQp() > 18) )
    
    Fangdong Chen's avatar
    Fangdong Chen committed
      {
        m_pcTrQuant->setLambda( 1.3 * m_pcTrQuant->getLambda() );
      }
    
          m_pcTrQuant->transformNxN(tu, compID, cQP, trModes, m_pcEncCfg->getMTSIntraMaxCand());
    
          tu.mtsIdx[compID] = trModes->at(0).first;
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    
    
        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);
        }
    
        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);
    
        if (tu.cu->ispMode && isLuma(compID) && CU::isISPLast(*tu.cu, area, area.compID) && CU::allLumaCBFsAreZero(*tu.cu))
        {
          // ISP has to have at least one non-zero CBF
          ruiDist = MAX_INT;
          return;
        }
        if ((m_pcEncCfg->getCostMode() == COST_LOSSLESS_CODING && slice.isLossless() && tu.mtsIdx[compID] == 0)
            && 0 == tu.cu->bdpcmMode)
        {
          uiAbsSum = 0;
          tu.getCoeffs(compID).fill(0);
          TU::setCbfAtDepth(tu, compID, tu.depth, 0);
        }
    
        //--- inverse transform ---
        if (uiAbsSum > 0)
        {
          m_pcTrQuant->invTransformNxN(tu, compID, piResi, cQP);
        }
        else
        {
          piResi.fill(0);
        }
    
        ComponentID codeCompId    = (tu.jointCbCr ? (tu.jointCbCr >> 1 ? COMPONENT_Cb : COMPONENT_Cr) : compID);
        const QpParam qpCbCr(tu, codeCompId);
    
    
        if( tu.jointCbCr )
        {
          ComponentID otherCompId = ( codeCompId==COMPONENT_Cr ? COMPONENT_Cb : COMPONENT_Cr );
          tu.getCoeffs( otherCompId ).fill(0); // do we need that?
          TU::setCbfAtDepth (tu, otherCompId, tu.depth, false );
        }
        PelBuf& codeResi = ( codeCompId == COMPONENT_Cr ? crResi : piResi );
        uiAbsSum = 0;
    
          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;
          }
    
        }
        // encoder bugfix: Set loadTr to aovid redundant transform process
    
        if (!(m_pcEncCfg->getCostMode() == COST_LOSSLESS_CODING && slice.isLossless() && tu.mtsIdx[compID] == 0) || tu.cu->bdpcmModeChroma != 0)
    
        {
            m_pcTrQuant->transformNxN(tu, codeCompId, qpCbCr, uiAbsSum, m_CABACEstimator->getCtx(), loadTr);
        }
    
        if ((m_pcEncCfg->getCostMode() == COST_LOSSLESS_CODING && slice.isLossless() && tu.mtsIdx[compID] == 0) && 0 == tu.cu->bdpcmModeChroma)
    
        {
            uiAbsSum = 0;
            tu.getCoeffs(compID).fill(0);
            TU::setCbfAtDepth(tu, compID, tu.depth, 0);
        }
    
    
        DTRACE( g_trace_ctx, D_TU_ABS_SUM, "%d: comp=%d, abssum=%d\n", DTRACE_GET_COUNTER( g_trace_ctx, D_TU_ABS_SUM ), codeCompId, uiAbsSum );
        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();
            return;
          }
          m_pcTrQuant->invTransformICT( tu, piResi, crResi );
          uiAbsSum = codedCbfMask;
        }
      }
    
    Brian Heng's avatar
    Brian Heng committed
      if ( flag && uiAbsSum > 0 && isChroma(compID) && slice.getPicHeader()->getLmcsChromaResidualScaleFlag() )
    
        piResi.scaleSignal(tu.getChromaAdj(), 0, tu.cu->cs->slice->clpRng(compID));
    
        if( jointCbCr )
        {
          crResi.scaleSignal(tu.getChromaAdj(), 0, tu.cu->cs->slice->clpRng(COMPONENT_Cr));
        }
    
      if (slice.getLmcsEnabledFlag() && m_pcReshape->getCTUFlag() && compID == COMPONENT_Y)
    
    Taoran Lu's avatar
    Taoran Lu committed
      {
        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( jointCbCr )
        {
          crReco.reconstruct(crPred, crResi, cs.slice->clpRng( COMPONENT_Cr ));
        }
      }
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #if SIGN_PREDICTION
      if ( sps.getNumPredSigns() > 0)
      {
        bool bJccrWithCr = tu.jointCbCr && !(tu.jointCbCr >> 1);
        bool bIsJccr     = tu.jointCbCr && isChroma(compID);
        ComponentID signPredCompID = bIsJccr ? (bJccrWithCr ? COMPONENT_Cr : COMPONENT_Cb): compID;
        bool reshapeChroma = flag && (TU::getCbf(tu, signPredCompID) || tu.jointCbCr) && isChroma(signPredCompID) && slice.getPicHeader()->getLmcsChromaResidualScaleFlag();
        m_pcTrQuant->predCoeffSigns(tu, compID, reshapeChroma);
      }
    #endif
    
    #if JVET_V0094_BILATERAL_FILTER
    
    Vadim Seregin's avatar
    Vadim Seregin committed
      CompArea      tmpArea1(COMPONENT_Y, area.chromaFormat, Position(0, 0), area.size());
      PelBuf tmpRecLuma;
      if(isLuma(compID))
      {
        tmpRecLuma = m_tmpStorageLCU.getBuf(tmpArea1);
        tmpRecLuma.copyFrom(piReco);
      }
      
      //===== update distortion =====
    #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 (compID == COMPONENT_Y)
        {
          if(!(m_pcEncCfg->getLumaLevelToDeltaQPMapping().isEnabled()))
          {
            tmpRecLuma.rspSignal(m_pcReshape->getInvLUT());
          }
    
          if (pps.getUseBIF() /*&& (uiAbsSum > 0)*/ && isLuma(compID) && (tu.cu->qp > 17) && (128 > std::max(tu.lumaSize().width, tu.lumaSize().height)))
          {
            CompArea compArea = tu.blocks[compID];
            PelBuf recIPredBuf = cs.slice->getPic()->getRecoBuf(compArea);
            if(!(m_pcEncCfg->getLumaLevelToDeltaQPMapping().isEnabled()))
            {
    
              m_bilateralFilter->bilateralFilterRDOdiamond5x5(tmpRecLuma, tmpRecLuma, tmpRecLuma, tu.cu->qp, recIPredBuf, cs.slice->clpRng(compID), tu, true, true, m_pcReshape->getInvLUT());
    
    Vadim Seregin's avatar
    Vadim Seregin committed
            }
            else
            {
              std::vector<Pel> dummy_invLUT;
    
              m_bilateralFilter->bilateralFilterRDOdiamond5x5(tmpRecLuma, tmpRecLuma, tmpRecLuma, tu.cu->qp, recIPredBuf, cs.slice->clpRng(compID), tu, true, false, dummy_invLUT);
    
    Vadim Seregin's avatar
    Vadim Seregin committed
            }
          }
          
          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);
          }
        }
      }
      else
    #endif
      {
        if(isLuma(compID))
        {
          if (pps.getUseBIF() /*&& (uiAbsSum > 0)*/ && isLuma(compID) && (tu.cu->qp > 17) && (128 > std::max(tu.lumaSize().width, tu.lumaSize().height)))
          {
            CompArea compArea = tu.blocks[compID];
            PelBuf recIPredBuf = cs.slice->getPic()->getRecoBuf(compArea);
            std::vector<Pel>        my_invLUT;
    
            m_bilateralFilter->bilateralFilterRDOdiamond5x5(tmpRecLuma, tmpRecLuma, tmpRecLuma, tu.cu->qp, recIPredBuf, cs.slice->clpRng(compID), tu, true, false, my_invLUT);
    
    Vadim Seregin's avatar
    Vadim Seregin committed
          }
          
          ruiDist += m_pcRdCost->getDistPart( piOrg, tmpRecLuma, bitDepth, compID, DF_SSE );
        }
        else
        {
          ruiDist += m_pcRdCost->getDistPart( piOrg, piReco, bitDepth, compID, DF_SSE );
          if( jointCbCr )
          {
            ruiDist += m_pcRdCost->getDistPart( crOrg, crReco, bitDepth, COMPONENT_Cr, DF_SSE );
          }
        }
      }
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #else
    
      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] );
    
    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);
    
    Vadim Seregin's avatar
    Vadim Seregin committed
          tmpRecLuma.rspSignal( piReco, m_pcReshape->getInvLUT() );
    
    Taoran Lu's avatar
    Taoran Lu committed
          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);
          }
        }
    
      }
      else
    #endif
      {
        ruiDist += m_pcRdCost->getDistPart( piOrg, piReco, bitDepth, compID, DF_SSE );
    
        if( jointCbCr )
        {
          ruiDist += m_pcRdCost->getDistPart( crOrg, crReco, bitDepth, COMPONENT_Cr, DF_SSE );
        }
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #endif
    
    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
        cs.picture->getRecoBuf( partitioner.currArea() ).copyFrom( cs.getRecoBuf( partitioner.currArea() ) );
    #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());
          cs.picture->getRecoBuf(currArea.Y()).copyFrom(cs.getRecoBuf(currArea.Y()));
    
          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 )
    
    {
            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;
    
      bool bCheckFull          = true;
      bool bCheckSplit         = false;