OpenShot Library | libopenshot 0.3.3
Loading...
Searching...
No Matches
CacheMemory.cpp
Go to the documentation of this file.
1
9// Copyright (c) 2008-2019 OpenShot Studios, LLC
10//
11// SPDX-License-Identifier: LGPL-3.0-or-later
12
13#include "CacheMemory.h"
14#include "Exceptions.h"
15#include "Frame.h"
16
17using namespace std;
18using namespace openshot;
19
20// Default constructor, no max bytes
22 // Set cache type name
23 cache_type = "CacheMemory";
24 range_version = 0;
26}
27
28// Constructor that sets the max bytes to cache
29CacheMemory::CacheMemory(int64_t max_bytes) : CacheBase(max_bytes) {
30 // Set cache type name
31 cache_type = "CacheMemory";
32 range_version = 0;
34}
35
36// Default destructor
38{
39 Clear();
40
41 // remove mutex
42 delete cacheMutex;
43}
44
45// Add a Frame to the cache
46void CacheMemory::Add(std::shared_ptr<Frame> frame)
47{
48 // Create a scoped lock, to protect the cache from multiple threads
49 const std::lock_guard<std::recursive_mutex> lock(*cacheMutex);
50 int64_t frame_number = frame->number;
51
52 // Freshen frame if it already exists
53 if (frames.count(frame_number))
54 // Move frame to front of queue
55 MoveToFront(frame_number);
56
57 else
58 {
59 // Add frame to queue and map
60 frames[frame_number] = frame;
61 frame_numbers.push_front(frame_number);
62 ordered_frame_numbers.push_back(frame_number);
64
65 // Clean up old frames
66 CleanUp();
67 }
68}
69
70// Check if frame is already contained in cache
71bool CacheMemory::Contains(int64_t frame_number) {
72 if (frames.count(frame_number) > 0) {
73 return true;
74 } else {
75 return false;
76 }
77}
78
79// Get a frame from the cache (or NULL shared_ptr if no frame is found)
80std::shared_ptr<Frame> CacheMemory::GetFrame(int64_t frame_number)
81{
82 // Create a scoped lock, to protect the cache from multiple threads
83 const std::lock_guard<std::recursive_mutex> lock(*cacheMutex);
84
85 // Does frame exists in cache?
86 if (frames.count(frame_number))
87 // return the Frame object
88 return frames[frame_number];
89
90 else
91 // no Frame found
92 return std::shared_ptr<Frame>();
93}
94
95// @brief Get an array of all Frames
96std::vector<std::shared_ptr<openshot::Frame>> CacheMemory::GetFrames()
97{
98 // Create a scoped lock, to protect the cache from multiple threads
99 const std::lock_guard<std::recursive_mutex> lock(*cacheMutex);
100
101 std::vector<std::shared_ptr<openshot::Frame>> all_frames;
102 std::vector<int64_t>::iterator itr_ordered;
103 for(itr_ordered = ordered_frame_numbers.begin(); itr_ordered != ordered_frame_numbers.end(); ++itr_ordered)
104 {
105 int64_t frame_number = *itr_ordered;
106 all_frames.push_back(GetFrame(frame_number));
107 }
108
109 return all_frames;
110}
111
112// Get the smallest frame number (or NULL shared_ptr if no frame is found)
113std::shared_ptr<Frame> CacheMemory::GetSmallestFrame()
114{
115 // Create a scoped lock, to protect the cache from multiple threads
116 const std::lock_guard<std::recursive_mutex> lock(*cacheMutex);
117
118 // Loop through frame numbers
119 std::deque<int64_t>::iterator itr;
120 int64_t smallest_frame = -1;
121 for(itr = frame_numbers.begin(); itr != frame_numbers.end(); ++itr)
122 {
123 if (*itr < smallest_frame || smallest_frame == -1)
124 smallest_frame = *itr;
125 }
126
127 // Return frame (if any)
128 if (smallest_frame != -1) {
129 return frames[smallest_frame];
130 } else {
131 return NULL;
132 }
133}
134
135// Gets the maximum bytes value
137{
138 // Create a scoped lock, to protect the cache from multiple threads
139 const std::lock_guard<std::recursive_mutex> lock(*cacheMutex);
140
141 int64_t total_bytes = 0;
142
143 // Loop through frames, and calculate total bytes
144 std::deque<int64_t>::reverse_iterator itr;
145 for(itr = frame_numbers.rbegin(); itr != frame_numbers.rend(); ++itr)
146 {
147 total_bytes += frames[*itr]->GetBytes();
148 }
149
150 return total_bytes;
151}
152
153// Remove a specific frame
154void CacheMemory::Remove(int64_t frame_number)
155{
156 Remove(frame_number, frame_number);
157}
158
159// Remove range of frames
160void CacheMemory::Remove(int64_t start_frame_number, int64_t end_frame_number)
161{
162 // Create a scoped lock, to protect the cache from multiple threads
163 const std::lock_guard<std::recursive_mutex> lock(*cacheMutex);
164
165 // Loop through frame numbers
166 std::deque<int64_t>::iterator itr;
167 for(itr = frame_numbers.begin(); itr != frame_numbers.end();)
168 {
169 if (*itr >= start_frame_number && *itr <= end_frame_number)
170 {
171 // erase frame number
172 itr = frame_numbers.erase(itr);
173 }else
174 itr++;
175 }
176
177 // Loop through ordered frame numbers
178 std::vector<int64_t>::iterator itr_ordered;
179 for(itr_ordered = ordered_frame_numbers.begin(); itr_ordered != ordered_frame_numbers.end();)
180 {
181 if (*itr_ordered >= start_frame_number && *itr_ordered <= end_frame_number)
182 {
183 // erase frame number
184 frames.erase(*itr_ordered);
185 itr_ordered = ordered_frame_numbers.erase(itr_ordered);
186 }else
187 itr_ordered++;
188 }
189
190 // Needs range processing (since cache has changed)
192}
193
194// Move frame to front of queue (so it lasts longer)
195void CacheMemory::MoveToFront(int64_t frame_number)
196{
197 // Create a scoped lock, to protect the cache from multiple threads
198 const std::lock_guard<std::recursive_mutex> lock(*cacheMutex);
199
200 // Does frame exists in cache?
201 if (frames.count(frame_number))
202 {
203 // Loop through frame numbers
204 std::deque<int64_t>::iterator itr;
205 for(itr = frame_numbers.begin(); itr != frame_numbers.end(); ++itr)
206 {
207 if (*itr == frame_number)
208 {
209 // erase frame number
210 frame_numbers.erase(itr);
211
212 // add frame number to 'front' of queue
213 frame_numbers.push_front(frame_number);
214 break;
215 }
216 }
217 }
218}
219
220// Clear the cache of all frames
222{
223 // Create a scoped lock, to protect the cache from multiple threads
224 const std::lock_guard<std::recursive_mutex> lock(*cacheMutex);
225
226 frames.clear();
227 frame_numbers.clear();
228 frame_numbers.shrink_to_fit();
229 ordered_frame_numbers.clear();
230 ordered_frame_numbers.shrink_to_fit();
232}
233
234// Count the frames in the queue
236{
237 // Create a scoped lock, to protect the cache from multiple threads
238 const std::lock_guard<std::recursive_mutex> lock(*cacheMutex);
239
240 // Return the number of frames in the cache
241 return frames.size();
242}
243
244// Clean up cached frames that exceed the number in our max_bytes variable
245void CacheMemory::CleanUp()
246{
247 // Do we auto clean up?
248 if (max_bytes > 0)
249 {
250 // Create a scoped lock, to protect the cache from multiple threads
251 const std::lock_guard<std::recursive_mutex> lock(*cacheMutex);
252
253 while (GetBytes() > max_bytes && frame_numbers.size() > 20)
254 {
255 // Get the oldest frame number.
256 int64_t frame_to_remove = frame_numbers.back();
257
258 // Remove frame_number and frame
259 Remove(frame_to_remove);
260 }
261 }
262}
263
264
265// Generate JSON string of this object
266std::string CacheMemory::Json() {
267
268 // Return formatted string
269 return JsonValue().toStyledString();
270}
271
272// Generate Json::Value for this object
274
275 // Process range data (if anything has changed)
277
278 // Create root json object
279 Json::Value root = CacheBase::JsonValue(); // get parent properties
280 root["type"] = cache_type;
281
282 root["version"] = std::to_string(range_version);
283
284 // Parse and append range data (if any)
285 try {
286 const Json::Value ranges = openshot::stringToJson(json_ranges);
287 root["ranges"] = ranges;
288 } catch (...) { }
289
290 // return JsonValue
291 return root;
292}
293
294// Load JSON string into this object
295void CacheMemory::SetJson(const std::string value) {
296
297 try
298 {
299 // Parse string to Json::Value
300 const Json::Value root = openshot::stringToJson(value);
301 // Set all values that match
302 SetJsonValue(root);
303 }
304 catch (const std::exception& e)
305 {
306 // Error parsing JSON (or missing keys)
307 throw InvalidJSON("JSON is invalid (missing keys or invalid data types)");
308 }
309}
310
311// Load Json::Value into this object
312void CacheMemory::SetJsonValue(const Json::Value root) {
313
314 // Close timeline before we do anything (this also removes all open and closing clips)
315 Clear();
316
317 // Set parent data
319
320 if (!root["type"].isNull())
321 cache_type = root["type"].asString();
322}
Header file for CacheMemory class.
Header file for all Exception classes.
Header file for Frame class.
All cache managers in libopenshot are based on this CacheBase class.
Definition CacheBase.h:35
int64_t range_version
The version of the JSON range data (incremented with each change)
Definition CacheBase.h:44
virtual Json::Value JsonValue()=0
Generate Json::Value for this object.
std::string cache_type
This is a friendly type name of the derived cache instance.
Definition CacheBase.h:37
void CalculateRanges()
Calculate ranges of frames.
Definition CacheBase.cpp:38
virtual void SetJsonValue(const Json::Value root)=0
Load Json::Value into this object.
bool needs_range_processing
Something has changed, and the range data needs to be re-calculated.
Definition CacheBase.h:40
int64_t max_bytes
This is the max number of bytes to cache (0 = no limit)
Definition CacheBase.h:38
std::recursive_mutex * cacheMutex
Mutex for multiple threads.
Definition CacheBase.h:47
std::string json_ranges
JSON ranges of frame numbers.
Definition CacheBase.h:41
std::vector< int64_t > ordered_frame_numbers
Ordered list of frame numbers used by cache.
Definition CacheBase.h:42
CacheMemory()
Default constructor, no max bytes.
int64_t Count()
Count the frames in the queue.
void Add(std::shared_ptr< openshot::Frame > frame)
Add a Frame to the cache.
void SetJson(const std::string value)
Load JSON string into this object.
int64_t GetBytes()
Gets the maximum bytes value.
std::string Json()
Generate JSON string of this object.
std::shared_ptr< openshot::Frame > GetFrame(int64_t frame_number)
Get a frame from the cache.
std::vector< std::shared_ptr< openshot::Frame > > GetFrames()
Get an array of all Frames.
void SetJsonValue(const Json::Value root)
Load Json::Value into this object.
void MoveToFront(int64_t frame_number)
Move frame to front of queue (so it lasts longer)
void Remove(int64_t frame_number)
Remove a specific frame.
void Clear()
Clear the cache of all frames.
Json::Value JsonValue()
Generate Json::Value for this object.
bool Contains(int64_t frame_number)
Check if frame is already contained in cache.
std::shared_ptr< openshot::Frame > GetSmallestFrame()
Get the smallest frame number.
Exception for invalid JSON.
Definition Exceptions.h:218
This namespace is the default namespace for all code in the openshot library.
Definition Compressor.h:29
const Json::Value stringToJson(const std::string value)
Definition Json.cpp:16