1 /*
2 * Copyright (c) 2012-2017 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 #ifndef VSCORE_H
22 #define VSCORE_H
23 
24 #include "VapourSynth.h"
25 #include "vslog.h"
26 #include <cstdlib>
27 #include <stdexcept>
28 #include <string>
29 #include <cstring>
30 #include <cassert>
31 #include <vector>
32 #include <list>
33 #include <set>
34 #include <map>
35 #include <memory>
36 #include <atomic>
37 #include <mutex>
38 #include <thread>
39 #include <condition_variable>
40 #include <random>
41 #include <algorithm>
42 #ifdef VS_TARGET_OS_WINDOWS
43 #    define WIN32_LEAN_AND_MEAN
44 #    ifndef NOMINMAX
45 #        define NOMINMAX
46 #    endif
47 #    include <windows.h>
48 #    define VS_FRAME_POOL
49 #else
50 #    include <dlfcn.h>
51 #endif
52 
53 #ifdef VS_FRAME_GUARD
54 static const uint32_t VS_FRAME_GUARD_PATTERN = 0xDEADBEEF;
55 #endif
56 
57 // Internal only filter mode for use by caches to make requests more linear
58 const int fmUnorderedLinear = fmUnordered + 13;
59 
60 class VSFrame;
61 struct VSCore;
62 class VSCache;
63 struct VSNode;
64 class VSThreadPool;
65 class FrameContext;
66 class ExtFunction;
67 
68 typedef std::shared_ptr<VSFrame> PVideoFrame;
69 typedef std::weak_ptr<VSFrame> WVideoFrame;
70 typedef std::shared_ptr<VSNode> PVideoNode;
71 typedef std::shared_ptr<ExtFunction> PExtFunction;
72 typedef std::shared_ptr<FrameContext> PFrameContext;
73 
74 extern const VSAPI vs_internal_vsapi;
75 const VSAPI *getVSAPIInternal(int apiMajor);
76 
77 class VSException : public std::runtime_error {
78 public:
79     using std::runtime_error::runtime_error;
80 };
81 
82 class NodeOutputKey {
83 private:
84     VSNode *node;
85     int n;
86     int index;
87 public:
NodeOutputKey(VSNode * node,int n,int index)88     NodeOutputKey(VSNode *node, int n, int index) : node(node), n(n), index(index) {}
89     inline bool operator==(const NodeOutputKey &v) const {
90         return node == v.node && n == v.n && index == v.index;
91     }
92     inline bool operator<(const NodeOutputKey &v) const {
93         return (node < v.node) || (node == v.node && n < v.n) || (node == v.node && n == v.n && index < v.index);
94     }
95 };
96 
97 // variant types
98 typedef std::shared_ptr<std::string> VSMapData;
99 typedef std::vector<int64_t> IntList;
100 typedef std::vector<double> FloatList;
101 typedef std::vector<VSMapData> DataList;
102 typedef std::vector<VSNodeRef> NodeList;
103 typedef std::vector<PVideoFrame> FrameList;
104 typedef std::vector<PExtFunction> FuncList;
105 
106 class ExtFunction {
107 private:
108     VSPublicFunction func;
109     void *userData;
110     VSFreeFuncData free;
111     VSCore *core;
112     const VSAPI *vsapi;
113 public:
114     ExtFunction(VSPublicFunction func, void *userData, VSFreeFuncData free, VSCore *core, const VSAPI *vsapi);
115     ~ExtFunction();
116     void call(const VSMap *in, VSMap *out);
117 };
118 
119 class VSVariant {
120 public:
121     enum VSVType { vUnset, vInt, vFloat, vData, vNode, vFrame, vMethod };
122     VSVariant(VSVType vtype = vUnset);
123     VSVariant(const VSVariant &v);
124     VSVariant(VSVariant &&v);
125     ~VSVariant();
126 
127     size_t size() const;
128     VSVType getType() const;
129 
130     void append(int64_t val);
131     void append(double val);
132     void append(const std::string &val);
133     void append(const VSNodeRef &val);
134     void append(const PVideoFrame &val);
135     void append(const PExtFunction &val);
136 
137     template<typename T>
getValue(size_t index)138     const T &getValue(size_t index) const {
139         return reinterpret_cast<std::vector<T>*>(storage)->at(index);
140     }
141 
142     template<typename T>
getArray()143     const T *getArray() const {
144         return reinterpret_cast<std::vector<T>*>(storage)->data();
145     }
146 
147     template<typename T>
setArray(const T * val,size_t size)148     void setArray(const T *val, size_t size) {
149         assert(val && !storage);
150         std::vector<T> *vect = new std::vector<T>(size);
151         if (size)
152             memcpy(vect->data(), val, size * sizeof(T));
153         internalSize = size;
154         storage = vect;
155     }
156 
157 private:
158     VSVType vtype;
159     size_t internalSize;
160     void *storage;
161 
162     void initStorage(VSVType t);
163 };
164 
165 class VSMapStorage {
166 private:
167     std::atomic<int> refCount;
168 public:
169     std::map<std::string, VSVariant> data;
170     bool error;
171 
VSMapStorage()172     VSMapStorage() : refCount(1), error(false) {}
173 
VSMapStorage(const VSMapStorage & s)174     VSMapStorage(const VSMapStorage &s) : refCount(1), data(s.data), error(s.error) {}
175 
unique()176     bool unique() {
177         return (refCount == 1);
178     };
179 
addRef()180     void addRef() {
181         ++refCount;
182     }
183 
release()184     void release() {
185         if (!--refCount)
186             delete this;
187     }
188 };
189 
190 struct VSMap {
191 private:
192     VSMapStorage *data;
193 public:
VSMapVSMap194     VSMap() : data(new VSMapStorage()) {}
195 
VSMapVSMap196     VSMap(const VSMap &map) : data(map.data) {
197         data->addRef();
198     }
199 
VSMapVSMap200     VSMap(VSMap &&map) : data(map.data) {
201         map.data = new VSMapStorage();
202     }
203 
~VSMapVSMap204     ~VSMap() {
205         data->release();
206     }
207 
208     VSMap &operator=(const VSMap &map) {
209         data->release();
210         data = map.data;
211         data->addRef();
212         return *this;
213     }
214 
detachVSMap215     void detach() {
216         if (!data->unique()) {
217             VSMapStorage *old = data;
218             data = new VSMapStorage(*data);
219             old->release();
220         }
221     }
222 
containsVSMap223     bool contains(const std::string &key) const {
224         return !!data->data.count(key);
225     }
226 
atVSMap227     VSVariant &at(const std::string &key) const {
228         return data->data.at(key);
229     }
230 
231     VSVariant &operator[](const std::string &key) const {
232         // implicit creation is unwanted so make sure it doesn't happen by wrapping at() instead
233         return data->data.at(key);
234     }
235 
findVSMap236     VSVariant *find(const std::string &key) const {
237         auto it = data->data.find(key);
238         return it == data->data.end() ? nullptr : &it->second;
239     }
240 
eraseVSMap241     bool erase(const std::string &key) {
242         detach();
243         return data->data.erase(key) > 0;
244     }
245 
insertVSMap246     bool insert(const std::string &key, VSVariant &&v) {
247         detach();
248         data->data.erase(key);
249         data->data.insert(std::make_pair(key, v));
250         return true;
251     }
252 
sizeVSMap253     size_t size() const {
254         return data->data.size();
255     }
256 
clearVSMap257     void clear() {
258         data->release();
259         data = new VSMapStorage();
260     }
261 
keyVSMap262     const char *key(int n) const {
263         if (n >= static_cast<int>(size()))
264             return nullptr;
265         auto iter = data->data.cbegin();
266         std::advance(iter, n);
267         return iter->first.c_str();
268     }
269 
getStorageVSMap270     const std::map<std::string, VSVariant> &getStorage() const {
271         return data->data;
272     }
273 
setErrorVSMap274     void setError(const std::string &errMsg) {
275         clear();
276         VSVariant v(VSVariant::vData);
277         v.append(errMsg);
278         insert("_Error", std::move(v));
279         data->error = true;
280     }
281 
hasErrorVSMap282     bool hasError() const {
283         return data->error;
284     }
285 
getErrorMessageVSMap286     const std::string &getErrorMessage() const {
287         return *((*this)["_Error"].getValue<VSMapData>(0).get());
288     }
289 };
290 
291 
292 
293 struct VSFrameRef {
294     PVideoFrame frame;
VSFrameRefVSFrameRef295     VSFrameRef(const PVideoFrame &frame) : frame(frame) {}
VSFrameRefVSFrameRef296     VSFrameRef(PVideoFrame &&frame) : frame(frame) {}
297 };
298 
299 struct VSNodeRef {
300     PVideoNode clip;
301     int index;
VSNodeRefVSNodeRef302     VSNodeRef(const PVideoNode &clip, int index) : clip(clip), index(index) {}
VSNodeRefVSNodeRef303     VSNodeRef(PVideoNode &&clip, int index) : clip(clip), index(index) {}
304 };
305 
306 struct VSFuncRef {
307     PExtFunction func;
VSFuncRefVSFuncRef308     VSFuncRef(const PExtFunction &func) : func(func) {}
VSFuncRefVSFuncRef309     VSFuncRef(PExtFunction &&func) : func(func) {}
310 };
311 
312 enum FilterArgumentType {
313     faNone = -1,
314     faInt = 0,
315     faFloat,
316     faData,
317     faClip,
318     faFrame,
319     faFunc
320 };
321 
322 class FilterArgument {
323 public:
324     std::string name;
325     FilterArgumentType type;
326     bool arr;
327     bool empty;
328     bool opt;
FilterArgument(const std::string & name,FilterArgumentType type,bool arr,bool empty,bool opt)329     FilterArgument(const std::string &name, FilterArgumentType type, bool arr, bool empty, bool opt)
330         : name(name), type(type), arr(arr), empty(empty), opt(opt) {}
331 };
332 
333 class MemoryUse {
334 private:
335     struct BlockHeader {
336         size_t size; // Size of memory allocation, minus header and padding.
337         bool large : 1; // Memory is allocated with large pages.
338     };
339     static_assert(sizeof(BlockHeader) <= 16, "block header too large");
340 
341     std::atomic<size_t> used;
342     size_t maxMemoryUse;
343     bool freeOnZero;
344     bool largePageEnabled;
345     bool memoryWarningIssued;
346     std::multimap<size_t, uint8_t *> buffers;
347     size_t unusedBufferSize;
348     std::minstd_rand generator;
349     std::mutex mutex;
350 
351     static bool largePageSupported();
352     static size_t largePageSize();
353 
354     // May allocate more than the requested amount.
355     void *allocateLargePage(size_t bytes) const;
356     void freeLargePage(void *ptr) const;
357     void *allocateMemory(size_t bytes) const;
358     void freeMemory(void *ptr) const;
359     bool isGoodFit(size_t requested, size_t actual) const;
360 public:
361     void add(size_t bytes);
362     void subtract(size_t bytes);
363     uint8_t *allocBuffer(size_t bytes);
364     void freeBuffer(uint8_t *buf);
365     size_t memoryUse();
366     size_t getLimit();
367     int64_t setMaxMemoryUse(int64_t bytes);
368     bool isOverLimit();
369     void signalFree();
370     MemoryUse();
371     ~MemoryUse();
372 };
373 
374 class VSPlaneData {
375 private:
376     std::atomic<int> refCount;
377     MemoryUse &mem;
378 public:
379     uint8_t *data;
380     const size_t size;
381     VSPlaneData(size_t dataSize, MemoryUse &mem);
382     VSPlaneData(const VSPlaneData &d);
383     ~VSPlaneData();
384     bool unique();
385     void addRef();
386     void release();
387 };
388 
389 class VSFrame {
390 private:
391     const VSFormat *format;
392     VSPlaneData *data[3];
393     int width;
394     int height;
395     int stride[3];
396     VSMap properties;
397 public:
398     static int alignment;
399 
400 #ifdef VS_FRAME_GUARD
401     static const int guardSpace = 64;
402 #else
403     static const int guardSpace = 0;
404 #endif
405 
406     VSFrame(const VSFormat *f, int width, int height, const VSFrame *propSrc, VSCore *core);
407     VSFrame(const VSFormat *f, int width, int height, const VSFrame * const *planeSrc, const int *plane, const VSFrame *propSrc, VSCore *core);
408     VSFrame(const VSFrame &f);
409     ~VSFrame();
410 
getProperties()411     VSMap &getProperties() {
412         return properties;
413     }
getConstProperties()414     const VSMap &getConstProperties() const {
415         return properties;
416     }
setProperties(const VSMap & properties)417     void setProperties(const VSMap &properties) {
418         this->properties = properties;
419     }
getFormat()420     const VSFormat *getFormat() const {
421         return format;
422     }
getWidth(int plane)423     int getWidth(int plane) const {
424         return width >> (plane ? format->subSamplingW : 0);
425     }
getHeight(int plane)426     int getHeight(int plane) const {
427         return height >> (plane ? format->subSamplingH : 0);
428     }
429     int getStride(int plane) const;
430     const uint8_t *getReadPtr(int plane) const;
431     uint8_t *getWritePtr(int plane);
432 
433 #ifdef VS_FRAME_GUARD
434     bool verifyGuardPattern();
435 #endif
436 };
437 
438 class FrameContext {
439     friend class VSThreadPool;
440 private:
441     uintptr_t reqOrder;
442     unsigned numFrameRequests;
443     int n;
444     VSNode *clip;
445     PVideoFrame returnedFrame;
446     PFrameContext upstreamContext;
447     PFrameContext notificationChain;
448     void *userData;
449     VSFrameDoneCallback frameDone;
450     std::string errorMessage;
451     bool error;
452     bool lockOnOutput;
453 public:
454     VSNodeRef *node;
455     std::map<NodeOutputKey, PVideoFrame> availableFrames;
456     int lastCompletedN;
457     int index;
458     VSNodeRef *lastCompletedNode;
459 
460     void *frameContext;
461     bool setError(const std::string &errorMsg);
hasError()462     inline bool hasError() const {
463         return error;
464     }
getErrorMessage()465     const std::string &getErrorMessage() {
466         return errorMessage;
467     }
468     FrameContext(int n, int index, VSNode *clip, const PFrameContext &upstreamContext);
469     FrameContext(int n, int index, VSNodeRef *node, VSFrameDoneCallback frameDone, void *userData, bool lockOnOutput = true);
470 };
471 
472 struct VSNode {
473     friend class VSThreadPool;
474     friend struct VSCore;
475 private:
476     void *instanceData;
477     std::string name;
478     VSFilterInit init;
479     VSFilterGetFrame filterGetFrame;
480     VSFilterFree free;
481     VSFilterMode filterMode;
482 
483     int apiMajor;
484     VSCore *core;
485     int flags;
486     bool hasVi;
487     std::vector<VSVideoInfo> vi;
488 
489     // for keeping track of when a filter is busy in the exclusive section and with which frame
490     // used for fmSerial and fmParallel (mutex only)
491     std::mutex serialMutex;
492     int serialFrame;
493     // to prevent multiple calls at the same time for the same frame
494     // this is used exclusively by fmParallel
495     // fmParallelRequests use this in combination with serialMutex to signal when all its frames are ready
496     std::mutex concurrentFramesMutex;
497     std::set<int> concurrentFrames;
498 
499     PVideoFrame getFrameInternal(int n, int activationReason, VSFrameContext &frameCtx);
500 public:
501     VSNode(const VSMap *in, VSMap *out, const std::string &name, VSFilterInit init, VSFilterGetFrame getFrame, VSFilterFree free, VSFilterMode filterMode, int flags, void *instanceData, int apiMajor, VSCore *core);
502 
503     ~VSNode();
504 
isRightCoreVSNode505     bool isRightCore(const VSCore *core2) const {
506         return core == core2;
507     }
508 
509     void getFrame(const PFrameContext &ct);
510 
511     const VSVideoInfo &getVideoInfo(int index);
512 
513     void setVideoInfo(const VSVideoInfo *vi, int numOutputs);
514 
getNumOutputsVSNode515     size_t getNumOutputs() const {
516         return vi.size();
517     }
518 
getNameVSNode519     const std::string &getName() const {
520         return name;
521     }
522 
523     // to get around encapsulation a bit, more elegant than making everything friends in this case
524     void reserveThread();
525     void releaseThread();
526     bool isWorkerThread();
527 
528     void notifyCache(bool needMemory);
529 };
530 
531 struct VSFrameContext {
532     PFrameContext &ctx;
533     std::vector<PFrameContext> reqList;
VSFrameContextVSFrameContext534     VSFrameContext(PFrameContext &ctx) : ctx(ctx) {}
535 };
536 
537 class VSThreadPool {
538     friend struct VSCore;
539 private:
540     VSCore *core;
541     std::mutex lock;
542     std::mutex callbackLock;
543     std::map<std::thread::id, std::thread *> allThreads;
544     std::list<PFrameContext> tasks;
545     std::map<NodeOutputKey, PFrameContext> allContexts;
546     std::condition_variable newWork;
547     std::condition_variable allIdle;
548     std::atomic<unsigned> activeThreads;
549     std::atomic<unsigned> idleThreads;
550     std::atomic<uintptr_t> reqCounter;
551     unsigned maxThreads;
552     std::atomic<bool> stopThreads;
553     std::atomic<unsigned> ticks;
554     int getNumAvailableThreads();
555     void wakeThread();
556     void notifyCaches(bool needMemory);
557     void startInternal(const PFrameContext &context);
558     void spawnThread();
559     static void runTasks(VSThreadPool *owner, std::atomic<bool> &stop);
560     static bool taskCmp(const PFrameContext &a, const PFrameContext &b);
561 public:
562     VSThreadPool(VSCore *core, int threads);
563     ~VSThreadPool();
564     void returnFrame(const PFrameContext &rCtx, const PVideoFrame &f);
565     void returnFrame(const PFrameContext &rCtx, const std::string &errMsg);
566     int threadCount();
567     int setThreadCount(int threads);
568     void start(const PFrameContext &context);
569     void releaseThread();
570     void reserveThread();
571     bool isWorkerThread();
572     void waitForDone();
573 };
574 
575 class VSFunction {
576 public:
577     std::vector<FilterArgument> args;
578     std::string argString;
579     void *functionData;
580     VSPublicFunction func;
581     VSFunction(const std::string &argString, VSPublicFunction func, void *functionData);
VSFunction()582     VSFunction() : functionData(nullptr), func(nullptr) {}
583 };
584 
585 
586 struct VSPlugin {
587 private:
588     int apiMajor;
589     int apiMinor;
590     bool hasConfig;
591     bool readOnly;
592     bool readOnlySet;
593     bool compat;
594 #ifdef VS_TARGET_OS_WINDOWS
595     HMODULE libHandle;
596 #else
597     void *libHandle;
598 #endif
599     std::map<std::string, VSFunction> funcs;
600     std::mutex registerFunctionLock;
601     VSCore *core;
602 public:
603     std::string filename;
604     std::string fullname;
605     std::string fnamespace;
606     std::string id;
607     explicit VSPlugin(VSCore *core);
608     VSPlugin(const std::string &relFilename, const std::string &forcedNamespace, const std::string &forcedId, bool altSearchPath, VSCore *core);
609     ~VSPlugin();
lockVSPlugin610     void lock() {
611         readOnly = true;
612     };
enableCompatVSPlugin613     void enableCompat() {
614         compat = true;
615     }
616     void configPlugin(const std::string &identifier, const std::string &defaultNamespace, const std::string &fullname, int apiVersion, bool readOnly);
617     void registerFunction(const std::string &name, const std::string &args, VSPublicFunction argsFunc, void *functionData);
618     VSMap invoke(const std::string &funcName, const VSMap &args);
619     VSMap getFunctions();
620 };
621 
622 struct VSCore {
623     friend class VSFrame;
624     friend class VSThreadPool;
625     friend class CacheInstance;
626 private:
627     //number of filter instances plus one, freeing the core reduces it by one
628     // the core will be freed once it reaches 0
629     bool coreFreed;
630     std::atomic_int numFilterInstances;
631     std::atomic_int numFunctionInstances;
632 
633     std::map<std::string, VSPlugin *> plugins;
634     std::recursive_mutex pluginLock;
635     std::map<int, VSFormat *> formats;
636     std::mutex formatLock;
637     int formatIdOffset;
638     VSCoreInfo coreInfo;
639     std::set<VSNode *> caches;
640     std::mutex cacheLock;
641 
642     std::atomic_int cpuLevel;
643 
644     ~VSCore();
645 
646     void registerFormats();
647 #ifdef VS_TARGET_OS_WINDOWS
648     bool loadAllPluginsInPath(const std::wstring &path, const std::wstring &filter);
649 #else
650     bool loadAllPluginsInPath(const std::string &path, const std::string &filter);
651 #endif
652 public:
653     VSThreadPool *threadPool;
654     MemoryUse *memory;
655 
656     PVideoFrame newVideoFrame(const VSFormat *f, int width, int height, const VSFrame *propSrc);
657     PVideoFrame newVideoFrame(const VSFormat *f, int width, int height, const VSFrame * const *planeSrc, const int *planes, const VSFrame *propSrc);
658     PVideoFrame copyFrame(const PVideoFrame &srcf);
659     void copyFrameProps(const PVideoFrame &src, PVideoFrame &dst);
660 
661     const VSFormat *getFormatPreset(int id);
662     const VSFormat *registerFormat(VSColorFamily colorFamily, VSSampleType sampleType, int bitsPerSample, int subSamplingW, int subSamplingH, const char *name = nullptr, int id = pfNone);
663     bool isValidFormatPointer(const VSFormat *f);
664 
665     void loadPlugin(const std::string &filename, const std::string &forcedNamespace = std::string(), const std::string &forcedId = std::string(), bool altSearchPath = false);
666     void createFilter(const VSMap *in, VSMap *out, const std::string &name, VSFilterInit init, VSFilterGetFrame getFrame, VSFilterFree free, VSFilterMode filterMode, int flags, void *instanceData, int apiMajor);
667 
668     int getCpuLevel() const;
669     int setCpuLevel(int cpu);
670 
671     VSMap getPlugins();
672     VSPlugin *getPluginById(const std::string &identifier);
673     VSPlugin *getPluginByNs(const std::string &ns);
674 
675     const VSCoreInfo &getCoreInfo();
676     void getCoreInfo2(VSCoreInfo &info);
677 
678     void functionInstanceCreated();
679     void functionInstanceDestroyed();
680     void filterInstanceCreated();
681     void filterInstanceDestroyed();
682     void destroyFilterInstance(VSNode *node);
683 
684     explicit VSCore(int threads);
685     void freeCore();
686 };
687 
688 #endif // VSCORE_H
689