Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
1c2f08c
demux_lavf: parent mp_codec_params members to it
kasper93 May 25, 2026
9ac4cd0
stream_dvdnav: remove unused mousex/mousey
kasper93 Jul 10, 2026
bf70f7f
sub/osd: change osd_set_external2 into generic osd_set_bitmaps
kasper93 Jul 5, 2026
a43f090
stream_dvdnav: read VTS event payload from the right buffer
kasper93 Jun 6, 2026
27bb672
sd_lavc: add support for DVD sub highlight
kasper93 May 25, 2026
89cc134
demux_disc: drop "PTS discontinuity" logs to verbose
kasper93 May 25, 2026
4f5024d
demux: allow to update duration, chapters and editions during playback
kasper93 Jun 5, 2026
63cb25b
stream: add disc-nav actions and states
kasper93 Jun 5, 2026
4e146bb
options: add `disc-menu` option
kasper93 May 25, 2026
dc59430
stream_dvdnav: implement DVD menu navigation
kasper93 Jun 6, 2026
bfded30
stream_bluray: implement HDMV menu navigation
kasper93 Jun 6, 2026
6957d4f
demux_disc: reopen slave demuxer on disc-nav hops
kasper93 Jun 6, 2026
658bde7
sub/osd: add OSDTYPE_DISC_MENU
kasper93 Jul 5, 2026
73e346c
player: add disc-menu state holder and overlay support
kasper93 Jun 6, 2026
4abcb2d
player/loadfile: auto-select default tracks added after initial open
kasper93 Jun 6, 2026
b45e8d5
player/loadfile: react to runtime chapter/edition list updates
kasper93 Jun 6, 2026
4d2d6d9
player/command: add `disc-menu-active` property
kasper93 May 25, 2026
3c7fbc2
player/command: add discnav command and bind default keys
kasper93 Jun 6, 2026
143198c
demux_disc: set partially_seekable to true
kasper93 Jun 6, 2026
bd29020
discnav: sync track selection state with VM
kasper93 Jun 6, 2026
daa1d97
stream_bluray: add BD-J menu support
kasper93 Jun 7, 2026
3808ebb
demux: in interactive mode disable forward cache
kasper93 Jun 7, 2026
49f2ec2
stream_bluray: use 1-based angle, same as in DVD
kasper93 Jun 8, 2026
0b4ea22
stream_bluray: lock all controls that read cached disc state
kasper93 Jun 8, 2026
01d065e
strema_dvdnav: add support for still frames
kasper93 Jun 28, 2026
c901f3f
strema_bluray: add support for still frames
kasper93 Jun 28, 2026
35dee94
stream_bluray: always use bd_read_ext in fill_buffer
kasper93 Jul 9, 2026
e71bf70
demux_lavf: clear sticky avio EOF in drop_buffers
kasper93 Jul 4, 2026
a0bb6a0
stream_dvdnav: emit a one-shot EOF at source jump boundaries
kasper93 Jul 4, 2026
6c9d6e5
demux_disc: soft-reload the slave demuxer on DVD discontinuities
kasper93 Jul 4, 2026
61a0343
demux: parent chapter metadata to the chapter list
kasper93 Jul 4, 2026
0d77b11
sd_lavc: treat the DVD menu subpicture as persistent display state
kasper93 Jul 4, 2026
354509c
demux_disc: retain and re-deliver DVD menu subpictures
kasper93 Jul 4, 2026
a5efa83
discnav: rework DVD menu subpicture handling
kasper93 Jul 4, 2026
d8bbf26
demux_disc: only add the menu edition for streams with menu support
kasper93 Jul 4, 2026
efc5dfd
demux_lavf: seek avfc only on seekable streams in drop_buffers
kasper93 Jul 5, 2026
dd26b3e
stream_bluray: rename BD_TIME_TO_MP to BD_TIME_TO_S
kasper93 Jul 9, 2026
654fa43
stream_dvdnav: keep cached duration in native time base
kasper93 Jul 9, 2026
7395112
stream_dvdnav: route logs from libdvdnav through mp_log
kasper93 Jul 9, 2026
e4a513f
stream_bluray: route logs through mp_log
kasper93 Jul 9, 2026
2222492
sub/osd_state: rename external2 to image_overlay
kasper93 Jul 6, 2026
cb9b961
stream: add mp_dvdnav_highlight struct and use it
kasper93 Jul 9, 2026
7dbd286
stream_dvda: add DVD-Audio playback support
kasper93 Jul 4, 2026
0896008
demux: read sparse still-image streams lazily
kasper93 Jul 5, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions DOCS/interface-changes/disc-menu.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
and `--disc-menu` option
add `disc-menu-active` property
add `discnav` command
2 changes: 2 additions & 0 deletions DOCS/interface-changes/dvda.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
add `dvda://` protocol for DVD-Audio playback (requires libdvdread >= 7.1.0)
add `--dvda-device` option
45 changes: 45 additions & 0 deletions DOCS/man/input.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1753,6 +1753,45 @@ Miscellaneous Commands
``context-menu``
Show context menu on the video window. See `Context Menu`_ section for details.

