ffmpeg_parse_options命令行解析—ffmpeg.c源码分析
作者:罗上文,微信:Loken1,公众号:FFmpeg弦外之音
ffmpeg_parse_options()
是 ffmpeg.exe
解析命令行参数的主函数,它的流程图如下:
main()
在调 ffmpeg_parse_options()
之前还有一些初始化的准备工作,不过不是重点。
从上图可以看到,ffmpeg_parse_options()
内部有 4 个重要的函数调用,如下:
1,split_commandline()
,作用是把命令行的参数先解析到一个中间结构(OptionParseContext)里面,这个中间结构就是 octx
变量,
2,parse_optgroup(NULL, &octx.global_opts)
,把 octx
里面的 global_opts
字段解析到全局变量。
3,open_files(&octx.groups[GROUP_INFILE],...)
,octx.groups[GROUP_INFILE]
里面会有一个或者多个输入文件,需要用这些信息打开一个或者多个输入文件。
4,open_files(&octx.groups[GROUP_OUTFILE],...)
,octx.groups[GROUP_OUTFILE]
里面会有一个或者多个输出文件,需要用这些信息打开一个或者多个输出文件。
命令行参数解析模块,主要用到 3 个数据结构,如下:
1,struct OptionParseContext
,存储命令行参数的中间状态。定义如下:
typedef struct OptionParseContext {
OptionGroup global_opts;
OptionGroupList *groups;
int nb_groups;
/* parsing state */
OptionGroup cur_group;
} OptionParseContext;
ffmpeg.exe
在使用 OptionParseContext
结构的时候,只定义了两个组,输入组跟输出组,如下:
static const OptionGroupDef groups[] = {
[GROUP_OUTFILE] = { "output url", NULL, OPT_OUTPUT },
[GROUP_INFILE] = { "input url", "i", OPT_INPUT },
};
//初始化 octx
init_parse_context(octx, groups, nb_groups);
ffmpeg.exe
初始化 octx
变量是在 init_parse_context()
函数里面的,这个比较简单,不过多介绍。
输入组 里面是可以有多个输入文件的,输出组也可以有多个输出文件。
2,struct OptionGroup
,存储单个输入或者输出文件的信息。
typedef struct OptionGroup {
const OptionGroupDef *group_def;
const char *arg; //这个字段是输入或者输出的文件名
Option *opts; // ffmpeg_opt.c 里面定义的选项
int nb_opts;
AVDictionary *codec_opts; //编码器选项
AVDictionary *format_opts; //容器选项
AVDictionary *resample_opts; //重采样选项 应该是快废弃的
AVDictionary *sws_dict; //图像转换选项
AVDictionary *swr_opts; //重采样选项
} OptionGroup;
OptionGroup
是一个非常重要的数据结构,存储单个输入或者输出文件的命令行参数信息,之前在《ffmpeg命令参数类型》讲过,每个输出文件都可以有自己的独立参数,不同的输出文件的参数是分开的。不同的输出文件可以指定不同的编码器等等。
codec_opts
,format_opts
,sws_dict
,swr_opts
这些字段存储的是组件库的参数。
Option *opts
字段存储的才是 ffmpeg.exe
工具自身的参数。
OptionGroup
里面的 arg
是文件名,然后 opts
存储的是 ffmpeg_opt.c
里面的 options[]
变量中的某些选项,如下:
typedef struct Option {
const OptionDef *opt; //ffmpeg_opt.c 里面的选项
const char *key; //命令行参数的 key
const char *val; //命令行参数的 value
} Option;
如果你命令行使用了 -f 888
,那 Option
的内容就是下面这样的:
const OptionDef *opt = options[1] // f 选项的下标是 1
const char *key = f
const char *val = 888
OptionDef
结构在分析 ffplay
的时候讲过了,推荐阅读《FFplay是如何解析命令行参数的》。
ffplay.exe
跟 ffmpeg.exe
都是用的 OptionDef
结构来定义自身支持的参数。
3,struct OptionGroupList
,OptionGroup
的列表。
typedef struct OptionGroupList {
const OptionGroupDef *group_def;
OptionGroup *groups;
int nb_groups;
} OptionGroupList;
static const OptionGroupDef groups[] = {
[GROUP_OUTFILE] = { "output url", NULL, OPT_OUTPUT },
[GROUP_INFILE] = { "input url", "i", OPT_INPUT },
};
通常 OptionGroup
裸露在外面直接用,例如 OptionParseContext::global_opts
,那就是全局组,如果 OptionGroup
包在 OptionGroupList
使用的,OptionGroup
的属性就由 OptionGroupDef
确定,确定他是输入组还是输出组。
上面这些数据结构的关系如下图所示:
不过 OptionGroup
跟 OptionGroupList
的结构设计得有点奇怪,他们里面都有一个 OptionGroupDef
。
全局组的定义如下:
static const OptionGroupDef global_group = { "global" };
相关的数据结构已经了解了,后面的文章会继续分析 ffmpeg_parse_options()
里面各个子函数的内部逻辑。
感谢 NETINT(镕铭微电子) 赞助《FFmpeg原理》免费版一书的服务器费用,下面是 VPU 产品介绍