summaryrefslogtreecommitdiffstats
path: root/player
diff options
context:
space:
mode:
authorKacper Michajłow <kasper93@gmail.com>2023-08-17 16:19:26 +0200
committerDudemanguy <random342@airmail.cc>2023-09-20 02:16:45 +0000
commiteab3842d8bb5ff5465e075fc42d171ac3757903d (patch)
tree17be06e09ab5abdd4185df734ec9595393e268cd /player
parent4435b1a0d5ac620eda3b18689dff3cb46fd2a732 (diff)
downloadmpv-eab3842d8bb5ff5465e075fc42d171ac3757903d.tar.bz2
mpv-eab3842d8bb5ff5465e075fc42d171ac3757903d.tar.xz
cplugin: allow loading mpv_* symbols dynamically
Defining MPV_CPLUGIN_DYNAMIC_SYM during plugin compilation will replace mpv_* functions with function pointers. Those pointer will be initialized when loading the plugin. It is recommended to use this symbol table when targeting Windows. The loader does not have notion of global symbols. Loading cplugin into mpv process will not allow this plugin to call any of the symbols that may be available in other modules. Instead cplugin has to link explicitly to specific PE binary, libmpv-2.dll/mpv.exe or any other binary that may have linked mpv statically. This limits portability of cplugin as it would need to be compiled separately for each of target PE binary that includes mpv's symbols. Which in practice is unrealictis, as we want one cplugin to be loaded without those restrictions. Instead of linking to any PE binary, we create function pointer for all mpv's exported symbols. For convinience names of entrypoints are redefined to those pointer so no changes are required in cplugin source code, except defining MPV_CPLUGIN_DYNAMIC_SYM. Those function pointer are exported to make them available for mpv to init with correct values during runtime, before calling `mpv_open_cplugin`. Note that those pointer are decorated with `selectany` attribute, so no need to worry about multiple definitions, linker will keep only single instance. This fixes cplugin usability on Windows. Without any API changes, only recompilation with -DMPV_CPLUGIN_DYNAMIC_SYM is needed.
Diffstat (limited to 'player')
-rw-r--r--player/scripting.c75
1 files changed, 75 insertions, 0 deletions
diff --git a/player/scripting.c b/player/scripting.c
index 48153ef6df..9a23a0dae0 100644
--- a/player/scripting.c
+++ b/player/scripting.c
@@ -40,6 +40,8 @@
#include "core.h"
#include "client.h"
#include "libmpv/client.h"
+#include "libmpv/render.h"
+#include "libmpv/stream_cb.h"
extern const struct mp_scripting mp_scripting_lua;
extern const struct mp_scripting mp_scripting_cplugin;
@@ -302,6 +304,76 @@ bool mp_load_scripts(struct MPContext *mpctx)
#define MPV_DLOPEN_FN "mpv_open_cplugin"
typedef int (*mpv_open_cplugin)(mpv_handle *handle);
+static void init_sym_table(struct mp_script_args *args, void *lib) {
+#define INIT_SYM(name) \
+ { \
+ void **sym = (void **)dlsym(lib, "pfn_" #name); \
+ if (sym) { \
+ if (*sym && *sym != &name) \
+ MP_ERR(args, "Overriding already set function " #name "\n"); \
+ *sym = &name; \
+ } \
+ }
+
+ INIT_SYM(mpv_client_api_version);
+ INIT_SYM(mpv_error_string);
+ INIT_SYM(mpv_free);
+ INIT_SYM(mpv_client_name);
+ INIT_SYM(mpv_client_id);
+ INIT_SYM(mpv_create);
+ INIT_SYM(mpv_initialize);
+ INIT_SYM(mpv_destroy);
+ INIT_SYM(mpv_terminate_destroy);
+ INIT_SYM(mpv_create_client);
+ INIT_SYM(mpv_create_weak_client);
+ INIT_SYM(mpv_load_config_file);
+ INIT_SYM(mpv_get_time_us);
+ INIT_SYM(mpv_free_node_contents);
+ INIT_SYM(mpv_set_option);
+ INIT_SYM(mpv_set_option_string);
+ INIT_SYM(mpv_command);
+ INIT_SYM(mpv_command_node);
+ INIT_SYM(mpv_command_ret);
+ INIT_SYM(mpv_command_string);
+ INIT_SYM(mpv_command_async);
+ INIT_SYM(mpv_command_node_async);
+ INIT_SYM(mpv_abort_async_command);
+ INIT_SYM(mpv_set_property);
+ INIT_SYM(mpv_set_property_string);
+ INIT_SYM(mpv_del_property);
+ INIT_SYM(mpv_set_property_async);
+ INIT_SYM(mpv_get_property);
+ INIT_SYM(mpv_get_property_string);
+ INIT_SYM(mpv_get_property_osd_string);
+ INIT_SYM(mpv_get_property_async);
+ INIT_SYM(mpv_observe_property);
+ INIT_SYM(mpv_unobserve_property);
+ INIT_SYM(mpv_event_name);
+ INIT_SYM(mpv_event_to_node);
+ INIT_SYM(mpv_request_event);
+ INIT_SYM(mpv_request_log_messages);
+ INIT_SYM(mpv_wait_event);
+ INIT_SYM(mpv_wakeup);
+ INIT_SYM(mpv_set_wakeup_callback);
+ INIT_SYM(mpv_wait_async_requests);
+ INIT_SYM(mpv_hook_add);
+ INIT_SYM(mpv_hook_continue);
+ INIT_SYM(mpv_get_wakeup_pipe);
+
+ INIT_SYM(mpv_render_context_create);
+ INIT_SYM(mpv_render_context_set_parameter);
+ INIT_SYM(mpv_render_context_get_info);
+ INIT_SYM(mpv_render_context_set_update_callback);
+ INIT_SYM(mpv_render_context_update);
+ INIT_SYM(mpv_render_context_render);
+ INIT_SYM(mpv_render_context_report_swap);
+ INIT_SYM(mpv_render_context_free);
+
+ INIT_SYM(mpv_stream_cb_add_ro);
+
+#undef INIT_SYM
+}
+
static int load_cplugin(struct mp_script_args *args)
{
void *lib = dlopen(args->filename, RTLD_NOW | RTLD_LOCAL);
@@ -312,6 +384,9 @@ static int load_cplugin(struct mp_script_args *args)
mpv_open_cplugin sym = (mpv_open_cplugin)dlsym(lib, MPV_DLOPEN_FN);
if (!sym)
goto error;
+
+ init_sym_table(args, lib);
+
return sym(args->client) ? -1 : 0;
error: ;
char *err = dlerror();