Build vsscript with Waf.
[vapoursynth-svn.git] / src / core / vsapi.cpp
blob156beee3eef40881933d26cdda54268c6c5ebb79
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 VapourSynth; 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 "cpufeatures.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 bitsPerSample, int subSamplingW, int subSamplingH, VSCore *core) {
37 return core->registerFormat((VSColorFamily)colorFamily, (VSSampleType)sampleType, bitsPerSample, subSamplingW, subSamplingH);
40 static const VSFrameRef *VS_CC cloneFrameRef(const VSFrameRef *frame) {
41 Q_ASSERT(frame);
42 return new VSFrameRef(frame->frame);
45 static VSNodeRef *VS_CC cloneNodeRef(VSNodeRef *node) {
46 Q_ASSERT(node);
47 return new VSNodeRef(node->clip, node->index);
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, VSNodeRef *clip, VSFrameDoneCallback fdc, void *userData) {
63 PFrameContext c(new FrameContext(n, clip->index, clip, fdc, userData));
64 clip->clip->getFrame(c);
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, VSNodeRef *node, 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);
83 g->errorMsg[g->bufSize - 1] = 0;
85 g->a.wakeOne();
88 static const VSFrameRef *VS_CC getFrame(int n, VSNodeRef *clip, char *errorMsg, int bufSize) {
89 GetFrameWaiter g(errorMsg, bufSize);
90 QMutexLocker l(&g.b);
91 PFrameContext c(new FrameContext(n, clip->index, clip, &frameWaiterCallback, &g));
92 VSNode *node = clip->clip.data();
93 bool isWorker = node->isWorkerThread();
94 if (isWorker)
95 node->releaseThread();
96 node->getFrame(c);
97 g.a.wait(&g.b);
98 if (isWorker)
99 node->reserveThread();
100 return g.r;
103 static void VS_CC requestFrameFilter(int n, VSNodeRef *clip, VSFrameContext *ctxHandle) {
104 PFrameContext f(*(PFrameContext *)ctxHandle);
105 PFrameContext g(new FrameContext(n, clip->index, clip->clip.data(), f));
106 clip->clip->getFrame(g);
109 static const VSFrameRef *VS_CC getFrameFilter(int n, VSNodeRef *clip, VSFrameContext *ctxHandle) {
110 PFrameContext f(*(PFrameContext *)ctxHandle);
111 PVideoFrame g = f->availableFrames.value(NodeOutputKey(clip->clip.data(), n, clip->index));
113 if (g)
114 return new VSFrameRef(g);
115 else
116 return NULL;
119 static void VS_CC freeFrame(const VSFrameRef *frame) {
120 delete frame;
123 static void VS_CC freeNode(VSNodeRef *clip) {
124 delete clip;
127 static VSFrameRef *VS_CC newVideoFrame(const VSFormat *format, int width, int height, const VSFrameRef *propSrc, VSCore *core) {
128 Q_ASSERT(format);
129 return new VSFrameRef(core->newVideoFrame(format, width, height, propSrc ? propSrc->frame.data() : NULL));
132 static VSFrameRef *VS_CC newVideoFrame2(const VSFormat *format, int width, int height, const VSFrameRef **planeSrc, const int *planes, const VSFrameRef *propSrc, VSCore *core) {
133 Q_ASSERT(format);
134 VSFrame *fp[3];
135 for (int i = 0; i < format->numPlanes; i++)
136 fp[i] = planeSrc[i] ? planeSrc[i]->frame.data() : NULL;
137 return new VSFrameRef(core->newVideoFrame(format, width, height, fp, planes, propSrc ? propSrc->frame.data() : NULL));
140 static VSFrameRef *VS_CC copyFrame(const VSFrameRef *frame, VSCore *core) {
141 return new VSFrameRef(core->copyFrame(frame->frame));
144 static void VS_CC copyFrameProps(const VSFrameRef *src, VSFrameRef *dst, VSCore *core) {
145 core->copyFrameProps(src->frame, dst->frame);
148 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) {
149 core->createFilter(in, out, name, init, getFrame, free, static_cast<VSFilterMode>(filterMode), flags, instanceData, VAPOURSYNTH_API_VERSION);
152 static void VS_CC setError(VSMap *map, const char *errorMessage) {
153 map->clear();
154 VSVariant l(VSVariant::vData);
155 l.s.append(errorMessage ? errorMessage : "Error: no error specified");
156 map->insert("_Error", l);
159 static const char *VS_CC getError(const VSMap *map) {
160 if (map->contains("_Error"))
161 return (*map)["_Error"].s[0].constData();
162 else
163 return NULL;
166 static void VS_CC setFilterError(const char *errorMessage, VSFrameContext *context) {
167 PFrameContext f(*(PFrameContext *)context);
168 f->setError(errorMessage);
171 //property access functions
172 static const VSVideoInfo *VS_CC getVideoInfo(VSNodeRef *c) {
173 return &c->clip->getVideoInfo(c->index);
176 static void VS_CC setVideoInfo(const VSVideoInfo *vi, int numOutputs, VSNode *c) {
177 c->setVideoInfo(vi, numOutputs);
180 static const VSFormat *VS_CC getFrameFormat(const VSFrameRef *f) {
181 return f->frame->getFormat();
184 static int VS_CC getFrameWidth(const VSFrameRef *f, int plane) {
185 return f->frame->getWidth(plane);
188 static int VS_CC getFrameHeight(const VSFrameRef *f, int plane) {
189 return f->frame->getHeight(plane);
192 static const VSMap *VS_CC getFramePropsRO(const VSFrameRef *frame) {
193 return &frame->frame->getConstProperties();
196 static VSMap *VS_CC getFramePropsRW(VSFrameRef *frame) {
197 return &frame->frame->getProperties();
200 static int VS_CC propNumKeys(const VSMap *props) {
201 return props->keys().count();
204 static const char *VS_CC propGetKey(const VSMap *props, int index) {
205 if (index < 0 || index >= props->count())
206 qFatal("Out of bound index");
208 return props->keys()[index].constData();
211 static int VS_CC propNumElements(const VSMap *props, const char *name) {
212 if (!props->contains(name))
213 return -1;
215 const VSVariant &val = (*props)[name];
216 return val.count();
219 static char VS_CC propGetType(const VSMap *props, const char *name) {
220 if (!props->contains(name))
221 return 'u';
223 const char a[] = { 'u', 'i', 'f', 's', 'c', 'v', 'm'};
224 const VSVariant &val = (*props)[name];
225 return a[val.vtype];
228 static int getPropErrorCheck(const VSMap *props, const char *name, int index, int *error, int type) {
229 int err = 0;
231 if (getError(props))
232 qFatal("Attempted to read from a map with error set: %s", getError(props));
234 if (!props->contains(name))
235 err |= peUnset;
237 if (!err && props->value(name).vtype != type)
238 err |= peType;
240 int c = propNumElements(props, name);
242 if ((!err && c <= index) || index < 0)
243 err |= peIndex;
245 if (err && !error)
246 qFatal("Property read unsuccessful but no error output: %s", name);
248 if (error)
249 *error = err;
251 return err;
254 static int64_t VS_CC propGetInt(const VSMap *props, const char *name, int index, int *error) {
255 int err = getPropErrorCheck(props, name, index, error, VSVariant::vInt);
257 if (err)
258 return 0;
260 const VSVariant &l = (*props)[name];
261 return l.i[index];
264 static double VS_CC propGetFloat(const VSMap *props, const char *name, int index, int *error) {
265 int err = getPropErrorCheck(props, name, index, error, VSVariant::vFloat);
267 if (err)
268 return 0;
270 const VSVariant &l = (*props)[name];
271 return l.f[index];
274 static const char *VS_CC propGetData(const VSMap *props, const char *name, int index, int *error) {
275 int err = getPropErrorCheck(props, name, index, error, VSVariant::vData);
277 if (err)
278 return 0;
280 const VSVariant &l = (*props)[name];
281 return l.s[index].constData();
284 static int VS_CC propGetDataSize(const VSMap *props, const char *name, int index, int *error) {
285 int err = getPropErrorCheck(props, name, index, error, VSVariant::vData);
287 if (err)
288 return 0;
290 const VSVariant &l = (*props)[name];
291 return l.s[index].size();
294 static VSNodeRef *VS_CC propGetNode(const VSMap *props, const char *name, int index, int *error) {
295 int err = getPropErrorCheck(props, name, index, error, VSVariant::vNode);
297 if (err)
298 return 0;
300 const VSVariant &l = (*props)[name];
301 return new VSNodeRef(l.c[index]);
304 static const VSFrameRef *VS_CC propGetFrame(const VSMap *props, const char *name, int index, int *error) {
305 int err = getPropErrorCheck(props, name, index, error, VSVariant::vFrame);
307 if (err)
308 return 0;
310 const VSVariant &l = (*props)[name];
311 return new VSFrameRef(l.v[index]);
314 static int VS_CC propDeleteKey(VSMap *props, const char *name) {
315 return props->remove(name);
318 static void sharedPropSet(VSMap *props, const char *name, int &append) {
319 if (append != paReplace && append != paAppend && append != paTouch)
320 qFatal("Invalid prop append mode given");
322 if (append == paReplace) {
323 props->remove(name);
324 append = paAppend;
328 static int VS_CC propSetInt(VSMap *props, const char *name, int64_t i, int append) {
329 sharedPropSet(props, name, append);
330 if (props->contains(name)) {
331 VSVariant &l = (*props)[name];
333 if (l.vtype != VSVariant::vInt)
334 return 1;
335 else if (append == paAppend)
336 l.i.append(i);
337 } else {
338 VSVariant l(VSVariant::vInt);
339 if (append == paAppend)
340 l.i.append(i);
341 props->insert(name, l);
344 return 0;
347 static int VS_CC propSetFloat(VSMap *props, const char *name, double d, int append) {
348 sharedPropSet(props, name, append);
349 if (props->contains(name)) {
350 VSVariant &l = (*props)[name];
352 if (l.vtype != VSVariant::vFloat)
353 return 1;
354 else if (append == paAppend)
355 l.f.append(d);
356 } else {
357 VSVariant l(VSVariant::vFloat);
358 if (append == paAppend)
359 l.f.append(d);
360 props->insert(name, l);
363 return 0;
366 static int VS_CC propSetData(VSMap *props, const char *name, const char *d, int length, int append) {
367 sharedPropSet(props, name, append);
368 if (props->contains(name)) {
369 VSVariant &l = (*props)[name];
371 if (l.vtype != VSVariant::vData)
372 return 1;
373 else if (append == paAppend)
374 l.s.append(d);
375 } else {
376 VSVariant l(VSVariant::vData);
377 if (append == paAppend)
378 l.s.append(length >= 0 ? QByteArray(d, length) : QByteArray(d));
379 props->insert(name, l);
382 return 0;
385 static int VS_CC propSetNode(VSMap *props, const char *name, VSNodeRef *clip, int append) {
386 sharedPropSet(props, name, append);
387 if (props->contains(name)) {
388 VSVariant &l = (*props)[name];
390 if (l.vtype != VSVariant::vNode)
391 return 1;
392 else if (append == paAppend)
393 l.c.append(*clip);
394 } else {
395 VSVariant l(VSVariant::vNode);
396 if (append == paAppend)
397 l.c.append(*clip);
398 props->insert(name, l);
401 return 0;
404 static int VS_CC propSetFrame(VSMap *props, const char *name, const VSFrameRef *frame, int append) {
405 sharedPropSet(props, name, append);
406 if (props->contains(name)) {
407 VSVariant &l = (*props)[name];
409 if (l.vtype != VSVariant::vFrame)
410 return 1;
411 else if (append == paAppend)
412 l.v.append(frame->frame);
413 } else {
414 VSVariant l(VSVariant::vFrame);
415 if (append == paAppend)
416 l.v.append(frame->frame);
417 props->insert(name, l);
420 return 0;
423 static VSMap *VS_CC invoke(VSPlugin *plugin, const char *name, const VSMap *args) {
424 Q_ASSERT(plugin);
425 return new VSMap(plugin->invoke(name, *args));
428 static VSMap *VS_CC newMap() {
429 return new VSMap();
432 static void VS_CC freeMap(VSMap *map) {
433 delete map;
436 static void VS_CC clearMap(VSMap *map) {
437 map->clear();
440 static VSCore *VS_CC createCore(int threads) {
441 return new VSCore(threads);
444 static void VS_CC freeCore(VSCore *core) {
445 delete core;
448 static VSPlugin *VS_CC getPluginId(const char *identifier, VSCore *core) {
449 return core->getPluginId(identifier);
452 static VSPlugin *VS_CC getPluginNs(const char *ns, VSCore *core) {
453 return core->getPluginNs(ns);
456 static VSMap *VS_CC getPlugins(VSCore *core) {
457 return new VSMap(core->getPlugins());
460 static VSMap *VS_CC getFunctions(VSPlugin *plugin) {
461 return new VSMap(plugin->getFunctions());
464 static const VSCoreInfo *VS_CC getCoreInfo(VSCore *core) {
465 return &core->getCoreInfo();
468 static VSFuncRef *VS_CC propGetFunc(const VSMap *props, const char *name, int index, int *error) {
469 int err = getPropErrorCheck(props, name, index, error, VSVariant::vMethod);
471 if (err)
472 return 0;
474 const VSVariant &l = (*props)[name];
475 return new VSFuncRef(l.m[index]);
478 static int VS_CC propSetFunc(VSMap *props, const char *name, VSFuncRef *func, int append) {
479 if (!append)
480 props->remove(name);
482 if (props->contains(name)) {
483 VSVariant &l = (*props)[name];
485 if (l.vtype != VSVariant::vMethod)
486 return 1;
487 else
488 l.m.append(func->func);
489 } else {
490 VSVariant l(VSVariant::vMethod);
491 l.m.append(func->func);
492 props->insert(name, l);
495 return 0;
498 static void VS_CC callFunc(VSFuncRef *func, const VSMap *in, VSMap *out, VSCore *core, const VSAPI *vsapi) {
499 func->func->call(in, out, core, vsapi);
502 static VSFuncRef *VS_CC createFunc(VSPublicFunction func, void *userData, VSFreeFuncData free) {
503 return new VSFuncRef(PExtFunction(new ExtFunction(func, userData, free)));
506 static void VS_CC freeFunc(VSFuncRef *f) {
507 delete f;
510 static void VS_CC queryCompletedFrame(VSNodeRef **node, int *n, VSFrameContext *frameCtx) {
511 PFrameContext f(*(PFrameContext *)frameCtx);
512 *node = f->lastCompletedNode;
513 *n = f->lastCompletedN;
516 static void VS_CC releaseFrameEarly(VSNodeRef *node, int n, VSFrameContext *frameCtx) {
517 PFrameContext f(*(PFrameContext *)frameCtx);
518 f->availableFrames.remove(NodeOutputKey(node->clip.data(), n, node->index));
521 static VSFuncRef *VS_CC cloneFuncRef(VSFuncRef *f) {
522 return new VSFuncRef(f->func);
525 static int64_t VS_CC setMaxCacheSize(int64_t bytes, VSCore *core) {
526 return core->setMaxCacheSize(bytes);
529 static int VS_CC getOutputIndex(VSFrameContext *frameCtx) {
530 PFrameContext f(*(PFrameContext *)frameCtx);
531 return f->index;
534 static VSMessageHandler handler = NULL;
536 void vsMessageHandler(QtMsgType type, const char *msg) {
537 handler(type, msg);
538 if (type == QtFatalMsg)
539 abort();
542 static void VS_CC setMessageHandler(VSMessageHandler handler) {
543 if (handler) {
544 ::handler = handler;
545 qInstallMsgHandler(vsMessageHandler);
546 } else {
547 qInstallMsgHandler(NULL);
548 ::handler = NULL;
552 const VSAPI vsapi = {
553 &createCore,
554 &freeCore,
555 &getCoreInfo,
557 &cloneFrameRef,
558 &cloneNodeRef,
559 &cloneFuncRef,
561 &freeFrame,
562 &freeNode,
563 &freeFunc,
565 &newVideoFrame,
566 &copyFrame,
567 &copyFrameProps,
568 &registerFunction,
569 &getPluginId,
570 &getPluginNs,
571 &getPlugins,
572 &getFunctions,
573 &createFilter,
574 &setError,
575 &getError,
576 &setFilterError,
577 &invoke,
578 &getFormatPreset,
579 &registerFormat,
580 &getFrame,
581 &getFrameAsync,
582 &getFrameFilter,
583 &requestFrameFilter,
584 &queryCompletedFrame,
585 &releaseFrameEarly,
587 &getStride,
588 &getReadPtr,
589 &getWritePtr,
591 &createFunc,
592 &callFunc,
594 &newMap,
595 &freeMap,
596 &clearMap,
598 &getVideoInfo,
599 &setVideoInfo,
600 &getFrameFormat,
601 &getFrameWidth,
602 &getFrameHeight,
603 &getFramePropsRO,
604 &getFramePropsRW,
606 &propNumKeys,
607 &propGetKey,
608 &propNumElements,
609 &propGetType,
610 &propGetInt,
611 &propGetFloat,
612 &propGetData,
613 &propGetDataSize,
614 &propGetNode,
615 &propGetFrame,
616 &propGetFunc,
617 &propDeleteKey,
618 &propSetInt,
619 &propSetFloat,
620 &propSetData,
621 &propSetNode,
622 &propSetFrame,
623 &propSetFunc,
625 &setMaxCacheSize,
626 &getOutputIndex,
627 &newVideoFrame2,
629 &setMessageHandler
632 //////////////////////////
633 // R2 compat junk
635 typedef void (VS_CC *VSSetVideoInfo_R2)(const VSVideoInfo *vi, VSNode *node);
636 typedef VSNodeRef *(VS_CC *VSCreateFilter_R2)(const VSMap *in, VSMap *out, const char *name, VSFilterInit init, VSFilterGetFrame getFrame, VSFilterFree free, int filterMode, int flags, void *instanceData, VSCore *core);
638 static void VS_CC setVideoInfoR2(const VSVideoInfo *vi, VSNode *c) {
639 setVideoInfo(vi, 1, c);
642 static VSNodeRef *VS_CC createFilterR2(const VSMap *in, VSMap *out, const char *name, VSFilterInit init, VSFilterGetFrame getFrame, VSFilterFree free, int filterMode, int flags, void *instanceData, VSCore *core) {
643 core->createFilter(in, out, name, init, getFrame, free, static_cast<VSFilterMode>(filterMode), flags, instanceData, 2);
644 return propGetNode(out, "clip", 0, NULL);
647 struct VSAPI_R2 {
648 VSCreateCore createCore;
649 VSFreeCore freeCore;
650 VSGetCoreInfo getCoreInfo;
652 VSCloneFrameRef cloneFrameRef;
653 VSCloneNodeRef cloneNodeRef;
654 VSCloneFuncRef cloneFuncRef;
656 VSFreeFrame freeFrame;
657 VSFreeNode freeNode;
658 VSFreeFunc freeFunc;
660 VSNewVideoFrame newVideoFrame;
661 VSCopyFrame copyFrame;
662 VSCopyFrameProps copyFrameProps;
664 VSRegisterFunction registerFunction;
665 VSGetPluginId getPluginId;
666 VSGetPluginNs getPluginNs;
667 VSGetPlugins getPlugins;
668 VSGetFunctions getFunctions;
669 VSCreateFilter_R2 createFilter;
670 VSSetError setError;
671 VSGetError getError;
672 VSSetFilterError setFilterError;
673 VSInvoke invoke;
675 VSGetFormatPreset getFormatPreset;
676 VSRegisterFormat registerFormat;
678 VSGetFrame getFrame;
679 VSGetFrameAsync getFrameAsync;
680 VSGetFrameFilter getFrameFilter;
681 VSRequestFrameFilter requestFrameFilter;
682 VSQueryCompletedFrame queryCompletedFrame;
683 VSReleaseFrameEarly releaseFrameEarly;
685 VSGetStride getStride;
686 VSGetReadPtr getReadPtr;
687 VSGetWritePtr getWritePtr;
689 VSCreateFunc createFunc;
690 VSCallFunc callFunc;
692 //property access functions
693 VSCreateMap createMap;
694 VSFreeMap freeMap;
695 VSClearMap clearMap;
697 VSGetVideoInfo getVideoInfo;
698 VSSetVideoInfo_R2 setVideoInfo;
699 VSGetFrameFormat getFrameFormat;
700 VSGetFrameWidth getFrameWidth;
701 VSGetFrameHeight getFrameHeight;
702 VSGetFramePropsRO getFramePropsRO;
703 VSGetFramePropsRW getFramePropsRW;
705 VSPropNumKeys propNumKeys;
706 VSPropGetKey propGetKey;
707 VSPropNumElements propNumElements;
708 VSPropGetType propGetType;
709 VSPropGetInt propGetInt;
710 VSPropGetFloat propGetFloat;
711 VSPropGetData propGetData;
712 VSPropGetDataSize propGetDataSize;
713 VSPropGetNode propGetNode;
714 VSPropGetFrame propGetFrame;
715 VSPropGetFunc propGetFunc;
717 VSPropDeleteKey propDeleteKey;
718 VSPropSetInt propSetInt;
719 VSPropSetFloat propSetFloat;
720 VSPropSetData propSetData;
721 VSPropSetNode propSetNode;
722 VSPropSetFrame propSetFrame;
723 VSPropSetFunc propSetFunc;
725 VSSetMaxCacheSize setMaxCacheSize;
726 VSGetOutputIndex getOutputIndex;
729 ///////////////////////////////
731 const VSAPI *getVSAPIInternal(int version) {
732 if (version == VAPOURSYNTH_API_VERSION) {
733 return &vsapi;
734 } else {
735 qFatal("Internally requested API version %d", version);
736 return NULL;
740 const VSAPI *VS_CC getVapourSynthAPI(int version) {
741 CPUFeatures f;
742 getCPUFeatures(&f);
743 if (!f.can_run_vs) {
744 qWarning("System does not meet minimum requirements to run VapourSynth");
745 return NULL;
746 } else if (version == VAPOURSYNTH_API_VERSION) {
747 return &vsapi;
748 } else {
749 return NULL;