summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2020-03-21 17:08:43 +0100
committerwm4 <wm4@nowhere>2020-03-21 19:32:50 +0100
commite9e93b4dbe748cd341a6fbea355e6ba013ada81b (patch)
treeae548b385123e620adf4432f3ab4666f425874c7
parent68d9d11ddf2817b682b0a9f87d4d42791d5666ca (diff)
downloadmpv-e9e93b4dbe748cd341a6fbea355e6ba013ada81b.tar.bz2
mpv-e9e93b4dbe748cd341a6fbea355e6ba013ada81b.tar.xz
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.
-rw-r--r--DOCS/interface-changes.rst6
-rw-r--r--DOCS/man/input.rst89
-rw-r--r--common/playlist.c4
-rw-r--r--player/command.c72
-rw-r--r--player/loadfile.c4
5 files changed, 156 insertions, 19 deletions
diff --git a/DOCS/interface-changes.rst b/DOCS/interface-changes.rst
index c63669ad7c..15be443190 100644
--- a/DOCS/interface-changes.rst
+++ b/DOCS/interface-changes.rst
@@ -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
diff --git a/DOCS/man/input.rst b/DOCS/man/input.rst
index 8f81b63f9f..e58bd2c507 100644
--- a/DOCS/man/input.rst
+++ b/DOCS/man/input.rst
@@ -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
diff --git a/common/playlist.c b/common/playlist.c
index 1fd202b98f..89c644dc33 100644
--- a/common/playlist.c
+++ b/common/playlist.c
@@ -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;
}
diff --git a/player/command.c b/player/command.c
index fd5ad60891..f8e248880a 100644
--- a/player/command.c
+++ b/player/command.c
@@ -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)} },
diff --git a/player/loadfile.c b/player/loadfile.c
index 0ae59a0e65..5dd8b7efbf 100644
--- a/player/loadfile.c
+++ b/player/loadfile.c
@@ -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);