diff --git a/DOCS/interface-changes/disc-menu.txt b/DOCS/interface-changes/disc-menu.txt index b5b4164937..0b976c067d 100644 --- a/DOCS/interface-changes/disc-menu.txt +++ b/DOCS/interface-changes/disc-menu.txt @@ -1,2 +1,3 @@ add `--disc-menu` option add `disc-menu-active` property +add `discnav` command diff --git a/DOCS/man/input.rst b/DOCS/man/input.rst index 9c79fbd982..8970d5ab52 100644 --- a/DOCS/man/input.rst +++ b/DOCS/man/input.rst @@ -1771,6 +1771,46 @@ Miscellaneous Commands ``context-menu`` Show context menu on the video window. See `Context Menu`_ section for details. +``discnav [ ]`` + Send a navigation command to the optical-disc stream that is currently + playing. The command does nothing when no disc is being played. + + ```` is one of: + + up, down, left, right + Move the on-disc button selection. + select + Activate the currently highlighted button. + menu + Jump to the root menu of the current title set (DVD: VTSM root menu, + BD: HDMV top menu). + title-menu + Jump to the disc's title menu (DVD: VMGM title menu, treated like + ``menu`` on BD). + popup + Show / dismiss the Blu-ray popup menu. For DVDs, falls back to the + chapter menu where available. + prev + Return from a menu to playback, or to the previous menu domain. + mouse-move + Forward a mouse position to the disc, so it can update the focused + button under the cursor. With no `` `` arguments, the position + is read from the ``mouse-pos`` property and mapped from window into + source-video coordinates automatically. + mouse-click + Like ``mouse-move`` but also activates the button under the cursor. + + ```` and ```` are optional and only meaningful for the ``mouse-*`` + actions. They are normalized coordinates in the range 0..1 (top-left at + ``0,0``), and are used instead of the live ``mouse-pos``. + + mpv ships default bindings for this command in the ``{discnav}`` input + section (``UP``/``DOWN``/``LEFT``/``RIGHT`` for navigation, ``ENTER`` to + select, ``ESC`` / ``BS`` to leave, ``MBTN_LEFT`` / ``MOUSE_MOVE`` for + mouse). The player enables and disables that section automatically as + the menu appears and disappears, so the bindings only shadow the normal + ones while a menu is actually on screen. + ``update-clipboard [timeout]`` Update the clipboard content so that the ``clipboard`` property reflects up-to-date value. This command is required to update the ``clipboard`` diff --git a/DOCS/man/mpv.rst b/DOCS/man/mpv.rst index 1a5a0c1b84..5029fc65b0 100644 --- a/DOCS/man/mpv.rst +++ b/DOCS/man/mpv.rst @@ -174,6 +174,15 @@ z and Z l Set/clear A-B loop points. See ``ab-loop`` command for details. +Ctrl+m + Jump to the disc menu when playing a DVD or Blu-ray (see the ``discnav`` + command). While a menu with a button highlight is on screen, the arrow + keys, ENTER, ESC/BACKSPACE and the mouse control the menu instead of + their usual functions. + +Ctrl+M + Show or hide the Blu-ray popup menu. + L Toggle infinite looping. @@ -1328,7 +1337,8 @@ PROTOCOLS by passing them to ``--bluray-device``. ``title`` can be: ``longest`` or ``first`` (selects the default - playlist); ``mpls/`` (selects .mpls playlist); + playlist); ``menu`` (starts in the disc menu, see ``--disc-menu`` and the + ``discnav`` command); ``mpls/`` (selects .mpls playlist); ```` (select playlist with the same index). mpv will list the available playlists on loading. @@ -1336,9 +1346,11 @@ PROTOCOLS ``dvd://[title][/device]`` ``--dvd-device=PATH`` - Play a DVD. DVD menus are not supported. If no title is given, the longest - title is auto-selected. Without ``--dvd-device``, it will probably try - to open an actual optical drive, if available and implemented for the OS. + Play a DVD. If no title is given, the longest title is auto-selected. + ``title`` can also be ``menu`` to start in the disc menu (see + ``--disc-menu`` and the ``discnav`` command). Without ``--dvd-device``, + it will probably try to open an actual optical drive, if available and + implemented for the OS. ``dvdnav://`` is an old alias for ``dvd://`` and does exactly the same thing. diff --git a/etc/input.conf b/etc/input.conf index 9519bdbe03..315b5b6f24 100644 --- a/etc/input.conf +++ b/etc/input.conf @@ -234,6 +234,22 @@ #Ctrl+KP_UP add video-align-y -0.01 # align video up #Ctrl+KP_PGUP add video-align-x 0.01; add video-align-y -0.01 # align video right and up +# +# The "{discnav}" section is enabled only while a disc menu with a button +# highlight is actually on screen. +# +#UP {discnav} discnav up +#DOWN {discnav} discnav down +#LEFT {discnav} discnav left +#RIGHT {discnav} discnav right +#ENTER {discnav} discnav select +#ESC {discnav} discnav prev +#BS {discnav} discnav prev +#MOUSE_MOVE {discnav} discnav mouse-move +#MBTN_LEFT {discnav} discnav mouse-click +#Ctrl+m discnav menu # jump to the disc's root menu +#Ctrl+M discnav popup # show/hide Blu-ray popup menu + # # Legacy bindings (may or may not be removed in the future) # diff --git a/player/command.c b/player/command.c index 71affb3bf9..41692b6c5a 100644 --- a/player/command.c +++ b/player/command.c @@ -1182,6 +1182,26 @@ static int mp_property_edition(void *ctx, struct m_property *prop, } return M_PROPERTY_OK; } + case M_PROPERTY_SET: { + // For disc demuxers, jump the title directly, we sometimes need to + // react even if the actual edition "value" doesn't change. + if (disc_nav_get_stream(mpctx)) { + int new_ed = *(int *)arg; + if (new_ed < 0 || new_ed >= demuxer->num_editions) + return M_PROPERTY_ERROR; + unsigned new_title = new_ed; + if (stream_control(demuxer->stream, STREAM_CTRL_SET_CURRENT_TITLE, + &new_title) < 1) + return M_PROPERTY_ERROR; + mpctx->opts->edition_id = new_ed; + m_config_notify_change_opt_ptr(mpctx->mconfig, + &mpctx->opts->edition_id); + mp_notify_property(mpctx, "edition"); + mp_wakeup_core(mpctx); + return M_PROPERTY_OK; + } + return mp_property_generic_option(mpctx, prop, action, arg); + } default: return mp_property_generic_option(mpctx, prop, action, arg); } @@ -7449,6 +7469,47 @@ static void cmd_context_menu(void *p) vo_control(vo, VOCTRL_SHOW_MENU, NULL); } +static void cmd_discnav(void *p) +{ + struct mp_cmd_ctx *cmd = p; + struct MPContext *mpctx = cmd->mpctx; + int action = cmd->args[0].v.i; + + struct stream *s = disc_nav_get_stream(mpctx); + if (!s) { + cmd->success = false; + return; + } + + struct stream_nav_cmd nc = { .action = action }; + + struct stream_nav_state pre = {0}; + stream_control(s, STREAM_CTRL_GET_NAV_STATE, &pre); + + if (action == STREAM_NAV_MOUSE_MOVE || action == STREAM_NAV_MOUSE_CLICK) { + double nx = cmd->args[1].v.d; + double ny = cmd->args[2].v.d; + if (nx >= 0 && ny >= 0) { + if (pre.src_w <= 0 || pre.src_h <= 0 || nx > 1 || ny > 1) { + cmd->success = false; + return; + } + nc.x = (int)(nx * pre.src_w); + nc.y = (int)(ny * pre.src_h); + } else if (!disc_nav_mouse_pos_to_src(mpctx, pre.src_w, pre.src_h, + &nc.x, &nc.y)) + { + cmd->success = false; + return; + } + } + + if (stream_control(s, STREAM_CTRL_NAV_CMD, &nc) < 1) + cmd->success = false; + + mp_wakeup_core(mpctx); +} + static void cmd_flush_status_line(void *p) { struct mp_cmd_ctx *cmd = p; @@ -8013,6 +8074,23 @@ const struct mp_cmd_def mp_cmds[] = { { "context-menu", cmd_context_menu }, + { "discnav", cmd_discnav, + { {"action", OPT_CHOICE(v.i, + {"up", STREAM_NAV_UP}, + {"down", STREAM_NAV_DOWN}, + {"left", STREAM_NAV_LEFT}, + {"right", STREAM_NAV_RIGHT}, + {"select", STREAM_NAV_SELECT}, + {"menu", STREAM_NAV_MENU_ROOT}, + {"title-menu", STREAM_NAV_MENU_TITLE}, + {"popup", STREAM_NAV_MENU_POPUP}, + {"prev", STREAM_NAV_PREV_MENU}, + {"mouse-move", STREAM_NAV_MOUSE_MOVE}, + {"mouse-click", STREAM_NAV_MOUSE_CLICK})}, + {"x", OPT_DOUBLE(v.d), OPTDEF_DOUBLE(-1)}, + {"y", OPT_DOUBLE(v.d), OPTDEF_DOUBLE(-1)} }, + }, + { "flush-status-line", cmd_flush_status_line, { {"clear", OPT_BOOL(v.b)} } }, { "notify-property", cmd_notify_property, { {"property", OPT_STRING(v.s)} } }, @@ -8438,6 +8516,10 @@ void mp_option_run_callback(struct MPContext *mpctx, struct mp_option_callback * mp_notify_property(mpctx, "current-edition"); print_track_list(mpctx, mp_tprintf(42, "Selected edition %d:", demuxer->edition)); + } else if (disc_nav_get_stream(mpctx)) { + unsigned new_title = opts->edition_id; + stream_control(demuxer->stream, + STREAM_CTRL_SET_CURRENT_TITLE, &new_title); } else { if (!mpctx->stop_play) mpctx->stop_play = PT_CURRENT_ENTRY;