From b440f6dfb3d29651d8dcb7abfeb8ed18e3f2b995 Mon Sep 17 00:00:00 2001 From: wm4 Date: Sun, 6 May 2018 18:27:18 +0200 Subject: command: add infrastructure for async commands This enables two types of command behavior: 1. Plain async behavior, like "loadfile" not completing until the file is fully loaded. 2. Running parts of the command on worker threads, e.g. for I/O, such as "sub-add" doing network accesses on a thread while the core continues. Both have no implementation yet, and most new code is actually inactive. The plan is to implement a number of useful cases in the following commits. The most tricky part is handling internal keybindings (input.conf) and the multi-command feature (concatenating commands with ";"). It requires a bunch of roundabout code to make it do the expected thing in combination with async commands. There is the question how commands should be handled that come in at a higher rate than what can be handled by the core. Currently, it will simply queue up input.conf commands as long as memory lasts. The client API is limited by the size of the reply queue per client. For commands which require a worker thread, the thread pool is limited to 30 threads, and then will queue up work in memory. The number is completely arbitrary. --- player/main.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'player/main.c') diff --git a/player/main.c b/player/main.c index f56191a297..bc14bbce1c 100644 --- a/player/main.c +++ b/player/main.c @@ -28,6 +28,7 @@ #include "mpv_talloc.h" #include "misc/dispatch.h" +#include "misc/thread_pool.h" #include "osdep/io.h" #include "osdep/terminal.h" #include "osdep/timer.h" @@ -279,6 +280,7 @@ struct MPContext *mp_create(void) .playlist = talloc_struct(mpctx, struct playlist, {0}), .dispatch = mp_dispatch_create(mpctx), .playback_abort = mp_cancel_new(mpctx), + .thread_pool = mp_thread_pool_create(mpctx, 0, 1, 30), }; pthread_mutex_init(&mpctx->lock, NULL); -- cgit v1.2.3 From ce1f5e78c2b10e24c78d7ee65d7196093709b8ce Mon Sep 17 00:00:00 2001 From: wm4 Date: Sat, 12 May 2018 16:51:53 +0200 Subject: player: rename "lock" to "abort_lock" If a struct as large as MPContext contains a field named "lock", it creates the impression that it is the primary lock for MPContext. This is wrong, the lock just protects a single field. --- player/main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'player/main.c') diff --git a/player/main.c b/player/main.c index bc14bbce1c..d744c9cf12 100644 --- a/player/main.c +++ b/player/main.c @@ -189,7 +189,7 @@ void mp_destroy(struct MPContext *mpctx) uninit_libav(mpctx->global); mp_msg_uninit(mpctx->global); - pthread_mutex_destroy(&mpctx->lock); + pthread_mutex_destroy(&mpctx->abort_lock); talloc_free(mpctx); } @@ -283,7 +283,7 @@ struct MPContext *mp_create(void) .thread_pool = mp_thread_pool_create(mpctx, 0, 1, 30), }; - pthread_mutex_init(&mpctx->lock, NULL); + pthread_mutex_init(&mpctx->abort_lock, NULL); mpctx->global = talloc_zero(mpctx, struct mpv_global); -- cgit v1.2.3 From e4fb23ed7de874bb2d05824d7edb84cfd1b21101 Mon Sep 17 00:00:00 2001 From: wm4 Date: Sat, 12 May 2018 18:46:37 +0200 Subject: command: add a way to abort asynchronous commands Many asynchronous commands are potentially long running operations, such as loading something from network or running a foreign process. Obviously it shouldn't just be possible for them to freeze the player if they don't terminate as expected. Also, there will be situations where you want to explicitly stop some of those operations explicitly. So add an infrastructure for this. Commands have to support this explicitly. The next commit uses this to actually add support to a command. --- player/main.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'player/main.c') diff --git a/player/main.c b/player/main.c index d744c9cf12..c51f93a430 100644 --- a/player/main.c +++ b/player/main.c @@ -189,6 +189,8 @@ void mp_destroy(struct MPContext *mpctx) uninit_libav(mpctx->global); mp_msg_uninit(mpctx->global); + assert(!mpctx->num_abort_list); + talloc_free(mpctx->abort_list); pthread_mutex_destroy(&mpctx->abort_lock); talloc_free(mpctx); } -- cgit v1.2.3 From 31b78ad7fa97d8047b609c1647a273e72612d425 Mon Sep 17 00:00:00 2001 From: wm4 Date: Thu, 17 May 2018 20:58:49 +0200 Subject: misc: move mp_cancel from stream.c to thread_tools.c It seems a bit inappropriate to have dumped this into stream.c, even if it's roughly speaking its main user. At least it made its way somewhat unfortunately to other components not related to the stream or demuxer layer at all. I'm too greedy to give this weird helper its own file, so dump it into thread_tools.c. Probably a somewhat pointless change. --- player/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'player/main.c') diff --git a/player/main.c b/player/main.c index c51f93a430..6d2b862e02 100644 --- a/player/main.c +++ b/player/main.c @@ -54,7 +54,7 @@ #include "audio/out/ao.h" #include "demux/demux.h" -#include "stream/stream.h" +#include "misc/thread_tools.h" #include "sub/osd.h" #include "video/out/vo.h" -- cgit v1.2.3 From 8816e1117ee65039dbb5700219ba3537d3e5290e Mon Sep 17 00:00:00 2001 From: wm4 Date: Sat, 19 May 2018 18:25:54 +0200 Subject: player: change the role of the "stop_play" and "playing" variable Before this, mpctx->playing was often used to determine whether certain new state could be added to the playback state. In particular this affected external files (which added tracks and demuxers). The variable was checked to prevent that they were added before the corresponding uninit code. We want to make a small part of uninit asynchronous, but mpctx->playing needs to stay in the place where it is. It can't be used for this purpose anymore. Use mpctx->stop_play instead. Make it never have the value 0 outside of loading/playback. On unloading, it obviously has to be non-0. Change some other code in playloop.c to use this, because it seems slightly more correct. But mostly this is preparation for the following commit. --- player/main.c | 1 + 1 file changed, 1 insertion(+) (limited to 'player/main.c') diff --git a/player/main.c b/player/main.c index 6d2b862e02..6a7fc68004 100644 --- a/player/main.c +++ b/player/main.c @@ -283,6 +283,7 @@ struct MPContext *mp_create(void) .dispatch = mp_dispatch_create(mpctx), .playback_abort = mp_cancel_new(mpctx), .thread_pool = mp_thread_pool_create(mpctx, 0, 1, 30), + .stop_play = PT_STOP, }; pthread_mutex_init(&mpctx->abort_lock, NULL); -- cgit v1.2.3 From dbcd654e612ca32673cf2703758b05700cb87d03 Mon Sep 17 00:00:00 2001 From: wm4 Date: Sat, 19 May 2018 18:41:13 +0200 Subject: player: make playback termination asynchronous Until now, stopping playback aborted the demuxer and I/O layer violently by signaling mp_cancel (bound to libavformat's AVIOInterruptCB mechanism). Change it to try closing them gracefully. The main purpose is to silence those libavformat errors that happen when you request termination. Most of libavformat barely cares about the termination mechanism (AVIOInterruptCB), and essentially it's like the network connection is abruptly severed, or file I/O suddenly returns I/O errors. There were issues with dumb TLS warnings, parsers complaining about incomplete data, and some special protocols that require server communication to gracefully disconnect. We still want to abort it forcefully if it refuses to terminate on its own, so a timeout is required. Users can set the timeout to 0, which should give them the old behavior. This also removes the old mechanism that treats certain commands (like "quit") specially, and tries to terminate the demuxers even if the core is currently frozen. This is for situations where the core synchronized to the demuxer or stream layer while network is unresponsive. This in turn can only happen due to the "program" or "cache-size" properties in the current code (see one of the previous commits). Also, the old mechanism doesn't fit particularly well with the new one. We wouldn't want to abort playback immediately on a "quit" command - the new code is all about giving it a chance to end it gracefully. We'd need some sort of watchdog thread or something equally complicated to handle this. So just remove it. The change in osd.c is to prevent that it clears the status line while waiting for termination. The normal status line code doesn't output anything useful at this point, and the code path taken clears it, both of which is an annoying behavior change, so just let it show the old one. --- player/main.c | 8 -------- 1 file changed, 8 deletions(-) (limited to 'player/main.c') diff --git a/player/main.c b/player/main.c index 6a7fc68004..ec5cdd69b1 100644 --- a/player/main.c +++ b/player/main.c @@ -244,12 +244,6 @@ static int cfg_include(void *ctx, char *filename, int flags) return r; } -static void abort_playback_cb(void *ctx) -{ - struct MPContext *mpctx = ctx; - mp_abort_playback_async(mpctx); -} - // We mostly care about LC_NUMERIC, and how "." vs. "," is treated, // Other locale stuff might break too, but probably isn't too bad. static bool check_locale(void) @@ -320,8 +314,6 @@ struct MPContext *mp_create(void) cocoa_set_input_context(mpctx->input); #endif - mp_input_set_cancel(mpctx->input, abort_playback_cb, mpctx); - char *verbose_env = getenv("MPV_VERBOSE"); if (verbose_env) mpctx->opts->verbose = atoi(verbose_env); -- cgit v1.2.3 From fb22bf2317d4704895fca407507972031e932298 Mon Sep 17 00:00:00 2001 From: wm4 Date: Mon, 21 May 2018 15:11:19 +0200 Subject: ao: use a local option struct Instead of accessing MPOpts. --- player/main.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'player/main.c') diff --git a/player/main.c b/player/main.c index ec5cdd69b1..5870574844 100644 --- a/player/main.c +++ b/player/main.c @@ -222,7 +222,9 @@ static bool handle_help_options(struct MPContext *mpctx) MP_INFO(mpctx, "\n"); return true; } - if (opts->audio_device && strcmp(opts->audio_device, "help") == 0) { + if (opts->ao_opts->audio_device && + strcmp(opts->ao_opts->audio_device, "help") == 0) + { ao_print_devices(mpctx->global, log); return true; } -- cgit v1.2.3 From 3569857b7580f9037f5168a2e3888a86cc3a85a0 Mon Sep 17 00:00:00 2001 From: wm4 Date: Mon, 21 May 2018 15:49:19 +0200 Subject: path: don't access global option struct The path functions need to access the option that forces non-default config directories. Just add it as a field to mpv_global - it seems justified. The accessed options were always enforced as immutable after init, so there's not much of a change. --- player/main.c | 1 + 1 file changed, 1 insertion(+) (limited to 'player/main.c') diff --git a/player/main.c b/player/main.c index 5870574844..d94b61230e 100644 --- a/player/main.c +++ b/player/main.c @@ -338,6 +338,7 @@ int mp_initialize(struct MPContext *mpctx, char **options) if (options) m_config_preparse_command_line(mpctx->mconfig, mpctx->global, options); + mp_init_paths(mpctx->global, opts); mp_update_logging(mpctx, true); if (options) { -- cgit v1.2.3 From f8ab59eacdde31af39f4defeb964adf4de140a50 Mon Sep 17 00:00:00 2001 From: wm4 Date: Mon, 21 May 2018 16:25:52 +0200 Subject: player: get rid of mpv_global.opts This was always a legacy thing. Remove it by applying an orgy of mp_get_config_group() calls, and sometimes m_config_cache_alloc() or mp_read_option_raw(). win32 changes untested. --- player/main.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'player/main.c') diff --git a/player/main.c b/player/main.c index d94b61230e..0a11bcf7d2 100644 --- a/player/main.c +++ b/player/main.c @@ -117,7 +117,7 @@ void mp_update_logging(struct MPContext *mpctx, bool preinit) { bool had_log_file = mp_msg_has_log_file(mpctx->global); - mp_msg_update_msglevels(mpctx->global); + mp_msg_update_msglevels(mpctx->global, mpctx->opts); bool enable = mpctx->opts->use_terminal; bool enabled = cas_terminal_owner(mpctx, mpctx); @@ -303,8 +303,6 @@ struct MPContext *mp_create(void) m_config_parse(mpctx->mconfig, "", bstr0(def_config), NULL, 0); m_config_create_shadow(mpctx->mconfig); - mpctx->global->opts = mpctx->opts; - mpctx->input = mp_input_init(mpctx->global, mp_wakeup_core_cb, mpctx); screenshot_init(mpctx); command_init(mpctx); @@ -335,8 +333,10 @@ int mp_initialize(struct MPContext *mpctx, char **options) assert(!mpctx->initialized); // Preparse the command line, so we can init the terminal early. - if (options) - m_config_preparse_command_line(mpctx->mconfig, mpctx->global, options); + if (options) { + m_config_preparse_command_line(mpctx->mconfig, mpctx->global, + &opts->verbose, options); + } mp_init_paths(mpctx->global, opts); mp_update_logging(mpctx, true); -- cgit v1.2.3