重要函数解析
main()
cpp
int main(int argc, char **argv)
{
int ret;
BenchmarkTimeStamps ti;
/* 初始化动态加载 */
init_dynload();
/* 注册退出回调函数 */
register_exit(ffmpeg_cleanup);
/* 设置stderr的缓冲模式(win32运行时需要) */
setvbuf(stderr, NULL, _IONBF, 0);
/* 设置日志打印选项 */
av_log_set_flags(AV_LOG_SKIP_REPEATED);
parse_loglevel(argc, argv, options);
#if CONFIG_AVDEVICE
/* 注册音视频设备 */
avdevice_register_all();
#endif
/* 初始化网络模块 */
avformat_network_init();
/* 显示ffmpeg的banner信息 */
show_banner(argc, argv, options);
/* 解析命令行选项并打开所有的输入/输出文件 */
ret = ffmpeg_parse_options(argc, argv);
if (ret < 0)
exit_program(1);
/* 检查是否没有指定输出文件并且没有输入文件 */
if (nb_output_files <= 0 && nb_input_files == 0) {
show_usage();
av_log(NULL, AV_LOG_WARNING, "Use -h to get full help or, even better, run 'man %s'\n", program_name);
exit_program(1);
}
/* 检查是否至少指定一个输出文件 */
if (nb_output_files <= 0) {
av_log(NULL, AV_LOG_FATAL, "At least one output file must be specified\n");
exit_program(1);
}
current_time = ti = get_benchmark_time_stamps();
/* 文件转码或抓取 */
if (transcode() < 0)
exit_program(1);
if (do_benchmark) {
int64_t utime, stime, rtime;
current_time = get_benchmark_time_stamps();
utime = current_time.user_usec - ti.user_usec;
stime = current_time.sys_usec - ti.sys_usec;
rtime = current_time.real_usec - ti.real_usec;
av_log(NULL, AV_LOG_INFO,
"bench: utime=%0.3fs stime=%0.3fs rtime=%0.3fs\n",
utime / 1000000.0, stime / 1000000.0, rtime / 1000000.0);
}
av_log(NULL, AV_LOG_DEBUG,
"%"PRIu64" frames successfully decoded, %"PRIu64" decoding errors\n",
decode_error_stat[0], decode_error_stat[1]);
/* 检查解码错误是否超过了指定的错误率 */
if ((decode_error_stat[0] + decode_error_stat[1]) * max_error_rate < decode_error_stat[1])
exit_program(69);
/* 根据是否接收到信号确定程序的返回码,并终止程序 */
exit_program(received_nb_signals ? 255 : main_return_code);
return main_return_code;
}
下面是对每个步骤的功能的详细解释:
- 初始化动态加载。
- 调用init_dynload函数,用于初始化动态加载库的相关资源,以便在需要时加载需要的库。
- 注册退出回调函数。
- 调用register_exit函数,将ffmpeg_cleanup函数注册为在程序退出时被调用的回调函数。
- 设置stderr的缓冲模式。
- 调用setvbuf函数,将stderr的缓冲模式设置为无缓冲模式,以确保错误信息可以立即显示在终端上。
- 设置日志打印选项。
- 调用av_log_set_flags函数,设置日志打印选项。在这里设置
AV_LOG_SKIP_REPEATED选项,表示日志会跳过重复的消息。
- 调用av_log_set_flags函数,设置日志打印选项。在这里设置
- 解析命令行参数中的日志级别选项。
- 调用parse_loglevel函数,解析命令行参数中的日志级别选项,并将其应用到日志系统中。
- 注册音视频设备。
- 调用avdevice_register_all函数,用于注册所有的音视频设备。
- 初始化网络模块。
- 调用avformat_network_init函数,初始化网络模块,以便进行网络相关的操作,如打开网络流。
- 显示ffmpeg的banner信息。
- 调用show_banner函数,根据命令行参数、选项和程序信息,打印ffmpeg的banner信息。
- 解析命令行选项并打开所有的输入/输出文件。
- 调用ffmpeg_parse_options函数,解析命令行选项,并根据选项打开所有的输入/输出文件。
- 检查是否没有指定输出文件并且没有输入文件。
- 检查nb_output_files和nb_input_files的值。
- 若满足条件,则打印用法信息和警告,并终止程序。
- 检查是否至少指定一个输出文件。
- 检查nb_output_files的值。
- 若不满足条件,则打印致命错误信息,并终止程序。
- 进行文件转码或抓取。
- 调用transcode函数,进行文件转码或抓取。
- transcode函数返回值小于0表示出错,并通过调用exit_program函数终止程序。
- 如果启用了性能评测,输出性能数据。
- 如果do_benchmark为真,计算从开始到结束的用户时间、系统时间和真实时间,并打印出来。
- 打印解码帧数和解码错误数。
- 调用av_log函数,打印成功解码的帧数和解码错误数。
- 检查解码错误是否超过了指定的错误率。
- 检查解码错误数是否超过了最大错误率。
- 若满足条件,则通过调用exit_program终止程序。
- 根据是否接收到信号确定程序的返回码,并终止程序。
- 返回main_return_code作为main函数的返回值。
ffmpeg_parse_options()
cpp
// 解析命令行参数并设置选项
int ffmpeg_parse_options(int argc, char **argv)
{
// 定义选项解析上下文和错误信息
OptionParseContext octx;
uint8_t error[128];
int ret;
memset(&octx, 0, sizeof(octx));
/* split the commandline into an internal representation */
// 将命令行参数拆分为内部表示形式
ret = split_commandline(&octx, argc, argv, options, groups,
FF_ARRAY_ELEMS(groups));
if (ret < 0) {
av_log(NULL, AV_LOG_FATAL, "Error splitting the argument list: ");
goto fail;
}
/* apply global options */
// 应用全局选项
ret = parse_optgroup(NULL, &octx.global_opts);
if (ret < 0) {
av_log(NULL, AV_LOG_FATAL, "Error parsing global options: ");
goto fail;
}
/* configure terminal and setup signal handlers */
// 配置终端并设置信号处理程序
term_init();
/* open input files */
// 打开输入文件
ret = open_files(&octx.groups[GROUP_INFILE], "input", open_input_file);
if (ret < 0) {
av_log(NULL, AV_LOG_FATAL, "Error opening input files: ");
goto fail;
}
// 应用同步偏移量
apply_sync_offsets();
/* create the complex filtergraphs */
// 创建复杂的滤波器图
ret = init_complex_filters();
if (ret < 0) {
av_log(NULL, AV_LOG_FATAL, "Error initializing complex filters.\n");
goto fail;
}
/* open output files */
// 打开输出文件
ret = open_files(&octx.groups[GROUP_OUTFILE], "output", open_output_file);
if (ret < 0) {
av_log(NULL, AV_LOG_FATAL, "Error opening output files: ");
goto fail;
}
// 检查滤波器的输出
check_filter_outputs();
fail:
// 反初始化选项解析上下文
uninit_parse_context(&octx);
if (ret < 0) {
// 如果有错误,将错误信息输出到日志
av_strerror(ret, error, sizeof(error));
av_log(NULL, AV_LOG_FATAL, "%s\n", error);
}
return ret;
}
函数功能:该函数用于解析命令行参数并进行相应处理,包括拆分命令行参数为内部表示形式、应用全局选项、配置终端和设置信号处理程序、打开输入文件、应用同步偏移量、创建复杂的滤波器图、打开输出文件、检查滤波器的输出。如果出现错误,会将错误信息输出到日志。