Skip to content
Snippets Groups Projects
CABACWriter.cpp 111 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 */ )
    
      QTBTPartitioner partitioner;
    
      partitioner.initCtu(area, CH_L, *cs.slice);
    
      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 (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 );
            }
          }
    
      if ( CS::isDualITree(cs) && cs.pcv->chrFormat != CHROMA_400 && cs.pcv->maxCUWidth > 64 )
    
        QTBTPartitioner chromaPartitioner;
        chromaPartitioner.initCtu(area, CH_C, *cs.slice);
        coding_tree(cs, partitioner, cuCtx, &chromaPartitioner, &chromaCuCtx);
    
        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);
    
    }
    
    
    
    
    
    //================================================================================
    //  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
    
    Yin Zhao's avatar
    Yin Zhao committed
      //Note: do not reset qg at chroma CU
      if( pps.getUseDQP() && partitioner.currQgEnable() && !isChroma( partitioner.chType ) )
    
      {
        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 (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
          {
    
            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;
            }
    
    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( 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;
    
      if( cuCtx.qgStart )
      {
        cuCtx.qgStart = false;
    
      CHECK( cu.treeType != partitioner.treeType, "treeType mismatch" );
    
    Yin Zhao's avatar
    Yin Zhao committed
      if( cu.chType == CHANNEL_TYPE_CHROMA )
      {
        DTRACE_COND( (isEncoding()), g_trace_ctx, D_QP, "[chroma CU]x=%d, y=%d, w=%d, h=%d, qp=%d\n", cu.Cb().x, cu.Cb().y, cu.Cb().width, cu.Cb().height, cu.qp );
      }
      else
      {
    
      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 );
    }
    
    
    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 );
      }
    }
    
    
    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  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 )
    {
    
      DTRACE( g_trace_ctx, D_SYNTAX, "coding_unit() treeType=%d modeType=%d\n", cu.treeType, cu.modeType );
    
      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;
      }
    
    
      // prediction mode and partitioning data
      pred_mode ( cu );
    
        {
          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 ) );
    
    
    
      // 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 ((cu.slice->isIntra() || cu.isConsIntra()) && cu.cs->slice->getSPS()->getIBCFlag())
    
        if (cu.lwidth() < 128 && cu.lheight() < 128) // disable IBC mode larger than 64x64
    
    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( !cu.cs->slice->getSPS()->getIBCFlag() && cu.isConsIntra() )
      {
        return;
      }
    
      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 (cu.lwidth() < 128 && cu.lheight() < 128 && !cu.isConsInter()) // disable IBC mode larger than 64x64 and disable IBC when only allowing inter 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 (cu.cs->slice->getSPS()->getIBCFlag() && cu.chType != CHANNEL_TYPE_CHROMA)
    
        if( cu.isConsInter() )
        {
          assert( CU::isInter( cu ) );
          return;
        }
    
        if ( cu.cs->slice->isIntra() || ( cu.lwidth() == 4 && cu.lheight() == 4 ) || cu.isConsIntra() )
    
          if (cu.lwidth() < 128 && cu.lheight() < 128) // disable IBC mode larger than 64x64
    
    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( cu.isConsInter() )
          {
            return;
          }
    
          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
    
            if (cu.lwidth() < 128 && cu.lheight() < 128) // disable IBC mode larger than 64x64
    
    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
            }
    
          assert( CU::isInter( cu ) );
    
    
        if ( cu.cs->slice->isIntra() || ( cu.lwidth() == 4 && cu.lheight() == 4 ) || cu.isConsIntra() )
    
          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( !cu.cs->sps->getBDPCMEnabledFlag() ) return;
    
      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::cu_pred_data( const CodingUnit& cu )
    {
      if( CU::isIntra( cu ) )
      {
        intra_luma_pred_modes  ( cu );
        intra_chroma_pred_modes( cu );
        return;
      }
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
      if (!cu.Y().valid()) // dual tree chroma CU
      {
        return;
      }
    
      for( auto &pu : CU::traversePUs( cu ) )
      {
        prediction_unit( pu );
      }
    
      imv_mode   ( cu );
    
      affine_amvr_mode( cu );
    
      cu_gbi_flag( cu );
    
    
    void CABACWriter::cu_gbi_flag(const CodingUnit& cu)
    {
      if(!CU::isGBiIdxCoded(cu))
      {
        return;
      }
    
      CHECK(!(GBI_NUM > 1 && (GBI_NUM == 2 || (GBI_NUM & 0x01) == 1)), " !( GBI_NUM > 1 && ( GBI_NUM == 2 || ( GBI_NUM & 0x01 ) == 1 ) ) ");
      const uint8_t gbiCodingIdx = (uint8_t)g_GbiCodingOrder[CU::getValidGbiIdx(cu)];
    
    
      const int32_t numGBi = (cu.slice->getCheckLDC()) ? 5 : 3;
    
      m_BinEncoder.encodeBin((gbiCodingIdx == 0 ? 0 : 1), Ctx::GBiIdx(0));
    
      if(numGBi > 2 && gbiCodingIdx != 0)
      {
    
        const uint32_t prefixNumBits = numGBi - 2;
        const uint32_t step = 1;
    
    
        uint8_t idx = 1;
        for(int ui = 0; ui < prefixNumBits; ++ui)
        {
    
          if (gbiCodingIdx == idx)
    
            m_BinEncoder.encodeBinEP(0);
    
            m_BinEncoder.encodeBinEP(1);
    
      DTRACE(g_trace_ctx, D_SYNTAX, "cu_gbi_flag() gbi_idx=%d\n", cu.GBiIdx ? 1 : 0);
    }
    
    ling's avatar
    ling committed
    void CABACWriter::xWriteTruncBinCode(uint32_t symbol, uint32_t maxSymbol)
    
    ling's avatar
    ling committed
      int thresh;
      if (maxSymbol > 256)
    
    ling's avatar
    ling committed
        int threshVal = 1 << 8;
        thresh = 8;
        while (threshVal <= maxSymbol)
    
    ling's avatar
    ling committed
          thresh++;
          threshVal <<= 1;
    
    ling's avatar
    ling committed
        thresh--;
    
    ling's avatar
    ling committed
        thresh = g_tbMax[maxSymbol];
    
    ling's avatar
    ling committed
      int val = 1 << thresh;
      assert(val <= maxSymbol);
      assert((val << 1) > maxSymbol);
      assert(symbol < maxSymbol);
      int b = maxSymbol - val;
      assert(b < val);
      if (symbol < val - b)
    
    ling's avatar
    ling committed
        m_BinEncoder.encodeBinsEP(symbol, thresh);
    
    ling's avatar
    ling committed
        symbol += val - b;
        assert(symbol < (val << 1));
        assert((symbol >> 1) >= val - b);
        m_BinEncoder.encodeBinsEP(symbol, thresh + 1);
    
    void CABACWriter::extend_ref_line(const PredictionUnit& pu)
    {
    
      const CodingUnit& cu = *pu.cu;
    
      if( !cu.Y().valid() || cu.predMode != MODE_INTRA || !isLuma( cu.chType ) || cu.bdpcmMode )
    
      {
        return;
      }
      bool isFirstLineOfCtu = (((cu.block(COMPONENT_Y).y)&((cu.cs->sps)->getMaxCUWidth() - 1)) == 0);
      if (isFirstLineOfCtu)
      {
        return;
      }
      int multiRefIdx = pu.multiRefIdx;
      if (MRL_NUM_REF_LINES > 1)
      {
        m_BinEncoder.encodeBin(multiRefIdx != MULTI_REF_LINE_IDX[0], Ctx::MultiRefLineIdx(0));
        if (MRL_NUM_REF_LINES > 2 && multiRefIdx != MULTI_REF_LINE_IDX[0])
        {
          m_BinEncoder.encodeBin(multiRefIdx != MULTI_REF_LINE_IDX[1], Ctx::MultiRefLineIdx(1));
        }
      }
    }
    
    void CABACWriter::extend_ref_line(const CodingUnit& cu)
    {
    
      if ( !cu.Y().valid() || cu.predMode != MODE_INTRA || !isLuma(cu.chType) || cu.bdpcmMode )
    
      {
        return;
      }
    
      const int numBlocks = CU::getNumPUs(cu);
      const PredictionUnit* pu = cu.firstPU;
    
      for (int k = 0; k < numBlocks; k++)
      {
        bool isFirstLineOfCtu = (((cu.block(COMPONENT_Y).y)&((cu.cs->sps)->getMaxCUWidth() - 1)) == 0);
        if (isFirstLineOfCtu)
        {
          return;
        }
        int multiRefIdx = pu->multiRefIdx;
        if (MRL_NUM_REF_LINES > 1)
        {
          m_BinEncoder.encodeBin(multiRefIdx != MULTI_REF_LINE_IDX[0], Ctx::MultiRefLineIdx(0));
          if (MRL_NUM_REF_LINES > 2 && multiRefIdx != MULTI_REF_LINE_IDX[0])
          {
            m_BinEncoder.encodeBin(multiRefIdx != MULTI_REF_LINE_IDX[1], Ctx::MultiRefLineIdx(1));
          }
    
        }
        pu = pu->next;
      }
    }
    
    
    void CABACWriter::intra_luma_pred_modes( const CodingUnit& cu )
    {
      if( !cu.Y().valid() )
      {
        return;
      }
    
    
      if( cu.bdpcmMode )
      {
    
        cu.firstPU->intraDir[0] = cu.bdpcmMode == 2? VER_IDX : HOR_IDX;
    
      mip_flag(cu);
      if (cu.mipFlag)
      {
        mip_pred_modes(cu);
        return;
      }
      extend_ref_line( cu );
    
      isp_mode( cu );
    
    
      const int numMPMs   = NUM_MOST_PROBABLE_MODES;
      const int numBlocks = CU::getNumPUs( cu );
      unsigned  mpm_preds   [4][numMPMs];
      unsigned  mpm_idxs    [4];
      unsigned  ipred_modes [4];
    
    
      const PredictionUnit* pu = cu.firstPU;
    
      // prev_intra_luma_pred_flag
      for( int k = 0; k < numBlocks; k++ )