mirror of
https://github.com/mpv-player/mpv
synced 2025-02-17 13:17:13 +00:00
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.
This commit is contained in:
parent
29f9e44723
commit
7d424b4ce4
@ -4,8 +4,8 @@ AUDIO FILTERS
|
||||
Audio filters allow you to modify the audio stream and its properties. The
|
||||
syntax is:
|
||||
|
||||
``--af=<filter1[=parameter1:parameter2:...],filter2,...>``
|
||||
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=<filter1[=parameter1:parameter2:...],filter2,...>``
|
||||
Set defaults for each filter.
|
||||
|
||||
Audio filters are managed in lists. There are a few commands to manage the
|
||||
filter list:
|
||||
|
||||
``--af-add=<filter1[,filter2,...]>``
|
||||
Appends the filters given as arguments to the filter list.
|
||||
|
||||
``--af-pre=<filter1[,filter2,...]>``
|
||||
Prepends the filters given as arguments to the filter list.
|
||||
|
||||
``--af-del=<index1[,index2,...]>``
|
||||
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:
|
||||
|
||||
|
@ -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"] <property> "<value1>" "<value2>" ...``
|
||||
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
|
||||
|
@ -5,7 +5,37 @@ Video filters allow you to modify the video stream and its properties. The
|
||||
syntax is:
|
||||
|
||||
``--vf=<filter1[=parameter1:parameter2:...],filter2,...>``
|
||||
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:
|
||||
|
||||
``["@"<label-name>":"] ["!"] <filter-name> [ "=" <filter-parameter-list> ]``
|
||||
|
||||
and the ``filter-parameter-list``:
|
||||
|
||||
``<filter-parameter> | <filter-parameter> "," <filter-parameter-list>``
|
||||
|
||||
and ``filter-parameter``:
|
||||
|
||||
``( <param-name> "=" <param-value> ) | <param-value>``
|
||||
|
||||
``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.
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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)");
|
||||
|
@ -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) {
|
||||
|
Loading…
Reference in New Issue
Block a user