Skip to content
Snippets Groups Projects
CABACWriter.cpp 81.4 KiB
Newer Older
  • Learn to ignore specific revisions
  • 
      ChromaCbfs chromaCbfs;
      transform_tree( *cu.cs, partitioner, cuCtx, chromaCbfs );
    
    
    #if !HM_EMT_NSST_AS_IN_JEM
    
    #if !HM_EMT_NSST_AS_IN_JEM
    
    void CABACWriter::cu_emt_pertu_idx( const CodingUnit& cu )
    {
      bool anyCbf = false, anyNonTs = false;
    
      for( const auto &tu : CU::traverseTUs( cu ) )
      {
        anyCbf   |= tu.cbf[0] != 0;
        anyNonTs |= !tu.transformSkip[0];
      }
    
      if( !cu.cs->pcv->noRQT || !isLuma( cu.chType ) || cu.nsstIdx != 0 ||
          !( cu.cs->sps->getSpsNext().getUseIntraEMT() || cu.cs->sps->getSpsNext().getUseInterEMT() ) || !anyCbf || !anyNonTs )
      {
        return;
      }
    
      emt_cu_flag( cu );
    
      if( cu.emtFlag )
      {
        for( const auto &tu : CU::traverseTUs( cu ) )
        {
          if( CU::isIntra( cu ) )
          {
            if( TU::getNumNonZeroCoeffsNonTS( tu, true, false ) > g_EmtSigNumThr )
            {
              emt_tu_index( tu );
            }
            else
            {
              CHECK( tu.emtIdx != 0, "If the number of significant coefficients is <= g_EmtSigNumThr, then the tu index must be 0" );
            }
          }
          else
          {
            emt_tu_index( *cu.firstTU );
          }
        }
      }
    }
    
    #endif
    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::end_of_ctu( const CodingUnit& cu, CUCtx& cuCtx )
    {
      const Slice*  slice             = cu.cs->slice;
    #if HEVC_TILES_WPP
      const TileMap& tileMap          = *cu.cs->picture->tileMap;
      const int     currentCTUTsAddr  = tileMap.getCtuRsToTsAddrMap( CU::getCtuAddr( cu ) );
    #else
      const int     currentCTUTsAddr  = CU::getCtuAddr( cu );
    #endif
      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 HEVC_DEPENDENT_SLICES
        if( slice->getSliceSegmentCurEndCtuTsAddr() != currentCTUTsAddr + 1 )
    #else
        if(slice->getSliceCurEndCtuTsAddr() != currentCTUTsAddr + 1)
    #endif
        {
          m_BinEncoder.encodeBinTrm( 0 );
        }
      }
    }
    
    
    
    
    
    //================================================================================
    //  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 )
      {
        affine_flag  ( *pu.cu );
    
    #if JVET_L0054_MMVD
        if (pu.mmvdMergeFlag)
        {
          mmvd_merge_idx(pu);
        }
        else
    #endif
    
        merge_idx    ( pu );
      }
      else
      {
        inter_pred_idc( pu );
        affine_flag   ( *pu.cu );
        if( pu.interDir != 2 /* PRED_L1 */ )
        {
          ref_idx     ( pu, REF_PIC_LIST_0 );
          if ( pu.cu->affine )
          {
            mvd_coding(pu.mvdAffi[REF_PIC_LIST_0][0], 0);
            mvd_coding(pu.mvdAffi[REF_PIC_LIST_0][1], 0);
            if ( pu.cu->affineType == AFFINEMODEL_6PARAM )
            {
              mvd_coding(pu.mvdAffi[REF_PIC_LIST_0][2], 0);
            }
          }
          else
          {
            mvd_coding( pu.mvd[REF_PIC_LIST_0], pu.cu->imv );
          }
          mvp_flag    ( pu, REF_PIC_LIST_0 );
        }
        if( pu.interDir != 1 /* PRED_L0 */ )
        {
          ref_idx     ( pu, REF_PIC_LIST_1 );
          if( !pu.cs->slice->getMvdL1ZeroFlag() || pu.interDir != 3 /* PRED_BI */ )
          {
            if ( pu.cu->affine )
            {
              mvd_coding(pu.mvdAffi[REF_PIC_LIST_1][0], 0);
              mvd_coding(pu.mvdAffi[REF_PIC_LIST_1][1], 0);
              if ( pu.cu->affineType == AFFINEMODEL_6PARAM )
              {
                mvd_coding(pu.mvdAffi[REF_PIC_LIST_1][2], 0);
              }
            }
            else
            {
              mvd_coding( pu.mvd[REF_PIC_LIST_1], pu.cu->imv );
            }
          }
          mvp_flag    ( pu, REF_PIC_LIST_1 );
        }
      }
    }
    
    void CABACWriter::affine_flag( const CodingUnit& cu )
    {
      if( cu.cs->slice->isIntra() || !cu.cs->sps->getSpsNext().getUseAffine() || cu.partSize != SIZE_2Nx2N )
      {
        return;
      }
    
      if( !cu.firstPU->mergeFlag && !( cu.lumaSize().width > 8 && cu.lumaSize().height > 8 ) )
      {
        return;
      }
    
      if( cu.firstPU->mergeFlag && !PU::isAffineMrgFlagCoded( *cu.firstPU ) )
      {
        return;
      }
    
      CHECK( !cu.cs->pcv->rectCUs && cu.lumaSize().width != cu.lumaSize().height, "CU width and height are not equal for QTBT off." );
    
    #if JVET_L0054_MMVD
      if (cu.firstPU->mergeFlag && (cu.firstPU->mmvdMergeFlag || cu.mmvdSkip))
      {
        return;
      }
    #endif
    
      unsigned ctxId = DeriveCtx::CtxAffineFlag( cu );
      m_BinEncoder.encodeBin( cu.affine, Ctx::AffineFlag( ctxId ) );
      DTRACE( g_trace_ctx, D_COMMON, " (%d) affine_flag() affine=%d\n", DTRACE_GET_COUNTER(g_trace_ctx, D_COMMON), cu.affine ? 1 : 0 );
    
      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.firstPU->mergeFlag && cu.cs->sps->getSpsNext().getUseAffineType() )
      {
        unsigned ctxId = 0;
        m_BinEncoder.encodeBin( cu.affineType, Ctx::AffineType( ctxId ) );
    
        DTRACE( g_trace_ctx, D_COMMON, " (%d) affine_type() affine_type=%d\n", DTRACE_GET_COUNTER( g_trace_ctx, D_COMMON ), cu.affineType ? 1 : 0 );
        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 );
    
    #if JVET_L0054_MMVD
      if (pu.mergeFlag)
      {
        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);
      }
    #endif
    
    }
    
    void CABACWriter::imv_mode( const CodingUnit& cu )
    {
      const SPSNext& spsNext = cu.cs->sps->getSpsNext();
    
      if( !spsNext.getUseIMV() )
      {
        return;
      }
    
      bool bNonZeroMvd = CU::hasSubCUNonZeroMVd( cu );
      if( !bNonZeroMvd )
      {
        return;
      }
    
      unsigned ctxId = DeriveCtx::CtxIMVFlag( cu );
    
        m_BinEncoder.encodeBin( ( cu.imv > 0 ), Ctx::ImvFlag( ctxId ) );
    
      DTRACE( g_trace_ctx, D_SYNTAX, "imv_mode() value=%d ctx=%d\n", (cu.imv > 0), ctxId );
    
      if( spsNext.getImvMode() == IMV_4PEL && cu.imv > 0 )
      {
        m_BinEncoder.encodeBin( ( cu.imv > 1 ), Ctx::ImvFlag( 3 ) );
        DTRACE( g_trace_ctx, D_SYNTAX, "imv_mode() value=%d ctx=%d\n", ( cu.imv > 1 ), 3 );
      }
    
      DTRACE( g_trace_ctx, D_SYNTAX, "imv_mode() IMVFlag=%d\n", cu.imv );
    }
    
    void CABACWriter::merge_idx( const PredictionUnit& pu )
    {
      if ( pu.cu->affine )
      {
        return;
      }
    
      int numCandminus1 = int( pu.cs->slice->getMaxNumMergeCand() ) - 1;
      if( numCandminus1 > 0 )
      {
        if( pu.mergeIdx == 0 )
        {
          m_BinEncoder.encodeBin( 0, Ctx::MergeIdx() );
          DTRACE( g_trace_ctx, D_SYNTAX, "merge_idx() merge_idx=%d\n", pu.mergeIdx );
          return;
        }
        else
        {
    
    #if !JVET_L0194_ONE_CTX_FOR_MRG_IDX
    
          bool useExtCtx = pu.cs->sps->getSpsNext().getUseSubPuMvp();
    
          m_BinEncoder.encodeBin( 1, Ctx::MergeIdx() );
          for( unsigned idx = 1; idx < numCandminus1; idx++ )
          {
    
    #if !JVET_L0194_ONE_CTX_FOR_MRG_IDX
    
            if( useExtCtx )
            {
              m_BinEncoder.encodeBin( pu.mergeIdx == idx ? 0 : 1, Ctx::MergeIdx( std::min<int>( idx, NUM_MERGE_IDX_EXT_CTX - 1 ) ) );
            }
            else
            {
    
              m_BinEncoder.encodeBinEP( pu.mergeIdx == idx ? 0 : 1 );
    
    #if !JVET_L0194_ONE_CTX_FOR_MRG_IDX
    
            if( pu.mergeIdx == idx )
            {
              break;
            }
          }
        }
      }
      DTRACE( g_trace_ctx, D_SYNTAX, "merge_idx() merge_idx=%d\n", pu.mergeIdx );
    }
    
    #if JVET_L0054_MMVD
    void CABACWriter::mmvd_merge_idx(const PredictionUnit& pu)
    {
      int var0, var1, var2;
      int mvpIdx = pu.mmvdMergeIdx;
      var0 = mvpIdx / MMVD_MAX_REFINE_NUM;
      var1 = (mvpIdx - (var0 * MMVD_MAX_REFINE_NUM)) / 4;
      var2 = mvpIdx - (var0 * MMVD_MAX_REFINE_NUM) - var1 * 4;
    
      int numCandminus1_base = MMVD_BASE_MV_NUM - 1;
      if (numCandminus1_base > 0)
      {
        if (var0 == 0)
        {
          m_BinEncoder.encodeBin(0, Ctx::MmvdMergeIdx());
        }
        else
        {
          m_BinEncoder.encodeBin(1, Ctx::MmvdMergeIdx());
          for (unsigned idx = 1; idx < numCandminus1_base; idx++)
          {
            m_BinEncoder.encodeBinEP(var0 == idx ? 0 : 1);
            if (var0 == idx)
            {
              break;
            }
          }
        }
      }
      DTRACE(g_trace_ctx, D_SYNTAX, "base_mvp_idx() base_mvp_idx=%d\n", var0);
    
      int numCandminus1_step = MMVD_REFINE_STEP - 1;
      if (numCandminus1_step > 0)
      {
        if (var1 == 0)
        {
          m_BinEncoder.encodeBin(0, Ctx::MmvdStepMvpIdx());
        }
        else
        {
          m_BinEncoder.encodeBin(1, Ctx::MmvdStepMvpIdx());
          for (unsigned idx = 1; idx < numCandminus1_step; idx++)
          {
            m_BinEncoder.encodeBinEP(var1 == idx ? 0 : 1);
            if (var1 == idx)
            {
              break;
            }
          }
        }
      }
      DTRACE(g_trace_ctx, D_SYNTAX, "MmvdStepMvpIdx() MmvdStepMvpIdx=%d\n", var1);
    
      m_BinEncoder.encodeBinsEP(var2, 2);
    
      DTRACE(g_trace_ctx, D_SYNTAX, "pos() pos=%d\n", var2);
      DTRACE(g_trace_ctx, D_SYNTAX, "mmvd_merge_idx() mmvd_merge_idx=%d\n", pu.mmvdMergeIdx);
    }
    #endif
    
    void CABACWriter::inter_pred_idc( const PredictionUnit& pu )
    {
      if( !pu.cs->slice->isInterB() )
      {
        return;
      }
    
    #if JVET_L0104_NO_4x4BI_INTER_CU
      if( !(PU::isBipredRestriction(pu)) && ( pu.cu->partSize == SIZE_2Nx2N || pu.cs->sps->getSpsNext().getUseSubPuMvp() || pu.cu->lumaSize().width != 8 ) )
    #else
    
      if( pu.cu->partSize == SIZE_2Nx2N || pu.cs->sps->getSpsNext().getUseSubPuMvp() || pu.cu->lumaSize().width != 8 )
    
      {
        unsigned ctxId = DeriveCtx::CtxInterDir(pu);
        if( pu.interDir == 3 )
        {
          m_BinEncoder.encodeBin( 1, Ctx::InterDir(ctxId) );
          DTRACE( g_trace_ctx, D_SYNTAX, "inter_pred_idc() ctx=%d value=%d pos=(%d,%d)\n", ctxId, pu.interDir, pu.lumaPos().x, pu.lumaPos().y );
          return;
        }
        else
        {
          m_BinEncoder.encodeBin( 0, Ctx::InterDir(ctxId) );
        }
      }
      m_BinEncoder.encodeBin( ( pu.interDir == 2 ), Ctx::InterDir( 4 ) );
      DTRACE( g_trace_ctx, D_SYNTAX, "inter_pred_idc() ctx=4 value=%d pos=(%d,%d)\n", pu.interDir, pu.lumaPos().x, pu.lumaPos().y );
    }
    
    
    void CABACWriter::ref_idx( const PredictionUnit& pu, RefPicList eRefList )
    {
      int numRef  = pu.cs->slice->getNumRefIdx(eRefList);
      if( numRef <= 1 )
      {
        return;
      }
      int refIdx  = pu.refIdx[eRefList];
      m_BinEncoder.encodeBin( (refIdx > 0), Ctx::RefPic() );
      if( numRef <= 2 || refIdx == 0 )
      {
        DTRACE( g_trace_ctx, D_SYNTAX, "ref_idx() value=%d pos=(%d,%d)\n", refIdx, pu.lumaPos().x, pu.lumaPos().y );
        return;
      }
      m_BinEncoder.encodeBin( (refIdx > 1), Ctx::RefPic(1) );
      if( numRef <= 3 || refIdx == 1 )
      {
        DTRACE( g_trace_ctx, D_SYNTAX, "ref_idx() value=%d pos=(%d,%d)\n", refIdx, pu.lumaPos().x, pu.lumaPos().y );
        return;
      }
      for( int idx = 3; idx < numRef; idx++ )
      {
        if( refIdx > idx - 1 )
        {
          m_BinEncoder.encodeBinEP( 1 );
          DTRACE( g_trace_ctx, D_SYNTAX, "ref_idx() value=%d ctxId=%d pos=(%d,%d)\n", 1, 0, pu.lumaPos().x, pu.lumaPos().y );
        }
        else
        {
          m_BinEncoder.encodeBinEP( 0 );
          DTRACE( g_trace_ctx, D_SYNTAX, "ref_idx() value=%d ctxId=%d pos=(%d,%d)\n", 0, 0, pu.lumaPos().x, pu.lumaPos().y );
          break;
        }
      }
      DTRACE( g_trace_ctx, D_SYNTAX, "ref_idx() value=%d pos=(%d,%d)\n", refIdx, pu.lumaPos().x, pu.lumaPos().y );
    }
    
    void CABACWriter::mvp_flag( const PredictionUnit& pu, RefPicList eRefList )
    {
      m_BinEncoder.encodeBin( pu.mvpIdx[eRefList], Ctx::MVPIdx() );
      DTRACE( g_trace_ctx, D_SYNTAX, "mvp_flag() value=%d pos=(%d,%d)\n", pu.mvpIdx[eRefList], pu.lumaPos().x, pu.lumaPos().y );
      DTRACE( g_trace_ctx, D_SYNTAX, "mvpIdx(refList:%d)=%d\n", eRefList, pu.mvpIdx[eRefList] );
    }
    
    
    
    //================================================================================
    //  clause 7.3.8.7
    //--------------------------------------------------------------------------------
    //    void  pcm_samples( tu )
    //================================================================================
    
    void CABACWriter::pcm_samples( const TransformUnit& tu )
    {
      CHECK( !tu.cu->ipcm, "pcm mode expected" );
    
      const SPS&        sps       = *tu.cu->cs->sps;
      const ComponentID maxCompId = ( tu.chromaFormat == CHROMA_400 ? COMPONENT_Y : COMPONENT_Cr );
      for( ComponentID compID = COMPONENT_Y; compID <= maxCompId; compID = ComponentID(compID+1) )
      {
        const CPelBuf   samples     = tu.getPcmbuf( compID );
        const unsigned  sampleBits  = sps.getPCMBitDepth( toChannelType(compID) );
        for( unsigned y = 0; y < samples.height; y++ )
        {
          for( unsigned x = 0; x < samples.width; x++ )
          {
            m_BinEncoder.encodeBinsPCM( samples.at(x, y), sampleBits );
          }
        }
      }
      m_BinEncoder.restart();
    }
    
    
    
    //================================================================================
    //  clause 7.3.8.8
    //--------------------------------------------------------------------------------
    //    void  transform_tree      ( cs, area, cuCtx, chromaCbfs )
    //    bool  split_transform_flag( split, depth )
    //    bool  cbf_comp            ( cbf, area, depth )
    //================================================================================
    
    void CABACWriter::transform_tree( const CodingStructure& cs, Partitioner& partitioner, CUCtx& cuCtx, ChromaCbfs& chromaCbfs )
    {
      const UnitArea&       area          = partitioner.currArea();
    
    #if HM_QTBT_AS_IN_JEM_SYNTAX
      if( cs.pcv->noRQT )
      {
        const TransformUnit &tu = *cs.getTU( area.blocks[partitioner.chType].pos(), partitioner.chType );
    
        transform_unit_qtbt( tu, cuCtx, chromaCbfs );
    
        return;
      }
    #endif
    
      const TransformUnit&  tu            = *cs.getTU( area.blocks[partitioner.chType].pos(), partitioner.chType );
      const CodingUnit&     cu            = *tu.cu;
    #if ENABLE_BMS
      const unsigned        trDepth       = partitioner.currTrDepth;
      const bool            split         = ( tu.depth > trDepth );
    
      // split_transform_flag
      if( cs.pcv->noRQT )
      {
    #if ENABLE_BMS
        if( partitioner.canSplit( TU_MAX_TR_SPLIT, cs ) )
        {
          CHECK( !split, "transform split implied" );
        }
        else
    #endif
        CHECK( split, "transform split not allowed with QTBT" );
      }
    #endif
    
      // cbf_cb & cbf_cr
      if( area.chromaFormat != CHROMA_400 && area.blocks[COMPONENT_Cb].valid() && ( !CS::isDualITree( cs ) || partitioner.chType == CHANNEL_TYPE_CHROMA ) )
      {
        {
    #if ENABLE_BMS
          if( trDepth == 0 || chromaCbfs.Cb )
    #endif
          {
    #if ENABLE_BMS
            chromaCbfs.Cb = TU::getCbfAtDepth( tu, COMPONENT_Cb, trDepth );
            cbf_comp( cs, chromaCbfs.Cb, area.blocks[COMPONENT_Cb], trDepth );
    #else
            chromaCbfs.Cb = TU::getCbf( tu, COMPONENT_Cb );
            cbf_comp( cs, chromaCbfs.Cb, area.blocks[COMPONENT_Cb] );
    #endif
          }
    #if ENABLE_BMS
          else
          {
            CHECK( TU::getCbfAtDepth( tu, COMPONENT_Cb, trDepth ) != chromaCbfs.Cb, "incorrect Cb cbf" );
          }
    
          if( trDepth == 0 || chromaCbfs.Cr )
    #endif
          {
    #if ENABLE_BMS
            chromaCbfs.Cr = TU::getCbfAtDepth( tu, COMPONENT_Cr,   trDepth );
            cbf_comp( cs, chromaCbfs.Cr, area.blocks[COMPONENT_Cr], trDepth, chromaCbfs.Cb );
    #else
            chromaCbfs.Cr = TU::getCbf( tu, COMPONENT_Cr );
            cbf_comp( cs, chromaCbfs.Cr, area.blocks[COMPONENT_Cr], chromaCbfs.Cb );
    #endif
          }
    #if ENABLE_BMS
          else
          {
            CHECK( TU::getCbfAtDepth( tu, COMPONENT_Cr, trDepth ) != chromaCbfs.Cr, "incorrect Cr cbf" );
          }
    #endif
        }
      }
      else if( CS::isDualITree( cs ) )
      {
        chromaCbfs = ChromaCbfs( false );
      }
    
    #if ENABLE_BMS
      if( split )
      {
        if( area.chromaFormat != CHROMA_400 )
        {
          chromaCbfs.Cb        = TU::getCbfAtDepth( tu, COMPONENT_Cb,  trDepth );
          chromaCbfs.Cr        = TU::getCbfAtDepth( tu, COMPONENT_Cr,  trDepth );
        }
    
    #if HM_EMT_NSST_AS_IN_JEM
    
        if( trDepth == 0 ) emt_cu_flag( cu );
    #endif
    
    #if ENABLE_BMS
        if( partitioner.canSplit( TU_MAX_TR_SPLIT, cs ) )
        {
    #if ENABLE_TRACING
          const CompArea &tuArea = partitioner.currArea().blocks[partitioner.chType];
          DTRACE( g_trace_ctx, D_SYNTAX, "transform_tree() maxTrSplit chType=%d pos=(%d,%d) size=%dx%d\n", partitioner.chType, tuArea.x, tuArea.y, tuArea.width, tuArea.height );
    
    #endif
          partitioner.splitCurrArea( TU_MAX_TR_SPLIT, cs );
        }
        else
    #endif
          THROW( "Implicit TU split not available" );
    
        do
        {
          ChromaCbfs subChromaCbfs = chromaCbfs;
          transform_tree( cs, partitioner, cuCtx, subChromaCbfs );
        } while( partitioner.nextPart( cs ) );
    
        partitioner.exitCurrSplit();
      }
      else
    #endif
      {
    #if ENABLE_BMS
        DTRACE( g_trace_ctx, D_SYNTAX, "transform_unit() pos=(%d,%d) size=%dx%d depth=%d trDepth=%d\n", tu.blocks[tu.chType].x, tu.blocks[tu.chType].y, tu.blocks[tu.chType].width, tu.blocks[tu.chType].height, cu.depth, partitioner.currTrDepth );
    #else
        DTRACE( g_trace_ctx, D_SYNTAX, "transform_unit() pos=(%d,%d) size=%dx%d depth=%d\n", tu.blocks[tu.chType].x, tu.blocks[tu.chType].y, tu.blocks[tu.chType].width, tu.blocks[tu.chType].height, cu.depth );
    #endif
    
        if( !isChroma( partitioner.chType ) )
        {
    #if ENABLE_BMS
          if( !CU::isIntra( cu ) && trDepth == 0 && !chromaCbfs.sigChroma( area.chromaFormat ) )
          {
            CHECK( !TU::getCbfAtDepth( tu, COMPONENT_Y, trDepth ), "Luma cbf must be true for inter units with no chroma coeffs" );
          }
    #else
          if( !CU::isIntra( cu ) && !chromaCbfs.sigChroma( area.chromaFormat ) )
          {
            CHECK( !TU::getCbf( tu, COMPONENT_Y ), "Luma cbf must be true for inter units with no chroma coeffs" );
          }
    #endif
          else
          {
    #if ENABLE_BMS
            cbf_comp( cs, TU::getCbfAtDepth( tu, COMPONENT_Y, trDepth ), tu.Y(), trDepth );
    #else
            cbf_comp( cs, TU::getCbf( tu, COMPONENT_Y ), tu.Y() );
    #endif
          }
        }
    
    
    #if HM_EMT_NSST_AS_IN_JEM
    
    #if ENABLE_BMS
        if( trDepth == 0 && TU::getCbfAtDepth( tu, COMPONENT_Y, 0 ) ) emt_cu_flag( cu );
    #else
        if( TU::getCbf( tu, COMPONENT_Y ) ) emt_cu_flag( cu );
    #endif
    #endif
    
        transform_unit( tu, cuCtx, chromaCbfs );
      }
    }
    
    #if ENABLE_BMS
    void CABACWriter::cbf_comp( const CodingStructure& cs, bool cbf, const CompArea& area, unsigned depth, const bool prevCbCbf )
    #else
    void CABACWriter::cbf_comp( const CodingStructure& cs, bool cbf, const CompArea& area, const bool prevCbCbf )
    #endif
    {
    #if ENABLE_BMS
      const unsigned  ctxId   = DeriveCtx::CtxQtCbf( area.compID, depth, prevCbCbf );
    #else
      const unsigned  ctxId   = DeriveCtx::CtxQtCbf( area.compID, prevCbCbf );
    #endif
      const CtxSet&   ctxSet  = Ctx::QtCbf[ area.compID ];
    
      m_BinEncoder.encodeBin( cbf, ctxSet( ctxId ) );
      DTRACE( g_trace_ctx, D_SYNTAX, "cbf_comp() etype=%d pos=(%d,%d) ctx=%d cbf=%d\n", area.compID, area.x, area.y, ctxId, cbf );
    }
    
    
    
    
    
    //================================================================================
    //  clause 7.3.8.9
    //--------------------------------------------------------------------------------
    //    void  mvd_coding( pu, refList )
    //================================================================================
    
    void CABACWriter::mvd_coding( const Mv &rMvd, uint8_t imv )
    {
      int       horMvd = rMvd.getHor();
      int       verMvd = rMvd.getVer();
      if( imv )
      {
        CHECK( (horMvd % 4) != 0 && (verMvd % 4) != 0, "IMV: MVD is not a multiple of 4" );
        horMvd >>= 2;
        verMvd >>= 2;
        if( imv == 2 )//IMV_4PEL
        {
          CHECK( (horMvd % 4) != 0 && (verMvd % 4) != 0, "IMV: MVD is not a multiple of 8" );
          horMvd >>= 2;
          verMvd >>= 2;
        }
      }
      unsigned  horAbs  = unsigned( horMvd < 0 ? -horMvd : horMvd );
      unsigned  verAbs  = unsigned( verMvd < 0 ? -verMvd : verMvd );
    
    
    #if !REMOVE_MV_ADAPT_PREC
    
      if (rMvd.highPrec)
    
        CHECK(horAbs & ((1 << VCEG_AZ07_MV_ADD_PRECISION_BIT_FOR_STORE) - 1), "mvd-x has high precision fractional part.");
        CHECK(verAbs & ((1 << VCEG_AZ07_MV_ADD_PRECISION_BIT_FOR_STORE) - 1), "mvd-y has high precision fractional part.");
    
        horAbs >>= VCEG_AZ07_MV_ADD_PRECISION_BIT_FOR_STORE;
        verAbs >>= VCEG_AZ07_MV_ADD_PRECISION_BIT_FOR_STORE;
      }
    #endif
    
      // abs_mvd_greater0_flag[ 0 | 1 ]
      m_BinEncoder.encodeBin( (horAbs > 0), Ctx::Mvd() );
      m_BinEncoder.encodeBin( (verAbs > 0), Ctx::Mvd() );
    
      // abs_mvd_greater1_flag[ 0 | 1 ]
      if( horAbs > 0 )
      {
        m_BinEncoder.encodeBin( (horAbs > 1), Ctx::Mvd(1) );
      }
      if( verAbs > 0 )
      {
        m_BinEncoder.encodeBin( (verAbs > 1), Ctx::Mvd(1) );
      }
    
      // abs_mvd_minus2[ 0 | 1 ] and mvd_sign_flag[ 0 | 1 ]
      if( horAbs > 0 )
      {
        if( horAbs > 1 )
        {
          exp_golomb_eqprob( horAbs - 2, 1 );
        }
        m_BinEncoder.encodeBinEP( (horMvd < 0) );
      }
      if( verAbs > 0 )
      {
        if( verAbs > 1 )
        {
          exp_golomb_eqprob( verAbs - 2, 1 );
        }
        m_BinEncoder.encodeBinEP( (verMvd < 0) );
      }
    }
    
    
    
    
    //================================================================================
    //  clause 7.3.8.10
    //--------------------------------------------------------------------------------
    //    void  transform_unit      ( tu, cuCtx, chromaCbfs )
    //    void  cu_qp_delta         ( cu )
    //    void  cu_chroma_qp_offset ( cu )
    //================================================================================
    
    void CABACWriter::transform_unit( const TransformUnit& tu, CUCtx& cuCtx, ChromaCbfs& chromaCbfs )
    {
      CodingUnit& cu        = *tu.cu;
      bool        lumaOnly  = ( cu.chromaFormat == CHROMA_400 || !tu.blocks[COMPONENT_Cb].valid() );
      bool        cbf[3]    = { TU::getCbf( tu, COMPONENT_Y ), chromaCbfs.Cb, chromaCbfs.Cr };
      bool        cbfLuma   = ( cbf[ COMPONENT_Y ] != 0 );
      bool        cbfChroma = false;
    
    
      if( cu.chromaFormat != CHROMA_400 )
      {
        if( tu.blocks[COMPONENT_Cb].valid() )
        {
          cbf   [ COMPONENT_Cb  ] = TU::getCbf( tu, COMPONENT_Cb );
          cbf   [ COMPONENT_Cr  ] = TU::getCbf( tu, COMPONENT_Cr );
        }
        cbfChroma = ( cbf[ COMPONENT_Cb ] || cbf[ COMPONENT_Cr ] );
      }
      if( cbfLuma || cbfChroma )
      {
        if( cu.cs->pps->getUseDQP() && !cuCtx.isDQPCoded )
        {
          cu_qp_delta( cu, cuCtx.qp, cu.qp );
          cuCtx.qp         = cu.qp;
          cuCtx.isDQPCoded = true;
        }
        if( cu.cs->slice->getUseChromaQpAdj() && cbfChroma && !cu.transQuantBypass && !cuCtx.isChromaQpAdjCoded )
        {
          cu_chroma_qp_offset( cu );
          cuCtx.isChromaQpAdjCoded = true;
        }
        if( cbfLuma )
        {
          residual_coding( tu, COMPONENT_Y );
        }
        if( !lumaOnly )
        {
          for( ComponentID compID = COMPONENT_Cb; compID <= COMPONENT_Cr; compID = ComponentID( compID + 1 ) )
          {
            if( TU::hasCrossCompPredInfo( tu, compID ) )
            {
              cross_comp_pred( tu, compID );
            }
            if( cbf[ compID ] )
            {
              residual_coding( tu, compID );
            }
          }
        }
      }
    }
    
    #if HM_QTBT_AS_IN_JEM_SYNTAX
    void CABACWriter::transform_unit_qtbt( const TransformUnit& tu, CUCtx& cuCtx, ChromaCbfs& chromaCbfs )
    {
      CodingUnit& cu  = *tu.cu;
      bool cbfLuma    = false;
      bool cbfChroma  = false;
    
      bool lumaOnly   = ( cu.chromaFormat == CHROMA_400 || !tu.blocks[COMPONENT_Cb].valid() );
      bool chromaOnly =                                    !tu.blocks[COMPONENT_Y ].valid();
    
      if( !lumaOnly )
      {
        bool prevCbf = false;
        for( ComponentID compID = COMPONENT_Cb; compID <= COMPONENT_Cr; compID = ComponentID( compID + 1 ) )
        {
    #if ENABLE_BMS
          cbf_comp( *tu.cs, tu.cbf[compID] != 0, tu.blocks[compID], tu.depth, prevCbf );
          prevCbf = (tu.cbf[compID] != 0);
    #else
          cbf_comp( *tu.cs, tu.cbf[compID] != 0, tu.blocks[compID], prevCbf );
          prevCbf = (tu.cbf[compID] != 0);
    #endif
          chromaCbfs.cbf( compID ) = tu.cbf[compID] != 0;
    
          if( TU::hasCrossCompPredInfo( tu, compID ) )
          {
            cross_comp_pred( tu, compID );
          }
          if( tu.cbf[compID] )
          {
            residual_coding( tu, compID );
            cbfChroma = true;
          }
        }
      }
    
      if( !chromaOnly )
      {
        if( !CU::isIntra( cu ) && !chromaCbfs.sigChroma( tu.chromaFormat ) )
        {
    #if ENABLE_BMS
          CHECK( !TU::getCbfAtDepth( tu, COMPONENT_Y, 0 ), "The luma CBF is implicitely '1', but '0' found" );
    #else
          CHECK( !TU::getCbf( tu, COMPONENT_Y ), "The luma CBF is implicitely '1', but '0' found" );
    #endif
        }
        else
        {
    #if ENABLE_BMS
          cbf_comp( *tu.cs, TU::getCbf( tu, COMPONENT_Y ), tu.Y(), tu.depth );
    #else
          cbf_comp( *tu.cs, TU::getCbf( tu, COMPONENT_Y ), tu.Y() );
    #endif
        }
    
        if( tu.cbf[0] )
        {
    
    #if HM_EMT_NSST_AS_IN_JEM
    
          emt_cu_flag( cu );
    #endif
          residual_coding( tu, COMPONENT_Y );
          cbfLuma = true;
        }
      }
    
      if( cbfLuma || cbfChroma )
      {
        if( cu.cs->pps->getUseDQP() && !cuCtx.isDQPCoded )
        {
          cu_qp_delta( cu, cuCtx.qp, cu.qp );
          cuCtx.qp         = cu.qp;
          cuCtx.isDQPCoded = true;
        }
        if( cu.cs->slice->getUseChromaQpAdj() && cbfChroma && !cu.transQuantBypass && !cuCtx.isChromaQpAdjCoded )
        {
          cu_chroma_qp_offset( cu );
          cuCtx.isChromaQpAdjCoded = true;
        }
      }
    }
    #endif
    
    void CABACWriter::cu_qp_delta( const CodingUnit& cu, int predQP, const int8_t qp )
    {
      CHECK(!( predQP != std::numeric_limits<int>::max()), "Unspecified error");
      int       DQp         = qp - predQP;
      int       qpBdOffsetY = cu.cs->sps->getQpBDOffset( CHANNEL_TYPE_LUMA );
      DQp                   = ( DQp + (MAX_QP + 1) + (MAX_QP + 1) / 2 + qpBdOffsetY + (qpBdOffsetY / 2)) % ((MAX_QP + 1) + qpBdOffsetY) - (MAX_QP + 1) / 2 - (qpBdOffsetY / 2);
      unsigned  absDQP      = unsigned( DQp < 0 ? -DQp : DQp );
      unsigned  unaryDQP    = std::min<unsigned>( absDQP, CU_DQP_TU_CMAX );
    
      unary_max_symbol( unaryDQP, Ctx::DeltaQP(), Ctx::DeltaQP(1), CU_DQP_TU_CMAX );
      if( absDQP >= CU_DQP_TU_CMAX )
      {
        exp_golomb_eqprob( absDQP - CU_DQP_TU_CMAX, CU_DQP_EG_k );
      }
      if( absDQP > 0 )
      {
        m_BinEncoder.encodeBinEP( DQp < 0 );
      }
    
      DTRACE_COND( ( isEncoding() ), g_trace_ctx, D_DQP, "x=%d, y=%d, d=%d, pred_qp=%d, DQp=%d, qp=%d\n", cu.blocks[cu.chType].lumaPos().x, cu.blocks[cu.chType].lumaPos().y, cu.qtDepth, predQP, DQp, qp );
    }
    
    
    void CABACWriter::cu_chroma_qp_offset( const CodingUnit& cu )
    {
      // cu_chroma_qp_offset_flag
      unsigned qpAdj = cu.chromaQpAdj;
      if( qpAdj == 0 )
      {
        m_BinEncoder.encodeBin( 0, Ctx::ChromaQpAdjFlag() );
      }
      else
      {
        m_BinEncoder.encodeBin( 1, Ctx::ChromaQpAdjFlag() );
        int length = cu.cs->pps->getPpsRangeExtension().getChromaQpOffsetListLen();
        if( length > 1 )
        {
          unary_max_symbol( qpAdj-1, Ctx::ChromaQpAdjIdc(), Ctx::ChromaQpAdjIdc(), length-1 );
        }
      }
    }
    
    
    
    
    
    //================================================================================
    //  clause 7.3.8.11
    //--------------------------------------------------------------------------------
    //    void        residual_coding         ( tu, compID )
    //    void        transform_skip_flag     ( tu, compID )
    //    void        explicit_rdpcm_mode     ( tu, compID )
    //    void        last_sig_coeff          ( coeffCtx )
    //    void        residual_coding_subblock( coeffCtx )
    //================================================================================
    
    void CABACWriter::residual_coding( const TransformUnit& tu, ComponentID compID )
    {
      const CodingUnit& cu = *tu.cu;
      DTRACE( g_trace_ctx, D_SYNTAX, "residual_coding() etype=%d pos=(%d,%d) size=%dx%d predMode=%d\n", tu.blocks[compID].compID, tu.blocks[compID].x, tu.blocks[compID].y, tu.blocks[compID].width, tu.blocks[compID].height, cu.predMode );
    
      // code transform skip and explicit rdpcm mode
      transform_skip_flag( tu, compID );
      explicit_rdpcm_mode( tu, compID );
    
    #if HEVC_USE_SIGN_HIDING
      // determine sign hiding
      bool signHiding  = ( cu.cs->slice->getSignDataHidingEnabledFlag() && !cu.transQuantBypass && tu.rdpcm[compID] == RDPCM_OFF );
      if(  signHiding && CU::isIntra(cu) && CU::isRDPCMEnabled(cu) && tu.transformSkip[compID] )
      {
        const ChannelType chType    = toChannelType( compID );
        const unsigned    intraMode = PU::getFinalIntraMode( *cu.cs->getPU( tu.blocks[compID].pos(), chType ), chType );
        if( intraMode == HOR_IDX || intraMode == VER_IDX )
        {
          signHiding = false;
        }
      }
    #endif
    
      // init coeff coding context
    #if HEVC_USE_SIGN_HIDING
      CoeffCodingContext  cctx    ( tu, compID, signHiding );
    #else
      CoeffCodingContext  cctx    ( tu, compID );
    #endif
      const TCoeff*       coeff   = tu.getCoeffs( compID ).buf;
      unsigned            numSig  = 0;
    
      // determine and set last coeff position and sig group flags
      int                      scanPosLast = -1;
      std::bitset<MLS_GRP_NUM> sigGroupFlags;
      for( int scanPos = 0; scanPos < cctx.maxNumCoeff(); scanPos++)
      {
        unsigned blkPos = cctx.blockPos( scanPos );
        if( coeff[blkPos] )
        {
          scanPosLast = scanPos;
          sigGroupFlags.set( scanPos >> cctx.log2CGSize() );
        }
      }
      CHECK( scanPosLast < 0, "Coefficient coding called for empty TU" );
      cctx.setScanPosLast(scanPosLast);
    
      // code last coeff position
      last_sig_coeff( cctx );
    
      // code subblocks
      const int stateTab  = ( tu.cs->slice->getDepQuantEnabledFlag() ? 32040 : 0 );
      int       state     = 0;
      bool useEmt = ( cu.cs->sps->getSpsNext().getUseIntraEMT() && cu.predMode == MODE_INTRA ) || ( cu.cs->sps->getSpsNext().getUseInterEMT() && cu.predMode != MODE_INTRA );
      useEmt = useEmt && isLuma(compID);
    
      for( int subSetId = ( cctx.scanPosLast() >> cctx.log2CGSize() ); subSetId >= 0; subSetId--)
      {
        cctx.initSubblock       ( subSetId, sigGroupFlags[subSetId] );
        residual_coding_subblock( cctx, coeff, stateTab, state );
    
        if (useEmt)
        {
          numSig += cctx.emtNumSigCoeff();
          cctx.setEmtNumSigCoeff( 0 );
        }
      }
    
    
    
    #if HM_EMT_NSST_AS_IN_JEM
    
      if( useEmt && !tu.transformSkip[compID] && compID == COMPONENT_Y && tu.cu->emtFlag )
      {
        if( CU::isIntra( *tu.cu ) )
        {
          if( numSig > g_EmtSigNumThr )