diff options
author | wm4 <wm4@nowhere> | 2014-10-06 21:20:38 +0200 |
---|---|---|
committer | wm4 <wm4@nowhere> | 2014-10-06 21:49:26 +0200 |
commit | 5fb05940f1b4d0dad208d94ddd73d78520d8ce03 (patch) | |
tree | 9be531822bb1cd7e2fc1daab2aa96eaf00043945 /player/misc.c | |
parent | d26104351b65a212c03ec08679cb45a3aa2f0a32 (diff) | |
download | mpv-5fb05940f1b4d0dad208d94ddd73d78520d8ce03.tar.bz2 mpv-5fb05940f1b4d0dad208d94ddd73d78520d8ce03.tar.xz |
player: open stream and demuxer asynchronously
Run opening the stream and opening the demuxer in a separate thread.
This should remove the last code paths in which the player can normally
get blocked on network.
When the stream is opened, the player will still react to input and so
on. Commands to abort opening can also be handled properly, instead of
using some of the old hacks in input.c. The only thing the user can
really do is aborting loading by navigating the playlist or quitting.
Whether playback abort works depends on the stream implementation; with
normal network, this will depend on what libavformat (via "interrupt"
callback) does.
Some pain is caused by DVD/BD/DVB. These want to reload the demuxer
sometimes. DVB wants it in order to discard old, inactive streams.
DVD/BD for the same reason, and also for reloading stream languages
and similar metadata. This means the stream and the demuxer have to
be loaded separately.
One minor detail is that we now need to copy all global options. This
wasn't really needed before, because the options were accessed on
opening only, but since opening is now on a separate thread, this
obviously becomes a necessity.
Diffstat (limited to 'player/misc.c')
-rw-r--r-- | player/misc.c | 64 |
1 files changed, 64 insertions, 0 deletions
diff --git a/player/misc.c b/player/misc.c index d5e27f9584..21e9bcbba3 100644 --- a/player/misc.c +++ b/player/misc.c @@ -18,6 +18,7 @@ #include <stddef.h> #include <stdbool.h> +#include <pthread.h> #include <assert.h> #include "config.h" @@ -29,7 +30,9 @@ #include "common/msg.h" #include "options/options.h" #include "options/m_property.h" +#include "options/m_config.h" #include "common/common.h" +#include "common/global.h" #include "common/encode.h" #include "common/playlist.h" #include "input/input.h" @@ -219,3 +222,64 @@ void merge_playlist_files(struct playlist *pl) playlist_add_file(pl, edl); talloc_free(edl); } + +// Create a talloc'ed copy of mpctx->global. It contains a copy of the global +// option struct. It still just references some things though, like mp_log. +// The main purpose is letting threads access the option struct without the +// need for additional synchronization. +struct mpv_global *create_sub_global(struct MPContext *mpctx) +{ + struct mpv_global *new = talloc_ptrtype(NULL, new); + struct m_config *new_config = m_config_dup(new, mpctx->mconfig); + *new = (struct mpv_global){ + .log = mpctx->global->log, + .opts = new_config->optstruct, + }; + return new; +} + +struct wrapper_args { + struct MPContext *mpctx; + void (*thread_fn)(void *); + void *thread_arg; + pthread_mutex_t mutex; + bool done; +}; + +static void *thread_wrapper(void *pctx) +{ + struct wrapper_args *args = pctx; + args->thread_fn(args->thread_arg); + pthread_mutex_lock(&args->mutex); + args->done = true; + pthread_mutex_unlock(&args->mutex); + mp_input_wakeup(args->mpctx->input); // this interrupts mp_idle() + return NULL; +} + +// Run the thread_fn in a new thread. Wait until the thread returns, but while +// waiting, process input and input commands. +int mpctx_run_non_blocking(struct MPContext *mpctx, void (*thread_fn)(void *arg), + void *thread_arg) +{ + struct wrapper_args args = {mpctx, thread_fn, thread_arg}; + pthread_mutex_init(&args.mutex, NULL); + bool success = false; + pthread_t thread; + if (pthread_create(&thread, NULL, thread_wrapper, &args)) + goto done; + while (!success) { + mp_idle(mpctx); + + if (mpctx->stop_play) + mp_cancel_trigger(mpctx->playback_abort); + + pthread_mutex_lock(&args.mutex); + success |= args.done; + pthread_mutex_unlock(&args.mutex); + } + pthread_join(thread, NULL); +done: + pthread_mutex_destroy(&args.mutex); + return success ? 0 : -1; +} |