ftools/ffmpeg.c 文件,包含ffmpeg指令信息,其主函数如下:
int main(int argc, char **argv)
{int i, ret;BenchmarkTimeStamps ti;init_dynload();register_exit(ffmpeg_cleanup);setvbuf(stderr,NULL,_IONBF,0); /* win32 runtime needs this */av_log_set_flags(AV_LOG_SKIP_REPEATED);parse_loglevel(argc, argv, options);if(argc>1 && !strcmp(argv[1], "-d")){run_as_daemon=1;av_log_set_callback(log_callback_null);argc--;argv++;}#if CONFIG_AVDEVICEavdevice_register_all();
#endifavformat_network_init();show_banner(argc, argv, options);/* parse options and open all input/output files */ret &#61; f(argc, argv);if (ret <0)exit_program(1);if (nb_output_files <&#61; 0 && nb_input_files &#61;&#61; 0) {show_usage();av_log(NULL, AV_LOG_WARNING, "Use -h to get full help or, even better, run &#39;man %s&#39;\n", program_name);exit_program(1);}/* file converter / grab */if (nb_output_files <&#61; 0) {av_log(NULL, AV_LOG_FATAL, "At least one output file must be specified\n");exit_program(1);}for (i &#61; 0; i
主函数中包含ffmpeg_parse_options()函数&#xff0c;主要用于解析命令行参数&#xff0c;其基本调用结构如下&#xff1a;
解析过程中主要起作用的函数为split_commandline()函数&#xff1a;
ret &#61; split_commandline(&octx, argc, argv, options, groups,FF_ARRAY_ELEMS(groups));
OptionParseContext octx&#xff0c;用来存储被解析后的数据&#xff0c;全局参数&#xff0c;输入输出参数
typedef struct OptionParseContext {OptionGroup global_opts;OptionGroupList *groups;int nb_groups;/* parsing state */OptionGroup cur_group;
} OptionParseContext;
options参数定义在ffmpeg_opt.c中&#xff0c;以下为其部分定义&#xff1a;
const OptionDef options[] &#61; {/* main options */CMDUTILS_COMMON_OPTIONS{ "f", HAS_ARG | OPT_STRING | OPT_OFFSET |OPT_INPUT | OPT_OUTPUT, { .off &#61; OFFSET(format) },"force format", "fmt" },{ "y", OPT_BOOL, { &file_overwrite },"overwrite output files" },{ "n", OPT_BOOL, { &no_file_overwrite },"never overwrite output files" },{ "ignore_unknown", OPT_BOOL, { &ignore_unknown_streams },"Ignore unknown stream types" },{ "copy_unknown", OPT_BOOL | OPT_EXPERT, { ©_unknown_streams },"Copy unknown stream types" },{ "c", HAS_ARG | OPT_STRING | OPT_SPEC |OPT_INPUT | OPT_OUTPUT, { .off &#61; OFFSET(codec_names) },"codec name", "codec" },{ "codec", HAS_ARG | OPT_STRING | OPT_SPEC |OPT_INPUT | OPT_OUTPUT, { .off &#61; OFFSET(codec_names) },"codec name", "codec" },{ "pre", HAS_ARG | OPT_STRING | OPT_SPEC |OPT_OUTPUT, { .off &#61; OFFSET(presets) },"preset name", "preset" },
typedef struct OptionDef {const char *name;int flags;
#define HAS_ARG 0x0001
#define OPT_BOOL 0x0002
#define OPT_EXPERT 0x0004
#define OPT_STRING 0x0008
#define OPT_VIDEO 0x0010
#define OPT_AUDIO 0x0020
#define OPT_INT 0x0080
#define OPT_FLOAT 0x0100
#define OPT_SUBTITLE 0x0200
#define OPT_INT64 0x0400
#define OPT_EXIT 0x0800
#define OPT_DATA 0x1000
#define OPT_PERFILE 0x2000 /* the option is per-file (currently ffmpeg-only).implied by OPT_OFFSET or OPT_SPEC */
#define OPT_OFFSET 0x4000 /* option is specified as an offset in a passed optctx */
#define OPT_SPEC 0x8000 /* option is to be stored in an array of SpecifierOpt.Implies OPT_OFFSET. Next element after the offset isan int containing element count in the array. */
#define OPT_TIME 0x10000
#define OPT_DOUBLE 0x20000
#define OPT_INPUT 0x40000
#define OPT_OUTPUT 0x80000union {void *dst_ptr;int (*func_arg)(void *, const char *, const char *);size_t off;} u;const char *help;const char *argname;
} OptionDef;
groups参数为输入输出参数
static const OptionGroupDef groups[] &#61; {[GROUP_OUTFILE] &#61; { "output url", NULL, OPT_OUTPUT },[GROUP_INFILE] &#61; { "input url", "i", OPT_INPUT },
};
typedef struct OptionGroupDef {/**
通过代码来分析split_commandline()函数的执行过程&#xff1a;
/*** 解析命令行参数* &#64;param octx: 用来将命令行中的参数通过分析分别存入此结构对应变量中* &#64;param options: 默认参数的定义 (具体参见ffmpeg_opt.c文件中的 const OptionDef options[] 定义)* &#64;param groups: 存储输入文件和输出文件相关参数* &#64;param nb_groups: 2*/
int split_commandline(OptionParseContext *octx, int argc, char *argv[],const OptionDef *options,const OptionGroupDef *groups, int nb_groups)
{int optindex &#61; 1;int dashdash &#61; -2;/* perform system-dependent conversions for arguments list */prepare_app_arguments(&argc, &argv);/* 基本的内存分配&#xff0c;OptionGroupDef 与 OptionParseContext 建立联系 */init_parse_context(octx, groups, nb_groups, data);av_log(NULL, AV_LOG_DEBUG, "Splitting the commandline.\n");/* 循环取出参数 */while (optindex
do { \arg &#61; argv[optindex&#43;&#43;]; \if (!arg) { \av_log(NULL, AV_LOG_ERROR, "Missing argument for option &#39;%s&#39;.\n", opt);\return AVERROR(EINVAL); \} \
} while (0)/* 参数格式是否为“-i xxx”&#xff0c;如果匹配&#xff0c;返回1 */if ((ret &#61; match_group_separator(groups, nb_groups, opt)) >&#61; 0) {// 获取参数对应的值GET_ARG(arg);/** * 将输入的路径、octx->cur_group数组的值以及专属参数&#xff0c;存储到 * octx->groups[0]结构体中,并清空 octx->cur_group 数组的值*/finish_group(octx, ret, arg);av_log(NULL, AV_LOG_DEBUG, " matched as %s with argument &#39;%s&#39;.\n",groups[ret].name, arg);continue;}// 判断此 opt 是否为 options 中定义的参数po &#61; find_option(options, opt);if (po->name) {if (po->flags & OPT_EXIT) {arg &#61; argv[optindex&#43;&#43;];} else if (po->flags & HAS_ARG) {/* 获取参数 */GET_ARG(arg);} else {// 允许参数后面的值缺失&#xff0c;直接设置为1arg &#61; "1";}/*** 判断参数类型(opt->flags)&#xff0c;存入 octx->global_opts(全局参数) 或 * octx->cur_group(临时数组)*/add_opt(octx, po, opt, arg);av_log(NULL, AV_LOG_DEBUG, " matched as option &#39;%s&#39; (%s) with ""argument &#39;%s&#39;.\n", po->name, po->help, arg);continue;}if (argv[optindex]) {/*** 在 avcodec_options、avformat_options、avresample_options、 * swscale_options、swresample 中的 options 参数中不断查找&#xff0c;查找专属 * 并存入 AVDictionary*/ret &#61; opt_default(NULL, opt, argv[optindex]);if (ret >&#61; 0) {av_log(NULL, AV_LOG_DEBUG, " matched as AVOption &#39;%s&#39; with ""argument &#39;%s&#39;.\n", opt, argv[optindex]);optindex&#43;&#43;;continue;} else if (ret !&#61; AVERROR_OPTION_NOT_FOUND) {// 参数格式错误av_log(NULL, AV_LOG_ERROR, "Error parsing option &#39;%s&#39; ""with argument &#39;%s&#39;.\n", opt, argv[optindex]);return ret;}}/* 处理 “-noxx" 格式参数 */if (opt[0] &#61;&#61; &#39;n&#39; && opt[1] &#61;&#61; &#39;o&#39; &&(po &#61; find_option(options, opt &#43; 2)) &&po->name && po->flags & OPT_BOOL) {// 存入默认值 ”0“add_opt(octx, po, opt, "0");av_log(NULL, AV_LOG_DEBUG, " matched as option &#39;%s&#39; (%s) with ""argument 0.\n", po->name, po->help);continue;}// 没有匹配的参数&#xff0c;返回错误av_log(NULL, AV_LOG_ERROR, "Unrecognized option &#39;%s&#39;.\n", opt);return AVERROR_OPTION_NOT_FOUND;}// 循环结束后&#xff0c;临时参数及专属参数还存在值&#xff0c;没有存储到输入&输出相关参数数组中if (octx->cur_group.nb_opts || codec_opts || format_opts || resample_opts)av_log(NULL, AV_LOG_WARNING, "Trailing options were found on the ""commandline.\n");av_log(NULL, AV_LOG_DEBUG, "Finished splitting the commandline.\n");return 0;
}
总结&#xff1a;跳过“--”开头的参数&#xff0c;分别解析“-”、“-no”、“-i”开头的参数以及输出参数&#xff0c;存入OptionParseContext *octx中。