VTM1.0代码阅读:coding_unit函数

coding_unit函数在coding_tree中被调用,来对一个cu中的所有预测信息、变换系数等信息进行编码。
其实对一个cu的编码,主要编码3个信息:预测模式、预测数据、变换系数。

void CABACWriter::coding_unit( const 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 )
  {
     
    CHECK( !cu.firstPU->mergeFlag, "Merge flag has to be on!" );
    PredictionUnit&   pu = *cu.firstPU;
    prediction_unit ( pu );				//skip模式时编码预测数据:merge_idx
    end_of_ctu      ( cu, cuCtx );		//如果ctu结束,编码一个0(一帧最后一个ctu不编码这个0)
    return;
  }

  // prediction mode and partitioning data
  pred_mode ( cu );						//编码帧内还是帧间
#if HEVC_USE_PART_SIZE
  part_mode ( cu );
#endif

  // pcm samples
  if( CU::isIntra(cu) && cu.partSize == SIZE_2Nx2N )
  {
     
    pcm_data( cu );			//pcm模式
    if( cu.ipcm )
    {
     
      end_of_ctu( cu, cuCtx );
      return;
    }
  }

  // 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 );	//残差数据,变换系数的编码

  // end of cu
  end_of_ctu( cu, cuCtx );				//如果ctu结束,编码一个0(一帧最后一个ctu不编码这个0)
}
//编码帧内还是帧间预测模式
void CABACWriter::pred_mode( const CodingUnit& cu )
{
     
  if( cu.cs->slice->isIntra() )		//I帧时默认帧内模式,不用编码
  {
     
    return;
  }							//不是I帧时,intra编码1,inter编码0
  m_BinEncoder.encodeBin( ( CU::isIntra( cu ) ), Ctx::PredMode() );
}
//编码具体的在预测模式下的预测信息
void CABACWriter::cu_pred_data( const CodingUnit& cu )
{
     
  if( CU::isIntra( cu ) )
  {
     
    intra_luma_pred_modes  ( cu );		//对亮度帧内模式和色度帧内模式的编码,帧内模式号的编码没细看
    intra_chroma_pred_modes( cu );
    return;
  }
  for( auto &pu : CU::traversePUs( cu ) )
  {
     
    prediction_unit( pu );				//帧间模式的编码
  }
}
//帧间模式的编码,即编码skip模式、merge模式、inter_ME模式
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 )
  {
     							//skip模式编码skip_flag之后,默认merge_flag为true,不用编码merge_flag
    CHECK( !pu.mergeFlag, "merge_flag must be true for skipped CUs" );
  }
  else
  {
     
    merge_flag( pu );		//merge_flag编码,表示是否为merge模式
  }
  if( pu.mergeFlag )
  {
     
    merge_idx    ( pu );	//merge_flag为true,再编码merge_idx
  }
  else						//merge_flag为false,则为inter_ME模式
  {
     
    inter_pred_idc( pu );					//编码帧间预测方向:编码00表示前向、编码01表示后向、编码1表示双向
    if( pu.interDir != 2 /* PRED_L1 */ )	//即第一个码区分单向双向,第二个码区分前向后向
    {
     
      ref_idx     ( pu, REF_PIC_LIST_0 );	//前向的refIdx、mvd以及AMVP列表中的mvp_Idx
      {
     
        mvd_coding( pu.mvd[REF_PIC_LIST_0] );
      }
      mvp_flag    ( pu, REF_PIC_LIST_0 );
    }
    if( pu.interDir != 1 /* PRED_L0 */ )	//后向的refIdx、mvd以及AMVP列表中的mvp_Idx
    {
     
      ref_idx     ( pu, REF_PIC_LIST_1 );
      if( !pu.cs->slice->getMvdL1ZeroFlag() || pu.interDir != 3 /* PRED_BI */ )
      {
     
        {
     
          mvd_coding( pu.mvd[REF_PIC_LIST_1] );		//单向的后向预测,或不是广义B帧时,编码后向的mvd
        }
      }
      mvp_flag    ( pu, REF_PIC_LIST_1 );
    }
  }
}
//如果编码的cu为ctu的最后一个cu,则编码一个0表示ctu结束(ctu若为一帧中的最后一个ctu时不编码这个0)
void CABACWriter::end_of_ctu( const CodingUnit& cu, CUCtx& cuCtx )
{
     
  const Slice*  slice             = cu.cs->slice;
  const int     currentCTUTsAddr  = CU::getCtuAddr( cu );
  const bool    isLastSubCUOfCtu  = CU::isLastSubCUOfCtu( cu );
												//DualITree时,编码完ctu色度分量的最后一个cu,才编码0
  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 );//当前cu如果是ctu中的最后一个cu,而且ctu不是一帧中的最后一个ctu,则编码一个0,表示ctu编码结束
    }
  }
}

你可能感兴趣的:(VTM1.0代码阅读:coding_unit函数)