r827: Fix a crash when no audio output device can be opened.
[cinelerra_cv.git] / cinelerra / cache.C
blob287f3a15cc128b6fc73f4e623c9eca9666503c3c
1 #include "asset.h"
2 #include "assets.h"
3 #include "cache.h"
4 #include "datatype.h"
5 #include "edl.h"
6 #include "edlsession.h"
7 #include "file.h"
8 #include "filesystem.h"
9 #include "mutex.h"
10 #include "preferences.h"
12 #include <string.h>
14 // edl came from a command which won't exist anymore
15 CICache::CICache(EDL *edl, 
16         Preferences *preferences,
17         ArrayList<PluginServer*> *plugindb)
18  : List<CICacheItem>()
20         this->edl = new EDL;
21         this->edl->create_objects();
22         this->edl->copy_all(edl);
23         this->plugindb = plugindb;
24         this->preferences = preferences;
25         check_in_lock = new Mutex("CICache::check_in_lock");
26         check_out_lock = new Mutex("CICache::check_out_lock");
27         total_lock = new Mutex("CICache::total_lock");
30 CICache::~CICache()
32         while(last) delete last;
33         delete edl;
34         delete check_in_lock;
35         delete check_out_lock;
36         delete total_lock;
39 void CICache::set_edl(EDL *edl)
41         this->edl->copy_all(edl);
44 void CICache::update(File* &file)
46 // Check if exists
47         for(CICacheItem *current = first; current; current = NEXT)
48         {
49                 if(!current->asset->test_path(file->asset->path))
50                 {
51                         if(file != current->file)
52                         {
53                                 delete file;
54                                 file = current->file;
55                         }
56                         return;
57                 }
58         }
60         CICacheItem *item;
61         append(item = new CICacheItem(this, file));
62         item->asset = new Asset(*(file->asset));
63         file->set_asset(item->asset);
66 File* CICache::check_out(Asset *asset)
68         File *result = 0;
70         check_out_lock->lock("CICache::check_out");
72 // search for it in the cache
73         CICacheItem *current, *new_item = 0;
75         for(current = first; current && !new_item; current = NEXT)
76         {
77                 if(!strcmp(current->asset->path, asset->path))
78                 {
79                         current->counter = 0;
80                         new_item = current;
81                 }
82         }
84 // didn't find it so create a new one
85         if(!new_item)
86         {
87                 new_item = append(new CICacheItem(this, asset));
88         }
90         if(new_item)
91         {
92                 if(new_item->file)
93                 {
94 // opened successfully
95                         new_item->item_lock->lock("CICache::check_out");
96                         new_item->checked_out = 1;
98                         result = new_item->file;
99                 }
100                 else
101                 {
102 // failed
103                         delete new_item;
104                         new_item = 0;
105                 }
106         }
109 //printf("CICache::check_out %s\n", asset->path);
110         check_out_lock->unlock();
112         return result;
115 int CICache::check_in(Asset *asset)
117         check_in_lock->lock("CICache::check_in");
119         CICacheItem *current;
120         int result = 0;
121         total_lock->lock("CICache::check_in");
122         for(current = first; current && !result; current = NEXT)
123         {
124 // Pointers are different
125                 if(!strcmp(current->asset->path, asset->path))
126                 {
127                         current->checked_out = 0;
128                         current->item_lock->unlock();
129                         result = 1;
130                 }
131         }
132         total_lock->unlock();
134         check_in_lock->unlock();
136         age();
137 //dump();
138         return result;
141 int CICache::delete_entry(char *path)
143         Asset *asset = edl->assets->get_asset(path);
144         if(asset) delete_entry(asset);
145         return 0;
148 int CICache::delete_entry(Asset *asset)
150         lock_all();
151         int result = 0;
152         CICacheItem *current, *temp;
154         for(current = first; current; current = temp)
155         {
156                 temp = NEXT;
157                 if(current->asset->equivalent(*asset, 0, 0))
158                 {
159                         if(!current->checked_out)
160                         {
161                                 delete current;
162                         }
163                         else
164                         {
165                                 printf("CICache::delete_entry asset checked out\n");
166                         }
167                 }
168                 current = temp;
169         }
171         unlock_all();
172         return 0;
175 int CICache::age()
177         check_out_lock->lock("CICache::age");
178         CICacheItem *current;
180         for(current = first; current; current = NEXT)
181         {
182                 current->counter++;
183         }
185 // delete old assets if memory usage is exceeded
186         int64_t memory_usage;
187         int result = 0;
188         do
189         {
190                 memory_usage = get_memory_usage();
191                 
192 //printf("CICache::age 3 %p %lld %lld\n", this, memory_usage, preferences->cache_size);
193                 if(memory_usage > preferences->cache_size)
194                 {
195                         result = delete_oldest();
196                 }
197         }while(memory_usage > preferences->cache_size && !result);
199         check_out_lock->unlock();
202 int64_t CICache::get_memory_usage()
204         CICacheItem *current;
205         int64_t result = 0;
206         
207         for(current = first; current; current = NEXT)
208         {
209                 File *file = current->file;
210                 if(file) result += file->get_memory_usage();
211         }
212         
213         return result;
216 int CICache::delete_oldest()
218         CICacheItem *current;
219         int highest_counter = 1;
220         CICacheItem *oldest = 0;
222         for(current = last; current; current =  PREVIOUS)
223         {
224                 if(current->counter >= highest_counter)
225                 {
226                         oldest = current;
227                         highest_counter = current->counter;
228                 }
229         }
231 //      if(highest_counter > 1 && oldest)
232         if(oldest)
233         {
234                 total_lock->lock("CICache::delete_oldest");
237 // Got the oldest file.  Try requesting cache purge.
238                 if(!oldest->file || oldest->file->purge_cache())
239                 {
240 // Delete the file if cache already empty and not checked out.
241                         if(!oldest->checked_out) delete oldest;
242                 }
243                 total_lock->unlock();
244                 return 0;    // success
245         }
246         else
247         {
248                 return 1;    // nothing was old enough to delete
249         }
252 int CICache::dump()
254         lock_all();
255         CICacheItem *current;
257         printf("CICache::dump total size %lld\n", get_memory_usage());
258         for(current = first; current; current = NEXT)
259         {
260                 printf("cache item %x asset %x %s counter %lld\n", 
261                         current, 
262                         current->asset,
263                         current->asset->path, 
264                         current->counter);
265         }
266         
267         unlock_all();
270 int CICache::lock_all()
272         check_in_lock->lock("CICache::lock_all");
273         check_out_lock->lock("CICache::lock_all");
276 int CICache::unlock_all()
278         check_in_lock->unlock();
279         check_out_lock->unlock();
292 // File not already opened.
293 CICacheItem::CICacheItem(CICache *cache, Asset *asset)
294  : ListItem<CICacheItem>()
296         int result = 0;
297         counter = 0;
298         this->asset = new Asset;
299         item_lock = new Mutex("CICacheItem::item_lock");
300         
301 // Must copy Asset since this belongs to an EDL which won't exist forever.
302         *this->asset = *asset;
303         this->cache = cache;
304         checked_out = 0;
306         file = new File;
307         file->set_processors(cache->preferences->processors);
308         file->set_preload(cache->edl->session->playback_preload);
311 // Copy decoding parameters from session to asset so file can see them.
312         this->asset->divx_use_deblocking = cache->edl->session->mpeg4_deblock;
316         if(result = file->open_file(cache->preferences, this->asset, 1, 0, -1, -1))
317         {
318                 delete file;
319                 file = 0;
320         }
323 // File already opened
324 CICacheItem::CICacheItem(CICache *cache, File *file)
325  : ListItem<CICacheItem>()
327         counter = 0;
328         this->asset = new Asset;
329         item_lock = new Mutex("CICacheItem::item_lock");
330         *this->asset = *file->asset;
331         this->file = file;
332         this->cache = cache;
333         checked_out = 0;
335         file->set_processors(cache->preferences->processors);
336         file->set_preload(cache->edl->session->playback_preload);
339 CICacheItem::~CICacheItem()
341         delete file;
342         delete asset;
343         delete item_lock;