Skip to content
Snippets Groups Projects
CABACWriter.cpp 123 KiB
Newer Older
/* 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 ( 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 (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
      {
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();
      }
      return;
  }

  // Predict QP on start of quantization group
  if( cuCtx.qgStart )
  {
    cuCtx.qgStart = false;
    cuCtx.qp = CU::predictQP( cu, cuCtx.qp );
  }


  // 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 );
}

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 )
{
  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;
  }

  if( CU::isIntra(cu) )
  {
    pcm_data( cu, partitioner );
    if( cu.ipcm )
    {
      end_of_ctu( cu, cuCtx );
      return;
    }
  }
  // prediction mode and partitioning data
  pred_mode ( cu );
#if JVET_O0119_BASE_PALETTE_444
  if (CU::isPLT(cu))
  {
	  if (CS::isDualITree(*cu.cs))
	  {
		  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;
  }
#endif
  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 );
Yu Han's avatar
Yu Han committed
  if (cu.slice->isIntra() && cu.cs->slice->getSPS()->getIBCFlag())
Yu Han's avatar
Yu Han committed
  {
#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;
  }
  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())
Yu Han's avatar
Yu Han committed
  {
#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
    {
      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::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);
        }
Yu Han's avatar
Yu Han committed
  }
  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);
      }
Yu Han's avatar
Yu Han committed
  }
#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())
Yu Han's avatar
Yu Han committed
  {
    if ( cu.cs->slice->isIntra() || ( cu.lwidth() == 4 && cu.lheight() == 4 ) )
Yu Han's avatar
Yu Han committed
    {
#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_O0119_BASE_PALETTE_444
	  if (!CU::isIBC(cu) && cu.cs->slice->getSPS()->getPLTMode() && cu.lwidth() <= 64 && cu.lheight() <= 64)
	  {
		  m_BinEncoder.encodeBin(CU::isPLT(cu), Ctx::PLTFlag(0));
	  }
#endif
#if JVET_O0119_BASE_PALETTE_444
	  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
Yu Han's avatar
Yu Han committed
      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 ( cu.cs->slice->isIntra() || ( cu.lwidth() == 4 && cu.lheight() == 4 ) )
Yu Han's avatar
Yu Han committed
    {
#if JVET_O0119_BASE_PALETTE_444
	  if (cu.cs->slice->getSPS()->getPLTMode() && cu.lwidth() <= 64 && cu.lheight() <= 64)
		  m_BinEncoder.encodeBin((CU::isPLT(cu)), Ctx::PLTFlag(0));
#endif
Yu Han's avatar
Yu Han committed
      return;
    }
    m_BinEncoder.encodeBin((CU::isIntra(cu)), Ctx::PredMode(DeriveCtx::CtxPredModeFlag(cu)));
#if JVET_O0119_BASE_PALETTE_444
	if (!CU::isIntra(cu) && cu.cs->slice->getSPS()->getPLTMode() && cu.lwidth() <= 64 && cu.lheight() <= 64)
	{
		m_BinEncoder.encodeBin((CU::isPLT(cu)), Ctx::PLTFlag(0));
	}
#endif
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;
  }
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;
#if JVET_O0126_BPWA_INDEX_CODING_FIX
  m_BinEncoder.encodeBin((gbiCodingIdx == 0 ? 0 : 1), Ctx::GBiIdx(0));
#else
  m_BinEncoder.encodeBin((gbiCodingIdx == 0 ? 1 : 0), 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)
#if JVET_O0126_BPWA_INDEX_CODING_FIX
        m_BinEncoder.encodeBinEP(0);
#else
        m_BinEncoder.encodeBinEP(1);
#if JVET_O0126_BPWA_INDEX_CODING_FIX
        m_BinEncoder.encodeBinEP(1);
#else
        m_BinEncoder.encodeBinEP(0);
  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
{
ling's avatar
ling committed
  int thresh;
  if (maxSymbol > 256)
ling's avatar
ling committed
  {
ling's avatar
ling committed
    int threshVal = 1 << 8;
    thresh = 8;
    while (threshVal <= maxSymbol)
ling's avatar
ling committed
    {
ling's avatar
ling committed
      thresh++;
      threshVal <<= 1;
ling's avatar
ling committed
    }
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
  {
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)
{
Liang Zhao's avatar
Liang Zhao committed
#if !ENABLE_JVET_L0283_MRL
  return;
#endif

  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)
{
Liang Zhao's avatar
Liang Zhao committed
#if !ENABLE_JVET_L0283_MRL
  return;
#endif

  if ( !cu.Y().valid() || cu.predMode != MODE_INTRA || !isLuma(cu.chType) || cu.ipcm || 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 )
  {
#if JVET_O0315_RDPCM_INTRAMODE_ALIGN
    cu.firstPU->intraDir[0] = cu.bdpcmMode == 2? VER_IDX : HOR_IDX;
#else
    PredictionUnit *pu = cu.firstPU;
    unsigned mpm_pred[NUM_MOST_PROBABLE_MODES];
    PU::getIntraMPMs( *pu, mpm_pred );
    cu.firstPU->intraDir[0] = mpm_pred[0];
  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++ )
  {
    unsigned*  mpm_pred   = mpm_preds[k];
    unsigned&  mpm_idx    = mpm_idxs[k];
    unsigned&  ipred_mode = ipred_modes[k];

    PU::getIntraMPMs( *pu, mpm_pred );

    ipred_mode = pu->intraDir[0];
    mpm_idx    = numMPMs;
    for( unsigned idx = 0; idx < numMPMs; idx++ )
    {
      if( ipred_mode == mpm_pred[idx] )
      {
        mpm_idx = idx;
        break;
      }
    }
    if( pu->multiRefIdx || ( cu.ispMode && isLuma( cu.chType ) ) )
    {
      CHECK(mpm_idx >= numMPMs, "use of non-MPM");
    }
    else
Frank Bossen's avatar
Frank Bossen committed
    {
      m_BinEncoder.encodeBin(mpm_idx < numMPMs, Ctx::IntraLumaMpmFlag());
    }

    pu = pu->next;
  }

  pu = cu.firstPU;

  // mpm_idx / rem_intra_luma_pred_mode
  for( int k = 0; k < numBlocks; k++ )
  {
    const unsigned& mpm_idx = mpm_idxs[k];
    if( mpm_idx < numMPMs )
    {
      {
        unsigned ctx = (pu->cu->ispMode == NOT_INTRA_SUBPARTITIONS ? 1 : 0);
        if (pu->multiRefIdx == 0)
          m_BinEncoder.encodeBin(mpm_idx > 0, Ctx::IntraLumaPlanarFlag(ctx));
        if( mpm_idx )
        {
          m_BinEncoder.encodeBinEP( mpm_idx > 1 );
        }
ling's avatar
ling committed
        if (mpm_idx > 1)
        {
          m_BinEncoder.encodeBinEP(mpm_idx > 2);
        }
        if (mpm_idx > 2)
        {
          m_BinEncoder.encodeBinEP(mpm_idx > 3);
        }
        if (mpm_idx > 3)
        {
          m_BinEncoder.encodeBinEP(mpm_idx > 4);
        }
      }
    }
    else
    {
      unsigned* mpm_pred   = mpm_preds[k];
      unsigned  ipred_mode = ipred_modes[k];

      // sorting of MPMs
      std::sort( mpm_pred, mpm_pred + numMPMs );

      {
        for (int idx = numMPMs - 1; idx >= 0; idx--)
        {
          if (ipred_mode > mpm_pred[idx])
          {
            ipred_mode--;
          }
        }
        CHECK(ipred_mode >= 64, "Incorrect mode");
ling's avatar
ling committed
        xWriteTruncBinCode(ipred_mode, NUM_LUMA_MODE - NUM_MOST_PROBABLE_MODES);  // Remaining mode is truncated binary coded
      }
    }

    DTRACE( g_trace_ctx, D_SYNTAX, "intra_luma_pred_modes() idx=%d pos=(%d,%d) mode=%d\n", k, pu->lumaPos().x, pu->lumaPos().y, pu->intraDir[0] );
    pu = pu->next;
  }
}


void CABACWriter::intra_luma_pred_mode( const PredictionUnit& pu )
{

  if( pu.cu->bdpcmMode ) return;
  mip_flag(*pu.cu);
  if (pu.cu->mipFlag)
  {
    mip_pred_mode(pu);
    return;
  }
  extend_ref_line( pu );

  isp_mode( *pu.cu );

  const int numMPMs  = NUM_MOST_PROBABLE_MODES;
  unsigned  mpm_pred[numMPMs];
  PU::getIntraMPMs( pu, mpm_pred );

  unsigned ipred_mode = pu.intraDir[0];
  unsigned mpm_idx = numMPMs;

  for( int idx = 0; idx < numMPMs; idx++ )
  if( pu.multiRefIdx || ( pu.cu->ispMode && isLuma( pu.cu->chType ) ) )
  {
    CHECK(mpm_idx >= numMPMs, "use of non-MPM");
  }
  else
Frank Bossen's avatar
Frank Bossen committed
  {
    m_BinEncoder.encodeBin(mpm_idx < numMPMs, Ctx::IntraLumaMpmFlag());
  }

  // mpm_idx / rem_intra_luma_pred_mode
  if( mpm_idx < numMPMs )
  {
    {
      unsigned ctx = (pu.cu->ispMode == NOT_INTRA_SUBPARTITIONS ? 1 : 0);
      if (pu.multiRefIdx == 0)
        m_BinEncoder.encodeBin( mpm_idx > 0, Ctx::IntraLumaPlanarFlag(ctx) );
      if( mpm_idx )
      {
        m_BinEncoder.encodeBinEP( mpm_idx > 1 );
      }
ling's avatar
ling committed
      if (mpm_idx > 1)
      {
        m_BinEncoder.encodeBinEP(mpm_idx > 2);
      }
      if (mpm_idx > 2)
      {
        m_BinEncoder.encodeBinEP(mpm_idx > 3);
      }
      if (mpm_idx > 3)
      {
        m_BinEncoder.encodeBinEP(mpm_idx > 4);
      }
      for (int idx = numMPMs - 1; idx >= 0; idx--)
ling's avatar
ling committed
      xWriteTruncBinCode(ipred_mode, NUM_LUMA_MODE - NUM_MOST_PROBABLE_MODES);  // Remaining mode is truncated binary coded
    }
  }
}


void CABACWriter::intra_chroma_pred_modes( const CodingUnit& cu )
{
  if( cu.chromaFormat == CHROMA_400 || ( CS::isDualITree( *cu.cs ) && cu.chType == CHANNEL_TYPE_LUMA ) )
  {
    return;
  }

  const PredictionUnit* pu = cu.firstPU;

  intra_chroma_pred_mode( *pu );
}

void CABACWriter::intra_chroma_lmc_mode( const PredictionUnit& pu )
{
  const unsigned intraDir = pu.intraDir[1];
    int lmModeList[10];
    int maxSymbol = PU::getLMSymbolList( pu, lmModeList );
    int symbol    = -1;
    for ( int k = 0; k < LM_SYMBOL_NUM; k++ )
    {
      if ( lmModeList[k] == intraDir || ( lmModeList[k] == -1 && intraDir < LM_CHROMA_IDX ) )
      {
        symbol = k;
        break;
      }
    }
    CHECK( symbol < 0, "invalid symbol found" );

Frank Bossen's avatar
Frank Bossen committed
    unary_max_symbol(symbol, Ctx::IntraChromaPredMode(1), Ctx::IntraChromaPredMode(2), maxSymbol - 1);
}


void CABACWriter::intra_chroma_pred_mode( const PredictionUnit& pu )
{
  const unsigned intraDir = pu.intraDir[1];
Frank Bossen's avatar
Frank Bossen committed
  const bool     isDerivedMode = intraDir == DM_CHROMA_IDX;

  m_BinEncoder.encodeBin(isDerivedMode ? 0 : 1, Ctx::IntraChromaPredMode(0));

  if (isDerivedMode)
Frank Bossen's avatar
Frank Bossen committed
    return;
#if JVET_O1124_ALLOW_CCLM_COND
  if( pu.cs->sps->getUseLMChroma() && pu.cu->checkCCLMAllowed() )
#else
  if( pu.cs->sps->getUseLMChroma() )
  {
    intra_chroma_lmc_mode( pu );
    if ( PU::isLMCMode( intraDir ) )
    {
      return;
    }
  }

  // chroma candidate index
  unsigned chromaCandModes[ NUM_CHROMA_MODE ];
  PU::getIntraChromaCandModes( pu, chromaCandModes );

  int candId = 0;
  for ( ; candId < NUM_CHROMA_MODE; candId++ )
  {
    if( intraDir == chromaCandModes[ candId ] )
    {
      break;
    }
  }

  CHECK( candId >= NUM_CHROMA_MODE, "Chroma prediction mode index out of bounds" );
  CHECK( chromaCandModes[ candId ] == DM_CHROMA_IDX, "The intra dir cannot be DM_CHROMA for this path" );
  {
    m_BinEncoder.encodeBinsEP( candId, 2 );
  }
}


void CABACWriter::cu_residual( const CodingUnit& cu, Partitioner& partitioner, CUCtx& cuCtx )
{
Yu Han's avatar
Yu Han committed
  if (!CU::isIntra(cu))
Karsten Suehring's avatar
Karsten Suehring committed
    if( !pu.mergeFlag )
    if( cu.rootCbf )
    {
      sbt_mode( cu );
    }
#if JVET_O0094_LFNST_ZERO_PRIM_COEFFS
Mischa Siekmann's avatar
Mischa Siekmann committed
  cuCtx.violatesLfnstConstrained[CHANNEL_TYPE_LUMA]   = false;
  cuCtx.violatesLfnstConstrained[CHANNEL_TYPE_CHROMA] = false;
#endif
#if !JVET_O0596_CBF_SIG_ALIGN_TO_SPEC
  if( cu.ispMode && isLuma( partitioner.chType ) )
  {
    TUIntraSubPartitioner subTuPartitioner( partitioner );
#if JVET_O0596_CBF_SIG_ALIGN_TO_SPEC
    transform_tree( *cu.cs, subTuPartitioner, cuCtx,             CU::getISPType( cu, getFirstComponentOfChannel( partitioner.chType)  ), 0 );
#else
    transform_tree( *cu.cs, subTuPartitioner, cuCtx, chromaCbfs, CU::getISPType( cu, getFirstComponentOfChannel( partitioner.chType ) ), 0 );
#if JVET_O0596_CBF_SIG_ALIGN_TO_SPEC
    transform_tree( *cu.cs, partitioner, cuCtx );
#else
    transform_tree( *cu.cs, partitioner, cuCtx, chromaCbfs );

  residual_lfnst_mode( cu, cuCtx );
}

void CABACWriter::rqt_root_cbf( const CodingUnit& cu )
{
  m_BinEncoder.encodeBin( cu.rootCbf, Ctx::QtRootCbf() );

  DTRACE( g_trace_ctx, D_SYNTAX, "rqt_root_cbf() ctx=0 root_cbf=%d pos=(%d,%d)\n", cu.rootCbf ? 1 : 0, cu.lumaPos().x, cu.lumaPos().y );
}

void CABACWriter::sbt_mode( const CodingUnit& cu )
{
  uint8_t sbtAllowed = cu.checkAllowedSbt();
  if( !sbtAllowed )
  {
    return;
  }

  SizeType cuWidth = cu.lwidth();
  SizeType cuHeight = cu.lheight();
  uint8_t sbtIdx = cu.getSbtIdx();
  uint8_t sbtPos = cu.getSbtPos();

  //bin - flag
  bool sbtFlag = cu.sbtInfo != 0;
  uint8_t ctxIdx = ( cuWidth * cuHeight <= 256 ) ? 1 : 0;
  m_BinEncoder.encodeBin( sbtFlag, Ctx::SbtFlag( ctxIdx ) );
  if( !sbtFlag )
  {
    return;
  }

  bool sbtQuadFlag = sbtIdx == SBT_HOR_QUAD || sbtIdx == SBT_VER_QUAD;
  bool sbtHorFlag = sbtIdx == SBT_HOR_HALF || sbtIdx == SBT_HOR_QUAD;
  bool sbtPosFlag = sbtPos == SBT_POS1;

  uint8_t sbtVerHalfAllow = CU::targetSbtAllowed( SBT_VER_HALF, sbtAllowed );
  uint8_t sbtHorHalfAllow = CU::targetSbtAllowed( SBT_HOR_HALF, sbtAllowed );
  uint8_t sbtVerQuadAllow = CU::targetSbtAllowed( SBT_VER_QUAD, sbtAllowed );
  uint8_t sbtHorQuadAllow = CU::targetSbtAllowed( SBT_HOR_QUAD, sbtAllowed );
  //bin - type
  if( ( sbtHorHalfAllow || sbtVerHalfAllow ) && ( sbtHorQuadAllow || sbtVerQuadAllow ) )
  {
    m_BinEncoder.encodeBin( sbtQuadFlag, Ctx::SbtQuadFlag( 0 ) );
  }
  else
  {
    assert( sbtQuadFlag == 0 );
  }

  //bin - dir
  if( ( sbtQuadFlag && sbtVerQuadAllow && sbtHorQuadAllow ) || ( !sbtQuadFlag && sbtVerHalfAllow && sbtHorHalfAllow ) ) //both direction allowed
  {
    uint8_t ctxIdx = ( cuWidth == cuHeight ) ? 0 : ( cuWidth < cuHeight ? 1 : 2 );
    m_BinEncoder.encodeBin( sbtHorFlag, Ctx::SbtHorFlag( ctxIdx ) );
  }
  else
  {
    assert( sbtHorFlag == ( ( sbtQuadFlag && sbtHorQuadAllow ) || ( !sbtQuadFlag && sbtHorHalfAllow ) ) );
  }

  //bin - pos
  m_BinEncoder.encodeBin( sbtPosFlag, Ctx::SbtPosFlag( 0 ) );

  DTRACE( g_trace_ctx, D_SYNTAX, "sbt_mode() pos=(%d,%d) sbtInfo=%d\n", cu.lx(), cu.ly(), (int)cu.sbtInfo );
}

void CABACWriter::end_of_ctu( const CodingUnit& cu, CUCtx& cuCtx )
{
  const Slice*  slice             = cu.cs->slice;
Karsten Suehring's avatar
Karsten Suehring committed
  const int     currentCTUTsAddr  = cu.cs->picture->brickMap->getCtuRsToBsAddrMap( CU::getCtuAddr( cu ) );
  const bool    isLastSubCUOfCtu  = CU::isLastSubCUOfCtu( cu );

  if ( isLastSubCUOfCtu
    && ( !CS::isDualITree( *cu.cs ) || cu.chromaFormat == CHROMA_400 || isChroma( cu.chType ) )
      )
  {
    cuCtx.isDQPCoded = ( cu.cs->pps->getUseDQP() && !cuCtx.isDQPCoded );

    // The 1-terminating bit is added to all streams, so don't add it here when it's 1.
    // i.e. when the slice segment CurEnd CTU address is the current CTU address+1.
    if(slice->getSliceCurEndCtuTsAddr() != currentCTUTsAddr + 1)
    {
      m_BinEncoder.encodeBinTrm( 0 );
    }
  }
}

void CABACWriter::cu_palette_info(const CodingUnit& cu, ComponentID compBegin, uint32_t numComp, CUCtx& cuCtx)
{
	const SPS&        sps = *(cu.cs->sps);
	TransformUnit&   tu = *cu.firstTU;

	uint32_t indexMaxSize = cu.useEscape[compBegin] ? (cu.curPLTSize[compBegin] + 1) : cu.curPLTSize[compBegin];


	if (cu.lastPLTSize[compBegin])
	{
		xEncodePLTPredIndicator(cu, MAXPLTSIZE, compBegin);
	}

	uint32_t reusedPLTnum = 0;
	for (int idx = 0; idx < cu.lastPLTSize[compBegin]; idx++)
	{
		if (cu.reuseflag[compBegin][idx])
			reusedPLTnum++;
	}

	if (reusedPLTnum < MAXPLTSIZE)
	{
		exp_golomb_eqprob(cu.curPLTSize[compBegin] - reusedPLTnum, 0);
	}

	for (int comp = compBegin; comp < (compBegin + numComp); comp++)
	{
		for (int idx = cu.reusePLTSize[compBegin]; idx < cu.curPLTSize[compBegin]; idx++)
		{
			ComponentID compID = (ComponentID)comp;
			const int  channelBitDepth = sps.getBitDepth(toChannelType(compID));
			m_BinEncoder.encodeBinsEP(cu.curPLT[comp][idx], channelBitDepth);
		}
	}
	uint32_t signalEscape = (cu.useEscape[compBegin]) ? 1 : 0;
	if (cu.curPLTSize[compBegin] > 0)
	{
		m_BinEncoder.encodeBinEP(signalEscape);
	}
	//encode index map
	PLTtypeBuf    runType = tu.getrunType(compBegin);
	PelBuf    runLength = tu.getrunLength(compBegin);
	PelBuf    curPLTIdx = tu.getcurPLTIdx(compBegin);
	uint32_t uiHeight = cu.block(compBegin).height;
	uint32_t uiWidth = cu.block(compBegin).width;

	m_puiScanOrder = g_scanOrder[SCAN_UNGROUPED][(cu.useRotation[compBegin]) ? SCAN_TRAV_VER : SCAN_TRAV_HOR][gp_sizeIdxInfo->idxFrom(uiWidth)][gp_sizeIdxInfo->idxFrom(uiHeight)];

	uint32_t total = uiHeight * uiWidth;

	int iLastRunPos = -1;
	uint32_t lastRunType = 0;
	uint32_t uiNumIndices = 0;
	std::vector<int> vIdxPos, vParsedIdx;
	vIdxPos.reserve(total);
	vParsedIdx.reserve(total);
	if (indexMaxSize > 1)
	{
		int idx = 0, run = 0;
		while (idx < total)
		{
			uint32_t posy = m_puiScanOrder[idx].y;
			uint32_t posx = m_puiScanOrder[idx].x;
			if (runType.at(posx, posy) == PLT_RUN_INDEX)
			{
				vIdxPos.push_back(idx);
				uiNumIndices++;
			}
			lastRunType = runType.at(posx, posy);
			iLastRunPos = idx;
			run = runLength.at(posx, posy);
			idx += run;
		}
		uint32_t currParam = 3 + ((indexMaxSize) >> 3);
		uint32_t uiMappedValue;
		assert(uiNumIndices);
		assert(uiNumIndices > 0);
		uiMappedValue = uiNumIndices - 1;
		m_BinEncoder.encodeRemAbsEP(uiMappedValue, currParam, false, MAX_NUM_CHANNEL_TYPE); // JC: code number of indices (PLT_RUN_INDEX)
		auto vIdxPosEnd = vIdxPos.end();
		for (auto iter = vIdxPos.begin(); iter != vIdxPosEnd; ++iter)
		{
			vParsedIdx.push_back( writePLTIndex(cu, *iter, curPLTIdx, runType, indexMaxSize, compBegin));
		}
		m_BinEncoder.encodeBin(lastRunType, Ctx::RunTypeFlag());
		codeScanRotationModeFlag(cu, compBegin);
	}
	else
	{
		assert(!cu.useRotation[compBegin]);
	}

	if (cu.useEscape[compBegin] && cu.cs->pps->getUseDQP() && !cuCtx.isDQPCoded)
	{
		if (!CS::isDualITree(*tu.cs) || isLuma(tu.chType))
		{
			cu_qp_delta(cu, cuCtx.qp, cu.qp);
			cuCtx.qp = cu.qp;
			cuCtx.isDQPCoded = true;
		}
	}
#if JVET_O1168_CU_CHROMA_QP_OFFSET
	if ( cu.useEscape[compBegin] && cu.cs->slice->getUseChromaQpAdj() && !cuCtx.isChromaQpAdjCoded)
#else
	if (cu.cs->slice->getUseChromaQpAdj() && !cu.transQuantBypass && !cuCtx.isChromaQpAdjCoded)
#endif
	{
		if (!CS::isDualITree(*tu.cs) || isChroma(tu.chType))
		{
			cu_chroma_qp_offset(cu);
			cuCtx.isChromaQpAdjCoded = true;
		}
	}

	uint32_t strPos = 0;
	uint32_t endPos = uiHeight * uiWidth;
	auto vParsedIdxEnd = vParsedIdx.end();
	auto vParsedIdxIter = vParsedIdx.begin();
	while (strPos < endPos)
	{
		uint32_t posy = m_puiScanOrder[strPos].y;
		uint32_t posx = m_puiScanOrder[strPos].x;
		uint32_t posyprev = strPos == 0 ? 0 : m_puiScanOrder[strPos - 1].y;
		uint32_t posxprev = strPos == 0 ? 0 : m_puiScanOrder[strPos - 1].x;

		if (indexMaxSize > 1)
		{
			if (((posy == 0) && !cu.useRotation[compBegin]) || ((posx == 0) && cu.useRotation[compBegin]))

			{
				assert(runType.at(posx, posy) == PLT_RUN_INDEX);
			}
			else if (strPos != 0 && runType.at(posxprev, posyprev) == PLT_RUN_COPY)
			{
				assert(runType.at(posx, posy) == PLT_RUN_INDEX);
			}
			else
			{
				if (uiNumIndices && strPos < endPos - 1) // if uiNumIndices (decoder will know this value) == 0 - > only CopyAbove, if strPos == endPos - 1, the last RunType was already coded
				{
					m_BinEncoder.encodeBin((runType.at(posx, posy)), Ctx::RunTypeFlag());
				}
			}
		}

		Pel siCurLevel = 0;
		if (runType.at(posx, posy) == PLT_RUN_INDEX)
		{
			if (vParsedIdxIter != vParsedIdxEnd)
			{
				siCurLevel = *vParsedIdxIter++;
			}
			else
			{
				siCurLevel = 0;
			}
		}

		if (indexMaxSize > 1)
		{
			if (iLastRunPos != strPos)
			{
				uiNumIndices -= (runType.at(posx, posy) == PLT_RUN_INDEX);
				cu_run_val(runLength.at(posx, posy) - 1, (PLTRunMode)runType.at(posx, posy), siCurLevel, endPos - strPos - uiNumIndices - 1 - lastRunType);
			}

		}

		strPos += (runLength.at(posx, posy));
	}
	assert(strPos == endPos);

	uint32_t scaleX = getComponentScaleX(COMPONENT_Cb, sps.getChromaFormatIdc());
	uint32_t scaleY = getComponentScaleY(COMPONENT_Cb, sps.getChromaFormatIdc());
	for (int comp = compBegin; comp < (compBegin + numComp); comp++)
	{
		ComponentID compID = (ComponentID)comp;
		for (strPos = 0; strPos < endPos; strPos++)
		{
			uint32_t posy = m_puiScanOrder[strPos].y;
			uint32_t posx = m_puiScanOrder[strPos].x;
			if (curPLTIdx.at(posx, posy) == cu.curPLTSize[compBegin])
			{
				{
					PLTescapeBuf    escapeValue = tu.getescapeValue((ComponentID)comp);
					if (compID == COMPONENT_Y || compBegin != COMPONENT_Y)
					{
						exp_golomb_eqprob((unsigned)escapeValue.at(posx, posy), 3);
					}
					if (compBegin == COMPONENT_Y && compID != COMPONENT_Y && posy % (1 << scaleY) == 0 && posx % (1 << scaleX) == 0)
					{
						uint32_t posxC = posx >> scaleX;
						uint32_t posyC = posy >> scaleY;
						exp_golomb_eqprob((unsigned)escapeValue.at(posxC, posyC), 3);
					}
				}
			}
		}
	}

}
void CABACWriter::codeScanRotationModeFlag(const CodingUnit& cu, ComponentID compBegin)
{
	m_BinEncoder.encodeBin((cu.useRotation[compBegin]), Ctx::RotationFlag());
}
void CABACWriter::xEncodePLTPredIndicator(const CodingUnit& cu, uint32_t uiMaxPLTSize, ComponentID compBegin)
{
	int lastPredIdx = -1;
	uint32_t run = 0;
	uint32_t uiNumPLTPredicted = 0;
	for (uint32_t idx = 0; idx < cu.lastPLTSize[compBegin]; idx++)
	{
		if (cu.reuseflag[compBegin][idx])
		{
			uiNumPLTPredicted++;
			lastPredIdx = idx;
		}
	}

	int idx = 0;
	while (idx <= lastPredIdx)
	{
		if (cu.reuseflag[compBegin][idx])
		{
			exp_golomb_eqprob(run ? run + 1 : run, 0);
			run = 0;
		}
		else
		{
			run++;
		}
		idx++;
	}
	if ((uiNumPLTPredicted < uiMaxPLTSize && lastPredIdx + 1 < cu.lastPLTSize[compBegin]) || !uiNumPLTPredicted)
	{
		exp_golomb_eqprob(1, 0);
	}
}
Pel CABACWriter::writePLTIndex(const CodingUnit& cu, uint32_t idx, PelBuf& paletteIdx, PLTtypeBuf& paletteRunType, int maxSymbol, ComponentID compBegin)
{
	uint32_t posy = m_puiScanOrder[idx].y;
	uint32_t posx = m_puiScanOrder[idx].x;
	Pel siCurLevel = (paletteIdx.at(posx, posy) == cu.curPLTSize[compBegin]) ? (maxSymbol - 1) : paletteIdx.at(posx, posy);
	if (idx) // R0348: remove index redundancy
	{
		uint32_t prevposy = m_puiScanOrder[idx - 1].y;
		uint32_t prevposx = m_puiScanOrder[idx - 1].x;
		if (paletteRunType.at(prevposx, prevposy) == PLT_RUN_INDEX)
			Pel siLeftLevel = paletteIdx.at(prevposx, prevposy); // left index
			if (siLeftLevel == cu.curPLTSize[compBegin]) // escape mode
			{
				siLeftLevel = maxSymbol - 1;
			}
			assert(siLeftLevel != siCurLevel);
			if (siCurLevel > siLeftLevel)
			{
				siCurLevel--;
			}
		}
		else
		{
			Pel siAboveLevel;
			if (cu.useRotation[compBegin])
			{
				assert(prevposx > 0);
				siAboveLevel = paletteIdx.at(posx - 1, posy);
				if (paletteIdx.at(posx - 1, posy) == cu.curPLTSize[compBegin]) // escape mode
				siAboveLevel = paletteIdx.at(posx, posy - 1);
				if (paletteIdx.at(posx, posy - 1) == cu.curPLTSize[compBegin]) // escape mode
				{
					siAboveLevel = maxSymbol - 1;
				}
			}
			assert(siCurLevel != siAboveLevel);
			if (siCurLevel > siAboveLevel)
			{
				siCurLevel--;
			}
		}
		maxSymbol--;
	}
	assert(maxSymbol > 0);
	assert(siCurLevel >= 0);
	assert(maxSymbol > siCurLevel);
	if (maxSymbol > 1)
	{
		xWriteTruncBinCode(siCurLevel, maxSymbol);
	}
	return siCurLevel;
}

void CABACWriter::encodeRunType(const CodingUnit&  cu, PLTtypeBuf& runType, uint32_t idx, ScanElement *refScanOrder, ComponentID compBegin)
{
	if (refScanOrder)
	{
		m_puiScanOrder = refScanOrder;
	}
	uint32_t posy = m_puiScanOrder[idx].y;
	uint32_t posx = m_puiScanOrder[idx].x;
	uint32_t posyprev = (idx == 0) ? 0 : m_puiScanOrder[idx - 1].y;
	uint32_t posxprev = (idx == 0) ? 0 : m_puiScanOrder[idx - 1].x;

	if (((posy == 0) && !cu.useRotation[compBegin]) || ((posx == 0) && cu.useRotation[compBegin]))
	{
		assert(runType.at(posx, posy) == PLT_RUN_INDEX);
	}
	else if (idx != 0 && runType.at(posxprev, posyprev) == PLT_RUN_COPY)
	{
		assert(runType.at(posx, posy) == PLT_RUN_INDEX);
	}
	else
	{
		m_BinEncoder.encodeBin((runType.at(posx, posy)), Ctx::RunTypeFlag());
	}
}
void CABACWriter::cu_run_val(uint32_t uiRun, PLTRunMode runtype, const uint32_t uiPltIdx, const uint32_t uiMaxRun)
{
	if (runtype == PLT_RUN_COPY)
	{
	}
	else
	{
		g_ucRunLeftLut[0] = (uiPltIdx < PLT_RUN_MSB_IDX_CTX_T1 ? 0 : (uiPltIdx < PLT_RUN_MSB_IDX_CTX_T2 ? 1 : 2));
	}
	xWriteTruncMsbP1RefinementBits(uiRun, runtype, uiMaxRun, PLT_RUN_MSB_IDX_CABAC_BYPASS_THRE);
}
uint32_t CABACWriter::xWriteTruncMsbP1(uint32_t uiSymbol, PLTRunMode runtype, uint32_t uiMax, uint32_t uiCtxT)
{
	if (uiMax == 0)
		return 0;

	uint8_t *ucCtxLut;
	ucCtxLut = (runtype == PLT_RUN_INDEX) ? g_ucRunLeftLut : g_ucRunTopLut;

	uint32_t uiMsbP1;
	for (uiMsbP1 = 0; uiSymbol > 0; uiMsbP1++)
	{
		uiSymbol >>= 1;
		if (uiMsbP1 > uiCtxT)
		{
			m_BinEncoder.encodeBinEP(1);
		}
		else
			m_BinEncoder.encodeBin(1, (uiMsbP1 <= uiCtxT)
				? ((runtype == PLT_RUN_INDEX) ? Ctx::IdxRunModel(ucCtxLut[uiMsbP1]) : Ctx::CopyRunModel(ucCtxLut[uiMsbP1]))
				: ((runtype == PLT_RUN_INDEX) ? Ctx::IdxRunModel(ucCtxLut[uiCtxT]) : Ctx::CopyRunModel(ucCtxLut[uiCtxT])));
	}
	assert(uiMsbP1 <= uiMax);
	if (uiMsbP1 < uiMax)
	{
		if (uiMsbP1 > uiCtxT)
		{
			m_BinEncoder.encodeBinEP(0);
		}
		else
			m_BinEncoder.encodeBin(0, uiMsbP1 <= uiCtxT
				? ((runtype == PLT_RUN_INDEX) ? Ctx::IdxRunModel(ucCtxLut[uiMsbP1]) : Ctx::CopyRunModel(ucCtxLut[uiMsbP1]))
				: ((runtype == PLT_RUN_INDEX) ? Ctx::IdxRunModel(ucCtxLut[uiCtxT]) : Ctx::CopyRunModel(ucCtxLut[uiCtxT])));

		//m_pcBinIf->encodeBin(0, uiMsbP1 <= uiCtxT? pcSCModel[ucCtxLut[uiMsbP1]] : pcSCModel[ucCtxLut[uiCtxT]]);
	}
	return uiMsbP1;
}
void CABACWriter::xWriteTruncMsbP1RefinementBits(uint32_t uiSymbol, PLTRunMode runtype, uint32_t uiMax, uint32_t uiCtxT)
{
	if (uiMax == 0)
		return;

	uint32_t uiMsbP1 = xWriteTruncMsbP1(uiSymbol, runtype, g_getMsbP1Idx(uiMax), uiCtxT);
	if (uiMsbP1 > 1)
	{
		uint32_t uiNumBins = g_getMsbP1Idx(uiMax);
		if (uiMsbP1 < uiNumBins)
		{

			uint32_t uiBits = uiMsbP1 - 1;
			m_BinEncoder.encodeBinsEP(uiSymbol & ((1 << uiBits) - 1), uiBits);
		}
		else
		{
			uint32_t curValue = 1 << (uiNumBins - 1);
			xWriteTruncBinCode(uiSymbol - curValue, uiMax + 1 - curValue);
		}
	}
}

//================================================================================
//  clause 7.3.8.6
//--------------------------------------------------------------------------------
//    void  prediction_unit ( pu );
//    void  merge_flag      ( pu );
//    void  merge_idx       ( pu );
//    void  inter_pred_idc  ( pu );
//    void  ref_idx         ( pu, refList );
//    void  mvp_flag        ( pu, refList );
//================================================================================

void CABACWriter::prediction_unit( const PredictionUnit& pu )
{
#if ENABLE_SPLIT_PARALLELISM || ENABLE_WPP_PARALLELISM
  CHECK( pu.cacheUsed, "Processing a PU that should be in cache!" );
  CHECK( pu.cu->cacheUsed, "Processing a CU that should be in cache!" );

#endif
  if( pu.cu->skip )
  {
    CHECK( !pu.mergeFlag, "merge_flag must be true for skipped CUs" );
  }
  else
  {
    merge_flag( pu );
  }
  if( pu.mergeFlag )
  {
Yu Han's avatar
Yu Han committed
    if (CU::isIBC(*pu.cu))
    {
      merge_idx(pu);
      return;
    }
    if (pu.regularMergeFlag)
      merge_idx(pu);
Yi-Wen Chen's avatar
Yi-Wen Chen committed
      subblock_merge_flag( *pu.cu );
      MHIntra_flag( pu );
      if (!pu.mhIntraFlag)
      {
        if (!pu.cu->affine && !pu.mmvdMergeFlag && !pu.cu->mmvdSkip)
        {
          CHECK(!pu.cu->triangle, "triangle_flag must be true");
        }
      }
Yi-Wen Chen's avatar
Yi-Wen Chen committed
      if (pu.mmvdMergeFlag)
      {
        mmvd_merge_idx(pu);
      }
      else
        merge_idx    ( pu );
Yu Han's avatar
Yu Han committed
  else if (CU::isIBC(*pu.cu))
  {
    ref_idx(pu, REF_PIC_LIST_0);
Xiang Li's avatar
Xiang Li committed
    Mv mvd = pu.mvd[REF_PIC_LIST_0];
    mvd.changeIbcPrecInternal2Amvr(pu.cu->imv);
    mvd_coding(mvd, 0); // already changed to signaling precision
#if JVET_O0162_IBC_MVP_FLAG
    if ( pu.cu->slice->getMaxNumMergeCand() == 1 )
    {
      CHECK( pu.mvpIdx[REF_PIC_LIST_0], "mvpIdx for IBC mode should be 0" );
    }
    else
#endif
Yu Han's avatar
Yu Han committed
    mvp_flag(pu, REF_PIC_LIST_0);
  }
    smvd_mode( pu );
    if( pu.interDir != 2 /* PRED_L1 */ )
    {
      ref_idx     ( pu, REF_PIC_LIST_0 );
      if ( pu.cu->affine )
      {
Xiang Li's avatar
Xiang Li committed
        Mv mvd = pu.mvdAffi[REF_PIC_LIST_0][0];
        mvd.changeAffinePrecInternal2Amvr(pu.cu->imv);
        mvd_coding(mvd, 0); // already changed to signaling precision
        mvd = pu.mvdAffi[REF_PIC_LIST_0][1];
        mvd.changeAffinePrecInternal2Amvr(pu.cu->imv);
        mvd_coding(mvd, 0); // already changed to signaling precision
        if ( pu.cu->affineType == AFFINEMODEL_6PARAM )
        {
Xiang Li's avatar
Xiang Li committed
          mvd = pu.mvdAffi[REF_PIC_LIST_0][2];
          mvd.changeAffinePrecInternal2Amvr(pu.cu->imv);
          mvd_coding(mvd, 0); // already changed to signaling precision
Xiang Li's avatar
Xiang Li committed
        Mv mvd = pu.mvd[REF_PIC_LIST_0];
        mvd.changeTransPrecInternal2Amvr(pu.cu->imv);
        mvd_coding(mvd, 0); // already changed to signaling precision
      }
      mvp_flag    ( pu, REF_PIC_LIST_0 );
    }
    if( pu.interDir != 1 /* PRED_L0 */ )
    {
      if ( pu.cu->smvdMode != 1 )
      {
      ref_idx     ( pu, REF_PIC_LIST_1 );
      if( !pu.cs->slice->getMvdL1ZeroFlag() || pu.interDir != 3 /* PRED_BI */ )
      {
        if ( pu.cu->affine )
        {
Xiang Li's avatar
Xiang Li committed
          Mv mvd = pu.mvdAffi[REF_PIC_LIST_1][0];
          mvd.changeAffinePrecInternal2Amvr(pu.cu->imv);
          mvd_coding(mvd, 0); // already changed to signaling precision
          mvd = pu.mvdAffi[REF_PIC_LIST_1][1];
          mvd.changeAffinePrecInternal2Amvr(pu.cu->imv);
          mvd_coding(mvd, 0); // already changed to signaling precision
          if ( pu.cu->affineType == AFFINEMODEL_6PARAM )
          {
Xiang Li's avatar
Xiang Li committed
            mvd = pu.mvdAffi[REF_PIC_LIST_1][2];
            mvd.changeAffinePrecInternal2Amvr(pu.cu->imv);
            mvd_coding(mvd, 0); // already changed to signaling precision
Xiang Li's avatar
Xiang Li committed
          Mv mvd = pu.mvd[REF_PIC_LIST_1];
          mvd.changeTransPrecInternal2Amvr(pu.cu->imv);
          mvd_coding(mvd, 0); // already changed to signaling precision
void CABACWriter::smvd_mode( const PredictionUnit& pu )
{
  if ( pu.interDir != 3 || pu.cu->affine )
  {
    return;
  }

  if ( pu.cs->slice->getBiDirPred() == false )
  {
    return;
  }

  m_BinEncoder.encodeBin( pu.cu->smvdMode ? 1 : 0, Ctx::SmvdFlag() );

  DTRACE( g_trace_ctx, D_SYNTAX, "symmvd_flag() symmvd=%d pos=(%d,%d) size=%dx%d\n", pu.cu->smvdMode ? 1 : 0, pu.lumaPos().x, pu.lumaPos().y, pu.lumaSize().width, pu.lumaSize().height );
}

void CABACWriter::subblock_merge_flag( const CodingUnit& cu )
{
Huanbang Chen's avatar
Huanbang Chen committed
  if ( cu.firstPU->mergeFlag && (cu.firstPU->mmvdMergeFlag || cu.mmvdSkip) )
  {
    return;
  }

  if ( !cu.cs->slice->isIntra() && (cu.cs->sps->getUseAffine() || cu.cs->sps->getSBTMVPEnabledFlag()) && cu.lumaSize().width >= 8 && cu.lumaSize().height >= 8 )
  {
    unsigned ctxId = DeriveCtx::CtxAffineFlag( cu );
#if JVET_O0500_SEP_CTX_AFFINE_SUBBLOCK_MRG
    m_BinEncoder.encodeBin( cu.affine, Ctx::SubblockMergeFlag( ctxId ) );
#else
    m_BinEncoder.encodeBin( cu.affine, Ctx::AffineFlag( ctxId ) );
    DTRACE( g_trace_ctx, D_SYNTAX, "subblock_merge_flag() subblock_merge_flag=%d ctx=%d pos=(%d,%d)\n", cu.affine ? 1 : 0, ctxId, cu.Y().x, cu.Y().y );
  }
}

void CABACWriter::affine_flag( const CodingUnit& cu )
{
  if ( !cu.cs->slice->isIntra() && cu.cs->sps->getUseAffine() && cu.lumaSize().width > 8 && cu.lumaSize().height > 8 )
  {
    unsigned ctxId = DeriveCtx::CtxAffineFlag( cu );
    m_BinEncoder.encodeBin( cu.affine, Ctx::AffineFlag( ctxId ) );
    DTRACE( g_trace_ctx, D_SYNTAX, "affine_flag() affine=%d ctx=%d pos=(%d,%d)\n", cu.affine ? 1 : 0, ctxId, cu.Y().x, cu.Y().y );

    if ( cu.affine && cu.cs->sps->getUseAffineType() )
    {
      unsigned ctxId = 0;
      m_BinEncoder.encodeBin( cu.affineType, Ctx::AffineType( ctxId ) );
      DTRACE( g_trace_ctx, D_SYNTAX, "affine_type() affine_type=%d ctx=%d pos=(%d,%d)\n", cu.affineType ? 1 : 0, ctxId, cu.Y().x, cu.Y().y );
    }
  }
}

void CABACWriter::merge_flag( const PredictionUnit& pu )
{
  m_BinEncoder.encodeBin( pu.mergeFlag, Ctx::MergeFlag() );

  DTRACE( g_trace_ctx, D_SYNTAX, "merge_flag() merge=%d pos=(%d,%d) size=%dx%d\n", pu.mergeFlag ? 1 : 0, pu.lumaPos().x, pu.lumaPos().y, pu.lumaSize().width, pu.lumaSize().height );
Yu Han's avatar
Yu Han committed
  if (pu.mergeFlag && CU::isIBC(*pu.cu))
  {
    return;
  }
  if (pu.mergeFlag)
  {
Yi-Wen Chen's avatar
Yi-Wen Chen committed
    if (!pu.cs->sps->getUseMMVD() && (pu.lwidth() * pu.lheight() == 32))
    {
      CHECK(!pu.regularMergeFlag, "regular_merge_flag must be true!");
    }
    else
    {
      m_BinEncoder.encodeBin(pu.regularMergeFlag, Ctx::RegularMergeFlag(1));
      DTRACE(g_trace_ctx, D_SYNTAX, "regularMergeFlag() ctx=%d regularMergeFlag=%d\n", 1, pu.regularMergeFlag?1:0);
    }
Yi-Wen Chen's avatar
Yi-Wen Chen committed
    if (pu.cs->sps->getUseMMVD())
    {
      bool isCUWithOnlyRegularAndMMVD=((pu.lwidth() == 8 && pu.lheight() == 4) || (pu.lwidth() == 4 && pu.lheight() == 8));
      if (isCUWithOnlyRegularAndMMVD)
      {
        CHECK(pu.mmvdMergeFlag==pu.regularMergeFlag, "mmvdMergeFlag must be !regularMergeFlag");
      }
      else if (!pu.regularMergeFlag)
      {
        m_BinEncoder.encodeBin(pu.mmvdMergeFlag, Ctx::MmvdFlag(0));
        DTRACE(g_trace_ctx, D_SYNTAX, "mmvd_merge_flag() mmvd_merge=%d pos=(%d,%d) size=%dx%d\n", pu.mmvdMergeFlag ? 1 : 0, pu.lumaPos().x, pu.lumaPos().y, pu.lumaSize().width, pu.lumaSize().height);
      }
  const SPS *sps = cu.cs->sps;
  if( !sps->getAMVREnabledFlag() )

  bool bNonZeroMvd = CU::hasSubCUNonZeroMVd( cu );
  if( !bNonZeroMvd )
  {
    return;
  }

Yu Han's avatar
Yu Han committed
  if (CU::isIBC(cu) == false)
    m_BinEncoder.encodeBin( (cu.imv > 0), Ctx::ImvFlag( 0 ) );
  DTRACE( g_trace_ctx, D_SYNTAX, "imv_mode() value=%d ctx=%d\n", (cu.imv > 0), 0 );
  if( sps->getAMVREnabledFlag() && cu.imv > 0 )
    m_BinEncoder.encodeBin( (cu.imv > 1), Ctx::ImvFlag( 1 ) );
    DTRACE( g_trace_ctx, D_SYNTAX, "imv_mode() value=%d ctx=%d\n", (cu.imv > 1), 1 );
  }

  DTRACE( g_trace_ctx, D_SYNTAX, "imv_mode() IMVFlag=%d\n", cu.imv );
}

void CABACWriter::affine_amvr_mode( const CodingUnit& cu )
{
  const SPS* sps = cu.slice->getSPS();

  if( !sps->getAffineAmvrEnabledFlag() || !cu.affine )
  {
    return;
  }

  if ( !CU::hasSubCUNonZeroAffineMVd( cu ) )
  {
    return;
  }

  m_BinEncoder.encodeBin( (cu.imv > 0), Ctx::ImvFlag( 2 ) );
  DTRACE( g_trace_ctx, D_SYNTAX, "affine_amvr_mode() value=%d ctx=%d\n", (cu.imv > 0), 2 );
    m_BinEncoder.encodeBin( (cu.imv > 1), Ctx::ImvFlag( 3 ) );
    DTRACE( g_trace_ctx, D_SYNTAX, "affine_amvr_mode() value=%d ctx=%d\n", (cu.imv > 1), 3 );
  }
  DTRACE( g_trace_ctx, D_SYNTAX, "affine_amvr_mode() IMVFlag=%d\n", cu.imv );
}

void CABACWriter::merge_idx( const PredictionUnit& pu )
{

  if ( pu.cu->affine )
  {
    int numCandminus1 = int( pu.cs->slice->getMaxNumAffineMergeCand() ) - 1;
    if ( numCandminus1 > 0 )
    {
      if ( pu.mergeIdx == 0 )
      {
        m_BinEncoder.encodeBin( 0, Ctx::AffMergeIdx() );
        DTRACE( g_trace_ctx, D_SYNTAX, "aff_merge_idx() aff_merge_idx=%d\n", pu.mergeIdx );
        return;
      }
      else
      {
        m_BinEncoder.encodeBin( 1, Ctx::AffMergeIdx() );
        for ( unsigned idx = 1; idx < numCandminus1; idx++ )
        {
            m_BinEncoder.encodeBinEP( pu.mergeIdx == idx ? 0 : 1 );
          if ( pu.mergeIdx == idx )
          {
            break;
          }
        }
      }
    }
    DTRACE( g_trace_ctx, D_SYNTAX, "aff_merge_idx() aff_merge_idx=%d\n", pu.mergeIdx );
  }
  else
  {
      bool    splitDir = pu.triangleSplitDir;
      uint8_t candIdx0 = pu.triangleMergeIdx0;
      uint8_t candIdx1 = pu.triangleMergeIdx1;
      DTRACE( g_trace_ctx, D_SYNTAX, "merge_idx() triangle_split_dir=%d\n", splitDir );
      DTRACE( g_trace_ctx, D_SYNTAX, "merge_idx() triangle_idx0=%d\n", candIdx0 );
      DTRACE( g_trace_ctx, D_SYNTAX, "merge_idx() triangle_idx1=%d\n", candIdx1 );
      candIdx1 -= candIdx1 < candIdx0 ? 0 : 1;
      auto encodeOneIdx = [this](uint8_t mrgIdx, int numCandminus1)
      {
        if (numCandminus1 == 0)
        {
          CHECK(mrgIdx, "Incorrect index!");
          return;
        }
        if(mrgIdx == 0)
        {
          this->m_BinEncoder.encodeBin( 0, Ctx::MergeIdx() );
          return;
        }
        else
        {
          this->m_BinEncoder.encodeBin( 1, Ctx::MergeIdx() );
          for( unsigned idx = 1; idx < numCandminus1; idx++ )
          {
            this->m_BinEncoder.encodeBinEP( mrgIdx == idx ? 0 : 1 );
            if( mrgIdx == idx )
            {
              break;
            }
Loading
Loading full blame...