Blender V4.3
strip_edit.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_listbase.h"
15#include "BLI_math_base.h"
16#include "BLI_string.h"
17#include "BLI_string_utf8.h"
18
19#include "BLT_translation.hh"
20
21#include "BKE_sound.h"
22
23#include "strip_time.hh"
24
25#include "SEQ_add.hh"
26#include "SEQ_animation.hh"
27#include "SEQ_channels.hh"
28#include "SEQ_connect.hh"
29
30#include "SEQ_edit.hh"
31#include "SEQ_effects.hh"
32#include "SEQ_iterator.hh"
33#include "SEQ_relations.hh"
34#include "SEQ_render.hh"
35#include "SEQ_sequencer.hh"
36#include "SEQ_time.hh"
37#include "SEQ_transform.hh"
38#include "SEQ_utils.hh"
39
40#include <cstring>
41
43 Sequence *seq_a,
44 Sequence *seq_b,
45 const char **r_error_str)
46{
47 char name[sizeof(seq_a->name)];
48
49 if (SEQ_time_strip_length_get(scene, seq_a) != SEQ_time_strip_length_get(scene, seq_b)) {
50 *r_error_str = N_("Strips must be the same length");
51 return false;
52 }
53
54 /* type checking, could be more advanced but disallow sound vs non-sound copy */
55 if (seq_a->type != seq_b->type) {
56 if (seq_a->type == SEQ_TYPE_SOUND_RAM || seq_b->type == SEQ_TYPE_SOUND_RAM) {
57 *r_error_str = N_("Strips were not compatible");
58 return false;
59 }
60
61 /* disallow effects to swap with non-effects strips */
62 if ((seq_a->type & SEQ_TYPE_EFFECT) != (seq_b->type & SEQ_TYPE_EFFECT)) {
63 *r_error_str = N_("Strips were not compatible");
64 return false;
65 }
66
67 if ((seq_a->type & SEQ_TYPE_EFFECT) && (seq_b->type & SEQ_TYPE_EFFECT)) {
69 *r_error_str = N_("Strips must have the same number of inputs");
70 return false;
71 }
72 }
73 }
74
75 blender::dna::shallow_swap(*seq_a, *seq_b);
76
77 /* swap back names so animation fcurves don't get swapped */
78 STRNCPY(name, seq_a->name + 2);
79 BLI_strncpy(seq_a->name + 2, seq_b->name + 2, sizeof(seq_b->name) - 2);
80 BLI_strncpy(seq_b->name + 2, name, sizeof(seq_b->name) - 2);
81
82 /* swap back opacity, and overlay mode */
83 std::swap(seq_a->blend_mode, seq_b->blend_mode);
84 std::swap(seq_a->blend_opacity, seq_b->blend_opacity);
85
86 std::swap(seq_a->prev, seq_b->prev);
87 std::swap(seq_a->next, seq_b->next);
88 std::swap(seq_a->start, seq_b->start);
89 std::swap(seq_a->startofs, seq_b->startofs);
90 std::swap(seq_a->endofs, seq_b->endofs);
91 std::swap(seq_a->machine, seq_b->machine);
92 seq_time_effect_range_set(scene, seq_a);
93 seq_time_effect_range_set(scene, seq_b);
94
95 return true;
96}
97
99 ListBase *seqbasep,
100 Sequence *metaseq,
101 const bool mute)
102{
103 /* For sound we go over full meta tree to update muted state,
104 * since sound is played outside of evaluating the imbufs. */
105 LISTBASE_FOREACH (Sequence *, seq, seqbasep) {
106 bool seqmute = (mute || SEQ_render_is_muted(channels, seq));
107
108 if (seq->type == SEQ_TYPE_META) {
109 /* if this is the current meta sequence, unmute because
110 * all sequences above this were set to mute */
111 if (seq == metaseq) {
112 seqmute = false;
113 }
114
115 seq_update_muting_recursive(&seq->channels, &seq->seqbase, metaseq, seqmute);
116 }
117 else if (ELEM(seq->type, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SCENE)) {
118 if (seq->scene_sound) {
119 BKE_sound_mute_scene_sound(seq->scene_sound, seqmute);
120 }
121 }
122 }
123}
124
126{
127 if (ed) {
128 /* mute all sounds up to current metastack list */
129 MetaStack *ms = static_cast<MetaStack *>(ed->metastack.last);
130
131 if (ms) {
132 seq_update_muting_recursive(&ed->channels, &ed->seqbase, ms->parseq, true);
133 }
134 else {
135 seq_update_muting_recursive(&ed->channels, &ed->seqbase, nullptr, false);
136 }
137 }
138}
139
140static void sequencer_flag_users_for_removal(Scene *scene, ListBase *seqbase, Sequence *seq)
141{
142 LISTBASE_FOREACH (Sequence *, user_seq, seqbase) {
143 /* Look in meta-strips for usage of seq. */
144 if (user_seq->type == SEQ_TYPE_META) {
145 sequencer_flag_users_for_removal(scene, &user_seq->seqbase, seq);
146 }
147
148 /* Clear seq from modifiers. */
149 LISTBASE_FOREACH (SequenceModifierData *, smd, &user_seq->modifiers) {
150 if (smd->mask_sequence == seq) {
151 smd->mask_sequence = nullptr;
152 }
153 }
154
155 /* Remove effects, that use seq. */
156 if (SEQ_relation_is_effect_of_strip(user_seq, seq)) {
157 user_seq->flag |= SEQ_FLAG_DELETE;
158 /* Strips can be used as mask even if not in same seqbase. */
159 sequencer_flag_users_for_removal(scene, &scene->ed->seqbase, user_seq);
160 }
161 }
162}
163
165{
166 if (seq == nullptr || (seq->flag & SEQ_FLAG_DELETE) != 0) {
167 return;
168 }
169
170 /* Flag and remove meta children. */
171 if (seq->type == SEQ_TYPE_META) {
172 LISTBASE_FOREACH (Sequence *, meta_child, &seq->seqbase) {
173 SEQ_edit_flag_for_removal(scene, &seq->seqbase, meta_child);
174 }
175 }
176
177 seq->flag |= SEQ_FLAG_DELETE;
178 sequencer_flag_users_for_removal(scene, seqbase, seq);
179}
180
182{
183 LISTBASE_FOREACH_MUTABLE (Sequence *, seq, seqbase) {
184 if (seq->flag & SEQ_FLAG_DELETE) {
185 if (seq->type == SEQ_TYPE_META) {
186 SEQ_edit_remove_flagged_sequences(scene, &seq->seqbase);
187 }
188 SEQ_free_animdata(scene, seq);
189 BLI_remlink(seqbase, seq);
190 SEQ_sequence_free(scene, seq);
192 }
193 }
194}
195
197 ListBase *seqbase,
198 Sequence *seq,
199 ListBase *dst_seqbase)
200{
201 /* Move to meta. */
202 BLI_remlink(seqbase, seq);
203 BLI_addtail(dst_seqbase, seq);
205
206 /* Update meta. */
207 if (SEQ_transform_test_overlap(scene, dst_seqbase, seq)) {
208 SEQ_transform_seqbase_shuffle(dst_seqbase, seq, scene);
209 }
210
211 return true;
212}
213
215 Sequence *src_seq,
216 Sequence *dst_seqm,
217 const char **r_error_str)
218{
219 /* Find the appropriate seqbase */
220 Editing *ed = SEQ_editing_get(scene);
221 ListBase *seqbase = SEQ_get_seqbase_by_seq(scene, src_seq);
222
223 if (dst_seqm->type != SEQ_TYPE_META) {
224 *r_error_str = N_("Cannot move strip to non-meta strip");
225 return false;
226 }
227
228 if (src_seq == dst_seqm) {
229 *r_error_str = N_("Strip cannot be moved into itself");
230 return false;
231 }
232
233 if (seqbase == &dst_seqm->seqbase) {
234 *r_error_str = N_("Moved strip is already inside provided meta strip");
235 return false;
236 }
237
238 if (src_seq->type == SEQ_TYPE_META && SEQ_exists_in_seqbase(dst_seqm, &src_seq->seqbase)) {
239 *r_error_str = N_("Moved strip is parent of provided meta strip");
240 return false;
241 }
242
243 if (!SEQ_exists_in_seqbase(dst_seqm, &ed->seqbase)) {
244 *r_error_str = N_("Cannot move strip to different scene");
245 return false;
246 }
247
249 strips.add(src_seq);
251
252 for (Sequence *seq : strips) {
253 /* Move to meta. */
254 SEQ_edit_move_strip_to_seqbase(scene, seqbase, seq, &dst_seqm->seqbase);
255 }
256
257 return true;
258}
259
261 Scene *scene,
262 Sequence *seq,
263 int timeline_frame)
264{
265 const float content_start = SEQ_time_start_frame_get(seq);
266 const float content_end = SEQ_time_content_end_frame_get(scene, seq);
267
268 /* Adjust within range of extended still-frames before strip. */
269 if (timeline_frame < content_start) {
270 const float offset = content_start + 1 - timeline_frame;
271 seq->start -= offset;
272 seq->startofs += offset;
273 }
274 /* Adjust within range of strip contents. */
275 else if ((timeline_frame >= content_start) && (timeline_frame <= content_end)) {
276 seq->endofs = 0;
277 float speed_factor = SEQ_time_media_playback_rate_factor_get(scene, seq);
278 seq->anim_endofs += round_fl_to_int((content_end - timeline_frame) * speed_factor);
279 }
280
281 /* Needed only to set `seq->len`. */
282 SEQ_add_reload_new_file(bmain, scene, seq, false);
283 SEQ_time_right_handle_frame_set(scene, seq, timeline_frame);
284}
285
287 Scene *scene,
288 Sequence *seq,
289 int timeline_frame)
290{
291 const float content_start = SEQ_time_start_frame_get(seq);
292 const float content_end = SEQ_time_content_end_frame_get(scene, seq);
293
294 /* Adjust within range of strip contents. */
295 if ((timeline_frame >= content_start) && (timeline_frame <= content_end)) {
296 float speed_factor = SEQ_time_media_playback_rate_factor_get(scene, seq);
297 seq->anim_startofs += round_fl_to_int((timeline_frame - content_start) * speed_factor);
298 seq->start = timeline_frame;
299 seq->startofs = 0;
300 }
301 /* Adjust within range of extended still-frames after strip. */
302 else if (timeline_frame > content_end) {
303 const float offset = timeline_frame - content_end + 1;
304 seq->start += offset;
305 seq->endofs += offset;
306 }
307
308 /* Needed only to set `seq->len`. */
309 SEQ_add_reload_new_file(bmain, scene, seq, false);
310 SEQ_time_left_handle_frame_set(scene, seq, timeline_frame);
311}
312
313static bool seq_edit_split_intersect_check(const Scene *scene,
314 const Sequence *seq,
315 const int timeline_frame)
316{
317 return timeline_frame > SEQ_time_left_handle_frame_get(scene, seq) &&
318 timeline_frame < SEQ_time_right_handle_frame_get(scene, seq);
319}
320
322 Scene *scene,
323 Sequence *left_seq,
324 Sequence *right_seq,
325 const int timeline_frame,
326 const eSeqSplitMethod method)
327{
328 if (seq_edit_split_intersect_check(scene, right_seq, timeline_frame)) {
329 switch (method) {
330 case SEQ_SPLIT_SOFT:
331 SEQ_time_left_handle_frame_set(scene, right_seq, timeline_frame);
332 break;
333 case SEQ_SPLIT_HARD:
334 seq_split_set_left_hold_offset(bmain, scene, right_seq, timeline_frame);
335 break;
336 }
337 }
338
339 if (seq_edit_split_intersect_check(scene, left_seq, timeline_frame)) {
340 switch (method) {
341 case SEQ_SPLIT_SOFT:
342 SEQ_time_right_handle_frame_set(scene, left_seq, timeline_frame);
343 break;
344 case SEQ_SPLIT_HARD:
345 seq_split_set_right_hold_offset(bmain, scene, left_seq, timeline_frame);
346 break;
347 }
348 }
349}
350
352 const Sequence *seq,
353 const int timeline_frame)
354{
355 bool input_does_intersect = false;
356 if (seq->seq1) {
357 input_does_intersect |= seq_edit_split_intersect_check(scene, seq->seq1, timeline_frame);
358 if ((seq->seq1->type & SEQ_TYPE_EFFECT) != 0) {
359 input_does_intersect |= seq_edit_split_effect_inputs_intersect(
360 scene, seq->seq1, timeline_frame);
361 }
362 }
363 if (seq->seq2) {
364 input_does_intersect |= seq_edit_split_intersect_check(scene, seq->seq2, timeline_frame);
365 if ((seq->seq1->type & SEQ_TYPE_EFFECT) != 0) {
366 input_does_intersect |= seq_edit_split_effect_inputs_intersect(
367 scene, seq->seq2, timeline_frame);
368 }
369 }
370 return input_does_intersect;
371}
372
375 const int timeline_frame,
376 const char **r_error)
377{
378 for (Sequence *seq : strips) {
380 if (SEQ_transform_is_locked(channels, seq)) {
381 *r_error = "Strip is locked.";
382 return false;
383 }
384 if ((seq->type & SEQ_TYPE_EFFECT) == 0) {
385 continue;
386 }
387 if (!seq_edit_split_intersect_check(scene, seq, timeline_frame)) {
388 continue;
389 }
390 if (SEQ_effect_get_num_inputs(seq->type) <= 1) {
391 continue;
392 }
394 *r_error = "Splitting transition effect is not permitted.";
395 return false;
396 }
397 if (!seq_edit_split_effect_inputs_intersect(scene, seq, timeline_frame)) {
398 *r_error = "Effect inputs don't overlap. Can not split such effect.";
399 return false;
400 }
401 }
402 return true;
403}
404
406 Scene *scene,
407 ListBase *seqbase,
408 Sequence *seq,
409 const int timeline_frame,
410 const eSeqSplitMethod method,
411 const char **r_error)
412{
413 if (!seq_edit_split_intersect_check(scene, seq, timeline_frame)) {
414 return nullptr;
415 }
416
417 /* Whole strip effect chain must be duplicated in order to preserve relationships. */
419 strips.add(seq);
421
422 /* All connected strips (that are selected and at the cut frame) must also be duplicated. */
423 blender::VectorSet<Sequence *> strips_old(strips);
424 for (Sequence *strip : strips_old) {
426 connections.remove_if([&](Sequence *connection) {
427 return !(connection->flag & SELECT) ||
428 !seq_edit_split_intersect_check(scene, connection, timeline_frame);
429 });
430 strips.add_multiple(connections.as_span());
431 }
432
433 /* In case connected strips had effects, duplicate those too: */
435
436 if (!seq_edit_split_operation_permitted_check(scene, strips, timeline_frame, r_error)) {
437 return nullptr;
438 }
439
440 /* Store `F-Curves`, so original ones aren't renamed. */
441 SeqAnimationBackup animation_backup{};
442 SEQ_animation_backup_original(scene, &animation_backup);
443
444 ListBase left_strips = {nullptr, nullptr};
445 for (Sequence *seq_iter : strips) {
446 /* Move strips in collection from seqbase to new ListBase. */
447 BLI_remlink(seqbase, seq_iter);
448 BLI_addtail(&left_strips, seq_iter);
449
450 /* Duplicate curves from backup, so they can be renamed along with split strips. */
451 SEQ_animation_duplicate_backup_to_scene(scene, seq_iter, &animation_backup);
452 }
453
454 /* Duplicate ListBase. */
455 ListBase right_strips = {nullptr, nullptr};
456 SEQ_sequence_base_dupli_recursive(scene, scene, &right_strips, &left_strips, SEQ_DUPE_ALL, 0);
457
458 Sequence *left_seq = static_cast<Sequence *>(left_strips.first);
459 Sequence *right_seq = static_cast<Sequence *>(right_strips.first);
460 Sequence *return_seq = nullptr;
461
462 /* Move strips from detached `ListBase`, otherwise they can't be flagged for removal. */
463 BLI_movelisttolist(seqbase, &left_strips);
464 BLI_movelisttolist(seqbase, &right_strips);
465
466 /* Rename duplicated strips. This has to be done immediately after adding
467 * strips to seqbase, for lookup cache to work correctly. */
468 Sequence *seq_rename = right_seq;
469 for (; seq_rename; seq_rename = seq_rename->next) {
470 SEQ_ensure_unique_name(seq_rename, scene);
471 }
472
473 /* Split strips. */
474 while (left_seq && right_seq) {
475 if (SEQ_time_left_handle_frame_get(scene, left_seq) >= timeline_frame) {
476 SEQ_edit_flag_for_removal(scene, seqbase, left_seq);
477 }
478 else if (SEQ_time_right_handle_frame_get(scene, right_seq) <= timeline_frame) {
479 SEQ_edit_flag_for_removal(scene, seqbase, right_seq);
480 }
481 else if (return_seq == nullptr) {
482 /* Store return value - pointer to strip that will not be removed. */
483 return_seq = right_seq;
484 }
485
486 seq_edit_split_handle_strip_offsets(bmain, scene, left_seq, right_seq, timeline_frame, method);
487 left_seq = left_seq->next;
488 right_seq = right_seq->next;
489 }
490
491 SEQ_edit_remove_flagged_sequences(scene, seqbase);
492 SEQ_animation_restore_original(scene, &animation_backup);
493
494 return return_seq;
495}
496
498 ListBase *seqbase,
499 const int initial_frame,
500 const bool remove_all_gaps)
501{
502 GapInfo gap_info = {0};
503 seq_time_gap_info_get(scene, seqbase, initial_frame, &gap_info);
504
505 if (!gap_info.gap_exists) {
506 return false;
507 }
508
509 if (remove_all_gaps) {
510 while (gap_info.gap_exists) {
512 scene, seqbase, -gap_info.gap_length, gap_info.gap_start_frame);
513 seq_time_gap_info_get(scene, seqbase, initial_frame, &gap_info);
514 }
515 }
516 else {
518 scene, seqbase, -gap_info.gap_length, gap_info.gap_start_frame);
519 }
520 return true;
521}
522
523void SEQ_edit_sequence_name_set(Scene *scene, Sequence *seq, const char *new_name)
524{
525 BLI_strncpy_utf8(seq->name + 2, new_name, MAX_NAME - 2);
526 BLI_str_utf8_invalid_strip(seq->name + 2, strlen(seq->name + 2));
528}
void BKE_sound_mute_scene_sound(void *handle, bool mute)
#define LISTBASE_FOREACH(type, var, list)
#define LISTBASE_FOREACH_MUTABLE(type, var, list)
void void void BLI_movelisttolist(struct ListBase *dst, struct ListBase *src) ATTR_NONNULL(1
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:110
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:130
MINLINE int round_fl_to_int(float a)
#define STRNCPY(dst, src)
Definition BLI_string.h:593
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy) ATTR_NONNULL(1
char * BLI_strncpy_utf8(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy) ATTR_NONNULL(1
int BLI_str_utf8_invalid_strip(char *str, size_t length) ATTR_NONNULL(1)
#define ELEM(...)
#define MAX_NAME
Definition DNA_defs.h:50
@ SEQ_TYPE_SOUND_RAM
@ SEQ_TYPE_CROSS
@ SEQ_TYPE_WIPE
@ SEQ_TYPE_META
@ SEQ_TYPE_SCENE
@ SEQ_TYPE_GAMCROSS
@ SEQ_TYPE_EFFECT
@ SEQ_FLAG_DELETE
eSeqSplitMethod
Definition SEQ_edit.hh:54
@ SEQ_SPLIT_SOFT
Definition SEQ_edit.hh:55
@ SEQ_SPLIT_HARD
Definition SEQ_edit.hh:56
#define SEQ_DUPE_ALL
void SEQ_animation_backup_original(Scene *scene, SeqAnimationBackup *backup)
Definition animation.cc:120
void SEQ_free_animdata(Scene *scene, Sequence *seq)
Definition animation.cc:102
void SEQ_animation_duplicate_backup_to_scene(Scene *scene, Sequence *seq, SeqAnimationBackup *backup)
Definition animation.cc:161
void SEQ_animation_restore_original(Scene *scene, SeqAnimationBackup *backup)
Definition animation.cc:130
ListBase * SEQ_channels_displayed_get(Editing *ed)
Definition channels.cc:23
bool add(const Key &key)
void add_multiple(Span< Key > keys)
#define SELECT
int SEQ_effect_get_num_inputs(int seq_type)
Definition effects.cc:3467
void SEQ_iterator_set_expand(const Scene *scene, ListBase *seqbase, VectorSet< Sequence * > &strips, void seq_query_func(const Scene *scene, Sequence *seq_reference, ListBase *seqbase, VectorSet< Sequence * > &strips))
Definition iterator.cc:61
void SEQ_query_strip_effect_chain(const Scene *scene, Sequence *reference_strip, ListBase *seqbase, VectorSet< Sequence * > &strips)
Definition iterator.cc:210
bool SEQ_render_is_muted(const ListBase *channels, const Sequence *seq)
Definition render.cc:2154
void SEQ_sequence_lookup_invalidate(const Scene *scene)
ListBase * SEQ_get_seqbase_by_seq(const Scene *scene, Sequence *seq)
void SEQ_ensure_unique_name(Sequence *seq, Scene *scene)
void SEQ_sequence_base_dupli_recursive(const Scene *scene_src, Scene *scene_dst, ListBase *nseqbase, const ListBase *seqbase, int dupe_flag, const int flag)
Definition sequencer.cc:653
void SEQ_sequence_free(Scene *scene, Sequence *seq)
Definition sequencer.cc:245
Editing * SEQ_editing_get(const Scene *scene)
Definition sequencer.cc:262
void SEQ_add_reload_new_file(Main *bmain, Scene *scene, Sequence *seq, const bool lock_range)
Definition strip_add.cc:525
blender::VectorSet< Sequence * > SEQ_get_connected_strips(const Sequence *seq)
bool SEQ_edit_remove_gaps(Scene *scene, ListBase *seqbase, const int initial_frame, const bool remove_all_gaps)
static bool seq_edit_split_operation_permitted_check(const Scene *scene, blender::Span< Sequence * > strips, const int timeline_frame, const char **r_error)
static void seq_split_set_left_hold_offset(Main *bmain, Scene *scene, Sequence *seq, int timeline_frame)
void SEQ_edit_flag_for_removal(Scene *scene, ListBase *seqbase, Sequence *seq)
bool SEQ_edit_move_strip_to_seqbase(Scene *scene, ListBase *seqbase, Sequence *seq, ListBase *dst_seqbase)
static void seq_edit_split_handle_strip_offsets(Main *bmain, Scene *scene, Sequence *left_seq, Sequence *right_seq, const int timeline_frame, const eSeqSplitMethod method)
Sequence * SEQ_edit_strip_split(Main *bmain, Scene *scene, ListBase *seqbase, Sequence *seq, const int timeline_frame, const eSeqSplitMethod method, const char **r_error)
static bool seq_edit_split_effect_inputs_intersect(const Scene *scene, const Sequence *seq, const int timeline_frame)
static bool seq_edit_split_intersect_check(const Scene *scene, const Sequence *seq, const int timeline_frame)
bool SEQ_edit_sequence_swap(Scene *scene, Sequence *seq_a, Sequence *seq_b, const char **r_error_str)
Definition strip_edit.cc:42
static void seq_split_set_right_hold_offset(Main *bmain, Scene *scene, Sequence *seq, int timeline_frame)
void SEQ_edit_sequence_name_set(Scene *scene, Sequence *seq, const char *new_name)
void SEQ_edit_remove_flagged_sequences(Scene *scene, ListBase *seqbase)
bool SEQ_edit_move_strip_to_meta(Scene *scene, Sequence *src_seq, Sequence *dst_seqm, const char **r_error_str)
static void seq_update_muting_recursive(ListBase *channels, ListBase *seqbasep, Sequence *metaseq, const bool mute)
Definition strip_edit.cc:98
void SEQ_edit_update_muting(Editing *ed)
static void sequencer_flag_users_for_removal(Scene *scene, ListBase *seqbase, Sequence *seq)
bool SEQ_exists_in_seqbase(const Sequence *seq, const ListBase *seqbase)
bool SEQ_relation_is_effect_of_strip(const Sequence *effect, const Sequence *input)
void SEQ_relations_invalidate_cache_preprocessed(Scene *scene, Sequence *seq)
int SEQ_time_strip_length_get(const Scene *scene, const Sequence *seq)
void SEQ_time_right_handle_frame_set(const Scene *scene, Sequence *seq, int timeline_frame)
void SEQ_time_left_handle_frame_set(const Scene *scene, Sequence *seq, int timeline_frame)
int SEQ_time_left_handle_frame_get(const Scene *, const Sequence *seq)
float SEQ_time_content_end_frame_get(const Scene *scene, const Sequence *seq)
void seq_time_gap_info_get(const Scene *scene, ListBase *seqbase, const int initial_frame, GapInfo *r_gap_info)
void seq_time_effect_range_set(const Scene *scene, Sequence *seq)
float SEQ_time_start_frame_get(const Sequence *seq)
float SEQ_time_media_playback_rate_factor_get(const Scene *scene, const Sequence *seq)
Definition strip_time.cc:38
int SEQ_time_right_handle_frame_get(const Scene *scene, const Sequence *seq)
bool SEQ_transform_seqbase_shuffle(ListBase *seqbasep, Sequence *test, Scene *evil_scene)
bool SEQ_transform_test_overlap(const Scene *scene, ListBase *seqbasep, Sequence *test)
bool SEQ_transform_is_locked(ListBase *channels, const Sequence *seq)
void SEQ_transform_offset_after_frame(Scene *scene, ListBase *seqbase, const int delta, const int timeline_frame)
ListBase seqbase
ListBase channels
ListBase metastack
int gap_length
Definition strip_time.hh:22
int gap_start_frame
Definition strip_time.hh:21
bool gap_exists
Definition strip_time.hh:23
void * last
void * first
Sequence * parseq
struct Sequence * prev
struct Sequence * seq1
struct Sequence * seq2
struct Sequence * next
#define N_(msgid)