Skip to content
Snippets Groups Projects
CABACWriter.cpp 139 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     CABACWriter.cpp
     *  \brief    Writer for low level syntax
     */
    
    #include "CommonLib/Contexts.h"
    #include "CABACWriter.h"
    
    #include "EncLib.h"
    
    #include "CommonLib/UnitTools.h"
    #include "CommonLib/dtrace_buffer.h"
    
    #include <map>
    #include <algorithm>
    #include <limits>
    
    
    //! \ingroup EncoderLib
    //! \{
    
    void CABACWriter::initCtxModels( const Slice& slice )
    {
      int       qp                = slice.getSliceQp();
      SliceType sliceType         = slice.getSliceType();
      SliceType encCABACTableIdx  = slice.getEncCABACTableIdx();
      if( !slice.isIntra() && (encCABACTableIdx==B_SLICE || encCABACTableIdx==P_SLICE) && slice.getPPS()->getCabacInitPresentFlag() )
      {
        sliceType = encCABACTableIdx;
      }
      m_BinEncoder.reset( qp, (int)sliceType );
    }
    
    
    
    template <class BinProbModel>
    SliceType xGetCtxInitId( const Slice& slice, const BinEncIf& binEncoder, Ctx& ctxTest )
    {
      const CtxStore<BinProbModel>& ctxStoreTest = static_cast<const CtxStore<BinProbModel>&>( ctxTest );
      const CtxStore<BinProbModel>& ctxStoreRef  = static_cast<const CtxStore<BinProbModel>&>( binEncoder.getCtx() );
      int qp = slice.getSliceQp();
      if( !slice.isIntra() )
      {
        SliceType aSliceTypeChoices[] = { B_SLICE, P_SLICE };
        uint64_t  bestCost            = std::numeric_limits<uint64_t>::max();
        SliceType bestSliceType       = aSliceTypeChoices[0];
        for (uint32_t idx=0; idx<2; idx++)
        {
          uint64_t  curCost           = 0;
          SliceType curSliceType      = aSliceTypeChoices[idx];
          ctxTest.init( qp, (int)curSliceType );
          for( int k = 0; k < Ctx::NumberOfContexts; k++ )
          {
            if( binEncoder.getNumBins(k) > 0 )
            {
              curCost += uint64_t( binEncoder.getNumBins(k) ) * ctxStoreRef[k].estFracExcessBits( ctxStoreTest[k] );
            }
          }
          if (curCost < bestCost)
          {
            bestSliceType = curSliceType;
            bestCost      = curCost;
          }
        }
        return bestSliceType;
      }
      else
      {
        return I_SLICE;
      }
    }
    
    
    SliceType CABACWriter::getCtxInitId( const Slice& slice )
    {
      switch( m_TestCtx.getBPMType() )
      {
      case BPM_Std:   return  xGetCtxInitId<BinProbModel_Std>   ( slice, m_BinEncoder, m_TestCtx );
      default:        return  NUMBER_OF_SLICE_TYPES;
      }
    }
    
    
    
    unsigned estBits( BinEncIf& binEnc, const std::vector<bool>& bins, const Ctx& ctx, const int ctxId, const uint8_t winSize )
    {
      binEnc.initCtxAndWinSize( ctxId, ctx, winSize );
      binEnc.start();
      const std::size_t numBins   = bins.size();
      unsigned          startBits = binEnc.getNumWrittenBits();
      for( std::size_t binId = 0; binId < numBins; binId++ )
      {
        unsigned  bin = ( bins[binId] ? 1 : 0 );
        binEnc.encodeBin( bin, ctxId );
      }
      unsigned endBits    = binEnc.getNumWrittenBits();
      unsigned codedBits  = endBits - startBits;
      return   codedBits;
    }
    
    
    
    
    
    //================================================================================
    //  clause 7.3.8.1
    //--------------------------------------------------------------------------------
    //    void  end_of_slice()
    //================================================================================
    
    void CABACWriter::end_of_slice()
    {
      m_BinEncoder.encodeBinTrm ( 1 );
      m_BinEncoder.finish       ();
    }
    
    
    
    
    //================================================================================
    //  clause 7.3.8.2
    //--------------------------------------------------------------------------------
    
    //    bool  coding_tree_unit( cs, area, qp, ctuRsAddr, skipSao, skipAlf )
    
    //================================================================================
    
    
    void CABACWriter::coding_tree_unit( CodingStructure& cs, const UnitArea& area, int (&qps)[2], unsigned ctuRsAddr, bool skipSao /* = false */, bool skipAlf /* = false */ )
    
    {
      CUCtx cuCtx( qps[CH_L] );
      Partitioner *partitioner = PartitionerFactory::get( *cs.slice );
    
      partitioner->initCtu( area, CH_L, *cs.slice );
    
      if( !skipSao )
      {
        sao( *cs.slice, ctuRsAddr );
      }
    
    
      if (!skipAlf)
    
        for (int compIdx = 0; compIdx < MAX_NUM_COMPONENT; compIdx++)
    
          codeAlfCtuEnableFlag(cs, ctuRsAddr, compIdx, NULL);
          if (isLuma(ComponentID(compIdx)))
          {
            codeAlfCtuFilterIndex(cs, ctuRsAddr, cs.slice->getTileGroupAlfEnabledFlag(COMPONENT_Y));
          }
    
    #if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB
          if (isChroma(ComponentID(compIdx)))
          {
            uint8_t* ctbAlfFlag = cs.slice->getTileGroupAlfEnabledFlag((ComponentID)compIdx) ? cs.slice->getPic()->getAlfCtuEnableFlag( compIdx ) : nullptr;
            if( ctbAlfFlag && ctbAlfFlag[ctuRsAddr] )
            {
              codeAlfCtuAlternative( cs, ctuRsAddr, compIdx );
            }
          }
    #endif
    
      if ( CS::isDualITree(cs) && cs.pcv->chrFormat != CHROMA_400 && cs.pcv->maxCUWidth > 64 )
    
      {
        CUCtx chromaCuCtx(qps[CH_C]);
        Partitioner *chromaPartitioner = PartitionerFactory::get(*cs.slice);
        chromaPartitioner->initCtu(area, CH_C, *cs.slice);
        coding_tree(cs, *partitioner, cuCtx, chromaPartitioner, &chromaCuCtx);
        qps[CH_L] = cuCtx.qp;
        qps[CH_C] = chromaCuCtx.qp;
    
        delete chromaPartitioner;
      }
      else
      {
    
        coding_tree( cs, *partitioner, cuCtx );
        qps[CH_L] = cuCtx.qp;
        if( CS::isDualITree( cs ) && cs.pcv->chrFormat != CHROMA_400 )
        {
          CUCtx cuCtxChroma( qps[CH_C] );
          partitioner->initCtu( area, CH_C, *cs.slice );
          coding_tree( cs, *partitioner, cuCtxChroma );
          qps[CH_C] = cuCtxChroma.qp;
        }
    
    
      delete partitioner;
    }
    
    
    
    
    
    //================================================================================
    //  clause 7.3.8.3
    //--------------------------------------------------------------------------------
    //    void  sao             ( slice, ctuRsAddr )
    //    void  sao_block_pars  ( saoPars, bitDepths, sliceEnabled, leftMergeAvail, aboveMergeAvail, onlyEstMergeInfo )
    //    void  sao_offset_pars ( ctbPars, compID, sliceEnabled, bitDepth )
    //================================================================================
    
    void CABACWriter::sao( const Slice& slice, unsigned ctuRsAddr )
    {
      const SPS& sps = *slice.getSPS();
    
      if( !sps.getSAOEnabledFlag() )
    
      {
        return;
      }
    
      CodingStructure&     cs                     = *slice.getPic()->cs;
      const PreCalcValues& pcv                    = *cs.pcv;
      const SAOBlkParam&  sao_ctu_pars            = cs.picture->getSAO()[ctuRsAddr];
      bool                slice_sao_luma_flag     = ( slice.getSaoEnabledFlag( CHANNEL_TYPE_LUMA ) );
      bool                slice_sao_chroma_flag   = ( slice.getSaoEnabledFlag( CHANNEL_TYPE_CHROMA ) && sps.getChromaFormatIdc() != CHROMA_400 );
      if( !slice_sao_luma_flag && !slice_sao_chroma_flag )
      {
        return;
      }
    
      bool                sliceEnabled[3]         = { slice_sao_luma_flag, slice_sao_chroma_flag, slice_sao_chroma_flag };
      int                 frame_width_in_ctus     = pcv.widthInCtus;
      int                 ry                      = ctuRsAddr      / frame_width_in_ctus;
      int                 rx                      = ctuRsAddr - ry * frame_width_in_ctus;
      const Position      pos                     ( rx * cs.pcv->maxCUWidth, ry * cs.pcv->maxCUHeight );
      const unsigned      curSliceIdx             = slice.getIndependentSliceIdx();
    
    Karsten Suehring's avatar
    Karsten Suehring committed
      const unsigned      curTileIdx              = cs.picture->brickMap->getBrickIdxRsMap( pos );
    
      bool                leftMergeAvail          = cs.getCURestricted( pos.offset( -(int)pcv.maxCUWidth, 0  ), pos, curSliceIdx, curTileIdx, CH_L ) ? true : false;
      bool                aboveMergeAvail         = cs.getCURestricted( pos.offset( 0, -(int)pcv.maxCUHeight ), pos, curSliceIdx, curTileIdx, CH_L ) ? true : false;
    
      sao_block_pars( sao_ctu_pars, sps.getBitDepths(), sliceEnabled, leftMergeAvail, aboveMergeAvail, false );
    }
    
    
    void CABACWriter::sao_block_pars( const SAOBlkParam& saoPars, const BitDepths& bitDepths, bool* sliceEnabled, bool leftMergeAvail, bool aboveMergeAvail, bool onlyEstMergeInfo )
    {
      bool isLeftMerge  = false;
      bool isAboveMerge = false;
      if( leftMergeAvail )
      {
        // sao_merge_left_flag
        isLeftMerge   = ( saoPars[COMPONENT_Y].modeIdc == SAO_MODE_MERGE && saoPars[COMPONENT_Y].typeIdc == SAO_MERGE_LEFT );
        m_BinEncoder.encodeBin( (isLeftMerge), Ctx::SaoMergeFlag() );
      }
      if( aboveMergeAvail && !isLeftMerge )
      {
        // sao_merge_above_flag
        isAboveMerge  = ( saoPars[COMPONENT_Y].modeIdc == SAO_MODE_MERGE && saoPars[COMPONENT_Y].typeIdc == SAO_MERGE_ABOVE );
        m_BinEncoder.encodeBin( (isAboveMerge), Ctx::SaoMergeFlag() );
      }
      if( onlyEstMergeInfo )
      {
        return; //only for RDO
      }
      if( !isLeftMerge && !isAboveMerge )
      {
        // explicit parameters
        for( int compIdx=0; compIdx < MAX_NUM_COMPONENT; compIdx++ )
        {
          sao_offset_pars( saoPars[compIdx], ComponentID(compIdx), sliceEnabled[compIdx], bitDepths.recon[ toChannelType(ComponentID(compIdx)) ] );
        }
      }
    }
    
    
    void CABACWriter::sao_offset_pars( const SAOOffset& ctbPars, ComponentID compID, bool sliceEnabled, int bitDepth )
    {
      if( !sliceEnabled )
      {
        CHECK( ctbPars.modeIdc != SAO_MODE_OFF, "Sao must be off, if it is disabled on slice level" );
        return;
      }
      const bool isFirstCompOfChType = ( getFirstComponentOfChannel( toChannelType(compID) ) == compID );
    
      if( isFirstCompOfChType )
      {
        // sao_type_idx_luma / sao_type_idx_chroma
        if( ctbPars.modeIdc == SAO_MODE_OFF )
        {
          m_BinEncoder.encodeBin  ( 0, Ctx::SaoTypeIdx() );
        }
        else if( ctbPars.typeIdc == SAO_TYPE_BO )
        {
          m_BinEncoder.encodeBin  ( 1, Ctx::SaoTypeIdx() );
          m_BinEncoder.encodeBinEP( 0 );
        }
        else
        {
          CHECK(!( ctbPars.typeIdc < SAO_TYPE_START_BO ), "Unspecified error");
          m_BinEncoder.encodeBin  ( 1, Ctx::SaoTypeIdx() );
          m_BinEncoder.encodeBinEP( 1 );
        }
      }
    
      if( ctbPars.modeIdc == SAO_MODE_NEW )
      {
        const int maxOffsetQVal = SampleAdaptiveOffset::getMaxOffsetQVal( bitDepth );
        int       numClasses    = ( ctbPars.typeIdc == SAO_TYPE_BO ? 4 : NUM_SAO_EO_CLASSES );
        int       k             = 0;
        int       offset[4];
        for( int i = 0; i < numClasses; i++ )
        {
          if( ctbPars.typeIdc != SAO_TYPE_BO && i == SAO_CLASS_EO_PLAIN )
          {
            continue;
          }
          int classIdx = ( ctbPars.typeIdc == SAO_TYPE_BO ? ( ctbPars.typeAuxInfo + i ) % NUM_SAO_BO_CLASSES : i );
          offset[k++]  = ctbPars.offset[classIdx];
        }
    
        // sao_offset_abs
        for( int i = 0; i < 4; i++ )
        {
          unsigned absOffset = ( offset[i] < 0 ? -offset[i] : offset[i] );
          unary_max_eqprob( absOffset, maxOffsetQVal );
        }
    
        // band offset mode
        if( ctbPars.typeIdc == SAO_TYPE_BO )
        {
          // sao_offset_sign
          for( int i = 0; i < 4; i++ )
          {
            if( offset[i] )
            {
              m_BinEncoder.encodeBinEP( (offset[i] < 0) );
            }
          }
          // sao_band_position
          m_BinEncoder.encodeBinsEP( ctbPars.typeAuxInfo, NUM_SAO_BO_CLASSES_LOG2 );
        }
        // edge offset mode
        else
        {
          if( isFirstCompOfChType )
          {
            // sao_eo_class_luma / sao_eo_class_chroma
            CHECK( ctbPars.typeIdc - SAO_TYPE_START_EO < 0, "sao edge offset class is outside valid range" );
            m_BinEncoder.encodeBinsEP( ctbPars.typeIdc - SAO_TYPE_START_EO, NUM_SAO_EO_TYPES_LOG2 );
          }
        }
      }
    }
    
    
    
    //================================================================================
    //  clause 7.3.8.4
    //--------------------------------------------------------------------------------
    //    void  coding_tree       ( cs, partitioner, cuCtx )
    //    void  split_cu_flag     ( split, cs, partitioner )
    //    void  split_cu_mode_mt  ( split, cs, partitioner )
    //================================================================================
    
    void CABACWriter::coding_tree(const CodingStructure& cs, Partitioner& partitioner, CUCtx& cuCtx, Partitioner* pPartitionerChroma, CUCtx* pCuCtxChroma)
    {
      const PPS      &pps         = *cs.pps;
      const UnitArea &currArea    = partitioner.currArea();
      const CodingUnit &cu        = *cs.getCU( currArea.blocks[partitioner.chType], partitioner.chType );
    
      // Reset delta QP coding flag and ChromaQPAdjustemt coding flag
    
      if( pps.getUseDQP() && partitioner.currQgEnable() )
      {
        cuCtx.qgStart    = true;
        cuCtx.isDQPCoded          = false;
      }
      if( cs.slice->getUseChromaQpAdj() && partitioner.currQgChromaEnable() )
    
      {
        cuCtx.isChromaQpAdjCoded  = false;
      }
      // Reset delta QP coding flag and ChromaQPAdjustemt coding flag
    
    #if JVET_O0050_LOCAL_DUAL_TREE
      if (partitioner.isSepTree(cs) && pPartitionerChroma != nullptr)
    #else
    
      if (CS::isDualITree(cs) && pPartitionerChroma != nullptr)
    
        if (pps.getUseDQP() && pPartitionerChroma->currQgEnable())
        {
          pCuCtxChroma->qgStart    = true;
          pCuCtxChroma->isDQPCoded = false;
        }
        if (cs.slice->getUseChromaQpAdj() && pPartitionerChroma->currQgChromaEnable())
    
    Adam Wieckowski's avatar
    Adam Wieckowski committed
      const PartSplit splitMode = CU::getSplitAtDepth( cu, partitioner.currDepth );
    
      split_cu_mode( splitMode, cs, partitioner );
    
      CHECK( !partitioner.canSplit( splitMode, cs ), "The chosen split mode is invalid!" );
    
      if( splitMode != CU_DONT_SPLIT )
      {
    
          if (CS::isDualITree(cs) && pPartitionerChroma != nullptr && (partitioner.currArea().lwidth() >= 64 || partitioner.currArea().lheight() >= 64))
          {
            partitioner.splitCurrArea(CU_QUAD_SPLIT, cs);
            pPartitionerChroma->splitCurrArea(CU_QUAD_SPLIT, cs);
            bool beContinue = true;
            bool lumaContinue = true;
            bool chromaContinue = true;
    
            while (beContinue)
            {
              if (partitioner.currArea().lwidth() > 64 || partitioner.currArea().lheight() > 64)
              {
                if (cs.picture->blocks[partitioner.chType].contains(partitioner.currArea().blocks[partitioner.chType].pos()))
                {
                  coding_tree(cs, partitioner, cuCtx, pPartitionerChroma, pCuCtxChroma);
                }
                lumaContinue = partitioner.nextPart(cs);
                chromaContinue = pPartitionerChroma->nextPart(cs);
                CHECK(lumaContinue != chromaContinue, "luma chroma partition should be matched");
                beContinue = lumaContinue;
              }
              else
              {
                //dual tree coding under 64x64 block
                if (cs.picture->blocks[partitioner.chType].contains(partitioner.currArea().blocks[partitioner.chType].pos()))
                {
                  coding_tree(cs, partitioner, cuCtx);
                }
                lumaContinue = partitioner.nextPart(cs);
                if (cs.picture->blocks[pPartitionerChroma->chType].contains(pPartitionerChroma->currArea().blocks[pPartitionerChroma->chType].pos()))
                {
                  coding_tree(cs, *pPartitionerChroma, *pCuCtxChroma);
                }
                chromaContinue = pPartitionerChroma->nextPart(cs);
                CHECK(lumaContinue != chromaContinue, "luma chroma partition should be matched");
                beContinue = lumaContinue;
              }
            }
            partitioner.exitCurrSplit();
            pPartitionerChroma->exitCurrSplit();
    
          }
          else
          {
    
    #if JVET_O0050_LOCAL_DUAL_TREE
            const ModeType modeTypeParent = partitioner.modeType;
            const ModeType modeTypeChild = CU::getModeTypeAtDepth( cu, partitioner.currDepth );
            mode_constraint( splitMode, cs, partitioner, modeTypeChild );
            partitioner.modeType = modeTypeChild;
    
            bool chromaNotSplit = modeTypeParent == MODE_TYPE_ALL && modeTypeChild == MODE_TYPE_INTRA ? true : false;
            CHECK( chromaNotSplit && partitioner.chType != CHANNEL_TYPE_LUMA, "chType must be luma" );
            if( partitioner.treeType == TREE_D )
            {
              partitioner.treeType = chromaNotSplit ? TREE_L : TREE_D;
            }
    #endif
    
    Adam Wieckowski's avatar
    Adam Wieckowski committed
          partitioner.splitCurrArea( splitMode, cs );
    
    
          do
          {
            if( cs.picture->blocks[partitioner.chType].contains( partitioner.currArea().blocks[partitioner.chType].pos() ) )
            {
              coding_tree( cs, partitioner, cuCtx );
            }
          } while( partitioner.nextPart( cs ) );
    
          partitioner.exitCurrSplit();
    
    #if JVET_O0050_LOCAL_DUAL_TREE
          if( chromaNotSplit )
          {
            CHECK( partitioner.chType != CHANNEL_TYPE_LUMA, "must be luma status" );
            partitioner.chType = CHANNEL_TYPE_CHROMA;
            partitioner.treeType = TREE_C;
    
            if( cs.picture->blocks[partitioner.chType].contains( partitioner.currArea().blocks[partitioner.chType].pos() ) )
            {
              coding_tree( cs, partitioner, cuCtx );
            }
    
            //recover
            partitioner.chType = CHANNEL_TYPE_LUMA;
            partitioner.treeType = TREE_D;
          }
          partitioner.modeType = modeTypeParent;
    #endif
    
      if( cuCtx.qgStart )
      {
        cuCtx.qgStart = false;
    
    #if JVET_O0050_LOCAL_DUAL_TREE
      CHECK( cu.treeType != partitioner.treeType, "treeType mismatch" );
    #endif
    
    
    
      // coding unit
      coding_unit( cu, partitioner, cuCtx );
    
      DTRACE_COND( ( isEncoding() ), g_trace_ctx, D_QP, "x=%d, y=%d, w=%d, h=%d, qp=%d\n", cu.Y().x, cu.Y().y, cu.Y().width, cu.Y().height, cu.qp );
      DTRACE_BLOCK_REC_COND( ( !isEncoding() ), cs.picture->getRecoBuf( cu ), cu, cu.predMode );
    }
    
    
    #if JVET_O0050_LOCAL_DUAL_TREE
    void CABACWriter::mode_constraint( const PartSplit split, const CodingStructure& cs, Partitioner& partitioner, const ModeType modeType )
    {
      CHECK( split == CU_DONT_SPLIT, "splitMode shall not be no split" );
      int val = cs.signalModeCons( split, partitioner, partitioner.modeType );
    
      if( val == LDT_MODE_TYPE_SIGNAL )
    
      {
        CHECK( modeType == MODE_TYPE_ALL, "shall not be no constraint case" );
        bool flag = modeType == MODE_TYPE_INTRA;
        int ctxIdx = DeriveCtx::CtxModeConsFlag( cs, partitioner );
        m_BinEncoder.encodeBin( flag, Ctx::ModeConsFlag( ctxIdx ) );
        DTRACE( g_trace_ctx, D_SYNTAX, "mode_cons_flag() flag=%d\n", flag );
      }
    
      else if( val == LDT_MODE_TYPE_INFER )
    
      {
        assert( modeType == MODE_TYPE_INTRA );
      }
      else
      {
        assert( modeType == partitioner.modeType );
      }
    }
    #endif
    
    
    Adam Wieckowski's avatar
    Adam Wieckowski committed
    void CABACWriter::split_cu_mode( const PartSplit split, const CodingStructure& cs, Partitioner& partitioner )
    {
      bool canNo, canQt, canBh, canBv, canTh, canTv;
      partitioner.canSplit( cs, canNo, canQt, canBh, canBv, canTh, canTv );
    
      bool canSpl[6] = { canNo, canQt, canBh, canBv, canTh, canTv };
    
      unsigned ctxSplit = 0, ctxQtSplit = 0, ctxBttHV = 0, ctxBttH12 = 0, ctxBttV12;
      DeriveCtx::CtxSplit( cs, partitioner, ctxSplit, ctxQtSplit, ctxBttHV, ctxBttH12, ctxBttV12, canSpl );
    
    Adam Wieckowski's avatar
    Adam Wieckowski committed
      const bool canSplit = canBh || canBv || canTh || canTv || canQt;
      const bool isNo     = split == CU_DONT_SPLIT;
    
      if( canNo && canSplit )
      {
        m_BinEncoder.encodeBin( !isNo, Ctx::SplitFlag( ctxSplit ) );
      }
    
      DTRACE( g_trace_ctx, D_SYNTAX, "split_cu_mode() ctx=%d split=%d\n", ctxSplit, !isNo );
    
      if( isNo )
      {
        return;
      }
    
      const bool canBtt = canBh || canBv || canTh || canTv;
      const bool isQt   = split == CU_QUAD_SPLIT;
    
      if( canQt && canBtt )
      {
        m_BinEncoder.encodeBin( isQt, Ctx::SplitQtFlag( ctxQtSplit ) );
      }
    
      DTRACE( g_trace_ctx, D_SYNTAX, "split_cu_mode() ctx=%d qt=%d\n", ctxQtSplit, isQt );
    
      if( isQt )
      {
        return;
      }
    
      const bool canHor = canBh || canTh;
      const bool canVer = canBv || canTv;
      const bool  isVer = split == CU_VERT_SPLIT || split == CU_TRIV_SPLIT;
    
      if( canVer && canHor )
      {
        m_BinEncoder.encodeBin( isVer, Ctx::SplitHvFlag( ctxBttHV ) );
      }
    
      const bool can14 = isVer ? canTv : canTh;
      const bool can12 = isVer ? canBv : canBh;
      const bool  is12 = isVer ? ( split == CU_VERT_SPLIT ) : ( split == CU_HORZ_SPLIT );
    
      if( can12 && can14 )
      {
        m_BinEncoder.encodeBin( is12, Ctx::Split12Flag( isVer ? ctxBttV12 : ctxBttH12 ) );
      }
    
      DTRACE( g_trace_ctx, D_SYNTAX, "split_cu_mode() ctxHv=%d ctx12=%d mode=%d\n", ctxBttHV, isVer ? ctxBttV12 : ctxBttH12, split );
    }
    
    
    //================================================================================
    //  clause 7.3.8.5
    //--------------------------------------------------------------------------------
    //    void  coding_unit               ( cu, partitioner, cuCtx )
    //    void  cu_transquant_bypass_flag ( cu )
    //    void  cu_skip_flag              ( cu )
    //    void  pred_mode                 ( cu )
    //    void  part_mode                 ( cu )
    //    void  pcm_flag                  ( cu )
    //    void  pcm_samples               ( tu )
    //    void  cu_pred_data              ( pus )
    //    void  cu_lic_flag               ( cu )
    //    void  intra_luma_pred_modes     ( pus )
    //    void  intra_chroma_pred_mode    ( pu )
    //    void  cu_residual               ( cu, partitioner, cuCtx )
    //    void  rqt_root_cbf              ( cu )
    //    void  end_of_ctu                ( cu, cuCtx )
    //================================================================================
    
    void CABACWriter::coding_unit( const CodingUnit& cu, Partitioner& partitioner, CUCtx& cuCtx )
    {
    
    #if JVET_O0050_LOCAL_DUAL_TREE
      DTRACE( g_trace_ctx, D_SYNTAX, "coding_unit() treeType=%d modeType=%d\n", cu.treeType, cu.modeType );
    #endif
    
      CodingStructure& cs = *cu.cs;
      // transquant bypass flag
      if( cs.pps->getTransquantBypassEnabledFlag() )
      {
        cu_transquant_bypass_flag( cu );
      }
    
      // skip flag
    
    Yu Han's avatar
    Yu Han committed
      if ((!cs.slice->isIntra() || cs.slice->getSPS()->getIBCFlag()) && cu.Y().valid())
    
      {
        cu_skip_flag( cu );
      }
    
    
      // skip data
      if( cu.skip )
      {
        CHECK( !cu.firstPU->mergeFlag, "Merge flag has to be on!" );
        PredictionUnit&   pu = *cu.firstPU;
        prediction_unit ( pu );
        end_of_ctu      ( cu, cuCtx );
        return;
      }
    
    
      {
        pcm_data( cu, partitioner );
        if( cu.ipcm )
        {
          end_of_ctu( cu, cuCtx );
          return;
        }
      }
    
      // prediction mode and partitioning data
      pred_mode ( cu );
    
    #if JVET_O0050_LOCAL_DUAL_TREE
        if (cu.isSepTree())
    #else
    
        {
          if (isLuma(partitioner.chType))
          {
            cu_palette_info(cu, COMPONENT_Y, 1, cuCtx);
          }
          if (cu.chromaFormat != CHROMA_400 && (partitioner.chType == CHANNEL_TYPE_CHROMA))
          {
            cu_palette_info(cu, COMPONENT_Cb, 2, cuCtx);
          }
        }
        else
        {
          cu_palette_info(cu, COMPONENT_Y, 3, cuCtx);
        }
        end_of_ctu(cu, cuCtx);
        return;
    
      bdpcm_mode( cu, ComponentID( partitioner.chType ) );
    
    #if FIX_PCM
      // pcm samples
      if( CU::isIntra(cu) )
      {
        pcm_data( cu, partitioner );
        if( cu.ipcm )
        {
          end_of_ctu( cu, cuCtx );
          return;
        }
      }
    #endif
    
    
      // prediction data ( intra prediction modes / reference indexes + motion vectors )
      cu_pred_data( cu );
    
      // residual data ( coded block flags + transform coefficient levels )
      cu_residual( cu, partitioner, cuCtx );
    
      // end of cu
      end_of_ctu( cu, cuCtx );
    }
    
    
    void CABACWriter::cu_transquant_bypass_flag( const CodingUnit& cu )
    {
      m_BinEncoder.encodeBin( (cu.transQuantBypass), Ctx::TransquantBypassFlag() );
    }
    
    
    void CABACWriter::cu_skip_flag( const CodingUnit& cu )
    {
      unsigned ctxId = DeriveCtx::CtxSkipFlag( cu );
    
    #if JVET_O0050_LOCAL_DUAL_TREE
      if ((cu.slice->isIntra() || cu.isConsIntra()) && cu.cs->slice->getSPS()->getIBCFlag())
    #else
    
    Yu Han's avatar
    Yu Han committed
      if (cu.slice->isIntra() && cu.cs->slice->getSPS()->getIBCFlag())
    
    #if JVET_O1161_IBC_MAX_SIZE
        if (cu.lwidth() < 128 && cu.lheight() < 128) // disable IBC mode larger than 64x64
    #else
    
    Yu Han's avatar
    Yu Han committed
        if (cu.lwidth() < 128 || cu.lheight() < 128) // disable 128x128 IBC mode
    
    Yu Han's avatar
    Yu Han committed
        {
    
    Yu Han's avatar
    Yu Han committed
        m_BinEncoder.encodeBin((cu.skip), Ctx::SkipFlag(ctxId));
    
    Yu Han's avatar
    Yu Han committed
        DTRACE(g_trace_ctx, D_SYNTAX, "cu_skip_flag() ctx=%d skip=%d\n", ctxId, cu.skip ? 1 : 0);
    
    Yu Han's avatar
    Yu Han committed
        }
    
    Yu Han's avatar
    Yu Han committed
        return;
      }
    
      if ( !cu.cs->slice->getSPS()->getIBCFlag() && cu.lwidth() == 4 && cu.lheight() == 4 )
      {
        return;
      }
    
    #if JVET_O0050_LOCAL_DUAL_TREE
      if( !cu.cs->slice->getSPS()->getIBCFlag() && cu.isConsIntra() )
      {
        return;
      }
    #endif
    
      m_BinEncoder.encodeBin( ( cu.skip ), Ctx::SkipFlag( ctxId ) );
    
      DTRACE( g_trace_ctx, D_SYNTAX, "cu_skip_flag() ctx=%d skip=%d\n", ctxId, cu.skip ? 1 : 0 );
    
    Yu Han's avatar
    Yu Han committed
      if (cu.skip && cu.cs->slice->getSPS()->getIBCFlag())
    
    #if JVET_O1161_IBC_MAX_SIZE
    
    #if JVET_O0050_LOCAL_DUAL_TREE
    
        if (cu.lwidth() < 128 && cu.lheight() < 128 && !cu.isConsInter()) // disable IBC mode larger than 64x64 and disable IBC when only allowing inter mode
    
        if (cu.lwidth() < 128 && cu.lheight() < 128) // disable IBC mode larger than 64x64
    
    #endif
    #else
    #if JVET_O0050_LOCAL_DUAL_TREE
    
        if ((cu.lwidth() < 128 || cu.lheight() < 128) && !cu.isConsInter()) // disable 128x128 IBC mode and disable IBC when only allowing inter mode
    
    Yu Han's avatar
    Yu Han committed
        if (cu.lwidth() < 128 || cu.lheight() < 128) // disable 128x128 IBC mode
    
    Yu Han's avatar
    Yu Han committed
        {
    
          if ( cu.lwidth() == 4 && cu.lheight() == 4 )
          {
            return;
          }
    
    Yu Han's avatar
    Yu Han committed
        unsigned ctxidx = DeriveCtx::CtxIBCFlag(cu);
        m_BinEncoder.encodeBin(CU::isIBC(cu) ? 1 : 0, Ctx::IBCFlag(ctxidx));
        DTRACE(g_trace_ctx, D_SYNTAX, "ibc() ctx=%d cu.predMode=%d\n", ctxidx, cu.predMode);
    
    Yu Han's avatar
    Yu Han committed
        }
    
    #if !JVET_O0249_MERGE_SYNTAX
    
        if (CU::isInter(cu))
        {
    
    Yi-Wen Chen's avatar
    Yi-Wen Chen committed
          if (!cu.cs->slice->getSPS()->getUseMMVD() && (cu.firstPU->lwidth() * cu.firstPU->lheight() == 32))
          {
            CHECK(!cu.firstPU->regularMergeFlag, "regular_merge_flag must be true!");
          }
          else
          {
            m_BinEncoder.encodeBin(cu.firstPU->regularMergeFlag, Ctx::RegularMergeFlag(0));
    
            DTRACE(g_trace_ctx, D_SYNTAX, "regularMergeFlag() ctx=%d regularMergeFlag=%d\n", 0, cu.firstPU->regularMergeFlag?1:0);
    
    Yi-Wen Chen's avatar
    Yi-Wen Chen committed
          }
    
          if (cu.cs->slice->getSPS()->getUseMMVD())
          {
    
    Yi-Wen Chen's avatar
    Yi-Wen Chen committed
            bool isCUWithOnlyRegularAndMMVD=((cu.firstPU->lwidth() == 8 && cu.firstPU->lheight() == 4) || (cu.firstPU->lwidth() == 4 && cu.firstPU->lheight() == 8));
            if (isCUWithOnlyRegularAndMMVD)
            {
              CHECK(cu.mmvdSkip==cu.firstPU->regularMergeFlag, "mmvdSkip_flag must be !regularMergeFlag");
            }
            else if (!cu.firstPU->regularMergeFlag)
            {
              m_BinEncoder.encodeBin(cu.mmvdSkip, Ctx::MmvdFlag(0));
              DTRACE(g_trace_ctx, D_SYNTAX, "mmvd_cu_skip_flag() ctx=%d mmvd_skip=%d\n", 0, cu.mmvdSkip ? 1 : 0);
            }
    
    #if !JVET_O0249_MERGE_SYNTAX
    
      if (cu.skip && !cu.cs->slice->getSPS()->getIBCFlag())
      {
    
    Yi-Wen Chen's avatar
    Yi-Wen Chen committed
        if (!cu.cs->slice->getSPS()->getUseMMVD() && (cu.firstPU->lwidth() * cu.firstPU->lheight() == 32))
        {
          CHECK(!cu.firstPU->regularMergeFlag, "regular_merge_flag must be true!");
        }
        else
        {
          m_BinEncoder.encodeBin(cu.firstPU->regularMergeFlag, Ctx::RegularMergeFlag(0));
          DTRACE(g_trace_ctx, D_SYNTAX, "regularMergeFlag() ctx=%d regularMergeFlag=%d\n", 0, cu.firstPU->regularMergeFlag?1:0);
        }
    
    Yi-Wen Chen's avatar
    Yi-Wen Chen committed
        if (cu.cs->slice->getSPS()->getUseMMVD())
    
    Yi-Wen Chen's avatar
    Yi-Wen Chen committed
          bool isCUWithOnlyRegularAndMMVD=((cu.firstPU->lwidth() == 8 && cu.firstPU->lheight() == 4) || (cu.firstPU->lwidth() == 4 && cu.firstPU->lheight() == 8));
          if (isCUWithOnlyRegularAndMMVD)
          {
            CHECK(cu.mmvdSkip==cu.firstPU->regularMergeFlag, "mmvdSkip_flag must be !regularMergeFlag");
          }
          else if (!cu.firstPU->regularMergeFlag)
          {
            m_BinEncoder.encodeBin(cu.mmvdSkip, Ctx::MmvdFlag(0));
            DTRACE(g_trace_ctx, D_SYNTAX, "mmvd_cu_skip_flag() ctx=%d mmvd_skip=%d\n", 0, cu.mmvdSkip ? 1 : 0);
          }
    
    #if JVET_O0258_REMOVE_CHROMA_IBC_FOR_DUALTREE
      if (cu.cs->slice->getSPS()->getIBCFlag() && cu.chType != CHANNEL_TYPE_CHROMA)
    #else
    
    Yu Han's avatar
    Yu Han committed
      if (cu.cs->slice->getSPS()->getIBCFlag())
    
    #if JVET_O0050_LOCAL_DUAL_TREE
        if( cu.isConsInter() )
        {
          assert( CU::isInter( cu ) );
          return;
        }
    #endif
    
    #if JVET_O0050_LOCAL_DUAL_TREE
        if ( cu.cs->slice->isIntra() || ( cu.lwidth() == 4 && cu.lheight() == 4 ) || cu.isConsIntra() )
    #else
    
        if ( cu.cs->slice->isIntra() || ( cu.lwidth() == 4 && cu.lheight() == 4 ) )
    
    #if JVET_O1161_IBC_MAX_SIZE
          if (cu.lwidth() < 128 && cu.lheight() < 128) // disable IBC mode larger than 64x64
    #else
    
    Yu Han's avatar
    Yu Han committed
          if (cu.lwidth() < 128 || cu.lheight() < 128) // disable 128x128 IBC mode
    
    Yu Han's avatar
    Yu Han committed
          {
    
    Yu Han's avatar
    Yu Han committed
          unsigned ctxidx = DeriveCtx::CtxIBCFlag(cu);
          m_BinEncoder.encodeBin(CU::isIBC(cu), Ctx::IBCFlag(ctxidx));
    
    Yu Han's avatar
    Yu Han committed
          }
    
          if (!CU::isIBC(cu) && cu.cs->slice->getSPS()->getPLTMode() && cu.lwidth() <= 64 && cu.lheight() <= 64)
          {
            m_BinEncoder.encodeBin(CU::isPLT(cu), Ctx::PLTFlag(0));
          }
    
    #if JVET_O0050_LOCAL_DUAL_TREE
          if( cu.isConsInter() )
          {
            return;
          }
    #endif
    
          m_BinEncoder.encodeBin((CU::isIntra(cu) || CU::isPLT(cu)), Ctx::PredMode(DeriveCtx::CtxPredModeFlag(cu)));
          if (CU::isIntra(cu) || CU::isPLT(cu))
          {
            if (cu.cs->slice->getSPS()->getPLTMode() && cu.lwidth() <= 64 && cu.lheight() <= 64)
              m_BinEncoder.encodeBin(CU::isPLT(cu), Ctx::PLTFlag(0));
          }
          else
    
    #else
            m_BinEncoder.encodeBin((CU::isIntra(cu)), Ctx::PredMode(DeriveCtx::CtxPredModeFlag(cu)));
            if (!CU::isIntra(cu))
            {
    
    #if JVET_O1161_IBC_MAX_SIZE
            if (cu.lwidth() < 128 && cu.lheight() < 128) // disable IBC mode larger than 64x64
    #else
    
    Yu Han's avatar
    Yu Han committed
            if (cu.lwidth() < 128 || cu.lheight() < 128) // disable 128x128 IBC mode
    
    Yu Han's avatar
    Yu Han committed
            {
    
    Yu Han's avatar
    Yu Han committed
            unsigned ctxidx = DeriveCtx::CtxIBCFlag(cu);
            m_BinEncoder.encodeBin(CU::isIBC(cu), Ctx::IBCFlag(ctxidx));
    
    Yu Han's avatar
    Yu Han committed
            }
    
    #if JVET_O0050_LOCAL_DUAL_TREE
    
          assert( CU::isInter( cu ) );
    
    
    #if JVET_O0050_LOCAL_DUAL_TREE
        if ( cu.cs->slice->isIntra() || ( cu.lwidth() == 4 && cu.lheight() == 4 ) || cu.isConsIntra() )
    #else
    
        if ( cu.cs->slice->isIntra() || ( cu.lwidth() == 4 && cu.lheight() == 4 ) )
    
          if (cu.cs->slice->getSPS()->getPLTMode() && cu.lwidth() <= 64 && cu.lheight() <= 64)
            m_BinEncoder.encodeBin((CU::isPLT(cu)), Ctx::PLTFlag(0));
    
    Yu Han's avatar
    Yu Han committed
          return;
        }
        m_BinEncoder.encodeBin((CU::isIntra(cu)), Ctx::PredMode(DeriveCtx::CtxPredModeFlag(cu)));
    
        if (!CU::isIntra(cu) && cu.cs->slice->getSPS()->getPLTMode() && cu.lwidth() <= 64 && cu.lheight() <= 64)
        {
          m_BinEncoder.encodeBin((CU::isPLT(cu)), Ctx::PLTFlag(0));
        }
    
    void CABACWriter::bdpcm_mode( const CodingUnit& cu, const ComponentID compID )
    {
    
    #if JVET_O1136_TS_BDPCM_SIGNALLING
      if( !cu.cs->sps->getBDPCMEnabledFlag() ) return;
    #endif
    
      if( !CU::bdpcmAllowed( cu, compID ) ) return;
    
      m_BinEncoder.encodeBin( cu.bdpcmMode > 0 ? 1 : 0, Ctx::BDPCMMode( 0 ) );
    
      if( cu.bdpcmMode )
      {
        m_BinEncoder.encodeBin( cu.bdpcmMode > 1 ? 1 : 0, Ctx::BDPCMMode( 1 ) );
      }
      DTRACE( g_trace_ctx, D_SYNTAX, "bdpcm_mode() x=%d, y=%d, w=%d, h=%d, bdpcm=%d\n", cu.lumaPos().x, cu.lumaPos().y, cu.lwidth(), cu.lheight(), cu.bdpcmMode );
    }
    
    void CABACWriter::pcm_data( const CodingUnit& cu, Partitioner& partitioner  )
    
      pcm_flag( cu, partitioner );
    
      if( cu.ipcm )
      {
        m_BinEncoder.pcmAlignBits();
        pcm_samples( *cu.firstTU );
      }
    }
    
    
    void CABACWriter::pcm_flag( const CodingUnit& cu, Partitioner& partitioner )
    
      if( !sps.getPCMEnabledFlag() || partitioner.currArea().lwidth() > (1 << sps.getPCMLog2MaxSize()) || partitioner.currArea().lwidth() < (1 << sps.getPCMLog2MinSize())
          || partitioner.currArea().lheight() > (1 << sps.getPCMLog2MaxSize()) || partitioner.currArea().lheight() < (1 << sps.getPCMLog2MinSize()) )
    
      {
        return;
      }
      m_BinEncoder.encodeBinTrm( cu.ipcm );
    }
    
    
    void CABACWriter::cu_pred_data( const CodingUnit& cu )
    {
      if( CU::isIntra( cu ) )
      {
        intra_luma_pred_modes  ( cu );
        intra_chroma_pred_modes( cu );
        return;