summaryrefslogtreecommitdiffstats
path: root/player/loadfile.c
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2014-10-06 21:20:38 +0200
committerwm4 <wm4@nowhere>2014-10-06 21:49:26 +0200
commit5fb05940f1b4d0dad208d94ddd73d78520d8ce03 (patch)
tree9be531822bb1cd7e2fc1daab2aa96eaf00043945 /player/loadfile.c
parentd26104351b65a212c03ec08679cb45a3aa2f0a32 (diff)
downloadmpv-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/loadfile.c')
-rw-r--r--player/loadfile.c67
1 files changed, 59 insertions, 8 deletions
diff --git a/player/loadfile.c b/player/loadfile.c
index e015b867e7..23ffa80684 100644
--- a/player/loadfile.c
+++ b/player/loadfile.c
@@ -32,6 +32,7 @@
#include "osdep/timer.h"
#include "common/msg.h"
+#include "common/global.h"
#include "options/path.h"
#include "options/m_config.h"
#include "options/parse_configfile.h"
@@ -844,6 +845,60 @@ static void load_per_file_options(m_config_t *conf,
}
}
+struct stream_open_args {
+ struct mp_cancel *cancel;
+ struct mpv_global *global; // contains copy of global options
+ char *filename;
+ int stream_flags;
+ struct stream *stream; // result
+};
+
+static void open_stream_thread(void *pctx)
+{
+ struct stream_open_args *args = pctx;
+ args->stream = stream_create(args->filename, args->stream_flags,
+ args->cancel, args->global);
+}
+
+static struct stream *open_stream_async(struct MPContext *mpctx,
+ char *filename, int stream_flags)
+{
+ struct stream_open_args args = {
+ .cancel = mpctx->playback_abort,
+ .global = create_sub_global(mpctx),
+ .filename = filename,
+ .stream_flags = stream_flags,
+ };
+ mpctx_run_non_blocking(mpctx, open_stream_thread, &args);
+ if (args.stream) {
+ talloc_steal(args.stream, args.global);
+ } else {
+ talloc_free(args.global);
+ }
+ return args.stream;
+}
+
+struct demux_open_args {
+ struct stream *stream;
+ struct demuxer *demux; // result
+};
+
+static void open_demux_thread(void *pctx)
+{
+ struct demux_open_args *args = pctx;
+ struct stream *s = args->stream;
+ struct mpv_global *global = s->global; // they run in the same thread anyway
+ args->demux = demux_open(s, global->opts->demuxer_name, NULL, global);
+}
+
+static struct demuxer *open_demux_async(struct MPContext *mpctx,
+ struct stream *stream)
+{
+ struct demux_open_args args = {stream};
+ mpctx_run_non_blocking(mpctx, open_demux_thread, &args);
+ return args.demux;
+}
+
// Start playing the current playlist entry.
// Handle initialization and deinitialization.
static void play_current_file(struct MPContext *mpctx)
@@ -880,7 +935,7 @@ static void play_current_file(struct MPContext *mpctx)
goto terminate_playback;
mpctx->playing->reserved += 1;
- mpctx->filename = mpctx->playing->filename;
+ mpctx->filename = talloc_strdup(tmp, mpctx->playing->filename);
mpctx->add_osd_seek_info &= OSD_SEEK_INFO_EDITION;
@@ -931,8 +986,7 @@ static void play_current_file(struct MPContext *mpctx)
int stream_flags = STREAM_READ;
if (!opts->load_unsafe_playlists)
stream_flags |= mpctx->playing->stream_flags;
- mpctx->stream = stream_create(stream_filename, stream_flags,
- mpctx->playback_abort, mpctx->global);
+ mpctx->stream = open_stream_async(mpctx, stream_filename, stream_flags);
if (!mpctx->stream) { // error...
mp_process_input(mpctx);
goto terminate_playback;
@@ -958,15 +1012,12 @@ goto_reopen_demuxer: ;
mp_nav_reset(mpctx);
- //============ Open DEMUXERS --- DETECT file type =======================
-
- mpctx->demuxer = demux_open(mpctx->stream, opts->demuxer_name, NULL,
- mpctx->global);
- mpctx->master_demuxer = mpctx->demuxer;
+ mpctx->demuxer = open_demux_async(mpctx, mpctx->stream);
if (!mpctx->demuxer) {
MP_ERR(mpctx, "Failed to recognize file format.\n");
goto terminate_playback;
}
+ mpctx->master_demuxer = mpctx->demuxer;
MP_TARRAY_APPEND(NULL, mpctx->sources, mpctx->num_sources, mpctx->demuxer);