summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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 {