diff options
Diffstat (limited to 'player/loadfile.c')
-rw-r--r-- | player/loadfile.c | 372 |
1 files changed, 194 insertions, 178 deletions
diff --git a/player/loadfile.c b/player/loadfile.c index 6032cf6193..95afd13550 100644 --- a/player/loadfile.c +++ b/player/loadfile.c @@ -17,13 +17,11 @@ #include <stddef.h> #include <stdbool.h> -#include <strings.h> #include <inttypes.h> #include <assert.h> #include <libavutil/avutil.h> -#include "config.h" #include "mpv_talloc.h" #include "misc/thread_pool.h" @@ -45,9 +43,9 @@ #include "options/m_property.h" #include "common/common.h" #include "common/encode.h" -#include "common/recorder.h" #include "common/stats.h" #include "input/input.h" +#include "misc/language.h" #include "audio/out/ao.h" #include "filters/f_decoder_wrapper.h" @@ -75,7 +73,7 @@ void mp_abort_playback_async(struct MPContext *mpctx) { mp_cancel_trigger(mpctx->playback_abort); - pthread_mutex_lock(&mpctx->abort_lock); + mp_mutex_lock(&mpctx->abort_lock); for (int n = 0; n < mpctx->num_abort_list; n++) { struct mp_abort_entry *abort = mpctx->abort_list[n]; @@ -83,25 +81,25 @@ void mp_abort_playback_async(struct MPContext *mpctx) mp_abort_trigger_locked(mpctx, abort); } - pthread_mutex_unlock(&mpctx->abort_lock); + mp_mutex_unlock(&mpctx->abort_lock); } // Add it to the global list, and allocate required data structures. void mp_abort_add(struct MPContext *mpctx, struct mp_abort_entry *abort) { - pthread_mutex_lock(&mpctx->abort_lock); + mp_mutex_lock(&mpctx->abort_lock); assert(!abort->cancel); abort->cancel = mp_cancel_new(NULL); MP_TARRAY_APPEND(NULL, mpctx->abort_list, mpctx->num_abort_list, abort); mp_abort_recheck_locked(mpctx, abort); - pthread_mutex_unlock(&mpctx->abort_lock); + mp_mutex_unlock(&mpctx->abort_lock); } // Remove Add it to the global list, and free/clear required data structures. // Does not deallocate the abort value itself. void mp_abort_remove(struct MPContext *mpctx, struct mp_abort_entry *abort) { - pthread_mutex_lock(&mpctx->abort_lock); + mp_mutex_lock(&mpctx->abort_lock); for (int n = 0; n < mpctx->num_abort_list; n++) { if (mpctx->abort_list[n] == abort) { MP_TARRAY_REMOVE_AT(mpctx->abort_list, mpctx->num_abort_list, n); @@ -111,7 +109,7 @@ void mp_abort_remove(struct MPContext *mpctx, struct mp_abort_entry *abort) } } assert(!abort); // should have been in the list - pthread_mutex_unlock(&mpctx->abort_lock); + mp_mutex_unlock(&mpctx->abort_lock); } // Verify whether the abort needs to be signaled after changing certain fields @@ -217,7 +215,6 @@ static void uninit_demuxer(struct MPContext *mpctx) assert(!track->dec && !track->d_sub); assert(!track->vo_c && !track->ao_c); assert(!track->sink); - assert(!track->remux_sink); // Demuxers can be added in any order (if they appear mid-stream), and // we can't know which tracks uses which, so here's some O(n^2) trash. @@ -258,7 +255,13 @@ static void print_stream(struct MPContext *mpctx, struct track *t) break; } char b[2048] = {0}; - APPEND(b, " %3s %-5s", t->selected ? "(+)" : "", tname); + bool forced_only = false; + if (t->type == STREAM_SUB) { + bool forced_opt = mpctx->opts->subs_rend->sub_forced_events_only; + if (forced_opt) + forced_only = t->selected; + } + APPEND(b, " %3s %-5s", t->selected ? (forced_only ? "(*)" : "(+)") : "", tname); APPEND(b, " --%s=%d", selopt, t->user_tid); if (t->lang && langopt) APPEND(b, " --%s=%s", langopt, t->lang); @@ -268,10 +271,14 @@ static void print_stream(struct MPContext *mpctx, struct track *t) APPEND(b, " (f)"); if (t->attached_picture) APPEND(b, " [P]"); + if (forced_only) + APPEND(b, " [F]"); if (t->title) APPEND(b, " '%s'", t->title); const char *codec = s ? s->codec->codec : NULL; APPEND(b, " (%s", codec ? codec : "<unknown>"); + if (s && s->codec->codec_profile) + APPEND(b, " [%s]", s->codec->codec_profile); if (t->type == STREAM_VIDEO) { if (s && s->codec->disp_w) APPEND(b, " %dx%d", s->codec->disp_w, s->codec->disp_h); @@ -284,7 +291,7 @@ static void print_stream(struct MPContext *mpctx, struct track *t) APPEND(b, " %dHz", s->codec->samplerate); } APPEND(b, ")"); - if (s->hls_bitrate > 0) + if (s && s->hls_bitrate > 0) APPEND(b, " (%d kbps)", (s->hls_bitrate + 500) / 1000); if (t->is_external) APPEND(b, " (external)"); @@ -353,7 +360,7 @@ void update_demuxer_properties(struct MPContext *mpctx) } talloc_free(mpctx->filtered_tags); mpctx->filtered_tags = info; - mp_notify(mpctx, MPV_EVENT_METADATA_UPDATE, NULL); + mp_notify(mpctx, MP_EVENT_METADATA_UPDATE, NULL); } if (events & DEMUX_EVENT_DURATION) mp_notify(mpctx, MP_EVENT_DURATION_UPDATE, NULL); @@ -415,12 +422,15 @@ static struct track *add_stream_track(struct MPContext *mpctx, .user_tid = find_new_tid(mpctx, stream->type), .demuxer_id = stream->demuxer_id, .ff_index = stream->ff_index, + .hls_bitrate = stream->hls_bitrate, + .program_id = stream->program_id, .title = stream->title, .default_track = stream->default_track, .forced_track = stream->forced_track, .dependent_track = stream->dependent_track, .visual_impaired_track = stream->visual_impaired_track, .hearing_impaired_track = stream->hearing_impaired_track, + .image = stream->image, .attached_picture = stream->attached_picture != NULL, .lang = stream->lang, .demuxer = demuxer, @@ -428,7 +438,7 @@ static struct track *add_stream_track(struct MPContext *mpctx, }; MP_TARRAY_APPEND(mpctx, mpctx->tracks, mpctx->num_tracks, track); - mp_notify(mpctx, MPV_EVENT_TRACKS_CHANGED, NULL); + mp_notify(mpctx, MP_EVENT_TRACKS_CHANGED, NULL); return track; } @@ -439,16 +449,6 @@ void add_demuxer_tracks(struct MPContext *mpctx, struct demuxer *demuxer) add_stream_track(mpctx, demuxer, demux_get_stream(demuxer, n)); } -// Result numerically higher => better match. 0 == no match. -static int match_lang(char **langs, char *lang) -{ - for (int idx = 0; langs && langs[idx]; idx++) { - if (lang && strcasecmp(langs[idx], lang) == 0) - return INT_MAX - idx; - } - return 0; -} - /* Get the track wanted by the user. * tid is the track ID requested by the user (-2: deselect, -1: default) * lang is a string list, NULL is same as empty list @@ -457,10 +457,12 @@ static int match_lang(char **langs, char *lang) * 0b) track is not from --external-file * 1) track is external (no_default cancels this) * 1b) track was passed explicitly (is not an auto-loaded subtitle) - * 2) earlier match in lang list + * 1c) track matches the program ID of the video + * 2) earlier match in lang list but not if we're using os_langs * 3a) track is marked forced and we're preferring forced tracks * 3b) track is marked non-forced and we're preferring non-forced tracks * 3c) track is marked default + * 3d) match in lang list with os_langs * 4) attached picture, HLS bitrate * 5) lower track number * If select_fallback is not set, 5) is only used to determine whether a @@ -469,24 +471,38 @@ static int match_lang(char **langs, char *lang) * Forced tracks are preferred when the user prefers not to display subtitles */ // Return whether t1 is preferred over t2 -static bool compare_track(struct track *t1, struct track *t2, char **langs, - int prefer_forced, struct MPOpts *opts) +static bool compare_track(struct track *t1, struct track *t2, char **langs, bool os_langs, + bool forced, struct MPOpts *opts, int preferred_program) { + bool sub = t2->type == STREAM_SUB; if (!opts->autoload_files && t1->is_external != t2->is_external) return !t1->is_external; bool ext1 = t1->is_external && !t1->no_default; bool ext2 = t2->is_external && !t2->no_default; - if (ext1 != ext2) + if (ext1 != ext2) { + if (t1->attached_picture && t2->attached_picture + && opts->audio_display == 1) + return !ext1; return ext1; + } if (t1->auto_loaded != t2->auto_loaded) return !t1->auto_loaded; - int l1 = match_lang(langs, t1->lang), l2 = match_lang(langs, t2->lang); - if (l1 != l2) + if (preferred_program != -1 && t1->program_id != -1 && t2->program_id != -1) { + if ((t1->program_id == preferred_program) != + (t2->program_id == preferred_program)) + return t1->program_id == preferred_program; + } + int l1 = mp_match_lang(langs, t1->lang), l2 = mp_match_lang(langs, t2->lang); + if (!os_langs && l1 != l2) return l1 > l2; - if (t1->forced_track != t2->forced_track) - return prefer_forced ? t1->forced_track : !t1->forced_track; - if (t1->default_track != t2->default_track) + if (forced) + return t1->forced_track; + if (t1->default_track != t2->default_track && !t2->forced_select) return t1->default_track; + if (sub && !t2->forced_select && t2->forced_track) + return !t1->forced_track; + if (os_langs && l1 != l2) + return l1 > l2; if (t1->attached_picture != t2->attached_picture) return !t1->attached_picture; if (t1->stream && t2->stream && opts->hls_bitrate >= 0 && @@ -513,46 +529,106 @@ static bool duplicate_track(struct MPContext *mpctx, int order, return false; } +static bool append_lang(size_t *nb, char ***out, char *in) +{ + if (!in) + return false; + MP_TARRAY_GROW(NULL, *out, *nb + 1); + (*out)[(*nb)++] = in; + (*out)[*nb] = NULL; + ta_set_parent(in, *out); + return true; +} + +static char **add_os_langs(void) +{ + size_t nb = 0; + char **out = NULL; + char **autos = mp_get_user_langs(); + for (int i = 0; autos && autos[i]; i++) { + if (!append_lang(&nb, &out, autos[i])) + goto cleanup; + } + +cleanup: + talloc_free(autos); + return out; +} + +static char **process_langs(char **in) +{ + size_t nb = 0; + char **out = NULL; + for (int i = 0; in && in[i]; i++) { + if (!append_lang(&nb, &out, talloc_strdup(NULL, in[i]))) + break; + } + return out; +} + struct track *select_default_track(struct MPContext *mpctx, int order, enum stream_type type) { struct MPOpts *opts = mpctx->opts; int tid = opts->stream_id[order][type]; - char **langs = opts->stream_lang[type]; - int prefer_forced = type != STREAM_SUB || - (!opts->subs_with_matching_audio && - mpctx->current_track[0][STREAM_AUDIO] && - match_lang(langs, mpctx->current_track[0][STREAM_AUDIO]->lang)); + int preferred_program = (type != STREAM_VIDEO && mpctx->current_track[0][STREAM_VIDEO]) ? + mpctx->current_track[0][STREAM_VIDEO]->program_id : -1; if (tid == -2) return NULL; - bool select_fallback = type == STREAM_VIDEO || type == STREAM_AUDIO; + char **langs = process_langs(opts->stream_lang[type]); + bool os_langs = false; + // Try to add OS languages if enabled by the user and we don't already have a lang from slang. + if (type == STREAM_SUB && (!langs || !strcmp(langs[0], "")) && opts->subs_match_os_language) { + talloc_free(langs); + langs = add_os_langs(); + os_langs = true; + } + const char *audio_lang = mpctx->current_track[0][STREAM_AUDIO] ? + mpctx->current_track[0][STREAM_AUDIO]->lang : + NULL; + bool sub = type == STREAM_SUB; struct track *pick = NULL; for (int n = 0; n < mpctx->num_tracks; n++) { struct track *track = mpctx->tracks[n]; if (track->type != type) continue; - if (track->user_tid == tid) - return track; + if (track->user_tid == tid) { + pick = track; + goto cleanup; + } if (tid >= 0) continue; if (track->no_auto_select) continue; if (duplicate_track(mpctx, order, type, track)) continue; - if (!pick || compare_track(track, pick, langs, prefer_forced, mpctx->opts)) + if (sub) { + // Subtitle specific auto-selecting crap. + bool audio_matches = audio_lang && track->lang && !strcasecmp(audio_lang, track->lang); + bool forced = track->forced_track && (opts->subs_fallback_forced == 2 || + (audio_matches && opts->subs_fallback_forced == 1)); + bool lang_match = !os_langs && mp_match_lang(langs, track->lang) > 0; + bool subs_fallback = (track->is_external && !track->no_default) || opts->subs_fallback == 2 || + (opts->subs_fallback == 1 && track->default_track); + bool subs_matching_audio = (!mp_match_lang(langs, audio_lang) || opts->subs_with_matching_audio == 2 || + (opts->subs_with_matching_audio == 1 && track->forced_track)); + if (subs_matching_audio && ((!pick && (forced || lang_match || subs_fallback)) || + (pick && compare_track(track, pick, langs, os_langs, forced, mpctx->opts, preferred_program)))) + { + pick = track; + pick->forced_select = forced; + } + } else if (!pick || compare_track(track, pick, langs, os_langs, false, mpctx->opts, preferred_program)) { pick = track; + } } - if (pick && !select_fallback && !(pick->is_external && !pick->no_default) - && !match_lang(langs, pick->lang) && !pick->default_track - && !pick->forced_track) - pick = NULL; + if (pick && pick->attached_picture && !mpctx->opts->audio_display) pick = NULL; if (pick && !opts->autoload_files && pick->is_external) pick = NULL; - if (pick && type == STREAM_SUB && prefer_forced && !pick->forced_track && - opts->subs_rend->forced_subs_only == -1) - opts->subs_rend->forced_subs_only_current = 1; +cleanup: + talloc_free(langs); return pick; } @@ -660,8 +736,6 @@ void mp_switch_track_n(struct MPContext *mpctx, int order, enum stream_type type uninit_sub(mpctx, current); if (current) { - if (current->remux_sink) - close_recorder_and_error(mpctx); current->selected = false; reselect_demux_stream(mpctx, current, false); } @@ -681,7 +755,7 @@ void mp_switch_track_n(struct MPContext *mpctx, int order, enum stream_type type reinit_sub(mpctx, track); } - mp_notify(mpctx, MPV_EVENT_TRACK_SWITCHED, NULL); + mp_notify(mpctx, MP_EVENT_TRACK_SWITCHED, NULL); mp_wakeup_core(mpctx); talloc_free(mpctx->track_layout_hash); @@ -702,6 +776,8 @@ void mp_deselect_track(struct MPContext *mpctx, struct track *track) { if (track && track->selected) { for (int t = 0; t < num_ptracks[track->type]; t++) { + if (mpctx->current_track[t][track->type] != track) + continue; mp_switch_track_n(mpctx, t, track->type, NULL, 0); mark_track_selection(mpctx, t, track->type, -1); // default } @@ -747,7 +823,7 @@ bool mp_remove_track(struct MPContext *mpctx, struct track *track) if (!in_use) demux_cancel_and_free(d); - mp_notify(mpctx, MPV_EVENT_TRACKS_CHANGED, NULL); + mp_notify(mpctx, MP_EVENT_TRACKS_CHANGED, NULL); return true; } @@ -951,8 +1027,6 @@ static void transfer_playlist(struct MPContext *mpctx, struct playlist *pl, if (pl->num_entries) { prepare_playlist(mpctx, pl); struct playlist_entry *new = pl->current; - if (mpctx->playlist->current) - playlist_add_redirect(pl, mpctx->playlist->current->filename); *num_new_entries = pl->num_entries; *start_id = playlist_transfer_entries(mpctx->playlist, pl); // current entry is replaced @@ -1024,11 +1098,11 @@ static void load_per_file_options(m_config_t *conf, } } -static void *open_demux_thread(void *ctx) +static MP_THREAD_VOID open_demux_thread(void *ctx) { struct MPContext *mpctx = ctx; - mpthread_set_name("opener"); + mp_thread_set_name("opener"); struct demuxer_params p = { .force_format = mpctx->open_format, @@ -1066,7 +1140,7 @@ static void *open_demux_thread(void *ctx) atomic_store(&mpctx->open_done, true); mp_wakeup_core(mpctx); - return NULL; + MP_THREAD_RETURN(); } static void cancel_open(struct MPContext *mpctx) @@ -1075,7 +1149,7 @@ static void cancel_open(struct MPContext *mpctx) mp_cancel_trigger(mpctx->open_cancel); if (mpctx->open_active) - pthread_join(mpctx->open_thread, NULL); + mp_thread_join(mpctx->open_thread); mpctx->open_active = false; if (mpctx->open_res_demuxer) @@ -1106,7 +1180,7 @@ static void start_open(struct MPContext *mpctx, char *url, int url_flags, mpctx->open_url_flags = url_flags; mpctx->open_for_prefetch = for_prefetch && mpctx->opts->demuxer_thread; - if (pthread_create(&mpctx->open_thread, NULL, open_demux_thread, mpctx)) { + if (mp_thread_create(&mpctx->open_thread, open_demux_thread, mpctx)) { cancel_open(mpctx); return; } @@ -1167,13 +1241,35 @@ void prefetch_next(struct MPContext *mpctx) if (!mpctx->opts->prefetch_open) return; - struct playlist_entry *new_entry = mp_next_file(mpctx, +1, false, false); + struct playlist_entry *new_entry = mp_next_file(mpctx, +1, false); if (new_entry && !mpctx->open_active && new_entry->filename) { MP_VERBOSE(mpctx, "Prefetching: %s\n", new_entry->filename); start_open(mpctx, new_entry->filename, new_entry->stream_flags, true); } } +static void clear_playlist_paths(struct MPContext *mpctx) +{ + TA_FREEP(&mpctx->playlist_paths); + mpctx->playlist_paths_len = 0; +} + +static bool infinite_playlist_loading_loop(struct MPContext *mpctx, struct playlist *pl) +{ + if (pl->num_entries) { + struct playlist_entry *e = pl->entries[0]; + for (int n = 0; n < mpctx->playlist_paths_len; n++) { + if (strcmp(mpctx->playlist_paths[n], e->filename) == 0) { + clear_playlist_paths(mpctx); + return true; + } + } + } + MP_TARRAY_APPEND(mpctx, mpctx->playlist_paths, mpctx->playlist_paths_len, + talloc_strdup(mpctx->playlist_paths, mpctx->filename)); + return false; +} + // Destroy the complex filter, and remove the references to the filter pads. // (Call cleanup_deassociated_complex_filters() to close decoders/VO/AO // that are not connected anymore due to this.) @@ -1252,7 +1348,7 @@ static int reinit_complex_filters(struct MPContext *mpctx, bool force_uninit) } struct mp_lavfi *l = - mp_lavfi_create_graph(mpctx->filter_root, 0, false, NULL, graph); + mp_lavfi_create_graph(mpctx->filter_root, 0, false, NULL, NULL, graph); if (!l) goto done; mpctx->lavfi = l->f; @@ -1353,7 +1449,7 @@ done: reselect_demux_stream(mpctx, mpctx->tracks[n], false); } - mp_notify(mpctx, MPV_EVENT_TRACKS_CHANGED, NULL); + mp_notify(mpctx, MP_EVENT_TRACKS_CHANGED, NULL); return success ? 1 : -1; } @@ -1414,7 +1510,6 @@ static void load_external_opts(struct MPContext *mpctx) static void play_current_file(struct MPContext *mpctx) { struct MPOpts *opts = mpctx->opts; - double playback_start = -1e100; assert(mpctx->stop_play); mpctx->stop_play = 0; @@ -1439,7 +1534,7 @@ static void play_current_file(struct MPContext *mpctx) mpctx->shown_aframes = 0; mpctx->shown_vframes = 0; mpctx->last_chapter_seek = -2; - mpctx->last_chapter_pts = MP_NOPTS_VALUE; + mpctx->last_chapter_flag = false; mpctx->last_chapter = -2; mpctx->paused = false; mpctx->playing_msg_shown = false; @@ -1482,7 +1577,7 @@ static void play_current_file(struct MPContext *mpctx) mp_load_auto_profiles(mpctx); - mp_load_playback_resume(mpctx, mpctx->filename); + bool watch_later = mp_load_playback_resume(mpctx, mpctx->filename); load_per_file_options(mpctx->mconfig, mpctx->playing->params, mpctx->playing->num_params); @@ -1492,7 +1587,7 @@ static void play_current_file(struct MPContext *mpctx) handle_force_window(mpctx, false); if (mpctx->playlist->num_entries > 1 || - mpctx->playing->num_redirects) + mpctx->playing->playlist_path) MP_INFO(mpctx, "Playing: %s\n", mpctx->filename); assert(mpctx->demuxer == NULL); @@ -1521,7 +1616,15 @@ static void play_current_file(struct MPContext *mpctx) goto terminate_playback; if (mpctx->demuxer->playlist) { + if (watch_later) + mp_delete_watch_later_conf(mpctx, mpctx->filename); struct playlist *pl = mpctx->demuxer->playlist; + playlist_populate_playlist_path(pl, mpctx->filename); + if (infinite_playlist_loading_loop(mpctx, pl)) { + mpctx->stop_play = PT_STOP; + MP_ERR(mpctx, "Infinite playlist loading loop detected.\n"); + goto terminate_playback; + } transfer_playlist(mpctx, pl, &end_event.playlist_insert_id, &end_event.playlist_insert_num_entries); mp_notify_property(mpctx, "playlist"); @@ -1548,8 +1651,6 @@ static void play_current_file(struct MPContext *mpctx) if (reinit_complex_filters(mpctx, false) < 0) goto terminate_playback; - opts->subs_rend->forced_subs_only_current = (opts->subs_rend->forced_subs_only == 1) ? 1 : 0; - for (int t = 0; t < STREAM_TYPE_COUNT; t++) { for (int i = 0; i < num_ptracks[t]; i++) { struct track *sel = NULL; @@ -1619,7 +1720,7 @@ static void play_current_file(struct MPContext *mpctx) if (mpctx->vo_chain && mpctx->vo_chain->is_coverart) { MP_INFO(mpctx, - "Displaying attached picture. Use --no-audio-display to prevent this.\n"); + "Displaying cover art. Use --no-audio-display to prevent this.\n"); } if (!mpctx->vo_chain) @@ -1628,8 +1729,13 @@ static void play_current_file(struct MPContext *mpctx) MP_VERBOSE(mpctx, "Starting playback...\n"); mpctx->playback_initialized = true; + mpctx->playing->playlist_prev_attempt = false; mp_notify(mpctx, MPV_EVENT_FILE_LOADED, NULL); update_screensaver_state(mpctx); + clear_playlist_paths(mpctx); + + if (watch_later) + mp_delete_watch_later_conf(mpctx, mpctx->filename); if (mpctx->max_frames == 0) { if (!mpctx->stop_play) @@ -1665,9 +1771,6 @@ static void play_current_file(struct MPContext *mpctx) update_internal_pause_state(mpctx); - open_recorder(mpctx, true); - - playback_start = mp_time_sec(); mpctx->error_playing = 0; mpctx->in_playloop = true; while (!mpctx->stop_play) @@ -1687,14 +1790,12 @@ terminate_playback: update_core_idle_state(mpctx); if (mpctx->step_frames) { - opts->pause = 1; + opts->pause = true; m_config_notify_change_opt_ptr(mpctx->mconfig, &opts->pause); } process_hooks(mpctx, "on_unload"); - close_recorder(mpctx); - // time to uninit all, except global stuff: reinit_complex_filters(mpctx, true); uninit_audio_chain(mpctx); @@ -1716,7 +1817,7 @@ terminate_playback: talloc_free(mpctx->filtered_tags); mpctx->filtered_tags = NULL; - mp_notify(mpctx, MPV_EVENT_TRACKS_CHANGED, NULL); + mp_notify(mpctx, MP_EVENT_TRACKS_CHANGED, NULL); if (encode_lavc_didfail(mpctx->encode_lavc_ctx)) mpctx->stop_play = PT_ERROR; @@ -1726,6 +1827,7 @@ terminate_playback: bool nothing_played = !mpctx->shown_aframes && !mpctx->shown_vframes && mpctx->error_playing <= 0; + bool playlist_prev_continue = false; switch (mpctx->stop_play) { case PT_ERROR: case AT_END_OF_FILE: @@ -1741,10 +1843,10 @@ terminate_playback: end_event.reason = MPV_END_FILE_REASON_EOF; } if (mpctx->playing) { - // Played/paused for longer than 1 second -> ok - mpctx->playing->playback_short = - playback_start < 0 || mp_time_sec() - playback_start < 1.0; mpctx->playing->init_failed = nothing_played; + playlist_prev_continue = mpctx->playing->playlist_prev_attempt && + nothing_played; + mpctx->playing->playlist_prev_attempt = false; } break; } @@ -1760,7 +1862,6 @@ terminate_playback: mpv_error_string(end_event.error), end_event.reason); if (end_event.error == MPV_ERROR_UNKNOWN_FORMAT) MP_ERR(mpctx, "Failed to recognize file format.\n"); - MP_INFO(mpctx, "\n"); if (mpctx->playing) playlist_entry_unref(mpctx->playing); @@ -1780,25 +1881,26 @@ terminate_playback: assert(mpctx->stop_play); process_hooks(mpctx, "on_after_end_file"); + + if (playlist_prev_continue) { + struct playlist_entry *e = mp_next_file(mpctx, -1, false); + if (e) { + mp_set_playlist_entry(mpctx, e); + play_current_file(mpctx); + } + } } // Determine the next file to play. Note that if this function returns non-NULL, // it can have side-effects and mutate mpctx. // direction: -1 (previous) or +1 (next) // force: if true, don't skip playlist entries marked as failed -// mutate: if true, change loop counters struct playlist_entry *mp_next_file(struct MPContext *mpctx, int direction, - bool force, bool mutate) + bool force) { struct playlist_entry *next = playlist_get_next(mpctx->playlist, direction); - if (next && direction < 0 && !force) { - // Don't jump to files that would immediately go to next file anyway - while (next && next->playback_short) - next = playlist_entry_get_rel(next, -1); - // Always allow jumping to first file - if (!next && mpctx->opts->loop_times == 1) - next = playlist_get_first(mpctx->playlist); - } + if (next && direction < 0 && !force) + next->playlist_prev_attempt = true; if (!next && mpctx->opts->loop_times != 1) { if (direction > 0) { if (mpctx->opts->shuffle) @@ -1811,9 +1913,6 @@ struct playlist_entry *mp_next_file(struct MPContext *mpctx, int direction, } } else { next = playlist_get_last(mpctx->playlist); - // Don't jump to files that would immediately go to next file anyway - while (next && next->playback_short) - next = playlist_entry_get_rel(next, -1); } bool ignore_failures = mpctx->opts->loop_times == -2; if (!force && next && next->init_failed && !ignore_failures) { @@ -1866,7 +1965,7 @@ void mp_play_files(struct MPContext *mpctx) if (mpctx->stop_play == PT_NEXT_ENTRY || mpctx->stop_play == PT_ERROR || mpctx->stop_play == AT_END_OF_FILE) { - new_entry = mp_next_file(mpctx, +1, false, true); + new_entry = mp_next_file(mpctx, +1, false); } else if (mpctx->stop_play == PT_CURRENT_ENTRY) { new_entry = mpctx->playlist->current; } @@ -1906,86 +2005,3 @@ void mp_set_playlist_entry(struct MPContext *mpctx, struct playlist_entry *e) mpctx->stop_play = e ? PT_CURRENT_ENTRY : PT_STOP; mp_wakeup_core(mpctx); } - -static void set_track_recorder_sink(struct track *track, - struct mp_recorder_sink *sink) -{ - if (track->d_sub) - sub_set_recorder_sink(track->d_sub, sink); - if (track->dec) - track->dec->recorder_sink = sink; - track->remux_sink = sink; -} - -void close_recorder(struct MPContext *mpctx) -{ - if (!mpctx->recorder) - return; - - for (int n = 0; n < mpctx->num_tracks; n++) - set_track_recorder_sink(mpctx->tracks[n], NULL); - - mp_recorder_destroy(mpctx->recorder); - mpctx->recorder = NULL; -} - -// Like close_recorder(), but also unset the option. Intended for use on errors. -void close_recorder_and_error(struct MPContext *mpctx) -{ - close_recorder(mpctx); - talloc_free(mpctx->opts->record_file); - mpctx->opts->record_file = NULL; - m_config_notify_change_opt_ptr(mpctx->mconfig, &mpctx->opts->record_file); - MP_ERR(mpctx, "Disabling stream recording.\n"); -} - -void open_recorder(struct MPContext *mpctx, bool on_init) -{ - if (!mpctx->playback_initialized) - return; - - close_recorder(mpctx); - - char *target = mpctx->opts->record_file; - if (!target || !target[0]) - return; - - struct sh_stream **streams = NULL; - int num_streams = 0; - - for (int n = 0; n < mpctx->num_tracks; n++) { - struct track *track = mpctx->tracks[n]; - if (track->stream && track->selected && (track->d_sub || track->dec)) - MP_TARRAY_APPEND(NULL, streams, num_streams, track->stream); - } - - mpctx->recorder = mp_recorder_create(mpctx->global, mpctx->opts->record_file, - streams, num_streams); - - if (!mpctx->recorder) { - talloc_free(streams); - close_recorder_and_error(mpctx); - return; - } - - if (!on_init) - mp_recorder_mark_discontinuity(mpctx->recorder); - - int n_stream = 0; - for (int n = 0; n < mpctx->num_tracks; n++) { - struct track *track = mpctx->tracks[n]; - if (n_stream >= num_streams) - break; - // (We expect track->stream not to be reused on other tracks.) - if (track->stream == streams[n_stream]) { - struct mp_recorder_sink * sink = - mp_recorder_get_sink(mpctx->recorder, streams[n_stream]); - assert(sink); - set_track_recorder_sink(track, sink); - n_stream++; - } - } - - talloc_free(streams); -} - |