diff options
author | Aditya Y Jeppu <quantimoney> | 2021-09-21 11:38:15 +0300 |
---|---|---|
committer | Richard Antalik <richardantalik@gmail.com> | 2021-09-21 11:55:04 +0300 |
commit | 997b5fe45dab8bd0e2976c8b673e56266134fc80 (patch) | |
tree | b8813b36decf96908507f6633cf909717bcfa534 /source/blender/sequencer/intern/image_cache.c | |
parent | fa2c1698b077f510175e79adf3dbf3e1602b1030 (diff) |
VSE strip thumbnails
Draw thumbnails as strip overlay. This works for movie and image strips.
To draw thumbnails, this overlay has to be enabled and strips must be
tall enough.
The thumbnails are loaded from source file using separate thread and
stored in cache.
Drawing code uses only images stored in cache, and if any is missing,
background rendering job is started. If job can not render thumbnail,
to prevent endless loop of creating job for missing image it sets
`SEQ_FLAG_SKIP_THUMBNAILS` bit of `Sequence` flag.
To prevent visual glitches during timeline panning and zooming, `View2D`
flag `V2D_IS_NAVIGATING` is implemented. If bit is set, drawing code
will look for set of evenly distributed thumbnails that should be
guaranteed to exist and also set of previously displayed thumbnails.
Due to volatile nature of cache these thumbnails can be missing anyway,
in which case no new thumbnails will be drawn for particular strip.
Cache capacity is limited to 5000 thumbnails and performs cleanup of
non visible images when limit is reached.
ref T89143
Reviewed By: ISS
Differential Revision: https://developer.blender.org/D12266
Diffstat (limited to 'source/blender/sequencer/intern/image_cache.c')
-rw-r--r-- | source/blender/sequencer/intern/image_cache.c | 81 |
1 files changed, 78 insertions, 3 deletions
diff --git a/source/blender/sequencer/intern/image_cache.c b/source/blender/sequencer/intern/image_cache.c index 86bd840ce31..86c198075e9 100644 --- a/source/blender/sequencer/intern/image_cache.c +++ b/source/blender/sequencer/intern/image_cache.c @@ -104,6 +104,7 @@ #define DCACHE_IMAGES_PER_FILE 100 #define DCACHE_CURRENT_VERSION 2 #define COLORSPACE_NAME_MAX 64 /* XXX: defined in imb intern */ +#define THUMB_CACHE_LIMIT 5000 typedef struct DiskCacheHeaderEntry { unsigned char encoding; @@ -148,6 +149,7 @@ typedef struct SeqCache { struct BLI_mempool *items_pool; struct SeqCacheKey *last_key; SeqDiskCache *disk_cache; + int thumbnail_count; } SeqCache; typedef struct SeqCacheItem { @@ -776,7 +778,7 @@ static float seq_cache_timeline_frame_to_frame_index(Sequence *seq, float timeli /* With raw images, map timeline_frame to strip input media frame range. This means that static * images or extended frame range of movies will only generate one cache entry. No special * treatment in converting frame index to timeline_frame is needed. */ - if (type == SEQ_CACHE_STORE_RAW) { + if (type == SEQ_CACHE_STORE_RAW || type == SEQ_CACHE_STORE_THUMBNAIL) { return seq_give_frame_index(seq, timeline_frame); } @@ -875,7 +877,7 @@ static void seq_cache_put_ex(Scene *scene, SeqCacheKey *key, ImBuf *ibuf) if (BLI_ghash_reinsert(cache->hash, key, item, seq_cache_keyfree, seq_cache_valfree)) { IMB_refImBuf(ibuf); - if (!key->is_temp_cache) { + if (!key->is_temp_cache || key->type != SEQ_CACHE_STORE_THUMBNAIL) { cache->last_key = key; } } @@ -1161,6 +1163,7 @@ static void seq_cache_create(Main *bmain, Scene *scene) cache->hash = BLI_ghash_new(seq_cache_hashhash, seq_cache_hashcmp, "SeqCache hash"); cache->last_key = NULL; cache->bmain = bmain; + cache->thumbnail_count = 0; BLI_mutex_init(&cache->iterator_mutex); scene->ed->cache = cache; @@ -1217,7 +1220,7 @@ void seq_cache_free_temp_cache(Scene *scene, short id, int timeline_frame) SeqCacheKey *key = BLI_ghashIterator_getKey(&gh_iter); BLI_ghashIterator_step(&gh_iter); - if (key->is_temp_cache && key->task_id == id) { + if (key->is_temp_cache && key->task_id == id && key->type != SEQ_CACHE_STORE_THUMBNAIL) { /* Use frame_index here to avoid freeing raw images if they are used for multiple frames. */ float frame_index = seq_cache_timeline_frame_to_frame_index( key->seq, timeline_frame, key->type); @@ -1278,6 +1281,7 @@ void SEQ_cache_cleanup(Scene *scene) BLI_ghash_remove(cache->hash, key, seq_cache_keyfree, seq_cache_valfree); } cache->last_key = NULL; + cache->thumbnail_count = 0; seq_cache_unlock(scene); } @@ -1345,6 +1349,46 @@ void seq_cache_cleanup_sequence(Scene *scene, seq_cache_unlock(scene); } +void seq_cache_thumbnail_cleanup(Scene *scene, rctf *view_area_safe) +{ + /* Add offsets to the left and right end to keep some frames in cache. */ + view_area_safe->xmax += 200; + view_area_safe->xmin -= 200; + view_area_safe->ymin -= 1; + view_area_safe->ymax += 1; + + SeqCache *cache = seq_cache_get_from_scene(scene); + if (!cache) { + return; + } + + GHashIterator gh_iter; + BLI_ghashIterator_init(&gh_iter, cache->hash); + while (!BLI_ghashIterator_done(&gh_iter)) { + SeqCacheKey *key = BLI_ghashIterator_getKey(&gh_iter); + BLI_ghashIterator_step(&gh_iter); + + const int frame_index = key->timeline_frame - key->seq->startdisp; + const int frame_step = SEQ_render_thumbnails_guaranteed_set_frame_step_get(key->seq); + const int relative_base_frame = round_fl_to_int((frame_index / (float)frame_step)) * + frame_step; + const int nearest_guaranted_absolute_frame = relative_base_frame + key->seq->startdisp; + + if (nearest_guaranted_absolute_frame == key->timeline_frame) { + continue; + } + + if ((key->type & SEQ_CACHE_STORE_THUMBNAIL) && + (key->timeline_frame > view_area_safe->xmax || + key->timeline_frame < view_area_safe->xmin || key->seq->machine > view_area_safe->ymax || + key->seq->machine < view_area_safe->ymin)) { + BLI_ghash_remove(cache->hash, key, seq_cache_keyfree, seq_cache_valfree); + cache->thumbnail_count--; + } + } + cache->last_key = NULL; +} + struct ImBuf *seq_cache_get(const SeqRenderData *context, Sequence *seq, float timeline_frame, @@ -1436,6 +1480,37 @@ bool seq_cache_put_if_possible( return false; } +void seq_cache_thumbnail_put( + const SeqRenderData *context, Sequence *seq, float timeline_frame, ImBuf *i, rctf *view_area) +{ + Scene *scene = context->scene; + + if (!scene->ed->cache) { + seq_cache_create(context->bmain, scene); + } + + seq_cache_lock(scene); + SeqCache *cache = seq_cache_get_from_scene(scene); + SeqCacheKey *key = seq_cache_allocate_key( + cache, context, seq, timeline_frame, SEQ_CACHE_STORE_THUMBNAIL); + + /* Prevent reinserting, it breaks cache key linking. */ + if (BLI_ghash_haskey(cache->hash, key)) { + seq_cache_unlock(scene); + return; + } + + /* Limit cache to THUMB_CACHE_LIMIT (5000) images stored. */ + if (cache->thumbnail_count >= THUMB_CACHE_LIMIT) { + rctf view_area_safe = *view_area; + seq_cache_thumbnail_cleanup(scene, &view_area_safe); + } + + seq_cache_put_ex(scene, key, i); + cache->thumbnail_count++; + seq_cache_unlock(scene); +} + void seq_cache_put( const SeqRenderData *context, Sequence *seq, float timeline_frame, int type, ImBuf *i) { |