Skip to content
Snippets Groups Projects
CABACWriter.cpp 104 KiB
Newer Older
  • Learn to ignore specific revisions
  •       break;
        }
      }
      DTRACE( g_trace_ctx, D_SYNTAX, "ref_idx() value=%d pos=(%d,%d)\n", refIdx, pu.lumaPos().x, pu.lumaPos().y );
    }
    
    void CABACWriter::mvp_flag( const PredictionUnit& pu, RefPicList eRefList )
    {
      m_BinEncoder.encodeBin( pu.mvpIdx[eRefList], Ctx::MVPIdx() );
      DTRACE( g_trace_ctx, D_SYNTAX, "mvp_flag() value=%d pos=(%d,%d)\n", pu.mvpIdx[eRefList], pu.lumaPos().x, pu.lumaPos().y );
      DTRACE( g_trace_ctx, D_SYNTAX, "mvpIdx(refList:%d)=%d\n", eRefList, pu.mvpIdx[eRefList] );
    }
    
    
    void CABACWriter::MHIntra_flag(const PredictionUnit& pu)
    {
    
      if (!pu.cs->sps->getUseMHIntra())
    
        CHECK(pu.mhIntraFlag == true, "invalid MHIntra SPS");
    
        CHECK(pu.mhIntraFlag == true, "invalid MHIntra and skip");
    
        CHECK(pu.mhIntraFlag == true, "invalid MHIntra and mmvd");
    
      if (pu.cu->affine)
      {
        CHECK(pu.mhIntraFlag == true, "invalid MHIntra and affine");
        return;
      }
    
      if (pu.cu->lwidth() * pu.cu->lheight() < 64 || pu.cu->lwidth() >= MAX_CU_SIZE || pu.cu->lheight() >= MAX_CU_SIZE)
      {
    
        CHECK(pu.mhIntraFlag == true, "invalid MHIntra and blk");
    
      m_BinEncoder.encodeBin(pu.mhIntraFlag, Ctx::MHIntraFlag());
    
      DTRACE(g_trace_ctx, D_SYNTAX, "MHIntra_flag() MHIntra=%d pos=(%d,%d) size=%dx%d\n", pu.mhIntraFlag ? 1 : 0, pu.lumaPos().x, pu.lumaPos().y, pu.lumaSize().width, pu.lumaSize().height);
    
    }
    
    void CABACWriter::MHIntra_luma_pred_modes(const CodingUnit& cu)
    {
      if (!cu.Y().valid())
      {
        return;
      }
    
    
      int      numBlocks = CU::getNumPUs(cu);
      unsigned mpm_idxs[4];
      unsigned pred_modes[4];
    
      const PredictionUnit* pu = cu.firstPU;
    
      unsigned mpm_pred[numMPMs];
      for (int k = 0; k < numBlocks; k++)
      {
        unsigned&  mpm_idx = mpm_idxs[k];
        unsigned&  pred_mode = pred_modes[k];
    
        PU::getMHIntraMPMs(*pu, mpm_pred);
    
        pred_mode = pu->intraDir[0];
    
        mpm_idx = numMPMs;
    
    
        for (int idx = 0; idx < numMPMs; idx++)
    
        {
          if (pred_mode == mpm_pred[idx])
          {
            mpm_idx = idx;
            break;
          }
        }
        if (PU::getNarrowShape(pu->lwidth(), pu->lheight()) == 0)
        {
          m_BinEncoder.encodeBin(mpm_idx < numMPMs, Ctx::MHIntraPredMode());
        }
        pu = pu->next;
      }
    
      pu = cu.firstPU;
    
      // mpm_idx / rem_intra_luma_pred_mode
      for (int k = 0; k < numBlocks; k++)
      {
        const unsigned& mpm_idx = mpm_idxs[k];
        if (mpm_idx < numMPMs)
        {
          m_BinEncoder.encodeBinEP(mpm_idx > 0);
          if (mpm_idx)
          {
            m_BinEncoder.encodeBinEP(mpm_idx > 1);
          }
        }
        DTRACE(g_trace_ctx, D_SYNTAX, "intra_luma_pred_modes() idx=%d pos=(%d,%d) mode=%d\n", k, pu->lumaPos().x, pu->lumaPos().y, pu->intraDir[0]);
        pu = pu->next;
      }
    }
    
    void CABACWriter::triangle_mode( const CodingUnit& cu )
    {
    
      if( !cu.cs->slice->getSPS()->getUseTriangle() || !cu.cs->slice->isInterB() || cu.lwidth() * cu.lheight() < TRIANGLE_MIN_SIZE || cu.affine )
    
    #if 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 )
    //================================================================================
    
    
    #if JVET_M0102_INTRA_SUBPARTITIONS
    void CABACWriter::transform_tree( const CodingStructure& cs, Partitioner& partitioner, CUCtx& cuCtx, ChromaCbfs& chromaCbfs, const PartSplit ispType, const int subTuIdx )
    #else
    
    void CABACWriter::transform_tree( const CodingStructure& cs, Partitioner& partitioner, CUCtx& cuCtx, ChromaCbfs& chromaCbfs )
    
    #if JVET_M0140_SBT
      ChromaCbfs chromaCbfsLastDepth;
      chromaCbfsLastDepth.Cb              = chromaCbfs.Cb;
      chromaCbfsLastDepth.Cr              = chromaCbfs.Cr;
    #endif
    
      const UnitArea&       area          = partitioner.currArea();
    
    #if JVET_M0102_INTRA_SUBPARTITIONS
            int             subTuCounter  = subTuIdx;
      const TransformUnit&  tu            = *cs.getTU( area.blocks[partitioner.chType].pos(), partitioner.chType, subTuIdx );
    #else
    
      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 );
    
    #if JVET_M0102_INTRA_SUBPARTITIONS
      const bool            chromaCbfISP  = area.blocks[COMPONENT_Cb].valid() && cu.ispMode && !split;
    #endif
    
    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" );
    
    #if JVET_M0140_SBT
      else if( cu.sbtInfo && partitioner.canSplit( PartSplit( cu.getSbtTuSplit() ), cs ) )
      {
        CHECK( !split, "transform split implied - sbt" );
      }
    #endif
    
    Karsten Suehring's avatar
    Karsten Suehring committed
      else
    
    #if JVET_M0102_INTRA_SUBPARTITIONS
      CHECK( split && !cu.ispMode, "transform split not allowed with QTBT" );
    #else
    
    Karsten Suehring's avatar
    Karsten Suehring committed
      CHECK( split, "transform split not allowed with QTBT" );
    
    #if JVET_M0102_INTRA_SUBPARTITIONS
      if( area.chromaFormat != CHROMA_400 && area.blocks[COMPONENT_Cb].valid() && ( !CS::isDualITree( cs ) || 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 ) )
    
    #if JVET_M0102_INTRA_SUBPARTITIONS
          unsigned cbfDepth = chromaCbfISP ? trDepth - 1 : trDepth;
          if( trDepth == 0 || chromaCbfs.Cb || chromaCbfISP )
          {
            chromaCbfs.Cb = TU::getCbfAtDepth( tu, COMPONENT_Cb, trDepth );
    
    #if JVET_M0140_SBT
            if( !( cu.sbtInfo && trDepth == 1 ) )
    #endif
    
            cbf_comp( cs, chromaCbfs.Cb, area.blocks[COMPONENT_Cb], cbfDepth );
          }
          else
          {
            CHECK( TU::getCbfAtDepth( tu, COMPONENT_Cb, cbfDepth ) != chromaCbfs.Cb, "incorrect Cb cbf" );
          }
    
          if( trDepth == 0 || chromaCbfs.Cr || chromaCbfISP )
          {
            chromaCbfs.Cr = TU::getCbfAtDepth( tu, COMPONENT_Cr, trDepth );
    
    #if JVET_M0140_SBT
            if( !( cu.sbtInfo && trDepth == 1 ) )
    #endif
    
            cbf_comp( cs, chromaCbfs.Cr, area.blocks[COMPONENT_Cr], cbfDepth, chromaCbfs.Cb );
          }
          else
          {
            CHECK( TU::getCbfAtDepth( tu, COMPONENT_Cr, cbfDepth ) != chromaCbfs.Cr, "incorrect Cr cbf" );
          }
    #else
    
          if( trDepth == 0 || chromaCbfs.Cb )
          {
            chromaCbfs.Cb = TU::getCbfAtDepth( tu, COMPONENT_Cb, trDepth );
    
    #if JVET_M0140_SBT
            if( !( cu.sbtInfo && trDepth == 1 ) )
    #endif
    
            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 );
    
    #if JVET_M0140_SBT
            if( !( cu.sbtInfo && trDepth == 1 ) )
    #endif
    
            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
    
    #if JVET_M0102_INTRA_SUBPARTITIONS
        if ( trDepth == 0 && !cu.ispMode ) emt_cu_flag( cu );
    #else
    
    Tung Nguyen's avatar
    Tung Nguyen committed
    #endif
    
    
        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 );
        }
    
    #if JVET_M0102_INTRA_SUBPARTITIONS
        else if( cu.ispMode )
        {
          partitioner.splitCurrArea( ispType, cs );
        }
    
    #endif
    #if JVET_M0140_SBT
        else if( cu.sbtInfo && partitioner.canSplit( PartSplit( cu.getSbtTuSplit() ), cs ) )
        {
          partitioner.splitCurrArea( PartSplit( cu.getSbtTuSplit() ), cs );
        }
    
        else
          THROW( "Implicit TU split not available" );
    
        do
        {
          ChromaCbfs subChromaCbfs = chromaCbfs;
    
    #if JVET_M0102_INTRA_SUBPARTITIONS
          transform_tree( cs, partitioner, cuCtx, subChromaCbfs, ispType, subTuCounter );
          subTuCounter += subTuCounter != -1 ? 1 : 0;
    #else
    
          transform_tree( cs, partitioner, cuCtx, subChromaCbfs );
    
        } while( partitioner.nextPart( cs ) );
    
        partitioner.exitCurrSplit();
      }
      else
      {
        DTRACE( g_trace_ctx, D_SYNTAX, "transform_unit() pos=(%d,%d) size=%dx%d depth=%d trDepth=%d\n", tu.blocks[tu.chType].x, tu.blocks[tu.chType].y, tu.blocks[tu.chType].width, tu.blocks[tu.chType].height, cu.depth, partitioner.currTrDepth );
    
        if( !isChroma( partitioner.chType ) )
        {
          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" );
          }
    
    #if JVET_M0140_SBT
          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" );
          }
    #endif
    
    #if JVET_M0102_INTRA_SUBPARTITIONS
            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
    
            cbf_comp( cs, TU::getCbfAtDepth( tu, COMPONENT_Y, trDepth ), tu.Y(), trDepth );
    
    Tung Nguyen's avatar
    Tung Nguyen committed
    #if !JVET_M0464_UNI_MTS
    
        if( trDepth == 0 && TU::getCbfAtDepth( tu, COMPONENT_Y, 0 ) ) emt_cu_flag( cu );
    
    Tung Nguyen's avatar
    Tung Nguyen committed
    #endif
    
    #if JVET_M0102_INTRA_SUBPARTITIONS
    void CABACWriter::cbf_comp( const CodingStructure& cs, bool cbf, const CompArea& area, unsigned depth, const bool prevCbCbf, const bool useISP )
    {
      const unsigned  ctxId   = DeriveCtx::CtxQtCbf( area.compID, depth, prevCbCbf, useISP && isLuma(area.compID) );
    #else
    
    void CABACWriter::cbf_comp( const CodingStructure& cs, bool cbf, const CompArea& area, unsigned depth, const bool prevCbCbf )
    {
      const unsigned  ctxId   = DeriveCtx::CtxQtCbf( area.compID, depth, prevCbCbf );
    
      const CtxSet&   ctxSet  = Ctx::QtCbf[ area.compID ];
    
      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 )
    //================================================================================
    
    #if JVET_M0246_AFFINE_AMVR
    void CABACWriter::mvd_coding( const Mv &rMvd, int8_t imv )
    #else
    
    void CABACWriter::mvd_coding( const Mv &rMvd, uint8_t imv )
    
    {
      int       horMvd = rMvd.getHor();
      int       verMvd = rMvd.getVer();
    
    #if JVET_M0246_AFFINE_AMVR
      if ( imv > 0 )
    #else
    
      {
        CHECK( (horMvd % 4) != 0 && (verMvd % 4) != 0, "IMV: MVD is not a multiple of 4" );
        horMvd >>= 2;
        verMvd >>= 2;
        if( imv == 2 )//IMV_4PEL
        {
          CHECK( (horMvd % 4) != 0 && (verMvd % 4) != 0, "IMV: MVD is not a multiple of 8" );
          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 )
    //================================================================================
    
    void CABACWriter::transform_unit( const TransformUnit& tu, CUCtx& cuCtx, ChromaCbfs& chromaCbfs )
    {
      CodingUnit& cu        = *tu.cu;
      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( 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;
          }
    
        }
        if( cu.cs->slice->getUseChromaQpAdj() && cbfChroma && !cu.transQuantBypass && !cuCtx.isChromaQpAdjCoded )
        {
          cu_chroma_qp_offset( cu );
          cuCtx.isChromaQpAdjCoded = true;
        }
        if( cbfLuma )
        {
          residual_coding( tu, COMPONENT_Y );
        }
        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 ] )
            {
              residual_coding( tu, compID );
            }
          }
        }
      }
    }
    
    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 )
    //================================================================================
    
    void CABACWriter::residual_coding( const TransformUnit& tu, ComponentID compID )
    {
      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 );
    
      // code transform skip and explicit rdpcm mode
    
    Tung Nguyen's avatar
    Tung Nguyen committed
    #if JVET_M0464_UNI_MTS
      mts_coding         ( tu, compID );
    #else
    
    Tung Nguyen's avatar
    Tung Nguyen committed
    #endif
    
      explicit_rdpcm_mode( tu, compID );
    
    #if HEVC_USE_SIGN_HIDING
      // determine sign hiding
      bool signHiding  = ( cu.cs->slice->getSignDataHidingEnabledFlag() && !cu.transQuantBypass && tu.rdpcm[compID] == RDPCM_OFF );
    
    Tung Nguyen's avatar
    Tung Nguyen committed
    #if JVET_M0464_UNI_MTS
      if(  signHiding && CU::isIntra(cu) && CU::isRDPCMEnabled(cu) && tu.mtsIdx==1 )
    #else
    
      if(  signHiding && CU::isIntra(cu) && CU::isRDPCMEnabled(cu) && tu.transformSkip[compID] )
    
    Tung Nguyen's avatar
    Tung Nguyen committed
    #endif
    
      {
        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;
        }
      }
    #endif
    
      // init coeff coding context
    #if HEVC_USE_SIGN_HIDING
      CoeffCodingContext  cctx    ( tu, compID, signHiding );
    #else
      CoeffCodingContext  cctx    ( tu, compID );
    #endif
      const TCoeff*       coeff   = tu.getCoeffs( compID ).buf;
    
    Tung Nguyen's avatar
    Tung Nguyen committed
    #if !JVET_M0464_UNI_MTS
    
    Tung Nguyen's avatar
    Tung Nguyen committed
    #endif
    
    
      // determine and set last coeff position and sig group flags
      int                      scanPosLast = -1;
      std::bitset<MLS_GRP_NUM> sigGroupFlags;
      for( int scanPos = 0; scanPos < cctx.maxNumCoeff(); scanPos++)
      {
        unsigned blkPos = cctx.blockPos( scanPos );
        if( coeff[blkPos] )
        {
          scanPosLast = scanPos;
          sigGroupFlags.set( scanPos >> cctx.log2CGSize() );
        }
      }
      CHECK( scanPosLast < 0, "Coefficient coding called for empty TU" );
      cctx.setScanPosLast(scanPosLast);
    
      // code last coeff position
    
    #if JVET_M0297_32PT_MTS_ZERO_OUT
      last_sig_coeff( cctx, tu, compID );
    #else
    
    #endif
    
    
      // code subblocks
      const int stateTab  = ( tu.cs->slice->getDepQuantEnabledFlag() ? 32040 : 0 );
      int       state     = 0;
    
    Tung Nguyen's avatar
    Tung Nguyen committed
    #if !JVET_M0464_UNI_MTS
    
      bool useEmt = ( cu.cs->sps->getUseIntraEMT() && cu.predMode == MODE_INTRA ) || ( cu.cs->sps->getUseInterEMT() && cu.predMode == MODE_INTER );
    
    #if JVET_M0102_INTRA_SUBPARTITIONS
      useEmt = useEmt && !cu.ispMode;
    #endif
    
    #if JVET_M0140_SBT
      useEmt = useEmt && !cu.sbtInfo;
    #endif
    
    Tung Nguyen's avatar
    Tung Nguyen committed
    #endif
    
    
      for( int subSetId = ( cctx.scanPosLast() >> cctx.log2CGSize() ); subSetId >= 0; subSetId--)
      {
        cctx.initSubblock       ( subSetId, sigGroupFlags[subSetId] );
    
    #if JVET_M0297_32PT_MTS_ZERO_OUT
    
    #if JVET_M0140_SBT
    #if JVET_M0464_UNI_MTS
        if( ( tu.mtsIdx > 1 || ( tu.cu->sbtInfo != 0 && tu.blocks[ compID ].height <= 32 && tu.blocks[ compID ].width <= 32 ) ) && !tu.cu->transQuantBypass && compID == COMPONENT_Y )
    
        if( ( ( tu.cu->emtFlag && !tu.transformSkip[ compID ] ) || ( tu.cu->sbtInfo != 0 && tu.blocks[ compID ].height <= 32 && tu.blocks[ compID ].width <= 32 ) ) && !tu.cu->transQuantBypass && compID == COMPONENT_Y )
    #endif
    #else
    #if JVET_M0464_UNI_MTS
        if( tu.mtsIdx > 1 && !tu.cu->transQuantBypass && compID == COMPONENT_Y )
    #else
        if( tu.cu->emtFlag && !tu.transformSkip[ compID ] && !tu.cu->transQuantBypass && compID == COMPONENT_Y )
    #endif
    
    #endif
    
        {
          if( ( tu.blocks[ compID ].height == 32 && cctx.cgPosY() >= ( 16 >> cctx.log2CGHeight() ) )
           || ( tu.blocks[ compID ].width  == 32 && cctx.cgPosX() >= ( 16 >> cctx.log2CGWidth()  ) ) )
          {
            continue;
          }
        }
    #endif
        residual_coding_subblock( cctx, coeff, stateTab, state );
    
    Tung Nguyen's avatar
    Tung Nguyen committed
    #if !JVET_M0464_UNI_MTS
    
        if (useEmt)
        {
          numSig += cctx.emtNumSigCoeff();
          cctx.setEmtNumSigCoeff( 0 );
        }
    
    Tung Nguyen's avatar
    Tung Nguyen committed
    #endif
    
    Tung Nguyen's avatar
    Tung Nguyen committed
    #if !JVET_M0464_UNI_MTS
    
      if( useEmt && !tu.transformSkip[compID] && compID == COMPONENT_Y && tu.cu->emtFlag )
      {
        if( CU::isIntra( *tu.cu ) )
        {
    
    Tung Nguyen's avatar
    Tung Nguyen committed
    #endif
    
    Tung Nguyen's avatar
    Tung Nguyen committed
    #if JVET_M0464_UNI_MTS
    void CABACWriter::mts_coding( const TransformUnit& tu, ComponentID compID )
    {
      const CodingUnit  &cu = *tu.cu;
      const bool  tsAllowed = TU::isTSAllowed ( tu, compID );
      const bool mtsAllowed = TU::isMTSAllowed( tu, compID );
    
      if( !mtsAllowed && !tsAllowed ) return;
    
      int symbol  = 0;
      int ctxIdx  = 0;
    
      if( tsAllowed )
      {
        symbol = 1 - ( tu.mtsIdx == 1 ? 1 : 0 );
        ctxIdx = 6;
        m_BinEncoder.encodeBin( symbol, Ctx::MTSIndex( ctxIdx ) );
      }
    
      if( tu.mtsIdx != 1 )
      {
        if( mtsAllowed )
        {
          symbol = tu.mtsIdx != 0 ? 1 : 0;
          ctxIdx = std::min( (int)cu.qtDepth, 5 );
          m_BinEncoder.encodeBin( symbol, Ctx::MTSIndex( ctxIdx ) );
    
    Tung Nguyen's avatar
    Tung Nguyen committed
          if( symbol )
          {
            ctxIdx = 7;
            for( int i = 0; i < 3; i++, ctxIdx++ )
            {
              symbol = tu.mtsIdx > i + 2 ? 1 : 0;
              m_BinEncoder.encodeBin( symbol, Ctx::MTSIndex( ctxIdx ) );
    
              if( !symbol )
              {
                break;
              }
            }
          }
        }
      }
    
      DTRACE( g_trace_ctx, D_SYNTAX, "mts_coding() etype=%d pos=(%d,%d) mtsIdx=%d\n", COMPONENT_Y, cu.lx(), cu.ly(), tu.mtsIdx );
    }
    #else
    
    void CABACWriter::transform_skip_flag( const TransformUnit& tu, ComponentID compID )
    {
    
    #if JVET_M0102_INTRA_SUBPARTITIONS
      if (!tu.cu->cs->pps->getUseTransformSkip() || tu.cu->transQuantBypass || !TU::hasTransformSkipFlag(*tu.cs, tu.blocks[compID]) || (isLuma(compID) && tu.cu->emtFlag) || (tu.cu->ispMode && isLuma(compID)))
    #else
    
      if( !tu.cu->cs->pps->getUseTransformSkip() || tu.cu->transQuantBypass || !TU::hasTransformSkipFlag( *tu.cs, tu.blocks[compID] ) || ( isLuma( compID ) && tu.cu->emtFlag ) )
    
      m_BinEncoder.encodeBin( tu.transformSkip[compID], Ctx::TransformSkipFlag(toChannelType(compID)) );
    
      DTRACE( g_trace_ctx, D_SYNTAX, "transform_skip_flag() etype=%d pos=(%d,%d) trSkip=%d\n", compID, tu.blocks[compID].x, tu.blocks[compID].y, (int)tu.transformSkip[compID] );
    }
    
    void CABACWriter::emt_tu_index( const TransformUnit& tu )
    {
    
    Karsten Suehring's avatar
    Karsten Suehring committed
      int maxSizeEmtIntra = EMT_INTRA_MAX_CU_WITH_QTBT;
      int maxSizeEmtInter = EMT_INTER_MAX_CU_WITH_QTBT;
    
    
      if( CU::isIntra( *tu.cu ) && ( tu.cu->Y().width <= maxSizeEmtIntra ) && ( tu.cu->Y().height <= maxSizeEmtIntra ) )
      {
        uint8_t trIdx = tu.emtIdx;
        m_BinEncoder.encodeBin( ( trIdx & 1 ) ? 1 : 0, Ctx::EMTTuIndex( 0 ) );
        m_BinEncoder.encodeBin( ( trIdx / 2 ) ? 1 : 0, Ctx::EMTTuIndex( 1 ) );
        DTRACE( g_trace_ctx, D_SYNTAX, "emt_tu_index() etype=%d pos=(%d,%d) emtTrIdx=%d\n", COMPONENT_Y, tu.blocks[COMPONENT_Y].x, tu.blocks[COMPONENT_Y].y, ( int ) tu.emtIdx );
      }
      if( !CU::isIntra( *tu.cu ) && ( tu.cu->Y().width <= maxSizeEmtInter ) && ( tu.cu->Y().height <= maxSizeEmtInter ) )
      {
        uint8_t trIdx = tu.emtIdx;
        m_BinEncoder.encodeBin( ( trIdx & 1 ) ? 1 : 0, Ctx::EMTTuIndex( 2 ) );
        m_BinEncoder.encodeBin( ( trIdx / 2 ) ? 1 : 0, Ctx::EMTTuIndex( 3 ) );
        DTRACE( g_trace_ctx, D_SYNTAX, "emt_tu_index() etype=%d pos=(%d,%d) emtTrIdx=%d\n", COMPONENT_Y, tu.blocks[COMPONENT_Y].x, tu.blocks[COMPONENT_Y].y, ( int ) tu.emtIdx );
      }
    }
    
    //void CABACWriter::emt_cu_flag(const CodingUnit& cu, uint32_t depth, bool codeCuFlag, const int tuWidth,const int tuHeight)
    void CABACWriter::emt_cu_flag( const CodingUnit& cu )
    {
    
    #if JVET_M0102_INTRA_SUBPARTITIONS
      if ( CU::isIntra( cu ) && cu.ispMode )
      {
        return;
      }
    
    Yu Han's avatar
    Yu Han committed
    #if JVET_M0483_IBC
    
      if (!((cs.sps->getUseIntraEMT() && CU::isIntra(cu)) || (cs.sps->getUseInterEMT() && CU::isInter(cu))) || isChroma(cu.chType))
    
    Yu Han's avatar
    Yu Han committed
    #else
    
      if( !( ( cs.sps->getUseIntraEMT() && CU::isIntra( cu ) ) || ( cs.sps->getUseInterEMT() && CU::isInter( cu ) ) ) || isChroma( cu.chType ) )
    
    Yu Han's avatar
    Yu Han committed
    #endif
    
      {
        return;
      }
    
      unsigned depth          = cu.qtDepth;
      const unsigned cuWidth  = cu.lwidth();
      const unsigned cuHeight = cu.lheight();
    
    
    Karsten Suehring's avatar
    Karsten Suehring committed
      if( depth >= NUM_EMT_CU_FLAG_CTX )
    
    Karsten Suehring's avatar
    Karsten Suehring committed
        depth = NUM_EMT_CU_FLAG_CTX - 1;
    
    Karsten Suehring's avatar
    Karsten Suehring committed
      int maxSizeEmtIntra = EMT_INTRA_MAX_CU_WITH_QTBT;
      int maxSizeEmtInter = EMT_INTER_MAX_CU_WITH_QTBT;
    
    
      const unsigned maxSizeEmt = CU::isIntra( cu ) ? maxSizeEmtIntra : maxSizeEmtInter;
    
      if( cuWidth <= maxSizeEmt && cuHeight <= maxSizeEmt )
      {
        m_BinEncoder.encodeBin( cu.emtFlag, Ctx::EMTCuFlag( depth ) );
        DTRACE( g_trace_ctx, D_SYNTAX, "emt_cu_flag() etype=%d pos=(%d,%d) emtCuFlag=%d\n", COMPONENT_Y, cu.lx(), cu.ly(), ( int ) cu.emtFlag );
      }
    }
    
    Tung Nguyen's avatar
    Tung Nguyen committed
    #endif
    
    #if JVET_M0102_INTRA_SUBPARTITIONS
    void CABACWriter::isp_mode( const CodingUnit& cu )
    {
      if( !CU::isIntra( cu ) || !isLuma( cu.chType ) || cu.firstPU->multiRefIdx )
      {
        CHECK( cu.ispMode != NOT_INTRA_SUBPARTITIONS, "error: cu.intraSubPartitions != 0" );
        return;
      }
      const ISPType allowedSplits = CU::canUseISPSplit( cu, getFirstComponentOfChannel( cu.chType ) );
      if( allowedSplits == NOT_INTRA_SUBPARTITIONS ) return;
    
      if( cu.ispMode == NOT_INTRA_SUBPARTITIONS )
      {
        m_BinEncoder.encodeBin( 0, Ctx::ISPMode( 0 ) );
      }
      else
      {
        m_BinEncoder.encodeBin( 1, Ctx::ISPMode( 0 ) );
    
        if( allowedSplits == CAN_USE_VER_AND_HORL_SPLITS )
        {
          m_BinEncoder.encodeBin( cu.ispMode - 1, Ctx::ISPMode( 1 ) );
        }
      }
      DTRACE( g_trace_ctx, D_SYNTAX, "intra_subPartitions() etype=%d pos=(%d,%d) ispIdx=%d\n", cu.chType, cu.blocks[cu.chType].x, cu.blocks[cu.chType].y, (int)cu.ispMode );
    }
    #endif
    
    
    void CABACWriter::explicit_rdpcm_mode( const TransformUnit& tu, ComponentID compID )
    {
      const CodingUnit& cu = *tu.cu;
    
    Tung Nguyen's avatar
    Tung Nguyen committed
    #if JVET_M0464_UNI_MTS
      if( !CU::isIntra(cu) && CU::isRDPCMEnabled(cu) && ( tu.mtsIdx==1 || cu.transQuantBypass ) )
    #else
    
      if( !CU::isIntra(cu) && CU::isRDPCMEnabled(cu) && ( tu.transformSkip[compID] || cu.transQuantBypass ) )
    
    Tung Nguyen's avatar
    Tung Nguyen committed
    #endif
    
      {
        ChannelType chType = toChannelType( compID );
        switch( tu.rdpcm[compID] )
        {
        case RDPCM_VER:
          m_BinEncoder.encodeBin( 1, Ctx::RdpcmFlag(chType) );
          m_BinEncoder.encodeBin( 1, Ctx::RdpcmDir (chType) );
          break;
        case RDPCM_HOR:
          m_BinEncoder.encodeBin( 1, Ctx::RdpcmFlag(chType) );
          m_BinEncoder.encodeBin( 0, Ctx::RdpcmDir (chType) );
          break;
        default: // RDPCM_OFF
          m_BinEncoder.encodeBin( 0, Ctx::RdpcmFlag(chType) );
        }
      }
    }
    
    
    
    #if JVET_M0297_32PT_MTS_ZERO_OUT
    void CABACWriter::last_sig_coeff( CoeffCodingContext& cctx, const TransformUnit& tu, ComponentID compID )
    #else
    
    void CABACWriter::last_sig_coeff( CoeffCodingContext& cctx )
    
    #endif
    
    {
      unsigned blkPos = cctx.blockPos( cctx.scanPosLast() );
      unsigned posX, posY;
    #if HEVC_USE_MDCS
      if( cctx.scanType() == SCAN_VER )
      {
        posX  = blkPos / cctx.width();
        posY  = blkPos - ( posX * cctx.width() );
      }
      else
    #endif
      {
        posY  = blkPos / cctx.width();
        posX  = blkPos - ( posY * cctx.width() );
      }
    
      unsigned CtxLast;
      unsigned GroupIdxX = g_uiGroupIdx[ posX ];
      unsigned GroupIdxY = g_uiGroupIdx[ posY ];
    
    
    #if JVET_M0297_32PT_MTS_ZERO_OUT
    
      unsigned maxLastPosX = cctx.maxLastPosX();
      unsigned maxLastPosY = cctx.maxLastPosY();
    
    #if JVET_M0140_SBT
    #if JVET_M0464_UNI_MTS
      if( ( tu.mtsIdx > 1 || ( tu.cu->sbtInfo != 0 && tu.blocks[ compID ].width <= 32 && tu.blocks[ compID ].height <= 32 ) ) && !tu.cu->transQuantBypass && compID == COMPONENT_Y )
    #else
      if( ( ( tu.cu->emtFlag && !tu.transformSkip[ compID ] ) || ( tu.cu->sbtInfo != 0 && tu.blocks[ compID ].width <= 32 && tu.blocks[ compID ].height <= 32 ) ) && !tu.cu->transQuantBypass && compID == COMPONENT_Y )
    #endif
    #else
    
    #if JVET_M0464_UNI_MTS
      if( tu.mtsIdx > 1 && !tu.cu->transQuantBypass && compID == COMPONENT_Y )
    #else
      if( tu.cu->emtFlag && !tu.transformSkip[ compID ] && !tu.cu->transQuantBypass && compID == COMPONENT_Y )
    
        maxLastPosX = ( tu.blocks[compID].width  == 32 ) ? g_uiGroupIdx[ 15 ] : maxLastPosX;
        maxLastPosY = ( tu.blocks[compID].height == 32 ) ? g_uiGroupIdx[ 15 ] : maxLastPosY;
    
      for( CtxLast = 0; CtxLast < GroupIdxX; CtxLast++ )
      {
        m_BinEncoder.encodeBin( 1, cctx.lastXCtxId( CtxLast ) );
      }
    
    #if JVET_M0297_32PT_MTS_ZERO_OUT
    
      if( GroupIdxX < maxLastPosX )
    
    #endif
    
      {
        m_BinEncoder.encodeBin( 0, cctx.lastXCtxId( CtxLast ) );
      }
      for( CtxLast = 0; CtxLast < GroupIdxY; CtxLast++ )
      {
        m_BinEncoder.encodeBin( 1, cctx.lastYCtxId( CtxLast ) );
      }
    
    #if JVET_M0297_32PT_MTS_ZERO_OUT
    
      if( GroupIdxY < maxLastPosY )