OpenShot Library | libopenshot  0.1.2
Cache.cpp
Go to the documentation of this file.
1 /**
2  * @file
3  * @brief Source file for Cache class
4  * @author Jonathan Thomas <jonathan@openshot.org>
5  *
6  * @section LICENSE
7  *
8  * Copyright (c) 2008-2014 OpenShot Studios, LLC
9  * <http://www.openshotstudios.com/>. This file is part of
10  * OpenShot Library (libopenshot), an open-source project dedicated to
11  * delivering high quality video editing and animation solutions to the
12  * world. For more information visit <http://www.openshot.org/>.
13  *
14  * OpenShot Library (libopenshot) is free software: you can redistribute it
15  * and/or modify it under the terms of the GNU Lesser General Public License
16  * as published by the Free Software Foundation, either version 3 of the
17  * License, or (at your option) any later version.
18  *
19  * OpenShot Library (libopenshot) is distributed in the hope that it will be
20  * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22  * GNU Lesser General Public License for more details.
23  *
24  * You should have received a copy of the GNU Lesser General Public License
25  * along with OpenShot Library. If not, see <http://www.gnu.org/licenses/>.
26  */
27 
28 #include "../include/Cache.h"
29 
30 using namespace std;
31 using namespace openshot;
32 
33 // Default constructor, no max frames
34 Cache::Cache() : max_bytes(0) {
35  // Init the critical section
36  cacheCriticalSection = new CriticalSection();
37 };
38 
39 // Constructor that sets the max frames to cache
40 Cache::Cache(int64 max_bytes) : max_bytes(max_bytes) {
41  // Init the critical section
42  cacheCriticalSection = new CriticalSection();
43 };
44 
45 // Default destructor
47 {
48  frames.clear();
49  frame_numbers.clear();
50 
51  // remove critical section
52  delete cacheCriticalSection;
53  cacheCriticalSection = NULL;
54 }
55 
56 // Add a Frame to the cache
57 void Cache::Add(long int frame_number, tr1::shared_ptr<Frame> frame)
58 {
59  // Create a scoped lock, to protect the cache from multiple threads
60  const GenericScopedLock<CriticalSection> lock(*cacheCriticalSection);
61 
62  // Freshen frame if it already exists
63  if (frames.count(frame_number))
64  // Move frame to front of queue
65  MoveToFront(frame_number);
66 
67  else
68  {
69  // Add frame to queue and map
70  frames[frame_number] = frame;
71  frame_numbers.push_front(frame_number);
72 
73  // Clean up old frames
74  CleanUp();
75  }
76 }
77 
78 // Get a frame from the cache (or NULL shared_ptr if no frame is found)
79 tr1::shared_ptr<Frame> Cache::GetFrame(long int frame_number)
80 {
81  // Create a scoped lock, to protect the cache from multiple threads
82  const GenericScopedLock<CriticalSection> lock(*cacheCriticalSection);
83 
84  // Does frame exists in cache?
85  if (frames.count(frame_number))
86  // return the Frame object
87  return frames[frame_number];
88 
89  else
90  // no Frame found
91  return tr1::shared_ptr<Frame>();
92 }
93 
94 // Return a deque of all frame numbers in this queue (returns just a copy of the data)
95 deque<long int> Cache::GetFrameNumbers() {
96 
97  // Create a scoped lock, to protect the cache from multiple threads
98  const GenericScopedLock<CriticalSection> lock(*cacheCriticalSection);
99 
100  // Make copy of deque
101  deque<long int> copy_frame_numbers;
102 
103  // Loop through frame numbers
104  deque<long int>::iterator itr;
105  for(itr = frame_numbers.begin(); itr != frame_numbers.end(); ++itr)
106  copy_frame_numbers.push_back(*itr);
107 
108  return copy_frame_numbers;
109 }
110 
111 // Get the smallest frame number (or NULL shared_ptr if no frame is found)
112 tr1::shared_ptr<Frame> Cache::GetSmallestFrame()
113 {
114  // Create a scoped lock, to protect the cache from multiple threads
115  const GenericScopedLock<CriticalSection> lock(*cacheCriticalSection);
116  tr1::shared_ptr<openshot::Frame> f;
117 
118  // Loop through frame numbers
119  deque<long int>::iterator itr;
120  long int 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
128  f = GetFrame(smallest_frame);
129 
130  return f;
131 }
132 
133 // Gets the maximum bytes value
135 {
136  // Create a scoped lock, to protect the cache from multiple threads
137  const GenericScopedLock<CriticalSection> lock(*cacheCriticalSection);
138 
139  int64 total_bytes = 0;
140 
141  // Loop through frames, and calculate total bytes
142  deque<long int>::reverse_iterator itr;
143  for(itr = frame_numbers.rbegin(); itr != frame_numbers.rend(); ++itr)
144  {
145  total_bytes += frames[*itr]->GetBytes();
146  }
147 
148  return total_bytes;
149 }
150 
151 // Remove a specific frame
152 void Cache::Remove(long int frame_number)
153 {
154  // Create a scoped lock, to protect the cache from multiple threads
155  const GenericScopedLock<CriticalSection> lock(*cacheCriticalSection);
156 
157  // Loop through frame numbers
158  deque<long int>::iterator itr;
159  for(itr = frame_numbers.begin(); itr != frame_numbers.end(); ++itr)
160  {
161  if (*itr == frame_number)
162  {
163  // erase frame number
164  frame_numbers.erase(itr);
165  break;
166  }
167  }
168 
169  // Remove frame from map. If frame_number doesn't exist, frames.erase returns zero.
170  frames.erase(frame_number);
171 }
172 
173 // Move frame to front of queue (so it lasts longer)
174 void Cache::MoveToFront(long int frame_number)
175 {
176  // Create a scoped lock, to protect the cache from multiple threads
177  const GenericScopedLock<CriticalSection> lock(*cacheCriticalSection);
178 
179  // Does frame exists in cache?
180  /* FIXME if the frame number isn't present, the loop will do nothing, so why protect it?
181  * Is it to save time by avoiding a loop?
182  * Do we really need to optmize the case where we've been given a nonexisting frame_number? */
183  if (frames.count(frame_number))
184  {
185  // Loop through frame numbers
186  deque<long int>::iterator itr;
187  for(itr = frame_numbers.begin(); itr != frame_numbers.end(); ++itr)
188  {
189  if (*itr == frame_number)
190  {
191  // erase frame number
192  frame_numbers.erase(itr);
193 
194  // add frame number to 'front' of queue
195  frame_numbers.push_front(frame_number);
196  break;
197  }
198  }
199  }
200 }
201 
202 // Clear the cache of all frames
204 {
205  // Create a scoped lock, to protect the cache from multiple threads
206  const GenericScopedLock<CriticalSection> lock(*cacheCriticalSection);
207 
208  frames.clear();
209  frame_numbers.clear();
210 }
211 
212 // Count the frames in the queue
213 long int Cache::Count()
214 {
215  // Create a scoped lock, to protect the cache from multiple threads
216  const GenericScopedLock<CriticalSection> lock(*cacheCriticalSection);
217 
218  // Return the number of frames in the cache
219  return frames.size();
220 }
221 
222 // Clean up cached frames that exceed the number in our max_bytes variable
223 void Cache::CleanUp()
224 {
225  // Create a scoped lock, to protect the cache from multiple threads
226  const GenericScopedLock<CriticalSection> lock(*cacheCriticalSection);
227 
228  // Do we auto clean up?
229  if (max_bytes > 0)
230  {
231  while (GetBytes() > max_bytes && frame_numbers.size() > 20)
232  {
233  // Get the oldest frame number.
234  long int frame_to_remove = frame_numbers.back();
235 
236  // Remove frame_number and frame
237  Remove(frame_to_remove);
238  }
239  }
240 }
241 
242 // Display a list of cached frame numbers
244 {
245  cout << "----- Cache List (" << frames.size() << ") ------" << endl;
246  deque<long int>::iterator itr;
247 
248  int i = 1;
249  for(itr = frame_numbers.begin(); itr != frame_numbers.end(); ++itr)
250  {
251  cout << " " << i << ") --- Frame " << *itr << endl;
252  i++;
253  }
254 }
255 
256 // Set maximum bytes to a different amount based on a ReaderInfo struct
257 void Cache::SetMaxBytesFromInfo(long int number_of_frames, int width, int height, int sample_rate, int channels)
258 {
259  // n frames X height X width X 4 colors of chars X audio channels X 4 byte floats
260  int64 bytes = number_of_frames * (height * width * 4 + (sample_rate * channels * 4));
261  SetMaxBytes(bytes);
262 }
263 
void SetMaxBytes(int64 number_of_bytes)
Set maximum bytes to a different amount.
Definition: Cache.h:120
void Add(long int frame_number, tr1::shared_ptr< Frame > frame)
Add a Frame to the cache.
Definition: Cache.cpp:57
void Remove(long int frame_number)
Remove a specific frame.
Definition: Cache.cpp:152
deque< long int > GetFrameNumbers()
Return a deque of all frame numbers in this queue (returns just a copy of the data) ...
Definition: Cache.cpp:95
void SetMaxBytesFromInfo(long int number_of_frames, int width, int height, int sample_rate, int channels)
Set maximum bytes to a different amount based on a ReaderInfo struct.
Definition: Cache.cpp:257
int64 GetBytes()
Gets the maximum bytes value.
Definition: Cache.cpp:134
tr1::shared_ptr< Frame > GetSmallestFrame()
Get the smallest frame number.
Definition: Cache.cpp:112
Cache()
Default constructor, no max bytes.
Definition: Cache.cpp:34
tr1::shared_ptr< Frame > GetFrame(long int frame_number)
Get a frame from the cache.
Definition: Cache.cpp:79
void Clear()
Clear the cache of all frames.
Definition: Cache.cpp:203
This namespace is the default namespace for all code in the openshot library.
void Display()
Display a list of cached frame numbers.
Definition: Cache.cpp:243
void MoveToFront(long int frame_number)
Move frame to front of queue (so it lasts longer)
Definition: Cache.cpp:174
long int Count()
Count the frames in the queue.
Definition: Cache.cpp:213