Make the core report how many threads it's decided on using when created
[vapoursynth-svn.git] / src / core / vsapi.cpp
blob54ac73eebb2192d209be09cda0378dc01155f981
1 /*
2 * Copyright (c) 2012 Fredrik Mellbin
4 * This file is part of VapourSynth.
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.
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.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with Libav; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 #include "vscore.h"
22 #include "version.h"
24 void VS_CC configPlugin(const char *identifier, const char *defaultNamespace, const char *name, int apiVersion, int readOnly, VSPlugin *plugin) {
25 plugin->configPlugin(identifier, defaultNamespace, name, apiVersion, readOnly);
28 void VS_CC registerFunction(const char *name, const char *args, VSPublicFunction argsFunc, void *functionData, VSPlugin *plugin) {
29 plugin->registerFunction(name, args, argsFunc, functionData);
32 static const VSFormat *VS_CC getFormatPreset(int id, VSCore *core) {
33 return core->getFormatPreset((VSPresetFormat)id);
36 static const VSFormat *VS_CC registerFormat(int colorFamily, int sampleType, int bytesPerSample, int subSamplingW, int subSamplingH, VSCore *core) {
37 return core->registerFormat((VSColorFamily)colorFamily, (VSSampleType)sampleType, bytesPerSample, subSamplingW, subSamplingH);
40 static const VSFrameRef *VS_CC cloneFrameRef(const VSFrameRef *frame) {
41 Q_ASSERT(frame);
42 return new VSFrameRef(frame->frame);
45 static const VSNodeRef *VS_CC cloneNodeRef(const VSNodeRef *node) {
46 Q_ASSERT(node);
47 return new VSNodeRef(node->clip);
50 static int VS_CC getStride(const VSFrameRef *frame, int plane) {
51 return frame->frame->getStride(plane);
54 static const uint8_t *VS_CC getReadPtr(const VSFrameRef *frame, int plane) {
55 return frame->frame->getReadPtr(plane);
58 static uint8_t *VS_CC getWritePtr(VSFrameRef *frame, int plane) {
59 return frame->frame->getWritePtr(plane);
62 static void VS_CC getFrameAsync(int n, const VSNodeRef *clip, VSFrameDoneCallback fdc, void *userData) {
63 PFrameContext g(new FrameContext(n, clip, fdc, userData));
64 clip->clip->getFrame(g);
67 struct GetFrameWaiter {
68 QMutex b;
69 QWaitCondition a;
70 const VSFrameRef *r;
71 char *errorMsg;
72 int bufSize;
73 GetFrameWaiter(char *errorMsg, int bufSize) : errorMsg(errorMsg), bufSize(bufSize) {}
76 static void VS_CC frameWaiterCallback(void *userData, const VSFrameRef *frame, int n, const VSNodeRef *, const char *errorMsg) {
77 GetFrameWaiter *g = (GetFrameWaiter *)userData;
78 QMutexLocker l(&g->b);
79 g->r = frame;
80 memset(g->errorMsg, 0, g->bufSize);
81 if (errorMsg)
82 strncpy(g->errorMsg, errorMsg, g->bufSize - 1);
83 g->a.wakeOne();
86 static const VSFrameRef *VS_CC getFrame(int n, const VSNodeRef *clip, char *errorMsg, int bufSize) {
87 GetFrameWaiter g(errorMsg, bufSize);
88 QMutexLocker l(&g.b);
89 getFrameAsync(n, clip, &frameWaiterCallback, &g);
90 g.a.wait(&g.b);
91 return g.r;
94 static void VS_CC requestFrameFilter(int n, const VSNodeRef *clip, VSFrameContext *ctxHandle) {
95 PFrameContext f(*(PFrameContext *)ctxHandle);
96 PFrameContext g(new FrameContext(n, clip->clip.data(), f));
97 clip->clip->getFrame(g);
100 static const VSFrameRef *VS_CC getFrameFilter(int n, const VSNodeRef *clip, VSFrameContext *ctxHandle) {
101 PFrameContext f(*(PFrameContext *)ctxHandle);
102 PVideoFrame g = f->availableFrames.value(FrameKey(clip->clip.data(), n));
104 if (g)
105 return new VSFrameRef(g);
106 else
107 return NULL;
110 static void VS_CC freeFrame(const VSFrameRef *frame) {
111 delete frame;
114 static void VS_CC freeNode(const VSNodeRef *clip) {
115 delete clip;
118 static VSFrameRef *VS_CC newVideoFrame(const VSFormat *f, int width, int height, const VSFrameRef *propSrc, VSCore *core) {
119 Q_ASSERT(f);
120 return new VSFrameRef(core->newVideoFrame(f, width, height, propSrc ? propSrc->frame.data() : NULL));
123 static VSFrameRef *VS_CC copyFrame(const VSFrameRef *frame, VSCore *core) {
124 return new VSFrameRef(core->copyFrame(frame->frame));
127 static void VS_CC copyFrameProps(const VSFrameRef *src, VSFrameRef *dst, VSCore *core) {
128 core->copyFrameProps(src->frame, dst->frame);
131 static const VSNodeRef *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) {
132 return new VSNodeRef(core->createFilter(in, out, name, init, getFrame, free, static_cast<VSFilterMode>(filterMode), flags, instanceData));
135 static void VS_CC setError(VSMap *map, const char *errorMessage) {
136 map->clear();
137 VSVariant l(VSVariant::vData);
138 l.s.append(errorMessage ? errorMessage : "Error: no error specified");
139 map->insert("_Error", l);
142 static const char *VS_CC getError(const VSMap *map) {
143 if (map->contains("_Error"))
144 return (*map)["_Error"].s[0].constData();
145 else
146 return NULL;
149 static void VS_CC setFilterError(const char *errorMessage, VSFrameContext *context) {
150 PFrameContext f(*(PFrameContext *)context);
151 f->setError(errorMessage);
154 //property access functions
155 static const VSVideoInfo *VS_CC getVideoInfo(const VSNodeRef *c) {
156 return &c->clip->getVideoInfo();
159 static void VS_CC setVideoInfo(const VSVideoInfo *vi, VSNode *c) {
160 c->setVideoInfo(*vi);
163 static const VSFormat *VS_CC getFrameFormat(const VSFrameRef *f) {
164 return f->frame->getFormat();
167 static int VS_CC getFrameWidth(const VSFrameRef *f, int plane) {
168 return f->frame->getWidth(plane);
171 static int VS_CC getFrameHeight(const VSFrameRef *f, int plane) {
172 return f->frame->getHeight(plane);
175 static const VSMap *VS_CC getFramePropsRO(const VSFrameRef *frame) {
176 return &frame->frame->getConstProperties();
179 static VSMap *VS_CC getFramePropsRW(VSFrameRef *frame) {
180 return &frame->frame->getProperties();
183 static int VS_CC propNumKeys(const VSMap *props) {
184 return props->keys().count();
187 static const char *VS_CC propGetKey(const VSMap *props, int index) {
188 if (index < 0 || index >= props->count())
189 qFatal("Out of bound index");
191 return props->keys()[index].constData();
194 static int VS_CC propNumElements(const VSMap *props, const char *name) {
195 if (!props->contains(name))
196 return -1;
198 const VSVariant &val = (*props)[name];
199 return val.count();
202 static char VS_CC propGetType(const VSMap *props, const char *name) {
203 if (!props->contains(name))
204 return 'u';
206 const char a[] = { 'u', 'i', 'f', 's', 'c', 'v', 'm'};
207 const VSVariant &val = (*props)[name];
208 return a[val.vtype];
211 static int getPropErrorCheck(const VSMap *props, const char *name, int index, int *error, int type) {
212 int err = 0;
214 if (vsapi.getError(props))
215 qFatal(QByteArray("Attempted to read from a map with error set: ") + vsapi.getError(props));
217 if (!props->contains(name))
218 err |= peUnset;
220 if (!err && props->value(name).vtype != type)
221 err |= peType;
223 int c = propNumElements(props, name);
225 if (!err && c <= index || index < 0)
226 err |= peIndex;
228 if (err && !error)
229 qFatal(QByteArray("Property read unsuccessful but no error output: ") + name);
231 if (error)
232 *error = err;
234 return err;
237 static int64_t VS_CC propGetInt(const VSMap *props, const char *name, int index, int *error) {
238 int err = getPropErrorCheck(props, name, index, error, VSVariant::vInt);
240 if (err)
241 return 0;
243 const VSVariant &l = (*props)[name];
244 return l.i[index];
247 static double VS_CC propGetFloat(const VSMap *props, const char *name, int index, int *error) {
248 int err = getPropErrorCheck(props, name, index, error, VSVariant::vFloat);
250 if (err)
251 return 0;
253 const VSVariant &l = (*props)[name];
254 return l.f[index];
257 static const char *VS_CC propGetData(const VSMap *props, const char *name, int index, int *error) {
258 int err = getPropErrorCheck(props, name, index, error, VSVariant::vData);
260 if (err)
261 return 0;
263 const VSVariant &l = (*props)[name];
264 return l.s[index].constData();
267 static int VS_CC propGetDataSize(const VSMap *props, const char *name, int index, int *error) {
268 int err = getPropErrorCheck(props, name, index, error, VSVariant::vData);
270 if (err)
271 return 0;
273 const VSVariant &l = (*props)[name];
274 return l.s[index].size();
277 static const VSNodeRef *VS_CC propGetNode(const VSMap *props, const char *name, int index, int *error) {
278 int err = getPropErrorCheck(props, name, index, error, VSVariant::vNode);
280 if (err)
281 return 0;
283 const VSVariant &l = (*props)[name];
284 return new VSNodeRef(l.c[index]);
287 static const VSFrameRef *VS_CC propGetFrame(const VSMap *props, const char *name, int index, int *error) {
288 int err = getPropErrorCheck(props, name, index, error, VSVariant::vFrame);
290 if (err)
291 return 0;
293 const VSVariant &l = (*props)[name];
294 return new VSFrameRef(l.v[index]);
297 static int VS_CC propDeleteKey(VSMap *props, const char *name) {
298 return props->remove(name);
301 static void sharedPropSet(VSMap *props, const char *name, int &append) {
302 if (append != paReplace && append != paAppend && append != paTouch)
303 qFatal("Invalid prop append mode given");
305 if (append == paReplace) {
306 props->remove(name);
307 append = paAppend;
311 static int VS_CC propSetInt(VSMap *props, const char *name, int64_t i, int append) {
312 sharedPropSet(props, name, append);
313 if (props->contains(name)) {
314 VSVariant &l = (*props)[name];
316 if (l.vtype != VSVariant::vInt)
317 return 1;
318 else if (append == paAppend)
319 l.i.append(i);
320 } else {
321 VSVariant l(VSVariant::vInt);
322 if (append == paAppend)
323 l.i.append(i);
324 props->insert(name, l);
327 return 0;
330 static int VS_CC propSetFloat(VSMap *props, const char *name, double d, int append) {
331 sharedPropSet(props, name, append);
332 if (props->contains(name)) {
333 VSVariant &l = (*props)[name];
335 if (l.vtype != VSVariant::vFloat)
336 return 1;
337 else if (append == paAppend)
338 l.f.append(d);
339 } else {
340 VSVariant l(VSVariant::vFloat);
341 if (append == paAppend)
342 l.f.append(d);
343 props->insert(name, l);
346 return 0;
349 static int VS_CC propSetData(VSMap *props, const char *name, const char *d, int length, int append) {
350 sharedPropSet(props, name, append);
351 if (props->contains(name)) {
352 VSVariant &l = (*props)[name];
354 if (l.vtype != VSVariant::vData)
355 return 1;
356 else if (append == paAppend)
357 l.s.append(d);
358 } else {
359 VSVariant l(VSVariant::vData);
360 if (append == paAppend)
361 l.s.append(length >= 0 ? QByteArray(d, length) : QByteArray(d));
362 props->insert(name, l);
365 return 0;
368 static int VS_CC propSetNode(VSMap *props, const char *name, const VSNodeRef *clip, int append) {
369 sharedPropSet(props, name, append);
370 if (props->contains(name)) {
371 VSVariant &l = (*props)[name];
373 if (l.vtype != VSVariant::vNode)
374 return 1;
375 else if (append == paAppend)
376 l.c.append(clip->clip);
377 } else {
378 VSVariant l(VSVariant::vNode);
379 if (append == paAppend)
380 l.c.append(clip->clip);
381 props->insert(name, l);
384 return 0;
387 static int VS_CC propSetFrame(VSMap *props, const char *name, const VSFrameRef *frame, int append) {
388 sharedPropSet(props, name, append);
389 if (props->contains(name)) {
390 VSVariant &l = (*props)[name];
392 if (l.vtype != VSVariant::vFrame)
393 return 1;
394 else if (append == paAppend)
395 l.v.append(frame->frame);
396 } else {
397 VSVariant l(VSVariant::vFrame);
398 if (append == paAppend)
399 l.v.append(frame->frame);
400 props->insert(name, l);
403 return 0;
406 static VSMap *VS_CC invoke(VSPlugin *plugin, const char *name, const VSMap *args) {
407 Q_ASSERT(plugin);
408 return new VSMap(plugin->invoke(name, *args));
411 static VSMap *VS_CC newMap() {
412 return new VSMap();
415 static void VS_CC freeMap(VSMap *map) {
416 delete map;
419 static void VS_CC clearMap(VSMap *map) {
420 map->clear();
423 static VSCore *VS_CC createCore(int *threads) {
424 return new VSCore(*threads);
427 static void VS_CC freeCore(VSCore *core) {
428 delete core;
431 const VSAPI *VS_CC getVapourSynthAPI(int version) {
432 if (version == VAPOURSYNTH_API_VERSION)
433 return &vsapi;
434 else
435 return NULL;
438 static VSPlugin *VS_CC getPluginId(const char *identifier, VSCore *core) {
439 return core->getPluginId(identifier);
442 static VSPlugin *VS_CC getPluginNs(const char *ns, VSCore *core) {
443 return core->getPluginNs(ns);
446 static VSMap *VS_CC getPlugins(VSCore *core) {
447 return new VSMap(core->getPlugins());
450 static VSMap *VS_CC getFunctions(VSPlugin *plugin) {
451 return new VSMap(plugin->getFunctions());
454 static const VSVersion version = { VAPOURSYNTH_CORE_VERSION, VAPOURSYNTH_API_VERSION, VAPOURSYNTH_VERSION_STRING };
456 static const VSVersion *VS_CC getVersion() {
457 return &version;
460 static VSFuncRef *VS_CC propGetFunc(const VSMap *props, const char *name, int index, int *error) {
461 int err = getPropErrorCheck(props, name, index, error, VSVariant::vMethod);
463 if (err)
464 return 0;
466 const VSVariant &l = (*props)[name];
467 return new VSFuncRef(l.m[index]);
470 static int VS_CC propSetFunc(VSMap *props, const char *name, VSFuncRef *func, int append) {
471 if (!append)
472 props->remove(name);
474 if (props->contains(name)) {
475 VSVariant &l = (*props)[name];
477 if (l.vtype != VSVariant::vMethod)
478 return 1;
479 else
480 l.m.append(func->func);
481 } else {
482 VSVariant l(VSVariant::vMethod);
483 l.m.append(func->func);
484 props->insert(name, l);
487 return 0;
490 static void VS_CC callFunc(VSFuncRef *func, const VSMap *in, VSMap *out, VSCore *core, const VSAPI *vsapi) {
491 func->func->call(in, out, core, vsapi);
494 static VSFuncRef *VS_CC createFunc(VSPublicFunction func, void *userData, VSFreeFuncData free) {
495 return new VSFuncRef(PExtFunction(new ExtFunction(func, userData, free)));
498 static void VS_CC freeFunc(VSFuncRef *f) {
499 delete f;
502 static void VS_CC queryCompletedFrame(const VSNodeRef **node, int *n, VSFrameContext *frameCtx) {
503 PFrameContext f(*(PFrameContext *)frameCtx);
504 *node = f->lastCompletedNode;
505 *n = f->lastCompletedN;
508 static void VS_CC releaseFrameEarly(const VSNodeRef *node, int n, VSFrameContext *frameCtx) {
509 PFrameContext f(*(PFrameContext *)frameCtx);
510 f->availableFrames.remove(FrameKey(node->clip.data(), n));
513 static VSFuncRef *VS_CC cloneFuncRef(VSFuncRef *f) {
514 return new VSFuncRef(f->func);
517 const VSAPI vsapi = {
518 &createCore,
519 &freeCore,
520 &getVersion,
522 &cloneFrameRef,
523 &cloneNodeRef,
524 &cloneFuncRef,
526 &freeFrame,
527 &freeNode,
528 &freeFunc,
530 &newVideoFrame,
531 &copyFrame,
532 &copyFrameProps,
533 &registerFunction,
534 &getPluginId,
535 &getPluginNs,
536 &getPlugins,
537 &getFunctions,
538 &createFilter,
539 &setError,
540 &getError,
541 &setFilterError,
542 &invoke,
543 &getFormatPreset,
544 &registerFormat,
545 &getFrame,
546 &getFrameAsync,
547 &getFrameFilter,
548 &requestFrameFilter,
549 &queryCompletedFrame,
550 &releaseFrameEarly,
552 &getStride,
553 &getReadPtr,
554 &getWritePtr,
556 &createFunc,
557 &callFunc,
559 &newMap,
560 &freeMap,
561 &clearMap,
563 &getVideoInfo,
564 &setVideoInfo,
565 &getFrameFormat,
566 &getFrameWidth,
567 &getFrameHeight,
568 &getFramePropsRO,
569 &getFramePropsRW,
571 &propNumKeys,
572 &propGetKey,
573 &propNumElements,
574 &propGetType,
575 &propGetInt,
576 &propGetFloat,
577 &propGetData,
578 &propGetDataSize,
579 &propGetNode,
580 &propGetFrame,
581 &propGetFunc,
582 &propDeleteKey,
583 &propSetInt,
584 &propSetFloat,
585 &propSetData,
586 &propSetNode,
587 &propSetFrame,
588 &propSetFunc