Last active
December 19, 2015 03:39
-
-
Save vdcrim/5891445 to your computer and use it in GitHub Desktop.
Incomplete and not very well thought out Python 2.7 bindings for the VapourSynth C API, just for playing around
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# coding: utf8 | |
# Python 2.7 bindings for the VapourSynth C API | |
# last updated: VapourSynth R19 | |
from __future__ import print_function | |
import sys | |
import os | |
import os.path | |
from collections import Iterable | |
import subprocess | |
from ctypes import * | |
# Misc | |
try: | |
basestring | |
except NameError: | |
basestring = (bytes, str) | |
def get_python33_directory(): | |
which = 'where' if os.name == 'nt' else 'which' | |
for name in ('python3', 'python3.3', 'python33', 'python'): | |
p = subprocess.Popen([which, name], stdout=subprocess.PIPE, | |
stderr=subprocess.PIPE) | |
if not p.wait(): | |
return os.path.dirname(p.stdout.read().decode(sys.stdin.encoding). | |
splitlines()[0]) | |
''' On Windows the Registry should be used instead | |
HKEY_CURRENT_USER\SOFTWARE\Python\PythonCore\3.3\InstallPath | |
HKEY_LOCAL_MACHINE\SOFTWARE\Python\PythonCore\3.3\InstallPath | |
HKEY_CURRENT_USER\SOFTWARE\Wow6432Node\Python\PythonCore\3.3\InstallPath | |
HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Python\PythonCore\3.3\InstallPath | |
''' | |
class PrintableStructure(Structure): | |
def __repr__(self): | |
s = type(self).__name__ + '(' | |
for field in self._fields_: | |
if 'c_char' in str(field[1]) or 'c_wchar' in str(field[1]): | |
value = '"{0}"'.format(getattr(self, field[0])) | |
else: | |
value = getattr(self, field[0]) | |
s = s + '{0}={1}, '.format(field[0], value) | |
return s[:-2] + ')' | |
def __str__(self): | |
s = '' | |
for field in self._fields_: | |
s = s + '{0}={1}\n'.format(field[0], getattr(self, field[0])) | |
return s | |
# Load libraries | |
# Add the site-packages directory to PATH on Windows, or a directory passed | |
# as a command line argument if the module is called as a script | |
_vs_dir = None | |
_python3_dir = get_python33_directory() | |
if _python3_dir: | |
print('Python 3 directory:', repr(_python3_dir)) | |
if os.name == 'nt': | |
_vs_dir = os.path.join(_python3_dir, 'Lib\site-packages') | |
if __name__ == '__main__': | |
if len(sys.argv) > 1: | |
_vs_dir = sys.argv[1] | |
if sys.version_info[0] >= 3: | |
_vs_dir = os.fsencode(_vs_dir) | |
_vs_dir = _vs_dir.decode(sys.stdin.encoding) | |
if _vs_dir and os.path.isdir(_vs_dir): | |
os.environ['PATH'] += os.pathsep + _vs_dir | |
# Awful work-around for a crash with vsscript - sys.path is populated | |
# from the calling Python version, not from Python 3 | |
if _python3_dir: | |
os.environ['PYTHONHOME'] = _python3_dir | |
# Finally load the libraries | |
if os.name == 'nt': | |
_vs = windll.vapoursynth | |
_vsscript = windll.vsscript | |
_FUNCTYPE = WINFUNCTYPE | |
else: | |
_vs = cdll.vapoursynth | |
_vsscript = cdll.vsscript | |
_FUNCTYPE = CFUNCTYPE | |
# VapourSynth.h | |
API_VERSION = 3 | |
class _API(Structure): | |
pass | |
_getVapourSynthAPI = _vs.getVapourSynthAPI | |
_getVapourSynthAPI.restype = POINTER(_API) | |
# ColorFamily enum | |
# all planar formats | |
cmGray = 1000000 | |
cmRGB = 2000000 | |
cmYUV = 3000000 | |
cmYCoCg = 4000000 | |
# special for compatibility | |
cmCompat = 9000000 | |
# SampleType enum | |
stInteger = 0 | |
stFloat = 1 | |
# PresetFormat enum | |
# The +10 is so people won't be using the constants interchangably "by accident" | |
pfNone = 0 | |
pfGray8 = cmGray + 10 | |
pfGray16 = pfGray8 + 1 | |
pfGrayH = pfGray16 + 1 | |
pfGrayS = pfGrayH + 1 | |
pfYUV420P8 = cmYUV + 10 | |
pfYUV422P8 = pfYUV420P8 + 1 | |
pfYUV444P8 = pfYUV422P8 + 1 | |
pfYUV410P8 = pfYUV444P8 + 1 | |
pfYUV411P8 = pfYUV410P8 + 1 | |
pfYUV440P8 = pfYUV411P8 + 1 | |
pfYUV420P9 = pfYUV440P8 + 1 | |
pfYUV422P9 = pfYUV420P9 + 1 | |
pfYUV444P9 = pfYUV422P9 + 1 | |
pfYUV420P10 = pfYUV444P9 + 1 | |
pfYUV422P10 = pfYUV420P10 + 1 | |
pfYUV444P10 = pfYUV422P10 + 1 | |
pfYUV420P16 = pfYUV444P10 + 1 | |
pfYUV422P16 = pfYUV420P16 + 1 | |
pfYUV444P16 = pfYUV422P16 + 1 | |
pfYUV444PH = pfYUV444P16 + 1 | |
pfYUV444PS = pfYUV444PH + 1 | |
pfRGB24 = cmRGB + 10 | |
pfRGB27 = pfRGB24 + 1 | |
pfRGB30 = pfRGB27 + 1 | |
pfRGB48 = pfRGB30 + 1 | |
pfRGBH = pfRGB48 + 1 | |
pfRGBS = pfRGBH + 1 | |
# special for compatibility, if you implement these in any filter I'll personally kill you | |
# I'll also change their ids around to break your stuff regularly | |
pfCompatBGR32 = cmCompat + 10 | |
pfCompatYUY2 = pfCompatBGR32 + 1 | |
# FilterMode enum | |
fmParallel = 100 # completely parallel execution | |
fmParallelRequests = 200 # for filters that are serial in nature but can request one or more frames they need in advance | |
fmUnordered = 300 # for filters that modify their internal state every request | |
fmSerial = 400 # for source filters and compatibility with other filtering architectures | |
class Format(PrintableStructure): | |
_fields_ = [ | |
("name", c_char * 32), | |
("id", c_int), | |
("colorFamily", c_int), # see ColorFamily | |
("sampleType", c_int), # see SampleType | |
("bitsPerSample", c_int), # number of significant bits | |
("bytesPerSample", c_int), # actual storage is always in a power of 2 and the smallest possible that can fit the number of bits used per sample | |
("subSamplingW", c_int), # log2 subsampling factor, applied to second and third plane | |
("subSamplingH", c_int), | |
("numPlanes", c_int), # implicit from colorFamily | |
] | |
# NodeFlags enum | |
nfNoCache = 1 | |
# GetPropErrors enum | |
peUnset = 1 | |
peType = 2 | |
peIndex = 4 | |
# PropAppendMode enum | |
paReplace = 0 | |
paAppend = 1 | |
paTouch = 2 | |
class CoreInfo(PrintableStructure): | |
_fields_ = [ | |
("versionString", c_char_p), | |
("core", c_int), | |
("api", c_int), | |
("numThreads", c_int), | |
("maxFramebufferSize", c_int64), | |
("usedFramebufferSize", c_int64), | |
] | |
class VideoInfo(PrintableStructure): | |
_fields_ = [ | |
("format", POINTER(Format)), | |
("fpsNum", c_int64), | |
("fpsDen", c_int64), | |
("width", c_int), | |
("height", c_int), | |
("numFrames", c_int), | |
("flags", c_int), | |
] | |
# ActivationReason enum | |
arInitial = 0 | |
arFrameReady = 1 | |
arAllFramesReady = 2 | |
arError = -1 | |
# MessageType enum | |
mtDebug = 0 | |
mtWarnin = 1 | |
mtCritical = 2 | |
mtFatal = mtCritical + 1 | |
# core functions | |
_createCore = _FUNCTYPE(c_void_p, c_int) | |
_freeCore = _FUNCTYPE(None, c_void_p) | |
_getCoreInfo = _FUNCTYPE(POINTER(CoreInfo), c_void_p) | |
# function/filter | |
_publicFunction = _FUNCTYPE(None, c_void_p, c_void_p, c_void_p, c_void_p, _API) | |
_freeFuncData = _FUNCTYPE(None, c_void_p) | |
_filterInit = _FUNCTYPE(None, c_void_p, c_void_p, POINTER(c_void_p), c_void_p, c_void_p, _API) | |
_filterGetFrame = _FUNCTYPE(c_void_p, c_int, c_int, POINTER(c_void_p), POINTER(c_void_p), c_void_p, c_void_p, _API) | |
_getOutputIndex = _FUNCTYPE(c_int, c_void_p) | |
_filterFree = _FUNCTYPE(None, c_void_p, c_void_p, _API) | |
_registerFunction = _FUNCTYPE(None, c_char_p, c_char_p, _publicFunction, c_void_p, c_void_p) | |
_createFilter = _FUNCTYPE(None, c_void_p, c_void_p, c_char_p, _filterInit, _filterGetFrame, _filterFree, c_int, c_int, c_void_p, c_void_p) | |
_invoke = _FUNCTYPE(c_void_p, c_void_p, c_char_p, c_void_p) | |
_setError = _FUNCTYPE(None, c_void_p, c_char_p) | |
_getError = _FUNCTYPE(c_char_p, c_void_p) | |
_setFilterError = _FUNCTYPE(None, c_char_p, c_void_p) | |
_getFormatPreset = _FUNCTYPE(Format, c_int, c_void_p) | |
_registerFormat = _FUNCTYPE(Format, c_int, c_int, c_int, c_int, c_int, c_void_p) | |
# frame and clip handling | |
_frameDoneCallback = _FUNCTYPE(None, c_void_p, c_void_p, c_int, c_void_p, c_char_p) | |
_getFrameAsync = _FUNCTYPE(None, c_int, c_void_p, _frameDoneCallback, c_void_p) | |
_getFrame = _FUNCTYPE(c_void_p, c_int, c_void_p, c_char_p, c_int) | |
_requestFrameFilter = _FUNCTYPE(None, c_int, c_void_p, c_void_p) | |
_getFrameFilter = _FUNCTYPE(c_void_p, c_int, c_void_p, c_void_p) | |
_cloneFrameRef= _FUNCTYPE(c_void_p, c_void_p) | |
_cloneNodeRef = _FUNCTYPE(c_void_p, c_void_p) | |
_cloneFuncRef = _FUNCTYPE(c_void_p, c_void_p) | |
_freeFrame = _FUNCTYPE(None, c_void_p) | |
_freeNode = _FUNCTYPE(None, c_void_p) | |
_freeFunc = _FUNCTYPE(None, c_void_p) | |
_newVideoFrame = _FUNCTYPE(c_void_p, Format, c_int, c_int, c_void_p, c_void_p) | |
_newVideoFrame2 = _FUNCTYPE(c_void_p, Format, c_int, c_int, c_void_p, POINTER(c_int), c_void_p, c_void_p) | |
_copyFrame = _FUNCTYPE(c_void_p, c_void_p, c_void_p) | |
_copyFrameProps = _FUNCTYPE(None, c_void_p, c_void_p, c_void_p) | |
_getStride = _FUNCTYPE(c_int, c_void_p, c_int) | |
_getReadPtr = _FUNCTYPE(c_uint8, c_void_p, c_int) | |
_getWritePtr = _FUNCTYPE(c_uint8, c_void_p, c_int) | |
# property access | |
_getVideoInfo = _FUNCTYPE(POINTER(VideoInfo), c_void_p) | |
_setVideoInfo = _FUNCTYPE(None, VideoInfo, c_int, c_void_p) | |
_getFrameFormat = _FUNCTYPE(POINTER(Format), c_void_p) | |
_getFrameWidth = _FUNCTYPE(c_int, c_void_p, c_int) | |
_getFrameHeight = _FUNCTYPE(c_int, c_void_p, c_int) | |
_getFramePropsRO = _FUNCTYPE(c_void_p, c_void_p) | |
_getFramePropsRW = _FUNCTYPE(c_void_p, c_void_p) | |
_propNumKeys = _FUNCTYPE(c_int, c_void_p) | |
_propGetKey = _FUNCTYPE(c_char_p, c_void_p, c_int) | |
_propNumElements = _FUNCTYPE(c_int, c_void_p, c_char_p) | |
_propGetType = _FUNCTYPE(c_char, c_void_p, c_char_p) | |
_createMap = _FUNCTYPE(c_void_p) | |
_freeMap = _FUNCTYPE(None, c_void_p) | |
_clearMap = _FUNCTYPE(None, c_void_p) | |
_propGetInt = _FUNCTYPE(c_int64, c_void_p, c_char_p, c_int, POINTER(c_int)) | |
_propGetFloat = _FUNCTYPE(c_double, c_void_p, c_char_p, c_int, POINTER(c_int)) | |
_propGetData = _FUNCTYPE(c_char_p, c_void_p, c_char_p, c_int, POINTER(c_int)) | |
_propGetDataSize = _FUNCTYPE(c_int, c_void_p, c_char_p, c_int, POINTER(c_int)) | |
_propGetNode = _FUNCTYPE(c_void_p, c_void_p, c_char_p, c_int, POINTER(c_int)) | |
_propGetFrame = _FUNCTYPE(c_void_p, c_void_p, c_char_p, c_int, POINTER(c_int)) | |
_propGetFunc = _FUNCTYPE(c_void_p, c_void_p, c_char_p, c_int, POINTER(c_int)) | |
_propDeleteKey = _FUNCTYPE(c_int, c_void_p, c_char_p) | |
_propSetInt = _FUNCTYPE(c_int, c_void_p, c_char_p, c_int, c_int) | |
_propSetFloat = _FUNCTYPE(c_int, c_void_p, c_char_p, c_double, c_int) | |
_propSetData = _FUNCTYPE(c_int, c_void_p, c_char_p, c_char_p, c_int, c_int) | |
_propSetNode = _FUNCTYPE(c_int, c_void_p, c_char_p, c_void_p, c_int) | |
_propSetFrame = _FUNCTYPE(c_int, c_void_p, c_char_p, c_void_p, c_int) | |
_propSetFunc = _FUNCTYPE(c_int, c_void_p, c_char_p, c_void_p, c_int) | |
# mixed | |
_configPlugin = _FUNCTYPE(None, c_char_p, c_char_p, c_char_p, c_int, c_int, c_void_p) | |
_initPlugin = _FUNCTYPE(None, _configPlugin, _registerFunction, c_void_p) | |
_getPluginId = _FUNCTYPE(c_void_p, c_char_p, c_void_p) | |
_getPluginNs = _FUNCTYPE(c_void_p, c_char_p, c_void_p) | |
_getPlugins = _FUNCTYPE(c_void_p, c_void_p) | |
_getFunctions = _FUNCTYPE(c_void_p, c_void_p) | |
_callFunc = _FUNCTYPE(None, c_void_p, c_void_p, c_void_p, c_void_p, _API) | |
_createFunc = _FUNCTYPE(c_void_p, _publicFunction, c_void_p, _freeFuncData) | |
_queryCompletedFrame = _FUNCTYPE(None, c_void_p, POINTER(c_int), c_void_p) | |
_releaseFrameEarly = _FUNCTYPE(None, POINTER(c_void_p), c_int, c_void_p) | |
_setMaxCacheSize = _FUNCTYPE(c_int64, c_int64, c_void_p) | |
_MessageHandler = _FUNCTYPE(None, c_int, c_char_p) | |
_setMessageHandler = _FUNCTYPE(None, c_void_p) | |
_API._fields_ = [ | |
("createCore", _createCore), | |
("freeCore", _freeCore), | |
("getCoreInfo", _getCoreInfo), | |
("cloneFrameRef", _cloneFrameRef), | |
("cloneNodeRef", _cloneNodeRef), | |
("cloneFuncRef", _cloneFuncRef), | |
("freeFrame", _freeFrame), | |
("freeNode", _freeNode), | |
("freeFunc", _freeFunc), | |
("newVideoFrame", _newVideoFrame), | |
("copyFrame", _copyFrame), | |
("copyFrameProps", _copyFrameProps), | |
("registerFunction", _registerFunction), | |
("getPluginId", _getPluginId), | |
("getPluginNs", _getPluginNs), | |
("getPlugins", _getPlugins), | |
("getFunctions", _getFunctions), | |
("createFilter", _createFilter), # do never use inside a filter's getframe function | |
("setError", _setError), # use to signal errors outside filter getframe functions | |
("getError", _getError), # use to query errors, returns 0 if no error | |
("setFilterError", _setFilterError), # use to signal errors in the filter getframe function | |
("invoke", _invoke), # may not be used inside a filter's getframe method | |
("getFormatPreset", _getFormatPreset), #threadsafe | |
("registerFormat", _registerFormat), # threadsafe | |
("getFrame", _getFrame), # do never use inside a filter's getframe function, for external applications using the core as a library or for requesting frames in a filter constructor | |
("getFrameAsync", _getFrameAsync), # do never use inside a filter's getframe function, for external applications using the core as a library or for requesting frames in a filter constructor | |
("getFrameFilter", _getFrameFilter), # only use inside a filter's getframe function | |
("requestFrameFilter", _requestFrameFilter), # only use inside a filter's getframe function | |
("queryCompletedFrame", _queryCompletedFrame), # only use inside a filter's getframe function | |
("releaseFrameEarly", _releaseFrameEarly), # only use inside a filter's getframe function | |
("getStride", _getStride), | |
("getReadPtr", _getReadPtr), | |
("getWritePtr", _getWritePtr), | |
("createFunc", _createFunc), | |
("callFunc", _callFunc), | |
# property access functions | |
("createMap", _createMap), | |
("freeMap", _freeMap), | |
("clearMap", _clearMap), | |
("getVideoInfo", _getVideoInfo), | |
("setVideoInfo", _setVideoInfo), | |
("getFrameFormat", _getFrameFormat), | |
("getFrameWidth", _getFrameWidth), | |
("getFrameHeight", _getFrameHeight), | |
("getFramePropsRO", _getFramePropsRO), | |
("getFramePropsRW", _getFramePropsRW), | |
("propNumKeys", _propNumKeys), | |
("propGetKey", _propGetKey), | |
("propNumElements", _propNumElements), | |
("propGetType", _propGetType), | |
("propGetInt", _propGetInt), | |
("propGetFloat", _propGetFloat), | |
("propGetData", _propGetData), | |
("propGetDataSize", _propGetDataSize), | |
("propGetNode", _propGetNode), | |
("propGetFrame", _propGetFrame), | |
("propGetFunc", _propGetFunc), | |
("propDeleteKey", _propDeleteKey), | |
("propSetInt", _propSetInt), | |
("propSetFloat", _propSetFloat), | |
("propSetData", _propSetData), | |
("propSetNode", _propSetNode), | |
("propSetFrame", _propSetFrame), | |
("propSetFunc", _propSetFunc), | |
("setMaxCacheSize", _setMaxCacheSize), | |
("getOutputIndex", _getOutputIndex), | |
("newVideoFrame2", _newVideoFrame2), | |
("setMessageHandler", _setMessageHandler), | |
] | |
class VapourSynthAPI(): | |
def __init__(self, version=None, api=None): | |
if api is None: | |
self.api = _getVapourSynthAPI(version) | |
else: | |
self.api = api | |
def create_core(self, threads=0): | |
return self.api.contents.createCore(threads) | |
def free_core(self, core): | |
self.api.contents.freeCore(core) | |
def get_core_info(self, core): | |
return self.api.contents.getCoreInfo(core).contents | |
def create_map(self): | |
return self.api.contents.createMap() | |
def prop_num_keys(self, map): | |
return self.api.contents.propNumKeys(map) | |
def prop_get_key(self, map, index): | |
return self.api.contents.propGetKey(map, index) | |
def prop_num_elements(self, map, key): | |
return self.api.contents.propNumElements(map, key) | |
def prop_get_type(self, map, key): | |
return self.api.contents.propGetType(map, key) | |
def prop_get_node(self, map, key, index=0): | |
error = c_int() | |
node = self.api.contents.propGetNode(map, key, index, byref(error)) | |
return node, error.value | |
def prop_get_data(self, map, key, index=0): | |
error = c_int() | |
string = self.api.contents.propGetData(map, key, index, byref(error)) | |
return string, error.value | |
def prop_set_int(self, map, key, int, append=False): | |
return self.api.contents.propSetInt(map, key, int, append) | |
def prop_set_data(self, map, key, string, append=False): | |
return self.api.contents.propSetData(map, key, string, len(string), append) | |
def get_plugins(self, core): | |
return self.api.contents.getPlugins(core) | |
def get_plugin_id(self, id, core): | |
return self.api.contents.getPluginId(id, core) | |
def get_plugin_ns(self, ns, core): | |
return self.api.contents.getPluginNs(ns, core) | |
def get_functions(self, plugin): | |
return self.api.contents.getFunctions(plugin) | |
def invoke(self, plugin, function_name, args=None): | |
if args is None: | |
args = self.create_map() | |
return self.api.contents.invoke(plugin, function_name, args) | |
def get_video_info(self, node): | |
return self.api.contents.getVideoInfo(node).contents | |
def get_frame(self, n, node, error_msg=b''): | |
return self.api.contents.getFrame(n, node, error_msg, len(error_msg)) | |
def get_frame_format(self, frame_ref): | |
return self.api.contents.getFrameFormat(frame_ref) | |
def get_stride(self, frame_ref, plane=0): | |
return self.api.contents.getStride(frame_ref, plane) | |
def get_frame_width(self, frame_ref, plane=0): | |
return self.api.contents.getFrameWidth(frame_ref, plane) | |
def get_frame_height(self, frame_ref, plane=0): | |
return self.api.contents.getFrameHeight(frame_ref, plane) | |
def get_read_ptr(self, frame_ref, plane=0): | |
return self.api.contents.getReadPtr(frame_ref, plane) | |
def free_frame(self, frame_ref): | |
self.api.contents.freeFrame(frame_ref) | |
def free_node(self, node): | |
self.api.contents.freeNode(node) | |
def get_error(self, map): | |
self.api.contents.getError(map) | |
# VSScript.h | |
# EvalFlags enum | |
efSetWorkingDir = 1 | |
# Initialize the available scripting runtimes, returns zero on failure | |
_vsscript_init = _vsscript.vsscript_init | |
_vsscript_init.argtypes = None | |
_vsscript_init.restype = c_int | |
# Free all scripting runtimes | |
_vsscript_finalize = _vsscript.vsscript_finalize | |
_vsscript_finalize.argtypes = None | |
_vsscript_finalize.restype = c_int | |
# Pass a pointer to a null handle to create a new one | |
# The values returned by the query functions are only valid during the lifetime of the VSScript | |
# scriptFilename is if the error message should reference a certain file, NULL allowed in vsscript_evaluateScript() | |
# core is to pass in an already created instance so that mixed environments can be used, | |
# If efSetWorkingDir is passed to flags the current working directory will be changed to the path of the script | |
# note that if scriptFilename is NULL in vsscript_evaluateScript() then __file__ won't be set and the working directory won't be changed | |
# Set efSetWorkingDir to get the default behavior | |
# NULL creates a new core that can be fetched with vsscript_getCore() later OR implicitly uses the one associated with an already existing handle when passed | |
_vsscript_evaluateScript = _vsscript.vsscript_evaluateScript | |
_vsscript_evaluateScript.argtypes = [POINTER(c_void_p), c_char_p, c_char_p, c_int] | |
_vsscript_evaluateScript.restype = c_int | |
# Convenience version of the above function that loads the script from a file | |
_vsscript_evaluateFile = _vsscript.vsscript_evaluateFile | |
_vsscript_evaluateFile.argtypes = [POINTER(c_void_p), c_char_p, c_int] | |
_vsscript_evaluateFile.restype = c_int | |
_vsscript_freeScript = _vsscript.vsscript_freeScript | |
_vsscript_freeScript.argtypes = [c_void_p] | |
_vsscript_freeScript.restype = None | |
_vsscript_getError = _vsscript.vsscript_getError | |
_vsscript_getError.argtypes = [c_void_p] | |
_vsscript_getError.restype = c_char_p | |
# The node returned must be freed using freeNode() before calling vsscript_freeScript() | |
_vsscript_getOutput = _vsscript.vsscript_getOutput | |
_vsscript_getOutput.argtypes = [c_void_p, c_int] | |
_vsscript_getOutput.restype = c_void_p | |
_vsscript_clearOutput = _vsscript.vsscript_clearOutput | |
_vsscript_clearOutput.argtypes = [c_void_p, c_int] | |
_vsscript_clearOutput.restype = None | |
# The core is valid as long as the environment exists | |
_vsscript_getCore = _vsscript.vsscript_getCore | |
_vsscript_getCore.argtypes = [c_void_p] | |
_vsscript_getCore.restype = c_void_p | |
_vsscript_getVSApi = _vsscript.vsscript_getVSApi | |
_vsscript_getVSApi.argtypes = None | |
_vsscript_getVSApi.restype = POINTER(_API) | |
# Variables names that are not set or not of a convertible type will return an error | |
_vsscript_getVariable = _vsscript.vsscript_getVariable | |
_vsscript_getVariable.argtypes = [c_void_p, c_char_p, c_void_p] | |
_vsscript_getVariable.restype = c_int | |
_vsscript_setVariable = _vsscript.vsscript_setVariable | |
_vsscript_setVariable.argtypes = [c_void_p, c_void_p] | |
_vsscript_setVariable.restype = None | |
_vsscript_clearVariable = _vsscript.vsscript_clearVariable | |
_vsscript_clearVariable.argtypes = [c_void_p, c_char_p] | |
_vsscript_clearVariable.restype = c_int | |
# Tries to clear everything set in an environment, normally it is better to simply free an environment completely and create a new one | |
_vsscript_clearEnvironment = _vsscript.vsscript_clearEnvironment | |
_vsscript_clearEnvironment.argtypes = [c_void_p] | |
_vsscript_clearEnvironment.restype = None | |
def init(): | |
"""Initialize the available scripting runtimes | |
Returns zero on failure""" | |
return _vsscript_init() | |
def finalize(): | |
"""Free all scripting runtimes""" | |
return _vsscript_finalize() | |
def evaluate_script(script, handle=None, script_filename=None, flags=efSetWorkingDir): | |
"""Evaluate 'script' string | |
If 'handle' is None a new one is created | |
'script_filename' is if the error message should reference a certain file, | |
None allowed | |
If efSetWorkingDir is passed to 'flags' the current working directory will | |
be changed to the path of the script before its evaluation, and changed back | |
afterwards. This is the default behavior. | |
Note that if 'script_filename' is None then __file__ won't be set and the | |
working directory won't be changed | |
Returns (error code, handle) | |
""" | |
if handle is None: | |
handle = c_void_p() | |
err = _vsscript_evaluateScript(byref(handle), script, script_filename, flags) | |
return err, handle | |
def evaluate_file(script_filename, handle=None, flags=efSetWorkingDir): | |
"""Convenience version of 'evaluate_script' that loads the script from a file""" | |
if handle is None: | |
handle = c_void_p() | |
err = _vsscript_evaluateFile(byref(handle), script_filename, flags) | |
return err, handle | |
def free_script(handle): | |
"""Free the script associated to 'handle'""" | |
_vsscript_freeScript(handle) | |
def get_error(handle): | |
"""Return the error string, if any""" | |
return _vsscript_getError(handle) | |
def get_output(handle, index=0): | |
"""Returns the output (NodeRef) from 'handle'""" | |
return _vsscript_getOutput(handle, index) | |
def clear_output(handle, index): | |
"""Clear the output 'index' from 'handle'""" | |
_vsscript_clearOutput(handle, index) | |
def get_core(handle): | |
"""Retrieve the Core object from 'handle'""" | |
return _vsscript_getCore(handle) | |
def get_VS_API(): | |
"""Retrieve an API object | |
Must be called after init() | |
""" | |
return VapourSynthAPI(api=_vsscript_getVSApi()) | |
def get_variable(handle, name): | |
"""Retrieve the variable 'name' | |
Return an error if the variable is not set | |
""" | |
map = api.create_map() | |
err = _vsscript_getVariable(handle, name, map) | |
return err, map | |
def set_variable(handle, vars): | |
"""Set variables from a 'vars' dict""" | |
_vsscript_setVariable(handle, _VSMap_from_map(vars)) | |
def clear_variable(handle, name): | |
"""Clear the variable 'name' | |
Return an error if the variable is not set | |
""" | |
return _vsscript_clearVariable(handle, name) | |
def clear_environment(handle): | |
"""Clear 'handle's environment""" | |
_vsscript_clearEnvironment(handle) | |
def _VSMap_from_map(py_map): | |
map = api.create_map() | |
for key, value in py_map.items(): | |
if not isinstance(value, Iterable) or isinstance(value, basestring): | |
value = value, | |
for item in value: | |
api.prop_set_data(map, key, item, append=True) | |
return map | |
# VSHelper.h | |
def is_constant_format(vi): | |
"""convenience function for checking if the format never changes between frames""" | |
return vi.height > 0 and vi.width > 0 and vi.format | |
def is_same_format(v1, v2): | |
"""convenience function to check for if two clips have the same format(unknown/changeable will be considered the same too)""" | |
return v1.height == v2.height and v1.width == v2.width and v1.format == v2.format | |
def muldiv_rational(num, den, mul, div): | |
"""multiplies and divides a rational number, such as a frame duration, in place and reduces the result""" | |
num *= mul | |
den *= div | |
a = num | |
b = den | |
while b != 0: | |
a, b = b, a % b | |
if a < 0: | |
a = -a | |
return num / a, den / a | |
def int64_to_ints(i): | |
"""converts an int64 to int with saturation, useful to silence warnings when reading int properties among other things""" | |
int_max = sizeof(c_int) * 8 - 1 | |
if(i > int_max): | |
return int_max | |
elif(i < 0): | |
return 0 | |
return i | |
def vs_bitblt(dstp, dst_stride, srcp, src_stride, row_size, height): | |
if height > 0: | |
if src_stride == dst_stride and src_stride == row_size: | |
memmove(dstp, srcp, row_size * height) | |
else: | |
for i in range(height): | |
memmove(dstp, srcp, row_size) | |
srcp += src_stride | |
dstp += dst_stride | |
def are_valid_dimensions(fi, width, height): | |
"""check if the frame dimensions are valid for a given format | |
returns non-zero for valid width and height""" | |
return not(width % (1 << fi.subSamplingW) or height % (1 << fi.subSamplingH)) | |
if __name__ == '__main__': | |
# get version and functions, invoke BlankClip and show video info | |
api = VapourSynthAPI(API_VERSION) | |
core = api.create_core() | |
print(repr(api.get_core_info(core))) | |
plugins = api.get_plugins(core) | |
for index in range(api.prop_num_keys(plugins)): | |
plugin_key = api.prop_get_key(plugins, index) | |
print(plugin_key) | |
functions = api.get_functions(api.get_plugin_id(plugin_key, core)) | |
for index in range(api.prop_num_keys(functions)): | |
function_key = api.prop_get_key(functions, index) | |
for index in range(api.prop_num_elements(functions, function_key)): | |
print(b' ' + api.prop_get_data(functions, function_key, index)[0][:74]) | |
clip_map = api.invoke(api.get_plugin_ns(b'std', core), b'BlankClip') | |
node, err = api.prop_get_node(clip_map, b'clip') | |
print(repr(api.get_video_info(node))) | |
print(repr(api.get_video_info(node).format.contents)) | |
api.free_node(node) | |
api.free_core(core) | |
# evaluate script (BlankClip again) | |
script_text = br""" | |
import sys | |
try: # add the script filename, when passed to evaluate_script | |
path = sys.path + ['vpy file: ' + __file__] | |
except NameError: | |
path = sys.path + ['__file__ not defined'] | |
import vapoursynth as vs | |
core = vs.get_core() | |
clip = core.std.BlankClip() | |
#core.std.LoadPlugin(r'C:\Program Files (x86)\AviSynth 2.5\plugins\ffms2.dll') | |
#clip = core.ffms2.Source('test.avi') # test relative paths | |
clip.set_output() | |
""" | |
print('\ninit', init()) | |
api = get_VS_API() | |
if 1: | |
err, handle = evaluate_script(script_text) | |
else: | |
alt_dir = r'' # test relative paths | |
vpf_path = os.path.join(alt_dir, 'test.vpy') | |
with open(vpf_path, 'wb') as vpy: | |
vpy.write(script_text) | |
err, handle = evaluate_file(vpf_path.encode('utf8')) | |
if err: | |
print('error {0} evaluating script'.format(get_error(handle))) | |
else: | |
# show video info | |
node = get_output(handle) | |
print(repr(api.get_video_info(node))) | |
print(repr(api.get_video_info(node).format.contents)) | |
# check setting and getting variables. retrieve sys.path | |
#err = set_variable(handle, {b'path': [b'123', b'678', u'ñ'.encode('utf8')], b'abc': b'cba'}) | |
err, var_map = get_variable(handle, b'path') | |
if err: | |
print("error {0} retrieving 'sys.path'".format(err)) | |
else: | |
for index in range(api.prop_num_keys(var_map)): | |
var_key = api.prop_get_key(var_map, index) | |
print("index {0}, key '{1}', type '{2}'".format( | |
index, var_key, api.prop_get_type(var_map, var_key))) | |
for index in range(api.prop_num_elements(var_map, var_key)): | |
print(api.prop_get_data(var_map, var_key, index)[0]. | |
decode('utf8').encode(sys.stdout.encoding)) | |
# get one frame and check again format | |
frame_ref = api.get_frame(5, node) | |
print('stride: {0}, width: {1}, height: {2}'.format( | |
api.get_stride(frame_ref), api.get_frame_width(frame_ref), | |
api.get_frame_height(frame_ref))) | |
print(repr(api.get_frame_format(frame_ref).contents)) | |
api.get_read_ptr(frame_ref) | |
api.free_frame(frame_ref) | |
api.free_node(node) | |
free_script(handle) | |
print('finalize', finalize()) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment