vapoursynth: Ship plugins on windows and add ensure_plugin function
This commit is contained in:
parent
1f2eaaf6e4
commit
256ddab369
8 changed files with 115 additions and 12 deletions
|
@ -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.")
|
||||
|
@ -143,11 +182,13 @@ def make_keyframes(clip: vs.VideoNode, use_scxvid: bool = False,
|
|||
"""
|
||||
|
||||
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"))
|
||||
|
||||
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
|
||||
|
@ -199,6 +240,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
|
||||
|
|
|
@ -56,6 +56,11 @@ Write-Output 'Copying - codecs\Avisynth'
|
|||
Copy-New-Item $InstallerDepsDir\AvisynthPlus64\x86-64\DevIL.dll $PortableOutputDir
|
||||
Copy-New-Item $InstallerDepsDir\AvisynthPlus64\x86-64\AviSynth.dll $PortableOutputDir
|
||||
Copy-New-Item $InstallerDepsDir\AvisynthPlus64\x86-64\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'
|
||||
|
|
|
@ -338,7 +338,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" : {
|
||||
|
@ -374,7 +374,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# 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"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -338,7 +338,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" : {
|
||||
|
@ -374,7 +374,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# 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"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -42,6 +42,11 @@ int OpenScriptOrVideo(const VSAPI *api, const VSSCRIPTAPI *sapi, VSScript *scrip
|
|||
|
||||
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());
|
||||
|
|
|
@ -58,6 +58,51 @@ 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
|
||||
|
|
Loading…
Reference in a new issue