From 88867d402ce89e1fdaf9666047d5f9e51b26459e Mon Sep 17 00:00:00 2001 From: arch1t3cht Date: Mon, 30 Jan 2023 01:55:22 +0100 Subject: [PATCH 1/3] vapoursynth: Default to 25fps when no clip fps set This matches the behavior of the FFMS video provider. --- src/video_provider_vs.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/video_provider_vs.cpp b/src/video_provider_vs.cpp index 8ecd621bb..bde0f9a70 100644 --- a/src/video_provider_vs.cpp +++ b/src/video_provider_vs.cpp @@ -141,7 +141,13 @@ VapoursynthVideoProvider::VapoursynthVideoProvider(agi::fs::path const& filename // Assume constant frame rate, since handling VFR would require going through all frames when loading. // Users can load custom timecodes files to deal with VFR. // Alternatively (TODO) the provider could read timecodes and keyframes from a second output node. - fps = agi::vfr::Framerate(vi->fpsNum, vi->fpsDen); + int fpsNum = vi->fpsNum; + int fpsDen = vi->fpsDen; + if (fpsDen == 0) { + fpsNum = 25; + fpsDen = 1; + } + fps = agi::vfr::Framerate(fpsNum, fpsDen); // Find the first frame to get some info const VSFrame *frame; From 32aaf6372c80ec117a919b85ec0c13aa69ac727c Mon Sep 17 00:00:00 2001 From: arch1t3cht Date: Mon, 30 Jan 2023 02:52:18 +0100 Subject: [PATCH 2/3] vapoursynth: Set path variables and import path in python --- src/audio_provider_vs.cpp | 2 +- src/vapoursynth_common.cpp | 36 +++++++++++++++++++++++++++++------- src/vapoursynth_common.h | 2 +- src/video_provider_vs.cpp | 2 +- 4 files changed, 32 insertions(+), 10 deletions(-) diff --git a/src/audio_provider_vs.cpp b/src/audio_provider_vs.cpp index b41b46773..49b3c7e06 100644 --- a/src/audio_provider_vs.cpp +++ b/src/audio_provider_vs.cpp @@ -61,7 +61,7 @@ VapoursynthAudioProvider::VapoursynthAudioProvider(agi::fs::path const& filename throw VapoursynthError("Error creating script API"); } vs.GetScriptAPI()->evalSetWorkingDir(script, 1); - if (OpenScriptOrVideo(vs.GetScriptAPI(), script, filename, OPT_GET("Provider/Audio/VapourSynth/Default Script")->GetString())) { + if (OpenScriptOrVideo(vs.GetAPI(), vs.GetScriptAPI(), script, filename, OPT_GET("Provider/Audio/VapourSynth/Default Script")->GetString())) { std::string msg = agi::format("Error executing VapourSynth script: %s", vs.GetScriptAPI()->getError(script)); vs.GetScriptAPI()->freeScript(script); throw VapoursynthError(msg); diff --git a/src/vapoursynth_common.cpp b/src/vapoursynth_common.cpp index 52614528c..83070111f 100644 --- a/src/vapoursynth_common.cpp +++ b/src/vapoursynth_common.cpp @@ -17,21 +17,43 @@ #ifdef WITH_VAPOURSYNTH #include "vapoursynth_common.h" +#include "vapoursynth_wrap.h" #include "options.h" #include +#include #include -int OpenScriptOrVideo(const VSSCRIPTAPI *api, VSScript *script, agi::fs::path const& filename, std::string default_script) { +void SetStringVar(const VSAPI *api, VSMap *map, std::string variable, std::string value) { + if (api->mapSetData(map, variable.c_str(), value.c_str(), -1, dtUtf8, 1)) + throw VapoursynthError("Failed to set VSMap entry"); +} + +int OpenScriptOrVideo(const VSAPI *api, const VSSCRIPTAPI *sapi, VSScript *script, agi::fs::path const& filename, std::string default_script) { int result; if (agi::fs::HasExtension(filename, "py") || agi::fs::HasExtension(filename, "vpy")) { - result = api->evaluateFile(script, filename.string().c_str()); + result = sapi->evaluateFile(script, filename.string().c_str()); } else { - std::string fname = filename.string(); - boost::replace_all(fname, "\\", "\\\\"); - boost::replace_all(fname, "'", "\\'"); - std::string vscript = "filename = '" + fname + "'\n" + default_script; - result = api->evaluateBuffer(script, vscript.c_str(), "aegisub"); + VSMap *map = api->createMap(); + if (map == nullptr) + throw VapoursynthError("Failed to create VSMap for script info"); + + SetStringVar(api, map, "filename", filename.string()); + for (std::string dir : { "data", "dictionary", "local", "script", "temp", "user", }) + // Don't include ?audio and ?video in here since these only hold the paths to the previous audio/video files. + SetStringVar(api, map, "__aegi_" + dir, config::path->Decode("?" + dir).string()); + + if (sapi->setVariables(script, map)) + throw VapoursynthError("Failed to set script info variables"); + + api->freeMap(map); + + std::string vscript; + vscript += "import sys\n"; + vscript += "sys.path.append(f'{__aegi_data}/automation/vapoursynth')\n"; + vscript += "sys.path.append(f'{__aegi_user}/automation/vapoursynth')\n"; + vscript += default_script; + result = sapi->evaluateBuffer(script, vscript.c_str(), "aegisub"); } return result; } diff --git a/src/vapoursynth_common.h b/src/vapoursynth_common.h index 06479e45e..2f03b4e7b 100644 --- a/src/vapoursynth_common.h +++ b/src/vapoursynth_common.h @@ -19,6 +19,6 @@ #include -int OpenScriptOrVideo(const VSSCRIPTAPI *api, VSScript *script, agi::fs::path const& filename, std::string default_script); +int OpenScriptOrVideo(const VSAPI *api, const VSSCRIPTAPI *sapi, VSScript *script, agi::fs::path const& filename, std::string default_script); #endif // WITH_VAPOURSYNTH diff --git a/src/video_provider_vs.cpp b/src/video_provider_vs.cpp index bde0f9a70..7b0d29449 100644 --- a/src/video_provider_vs.cpp +++ b/src/video_provider_vs.cpp @@ -116,7 +116,7 @@ VapoursynthVideoProvider::VapoursynthVideoProvider(agi::fs::path const& filename throw VapoursynthError("Error creating script API"); } vs.GetScriptAPI()->evalSetWorkingDir(script, 1); - if (OpenScriptOrVideo(vs.GetScriptAPI(), script, filename, OPT_GET("Provider/Video/VapourSynth/Default Script")->GetString())) { + if (OpenScriptOrVideo(vs.GetAPI(), vs.GetScriptAPI(), script, filename, OPT_GET("Provider/Video/VapourSynth/Default Script")->GetString())) { std::string msg = agi::format("Error executing VapourSynth script: %s", vs.GetScriptAPI()->getError(script)); vs.GetScriptAPI()->freeScript(script); throw VapoursynthError(msg); From c348f8582a97b8f9473d403113ea95164bdfb15e Mon Sep 17 00:00:00 2001 From: arch1t3cht Date: Tue, 31 Jan 2023 21:35:24 +0100 Subject: [PATCH 3/3] vapoursynth: Add a preferred cache directory and clean it when necessary --- src/audio_provider_vs.cpp | 2 ++ src/libresrc/default_config.json | 6 ++++++ src/libresrc/osx/default_config.json | 6 ++++++ src/vapoursynth_common.cpp | 9 +++++++++ src/vapoursynth_common.h | 1 + src/video_provider_vs.cpp | 2 ++ 6 files changed, 26 insertions(+) diff --git a/src/audio_provider_vs.cpp b/src/audio_provider_vs.cpp index 49b3c7e06..55151e896 100644 --- a/src/audio_provider_vs.cpp +++ b/src/audio_provider_vs.cpp @@ -56,6 +56,8 @@ public: VapoursynthAudioProvider::VapoursynthAudioProvider(agi::fs::path const& filename) try { std::lock_guard lock(vs.GetMutex()); + VSCleanCache(); + script = vs.GetScriptAPI()->createScript(nullptr); if (script == nullptr) { throw VapoursynthError("Error creating script API"); diff --git a/src/libresrc/default_config.json b/src/libresrc/default_config.json index 3e76c8e06..dbdc303a3 100644 --- a/src/libresrc/default_config.json +++ b/src/libresrc/default_config.json @@ -353,6 +353,12 @@ "Index All Tracks" : true, "Log Level" : "quiet" }, + "VapourSynth" : { + "Cache" : { + "Files" : 500, + "Size" : 1000 + } + }, "Video" : { "Cache" : { "Size" : 32 diff --git a/src/libresrc/osx/default_config.json b/src/libresrc/osx/default_config.json index 61a9e965a..412f13f50 100644 --- a/src/libresrc/osx/default_config.json +++ b/src/libresrc/osx/default_config.json @@ -353,6 +353,12 @@ "Index All Tracks" : true, "Log Level" : "quiet" }, + "VapourSynth" : { + "Cache" : { + "Files" : 500, + "Size" : 1000 + } + }, "Video" : { "Cache" : { "Size" : 32 diff --git a/src/vapoursynth_common.cpp b/src/vapoursynth_common.cpp index 83070111f..9a0e3ebe3 100644 --- a/src/vapoursynth_common.cpp +++ b/src/vapoursynth_common.cpp @@ -19,6 +19,7 @@ #include "vapoursynth_wrap.h" #include "options.h" +#include "utils.h" #include #include @@ -39,6 +40,7 @@ int OpenScriptOrVideo(const VSAPI *api, const VSSCRIPTAPI *sapi, VSScript *scrip throw VapoursynthError("Failed to create VSMap for script info"); SetStringVar(api, map, "filename", filename.string()); + SetStringVar(api, map, "__aegi_vscache", config::path->Decode("?local/vscache").string()); for (std::string dir : { "data", "dictionary", "local", "script", "temp", "user", }) // Don't include ?audio and ?video in here since these only hold the paths to the previous audio/video files. SetStringVar(api, map, "__aegi_" + dir, config::path->Decode("?" + dir).string()); @@ -58,4 +60,11 @@ int OpenScriptOrVideo(const VSAPI *api, const VSSCRIPTAPI *sapi, VSScript *scrip return result; } +void VSCleanCache() { + CleanCache(config::path->Decode("?local/vscache/"), + "", + OPT_GET("Provider/VapourSynth/Cache/Size")->GetInt(), + OPT_GET("Provider/VapourSynth/Cache/Files")->GetInt()); +} + #endif // WITH_VAPOURSYNTH diff --git a/src/vapoursynth_common.h b/src/vapoursynth_common.h index 2f03b4e7b..af35da3aa 100644 --- a/src/vapoursynth_common.h +++ b/src/vapoursynth_common.h @@ -20,5 +20,6 @@ #include int OpenScriptOrVideo(const VSAPI *api, const VSSCRIPTAPI *sapi, VSScript *script, agi::fs::path const& filename, std::string default_script); +void VSCleanCache(); #endif // WITH_VAPOURSYNTH diff --git a/src/video_provider_vs.cpp b/src/video_provider_vs.cpp index 7b0d29449..7650a5045 100644 --- a/src/video_provider_vs.cpp +++ b/src/video_provider_vs.cpp @@ -111,6 +111,8 @@ void VapoursynthVideoProvider::SetResizeArg(VSMap *args, const VSMap *props, con VapoursynthVideoProvider::VapoursynthVideoProvider(agi::fs::path const& filename, std::string const& colormatrix) try { std::lock_guard lock(vs.GetMutex()); + VSCleanCache(); + script = vs.GetScriptAPI()->createScript(nullptr); if (script == nullptr) { throw VapoursynthError("Error creating script API");