diff options
-rw-r--r-- | mpvcore/command.c | 2 | ||||
-rw-r--r-- | mpvcore/mp_core.h | 6 | ||||
-rw-r--r-- | mpvcore/mplayer.c | 33 | ||||
-rw-r--r-- | mpvcore/playlist.h | 6 |
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 { |