From e04045e297aac09ae40086220846660318a0e22e Mon Sep 17 00:00:00 2001 From: akarin Date: Tue, 21 Sep 2021 10:13:37 +0900 Subject: [PATCH 1/8] src/core/vscore.cpp: add support for profiling filter creation Signed-off-by: akarin --- src/core/vscore.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/core/vscore.cpp b/src/core/vscore.cpp index 0bbdca116..09e6dba0f 100644 --- a/src/core/vscore.cpp +++ b/src/core/vscore.cpp @@ -32,6 +32,10 @@ #include #include +#ifdef VS_PROFILE_CREATE +#include +#endif + #ifdef VS_TARGET_CPU_X86 #include "x86utils.h" #endif @@ -812,7 +816,16 @@ VSMap *VSPluginFunction::invoke(const VSMap &args) { if (enableGraphInspection) { plugin->core->functionFrame = std::make_shared(name, new VSMap(&args), plugin->core->functionFrame); } + +#ifdef VS_PROFILE_CREATE + std::chrono::time_point startTime = std::chrono::high_resolution_clock::now(); +#endif func(&args, v, functionData, plugin->core, getVSAPIInternal(plugin->apiMajor)); +#ifdef VS_PROFILE_CREATE + std::chrono::nanoseconds duration = std::chrono::high_resolution_clock::now() - startTime; + std::cerr << this->plugin->fnamespace << "." << this->name << " uses " << 0.001 * (double)duration.count() << " us" << std::endl; +#endif + if (enableGraphInspection) { assert(plugin->core->functionFrame); plugin->core->functionFrame = plugin->core->functionFrame->next; From f80dcdfd21a3c3f5f011ed8f952d81bc3c047173 Mon Sep 17 00:00:00 2001 From: akarin Date: Mon, 17 Jan 2022 19:09:48 +0900 Subject: [PATCH 2/8] Makefile.am, msvc_project/Core/Core.vcxproj: update to use C++17 Signed-off-by: akarin --- Makefile.am | 2 +- msvc_project/Core/Core.vcxproj | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Makefile.am b/Makefile.am index 1229eda11..8749ad2a1 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,6 +1,6 @@ warningflags = -Wall -Wextra -Wno-unused-parameter -Wno-unused-function -Wno-ignored-attributes commoncflags = -O3 -fvisibility=hidden $(warningflags) -I$(srcdir)/include $(DEBUGCFLAGS) $(MFLAGS) $(UNICODECFLAGS) $(STACKREALIGN) -AM_CXXFLAGS = -std=c++14 $(commoncflags) +AM_CXXFLAGS = -std=c++17 $(commoncflags) AM_CFLAGS = -std=c99 $(commoncflags) ACLOCAL_AMFLAGS = -I m4 diff --git a/msvc_project/Core/Core.vcxproj b/msvc_project/Core/Core.vcxproj index 1f92ca554..5123ab042 100644 --- a/msvc_project/Core/Core.vcxproj +++ b/msvc_project/Core/Core.vcxproj @@ -89,7 +89,7 @@ true NOMINMAX;VS_CORE_EXPORTS;VS_TARGET_OS_WINDOWS;VS_TARGET_CPU_X86;VS_USE_MIMALLOC;VS_GRAPH_API;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) true - stdcpp14 + stdcpp17 true @@ -108,7 +108,7 @@ true NOMINMAX;VS_CORE_EXPORTS;VS_TARGET_OS_WINDOWS;VS_TARGET_CPU_X86;VS_USE_MIMALLOC;VS_GRAPH_API;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) true - stdcpp14 + stdcpp17 true @@ -130,7 +130,7 @@ StreamingSIMDExtensions2 false true - stdcpp14 + stdcpp17 true @@ -154,7 +154,7 @@ NOMINMAX;VS_CORE_EXPORTS;VS_TARGET_OS_WINDOWS;VS_TARGET_CPU_X86;VS_USE_MIMALLOC;VS_GRAPH_API;_CRT_SECURE_NO_WARNINGS;NDEBUG;%(PreprocessorDefinitions) false true - stdcpp14 + stdcpp17 true From e2ebccda791456b8753de0fd6c8631d802169bfa Mon Sep 17 00:00:00 2001 From: akarin Date: Mon, 17 Jan 2022 19:10:37 +0900 Subject: [PATCH 3/8] src/core/vsapi.cpp, vscore.h: introduce vs-c internal API It will only be used internally: 1. getPluginAPIVersion: returns the major API version of a plugin. 2. pluginSetRO: set the readonly status of a plugin, and return the old status. 3. pluginRenameFunc: rename a plugin function. They should provide the basis for cython level filter function replacement. Signed-off-by: akarin --- include/VapourSynthC.h | 36 ++++++++++++++++++++++++++++++++++ src/core/vsapi.cpp | 44 ++++++++++++++++++++++++++++++++++++++++++ src/core/vscore.h | 4 ++++ 3 files changed, 84 insertions(+) create mode 100644 include/VapourSynthC.h diff --git a/include/VapourSynthC.h b/include/VapourSynthC.h new file mode 100644 index 000000000..e3067f9a6 --- /dev/null +++ b/include/VapourSynthC.h @@ -0,0 +1,36 @@ +/* +* Copyright (c) 2012-2022 Fredrik Mellbin +* +* This file is part of VapourSynth Classic. +* +* VS-C is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 3 of the License, or (at your option) any later version. +* +* VapourSynth is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with VapourSynth; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// This API is for VS-C internal use only. + +#ifndef VAPOURSYNTHC_H +#define VAPOURSYNTHC_H + +#include + +#define VAPOURSYNTHC_API_VERSION 0x76732d63 // 'vs-c' + +typedef struct VSCAPI { + int (VS_CC *getPluginAPIVersion)(const VSPlugin *); // major version only + int (VS_CC *pluginSetRO)(VSPlugin *, int readonly); // returns old status + int (VS_CC *pluginRenameFunc)(VSPlugin *, const char *oldname, const char *newname); +} VSCAPI; + +#endif /* VAPOURSYNTHC_H */ diff --git a/src/core/vsapi.cpp b/src/core/vsapi.cpp index 2d51a730e..5cbf41d00 100644 --- a/src/core/vsapi.cpp +++ b/src/core/vsapi.cpp @@ -22,6 +22,7 @@ #include "cpufeatures.h" #include "vslog.h" #include "VSHelper4.h" +#include "VapourSynthC.h" #include #include #include @@ -1278,6 +1279,47 @@ const vs3::VSAPI3 vs_internal_vsapi3 = { &getCoreInfo2 }; +/////////////////////////////// +static int VS_CC getPluginAPIVersion(const VSPlugin *plugin) VS_NOEXCEPT { + assert(plugin); + if (!plugin) + return -1; + return plugin->getAPIVersion(); +} +static int VS_CC pluginSetRO(VSPlugin *plugin, int readonly) VS_NOEXCEPT { + assert(plugin); + const bool old = plugin->isLocked(); + if (readonly) + plugin->lock(); + else + plugin->unlock(); + return old; +} +bool VSPluginFunction::rename(const std::string &newname) { + if (name == newname) + return false; + + std::lock_guard lock(plugin->functionLock); + + auto &funcs = plugin->funcs; + auto node = funcs.extract(name); + node.key() = newname; + funcs.insert(std::move(node)); + + name = newname; + return true; +} +static int VS_CC pluginRenameFunc(VSPlugin *plugin, const char *oldname, const char *newname) VS_NOEXCEPT { + assert(plugin && oldname && newname); + VSPluginFunction *func = plugin->getFunctionByName(oldname); + if (!func) return false; + return func->rename(newname); +} +static const VSCAPI vsc_internal_api = { + &getPluginAPIVersion, + &pluginSetRO, + &pluginRenameFunc, +}; /////////////////////////////// const VSAPI *getVSAPIInternal(int apiMajor) { @@ -1305,6 +1347,8 @@ const VSAPI *VS_CC getVapourSynthAPI(int version) VS_NOEXCEPT { return &vs_internal_vsapi; } else if (apiMajor == VAPOURSYNTH3_API_MAJOR && apiMinor <= VAPOURSYNTH3_API_MINOR) { return reinterpret_cast(&vs_internal_vsapi3); + } else if (version == VAPOURSYNTHC_API_VERSION) { + return reinterpret_cast(&vsc_internal_api); } else { return nullptr; } diff --git a/src/core/vscore.h b/src/core/vscore.h index e7c69f3eb..d0cbd83b4 100644 --- a/src/core/vscore.h +++ b/src/core/vscore.h @@ -1005,6 +1005,7 @@ struct VSPluginFunction { bool isV3Compatible() const; std::string getV4ArgString() const; std::string getV3ArgString() const; + bool rename(const std::string &newname); // 'vs-c' }; @@ -1034,6 +1035,8 @@ struct VSPlugin { VSPlugin(const std::string &relFilename, const std::string &forcedNamespace, const std::string &forcedId, bool altSearchPath, VSCore *core); ~VSPlugin(); void lock() { readOnly = true; } + void unlock() { readOnly = false; } // 'vs-c' + bool isLocked() const { return readOnly; } // 'vs-c' bool configPlugin(const std::string &identifier, const std::string &pluginsNamespace, const std::string &fullname, int pluginVersion, int apiVersion, int flags); bool registerFunction(const std::string &name, const std::string &args, const std::string &returnType, VSPublicFunction argsFunc, void *functionData); VSMap *invoke(const std::string &funcName, const VSMap &args); @@ -1044,6 +1047,7 @@ struct VSPlugin { const std::string &getNamespace() const { return fnamespace; } const std::string &getFilename() const { return filename; } int getPluginVersion() const { return pluginVersion; } + int getAPIVersion() const { return apiMajor; } // 'vs-c' void getFunctions3(VSMap *out) const; }; From 6175fdcdf2a86ce437904d24f4132ae5701f5c3c Mon Sep 17 00:00:00 2001 From: akarin Date: Mon, 17 Jan 2022 22:48:18 +0900 Subject: [PATCH 4/8] src/cython/vapoursynth.pxd, vapoursynth.pyx: add Plugin._register_func This provides a way for the user to define Python filter function in a plugin namespace and it also allows overriding existing filters. While this functionality is very generic, our intended use is to provide compatibility wrapper for filters. For example, ``` def tcanny(**args): if 'gmmax' in args: args['scale'] = args['gmmax'] / 255.0 del args['gmmax'] return core.tcanny._TCanny(**args) core.tcanny._register_func('TCanny', \ core.tcanny.get_functions()['TCanny']+'gmmax:float:opt;', \ None, tcanny, override=True) ``` As this is an advanced API, there is no safe guard in place, and you can even modify the `core.std` namespace. Please be careful. Signed-off-by: akarin --- src/cython/vapoursynth.pxd | 8 ++++ src/cython/vapoursynth.pyx | 83 +++++++++++++++++++++++++++++++++++++- 2 files changed, 90 insertions(+), 1 deletion(-) diff --git a/src/cython/vapoursynth.pxd b/src/cython/vapoursynth.pxd index ec75a4bca..98847ecc9 100644 --- a/src/cython/vapoursynth.pxd +++ b/src/cython/vapoursynth.pxd @@ -388,3 +388,11 @@ cdef extern from "include/VapourSynth4.h" nogil: bint removeLogHandler(VSLogHandle *handle, VSCore *core) nogil const VSAPI *getVapourSynthAPI(int version) nogil + +cdef extern from "include/VapourSynthC.h" nogil: + enum: + VAPOURSYNTHC_API_VERSION + ctypedef struct VSCAPI: + int getPluginAPIVersion(VSPlugin *) nogil + int pluginSetRO(VSPlugin *, int) nogil + int pluginRenameFunc(VSPlugin *, const char *, const char *) nogil diff --git a/src/cython/vapoursynth.pyx b/src/cython/vapoursynth.pyx index 7acfd57c0..fba03bab2 100644 --- a/src/cython/vapoursynth.pyx +++ b/src/cython/vapoursynth.pyx @@ -171,6 +171,7 @@ cdef class StandaloneEnvironmentPolicy: cdef object _policy = None cdef const VSAPI *_vsapi = NULL +cdef const VSCAPI *_vscapi = NULL cdef void _set_logger(EnvironmentData env, VSLogHandler handler, VSLogHandlerFree free, void *userData): @@ -2491,6 +2492,84 @@ cdef class Plugin(object): return True return False + def _register_func(self, name, args, returnType, func, *, override=False): + if not override and name in self.__dir__(): + raise Error('cannot override existing filter "' + name + '" without explicitly setting override.') + if _vscapi == NULL: + getVSAPIInternal() + + tname = name.encode('utf-8') + cdef const char *cname = tname + + cdef int apiver = _vscapi.getPluginAPIVersion(self.plugin) + if apiver < VAPOURSYNTH_API_MAJOR: + args = args.replace(':vnode', ':clip').replace(':vframe', ':frame') + returnType = 'any' + + cdef const char *cargs = NULL + cdef const char *crett = NULL + + cdef VSPluginFunction *mfunc = self.funcs.getPluginFunctionByName(cname, self.plugin) + if (args is None or returnType is None) and mfunc == NULL: + raise Error('args or return type cannot be None unless the function already exists') + if args is None: + cargs = self.funcs.getPluginFunctionArguments(mfunc) + else: + targs = args.encode('utf-8') + cargs = targs + if returnType is None: + crett = self.funcs.getPluginFunctionReturnType(mfunc) + else: + trett = returnType.encode('utf-8') + crett = trett + + cdef bint ro = _vscapi.pluginSetRO(self.plugin, 0) + cdef const char *cnewname = NULL + if override: + tnewname = ('_' + name).encode('utf-8') + cnewname = tnewname + if not _vscapi.pluginRenameFunc(self.plugin, cname, cnewname): + raise Error('failed to rename existing filter') + + fdata = createFilterFuncData(func, self.core.core) + Py_INCREF(fdata) + + cdef bint ret = self.funcs.registerFunction(cname, cargs, crett, publicFilterFunction, fdata, self.plugin) + if ro: + _vscapi.pluginSetRO(self.plugin, 1) + return ret + +cdef class FilterFuncData(object): + cdef object func + cdef VSCore *core + + def __init__(self): + raise Error('Class cannot be instantiated directly') + + def __call__(self, **kwargs): + return self.func(**kwargs) + +cdef FuncData createFilterFuncData(object func, VSCore *core): + cdef FuncData instance = FuncData.__new__(FuncData) + instance.func = func + instance.core = core + return instance + +cdef void __stdcall publicFilterFunction(const VSMap *inm, VSMap *outm, void *userData, VSCore *core, const VSAPI *vsapi_do_not_use) nogil: + with gil: + d = userData + try: + m = mapToDict(inm, False) + ret = d(**m) + if not isinstance(ret, dict): + if ret is None: + ret = 0 + ret = {'clip':ret} + dictToMap(ret, outm, core, _vsapi) + except BaseException, e: + emsg = str(e).encode('utf-8') + _vsapi.mapSetError(outm, emsg) + cdef Plugin createPlugin(VSPlugin *plugin, const VSAPI *funcs, Core core): cdef Plugin instance = Plugin.__new__(Plugin) instance.core = core @@ -3074,9 +3153,11 @@ cdef public api const VSAPI *vpy4_getVSAPI(int version) nogil: return getVapourSynthAPI(version) cdef const VSAPI *getVSAPIInternal() nogil: - global _vsapi + global _vsapi, _vscapi if _vsapi == NULL: _vsapi = getVapourSynthAPI(VAPOURSYNTH_API_VERSION) + if _vscapi == NULL: + _vscapi = getVapourSynthAPI(VAPOURSYNTHC_API_VERSION) return _vsapi cdef public api int vpy4_getVariable(VSScript *se, const char *name, VSMap *dst) nogil: From c5e5ef91a97257c5d433785c0b07e772092ab567 Mon Sep 17 00:00:00 2001 From: akarin Date: Mon, 17 Jan 2022 23:23:51 +0900 Subject: [PATCH 5/8] src/cython/vapoursynth.pyx: allow explicitly specifying old name for the overridden function Also check for conflicting function names. Signed-off-by: akarin --- src/cython/vapoursynth.pyx | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/cython/vapoursynth.pyx b/src/cython/vapoursynth.pyx index fba03bab2..ad57d73a0 100644 --- a/src/cython/vapoursynth.pyx +++ b/src/cython/vapoursynth.pyx @@ -2492,9 +2492,18 @@ cdef class Plugin(object): return True return False - def _register_func(self, name, args, returnType, func, *, override=False): - if not override and name in self.__dir__(): + def _register_func(self, name, args, returnType, func, *, override=False): # 'vs-c' + myfuncs = self.__dir__() + if not override and name in myfuncs: raise Error('cannot override existing filter "' + name + '" without explicitly setting override.') + if override: + if isinstance(override, str): + newname = override + else: + newname = '_' + name + if newname in myfuncs: + raise Error('renamed function "' + newname + '" already exists') + if _vscapi == NULL: getVSAPIInternal() @@ -2526,7 +2535,7 @@ cdef class Plugin(object): cdef bint ro = _vscapi.pluginSetRO(self.plugin, 0) cdef const char *cnewname = NULL if override: - tnewname = ('_' + name).encode('utf-8') + tnewname = newname.encode('utf-8') cnewname = tnewname if not _vscapi.pluginRenameFunc(self.plugin, cname, cnewname): raise Error('failed to rename existing filter') From a4057332649198caff3e704e5bfa942245248826 Mon Sep 17 00:00:00 2001 From: akarin Date: Tue, 18 Jan 2022 00:43:38 +0900 Subject: [PATCH 6/8] src/cython/vapoursynth.pyx: if $VSC_DEBUG_REGISTER_FUNC is set, show detailed trace for registered Python functions Signed-off-by: akarin --- src/cython/vapoursynth.pyx | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/cython/vapoursynth.pyx b/src/cython/vapoursynth.pyx index ad57d73a0..beaa09e8f 100644 --- a/src/cython/vapoursynth.pyx +++ b/src/cython/vapoursynth.pyx @@ -2493,6 +2493,15 @@ cdef class Plugin(object): return False def _register_func(self, name, args, returnType, func, *, override=False): # 'vs-c' + if os.getenv('VSC_DEBUG_REGISTER_FUNC'): + dbgname = '%s.%s' % (self.namespace, name) + print('[VS-C]: registering %s(%s) -> %s, override=%r' % (dbgname, args, returnType, override), file=sys.stderr) + traceback.print_stack() + func_ = func + def wrapped(**args): + print('[VS-C] registered Python filter %s called with %r' % (dbgname, args), file=sys.stderr) + return func_(**args) + func = wrapped myfuncs = self.__dir__() if not override and name in myfuncs: raise Error('cannot override existing filter "' + name + '" without explicitly setting override.') From 69c75c68c553eec28dd0bd9a4792abfde35e82da Mon Sep 17 00:00:00 2001 From: akarin Date: Tue, 18 Jan 2022 02:16:45 +0900 Subject: [PATCH 7/8] src/cython/vapoursynth.pyx: restore if filter creation failed Signed-off-by: akarin --- src/cython/vapoursynth.pyx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/cython/vapoursynth.pyx b/src/cython/vapoursynth.pyx index beaa09e8f..b79d9f47b 100644 --- a/src/cython/vapoursynth.pyx +++ b/src/cython/vapoursynth.pyx @@ -2553,6 +2553,10 @@ cdef class Plugin(object): Py_INCREF(fdata) cdef bint ret = self.funcs.registerFunction(cname, cargs, crett, publicFilterFunction, fdata, self.plugin) + if not ret: + if cnewname != NULL: + assert _vscapi.pluginRenameFunc(self.plugin, cnewname, cname), 'failed to restore old filter name' + Py_DECREF(fdata) if ro: _vscapi.pluginSetRO(self.plugin, 1) return ret From a160fb782f4dac5a49a8a302e57c928d049478d3 Mon Sep 17 00:00:00 2001 From: akarin Date: Tue, 18 Jan 2022 02:17:08 +0900 Subject: [PATCH 8/8] include/VapourSynthC.h, core/vsapi.cpp, cython/vapoursynth.pyx: add Core._create_plugin This introduces Core._create_plugin to create a plugin namespace with pure Python. ``` import havsfunc as haf core._create_plugin('id', 'haf')._register_func('QTGMC', \ 'clip:vnode;any', 'clip:vnode', \ lambda clip, **kwargs: haf.QTGMC(clip, **kwargs)) c = core.std.BlankClip(format=vs.YUV420P10) d = c.haf.QTGMC(TFF=1) ``` Signed-off-by: akarin --- include/VapourSynthC.h | 1 + src/core/vsapi.cpp | 13 +++++++++++++ src/core/vscore.h | 2 ++ src/cython/vapoursynth.pxd | 1 + src/cython/vapoursynth.pyx | 12 ++++++++++++ 5 files changed, 29 insertions(+) diff --git a/include/VapourSynthC.h b/include/VapourSynthC.h index e3067f9a6..5faff3dbc 100644 --- a/include/VapourSynthC.h +++ b/include/VapourSynthC.h @@ -31,6 +31,7 @@ typedef struct VSCAPI { int (VS_CC *getPluginAPIVersion)(const VSPlugin *); // major version only int (VS_CC *pluginSetRO)(VSPlugin *, int readonly); // returns old status int (VS_CC *pluginRenameFunc)(VSPlugin *, const char *oldname, const char *newname); + VSPlugin *(VS_CC *createPlugin)(const char *id, const char *ns, int version, VSCore *core); } VSCAPI; #endif /* VAPOURSYNTHC_H */ diff --git a/src/core/vsapi.cpp b/src/core/vsapi.cpp index 5cbf41d00..e4a000b11 100644 --- a/src/core/vsapi.cpp +++ b/src/core/vsapi.cpp @@ -1315,10 +1315,23 @@ static int VS_CC pluginRenameFunc(VSPlugin *plugin, const char *oldname, const c if (!func) return false; return func->rename(newname); } +void VSCore::addPlugin(const std::string &name, VSPlugin *plugin) { + std::lock_guard lock(pluginLock); + plugins.emplace(name, plugin); +} +static VSPlugin *VS_CC createPlugin(const char *id, const char *ns, int version, VSCore *core) { + assert(id && ns && core); + VSPlugin *p = new VSPlugin(core); + vs_internal_vspapi.configPlugin(id, ns, "python plugin", version, VAPOURSYNTH_API_VERSION, 0, p); + p->lock(); + core->addPlugin(ns, p); + return p; +} static const VSCAPI vsc_internal_api = { &getPluginAPIVersion, &pluginSetRO, &pluginRenameFunc, + &createPlugin, }; /////////////////////////////// diff --git a/src/core/vscore.h b/src/core/vscore.h index d0cbd83b4..109dad867 100644 --- a/src/core/vscore.h +++ b/src/core/vscore.h @@ -1166,6 +1166,8 @@ struct VSCore { explicit VSCore(int flags); void freeCore(); + + void addPlugin(const std::string &name, VSPlugin *plugin); // 'vs-c' }; #endif // VSCORE_H diff --git a/src/cython/vapoursynth.pxd b/src/cython/vapoursynth.pxd index 98847ecc9..ba36340fe 100644 --- a/src/cython/vapoursynth.pxd +++ b/src/cython/vapoursynth.pxd @@ -396,3 +396,4 @@ cdef extern from "include/VapourSynthC.h" nogil: int getPluginAPIVersion(VSPlugin *) nogil int pluginSetRO(VSPlugin *, int) nogil int pluginRenameFunc(VSPlugin *, const char *, const char *) nogil + VSPlugin *createPlugin(const char *id, const char *ns, int version, VSCore *core) nogil diff --git a/src/cython/vapoursynth.pyx b/src/cython/vapoursynth.pyx index b79d9f47b..fbb2efe35 100644 --- a/src/cython/vapoursynth.pyx +++ b/src/cython/vapoursynth.pyx @@ -2338,6 +2338,18 @@ cdef class Core(object): s += '\tNumber of Threads: ' + str(self.num_threads) + '\n' return s + def _create_plugin(self, id, ns, int version=0): # 'vs-c' + if os.getenv('VSC_DEBUG_REGISTER_FUNC'): + print('[VS-C]: creating plugin %s: id=%s, version=%d' % (ns, id, version), file=sys.stderr) + if _vscapi == NULL: + getVSAPIInternal() + tid = id.encode('utf-8') + cdef const char *cid = tid + tns = ns.encode('utf-8') + cdef const char *cns = tns + cdef VSPlugin *p = _vscapi.createPlugin(cid, cns, version, self.core) + return createPlugin(p, self.funcs, self) + cdef object createNode(VSNode *node, const VSAPI *funcs, Core core): if funcs.getNodeType(node) == VIDEO: return createVideoNode(node, funcs, core)