From b439c992c23f3e0f3832fffd2a34a664b236c525 Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Mon, 25 Feb 2013 21:21:29 +0100 Subject: [PATCH] lavfi: switch to an AVOptions-based system. --- doc/filters.texi | 21 +++++++++-- libavfilter/avfilter.c | 81 +++++++++++++++++++++++++++++++++++++++++- libavfilter/avfilter.h | 6 ++++ libavfilter/version.h | 3 ++ 4 files changed, 108 insertions(+), 3 deletions(-) diff --git a/doc/filters.texi b/doc/filters.texi index 88888c60e3..d32a2619d2 100644 --- a/doc/filters.texi +++ b/doc/filters.texi @@ -41,8 +41,25 @@ The name of the filter class is optionally followed by a string "=@var{arguments}". @var{arguments} is a string which contains the parameters used to -initialize the filter instance, and are described in the filter -descriptions below. +initialize the filter instance. It may have one of the two allowed forms: +@itemize + +@item +A ':'-separated list of @var{key=value} pairs. + +@item +A ':'-separated list of @var{value}. In this case, the keys are assumed to be +the option names in the order they are declared. E.g. the @code{fade} filter +declares three options in this order -- @option{type}, @option{start_frame} and +@option{nb_frames}. Then the parameter list @var{in:0:30} means that the value +@var{in} is assigned to the option @option{type}, @var{0} to +@option{start_frame} and @var{30} to @option{nb_frames}. + +@end itemize + +If the option value itself is a list of items (e.g. the @code{format} filter +takes a list of pixel formats), the items in the list are usually separated by +'|'. The list of arguments can be quoted using the character "'" as initial and ending mark, and the character '\' for escaping the characters diff --git a/libavfilter/avfilter.c b/libavfilter/avfilter.c index 4985ce9579..93d1855ce3 100644 --- a/libavfilter/avfilter.c +++ b/libavfilter/avfilter.c @@ -21,9 +21,11 @@ /* #define DEBUG */ +#include "libavutil/avstring.h" #include "libavutil/channel_layout.h" #include "libavutil/common.h" #include "libavutil/imgutils.h" +#include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "libavutil/rational.h" #include "libavutil/samplefmt.h" @@ -346,6 +348,11 @@ int avfilter_open(AVFilterContext **filter_ctx, AVFilter *filter, const char *in goto err; } + if (filter->priv_class) { + *(const AVClass**)ret->priv = filter->priv_class; + av_opt_set_defaults(ret->priv); + } + ret->nb_inputs = pad_count(filter->inputs); if (ret->nb_inputs ) { ret->input_pads = av_malloc(sizeof(AVFilterPad) * ret->nb_inputs); @@ -422,6 +429,9 @@ void avfilter_free(AVFilterContext *filter) av_freep(&link); } + if (filter->filter->priv_class) + av_opt_free(filter->priv); + av_freep(&filter->name); av_freep(&filter->input_pads); av_freep(&filter->output_pads); @@ -431,12 +441,81 @@ void avfilter_free(AVFilterContext *filter) av_free(filter); } +/* process a list of value1:value2:..., each value corresponding + * to subsequent AVOption, in the order they are declared */ +static int process_unnamed_options(AVFilterContext *ctx, AVDictionary **options, + const char *args) +{ + const AVOption *o = NULL; + const char *p = args; + char *val; + + while (*p) { + o = av_opt_next(ctx->priv, o); + if (!o) { + av_log(ctx, AV_LOG_ERROR, "More options provided than " + "this filter supports.\n"); + return AVERROR(EINVAL); + } + if (o->type == AV_OPT_TYPE_CONST) + continue; + + val = av_get_token(&p, ":"); + if (!val) + return AVERROR(ENOMEM); + + av_dict_set(options, o->name, val, 0); + + av_freep(&val); + if (*p) + p++; + } + + return 0; +} + int avfilter_init_filter(AVFilterContext *filter, const char *args, void *opaque) { + AVDictionary *options = NULL; + AVDictionaryEntry *e; int ret=0; - if (filter->filter->init) + if (args && *args && filter->filter->priv_class) { + if (strchr(args, '=')) { + /* assume a list of key1=value1:key2=value2:... */ + ret = av_dict_parse_string(&options, args, "=", ":", 0); + if (ret < 0) + goto fail; + } else { + ret = process_unnamed_options(filter, &options, args); + if (ret < 0) + goto fail; + } + } + + if (filter->filter->priv_class) { + ret = av_opt_set_dict(filter->priv, &options); + if (ret < 0) { + av_log(filter, AV_LOG_ERROR, "Error applying options to the filter.\n"); + goto fail; + } + } + + if (filter->filter->init) { ret = filter->filter->init(filter, args); + if (ret < 0) + goto fail; + } + + if ((e = av_dict_get(options, "", NULL, AV_DICT_IGNORE_SUFFIX))) { + av_log(filter, AV_LOG_ERROR, "No such option: %s.\n", e->key); + ret = AVERROR_OPTION_NOT_FOUND; + goto fail; + } + +fail: + av_dict_free(&options); + return ret; } diff --git a/libavfilter/avfilter.h b/libavfilter/avfilter.h index b3522f87d3..66f57df150 100644 --- a/libavfilter/avfilter.h +++ b/libavfilter/avfilter.h @@ -388,6 +388,12 @@ typedef struct AVFilter { const AVFilterPad *inputs; ///< NULL terminated list of inputs. NULL if none const AVFilterPad *outputs; ///< NULL terminated list of outputs. NULL if none + /** + * A class for the private data, used to access filter private + * AVOptions. + */ + const AVClass *priv_class; + /***************************************************************** * All fields below this line are not part of the public API. They * may not be used outside of libavfilter and can be changed and diff --git a/libavfilter/version.h b/libavfilter/version.h index 1a5ec42916..914b7ca3fa 100644 --- a/libavfilter/version.h +++ b/libavfilter/version.h @@ -55,5 +55,8 @@ #ifndef FF_API_AVFILTERBUFFER #define FF_API_AVFILTERBUFFER (LIBAVFILTER_VERSION_MAJOR < 4) #endif +#ifndef FF_API_OLD_FILTER_OPTS +#define FF_API_OLD_FILTER_OPTS (LIBAVFILTER_VERSION_MAJOR < 4) +#endif #endif /* AVFILTER_VERSION_H */