``discnav <action> [<x> <y>]``
Send a navigation command to the optical-disc stream that is currently
playing (DVD via ``dvdnav``, Blu-ray via ``libbluray``). The command does
nothing when no disc is being played.

``<action>`` is one of:

up, down, left, right
Move the on-disc button selection.
select
Activate the currently highlighted button.
menu
Jump to the disc's root menu (DVD: VMGM root menu, BD: HDMV top menu).
title-menu
Jump to the current title's menu (DVD only; 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 ``<x> <y>`` 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.

``<x>`` and ``<y>`` are optional and only meaningful for the ``mouse-*``
actions. They should normalized cormalized coordinates (top-left at ``0,0``).
Those values are used directly, 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 <type> [timeout]``
Update the clipboard content so that the ``clipboard`` property reflects
up-to-date value. This command is required to update the ``clipboard``
Expand Down Expand Up @@ -2423,6 +2462,12 @@ Property list
between having no editions and a single edition, which will be reflected by
the property, although in practice it does not matter.)

``disc-menu-active``
``yes`` when the current optical-disc stream (DVD or Blu-ray) is showing
an interactive menu with a selectable button highlight, and ``no``
otherwise. Unavailable when the currently playing source is not an
optical disc.

``chapters``
Number of chapters.

Expand Down
7 changes: 7 additions & 0 deletions DOCS/man/mpv.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1336,6 +1336,13 @@ PROTOCOLS
``dvdnav://`` is an old alias for ``dvd://`` and does exactly the same
thing.

``dvda://[title][/device]`` ``--dvda-device=PATH``

Play the AUDIO_TS zone of a DVD-Audio disc. Titles correspond to the
disc's audio groups, tracks are exposed as chapters. If no title is
given, the longest title is auto-selected. Menus and still images are
not supported.

``dvb://[cardnumber@]channel`` ``--dvbin-...``

Digital TV via DVB. (Linux only.)
Expand Down
16 changes: 16 additions & 0 deletions DOCS/man/options.rst
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,12 @@ Track Selection
flat list. Note that depending on the file, tracks from different programs
may be completely unrelated to each other.

``--disc-menu=<yes|no>``
When set, opening ``dvd://`` or ``bd://`` boots into the disc's interactive
menu instead of automatically playing the longest title (default: ``no``).
The menu can also be reached at any time via the synthetic "Disc Menu"
entry in the editions/titles list, or with ``discnav menu`` command.

``--show-dependent-tracks=<yes|no>``
Show dependent tracks in the track list (default: no). Dependent tracks
carry coded data that is not independently decodable. For example, the
Expand Down Expand Up @@ -3888,6 +3894,16 @@ Disc Devices

``mpv dvd:// --dvd-device=/path/to/dvd/``

``--dvda-device=<path>``
Specify the DVD-Audio device or .iso filename for ``dvda://`` playback.
You can also specify a directory that contains files previously copied
directly from a DVD-Audio disc. The default device path depends on
the OS. See the `OPTICAL DRIVES`_ section.

.. admonition:: Example

``mpv dvda:// --dvda-device=/path/to/dvda/``

