Skip to content
Snippets Groups Projects
CABACWriter.cpp 84.2 KiB
Newer Older
  • Learn to ignore specific revisions
  •   }
    }
    
    
    void CABACWriter::intra_luma_pred_mode( const PredictionUnit& pu )
    {
    
      // prev_intra_luma_pred_flag
    
      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 )
      {
        {
    
    #if JVET_N0185_UNIFIED_MPM
          unsigned ctx = (pu.cu->ispMode == NOT_INTRA_SUBPARTITIONS ? 1 : 0);
          if (pu.multiRefIdx == 0)
            m_BinEncoder.encodeBin( mpm_idx > 0, Ctx::HarmonizedMPMIdx(ctx) );
    #else
    
    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( 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( cu.ispMode && isLuma( partitioner.chType ) )
      {
        TUIntraSubPartitioner subTuPartitioner( partitioner );
        transform_tree( *cu.cs, subTuPartitioner, cuCtx, chromaCbfs, CU::getISPType( cu, getFirstComponentOfChannel( partitioner.chType ) ), 0 );
      }
      else
      {
        transform_tree( *cu.cs, partitioner, cuCtx, chromaCbfs );
      }
    
    }
    
    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;
    #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 )
      {
    
    Yu Han's avatar
    Yu Han committed
        if (CU::isIBC(*pu.cu))
        {
          merge_idx(pu);
          return;
        }
    
        subblock_merge_flag( *pu.cu );
    
        if ( pu.mhIntraFlag )
    
        if (pu.mmvdMergeFlag)
        {
          mmvd_merge_idx(pu);
        }
        else
    
    Yu Han's avatar
    Yu Han committed
      else if (CU::isIBC(*pu.cu))
      {
        ref_idx(pu, REF_PIC_LIST_0);
        mvd_coding(pu.mvd[REF_PIC_LIST_0], pu.cu->imv);
        mvp_flag(pu, REF_PIC_LIST_0);
      }
    
        int8_t affineMvdShift = pu.cu->imv ? ( pu.cu->imv == 1 ? -1 : 1 ) : 0;
    
        smvd_mode( pu );
    
        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], affineMvdShift );
            mvd_coding( pu.mvdAffi[REF_PIC_LIST_0][1], affineMvdShift );
            if ( pu.cu->affineType == AFFINEMODEL_6PARAM )
            {
              mvd_coding( pu.mvdAffi[REF_PIC_LIST_0][2], affineMvdShift );
            }
    
          }
          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 */ )
        {
    
          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 )
            {
    
              mvd_coding( pu.mvdAffi[REF_PIC_LIST_1][0], affineMvdShift );
              mvd_coding( pu.mvdAffi[REF_PIC_LIST_1][1], affineMvdShift );
              if ( pu.cu->affineType == AFFINEMODEL_6PARAM )
              {
                mvd_coding( pu.mvdAffi[REF_PIC_LIST_1][2], affineMvdShift );
              }
    
    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 );
        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;
      }
    
    Frank Bossen's avatar
    Frank Bossen committed
    #if !JVET_MMVD_OFF_MACRO
    
      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);
      }
    
    Frank Bossen's avatar
    Frank Bossen committed
    #endif
    
      const SPS *sps = cu.cs->sps;
    
      if( !sps->getAMVREnabledFlag() )
    
    
      bool bNonZeroMvd = CU::hasSubCUNonZeroMVd( cu );
      if( !bNonZeroMvd )
      {
        return;
      }
    
      unsigned ctxId = DeriveCtx::CtxIMVFlag( cu );
    
    Yu Han's avatar
    Yu Han committed
      if (CU::isIBC(cu) == false)
    
        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( sps->getAMVREnabledFlag() && 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::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( 4 ) );
      DTRACE( g_trace_ctx, D_SYNTAX, "affine_amvr_mode() value=%d ctx=%d\n", ( cu.imv > 0 ), 4 );
    
      if( cu.imv > 0 )
      {
        m_BinEncoder.encodeBin( ( cu.imv > 1 ), Ctx::ImvFlag( 5 ) );
        DTRACE( g_trace_ctx, D_SYNTAX, "affine_amvr_mode() value=%d ctx=%d\n", ( cu.imv > 1 ), 5 );
      }
      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(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;
                }
              }
            }
          };
          m_BinEncoder.encodeBinEP(splitDir);
          encodeOneIdx(candIdx0, TRIANGLE_MAX_NUM_UNI_CANDS - 1);
          encodeOneIdx(candIdx1, TRIANGLE_MAX_NUM_UNI_CANDS - 2);
    
      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
        {
          m_BinEncoder.encodeBin( 1, Ctx::MergeIdx() );
          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, "merge_idx() merge_idx=%d\n", pu.mergeIdx );
    
    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);
    }
    
    void CABACWriter::inter_pred_idc( const PredictionUnit& pu )
    {
      if( !pu.cs->slice->isInterB() )
      {
        return;
      }
    
    Karsten Suehring's avatar
    Karsten Suehring committed
      if( !(PU::isBipredRestriction(pu)) )
    
      {
        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 )
    {
    
      if ( pu.cu->smvdMode )
      {
        CHECK( pu.refIdx[eRefList] != pu.cs->slice->getSymRefIdx( eRefList ), "Invalid reference index!\n" );
        return;
      }
    
    
      int numRef  = pu.cs->slice->getNumRefIdx(eRefList);
    
    Yu Han's avatar
    Yu Han committed
      if (eRefList == REF_PIC_LIST_0 && pu.cs->sps->getIBCFlag())
    
    Yu Han's avatar
    Yu Han committed
      {
        if (CU::isIBC(*pu.cu))
          return;
      }
    
    
      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 );
        }
        else
        {
          m_BinEncoder.encodeBinEP( 0 );
          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] );
    }
    
    
    void CABACWriter::MHIntra_flag(const PredictionUnit& pu)
    {
    
      if (!pu.cs->sps->getUseMHIntra())
    
        CHECK(pu.mhIntraFlag == true, "invalid MHIntra SPS");
    
        CHECK(pu.mhIntraFlag == true, "invalid MHIntra and skip");
    
        CHECK(pu.mhIntraFlag == true, "invalid MHIntra and mmvd");
    
      if (pu.cu->affine)
      {
        CHECK(pu.mhIntraFlag == true, "invalid MHIntra and affine");
        return;
      }
    
      if (pu.cu->lwidth() * pu.cu->lheight() < 64 || pu.cu->lwidth() >= MAX_CU_SIZE || pu.cu->lheight() >= MAX_CU_SIZE)
      {
    
        CHECK(pu.mhIntraFlag == true, "invalid MHIntra and blk");
    
      m_BinEncoder.encodeBin(pu.mhIntraFlag, Ctx::MHIntraFlag());
    
      DTRACE(g_trace_ctx, D_SYNTAX, "MHIntra_flag() MHIntra=%d pos=(%d,%d) size=%dx%d\n", pu.mhIntraFlag ? 1 : 0, pu.lumaPos().x, pu.lumaPos().y, pu.lumaSize().width, pu.lumaSize().height);
    
    }
    
    void CABACWriter::MHIntra_luma_pred_modes(const CodingUnit& cu)
    {
      if (!cu.Y().valid())
      {
        return;
      }
    
    
      int      numBlocks = CU::getNumPUs(cu);
      unsigned mpm_idxs[4];
      unsigned pred_modes[4];
    
      const PredictionUnit* pu = cu.firstPU;
    
      unsigned mpm_pred[numMPMs];
      for (int k = 0; k < numBlocks; k++)
      {
        unsigned&  mpm_idx = mpm_idxs[k];
        unsigned&  pred_mode = pred_modes[k];
    
        PU::getMHIntraMPMs(*pu, mpm_pred);
    
        pred_mode = pu->intraDir[0];
    
        mpm_idx = numMPMs;
    
    
        for (int idx = 0; idx < numMPMs; idx++)
    
        {
          if (pred_mode == mpm_pred[idx])
          {
            mpm_idx = idx;
            break;
          }
        }
        if (PU::getNarrowShape(pu->lwidth(), pu->lheight()) == 0)
        {
          m_BinEncoder.encodeBin(mpm_idx < numMPMs, Ctx::MHIntraPredMode());
        }
        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)
        {
          m_BinEncoder.encodeBinEP(mpm_idx > 0);
          if (mpm_idx)
          {
            m_BinEncoder.encodeBinEP(mpm_idx > 1);
          }
        }
        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::triangle_mode( const CodingUnit& cu )
    {
    
      if( !cu.cs->slice->getSPS()->getUseTriangle() || !cu.cs->slice->isInterB() || cu.lwidth() * cu.lheight() < TRIANGLE_MIN_SIZE || cu.affine )
    
      if ( cu.firstPU->mmvdMergeFlag || cu.mmvdSkip )
      {
        return;
      }
    
      if ( cu.firstPU->mhIntraFlag )
      {
        return;
      }
    
    
      unsigned flag_idx     = DeriveCtx::CtxTriangleFlag( cu );
    
      m_BinEncoder.encodeBin( cu.triangle, Ctx::TriangleFlag(flag_idx) );
    
      DTRACE( g_trace_ctx, D_SYNTAX, "triangle_mode() triangle_mode=%d pos=(%d,%d) size: %dx%d\n", cu.triangle, cu.Y().x, cu.Y().y, cu.lumaSize().width, cu.lumaSize().height );
    }
    
    
    //================================================================================
    //  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 CodingStructure *cs = tu.cs;
      const ChannelType chType = tu.chType;
    
      ComponentID compStr = (CS::isDualITree(*cs) && !isLuma(chType)) ? COMPONENT_Cb: COMPONENT_Y;
      ComponentID compEnd = (CS::isDualITree(*cs) && isLuma(chType)) ? COMPONENT_Y : COMPONENT_Cr;
      for( ComponentID compID = compStr; compID <= compEnd; 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 PartSplit ispType, const int subTuIdx )
    
      ChromaCbfs chromaCbfsLastDepth;
      chromaCbfsLastDepth.Cb              = chromaCbfs.Cb;
      chromaCbfsLastDepth.Cr              = chromaCbfs.Cr;
    
      const UnitArea&       area          = partitioner.currArea();
    
            int             subTuCounter  = subTuIdx;
      const TransformUnit&  tu            = *cs.getTU( area.blocks[partitioner.chType].pos(), partitioner.chType, subTuIdx );
    
      const CodingUnit&     cu            = *tu.cu;
      const unsigned        trDepth       = partitioner.currTrDepth;
      const bool            split         = ( tu.depth > trDepth );
    
      const bool            chromaCbfISP  = area.blocks[COMPONENT_Cb].valid() && cu.ispMode && !split;
    
    Karsten Suehring's avatar
    Karsten Suehring committed
      if( partitioner.canSplit( TU_MAX_TR_SPLIT, cs ) )
    
    Karsten Suehring's avatar
    Karsten Suehring committed
        CHECK( !split, "transform split implied" );
    
      else if( cu.sbtInfo && partitioner.canSplit( PartSplit( cu.getSbtTuSplit() ), cs ) )
      {
        CHECK( !split, "transform split implied - sbt" );
      }
    
    Karsten Suehring's avatar
    Karsten Suehring committed
      else
    
      CHECK( split && !cu.ispMode, "transform split not allowed with QTBT" );
    
    
      if( area.chromaFormat != CHROMA_400 && area.blocks[COMPONENT_Cb].valid() && ( !CS::isDualITree( cs ) || partitioner.chType == CHANNEL_TYPE_CHROMA ) && ( !cu.ispMode || chromaCbfISP ) )
    
          unsigned cbfDepth = chromaCbfISP ? trDepth - 1 : trDepth;
          if( trDepth == 0 || chromaCbfs.Cb || chromaCbfISP )
          {
            chromaCbfs.Cb = TU::getCbfAtDepth( tu, COMPONENT_Cb, trDepth );
    
            if( !( cu.sbtInfo && trDepth == 1 ) )
    
            cbf_comp( cs, chromaCbfs.Cb, area.blocks[COMPONENT_Cb], cbfDepth );
          }
          else
          {
            CHECK( TU::getCbfAtDepth( tu, COMPONENT_Cb, cbfDepth ) != chromaCbfs.Cb, "incorrect Cb cbf" );
          }
    
          if( trDepth == 0 || chromaCbfs.Cr || chromaCbfISP )
          {
            chromaCbfs.Cr = TU::getCbfAtDepth( tu, COMPONENT_Cr, trDepth );
    
            if( !( cu.sbtInfo && trDepth == 1 ) )
    
            cbf_comp( cs, chromaCbfs.Cr, area.blocks[COMPONENT_Cr], cbfDepth, chromaCbfs.Cb );
          }
          else
          {
            CHECK( TU::getCbfAtDepth( tu, COMPONENT_Cr, cbfDepth ) != chromaCbfs.Cr, "incorrect Cr cbf" );
          }
    
        }
      }
      else if( CS::isDualITree( cs ) )
      {
        chromaCbfs = ChromaCbfs( false );
      }
    
      if( split )
      {
        if( area.chromaFormat != CHROMA_400 )
        {
          chromaCbfs.Cb        = TU::getCbfAtDepth( tu, COMPONENT_Cb,  trDepth );
          chromaCbfs.Cr        = TU::getCbfAtDepth( tu, COMPONENT_Cr,  trDepth );
        }
    
        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 if( cu.ispMode )
        {
          partitioner.splitCurrArea( ispType, cs );
        }
    
        else if( cu.sbtInfo && partitioner.canSplit( PartSplit( cu.getSbtTuSplit() ), cs ) )
        {
          partitioner.splitCurrArea( PartSplit( cu.getSbtTuSplit() ), cs );
        }
    
        else
          THROW( "Implicit TU split not available" );
    
        do
        {
          ChromaCbfs subChromaCbfs = chromaCbfs;
    
          transform_tree( cs, partitioner, cuCtx, subChromaCbfs, ispType, subTuCounter );
          subTuCounter += subTuCounter != -1 ? 1 : 0;
    
        } while( partitioner.nextPart( cs ) );
    
        partitioner.exitCurrSplit();
      }
      else
      {
        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 );
    
        if( !isChroma( partitioner.chType ) )