Skip to content
Snippets Groups Projects
IntraPrediction.cpp 70.5 KiB
Newer Older
  • Learn to ignore specific revisions
  • void IntraPrediction::xFillReferenceSamples( const CPelBuf &recoBuf, Pel* refBufUnfiltered, const CompArea &area, const CodingUnit &cu )
    {
      const ChannelType      chType = toChannelType( area.compID );
      const CodingStructure &cs     = *cu.cs;
      const SPS             &sps    = *cs.sps;
      const PreCalcValues   &pcv    = *cs.pcv;
    
    
      const int multiRefIdx         = (area.compID == COMPONENT_Y) ? cu.firstPU->multiRefIdx : 0;
    
    
      const int  tuWidth            = area.width;
      const int  tuHeight           = area.height;
      const int  predSize           = m_topRefLength;
      const int  predHSize          = m_leftRefLength;
    
      const int predStride = predSize + 1 + multiRefIdx;
    
      m_refBufferStride[area.compID] = predStride;
    
    
      const bool noShift            = pcv.noChroma2x2 && area.width == 4; // don't shift on the lowest level (chroma not-split)
    
      const int  unitWidth          = tuWidth  <= 2 && cu.ispMode && isLuma(area.compID) ? tuWidth  : pcv.minCUWidth  >> (noShift ? 0 : getComponentScaleX(area.compID, sps.getChromaFormatIdc()));
      const int  unitHeight         = tuHeight <= 2 && cu.ispMode && isLuma(area.compID) ? tuHeight : pcv.minCUHeight >> (noShift ? 0 : getComponentScaleY(area.compID, sps.getChromaFormatIdc()));
    
    
      const int  totalAboveUnits    = (predSize + (unitWidth - 1)) / unitWidth;
      const int  totalLeftUnits     = (predHSize + (unitHeight - 1)) / unitHeight;
      const int  totalUnits         = totalAboveUnits + totalLeftUnits + 1; //+1 for top-left
      const int  numAboveUnits      = std::max<int>( tuWidth / unitWidth, 1 );
      const int  numLeftUnits       = std::max<int>( tuHeight / unitHeight, 1 );
      const int  numAboveRightUnits = totalAboveUnits - numAboveUnits;
      const int  numLeftBelowUnits  = totalLeftUnits - numLeftUnits;
    
      CHECK( numAboveUnits <= 0 || numLeftUnits <= 0 || numAboveRightUnits <= 0 || numLeftBelowUnits <= 0, "Size not supported" );
    
      // ----- Step 1: analyze neighborhood -----
      const Position posLT          = area;
      const Position posRT          = area.topRight();
      const Position posLB          = area.bottomLeft();
    
      bool  neighborFlags[4 * MAX_NUM_PART_IDXS_IN_CTU_WIDTH + 1];
      int   numIntraNeighbor = 0;
    
      memset( neighborFlags, 0, totalUnits );
    
      neighborFlags[totalLeftUnits] = isAboveLeftAvailable( cu, chType, posLT );
      numIntraNeighbor += neighborFlags[totalLeftUnits] ? 1 : 0;
      numIntraNeighbor += isAboveAvailable     ( cu, chType, posLT, numAboveUnits,      unitWidth,  (neighborFlags + totalLeftUnits + 1) );
      numIntraNeighbor += isAboveRightAvailable( cu, chType, posRT, numAboveRightUnits, unitWidth,  (neighborFlags + totalLeftUnits + 1 + numAboveUnits) );
      numIntraNeighbor += isLeftAvailable      ( cu, chType, posLT, numLeftUnits,       unitHeight, (neighborFlags + totalLeftUnits - 1) );
      numIntraNeighbor += isBelowLeftAvailable ( cu, chType, posLB, numLeftBelowUnits,  unitHeight, (neighborFlags + totalLeftUnits - 1 - numLeftUnits) );
    
      // ----- Step 2: fill reference samples (depending on neighborhood) -----
    
      const Pel*  srcBuf    = recoBuf.buf;
      const int   srcStride = recoBuf.stride;
            Pel*  ptrDst    = refBufUnfiltered;
      const Pel*  ptrSrc;
      const Pel   valueDC   = 1 << (sps.getBitDepth( chType ) - 1);
    
    
      if( numIntraNeighbor == 0 )
      {
        // Fill border with DC value
    
        for (int j = 0; j <= predSize + multiRefIdx; j++) { ptrDst[j] = valueDC; }
    
        for (int i = 0; i <= predHSize + multiRefIdx; i++)
        {
          ptrDst[i + predStride] = valueDC;
        }
    
      }
      else if( numIntraNeighbor == totalUnits )
      {
        // Fill top-left border and top and top right with rec. samples
    
        ptrSrc = srcBuf - (1 + multiRefIdx) * srcStride - (1 + multiRefIdx);
        for (int j = 0; j <= predSize + multiRefIdx; j++) { ptrDst[j] = ptrSrc[j]; }
    
        for (int i = 0; i <= predHSize + multiRefIdx; i++)
        {
          ptrDst[i + predStride] = ptrSrc[i * srcStride];
        }
    
        // Fill top-left sample(s) if available
        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))
    
    }
    
    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))
    
        ++numIntra;
        *validFlags = true;
    
    }
    
    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))
    
        ++numIntra;
        *validFlags = true;
    
    }
    
    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))
    
        ++numIntra;
        *validFlags = true;
    
    }
    
    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))
    
        ++numIntra;
        *validFlags = true;
    
    // 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 int mult        =          1 << logSubWidthC ;
    
    
      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);
    
      int availlableUnit = isLeftAvailable( isChroma( pu.chType ) ? cu : lumaCU, toChannelType( area.compID ), area.pos(), iLeftUnits, iUnitHeight,
      ( bNeighborFlags + iLeftUnits + leftBelowUnits - 1 ) );
    
    Karsten Suehring's avatar
    Karsten Suehring committed
      bLeftAvaillable = availlableUnit == iTUHeightInUnits;
    
      availlableUnit = isAboveAvailable( isChroma( pu.chType ) ? cu : lumaCU, toChannelType( area.compID ), area.pos(), iAboveUnits, iUnitWidth,
      ( bNeighborFlags + iLeftUnits + leftBelowUnits + 1 ) );
    
    Karsten Suehring's avatar
    Karsten Suehring committed
      bAboveAvaillable = availlableUnit == iTUWidthInUnits;
    
    
      if (bLeftAvaillable) // 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 (bAboveAvaillable) // 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;
    
      const int strOffset = (CHROMA_444 == pu.chromaFormat) ? 0 : iRecStride;
    
      int c0_2tap = 1, c1_2tap = 1,                                                     offset_2tap = 1, shift_2tap = 1; //sum = 2
      int c0_3tap = 2, c1_3tap = 1, c2_3tap = 1,                                        offset_3tap = 2, shift_3tap = 2; //sum = 4
      int c0_5tap = 1, c1_5tap = 4, c2_5tap = 1, c3_5tap = 1, c4_5tap = 1,              offset_5tap = 4, shift_5tap = 3; //sum = 8
      int c0_6tap = 2, c1_6tap = 1, c2_6tap = 1, c3_6tap = 2, c4_6tap = 1, c5_6tap = 1, offset_6tap = 4, shift_6tap = 3; //sum = 8
    
      switch (pu.chromaFormat)
      {
        case CHROMA_422: //overwrite filter coefficient values for 422
          c0_2tap = 1, c1_2tap = 0,                                                     offset_2tap = 0, shift_2tap = 0; //sum = 1
          c0_3tap = 2, c1_3tap = 1, c2_3tap = 1,                                        offset_3tap = 2, shift_3tap = 2; //sum = 4
          c0_5tap = 0, c1_5tap = 1, c2_5tap = 0, c3_5tap = 0, c4_5tap = 0,              offset_5tap = 0, shift_5tap = 0; //sum = 1
          c0_6tap = 2, c1_6tap = 1, c2_6tap = 1, c3_6tap = 0, c4_6tap = 0, c5_6tap = 0, offset_6tap = 2, shift_6tap = 2; //sum = 4
          break;
    
        case CHROMA_444:  //overwrite filter coefficient values for 422
          c0_2tap = 1, c1_2tap = 0,                                                     offset_2tap = 0, shift_2tap = 0; //sum = 1
          c0_3tap = 1, c1_3tap = 0, c2_3tap = 0,                                        offset_3tap = 0, shift_3tap = 0; //sum = 1
          c0_5tap = 0, c1_5tap = 1, c2_5tap = 0, c3_5tap = 0, c4_5tap = 0,              offset_5tap = 0, shift_5tap = 0; //sum = 1
          c0_6tap = 1, c1_6tap = 0, c2_6tap = 0, c3_6tap = 0, c4_6tap = 0, c5_6tap = 0, offset_6tap = 0, shift_6tap = 0; //sum = 1
          break;
    
        default:
          break;
      }
    
        int addedAboveRight = 0;
        if ((curChromaMode == MDLM_L_IDX) || (curChromaMode == MDLM_T_IDX))
        {
          addedAboveRight = avaiAboveRightUnits*chromaUnitWidth;
        }
        for (int i = 0; i < uiCWidth + addedAboveRight; i++)
    
            if ((i == 0 && !bLeftAvaillable) || (i == uiCWidth + addedAboveRight - 1 + logSubWidthC))
    
              pDst[i] = (piSrc[mult * i] * c0_3tap + piSrc[mult * i - 1] * c1_3tap + piSrc[mult * i + 1] * c2_3tap + offset_3tap) >> shift_3tap;
    
          else if( pu.cs->sps->getCclmCollocatedChromaFlag() )
    
    Philippe Hanhart's avatar
    Philippe Hanhart committed
          {
            piSrc = pRecSrc0 - iRecStride2;
    
            if ((i == 0 && !bLeftAvaillable) || (i == uiCWidth + addedAboveRight - 1 + logSubWidthC))
    
    Philippe Hanhart's avatar
    Philippe Hanhart committed
            {
    
              pDst[i] = (piSrc[mult * i] * c0_3tap + piSrc[mult * i - strOffset] * c1_3tap + piSrc[mult * i + strOffset] * c2_3tap + offset_3tap) >> shift_3tap;
    
    Philippe Hanhart's avatar
    Philippe Hanhart committed
            }
            else
            {
    
              pDst[i] = (piSrc[mult * i - strOffset] * c0_5tap
                      +  piSrc[mult * i]             * c1_5tap + piSrc[mult * i - 1] * c2_5tap + piSrc[mult * i + 1] * c3_5tap
                      +  piSrc[mult * i + strOffset] * c4_5tap
                      +  offset_5tap) >> shift_5tap;
    
    Philippe Hanhart's avatar
    Philippe Hanhart committed
            }
          }
    
            if ((i == 0 && !bLeftAvaillable) || (i == uiCWidth + addedAboveRight - 1 + logSubWidthC))
    
              pDst[i] = (piSrc[mult * i] * c0_2tap + piSrc[mult * i + strOffset] * c1_2tap + offset_2tap) >> shift_2tap;
    
              pDst[i] = ((piSrc[mult * i]            * c0_6tap + piSrc[mult * i - 1]             * c1_6tap + piSrc[mult * i + 1]             * c2_6tap)
                      + (piSrc[mult * i + strOffset] * c3_6tap + piSrc[mult * i - 1 + strOffset] * c4_6tap + piSrc[mult * i + 1 + strOffset] * c5_6tap)
                      + offset_6tap) >> shift_6tap;
    
        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.cs->sps->getCclmCollocatedChromaFlag() )
    
    Philippe Hanhart's avatar
    Philippe Hanhart committed
          {
    
            if ((j == 0 && !bAboveAvaillable) || (j == uiCHeight + addedLeftBelow - 1 + logSubWidthC))
            {
              pDst[0] = ( piSrc[1] * c0_3tap + piSrc[0] * c1_3tap + piSrc[2] * c2_3tap + offset_3tap) >> shift_3tap;
    
    Philippe Hanhart's avatar
    Philippe Hanhart committed
            }
            else
            {
    
              pDst[0] = ( piSrc[1 - strOffset] * c0_5tap
                        + piSrc[1            ] * c1_5tap + piSrc[0] * c2_5tap + piSrc[2] * c3_5tap
                        + piSrc[1 + strOffset] * c4_5tap
                        + offset_5tap ) >> shift_5tap;
    
            pDst[0] = ((piSrc[1]             * c0_6tap + piSrc[0]         * c1_6tap + piSrc[2]             * c2_6tap)
                    +  (piSrc[1 + strOffset] * c3_6tap + piSrc[strOffset] * c4_6tap + piSrc[2 + strOffset] * c5_6tap)
                    +   offset_6tap) >> shift_6tap;
    
    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.cs->sps->getCclmCollocatedChromaFlag() )
    
    Philippe Hanhart's avatar
    Philippe Hanhart committed
            if( i == 0 && !bLeftAvaillable )
            {
    
              if ( j == 0 && !bAboveAvaillable )
    
    Philippe Hanhart's avatar
    Philippe Hanhart committed
              {
    
                pDst0[i] = pRecSrc0[mult * i];
    
    Philippe Hanhart's avatar
    Philippe Hanhart committed
              }
              else
              {
    
                pDst0[i] = (pRecSrc0[mult * i] * c0_3tap + pRecSrc0[mult * i - strOffset] * c1_3tap + pRecSrc0[mult * i + strOffset] * c2_3tap + offset_3tap) >> shift_3tap;
    
    Philippe Hanhart's avatar
    Philippe Hanhart committed
              }
            }
    
            else if ( j == 0 && !bAboveAvaillable )
    
    Philippe Hanhart's avatar
    Philippe Hanhart committed
            {
    
              pDst0[i] = (pRecSrc0[mult * i] * c0_3tap + pRecSrc0[mult * i - 1] * c1_3tap + pRecSrc0[mult * i + 1] * c2_3tap + offset_3tap) >> shift_3tap;
    
    Philippe Hanhart's avatar
    Philippe Hanhart committed
            }
            else
            {
    
              pDst0[i] = (pRecSrc0[mult * i - strOffset] * c0_5tap
                       +  pRecSrc0[mult * i]             * c1_5tap + pRecSrc0[mult * i - 1] * c2_5tap + pRecSrc0[mult * i + 1] * c3_5tap
                       +  pRecSrc0[mult * i + strOffset] * c4_5tap
                       +  offset_5tap) >> shift_5tap;
    
    Philippe Hanhart's avatar
    Philippe Hanhart committed
            }
    
    
            if ((i == 0 && !bLeftAvaillable) || (i == uiCWidth - 1 + logSubWidthC))
    
    Philippe Hanhart's avatar
    Philippe Hanhart committed
            {
    
              pDst0[i] = (pRecSrc0[mult * i] * c0_2tap + pRecSrc0[mult * i + strOffset] * c1_2tap + offset_2tap) >> shift_2tap;
    
    Philippe Hanhart's avatar
    Philippe Hanhart committed
            }
            else
            {
    
              int s = offset_6tap;
              s += pRecSrc0[mult * i] * c0_6tap;
              s += pRecSrc0[mult * i + 1] * c1_6tap;
              s += pRecSrc0[mult * i - 1] * c2_6tap;
              if (pu.chromaFormat == CHROMA_420)
              {
                s += pRecSrc0[mult * i + strOffset] * c3_6tap;
                s += pRecSrc0[mult * i + 1 + strOffset] * c4_6tap;
                s += pRecSrc0[mult * i - 1 + strOffset] * c5_6tap;
              }
              pDst0[i] = s >> shift_6tap;
    
    Philippe Hanhart's avatar
    Philippe Hanhart committed
            }
    
    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;
        }
    
    #if JVET_P0803_COMBINED_MIP_CLEANUP
    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( COMPONENT_Y );
      const int srcStride  = m_refBufferStride[COMPONENT_Y];
      const int srcHStride = 2;
    
      m_matrixIntraPred.prepareInputForPred( CPelBuf( ptrSrc, srcStride, srcHStride ), area, pu.cu->slice->getSPS()->getBitDepth( CHANNEL_TYPE_LUMA ) );
    }
    #else
    
    void IntraPrediction::initIntraMip( const PredictionUnit &pu )
    {
    
      CHECK( pu.lwidth() > pu.cs->sps->getMaxTbSize() || pu.lheight() > pu.cs->sps->getMaxTbSize(), "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(COMPONENT_Y);
    
      const int srcStride  = m_refBufferStride[COMPONENT_Y];
      const int srcHStride = 2;
    
    
      m_matrixIntraPred.prepareInputForPred(CPelBuf(ptrSrc, srcStride, srcHStride), pu.Y(), pu.cu->slice->getSPS()->getBitDepth(CHANNEL_TYPE_LUMA));
    
    
    void IntraPrediction::predIntraMip( const ComponentID compId, PelBuf &piPred, const PredictionUnit &pu )
    {
      CHECK( compId != COMPONENT_Y, "Error: chroma not supported" );
    
    #if JVET_P0803_COMBINED_MIP_CLEANUP
      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
      const int bitDepth = pu.cu->slice->getSPS()->getBitDepth( CHANNEL_TYPE_LUMA );
    
      static_vector<int, MIP_MAX_WIDTH* MIP_MAX_HEIGHT> predMip( piPred.width * piPred.height );
      m_matrixIntraPred.predBlock( predMip.data(), pu.intraDir[CHANNEL_TYPE_LUMA], pu.mipTransposedFlag, bitDepth );
    
      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]);
        }
      }
    #else
    
      CHECK( pu.lwidth() > pu.cs->sps->getMaxTbSize() || pu.lheight() > pu.cs->sps->getMaxTbSize(), "Error: block size not supported for MIP" );
    
      CHECK( pu.lwidth() != (1 << floorLog2(pu.lwidth())) || pu.lheight() != (1 << floorLog2(pu.lheight())), "Error: expecting blocks of size 2^M x 2^N" );
    
    
      // generate mode-specific prediction
      const int bitDepth = pu.cu->slice->getSPS()->getBitDepth(CHANNEL_TYPE_LUMA);
    
      static_vector<int, MIP_MAX_WIDTH * MIP_MAX_HEIGHT> predMip(pu.Y().area());
      m_matrixIntraPred.predBlock(predMip.data(), pu.intraDir[CHANNEL_TYPE_LUMA], bitDepth);
    
      for (int y = 0; y < pu.lheight(); y++)
      {
        for (int x = 0; x < pu.lwidth(); x++)
        {
          piPred.at(x, y) = Pel(predMip[y * pu.lwidth() + x]);
        }
      }
    
    #if !JVET_P0077_LINE_CG_PALETTE
    
    bool IntraPrediction::calCopyRun(CodingStructure &cs, Partitioner& partitioner, uint32_t startPos, uint32_t total, uint32_t &run, ComponentID compBegin)
    
      CodingUnit    &cu = *cs.getCU(partitioner.chType);
    
      TransformUnit &tu = *cs.getTU(partitioner.chType);
    
      PelBuf     curPLTIdx = tu.getcurPLTIdx(compBegin);
      PLTtypeBuf runType   = tu.getrunType(compBegin);
    
      uint32_t idx = startPos;
      uint32_t xPos;
      uint32_t yPos;
    
      run = 0;
      while (idx < total)
    
    Yung-Hsuan Chao (Jessie)'s avatar
    Yung-Hsuan Chao (Jessie) committed
        xPos = m_scanOrder[idx].x;
        yPos = m_scanOrder[idx].y;
    
        runType.at(xPos, yPos) = PLT_RUN_COPY;
    
        if (yPos == 0 && !cu.useRotation[compBegin])
    
        if (xPos == 0 && cu.useRotation[compBegin])
    
        if (!cu.useRotation[compBegin] && curPLTIdx.at(xPos, yPos) == curPLTIdx.at(xPos, yPos - 1))
    
        else if (cu.useRotation[compBegin] && curPLTIdx.at(xPos, yPos) == curPLTIdx.at(xPos - 1, yPos))