文章目录
- encmain.cpp
- 引入的库
- 执行主体
- 1. 读取输入的配置文件
- 2. 编码启动和过程计时
- 实现细节
- 1. cTAppEncTop.parseCfg( argc, argv );
- 2. df::program_options_lite::ParseFailure;
- 3. EnvVar::printEnvVar();
- 4. EnvVar::printEnvVarInUse();
- 5. printMacroSettings();
- 执行流程
encmain.cpp
encmain.cpp是TAppEncoder的入口主文件,编码器从该文件启动编码。完成的工作为初始化最外层的编码类,导入和测试配置文件的参数,调用编码函数并进行计时。
引入的库
#include <time.h> //用于计算编码用时
#include <iostream> //用于输出调试和错误信息
#include "TAppEncTop.h" //最外层的编码类,集成了大量用于编码的函数和类
#include "Utilities/program_options_lite.h" //公共库中用于检测配置文件中的参数的类
#include "../Lib/TLibCommon/Debug.h" //公共库中用于调试的类
执行主体
int main(int argc, char* argv[])
argc和argv参数在用命令行编译程序时有用。在main( int argc, char* argv[], char ** env ) 中
第一个参数,int型的argc,为整型,用来统计程序运行时发送给main函数的命令行参数的个数,在VS中默认值为1。
第二个参数,char*型的argv[],为字符串数组,用来存放指向的字符串参数的指针数组,每一个元素指向一个参数。各成员含义如下:
argv[0]指向程序运行的全路径名
argv[1]指向在DOS命令行中执行程序名后的第一个字符串
argv[2]指向执行程序名后的第二个字符串
argv[3]指向执行程序名后的第三个字符串
argv[argc]为NULL
第三个参数,char** 型的env,为字符串数组。env[]的每一个元素都包含ENVVAR=value形式的字符串,其中ENVVAR为环境变量,value为其对应的值。平时使用到的比较少。
在这里,char** argv表示的是在属性中设置的配置文件的绝对路径:-c XX.cfg
1. 读取输入的配置文件
TAppEncTop cTAppEncTop;//创建第一层即最外层的编码类
/*
打印HM的版本信息,使用了CommonDef.h定义的常量,该文件在../Lib/TLibCommon/Debug.h中引用。省略该部分代码
*/
cTAppEncTop.create();//创建编码类,实际是空操作
//尝试解析配置文件
try
{
if(!cTAppEncTop.parseCfg( argc, argv ))//检测配置参数
{
cTAppEncTop.destroy(); //如果cfg文件错误,调用destroy函数,实际也是一个空函数,不做任何操作
#if ENVIRONMENT_VARIABLE_DEBUG_AND_TEST
EnvVar::printEnvVar();//调试时打印环境变量(自定义EnvVar类的成员)
#endif
return 1;//结束程序
}
}
catch (df::program_options_lite::ParseFailure &e)//df命名空间在program_options_lite.h中,使用自定义的错误类ParseFailure ,输出异常信息
{
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
2. 编码启动和过程计时
Double dResult;
clock_t lBefore = clock();//开始计时
cTAppEncTop.encode();// 执行编码函数
dResult = (Double)(clock()-lBefore) / CLOCKS_PER_SEC;// 计算编码用时
printf("\n Total Time: %12.3f sec.\n", dResult);
cTAppEncTop.destroy(); //销毁编码实例
return 0;//结束
实现细节
1. cTAppEncTop.parseCfg( argc, argv );
功能:将配置文件的参数设置到类中
//代码有接近1400行,此处简要分析,是继承自基类TAppEncCfg的方法
Bool TAppEncCfg::parseCfg( Int argc, TChar* argv[] ){
//1.使用SMultiValueInput类或其他容器设置各类参数的默认值范围,例如,
SMultiValueInput<UInt> cfg_rwpSEIRwpTransformType (0, 7, 0, std::numeric_limits<UChar>::max());
//2.利用options类保存参数的默认配置,例如,
po::Options opts;
opts.addOptions()
(..)(..)(..);//参数列表
//参数列表的结构类似于下例,(键值,键,值,说明)
("InputFile,i",m_inputFileName, string(""), "Original YUV input file name")
//完成参数默认设置
po::setDefaults(opts);
//3.读取并检测配置文件的参数
po::scanArgv(opts, argc, (const TChar**) argv, err);
//4.计算和选择各类派生属性,开始逐项配置TAppEncCfg的成员属性,同时检测输出对应参数错误的信息
//5.检查输入参数的有效性
xCheckParameter();
//打印配置好的参数
xPrintParameter();
}
TChar是C++为了消除不同机器的char字节数不同而设置的。
如果字符串是ANSI编码的,TChar等同于char,是单字节的。
如果是字符串是UNICODE编码的,TChar 等同于unsigned short 类型,是双字节,。
比如汉字版和一些扩展权字符都是2个字节表示的, 刚好可以和这个类型对应上
opts.addOptions()返回一个OptionSpecific型对象
OptionSpecific Options::addOptions() { return OptionSpecific(*this); }
而该派生类重载了操作符(),执行基类添加参数的操作,并返回调用者本身,故可连续使用多个(),表示反复调用添加参数
OptionSpecific&
operator()(const std::string& name, OptionFunc::Func *func, const std::string& desc = "")
{
parent.addOption(new OptionFunc(name, parent, func, desc));
return *this;
}
添加的参数类别有以下几类:
File, I/O and source parameters、Field coding parameters、Profile and level、Unit definition parameters、todo: remove defaults from MaxCUSize、…
2. df::program_options_lite::ParseFailure;
功能:简单的自定义错误类
//继承自exception类
struct ParseFailure : public std::exception
{
ParseFailure(std::string arg0, std::string val0) throw()
: arg(arg0), val(val0)
{}
~ParseFailure() throw() {};
std::string arg;
std::string val;
const char* what() const throw() { return "Option Parse Failure"; }
};
3. EnvVar::printEnvVar();
功能:打印设置的环境变量
Void EnvVar::printEnvVar()
{
// getEnvVarList().unique(sameEnvName);
if (getEnvVarList().size()!=0)
{
std::cout << "--- Environment variables:\n" << std::endl;
for_each(getEnvVarList().begin(), getEnvVarList().end(), printPair);
}
std::cout << std::endl;
}
其中,printPair是打印的格式函数:
static inline Void printPair(const std::pair<std::string, std::string> &p)
{
if (p.second=="")
{
std::cout << "\n" << std::setw(settingNameWidth) << p.first << "\n" << std::endl;
}
else
{
std::cout << std::setw(settingNameWidth) << p.first << ": " << p.second << "\n" << std::endl;
}
}
4. EnvVar::printEnvVarInUse();
功能:打印正在使用的环境变量
Void EnvVar::printEnvVarInUse()
{
if (getEnvVarInUse().size()!=0)
{
std::cout << "RExt Environment variables set as follows: \n" << std::endl;
for_each(getEnvVarInUse().begin(), getEnvVarInUse().end(), printVal);
}
std::cout << std::endl;
}
其中,printVal是打印各项参数的函数:
static inline Void printVal(const EnvVar* env)
{
std::cout << std::setw(settingNameWidth) << env->getName() << " = " << std::setw(settingValueWidth) << env->getInt() << " (string = " << std::setw(15) << env->getString() << ")" << std::endl;
}
前两个函数借助了自定义的环境变量类EnvVar,默认下都没有打印消息。
5. printMacroSettings();
功能:打印非环境变量所控制的宏块的值,比如默认编码比特深度、解码使用比特数统计、解码质量设置等等。
Void printMacroSettings()
{
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);
PRINT_CONSTANT(O0043_BEST_EFFORT_DECODING, settingNameWidth, settingValueWidth);
PRINT_CONSTANT(ME_ENABLE_ROUNDING_OF_MVS, settingNameWidth, settingValueWidth);
std::cout << std::endl;
}
其中,PRINT_CONSTANT是打印格式的替换定义,其参数分别是被相关文件定义的常量和静态常量
#define PRINT_CONSTANT(NAME, NAME_WIDTH, VALUE_WIDTH) std::cout << std::setw(NAME_WIDTH) << #NAME << " = " << std::setw(VALUE_WIDTH) << NAME << std::endl;