1
0
mirror of https://github.com/mpv-player/mpv synced 2024-12-27 17:42:17 +00:00

command: give named arguments to almost all commands

Before this change, only 1 command or so had named arguments. There is
no reason why other commands can't have them, except that it's a bit of
work to add them.

Commands with variable number of arguments are inherently incompatible
to named arguments, such as the "run" command. They still have dummy
names, but obviously you can't assign multiple values to a single named
argument (unless the argument has an array type, which would be
something different). For now, disallow using named argument APIs with
these commands. This might change later.

2 commands are adjusted to not need a separate default value by changing
flag constants. (The numeric values are C only and can't be set by
users.)

Make the command syntax in the manpage more consistent. Now none of the
allowed choice/flag names are in the command header, and all arguments
are shown with their proper name and quoted with <...>.

Some places in the manpage and the client.h doxygen are updated to
reflect that most commands support named arguments. In addition, try to
improve the documentation of the syntax and need for escaping etc. as
well.

(Or actually most uses of the word "argument" should be "parameter".)
This commit is contained in:
wm4 2018-05-17 20:10:39 +02:00
parent d36b85cfdf
commit 332907e1d7
5 changed files with 406 additions and 246 deletions

View File

@ -106,6 +106,9 @@ Interface changes
- ipc: require that "request_id" fields are integers. Other types are still
accepted for compatibility, but this will stop in the future. Also, if no
request_id is provided, 0 will be assumed.
- mpv_command_node() and mp.command_native() now support named arguments
(see manpage). If you want to use them, use a new version of the manpage
as reference, which lists the definitive names.
--- mpv 0.28.0 ---
- rename --hwdec=mediacodec option to mediacodec-copy, to reflect
conventions followed by other hardware video decoding APIs

View File

