summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2013-09-15 05:03:37 +0200
committerwm4 <wm4@nowhere>2013-09-15 05:03:55 +0200
commit884c179177063ad81cf7a7242c01767f46cd1cf8 (patch)
treeb7f1c8b896541594eff6f59c36a97a65decdca3f
parentaa43405020e2e710b8b431633b6750e92897c6b9 (diff)
downloadmpv-884c179177063ad81cf7a7242c01767f46cd1cf8.tar.bz2
mpv-884c179177063ad81cf7a7242c01767f46cd1cf8.tar.xz
mplayer: attempt to skip playlist entries which can't be played
This is for situations when repeated attempts at playing a playlist entry failed, and playlist navigation becomes impossible due to that. For example, it wasn't possible to skip backwards past an unplayable playlist entry: mpv file1.mkv doesntexist.mkv file3.mkv You couldn't skip back to file1.mkv from file3.mkv. When running a single "playlist_prev" command, doesntexist.mkv would be played, which would fail to load. As reaction to the failure to load it, the next file would be played, which is file3.mkv. To make this even worse, the file could successfully load, but run only for a split second. So just loading successfully isn't good enough. Attempt to solve this by marking problematic playlist entries as failed, and by having playlist_prev skip past such playlist entries. We define failure as not being able to play more than 3 seconds (or failing to initialize to begin with). (The 3 seconds are in real time, not file duration.) "playlist_prev force" still exhibits the old behavior. Additionally, use the same mechanism to prevent pointless infinite reloading if none of the files on the playlist exist. (See github issue All in all, this is a heuristic, and later adjustments might be necessary. Note: forward skips (playlist_next) are not affected at all. (Except for the interaction with --loop.)
-rw-r--r--mpvcore/command.c2
-rw-r--r--mpvcore/mp_core.h6
-rw-r--r--mpvcore/mplayer.c33
-rw-r--r--mpvcore/playlist.h6
4 files changed, 42 insertions, 5 deletions
diff --git a/mpvcore/command.c b/mpvcore/command.c
index b3a1b7a360..df78f59d4b 100644
--- a/mpvcore/command.c
+++ b/mpvcore/command.c
@@ -2295,7 +2295,7 @@ void run_command(MPContext *mpctx, mp_cmd_t *cmd)
int dir = cmd->id == MP_CMD_PLAYLIST_PREV ? -1 : +1;
int force = cmd->args[0].v.i;
- struct playlist_entry *e = mp_next_file(mpctx, dir);
+ struct playlist_entry *e = mp_next_file(mpctx, dir, force);
if (!e && !force)
break;
mpctx->playlist->current = e;
diff --git a/mpvcore/mp_core.h b/mpvcore/mp_core.h
index d997aa4d58..9f3e095110 100644
--- a/mpvcore/mp_core.h
+++ b/mpvcore/mp_core.h
@@ -42,7 +42,8 @@
enum stop_play_reason {
KEEP_PLAYING = 0, // must be 0, numeric values of others do not matter
- AT_END_OF_FILE, // file has ended normally, prepare to play next
+ AT_END_OF_FILE, // file has ended, prepare to play next
+ // also returned on unrecoverable playback errors
PT_NEXT_ENTRY, // prepare to play next entry in playlist
PT_CURRENT_ENTRY, // prepare to play mpctx->playlist->current
PT_STOP, // stop playback, clear playlist
@@ -332,7 +333,8 @@ void mp_switch_track(struct MPContext *mpctx, enum stream_type type,
struct track *mp_track_by_tid(struct MPContext *mpctx, enum stream_type type,
int tid);
bool mp_remove_track(struct MPContext *mpctx, struct track *track);
-struct playlist_entry *mp_next_file(struct MPContext *mpctx, int direction);
+struct playlist_entry *mp_next_file(struct MPContext *mpctx, int direction,
+ bool force);
int mp_get_cache_percent(struct MPContext *mpctx);
void mp_write_watch_later_conf(struct MPContext *mpctx);
void mp_set_playlist_entry(struct MPContext *mpctx, struct playlist_entry *e);
diff --git a/mpvcore/mplayer.c b/mpvcore/mplayer.c
index 06017c7d32..fe5b120c50 100644
--- a/mpvcore/mplayer.c
+++ b/mpvcore/mplayer.c
@@ -4287,6 +4287,7 @@ static void transfer_playlist(struct MPContext *mpctx, struct playlist *pl)
static void play_current_file(struct MPContext *mpctx)
{
struct MPOpts *opts = mpctx->opts;
+ double playback_start = -1e100;
mpctx->initialized_flags |= INITIALIZED_PLAYBACK;
mpctx->stop_play = 0;
@@ -4574,6 +4575,7 @@ goto_reopen_demuxer: ;
if (mpctx->opts->pause)
pause_player(mpctx);
+ playback_start = mp_time_sec();
mpctx->error_playing = false;
while (!mpctx->stop_play)
run_playloop(mpctx);
@@ -4591,6 +4593,9 @@ goto_reopen_demuxer: ;
terminate_playback: // don't jump here after ao/vo/getch initialization!
+ if (mpctx->stop_play == KEEP_PLAYING)
+ mpctx->stop_play = AT_END_OF_FILE;
+
if (opts->position_save_on_quit && mpctx->stop_play == PT_QUIT)
mp_write_watch_later_conf(mpctx);
@@ -4622,13 +4627,26 @@ terminate_playback: // don't jump here after ao/vo/getch initialization!
mpctx->osd->ass_renderer = NULL;
ass_clear_fonts(mpctx->ass_library);
#endif
+
+ // Played/paused for longer than 3 seconds -> ok
+ bool playback_failed = mpctx->stop_play == AT_END_OF_FILE &&
+ (playback_start < 0 || mp_time_sec() - playback_start < 3.0);
+ if (mpctx->playlist->current && !mpctx->playlist->current_was_replaced)
+ mpctx->playlist->current->playback_failed = playback_failed;
}
// Determine the next file to play. Note that if this function returns non-NULL,
// it can have side-effects and mutate mpctx.
-struct playlist_entry *mp_next_file(struct MPContext *mpctx, int direction)
+// direction: -1 (previous) or +1 (next)
+// force: if true, don't skip playlist entries marked as failed
+struct playlist_entry *mp_next_file(struct MPContext *mpctx, int direction,
+ bool force)
{
struct playlist_entry *next = playlist_get_next(mpctx->playlist, direction);
+ if (direction < 0 && !force) {
+ while (next && next->playback_failed)
+ next = next->prev;
+ }
if (!next && mpctx->opts->loop_times >= 0) {
if (direction > 0) {
if (mpctx->opts->shuffle)
@@ -4642,6 +4660,17 @@ struct playlist_entry *mp_next_file(struct MPContext *mpctx, int direction)
} else {
next = mpctx->playlist->last;
}
+ if (!force && next && next->playback_failed) {
+ bool all_failed = true;
+ struct playlist_entry *cur;
+ for (cur = mpctx->playlist->first; cur; cur = cur->next) {
+ all_failed &= cur->playback_failed;
+ if (!all_failed)
+ break;
+ }
+ if (all_failed)
+ next = NULL;
+ }
}
return next;
}
@@ -4678,7 +4707,7 @@ static void play_files(struct MPContext *mpctx)
struct playlist_entry *new_entry = NULL;
if (mpctx->stop_play == PT_NEXT_ENTRY) {
- new_entry = mp_next_file(mpctx, +1);
+ new_entry = mp_next_file(mpctx, +1, false);
} else if (mpctx->stop_play == PT_CURRENT_ENTRY) {
new_entry = mpctx->playlist->current;
} else if (mpctx->stop_play == PT_RESTART) {
diff --git a/mpvcore/playlist.h b/mpvcore/playlist.h
index fcf04929ac..17a5cf6a9b 100644
--- a/mpvcore/playlist.h
+++ b/mpvcore/playlist.h
@@ -33,6 +33,12 @@ struct playlist_entry {
struct playlist_param *params;
int num_params;
+
+ // Set to true if playback didn't seem to work, or if the file could be
+ // played only for a very short time. This is used to make playlist
+ // navigation just work in case the user has unplayable files in the
+ // playlist.
+ bool playback_failed;
};
struct playlist {