Changeset View
Changeset View
Standalone View
Standalone View
source/blender/editors/space_sequencer/sequencer_thumbnails.c
| /* SPDX-License-Identifier: GPL-2.0-or-later | /* SPDX-License-Identifier: GPL-2.0-or-later | ||||
| * Copyright 2021 Blender Foundation. All rights reserved. */ | * Copyright 2021 Blender Foundation. All rights reserved. */ | ||||
| /** \file | /** \file | ||||
| * \ingroup spseq | * \ingroup spseq | ||||
| */ | */ | ||||
| #include "DNA_video_edit_types.h" | |||||
| #include "BLI_blenlib.h" | #include "BLI_blenlib.h" | ||||
| #include "BLI_ghash.h" | #include "BLI_ghash.h" | ||||
| #include "BLI_math.h" | #include "BLI_math.h" | ||||
| #include "BKE_context.h" | #include "BKE_context.h" | ||||
| #include "BKE_global.h" | #include "BKE_global.h" | ||||
| #include "BKE_scene.h" | #include "BKE_scene.h" | ||||
| Show All 16 Lines | |||||
| #include "MEM_guardedalloc.h" | #include "MEM_guardedalloc.h" | ||||
| /* Own include. */ | /* Own include. */ | ||||
| #include "sequencer_intern.h" | #include "sequencer_intern.h" | ||||
| typedef struct ThumbnailDrawJob { | typedef struct ThumbnailDrawJob { | ||||
| SeqRenderData context; | SeqRenderData context; | ||||
| GHash *sequences_ghash; | GHash *sequences_ghash; | ||||
| Scene *scene; | VideoEdit *video_edit; | ||||
| rctf *view_area; | rctf *view_area; | ||||
| float pixelx; | float pixelx; | ||||
| float pixely; | float pixely; | ||||
| float thumb_height; | float thumb_height; | ||||
| } ThumbnailDrawJob; | } ThumbnailDrawJob; | ||||
| typedef struct ThumbDataItem { | typedef struct ThumbDataItem { | ||||
| Sequence *seq_dupli; | Sequence *seq_dupli; | ||||
| Scene *scene; | VideoEdit *video_edit; | ||||
| } ThumbDataItem; | } ThumbDataItem; | ||||
| static void thumbnail_hash_data_free(void *val) | static void thumbnail_hash_data_free(void *val) | ||||
| { | { | ||||
| ThumbDataItem *item = val; | ThumbDataItem *item = val; | ||||
| SEQ_sequence_free(item->scene, item->seq_dupli); | SEQ_sequence_free(item->video_edit, item->seq_dupli); | ||||
| MEM_freeN(val); | MEM_freeN(val); | ||||
| } | } | ||||
| static void thumbnail_freejob(void *data) | static void thumbnail_freejob(void *data) | ||||
| { | { | ||||
| ThumbnailDrawJob *tj = data; | ThumbnailDrawJob *tj = data; | ||||
| BLI_ghash_free(tj->sequences_ghash, NULL, thumbnail_hash_data_free); | BLI_ghash_free(tj->sequences_ghash, NULL, thumbnail_hash_data_free); | ||||
| MEM_freeN(tj->view_area); | MEM_freeN(tj->view_area); | ||||
| MEM_freeN(tj); | MEM_freeN(tj); | ||||
| } | } | ||||
| static void thumbnail_endjob(void *data) | static void thumbnail_endjob(void *data) | ||||
| { | { | ||||
| ThumbnailDrawJob *tj = data; | ThumbnailDrawJob *tj = data; | ||||
| WM_main_add_notifier(NC_SCENE | ND_SEQUENCER, tj->scene); | WM_main_add_notifier(NC_VIDEO_EDIT | ND_SEQUENCER, tj->video_edit); | ||||
| } | } | ||||
| static bool check_seq_need_thumbnails(const Scene *scene, Sequence *seq, rctf *view_area) | static bool check_seq_need_thumbnails(const VideoEdit *video_edit, Sequence *seq, rctf *view_area) | ||||
| { | { | ||||
| if (!ELEM(seq->type, SEQ_TYPE_MOVIE, SEQ_TYPE_IMAGE)) { | if (!ELEM(seq->type, SEQ_TYPE_MOVIE, SEQ_TYPE_IMAGE)) { | ||||
| return false; | return false; | ||||
| } | } | ||||
| if (min_ii(SEQ_time_left_handle_frame_get(scene, seq), SEQ_time_start_frame_get(seq)) > | if (min_ii(SEQ_time_left_handle_frame_get(video_edit, seq), SEQ_time_start_frame_get(seq)) > | ||||
| view_area->xmax) { | view_area->xmax) { | ||||
| return false; | return false; | ||||
| } | } | ||||
| if (max_ii(SEQ_time_right_handle_frame_get(scene, seq), | if (max_ii(SEQ_time_right_handle_frame_get(video_edit, seq), | ||||
| SEQ_time_content_end_frame_get(scene, seq)) < view_area->xmin) { | SEQ_time_content_end_frame_get(video_edit, seq)) < view_area->xmin) { | ||||
| return false; | return false; | ||||
| } | } | ||||
| if (seq->machine + 1.0f < view_area->ymin) { | if (seq->machine + 1.0f < view_area->ymin) { | ||||
| return false; | return false; | ||||
| } | } | ||||
| if (seq->machine > view_area->ymax) { | if (seq->machine > view_area->ymax) { | ||||
| return false; | return false; | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 41 Lines • ▼ Show 20 Lines | |||||
| } | } | ||||
| static void thumbnail_start_job(void *data, | static void thumbnail_start_job(void *data, | ||||
| short *stop, | short *stop, | ||||
| short *UNUSED(do_update), | short *UNUSED(do_update), | ||||
| float *UNUSED(progress)) | float *UNUSED(progress)) | ||||
| { | { | ||||
| ThumbnailDrawJob *tj = data; | ThumbnailDrawJob *tj = data; | ||||
| const Scene *scene = tj->scene; | const VideoEdit *video_edit = tj->video_edit; | ||||
| float frame_step; | float frame_step; | ||||
| GHashIterator gh_iter; | GHashIterator gh_iter; | ||||
| /* First pass: render visible images. */ | /* First pass: render visible images. */ | ||||
| BLI_ghashIterator_init(&gh_iter, tj->sequences_ghash); | BLI_ghashIterator_init(&gh_iter, tj->sequences_ghash); | ||||
| while (!BLI_ghashIterator_done(&gh_iter) & !*stop) { | while (!BLI_ghashIterator_done(&gh_iter) & !*stop) { | ||||
| Sequence *seq_orig = BLI_ghashIterator_getKey(&gh_iter); | Sequence *seq_orig = BLI_ghashIterator_getKey(&gh_iter); | ||||
| ThumbDataItem *val = BLI_ghash_lookup(tj->sequences_ghash, seq_orig); | ThumbDataItem *val = BLI_ghash_lookup(tj->sequences_ghash, seq_orig); | ||||
| if (check_seq_need_thumbnails(scene, seq_orig, tj->view_area)) { | if (check_seq_need_thumbnails(video_edit, seq_orig, tj->view_area)) { | ||||
| seq_get_thumb_image_dimensions( | seq_get_thumb_image_dimensions( | ||||
| val->seq_dupli, tj->pixelx, tj->pixely, &frame_step, tj->thumb_height, NULL, NULL); | val->seq_dupli, tj->pixelx, tj->pixely, &frame_step, tj->thumb_height, NULL, NULL); | ||||
| SEQ_render_thumbnails( | SEQ_render_thumbnails( | ||||
| &tj->context, val->seq_dupli, seq_orig, frame_step, tj->view_area, stop); | &tj->context, val->seq_dupli, seq_orig, frame_step, tj->view_area, stop); | ||||
| SEQ_relations_sequence_free_anim(val->seq_dupli); | SEQ_relations_sequence_free_anim(val->seq_dupli); | ||||
| } | } | ||||
| BLI_ghashIterator_step(&gh_iter); | BLI_ghashIterator_step(&gh_iter); | ||||
| } | } | ||||
| /* Second pass: render "guaranteed" set of images. */ | /* Second pass: render "guaranteed" set of images. */ | ||||
| BLI_ghashIterator_init(&gh_iter, tj->sequences_ghash); | BLI_ghashIterator_init(&gh_iter, tj->sequences_ghash); | ||||
| while (!BLI_ghashIterator_done(&gh_iter) & !*stop) { | while (!BLI_ghashIterator_done(&gh_iter) & !*stop) { | ||||
| Sequence *seq_orig = BLI_ghashIterator_getKey(&gh_iter); | Sequence *seq_orig = BLI_ghashIterator_getKey(&gh_iter); | ||||
| ThumbDataItem *val = BLI_ghash_lookup(tj->sequences_ghash, seq_orig); | ThumbDataItem *val = BLI_ghash_lookup(tj->sequences_ghash, seq_orig); | ||||
| if (check_seq_need_thumbnails(scene, seq_orig, tj->view_area)) { | if (check_seq_need_thumbnails(video_edit, seq_orig, tj->view_area)) { | ||||
| seq_get_thumb_image_dimensions( | seq_get_thumb_image_dimensions( | ||||
| val->seq_dupli, tj->pixelx, tj->pixely, &frame_step, tj->thumb_height, NULL, NULL); | val->seq_dupli, tj->pixelx, tj->pixely, &frame_step, tj->thumb_height, NULL, NULL); | ||||
| SEQ_render_thumbnails_base_set(&tj->context, val->seq_dupli, seq_orig, tj->view_area, stop); | SEQ_render_thumbnails_base_set(&tj->context, val->seq_dupli, seq_orig, tj->view_area, stop); | ||||
| SEQ_relations_sequence_free_anim(val->seq_dupli); | SEQ_relations_sequence_free_anim(val->seq_dupli); | ||||
| } | } | ||||
| BLI_ghashIterator_step(&gh_iter); | BLI_ghashIterator_step(&gh_iter); | ||||
| } | } | ||||
| } | } | ||||
| static SeqRenderData sequencer_thumbnail_context_init(const bContext *C) | static SeqRenderData sequencer_thumbnail_context_init(const bContext *C) | ||||
| { | { | ||||
| struct Main *bmain = CTX_data_main(C); | struct Main *bmain = CTX_data_main(C); | ||||
| struct Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); | struct Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); | ||||
| Scene *scene = CTX_data_scene(C); | VideoEdit *video_edit = CTX_data_video_edit(C); | ||||
| SpaceSeq *sseq = CTX_wm_space_seq(C); | SpaceSeq *sseq = CTX_wm_space_seq(C); | ||||
| SeqRenderData context = {0}; | SeqRenderData context = {0}; | ||||
| /* Taking rectx and recty as 0 as dimensions not known here, and context is used to calculate | /* Taking rectx and recty as 0 as dimensions not known here, and context is used to calculate | ||||
| * hash key but not necessary as other variables of SeqRenderData are unique enough. */ | * hash key but not necessary as other variables of SeqRenderData are unique enough. */ | ||||
| SEQ_render_new_render_data(bmain, depsgraph, scene, 0, 0, sseq->render_size, false, &context); | SEQ_render_new_render_data(bmain, depsgraph, video_edit, 0, 0, sseq->render_size, false, &context); | ||||
| context.view_id = BKE_scene_multiview_view_id_get(&scene->r, STEREO_LEFT_NAME); | context.view_id = BKE_scene_multiview_view_id_get(&video_edit->r, STEREO_LEFT_NAME); | ||||
| context.use_proxies = false; | context.use_proxies = false; | ||||
| return context; | return context; | ||||
| } | } | ||||
| static GHash *sequencer_thumbnail_ghash_init(const bContext *C, View2D *v2d, Editing *ed) | static GHash *sequencer_thumbnail_ghash_init(const bContext *C, View2D *v2d) | ||||
| { | { | ||||
| Scene *scene = CTX_data_scene(C); | VideoEdit *video_edit = CTX_data_video_edit(C); | ||||
| /* Set the data for thumbnail caching job. */ | /* Set the data for thumbnail caching job. */ | ||||
| GHash *thumb_data_hash = BLI_ghash_ptr_new("seq_duplicates_and_origs"); | GHash *thumb_data_hash = BLI_ghash_ptr_new("seq_duplicates_and_origs"); | ||||
| LISTBASE_FOREACH (Sequence *, seq, ed->seqbasep) { | LISTBASE_FOREACH (Sequence *, seq, video_edit->seqbasep) { | ||||
| ThumbDataItem *val_need_update = BLI_ghash_lookup(thumb_data_hash, seq); | ThumbDataItem *val_need_update = BLI_ghash_lookup(thumb_data_hash, seq); | ||||
| if (val_need_update == NULL && check_seq_need_thumbnails(scene, seq, &v2d->cur)) { | if (val_need_update == NULL && check_seq_need_thumbnails(video_edit, seq, &v2d->cur)) { | ||||
| ThumbDataItem *val = MEM_callocN(sizeof(ThumbDataItem), "Thumbnail Hash Values"); | ThumbDataItem *val = MEM_callocN(sizeof(ThumbDataItem), "Thumbnail Hash Values"); | ||||
| val->seq_dupli = SEQ_sequence_dupli_recursive(scene, scene, NULL, seq, 0); | val->seq_dupli = SEQ_sequence_dupli_recursive(NULL, NULL, NULL, seq, 0); | ||||
| val->scene = scene; | val->video_edit = video_edit; | ||||
| BLI_ghash_insert(thumb_data_hash, seq, val); | BLI_ghash_insert(thumb_data_hash, seq, val); | ||||
| } | } | ||||
| else { | else { | ||||
| if (val_need_update != NULL) { | if (val_need_update != NULL) { | ||||
| val_need_update->seq_dupli->start = seq->start; | val_need_update->seq_dupli->start = seq->start; | ||||
| val_need_update->seq_dupli->startdisp = SEQ_time_left_handle_frame_get(scene, seq); | val_need_update->seq_dupli->startdisp = SEQ_time_left_handle_frame_get(video_edit, seq); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| return thumb_data_hash; | return thumb_data_hash; | ||||
| } | } | ||||
| static void sequencer_thumbnail_init_job(const bContext *C, | static void sequencer_thumbnail_init_job(const bContext *C, | ||||
| View2D *v2d, | View2D *v2d, | ||||
| Editing *ed, | VideoEdit *video_edit, | ||||
| float thumb_height) | float thumb_height) | ||||
| { | { | ||||
| wmJob *wm_job; | wmJob *wm_job; | ||||
| ThumbnailDrawJob *tj = NULL; | ThumbnailDrawJob *tj = NULL; | ||||
| ScrArea *area = CTX_wm_area(C); | ScrArea *area = CTX_wm_area(C); | ||||
| wm_job = WM_jobs_get(CTX_wm_manager(C), | wm_job = WM_jobs_get(CTX_wm_manager(C), | ||||
| CTX_wm_window(C), | CTX_wm_window(C), | ||||
| CTX_data_scene(C), | video_edit, | ||||
| "Draw Thumbnails", | "Draw Thumbnails", | ||||
| 0, | 0, | ||||
| WM_JOB_TYPE_SEQ_DRAW_THUMBNAIL); | WM_JOB_TYPE_SEQ_DRAW_THUMBNAIL); | ||||
| /* Get the thumbnail job if it exists. */ | /* Get the thumbnail job if it exists. */ | ||||
| tj = WM_jobs_customdata_get(wm_job); | tj = WM_jobs_customdata_get(wm_job); | ||||
| if (!tj) { | if (!tj) { | ||||
| tj = MEM_callocN(sizeof(ThumbnailDrawJob), "Thumbnail cache job"); | tj = MEM_callocN(sizeof(ThumbnailDrawJob), "Thumbnail cache job"); | ||||
| /* Duplicate value of v2d->cur and v2d->tot to have module separation. */ | /* Duplicate value of v2d->cur and v2d->tot to have module separation. */ | ||||
| rctf *view_area = MEM_callocN(sizeof(struct rctf), "viewport area"); | rctf *view_area = MEM_callocN(sizeof(struct rctf), "viewport area"); | ||||
| view_area->xmax = v2d->cur.xmax; | view_area->xmax = v2d->cur.xmax; | ||||
| view_area->xmin = v2d->cur.xmin; | view_area->xmin = v2d->cur.xmin; | ||||
| view_area->ymax = v2d->cur.ymax; | view_area->ymax = v2d->cur.ymax; | ||||
| view_area->ymin = v2d->cur.ymin; | view_area->ymin = v2d->cur.ymin; | ||||
| tj->scene = CTX_data_scene(C); | tj->video_edit = CTX_data_video_edit(C); | ||||
| tj->view_area = view_area; | tj->view_area = view_area; | ||||
| tj->context = sequencer_thumbnail_context_init(C); | tj->context = sequencer_thumbnail_context_init(C); | ||||
| tj->sequences_ghash = sequencer_thumbnail_ghash_init(C, v2d, ed); | tj->sequences_ghash = sequencer_thumbnail_ghash_init(C, v2d); | ||||
| tj->pixelx = BLI_rctf_size_x(&v2d->cur) / BLI_rcti_size_x(&v2d->mask); | tj->pixelx = BLI_rctf_size_x(&v2d->cur) / BLI_rcti_size_x(&v2d->mask); | ||||
| tj->pixely = BLI_rctf_size_y(&v2d->cur) / BLI_rcti_size_y(&v2d->mask); | tj->pixely = BLI_rctf_size_y(&v2d->cur) / BLI_rcti_size_y(&v2d->mask); | ||||
| tj->thumb_height = thumb_height; | tj->thumb_height = thumb_height; | ||||
| WM_jobs_customdata_set(wm_job, tj, thumbnail_freejob); | WM_jobs_customdata_set(wm_job, tj, thumbnail_freejob); | ||||
| WM_jobs_timer(wm_job, 0.1, NC_SCENE | ND_SEQUENCER, NC_SCENE | ND_SEQUENCER); | WM_jobs_timer(wm_job, 0.1, NC_VIDEO_EDIT | ND_SEQUENCER, NC_VIDEO_EDIT | ND_SEQUENCER); | ||||
| WM_jobs_callbacks(wm_job, thumbnail_start_job, NULL, NULL, thumbnail_endjob); | WM_jobs_callbacks(wm_job, thumbnail_start_job, NULL, NULL, thumbnail_endjob); | ||||
| } | } | ||||
| if (!WM_jobs_is_running(wm_job)) { | if (!WM_jobs_is_running(wm_job)) { | ||||
| G.is_break = false; | G.is_break = false; | ||||
| WM_jobs_start(CTX_wm_manager(C), wm_job); | WM_jobs_start(CTX_wm_manager(C), wm_job); | ||||
| } | } | ||||
| else { | else { | ||||
| WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, NULL); | WM_event_add_notifier(C, NC_VIDEO_EDIT | ND_SEQUENCER, NULL); | ||||
| } | } | ||||
| ED_area_tag_redraw(area); | ED_area_tag_redraw(area); | ||||
| } | } | ||||
| static bool sequencer_thumbnail_v2d_is_navigating(const bContext *C) | static bool sequencer_thumbnail_v2d_is_navigating(const bContext *C) | ||||
| { | { | ||||
| ARegion *region = CTX_wm_region(C); | ARegion *region = CTX_wm_region(C); | ||||
| View2D *v2d = ®ion->v2d; | View2D *v2d = ®ion->v2d; | ||||
| return (v2d->flag & V2D_IS_NAVIGATING) != 0; | return (v2d->flag & V2D_IS_NAVIGATING) != 0; | ||||
| } | } | ||||
| static void sequencer_thumbnail_start_job_if_necessary( | static void sequencer_thumbnail_start_job_if_necessary(const bContext *C, | ||||
| const bContext *C, Editing *ed, View2D *v2d, bool thumbnail_is_missing, float thumb_height) | VideoEdit *video_edit, | ||||
| View2D *v2d, | |||||
| bool thumbnail_is_missing, | |||||
| float thumb_height) | |||||
| { | { | ||||
| SpaceSeq *sseq = CTX_wm_space_seq(C); | SpaceSeq *sseq = CTX_wm_space_seq(C); | ||||
| if (sequencer_thumbnail_v2d_is_navigating(C)) { | if (sequencer_thumbnail_v2d_is_navigating(C)) { | ||||
| WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, NULL); | WM_event_add_notifier(C, NC_VIDEO_EDIT | ND_SEQUENCER, NULL); | ||||
| return; | return; | ||||
| } | } | ||||
| /* During rendering, cache is wiped, it doesn't make sense to render thumbnails. */ | /* During rendering, cache is wiped, it doesn't make sense to render thumbnails. */ | ||||
| if (G.is_rendering) { | if (G.is_rendering) { | ||||
| return; | return; | ||||
| } | } | ||||
| /* Job start requested, but over area which has been processed. Unless `thumbnail_is_missing` is | /* Job start requested, but over area which has been processed. Unless `thumbnail_is_missing` is | ||||
| * true, ignore this request as all images are in view. */ | * true, ignore this request as all images are in view. */ | ||||
| if (v2d->cur.xmax == sseq->runtime.last_thumbnail_area.xmax && | if (v2d->cur.xmax == sseq->runtime.last_thumbnail_area.xmax && | ||||
| v2d->cur.ymax == sseq->runtime.last_thumbnail_area.ymax && !thumbnail_is_missing) { | v2d->cur.ymax == sseq->runtime.last_thumbnail_area.ymax && !thumbnail_is_missing) { | ||||
| return; | return; | ||||
| } | } | ||||
| /* Stop the job first as view has changed. Pointless to continue old job. */ | /* Stop the job first as view has changed. Pointless to continue old job. */ | ||||
| if (v2d->cur.xmax != sseq->runtime.last_thumbnail_area.xmax || | if (v2d->cur.xmax != sseq->runtime.last_thumbnail_area.xmax || | ||||
| v2d->cur.ymax != sseq->runtime.last_thumbnail_area.ymax) { | v2d->cur.ymax != sseq->runtime.last_thumbnail_area.ymax) { | ||||
| WM_jobs_stop(CTX_wm_manager(C), NULL, thumbnail_start_job); | WM_jobs_stop(CTX_wm_manager(C), NULL, thumbnail_start_job); | ||||
| } | } | ||||
| sequencer_thumbnail_init_job(C, v2d, ed, thumb_height); | sequencer_thumbnail_init_job(C, v2d, video_edit, thumb_height); | ||||
| sseq->runtime.last_thumbnail_area = v2d->cur; | sseq->runtime.last_thumbnail_area = v2d->cur; | ||||
| } | } | ||||
| void last_displayed_thumbnails_list_free(void *val) | void last_displayed_thumbnails_list_free(void *val) | ||||
| { | { | ||||
| BLI_gset_free(val, NULL); | BLI_gset_free(val, NULL); | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 45 Lines • ▼ Show 20 Lines | if (diff < best_diff) { | ||||
| best_diff = diff; | best_diff = diff; | ||||
| best_frame = frame; | best_frame = frame; | ||||
| } | } | ||||
| BLI_gsetIterator_step(&gset_iter); | BLI_gsetIterator_step(&gset_iter); | ||||
| } | } | ||||
| return best_frame; | return best_frame; | ||||
| } | } | ||||
| static int sequencer_thumbnail_closest_guaranteed_frame_get(struct Scene *scene, | static int sequencer_thumbnail_closest_guaranteed_frame_get(VideoEdit *video_edit, | ||||
| Sequence *seq, | Sequence *seq, | ||||
| int timeline_frame) | int timeline_frame) | ||||
| { | { | ||||
| if (timeline_frame <= SEQ_time_left_handle_frame_get(scene, seq)) { | if (timeline_frame <= SEQ_time_left_handle_frame_get(video_edit, seq)) { | ||||
| return SEQ_time_left_handle_frame_get(scene, seq); | return SEQ_time_left_handle_frame_get(video_edit, seq); | ||||
| } | } | ||||
| /* Set of "guaranteed" thumbnails. */ | /* Set of "guaranteed" thumbnails. */ | ||||
| const int frame_index = timeline_frame - SEQ_time_left_handle_frame_get(scene, seq); | const int frame_index = timeline_frame - SEQ_time_left_handle_frame_get(video_edit, seq); | ||||
| const int frame_step = SEQ_render_thumbnails_guaranteed_set_frame_step_get(scene, seq); | const int frame_step = SEQ_render_thumbnails_guaranteed_set_frame_step_get(video_edit, seq); | ||||
| const int relative_base_frame = round_fl_to_int(frame_index / (float)frame_step) * frame_step; | 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 + | const int nearest_guaranted_absolute_frame = relative_base_frame + | ||||
| SEQ_time_left_handle_frame_get(scene, seq); | SEQ_time_left_handle_frame_get(video_edit, seq); | ||||
| return nearest_guaranted_absolute_frame; | return nearest_guaranted_absolute_frame; | ||||
| } | } | ||||
| static ImBuf *sequencer_thumbnail_closest_from_memory(const SeqRenderData *context, | static ImBuf *sequencer_thumbnail_closest_from_memory(const SeqRenderData *context, | ||||
| Sequence *seq, | Sequence *seq, | ||||
| int timeline_frame, | int timeline_frame, | ||||
| GSet *previously_displayed, | GSet *previously_displayed, | ||||
| rcti *crop, | rcti *crop, | ||||
| bool clipped) | bool clipped) | ||||
| { | { | ||||
| int frame_previous = sequencer_thumbnail_closest_previous_frame_get(timeline_frame, | int frame_previous = sequencer_thumbnail_closest_previous_frame_get(timeline_frame, | ||||
| previously_displayed); | previously_displayed); | ||||
| ImBuf *ibuf_previous = SEQ_get_thumbnail(context, seq, frame_previous, crop, clipped); | ImBuf *ibuf_previous = SEQ_get_thumbnail(context, seq, frame_previous, crop, clipped); | ||||
| int frame_guaranteed = sequencer_thumbnail_closest_guaranteed_frame_get( | int frame_guaranteed = sequencer_thumbnail_closest_guaranteed_frame_get( | ||||
| context->scene, seq, timeline_frame); | context->video_edit, seq, timeline_frame); | ||||
| ImBuf *ibuf_guaranteed = SEQ_get_thumbnail(context, seq, frame_guaranteed, crop, clipped); | ImBuf *ibuf_guaranteed = SEQ_get_thumbnail(context, seq, frame_guaranteed, crop, clipped); | ||||
| ImBuf *closest_in_memory = NULL; | ImBuf *closest_in_memory = NULL; | ||||
| if (ibuf_previous && ibuf_guaranteed) { | if (ibuf_previous && ibuf_guaranteed) { | ||||
| if (abs(frame_previous - timeline_frame) < abs(frame_guaranteed - timeline_frame)) { | if (abs(frame_previous - timeline_frame) < abs(frame_guaranteed - timeline_frame)) { | ||||
| IMB_freeImBuf(ibuf_guaranteed); | IMB_freeImBuf(ibuf_guaranteed); | ||||
| closest_in_memory = ibuf_previous; | closest_in_memory = ibuf_previous; | ||||
| Show All 12 Lines | if (ibuf_guaranteed == NULL) { | ||||
| closest_in_memory = ibuf_previous; | closest_in_memory = ibuf_previous; | ||||
| } | } | ||||
| return closest_in_memory; | return closest_in_memory; | ||||
| } | } | ||||
| void draw_seq_strip_thumbnail(View2D *v2d, | void draw_seq_strip_thumbnail(View2D *v2d, | ||||
| const bContext *C, | const bContext *C, | ||||
| Scene *scene, | VideoEdit *video_edit, | ||||
| Sequence *seq, | Sequence *seq, | ||||
| float y1, | float y1, | ||||
| float y2, | float y2, | ||||
| float pixelx, | float pixelx, | ||||
| float pixely) | float pixely) | ||||
| { | { | ||||
| bool clipped = false; | bool clipped = false; | ||||
| float image_height, image_width, thumb_width; | float image_height, image_width, thumb_width; | ||||
| Show All 17 Lines | void draw_seq_strip_thumbnail(View2D *v2d, | ||||
| const float thumb_height = y2 - y1; | const float thumb_height = y2 - y1; | ||||
| seq_get_thumb_image_dimensions( | seq_get_thumb_image_dimensions( | ||||
| seq, pixelx, pixely, &thumb_width, thumb_height, &image_width, &image_height); | seq, pixelx, pixely, &thumb_width, thumb_height, &image_width, &image_height); | ||||
| float thumb_y_end = y1 + thumb_height; | float thumb_y_end = y1 + thumb_height; | ||||
| float cut_off = 0; | float cut_off = 0; | ||||
| float upper_thumb_bound = SEQ_time_has_right_still_frames(scene, seq) ? | float upper_thumb_bound = SEQ_time_has_right_still_frames(video_edit, seq) ? | ||||
| (seq->start + seq->len) : | (seq->start + seq->len) : | ||||
| SEQ_time_right_handle_frame_get(scene, seq); | SEQ_time_right_handle_frame_get(video_edit, seq); | ||||
| if (seq->type == SEQ_TYPE_IMAGE) { | if (seq->type == SEQ_TYPE_IMAGE) { | ||||
| upper_thumb_bound = SEQ_time_right_handle_frame_get(scene, seq); | upper_thumb_bound = SEQ_time_right_handle_frame_get(video_edit, seq); | ||||
| } | } | ||||
| float timeline_frame = SEQ_render_thumbnail_first_frame_get(scene, seq, thumb_width, &v2d->cur); | float timeline_frame = SEQ_render_thumbnail_first_frame_get( | ||||
| video_edit, seq, thumb_width, &v2d->cur); | |||||
| float thumb_x_end; | float thumb_x_end; | ||||
| GSet *last_displayed_thumbnails = last_displayed_thumbnails_list_ensure(C, seq); | GSet *last_displayed_thumbnails = last_displayed_thumbnails_list_ensure(C, seq); | ||||
| /* Cleanup thumbnail list outside of rendered range, which is cleaned up one by one to prevent | /* Cleanup thumbnail list outside of rendered range, which is cleaned up one by one to prevent | ||||
| * flickering after zooming. */ | * flickering after zooming. */ | ||||
| if (!sequencer_thumbnail_v2d_is_navigating(C)) { | if (!sequencer_thumbnail_v2d_is_navigating(C)) { | ||||
| last_displayed_thumbnails_list_cleanup(last_displayed_thumbnails, -FLT_MAX, timeline_frame); | last_displayed_thumbnails_list_cleanup(last_displayed_thumbnails, -FLT_MAX, timeline_frame); | ||||
| } | } | ||||
| /* Start drawing. */ | /* Start drawing. */ | ||||
| while (timeline_frame < upper_thumb_bound) { | while (timeline_frame < upper_thumb_bound) { | ||||
| thumb_x_end = timeline_frame + thumb_width; | thumb_x_end = timeline_frame + thumb_width; | ||||
| clipped = false; | clipped = false; | ||||
| /* Checks to make sure that thumbs are loaded only when in view and within the confines of the | /* Checks to make sure that thumbs are loaded only when in view and within the confines of the | ||||
| * strip. Some may not be required but better to have conditions for safety as x1 here is | * strip. Some may not be required but better to have conditions for safety as x1 here is | ||||
| * point to start caching from and not drawing. */ | * point to start caching from and not drawing. */ | ||||
| if (timeline_frame > v2d->cur.xmax) { | if (timeline_frame > v2d->cur.xmax) { | ||||
| break; | break; | ||||
| } | } | ||||
| /* Set the clipping bound to show the left handle moving over thumbs and not shift thumbs. */ | /* Set the clipping bound to show the left handle moving over thumbs and not shift thumbs. */ | ||||
| if (IN_RANGE_INCL(SEQ_time_left_handle_frame_get(scene, seq), timeline_frame, thumb_x_end)) { | if (IN_RANGE_INCL( | ||||
| cut_off = SEQ_time_left_handle_frame_get(scene, seq) - timeline_frame; | SEQ_time_left_handle_frame_get(video_edit, seq), timeline_frame, thumb_x_end)) { | ||||
| cut_off = SEQ_time_left_handle_frame_get(video_edit, seq) - timeline_frame; | |||||
| clipped = true; | clipped = true; | ||||
| } | } | ||||
| /* Clip if full thumbnail cannot be displayed. */ | /* Clip if full thumbnail cannot be displayed. */ | ||||
| if (thumb_x_end > (upper_thumb_bound)) { | if (thumb_x_end > (upper_thumb_bound)) { | ||||
| thumb_x_end = upper_thumb_bound; | thumb_x_end = upper_thumb_bound; | ||||
| clipped = true; | clipped = true; | ||||
| if (thumb_x_end - timeline_frame < 1) { | if (thumb_x_end - timeline_frame < 1) { | ||||
| Show All 10 Lines | if (cropx_max == (thumb_x_end - timeline_frame)) { | ||||
| cropx_max = cropx_max + 1; | cropx_max = cropx_max + 1; | ||||
| } | } | ||||
| BLI_rcti_init(&crop, (int)(cropx_min), (int)cropx_max, 0, (int)(image_height)-1); | BLI_rcti_init(&crop, (int)(cropx_min), (int)cropx_max, 0, (int)(image_height)-1); | ||||
| /* Get the image. */ | /* Get the image. */ | ||||
| ImBuf *ibuf = SEQ_get_thumbnail(&context, seq, timeline_frame, &crop, clipped); | ImBuf *ibuf = SEQ_get_thumbnail(&context, seq, timeline_frame, &crop, clipped); | ||||
| if (!ibuf) { | if (!ibuf) { | ||||
| sequencer_thumbnail_start_job_if_necessary(C, scene->ed, v2d, true, thumb_height); | sequencer_thumbnail_start_job_if_necessary(C, video_edit, v2d, true, thumb_height); | ||||
| ibuf = sequencer_thumbnail_closest_from_memory( | ibuf = sequencer_thumbnail_closest_from_memory( | ||||
| &context, seq, timeline_frame, last_displayed_thumbnails, &crop, clipped); | &context, seq, timeline_frame, last_displayed_thumbnails, &crop, clipped); | ||||
| } | } | ||||
| /* Store recently rendered frames, so they can be reused when zooming. */ | /* Store recently rendered frames, so they can be reused when zooming. */ | ||||
| else if (!sequencer_thumbnail_v2d_is_navigating(C)) { | else if (!sequencer_thumbnail_v2d_is_navigating(C)) { | ||||
| /* Clear images in frame range occupied by new thumbnail. */ | /* Clear images in frame range occupied by new thumbnail. */ | ||||
| last_displayed_thumbnails_list_cleanup( | last_displayed_thumbnails_list_cleanup( | ||||
| Show All 33 Lines | ED_draw_imbuf_ctx_clipping(C, | ||||
| y1, | y1, | ||||
| thumb_x_end, | thumb_x_end, | ||||
| thumb_y_end, | thumb_y_end, | ||||
| zoom_x, | zoom_x, | ||||
| zoom_y); | zoom_y); | ||||
| IMB_freeImBuf(ibuf); | IMB_freeImBuf(ibuf); | ||||
| GPU_blend(GPU_BLEND_NONE); | GPU_blend(GPU_BLEND_NONE); | ||||
| cut_off = 0; | cut_off = 0; | ||||
| timeline_frame = SEQ_render_thumbnail_next_frame_get(scene, seq, timeline_frame, thumb_width); | timeline_frame = SEQ_render_thumbnail_next_frame_get(video_edit, seq, timeline_frame, thumb_width); | ||||
| } | } | ||||
| last_displayed_thumbnails_list_cleanup(last_displayed_thumbnails, timeline_frame, FLT_MAX); | last_displayed_thumbnails_list_cleanup(last_displayed_thumbnails, timeline_frame, FLT_MAX); | ||||
| } | } | ||||