Skip to content
Snippets Groups Projects
CABACWriter.cpp 112 KiB
Newer Older
  • Learn to ignore specific revisions
  • Frank Bossen's avatar
    Frank Bossen committed
            unsigned &riceStats = m_binEncoder.getCtx().getGRAdaptStats((unsigned) (cctx.compID()));
    
            cctx.updateRiceStat(riceStats, rem, 1);
            cctx.setUpdateHist(0);
            updateHistory = 0;
          }
    
      for (int scanPos = minPos2ndPass; scanPos >= minSubPos; scanPos--)
    
    Frank Bossen's avatar
    Frank Bossen committed
        TCoeff      coeffVal  = coeff[cctx.blockPos(scanPos)];
        unsigned    absLevel  = (unsigned) abs(coeffVal);
    
        int rice = (cctx.*(cctx.deriveRiceRRC))(scanPos, coeff, 0);
    
    Frank Bossen's avatar
    Frank Bossen committed
        int         pos0      = g_goRicePosCoeff0(state, rice);
    
        unsigned  rem       = ( absLevel == 0 ? pos0 : absLevel <= pos0 ? absLevel-1 : absLevel );
    
    Frank Bossen's avatar
    Frank Bossen committed
        m_binEncoder.encodeRemAbsEP(rem, rice, COEF_REMAIN_BIN_REDUCTION, 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 ((updateHistory) && (rem > 0))
        {
    
    Frank Bossen's avatar
    Frank Bossen committed
          unsigned &riceStats = m_binEncoder.getCtx().getGRAdaptStats((unsigned) cctx.compID());
    
          cctx.updateRiceStat(riceStats, rem, 0);
          cctx.setUpdateHist(0);
          updateHistory = 0;
        }
    
          lastNZPos   = std::max<int>( lastNZPos, scanPos );
          signPattern <<= 1;
    
    Frank Bossen's avatar
    Frank Bossen committed
          if (coeffVal < 0)
    
          {
            signPattern++;
          }
    
    
      //===== encode sign's =====
      unsigned numSigns = numNonZero;
      if( cctx.hideSign( firstNZPos, lastNZPos ) )
      {
        numSigns    --;
        signPattern >>= 1;
      }
    
    Frank Bossen's avatar
    Frank Bossen committed
      m_binEncoder.encodeBinsEP(signPattern, numSigns);
    
    void CABACWriter::residual_codingTS( const TransformUnit& tu, ComponentID compID )
    {
      DTRACE( g_trace_ctx, D_SYNTAX, "residual_codingTS() etype=%d pos=(%d,%d) size=%dx%d\n", tu.blocks[compID].compID, tu.blocks[compID].x, tu.blocks[compID].y, tu.blocks[compID].width, tu.blocks[compID].height );
    
      // init coeff coding context
    
      CoeffCodingContext  cctx    ( tu, compID, false, isLuma(compID) ? tu.cu->bdpcmMode : tu.cu->bdpcmModeChroma);
    
      const TCoeff*       coeff   = tu.getCoeffs( compID ).buf;
    
      int maxCtxBins = (cctx.maxNumCoeff() * 7) >> 2;
      cctx.setNumCtxBins(maxCtxBins);
    
    
      // determine and set last coeff position and sig group flags
      std::bitset<MLS_GRP_NUM> sigGroupFlags;
      for( int scanPos = 0; scanPos < cctx.maxNumCoeff(); scanPos++)
      {
        unsigned blkPos = cctx.blockPos( scanPos );
        if( coeff[blkPos] )
        {
          sigGroupFlags.set( scanPos >> cctx.log2CGSize() );
        }
      }
    
      // code subblocks
      for( int subSetId = 0; subSetId <= ( cctx.maxNumCoeff() - 1 ) >> cctx.log2CGSize(); subSetId++ )
      {
        cctx.initSubblock         ( subSetId, sigGroupFlags[subSetId] );
    
        int goRiceParam = 1;
        bool ricePresentFlag = false;
        unsigned RiceBit[8]   = { 0, 0, 0, 0, 0, 0, 0, 0 };
    
        if (tu.cu->slice->getSPS()->getSpsRangeExtension().getTSRCRicePresentFlag() && tu.mtsIdx[compID] == MtsType::SKIP)
    
    Frank Bossen's avatar
    Frank Bossen committed
          goRiceParam = goRiceParam + tu.cu->slice->getTsrcIndex();
    
          if (isEncoding())
          {
            ricePresentFlag = true;
            for (int i = 0; i < MAX_TSRC_RICE; i++)
            {
              RiceBit[i] = tu.cu->slice->getRiceBit(i);
            }
          }
        }
        residual_coding_subblockTS( cctx, coeff, RiceBit, goRiceParam, ricePresentFlag);
    
        if (tu.cu->slice->getSPS()->getSpsRangeExtension().getTSRCRicePresentFlag() && tu.mtsIdx[compID] == MtsType::SKIP
            && isEncoding())
    
        {
          for (int i = 0; i < MAX_TSRC_RICE; i++)
          {
            tu.cu->slice->setRiceBit(i, RiceBit[i]);
          }
        }
    
    void CABACWriter::residual_coding_subblockTS(CoeffCodingContext &cctx, const TCoeff *coeff, unsigned (&RiceBit)[8],
                                                 const int riceParam, bool ricePresentFlag)
    
    {
      //===== init =====
      const int   minSubPos   = cctx.maxSubPos();
      int         firstSigPos = cctx.minSubPos();
      int         nextSigPos  = firstSigPos;
    
      //===== encode significant_coeffgroup_flag =====
      if( !cctx.isLastSubSet() || !cctx.only1stSigGroup() )
      {
        if( cctx.isSigGroup() )
        {
    
    Frank Bossen's avatar
    Frank Bossen committed
          m_binEncoder.encodeBin(1, cctx.sigGroupCtxId(true));
    
          DTRACE(g_trace_ctx, D_SYNTAX_RESI, "ts_sigGroup() bin=%d ctx=%d\n", 1, cctx.sigGroupCtxId());
    
    Frank Bossen's avatar
    Frank Bossen committed
          m_binEncoder.encodeBin(0, cctx.sigGroupCtxId(true));
    
          DTRACE(g_trace_ctx, D_SYNTAX_RESI, "ts_sigGroup() bin=%d ctx=%d\n", 0, cctx.sigGroupCtxId());
    
          return;
        }
      }
    
      //===== encode absolute values =====
      const int inferSigPos   = minSubPos;
      int       remAbsLevel   = -1;
      int       numNonZero    =  0;
    
    
      int rightPixel, belowPixel, modAbsCoeff;
    
    
      int lastScanPosPass1 = -1;
      int lastScanPosPass2 = -1;
      for (; nextSigPos <= minSubPos && cctx.numCtxBins() >= 4; nextSigPos++)
    
    Frank Bossen's avatar
    Frank Bossen committed
        TCoeff   coeffVal = coeff[cctx.blockPos(nextSigPos)];
        unsigned sigFlag  = (coeffVal != 0);
    
        if( numNonZero || nextSigPos != inferSigPos )
        {
    
          const unsigned sigCtxId = cctx.sigCtxIdAbsTS(nextSigPos, coeff);
    
    Frank Bossen's avatar
    Frank Bossen committed
          m_binEncoder.encodeBin(sigFlag, sigCtxId);
    
          DTRACE(g_trace_ctx, D_SYNTAX_RESI, "ts_sig_bin() bin=%d ctx=%d\n", sigFlag, sigCtxId);
          cctx.decimateNumCtxBins(1);
    
        }
    
        if( sigFlag )
        {
          //===== encode sign's =====
    
    Frank Bossen's avatar
    Frank Bossen committed
          int            sign      = coeffVal < 0;
    
          const unsigned signCtxId = cctx.signCtxIdAbsTS(nextSigPos, coeff, cctx.bdpcm());
    
    Frank Bossen's avatar
    Frank Bossen committed
          m_binEncoder.encodeBin(sign, signCtxId);
    
          cctx.decimateNumCtxBins(1);
    
          cctx.neighTS(rightPixel, belowPixel, nextSigPos, coeff);
    
          modAbsCoeff = cctx.deriveModCoeff(rightPixel, belowPixel, abs(coeffVal), cctx.bdpcm() != BdpcmMode::NONE);
    
    
          unsigned gt1 = !!remAbsLevel;
    
          const unsigned gt1CtxId = cctx.lrg1CtxIdAbsTS(nextSigPos, coeff, cctx.bdpcm());
    
    Frank Bossen's avatar
    Frank Bossen committed
          m_binEncoder.encodeBin(gt1, gt1CtxId);
    
          DTRACE(g_trace_ctx, D_SYNTAX_RESI, "ts_gt1_flag() bin=%d ctx=%d\n", gt1, gt1CtxId);
          cctx.decimateNumCtxBins(1);
    
    Frank Bossen's avatar
    Frank Bossen committed
            m_binEncoder.encodeBin(remAbsLevel & 1, cctx.parityCtxIdAbsTS());
            DTRACE(g_trace_ctx, D_SYNTAX_RESI, "ts_par_flag() bin=%d ctx=%d\n", remAbsLevel & 1, cctx.parityCtxIdAbsTS());
            cctx.decimateNumCtxBins(1);
    
        lastScanPosPass1 = nextSigPos;
    
      }
    
      int cutoffVal = 2;
      int numGtBins = 4;
    
      for (int scanPos = firstSigPos; scanPos <= minSubPos && cctx.numCtxBins() >= 4; scanPos++)
    
        unsigned absLevel;
        cctx.neighTS(rightPixel, belowPixel, scanPos, coeff);
    
        absLevel =
          cctx.deriveModCoeff(rightPixel, belowPixel, abs(coeff[cctx.blockPos(scanPos)]), cctx.bdpcm() != BdpcmMode::NONE);
    
        cutoffVal = 2;
        for (int i = 0; i < numGtBins; i++)
        {
          if (absLevel >= cutoffVal)
          {
            unsigned gt2 = (absLevel >= (cutoffVal + 2));
    
    Frank Bossen's avatar
    Frank Bossen committed
            m_binEncoder.encodeBin(gt2, cctx.greaterXCtxIdAbsTS(cutoffVal >> 1));
            DTRACE(g_trace_ctx, D_SYNTAX_RESI, "ts_gt%d_flag() bin=%d ctx=%d sp=%d coeff=%d\n", i, gt2,
                   cctx.greaterXCtxIdAbsTS(cutoffVal >> 1), scanPos, std::min<int>(absLevel, cutoffVal + 2));
            cctx.decimateNumCtxBins(1);
    
        lastScanPosPass2 = scanPos;
    
    
      //===== coeff bypass ====
      for( int scanPos = firstSigPos; scanPos <= minSubPos; scanPos++ )
      {
    
        unsigned absLevel;
        cctx.neighTS(rightPixel, belowPixel, scanPos, coeff);
    
    Kato Yusuke's avatar
    Kato Yusuke committed
        cutoffVal = (scanPos <= lastScanPosPass2 ? 10 : (scanPos <= lastScanPosPass1 ? 2 : 0));
    
        absLevel  = cctx.deriveModCoeff(rightPixel, belowPixel, abs(coeff[cctx.blockPos(scanPos)]),
                                        cctx.bdpcm() != BdpcmMode::NONE || cutoffVal == 0);
    
    Kato Yusuke's avatar
    Kato Yusuke committed
    
    
        if( absLevel >= cutoffVal )
        {
    
          unsigned  rem = scanPos <= lastScanPosPass1 ? (absLevel - cutoffVal) >> 1 : absLevel;
    
          m_binEncoder.encodeRemAbsEP(rem, riceParam, COEF_REMAIN_BIN_REDUCTION, cctx.maxLog2TrDRange());
          DTRACE(g_trace_ctx, D_SYNTAX_RESI, "ts_rem_val() bin=%d ctx=%d sp=%d\n", rem, riceParam, scanPos);
    
          if ( ricePresentFlag && (isEncoding()) && (cctx.compID() == COMPONENT_Y))
          {
            for (int idx = 1; idx < 9; idx++)
            {
              uint32_t length;
              uint32_t symbol = rem;
              if (rem < (5 << idx))
              {
                length = rem >> idx;
                RiceBit[idx - 1] += (length + 1 + idx);
              }
              else
              {
                length = idx;
                symbol = symbol - (5 << idx);
                while (symbol >= (1 << length))
                {
                  symbol -= (1 << (length++));
                }
                RiceBit[idx - 1] += (5 + length + 1 - idx + length);
              }
            }
          }
    
    
          if (absLevel && scanPos > lastScanPosPass1)
          {
    
            const int sign = coeff[cctx.blockPos(scanPos)] < 0 ? 1 : 0;
    
    Frank Bossen's avatar
    Frank Bossen committed
            m_binEncoder.encodeBinEP(sign);
    
    
    //================================================================================
    //  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;
    
    Frank Bossen's avatar
    Frank Bossen committed
        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");
    
    Frank Bossen's avatar
    Frank Bossen committed
      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++;
    
      //CHECK(!( numBins + count <= 32 ), "Unspecified error");
    
    Frank Bossen's avatar
    Frank Bossen committed
      m_binEncoder.encodeBinsEP(bins, numBins);
      m_binEncoder.encodeBinsEP(symbol, count);
    
    void CABACWriter::codeAlfCtuEnableFlags( CodingStructure& cs, ChannelType channel, AlfParam* alfParam)
    
    {
      if( isLuma( channel ) )
      {
        if (alfParam->enabledFlag[COMPONENT_Y])
    
          codeAlfCtuEnableFlags( cs, COMPONENT_Y, alfParam );
    
          codeAlfCtuEnableFlags( cs, COMPONENT_Cb, alfParam );
    
          codeAlfCtuEnableFlags( cs, COMPONENT_Cr, alfParam );
    
    void CABACWriter::codeAlfCtuEnableFlags( CodingStructure& cs, ComponentID compID, AlfParam* 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, AlfParam* alfParam)
    
      const bool alfComponentEnabled =
        (alfParam != nullptr) ? alfParam->enabledFlag[compIdx] : cs.slice->getAlfEnabledFlag((ComponentID) compIdx);
    
    Karsten Suehring's avatar
    Karsten Suehring committed
      if( cs.sps->getALFEnabledFlag() && alfComponentEnabled )
    
    
        const int frameWidthInCtus = pcv.widthInCtus;
    
        const int ry = ctuRsAddr / frameWidthInCtus;
        const int rx = ctuRsAddr - ry * frameWidthInCtus;
    
        const Position pos(rx * cs.pcv->maxCUWidth, ry * cs.pcv->maxCUHeight);
    
        const uint32_t curSliceIdx = cs.slice->getIndependentSliceIdx();
    
        const TileIdx  curTileIdx  = cs.pps->getTileIdx(pos);
    
    
        const bool leftAvail =
    
          cs.getCURestricted(pos.offset(-(int) pcv.maxCUWidth, 0), pos, curSliceIdx, curTileIdx, ChannelType::LUMA)
          != nullptr;
    
        const bool aboveAvail =
    
          cs.getCURestricted(pos.offset(0, -(int) pcv.maxCUHeight), pos, curSliceIdx, curTileIdx, ChannelType::LUMA)
          != nullptr;
    
    
        const int leftCTUAddr  = leftAvail ? ctuRsAddr - 1 : -1;
        const int aboveCTUAddr = aboveAvail ? ctuRsAddr - frameWidthInCtus : -1;
    
        AlfMode *alfModes = cs.slice->getPic()->getAlfModes(compIdx);
    
    Karsten Suehring's avatar
    Karsten Suehring committed
        int ctx = 0;
    
        ctx += leftCTUAddr > -1 ? (alfModes[leftCTUAddr] != AlfMode::OFF ? 1 : 0) : 0;
        ctx += aboveCTUAddr > -1 ? (alfModes[aboveCTUAddr] != AlfMode::OFF ? 1 : 0) : 0;
        m_binEncoder.encodeBin(alfModes[ctuRsAddr] != AlfMode::OFF, Ctx::alfCtbFlag(compIdx * 3 + ctx));
    
    void CABACWriter::codeCcAlfFilterControlIdc(uint8_t idcVal, CodingStructure &cs, const ComponentID compID,
                                                const int curIdx, const uint8_t *filterControlIdc, Position lumaPos,
                                                const int filterCount)
    {
      CHECK(idcVal > filterCount, "Filter index is too large");
    
      const uint32_t curSliceIdx    = cs.slice->getIndependentSliceIdx();
    
      const TileIdx  curTileIdx     = cs.pps->getTileIdx( lumaPos );
    
      Position       leftLumaPos    = lumaPos.offset(-(int)cs.pcv->maxCUWidth, 0);
      Position       aboveLumaPos   = lumaPos.offset(0, -(int)cs.pcv->maxCUWidth);
    
      bool leftAvail = cs.getCURestricted(leftLumaPos, lumaPos, curSliceIdx, curTileIdx, ChannelType::LUMA) ? true : false;
      bool aboveAvail =
        cs.getCURestricted(aboveLumaPos, lumaPos, curSliceIdx, curTileIdx, ChannelType::LUMA) ? true : false;
    
      int            ctxt           = 0;
    
      if (leftAvail)
      {
        ctxt += ( filterControlIdc[curIdx - 1]) ? 1 : 0;
      }
      if (aboveAvail)
      {
        ctxt += (filterControlIdc[curIdx - cs.pcv->widthInCtus]) ? 1 : 0;
      }
      ctxt += ( compID == COMPONENT_Cr ) ? 3 : 0;
    
    
    Frank Bossen's avatar
    Frank Bossen committed
      m_binEncoder.encodeBin((idcVal == 0) ? 0 : 1, Ctx::CcAlfFilterControlFlag(ctxt));   // ON/OFF flag is context coded
    
      if ( idcVal > 0 )
      {
        int val = (idcVal - 1);
        while ( val )
        {
    
    Frank Bossen's avatar
    Frank Bossen committed
          m_binEncoder.encodeBinEP(1);
    
          val--;
        }
        if ( idcVal < filterCount )
        {
    
    Frank Bossen's avatar
    Frank Bossen committed
          m_binEncoder.encodeBinEP(0);
    
        }
      }
      DTRACE( g_trace_ctx, D_SYNTAX, "ccAlfFilterControlIdc() compID=%d pos=(%d,%d) ctxt=%d, filterCount=%d, idcVal=%d\n", compID, lumaPos.x, lumaPos.y, ctxt, filterCount, idcVal );
    }
    
    
    void CABACWriter::mip_flag( const CodingUnit& cu )
    {
      if( !cu.Y().valid() )
      {
        return;
      }
      if( !cu.cs->sps->getUseMIP() )
      {
        return;
      }
    
      unsigned ctxId = DeriveCtx::CtxMipFlag( cu );
    
    Frank Bossen's avatar
    Frank Bossen committed
      m_binEncoder.encodeBin(cu.mipFlag, Ctx::MipFlag(ctxId));
    
      DTRACE( g_trace_ctx, D_SYNTAX, "mip_flag() pos=(%d,%d) mode=%d\n", cu.lumaPos().x, cu.lumaPos().y, cu.mipFlag ? 1 : 0 );
    }
    
    void CABACWriter::mip_pred_modes( const CodingUnit& cu )
    {
      if( !cu.Y().valid() )
      {
        return;
      }
      for( const auto &pu : CU::traversePUs( cu ) )
      {
        mip_pred_mode( pu );
      }
    }
    
    void CABACWriter::mip_pred_mode( const PredictionUnit& pu )
    {
    
    Frank Bossen's avatar
    Frank Bossen committed
      m_binEncoder.encodeBinEP((pu.mipTransposedFlag ? 1 : 0));
    
      const int numModes = MatrixIntraPrediction::getNumModesMip(pu.Y());
    
      CHECKD(pu.intraDir[ChannelType::LUMA] < 0 || pu.intraDir[ChannelType::LUMA] >= numModes, "Invalid MIP mode");
      xWriteTruncBinCode(pu.intraDir[ChannelType::LUMA], numModes);
    
      DTRACE(g_trace_ctx, D_SYNTAX, "mip_pred_mode() pos=(%d,%d) mode=%d transposed=%d\n", pu.lumaPos().x, pu.lumaPos().y,
             pu.intraDir[ChannelType::LUMA], pu.mipTransposedFlag ? 1 : 0);
    
    Karsten Suehring's avatar
    Karsten Suehring committed
    void CABACWriter::codeAlfCtuFilterIndex(CodingStructure& cs, uint32_t ctuRsAddr, bool alfEnableLuma)
    
      if (!cs.sps->getALFEnabledFlag() || !alfEnableLuma)
    
      AlfMode *alfModes = cs.slice->getPic()->getAlfModes(COMPONENT_Y);
    
      AlfMode m = alfModes[ctuRsAddr];
      if (m == AlfMode::OFF)
    
      const int numAps = cs.slice->getNumAlfApsIdsLuma();
    
      const bool alfUseApsFlag = !isAlfLumaFixed(m);
    
      if (numAps > 0)
    
        m_binEncoder.encodeBin(alfUseApsFlag ? 1 : 0, Ctx::alfUseApsFlag());
      }
      if (alfUseApsFlag)
      {
        const uint32_t alfLumaPrevFilterIdx = m - AlfMode::LUMA0;
        CHECK(alfLumaPrevFilterIdx >= numAps, "alfLumaPrevFilterIdx is too large");
    
        if (numAps > 1)
    
          xWriteTruncBinCode(alfLumaPrevFilterIdx, numAps);
    
        const uint32_t alfLumaFixedFilterIdx = m - AlfMode::LUMA_FIXED0;
    
        xWriteTruncBinCode(alfLumaFixedFilterIdx, ALF_NUM_FIXED_FILTER_SETS);
    
    void CABACWriter::codeAlfCtuAlternatives( CodingStructure& cs, ChannelType channel, AlfParam* alfParam)
    {
      if( isChroma( channel ) )
      {
        if (alfParam->enabledFlag[COMPONENT_Cb])
    
          codeAlfCtuAlternatives( cs, COMPONENT_Cb, alfParam );
    
        if (alfParam->enabledFlag[COMPONENT_Cr])
    
          codeAlfCtuAlternatives( cs, COMPONENT_Cr, alfParam );
    
    void CABACWriter::codeAlfCtuAlternatives( CodingStructure& cs, ComponentID compID, AlfParam* alfParam)
    {
      if( compID == COMPONENT_Y )
    
      uint32_t numCTUs = cs.pcv->sizeInCtus;
    
      AlfMode *alfModes = cs.slice->getPic()->getAlfModes(compID);
    
    
      for( int ctuIdx = 0; ctuIdx < numCTUs; ctuIdx++ )
      {
    
        if (alfModes[ctuIdx] != AlfMode::OFF)
    
        {
          codeAlfCtuAlternative( cs, ctuIdx, compID, alfParam );
        }
      }
    }
    
    void CABACWriter::codeAlfCtuAlternative( CodingStructure& cs, uint32_t ctuRsAddr, const int compIdx, const AlfParam* alfParam)
    {
      if( compIdx == COMPONENT_Y )
    
      int apsIdx = alfParam ? 0 : cs.slice->getAlfApsIdChroma();
    
      const AlfParam& alfParamRef = alfParam ? (*alfParam) : cs.slice->getAlfAPSs()[apsIdx]->getAlfAPSParam();
    
    
      if( alfParam || (cs.sps->getALFEnabledFlag() && cs.slice->getAlfEnabledFlag( (ComponentID)compIdx )) )
    
        AlfMode *alfModes = cs.slice->getPic()->getAlfModes(compIdx);
    
        if (alfModes[ctuRsAddr] != AlfMode::OFF)
    
        {
          const int numAlts = alfParamRef.numAlternativesChroma;
    
          const int numOnes = alfModes[ctuRsAddr] - AlfMode::CHROMA0;
          CHECK(numOnes >= numAlts, "Invalid ALF mode");
    
    Frank Bossen's avatar
    Frank Bossen committed
            m_binEncoder.encodeBin(1, Ctx::ctbAlfAlternative(compIdx - 1));
    
    Frank Bossen's avatar
    Frank Bossen committed
            m_binEncoder.encodeBin(0, Ctx::ctbAlfAlternative(compIdx - 1));