diff options
Diffstat (limited to 'player/loadfile.c')
-rw-r--r-- | player/loadfile.c | 159 |
1 files changed, 121 insertions, 38 deletions
diff --git a/player/loadfile.c b/player/loadfile.c index e59acbc8d4..8023428e75 100644 --- a/player/loadfile.c +++ b/player/loadfile.c @@ -790,61 +790,141 @@ static void load_per_file_options(m_config_t *conf, } } -struct demux_open_args { - int stream_flags; - char *url; - struct mpv_global *global; - struct mp_cancel *cancel; - struct mp_log *log; - // results - struct demuxer *demux; - int err; -}; - -static void open_demux_thread(void *pctx) +static void *open_demux_thread(void *ctx) { - struct demux_open_args *args = pctx; - struct mpv_global *global = args->global; + struct MPContext *mpctx = ctx; + struct demuxer_params p = { - .force_format = global->opts->demuxer_name, + .force_format = mpctx->open_format, .allow_capture = true, - .stream_flags = args->stream_flags, + .stream_flags = mpctx->open_url_flags, }; - args->demux = demux_open_url(args->url, &p, args->cancel, global); - if (!args->demux) { + mpctx->open_res_demuxer = + demux_open_url(mpctx->open_url, &p, mpctx->open_cancel, mpctx->global); + + if (mpctx->open_res_demuxer) { + MP_VERBOSE(mpctx, "Opening done: %s\n", mpctx->open_url); + } else { + MP_VERBOSE(mpctx, "Opening failed or was aborted: %s\n", mpctx->open_url); + if (p.demuxer_failed) { - args->err = MPV_ERROR_UNKNOWN_FORMAT; + mpctx->open_res_error = MPV_ERROR_UNKNOWN_FORMAT; } else { - args->err = MPV_ERROR_LOADING_FAILED; + mpctx->open_res_error = MPV_ERROR_LOADING_FAILED; } } + + atomic_store(&mpctx->open_done, true); + mp_wakeup_core(mpctx); + return NULL; +} + +static void cancel_open(struct MPContext *mpctx) +{ + if (mpctx->open_cancel) + mp_cancel_trigger(mpctx->open_cancel); + + if (mpctx->open_active) + pthread_join(mpctx->open_thread, NULL); + mpctx->open_active = false; + + TA_FREEP(&mpctx->open_cancel); + TA_FREEP(&mpctx->open_url); + TA_FREEP(&mpctx->open_format); + + if (mpctx->open_res_demuxer) + free_demuxer_and_stream(mpctx->open_res_demuxer); + mpctx->open_res_demuxer = NULL; + + atomic_store(&mpctx->open_done, false); +} + +// Setup all the field to open this url, and make sure a thread is running. +static void start_open(struct MPContext *mpctx, char *url, int url_flags) +{ + cancel_open(mpctx); + + assert(!mpctx->open_active); + assert(!mpctx->open_cancel); + assert(!mpctx->open_res_demuxer); + assert(!atomic_load(&mpctx->open_done)); + + mpctx->open_cancel = mp_cancel_new(NULL); + mpctx->open_url = talloc_strdup(NULL, url); + mpctx->open_format = talloc_strdup(NULL, mpctx->opts->demuxer_name); + mpctx->open_url_flags = url_flags; + if (mpctx->opts->load_unsafe_playlists) + mpctx->open_url_flags = 0; + + if (pthread_create(&mpctx->open_thread, NULL, open_demux_thread, mpctx)) { + cancel_open(mpctx); + return; + } + + mpctx->open_active = true; } static void open_demux_reentrant(struct MPContext *mpctx) { - struct demux_open_args args = { - .global = mpctx->global, - .cancel = mp_cancel_new(NULL), - .log = mpctx->log, - .stream_flags = mpctx->playing->stream_flags, - .url = talloc_strdup(NULL, mpctx->stream_open_filename), - }; + char *url = mpctx->stream_open_filename; + + if (mpctx->open_active) { + bool done = atomic_load(&mpctx->open_done); + bool failed = done && !mpctx->open_res_demuxer; + bool correct_url = strcmp(mpctx->open_url, url) == 0; + + if (correct_url && !failed) { + MP_VERBOSE(mpctx, "Using prefetched/prefetching URL.\n"); + } else if (correct_url && failed) { + MP_VERBOSE(mpctx, "Prefetched URL failed, retrying.\n"); + cancel_open(mpctx); + } else { + if (!done) + MP_VERBOSE(mpctx, "Aborting onging prefetch of wrong URL.\n"); + cancel_open(mpctx); + } + } + + if (!mpctx->open_active) + start_open(mpctx, url, mpctx->playing->stream_flags); + + // User abort should cancel the opener now. pthread_mutex_lock(&mpctx->lock); - mpctx->demuxer_cancel = args.cancel; + mpctx->demuxer_cancel = mpctx->open_cancel; pthread_mutex_unlock(&mpctx->lock); - if (mpctx->opts->load_unsafe_playlists) - args.stream_flags = 0; - mpctx_run_reentrant(mpctx, open_demux_thread, &args); - if (args.demux) { - mpctx->demuxer = args.demux; + + while (!atomic_load(&mpctx->open_done)) { + mp_idle(mpctx); + + if (mpctx->stop_play) + mp_abort_playback_async(mpctx); + } + + if (mpctx->open_res_demuxer) { + assert(mpctx->demuxer_cancel == mpctx->open_cancel); + mpctx->demuxer = mpctx->open_res_demuxer; + mpctx->open_res_demuxer = NULL; + mpctx->open_cancel = NULL; } else { - mpctx->error_playing = args.err; + mpctx->error_playing = mpctx->open_res_error; pthread_mutex_lock(&mpctx->lock); - talloc_free(mpctx->demuxer_cancel); mpctx->demuxer_cancel = NULL; pthread_mutex_unlock(&mpctx->lock); } - talloc_free(args.url); + + cancel_open(mpctx); // cleanup +} + +void prefetch_next(struct MPContext *mpctx) +{ + if (!mpctx->opts->prefetch_open) + return; + + struct playlist_entry *new_entry = mp_next_file(mpctx, +1, false, 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); + } } static bool init_complex_filters(struct MPContext *mpctx) @@ -1279,8 +1359,9 @@ terminate_playback: // 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 force, bool mutate) { struct playlist_entry *next = playlist_get_next(mpctx->playlist, direction); if (next && direction < 0 && !force) { @@ -1340,7 +1421,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 || !mpctx->stop_play) { - new_entry = mp_next_file(mpctx, +1, false); + new_entry = mp_next_file(mpctx, +1, false, true); } mpctx->playlist->current = new_entry; @@ -1350,6 +1431,8 @@ void mp_play_files(struct MPContext *mpctx) if (!mpctx->playlist->current && mpctx->opts->player_idle_mode < 2) break; } + + cancel_open(mpctx); } // Abort current playback and set the given entry to play next. |