From b8ade7c99b830ee9870040bcfc1f2c3d3a64d172 Mon Sep 17 00:00:00 2001 From: wm4 Date: Fri, 16 Sep 2016 14:23:54 +0200 Subject: [PATCH] player, ao, vo: don't call mp_input_wakeup() directly Currently, calling mp_input_wakeup() will wake up the core thread (also called the playloop). This seems odd, but currently the core indeed calls mp_input_wait() when it has nothing more to do. It's done this way because MPlayer used input_ctx as central "mainloop". This is probably going to change. Remove direct calls to this function, and replace it with mp_wakeup_core() calls. ao and vo are changed to use opaque callbacks and not use input_ctx for this purpose. Other code already uses opaque callbacks, or has legitimate reasons to use input_ctx directly (such as sending actual user input). --- audio/out/ao.c | 44 +++++++++++++++++++++++++++----------------- audio/out/ao.h | 5 +++-- audio/out/internal.h | 3 ++- audio/out/pull.c | 2 +- audio/out/push.c | 4 ++-- player/audio.c | 4 ++-- player/client.c | 7 +++---- player/command.c | 22 +++++++++++++++------- player/core.h | 2 ++ player/loadfile.c | 2 +- player/lua.c | 2 +- player/main.c | 2 +- player/misc.c | 2 +- player/playloop.c | 19 ++++++++++++++++++- player/video.c | 2 ++ video/out/vo.c | 20 ++++++++++++++------ video/out/vo.h | 2 ++ 17 files changed, 97 insertions(+), 47 deletions(-) diff --git a/audio/out/ao.c b/audio/out/ao.c index cd2b9e8089..15c0f8139e 100644 --- a/audio/out/ao.c +++ b/audio/out/ao.c @@ -28,7 +28,6 @@ #include "audio/format.h" #include "audio/audio.h" -#include "input/input.h" #include "options/options.h" #include "options/m_config.h" #include "common/msg.h" @@ -127,8 +126,11 @@ const struct m_obj_list ao_obj_list = { }; static struct ao *ao_alloc(bool probing, struct mpv_global *global, - struct input_ctx *input_ctx, char *name, char **args) + void (*wakeup_cb)(void *ctx), void *wakeup_ctx, + char *name, char **args) { + assert(wakeup_cb); + struct MPOpts *opts = global->opts; struct mp_log *log = mp_log_new(NULL, global->log, "ao"); struct m_obj_desc desc; @@ -143,7 +145,8 @@ static struct ao *ao_alloc(bool probing, struct mpv_global *global, .driver = desc.p, .probing = probing, .global = global, - .input_ctx = input_ctx, + .wakeup_cb = wakeup_cb, + .wakeup_ctx = wakeup_ctx, .log = mp_log_new(ao, log, name), .def_buffer = opts->audio_buffer, .client_name = talloc_strdup(ao, opts->audio_client_name), @@ -161,12 +164,12 @@ error: } static struct ao *ao_init(bool probing, struct mpv_global *global, - struct input_ctx *input_ctx, + void (*wakeup_cb)(void *ctx), void *wakeup_ctx, struct encode_lavc_context *encode_lavc_ctx, int flags, int samplerate, int format, struct mp_chmap channels, char *dev, char *name, char **args) { - struct ao *ao = ao_alloc(probing, global, input_ctx, name, args); + struct ao *ao = ao_alloc(probing, global, wakeup_cb, wakeup_ctx, name, args); if (!ao) return NULL; ao->samplerate = samplerate; @@ -197,8 +200,9 @@ static struct ao *ao_init(bool probing, struct mpv_global *global, snprintf(redirect, sizeof(redirect), "%s", ao->redirect); snprintf(rdevice, sizeof(rdevice), "%s", ao->device ? ao->device : ""); talloc_free(ao); - return ao_init(probing, global, input_ctx, encode_lavc_ctx, flags, - samplerate, format, channels, rdevice, redirect, NULL); + return ao_init(probing, global, wakeup_cb, wakeup_ctx, + encode_lavc_ctx, flags, samplerate, format, channels, + rdevice, redirect, NULL); } goto fail; } @@ -248,7 +252,7 @@ static void split_ao_device(void *tmp, char *opt, char **out_ao, char **out_dev) struct ao *ao_init_best(struct mpv_global *global, int init_flags, - struct input_ctx *input_ctx, + void (*wakeup_cb)(void *ctx), void *wakeup_ctx, struct encode_lavc_context *encode_lavc_ctx, int samplerate, int format, struct mp_chmap channels) { @@ -304,8 +308,8 @@ struct ao *ao_init_best(struct mpv_global *global, dev = pref_dev; mp_verbose(log, "Using preferred device '%s'\n", dev); } - ao = ao_init(probing, global, input_ctx, encode_lavc_ctx, init_flags, - samplerate, format, channels, dev, + ao = ao_init(probing, global, wakeup_cb, wakeup_ctx, encode_lavc_ctx, + init_flags, samplerate, format, channels, dev, entry->name, entry->attribs); if (ao) break; @@ -409,8 +413,7 @@ int ao_query_and_reset_events(struct ao *ao, int events) static void ao_add_events(struct ao *ao, int events) { atomic_fetch_or(&ao->events_, events); - if (ao->input_ctx) - mp_input_wakeup(ao->input_ctx); + ao->wakeup_cb(ao->wakeup_ctx); } // Request that the player core destroys and recreates the AO. Fully thread-safe. @@ -494,7 +497,8 @@ bool ao_untimed(struct ao *ao) struct ao_hotplug { struct mpv_global *global; - struct input_ctx *input_ctx; + void (*wakeup_cb)(void *ctx); + void *wakeup_ctx; // A single AO instance is used to listen to hotplug events. It wouldn't // make much sense to allow multiple AO drivers; all sane platforms have // a single such audio API. @@ -506,12 +510,14 @@ struct ao_hotplug { }; struct ao_hotplug *ao_hotplug_create(struct mpv_global *global, - struct input_ctx *input_ctx) + void (*wakeup_cb)(void *ctx), + void *wakeup_ctx) { struct ao_hotplug *hp = talloc_ptrtype(NULL, hp); *hp = (struct ao_hotplug){ .global = global, - .input_ctx = input_ctx, + .wakeup_cb = wakeup_cb, + .wakeup_ctx = wakeup_ctx, .needs_update = true, }; return hp; @@ -564,7 +570,7 @@ struct ao_device_list *ao_hotplug_get_device_list(struct ao_hotplug *hp) if (d == &audio_out_null) break; // don't add unsafe/special entries - struct ao *ao = ao_alloc(true, hp->global, hp->input_ctx, + struct ao *ao = ao_alloc(true, hp->global, hp->wakeup_cb, hp->wakeup_ctx, (char *)d->name, NULL); if (!ao) continue; @@ -605,9 +611,13 @@ void ao_hotplug_destroy(struct ao_hotplug *hp) talloc_free(hp); } +static void dummy_wakeup(void *ctx) +{ +} + void ao_print_devices(struct mpv_global *global, struct mp_log *log) { - struct ao_hotplug *hp = ao_hotplug_create(global, NULL); + struct ao_hotplug *hp = ao_hotplug_create(global, dummy_wakeup, NULL); struct ao_device_list *list = ao_hotplug_get_device_list(hp); mp_info(log, "List of detected audio devices:\n"); for (int n = 0; n < list->num_devices; n++) { diff --git a/audio/out/ao.h b/audio/out/ao.h index fe09e2750a..4a4d433c2b 100644 --- a/audio/out/ao.h +++ b/audio/out/ao.h @@ -85,7 +85,7 @@ struct mp_audio; struct ao *ao_init_best(struct mpv_global *global, int init_flags, - struct input_ctx *input_ctx, + void (*wakeup_cb)(void *ctx), void *wakeup_ctx, struct encode_lavc_context *encode_lavc_ctx, int samplerate, int format, struct mp_chmap channels); void ao_uninit(struct ao *ao); @@ -108,7 +108,8 @@ void ao_hotplug_event(struct ao *ao); struct ao_hotplug; struct ao_hotplug *ao_hotplug_create(struct mpv_global *global, - struct input_ctx *input_ctx); + void (*wakeup_cb)(void *ctx), + void *wakeup_ctx); void ao_hotplug_destroy(struct ao_hotplug *hp); bool ao_hotplug_check_update(struct ao_hotplug *hp); const char *ao_hotplug_get_detected_device(struct ao_hotplug *hp); diff --git a/audio/out/internal.h b/audio/out/internal.h index 319881b194..3ddc1becb9 100644 --- a/audio/out/internal.h +++ b/audio/out/internal.h @@ -42,7 +42,8 @@ struct ao { void *priv; struct mpv_global *global; struct encode_lavc_context *encode_lavc_ctx; - struct input_ctx *input_ctx; + void (*wakeup_cb)(void *ctx); + void *wakeup_ctx; struct mp_log *log; // Using e.g. "[ao/coreaudio]" as prefix int init_flags; // AO_INIT_* flags bool stream_silence; // if audio inactive, just play silence diff --git a/audio/out/pull.c b/audio/out/pull.c index 5dd6525fc8..44f6ab3355 100644 --- a/audio/out/pull.c +++ b/audio/out/pull.c @@ -151,7 +151,7 @@ int ao_read_data(struct ao *ao, void **data, int samples, int64_t out_time_us) end: if (need_wakeup) - mp_input_wakeup_nolock(ao->input_ctx); + ao->wakeup_cb(ao->wakeup_ctx); // pad with silence (underflow/paused/eof) for (int n = 0; n < ao->num_planes; n++) diff --git a/audio/out/push.c b/audio/out/push.c index 406b0da790..623ee6827a 100644 --- a/audio/out/push.c +++ b/audio/out/push.c @@ -305,7 +305,7 @@ static void ao_play_data(struct ao *ao) bool more = needed >= (r == space ? ao->device_buffer / 4 : 1) && !stuck && !(flags & AOPLAY_FINAL_CHUNK); if (more) - mp_input_wakeup(ao->input_ctx); // request more data + ao->wakeup_cb(ao->wakeup_ctx); // request more data MP_TRACE(ao, "in=%d flags=%d space=%d r=%d wa/pl=%d/%d needed=%d more=%d\n", max, flags, space, r, p->wait_on_ao, p->still_playing, needed, more); } @@ -347,7 +347,7 @@ static void *playthread(void *arg) } if (was_playing && !p->still_playing) - mp_input_wakeup(ao->input_ctx); + ao->wakeup_cb(ao->wakeup_ctx); pthread_cond_signal(&p->wakeup); // for draining if (p->still_playing && timeout > 0) { diff --git a/player/audio.c b/player/audio.c index 1329057033..7bcd5c87bb 100644 --- a/player/audio.c +++ b/player/audio.c @@ -397,8 +397,8 @@ static void reinit_audio_filters_and_output(struct MPContext *mpctx) mp_audio_set_channels(&afs->output, &afs->output.channels); - mpctx->ao = ao_init_best(mpctx->global, ao_flags, mpctx->input, - mpctx->encode_lavc_ctx, afs->output.rate, + mpctx->ao = ao_init_best(mpctx->global, ao_flags, mp_wakeup_core_cb, + mpctx, mpctx->encode_lavc_ctx, afs->output.rate, afs->output.format, afs->output.channels); ao_c->ao = mpctx->ao; diff --git a/player/client.c b/player/client.c index 803ef36fca..807fab5df6 100644 --- a/player/client.c +++ b/player/client.c @@ -424,8 +424,7 @@ void mpv_detach_destroy(mpv_handle *ctx) ctx = NULL; // shutdown_clients() sleeps to avoid wasting CPU. // mp_hook_test_completion() also relies on this a bit. - if (clients->mpctx->input) - mp_input_wakeup(clients->mpctx->input); + mp_wakeup_core(clients->mpctx); break; } } @@ -759,8 +758,8 @@ mpv_event *mpv_wait_event(mpv_handle *ctx, double timeout) pthread_mutex_lock(&ctx->lock); - if (!ctx->fuzzy_initialized && ctx->clients->mpctx->input) - mp_input_wakeup(ctx->clients->mpctx->input); + if (!ctx->fuzzy_initialized) + mp_wakeup_core(ctx->clients->mpctx); ctx->fuzzy_initialized = true; if (timeout < 0) diff --git a/player/command.c b/player/command.c index 1b7f9eb088..bc103d0c6b 100644 --- a/player/command.c +++ b/player/command.c @@ -190,7 +190,7 @@ void mp_hook_run(struct MPContext *mpctx, char *client, char *type) next->active = true; if (!send_hook_msg(mpctx, next, "hook_run")) { hook_remove(mpctx, index); - mp_input_wakeup(mpctx->input); // repeat next iteration to finish + mp_wakeup_core(mpctx); // repeat next iteration to finish } } @@ -1742,14 +1742,24 @@ static void reload_audio_output(struct MPContext *mpctx) ao_request_reload(mpctx->ao); } +static void create_hotplug(struct MPContext *mpctx) +{ + struct command_ctx *cmd = mpctx->command_ctx; + + if (!cmd->hotplug) { + cmd->hotplug = ao_hotplug_create(mpctx->global, mp_wakeup_core_cb, + mpctx); + } +} + static int mp_property_audio_device(void *ctx, struct m_property *prop, int action, void *arg) { struct MPContext *mpctx = ctx; struct command_ctx *cmd = mpctx->command_ctx; if (action == M_PROPERTY_PRINT) { - if (!cmd->hotplug) - cmd->hotplug = ao_hotplug_create(mpctx->global, mpctx->input); + create_hotplug(mpctx); + struct ao_device_list *list = ao_hotplug_get_device_list(cmd->hotplug); for (int n = 0; n < list->num_devices; n++) { struct ao_device_desc *dev = &list->devices[n]; @@ -1770,8 +1780,7 @@ static int mp_property_audio_devices(void *ctx, struct m_property *prop, { struct MPContext *mpctx = ctx; struct command_ctx *cmd = mpctx->command_ctx; - if (!cmd->hotplug) - cmd->hotplug = ao_hotplug_create(mpctx->global, mpctx->input); + create_hotplug(mpctx); struct ao_device_list *list = ao_hotplug_get_device_list(cmd->hotplug); return m_property_read_list(action, arg, list->num_devices, @@ -1790,8 +1799,7 @@ static int mp_property_ao_detected_device(void *ctx,struct m_property *prop, { struct MPContext *mpctx = ctx; struct command_ctx *cmd = mpctx->command_ctx; - if (!cmd->hotplug) - cmd->hotplug = ao_hotplug_create(mpctx->global, mpctx->input); + create_hotplug(mpctx); const char *d = ao_hotplug_get_detected_device(cmd->hotplug); return m_property_strdup_ro(action, arg, d); diff --git a/player/core.h b/player/core.h index 0ffb47404c..3fa2c102b4 100644 --- a/player/core.h +++ b/player/core.h @@ -511,6 +511,8 @@ void set_osd_bar_chapters(struct MPContext *mpctx, int type); // playloop.c void mp_wait_events(struct MPContext *mpctx, double sleeptime); +void mp_wakeup_core(struct MPContext *mpctx); +void mp_wakeup_core_cb(void *ctx); void mp_process_input(struct MPContext *mpctx); double get_relative_time(struct MPContext *mpctx); void reset_playback_state(struct MPContext *mpctx); diff --git a/player/loadfile.c b/player/loadfile.c index ebead19e4e..e89047f0aa 100644 --- a/player/loadfile.c +++ b/player/loadfile.c @@ -204,7 +204,7 @@ void reselect_demux_stream(struct MPContext *mpctx, struct track *track) static void wakeup_demux(void *pctx) { struct MPContext *mpctx = pctx; - mp_input_wakeup(mpctx->input); + mp_wakeup_core(mpctx); } static void enable_demux_thread(struct MPContext *mpctx, struct demuxer *demux) diff --git a/player/lua.c b/player/lua.c index 84d7295640..b805a34ca8 100644 --- a/player/lua.c +++ b/player/lua.c @@ -971,7 +971,7 @@ static int script_set_osd_ass(lua_State *L) if (!text[0]) text = " "; // force external OSD initialization osd_set_external(ctx->mpctx->osd, ctx->client, res_x, res_y, (char *)text); - mp_input_wakeup(ctx->mpctx->input); + mp_wakeup_core(ctx->mpctx); return 0; } diff --git a/player/main.c b/player/main.c index b3a08082d8..7d2aa399ea 100644 --- a/player/main.c +++ b/player/main.c @@ -306,7 +306,7 @@ static int cfg_include(void *ctx, char *filename, int flags) void wakeup_playloop(void *ctx) { struct MPContext *mpctx = ctx; - mp_input_wakeup(mpctx->input); + mp_wakeup_core(mpctx); } struct MPContext *mp_create(void) diff --git a/player/misc.c b/player/misc.c index 17232ff828..65aad50de7 100644 --- a/player/misc.c +++ b/player/misc.c @@ -267,7 +267,7 @@ static void *thread_wrapper(void *pctx) pthread_mutex_lock(&args->mutex); args->done = true; pthread_mutex_unlock(&args->mutex); - mp_input_wakeup(args->mpctx->input); // this interrupts mp_idle() + mp_wakeup_core(args->mpctx); // this interrupts mp_idle() return NULL; } diff --git a/player/playloop.c b/player/playloop.c index 449813c777..f2f421021d 100644 --- a/player/playloop.c +++ b/player/playloop.c @@ -50,13 +50,28 @@ #include "client.h" #include "command.h" -// Wait until mp_input_wakeup(mpctx->input) is called, since the last time +// Wait until mp_wakeup_core() is called, since the last time // mp_wait_events() was called. (But see mp_process_input().) void mp_wait_events(struct MPContext *mpctx, double sleeptime) { mp_input_wait(mpctx->input, sleeptime); } +// Cause the playloop to run. This can be called from any thread. If called +// from within the playloop itself, it will be run immediately again, instead +// of going to sleep in the next mp_wait_events(). +void mp_wakeup_core(struct MPContext *mpctx) +{ + mp_input_wakeup(mpctx->input); +} + +// Opaque callback variant of mp_wakeup_core(). +void mp_wakeup_core_cb(void *ctx) +{ + struct MPContext *mpctx = ctx; + mp_wakeup_core(mpctx); +} + // Process any queued input, whether it's user input, or requests from client // API threads. This also resets the "wakeup" flag used with mp_wait_events(). void mp_process_input(struct MPContext *mpctx) @@ -816,6 +831,8 @@ int handle_force_window(struct MPContext *mpctx, bool force) .osd = mpctx->osd, .encode_lavc_ctx = mpctx->encode_lavc_ctx, .opengl_cb_context = mpctx->gl_cb_ctx, + .wakeup_cb = mp_wakeup_core_cb, + .wakeup_ctx = mpctx, }; mpctx->video_out = init_best_video_out(mpctx->global, &ex); if (!mpctx->video_out) diff --git a/player/video.c b/player/video.c index 5e87564690..e66426f24d 100644 --- a/player/video.c +++ b/player/video.c @@ -466,6 +466,8 @@ int reinit_video_chain_src(struct MPContext *mpctx, struct lavfi_pad *src) .osd = mpctx->osd, .encode_lavc_ctx = mpctx->encode_lavc_ctx, .opengl_cb_context = mpctx->gl_cb_ctx, + .wakeup_cb = mp_wakeup_core_cb, + .wakeup_ctx = mpctx, }; mpctx->video_out = init_best_video_out(mpctx->global, &ex); if (!mpctx->video_out) { diff --git a/video/out/vo.c b/video/out/vo.c index 8c66b0dab3..b9d9bcd4f2 100644 --- a/video/out/vo.c +++ b/video/out/vo.c @@ -213,6 +213,8 @@ static void dealloc_vo(struct vo *vo) static struct vo *vo_create(bool probing, struct mpv_global *global, struct vo_extra *ex, char *name, char **args) { + assert(ex->wakeup_cb); + struct mp_log *log = mp_log_new(NULL, global->log, "vo"); struct m_obj_desc desc; if (!m_obj_list_find(&desc, &vo_obj_list, bstr0(name))) { @@ -313,6 +315,12 @@ void vo_destroy(struct vo *vo) dealloc_vo(vo); } +// Wakeup the playloop to queue new video frames etc. +static void wakeup_core(struct vo *vo) +{ + vo->extra.wakeup_cb(vo->extra.wakeup_ctx); +} + // Drop timing information on discontinuities like seeking. // Always called locked. static void reset_vsync_timings(struct vo *vo) @@ -477,7 +485,7 @@ static void update_display_fps(struct vo *vo) // make sure to update the player in->queued_events |= VO_EVENT_WIN_STATE; - mp_input_wakeup(vo->input_ctx); + wakeup_core(vo); } in->nominal_vsync_interval = in->display_fps > 0 ? 1e6 / in->display_fps : 0; @@ -795,7 +803,7 @@ static bool render_frame(struct vo *vo) in->hasframe_rendered = true; int64_t prev_drop_count = vo->in->drop_count; pthread_mutex_unlock(&in->lock); - mp_input_wakeup(vo->input_ctx); // core can queue new video now + wakeup_core(vo); // core can queue new video now MP_STATS(vo, "start video"); @@ -826,7 +834,7 @@ static bool render_frame(struct vo *vo) } pthread_cond_broadcast(&in->wakeup); // for vo_wait_frame() - mp_input_wakeup(vo->input_ctx); + wakeup_core(vo); got_frame = true; @@ -906,12 +914,12 @@ static void *vo_thread(void *ptr) wait_until = MPMIN(wait_until, in->wakeup_pts); } else { in->wakeup_pts = 0; - mp_input_wakeup(vo->input_ctx); + wakeup_core(vo); } } if (vo->want_redraw && !in->want_redraw) { in->want_redraw = true; - mp_input_wakeup(vo->input_ctx); + wakeup_core(vo); } bool redraw = in->request_redraw; bool send_reset = in->send_reset; @@ -1159,7 +1167,7 @@ void vo_event(struct vo *vo, int event) struct vo_internal *in = vo->in; pthread_mutex_lock(&in->lock); if ((in->queued_events & event & VO_EVENTS_USER) != (event & VO_EVENTS_USER)) - mp_input_wakeup(vo->input_ctx); + wakeup_core(vo); if (event) wakeup_locked(vo); in->queued_events |= event; diff --git a/video/out/vo.h b/video/out/vo.h index c40367d406..e35085c49b 100644 --- a/video/out/vo.h +++ b/video/out/vo.h @@ -169,6 +169,8 @@ struct vo_extra { struct osd_state *osd; struct encode_lavc_context *encode_lavc_ctx; struct mpv_opengl_cb_context *opengl_cb_context; + void (*wakeup_cb)(void *ctx); + void *wakeup_ctx; }; struct vo_frame {