You've already forked FFmpeg
							
							
				mirror of
				https://github.com/FFmpeg/FFmpeg.git
				synced 2025-10-30 23:18:11 +02:00 
			
		
		
		
	Merge commit '8c9af5b2051b9927f845c7afdfeb30b82670ee77'
* commit '8c9af5b2051b9927f845c7afdfeb30b82670ee77': cmdutils: add a commandline pre-parser. Merged-by: Michael Niedermayer <michaelni@gmx.at>
This commit is contained in:
		
							
								
								
									
										241
									
								
								cmdutils.c
									
									
									
									
									
								
							
							
						
						
									
										241
									
								
								cmdutils.c
									
									
									
									
									
								
							| @@ -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[] = { | ||||
|   | ||||
							
								
								
									
										88
									
								
								cmdutils.h
									
									
									
									
									
								
							
							
						
						
									
										88
									
								
								cmdutils.h
									
									
									
									
									
								
							| @@ -223,6 +223,94 @@ void parse_options(void *optctx, int argc, char **argv, const OptionDef *options | ||||
| int parse_option(void *optctx, const char *opt, const char *arg, | ||||
|                  const OptionDef *options); | ||||
|  | ||||
| /** | ||||
|  * An option extracted from the commandline. | ||||
|  * Cannot use AVDictionary because of options like -map which can be | ||||
|  * used multiple times. | ||||
|  */ | ||||
| typedef struct Option { | ||||
|     const OptionDef  *opt; | ||||
|     const char       *key; | ||||
|     const char       *val; | ||||
| } Option; | ||||
|  | ||||
| typedef struct OptionGroupDef { | ||||
|     /**< group name */ | ||||
|     const char *name; | ||||
|     /** | ||||
|      * Option to be used as group separator. Can be NULL for groups which | ||||
|      * are terminated by a non-option argument (e.g. ffmpeg output files) | ||||
|      */ | ||||
|     const char *sep; | ||||
| } OptionGroupDef; | ||||
|  | ||||
| typedef struct OptionGroup { | ||||
|     const OptionGroupDef *group_def; | ||||
|     const char *arg; | ||||
|  | ||||
|     Option *opts; | ||||
|     int  nb_opts; | ||||
|  | ||||
|     AVDictionary *codec_opts; | ||||
|     AVDictionary *format_opts; | ||||
|     struct SwsContext *sws_opts; | ||||
| } OptionGroup; | ||||
|  | ||||
| /** | ||||
|  * A list of option groups that all have the same group type | ||||
|  * (e.g. input files or output files) | ||||
|  */ | ||||
| typedef struct OptionGroupList { | ||||
|     const OptionGroupDef *group_def; | ||||
|  | ||||
|     OptionGroup *groups; | ||||
|     int       nb_groups; | ||||
| } OptionGroupList; | ||||
|  | ||||
| typedef struct OptionParseContext { | ||||
|     OptionGroup global_opts; | ||||
|  | ||||
|     OptionGroupList *groups; | ||||
|     int           nb_groups; | ||||
|  | ||||
|     /* parsing state */ | ||||
|     OptionGroup cur_group; | ||||
| } OptionParseContext; | ||||
|  | ||||
| /** | ||||
|  * Parse an options group and write results into optctx. | ||||
|  * | ||||
|  * @param optctx an app-specific options context. NULL for global options group | ||||
|  */ | ||||
| int parse_optgroup(void *optctx, OptionGroup *g); | ||||
|  | ||||
| /** | ||||
|  * Split the commandline into an intermediate form convenient for further | ||||
|  * processing. | ||||
|  * | ||||
|  * The commandline is assumed to be composed of options which either belong to a | ||||
|  * group (those with OPT_SPEC, OPT_OFFSET or OPT_PERFILE) or are global | ||||
|  * (everything else). | ||||
|  * | ||||
|  * A group (defined by an OptionGroupDef struct) is a sequence of options | ||||
|  * terminated by either a group separator option (e.g. -i) or a parameter that | ||||
|  * is not an option (doesn't start with -). A group without a separator option | ||||
|  * must always be first in the supplied groups list. | ||||
|  * | ||||
|  * All options within the same group are stored in one OptionGroup struct in an | ||||
|  * OptionGroupList, all groups with the same group definition are stored in one | ||||
|  * OptionGroupList in OptionParseContext.groups. The order of group lists is the | ||||
|  * same as the order of group definitions. | ||||
|  */ | ||||
| int split_commandline(OptionParseContext *octx, int argc, char *argv[], | ||||
|                       const OptionDef *options, | ||||
|                       const OptionGroupDef *groups); | ||||
|  | ||||
| /** | ||||
|  * Free all allocated memory in an OptionParseContext. | ||||
|  */ | ||||
| void uninit_parse_context(OptionParseContext *octx); | ||||
|  | ||||
| /** | ||||
|  * Find the '-loglevel' option in the command line args and apply it. | ||||
|  */ | ||||
|   | ||||
		Reference in New Issue
	
	Block a user