|
|
|
@ -374,6 +374,29 @@ void parse_options(void *optctx, int argc, char **argv, const OptionDef *options |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int parse_optgroup(void *optctx, OptionGroup *g) |
|
|
|
|
{ |
|
|
|
|
int i, ret; |
|
|
|
|
|
|
|
|
|
av_log(NULL, AV_LOG_DEBUG, "Parsing a group of options: %s %s.\n", |
|
|
|
|
g->group_def->name, g->arg); |
|
|
|
|
|
|
|
|
|
for (i = 0; i < g->nb_opts; i++) { |
|
|
|
|
Option *o = &g->opts[i]; |
|
|
|
|
|
|
|
|
|
av_log(NULL, AV_LOG_DEBUG, "Applying option %s (%s) with argument %s.\n", |
|
|
|
|
o->key, o->opt->help, o->val); |
|
|
|
|
|
|
|
|
|
ret = write_option(optctx, o->opt, o->key, o->val); |
|
|
|
|
if (ret < 0) |
|
|
|
|
return ret; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
av_log(NULL, AV_LOG_DEBUG, "Successfully parsed a group of options.\n"); |
|
|
|
|
|
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int locate_option(int argc, char **argv, const OptionDef *options, |
|
|
|
|
const char *optname) |
|
|
|
|
{ |
|
|
|
@ -507,6 +530,224 @@ int opt_default(void *optctx, const char *opt, const char *arg) |
|
|
|
|
return AVERROR_OPTION_NOT_FOUND; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Check whether given option is a group separator. |
|
|
|
|
* |
|
|
|
|
* @return index of the group definition that matched or -1 if none |
|
|
|
|
*/ |
|
|
|
|
static int match_group_separator(const OptionGroupDef *groups, const char *opt) |
|
|
|
|
{ |
|
|
|
|
const OptionGroupDef *p = groups; |
|
|
|
|
|
|
|
|
|
while (p->name) { |
|
|
|
|
if (p->sep && !strcmp(p->sep, opt)) |
|
|
|
|
return p - groups; |
|
|
|
|
p++; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return -1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Finish parsing an option group. |
|
|
|
|
* |
|
|
|
|
* @param group_idx which group definition should this group belong to |
|
|
|
|
* @param arg argument of the group delimiting option |
|
|
|
|
*/ |
|
|
|
|
static void finish_group(OptionParseContext *octx, int group_idx, |
|
|
|
|
const char *arg) |
|
|
|
|
{ |
|
|
|
|
OptionGroupList *l = &octx->groups[group_idx]; |
|
|
|
|
OptionGroup *g; |
|
|
|
|
|
|
|
|
|
GROW_ARRAY(l->groups, l->nb_groups); |
|
|
|
|
g = &l->groups[l->nb_groups - 1]; |
|
|
|
|
|
|
|
|
|
*g = octx->cur_group; |
|
|
|
|
g->arg = arg; |
|
|
|
|
g->group_def = l->group_def; |
|
|
|
|
#if CONFIG_SWSCALE |
|
|
|
|
g->sws_opts = sws_opts; |
|
|
|
|
#endif |
|
|
|
|
g->codec_opts = codec_opts; |
|
|
|
|
g->format_opts = format_opts; |
|
|
|
|
|
|
|
|
|
codec_opts = NULL; |
|
|
|
|
format_opts = NULL; |
|
|
|
|
#if CONFIG_SWSCALE |
|
|
|
|
sws_opts = NULL; |
|
|
|
|
#endif |
|
|
|
|
init_opts(); |
|
|
|
|
|
|
|
|
|
memset(&octx->cur_group, 0, sizeof(octx->cur_group)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Add an option instance to currently parsed group. |
|
|
|
|
*/ |
|
|
|
|
static void add_opt(OptionParseContext *octx, const OptionDef *opt, |
|
|
|
|
const char *key, const char *val) |
|
|
|
|
{ |
|
|
|
|
int global = !(opt->flags & (OPT_PERFILE | OPT_SPEC | OPT_OFFSET)); |
|
|
|
|
OptionGroup *g = global ? &octx->global_opts : &octx->cur_group; |
|
|
|
|
|
|
|
|
|
GROW_ARRAY(g->opts, g->nb_opts); |
|
|
|
|
g->opts[g->nb_opts - 1].opt = opt; |
|
|
|
|
g->opts[g->nb_opts - 1].key = key; |
|
|
|
|
g->opts[g->nb_opts - 1].val = val; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void init_parse_context(OptionParseContext *octx, |
|
|
|
|
const OptionGroupDef *groups) |
|
|
|
|
{ |
|
|
|
|
static const OptionGroupDef global_group = { "global" }; |
|
|
|
|
const OptionGroupDef *g = groups; |
|
|
|
|
int i; |
|
|
|
|
|
|
|
|
|
memset(octx, 0, sizeof(*octx)); |
|
|
|
|
|
|
|
|
|
while (g->name) |
|
|
|
|
g++; |
|
|
|
|
octx->nb_groups = g - groups; |
|
|
|
|
octx->groups = av_mallocz(sizeof(*octx->groups) * octx->nb_groups); |
|
|
|
|
if (!octx->groups) |
|
|
|
|
exit(1); |
|
|
|
|
|
|
|
|
|
for (i = 0; i < octx->nb_groups; i++) |
|
|
|
|
octx->groups[i].group_def = &groups[i]; |
|
|
|
|
|
|
|
|
|
octx->global_opts.group_def = &global_group; |
|
|
|
|
octx->global_opts.arg = ""; |
|
|
|
|
|
|
|
|
|
init_opts(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void uninit_parse_context(OptionParseContext *octx) |
|
|
|
|
{ |
|
|
|
|
int i, j; |
|
|
|
|
|
|
|
|
|
for (i = 0; i < octx->nb_groups; i++) { |
|
|
|
|
OptionGroupList *l = &octx->groups[i]; |
|
|
|
|
|
|
|
|
|
for (j = 0; j < l->nb_groups; j++) { |
|
|
|
|
av_freep(&l->groups[j].opts); |
|
|
|
|
av_dict_free(&l->groups[j].codec_opts); |
|
|
|
|
av_dict_free(&l->groups[j].format_opts); |
|
|
|
|
#if CONFIG_SWSCALE |
|
|
|
|
sws_freeContext(l->groups[j].sws_opts); |
|
|
|
|
#endif |
|
|
|
|
} |
|
|
|
|
av_freep(&l->groups); |
|
|
|
|
} |
|
|
|
|
av_freep(&octx->groups); |
|
|
|
|
|
|
|
|
|
av_freep(&octx->cur_group.opts); |
|
|
|
|
av_freep(&octx->global_opts.opts); |
|
|
|
|
|
|
|
|
|
uninit_opts(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int split_commandline(OptionParseContext *octx, int argc, char *argv[], |
|
|
|
|
const OptionDef *options, |
|
|
|
|
const OptionGroupDef *groups) |
|
|
|
|
{ |
|
|
|
|
int optindex = 1; |
|
|
|
|
|
|
|
|
|
/* perform system-dependent conversions for arguments list */ |
|
|
|
|
prepare_app_arguments(&argc, &argv); |
|
|
|
|
|
|
|
|
|
init_parse_context(octx, groups); |
|
|
|
|
av_log(NULL, AV_LOG_DEBUG, "Splitting the commandline.\n"); |
|
|
|
|
|
|
|
|
|
while (optindex < argc) { |
|
|
|
|
const char *opt = argv[optindex++], *arg; |
|
|
|
|
const OptionDef *po; |
|
|
|
|
int ret; |
|
|
|
|
|
|
|
|
|
av_log(NULL, AV_LOG_DEBUG, "Reading option '%s' ...", opt); |
|
|
|
|
|
|
|
|
|
/* unnamed group separators, e.g. output filename */ |
|
|
|
|
if (opt[0] != '-' || !opt[1]) { |
|
|
|
|
finish_group(octx, 0, opt); |
|
|
|
|
av_log(NULL, AV_LOG_DEBUG, " matched as %s.\n", groups[0].name); |
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
opt++; |
|
|
|
|
|
|
|
|
|
#define GET_ARG(arg) \ |
|
|
|
|
do { \
|
|
|
|
|
arg = argv[optindex++]; \
|
|
|
|
|
if (!arg) { \
|
|
|
|
|
av_log(NULL, AV_LOG_ERROR, "Missing argument for option '%s'.\n", opt);\
|
|
|
|
|
return AVERROR(EINVAL); \
|
|
|
|
|
} \
|
|
|
|
|
} while (0) |
|
|
|
|
|
|
|
|
|
/* named group separators, e.g. -i */ |
|
|
|
|
if ((ret = match_group_separator(groups, opt)) >= 0) { |
|
|
|
|
GET_ARG(arg); |
|
|
|
|
finish_group(octx, ret, arg); |
|
|
|
|
av_log(NULL, AV_LOG_DEBUG, " matched as %s with argument '%s'.\n", |
|
|
|
|
groups[ret].name, arg); |
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* normal options */ |
|
|
|
|
po = find_option(options, opt); |
|
|
|
|
if (po->name) { |
|
|
|
|
if (po->flags & OPT_EXIT) { |
|
|
|
|
/* optional argument, e.g. -h */ |
|
|
|
|
arg = argv[optindex++]; |
|
|
|
|
} else if (po->flags & HAS_ARG) { |
|
|
|
|
GET_ARG(arg); |
|
|
|
|
} else { |
|
|
|
|
arg = "1"; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
add_opt(octx, po, opt, arg); |
|
|
|
|
av_log(NULL, AV_LOG_DEBUG, " matched as option '%s' (%s) with " |
|
|
|
|
"argument '%s'.\n", po->name, po->help, arg); |
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* AVOptions */ |
|
|
|
|
if (argv[optindex]) { |
|
|
|
|
ret = opt_default(NULL, opt, argv[optindex]); |
|
|
|
|
if (ret >= 0) { |
|
|
|
|
av_log(NULL, AV_LOG_DEBUG, " matched as AVOption '%s' with " |
|
|
|
|
"argument '%s'.\n", opt, argv[optindex]); |
|
|
|
|
optindex++; |
|
|
|
|
continue; |
|
|
|
|
} else if (ret != AVERROR_OPTION_NOT_FOUND) { |
|
|
|
|
av_log(NULL, AV_LOG_ERROR, "Error parsing option '%s' " |
|
|
|
|
"with argument '%s'.\n", opt, argv[optindex]); |
|
|
|
|
return ret; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* boolean -nofoo options */ |
|
|
|
|
if (opt[0] == 'n' && opt[1] == 'o' && |
|
|
|
|
(po = find_option(options, opt + 2)) && |
|
|
|
|
po->name && po->flags & OPT_BOOL) { |
|
|
|
|
add_opt(octx, po, opt, "0"); |
|
|
|
|
av_log(NULL, AV_LOG_DEBUG, " matched as option '%s' (%s) with " |
|
|
|
|
"argument 0.\n", po->name, po->help); |
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
av_log(NULL, AV_LOG_ERROR, "Unrecognized option '%s'.\n", opt); |
|
|
|
|
return AVERROR_OPTION_NOT_FOUND; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (octx->cur_group.nb_opts || codec_opts || format_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; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int opt_loglevel(void *optctx, const char *opt, const char *arg) |
|
|
|
|
{ |
|
|
|
|
const struct { const char *name; int level; } log_levels[] = { |
|
|
|
|