VTM代码阅读——encmain.cpp()

#include <time.h>
#include <iostream>
#include <chrono>
#include <ctime>

#include "EncoderLib/EncLibCommon.h"
#include "EncApp.h"
#include "Utilities/program_options_lite.h"

一些头文件,前一段是引入标准库,后面一段是自定义的头文件

static constexpr uint32_t settingNameWidth = 66;
static constexpr uint32_t settingHelpWidth = 84;
static constexpr uint32_t settingValueWidth = 3;
  • static:表示静态变量,具有静态存储持续时间,在整个程序执行期间都存在,并且只会被初始化一次。

  • constexpr:表示常量表达式,编译时就可以计算出结果并替换为常量值,通常用于声明编译期间就能确定的常量。

  • uint32_t:是C++中无符号32位整数类型的数据类型,表示范围在0到4294967295之间的整数。

  • settingNameWidth:是变量名,表示设置名称的宽度。

#define PRINT_CONSTANT(NAME, NAME_WIDTH, VALUE_WIDTH) std::cout << std::setw(NAME_WIDTH) << #NAME << " = " << std::setw(VALUE_WIDTH) << NAME << std::endl;
static void printMacroSettings()
{
  if( g_verbosity >= DETAILS )
  {
    std::cout << "Non-environment-variable-controlled macros set as follows: \n" << std::endl;

    //------------------------------------------------

    //setting macros

    PRINT_CONSTANT( RExt__DECODER_DEBUG_BIT_STATISTICS,                         settingNameWidth, settingValueWidth );
    PRINT_CONSTANT( RExt__HIGH_BIT_DEPTH_SUPPORT,                               settingNameWidth, settingValueWidth );
    PRINT_CONSTANT( RExt__HIGH_PRECISION_FORWARD_TRANSFORM,                     settingNameWidth, settingValueWidth );

    //------------------------------------------------

    std::cout << std::endl;
  }
}

上面这两块没看懂

主函数:

int main(int argc, char* argv[])

 C语言命令行参数详解-CSDN博客

c语言中main函数参数argc,argv说明,及命令行中如何传参数_c语言 argv 赋值-CSDN博客

  // print information
  //打印编码信息(编码器版本平台等)
  fprintf( stdout, "\n" );
  fprintf( stdout, "VVCSoftware: VTM Encoder Version %s ", VTM_VERSION );
  //fprintf( stdout, NVM_ONOS );
  fprintf( stdout, NVM_COMPILEDBY );
  fprintf( stdout, NVM_BITS );
#if ENABLE_SIMD_OPT
  std::string SIMD;
  ProgramOptionsLite::Options opts;
  opts.addOptions()("SIMD", SIMD, std::string(""), "")("c", ProgramOptionsLite::parseConfigFile, "");
  ProgramOptionsLite::SilentReporter err;
  ProgramOptionsLite::scanArgv(opts, argc, (const char**) argv, err);
  fprintf( stdout, "[SIMD=%s] ", read_x86_extension( SIMD ) );
#endif
#if ENABLE_TRACING
  fprintf( stdout, "[ENABLE_TRACING] " );
#endif
  fprintf( stdout, "\n" );

 //stdout, stdin, stderr的中文名字分别是标准输出,标准输入和标准错误。fprintf()函数根据指定的format(格式)发送信息(参数)到由stream(流)指定的文件.因此fprintf()可以使得信息输出到指定的文件 

/if endif 后为0执行 endif 后的程序,为1执行其中的程序。

  std::fstream bitstream;
  EncLibCommon encLibCommon;

//fstream是用using为basic_fstream这个类起的一个别名,bitstream是实例化的对象。规定了与C流相关联的输入/输出流  

 std::vector<EncApp*> pcEncApp(1);
  bool resized = false;
  int layerIdx = 0;
//初始化rom.cpp中的一些全局变量
initROM();

char** layerArgv = new char*[argc];
//遍历layers创建pcEncApp并初始化各个layer的参数

//在堆区开辟一块内存,存入命令行输入的每个参数的地址,然后用新建的指针 layerArgv来接收,这个指针(指向一块内存地址,该内存地址中存储的是 char* 类型的数据。指针的加减运算在这里的体现为: layerArgv + 1 表示地址加 8 字节(在 32 位系统中,地址加 4 字节)