``--bluray-device=<path>``
Specify the Blu-ray disc location. Must be a directory with Blu-ray
structure. The default device path depends on the OS. See the
Expand Down
115 changes: 111 additions & 4 deletions demux/demux.c
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,12 @@ struct demux_internal {
double hyst_secs; // stop reading till there's hyst_secs remaining
size_t hyst_bytes; // stop reading till there's hyst_bytes remaining
bool hyst_active;
// Set while interactive disc navigation (DVD/BD menus) is active.
bool nav_active;
// One-shot request to force a single read even when nothing is being
// consumed, so a disc-nav command can drive the VM forward. Mostly used in
// paused state.
bool nav_pump;
size_t max_bytes;
size_t max_bytes_bw;
bool seekable_cache;
Expand Down Expand Up @@ -241,6 +247,7 @@ struct demux_internal {
bool back_any_need_recheck; // at least 1 ds->back_need_recheck set

bool tracks_switched; // thread needs to inform demuxer of this
bool nav_refresh; // thread needs to call desc->nav_refresh

bool seeking; // there's a seek queued
int seek_flags; // flags for next seek (if seeking==true)
Expand Down Expand Up @@ -900,13 +907,13 @@ static void update_stream_selection_state(struct demux_internal *in,
any_streams |= s->selected;
}

// Subtitles are only eagerly read if there are no other eagerly read
// streams.
// Subtitles and sparse still-image video are only eagerly read if there are
// no other eagerly read streams.
if (any_av_streams) {
for (int n = 0; n < in->num_streams; n++) {
struct demux_stream *s = in->streams[n]->ds;

if (s->type == STREAM_SUB)
if (s->type == STREAM_SUB || s->still_image)
s->eager = false;
}
}
Expand Down Expand Up @@ -1246,6 +1253,33 @@ void demux_start_prefetch(struct demuxer *demuxer)
mp_mutex_unlock(&in->lock);
}

void demux_drive_nav(struct demuxer *demuxer)
{
struct demux_internal *in = demuxer->in;
mp_assert(demuxer == in->d_user);

mp_mutex_lock(&in->lock);
in->nav_pump = true;
in->reading = true;
mp_cond_signal(&in->wakeup);
mp_mutex_unlock(&in->lock);
}

// Re-queue sticky packets (e.g. the DVD menu subpicture) for re-delivery.
void demux_nav_refresh(struct demuxer *demuxer)
{
struct demux_internal *in = demuxer->in;
mp_assert(demuxer == in->d_user);

mp_mutex_lock(&in->lock);
if (in->d_thread->desc->nav_refresh) {
in->nav_refresh = true;
in->reading = true;
mp_cond_signal(&in->wakeup);
}
mp_mutex_unlock(&in->lock);
}

const char *stream_type_name(enum stream_type type)
{
switch (type) {
Expand Down Expand Up @@ -2301,6 +2335,12 @@ static bool read_packet(struct demux_internal *in)
prefetch_more |= true;
}

// While interactive disc navigation is active, never read ahead. It would
// advance the disc VM past what the user is watching.
if (in->nav_active)
prefetch_more = false;
prefetch_more |= in->nav_pump;

MP_TRACE(in, "bytes=%zd, read_more=%d prefetch_more=%d, refresh_more=%d\n",
(size_t)total_fw_bytes, read_more, prefetch_more, refresh_more);
if (total_fw_bytes >= in->max_bytes) {
Expand Down Expand Up @@ -2354,6 +2394,7 @@ static bool read_packet(struct demux_internal *in)
// Actually read a packet. Drop the lock while doing so, because waiting
// for disk or network I/O can take time.
in->reading = true;
in->nav_pump = false;
in->after_seek = false;
in->after_seek_to_start = false;
mp_mutex_unlock(&in->lock);
Expand Down Expand Up @@ -2518,6 +2559,18 @@ static void execute_trackswitch(struct demux_internal *in)
mp_mutex_lock(&in->lock);
}

static void execute_nav_refresh(struct demux_internal *in)
{
in->nav_refresh = false;

mp_mutex_unlock(&in->lock);

if (in->d_thread->desc->nav_refresh)
in->d_thread->desc->nav_refresh(in->d_thread);

mp_mutex_lock(&in->lock);
}

static void execute_seek(struct demux_internal *in)
{
int flags = in->seek_flags;
Expand Down Expand Up @@ -2634,6 +2687,10 @@ static bool thread_work(struct demux_internal *in)
execute_trackswitch(in);
return true;
}
if (in->nav_refresh) {
execute_nav_refresh(in);
return true;
}
if (in->need_back_seek) {
perform_backward_seek(in);
return true;
Expand Down Expand Up @@ -3072,7 +3129,7 @@ static void demux_update_replaygain(demuxer_t *demuxer)
if (!rg)
rg = decode_rgain(demuxer->log, demuxer->metadata);
if (rg)
sh->codec->replaygain_data = talloc_steal(in, rg);
sh->codec->replaygain_data = talloc_steal(sh->codec, rg);
}
}
}
Expand Down Expand Up @@ -3178,6 +3235,55 @@ void demux_metadata_changed(demuxer_t *demuxer)
mp_mutex_unlock(&in->lock);
}

