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
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
) {
42 return new VSFrameRef(frame
->frame
);
45 static const VSNodeRef
*VS_CC
cloneNodeRef(const VSNodeRef
*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
{
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
);
80 memset(g
->errorMsg
, 0, g
->bufSize
);
82 strncpy(g
->errorMsg
, errorMsg
, g
->bufSize
- 1);
86 static const VSFrameRef
*VS_CC
getFrame(int n
, const VSNodeRef
*clip
, char *errorMsg
, int bufSize
) {
87 GetFrameWaiter
g(errorMsg
, bufSize
);
89 getFrameAsync(n
, clip
, &frameWaiterCallback
, &g
);
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
));
105 return new VSFrameRef(g
);
110 static void VS_CC
freeFrame(const VSFrameRef
*frame
) {
114 static void VS_CC
freeNode(const VSNodeRef
*clip
) {
118 static VSFrameRef
*VS_CC
newVideoFrame(const VSFormat
*f
, int width
, int height
, const VSFrameRef
*propSrc
, VSCore
*core
) {
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
) {
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();
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
))
198 const VSVariant
&val
= (*props
)[name
];
202 static char VS_CC
propGetType(const VSMap
*props
, const char *name
) {
203 if (!props
->contains(name
))
206 const char a
[] = { 'u', 'i', 'f', 's', 'c', 'v', 'm'};
207 const VSVariant
&val
= (*props
)[name
];
211 static int getPropErrorCheck(const VSMap
*props
, const char *name
, int index
, int *error
, int type
) {
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
))
220 if (!err
&& props
->value(name
).vtype
!= type
)
223 int c
= propNumElements(props
, name
);
225 if (!err
&& c
<= index
|| index
< 0)
229 qFatal(QByteArray("Property read unsuccessful but no error output: ") + name
);
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
);
243 const VSVariant
&l
= (*props
)[name
];
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
);
253 const VSVariant
&l
= (*props
)[name
];
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
);
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
);
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
);
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
);
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
) {
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
)
318 else if (append
== paAppend
)
321 VSVariant
l(VSVariant::vInt
);
322 if (append
== paAppend
)
324 props
->insert(name
, l
);
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
)
337 else if (append
== paAppend
)
340 VSVariant
l(VSVariant::vFloat
);
341 if (append
== paAppend
)
343 props
->insert(name
, l
);
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
)
356 else if (append
== paAppend
)
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
);
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
)
375 else if (append
== paAppend
)
376 l
.c
.append(clip
->clip
);
378 VSVariant
l(VSVariant::vNode
);
379 if (append
== paAppend
)
380 l
.c
.append(clip
->clip
);
381 props
->insert(name
, l
);
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
)
394 else if (append
== paAppend
)
395 l
.v
.append(frame
->frame
);
397 VSVariant
l(VSVariant::vFrame
);
398 if (append
== paAppend
)
399 l
.v
.append(frame
->frame
);
400 props
->insert(name
, l
);
406 static VSMap
*VS_CC
invoke(VSPlugin
*plugin
, const char *name
, const VSMap
*args
) {
408 return new VSMap(plugin
->invoke(name
, *args
));
411 static VSMap
*VS_CC
newMap() {
415 static void VS_CC
freeMap(VSMap
*map
) {
419 static void VS_CC
clearMap(VSMap
*map
) {
423 static VSCore
*VS_CC
createCore(int *threads
) {
424 return new VSCore(*threads
);
427 static void VS_CC
freeCore(VSCore
*core
) {
431 const VSAPI
*VS_CC
getVapourSynthAPI(int version
) {
432 if (version
== VAPOURSYNTH_API_VERSION
)
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() {
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
);
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
) {
474 if (props
->contains(name
)) {
475 VSVariant
&l
= (*props
)[name
];
477 if (l
.vtype
!= VSVariant::vMethod
)
480 l
.m
.append(func
->func
);
482 VSVariant
l(VSVariant::vMethod
);
483 l
.m
.append(func
->func
);
484 props
->insert(name
, l
);
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
) {
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
= {
549 &queryCompletedFrame
,