OpenShot Library | libopenshot  0.3.3
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 
17 using namespace std;
18 using namespace openshot;
19 
20 // Default constructor, no max bytes
21 CacheMemory::CacheMemory() : CacheBase(0) {
22  // Set cache type name
23  cache_type = "CacheMemory";
24  range_version = 0;
25  needs_range_processing = false;
26 }
27 
28 // Constructor that sets the max bytes to cache
29 CacheMemory::CacheMemory(int64_t max_bytes) : CacheBase(max_bytes) {
30  // Set cache type name
31  cache_type = "CacheMemory";
32  range_version = 0;
33  needs_range_processing = false;
34 }
35 
36 // Default destructor
38 {
39  Clear();
40 
41  // remove mutex
42  delete cacheMutex;
43 }
44 
45 // Add a Frame to the cache
46 void 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
71 bool 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)
80 std::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
96 std::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)
113 std::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
154 void CacheMemory::Remove(int64_t frame_number)
155 {
156  Remove(frame_number, frame_number);
157 }
158 
159 // Remove range of frames
160 void 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)
191  needs_range_processing = true;
192 }
193 
194 // Move frame to front of queue (so it lasts longer)
195 void 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();
231  needs_range_processing = true;
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
245 void 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
266 std::string CacheMemory::Json() {
267 
268  // Return formatted string
269  return JsonValue().toStyledString();
270 }
271 
272 // Generate Json::Value for this object
273 Json::Value CacheMemory::JsonValue() {
274 
275  // Process range data (if anything has changed)
276  CalculateRanges();
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
295 void 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
312 void 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 }
openshot::stringToJson
const Json::Value stringToJson(const std::string value)
Definition: Json.cpp:16
openshot::CacheMemory::Clear
void Clear()
Clear the cache of all frames.
Definition: CacheMemory.cpp:221
openshot::CacheMemory::Count
int64_t Count()
Count the frames in the queue.
Definition: CacheMemory.cpp:235
openshot::CacheBase::needs_range_processing
bool needs_range_processing
Something has changed, and the range data needs to be re-calculated.
Definition: CacheBase.h:40
openshot::CacheMemory::GetBytes
int64_t GetBytes()
Gets the maximum bytes value.
Definition: CacheMemory.cpp:136
openshot::CacheMemory::GetFrame
std::shared_ptr< openshot::Frame > GetFrame(int64_t frame_number)
Get a frame from the cache.
Definition: CacheMemory.cpp:80
openshot::CacheBase::max_bytes
int64_t max_bytes
This is the max number of bytes to cache (0 = no limit)
Definition: CacheBase.h:38
openshot::CacheMemory::Add
void Add(std::shared_ptr< openshot::Frame > frame)
Add a Frame to the cache.
Definition: CacheMemory.cpp:46
openshot::CacheBase::ordered_frame_numbers
std::vector< int64_t > ordered_frame_numbers
Ordered list of frame numbers used by cache.
Definition: CacheBase.h:42
openshot
This namespace is the default namespace for all code in the openshot library.
Definition: Compressor.h:28
openshot::CacheBase::json_ranges
std::string json_ranges
JSON ranges of frame numbers.
Definition: CacheBase.h:41
openshot::CacheMemory::Contains
bool Contains(int64_t frame_number)
Check if frame is already contained in cache.
Definition: CacheMemory.cpp:71
openshot::CacheMemory::Remove
void Remove(int64_t frame_number)
Remove a specific frame.
Definition: CacheMemory.cpp:154
openshot::CacheMemory::JsonValue
Json::Value JsonValue()
Generate Json::Value for this object.
Definition: CacheMemory.cpp:273
openshot::CacheBase
All cache managers in libopenshot are based on this CacheBase class.
Definition: CacheBase.h:34
openshot::CacheBase::SetJsonValue
virtual void SetJsonValue(const Json::Value root)=0
Load Json::Value into this object.
Definition: CacheBase.cpp:115
openshot::CacheMemory::~CacheMemory
virtual ~CacheMemory()
Definition: CacheMemory.cpp:37
openshot::InvalidJSON
Exception for invalid JSON.
Definition: Exceptions.h:217
CacheMemory.h
Header file for CacheMemory class.
openshot::CacheMemory::Json
std::string Json()
Generate JSON string of this object.
Definition: CacheMemory.cpp:266
openshot::CacheBase::JsonValue
virtual Json::Value JsonValue()=0
Generate Json::Value for this object.
Definition: CacheBase.cpp:102
openshot::CacheBase::CalculateRanges
void CalculateRanges()
Calculate ranges of frames.
Definition: CacheBase.cpp:38
Frame.h
Header file for Frame class.
openshot::CacheMemory::GetSmallestFrame
std::shared_ptr< openshot::Frame > GetSmallestFrame()
Get the smallest frame number.
Definition: CacheMemory.cpp:113
openshot::CacheBase::cache_type
std::string cache_type
This is a friendly type name of the derived cache instance.
Definition: CacheBase.h:37
openshot::CacheMemory::CacheMemory
CacheMemory()
Default constructor, no max bytes.
Definition: CacheMemory.cpp:21
openshot::CacheMemory::MoveToFront
void MoveToFront(int64_t frame_number)
Move frame to front of queue (so it lasts longer)
Definition: CacheMemory.cpp:195
openshot::CacheMemory::SetJson
void SetJson(const std::string value)
Load JSON string into this object.
Definition: CacheMemory.cpp:295
openshot::CacheMemory::SetJsonValue
void SetJsonValue(const Json::Value root)
Load Json::Value into this object.
Definition: CacheMemory.cpp:312
openshot::CacheMemory::GetFrames
std::vector< std::shared_ptr< openshot::Frame > > GetFrames()
Get an array of all Frames.
Definition: CacheMemory.cpp:96
openshot::CacheBase::range_version
int64_t range_version
The version of the JSON range data (incremented with each change)
Definition: CacheBase.h:44
Exceptions.h
Header file for all Exception classes.
openshot::CacheBase::cacheMutex
std::recursive_mutex * cacheMutex
Mutex for multiple threads.
Definition: CacheBase.h:47