Skip to content
Snippets Groups Projects
UnitTools.cpp 174 KiB
Newer Older
  • Learn to ignore specific revisions
  • /* The copyright in this software is being made available under the BSD
     * License, included below. This software may be subject to other third party
     * and contributor rights, including patent rights, and no such rights are
     * granted under this license.
     *
    
     * Copyright (c) 2010-2019, ITU/ISO/IEC
    
     * All rights reserved.
     *
     * Redistribution and use in source and binary forms, with or without
     * modification, are permitted provided that the following conditions are met:
     *
     *  * Redistributions of source code must retain the above copyright notice,
     *    this list of conditions and the following disclaimer.
     *  * Redistributions in binary form must reproduce the above copyright notice,
     *    this list of conditions and the following disclaimer in the documentation
     *    and/or other materials provided with the distribution.
     *  * Neither the name of the ITU/ISO/IEC nor the names of its contributors may
     *    be used to endorse or promote products derived from this software without
     *    specific prior written permission.
     *
     * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
     * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
     * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
     * THE POSSIBILITY OF SUCH DAMAGE.
     */
    
    /** \file     UnitTool.cpp
     *  \brief    defines operations for basic units
     */
    
    #include "UnitTools.h"
    
    #include "dtrace_next.h"
    
    #include "Unit.h"
    #include "Slice.h"
    #include "Picture.h"
    
    #include <utility>
    #include <algorithm>
    
    // CS tools
    
    
    uint64_t CS::getEstBits(const CodingStructure &cs)
    {
      return cs.fracBits >> SCALE_BITS;
    }
    
    
    
    bool CS::isDualITree( const CodingStructure &cs )
    {
    
      return cs.slice->isIRAP() && !cs.pcv->ISingleTree;
    
    }
    
    UnitArea CS::getArea( const CodingStructure &cs, const UnitArea &area, const ChannelType chType )
    {
      return isDualITree( cs ) ? area.singleChan( chType ) : area;
    }
    
    void CS::setRefinedMotionField(CodingStructure &cs)
    {
      for (CodingUnit *cu : cs.cus)
      {
        for (auto &pu : CU::traversePUs(*cu))
        {
          PredictionUnit subPu = pu;
          int dx, dy, x, y, num = 0;
          dy = std::min<int>(pu.lumaSize().height, DMVR_SUBCU_HEIGHT);
          dx = std::min<int>(pu.lumaSize().width, DMVR_SUBCU_WIDTH);
    
          Position puPos = pu.lumaPos();
    
          if (PU::checkDMVRCondition(pu))
          {
            for (y = puPos.y; y < (puPos.y + pu.lumaSize().height); y = y + dy)
            {
              for (x = puPos.x; x < (puPos.x + pu.lumaSize().width); x = x + dx)
              {
                subPu.UnitArea::operator=(UnitArea(pu.chromaFormat, Area(x, y, dx, dy)));
                subPu.mv[0] = pu.mv[0];
                subPu.mv[1] = pu.mv[1];
                subPu.mv[REF_PIC_LIST_0] += pu.mvdL0SubPu[num];
                subPu.mv[REF_PIC_LIST_1] -= pu.mvdL0SubPu[num];
    
    #if JVET_N0334_MVCLIPPING
                subPu.mv[REF_PIC_LIST_0].clipToStorageBitDepth();
                subPu.mv[REF_PIC_LIST_1].clipToStorageBitDepth();
    #endif
    
                pu.mvdL0SubPu[num].setZero();
                num++;
                PU::spanMotionInfo(subPu);
              }
            }
          }
        }
    
    // CU tools
    
    bool CU::isIntra(const CodingUnit &cu)
    {
      return cu.predMode == MODE_INTRA;
    }
    
    bool CU::isInter(const CodingUnit &cu)
    {
      return cu.predMode == MODE_INTER;
    }
    
    
    Yu Han's avatar
    Yu Han committed
    bool CU::isIBC(const CodingUnit &cu)
    {
      return cu.predMode == MODE_IBC;
    }
    
    
    bool CU::isRDPCMEnabled(const CodingUnit& cu)
    {
      return cu.cs->sps->getSpsRangeExtension().getRdpcmEnabledFlag(cu.predMode == MODE_INTRA ? RDPCM_SIGNAL_IMPLICIT : RDPCM_SIGNAL_EXPLICIT);
    }
    
    bool CU::isLosslessCoded(const CodingUnit &cu)
    {
      return cu.cs->pps->getTransquantBypassEnabledFlag() && cu.transQuantBypass;
    }
    
    bool CU::isSameSlice(const CodingUnit& cu, const CodingUnit& cu2)
    {
      return cu.slice->getIndependentSliceIdx() == cu2.slice->getIndependentSliceIdx();
    }
    
    bool CU::isSameTile(const CodingUnit& cu, const CodingUnit& cu2)
    {
      return cu.tileIdx == cu2.tileIdx;
    }
    
    bool CU::isSameSliceAndTile(const CodingUnit& cu, const CodingUnit& cu2)
    {
      return ( cu.slice->getIndependentSliceIdx() == cu2.slice->getIndependentSliceIdx() ) && ( cu.tileIdx == cu2.tileIdx );
    }
    
    bool CU::isSameCtu(const CodingUnit& cu, const CodingUnit& cu2)
    {
      uint32_t ctuSizeBit = g_aucLog2[cu.cs->sps->getMaxCUWidth()];
    
      Position pos1Ctu(cu.lumaPos().x  >> ctuSizeBit, cu.lumaPos().y  >> ctuSizeBit);
      Position pos2Ctu(cu2.lumaPos().x >> ctuSizeBit, cu2.lumaPos().y >> ctuSizeBit);
    
      return pos1Ctu.x == pos2Ctu.x && pos1Ctu.y == pos2Ctu.y;
    }
    
    uint32_t CU::getIntraSizeIdx(const CodingUnit &cu)
    {
      uint8_t uiWidth = cu.lumaSize().width;
    
      uint32_t  uiCnt   = 0;
    
      while (uiWidth)
      {
        uiCnt++;
        uiWidth >>= 1;
      }
    
      uiCnt -= 2;
    
      return uiCnt > 6 ? 6 : uiCnt;
    }
    
    bool CU::isLastSubCUOfCtu( const CodingUnit &cu )
    {
      const SPS &sps      = *cu.cs->sps;
      const Area cuAreaY = CS::isDualITree( *cu.cs ) ? Area( recalcPosition( cu.chromaFormat, cu.chType, CHANNEL_TYPE_LUMA, cu.blocks[cu.chType].pos() ), recalcSize( cu.chromaFormat, cu.chType, CHANNEL_TYPE_LUMA, cu.blocks[cu.chType].size() ) ) : ( const Area& ) cu.Y();
    
      return ( ( ( ( cuAreaY.x + cuAreaY.width  ) & cu.cs->pcv->maxCUWidthMask  ) == 0 || cuAreaY.x + cuAreaY.width  == sps.getPicWidthInLumaSamples()  ) &&
               ( ( ( cuAreaY.y + cuAreaY.height ) & cu.cs->pcv->maxCUHeightMask ) == 0 || cuAreaY.y + cuAreaY.height == sps.getPicHeightInLumaSamples() ) );
    }
    
    uint32_t CU::getCtuAddr( const CodingUnit &cu )
    {
      return getCtuAddr( cu.blocks[cu.chType].lumaPos(), *cu.cs->pcv );
    }
    
    int CU::predictQP( const CodingUnit& cu, const int prevQP )
    {
      const CodingStructure &cs = *cu.cs;
    
    
      if ( !cu.blocks[cu.chType].x && !( cu.blocks[cu.chType].y & ( cs.pcv->maxCUHeightMask >> getChannelTypeScaleY( cu.chType, cu.chromaFormat ) ) ) && ( cs.getCU( cu.blocks[cu.chType].pos().offset( 0, -1 ), cu.chType) != NULL ) )
      {
        return ( ( cs.getCU( cu.blocks[cu.chType].pos().offset( 0, -1 ), cu.chType ) )->qp );
      }
      else
      {
        const int a = ( cu.blocks[cu.chType].y & ( cs.pcv->maxCUHeightMask >> getChannelTypeScaleY( cu.chType, cu.chromaFormat ) ) ) ? ( cs.getCU(cu.blocks[cu.chType].pos().offset( 0, -1 ), cu.chType))->qp : prevQP;
        const int b = ( cu.blocks[cu.chType].x & ( cs.pcv->maxCUWidthMask  >> getChannelTypeScaleX( cu.chType, cu.chromaFormat ) ) ) ? ( cs.getCU(cu.blocks[cu.chType].pos().offset( -1, 0 ), cu.chType))->qp : prevQP;
    
        return ( a + b + 1 ) >> 1;
      }
    
    }
    
    
    uint32_t CU::getNumPUs( const CodingUnit& cu )
    {
      uint32_t cnt = 0;
      PredictionUnit *pu = cu.firstPU;
    
      do
      {
        cnt++;
      } while( ( pu != cu.lastPU ) && ( pu = pu->next ) );
    
      return cnt;
    }
    
    void CU::addPUs( CodingUnit& cu )
    {
      cu.cs->addPU( CS::getArea( *cu.cs, cu, cu.chType ), cu.chType );
    }
    
    
    PartSplit CU::getSplitAtDepth( const CodingUnit& cu, const unsigned depth )
    {
      if( depth >= cu.depth ) return CU_DONT_SPLIT;
    
      const PartSplit cuSplitType = PartSplit( ( cu.splitSeries >> ( depth * SPLIT_DMULT ) ) & SPLIT_MASK );
    
      if     ( cuSplitType == CU_QUAD_SPLIT    ) return CU_QUAD_SPLIT;
    
      else if( cuSplitType == CU_HORZ_SPLIT    ) return CU_HORZ_SPLIT;
    
      else if( cuSplitType == CU_VERT_SPLIT    ) return CU_VERT_SPLIT;
    
      else if( cuSplitType == CU_TRIH_SPLIT    ) return CU_TRIH_SPLIT;
      else if( cuSplitType == CU_TRIV_SPLIT    ) return CU_TRIV_SPLIT;
      else   { THROW( "Unknown split mode"    ); return CU_QUAD_SPLIT; }
    }
    
    bool CU::hasNonTsCodedBlock( const CodingUnit& cu )
    {
      bool hasAnyNonTSCoded = false;
    
      for( auto &currTU : traverseTUs( cu ) )
      {
        for( uint32_t i = 0; i < ::getNumberValidTBlocks( *cu.cs->pcv ); i++ )
        {
    
    Tung Nguyen's avatar
    Tung Nguyen committed
          hasAnyNonTSCoded |= ( currTU.blocks[i].valid() && ( isLuma(ComponentID(i)) ? currTU.mtsIdx != 1 : true ) && TU::getCbf( currTU, ComponentID( i ) ) );
    
        }
      }
    
      return hasAnyNonTSCoded;
    }
    
    uint32_t CU::getNumNonZeroCoeffNonTs( const CodingUnit& cu )
    {
      uint32_t count = 0;
      for( auto &currTU : traverseTUs( cu ) )
      {
        count += TU::getNumNonZeroCoeffsNonTS( currTU );
      }
    
      return count;
    }
    
    
    bool CU::divideTuInRows( const CodingUnit &cu )
    {
      CHECK( cu.ispMode != HOR_INTRA_SUBPARTITIONS && cu.ispMode != VER_INTRA_SUBPARTITIONS, "Intra Subpartitions type not recognized!" );
      return cu.ispMode == HOR_INTRA_SUBPARTITIONS ? true : false;
    }
    
    bool CU::firstTestISPHorSplit( const int width, const int height, const ComponentID compID, const CodingUnit *cuLeft, const CodingUnit *cuAbove )
    {
      //this function decides which split mode (horizontal or vertical) is tested first (encoder only)
      //we check the logarithmic aspect ratios of the block
      int aspectRatio = g_aucLog2[width] - g_aucLog2[height];
      if( aspectRatio > 0 )
      {
        return true;
      }
      else if( aspectRatio < 0 )
      {
        return false;
      }
      else //if (aspectRatio == 0)
      {
        //we gather data from the neighboring CUs
        const int cuLeftWidth    = cuLeft  != nullptr                                    ? cuLeft->blocks[compID].width   : -1;
        const int cuLeftHeight   = cuLeft  != nullptr                                    ? cuLeft->blocks[compID].height  : -1;
        const int cuAboveWidth   = cuAbove != nullptr                                    ? cuAbove->blocks[compID].width  : -1;
        const int cuAboveHeight  = cuAbove != nullptr                                    ? cuAbove->blocks[compID].height : -1;
        const int cuLeft1dSplit  = cuLeft  != nullptr &&  cuLeft->predMode == MODE_INTRA ? cuLeft->ispMode                :  0;
        const int cuAbove1dSplit = cuAbove != nullptr && cuAbove->predMode == MODE_INTRA ? cuAbove->ispMode               :  0;
        if( cuLeftWidth != -1 && cuAboveWidth == -1 )
        {
          int cuLeftAspectRatio = g_aucLog2[cuLeftWidth] - g_aucLog2[cuLeftHeight];
          return cuLeftAspectRatio < 0 ? false : cuLeftAspectRatio > 0 ? true : cuLeft1dSplit == VER_INTRA_SUBPARTITIONS ? false : true;
        }
        else if( cuLeftWidth == -1 && cuAboveWidth != -1 )
        {
          int cuAboveAspectRatio = g_aucLog2[cuAboveWidth] - g_aucLog2[cuAboveHeight];
          return cuAboveAspectRatio < 0 ? false : cuAboveAspectRatio > 0 ? true : cuAbove1dSplit == VER_INTRA_SUBPARTITIONS ? false : true;
        }
        else if( cuLeftWidth != -1 && cuAboveWidth != -1 )
        {
          int cuLeftAspectRatio = g_aucLog2[cuLeftWidth] - g_aucLog2[cuLeftHeight];
          int cuAboveAspectRatio = g_aucLog2[cuAboveWidth] - g_aucLog2[cuAboveHeight];
          if( cuLeftAspectRatio < 0 && cuAboveAspectRatio < 0 )
          {
            return false;
          }
          else if( cuLeftAspectRatio > 0 && cuAboveAspectRatio > 0 )
          {
            return true;
          }
          else if( cuLeftAspectRatio == 0 && cuAboveAspectRatio == 0 )
          {
            if( cuLeft1dSplit != 0 && cuAbove1dSplit != 0 )
            {
              return cuLeft1dSplit == VER_INTRA_SUBPARTITIONS && cuAbove1dSplit == VER_INTRA_SUBPARTITIONS ? false : true;
            }
            else if( cuLeft1dSplit != 0 && cuAbove1dSplit == 0 )
            {
              return cuLeft1dSplit == VER_INTRA_SUBPARTITIONS ? false : true;
            }
            else if( cuLeft1dSplit == 0 && cuAbove1dSplit != 0 )
            {
              return cuAbove1dSplit == VER_INTRA_SUBPARTITIONS ? false : true;
            }
            return true;
          }
          else
          {
            return cuLeftAspectRatio > cuAboveAspectRatio ? cuLeftAspectRatio > 0 : cuAboveAspectRatio > 0;
          }
          //return true;
        }
        return true;
      }
    }
    
    PartSplit CU::getISPType( const CodingUnit &cu, const ComponentID compID )
    {
      if( cu.ispMode && isLuma( compID ) )
      {
        const bool tuIsDividedInRows = CU::divideTuInRows( cu );
    
        return tuIsDividedInRows ? TU_1D_HORZ_SPLIT : TU_1D_VERT_SPLIT;
      }
      return TU_NO_ISP;
    }
    
    bool CU::isISPLast( const CodingUnit &cu, const CompArea &tuArea, const ComponentID compID )
    {
      PartSplit partitionType = CU::getISPType( cu, compID );
    
      Area originalArea = cu.blocks[compID];
      switch( partitionType )
      {
        case TU_1D_HORZ_SPLIT:
          return tuArea.y + tuArea.height == originalArea.y + originalArea.height;
        case TU_1D_VERT_SPLIT:
          return tuArea.x + tuArea.width == originalArea.x + originalArea.width;
        default:
          THROW( "Unknown ISP processing order type!" );
          return false;
      }
    }
    
    bool CU::isISPFirst( const CodingUnit &cu, const CompArea &tuArea, const ComponentID compID )
    {
      return tuArea == cu.firstTU->blocks[compID];
    }
    
    ISPType CU::canUseISPSplit( const CodingUnit &cu, const ComponentID compID )
    {
      const int width     = cu.blocks[compID].width;
      const int height    = cu.blocks[compID].height;
    
    #if MAX_TB_SIZE_SIGNALLING
      const int maxTrSize = cu.cs->sps->getMaxTbSize();
    #else
      const int maxTrSize = MAX_TB_SIZEY;
    #endif
    
      return CU::canUseISPSplit( width, height, maxTrSize );
    }
    
    ISPType CU::canUseISPSplit( const int width, const int height, const int maxTrSize )
    {
      bool widthCannotBeUsed = false, heightCannotBeUsed = false;
    
    
      const uint32_t minTuSizeForISP = MIN_TB_SIZEY;
    
      bool  notEnoughSamplesToSplit = ( g_aucLog2[width] + g_aucLog2[height] <= ( g_aucLog2[minTuSizeForISP] << 1 ) );
      widthCannotBeUsed  = width  > maxTrSize || notEnoughSamplesToSplit;
      heightCannotBeUsed = height > maxTrSize || notEnoughSamplesToSplit;
    
      if( !widthCannotBeUsed && !heightCannotBeUsed )
      {
        return CAN_USE_VER_AND_HORL_SPLITS; //both splits can be used
      }
      else if( widthCannotBeUsed && !heightCannotBeUsed )
      {
        return VER_INTRA_SUBPARTITIONS; //only the vertical split can be performed
      }
      else if( !widthCannotBeUsed && heightCannotBeUsed )
      {
        return HOR_INTRA_SUBPARTITIONS; //only the horizontal split can be performed
      }
      else
      {
        return NOT_INTRA_SUBPARTITIONS; //neither of the splits can be used
      }
    }
    
    uint32_t CU::getISPSplitDim( const int width, const int height, const PartSplit ispType )
    {
      bool divideTuInRows = ispType == TU_1D_HORZ_SPLIT;
      uint32_t splitDimensionSize, nonSplitDimensionSize, partitionSize, divShift = 2;
    
      if( divideTuInRows )
      {
        splitDimensionSize    = height;
        nonSplitDimensionSize = width;
      }
      else
      {
        splitDimensionSize    = width;
        nonSplitDimensionSize = height;
      }
    
      const int minNumberOfSamplesPerCu = 1 << ( ( g_aucLog2[MIN_TB_SIZEY] << 1 ) );
    
      const int factorToMinSamples = nonSplitDimensionSize < minNumberOfSamplesPerCu ? minNumberOfSamplesPerCu >> g_aucLog2[nonSplitDimensionSize] : 1;
      partitionSize = ( splitDimensionSize >> divShift ) < factorToMinSamples ? factorToMinSamples : ( splitDimensionSize >> divShift );
    
      CHECK( g_aucLog2[partitionSize] + g_aucLog2[nonSplitDimensionSize] < g_aucLog2[minNumberOfSamplesPerCu], "A partition has less than the minimum amount of samples!" );
      return partitionSize;
    }
    
    
    
    PUTraverser CU::traversePUs( CodingUnit& cu )
    {
      return PUTraverser( cu.firstPU, cu.lastPU->next );
    }
    
    TUTraverser CU::traverseTUs( CodingUnit& cu )
    {
      return TUTraverser( cu.firstTU, cu.lastTU->next );
    }
    
    cPUTraverser CU::traversePUs( const CodingUnit& cu )
    {
      return cPUTraverser( cu.firstPU, cu.lastPU->next );
    }
    
    cTUTraverser CU::traverseTUs( const CodingUnit& cu )
    {
      return cTUTraverser( cu.firstTU, cu.lastTU->next );
    }
    
    // PU tools
    
    int PU::getIntraMPMs( const PredictionUnit &pu, unsigned* mpm, const ChannelType &channelType /*= CHANNEL_TYPE_LUMA*/ )
    {
    
      const int numMPMs = NUM_MOST_PROBABLE_MODES;
    
    #if !JVET_N0185_UNIFIED_MPM
    
      const int extendRefLine = (channelType == CHANNEL_TYPE_LUMA) ? pu.multiRefIdx : 0;
    
      const ISPType ispType = isLuma( channelType ) ? ISPType( pu.cu->ispMode ) : NOT_INTRA_SUBPARTITIONS;
      const bool isHorSplit = ispType == HOR_INTRA_SUBPARTITIONS;
    
    ling's avatar
    ling committed
        int leftIntraDir = PLANAR_IDX, aboveIntraDir = PLANAR_IDX;
    
        const CompArea &area = pu.block(getFirstComponentOfChannel(channelType));
        const Position posRT = area.topRight();
        const Position posLB = area.bottomLeft();
    
        // Get intra direction of left PU
        const PredictionUnit *puLeft = pu.cs->getPURestricted(posLB.offset(-1, 0), pu, channelType);
        if (puLeft && CU::isIntra(*puLeft->cu))
        {
          leftIntraDir = puLeft->intraDir[channelType];
        }
    
        // Get intra direction of above PU
        const PredictionUnit *puAbove = pu.cs->getPURestricted(posRT.offset(0, -1), pu, channelType);
        if (puAbove && CU::isIntra(*puAbove->cu) && CU::isSameCtu(*pu.cu, *puAbove->cu))
        {
          aboveIntraDir = puAbove->intraDir[channelType];
        }
    
        CHECK(2 >= numMPMs, "Invalid number of most probable modes");
    
    
        const int offset = (int)NUM_LUMA_MODE - 6;
    
    ling's avatar
    ling committed
        const int mod = offset + 3;
    
    
    #if !JVET_N0185_UNIFIED_MPM
    
        if (extendRefLine)
    
          int modeIdx = 0;
          int angularMode[2] = { 0, 0 };
    
    
    ling's avatar
    ling committed
          if (leftIntraDir > DC_IDX)
          {
    
            angularMode[modeIdx++] = leftIntraDir;
          }
    
          if (aboveIntraDir > DC_IDX && aboveIntraDir != leftIntraDir)
    
          {
            angularMode[modeIdx++] = aboveIntraDir;
          }
          if (modeIdx == 0)
          {
            mpm[0] = VER_IDX;
            mpm[1] = HOR_IDX;
            mpm[2] = 2;
            mpm[3] = DIA_IDX;
            mpm[4] = VDIA_IDX;
            mpm[5] = 26;
          }
          else if (modeIdx == 1)
          {
            mpm[0] = angularMode[0];
            mpm[1] = ((angularMode[0] + offset) % mod) + 2;
            mpm[2] = ((angularMode[0] - 1) % mod) + 2;
            mpm[3] = ((angularMode[0] + offset - 1) % mod) + 2;
            mpm[4] = (angularMode[0] % mod) + 2;
            mpm[5] = ((angularMode[0] + offset - 2) % mod) + 2;
          }
          else
          {
            mpm[0] = angularMode[0];
            mpm[1] = angularMode[1];
            int maxCandModeIdx = mpm[0] > mpm[1] ? 0 : 1;
            int minCandModeIdx = 1 - maxCandModeIdx;
            if (mpm[maxCandModeIdx] - mpm[minCandModeIdx] == 1)
            {
              mpm[2] = ((angularMode[minCandModeIdx] + offset) % mod) + 2;
              mpm[3] = ((angularMode[maxCandModeIdx] - 1) % mod) + 2;
              mpm[4] = ((angularMode[minCandModeIdx] + offset - 1) % mod) + 2;
              mpm[5] = ( angularMode[maxCandModeIdx] % mod) + 2;
            }
            else if (mpm[maxCandModeIdx] - mpm[minCandModeIdx] >= 62)
            {
              mpm[2] = ((angularMode[minCandModeIdx] - 1) % mod) + 2;
              mpm[3] = ((angularMode[maxCandModeIdx] + offset) % mod) + 2;
              mpm[4] = ((angularMode[minCandModeIdx]) % mod) + 2;
              mpm[5] = ((angularMode[maxCandModeIdx] + offset - 1) % mod) + 2;
            }
            else if (mpm[maxCandModeIdx] - mpm[minCandModeIdx] == 2)
            {
              mpm[2] = ((angularMode[minCandModeIdx] - 1) % mod) + 2;
              mpm[3] = ((angularMode[minCandModeIdx] + offset) % mod) + 2;
              mpm[4] = ((angularMode[maxCandModeIdx] - 1) % mod) + 2;
              mpm[5] = ((angularMode[minCandModeIdx] + offset - 1) % mod) + 2;
            }
            else
            {
              mpm[2] = ((angularMode[minCandModeIdx] + offset) % mod) + 2;
              mpm[3] = ((angularMode[minCandModeIdx] - 1) % mod) + 2;
              mpm[4] = ((angularMode[maxCandModeIdx] + offset) % mod) + 2;
              mpm[5] = ((angularMode[maxCandModeIdx] - 1) % mod) + 2;
            }
    
        else if( ispType != NOT_INTRA_SUBPARTITIONS )
        {
          //default case
          mpm[0] = PLANAR_IDX;
          if( isHorSplit )
          {
            mpm[1] = HOR_IDX;
            mpm[2] = 25;
            mpm[3] = 10;
            mpm[4] = 65;
            mpm[5] = VER_IDX;
          }
          else
          {
            mpm[1] = VER_IDX;
            mpm[2] = 43;
            mpm[3] = 60;
            mpm[4] = 3;
            mpm[5] = HOR_IDX;
          }
          int canonicalMode = mpm[1];
          if( leftIntraDir == aboveIntraDir ) //L=A
          {
            numCand = 1;
            if( leftIntraDir > DC_IDX )
            {
              mpm[0] =     leftIntraDir;
              mpm[1] = ( ( leftIntraDir + offset ) % mod ) + 2;
              mpm[2] = ( ( leftIntraDir - 1 ) % mod ) + 2;
              if( ( isHorSplit && leftIntraDir < DIA_IDX ) || ( !isHorSplit && leftIntraDir >= DIA_IDX ) )
              {
                mpm[3] = ( ( leftIntraDir + offset - 1 ) % mod ) + 2;
                mpm[4] =   ( leftIntraDir                % mod ) + 2;
                mpm[5] = ( ( leftIntraDir + offset - 2 ) % mod ) + 2;;
              }
              else
              {
                if( isHorSplit )
                {
                  mpm[3] = HOR_IDX;
                  mpm[4] = 5;
                }
                else
                {
                  mpm[3] = VER_IDX;
                  mpm[4] = VDIA_IDX - 3;
                }
                mpm[5] = PLANAR_IDX;
              }
            }
          }
          else //L!=A
          {
            numCand = 2;
            if( ( leftIntraDir > DC_IDX ) && ( aboveIntraDir > DC_IDX ) )
            {
              int distLeftToCanonicalMode  = abs( leftIntraDir - canonicalMode );
              int distAboveToCanonicalMode = abs( aboveIntraDir - canonicalMode );
              mpm[0] = aboveIntraDir;
              mpm[1] = leftIntraDir;
              if( distLeftToCanonicalMode <= distAboveToCanonicalMode )
              {
                mpm[0] = leftIntraDir;
                mpm[1] = aboveIntraDir;
              }
              int maxCandModeIdx = mpm[0] > mpm[1] ? 0 : 1;
              int minCandModeIdx = 1 - maxCandModeIdx;
              if( mpm[maxCandModeIdx] - mpm[minCandModeIdx] == 1 )
              {
                mpm[2] = ( ( mpm[minCandModeIdx] + offset )     % mod ) + 2;
                mpm[3] = ( ( mpm[maxCandModeIdx] - 1 )          % mod ) + 2;
                mpm[4] = ( ( mpm[minCandModeIdx] + offset - 1 ) % mod ) + 2;
                mpm[5] =   ( mpm[maxCandModeIdx]                % mod ) + 2;
              }
              else if( mpm[maxCandModeIdx] - mpm[minCandModeIdx] >= 62 )
              {
                mpm[2] = ( ( mpm[minCandModeIdx] - 1 )          % mod ) + 2;
                mpm[3] = ( ( mpm[maxCandModeIdx] + offset )     % mod ) + 2;
                mpm[4] = ( ( mpm[minCandModeIdx] )              % mod ) + 2;
                mpm[5] = ( ( mpm[maxCandModeIdx] + offset - 1 ) % mod ) + 2;
              }
              else if( mpm[maxCandModeIdx] - mpm[minCandModeIdx] == 2 )
              {
                mpm[2] = ( ( mpm[minCandModeIdx] - 1 )          % mod ) + 2;
                mpm[3] = ( ( mpm[minCandModeIdx] + offset )     % mod ) + 2;
                mpm[4] = ( ( mpm[maxCandModeIdx] - 1 )          % mod ) + 2;
                mpm[5] = ( ( mpm[minCandModeIdx] + offset - 1 ) % mod ) + 2;
              }
              else
              {
                mpm[2] = ( ( mpm[minCandModeIdx] + offset )     % mod ) + 2;
                mpm[3] = ( ( mpm[minCandModeIdx] - 1 )          % mod ) + 2;
                mpm[4] = ( ( mpm[maxCandModeIdx] + offset )     % mod ) + 2;
                mpm[5] = ( ( mpm[maxCandModeIdx] - 1 )          % mod ) + 2;
              }
            }
            else if( leftIntraDir + aboveIntraDir > 2 )
            {
              //mpm[0] = PLANAR_IDX;
              int angMode = leftIntraDir > DC_IDX ? leftIntraDir : aboveIntraDir;
              mpm[1] = angMode;
              mpm[2] = ( ( angMode + offset )     % mod ) + 2;
              mpm[3] = ( ( angMode - 1 )          % mod ) + 2;
              mpm[4] = ( ( angMode + offset - 1 ) % mod ) + 2;
              mpm[5] = ( ( angMode )              % mod ) + 2;
            }
          }
        }
    
    #if JVET_N0185_UNIFIED_MPM
          mpm[0] = PLANAR_IDX;
          mpm[1] = DC_IDX;
    #else
    
    ling's avatar
    ling committed
          mpm[0] = leftIntraDir;
    
          mpm[1] = (mpm[0] == PLANAR_IDX) ? DC_IDX : PLANAR_IDX;
    
          mpm[2] = VER_IDX;
          mpm[3] = HOR_IDX;
          mpm[4] = VER_IDX - 4;
          mpm[5] = VER_IDX + 4;
    
          if (leftIntraDir == aboveIntraDir)
    
            numCand = 1;
            if (leftIntraDir > DC_IDX)
    
    #if JVET_N0185_UNIFIED_MPM
              mpm[0] = PLANAR_IDX;
              mpm[1] = leftIntraDir;
              mpm[2] = ((leftIntraDir + offset) % mod) + 2;
              mpm[3] = ((leftIntraDir - 1) % mod) + 2;
              mpm[4] = DC_IDX;
              mpm[5] = ((leftIntraDir + offset - 1) % mod) + 2;
    #else
    
              mpm[0] = leftIntraDir;
              mpm[1] = PLANAR_IDX;
              mpm[2] = DC_IDX;
              mpm[3] = ((leftIntraDir + offset) % mod) + 2;
              mpm[4] = ((leftIntraDir - 1) % mod) + 2;
              mpm[5] = ((leftIntraDir + offset - 1) % mod) + 2;
    
          else //L!=A
    
            numCand = 2;
    
    #if !JVET_N0185_UNIFIED_MPM
    
            mpm[0] = leftIntraDir;
            mpm[1] = aboveIntraDir;
    
    #endif
    #if JVET_N0185_UNIFIED_MPM
            int  maxCandModeIdx = mpm[0] > mpm[1] ? 0 : 1;
    #else
    
            bool maxCandModeIdx = mpm[0] > mpm[1] ? 0 : 1;
    
    
            if ((leftIntraDir > DC_IDX) && (aboveIntraDir > DC_IDX))
            {
    
    #if JVET_N0185_UNIFIED_MPM
              mpm[0] = PLANAR_IDX;
              mpm[1] = leftIntraDir;
              mpm[2] = aboveIntraDir;
              maxCandModeIdx = mpm[1] > mpm[2] ? 1 : 2;
              int minCandModeIdx = mpm[1] > mpm[2] ? 2 : 1;
    #else
    
              mpm[2] = PLANAR_IDX;
    
              mpm[3] = DC_IDX;
    
    #if JVET_N0185_UNIFIED_MPM
              if ((mpm[maxCandModeIdx] - mpm[minCandModeIdx] < 63) && (mpm[maxCandModeIdx] - mpm[minCandModeIdx] > 1))
    #else
    
              if ((mpm[maxCandModeIdx] - mpm[!maxCandModeIdx] < 63) && (mpm[maxCandModeIdx] - mpm[!maxCandModeIdx] > 1))
    
              {
                mpm[4] = ((mpm[maxCandModeIdx] + offset) % mod) + 2;
                mpm[5] = ((mpm[maxCandModeIdx] - 1) % mod) + 2;
              }
              else
              {
                mpm[4] = ((mpm[maxCandModeIdx] + offset - 1) % mod) + 2;
                mpm[5] = ((mpm[maxCandModeIdx]) % mod) + 2;
              }
            }
            else if (leftIntraDir + aboveIntraDir >= 2)
            {
    
    #if JVET_N0185_UNIFIED_MPM
              mpm[0] = PLANAR_IDX;
              mpm[1] = (leftIntraDir < aboveIntraDir) ? aboveIntraDir : leftIntraDir;
              maxCandModeIdx = 1;
              mpm[2] = DC_IDX;
    #else
    
              mpm[2] = (mpm[!maxCandModeIdx] == PLANAR_IDX) ? DC_IDX : PLANAR_IDX;
    
              mpm[3] = ((mpm[maxCandModeIdx] + offset) % mod) + 2;
              mpm[4] = ((mpm[maxCandModeIdx] - 1) % mod) + 2;
              mpm[5] = ((mpm[maxCandModeIdx] + offset - 1) % mod) + 2;
            }
    
        for (int i = 0; i < numMPMs; i++)
        {
          CHECK(mpm[i] >= NUM_LUMA_MODE, "Invalid MPM");
        }
        CHECK(numCand == 0, "No candidates found");
        return numCand;
      }
    }
    
    
    void PU::getIntraChromaCandModes( const PredictionUnit &pu, unsigned modeList[NUM_CHROMA_MODE] )
    {
      {
        modeList[  0 ] = PLANAR_IDX;
        modeList[  1 ] = VER_IDX;
        modeList[  2 ] = HOR_IDX;
        modeList[  3 ] = DC_IDX;
        modeList[4] = LM_CHROMA_IDX;
    
        modeList[5] = MDLM_L_IDX;
        modeList[6] = MDLM_T_IDX;
        modeList[7] = DM_CHROMA_IDX;
    
    Li's avatar
    Li committed
        Position topLeftPos = pu.blocks[pu.chType].lumaPos();
    
    Li's avatar
    Li committed
        Position refPos = topLeftPos.offset( pu.blocks[pu.chType].lumaSize().width >> 1, pu.blocks[pu.chType].lumaSize().height >> 1 );
    
    Li's avatar
    Li committed
        const PredictionUnit *lumaPU = CS::isDualITree( *pu.cs ) ? pu.cs->picture->cs->getPU( refPos, CHANNEL_TYPE_LUMA ) : &pu;
    
        const uint32_t lumaMode = lumaPU->intraDir[CHANNEL_TYPE_LUMA];
        for( int i = 0; i < 4; i++ )
        {
          if( lumaMode == modeList[i] )
          {
            modeList[i] = VDIA_IDX;
            break;
          }
        }
      }
    }
    
    
    bool PU::isLMCMode(unsigned mode)
    {
    
      return (mode >= LM_CHROMA_IDX && mode <= MDLM_T_IDX);
    
    }
    bool PU::isLMCModeEnabled(const PredictionUnit &pu, unsigned mode)
    {
    
      if ( pu.cs->sps->getUseLMChroma() )
    
      {
        return true;
      }
      return false;
    }
    
    int PU::getLMSymbolList(const PredictionUnit &pu, int *pModeList)
    {
      int iIdx = 0;
    
      pModeList[ iIdx++ ] = LM_CHROMA_IDX;
        pModeList[ iIdx++ ] = -1;
    
      pModeList[iIdx++] = MDLM_L_IDX;
      pModeList[iIdx++] = MDLM_T_IDX;
    
      return iIdx;
    }
    
    
    
    bool PU::isChromaIntraModeCrossCheckMode( const PredictionUnit &pu )
    {
      return pu.intraDir[CHANNEL_TYPE_CHROMA] == DM_CHROMA_IDX;
    }
    
    
    int PU::getMHIntraMPMs(const PredictionUnit &pu, unsigned* mpm, const ChannelType &channelType /*= CHANNEL_TYPE_LUMA*/, const bool isChromaMDMS /*= false*/, const unsigned startIdx /*= 0*/)
    {
    
      const int numMPMs = 3; // Multi-hypothesis intra uses only 3 MPM
    
      {
        int numCand = -1;
        uint32_t leftIntraDir = DC_IDX, aboveIntraDir = DC_IDX;
    
        const CompArea& area = pu.block(getFirstComponentOfChannel(channelType));
        const Position& pos = area.pos();
    
        // Get intra direction of left PU
        const PredictionUnit *puLeft = pu.cs->getPURestricted(pos.offset(-1, 0), pu, channelType);
    
    
        if (puLeft && (CU::isIntra(*puLeft->cu) || puLeft->mhIntraFlag))
    
        {
          leftIntraDir = puLeft->intraDir[channelType];
    
          if (isChroma(channelType) && leftIntraDir == DM_CHROMA_IDX)
          {
            leftIntraDir = puLeft->intraDir[0];
          }
        }
    
        // Get intra direction of above PU
        const PredictionUnit* puAbove = pu.cs->getPURestricted(pos.offset(0, -1), pu, channelType);
    
    
        if (puAbove && (CU::isIntra(*puAbove->cu) || puAbove->mhIntraFlag) && CU::isSameCtu(*pu.cu, *puAbove->cu))
    
        {
          aboveIntraDir = puAbove->intraDir[channelType];
    
          if (isChroma(channelType) && aboveIntraDir == DM_CHROMA_IDX)
          {
            aboveIntraDir = puAbove->intraDir[0];
          }
        }
    
        CHECK(2 >= numMPMs, "Invalid number of most probable modes");
    
        uint32_t leftIntraDir2 = leftIntraDir;
        uint32_t aboveIntraDir2 = aboveIntraDir;
    
        leftIntraDir2 = (leftIntraDir2 > DC_IDX) ? ((leftIntraDir2 <= DIA_IDX) ? HOR_IDX : VER_IDX) : leftIntraDir2;
        aboveIntraDir2 = (aboveIntraDir2 > DC_IDX) ? ((aboveIntraDir2 <= DIA_IDX) ? HOR_IDX : VER_IDX) : aboveIntraDir2;
    
        if (leftIntraDir2 == aboveIntraDir2)
        {
          numCand = 1;
    
          if (leftIntraDir2 > DC_IDX) // angular modes
          {
            mpm[0] = leftIntraDir2;
            mpm[1] = PLANAR_IDX;
            mpm[2] = DC_IDX;
          }
          else //non-angular
          {
            mpm[0] = PLANAR_IDX;
            mpm[1] = DC_IDX;
            mpm[2] = VER_IDX;
          }
        }
        else
        {
          numCand = 2;
    
          mpm[0] = leftIntraDir2;
          mpm[1] = aboveIntraDir2;
    
          if (leftIntraDir2 && aboveIntraDir2) //both modes are non-planar
          {
            mpm[2] = PLANAR_IDX;
          }
          else
          {
            mpm[2] = (leftIntraDir2 + aboveIntraDir2) < 2 ? VER_IDX : DC_IDX;
          }
        }
        int narrowCase = getNarrowShape(pu.lwidth(), pu.lheight());
        if (narrowCase > 0)
        {
          bool isMPM[NUM_LUMA_MODE];
          for (int idx = 0; idx < NUM_LUMA_MODE; idx++)
          {
            isMPM[idx] = false;
          }
          for (int idx = 0; idx < numMPMs; idx++)
          {
            isMPM[mpm[idx]] = true;
          }
          if (narrowCase == 1 && isMPM[HOR_IDX])
          {
            for (int idx = 0; idx < numMPMs; idx++)
            {
              if (mpm[idx] == HOR_IDX)
              {
                if (!isMPM[PLANAR_IDX])
                  mpm[idx] = PLANAR_IDX;
                else if (!isMPM[DC_IDX])
                  mpm[idx] = DC_IDX;
                else if (!isMPM[VER_IDX])
                  mpm[idx] = VER_IDX;
                break;
              }
            }
          }
          if (narrowCase == 2 && isMPM[VER_IDX])
          {
            for (int idx = 0; idx < numMPMs; idx++)
            {
              if (mpm[idx] == VER_IDX)
              {
                if (!isMPM[PLANAR_IDX])
                  mpm[idx] = PLANAR_IDX;
                else if (!isMPM[DC_IDX])
                  mpm[idx] = DC_IDX;
                else if (!isMPM[HOR_IDX])
                  mpm[idx] = HOR_IDX;
                break;
              }
            }
          }
        }
        CHECK(numCand == 0, "No candidates found");
        CHECK(mpm[0] == mpm[1] || mpm[0] == mpm[2] || mpm[2] == mpm[1], "redundant MPM");
        return numCand;
      }
    }
    int PU::getNarrowShape(const int width, const int height)
    {
      int longSide = (width > height) ? width : height;
      int shortSide = (width > height) ? height : width;
      if (longSide > (2 * shortSide))
      {
        if (longSide == width)
          return 1;
        else
          return 2;
      }
      else
      {
        return 0;
      }
    }
    
    
    uint32_t PU::getFinalIntraMode( const PredictionUnit &pu, const ChannelType &chType )
    {
      uint32_t uiIntraMode = pu.intraDir[chType];
    
      if( uiIntraMode == DM_CHROMA_IDX && !isLuma( chType ) )
      {
    
    Li's avatar
    Li committed
        Position topLeftPos = pu.blocks[pu.chType].lumaPos();
    
    Li's avatar
    Li committed
        Position refPos = topLeftPos.offset( pu.blocks[pu.chType].lumaSize().width >> 1, pu.blocks[pu.chType].lumaSize().height >> 1 );
    
    Li's avatar
    Li committed
        const PredictionUnit &lumaPU = CS::isDualITree( *pu.cs ) ? *pu.cs->picture->cs->getPU( refPos, CHANNEL_TYPE_LUMA ) : *pu.cs->getPU( topLeftPos, CHANNEL_TYPE_LUMA );
    
      if( pu.chromaFormat == CHROMA_422 && !isLuma( chType ) 
    #if JVET_N0671_CHROMA_FORMAT_422
          && uiIntraMode < NUM_LUMA_MODE
    #endif //JVET_N0671_CHROMA_FORMAT_422
        ) // map directional, planar and dc
    
      {
        uiIntraMode = g_chroma422IntraAngleMappingTable[uiIntraMode];
      }
      return uiIntraMode;
    }