@ -41,10 +41,10 @@ commands they're bound to on the OSD, instead of executing the commands::
(Only closing the window will make **mpv** exit, pressing normal keys will
merely display the binding, even if mapped to quit.)
General Input Command Syntax
----------------------------
input.conf syntax
-----------------
``[Shift+][Ctrl+][Alt+][Meta+]<key> [{<section>}] [<prefixes>] <command> (<argument>)* [; <command>]``
``[Shift+][Ctrl+][Alt+][Meta+]<key> [{<section>}] <command> ( ; <command> )*``
Note that by default, the right Alt key can be used to create special
characters, and thus does not register as a modifier. The option
@ -59,9 +59,9 @@ character), or a symbolic name (as printed by ``--input-keylist``).
``<section>`` (braced with ``{`` and ``}``) is the input section for this
command.
Arguments are separated by whitespace. This applies even to string arguments.
For this reason, string arguments should be quoted with ``"``. Inside quotes,
C-style escaping can be used.
``<command>`` is the command itself. It consists of the command name and
multiple (or none) commands, all separated by whitespace. String arguments
need to be quoted with ``"``. Details see ``Flat command syntax``.
You can bind multiple commands to one key. For example:
@ -78,25 +78,89 @@ that matches, and the multi-key command will never be called. Intermediate keys
can be remapped to ``ignore`` in order to avoid this issue. The maximum number
of (non-modifier) keys for combinations is currently 4.
Flat command syntax
-------------------
This is the syntax used in input.conf, and referred to "input.conf syntax" in
a number of other places.
``<command> ::= [<prefixes>] <command_name> (<argument>)*``
``<argument> ::= (<string> | " <quoted_string> " )``
``command_name`` is an unquoted string with the command name itself. See
`List of Input Commands`_ for a list.
Arguments are separated by whitespace. This applies even to string arguments.
For this reason, string arguments should be quoted with ``"``. If a string
argument contains spaces or certain special characters, quoting and possibly
escaping is mandatory, or the command cannot be parsed correctly.
Inside quotes, C-style escaping can be used. JSON escapes according to RFC 8259,
minus surrogate pair escapes, should be a safe subset that can be used.
Commands specified as arrays
----------------------------
This applies to certain APIs, such as ``mp.commandv()`` or
``mp.command_native()`` (with array parameters) in Lua scripting, or
``mpv_command()`` or ``mpv_command_node()`` (with MPV_FORMAT_NODE_ARRAY) in the
C libmpv client API.
The command as well as all arguments are passed as a single array. Similar to
the `Flat command syntax`_, you can first pass prefixes as strings (each as
separate array item), then the command name as string, and then each argument
as string or a native value.
Since these APIs pass arguments as separate strings or native values, they do
not expect quotes, and do support escaping. Technically, there is the input.conf
parser, which first splits the command string into arguments, and then invokes
argument parsers for each argument. The input.conf parser normally handles
quotes and escaping. The array command APIs mentioned above pass strings
directly to the argument parsers, or can sidestep them by the ability to pass
non-string values.
Sometimes commands have string arguments, that in turn are actually parsed by
other components (e.g. filter strings with ``vf add``) - in these cases, you
you would have to double-escape in input.conf, but not with the array APIs.
For complex commands, consider using `Named arguments`_ instead, which should
give slightly more compatibility. Some commands do not support named arguments
and inherently take an array, though.
Named arguments
---------------
Some commands support named arguments (most currently don't). Named arguments
cannot be used with the "flat" input.conf syntax shown above, but require using
e.g. ``mp.command_native()`` in Lua scripting, or e.g. ``mpv_command_node()``
with the libmpv API. Some commands ask you to only use named arguments (because
the command order is not guaranteed), which means you can't use them as
key bindings in input.conf at all.
This applies to certain APIs, such as ``mp.command_native()`` (with tables that
have string keys) in Lua scripting, or ``mpv_command_node()`` (with
MPV_FORMAT_NODE_MAP) in the C libmpv client API.
Like with array commands, quoting and escaping is inherently not needed in the
normal case.
The name of each command is defined in each command description in the
`List of Input Commands`_.
Some commands do not support named arguments (e.g. ``run`` command). You need
to use APIs that pass arguments as arrays.
Named arguments are not supported in the "flat" input.conf syntax, which means
you cannot use them for key bindings in input.conf at all.
List of Input Commands
----------------------
Commands with parameters have the parameter name enclosed in ``<`` / ``>``.
Don't add those to the actual command. Optional arguments are enclosed in
``[`` / ``]``. If you don't pass them, they will be set to a default value.
Remember to quote string arguments in input.conf (see `Flat command syntax`_).
``ignore``
Use this to "block" keys that should be unbound, and do nothing. Useful for
disabling default bindings, without disabling all bindings with
``--no-input-default-bindings``.
``seek <seconds> [relative|absolute|absolute-percent|relative-percent|exact|keyframes]``
``seek <target> [<flags>]``
Change the playback position. By default, seeks by a relative amount of
seconds.
@ -124,7 +188,7 @@ List of Input Commands
3rd parameter (essentially using a space instead of ``+``). The 3rd
parameter is still parsed, but is considered deprecated.
``revert-seek [mode]``
``revert-seek [<flags>]``
Undoes the ``seek`` command, and some other commands that seek (but not
necessarily all of them). Calling this command once will jump to the
playback position before the seek. Calling it a second time undoes the
@ -154,22 +218,24 @@ List of Input Commands
This does not work with audio-only playback.
``set <property> "<value>"``
Set the given property to the given value.
``set <name> <value>``
Set the given property or option to the given value.
``add <property> [<value>]``
Add the given value to the property. On overflow or underflow, clamp the
property to the maximum. If ``<value>`` is omitted, assume ``1``.
``add <name> [<value>]``
Add the given value to the property or option. On overflow or underflow,
clamp the property to the maximum. If ``<value>`` is omitted, assume ``1``.
``cycle <property> [up|down]``
Cycle the given property. ``up`` and ``down`` set the cycle direction. On
overflow, set the property back to the minimum, on underflow set it to the
maximum. If ``up`` or ``down`` is omitted, assume ``up``.
``cycle <name> [<value>]``
Cycle the given property or option. The second argument can be ``up`` or
``down`` to set the cycle direction. On overflow, set the property back to
the minimum, on underflow set it to the maximum. If ``up`` or ``down`` is
omitted, assume ``up``.
``multiply <property> <factor>``
Multiplies the value of a property with the numeric factor.
``multiply <name> <value>``
Similar to ``add``, but multiplies the property or option with the numeric
value.
``screenshot [subtitles|video|window|single|each-frame]``
``screenshot <flags>``
Take a screenshot.
Multiple flags are available (some can be combined with ``+``):
@ -201,36 +267,41 @@ List of Input Commands
normal standalone commands, this is always asynchronous, and the flag has
no effect. (This behavior changed with mpv 0.29.0.)
``screenshot-to-file "<filename>" [subtitles|video|window]``
``screenshot-to-file <filename> <flags>``
Take a screenshot and save it to a given file. The format of the file will
be guessed by the extension (and ``--screenshot-format`` is ignored - the
behavior when the extension is missing or unknown is arbitrary).
The second argument is like the first argument to ``screenshot``.
The second argument is like the first argument to ``screenshot`` and
supports ``subtitles``, ``video``, ``window``.
If the file already exists, it's overwritten.
Like all input command parameters, the filename is subject to property
expansion as described in `Property Expansion`_.
``playlist-next [weak|force]``
``playlist-next <flags>``
Go to the next entry on the playlist.
First argument:
weak (default)
If the last file on the playlist is currently played, do nothing.
force
Terminate playback if there are no more files on the playlist.
``playlist-prev [weak|force]``
``playlist-prev <flags>``
Go to the previous entry on the playlist.
First argument:
weak (default)
If the first file on the playlist is currently played, do nothing.
force
Terminate playback if the first file is being played.
``loadfile "<file>" [replace|append|append-play [options]]``
Load the given file and play it.
``loadfile <url> [<flags> [<options>]]``
Load the given file or URL and play it.
Second argument:
@ -248,13 +319,20 @@ List of Input Commands
Not all options can be changed this way. Some options require a restart
of the player.
``loadlist "<playlist>" [replace|append]``
Load the given playlist file (like ``--playlist``).
``loadlist <url> [<flags>]``
Load the given playlist file or URL (like ``--playlist``).
Second argument:
<replace> (default)
Stop playback and replace the internal playlist with the new one.
<append>
Append the new playlist at the end of the current internal playlist.
``playlist-clear``
Clear the playlist, except the currently played file.
``playlist-remove current|<index>``
``playlist-remove <index>``
Remove the playlist entry at the given index. Index values start counting
with 0. The special value ``current`` removes the current entry. Note that
removing the current entry also stops playback and starts playing the next
@ -271,12 +349,14 @@ List of Input Commands
Shuffle the playlist. This is similar to what is done on start if the
``--shuffle`` option is used.
``run "command" "arg1" "arg2" ...``
``run <command> [<arg1> [<arg2> [...]]]``
Run the given command. Unlike in MPlayer/mplayer2 and earlier versions of
mpv (0.2.x and older), this doesn't call the shell. Instead, the command
is run directly, with each argument passed separately. Each argument is
expanded like in `Property Expansion`_. Note that there is a static limit
of (as of this writing) 9 arguments (this limit could be raised on demand).
expanded like in `Property Expansion`_.
This command has a variable number of arguments, and cannot be used with
named arguments.
The program is run in a detached way. mpv doesn't wait until the command
is completed, but continues playback right after spawning it.
@ -376,15 +456,15 @@ List of Input Commands
will seek to the previous position on start. The (optional) argument is
exactly as in the ``quit`` command.
``sub-add "<file>" [<flags> [<title> [<lang>]]]``
Load the given subtitle file. It is selected as current subtitle after
loading.
``sub-add <url> [<flags> [<title> [<lang>]]]``
Load the given subtitle file or stream. By default, it is selected as
current subtitle after loading.
The ``flags`` args is one of the following values:
The ``flags`` argument is one of the following values:
<select>
Select the subtitle immediately.
Select the subtitle immediately (default).
<auto>
@ -427,11 +507,11 @@ List of Input Commands
events that have already been displayed, or are within a short prefetch
range.
``print-text "<string>"``
``print-text <text>``
Print text to stdout. The string can contain properties (see
`Property Expansion`_).
`Property Expansion`_). Take care to put the argument in quotes.
``show-text "<string>" [<duration>|- [<level>]]``
``show-text <text> [<duration> [<level>]]``
Show text on the OSD. The string can contain properties, which are expanded
as described in `Property Expansion`_. This can be used to show playback
time, filename, and so on.
@ -443,7 +523,7 @@ List of Input Commands
<level>
The minimum OSD level to show the text at (see ``--osd-level``).
``expand-text "<string>"``
``expand-text <string>``
Property-expand the argument and return the expanded string. This can be
used only through the client API or from a script using
``mp.command_native``. (see `Property Expansion`_).
@ -461,7 +541,7 @@ List of Input Commands
essentially like ``quit``. Useful for the client API: playback can be
stopped without terminating the player.
``mouse <x> <y> [<button> [single|double]]``
``mouse <x> <y> [<button> [<mode>]]``
Send a mouse event with given coordinate (``<x>``, ``<y>``).
Second argument:
@ -478,24 +558,24 @@ List of Input Commands
<double>
The mouse event represents double-click.
``keypress <key_name>``
``keypress <name>``
Send a key event through mpv's input handler, triggering whatever
behavior is configured to that key. ``key_name`` uses the ``input.conf``
behavior is configured to that key. ``name`` uses the ``input.conf``
naming scheme for keys and modifiers. Useful for the client API: key events
can be sent to libmpv to handle internally.
``keydown <key_name>``
``keydown <name>``
Similar to ``keypress``, but sets the ``KEYDOWN`` flag so that if the key is
bound to a repeatable command, it will be run repeatedly with mpv's key
repeat timing until the ``keyup`` command is called.
``keyup [<key_name>]``
``keyup [<name>]``
Set the ``KEYUP`` flag, stopping any repeated behavior that had been
triggered. ``key_name`` is optional. If ``key_name`` is not given or is an
triggered. ``name`` is optional. If ``name`` is not given or is an
empty string, ``KEYUP`` will be set on all keys. Otherwise, ``KEYUP`` will
only be set on the key specified by ``key_name``.
only be set on the key specified by ``name``.
``audio-add "<file>" [<flags> [<title> [<lang>]]]``
``audio-add <url> [<flags> [<title> [<lang>]]]``
Load the given audio file. See ``sub-add`` command.
``audio-remove [<id>]``
@ -523,21 +603,21 @@ List of Input Commands
Input Commands that are Possibly Subject to Change
--------------------------------------------------
``af set|add|toggle|del|clr "filter1=params,filter2,..."``
``af <operation> <value>``
Change audio filter chain. See ``vf`` command.
``vf set|add|toggle|del|clr "filter1=params,filter2,..."``
``vf <operation> <value>``
Change video filter chain.
The first argument decides what happens:
set
<set>
Overwrite the previous filter chain with the new one.
add
<add>
Append the new filter chain to the previous one.
toggle
<toggle>
Check if the given filter (with the exact parameters) is already
in the video chain. If yes, remove the filter. If no, add the filter.
(If several filters are passed to the command, this is done for
@ -547,14 +627,14 @@ Input Commands that are Possibly Subject to Change
without filter name and parameters as filter entry. This toggles the
enable/disable flag.
del
<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
or integer indexes. ``0`` would denote the first filter. Negative
indexes start from the last filter, and ``-1`` denotes the last
filter.
clr
<clr>
Remove all filters. Note that like the other sub-commands, this does
not control automatically inserted filters.
@ -593,18 +673,21 @@ Input Commands that are Possibly Subject to Change
"disabled" flag for the filter with the label ``deband`` when the
``a`` key is hit.
``cycle-values ["!reverse"] <property> "<value1>" "<value2>" ...``
``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 will use the
current value of the property/option, and use it to determine the current
position in the list of values. Once it has found it, it will set the
next value in the list (wrapping around to the first item if needed).
This command has a variable number of arguments, and cannot be used with
named arguments.
The special argument ``!reverse`` can be used to cycle the value list in
reverse. The only advantage is that you don't need to reverse the value
list yourself when adding a second key binding for cycling backwards.
``enable-section "<section>" [flags]``
``enable-section <name> [<flags>]``
Enable all key bindings in the named input section.
The enabled input sections form a stack. Bindings in sections on the top of
@ -626,10 +709,10 @@ Input Commands that are Possibly Subject to Change
<allow-vo-dragging>
Same.
``disable-section "<section>"``
``disable-section <name>``
Disable the named input section. Undoes ``enable-section``.
``define-section "<section>" "<contents>" [default|force]``
``define-section <name> <contents> [<flags>]``
Create a named input section, or replace the contents of an already existing
input section. The ``contents`` parameter uses the same syntax as the
``input.conf`` file (except that using the section syntax in it is not
@ -657,7 +740,7 @@ Input Commands that are Possibly Subject to Change
information about the key state. The special key name ``unmapped`` can be
used to match any unmapped key.
``overlay-add <id> <x> <y> "<file>" <offset> "<fmt>" <w> <h> <stride>``
``overlay-add <id> <x> <y> <file> <offset> <fmt> <w> <h> <stride>``
Add an OSD overlay sourced from raw data. This might be useful for scripts
and applications controlling mpv, and which want to display things on top
of the video window.
@ -668,6 +751,9 @@ Input Commands that are Possibly Subject to Change
anamorphic video (such as DVD), ``osd-par`` should be read as well, and the
overlay should be aspect-compensated.
This has the following named arguments. The order of them is not guaranteed,
so you should always call them with named arguments, see `Named arguments`_.
``id`` is an integer between 0 and 63 identifying the overlay element. The
ID can be used to add multiple overlay parts, update a part by using this
command with an already existing ID, or to remove a part with
@ -725,18 +811,24 @@ Input Commands that are Possibly Subject to Change
Remove an overlay added with ``overlay-add`` and the same ID. Does nothing
if no overlay with this ID exists.
``script-message "<arg1>" "<arg2>" ...``
``script-message [<arg1> [<arg2> [...]]]``
Send a message to all clients, and pass it the following list of arguments.
What this message means, how many arguments it takes, and what the arguments
mean is fully up to the receiver and the sender. Every client receives the
message, so be careful about name clashes (or use ``script-message-to``).
``script-message-to "<target>" "<arg1>" "<arg2>" ...``
This command has a variable number of arguments, and cannot be used with
named arguments.
``script-message-to <target> [<arg1> [<arg2> [...]]]``
Same as ``script-message``, but send it only to the client named
``<target>``. Each client (scripts etc.) has a unique name. For example,
Lua scripts can get their name via ``mp.get_script_name()``.
``script-binding "<name>"``
This command has a variable number of arguments, and cannot be used with
named arguments.
``script-binding <name>``
Invoke a script-provided key binding. This can be used to remap key
bindings provided by external Lua scripts.
@ -773,7 +865,7 @@ Input Commands that are Possibly Subject to Change
unseekable streams that are going out of sync.
This command might be changed or removed in the future.
``screenshot-raw [subtitles|video|window]``
``screenshot-raw [<flags>]``
Return a screenshot in memory. This can be used only through the client
API. The MPV_FORMAT_NODE_MAP returned by this command has the ``w``, ``h``,
``stride`` fields set to obvious contents. The ``format`` field is set to
@ -783,7 +875,10 @@ Input Commands that are Possibly Subject to Change
is freed as soon as the result mpv_node is freed. As usual with client API
semantics, you are not allowed to write to the image data.
``vf-command "<label>" "<cmd>" "<args>"``
The ``flags`` argument is like the first argument to ``screenshot`` and
supports ``subtitles``, ``video``, ``window``.
``vf-command <label> <command> <argument>``
Send a command to the filter with the given ``<label>``. Use ``all`` to send
it to all filters at once. The command and argument string is filter
specific. Currently, this only works with the ``lavfi`` filter - see
@ -792,10 +887,10 @@ Input Commands that are Possibly Subject to Change
Note that the ``<label>`` is a mpv filter label, not a libavfilter filter
name.
``af-command "<label>" "<cmd>" "<args>"``
``af-command <label> <command> <argument>``
Same as ``vf-command``, but for audio filters.
``apply-profile "<name>"``
``apply-profile <name>``
Apply the contents of a named profile. This is like using ``profile=name``
in a config file, except you can map it to a key binding to change it at
runtime.
@ -803,14 +898,14 @@ Input Commands that are Possibly Subject to Change
There is no such thing as "unapplying" a profile - applying a profile
merely sets all option values listed within the profile.
``load-script "<path>"``
``load-script <filename>``
Load a script, similar to the ``--script`` option. Whether this waits for
the script to finish initialization or not changed multiple times, and the
future behavior is left undefined.
``change-list "<option>" "<operation>" "<value>"``
``change-list <name> <operation> <value>``
This command changes list options as described in `List Options`_. The
``<option>`` parameter is the normal option name, while ``<operation>`` is
``<name>`` parameter is the normal option name, while ``<operation>`` is
the suffix or action used on the option.
Some operations take no value, but the command still requires the value

View File

@ -239,6 +239,13 @@ static bool cmd_node_map(struct mp_log *log, struct mp_cmd *cmd, mpv_node *node)
if (!find_cmd(log, cmd, bstr0(name->u.string)))
return false;
if (cmd->def->vararg) {
mp_err(log, "Command %s: this command uses a variable number of "
"arguments, which does not work with named arguments.\n",
cmd->name);
return false;
}
for (int n = 0; n < args->num; n++) {
const char *key = args->keys[n];
mpv_node *val = &args->values[n];

View File

@ -955,8 +955,8 @@ int mpv_command(mpv_handle *ctx, const char **args);
* The special entry "_flags" is optional, and if present, must be an
* array of strings, each being a command prefix to apply. All other
* entries are interpreted as arguments. They must use the argument names
* as documented in each command description. Currently, most commands do
* not support named arguments at all.
* as documented in each command description. Some commands do not
* support named arguments at all, and must use MPV_FORMAT_NODE_ARRAY.
*
* @param[in] args mpv_node with format set to one of the values documented
* above (see there for details)

View File

@ -5623,7 +5623,7 @@ static void cmd_rescan_external_files(void *p)
}
autoload_external_files(mpctx);
if (cmd->args[0].v.i && mpctx->playback_initialized) {
if (!cmd->args[0].v.i && mpctx->playback_initialized) {
// somewhat fuzzy and not ideal
struct track *a = select_default_track(mpctx, 0, STREAM_AUDIO);
if (a && a->is_external)
@ -5752,7 +5752,7 @@ static void cmd_define_input_section(void *p)
struct mp_cmd_ctx *cmd = p;
struct MPContext *mpctx = cmd->mpctx;
mp_input_define_section(mpctx->input, cmd->args[0].v.s, "<api>",
cmd->args[1].v.s, !!cmd->args[2].v.i,
cmd->args[1].v.s, !cmd->args[2].v.i,
cmd->cmd->sender);
}
@ -6005,263 +6005,318 @@ static void cmd_load_script(void *p)
cmd->success = false;
}
// This does not specify the real destination of the command parameter values,
// it just provides a dummy for the OPT_ macros.
#define OPT_BASE_STRUCT struct mp_cmd_arg
#define ARG(t) "", v. t
/* This array defines all known commands.
* The first field is an id used to recognize the command.
* The second is the command name used in slave mode and input.conf.
* Then comes the definition of each argument, first mandatory arguments
* (ARG_INT, ARG_FLOAT, ARG_STRING) if any, then optional arguments
* (OARG_INT(default), etc) if any. The command will be given the default
* argument value if the user didn't give enough arguments to specify it.
* A command can take a maximum of MP_CMD_DEF_MAX_ARGS arguments, or more
* if the command uses varargs.
* The first field the command name used in libmpv and input.conf.
* The second field is the handler function (see mp_cmd_def.handler and
* run_command()).
* Then comes the definition of each argument. They are defined like options,
* except that the result is parsed into mp_cmd.args[] (thus the option variable
* is a field in the mp_cmd_arg union field). Arguments are optional if either
* defval is set (usually via OPTDEF_ macros), or the MP_CMD_OPT_ARG flag is
* set, or if it's the last argument and .vararg is set. If .vararg is set, the
* command has an arbitrary number of arguments, all using the type indicated by
* the last argument (they are appended to mp_cmd.args[] starting at the last
* argument's index).
* Arguments have named, which can be used by named argument functions, e.g. in
* Lua with mp.command_native().
*/
#define ARG_INT OPT_INT(ARG(i), 0)
#define ARG_FLOAT OPT_FLOAT(ARG(f), 0)
#define ARG_DOUBLE OPT_DOUBLE(ARG(d), 0)
#define ARG_STRING OPT_STRING(ARG(s), 0)
#define ARG_CHOICE(c) OPT_CHOICE(ARG(i), 0, c)
#define ARG_CHOICE_OR_INT(...) OPT_CHOICE_OR_INT(ARG(i), 0, __VA_ARGS__)
#define ARG_TIME OPT_TIME(ARG(d), 0)
#define OARG_DOUBLE(def) OPT_DOUBLE(ARG(d), 0, OPTDEF_DOUBLE(def))
#define OARG_INT(def) OPT_INT(ARG(i), 0, OPTDEF_INT(def))
#define OARG_CHOICE(def, c) OPT_CHOICE(ARG(i), 0, c, OPTDEF_INT(def))
#define OARG_FLAGS(def, c) OPT_FLAGS(ARG(i), 0, c, OPTDEF_INT(def))
#define OARG_STRING(def) OPT_STRING(ARG(s), 0, OPTDEF_STR(def))
#define OARG_CYCLEDIR(def) OPT_CYCLEDIR(ARG(d), 0, OPTDEF_DOUBLE(def))
// This does not specify the real destination of the command parameter values,
// it just provides a dummy for the OPT_ macros. The real destination is an
// array item in mp_cmd.args[], using the index of the option definition.
#define OPT_BASE_STRUCT struct mp_cmd_arg
const struct mp_cmd_def mp_cmds[] = {
{ "ignore", cmd_ignore, .is_ignore = true },
{ "seek", cmd_seek, {
ARG_TIME,
OARG_FLAGS(4|0, ({"relative", 4|0}, {"-", 4|0},
{"absolute-percent", 4|1},
{"absolute", 4|2},
{"relative-percent", 4|3},
{"keyframes", 32|8},
{"exact", 32|16})),
// backwards compatibility only
OARG_CHOICE(0, ({"unused", 0}, {"default-precise", 0},
{ "seek", cmd_seek,
{
OPT_TIME("target", v.d, 0),
OPT_FLAGS("flags", v.i, 0,
({"relative", 4|0}, {"-", 4|0},
{"absolute-percent", 4|1},
{"absolute", 4|2},
{"relative-percent", 4|3},
{"keyframes", 32|8},
{"exact", 32|16}),
OPTDEF_INT(4|0)),
// backwards compatibility only
OPT_CHOICE("legacy", v.i, MP_CMD_OPT_ARG,
({"unused", 0}, {"default-precise", 0},
{"keyframes", 32|8},
{"exact", 32|16})),
},
.allow_auto_repeat = true,
.scalable = true,
},
{ "revert-seek", cmd_revert_seek, {
OARG_FLAGS(0, ({"mark", 1})),
}},
{ "quit", cmd_quit, { OARG_INT(0) },
{ "revert-seek", cmd_revert_seek,
{OPT_FLAGS("flags", v.i, MP_CMD_OPT_ARG, ({"mark", 1}))},
},
{ "quit", cmd_quit, { OPT_INT("code", v.i, MP_CMD_OPT_ARG) },
.priv = &(const bool){0}, .is_abort = true },
{ "quit-watch-later", cmd_quit, { OARG_INT(0) },
{ "quit-watch-later", cmd_quit, { OPT_INT("code", v.i, MP_CMD_OPT_ARG) },
.priv = &(const bool){1}, .is_abort = true },
{ "stop", cmd_stop, .is_abort = true },
{ "frame-step", cmd_frame_step, .allow_auto_repeat = true,
.on_updown = true },
{ "frame-back-step", cmd_frame_back_step, .allow_auto_repeat = true },
{ "playlist-next", cmd_playlist_next_prev, {
OARG_CHOICE(0, ({"weak", 0},
{"force", 1})),
{ "playlist-next", cmd_playlist_next_prev,
{
OPT_CHOICE("flags", v.i, MP_CMD_OPT_ARG, ({"weak", 0},
{"force", 1})),
},
.is_soft_abort = true, .priv = &(const int){1},
},
{ "playlist-prev", cmd_playlist_next_prev, {
OARG_CHOICE(0, ({"weak", 0},
{"force", 1})),
{ "playlist-prev", cmd_playlist_next_prev,
{
OPT_CHOICE("flags", v.i, MP_CMD_OPT_ARG, ({"weak", 0},
{"force", 1})),
},
.is_soft_abort = true, .priv = &(const int){-1},
},
{ "playlist-shuffle", cmd_playlist_shuffle, },
{ "sub-step", cmd_sub_step_seek, { ARG_INT }, .allow_auto_repeat = true,
.priv = &(const bool){true} },
{ "sub-seek", cmd_sub_step_seek, { ARG_INT }, .allow_auto_repeat = true,
.priv = &(const bool){false} },
{ "print-text", cmd_print_text, { ARG_STRING }, .allow_auto_repeat = true },
{ "show-text", cmd_show_text, { ARG_STRING, OARG_INT(-1), OARG_INT(0) },
{ "sub-step", cmd_sub_step_seek, { OPT_INT("skip", v.i, 0) },
.allow_auto_repeat = true, .priv = &(const bool){true} },
{ "sub-seek", cmd_sub_step_seek, { OPT_INT("skip", v.i, 0) },
.allow_auto_repeat = true, .priv = &(const bool){false} },
{ "print-text", cmd_print_text, { OPT_STRING("text", v.s, 0) },
.allow_auto_repeat = true },
{ "show-text", cmd_show_text, { OPT_STRING("text", v.s, 0),
OPT_INT("duration", v.i, 0, OPTDEF_INT(-1)),
OPT_INT("level", v.i, MP_CMD_OPT_ARG), },
.allow_auto_repeat = true},
{ "expand-text", cmd_expand_text, { ARG_STRING } },
{ "expand-text", cmd_expand_text, { OPT_STRING("text", v.s, 0) } },
{ "show-progress", cmd_show_progress, .allow_auto_repeat = true},
{ "sub-add", cmd_track_add, {
ARG_STRING,
OARG_CHOICE(0, ({"select", 0}, {"auto", 1}, {"cached", 2})),
OARG_STRING(""), OARG_STRING(""),
{ "sub-add", cmd_track_add,
{
OPT_STRING("url", v.s, 0),
OPT_CHOICE("flags", v.i, MP_CMD_OPT_ARG,
({"select", 0}, {"auto", 1}, {"cached", 2})),
OPT_STRING("title", v.s, MP_CMD_OPT_ARG),
OPT_STRING("lang", v.s, MP_CMD_OPT_ARG),
},
.priv = &(const int){STREAM_SUB},
.spawn_thread = true,
},
{ "sub-remove", cmd_track_remove, { OARG_INT(-1) },
{ "audio-add", cmd_track_add,
{
OPT_STRING("url", v.s, 0),
OPT_CHOICE("flags", v.i, MP_CMD_OPT_ARG,
({"select", 0}, {"auto", 1}, {"cached", 2})),
OPT_STRING("title", v.s, MP_CMD_OPT_ARG),
OPT_STRING("lang", v.s, MP_CMD_OPT_ARG),
},
.priv = &(const int){STREAM_AUDIO},
.spawn_thread = true,
},
{ "sub-remove", cmd_track_remove, { OPT_INT("id", v.i, 0, OPTDEF_INT(-1)) },
.priv = &(const int){STREAM_SUB}, },
{ "sub-reload", cmd_track_reload, { OARG_INT(-1) },
{ "audio-remove", cmd_track_remove, { OPT_INT("id", v.i, 0, OPTDEF_INT(-1)) },
.priv = &(const int){STREAM_AUDIO}, },
{ "sub-reload", cmd_track_reload, { OPT_INT("id", v.i, 0, OPTDEF_INT(-1)) },
.priv = &(const int){STREAM_SUB},
.spawn_thread = true,
},
{ "audio-reload", cmd_track_reload, { OPT_INT("id", v.i, 0, OPTDEF_INT(-1)) },
.priv = &(const int){STREAM_AUDIO},
.spawn_thread = true,
},
{ "rescan-external-files", cmd_rescan_external_files,
{
OPT_CHOICE("flags", v.i, MP_CMD_OPT_ARG,
({"keep-selection", 1},
{"reselect", 0})),
},
.spawn_thread = true,
},
{ "tv-last-channel", cmd_tv_last_channel, },
{ "screenshot", cmd_screenshot, {
OARG_FLAGS(4|2, ({"video", 4|0}, {"-", 4|0},
{"window", 4|1},
{"subtitles", 4|2},
{"each-frame", 8})),
// backwards compatibility
OARG_CHOICE(0, ({"unused", 0}, {"single", 0},
{"each-frame", 8})),
{ "screenshot", cmd_screenshot,
{
OPT_FLAGS("flags", v.i, 0,
({"video", 4|0}, {"-", 4|0},
{"window", 4|1},
{"subtitles", 4|2},
{"each-frame", 8}),
OPTDEF_INT(4|2)),
// backwards compatibility
OPT_CHOICE("legacy", v.i, MP_CMD_OPT_ARG,
({"unused", 0}, {"single", 0},
{"each-frame", 8})),
},
.spawn_thread = true,
},
{ "screenshot-to-file", cmd_screenshot_to_file, {
ARG_STRING,
OARG_CHOICE(2, ({"video", 0},
{ "screenshot-to-file", cmd_screenshot_to_file,
{
OPT_STRING("filename", v.s, 0),
OPT_CHOICE("flags", v.i, 0,
({"video", 0},
{"window", 1},
{"subtitles", 2})),
{"subtitles", 2}),
OPTDEF_INT(2)),
},
.spawn_thread = true,
},
{ "screenshot-raw", cmd_screenshot_raw, {
OARG_CHOICE(2, ({"video", 0},
{ "screenshot-raw", cmd_screenshot_raw,
{
OPT_CHOICE("flags", v.i, 0,
({"video", 0},
{"window", 1},
{"subtitles", 2})),
}},
{ "loadfile", cmd_loadfile, {
ARG_STRING,
OARG_CHOICE(0, ({"replace", 0},
{"subtitles", 2}),
OPTDEF_INT(2)),
},
},
{ "loadfile", cmd_loadfile,
{
OPT_STRING("url", v.s, 0),
OPT_CHOICE("flags", v.i, MP_CMD_OPT_ARG,
({"replace", 0},
{"append", 1},
{"append-play", 2})),
OPT_KEYVALUELIST(ARG(str_list), MP_CMD_OPT_ARG),
}},
{ "loadlist", cmd_loadlist, {
ARG_STRING,
OARG_CHOICE(0, ({"replace", 0},
{"append", 1})),
}},
OPT_KEYVALUELIST("options", v.str_list, MP_CMD_OPT_ARG),
},
},
{ "loadlist", cmd_loadlist, { OPT_STRING("url", v.s, 0),
OPT_CHOICE("flags", v.i, MP_CMD_OPT_ARG,
({"replace", 0}, {"append", 1})), }},
{ "playlist-clear", cmd_playlist_clear },
{ "playlist-remove", cmd_playlist_remove, {
ARG_CHOICE_OR_INT(0, INT_MAX, ({"current", -1})),
}},
{ "playlist-move", cmd_playlist_move, { ARG_INT, ARG_INT } },
{ "run", cmd_run, { ARG_STRING, ARG_STRING }, .vararg = true },
{ "playlist-remove", cmd_playlist_remove,
{OPT_CHOICE_OR_INT("index", v.i, MP_CMD_OPT_ARG, 0, INT_MAX,
({"current", -1}))},
},
{ "playlist-move", cmd_playlist_move, { OPT_INT("index1", v.i, 0),
OPT_INT("index2", v.i, 0), }},
{ "run", cmd_run, { OPT_STRING("command", v.s, 0),
OPT_STRING("args", v.s, 0), },
.vararg = true,
},
{ "subprocess", cmd_subprocess,
{
OPT_STRINGLIST("args", v.str_list, 0),
OPT_FLAG("playback_only", v.i, 0, OPTDEF_INT(1)),
OPT_BYTE_SIZE("capture_size", v.i64, 0, 0, INT_MAX,
OPTDEF_INT64(64 * 1024 * 1024)),
OPT_FLAG("capture_stdout", v.i, 0, OPTDEF_INT(0)),
OPT_FLAG("capture_stderr", v.i, 0, OPTDEF_INT(0)),
OPT_FLAG("capture_stdout", v.i, MP_CMD_OPT_ARG),
OPT_FLAG("capture_stderr", v.i, MP_CMD_OPT_ARG),
},
.spawn_thread = true,
.can_abort = true,
},
{ "set", cmd_set, { ARG_STRING, ARG_STRING } },
{ "change-list", cmd_change_list, { ARG_STRING, ARG_STRING, ARG_STRING } },
{ "add", cmd_add_cycle, { ARG_STRING, OARG_DOUBLE(1) },
{ "set", cmd_set, {OPT_STRING("name", v.s, 0), OPT_STRING("value", v.s, 0)}},
{ "change-list", cmd_change_list, { OPT_STRING("name", v.s, 0),
OPT_STRING("operation", v.s, 0),
OPT_STRING("value", v.s, 0) }},
{ "add", cmd_add_cycle, { OPT_STRING("name", v.s, 0),
OPT_DOUBLE("value", v.d, 0, OPTDEF_DOUBLE(1)), },
.allow_auto_repeat = true,
.scalable = true,
},
{ "cycle", cmd_add_cycle, {
ARG_STRING,
OARG_CYCLEDIR(1),
},
{ "cycle", cmd_add_cycle, { OPT_STRING("name", v.s, 0),
OPT_CYCLEDIR("value", v.d, 0, OPTDEF_DOUBLE(1)), },
.allow_auto_repeat = true,
.scalable = true,
.priv = "",
},
{ "multiply", cmd_multiply, { ARG_STRING, ARG_DOUBLE },
{ "multiply", cmd_multiply, { OPT_STRING("name", v.s, 0),
OPT_DOUBLE("value", v.d, 0)},
.allow_auto_repeat = true},
{ "cycle-values", cmd_cycle_values, { ARG_STRING, ARG_STRING, ARG_STRING },
{ "cycle-values", cmd_cycle_values, { OPT_STRING("arg0", v.s, 0),
OPT_STRING("arg1", v.s, 0),
OPT_STRING("argN", v.s, 0), },
.vararg = true},
{ "enable-section", cmd_enable_input_section, {
ARG_STRING,
OARG_FLAGS(0, ({"default", 0},
{ "enable-section", cmd_enable_input_section,
{
OPT_STRING("name", v.s, 0),
OPT_FLAGS("flags", v.i, MP_CMD_OPT_ARG,
({"default", 0},
{"exclusive", MP_INPUT_EXCLUSIVE},
{"allow-hide-cursor", MP_INPUT_ALLOW_HIDE_CURSOR},
{"allow-vo-dragging", MP_INPUT_ALLOW_VO_DRAGGING})),
}},
{ "disable-section", cmd_disable_input_section, { ARG_STRING } },
{ "define-section", cmd_define_input_section, {
ARG_STRING,
ARG_STRING,
OARG_CHOICE(1, ({"default", 1},
{"force", 0})),
}},
}
},
{ "disable-section", cmd_disable_input_section,
{OPT_STRING("name", v.s, 0) }},
{ "define-section", cmd_define_input_section,
{
OPT_STRING("name", v.s, 0),
OPT_STRING("contents", v.s, 0),
OPT_CHOICE("flags", v.i, MP_CMD_OPT_ARG,
({"default", 0}, {"force", 1})),
},
},
{ "ab-loop", cmd_ab_loop },
{ "drop-buffers", cmd_drop_buffers, },
{ "af", cmd_filter, { ARG_STRING, ARG_STRING },
.priv = &(const int){STREAM_AUDIO}, },
{ "af-command", cmd_filter_command, { ARG_STRING, ARG_STRING, ARG_STRING },
.priv = &(const int){STREAM_AUDIO}, },
{ "af", cmd_filter, { OPT_STRING("operation", v.s, 0),
OPT_STRING("value", v.s, 0), },
.priv = &(const int){STREAM_AUDIO} },
{ "vf", cmd_filter, { OPT_STRING("operation", v.s, 0),
OPT_STRING("value", v.s, 0), },
.priv = &(const int){STREAM_VIDEO} },
{ "af-command", cmd_filter_command, { OPT_STRING("label", v.s, 0),
OPT_STRING("command", v.s, 0),
OPT_STRING("argument", v.s, 0), },
.priv = &(const int){STREAM_AUDIO} },
{ "vf-command", cmd_filter_command, { OPT_STRING("label", v.s, 0),
OPT_STRING("command", v.s, 0),
OPT_STRING("argument", v.s, 0), },
.priv = &(const int){STREAM_VIDEO} },
{ "ao-reload", cmd_ao_reload },
{ "vf", cmd_filter, { ARG_STRING, ARG_STRING },
.priv = &(const int){STREAM_VIDEO}, },
{ "vf-command", cmd_filter_command, { ARG_STRING, ARG_STRING, ARG_STRING },
.priv = &(const int){STREAM_VIDEO}, },
{ "script-binding", cmd_script_binding, { ARG_STRING },
{ "script-binding", cmd_script_binding, { OPT_STRING("name", v.s, 0) },
.allow_auto_repeat = true, .on_updown = true},
{ "script-message", cmd_script_message, { ARG_STRING }, .vararg = true },
{ "script-message-to", cmd_script_message_to, { ARG_STRING, ARG_STRING },
{ "script-message", cmd_script_message, { OPT_STRING("args", v.s, 0) },
.vararg = true },
{ "script-message-to", cmd_script_message_to, { OPT_STRING("target", v.s, 0),
OPT_STRING("args", v.s, 0) },
.vararg = true },
{ "overlay-add", cmd_overlay_add,
{ ARG_INT, ARG_INT, ARG_INT, ARG_STRING, ARG_INT, ARG_STRING, ARG_INT,
ARG_INT, ARG_INT }},
{ "overlay-remove", cmd_overlay_remove, { ARG_INT } },
{ "overlay-add", cmd_overlay_add, { OPT_INT("id", v.i, 0),
OPT_INT("x", v.i, 0),
OPT_INT("y", v.i, 0),
OPT_STRING("file", v.s, 0),
OPT_INT("offset", v.i, 0),
OPT_STRING("fmt", v.s, 0),
OPT_INT("w", v.i, 0),
OPT_INT("h", v.i, 0),
OPT_INT("stride", v.i, 0), }},
{ "overlay-remove", cmd_overlay_remove, { OPT_INT("id", v.i, 0) } },
{ "write-watch-later-config", cmd_write_watch_later_config },
{ "hook-add", cmd_hook_add, { ARG_STRING, ARG_INT, ARG_INT } },
{ "hook-ack", cmd_hook_ack, { ARG_INT } },
{ "hook-add", cmd_hook_add, { OPT_STRING("arg0", v.s, 0),
OPT_INT("arg1", v.i, 0),
OPT_INT("arg2", v.i, 0) }},
{ "hook-ack", cmd_hook_ack, { OPT_INT("arg0", v.i, 0) }},
{ "mouse", cmd_mouse, {
ARG_INT, ARG_INT, // coordinate (x, y)
OARG_INT(-1), // button number
OARG_CHOICE(0, ({"single", 0},
{"double", 1})),
}},
{ "keypress", cmd_key, { ARG_STRING }, .priv = &(const int){0}},
{ "keydown", cmd_key, { ARG_STRING }, .priv = &(const int){MP_KEY_STATE_DOWN}},
{ "keyup", cmd_key, { OARG_STRING("") }, .priv = &(const int){MP_KEY_STATE_UP}},
{ "mouse", cmd_mouse, { OPT_INT("x", v.i, 0),
OPT_INT("y", v.i, 0),
OPT_INT("button", v.i, 0, OPTDEF_INT(-1)),
OPT_CHOICE("mode", v.i, MP_CMD_OPT_ARG,
({"single", 0}, {"double", 1})), }},
{ "keypress", cmd_key, { OPT_STRING("name", v.s, 0) },
.priv = &(const int){0}},
{ "keydown", cmd_key, { OPT_STRING("name", v.s, 0) },
.priv = &(const int){MP_KEY_STATE_DOWN}},
{ "keyup", cmd_key, { OPT_STRING("name", v.s, MP_CMD_OPT_ARG) },
.priv = &(const int){MP_KEY_STATE_UP}},
{ "audio-add", cmd_track_add, {
ARG_STRING,
OARG_CHOICE(0, ({"select", 0}, {"auto", 1}, {"cached", 2})),
OARG_STRING(""), OARG_STRING(""),
},
.priv = &(const int){STREAM_AUDIO},
.spawn_thread = true,
},
{ "audio-remove", cmd_track_remove, { OARG_INT(-1) },
.priv = &(const int){STREAM_AUDIO}, },
{ "audio-reload", cmd_track_reload, { OARG_INT(-1) },
.priv = &(const int){STREAM_AUDIO},
.spawn_thread = true,
},
{ "apply-profile", cmd_apply_profile, {OPT_STRING("name", v.s, 0)} },
{ "rescan-external-files", cmd_rescan_external_files, {
OARG_CHOICE(1, ({"keep-selection", 0},
{"reselect", 1})),
},
.spawn_thread = true,
},
{ "apply-profile", cmd_apply_profile, {ARG_STRING } },
{ "load-script", cmd_load_script, {ARG_STRING} },
{ "load-script", cmd_load_script, {OPT_STRING("filename", v.s, 0)} },
{0}
};