From 8aabba933bd600ea89924b97d4e5b2361b96f6fa Mon Sep 17 00:00:00 2001
From: Crend King <975235+CrendKing@users.noreply.github.com>
Date: Thu, 23 Apr 2026 18:02:38 -0700
Subject: [PATCH] vf_vapoursynth: improve backward compatibility

The previous commit to dynamically load VapourSynth R74 would fail to work
for VapourSynth R73 and before on Linux due to load mode RTLD_LOCAL. To
make it work on all VapourSynth version, switch to use RTLD_GLOBAL mode.

Add library handle closing in drv_vss_uninit for completeness.
---
 osdep/io.c                    |  5 +++++
 osdep/io.h                    |  3 +++
 video/filter/vf_vapoursynth.c | 24 +++++++++++++++---------
 3 files changed, 23 insertions(+), 9 deletions(-)

diff --git a/osdep/io.c b/osdep/io.c
index 9401a468056e3..96e98d72a499b 100644
--- a/osdep/io.c
+++ b/osdep/io.c
@@ -781,6 +781,11 @@ void *mp_dlsym(void *handle, const char *symbol)
     return (void *)addr;
 }
 
+int mp_dlclose(void *handle)
+{
+    return CloseHandle(handle);
+}
+
 char *mp_dlerror(void)
 {
     if (mp_dl_result.errcode == 0)
diff --git a/osdep/io.h b/osdep/io.h
index bf672224e78a7..80426e76d0ab8 100644
--- a/osdep/io.h
+++ b/osdep/io.h
@@ -138,6 +138,7 @@ off_t mp_lseek64(int fd, off_t offset, int whence);
 int mp_ftruncate64(int fd, off_t length);
 void *mp_dlopen(const char *filename, int flag);
 void *mp_dlsym(void *handle, const char *symbol);
+int mp_dlclose(void *handle);
 char *mp_dlerror(void);
 
 // mp_stat types. MSVCRT's dev_t and ino_t are way too short to be unique.
@@ -207,8 +208,10 @@ void mp_globfree(mp_glob_t *pglob);
 
 #define RTLD_NOW 0
 #define RTLD_LOCAL 0
+#define RTLD_GLOBAL 0
 #define dlopen(fn,fg) mp_dlopen((fn), (fg))
 #define dlsym(h,s) mp_dlsym((h), (s))
+#define dlclose(h) mp_dlclose((h))
 #define dlerror mp_dlerror
 
 // Affects both "stat()" and "struct stat".
diff --git a/video/filter/vf_vapoursynth.c b/video/filter/vf_vapoursynth.c
index 22bfa646581e9..4882565a11cf0 100644
--- a/video/filter/vf_vapoursynth.c
+++ b/video/filter/vf_vapoursynth.c
@@ -75,6 +75,7 @@ struct priv {
 
     const struct script_driver *drv;
     // drv_vss
+    void *vs_script_lib;
     const VSSCRIPTAPI *vs_script_api;
     VSScript *vs_script;
 
@@ -817,24 +818,24 @@ static const m_option_t vf_opts_fields[] = {
 static int drv_vss_init(struct priv *p)
 {
     const char *vsscript_path = getenv("VSSCRIPT_PATH");
-    const int dl_mode = RTLD_NOW | RTLD_LOCAL;
-    void *vsscript_lib = NULL;
+    const int dl_mode = RTLD_NOW | RTLD_GLOBAL;
+    p->vs_script_lib = NULL;
 
     if (vsscript_path) {
-        vsscript_lib = dlopen(vsscript_path, dl_mode);
+        p->vs_script_lib = dlopen(vsscript_path, dl_mode);
     } else {
-        for (size_t i = 0; i < MP_ARRAY_SIZE(vsscript_lib_names) && !vsscript_lib; ++i) {
-            vsscript_lib = dlopen(vsscript_lib_names[i], dl_mode);
+        for (size_t i = 0; i < MP_ARRAY_SIZE(vsscript_lib_names) && !p->vs_script_lib; ++i) {
+            p->vs_script_lib = dlopen(vsscript_lib_names[i], dl_mode);
         }
     }
 
     VS_CC const VSSCRIPTAPI *(*getVSScriptAPI_func)(int) = NULL;
     VS_CC const char *(*getVSScriptAPILastError_func)(void) = NULL;
-    const char *unknown_error_msg = "Last error unknown";
+    const char *unknown_error_msg = "last error unknown";
 
-    if (vsscript_lib) {
-        getVSScriptAPI_func = (void *) dlsym(vsscript_lib, "getVSScriptAPI");
-        getVSScriptAPILastError_func = (void *) dlsym(vsscript_lib, "getVSScriptAPILastError");
+    if (p->vs_script_lib) {
+        getVSScriptAPI_func = (void *) dlsym(p->vs_script_lib, "getVSScriptAPI");
+        getVSScriptAPILastError_func = (void *) dlsym(p->vs_script_lib, "getVSScriptAPILastError");
     }
 
     if (!getVSScriptAPI_func) {
@@ -858,6 +859,11 @@ static int drv_vss_init(struct priv *p)
 static void drv_vss_uninit(struct priv *p)
 {
     p->vs_script_api = NULL;
+
+    if (p->vs_script_lib) {
+        dlclose(p->vs_script_lib);
+        p->vs_script_lib = NULL;
+    }
 }
 
 static int drv_vss_load_core(struct priv *p)
