Skip to content
Snippets Groups Projects
IntraSearch.cpp 293 KiB
Newer Older
  • Learn to ignore specific revisions
  •           for (int i = idx - 1; i >= 0; i--)
    
                uint32_t sad = pelList[i].getSAD(element, cs.sps->getBitDepths(), tmpCompBegin, tmpNumComp, lossless);
                if (sad < bestSAD)
                {
                  bestSAD = sad;
                  besti   = i;
                  if (!sad)
                  {
                    break;
                  }
                }
    
          if (besti >= 0 && pelList[besti].almostEqualData(element, errorLimit, cs.sps->getBitDepths(), tmpCompBegin, tmpNumComp, lossless))
    
          {
            pelList[besti].addElement(element, tmpCompBegin, tmpNumComp);
            last = besti;
          }
          else
          {
            pelList[idx].copyDataFrom(element, tmpCompBegin, tmpNumComp);
            for (int comp = tmpCompBegin; comp < (tmpCompBegin + tmpNumComp); comp++)
    
              pelList[idx].setCnt(1, comp);
    
            last = idx;
            idx++;
          }
        }
      }
    
      if( cs.sps->getChromaFormatIdc() != CHROMA_444 && numComp == 3 )
      {
        for( int i = 0; i < idx; i++ )
        {
          pelList[i].setCnt( pelList[i].getCnt(COMPONENT_Y) + (pelList[i].getCnt(COMPONENT_Cb) >> 2), MAX_NUM_COMPONENT);
        }
      }
      else
      {
        if( compBegin == 0 )
        {
          for( int i = 0; i < idx; i++ )
          {
            pelList[i].setCnt(pelList[i].getCnt(COMPONENT_Y), COMPONENT_Cb);
            pelList[i].setCnt(pelList[i].getCnt(COMPONENT_Y), COMPONENT_Cr);
            pelList[i].setCnt(pelList[i].getCnt(COMPONENT_Y), MAX_NUM_COMPONENT);
          }
        }
        else
        {
          for( int i = 0; i < idx; i++ )
          {
            pelList[i].setCnt(pelList[i].getCnt(COMPONENT_Cb), COMPONENT_Y);
            pelList[i].setCnt(pelList[i].getCnt(COMPONENT_Cb), MAX_NUM_COMPONENT);
          }
        }
      }
    
      for (int i = 0; i < dictMaxSize; i++)
    
        pelListSort[i].setCnt(0, COMPONENT_Y);
        pelListSort[i].setCnt(0, COMPONENT_Cb);
        pelListSort[i].setCnt(0, COMPONENT_Cr);
        pelListSort[i].setCnt(0, MAX_NUM_COMPONENT);
    
        pelListSort[i].resetAll(compBegin, numComp);
    
      dictMaxSize = 1;
      for (int i = 0; i < idx; i++)
    
        if( pelList[i].getCnt(MAX_NUM_COMPONENT) > pelListSort[dictMaxSize - 1].getCnt(MAX_NUM_COMPONENT) )
    
          for (j = dictMaxSize; j > 0; j--)
    
            if (pelList[i].getCnt(MAX_NUM_COMPONENT) > pelListSort[j - 1].getCnt(MAX_NUM_COMPONENT))
    
              pelListSort[j].copyAllFrom(pelListSort[j - 1], compBegin, numComp);
    
              dictMaxSize = std::min(dictMaxSize + 1, (uint32_t)maxPltSize);
    
          pelListSort[j].copyAllFrom(pelList[i], compBegin, numComp);
    
      uint32_t paletteSize = 0;
    
      uint64_t numColorBits = 0;
      for (int comp = compBegin; comp < (compBegin + numComp); comp++)
      {
        numColorBits += (comp > 0) ? channelBitDepth_C : channelBitDepth_L;
      }
    
      const int plt_lambda_shift = (compBegin > 0) ? pcmShiftRight_C : pcmShiftRight_L;
      double    bitCost          = m_pcRdCost->getLambda() / (double) (1 << (2 * plt_lambda_shift)) * numColorBits;
    
      bool   reuseflag[MAXPLTPREDSIZE] = { false };
      int    run;
      double reuseflagCost;
    
      for (int i = 0; i < maxPltSize; i++)
    
      {
        if( pelListSort[i].getCnt(MAX_NUM_COMPONENT) )
        {
          ComponentID tmpCompBegin = compBegin;
          int tmpNumComp = numComp;
          if( cs.sps->getChromaFormatIdc() != CHROMA_444 && numComp == 3 && pelListSort[i].getCnt(COMPONENT_Cb) == 0 )
          {
            tmpCompBegin = COMPONENT_Y;
            tmpNumComp   = 1;
          }
    
          for( int comp = tmpCompBegin; comp < (tmpCompBegin + tmpNumComp); comp++ )
          {
            int half = pelListSort[i].getCnt(comp) >> 1;
            cu.curPLT[comp][paletteSize] = (pelListSort[i].getSumData(comp) + half) / pelListSort[i].getCnt(comp);
          }
    
          int best = -1;
          if( errorLimit )
          {
            double pal[MAX_NUM_COMPONENT], err = 0.0, bestCost = 0.0;
            for( int comp = tmpCompBegin; comp < (tmpCompBegin + tmpNumComp); comp++ )
            {
              pal[comp] = pelListSort[i].getSumData(comp) / (double)pelListSort[i].getCnt(comp);
              err = pal[comp] - cu.curPLT[comp][paletteSize];
              if( isChroma((ComponentID) comp) )
              {
                bestCost += (err * err * PLT_CHROMA_WEIGHTING) / (1 << (2 * pcmShiftRight_C)) * pelListSort[i].getCnt(comp);
              }
              else
              {
                bestCost += (err * err) / (1 << (2 * pcmShiftRight_L)) * pelListSort[i].getCnt(comp);
              }
            }
            bestCost += bitCost;
    
            for( int t = 0; t < cs.prevPLT.curPLTSize[compBegin]; t++ )
            {
              double cost = 0.0;
              for( int comp = tmpCompBegin; comp < (tmpCompBegin + tmpNumComp); comp++ )
              {
                err = pal[comp] - cs.prevPLT.curPLT[comp][t];
                if( isChroma((ComponentID) comp) )
                {
                  cost += (err * err * PLT_CHROMA_WEIGHTING) / (1 << (2 * pcmShiftRight_C)) * pelListSort[i].getCnt(comp);
                }
                else
                {
                  cost += (err * err) / (1 << (2 * pcmShiftRight_L)) * pelListSort[i].getCnt(comp);
                }
              }
              run = 0;
              for (int t2 = t; t2 >= 0; t2--)
              {
                if (!reuseflag[t2])
                {
                  run++;
                }
                else
                {
                  break;
                }
              }
              reuseflagCost = m_pcRdCost->getLambda() / (double)(1 << (2 * plt_lambda_shift)) * getEpExGolombNumBins(run ? run + 1 : run, 0);
              cost += reuseflagCost;
    
              if( cost < bestCost )
              {
                best = t;
                bestCost = cost;
              }
            }
            if( best != -1 )
            {
              for( int comp = tmpCompBegin; comp < (tmpCompBegin + tmpNumComp); comp++ )
              {
                cu.curPLT[comp][paletteSize] = cs.prevPLT.curPLT[comp][best];
              }
              reuseflag[best] = true;
            }
          }
    
          bool duplicate = false;
          if( pelListSort[i].getCnt(MAX_NUM_COMPONENT) == 1 && best == -1 )
          {
            duplicate = true;
          }
          else
          {
            for( int t = 0; t < paletteSize; t++ )
            {
              bool duplicateTmp = true;
              for( int comp = tmpCompBegin; comp < (tmpCompBegin + tmpNumComp); comp++ )
              {
                duplicateTmp = duplicateTmp && (cu.curPLT[comp][paletteSize] == cu.curPLT[comp][t]);
              }
              if( duplicateTmp )
              {
                duplicate = true;
                break;
              }
            }
          }
          if( !duplicate )
          {
            if( cs.sps->getChromaFormatIdc() != CHROMA_444 && numComp == 3 && pelListSort[i].getCnt(COMPONENT_Cb) == 0 )
            {
              if( best != -1 )
              {
                cu.curPLT[COMPONENT_Cb][paletteSize] = cs.prevPLT.curPLT[COMPONENT_Cb][best];
                cu.curPLT[COMPONENT_Cr][paletteSize] = cs.prevPLT.curPLT[COMPONENT_Cr][best];
              }
              else
              {
                cu.curPLT[COMPONENT_Cb][paletteSize] = 1 << (channelBitDepth_C - 1);
                cu.curPLT[COMPONENT_Cr][paletteSize] = 1 << (channelBitDepth_C - 1);
              }
            }
            paletteSize++;
          }
        }
        else
        {
          break;
        }
      }
    
      cu.curPLTSize[compBegin] = paletteSize;
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #if !INTRA_RM_SMALL_BLOCK_SIZE_CONSTRAINTS
    
      if( cu.isLocalSepTree() )
    
        cu.curPLTSize[COMPONENT_Y] = paletteSize;
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #endif
    
      delete[] pelList;
      delete[] pelListSort;
    
    // -------------------------------------------------------------------------------------------------------------------
    // 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();
    
          if ((!cs.slice->isIntra() || cs.slice->getSPS()->getIBCFlag() || cs.slice->getSPS()->getPLTMode())
    
              && cu.Y().valid())
    
          {
            m_CABACEstimator->cu_skip_flag( cu );
            m_CABACEstimator->pred_mode   ( cu );
          }
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #if ENABLE_DIMD
          m_CABACEstimator->cu_dimd_flag(cu);
    #endif
    
        }
    
        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())
    
    Karsten Suehring's avatar
    Karsten Suehring committed
            m_CABACEstimator->pred_mode( cu );
    
          m_CABACEstimator->bdpcm_mode( cu, COMPONENT_Y );
    
    Karsten Suehring's avatar
    Karsten Suehring committed
          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 )
    
          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;
    }
    
    #if JVET_W0103_INTRA_MTS
    void IntraSearch::xSelectAMTForFullRD(TransformUnit &tu)
    {
      if (!tu.blocks[COMPONENT_Y].valid())
      {
        return;
      }
    
      if (!tu.cu->mtsFlag)
      {
        return;
      }
    
      CodingStructure &cs = *tu.cs;
      m_pcRdCost->setChromaFormat(cs.sps->getChromaFormatIdc());
    
      const CompArea      &area = tu.blocks[COMPONENT_Y];
    
      const ChannelType    chType = toChannelType(COMPONENT_Y);
    
    
      PelBuf         piOrg = cs.getOrgBuf(area);
      PelBuf         piPred = cs.getPredBuf(area);
      PelBuf         piResi = cs.getResiBuf(area);
    
    
      const PredictionUnit &pu = *cs.getPU(area.pos(), chType);
    
      //===== init availability pattern =====
    
      PelBuf sharedPredTS(m_pSharedPredTransformSkip[COMPONENT_Y], area);
      initIntraPatternChType(*tu.cu, area);
    
      //===== get prediction signal =====
      if (PU::isMIP(pu, chType))
      {
        initIntraMip(pu, area);
        predIntraMip(COMPONENT_Y, piPred, pu);
      }
      else
      {
        predIntraAng(COMPONENT_Y, piPred, pu);
      }
    
    
      // save prediction
      sharedPredTS.copyFrom(piPred);
    
      const Slice           &slice = *cs.slice;
      //===== get residual signal =====
      piResi.copyFrom(piOrg);
      if (slice.getLmcsEnabledFlag() && m_pcReshape->getCTUFlag())
      {
        piResi.rspSignal(m_pcReshape->getFwdLUT());
        piResi.subtract(piPred);
      }
      else
      {
        piResi.subtract(piPred);
      }
      // do transform and calculate Coeff AbsSum for all MTS candidates
    
    #if JVET_Y0142_ADAPT_INTRA_MTS
      int nCands = MTS_NCANDS[2];
      if (m_coeffAbsSumDCT2 >= 0 && m_coeffAbsSumDCT2 <= MTS_TH_COEFF[0])
      {
        nCands = MTS_NCANDS[0];
      }
      else if(m_coeffAbsSumDCT2 > MTS_TH_COEFF[0] && m_coeffAbsSumDCT2 <= MTS_TH_COEFF[1])
      {
        nCands = MTS_NCANDS[1];
      }
      std::vector<std::pair<int, uint64_t>> coeffAbsSum(nCands);
      for (int i = 0; i < nCands; i++)
    #else
      std::vector<std::pair<int, uint64_t>> coeffAbsSum(4);
    
      for (int i = 0; i < 4; i++)
    
      {
        tu.mtsIdx[0] = i + MTS_DST7_DST7;
        uint64_t AbsSum = m_pcTrQuant->transformNxN(tu);
    
        coeffAbsSum[i] = { i, AbsSum };
    
      std::stable_sort(coeffAbsSum.begin(), coeffAbsSum.end(), [](const std::pair<int, uint64_t> & l, const std::pair<int, uint64_t> & r) {return l.second < r.second; });
    #if JVET_Y0142_ADAPT_INTRA_MTS
      for (int i = 0; i < nCands; i++)
    #else
    
      for (int i = 0; i < 4; i++)
    
        m_testAMTForFullRD[i] = coeffAbsSum[i].first;
    
    #if JVET_Y0142_ADAPT_INTRA_MTS
      m_numCandAMTForFullRD = nCands;
    #else
    
      m_numCandAMTForFullRD = 4;
    
    #endif
    #if !JVET_Y0142_ADAPT_INTRA_MTS
    
      if (m_pcEncCfg->getUseFastLFNST())
      {
        double skipThreshold = 1.0 + 1.0 / sqrt((double)(area.width*area.height));
        skipThreshold = std::max(skipThreshold, 1.03);
        for (int i = 1; i < m_numCandAMTForFullRD; i++)
        {
    
          if (coeffAbsSum[i].second > skipThreshold * coeffAbsSum[0].second)
    
          {
            m_numCandAMTForFullRD = i;
            break;
          }
        }
      }
    
    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 || JVET_X0071_CHROMA_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);
    
    
    #if JVET_AB0061_ITMP_BV_FOR_IBC
      PredictionUnit &pu = *cs.getPU(area.pos(), chType);
    #else
    
      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;
    
    #if JVET_W0069_TMP_BOUNDARY
    
              RefTemplateType tempType = getRefTemplateType( *(tu.cu), tu.cu->blocks[COMPONENT_Y] );
              if( tempType != NO_TEMPLATE )
    
    Vadim Seregin's avatar
    Vadim Seregin committed
              {
    
                getTargetTemplate( tu.cu, pu.lwidth(), pu.lheight(), tempType );
                candidateSearchIntra( tu.cu, pu.lwidth(), pu.lheight(), tempType );
                generateTMPrediction( piPred.buf, piPred.stride, pu.lwidth(), pu.lheight(), foundCandiNum );
    
    #if JVET_AB0061_ITMP_BV_FOR_IBC
                pu.interDir               = 1;             // use list 0 for IBC mode
                pu.refIdx[REF_PIC_LIST_0] = MAX_NUM_REF;   // last idx in the list
                pu.mv->set(m_tempLibFast.getX() << MV_FRACTIONAL_BITS_INTERNAL, m_tempLibFast.getY() << MV_FRACTIONAL_BITS_INTERNAL);
                pu.bv.set(m_tempLibFast.getX(), m_tempLibFast.getY());
    #endif
    
    Vadim Seregin's avatar
    Vadim Seregin committed
              }
              else
              {
                foundCandiNum = 1;
    
                generateTmDcPrediction( piPred.buf, piPred.stride, pu.lwidth(), pu.lheight(), 1 << (tu.cu->cs->sps->getBitDepth( CHANNEL_TYPE_LUMA ) - 1) );
    
    #if JVET_AB0061_ITMP_BV_FOR_IBC
                pu.interDir               = 1;             // use list 0 for IBC mode
                pu.refIdx[REF_PIC_LIST_0] = MAX_NUM_REF;   // last idx in the list
                pu.mv->set(0, 0);
                pu.bv.set(0, 0);
    #endif
    
    Vadim Seregin's avatar
    Vadim Seregin committed
              }
    
              getTargetTemplate( tu.cu, pu.lwidth(), pu.lheight() );
              candidateSearchIntra( tu.cu, pu.lwidth(), pu.lheight() );
              generateTMPrediction( piPred.buf, piPred.stride, pu.lwidth(), pu.lheight(), foundCandiNum );
    
    #endif
    
    Vadim Seregin's avatar
    Vadim Seregin committed
              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
    
    #if JVET_Z0050_DIMD_CHROMA_FUSION
              if (compID != COMPONENT_Y && pu.isChromaFusion)
              {
                geneChromaFusionPred(compID, piPred, pu);
              }
    #endif
    
          // 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()));
    
    #if JVET_W0103_INTRA_MTS
      if (!tu.cu->mtsFlag && isLuma(compID))
    #else
    
        //===== 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() );
      }
    
    #if JVET_Y0142_ADAPT_INTRA_MTS
          m_pcTrQuant->transformNxN(tu, compID, cQP, trModes, 8);
    #else
    
          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 JVET_Y0142_ADAPT_INTRA_MTS
        if (isLuma(compID) && tu.mtsIdx[compID] >= MTS_DST7_DST7)
        {
          bool signHiding = cs.slice->getSignDataHidingEnabledFlag();
          CoeffCodingContext  cctx(tu, compID, signHiding);
          const TCoeff*       coeff = tu.getCoeffs(compID).buf;
          int          scanPosLast = -1;
          uint64_t     coeffAbsSum = 0;
    
          for (int scanPos = 0; scanPos < cctx.maxNumCoeff(); scanPos++)
          {
            unsigned blkPos = cctx.blockPos(scanPos);
            if (coeff[blkPos])
            {
              scanPosLast = scanPos;
              coeffAbsSum += abs(coeff[blkPos]);
            }
          }
          int nCands = (coeffAbsSum > MTS_TH_COEFF[1]) ? MTS_NCANDS[2] : (coeffAbsSum > MTS_TH_COEFF[0]) ? MTS_NCANDS[1] : MTS_NCANDS[0];
          bool isInvalid = (scanPosLast <= 0) || ((tu.mtsIdx[COMPONENT_Y] - MTS_DST7_DST7) >= nCands);
          if (isInvalid)
          {
            m_validMTSReturn = false;
            ruiDist = MAX_INT;
            return;
          }
        }
    #endif
    
        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;