ffmpeg_parse_options命令行解析—ffmpeg.c源码分析

作者:罗上文,微信:Loken1,公众号:FFmpeg弦外之音

ffmpeg_parse_options()ffmpeg.exe 解析命令行参数的主函数,它的流程图如下:

1-1

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_optsformat_optssws_dictswr_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;

1-2

如果你命令行使用了 -f 888,那 Option 的内容就是下面这样的:

const OptionDef  *opt = options[1] // f 选项的下标是 1
const char       *key = f 
const char       *val = 888

OptionDef 结构在分析 ffplay 的时候讲过了,推荐阅读《FFplay是如何解析命令行参数的》。

ffplay.exeffmpeg.exe 都是用的 OptionDef 结构来定义自身支持的参数。


3,struct OptionGroupListOptionGroup 的列表。

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 确定,确定他是输入组还是输出组。


上面这些数据结构的关系如下图所示:

1-3

不过 OptionGroupOptionGroupList 的结构设计得有点奇怪,他们里面都有一个 OptionGroupDef

全局组的定义如下:

static const OptionGroupDef global_group = { "global" };

1-4


相关的数据结构已经了解了,后面的文章会继续分析 ffmpeg_parse_options() 里面各个子函数的内部逻辑。



感谢 NETINT(镕铭微电子) 赞助《FFmpeg原理》免费版一书的服务器费用,下面是 VPU 产品介绍

版权所属 xianwanzhiyin.net 罗上文 2024 all right reserved,powered by Gitbook该文件修订时间: 2023-05-17 13:42:09

results matching ""

    No results matching ""