Merge branches 'bugfixes' and 'vapoursynth' into feature
This commit is contained in:
commit
1de8d04a43
18 changed files with 222 additions and 88 deletions
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
|
@ -136,6 +136,7 @@ jobs:
|
|||
with:
|
||||
name: ${{ matrix.config.name }} - installer
|
||||
path: build/Aegisub-*.exe
|
||||
if-no-files-found: error
|
||||
|
||||
- name: Upload artifacts - portable.zip
|
||||
uses: actions/upload-artifact@v3
|
||||
|
@ -157,3 +158,4 @@ jobs:
|
|||
with:
|
||||
name: ${{ matrix.config.name }} - installer
|
||||
path: build/Aegisub-*.dmg
|
||||
if-no-files-found: error
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
"""
|
||||
Utility functions for loading video files into Aegisub using the Vapoursynth
|
||||
Utility functions for loading video files into Aegisub using the VapourSynth
|
||||
video provider.
|
||||
|
||||
When encountering a file whose file extension is not .py or .vpy, the
|
||||
Vapoursynth audio and video providers will execute the respective default
|
||||
VapourSynth audio and video providers will execute the respective default
|
||||
script set in Aegisub's configuration, with the following string variables set:
|
||||
- filename: The path to the file that's being opened.
|
||||
- __aegi_data, __aegi_dictionary, __aegi_local, __aegi_script, __aegi_temp, __aegi_user:
|
||||
The values of ?data, ?dictionary, etc. respectively.
|
||||
- __aegi_vscache: The path to a directory where the Vapoursynth script can
|
||||
- __aegi_vscache: The path to a directory where the VapourSynth script can
|
||||
store cache files. This directory is cleaned by Aegisub when it gets too
|
||||
large (as defined by Aegisub's configuration).
|
||||
|
||||
|
@ -34,6 +34,43 @@ from typing import Any, Dict, List, Tuple
|
|||
import vapoursynth as vs
|
||||
core = vs.core
|
||||
|
||||
aegi_vscache: str = ""
|
||||
aegi_vsplugins: str = ""
|
||||
|
||||
plugin_extension = ".dll" if os.name == "nt" else ".so"
|
||||
|
||||
def set_paths(vars: dict):
|
||||
"""
|
||||
Initialize the wrapper library with the given configuration directories.
|
||||
Should usually be called at the start of the default script as
|
||||
set_paths(globals())
|
||||
"""
|
||||
global aegi_vscache
|
||||
global aegi_vsplugins
|
||||
aegi_vscache = vars["__aegi_vscache"]
|
||||
aegi_vsplugins = vars["__aegi_vsplugins"]
|
||||
|
||||
|
||||
def ensure_plugin(name: str, loadname: str, errormsg: str):
|
||||
"""
|
||||
Ensures that the VapourSynth plugin with the given name exists.
|
||||
If it doesn't, it tries to load it from `loadname`.
|
||||
If that fails, it raises an error with the given error message.
|
||||
"""
|
||||
if hasattr(core, name):
|
||||
return
|
||||
|
||||
if aegi_vsplugins and loadname:
|
||||
try:
|
||||
core.std.LoadPlugin(os.path.join(aegi_vsplugins, loadname + plugin_extension))
|
||||
if hasattr(core, name):
|
||||
return
|
||||
except vs.Error:
|
||||
pass
|
||||
|
||||
raise vs.Error(errormsg)
|
||||
|
||||
|
||||
def make_lwi_cache_filename(filename: str) -> str:
|
||||
"""
|
||||
Given a path to a video, will return a file name like the one LWLibavSource
|
||||
|
@ -103,21 +140,23 @@ def info_from_lwindex(indexfile: str) -> Dict[str, List[int]]:
|
|||
}
|
||||
|
||||
|
||||
def wrap_lwlibavsource(filename: str, cachedir: str, **kwargs: Any) -> Tuple[vs.VideoNode, Dict[str, List[int]]]:
|
||||
def wrap_lwlibavsource(filename: str, cachedir: str | None = None, **kwargs: Any) -> Tuple[vs.VideoNode, Dict[str, List[int]]]:
|
||||
"""
|
||||
Given a path to a video file and a directory to store index files in
|
||||
(usually __aegi_vscache), will open the video with LWLibavSource and read
|
||||
the generated .lwi file to obtain the timecodes and keyframes.
|
||||
Additional keyword arguments are passed on to LWLibavSource.
|
||||
"""
|
||||
if cachedir is None:
|
||||
cachedir = aegi_vscache
|
||||
|
||||
try:
|
||||
os.mkdir(cachedir)
|
||||
except FileExistsError:
|
||||
pass
|
||||
cachefile = os.path.join(cachedir, make_lwi_cache_filename(filename))
|
||||
|
||||
if not hasattr(core, "lsmas"):
|
||||
raise vs.Error("To use Aegisub's LWLibavSource wrapper, the `lsmas` plugin for VapourSynth must be installed")
|
||||
ensure_plugin("lsmas", "libvslsmashsource", "To use Aegisub's LWLibavSource wrapper, the `lsmas` plugin for VapourSynth must be installed")
|
||||
|
||||
if b"-Dcachedir" not in core.lsmas.Version()["config"]: # type: ignore
|
||||
raise vs.Error("To use Aegisub's LWLibavSource wrapper, the `lsmas` plugin must support the `cachedir` option for LWLibavSource.")
|
||||
|
@ -128,7 +167,7 @@ def wrap_lwlibavsource(filename: str, cachedir: str, **kwargs: Any) -> Tuple[vs.
|
|||
|
||||
|
||||
def make_keyframes(clip: vs.VideoNode, use_scxvid: bool = False,
|
||||
resize_h: int = 360, resize_format: int = vs.YUV420P8,
|
||||
resize_h: int = 360, resize_format: int = vs.GRAY8,
|
||||
**kwargs: Any) -> List[int]:
|
||||
"""
|
||||
Generates a list of keyframes from a clip, using either WWXD or Scxvid.
|
||||
|
@ -142,12 +181,14 @@ def make_keyframes(clip: vs.VideoNode, use_scxvid: bool = False,
|
|||
The remaining keyword arguments are passed on to the respective filter.
|
||||
"""
|
||||
|
||||
clip = core.resize.Bilinear(clip, width=resize_h * clip.width // clip.height, height=resize_h, format=resize_format);
|
||||
try:
|
||||
clip = core.scxvid.Scxvid(clip, **kwargs) if use_scxvid else core.wwxd.WWXD(clip, **kwargs)
|
||||
except AttributeError:
|
||||
raise vs.Error("To use the keyframe generation, the `{}` plugin for VapourSynth must be installed"
|
||||
.format("scxvid" if use_scxvid else "wwxd"))
|
||||
clip = core.resize.Bilinear(clip, width=resize_h * clip.width // clip.height, height=resize_h, format=resize_format)
|
||||
|
||||
if use_scxvid:
|
||||
ensure_plugin("scxvid", "libscxvid", "To use the keyframe generation, the scxvid plugin for VapourSynth must be installed")
|
||||
clip = core.scxvid.Scxvid(clip, **kwargs)
|
||||
else:
|
||||
ensure_plugin("wwxd", "libwwxd64", "To use the keyframe generation, the wwxdplugin for VapourSynth must be installed")
|
||||
clip = core.wwxd.WWXD(clip, **kwargs)
|
||||
|
||||
keyframes = {}
|
||||
done = 0
|
||||
|
@ -175,6 +216,16 @@ def save_keyframes(filename: str, keyframes: List[int]):
|
|||
f.write("".join(f"{n}\n" for n in keyframes))
|
||||
|
||||
|
||||
def try_get_keyframes(filename: str, default: str | List[int]) -> str | List[int]:
|
||||
"""
|
||||
Checks if a keyframes file for the given filename is present and, if so,
|
||||
returns it. Otherwise, returns the given list of keyframes.
|
||||
"""
|
||||
kffilename = make_keyframes_filename(filename)
|
||||
|
||||
return kffilename if os.path.exists(kffilename) else default
|
||||
|
||||
|
||||
def get_keyframes(filename: str, clip: vs.VideoNode, **kwargs: Any) -> str:
|
||||
"""
|
||||
When not already present, creates a keyframe file for the given clip next
|
||||
|
@ -199,6 +250,7 @@ def check_audio(filename: str, **kwargs: Any) -> bool:
|
|||
Additional keyword arguments are passed on to BestAudioSource.
|
||||
"""
|
||||
try:
|
||||
ensure_plugin("bas", "BestAudioSource", "")
|
||||
vs.core.bas.Source(source=filename, **kwargs)
|
||||
return True
|
||||
except AttributeError:
|
||||
|
|
|
@ -5,3 +5,8 @@ DestDir: {app}; Source: {#DEPS_DIR}\AvisynthPlus64\x64\AviSynth.dll; Flags: igno
|
|||
DestDir: {app}; Source: {#DEPS_DIR}\AvisynthPlus64\x64\plugins\DirectShowSource.dll; Flags: ignoreversion; Components: main
|
||||
; VSFilter
|
||||
DestDir: {app}\csri; Source: {#DEPS_DIR}\VSFilter\x64\VSFilter.dll; Flags: ignoreversion; Components: main
|
||||
; VapourSynth
|
||||
DestDir: {app}\vapoursynth; Source: {#DEPS_DIR}\L-SMASH-Works\libvslsmashsource.dll; Flags: ignoreversion; Components: vapoursynth
|
||||
DestDir: {app}\vapoursynth; Source: {#DEPS_DIR}\bestaudiosource\win64\BestAudioSource.dll; Flags: ignoreversion; Components: vapoursynth
|
||||
DestDir: {app}\vapoursynth; Source: {#DEPS_DIR}\SCXVid\libscxvid.dll; Flags: ignoreversion; Components: vapoursynth
|
||||
DestDir: {app}\vapoursynth; Source: {#DEPS_DIR}\WWXD\libwwxd64.dll; Flags: ignoreversion; Components: vapoursynth
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
[Components]
|
||||
Name: "main"; Description: "Main Files"; Types: full compact custom; Flags: fixed
|
||||
Name: "vapoursynth"; Description: "Bundled VapourSynth Plugins"; Types: full
|
||||
Name: "macros"; Description: "Automation Scripts"; Types: full
|
||||
Name: "macros\bundled"; Description: "Bundled macros"; Types: full
|
||||
Name: "macros\demos"; Description: "Example macros/Demos"; Types: full
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
; This file declares all installables related to spell checking and thesaurii in Aegisub
|
||||
|
||||
[Files]
|
||||
Source: {#DEPS_DIR}\dictionaries\en_US.aff; DestDir: {app}\dictionaries; Flags: skipifsourcedoesntexist ignoreversion
|
||||
Source: {#DEPS_DIR}\dictionaries\en_US.dic; DestDir: {app}\dictionaries; Flags: skipifsourcedoesntexist ignoreversion
|
||||
Source: {#DEPS_DIR}\dictionaries\en_US.aff; DestDir: {app}\dictionaries; Flags: ignoreversion; Components: dictionaries/en_US
|
||||
Source: {#DEPS_DIR}\dictionaries\en_US.dic; DestDir: {app}\dictionaries; Flags: ignoreversion; Components: dictionaries/en_US
|
||||
|
|
|
@ -51,11 +51,19 @@ Copy-New-Item $InstallerDir\bin\aegisub.exe $PortableOutputDir
|
|||
|
||||
Write-Output 'Copying - translations'
|
||||
Copy-New-Items "$InstallerDir\share\locale\*" "$PortableOutputDir\locale" -Recurse
|
||||
Write-Output 'Copying - dictionaries'
|
||||
Copy-New-Item $InstallerDepsDir\dictionaries\en_US.aff $PortableOutputDir\dictionaries
|
||||
Copy-New-Item $InstallerDepsDir\dictionaries\en_US.dic $PortableOutputDir\dictionaries
|
||||
Write-Output 'Copying - codecs'
|
||||
Write-Output 'Copying - codecs\Avisynth'
|
||||
Copy-New-Item $InstallerDepsDir\AvisynthPlus64\x64\system\DevIL.dll $PortableOutputDir
|
||||
Copy-New-Item $InstallerDepsDir\AvisynthPlus64\x64\AviSynth.dll $PortableOutputDir
|
||||
Copy-New-Item $InstallerDepsDir\AvisynthPlus64\x64\plugins\DirectShowSource.dll $PortableOutputDir
|
||||
Write-Output 'Copying - codecs\VapourSynth'
|
||||
Copy-New-Item $InstallerDepsDir\L-SMASH-Works\libvslsmashsource.dll $PortableOutputDir\vapoursynth
|
||||
Copy-New-Item $InstallerDepsDir\bestaudiosource\win64\BestAudioSource.dll $PortableOutputDir\vapoursynth
|
||||
Copy-New-Item $InstallerDepsDir\SCXVid\libscxvid.dll $PortableOutputDir\vapoursynth
|
||||
Copy-New-Item $InstallerDepsDir\WWXD\libwwxd64.dll $PortableOutputDir\vapoursynth
|
||||
Write-Output 'Copying - codecs\VSFilter'
|
||||
Copy-New-Item $InstallerDepsDir\VSFilter\x64\VSFilter.dll $PortableOutputDir\csri
|
||||
Write-Output 'Copying - runtimes\MS-CRT'
|
||||
|
|
|
@ -32,7 +32,7 @@ using namespace agi;
|
|||
std::unique_ptr<AudioProvider> CreateAvisynthAudioProvider(fs::path const& filename, BackgroundRunner *);
|
||||
std::unique_ptr<AudioProvider> CreateFFmpegSourceAudioProvider(fs::path const& filename, BackgroundRunner *);
|
||||
std::unique_ptr<AudioProvider> CreateBSAudioProvider(fs::path const& filename, BackgroundRunner *);
|
||||
std::unique_ptr<AudioProvider> CreateVapoursynthAudioProvider(fs::path const& filename, BackgroundRunner *);
|
||||
std::unique_ptr<AudioProvider> CreateVapourSynthAudioProvider(fs::path const& filename, BackgroundRunner *);
|
||||
|
||||
namespace {
|
||||
struct factory {
|
||||
|
@ -54,7 +54,7 @@ const factory providers[] = {
|
|||
{"BestSource", CreateBSAudioProvider, false},
|
||||
#endif
|
||||
#ifdef WITH_VAPOURSYNTH
|
||||
{"Vapoursynth", CreateVapoursynthAudioProvider, false},
|
||||
{"VapourSynth", CreateVapourSynthAudioProvider, false},
|
||||
#endif
|
||||
};
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
// Aegisub Project http://www.aegisub.org/
|
||||
|
||||
/// @file audio_provider_vs.cpp
|
||||
/// @brief Vapoursynth-based audio provider
|
||||
/// @brief VapourSynth-based audio provider
|
||||
/// @ingroup audio_input
|
||||
///
|
||||
|
||||
|
@ -38,7 +38,7 @@
|
|||
#include "VSScript4.h"
|
||||
|
||||
namespace {
|
||||
class VapoursynthAudioProvider final : public agi::AudioProvider {
|
||||
class VapourSynthAudioProvider final : public agi::AudioProvider {
|
||||
VapourSynthWrapper vs;
|
||||
VSScript *script = nullptr;
|
||||
VSNode *node = nullptr;
|
||||
|
@ -47,36 +47,36 @@ class VapoursynthAudioProvider final : public agi::AudioProvider {
|
|||
void FillBufferWithFrame(void *buf, int frame, int64_t start, int64_t count) const;
|
||||
void FillBuffer(void *buf, int64_t start, int64_t count) const override;
|
||||
public:
|
||||
VapoursynthAudioProvider(agi::fs::path const& filename);
|
||||
~VapoursynthAudioProvider();
|
||||
VapourSynthAudioProvider(agi::fs::path const& filename);
|
||||
~VapourSynthAudioProvider();
|
||||
|
||||
bool NeedsCache() const override { return true; }
|
||||
};
|
||||
|
||||
VapoursynthAudioProvider::VapoursynthAudioProvider(agi::fs::path const& filename) try {
|
||||
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");
|
||||
throw VapourSynthError("Error creating script API");
|
||||
}
|
||||
vs.GetScriptAPI()->evalSetWorkingDir(script, 1);
|
||||
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);
|
||||
throw VapourSynthError(msg);
|
||||
}
|
||||
node = vs.GetScriptAPI()->getOutputNode(script, 0);
|
||||
if (node == nullptr) {
|
||||
vs.GetScriptAPI()->freeScript(script);
|
||||
throw VapoursynthError("No output node set");
|
||||
throw VapourSynthError("No output node set");
|
||||
}
|
||||
if (vs.GetAPI()->getNodeType(node) != mtAudio) {
|
||||
vs.GetAPI()->freeNode(node);
|
||||
vs.GetScriptAPI()->freeScript(script);
|
||||
throw VapoursynthError("Output node isn't an audio node");
|
||||
throw VapourSynthError("Output node isn't an audio node");
|
||||
}
|
||||
vi = vs.GetAPI()->getAudioInfo(node);
|
||||
float_samples = vi->format.sampleType == stFloat;
|
||||
|
@ -85,10 +85,10 @@ VapoursynthAudioProvider::VapoursynthAudioProvider(agi::fs::path const& filename
|
|||
channels = vi->format.numChannels;
|
||||
num_samples = vi->numSamples;
|
||||
}
|
||||
catch (VapoursynthError const& err) {
|
||||
catch (VapourSynthError const& err) {
|
||||
// Unlike the video provider manager, the audio provider factory catches AudioProviderErrors and picks whichever source doesn't throw one.
|
||||
// So just rethrow the Error here with an extra label so the user will see the error message and know the audio wasn't loaded with VS
|
||||
throw VapoursynthError(agi::format("Vapoursynth error: %s", err.GetMessage()));
|
||||
throw VapourSynthError(agi::format("VapourSynth error: %s", err.GetMessage()));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
|
@ -102,19 +102,19 @@ static void PackChannels(const uint8_t **Src, void *Dst, size_t Length, size_t C
|
|||
}
|
||||
}
|
||||
|
||||
void VapoursynthAudioProvider::FillBufferWithFrame(void *buf, int n, int64_t start, int64_t count) const {
|
||||
void VapourSynthAudioProvider::FillBufferWithFrame(void *buf, int n, int64_t start, int64_t count) const {
|
||||
char errorMsg[1024];
|
||||
const VSFrame *frame = vs.GetAPI()->getFrame(n, node, errorMsg, sizeof(errorMsg));
|
||||
if (frame == nullptr) {
|
||||
throw VapoursynthError(agi::format("Error getting frame: %s", errorMsg));
|
||||
throw VapourSynthError(agi::format("Error getting frame: %s", errorMsg));
|
||||
}
|
||||
if (vs.GetAPI()->getFrameLength(frame) < count) {
|
||||
vs.GetAPI()->freeFrame(frame);
|
||||
throw VapoursynthError("Audio frame too short");
|
||||
throw VapourSynthError("Audio frame too short");
|
||||
}
|
||||
if (vs.GetAPI()->getAudioFrameFormat(frame)->numChannels != channels || vs.GetAPI()->getAudioFrameFormat(frame)->bytesPerSample != bytes_per_sample) {
|
||||
vs.GetAPI()->freeFrame(frame);
|
||||
throw VapoursynthError("Audio format is not constant");
|
||||
throw VapourSynthError("Audio format is not constant");
|
||||
}
|
||||
|
||||
std::vector<const uint8_t *> planes(channels);
|
||||
|
@ -122,7 +122,7 @@ void VapoursynthAudioProvider::FillBufferWithFrame(void *buf, int n, int64_t sta
|
|||
planes[c] = vs.GetAPI()->getReadPtr(frame, c) + bytes_per_sample * start;
|
||||
if (planes[c] == nullptr) {
|
||||
vs.GetAPI()->freeFrame(frame);
|
||||
throw VapoursynthError("Failed to read audio channel");
|
||||
throw VapourSynthError("Failed to read audio channel");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -138,7 +138,7 @@ void VapoursynthAudioProvider::FillBufferWithFrame(void *buf, int n, int64_t sta
|
|||
vs.GetAPI()->freeFrame(frame);
|
||||
}
|
||||
|
||||
void VapoursynthAudioProvider::FillBuffer(void *buf, int64_t start, int64_t count) const {
|
||||
void VapourSynthAudioProvider::FillBuffer(void *buf, int64_t start, int64_t count) const {
|
||||
int end = start + count; // exclusive
|
||||
int startframe = start / VS_AUDIO_FRAME_SAMPLES;
|
||||
int endframe = (end - 1) / VS_AUDIO_FRAME_SAMPLES;
|
||||
|
@ -154,7 +154,7 @@ void VapoursynthAudioProvider::FillBuffer(void *buf, int64_t start, int64_t coun
|
|||
}
|
||||
}
|
||||
|
||||
VapoursynthAudioProvider::~VapoursynthAudioProvider() {
|
||||
VapourSynthAudioProvider::~VapourSynthAudioProvider() {
|
||||
if (node != nullptr) {
|
||||
vs.GetAPI()->freeNode(node);
|
||||
}
|
||||
|
@ -164,7 +164,7 @@ VapoursynthAudioProvider::~VapoursynthAudioProvider() {
|
|||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<agi::AudioProvider> CreateVapoursynthAudioProvider(agi::fs::path const& file, agi::BackgroundRunner *) {
|
||||
return agi::make_unique<VapoursynthAudioProvider>(file);
|
||||
std::unique_ptr<agi::AudioProvider> CreateVapourSynthAudioProvider(agi::fs::path const& file, agi::BackgroundRunner *) {
|
||||
return agi::make_unique<VapourSynthAudioProvider>(file);
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -351,7 +351,7 @@
|
|||
"Aegisub Cache" : true
|
||||
},
|
||||
"VapourSynth" : {
|
||||
"Default Script" : "# This default script will load an audio file using BestAudioSource.\n# It requires the `bas` plugin.\n\nimport vapoursynth as vs\ntry:\n vs.core.bas.Source(source=filename).set_output()\nexcept AttributeError:\n raise vs.Error(\"To use Aegisub's default audio loader, the `bas` plugin for VapourSynth must be installed\")"
|
||||
"Default Script" : "# This default script will load an audio file using BestAudioSource.\n# It requires the `bas` plugin.\n\nimport vapoursynth as vs\nimport aegisub_vs as a\na.set_paths(locals())\n\na.ensure_plugin(\"bas\", \"BestAudioSource\", \"To use Aegisub's default audio loader, the `bas` plugin for VapourSynth must be installed\")\nvs.core.bas.Source(source=filename).set_output()"
|
||||
}
|
||||
},
|
||||
"Avisynth" : {
|
||||
|
@ -392,7 +392,7 @@
|
|||
},
|
||||
"VapourSynth" : {
|
||||
"Log Level": "Information",
|
||||
"Default Script" : "# This default script will load a video file using LWLibavSource.\n# It requires the `lsmas` plugin.\n# See ?data/automation/vapoursynth/aegisub_vs.py for more information.\n\nimport aegisub_vs as a\nimport vapoursynth as vs\n\nclip, videoinfo = a.wrap_lwlibavsource(filename, __aegi_vscache)\nclip.set_output()\n__aegi_timecodes = videoinfo[\"timecodes\"]\n__aegi_keyframes = videoinfo[\"keyframes\"]\n# Uncomment this to automatically generate keyframes at scene changes.\n#__aegi_keyframes = a.get_keyframes(filename, clip)\n\n# Check if the file has an audio track. This requires the `bas` plugin.\n__aegi_hasaudio = 1 if a.check_audio(filename) else 0"
|
||||
"Default Script" : "# This default script will load a video file using LWLibavSource.\n# It requires the `lsmas` plugin.\n# See ?data/automation/vapoursynth/aegisub_vs.py for more information.\n\nimport vapoursynth as vs\nimport time\nimport aegisub_vs as a\na.set_paths(locals())\n\nclip, videoinfo = a.wrap_lwlibavsource(filename)\nclip.set_output()\n__aegi_timecodes = videoinfo[\"timecodes\"]\n__aegi_keyframes = videoinfo[\"keyframes\"]\n\n# Uncomment the first following line to read keyframes from a file when present.\n#__aegi_keyframes = a.try_get_keyframes(filename, __aegi_keyframes)\n\n# Uncomment the following line to automatically generate keyframes at scene changes. This will take some time when first loading a video.\n__aegi_keyframes = a.get_keyframes(filename, clip)\n\n# Check if the file has an audio track. This requires the `bas` plugin.\n__aegi_hasaudio = 1 if a.check_audio(filename) else 0"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -351,7 +351,7 @@
|
|||
"Aegisub Cache" : true
|
||||
},
|
||||
"VapourSynth" : {
|
||||
"Default Script" : "# This default script will load an audio file using BestAudioSource.\n# It requires the `bas` plugin.\n\nimport vapoursynth as vs\ntry:\n vs.core.bas.Source(source=filename).set_output()\nexcept AttributeError:\n raise vs.Error(\"To use Aegisub's default audio loader, the `bas` plugin for VapourSynth must be installed\")"
|
||||
"Default Script" : "# This default script will load an audio file using BestAudioSource.\n# It requires the `bas` plugin.\n\nimport vapoursynth as vs\nimport aegisub_vs as a\na.set_paths(globals())\n\na.ensure_plugin(\"bas\", \"BestAudioSource\", \"To use Aegisub's default audio loader, the `bas` plugin for VapourSynth must be installed\")\nvs.core.bas.Source(source=filename).set_output()"
|
||||
}
|
||||
},
|
||||
"Avisynth" : {
|
||||
|
@ -392,7 +392,7 @@
|
|||
},
|
||||
"VapourSynth" : {
|
||||
"Log Level": "Information",
|
||||
"Default Script" : "# This default script will load a video file using LWLibavSource.\n# It requires the `lsmas` plugin.\n# See ?data/automation/vapoursynth/aegisub_vs.py for more information.\n\nimport aegisub_vs as a\nimport vapoursynth as vs\n\nclip, videoinfo = a.wrap_lwlibavsource(filename, __aegi_vscache)\nclip.set_output()\n__aegi_timecodes = videoinfo[\"timecodes\"]\n__aegi_keyframes = videoinfo[\"keyframes\"]\n# Uncomment this to automatically generate keyframes at scene changes.\n#__aegi_keyframes = a.get_keyframes(filename, clip)\n\n# Check if the file has an audio track. This requires the `bas` plugin.\n__aegi_hasaudio = 1 if a.check_audio(filename) else 0"
|
||||
"Default Script" : "# This default script will load a video file using LWLibavSource.\n# It requires the `lsmas` plugin.\n# See ?data/automation/vapoursynth/aegisub_vs.py for more information.\n\nimport vapoursynth as vs\nimport time\nimport aegisub_vs as a\na.set_paths(locals())\n\nclip, videoinfo = a.wrap_lwlibavsource(filename)\nclip.set_output()\n__aegi_timecodes = videoinfo[\"timecodes\"]\n__aegi_keyframes = videoinfo[\"keyframes\"]\n\n# Uncomment the first following line to read keyframes from a file when present.\n#__aegi_keyframes = a.try_get_keyframes(filename, __aegi_keyframes)\n\n# Uncomment the following line to automatically generate keyframes at scene changes. This will take some time when first loading a video.\n__aegi_keyframes = a.get_keyframes(filename, clip)\n\n# Check if the file has an audio track. This requires the `bas` plugin.\n__aegi_hasaudio = 1 if a.check_audio(filename) else 0"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
|
||||
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");
|
||||
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) {
|
||||
|
@ -38,16 +38,21 @@ int OpenScriptOrVideo(const VSAPI *api, const VSSCRIPTAPI *sapi, VSScript *scrip
|
|||
} else {
|
||||
VSMap *map = api->createMap();
|
||||
if (map == nullptr)
|
||||
throw VapoursynthError("Failed to create VSMap for script info");
|
||||
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());
|
||||
#ifdef WIN32
|
||||
SetStringVar(api, map, "__aegi_vsplugins", config::path->Decode("?data/vapoursynth").string());
|
||||
#else
|
||||
SetStringVar(api, map, "__aegi_vsplugins", "");
|
||||
#endif
|
||||
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");
|
||||
throw VapourSynthError("Failed to set script info variables");
|
||||
|
||||
api->freeMap(map);
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
// Aegisub Project http://www.aegisub.org/
|
||||
|
||||
/// @file vapoursynth_wrap.cpp
|
||||
/// @brief Wrapper-layer for Vapoursynth
|
||||
/// @brief Wrapper-layer for VapourSynth
|
||||
/// @ingroup video_input audio_input
|
||||
///
|
||||
|
||||
|
@ -67,7 +67,7 @@ VapourSynthWrapper::VapourSynthWrapper() {
|
|||
#endif
|
||||
|
||||
if (!hLib)
|
||||
throw VapoursynthError("Could not load " VSSCRIPT_SO);
|
||||
throw VapourSynthError("Could not load " VSSCRIPT_SO);
|
||||
|
||||
#ifdef _WIN32
|
||||
FUNC* getVSScriptAPI = (FUNC*)GetProcAddress(hLib, "getVSScriptAPI");
|
||||
|
@ -75,7 +75,7 @@ VapourSynthWrapper::VapourSynthWrapper() {
|
|||
FUNC* getVSScriptAPI = (FUNC*)dlsym(hLib, "getVSScriptAPI");
|
||||
#endif
|
||||
if (!getVSScriptAPI)
|
||||
throw VapoursynthError("Failed to get address of getVSScriptAPI from " VSSCRIPT_SO);
|
||||
throw VapourSynthError("Failed to get address of getVSScriptAPI from " VSSCRIPT_SO);
|
||||
|
||||
// Python will set the program's locale to the user's default locale, which will break
|
||||
// half of wxwidgets on some operating systems due to locale mismatches. There's not really anything
|
||||
|
@ -85,12 +85,12 @@ VapourSynthWrapper::VapourSynthWrapper() {
|
|||
setlocale(LC_ALL, oldlocale.c_str());
|
||||
|
||||
if (!scriptapi)
|
||||
throw VapoursynthError("Failed to get Vapoursynth ScriptAPI");
|
||||
throw VapourSynthError("Failed to get VapourSynth ScriptAPI");
|
||||
|
||||
api = scriptapi->getVSAPI(VAPOURSYNTH_API_VERSION);
|
||||
|
||||
if (!api)
|
||||
throw VapoursynthError("Failed to get Vapoursynth API");
|
||||
throw VapourSynthError("Failed to get VapourSynth API");
|
||||
|
||||
vs_loaded = true;
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
|
||||
#include <libaegisub/exception.h>
|
||||
|
||||
DEFINE_EXCEPTION(VapoursynthError, agi::Exception);
|
||||
DEFINE_EXCEPTION(VapourSynthError, agi::Exception);
|
||||
|
||||
struct VSAPI;
|
||||
struct VSSCRIPTAPI;
|
||||
|
|
|
@ -30,7 +30,7 @@ std::unique_ptr<VideoProvider> CreateYUV4MPEGVideoProvider(agi::fs::path const&,
|
|||
std::unique_ptr<VideoProvider> CreateFFmpegSourceVideoProvider(agi::fs::path const&, std::string const&, agi::BackgroundRunner *);
|
||||
std::unique_ptr<VideoProvider> CreateAvisynthVideoProvider(agi::fs::path const&, std::string const&, agi::BackgroundRunner *);
|
||||
std::unique_ptr<VideoProvider> CreateBSVideoProvider(agi::fs::path const&, std::string const&, agi::BackgroundRunner *);
|
||||
std::unique_ptr<VideoProvider> CreateVapoursynthVideoProvider(agi::fs::path const&, std::string const&, agi::BackgroundRunner *);
|
||||
std::unique_ptr<VideoProvider> CreateVapourSynthVideoProvider(agi::fs::path const&, std::string const&, agi::BackgroundRunner *);
|
||||
|
||||
std::unique_ptr<VideoProvider> CreateCacheVideoProvider(std::unique_ptr<VideoProvider>);
|
||||
|
||||
|
@ -54,7 +54,7 @@ namespace {
|
|||
{"BestSource (SLOW)", CreateBSVideoProvider, false},
|
||||
#endif
|
||||
#ifdef WITH_VAPOURSYNTH
|
||||
{"Vapoursynth", CreateVapoursynthVideoProvider, false},
|
||||
{"VapourSynth", CreateVapourSynthVideoProvider, false},
|
||||
#endif
|
||||
};
|
||||
}
|
||||
|
|
|
@ -42,7 +42,7 @@ static const char *tc_key = "__aegi_timecodes";
|
|||
static const char *audio_key = "__aegi_hasaudio";
|
||||
|
||||
namespace {
|
||||
class VapoursynthVideoProvider: public VideoProvider {
|
||||
class VapourSynthVideoProvider: public VideoProvider {
|
||||
VapourSynthWrapper vs;
|
||||
VSScript *script = nullptr;
|
||||
VSNode *node = nullptr;
|
||||
|
@ -59,8 +59,8 @@ class VapoursynthVideoProvider: public VideoProvider {
|
|||
void SetResizeArg(VSMap *args, const VSMap *props, const char *arg_name, const char *prop_name, int64_t deflt, int64_t unspecified = -1);
|
||||
|
||||
public:
|
||||
VapoursynthVideoProvider(agi::fs::path const& filename, std::string const& colormatrix, agi::BackgroundRunner *br);
|
||||
~VapoursynthVideoProvider();
|
||||
VapourSynthVideoProvider(agi::fs::path const& filename, std::string const& colormatrix, agi::BackgroundRunner *br);
|
||||
~VapourSynthVideoProvider();
|
||||
|
||||
void GetFrame(int n, VideoFrame &frame) override;
|
||||
|
||||
|
@ -105,7 +105,7 @@ std::string colormatrix_description(int colorFamily, int colorRange, int matrix)
|
|||
}
|
||||
|
||||
// Adds an argument to the rescaler if the corresponding frameprop does not exist or is set as unspecified
|
||||
void VapoursynthVideoProvider::SetResizeArg(VSMap *args, const VSMap *props, const char *arg_name, const char *prop_name, int64_t deflt, int64_t unspecified) {
|
||||
void VapourSynthVideoProvider::SetResizeArg(VSMap *args, const VSMap *props, const char *arg_name, const char *prop_name, int64_t deflt, int64_t unspecified) {
|
||||
int err;
|
||||
int64_t result = vs.GetAPI()->mapGetInt(props, prop_name, 0, &err);
|
||||
if (err != 0 || result == unspecified) {
|
||||
|
@ -117,7 +117,7 @@ void VapoursynthVideoProvider::SetResizeArg(VSMap *args, const VSMap *props, con
|
|||
}
|
||||
}
|
||||
|
||||
VapoursynthVideoProvider::VapoursynthVideoProvider(agi::fs::path const& filename, std::string const& colormatrix, agi::BackgroundRunner *br) try { try {
|
||||
VapourSynthVideoProvider::VapourSynthVideoProvider(agi::fs::path const& filename, std::string const& colormatrix, agi::BackgroundRunner *br) try { try {
|
||||
std::lock_guard<std::mutex> lock(vs.GetMutex());
|
||||
|
||||
VSCleanCache();
|
||||
|
@ -125,16 +125,16 @@ VapoursynthVideoProvider::VapoursynthVideoProvider(agi::fs::path const& filename
|
|||
int err1, err2;
|
||||
VSCore *core = vs.GetAPI()->createCore(0);
|
||||
if (core == nullptr) {
|
||||
throw VapoursynthError("Error creating core");
|
||||
throw VapourSynthError("Error creating core");
|
||||
}
|
||||
script = vs.GetScriptAPI()->createScript(core);
|
||||
if (script == nullptr) {
|
||||
vs.GetAPI()->freeCore(core);
|
||||
throw VapoursynthError("Error creating script API");
|
||||
throw VapourSynthError("Error creating script API");
|
||||
}
|
||||
vs.GetScriptAPI()->evalSetWorkingDir(script, 1);
|
||||
br->Run([&](agi::ProgressSink *ps) {
|
||||
ps->SetTitle(from_wx(_("Executing Vapoursynth Script")));
|
||||
ps->SetTitle(from_wx(_("Executing VapourSynth Script")));
|
||||
ps->SetMessage("");
|
||||
ps->SetIndeterminate();
|
||||
|
||||
|
@ -148,20 +148,20 @@ VapoursynthVideoProvider::VapoursynthVideoProvider(agi::fs::path const& filename
|
|||
});
|
||||
if (err1) {
|
||||
std::string msg = agi::format("Error executing VapourSynth script: %s", vs.GetScriptAPI()->getError(script));
|
||||
throw VapoursynthError(msg);
|
||||
throw VapourSynthError(msg);
|
||||
}
|
||||
node = vs.GetScriptAPI()->getOutputNode(script, 0);
|
||||
if (node == nullptr)
|
||||
throw VapoursynthError("No output node set");
|
||||
throw VapourSynthError("No output node set");
|
||||
|
||||
if (vs.GetAPI()->getNodeType(node) != mtVideo) {
|
||||
throw VapoursynthError("Output node isn't a video node");
|
||||
throw VapourSynthError("Output node isn't a video node");
|
||||
}
|
||||
vi = vs.GetAPI()->getVideoInfo(node);
|
||||
if (vi == nullptr)
|
||||
throw VapoursynthError("Couldn't get video info");
|
||||
throw VapourSynthError("Couldn't get video info");
|
||||
if (!vsh::isConstantVideoFormat(vi))
|
||||
throw VapoursynthError("Video doesn't have constant format");
|
||||
throw VapourSynthError("Video doesn't have constant format");
|
||||
|
||||
int fpsNum = vi->fpsNum;
|
||||
int fpsDen = vi->fpsDen;
|
||||
|
@ -174,7 +174,7 @@ VapoursynthVideoProvider::VapoursynthVideoProvider(agi::fs::path const& filename
|
|||
// Get timecodes and/or keyframes if provided
|
||||
VSMap *clipinfo = vs.GetAPI()->createMap();
|
||||
if (clipinfo == nullptr)
|
||||
throw VapoursynthError("Couldn't create map");
|
||||
throw VapourSynthError("Couldn't create map");
|
||||
vs.GetScriptAPI()->getVariable(script, kf_key, clipinfo);
|
||||
vs.GetScriptAPI()->getVariable(script, tc_key, clipinfo);
|
||||
vs.GetScriptAPI()->getVariable(script, audio_key, clipinfo);
|
||||
|
@ -190,7 +190,7 @@ VapoursynthVideoProvider::VapoursynthVideoProvider(agi::fs::path const& filename
|
|||
const int64_t *kfs = vs.GetAPI()->mapGetIntArray(clipinfo, kf_key, &err1);
|
||||
const char *kfs_path = vs.GetAPI()->mapGetData(clipinfo, kf_key, 0, &err2);
|
||||
if (err1 && err2)
|
||||
throw VapoursynthError("Error getting keyframes from returned VSMap");
|
||||
throw VapourSynthError("Error getting keyframes from returned VSMap");
|
||||
|
||||
if (!err1) {
|
||||
keyframes.reserve(numkf);
|
||||
|
@ -199,7 +199,7 @@ VapoursynthVideoProvider::VapoursynthVideoProvider(agi::fs::path const& filename
|
|||
} else {
|
||||
int kfs_path_size = vs.GetAPI()->mapGetDataSize(clipinfo, kf_key, 0, &err1);
|
||||
if (err1)
|
||||
throw VapoursynthError("Error getting size of keyframes path");
|
||||
throw VapourSynthError("Error getting size of keyframes path");
|
||||
|
||||
try {
|
||||
keyframes = agi::keyframe::Load(config::path->Decode(std::string(kfs_path, size_t(kfs_path_size))));
|
||||
|
@ -213,11 +213,11 @@ VapoursynthVideoProvider::VapoursynthVideoProvider(agi::fs::path const& filename
|
|||
const int64_t *tcs = vs.GetAPI()->mapGetIntArray(clipinfo, tc_key, &err1);
|
||||
const char *tcs_path = vs.GetAPI()->mapGetData(clipinfo, tc_key, 0, &err2);
|
||||
if (err1 && err2)
|
||||
throw VapoursynthError("Error getting timecodes from returned map");
|
||||
throw VapourSynthError("Error getting timecodes from returned map");
|
||||
|
||||
if (!err1) {
|
||||
if (numtc != vi->numFrames)
|
||||
throw VapoursynthError("Number of returned timecodes does not match number of frames");
|
||||
throw VapourSynthError("Number of returned timecodes does not match number of frames");
|
||||
|
||||
std::vector<int> timecodes;
|
||||
timecodes.reserve(numtc);
|
||||
|
@ -228,13 +228,13 @@ VapoursynthVideoProvider::VapoursynthVideoProvider(agi::fs::path const& filename
|
|||
} else {
|
||||
int tcs_path_size = vs.GetAPI()->mapGetDataSize(clipinfo, tc_key, 0, &err1);
|
||||
if (err1)
|
||||
throw VapoursynthError("Error getting size of keyframes path");
|
||||
throw VapourSynthError("Error getting size of keyframes path");
|
||||
|
||||
try {
|
||||
fps = agi::vfr::Framerate(config::path->Decode(std::string(tcs_path, size_t(tcs_path_size))));
|
||||
} catch (agi::Exception const& e) {
|
||||
// Throw an error here unlike with keyframes since the timecodes not being loaded might not be immediately noticeable
|
||||
throw VapoursynthError("Failed to open timecodes file specified by script: " + e.GetMessage());
|
||||
throw VapourSynthError("Failed to open timecodes file specified by script: " + e.GetMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -245,7 +245,7 @@ VapoursynthVideoProvider::VapoursynthVideoProvider(agi::fs::path const& filename
|
|||
|
||||
const VSMap *props = vs.GetAPI()->getFramePropertiesRO(frame);
|
||||
if (props == nullptr)
|
||||
throw VapoursynthError("Couldn't get frame properties");
|
||||
throw VapourSynthError("Couldn't get frame properties");
|
||||
int64_t sarn = vs.GetAPI()->mapGetInt(props, "_SARNum", 0, &err1);
|
||||
int64_t sard = vs.GetAPI()->mapGetInt(props, "_SARDen", 0, &err2);
|
||||
if (!err1 && !err2) {
|
||||
|
@ -262,11 +262,11 @@ VapoursynthVideoProvider::VapoursynthVideoProvider(agi::fs::path const& filename
|
|||
// Convert to RGB24 format
|
||||
VSPlugin *resize = vs.GetAPI()->getPluginByID(VSH_RESIZE_PLUGIN_ID, vs.GetScriptAPI()->getCore(script));
|
||||
if (resize == nullptr)
|
||||
throw VapoursynthError("Couldn't find resize plugin");
|
||||
throw VapourSynthError("Couldn't find resize plugin");
|
||||
|
||||
VSMap *args = vs.GetAPI()->createMap();
|
||||
if (args == nullptr)
|
||||
throw VapoursynthError("Failed to create argument map");
|
||||
throw VapourSynthError("Failed to create argument map");
|
||||
|
||||
vs.GetAPI()->mapSetNode(args, "clip", node, maAppend);
|
||||
vs.GetAPI()->mapSetInt(args, "format", pfRGB24, maAppend);
|
||||
|
@ -299,7 +299,7 @@ VapoursynthVideoProvider::VapoursynthVideoProvider(agi::fs::path const& filename
|
|||
const VSFrame *rgbframe = GetVSFrame(0);
|
||||
vs.GetAPI()->freeFrame(rgbframe);
|
||||
}
|
||||
} catch (VapoursynthError const& err) { // for try inside of function. We need both here since we need to catch errors from the VapoursynthWrap constructor.
|
||||
} catch (VapourSynthError const& err) { // for try inside of function. We need both here since we need to catch errors from the VapourSynthWrap constructor.
|
||||
if (node != nullptr)
|
||||
vs.GetAPI()->freeNode(node);
|
||||
if (script != nullptr)
|
||||
|
@ -307,27 +307,27 @@ VapoursynthVideoProvider::VapoursynthVideoProvider(agi::fs::path const& filename
|
|||
throw err;
|
||||
}
|
||||
}
|
||||
catch (VapoursynthError const& err) { // for the entire constructor
|
||||
throw VideoProviderError(agi::format("Vapoursynth error: %s", err.GetMessage()));
|
||||
catch (VapourSynthError const& err) { // for the entire constructor
|
||||
throw VideoProviderError(agi::format("VapourSynth error: %s", err.GetMessage()));
|
||||
}
|
||||
|
||||
const VSFrame *VapoursynthVideoProvider::GetVSFrame(int n) {
|
||||
const VSFrame *VapourSynthVideoProvider::GetVSFrame(int n) {
|
||||
char errorMsg[1024];
|
||||
const VSFrame *frame = vs.GetAPI()->getFrame(n, node, errorMsg, sizeof(errorMsg));
|
||||
if (frame == nullptr) {
|
||||
throw VapoursynthError(agi::format("Error getting frame: %s", errorMsg));
|
||||
throw VapourSynthError(agi::format("Error getting frame: %s", errorMsg));
|
||||
}
|
||||
return frame;
|
||||
}
|
||||
|
||||
void VapoursynthVideoProvider::GetFrame(int n, VideoFrame &out) {
|
||||
void VapourSynthVideoProvider::GetFrame(int n, VideoFrame &out) {
|
||||
std::lock_guard<std::mutex> lock(vs.GetMutex());
|
||||
|
||||
const VSFrame *frame = GetVSFrame(n);
|
||||
|
||||
const VSVideoFormat *format = vs.GetAPI()->getVideoFrameFormat(frame);
|
||||
if (format->colorFamily != cfRGB || format->numPlanes != 3 || format->bitsPerSample != 8 || format->subSamplingH != 0 || format->subSamplingW != 0) {
|
||||
throw VapoursynthError("Frame not in RGB24 format");
|
||||
throw VapourSynthError("Frame not in RGB24 format");
|
||||
}
|
||||
|
||||
out.width = vs.GetAPI()->getFrameWidth(frame, 0);
|
||||
|
@ -359,7 +359,7 @@ void VapoursynthVideoProvider::GetFrame(int n, VideoFrame &out) {
|
|||
vs.GetAPI()->freeFrame(frame);
|
||||
}
|
||||
|
||||
VapoursynthVideoProvider::~VapoursynthVideoProvider() {
|
||||
VapourSynthVideoProvider::~VapourSynthVideoProvider() {
|
||||
if (node != nullptr) {
|
||||
vs.GetAPI()->freeNode(node);
|
||||
}
|
||||
|
@ -370,7 +370,7 @@ VapoursynthVideoProvider::~VapoursynthVideoProvider() {
|
|||
}
|
||||
|
||||
namespace agi { class BackgroundRunner; }
|
||||
std::unique_ptr<VideoProvider> CreateVapoursynthVideoProvider(agi::fs::path const& path, std::string const& colormatrix, agi::BackgroundRunner *br) {
|
||||
return agi::make_unique<VapoursynthVideoProvider>(path, colormatrix, br);
|
||||
std::unique_ptr<VideoProvider> CreateVapourSynthVideoProvider(agi::fs::path const& path, std::string const& colormatrix, agi::BackgroundRunner *br) {
|
||||
return agi::make_unique<VapourSynthVideoProvider>(path, colormatrix, br);
|
||||
}
|
||||
#endif // WITH_VAPOURSYNTH
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
[wrap-git]
|
||||
url = https://github.com/Vapoursynth/vapoursynth.git
|
||||
url = https://github.com/vapoursynth/vapoursynth.git
|
||||
revision = R59
|
||||
patch_directory = vapoursynth
|
||||
|
|
|
@ -61,7 +61,12 @@ echo "---- Copying dictionaries ----"
|
|||
if test -f "${DICT_DIR}"; then
|
||||
cp -v "${DICT_DIR}/*" "${PKG_DIR}/Contents/SharedSupport/dictionaries"
|
||||
else
|
||||
echo "Specified dictionary directory ${DICT_DIR} not found!"
|
||||
echo "Specified dictionary directory ${DICT_DIR} not found. Downloading dictionaries:"
|
||||
mkdir "${BUILD_DIR}/dictionaries"
|
||||
curl -L "https://downloads.sourceforge.net/project/openofficeorg.mirror/contrib/dictionaries/en_US.zip" -o "${BUILD_DIR}/dictionaries/en_US.zip"
|
||||
unzip "${BUILD_DIR}/dictionaries/en_US.zip" -d "${BUILD_DIR}/dictionaries"
|
||||
cp -v "${BUILD_DIR}/dictionaries/en_US.aff" "${PKG_DIR}/Contents/SharedSupport/dictionaries"
|
||||
cp -v "${BUILD_DIR}/dictionaries/en_US.dic" "${PKG_DIR}/Contents/SharedSupport/dictionaries"
|
||||
fi
|
||||
|
||||
echo
|
||||
|
|
|
@ -63,13 +63,60 @@ if (!(Test-Path VSFilter)) {
|
|||
Set-Location $DepsDir
|
||||
}
|
||||
|
||||
### VapourSynth plugins
|
||||
|
||||
# L-SMASH-Works
|
||||
if (!(Test-Path L-SMASH-Works)) {
|
||||
New-Item -ItemType Directory L-SMASH-Works
|
||||
$lsmasReleases = Invoke-WebRequest "https://api.github.com/repos/AkarinVS/L-SMASH-Works/releases/latest" -Headers $GitHeaders -UseBasicParsing | ConvertFrom-Json
|
||||
$lsmasUrl = "https://github.com/AkarinVS/L-SMASH-Works/releases/download/" + $lsmasReleases.tag_name + "/release-x86_64-cachedir-cwd.zip"
|
||||
Invoke-WebRequest $lsmasUrl -OutFile release-x86_64-cachedir-cwd.zip -UseBasicParsing
|
||||
Expand-Archive -LiteralPath release-x86_64-cachedir-cwd.zip -DestinationPath L-SMASH-Works
|
||||
Remove-Item release-x86_64-cachedir-cwd.zip
|
||||
}
|
||||
|
||||
# bestaudiosource
|
||||
if (!(Test-Path bestaudiosource)) {
|
||||
$basDir = New-Item -ItemType Directory bestaudiosource
|
||||
Set-Location $basDir
|
||||
$basReleases = Invoke-WebRequest "https://api.github.com/repos/vapoursynth/bestaudiosource/releases/latest" -Headers $GitHeaders -UseBasicParsing | ConvertFrom-Json
|
||||
$basUrl = $basReleases.assets[0].browser_download_url
|
||||
Invoke-WebRequest $basUrl -OutFile bas-r1.7z -UseBasicParsing
|
||||
7z x bas-r1.7z
|
||||
Remove-Item bas-r1.7z
|
||||
Set-Location $DepsDir
|
||||
}
|
||||
|
||||
# SCXVid
|
||||
if (!(Test-Path SCXVid)) {
|
||||
$scxDir = New-Item -ItemType Directory SCXVid
|
||||
Set-Location $scxDir
|
||||
$scxReleases = Invoke-WebRequest "https://api.github.com/repos/dubhater/vapoursynth-scxvid/releases/latest" -Headers $GitHeaders -UseBasicParsing | ConvertFrom-Json
|
||||
$scxUrl = "https://github.com/dubhater/vapoursynth-scxvid/releases/download/" + $scxReleases.tag_name + "/vapoursynth-scxvid-v1-win64.7z"
|
||||
Invoke-WebRequest $scxUrl -OutFile vapoursynth-scxvid-v1-win64.7z -UseBasicParsing
|
||||
7z x vapoursynth-scxvid-v1-win64.7z
|
||||
Remove-Item vapoursynth-scxvid-v1-win64.7z
|
||||
Set-Location $DepsDir
|
||||
}
|
||||
|
||||
# WWXD
|
||||
if (!(Test-Path WWXD)) {
|
||||
New-Item -ItemType Directory WWXD
|
||||
$wwxdReleases = Invoke-WebRequest "https://api.github.com/repos/dubhater/vapoursynth-wwxd/releases/latest" -Headers $GitHeaders -UseBasicParsing | ConvertFrom-Json
|
||||
$wwxdUrl = "https://github.com/dubhater/vapoursynth-wwxd/releases/download/" + $wwxdReleases.tag_name + "/libwwxd64.dll"
|
||||
Invoke-WebRequest $wwxdUrl -OutFile WWXD/libwwxd64.dll -UseBasicParsing
|
||||
}
|
||||
|
||||
|
||||
# ffi-experiments
|
||||
if (!(Test-Path ffi-experiments)) {
|
||||
Get-Command "moonc" # check to ensure Moonscript is present
|
||||
git clone https://github.com/arch1t3cht/ffi-experiments.git
|
||||
Set-Location ffi-experiments
|
||||
meson build -Ddefault_library=static
|
||||
if(!$?) { Exit $LASTEXITCODE }
|
||||
meson compile -C build
|
||||
if(!$?) { Exit $LASTEXITCODE }
|
||||
Set-Location $DepsDir
|
||||
}
|
||||
|
||||
|
@ -79,12 +126,21 @@ if (!(Test-Path VC_redist)) {
|
|||
Invoke-WebRequest https://aka.ms/vs/17/release/VC_redist.x64.exe -OutFile "$redistDir\VC_redist.x64.exe" -UseBasicParsing
|
||||
}
|
||||
|
||||
# TODO dictionaries
|
||||
# dictionaries
|
||||
if (!(Test-Path dictionaries)) {
|
||||
New-Item -ItemType Directory dictionaries
|
||||
[Net.ServicePointManager]::SecurityProtocol = "Tls12" # Needed since otherwise downloading fails in some places like on the GitHub CI: https://stackoverflow.com/a/66614041/4730656
|
||||
Invoke-WebRequest https://downloads.sourceforge.net/project/openofficeorg.mirror/contrib/dictionaries/en_US.zip -UserAgent "Wget" -OutFile en_US.zip -UseBasicParsing
|
||||
Expand-Archive -LiteralPath en_US.zip -DestinationPath dictionaries
|
||||
Remove-Item en_US.zip
|
||||
}
|
||||
|
||||
# localization
|
||||
Set-Location $BuildRoot
|
||||
meson compile aegisub-gmo
|
||||
if(!$?) { Exit $LASTEXITCODE }
|
||||
|
||||
# Invoke InnoSetup
|
||||
$IssUrl = Join-Path $InstallerDir "aegisub_depctrl.iss"
|
||||
iscc $IssUrl
|
||||
if(!$?) { Exit $LASTEXITCODE }
|
Loading…
Reference in a new issue