diff options
Diffstat (limited to 'player/client.c')
-rw-r--r-- | player/client.c | 433 |
1 files changed, 157 insertions, 276 deletions
diff --git a/player/client.c b/player/client.c index 0babacf147..5087f89885 100644 --- a/player/client.c +++ b/player/client.c @@ -13,14 +13,15 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include <assert.h> +#include <errno.h> +#include <fcntl.h> +#include <math.h> +#include <stdatomic.h> #include <stddef.h> #include <stdint.h> #include <stdlib.h> #include <unistd.h> -#include <fcntl.h> -#include <errno.h> -#include <math.h> -#include <assert.h> #include "common/common.h" #include "common/global.h" @@ -39,7 +40,6 @@ #include "options/m_property.h" #include "options/path.h" #include "options/parse_configfile.h" -#include "osdep/atomic.h" #include "osdep/threads.h" #include "osdep/timer.h" #include "osdep/io.h" @@ -64,7 +64,7 @@ struct mp_client_api { struct MPContext *mpctx; - pthread_mutex_t lock; + mp_mutex lock; // -- protected by lock @@ -83,7 +83,6 @@ struct mp_client_api { int num_custom_protocols; struct mpv_render_context *render_context; - struct mpv_opengl_cb_context *gl_cb_ctx; }; struct observe_property { @@ -107,7 +106,7 @@ struct observe_property { }; struct mpv_handle { - // -- immmutable + // -- immutable char name[MAX_CLIENT_NAME]; struct mp_log *log; struct MPContext *mpctx; @@ -119,10 +118,10 @@ struct mpv_handle { struct mpv_event_property cur_property_event; struct observe_property *cur_property; - pthread_mutex_t lock; + mp_mutex lock; - pthread_mutex_t wakeup_lock; - pthread_cond_t wakeup; + mp_mutex wakeup_lock; + mp_cond wakeup; // -- protected by wakeup_lock bool need_wakeup; @@ -186,7 +185,7 @@ void mp_clients_init(struct MPContext *mpctx) .mpctx = mpctx, }; mpctx->global->client_api = mpctx->clients; - pthread_mutex_init(&mpctx->clients->lock, NULL); + mp_mutex_init(&mpctx->clients->lock); } void mp_clients_destroy(struct MPContext *mpctx) @@ -195,8 +194,6 @@ void mp_clients_destroy(struct MPContext *mpctx) return; assert(mpctx->clients->num_clients == 0); - TA_FREEP(&mpctx->clients->gl_cb_ctx); - // The API user is supposed to call mpv_render_context_free(). It's simply // not allowed not to do this. if (mpctx->clients->render_context) { @@ -204,7 +201,7 @@ void mp_clients_destroy(struct MPContext *mpctx) abort(); } - pthread_mutex_destroy(&mpctx->clients->lock); + mp_mutex_destroy(&mpctx->clients->lock); talloc_free(mpctx->clients); mpctx->clients = NULL; } @@ -214,14 +211,14 @@ void mp_clients_destroy(struct MPContext *mpctx) bool mp_clients_all_initialized(struct MPContext *mpctx) { bool all_ok = true; - pthread_mutex_lock(&mpctx->clients->lock); + mp_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); + mp_mutex_lock(&ctx->lock); all_ok &= ctx->fuzzy_initialized; - pthread_mutex_unlock(&ctx->lock); + mp_mutex_unlock(&ctx->lock); } - pthread_mutex_unlock(&mpctx->clients->lock); + mp_mutex_unlock(&mpctx->clients->lock); return all_ok; } @@ -256,15 +253,15 @@ static struct mpv_handle *find_client(struct mp_client_api *clients, bool mp_client_id_exists(struct MPContext *mpctx, int64_t id) { - pthread_mutex_lock(&mpctx->clients->lock); + mp_mutex_lock(&mpctx->clients->lock); bool r = find_client_id(mpctx->clients, id); - pthread_mutex_unlock(&mpctx->clients->lock); + mp_mutex_unlock(&mpctx->clients->lock); return r; } struct mpv_handle *mp_new_client(struct mp_client_api *clients, const char *name) { - pthread_mutex_lock(&clients->lock); + mp_mutex_lock(&clients->lock); char nname[MAX_CLIENT_NAME]; for (int n = 1; n < 1000; n++) { @@ -281,7 +278,7 @@ struct mpv_handle *mp_new_client(struct mp_client_api *clients, const char *name } if (!nname[0] || clients->shutting_down) { - pthread_mutex_unlock(&clients->lock); + mp_mutex_unlock(&clients->lock); return NULL; } @@ -299,9 +296,9 @@ struct mpv_handle *mp_new_client(struct mp_client_api *clients, const char *name .event_mask = (1ULL << INTERNAL_EVENT_BASE) - 1, // exclude internal events .wakeup_pipe = {-1, -1}, }; - pthread_mutex_init(&client->lock, NULL); - pthread_mutex_init(&client->wakeup_lock, NULL); - pthread_cond_init(&client->wakeup, NULL); + mp_mutex_init(&client->lock); + mp_mutex_init(&client->wakeup_lock); + mp_cond_init(&client->wakeup); snprintf(client->name, sizeof(client->name), "%s", nname); @@ -311,7 +308,7 @@ struct mpv_handle *mp_new_client(struct mp_client_api *clients, const char *name if (clients->num_clients == 1 && !clients->mpctx->is_cli) client->fuzzy_initialized = true; - pthread_mutex_unlock(&clients->lock); + mp_mutex_unlock(&clients->lock); mpv_request_event(client, MPV_EVENT_TICK, 0); @@ -320,9 +317,9 @@ struct mpv_handle *mp_new_client(struct mp_client_api *clients, const char *name void mp_client_set_weak(struct mpv_handle *ctx) { - pthread_mutex_lock(&ctx->lock); + mp_mutex_lock(&ctx->lock); ctx->is_weak = true; - pthread_mutex_unlock(&ctx->lock); + mp_mutex_unlock(&ctx->lock); } const char *mpv_client_name(mpv_handle *ctx) @@ -347,52 +344,41 @@ struct mpv_global *mp_client_get_global(struct mpv_handle *ctx) static void wakeup_client(struct mpv_handle *ctx) { - pthread_mutex_lock(&ctx->wakeup_lock); + mp_mutex_lock(&ctx->wakeup_lock); if (!ctx->need_wakeup) { ctx->need_wakeup = true; - pthread_cond_broadcast(&ctx->wakeup); + mp_cond_broadcast(&ctx->wakeup); if (ctx->wakeup_cb) ctx->wakeup_cb(ctx->wakeup_cb_ctx); if (ctx->wakeup_pipe[0] != -1) (void)write(ctx->wakeup_pipe[1], &(char){0}, 1); } - pthread_mutex_unlock(&ctx->wakeup_lock); + mp_mutex_unlock(&ctx->wakeup_lock); } // Note: the caller has to deal with sporadic wakeups. static int wait_wakeup(struct mpv_handle *ctx, int64_t end) { int r = 0; - pthread_mutex_unlock(&ctx->lock); - pthread_mutex_lock(&ctx->wakeup_lock); - if (!ctx->need_wakeup) { - struct timespec ts = mp_time_us_to_timespec(end); - r = pthread_cond_timedwait(&ctx->wakeup, &ctx->wakeup_lock, &ts); - } + mp_mutex_unlock(&ctx->lock); + mp_mutex_lock(&ctx->wakeup_lock); + if (!ctx->need_wakeup) + r = mp_cond_timedwait_until(&ctx->wakeup, &ctx->wakeup_lock, end); if (r == 0) ctx->need_wakeup = false; - pthread_mutex_unlock(&ctx->wakeup_lock); - pthread_mutex_lock(&ctx->lock); + mp_mutex_unlock(&ctx->wakeup_lock); + mp_mutex_lock(&ctx->lock); return r; } void mpv_set_wakeup_callback(mpv_handle *ctx, void (*cb)(void *d), void *d) { - pthread_mutex_lock(&ctx->wakeup_lock); + mp_mutex_lock(&ctx->wakeup_lock); ctx->wakeup_cb = cb; ctx->wakeup_cb_ctx = d; if (ctx->wakeup_cb) ctx->wakeup_cb(ctx->wakeup_cb_ctx); - pthread_mutex_unlock(&ctx->wakeup_lock); -} - -void mpv_suspend(mpv_handle *ctx) -{ - MP_ERR(ctx, "mpv_suspend() is deprecated and does nothing.\n"); -} - -void mpv_resume(mpv_handle *ctx) -{ + mp_mutex_unlock(&ctx->wakeup_lock); } static void lock_core(mpv_handle *ctx) @@ -407,10 +393,10 @@ static void unlock_core(mpv_handle *ctx) void mpv_wait_async_requests(mpv_handle *ctx) { - pthread_mutex_lock(&ctx->lock); + mp_mutex_lock(&ctx->lock); while (ctx->reserved_events || ctx->async_counter) wait_wakeup(ctx, INT64_MAX); - pthread_mutex_unlock(&ctx->lock); + mp_mutex_unlock(&ctx->lock); } // Send abort signal to all matching work items. @@ -419,7 +405,7 @@ void mpv_wait_async_requests(mpv_handle *ctx) static void abort_async(struct MPContext *mpctx, mpv_handle *ctx, int type, uint64_t id) { - pthread_mutex_lock(&mpctx->abort_lock); + mp_mutex_lock(&mpctx->abort_lock); // Destroy all => ensure any newly appearing work is aborted immediately. if (ctx == NULL) @@ -434,12 +420,12 @@ static void abort_async(struct MPContext *mpctx, mpv_handle *ctx, } } - pthread_mutex_unlock(&mpctx->abort_lock); + mp_mutex_unlock(&mpctx->abort_lock); } -static void get_thread(void *ptr) +static void get_thread_id(void *ptr) { - *(pthread_t *)ptr = pthread_self(); + *(mp_thread_id *)ptr = mp_thread_current_id(); } static void mp_destroy_client(mpv_handle *ctx, bool terminate) @@ -455,7 +441,7 @@ static void mp_destroy_client(mpv_handle *ctx, bool terminate) if (terminate) mpv_command(ctx, (const char*[]){"quit", NULL}); - pthread_mutex_lock(&ctx->lock); + mp_mutex_lock(&ctx->lock); ctx->destroying = true; @@ -467,7 +453,7 @@ static void mp_destroy_client(mpv_handle *ctx, bool terminate) prop_unref(ctx->cur_property); ctx->cur_property = NULL; - pthread_mutex_unlock(&ctx->lock); + mp_mutex_unlock(&ctx->lock); abort_async(mpctx, ctx, 0, 0); @@ -479,7 +465,7 @@ static void mp_destroy_client(mpv_handle *ctx, bool terminate) osd_set_external_remove_owner(mpctx->osd, ctx); mp_input_remove_sections_by_owner(mpctx->input, ctx->name); - pthread_mutex_lock(&clients->lock); + mp_mutex_lock(&clients->lock); for (int n = 0; n < clients->num_clients; n++) { if (clients->clients[n] == ctx) { @@ -491,9 +477,9 @@ static void mp_destroy_client(mpv_handle *ctx, bool terminate) ctx->num_events--; } mp_msg_log_buffer_destroy(ctx->messages); - pthread_cond_destroy(&ctx->wakeup); - pthread_mutex_destroy(&ctx->wakeup_lock); - pthread_mutex_destroy(&ctx->lock); + mp_cond_destroy(&ctx->wakeup); + mp_mutex_destroy(&ctx->wakeup_lock); + mp_mutex_destroy(&ctx->lock); if (ctx->wakeup_pipe[0] != -1) { close(ctx->wakeup_pipe[0]); close(ctx->wakeup_pipe[1]); @@ -525,7 +511,7 @@ static void mp_destroy_client(mpv_handle *ctx, bool terminate) // mp_hook_test_completion() also relies on this a bit. mp_wakeup_core(mpctx); - pthread_mutex_unlock(&clients->lock); + mp_mutex_unlock(&clients->lock); // Note that even if num_clients==0, having set have_terminator keeps mpctx // and the core thread alive. @@ -536,17 +522,17 @@ static void mp_destroy_client(mpv_handle *ctx, bool terminate) mpctx->stop_play = PT_QUIT; mp_dispatch_unlock(mpctx->dispatch); - pthread_t playthread; - mp_dispatch_run(mpctx->dispatch, get_thread, &playthread); + mp_thread_id playthread; + mp_dispatch_run(mpctx->dispatch, get_thread_id, &playthread); // Ask the core thread to stop. - pthread_mutex_lock(&clients->lock); + mp_mutex_lock(&clients->lock); clients->terminate_core_thread = true; - pthread_mutex_unlock(&clients->lock); + mp_mutex_unlock(&clients->lock); mp_wakeup_core(mpctx); // Blocking wait for all clients and core thread to terminate. - pthread_join(playthread, NULL); + mp_thread_join_id(playthread); mp_destroy(mpctx); } @@ -557,11 +543,6 @@ void mpv_destroy(mpv_handle *ctx) mp_destroy_client(ctx, false); } -void mpv_detach_destroy(mpv_handle *ctx) -{ - mpv_destroy(ctx); -} - void mpv_terminate_destroy(mpv_handle *ctx) { mp_destroy_client(ctx, true); @@ -576,7 +557,7 @@ void mp_shutdown_clients(struct MPContext *mpctx) // Forcefully abort async work after 2 seconds of waiting. double abort_time = mp_time_sec() + 2; - pthread_mutex_lock(&clients->lock); + mp_mutex_lock(&clients->lock); // Prevent that new clients can appear. clients->shutting_down = true; @@ -585,7 +566,7 @@ void mp_shutdown_clients(struct MPContext *mpctx) while (clients->num_clients || mpctx->outstanding_async || !(mpctx->is_cli || clients->terminate_core_thread)) { - pthread_mutex_unlock(&clients->lock); + mp_mutex_unlock(&clients->lock); double left = abort_time - mp_time_sec(); if (left >= 0) { @@ -600,26 +581,26 @@ void mp_shutdown_clients(struct MPContext *mpctx) mp_client_broadcast_event(mpctx, MPV_EVENT_SHUTDOWN, NULL); mp_wait_events(mpctx); - pthread_mutex_lock(&clients->lock); + mp_mutex_lock(&clients->lock); } - pthread_mutex_unlock(&clients->lock); + mp_mutex_unlock(&clients->lock); } bool mp_is_shutting_down(struct MPContext *mpctx) { struct mp_client_api *clients = mpctx->clients; - pthread_mutex_lock(&clients->lock); + mp_mutex_lock(&clients->lock); bool res = clients->shutting_down; - pthread_mutex_unlock(&clients->lock); + mp_mutex_unlock(&clients->lock); return res; } -static void *core_thread(void *p) +static MP_THREAD_VOID core_thread(void *p) { struct MPContext *mpctx = p; - mpthread_set_name("mpv core"); + mp_thread_set_name("core"); while (!mpctx->initialized && mpctx->stop_play != PT_QUIT) mp_idle(mpctx); @@ -632,7 +613,7 @@ static void *core_thread(void *p) // the last mpv_handle. mp_shutdown_clients(mpctx); - return NULL; + MP_THREAD_RETURN(); } mpv_handle *mpv_create(void) @@ -649,8 +630,8 @@ mpv_handle *mpv_create(void) return NULL; } - pthread_t thread; - if (pthread_create(&thread, NULL, core_thread, mpctx) != 0) { + mp_thread thread; + if (mp_thread_create(&thread, core_thread, mpctx) != 0) { ctx->clients->have_terminator = true; // avoid blocking mpv_terminate_destroy(ctx); mp_destroy(mpctx); @@ -723,13 +704,13 @@ static void dup_event_data(struct mpv_event *ev) static int reserve_reply(struct mpv_handle *ctx) { int res = MPV_ERROR_EVENT_QUEUE_FULL; - pthread_mutex_lock(&ctx->lock); + mp_mutex_lock(&ctx->lock); if (ctx->reserved_events + ctx->num_events < ctx->max_events && !ctx->choked) { ctx->reserved_events++; res = 0; } - pthread_mutex_unlock(&ctx->lock); + mp_mutex_unlock(&ctx->lock); return res; } @@ -749,7 +730,7 @@ static int append_event(struct mpv_handle *ctx, struct mpv_event event, bool cop static int send_event(struct mpv_handle *ctx, struct mpv_event *event, bool copy) { - pthread_mutex_lock(&ctx->lock); + mp_mutex_lock(&ctx->lock); uint64_t mask = 1ULL << event->event_id; if (ctx->property_event_masks & mask) notify_property_events(ctx, event->event_id); @@ -765,7 +746,7 @@ static int send_event(struct mpv_handle *ctx, struct mpv_event *event, bool copy ctx->choked = true; } } - pthread_mutex_unlock(&ctx->lock); + mp_mutex_unlock(&ctx->lock); return r; } @@ -775,20 +756,20 @@ static void send_reply(struct mpv_handle *ctx, uint64_t userdata, struct mpv_event *event) { event->reply_userdata = userdata; - pthread_mutex_lock(&ctx->lock); + mp_mutex_lock(&ctx->lock); // If this fails, reserve_reply() probably wasn't called. assert(ctx->reserved_events > 0); ctx->reserved_events--; if (append_event(ctx, *event, false) < 0) - abort(); // not reached - pthread_mutex_unlock(&ctx->lock); + MP_ASSERT_UNREACHABLE(); + mp_mutex_unlock(&ctx->lock); } void mp_client_broadcast_event(struct MPContext *mpctx, int event, void *data) { struct mp_client_api *clients = mpctx->clients; - pthread_mutex_lock(&clients->lock); + mp_mutex_lock(&clients->lock); for (int n = 0; n < clients->num_clients; n++) { struct mpv_event event_data = { @@ -798,7 +779,7 @@ void mp_client_broadcast_event(struct MPContext *mpctx, int event, void *data) send_event(clients->clients[n], &event_data, true); } - pthread_mutex_unlock(&clients->lock); + mp_mutex_unlock(&clients->lock); } // Like mp_client_broadcast_event(), but can be called from any thread. @@ -831,7 +812,7 @@ int mp_client_send_event(struct MPContext *mpctx, const char *client_name, .reply_userdata = reply_userdata, }; - pthread_mutex_lock(&clients->lock); + mp_mutex_lock(&clients->lock); struct mpv_handle *ctx = find_client(clients, client_name); if (ctx) { @@ -841,7 +822,7 @@ int mp_client_send_event(struct MPContext *mpctx, const char *client_name, talloc_free(data); } - pthread_mutex_unlock(&clients->lock); + mp_mutex_unlock(&clients->lock); return r; } @@ -863,16 +844,9 @@ int mp_client_send_event_dup(struct MPContext *mpctx, const char *client_name, return mp_client_send_event(mpctx, client_name, 0, event, event_data.data); } -static bool deprecated_events[] = { - [MPV_EVENT_TRACKS_CHANGED] = true, - [MPV_EVENT_TRACK_SWITCHED] = true, +static const bool deprecated_events[] = { [MPV_EVENT_IDLE] = true, - [MPV_EVENT_PAUSE] = true, - [MPV_EVENT_UNPAUSE] = true, [MPV_EVENT_TICK] = true, - [MPV_EVENT_SCRIPT_INPUT_DISPATCH] = true, - [MPV_EVENT_METADATA_UPDATE] = true, - [MPV_EVENT_CHAPTER_CHANGE] = true, }; int mpv_request_event(mpv_handle *ctx, mpv_event_id event, int enable) @@ -882,7 +856,7 @@ int mpv_request_event(mpv_handle *ctx, mpv_event_id event, int enable) if (event == MPV_EVENT_SHUTDOWN && !enable) return MPV_ERROR_INVALID_PARAMETER; assert(event < (int)INTERNAL_EVENT_BASE); // excluded above; they have no name - pthread_mutex_lock(&ctx->lock); + mp_mutex_lock(&ctx->lock); uint64_t bit = 1ULL << event; ctx->event_mask = enable ? ctx->event_mask | bit : ctx->event_mask & ~bit; if (enable && event < MP_ARRAY_SIZE(deprecated_events) && @@ -891,7 +865,7 @@ int mpv_request_event(mpv_handle *ctx, mpv_event_id event, int enable) MP_WARN(ctx, "The '%s' event is deprecated and will be removed.\n", mpv_event_name(event)); } - pthread_mutex_unlock(&ctx->lock); + mp_mutex_unlock(&ctx->lock); return 0; } @@ -920,7 +894,7 @@ mpv_event *mpv_wait_event(mpv_handle *ctx, double timeout) { mpv_event *event = ctx->cur_event; - pthread_mutex_lock(&ctx->lock); + mp_mutex_lock(&ctx->lock); if (!ctx->fuzzy_initialized) mp_wakeup_core(ctx->clients->mpctx); @@ -929,7 +903,7 @@ mpv_event *mpv_wait_event(mpv_handle *ctx, double timeout) if (timeout < 0) timeout = 1e20; - int64_t deadline = mp_add_timeout(mp_time_us(), timeout); + int64_t deadline = mp_time_ns_add(mp_time_ns(), timeout); *event = (mpv_event){0}; talloc_free_children(event); @@ -978,17 +952,17 @@ mpv_event *mpv_wait_event(mpv_handle *ctx, double timeout) } ctx->queued_wakeup = false; - pthread_mutex_unlock(&ctx->lock); + mp_mutex_unlock(&ctx->lock); return event; } void mpv_wakeup(mpv_handle *ctx) { - pthread_mutex_lock(&ctx->lock); + mp_mutex_lock(&ctx->lock); ctx->queued_wakeup = true; wakeup_client(ctx); - pthread_mutex_unlock(&ctx->lock); + mp_mutex_unlock(&ctx->lock); } // map client API types to internal types @@ -1361,6 +1335,12 @@ int mpv_set_property(mpv_handle *ctx, const char *name, mpv_format format, return req.status; } +int mpv_del_property(mpv_handle *ctx, const char *name) +{ + const char* args[] = { "del", name, NULL }; + return mpv_command(ctx, args); +} + int mpv_set_property_string(mpv_handle *ctx, const char *name, const char *data) { return mpv_set_property(ctx, name, MPV_FORMAT_STRING, &data); @@ -1420,7 +1400,7 @@ static void getproperty_fn(void *arg) struct getproperty_request *req = arg; const struct m_option *type = get_mp_type_get(req->format); - union m_option_value xdata = {0}; + union m_option_value xdata = m_option_value_default; void *data = req->data ? req->data : &xdata; int err = -1; @@ -1564,7 +1544,7 @@ int mpv_observe_property(mpv_handle *ctx, uint64_t userdata, if (format == MPV_FORMAT_OSD_STRING) return MPV_ERROR_PROPERTY_FORMAT; - pthread_mutex_lock(&ctx->lock); + mp_mutex_lock(&ctx->lock); assert(!ctx->destroying); struct observe_property *prop = talloc_ptrtype(ctx, prop); talloc_set_destructor(prop, property_free); @@ -1578,6 +1558,8 @@ int mpv_observe_property(mpv_handle *ctx, uint64_t userdata, .type = type, .change_ts = 1, // force initial event .refcount = 1, + .value = m_option_value_default, + .value_ret = m_option_value_default, }; ctx->properties_change_ts += 1; MP_TARRAY_APPEND(ctx, ctx->properties, ctx->num_properties, prop); @@ -1585,14 +1567,14 @@ int mpv_observe_property(mpv_handle *ctx, uint64_t userdata, ctx->new_property_events = true; ctx->cur_property_index = 0; ctx->has_pending_properties = true; - pthread_mutex_unlock(&ctx->lock); + mp_mutex_unlock(&ctx->lock); mp_wakeup_core(ctx->mpctx); return 0; } int mpv_unobserve_property(mpv_handle *ctx, uint64_t userdata) { - pthread_mutex_lock(&ctx->lock); + mp_mutex_lock(&ctx->lock); int count = 0; for (int n = ctx->num_properties - 1; n >= 0; n--) { struct observe_property *prop = ctx->properties[n]; @@ -1606,10 +1588,34 @@ int mpv_unobserve_property(mpv_handle *ctx, uint64_t userdata) count++; } } - pthread_mutex_unlock(&ctx->lock); + mp_mutex_unlock(&ctx->lock); return count; } +static bool property_shared_prefix(const char *a0, const char *b0) +{ + bstr a = bstr0(a0); + bstr b = bstr0(b0); + + // Treat options and properties as equivalent. + bstr_eatstart0(&a, "options/"); + bstr_eatstart0(&b, "options/"); + + // Compare the potentially-common portion + if (memcmp(a.start, b.start, MPMIN(a.len, b.len))) + return false; + + // If lengths were equal, we're done + if (a.len == b.len) + return true; + + // Check for a slash in the first non-common byte of the longer string + if (a.len > b.len) + return a.start[b.len] == '/'; + else + return b.start[a.len] == '/'; +} + // Broadcast that a property has changed. void mp_client_property_change(struct MPContext *mpctx, const char *name) { @@ -1617,22 +1623,23 @@ void mp_client_property_change(struct MPContext *mpctx, const char *name) int id = mp_get_property_id(mpctx, name); bool any_pending = false; - pthread_mutex_lock(&clients->lock); + mp_mutex_lock(&clients->lock); for (int n = 0; n < clients->num_clients; n++) { struct mpv_handle *client = clients->clients[n]; - pthread_mutex_lock(&client->lock); + mp_mutex_lock(&client->lock); for (int i = 0; i < client->num_properties; i++) { - if (client->properties[i]->id == id) { + if (client->properties[i]->id == id && + property_shared_prefix(name, client->properties[i]->name)) { client->properties[i]->change_ts += 1; client->has_pending_properties = true; any_pending = true; } } - pthread_mutex_unlock(&client->lock); + mp_mutex_unlock(&client->lock); } - pthread_mutex_unlock(&clients->lock); + mp_mutex_unlock(&clients->lock); // If we're inside mp_dispatch_queue_process(), this will cause the playloop // to be re-run (to get mp_client_send_property_changes() called). If we're @@ -1675,7 +1682,7 @@ static void send_client_property_changes(struct mpv_handle *ctx) bool changed = false; if (prop->format) { const struct m_option *type = prop->type; - union m_option_value val = {0}; + union m_option_value val = m_option_value_default; struct getproperty_request req = { .mpctx = ctx->mpctx, .name = prop->name, @@ -1689,9 +1696,9 @@ static void send_client_property_changes(struct mpv_handle *ctx) // or similar things are involved). prop->refcount += 1; // keep prop alive (esp. prop->name) ctx->async_counter += 1; // keep ctx alive - pthread_mutex_unlock(&ctx->lock); + mp_mutex_unlock(&ctx->lock); getproperty_fn(&req); - pthread_mutex_lock(&ctx->lock); + mp_mutex_lock(&ctx->lock); ctx->async_counter -= 1; prop_unref(prop); @@ -1748,22 +1755,22 @@ void mp_client_send_property_changes(struct MPContext *mpctx) { struct mp_client_api *clients = mpctx->clients; - pthread_mutex_lock(&clients->lock); + mp_mutex_lock(&clients->lock); uint64_t cur_ts = clients->clients_list_change_ts; for (int n = 0; n < clients->num_clients; n++) { struct mpv_handle *ctx = clients->clients[n]; - pthread_mutex_lock(&ctx->lock); + mp_mutex_lock(&ctx->lock); if (!ctx->has_pending_properties || ctx->destroying) { - pthread_mutex_unlock(&ctx->lock); + mp_mutex_unlock(&ctx->lock); continue; } // Keep ctx->lock locked (unlock order does not matter). - pthread_mutex_unlock(&clients->lock); + mp_mutex_unlock(&clients->lock); send_client_property_changes(ctx); - pthread_mutex_unlock(&ctx->lock); - pthread_mutex_lock(&clients->lock); + mp_mutex_unlock(&ctx->lock); + mp_mutex_lock(&clients->lock); if (cur_ts != clients->clients_list_change_ts) { // List changed; need to start over. Do it in the next iteration. mp_wakeup_core(mpctx); @@ -1771,7 +1778,7 @@ void mp_client_send_property_changes(struct MPContext *mpctx) } } - pthread_mutex_unlock(&clients->lock); + mp_mutex_unlock(&clients->lock); } // Set ctx->cur_event to a generated property change event, if there is any @@ -1841,7 +1848,7 @@ int mpv_hook_continue(mpv_handle *ctx, uint64_t id) int mpv_load_config_file(mpv_handle *ctx, const char *filename) { lock_core(ctx); - int r = m_config_parse_config_file(ctx->mpctx->mconfig, filename, NULL, 0); + int r = m_config_parse_config_file(ctx->mpctx->mconfig, ctx->mpctx->global, filename, NULL, 0); unlock_core(ctx); if (r == 0) return MPV_ERROR_INVALID_PARAMETER; @@ -1878,7 +1885,7 @@ int mpv_request_log_messages(mpv_handle *ctx, const char *min_level) if (level < 0 && strcmp(min_level, "no") != 0) return MPV_ERROR_INVALID_PARAMETER; - pthread_mutex_lock(&ctx->lock); + mp_mutex_lock(&ctx->lock); if (level < 0 || level != ctx->messages_level) { mp_msg_log_buffer_destroy(ctx->messages); ctx->messages = NULL; @@ -1893,7 +1900,7 @@ int mpv_request_log_messages(mpv_handle *ctx, const char *min_level) mp_msg_log_buffer_set_silent(ctx->messages, silent); } wakeup_client(ctx); - pthread_mutex_unlock(&ctx->lock); + mp_mutex_unlock(&ctx->lock); return 0; } @@ -1925,13 +1932,13 @@ static bool gen_log_message_event(struct mpv_handle *ctx) int mpv_get_wakeup_pipe(mpv_handle *ctx) { - pthread_mutex_lock(&ctx->wakeup_lock); + mp_mutex_lock(&ctx->wakeup_lock); if (ctx->wakeup_pipe[0] == -1) { if (mp_make_wakeup_pipe(ctx->wakeup_pipe) >= 0) (void)write(ctx->wakeup_pipe[1], &(char){0}, 1); } int fd = ctx->wakeup_pipe[0]; - pthread_mutex_unlock(&ctx->wakeup_lock); + mp_mutex_unlock(&ctx->wakeup_lock); return fd; } @@ -2098,21 +2105,14 @@ static const char *const event_table[] = { [MPV_EVENT_START_FILE] = "start-file", [MPV_EVENT_END_FILE] = "end-file", [MPV_EVENT_FILE_LOADED] = "file-loaded", - [MPV_EVENT_TRACKS_CHANGED] = "tracks-changed", - [MPV_EVENT_TRACK_SWITCHED] = "track-switched", [MPV_EVENT_IDLE] = "idle", - [MPV_EVENT_PAUSE] = "pause", - [MPV_EVENT_UNPAUSE] = "unpause", [MPV_EVENT_TICK] = "tick", - [MPV_EVENT_SCRIPT_INPUT_DISPATCH] = "script-input-dispatch", [MPV_EVENT_CLIENT_MESSAGE] = "client-message", [MPV_EVENT_VIDEO_RECONFIG] = "video-reconfig", [MPV_EVENT_AUDIO_RECONFIG] = "audio-reconfig", - [MPV_EVENT_METADATA_UPDATE] = "metadata-update", [MPV_EVENT_SEEK] = "seek", [MPV_EVENT_PLAYBACK_RESTART] = "playback-restart", [MPV_EVENT_PROPERTY_CHANGE] = "property-change", - [MPV_EVENT_CHAPTER_CHANGE] = "chapter-change", [MPV_EVENT_QUEUE_OVERFLOW] = "event-queue-overflow", [MPV_EVENT_HOOK] = "hook", }; @@ -2129,9 +2129,14 @@ void mpv_free(void *data) talloc_free(data); } +int64_t mpv_get_time_ns(mpv_handle *ctx) +{ + return mp_time_ns(); +} + int64_t mpv_get_time_us(mpv_handle *ctx) { - return mp_time_us(); + return mp_time_ns() / 1000; } #include "video/out/libmpv.h" @@ -2161,14 +2166,14 @@ bool mp_set_main_render_context(struct mp_client_api *client_api, { assert(ctx); - pthread_mutex_lock(&client_api->lock); + mp_mutex_lock(&client_api->lock); bool is_set = !!client_api->render_context; bool is_same = client_api->render_context == ctx; // Can set if it doesn't remove another existing ctx. bool res = is_same || !is_set; if (res) client_api->render_context = active ? ctx : NULL; - pthread_mutex_unlock(&client_api->lock); + mp_mutex_unlock(&client_api->lock); return res; } @@ -2177,134 +2182,10 @@ struct mpv_render_context * mp_client_api_acquire_render_context(struct mp_client_api *ca) { struct mpv_render_context *res = NULL; - pthread_mutex_lock(&ca->lock); + mp_mutex_lock(&ca->lock); if (ca->render_context && mp_render_context_acquire(ca->render_context)) res = ca->render_context; - pthread_mutex_unlock(&ca->lock); - return res; -} - -// Emulation of old opengl_cb API. - -#include "libmpv/opengl_cb.h" -#include "libmpv/render_gl.h" - -struct mpv_opengl_cb_context { - struct mp_client_api *client_api; - mpv_opengl_cb_update_fn callback; - void *callback_ctx; -}; - -static mpv_opengl_cb_context *opengl_cb_get_context(mpv_handle *ctx) -{ - pthread_mutex_lock(&ctx->clients->lock); - mpv_opengl_cb_context *cb = ctx->clients->gl_cb_ctx; - if (!cb) { - cb = talloc_zero(NULL, struct mpv_opengl_cb_context); - cb->client_api = ctx->clients; - cb->client_api->gl_cb_ctx = cb; - } - pthread_mutex_unlock(&ctx->clients->lock); - return cb; -} - -void mpv_opengl_cb_set_update_callback(mpv_opengl_cb_context *ctx, - mpv_opengl_cb_update_fn callback, - void *callback_ctx) -{ - // This was probably supposed to be thread-safe, but we don't care. It's - // compatibility code, and if you have problems, use the new API. - if (ctx->client_api->render_context) { - mpv_render_context_set_update_callback(ctx->client_api->render_context, - callback, callback_ctx); - } - // Nasty thing: could set this even while not initialized, so we need to - // preserve it. - ctx->callback = callback; - ctx->callback_ctx = callback_ctx; -} - -int mpv_opengl_cb_init_gl(mpv_opengl_cb_context *ctx, const char *exts, - mpv_opengl_cb_get_proc_address_fn get_proc_address, - void *get_proc_address_ctx) -{ - if (ctx->client_api->render_context) - return MPV_ERROR_INVALID_PARAMETER; - - // mpv_render_context_create() only calls mp_client_get_global() on it. - mpv_handle dummy = {.mpctx = ctx->client_api->mpctx}; - - mpv_render_param params[] = { - {MPV_RENDER_PARAM_API_TYPE, MPV_RENDER_API_TYPE_OPENGL}, - {MPV_RENDER_PARAM_OPENGL_INIT_PARAMS, &(mpv_opengl_init_params){ - .get_proc_address = get_proc_address, - .get_proc_address_ctx = get_proc_address_ctx, - .extra_exts = exts, - }}, - // Hack for explicit legacy hwdec loading. We really want to make it - // impossible for proper render API users to trigger this. - {(mpv_render_param_type)-1, ctx->client_api->mpctx->global}, - {0} - }; - int err = mpv_render_context_create(&ctx->client_api->render_context, - &dummy, params); - if (err >= 0) { - mpv_render_context_set_update_callback(ctx->client_api->render_context, - ctx->callback, ctx->callback_ctx); - } - return err; -} - -int mpv_opengl_cb_draw(mpv_opengl_cb_context *ctx, int fbo, int w, int h) -{ - if (!ctx->client_api->render_context) - return MPV_ERROR_INVALID_PARAMETER; - - mpv_render_param params[] = { - {MPV_RENDER_PARAM_OPENGL_FBO, &(mpv_opengl_fbo){ - .fbo = fbo, - .w = w, - .h = abs(h), - }}, - {MPV_RENDER_PARAM_FLIP_Y, &(int){h < 0}}, - {0} - }; - return mpv_render_context_render(ctx->client_api->render_context, params); -} - -int mpv_opengl_cb_report_flip(mpv_opengl_cb_context *ctx, int64_t time) -{ - if (!ctx->client_api->render_context) - return MPV_ERROR_INVALID_PARAMETER; - - mpv_render_context_report_swap(ctx->client_api->render_context); - return 0; -} - -int mpv_opengl_cb_uninit_gl(mpv_opengl_cb_context *ctx) -{ - if (ctx->client_api->render_context) - mpv_render_context_free(ctx->client_api->render_context); - ctx->client_api->render_context = NULL; - return 0; -} - -int mpv_opengl_cb_render(mpv_opengl_cb_context *ctx, int fbo, int vp[4]) -{ - return mpv_opengl_cb_draw(ctx, fbo, vp[2], vp[3]); -} - -void *mpv_get_sub_api(mpv_handle *ctx, mpv_sub_api sub_api) -{ - if (!ctx->mpctx->initialized) - return NULL; - void *res = NULL; - switch (sub_api) { - case MPV_SUB_API_OPENGL_CB: - res = opengl_cb_get_context(ctx); - break; - default:; - } |