From 453fea87fa8e048b0b49eb7996c929792d7bfb40 Mon Sep 17 00:00:00 2001 From: wm4 Date: Thu, 1 Sep 2016 21:55:21 +0200 Subject: client API: create core thread at an earlier time Create the core thread right in mpv_create(), and reduce what mpv_initialize() does further. This is simpler, and allows the API user to do more before calling mpv_initialize(). The latter is not the real goal, rather we'd like mpv_intialize() reduced to do almost nothing. It still does a lot, but nothing truly special anymore that is absolutely required for basic mpv workings. One thing we want the user to be able to do is changing properties before mpv_initialize() to reduce the special status of mpv_set_option(). --- DOCS/client-api-changes.rst | 2 ++ libmpv/client.h | 2 +- player/client.c | 80 +++++++++++++++++++++------------------------ player/main.c | 21 ++++++------ 4 files changed, 50 insertions(+), 55 deletions(-) diff --git a/DOCS/client-api-changes.rst b/DOCS/client-api-changes.rst index 165218a600..d7fbfaadf6 100644 --- a/DOCS/client-api-changes.rst +++ b/DOCS/client-api-changes.rst @@ -35,6 +35,8 @@ API changes --- mpv 0.21.0 --- 1.23 - deprecate setting "no-" options via mpv_set_option*(). For example, instead of "no-video=" you should set "video=no". + - be much more permissive what API calls are allowed before + mpv_initialize(). --- mpv 0.19.0 --- 1.22 - add stream_cb API for custom protocols --- mpv 0.18.1 --- diff --git a/libmpv/client.h b/libmpv/client.h index 7ec6590e64..9b73600da2 100644 --- a/libmpv/client.h +++ b/libmpv/client.h @@ -370,7 +370,7 @@ const char *mpv_client_name(mpv_handle *ctx); * and needs to be initialized to be actually used with most other API * functions. * - * Most API functions will return MPV_ERROR_UNINITIALIZED in the uninitialized + * Some API functions will return MPV_ERROR_UNINITIALIZED in the uninitialized * state. You can call mpv_set_option() (or mpv_set_option_string() and other * variants) to set initial options. After this, call mpv_initialize() to start * the player, and then use e.g. mpv_command() to start playback of a file. diff --git a/player/client.c b/player/client.c index df3aa01739..81b94abd22 100644 --- a/player/client.c +++ b/player/client.c @@ -364,14 +364,12 @@ void mp_resume_all(mpv_handle *ctx) static void lock_core(mpv_handle *ctx) { - if (ctx->mpctx->initialized) - mp_dispatch_lock(ctx->mpctx->dispatch); + mp_dispatch_lock(ctx->mpctx->dispatch); } static void unlock_core(mpv_handle *ctx) { - if (ctx->mpctx->initialized) - mp_dispatch_unlock(ctx->mpctx->dispatch); + mp_dispatch_unlock(ctx->mpctx->dispatch); } void mpv_wait_async_requests(mpv_handle *ctx) @@ -438,7 +436,7 @@ void mpv_terminate_destroy(mpv_handle *ctx) mpv_command(ctx, (const char*[]){"quit", NULL}); - if (!ctx->owner || !ctx->mpctx->initialized) { + if (!ctx->owner) { mpv_detach_destroy(ctx); return; } @@ -458,6 +456,26 @@ void mpv_terminate_destroy(mpv_handle *ctx) pthread_join(playthread, NULL); } +static void *playback_thread(void *p) +{ + struct MPContext *mpctx = p; + mpctx->autodetach = true; + + mpthread_set_name("mpv core"); + + while (!mpctx->initialized && mpctx->stop_play != PT_QUIT) + mp_idle(mpctx); + + if (mpctx->initialized) + mp_play_files(mpctx); + + // This actually waits until all clients are gone before actually + // destroying mpctx. + mp_destroy(mpctx); + + return NULL; +} + // 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) @@ -484,6 +502,13 @@ mpv_handle *mpv_create(void) } else { mp_destroy(mpctx); } + + pthread_t thread; + if (pthread_create(&thread, NULL, playback_thread, ctx->mpctx) != 0) { + mpv_terminate_destroy(ctx); + return NULL; + } + return ctx; } @@ -491,40 +516,25 @@ mpv_handle *mpv_create_client(mpv_handle *ctx, const char *name) { if (!ctx) return mpv_create(); - if (!ctx->mpctx->initialized) - return NULL; mpv_handle *new = mp_new_client(ctx->mpctx->clients, name); if (new) mpv_wait_event(new, 0); // set fuzzy_initialized return new; } -static void *playback_thread(void *p) +static void doinit(void *ctx) { - struct MPContext *mpctx = p; - mpctx->autodetach = true; - - mpthread_set_name("playback core"); - - mp_play_files(mpctx); + void **args = ctx; - // This actually waits until all clients are gone before actually - // destroying mpctx. - mp_destroy(mpctx); - - return NULL; + *(int *)args[1] = mp_initialize(args[0], NULL); } int mpv_initialize(mpv_handle *ctx) { - if (mp_initialize(ctx->mpctx, NULL) < 0) - return MPV_ERROR_INVALID_PARAMETER; - - pthread_t thread; - if (pthread_create(&thread, NULL, playback_thread, ctx->mpctx) != 0) - return MPV_ERROR_NOMEM; - - return 0; + int res = 0; + void *args[2] = {ctx->mpctx, &res}; + mp_dispatch_run(ctx->mpctx->dispatch, doinit, args); + return res < 0 ? MPV_ERROR_INVALID_PARAMETER : 0; } // set ev->data to a new copy of the original data @@ -979,8 +989,6 @@ static void cmd_fn(void *data) static int run_client_command(mpv_handle *ctx, struct mp_cmd *cmd, mpv_node *res) { - if (!ctx->mpctx->initialized) - return MPV_ERROR_UNINITIALIZED; if (!cmd) return MPV_ERROR_INVALID_PARAMETER; @@ -1020,8 +1028,6 @@ int mpv_command_string(mpv_handle *ctx, const char *args) static int run_cmd_async(mpv_handle *ctx, uint64_t ud, struct mp_cmd *cmd) { - if (!ctx->mpctx->initialized) - return MPV_ERROR_UNINITIALIZED; if (!cmd) return MPV_ERROR_INVALID_PARAMETER; @@ -1099,8 +1105,6 @@ static void setproperty_fn(void *arg) int mpv_set_property(mpv_handle *ctx, const char *name, mpv_format format, void *data) { - if (!ctx->mpctx->initialized) - return MPV_ERROR_UNINITIALIZED; if (!get_mp_type(format)) return MPV_ERROR_PROPERTY_FORMAT; @@ -1130,8 +1134,6 @@ int mpv_set_property_async(mpv_handle *ctx, uint64_t ud, const char *name, mpv_format format, void *data) { const struct m_option *type = get_mp_type(format); - if (!ctx->mpctx->initialized) - return MPV_ERROR_UNINITIALIZED; if (!type) return MPV_ERROR_PROPERTY_FORMAT; @@ -1244,8 +1246,6 @@ static void getproperty_fn(void *arg) int mpv_get_property(mpv_handle *ctx, const char *name, mpv_format format, void *data) { - if (!ctx->mpctx->initialized) - return MPV_ERROR_UNINITIALIZED; if (!data) return MPV_ERROR_INVALID_PARAMETER; if (!get_mp_type_get(format)) @@ -1278,8 +1278,6 @@ char *mpv_get_property_osd_string(mpv_handle *ctx, const char *name) int mpv_get_property_async(mpv_handle *ctx, uint64_t ud, const char *name, mpv_format format) { - if (!ctx->mpctx->initialized) - return MPV_ERROR_UNINITIALIZED; if (!get_mp_type_get(format)) return MPV_ERROR_PROPERTY_FORMAT; @@ -1448,8 +1446,6 @@ static void update_prop(void *p) // outstanding property. static bool gen_property_change_event(struct mpv_handle *ctx) { - if (!ctx->mpctx->initialized) - return false; int start = ctx->lowest_changed; ctx->lowest_changed = ctx->num_properties; for (int n = start; n < ctx->num_properties; n++) { @@ -1715,8 +1711,6 @@ int mpv_opengl_cb_render(mpv_opengl_cb_context *ctx, int fbo, int vp[4]) void *mpv_get_sub_api(mpv_handle *ctx, mpv_sub_api sub_api) { - if (!ctx->mpctx->initialized) - return NULL; void *res = NULL; lock_core(ctx); switch (sub_api) { diff --git a/player/main.c b/player/main.c index 3faa25ecd5..6acb617520 100644 --- a/player/main.c +++ b/player/main.c @@ -323,6 +323,12 @@ static int cfg_include(void *ctx, char *filename, int flags) return r; } +void wakeup_playloop(void *ctx) +{ + struct MPContext *mpctx = ctx; + mp_input_wakeup(mpctx->input); +} + struct MPContext *mp_create(void) { mp_time_init(); @@ -366,18 +372,16 @@ struct MPContext *mp_create(void) command_init(mpctx); init_libav(mpctx->global); mp_clients_init(mpctx); + mpctx->osd = osd_create(mpctx->global); #if HAVE_COCOA cocoa_set_input_context(mpctx->input); #endif - return mpctx; -} + mp_input_set_cancel(mpctx->input, mpctx->playback_abort); + mp_dispatch_set_wakeup_fn(mpctx->dispatch, wakeup_playloop, mpctx); -void wakeup_playloop(void *ctx) -{ - struct MPContext *mpctx = ctx; - mp_input_wakeup(mpctx->input); + return mpctx; } // Finish mpctx initialization. This must be done after setting up all options. @@ -442,9 +446,6 @@ int mp_initialize(struct MPContext *mpctx, char **options) return -3; mp_input_load(mpctx->input); - mp_input_set_cancel(mpctx->input, mpctx->playback_abort); - - mp_dispatch_set_wakeup_fn(mpctx->dispatch, wakeup_playloop, mpctx); #if HAVE_ENCODING if (opts->encode_opts->file && opts->encode_opts->file[0]) { @@ -464,8 +465,6 @@ int mp_initialize(struct MPContext *mpctx, char **options) MP_WARN(mpctx, "There will be no OSD and no text subtitles.\n"); #endif - mpctx->osd = osd_create(mpctx->global); - // From this point on, all mpctx members are initialized. mpctx->initialized = true; -- cgit v1.2.3