mirror of https://github.com/mpv-player/mpv
lua: synchronously wait until scripts are loaded
This makes the player wait until each script is loaded. Do this to give the script a chance to setup all its event handlers. It might also be useful to allow a script to change options that matter for playback. While waiting for a script to be loaded, the player actually accepts input. This is needed because the scripts can execute player commands anyway while they are being "loaded". The player won't react to most commands though: it can't quit or navigate the playlist in this state. For deciding whether a script is finally loaded, we use a cheap hack: if mpv_wait_event() is called, it's considered loaded. Let's hope this is good enough. I think it's better than introducing explicit API for this. Although I'm sure this will turn out as too simplistic some time in the future, the same would probably happen with a more explicit API.
This commit is contained in:
parent
348dfd93c4
commit
017b3fa9db
|
@ -47,6 +47,15 @@ The event loop will wait for events and dispatch events registered with
|
||||||
``mp.register_event``. It will also handle timers added with ``mp.add_timeout``
|
``mp.register_event``. It will also handle timers added with ``mp.add_timeout``
|
||||||
and similar (by waiting with a timeout).
|
and similar (by waiting with a timeout).
|
||||||
|
|
||||||
|
Since mpv 0.6.0, the player will wait until the script is fully loaded before
|
||||||
|
continuing normal operation. The player considers a script as fully loaded as
|
||||||
|
soon as it starts waiting for mpv events (or it exits). In practice this means
|
||||||
|
the player will more or less hang until the script returns from the main chunk
|
||||||
|
(and ``mp_event_loop`` is called), or the script calls ``mp_event_loop`` or
|
||||||
|
``mp.dispatch_events`` directly. This is done to make it possible for a script
|
||||||
|
to fully setup event handlers etc. before playback actually starts. In older
|
||||||
|
mpv versions, this happened asynchronously.
|
||||||
|
|
||||||
mp functions
|
mp functions
|
||||||
------------
|
------------
|
||||||
|
|
||||||
|
|
|
@ -118,6 +118,7 @@ struct mpv_handle {
|
||||||
int properties_updating;
|
int properties_updating;
|
||||||
uint64_t property_event_masks; // or-ed together event masks of all properties
|
uint64_t property_event_masks; // or-ed together event masks of all properties
|
||||||
|
|
||||||
|
bool fuzzy_initialized;
|
||||||
struct mp_log_buffer *messages;
|
struct mp_log_buffer *messages;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -151,6 +152,22 @@ int mp_clients_num(struct MPContext *mpctx)
|
||||||
return num_clients;
|
return num_clients;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test for "fuzzy" initialization of all clients. That is, all clients have
|
||||||
|
// at least called mpv_wait_event() at least once since creation (or exited).
|
||||||
|
bool mp_clients_all_initialized(struct MPContext *mpctx)
|
||||||
|
{
|
||||||
|
bool all_ok = true;
|
||||||
|
pthread_mutex_lock(&mpctx->clients->lock);
|
||||||
|
for (int n = 0; n < mpctx->clients->num_clients; n++) {
|
||||||
|
struct mpv_handle *ctx = mpctx->clients->clients[n];
|
||||||
|
pthread_mutex_lock(&ctx->lock);
|
||||||
|
all_ok &= ctx->fuzzy_initialized;
|
||||||
|
pthread_mutex_unlock(&ctx->lock);
|
||||||
|
}
|
||||||
|
pthread_mutex_unlock(&mpctx->clients->lock);
|
||||||
|
return all_ok;
|
||||||
|
}
|
||||||
|
|
||||||
static void invalidate_global_event_mask(struct mpv_handle *ctx)
|
static void invalidate_global_event_mask(struct mpv_handle *ctx)
|
||||||
{
|
{
|
||||||
pthread_mutex_lock(&ctx->clients->lock);
|
pthread_mutex_lock(&ctx->clients->lock);
|
||||||
|
@ -377,6 +394,7 @@ mpv_handle *mpv_create(void)
|
||||||
mpv_handle *ctx = mp_new_client(mpctx->clients, "main");
|
mpv_handle *ctx = mp_new_client(mpctx->clients, "main");
|
||||||
if (ctx) {
|
if (ctx) {
|
||||||
ctx->owner = true;
|
ctx->owner = true;
|
||||||
|
ctx->fuzzy_initialized = true;
|
||||||
// Set some defaults.
|
// Set some defaults.
|
||||||
mpv_set_option_string(ctx, "config", "no");
|
mpv_set_option_string(ctx, "config", "no");
|
||||||
mpv_set_option_string(ctx, "idle", "yes");
|
mpv_set_option_string(ctx, "idle", "yes");
|
||||||
|
@ -599,6 +617,10 @@ mpv_event *mpv_wait_event(mpv_handle *ctx, double timeout)
|
||||||
|
|
||||||
pthread_mutex_lock(&ctx->lock);
|
pthread_mutex_lock(&ctx->lock);
|
||||||
|
|
||||||
|
if (!ctx->fuzzy_initialized && ctx->clients->mpctx->input)
|
||||||
|
mp_input_wakeup(ctx->clients->mpctx->input);
|
||||||
|
ctx->fuzzy_initialized = true;
|
||||||
|
|
||||||
if (timeout < 0)
|
if (timeout < 0)
|
||||||
timeout = 1e20;
|
timeout = 1e20;
|
||||||
if (ctx->queued_wakeup)
|
if (ctx->queued_wakeup)
|
||||||
|
|
|
@ -13,6 +13,7 @@ struct mp_log;
|
||||||
void mp_clients_init(struct MPContext *mpctx);
|
void mp_clients_init(struct MPContext *mpctx);
|
||||||
void mp_clients_destroy(struct MPContext *mpctx);
|
void mp_clients_destroy(struct MPContext *mpctx);
|
||||||
int mp_clients_num(struct MPContext *mpctx);
|
int mp_clients_num(struct MPContext *mpctx);
|
||||||
|
bool mp_clients_all_initialized(struct MPContext *mpctx);
|
||||||
|
|
||||||
void mp_client_broadcast_event(struct MPContext *mpctx, int event, void *data);
|
void mp_client_broadcast_event(struct MPContext *mpctx, int event, void *data);
|
||||||
int mp_client_send_event(struct MPContext *mpctx, const char *client_name,
|
int mp_client_send_event(struct MPContext *mpctx, const char *client_name,
|
||||||
|
|
|
@ -66,6 +66,7 @@ static char *script_name_from_filename(void *talloc_ctx, const char *fname)
|
||||||
}
|
}
|
||||||
|
|
||||||
struct thread_arg {
|
struct thread_arg {
|
||||||
|
struct mp_log *log;
|
||||||
const struct mp_scripting *backend;
|
const struct mp_scripting *backend;
|
||||||
mpv_handle *client;
|
mpv_handle *client;
|
||||||
const char *fname;
|
const char *fname;
|
||||||
|
@ -76,20 +77,25 @@ static void *script_thread(void *p)
|
||||||
pthread_detach(pthread_self());
|
pthread_detach(pthread_self());
|
||||||
|
|
||||||
struct thread_arg *arg = p;
|
struct thread_arg *arg = p;
|
||||||
struct mp_log *log = mp_client_get_log(arg->client);
|
|
||||||
|
|
||||||
mp_verbose(log, "Loading script...\n");
|
|
||||||
|
|
||||||
if (arg->backend->load(arg->client, arg->fname) < 0)
|
if (arg->backend->load(arg->client, arg->fname) < 0)
|
||||||
mp_err(log, "Could not load script %s\n", arg->fname);
|
MP_ERR(arg, "Could not load script %s\n", arg->fname);
|
||||||
|
|
||||||
mp_verbose(log, "Exiting...\n");
|
MP_VERBOSE(arg, "Exiting...\n");
|
||||||
|
|
||||||
mpv_detach_destroy(arg->client);
|
mpv_detach_destroy(arg->client);
|
||||||
talloc_free(arg);
|
talloc_free(arg);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void wait_loaded(struct MPContext *mpctx)
|
||||||
|
{
|
||||||
|
while (!mp_clients_all_initialized(mpctx)) {
|
||||||
|
mp_wait_events(mpctx, 1e9);
|
||||||
|
mp_process_input(mpctx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void mp_load_script(struct MPContext *mpctx, const char *fname)
|
static void mp_load_script(struct MPContext *mpctx, const char *fname)
|
||||||
{
|
{
|
||||||
char *ext = mp_splitext(fname, NULL);
|
char *ext = mp_splitext(fname, NULL);
|
||||||
|
@ -121,11 +127,17 @@ static void mp_load_script(struct MPContext *mpctx, const char *fname)
|
||||||
talloc_free(arg);
|
talloc_free(arg);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
arg->log = mp_client_get_log(arg->client);
|
||||||
|
|
||||||
|
MP_VERBOSE(arg, "Loading script %s...\n", fname);
|
||||||
|
|
||||||
pthread_t thread;
|
pthread_t thread;
|
||||||
if (pthread_create(&thread, NULL, script_thread, arg))
|
if (pthread_create(&thread, NULL, script_thread, arg))
|
||||||
talloc_free(arg);
|
talloc_free(arg);
|
||||||
|
|
||||||
|
wait_loaded(mpctx);
|
||||||
|
MP_VERBOSE(mpctx, "Done loading %s.\n", fname);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue