Blender V4.3
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
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 "IMB_imbuf.hh"
25
26#include "SEQ_iterator.hh"
27#include "SEQ_prefetch.hh"
28#include "SEQ_relations.hh"
29#include "SEQ_sequencer.hh"
30#include "SEQ_time.hh"
31#include "SEQ_utils.hh"
32
33#include "effects.hh"
34#include "image_cache.hh"
35#include "utils.hh"
36
37bool SEQ_relation_is_effect_of_strip(const Sequence *effect, const Sequence *input)
38{
39 return ELEM(input, effect->seq1, effect->seq2);
40}
41
42/* check whether sequence cur depends on seq */
43static bool seq_relations_check_depend(const Scene *scene, Sequence *seq, Sequence *cur)
44{
45 if (SEQ_relation_is_effect_of_strip(cur, seq)) {
46 return true;
47 }
48
49 /* sequences are not intersecting in time, assume no dependency exists between them */
52 {
53 return false;
54 }
55
56 /* checking sequence is below reference one, not dependent on it */
57 if (cur->machine < seq->machine) {
58 return false;
59 }
60
61 /* sequence is not blending with lower machines, no dependency here occurs
62 * check for non-effects only since effect could use lower machines as input
63 */
64 if ((cur->type & SEQ_TYPE_EFFECT) == 0 &&
65 ((cur->blend_mode == SEQ_BLEND_REPLACE) ||
66 (cur->blend_mode == SEQ_TYPE_CROSS && cur->blend_opacity == 100.0f)))
67 {
68 return false;
69 }
70
71 return true;
72}
73
74static void sequence_do_invalidate_dependent(Scene *scene, Sequence *seq, ListBase *seqbase)
75{
76 LISTBASE_FOREACH (Sequence *, cur, seqbase) {
77 if (cur == seq) {
78 continue;
79 }
80
81 if (seq_relations_check_depend(scene, seq, cur)) {
82 /* Effect must be invalidated completely if they depend on invalidated seq. */
83 if ((cur->type & SEQ_TYPE_EFFECT) != 0) {
84 seq_cache_cleanup_sequence(scene, cur, seq, SEQ_CACHE_ALL_TYPES, false);
85 }
86 else {
87 /* In case of alpha over for example only invalidate composite image */
90 }
91 }
92
93 if (cur->seqbase.first) {
95 }
96 }
97}
98
100 Sequence *seq,
101 bool invalidate_self,
102 int invalidate_types)
103{
104 Editing *ed = scene->ed;
105
106 if (invalidate_self) {
107 seq_cache_cleanup_sequence(scene, seq, seq, invalidate_types, false);
108 }
109
110 if (seq->effectdata && seq->type == SEQ_TYPE_SPEED) {
112 }
113
117 SEQ_prefetch_stop(scene);
118}
119
120/* Find meta-strips that contain invalidated_seq and invalidate them. */
122 Sequence *invalidated_seq,
123 Sequence *meta_seq)
124{
125 ListBase *seqbase;
126
127 if (meta_seq == nullptr) {
128 Editing *ed = SEQ_editing_get(scene);
129 seqbase = &ed->seqbase;
130 }
131 else {
132 seqbase = &meta_seq->seqbase;
133 }
134
135 LISTBASE_FOREACH (Sequence *, seq, seqbase) {
136 if (seq->type == SEQ_TYPE_META) {
137 if (seq_relations_find_and_invalidate_metas(scene, invalidated_seq, seq)) {
139 return true;
140 }
141 }
142 if (seq == invalidated_seq && meta_seq != nullptr) {
143 sequence_invalidate_cache(scene, meta_seq, true, SEQ_CACHE_ALL_TYPES);
144 return true;
145 }
146 }
147 return false;
148}
149
151 Sequence *seq,
152 Sequence *range_mask,
153 int invalidate_types)
154{
155 seq_cache_cleanup_sequence(scene, seq, range_mask, invalidate_types, true);
156 seq_relations_find_and_invalidate_metas(scene, seq, nullptr);
157}
158
164
174
176{
177 if (seq->type == SEQ_TYPE_SOUND_RAM) {
178 return;
179 }
180
183 seq_relations_find_and_invalidate_metas(scene, seq, nullptr);
184}
185
187{
188 if (seq->type == SEQ_TYPE_SOUND_RAM) {
189 return;
190 }
191
194 seq_relations_find_and_invalidate_metas(scene, seq, nullptr);
195}
196
197static void invalidate_scene_strips(Scene *scene, Scene *scene_target, ListBase *seqbase)
198{
199 for (Sequence *seq = static_cast<Sequence *>(seqbase->first); seq != nullptr; seq = seq->next) {
200 if (seq->scene == scene_target) {
202 }
203
204 if (seq->seqbase.first != nullptr) {
205 invalidate_scene_strips(scene, scene_target, &seq->seqbase);
206 }
207 }
208}
209
211{
212 for (Scene *scene = static_cast<Scene *>(bmain->scenes.first); scene != nullptr;
213 scene = static_cast<Scene *>(scene->id.next))
214 {
215 if (scene->ed != nullptr) {
216 invalidate_scene_strips(scene, scene_target, &scene->ed->seqbase);
217 }
218 }
219}
220
221static void invalidate_movieclip_strips(Scene *scene, MovieClip *clip_target, ListBase *seqbase)
222{
223 for (Sequence *seq = static_cast<Sequence *>(seqbase->first); seq != nullptr; seq = seq->next) {
224 if (seq->clip == clip_target) {
226 }
227
228 if (seq->seqbase.first != nullptr) {
229 invalidate_movieclip_strips(scene, clip_target, &seq->seqbase);
230 }
231 }
232}
233
235{
236 for (Scene *scene = static_cast<Scene *>(bmain->scenes.first); scene != nullptr;
237 scene = static_cast<Scene *>(scene->id.next))
238 {
239 if (scene->ed != nullptr) {
240 invalidate_movieclip_strips(scene, clip_target, &scene->ed->seqbase);
241 }
242 }
243}
244
245void SEQ_relations_free_imbuf(Scene *scene, ListBase *seqbase, bool for_render)
246{
247 if (scene->ed == nullptr) {
248 return;
249 }
250
251 SEQ_cache_cleanup(scene);
252 SEQ_prefetch_stop(scene);
253
254 LISTBASE_FOREACH (Sequence *, seq, seqbase) {
255 if (for_render && SEQ_time_strip_intersects_frame(scene, seq, scene->r.cfra)) {
256 continue;
257 }
258
259 if (seq->strip) {
260 if (seq->type == SEQ_TYPE_MOVIE) {
262 }
263 if (seq->type == SEQ_TYPE_SPEED) {
265 }
266 }
267 if (seq->type == SEQ_TYPE_META) {
268 SEQ_relations_free_imbuf(scene, &seq->seqbase, for_render);
269 }
270 if (seq->type == SEQ_TYPE_SCENE) {
271 /* FIXME: recurse downwards,
272 * but do recurse protection somehow! */
273 }
274 }
275}
276
277static void sequencer_all_free_anim_ibufs(const Scene *scene,
278 ListBase *seqbase,
279 int timeline_frame,
280 const int frame_range[2])
281{
282 Editing *ed = SEQ_editing_get(scene);
283 for (Sequence *seq = static_cast<Sequence *>(seqbase->first); seq != nullptr; seq = seq->next) {
284 if (!SEQ_time_strip_intersects_frame(scene, seq, timeline_frame) ||
285 !((frame_range[0] <= timeline_frame) && (frame_range[1] > timeline_frame)))
286 {
288 }
289 if (seq->type == SEQ_TYPE_META) {
290 int meta_range[2];
291
293 if (ms != nullptr && ms->parseq == seq) {
294 meta_range[0] = -MAXFRAME;
295 meta_range[1] = MAXFRAME;
296 }
297 else {
298 /* Limit frame range to meta strip. */
299 meta_range[0] = max_ii(frame_range[0], SEQ_time_left_handle_frame_get(scene, seq));
300 meta_range[1] = min_ii(frame_range[1], SEQ_time_right_handle_frame_get(scene, seq));
301 }
302
303 sequencer_all_free_anim_ibufs(scene, &seq->seqbase, timeline_frame, meta_range);
304 }
305 }
306}
307
308void SEQ_relations_free_all_anim_ibufs(Scene *scene, int timeline_frame)
309{
310 Editing *ed = SEQ_editing_get(scene);
311 if (ed == nullptr) {
312 return;
313 }
314
315 const int frame_range[2] = {-MAXFRAME, MAXFRAME};
316 sequencer_all_free_anim_ibufs(scene, &ed->seqbase, timeline_frame, frame_range);
317}
318
320{
321 LISTBASE_FOREACH (Sequence *, seq, seqbase) {
322 if (seq->type == SEQ_TYPE_SCENE && seq->scene == scene) {
323 return seq;
324 }
325
326 if (seq->type == SEQ_TYPE_SCENE && (seq->flag & SEQ_SCENE_STRIPS)) {
327 if (seq->scene && seq->scene->ed &&
328 sequencer_check_scene_recursion(scene, &seq->scene->ed->seqbase))
329 {
330 return seq;
331 }
332 }
333
334 if (seq->type == SEQ_TYPE_META && sequencer_check_scene_recursion(scene, &seq->seqbase)) {
335 return seq;
336 }
337 }
338
339 return nullptr;
340}
341
343{
344 Editing *ed = SEQ_editing_get(scene);
345 if (ed == nullptr) {
346 return false;
347 }
348
349 Sequence *recursive_seq = sequencer_check_scene_recursion(scene, &ed->seqbase);
350
351 if (recursive_seq != nullptr) {
352 BKE_reportf(reports,
354 "Recursion detected in video sequencer. Strip %s at frame %d will not be rendered",
355 recursive_seq->name + 2,
356 SEQ_time_left_handle_frame_get(scene, recursive_seq));
357
358 LISTBASE_FOREACH (Sequence *, seq, &ed->seqbase) {
359 if (seq->type != SEQ_TYPE_SCENE && sequencer_seq_generates_image(seq)) {
360 /* There are other strips to render, so render them. */
361 return false;
362 }
363 }
364 /* No other strips to render - cancel operator. */
365 return true;
366 }
367
368 return false;
369}
370
372{
373 if (seq_main == nullptr || seq == nullptr) {
374 return false;
375 }
376
377 if (seq_main == seq) {
378 return true;
379 }
380
381 if ((seq_main->seq1 && SEQ_relations_render_loop_check(seq_main->seq1, seq)) ||
382 (seq_main->seq2 && SEQ_relations_render_loop_check(seq_main->seq2, seq)))
383 {
384 return true;
385 }
386
387 LISTBASE_FOREACH (SequenceModifierData *, smd, &seq_main->modifiers) {
388 if (smd->mask_sequence && SEQ_relations_render_loop_check(smd->mask_sequence, seq)) {
389 return true;
390 }
391 }
392
393 return false;
394}
395
397{
398 while (seq->anims.last) {
399 StripAnim *sanim = static_cast<StripAnim *>(seq->anims.last);
400
401 if (sanim->anim) {
402 IMB_free_anim(sanim->anim);
403 sanim->anim = nullptr;
404 }
405
406 BLI_freelinkN(&seq->anims, sanim);
407 }
409}
410
415
416static bool get_uids_cb(Sequence *seq, void *user_data)
417{
418 GSet *used_uids = (GSet *)user_data;
419 const SessionUID *session_uid = &seq->runtime.session_uid;
420 if (!BLI_session_uid_is_generated(session_uid)) {
421 printf("Sequence %s does not have UID generated.\n", seq->name);
422 return true;
423 }
424
425 if (BLI_gset_lookup(used_uids, session_uid) != nullptr) {
426 printf("Sequence %s has duplicate UID generated.\n", seq->name);
427 return true;
428 }
429
430 BLI_gset_insert(used_uids, (void *)session_uid);
431 return true;
432}
433
435{
436 if (scene->ed == nullptr) {
437 return;
438 }
439
440 GSet *used_uids = BLI_gset_new(
442
443 SEQ_for_each_callback(&scene->ed->seqbase, get_uids_cb, used_uids);
444
445 BLI_gset_free(used_uids, nullptr);
446}
447
449{
450 LISTBASE_FOREACH (Sequence *, iseq, seqbase) {
451 Sequence *rval;
452
453 if (seq == iseq) {
454 return meta;
455 }
456 if (iseq->seqbase.first && (rval = SEQ_find_metastrip_by_sequence(&iseq->seqbase, iseq, seq)))
457 {
458 return rval;
459 }
460 }
461
462 return nullptr;
463}
464
465bool SEQ_exists_in_seqbase(const Sequence *seq, const ListBase *seqbase)
466{
467 LISTBASE_FOREACH (Sequence *, seq_test, seqbase) {
468 if (seq_test->type == SEQ_TYPE_META && SEQ_exists_in_seqbase(seq, &seq_test->seqbase)) {
469 return true;
470 }
471 if (seq_test == seq) {
472 return true;
473 }
474 }
475 return false;
476}
void BKE_reportf(ReportList *reports, eReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
struct GSet GSet
Definition BLI_ghash.h:341
void * BLI_gset_lookup(const GSet *gs, const void *key) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.c:1058
void BLI_gset_insert(GSet *gs, void *key)
Definition BLI_ghash.c:959
GSet * BLI_gset_new(GSetHashFP hashfp, GSetCmpFP cmpfp, const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.c:944
void BLI_gset_free(GSet *gs, GSetKeyFreeFP keyfreefp)
Definition BLI_ghash.c:1034
#define LISTBASE_FOREACH(type, var, list)
void BLI_freelinkN(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:269
BLI_INLINE void BLI_listbase_clear(struct ListBase *lb)
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)
Definition session_uid.c:38
uint BLI_session_uid_ghash_hash(const void *uid_v)
Definition session_uid.c:53
bool BLI_session_uid_ghash_compare(const void *lhs_v, const void *rhs_v)
Definition session_uid.c:59
SessionUID BLI_session_uid_generate(void)
Definition session_uid.c:22
#define ELEM(...)
void DEG_id_tag_update(ID *id, unsigned int flags)
@ ID_RECALC_SEQUENCER_STRIPS
Definition DNA_ID.h:1089
#define MAXFRAME
@ SEQ_BLEND_REPLACE
@ SEQ_CACHE_ALL_TYPES
@ SEQ_CACHE_STORE_PREPROCESSED
@ SEQ_CACHE_STORE_FINAL_OUT
@ SEQ_CACHE_STORE_COMPOSITE
@ SEQ_TYPE_SOUND_RAM
@ SEQ_TYPE_CROSS
@ SEQ_TYPE_META
@ SEQ_TYPE_SCENE
@ SEQ_TYPE_SPEED
@ SEQ_TYPE_EFFECT
@ SEQ_TYPE_MOVIE
@ SEQ_SCENE_STRIPS
void IMB_free_anim(ImBufAnim *anim)
Definition anim_movie.cc:60
#define printf
void seq_effect_speed_rebuild_map(Scene *scene, Sequence *seq)
Definition effects.cc:2118
void SEQ_cache_cleanup(Scene *scene)
void seq_cache_cleanup_sequence(Scene *scene, Sequence *seq, Sequence *seq_changed, int invalidate_types, bool force_seq_changed_range)
void SEQ_for_each_callback(ListBase *seqbase, SeqForEachFunc callback, void *user_data)
Definition iterator.cc:43
void media_presence_invalidate_strip(Scene *scene, const Sequence *seq)
void SEQ_prefetch_stop(Scene *scene)
Definition prefetch.cc:247
bool sequencer_seq_generates_image(Sequence *seq)
Editing * SEQ_editing_get(const Scene *scene)
Definition sequencer.cc:262
MetaStack * SEQ_meta_stack_active_get(const Editing *ed)
Definition sequencer.cc:448
bool SEQ_relations_render_loop_check(Sequence *seq_main, Sequence *seq)
void SEQ_relations_invalidate_cache_raw(Scene *scene, Sequence *seq)
static void sequence_invalidate_cache(Scene *scene, Sequence *seq, bool invalidate_self, int invalidate_types)
static Sequence * sequencer_check_scene_recursion(Scene *scene, ListBase *seqbase)
static bool seq_relations_find_and_invalidate_metas(Scene *scene, Sequence *invalidated_seq, Sequence *meta_seq)
static void sequencer_all_free_anim_ibufs(const Scene *scene, ListBase *seqbase, int timeline_frame, const int frame_range[2])
bool SEQ_exists_in_seqbase(const Sequence *seq, const ListBase *seqbase)
void SEQ_relations_session_uid_generate(Sequence *sequence)
static bool seq_relations_check_depend(const Scene *scene, Sequence *seq, Sequence *cur)
void SEQ_relations_invalidate_cache_in_range(Scene *scene, Sequence *seq, Sequence *range_mask, int invalidate_types)
void SEQ_relations_sequence_free_anim(Sequence *seq)
bool SEQ_relations_check_scene_recursion(Scene *scene, ReportList *reports)
void SEQ_relations_invalidate_scene_strips(Main *bmain, Scene *scene_target)
Sequence * SEQ_find_metastrip_by_sequence(ListBase *seqbase, Sequence *meta, Sequence *seq)
void SEQ_relations_free_all_anim_ibufs(Scene *scene, int timeline_frame)
static void sequence_do_invalidate_dependent(Scene *scene, Sequence *seq, ListBase *seqbase)
static void invalidate_scene_strips(Scene *scene, Scene *scene_target, ListBase *seqbase)
void SEQ_relations_invalidate_dependent(Scene *scene, Sequence *seq)
static bool get_uids_cb(Sequence *seq, void *user_data)
void SEQ_relations_check_uids_unique_and_report(const Scene *scene)
bool SEQ_relation_is_effect_of_strip(const Sequence *effect, const Sequence *input)
void SEQ_relations_invalidate_movieclip_strips(Main *bmain, MovieClip *clip_target)
static void invalidate_movieclip_strips(Scene *scene, MovieClip *clip_target, ListBase *seqbase)
void SEQ_relations_free_imbuf(Scene *scene, ListBase *seqbase, bool for_render)
void SEQ_relations_invalidate_cache_preprocessed(Scene *scene, Sequence *seq)
void SEQ_relations_invalidate_cache_composite(Scene *scene, Sequence *seq)
int SEQ_time_left_handle_frame_get(const Scene *, const Sequence *seq)
bool SEQ_time_strip_intersects_frame(const Scene *scene, const Sequence *seq, const int timeline_frame)
int SEQ_time_right_handle_frame_get(const Scene *scene, const Sequence *seq)
ListBase seqbase
void * last
void * first
ListBase scenes
Definition BKE_main.hh:210
Sequence * parseq
struct Editing * ed
ListBase modifiers
struct Sequence * seq1
struct Sequence * seq2
SequenceRuntime runtime
struct ImBufAnim * anim