Skip to content
Snippets Groups Projects
CABACWriter.cpp 123 KiB
Newer Older
  • Learn to ignore specific revisions
  • Liang Zhao's avatar
    Liang Zhao committed
    #if !ENABLE_JVET_L0283_MRL
      return;
    #endif
    
    
      if ( !cu.Y().valid() || cu.predMode != MODE_INTRA || !isLuma(cu.chType) || cu.ipcm || cu.bdpcmMode )
    
      {
        return;
      }
    
      const int numBlocks = CU::getNumPUs(cu);
      const PredictionUnit* pu = cu.firstPU;
    
      for (int k = 0; k < numBlocks; k++)
      {
        bool isFirstLineOfCtu = (((cu.block(COMPONENT_Y).y)&((cu.cs->sps)->getMaxCUWidth() - 1)) == 0);
        if (isFirstLineOfCtu)
        {
          return;
        }
        int multiRefIdx = pu->multiRefIdx;
        if (MRL_NUM_REF_LINES > 1)
        {
          m_BinEncoder.encodeBin(multiRefIdx != MULTI_REF_LINE_IDX[0], Ctx::MultiRefLineIdx(0));
          if (MRL_NUM_REF_LINES > 2 && multiRefIdx != MULTI_REF_LINE_IDX[0])
          {
            m_BinEncoder.encodeBin(multiRefIdx != MULTI_REF_LINE_IDX[1], Ctx::MultiRefLineIdx(1));
          }
    
        }
        pu = pu->next;
      }
    }
    
    
    void CABACWriter::intra_luma_pred_modes( const CodingUnit& cu )
    {
      if( !cu.Y().valid() )
      {
        return;
      }
    
    
      if( cu.bdpcmMode )
      {
    
    #if JVET_O0315_RDPCM_INTRAMODE_ALIGN
        cu.firstPU->intraDir[0] = cu.bdpcmMode == 2? VER_IDX : HOR_IDX;
    #else
    
        PredictionUnit *pu = cu.firstPU;
        unsigned mpm_pred[NUM_MOST_PROBABLE_MODES];
        PU::getIntraMPMs( *pu, mpm_pred );
        cu.firstPU->intraDir[0] = mpm_pred[0];
    
      mip_flag(cu);
      if (cu.mipFlag)
      {
        mip_pred_modes(cu);
        return;
      }
      extend_ref_line( cu );
    
      isp_mode( cu );
    
    
      const int numMPMs   = NUM_MOST_PROBABLE_MODES;
      const int numBlocks = CU::getNumPUs( cu );
      unsigned  mpm_preds   [4][numMPMs];
      unsigned  mpm_idxs    [4];
      unsigned  ipred_modes [4];
    
    
      const PredictionUnit* pu = cu.firstPU;
    
      // prev_intra_luma_pred_flag
      for( int k = 0; k < numBlocks; k++ )
      {
    
        unsigned*  mpm_pred   = mpm_preds[k];
    
        unsigned&  mpm_idx    = mpm_idxs[k];
        unsigned&  ipred_mode = ipred_modes[k];
    
        PU::getIntraMPMs( *pu, mpm_pred );
    
        ipred_mode = pu->intraDir[0];
        mpm_idx    = numMPMs;
        for( unsigned idx = 0; idx < numMPMs; idx++ )
        {
          if( ipred_mode == mpm_pred[idx] )
          {
            mpm_idx = idx;
            break;
          }
        }
    
        if( pu->multiRefIdx || ( cu.ispMode && isLuma( cu.chType ) ) )
    
        {
          CHECK(mpm_idx >= numMPMs, "use of non-MPM");
        }
        else
    
    Frank Bossen's avatar
    Frank Bossen committed
        {
          m_BinEncoder.encodeBin(mpm_idx < numMPMs, Ctx::IntraLumaMpmFlag());
        }
    
    
        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 )
        {
          {
    
            unsigned ctx = (pu->cu->ispMode == NOT_INTRA_SUBPARTITIONS ? 1 : 0);
            if (pu->multiRefIdx == 0)
    
              m_BinEncoder.encodeBin(mpm_idx > 0, Ctx::IntraLumaPlanarFlag(ctx));
    
    ling's avatar
    ling committed
            if (mpm_idx > 1)
            {
              m_BinEncoder.encodeBinEP(mpm_idx > 2);
            }
            if (mpm_idx > 2)
            {
              m_BinEncoder.encodeBinEP(mpm_idx > 3);
            }
            if (mpm_idx > 3)
            {
              m_BinEncoder.encodeBinEP(mpm_idx > 4);
            }
    
          }
        }
        else
        {
          unsigned* mpm_pred   = mpm_preds[k];
          unsigned  ipred_mode = ipred_modes[k];
    
          // sorting of MPMs
          std::sort( mpm_pred, mpm_pred + numMPMs );
    
          {
    
            for (int idx = numMPMs - 1; idx >= 0; idx--)
    
            {
              if (ipred_mode > mpm_pred[idx])
              {
                ipred_mode--;
              }
            }
            CHECK(ipred_mode >= 64, "Incorrect mode");
    
    ling's avatar
    ling committed
            xWriteTruncBinCode(ipred_mode, NUM_LUMA_MODE - NUM_MOST_PROBABLE_MODES);  // Remaining mode is truncated binary coded
    
          }
        }
    
        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::intra_luma_pred_mode( const PredictionUnit& pu )
    {
    
    
      if( pu.cu->bdpcmMode ) return;
    
      mip_flag(*pu.cu);
      if (pu.cu->mipFlag)
      {
        mip_pred_mode(pu);
        return;
      }
      extend_ref_line( pu );
    
      isp_mode( *pu.cu );
    
    
      const int numMPMs  = NUM_MOST_PROBABLE_MODES;
      unsigned  mpm_pred[numMPMs];
    
      PU::getIntraMPMs( pu, mpm_pred );
    
      unsigned ipred_mode = pu.intraDir[0];
      unsigned mpm_idx = numMPMs;
    
    
      for( int idx = 0; idx < numMPMs; idx++ )
    
      if( pu.multiRefIdx || ( pu.cu->ispMode && isLuma( pu.cu->chType ) ) )
    
      {
        CHECK(mpm_idx >= numMPMs, "use of non-MPM");
      }
      else
    
    Frank Bossen's avatar
    Frank Bossen committed
      {
        m_BinEncoder.encodeBin(mpm_idx < numMPMs, Ctx::IntraLumaMpmFlag());
      }
    
    
      // mpm_idx / rem_intra_luma_pred_mode
      if( mpm_idx < numMPMs )
      {
        {
    
          unsigned ctx = (pu.cu->ispMode == NOT_INTRA_SUBPARTITIONS ? 1 : 0);
          if (pu.multiRefIdx == 0)
    
            m_BinEncoder.encodeBin( mpm_idx > 0, Ctx::IntraLumaPlanarFlag(ctx) );
    
    ling's avatar
    ling committed
          if (mpm_idx > 1)
          {
            m_BinEncoder.encodeBinEP(mpm_idx > 2);
          }
          if (mpm_idx > 2)
          {
            m_BinEncoder.encodeBinEP(mpm_idx > 3);
          }
          if (mpm_idx > 3)
          {
            m_BinEncoder.encodeBinEP(mpm_idx > 4);
          }
    
          for (int idx = numMPMs - 1; idx >= 0; idx--)
    
    ling's avatar
    ling committed
          xWriteTruncBinCode(ipred_mode, NUM_LUMA_MODE - NUM_MOST_PROBABLE_MODES);  // Remaining mode is truncated binary coded
    
        }
      }
    }
    
    
    void CABACWriter::intra_chroma_pred_modes( const CodingUnit& cu )
    {
      if( cu.chromaFormat == CHROMA_400 || ( CS::isDualITree( *cu.cs ) && cu.chType == CHANNEL_TYPE_LUMA ) )
      {
        return;
      }
    
      const PredictionUnit* pu = cu.firstPU;
    
      intra_chroma_pred_mode( *pu );
    }
    
    void CABACWriter::intra_chroma_lmc_mode( const PredictionUnit& pu )
    {
      const unsigned intraDir = pu.intraDir[1];
        int lmModeList[10];
        int maxSymbol = PU::getLMSymbolList( pu, lmModeList );
        int symbol    = -1;
        for ( int k = 0; k < LM_SYMBOL_NUM; k++ )
        {
          if ( lmModeList[k] == intraDir || ( lmModeList[k] == -1 && intraDir < LM_CHROMA_IDX ) )
          {
            symbol = k;
            break;
          }
        }
        CHECK( symbol < 0, "invalid symbol found" );
    
    
    Frank Bossen's avatar
    Frank Bossen committed
        unary_max_symbol(symbol, Ctx::IntraChromaPredMode(1), Ctx::IntraChromaPredMode(2), maxSymbol - 1);
    
    }
    
    
    void CABACWriter::intra_chroma_pred_mode( const PredictionUnit& pu )
    {
      const unsigned intraDir = pu.intraDir[1];
    
    Frank Bossen's avatar
    Frank Bossen committed
      const bool     isDerivedMode = intraDir == DM_CHROMA_IDX;
    
      m_BinEncoder.encodeBin(isDerivedMode ? 0 : 1, Ctx::IntraChromaPredMode(0));
    
      if (isDerivedMode)
    
    Frank Bossen's avatar
    Frank Bossen committed
        return;
    
    #if JVET_O1124_ALLOW_CCLM_COND
      if( pu.cs->sps->getUseLMChroma() && pu.cu->checkCCLMAllowed() )
    #else
    
      if( pu.cs->sps->getUseLMChroma() )
    
      {
        intra_chroma_lmc_mode( pu );
        if ( PU::isLMCMode( intraDir ) )
        {
          return;
        }
      }
    
      // chroma candidate index
      unsigned chromaCandModes[ NUM_CHROMA_MODE ];
      PU::getIntraChromaCandModes( pu, chromaCandModes );
    
      int candId = 0;
      for ( ; candId < NUM_CHROMA_MODE; candId++ )
      {
        if( intraDir == chromaCandModes[ candId ] )
        {
          break;
        }
      }
    
      CHECK( candId >= NUM_CHROMA_MODE, "Chroma prediction mode index out of bounds" );
      CHECK( chromaCandModes[ candId ] == DM_CHROMA_IDX, "The intra dir cannot be DM_CHROMA for this path" );
      {
        m_BinEncoder.encodeBinsEP( candId, 2 );
      }
    }
    
    
    void CABACWriter::cu_residual( const CodingUnit& cu, Partitioner& partitioner, CUCtx& cuCtx )
    {
    
    Yu Han's avatar
    Yu Han committed
      if (!CU::isIntra(cu))
    
    Karsten Suehring's avatar
    Karsten Suehring committed
        if( !pu.mergeFlag )
    
        if( cu.rootCbf )
        {
          sbt_mode( cu );
        }
    
    #if JVET_O0094_LFNST_ZERO_PRIM_COEFFS
    
    Mischa Siekmann's avatar
    Mischa Siekmann committed
      cuCtx.violatesLfnstConstrained[CHANNEL_TYPE_LUMA]   = false;
      cuCtx.violatesLfnstConstrained[CHANNEL_TYPE_CHROMA] = false;
    #endif
    
    #if !JVET_O0596_CBF_SIG_ALIGN_TO_SPEC
    
      if( cu.ispMode && isLuma( partitioner.chType ) )
      {
        TUIntraSubPartitioner subTuPartitioner( partitioner );
    
    #if JVET_O0596_CBF_SIG_ALIGN_TO_SPEC
        transform_tree( *cu.cs, subTuPartitioner, cuCtx,             CU::getISPType( cu, getFirstComponentOfChannel( partitioner.chType)  ), 0 );
    #else
    
        transform_tree( *cu.cs, subTuPartitioner, cuCtx, chromaCbfs, CU::getISPType( cu, getFirstComponentOfChannel( partitioner.chType ) ), 0 );
    
    #if JVET_O0596_CBF_SIG_ALIGN_TO_SPEC
        transform_tree( *cu.cs, partitioner, cuCtx );
    #else
    
        transform_tree( *cu.cs, partitioner, cuCtx, chromaCbfs );
    
    
      residual_lfnst_mode( cu, cuCtx );
    
    }
    
    void CABACWriter::rqt_root_cbf( const CodingUnit& cu )
    {
      m_BinEncoder.encodeBin( cu.rootCbf, Ctx::QtRootCbf() );
    
      DTRACE( g_trace_ctx, D_SYNTAX, "rqt_root_cbf() ctx=0 root_cbf=%d pos=(%d,%d)\n", cu.rootCbf ? 1 : 0, cu.lumaPos().x, cu.lumaPos().y );
    }
    
    
    void CABACWriter::sbt_mode( const CodingUnit& cu )
    {
      uint8_t sbtAllowed = cu.checkAllowedSbt();
      if( !sbtAllowed )
      {
        return;
      }
    
      SizeType cuWidth = cu.lwidth();
      SizeType cuHeight = cu.lheight();
      uint8_t sbtIdx = cu.getSbtIdx();
      uint8_t sbtPos = cu.getSbtPos();
    
      //bin - flag
      bool sbtFlag = cu.sbtInfo != 0;
      uint8_t ctxIdx = ( cuWidth * cuHeight <= 256 ) ? 1 : 0;
      m_BinEncoder.encodeBin( sbtFlag, Ctx::SbtFlag( ctxIdx ) );
      if( !sbtFlag )
      {
        return;
      }
    
      bool sbtQuadFlag = sbtIdx == SBT_HOR_QUAD || sbtIdx == SBT_VER_QUAD;
      bool sbtHorFlag = sbtIdx == SBT_HOR_HALF || sbtIdx == SBT_HOR_QUAD;
      bool sbtPosFlag = sbtPos == SBT_POS1;
    
      uint8_t sbtVerHalfAllow = CU::targetSbtAllowed( SBT_VER_HALF, sbtAllowed );
      uint8_t sbtHorHalfAllow = CU::targetSbtAllowed( SBT_HOR_HALF, sbtAllowed );
      uint8_t sbtVerQuadAllow = CU::targetSbtAllowed( SBT_VER_QUAD, sbtAllowed );
      uint8_t sbtHorQuadAllow = CU::targetSbtAllowed( SBT_HOR_QUAD, sbtAllowed );
      //bin - type
      if( ( sbtHorHalfAllow || sbtVerHalfAllow ) && ( sbtHorQuadAllow || sbtVerQuadAllow ) )
      {
        m_BinEncoder.encodeBin( sbtQuadFlag, Ctx::SbtQuadFlag( 0 ) );
      }
      else
      {
        assert( sbtQuadFlag == 0 );
      }
    
      //bin - dir
      if( ( sbtQuadFlag && sbtVerQuadAllow && sbtHorQuadAllow ) || ( !sbtQuadFlag && sbtVerHalfAllow && sbtHorHalfAllow ) ) //both direction allowed
      {
        uint8_t ctxIdx = ( cuWidth == cuHeight ) ? 0 : ( cuWidth < cuHeight ? 1 : 2 );
        m_BinEncoder.encodeBin( sbtHorFlag, Ctx::SbtHorFlag( ctxIdx ) );
      }
      else
      {
        assert( sbtHorFlag == ( ( sbtQuadFlag && sbtHorQuadAllow ) || ( !sbtQuadFlag && sbtHorHalfAllow ) ) );
      }
    
      //bin - pos
      m_BinEncoder.encodeBin( sbtPosFlag, Ctx::SbtPosFlag( 0 ) );
    
      DTRACE( g_trace_ctx, D_SYNTAX, "sbt_mode() pos=(%d,%d) sbtInfo=%d\n", cu.lx(), cu.ly(), (int)cu.sbtInfo );
    }
    
    
    void CABACWriter::end_of_ctu( const CodingUnit& cu, CUCtx& cuCtx )
    {
      const Slice*  slice             = cu.cs->slice;
    
    Karsten Suehring's avatar
    Karsten Suehring committed
      const int     currentCTUTsAddr  = cu.cs->picture->brickMap->getCtuRsToBsAddrMap( CU::getCtuAddr( cu ) );
    
      const bool    isLastSubCUOfCtu  = CU::isLastSubCUOfCtu( cu );
    
      if ( isLastSubCUOfCtu
        && ( !CS::isDualITree( *cu.cs ) || cu.chromaFormat == CHROMA_400 || isChroma( cu.chType ) )
          )
      {
        cuCtx.isDQPCoded = ( cu.cs->pps->getUseDQP() && !cuCtx.isDQPCoded );
    
        // The 1-terminating bit is added to all streams, so don't add it here when it's 1.
        // i.e. when the slice segment CurEnd CTU address is the current CTU address+1.
        if(slice->getSliceCurEndCtuTsAddr() != currentCTUTsAddr + 1)
        {
          m_BinEncoder.encodeBinTrm( 0 );
        }
      }
    }
    
    
    void CABACWriter::cu_palette_info(const CodingUnit& cu, ComponentID compBegin, uint32_t numComp, CUCtx& cuCtx)
    
    {
    	const SPS&        sps = *(cu.cs->sps);
    	TransformUnit&   tu = *cu.firstTU;
    
    	uint32_t indexMaxSize = cu.useEscape[compBegin] ? (cu.curPLTSize[compBegin] + 1) : cu.curPLTSize[compBegin];
    
    
    	if (cu.lastPLTSize[compBegin])
    	{
    		xEncodePLTPredIndicator(cu, MAXPLTSIZE, compBegin);
    	}
    
    	uint32_t reusedPLTnum = 0;
    	for (int idx = 0; idx < cu.lastPLTSize[compBegin]; idx++)
    	{
    		if (cu.reuseflag[compBegin][idx])
    			reusedPLTnum++;
    	}
    
    	if (reusedPLTnum < MAXPLTSIZE)
    	{
    		exp_golomb_eqprob(cu.curPLTSize[compBegin] - reusedPLTnum, 0);
    	}
    
    
    	for (int comp = compBegin; comp < (compBegin + numComp); comp++)
    
    	{
    		for (int idx = cu.reusePLTSize[compBegin]; idx < cu.curPLTSize[compBegin]; idx++)
    		{
    			ComponentID compID = (ComponentID)comp;
    			const int  channelBitDepth = sps.getBitDepth(toChannelType(compID));
    			m_BinEncoder.encodeBinsEP(cu.curPLT[comp][idx], channelBitDepth);
    		}
    	}
    	uint32_t signalEscape = (cu.useEscape[compBegin]) ? 1 : 0;
    	if (cu.curPLTSize[compBegin] > 0)
    	{
    		m_BinEncoder.encodeBinEP(signalEscape);
    	}
    	//encode index map
    	PLTtypeBuf    runType = tu.getrunType(compBegin);
    	PelBuf    runLength = tu.getrunLength(compBegin);
    	PelBuf    curPLTIdx = tu.getcurPLTIdx(compBegin);
    	uint32_t uiHeight = cu.block(compBegin).height;
    	uint32_t uiWidth = cu.block(compBegin).width;
    
    	m_puiScanOrder = g_scanOrder[SCAN_UNGROUPED][(cu.useRotation[compBegin]) ? SCAN_TRAV_VER : SCAN_TRAV_HOR][gp_sizeIdxInfo->idxFrom(uiWidth)][gp_sizeIdxInfo->idxFrom(uiHeight)];
    
    	uint32_t total = uiHeight * uiWidth;
    
    	int iLastRunPos = -1;
    	uint32_t lastRunType = 0;
    	uint32_t uiNumIndices = 0;
    	std::vector<int> vIdxPos, vParsedIdx;
    	vIdxPos.reserve(total);
    	vParsedIdx.reserve(total);
    	if (indexMaxSize > 1)
    	{
    		int idx = 0, run = 0;
    		while (idx < total)
    		{
    			uint32_t posy = m_puiScanOrder[idx].y;
    			uint32_t posx = m_puiScanOrder[idx].x;
    			if (runType.at(posx, posy) == PLT_RUN_INDEX)
    			{
    				vIdxPos.push_back(idx);
    				uiNumIndices++;
    			}
    			lastRunType = runType.at(posx, posy);
    			iLastRunPos = idx;
    			run = runLength.at(posx, posy);
    			idx += run;
    		}
    		uint32_t currParam = 3 + ((indexMaxSize) >> 3);
    		uint32_t uiMappedValue;
    		assert(uiNumIndices);
    		assert(uiNumIndices > 0);
    		uiMappedValue = uiNumIndices - 1;
    		m_BinEncoder.encodeRemAbsEP(uiMappedValue, currParam, false, MAX_NUM_CHANNEL_TYPE); // JC: code number of indices (PLT_RUN_INDEX)
    		auto vIdxPosEnd = vIdxPos.end();
    		for (auto iter = vIdxPos.begin(); iter != vIdxPosEnd; ++iter)
    		{
    			vParsedIdx.push_back( writePLTIndex(cu, *iter, curPLTIdx, runType, indexMaxSize, compBegin));
    		}
    		m_BinEncoder.encodeBin(lastRunType, Ctx::RunTypeFlag());
    		codeScanRotationModeFlag(cu, compBegin);
    	}
    	else
    	{
    		assert(!cu.useRotation[compBegin]);
    	}
    
    	if (cu.useEscape[compBegin] && 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 JVET_O1168_CU_CHROMA_QP_OFFSET
    	if ( cu.useEscape[compBegin] && cu.cs->slice->getUseChromaQpAdj() && !cuCtx.isChromaQpAdjCoded)
    #else
    	if (cu.cs->slice->getUseChromaQpAdj() && !cu.transQuantBypass && !cuCtx.isChromaQpAdjCoded)
    #endif
    	{
    		if (!CS::isDualITree(*tu.cs) || isChroma(tu.chType))
    		{
    			cu_chroma_qp_offset(cu);
    			cuCtx.isChromaQpAdjCoded = true;
    		}
    	}
    
    	uint32_t strPos = 0;
    	uint32_t endPos = uiHeight * uiWidth;
    	auto vParsedIdxEnd = vParsedIdx.end();
    	auto vParsedIdxIter = vParsedIdx.begin();
    	while (strPos < endPos)
    	{
    		uint32_t posy = m_puiScanOrder[strPos].y;
    		uint32_t posx = m_puiScanOrder[strPos].x;
    		uint32_t posyprev = strPos == 0 ? 0 : m_puiScanOrder[strPos - 1].y;
    		uint32_t posxprev = strPos == 0 ? 0 : m_puiScanOrder[strPos - 1].x;
    
    		if (indexMaxSize > 1)
    		{
    			if (((posy == 0) && !cu.useRotation[compBegin]) || ((posx == 0) && cu.useRotation[compBegin]))
    
    			{
    				assert(runType.at(posx, posy) == PLT_RUN_INDEX);
    			}
    			else if (strPos != 0 && runType.at(posxprev, posyprev) == PLT_RUN_COPY)
    			{
    				assert(runType.at(posx, posy) == PLT_RUN_INDEX);
    			}
    			else
    			{
    				if (uiNumIndices && strPos < endPos - 1) // if uiNumIndices (decoder will know this value) == 0 - > only CopyAbove, if strPos == endPos - 1, the last RunType was already coded
    				{
    					m_BinEncoder.encodeBin((runType.at(posx, posy)), Ctx::RunTypeFlag());
    				}
    			}
    		}
    
    		Pel siCurLevel = 0;
    		if (runType.at(posx, posy) == PLT_RUN_INDEX)
    		{
    			if (vParsedIdxIter != vParsedIdxEnd)
    			{
    				siCurLevel = *vParsedIdxIter++;
    			}
    			else
    			{
    				siCurLevel = 0;
    			}
    		}
    
    		if (indexMaxSize > 1)
    		{
    			if (iLastRunPos != strPos)
    			{
    				uiNumIndices -= (runType.at(posx, posy) == PLT_RUN_INDEX);
    				cu_run_val(runLength.at(posx, posy) - 1, (PLTRunMode)runType.at(posx, posy), siCurLevel, endPos - strPos - uiNumIndices - 1 - lastRunType);
    			}
    
    		}
    
    		strPos += (runLength.at(posx, posy));
    	}
    	assert(strPos == endPos);
    
    	uint32_t scaleX = getComponentScaleX(COMPONENT_Cb, sps.getChromaFormatIdc());
    	uint32_t scaleY = getComponentScaleY(COMPONENT_Cb, sps.getChromaFormatIdc());
    
    	for (int comp = compBegin; comp < (compBegin + numComp); comp++)
    
    	{
    		ComponentID compID = (ComponentID)comp;
    		for (strPos = 0; strPos < endPos; strPos++)
    		{
    			uint32_t posy = m_puiScanOrder[strPos].y;
    			uint32_t posx = m_puiScanOrder[strPos].x;
    			if (curPLTIdx.at(posx, posy) == cu.curPLTSize[compBegin])
    			{
    				{
    					PLTescapeBuf    escapeValue = tu.getescapeValue((ComponentID)comp);
    					if (compID == COMPONENT_Y || compBegin != COMPONENT_Y)
    					{
    						exp_golomb_eqprob((unsigned)escapeValue.at(posx, posy), 3);
    					}
    					if (compBegin == COMPONENT_Y && compID != COMPONENT_Y && posy % (1 << scaleY) == 0 && posx % (1 << scaleX) == 0)
    					{
    						uint32_t posxC = posx >> scaleX;
    						uint32_t posyC = posy >> scaleY;
    						exp_golomb_eqprob((unsigned)escapeValue.at(posxC, posyC), 3);
    					}
    				}
    			}
    		}
    	}
    
    }
    void CABACWriter::codeScanRotationModeFlag(const CodingUnit& cu, ComponentID compBegin)
    {
    	m_BinEncoder.encodeBin((cu.useRotation[compBegin]), Ctx::RotationFlag());
    }
    void CABACWriter::xEncodePLTPredIndicator(const CodingUnit& cu, uint32_t uiMaxPLTSize, ComponentID compBegin)
    {
    	int lastPredIdx = -1;
    	uint32_t run = 0;
    	uint32_t uiNumPLTPredicted = 0;
    	for (uint32_t idx = 0; idx < cu.lastPLTSize[compBegin]; idx++)
    	{
    		if (cu.reuseflag[compBegin][idx])
    		{
    			uiNumPLTPredicted++;
    			lastPredIdx = idx;
    		}
    	}
    
    	int idx = 0;
    	while (idx <= lastPredIdx)
    	{
    		if (cu.reuseflag[compBegin][idx])
    		{
    			exp_golomb_eqprob(run ? run + 1 : run, 0);
    			run = 0;
    		}
    		else
    		{
    			run++;
    		}
    		idx++;
    	}
    	if ((uiNumPLTPredicted < uiMaxPLTSize && lastPredIdx + 1 < cu.lastPLTSize[compBegin]) || !uiNumPLTPredicted)
    	{
    		exp_golomb_eqprob(1, 0);
    	}
    }
    
    Pel CABACWriter::writePLTIndex(const CodingUnit& cu, uint32_t idx, PelBuf& paletteIdx, PLTtypeBuf& paletteRunType, int maxSymbol, ComponentID compBegin)
    
    {
    	uint32_t posy = m_puiScanOrder[idx].y;
    	uint32_t posx = m_puiScanOrder[idx].x;
    
    	Pel siCurLevel = (paletteIdx.at(posx, posy) == cu.curPLTSize[compBegin]) ? (maxSymbol - 1) : paletteIdx.at(posx, posy);
    
    	if (idx) // R0348: remove index redundancy
    	{
    		uint32_t prevposy = m_puiScanOrder[idx - 1].y;
    		uint32_t prevposx = m_puiScanOrder[idx - 1].x;
    
    		if (paletteRunType.at(prevposx, prevposy) == PLT_RUN_INDEX)
    
    			Pel siLeftLevel = paletteIdx.at(prevposx, prevposy); // left index
    
    			if (siLeftLevel == cu.curPLTSize[compBegin]) // escape mode
    			{
    				siLeftLevel = maxSymbol - 1;
    			}
    			assert(siLeftLevel != siCurLevel);
    			if (siCurLevel > siLeftLevel)
    			{
    				siCurLevel--;
    			}
    		}
    		else
    		{
    			Pel siAboveLevel;
    			if (cu.useRotation[compBegin])
    			{
    				assert(prevposx > 0);
    
    				siAboveLevel = paletteIdx.at(posx - 1, posy);
    				if (paletteIdx.at(posx - 1, posy) == cu.curPLTSize[compBegin]) // escape mode
    
    				siAboveLevel = paletteIdx.at(posx, posy - 1);
    				if (paletteIdx.at(posx, posy - 1) == cu.curPLTSize[compBegin]) // escape mode
    
    				{
    					siAboveLevel = maxSymbol - 1;
    				}
    			}
    			assert(siCurLevel != siAboveLevel);
    			if (siCurLevel > siAboveLevel)
    			{
    				siCurLevel--;
    			}
    		}
    		maxSymbol--;
    	}
    	assert(maxSymbol > 0);
    	assert(siCurLevel >= 0);
    	assert(maxSymbol > siCurLevel);
    	if (maxSymbol > 1)
    	{
    		xWriteTruncBinCode(siCurLevel, maxSymbol);
    	}
    	return siCurLevel;
    }
    
    void CABACWriter::encodeRunType(const CodingUnit&  cu, PLTtypeBuf& runType, uint32_t idx, ScanElement *refScanOrder, ComponentID compBegin)
    {
    	if (refScanOrder)
    	{
    		m_puiScanOrder = refScanOrder;
    	}
    	uint32_t posy = m_puiScanOrder[idx].y;
    	uint32_t posx = m_puiScanOrder[idx].x;
    	uint32_t posyprev = (idx == 0) ? 0 : m_puiScanOrder[idx - 1].y;
    	uint32_t posxprev = (idx == 0) ? 0 : m_puiScanOrder[idx - 1].x;
    
    	if (((posy == 0) && !cu.useRotation[compBegin]) || ((posx == 0) && cu.useRotation[compBegin]))
    	{
    		assert(runType.at(posx, posy) == PLT_RUN_INDEX);
    	}
    	else if (idx != 0 && runType.at(posxprev, posyprev) == PLT_RUN_COPY)
    	{
    		assert(runType.at(posx, posy) == PLT_RUN_INDEX);
    	}
    	else
    	{
    		m_BinEncoder.encodeBin((runType.at(posx, posy)), Ctx::RunTypeFlag());
    	}
    }
    
    void CABACWriter::cu_run_val(uint32_t uiRun, PLTRunMode runtype, const uint32_t uiPltIdx, const uint32_t uiMaxRun)
    {
    	if (runtype == PLT_RUN_COPY)
    	{
    	}
    	else
    	{
    		g_ucRunLeftLut[0] = (uiPltIdx < PLT_RUN_MSB_IDX_CTX_T1 ? 0 : (uiPltIdx < PLT_RUN_MSB_IDX_CTX_T2 ? 1 : 2));
    	}
    	xWriteTruncMsbP1RefinementBits(uiRun, runtype, uiMaxRun, PLT_RUN_MSB_IDX_CABAC_BYPASS_THRE);
    }
    uint32_t CABACWriter::xWriteTruncMsbP1(uint32_t uiSymbol, PLTRunMode runtype, uint32_t uiMax, uint32_t uiCtxT)
    {
    	if (uiMax == 0)
    		return 0;
    
    	uint8_t *ucCtxLut;
    	ucCtxLut = (runtype == PLT_RUN_INDEX) ? g_ucRunLeftLut : g_ucRunTopLut;
    
    	uint32_t uiMsbP1;
    	for (uiMsbP1 = 0; uiSymbol > 0; uiMsbP1++)
    	{
    		uiSymbol >>= 1;
    		if (uiMsbP1 > uiCtxT)
    		{
    			m_BinEncoder.encodeBinEP(1);
    		}
    		else
    			m_BinEncoder.encodeBin(1, (uiMsbP1 <= uiCtxT)
    				? ((runtype == PLT_RUN_INDEX) ? Ctx::IdxRunModel(ucCtxLut[uiMsbP1]) : Ctx::CopyRunModel(ucCtxLut[uiMsbP1]))
    				: ((runtype == PLT_RUN_INDEX) ? Ctx::IdxRunModel(ucCtxLut[uiCtxT]) : Ctx::CopyRunModel(ucCtxLut[uiCtxT])));
    	}
    	assert(uiMsbP1 <= uiMax);
    	if (uiMsbP1 < uiMax)
    	{
    		if (uiMsbP1 > uiCtxT)
    		{
    			m_BinEncoder.encodeBinEP(0);
    		}
    		else
    			m_BinEncoder.encodeBin(0, uiMsbP1 <= uiCtxT
    				? ((runtype == PLT_RUN_INDEX) ? Ctx::IdxRunModel(ucCtxLut[uiMsbP1]) : Ctx::CopyRunModel(ucCtxLut[uiMsbP1]))
    				: ((runtype == PLT_RUN_INDEX) ? Ctx::IdxRunModel(ucCtxLut[uiCtxT]) : Ctx::CopyRunModel(ucCtxLut[uiCtxT])));
    
    		//m_pcBinIf->encodeBin(0, uiMsbP1 <= uiCtxT? pcSCModel[ucCtxLut[uiMsbP1]] : pcSCModel[ucCtxLut[uiCtxT]]);
    	}
    	return uiMsbP1;
    }
    
    void CABACWriter::xWriteTruncMsbP1RefinementBits(uint32_t uiSymbol, PLTRunMode runtype, uint32_t uiMax, uint32_t uiCtxT)
    {
    	if (uiMax == 0)
    		return;
    
    	uint32_t uiMsbP1 = xWriteTruncMsbP1(uiSymbol, runtype, g_getMsbP1Idx(uiMax), uiCtxT);
    	if (uiMsbP1 > 1)
    	{
    		uint32_t uiNumBins = g_getMsbP1Idx(uiMax);
    		if (uiMsbP1 < uiNumBins)
    		{
    
    			uint32_t uiBits = uiMsbP1 - 1;
    			m_BinEncoder.encodeBinsEP(uiSymbol & ((1 << uiBits) - 1), uiBits);
    		}
    		else
    		{
    			uint32_t curValue = 1 << (uiNumBins - 1);
    			xWriteTruncBinCode(uiSymbol - curValue, uiMax + 1 - curValue);
    		}
    	}
    }
    
    
    //================================================================================
    //  clause 7.3.8.6
    //--------------------------------------------------------------------------------
    //    void  prediction_unit ( pu );
    //    void  merge_flag      ( pu );
    //    void  merge_idx       ( pu );
    //    void  inter_pred_idc  ( pu );
    //    void  ref_idx         ( pu, refList );
    //    void  mvp_flag        ( pu, refList );
    //================================================================================
    
    void CABACWriter::prediction_unit( const PredictionUnit& pu )
    {
    #if ENABLE_SPLIT_PARALLELISM || ENABLE_WPP_PARALLELISM
      CHECK( pu.cacheUsed, "Processing a PU that should be in cache!" );
      CHECK( pu.cu->cacheUsed, "Processing a CU that should be in cache!" );
    
    #endif
      if( pu.cu->skip )
      {
        CHECK( !pu.mergeFlag, "merge_flag must be true for skipped CUs" );
      }
      else
      {
        merge_flag( pu );
      }
      if( pu.mergeFlag )
      {
    
    Yu Han's avatar
    Yu Han committed
        if (CU::isIBC(*pu.cu))
        {
          merge_idx(pu);
          return;
        }
    
        if (pu.regularMergeFlag)
    
    Yi-Wen Chen's avatar
    Yi-Wen Chen committed
          subblock_merge_flag( *pu.cu );
          MHIntra_flag( pu );
    
          if (!pu.mhIntraFlag)
          {
            if (!pu.cu->affine && !pu.mmvdMergeFlag && !pu.cu->mmvdSkip)
            {
              CHECK(!pu.cu->triangle, "triangle_flag must be true");
            }
          }
    
    Yi-Wen Chen's avatar
    Yi-Wen Chen committed
          if (pu.mmvdMergeFlag)
          {
            mmvd_merge_idx(pu);
          }
          else
            merge_idx    ( pu );
    
    Yu Han's avatar
    Yu Han committed
      else if (CU::isIBC(*pu.cu))
      {
        ref_idx(pu, REF_PIC_LIST_0);
    
    Xiang Li's avatar
    Xiang Li committed
        Mv mvd = pu.mvd[REF_PIC_LIST_0];
        mvd.changeIbcPrecInternal2Amvr(pu.cu->imv);
        mvd_coding(mvd, 0); // already changed to signaling precision
    
    #if JVET_O0162_IBC_MVP_FLAG
        if ( pu.cu->slice->getMaxNumMergeCand() == 1 )
        {
          CHECK( pu.mvpIdx[REF_PIC_LIST_0], "mvpIdx for IBC mode should be 0" );
        }
        else
    #endif
    
    Yu Han's avatar
    Yu Han committed
        mvp_flag(pu, REF_PIC_LIST_0);
      }
    
        smvd_mode( pu );
    
        if( pu.interDir != 2 /* PRED_L1 */ )
        {
          ref_idx     ( pu, REF_PIC_LIST_0 );
          if ( pu.cu->affine )
          {
    
    Xiang Li's avatar
    Xiang Li committed
            Mv mvd = pu.mvdAffi[REF_PIC_LIST_0][0];
            mvd.changeAffinePrecInternal2Amvr(pu.cu->imv);
            mvd_coding(mvd, 0); // already changed to signaling precision
            mvd = pu.mvdAffi[REF_PIC_LIST_0][1];
            mvd.changeAffinePrecInternal2Amvr(pu.cu->imv);
            mvd_coding(mvd, 0); // already changed to signaling precision
    
            if ( pu.cu->affineType == AFFINEMODEL_6PARAM )
            {
    
    Xiang Li's avatar
    Xiang Li committed
              mvd = pu.mvdAffi[REF_PIC_LIST_0][2];
              mvd.changeAffinePrecInternal2Amvr(pu.cu->imv);
              mvd_coding(mvd, 0); // already changed to signaling precision
    
    Xiang Li's avatar
    Xiang Li committed
            Mv mvd = pu.mvd[REF_PIC_LIST_0];
            mvd.changeTransPrecInternal2Amvr(pu.cu->imv);
            mvd_coding(mvd, 0); // already changed to signaling precision
    
          }
          mvp_flag    ( pu, REF_PIC_LIST_0 );
        }
        if( pu.interDir != 1 /* PRED_L0 */ )
        {
    
          if ( pu.cu->smvdMode != 1 )
          {
    
          ref_idx     ( pu, REF_PIC_LIST_1 );
          if( !pu.cs->slice->getMvdL1ZeroFlag() || pu.interDir != 3 /* PRED_BI */ )
          {
            if ( pu.cu->affine )
            {
    
    Xiang Li's avatar
    Xiang Li committed
              Mv mvd = pu.mvdAffi[REF_PIC_LIST_1][0];
              mvd.changeAffinePrecInternal2Amvr(pu.cu->imv);
              mvd_coding(mvd, 0); // already changed to signaling precision
              mvd = pu.mvdAffi[REF_PIC_LIST_1][1];
              mvd.changeAffinePrecInternal2Amvr(pu.cu->imv);
              mvd_coding(mvd, 0); // already changed to signaling precision
    
              if ( pu.cu->affineType == AFFINEMODEL_6PARAM )
              {
    
    Xiang Li's avatar
    Xiang Li committed
                mvd = pu.mvdAffi[REF_PIC_LIST_1][2];
                mvd.changeAffinePrecInternal2Amvr(pu.cu->imv);
                mvd_coding(mvd, 0); // already changed to signaling precision
    
    Xiang Li's avatar
    Xiang Li committed
              Mv mvd = pu.mvd[REF_PIC_LIST_1];
              mvd.changeTransPrecInternal2Amvr(pu.cu->imv);
              mvd_coding(mvd, 0); // already changed to signaling precision
    
    void CABACWriter::smvd_mode( const PredictionUnit& pu )
    {
      if ( pu.interDir != 3 || pu.cu->affine )
      {
        return;
      }
    
      if ( pu.cs->slice->getBiDirPred() == false )
      {