Message ID | fdcdcdb3-ce6c-4dec-9759-489d1aa501a4@gmx.net |
---|---|
State | New |
Headers | show |
Series | [FFmpeg-devel,v3,1/2] libavformat/vapoursynth: Update to API version 4, load library at runtime | expand |
Context | Check | Description |
---|---|---|
andriy/make_x86 | success | Make finished |
andriy/make_fate_x86 | success | Make fate finished |
On 2024-07-23 16:51, Stefan Oltmanns via ffmpeg-devel wrote: > 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. > From 164a440ffbb5951ca38bfff56e7b62bd677d1f52 Mon Sep 17 00:00:00 2001 > From: Stefan Oltmanns <stefan-oltmanns@gmx.net> > 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 <stefan-oltmanns@gmx.net> > --- > 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 <limits.h> > > -#include <VapourSynth.h> > -#include <VSScript.h> > +#include <VSScript4.h> > > #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_state->vss = vs->vssapi->createScript(NULL))) { > av_log(s, AV_LOG_ERROR, "Failed to create script instance.\n"); > err = AVERROR_EXTERNAL; > - vsscript_finalize(); > goto done; > } > > @@ -235,17 +240,14 @@ static av_cold int read_header_vs(AVFormatContext *s) > } > > buf[sz] = '\0'; > - if (vsscript_evaluateScript(&vss_state->vss, buf, s->url, 0)) { > - const char *msg = vsscript_getError(vss_state->vss); > + if (vs->vssapi->evaluateBuffer(vss_state->vss, buf, s->url)) { > + const char *msg = vs->vssapi->getError(vss_state->vss); > av_log(s, AV_LOG_ERROR, "Failed to parse script: %s\n", msg ? msg : "(unknown)"); > err = AVERROR_EXTERNAL; > goto done; > } > > - vs->vsapi = vsscript_getVSApi(); > - vs->vscore = vsscript_getCore(vss_state->vss); > - > - vs->outnode = vsscript_getOutput(vss_state->vss, 0); > + vs->outnode = vs->vssapi->getOutputNode(vss_state->vss, 0); > if (!vs->outnode) { > av_log(s, AV_LOG_ERROR, "Could not get script output node.\n"); > err = AVERROR_EXTERNAL; > @@ -260,7 +262,7 @@ static av_cold int read_header_vs(AVFormatContext *s) > > info = vs->vsapi->getVideoInfo(vs->outnode); > > - if (!info->format || !info->width || !info->height) { > + if (!info->format.colorFamily || !info->width || !info->height) { > av_log(s, AV_LOG_ERROR, "Non-constant input format not supported.\n"); > err = AVERROR_PATCHWELCOME; > goto done; > @@ -280,18 +282,22 @@ static av_cold int read_header_vs(AVFormatContext *s) > st->codecpar->codec_id = AV_CODEC_ID_WRAPPED_AVFRAME; > st->codecpar->width = info->width; > st->codecpar->height = info->height; > - st->codecpar->format = match_pixfmt(info->format, vs->c_order); > + st->codecpar->format = match_pixfmt(&info->format, vs->c_order); > > 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. [...] Also could you give us a very minimal test script to test this? Regards, Ramiro
On 2024-07-23 16:59, Stefan Oltmanns via ffmpeg-devel wrote: > 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 > From 6a8e8b7d5bfcfb8eb3cb24ea1f7e14ca117882c4 Mon Sep 17 00:00:00 2001 > From: Stefan Oltmanns <stefan-oltmanns@gmx.net> > Date: Tue, 23 Jul 2024 16:19:46 +0200 > Subject: [PATCH 2/2] avformat/vapoursynth: load library at runtime > > Signed-off-by: Stefan Oltmanns <stefan-oltmanns@gmx.net> > --- > 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 <limits.h> > > -#include <VSScript4.h> > +#include <vapoursynth/VSScript4.h> > > #include "libavutil/avassert.h" > #include "libavutil/avstring.h" > @@ -39,11 +39,26 @@ > #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" > +#else > + #include <dlfcn.h> > + #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++) { FF_ARRAY_ELEMS(hkeys) > + 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. [...] Regards, Ramiro
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 import vapoursynth as vs core = vs.core a = core.std.BlankClip(width=640,height=480,length=10) b = core.std.BlankClip(width=640,height=480,length=10,color=[255, 0, 0]) c = core.std.BlankClip(width=640,height=480,length=10,color=[ 0, 255, 0]) d = core.std.BlankClip(width=640,height=480,length=10,color=[ 0, 0, 255]) r = a + b + c + d r.set_output(0)
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
On Mon, Jul 29, 2024 at 5:56 AM Stefan Oltmanns via ffmpeg-devel <ffmpeg-devel@ffmpeg.org> 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. Ramiro
Am 30.07.24 um 16:12 schrieb Ramiro Polla: > On Mon, Jul 29, 2024 at 5:56 AM Stefan Oltmanns via ffmpeg-devel > <ffmpeg-devel@ffmpeg.org> 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
On Tue, Jul 30, 2024 at 4:12 PM Ramiro Polla <ramiro.polla@gmail.com> wrote: > On Mon, Jul 29, 2024 at 5:56 AM Stefan Oltmanns via ffmpeg-devel > <ffmpeg-devel@ffmpeg.org> 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 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. Ramiro
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
On Sat, Aug 24, 2024 at 1:06 PM Stefan Oltmanns via ffmpeg-devel <ffmpeg-devel@ffmpeg.org> wrote: > 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. Applied. Thank you for the patches. > > 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. Yes, it was unrelated to the patch. > 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 Something like this could be added to the wiki.
From 164a440ffbb5951ca38bfff56e7b62bd677d1f52 Mon Sep 17 00:00:00 2001 From: Stefan Oltmanns <stefan-oltmanns@gmx.net> 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 <stefan-oltmanns@gmx.net> --- 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 <limits.h> -#include <VapourSynth.h> -#include <VSScript.h> +#include <VSScript4.h> #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_state->vss = vs->vssapi->createScript(NULL))) { av_log(s, AV_LOG_ERROR, "Failed to create script instance.\n"); err = AVERROR_EXTERNAL; - vsscript_finalize(); goto done; } @@ -235,17 +240,14 @@ static av_cold int read_header_vs(AVFormatContext *s) } buf[sz] = '\0'; - if (vsscript_evaluateScript(&vss_state->vss, buf, s->url, 0)) { - const char *msg = vsscript_getError(vss_state->vss); + if (vs->vssapi->evaluateBuffer(vss_state->vss, buf, s->url)) { + const char *msg = vs->vssapi->getError(vss_state->vss); av_log(s, AV_LOG_ERROR, "Failed to parse script: %s\n", msg ? msg : "(unknown)"); err = AVERROR_EXTERNAL; goto done; } - vs->vsapi = vsscript_getVSApi(); - vs->vscore = vsscript_getCore(vss_state->vss); - - vs->outnode = vsscript_getOutput(vss_state->vss, 0); + vs->outnode = vs->vssapi->getOutputNode(vss_state->vss, 0); if (!vs->outnode) { av_log(s, AV_LOG_ERROR, "Could not get script output node.\n"); err = AVERROR_EXTERNAL; @@ -260,7 +262,7 @@ static av_cold int read_header_vs(AVFormatContext *s) info = vs->vsapi->getVideoInfo(vs->outnode); - if (!info->format || !info->width || !info->height) { + if (!info->format.colorFamily || !info->width || !info->height) { av_log(s, AV_LOG_ERROR, "Non-constant input format not supported.\n"); err = AVERROR_PATCHWELCOME; goto done; @@ -280,18 +282,22 @@ static av_cold int read_header_vs(AVFormatContext *s) st->codecpar->codec_id = AV_CODEC_ID_WRAPPED_AVFRAME; st->codecpar->width = info->width; st->codecpar->height = info->height; - st->codecpar->format = match_pixfmt(info->format, vs->c_order); + st->codecpar->format = match_pixfmt(&info->format, vs->c_order); 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)); done: av_free(buf); @@ -311,13 +317,13 @@ static int get_vs_prop_int(AVFormatContext *s, const VSMap *map, const char *nam int64_t res; int err = 1; - res = vs->vsapi->propGetInt(map, name, 0, &err); + res = vs->vsapi->mapGetInt(map, name, 0, &err); return err || res < INT_MIN || res > INT_MAX ? def : res; } struct vsframe_ref_data { const VSAPI *vsapi; - const VSFrameRef *frame; + const VSFrame *frame; AVBufferRef *vss_state; }; @@ -339,7 +345,7 @@ static int read_packet_vs(AVFormatContext *s, AVPacket *pkt) AVStream *st = s->streams[0]; AVFrame *frame = NULL; char vserr[80]; - const VSFrameRef *vsframe; + const VSFrame *vsframe; const VSVideoInfo *info = vs->vsapi->getVideoInfo(vs->outnode); const VSMap *props; const AVPixFmtDescriptor *desc; @@ -381,7 +387,7 @@ static int read_packet_vs(AVFormatContext *s, AVPacket *pkt) goto end; } - props = vs->vsapi->getFramePropsRO(vsframe); + props = vs->vsapi->getFramePropertiesRO(vsframe); frame = av_frame_alloc(); if (!frame) { @@ -410,7 +416,7 @@ static int read_packet_vs(AVFormatContext *s, AVPacket *pkt) desc = av_pix_fmt_desc_get(frame->format); - for (i = 0; i < info->format->numPlanes; i++) { + for (i = 0; i < info->format.numPlanes; i++) { int p = vs->c_order[i]; ptrdiff_t plane_h = frame->height; -- 2.34.1