VTM1.0代码阅读:解码端coding_unit函数

解码端coding_unit函数在coding_tree函数中被调用,用来解码一个cu的预测模式、残差等信息。
其实,编码端的coding_unit是如何编码的,解码端的coding_unit按照相同的顺序如何解码就行。
函数return一个bool值,表示当前cu是否是这一帧的最后一个cu。
主要解码三个信息:预测模式、预测数据、残差数据。

bool CABACReader::coding_unit( CodingUnit &cu, Partitioner &partitioner, CUCtx& cuCtx )
{
  CodingStructure& cs = *cu.cs;

  // transquant bypass flag
  if( cs.pps->getTransquantBypassEnabledFlag() )
  {
    cu_transquant_bypass_flag( cu );	//变换系数旁路编码标志
  }

  // skip flag
  if( !cs.slice->isIntra() )
  {
    cu_skip_flag( cu );					//skip模式时的skip_flag
  }

  // skip data
  if( cu.skip )
  {
    cs.addTU         ( cu, partitioner.chType );
    PredictionUnit&    pu = cs.addPU( cu, partitioner.chType );
    MergeCtx           mrgCtx;			//merge候选列表
    prediction_unit  ( pu, mrgCtx );	//解码skip模式数据,构建merge列表,解码得到merge_idx,从而得到skip模式信息
    return end_of_ctu( cu, cuCtx );
  }

  // prediction mode and partitioning data
  pred_mode ( cu );						//解码帧内还是帧间
  
  cu.partSize = SIZE_2Nx2N;

  // --> create PUs
  CU::addPUs( cu );

  // pcm samples
  if( CU::isIntra(cu) && cu.partSize == SIZE_2Nx2N )
  {
    pcm_flag( cu );				//pcm模式
    if( cu.ipcm )
    {
      TransformUnit& tu = cs.addTU( cu, partitioner.chType );
      pcm_samples( tu );
      return end_of_ctu( cu, cuCtx );
    }
  }

  // prediction data ( intra prediction modes / reference indexes + motion vectors )
  cu_pred_data( cu );			//预测信息的解码,帧内亮度色度的具体模式,或帧间的merge_Idx、refIdx、mv、mvd等这些

  // residual data ( coded block flags + transform coefficient levels )
  cu_residual( cu, partitioner, cuCtx );	//残差数据,变换系数的解码

  // check end of cu
  return end_of_ctu( cu, cuCtx );		//return当前cu是否是这一帧的最后一个cu
}
//解码帧内帧间
void CABACReader::pred_mode( CodingUnit& cu )
{
  RExt__DECODER_DEBUG_BIT_STATISTICS_CREATE_SET( STATS__CABAC_BITS__PRED_MODE );

  if( cu.cs->slice->isIntra() || m_BinDecoder.decodeBin( Ctx::PredMode() ) )
  {										//I帧,或解码为1,则为帧内
    cu.predMode = MODE_INTRA;
  }
  else
  {
    cu.predMode = MODE_INTER;
  }
}
//解码cu的预测数据
void CABACReader::cu_pred_data( CodingUnit &cu )
{
  if( CU::isIntra( cu ) )
  {
    intra_luma_pred_modes( cu );
    intra_chroma_pred_modes( cu );		//解码帧内预测的模式信息,亮度模式和色度模式
    return;
  }

  MergeCtx mrgCtx;		//merge列表,好像没啥用,prediction_unit中用不到

  for( auto &pu : CU::traversePUs( cu ) )	//对于cu下的所有pu
  {
    prediction_unit( pu, mrgCtx );		//解码帧间预测的数据,包括skip、merge、inter_ME模式
  }
}

//解码帧间预测的数据,包括skip、merge、inter_ME模式
void CABACReader::prediction_unit( PredictionUnit& pu, MergeCtx& mrgCtx )
{
  if( pu.cu->skip )
  {
    pu.mergeFlag = true;		//skip_flag为真时,skip模式默认merge_flag为true
  }
  else
  {
    merge_flag( pu );		//merge和inter_ME模式需要解码merge_falg
  }
  if( pu.mergeFlag )		//merge模式
  {
    merge_data   ( pu );	//解码merge_idx
  }
  else				//inter_ME模式
  {
    inter_pred_idc( pu );		//解码帧间预测方向,00表示前向、01表示后向、1表示双向

    if( pu.interDir != 2 /* PRED_L1 */ )		//解码前向预测信息,refIdx、mvd、mvpIdx
    {
      ref_idx     ( pu, REF_PIC_LIST_0 );
      {
        mvd_coding( pu.mvd[REF_PIC_LIST_0] );
      }
      mvp_flag    ( pu, REF_PIC_LIST_0 );
    }
    if( pu.interDir != 1 /* PRED_L0 */ )		//解码后向预测信息,refIdx、mvd、mvpIdx
    {
      ref_idx     ( pu, REF_PIC_LIST_1 );
      if( pu.cu->cs->slice->getMvdL1ZeroFlag() && pu.interDir == 3 /* PRED_BI */ )
      {
        pu.mvd[ REF_PIC_LIST_1 ] = Mv();
      }
      else
      {
        mvd_coding( pu.mvd[REF_PIC_LIST_1] );
      }
      mvp_flag    ( pu, REF_PIC_LIST_1 );
    }
  }
  if( pu.interDir == 3 /* PRED_BI */ && PU::isBipredRestriction(pu) )
  {
    pu.mv    [REF_PIC_LIST_1] = Mv(0, 0);
    pu.refIdx[REF_PIC_LIST_1] = -1;
    pu.interDir               =  1;
  }

  PU::spanMotionInfo( pu, mrgCtx );			//将pu解码得到的信息,扩展到pu所在区域的所有小块
}
//解码ctu结束时的标志bit 0,return当前cu是否是一帧的最后一个cu
bool CABACReader::end_of_ctu( CodingUnit& cu, CUCtx& cuCtx )
{
  const SPS     &sps   = *cu.cs->sps;				//rbPox为cu的右下角顶点的坐标
  const Position rbPos = recalcPosition( cu.chromaFormat, cu.chType, CHANNEL_TYPE_LUMA, cu.blocks[cu.chType].bottomRight().offset( 1, 1 ) );

  if ( ( ( rbPos.x & cu.cs->pcv->maxCUWidthMask  ) == 0 || rbPos.x == sps.getPicWidthInLumaSamples () )
    && ( ( rbPos.y & cu.cs->pcv->maxCUHeightMask ) == 0 || rbPos.y == sps.getPicHeightInLumaSamples() )
    && ( !CS::isDualITree( *cu.cs ) || cu.chromaFormat == CHROMA_400 || isChroma( cu.chType ) )
      )				//DualITree的luma时,并不会解码这个ctu结束标志。DualITree的色度cu解码完成时才会解码这个ctu结束码
  {
    cuCtx.isDQPCoded = ( cu.cs->pps->getUseDQP() && !cuCtx.isDQPCoded );

    return terminating_bit();			//return当前帧是否已经解码完成
  }

  return false;		//cu如果不是ctu的最后一个,直接false
}
bool CABACReader::terminating_bit()		//解码ctu的结束标志,以此判断并return当前帧是否已经解码完成
{
  if( m_BinDecoder.decodeBinTrm() )		//解码编码端在ctu结束后编码的那个0
  {										//如果解码为0,return false;表示当前ctu并不是一帧的最后一个ctu
    m_BinDecoder.finish();				//如果解码为1,if条件满足,即当前cu为一帧的最后一个cu,再解码尾部剩余bit,返回true,即一帧解码完成
	
    m_Bitstream->readOutTrailingBits();
    return true;
  }
  return false;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值