Blender V4.5
strip_relations.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
2 * SPDX-FileCopyrightText: 2003-2009 Blender Authors
3 * SPDX-FileCopyrightText: 2005-2006 Peter Schlaile <peter [at] schlaile [dot] de>
4 *
5 * SPDX-License-Identifier: GPL-2.0-or-later */
6
10
11#include "DNA_scene_types.h"
12#include "DNA_sequence_types.h"
13
14#include "BLI_ghash.h"
15#include "BLI_listbase.h"
16#include "BLI_math_base.h"
17#include "BLI_session_uid.h"
18
19#include "BKE_main.hh"
20#include "BKE_report.hh"
21
22#include "DEG_depsgraph.hh"
23
24#include "MOV_read.hh"
25
26#include "SEQ_iterator.hh"
27#include "SEQ_prefetch.hh"
28#include "SEQ_relations.hh"
29#include "SEQ_sequencer.hh"
31#include "SEQ_time.hh"
32#include "SEQ_utils.hh"
33
37#include "effects/effects.hh"
38#include "sequencer.hh"
39#include "utils.hh"
40
41namespace blender::seq {
42
43bool relation_is_effect_of_strip(const Strip *effect, const Strip *input)
44{
45 return ELEM(input, effect->input1, effect->input2);
46}
47
55
60
62{
64}
65
66bool is_cache_full(const Scene *scene)
67{
68 size_t cache_limit = size_t(U.memcachelimit) * 1024 * 1024;
70 cache_limit;
71}
72
73static void invalidate_final_cache_strip_range(Scene *scene, const Strip *strip)
74{
75 const int strip_left = time_left_handle_frame_get(scene, strip);
76 const int strip_right = time_right_handle_frame_get(scene, strip);
77 final_image_cache_invalidate_frame_range(scene, strip_left, strip_right);
78}
79
81{
82 Strip *meta = lookup_meta_by_strip(editing_get(scene), strip);
83 if (meta == nullptr) {
84 return;
85 }
86
88}
89
91{
93 relations_invalidate_cache(scene, strip);
94}
95
97{
98 if (strip->effectdata && strip->type == STRIP_TYPE_SPEED) {
100 }
101
103
105 intra_frame_cache_invalidate(scene, strip);
107
108 /* Needed to update VSE sound. */
110 prefetch_stop(scene);
111}
112
113void relations_invalidate_scene_strips(const Main *bmain, const Scene *scene_target)
114{
115 LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
116 if (scene->ed != nullptr) {
117 for (Strip *strip : lookup_strips_by_scene(editing_get(scene), scene_target)) {
118 relations_invalidate_cache_raw(scene, strip);
119 }
120 }
121 }
122}
123
124static void invalidate_movieclip_strips(Scene *scene, MovieClip *clip_target, ListBase *seqbase)
125{
126 for (Strip *strip = static_cast<Strip *>(seqbase->first); strip != nullptr; strip = strip->next)
127 {
128 if (strip->clip == clip_target) {
129 relations_invalidate_cache_raw(scene, strip);
130 }
131
132 if (strip->seqbase.first != nullptr) {
133 invalidate_movieclip_strips(scene, clip_target, &strip->seqbase);
134 }
135 }
136}
137
139{
140 for (Scene *scene = static_cast<Scene *>(bmain->scenes.first); scene != nullptr;
141 scene = static_cast<Scene *>(scene->id.next))
142 {
143 if (scene->ed != nullptr) {
144 invalidate_movieclip_strips(scene, clip_target, &scene->ed->seqbase);
145 }
146 }
147}
148
149void relations_free_imbuf(Scene *scene, ListBase *seqbase, bool for_render)
150{
151 if (scene->ed == nullptr) {
152 return;
153 }
154
155 cache_cleanup(scene);
156 prefetch_stop(scene);
157
158 LISTBASE_FOREACH (Strip *, strip, seqbase) {
159 if (for_render && time_strip_intersects_frame(scene, strip, scene->r.cfra)) {
160 continue;
161 }
162
163 if (strip->data) {
164 if (strip->type == STRIP_TYPE_MOVIE) {
166 }
167 if (strip->type == STRIP_TYPE_SPEED) {
168 strip_effect_speed_rebuild_map(scene, strip);
169 }
170 }
171 if (strip->type == STRIP_TYPE_META) {
172 relations_free_imbuf(scene, &strip->seqbase, for_render);
173 }
174 if (strip->type == STRIP_TYPE_SCENE) {
175 /* FIXME: recurse downwards,
176 * but do recurse protection somehow! */
177 }
178 }
179}
180
181static void sequencer_all_free_anim_ibufs(const Scene *scene,
182 ListBase *seqbase,
183 int timeline_frame,
184 const int frame_range[2])
185{
186 Editing *ed = editing_get(scene);
187 for (Strip *strip = static_cast<Strip *>(seqbase->first); strip != nullptr; strip = strip->next)
188 {
189 if (!time_strip_intersects_frame(scene, strip, timeline_frame) ||
190 !((frame_range[0] <= timeline_frame) && (frame_range[1] > timeline_frame)))
191 {
193 }
194 if (strip->type == STRIP_TYPE_META) {
195 int meta_range[2];
196
198 if (ms != nullptr && ms->parent_strip == strip) {
199 meta_range[0] = -MAXFRAME;
200 meta_range[1] = MAXFRAME;
201 }
202 else {
203 /* Limit frame range to meta strip. */
204 meta_range[0] = max_ii(frame_range[0], time_left_handle_frame_get(scene, strip));
205 meta_range[1] = min_ii(frame_range[1], time_right_handle_frame_get(scene, strip));
206 }
207
208 sequencer_all_free_anim_ibufs(scene, &strip->seqbase, timeline_frame, meta_range);
209 }
210 }
211}
212
213void relations_free_all_anim_ibufs(Scene *scene, int timeline_frame)
214{
215 Editing *ed = editing_get(scene);
216 if (ed == nullptr) {
217 return;
218 }
219
220 const int frame_range[2] = {-MAXFRAME, MAXFRAME};
221 sequencer_all_free_anim_ibufs(scene, &ed->seqbase, timeline_frame, frame_range);
222}
223
225{
226 LISTBASE_FOREACH (Strip *, strip, seqbase) {
227 if (strip->type == STRIP_TYPE_SCENE && strip->scene == scene) {
228 return strip;
229 }
230
231 if (strip->type == STRIP_TYPE_SCENE && (strip->flag & SEQ_SCENE_STRIPS)) {
232 if (strip->scene && strip->scene->ed &&
233 sequencer_check_scene_recursion(scene, &strip->scene->ed->seqbase))
234 {
235 return strip;
236 }
237 }
238
239 if (strip->type == STRIP_TYPE_META && sequencer_check_scene_recursion(scene, &strip->seqbase))
240 {
241 return strip;
242 }
243 }
244
245 return nullptr;
246}
247
249{
250 Editing *ed = editing_get(scene);
251 if (ed == nullptr) {
252 return false;
253 }
254
255 Strip *recursive_seq = sequencer_check_scene_recursion(scene, &ed->seqbase);
256
257 if (recursive_seq != nullptr) {
260 "Recursion detected in video sequencer. Strip %s at frame %d will not be rendered",
261 recursive_seq->name + 2,
262 time_left_handle_frame_get(scene, recursive_seq));
263
264 LISTBASE_FOREACH (Strip *, strip, &ed->seqbase) {
265 if (strip->type != STRIP_TYPE_SCENE && sequencer_strip_generates_image(strip)) {
266 /* There are other strips to render, so render them. */
267 return false;
268 }
269 }
270 /* No other strips to render - cancel operator. */
271 return true;
272 }
273
274 return false;
275}
276
277bool relations_render_loop_check(Strip *strip_main, Strip *strip)
278{
279 if (strip_main == nullptr || strip == nullptr) {
280 return false;
281 }
282
283 if (strip_main == strip) {
284 return true;
285 }
286
287 if ((strip_main->input1 && relations_render_loop_check(strip_main->input1, strip)) ||
288 (strip_main->input2 && relations_render_loop_check(strip_main->input2, strip)))
289 {
290 return true;
291 }
292
293 LISTBASE_FOREACH (StripModifierData *, smd, &strip_main->modifiers) {
294 if (smd->mask_strip && relations_render_loop_check(smd->mask_strip, strip)) {
295 return true;
296 }
297 }
298
299 return false;
300}
301
303{
304 while (strip->anims.last) {
305 StripAnim *sanim = static_cast<StripAnim *>(strip->anims.last);
306
307 if (sanim->anim) {
308 MOV_close(sanim->anim);
309 sanim->anim = nullptr;
310 }
311
312 BLI_freelinkN(&strip->anims, sanim);
313 }
314 BLI_listbase_clear(&strip->anims);
315}
316
321
322static bool get_uids_cb(Strip *strip, void *user_data)
323{
324 GSet *used_uids = (GSet *)user_data;
325 const SessionUID *session_uid = &strip->runtime.session_uid;
326 if (!BLI_session_uid_is_generated(session_uid)) {
327 printf("Sequence %s does not have UID generated.\n", strip->name);
328 return true;
329 }
330
331 if (BLI_gset_lookup(used_uids, session_uid) != nullptr) {
332 printf("Sequence %s has duplicate UID generated.\n", strip->name);
333 return true;
334 }
335
336 BLI_gset_insert(used_uids, (void *)session_uid);
337 return true;
338}
339
341{
342 if (scene->ed == nullptr) {
343 return;
344 }
345
346 GSet *used_uids = BLI_gset_new(
348
349 for_each_callback(&scene->ed->seqbase, get_uids_cb, used_uids);
350
351 BLI_gset_free(used_uids, nullptr);
352}
353
354bool exists_in_seqbase(const Strip *strip, const ListBase *seqbase)
355{
356 LISTBASE_FOREACH (Strip *, strip_test, seqbase) {
357 if (strip_test->type == STRIP_TYPE_META && exists_in_seqbase(strip, &strip_test->seqbase)) {
358 return true;
359 }
360 if (strip_test == strip) {
361 return true;
362 }
363 }
364 return false;
365}
366
367} // namespace blender::seq
void BKE_reportf(ReportList *reports, eReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
struct GSet GSet
Definition BLI_ghash.h:337
void * BLI_gset_lookup(const GSet *gs, const void *key) ATTR_WARN_UNUSED_RESULT
void BLI_gset_insert(GSet *gs, void *key)
Definition BLI_ghash.cc:959
GSet * BLI_gset_new(GSetHashFP hashfp, GSetCmpFP cmpfp, const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.cc:944
void BLI_gset_free(GSet *gs, GSetKeyFreeFP keyfreefp)
#define LISTBASE_FOREACH(type, var, list)
BLI_INLINE void BLI_listbase_clear(ListBase *lb)
void BLI_freelinkN(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:270
MINLINE int min_ii(int a, int b)
MINLINE int max_ii(int a, int b)
bool BLI_session_uid_is_generated(const SessionUID *uid)
uint BLI_session_uid_ghash_hash(const void *uid_v)
bool BLI_session_uid_ghash_compare(const void *lhs_v, const void *rhs_v)
SessionUID BLI_session_uid_generate(void)
#define ELEM(...)
void DEG_id_tag_update(ID *id, unsigned int flags)
@ ID_RECALC_SEQUENCER_STRIPS
Definition DNA_ID.h:1030
#define MAXFRAME
@ SEQ_SCENE_STRIPS
@ STRIP_TYPE_SCENE
@ STRIP_TYPE_MOVIE
@ STRIP_TYPE_SPEED
@ STRIP_TYPE_META
ReportList * reports
Definition WM_types.hh:1025
#define U
#define input
#define printf(...)
void MOV_close(MovieReader *anim)
Definition movie_read.cc:58
void relations_strip_free_anim(Strip *strip)
void prefetch_stop(Scene *scene)
Definition prefetch.cc:283
Strip * lookup_meta_by_strip(Editing *ed, const Strip *key)
int time_right_handle_frame_get(const Scene *scene, const Strip *strip)
void cache_cleanup_final(Scene *scene)
bool sequencer_strip_generates_image(Strip *strip)
size_t final_image_cache_calc_memory_size(const Scene *scene)
static void invalidate_movieclip_strips(Scene *scene, MovieClip *clip_target, ListBase *seqbase)
void relations_invalidate_cache(Scene *scene, Strip *strip)
void intra_frame_cache_invalidate(Scene *scene)
static Strip * sequencer_check_scene_recursion(Scene *scene, ListBase *seqbase)
bool relations_render_loop_check(Strip *strip_main, Strip *strip)
void final_image_cache_invalidate_frame_range(Scene *scene, const float timeline_frame_start, const float timeline_frame_end)
void relations_free_all_anim_ibufs(Scene *scene, int timeline_frame)
Span< Strip * > lookup_strips_by_scene(Editing *ed, const Scene *key)
void relations_invalidate_scene_strips(const Main *bmain, const Scene *scene_target)
Editing * editing_get(const Scene *scene)
Definition sequencer.cc:272
static void invalidate_final_cache_strip_range(Scene *scene, const Strip *strip)
static void invalidate_raw_cache_of_parent_meta(Scene *scene, Strip *strip)
int time_left_handle_frame_get(const Scene *, const Strip *strip)
void source_image_cache_clear(Scene *scene)
static bool get_uids_cb(Strip *strip, void *user_data)
void relations_invalidate_cache_raw(Scene *scene, Strip *strip)
void thumbnail_cache_clear(Scene *scene)
void source_image_cache_invalidate_strip(Scene *scene, const Strip *strip)
void relations_invalidate_movieclip_strips(Main *bmain, MovieClip *clip_target)
MetaStack * meta_stack_active_get(const Editing *ed)
Definition sequencer.cc:452
void for_each_callback(ListBase *seqbase, ForEachFunc callback, void *user_data)
Definition iterator.cc:59
bool time_strip_intersects_frame(const Scene *scene, const Strip *strip, const int timeline_frame)
void final_image_cache_clear(Scene *scene)
void strip_effect_speed_rebuild_map(Scene *scene, Strip *strip)
void cache_cleanup(Scene *scene)
static void sequencer_all_free_anim_ibufs(const Scene *scene, ListBase *seqbase, int timeline_frame, const int frame_range[2])
bool is_cache_full(const Scene *scene)
void relations_session_uid_generate(Strip *strip)
bool relation_is_effect_of_strip(const Strip *effect, const Strip *input)
void media_presence_invalidate_strip(Scene *scene, const Strip *strip)
size_t source_image_cache_calc_memory_size(const Scene *scene)
void relations_free_imbuf(Scene *scene, ListBase *seqbase, bool for_render)
void cache_cleanup_intra(Scene *scene)
void relations_check_uids_unique_and_report(const Scene *scene)
bool relations_check_scene_recursion(Scene *scene, ReportList *reports)
bool exists_in_seqbase(const Strip *strip, const ListBase *seqbase)
ListBase seqbase
void * last
void * first
ListBase scenes
Definition BKE_main.hh:245
struct Editing * ed
struct RenderData r
struct MovieReader * anim
SessionUID session_uid
struct Strip * input1
void * effectdata
ListBase seqbase
StripRuntime runtime
struct Strip * next
char name[64]
ListBase modifiers
struct Strip * input2
ListBase anims