From 31611fc46b29e0704004e21f1e25de2f9608e109 Mon Sep 17 00:00:00 2001 From: wm4 Date: Mon, 3 Apr 2017 18:04:18 +0200 Subject: video: support positional arguments for automatic lavfi option bridge Now e.g. --vf=pad=1000:1000 works. All in all pretty ugly and hacky. Just look away. --- DOCS/man/vf.rst | 10 +++++----- common/av_common.c | 30 ++++++++++++++++++++++++++++++ options/m_option.c | 27 ++++++++++++++++++++++----- video/filter/vf_lavfi.c | 2 +- 4 files changed, 58 insertions(+), 11 deletions(-) diff --git a/DOCS/man/vf.rst b/DOCS/man/vf.rst index f2bd16033c..2d53fc4ce2 100644 --- a/DOCS/man/vf.rst +++ b/DOCS/man/vf.rst @@ -60,11 +60,11 @@ normal filter parameters. implemented in mpv only). If a filter is not builtin, the ``lavfi-bridge`` will be automatically - tried. Keep in mind that this filter does not support positional arguments - like ``--vf=name=arg1:arg2``. Instead, you must use - ``--vf=name=arg1name=arg1value:...``. This bridge also does not support - help output, and does not verify parameters before the filter is actually - used. + tried. This bridge does not support help output, and does not verify + parameters before the filter is actually used. Although the mpv syntax + is rather similar to libavfilter's, it's not the same. (Which means not + everything accepted by vf_lavfi's ``graph`` option will be accepted by + ``--vf``.) Video filters are managed in lists. There are a few commands to manage the filter list. diff --git a/common/av_common.c b/common/av_common.c index 5c58f3fea8..d7ad8e172c 100644 --- a/common/av_common.c +++ b/common/av_common.c @@ -302,6 +302,35 @@ void mp_avdict_print_unset(struct mp_log *log, int msgl, AVDictionary *dict) mp_msg(log, msgl, "Could not set AVOption %s='%s'\n", t->key, t->value); } +// If the name starts with "@", try to interpret it as a number, and set *name +// to the name of the n-th parameter. +static void resolve_positional_arg(void *avobj, char **name) +{ + if (!*name || (*name)[0] != '@') + return; + + char *end = NULL; + int pos = strtol(*name + 1, &end, 10); + if (!end || *end) + return; + + const AVOption *opt = NULL; + int offset = -1; + while (1) { + opt = av_opt_next(avobj, opt); + if (!opt) + return; + // This is what libavfilter's parser does to skip aliases. + if (opt->offset != offset && opt->type != AV_OPT_TYPE_CONST) + pos--; + if (pos < 0) { + *name = (char *)opt->name; + return; + } + offset = opt->offset; + } +} + // kv is in the format as by OPT_KEYVALUELIST(): kv[0]=key0, kv[1]=val0, ... // Set these options on given avobj (using av_opt_set..., meaning avobj must // point to a struct that has AVClass as first member). @@ -313,6 +342,7 @@ int mp_set_avopts(struct mp_log *log, void *avobj, char **kv) for (int n = 0; kv && kv[n * 2]; n++) { char *k = kv[n * 2 + 0]; char *v = kv[n * 2 + 1]; + resolve_positional_arg(avobj, &k); int r = av_opt_set(avobj, k, v, AV_OPT_SEARCH_CHILDREN); if (r == AVERROR_OPTION_NOT_FOUND) { mp_err(log, "AVOption '%s' not found.\n", k); diff --git a/options/m_option.c b/options/m_option.c index a30f89d18d..fa93dd47c7 100644 --- a/options/m_option.c +++ b/options/m_option.c @@ -2606,17 +2606,33 @@ static void copy_obj_settings_list(const m_option_t *opt, void *dst, static int get_obj_param(struct mp_log *log, bstr opt_name, bstr obj_name, struct m_config *config, bstr name, bstr val, int flags, bool nopos, - int *nold, bstr *out_name, bstr *out_val) + int *nold, bstr *out_name, bstr *out_val, + char *tmp, size_t tmp_size) { int r; if (!config) { - *out_name = name; // preserve args for opengl-hq legacy handling - *out_val = val; + // Duplicates the logic below, but with unknown parameter types/names. + if (val.start || nopos) { + *out_name = name; + *out_val = val; + } else { + val = name; + // positional fields + if (val.len == 0) { // Empty field, count it and go on + (*nold)++; + return 0; + } + // Positional naming convention for/followed by mp_set_avopts(). + snprintf(tmp, tmp_size, "@%d", *nold); + *out_name = bstr0(tmp); + *out_val = val; + (*nold)++; + } return 1; } - // va.start != NULL => of the form name=val (not positional) + // val.start != NULL => of the form name=val (not positional) // If it's just "name", and the associated option exists and is a flag, // don't accept it as positional argument. if (val.start || m_config_option_requires_param(config, name) == 0 || nopos) { @@ -2683,6 +2699,7 @@ static int m_obj_parse_sub_config(struct mp_log *log, struct bstr opt_name, char **args = NULL; int num_args = 0; int r = 1; + char tmp[80]; if (ret) { args = *ret; @@ -2708,7 +2725,7 @@ static int m_obj_parse_sub_config(struct mp_log *log, struct bstr opt_name, if (bstr_equals0(fname, "help")) goto print_help; r = get_obj_param(log, opt_name, name, config, fname, fval, flags, - nopos, &nold, &fname, &fval); + nopos, &nold, &fname, &fval, tmp, sizeof(tmp)); if (r < 0) goto exit; diff --git a/video/filter/vf_lavfi.c b/video/filter/vf_lavfi.c index 91930e3b02..28869075b5 100644 --- a/video/filter/vf_lavfi.c +++ b/video/filter/vf_lavfi.c @@ -172,7 +172,7 @@ static bool recreate_graph(struct vf_instance *vf, struct mp_image_params *fmt) if (!filter) goto error; - if (mp_set_avopts(vf->log, filter, p->cfg_filter_opts) < 0) + if (mp_set_avopts(vf->log, filter->priv, p->cfg_filter_opts) < 0) goto error; if (avfilter_init_str(filter, NULL) < 0) -- cgit v1.2.3