mirror of
https://github.com/mpv-player/mpv
synced 2025-01-31 04:02:06 +00:00
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().
This commit is contained in:
parent
1393d79417
commit
453fea87fa
@ -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 ---
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
void **args = ctx;
|
||||
|
||||
mpthread_set_name("playback core");
|
||||
|
||||
mp_play_files(mpctx);
|
||||
|
||||
// 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) {
|
||||
|
@ -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;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user