Skip to content
Snippets Groups Projects
IntraSearch.cpp 166 KiB
Newer Older
  • Learn to ignore specific revisions
  •   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_O0919_TS_MIN_QP
        qp[ch] = cQP.Qp(false);
    #else
    
        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()
          )
    
    Yu Han's avatar
    Yu Han committed
          if ((!cs.slice->isIntra() || cs.slice->getSPS()->getIBCFlag())
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
            && cu.Y().valid()
    
          {
            if( cs.pps->getTransquantBypassEnabledFlag() )
            {
              m_CABACEstimator->cu_transquant_bypass_flag( cu );
            }
            m_CABACEstimator->cu_skip_flag( cu );
            m_CABACEstimator->pred_mode   ( cu );
          }
    
          m_CABACEstimator->bdpcm_mode  ( cu, ComponentID(partitioner.chType) );
    
    #if !JVET_O0525_REMOVE_PCM
    
    Karsten Suehring's avatar
    Karsten Suehring committed
          if( CU::isIntra(cu) )
    
            m_CABACEstimator->pcm_data( cu, partitioner );
    
        }
    
        PredictionUnit &pu = *cs.getPU(partitioner.currArea().lumaPos(), partitioner.chType);
    
        // luma prediction mode
    
    Karsten Suehring's avatar
    Karsten Suehring committed
        if (isFirst)
    
    Karsten Suehring's avatar
    Karsten Suehring committed
          if ( !cu.Y().valid())
            m_CABACEstimator->pred_mode( cu );
          m_CABACEstimator->intra_luma_pred_mode( pu );
    
        }
      }
    
      if (bChroma)
      {
        bool isFirst = partitioner.currArea().Cb().valid() && partitioner.currArea().chromaPos() == cs.area.chromaPos();
    
        PredictionUnit &pu = *cs.getPU( partitioner.currArea().chromaPos(), CHANNEL_TYPE_CHROMA );
    
    
    Karsten Suehring's avatar
    Karsten Suehring committed
        if( isFirst )
    
    Karsten Suehring's avatar
    Karsten Suehring committed
          m_CABACEstimator->intra_chroma_pred_mode( pu );
    
    void IntraSearch::xEncSubdivCbfQT( CodingStructure &cs, Partitioner &partitioner, const bool &bLuma, const bool &bChroma, const int subTuIdx, const PartSplit ispType )
    {
      const UnitArea &currArea = partitioner.currArea();
              int subTuCounter = subTuIdx;
      TransformUnit &currTU = *cs.getTU( currArea.blocks[partitioner.chType], partitioner.chType, subTuCounter );
      CodingUnit    &currCU = *currTU.cu;
    
      uint32_t currDepth           = partitioner.currTrDepth;
    
      const bool subdiv        = currTU.depth > currDepth;
    
      ComponentID compID = partitioner.chType == CHANNEL_TYPE_LUMA ? COMPONENT_Y : COMPONENT_Cb;
      const bool chromaCbfISP = currArea.blocks[COMPONENT_Cb].valid() && currCU.ispMode && !subdiv;
    
    Karsten Suehring's avatar
    Karsten Suehring committed
      if( partitioner.canSplit( TU_MAX_TR_SPLIT, cs ) )
    
    Karsten Suehring's avatar
    Karsten Suehring committed
        CHECK( !subdiv, "TU split implied" );
      }
      else
      {
    
        CHECK( subdiv && !currCU.ispMode && isLuma( compID ), "No TU subdivision is allowed with QTBT" );
      }
    
      if( bChroma && ( !currCU.ispMode || chromaCbfISP ) )
    
      {
        const uint32_t numberValidComponents = getNumberValidComponents(currArea.chromaFormat);
    
        const uint32_t cbfDepth = ( chromaCbfISP ? currDepth - 1 : currDepth );
    
    
        for (uint32_t ch = COMPONENT_Cb; ch < numberValidComponents; ch++)
        {
          const ComponentID compID = ComponentID(ch);
    
    
          if( currDepth == 0 || TU::getCbfAtDepth( currTU, compID, currDepth - 1 ) || chromaCbfISP )
    
          {
            const bool prevCbf = ( compID == COMPONENT_Cr ? TU::getCbfAtDepth( currTU, COMPONENT_Cb, currDepth ) : false );
    
            m_CABACEstimator->cbf_comp( cs, TU::getCbfAtDepth( currTU, compID, currDepth ), currArea.blocks[compID], cbfDepth, prevCbf );
    
    
          }
        }
      }
    
      if (subdiv)
      {
    
        if( partitioner.canSplit( TU_MAX_TR_SPLIT, cs ) )
        {
          partitioner.splitCurrArea( TU_MAX_TR_SPLIT, cs );
        }
    
        else if( currCU.ispMode && isLuma( compID ) )
        {
          partitioner.splitCurrArea( ispType, cs );
        }
    
          xEncSubdivCbfQT( cs, partitioner, bLuma, bChroma, subTuCounter, ispType );
          subTuCounter += subTuCounter != -1 ? 1 : 0;
    
        } while( partitioner.nextPart( cs ) );
    
        partitioner.exitCurrSplit();
      }
      else
      {
        //===== Cbfs =====
        if (bLuma)
        {
    
          bool previousCbf       = false;
          bool lastCbfIsInferred = false;
          if( ispType != TU_NO_ISP )
          {
            bool rootCbfSoFar = false;
    
            uint32_t nTus = currCU.ispMode == HOR_INTRA_SUBPARTITIONS ? currCU.lheight() >> 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 )
    
    {
      const UnitArea &currArea  = partitioner.currArea();
    
    
           int subTuCounter     = subTuIdx;
      TransformUnit &currTU     = *cs.getTU( currArea.blocks[partitioner.chType], partitioner.chType, subTuIdx );
    
      uint32_t      currDepth       = partitioner.currTrDepth;
      const bool subdiv         = currTU.depth > currDepth;
    
      if (subdiv)
      {
        if (partitioner.canSplit(TU_MAX_TR_SPLIT, cs))
        {
          partitioner.splitCurrArea(TU_MAX_TR_SPLIT, cs);
        }
    
        else if( currTU.cu->ispMode )
        {
          partitioner.splitCurrArea( ispType, cs );
        }
    
          xEncCoeffQT( cs, partitioner, compID, subTuCounter, ispType );
          subTuCounter += subTuCounter != -1 ? 1 : 0;
    
        } while( partitioner.nextPart( cs ) );
    
        partitioner.exitCurrSplit();
      }
      else
    
      if( currArea.blocks[compID].valid() )
      {
    
        if( 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 );
        }
    #endif
    
        if( TU::hasCrossCompPredInfo( currTU, compID ) )
        {
          m_CABACEstimator->cross_comp_pred( currTU, compID );
        }
        if( TU::getCbf( currTU, compID ) )
        {
          m_CABACEstimator->residual_coding( currTU, compID );
        }
      }
    }
    
    
    uint64_t IntraSearch::xGetIntraFracBitsQT( CodingStructure &cs, Partitioner &partitioner, const bool &bLuma, const bool &bChroma, const int subTuIdx, const PartSplit ispType )
    
      xEncIntraHeader( cs, partitioner, bLuma, bChroma, subTuIdx );
      xEncSubdivCbfQT( cs, partitioner, bLuma, bChroma, subTuIdx, ispType );
    
    
        xEncCoeffQT( cs, partitioner, COMPONENT_Y, subTuIdx, ispType );
    
        xEncCoeffQT( cs, partitioner, COMPONENT_Cb, subTuIdx, ispType );
        xEncCoeffQT( cs, partitioner, COMPONENT_Cr, subTuIdx, ispType );
      }
    
      uint64_t fracBits = m_CABACEstimator->getEstFracBits();
      return fracBits;
    }
    
    uint64_t IntraSearch::xGetIntraFracBitsQTSingleChromaComponent( CodingStructure &cs, Partitioner &partitioner, const ComponentID compID )
    {
      m_CABACEstimator->resetBits();
    
      if( compID == COMPONENT_Cb )
      {
    
        //intra mode coding
    
        PredictionUnit &pu = *cs.getPU( partitioner.currArea().lumaPos(), partitioner.chType );
        m_CABACEstimator->intra_chroma_pred_mode( pu );
        //xEncIntraHeader(cs, partitioner, false, true);
      }
      CHECK( partitioner.currTrDepth != 1, "error in the depth!" );
      const UnitArea &currArea = partitioner.currArea();
    
      TransformUnit &currTU = *cs.getTU( currArea.blocks[partitioner.chType], partitioner.chType );
    
      //cbf coding
    
      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 );
    #else
    
      m_CABACEstimator->cbf_comp( cs, TU::getCbfAtDepth( currTU, compID, partitioner.currTrDepth ), currArea.blocks[compID], partitioner.currTrDepth - 1 );
    
      //coeffs coding and cross comp coding
      if( TU::hasCrossCompPredInfo( currTU, compID ) )
      {
        m_CABACEstimator->cross_comp_pred( currTU, compID );
      }
      if( TU::getCbf( currTU, compID ) )
      {
        m_CABACEstimator->residual_coding( currTU, compID );
    
      }
    
      uint64_t fracBits = m_CABACEstimator->getEstFracBits();
      return fracBits;
    }
    
    uint64_t IntraSearch::xGetIntraFracBitsQTChroma(TransformUnit& currTU, const ComponentID &compID)
    {
      m_CABACEstimator->resetBits();
    
      if( TU::hasCrossCompPredInfo( currTU, compID ) )
      {
        m_CABACEstimator->cross_comp_pred( currTU, compID );
      }
    
    
      // 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 );
        if( cbfMask >> 1 )
          m_CABACEstimator->residual_coding( currTU, COMPONENT_Cb );
        if( cbfMask & 1 )
          m_CABACEstimator->residual_coding( currTU, COMPONENT_Cr );
    #else
    
        if ( TU::getCbf( currTU, COMPONENT_Cb ) )
        {
          m_CABACEstimator->cbf_comp( cs, true, currTU.blocks[ COMPONENT_Cb ], currTU.depth, false );
          m_CABACEstimator->cbf_comp( cs, true, currTU.blocks[ COMPONENT_Cr ], currTU.depth, true );
          m_CABACEstimator->joint_cb_cr( currTU );
        }
        else
        {
          m_CABACEstimator->cbf_comp( cs, false, currTU.blocks[ COMPONENT_Cb ], currTU.depth, false );
          m_CABACEstimator->cbf_comp( cs, false, currTU.blocks[ COMPONENT_Cr ], currTU.depth, false );
        }
    
      }
      else
      {
        if ( compID == COMPONENT_Cb )
          m_CABACEstimator->cbf_comp( cs, TU::getCbf( currTU, compID ), currTU.blocks[ compID ], currTU.depth, false );
        else
    
        {
          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 );
        }
    #else
    
          m_CABACEstimator->cbf_comp( cs, TU::getCbf( currTU, compID ), currTU.blocks[ compID ], currTU.depth, TU::getCbf( currTU, COMPONENT_Cb ) );
    
      if( !currTU.jointCbCr && TU::getCbf( currTU, compID ) )
    #else
    
      {
        m_CABACEstimator->residual_coding( currTU, compID );
      }
    
      uint64_t fracBits = m_CABACEstimator->getEstFracBits();
      return fracBits;
    }
    
    
    Tung Nguyen's avatar
    Tung Nguyen committed
    void IntraSearch::xIntraCodingTUBlock(TransformUnit &tu, const ComponentID &compID, const bool &checkCrossCPrediction, Distortion& ruiDist, const int &default0Save1Load2, uint32_t* numSig, std::vector<TrMode>* trModes, const bool loadTr)
    
    {
      if (!tu.blocks[compID].valid())
      {
        return;
      }
    
      CodingStructure &cs                       = *tu.cs;
    
      m_pcRdCost->setChromaFormat(cs.sps->getChromaFormatIdc());
    
    
      const CompArea      &area                 = tu.blocks[compID];
      const SPS           &sps                  = *cs.sps;
      const PPS           &pps                  = *cs.pps;
    
      const ChannelType    chType               = toChannelType(compID);
      const int            bitDepth             = sps.getBitDepth(chType);
    
      PelBuf         piOrg                      = cs.getOrgBuf    (area);
      PelBuf         piPred                     = cs.getPredBuf   (area);
      PelBuf         piResi                     = cs.getResiBuf   (area);
      PelBuf         piOrgResi                  = cs.getOrgResiBuf(area);
      PelBuf         piReco                     = cs.getRecoBuf   (area);
    
      const PredictionUnit &pu                  = *cs.getPU(area.pos(), chType);
      const uint32_t           uiChFinalMode        = PU::getFinalIntraMode(pu, chType);
    
      const bool           bUseCrossCPrediction = pps.getPpsRangeExtension().getCrossComponentPredictionEnabledFlag() && isChroma( compID ) && PU::isChromaIntraModeCrossCheckMode( pu ) && checkCrossCPrediction;
      const bool           ccUseRecoResi        = m_pcEncCfg->getUseReconBasedCrossCPredictionEstimate();
    
    #if !JVET_O0502_ISP_CLEANUP
    
      const bool           ispSplitIsAllowed    = sps.getUseISP() && CU::canUseISP( *tu.cu, compID );
    
      CHECK( tu.jointCbCr && compID == COMPONENT_Cr, "wrong combination of compID and jointCbCr" );
    #endif
    
      bool jointCbCr = tu.jointCbCr && compID == COMPONENT_Cb;
    
      if ( compID == COMPONENT_Y )
      {
    
      PelBuf sharedPredTS( m_pSharedPredTransformSkip[compID], area );
      if( default0Save1Load2 != 2 )
      {
    
    #if JVET_O0502_ISP_CLEANUP
    #if JVET_O0106_ISP_4xN_PREDREG_FOR_1xN_2xN
        bool predRegDiffFromTB = CU::isPredRegDiffFromTB(*tu.cu, compID);
        bool firstTBInPredReg = CU::isFirstTBInPredReg(*tu.cu, compID, area);
        CompArea areaPredReg(COMPONENT_Y, tu.chromaFormat, area);
    #endif
        if (tu.cu->ispMode && isLuma(compID))
        {
    #if JVET_O0106_ISP_4xN_PREDREG_FOR_1xN_2xN
          if (predRegDiffFromTB)
          {
            if (firstTBInPredReg)
            {
              CU::adjustPredArea(areaPredReg);
              initIntraPatternChTypeISP(*tu.cu, areaPredReg, piReco);
            }
          }
          else
    #endif
            initIntraPatternChTypeISP(*tu.cu, area, piReco);
        }
        else
        {
          initIntraPatternChType(*tu.cu, area);
        }
    #else
    
    #if JVET_O0106_ISP_4xN_PREDREG_FOR_1xN_2xN
        bool predRegDiffFromTB = CU::isPredRegDiffFromTB(*tu.cu, compID);
        bool firstTBInPredReg = CU::isFirstTBInPredReg(*tu.cu, compID, area);
        CompArea areaPredReg(COMPONENT_Y, tu.chromaFormat, area);
        if (predRegDiffFromTB)
        {
          if (firstTBInPredReg)
          {
            CU::adjustPredArea(areaPredReg);
            initIntraPatternChType(*tu.cu, areaPredReg);
          }
        }
        else
    #endif
          initIntraPatternChType(*tu.cu, area);
    
    
        //===== get prediction signal =====
        if( compID != COMPONENT_Y && PU::isLMCMode( uiChFinalMode ) )
        {
          {
            xGetLumaRecPixels( pu, area );
          }
          predIntraChromaLM( compID, piPred, pu, area, uiChFinalMode );
        }
        else
        {
    
          if( PU::isMIP( pu, chType ) )
          {
            predIntraMip( compID, piPred, pu );
          }
          else
          {
    
    #if JVET_O0106_ISP_4xN_PREDREG_FOR_1xN_2xN
            if (predRegDiffFromTB)
            {
              if (firstTBInPredReg)
              {
                PelBuf piPredReg = cs.getPredBuf(areaPredReg);
                predIntraAng(compID, piPredReg, pu);
              }
            }
            else
    #endif
              predIntraAng(compID, piPred, pu);
    
        }
    
    
        // 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 (flag && slice.getLmcsChromaResidualScaleFlag() && isChroma(compID))
    
    Taoran Lu's avatar
    Taoran Lu committed
      {
        const Area area = tu.Y().valid() ? tu.Y() : Area(recalcPosition(tu.chromaFormat, tu.chType, CHANNEL_TYPE_LUMA, tu.blocks[tu.chType].pos()), recalcSize(tu.chromaFormat, tu.chType, CHANNEL_TYPE_LUMA, tu.blocks[tu.chType].size()));
        const CompArea &areaY = CompArea(COMPONENT_Y, tu.chromaFormat, area );
    
    #if JVET_O1109_UNFIY_CRS
        int adj = m_pcReshape->calculateChromaAdjVpduNei(tu, areaY);
    #else
    
    Taoran Lu's avatar
    Taoran Lu committed
        PelBuf piPredY;
        piPredY = cs.picture->getPredBuf(areaY);
        const Pel avgLuma = piPredY.computeAvg();
        int adj = m_pcReshape->calculateChromaAdj(avgLuma);
    
    Taoran Lu's avatar
    Taoran Lu committed
        tu.setChromaAdj(adj);
      }
    
      //===== get residual signal =====
      piResi.copyFrom( piOrg  );
    
      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);
        piResi.rspSignal(m_pcReshape->getFwdLUT());
        piResi.subtract(tmpPred);
      }
      else
    
      piResi.subtract( piPred );
    
      if (pps.getPpsRangeExtension().getCrossComponentPredictionEnabledFlag() && isLuma(compID))
      {
        piOrgResi.copyFrom (piResi);
      }
    
      if (bUseCrossCPrediction)
      {
        if (xCalcCrossComponentPredictionAlpha(tu, compID, ccUseRecoResi) == 0)
        {
          return;
        }
        CrossComponentPrediction::crossComponentPrediction(tu, compID, cs.getResiBuf(tu.Y()), piResi, piResi, false);
      }
    
    
      //===== transform and quantization =====
      //--- init rate estimation arrays for RDOQ ---
      //--- transform and quantization           ---
      TCoeff uiAbsSum = 0;
    
      const QpParam cQP(tu, compID);
    
    #if RDOQ_CHROMA_LAMBDA
      m_pcTrQuant->selectLambda(compID);
    #endif
    
    
      flag =flag && (tu.blocks[compID].width*tu.blocks[compID].height > 4);
    
      if (flag && isChroma(compID) && slice.getLmcsChromaResidualScaleFlag() )
    
    Taoran Lu's avatar
    Taoran Lu committed
        int cResScaleInv = tu.getChromaAdj();
    
    #if JVET_O0429_CRS_LAMBDA_FIX
        double cResScale = (double)(1 << CSCALE_FP_PREC) / (double)cResScaleInv;
    #else
    
    Taoran Lu's avatar
    Taoran Lu committed
        double cResScale = round((double)(1 << CSCALE_FP_PREC) / (double)cResScaleInv);
    
    Taoran Lu's avatar
    Taoran Lu committed
        m_pcTrQuant->setLambda(m_pcTrQuant->getLambda() / (cResScale*cResScale));
    
        if ( !jointCbCr ) // Joint CbCr signal is to be scaled in the case of joint chroma
    
    Taoran Lu's avatar
    Taoran Lu committed
        piResi.scaleSignal(cResScaleInv, 1, tu.cu->cs->slice->clpRng(compID));
    
      const CompArea &crArea = tu.blocks     [ COMPONENT_Cr ];
      PelBuf          crOrg  = cs.getOrgBuf  ( crArea );
      PelBuf          crPred = cs.getPredBuf ( crArea );
      PelBuf          crResi = cs.getResiBuf ( crArea );
      PelBuf          crReco = cs.getRecoBuf ( crArea );
    
      if ( jointCbCr )
      {
    
        // Get Cr prediction and residual
        crResi.copyFrom( crOrg  );
        crResi.subtract( crPred );
    
        // Create joint residual and store it for Cb component: jointResi = (cbResi - crResi)/2
        piResi.subtractAndHalve( crResi );
    
        // Scale the joint signal
    
        if ( flag && slice.getLmcsChromaResidualScaleFlag() )
    
          piResi.scaleSignal(tu.getChromaAdj(), 1, tu.cu->cs->slice->clpRng(compID));
    
        // Lambda is loosened for the joint mode with respect to single modes as the same residual is used for both chroma blocks
    
        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() );
    #else
    
        m_pcTrQuant->setLambda( 0.60 * m_pcTrQuant->getLambda() );
    
    #if JVET_O0376_SPS_JOINTCBCR_FLAG
      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() );
      }
    #else
    
      if( isChroma(compID) && tu.cu->cs->slice->getSliceQp() > 18 )
      {
        m_pcTrQuant->setLambda( 1.3 * m_pcTrQuant->getLambda() );
      }
    
    Fangdong Chen's avatar
    Fangdong Chen committed
    #else
    
    #if JVET_O0376_SPS_JOINTCBCR_FLAG
      else if ( sps.getJointCbCrEnabledFlag() && isChroma(compID) && (tu.cu->cs->slice->getSliceQp() > 18) )
    
      else if ( isChroma(compID) && tu.cu->cs->slice->getSliceQp() > 18 )
    
    Fangdong Chen's avatar
    Fangdong Chen committed
    #endif
    
        m_pcTrQuant->setLambda( 1.10 * m_pcTrQuant->getLambda() );
    
    #if JVET_O0502_ISP_CLEANUP
        if (trModes)
        {
          m_pcTrQuant->transformNxN(tu, compID, cQP, trModes, CU::isIntra(*tu.cu) ? m_pcEncCfg->getIntraMTSMaxCand() : m_pcEncCfg->getInterMTSMaxCand());
          tu.mtsIdx = trModes->at(0).first;
        }
        m_pcTrQuant->transformNxN(tu, compID, cQP, uiAbsSum, m_CABACEstimator->getCtx(), loadTr);
    #else
    
      double diagRatio = 0, horVerRatio = 0;
    
    
    Tung Nguyen's avatar
    Tung Nguyen committed
      if( trModes )
      {
    
        m_pcTrQuant->transformNxN( tu, compID, cQP, trModes, CU::isIntra( *tu.cu ) ? m_pcEncCfg->getIntraMTSMaxCand() : m_pcEncCfg->getInterMTSMaxCand(), ispSplitIsAllowed ? &diagRatio : nullptr, ispSplitIsAllowed ? &horVerRatio : nullptr );
    
    Tung Nguyen's avatar
    Tung Nguyen committed
        tu.mtsIdx = trModes->at(0).first;
      }
    
      m_pcTrQuant->transformNxN( tu, compID, cQP, uiAbsSum, m_CABACEstimator->getCtx(), loadTr, &diagRatio, &horVerRatio );
    
        if ( !tu.cu->ispMode && isLuma(compID) && ispSplitIsAllowed && tu.mtsIdx == MTS_DCT2_DCT2 && ispSplitIsAllowed )
    
      {
        m_intraModeDiagRatio        .push_back(diagRatio);
        m_intraModeHorVerRatio      .push_back(horVerRatio);
        m_intraModeTestedNormalIntra.push_back((int)uiChFinalMode);
      }
    
    
    
      DTRACE( g_trace_ctx, D_TU_ABS_SUM, "%d: comp=%d, abssum=%d\n", DTRACE_GET_COUNTER( g_trace_ctx, D_TU_ABS_SUM ), compID, uiAbsSum );
    
    
    #if JVET_O0502_ISP_CLEANUP
    
    Santiago de Luxán Hernández's avatar
    Santiago de Luxán Hernández committed
      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;
      }
    #endif