Skip to content
Snippets Groups Projects
CABACWriter.cpp 114 KiB
Newer Older
  • Learn to ignore specific revisions
  •   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));
    
    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) );
    
    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_O0472_LFNST_SIGNALLING_LAST_SCAN_POS
      cuCtx.lastScanPos[COMPONENT_Y ] = -1;
      cuCtx.lastScanPos[COMPONENT_Cb] = -1;
      cuCtx.lastScanPos[COMPONENT_Cr] = -1;
    #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 );
        }
      }
    }
    
    
    
    
    
    //================================================================================
    //  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)
    
    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 JVET_O0220_METHOD1_SUBBLK_FLAG_PARSING
      if ( !cu.cs->slice->isIntra() && (cu.slice->getMaxNumAffineMergeCand() > 0) && cu.lumaSize().width >= 8 && cu.lumaSize().height >= 8 )
    #else
    
      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;
      }
    
    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;
                }
              }
            }
          };
          m_BinEncoder.encodeBinEP(splitDir);
    
          const int maxNumTriangleCand = pu.cs->slice->getMaxNumTriangleCand();
          CHECK(maxNumTriangleCand < 2, "Incorrect max number of triangle candidates");
          CHECK(candIdx0 >= maxNumTriangleCand, "Incorrect candIdx0");
          CHECK(candIdx1 >= maxNumTriangleCand, "Incorrect candIdx1");
          encodeOneIdx(candIdx0, maxNumTriangleCand - 1);
          encodeOneIdx(candIdx1, maxNumTriangleCand - 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 numCand = int(pu.cs->slice->getMaxNumMergeCand());
      int numCandminus1_base = (numCand > 1) ? MMVD_BASE_MV_NUM - 1 : 0;
    
      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);
    
    //================================================================================
    //  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;