static void *filter_child_next(void *obj, void *prev)
{
AVFilterContext *ctx = obj;
- if (!prev && ctx->filter && ctx->filter->priv_class)
+ if (!prev && ctx->filter && ctx->filter->priv_class && ctx->priv)
return ctx->priv;
return NULL;
}
static const AVClass *filter_child_class_next(const AVClass *prev)
{
- AVFilter **filter_ptr = NULL;
+ AVFilter **f = NULL;
/* find the filter that corresponds to prev */
- while (prev && *(filter_ptr = av_filter_next(filter_ptr)))
- if ((*filter_ptr)->priv_class == prev)
+ while (prev && *(f = av_filter_next(f)))
+ if ((*f)->priv_class == prev)
break;
/* could not find filter corresponding to prev */
- if (prev && !(*filter_ptr))
+ if (prev && !(*f))
return NULL;
/* find next filter with specific options */
- while (*(filter_ptr = av_filter_next(filter_ptr)))
- if ((*filter_ptr)->priv_class)
- return (*filter_ptr)->priv_class;
+ while (*(f = av_filter_next(f)))
+ if ((*f)->priv_class)
+ return (*f)->priv_class;
return NULL;
}
.child_class_next = filter_child_class_next,
};
-const AVClass *avfilter_get_class(void)
-{
- return &avfilter_class;
-}
-
int avfilter_open(AVFilterContext **filter_ctx, AVFilter *filter, const char *inst_name)
{
AVFilterContext *ret;
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)
+static int process_options(AVFilterContext *ctx, AVDictionary **options,
+ const char *args)
{
const AVOption *o = NULL;
- const char *p = args;
- char *val;
+ int ret, count = 0;
+ char *av_uninit(parsed_key), *av_uninit(value);
+ const char *key;
int offset= -1;
- while (*p) {
+ if (!args)
+ return 0;
+
+ while (*args) {
+ const char *shorthand = NULL;
+
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) {
+ if (o->type == AV_OPT_TYPE_CONST || o->offset == offset)
+ continue;
+ offset = o->offset;
+ shorthand = o->name;
}
- if (o->type == AV_OPT_TYPE_CONST || o->offset == offset)
- continue;
- offset = o->offset;
- val = av_get_token(&p, ":");
- if (!val)
- return AVERROR(ENOMEM);
+ ret = av_opt_get_key_value(&args, "=", ":",
+ shorthand ? AV_OPT_FLAG_IMPLICIT_KEY : 0,
+ &parsed_key, &value);
+ if (ret < 0) {
+ if (ret == AVERROR(EINVAL))
+ av_log(ctx, AV_LOG_ERROR, "No option name near '%s'\n", args);
+ else
+ av_log(ctx, AV_LOG_ERROR, "Unable to parse '%s': %s\n", args,
+ av_err2str(ret));
+ return ret;
+ }
+ if (*args)
+ args++;
+ if (parsed_key) {
+ key = parsed_key;
+ while ((o = av_opt_next(ctx->priv, o))); /* discard all remaining shorthand */
+ } else {
+ key = shorthand;
+ }
- av_dict_set(options, o->name, val, 0);
+ av_log(ctx, AV_LOG_DEBUG, "Setting '%s' to value '%s'\n", key, value);
+ av_dict_set(options, key, value, 0);
+ if ((ret = av_opt_set(ctx->priv, key, value, 0)) < 0) {
+ if (ret == AVERROR_OPTION_NOT_FOUND)
+ av_log(ctx, AV_LOG_ERROR, "Option '%s' not found\n", key);
+ av_free(value);
+ av_free(parsed_key);
+ return ret;
+ }
- av_freep(&val);
- if (*p)
- p++;
+ av_free(value);
+ av_free(parsed_key);
+ count++;
}
+ return count;
+}
+
+// TODO: drop me
+static const char *const filters_left_to_update[] = {
+ "abuffer",
+ "aconvert",
+ "aevalsrc",
+ "amerge",
+ "anullsrc",
+ "aresample",
+ "asendcmd",
+ "asetnsamples",
+ "astreamsync",
+ "atempo",
+ "bbox",
+ "blackdetect",
+ "buffer",
+ "flite",
+ "hue",
+ "mp",
+ "pan",
+ "removelogo",
+ "scale",
+ "sendcmd",
+ "setdar",
+ "setsar",
+};
+static int filter_use_deprecated_init(const char *name)
+{
+ int i;
+ for (i = 0; i < FF_ARRAY_ELEMS(filters_left_to_update); i++)
+ if (!strcmp(name, filters_left_to_update[i]))
+ return 1;
return 0;
}
AVDictionary *options = NULL;
AVDictionaryEntry *e;
int ret=0;
- int anton_options =
- !strcmp(filter->filter->name, "aformat") ||
- !strcmp(filter->filter->name, "blackframe") ||
- !strcmp(filter->filter->name, "boxblur" ) ||
- !strcmp(filter->filter->name, "crop" ) ||
- !strcmp(filter->filter->name, "format") ||
- !strcmp(filter->filter->name, "noformat") ||
- !strcmp(filter->filter->name, "resample")
- ;
+ int deprecated_init = filter_use_deprecated_init(filter->filter->name);
+ // TODO: remove old shorthand
if (filter->filter->shorthand) {
av_assert0(filter->priv);
av_assert0(filter->filter->priv_class);
args = NULL;
}
- if (anton_options && 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 (!deprecated_init && args && *args) {
+ if (!filter->filter->priv_class) {
+ av_log(filter, AV_LOG_ERROR, "This filter does not take any "
+ "options, but options were provided: %s.\n", args);
+ return AVERROR(EINVAL);
+ }
+
+#if FF_API_OLD_FILTER_OPTS
+ if (!strcmp(filter->filter->name, "scale") &&
+ strchr(args, ':') < strchr(args, '=')) {
+ /* old w:h:flags=<flags> syntax */
+ char *copy = av_strdup(args);
+ char *p;
+
+ av_log(filter, AV_LOG_WARNING, "The <w>:<h>:flags=<flags> option "
+ "syntax is deprecated. Use either <w>:<h>:<flags> or "
+ "w=<w>:h=<h>:flags=<flags>.\n");
+
+ if (!copy) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+
+ p = strrchr(copy, ':');
+ if (p) {
+ *p++ = 0;
+ ret = av_dict_parse_string(&options, p, "=", ":", 0);
+ }
+ if (ret >= 0)
+ ret = process_options(filter, &options, copy);
+ av_freep(©);
+
if (ret < 0)
goto fail;
-#if FF_API_OLD_FILTER_OPTS
- } else if (!strcmp(filter->filter->name, "format") ||
- !strcmp(filter->filter->name, "noformat")) {
+ } else if (!strcmp(filter->filter->name, "format") ||
+ !strcmp(filter->filter->name, "noformat") ||
+ !strcmp(filter->filter->name, "frei0r") ||
+ !strcmp(filter->filter->name, "frei0r_src") ||
+ !strcmp(filter->filter->name, "ocv")) {
/* a hack for compatibility with the old syntax
* replace colons with |s */
char *copy = av_strdup(args);
char *p = copy;
+ int nb_leading = 0; // number of leading colons to skip
if (!copy) {
ret = AVERROR(ENOMEM);
goto fail;
}
- if (strchr(copy, ':')) {
+ if (!strcmp(filter->filter->name, "frei0r") ||
+ !strcmp(filter->filter->name, "ocv"))
+ nb_leading = 1;
+ else if (!strcmp(filter->filter->name, "frei0r_src"))
+ nb_leading = 3;
+
+ while (nb_leading--) {
+ p = strchr(p, ':');
+ if (!p) {
+ p = copy + strlen(copy);
+ break;
+ }
+ p++;
+ }
+
+ if (strchr(p, ':')) {
av_log(filter, AV_LOG_WARNING, "This syntax is deprecated. Use "
"'|' to separate the list items.\n");
}
while ((p = strchr(p, ':')))
*p++ = '|';
- ret = process_unnamed_options(filter, &options, copy);
+ ret = process_options(filter, &options, copy);
av_freep(©);
if (ret < 0)
goto fail;
#endif
} else {
- ret = process_unnamed_options(filter, &options, args);
+ ret = process_options(filter, &options, args);
if (ret < 0)
goto fail;
}
}
- if (anton_options && filter->filter->priv_class) {
+ if (!deprecated_init && 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");
return ff_filter_frame_framed(link, frame);
}
}
+
+const AVClass *avfilter_get_class(void)
+{
+ return &avfilter_class;
+}