diff options
-rw-r--r-- | DOCS/client-api-changes.rst | 1 | ||||
-rw-r--r-- | DOCS/interface-changes.rst | 2 | ||||
-rw-r--r-- | DOCS/man/input.rst | 144 | ||||
-rw-r--r-- | DOCS/man/lua.rst | 111 | ||||
-rw-r--r-- | input/ipc.c | 108 | ||||
-rw-r--r-- | libmpv/client.h | 25 | ||||
-rw-r--r-- | libmpv/mpv.def | 1 | ||||
-rw-r--r-- | player/client.c | 100 | ||||
-rw-r--r-- | player/lua.c | 61 |
9 files changed, 294 insertions, 259 deletions
diff --git a/DOCS/client-api-changes.rst b/DOCS/client-api-changes.rst index 9a224c9f5b..2ccbc24e76 100644 --- a/DOCS/client-api-changes.rst +++ b/DOCS/client-api-changes.rst @@ -35,6 +35,7 @@ API changes --- mpv 0.33.0 --- 1.108 - Deprecate MPV_EVENT_IDLE - add mpv_event_start_file, mpv_event_end_file.playlist_entry_id + - add mpv_event_to_node() 1.107 - Remove the deprecated qthelper.hpp. This was obviously not part of the libmpv API, only an "additionally" provided helper, thus this is not considered an API change. If you are maintaining a project that relies diff --git a/DOCS/interface-changes.rst b/DOCS/interface-changes.rst index 15be443190..d35164f718 100644 --- a/DOCS/interface-changes.rst +++ b/DOCS/interface-changes.rst @@ -54,6 +54,8 @@ Interface changes Using the "playlist-play-index" command is recommended instead. - add "playlist-play-index" command - add playlist-current-pos, playlist-playing-pos properties + - Lua end-file events do not set the "error" field anymore, use "file_error" + instead. --- mpv 0.32.0 --- - change behavior when using legacy option syntax with options that start with two dashes (``--`` instead of a ``-``). Now, using the recommended diff --git a/DOCS/man/input.rst b/DOCS/man/input.rst index 60e024ebc9..a4567be3aa 100644 --- a/DOCS/man/input.rst +++ b/DOCS/man/input.rst @@ -1275,6 +1275,150 @@ Input Commands that are Possibly Subject to Change Undocumented commands: ``ao-reload`` (experimental/internal). +List of events +~~~~~~~~~~~~~~ + +This is a partial list of events. This section describes what +``mpv_event_to_node()`` returns, and which is what scripting APIs and the JSON +IPC sees. Note that the C API has separate C-level declarations with +``mpv_event``, which may be slightly different. + +All events can have the following fields: + +``event`` + Name as the event (as returned by ``mpv_event_name()``). + +``error`` + Set to an error string (as returned by ``mpv_error_string()``). This field + is missing if no error happened, or the event type does not report error. + Most events leave this unset. + +This list uses the event name field value, and the C API symbol in brackets: + +``start-file`` (``MPV_EVENT_START_FILE``) + Happens right before a new file is loaded. When you receive this, the + player is loading the file (or possibly already done with it). + + This has the following fields: + + ``playlist_entry_id`` + Playlist entry ID of the file being loaded now. + +``end-file`` (``MPV_EVENT_END_FILE``) + Happens after a file was unloaded. Typically, the player will load the + next file right away, or quit if this was the last file. + + The event has the following fields: + + ``reason`` + Has one of these values: + + ``eof`` + The file has ended. This can (but doesn't have to) include + incomplete files or broken network connections under + circumstances. + + ``stop`` + Playback was ended by a command. + + ``quit`` + Playback was ended by sending the quit command. + + ``error`` + An error happened. In this case, an ``error`` field is present with + the error string. + + ``redirect`` + Happens with playlists and similar. Details see + ``MPV_END_FILE_REASON_REDIRECT`` in the C API. + + ``unknown`` + Unknown. Normally doesn't happen, unless the Lua API is out of sync + with the C API. (Likewise, it could happen that your script gets + reason strings that did not exist yet at the time your script was + written.) + + ``playlist_entry_id`` + Playlist entry ID of the file that was being played or attempted to be + played. This has the same value as the ``playlist_entry_id`` field in the + corresponding ``start-file`` event. + + ``file_error`` + Set to mpv error string describing the approximate reason why playback + failed. Unset if no error known. (In Lua scripting, this value was set + on the ``error`` field directly before mpv 0.33.0. Now the ``error`` + field always indicates success, i.e. is not set.) + +``file-loaded`` (``MPV_EVENT_FILE_LOADED``) + Happens after a file was loaded and begins playback. + +``seek`` (``MPV_EVENT_SEEK``) + Happens on seeking. (This might include cases when the player seeks + internally, even without user interaction. This includes e.g. segment + changes when playing ordered chapters Matroska files.) + +``playback-restart`` (``MPV_EVENT_PLAYBACK_RESTART``) + Start of playback after seek or after file was loaded. + +``shutdown`` (``MPV_EVENT_SHUTDOWN``) + Sent when the player quits, and the script should terminate. Normally + handled automatically. See `Details on the script initialization and lifecycle`_. + +``log-message`` (``MPV_EVENT_LOG_MESSAGE``) + Receives messages enabled with ``mpv_request_log_messages()`` (Lua: + ``mp.enable_messages``). + + This contains, in addition to the default event fields, the following + fields: + + ``prefix`` + The module prefix, identifies the sender of the message. This is what + the terminal player puts in front of the message text when using the + ``--v`` option, and is also what is used for ``--msg-level``. + + ``level`` + The log level as string. See ``msg.log`` for possible log level names. + Note that later versions of mpv might add new levels or remove + (undocumented) existing ones. + + ``text`` + The log message. The text will end with a newline character. Sometimes + it can contain multiple lines. + + Keep in mind that these messages are meant to be hints for humans. You + should not parse them, and prefix/level/text of messages might change + any time. + +``hook`` + The event has the following fields: + + ``hook_id`` + ID to pass to ``mpv_hook_continue()``. The Lua scripting wrapper + provides a better API around this with ``mp.add_hook()``. + +``get-property-reply`` (``MPV_EVENT_GET_PROPERTY_REPLY``) + Undocumented. + +``set-property-reply`` (``MPV_EVENT_SET_PROPERTY_REPLY``) + Undocumented. + +``command-reply`` (``MPV_EVENT_COMMAND_REPLY``) + Undocumented. + +``client-message`` (``MPV_EVENT_CLIENT_MESSAGE``) + Undocumented. + +``video-reconfig`` (``MPV_EVENT_VIDEO_RECONFIG``) + Happens on video output or filter reconfig. + +``audio-reconfig`` (``MPV_EVENT_AUDIO_RECONFIG``) + Happens on audio output or filter reconfig. + +The following events also happen, but are deprecated: ``tracks-changed``, +``track-switched``, ``pause``, ``unpause``, ``metadata-update``, ``idle``, +``tick``, ``chapter-change``. Use ``mpv_observe_property()`` +(Lua: ``mp.observe_property()``) instead. + Hooks ~~~~~ diff --git a/DOCS/man/lua.rst b/DOCS/man/lua.rst index 339ec60dd1..b256d7bf2d 100644 --- a/DOCS/man/lua.rst +++ b/DOCS/man/lua.rst @@ -871,116 +871,7 @@ Example: mp.register_event("file-loaded", my_fn) - - -List of events --------------- - -``start-file`` - Happens right before a new file is loaded. When you receive this, the - player is loading the file (or possibly already done with it). - -``end-file`` - Happens after a file was unloaded. Typically, the player will load the - next file right away, or quit if this was the last file. - - The event has the ``reason`` field, which takes one of these values: - - ``eof`` - The file has ended. This can (but doesn't have to) include - incomplete files or broken network connections under - circumstances. - - ``stop`` - Playback was ended by a command. - - ``quit`` - Playback was ended by sending the quit command. - - ``error`` - An error happened. In this case, an ``error`` field is present with - the error string. - - ``redirect`` - Happens with playlists and similar. Details see - ``MPV_END_FILE_REASON_REDIRECT`` in the C API. - - ``unknown`` - Unknown. Normally doesn't happen, unless the Lua API is out of sync - with the C API. (Likewise, it could happen that your script gets - reason strings that did not exist yet at the time your script was - written.) - -``file-loaded`` - Happens after a file was loaded and begins playback. - -``seek`` - Happens on seeking. (This might include cases when the player seeks - internally, even without user interaction. This includes e.g. segment - changes when playing ordered chapters Matroska files.) - -``playback-restart`` - Start of playback after seek or after file was loaded. - -``idle`` - Idle mode is entered. This happens when playback ended, and the player was - started with ``--idle`` or ``--force-window``. This mode is implicitly ended - when the ``start-file`` or ``shutdown`` events happen. - -``tick`` - Called after a video frame was displayed. This is a hack, and you should - avoid using it. Use timers instead and maybe watch pausing/unpausing events - to avoid wasting CPU when the player is paused. This is deprecated. - -``shutdown`` - Sent when the player quits, and the script should terminate. Normally - handled automatically. See `Details on the script initialization and lifecycle`_. - -``log-message`` - Receives messages enabled with ``mp.enable_messages``. The message data - is contained in the table passed as first parameter to the event handler. - The table contains, in addition to the default event fields, the following - fields: - - ``prefix`` - The module prefix, identifies the sender of the message. This is what - the terminal player puts in front of the message text when using the - ``--v`` option, and is also what is used for ``--msg-level``. - - ``level`` - The log level as string. See ``msg.log`` for possible log level names. - Note that later versions of mpv might add new levels or remove - (undocumented) existing ones. - - ``text`` - The log message. The text will end with a newline character. Sometimes - it can contain multiple lines. - - Keep in mind that these messages are meant to be hints for humans. You - should not parse them, and prefix/level/text of messages might change - any time. - -``get-property-reply`` - Undocumented (not useful for Lua scripts). - -``set-property-reply`` - Undocumented (not useful for Lua scripts). - -``command-reply`` - Undocumented (not useful for Lua scripts). - -``client-message`` - Undocumented (used internally). - -``video-reconfig`` - Happens on video output or filter reconfig. - -``audio-reconfig`` - Happens on audio output or filter reconfig. - -The following events also happen, but are deprecated: ``tracks-changed``, -``track-switched``, ``pause``, ``unpause``, ``metadata-update``, -``chapter-change``. Use ``mp.observe_property()`` instead. +For the existing event types, see `List of events`_. Extras ------ diff --git a/input/ipc.c b/input/ipc.c index 188b863338..1b35afc0ed 100644 --- a/input/ipc.c +++ b/input/ipc.c @@ -37,28 +37,6 @@ static mpv_node *mpv_node_array_get(mpv_node *src, int index) return &src->u.list->values[index]; } -static void mpv_node_array_add(void *ta_parent, mpv_node *src, mpv_node *val) -{ - if (src->format != MPV_FORMAT_NODE_ARRAY) - return; - - if (!src->u.list) - src->u.list = talloc_zero(ta_parent, mpv_node_list); - - MP_TARRAY_GROW(src->u.list, src->u.list->values, src->u.list->num); - - static const struct m_option type = { .type = CONF_TYPE_NODE }; - m_option_get_node(&type, ta_parent, &src->u.list->values[src->u.list->num], val); - - src->u.list->num++; -} - -static void mpv_node_array_add_string(void *ta_parent, mpv_node *src, const char *val) -{ - mpv_node val_node = {.format = MPV_FORMAT_STRING, .u.string = (char *)val}; - mpv_node_array_add(ta_parent, src, &val_node); -} - static void mpv_node_map_add(void *ta_parent, mpv_node *src, const char *key, mpv_node *val) { if (src->format != MPV_FORMAT_NODE_MAP) @@ -84,25 +62,12 @@ static void mpv_node_map_add_null(void *ta_parent, mpv_node *src, const char *ke mpv_node_map_add(ta_parent, src, key, &val_node); } -static void mpv_node_map_add_flag(void *ta_parent, mpv_node *src, const char *key, bool val) -{ - mpv_node val_node = {.format = MPV_FORMAT_FLAG, .u.flag = val}; - - mpv_node_map_add(ta_parent, src, key, &val_node); -} - static void mpv_node_map_add_int64(void *ta_parent, mpv_node *src, const char *key, int64_t val) { mpv_node val_node = {.format = MPV_FORMAT_INT64, .u.int64 = val}; mpv_node_map_add(ta_parent, src, key, &val_node); } -static void mpv_node_map_add_double(void *ta_parent, mpv_node *src, const char *key, double val) -{ - mpv_node val_node = {.format = MPV_FORMAT_DOUBLE, .u.double_ = val}; - mpv_node_map_add(ta_parent, src, key, &val_node); -} - static void mpv_node_map_add_string(void *ta_parent, mpv_node *src, const char *key, const char *val) { mpv_node val_node = {.format = MPV_FORMAT_STRING, .u.string = (char*)val}; @@ -124,74 +89,19 @@ static void mpv_format_command_reply(void *ta_parent, mpv_event *event, mpv_node_map_add(ta_parent, dst, "data", &cmd->result); } -static void mpv_event_to_node(void *ta_parent, mpv_event *event, mpv_node *dst) -{ - if (event->event_id == MPV_EVENT_COMMAND_REPLY) { - mpv_format_command_reply(ta_parent, event, dst); - return; - } - - mpv_node_map_add_string(ta_parent, dst, "event", mpv_event_name(event->event_id)); - - if (event->reply_userdata) - mpv_node_map_add_int64(ta_parent, dst, "id", event->reply_userdata); - - if (event->error < 0) - mpv_node_map_add_string(ta_parent, dst, "error", mpv_error_string(event->error)); - - switch (event->event_id) { - case MPV_EVENT_LOG_MESSAGE: { - mpv_event_log_message *msg = event->data; - - mpv_node_map_add_string(ta_parent, dst, "prefix", msg->prefix); - mpv_node_map_add_string(ta_parent, dst, "level", msg->level); - mpv_node_map_add_string(ta_parent, dst, "text", msg->text); - - break; - } - - case MPV_EVENT_CLIENT_MESSAGE: { - mpv_event_client_message *msg = event->data; - - mpv_node args_node = {.format = MPV_FORMAT_NODE_ARRAY, .u.list = NULL}; - for (int n = 0; n < msg->num_args; n++) - mpv_node_array_add_string(ta_parent, &args_node, msg->args[n]); - mpv_node_map_add(ta_parent, dst, "args", &args_node); - break; - } - - case MPV_EVENT_PROPERTY_CHANGE: { - mpv_event_property *prop = event->data; - - mpv_node_map_add_string(ta_parent, dst, "name", prop->name); - - switch (prop->format) { - case MPV_FORMAT_NODE: - mpv_node_map_add(ta_parent, dst, "data", prop->data); - break; - case MPV_FORMAT_DOUBLE: - mpv_node_map_add_double(ta_parent, dst, "data", *(double *)prop->data); - break; - case MPV_FORMAT_FLAG: - mpv_node_map_add_flag(ta_parent, dst, "data", *(int *)prop->data); - break; - case MPV_FORMAT_STRING: - mpv_node_map_add_string(ta_parent, dst, "data", *(char **)prop->data); - break; - default: - mpv_node_map_add_null(ta_parent, dst, "data"); - } - break; - } - } -} - char *mp_json_encode_event(mpv_event *event) { void *ta_parent = talloc_new(NULL); - mpv_node event_node = {.format = MPV_FORMAT_NODE_MAP, .u.list = NULL}; - mpv_event_to_node(ta_parent, event, &event_node); + struct mpv_node event_node; + if (event->event_id == MPV_EVENT_COMMAND_REPLY) { + event_node = (mpv_node){.format = MPV_FORMAT_NODE_MAP, .u.list = NULL}; + mpv_format_command_reply(ta_parent, event, &event_node); + } else { + mpv_event_to_node(&event_node, event); + // Abuse mpv_event_to_node() internals. + talloc_steal(ta_parent, node_get_alloc(&event_node)); + } char *output = talloc_strdup(NULL, ""); json_write(&output, &event_node); diff --git a/libmpv/client.h b/libmpv/client.h index ef9ba0d423..e57f727846 100644 --- a/libmpv/client.h +++ b/libmpv/client.h @@ -1718,6 +1718,31 @@ typedef struct mpv_event { } mpv_event; /** + * Convert the given src event to a mpv_node, and set *dst to the result. *dst + * is set to a MPV_FORMAT_NODE_MAP, with fields for corresponding mpv_event and + * mpv_event.data/mpv_event_* fields. + * + * The exact details are not completely documented out of laziness. A start + * is located in the "Events" section of the manpage. + * + * *dst may point to newly allocated memory, or pointers in mpv_event. You must + * copy the entire mpv_node if you want to reference it after mpv_event becomes + * invalid (such as making a new mpv_wait_event() call, or destroying the + * mpv_handle from which it was returned). Call mpv_free_node_contents() to free + * any memory allocations made by this API function. + * + * Safe to be called from mpv render API threads. + * + * @param dst Target. This is not read and fully overwritten. Must be released + * with mpv_free_node_contents(). Do not write to pointers returned + * by it. (On error, this may be left as an empty node.) + * @param src The source event. Not modified (it's not const due to the author's + * prejudice of the C version of const). + * @return error code (MPV_ERROR_NOMEM only, if at all) + */ +int mpv_event_to_node(mpv_node *dst, mpv_event *src); + +/** * Enable or disable the given event. * * Some events are enabled by default. Some events can't be disabled. diff --git a/libmpv/mpv.def b/libmpv/mpv.def index a2c6fd1ac9..6e20a668de 100644 --- a/libmpv/mpv.def +++ b/libmpv/mpv.def @@ -13,6 +13,7 @@ mpv_create_weak_client mpv_destroy mpv_detach_destroy mpv_error_string +mpv_event_to_node mpv_event_name mpv_free mpv_free_node_contents diff --git a/player/client.c b/player/client.c index f9f8cd48f6..396c623cea 100644 --- a/player/client.c +++ b/player/client.c @@ -676,6 +676,9 @@ static void dup_event_data(struct mpv_event *ev) ev->data = msg; break; } + case MPV_EVENT_START_FILE: + ev->data = talloc_memdup(NULL, ev->data, sizeof(mpv_event_start_file)); + break; case MPV_EVENT_END_FILE: ev->data = talloc_memdup(NULL, ev->data, sizeof(mpv_event_end_file)); break; @@ -1910,6 +1913,103 @@ unsigned long mpv_client_api_version(void) return MPV_CLIENT_API_VERSION; } +int mpv_event_to_node(mpv_node *dst, mpv_event *event) +{ + *dst = (mpv_node){0}; + + node_init(dst, MPV_FORMAT_NODE_MAP, NULL); + node_map_add_string(dst, "event", mpv_event_name(event->event_id)); + + if (event->error < 0) + node_map_add_string(dst, "error", mpv_error_string(event->error)); + + switch (event->event_id) { + + case MPV_EVENT_START_FILE: { + mpv_event_start_file *esf = event->data; + + node_map_add_int64(dst, "playlist_entry_id", esf->playlist_entry_id); + break; + } + + case MPV_EVENT_END_FILE: { + mpv_event_end_file *eef = event->data; + + const char *reason; + switch (eef->reason) { + case MPV_END_FILE_REASON_EOF: reason = "eof"; break; + case MPV_END_FILE_REASON_STOP: reason = "stop"; break; + case MPV_END_FILE_REASON_QUIT: reason = "quit"; break; + case MPV_END_FILE_REASON_ERROR: reason = "error"; break; + case MPV_END_FILE_REASON_REDIRECT: reason = "redirect"; break; + default: + reason = "unknown"; + } + node_map_add_string(dst, "reason", reason); + + node_map_add_int64(dst, "playlist_entry_id", eef->playlist_entry_id); + + if (eef->reason == MPV_END_FILE_REASON_ERROR) + node_map_add_string(dst, "file_error", mpv_error_string(eef->error)); + break; + } + + case MPV_EVENT_LOG_MESSAGE: { + mpv_event_log_message *msg = event->data; + + node_map_add_string(dst, "prefix", msg->prefix); + node_map_add_string(dst, "level", msg->level); + node_map_add_string(dst, "text", msg->text); + break; + } + + case MPV_EVENT_CLIENT_MESSAGE: { + mpv_event_client_message *msg = event->data; + + struct mpv_node *args = node_map_add(dst, "args", MPV_FORMAT_NODE_ARRAY); + for (int n = 0; n < msg->num_args; n++) { + struct mpv_node *sn = node_array_add(args, MPV_FORMAT_NONE); + sn->format = MPV_FORMAT_STRING; + sn->u.string = (char *)msg->args[n]; + } + break; + } + + case MPV_EVENT_PROPERTY_CHANGE: { + mpv_event_property *prop = event->data; + + node_map_add_string(dst, "name", prop->name); + + switch (prop->format) { + case MPV_FORMAT_NODE: + *node_map_add(dst, "data", MPV_FORMAT_NONE) = + *(struct mpv_node *)prop->data; + break; + case MPV_FORMAT_DOUBLE: + node_map_add_double(dst, "data", *(double *)prop->data); + break; + case MPV_FORMAT_FLAG: + node_map_add_flag(dst, "data", *(int *)prop->data); + break; + case MPV_FORMAT_STRING: + node_map_add_string(dst, "data", *(char **)prop->data); + break; + default: ; + } + break; + } + + case MPV_EVENT_HOOK: { + mpv_event_hook *hook = event->data; + + node_map_add_int64(dst, "hook_id", hook->id); + break; + } + + } + return 0; +} + static const char *const err_table[] = { [-MPV_ERROR_SUCCESS] = "success", [-MPV_ERROR_EVENT_QUEUE_FULL] = "event queue full", diff --git a/player/lua.c b/player/lua.c index 13a368f7c5..aa0b071eb5 100644 --- a/player/lua.c +++ b/player/lua.c @@ -519,50 +519,6 @@ static int script_wait_event(lua_State *L) } switch (event->event_id) { - case MPV_EVENT_LOG_MESSAGE: { - mpv_event_log_message *msg = event->data; - - lua_pushstring(L, msg->prefix); // event s - lua_setfield(L, -2, "prefix"); // event - lua_pushstring(L, msg->level); // event s - lua_setfield(L, -2, "level"); // event - lua_pushstring(L, msg->text); // event s - lua_setfield(L, -2, "text"); // event - break; - } - case MPV_EVENT_CLIENT_MESSAGE: { - mpv_event_client_message *msg = event->data; - - lua_newtable(L); // event args - for (int n = 0; n < msg->num_args; n++) { - lua_pushinteger(L, n + 1); // event args N - lua_pushstring(L, msg->args[n]); // event args N val - lua_settable(L, -3); // event args - } - lua_setfield(L, -2, "args"); // event - break; - } - case MPV_EVENT_END_FILE: { - mpv_event_end_file *eef = event->data; - const char *reason; - switch (eef->reason) { - case MPV_END_FILE_REASON_EOF: reason = "eof"; break; - case MPV_END_FILE_REASON_STOP: reason = "stop"; break; - case MPV_END_FILE_REASON_QUIT: reason = "quit"; break; - case MPV_END_FILE_REASON_ERROR: reason = "error"; break; - case MPV_END_FILE_REASON_REDIRECT: reason = "redirect"; break; - default: - reason = "unknown"; - } - lua_pushstring(L, reason); // event reason - lua_setfield(L, -2, "reason"); // event - - if (eef->reason == MPV_END_FILE_REASON_ERROR) { - lua_pushstring(L, mpv_error_string(eef->error)); // event error - lua_setfield(L, -2, "error"); // event - } - break; - } case MPV_EVENT_PROPERTY_CHANGE: { mpv_event_property *prop = event->data; lua_pushstring(L, prop->name); @@ -586,12 +542,6 @@ static int script_wait_event(lua_State *L) lua_setfield(L, -2, "data"); break; } - case MPV_EVENT_HOOK: { - mpv_event_hook *hook = event->data; - lua_pushinteger(L, hook->id); - lua_setfield(L, -2, "hook_id"); - break; - } case MPV_EVENT_COMMAND_REPLY: { mpv_event_command *cmd = event->data; pushnode(L, &cmd->result); @@ -599,6 +549,17 @@ static int script_wait_event(lua_State *L) break; } default: ; + struct mpv_node rn; + mpv_event_to_node(&rn, event); + + assert(rn.format == MPV_FORMAT_NODE_MAP); + mpv_node_list *list = rn.u.list; + for (int n = 0; n < list->num; n++) { + pushnode(L, &list->values[n]); + lua_setfield(L, -2, list->keys[n]); + } + + mpv_free_node_contents(&rn); } // return event |