Skip to content
Snippets Groups Projects
CABACWriter.cpp 89.6 KiB
Newer Older
  • Learn to ignore specific revisions
  •     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)
        {
          CHECK(mpm_idx >= numMPMs, "use of non-MPM");
        }
        else
    
        m_BinEncoder.encodeBin( mpm_idx < numMPMs, Ctx::IPredMode[0]() );
    
        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 );
            }
    
    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 )
    {
    
      // 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)
      {
        CHECK(mpm_idx >= numMPMs, "use of non-MPM");
      }
      else
    
      m_BinEncoder.encodeBin( mpm_idx < numMPMs, Ctx::IPredMode[0]() );
    
      // mpm_idx / rem_intra_luma_pred_mode
      if( mpm_idx < numMPMs )
      {
        {
          m_BinEncoder.encodeBinEP( mpm_idx > 0 );
          if( mpm_idx )
          {
            m_BinEncoder.encodeBinEP( mpm_idx > 1 );
          }
    
    ling's avatar
    ling committed
          if (mpm_idx > 1)
          {
            m_BinEncoder.encodeBinEP(mpm_idx > 2);
          }
          if (mpm_idx > 2)
          {
            m_BinEncoder.encodeBinEP(mpm_idx > 3);
          }
          if (mpm_idx > 3)
          {
            m_BinEncoder.encodeBinEP(mpm_idx > 4);
          }
    
          for (int idx = numMPMs - 1; idx >= 0; idx--)
    
    ling's avatar
    ling committed
          xWriteTruncBinCode(ipred_mode, NUM_LUMA_MODE - NUM_MOST_PROBABLE_MODES);  // Remaining mode is truncated binary coded
    
        }
      }
    }
    
    
    void CABACWriter::intra_chroma_pred_modes( const CodingUnit& cu )
    {
      if( cu.chromaFormat == CHROMA_400 || ( CS::isDualITree( *cu.cs ) && cu.chType == CHANNEL_TYPE_LUMA ) )
      {
        return;
      }
    
      const PredictionUnit* pu = cu.firstPU;
    
      intra_chroma_pred_mode( *pu );
    }
    
    void CABACWriter::intra_chroma_lmc_mode( const PredictionUnit& pu )
    {
      const unsigned intraDir = pu.intraDir[1];
        int lmModeList[10];
        int maxSymbol = PU::getLMSymbolList( pu, lmModeList );
        int symbol    = -1;
        for ( int k = 0; k < LM_SYMBOL_NUM; k++ )
        {
          if ( lmModeList[k] == intraDir || ( lmModeList[k] == -1 && intraDir < LM_CHROMA_IDX ) )
          {
            symbol = k;
            break;
          }
        }
        CHECK( symbol < 0, "invalid symbol found" );
    
        unary_max_symbol( symbol, Ctx::IPredMode[1]( 2 ), Ctx::IPredMode[1]( 3 ), maxSymbol - 1 );
    }
    
    
    void CABACWriter::intra_chroma_pred_mode( const PredictionUnit& pu )
    {
      const unsigned intraDir = pu.intraDir[1];
      {
        if( intraDir == DM_CHROMA_IDX )
        {
          m_BinEncoder.encodeBin( 0, Ctx::IPredMode[1]( 1 ) );
          return;
        }
        m_BinEncoder.encodeBin( 1, Ctx::IPredMode[1]( 1 ) );
      }
    
      // LM chroma mode
      if( pu.cs->sps->getSpsNext().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 )
    {
      if( CU::isInter( cu ) )
      {
        PredictionUnit& pu = *cu.firstPU;
    
    Karsten Suehring's avatar
    Karsten Suehring committed
        if( !pu.mergeFlag )
    
        {
          rqt_root_cbf( cu );
        }
    
        if( !cu.rootCbf )
        {
          return;
        }
      }
    
    
      ChromaCbfs chromaCbfs;
      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::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 )
      {
    
        subblock_merge_flag( *pu.cu );
    
        if ( pu.mhIntraFlag )
    
        if (pu.mmvdMergeFlag)
        {
          mmvd_merge_idx(pu);
        }
        else
    
    #if JVET_M0246_AFFINE_AMVR
        int8_t affineMvdShift = pu.cu->imv ? ( pu.cu->imv == 1 ? -1 : 1 ) : 0;
    #endif
    
    #if JVET_M0444_SMVD
        smvd_mode( pu );
    #endif
    
        if( pu.interDir != 2 /* PRED_L1 */ )
        {
          ref_idx     ( pu, REF_PIC_LIST_0 );
          if ( pu.cu->affine )
          {
    
    #if JVET_M0246_AFFINE_AMVR
            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.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 */ )
        {
    
    #if JVET_M0444_SMVD
          if ( pu.cu->smvdMode != 1 )
          {
    #endif
    
          ref_idx     ( pu, REF_PIC_LIST_1 );
          if( !pu.cs->slice->getMvdL1ZeroFlag() || pu.interDir != 3 /* PRED_BI */ )
          {
            if ( pu.cu->affine )
            {
    
    #if JVET_M0246_AFFINE_AMVR
              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 );
              }
    #else
    
              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);
              }
    
    #if JVET_M0444_SMVD
          }
    #endif
    
    #if JVET_M0444_SMVD
    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 );
    }
    #endif
    
    
    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->getSpsNext().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->getSpsNext().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->getSpsNext().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 );
    
      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);
      }
    
    }
    
    void CABACWriter::imv_mode( const CodingUnit& cu )
    {
      const SPSNext& spsNext = cu.cs->sps->getSpsNext();
    
      if( !spsNext.getUseIMV() )
      {
        return;
      }
    
    #if JVET_M0246_AFFINE_AMVR
      if ( cu.affine )
      {
        return;
      }
    #endif
    
    
      bool bNonZeroMvd = CU::hasSubCUNonZeroMVd( cu );
      if( !bNonZeroMvd )
      {
        return;
      }
    
      unsigned ctxId = DeriveCtx::CtxIMVFlag( cu );
    
    Yu Han's avatar
    Yu Han committed
      if (!(cu.firstPU->interDir == 1 && cu.cs->slice->getRefPic(REF_PIC_LIST_0, cu.firstPU->refIdx[REF_PIC_LIST_0])->getPOC() == cu.cs->slice->getPOC())) // the first bin of IMV flag does need to be signaled in IBC block
    
        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 );
    }
    
    
    #if JVET_M0246_AFFINE_AMVR
    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 );
    }
    #endif
    
    
    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
          {
    
            bool useExtCtx = pu.cs->sps->getSBTMVPEnabledFlag();
    
            m_BinEncoder.encodeBin( 1, Ctx::AffMergeIdx() );
            for ( unsigned idx = 1; idx < numCandminus1; idx++ )
            {
    
              if ( useExtCtx )
              {
                m_BinEncoder.encodeBin( pu.mergeIdx == idx ? 0 : 1, Ctx::AffMergeIdx( std::min<int>( idx, NUM_MERGE_IDX_EXT_CTX - 1 ) ) );
              }
              else
              {
    
                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
      {
    
    #if JVET_M0883_TRIANGLE_SIGNALING
          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);
    #else
    
          if( pu.mergeIdx < 2 )
          {
            m_BinEncoder.encodeBin( 0, Ctx::TriangleIdx() );
            m_BinEncoder.encodeBinEP( pu.mergeIdx );
          }
          else
          {
            m_BinEncoder.encodeBin( 1, Ctx::TriangleIdx() );
            exp_golomb_eqprob( pu.mergeIdx - 2, 2 );
          }
    
          DTRACE( g_trace_ctx, D_SYNTAX, "merge_idx() triangle_idx=%d\n", pu.mergeIdx );
    
      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 JVET_M0444_SMVD
      if ( pu.cu->smvdMode )
      {
        CHECK( pu.refIdx[eRefList] != pu.cs->slice->getSymRefIdx( eRefList ), "Invalid reference index!\n" );
        return;
      }
    #endif
    
    
      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 );
        }
        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->getSpsNext().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()->getSpsNext().getUseTriangle() || !cu.cs->slice->isInterB() || cu.lwidth() * cu.lheight() < TRIANGLE_MIN_SIZE || cu.affine )
      {
        return;
      }
    
    
    #if JVET_M0118_M0185_TRIANGLE_FLAG_FIX
      if ( cu.firstPU->mmvdMergeFlag || cu.mmvdSkip )
      {
        return;
      }
    
      if ( cu.firstPU->mhIntraFlag )
      {
        return;
      }
    #endif
    
    
      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 UnitArea&       area          = partitioner.currArea();
      const TransformUnit&  tu            = *cs.getTU( area.blocks[partitioner.chType].pos(), partitioner.chType );
      const CodingUnit&     cu            = *tu.cu;
      const unsigned        trDepth       = partitioner.currTrDepth;
      const bool            split         = ( tu.depth > trDepth );
    
      // split_transform_flag
    
    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" );
    
    Karsten Suehring's avatar
    Karsten Suehring committed
      else
      CHECK( split, "transform split not allowed with QTBT" );
    
    
      // cbf_cb & cbf_cr
      if( area.chromaFormat != CHROMA_400 && area.blocks[COMPONENT_Cb].valid() && ( !CS::isDualITree( cs ) || partitioner.chType == CHANNEL_TYPE_CHROMA ) )
      {
        {
          if( trDepth == 0 || chromaCbfs.Cb )
          {
            chromaCbfs.Cb = TU::getCbfAtDepth( tu, COMPONENT_Cb, trDepth );
            cbf_comp( cs, chromaCbfs.Cb, area.blocks[COMPONENT_Cb], trDepth );
          }
          else
          {
            CHECK( TU::getCbfAtDepth( tu, COMPONENT_Cb, trDepth ) != chromaCbfs.Cb, "incorrect Cb cbf" );
          }
    
          if( trDepth == 0 || chromaCbfs.Cr )
          {
            chromaCbfs.Cr = TU::getCbfAtDepth( tu, COMPONENT_Cr,   trDepth );
            cbf_comp( cs, chromaCbfs.Cr, area.blocks[COMPONENT_Cr], trDepth, chromaCbfs.Cb );
          }
          else
          {
            CHECK( TU::getCbfAtDepth( tu, COMPONENT_Cr, trDepth ) != 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 );
        }
    
    Tung Nguyen's avatar
    Tung Nguyen committed
    #if !JVET_M0464_UNI_MTS
    
    Tung Nguyen's avatar
    Tung Nguyen committed
    #endif