1 /* 2 * Copyright (c) 2012-2016 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 CACHEFILTER_H 22 #define CACHEFILTER_H 23 24 #include "vscore.h" 25 #include <unordered_map> 26 #include <cassert> 27 28 class VSCache { 29 private: 30 struct Node { NodeNode31 inline Node() : key(-1) {} NodeNode32 inline Node(int key, const PVideoFrame &frame) : key(key), frame(frame), weakFrame(frame), prevNode(0), nextNode(0) {} 33 int key; 34 PVideoFrame frame; 35 WVideoFrame weakFrame; 36 Node *prevNode; 37 Node *nextNode; 38 }; 39 40 Node *first; 41 Node *weakpoint; 42 Node *last; 43 44 std::unordered_map<int, Node> hash; 45 46 int maxSize; 47 int currentSize; 48 int maxHistorySize; 49 int historySize; 50 51 bool fixedSize; 52 53 int hits; 54 int nearMiss; 55 int farMiss; 56 unlink(Node & n)57 inline void unlink(Node &n) { 58 if (&n == weakpoint) 59 weakpoint = weakpoint->nextNode; 60 61 if (n.prevNode) 62 n.prevNode->nextNode = n.nextNode; 63 64 if (n.nextNode) 65 n.nextNode->prevNode = n.prevNode; 66 67 if (last == &n) 68 last = n.prevNode; 69 70 if (first == &n) 71 first = n.nextNode; 72 73 if (n.frame) 74 currentSize--; 75 else 76 historySize--; 77 78 hash.erase(n.key); 79 } 80 relink(const int key)81 inline PVideoFrame relink(const int key) { 82 auto i = hash.find(key); 83 84 if (i == hash.end()) { 85 farMiss++; 86 return PVideoFrame(); 87 } 88 89 Node &n = i->second; 90 91 if (!n.frame) { 92 nearMiss++; 93 try { 94 n.frame = PVideoFrame(n.weakFrame); 95 } catch (std::bad_weak_ptr &) { 96 return PVideoFrame(); 97 } 98 99 currentSize++; 100 historySize--; 101 } 102 103 hits++; 104 Node *origWeakPoint = weakpoint; 105 106 if (&n == origWeakPoint) 107 weakpoint = weakpoint->nextNode; 108 109 if (first != &n) { 110 if (n.prevNode) 111 n.prevNode->nextNode = n.nextNode; 112 113 if (n.nextNode) 114 n.nextNode->prevNode = n.prevNode; 115 116 if (last == &n) 117 last = n.prevNode; 118 119 n.prevNode = 0; 120 n.nextNode = first; 121 first->prevNode = &n; 122 first = &n; 123 } 124 125 if (!weakpoint) { 126 if (currentSize > maxSize) { 127 weakpoint = last; 128 weakpoint->frame.reset(); 129 } 130 } else if (&n == origWeakPoint || historySize > maxHistorySize) { 131 weakpoint = weakpoint->prevNode; 132 weakpoint->frame.reset(); 133 } 134 135 assert(historySize <= maxHistorySize); 136 137 return n.frame; 138 } 139 140 public: 141 enum CacheAction { 142 caGrow, 143 caNoChange, 144 caShrink, 145 caClear 146 }; 147 148 VSCache(int maxSize, int maxHistorySize, bool fixedSize); ~VSCache()149 ~VSCache() { 150 clear(); 151 } 152 getMaxFrames()153 inline int getMaxFrames() const { 154 return maxSize; 155 } setMaxFrames(int m)156 inline void setMaxFrames(int m) { 157 maxSize = m; 158 trim(maxSize, maxHistorySize); 159 } getMaxHistory()160 inline int getMaxHistory() const { 161 return maxHistorySize; 162 } setMaxHistory(int m)163 inline void setMaxHistory(int m) { 164 maxHistorySize = m; 165 trim(maxSize, maxHistorySize); 166 } 167 size()168 inline size_t size() const { 169 return hash.size(); 170 } 171 clear()172 inline void clear() { 173 hash.clear(); 174 first = nullptr; 175 last = nullptr; 176 weakpoint = nullptr; 177 currentSize = 0; 178 historySize = 0; 179 clearStats(); 180 } 181 clearStats()182 inline void clearStats() { 183 hits = 0; 184 nearMiss = 0; 185 farMiss = 0; 186 } 187 188 bool insert(const int key, const PVideoFrame &object); 189 PVideoFrame object(const int key); contains(const int key)190 inline bool contains(const int key) const { 191 return hash.count(key) > 0; 192 } 193 PVideoFrame operator[](const int key); 194 195 bool remove(const int key); 196 197 198 199 CacheAction recommendSize(); 200 201 void adjustSize(bool needMemory); 202 private: 203 void trim(int max, int maxHistory); 204 205 }; 206 207 class CacheInstance { 208 public: 209 VSCache cache; 210 VSNodeRef *clip; 211 VSCore *core; 212 VSNode *node; 213 int lastN; 214 int numThreads; 215 bool makeLinear; 216 CacheInstance(VSNodeRef * clip,VSCore * core,bool fixedSize)217 CacheInstance(VSNodeRef *clip, VSCore *core, bool fixedSize) : cache(20, 20, fixedSize), clip(clip), core(core), node(nullptr), lastN(-1), numThreads(0), makeLinear(false) {} 218 addCache()219 void addCache() { 220 std::lock_guard<std::mutex> lock(core->cacheLock); 221 core->caches.insert(node); 222 } 223 removeCache()224 void removeCache() { 225 std::lock_guard<std::mutex> lock(core->cacheLock); 226 core->caches.erase(node); 227 } 228 }; 229 230 void VS_CC cacheInitialize(VSConfigPlugin configFunc, VSRegisterFunction registerFunc, VSPlugin *plugin); 231 232 #endif // CACHEFILTER_H 233