mirror of
https://github.com/mpv-player/mpv
synced 2025-03-21 18:57:35 +00:00
player: add a number of new playlist contol commands/properties
Should give a good deal more explicit control and insight over the player state. Some feel a bit pointless, and/or expose internal weirdness. However, it's not like the existing weirdness didn't exist before, or can be made go away. (In part, the weirdness is because certain in-between states are visible. Hiding them would make things simpler, but less flexible.) Maybe this actually gives users a better idea how the API _should_ look like, too. On a side note, this tries to really guarantee that mpctx->playing is set between playback start/end. For that, the loadfile.c changes assume that mpctx->playing is set (guaranteed by code above the change), and that playing->filename is set (probably could never be false; was broken before and actually would have crashed if that could ever happen; in any case, also add an assert to playlist.c for this). playlist_entry_to_index() now tolerates playlist_entrys that are not part of the playlist. This is also needed for mpctx->playing.
This commit is contained in:
parent
68d9d11ddf
commit
e9e93b4dbe
@ -48,6 +48,12 @@ Interface changes
|
||||
- the playlist-pos and playlist-pos-1 properties now can return and accept
|
||||
-1, and are never unavailable. Out of range indexes are now accepted, but
|
||||
behave like writing -1.
|
||||
- the playlist-pos and playlist-pos-1 properties deprecate the current
|
||||
behavior when writing back the current value to the property: currently,
|
||||
this restarts playback, but in the future, it will do nothing.
|
||||
Using the "playlist-play-index" command is recommended instead.
|
||||
- add "playlist-play-index" command
|
||||
- add playlist-current-pos, playlist-playing-pos properties
|
||||
--- 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
|
||||
|
@ -377,6 +377,29 @@ Remember to quote string arguments in input.conf (see `Flat command syntax`_).
|
||||
force
|
||||
Terminate playback if the first file is being played.
|
||||
|
||||
``playlist-play-index <integer|current|none>``
|
||||
Start (or restart) playback of the given playlist index. In addition to the
|
||||
0-based playlist entry index, it supports the following values:
|
||||
|
||||
<current>
|
||||
The current playlist entry (as in ``playlist-current-pos``) will be
|
||||
played again (unload and reload). If none is set, playback is stopped.
|
||||
(In corner cases, ``playlist-current-pos`` can point to a playlist entry
|
||||
even if playback is currently inactive,
|
||||
|
||||
<none>
|
||||
Playback is stopped. If idle mode (``--idle``) is enabled, the player
|
||||
will enter idle mode, otherwise it will exit.
|
||||
|
||||
This comm and is similar to ``loadfile`` in that it only manipulates the
|
||||
state of what to play next, without waiting until the current file is
|
||||
unloaded, and the next one is loaded.
|
||||
|
||||
Setting ``playlist-pos`` or similar properties can have a similar effect to
|
||||
this command. However, it's more explicit, and guarantees that playback is
|
||||
restarted if for example the new playlist entry is the same as the previous
|
||||
one.
|
||||
|
||||
``loadfile <url> [<flags> [<options>]]``
|
||||
Load the given file or URL and play it. Technically, this is just a playlist
|
||||
manipulation command (which either replaces the playlist or appends an entry
|
||||
@ -649,11 +672,17 @@ Remember to quote string arguments in input.conf (see `Flat command syntax`_).
|
||||
Write the resume config file that the ``quit-watch-later`` command writes,
|
||||
but continue playback normally.
|
||||
|
||||
``stop``
|
||||
``stop [<flags>]``
|
||||
Stop playback and clear playlist. With default settings, this is
|
||||
essentially like ``quit``. Useful for the client API: playback can be
|
||||
stopped without terminating the player.
|
||||
|
||||
The first argument is optional, and supports the following flags:
|
||||
|
||||
keep-playlist
|
||||
Do not clear the playlist.
|
||||
|
||||
|
||||
``mouse <x> <y> [<button> [<mode>]]``
|
||||
Send a mouse event with given coordinate (``<x>``, ``<y>``).
|
||||
|
||||
@ -2242,6 +2271,9 @@ Property list
|
||||
Current position on playlist. The first entry is on position 0. Writing to
|
||||
this property may start playback at the new position.
|
||||
|
||||
In some cases, this is not necessarily the currently playing file. See
|
||||
explanation of ``current`` and ``playing`` flags in ``playlist``.
|
||||
|
||||
If there the playlist is empty, or if it's non-empty, but no entry is
|
||||
"current", this property returns -1. Likewise, writing -1 will put the
|
||||
player into idle mode (or exit playback if idle mode is not enabled). If an
|
||||
@ -2249,15 +2281,47 @@ Property list
|
||||
(Before mpv 0.33.0, instead of returning -1, this property was unavailable
|
||||
if no playlist entry was current.)
|
||||
|
||||
What happens if you write the same value back to the property is
|
||||
implementation dependent. Currently, writing the same value will restart
|
||||
playback from the beginning. It is possible (but not necessarily planned)
|
||||
that in the future, write access if the same value is written will be
|
||||
ignored.
|
||||
Writing the current value back to the property is subject to change.
|
||||
Currently, it will restart playback of the playlist entry. But in the
|
||||
future, writing the current value will be ignored. Use the
|
||||
``playlist-play-index`` command to get guaranteed behavior.
|
||||
|
||||
``playlist-pos-1`` (RW)
|
||||
Same as ``playlist-pos``, but 1-based.
|
||||
|
||||
``playlist-current-pos`` (RW)
|
||||
Index of the "current" item on playlist. This usually, but not necessarily,
|
||||
the currently playing item (see ``playlist-playing-pos``). Depending on the
|
||||
exact internal state of the player, it may refer to the playlist item to
|
||||
play next, or the playlist item used to determine what to play next.
|
||||
|
||||
For reading, this is exactly the same as ``playlist-pos``.
|
||||
|
||||
For writing, this *only* sets the position of the "current" item, without
|
||||
stopping playback of the current file (or starting playback, if this is done
|
||||
in idle mode). Use -1 to remove the current flag.
|
||||
|
||||
This property is only vaguely useful. If set during playback, it will
|
||||
typically cause the playlist entry *after* it to be played next. Another
|
||||
possibly odd observable state is that if ``playlist-next`` is run during
|
||||
playback, this property is set to the playlist entry to play next (unlike
|
||||
the previous case). There is an internal flag that decides whether the
|
||||
current playlist entry or the next one should be played, and this flag is
|
||||
currently inaccessible for API users. (Whether this behavior will kept is
|
||||
possibly subject to change.)
|
||||
|
||||
``playlist-playing-pos``
|
||||
Index of the "playing" item on playlist. A playlist item is "playing" if
|
||||
it's being loaded, actually playing, or being unloaded. This property is set
|
||||
during the ``MPV_EVENT_START_FILE`` (``start-file``) and the
|
||||
``MPV_EVENT_START_END`` (``end-file``) events. Outside of that, it returns
|
||||
-1. If the playlist entry was somehow removed during playback, but playback
|
||||
hasn't stopped yet, or is in progress of being stopped, it also returns -1.
|
||||
(This can happen at least during state transitions.)
|
||||
|
||||
In the "playing" state, this is usually the same as ``playlist-pos``, except
|
||||
during state changes, or if ``playlist-current-pos`` was written explicitly.
|
||||
|
||||
``playlist-count``
|
||||
Number of total playlist entries.
|
||||
|
||||
@ -2274,12 +2338,13 @@ Property list
|
||||
``playlist/N/filename``
|
||||
Filename of the Nth entry.
|
||||
|
||||
``playlist/N/current``, ``playlist/N/playing``
|
||||
``yes`` if this entry is currently playing (or being loaded).
|
||||
Unavailable or ``no`` otherwise. When changing files, ``current`` and
|
||||
``playing`` can be different, because the currently playing file hasn't
|
||||
been unloaded yet; in this case, ``current`` refers to the new
|
||||
selection. (Since mpv 0.7.0.)
|
||||
``playlist/N/playing``
|
||||
``yes`` if the ``playlist-playing-pos`` property points to this entry,
|
||||
unavailable or ``no`` otherwise.
|
||||
|
||||
``playlist/N/current``
|
||||
``yes`` if the ``playlist-current-pos`` property points to this entry,
|
||||
unavailable or ``no`` otherwise.
|
||||
|
||||
``playlist/N/title``
|
||||
Name of the Nth entry. Only available if the playlist file contains
|
||||
|
@ -62,6 +62,7 @@ static void playlist_update_indexes(struct playlist *pl, int start, int end)
|
||||
|
||||
void playlist_add(struct playlist *pl, struct playlist_entry *add)
|
||||
{
|
||||
assert(add->filename);
|
||||
MP_TARRAY_APPEND(pl, pl->entries, pl->num_entries, add);
|
||||
add->pl = pl;
|
||||
add->pl_index = pl->num_entries - 1;
|
||||
@ -283,9 +284,8 @@ void playlist_append_entries(struct playlist *pl, struct playlist *source_pl)
|
||||
// Return -1 if e is not on the list, or if e is NULL.
|
||||
int playlist_entry_to_index(struct playlist *pl, struct playlist_entry *e)
|
||||
{
|
||||
if (!e)
|
||||
if (!e || e->pl != pl)
|
||||
return -1;
|
||||
assert(e->pl == pl);
|
||||
return e->pl_index;
|
||||
}
|
||||
|
||||
|
@ -2700,6 +2700,39 @@ static int mp_property_sub_end(void *ctx, struct m_property *prop,
|
||||
return m_property_double_ro(action, arg, end);
|
||||
}
|
||||
|
||||
static int mp_property_playlist_current_pos(void *ctx, struct m_property *prop,
|
||||
int action, void *arg)
|
||||
{
|
||||
MPContext *mpctx = ctx;
|
||||
struct playlist *pl = mpctx->playlist;
|
||||
|
||||
switch (action) {
|
||||
case M_PROPERTY_GET: {
|
||||
*(int *)arg = playlist_entry_to_index(pl, pl->current);
|
||||
return M_PROPERTY_OK;
|
||||
}
|
||||
case M_PROPERTY_SET: {
|
||||
pl->current = playlist_entry_from_index(pl, *(int *)arg);
|
||||
mp_notify(mpctx, MP_EVENT_CHANGE_PLAYLIST, NULL);
|
||||
return M_PROPERTY_OK;
|
||||
}
|
||||
case M_PROPERTY_GET_TYPE:
|
||||
*(struct m_option *)arg = (struct m_option){.type = CONF_TYPE_INT};
|
||||
return M_PROPERTY_OK;
|
||||
}
|
||||
return M_PROPERTY_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
|
||||
static int mp_property_playlist_playing_pos(void *ctx, struct m_property *prop,
|
||||
int action, void *arg)
|
||||
{
|
||||
MPContext *mpctx = ctx;
|
||||
struct playlist *pl = mpctx->playlist;
|
||||
return m_property_int_ro(action, arg,
|
||||
playlist_entry_to_index(pl, mpctx->playing));
|
||||
}
|
||||
|
||||
static int mp_property_playlist_pos_x(void *ctx, struct m_property *prop,
|
||||
int action, void *arg, int base)
|
||||
{
|
||||
@ -2714,6 +2747,11 @@ static int mp_property_playlist_pos_x(void *ctx, struct m_property *prop,
|
||||
}
|
||||
case M_PROPERTY_SET: {
|
||||
int pos = *(int *)arg - base;
|
||||
if (pos >= 0 && playlist_entry_to_index(pl, pl->current) == pos) {
|
||||
MP_WARN(mpctx, "Behavior of %s when writing the same value will "
|
||||
"change (currently restarts, it will stop doing this).\n",
|
||||
prop->name);
|
||||
}
|
||||
mp_set_playlist_entry(mpctx, playlist_entry_from_index(pl, pos));
|
||||
return M_PROPERTY_OK;
|
||||
}
|
||||
@ -3348,6 +3386,8 @@ static const struct m_property mp_properties_base[] = {
|
||||
{"playlist", mp_property_playlist},
|
||||
{"playlist-pos", mp_property_playlist_pos},
|
||||
{"playlist-pos-1", mp_property_playlist_pos_1},
|
||||
{"playlist-current-pos", mp_property_playlist_current_pos},
|
||||
{"playlist-playing-pos", mp_property_playlist_playing_pos},
|
||||
M_PROPERTY_ALIAS("playlist-count", "playlist/count"),
|
||||
|
||||
// Audio
|
||||
@ -3508,7 +3548,8 @@ static const char *const *const mp_event_property_change[] = {
|
||||
E(MP_EVENT_WIN_STATE, "display-names", "display-fps"),
|
||||
E(MP_EVENT_WIN_STATE2, "display-hidpi-scale"),
|
||||
E(MP_EVENT_CHANGE_PLAYLIST, "playlist", "playlist-pos", "playlist-pos-1",
|
||||
"playlist-count", "playlist/count"),
|
||||
"playlist-count", "playlist/count", "playlist-current-pos",
|
||||
"playlist-playing-pos"),
|
||||
E(MP_EVENT_CORE_IDLE, "core-idle", "eof-reached"),
|
||||
};
|
||||
#undef E
|
||||
@ -4722,6 +4763,21 @@ static void cmd_playlist_next_prev(void *p)
|
||||
mpctx->add_osd_seek_info |= OSD_SEEK_INFO_CURRENT_FILE;
|
||||
}
|
||||
|
||||
static void cmd_playlist_play_index(void *p)
|
||||
{
|
||||
struct mp_cmd_ctx *cmd = p;
|
||||
struct MPContext *mpctx = cmd->mpctx;
|
||||
struct playlist *pl = mpctx->playlist;
|
||||
int pos = cmd->args[0].v.i;
|
||||
|
||||
if (pos == -2)
|
||||
pos = playlist_entry_to_index(pl, pl->current);
|
||||
|
||||
mp_set_playlist_entry(mpctx, playlist_entry_from_index(pl, pos));
|
||||
if (cmd->on_osd & MP_ON_OSD_MSG)
|
||||
mpctx->add_osd_seek_info |= OSD_SEEK_INFO_CURRENT_FILE;
|
||||
}
|
||||
|
||||
static void cmd_sub_step_seek(void *p)
|
||||
{
|
||||
struct mp_cmd_ctx *cmd = p;
|
||||
@ -4940,8 +4996,10 @@ static void cmd_stop(void *p)
|
||||
{
|
||||
struct mp_cmd_ctx *cmd = p;
|
||||
struct MPContext *mpctx = cmd->mpctx;
|
||||
int flags = cmd->args[0].v.i;
|
||||
|
||||
playlist_clear(mpctx->playlist);
|
||||
if (!(flags & 1))
|
||||
playlist_clear(mpctx->playlist);
|
||||
if (mpctx->stop_play != PT_QUIT)
|
||||
mpctx->stop_play = PT_STOP;
|
||||
mp_wakeup_core(mpctx);
|
||||
@ -5605,7 +5663,9 @@ const struct mp_cmd_def mp_cmds[] = {
|
||||
{ "quit-watch-later", cmd_quit, { {"code", OPT_INT(v.i),
|
||||
.flags = MP_CMD_OPT_ARG} },
|
||||
.priv = &(const bool){1} },
|
||||
{ "stop", cmd_stop, },
|
||||
{ "stop", cmd_stop,
|
||||
{ {"flags", OPT_FLAGS(v.i, {"keep-playlist", 1}), .flags = MP_CMD_OPT_ARG} }
|
||||
},
|
||||
{ "frame-step", cmd_frame_step, .allow_auto_repeat = true,
|
||||
.on_updown = true },
|
||||
{ "frame-back-step", cmd_frame_back_step, .allow_auto_repeat = true },
|
||||
@ -5627,6 +5687,12 @@ const struct mp_cmd_def mp_cmds[] = {
|
||||
},
|
||||
.priv = &(const int){-1},
|
||||
},
|
||||
{ "playlist-play-index", cmd_playlist_play_index,
|
||||
{
|
||||
{"index", OPT_CHOICE(v.i, {"current", -2}, {"none", -1}),
|
||||
M_RANGE(-1, INT_MAX)},
|
||||
}
|
||||
},
|
||||
{ "playlist-shuffle", cmd_playlist_shuffle, },
|
||||
{ "playlist-unshuffle", cmd_playlist_unshuffle, },
|
||||
{ "sub-step", cmd_sub_step_seek, { {"skip", OPT_INT(v.i)} },
|
||||
|
@ -1409,8 +1409,8 @@ static void play_current_file(struct MPContext *mpctx)
|
||||
reset_playback_state(mpctx);
|
||||
|
||||
mpctx->playing = mpctx->playlist->current;
|
||||
if (!mpctx->playing || !mpctx->playing->filename)
|
||||
goto terminate_playback;
|
||||
assert(mpctx->playing);
|
||||
assert(mpctx->playing->filename);
|
||||
mpctx->playing->reserved += 1;
|
||||
|
||||
mpctx->filename = talloc_strdup(NULL, mpctx->playing->filename);
|
||||
|
Loading…
Reference in New Issue
Block a user