HM--TAppEncoder 函数调用关系图以及编码入口

版权声明:转载请注明出处 https://blog.csdn.net/weixin_42683993/article/details/88085638

HM代码分析–TAppEncoder
一.函数调用关系图
HM中的HEVC视频编码器TAppEncoder的函数调用关系图如下所示。

在这里插入图片描述

下面解释一下图中关键标记的含义。

1.函数背景色
函数在图中以方框的形式表现出来。不同的背景色标志了该函数不同的作用:
白色背景的函数:不加区分的普通内部函数。
黄色背景函数:滤波函数(Filter)。用于环路滤波,半像素插值,SSIM/PSNR的计算。
绿色背景的函数:CU编码函数(Encode)。通过对残差的DCT变换、量化等方式对CU进行编码。
紫色背景的函数:熵编码函数(Entropy Coding)。对CU编码后的数据进行CABAC熵编码。
浅蓝色背景函数:码率控制函数(Rate Control)。对码率进行控制的函数。

2.箭头线
箭头线标志了函数的调用关系:
黑色箭头线:不加区别的调用关系。
黄色箭头线:滤波函数(Filter)之间的调用关系。
绿色箭头线:CU编码函数(Encode)之间的调用关系。
紫色箭头线:熵编码函数(Entropy Coding)之间的调用关系。

3.下文记录结构图中的几个关键部分。

1)普通内部函数
普通内部函数指的是TAppEncoder中还没有进行分类的函数。例如:
编码器的main()函数中调用的TAppEncTop类的配置读取函数parseCfg()、编码函数encode()等。
编码器最主要的函数:TEncTop中的encode()、TEncGOP中的compressGOP()、TEncSlice的compressSlice()等。

2)CU编码函数
CU编码函数通过运动估计、DCT变换、量化等步骤对图像数据进行编码。编码的工作都是在TEncCu类中的compressCtu()中完成的。compressCtu()调用了xCompressCU()完成了CU的编码工作。xCompressCU()本身是一个递归调用的函数,其中的xCheckRDCostInter()完成了分析帧间CU编码代价的工作;其中的xCheckRDCostIntra()则完成了分析帧内CU编码代价的工作。

3)熵编码函数
熵编码函数使用CABAC的方式对CU编码后的数据进行熵编码。熵编码的工作都是在TEncCu类中的encodeCtu()中完成的。

4)环路滤波函数
环路滤波函数对重建帧数据进行滤波,去除方块效应和振铃效应。TComLoopFilter类的loopFilterPic()完成了去块效应滤波器的工作; TComSampleAdaptiveOffset类的SAOProcess()完成了去除振铃效应的SAO滤波器的工作。

5)码率控制函数
码率控制模块函数分布在lencod源代码不同的地方,包括rc_init_seq()、rc_init_GOP()、rc_init_frame()、rc_handle_mb()等。

二.TAppEncoder 具体流程
1.从编码端入手,在TAppEncoder中我们可以看到有一个encmain.cpp文件,这个文件即是编码的主函数。
在这里插入图片描述
在encmain.cpp中主要做了以下几件事:
![![在这里插入图片描述](https://img-blog.csdnimg.cn/20190303105029616.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MjY4Mzk5Mw==,size_16,color_FFFFFF,t_70]
其中TAppEncTop继承自TAppEncCfg,在父类TAppEncCfg中,定义了大量成员变量来保存参数,子类TAppEncTop中除了父类的成员外,还包括编码所需要的各种成员变量和成员方法。

encmain.cpp的代码(HM16.6):

 <span style="font-size:14px;">int main(int argc, char* argv[])
{
  TAppEncTop  cTAppEncTop; //定义cTAppEncTop
 
  // print information 打印信息并标准输出HM版本信息
  fprintf( stdout, "\n" );
  fprintf( stdout, "HM software: Encoder Version [%s] (including RExt)", NV_VERSION );
  fprintf( stdout, NVM_ONOS );
  fprintf( stdout, NVM_COMPILEDBY );
  fprintf( stdout, NVM_BITS );
  fprintf( stdout, "\n\n" );
 
  // create application encoder class
  cTAppEncTop.create(); //创建encoder类,实际create是一个空函数,不做任何操作。
 
  // parse configuration 解析cfg配置文件
  try
  {
    if(!cTAppEncTop.parseCfg( argc, argv ))//如果cfg文件正确,会调用xCheckParameter函数,在命令行窗口中输出解析提示,并调用xPrintParameter来回显参数
    {
      cTAppEncTop.destroy(); //如果cfg文件错误,调用destroy函数,实际也是一个空函数,不做任何操作。
#if ENVIRONMENT_VARIABLE_DEBUG_AND_TEST
      EnvVar::printEnvVar();
#endif
      return 1;
    }
  }
  catch (df::program_options_lite::ParseFailure &e) //异常处理,如果cfg文件错误时回显错误提示
  {
    std::cerr << "Error parsing option \""<< e.arg <<"\" with argument \""<< e.val <<"\"." << std::endl;
    return 1;
  }
 
#if PRINT_MACRO_VALUES //打印宏块值
  printMacroSettings();
#endif
 
#if ENVIRONMENT_VARIABLE_DEBUG_AND_TEST
  EnvVar::printEnvVarInUse();
#endif
 
  // starting time
  Double dResult;
  clock_t lBefore = clock(); //计时
 
  // call encoding function
  cTAppEncTop.encode(); //调用encode函数,进行编码
 
  // ending time
  dResult = (Double)(clock()-lBefore) / CLOCKS_PER_SEC; //计时结果
  printf("\n Total Time: %12.3f sec.\n", dResult); //显示计时结果
 
  // destroy application encoder class
  cTAppEncTop.destroy();  //调用destroy函数
 
  return 0;
}</span>

2.在"encode"函数中,主要实现了读取YUV文件的数据、初始化工具对象例如:GOPEncoder、SliceEncoder、CUEncder……。在此函数里,还包括一个encode函数,调用CompressGOP函数来具体执行编码任务。

3.在CompressGOP函数中,完成了以下的功能:

  • 1)InitGOP将文件的码流分成若干GOP以便后续程序能够顺利执行。
    2)InitEncSlice创建编码的Slice。
    3)preCompressSlice和CompressSlice两个函数,前者的作用是选择不同的lamuda进行编码(编码是调用了CompressCU函数,后续介绍),后者是在最好的lamuda下进行编码。
    4)循环滤波, DB, ALF, SAO等
    5)cabac。

下面跟踪下帧内预测:

4.在xCompressCU函数中(CompressCU函数的主体也是调用xComprssCU函数),先进行帧间预测xCheckRDCostMerge2Nx2N,xCheckRDCostInter等。在做完帧间预测后进行帧内预测,这是调用的函数是xCheckRDCostIntra,在xCompressCU函数的后续部分,还递归调用自身以实现对每个CU的编码。变换编码在encodeCoeff中实现,量化在xCheckIntraPCM完成。

5.xCheckRDCostIntra函数,主要完成帧内预测的任务,对亮度的预测使用estIntraPredQT,对色度使用estIntraPredChromaQT。

6.estIntraPredQT函数,在思想对亮度的处理和色度的处理是一样的,所以只介绍亮度的处理函数。在estIntraPredQT函数中,主要完成了RDCost的选择,在其中predIntraLumaAng函数实现了方向的预测;calcHAD函数计算了SATD;xModeBitsIntra函数计算编码的码率;xUpdateCandList更新了最好的RDCost所使用的模式。

猜你喜欢

转载自blog.csdn.net/weixin_42683993/article/details/88085638