From 75b2ccfeb1ce4ed5a40ac9860fa74f3d1265e13f Mon Sep 17 00:00:00 2001
From: Crend King <975235+CrendKing@users.noreply.github.com>
Date: Thu, 9 Apr 2026 21:53:16 -0700
Subject: [PATCH] vf_vapoursynth: update for VapourSynth R74

VapourSynth R74 changed two things relevant to mpv build process:

1) VSScript no longer has static library to link to, and only support runtime loading.
This is reflected on the new VSScript example in VapourSynth SDK.
2) The VSScript library name is changed from libvapoursynth-script to libvsscript for Linux
and MacOS.

The new VSScript initialization code is modified from their SDK example to utilize
mpv's mechanisms. Build dependency is also updated accordingly.
---
 meson.build                   |  6 ++---
 osdep/io.h                    |  5 ++--
 video/filter/vf_vapoursynth.c | 49 ++++++++++++++++++++++++++++++++---
 3 files changed, 51 insertions(+), 9 deletions(-)

diff --git a/meson.build b/meson.build
index a40e4f1aec520..d7bfd5f3a3311 100644
--- a/meson.build
+++ b/meson.build
@@ -772,11 +772,9 @@ if features['uchardet']
 endif
 
 vapoursynth = dependency('vapoursynth', version: '>= 56', required: get_option('vapoursynth'))
-vapoursynth_script = dependency('vapoursynth-script', version: '>= 56',
-                                required: get_option('vapoursynth'))
-features += {'vapoursynth': vapoursynth.found() and vapoursynth_script.found()}
+features += {'vapoursynth': vapoursynth.found()}
 if features['vapoursynth']
-    dependencies += [vapoursynth, vapoursynth_script]
+    dependencies += vapoursynth.partial_dependency(compile_args: true, includes: true)
     sources += files('video/filter/vf_vapoursynth.c')
 endif
 
diff --git a/osdep/io.h b/osdep/io.h
index cc72e22473a54..bf672224e78a7 100644
--- a/osdep/io.h
+++ b/osdep/io.h
@@ -247,12 +247,13 @@ locale_t newlocale(int, const char *, locale_t);
 locale_t uselocale(locale_t);
 void freelocale(locale_t);
 
-#else /* __MINGW32__ */
+#else /* _WIN32 */
 
+#include <dlfcn.h>
 #include <sys/mman.h>
 
 extern char **environ;
 
-#endif /* __MINGW32__ */
+#endif /* _WIN32 */
 
 #endif
diff --git a/video/filter/vf_vapoursynth.c b/video/filter/vf_vapoursynth.c
index d2ab916220edf..22bfa646581e9 100644
--- a/video/filter/vf_vapoursynth.c
+++ b/video/filter/vf_vapoursynth.c
@@ -22,7 +22,6 @@
 #include <limits.h>
 #include <assert.h>
 
-#include <VapourSynth4.h>
 #include <VSScript4.h>
 
 #include <libavutil/rational.h>
@@ -37,11 +36,24 @@
 #include "filters/user_filters.h"
 #include "options/m_option.h"
 #include "options/path.h"
+#include "osdep/io.h"
 #include "osdep/threads.h"
 #include "video/img_format.h"
 #include "video/mp_image.h"
 #include "video/sws_utils.h"
 
+static const char *const vsscript_lib_names[] = {
+#ifdef _WIN32
+    "VSScript.dll",
+#elif defined(__APPLE__)
+    "libvsscript.dylib",
+    "libvapoursynth-script.dylib",
+#else
+    "libvsscript.so",
+    "libvapoursynth-script.so",
+#endif
+};
+
 struct vapoursynth_opts {
     char *file;
     int maxbuffer;
@@ -804,11 +816,42 @@ static const m_option_t vf_opts_fields[] = {
 
 static int drv_vss_init(struct priv *p)
 {
-    p->vs_script_api = getVSScriptAPI(VSSCRIPT_API_VERSION);
+    const char *vsscript_path = getenv("VSSCRIPT_PATH");
+    const int dl_mode = RTLD_NOW | RTLD_LOCAL;
+    void *vsscript_lib = NULL;
+
+    if (vsscript_path) {
+        vsscript_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);
+        }
+    }
+
+    VS_CC const VSSCRIPTAPI *(*getVSScriptAPI_func)(int) = NULL;
+    VS_CC const char *(*getVSScriptAPILastError_func)(void) = NULL;
+    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 (!getVSScriptAPI_func) {
+        const char *dl_error_msg = dlerror();
+        const char *last_error_msg = dl_error_msg ? dl_error_msg : unknown_error_msg;
+        MP_FATAL(p, "Failed to load VapourSynth VSScript library: %s\n", last_error_msg);
+        return -1;
+    }
+
+    p->vs_script_api = getVSScriptAPI_func(VSSCRIPT_API_VERSION);
     if (!p->vs_script_api) {
-        MP_FATAL(p, "Could not initialize VapourSynth scripting.\n");
+        const char *vs_error_msg = getVSScriptAPILastError_func ? getVSScriptAPILastError_func() : NULL;
+        const char *last_error_msg = vs_error_msg ? vs_error_msg : unknown_error_msg;
+        MP_FATAL(p, "Failed to initialize VapourSynth VSScript library: %s\n", last_error_msg);
         return -1;
     }
+
     return 0;
 }
 
