#include "vscore.h"
#include "cpufeatures.h"
#include "vslog.h"
#include "VSHelper4.h"
#include <cassert>
#include <cstring>
#include <string>
using namespace vsh;
static int VS_CC configPlugin(const char *identifier, const char *defaultNamespace, const char *name, int pluginVersion, int apiVersion, int flags, VSPlugin *plugin) VS_NOEXCEPT {
assert(identifier && defaultNamespace && name && plugin);
return plugin->configPlugin(identifier, defaultNamespace, name, pluginVersion, apiVersion, flags);
}
static int VS_CC registerFunction(const char *name, const char *args, const char *returnType, VSPublicFunction argsFunc, void *functionData, VSPlugin *plugin) VS_NOEXCEPT {
assert(name && args && returnType && argsFunc && plugin);
return plugin->registerFunction(name, args, returnType, argsFunc, functionData);
}
static void VS_CC registerFunction3(const char *name, const char *args, vs3::VSPublicFunction argsFunc, void *functionData, VSPlugin *plugin) VS_NOEXCEPT {
assert(name && args && argsFunc && plugin);
plugin->registerFunction(name, args, "any", reinterpret_cast<VSPublicFunction>(argsFunc), functionData);
}
static const vs3::VSVideoFormat *VS_CC getFormatPreset3(int id, VSCore *core) VS_NOEXCEPT {
assert(core);
return core->getVideoFormat3(id);
}
static const vs3::VSVideoFormat *VS_CC registerFormat3(int colorFamily, int sampleType, int bitsPerSample, int subSamplingW, int subSamplingH, VSCore *core) VS_NOEXCEPT {
assert(core);
return core->queryVideoFormat3(static_cast<vs3::VSColorFamily>(colorFamily), static_cast<VSSampleType>(sampleType), bitsPerSample, subSamplingW, subSamplingH);
}
static const VSFrame *VS_CC addFrameRef(const VSFrame *frame) VS_NOEXCEPT {
assert(frame);
const_cast<VSFrame *>(frame)->add_ref();
return frame;
}
static VSNode *VS_CC addNodeRef(VSNode *node) VS_NOEXCEPT {
assert(node);
node->add_ref();
return node;
}
static ptrdiff_t VS_CC getStride(const VSFrame *frame, int plane) VS_NOEXCEPT {
assert(frame);
return frame->getStride(plane);
}
static int VS_CC getStride3(const VSFrame *frame, int plane) VS_NOEXCEPT {
assert(frame);
return static_cast<int>(frame->getStride(plane));
}
static const uint8_t *VS_CC getReadPtr(const VSFrame *frame, int plane) VS_NOEXCEPT {
assert(frame);
return frame->getReadPtr(plane);
}
static uint8_t *VS_CC getWritePtr(VSFrame *frame, int plane) VS_NOEXCEPT {
assert(frame);
return frame->getWritePtr(plane);
}
static void VS_CC getFrameAsync(int n, VSNode *clip, VSFrameDoneCallback fdc, void *userData) VS_NOEXCEPT {
assert(clip && fdc);
int numFrames = (clip->getNodeType() == mtVideo) ? clip->getVideoInfo().numFrames : clip->getAudioInfo().numFrames;
VSFrameContext *ctx = new VSFrameContext(n, clip, fdc, userData, true);
if (n < 0 || n >= numFrames)
ctx->setError("Invalid frame number " + std::to_string(n) + " requested, clip only has " + std::to_string(numFrames) + " frames");
clip->getFrame(ctx);
}
struct GetFrameWaiter {
std::mutex b;
std::condition_variable a;
const VSFrame *r = nullptr;
char *errorMsg;
int bufSize;
GetFrameWaiter(char *errorMsg, int bufSize) : errorMsg(errorMsg), bufSize(bufSize) {}
};
static void VS_CC frameWaiterCallback(void *userData, const VSFrame *frame, int n, VSNode *node, const char *errorMsg) VS_NOEXCEPT {
GetFrameWaiter *g = static_cast<GetFrameWaiter *>(userData);
std::lock_guard<std::mutex> l(g->b);
g->r = frame;
if (g->errorMsg && g->bufSize > 0) {
memset(g->errorMsg, 0, g->bufSize);
if (errorMsg) {
strncpy(g->errorMsg, errorMsg, g->bufSize);
g->errorMsg[g->bufSize - 1] = 0;
}
}
g->a.notify_one();
}
static const VSFrame *VS_CC getFrame(int n, VSNode *node, char *errorMsg, int bufSize) VS_NOEXCEPT {
assert(node);
int numFrames = (node->getNodeType() == mtVideo) ? node->getVideoInfo().numFrames : node->getAudioInfo().numFrames;
if (n < 0 || n >= numFrames) {
if (errorMsg && bufSize > 0) {
memset(errorMsg, 0, bufSize);
if (errorMsg) {
strncpy(errorMsg, ("Invalid frame number " + std::to_string(n) + " requested, clip only has " + std::to_string(numFrames) + " frames").c_str(), bufSize);
errorMsg[bufSize - 1] = 0;
}
}
return nullptr;
}
GetFrameWaiter g(errorMsg, bufSize);
std::unique_lock<std::mutex> l(g.b);
bool isWorker = node->isWorkerThread();
if (isWorker)
node->releaseThread();
node->getFrame(new VSFrameContext(n, node, &frameWaiterCallback, &g, false));
g.a.wait(l);
if (isWorker)
node->reserveThread();
return g.r;
}
static void VS_CC requestFrameFilter(int n, VSNode *node, VSFrameContext *frameCtx) VS_NOEXCEPT {
assert(node && frameCtx);
int numFrames = (node->getNodeType() == mtVideo) ? node->getVideoInfo().numFrames : node->getAudioInfo().numFrames;
if (n >= numFrames)
n = numFrames - 1;
frameCtx->reqList.emplace_back(NodeOutputKey(node, n));
}
static const VSFrame *VS_CC getFrameFilter(int n, VSNode *node, VSFrameContext *frameCtx) VS_NOEXCEPT {
assert(node && frameCtx);
int numFrames = (node->getNodeType() == mtVideo) ? node->getVideoInfo().numFrames : node->getAudioInfo().numFrames;
if (numFrames && n >= numFrames)
n = numFrames - 1;
auto key = NodeOutputKey(node, n);
for (size_t i = 0; i < frameCtx->availableFrames.size(); i++) {
const auto &tmp = frameCtx->availableFrames[i];
if (tmp.first == key) {
tmp.second->add_ref();
return tmp.second.get();
}
}
return nullptr;
}
static void VS_CC freeFrame(const VSFrame *frame) VS_NOEXCEPT {
if (frame)
const_cast<VSFrame *>(frame)->release();
}
static void VS_CC freeNode(VSNode *clip) VS_NOEXCEPT {
if (clip)
clip->release();
}
static VSFrame *VS_CC newVideoFrame(const VSVideoFormat *format, int width, int height, const VSFrame *propSrc, VSCore *core) VS_NOEXCEPT {
assert(format && core);
return new VSFrame(*format, width, height, propSrc, core);
}
static VSFrame *VS_CC newVideoFrame3(const vs3::VSVideoFormat *format, int width, int height, const VSFrame *propSrc, VSCore *core) VS_NOEXCEPT {
assert(format && core);
VSVideoFormat v4;
if (core->VideoFormatFromV3(v4, format))
return new VSFrame(v4, width, height, propSrc, core);
else
return nullptr;
}
static VSFrame *VS_CC newVideoFrame2(const VSVideoFormat *format, int width, int height, const VSFrame **planeSrc, const int *planes, const VSFrame *propSrc, VSCore *core) VS_NOEXCEPT {
assert(format && core);
return new VSFrame(*format, width, height, planeSrc, planes, propSrc, core);
}
static VSFrame *VS_CC newVideoFrame23(const vs3::VSVideoFormat *format, int width, int height, const VSFrame **planeSrc, const int *planes, const VSFrame *propSrc, VSCore *core) VS_NOEXCEPT {
assert(format && core);
VSVideoFormat v4;
if (core->VideoFormatFromV3(v4, format))
return new VSFrame(v4, width, height, planeSrc, planes, propSrc, core);
else
return nullptr;
}
static VSFrame *VS_CC copyFrame(const VSFrame *frame, VSCore *core) VS_NOEXCEPT {
assert(frame && core);
return new VSFrame(*frame);
}
static void VS_CC copyFrameProps3(const VSFrame *src, VSFrame *dst, VSCore *core) VS_NOEXCEPT {
assert(src && dst && core);
dst->setProperties(src->getConstProperties());
}
static void VS_CC createFilter3(const VSMap *in, VSMap *out, const char *name, vs3::VSFilterInit init, vs3::VSFilterGetFrame getFrame, VSFilterFree free, int filterMode, int flags, void *instanceData, VSCore *core) VS_NOEXCEPT {
assert(in && out && name && init && getFrame && core);
VSFilterMode fm;
switch (filterMode) {
case vs3::fmParallel:
fm = fmParallel;
break;
case vs3::fmParallelRequests:
fm = fmParallelRequests;
break;
case vs3::fmUnordered:
fm = fmUnordered;
break;
case vs3::fmFrameState:
fm = fmFrameState;
break;
default:
core->logFatal("Invalid filter mode specified for " + std::string(name));
}
core->createFilter3(in, out, name, init, reinterpret_cast<VSFilterGetFrame>(getFrame), free, fm, flags, instanceData, VAPOURSYNTH3_API_MAJOR);
}
static void VS_CC mapSetError(VSMap *map, const char *errorMessage) VS_NOEXCEPT {
assert(map && errorMessage);
map->setError(errorMessage ? errorMessage : "Error: no error specified");
}
static const char *VS_CC mapGetError(const VSMap *map) VS_NOEXCEPT {
assert(map);
return map->getErrorMessage();
}
static void VS_CC setFilterError(const char *errorMessage, VSFrameContext *context) VS_NOEXCEPT {
assert(errorMessage && context);
context->setError(errorMessage);
}
static const VSVideoInfo *VS_CC getVideoInfo(VSNode *node) VS_NOEXCEPT {
assert(node && node->getNodeType() == mtVideo);
return &node->getVideoInfo();
}
static const vs3::VSVideoInfo *VS_CC getVideoInfo3(VSNode *c) VS_NOEXCEPT {
assert(c);
return &c->getVideoInfo3();
}
static void VS_CC setVideoInfo3(const vs3::VSVideoInfo *vi, int numOutputs, VSNode *c) VS_NOEXCEPT {
assert(vi && numOutputs > 0 && c);
c->setVideoInfo3(vi, numOutputs);
}
static const VSVideoFormat *VS_CC getVideoFrameFormat(const VSFrame *f) VS_NOEXCEPT {
assert(f);
return f->getVideoFormat();
}
static const vs3::VSVideoFormat *VS_CC getFrameFormat3(const VSFrame *f) VS_NOEXCEPT {
assert(f);
return f->getVideoFormatV3();
}
static int VS_CC getFrameWidth(const VSFrame *f, int plane) VS_NOEXCEPT {
assert(f);
assert(plane >= 0);
return f->getWidth(plane);
}
static int VS_CC getFrameHeight(const VSFrame *f, int plane) VS_NOEXCEPT {
assert(f);
assert(plane >= 0);
return f->getHeight(plane);
}
static const VSMap *VS_CC getFramePropertiesRO(const VSFrame *frame) VS_NOEXCEPT {
assert(frame);
return &frame->getConstProperties();
}
static VSMap *VS_CC getFramePropertiesRW(VSFrame *frame) VS_NOEXCEPT {
assert(frame);
return &frame->getProperties();
}
static int VS_CC mapNumKeys(const VSMap *map) VS_NOEXCEPT {
assert(map);
return static_cast<int>(map->size());
}
static const char *VS_CC mapGetKey(const VSMap *map, int index) VS_NOEXCEPT {
assert(map);
return map->key(static_cast<size_t>(index));
}
static int VS_CC mapNumElements(const VSMap *map, const char *key) VS_NOEXCEPT {
assert(map && key);
VSArrayBase *val = map->find(key);
return val ? static_cast<int>(val->size()) : -1;
}
static int VS_CC mapGetType(const VSMap *map, const char *key) VS_NOEXCEPT {
assert(map && key);
VSArrayBase *val = map->find(key);
return val ? val->type() : ptUnset;
}
static char VS_CC propGetType3(const VSMap *map, const char *key) VS_NOEXCEPT {
assert(map && key);
VSArrayBase *val = map->find(key);
VSPropertyType pt = val ? val->type() : ptUnset;
switch (pt) {
case ptInt:
return vs3::ptInt;
case ptFloat:
return vs3::ptFloat;
case ptData:
return vs3::ptData;
case ptVideoNode:
return vs3::ptNode;
case ptVideoFrame:
return vs3::ptFrame;
case ptFunction:
return vs3::ptFunction;
default:
return vs3::ptUnset;
}
}
static VSArrayBase *propGetShared(const VSMap *map, const char *key, int index, int *error, VSPropertyType propType) noexcept {
assert(map && key && index >= 0);
if (error)
*error = peSuccess;
if (map->hasError()) {
if (error)
*error = peError;
else
VS_FATAL_ERROR(("Property read unsuccessful on map with error set but no error output: " + std::string(key)).c_str());
return nullptr;
}
VSArrayBase *arr = map->find(key);
if (!arr) {
if (error)
*error = peUnset;
else
VS_FATAL_ERROR(("Property read unsuccessful due to missing key but no error output: " + std::string(key)).c_str());
return nullptr;
}
if (index < 0 || index >= static_cast<int>(arr->size())) {
if (error)
*error = peIndex;
else
VS_FATAL_ERROR(("Property read unsuccessful due to out of bounds index but no error output: " + std::string(key)).c_str());
return nullptr;
}
if (arr->type() != propType) {
if (error)
*error = peType;
else
VS_FATAL_ERROR(("Property read unsuccessful due to wrong type but no error output: " + std::string(key)).c_str());
return nullptr;
}
return arr;
}
static int64_t VS_CC mapGetInt(const VSMap *map, const char *key, int index, int *error) VS_NOEXCEPT {
VSArrayBase *arr = propGetShared(map, key, index, error, ptInt);
if (arr)
return reinterpret_cast<const VSIntArray *>(arr)->at(index);
else
return 0;
}
static int VS_CC mapGetIntSaturated(const VSMap *map, const char *key, int index, int *error) VS_NOEXCEPT {
return int64ToIntS(mapGetInt(map, key, index, error));
}
static double VS_CC mapGetFloat(const VSMap *map, const char *key, int index, int *error) VS_NOEXCEPT {
VSArrayBase *arr = propGetShared(map, key, index, error, ptFloat);
if (arr)
return reinterpret_cast<const VSFloatArray *>(arr)->at(index);
else
return 0;
}
static float VS_CC mapGetFloatSaturated(const VSMap *map, const char *key, int index, int *error) VS_NOEXCEPT {
return doubleToFloatS(mapGetFloat(map, key, index, error));
}
static const char *VS_CC mapGetData(const VSMap *map, const char *key, int index, int *error) VS_NOEXCEPT {
VSArrayBase *arr = propGetShared(map, key, index, error, ptData);
if (arr)
return reinterpret_cast<const VSDataArray *>(arr)->at(index).data.c_str();
else
return nullptr;
}
static int VS_CC mapGetDataSize(const VSMap *map, const char *key, int index, int *error) VS_NOEXCEPT {
VSArrayBase *arr = propGetShared(map, key, index, error, ptData);
if (arr)
return static_cast<int>(reinterpret_cast<const VSDataArray *>(arr)->at(index).data.size());
else
return -1;
}
static int VS_CC mapGetDataTypeHint(const VSMap *map, const char *key, int index, int *error) VS_NOEXCEPT {
VSArrayBase *arr = propGetShared(map, key, index, error, ptData);
if (arr)
return reinterpret_cast<const VSDataArray *>(arr)->at(index).typeHint;
else
return dtUnknown;
}
static VSNode *VS_CC mapGetNode(const VSMap *map, const char *key, int index, int *error) VS_NOEXCEPT {
int dummyError;
VSArrayBase *arr = propGetShared(map, key, index, &dummyError, ptVideoNode);
if (arr) {
VSNode *ref = reinterpret_cast<VSVideoNodeArray *>(arr)->at(index).get();
ref->add_ref();
if (error)
*error = dummyError;
return ref;
} else {
arr = propGetShared(map, key, index, error, ptAudioNode);
if (arr) {
VSNode *ref = reinterpret_cast<VSAudioNodeArray *>(arr)->at(index).get();
ref->add_ref();
return ref;
} else {
return nullptr;
}
}
}
static const VSFrame *VS_CC mapGetFrame(const VSMap *map, const char *key, int index, int *error) VS_NOEXCEPT {
int dummyError;
VSArrayBase *arr = propGetShared(map, key, index, &dummyError, ptVideoFrame);
if (arr) {
VSFrame *ref = reinterpret_cast<VSVideoFrameArray *>(arr)->at(index).get();
ref->add_ref();
if (error)
*error = dummyError;
return ref;
} else {
arr = propGetShared(map, key, index, error, ptAudioFrame);
if (arr) {
VSFrame *ref = reinterpret_cast<VSAudioFrameArray *>(arr)->at(index).get();
ref->add_ref();
return ref;
} else {
return nullptr;
}
}
}
static int VS_CC mapDeleteKey(VSMap *map, const char *key) VS_NOEXCEPT {
assert(map && key);
return map->erase(key);
}
static inline bool isAlphaUnderscore(char c) {
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_';
}
static inline bool isAlphaNumUnderscore(char c) {
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_';
}
static bool isValidVSMapKey(const char *s) {
if (!s)
return false;
if (!isAlphaUnderscore(*s))
return false;
s++;
while (*s) {
if (!isAlphaNumUnderscore(*s))
return false;
s++;
}
return true;
}
static int VS_CC mapSetEmpty(VSMap *map, const char *key, int type) VS_NOEXCEPT {
assert(map && key);
if (!isValidVSMapKey(key))
return 1;
std::string skey = key;
if (map->find(skey))
return 1;
switch (type) {
case ptInt:
map->insert(key, new VSIntArray);
break;
case ptFloat:
map->insert(key, new VSFloatArray);
break;
case ptData:
map->insert(key, new VSDataArray);
break;
case ptVideoNode:
map->insert(key, new VSVideoNodeArray);
break;
case ptAudioNode:
map->insert(key, new VSAudioNodeArray);
break;
case ptVideoFrame:
map->insert(key, new VSVideoFrameArray);
break;
case ptAudioFrame:
map->insert(key, new VSAudioFrameArray);
break;
case ptFunction:
map->insert(key, new VSFunctionArray);
break;
default:
return 1;
}
return 0;
}
template<typename T, VSPropertyType propType>
bool propSetShared(VSMap *map, const char *key, const T &val, int append) {
assert(map && key);
if (append != maReplace && append != maAppend && append != vs3::paTouch)
VS_FATAL_ERROR(("Invalid prop append mode given when setting key '" + std::string(key) + "'").c_str());
if (!isValidVSMapKey(key))
return false;
std::string skey = key;
if (append == maReplace) {
VSArray<T, propType> *v = new VSArray<T, propType>();
v->push_back(val);
map->insert(key, v);
return true;
} else if (append == maAppend) {
VSArrayBase *arr = map->find(skey);
if (arr && arr->type() == propType) {
arr = map->detach(skey);
reinterpret_cast<VSArray<T, propType> *>(arr)->push_back(val);
return true;
} else if (arr) {
return false;
} else {
VSArray<T, propType> *v = new VSArray<T, propType>();
v->push_back(val);
map->insert(key, v);
return true;
}
} else {
return !mapSetEmpty(map, key, propType);
}
}
static int VS_CC mapSetInt(VSMap *map, const char *key, int64_t i, int append) VS_NOEXCEPT {
return !propSetShared<int64_t, ptInt>(map, key, i, append);
}
static int VS_CC mapSetFloat(VSMap *map, const char *key, double d, int append) VS_NOEXCEPT {
return !propSetShared<double, ptFloat>(map, key, d, append);
}
static int VS_CC mapSetData(VSMap *map, const char *key, const char *d, int length, int type, int append) VS_NOEXCEPT {
return !propSetShared<VSMapData, ptData>(map, key, { static_cast<VSDataTypeHint>(type), (length >= 0) ? std::string(d, length) : std::string(d) }, append);
}
static int VS_CC propSetData3(VSMap *map, const char *key, const char *d, int length, int append) VS_NOEXCEPT {
return mapSetData(map, key, d, length, dtUnknown, append);
}
static int VS_CC mapSetNode(VSMap *map, const char *key, VSNode *node, int append) VS_NOEXCEPT {
if (node == nullptr || node->getNodeType() == mtVideo)
return !propSetShared<PVSNode, ptVideoNode>(map, key, { node, true }, append);
else
return !propSetShared<PVSNode, ptAudioNode>(map, key, { node, true }, append);
}
static int VS_CC mapConsumeNode(VSMap *map, const char *key, VSNode *node, int append) VS_NOEXCEPT {
if (node == nullptr || node->getNodeType() == mtVideo)
return !propSetShared<PVSNode, ptVideoNode>(map, key, {node, false}, append);
else
return !propSetShared<PVSNode, ptAudioNode>(map, key, {node, false}, append);
}
static int VS_CC mapSetFrame(VSMap *map, const char *key, const VSFrame *frame, int append) VS_NOEXCEPT {
if (frame == nullptr || frame->getFrameType() == mtVideo)
return !propSetShared<PVSFrame, ptVideoFrame>(map, key, { const_cast<VSFrame *>(frame), true }, append);
else
return !propSetShared<PVSFrame, ptAudioFrame>(map, key, { const_cast<VSFrame *>(frame), true }, append);
}
static int VS_CC mapConsumeFrame(VSMap *map, const char *key, const VSFrame *frame, int append) VS_NOEXCEPT {
if (frame == nullptr || frame->getFrameType() == mtVideo)
return !propSetShared<PVSFrame, ptVideoFrame>(map, key, {const_cast<VSFrame *>(frame), false}, append);
else
return !propSetShared<PVSFrame, ptAudioFrame>(map, key, {const_cast<VSFrame *>(frame), false}, append);
}
static VSMap *VS_CC invoke(VSPlugin *plugin, const char *name, const VSMap *args) VS_NOEXCEPT {
assert(plugin && name && args);
return plugin->invoke(name, *args);
}
static VSMap *VS_CC createMap() VS_NOEXCEPT {
return new VSMap();
}
static void VS_CC freeMap(VSMap *map) VS_NOEXCEPT {
delete map;
}
static void VS_CC clearMap(VSMap *map) VS_NOEXCEPT {
assert(map);
map->clear();
}
static void VS_CC copyMap(const VSMap *src, VSMap *dst) VS_NOEXCEPT {
assert(src && dst);
dst->copy(src);
}
static VSCore *VS_CC createCore(int flags) VS_NOEXCEPT {
return new VSCore(flags);
}
static VSCore *VS_CC createCore3(int threads) VS_NOEXCEPT {
VSCore *core = new VSCore(0);
if (core)
core->threadPool->setThreadCount(threads);
return core;
}
static void VS_CC freeCore(VSCore *core) VS_NOEXCEPT {
if (core)
core->freeCore();
}
static VSPlugin *VS_CC getPluginByID(const char *identifier, VSCore *core) VS_NOEXCEPT {
assert(identifier && core);
return core->getPluginByID(identifier);
}
static VSPlugin *VS_CC getPluginByNamespace(const char *ns, VSCore *core) VS_NOEXCEPT {
assert(ns && core);
return core->getPluginByNamespace(ns);
}
static VSPlugin *VS_CC getNextPlugin(VSPlugin *plugin, VSCore *core) VS_NOEXCEPT {
assert(core);
return core->getNextPlugin(plugin);
}
const char *VS_CC getPluginName(VSPlugin *plugin) VS_NOEXCEPT {
assert(plugin);
return plugin->getName().c_str();
}
const char *VS_CC getPluginID(VSPlugin *plugin) VS_NOEXCEPT {
assert(plugin);
return plugin->getID().c_str();
}
const char *VS_CC getPluginNamespace(VSPlugin *plugin) VS_NOEXCEPT {
assert(plugin);
return plugin->getNamespace().c_str();
}
static VSPluginFunction *VS_CC getNextPluginFunction(VSPluginFunction *func, VSPlugin *plugin) VS_NOEXCEPT {
assert(plugin);
return plugin->getNextFunction(func);
}
static VSPluginFunction *VS_CC getPluginFunctionByName(const char *name, VSPlugin *plugin) VS_NOEXCEPT {
assert(name && plugin);
return plugin->getFunctionByName(name);
}
static const char *VS_CC getPluginFunctionName(VSPluginFunction *func) VS_NOEXCEPT {
assert(func);
return func->getName().c_str();
}
static const char *VS_CC getPluginFunctionArguments(VSPluginFunction *func) VS_NOEXCEPT {
assert(func);
return func->getArguments().c_str();
}
static const char *VS_CC getPluginFunctionReturnType(VSPluginFunction *func) VS_NOEXCEPT {
assert(func);
return func->getReturnType().c_str();
}
static VSMap *VS_CC getPlugins3(VSCore *core) VS_NOEXCEPT {
assert(core);
return core->getPlugins3();
}
static VSMap *VS_CC getFunctions3(VSPlugin *plugin) VS_NOEXCEPT {
assert(plugin);
VSMap *m = new VSMap();
plugin->getFunctions3(m);
return m;
}
static const VSCoreInfo *VS_CC getCoreInfo3(VSCore *core) VS_NOEXCEPT {
assert(core);
return &core->getCoreInfo3();
}
static VSFunction *VS_CC mapGetFunction(const VSMap *map, const char *key, int index, int *error) VS_NOEXCEPT {
const VSArrayBase *arr = propGetShared(map, key, index, error, ptFunction);
if (arr) {
VSFunction *ref = reinterpret_cast<const VSFunctionArray *>(arr)->at(index).get();
ref->add_ref();
return ref;
} else {
return nullptr;
}
}
static int VS_CC mapSetFunction(VSMap *map, const char *key, VSFunction *func, int append) VS_NOEXCEPT {
return !propSetShared<PVSFunction, ptFunction>(map, key, { func, true }, append);
}
static int VS_CC mapConsumeFunction(VSMap *map, const char *key, VSFunction *func, int append) VS_NOEXCEPT {
return !propSetShared<PVSFunction, ptFunction>(map, key, {func, false}, append);
}
static void VS_CC callFunction(VSFunction *func, const VSMap *in, VSMap *out) VS_NOEXCEPT {
assert(func && in && out);
func->call(in, out);
}
static void VS_CC callFunction3(VSFunction *func, const VSMap *in, VSMap *out, VSCore *core, const vs3::VSAPI3 *vsapi) VS_NOEXCEPT {
assert(func && in && out);
func->call(in, out);
}
static VSFunction *VS_CC createFunction(VSPublicFunction func, void *userData, VSFreeFunctionData free, VSCore *core) VS_NOEXCEPT {
assert(func && core);
return new VSFunction(func, userData, free, core, VAPOURSYNTH_API_MAJOR);
}
static VSFunction *VS_CC createFunction3(vs3::VSPublicFunction func, void *userData, VSFreeFunctionData free, VSCore *core, const vs3::VSAPI3 *vsapi) VS_NOEXCEPT {
assert(func && core && vsapi);
return new VSFunction(reinterpret_cast<VSPublicFunction>(func), userData, free, core, VAPOURSYNTH3_API_MAJOR);
}
static void VS_CC freeFunction(VSFunction *f) VS_NOEXCEPT {
if (f)
f->release();
}
static void VS_CC queryCompletedFrame3(VSNode **node, int *n, VSFrameContext *frameCtx) VS_NOEXCEPT {
assert(node && n && frameCtx);
assert(false);
*node = nullptr;
*n = -1;
}
static void VS_CC releaseFrameEarly(VSNode *node, int n, VSFrameContext *frameCtx) VS_NOEXCEPT {
assert(node && frameCtx);
auto key = NodeOutputKey(node, n);
for (size_t i = 0; i < frameCtx->reqList.size(); i++) {
auto &tmp = frameCtx->availableFrames[i];
if (tmp.first == key) {
tmp.first = NodeOutputKey(nullptr, -1);
tmp.second.reset();
}
}
}
void VS_CC cacheFrame(const VSFrame *frame, int n, VSFrameContext *frameCtx) VS_NOEXCEPT {
assert(frame && n >= 0 && frameCtx);
frameCtx->key.first->cacheFrame(frame, n);
}
static VSFunction *VS_CC addFunctionRef(VSFunction *func) VS_NOEXCEPT {
assert(func);
func->add_ref();
return func;
}
static int64_t VS_CC setMaxCacheSize(int64_t bytes, VSCore *core) VS_NOEXCEPT {
assert(core);
return core->memory->set_limit(bytes);
}
static int VS_CC getOutputIndex(VSFrameContext *frameCtx) VS_NOEXCEPT {
assert(frameCtx);
assert(false);
return 0;
}
static void VS_CC setMessageHandler(VSLogHandler handler, void *userData) VS_NOEXCEPT {
vsSetMessageHandler3(handler, userData);
}
static int VS_CC setThreadCount(int threads, VSCore *core) VS_NOEXCEPT {
assert(core);
return static_cast<int>(core->threadPool->setThreadCount(threads));
}
static const char *VS_CC getPluginPath(const VSPlugin *plugin) VS_NOEXCEPT {
assert(plugin);
if (!plugin)
return nullptr;
if (!plugin->getFilename().empty())
return plugin->getFilename().c_str();
else
return nullptr;
}
static int VS_CC getPluginVersion(const VSPlugin *plugin) VS_NOEXCEPT {
assert(plugin);
if (!plugin)
return -1;
return plugin->getPluginVersion();
}
static const int64_t *VS_CC mapGetIntArray(const VSMap *map, const char *key, int *error) VS_NOEXCEPT {
const VSArrayBase *arr = propGetShared(map, key, 0, error, ptInt);
if (arr) {
return reinterpret_cast<const VSIntArray *>(arr)->getDataPointer();
} else {
return nullptr;
}
}
static const double *VS_CC mapGetFloatArray(const VSMap *map, const char *key, int *error) VS_NOEXCEPT {
const VSArrayBase *arr = propGetShared(map, key, 0, error, ptFloat);
if (arr) {
return reinterpret_cast<const VSFloatArray *>(arr)->getDataPointer();
} else {
return nullptr;
}
}
static int VS_CC mapSetIntArray(VSMap *map, const char *key, const int64_t *i, int size) VS_NOEXCEPT {
assert(map && key && size >= 0);
if (size < 0)
return 1;
if (!isValidVSMapKey(key))
return 1;
map->insert(key, new VSIntArray(i, size));
return 0;
}
static int VS_CC mapSetFloatArray(VSMap *map, const char *key, const double *d, int size) VS_NOEXCEPT {
assert(map && key && size >= 0);
if (size < 0)
return 1;
if (!isValidVSMapKey(key))
return 1;
map->insert(key, new VSFloatArray(d, size));
return 0;
}
static void VS_CC logMessage(int msgType, const char *msg, VSCore *core) VS_NOEXCEPT {
assert(msg && core);
core->logMessage(static_cast<VSMessageType>(msgType), msg);
}
static VSLogHandle *VS_CC addLogHandler(VSLogHandler handler, VSLogHandlerFree free, void *userData, VSCore *core) VS_NOEXCEPT {
assert(handler && core);
return core->addLogHandler(handler, free, userData);
}
static int VS_CC removeLogHandler(VSLogHandle *handle, VSCore *core) VS_NOEXCEPT {
assert(handle && core);
return core->removeLogHandler(reinterpret_cast<VSLogHandle *>(handle));
}
static void VS_CC logMessage3(int msgType, const char *msg) VS_NOEXCEPT {
vsLog3(static_cast<vs3::VSMessageType>(msgType), "%s", msg);
}
static int VS_CC addMessageHandler3(VSLogHandler handler, VSLogHandlerFree free, void *userData) VS_NOEXCEPT {
return vsAddMessageHandler3(handler, free, userData);
}
static int VS_CC removeMessageHandler3(int id) VS_NOEXCEPT {
return vsRemoveMessageHandler3(id);
}
static void VS_CC getCoreInfo2(VSCore *core, VSCoreInfo *info) VS_NOEXCEPT {
assert(core && info);
core->getCoreInfo(*info);
}
static void VS_CC createVideoFilter(VSMap *out, const char *name, const VSVideoInfo *vi, VSFilterGetFrame getFrame, VSFilterFree free, int filterMode, const VSFilterDependency *dependencies, int numDeps, void *instanceData, VSCore *core) VS_NOEXCEPT {
assert(out && name && vi && getFrame && core);
core->createVideoFilter(out, name, vi, getFrame, free, static_cast<VSFilterMode>(filterMode), dependencies, numDeps, instanceData, VAPOURSYNTH_API_MAJOR);
}
static VSNode *VS_CC createVideoFilter2(const char *name, const VSVideoInfo *vi, VSFilterGetFrame getFrame, VSFilterFree free, int filterMode, const VSFilterDependency *dependencies, int numDeps, void *instanceData, VSCore *core) VS_NOEXCEPT {
assert(name && vi && getFrame && core);
return core->createVideoFilter(name, vi, getFrame, free, static_cast<VSFilterMode>(filterMode), dependencies, numDeps, instanceData, VAPOURSYNTH_API_MAJOR);
}
static void VS_CC createAudioFilter(VSMap *out, const char *name, const VSAudioInfo *ai, VSFilterGetFrame getFrame, VSFilterFree free, int filterMode, const VSFilterDependency *dependencies, int numDeps, void *instanceData, VSCore *core) VS_NOEXCEPT {
assert(out && name && ai && getFrame && core);
core->createAudioFilter(out, name, ai, getFrame, free, static_cast<VSFilterMode>(filterMode), dependencies, numDeps, instanceData, VAPOURSYNTH_API_MAJOR);
}
static VSNode *VS_CC createAudioFilter2(const char *name, const VSAudioInfo *ai, VSFilterGetFrame getFrame, VSFilterFree free, int filterMode, const VSFilterDependency *dependencies, int numDeps, void *instanceData, VSCore *core) VS_NOEXCEPT {
assert(name && ai && getFrame && core);
return core->createAudioFilter(name, ai, getFrame, free, static_cast<VSFilterMode>(filterMode), dependencies, numDeps, instanceData, VAPOURSYNTH_API_MAJOR);
}
static int VS_CC setLinearFilter(VSNode *node) VS_NOEXCEPT {
return node->setLinear();
}
static VSFrame *VS_CC newAudioFrame(const VSAudioFormat *format, int numSamples, const VSFrame *propSrc, VSCore *core) VS_NOEXCEPT {
assert(format && core && numSamples > 0);
return new VSFrame(*format, numSamples, propSrc, core);
}
static VSFrame *VS_CC newAudioFrame2(const VSAudioFormat *format, int numSamples, const VSFrame **channelSrc, const int *channels, const VSFrame *propSrc, VSCore *core) VS_NOEXCEPT {
assert(format && core && numSamples > 0 && channelSrc && channels);
return new VSFrame(*format, numSamples, channelSrc, channels, propSrc, core);
}
static int VS_CC queryAudioFormat(VSAudioFormat *format, int sampleType, int bitsPerSample, uint64_t channelLayout, VSCore *core) VS_NOEXCEPT {
assert(format);
return core->queryAudioFormat(*format, static_cast<VSSampleType>(sampleType), bitsPerSample, channelLayout);
}
static int VS_CC queryVideoFormat(VSVideoFormat *format, int colorFamily, int sampleType, int bitsPerSample, int subSamplingW, int subSamplingH, VSCore *core) VS_NOEXCEPT {
assert(format);
return core->queryVideoFormat(*format, static_cast<VSColorFamily>(colorFamily), static_cast<VSSampleType>(sampleType), bitsPerSample, subSamplingW, subSamplingH);
}
static uint32_t VS_CC queryVideoFormatID(int colorFamily, int sampleType, int bitsPerSample, int subSamplingW, int subSamplingH, VSCore *core) VS_NOEXCEPT {
assert(core);
return core->queryVideoFormatID(static_cast<VSColorFamily>(colorFamily), static_cast<VSSampleType>(sampleType), bitsPerSample, subSamplingW, subSamplingH);
}
static int VS_CC getVideoFormatByID(VSVideoFormat *format, uint32_t id, VSCore *core) VS_NOEXCEPT {
assert(format && core);
return core->getVideoFormatByID(*format, id);
}
static int VS_CC getAudioFormatName(const VSAudioFormat *format, char *buffer) VS_NOEXCEPT {
assert(format && buffer);
return VSCore::getAudioFormatName(*format, buffer);
}
static int VS_CC getVideoFormatName(const VSVideoFormat *format, char *buffer) VS_NOEXCEPT {
assert(format && buffer);
return VSCore::getVideoFormatName(*format, buffer);
}
static const VSAudioInfo *VS_CC getAudioInfo(VSNode *node) VS_NOEXCEPT {
assert(node && node->getNodeType() == mtAudio);
return &node->getAudioInfo();
}
static const VSAudioFormat *VS_CC getAudioFrameFormat(const VSFrame *f) VS_NOEXCEPT {
return f->getAudioFormat();
}
static int VS_CC getNodeType(VSNode *node) VS_NOEXCEPT {
assert(node);
return node->getNodeType();
}
static void VS_CC setCacheMode(VSNode *node, int mode) VS_NOEXCEPT {
assert(node && mode >= cmAuto && mode <= cmForceEnable);
node->setCacheMode(mode);
}
static void VS_CC setCacheOptions(VSNode *node, int fixedSize, int maxSize, int maxHistorySize) VS_NOEXCEPT {
assert(node);
node->setCacheOptions(fixedSize, maxSize, maxHistorySize);
}
static int VS_CC getFrameType(const VSFrame *f) VS_NOEXCEPT {
assert(f);
return f->getFrameType();
}
static int VS_CC getFrameLength(const VSFrame *f) VS_NOEXCEPT {
assert(f);
return f->getFrameLength();
}
static int VS_CC getAPIVersion(void) VS_NOEXCEPT{
return VAPOURSYNTH_API_VERSION;
}
static const char *VS_CC getNodeCreationFunctionName(VSNode *node, int level) VS_NOEXCEPT {
assert(node);
return node->getCreationFunctionName(level);
}
static const VSMap *VS_CC getNodeCreationFunctionArguments(VSNode *node, int level) VS_NOEXCEPT {
assert(node);
return node->getCreationFunctionArguments(level);
}
static const char *VS_CC getNodeName(VSNode *node) VS_NOEXCEPT {
assert(node);
return node->getName().c_str();
}
static int VS_CC getNodeFilterMode(VSNode *node) VS_NOEXCEPT {
assert(node);
return node->getFilterMode();
}
static int64_t VS_CC getNodeProcessingTime(VSNode *node, int reset) VS_NOEXCEPT {
assert(node);
return node->getProcessingTime(!!reset);
}
static int64_t VS_CC getFreedNodeProcessingTime(VSCore *core, int reset) VS_NOEXCEPT {
assert(core);
return core->getFreedNodeProcessingTime(!!reset);
}
static int VS_CC getNumNodeDependencies(VSNode *node) VS_NOEXCEPT {
assert(node);
return static_cast<int>(node->getNumDependencies());
}
static const VSFilterDependency *VS_CC getNodeDependency(VSNode *node, int index) VS_NOEXCEPT {
return node->getDependency(index);
}
static void VS_CC clearNodeCache(VSNode *node) VS_NOEXCEPT {
assert(node);
node->clearCache();
}
static void VS_CC clearCoreCaches(VSCore *core) VS_NOEXCEPT {
assert(core);
core->clearCaches();
}
static int VS_CC getCoreNodeTiming(VSCore *core) VS_NOEXCEPT {
assert(core);
return core->getNodeTiming();
}
static void VS_CC setCoreNodeTiming(VSCore *core, int enable) VS_NOEXCEPT {
assert(core);
core->setNodeTiming(!!enable);
}
const VSPLUGINAPI vs_internal_vspapi {
&getAPIVersion,
&configPlugin,
®isterFunction
};
const VSAPI vs_internal_vsapi = {
&createVideoFilter,
&createVideoFilter2,
&createAudioFilter,
&createAudioFilter2,
&setLinearFilter,
&setCacheMode,
&setCacheOptions,
&freeNode,
&addNodeRef,
&getNodeType,
&getVideoInfo,
&getAudioInfo,
&newVideoFrame,
&newVideoFrame2,
&newAudioFrame,
&newAudioFrame2,
&freeFrame,
&addFrameRef,
©Frame,
&getFramePropertiesRO,
&getFramePropertiesRW,
&getStride,
&getReadPtr,
&getWritePtr,
&getVideoFrameFormat,
&getAudioFrameFormat,
&getFrameType,
&getFrameWidth,
&getFrameHeight,
&getFrameLength,
&getVideoFormatName,
&getAudioFormatName,
&queryVideoFormat,
&queryAudioFormat,
&queryVideoFormatID,
&getVideoFormatByID,
&getFrame,
&getFrameAsync,
&getFrameFilter,
&requestFrameFilter,
&releaseFrameEarly,
&cacheFrame,
&setFilterError,
&createFunction,
&freeFunction,
&addFunctionRef,
&callFunction,
&createMap,
&freeMap,
&clearMap,
©Map,
&mapSetError,
&mapGetError,
&mapNumKeys,
&mapGetKey,
&mapDeleteKey,
&mapNumElements,
&mapGetType,
&mapSetEmpty,
&mapGetInt,
&mapGetIntSaturated,
&mapGetIntArray,
&mapSetInt,
&mapSetIntArray,
&mapGetFloat,
&mapGetFloatSaturated,
&mapGetFloatArray,
&mapSetFloat,
&mapSetFloatArray,
&mapGetData,
&mapGetDataSize,
&mapGetDataTypeHint,
&mapSetData,
&mapGetNode,
&mapSetNode,
&mapConsumeNode,
&mapGetFrame,
&mapSetFrame,
&mapConsumeFrame,
&mapGetFunction,
&mapSetFunction,
&mapConsumeFunction,
®isterFunction,
&getPluginByID,
&getPluginByNamespace,
&getNextPlugin,
&getPluginName,
&getPluginID,
&getPluginNamespace,
&getNextPluginFunction,
&getPluginFunctionByName,
&getPluginFunctionName,
&getPluginFunctionArguments,
&getPluginFunctionReturnType,
&getPluginPath,
&getPluginVersion,
&invoke,
&createCore,
&freeCore,
&setMaxCacheSize,
&setThreadCount,
&getCoreInfo2,
&getAPIVersion,
&logMessage,
&addLogHandler,
&removeLogHandler,
&clearNodeCache,
&clearCoreCaches,
&getNodeName,
&getNodeFilterMode,
&getNumNodeDependencies,
&getNodeDependency,
&getCoreNodeTiming,
&setCoreNodeTiming,
&getNodeProcessingTime,
&getFreedNodeProcessingTime,
&getNodeCreationFunctionName,
&getNodeCreationFunctionArguments
};
const vs3::VSAPI3 vs_internal_vsapi3 = {
&createCore3,
&freeCore,
&getCoreInfo3,
&addFrameRef,
&addNodeRef,
&addFunctionRef,
&freeFrame,
&freeNode,
&freeFunction,
&newVideoFrame3,
©Frame,
©FrameProps3,
®isterFunction3,
&getPluginByID,
&getPluginByNamespace,
&getPlugins3,
&getFunctions3,
&createFilter3,
&mapSetError,
&mapGetError,
&setFilterError,
&invoke,
&getFormatPreset3,
®isterFormat3,
&getFrame,
&getFrameAsync,
&getFrameFilter,
&requestFrameFilter,
&queryCompletedFrame3,
&releaseFrameEarly,
&getStride3,
&getReadPtr,
&getWritePtr,
&createFunction3,
&callFunction3,
&createMap,
&freeMap,
&clearMap,
&getVideoInfo3,
&setVideoInfo3,
&getFrameFormat3,
&getFrameWidth,
&getFrameHeight,
&getFramePropertiesRO,
&getFramePropertiesRW,
&mapNumKeys,
&mapGetKey,
&mapNumElements,
&propGetType3,
&mapGetInt,
&mapGetFloat,
&mapGetData,
&mapGetDataSize,
&mapGetNode,
&mapGetFrame,
&mapGetFunction,
&mapDeleteKey,
&mapSetInt,
&mapSetFloat,
&propSetData3,
&mapSetNode,
&mapSetFrame,
&mapSetFunction,
&setMaxCacheSize,
&getOutputIndex,
&newVideoFrame23,
&setMessageHandler,
&setThreadCount,
&getPluginPath,
&mapGetIntArray,
&mapGetFloatArray,
&mapSetIntArray,
&mapSetFloatArray,
&logMessage3,
&addMessageHandler3,
&removeMessageHandler3,
&getCoreInfo2
};
const VSAPI *getVSAPIInternal(int apiMajor) {
if (apiMajor == VAPOURSYNTH_API_MAJOR) {
return &vs_internal_vsapi;
} else if (apiMajor == VAPOURSYNTH3_API_MAJOR) {
return reinterpret_cast<const VSAPI *>(&vs_internal_vsapi3);
} else {
assert(false);
return nullptr;
}
}
const VSAPI *VS_CC getVapourSynthAPI(int version) VS_NOEXCEPT {
int apiMajor = version;
int apiMinor = 0;
if (apiMajor >= 0x10000) {
apiMinor = (apiMajor & 0xFFFF);
apiMajor >>= 16;
}
if (!getCPUFeatures()->can_run_vs) {
return nullptr;
} else if (apiMajor == VAPOURSYNTH_API_MAJOR && apiMinor <= VAPOURSYNTH_API_MINOR) {
return &vs_internal_vsapi;
} else if (apiMajor == VAPOURSYNTH3_API_MAJOR && apiMinor <= VAPOURSYNTH3_API_MINOR) {
return reinterpret_cast<const VSAPI *>(&vs_internal_vsapi3);
} else {
return nullptr;
}
}