[FFmpeg-devel] libavformat / vapoursynth update
Hello, I updated the VapourSynth input module from the old API to the "new" API (the "new" API was introduced 4 years ago). The greatest advantage of the new API is, that it requires only a single import from the VapourSynth library, optimizing it for runtime loading instead of linking to the library during the build process. Currently almost no one builds ffmpeg with VapourSynth enabled: Understandable, because VapourSynth is not just an external library, but an entire application with its own dependencies. Making ffmpeg load the VapourSynth library at runtime only when a VapourSynth script is opened would allow building ffmpeg binaries with VapourSynth enabled, that do not require VapourSynth to be installed on the user system (unless the user would want to open a VapourSynth script). I have already successfully tested this approach on different platforms (Linux, macOS and partly Windows). There are a few options on how to do it exactly: -Remove linking at build time all together and disable VapourSynth on platforms that do not support LoadLibrary or dlopen (as VapourSynth is based on plug-ins, on platforms that do not have these function it won't work at all) or make it selectable at build time. -Include the header files directly in ffmpeg (VapourSynth is LPGL 2.1 or later just like ffmpeg, so no license issue), this would allow for building ffmpeg with VapourSynth support without the need to have VapourSynth installed on the build machine. The alternative would be to use the header files installed on the system if available. (In case additional files should be avoided, the header files could of course be copied into the vapoursynth.c, or at least merged into a single header file). What do you think about this? Should I prepare a patch for this? What option should I choose? Best regards, Stefan ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
[FFmpeg-devel] [PATCH] libavformat/vapoursynth: Update to API version 4, load library at runtime
Hello, this is my first patch, I hope I got all the formalities correct. The current VapourSynth implementation is rarely used, as it links the VapourSynth library at build time, making the resulting build unable to run when VapourSynth is not installed. Therefore barely anyone compiles with VapourSynth activated. I changed it, so that it loads the library at runtime when a VapourSynth script should be opened, just like AviSynth does. On Windows the DLL from VapourSynth is not installed in the system directory, but the location is stored in the Registry. Therefore I added some code to read that information from the registry. As the V4 API is designed with dynamic loading in mind (only a single import), I updated the implementation to V4 (changes are mostly superficial, no structural changes). The V4 API is already several years old, fully supported since R55 released in 2021. I copied the two needed header files directly in a vapoursynth.h, removing the need to install VapourSynth on the build machine (VapourSynth is also LGPL 2.1 or later, so no license issue). I updated the configure so that it checks for the ability to load libraries at runtime for VapourSynth, just like AviSynth and activate it if not disabled. make fate runs without any issue. I tested VapourSynth input scripts with various color formats on different platforms: Ubuntu 22.04 macOS 13 (x86_64) macOS 13 (arm64) Windows 10 (msys2/gcc) It compiles on these platforms without any warning and runs without any issues. Best regards Stefan From c13faf46f5d210c676b237f855d56a9b8a0a127d Mon Sep 17 00:00:00 2001 From: John Doe Date: Sat, 22 Jun 2024 02:53:07 +0200 Subject: [PATCH] libavformat/vapoursynth: Update to API version 4, load library at runtime The VapourSynth V4 API is designed for loading at runtime instead of linking to it during build time, this is now done in ffmpeg, similar to how AviSynth support is implemented. This allows building with VapourSynth support enabled, but ffmpeg still working fine without VapourSynth installed on target machine. --- configure | 7 +- libavformat/vapoursynth.c | 167 +++--- libavformat/vapoursynth.h | 635 ++ 3 files changed, 768 insertions(+), 41 deletions(-) create mode 100644 libavformat/vapoursynth.h diff --git a/configure b/configure index 3bca638459..a54d2976f5 100755 --- a/configure +++ b/configure @@ -333,7 +333,7 @@ External library support: --disable-sdl2 disable sdl2 [autodetect] --disable-securetransport disable Secure Transport, needed for TLS support on OSX if openssl and gnutls are not used [autodetect] - --enable-vapoursynth enable VapourSynth demuxer [no] + --disable-vapoursynthdisable VapourSynth demuxer [autodetect] --disable-xlib disable xlib [autodetect] --disable-zlib disable zlib [autodetect] @@ -1853,6 +1853,7 @@ EXTERNAL_AUTODETECT_LIBRARY_LIST=" sdl2 securetransport sndio +vapoursynth xlib zlib " @@ -1981,7 +1982,6 @@ EXTERNAL_LIBRARY_LIST=" opengl openssl pocketsphinx -vapoursynth " HWACCEL_AUTODETECT_LIBRARY_LIST=" @@ -3572,6 +3572,7 @@ libxevd_decoder_deps="libxevd" libxeve_encoder_deps="libxeve" libxvid_encoder_deps="libxvid" libzvbi_teletext_decoder_deps="libzvbi" +vapoursynth_deps_any="libdl LoadLibrary" vapoursynth_demuxer_deps="vapoursynth" videotoolbox_suggest="coreservices" videotoolbox_deps="corefoundation coremedia corevideo" @@ -7068,8 +7069,6 @@ enabled rkmpp && { require_pkg_config rkmpp rockchip_mpp rockchip/r { enabled libdrm || die "ERROR: rkmpp requires --enable-libdrm"; } } -enabled vapoursynth && require_pkg_config vapoursynth "vapoursynth-script >= 42" VSScript.h vsscript_init - if enabled gcrypt; then GCRYPT_CONFIG="${cross_prefix}libgcrypt-config" diff --git a/libavformat/vapoursynth.c b/libavformat/vapoursynth.c index 8a2519e19a..8cf309002b 100644 --- a/libavformat/vapoursynth.c +++ b/libavformat/vapoursynth.c @@ -25,9 +25,6 @@ #include -#include -#include - #include "libavutil/avassert.h" #include "libavutil/avstring.h" #include "libavutil/eval.h" @@ -39,20 +36,65 @@ #include "avformat.h" #include "demux.h" #include "internal.h" +#include "vapoursynth.h" + +/* Platform-specific directives. */ +#ifdef _WIN32 + #include + #include "compat/w32dlfcn.h" + #include "libavutil/wchar_filename.h" + static av_cold char* get_vs_script_dll_name(void) { + LONG r; + WCHAR vss_path[512]; + char *vss_path_utf8; + DWORD buf_size = sizeof(vss_path) - 2; + r = RegGetValueW(HKEY_CURRENT_USER, L"SOFTWARE\\VapourSynth", +L"VSScriptDLL", RRF_RT_REG_SZ, NULL, +&vss_path, &buf_size); + if (r == ERROR_SUCCESS && wchartoutf8(vss_path, &vss_path_
Re: [FFmpeg-devel] [PATCH] libavformat/vapoursynth: Update to API version 4, load library at runtime
Am 22.06.24 um 08:27 schrieb Stephen Hutchinson: On 6/21/24 9:37 PM, Stefan Oltmanns via ffmpeg-devel wrote: The current VapourSynth implementation is rarely used, as it links the VapourSynth library at build time, making the resulting build unable to run when VapourSynth is not installed. Therefore barely anyone compiles with VapourSynth activated. How many distros package VapourSynth yet don't enable it in FFmpeg vs. both not packaging it and not enabling it? VapourSynth not being available as a package in the distro's repository is a far more likely reason than linking is. I don't know the extact reason, but VapourSynth is not just a library like avisynth, but an application that uses Python, meaning a lot of dependencies. Additionally VapourSynth can nowadays be installed using pip, so no reason to package it for distros anymore. Switching to dynamic loading would absolutely make the experience on or building for Windows smoother, and would remove the need to rebuild FFmpeg when VapourSynth updates, outside of future API changes the demuxer would need to actively account for. Exactly I changed it, so that it loads the library at runtime when a VapourSynth script should be opened, just like AviSynth does. On Windows the DLL from VapourSynth is not installed in the system directory, but the location is stored in the Registry. Therefore I added some code to read that information from the registry. That function is in the wrong place. I thought that to, should it be in /compat as w32registry.h or something like that? But what exactly should it contain? I could make a function that would be used like get_w32_regsitry_str(HKEY_CURRENT_USER, L"SOFTWARE\\VapourSynth", L"VSScriptDLL"); That would return a utf8 string on success and NULL on failure But that would still contain 3 Windows-specific constants in the function call. Also is it useful to write the literals as utf-8 just for them to be converted to wchar again or should it just take WCHAR and return utf8? Or shoulds the entire function be located in /compat/vapoursynth/w32_vsscript_dll.h as "get_w32_vsscript_dll" or something similar? I copied the two needed header files directly in a vapoursynth.h, removing the need to install VapourSynth on the build machine (VapourSynth is also LGPL 2.1 or later, so no license issue). I updated the configure so that it checks for the ability to load libraries at runtime for VapourSynth, just like AviSynth and activate it if not disabled. Including local copies of the headers in compat/ wasn't acceptable for AviSynth (and were removed as soon as it was no longer necessary for there to be an OS distinction between what headers were being used), it's not going to be acceptable for this either. As distros probably won't package VapourSynth as it can be installed using pip, they probably won't build ffmpeg with VapourSynth support, because they don't have the headers on the build system. Even when someone decides to build ffmpeg for themself with VapourSynth support, it will fail unless they have manually build VapourSynth, because pip won't install any header. That was my motivation to include those headers. Is there a specific rule when it is allowed to include headers for external libaries? And setting it up as autodetect seems like overreach. I don't know if there's any actual written rule about which libraries to autodetect and which ones require explicit enabling, but most of the autodetected ones thus far appear to be OS-level or otherwise foundational libraries, not libraries for a singular media format. I did not find any rule on that. I made it autodetect, because I saw no negative impact (same license and no dependency at runtime). ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
Re: [FFmpeg-devel] [PATCH] libavformat/vapoursynth: Update to API version 4, load library at runtime
Am 22.06.24 um 20:23 schrieb Stephen Hutchinson: On 6/22/24 6:02 AM, Stefan Oltmanns via ffmpeg-devel wrote: I don't know the extact reason, but VapourSynth is not just a library like avisynth, but an application that uses Python, meaning a lot of dependencies. If we want to be technical, then yes, VapourSynth is just a library, with bindings to integrate it into Python. Lua bindings used to exist in mpv, but were removed several years ago; I don't know if those still exist somewhere externally. Maybe someone's tried writing Ruby or JS bindings for it, crazier things have happened. Python is the thing that provides the ability to execute scripts, not VapourSynth/VSScript[.dll|.so|.dylib] itself. Technically yes, but a library that is not mostly self-contained like for example libx264, but one with massive dependencies to Python. That's why you might not want to link to VapourSynth even if you have packaged it. Additionally VapourSynth can nowadays be installed using pip, so no reason to package it for distros anymore. > As distros probably won't package VapourSynth as it can be installed > using pip, they probably won't build ffmpeg with VapourSynth support, > because they don't have the headers on the build system. > Even when someone decides to build ffmpeg for themself with VapourSynth > support, it will fail unless they have manually build VapourSynth, > because pip won't install any header. > That was my motivation to include those headers. Is there a specific > rule when it is allowed to include headers for external libaries? > Distros don't really care about whether something is installable via pip before providing their own packages, and this was even acknowledged by upstream Python/pip with the recent move to the venv/--break-system-packages thing. What a distro decides to package or not package in conjunction with enabling support for it in FFmpeg relates directly to their native repository system. This would also apply to a project like libdovi; if it's going to be provided and enabled in a distro's FFmpeg package, they aren't going to take the stance of 'users will just install it through their Rust environment first' - the distro will have to provide a package for it for the distro's FFmpeg package to enable it. What I mean before a distro will include something there needs to be a need for that and a maintainer for that package. If people will just use pip no one will ask for that package to be included in the distro and it's difficult to find someone to maintain it. The pip vs. distro packet manager is in my experience mostly a result of an application that is provided by the distro that has Python dependencies to something like numpy. Later the user wants to install a application with pip, but that has a dependency to a newer numpy version. Then the solutions are what you have described. I changed it, so that it loads the library at runtime when a VapourSynth script should be opened, just like AviSynth does. On Windows the DLL from VapourSynth is not installed in the system directory, but the location is stored in the Registry. Therefore I added some code to read that information from the registry. That function is in the wrong place. I thought that to, should it be in /compat as w32registry.h or something like that? > But what exactly should it contain? I could make a function that would be used like get_w32_regsitry_str(HKEY_CURRENT_USER, L"SOFTWARE\\VapourSynth", L"VSScriptDLL"); That would return a utf8 string on success and NULL on failure I would say either unify the logic inside of vs_load_library with the minimum of Windows-specific things still cordoned off behind an ifdef, or move the function (again, still behind an ifdef) to just above where vs_load_library is. It was mainly that putting it inside a big block of header #includes isn't the right place for that. Ah ok, I see. I made it like this to not have platform-specific code at different places, but if it's preferred at another place, that's fine. Have you tested whether simply adding the directory VapourSynth.dll and VSScript.dll reside in to the %PATH% gets around the need to read locations from the registry? Without adding it to the %PATH%, you could use Windows' own DLL loading rules to test it (just plop ffmpeg.exe down in the same directory and run it when navigated into that directory). Yes, that works and is fallback when no registry entries are found (for portable packages). But when a user has installed VapourSynth and wants to use ffmpeg with it it's quite inconvenient to force him to copy the DLL somewhere else. It might also create a problem: When the version of VSScript.dll does not match the version of the installed Vapoursynth (because it was updated) that could cause a
[FFmpeg-devel] [PATCH v2] libavformat/vapoursynth: Update to API version 4, load library at runtime
Hello, this is revised patch, to sum up the changes: The current VapourSynth implementation is rarely used, as it links the VapourSynth library at build time, making the resulting build unable to run when VapourSynth is not installed. Therefore barely anyone compiles with VapourSynth activated. I changed it, so that it loads the library at runtime when a VapourSynth script should be opened, just like AviSynth does. On Windows the DLL from VapourSynth is not installed in the system directory, but the location is stored in the Registry. Therefore I added some code to read that information from the registry. As the V4 API is designed with dynamic loading in mind (only a single import), I updated the implementation to V4 (changes are mostly superficial, no structural changes). The V4 API is already several years old, fully supported since R55 released in 2021. Changes from first patch: -Separated the Windows-specific function for getting the DLL location from the platform-specific includes -It is not enabled by default in configure -The header files are not included anymore I would like to include the header files for this reason: While most Linux distributions ship ffmpeg, only very few contain VapourSynth. Therefore ffmpeg won't be compiled with VapourSynth support by these distributions, because no VapourSynth headers. Including the headers in ffmpeg would mean they can compile with VapourSynth support and if a user decided to install VapourSynth from somewhere else or compile it by himself, ffmpeg support would be ready and no need for the user to install another ffmpeg or compile one. I'm not sure what the rules for shipping include files are, as there are a few 3rd-party include files in ffmpeg. License is not an issue (Vapourynth is LGPL v2.1 or later like ffmpeg). make fate runs without any issue. I tested VapourSynth input scripts with various color formats on different platforms: Ubuntu 22.04 macOS 13 (x86_64) macOS 13 (arm64) Windows 10 (msys2/gcc) It compiles on these platforms without any warning and runs without any issues. Best regards Stefan From 759b097865953ee66949ecbcdadbebfad623c29a Mon Sep 17 00:00:00 2001 From: Stefan Oltmanns Date: Sat, 6 Jul 2024 22:56:53 +0200 Subject: [PATCH] avformat/vapoursynth: Update to API version 4, load library at runtime Signed-off-by: Stefan Oltmanns --- configure | 3 +- libavformat/vapoursynth.c | 171 +- 2 files changed, 136 insertions(+), 38 deletions(-) diff --git a/configure b/configure index b28221f258..e43f3827ec 100755 --- a/configure +++ b/configure @@ -3575,6 +3575,7 @@ libxevd_decoder_deps="libxevd" libxeve_encoder_deps="libxeve" libxvid_encoder_deps="libxvid" libzvbi_teletext_decoder_deps="libzvbi" +vapoursynth_deps_any="libdl LoadLibrary" vapoursynth_demuxer_deps="vapoursynth" videotoolbox_suggest="coreservices" videotoolbox_deps="corefoundation coremedia corevideo" @@ -7080,7 +7081,7 @@ enabled rkmpp && { require_pkg_config rkmpp rockchip_mpp rockchip/r { enabled libdrm || die "ERROR: rkmpp requires --enable-libdrm"; } } -enabled vapoursynth && require_pkg_config vapoursynth "vapoursynth-script >= 42" VSScript.h vsscript_init +enabled vapoursynth && require_headers "vapoursynth/VSScript4.h vapoursynth/VapourSynth4.h" if enabled gcrypt; then diff --git a/libavformat/vapoursynth.c b/libavformat/vapoursynth.c index 8a2519e19a..9c82f8f3b8 100644 --- a/libavformat/vapoursynth.c +++ b/libavformat/vapoursynth.c @@ -25,9 +25,6 @@ #include -#include -#include - #include "libavutil/avassert.h" #include "libavutil/avstring.h" #include "libavutil/eval.h" @@ -40,19 +37,46 @@ #include "demux.h" #include "internal.h" +/* Platform-specific directives. */ +#ifdef _WIN32 + #include + #include "compat/w32dlfcn.h" + #include "libavutil/wchar_filename.h" + #undef EXTERN_C + #define VSSCRIPT_LIB "VSScript.dll" + #define VS_DLOPEN() ({ void *handle = NULL; \ +char *dll_name = get_vs_script_dll_name(); \ +handle = dlopen(dll_name, RTLD_NOW | RTLD_GLOBAL); \ +av_free(dll_name); \ +handle; }) +#else + #include + #define VSSCRIPT_NAME "libvapoursynth-script" + #define VSSCRIPT_LIB VSSCRIPT_NAME SLIBSUF + #define VS_DLOPEN() dlopen(VSSCRIPT_LIB, RTLD_NOW | RTLD_GLOBAL) +#endif + +#include + struct VSState { VSScript *vss; }; +typedef const VSSCRIPTAPI *(*VSScriptGetAPIFunc)(int version); + +typedef struct VSScriptLibrary { +void *library; +const VSSCRIPTAPI *vssapi; +} VSScriptLibrary; + typedef struct VSContext { const AVClass *class; AVBufferRef *vss_state; const VSAPI *vsapi; -VSCore *vscore; -VSNodeRef *outnode; +VSNode *outnode; int is_cfr; int current_frame; @@ -70,19 +94,72 @@ s
Re: [FFmpeg-devel] [PATCH v2] libavformat/vapoursynth: Update to API version 4, load library at runtime
Hello, I adressed the issues/concerns that were raised with the first revision of the patch. Any feedback? Did I do something wrong? Best regards Stefan Am 06.07.24 um 23:08 schrieb Stefan Oltmanns via ffmpeg-devel: Hello, this is revised patch, to sum up the changes: The current VapourSynth implementation is rarely used, as it links the VapourSynth library at build time, making the resulting build unable to run when VapourSynth is not installed. Therefore barely anyone compiles with VapourSynth activated. I changed it, so that it loads the library at runtime when a VapourSynth script should be opened, just like AviSynth does. On Windows the DLL from VapourSynth is not installed in the system directory, but the location is stored in the Registry. Therefore I added some code to read that information from the registry. As the V4 API is designed with dynamic loading in mind (only a single import), I updated the implementation to V4 (changes are mostly superficial, no structural changes). The V4 API is already several years old, fully supported since R55 released in 2021. Changes from first patch: -Separated the Windows-specific function for getting the DLL location from the platform-specific includes -It is not enabled by default in configure -The header files are not included anymore I would like to include the header files for this reason: While most Linux distributions ship ffmpeg, only very few contain VapourSynth. Therefore ffmpeg won't be compiled with VapourSynth support by these distributions, because no VapourSynth headers. Including the headers in ffmpeg would mean they can compile with VapourSynth support and if a user decided to install VapourSynth from somewhere else or compile it by himself, ffmpeg support would be ready and no need for the user to install another ffmpeg or compile one. I'm not sure what the rules for shipping include files are, as there are a few 3rd-party include files in ffmpeg. License is not an issue (Vapourynth is LGPL v2.1 or later like ffmpeg). make fate runs without any issue. I tested VapourSynth input scripts with various color formats on different platforms: Ubuntu 22.04 macOS 13 (x86_64) macOS 13 (arm64) Windows 10 (msys2/gcc) It compiles on these platforms without any warning and runs without any issues. Best regards Stefan ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe". ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
Re: [FFmpeg-devel] avisynth as an internal filter, any objections?
AviSynth (or better VapourSynth) as filter sounds great, but is it possible? The reason why input plugins (like FFmpegSource2) in AviSynth/VapourSynth create an index file in a first pass is to allow frame-accurate random access to the video. Also the exact number of frames of a clip has to be known, because I could access that property in VapourSynth. There is a reverse filter in ffmpeg, but there is a warning to not use it on long clips, because every frame needs to be buffered, so I don't think the ffmpeg filter API has the ability to randomly access frames (that for example wouldn't work with stdin). But maybe porting some specific filters like QTGMC (which is probably the best deinterlacer) that don't need that random-access functionality would be possible. Best regards Stefan Am 18.07.24 um 00:37 schrieb Marth64: LOL, Isn't there demuxer already? Also as filter it would be less useful. I haven't actually used QTGMC. I have just read of it but have not had the time to apply it with VapourSynth. But it could be cool. ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe". ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
Re: [FFmpeg-devel] [PATCH v2] libavformat/vapoursynth: Update to API version 4, load library at runtime
Hi Ramiro, Am 18.07.24 um 13:08 schrieb Ramiro Polla: Hi Stefan, [...] + +#include + struct VSState { VSScript *vss; }; +typedef const VSSCRIPTAPI *(*VSScriptGetAPIFunc)(int version); + +typedef struct VSScriptLibrary { + void *library; + const VSSCRIPTAPI *vssapi; +} VSScriptLibrary; + typedef struct VSContext { const AVClass *class; AVBufferRef *vss_state; const VSAPI *vsapi; - VSCore *vscore; - VSNodeRef *outnode; + VSNode *outnode; int is_cfr; int current_frame; @@ -70,19 +94,72 @@ static const AVOption options[] = { {NULL} }; +static VSScriptLibrary vs_script_library; Does vs_script_library have to be a global? I think it has to: ffmpeg allows multiple input files, in case you open two VapourSynth files you want to load the Library only once. This is exactly how it's done for AviSynth. + +static int vs_atexit_called = 0; + +static av_cold void vs_atexit_handler(void); + +#ifdef _WIN32 +static av_cold char* get_vs_script_dll_name(void) { + LONG r; + WCHAR vss_path[512]; + char *vss_path_utf8; + DWORD buf_size = sizeof(vss_path) - 2; + r = RegGetValueW(HKEY_CURRENT_USER, L"SOFTWARE\\VapourSynth", + L"VSScriptDLL", RRF_RT_REG_SZ, NULL, + &vss_path, &buf_size); + if (r == ERROR_SUCCESS && wchartoutf8(vss_path, &vss_path_utf8) == 0) + return vss_path_utf8; + r = RegGetValueW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\VapourSynth", + L"VSScriptDLL", RRF_RT_REG_SZ, NULL, + &vss_path, &buf_size); + if (r == ERROR_SUCCESS && wchartoutf8(vss_path, &vss_path_utf8) == 0) + return vss_path_utf8; + if (wchartoutf8(L"VSScript.dll", &vss_path_utf8) == 0) + return vss_path_utf8; + return 0; +} +#endif Don't fetch the path on the registry on Windows. The user should set the path outside of FFmpeg. How exactly should the user do that? Additional option to ffmpeg? Fetching the path from the registry is the recommended method by the VaopourSynth author. Would it be an acceptable way to move the registry stuff to the Windows specific area (where for example the LoadLibrary stuff is) and create a function to get a UTF-8 string from the registry, so that there is no Windows-style code in the VapourSynth module? + +static av_cold int vs_load_library(void) +{ + VSScriptGetAPIFunc get_vs_script_api; + vs_script_library.library = VS_DLOPEN(); + if (!vs_script_library.library) + return -1; + get_vs_script_api = (VSScriptGetAPIFunc)dlsym(vs_script_library.library, + "getVSScriptAPI"); + if (!get_vs_script_api) { + dlclose(vs_script_library.library); + return -2; + } + vs_script_library.vssapi = get_vs_script_api(VSSCRIPT_API_VERSION); + if (!vs_script_library.vssapi) { + dlclose(vs_script_library.library); + return -3; + } + atexit(vs_atexit_handler); Can you get rid of the call to atexit()? Yes, that should be possible. I just read it was only included in AviSynth to work around a crash at exit caused one specific AviSynth variant. So it's probably save to remove. [...] Could you split the patch into first moving to API 4 and then working on the runtime loading? The first part might be reviewed and merged faster. I can do that. Best regards, Stefan ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
Re: [FFmpeg-devel] [PATCH v2] libavformat/vapoursynth: Update to API version 4, load library at runtime
Hi Ramiro, Am 18.07.24 um 15:04 schrieb Ramiro Polla: [...] +static VSScriptLibrary vs_script_library; Does vs_script_library have to be a global? I think it has to: ffmpeg allows multiple input files, in case you open two VapourSynth files you want to load the Library only once. It should be possible to dlopen()/LoadLibrary() multiple times, and the library only gets really unloaded after the last call to dlclose()/FreeLibrary(). In that case you could move that struct to the context. If it's unavoidable to keep the global, at least add some locks to access it. Yes, that should be possible. I did a quick search at it seems that dlopen()/LoadLibrary() is smart and will not open the same library multiple times, but return the same pointer. As dlclose won't be used anymore when removing the atexit handler, that is not an issue at all. This is exactly how it's done for AviSynth. Perhaps AviSynth is not the best example to follow :) + +static int vs_atexit_called = 0; + +static av_cold void vs_atexit_handler(void); + +#ifdef _WIN32 +static av_cold char* get_vs_script_dll_name(void) { + LONG r; + WCHAR vss_path[512]; + char *vss_path_utf8; + DWORD buf_size = sizeof(vss_path) - 2; + r = RegGetValueW(HKEY_CURRENT_USER, L"SOFTWARE\\VapourSynth", + L"VSScriptDLL", RRF_RT_REG_SZ, NULL, + &vss_path, &buf_size); + if (r == ERROR_SUCCESS && wchartoutf8(vss_path, &vss_path_utf8) == 0) + return vss_path_utf8; + r = RegGetValueW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\VapourSynth", + L"VSScriptDLL", RRF_RT_REG_SZ, NULL, + &vss_path, &buf_size); + if (r == ERROR_SUCCESS && wchartoutf8(vss_path, &vss_path_utf8) == 0) + return vss_path_utf8; + if (wchartoutf8(L"VSScript.dll", &vss_path_utf8) == 0) + return vss_path_utf8; + return 0; +} +#endif Don't fetch the path on the registry on Windows. The user should set the path outside of FFmpeg. How exactly should the user do that? Additional option to ffmpeg? By making sure the libraries are accessible in the PATH environment variable. For example by adding the VapourSynth path to the PATH environment variable, or overriding PATH on the call to FFmpeg on a script. Either way that's outside the scope of FFmpeg. Well, the DLL directory is added to PATH by the VapourSynth installer, but for safety reasons ffmpeg explictly tells the LoadLibrary function to only search the application directory and system32, quote from w32dlfcn.h: /** * Safe function used to open dynamic libs. This attempts to improve program security * by removing the current directory from the dll search path. Only dll's found in the * executable or system directory are allowed to be loaded. * @param name The dynamic lib name. * @return A handle to the opened lib. */ So ffmpeg prevents that solution on purpose. Or should that behavior be changed in the w32dlfcn.h? Best regards Stefan ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
Re: [FFmpeg-devel] [PATCH v2] libavformat/vapoursynth: Update to API version 4, load library at runtime
Am 18.07.24 um 16:21 schrieb Ramiro Polla: On Thu, Jul 18, 2024 at 3:41 PM Stefan Oltmanns via ffmpeg-devel wrote: Am 18.07.24 um 15:04 schrieb Ramiro Polla: [...] +static VSScriptLibrary vs_script_library; Does vs_script_library have to be a global? I think it has to: ffmpeg allows multiple input files, in case you open two VapourSynth files you want to load the Library only once. It should be possible to dlopen()/LoadLibrary() multiple times, and the library only gets really unloaded after the last call to dlclose()/FreeLibrary(). In that case you could move that struct to the context. If it's unavoidable to keep the global, at least add some locks to access it. Yes, that should be possible. I did a quick search at it seems that dlopen()/LoadLibrary() is smart and will not open the same library multiple times, but return the same pointer. As dlclose won't be used anymore when removing the atexit handler, that is not an issue at all. dlclose() will have to be called at some point (i.e.: in read_close). The AviSynth patch to remove it by Stephen Hutchinson does not introduce it somewhere else. It is now only called directly at the start in case a needed function cannot be loaded from the DLL. From what I read dlclose is only needed if there are any C++ deconstructors or similar stuff that need to be called before exiting the program. dlclose usually won't unload the library anyway (the spec does not require dlclose to do that) This is exactly how it's done for AviSynth. Perhaps AviSynth is not the best example to follow :) Is not using dlclose just another case? + +static int vs_atexit_called = 0; + +static av_cold void vs_atexit_handler(void); + +#ifdef _WIN32 +static av_cold char* get_vs_script_dll_name(void) { + LONG r; + WCHAR vss_path[512]; + char *vss_path_utf8; + DWORD buf_size = sizeof(vss_path) - 2; + r = RegGetValueW(HKEY_CURRENT_USER, L"SOFTWARE\\VapourSynth", + L"VSScriptDLL", RRF_RT_REG_SZ, NULL, + &vss_path, &buf_size); + if (r == ERROR_SUCCESS && wchartoutf8(vss_path, &vss_path_utf8) == 0) + return vss_path_utf8; + r = RegGetValueW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\VapourSynth", + L"VSScriptDLL", RRF_RT_REG_SZ, NULL, + &vss_path, &buf_size); + if (r == ERROR_SUCCESS && wchartoutf8(vss_path, &vss_path_utf8) == 0) + return vss_path_utf8; + if (wchartoutf8(L"VSScript.dll", &vss_path_utf8) == 0) + return vss_path_utf8; + return 0; +} +#endif Don't fetch the path on the registry on Windows. The user should set the path outside of FFmpeg. How exactly should the user do that? Additional option to ffmpeg? By making sure the libraries are accessible in the PATH environment variable. For example by adding the VapourSynth path to the PATH environment variable, or overriding PATH on the call to FFmpeg on a script. Either way that's outside the scope of FFmpeg. Well, the DLL directory is added to PATH by the VapourSynth installer, but for safety reasons ffmpeg explictly tells the LoadLibrary function to only search the application directory and system32, quote from w32dlfcn.h: /** * Safe function used to open dynamic libs. This attempts to improve program security * by removing the current directory from the dll search path. Only dll's found in the * executable or system directory are allowed to be loaded. * @param name The dynamic lib name. * @return A handle to the opened lib. */ So ffmpeg prevents that solution on purpose. Or should that behavior be changed in the w32dlfcn.h? Oh, bummer. I would expect that overriding the PATH environment variable would work kind of like how LD_LIBRARY_PATH works on Linux. I don't know why that was changed. I don't really follow what goes on in Windowsland anymore. Does anyone else care to comment on this? Martin, maybe? Usually it would work on Windows that way (there is a list of all directories it looks in what order). ffmpeg changes the default behavior. Best regards Stefan ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
Re: [FFmpeg-devel] [PATCH v2] libavformat/vapoursynth: Update to API version 4, load library at runtime
Hello Anton, can you eloborate on that? What is unacceptable with my patch that is perfectly fine in the AviSynth input module? It's the very same concept. Loading the library at runtime makes it so much more useful, because you can distribute ffmpeg binaries without forcing the user to install VapourSynth (which requires the user to install Python). VapourSynth is not just a library like x264 that you can link in statically if you like, VapourSynth is a frame server (like AviSynth) with it's own dependencies. If you worry about platforms that do not support loading libraries at runtime: VapourSynth is based on plugins that are loaded on runtime, so it won't work on those platforms anyway. Best regards Stefan Am 18.07.24 um 13:25 schrieb Anton Khirnov: Quoting Stefan Oltmanns via ffmpeg-devel (2024-07-18 11:37:56) Hello, I adressed the issues/concerns that were raised with the first revision of the patch. Any feedback? Did I do something wrong? I dislike the concept in general, not to mention adding unacceptable global state. ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
Re: [FFmpeg-devel] [PATCH v2] libavformat/vapoursynth: Update to API version 4, load library at runtime
Am 18.07.24 um 17:23 schrieb epira...@gmail.com: Well, the DLL directory is added to PATH by the VapourSynth installer, but for safety reasons ffmpeg explictly tells the LoadLibrary function to only search the application directory and system32, quote from w32dlfcn.h: /** * Safe function used to open dynamic libs. This attempts to improve program security * by removing the current directory from the dll search path. Only dll's found in the * executable or system directory are allowed to be loaded. * @param name The dynamic lib name. * @return A handle to the opened lib. */ So ffmpeg prevents that solution on purpose. Or should that behavior be changed in the w32dlfcn.h? Oh, bummer. I would expect that overriding the PATH environment variable would work kind of like how LD_LIBRARY_PATH works on Linux. I don't know why that was changed. I don't really follow what goes on in Windowsland anymore. Does anyone else care to comment on this? Martin, maybe? IIRC this is done to prevent DLL injection attacks https://learn.microsoft.com/en-us/windows/win32/dlls/dynamic-link-library-security So what's your proposal how to continue? I see different options with pros&cons: 1. Read the DLL path from registry, function for that could be located outside the VapourSynth module. Pro: Safest method to protect from DLL-injection Con: A lot of custom code/functionality for Windows 2. Change w32dlfcn.h to allow loading DLLs from PATH Pro: Minimal code-change, highest similarity between different OSes Con: Open for DLL-injection attacks the current implementations wants to prevent. 3. Allow loading DLLs from PATH with a special flag when calling dlopen. dlopen has a parameter for flags, we could define a WIN_ALLOW_LOAD_DLL_FROM_PATH for Windows that will enable load from PATH Pro: Reduced risk for DLL-injection attack, high similarity between different OSes Con: Flag needs to be defined 0 for other OSes, Posix flags need to be defined 0 for Windows (currently not needed, as the flags are thrown away by the pre-processor) Best regards Stefan ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
Re: [FFmpeg-devel] [PATCH v2] libavformat/vapoursynth: Update to API version 4, load library at runtime
Am 22.07.24 um 00:15 schrieb Hendrik Leppkes: On Mon, Jul 22, 2024 at 12:08 AM Stefan Oltmanns via ffmpeg-devel wrote: Am 18.07.24 um 17:23 schrieb epira...@gmail.com: Well, the DLL directory is added to PATH by the VapourSynth installer, but for safety reasons ffmpeg explictly tells the LoadLibrary function to only search the application directory and system32, quote from w32dlfcn.h: /** * Safe function used to open dynamic libs. This attempts to improve program security * by removing the current directory from the dll search path. Only dll's found in the * executable or system directory are allowed to be loaded. * @param name The dynamic lib name. * @return A handle to the opened lib. */ So ffmpeg prevents that solution on purpose. Or should that behavior be changed in the w32dlfcn.h? Oh, bummer. I would expect that overriding the PATH environment variable would work kind of like how LD_LIBRARY_PATH works on Linux. I don't know why that was changed. I don't really follow what goes on in Windowsland anymore. Does anyone else care to comment on this? Martin, maybe? IIRC this is done to prevent DLL injection attacks https://learn.microsoft.com/en-us/windows/win32/dlls/dynamic-link-library-security So what's your proposal how to continue? I see different options with pros&cons: 1. Read the DLL path from registry, function for that could be located outside the VapourSynth module. Pro: Safest method to protect from DLL-injection Con: A lot of custom code/functionality for Windows Relaxing security considerations to avoid a 10 line function seems not worth it to me. So go with actually finding the correct path. Ok, should that function remain in the vapoursynth module, or should handling the registry be done in a header like "compat/w32registry.h"? An external file with a universal function would of course require more code. Best regards Stefan ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
Re: [FFmpeg-devel] [PATCH v2] libavformat/vapoursynth: Update to API version 4, load library at runtime
Am 22.07.24 um 14:13 schrieb Ramiro Polla: On Mon, Jul 22, 2024 at 12:15 AM Hendrik Leppkes wrote: On Mon, Jul 22, 2024 at 12:08 AM Stefan Oltmanns via ffmpeg-devel wrote: Am 18.07.24 um 17:23 schrieb epira...@gmail.com: Well, the DLL directory is added to PATH by the VapourSynth installer, but for safety reasons ffmpeg explictly tells the LoadLibrary function to only search the application directory and system32, quote from w32dlfcn.h: /** * Safe function used to open dynamic libs. This attempts to improve program security * by removing the current directory from the dll search path. Only dll's found in the * executable or system directory are allowed to be loaded. * @param name The dynamic lib name. * @return A handle to the opened lib. */ So ffmpeg prevents that solution on purpose. Or should that behavior be changed in the w32dlfcn.h? Oh, bummer. I would expect that overriding the PATH environment variable would work kind of like how LD_LIBRARY_PATH works on Linux. I don't know why that was changed. I don't really follow what goes on in Windowsland anymore. Does anyone else care to comment on this? Martin, maybe? IIRC this is done to prevent DLL injection attacks https://learn.microsoft.com/en-us/windows/win32/dlls/dynamic-link-library-security So what's your proposal how to continue? I see different options with pros&cons: 1. Read the DLL path from registry, function for that could be located outside the VapourSynth module. Pro: Safest method to protect from DLL-injection Con: A lot of custom code/functionality for Windows Relaxing security considerations to avoid a 10 line function seems not worth it to me. So go with actually finding the correct path. I would prefer changing w32dlfcn.h to allow loading DLLs from PATH. Limiting to only the directory of the executable and system32 seems too excessive to me. Removing the current working directory is more understandable, but it's perfectly fine to expect PATH to be searched. Also, we don't have such restrictions on other platforms. (DY)LD_LIBRARY_PATH still work as expected. I had a look at the documentation from LoadLibrary: That does not seem to be an option, you cannot explicitly allow PATH. If you want to allow PATH, you need the option for default search directories and that will also include the current working directory. You can use custom search paths (that's what ffmpeg does for older Windows where these flags don't exist), but those have to be explicit, so no help here. Best regards Stefan ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
Re: [FFmpeg-devel] [PATCH v2] libavformat/vapoursynth: Update to API version 4, load library at runtime
Am 22.07.24 um 08:57 schrieb Anton Khirnov: Quoting Stefan Oltmanns (2024-07-18 14:12:42) Hello Anton, can you eloborate on that? What is unacceptable with my patch that is perfectly fine in the AviSynth input module? It's the very same concept. It's not perfectly fine in avisynth, I dislike it there as well. There are also recent patches that remove the atexit handler. The atexit will be removed in the next revision of the patch. Loading the library at runtime makes it so much more useful, because you can distribute ffmpeg binaries without forcing the user to install VapourSynth (which requires the user to install Python). Runtime loading hides dependencies from standard tools and makes program behaviour harder to analyze. Not to mention you're adding a bunch of global state, which is evil. All global states will be removed in the next revision of the patch. It's the intention of my patch to reduce ("hide") the VapourSynth dependency, so unless you want to actually open a VapourSynth script there is no dependency to it. If you try to open a VapourScript script without having VapourSynth installed, you'll get an error message. VapourSynth itself has unclear dependencies, it will load plug-ins on runtime and as it uses Python you can in fact load other Python libaries, for example AI stuff like PyTorch for fancy upscaling, that will then load CUDA/ROCM. VapourSynth is not just a library like x264 that you can link in statically if you like, VapourSynth is a frame server (like AviSynth) with it's own dependencies. If you worry about platforms that do not support loading libraries at runtime: VapourSynth is based on plugins that are loaded on runtime, so it won't work on those platforms anyway. I am worried about special "demuxers" than are not really demuxers and don't work like other demuxers, hence massively increasing library maintenance load. I somewhat agree here, when I first saw a AviSynth demuxer in the list of supported formats it looked weird, because it's not a format that you demux. But what's the solution? Create a new library like "avframeserver" for 2 (?) different tools? How do they increase the maintinace load? There are a lot of external libraries that get used by ffmpeg, what's the difference here? As these formats do not contain any advanced video codec, but raw video, shouldn't it be rather easy to maintain, because no weird complications with some decoder? Best regards Stefan ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
[FFmpeg-devel] [PATCH v3 1/2] libavformat/vapoursynth: Update to API version 4, load library at runtime
Hello, this is revised patch, this is the first part that just updates to the API v4 of VapourSynth. Changes in API v4: -All functions previously in header are now part of the "vssapi" object -Renames of different types and functions -YCoCg is not treated as different format to YUV anymore -Some pointers to arrays are now arrays inside a struct. Best regards Stefan From 164a440ffbb5951ca38bfff56e7b62bd677d1f52 Mon Sep 17 00:00:00 2001 From: Stefan Oltmanns Date: Tue, 23 Jul 2024 16:15:36 +0200 Subject: [PATCH 1/2] avformat/vapoursynth: Update to API version 4 Signed-off-by: Stefan Oltmanns --- configure | 2 +- libavformat/vapoursynth.c | 84 +-- 2 files changed, 46 insertions(+), 40 deletions(-) diff --git a/configure b/configure index f6f5c29fea..c50b5ad4b4 100755 --- a/configure +++ b/configure @@ -7085,7 +7085,7 @@ enabled rkmpp && { require_pkg_config rkmpp rockchip_mpp rockchip/r { enabled libdrm || die "ERROR: rkmpp requires --enable-libdrm"; } } -enabled vapoursynth && require_pkg_config vapoursynth "vapoursynth-script >= 42" VSScript.h vsscript_init +enabled vapoursynth && require_pkg_config vapoursynth "vapoursynth-script >= 55" VSScript4.h getVSScriptAPI if enabled gcrypt; then diff --git a/libavformat/vapoursynth.c b/libavformat/vapoursynth.c index 8a2519e19a..ce15f68180 100644 --- a/libavformat/vapoursynth.c +++ b/libavformat/vapoursynth.c @@ -25,8 +25,7 @@ #include -#include -#include +#include #include "libavutil/avassert.h" #include "libavutil/avstring.h" @@ -41,6 +40,7 @@ #include "internal.h" struct VSState { +const VSSCRIPTAPI *vssapi; VSScript *vss; }; @@ -49,10 +49,10 @@ typedef struct VSContext { AVBufferRef *vss_state; +const VSSCRIPTAPI *vssapi; const VSAPI *vsapi; -VSCore *vscore; -VSNodeRef *outnode; +VSNode *outnode; int is_cfr; int current_frame; @@ -75,8 +75,7 @@ static void free_vss_state(void *opaque, uint8_t *data) struct VSState *vss = opaque; if (vss->vss) { -vsscript_freeScript(vss->vss); -vsscript_finalize(); +vss->vssapi->freeScript(vss->vss); } } @@ -90,7 +89,6 @@ static av_cold int read_close_vs(AVFormatContext *s) av_buffer_unref(&vs->vss_state); vs->vsapi = NULL; -vs->vscore = NULL; vs->outnode = NULL; return 0; @@ -106,7 +104,7 @@ static av_cold int is_native_endian(enum AVPixelFormat pixfmt) return pd && (!!HAVE_BIGENDIAN == !!(pd->flags & AV_PIX_FMT_FLAG_BE)); } -static av_cold enum AVPixelFormat match_pixfmt(const VSFormat *vsf, int c_order[4]) +static av_cold enum AVPixelFormat match_pixfmt(const VSVideoFormat *vsf, int c_order[4]) { static const int yuv_order[4] = {0, 1, 2, 0}; static const int rgb_order[4] = {1, 2, 0, 0}; @@ -128,13 +126,12 @@ static av_cold enum AVPixelFormat match_pixfmt(const VSFormat *vsf, int c_order[ pd->log2_chroma_h != vsf->subSamplingH) continue; -is_rgb = vsf->colorFamily == cmRGB; +is_rgb = vsf->colorFamily == cfRGB; if (is_rgb != !!(pd->flags & AV_PIX_FMT_FLAG_RGB)) continue; -is_yuv = vsf->colorFamily == cmYUV || - vsf->colorFamily == cmYCoCg || - vsf->colorFamily == cmGray; +is_yuv = vsf->colorFamily == cfYUV || + vsf->colorFamily == cfGray; if (!is_rgb && !is_yuv) continue; @@ -176,15 +173,30 @@ static av_cold int read_header_vs(AVFormatContext *s) int64_t sz = avio_size(pb); char *buf = NULL; char dummy; +char vsfmt[32]; const VSVideoInfo *info; struct VSState *vss_state; int err = 0; +if (!(vs->vssapi = getVSScriptAPI(VSSCRIPT_API_VERSION))) { +av_log(s, AV_LOG_ERROR, "Failed to initialize VSScript (possibly PYTHONPATH not set).\n"); +err = AVERROR_EXTERNAL; +goto done; +} + +if (!(vs->vsapi = vs->vssapi->getVSAPI(VAPOURSYNTH_API_VERSION))) { +av_log(s, AV_LOG_ERROR, "Could not get VSAPI. " +"Check VapourSynth installation.\n"); +err = AVERROR_EXTERNAL; +goto done; +} + vss_state = av_mallocz(sizeof(*vss_state)); if (!vss_state) { err = AVERROR(ENOMEM); goto done; } +vss_state->vssapi = vs->vssapi; vs->vss_state = av_buffer_create(NULL, 0, free_vss_state, vss_state, 0); if (!vs->vss_state) { @@ -193,16 +205,9 @@ static av_cold int read_header_vs(AVFormatContext *s) goto done; } -if (!vsscript_init()) { -av_log(s, AV_LOG_ERROR, "Failed to initialize VSScript (possibly PYTHONPATH not set).\n"); -err = AVERROR_EXTERNAL; -goto done; -} - -if (vsscript_createScript(&vss_state->vss)) { +if (!(vss_stat
Re: [FFmpeg-devel] [PATCH v3 2/2] libavformat/vapoursynth: Update to API version 4, load library at runtime
This is the second part for loading the library at runtime, changes compared to previous patch revisions: -No atexit anymore -No global states anymore -Moved the registry read for Windows from a separate function inside the function to load the dynamic library and simplified it, reducing the amount windows-specific code. Tested with 2 VapourSynth inputs on these platforms, no problems and clean exit: -Linux x86_64 (Ubuntu 22.04) -Windows 10 x86_64 -macOS 14 aarch64 Best regards Stefan Am 23.07.24 um 16:51 schrieb Stefan Oltmanns via ffmpeg-devel: Hello, this is revised patch, this is the first part that just updates to the API v4 of VapourSynth. Changes in API v4: -All functions previously in header are now part of the "vssapi" object -Renames of different types and functions -YCoCg is not treated as different format to YUV anymore -Some pointers to arrays are now arrays inside a struct. Best regards Stefan ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe". From 6a8e8b7d5bfcfb8eb3cb24ea1f7e14ca117882c4 Mon Sep 17 00:00:00 2001 From: Stefan Oltmanns Date: Tue, 23 Jul 2024 16:19:46 +0200 Subject: [PATCH 2/2] avformat/vapoursynth: load library at runtime Signed-off-by: Stefan Oltmanns --- configure | 2 +- libavformat/vapoursynth.c | 65 +-- 2 files changed, 64 insertions(+), 3 deletions(-) diff --git a/configure b/configure index c50b5ad4b4..1b6670505a 100755 --- a/configure +++ b/configure @@ -7085,7 +7085,7 @@ enabled rkmpp && { require_pkg_config rkmpp rockchip_mpp rockchip/r { enabled libdrm || die "ERROR: rkmpp requires --enable-libdrm"; } } -enabled vapoursynth && require_pkg_config vapoursynth "vapoursynth-script >= 55" VSScript4.h getVSScriptAPI +enabled vapoursynth && require_headers "vapoursynth/VSScript4.h vapoursynth/VapourSynth4.h" if enabled gcrypt; then diff --git a/libavformat/vapoursynth.c b/libavformat/vapoursynth.c index ce15f68180..ad1d6eac61 100644 --- a/libavformat/vapoursynth.c +++ b/libavformat/vapoursynth.c @@ -25,7 +25,7 @@ #include -#include +#include #include "libavutil/avassert.h" #include "libavutil/avstring.h" @@ -39,11 +39,26 @@ #include "demux.h" #include "internal.h" +/* Platform-specific directives. */ +#ifdef _WIN32 + #include + #include "compat/w32dlfcn.h" + #include "libavutil/wchar_filename.h" + #undef EXTERN_C + #define VSSCRIPT_LIB "VSScript.dll" +#else + #include + #define VSSCRIPT_NAME "libvapoursynth-script" + #define VSSCRIPT_LIB VSSCRIPT_NAME SLIBSUF +#endif + struct VSState { const VSSCRIPTAPI *vssapi; VSScript *vss; }; +typedef const VSSCRIPTAPI *(*VSScriptGetAPIFunc)(int version); + typedef struct VSContext { const AVClass *class; @@ -51,6 +66,7 @@ typedef struct VSContext { const VSSCRIPTAPI *vssapi; const VSAPI *vsapi; +void *vslibrary; VSNode *outnode; int is_cfr; @@ -70,6 +86,40 @@ static const AVOption options[] = { {NULL} }; +static av_cold void* vs_load_library(VSScriptGetAPIFunc *get_vssapi) +{ +void *vslibrary = NULL; +#ifdef _WIN32 +const HKEY hkeys[] = {HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE}; +LONG r; +WCHAR vss_path[512]; +DWORD buf_size = sizeof(vss_path) - 2; +char *vss_path_utf8; +int i; + +for (i = 0; i < sizeof(hkeys); i++) { +if ((r = RegGetValueW(hkeys[i], L"SOFTWARE\\VapourSynth", + L"VSScriptDLL", RRF_RT_REG_SZ, NULL, + &vss_path, &buf_size)) == ERROR_SUCCESS) +break; +} +if (r == ERROR_SUCCESS && wchartoutf8(vss_path, &vss_path_utf8) == 0) { +vslibrary = dlopen(vss_path_utf8, RTLD_NOW | RTLD_GLOBAL); +av_free(vss_path_utf8); +} +else +#endif +vslibrary = dlopen(VSSCRIPT_LIB, RTLD_NOW | RTLD_GLOBAL); + +if (vslibrary != NULL) { +if (!(*get_vssapi = (VSScriptGetAPIFunc)dlsym(vslibrary, "getVSScriptAPI"))) { +dlclose(vslibrary); +return NULL; +} +} +return vslibrary; +} + static void free_vss_state(void *opaque, uint8_t *data) { struct VSState *vss = opaque; @@ -91,6 +141,9 @@ static av_cold int read_close_vs(AVFormatContext *s) vs->vsapi = NULL; vs->outnode = NULL; +if (vs->vslibrary) +dlclose(vs->vslibrary); + return 0; } @@ -170,6 +223,7 @@ static av_cold int read_header_vs(AVFormatContext *s) AVStream *st; A
Re: [FFmpeg-devel] [PATCH v4 1/2] libavformat/vapoursynth: Update to API version 4, load library at runtime
Am 28.07.24 um 15:09 schrieb Ramiro Polla: if (st->codecpar->format == AV_PIX_FMT_NONE) { - av_log(s, AV_LOG_ERROR, "Unsupported VS pixel format %s\n", info->format->name); + if(vs->vsapi->getVideoFormatName(&info->format, vsfmt)) + av_log(s, AV_LOG_ERROR, "Unsupported VS pixel format %s\n", vsfmt); + else + av_log(s, AV_LOG_ERROR, "Unsupported VS pixel format\n"); err = AVERROR_EXTERNAL; goto done; } - av_log(s, AV_LOG_VERBOSE, "VS format %s -> pixfmt %s\n", info->format->name, - av_get_pix_fmt_name(st->codecpar->format)); - - if (info->format->colorFamily == cmYCoCg) - st->codecpar->color_space = AVCOL_SPC_YCGCO; + if (vs->vsapi->getVideoFormatName(&info->format, vsfmt)) + av_log(s, AV_LOG_VERBOSE, "VS format %s -> pixfmt %s\n", + vsfmt, av_get_pix_fmt_name(st->codecpar->format)); + else + av_log(s, AV_LOG_VERBOSE, "VS format -> pixfmt %s\n", + av_get_pix_fmt_name(st->codecpar->format)); Could you change this to have a single call go av_log()? Possibly using a %s with a string for the unknown format. Same thing for the other av_log() above. [...] It now prints "(unknown)" for a video format that VapourSynth cannot resolve. "(unknown)" is also printed at other places in ffmpeg in similar cases, so it's consistent. Also could you give us a very minimal test script to test this? I have attached a minimal test script, it will generate 10 frames each black, red, green, blue in 640x480, RGB24 Best regards Stefan From 2279d2e225c665cab68d26652e1cca4fdf04faaa Mon Sep 17 00:00:00 2001 From: Stefan Oltmanns Date: Mon, 29 Jul 2024 05:08:57 +0200 Subject: [PATCH 1/2] avformat/vapoursynth: Update to API version 4 Signed-off-by: Stefan Oltmanns --- configure | 2 +- libavformat/vapoursynth.c | 77 --- 2 files changed, 40 insertions(+), 39 deletions(-) diff --git a/configure b/configure index f6f5c29fea..c50b5ad4b4 100755 --- a/configure +++ b/configure @@ -7085,7 +7085,7 @@ enabled rkmpp && { require_pkg_config rkmpp rockchip_mpp rockchip/r { enabled libdrm || die "ERROR: rkmpp requires --enable-libdrm"; } } -enabled vapoursynth && require_pkg_config vapoursynth "vapoursynth-script >= 42" VSScript.h vsscript_init +enabled vapoursynth && require_pkg_config vapoursynth "vapoursynth-script >= 55" VSScript4.h getVSScriptAPI if enabled gcrypt; then diff --git a/libavformat/vapoursynth.c b/libavformat/vapoursynth.c index 8a2519e19a..26c9986138 100644 --- a/libavformat/vapoursynth.c +++ b/libavformat/vapoursynth.c @@ -25,8 +25,7 @@ #include -#include -#include +#include #include "libavutil/avassert.h" #include "libavutil/avstring.h" @@ -41,6 +40,7 @@ #include "internal.h" struct VSState { +const VSSCRIPTAPI *vssapi; VSScript *vss; }; @@ -49,10 +49,10 @@ typedef struct VSContext { AVBufferRef *vss_state; +const VSSCRIPTAPI *vssapi; const VSAPI *vsapi; -VSCore *vscore; -VSNodeRef *outnode; +VSNode *outnode; int is_cfr; int current_frame; @@ -75,8 +75,7 @@ static void free_vss_state(void *opaque, uint8_t *data) struct VSState *vss = opaque; if (vss->vss) { -vsscript_freeScript(vss->vss); -vsscript_finalize(); +vss->vssapi->freeScript(vss->vss); } } @@ -90,7 +89,6 @@ static av_cold int read_close_vs(AVFormatContext *s) av_buffer_unref(&vs->vss_state); vs->vsapi = NULL; -vs->vscore = NULL; vs->outnode = NULL; return 0; @@ -106,7 +104,7 @@ static av_cold int is_native_endian(enum AVPixelFormat pixfmt) return pd && (!!HAVE_BIGENDIAN == !!(pd->flags & AV_PIX_FMT_FLAG_BE)); } -static av_cold enum AVPixelFormat match_pixfmt(const VSFormat *vsf, int c_order[4]) +static av_cold enum AVPixelFormat match_pixfmt(const VSVideoFormat *vsf, int c_order[4]) { static const int yuv_order[4] = {0, 1, 2, 0}; static const int rgb_order[4] = {1, 2, 0, 0}; @@ -128,13 +126,12 @@ static av_cold enum AVPixelFormat match_pixfmt(const VSFormat *vsf, int c_order[ pd->log2_chroma_h != vsf->subSamplingH) continue; -is_rgb = vsf->colorFamily == cmRGB; +is_rgb = vsf->colorFamily == cfRGB; if (is_rgb != !!(pd->flags & AV_PIX_FMT_FLAG_RGB)) continue; -is_yuv = vsf->colorFamily == cmYUV || - vsf->colorFamily == cmYCoCg || - vsf->colorFamily == cmGray; +is_yuv = vsf->colorFamily == cfYUV || + vsf->colorFamily == cfGray; if (!is_rgb && !is_yuv) continue; @@ -176,15 +173,30 @@ static av_cold int read_header_vs(AVFormatContext *s) int64_t sz = avio_size(pb); char *buf = NULL; char dummy; +char vsfmt[3
Re: [FFmpeg-devel] [PATCH v3 2/2] libavformat/vapoursynth: Update to API version 4, load library at runtime
Am 28.07.24 um 15:15 schrieb Ramiro Polla: + void *vslibrary = NULL; +#ifdef _WIN32 + const HKEY hkeys[] = {HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE}; + LONG r; + WCHAR vss_path[512]; + DWORD buf_size = sizeof(vss_path) - 2; + char *vss_path_utf8; + int i; + + for (i = 0; i < sizeof(hkeys); i++) { FF_ARRAY_ELEMS(hkeys) fixed + if ((r = RegGetValueW(hkeys[i], L"SOFTWARE\\VapourSynth", + L"VSScriptDLL", RRF_RT_REG_SZ, NULL, + &vss_path, &buf_size)) == ERROR_SUCCESS) + break; + } + if (r == ERROR_SUCCESS && wchartoutf8(vss_path, &vss_path_utf8) == 0) { + vslibrary = dlopen(vss_path_utf8, RTLD_NOW | RTLD_GLOBAL); I think calling win32_dlopen() with a full path will be problematic for systems without KB2533623. win32_dlopen() might need to be fixed in a separate patch. Yes, win32_dlopen would need to check if a full path is already given and if yes skip all the stuff to determine it's own and system32 path, but instead just use the given parameter directly. To check if it's a full path it should be enough to check if it either starts with "\??\" (NT-style path) or if the second character is ":" (win32 style path). But is this really is needed for an operating system that reached support end over 4 years ago and does not have a security patch applied released over 13 years ago? I don't know what ffmpeg's exact policy is in this case, just asking. Best regards Stefan From dc396711d050c112b2ef6c37fdb67c4ec59c16a1 Mon Sep 17 00:00:00 2001 From: Stefan Oltmanns Date: Mon, 29 Jul 2024 05:12:31 +0200 Subject: [PATCH 2/2] avformat/vapoursynth: load library at runtime Signed-off-by: Stefan Oltmanns --- configure | 2 +- libavformat/vapoursynth.c | 65 +-- 2 files changed, 64 insertions(+), 3 deletions(-) diff --git a/configure b/configure index c50b5ad4b4..1b6670505a 100755 --- a/configure +++ b/configure @@ -7085,7 +7085,7 @@ enabled rkmpp && { require_pkg_config rkmpp rockchip_mpp rockchip/r { enabled libdrm || die "ERROR: rkmpp requires --enable-libdrm"; } } -enabled vapoursynth && require_pkg_config vapoursynth "vapoursynth-script >= 55" VSScript4.h getVSScriptAPI +enabled vapoursynth && require_headers "vapoursynth/VSScript4.h vapoursynth/VapourSynth4.h" if enabled gcrypt; then diff --git a/libavformat/vapoursynth.c b/libavformat/vapoursynth.c index 26c9986138..0fa5affa63 100644 --- a/libavformat/vapoursynth.c +++ b/libavformat/vapoursynth.c @@ -25,7 +25,7 @@ #include -#include +#include #include "libavutil/avassert.h" #include "libavutil/avstring.h" @@ -39,11 +39,26 @@ #include "demux.h" #include "internal.h" +/* Platform-specific directives. */ +#ifdef _WIN32 + #include + #include "compat/w32dlfcn.h" + #include "libavutil/wchar_filename.h" + #undef EXTERN_C + #define VSSCRIPT_LIB "VSScript.dll" +#else + #include + #define VSSCRIPT_NAME "libvapoursynth-script" + #define VSSCRIPT_LIB VSSCRIPT_NAME SLIBSUF +#endif + struct VSState { const VSSCRIPTAPI *vssapi; VSScript *vss; }; +typedef const VSSCRIPTAPI *(*VSScriptGetAPIFunc)(int version); + typedef struct VSContext { const AVClass *class; @@ -51,6 +66,7 @@ typedef struct VSContext { const VSSCRIPTAPI *vssapi; const VSAPI *vsapi; +void *vslibrary; VSNode *outnode; int is_cfr; @@ -70,6 +86,40 @@ static const AVOption options[] = { {NULL} }; +static av_cold void* vs_load_library(VSScriptGetAPIFunc *get_vssapi) +{ +void *vslibrary = NULL; +#ifdef _WIN32 +const HKEY hkeys[] = {HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE}; +LONG r; +WCHAR vss_path[512]; +DWORD buf_size = sizeof(vss_path) - 2; +char *vss_path_utf8; +int i; + +for (i = 0; i < FF_ARRAY_ELEMS(hkeys); i++) { +if ((r = RegGetValueW(hkeys[i], L"SOFTWARE\\VapourSynth", + L"VSScriptDLL", RRF_RT_REG_SZ, NULL, + &vss_path, &buf_size)) == ERROR_SUCCESS) +break; +} +if (r == ERROR_SUCCESS && wchartoutf8(vss_path, &vss_path_utf8) == 0) { +vslibrary = dlopen(vss_path_utf8, RTLD_NOW | RTLD_GLOBAL); +av_free(vss_path_utf8); +} +else +#endif +vslibrary = dlopen(VSSCRIPT_LIB, RTLD_NOW | RTLD_GLOBAL); + +if (vslibrary != NULL) { +if (!(*get_vssapi = (VSScriptGetAPIFunc)dlsym(vslibrary, "getVSScriptAPI"))) { +dlclose(vslibrary); +return NULL; +} +} +return vslibrary; +} + static void free_vss_state(void *opaque, uint8_t *data) { struct VSState *vss = opaque; @@ -91,6 +141,9 @@ static av_cold int read_close_vs(AVFormatContext *s) vs->vsapi = NULL; vs->outnode = NULL; +if (vs->vslibrary) +dlclose(vs->vslibrary); + return 0; } @@ -170,6 +223,7 @
Re: [FFmpeg-devel] [PATCH v3 2/2] libavformat/vapoursynth: Update to API version 4, load library at runtime
Am 30.07.24 um 16:12 schrieb Ramiro Polla: On Mon, Jul 29, 2024 at 5:56 AM Stefan Oltmanns via ffmpeg-devel wrote: Am 28.07.24 um 15:15 schrieb Ramiro Polla: I think calling win32_dlopen() with a full path will be problematic for systems without KB2533623. win32_dlopen() might need to be fixed in a separate patch. Yes, win32_dlopen would need to check if a full path is already given and if yes skip all the stuff to determine it's own and system32 path, but instead just use the given parameter directly. To check if it's a full path it should be enough to check if it either starts with "\??\" (NT-style path) or if the second character is ":" (win32 style path). But is this really is needed for an operating system that reached support end over 4 years ago and does not have a security patch applied released over 13 years ago? I don't know what ffmpeg's exact policy is in this case, just asking. Makes sense. I sent a patchset to clean this, but I haven't been able to test on a real Windows system. I'll test the vapoursynth patches later on Linux. Any progress on this? Anything I can do? Best regards Stefan ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
Re: [FFmpeg-devel] [PATCH v3 2/2] libavformat/vapoursynth: Update to API version 4, load library at runtime
Am 23.08.24 um 14:25 schrieb Ramiro Polla: I finally managed to test the patches on a real Windows system. They both look good to me, I'll apply them in a couple of days if there are no other comments. It would be helpful to write a page in the trac wiki with a basic howto and common pitfalls. I had problems installing python and vapoursynth for my user only, and then for all users on the Windows machine. I had to uninstall everything, remove some registry keys, and try again using administrator to install to all users. I also had to manually install Microsoft Visual C++ Redistributable. There was no good error message telling me what was going wrong. When I added an av_log() with FormatMessage() after LoadLibraryW() failed, the error message was also unhelpful. Just to make that clear: You had problem installing Python/VapourSynth on Windows, not with the patch? I know Python can be somewhat problematic on Windows from other contexts, but VapourSynth is usually straight forward. The install guide for VapourSynth lists some problems you may have experienced: http://www.vapoursynth.com/doc/installation.html#windows-installation -Both Python and VapourSynth must be installed as either current user or all users/system -On current user installs it cannot install the required Microsoft Visual C++ Redistributable To ensure installation of VapourSynth worked you can run "vspipe -v", this will show the installed version if it's working or an error message if not. Common issue on Linux/macOS is that the Python package cannot be found, you have to set PYTHONPATH for example like this: PYTHONPATH=/usr/local/lib/python3.12/site-packages ffmpeg will display the PYTHONPATH issue as a possible problem if can find the vapoursynth library, but not initialize it. On recent versions of macOS, it will not look for libraries in /usr/local/lib anymore, you may have to set DYLD_LIBRARY_PATH=/usr/local/lib Best regards Stefan ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".