Skip to content
Snippets Groups Projects
UnitTools.cpp 128 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-2020, 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->isIntra() && !cs.pcv->ISingleTree;
    
    }
    
    UnitArea CS::getArea( const CodingStructure &cs, const UnitArea &area, const ChannelType chType )
    {
    
      return isDualITree( cs ) || cs.treeType != TREE_D ? 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];
    
                subPu.mv[REF_PIC_LIST_0].clipToStorageBitDepth();
                subPu.mv[REF_PIC_LIST_1].clipToStorageBitDepth();
    
                pu.mvdL0SubPu[num].setZero();
                num++;
                PU::spanMotionInfo(subPu);
              }
            }
          }
        }
    
    Brian Heng's avatar
    Brian Heng committed
    bool CU::getRprScaling( const SPS* sps, const PPS* curPPS, Picture* refPic, int& xScale, int& yScale )
    
      const Window& curScalingWindow = curPPS->getScalingWindow();
    
    #if JVET_Q0487_SCALING_WINDOW_ISSUES
      int curPicWidth = curPPS->getPicWidthInLumaSamples()   - SPS::getWinUnitX( sps->getChromaFormatIdc() ) * (curScalingWindow.getWindowLeftOffset() + curScalingWindow.getWindowRightOffset());
      int curPicHeight = curPPS->getPicHeightInLumaSamples() - SPS::getWinUnitY( sps->getChromaFormatIdc() ) * (curScalingWindow.getWindowTopOffset()  + curScalingWindow.getWindowBottomOffset());
    #else
    
      int curPicWidth = curPPS->getPicWidthInLumaSamples() - curScalingWindow.getWindowLeftOffset() - curScalingWindow.getWindowRightOffset();
      int curPicHeight = curPPS->getPicHeightInLumaSamples() - curScalingWindow.getWindowTopOffset() - curScalingWindow.getWindowBottomOffset();
    
    
      const Window& refScalingWindow = refPic->getScalingWindow();
    
    #if JVET_Q0487_SCALING_WINDOW_ISSUES
      int refPicWidth = refPic->getPicWidthInLumaSamples()   - SPS::getWinUnitX( sps->getChromaFormatIdc() ) * (refScalingWindow.getWindowLeftOffset() + refScalingWindow.getWindowRightOffset());
      int refPicHeight = refPic->getPicHeightInLumaSamples() - SPS::getWinUnitY( sps->getChromaFormatIdc() ) * (refScalingWindow.getWindowTopOffset()  + refScalingWindow.getWindowBottomOffset());
    #else
    
      int refPicWidth = refPic->getPicWidthInLumaSamples() - refScalingWindow.getWindowLeftOffset() - refScalingWindow.getWindowRightOffset();
      int refPicHeight = refPic->getPicHeightInLumaSamples() - refScalingWindow.getWindowTopOffset() - refScalingWindow.getWindowBottomOffset();
    
      xScale = ( ( refPicWidth << SCALE_RATIO_BITS ) + ( curPicWidth >> 1 ) ) / curPicWidth;
      yScale = ( ( refPicHeight << SCALE_RATIO_BITS ) + ( curPicHeight >> 1 ) ) / curPicHeight;
    
      int curSeqMaxPicWidthY = sps->getMaxPicWidthInLumaSamples();                  // pic_width_max_in_luma_samples
      int curSeqMaxPicHeightY = sps->getMaxPicHeightInLumaSamples();                // pic_height_max_in_luma_samples
      int curPicWidthY = curPPS->getPicWidthInLumaSamples();                        // pic_width_in_luma_samples
      int curPicHeightY = curPPS->getPicHeightInLumaSamples();                      // pic_height_in_luma_samples 
      int max8MinCbSizeY = std::max((int)8, (1<<sps->getLog2MinCodingBlockSize())); // Max(8, MinCbSizeY)
    
      CHECK((curPicWidth * curSeqMaxPicWidthY) < refPicWidth * (curPicWidthY - max8MinCbSizeY), "(curPicWidth * curSeqMaxPicWidthY) should be greater than or equal to refPicWidth * (curPicWidthY - max8MinCbSizeY))");
      CHECK((curPicHeight * curSeqMaxPicHeightY) < refPicHeight * (curPicHeightY - max8MinCbSizeY), "(curPicHeight * curSeqMaxPicHeightY) should be greater than or equal to refPicHeight * (curPicHeightY - max8MinCbSizeY))");
    
    
      CHECK(curPicWidth * 2 < refPicWidth, "curPicWidth * 2 shall be greater than or equal to refPicWidth");
      CHECK(curPicHeight * 2 < refPicHeight, "curPicHeight * 2 shall be greater than or equal to refPicHeight");
      CHECK(curPicWidth > refPicWidth * 8, "curPicWidth shall be less than or equal to refPicWidth * 8");
      CHECK(curPicHeight > refPicHeight * 8, "curPicHeight shall be less than or equal to refPicHeight * 8");
    
    
    #if JVET_Q0487_SCALING_WINDOW_ISSUES
      return refPic->isRefScaled( curPPS );
    #else
    
      return refPicWidth != curPicWidth || refPicHeight != curPicHeight;
    
    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::isPLT(const CodingUnit &cu)
    {
      return cu.predMode == MODE_PLT;
    }
    
    
    bool CU::isRDPCMEnabled(const CodingUnit& cu)
    {
      return cu.cs->sps->getSpsRangeExtension().getRdpcmEnabledFlag(cu.predMode == MODE_INTRA ? RDPCM_SIGNAL_IMPLICIT : RDPCM_SIGNAL_EXPLICIT);
    }
    
    
    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 );
    }
    
    
    #if JVET_O1143_SUBPIC_BOUNDARY
    bool CU::isSameSubPic(const CodingUnit& cu, const CodingUnit& cu2)
    {
      return (cu.slice->getPPS()->getSubPicFromCU(cu).getSubPicIdx() == cu2.slice->getPPS()->getSubPicFromCU(cu2).getSubPicIdx()) ;
    }
    #endif 
    
    
    bool CU::isSameCtu(const CodingUnit& cu, const CodingUnit& cu2)
    {
    
      uint32_t ctuSizeBit = floorLog2(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;
    }
    
    bool CU::isLastSubCUOfCtu( const CodingUnit &cu )
    {
    
      const Area cuAreaY = cu.isSepTree() ? 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  == cu.cs->pps->getPicWidthInLumaSamples()  ) &&
               ( ( ( cuAreaY.y + cuAreaY.height ) & cu.cs->pcv->maxCUHeightMask ) == 0 || cuAreaY.y + cuAreaY.height == cu.cs->pps->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;
    
    
      uint32_t  ctuRsAddr       = getCtuAddr( cu );
      uint32_t  ctuXPosInCtus   = ctuRsAddr % cs.pcv->widthInCtus;
      uint32_t  tileColIdx      = cu.slice->getPPS()->ctuToTileCol( ctuXPosInCtus );
      uint32_t  tileXPosInCtus  = cu.slice->getPPS()->getTileColumnBd( tileColIdx );
      if( ctuXPosInCtus == tileXPosInCtus &&
          !( cu.blocks[cu.chType].x & ( cs.pcv->maxCUWidthMask  >> getChannelTypeScaleX( cu.chType, cu.chromaFormat ) ) ) &&
          !( 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 ) && 
          CU::isSameSliceAndTile( *cs.getCU( cu.blocks[cu.chType].pos().offset( 0, -1 ), cu.chType), cu ) )
    
      {
        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 );
    }
    
    
    void CU::saveMotionInHMVP( const CodingUnit& cu, const bool isToBeDone )
    {
      const PredictionUnit& pu = *cu.firstPU;
    
    
      if (!cu.triangle && !cu.affine && !isToBeDone )
    
    #else
      if (!cu.geoFlag && !cu.affine && !isToBeDone)
    #endif
    
      {
        MotionInfo mi = pu.getMotionInfo();
    
    
        mi.BcwIdx = (mi.interDir == 3) ? cu.BcwIdx : BCW_DEFAULT;
    
    #if JVET_Q0297_MER
        const unsigned log2ParallelMergeLevel = (pu.cs->sps->getLog2ParallelMergeLevelMinus2() + 2);
        const unsigned xBr = pu.cu->Y().width + pu.cu->Y().x;
        const unsigned yBr = pu.cu->Y().height + pu.cu->Y().y;
        bool enableHmvp = ((xBr >> log2ParallelMergeLevel) > (pu.cu->Y().x >> log2ParallelMergeLevel)) && ((yBr >> log2ParallelMergeLevel) > (pu.cu->Y().y >> log2ParallelMergeLevel));
        bool enableInsertion = CU::isIBC(cu) || enableHmvp;
        if (enableInsertion)
    #endif
    
        cu.cs->addMiToLut(CU::isIBC(cu) ? cu.cs->motionLut.lutIbc : cu.cs->motionLut.lut, mi);
      }
    }
    
    
    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; }
    }
    
    
    ModeType CU::getModeTypeAtDepth( const CodingUnit& cu, const unsigned depth )
    {
      ModeType modeType = ModeType( (cu.modeTypeSeries >> (depth * 3)) & 0x07 );
      CHECK( depth > cu.depth, " depth is wrong" );
      return modeType;
    }
    
    
    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;
    }
    
    
    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];
    }
    
    
    bool CU::canUseISP( const CodingUnit &cu, const ComponentID compID )
    
    {
      const int width     = cu.blocks[compID].width;
      const int height    = cu.blocks[compID].height;
    
      const int maxTrSize = cu.cs->sps->getMaxTbSize();
    
    bool CU::canUseISP( const int width, const int height, const int maxTrSize )
    
      bool  notEnoughSamplesToSplit = ( floorLog2(width) + floorLog2(height) <= ( floorLog2(MIN_TB_SIZEY) << 1 ) );
    
      bool  cuSizeLargerThanMaxTrSize = width > maxTrSize || height > maxTrSize;
      if ( notEnoughSamplesToSplit || cuSizeLargerThanMaxTrSize )
    
    bool CU::canUseLfnstWithISP( const CompArea& cuArea, const ISPType ispSplitType )
    {
      if( ispSplitType == NOT_INTRA_SUBPARTITIONS )
      {
        return false;
      }
      Size tuSize = ( ispSplitType == HOR_INTRA_SUBPARTITIONS ) ? Size( cuArea.width, CU::getISPSplitDim( cuArea.width, cuArea.height, TU_1D_HORZ_SPLIT ) ) :
        Size( CU::getISPSplitDim( cuArea.width, cuArea.height, TU_1D_VERT_SPLIT ), cuArea.height );
    
      if( !( tuSize.width >= MIN_TB_SIZEY && tuSize.height >= MIN_TB_SIZEY ) )
      {
        return false;
      }
      return true;
    }
    
    bool CU::canUseLfnstWithISP( const CodingUnit& cu, const ChannelType chType )
    {
      CHECK( !isLuma( chType ), "Wrong ISP mode!" );
      return CU::canUseLfnstWithISP( cu.blocks[chType == CHANNEL_TYPE_LUMA ? 0 : 1], (ISPType)cu.ispMode );
    }
    
    
    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 << ( ( floorLog2(MIN_TB_SIZEY) << 1 ) );
      const int factorToMinSamples = nonSplitDimensionSize < minNumberOfSamplesPerCu ? minNumberOfSamplesPerCu >> floorLog2(nonSplitDimensionSize) : 1;
    
      partitionSize = ( splitDimensionSize >> divShift ) < factorToMinSamples ? factorToMinSamples : ( splitDimensionSize >> divShift );
    
    
      CHECK( floorLog2(partitionSize) + floorLog2(nonSplitDimensionSize) < floorLog2(minNumberOfSamplesPerCu), "A partition has less than the minimum amount of samples!" );
    
    Santiago de Luxán Hernández's avatar
    Santiago de Luxán Hernández committed
    bool CU::allLumaCBFsAreZero(const CodingUnit& cu)
    
    {
      if (!cu.ispMode)
      {
        return TU::getCbf(*cu.firstTU, COMPONENT_Y) == false;
      }
      else
      {
    
        int numTotalTUs = cu.ispMode == HOR_INTRA_SUBPARTITIONS ? cu.lheight() >> floorLog2(cu.firstTU->lheight()) : cu.lwidth() >> floorLog2(cu.firstTU->lwidth());
    
        TransformUnit* tuPtr = cu.firstTU;
        for (int tuIdx = 0; tuIdx < numTotalTUs; tuIdx++)
        {
          if (TU::getCbf(*tuPtr, COMPONENT_Y) == true)
          {
            return false;
          }
          tuPtr = tuPtr->next;
        }
        return true;
      }
    }
    
    
    
    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;
    
        CHECK(channelType != CHANNEL_TYPE_LUMA, "Not harmonized yet");
    
    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 = PU::getIntraDirLuma( *puLeft );
    
    ling's avatar
    ling committed
        }
    
        // 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 = PU::getIntraDirLuma( *puAbove );
    
    ling's avatar
    ling committed
        }
    
        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;
    
        {
    
          mpm[0] = PLANAR_IDX;
          mpm[1] = DC_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)
    
              mpm[0] = PLANAR_IDX;
              mpm[1] = leftIntraDir;
              mpm[2] = ((leftIntraDir + offset) % mod) + 2;
              mpm[3] = ((leftIntraDir - 1) % mod) + 2;
    
              mpm[4] = ((leftIntraDir + offset - 1) % mod) + 2;
              mpm[5] = ( leftIntraDir               % mod) + 2;
    
          else //L!=A
    
            numCand = 2;
    
            int  maxCandModeIdx = mpm[0] > mpm[1] ? 0 : 1;
    
    
            if ((leftIntraDir > DC_IDX) && (aboveIntraDir > DC_IDX))
            {
    
              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;
    
              if (mpm[maxCandModeIdx] - mpm[minCandModeIdx] == 1)
              {
                mpm[3] = ((mpm[minCandModeIdx] + offset)     % mod) + 2;
                mpm[4] = ((mpm[maxCandModeIdx] - 1)          % mod) + 2;
                mpm[5] = ((mpm[minCandModeIdx] + offset - 1) % mod) + 2;
              }
              else if (mpm[maxCandModeIdx] - mpm[minCandModeIdx] >= 62)
              {
                mpm[3] = ((mpm[minCandModeIdx] - 1)      % mod) + 2;
                mpm[4] = ((mpm[maxCandModeIdx] + offset) % mod) + 2;
                mpm[5] = ( mpm[minCandModeIdx]           % mod) + 2;
              }
              else if (mpm[maxCandModeIdx] - mpm[minCandModeIdx] == 2)
              {
                mpm[3] = ((mpm[minCandModeIdx] - 1)      % mod) + 2;
                mpm[4] = ((mpm[minCandModeIdx] + offset) % mod) + 2;
                mpm[5] = ((mpm[maxCandModeIdx] - 1)      % mod) + 2;
              }
              else
              {
                mpm[3] = ((mpm[minCandModeIdx] + offset) % mod) + 2;
                mpm[4] = ((mpm[minCandModeIdx] - 1)      % mod) + 2;
                mpm[5] = ((mpm[maxCandModeIdx] + offset) % mod) + 2;
              }
    
            }
            else if (leftIntraDir + aboveIntraDir >= 2)
            {
    
              mpm[0] = PLANAR_IDX;
              mpm[1] = (leftIntraDir < aboveIntraDir) ? aboveIntraDir : leftIntraDir;
              maxCandModeIdx = 1;
    
              mpm[2] = ((mpm[maxCandModeIdx] + offset)     % mod) + 2;
              mpm[3] = ((mpm[maxCandModeIdx] - 1)          % mod) + 2;
              mpm[4] = ((mpm[maxCandModeIdx] + offset - 1) % mod) + 2;
              mpm[5] = ( mpm[maxCandModeIdx]               % 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;
      }
    }
    
    
    bool PU::isMIP(const PredictionUnit &pu, const ChannelType &chType)
    {
      return (chType == CHANNEL_TYPE_LUMA && pu.cu->mipFlag);
    }
    
    
    uint32_t PU::getIntraDirLuma( const PredictionUnit &pu )
    {
      if (isMIP(pu))
      {
    
        return PLANAR_IDX;
    
      }
      else
      {
        return pu.intraDir[CHANNEL_TYPE_LUMA];
      }
    }
    
    
    
    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;
    
        const uint32_t lumaMode = getCoLocatedIntraLumaMode(pu);
    
        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() && pu.cu->checkCCLMAllowed() )
    
    int PU::getLMSymbolList(const PredictionUnit &pu, int *modeList)
    
      int idx = 0;
    
    U-EU\bray's avatar
    U-EU\bray committed
      modeList[idx++] = LM_CHROMA_IDX;
    
      modeList[idx++] = MDLM_L_IDX;
      modeList[idx++] = MDLM_T_IDX;
      return idx;
    
    }
    
    bool PU::isChromaIntraModeCrossCheckMode( const PredictionUnit &pu )
    {
    
      return !pu.cu->bdpcmModeChroma && pu.intraDir[CHANNEL_TYPE_CHROMA] == DM_CHROMA_IDX;
    
    }
    
    uint32_t PU::getFinalIntraMode( const PredictionUnit &pu, const ChannelType &chType )
    {
      uint32_t uiIntraMode = pu.intraDir[chType];
    
      if( uiIntraMode == DM_CHROMA_IDX && !isLuma( chType ) )
      {
    
        uiIntraMode = getCoLocatedIntraLumaMode(pu);
    
      if( pu.chromaFormat == CHROMA_422 && !isLuma( chType ) && uiIntraMode < NUM_LUMA_MODE ) // map directional, planar and dc
    
      {
        uiIntraMode = g_chroma422IntraAngleMappingTable[uiIntraMode];
      }
      return uiIntraMode;
    }
    
    
    uint32_t PU::getCoLocatedIntraLumaMode( const PredictionUnit &pu )
    {
      Position topLeftPos = pu.blocks[pu.chType].lumaPos();
      Position refPos = topLeftPos.offset( pu.blocks[pu.chType].lumaSize().width >> 1, pu.blocks[pu.chType].lumaSize().height >> 1 );
    
      const PredictionUnit &lumaPU = pu.cu->isSepTree() ? *pu.cs->picture->cs->getPU( refPos, CHANNEL_TYPE_LUMA ) : *pu.cs->getPU( topLeftPos, CHANNEL_TYPE_LUMA );
    
    int PU::getWideAngIntraMode( const TransformUnit &tu, const uint32_t dirMode, const ComponentID compID )
    {
      if( dirMode < 2 )
      {
        return ( int ) dirMode;
      }
    
    
      const CompArea&  area         = tu.cu->ispMode && isLuma(compID) ? tu.cu->blocks[compID] : tu.blocks[ compID ];
      int              width        = area.width;
      int              height       = area.height;
    
      int              modeShift[ ] = { 0, 6, 10, 12, 14, 15 };
    
      int              deltaSize    = abs( floorLog2( width ) - floorLog2( height ) );
    
      int              predMode     = dirMode;
    
      if( width > height && dirMode < 2 + modeShift[ deltaSize ] )
      {
        predMode += ( VDIA_IDX - 1 );
      }
      else if( height > width && predMode > VDIA_IDX - modeShift[ deltaSize ] )
      {
        predMode -= ( VDIA_IDX + 1 );
      }
    
      return predMode;
    }
    
    
    Remy Foray's avatar
    Remy Foray committed
    bool PU::addMergeHMVPCand(const CodingStructure &cs, MergeCtx& mrgCtx, const int& mrgCandIdx, const uint32_t maxNumMergeCandMin1, int &cnt
    
      , const bool isAvailableA1, const MotionInfo miLeft, const bool isAvailableB1, const MotionInfo miAbove
      , const bool ibcFlag
      , const bool isGt4x4
      )
    
      const Slice& slice = *cs.slice;
    
      MotionInfo miNeighbor;
    
      auto &lut = ibcFlag ? cs.motionLut.lutIbc : cs.motionLut.lut;
    
    ROBERT Antoine's avatar
    ROBERT Antoine committed
      int num_avai_candInLUT = (int)lut.size();
    
      for (int mrgIdx = 1; mrgIdx <= num_avai_candInLUT; mrgIdx++)
      {
    
        miNeighbor = lut[num_avai_candInLUT - mrgIdx];
    
    
        if ( mrgIdx > 2 || ((mrgIdx > 1 || !isGt4x4) && ibcFlag)
          || ((!isAvailableA1 || (miLeft != miNeighbor)) && (!isAvailableB1 || (miAbove != miNeighbor))) )
    
          mrgCtx.interDirNeighbours[cnt] = miNeighbor.interDir;
    
    ROBERT Antoine's avatar
    ROBERT Antoine committed
          mrgCtx.useAltHpelIf      [cnt] = !ibcFlag && miNeighbor.useAltHpelIf;
    
          mrgCtx.BcwIdx            [cnt] = (miNeighbor.interDir == 3) ? miNeighbor.BcwIdx : BCW_DEFAULT;
    
          mrgCtx.mvFieldNeighbours[cnt << 1].setMvField(miNeighbor.mv[0], miNeighbor.refIdx[0]);
          if (slice.isInterB())
          {
            mrgCtx.mvFieldNeighbours[(cnt << 1) + 1].setMvField(miNeighbor.mv[1], miNeighbor.refIdx[1]);
          }
    
    
    Remy Foray's avatar
    Remy Foray committed
          if (mrgCandIdx == cnt)
    
          if (cnt  == maxNumMergeCandMin1)
          {
            break;
          }
        }
      }
    
    Xiang Li's avatar
    Xiang Li committed
      if (cnt < maxNumMergeCandMin1)
      {
        mrgCtx.useAltHpelIf[cnt] = false;
      }
    
    Yu Han's avatar
    Yu Han committed
    void PU::getIBCMergeCandidates(const PredictionUnit &pu, MergeCtx& mrgCtx, const int& mrgCandIdx)
    {
      const CodingStructure &cs = *pu.cs;
    
    Ling Li's avatar
    Ling Li committed
      const uint32_t maxNumMergeCand = pu.cs->sps->getMaxNumIBCMergeCand();
    
    Yu Han's avatar
    Yu Han committed
      for (uint32_t ui = 0; ui < maxNumMergeCand; ++ui)
      {
    
        mrgCtx.BcwIdx[ui] = BCW_DEFAULT;
    
    Yu Han's avatar
    Yu Han committed
        mrgCtx.interDirNeighbours[ui] = 0;
        mrgCtx.mrgTypeNeighbours[ui] = MRG_TYPE_IBC;
    
    Yu Han's avatar
    Yu Han committed
        mrgCtx.mvFieldNeighbours[ui * 2].refIdx = NOT_VALID;
        mrgCtx.mvFieldNeighbours[ui * 2 + 1].refIdx = NOT_VALID;
    
    Xiang Li's avatar
    Xiang Li committed
        mrgCtx.useAltHpelIf[ui] = false;
    
    Yu Han's avatar
    Yu Han committed
      }
    
      mrgCtx.numValidMergeCand = maxNumMergeCand;
      // compute the location of the current PU
    
      int cnt = 0;
    
    
      const Position posRT = pu.Y().topRight();
      const Position posLB = pu.Y().bottomLeft();
    
    Yu Han's avatar
    Yu Han committed
    
      MotionInfo miAbove, miLeft, miAboveLeft, miAboveRight, miBelowLeft;
    
      //left
      const PredictionUnit* puLeft = cs.getPURestricted(posLB.offset(-1, 0), pu, pu.chType);
    
      bool isGt4x4 = pu.lwidth() * pu.lheight() > 16;
    
    #if JVET_Q0297_MER
      const bool isAvailableA1 = puLeft && pu.cu != puLeft->cu && CU::isIBC(*puLeft->cu);
    #else
    
    Yu Han's avatar
    Yu Han committed
      const bool isAvailableA1 = puLeft && isDiffMER(pu, *puLeft) && pu.cu != puLeft->cu && CU::isIBC(*puLeft->cu);
    
      if (isGt4x4 && isAvailableA1)
    
    Yu Han's avatar
    Yu Han committed
      {
        miLeft = puLeft->getMotionInfo(posLB.offset(-1, 0));
    
        // get Inter Dir
        mrgCtx.interDirNeighbours[cnt] = miLeft.interDir;
        // get Mv from Left
        mrgCtx.mvFieldNeighbours[cnt << 1].setMvField(miLeft.mv[0], miLeft.refIdx[0]);
    
    Remy Foray's avatar
    Remy Foray committed
        if (mrgCandIdx == cnt)
    
    Yu Han's avatar
    Yu Han committed
        {
          return;
        }
        cnt++;
      }
    
      // early termination
      if (cnt == maxNumMergeCand)
      {
        return;
      }
    
      // above
      const PredictionUnit *puAbove = cs.getPURestricted(posRT.offset(0, -1), pu, pu.chType);
    
    #if JVET_Q0297_MER
      bool isAvailableB1 = puAbove && pu.cu != puAbove->cu && CU::isIBC(*puAbove->cu);
    #else
    
    Yu Han's avatar
    Yu Han committed
      bool isAvailableB1 = puAbove && isDiffMER(pu, *puAbove) && pu.cu != puAbove->cu && CU::isIBC(*puAbove->cu);
    
      if (isGt4x4 && isAvailableB1)
    
    Yu Han's avatar
    Yu Han committed
      {
        miAbove = puAbove->getMotionInfo(posRT.offset(0, -1));
    
        if (!isAvailableA1 || (miAbove != miLeft))
        {
          // get Inter Dir
          mrgCtx.interDirNeighbours[cnt] = miAbove.interDir;
          // get Mv from Above
          mrgCtx.mvFieldNeighbours[cnt << 1].setMvField(miAbove.mv[0], miAbove.refIdx[0]);
    
    Remy Foray's avatar
    Remy Foray committed
          if (mrgCandIdx == cnt)
    
    Yu Han's avatar
    Yu Han committed
          {
            return;
          }
    
          cnt++;
        }
      }
    
      // early termination
      if (cnt == maxNumMergeCand)
      {
        return;
      }
    
    
      if (cnt != maxNumMergeCand)
    
    Remy Foray's avatar
    Remy Foray committed
        bool bFound = addMergeHMVPCand(cs, mrgCtx, mrgCandIdx, maxNumMergeCand, cnt
    
          , isAvailableA1, miLeft, isAvailableB1, miAbove
    
    Yu Han's avatar
    Yu Han committed
          , true
    
          , isGt4x4
    
    Yu Han's avatar
    Yu Han committed
        if (bFound)
        {
          return;
        }
      }
    
    
    Yu Han's avatar
    Yu Han committed
        while (cnt < maxNumMergeCand)
        {
          mrgCtx.mvFieldNeighbours[cnt * 2].setMvField(Mv(0, 0), MAX_NUM_REF);
          mrgCtx.interDirNeighbours[cnt] = 1;
    
    Remy Foray's avatar
    Remy Foray committed
          if (mrgCandIdx == cnt)
    
    Yu Han's avatar
    Yu Han committed
          {
            return;
          }
    
    Yu Han's avatar
    Yu Han committed
      mrgCtx.numValidMergeCand = cnt;
    }
    
    
    void PU::getInterMergeCandidates( const PredictionUnit &pu, MergeCtx& mrgCtx,
    
                                     int mmvdList,
                                     const int& mrgCandIdx )
    
    Han Huang's avatar
    Han Huang committed
    #if JVET_Q0297_MER
    
    Han Huang's avatar
    Han Huang committed
      const unsigned plevel = pu.cs->sps->getLog2ParallelMergeLevelMinus2() + 2;
    #endif
    
      const CodingStructure &cs  = *pu.cs;
      const Slice &slice         = *pu.cs->slice;
    
    Ling Li's avatar
    Ling Li committed
      const uint32_t maxNumMergeCand = pu.cs->sps->getMaxNumMergeCand();
    
      for (uint32_t ui = 0; ui < maxNumMergeCand; ++ui)
      {
    
        mrgCtx.BcwIdx[ui] = BCW_DEFAULT;
    
        mrgCtx.interDirNeighbours[ui] = 0;
        mrgCtx.mrgTypeNeighbours [ui] = MRG_TYPE_DEFAULT_N;
        mrgCtx.mvFieldNeighbours[(ui << 1)    ].refIdx = NOT_VALID;
        mrgCtx.mvFieldNeighbours[(ui << 1) + 1].refIdx = NOT_VALID;
    
        mrgCtx.useAltHpelIf[ui] = false;
    
      }
    
      mrgCtx.numValidMergeCand = maxNumMergeCand;
      // compute the location of the current PU
    
      int cnt = 0;
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
    
    
      const Position posLT = pu.Y().topLeft();
      const Position posRT = pu.Y().topRight();
      const Position posLB = pu.Y().bottomLeft();
    
      MotionInfo miAbove, miLeft, miAboveLeft, miAboveRight, miBelowLeft;
    
    
      // above
      const PredictionUnit *puAbove = cs.getPURestricted(posRT.offset(0, -1), pu, pu.chType);
    
    
    Han Huang's avatar
    Han Huang committed
    #if JVET_Q0297_MER
    
    Han Huang's avatar
    Han Huang committed
      bool isAvailableB1 = puAbove && isDiffMER(pu.lumaPos(), posRT.offset(0, -1), plevel) && pu.cu != puAbove->cu && CU::isInter(*puAbove->cu);
    #else
    
      bool isAvailableB1 = puAbove && isDiffMER(pu, *puAbove) && pu.cu != puAbove->cu && CU::isInter(*puAbove->cu);
    
    Han Huang's avatar
    Han Huang committed
    #endif
    
    
      if (isAvailableB1)
      {
        miAbove = puAbove->getMotionInfo(posRT.offset(0, -1));
    
        // get Inter Dir
        mrgCtx.interDirNeighbours[cnt] = miAbove.interDir;
        mrgCtx.useAltHpelIf[cnt] = miAbove.useAltHpelIf;
        // get Mv from Above
    
        mrgCtx.BcwIdx[cnt] = (mrgCtx.interDirNeighbours[cnt] == 3) ? puAbove->cu->BcwIdx : BCW_DEFAULT;
    
        mrgCtx.mvFieldNeighbours[cnt << 1].setMvField(miAbove.mv[0], miAbove.refIdx[0]);
    
        if (slice.isInterB())
        {
          mrgCtx.mvFieldNeighbours[(cnt << 1) + 1].setMvField(miAbove.mv[1], miAbove.refIdx[1]);
        }
    
    Remy Foray's avatar
    Remy Foray committed
        if (mrgCandIdx == cnt)
    
        {
          return;
        }
    
        cnt++;
      }
    
      // early termination
      if (cnt == maxNumMergeCand)
      {
        return;
      }
    
      //left
      const PredictionUnit* puLeft = cs.getPURestricted(posLB.offset(-1, 0), pu, pu.chType);
    
    
    Han Huang's avatar
    Han Huang committed
    #if JVET_Q0297_MER
    
    Han Huang's avatar
    Han Huang committed
      const bool isAvailableA1 = puLeft && isDiffMER(pu.lumaPos(), posLB.offset(-1, 0), plevel) && pu.cu != puLeft->cu && CU::isInter(*puLeft->cu);
    #else
    
      const bool isAvailableA1 = puLeft && isDiffMER(pu, *puLeft) && pu.cu != puLeft->cu && CU::isInter(*puLeft->cu);
    
    Han Huang's avatar
    Han Huang committed
    #endif
    
    
      if (isAvailableA1)
      {
        miLeft = puLeft->getMotionInfo(posLB.offset(-1, 0));
    
        if (!isAvailableB1 || (miAbove != miLeft))
        {
          // get Inter Dir
          mrgCtx.interDirNeighbours[cnt] = miLeft.interDir;
          mrgCtx.useAltHpelIf[cnt] = miLeft.useAltHpelIf;
    
          mrgCtx.BcwIdx[cnt] = (mrgCtx.interDirNeighbours[cnt] == 3) ? puLeft->cu->BcwIdx : BCW_DEFAULT;
    
          // get Mv from Left
          mrgCtx.mvFieldNeighbours[cnt << 1].setMvField(miLeft.mv[0], miLeft.refIdx[0]);
    
          if (slice.isInterB())
          {
            mrgCtx.mvFieldNeighbours[(cnt << 1) + 1].setMvField(miLeft.mv[1], miLeft.refIdx[1]);
          }
    
    Remy Foray's avatar
    Remy Foray committed
          if (mrgCandIdx == cnt)
    
    
      // early termination
      if( cnt == maxNumMergeCand )
      {
        return;
      }
    
      // above right
      const PredictionUnit *puAboveRight = cs.getPURestricted( posRT.offset( 1, -1 ), pu, pu.chType );
    
    
    Han Huang's avatar
    Han Huang committed
    #if JVET_Q0297_MER
    
    Han Huang's avatar
    Han Huang committed
      bool isAvailableB0 = puAboveRight && isDiffMER( pu.lumaPos(), posRT.offset(1, -1), plevel) && CU::isInter( *puAboveRight->cu );
    #else
    
      bool isAvailableB0 = puAboveRight && isDiffMER( pu, *puAboveRight ) && CU::isInter( *puAboveRight->cu );
    
    Han Huang's avatar
    Han Huang committed
    #endif
    
    
      if( isAvailableB0 )
      {
        miAboveRight = puAboveRight->getMotionInfo( posRT.offset( 1, -1 ) );
    
        if( !isAvailableB1 || ( miAbove != miAboveRight ) )
        {
    
          // get Inter Dir
          mrgCtx.interDirNeighbours[cnt] = miAboveRight.interDir;
    
          mrgCtx.useAltHpelIf[cnt] = miAboveRight.useAltHpelIf;
    
          mrgCtx.BcwIdx[cnt] = (mrgCtx.interDirNeighbours[cnt] == 3) ? puAboveRight->cu->BcwIdx : BCW_DEFAULT;
    
          mrgCtx.mvFieldNeighbours[cnt << 1].setMvField( miAboveRight.mv[0], miAboveRight.refIdx[0] );
    
    
          if( slice.isInterB() )
          {
            mrgCtx.mvFieldNeighbours[( cnt << 1 ) + 1].setMvField( miAboveRight.mv[1], miAboveRight.refIdx[1] );
          }
    
    
    Remy Foray's avatar
    Remy Foray committed
          if (mrgCandIdx == cnt)