Skip to content
Snippets Groups Projects
CABACWriter.cpp 123 KiB
Newer Older
  • Learn to ignore specific revisions
  •     return;
      }
    
      m_BinEncoder.encodeBin( pu.cu->smvdMode ? 1 : 0, Ctx::SmvdFlag() );
    
      DTRACE( g_trace_ctx, D_SYNTAX, "symmvd_flag() symmvd=%d pos=(%d,%d) size=%dx%d\n", pu.cu->smvdMode ? 1 : 0, pu.lumaPos().x, pu.lumaPos().y, pu.lumaSize().width, pu.lumaSize().height );
    }
    
    
    void CABACWriter::subblock_merge_flag( const CodingUnit& cu )
    {
    
    Huanbang Chen's avatar
    Huanbang Chen committed
      if ( cu.firstPU->mergeFlag && (cu.firstPU->mmvdMergeFlag || cu.mmvdSkip) )
      {
        return;
      }
    
    
      if ( !cu.cs->slice->isIntra() && (cu.cs->sps->getUseAffine() || cu.cs->sps->getSBTMVPEnabledFlag()) && cu.lumaSize().width >= 8 && cu.lumaSize().height >= 8 )
    
      {
        unsigned ctxId = DeriveCtx::CtxAffineFlag( cu );
    
    #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;
      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( 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 );
          }
    
        }
      }
      else if( CS::isDualITree( cs ) )
      {
        chromaCbfs = ChromaCbfs( false );
      }
    
    #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 prevCbCbf, const bool useISP )
    {
    
    #if JVET_O0193_REMOVE_TR_DEPTH_IN_CBF_CTX
      const unsigned  ctxId   = DeriveCtx::CtxQtCbf( area.compID, prevCbCbf, useISP && isLuma(area.compID) );
    #else
    
      const unsigned  ctxId   = DeriveCtx::CtxQtCbf( area.compID, depth, prevCbCbf, 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();
    
      {
        CHECK( (horMvd % 4) != 0 && (verMvd % 4) != 0, "IMV: MVD is not a multiple of 4" );
        horMvd >>= 2;
        verMvd >>= 2;
        if( imv == 2 )//IMV_4PEL
        {
    
    Xiang Li's avatar
    Xiang Li committed
          CHECK( (horMvd % 4) != 0 && (verMvd % 4) != 0, "IMV: MVD is not a multiple of 16" );
    
          horMvd >>= 2;
          verMvd >>= 2;
        }
      }
      unsigned  horAbs  = unsigned( horMvd < 0 ? -horMvd : horMvd );
      unsigned  verAbs  = unsigned( verMvd < 0 ? -verMvd : verMvd );
    
    
      // abs_mvd_greater0_flag[ 0 | 1 ]
      m_BinEncoder.encodeBin( (horAbs > 0), Ctx::Mvd() );
      m_BinEncoder.encodeBin( (verAbs > 0), Ctx::Mvd() );
    
      // abs_mvd_greater1_flag[ 0 | 1 ]
      if( horAbs > 0 )
      {
        m_BinEncoder.encodeBin( (horAbs > 1), Ctx::Mvd(1) );
      }
      if( verAbs > 0 )
      {
        m_BinEncoder.encodeBin( (verAbs > 1), Ctx::Mvd(1) );
      }
    
      // abs_mvd_minus2[ 0 | 1 ] and mvd_sign_flag[ 0 | 1 ]
      if( horAbs > 0 )
      {
        if( horAbs > 1 )
        {
          exp_golomb_eqprob( horAbs - 2, 1 );
        }
        m_BinEncoder.encodeBinEP( (horMvd < 0) );
      }
      if( verAbs > 0 )
      {
        if( verAbs > 1 )
        {
          exp_golomb_eqprob( verAbs - 2, 1 );
        }
        m_BinEncoder.encodeBinEP( (verMvd < 0) );
      }
    }
    
    
    
    
    //================================================================================
    //  clause 7.3.8.10
    //--------------------------------------------------------------------------------
    //    void  transform_unit      ( tu, cuCtx, chromaCbfs )
    //    void  cu_qp_delta         ( cu )
    //    void  cu_chroma_qp_offset ( cu )
    //================================================================================
    
    #if JVET_O0596_CBF_SIG_ALIGN_TO_SPEC
    void CABACWriter::transform_unit( const TransformUnit& tu, CUCtx& cuCtx, Partitioner& partitioner, const int subTuCounter)
    #else
    
    void CABACWriter::transform_unit( const TransformUnit& tu, CUCtx& cuCtx, ChromaCbfs& chromaCbfs )
    
    #if JVET_O0596_CBF_SIG_ALIGN_TO_SPEC
      const CodingStructure&  cs = *tu.cs;
      const CodingUnit&       cu = *tu.cu;
      const UnitArea&         area = partitioner.currArea();
      const unsigned          trDepth = partitioner.currTrDepth;
      const bool              chromaCbfISP = area.blocks[COMPONENT_Cb].valid() && cu.ispMode;
      ChromaCbfs              chromaCbfs;
      CHECK(tu.depth != trDepth, " transform unit should be not be futher partitioned");
    
      // cbf_cb & cbf_cr
      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;
          {
            chromaCbfs.Cb = TU::getCbfAtDepth(tu, COMPONENT_Cb, trDepth);
            //if (!(cu.sbtInfo && trDepth == 1))
            if (!(cu.sbtInfo && tu.noResidual))
              cbf_comp(cs, chromaCbfs.Cb, area.blocks[COMPONENT_Cb], cbfDepth);
          }
    
          {
            chromaCbfs.Cr = TU::getCbfAtDepth(tu, COMPONENT_Cr, trDepth);
            //if (!(cu.sbtInfo && trDepth == 1))
            if (!(cu.sbtInfo && tu.noResidual))
              cbf_comp(cs, chromaCbfs.Cr, area.blocks[COMPONENT_Cr], cbfDepth, chromaCbfs.Cb);
          }
        }
      }
      else if (CS::isDualITree(cs))
      {
        chromaCbfs = ChromaCbfs(false);
      }
    
      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 && !chromaCbfs.sigChroma(area.chromaFormat))
        {
          assert(!tu.noResidual);
          CHECK(!TU::getCbfAtDepth(tu, COMPONENT_Y, trDepth), "Luma cbf must be true for inter sbt residual tu");
        }
        else
        {
          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);
          }
        }
      }
    #else
    
      bool        lumaOnly  = ( cu.chromaFormat == CHROMA_400 || !tu.blocks[COMPONENT_Cb].valid() );
      bool        cbf[3]    = { TU::getCbf( tu, COMPONENT_Y ), chromaCbfs.Cb, chromaCbfs.Cr };
      bool        cbfLuma   = ( cbf[ COMPONENT_Y ] != 0 );
      bool        cbfChroma = false;
    
    
      {
        if( tu.blocks[COMPONENT_Cb].valid() )
        {
          cbf   [ COMPONENT_Cb  ] = TU::getCbf( tu, COMPONENT_Cb );
          cbf   [ COMPONENT_Cr  ] = TU::getCbf( tu, COMPONENT_Cr );
        }
        cbfChroma = ( cbf[ COMPONENT_Cb ] || cbf[ COMPONENT_Cr ] );
      }
    
    
    #if JVET_O0105_ICT
      if( !lumaOnly )
      {
        joint_cb_cr( tu, ( cbf[COMPONENT_Cb] ? 2 : 0 ) + ( cbf[COMPONENT_Cr] ? 1 : 0 ) );
      }
    #endif
    
    
      if( cbfLuma || cbfChroma )
      {
        if( cu.cs->pps->getUseDQP() && !cuCtx.isDQPCoded )
        {
    
          if (!CS::isDualITree(*tu.cs) || isLuma(tu.chType))
    
          {
            cu_qp_delta(cu, cuCtx.qp, cu.qp);
            cuCtx.qp = cu.qp;
            cuCtx.isDQPCoded = true;
          }
    
    Yu Han's avatar
    Yu Han committed
    #if JVET_O1168_CU_CHROMA_QP_OFFSET
        if (cu.cs->slice->getUseChromaQpAdj() && cbfChroma && !cuCtx.isChromaQpAdjCoded)
    #else
    
        if( cu.cs->slice->getUseChromaQpAdj() && cbfChroma && !cu.transQuantBypass && !cuCtx.isChromaQpAdjCoded )
    
    Yu Han's avatar
    Yu Han committed
    #endif
    
        {
          cu_chroma_qp_offset( cu );
          cuCtx.isChromaQpAdjCoded = true;
        }
        if( cbfLuma )
        {
    
    #if JVET_O0094_LFNST_ZERO_PRIM_COEFFS
    
    Mischa Siekmann's avatar
    Mischa Siekmann committed
          residual_coding( tu, COMPONENT_Y, &cuCtx );
    #else
    
    Mischa Siekmann's avatar
    Mischa Siekmann committed
    #endif
    
        }
        if( !lumaOnly )
        {
          for( ComponentID compID = COMPONENT_Cb; compID <= COMPONENT_Cr; compID = ComponentID( compID + 1 ) )
          {
            if( TU::hasCrossCompPredInfo( tu, compID ) )
            {
              cross_comp_pred( tu, compID );
            }
            if( cbf[ compID ] )
            {
    
    #if JVET_O0094_LFNST_ZERO_PRIM_COEFFS
    
    Mischa Siekmann's avatar
    Mischa Siekmann committed
              residual_coding( tu, compID, &cuCtx );
    #else
    
    Mischa Siekmann's avatar
    Mischa Siekmann committed
    #endif
    
            }
          }
        }
      }
    }
    
    void CABACWriter::cu_qp_delta( const CodingUnit& cu, int predQP, const int8_t qp )
    {
      CHECK(!( predQP != std::numeric_limits<int>::max()), "Unspecified error");
      int       DQp         = qp - predQP;
      int       qpBdOffsetY = cu.cs->sps->getQpBDOffset( CHANNEL_TYPE_LUMA );
      DQp                   = ( DQp + (MAX_QP + 1) + (MAX_QP + 1) / 2 + qpBdOffsetY + (qpBdOffsetY / 2)) % ((MAX_QP + 1) + qpBdOffsetY) - (MAX_QP + 1) / 2 - (qpBdOffsetY / 2);
      unsigned  absDQP      = unsigned( DQp < 0 ? -DQp : DQp );
      unsigned  unaryDQP    = std::min<unsigned>( absDQP, CU_DQP_TU_CMAX );
    
      unary_max_symbol( unaryDQP, Ctx::DeltaQP(), Ctx::DeltaQP(1), CU_DQP_TU_CMAX );
      if( absDQP >= CU_DQP_TU_CMAX )
      {
        exp_golomb_eqprob( absDQP - CU_DQP_TU_CMAX, CU_DQP_EG_k );
      }
      if( absDQP > 0 )
      {
        m_BinEncoder.encodeBinEP( DQp < 0 );
      }
    
      DTRACE_COND( ( isEncoding() ), g_trace_ctx, D_DQP, "x=%d, y=%d, d=%d, pred_qp=%d, DQp=%d, qp=%d\n", cu.blocks[cu.chType].lumaPos().x, cu.blocks[cu.chType].lumaPos().y, cu.qtDepth, predQP, DQp, qp );
    }
    
    
    void CABACWriter::cu_chroma_qp_offset( const CodingUnit& cu )
    {
      // cu_chroma_qp_offset_flag
      unsigned qpAdj = cu.chromaQpAdj;
      if( qpAdj == 0 )
      {
        m_BinEncoder.encodeBin( 0, Ctx::ChromaQpAdjFlag() );
      }
      else
      {
        m_BinEncoder.encodeBin( 1, Ctx::ChromaQpAdjFlag() );
        int length = cu.cs->pps->getPpsRangeExtension().getChromaQpOffsetListLen();
        if( length > 1 )
        {
          unary_max_symbol( qpAdj-1, Ctx::ChromaQpAdjIdc(), Ctx::ChromaQpAdjIdc(), length-1 );
        }
      }
    }
    
    
    
    
    
    //================================================================================
    //  clause 7.3.8.11
    //--------------------------------------------------------------------------------
    //    void        residual_coding         ( tu, compID )
    //    void        transform_skip_flag     ( tu, compID )
    //    void        explicit_rdpcm_mode     ( tu, compID )
    //    void        last_sig_coeff          ( coeffCtx )
    //    void        residual_coding_subblock( coeffCtx )
    //================================================================================
    
    
    #if JVET_O0105_ICT
    void CABACWriter::joint_cb_cr( const TransformUnit& tu, const int cbfMask )
    {
      CHECK( tu.jointCbCr && tu.jointCbCr != cbfMask, "wrong value of jointCbCr (" << (int)tu.jointCbCr << " vs " << (int)cbfMask << ")" );
    #if JVET_O0543_ICT_ICU_ONLY
      if( ( CU::isIntra( *tu.cu ) && cbfMask ) || ( cbfMask == 3 ) )
    #else
      if( cbfMask )
    #endif
      {
        m_BinEncoder.encodeBin( tu.jointCbCr ? 1 : 0, Ctx::JointCbCrFlag( cbfMask - 1 ) );
      }
    }
    #else
    
    void CABACWriter::joint_cb_cr( const TransformUnit& tu )
    {
      m_BinEncoder.encodeBin( tu.jointCbCr ? 1 : 0, Ctx::JointCbCrFlag( 0 ) );
    }
    
    #if JVET_O0094_LFNST_ZERO_PRIM_COEFFS
    
    Mischa Siekmann's avatar
    Mischa Siekmann committed
    void CABACWriter::residual_coding( const TransformUnit& tu, ComponentID compID, CUCtx* cuCtx )
    #else
    void CABACWriter::residual_coding( const TransformUnit& tu, ComponentID compID)
    #endif
    
    {
      const CodingUnit& cu = *tu.cu;
      DTRACE( g_trace_ctx, D_SYNTAX, "residual_coding() etype=%d pos=(%d,%d) size=%dx%d predMode=%d\n", tu.blocks[compID].compID, tu.blocks[compID].x, tu.blocks[compID].y, tu.blocks[compID].width, tu.blocks[compID].height, cu.predMode );
    
    
    #if JVET_O0105_ICT
      if( compID == COMPONENT_Cr && tu.jointCbCr == 3 )
        return;
    #else
    
      // Joint Cb-Cr residual mode is signalled if both Cb and Cr cbfs are true
    
      if ( compID == COMPONENT_Cr && TU::getCbf( tu, COMPONENT_Cb ) )
      {
        joint_cb_cr( tu );
    
        // No Cr residual in bitstream in joint Cb-Cr residual mode
        if ( tu.jointCbCr )
          return;
      }
    
      // code transform skip and explicit rdpcm mode
    
    Tung Nguyen's avatar
    Tung Nguyen committed
      mts_coding         ( tu, compID );
    
      if( isLuma( compID ) && ( tu.mtsIdx == MTS_SKIP || tu.cu->bdpcmMode ) )
    
      {
        residual_codingTS( tu, compID );
        return;
      }
    
    
      // determine sign hiding
      bool signHiding  = ( cu.cs->slice->getSignDataHidingEnabledFlag() && !cu.transQuantBypass && tu.rdpcm[compID] == RDPCM_OFF );
    
      if(  signHiding && CU::isIntra(cu) && CU::isRDPCMEnabled(cu) && tu.mtsIdx==MTS_SKIP )
    
      {
        const ChannelType chType    = toChannelType( compID );
        const unsigned    intraMode = PU::getFinalIntraMode( *cu.cs->getPU( tu.blocks[compID].pos(), chType ), chType );
        if( intraMode == HOR_IDX || intraMode == VER_IDX )
        {
          signHiding = false;
        }
      }