H.266/VVC VTM阅读2-CU预测信息编码

  本文以bcw索引为例,记录VTM中CU预测信息编码的过程。进行决策时一种调用顺序是:
  EncSlice::compressSlice() ->
  EncSlice::encodeCtus() ->
  EncCu::xCompressCU() ->
  EncCu::xCheckRDCostInter() ->
  EncCu::xEncodeInterResidual() ->
  InterSearch::encodeResAndCalcRdInterCU() ->
  InterSearch::xGetSymbolFracBitsInter() ->
  CABACWriter::cu_pred_data() ->
  CABACWriter::cu_gbi_flag() ->
  TBinEncoder::encodeBin()
  
  进行编码时调用顺序是:
  EncSlice::encodeSlice() ->
  CABACWriter::coding_tree_unit() ->
  CABACWriter::coding_tree() ->
  CABACWriter::coding_unit() - >
  CABACWriter::cu_pred_data() ->
  CABACWriter::cu_gbi_flag() ->
  TBinEncoder::encodeBin()。
  
  实际进行CU预测信息编码操作是 CABACWriter::cu_pred_data()->CABACWriter::cu_gbi_flag() ->TBinEncoder::encodeBin()结构。

1、void TBinEncoder::encodeBin()

  根据预测模型,对一个二进制位编码,满足条件时将一个字节写到码流中。

template 
void TBinEncoder::encodeBin( unsigned bin, unsigned ctxId )
{
  BinCounter::addCtx( ctxId );
  BinProbModel& rcProbModel = m_Ctx[ctxId];
  uint32_t      LPS         = rcProbModel.getLPS( m_Range );

  DTRACE( g_trace_ctx, D_CABAC, "%d" " %d " "%d" "  " "[%d:%d]" "  " "%2d(MPS=%d)"  "  " "  -  " "%d" "\n", DTRACE_GET_COUNTER( g_trace_ctx, D_CABAC ), ctxId, m_Range, m_Range - LPS, LPS, ( unsigned int ) ( rcProbModel.state() ), bin == rcProbModel.mps(), bin );

  m_Range   -=  LPS;
  if( bin != rcProbModel.mps() )
  {
    int numBits   = rcProbModel.getRenormBitsLPS( LPS );
    m_bitsLeft   -= numBits;
    m_Low        += m_Range;
    m_Low         = m_Low << numBits;
    m_Range       = LPS   << numBits;
    if( m_bitsLeft < 12 )
    {
      writeOut();
    }
  }
  else
  {
    if( m_Range < 256 )
    {
      int numBits   = rcProbModel.getRenormBitsRange( m_Range );
      m_bitsLeft   -= numBits;
      m_Low       <<= numBits;
      m_Range     <<= numBits;
      if( m_bitsLeft < 12 )
      {
        writeOut();
      }
    }
  }
  rcProbModel.update( bin );
  BinEncoderBase::m_BinStore.addBin( bin, ctxId );
}
2、void CABACWriter::cu_gbi_flag()

  按照索引的编码顺序进行编码,对于LD模式,有5种索引,对于RA模式有3种索引。首先使用上下文编码一位,表示是否为等权重,如果不是,使用旁路编码(encodeBinEP()函数)来编码剩余索引。

void CABACWriter::cu_gbi_flag(const CodingUnit& cu)
{
  if(!CU::isGBiIdxCoded(cu))
  {
    return;
  }

  CHECK(!(GBI_NUM > 1 && (GBI_NUM == 2 || (GBI_NUM & 0x01) == 1)), " !( GBI_NUM > 1 && ( GBI_NUM == 2 || ( GBI_NUM & 0x01 ) == 1 ) ) ");
  const uint8_t gbiCodingIdx = (uint8_t)g_GbiCodingOrder[CU::getValidGbiIdx(cu)];

  const int32_t numGBi = (cu.slice->getCheckLDC()) ? 5 : 3;
#if JVET_O0126_BPWA_INDEX_CODING_FIX
  m_BinEncoder.encodeBin((gbiCodingIdx == 0 ? 0 : 1), Ctx::GBiIdx(0));
#else
  m_BinEncoder.encodeBin((gbiCodingIdx == 0 ? 1 : 0), Ctx::GBiIdx(0));
#endif
  if(numGBi > 2 && gbiCodingIdx != 0)
  {
    const uint32_t prefixNumBits = numGBi - 2;
    const uint32_t step = 1;

    uint8_t idx = 1;
    for(int ui = 0; ui < prefixNumBits; ++ui)
    {
      if (gbiCodingIdx == idx)
      {
#if JVET_O0126_BPWA_INDEX_CODING_FIX
        m_BinEncoder.encodeBinEP(0);
#else
        m_BinEncoder.encodeBinEP(1);
#endif
        break;
      }
      else
      {
#if JVET_O0126_BPWA_INDEX_CODING_FIX
        m_BinEncoder.encodeBinEP(1);
#else
        m_BinEncoder.encodeBinEP(0);
#endif
        idx += step;
      }
    }
  }

  DTRACE(g_trace_ctx, D_SYNTAX, "cu_gbi_flag() gbi_idx=%d\n", cu.GBiIdx ? 1 : 0);
}

3、void CABACWriter::cu_pred_data()

  对CU的预测信息进行编码,如果是帧内CU编码预测模式后返回,如果是帧间CU调用prediction_unit()函数编码pu级预测信息,然后编码cu级预测信息。

void CABACWriter::cu_pred_data( const CodingUnit& cu )
{
  if( CU::isIntra( cu ) )
  {
    intra_luma_pred_modes  ( cu );
    intra_chroma_pred_modes( cu );
    return;
  }
  if (!cu.Y().valid()) // dual tree chroma CU
  {
    return;
  }
  for( auto &pu : CU::traversePUs( cu ) )
  {
    prediction_unit( pu );
  }

  imv_mode   ( cu );
  affine_amvr_mode( cu );

  cu_gbi_flag( cu );

}

你可能感兴趣的:(H.266/VVC,视频编码)