diff --git a/input/input.c b/input/input.c index 9525dbcbb1..f0f9f64e9b 100644 --- a/input/input.c +++ b/input/input.c @@ -144,7 +144,8 @@ struct input_ctx { struct cmd_queue cmd_queue; - struct mp_cancel *cancel; + void (*cancel)(void *cancel_ctx); + void *cancel_ctx; void (*wakeup_cb)(void *ctx); void *wakeup_ctx; @@ -809,7 +810,7 @@ int mp_input_queue_cmd(struct input_ctx *ictx, mp_cmd_t *cmd) input_lock(ictx); if (cmd) { if (ictx->cancel && test_abort_cmd(ictx, cmd)) - mp_cancel_trigger(ictx->cancel); + ictx->cancel(ictx->cancel_ctx); queue_add_tail(&ictx->cmd_queue, cmd); mp_input_wakeup(ictx); } @@ -1335,10 +1336,11 @@ void mp_input_uninit(struct input_ctx *ictx) talloc_free(ictx); } -void mp_input_set_cancel(struct input_ctx *ictx, struct mp_cancel *cancel) +void mp_input_set_cancel(struct input_ctx *ictx, void (*cb)(void *c), void *c) { input_lock(ictx); - ictx->cancel = cancel; + ictx->cancel = cb; + ictx->cancel_ctx = c; input_unlock(ictx); } diff --git a/input/input.h b/input/input.h index 5b5edd580d..fb928e0808 100644 --- a/input/input.h +++ b/input/input.h @@ -242,8 +242,7 @@ void mp_input_wakeup(struct input_ctx *ictx); // Used to asynchronously abort playback. Needed because the core still can // block on network in some situations. -struct mp_cancel; -void mp_input_set_cancel(struct input_ctx *ictx, struct mp_cancel *cancel); +void mp_input_set_cancel(struct input_ctx *ictx, void (*cb)(void *c), void *c); // If this returns true, use Right Alt key as Alt Gr to produce special // characters. If false, count Right Alt as the modifier Alt key. diff --git a/player/client.c b/player/client.c index 88926f3544..31a55332d2 100644 --- a/player/client.c +++ b/player/client.c @@ -982,7 +982,7 @@ static int run_client_command(mpv_handle *ctx, struct mp_cmd *cmd, mpv_node *res return MPV_ERROR_INVALID_PARAMETER; if (mp_input_is_abort_cmd(cmd)) - mp_cancel_trigger(ctx->mpctx->playback_abort); + mp_abort_playback_async(ctx->mpctx); cmd->sender = ctx->name; diff --git a/player/core.h b/player/core.h index d7ff507524..ad61500741 100644 --- a/player/core.h +++ b/player/core.h @@ -430,6 +430,11 @@ typedef struct MPContext { struct mp_ipc_ctx *ipc_ctx; struct mpv_opengl_cb_context *gl_cb_ctx; + + pthread_mutex_t lock; + + // --- The following fields are protected by lock + struct mp_cancel *demuxer_cancel; // cancel handle for MPContext.demuxer } MPContext; // audio.c @@ -460,6 +465,7 @@ struct playlist_entry *mp_check_playlist_resume(struct MPContext *mpctx, struct playlist *playlist); // loadfile.c +void mp_abort_playback_async(struct MPContext *mpctx); void uninit_player(struct MPContext *mpctx, unsigned int mask); struct track *mp_add_external_file(struct MPContext *mpctx, char *filename, enum stream_type filter); diff --git a/player/loadfile.c b/player/loadfile.c index 872db20399..e59acbc8d4 100644 --- a/player/loadfile.c +++ b/player/loadfile.c @@ -57,6 +57,17 @@ #include "command.h" #include "libmpv/client.h" +// Called by foreign threads when playback should be stopped and such. +void mp_abort_playback_async(struct MPContext *mpctx) +{ + mp_cancel_trigger(mpctx->playback_abort); + + pthread_mutex_lock(&mpctx->lock); + if (mpctx->demuxer_cancel) + mp_cancel_trigger(mpctx->demuxer_cancel); + pthread_mutex_unlock(&mpctx->lock); +} + static void uninit_demuxer(struct MPContext *mpctx) { for (int r = 0; r < NUM_PTRACKS; r++) { @@ -80,6 +91,11 @@ static void uninit_demuxer(struct MPContext *mpctx) free_demuxer_and_stream(mpctx->demuxer); mpctx->demuxer = NULL; + + pthread_mutex_lock(&mpctx->lock); + talloc_free(mpctx->demuxer_cancel); + mpctx->demuxer_cancel = NULL; + pthread_mutex_unlock(&mpctx->lock); } #define APPEND(s, ...) mp_snprintf_cat(s, sizeof(s), __VA_ARGS__) @@ -808,11 +824,14 @@ static void open_demux_reentrant(struct MPContext *mpctx) { struct demux_open_args args = { .global = mpctx->global, - .cancel = mpctx->playback_abort, + .cancel = mp_cancel_new(NULL), .log = mpctx->log, .stream_flags = mpctx->playing->stream_flags, .url = talloc_strdup(NULL, mpctx->stream_open_filename), }; + pthread_mutex_lock(&mpctx->lock); + mpctx->demuxer_cancel = args.cancel; + pthread_mutex_unlock(&mpctx->lock); if (mpctx->opts->load_unsafe_playlists) args.stream_flags = 0; mpctx_run_reentrant(mpctx, open_demux_thread, &args); @@ -820,6 +839,10 @@ static void open_demux_reentrant(struct MPContext *mpctx) mpctx->demuxer = args.demux; } else { mpctx->error_playing = args.err; + pthread_mutex_lock(&mpctx->lock); + talloc_free(mpctx->demuxer_cancel); + mpctx->demuxer_cancel = NULL; + pthread_mutex_unlock(&mpctx->lock); } talloc_free(args.url); } @@ -1170,7 +1193,7 @@ terminate_playback: if (mpctx->step_frames) opts->pause = 1; - mp_cancel_trigger(mpctx->playback_abort); + mp_abort_playback_async(mpctx); // time to uninit all, except global stuff: uninit_complex_filters(mpctx); diff --git a/player/main.c b/player/main.c index 3a07e0f539..8f54b98728 100644 --- a/player/main.c +++ b/player/main.c @@ -311,6 +311,12 @@ 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); +} + struct MPContext *mp_create(void) { char *enable_talloc = getenv("MPV_LEAK_REPORT"); @@ -361,7 +367,7 @@ struct MPContext *mp_create(void) cocoa_set_input_context(mpctx->input); #endif - mp_input_set_cancel(mpctx->input, mpctx->playback_abort); + mp_input_set_cancel(mpctx->input, abort_playback_cb, mpctx); char *verbose_env = getenv("MPV_VERBOSE"); if (verbose_env) diff --git a/player/misc.c b/player/misc.c index eb4c1c031e..032342e84a 100644 --- a/player/misc.c +++ b/player/misc.c @@ -287,7 +287,7 @@ int mpctx_run_reentrant(struct MPContext *mpctx, void (*thread_fn)(void *arg), mp_idle(mpctx); if (mpctx->stop_play) - mp_cancel_trigger(mpctx->playback_abort); + mp_abort_playback_async(mpctx); pthread_mutex_lock(&args.mutex); success |= args.done;