Blender V5.0
moviecache.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2024 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#undef DEBUG_MESSAGES
10
11#include <cstdlib> /* for qsort */
12#include <memory.h>
13#include <mutex>
14
16#include "MEM_guardedalloc.h"
17
18#include "BLI_ghash.h"
19#include "BLI_mempool.h"
20#include "BLI_string.h"
21
22#include "IMB_moviecache.hh"
23
24#include "IMB_imbuf.hh"
25#include "IMB_imbuf_types.hh"
26
27#ifdef DEBUG_MESSAGES
28# if defined __GNUC__
29# define PRINT(format, args...) printf(format, ##args)
30# else
31# define PRINT(format, ...) printf(__VA_ARGS__)
32# endif
33#else
34# define PRINT(format, ...)
35#endif
36
37static MEM_CacheLimiterC *limitor = nullptr;
38
39/* Image buffers managed by a moviecache might be using their own movie caches (used by color
40 * management). In practice this means that, for example, freeing MovieCache used by MovieClip
41 * will request freeing MovieCache owned by ImBuf. Freeing MovieCache needs to be thread-safe,
42 * so regular mutex will not work here, hence the recursive lock. */
43static std::recursive_mutex limitor_lock;
44
68
73
79 /* Indicates that #ibuf is null, because there was an error during load. */
81};
82
83static uint moviecache_hashhash(const void *keyv)
84{
85 const MovieCacheKey *key = (const MovieCacheKey *)keyv;
86
87 return key->cache_owner->hashfp(key->userkey);
88}
89
90static bool moviecache_hashcmp(const void *av, const void *bv)
91{
92 const MovieCacheKey *a = (const MovieCacheKey *)av;
93 const MovieCacheKey *b = (const MovieCacheKey *)bv;
94
95 return a->cache_owner->cmpfp(a->userkey, b->userkey);
96}
97
98static void moviecache_keyfree(void *val)
99{
100 MovieCacheKey *key = (MovieCacheKey *)val;
101
103
105}
106
107static void moviecache_valfree(void *val)
108{
109 MovieCacheItem *item = (MovieCacheItem *)val;
110 MovieCache *cache = item->cache_owner;
111
112 PRINT("%s: cache '%s' free item %p buffer %p\n", __func__, cache->name, item, item->ibuf);
113
114 if (item->c_handle) {
115 limitor_lock.lock();
117 limitor_lock.unlock();
118 }
119
120 if (item->ibuf) {
121 IMB_freeImBuf(item->ibuf);
122 }
123
124 if (item->priority_data && cache->prioritydeleterfp) {
125 cache->prioritydeleterfp(item->priority_data);
126 }
127
129}
130
131static void check_unused_keys(MovieCache *cache)
132{
133 GHashIterator gh_iter;
134
135 BLI_ghashIterator_init(&gh_iter, cache->hash);
136
137 while (!BLI_ghashIterator_done(&gh_iter)) {
138 const MovieCacheKey *key = (const MovieCacheKey *)BLI_ghashIterator_getKey(&gh_iter);
139 const MovieCacheItem *item = (const MovieCacheItem *)BLI_ghashIterator_getValue(&gh_iter);
140
141 BLI_ghashIterator_step(&gh_iter);
142
143 if (item->added_empty) {
144 /* Don't remove entries that have been added empty. Those indicate that the image couldn't be
145 * loaded correctly. */
146 continue;
147 }
148
149 bool remove = !item->ibuf;
150
151 if (remove) {
152 PRINT("%s: cache '%s' remove item %p without buffer\n", __func__, cache->name, item);
153 }
154
155 if (remove) {
157 }
158 }
159}
160
161static int compare_int(const void *av, const void *bv)
162{
163 const int *a = (int *)av;
164 const int *b = (int *)bv;
165 return *a - *b;
166}
167
168static void moviecache_destructor(void *p)
169{
170 MovieCacheItem *item = (MovieCacheItem *)p;
171
172 if (item && item->ibuf) {
173 MovieCache *cache = item->cache_owner;
174
175 PRINT("%s: cache '%s' destroy item %p buffer %p\n", __func__, cache->name, item, item->ibuf);
176
177 IMB_freeImBuf(item->ibuf);
178
179 item->ibuf = nullptr;
180 item->c_handle = nullptr;
181
182 /* force cached segments to be updated */
183 MEM_SAFE_FREE(cache->points);
184 }
185}
186
187static size_t get_size_in_memory(ImBuf *ibuf)
188{
189 /* Keep textures in the memory to avoid constant file reload on viewport update. */
190 if (ibuf->userflags & IB_PERSISTENT) {
191 return 0;
192 }
193
194 return IMB_get_size_in_memory(ibuf);
195}
196static size_t get_item_size(void *p)
197{
198 size_t size = sizeof(MovieCacheItem);
199 MovieCacheItem *item = (MovieCacheItem *)p;
200
201 if (item->ibuf) {
202 size += get_size_in_memory(item->ibuf);
203 }
204
205 return size;
206}
207
208static int get_item_priority(void *item_v, int default_priority)
209{
210 MovieCacheItem *item = (MovieCacheItem *)item_v;
211 MovieCache *cache = item->cache_owner;
212 int priority;
213
214 if (!cache->getitempriorityfp) {
215 PRINT("%s: cache '%s' item %p use default priority %d\n",
216 __func__,
217 cache->name,
218 item,
219 default_priority);
220
221 return default_priority;
222 }
223
224 priority = cache->getitempriorityfp(cache->last_userkey, item->priority_data);
225
226 PRINT("%s: cache '%s' item %p priority %d\n", __func__, cache->name, item, priority);
227
228 return priority;
229}
230
231static bool get_item_destroyable(void *item_v)
232{
233 MovieCacheItem *item = (MovieCacheItem *)item_v;
234 if (item->ibuf == nullptr) {
235 return true;
236 }
237 /* IB_BITMAPDIRTY means image was modified from inside blender and
238 * changes are not saved to disk.
239 *
240 * Such buffers are never to be freed.
241 */
242 if ((item->ibuf->userflags & IB_BITMAPDIRTY) || (item->ibuf->userflags & IB_PERSISTENT)) {
243 return false;
244 }
245 return true;
246}
247
255
257{
258 if (limitor) {
260 limitor = nullptr;
261 }
262}
263
265 int keysize,
266 GHashHashFP hashfp,
267 GHashCmpFP cmpfp)
268{
269 MovieCache *cache;
270
271 PRINT("%s: cache '%s' create\n", __func__, name);
272
273 cache = MEM_callocN<MovieCache>("MovieCache");
274
275 STRNCPY(cache->name, name);
276
279 cache->userkeys_pool = BLI_mempool_create(keysize, 0, 64, BLI_MEMPOOL_NOP);
280 cache->hash = BLI_ghash_new(
281 moviecache_hashhash, moviecache_hashcmp, "MovieClip ImBuf cache hash");
282
283 cache->keysize = keysize;
284 cache->hashfp = hashfp;
285 cache->cmpfp = cmpfp;
286 cache->proxy = -1;
287
288 return cache;
289}
290
292{
293 cache->getdatafp = getdatafp;
294}
295
297 MovieCacheGetPriorityDataFP getprioritydatafp,
298 MovieCacheGetItemPriorityFP getitempriorityfp,
299 MovieCachePriorityDeleterFP prioritydeleterfp)
300{
301 cache->last_userkey = MEM_mallocN(cache->keysize, "movie cache last user key");
302
303 cache->getprioritydatafp = getprioritydatafp;
304 cache->getitempriorityfp = getitempriorityfp;
305 cache->prioritydeleterfp = prioritydeleterfp;
306}
307
308static void do_moviecache_put(MovieCache *cache, void *userkey, ImBuf *ibuf, bool need_lock)
309{
310 MovieCacheKey *key;
311 MovieCacheItem *item;
312
313 if (!limitor) {
315 }
316
317 if (ibuf != nullptr) {
318 IMB_refImBuf(ibuf);
319 }
320
322 key->cache_owner = cache;
324 memcpy(key->userkey, userkey, cache->keysize);
325
327
328 PRINT("%s: cache '%s' put %p, item %p\n", __func__, cache->name, ibuf, item);
329
330 item->ibuf = ibuf;
331 item->cache_owner = cache;
332 item->c_handle = nullptr;
333 item->priority_data = nullptr;
334 item->added_empty = ibuf == nullptr;
335
336 if (cache->getprioritydatafp) {
337 item->priority_data = cache->getprioritydatafp(userkey);
338 }
339
341
342 if (cache->last_userkey) {
343 memcpy(cache->last_userkey, userkey, cache->keysize);
344 }
345
346 if (need_lock) {
347 limitor_lock.lock();
348 }
349
351
355
356 if (need_lock) {
357 limitor_lock.unlock();
358 }
359
360 /* cache limiter can't remove unused keys which points to destroyed values */
361 check_unused_keys(cache);
362
363 MEM_SAFE_FREE(cache->points);
364}
365
366void IMB_moviecache_put(MovieCache *cache, void *userkey, ImBuf *ibuf)
367{
368 do_moviecache_put(cache, userkey, ibuf, true);
369}
370
371bool IMB_moviecache_put_if_possible(MovieCache *cache, void *userkey, ImBuf *ibuf)
372{
373 size_t mem_in_use, mem_limit, elem_size;
374 bool result = false;
375
376 elem_size = (ibuf == nullptr) ? 0 : get_size_in_memory(ibuf);
377 mem_limit = MEM_CacheLimiter_get_maximum();
378
379 limitor_lock.lock();
381
382 if (mem_in_use + elem_size <= mem_limit) {
383 do_moviecache_put(cache, userkey, ibuf, false);
384 result = true;
385 }
386
387 limitor_lock.unlock();
388
389 return result;
390}
391
392void IMB_moviecache_remove(MovieCache *cache, void *userkey)
393{
394 MovieCacheKey key;
395 key.cache_owner = cache;
396 key.userkey = userkey;
398}
399
400ImBuf *IMB_moviecache_get(MovieCache *cache, void *userkey, bool *r_is_cached_empty)
401{
402 MovieCacheKey key;
403 MovieCacheItem *item;
404
405 key.cache_owner = cache;
406 key.userkey = userkey;
407 item = (MovieCacheItem *)BLI_ghash_lookup(cache->hash, &key);
408
409 if (r_is_cached_empty) {
410 *r_is_cached_empty = false;
411 }
412
413 if (item) {
414 if (item->ibuf) {
415 std::lock_guard lock(limitor_lock);
416 /* Check again, the condition might have changed before we acquired the lock. */
417 if (item->ibuf) {
419 IMB_refImBuf(item->ibuf);
420 return item->ibuf;
421 }
422 }
423 if (r_is_cached_empty && item->added_empty) {
424 *r_is_cached_empty = true;
425 }
426 }
427
428 return nullptr;
429}
430
431bool IMB_moviecache_has_frame(MovieCache *cache, void *userkey)
432{
433 MovieCacheKey key;
434 MovieCacheItem *item;
435
436 key.cache_owner = cache;
437 key.userkey = userkey;
438 item = (MovieCacheItem *)BLI_ghash_lookup(cache->hash, &key);
439
440 return item != nullptr;
441}
442
444{
445 PRINT("%s: cache '%s' free\n", __func__, cache->name);
446
448
452
453 if (cache->points) {
454 MEM_freeN(cache->points);
455 }
456
457 if (cache->last_userkey) {
458 MEM_freeN(cache->last_userkey);
459 }
460
461 MEM_freeN(cache);
462}
463
465 bool(cleanup_check_cb)(ImBuf *ibuf, void *userkey, void *userdata),
466 void *userdata)
467{
468 GHashIterator gh_iter;
469
470 check_unused_keys(cache);
471
472 BLI_ghashIterator_init(&gh_iter, cache->hash);
473
474 while (!BLI_ghashIterator_done(&gh_iter)) {
477
478 BLI_ghashIterator_step(&gh_iter);
479
480 if (cleanup_check_cb(item->ibuf, key->userkey, userdata)) {
481 PRINT("%s: cache '%s' remove item %p\n", __func__, cache->name, item);
482
484 }
485 }
486}
487
489 MovieCache *cache, int proxy, int render_flags, int *r_totseg, int **r_points)
490{
491 *r_totseg = 0;
492 *r_points = nullptr;
493
494 if (!cache->getdatafp) {
495 return;
496 }
497
498 if (cache->proxy != proxy || cache->render_flags != render_flags) {
499 MEM_SAFE_FREE(cache->points);
500 }
501
502 if (cache->points) {
503 *r_totseg = cache->totseg;
504 *r_points = cache->points;
505 }
506 else {
507 int totframe = BLI_ghash_len(cache->hash);
508 int *frames = MEM_calloc_arrayN<int>(totframe, "movieclip cache frames");
509 int a, totseg = 0;
510 GHashIterator gh_iter;
511
512 a = 0;
513 GHASH_ITER (gh_iter, cache->hash) {
516 int framenr, curproxy, curflags;
517
518 if (item->ibuf) {
519 cache->getdatafp(key->userkey, &framenr, &curproxy, &curflags);
520
521 if (curproxy == proxy && curflags == render_flags) {
522 frames[a++] = framenr;
523 }
524 }
525 }
526
527 qsort(frames, totframe, sizeof(int), compare_int);
528
529 /* count */
530 for (a = 0; a < totframe; a++) {
531 if (a && frames[a] - frames[a - 1] != 1) {
532 totseg++;
533 }
534
535 if (a == totframe - 1) {
536 totseg++;
537 }
538 }
539
540 if (totseg) {
541 int b, *points;
542
543 points = MEM_calloc_arrayN<int>(2 * size_t(totseg), "movieclip cache segments");
544
545 /* fill */
546 for (a = 0, b = 0; a < totframe; a++) {
547 if (a == 0) {
548 points[b++] = frames[a];
549 }
550
551 if (a && frames[a] - frames[a - 1] != 1) {
552 points[b++] = frames[a - 1];
553 points[b++] = frames[a];
554 }
555
556 if (a == totframe - 1) {
557 points[b++] = frames[a];
558 }
559 }
560
561 *r_totseg = totseg;
562 *r_points = points;
563
564 cache->totseg = totseg;
565 cache->points = points;
566 cache->proxy = proxy;
567 cache->render_flags = render_flags;
568 }
569
570 MEM_freeN(frames);
571 }
572}
573
574MovieCacheIter *IMB_moviecacheIter_new(MovieCache *cache)
575{
576 GHashIterator *iter;
577
578 check_unused_keys(cache);
579 iter = BLI_ghashIterator_new(cache->hash);
580
581 return (MovieCacheIter *)iter;
582}
583
584void IMB_moviecacheIter_free(MovieCacheIter *iter)
585{
587}
588
589bool IMB_moviecacheIter_done(MovieCacheIter *iter)
590{
592}
593
594void IMB_moviecacheIter_step(MovieCacheIter *iter)
595{
597}
598
599ImBuf *IMB_moviecacheIter_getImBuf(MovieCacheIter *iter)
600{
602 return item->ibuf;
603}
604
605void *IMB_moviecacheIter_getUserKey(MovieCacheIter *iter)
606{
608 return key->userkey;
609}
BLI_INLINE void * BLI_ghashIterator_getKey(GHashIterator *ghi) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.h:295
bool BLI_ghash_reinsert(GHash *gh, void *key, void *val, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition BLI_ghash.cc:712
void BLI_ghashIterator_step(GHashIterator *ghi)
Definition BLI_ghash.cc:911
void BLI_ghashIterator_free(GHashIterator *ghi)
Definition BLI_ghash.cc:925
bool(* GHashCmpFP)(const void *a, const void *b)
Definition BLI_ghash.h:33
BLI_INLINE void * BLI_ghashIterator_getValue(GHashIterator *ghi) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.h:299
#define GHASH_ITER(gh_iter_, ghash_)
Definition BLI_ghash.h:318
GHash * BLI_ghash_new(GHashHashFP hashfp, GHashCmpFP cmpfp, const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.cc:686
GHashIterator * BLI_ghashIterator_new(GHash *gh) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.cc:888
unsigned int(* GHashHashFP)(const void *key)
Definition BLI_ghash.h:31
unsigned int BLI_ghash_len(const GHash *gh) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.cc:702
bool BLI_ghash_remove(GHash *gh, const void *key, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition BLI_ghash.cc:787
void * BLI_ghash_lookup(const GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.cc:731
void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition BLI_ghash.cc:860
void BLI_ghashIterator_init(GHashIterator *ghi, GHash *gh)
Definition BLI_ghash.cc:895
BLI_INLINE bool BLI_ghashIterator_done(const GHashIterator *ghi) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.h:307
void * BLI_mempool_alloc(BLI_mempool *pool) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL ATTR_NONNULL(1)
@ BLI_MEMPOOL_NOP
void BLI_mempool_free(BLI_mempool *pool, void *addr) ATTR_NONNULL(1
BLI_mempool * BLI_mempool_create(unsigned int esize, unsigned int elem_num, unsigned int pchunk, unsigned int flag) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL
void BLI_mempool_destroy(BLI_mempool *pool) ATTR_NONNULL(1)
char * STRNCPY(char(&dst)[N], const char *src)
Definition BLI_string.h:693
unsigned int uint
void IMB_freeImBuf(ImBuf *ibuf)
void IMB_refImBuf(ImBuf *ibuf)
size_t IMB_get_size_in_memory(const ImBuf *ibuf)
@ IB_PERSISTENT
@ IB_BITMAPDIRTY
int(*)(void *last_userkey, void *priority_data) MovieCacheGetItemPriorityFP
void(*)(void *userkey, int *framenr, int *proxy, int *render_flags) MovieCacheGetKeyDataFP
void *(*)(void *userkey) MovieCacheGetPriorityDataFP
void(*)(void *priority_data) MovieCachePriorityDeleterFP
void MEM_CacheLimiter_ItemPriority_Func_set(MEM_CacheLimiterC *This, MEM_CacheLimiter_ItemPriority_Func item_priority_func)
void MEM_CacheLimiter_enforce_limits(MEM_CacheLimiterC *This)
void MEM_CacheLimiter_touch(MEM_CacheLimiterHandleC *handle)
void MEM_CacheLimiter_unref(MEM_CacheLimiterHandleC *handle)
void delete_MEM_CacheLimiter(MEM_CacheLimiterC *This)
void MEM_CacheLimiter_ItemDestroyable_Func_set(MEM_CacheLimiterC *This, MEM_CacheLimiter_ItemDestroyable_Func item_destroyable_func)
size_t MEM_CacheLimiter_get_memory_in_use(MEM_CacheLimiterC *This)
size_t MEM_CacheLimiter_get_maximum()
MEM_CacheLimiterC * new_MEM_CacheLimiter(MEM_CacheLimiter_Destruct_Func data_destructor, MEM_CacheLimiter_DataSize_Func data_size)
MEM_CacheLimiterHandleC * MEM_CacheLimiter_insert(MEM_CacheLimiterC *This, void *data)
void MEM_CacheLimiter_ref(MEM_CacheLimiterHandleC *handle)
void MEM_CacheLimiter_unmanage(MEM_CacheLimiterHandleC *handle)
struct MEM_CacheLimiter_s MEM_CacheLimiterC
struct MEM_CacheLimiterHandle_s MEM_CacheLimiterHandleC
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
volatile int lock
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
void * MEM_mallocN(size_t len, const char *str)
Definition mallocn.cc:128
void * MEM_calloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:123
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
static size_t mem_in_use
bool IMB_moviecache_put_if_possible(MovieCache *cache, void *userkey, ImBuf *ibuf)
MovieCacheIter * IMB_moviecacheIter_new(MovieCache *cache)
static std::recursive_mutex limitor_lock
Definition moviecache.cc:43
static size_t get_size_in_memory(ImBuf *ibuf)
void * IMB_moviecacheIter_getUserKey(MovieCacheIter *iter)
static bool moviecache_hashcmp(const void *av, const void *bv)
Definition moviecache.cc:90
static void moviecache_destructor(void *p)
void IMB_moviecache_free(MovieCache *cache)
bool IMB_moviecache_has_frame(MovieCache *cache, void *userkey)
void IMB_moviecache_cleanup(MovieCache *cache, bool(cleanup_check_cb)(ImBuf *ibuf, void *userkey, void *userdata), void *userdata)
static void check_unused_keys(MovieCache *cache)
ImBuf * IMB_moviecache_get(MovieCache *cache, void *userkey, bool *r_is_cached_empty)
static int get_item_priority(void *item_v, int default_priority)
void IMB_moviecacheIter_free(MovieCacheIter *iter)
bool IMB_moviecacheIter_done(MovieCacheIter *iter)
void IMB_moviecache_put(MovieCache *cache, void *userkey, ImBuf *ibuf)
static uint moviecache_hashhash(const void *keyv)
Definition moviecache.cc:83
static size_t get_item_size(void *p)
static int compare_int(const void *av, const void *bv)
void IMB_moviecache_set_getdata_callback(MovieCache *cache, MovieCacheGetKeyDataFP getdatafp)
static bool get_item_destroyable(void *item_v)
void IMB_moviecache_set_priority_callback(MovieCache *cache, MovieCacheGetPriorityDataFP getprioritydatafp, MovieCacheGetItemPriorityFP getitempriorityfp, MovieCachePriorityDeleterFP prioritydeleterfp)
void IMB_moviecacheIter_step(MovieCacheIter *iter)
static void do_moviecache_put(MovieCache *cache, void *userkey, ImBuf *ibuf, bool need_lock)
void IMB_moviecache_destruct()
void IMB_moviecache_init()
static void moviecache_keyfree(void *val)
Definition moviecache.cc:98
ImBuf * IMB_moviecacheIter_getImBuf(MovieCacheIter *iter)
static void moviecache_valfree(void *val)
void IMB_moviecache_get_cache_segments(MovieCache *cache, int proxy, int render_flags, int *r_totseg, int **r_points)
static MEM_CacheLimiterC * limitor
Definition moviecache.cc:37
MovieCache * IMB_moviecache_create(const char *name, int keysize, GHashHashFP hashfp, GHashCmpFP cmpfp)
#define PRINT(format,...)
Definition moviecache.cc:34
void IMB_moviecache_remove(MovieCache *cache, void *userkey)
static bool moviecache_hashcmp(const void *av, const void *bv)
Definition movieclip.cc:766
static uint moviecache_hashhash(const void *keyv)
Definition movieclip.cc:758
const char * name
MovieCache * cache_owner
Definition moviecache.cc:75
void * priority_data
Definition moviecache.cc:78
MEM_CacheLimiterHandleC * c_handle
Definition moviecache.cc:77
MovieCache * cache_owner
Definition moviecache.cc:70
BLI_mempool * keys_pool
Definition moviecache.cc:57
MovieCacheGetKeyDataFP getdatafp
Definition moviecache.cc:51
GHashHashFP hashfp
Definition moviecache.cc:49
BLI_mempool * userkeys_pool
Definition moviecache.cc:59
void * last_userkey
Definition moviecache.cc:63
MovieCacheGetItemPriorityFP getitempriorityfp
Definition moviecache.cc:54
MovieCachePriorityDeleterFP prioritydeleterfp
Definition moviecache.cc:55
int render_flags
Definition moviecache.cc:65
char name[64]
Definition moviecache.cc:46
BLI_mempool * items_pool
Definition moviecache.cc:58
GHashCmpFP cmpfp
Definition moviecache.cc:50
int * points
Definition moviecache.cc:65
GHash * hash
Definition moviecache.cc:48
MovieCacheGetPriorityDataFP getprioritydatafp
Definition moviecache.cc:53