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 ©Frame,
576 ©FrameProps,
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 ®isterFormat,
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