do
  {
    pcEncApp[layerIdx] = new EncApp( bitstream, &encLibCommon );
    // create application encoder class per layer
    pcEncApp[layerIdx]->create();

    // parse configuration per layer
    //为当前遍历的layer初始化配置
    try
    {
      int j = 0;
      for( int i = 0; i < argc; i++ )
      {
        if( argv[i][0] == '-' && argv[i][1] == 'l' )
        {
          if (argc <= i + 1)
          {
            THROW("Command line parsing error: missing parameter after -lx\n");
          }
          int numParams = 1; // count how many parameters are consumed
          // 检查以“——”开头的长参数。
          const std::string param = argv[i + 1];
          if (param.rfind("--", 0) != 0)
          {
            // only short parameters have a second parameter for the value
            if (argc <= i + 2)
            {
              THROW("Command line parsing error: missing parameter after -lx\n");
            }
            numParams++;
          }
          // 检查图层索引是否正确
          if( argv[i][2] == std::to_string( layerIdx ).c_str()[0] )
          {
            layerArgv[j] = argv[i + 1];
            if (numParams > 1)
            {
              layerArgv[j + 1] = argv[i + 2];
            }
            j+= numParams;
          }
          i += numParams;
        }
       

这一段是解析每层的配置,在命令行参数为5的情况时,i的值从0~4,将5个命令行参数的地址分别赋给了layerArgv[j],如果命令函参数出错,则报错检查 

 else
        {
          layerArgv[j] = argv[i];
          j++;
        }
      }

//前面定义的layerArgv是开辟的一块内存来存储命令行参数argc地址的,比如这里存了5个地址,这里就是给这个地址作个排序,按顺序赋给 layerArgv 

//解析输入的参数
      if( !pcEncApp[layerIdx]->parseCfg( j, layerArgv ) )
      {
        pcEncApp[layerIdx]->destroy();
        return 1;
      }
    }
    catch (ProgramOptionsLite::ParseFailure& e)
    {
      std::cerr << "Error parsing option \"" << e.arg << "\" with argument \"" << e.val << "\"." << std::endl;
      return 1;
    }

    pcEncApp[layerIdx]->createLib( layerIdx );

    if( !resized )
    {
      pcEncApp.resize( pcEncApp[layerIdx]->getMaxLayers() );
      resized = true;
    }

    layerIdx++;
  } while( layerIdx < pcEncApp.size() );
  //结束对各个layer的遍历初始化
 delete[] layerArgv;

记录开始编码的时间

//**********************从此处开始计算编码时间*********
  // 记录开始编码的时间
  // starting time
  auto startTime  = std::chrono::steady_clock::now();
  std::time_t startTime2 = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
  fprintf(stdout, " started @ %s", std::ctime(&startTime2) );
  clock_t startClock = clock();

编码器将多张图像进行编码后生产成一段一段的 GOP ( Group of Pictures ) , 解码器在播放时则是读取一段一段的 GOP 进行解码后读取画面再渲染显示。GOP ( Group of Pictures) 是一组连续的画面,由一张 I 帧和数张 B / P 帧组成,是视频图像编码器和解码器存取的基本单位,它的排列顺序将会一直重复到影像结束。GOP即Group of picture(图像组),指两个I帧之间的距离。一个序列的第一个图像叫做 IDR 图像(立即刷新图像),IDR 图像都是 I 帧图像。

 bool eos = false;//eos:End Of Sequence,代表一个gop中的最后一帧。如果eos为true,则代表已经读取到输入视频的最后一帧

eos:End Of Sequence,代表一个gop中的最后一帧。如果eos为true,则代表已经读取到输入视频的最后一帧 

//大循环直到编码完序列的所有帧才结束
  while( !eos )
  {
    // read GOP
    //编码前的预处理,主要作用有从输入视频中读取一帧,给帧分配缓存(存在EncLib的属性m_cListPic中),设置对应的CS
    //keepLoop用于记录当前的GOP是否已经编完,若编完则true,否则False,这里初始化为true
    bool keepLoop = true;
    //小循环遍历当前的GOP内的所有帧进行预处理
    while( keepLoop )
    {
      for( auto & encApp : pcEncApp )
      {
#ifndef _DEBUG
        try
        {
#endif
          //对当前GOP内的帧进行预处理的入口函数,keeploop是预处理函数的输出,若已处理完当前GOP所有帧则为true,否则为false
          keepLoop = encApp->encodePrep( eos );
 // encode GOP
    //正式编码开始
    keepLoop = true;
    //小循环遍历当前的GOP内的所有帧进行编码
    while( keepLoop )
    {
      for( auto & encApp : pcEncApp )
      {
#ifndef _DEBUG
        try
        {
#endif
          //编码当前帧的入口函数,与预处理的函数一样,keeploop是输出,若已处理完当前GOP所有帧则为true,否则为false
          keepLoop = encApp->encode();
#ifndef _DEBUG
        }

 编码预处理后keeploop的值变成了false,结束了while循环,keepLoop = encApp->encode();

  • 6
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值