Merge branch 'vapoursynth' (early part) into feature
This commit is contained in:
commit
b5a646de66
6 changed files with 65 additions and 11 deletions
|
@ -56,12 +56,14 @@ public:
|
|||
VapoursynthAudioProvider::VapoursynthAudioProvider(agi::fs::path const& filename) try {
|
||||
std::lock_guard<std::mutex> lock(vs.GetMutex());
|
||||
|
||||
VSCleanCache();
|
||||
|
||||
script = vs.GetScriptAPI()->createScript(nullptr);
|
||||
if (script == nullptr) {
|
||||
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);
|
||||
|
|
|
@ -371,6 +371,12 @@
|
|||
"Size" : 42
|
||||
}
|
||||
},
|
||||
"VapourSynth" : {
|
||||
"Cache" : {
|
||||
"Files" : 500,
|
||||
"Size" : 1000
|
||||
}
|
||||
},
|
||||
"Video" : {
|
||||
"Cache" : {
|
||||
"Size" : 32
|
||||
|
|
|
@ -371,6 +371,12 @@
|
|||
"Size" : 42
|
||||
}
|
||||
},
|
||||
"VapourSynth" : {
|
||||
"Cache" : {
|
||||
"Files" : 500,
|
||||
"Size" : 1000
|
||||
}
|
||||
},
|
||||
"Video" : {
|
||||
"Cache" : {
|
||||
"Size" : 32
|
||||
|
|
|
@ -17,23 +17,54 @@
|
|||
#ifdef WITH_VAPOURSYNTH
|
||||
#include "vapoursynth_common.h"
|
||||
|
||||
#include "vapoursynth_wrap.h"
|
||||
#include "options.h"
|
||||
#include "utils.h"
|
||||
#include <libaegisub/fs.h>
|
||||
#include <libaegisub/path.h>
|
||||
|
||||
#include <boost/algorithm/string/replace.hpp>
|
||||
|
||||
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());
|
||||
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());
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
#include <libaegisub/fs_fwd.h>
|
||||
|
||||
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);
|
||||
void VSCleanCache();
|
||||
|
||||
#endif // WITH_VAPOURSYNTH
|
||||
|
|
|
@ -111,12 +111,14 @@ void VapoursynthVideoProvider::SetResizeArg(VSMap *args, const VSMap *props, con
|
|||
VapoursynthVideoProvider::VapoursynthVideoProvider(agi::fs::path const& filename, std::string const& colormatrix) try {
|
||||
std::lock_guard<std::mutex> lock(vs.GetMutex());
|
||||
|
||||
VSCleanCache();
|
||||
|
||||
script = vs.GetScriptAPI()->createScript(nullptr);
|
||||
if (script == nullptr) {
|
||||
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);
|
||||
|
@ -141,7 +143,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;
|
||||
|
|
Loading…
Reference in a new issue