Skip to content
Snippets Groups Projects
UnitTools.cpp 166 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 )
    {
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #if INTRA_RM_SMALL_BLOCK_SIZE_CONSTRAINTS
      return isDualITree(cs) ? area.singleChan(chType) : area;
    #else
    
      return isDualITree( cs ) || cs.treeType != TREE_D ? area.singleChan( chType ) : area;
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #endif
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #if !MULTI_PASS_DMVR
    
    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);
              }
            }
          }
        }
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #endif
    
    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();
    
      int curPicWidth = curPPS->getPicWidthInLumaSamples()   - SPS::getWinUnitX( sps->getChromaFormatIdc() ) * (curScalingWindow.getWindowLeftOffset() + curScalingWindow.getWindowRightOffset());
      int curPicHeight = curPPS->getPicHeightInLumaSamples() - SPS::getWinUnitY( sps->getChromaFormatIdc() ) * (curScalingWindow.getWindowTopOffset()  + curScalingWindow.getWindowBottomOffset());
    
    
      const Window& refScalingWindow = refPic->getScalingWindow();
    
      int refPicWidth = refPic->getPicWidthInLumaSamples()   - SPS::getWinUnitX( sps->getChromaFormatIdc() ) * (refScalingWindow.getWindowLeftOffset() + refScalingWindow.getWindowRightOffset());
      int refPicHeight = refPic->getPicHeightInLumaSamples() - SPS::getWinUnitY( sps->getChromaFormatIdc() ) * (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_S0048_SCALING_OFFSET
      int subWidthC = SPS::getWinUnitX(sps->getChromaFormatIdc());
      int subHeightC = SPS::getWinUnitY(sps->getChromaFormatIdc());
    
      CHECK(subWidthC * curScalingWindow.getWindowLeftOffset() < (-curPicWidthY) * 15, "The value of SubWidthC * pps_scaling_win_left_offset shall be greater than or equal to -pps_pic_width_in_luma_samples * 15");
      CHECK(subWidthC * curScalingWindow.getWindowLeftOffset() >= curPicWidthY, "The value of SubWidthC * pps_scaling_win_left_offset shall be less than pic_width_in_luma_samples");
      CHECK(subWidthC * curScalingWindow.getWindowRightOffset() < (-curPicWidthY) * 15, "The value of SubWidthC * pps_scaling_win_right_offset shall be greater than or equal to -pps_pic_width_in_luma_samples * 15");
      CHECK(subWidthC * curScalingWindow.getWindowRightOffset() >= curPicWidthY, "The value of SubWidthC * pps_scaling_win_right_offset shall be less than pic_width_in_luma_samples");
    
      CHECK(subHeightC * curScalingWindow.getWindowTopOffset() < (-curPicHeightY) * 15, "The value of SubHeightC * pps_scaling_win_top_offset shall be greater than or equal to -pps_pic_height_in_luma_samples * 15");
      CHECK(subHeightC * curScalingWindow.getWindowTopOffset() >= curPicHeightY, "The value of SubHeightC * pps_scaling_win_top_offset shall be less than pps_pic_height_in_luma_samples");
      CHECK(subHeightC * curScalingWindow.getWindowBottomOffset() < (-curPicHeightY) * 15, "The value of SubHeightC *pps_scaling_win_bottom_offset shall be greater than or equal to -pps_pic_height_in_luma_samples * 15");
      CHECK(subHeightC * curScalingWindow.getWindowBottomOffset() >= curPicHeightY, "The value of SubHeightC *pps_scaling_win_bottom_offset shall be less than pps_pic_height_in_luma_samples");
    
      CHECK(subWidthC * (curScalingWindow.getWindowLeftOffset() + curScalingWindow.getWindowRightOffset()) < (-curPicWidthY) * 15, "The value of SubWidthC * ( pps_scaling_win_left_offset + pps_scaling_win_right_offset ) shall be greater than or equal to -pps_pic_width_in_luma_samples * 15");
      CHECK(subWidthC * (curScalingWindow.getWindowLeftOffset() + curScalingWindow.getWindowRightOffset()) >= curPicWidthY, "The value of SubWidthC * ( pps_scaling_win_left_offset + pps_scaling_win_right_offset ) shall be less than pic_width_in_luma_samples");
      CHECK(subHeightC * (curScalingWindow.getWindowTopOffset() + curScalingWindow.getWindowBottomOffset()) < (-curPicHeightY) * 15, "The value of SubHeightC * ( pps_scaling_win_top_offset + pps_scaling_win_bottom_offset ) shall be greater than or equal to -pps_pic_height_in_luma_samples * 15");
      CHECK(subHeightC * (curScalingWindow.getWindowTopOffset() + curScalingWindow.getWindowBottomOffset()) >= curPicHeightY, "The value of SubHeightC * ( pps_scaling_win_top_offset + pps_scaling_win_bottom_offset ) shall be less than pic_height_in_luma_samples");
    #else
    
      CHECK(SPS::getWinUnitX(sps->getChromaFormatIdc()) * (abs(curScalingWindow.getWindowLeftOffset()) + abs(curScalingWindow.getWindowRightOffset())) > curPPS->getPicWidthInLumaSamples(), "The value of SubWidthC * ( Abs(pps_scaling_win_left_offset) + Abs(pps_scaling_win_right_offset) ) shall be less than pic_width_in_luma_samples");
      CHECK(SPS::getWinUnitY(sps->getChromaFormatIdc()) * (abs(curScalingWindow.getWindowTopOffset()) + abs(curScalingWindow.getWindowBottomOffset())) > curPPS->getPicHeightInLumaSamples(), "The value of SubHeightC * ( Abs(pps_scaling_win_top_offset) + Abs(pps_scaling_win_bottom_offset) ) shall be less than pic_height_in_luma_samples");
    
      return refPic->isRefScaled( curPPS );
    
    void CU::checkConformanceILRP(Slice *slice)
    
      const int numRefList = slice->isInterB() ? 2 : 1;
    
    #if JVET_S0258_SUBPIC_CONSTRAINTS
      int currentSubPicIdx = NOT_VALID;
    
      // derive sub-picture index for the current slice
      for( int subPicIdx = 0; subPicIdx < slice->getPic()->cs->sps->getNumSubPics(); subPicIdx++ )
      {
        if( slice->getPic()->cs->pps->getSubPic( subPicIdx ).getSubPicID() == slice->getSliceSubPicId() )
        {
          currentSubPicIdx = subPicIdx;
          break;
        }
      }
    
      CHECK( currentSubPicIdx == NOT_VALID, "Sub-picture was not found" );
    
      if( !slice->getPic()->cs->sps->getSubPicTreatedAsPicFlag( currentSubPicIdx ) )
      {
        return;
      }
    #endif
    
    Vadim Seregin's avatar
    Vadim Seregin committed
      //constraint 1: The picture referred to by each active entry in RefPicList[ 0 ] or RefPicList[ 1 ] has the same subpicture layout as the current picture
    
      bool isAllRefSameSubpicLayout = true;
    
    Zhipin Deng's avatar
    Zhipin Deng committed
      for (int refList = 0; refList < numRefList; refList++) // loop over l0 and l1
    
    Zhipin Deng's avatar
    Zhipin Deng committed
        RefPicList  eRefPicList = (refList ? REF_PIC_LIST_1 : REF_PIC_LIST_0);
    
    Zhipin Deng's avatar
    Zhipin Deng committed
        for (int refIdx = 0; refIdx < slice->getNumRefIdx(eRefPicList); refIdx++)
    
    #if JVET_S0258_SUBPIC_CONSTRAINTS
          const Picture* refPic = slice->getRefPic( eRefPicList, refIdx );
    
          if( refPic->subPictures.size() != slice->getPic()->cs->pps->getNumSubPics() )
    #else
    
    Zhipin Deng's avatar
    Zhipin Deng committed
          const Picture* refPic = slice->getRefPic(eRefPicList, refIdx)->unscaledPic;
    
          if (refPic->numSubpics != slice->getPic()->cs->pps->getNumSubPics())
    
          {
            isAllRefSameSubpicLayout = false;
    
    Zhipin Deng's avatar
    Zhipin Deng committed
            refList = numRefList;
    
            break;
    
    #if JVET_S0258_SUBPIC_CONSTRAINTS
            for( int i = 0; i < refPic->subPictures.size(); i++ )
            {
              const SubPic& refSubPic = refPic->subPictures[i];
              const SubPic& curSubPic = slice->getPic()->cs->pps->getSubPic( i );
    
              if( refSubPic.getSubPicWidthInCTUs() != curSubPic.getSubPicWidthInCTUs()
                || refSubPic.getSubPicHeightInCTUs() != curSubPic.getSubPicHeightInCTUs()
                || refSubPic.getSubPicCtuTopLeftX() != curSubPic.getSubPicCtuTopLeftX()
                || refSubPic.getSubPicCtuTopLeftY() != curSubPic.getSubPicCtuTopLeftY()
                || ( refPic->layerId != slice->getPic()->layerId && refSubPic.getSubPicID() != curSubPic.getSubPicID() )
                || refSubPic.getTreatedAsPicFlag() != curSubPic.getTreatedAsPicFlag())
    #else
    
            for (int i = 0; i < refPic->numSubpics; i++)
    
              if (refPic->subpicWidthInCTUs[i] != slice->getPic()->cs->pps->getSubPic(i).getSubPicWidthInCTUs()
                || refPic->subpicHeightInCTUs[i] != slice->getPic()->cs->pps->getSubPic(i).getSubPicHeightInCTUs()
                || refPic->subpicCtuTopLeftX[i] != slice->getPic()->cs->pps->getSubPic(i).getSubPicCtuTopLeftX()
                || refPic->subpicCtuTopLeftY[i] != slice->getPic()->cs->pps->getSubPic(i).getSubPicCtuTopLeftY())
    
              {
                isAllRefSameSubpicLayout = false;
    
    Zhipin Deng's avatar
    Zhipin Deng committed
                refIdx = slice->getNumRefIdx(eRefPicList);
                refList = numRefList;
    
                break;
    
    
    #if JVET_S0258_SUBPIC_CONSTRAINTS
            // A picture with different sub-picture ID of the collocated sub-picture cannot be used as an active reference picture in the same layer
            if( refPic->layerId == slice->getPic()->layerId )
            {
              isAllRefSameSubpicLayout = isAllRefSameSubpicLayout && refPic->subPictures[currentSubPicIdx].getSubPicID() == slice->getSliceSubPicId();
            }
    #endif
    
          }
        }
      }
    
      //constraint 2: The picture referred to by each active entry in RefPicList[ 0 ] or RefPicList[ 1 ] is an ILRP for which the value of sps_num_subpics_minus1 is equal to 0
      if (!isAllRefSameSubpicLayout)
      {
    
    Zhipin Deng's avatar
    Zhipin Deng committed
        for (int refList = 0; refList < numRefList; refList++) // loop over l0 and l1
    
    Zhipin Deng's avatar
    Zhipin Deng committed
          RefPicList  eRefPicList = (refList ? REF_PIC_LIST_1 : REF_PIC_LIST_0);
          for (int refIdx = 0; refIdx < slice->getNumRefIdx(eRefPicList); refIdx++)
    
    #if JVET_S0258_SUBPIC_CONSTRAINTS
            const Picture* refPic = slice->getRefPic( eRefPicList, refIdx );
            CHECK( refPic->layerId == slice->getPic()->layerId || refPic->subPictures.size() > 1, "The inter-layer reference shall contain a single subpicture or have same subpicture layout with the current picture" );
    #else
    
    Zhipin Deng's avatar
    Zhipin Deng committed
            const Picture* refPic = slice->getRefPic(eRefPicList, refIdx)->unscaledPic;
    
            CHECK(!(refPic->layerId != slice->getPic()->layerId && refPic->numSubpics == 1), "The inter-layer reference shall contain a single subpicture or have same subpicture layout with the current picture");
    
    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::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::isSameSubPic(const CodingUnit& cu, const CodingUnit& cu2)
    {
      return (cu.slice->getPPS()->getSubPicFromCU(cu).getSubPicIdx() == cu2.slice->getPPS()->getSubPicFromCU(cu2).getSubPicIdx()) ;
    }
    
    
    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 )
    {
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #if INTRA_RM_SMALL_BLOCK_SIZE_CONSTRAINTS
      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();
    #else
    
      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();
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #endif
    
    
      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.geoFlag && !cu.affine && !isToBeDone)
    
      {
        MotionInfo mi = pu.getMotionInfo();
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #if MULTI_HYP_PRED
        mi.addHypData = pu.addHypData;
    #endif
    
        mi.BcwIdx = (mi.interDir == 3) ? cu.BcwIdx : BCW_DEFAULT;
    
        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)
    
        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;
      }
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #if !INTRA_RM_SMALL_BLOCK_SIZE_CONSTRAINTS
    
    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;
    }
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #endif
    
    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
    
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #if SECONDARY_MPM
    int PU::getIntraMPMs( const PredictionUnit &pu, uint8_t* mpm, uint8_t* non_mpm, const ChannelType &channelType /*= CHANNEL_TYPE_LUMA*/ )
    #else
    int PU::getIntraMPMs(const PredictionUnit &pu, unsigned* mpm, const ChannelType &channelType /*= CHANNEL_TYPE_LUMA*/)
    #endif
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #if SECONDARY_MPM
      bool includedMode[NUM_INTRA_MODE];
      memset(includedMode, false, sizeof(includedMode));
    
      int numValidMPM = 0;
      mpm[numValidMPM++] = PLANAR_IDX;
      includedMode[PLANAR_IDX] = true;
    #endif
    
    
      const int numMPMs = NUM_MOST_PROBABLE_MODES;
    
        CHECK(channelType != CHANNEL_TYPE_LUMA, "Not harmonized yet");
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #if !SECONDARY_MPM
    
    ling's avatar
    ling committed
        int leftIntraDir = PLANAR_IDX, aboveIntraDir = PLANAR_IDX;
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #endif
    
    ling's avatar
    ling committed
    
        const CompArea &area = pu.block(getFirstComponentOfChannel(channelType));
        const Position posRT = area.topRight();
        const Position posLB = area.bottomLeft();
    
        // Get intra direction of left PU
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #if SECONDARY_MPM
        const PredictionUnit *puLeft = (pu.lheight() >= pu.lwidth())
          ? pu.cs->getPURestricted(posRT.offset(0, -1), pu, channelType)
          : pu.cs->getPURestricted(posLB.offset(-1, 0), pu, channelType);
    #else
    
    ling's avatar
    ling committed
        const PredictionUnit *puLeft = pu.cs->getPURestricted(posLB.offset(-1, 0), pu, channelType);
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #endif
    
    ling's avatar
    ling committed
        if (puLeft && CU::isIntra(*puLeft->cu))
        {
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #if SECONDARY_MPM
          mpm[numValidMPM] = PU::getIntraDirLuma(*puLeft);
          if( !includedMode[mpm[numValidMPM]] )
          {
            includedMode[mpm[numValidMPM++]] = true;
          }
    #else
    
          leftIntraDir = PU::getIntraDirLuma( *puLeft );
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #endif
    
    ling's avatar
    ling committed
        }
    
        // Get intra direction of above PU
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #if SECONDARY_MPM
        const PredictionUnit *puAbove = (pu.lheight() >= pu.lwidth())
          ? pu.cs->getPURestricted(posLB.offset(-1, 0), pu, channelType)
          : pu.cs->getPURestricted(posRT.offset(0, -1), pu, channelType);
    #else
    
    ling's avatar
    ling committed
        const PredictionUnit *puAbove = pu.cs->getPURestricted(posRT.offset(0, -1), pu, channelType);
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #endif
    
    ling's avatar
    ling committed
        if (puAbove && CU::isIntra(*puAbove->cu) && CU::isSameCtu(*pu.cu, *puAbove->cu))
        {
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #if SECONDARY_MPM
          mpm[numValidMPM] = PU::getIntraDirLuma(*puAbove);
          if( !includedMode[mpm[numValidMPM]] )
          {
            includedMode[mpm[numValidMPM++]] = true;
          }
    #else
    
          aboveIntraDir = PU::getIntraDirLuma( *puAbove );
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #endif
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #if SECONDARY_MPM
        // Get intra direction of below-left PU
        const PredictionUnit *puBelowLeft = pu.cs->getPURestricted(posLB.offset(-1, 1), pu, channelType);
        if (puBelowLeft && CU::isIntra(*puBelowLeft->cu))
        {
          mpm[numValidMPM] = PU::getIntraDirLuma(*puBelowLeft);
          if( !includedMode[mpm[numValidMPM]] )
          {
            includedMode[mpm[numValidMPM++]] = true;
          }
        }
    
    Vadim Seregin's avatar
    Vadim Seregin committed
        // Get intra direction of above-right PU
        const PredictionUnit *puAboveRight = pu.cs->getPURestricted(posRT.offset(1, -1), pu, channelType);
        if (puAboveRight && CU::isIntra(*puAboveRight->cu) && CU::isSameCtu(*pu.cu, *puAboveRight->cu))
        {
          mpm[numValidMPM] = PU::getIntraDirLuma(*puAboveRight);
          if( !includedMode[mpm[numValidMPM]] )
          {
            includedMode[mpm[numValidMPM++]] = true;
          }
        }
    
    Vadim Seregin's avatar
    Vadim Seregin committed
        // Get intra direction of above-left PU
        const Position posTL = area.topLeft();
        const PredictionUnit *puAboveLeft = pu.cs->getPURestricted(posTL.offset(-1, -1), pu, channelType);
        if (puAboveLeft && CU::isIntra(*puAboveLeft->cu) && CU::isSameCtu(*pu.cu, *puAboveLeft->cu))
    
    Vadim Seregin's avatar
    Vadim Seregin committed
          mpm[numValidMPM] = PU::getIntraDirLuma(*puAboveLeft);
          if( !includedMode[mpm[numValidMPM]] )
    
    Vadim Seregin's avatar
    Vadim Seregin committed
            includedMode[mpm[numValidMPM++]] = true;
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #endif
    
        CHECK(2 >= numMPMs, "Invalid number of most probable modes");
    
        const int offset = ( int ) NUM_LUMA_MODE - 6;
        const int mod = offset + 3;
    
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #if SECONDARY_MPM
          numCand = numValidMPM;
    #else
          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;
    #endif
    #if ENABLE_DIMD && SECONDARY_MPM
          //adding dimd modes
          if (pu.cu->slice->getSPS()->getUseDimd())
          {
            if (pu.cu->dimdMode != -1)
            {
              mpm[numValidMPM] = pu.cu->dimdMode;
              if( !includedMode[mpm[numValidMPM]] )
              {
                includedMode[mpm[numValidMPM++]] = true;
              }
            }
    
            if (pu.cu->dimdBlendMode[0] != -1)
            {
              mpm[numValidMPM] = pu.cu->dimdBlendMode[0];
              if( !includedMode[mpm[numValidMPM]] )
              {
                includedMode[mpm[numValidMPM++]] = true;
              }
            }
          }
    #endif
    
    #if SECONDARY_MPM
          bool checkDCEnabled = false;
    
          // Derived modes of mpm[1]
          if (numCand >= 2)
          {
            if (mpm[1] > DC_IDX)
            {
              for (int i = 0; i < 4 && numValidMPM < numMPMs; i++)
              {
                mpm[numValidMPM] = ((mpm[1] + offset - i) % mod) + 2;
                if( !includedMode[mpm[numValidMPM]] )
                {
                  includedMode[mpm[numValidMPM++]] = true;
                }
    
                if( numValidMPM >= numMPMs )
                {
                  break;
                }
    
                mpm[numValidMPM] = ((mpm[1] - 1 + i) % mod) + 2;
                if( !includedMode[mpm[numValidMPM]] )
                {
                  includedMode[mpm[numValidMPM++]] = true;
                }
              }
            }
            else if( mpm[1] == DC_IDX )
            {
              checkDCEnabled = true;
            }
          }
    
    
          // Derived modes of mpm[2]
          if (numCand >= 3)
          {
            if (mpm[2] > DC_IDX)
            {
              for (int i = 0; i < 4 && numValidMPM < numMPMs; i++)
              {
                mpm[numValidMPM] = ((mpm[2] + offset - i) % mod) + 2;
                if( !includedMode[mpm[numValidMPM]] )
                {
                  includedMode[mpm[numValidMPM++]] = true;
                }
    
                if (numValidMPM >= numMPMs)
                  break;
    
                mpm[numValidMPM] = ((mpm[2] - 1 + i) % mod) + 2;
                if( !includedMode[mpm[numValidMPM]] )
                {
                  includedMode[mpm[numValidMPM++]] = true;
                }
              }
            }
            else if( mpm[2] == DC_IDX )
            {
              checkDCEnabled = true;
            }
          }
    
    
          // Derived modes of mpm[3]
          if (checkDCEnabled && numCand >= 4 && mpm[3] > DC_IDX)
          {
            for (int i = 0; i < 3 && numValidMPM < numMPMs; i++)
            {
              mpm[numValidMPM] = ((mpm[3] + offset - i) % mod) + 2;
              if( !includedMode[mpm[numValidMPM]] )
              {
                includedMode[mpm[numValidMPM++]] = true;
              }
    
              if( numValidMPM >= numMPMs )
              {
                break;
              }
    
    Vadim Seregin's avatar
    Vadim Seregin committed
              mpm[numValidMPM] = ((mpm[3] - 1 + i) % mod) + 2;
              if( !includedMode[mpm[numValidMPM]] )
              {
                includedMode[mpm[numValidMPM++]] = true;
              }
            }
          }
    #else
          if (leftIntraDir == aboveIntraDir)
    
    Vadim Seregin's avatar
    Vadim Seregin committed
            numCand = 1;
            if (leftIntraDir > DC_IDX)
    
    Vadim Seregin's avatar
    Vadim Seregin committed
              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;
    
    Vadim Seregin's avatar
    Vadim Seregin committed
          }
          else //L!=A
          {
            numCand = 2;
            int  maxCandModeIdx = mpm[0] > mpm[1] ? 0 : 1;
    
            if ((leftIntraDir > DC_IDX) && (aboveIntraDir > DC_IDX))
    
    Vadim Seregin's avatar
    Vadim Seregin committed
              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;
              }
    
    Vadim Seregin's avatar
    Vadim Seregin committed
            else if (leftIntraDir + aboveIntraDir >= 2)
    
    Vadim Seregin's avatar
    Vadim Seregin committed
              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;
    
    Vadim Seregin's avatar
    Vadim Seregin committed
          }
    #endif
    
    #if SECONDARY_MPM
          unsigned mpm_default[numMPMs - 1] = { DC_IDX, VER_IDX, HOR_IDX, VER_IDX - 4, VER_IDX + 4, 14, 22, 42, 58, 10, 26,
                                               38, 62, 6, 30, 34, 66, 2, 48, 52, 16 };
          for (int idx = 0; (idx < numMPMs - 1) && numValidMPM < numMPMs; idx++)
          {
            mpm[numValidMPM] = mpm_default[idx];
            if( !includedMode[mpm[numValidMPM]] )
    
    Vadim Seregin's avatar
    Vadim Seregin committed
              includedMode[mpm[numValidMPM++]] = true;
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    
          int numNonMPM = 0;
          for (int idx = 0; idx < NUM_LUMA_MODE; idx++)
    
    Vadim Seregin's avatar
    Vadim Seregin committed
            if( !includedMode[idx] )
            {
              non_mpm[numNonMPM++] = idx;
            }
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #endif
    
        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)
    {
    
      if (chType == CHANNEL_TYPE_LUMA)
      {
        // Default case if chType is omitted.
        return pu.cu->mipFlag;
      }
      else
      {
        return isDMChromaMIP(pu) && (pu.intraDir[CHANNEL_TYPE_CHROMA] == DM_CHROMA_IDX);
      }
    
    bool PU::isDMChromaMIP(const PredictionUnit &pu)
    {
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #if !INTRA_RM_SMALL_BLOCK_SIZE_CONSTRAINTS
    
      return !pu.cu->isSepTree() && (pu.chromaFormat == CHROMA_444) && getCoLocatedLumaPU(pu).cu->mipFlag;
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #else
      return !(CS::isDualITree(*pu.cs)) && (pu.chromaFormat == CHROMA_444) && getCoLocatedLumaPU(pu).cu->mipFlag;
    #endif
    
    
    uint32_t PU::getIntraDirLuma( const PredictionUnit &pu )
    {
      if (isMIP(pu))
      {
    
        return PLANAR_IDX;
    
      }
      else
      {
        return pu.intraDir[CHANNEL_TYPE_LUMA];
      }
    }
    
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    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;
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #if MMLM
      modeList[5] = MDLM_L_IDX;
      modeList[6] = MDLM_T_IDX;
      modeList[7] = MMLM_CHROMA_IDX;
      modeList[8] = MMLM_L_IDX;
      modeList[9] = MMLM_T_IDX;
      modeList[10] = DM_CHROMA_IDX;
    #else
    
      modeList[5] = MDLM_L_IDX;
      modeList[6] = MDLM_T_IDX;
      modeList[7] = DM_CHROMA_IDX;
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #endif
    
      // If Direct Mode is MIP, mode cannot be already in the list.
      if (isDMChromaMIP(pu))
      {
        return;
      }
    
      const uint32_t lumaMode = getCoLocatedIntraLumaMode(pu);
      for (int i = 0; i < 4; i++)
      {
        if (lumaMode == modeList[i])
    
          modeList[i] = VDIA_IDX;
          break;