Skip to content
Snippets Groups Projects
IntraSearch.cpp 146 KiB
Newer Older
  • Learn to ignore specific revisions
  •             m_bestModeCostValid[ lfnstIdx ] = true;
    
              }
              if( csBest->cost < bestCurrentCost )
              {
                bestCurrentCost = csBest->cost;
              }
              if( !cu.ispMode && !cu.mtsFlag )
              {
                m_modeCtrl->setMtsFirstPassNoIspCost( csBest->cost );
              }
            }
            if( !cu.ispMode && !cu.bdpcmMode && csBest->cost < bestCostNonBDPCM )
    
              bestCostNonBDPCM = csBest->cost;
    
          if( m_pcEncCfg->getFastLocalDualTreeMode() )
    
            if( cu.isConsIntra() && !cu.slice->isIntra() && csBest->cost != MAX_DOUBLE && costInterCU != COST_UNKNOWN && mode >= 0 )
    
              if( m_pcEncCfg->getFastLocalDualTreeMode() == 2 )
    
                //Note: only try one intra mode, which is especially useful to reduce EncT for LDB case (around 4%)
    
        cu.ispMode = uiBestPUMode.ispMod;
    
        if( validReturn )
        {
          cs.useSubStructure( *csBest, partitioner.chType, pu.singleChan( CHANNEL_TYPE_LUMA ), true, true, keepResi, keepResi );
        }
    
        if( validReturn )
        {
          //=== update PU data ====
          cu.mipFlag = uiBestPUMode.mipFlg;
          pu.multiRefIdx = uiBestPUMode.mRefId;
          pu.intraDir[ CHANNEL_TYPE_LUMA ] = uiBestPUMode.modeId;
          cu.bdpcmMode = bestBDPCMMode;
        }
    
      }
    
      //===== reset context models =====
      m_CABACEstimator->getCtx() = ctxStart;
    
    void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner, const double maxCostAllowed )
    
    {
      const ChromaFormat format   = cu.chromaFormat;
      const uint32_t    numberValidComponents = getNumberValidComponents(format);
      CodingStructure &cs = *cu.cs;
      const TempCtx ctxStart  ( m_CtxCache, m_CABACEstimator->getCtx() );
    
      cs.setDecomp( cs.area.Cb(), false );
    
    
      double    bestCostSoFar = maxCostAllowed;
    
      bool      lumaUsesISP   = !cu.isSepTree() && cu.ispMode;
    
      PartSplit ispType       = lumaUsesISP ? CU::getISPType( cu, COMPONENT_Y ) : TU_NO_ISP;
      CHECK( cu.ispMode && bestCostSoFar < 0, "bestCostSoFar must be positive!" );
    
    
      auto &pu = *cu.firstPU;
    
      {
        uint32_t       uiBestMode = 0;
        Distortion uiBestDist = 0;
        double     dBestCost = MAX_DOUBLE;
    
        //----- init mode list ----
        {
          uint32_t  uiMinMode = 0;
          uint32_t  uiMaxMode = NUM_CHROMA_MODE;
    
          //----- check chroma modes -----
          uint32_t chromaCandModes[ NUM_CHROMA_MODE ];
          PU::getIntraChromaCandModes( pu, chromaCandModes );
    
          // create a temporary CS
          CodingStructure &saveCS = *m_pSaveCS[0];
          saveCS.pcv      = cs.pcv;
          saveCS.picture  = cs.picture;
          saveCS.area.repositionTo( cs.area );
          saveCS.clearTUs();
    
    
          if( !cu.isSepTree() && cu.ispMode )
    
          if( cu.isSepTree() )
    
          {
            if( partitioner.canSplit( TU_MAX_TR_SPLIT, cs ) )
            {
              partitioner.splitCurrArea( TU_MAX_TR_SPLIT, cs );
    
              do
              {
                cs.addTU( CS::getArea( cs, partitioner.currArea(), partitioner.chType ), partitioner.chType ).depth = partitioner.currTrDepth;
              } while( partitioner.nextPart( cs ) );
    
              partitioner.exitCurrSplit();
            }
            else
            cs.addTU( CS::getArea( cs, partitioner.currArea(), partitioner.chType ), partitioner.chType );
          }
    
          std::vector<TransformUnit*> orgTUs;
    
    
          if( lumaUsesISP )
          {
            CodingUnit& auxCU = saveCS.addCU( cu, partitioner.chType );
            auxCU.ispMode = cu.ispMode;
            saveCS.sps = cu.cs->sps;
            saveCS.addPU( *cu.firstPU, partitioner.chType );
          }
    
    
    
          // create a store for the TUs
          for( const auto &ptu : cs.tus )
          {
            // for split TUs in HEVC, add the TUs without Chroma parts for correct setting of Cbfs
    
            if( lumaUsesISP || pu.contains( *ptu, CHANNEL_TYPE_CHROMA ) )
    
            {
              saveCS.addTU( *ptu, partitioner.chType );
              orgTUs.push_back( ptu );
            }
          }
    
          // SATD pre-selecting.
          int satdModeList[NUM_CHROMA_MODE];
          int64_t satdSortedCost[NUM_CHROMA_MODE];
          for (int i = 0; i < NUM_CHROMA_MODE; i++)
          {
            satdSortedCost[i] = 0; // for the mode not pre-select by SATD, do RDO by default, so set the initial value 0.
            satdModeList[i] = 0;
          }
          bool modeIsEnable[NUM_INTRA_MODE + 1]; // use intra mode idx to check whether enable
          for (int i = 0; i < NUM_INTRA_MODE + 1; i++)
          {
            modeIsEnable[i] = 1;
          }
    
    #if JVET_P0058_CHROMA_TS_ENCODER_INTRA_SAD_MOD
          DistParam distParamSad;
          DistParam distParamSatd;
    #else
    
          DistParam distParam;
    
    #endif
    #if JVET_P0058_CHROMA_TS_ENCODER_INTRA_SAD_MOD
    #else
    
          const bool useHadamard = !cu.transQuantBypass;
    
          pu.intraDir[1] = MDLM_L_IDX; // temporary assigned, just to indicate this is a MDLM mode. for luma down-sampling operation.
    
          initIntraPatternChType(cu, pu.Cb());
          initIntraPatternChType(cu, pu.Cr());
          xGetLumaRecPixels(pu, pu.Cb());
    
          for (int idx = uiMinMode; idx <= uiMaxMode - 1; idx++)
          {
            int mode = chromaCandModes[idx];
            satdModeList[idx] = mode;
            if (PU::isLMCMode(mode) && !PU::isLMCModeEnabled(pu, mode))
            {
              continue;
            }
    
            if ((mode == LM_CHROMA_IDX) || (mode == PLANAR_IDX) || (mode == DM_CHROMA_IDX)) // only pre-check regular modes and MDLM modes, not including DM ,Planar, and LM
    
            {
              continue;
            }
            pu.intraDir[1] = mode; // temporary assigned, for SATD checking.
    
    
    #if JVET_P0058_CHROMA_TS_ENCODER_INTRA_SAD_MOD
            int64_t sad = 0;
            int64_t sadCb = 0;
            int64_t satdCb = 0;
            int64_t sadCr = 0;
            int64_t satdCr = 0;
    #else
    
            int64_t sad = 0;
    
            CodingStructure& cs = *(pu.cs);
    
            CompArea areaCb = pu.Cb();
            PelBuf orgCb = cs.getOrgBuf(areaCb);
            PelBuf predCb = cs.getPredBuf(areaCb);
    
    #if JVET_P0058_CHROMA_TS_ENCODER_INTRA_SAD_MOD
            m_pcRdCost->setDistParam(distParamSad, orgCb, predCb, pu.cs->sps->getBitDepth(CHANNEL_TYPE_CHROMA), COMPONENT_Cb, false);
            m_pcRdCost->setDistParam(distParamSatd, orgCb, predCb, pu.cs->sps->getBitDepth(CHANNEL_TYPE_CHROMA), COMPONENT_Cb, true);
    #else
    
            m_pcRdCost->setDistParam(distParam, orgCb, predCb, pu.cs->sps->getBitDepth(CHANNEL_TYPE_CHROMA), COMPONENT_Cb, useHadamard);
    
    #endif
    #if JVET_P0058_CHROMA_TS_ENCODER_INTRA_SAD_MOD
            distParamSad.applyWeight = false;
            distParamSatd.applyWeight = false;
    #else
    
            distParam.applyWeight = false;
    
            if (PU::isLMCMode(mode))
            {
              predIntraChromaLM(COMPONENT_Cb, predCb, pu, areaCb, mode);
            }
            else
            {
    
              initPredIntraParams(pu, pu.Cb(), *pu.cs->sps);
              predIntraAng(COMPONENT_Cb, predCb, pu);
    
    #if JVET_P0058_CHROMA_TS_ENCODER_INTRA_SAD_MOD
            sadCb = distParamSad.distFunc(distParamSad) * 2;
            satdCb = distParamSatd.distFunc(distParamSatd);
            sad += std::min(sadCb, satdCb);
    #else
    
            sad += distParam.distFunc(distParam);
    
            CompArea areaCr = pu.Cr();
            PelBuf orgCr = cs.getOrgBuf(areaCr);
            PelBuf predCr = cs.getPredBuf(areaCr);
    
    #if JVET_P0058_CHROMA_TS_ENCODER_INTRA_SAD_MOD
            m_pcRdCost->setDistParam(distParamSad, orgCr, predCr, pu.cs->sps->getBitDepth(CHANNEL_TYPE_CHROMA), COMPONENT_Cr, false);
            m_pcRdCost->setDistParam(distParamSatd, orgCr, predCr, pu.cs->sps->getBitDepth(CHANNEL_TYPE_CHROMA), COMPONENT_Cr, true);
    #else
    
            m_pcRdCost->setDistParam(distParam, orgCr, predCr, pu.cs->sps->getBitDepth(CHANNEL_TYPE_CHROMA), COMPONENT_Cr, useHadamard);
    
    #endif
    #if JVET_P0058_CHROMA_TS_ENCODER_INTRA_SAD_MOD
            distParamSad.applyWeight = false;
            distParamSatd.applyWeight = false;
    #else
    
            distParam.applyWeight = false;
    
            if (PU::isLMCMode(mode))
            {
              predIntraChromaLM(COMPONENT_Cr, predCr, pu, areaCr, mode);
            }
            else
            {
    
              initPredIntraParams(pu, pu.Cr(), *pu.cs->sps);
              predIntraAng(COMPONENT_Cr, predCr, pu);
    
    #if JVET_P0058_CHROMA_TS_ENCODER_INTRA_SAD_MOD
            sadCr = distParamSad.distFunc(distParamSad) * 2;
            satdCr = distParamSatd.distFunc(distParamSatd);
            sad += std::min(sadCr, satdCr);
    #else
    
            sad += distParam.distFunc(distParam);
    
            satdSortedCost[idx] = sad;
          }
          // sort the mode based on the cost from small to large.
          int tempIdx = 0;
          int64_t tempCost = 0;
          for (int i = uiMinMode; i <= uiMaxMode - 1; i++)
          {
            for (int j = i + 1; j <= uiMaxMode - 1; j++)
            {
              if (satdSortedCost[j] < satdSortedCost[i])
              {
                tempIdx = satdModeList[i];
                satdModeList[i] = satdModeList[j];
                satdModeList[j] = tempIdx;
    
                tempCost = satdSortedCost[i];
                satdSortedCost[i] = satdSortedCost[j];
                satdSortedCost[j] = tempCost;
    
              }
            }
          }
          int reducedModeNumber = 2; // reduce the number of chroma modes
          for (int i = 0; i < reducedModeNumber; i++)
          {
            modeIsEnable[satdModeList[uiMaxMode - 1 - i]] = 0; // disable the last reducedModeNumber modes
          }
    
    
          // save the dist
          Distortion baseDist = cs.dist;
    
          for (uint32_t uiMode = uiMinMode; uiMode < uiMaxMode; uiMode++)
          {
            const int chromaIntraMode = chromaCandModes[uiMode];
            if( PU::isLMCMode( chromaIntraMode ) && ! PU::isLMCModeEnabled( pu, chromaIntraMode ) )
            {
              continue;
            }
    
            if (!modeIsEnable[chromaIntraMode] && PU::isLMCModeEnabled(pu, chromaIntraMode)) // when CCLM is disable, then MDLM is disable. not use satd checking
            {
              continue;
            }
    
            cs.setDecomp( pu.Cb(), false );
            cs.dist = baseDist;
            //----- restore context models -----
            m_CABACEstimator->getCtx() = ctxStart;
    
            //----- chroma coding -----
            pu.intraDir[1] = chromaIntraMode;
    
    
            xRecurIntraChromaCodingQT( cs, partitioner, bestCostSoFar, ispType );
            if( lumaUsesISP && cs.dist == MAX_UINT )
            {
              continue;
            }
    
            if (cs.sps->getTransformSkipEnabledFlag())
    
            uint64_t fracBits   = xGetIntraFracBitsQT( cs, partitioner, false, true, -1, ispType );
    
            Distortion uiDist = cs.dist;
            double    dCost   = m_pcRdCost->calcRdCost( fracBits, uiDist - baseDist );
    
            //----- compare -----
            if( dCost < dBestCost )
            {
    
              if( lumaUsesISP && dCost < bestCostSoFar )
              {
                bestCostSoFar = dCost;
              }
    
              for( uint32_t i = getFirstComponentOfChannel( CHANNEL_TYPE_CHROMA ); i < numberValidComponents; i++ )
              {
                const CompArea &area = pu.blocks[i];
    
                saveCS.getRecoBuf     ( area ).copyFrom( cs.getRecoBuf   ( area ) );
    #if KEEP_PRED_AND_RESI_SIGNALS
                saveCS.getPredBuf     ( area ).copyFrom( cs.getPredBuf   ( area ) );
                saveCS.getResiBuf     ( area ).copyFrom( cs.getResiBuf   ( area ) );
    
    Taoran Lu's avatar
    Taoran Lu committed
    #endif
                saveCS.getPredBuf     ( area ).copyFrom( cs.getPredBuf   (area ) );
                cs.picture->getPredBuf( area ).copyFrom( cs.getPredBuf   (area ) );
    
                cs.picture->getRecoBuf( area ).copyFrom( cs.getRecoBuf( area ) );
    
                for( uint32_t j = 0; j < saveCS.tus.size(); j++ )
                {
                  saveCS.tus[j]->copyComponentFrom( *orgTUs[j], area.compID );
                }
              }
    
              dBestCost  = dCost;
              uiBestDist = uiDist;
              uiBestMode = chromaIntraMode;
            }
          }
    
          for( uint32_t i = getFirstComponentOfChannel( CHANNEL_TYPE_CHROMA ); i < numberValidComponents; i++ )
          {
            const CompArea &area = pu.blocks[i];
    
            cs.getRecoBuf         ( area ).copyFrom( saveCS.getRecoBuf( area ) );
    #if KEEP_PRED_AND_RESI_SIGNALS
            cs.getPredBuf         ( area ).copyFrom( saveCS.getPredBuf( area ) );
            cs.getResiBuf         ( area ).copyFrom( saveCS.getResiBuf( area ) );
    #endif
    
    Taoran Lu's avatar
    Taoran Lu committed
            cs.getPredBuf         ( area ).copyFrom( saveCS.getPredBuf( area ) );
            cs.picture->getPredBuf( area ).copyFrom( cs.getPredBuf    ( area ) );
    
    
            cs.picture->getRecoBuf( area ).copyFrom( cs.    getRecoBuf( area ) );
    
            for( uint32_t j = 0; j < saveCS.tus.size(); j++ )
            {
              orgTUs[ j ]->copyComponentFrom( *saveCS.tus[ j ], area.compID );
            }
          }
        }
    
        pu.intraDir[1] = uiBestMode;
        cs.dist        = uiBestDist;
      }
    
      //----- restore context models -----
      m_CABACEstimator->getCtx() = ctxStart;
    
      if( lumaUsesISP && bestCostSoFar >= maxCostAllowed )
      {
        cu.ispMode = 0;
      }
    
    void IntraSearch::saveCuAreaCostInSCIPU( Area area, double cost )
    {
      if( m_numCuInSCIPU < NUM_INTER_CU_INFO_SAVE )
      {
        m_cuAreaInSCIPU[m_numCuInSCIPU] = area;
        m_cuCostInSCIPU[m_numCuInSCIPU] = cost;
        m_numCuInSCIPU++;
      }
    }
    
    void IntraSearch::initCuAreaCostInSCIPU()
    {
      for( int i = 0; i < NUM_INTER_CU_INFO_SAVE; i++ )
      {
        m_cuAreaInSCIPU[i] = Area();
        m_cuCostInSCIPU[i] = 0;
      }
      m_numCuInSCIPU = 0;
    }
    
    void IntraSearch::PLTSearch(CodingStructure &cs, Partitioner& partitioner, ComponentID compBegin, uint32_t numComp)
    
      CodingUnit    &cu = *cs.getCU(partitioner.chType);
    
      TransformUnit &tu = *cs.getTU(partitioner.chType);
    
      uint32_t height = cu.block(compBegin).height;
      uint32_t width = cu.block(compBegin).width;
    
      m_orgCtxRD = PLTCtx(m_CABACEstimator->getCtx());
    
      if (m_pcEncCfg->getReshaper() && (cs.slice->getLmcsEnabledFlag() && m_pcReshape->getCTUFlag()))
      {
        cs.getPredBuf().copyFrom(cs.getOrgBuf());
        cs.getPredBuf().Y().rspSignal(m_pcReshape->getFwdLUT());
      }
    
    
      Pel  *runLength = tu.getRunLens (compBegin);
    
      bool *runType   = tu.getRunTypes(compBegin);
    
      cu.lastPLTSize[compBegin] = cs.prevPLT.curPLTSize[compBegin];
      //derive palette
      derivePLTLossy(cs, partitioner, compBegin, numComp);
      reorderPLT(cs, partitioner, compBegin, numComp);
    
      //calculate palette index
      preCalcPLTIndex(cs, partitioner, compBegin, numComp);
      //derive run
    
      uint64_t bits = MAX_UINT64;
    
      deriveRunAndCalcBits(cs, partitioner, compBegin, numComp, PLT_SCAN_HORTRAV, bits);
    
      if ((cu.curPLTSize[compBegin] + cu.useEscape[compBegin]) > 1)
      {
    
        deriveRunAndCalcBits(cs, partitioner, compBegin, numComp, PLT_SCAN_VERTRAV, bits);
    
    Yung-Hsuan Chao (Jessie)'s avatar
    Yung-Hsuan Chao (Jessie) committed
      cu.useRotation[compBegin] = m_bestScanRotationMode;
    
      memcpy(runType, m_runTypeRD, sizeof(bool)*width*height);
    
      memcpy(runLength, m_runLengthRD, sizeof(Pel)*width*height);
    
      //reconstruct pixel
      PelBuf    curPLTIdx = tu.getcurPLTIdx(compBegin);
    
      for (uint32_t y = 0; y < height; y++)
    
        for (uint32_t x = 0; x < width; x++)
    
          if (curPLTIdx.at(x, y) == cu.curPLTSize[compBegin])
    
          }
          else
          {
            for (uint32_t compID = compBegin; compID < (compBegin + numComp); compID++)
            {
    
              CompArea area = cu.blocks[compID];
              PelBuf   recBuf = cs.getRecoBuf(area);
    
              uint32_t scaleX = getComponentScaleX((ComponentID)COMPONENT_Cb, cs.sps->getChromaFormatIdc());
              uint32_t scaleY = getComponentScaleY((ComponentID)COMPONENT_Cb, cs.sps->getChromaFormatIdc());
              if (compBegin != COMPONENT_Y || compID == COMPONENT_Y)
              {
    
                recBuf.at(x, y) = cu.curPLT[compID][curPLTIdx.at(x, y)];
    
              else if (compBegin == COMPONENT_Y && compID != COMPONENT_Y && y % (1 << scaleY) == 0 && x % (1 << scaleX) == 0)
    
                recBuf.at(x >> scaleX, y >> scaleY) = cu.curPLT[compID][curPLTIdx.at(x, y)];
    
              }
            }
          }
        }
      }
    
      cs.getPredBuf().fill(0);
      cs.getResiBuf().fill(0);
      cs.getOrgResiBuf().fill(0);
    
      cs.fracBits = MAX_UINT;
      cs.cost = MAX_DOUBLE;
      Distortion distortion = 0;
      for (uint32_t comp = compBegin; comp < (compBegin + numComp); comp++)
      {
        const ComponentID compID = ComponentID(comp);
        CPelBuf reco = cs.getRecoBuf(compID);
        CPelBuf org = cs.getOrgBuf(compID);
    
        if (m_pcEncCfg->getLumaLevelToDeltaQPMapping().isEnabled() || (
          m_pcEncCfg->getReshaper() && (cs.slice->getLmcsEnabledFlag() && m_pcReshape->getCTUFlag())))
        {
          const CPelBuf orgLuma = cs.getOrgBuf(cs.area.blocks[COMPONENT_Y]);
    
          if (compID == COMPONENT_Y && !(m_pcEncCfg->getLumaLevelToDeltaQPMapping().isEnabled()))
          {
            const CompArea &areaY = cu.Y();
    
            CompArea tmpArea1(COMPONENT_Y, areaY.chromaFormat, Position(0, 0), areaY.size());
            PelBuf   tmpRecLuma = m_tmpStorageLCU.getBuf(tmpArea1);
    
            tmpRecLuma.copyFrom(reco);
            tmpRecLuma.rspSignal(m_pcReshape->getInvLUT());
            distortion += m_pcRdCost->getDistPart(org, tmpRecLuma, cs.sps->getBitDepth(toChannelType(compID)), compID, DF_SSE_WTD, &orgLuma);
          }
          else
          {
            distortion += m_pcRdCost->getDistPart(org, reco, cs.sps->getBitDepth(toChannelType(compID)), compID, DF_SSE_WTD, &orgLuma);
          }
        }
        else
    
          distortion += m_pcRdCost->getDistPart(org, reco, cs.sps->getBitDepth(toChannelType(compID)), compID, DF_SSE);
      }
    
      cs.dist += distortion;
      const CompArea &area = cu.blocks[compBegin];
      cs.setDecomp(area);
      cs.picture->getRecoBuf(area).copyFrom(cs.getRecoBuf(area));
    
    void IntraSearch::deriveRunAndCalcBits(CodingStructure& cs, Partitioner& partitioner, ComponentID compBegin, uint32_t numComp, PLTScanMode pltScanMode, uint64_t& minBits)
    
      CodingUnit    &cu = *cs.getCU(partitioner.chType);
    
      TransformUnit &tu = *cs.getTU(partitioner.chType);
    
      uint32_t height = cu.block(compBegin).height;
      uint32_t width = cu.block(compBegin).width;
      Pel  *runLength = tu.getRunLens (compBegin);
    
      bool *runType   = tu.getRunTypes(compBegin);
    
      cu.useRotation[compBegin] = (pltScanMode == PLT_SCAN_VERTRAV);
    
    Yung-Hsuan Chao (Jessie)'s avatar
    Yung-Hsuan Chao (Jessie) committed
      m_scanOrder = g_scanOrder[SCAN_UNGROUPED][(cu.useRotation[compBegin]) ? SCAN_TRAV_VER : SCAN_TRAV_HOR][gp_sizeIdxInfo->idxFrom(width)][gp_sizeIdxInfo->idxFrom(height)];
    
      deriveRun(cs, partitioner, compBegin);
    
      m_CABACEstimator->getCtx() = PLTCtx(m_orgCtxRD);
      m_CABACEstimator->resetBits();
      CUCtx cuCtx;
      cuCtx.isDQPCoded = true;
      cuCtx.isChromaQpAdjCoded = true;
      m_CABACEstimator->cu_palette_info(cu, compBegin, numComp, cuCtx);
    
      uint64_t bitsTemp = m_CABACEstimator->getEstFracBits();
      if (minBits > bitsTemp)
    
    Yung-Hsuan Chao (Jessie)'s avatar
    Yung-Hsuan Chao (Jessie) committed
        m_bestScanRotationMode = pltScanMode;
    
        memcpy(m_runTypeRD, runType, sizeof(bool)*width*height);
        memcpy(m_runLengthRD, runLength, sizeof(Pel)*width*height);
        minBits = bitsTemp;
    
    void IntraSearch::deriveRun(CodingStructure& cs, Partitioner& partitioner, ComponentID compBegin)
    
      CodingUnit    &cu = *cs.getCU(partitioner.chType);
    
      TransformUnit &tu = *cs.getTU(partitioner.chType);
    
      uint32_t height = cu.block(compBegin).height;
      uint32_t width = cu.block(compBegin).width;
      uint32_t total = height * width, idx = 0;
      uint32_t startPos = 0;
    
      uint64_t indexBits = 0, runBitsIndex = 0, runBitsCopy = 0;
    
    Yung-Hsuan Chao (Jessie)'s avatar
    Yung-Hsuan Chao (Jessie) committed
      m_storeCtxRun = PLTCtx(m_orgCtxRD);
    
    
      PLTtypeBuf  runType = tu.getrunType(compBegin);
      PelBuf      runLength = tu.getrunLength(compBegin);
    
      while (idx < total)
    
        startPos = idx;
        double aveBitsPerPix[NUM_PLT_RUN];
        uint32_t indexRun = 0;
        bool runValid = calIndexRun(cs, partitioner, startPos, total, indexRun, compBegin);
    
    Yung-Hsuan Chao (Jessie)'s avatar
    Yung-Hsuan Chao (Jessie) committed
        m_CABACEstimator->getCtx() = PLTCtx(m_storeCtxRun);
    
        aveBitsPerPix[PLT_RUN_INDEX] = runValid ? getRunBits(cu, indexRun, startPos, PLT_RUN_INDEX, &indexBits, &runBitsIndex, compBegin) : MAX_DOUBLE;
    
    Yung-Hsuan Chao (Jessie)'s avatar
    Yung-Hsuan Chao (Jessie) committed
        m_storeCtxRunIndex = PLTCtx(m_CABACEstimator->getCtx());
    
        uint32_t copyRun = 0;
        bool copyValid = calCopyRun(cs, partitioner, startPos, total, copyRun, compBegin);
    
    Yung-Hsuan Chao (Jessie)'s avatar
    Yung-Hsuan Chao (Jessie) committed
        m_CABACEstimator->getCtx() = PLTCtx(m_storeCtxRun);
    
        aveBitsPerPix[PLT_RUN_COPY] = copyValid ? getRunBits(cu, copyRun, startPos, PLT_RUN_COPY, &indexBits, &runBitsCopy, compBegin) : MAX_DOUBLE;
    
    Yung-Hsuan Chao (Jessie)'s avatar
    Yung-Hsuan Chao (Jessie) committed
        m_storeCtxRunCopy = PLTCtx(m_CABACEstimator->getCtx());
    
        if (copyValid == 0 && runValid == 0)
    
          if (aveBitsPerPix[PLT_RUN_COPY] <= aveBitsPerPix[PLT_RUN_INDEX])
    
            for (int runidx = 0; runidx <copyRun; runidx++)
    
    Yung-Hsuan Chao (Jessie)'s avatar
    Yung-Hsuan Chao (Jessie) committed
              uint32_t posy = m_scanOrder[idx + runidx].y;
              uint32_t posx = m_scanOrder[idx + runidx].x;
    
              runType.at(posx, posy) = PLT_RUN_COPY;
    
              runLength.at(posx, posy) = copyRun;
    
    Yung-Hsuan Chao (Jessie)'s avatar
    Yung-Hsuan Chao (Jessie) committed
            m_storeCtxRun = PLTCtx(m_storeCtxRunCopy);
    
            for (int runidx = 0; runidx <indexRun; runidx++)
    
    Yung-Hsuan Chao (Jessie)'s avatar
    Yung-Hsuan Chao (Jessie) committed
              uint32_t posy = m_scanOrder[idx + runidx].y;
              uint32_t posx = m_scanOrder[idx + runidx].x;
    
              runType.at(posx, posy) = PLT_RUN_INDEX;
    
              runLength.at(posx, posy) = indexRun;
    
    Yung-Hsuan Chao (Jessie)'s avatar
    Yung-Hsuan Chao (Jessie) committed
            m_storeCtxRun = PLTCtx(m_storeCtxRunIndex);
    
      assert(idx == total);
    
    double IntraSearch::getRunBits(const CodingUnit&  cu, uint32_t run, uint32_t strPos, PLTRunMode paletteRunMode, uint64_t* indexBits, uint64_t* runBits, ComponentID compBegin)
    
      TransformUnit&   tu = *cu.firstTU;
    
      uint32_t height = cu.block(compBegin).height;
      uint32_t width  = cu.block(compBegin).width;
      uint32_t endPos = height*width;
      PLTtypeBuf runType   = tu.getrunType(compBegin);
      PelBuf     curPLTIdx = tu.getcurPLTIdx(compBegin);
      uint32_t   indexMaxSize = (cu.useEscape[compBegin]) ? (cu.curPLTSize[compBegin] + 1) : cu.curPLTSize[compBegin];
    
    
      m_CABACEstimator->resetBits();
      ///////////////// encode Run Type
    
    Yung-Hsuan Chao (Jessie)'s avatar
    Yung-Hsuan Chao (Jessie) committed
      m_CABACEstimator->encodeRunType(cu, runType, strPos, m_scanOrder, compBegin);
    
      uint64_t runTypeBits = m_CABACEstimator->getEstFracBits();
    
      uint32_t curLevel = 0;
      switch (paletteRunMode)
      {
      case PLT_RUN_INDEX:
    
        curLevel = m_CABACEstimator->writePLTIndex(cu, strPos, curPLTIdx, runType, indexMaxSize, compBegin);
        *indexBits = m_CABACEstimator->getEstFracBits() - runTypeBits;
    
        m_CABACEstimator->cu_run_val(run - 1, PLT_RUN_INDEX, curLevel, endPos - strPos - 1);
    
        *runBits = m_CABACEstimator->getEstFracBits() - runTypeBits - (*indexBits);
    
        break;
      case PLT_RUN_COPY:
        m_CABACEstimator->cu_run_val(run - 1, PLT_RUN_COPY, curLevel, endPos - strPos - 1);
    
        *runBits = m_CABACEstimator->getEstFracBits() - runTypeBits;
    
      double costPerPixel = (double)m_CABACEstimator->getEstFracBits() / (double)run;
      return costPerPixel;
    
    void IntraSearch::preCalcPLTIndex(CodingStructure& cs, Partitioner& partitioner, ComponentID compBegin, uint32_t numComp)
    
      CodingUnit &cu = *cs.getCU(partitioner.chType);
      TransformUnit &tu = *cs.getTU(partitioner.chType);
      const int  channelBitDepth_L = cs.sps->getBitDepth(CHANNEL_TYPE_LUMA);
      const int  channelBitDepth_C = cs.sps->getBitDepth(CHANNEL_TYPE_CHROMA);
      const int  pcmShiftRight_L = (channelBitDepth_L - PLT_ENCBITDEPTH);
      const int  pcmShiftRight_C = (channelBitDepth_C - PLT_ENCBITDEPTH);
    
    
      uint32_t height = cu.block(compBegin).height;
      uint32_t width = cu.block(compBegin).width;
    
    
      CPelBuf   orgBuf[3];
      for (int comp = compBegin; comp < (compBegin + numComp); comp++)
      {
        CompArea  area = cu.blocks[comp];
        if (m_pcEncCfg->getReshaper() && (cs.slice->getLmcsEnabledFlag() && m_pcReshape->getCTUFlag()))
        {
          orgBuf[comp] = cs.getPredBuf(area);
        }
        else
        {
          orgBuf[comp] = cs.getOrgBuf(area);
        }
      }
    
      PelBuf   curPLTIdx = tu.getcurPLTIdx(compBegin);
    
    Yung-Hsuan Chao (Jessie)'s avatar
    Yung-Hsuan Chao (Jessie) committed
      int      errorLimit = numComp * g_paletteQuant[cu.qp];
    
      uint32_t bestIdx = 0;
    
      uint32_t scaleX = getComponentScaleX(COMPONENT_Cb, cs.sps->getChromaFormatIdc());
      uint32_t scaleY = getComponentScaleY(COMPONENT_Cb, cs.sps->getChromaFormatIdc());
    
      for (uint32_t y = 0; y < height; y++)
    
        for (uint32_t x = 0; x < width; x++)
    
          uint32_t pltIdx = 0;
          uint32_t minError = MAX_UINT;
          while (pltIdx < cu.curPLTSize[compBegin])
    
            uint32_t absError = 0, pX, pY;
    
            for (int comp = compBegin; comp < (compBegin + numComp); comp++)
            {
    
              pX = (comp > 0 && compBegin == COMPONENT_Y) ? (x >> scaleX) : x;
              pY = (comp > 0 && compBegin == COMPONENT_Y) ? (y >> scaleY) : y;
    
              int shift = (comp > 0) ? pcmShiftRight_C : pcmShiftRight_L;
    
              absError += abs(cu.curPLT[comp][pltIdx] - orgBuf[comp].at(pX, pY)) >> shift;
    
            if (absError < minError)
    
              bestIdx = pltIdx;
              minError = absError;
              if (minError == 0)
    
          curPLTIdx.at(x, y) = bestIdx;
          if (minError > errorLimit)
    
            curPLTIdx.at(x, y) = cu.curPLTSize[compBegin];
    
            cu.useEscape[compBegin] = true;
    
            calcPixelPred(cs, partitioner, y, x, compBegin, numComp);
    
    void IntraSearch::calcPixelPred(CodingStructure& cs, Partitioner& partitioner, uint32_t yPos, uint32_t xPos, ComponentID compBegin, uint32_t numComp)
    
      CodingUnit    &cu = *cs.getCU(partitioner.chType);
    
      TransformUnit &tu = *cs.getTU(partitioner.chType);
    
      CPelBuf   orgBuf[3];
      for (int comp = compBegin; comp < (compBegin + numComp); comp++)
      {
        CompArea  area = cu.blocks[comp];
        if (m_pcEncCfg->getReshaper() && (cs.slice->getLmcsEnabledFlag() && m_pcReshape->getCTUFlag()))
        {
          orgBuf[comp] = cs.getPredBuf(area);
        }
        else
        {
          orgBuf[comp] = cs.getOrgBuf(area);
        }
      }
    
    
      int qp[3];
      int qpRem[3];
      int qpPer[3];
    
      int quantiserScale[3];
      int quantiserRightShift[3];
      int rightShiftOffset[3];
      int InvquantiserRightShift[3];
    
      for (uint32_t ch = compBegin; ch < (compBegin + numComp); ch++)
      {
        QpParam cQP(tu, ComponentID(ch));
    
    #if JVET_P0460_PLT_TS_MIN_QP
        qp[ch] = cQP.Qp(true);
    #else
    
        qp[ch] = cQP.Qp(false);
    
        qpRem[ch] = qp[ch] % 6;
        qpPer[ch] = qp[ch] / 6;
        quantiserScale[ch] = g_quantScales[0][qpRem[ch]];
        quantiserRightShift[ch] = QUANT_SHIFT + qpPer[ch];
    
        rightShiftOffset[ch] = 1 << (quantiserRightShift[ch] - 1);
        InvquantiserRightShift[ch] = IQUANT_SHIFT;
    
        add[ch] = 1 << (InvquantiserRightShift[ch] - 1);
    
      }
    
      uint32_t scaleX = getComponentScaleX(COMPONENT_Cb, cs.sps->getChromaFormatIdc());
      uint32_t scaleY = getComponentScaleY(COMPONENT_Cb, cs.sps->getChromaFormatIdc());
      for (uint32_t ch = compBegin; ch < (compBegin + numComp); ch++)
      {
    
        const int channelBitDepth = cu.cs->sps->getBitDepth(toChannelType((ComponentID)ch));
    
        CompArea  area = cu.blocks[ch];
        PelBuf    recBuf = cs.getRecoBuf(area);
    
        PLTescapeBuf escapeValue = tu.getescapeValue((ComponentID)ch);
    
        if (compBegin != COMPONENT_Y || ch == 0)
        {
    
          escapeValue.at(xPos, yPos) = TCoeff(std::max<int>(0, ((orgBuf[ch].at(xPos, yPos) * quantiserScale[ch] + rightShiftOffset[ch]) >> quantiserRightShift[ch])));
          assert(escapeValue.at(xPos, yPos) < (1 << (channelBitDepth + 1)));
          recBuf.at(xPos, yPos) = (((escapeValue.at(xPos, yPos)*g_invQuantScales[0][qpRem[ch]]) << qpPer[ch]) + add[ch]) >> InvquantiserRightShift[ch];
          recBuf.at(xPos, yPos) = Pel(ClipBD<int>(recBuf.at(xPos, yPos), channelBitDepth));//to be checked
    
        else if (compBegin == COMPONENT_Y && ch > 0 && yPos % (1 << scaleY) == 0 && xPos % (1 << scaleX) == 0)
    
          uint32_t yPosC = yPos >> scaleY;
          uint32_t xPosC = xPos >> scaleX;
          escapeValue.at(xPosC, yPosC) = TCoeff(std::max<int>(0, ((orgBuf[ch].at(xPosC, yPosC) * quantiserScale[ch] + rightShiftOffset[ch]) >> quantiserRightShift[ch])));
          assert(escapeValue.at(xPosC, yPosC) < (1 << (channelBitDepth + 1)));
          recBuf.at(xPosC, yPosC) = (((escapeValue.at(xPosC, yPosC)*g_invQuantScales[0][qpRem[ch]]) << qpPer[ch]) + add[ch]) >> InvquantiserRightShift[ch];
          recBuf.at(xPosC, yPosC) = Pel(ClipBD<int>(recBuf.at(xPosC, yPosC), channelBitDepth));//to be checked
    
    void IntraSearch::derivePLTLossy(CodingStructure& cs, Partitioner& partitioner, ComponentID compBegin, uint32_t numComp)
    
      CodingUnit &cu = *cs.getCU(partitioner.chType);
      const int channelBitDepth_L = cs.sps->getBitDepth(CHANNEL_TYPE_LUMA);
      const int channelBitDepth_C = cs.sps->getBitDepth(CHANNEL_TYPE_CHROMA);
      const int pcmShiftRight_L = (channelBitDepth_L - PLT_ENCBITDEPTH);
      const int pcmShiftRight_C = (channelBitDepth_C - PLT_ENCBITDEPTH);
    
    
      uint32_t height = cu.block(compBegin).height;
      uint32_t width = cu.block(compBegin).width;
    
    
      CPelBuf   orgBuf[3];
      for (int comp = compBegin; comp < (compBegin + numComp); comp++)
      {
        CompArea  area = cu.blocks[comp];
        if (m_pcEncCfg->getReshaper() && (cs.slice->getLmcsEnabledFlag() && m_pcReshape->getCTUFlag()))
        {
          orgBuf[comp] = cs.getPredBuf(area);
        }
        else
        {
          orgBuf[comp] = cs.getOrgBuf(area);
        }
      }
    
    
    Yung-Hsuan Chao (Jessie)'s avatar
    Yung-Hsuan Chao (Jessie) committed
      int errorLimit = g_paletteQuant[cu.qp];
    
      uint32_t totalSize = height*width;
      SortingElement *pelList = new SortingElement[totalSize];
      SortingElement  element;
      SortingElement *pelListSort = new SortingElement[MAXPLTSIZE + 1];
    
      uint32_t dictMaxSize = MAXPLTSIZE;
    
      int last = -1;
    
      uint32_t scaleX = getComponentScaleX(COMPONENT_Cb, cs.sps->getChromaFormatIdc());
      uint32_t scaleY = getComponentScaleY(COMPONENT_Cb, cs.sps->getChromaFormatIdc());
    
      for (uint32_t y = 0; y < height; y++)
    
        for (uint32_t x = 0; x < width; x++)
    
          uint32_t org[3], pX, pY;
    
          for (int comp = compBegin; comp < (compBegin + numComp); comp++)
          {
    
            pX = (comp > 0 && compBegin == COMPONENT_Y) ? (x >> scaleX) : x;
            pY = (comp > 0 && compBegin == COMPONENT_Y) ? (y >> scaleY) : y;
            org[comp] = orgBuf[comp].at(pX, pY);
    
          element.setAll(org, compBegin, numComp);
          int besti = last, bestSAD = (last == -1) ? MAX_UINT : pelList[last].getSAD(element, cs.sps->getBitDepths(), compBegin, numComp);
    
            for (int i = idx - 1; i >= 0; i--)
    
              uint32_t sad = pelList[i].getSAD(element, cs.sps->getBitDepths(), compBegin, numComp);
    
              if (sad < bestSAD)
              {
                bestSAD = sad;
                besti = i;
                if (!sad) break;
              }
            }
          }
    
          if (besti >= 0 && pelList[besti].almostEqualData(element, errorLimit, cs.sps->getBitDepths(), compBegin, numComp))
    
            pelList[besti].addElement(element, compBegin, numComp);
    
            pelList[idx].copyDataFrom(element, compBegin, numComp);
    
      for (int i = 0; i < dictMaxSize; i++)
    
        pelListSort[i].resetAll(compBegin, numComp);
    
      dictMaxSize = 1;
      for (int i = 0; i < idx; i++)
    
        if (pelList[i].getCnt() > pelListSort[dictMaxSize - 1].getCnt())
    
          for (j = dictMaxSize; j > 0; j--)
    
            if (pelList[i].getCnt() > pelListSort[j - 1].getCnt() )
    
              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;
      }
    
      double bitCost = m_pcRdCost->getLambda()*numColorBits;
      for (int i = 0; i < MAXPLTSIZE; i++)
      {
    
          for (int comp = compBegin; comp < (compBegin + numComp); comp++)
          {
    
    Yung-Hsuan Chao (Jessie)'s avatar
    Yung-Hsuan Chao (Jessie) committed
            cu.curPLT[comp][paletteSize] = (pelListSort[i].getSumData(comp) + half) / pelListSort[i].getCnt();
    
          {
            double pal[MAX_NUM_COMPONENT], err = 0.0, bestCost = 0.0;
            for (int comp = compBegin; comp < (compBegin + numComp); comp++)
            {
              const int shift = (comp > 0) ? pcmShiftRight_C : pcmShiftRight_L;
    
    Yung-Hsuan Chao (Jessie)'s avatar
    Yung-Hsuan Chao (Jessie) committed
              pal[comp] = pelListSort[i].getSumData(comp) / (double)pelListSort[i].getCnt();
    
              err = pal[comp] - cu.curPLT[comp][paletteSize];
    
              bestCost += (err*err) / (1 << (2 * shift));
            }
    
            bestCost = bestCost * pelListSort[i].getCnt() + bitCost;
    
    
            for (int t = 0; t < cs.prevPLT.curPLTSize[compBegin]; t++)
            {
              double cost = 0.0;
              for (int comp = compBegin; comp < (compBegin + numComp); comp++)
              {
                const int shift = (comp > 0) ? pcmShiftRight_C : pcmShiftRight_L;
                err = pal[comp] - cs.prevPLT.curPLT[comp][t];
                cost += (err*err) / (1 << (2 * shift));
              }
    
              if (cost < bestCost)
              {
                best = t;
                bestCost = cost;
              }
            }
            if (best != -1)
            {
              for (int comp = compBegin; comp < (compBegin + numComp); comp++)
              {
    
                cu.curPLT[comp][paletteSize] = cs.prevPLT.curPLT[comp][best];
    
          bool duplicate = false;
    
            for (int t = 0; t<paletteSize; t++)
    
              bool duplicateTmp = true;
    
              for (int comp = compBegin; comp < (compBegin + numComp); comp++)
              {
    
                duplicateTmp = duplicateTmp && (cu.curPLT[comp][paletteSize] == cu.curPLT[comp][t]);
    
          if (!duplicate) paletteSize++;
    
      cu.curPLTSize[compBegin] = paletteSize;
    
      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()
          )
    
          {
            if( cs.pps->getTransquantBypassEnabledFlag() )
            {
              m_CABACEstimator->cu_transquant_bypass_flag( cu );