// Updates the duration should it need to be changed. Used for demuxers that
// changes titles/playlists at runtime.
void demux_set_duration(demuxer_t *demuxer, double duration)
{
mp_assert(demuxer == demuxer->in->d_thread);
struct demux_internal *in = demuxer->in;

mp_mutex_lock(&in->lock);
in->duration = duration;
in->d_thread->duration = duration;
// Clear the high-water mark so subsequent packets can re-ratchet duration
// upward from the new playlist's PTS base without being shadowed by the
// previous title's value.
in->highest_av_pts = MP_NOPTS_VALUE;
in->events |= DEMUX_EVENT_DURATION;
mp_mutex_unlock(&in->lock);
}

// Tell the cache whether interactive disc navigation is active.
void demux_set_nav_active(demuxer_t *demuxer, bool active)
{
mp_assert(demuxer == demuxer->in->d_thread);
struct demux_internal *in = demuxer->in;

mp_mutex_lock(&in->lock);
if (in->nav_active != active) {
in->nav_active = active;
mp_cond_signal(&in->wakeup);
}
mp_mutex_unlock(&in->lock);
}

// Updates the chapters/editions should it need to be changed. Used for demuxers
// that changes titles/playlists at runtime.
void demux_lists_changed(demuxer_t *demuxer)
{
mp_assert(demuxer == demuxer->in->d_thread);
struct demux_internal *in = demuxer->in;

mp_mutex_lock(&in->lock);
in->d_user->chapters = in->d_thread->chapters;
in->d_user->num_chapters = in->d_thread->num_chapters;
in->d_user->editions = in->d_thread->editions;
in->d_user->num_editions = in->d_thread->num_editions;
in->d_user->edition = in->d_thread->edition;
in->events |= DEMUX_EVENT_LISTS;
mp_mutex_unlock(&in->lock);
}

// Called locked, with user demuxer.
static void update_final_metadata(demuxer_t *demuxer, struct timed_metadata *tm)
{
Expand Down Expand Up @@ -4248,6 +4354,7 @@ int demuxer_add_chapter(demuxer_t *demuxer, char *name,
};
mp_tags_set_str(new.metadata, "TITLE", name);
MP_TARRAY_APPEND(demuxer, demuxer->chapters, demuxer->num_chapters, new);
talloc_steal(demuxer->chapters, new.metadata);
return demuxer->num_chapters - 1;
}

Expand Down
8 changes: 8 additions & 0 deletions demux/demux.h
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ enum demux_event {
DEMUX_EVENT_STREAMS = 1 << 1, // a stream was added
DEMUX_EVENT_METADATA = 1 << 2, // metadata or stream_metadata changed
DEMUX_EVENT_DURATION = 1 << 3, // duration updated
DEMUX_EVENT_LISTS = 1 << 4, // chapters / editions list changed
DEMUX_EVENT_ALL = 0xFFFF,
};

Expand All @@ -146,6 +147,8 @@ typedef struct demuxer_desc {
// will be repeated.
bool (*read_packet)(struct demuxer *demuxer, struct demux_packet **pkt);
void (*drop_buffers)(struct demuxer *demuxer);
// Optional. Re-queue retained sticky packets (DVD menu subpicture).
void (*nav_refresh)(struct demuxer *demuxer);
void (*close)(struct demuxer *demuxer);
void (*seek)(struct demuxer *demuxer, double rel_seek_secs, int flags);
void (*switched_tracks)(struct demuxer *demuxer);
Expand Down Expand Up @@ -320,6 +323,8 @@ void demux_start_thread(struct demuxer *demuxer);
void demux_stop_thread(struct demuxer *demuxer);
void demux_set_wakeup_cb(struct demuxer *demuxer, void (*cb)(void *ctx), void *ctx);
void demux_start_prefetch(struct demuxer *demuxer);
void demux_drive_nav(struct demuxer *demuxer);
void demux_nav_refresh(struct demuxer *demuxer);

bool demux_cancel_test(struct demuxer *demuxer);

Expand Down Expand Up @@ -348,6 +353,9 @@ void demux_stream_tags_changed(struct demuxer *demuxer, struct sh_stream *sh,
void demux_close_stream(struct demuxer *demuxer);

void demux_metadata_changed(demuxer_t *demuxer);
void demux_set_duration(demuxer_t *demuxer, double duration);
void demux_set_nav_active(demuxer_t *demuxer, bool active);
void demux_lists_changed(demuxer_t *demuxer);
void demux_update(demuxer_t *demuxer, double playback_pts);

bool demux_cache_dump_set(struct demuxer *demuxer, double start, double end,
Expand Down
Loading
Loading