Skip to content
Snippets Groups Projects
CABACWriter.cpp 114 KiB
Newer Older
  • Learn to ignore specific revisions
  • 
      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 )
    
        {
          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 )
    
      {
        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
    
      if( cu.chromaFormat == CHROMA_400 || ( cu.isSepTree() && cu.chType == CHANNEL_TYPE_LUMA ) )
    
      {
        return;
      }
    
      const PredictionUnit* pu = cu.firstPU;
    
      intra_chroma_pred_mode( *pu );
    }
    
    U-EU\bray's avatar
    U-EU\bray committed
    void CABACWriter::intra_chroma_lmc_mode(const PredictionUnit& pu)
    {
      const unsigned intraDir = pu.intraDir[1];
      int lmModeList[10];
      PU::getLMSymbolList(pu, lmModeList);
      int symbol = -1;
      for (int k = 0; k < LM_SYMBOL_NUM; k++)
      {
        if (lmModeList[k] == intraDir)
        {
          symbol = k;
          break;
        }
      }
      CHECK(symbol < 0, "invalid symbol found");
    
      m_BinEncoder.encodeBin(symbol == 0 ? 0 : 1, Ctx::IntraChromaPredMode(0));
    
      if (symbol > 0)
      {
        CHECK(symbol > 2, "invalid symbol for MMLM");
        unsigned int symbol_minus_1 = symbol - 1;
        m_BinEncoder.encodeBinEP(symbol_minus_1);
      }
    }
    
    
    void CABACWriter::intra_chroma_pred_mode(const PredictionUnit& pu)
    {
      const unsigned intraDir = pu.intraDir[1];
      if (pu.cs->sps->getUseLMChroma() && pu.cu->checkCCLMAllowed())
      {
        m_BinEncoder.encodeBin(PU::isLMCMode(intraDir) ? 1 : 0, Ctx::CclmModeFlag(0));
        if (PU::isLMCMode(intraDir))
        {
          intra_chroma_lmc_mode(pu);
          return;
        }
      }
    
      const bool     isDerivedMode = intraDir == DM_CHROMA_IDX;
      m_BinEncoder.encodeBin(isDerivedMode ? 0 : 1, Ctx::IntraChromaPredMode(0));
      if (isDerivedMode)
      {
        return;
      }
    
      // chroma candidate index
      unsigned chromaCandModes[NUM_CHROMA_MODE];
      PU::getIntraChromaCandModes(pu, chromaCandModes);
    
    U-EU\bray's avatar
    U-EU\bray committed
      int candId = 0;
      for (; candId < NUM_CHROMA_MODE; candId++)
      {
        if (intraDir == chromaCandModes[candId])
        {
          break;
        }
      }
    
    U-EU\bray's avatar
    U-EU\bray committed
      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 );
        }
    
    Mischa Siekmann's avatar
    Mischa Siekmann committed
      cuCtx.violatesLfnstConstrained[CHANNEL_TYPE_LUMA]   = false;
      cuCtx.violatesLfnstConstrained[CHANNEL_TYPE_CHROMA] = false;
    
    Jason Jung's avatar
    Jason Jung committed
      cuCtx.lfnstLastScanPos = false;
    
      if( cu.ispMode && isLuma( partitioner.chType ) )
      {
        TUIntraSubPartitioner subTuPartitioner( partitioner );
    
        transform_tree( *cu.cs, subTuPartitioner, cuCtx,             CU::getISPType( cu, getFirstComponentOfChannel( partitioner.chType)  ), 0 );
    
        transform_tree( *cu.cs, partitioner, cuCtx );
    
    
      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
    
        && ( !cu.isSepTree() || 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   height = cu.block(compBegin).height;
      uint32_t   width = cu.block(compBegin).width;
    
    Yung-Hsuan Chao (Jessie)'s avatar
    Yung-Hsuan Chao (Jessie) committed
      m_scanOrder = g_scanOrder[SCAN_UNGROUPED][(cu.useRotation[compBegin]) ? SCAN_TRAV_VER : SCAN_TRAV_HOR][gp_sizeIdxInfo->idxFrom(width)][gp_sizeIdxInfo->idxFrom(height)];
    
      uint32_t total = height * width;
      int lastRunPos = -1;
    
      uint32_t numIndices = 0;
      std::vector<int> idxPos, parsedIdx;
      idxPos.reserve(total);
      parsedIdx.reserve(total);
    
      if (indexMaxSize > 1)
      {
        int idx = 0, run = 0;
        while (idx < total)
        {
    
    Yung-Hsuan Chao (Jessie)'s avatar
    Yung-Hsuan Chao (Jessie) committed
          uint32_t posy = m_scanOrder[idx].y;
          uint32_t posx = m_scanOrder[idx].x;
    
          if (runType.at(posx, posy) == PLT_RUN_INDEX)
          {
    
            idxPos.push_back(idx);
            numIndices++;
    
          }
          lastRunType = runType.at(posx, posy);
    
          run = runLength.at(posx, posy);
          idx += run;
        }
        uint32_t currParam = 3 + ((indexMaxSize) >> 3);
    
        uint32_t mappedValue;
        assert(numIndices);
        assert(numIndices > 0);
        mappedValue = numIndices - 1;
        m_BinEncoder.encodeRemAbsEP(mappedValue, currParam, false, MAX_NUM_CHANNEL_TYPE); // JC: code number of indices (PLT_RUN_INDEX)
        auto idxPosEnd = idxPos.end();
        for (auto iter = idxPos.begin(); iter != idxPosEnd; ++iter)
    
          parsedIdx.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)
      {
    
    Yin Zhao's avatar
    Yin Zhao committed
        if (!cu.isSepTree() || isLuma(tu.chType))
    
        {
          cu_qp_delta(cu, cuCtx.qp, cu.qp);
          cuCtx.qp = cu.qp;
          cuCtx.isDQPCoded = true;
        }
      }
      if ( cu.useEscape[compBegin] && cu.cs->slice->getUseChromaQpAdj() && !cuCtx.isChromaQpAdjCoded)
      {
        if (!CS::isDualITree(*tu.cs) || isChroma(tu.chType))
        {
          cu_chroma_qp_offset(cu);
          cuCtx.isChromaQpAdjCoded = true;
        }
      }
    
      uint32_t endPos = height * width;
      auto parsedIdxEnd = parsedIdx.end();
      auto parsedIdxIter = parsedIdx.begin();
    
    Yung-Hsuan Chao (Jessie)'s avatar
    Yung-Hsuan Chao (Jessie) committed
        uint32_t posy = m_scanOrder[strPos].y;
        uint32_t posx = m_scanOrder[strPos].x;
        uint32_t posyprev = strPos == 0 ? 0 : m_scanOrder[strPos - 1].y;
        uint32_t posxprev = strPos == 0 ? 0 : m_scanOrder[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 (numIndices && strPos < endPos - 1) // if numIndices (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());
            }
          }
        }
    
        if (runType.at(posx, posy) == PLT_RUN_INDEX)
        {
    
          if (parsedIdxIter != parsedIdxEnd)
    
            curLevel = *parsedIdxIter++;
    
          if (lastRunPos != strPos)
    
            numIndices -= (runType.at(posx, posy) == PLT_RUN_INDEX);
    
            cu_run_val(runLength.at(posx, posy) - 1, (PLTRunMode)runType.at(posx, posy), curLevel, endPos - strPos - numIndices - 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++)
        {
    
    Yung-Hsuan Chao (Jessie)'s avatar
    Yung-Hsuan Chao (Jessie) committed
          uint32_t posy = m_scanOrder[strPos].y;
          uint32_t posx = m_scanOrder[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 maxPLTSize, ComponentID compBegin)
    
      int lastPredIdx = -1;
      uint32_t run = 0;
    
      uint32_t numPLTPredicted = 0;
    
      for (uint32_t idx = 0; idx < cu.lastPLTSize[compBegin]; idx++)
      {
        if (cu.reuseflag[compBegin][idx])
        {
    
          numPLTPredicted++;
    
          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 ((numPLTPredicted < maxPLTSize && lastPredIdx + 1 < cu.lastPLTSize[compBegin]) || !numPLTPredicted)
    
    Pel CABACWriter::writePLTIndex(const CodingUnit& cu, uint32_t idx, PelBuf& paletteIdx, PLTtypeBuf& paletteRunType, int maxSymbol, ComponentID compBegin)
    
    Yung-Hsuan Chao (Jessie)'s avatar
    Yung-Hsuan Chao (Jessie) committed
      uint32_t posy = m_scanOrder[idx].y;
      uint32_t posx = m_scanOrder[idx].x;
    
      Pel curLevel = (paletteIdx.at(posx, posy) == cu.curPLTSize[compBegin]) ? (maxSymbol - 1) : paletteIdx.at(posx, posy);
    
      if (idx) // R0348: remove index redundancy
      {
    
    Yung-Hsuan Chao (Jessie)'s avatar
    Yung-Hsuan Chao (Jessie) committed
        uint32_t prevposy = m_scanOrder[idx - 1].y;
        uint32_t prevposx = m_scanOrder[idx - 1].x;
    
        if (paletteRunType.at(prevposx, prevposy) == PLT_RUN_INDEX)
        {
    
          Pel leftLevel = paletteIdx.at(prevposx, prevposy); // left index
          if (leftLevel == cu.curPLTSize[compBegin]) // escape mode
    
            leftLevel = maxSymbol - 1;
    
          assert(leftLevel != curLevel);
          if (curLevel > leftLevel)
    
          if (cu.useRotation[compBegin])
          {
            assert(prevposx > 0);
    
            aboveLevel = paletteIdx.at(posx - 1, posy);
    
            if (paletteIdx.at(posx - 1, posy) == cu.curPLTSize[compBegin]) // escape mode
            {
    
              aboveLevel = maxSymbol - 1;
    
            aboveLevel = paletteIdx.at(posx, posy - 1);
    
            if (paletteIdx.at(posx, posy - 1) == cu.curPLTSize[compBegin]) // escape mode
            {
    
              aboveLevel = maxSymbol - 1;
    
          assert(curLevel != aboveLevel);
          if (curLevel > aboveLevel)
    
      assert(curLevel >= 0);
      assert(maxSymbol > curLevel);
    
        xWriteTruncBinCode(curLevel, maxSymbol);
    
    }
    
    void CABACWriter::encodeRunType(const CodingUnit&  cu, PLTtypeBuf& runType, uint32_t idx, ScanElement *refScanOrder, ComponentID compBegin)
    {
    
    Yung-Hsuan Chao (Jessie)'s avatar
    Yung-Hsuan Chao (Jessie) committed
        m_scanOrder = refScanOrder;
    
    Yung-Hsuan Chao (Jessie)'s avatar
    Yung-Hsuan Chao (Jessie) committed
      uint32_t posy = m_scanOrder[idx].y;
      uint32_t posx = m_scanOrder[idx].x;
      uint32_t posyprev = (idx == 0) ? 0 : m_scanOrder[idx - 1].y;
      uint32_t posxprev = (idx == 0) ? 0 : m_scanOrder[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 run, PLTRunMode runtype, const uint32_t paletteIdx, const uint32_t maxRun)
    
    Yung-Hsuan Chao (Jessie)'s avatar
    Yung-Hsuan Chao (Jessie) committed
        g_paletteRunLeftLut[0] = (paletteIdx < PLT_RUN_MSB_IDX_CTX_T1 ? 0 : (paletteIdx < PLT_RUN_MSB_IDX_CTX_T2 ? 1 : 2));
    
      xWriteTruncMsbP1RefinementBits(run, runtype, maxRun, PLT_RUN_MSB_IDX_CABAC_BYPASS_THRE);
    
    uint32_t CABACWriter::xWriteTruncMsbP1(uint32_t symbol, PLTRunMode runtype, uint32_t uiMax, uint32_t uiCtxT)
    
    Yung-Hsuan Chao (Jessie)'s avatar
    Yung-Hsuan Chao (Jessie) committed
      ctxLut = (runtype == PLT_RUN_INDEX) ? g_paletteRunLeftLut : g_paletteRunTopLut;
    
      uint32_t msbP1;
      for (msbP1 = 0; symbol > 0; msbP1++)
    
        symbol >>= 1;
        if (msbP1 > uiCtxT)
    
          m_BinEncoder.encodeBin(1, (msbP1 <= uiCtxT)
            ? ((runtype == PLT_RUN_INDEX) ? Ctx::IdxRunModel(ctxLut[msbP1]) : Ctx::CopyRunModel(ctxLut[msbP1]))
            : ((runtype == PLT_RUN_INDEX) ? Ctx::IdxRunModel(ctxLut[uiCtxT]) : Ctx::CopyRunModel(ctxLut[uiCtxT])));
    
      assert(msbP1 <= uiMax);
      if (msbP1 < uiMax)
    
        if (msbP1 > uiCtxT)
    
          m_BinEncoder.encodeBin(0, msbP1 <= uiCtxT
            ? ((runtype == PLT_RUN_INDEX) ? Ctx::IdxRunModel(ctxLut[msbP1]) : Ctx::CopyRunModel(ctxLut[msbP1]))
            : ((runtype == PLT_RUN_INDEX) ? Ctx::IdxRunModel(ctxLut[uiCtxT]) : Ctx::CopyRunModel(ctxLut[uiCtxT])));
    
        //m_pcBinIf->encodeBin(0, msbP1 <= uiCtxT? pcSCModel[ctxLut[msbP1]] : pcSCModel[ctxLut[uiCtxT]]);
    
    void CABACWriter::xWriteTruncMsbP1RefinementBits(uint32_t symbol, PLTRunMode runtype, uint32_t maxVal, uint32_t uiCtxT)
    
      uint32_t msbP1 = xWriteTruncMsbP1(symbol, runtype, floorLog2(maxVal) + 1, uiCtxT);
    
        if (msbP1 < numBins)
    
          uint32_t bits = msbP1 - 1;
          m_BinEncoder.encodeBinsEP(symbol & ((1 << bits) - 1), bits);
    
          uint32_t curValue = 1 << (numBins - 1);
          xWriteTruncBinCode(symbol - curValue, maxVal + 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 )
    {
    
      CHECK( pu.cu->treeType == TREE_C, "cannot be chroma CU" );
    
    #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
      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
    
    Xiang Li's avatar
    Xiang Li committed
        if ( pu.cu->slice->getMaxNumIBCMergeCand() == 1 )
    
        {
          CHECK( pu.mvpIdx[REF_PIC_LIST_0], "mvpIdx for IBC mode should be 0" );
        }
        else
    
    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 )
      {
        return;
      }
    
      m_BinEncoder.encodeBin( pu.cu->smvdMode ? 1 : 0, Ctx::SmvdFlag() );
    
      DTRACE( g_trace_ctx, D_SYNTAX, "symmvd_flag() symmvd=%d pos=(%d,%d) size=%dx%d\n", pu.cu->smvdMode ? 1 : 0, pu.lumaPos().x, pu.lumaPos().y, pu.lumaSize().width, pu.lumaSize().height );
    }
    
    
    void CABACWriter::subblock_merge_flag( const CodingUnit& cu )
    {
    
      if ( !cu.cs->slice->isIntra() && (cu.slice->getMaxNumAffineMergeCand() > 0) && cu.lumaSize().width >= 8 && cu.lumaSize().height >= 8 )
    
      {
        unsigned ctxId = DeriveCtx::CtxAffineFlag( cu );
    
        m_BinEncoder.encodeBin( cu.affine, Ctx::SubblockMergeFlag( ctxId ) );
    
        DTRACE( g_trace_ctx, D_SYNTAX, "subblock_merge_flag() subblock_merge_flag=%d ctx=%d pos=(%d,%d)\n", cu.affine ? 1 : 0, ctxId, cu.Y().x, cu.Y().y );
      }
    }
    
    
    void CABACWriter::affine_flag( const CodingUnit& cu )
    {
    
      if ( !cu.cs->slice->isIntra() && cu.cs->sps->getUseAffine() && cu.lumaSize().width > 8 && cu.lumaSize().height > 8 )
    
      {
        unsigned ctxId = DeriveCtx::CtxAffineFlag( cu );
        m_BinEncoder.encodeBin( cu.affine, Ctx::AffineFlag( ctxId ) );
        DTRACE( g_trace_ctx, D_SYNTAX, "affine_flag() affine=%d ctx=%d pos=(%d,%d)\n", cu.affine ? 1 : 0, ctxId, cu.Y().x, cu.Y().y );
    
    
        if ( cu.affine && cu.cs->sps->getUseAffineType() )
    
        {
          unsigned ctxId = 0;
          m_BinEncoder.encodeBin( cu.affineType, Ctx::AffineType( ctxId ) );
          DTRACE( g_trace_ctx, D_SYNTAX, "affine_type() affine_type=%d ctx=%d pos=(%d,%d)\n", cu.affineType ? 1 : 0, ctxId, cu.Y().x, cu.Y().y );
        }
      }
    
    }
    
    void CABACWriter::merge_flag( const PredictionUnit& pu )
    {
      m_BinEncoder.encodeBin( pu.mergeFlag, Ctx::MergeFlag() );
    
      DTRACE( g_trace_ctx, D_SYNTAX, "merge_flag() merge=%d pos=(%d,%d) size=%dx%d\n", pu.mergeFlag ? 1 : 0, pu.lumaPos().x, pu.lumaPos().y, pu.lumaSize().width, pu.lumaSize().height );
    
    void CABACWriter::merge_data(const PredictionUnit& pu)
    {
      if (CU::isIBC(*pu.cu))
      {
        merge_idx(pu);
        return;
      }
      subblock_merge_flag(*pu.cu);
      if (pu.cu->affine)
      {
        merge_idx(pu);
        return;
      }
    
      const bool triangleAvailable = pu.cu->cs->slice->getSPS()->getUseTriangle() && pu.cu->cs->slice->isInterB() && pu.cu->cs->slice->getMaxNumTriangleCand() > 1;
    
      const bool ciipAvailable = pu.cs->sps->getUseMHIntra() && !pu.cu->skip && pu.cu->lwidth() < MAX_CU_SIZE && pu.cu->lheight() < MAX_CU_SIZE;
      if (pu.cu->lwidth() * pu.cu->lheight() >= 64
        && (triangleAvailable || ciipAvailable))
      {
        m_BinEncoder.encodeBin(pu.regularMergeFlag, Ctx::RegularMergeFlag(pu.cu->skip ? 0 : 1));
      }
      if (pu.regularMergeFlag)
      {
        if (pu.cs->sps->getUseMMVD())
        {
          m_BinEncoder.encodeBin(pu.mmvdMergeFlag, Ctx::MmvdFlag(0));
          DTRACE(g_trace_ctx, D_SYNTAX, "mmvd_merge_flag() mmvd_merge=%d pos=(%d,%d) size=%dx%d\n", pu.mmvdMergeFlag ? 1 : 0, pu.lumaPos().x, pu.lumaPos().y, pu.lumaSize().width, pu.lumaSize().height);
        }
        if (pu.mmvdMergeFlag || pu.cu->mmvdSkip)
        {
          mmvd_merge_idx(pu);
        }
        else
        {
          merge_idx(pu);
        }
      }
      else
      {
        if (triangleAvailable && ciipAvailable)
        {
          MHIntra_flag(pu);
        }
        merge_idx(pu);
      }
    
      const SPS *sps = cu.cs->sps;
    
      if( !sps->getAMVREnabledFlag() )
    
    
      bool bNonZeroMvd = CU::hasSubCUNonZeroMVd( cu );
      if( !bNonZeroMvd )
      {
        return;
      }
    
    
    Yu Han's avatar
    Yu Han committed
      if (CU::isIBC(cu) == false)
    
        m_BinEncoder.encodeBin( (cu.imv > 0), Ctx::ImvFlag( 0 ) );
      DTRACE( g_trace_ctx, D_SYNTAX, "imv_mode() value=%d ctx=%d\n", (cu.imv > 0), 0 );
    
      if( sps->getAMVREnabledFlag() && cu.imv > 0 )
    
        if (!CU::isIBC(cu))
        {
          m_BinEncoder.encodeBin(cu.imv < IMV_HPEL, Ctx::ImvFlag(4));
          DTRACE(g_trace_ctx, D_SYNTAX, "imv_mode() value=%d ctx=%d\n", cu.imv < 3, 4);