[FFmpeg-devel] [PATCH v2] libavformat/vapoursynth: Update to API version 4, load library at runtime

Ramiro Polla ramiro.polla at gmail.com
Thu Jul 18 14:08:05 EEST 2024


Hi Stefan,

On 7/6/24 23:08, Stefan Oltmanns via ffmpeg-devel wrote:
> 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.

> From 759b097865953ee66949ecbcdadbebfad623c29a Mon Sep 17 00:00:00 2001
> From: Stefan Oltmanns <stefan-oltmanns at gmx.net>
> 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 <stefan-oltmanns at gmx.net>
> ---
>  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 <limits.h>
>  
> -#include <VapourSynth.h>
> -#include <VSScript.h>
> -
>  #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 <windows.h>
> +  #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 <dlfcn.h>
> +  #define VSSCRIPT_NAME "libvapoursynth-script"
> +  #define VSSCRIPT_LIB VSSCRIPT_NAME SLIBSUF
> +  #define VS_DLOPEN() dlopen(VSSCRIPT_LIB, RTLD_NOW | RTLD_GLOBAL)
> +#endif
> +
> +#include <vapoursynth/VSScript4.h>
> +
>  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?

> +
> +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.

> +
> +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()?

[...]

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.

Ramiro


More information about the ffmpeg-devel mailing list