Skip to content
Snippets Groups Projects
UnitPartitioner.cpp 38.7 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     UnitPartitioner.h
     *  \brief    Provides a class for partitioning management
     */
    
    #include "UnitPartitioner.h"
    
    #include "CodingStructure.h"
    #include "Unit.h"
    #include "Slice.h"
    #include "UnitTools.h"
    #include "Picture.h"
    
    
    PartLevel::PartLevel()
    : split               ( CU_DONT_SPLIT )
    , parts               (               )
    , idx                 ( 0u            )
    , checkdIfImplicit    ( false         )
    , isImplicit          ( false         )
    , implicitSplit       ( CU_DONT_SPLIT )
    , firstSubPartSplit   ( CU_DONT_SPLIT )
    , canQtSplit          ( true          )
    
    #if JVET_M0113_M0188_QG_SIZE
    , qgEnable            ( true          )
    , qgChromaEnable      ( true          )
    #endif
    
    {
    }
    
    PartLevel::PartLevel( const PartSplit _split, const Partitioning& _parts )
    : split               ( _split        )
    , parts               ( _parts        )
    , idx                 ( 0u            )
    , checkdIfImplicit    ( false         )
    , isImplicit          ( false         )
    , implicitSplit       ( CU_DONT_SPLIT )
    , firstSubPartSplit   ( CU_DONT_SPLIT )
    , canQtSplit          ( true          )
    
    #if JVET_M0113_M0188_QG_SIZE
    , qgEnable            ( true          )
    , qgChromaEnable      ( true          )
    #endif
    
    {
    }
    
    PartLevel::PartLevel( const PartSplit _split, Partitioning&& _parts )
    : split               ( _split                               )
    , parts               ( std::forward<Partitioning>( _parts ) )
    , idx                 ( 0u                                   )
    , checkdIfImplicit    ( false                                )
    , isImplicit          ( false                                )
    , implicitSplit       ( CU_DONT_SPLIT                        )
    , firstSubPartSplit   ( CU_DONT_SPLIT                        )
    , canQtSplit          ( true                                 )
    
    #if JVET_M0113_M0188_QG_SIZE
    , qgEnable            ( true                                 )
    , qgChromaEnable      ( true                                 )
    #endif
    
    {
    }
    
    //////////////////////////////////////////////////////////////////////////
    // Partitioner class
    //////////////////////////////////////////////////////////////////////////
    
    SplitSeries Partitioner::getSplitSeries() const
    {
      SplitSeries splitSeries = 0;
      SplitSeries depth = 0;
    
      for( const auto &level : m_partStack )
      {
        if( level.split == CTU_LEVEL ) continue;
        else splitSeries += static_cast< SplitSeries >( level.split ) << ( depth * SPLIT_DMULT );
    
        depth++;
      }
    
      return splitSeries;
    }
    
    void Partitioner::setCUData( CodingUnit& cu )
    {
      cu.depth       = currDepth;
      cu.btDepth     = currBtDepth;
      cu.mtDepth     = currMtDepth;
      cu.qtDepth     = currQtDepth;
      cu.splitSeries = getSplitSeries();
    }
    
    void Partitioner::copyState( const Partitioner& other )
    {
      m_partStack = other.m_partStack;
      currBtDepth = other.currBtDepth;
      currQtDepth = other.currQtDepth;
      currDepth   = other.currDepth;
      currMtDepth = other.currMtDepth;
      currTrDepth = other.currTrDepth;
    
    #if JVET_M0113_M0188_QG_SIZE
      currSubdiv  = other.currSubdiv;
    #endif
    
      currImplicitBtDepth
                  = other.currImplicitBtDepth;
      chType      = other.chType;
    #ifdef _DEBUG
      m_currArea  = other.m_currArea;
    #endif
    }
    
    //////////////////////////////////////////////////////////////////////////
    // AdaptiveDepthPartitioner class
    //////////////////////////////////////////////////////////////////////////
    
    void AdaptiveDepthPartitioner::setMaxMinDepth( unsigned& minDepth, unsigned& maxDepth, const CodingStructure& cs ) const
    {
      unsigned          stdMinDepth = 0;
    
      unsigned          stdMaxDepth = ( g_aucLog2[cs.sps->getCTUSize()] - g_aucLog2[cs.sps->getMinQTSize( cs.slice->getSliceType(), chType )]);
    
      const Position    pos         = currArea().blocks[chType].pos();
      const unsigned    curSliceIdx = cs.slice->getIndependentSliceIdx();
    #if HEVC_TILES_WPP
      const unsigned    curTileIdx  = cs.picture->tileMap->getTileIdxMap( currArea().lumaPos() );
    
    
      const CodingUnit* cuLeft        = cs.getCURestricted( pos.offset( -1,                               0 ), curSliceIdx, curTileIdx, chType );
    
      const CodingUnit* cuBelowLeft   = cs.getCURestricted( pos.offset( -1, currArea().blocks[chType].height), curSliceIdx, curTileIdx, chType );
    
      const CodingUnit* cuAbove       = cs.getCURestricted( pos.offset(  0,                              -1 ), curSliceIdx, curTileIdx, chType );
    
      const CodingUnit* cuAboveRight  = cs.getCURestricted( pos.offset( currArea().blocks[chType].width, -1 ), curSliceIdx, curTileIdx, chType );
    
      const CodingUnit* cuLeft        = cs.getCURestricted( pos.offset( -1,                               0 ), curSliceIdx, chType );
      const CodingUnit* cuBelowLeft   = cs.getCURestricted( pos.offset( -1, currArea().blocks[chType].height), curSliceIdx, chType );
      const CodingUnit* cuAbove       = cs.getCURestricted( pos.offset(  0,                              -1 ), curSliceIdx, chType );
    
      const CodingUnit* cuAboveRight  = cs.getCURestricted( pos.offset( currArea().blocks[chType].width, -1 ), curSliceIdx, chType );
    
    #endif
    
      minDepth = stdMaxDepth;
      maxDepth = stdMinDepth;
    
      if( cuLeft )
      {
        minDepth = std::min<unsigned>( minDepth, cuLeft->qtDepth );
        maxDepth = std::max<unsigned>( maxDepth, cuLeft->qtDepth );
      }
      else
      {
        minDepth = stdMinDepth;
        maxDepth = stdMaxDepth;
      }
    
      if( cuBelowLeft )
      {
        minDepth = std::min<unsigned>( minDepth, cuBelowLeft->qtDepth );
        maxDepth = std::max<unsigned>( maxDepth, cuBelowLeft->qtDepth );
      }
      else
      {
        minDepth = stdMinDepth;
        maxDepth = stdMaxDepth;
      }
    
      if( cuAbove )
      {
        minDepth = std::min<unsigned>( minDepth, cuAbove->qtDepth );
        maxDepth = std::max<unsigned>( maxDepth, cuAbove->qtDepth );
      }
      else
      {
        minDepth = stdMinDepth;
        maxDepth = stdMaxDepth;
      }
    
      if( cuAboveRight )
      {
        minDepth = std::min<unsigned>( minDepth, cuAboveRight->qtDepth );
        maxDepth = std::max<unsigned>( maxDepth, cuAboveRight->qtDepth );
      }
      else
      {
        minDepth = stdMinDepth;
        maxDepth = stdMaxDepth;
      }
    
      minDepth = ( minDepth >= 1 ? minDepth - 1 : 0 );
      maxDepth = std::min<unsigned>( stdMaxDepth, maxDepth + 1 );
    }
    
    //////////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////
    // QTBTPartitioner
    //////////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////
    
    void QTBTPartitioner::initCtu( const UnitArea& ctuArea, const ChannelType _chType, const Slice& slice )
    {
    #if _DEBUG
      m_currArea = ctuArea;
    #endif
      currDepth   = 0;
      currTrDepth = 0;
      currBtDepth = 0;
      currMtDepth = 0;
      currQtDepth = 0;
    
    #if JVET_M0113_M0188_QG_SIZE
      currSubdiv  = 0;
    #endif
    
      currImplicitBtDepth = 0;
      chType      = _chType;
    
      m_partStack.clear();
      m_partStack.push_back( PartLevel( CTU_LEVEL, Partitioning{ ctuArea } ) );
    }
    
    void QTBTPartitioner::splitCurrArea( const PartSplit split, const CodingStructure& cs )
    {
      CHECKD( !canSplit( split, cs ), "Trying to apply a prohibited split!" );
    
      bool isImplicit = isSplitImplicit( split, cs );
      bool canQtSplit = canSplit( CU_QUAD_SPLIT, cs );
    
    #if JVET_M0113_M0188_QG_SIZE
      bool qgEnable = currQgEnable();
      bool qgChromaEnable = currQgChromaEnable();
    #endif
    
    
      switch( split )
      {
      case CU_QUAD_SPLIT:
        m_partStack.push_back( PartLevel( split, PartitionerImpl::getCUSubPartitions( currArea(), cs ) ) );
        break;
      case CU_HORZ_SPLIT:
      case CU_VERT_SPLIT:
        m_partStack.push_back( PartLevel( split, PartitionerImpl::getCUSubPartitions( currArea(), cs, split ) ) );
        break;
      case CU_TRIH_SPLIT:
      case CU_TRIV_SPLIT:
        m_partStack.push_back( PartLevel( split, PartitionerImpl::getCUSubPartitions( currArea(), cs, split ) ) );
        break;
      case TU_MAX_TR_SPLIT:
        m_partStack.push_back( PartLevel( split, PartitionerImpl::getMaxTuTiling( currArea(), cs ) ) );
        break;
    
    #if JVET_M0140_SBT
      case SBT_VER_HALF_POS0_SPLIT:
      case SBT_VER_HALF_POS1_SPLIT:
      case SBT_HOR_HALF_POS0_SPLIT:
      case SBT_HOR_HALF_POS1_SPLIT:
      case SBT_VER_QUAD_POS0_SPLIT:
      case SBT_VER_QUAD_POS1_SPLIT:
      case SBT_HOR_QUAD_POS0_SPLIT:
      case SBT_HOR_QUAD_POS1_SPLIT:
        m_partStack.push_back( PartLevel( split, PartitionerImpl::getSbtTuTiling( currArea(), cs, split ) ) );
        break;
    #endif
    
    #if JVET_M0113_M0188_QG_SIZE
      currSubdiv++;
    #endif
    
    #if _DEBUG
      m_currArea = m_partStack.back().parts.front();
    #endif
    
      if( split == TU_MAX_TR_SPLIT )
      {
        currTrDepth++;
      }
    
    #if JVET_M0140_SBT
      else if( split >= SBT_VER_HALF_POS0_SPLIT && split <= SBT_HOR_QUAD_POS1_SPLIT )
      {
        currTrDepth++;
      }
    #endif
    
      else
      {
        currTrDepth = 0;
      }
    
      if( split == CU_HORZ_SPLIT || split == CU_VERT_SPLIT || split == CU_TRIH_SPLIT || split == CU_TRIV_SPLIT )
      {
        currBtDepth++;
        if( isImplicit ) currImplicitBtDepth++;
        currMtDepth++;
    
        if( split == CU_TRIH_SPLIT || split == CU_TRIV_SPLIT )
        {
          // first and last part of triple split are equivalent to double bt split
          currBtDepth++;
    
    #if JVET_M0113_M0188_QG_SIZE
          currSubdiv++;
    #endif
    
        }
        m_partStack.back().canQtSplit = canQtSplit;
      }
      else if( split == CU_QUAD_SPLIT )
      {
        CHECK( currBtDepth > 0, "Cannot split a non-square area other than with a binary split" );
        CHECK( currMtDepth > 0, "Cannot split a non-square area other than with a binary split" );
        currMtDepth = 0;
        currBtDepth = 0;
        currQtDepth++;
    
    #if JVET_M0113_M0188_QG_SIZE
        currSubdiv++;
    #endif
    
    #if JVET_M0113_M0188_QG_SIZE
      m_partStack.back().qgEnable       = qgEnable       && (currSubdiv <= cs.pps->getCuQpDeltaSubdiv());
      m_partStack.back().qgChromaEnable = qgChromaEnable && (currSubdiv <= cs.pps->getPpsRangeExtension().getCuChromaQpOffsetSubdiv());
    #endif
    
    Adam Wieckowski's avatar
    Adam Wieckowski committed
    #if JVET_M0421_SPLIT_SIG
    void QTBTPartitioner::canSplit( const CodingStructure &cs, bool& canNo, bool& canQt, bool& canBh, bool& canBv, bool& canTh, bool& canTv )
    {
      const PartSplit implicitSplit = m_partStack.back().checkdIfImplicit ? m_partStack.back().implicitSplit : getImplicitSplit( cs );
    
    Adam Wieckowski's avatar
    Adam Wieckowski committed
      const unsigned maxBTD         = cs.pcv->getMaxBtDepth( *cs.slice, chType ) + currImplicitBtDepth;
      const unsigned maxBtSize      = cs.pcv->getMaxBtSize ( *cs.slice, chType );
      const unsigned minBtSize      = cs.pcv->getMinBtSize ( *cs.slice, chType );
      const unsigned maxTtSize      = cs.pcv->getMaxTtSize ( *cs.slice, chType );
      const unsigned minTtSize      = cs.pcv->getMinTtSize ( *cs.slice, chType );
      const unsigned minQtSize      = cs.pcv->getMinQtSize ( *cs.slice, chType );
    
      canNo = canQt = canBh = canTh = canBv = canTv = true;
      bool canBtt = currMtDepth < maxBTD;
    
      // the minimal and maximal sizes are given in luma samples
      const CompArea&  area  = currArea().Y();
            PartLevel& level = m_partStack.back();
    
      const PartSplit lastSplit = level.split;
      const PartSplit parlSplit = lastSplit == CU_TRIH_SPLIT ? CU_HORZ_SPLIT : CU_VERT_SPLIT;
    
      // don't allow QT-splitting below a BT split
      if( lastSplit != CTU_LEVEL && lastSplit != CU_QUAD_SPLIT ) canQt = false;
      if( area.width <= minQtSize )                              canQt = false;
    
      if( implicitSplit != CU_DONT_SPLIT )
      {
        canNo = canTh = canTv = false;
    
        canBh = implicitSplit == CU_HORZ_SPLIT;
        canBv = implicitSplit == CU_VERT_SPLIT;
    
        return;
      }
    
      if( ( lastSplit == CU_TRIH_SPLIT || lastSplit == CU_TRIV_SPLIT ) && currPartIdx() == 1 )
      {
        canBh = parlSplit != CU_HORZ_SPLIT;
        canBv = parlSplit != CU_VERT_SPLIT;
      }
    
    
      if( canBtt && ( area.width <= minBtSize && area.height <= minBtSize )
    
          && ( ( area.width <= minTtSize && area.height <= minTtSize ) ) )
    
      {
        canBtt = false;
      }
      if( canBtt && ( area.width > maxBtSize || area.height > maxBtSize )
    
          && ( ( area.width > maxTtSize || area.height > maxTtSize ) ) )
    
    Adam Wieckowski's avatar
    Adam Wieckowski committed
    
      if( !canBtt )
      {
        canBh = canTh = canBv = canTv = false;
    
        return;
      }
    
      // specific check for BT splits
      if( area.height <= minBtSize || area.height > maxBtSize )                            canBh = false;
    
      if( area.width > MAX_TB_SIZEY && area.height <= MAX_TB_SIZEY ) canBh = false;
    
    Adam Wieckowski's avatar
    Adam Wieckowski committed
    
      if( area.width <= minBtSize || area.width > maxBtSize )                              canBv = false;
    
      if( area.width <= MAX_TB_SIZEY && area.height > MAX_TB_SIZEY ) canBv = false;
    
    Adam Wieckowski's avatar
    Adam Wieckowski committed
    
    
      if( area.height <= 2 * minTtSize || area.height > maxTtSize || area.width > maxTtSize )
    
    Adam Wieckowski's avatar
    Adam Wieckowski committed
                                                                                           canTh = false;
    
      if( area.width > MAX_TB_SIZEY || area.height > MAX_TB_SIZEY )  canTh = false;
    
    Adam Wieckowski's avatar
    Adam Wieckowski committed
    
      if( area.width <= 2 * minTtSize || area.width > maxTtSize || area.height > maxTtSize )
                                                                                           canTv = false;
    
      if( area.width > MAX_TB_SIZEY || area.height > MAX_TB_SIZEY )  canTv = false;
    
    Adam Wieckowski's avatar
    Adam Wieckowski committed
    }
    
    #endif
    
    bool QTBTPartitioner::canSplit( const PartSplit split, const CodingStructure &cs )
    {
    
    Adam Wieckowski's avatar
    Adam Wieckowski committed
    #if JVET_M0421_SPLIT_SIG
      const CompArea area       = currArea().Y();
    
    #if MAX_TB_SIZE_SIGNALLING
      const unsigned maxTrSize  = cs.sps->getMaxTbSize();
    #else
      const unsigned maxTrSize  = MAX_TB_SIZEY;
    #endif
    
    Adam Wieckowski's avatar
    Adam Wieckowski committed
    
      bool canNo, canQt, canBh, canTh, canBv, canTv;
    
      canSplit( cs, canNo, canQt, canBh, canBv, canTh, canTv );
    #else
    
      const PartSplit implicitSplit = getImplicitSplit( cs );
    
      // the minimal and maximal sizes are given in luma samples
      const CompArea area           = currArea().Y();
    
      const unsigned maxBTD         = cs.pcv->getMaxBtDepth( *cs.slice, chType ) + currImplicitBtDepth;
      const unsigned maxBtSize      = cs.pcv->getMaxBtSize( *cs.slice, chType );
      const unsigned minBtSize      = cs.pcv->getMinBtSize( *cs.slice, chType );
      const unsigned maxTtSize      = cs.pcv->getMaxTtSize( *cs.slice, chType );
      const unsigned minTtSize      = cs.pcv->getMinTtSize( *cs.slice, chType );
    
    #if MAX_TB_SIZE_SIGNALLING
      const unsigned maxTrSize  = cs.sps->getMaxTbSize();
    #else
      const unsigned maxTrSize  = MAX_TB_SIZEY;
    #endif
    
    
      const PartSplit lastSplit = m_partStack.back().split;
      const PartSplit parlSplit = lastSplit == CU_TRIH_SPLIT ? CU_HORZ_SPLIT : CU_VERT_SPLIT;
    
      if( isNonLog2BlockSize( currArea().Y() ) )
      {
        return false;
      }
    
    
    Adam Wieckowski's avatar
    Adam Wieckowski committed
    #endif
    
      switch( split )
      {
      case CTU_LEVEL:
        THROW( "Checking if top level split is possible" );
        return true;
        break;
      case TU_MAX_TR_SPLIT:
        return area.width > maxTrSize || area.height > maxTrSize;
        break;
    
    #if JVET_M0140_SBT
      case SBT_VER_HALF_POS0_SPLIT:
      case SBT_VER_HALF_POS1_SPLIT:
      case SBT_HOR_HALF_POS0_SPLIT:
      case SBT_HOR_HALF_POS1_SPLIT:
      case SBT_VER_QUAD_POS0_SPLIT:
      case SBT_VER_QUAD_POS1_SPLIT:
      case SBT_HOR_QUAD_POS0_SPLIT:
      case SBT_HOR_QUAD_POS1_SPLIT:
        return currTrDepth == 0;
        break;
    #endif
    
    Adam Wieckowski's avatar
    Adam Wieckowski committed
    #if JVET_M0421_SPLIT_SIG
      case CU_QUAD_SPLIT:
        return canQt;
      case CU_DONT_SPLIT:
        return canNo;
      case CU_HORZ_SPLIT:
        return canBh;
      case CU_VERT_SPLIT:
        return canBv;
      case CU_TRIH_SPLIT:
        return canTh;
      case CU_TRIV_SPLIT:
        return canTv;
    #else
    
      case CU_QUAD_SPLIT:
      {
        // don't allow QT-splitting below a BT split
        PartSplit lastSplit = m_partStack.back().split;
        if( lastSplit != CTU_LEVEL && lastSplit != CU_QUAD_SPLIT )                  return false;
    
        unsigned minQtSize = cs.pcv->getMinQtSize( *cs.slice, chType );
        if( currArea().lwidth() <= minQtSize || currArea().lheight() <= minQtSize ) return false;
    
        // allowing QT split even if a BT split is implied
        if( implicitSplit != CU_DONT_SPLIT )                                        return true;
    
        return true;
      }
      break;
      case CU_DONT_SPLIT:
        return implicitSplit == CU_DONT_SPLIT;
        break;
      // general check for BT split, specific checks are done in a separate switch
      case CU_HORZ_SPLIT:
      case CU_VERT_SPLIT:
      {
        if( ( lastSplit == CU_TRIH_SPLIT || lastSplit == CU_TRIV_SPLIT ) && currPartIdx() == 1 && split == parlSplit )
        {
          return false;
        }
        if (CS::isDualITree(cs) && (area.width > 64 || area.height > 64))
        {
          return false;
        }
      }
      case CU_TRIH_SPLIT:
      case CU_TRIV_SPLIT:
      {
        if (CS::isDualITree(cs) && (area.width > 64 || area.height > 64))
        {
          return false;
        }
      }
        if( implicitSplit == split )                                   return true;
        if( implicitSplit != CU_DONT_SPLIT && implicitSplit != split ) return false;
    
    Adam Wieckowski's avatar
    Adam Wieckowski committed
    #endif
    
    Adam Wieckowski's avatar
    Adam Wieckowski committed
    #if JVET_M0421_SPLIT_SIG
        return ( canBh || canTh || canBv || canTv );
    #endif
    
    Adam Wieckowski's avatar
    Adam Wieckowski committed
    #if JVET_M0421_SPLIT_SIG
        return ( canBh || canBv );
    #else
    
      {
        if( currMtDepth >= maxBTD )                               return false;
        if(      ( area.width <= minBtSize && area.height <= minBtSize )
    
            && ( ( area.width <= minTtSize && area.height <= minTtSize ) ) ) return false;
    
        if(      ( area.width > maxBtSize || area.height > maxBtSize )
    
            && ( ( area.width > maxTtSize || area.height > maxTtSize ) ) ) return false;
    
        if (CS::isDualITree(cs) && (area.width > 64 || area.height > 64))
        {
          return false;
        }
      }
    
    Adam Wieckowski's avatar
    Adam Wieckowski committed
    #endif
    
      break;
      default:
        THROW( "Unknown split mode" );
        return false;
        break;
      }
    
    Adam Wieckowski's avatar
    Adam Wieckowski committed
    #if !JVET_M0421_SPLIT_SIG
    
      // specific check for BT splits
      switch( split )
      {
      case CU_HORZ_SPLIT:
        if( area.height <= minBtSize || area.height > maxBtSize )     return false;
    
        if( area.width > MAX_TB_SIZEY && area.height <= MAX_TB_SIZEY ) return false;
    
        break;
      case CU_VERT_SPLIT:
        if( area.width <= minBtSize || area.width > maxBtSize )       return false;
    
        if( area.width <= MAX_TB_SIZEY && area.height > MAX_TB_SIZEY ) return false;
    
        if( area.height <= 2 * minTtSize || area.height > maxTtSize || area.width > maxTtSize) return false;
    
        if( area.width > MAX_TB_SIZEY || area.height > MAX_TB_SIZEY ) return false;
    
        if( area.width <= 2 * minTtSize || area.width > maxTtSize || area.height > maxTtSize)  return false;
    
        if( area.width > MAX_TB_SIZEY || area.height > MAX_TB_SIZEY ) return false;
    
    Adam Wieckowski's avatar
    Adam Wieckowski committed
    #endif
    
    
      return true;
    }
    
    bool QTBTPartitioner::isSplitImplicit( const PartSplit split, const CodingStructure &cs )
    {
      return split == getImplicitSplit( cs );
    }
    
    PartSplit QTBTPartitioner::getImplicitSplit( const CodingStructure &cs )
    {
      if( m_partStack.back().checkdIfImplicit )
      {
        return m_partStack.back().implicitSplit;
      }
    
      PartSplit split = CU_DONT_SPLIT;
    
      if( split == CU_DONT_SPLIT )
      {
        const bool isBlInPic = cs.picture->Y().contains( currArea().Y().bottomLeft() );
        const bool isTrInPic = cs.picture->Y().contains( currArea().Y().topRight() );
    
        const CompArea& area      = currArea().Y();
        const unsigned maxBtSize  = cs.pcv->getMaxBtSize( *cs.slice, chType );
        const bool isBtAllowed    = area.width <= maxBtSize && area.height <= maxBtSize;
        const unsigned minQtSize  = cs.pcv->getMinQtSize( *cs.slice, chType );
        const bool isQtAllowed    = area.width >  minQtSize && area.height >  minQtSize && currBtDepth == 0;
    
        if( !isBlInPic && !isTrInPic && isQtAllowed )
        {
          split = CU_QUAD_SPLIT;
        }
        else if( !isBlInPic && isBtAllowed )
        {
          split = CU_HORZ_SPLIT;
        }
        else if( !isTrInPic && isBtAllowed )
        {
          split = CU_VERT_SPLIT;
        }
        else if( !isBlInPic || !isTrInPic )
        {
          split = CU_QUAD_SPLIT;
        }
        if (CS::isDualITree(cs) && (currArea().Y().width > 64 || currArea().Y().height > 64))
        {
          split = CU_QUAD_SPLIT;
        }
    
    #if JVET_M0446_M0888_M0905_VPDU_AT_PIC_BOUNDARY
    
        if ((!isBlInPic || !isTrInPic) && (currArea().Y().width > MAX_TB_SIZEY || currArea().Y().height > MAX_TB_SIZEY))
    
      }
    
      m_partStack.back().checkdIfImplicit = true;
      m_partStack.back().isImplicit = split != CU_DONT_SPLIT;
      m_partStack.back().implicitSplit = split;
    
      return split;
    }
    
    void QTBTPartitioner::exitCurrSplit()
    {
      PartSplit currSplit = m_partStack.back().split;
      unsigned  currIdx = m_partStack.back().idx;
    
      m_partStack.pop_back();
    
      CHECK( currDepth == 0, "depth is '0', although a split was performed" );
      currDepth--;
    
    #if JVET_M0113_M0188_QG_SIZE
      currSubdiv--;
    #endif
    
    #if _DEBUG
      m_currArea = m_partStack.back().parts[m_partStack.back().idx];
    #endif
    
      if( currSplit == CU_HORZ_SPLIT || currSplit == CU_VERT_SPLIT || currSplit == CU_TRIH_SPLIT || currSplit == CU_TRIV_SPLIT )
      {
        CHECK( !m_partStack.back().checkdIfImplicit, "Didn't check if the current split is implicit" );
        CHECK( currBtDepth == 0, "BT depth is '0', athough a BT split was performed" );
        CHECK( currMtDepth == 0, "MT depth is '0', athough a BT split was performed" );
        currMtDepth--;
        if( m_partStack.back().isImplicit ) currImplicitBtDepth--;
        currBtDepth--;
        if( ( currSplit == CU_TRIH_SPLIT || currSplit == CU_TRIV_SPLIT ) && currIdx != 1 )
        {
          CHECK( currBtDepth == 0, "BT depth is '0', athough a TT split was performed" );
          currBtDepth--;
    
    #if JVET_M0113_M0188_QG_SIZE
          currSubdiv--;
    #endif
    
        }
      }
      else if( currSplit == TU_MAX_TR_SPLIT )
      {
        CHECK( currTrDepth == 0, "TR depth is '0', although a TU split was performed" );
        currTrDepth--;
      }
    
    #if JVET_M0140_SBT
      else if( currSplit >= SBT_VER_HALF_POS0_SPLIT && currSplit <= SBT_HOR_QUAD_POS1_SPLIT )
      {
        CHECK( currTrDepth == 0, "TR depth is '0', although a TU split was performed" );
        currTrDepth--;
      }
    #endif
    
      else
      {
        CHECK( currTrDepth > 0, "RQT found with QTBT partitioner" );
    
        CHECK( currQtDepth == 0, "QT depth is '0', although a QT split was performed" );
        currQtDepth--;
    
    #if JVET_M0113_M0188_QG_SIZE
        currSubdiv--;
    #endif
    
      }
    }
    
    bool QTBTPartitioner::nextPart( const CodingStructure &cs, bool autoPop /*= false*/ )
    {
      const Position &prevPos = currArea().blocks[chType].pos();
    
      unsigned currIdx = ++m_partStack.back().idx;
    
      m_partStack.back().checkdIfImplicit = false;
      m_partStack.back().isImplicit = false;
    
      if( currIdx == 1 )
      {
        const CodingUnit* prevCU = cs.getCU( prevPos, chType );
        m_partStack.back().firstSubPartSplit = prevCU ? CU::getSplitAtDepth( *prevCU, currDepth ) : CU_DONT_SPLIT;
      }
    
      if( currIdx < m_partStack.back().parts.size() )
      {
        if( m_partStack.back().split == CU_TRIH_SPLIT || m_partStack.back().split == CU_TRIV_SPLIT )
        {
          // adapt the current bt depth
          if( currIdx == 1 ) currBtDepth--;
          else               currBtDepth++;
    
    #if JVET_M0113_M0188_QG_SIZE
          if( currIdx == 1 ) currSubdiv--;
          else               currSubdiv++;
    #endif
    
        }
    #if _DEBUG
        m_currArea = m_partStack.back().parts[currIdx];
    #endif
        return true;
      }
      else
      {
        if( autoPop ) exitCurrSplit();
        return false;
      }
    }
    
    bool QTBTPartitioner::hasNextPart()
    {
      return ( ( m_partStack.back().idx + 1 ) < m_partStack.back().parts.size() );
    }
    
    
    #if JVET_M0102_INTRA_SUBPARTITIONS
    void TUIntraSubPartitioner::splitCurrArea( const PartSplit split, const CodingStructure& cs )
    {
      switch( split )
      {
        case TU_1D_HORZ_SPLIT:
        case TU_1D_VERT_SPLIT:
        {
          const UnitArea &area = currArea();
          m_partStack.push_back( PartLevel() );
          m_partStack.back().split = split;
          PartitionerImpl::getTUIntraSubPartitions( m_partStack.back().parts, area, cs, split );
          break;
        }
        case TU_MAX_TR_SPLIT: //we need this non ISP split because of the maxTrSize limitation
          m_partStack.push_back( PartLevel( split, PartitionerImpl::getMaxTuTiling( currArea(), cs ) ) );
          break;
        default:
          THROW( "Unknown ISP split mode" );
          break;
      }
    
      currDepth++;
      currTrDepth++; // we need this to identify the level. since the 1d partitions are forbidden if the RQT is on, there area no compatibility issues
    
    #if _DEBUG
      m_currArea = m_partStack.back().parts.front();
    #endif
    }
    
    void TUIntraSubPartitioner::exitCurrSplit()
    {
      PartSplit currSplit = m_partStack.back().split;
    
      m_partStack.pop_back();
    
      CHECK( currDepth == 0, "depth is '0', although a split was performed" );
    
      currDepth--;
      currTrDepth--;
    
    #if _DEBUG
      m_currArea = m_partStack.back().parts[m_partStack.back().idx];
    #endif
    
      CHECK( !( currSplit == TU_1D_HORZ_SPLIT || currSplit == TU_1D_VERT_SPLIT || currSplit == TU_MAX_TR_SPLIT ), "Unknown 1D partition split type!" );
    }
    
    bool TUIntraSubPartitioner::nextPart( const CodingStructure &cs, bool autoPop /*= false*/ )
    {
      unsigned currIdx = ++m_partStack.back().idx;
    
      m_partStack.back().checkdIfImplicit = false;
      m_partStack.back().isImplicit = false;
    
      if( currIdx < m_partStack.back().parts.size() )
      {
    #if _DEBUG
        m_currArea = m_partStack.back().parts[m_partStack.back().idx];
    #endif
        return true;
      }
      else
      {
        if( autoPop ) exitCurrSplit();
        return false;
      }
    }
    
    bool TUIntraSubPartitioner::hasNextPart()
    {
      return ( ( m_partStack.back().idx + 1 ) < m_partStack.back().parts.size() );
    }
    
    bool TUIntraSubPartitioner::canSplit( const PartSplit split, const CodingStructure &cs )
    {
      //const PartSplit implicitSplit = getImplicitSplit(cs);
      const UnitArea &area = currArea();
    
      switch( split )
      {
        case TU_1D_HORZ_SPLIT:
        {
          return area.lheight() == m_partStack[0].parts[0].lheight();
        }
        case TU_1D_VERT_SPLIT:
        {
          return area.lwidth() == m_partStack[0].parts[0].lwidth();
        }
        case TU_MAX_TR_SPLIT:
        {
          //this split is performed implicitly with the other splits
          return false;
        }
        default:
          THROW( "Unknown 1-D split mode" );
          break;
      }
    }
    #endif
    
    
    
    //////////////////////////////////////////////////////////////////////////
    // PartitionerFactory
    //////////////////////////////////////////////////////////////////////////
    
    Partitioner* PartitionerFactory::get( const Slice& slice )
    {
    
    Karsten Suehring's avatar
    Karsten Suehring committed
      return new QTBTPartitioner;
    
    }
    
    //////////////////////////////////////////////////////////////////////////
    // Partitioner methods describing the actual partitioning logic
    //////////////////////////////////////////////////////////////////////////
    
    Partitioning PartitionerImpl::getCUSubPartitions( const UnitArea &cuArea, const CodingStructure &cs, const PartSplit _splitType /*= CU_QUAD_SPLIT*/ )
    {
      const PartSplit splitType = _splitType;
    
      if( splitType == CU_QUAD_SPLIT )
      {
        if( !cs.pcv->noChroma2x2 )
        {
          Partitioning sub;
    
          sub.resize( 4, cuArea );
    
          for( uint32_t i = 0; i < 4; i++ )
          {
            for( auto &blk : sub[i].blocks )
            {
              blk.height >>= 1;
              blk.width  >>= 1;
              if( i >= 2 ) blk.y += blk.height;
              if( i &  1 ) blk.x += blk.width;
            }
    
    
            CHECK( sub[i].lumaSize().height < MIN_TB_SIZEY, "the split causes the block to be smaller than the minimal TU size" );
    
          }
    
          return sub;
        }
        else
        {
          const uint32_t minCUSize = ( cs.sps->getMaxCUWidth() >> cs.sps->getMaxCodingDepth() );
    
          bool canSplit = cuArea.lumaSize().width > minCUSize && cuArea.lumaSize().height > minCUSize;
    
          Partitioning ret;
    
          if( cs.slice->getSliceType() == I_SLICE )
          {
            canSplit &= cuArea.lumaSize().width > cs.pcv->minCUWidth && cuArea.lumaSize().height > cs.pcv->minCUHeight;
          }
    
          if( canSplit )
          {
            ret.resize( 4 );
    
            if( cuArea.chromaFormat == CHROMA_400 )
            {
              CompArea  blkY = cuArea.Y();
              blkY.width >>= 1;
              blkY.height >>= 1;
              ret[0]  = UnitArea( cuArea.chromaFormat, blkY );
              blkY.x += blkY.width;
              ret[1]  = UnitArea( cuArea.chromaFormat, blkY );
              blkY.x -= blkY.width;
              blkY.y += blkY.height;
              ret[2]  = UnitArea( cuArea.chromaFormat, blkY );
              blkY.x += blkY.width;
              ret[3]  = UnitArea( cuArea.chromaFormat, blkY );
            }
            else
            {
              for( uint32_t i = 0; i < 4; i++ )
              {
                ret[i] = cuArea;
    
                CompArea &blkY  = ret[i].Y();
                CompArea &blkCb = ret[i].Cb();
                CompArea &blkCr = ret[i].Cr();
    
                blkY.width  /= 2;
                blkY.height /= 2;
    
                // TODO: get those params from SPS
                if( blkCb.width > 4 )
                {
                  blkCb.width  /= 2;
                  blkCb.height /= 2;
                  blkCr.width  /= 2;
                  blkCr.height /= 2;
                }
                else if( i > 0 )
                {
                  blkCb = CompArea();
                  blkCr = CompArea();
                }
    
                if( ( i & 1 ) == 1 )
                {
                  blkY.x  += blkY .width;
                  blkCb.x += blkCb.width;
                  blkCr.x += blkCr.width;
                }
    
                if( i > 1 )
                {
                  blkY.y  += blkY .height;
                  blkCb.y += blkCb.height;
                  blkCr.y += blkCr.height;
                }
              }
            }
          }
    
          return ret;
        }
      }
      else if( splitType == CU_HORZ_SPLIT )
      {
        Partitioning sub;
    
        sub.resize(2, cuArea);
    
        for (uint32_t i = 0; i < 2; i++)
        {
          for (auto &blk : sub[i].blocks)
          {
            blk.height >>= 1;
            if (i == 1) blk.y += blk.height;
          }
    
    
          CHECK(sub[i].lumaSize().height < MIN_TB_SIZEY, "the cs split causes the block to be smaller than the minimal TU size");