Skip to content
Snippets Groups Projects
CABACWriter.cpp 86.7 KiB
Newer Older
  • Learn to ignore specific revisions
  •   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( cu.chromaFormat != CHROMA_400 )
      {
        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
      last_sig_coeff( cctx );
    
      // 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->getSpsNext().getUseIntraEMT() && cu.predMode == MODE_INTRA ) || ( cu.cs->sps->getSpsNext().getUseInterEMT() && cu.predMode != MODE_INTRA );
      useEmt = useEmt && isLuma(compID);
    
    Tung Nguyen's avatar
    Tung Nguyen committed
    #endif
    
    
      for( int subSetId = ( cctx.scanPosLast() >> cctx.log2CGSize() ); subSetId >= 0; subSetId--)
      {
        cctx.initSubblock       ( subSetId, sigGroupFlags[subSetId] );
        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( !tu.cu->cs->pps->getUseTransformSkip() || tu.cu->transQuantBypass || !TU::hasTransformSkipFlag( *tu.cs, tu.blocks[compID] ) || ( isLuma( compID ) && tu.cu->emtFlag ) )
      {
        return;
      }
      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 )
    {
      const CodingStructure& cs = *cu.cs;
    
      if( !( ( cs.sps->getSpsNext().getUseIntraEMT() && CU::isIntra( cu ) ) || ( cs.sps->getSpsNext().getUseInterEMT() && CU::isInter( cu ) ) ) || isChroma( cu.chType ) )
      {
        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
    
    
    
    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) );
        }
      }
    }
    
    
    void CABACWriter::last_sig_coeff( CoeffCodingContext& cctx )
    {
      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 ];
    
      for( CtxLast = 0; CtxLast < GroupIdxX; CtxLast++ )
      {
        m_BinEncoder.encodeBin( 1, cctx.lastXCtxId( CtxLast ) );
      }
      if( GroupIdxX < cctx.maxLastPosX() )
      {
        m_BinEncoder.encodeBin( 0, cctx.lastXCtxId( CtxLast ) );
      }
      for( CtxLast = 0; CtxLast < GroupIdxY; CtxLast++ )
      {
        m_BinEncoder.encodeBin( 1, cctx.lastYCtxId( CtxLast ) );
      }
      if( GroupIdxY < cctx.maxLastPosY() )
      {
        m_BinEncoder.encodeBin( 0, cctx.lastYCtxId( CtxLast ) );
      }
      if( GroupIdxX > 3 )
      {
        posX -= g_uiMinInGroup[ GroupIdxX ];
        for (int i = ( ( GroupIdxX - 2 ) >> 1 ) - 1 ; i >= 0; i-- )
        {
          m_BinEncoder.encodeBinEP( ( posX >> i ) & 1 );
        }
      }
      if( GroupIdxY > 3 )
      {
        posY -= g_uiMinInGroup[ GroupIdxY ];
        for ( int i = ( ( GroupIdxY - 2 ) >> 1 ) - 1 ; i >= 0; i-- )
        {
          m_BinEncoder.encodeBinEP( ( posY >> i ) & 1 );
        }
      }
    }
    
    
    
    void CABACWriter::residual_coding_subblock( CoeffCodingContext& cctx, const TCoeff* coeff, const int stateTransTable, int& state )
    {
      //===== init =====
      const int   minSubPos   = cctx.minSubPos();
      const bool  isLast      = cctx.isLast();
      int         firstSigPos = ( isLast ? cctx.scanPosLast() : cctx.maxSubPos() );
      int         nextSigPos  = firstSigPos;
    
      //===== encode significant_coeffgroup_flag =====
      if( !isLast && cctx.isNotFirst() )
      {
        if( cctx.isSigGroup() )
        {
          m_BinEncoder.encodeBin( 1, cctx.sigGroupCtxId() );
        }
        else
        {
          m_BinEncoder.encodeBin( 0, cctx.sigGroupCtxId() );
          return;
        }
      }
    
      uint8_t   ctxOffset[16];
    
      //===== encode absolute values =====
      const int inferSigPos   = nextSigPos != cctx.scanPosLast() ? ( cctx.isNotFirst() ? minSubPos : -1 ) : nextSigPos;
    #if HEVC_USE_SIGN_HIDING
      int       firstNZPos    = nextSigPos;
      int       lastNZPos     = -1;
    #endif
      int       remAbsLevel   = -1;
      int       numNonZero    =  0;
      unsigned  signPattern   =  0;
    
      bool      is2x2subblock = ( cctx.log2CGSize() == 2 );
    
    #if JVET_M0173_MOVE_GT2_TO_FIRST_PASS
      int       remRegBins    = ( is2x2subblock ? MAX_NUM_REG_BINS_2x2SUBBLOCK : MAX_NUM_REG_BINS_4x4SUBBLOCK );
    #else
    
      int       remGt2Bins    = ( is2x2subblock ? MAX_NUM_GT2_BINS_2x2SUBBLOCK : MAX_NUM_GT2_BINS_4x4SUBBLOCK );
      int       remRegBins    = ( is2x2subblock ? MAX_NUM_REG_BINS_2x2SUBBLOCK : MAX_NUM_REG_BINS_4x4SUBBLOCK ) - remGt2Bins;
    
      int       firstPosMode2 = minSubPos - 1;
    
    #if !JVET_M0173_MOVE_GT2_TO_FIRST_PASS
    
      int       firstPosMode1 = minSubPos - 1;
    
    #if JVET_M0173_MOVE_GT2_TO_FIRST_PASS
      for( ; nextSigPos >= minSubPos && remRegBins >= 4; nextSigPos-- )
    #else
    
      for( ; nextSigPos >= minSubPos && remRegBins >= 3; nextSigPos-- )
    
      {
        TCoeff    Coeff      = coeff[ cctx.blockPos( nextSigPos ) ];
        unsigned  sigFlag    = ( Coeff != 0 );
        if( numNonZero || nextSigPos != inferSigPos )
        {
          const unsigned sigCtxId = cctx.sigCtxIdAbs( nextSigPos, coeff, state );
          m_BinEncoder.encodeBin( sigFlag, sigCtxId );
          DTRACE( g_trace_ctx, D_SYNTAX_RESI, "sig_bin() bin=%d ctx=%d\n", sigFlag, sigCtxId );
    
        }
    
        if( sigFlag )
        {
          uint8_t&  ctxOff  = ctxOffset[ nextSigPos - minSubPos ];
          ctxOff            = cctx.ctxOffsetAbs();
          numNonZero++;
    #if HEVC_USE_SIGN_HIDING
          firstNZPos  = nextSigPos;
          lastNZPos   = std::max<int>( lastNZPos, nextSigPos );
    #endif
          remAbsLevel = abs( Coeff ) - 1;
    
          if( nextSigPos != cctx.scanPosLast() ) signPattern <<= 1;
          if( Coeff < 0 )                        signPattern++;
    
    
          unsigned gt1 = !!remAbsLevel;
          m_BinEncoder.encodeBin( gt1, cctx.greater1CtxIdAbs(ctxOff) );
          DTRACE( g_trace_ctx, D_SYNTAX_RESI, "gt1_flag() bin=%d ctx=%d\n", gt1, cctx.greater1CtxIdAbs(ctxOff) );
          remRegBins--;
    
          if( gt1 )
          {
            remAbsLevel  -= 1;
            m_BinEncoder.encodeBin( remAbsLevel&1, cctx.parityCtxIdAbs( ctxOff ) );
            DTRACE( g_trace_ctx, D_SYNTAX_RESI, "par_flag() bin=%d ctx=%d\n", remAbsLevel&1, cctx.parityCtxIdAbs( ctxOff ) );
            remAbsLevel >>= 1;
    
            remRegBins--;
    
    #if JVET_M0173_MOVE_GT2_TO_FIRST_PASS
            unsigned gt2 = !!remAbsLevel;
            m_BinEncoder.encodeBin(gt2, cctx.greater2CtxIdAbs(ctxOff));
            DTRACE(g_trace_ctx, D_SYNTAX_RESI, "gt2_flag() bin=%d ctx=%d\n", gt2, cctx.greater2CtxIdAbs(ctxOff));
            remRegBins--;
    #else
    
            if( remGt2Bins && !--remGt2Bins )
            {
              firstPosMode1 = nextSigPos - 1;
            }
    
        }
    
        state = ( stateTransTable >> ((state<<2)+((Coeff&1)<<1)) ) & 3;
      }
    
    #if !JVET_M0173_MOVE_GT2_TO_FIRST_PASS
    
      firstPosMode1 = ( firstPosMode1 > firstPosMode2 ? firstPosMode1 : firstPosMode2 );
    
    #if !JVET_M0173_MOVE_GT2_TO_FIRST_PASS
    
      //===== 2nd PASS: gt2 =====
      for( int scanPos = firstSigPos; scanPos > firstPosMode1; scanPos-- )
      {
        unsigned absLevel = abs( coeff[ cctx.blockPos( scanPos ) ] );
        if( absLevel >= 2 )
        {
          uint8_t& ctxOff = ctxOffset[ scanPos - minSubPos ];
          unsigned gt2    = ( absLevel >= 4 );
          m_BinEncoder.encodeBin( gt2, cctx.greater2CtxIdAbs(ctxOff) );
          DTRACE( g_trace_ctx, D_SYNTAX_RESI, "gt2_flag() bin=%d ctx=%d\n", gt2, cctx.greater2CtxIdAbs(ctxOff) );
        }
      }
    
    #if JVET_M0173_MOVE_GT2_TO_FIRST_PASS
      //===== 2nd PASS: Go-rice codes =====
      unsigned ricePar = 0;
      for( int scanPos = firstSigPos; scanPos > firstPosMode2; scanPos-- )
    #else
    
      //===== 3rd PASS: Go-rice codes =====
      unsigned ricePar = 0;
      for( int scanPos = firstSigPos; scanPos > firstPosMode1; scanPos-- )
    
      {
        unsigned absLevel = abs( coeff[ cctx.blockPos( scanPos ) ] );
        if( absLevel >= 4 )
        {
          unsigned rem      = ( absLevel - 4 ) >> 1;
          m_BinEncoder.encodeRemAbsEP( rem, ricePar, cctx.extPrec(), cctx.maxLog2TrDRange() );
          DTRACE( g_trace_ctx, D_SYNTAX_RESI, "rem_val() bin=%d ctx=%d\n", rem, ricePar );
          if( ricePar < 3 && rem > (3<<ricePar)-1 )
          {
            ricePar++;
          }
        }
      }
    
    #if !JVET_M0173_MOVE_GT2_TO_FIRST_PASS
    
      for( int scanPos = firstPosMode1; scanPos > firstPosMode2; scanPos-- )
      {
        unsigned absLevel = abs( coeff[ cctx.blockPos( scanPos ) ] );
        if( absLevel >= 2 )
        {
          unsigned rem      = ( absLevel - 2 ) >> 1;
          m_BinEncoder.encodeRemAbsEP( rem, ricePar, cctx.extPrec(), cctx.maxLog2TrDRange() );
          DTRACE( g_trace_ctx, D_SYNTAX_RESI, "rem_val() bin=%d ctx=%d\n", rem, ricePar );
          if( ricePar < 3 && rem > (3<<ricePar)-1 )
          {
            ricePar++;
          }
        }
      }
    
    
      //===== coeff bypass ====
      for( int scanPos = firstPosMode2; scanPos >= minSubPos; scanPos-- )
      {
        TCoeff    Coeff     = coeff[ cctx.blockPos( scanPos ) ];
        unsigned  absLevel  = abs( Coeff );
        int       sumAll    = cctx.templateAbsSum(scanPos, coeff);
        int       rice      = g_auiGoRiceParsCoeff                        [sumAll];
        int       pos0      = g_auiGoRicePosCoeff0[std::max(0, state - 1)][sumAll];
        unsigned  rem       = ( absLevel == 0 ? pos0 : absLevel <= pos0 ? absLevel-1 : absLevel );
        m_BinEncoder.encodeRemAbsEP( rem, rice, cctx.extPrec(), cctx.maxLog2TrDRange() );
        DTRACE( g_trace_ctx, D_SYNTAX_RESI, "rem_val() bin=%d ctx=%d\n", rem, rice );
        state = ( stateTransTable >> ((state<<2)+((absLevel&1)<<1)) ) & 3;
        if( absLevel )
        {
          numNonZero++;
    #if HEVC_USE_SIGN_HIDING
          lastNZPos   = std::max<int>( lastNZPos, scanPos );
    #endif
          signPattern <<= 1;
          if( Coeff < 0 ) signPattern++;
        }
      }
    
    
      //===== encode sign's =====
    #if HEVC_USE_SIGN_HIDING
      unsigned numSigns = numNonZero;
      if( cctx.hideSign( firstNZPos, lastNZPos ) )
      {
        numSigns    --;
        signPattern >>= 1;
      }
      m_BinEncoder.encodeBinsEP( signPattern, numSigns );
    #else
      m_BinEncoder.encodeBinsEP( signPattern, numNonZero );
    #endif
    
    Tung Nguyen's avatar
    Tung Nguyen committed
    #if !JVET_M0464_UNI_MTS
    
    Tung Nguyen's avatar
    Tung Nguyen committed
    #endif
    
    }
    
    
    
    
    
    
    //================================================================================
    //  clause 7.3.8.12
    //--------------------------------------------------------------------------------
    //    void  cross_comp_pred( tu, compID )
    //================================================================================
    
    void CABACWriter::cross_comp_pred( const TransformUnit& tu, ComponentID compID )
    {
      CHECK(!( !isLuma( compID ) ), "Unspecified error");
      signed char alpha   = tu.compAlpha[compID];
      unsigned    ctxBase = ( compID == COMPONENT_Cr ? 5 : 0 );
      if( alpha == 0 )
      {
        m_BinEncoder.encodeBin( 0, Ctx::CrossCompPred( ctxBase ) );
        DTRACE( g_trace_ctx, D_SYNTAX, "cross_comp_pred() etype=%d pos=(%d,%d) alpha=%d\n", compID, tu.blocks[compID].x, tu.blocks[compID].y, tu.compAlpha[compID] );
        return;
      }
    
      static const unsigned log2AbsAlphaMinus1Table[8] = { 0, 1, 1, 2, 2, 2, 3, 3 };
      unsigned sign = ( alpha < 0 );
      if( sign )
      {
        alpha = -alpha;
      }
      CHECK(!( alpha <= 8 ), "Unspecified error");
      m_BinEncoder.encodeBin( 1, Ctx::CrossCompPred(ctxBase) );
      if( alpha > 1)
      {
         m_BinEncoder.encodeBin( 1, Ctx::CrossCompPred(ctxBase+1) );
         unary_max_symbol( log2AbsAlphaMinus1Table[alpha-1]-1, Ctx::CrossCompPred(ctxBase+2), Ctx::CrossCompPred(ctxBase+3), 2 );
      }
      else
      {
         m_BinEncoder.encodeBin( 0, Ctx::CrossCompPred(ctxBase+1) );
      }
      m_BinEncoder.encodeBin( sign, Ctx::CrossCompPred(ctxBase+4) );
    
      DTRACE( g_trace_ctx, D_SYNTAX, "cross_comp_pred() etype=%d pos=(%d,%d) alpha=%d\n", compID, tu.blocks[compID].x, tu.blocks[compID].y, tu.compAlpha[compID] );
    }
    
    
    
    
    //================================================================================
    //  helper functions
    //--------------------------------------------------------------------------------
    //    void  unary_max_symbol  ( symbol, ctxId0, ctxIdN, maxSymbol )
    //    void  unary_max_eqprob  ( symbol,                 maxSymbol )
    //    void  exp_golomb_eqprob ( symbol, count )
    //================================================================================
    
    void CABACWriter::unary_max_symbol( unsigned symbol, unsigned ctxId0, unsigned ctxIdN, unsigned maxSymbol )
    {
      CHECK( symbol > maxSymbol, "symbol > maxSymbol" );
      const unsigned totalBinsToWrite = std::min( symbol + 1, maxSymbol );
      for( unsigned binsWritten = 0; binsWritten < totalBinsToWrite; ++binsWritten )
      {
        const unsigned nextBin = symbol > binsWritten;
        m_BinEncoder.encodeBin( nextBin, binsWritten == 0 ? ctxId0 : ctxIdN );
      }
    }
    
    
    void CABACWriter::unary_max_eqprob( unsigned symbol, unsigned maxSymbol )
    {
      if( maxSymbol == 0 )
      {
        return;
      }
      bool     codeLast = ( maxSymbol > symbol );
      unsigned bins     = 0;
      unsigned numBins  = 0;
      while( symbol-- )
      {
        bins   <<= 1;
        bins   ++;
        numBins++;
      }
      if( codeLast )
      {
        bins  <<= 1;
        numBins++;
      }
      CHECK(!( numBins <= 32 ), "Unspecified error");
      m_BinEncoder.encodeBinsEP( bins, numBins );
    }
    
    
    void CABACWriter::exp_golomb_eqprob( unsigned symbol, unsigned count )
    {
      unsigned bins    = 0;
      unsigned numBins = 0;
      while( symbol >= (unsigned)(1<<count) )
      {
        bins <<= 1;
        bins++;
        numBins++;
        symbol -= 1 << count;
        count++;
      }
      bins <<= 1;
      numBins++;
      bins = (bins << count) | symbol;
      numBins += count;
      CHECK(!( numBins <= 32 ), "Unspecified error");
      m_BinEncoder.encodeBinsEP( bins, numBins );
    }
    
    
    void CABACWriter::encode_sparse_dt( DecisionTree& dt, unsigned toCodeId )
    {
      // propagate the sparsity information from end-nodes to intermediate nodes
      dt.reduce();
    
      unsigned depth  = dt.dtt.depth;
      unsigned offset = 0;
    
      const unsigned encElPos = dt.dtt.mapping[toCodeId];
    
      while( dt.dtt.hasSub[offset] )
      {
        CHECKD( depth == 0, "Depth is '0' for a decision node in a decision tree" );
    
        const unsigned posRight = offset + 1;
        const unsigned posLeft  = offset + ( 1u << depth );
    
        const bool isLeft = encElPos >= posLeft;
    
        if( dt.isAvail[posRight] && dt.isAvail[posLeft] )
        {
          // encode the decision as both sub-paths are available
          const unsigned ctxId = dt.ctxId[offset];
    
          if( ctxId > 0 )
          {
            DTRACE( g_trace_ctx, D_DECISIONTREE, "Decision coding using context %d\n", ctxId - 1 );
            m_BinEncoder.encodeBin( isLeft ? 0 : 1, ctxId - 1 );
          }
          else
          {
            DTRACE( g_trace_ctx, D_DECISIONTREE, "Decision coding as an EP bin\n" );
            m_BinEncoder.encodeBinEP( isLeft ? 0 : 1 );
          }
        }
    
        DTRACE( g_trace_ctx, D_DECISIONTREE, "Following the tree to the %s sub-node\n", isLeft ? "left" : "right" );
    
        offset = isLeft ? posLeft : posRight;
        depth--;
      }
    
      CHECKD( offset != encElPos,             "Encoded a different element than assigned" );
      CHECKD( dt.dtt.ids[offset] != toCodeId, "Encoded a different element than assigned" );
      CHECKD( dt.isAvail[offset] == false,    "The encoded element is not available" );
      DTRACE( g_trace_ctx, D_DECISIONTREE,    "Found an end-node of the tree\n" );
      return;
    }
    
    
    void CABACWriter::codeAlfCtuEnableFlags( CodingStructure& cs, ChannelType channel, AlfSliceParam* alfParam)
    {
      if( isLuma( channel ) )
      {
        if (alfParam->enabledFlag[COMPONENT_Y])
          codeAlfCtuEnableFlags( cs, COMPONENT_Y, alfParam );
      }
      else
      {
        if (alfParam->enabledFlag[COMPONENT_Cb])
          codeAlfCtuEnableFlags( cs, COMPONENT_Cb, alfParam );
        if (alfParam->enabledFlag[COMPONENT_Cr])
          codeAlfCtuEnableFlags( cs, COMPONENT_Cr, alfParam );
      }
    }
    void CABACWriter::codeAlfCtuEnableFlags( CodingStructure& cs, ComponentID compID, AlfSliceParam* alfParam)
    {
      uint32_t numCTUs = cs.pcv->sizeInCtus;
    
      for( int ctuIdx = 0; ctuIdx < numCTUs; ctuIdx++ )
      {
        codeAlfCtuEnableFlag( cs, ctuIdx, compID, alfParam );
      }
    }
    
    void CABACWriter::codeAlfCtuEnableFlag( CodingStructure& cs, uint32_t ctuRsAddr, const int compIdx, AlfSliceParam* alfParam)
    {
      AlfSliceParam& alfSliceParam = alfParam ? (*alfParam) : cs.slice->getAlfSliceParam();
    
    
      if( cs.sps->getALFEnabledFlag() && alfSliceParam.enabledFlag[compIdx] )
    
      {
        const PreCalcValues& pcv = *cs.pcv;
        int                 frame_width_in_ctus = pcv.widthInCtus;
        int                 ry = ctuRsAddr / frame_width_in_ctus;
        int                 rx = ctuRsAddr - ry * frame_width_in_ctus;
        const Position      pos( rx * cs.pcv->maxCUWidth, ry * cs.pcv->maxCUHeight );
        const uint32_t          curSliceIdx = cs.slice->getIndependentSliceIdx();
    #if HEVC_TILES_WPP
        const uint32_t          curTileIdx = cs.picture->tileMap->getTileIdxMap( pos );
    
    Karsten Suehring's avatar
    Karsten Suehring committed
        bool                leftAvail = cs.getCURestricted( pos.offset( -(int)pcv.maxCUWidth, 0 ), curSliceIdx, curTileIdx, CH_L ) ? true : false;
        bool                aboveAvail = cs.getCURestricted( pos.offset( 0, -(int)pcv.maxCUHeight ), curSliceIdx, curTileIdx, CH_L ) ? true : false;
    
    #else
        bool                leftAvail = cs.getCURestricted( pos.offset( -(int)pcv.maxCUWidth, 0 ), curSliceIdx, CH_L ) ? true : false;
        bool                aboveAvail = cs.getCURestricted( pos.offset( 0, -(int)pcv.maxCUHeight ), curSliceIdx, CH_L ) ? true : false;
    #endif
    
        int leftCTUAddr = leftAvail ? ctuRsAddr - 1 : -1;
        int aboveCTUAddr = aboveAvail ? ctuRsAddr - frame_width_in_ctus : -1;
    
        if( alfSliceParam.enabledFlag[compIdx] )
        {
          uint8_t* ctbAlfFlag = cs.slice->getPic()->getAlfCtuEnableFlag( compIdx );
    
          int ctx = 0;
          ctx += leftCTUAddr > -1 ? ( ctbAlfFlag[leftCTUAddr] ? 1 : 0 ) : 0;
          ctx += aboveCTUAddr > -1 ? ( ctbAlfFlag[aboveCTUAddr] ? 1 : 0 ) : 0;
          m_BinEncoder.encodeBin( ctbAlfFlag[ctuRsAddr], Ctx::ctbAlfFlag( compIdx * 3 + ctx ) );