From 7d424b4ce45534ade52f38df68308498decc0171 Mon Sep 17 00:00:00 2001 From: wm4 Date: Sat, 25 Mar 2017 17:07:40 +0100 Subject: command: add better runtime filter toggling method Basically, see the example in input.rst. This is better than the "old" vf-toggle method, because it doesn't require the user to duplicate the filter string in mpv.conf and input.conf. Some aspects of this changes are untested, so enjoy your alpha testing. --- DOCS/man/af.rst | 27 ++++----------------------- DOCS/man/input.rst | 13 +++++++++++++ DOCS/man/vf.rst | 32 +++++++++++++++++++++++++++++++- audio/filter/af.c | 3 +++ options/m_option.c | 45 ++++++++++++++++++++++++++++++++++++++------- options/m_option.h | 4 ++++ player/command.c | 5 ++++- video/filter/vf.c | 3 +++ 8 files changed, 100 insertions(+), 32 deletions(-) diff --git a/DOCS/man/af.rst b/DOCS/man/af.rst index 040b44cd64..9dff18ebbe 100644 --- a/DOCS/man/af.rst +++ b/DOCS/man/af.rst @@ -4,8 +4,8 @@ AUDIO FILTERS Audio filters allow you to modify the audio stream and its properties. The syntax is: -``--af=`` - Setup a chain of audio filters. +``--af=...`` + Setup a chain of audio filters. See ``--vf`` for the syntax. .. note:: @@ -15,27 +15,8 @@ syntax is: wrapper, which gives you access to most of libavfilter's filters. This includes all filters that have been ported from MPlayer to libavfilter. -You can also set defaults for each filter. The defaults are applied before the -normal filter parameters. - -``--af-defaults=`` - Set defaults for each filter. - -Audio filters are managed in lists. There are a few commands to manage the -filter list: - -``--af-add=`` - Appends the filters given as arguments to the filter list. - -``--af-pre=`` - Prepends the filters given as arguments to the filter list. - -``--af-del=`` - Deletes the filters at the given indexes. Index numbers start at 0, - negative numbers address the end of the list (-1 is the last). - -``--af-clr`` - Completely empties the filter list. +See ``--vf`` group of options for info on how ``--af-defaults``, ``--af-add``, +``--af-pre``, ``--af-del``, ``--af-clr``, and possibly others work. Available filters are: diff --git a/DOCS/man/input.rst b/DOCS/man/input.rst index 9e578867cf..d252bb93a1 100644 --- a/DOCS/man/input.rst +++ b/DOCS/man/input.rst @@ -452,6 +452,9 @@ Input Commands that are Possibly Subject to Change (If several filters are passed to the command, this is done for each filter.) + A special variant is combining this with labels, and using ``@name:!`` + as filter entry. This toggles the enable/disable flag. + del Remove the given filters from the video chain. Unlike in the other cases, the second parameter is a comma separated list of filter names @@ -487,6 +490,16 @@ Input Commands that are Possibly Subject to Change - ``b vf set ""`` remove all video filters on ``b`` - ``c vf toggle lavfi=gradfun`` toggle debanding on ``c`` + .. admonition:: Example how to toggle disabled filters at runtime + + - Add something ``vf-add=@deband:!lavfi=[gradfun]`` to ``mpv.conf``. The + ``@deband:`` is the label, and ``deband`` is an arbitrary, user-given + name for this filter entry. The ``!`` before the filter name disables + the filter by default. Everything after this is the normal filter name + and the filter parameters. + - Add ``a vf toggle @deband:!`` to ``input.conf``. This toggles the + "disabled" flag for the filter identified with ``deband``. + ``cycle-values ["!reverse"] "" "" ...`` Cycle through a list of values. Each invocation of the command will set the given property to the next value in the list. The command maintains an diff --git a/DOCS/man/vf.rst b/DOCS/man/vf.rst index 9da20942f6..a3f7ee6dab 100644 --- a/DOCS/man/vf.rst +++ b/DOCS/man/vf.rst @@ -5,7 +5,37 @@ Video filters allow you to modify the video stream and its properties. The syntax is: ``--vf=`` - Setup a chain of video filters. + Setup a chain of video filters. This consists on the filter name, and an + option list of parameters after ``=``. The parameters are separated by + ``:`` (not ``,``, as that starts a new filter entry). + + Before the filter name, a label can be specified with ``@name:``, where + name is an arbitrary user-given name, which identifies the filter. This + is only needed if you want to toggle the filter at runtime. + + A ``!`` before the filter name means the filter is enabled by default. It + will be skipped on filter creation. This is also useful for runtime filter + toggling. + + See the ``vf`` command (and ``toggle`` sub-command) for further explanations + and examples. + + The general filter entry syntax is: + + ``["@"":"] ["!"] [ "=" ]`` + + and the ``filter-parameter-list``: + + `` | "," `` + + and ``filter-parameter``: + + ``( "=" ) | `` + + ``param-value`` can further be quoted in ``[`` / ``]`` in case the value + contains characters like ``,`` or ``=``. This is used in particular with + the ``lavfi`` filter, which uses a very similar syntax as mpv (MPlayer + historically) to specify filters and their parameters. You can also set defaults for each filter. The defaults are applied before the normal filter parameters. diff --git a/audio/filter/af.c b/audio/filter/af.c index 31f4e45614..84ee377136 100644 --- a/audio/filter/af.c +++ b/audio/filter/af.c @@ -78,6 +78,7 @@ static bool get_desc(struct m_obj_desc *dst, int index) const struct m_obj_list af_obj_list = { .get_desc = get_desc, .description = "audio filters", + .allow_disable_entries = true, .aliases = { {"force", "format"}, {0} @@ -545,6 +546,8 @@ int af_init(struct af_stream *s) // Add all filters in the list (if there are any) struct m_obj_settings *list = s->opts->af_settings; for (int i = 0; list && list[i].name; i++) { + if (!list[i].enabled) + continue; struct af_instance *af = af_prepend(s, s->last, list[i].name, list[i].attribs); if (!af) { diff --git a/options/m_option.c b/options/m_option.c index 7f30b73a9a..29bbcb17db 100644 --- a/options/m_option.c +++ b/options/m_option.c @@ -2590,6 +2590,7 @@ static void copy_obj_settings_list(const m_option_t *opt, void *dst, for (n = 0; s[n].name; n++) { d[n].name = talloc_strdup(NULL, s[n].name); d[n].label = talloc_strdup(NULL, s[n].label); + d[n].enabled = s[n].enabled; d[n].attribs = NULL; copy_str_list(NULL, &(d[n].attribs), &(s[n].attribs)); } @@ -2754,7 +2755,7 @@ exit: #define NAMECH "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-" // Parse one item, e.g. -vf a=b:c:d,e=f:g => parse a=b:c:d into "a" and "b:c:d" -static int parse_obj_settings(struct mp_log *log, struct bstr opt, +static int parse_obj_settings(struct mp_log *log, struct bstr opt, int op, struct bstr *pstr, const struct m_obj_list *list, m_obj_settings_t **_ret) { @@ -2763,6 +2764,7 @@ static int parse_obj_settings(struct mp_log *log, struct bstr opt, struct m_obj_desc desc; bstr label = {0}; bool nopos = list->disallow_positional_parameters; + bool enabled = true; if (bstr_eatstart0(pstr, "@")) { if (!bstr_split_tok(*pstr, ":", &label, pstr)) { @@ -2771,9 +2773,14 @@ static int parse_obj_settings(struct mp_log *log, struct bstr opt, } } + if (list->allow_disable_entries && bstr_eatstart0(pstr, "!")) + enabled = false; + bool has_param = false; int idx = bstrspn(*pstr, NAMECH); bstr str = bstr_splice(*pstr, 0, idx); + if (str.len == 0 && !enabled && label.len && op == OP_TOGGLE) + goto done; // "@labelname:!" is the special enable/disable toggle syntax *pstr = bstr_cut(*pstr, idx); // video filters use "=", VOs use ":" if (bstr_eatstart0(pstr, "=") || bstr_eatstart0(pstr, ":")) @@ -2817,9 +2824,11 @@ static int parse_obj_settings(struct mp_log *log, struct bstr opt, if (!_ret) return 1; +done: ; m_obj_settings_t item = { .name = bstrto0(NULL, str), .label = bstrdup0(NULL, label), + .enabled = enabled, .attribs = plist, }; obj_settings_list_insert_at(_ret, -1, &item); @@ -2964,7 +2973,7 @@ static int parse_obj_settings_list(struct mp_log *log, const m_option_t *opt, if (op == OP_DEL) r = parse_obj_settings_del(log, name, ¶m, dst, mark_del); if (r == 0) { - r = parse_obj_settings(log, name, ¶m, ol, dst ? &res : NULL); + r = parse_obj_settings(log, name, op, ¶m, ol, dst ? &res : NULL); } if (r < 0) return r; @@ -3017,12 +3026,25 @@ static int parse_obj_settings_list(struct mp_log *log, const m_option_t *opt, talloc_free(res); } else if (op == OP_TOGGLE) { for (int n = 0; res && res[n].name; n++) { - int found = obj_settings_find_by_content(list, &res[n]); - if (found < 0) { - obj_settings_list_insert_at(&list, -1, &res[n]); - } else { - obj_settings_list_del_at(&list, found); + if (!res[n].enabled && !res[n].name[0]) { + // Toggle enable/disable special case. + int found = + obj_settings_list_find_by_label0(list, res[n].label); + if (found < 0) { + mp_warn(log, "Option %.*s: Label %s not found\n", + BSTR_P(name), res[n].label); + } else { + list[found].enabled = !list[found].enabled; + } obj_setting_free(&res[n]); + } else { + int found = obj_settings_find_by_content(list, &res[n]); + if (found < 0) { + obj_settings_list_insert_at(&list, -1, &res[n]); + } else { + obj_settings_list_del_at(&list, found); + obj_setting_free(&res[n]); + } } } talloc_free(res); @@ -3073,6 +3095,8 @@ static char *print_obj_settings_list(const m_option_t *opt, const void *val) // Assume labels and names don't need escaping if (entry->label && entry->label[0]) res = talloc_asprintf_append(res, "@%s:", entry->label); + if (!entry->enabled) + res = talloc_strdup_append(res, "!"); res = talloc_strdup_append(res, entry->name); if (entry->attribs && entry->attribs[0]) { res = talloc_strdup_append(res, "="); @@ -3111,6 +3135,10 @@ static int set_obj_settings_list(const m_option_t *opt, void *dst, if (val->format != MPV_FORMAT_STRING) goto error; entry->label = talloc_strdup(NULL, val->u.string); + } else if (strcmp(key, "enabled") == 0) { + if (val->format != MPV_FORMAT_FLAG) + goto error; + entry->enabled = val->u.flag; } else if (strcmp(key, "params") == 0) { if (val->format != MPV_FORMAT_NODE_MAP) goto error; @@ -3176,6 +3204,9 @@ static int get_obj_settings_list(const m_option_t *opt, void *ta_parent, add_map_string(nentry, "name", entry->name); if (entry->label && entry->label[0]) add_map_string(nentry, "label", entry->label); + struct mpv_node *enabled = add_map_entry(nentry, "enabled"); + enabled->format = MPV_FORMAT_FLAG; + enabled->u.flag = entry->enabled; struct mpv_node *params = add_map_entry(nentry, "params"); params->format = MPV_FORMAT_NODE_MAP; params->u.list = talloc_zero(ta_parent, struct mpv_node_list); diff --git a/options/m_option.h b/options/m_option.h index 8709d20bb2..f3a4e7bc1e 100644 --- a/options/m_option.h +++ b/options/m_option.h @@ -146,6 +146,8 @@ struct m_obj_list { // Allow unknown entries, for which a dummy entry is inserted, and whose // options are skipped and ignored. bool allow_unknown_entries; + // Allow syntax for disabling entries. + bool allow_disable_entries; // This helps with confusing error messages if unknown flag options are used. bool disallow_positional_parameters; // Each sub-item is backed by global options (for AOs and VOs). @@ -162,6 +164,8 @@ typedef struct m_obj_settings { char *name; // Optional user-defined name. char *label; + // User enable flag. + bool enabled; // NULL terminated array of parameter/value pairs. char **attribs; } m_obj_settings_t; diff --git a/player/command.c b/player/command.c index 9050812fb3..28d331c97e 100644 --- a/player/command.c +++ b/player/command.c @@ -3449,7 +3449,10 @@ static char *print_obj_osd_list(struct m_obj_settings *list) list[n].attribs[i], list[n].attribs[i + 1]); } - res = talloc_asprintf_append(res, "]\n"); + res = talloc_asprintf_append(res, "]"); + if (!list[n].enabled) + res = talloc_strdup_append(res, " (disabled)"); + res = talloc_strdup_append(res, "\n"); } if (!res) res = talloc_strdup(NULL, "(empty)"); diff --git a/video/filter/vf.c b/video/filter/vf.c index 94e6760603..5208c7f824 100644 --- a/video/filter/vf.c +++ b/video/filter/vf.c @@ -128,6 +128,7 @@ static bool get_desc(struct m_obj_desc *dst, int index) const struct m_obj_list vf_obj_list = { .get_desc = get_desc, .description = "video filters", + .allow_disable_entries = true, }; // Try the cmd on each filter (starting with the first), and stop at the first @@ -322,6 +323,8 @@ struct vf_instance *vf_append_filter(struct vf_chain *c, const char *name, int vf_append_filter_list(struct vf_chain *c, struct m_obj_settings *list) { for (int n = 0; list && list[n].name; n++) { + if (!list[n].enabled) + continue; struct vf_instance *vf = vf_append_filter(c, list[n].name, list[n].attribs); if (vf) { -- cgit v1.2.3