Skip to content
Snippets Groups Projects
CABACWriter.cpp 139 KiB
Newer Older
  • Learn to ignore specific revisions
  • Yung-Hsuan Chao (Jessie)'s avatar
    Yung-Hsuan Chao (Jessie) committed
        g_paletteRunLeftLut[0] = (paletteIdx < PLT_RUN_MSB_IDX_CTX_T1 ? 0 : (paletteIdx < PLT_RUN_MSB_IDX_CTX_T2 ? 1 : 2));
    
      xWriteTruncMsbP1RefinementBits(run, runtype, maxRun, PLT_RUN_MSB_IDX_CABAC_BYPASS_THRE);
    
    uint32_t CABACWriter::xWriteTruncMsbP1(uint32_t symbol, PLTRunMode runtype, uint32_t uiMax, uint32_t uiCtxT)
    
    Yung-Hsuan Chao (Jessie)'s avatar
    Yung-Hsuan Chao (Jessie) committed
      ctxLut = (runtype == PLT_RUN_INDEX) ? g_paletteRunLeftLut : g_paletteRunTopLut;
    
      uint32_t msbP1;
      for (msbP1 = 0; symbol > 0; msbP1++)
    
        symbol >>= 1;
        if (msbP1 > uiCtxT)
    
          m_BinEncoder.encodeBin(1, (msbP1 <= uiCtxT)
            ? ((runtype == PLT_RUN_INDEX) ? Ctx::IdxRunModel(ctxLut[msbP1]) : Ctx::CopyRunModel(ctxLut[msbP1]))
            : ((runtype == PLT_RUN_INDEX) ? Ctx::IdxRunModel(ctxLut[uiCtxT]) : Ctx::CopyRunModel(ctxLut[uiCtxT])));
    
      assert(msbP1 <= uiMax);
      if (msbP1 < uiMax)
    
        if (msbP1 > uiCtxT)
    
          m_BinEncoder.encodeBin(0, msbP1 <= uiCtxT
            ? ((runtype == PLT_RUN_INDEX) ? Ctx::IdxRunModel(ctxLut[msbP1]) : Ctx::CopyRunModel(ctxLut[msbP1]))
            : ((runtype == PLT_RUN_INDEX) ? Ctx::IdxRunModel(ctxLut[uiCtxT]) : Ctx::CopyRunModel(ctxLut[uiCtxT])));
    
        //m_pcBinIf->encodeBin(0, msbP1 <= uiCtxT? pcSCModel[ctxLut[msbP1]] : pcSCModel[ctxLut[uiCtxT]]);
    
    void CABACWriter::xWriteTruncMsbP1RefinementBits(uint32_t symbol, PLTRunMode runtype, uint32_t maxVal, uint32_t uiCtxT)
    
      uint32_t msbP1 = xWriteTruncMsbP1(symbol, runtype, floorLog2(maxVal) + 1, uiCtxT);
    
        if (msbP1 < numBins)
    
          uint32_t bits = msbP1 - 1;
          m_BinEncoder.encodeBinsEP(symbol & ((1 << bits) - 1), bits);
    
          uint32_t curValue = 1 << (numBins - 1);
          xWriteTruncBinCode(symbol - curValue, maxVal + 1 - curValue);
    
    
    //================================================================================
    //  clause 7.3.8.6
    //--------------------------------------------------------------------------------
    //    void  prediction_unit ( pu );
    //    void  merge_flag      ( pu );
    //    void  merge_idx       ( pu );
    //    void  inter_pred_idc  ( pu );
    //    void  ref_idx         ( pu, refList );
    //    void  mvp_flag        ( pu, refList );
    //================================================================================
    
    void CABACWriter::prediction_unit( const PredictionUnit& pu )
    {
    
    #if JVET_O0050_LOCAL_DUAL_TREE
      CHECK( pu.cu->treeType == TREE_C, "cannot be chroma CU" );
    #endif
    
    #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 )
      {
    
    #if JVET_O0249_MERGE_SYNTAX
        merge_data(pu);
    #else
    
    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
    
    Xiang Li's avatar
    Xiang Li committed
    #if JVET_O0455_IBC_MAX_MERGE_NUM
        if ( pu.cu->slice->getMaxNumIBCMergeCand() == 1 )
    #else
    
        if ( pu.cu->slice->getMaxNumMergeCand() == 1 )
    
    Xiang Li's avatar
    Xiang Li committed
    #endif
    
        {
          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 )
    {
    
    #if !JVET_O0249_MERGE_SYNTAX
    
    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 );
    
    #if !JVET_O0249_MERGE_SYNTAX
    
    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);
          }
    
    #if JVET_O0249_MERGE_SYNTAX
    void CABACWriter::merge_data(const PredictionUnit& pu)
    {
      if (CU::isIBC(*pu.cu))
      {
        merge_idx(pu);
        return;
      }
      subblock_merge_flag(*pu.cu);
      if (pu.cu->affine)
      {
        merge_idx(pu);
        return;
      }
    
      const bool triangleAvailable = pu.cu->cs->slice->getSPS()->getUseTriangle() && pu.cu->cs->slice->isInterB() && pu.cu->cs->slice->getMaxNumTriangleCand() > 1;
    
      const bool ciipAvailable = pu.cs->sps->getUseMHIntra() && !pu.cu->skip && pu.cu->lwidth() < MAX_CU_SIZE && pu.cu->lheight() < MAX_CU_SIZE;
      if (pu.cu->lwidth() * pu.cu->lheight() >= 64
        && (triangleAvailable || ciipAvailable))
      {
        m_BinEncoder.encodeBin(pu.regularMergeFlag, Ctx::RegularMergeFlag(pu.cu->skip ? 0 : 1));
      }
      if (pu.regularMergeFlag)
      {
        if (pu.cs->sps->getUseMMVD())
        {
          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);
        }
        if (pu.mmvdMergeFlag || pu.cu->mmvdSkip)
        {
          mmvd_merge_idx(pu);
        }
        else
        {
          merge_idx(pu);
        }
      }
      else
      {
        if (triangleAvailable && ciipAvailable)
        {
          MHIntra_flag(pu);
        }
        merge_idx(pu);
      }
    
      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 )
    
    #if JVET_O0057_ALTHPELIF
        if (!CU::isIBC(cu))
        {
          m_BinEncoder.encodeBin(cu.imv < IMV_HPEL, Ctx::ImvFlag(4));
          DTRACE(g_trace_ctx, D_SYNTAX, "imv_mode() value=%d ctx=%d\n", cu.imv < 3, 4);
        }
        if (cu.imv < IMV_HPEL)
        {
    #endif
    
        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 );
    
    #if JVET_O0057_ALTHPELIF
        }
    #endif
    
      }
    
      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);
    
    Yan Zhang's avatar
    Yan Zhang committed
    #if JVET_O0455_IBC_MAX_MERGE_NUM
        int numCandminus1;
        if (pu.cu->predMode == MODE_IBC)
          numCandminus1 = int(pu.cs->slice->getMaxNumIBCMergeCand()) - 1;
        else
          numCandminus1 = int(pu.cs->slice->getMaxNumMergeCand()) - 1;
    #else
        int numCandminus1 = int(pu.cs->slice->getMaxNumMergeCand()) - 1;
    #endif
    
      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");
    
    #if !JVET_O0249_MERGE_SYNTAX
    
        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;
    
    #if !JVET_O0050_LOCAL_DUAL_TREE
    
      const CodingStructure *cs = tu.cs;
    
      const ChannelType chType = tu.chType;
    
    
    #if JVET_O0050_LOCAL_DUAL_TREE
      ComponentID compStr = (tu.cu->isSepTree() && !isLuma( chType )) ? COMPONENT_Cb : COMPONENT_Y;
      ComponentID compEnd = (tu.cu->isSepTree() && isLuma( chType )) ? COMPONENT_Y : COMPONENT_Cr;
    #else
    
      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 )
    //================================================================================
    
    #if JVET_O0596_CBF_SIG_ALIGN_TO_SPEC
    void CABACWriter::transform_tree( const CodingStructure& cs, Partitioner& partitioner, CUCtx& cuCtx,                         const PartSplit ispType, const int subTuIdx )
    #else
    
    void CABACWriter::transform_tree( const CodingStructure& cs, Partitioner& partitioner, CUCtx& cuCtx, ChromaCbfs& chromaCbfs, const PartSplit ispType, const int subTuIdx )
    
    #if JVET_O0596_CBF_SIG_ALIGN_TO_SPEC
      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);
    #else
    
      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;
    
      bool max_tu_split = false;
    
    Karsten Suehring's avatar
    Karsten Suehring committed
      if( partitioner.canSplit( TU_MAX_TR_SPLIT, cs ) )
    
    #if !JVET_O0596_CBF_SIG_ALIGN_TO_SPEC
    
    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 !JVET_O0596_CBF_SIG_ALIGN_TO_SPEC
    
    #if JVET_O0050_LOCAL_DUAL_TREE
      if( area.chromaFormat != CHROMA_400 && area.blocks[COMPONENT_Cb].valid() && ( !cu.isSepTree() || partitioner.chType == CHANNEL_TYPE_CHROMA ) && ( !cu.ispMode || chromaCbfISP ) )
    #else
    
      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 (!max_tu_split || chromaCbfISP)
    
          {
            chromaCbfs.Cb = TU::getCbfAtDepth( tu, COMPONENT_Cb, trDepth );
    
            if( !( cu.sbtInfo && trDepth == 1 ) )
    
            cbf_comp( cs, chromaCbfs.Cb, area.blocks[COMPONENT_Cb], cbfDepth );
          }
    
    
          if (!max_tu_split || 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 );
          }
    
    #if JVET_O0050_LOCAL_DUAL_TREE
      else if( cu.isSepTree() )
    #else
    
    #if !JVET_O0596_CBF_SIG_ALIGN_TO_SPEC
    
        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 );
        }
    
    #if JVET_O0596_CBF_SIG_ALIGN_TO_SPEC
          transform_tree( cs, partitioner, cuCtx,                ispType, subTuCounter );
    #else
    
          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 JVET_O0596_CBF_SIG_ALIGN_TO_SPEC
        transform_unit( tu, cuCtx, partitioner, subTuCounter);
    #else
    
        if( !isChroma( partitioner.chType ) )
        {
          if( !CU::isIntra( cu ) && trDepth == 0 && !chromaCbfs.sigChroma( area.chromaFormat ) )
          {
            CHECK( !TU::getCbfAtDepth( tu, COMPONENT_Y, trDepth ), "Luma cbf must be true for inter units with no chroma coeffs" );
          }
    
          else if( cu.sbtInfo && tu.noResidual )
          {
            CHECK( TU::getCbfAtDepth( tu, COMPONENT_Y, trDepth ), "Luma cbf must be false for inter sbt no-residual tu" );
          }
          else if( cu.sbtInfo && !chromaCbfsLastDepth.sigChroma( area.chromaFormat ) )
          {
            assert( !tu.noResidual );
            CHECK( !TU::getCbfAtDepth( tu, COMPONENT_Y, trDepth ), "Luma cbf must be true for inter sbt residual tu" );
          }
    
            bool previousCbf       = false;
            bool rootCbfSoFar      = false;
            bool lastCbfIsInferred = false;
            if( cu.ispMode )
            {
              uint32_t nTus = cu.ispMode == HOR_INTRA_SUBPARTITIONS ? cu.lheight() >> g_aucLog2[tu.lheight()] : cu.lwidth() >> g_aucLog2[tu.lwidth()];
              if( subTuCounter == nTus - 1 )
              {
                TransformUnit* tuPointer = cu.firstTU;
                for( int tuIdx = 0; tuIdx < subTuCounter; tuIdx++ )
                {
                  rootCbfSoFar |= TU::getCbfAtDepth( *tuPointer, COMPONENT_Y, trDepth );
                  tuPointer = tuPointer->next;
                }
                if( !rootCbfSoFar )
                {
                  lastCbfIsInferred = true;
                }
              }
              if( !lastCbfIsInferred )
              {
                previousCbf = TU::getPrevTuCbfAtDepth( tu, COMPONENT_Y, partitioner.currTrDepth );
              }
            }
            if( !lastCbfIsInferred )
            {
              cbf_comp( cs, TU::getCbfAtDepth( tu, COMPONENT_Y, trDepth ), tu.Y(), trDepth, previousCbf, cu.ispMode );
            }
    
    void CABACWriter::cbf_comp( const CodingStructure& cs, bool cbf, const CompArea& area, unsigned depth, const bool prevCbf, const bool useISP )
    
    #if JVET_O0193_REMOVE_TR_DEPTH_IN_CBF_CTX
    
      const unsigned  ctxId   = DeriveCtx::CtxQtCbf( area.compID, prevCbf, useISP && isLuma(area.compID) );
    
      const unsigned  ctxId   = DeriveCtx::CtxQtCbf( area.compID, depth, prevCbf, useISP && isLuma(area.compID) );
    
      const CtxSet&   ctxSet  = Ctx::QtCbf[ area.compID ];
    
      if( area.compID == COMPONENT_Y && cs.getCU( area.pos(), ChannelType( area.compID ) )->bdpcmMode )
      {
    
    #if JVET_O0193_REMOVE_TR_DEPTH_IN_CBF_CTX
        m_BinEncoder.encodeBin( cbf, ctxSet( 1 ) );
    #else
    
        m_BinEncoder.encodeBin( cbf, ctxSet( 4 ) );
    
      m_BinEncoder.encodeBin( cbf, ctxSet( ctxId ) );
    
      DTRACE( g_trace_ctx, D_SYNTAX, "cbf_comp() etype=%d pos=(%d,%d) ctx=%d cbf=%d\n", area.compID, area.x, area.y, ctxId, cbf );
    }
    
    
    
    
    
    //================================================================================
    //  clause 7.3.8.9
    //--------------------------------------------------------------------------------
    //    void  mvd_coding( pu, refList )
    //================================================================================
    
    void CABACWriter::mvd_coding( const Mv &rMvd, int8_t imv )
    
    {
      int       horMvd = rMvd.getHor();
      int       verMvd = rMvd.getVer();
    
    #if JVET_O0057_ALTHPELIF
        CHECK((horMvd % 2) != 0 && (verMvd % 2) != 0, "IMV: MVD is not a multiple of 2");
        horMvd >>= 1;
        verMvd >>= 1;
        if (imv < IMV_HPEL)
        {
          CHECK((horMvd % 2) != 0 && (verMvd % 2) != 0, "IMV: MVD is not a multiple of 4");
          horMvd >>= 1;
          verMvd >>= 1;
          if (imv == IMV_4PEL)//IMV_4PEL
          {
            CHECK((horMvd % 4) != 0 && (verMvd % 4) != 0, "IMV: MVD is not a multiple of 16");
            horMvd >>= 2;
            verMvd >>= 2;
          }
        }
    #else
    
        CHECK( (horMvd % 4) != 0 && (verMvd % 4) != 0, "IMV: MVD is not a multiple of 4" );
        horMvd >>= 2;
        verMvd >>= 2;