1 /*
2 * Copyright (c) 2012-2015 Fredrik Mellbin
3 *
4 * This file is part of VapourSynth.
5 *
6 * VapourSynth is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * VapourSynth is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with VapourSynth; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20 
21 #include "vscore.h"
22 #include "cpufeatures.h"
23 #include "vslog.h"
24 #include <cassert>
25 #include <cstring>
26 #include <string>
27 
vs_internal_configPlugin(const char * identifier,const char * defaultNamespace,const char * name,int apiVersion,int readOnly,VSPlugin * plugin)28 void VS_CC vs_internal_configPlugin(const char *identifier, const char *defaultNamespace, const char *name, int apiVersion, int readOnly, VSPlugin *plugin) VS_NOEXCEPT {
29     assert(identifier && defaultNamespace && name && plugin);
30     plugin->configPlugin(identifier, defaultNamespace, name, apiVersion, !!readOnly);
31 }
32 
vs_internal_registerFunction(const char * name,const char * args,VSPublicFunction argsFunc,void * functionData,VSPlugin * plugin)33 void VS_CC vs_internal_registerFunction(const char *name, const char *args, VSPublicFunction argsFunc, void *functionData, VSPlugin *plugin) VS_NOEXCEPT {
34     assert(name && args && argsFunc && plugin);
35     plugin->registerFunction(name, args, argsFunc, functionData);
36 }
37 
getFormatPreset(int id,VSCore * core)38 static const VSFormat *VS_CC getFormatPreset(int id, VSCore *core) VS_NOEXCEPT {
39     assert(core);
40     return core->getFormatPreset((VSPresetFormat)id);
41 }
42 
registerFormat(int colorFamily,int sampleType,int bitsPerSample,int subSamplingW,int subSamplingH,VSCore * core)43 static const VSFormat *VS_CC registerFormat(int colorFamily, int sampleType, int bitsPerSample, int subSamplingW, int subSamplingH, VSCore *core) VS_NOEXCEPT {
44     assert(core);
45     return core->registerFormat((VSColorFamily)colorFamily, (VSSampleType)sampleType, bitsPerSample, subSamplingW, subSamplingH);
46 }
47 
cloneFrameRef(const VSFrameRef * frame)48 static const VSFrameRef *VS_CC cloneFrameRef(const VSFrameRef *frame) VS_NOEXCEPT {
49     assert(frame);
50     return new VSFrameRef(frame->frame);
51 }
52 
cloneNodeRef(VSNodeRef * node)53 static VSNodeRef *VS_CC cloneNodeRef(VSNodeRef *node) VS_NOEXCEPT {
54     assert(node);
55     return new VSNodeRef(node->clip, node->index);
56 }
57 
getStride(const VSFrameRef * frame,int plane)58 static int VS_CC getStride(const VSFrameRef *frame, int plane) VS_NOEXCEPT {
59     assert(frame);
60     return frame->frame->getStride(plane);
61 }
62 
getReadPtr(const VSFrameRef * frame,int plane)63 static const uint8_t *VS_CC getReadPtr(const VSFrameRef *frame, int plane) VS_NOEXCEPT {
64     assert(frame);
65     return frame->frame->getReadPtr(plane);
66 }
67 
getWritePtr(VSFrameRef * frame,int plane)68 static uint8_t *VS_CC getWritePtr(VSFrameRef *frame, int plane) VS_NOEXCEPT {
69     assert(frame);
70     return frame->frame->getWritePtr(plane);
71 }
72 
getFrameAsync(int n,VSNodeRef * clip,VSFrameDoneCallback fdc,void * userData)73 static void VS_CC getFrameAsync(int n, VSNodeRef *clip, VSFrameDoneCallback fdc, void *userData) VS_NOEXCEPT {
74     assert(clip && fdc);
75     int numFrames = clip->clip->getVideoInfo(clip->index).numFrames;
76     if (n < 0 || (numFrames && n >= numFrames)) {
77         PFrameContext ctx(std::make_shared<FrameContext>(n, clip->index, clip, fdc, userData));
78         ctx->setError("Invalid frame number " + std::to_string(n) + " requested, clip only has " + std::to_string(numFrames) + " frames");
79         clip->clip->getFrame(ctx);
80     } else {
81         clip->clip->getFrame(std::make_shared<FrameContext>(n, clip->index, clip, fdc, userData));
82     }
83 }
84 
85 struct GetFrameWaiter {
86     std::mutex b;
87     std::condition_variable a;
88     const VSFrameRef *r;
89     char *errorMsg;
90     int bufSize;
GetFrameWaiterGetFrameWaiter91     GetFrameWaiter(char *errorMsg, int bufSize) : errorMsg(errorMsg), bufSize(bufSize) {}
92 };
93 
frameWaiterCallback(void * userData,const VSFrameRef * frame,int n,VSNodeRef * node,const char * errorMsg)94 static void VS_CC frameWaiterCallback(void *userData, const VSFrameRef *frame, int n, VSNodeRef *node, const char *errorMsg) VS_NOEXCEPT {
95     GetFrameWaiter *g = static_cast<GetFrameWaiter *>(userData);
96     std::lock_guard<std::mutex> l(g->b);
97     g->r = frame;
98     if (g->errorMsg && g->bufSize > 0) {
99         memset(g->errorMsg, 0, g->bufSize);
100         if (errorMsg) {
101             strncpy(g->errorMsg, errorMsg, g->bufSize);
102             g->errorMsg[g->bufSize - 1] = 0;
103         }
104     }
105     g->a.notify_one();
106 }
107 
getFrame(int n,VSNodeRef * clip,char * errorMsg,int bufSize)108 static const VSFrameRef *VS_CC getFrame(int n, VSNodeRef *clip, char *errorMsg, int bufSize) VS_NOEXCEPT {
109     assert(clip);
110     GetFrameWaiter g(errorMsg, bufSize);
111     std::unique_lock<std::mutex> l(g.b);
112     VSNode *node = clip->clip.get();
113     bool isWorker = node->isWorkerThread();
114     if (isWorker)
115         node->releaseThread();
116     node->getFrame(std::make_shared<FrameContext>(n, clip->index, clip, &frameWaiterCallback, &g, false));
117     g.a.wait(l);
118     if (isWorker)
119         node->reserveThread();
120     return g.r;
121 }
122 
requestFrameFilter(int n,VSNodeRef * clip,VSFrameContext * frameCtx)123 static void VS_CC requestFrameFilter(int n, VSNodeRef *clip, VSFrameContext *frameCtx) VS_NOEXCEPT {
124     assert(clip && frameCtx);
125     int numFrames = clip->clip->getVideoInfo(clip->index).numFrames;
126     if (numFrames && n >= numFrames)
127         n = numFrames - 1;
128     frameCtx->reqList.push_back(std::make_shared<FrameContext>(n, clip->index, clip->clip.get(), frameCtx->ctx));
129 }
130 
getFrameFilter(int n,VSNodeRef * clip,VSFrameContext * frameCtx)131 static const VSFrameRef *VS_CC getFrameFilter(int n, VSNodeRef *clip, VSFrameContext *frameCtx) VS_NOEXCEPT {
132     assert(clip && frameCtx);
133 
134     int numFrames = clip->clip->getVideoInfo(clip->index).numFrames;
135     if (numFrames && n >= numFrames)
136         n = numFrames - 1;
137     auto ref = frameCtx->ctx->availableFrames.find(NodeOutputKey(clip->clip.get(), n, clip->index));
138     if (ref != frameCtx->ctx->availableFrames.end())
139         return new VSFrameRef(ref->second);
140     return nullptr;
141 }
142 
freeFrame(const VSFrameRef * frame)143 static void VS_CC freeFrame(const VSFrameRef *frame) VS_NOEXCEPT {
144     delete frame;
145 }
146 
freeNode(VSNodeRef * clip)147 static void VS_CC freeNode(VSNodeRef *clip) VS_NOEXCEPT {
148     delete clip;
149 }
150 
newVideoFrame(const VSFormat * format,int width,int height,const VSFrameRef * propSrc,VSCore * core)151 static VSFrameRef *VS_CC newVideoFrame(const VSFormat *format, int width, int height, const VSFrameRef *propSrc, VSCore *core) VS_NOEXCEPT {
152     assert(format && core);
153     return new VSFrameRef(core->newVideoFrame(format, width, height, propSrc ? propSrc->frame.get() : nullptr));
154 }
155 
newVideoFrame2(const VSFormat * format,int width,int height,const VSFrameRef ** planeSrc,const int * planes,const VSFrameRef * propSrc,VSCore * core)156 static VSFrameRef *VS_CC newVideoFrame2(const VSFormat *format, int width, int height, const VSFrameRef **planeSrc, const int *planes, const VSFrameRef *propSrc, VSCore *core) VS_NOEXCEPT {
157     assert(format && core);
158     VSFrame *fp[3];
159     for (int i = 0; i < format->numPlanes; i++)
160         fp[i] = planeSrc[i] ? planeSrc[i]->frame.get() : nullptr;
161     return new VSFrameRef(core->newVideoFrame(format, width, height, fp, planes, propSrc ? propSrc->frame.get() : nullptr));
162 }
163 
copyFrame(const VSFrameRef * frame,VSCore * core)164 static VSFrameRef *VS_CC copyFrame(const VSFrameRef *frame, VSCore *core) VS_NOEXCEPT {
165     assert(frame && core);
166     return new VSFrameRef(core->copyFrame(frame->frame));
167 }
168 
copyFrameProps(const VSFrameRef * src,VSFrameRef * dst,VSCore * core)169 static void VS_CC copyFrameProps(const VSFrameRef *src, VSFrameRef *dst, VSCore *core) VS_NOEXCEPT {
170     assert(src && dst && core);
171     core->copyFrameProps(src->frame, dst->frame);
172 }
173 
createFilter(const VSMap * in,VSMap * out,const char * name,VSFilterInit init,VSFilterGetFrame getFrame,VSFilterFree free,int filterMode,int flags,void * instanceData,VSCore * core)174 static void VS_CC createFilter(const VSMap *in, VSMap *out, const char *name, VSFilterInit init, VSFilterGetFrame getFrame, VSFilterFree free, int filterMode, int flags, void *instanceData, VSCore *core) VS_NOEXCEPT {
175     assert(in && out && name && init && getFrame && core);
176     if (!name)
177         vsFatal("NULL name pointer passed to createFilter()");
178     core->createFilter(in, out, name, init, getFrame, free, static_cast<VSFilterMode>(filterMode), flags, instanceData, VAPOURSYNTH_API_MAJOR);
179 }
180 
setError(VSMap * map,const char * errorMessage)181 static void VS_CC setError(VSMap *map, const char *errorMessage) VS_NOEXCEPT {
182     assert(map && errorMessage);
183     map->setError(errorMessage ? errorMessage : "Error: no error specified");
184 }
185 
getError(const VSMap * map)186 static const char *VS_CC getError(const VSMap *map) VS_NOEXCEPT {
187     assert(map);
188     if (map->hasError())
189         return map->getErrorMessage().c_str();
190     else
191         return nullptr;
192 }
193 
setFilterError(const char * errorMessage,VSFrameContext * context)194 static void VS_CC setFilterError(const char *errorMessage, VSFrameContext *context) VS_NOEXCEPT {
195     assert(errorMessage && context);
196     context->ctx->setError(errorMessage);
197 }
198 
199 //property access functions
getVideoInfo(VSNodeRef * c)200 static const VSVideoInfo *VS_CC getVideoInfo(VSNodeRef *c) VS_NOEXCEPT {
201     assert(c);
202     return &c->clip->getVideoInfo(c->index);
203 }
204 
setVideoInfo(const VSVideoInfo * vi,int numOutputs,VSNode * c)205 static void VS_CC setVideoInfo(const VSVideoInfo *vi, int numOutputs, VSNode *c) VS_NOEXCEPT {
206     assert(vi && numOutputs > 0 && c);
207     c->setVideoInfo(vi, numOutputs);
208 }
209 
getFrameFormat(const VSFrameRef * f)210 static const VSFormat *VS_CC getFrameFormat(const VSFrameRef *f) VS_NOEXCEPT {
211     assert(f);
212     return f->frame->getFormat();
213 }
214 
getFrameWidth(const VSFrameRef * f,int plane)215 static int VS_CC getFrameWidth(const VSFrameRef *f, int plane) VS_NOEXCEPT {
216     assert(f);
217     assert(plane >= 0);
218     return f->frame->getWidth(plane);
219 }
220 
getFrameHeight(const VSFrameRef * f,int plane)221 static int VS_CC getFrameHeight(const VSFrameRef *f, int plane) VS_NOEXCEPT {
222     assert(f);
223     assert(plane >= 0);
224     return f->frame->getHeight(plane);
225 }
226 
getFramePropsRO(const VSFrameRef * frame)227 static const VSMap *VS_CC getFramePropsRO(const VSFrameRef *frame) VS_NOEXCEPT {
228     assert(frame);
229     return &frame->frame->getConstProperties();
230 }
231 
getFramePropsRW(VSFrameRef * frame)232 static VSMap *VS_CC getFramePropsRW(VSFrameRef *frame) VS_NOEXCEPT {
233     assert(frame);
234     return &frame->frame->getProperties();
235 }
236 
propNumKeys(const VSMap * map)237 static int VS_CC propNumKeys(const VSMap *map) VS_NOEXCEPT {
238     assert(map);
239     return static_cast<int>(map->size());
240 }
241 
propGetKey(const VSMap * map,int index)242 static const char *VS_CC propGetKey(const VSMap *map, int index) VS_NOEXCEPT {
243     assert(map);
244     if (index < 0 || static_cast<size_t>(index) >= map->size())
245         vsFatal(("propGetKey: Out of bounds index " + std::to_string(index) + " passed. Valid range: [0," + std::to_string(map->size() - 1) + "]").c_str());
246 
247     return map->key(index);
248 }
249 
propNumElementsInternal(const VSMap * map,const std::string & key)250 static int propNumElementsInternal(const VSMap *map, const std::string &key) VS_NOEXCEPT {
251     VSVariant *val = map->find(key);
252     return val ? val->size() : -1;
253 }
254 
255 
propNumElements(const VSMap * map,const char * key)256 static int VS_CC propNumElements(const VSMap *map, const char *key) VS_NOEXCEPT {
257     assert(map && key);
258     return propNumElementsInternal(map, key);
259 }
260 
propGetType(const VSMap * map,const char * key)261 static char VS_CC propGetType(const VSMap *map, const char *key) VS_NOEXCEPT {
262     assert(map && key);
263     const char a[] = { 'u', 'i', 'f', 's', 'c', 'v', 'm' };
264     VSVariant *val = map->find(key);
265     return val ? a[val->getType()] : 'u';
266 }
267 
268 #define PROP_GET_SHARED(vt, retexpr) \
269     assert(map && key); \
270     if (map->hasError()) \
271         vsFatal("Attempted to read key '%s' from a map with error set: %s", key, map->getErrorMessage().c_str()); \
272     int err = 0; \
273     VSVariant *l = map->find(key); \
274     if (l && l->getType() == (vt)) { \
275         if (index >= 0 && static_cast<size_t>(index) < l->size()) { \
276             if (error) \
277                 *error = 0; \
278             return (retexpr); \
279         } else { \
280             err |= peIndex; \
281         } \
282     } else if (l) { \
283         err |= peType; \
284     } else { \
285         err = peUnset; \
286     } \
287     if (!error) \
288         vsFatal("Property read unsuccessful but no error output: %s", key); \
289     *error = err; \
290     return 0;
291 
propGetInt(const VSMap * map,const char * key,int index,int * error)292 static int64_t VS_CC propGetInt(const VSMap *map, const char *key, int index, int *error) VS_NOEXCEPT {
293     PROP_GET_SHARED(VSVariant::vInt, l->getValue<int64_t>(index))
294 }
295 
propGetFloat(const VSMap * map,const char * key,int index,int * error)296 static double VS_CC propGetFloat(const VSMap *map, const char *key, int index, int *error) VS_NOEXCEPT {
297     PROP_GET_SHARED(VSVariant::vFloat, l->getValue<double>(index))
298 }
299 
propGetData(const VSMap * map,const char * key,int index,int * error)300 static const char *VS_CC propGetData(const VSMap *map, const char *key, int index, int *error) VS_NOEXCEPT {
301     PROP_GET_SHARED(VSVariant::vData, l->getValue<VSMapData>(index)->c_str())
302 }
303 
propGetDataSize(const VSMap * map,const char * key,int index,int * error)304 static int VS_CC propGetDataSize(const VSMap *map, const char *key, int index, int *error) VS_NOEXCEPT {
305     PROP_GET_SHARED(VSVariant::vData, static_cast<int>(l->getValue<VSMapData>(index)->size()))
306 }
307 
propGetNode(const VSMap * map,const char * key,int index,int * error)308 static VSNodeRef *VS_CC propGetNode(const VSMap *map, const char *key, int index, int *error) VS_NOEXCEPT {
309     PROP_GET_SHARED(VSVariant::vNode, new VSNodeRef(l->getValue<VSNodeRef>(index)))
310 }
311 
propGetFrame(const VSMap * map,const char * key,int index,int * error)312 static const VSFrameRef *VS_CC propGetFrame(const VSMap *map, const char *key, int index, int *error) VS_NOEXCEPT {
313     PROP_GET_SHARED(VSVariant::vFrame, new VSFrameRef(l->getValue<PVideoFrame>(index)))
314 }
315 
propDeleteKey(VSMap * map,const char * key)316 static int VS_CC propDeleteKey(VSMap *map, const char *key) VS_NOEXCEPT {
317     assert(map && key);
318     return map->erase(key);
319 }
320 
isAlphaUnderscore(char c)321 static inline bool isAlphaUnderscore(char c) {
322     return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_';
323 }
324 
isAlphaNumUnderscore(char c)325 static inline bool isAlphaNumUnderscore(char c) {
326     return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_';
327 }
328 
isValidVSMapKey(const std::string & s)329 static bool isValidVSMapKey(const std::string &s) {
330     size_t len = s.length();
331     if (!len)
332         return false;
333 
334     if (!isAlphaUnderscore(s[0]))
335         return false;
336     for (size_t i = 1; i < len; i++)
337         if (!isAlphaNumUnderscore(s[i]))
338             return false;
339     return true;
340 }
341 
342 #define PROP_SET_SHARED(vv, appendexpr) \
343     assert(map && key); \
344     if (append != paReplace && append != paAppend && append != paTouch) \
345         vsFatal("Invalid prop append mode given when setting key '%s'", key); \
346     std::string skey = key; \
347     if (!isValidVSMapKey(skey)) \
348         return 1; \
349     if (append != paReplace && map->contains(skey)) { \
350         map->detach(); \
351         VSVariant &l = map->at(skey); \
352         if (l.getType() != (vv)) { \
353             return 1; \
354         } else if (append == paAppend) { \
355             l.append(appendexpr); \
356         } \
357     } else { \
358         VSVariant l((vv)); \
359         if (append != paTouch) \
360             l.append(appendexpr); \
361         map->detach(); \
362         map->insert(skey, std::move(l)); \
363     } \
364     return 0;
365 
366 
propSetInt(VSMap * map,const char * key,int64_t i,int append)367 static int VS_CC propSetInt(VSMap *map, const char *key, int64_t i, int append) VS_NOEXCEPT {
368     PROP_SET_SHARED(VSVariant::vInt, i)
369 }
370 
propSetFloat(VSMap * map,const char * key,double d,int append)371 static int VS_CC propSetFloat(VSMap *map, const char *key, double d, int append) VS_NOEXCEPT {
372     PROP_SET_SHARED(VSVariant::vFloat, d)
373 }
374 
propSetData(VSMap * map,const char * key,const char * d,int length,int append)375 static int VS_CC propSetData(VSMap *map, const char *key, const char *d, int length, int append) VS_NOEXCEPT {
376     PROP_SET_SHARED(VSVariant::vData, length >= 0 ? std::string(d, length) : std::string(d))
377 }
378 
propSetNode(VSMap * map,const char * key,VSNodeRef * clip,int append)379 static int VS_CC propSetNode(VSMap *map, const char *key, VSNodeRef *clip, int append) VS_NOEXCEPT {
380     PROP_SET_SHARED(VSVariant::vNode, *clip)
381 }
382 
propSetFrame(VSMap * map,const char * key,const VSFrameRef * frame,int append)383 static int VS_CC propSetFrame(VSMap *map, const char *key, const VSFrameRef *frame, int append) VS_NOEXCEPT {
384     PROP_SET_SHARED(VSVariant::vFrame, frame->frame)
385 }
386 
invoke(VSPlugin * plugin,const char * name,const VSMap * args)387 static VSMap *VS_CC invoke(VSPlugin *plugin, const char *name, const VSMap *args) VS_NOEXCEPT {
388     assert(plugin && name && args);
389     return new VSMap(plugin->invoke(name, *args));
390 }
391 
createMap()392 static VSMap *VS_CC createMap() VS_NOEXCEPT {
393     return new VSMap();
394 }
395 
freeMap(VSMap * map)396 static void VS_CC freeMap(VSMap *map) VS_NOEXCEPT {
397     delete map;
398 }
399 
clearMap(VSMap * map)400 static void VS_CC clearMap(VSMap *map) VS_NOEXCEPT {
401     assert(map);
402     map->clear();
403 }
404 
createCore(int threads)405 static VSCore *VS_CC createCore(int threads) VS_NOEXCEPT {
406     return new VSCore(threads);
407 }
408 
freeCore(VSCore * core)409 static void VS_CC freeCore(VSCore *core) VS_NOEXCEPT {
410     if (core)
411         core->freeCore();
412 }
413 
getPluginById(const char * identifier,VSCore * core)414 static VSPlugin *VS_CC getPluginById(const char *identifier, VSCore *core) VS_NOEXCEPT {
415     assert(identifier && core);
416     return core->getPluginById(identifier);
417 }
418 
getPluginByNs(const char * ns,VSCore * core)419 static VSPlugin *VS_CC getPluginByNs(const char *ns, VSCore *core) VS_NOEXCEPT {
420     assert(ns && core);
421     return core->getPluginByNs(ns);
422 }
423 
getPlugins(VSCore * core)424 static VSMap *VS_CC getPlugins(VSCore *core) VS_NOEXCEPT {
425     assert(core);
426     return new VSMap(core->getPlugins());
427 }
428 
getFunctions(VSPlugin * plugin)429 static VSMap *VS_CC getFunctions(VSPlugin *plugin) VS_NOEXCEPT {
430     assert(plugin);
431     return new VSMap(plugin->getFunctions());
432 }
433 
getCoreInfo(VSCore * core)434 static const VSCoreInfo *VS_CC getCoreInfo(VSCore *core) VS_NOEXCEPT {
435     assert(core);
436     return &core->getCoreInfo();
437 }
438 
propGetFunc(const VSMap * map,const char * key,int index,int * error)439 static VSFuncRef *VS_CC propGetFunc(const VSMap *map, const char *key, int index, int *error) VS_NOEXCEPT {
440     PROP_GET_SHARED(VSVariant::vMethod, new VSFuncRef(l->getValue<PExtFunction>(index)))
441 }
442 
propSetFunc(VSMap * map,const char * key,VSFuncRef * func,int append)443 static int VS_CC propSetFunc(VSMap *map, const char *key, VSFuncRef *func, int append) VS_NOEXCEPT {
444     assert(func);
445     PROP_SET_SHARED(VSVariant::vMethod, func->func)
446 }
447 
callFunc(VSFuncRef * func,const VSMap * in,VSMap * out,VSCore * core,const VSAPI * vsapi)448 static void VS_CC callFunc(VSFuncRef *func, const VSMap *in, VSMap *out, VSCore *core, const VSAPI *vsapi) VS_NOEXCEPT {
449     assert(func && in && out);
450     func->func->call(in, out);
451 }
452 
createFunc(VSPublicFunction func,void * userData,VSFreeFuncData free,VSCore * core,const VSAPI * vsapi)453 static VSFuncRef *VS_CC createFunc(VSPublicFunction func, void *userData, VSFreeFuncData free, VSCore *core, const VSAPI *vsapi) VS_NOEXCEPT {
454     assert(func && core && vsapi);
455     return new VSFuncRef(std::make_shared<ExtFunction>(func, userData, free, core, vsapi));
456 }
457 
freeFunc(VSFuncRef * f)458 static void VS_CC freeFunc(VSFuncRef *f) VS_NOEXCEPT {
459     delete f;
460 }
461 
queryCompletedFrame(VSNodeRef ** node,int * n,VSFrameContext * frameCtx)462 static void VS_CC queryCompletedFrame(VSNodeRef **node, int *n, VSFrameContext *frameCtx) VS_NOEXCEPT {
463     assert(node && n && frameCtx);
464     *node = frameCtx->ctx->lastCompletedNode;
465     *n = frameCtx->ctx->lastCompletedN;
466 }
467 
releaseFrameEarly(VSNodeRef * node,int n,VSFrameContext * frameCtx)468 static void VS_CC releaseFrameEarly(VSNodeRef *node, int n, VSFrameContext *frameCtx) VS_NOEXCEPT {
469     assert(node && frameCtx);
470     frameCtx->ctx->availableFrames.erase(NodeOutputKey(node->clip.get(), n, node->index));
471 }
472 
cloneFuncRef(VSFuncRef * f)473 static VSFuncRef *VS_CC cloneFuncRef(VSFuncRef *f) VS_NOEXCEPT {
474     assert(f);
475     return new VSFuncRef(f->func);
476 }
477 
setMaxCacheSize(int64_t bytes,VSCore * core)478 static int64_t VS_CC setMaxCacheSize(int64_t bytes, VSCore *core) VS_NOEXCEPT {
479     assert(core);
480     return core->memory->setMaxMemoryUse(bytes);
481 }
482 
getOutputIndex(VSFrameContext * frameCtx)483 static int VS_CC getOutputIndex(VSFrameContext *frameCtx) VS_NOEXCEPT {
484     assert(frameCtx);
485     return frameCtx->ctx->index;
486 }
487 
setMessageHandler(VSMessageHandler handler,void * userData)488 static void VS_CC setMessageHandler(VSMessageHandler handler, void *userData) VS_NOEXCEPT {
489     vsSetMessageHandler(handler, userData);
490 }
491 
setThreadCount(int threads,VSCore * core)492 static int VS_CC setThreadCount(int threads, VSCore *core) VS_NOEXCEPT {
493     assert(core);
494     return core->threadPool->setThreadCount(threads);
495 }
496 
getPluginPath(const VSPlugin * plugin)497 static const char *VS_CC getPluginPath(const VSPlugin *plugin) VS_NOEXCEPT {
498     if (!plugin)
499         vsFatal("NULL passed to getPluginPath");
500     if (!plugin->filename.empty())
501         return plugin->filename.c_str();
502     else
503         return nullptr;
504 }
505 
propGetIntArray(const VSMap * map,const char * key,int * error)506 static const int64_t *VS_CC propGetIntArray(const VSMap *map, const char *key, int *error) VS_NOEXCEPT {
507     int index = 0;
508     PROP_GET_SHARED(VSVariant::vInt, l->getArray<int64_t>())
509 }
510 
propGetFloatArray(const VSMap * map,const char * key,int * error)511 static const double *VS_CC propGetFloatArray(const VSMap *map, const char *key, int *error) VS_NOEXCEPT {
512     int index = 0;
513     PROP_GET_SHARED(VSVariant::vFloat, l->getArray<double>())
514 }
515 
propSetIntArray(VSMap * map,const char * key,const int64_t * i,int size)516 static int VS_CC propSetIntArray(VSMap *map, const char *key, const int64_t *i, int size) VS_NOEXCEPT {
517     assert(map && key && size >= 0);
518     if (size < 0)
519         return 1;
520     std::string skey = key;
521     if (!isValidVSMapKey(skey))
522         return 1;
523     VSVariant l(VSVariant::vInt);
524     l.setArray(i, size);
525     map->insert(skey, std::move(l));
526     return 0;
527 }
528 
propSetFloatArray(VSMap * map,const char * key,const double * d,int size)529 static int VS_CC propSetFloatArray(VSMap *map, const char *key, const double *d, int size) VS_NOEXCEPT {
530     assert(map && key && size >= 0);
531     if (size < 0)
532         return 1;
533     std::string skey = key;
534     if (!isValidVSMapKey(skey))
535         return 1;
536     VSVariant l(VSVariant::vFloat);
537     l.setArray(d, size);
538     map->insert(skey, std::move(l));
539     return 0;
540 }
541 
logMessage(int msgType,const char * msg)542 static void VS_CC logMessage(int msgType, const char *msg) VS_NOEXCEPT {
543     vsLog(__FILE__, __LINE__, static_cast<VSMessageType>(msgType), "%s", msg);
544 }
545 
addMessageHandler(VSMessageHandler handler,VSMessageHandlerFree free,void * userData)546 static int VS_CC addMessageHandler(VSMessageHandler handler, VSMessageHandlerFree free, void *userData) VS_NOEXCEPT {
547     return vsAddMessageHandler(handler, free, userData);
548 }
549 
removeMessageHandler(int id)550 static int VS_CC removeMessageHandler(int id) VS_NOEXCEPT {
551     return vsRemoveMessageHandler(id);
552 }
553 
getCoreInfo2(VSCore * core,VSCoreInfo * info)554 static void VS_CC getCoreInfo2(VSCore *core, VSCoreInfo *info) VS_NOEXCEPT {
555     assert(core && info);
556     core->getCoreInfo2(*info);
557 }
558 
559 
560 
561 const VSAPI vs_internal_vsapi = {
562     &createCore,
563     &freeCore,
564     &getCoreInfo,
565 
566     &cloneFrameRef,
567     &cloneNodeRef,
568     &cloneFuncRef,
569 
570     &freeFrame,
571     &freeNode,
572     &freeFunc,
573 
574     &newVideoFrame,
575     &copyFrame,
576     &copyFrameProps,
577     &vs_internal_registerFunction,
578     &getPluginById,
579     &getPluginByNs,
580     &getPlugins,
581     &getFunctions,
582     &createFilter,
583     &setError,
584     &getError,
585     &setFilterError,
586     &invoke,
587     &getFormatPreset,
588     &registerFormat,
589     &getFrame,
590     &getFrameAsync,
591     &getFrameFilter,
592     &requestFrameFilter,
593     &queryCompletedFrame,
594     &releaseFrameEarly,
595 
596     &getStride,
597     &getReadPtr,
598     &getWritePtr,
599 
600     &createFunc,
601     &callFunc,
602 
603     &createMap,
604     &freeMap,
605     &clearMap,
606 
607     &getVideoInfo,
608     &setVideoInfo,
609     &getFrameFormat,
610     &getFrameWidth,
611     &getFrameHeight,
612     &getFramePropsRO,
613     &getFramePropsRW,
614 
615     &propNumKeys,
616     &propGetKey,
617     &propNumElements,
618     &propGetType,
619     &propGetInt,
620     &propGetFloat,
621     &propGetData,
622     &propGetDataSize,
623     &propGetNode,
624     &propGetFrame,
625     &propGetFunc,
626     &propDeleteKey,
627     &propSetInt,
628     &propSetFloat,
629     &propSetData,
630     &propSetNode,
631     &propSetFrame,
632     &propSetFunc,
633 
634     &setMaxCacheSize,
635     &getOutputIndex,
636     &newVideoFrame2,
637 
638     &setMessageHandler,
639     &setThreadCount,
640 
641     &getPluginPath,
642 
643     &propGetIntArray,
644     &propGetFloatArray,
645     &propSetIntArray,
646     &propSetFloatArray,
647 
648     &logMessage,
649     &addMessageHandler,
650     &removeMessageHandler,
651     &getCoreInfo2
652 };
653 
654 ///////////////////////////////
655 
getVSAPIInternal(int apiMajor)656 const VSAPI *getVSAPIInternal(int apiMajor) {
657     if (apiMajor == VAPOURSYNTH_API_MAJOR) {
658         return &vs_internal_vsapi;
659     } else {
660         vsFatal("Internally requested API version %d not supported", apiMajor);
661         return nullptr;
662     }
663 }
664 
getVapourSynthAPI(int version)665 const VSAPI *VS_CC getVapourSynthAPI(int version) VS_NOEXCEPT {
666     int apiMajor = version;
667     int apiMinor = 0;
668     if (apiMajor >= 0x10000) {
669         apiMinor = (apiMajor & 0xFFFF);
670         apiMajor >>= 16;
671     }
672 
673     if (!getCPUFeatures()->can_run_vs) {
674         return nullptr;
675     } else if (apiMajor == VAPOURSYNTH_API_MAJOR && apiMinor <= VAPOURSYNTH_API_MINOR) {
676         return &vs_internal_vsapi;
677     } else {
678         return nullptr;
679     }
680 }
681