H.266/VVC代码学习16:帧内色度预测的编解码(intra_chroma_pred_modes)

引——色度预测:H.266/VVC代码学习7:VTM4.0帧内色度预测代码(estIntraPredChromaQT)
先放结论,VTM4.0中编码方式如下:
在这里插入图片描述
如果需要进一步研究请继续。

一、编码:CABACWriter

关于encodeBinsEP和encodeBin函数,可阅读:H.266/VVC代码学习24:常见的熵编码函数(encodeBin、encodeBinEP、encodeBinsEP)
调用的函数及结构如下

CABACWriter::

intra_chroma_pred_mode
	—intra_chroma_lmc_mode
		——unary_max_symbol
	—getIntraChromaCandModes

1 入口函数

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 );//对单个pu进行色度预测
}

2 处理方法

判断顺序:先看是否为DM,如是,编0返回。再看是否为CCLM模式,如是,编0返回。再看是否为MDLM模式,如是,编1。最后判断传统模式。请看代码:

void CABACWriter::intra_chroma_pred_mode( const PredictionUnit& pu )
{
  const unsigned intraDir = pu.intraDir[1];//获取色度预测模式

  /************ DM的处理 ***********/
  const bool     isDerivedMode = intraDir == DM_CHROMA_IDX;//是否为DM模式

  m_BinEncoder.encodeBin(isDerivedMode ? 0 : 1, Ctx::IntraChromaPredMode(0));//用常规编码器,是DM编0,不是编1

  if (isDerivedMode)//是DM就直接返回,即只编了一个0返回,否则编1继续进行下面。
  {
    return;
  }

  /************ LM的处理 ***********/
  if( pu.cs->sps->getUseLMChroma() )//如果使用了LM模式
  {
    intra_chroma_lmc_mode( pu );//是LM,进行LM的处理(内部函数会看到用常规编码器的两个码字来编这三种LM模式)
    if ( PU::isLMCMode( intraDir ) )//是LM的情况(模式67,68,69),直接返回,否则继续进行下面
    {
      return;
    }
  }

  /******** 其他模式的处理 *******/
  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 );//用旁路编码器,两个码字编列表中的序号。注意:编的是序号candId!
  }
}

3 LM模式的额外操作

LM模式中有很多预留,列表中有10个,而VTM4.0中用了三个。最后编码的是LM的序号symbol。

void CABACWriter::intra_chroma_lmc_mode( const PredictionUnit& pu )
{
  const unsigned intraDir = pu.intraDir[1];//看是67,68还是69
    int lmModeList[10];//设LM有10种(很多是预留的,并没有用上)
    int maxSymbol = PU::getLMSymbolList( pu, lmModeList );
    int symbol    = -1;
    for ( int k = 0; k < LM_SYMBOL_NUM; k++ )//找到symbol的序号
    {
      if ( lmModeList[k] == intraDir || ( lmModeList[k] == -1 && intraDir < LM_CHROMA_IDX ) )
      {
        symbol = k;
        break;
      }
    }
    CHECK( symbol < 0, "invalid symbol found" );

    unary_max_symbol(symbol, Ctx::IntraChromaPredMode(1), Ctx::IntraChromaPredMode(2), maxSymbol - 1);//编这个序号
}

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 );
  }
}

二、解码:CABACReader

调用的函数及结构如下

CABACReader::

intra_chroma_pred_mode
	—intra_chroma_lmc_mode
		——unary_max_symbol
	—getIntraChromaCandModes

整体来看就是编码的逆过程:

1 入口函数

void CABACReader::intra_chroma_pred_modes( CodingUnit& cu )
{
  if( cu.chromaFormat == CHROMA_400 || ( CS::isDualITree( *cu.cs ) && cu.chType == CHANNEL_TYPE_LUMA ) )
  {
    return;
  }

  PredictionUnit *pu = cu.firstPU;

  {
    CHECK( pu->cu != &cu, "Inkonsistent PU-CU mapping" );
    intra_chroma_pred_mode( *pu );
  }
}

2 处理方法

void CABACReader::intra_chroma_pred_mode( PredictionUnit& pu )
{
  RExt__DECODER_DEBUG_BIT_STATISTICS_CREATE_SET_SIZE2( STATS__CABAC_BITS__INTRA_DIR_ANG, pu.cu->blocks[pu.chType].lumaSize(), CHANNEL_TYPE_CHROMA );

  if (m_BinDecoder.decodeBin(Ctx::IntraChromaPredMode(0)) == 0)//第一位为0,直接解码为66
  {
    pu.intraDir[1] = DM_CHROMA_IDX;
    return;
  }

  // LM chroma mode
  if( pu.cs->sps->getUseLMChroma() )//第一位为1,则拿出第二三位,判断是哪种LM模式,解码出来
  {
    if( intra_chroma_lmc_mode( pu ) )
    {
      return;
    }
  }
  unsigned candId = m_BinDecoder.decodeBinsEP( 2 );//前面都不是,则看第四五位,得到一个序号

  unsigned chromaCandModes[ NUM_CHROMA_MODE ];
  PU::getIntraChromaCandModes( pu, chromaCandModes );

  CHECK( candId >= NUM_CHROMA_MODE, "Chroma prediction mode index out of bounds" );
  CHECK( PU::isLMCMode( chromaCandModes[ candId ] ), "The intra dir cannot be LM_CHROMA for this path" );
  CHECK( chromaCandModes[ candId ] == DM_CHROMA_IDX, "The intra dir cannot be DM_CHROMA for this path" );

  pu.intraDir[1] = chromaCandModes[ candId ];//获取列表,解码得出列表中对应的序号的模式
}

3 LM模式的额外操作

这里我还没仔细阅读,先放代码,以后填坑:

bool CABACReader::intra_chroma_lmc_mode( PredictionUnit& pu )
{
  int lmModeList[10];
  int maxSymbol = PU::getLMSymbolList(pu, lmModeList);
  int symbol    = unary_max_symbol(Ctx::IntraChromaPredMode(1), Ctx::IntraChromaPredMode(2), maxSymbol - 1);
  if (lmModeList[symbol] != -1)
  {
    pu.intraDir[1] = lmModeList[symbol];
    return true;
  }
  return false;
}

unsigned CABACReader::unary_max_symbol( unsigned ctxId0, unsigned ctxIdN, unsigned maxSymbol  )
{
  unsigned onesRead = 0;
  while( onesRead < maxSymbol && m_BinDecoder.decodeBin( onesRead == 0 ? ctxId0 : ctxIdN ) == 1 )
  {
    ++onesRead;
  }
  return onesRead;
}

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值