Skip to content
Snippets Groups Projects
IntraPrediction.cpp 64.9 KiB
Newer Older
  • Learn to ignore specific revisions
  •     ptrSrc = srcBuf - (1 + multiRefIdx) * srcStride - (1 + multiRefIdx);
        ptrDst = refBufUnfiltered;
        if (neighborFlags[totalLeftUnits])
        {
          ptrDst[0] = ptrSrc[0];
    
          ptrDst[predStride] = ptrSrc[0];
    
          for (int i = 1; i <= multiRefIdx; i++)
          {
            ptrDst[i] = ptrSrc[i];
    
            ptrDst[i + predStride] = ptrSrc[i * srcStride];
    
          }
        }
    
        // Fill left & below-left samples if available (downwards)
        ptrSrc += (1 + multiRefIdx) * srcStride;
    
        ptrDst += (1 + multiRefIdx) + predStride;
    
        for (int unitIdx = totalLeftUnits - 1; unitIdx > 0; unitIdx--)
        {
          if (neighborFlags[unitIdx])
          {
            for (int i = 0; i < unitHeight; i++)
            {
    
              ptrDst[i] = ptrSrc[i * srcStride];
    
            }
          }
          ptrSrc += unitHeight * srcStride;
    
        }
        // Fill last below-left sample(s)
        if (neighborFlags[0])
        {
          int lastSample = (predHSize % unitHeight == 0) ? unitHeight : predHSize % unitHeight;
          for (int i = 0; i < lastSample; i++)
          {
    
            ptrDst[i] = ptrSrc[i * srcStride];
    
          }
        }
    
        // Fill above & above-right samples if available (left-to-right)
        ptrSrc = srcBuf - srcStride * (1 + multiRefIdx);
        ptrDst = refBufUnfiltered + 1 + multiRefIdx;
        for (int unitIdx = totalLeftUnits + 1; unitIdx < totalUnits - 1; unitIdx++)
        {
          if (neighborFlags[unitIdx])
          {
            for (int j = 0; j < unitWidth; j++)
            {
              ptrDst[j] = ptrSrc[j];
            }
          }
          ptrSrc += unitWidth;
          ptrDst += unitWidth;
        }
        // Fill last above-right sample(s)
        if (neighborFlags[totalUnits - 1])
        {
          int lastSample = (predSize % unitWidth == 0) ? unitWidth : predSize % unitWidth;
          for (int j = 0; j < lastSample; j++)
          {
            ptrDst[j] = ptrSrc[j];
          }
        }
    
        // pad from first available down to the last below-left
        ptrDst = refBufUnfiltered;
        int lastAvailUnit = 0;
        if (!neighborFlags[0])
        {
          int firstAvailUnit = 1;
          while (firstAvailUnit < totalUnits && !neighborFlags[firstAvailUnit])
          {
            firstAvailUnit++;
          }
    
          // first available sample
    
          int firstAvailCol = 0;
          if (firstAvailUnit < totalLeftUnits)
          {
            firstAvailRow = (totalLeftUnits - firstAvailUnit) * unitHeight + multiRefIdx;
          }
          else if (firstAvailUnit == totalLeftUnits)
          {
            firstAvailRow = multiRefIdx;
          }
          else
          {
            firstAvailCol = (firstAvailUnit - totalLeftUnits - 1) * unitWidth + 1 + multiRefIdx;
          }
    
          const Pel firstAvailSample = ptrDst[firstAvailRow < 0 ? firstAvailCol : firstAvailRow + predStride];
    
    
          // last sample below-left (n.a.)
          int lastRow = predHSize + multiRefIdx;
    
          // fill left column
          for (int i = lastRow; i > firstAvailRow; i--)
          {
    
            ptrDst[i + predStride] = firstAvailSample;
    
          }
          // fill top row
          if (firstAvailCol > 0)
          {
            for (int j = 0; j < firstAvailCol; j++)
            {
              ptrDst[j] = firstAvailSample;
            }
          }
          lastAvailUnit = firstAvailUnit;
        }
    
        // pad all other reference samples.
        int currUnit = lastAvailUnit + 1;
        while (currUnit < totalUnits)
        {
          if (!neighborFlags[currUnit]) // samples not available
          {
            // last available sample
    
            int lastAvailCol = 0;
            if (lastAvailUnit < totalLeftUnits)
            {
              lastAvailRow = (totalLeftUnits - lastAvailUnit - 1) * unitHeight + multiRefIdx + 1;
            }
            else if (lastAvailUnit == totalLeftUnits)
            {
              lastAvailCol = multiRefIdx;
            }
            else
            {
              lastAvailCol = (lastAvailUnit - totalLeftUnits) * unitWidth + multiRefIdx;
            }
    
            const Pel lastAvailSample = ptrDst[lastAvailRow < 0 ? lastAvailCol : lastAvailRow + predStride];
    
    
            // fill current unit with last available sample
            if (currUnit < totalLeftUnits)
            {
    
              for (int i = lastAvailRow - 1; i >= lastAvailRow - unitHeight; i--)
    
                ptrDst[i + predStride] = lastAvailSample;
    
              }
            }
            else if (currUnit == totalLeftUnits)
            {
    
              for (int i = 0; i < multiRefIdx + 1; i++)
    
                ptrDst[i + predStride] = lastAvailSample;
    
              }
              for (int j = 0; j < multiRefIdx + 1; j++)
              {
                ptrDst[j] = lastAvailSample;
              }
            }
            else
            {
              int numSamplesInUnit = (currUnit == totalUnits - 1) ? ((predSize % unitWidth == 0) ? unitWidth : predSize % unitWidth) : unitWidth;
              for (int j = lastAvailCol + 1; j <= lastAvailCol + numSamplesInUnit; j++)
              {
                ptrDst[j] = lastAvailSample;
              }
            }
          }
          lastAvailUnit = currUnit;
          currUnit++;
        }
    
    void IntraPrediction::xFilterReferenceSamples(const Pel *refBufUnfiltered, Pel *refBufFiltered, const CompArea &area,
                                                  const SPS &sps, int multiRefIdx
    
      if (area.compID != COMPONENT_Y)
      {
        multiRefIdx = 0;
      }
    
      const int predSize = m_topRefLength + multiRefIdx;
      const int predHSize = m_leftRefLength + multiRefIdx;
    
      const size_t predStride = m_refBufferStride[area.compID];
    
      const Pel topLeft =
        (refBufUnfiltered[0] + refBufUnfiltered[1] + refBufUnfiltered[predStride] + refBufUnfiltered[predStride + 1] + 2)
        >> 2;
    
      refBufFiltered[0] = topLeft;
    
      for (int i = 1; i < predSize; i++)
      {
        refBufFiltered[i] = (refBufUnfiltered[i - 1] + 2 * refBufUnfiltered[i] + refBufUnfiltered[i + 1] + 2) >> 2;
      }
      refBufFiltered[predSize] = refBufUnfiltered[predSize];
    
      refBufFiltered += predStride;
      refBufUnfiltered += predStride;
    
      refBufFiltered[0] = topLeft;
    
      for (int i = 1; i < predHSize; i++)
      {
        refBufFiltered[i] = (refBufUnfiltered[i - 1] + 2 * refBufUnfiltered[i] + refBufUnfiltered[i + 1] + 2) >> 2;
      }
      refBufFiltered[predHSize] = refBufUnfiltered[predHSize];
    
    }
    
    bool isAboveLeftAvailable(const CodingUnit &cu, const ChannelType &chType, const Position &posLT)
    {
      const CodingStructure& cs = *cu.cs;
      const Position refPos = posLT.offset(-1, -1);
    
    
      if (!cs.isDecomp(refPos, chType))
    
      return (cs.getCURestricted(refPos, cu, chType) != NULL);
    
    }
    
    int isAboveAvailable(const CodingUnit &cu, const ChannelType &chType, const Position &posLT, const uint32_t uiNumUnitsInPU, const uint32_t unitWidth, bool *bValidFlags)
    {
      const CodingStructure& cs = *cu.cs;
    
    
      bool *    validFlags = bValidFlags;
      int       numIntra   = 0;
      const int maxDx      = uiNumUnitsInPU * unitWidth;
    
      for (int dx = 0; dx < maxDx; dx += unitWidth)
    
        if (!cs.isDecomp(refPos, chType))
    
        const bool valid = (cs.getCURestricted(refPos, cu, chType) != NULL);
        numIntra += valid ? 1 : 0;
        *validFlags = valid;
    
    }
    
    int isLeftAvailable(const CodingUnit &cu, const ChannelType &chType, const Position &posLT, const uint32_t uiNumUnitsInPU, const uint32_t unitHeight, bool *bValidFlags)
    {
      const CodingStructure& cs = *cu.cs;
    
    
      bool *    validFlags = bValidFlags;
      int       numIntra   = 0;
      const int maxDy      = uiNumUnitsInPU * unitHeight;
    
      for (int dy = 0; dy < maxDy; dy += unitHeight)
    
        if (!cs.isDecomp(refPos, chType))
    
        const bool valid = (cs.getCURestricted(refPos, cu, chType) != NULL);
        numIntra += valid ? 1 : 0;
        *validFlags = valid;
    
    }
    
    int isAboveRightAvailable(const CodingUnit &cu, const ChannelType &chType, const Position &posRT, const uint32_t uiNumUnitsInPU, const uint32_t unitWidth, bool *bValidFlags )
    {
      const CodingStructure& cs = *cu.cs;
    
    
      bool *    validFlags = bValidFlags;
      int       numIntra   = 0;
      const int maxDx      = uiNumUnitsInPU * unitWidth;
    
      for (int dx = 0; dx < maxDx; dx += unitWidth)
    
      {
        const Position refPos = posRT.offset(unitWidth + dx, -1);
    
    
        if (!cs.isDecomp(refPos, chType))
    
        const bool valid = (cs.getCURestricted(refPos, cu, chType) != NULL);
        numIntra += valid ? 1 : 0;
        *validFlags = valid;
    
    }
    
    int isBelowLeftAvailable(const CodingUnit &cu, const ChannelType &chType, const Position &posLB, const uint32_t uiNumUnitsInPU, const uint32_t unitHeight, bool *bValidFlags )
    {
      const CodingStructure& cs = *cu.cs;
    
    
      bool *    validFlags = bValidFlags;
      int       numIntra   = 0;
      const int maxDy      = uiNumUnitsInPU * unitHeight;
    
      for (int dy = 0; dy < maxDy; dy += unitHeight)
    
      {
        const Position refPos = posLB.offset(-1, unitHeight + dy);
    
    
        if (!cs.isDecomp(refPos, chType))
    
        const bool valid = (cs.getCURestricted(refPos, cu, chType) != NULL);
        numIntra += valid ? 1 : 0;
        *validFlags = valid;
    
    // LumaRecPixels
    void IntraPrediction::xGetLumaRecPixels(const PredictionUnit &pu, CompArea chromaArea)
    {
      int iDstStride = 0;
      Pel* pDst0 = 0;
    
      int curChromaMode = pu.intraDir[1];
      if ((curChromaMode == MDLM_L_IDX) || (curChromaMode == MDLM_T_IDX))
      {
        iDstStride = 2 * MAX_CU_SIZE + 1;
        pDst0 = m_pMdlmTemp + iDstStride + 1;
      }
      else
      {
    
        iDstStride = MAX_CU_SIZE + 1;
        pDst0 = m_piTemp + iDstStride + 1; //MMLM_SAMPLE_NEIGHBOR_LINES;
    
      //assert 420 chroma subsampling
      CompArea lumaArea = CompArea( COMPONENT_Y, pu.chromaFormat, chromaArea.lumaPos(), recalcSize( pu.chromaFormat, CHANNEL_TYPE_CHROMA, CHANNEL_TYPE_LUMA, chromaArea.size() ) );//needed for correct pos/size (4x4 Tus)
    
      CHECK(lumaArea.width == chromaArea.width && CHROMA_444 != pu.chromaFormat, "");
      CHECK(lumaArea.height == chromaArea.height && CHROMA_444 != pu.chromaFormat && CHROMA_422 != pu.chromaFormat, "");
    
    
      const SizeType uiCWidth = chromaArea.width;
      const SizeType uiCHeight = chromaArea.height;
    
      const CPelBuf Src = pu.cs->picture->getRecoBuf( lumaArea );
      Pel const* pRecSrc0   = Src.bufAt( 0, 0 );
      int iRecStride        = Src.stride;
    
      int logSubWidthC  = getChannelTypeScaleX(CHANNEL_TYPE_CHROMA, pu.chromaFormat);
      int logSubHeightC = getChannelTypeScaleY(CHANNEL_TYPE_CHROMA, pu.chromaFormat);
    
      int iRecStride2       = iRecStride << logSubHeightC;
    
    
      const CodingUnit& lumaCU = isChroma( pu.chType ) ? *pu.cs->picture->cs->getCU( lumaArea.pos(), CH_L ) : *pu.cu;
      const CodingUnit&     cu = *pu.cu;
    
      const CompArea& area = isChroma( pu.chType ) ? chromaArea : lumaArea;
    
      const uint32_t uiTuWidth  = area.width;
      const uint32_t uiTuHeight = area.height;
    
      int iBaseUnitSize = ( 1 << MIN_CU_LOG2 );
    
      const int  iUnitWidth       = iBaseUnitSize >> getComponentScaleX( area.compID, area.chromaFormat );
    
      const int  iUnitHeight = iBaseUnitSize >> getComponentScaleY(area.compID, area.chromaFormat);
    
      const int  iTUWidthInUnits = uiTuWidth / iUnitWidth;
    
      const int  iTUHeightInUnits = uiTuHeight / iUnitHeight;
      const int  iAboveUnits      = iTUWidthInUnits;
      const int  iLeftUnits       = iTUHeightInUnits;
    
      const int  chromaUnitWidth = iBaseUnitSize >> getComponentScaleX(COMPONENT_Cb, area.chromaFormat);
    
      const int  chromaUnitHeight = iBaseUnitSize >> getComponentScaleY(COMPONENT_Cb, area.chromaFormat);
    
      const int  topTemplateSampNum = 2 * uiCWidth; // for MDLM, the number of template samples is 2W or 2H.
      const int  leftTemplateSampNum = 2 * uiCHeight;
      assert(m_topRefLength >= topTemplateSampNum);
      assert(m_leftRefLength >= leftTemplateSampNum);
      const int  totalAboveUnits = (topTemplateSampNum + (chromaUnitWidth - 1)) / chromaUnitWidth;
      const int  totalLeftUnits = (leftTemplateSampNum + (chromaUnitHeight - 1)) / chromaUnitHeight;
      const int  totalUnits = totalLeftUnits + totalAboveUnits + 1;
      const int  aboveRightUnits = totalAboveUnits - iAboveUnits;
      const int  leftBelowUnits = totalLeftUnits - iLeftUnits;
    
      int avaiAboveRightUnits = 0;
      int avaiLeftBelowUnits = 0;
    
      bool  bNeighborFlags[4 * MAX_NUM_PART_IDXS_IN_CTU_WIDTH + 1];
    
      memset(bNeighborFlags, 0, totalUnits);
    
      bool aboveIsAvailable, leftIsAvailable;
    
      int availlableUnit = isLeftAvailable( isChroma( pu.chType ) ? cu : lumaCU, toChannelType( area.compID ), area.pos(), iLeftUnits, iUnitHeight,
      ( bNeighborFlags + iLeftUnits + leftBelowUnits - 1 ) );
    
      leftIsAvailable = availlableUnit == iTUHeightInUnits;
    
      availlableUnit = isAboveAvailable( isChroma( pu.chType ) ? cu : lumaCU, toChannelType( area.compID ), area.pos(), iAboveUnits, iUnitWidth,
      ( bNeighborFlags + iLeftUnits + leftBelowUnits + 1 ) );
    
      aboveIsAvailable = availlableUnit == iTUWidthInUnits;
    
      if (leftIsAvailable)   // if left is not available, then the below left is not available
    
      {
        avaiLeftBelowUnits = isBelowLeftAvailable(isChroma(pu.chType) ? cu : lumaCU, toChannelType(area.compID), area.bottomLeftComp(area.compID), leftBelowUnits, iUnitHeight, (bNeighborFlags + leftBelowUnits - 1));
      }
    
      if (aboveIsAvailable)   // if above is not available, then  the above right is not available.
    
      {
        avaiAboveRightUnits = isAboveRightAvailable(isChroma(pu.chType) ? cu : lumaCU, toChannelType(area.compID), area.topRightComp(area.compID), aboveRightUnits, iUnitWidth, (bNeighborFlags + iLeftUnits + leftBelowUnits + iAboveUnits + 1));
      }
    
      bool isFirstRowOfCtu = (lumaArea.y & ((pu.cs->sps)->getCTUSize() - 1)) == 0;
    
        int addedAboveRight = 0;
        if ((curChromaMode == MDLM_L_IDX) || (curChromaMode == MDLM_T_IDX))
        {
          addedAboveRight = avaiAboveRightUnits*chromaUnitWidth;
        }
        for (int i = 0; i < uiCWidth + addedAboveRight; i++)
    
          const bool leftPadding = i == 0 && !leftIsAvailable;
          if (pu.chromaFormat == CHROMA_444)
    
            pDst[i] = piSrc[i];
          }
          else if (isFirstRowOfCtu)
          {
            piSrc   = pRecSrc0 - iRecStride;
            pDst[i] = (piSrc[2 * i] * 2 + piSrc[2 * i - (leftPadding ? 0 : 1)] + piSrc[2 * i + 1] + 2) >> 2;
          }
          else if (pu.chromaFormat == CHROMA_422)
          {
            piSrc = pRecSrc0 - iRecStride2;
    
            int s = 2;
            s += piSrc[2 * i] * 2;
            s += piSrc[2 * i - (leftPadding ? 0 : 1)];
            s += piSrc[2 * i + 1];
            pDst[i] = s >> 2;
    
          else if (pu.cs->sps->getCclmCollocatedChromaFlag())
    
    Philippe Hanhart's avatar
    Philippe Hanhart committed
          {
            piSrc = pRecSrc0 - iRecStride2;
    
            int s = 4;
            s += piSrc[2 * i - iRecStride];
            s += piSrc[2 * i] * 4;
            s += piSrc[2 * i - (leftPadding ? 0 : 1)];
            s += piSrc[2 * i + 1];
            s += piSrc[2 * i + iRecStride];
            pDst[i] = s >> 3;
    
    Philippe Hanhart's avatar
    Philippe Hanhart committed
          }
    
            int s = 4;
            s += piSrc[2 * i] * 2;
            s += piSrc[2 * i + 1];
            s += piSrc[2 * i - (leftPadding ? 0 : 1)];
            s += piSrc[2 * i + iRecStride] * 2;
            s += piSrc[2 * i + 1 + iRecStride];
            s += piSrc[2 * i + iRecStride - (leftPadding ? 0 : 1)];
            pDst[i] = s >> 3;
    
        piSrc = pRecSrc0 - 1 - logSubWidthC;
    
        int addedLeftBelow = 0;
        if ((curChromaMode == MDLM_L_IDX) || (curChromaMode == MDLM_T_IDX))
        {
          addedLeftBelow = avaiLeftBelowUnits*chromaUnitHeight;
        }
    
        for (int j = 0; j < uiCHeight + addedLeftBelow; j++)
    
          if (pu.chromaFormat == CHROMA_444)
    
    Philippe Hanhart's avatar
    Philippe Hanhart committed
          {
    
            pDst[0] = piSrc[0];
          }
          else if (pu.chromaFormat == CHROMA_422)
          {
            int s = 2;
            s += piSrc[0] * 2;
            s += piSrc[-1];
            s += piSrc[1];
            pDst[0] = s >> 2;
          }
          else if (pu.cs->sps->getCclmCollocatedChromaFlag())
          {
            const bool abovePadding = j == 0 && !aboveIsAvailable;
    
            int s = 4;
            s += piSrc[-(abovePadding ? 0 : iRecStride)];
            s += piSrc[0] * 4;
            s += piSrc[-1];
            s += piSrc[1];
            s += piSrc[iRecStride];
            pDst[0] = s >> 3;
    
    Philippe Hanhart's avatar
    Philippe Hanhart committed
          }
          else
          {
    
            int s = 4;
            s += piSrc[0] * 2;
            s += piSrc[1];
            s += piSrc[-1];
            s += piSrc[iRecStride] * 2;
            s += piSrc[iRecStride + 1];
            s += piSrc[iRecStride - 1];
            pDst[0] = s >> 3;
    
    Philippe Hanhart's avatar
    Philippe Hanhart committed
          }
    
    
          piSrc += iRecStride2;
          pDst  += iDstStride;
        }
      }
    
      // inner part from reconstructed picture buffer
      for( int j = 0; j < uiCHeight; j++ )
      {
        for( int i = 0; i < uiCWidth; i++ )
        {
    
          if (pu.chromaFormat == CHROMA_444)
    
          else if (pu.chromaFormat == CHROMA_422)
    
            const bool leftPadding  = i == 0 && !leftIsAvailable;
    
            int s = 2;
            s += pRecSrc0[2 * i] * 2;
            s += pRecSrc0[2 * i - (leftPadding ? 0 : 1)];
            s += pRecSrc0[2 * i + 1];
            pDst0[i] = s >> 2;
          }
          else if (pu.cs->sps->getCclmCollocatedChromaFlag())
          {
            const bool leftPadding  = i == 0 && !leftIsAvailable;
            const bool abovePadding = j == 0 && !aboveIsAvailable;
    
            int s = 4;
            s += pRecSrc0[2 * i - (abovePadding ? 0 : iRecStride)];
            s += pRecSrc0[2 * i] * 4;
            s += pRecSrc0[2 * i - (leftPadding ? 0 : 1)];
            s += pRecSrc0[2 * i + 1];
            s += pRecSrc0[2 * i + iRecStride];
            pDst0[i] = s >> 3;
          }
          else
          {
            CHECK(pu.chromaFormat != CHROMA_420, "Chroma format must be 4:2:0 for vertical filtering");
            const bool leftPadding = i == 0 && !leftIsAvailable;
    
            int s = 4;
            s += pRecSrc0[2 * i] * 2;
            s += pRecSrc0[2 * i + 1];
            s += pRecSrc0[2 * i - (leftPadding ? 0 : 1)];
            s += pRecSrc0[2 * i + iRecStride] * 2;
            s += pRecSrc0[2 * i + 1 + iRecStride];
            s += pRecSrc0[2 * i + iRecStride - (leftPadding ? 0 : 1)];
            pDst0[i] = s >> 3;
    
    void IntraPrediction::xGetLMParameters(const PredictionUnit &pu, const ComponentID compID,
                                                  const CompArea &chromaArea,
                                                  int &a, int &b, int &iShift)
    {
      CHECK(compID == COMPONENT_Y, "");
    
      const SizeType cWidth  = chromaArea.width;
      const SizeType cHeight = chromaArea.height;
    
      const Position posLT = chromaArea;
    
      CodingStructure & cs = *(pu.cs);
      const CodingUnit &cu = *(pu.cu);
    
      const SPS &        sps           = *cs.sps;
      const uint32_t     tuWidth     = chromaArea.width;
      const uint32_t     tuHeight    = chromaArea.height;
      const ChromaFormat nChromaFormat = sps.getChromaFormatIdc();
    
      const int baseUnitSize = 1 << MIN_CU_LOG2;
      const int unitWidth    = baseUnitSize >> getComponentScaleX(chromaArea.compID, nChromaFormat);
    
      const int unitHeight   = baseUnitSize >> getComponentScaleY(chromaArea.compID, nChromaFormat);
    
    
      const int tuWidthInUnits  = tuWidth / unitWidth;
      const int tuHeightInUnits = tuHeight / unitHeight;
      const int aboveUnits      = tuWidthInUnits;
      const int leftUnits       = tuHeightInUnits;
    
      int topTemplateSampNum = 2 * cWidth; // for MDLM, the template sample number is 2W or 2H;
      int leftTemplateSampNum = 2 * cHeight;
      assert(m_topRefLength >= topTemplateSampNum);
      assert(m_leftRefLength >= leftTemplateSampNum);
      int totalAboveUnits = (topTemplateSampNum + (unitWidth - 1)) / unitWidth;
      int totalLeftUnits = (leftTemplateSampNum + (unitHeight - 1)) / unitHeight;
      int totalUnits = totalLeftUnits + totalAboveUnits + 1;
      int aboveRightUnits = totalAboveUnits - aboveUnits;
      int leftBelowUnits = totalLeftUnits - leftUnits;
      int avaiAboveRightUnits = 0;
      int avaiLeftBelowUnits = 0;
      int avaiAboveUnits = 0;
      int avaiLeftUnits = 0;
    
      int curChromaMode = pu.intraDir[1];
    
      bool neighborFlags[4 * MAX_NUM_PART_IDXS_IN_CTU_WIDTH + 1];
    
      memset(neighborFlags, 0, totalUnits);
    
    
      bool aboveAvailable, leftAvailable;
    
      int availableUnit =
    
        isAboveAvailable(cu, CHANNEL_TYPE_CHROMA, posLT, aboveUnits, unitWidth,
    
        (neighborFlags + leftUnits + leftBelowUnits + 1));
    
      aboveAvailable = availableUnit == tuWidthInUnits;
    
      availableUnit =
    
        isLeftAvailable(cu, CHANNEL_TYPE_CHROMA, posLT, leftUnits, unitHeight,
    
        (neighborFlags + leftUnits + leftBelowUnits - 1));
    
      leftAvailable = availableUnit == tuHeightInUnits;
    
      if (leftAvailable) // if left is not available, then the below left is not available
      {
        avaiLeftUnits = tuHeightInUnits;
        avaiLeftBelowUnits = isBelowLeftAvailable(cu, CHANNEL_TYPE_CHROMA, chromaArea.bottomLeftComp(chromaArea.compID), leftBelowUnits, unitHeight, (neighborFlags + leftBelowUnits - 1));
      }
      if (aboveAvailable) // if above is not available, then  the above right is not available.
      {
        avaiAboveUnits = tuWidthInUnits;
        avaiAboveRightUnits = isAboveRightAvailable(cu, CHANNEL_TYPE_CHROMA, chromaArea.topRightComp(chromaArea.compID), aboveRightUnits, unitWidth, (neighborFlags + leftUnits + leftBelowUnits + aboveUnits + 1));
      }
    
      Pel *srcColor0, *curChroma0;
    
      if ((curChromaMode == MDLM_L_IDX) || (curChromaMode == MDLM_T_IDX))
      {
        srcStride = 2 * MAX_CU_SIZE + 1;
        temp = PelBuf(m_pMdlmTemp + srcStride + 1, srcStride, Size(chromaArea));
      }
      else
      {
    
        srcStride = MAX_CU_SIZE + 1;
        temp        = PelBuf(m_piTemp + srcStride + 1, srcStride, Size(chromaArea));
    
      srcColor0 = temp.bufAt(0, 0);
      curChroma0 = getPredictorPtr(compID);
    
    
      unsigned internalBitDepth = sps.getBitDepth(CHANNEL_TYPE_CHROMA);
    
    
      int maxLuma[2] = { -MAX_INT, 0 };
    
      Pel *src = srcColor0 - srcStride;
    
      int actualTopTemplateSampNum = 0;
      int actualLeftTemplateSampNum = 0;
      if (curChromaMode == MDLM_T_IDX)
      {
        leftAvailable = 0;
    
    Kai Zhang's avatar
    Kai Zhang committed
        avaiAboveRightUnits = avaiAboveRightUnits > (cHeight/unitWidth) ?  cHeight/unitWidth : avaiAboveRightUnits;
    
        actualTopTemplateSampNum = unitWidth*(avaiAboveUnits + avaiAboveRightUnits);
      }
      else if (curChromaMode == MDLM_L_IDX)
      {
        aboveAvailable = 0;
    
        avaiLeftBelowUnits = avaiLeftBelowUnits > (cWidth/unitHeight) ? cWidth/unitHeight : avaiLeftBelowUnits;
    
        actualLeftTemplateSampNum = unitHeight*(avaiLeftUnits + avaiLeftBelowUnits);
      }
      else if (curChromaMode == LM_CHROMA_IDX)
      {
        actualTopTemplateSampNum = cWidth;
        actualLeftTemplateSampNum = cHeight;
    
    Kai Zhang's avatar
    Kai Zhang committed
      }
      int startPos[2]; //0:Above, 1: Left
      int pickStep[2];
    
      int aboveIs4 = leftAvailable  ? 0 : 1;
      int leftIs4 =  aboveAvailable ? 0 : 1;
    
      startPos[0] = actualTopTemplateSampNum >> (2 + aboveIs4);
      pickStep[0] = std::max(1, actualTopTemplateSampNum >> (1 + aboveIs4));
    
      startPos[1] = actualLeftTemplateSampNum >> (2 + leftIs4);
      pickStep[1] = std::max(1, actualLeftTemplateSampNum >> (1 + leftIs4));
    
    
    Kai Zhang's avatar
    Kai Zhang committed
      Pel selectLumaPix[4] = { 0, 0, 0, 0 };
      Pel selectChromaPix[4] = { 0, 0, 0, 0 };
    
    Kai Zhang's avatar
    Kai Zhang committed
    
      int cntT, cntL;
      cntT = cntL = 0;
      int cnt = 0;
      if (aboveAvailable)
      {
        cntT = std::min(actualTopTemplateSampNum, (1 + aboveIs4) << 1);
        src = srcColor0 - srcStride;
    
        const Pel *cur = curChroma0 + 1;
    
    Kai Zhang's avatar
    Kai Zhang committed
        for (int pos = startPos[0]; cnt < cntT; pos += pickStep[0], cnt++)
        {
          selectLumaPix[cnt] = src[pos];
          selectChromaPix[cnt] = cur[pos];
        }
    
    Kai Zhang's avatar
    Kai Zhang committed
    
      if (leftAvailable)
      {
        cntL = std::min(actualLeftTemplateSampNum, ( 1 + leftIs4 ) << 1 );
        src = srcColor0 - 1;
    
        const Pel *cur = curChroma0 + m_refBufferStride[compID] + 1;
    
    Kai Zhang's avatar
    Kai Zhang committed
        for (int pos = startPos[1], cnt = 0; cnt < cntL; pos += pickStep[1], cnt++)
        {
          selectLumaPix[cnt + cntT] = src[pos * srcStride];
    
          selectChromaPix[cnt + cntT] = cur[pos];
    
    Kai Zhang's avatar
    Kai Zhang committed
        }
      }
      cnt = cntL + cntT;
    
    Kai Zhang's avatar
    Kai Zhang committed
      if (cnt == 2)
      {
        selectLumaPix[3] = selectLumaPix[0]; selectChromaPix[3] = selectChromaPix[0];
        selectLumaPix[2] = selectLumaPix[1]; selectChromaPix[2] = selectChromaPix[1];
        selectLumaPix[0] = selectLumaPix[1]; selectChromaPix[0] = selectChromaPix[1];
        selectLumaPix[1] = selectLumaPix[3]; selectChromaPix[1] = selectChromaPix[3];
      }
    
      int minGrpIdx[2] = { 0, 2 };
      int maxGrpIdx[2] = { 1, 3 };
      int *tmpMinGrp = minGrpIdx;
      int *tmpMaxGrp = maxGrpIdx;
      if (selectLumaPix[tmpMinGrp[0]] > selectLumaPix[tmpMinGrp[1]]) std::swap(tmpMinGrp[0], tmpMinGrp[1]);
      if (selectLumaPix[tmpMaxGrp[0]] > selectLumaPix[tmpMaxGrp[1]]) std::swap(tmpMaxGrp[0], tmpMaxGrp[1]);
      if (selectLumaPix[tmpMinGrp[0]] > selectLumaPix[tmpMaxGrp[1]]) std::swap(tmpMinGrp, tmpMaxGrp);
      if (selectLumaPix[tmpMinGrp[1]] > selectLumaPix[tmpMaxGrp[0]]) std::swap(tmpMinGrp[1], tmpMaxGrp[0]);
    
      minLuma[0] = (selectLumaPix[tmpMinGrp[0]] + selectLumaPix[tmpMinGrp[1]] + 1 )>>1;
      minLuma[1] = (selectChromaPix[tmpMinGrp[0]] + selectChromaPix[tmpMinGrp[1]] + 1) >> 1;
      maxLuma[0] = (selectLumaPix[tmpMaxGrp[0]] + selectLumaPix[tmpMaxGrp[1]] + 1 )>>1;
      maxLuma[1] = (selectChromaPix[tmpMaxGrp[0]] + selectChromaPix[tmpMaxGrp[1]] + 1) >> 1;
    
        int diff = maxLuma[0] - minLuma[0];
        if (diff > 0)
        {
          int diffC = maxLuma[1] - minLuma[1];
          int x = floorLog2( diff );
          static const uint8_t DivSigTable[1 << 4] = {
            // 4bit significands - 8 ( MSB is omitted )
            0,  7,  6,  5,  5,  4,  4,  3,  3,  2,  2,  1,  1,  1,  1,  0
          };
          int normDiff = (diff << 4 >> x) & 15;
          int v = DivSigTable[normDiff] | 8;
          x += normDiff != 0;
    
          int y = floorLog2( abs( diffC ) ) + 1;
          int add = 1 << y >> 1;
          a = (diffC * v + add) >> y;
          iShift = 3 + x - y;
    
          if ( iShift < 1 )
          {
    
            iShift = 1;
            a = ( (a == 0)? 0: (a < 0)? -15 : 15 );   // a=Sign(a)*15
          }
          b = minLuma[1] - ((a * minLuma[0]) >> iShift);
        }
        else
        {
          a = 0;
          b = minLuma[1];
          iShift = 0;
        }
    
    void IntraPrediction::initIntraMip( const PredictionUnit &pu, const CompArea &area )
    {
      CHECK( area.width > MIP_MAX_WIDTH || area.height > MIP_MAX_HEIGHT, "Error: block size not supported for MIP" );
    
      // prepare input (boundary) data for prediction
      CHECK( m_ipaParam.refFilterFlag, "ERROR: unfiltered refs expected for MIP" );
    
      Pel       *ptrSrc     = getPredictorPtr(area.compID);
      const int  srcStride  = m_refBufferStride[area.compID];
      const int  srcHStride = 2;
    
      m_matrixIntraPred.prepareInputForPred(CPelBuf(ptrSrc, srcStride, srcHStride), area,
                                            pu.cu->slice->getSPS()->getBitDepth(toChannelType(area.compID)), area.compID);
    
    
    void IntraPrediction::predIntraMip( const ComponentID compId, PelBuf &piPred, const PredictionUnit &pu )
    {
    
      CHECK( piPred.width > MIP_MAX_WIDTH || piPred.height > MIP_MAX_HEIGHT, "Error: block size not supported for MIP" );
      CHECK( piPred.width != (1 << floorLog2(piPred.width)) || piPred.height != (1 << floorLog2(piPred.height)), "Error: expecting blocks of size 2^M x 2^N" );
    
      // generate mode-specific prediction
    
      uint32_t modeIdx       = MAX_NUM_MIP_MODE;
      bool     transposeFlag = false;
      if (compId == COMPONENT_Y)
      {
        modeIdx       = pu.intraDir[CHANNEL_TYPE_LUMA];
        transposeFlag = pu.mipTransposedFlag;
      }
      else
      {
        const PredictionUnit &coLocatedLumaPU = PU::getCoLocatedLumaPU(pu);
    
        CHECK(pu.intraDir[CHANNEL_TYPE_CHROMA] != DM_CHROMA_IDX, "Error: MIP is only supported for chroma with DM_CHROMA.");
        CHECK(!coLocatedLumaPU.cu->mipFlag, "Error: Co-located luma CU should use MIP.");
    
        modeIdx       = coLocatedLumaPU.intraDir[CHANNEL_TYPE_LUMA];
        transposeFlag = coLocatedLumaPU.mipTransposedFlag;
      }
      const int bitDepth = pu.cu->slice->getSPS()->getBitDepth(toChannelType(compId));
    
      CHECK(modeIdx >= getNumModesMip(piPred), "Error: Wrong MIP mode index");
    
    
      static_vector<int, MIP_MAX_WIDTH* MIP_MAX_HEIGHT> predMip( piPred.width * piPred.height );
    
      m_matrixIntraPred.predBlock(predMip.data(), modeIdx, transposeFlag, bitDepth, compId);
    
    
      for( int y = 0; y < piPred.height; y++ )
      {
        for( int x = 0; x < piPred.width; x++ )
        {
          piPred.at( x, y ) = Pel(predMip[y * piPred.width + x]);
        }
      }
    
    void IntraPrediction::reorderPLT(CodingStructure& cs, Partitioner& partitioner, ComponentID compBegin, uint32_t numComp)
    
      CodingUnit &cu = *cs.getCU(partitioner.chType);
    
    
      uint8_t        reusePLTSizetmp = 0;
      uint8_t        pltSizetmp = 0;
    
      Pel            curPLTtmp[MAX_NUM_COMPONENT][MAXPLTSIZE];
      bool           curPLTpred[MAXPLTPREDSIZE];
    
      for (int idx = 0; idx < MAXPLTPREDSIZE; idx++)
      {
        curPLTpred[idx] = false;
        cu.reuseflag[compBegin][idx] = false;
      }
      for (int idx = 0; idx < MAXPLTSIZE; idx++)
      {
        curPLTpred[idx] = false;
      }
    
      for (int predidx = 0; predidx < cs.prevPLT.curPLTSize[compBegin]; predidx++)
      {
        bool match = false;
        int curidx = 0;
    
        for (curidx = 0; curidx < cu.curPLTSize[compBegin]; curidx++)
        {
    
          if( curPLTpred[curidx] )
            continue;
    
          bool matchTmp = true;
          for (int comp = compBegin; comp < (compBegin + numComp); comp++)
          {
            matchTmp = matchTmp && (cu.curPLT[comp][curidx] == cs.prevPLT.curPLT[comp][predidx]);
          }
          if (matchTmp)
          {
            match = true;
            break;
          }
        }
    
        if (match)
        {
          cu.reuseflag[compBegin][predidx] = true;
          curPLTpred[curidx] = true;
    
          if( cu.isLocalSepTree() )
          {
            cu.reuseflag[COMPONENT_Y][predidx] = true;
            for( int comp = COMPONENT_Y; comp < MAX_NUM_COMPONENT; comp++ )
            {
              curPLTtmp[comp][reusePLTSizetmp] = cs.prevPLT.curPLT[comp][predidx];
            }
          }
          else
          {
    
          for (int comp = compBegin; comp < (compBegin + numComp); comp++)
          {
            curPLTtmp[comp][reusePLTSizetmp] = cs.prevPLT.curPLT[comp][predidx];
          }
    
        }
      }
      cu.reusePLTSize[compBegin] = reusePLTSizetmp;
      for (int curidx = 0; curidx < cu.curPLTSize[compBegin]; curidx++)
      {
        if (!curPLTpred[curidx])
        {
    
          if( cu.isLocalSepTree() )
          {
            for( int comp = compBegin; comp < (compBegin + numComp); comp++ )
            {
              curPLTtmp[comp][pltSizetmp] = cu.curPLT[comp][curidx];
            }
            if( isLuma(partitioner.chType) )
            {
              curPLTtmp[COMPONENT_Cb][pltSizetmp] = 1 << (cs.sps->getBitDepth(CHANNEL_TYPE_CHROMA) - 1);
              curPLTtmp[COMPONENT_Cr][pltSizetmp] = 1 << (cs.sps->getBitDepth(CHANNEL_TYPE_CHROMA) - 1);
            }
            else
            {
              curPLTtmp[COMPONENT_Y][pltSizetmp] = 1 << (cs.sps->getBitDepth(CHANNEL_TYPE_LUMA) - 1);
            }
          }
          else
          {
    
          for (int comp = compBegin; comp < (compBegin + numComp); comp++)
          {
    
            curPLTtmp[comp][pltSizetmp] = cu.curPLT[comp][curidx];
    
      assert(pltSizetmp == cu.curPLTSize[compBegin]);
    
      for (int curidx = 0; curidx < cu.curPLTSize[compBegin]; curidx++)
      {
    
        if( cu.isLocalSepTree() )
        {
          for( int comp = COMPONENT_Y; comp < MAX_NUM_COMPONENT; comp++ )
          {
            cu.curPLT[comp][curidx] = curPLTtmp[comp][curidx];
          }
        }
        else
        {
    
        for (int comp = compBegin; comp < (compBegin + numComp); comp++)
        {
          cu.curPLT[comp][curidx] = curPLTtmp[comp][curidx];
        }