neulab/tldr huggingface dataset:
oneshot (RW) Whether the timer is periodic (false) or fires just once (true). This value is used when the timer expires (but before the timer callback function fn is run).
Note that these are methods, and you have to call them using : instead of . (Refer to https://www.lua.org/manual/5.2/manual.html#3.4.9 .)
seconds = 0 timer = mp.add_periodic_timer(1, function() print("called every second") # stop it after 10 seconds seconds = seconds + 1 if seconds >= 10 then timer:kill() end end)
mp.get_opt(key) Return a setting from the --script-opts option. It's up to the user and the script how this mechanism is used. Currently, all scripts can access this equally, so you should be careful about collisions.
mp.get_script_name() Return the name of the current script. The name is usually made of the filename of the script, with directory and file extension removed. If there are several scripts which would have the same name, it's made unique by appending a number. Any nonalphanumeric characters are replaced with _.
The script /path/to/foo-script.lua becomes foo_script.
mp.get_script_directory() Return the directory if this is a script packaged as directory (see Script location for a description). Return nothing if this is a single file script.
mp.osd_message(text [,duration]) Show an OSD message on the screen. duration is in seconds, and is optional (uses --osd-duration by default).
Advanced mp functions These also live in the mp module, but are documented separately as they are useful only in special situations.
mp.suspend() This function has been deprecated in mpv 0.21.0 and does nothing starting with mpv 0.23.0 (no replacement).
mp.resume() This function has been deprecated in mpv 0.21.0 and does nothing starting with mpv 0.23.0 (no replacement).
mp.resume_all() This function has been deprecated in mpv 0.21.0 and does nothing starting with mpv 0.23.0 (no replacement).
mp.get_wakeup_pipe() Calls mpv_get_wakeup_pipe() and returns the read end of the wakeup pipe. This is deprecated, but still works. (See client.h for details.)
mp.get_next_timeout() Return the relative time in seconds when the next timer (mp.add_timeout and similar) expires. If there is no timer, return nil.
mp.dispatch_events([allow_wait]) This can be used to run custom event loops. If you want to have direct control what the Lua script does (instead of being called by the default event loop), you can set the global variable mp_event_loop to your own function running the event loop. From your event loop, you should call mp.dispatch_events() to dequeue and dispatch mpv events.
If the allow_wait parameter is set to true, the function will block until the next event is received or the next timer expires. Otherwise (and this is the default behavior), it returns as soon as the event loop is emptied. It's strongly recommended to use mp.get_next_timeout() and mp.get_wakeup_pipe() if you're interested in properly working notification of new events and working timers.
mp.register_idle(fn) Register an event loop idle handler. Idle handlers are called before the script goes to sleep after handling all new events. This can be used for example to delay processing of property change events: if you're observing multiple properties at once, you might not want to act on each property change, but only when all change notifications have been received.
mp.unregister_idle(fn) Undo mp.register_idle(fn). This removes all idle handlers that are equal to the fn parameter. This uses normal Lua == comparison, so be careful when dealing with closures.
mp.enable_messages(level) Set the minimum log level of which mpv message output to receive. These messages are normally printed to the terminal. By calling this function, you can set the minimum log level of messages which should be received with the log-message event. See the description of this event for details.  The level is a string, see msg.log for allowed log levels.
mp.register_script_message(name, fn) This is a helper to dispatch script-message or script-message-to invocations to Lua functions. fn is called if script-message or script-message-to (with this script as destination) is run with name as first parameter. The other parameters are passed to fn. If a message with the given name is already registered, it's overwritten.
Used by mp.add_key_binding, so be careful about name collisions.
mp.unregister_script_message(name) Undo a previous registration with mp.register_script_message. Does nothing if the name wasn't registered.
mp.create_osd_overlay(format) Create an OSD overlay. This is a very thin wrapper around the osd-overlay command. The function returns a table, which mostly contains fields that will be passed to osd-overlay. The format parameter is used to initialize the format field. The data field contains the text to be used as overlay. For details, see the osd-overlay command.
In addition, it provides the following methods:
update() Commit the OSD overlay to the screen, or in other words, run the osd-overlay command with the current fields of the overlay table.  Returns the result of the osd-overlay command itself.
remove() Remove the overlay from the screen. A update() call will add it again.
ov = mp.create_osd_overlay("ass-events") ov.data = "{\\an5}{\\b1}hello world!" ov:update()
The advantage of using this wrapper (as opposed to running osd-overlay directly) is that the id field is allocated automatically.
mp.get_osd_size() Returns a tuple of osd_width, osd_height, osd_par. The first two give the size of the OSD in pixels (for video outputs like --vo=xv, this may be "scaled" pixels). The third is the display pixel aspect ratio.
May return invalid/nonsense values if OSD is not initialized yet.
mp.msg functions This module allows outputting messages to the terminal, and can be loaded with require 'mp.msg'.
msg.log(level, ...) The level parameter is the message priority. It's a string and one of fatal, error, warn, info, v, debug, trace. The user's settings will determine which of these messages will be visible. Normally, all messages are visible, except v, debug and trace.
The parameters after that are all converted to strings. Spaces are inserted to separate multiple parameters.
You don't need to add newlines.
msg.fatal(...), msg.error(...), msg.warn(...), msg.info(...), msg.verbose(...), msg.debug(...), msg.trace(...) All of these are shortcuts and equivalent to the corresponding msg.log(level, ...) call.
mp.options functions mpv comes with a built-in module to manage options from config-files and the command-line. All you have to do is to supply a table with default options to the read_options function. The function will overwrite the default values with values found in the config-file and the command-line (in that order).
options.read_options(table [, identifier [, on_update]]) A table with key-value pairs. The type of the default values is important for converting the values read from the config file or command-line back. Do not use nil as a default value!
The identifier is used to identify the config-file and the command-line options. These needs to unique to avoid collisions with other scripts.  Defaults to mp.get_script_name() if the parameter is nil or missing.
The on_update parameter enables run-time updates of all matching option values via the script-opts option/property. If any of the matching options changes, the values in the table (which was originally passed to the function) are changed, and on_update(list) is called. list is a table where each updated option has a list[option_name] = true entry.  There is no initial on_update() call. This never re-reads the config file. script-opts is always applied on the original config file, ignoring previous script-opts values (for example, if an option is removed from script-opts at runtime, the option will have the value in the config file). table entries are only written for option values whose values effectively change (this is important if the script changes table entries independently).
Example implementation:
require 'mp.options' local options = { optionA = "defaultvalueA", optionB = -0.5, optionC = true, } read_options(options, "myscript") print(options.optionA)
The config file will be stored in script-opts/identifier.conf in mpv's user folder. Comment lines can be started with # and stray spaces are not removed.  Boolean values will be represented with yes/no.
Example config:
# comment optionA=Hello World optionB=9999 optionC=no
Command-line options are read from the --script-opts parameter. To avoid collisions, all keys have to be prefixed with identifier-.
Example command-line:
--script-opts=myscript-optionA=TEST,myscript-optionB=0,myscript-optionC=yes
mp.utils functions This built-in module provides generic helper functions for Lua, and have strictly speaking nothing to do with mpv or video/audio playback. They are provided for convenience. Most compensate for Lua's scarce standard library.
Be warned that any of these functions might disappear any time. They are not strictly part of the guaranteed API.
utils.getcwd() Returns the directory that mpv was launched from. On error, nil, error is returned.
utils.readdir(path [, filter]) Enumerate all entries at the given path on the filesystem, and return them as array. Each entry is a directory entry (without the path).  The list is unsorted (in whatever order the operating system returns it).
If the filter argument is given, it must be one of the following strings:
files  List regular files only. This excludes directories, special files (like UNIX device files or FIFOs), and dead symlinks. It includes UNIX symlinks to regular files.
dirs   List directories only, or symlinks to directories. . and ..  are not included.
normal Include the results of both files and dirs. (This is the default.)
all    List all entries, even device files, dead symlinks, FIFOs, and the . and .. entries.
On error, nil, error is returned.
utils.file_info(path) Stats the given path for information and returns a table with the following entries:
mode   protection bits (on Windows, always 755 (octal) for directories and 644 (octal) for files)
size   size in bytes
atime  time of last access
mtime  time of last modification
ctime  time of last metadata change
is_file Whether path is a regular file (boolean)
is_dir Whether path is a directory (boolean)
mode and size are integers.  Timestamps (atime, mtime and ctime) are integer seconds since the Unix epoch (Unix time).  The booleans is_file and is_dir are provided as a convenience; they can be and are derived from mode.
On error (e.g. path does not exist), nil, error is returned.
utils.split_path(path) Split a path into directory component and filename component, and return them. The first return value is always the directory. The second return value is the trailing part of the path, the directory entry.
utils.join_path(p1, p2) Return the concatenation of the 2 paths. Tries to be clever. For example, if p2 is an absolute path, p2 is returned without change.
utils.subprocess(t) Runs an external process and waits until it exits. Returns process status and the captured output. This is a legacy wrapper around calling the subprocess command with mp.command_native. It does the following things:
• copy the table t
• rename cancellable field to playback_only
• rename max_size to capture_size
• set capture_stdout field to true if unset
• set name field to subprocess
• call mp.command_native(copied_t)
• if the command failed, create a dummy result table
• copy error_string to error field if the string is non-empty
• return the result table
It is recommended to use mp.command_native or mp.command_native_async directly, instead of calling this legacy wrapper. It is for compatibility only.
See the subprocess documentation for semantics and further parameters.
utils.subprocess_detached(t) Runs an external process and detaches it from mpv's control.
The parameter t is a table. The function reads the following entries:
args   Array of strings of the same semantics as the args used in the subprocess function.
The function returns nil.
This is a legacy wrapper around calling the run command with mp.commandv and other functions.
utils.getpid() Returns the process ID of the running mpv process. This can be used to identify the calling mpv when launching (detached) subprocesses.
utils.get_env_list() Returns the C environment as a list of strings. (Do not confuse this with the Lua "environment", which is an unrelated concept.)
utils.parse_json(str [, trail]) Parses the given string argument as JSON, and returns it as a Lua table. On error, returns nil, error. (Currently, error is just a string reading error, because there is no fine-grained error reporting of any kind.)
The returned value uses similar conventions as mp.get_property_native() to distinguish empty objects and arrays.
If the trail parameter is true (or any value equal to true), then trailing non-whitespace text is tolerated by the function, and the trailing text is returned as 3rd return value. (The 3rd return value is always there, but with trail set, no error is raised.)
utils.format_json(v) Format the given Lua table (or value) as a JSON string and return it. On error, returns nil, error. (Errors usually only happen on value types incompatible with JSON.)
The argument value uses similar conventions as mp.set_property_native() to distinguish empty objects and arrays.
utils.to_string(v) Turn the given value into a string. Formats tables and their contents. This doesn't do anything special; it is only needed because Lua is terrible.
Events Events are notifications from player core to scripts. You can register an event handler with mp.register_event.
Note that all scripts (and other parts of the player) receive events equally, and there's no such thing as blocking other scripts from receiving events.
function my_fn(event) print("start of playback!") end
mp.register_event("file-loaded", my_fn)
For the existing event types, see List of events.
Extras This documents experimental features, or features that are "too special" to guarantee a stable interface.
mp.add_hook(type, priority, fn) Add a hook callback for type (a string identifying a certain kind of hook). These hooks allow the player to call script functions and wait for their result (normally, the Lua scripting interface is asynchronous from the point of view of the player core). priority is an arbitrary integer that allows ordering among hooks of the same kind. Using the value 50 is recommended as neutral default value.
fn(hook) is the function that will be called during execution of the hook. The parameter passed to it (hook) is a Lua object that can control further aspects about the currently invoked hook. It provides the following methods:
defer() Returning from the hook function should not automatically continue the hook. Instead, the API user wants to call hook:cont() on its own at a later point in time (before or after the function has returned).
cont() Continue the hook. Doesn't need to be called unless defer() was called.
See Hooks for currently existing hooks and what they do - only the hook list is interesting; handling hook execution is done by the Lua script function automatically.
JavaScript support in mpv is near identical to its Lua support. Use this section as reference on differences and availability of APIs, but otherwise you should refer to the Lua documentation for API details and general scripting in mpv.
Example JavaScript code which leaves fullscreen mode when the player is paused:
function on_pause_change(name, value) { if (value == true) mp.set_property("fullscreen", "no"); } mp.observe_property("pause", "bool", on_pause_change);
Similarities with Lua mpv tries to load a script file as JavaScript if it has a .js extension, but otherwise, the documented Lua options, script directories, loading, etc apply to JavaScript files too.
Script initialization and lifecycle is the same as with Lua, and most of the Lua functions at the modules mp, mp.utils, mp.msg and mp.options are available to JavaScript with identical APIs - including running commands, getting/setting properties, registering events/key-bindings/hooks, etc.
Differences from Lua No need to load modules. mp, mp.utils,  mp.msg and mp.options are preloaded, and you can use e.g. var cwd = mp.utils.getcwd(); without prior setup.
Errors are slightly different. Where the Lua APIs return nil for error, the JavaScript ones return undefined. Where Lua returns something, error JavaScript returns only something - and makes error available via mp.last_error(). Note that only some of the functions have this additional error value - typically the same ones which have it in Lua.
Standard APIs are preferred. For instance setTimeout and JSON.stringify are available, but mp.add_timeout and mp.utils.format_json are not.
No standard library. This means that interaction with anything outside of mpv is limited to the available APIs, typically via mp.utils. However, some file functions were added, and CommonJS require is available too - where the loaded modules have the same privileges as normal scripts.
Language features - ECMAScript 5 The scripting backend which mpv currently uses is MuJS - a compatible minimal ES5 interpreter. As such, String.substring is implemented for instance, while the common but non-standard String.substr is not. Please consult the MuJS pages on language features and platform support - https://mujs.com .
Unsupported Lua APIs and their JS alternatives mp.add_timeout(seconds, fn)  JS: id = setTimeout(fn, ms)
mp.add_periodic_timer(seconds, fn)  JS: id = setInterval(fn, ms)
utils.parse_json(str [, trail])  JS: JSON.parse(str)
utils.format_json(v)  JS: JSON.stringify(v)
utils.to_string(v)  see dump below.
mp.suspend() JS: none (deprecated).
mp.resume() JS: none (deprecated).
mp.resume_all() JS: none (deprecated).
mp.get_next_timeout() see event loop below.
mp.dispatch_events([allow_wait]) see event loop below.
Scripting APIs - identical to Lua (LE) - Last-Error, indicates that mp.last_error() can be used after the call to test for success (empty string) or failure (non empty reason string).  Where the Lua APIs use nil to indicate error, JS APIs use undefined.
mp.command(string) (LE)
mp.commandv(arg1, arg2, ...) (LE)
mp.command_native(table [,def]) (LE)
id = mp.command_native_async(table [,fn]) (LE) Notes: id is true-thy on success, fn is called always a-sync, error is empty string on success.
mp.abort_async_command(id)
mp.get_property(name [,def]) (LE)
mp.get_property_osd(name [,def]) (LE)
mp.get_property_bool(name [,def]) (LE)
mp.get_property_number(name [,def]) (LE)
mp.get_property_native(name [,def]) (LE)
mp.set_property(name, value) (LE)
mp.set_property_bool(name, value) (LE)
mp.set_property_number(name, value) (LE)
mp.set_property_native(name, value) (LE)
mp.get_time()
mp.add_key_binding(key, name|fn [,fn [,flags]])
mp.add_forced_key_binding(...)
mp.remove_key_binding(name)
mp.register_event(name, fn)
mp.unregister_event(fn)
mp.observe_property(name, type, fn)
mp.unobserve_property(fn)
mp.get_opt(key)
mp.get_script_name()
mp.get_script_directory()
mp.osd_message(text [,duration])
mp.get_wakeup_pipe()
mp.register_idle(fn)
mp.unregister_idle(fn)
mp.enable_messages(level)
mp.register_script_message(name, fn)
mp.unregister_script_message(name)
mp.create_osd_overlay(format)
mp.get_osd_size()  (returned object has properties: width, height, aspect)
mp.msg.log(level, ...)
mp.msg.fatal(...)
mp.msg.error(...)
mp.msg.warn(...)
mp.msg.info(...)
mp.msg.verbose(...)
mp.msg.debug(...)
mp.msg.trace(...)
mp.utils.getcwd() (LE)
mp.utils.readdir(path [, filter]) (LE)
mp.utils.file_info(path) (LE) Note: like lua - this does NOT expand meta-paths like ~~/foo (other JS file functions do expand meta paths).
mp.utils.split_path(path)
mp.utils.join_path(p1, p2)
mp.utils.subprocess(t)
mp.utils.subprocess_detached(t)
mp.utils.get_env_list()
mp.utils.getpid() (LE)
mp.add_hook(type, priority, fn(hook))
mp.options.read_options(obj [, identifier [, on_update]]) (types: string/boolean/number)
Additional utilities mp.last_error() If used after an API call which updates last error, returns an empty string if the API call succeeded, or a non-empty error reason string otherwise.
Error.stack (string) When using try { ... } catch(e) { ... }, then e.stack is the stack trace of the error - if it was created using the Error(...) constructor.
print (global) A convenient alias to mp.msg.info.
dump (global) Like print but also expands objects and arrays recursively.
mp.utils.getenv(name) Returns the value of the host environment variable name, or undefined if the variable is not defined.
mp.utils.get_user_path(path) Expands (mpv) meta paths like ~/x, ~~/y, ~~desktop/z etc. read_file, write_file, append_file and require already use this internally.
mp.utils.read_file(fname [,max]) Returns the content of file fname as string. If max is provided and not negative, limit the read to max bytes.
mp.utils.write_file(fname, str) (Over)write file fname with text content str. fname must be prefixed with file:// as simple protection against accidental arguments switch, e.g. mp.utils.write_file("file://~/abc.txt", "hello world").
mp.utils.append_file(fname, str) Same as mp.utils.write_file if the file fname does not exist. If it does exist then append instead of overwrite.
Note: read_file, write_file and append_file throw on errors, allow text content only.
mp.get_time_ms() Same as mp.get_time() but in ms instead of seconds.
mp.get_script_file() Returns the file name of the current script.
exit() (global) Make the script exit at the end of the current event loop iteration.  Note: please remove added key bindings before calling exit().
mp.utils.compile_js(fname, content_str) Compiles the JS code content_str as file name fname (without loading anything from the filesystem), and returns it as a function. Very similar to a Function constructor, but shows at stack traces as fname.
mp.module_paths Global modules search paths array for the require function (see below).
Timers (global) The standard HTML/node.js timers are available:
id = setTimeout(fn [,duration [,arg1 [,arg2...]]])
id = setTimeout(code_string [,duration])
clearTimeout(id)
id = setInterval(fn [,duration [,arg1 [,arg2...]]])
id = setInterval(code_string [,duration])
clearInterval(id)
setTimeout and setInterval return id, and later call fn (or execute code_string) after duration ms. Interval also repeat every duration.
duration has a minimum and default value of 0, code_string is a plain string which is evaluated as JS code, and [,arg1 [,arg2..]] are used as arguments (if provided) when calling back fn.
The clear...(id) functions cancel timer id, and are irreversible.
Note: timers always call back asynchronously, e.g. setTimeout(fn) will never call fn before returning. fn will be called either at the end of this event loop iteration or at a later event loop iteration. This is true also for intervals - which also never call back twice at the same event loop iteration.
Additionally, timers are processed after the event queue is empty, so it's valid to use setTimeout(fn) as a one-time idle observer.
CommonJS modules and require(id) CommonJS Modules are a standard system where scripts can export common functions for use by other scripts. Specifically, a module is a script which adds properties (functions, etc) to its pre-existing exports object, which another script can access with require(module-id). This runs the module and returns its exports object. Further calls to require for the same module will return its cached exports object without running the module again.
Modules and require are supported, standard compliant, and generally similar to node.js. However, most node.js modules won't run due to missing modules such as fs, process, etc, but some node.js modules with minimal dependencies do work. In general, this is for mpv modules and not a node.js replacement.
A .js file extension is always added to id, e.g. require("./foo") will load the file ./foo.js and return its exports object.
An id which starts with ./ or ../ is relative to the script or module which require it. Otherwise it's considered a top-level id (CommonJS term).
Top-level id is evaluated as absolute filesystem path if possible, e.g. /x/y or ~/x. Otherwise it's considered a global module id and searched according to mp.module_paths in normal array order, e.g. require("x") tries to load x.js at one of the array paths, and id foo/x tries to load x.js inside dir foo at one of the paths.
The mp.module_paths array is empty by default except for scripts which are loaded as a directory where it contains one item - <directory>/modules/ .  The array may be updated from a script (or using custom init - see below) which will affect future calls to require for global module id's which are not already loaded/cached.
No global variable, but a module's this at its top lexical scope is the global object - also in strict mode. If you have a module which needs global as the global object, you could do this.global = this; before require.
Functions and variables declared at a module don't pollute the global object.
Custom initialization After mpv initializes the JavaScript environment for a script but before it loads the script - it tries to run the file init.js at the root of the mpv configuration directory. Code at this file can update the environment further for all scripts. E.g. if it contains mp.module_paths.push("/foo") then require at all scripts will search global module id's also at /foo (do NOT do mp.module_paths = ["/foo"]; because this will remove existing paths - like <script-dir>/modules for scripts which load from a directory).
The custom-init file is ignored if mpv is invoked with --no-config.
Before mpv 0.34, the file name was .init.js (with dot) at the same dir.
The event loop The event loop poll/dispatch mpv events as long as the queue is not empty, then processes the timers, then waits for the next event, and repeats this forever.
You could put this code at your script to replace the built-in event loop, and also print every event which mpv sends to your script:
function mp_event_loop() { var wait = 0; do { var e = mp.wait_event(wait); dump(e);  // there could be a lot of prints... if (e.event != "none") { mp.dispatch_event(e); wait = 0; } else { wait = mp.process_timers() / 1000; if (wait != 0) { mp.notify_idle_observers(); wait = mp.peek_timers_wait() / 1000; } } } while (mp.keep_running); }
mp_event_loop is a name which mpv tries to call after the script loads. The internal implementation is similar to this (without dump though..).
e = mp.wait_event(wait) returns when the next mpv event arrives, or after wait seconds if positive and no mpv events arrived. wait value of 0 returns immediately (with e.event == "none" if the queue is empty).
mp.dispatch_event(e) calls back the handlers registered for e.event, if there are such (event handlers, property observers, script messages, etc).
mp.process_timers() calls back the already-added, non-canceled due timers, and returns the duration in ms till the next due timer (possibly 0), or -1 if there are no pending timers. Must not be called recursively.
mp.notify_idle_observers() calls back the idle observers, which we do when we're about to sleep (wait != 0), but the observers may add timers or take non-negligible duration to complete, so we re-calculate wait afterwards.
mp.peek_timers_wait() returns the same values as mp.process_timers() but without doing anything. Invalid result if called from a timer callback.
Note: exit() is also registered for the shutdown event, and its implementation is a simple mp.keep_running = false.
mpv can be controlled by external programs using the JSON-based IPC protocol.  It can be enabled by specifying the path to a unix socket or a named pipe using the option --input-ipc-server. Clients can connect to this socket and send commands to the player or receive events from it.
WARNING: This is not intended to be a secure network protocol. It is explicitly insecure: there is no authentication, no encryption, and the commands themselves are insecure too. For example, the run command is exposed, which can run arbitrary system commands. The use-case is controlling the player locally. This is not different from the MPlayer slave protocol.
Socat example You can use the socat tool to send commands (and receive replies) from the shell. Assuming mpv was started with:
mpv file.mkv --input-ipc-server=/tmp/mpvsocket
Then you can control it using socat:
> echo '{ "command": ["get_property", "playback-time"] }' | socat - /tmp/mpvsocket {"data":190.482000,"error":"success"}
In this case, socat copies data between stdin/stdout and the mpv socket connection.
See the --idle option how to make mpv start without exiting immediately or playing a file.
It's also possible to send input.conf style text-only commands:
> echo 'show-text ${playback-time}' | socat - /tmp/mpvsocket
But you won't get a reply over the socket. (This particular command shows the playback time on the player's OSD.)
Command Prompt example Unfortunately, it's not as easy to test the IPC protocol on Windows, since Windows ports of socat (in Cygwin and MSYS2) don't understand named pipes. In the absence of a simple tool to send and receive from bidirectional pipes, the echo command can be used to send commands, but not receive replies from the command prompt.
Assuming mpv was started with:
mpv file.mkv --input-ipc-server=\\.\pipe\mpvsocket
You can send commands from a command prompt:
echo show-text ${playback-time} >\\.\pipe\mpvsocket
To be able to simultaneously read and write from the IPC pipe, like on Linux, it's necessary to write an external program that uses overlapped file I/O (or some wrapper like .NET's NamedPipeClientStream.)
You can open the pipe in PuTTY as "serial" device. This is not very comfortable, but gives a way to test interactively without having to write code.
Protocol The protocol uses UTF-8-only JSON as defined by RFC-8259. Unlike standard JSON, "u" escape sequences are not allowed to construct surrogate pairs. To avoid getting conflicts, encode all text characters including and above codepoint U+0020 as UTF-8. mpv might output broken UTF-8 in corner cases (see "UTF-8" section below).
Clients can execute commands on the player by sending JSON messages of the following form:
{ "command": ["command_name", "param1", "param2", ...] }
where command_name is the name of the command to be executed, followed by a list of parameters. Parameters must be formatted as native JSON values (integers, strings, booleans, ...). Every message must be terminated with \n. Additionally, \n must not appear anywhere inside the message. In practice this means that messages should be minified before being sent to mpv.
mpv will then send back a reply indicating whether the command was run correctly, and an additional field holding the command-specific return data (it can also be null).
{ "error": "success", "data": null }
mpv will also send events to clients with JSON messages of the following form:
{ "event": "event_name" }
where event_name is the name of the event. Additional event-specific fields can also be present. See List of events for a list of all supported events.
Because events can occur at any time, it may be difficult at times to determine which response goes with which command. Commands may optionally include a request_id which, if provided in the command request, will be copied verbatim into the response. mpv does not interpret the request_id in any way; it is solely for the use of the requester. The only requirement is that the request_id field must be an integer (a number without fractional parts in the range -2^63..2^63-1). Using other types is deprecated and will currently show a warning. In the future, this will raise an error.
For example, this request:
{ "command": ["get_property", "time-pos"], "request_id": 100 }
Would generate this response:
{ "error": "success", "data": 1.468135, "request_id": 100 }
If you don't specify a request_id, command replies will set it to 0.
All commands, replies, and events are separated from each other with a line break character (\n).
If the first character (after skipping whitespace) is not {, the command will be interpreted as non-JSON text command, as they are used in input.conf (or mpv_command_string() in the client API). Additionally, lines starting with # and empty lines are ignored.
Currently, embedded 0 bytes terminate the current line, but you should not rely on this.
Data flow Currently, the mpv-side IPC implementation does not service the socket while a command is executed and the reply is written. It is for example not possible that other events, that happened during the execution of the command, are written to the socket before the reply is written.
This might change in the future. The only guarantee is that replies to IPC messages are sent in sequence.
Also, since socket I/O is inherently asynchronous, it is possible that you read unrelated event messages from the socket, before you read the reply to the previous command you sent. In this case, these events were queued by the mpv side before it read and started processing your command message.
If the mpv-side IPC implementation switches away from blocking writes and blocking command execution, it may attempt to send events at any time.
You can also use asynchronous commands, which can return in any order, and which do not block IPC protocol interaction at all while the command is executed in the background.
Asynchronous commands Command can be run asynchronously. This behaves exactly as with normal command execution, except that execution is not blocking. Other commands can be sent while it's executing, and command completion can be arbitrarily reordered.
The async field controls this. If present, it must be a boolean. If missing, false is assumed.
For example, this initiates an asynchronous command:
{ "command": ["screenshot"], "request_id": 123, "async": true }
And this is the completion:
{"request_id":123,"error":"success","data":null}
By design, you will not get a confirmation that the command was started. If a command is long running, sending the message will lead to any reply until much later when the command finishes.
Some commands execute synchronously, but these will behave like asynchronous commands that finished execution immediately.
Cancellation of asynchronous commands is available in the libmpv API, but has not yet been implemented in the IPC protocol.
Commands with named arguments If the command field is a JSON object, named arguments are expected. This is described in the C API mpv_command_node() documentation (the MPV_FORMAT_NODE_MAP case). In some cases, this may make commands more readable, while some obscure commands basically require using named arguments.
Currently, only "proper" commands (as listed by List of Input Commands) support named arguments.
Commands In addition to the commands described in List of Input Commands, a few extra commands can also be used as part of the protocol:
client_name Return the name of the client as string. This is the string ipc-N with N being an integer number.
get_time_us Return the current mpv internal time in microseconds as a number. This is basically the system time, with an arbitrary offset.
get_property Return the value of the given property. The value will be sent in the data field of the replay message.
{ "command": ["get_property", "volume"] } { "data": 50.0, "error": "success" }
get_property_string Like get_property, but the resulting data will always be a string.
{ "command": ["get_property_string", "volume"] } { "data": "50.000000", "error": "success" }
set_property Set the given property to the given value. See Properties for more information about properties.
{ "command": ["set_property", "pause", true] } { "error": "success" }
set_property_string Alias for set_property. Both commands accept native values and strings.
observe_property Watch a property for changes. If the given property is changed, then an event of type property-change will be generated
{ "command": ["observe_property", 1, "volume"] } { "error": "success" } { "event": "property-change", "id": 1, "data": 52.0, "name": "volume" }
WARNING: If the connection is closed, the IPC client is destroyed internally, and the observed properties are unregistered. This happens for example when sending commands to a socket with separate socat invocations.  This can make it seem like property observation does not work. You must keep the IPC connection open to make it work.
observe_property_string Like observe_property, but the resulting data will always be a string.
{ "command": ["observe_property_string", 1, "volume"] } { "error": "success" } { "event": "property-change", "id": 1, "data": "52.000000", "name": "volume" }
unobserve_property Undo observe_property or observe_property_string. This requires the numeric id passed to the observed command as argument.
{ "command": ["unobserve_property", 1] } { "error": "success" }
request_log_messages Enable output of mpv log messages. They will be received as events. The parameter to this command is the log-level (see mpv_request_log_messages C API function).
Log message output is meant for humans only (mostly for debugging).  Attempting to retrieve information by parsing these messages will just lead to breakages with future mpv releases. Instead, make a feature request, and ask for a proper event that returns the information you need.
enable_event, disable_event Enables or disables the named event. Mirrors the mpv_request_event C API function. If the string all is used instead of an event name, all events are enabled or disabled.
By default, most events are enabled, and there is not much use for this command.
get_version Returns the client API version the C API of the remote mpv instance provides.
See also: DOCS/client-api-changes.rst.
UTF-8 Normally, all strings are in UTF-8. Sometimes it can happen that strings are in some broken encoding (often happens with file tags and such, and filenames on many Unixes are not required to be in UTF-8 either). This means that mpv sometimes sends invalid JSON. If that is a problem for the client application's parser, it should filter the raw data for invalid UTF-8 sequences and perform the desired replacement, before feeding the data to its JSON parser.
mpv will not attempt to construct invalid UTF-8 with broken "u" escape sequences. This includes surrogate pairs.
JSON extensions The following non-standard extensions are supported:
• a list or object item can have a trailing ","
• object syntax accepts "=" in addition of ":"
• object keys can be unquoted, if they start with a character in "A-Za-z_" and contain only characters in "A-Za-z0-9_"
• byte escapes with "xAB" are allowed (with AB being a 2 digit hex number)
{ objkey = "value\x0A" }
Is equivalent to:
{ "objkey": "value\n" }
Alternative ways of starting clients You can create an anonymous IPC connection without having to set --input-ipc-server. This is achieved through a mpv pseudo scripting backend that starts processes.
You can put .run file extension in the mpv scripts directory in its config directory (see the FILES section for details), or load them through other means (see Script location). These scripts are simply executed with the OS native mechanism (as if you ran them in the shell). They must have a proper shebang and have the executable bit set.
When executed, a socket (the IPC connection) is passed to them through file descriptor inheritance. The file descriptor is indicated as the special command line argument --mpv-ipc-fd=N, where N is the numeric file descriptor.
The rest is the same as with a normal --input-ipc-server IPC connection. mpv does not attempt to observe or other interact with the started script process.
This does not work in Windows yet.
There is no real changelog, but you can look at the following things:
• The release changelog, which should contain most user-visible changes, including new features and bug fixes:
https://github.com/mpv-player/mpv/releases
• The git log, which is the "real" changelog
• The file https://github.com/mpv-player/mpv/blob/master/DOCS/interface-changes.rst documents changes to the command and user interface, such as options and properties. (It usually documents breaking changes only, additions and enhancements are often not listed.)
• C API changes are listed in https://github.com/mpv-player/mpv/blob/master/DOCS/client-api-changes.rst
• The file mplayer-changes.rst in the DOCS sub directory on the git repository, which used to be in place of this section. It documents some changes that happened since mplayer2 forked off MPlayer. (Not updated anymore.)
EMBEDDING INTO OTHER PROGRAMS (LIBMPV) mpv can be embedded into other programs as video/audio playback backend. The recommended way to do so is using libmpv. See libmpv/client.h in the mpv source code repository. This provides a C API. Bindings for other languages might be available (see wiki).
Since libmpv merely allows access to underlying mechanisms that can control mpv, further documentation is spread over a few places:
• https://github.com/mpv-player/mpv/blob/master/libmpv/client.h
• https://mpv.io/manual/master/#options
• https://mpv.io/manual/master/#list-of-input-commands
• https://mpv.io/manual/master/#properties
• https://github.com/mpv-player/mpv-examples/tree/master/libmpv
You can write C plugins for mpv. These use the libmpv API, although they do not use the libmpv library itself.
They are available on Linux/BSD platforms only and enabled by default if the compiler supports linking with the -rdynamic flag.
C plugins location C plugins are put into the mpv scripts directory in its config directory (see the FILES section for details). They must have a .so file extension. They can also be explicitly loaded with the --script option.
API A C plugin must export the following function:
int mpv_open_cplugin(mpv_handle *handle)
The plugin function will be called on loading time. This function does not return as long as your plugin is loaded (it runs in its own thread). The handle will be deallocated as soon as the plugin function returns.
The return value is interpreted as error status. A value of 0 is interpreted as success, while -1 signals an error. In the latter case, the player prints an uninformative error message that loading failed.
Return values other than 0 and -1 are reserved, and trigger undefined behavior.
Within the plugin function, you can call libmpv API functions. The handle is created by mpv_create_client() (or actually an internal equivalent), and belongs to you. You can call mpv_wait_event() to wait for things happening, and so on.
Note that the player might block until your plugin calls mpv_wait_event() for the first time. This gives you a chance to install initial hooks etc. before playback begins.
The details are quite similar to Lua scripts.
Linkage to libmpv The current implementation requires that your plugins are not linked against libmpv. What your plugins uses are not symbols from a libmpv binary, but symbols from the mpv host binary.
Examples See:
• https://github.com/mpv-player/mpv-examples/tree/master/cplugins
There are a number of environment variables that can be used to control the behavior of mpv.
HOME, XDG_CONFIG_HOME Used to determine mpv config directory. If XDG_CONFIG_HOME is not set, $HOME/.config/mpv is used.
$HOME/.mpv is always added to the list of config search paths with a lower priority.
MPV_HOME Directory where mpv looks for user settings. Overrides HOME, and mpv will try to load the config file as $MPV_HOME/mpv.conf.
MPV_VERBOSE (see also -v and --msg-level) Set the initial verbosity level across all message modules (default: 0).  This is an integer, and the resulting verbosity corresponds to the number of --v options passed to the command line.
MPV_LEAK_REPORT If set to 1, enable internal talloc leak reporting. If set to another value, disable leak reporting. If unset, use the default, which normally is 0. If mpv was built with --enable-ta-leak-report, the default is 1. If leak reporting was disabled at compile time (NDEBUG in custom CFLAGS), this environment variable is ignored.
LADSPA_PATH Specifies the search path for LADSPA plugins. If it is unset, fully qualified path names must be used.
DISPLAY Standard X11 display name to use.
FFmpeg/Libav: This library accesses various environment variables. However, they are not centrally documented, and documenting them is not our job. Therefore, this list is incomplete.
Notable environment variables:
http_proxy URL to proxy for http:// and https:// URLs.
no_proxy List of domain patterns for which no proxy should be used. List entries are separated by ,. Patterns can include *.
libdvdcss:
DVDCSS_CACHE Specify a directory in which to store title key values. This will speed up descrambling of DVDs which are in the cache. The DVDCSS_CACHE directory is created if it does not exist, and a subdirectory is created named after the DVD's title or manufacturing date. If DVDCSS_CACHE is not set or is empty, libdvdcss will use the default value which is ${HOME}/.dvdcss/ under Unix and the roaming application data directory (%APPDATA%) under Windows. The special value "off" disables caching.
DVDCSS_METHOD Sets the authentication and decryption method that libdvdcss will use to read scrambled discs. Can be one of title, key or disc.
key    is the default method. libdvdcss will use a set of calculated player keys to try to get the disc key. This can fail if the drive does not recognize any of the player keys.
disc   is a fallback method when key has failed. Instead of using player keys, libdvdcss will crack the disc key using a brute force algorithm. This process is CPU intensive and requires 64 MB of memory to store temporary data.
title  is the fallback when all other methods have failed. It does not rely on a key exchange with the DVD drive, but rather uses a crypto attack to guess the title key. On rare cases this may fail because there is not enough encrypted data on the disc to perform a statistical attack, but on the other hand it is the only way to decrypt a DVD stored on a hard disc, or a DVD with the wrong region on an RPC2 drive.
DVDCSS_RAW_DEVICE Specify the raw device to use. Exact usage will depend on your operating system, the Linux utility to set up raw devices is raw(8) for instance. Please note that on most operating systems, using a raw device requires highly aligned buffers: Linux requires a 2048 bytes alignment (which is the size of a DVD sector).
DVDCSS_VERBOSE Sets the libdvdcss verbosity level.
0      Outputs no messages at all.
1      Outputs error messages to stderr.
2      Outputs error messages and debug messages to stderr.
DVDREAD_NOKEYS Skip retrieving all keys on startup. Currently disabled.
Normally mpv returns 0 as exit code after finishing playback successfully.  If errors happen, the following exit codes can be returned:
1      Error initializing mpv. This is also returned if unknown options are passed to mpv.
2      The file passed to mpv couldn't be played. This is somewhat fuzzy: currently, playback of a file is considered to be successful if initialization was mostly successful, even if playback fails immediately after initialization.
3      There were some files that could be played, and some files which couldn't (using the definition of success from above).
4      Quit due to a signal, Ctrl+c in a VO window (by default), or from the default quit key bindings in encoding mode.
Note that quitting the player manually will always lead to exit code 0, overriding the exit code that would be returned normally. Also, the quit input command can take an exit code: in this case, that exit code is returned.
For Windows-specifics, see FILES ON WINDOWS section.
/usr/local/etc/mpv/mpv.conf mpv system-wide settings (depends on --prefix passed to configure - mpv in default configuration will use /usr/local/etc/mpv/ as config directory, while most Linux distributions will set it to /etc/mpv/).
~/.config/mpv The standard configuration directory. This can be overridden by environment variables, in ascending order:
1      If $XDG_CONFIG_HOME is set, then the derived configuration directory will be $XDG_CONFIG_HOME/mpv.
2      If $MPV_HOME is set, then the derived configuration directory will be $MPV_HOME.
If this directory, nor the original configuration directory (see below) do not exist, mpv tries to create this directory automatically.
~/.mpv/ The original (pre 0.5.0) configuration directory. It will continue to be read if present.
If both this directory and the standard configuration directory are present, configuration will be read from both with the standard configuration directory content taking precedence. However, you should fully migrate to the standard directory and a warning will be shown in this situation.
~/.config/mpv/mpv.conf mpv user settings (see CONFIGURATION FILES section)
~/.config/mpv/input.conf key bindings (see INPUT.CONF section)