Blender V5.0
strip_time.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 <algorithm>
12
13#include "DNA_scene_types.h"
14#include "DNA_sequence_types.h"
15
16#include "BLI_listbase.h"
17#include "BLI_math_base.h"
18
19#include "BKE_movieclip.h"
20#include "BKE_sound.h"
21
22#include "DNA_sound_types.h"
23
24#include "MOV_read.hh"
25
26#include "SEQ_animation.hh"
27#include "SEQ_channels.hh"
28#include "SEQ_iterator.hh"
29#include "SEQ_render.hh"
30#include "SEQ_retiming.hh"
31#include "SEQ_sequencer.hh"
32#include "SEQ_time.hh"
33#include "SEQ_transform.hh"
34
35#include "sequencer.hh"
36#include "strip_time.hh"
37#include "utils.hh"
38
39namespace blender::seq {
40
41float time_media_playback_rate_factor_get(const Strip *strip, const float scene_fps)
42{
43 if ((strip->flag & SEQ_AUTO_PLAYBACK_RATE) == 0) {
44 return 1.0f;
45 }
46 if (strip->media_playback_rate == 0.0f) {
47 return 1.0f;
48 }
49 return strip->media_playback_rate / scene_fps;
50}
51
52float give_frame_index(const Scene *scene, const Strip *strip, float timeline_frame)
53{
54 float frame_index;
55 float sta = time_start_frame_get(strip);
56 float end = strip->is_effect() ? time_right_handle_frame_get(scene, strip) :
57 time_content_end_frame_get(scene, strip) - 1;
58
59 if (end < sta) {
60 return -1;
61 }
62
63 if (strip->type == STRIP_TYPE_IMAGE && transform_single_image_check(strip)) {
64 return 0;
65 }
66
67 if (strip->flag & SEQ_REVERSE_FRAMES) {
68 frame_index = end - timeline_frame;
69 }
70 else {
71 frame_index = timeline_frame - sta;
72 }
73
74 frame_index = max_ff(frame_index, 0);
75
76 const float scene_fps = float(scene->r.frs_sec) / float(scene->r.frs_sec_base);
77 frame_index *= time_media_playback_rate_factor_get(strip, scene_fps);
78
79 if (retiming_is_active(strip)) {
80 const float retiming_factor = strip_retiming_evaluate(strip, frame_index);
81 /* Retiming maps frame index from 0 up to `strip->len`, because key is positioned at the end of
82 * last frame. Otherwise the last frame could not be retimed. */
83 frame_index = retiming_factor * strip->len;
84 }
85 /* Clamp frame index to strip content frame range. */
86 float frame_index_max = strip->is_effect() ? end - sta : strip->len - 1;
87 frame_index = clamp_f(frame_index, 0, frame_index_max);
88
89 if (strip->strobe > 1.0f) {
90 frame_index -= fmodf(double(frame_index), double(strip->strobe));
91 }
92
93 return frame_index;
94}
95
96static int metastrip_start_get(Strip *strip_meta)
97{
98 return strip_meta->start + strip_meta->startofs;
99}
100
101static int metastrip_end_get(Strip *strip_meta)
102{
103 return strip_meta->start + strip_meta->len - strip_meta->endofs;
104}
105
107 Strip *strip_meta,
108 int start,
109 int end)
110{
111 /* For sound we go over full meta tree to update bounds of the sound strips,
112 * since sound is played outside of evaluating the image-buffers (#ImBuf). */
113 LISTBASE_FOREACH (Strip *, strip, &strip_meta->seqbase) {
114 if (strip->type == STRIP_TYPE_META) {
116 strip,
117 max_ii(start, metastrip_start_get(strip)),
118 min_ii(end, metastrip_end_get(strip)));
119 }
120 else if (ELEM(strip->type, STRIP_TYPE_SOUND_RAM, STRIP_TYPE_SCENE)) {
121 if (strip->scene_sound) {
122 int startofs = strip->startofs;
123 int endofs = strip->endofs;
124 if (strip->startofs + strip->start < start) {
125 startofs = start - strip->start;
126 }
127
128 if (strip->start + strip->len - strip->endofs > end) {
129 endofs = strip->start + strip->len - end;
130 }
131
132 double offset_time = 0.0f;
133 if (strip->sound != nullptr) {
134 offset_time = strip->sound->offset_time + strip->sound_offset;
135 }
136
138 strip->scene_sound,
139 strip->start + startofs,
140 strip->start + strip->len - endofs,
141 startofs + strip->anim_startofs,
142 offset_time);
143 }
144 }
145 }
146}
147
148void strip_update_sound_bounds_recursive(const Scene *scene, Strip *strip_meta)
149{
151 scene, strip_meta, metastrip_start_get(strip_meta), metastrip_end_get(strip_meta));
152}
153
154void time_update_meta_strip_range(const Scene *scene, Strip *strip_meta)
155{
156 if (strip_meta == nullptr) {
157 return;
158 }
159
160 if (BLI_listbase_is_empty(&strip_meta->seqbase)) {
161 return;
162 }
163
164 const int strip_start = time_left_handle_frame_get(scene, strip_meta);
165 const int strip_end = time_right_handle_frame_get(scene, strip_meta);
166
167 int min = MAXFRAME * 2;
168 int max = -MAXFRAME * 2;
169 LISTBASE_FOREACH (Strip *, strip, &strip_meta->seqbase) {
170 min = min_ii(time_left_handle_frame_get(scene, strip), min);
171 max = max_ii(time_right_handle_frame_get(scene, strip), max);
172 }
173
174 strip_meta->start = min + strip_meta->anim_startofs;
175 strip_meta->len = max - strip_meta->anim_endofs - strip_meta->start;
176
177 /* Functions `SEQ_time_*_handle_frame_set()` can not be used here, because they are clamped, so
178 * change must be done at once. */
179 strip_meta->startofs = strip_start - strip_meta->start;
180 strip_meta->startdisp = strip_start; /* Only to make files usable in older versions. */
181 strip_meta->endofs = strip_meta->start + time_strip_length_get(scene, strip_meta) - strip_end;
182 strip_meta->enddisp = strip_end; /* Only to make files usable in older versions. */
183
184 strip_update_sound_bounds_recursive(scene, strip_meta);
185 blender::Span<Strip *> effects = SEQ_lookup_effects_by_strip(scene->ed, strip_meta);
187 time_update_meta_strip_range(scene, lookup_meta_by_strip(scene->ed, strip_meta));
188}
189
190void strip_time_effect_range_set(const Scene *scene, Strip *strip)
191{
192 if (strip->input1 == nullptr && strip->input2 == nullptr) {
193 return;
194 }
195
196 if (strip->input1 && strip->input2) { /* 2 - input effect. */
197 strip->startdisp = max_ii(time_left_handle_frame_get(scene, strip->input1),
198 time_left_handle_frame_get(scene, strip->input2));
199 strip->enddisp = min_ii(time_right_handle_frame_get(scene, strip->input1),
200 time_right_handle_frame_get(scene, strip->input2));
201 }
202 else if (strip->input1) { /* Single input effect. */
203 strip->startdisp = time_right_handle_frame_get(scene, strip->input1);
204 strip->enddisp = time_left_handle_frame_get(scene, strip->input1);
205 }
206 else if (strip->input2) { /* Strip may be missing one of inputs. */
207 strip->startdisp = time_right_handle_frame_get(scene, strip->input2);
208 strip->enddisp = time_left_handle_frame_get(scene, strip->input2);
209 }
210
211 if (strip->startdisp > strip->enddisp) {
212 std::swap(strip->startdisp, strip->enddisp);
213 }
214
215 /* Values unusable for effects, these should be always 0. */
216 strip->startofs = strip->endofs = strip->anim_startofs = strip->anim_endofs = 0;
217 strip->start = strip->startdisp;
218 strip->len = strip->enddisp - strip->startdisp;
219}
220
222 const blender::Span<Strip *> effects)
223{
224 /* First pass: Update length of immediate effects. */
225 for (Strip *strip : effects) {
226 strip_time_effect_range_set(scene, strip);
227 }
228
229 /* Second pass: Recursive call to update effects in chain and in order, so they inherit length
230 * correctly. */
231 for (Strip *strip : effects) {
232 blender::Span<Strip *> effects_recurse = SEQ_lookup_effects_by_strip(scene->ed, strip);
233 strip_time_update_effects_strip_range(scene, effects_recurse);
234 }
235}
236
238 int timeline_frame,
239 const short side,
240 const bool do_skip_mute,
241 const bool do_center,
242 const bool do_unselected)
243{
244 Editing *ed = editing_get(scene);
246
247 int dist, best_dist, best_frame = timeline_frame;
248 int strip_frames[2], strip_frames_tot;
249
250 /* In case where both is passed,
251 * frame just finds the nearest end while frame_left the nearest start. */
252
253 best_dist = MAXFRAME * 2;
254
255 if (ed == nullptr) {
256 return timeline_frame;
257 }
258
259 LISTBASE_FOREACH (Strip *, strip, ed->current_strips()) {
260 int i;
261
262 if (do_skip_mute && render_is_muted(channels, strip)) {
263 continue;
264 }
265
266 if (do_unselected && (strip->flag & SELECT)) {
267 continue;
268 }
269
270 if (do_center) {
271 strip_frames[0] = (time_left_handle_frame_get(scene, strip) +
272 time_right_handle_frame_get(scene, strip)) /
273 2;
274 strip_frames_tot = 1;
275 }
276 else {
277 strip_frames[0] = time_left_handle_frame_get(scene, strip);
278 strip_frames[1] = time_right_handle_frame_get(scene, strip);
279
280 strip_frames_tot = 2;
281 }
282
283 for (i = 0; i < strip_frames_tot; i++) {
284 const int strip_frame = strip_frames[i];
285
286 dist = MAXFRAME * 2;
287
288 switch (side) {
289 case SIDE_LEFT:
290 if (strip_frame < timeline_frame) {
291 dist = timeline_frame - strip_frame;
292 }
293 break;
294 case SIDE_RIGHT:
295 if (strip_frame > timeline_frame) {
296 dist = strip_frame - timeline_frame;
297 }
298 break;
299 case SIDE_BOTH:
300 dist = abs(strip_frame - timeline_frame);
301 break;
302 }
303
304 if (dist < best_dist) {
305 best_frame = strip_frame;
306 best_dist = dist;
307 }
308 }
309 }
310
311 return best_frame;
312}
313
314float time_strip_fps_get(Scene *scene, Strip *strip)
315{
316 switch (strip->type) {
317 case STRIP_TYPE_MOVIE: {
318 strip_open_anim_file(scene, strip, true);
319 if (BLI_listbase_is_empty(&strip->anims)) {
320 return 0.0f;
321 }
322 StripAnim *strip_anim = static_cast<StripAnim *>(strip->anims.first);
323 if (strip_anim->anim == nullptr) {
324 return 0.0f;
325 }
326 return MOV_get_fps(strip_anim->anim);
327 }
329 if (strip->clip != nullptr) {
330 return BKE_movieclip_get_fps(strip->clip);
331 }
332 break;
333 case STRIP_TYPE_SCENE:
334 if (strip->scene != nullptr) {
335 return float(strip->scene->r.frs_sec) / strip->scene->r.frs_sec_base;
336 }
337 break;
338 }
339 return 0.0f;
340}
341
342void timeline_init_boundbox(const Scene *scene, rctf *r_rect)
343{
344 r_rect->xmin = scene->r.sfra;
345 r_rect->xmax = scene->r.efra + 1;
346 r_rect->ymin = 1.0f; /* The first strip is drawn at y == 1.0f */
347 r_rect->ymax = 8.0f;
348}
349
350void timeline_expand_boundbox(const Scene *scene, const ListBase *seqbase, rctf *rect)
351{
352 if (seqbase == nullptr) {
353 return;
354 }
355
356 LISTBASE_FOREACH (Strip *, strip, seqbase) {
357 rect->xmin = std::min<float>(rect->xmin, time_left_handle_frame_get(scene, strip) - 1);
358 rect->xmax = std::max<float>(rect->xmax, time_right_handle_frame_get(scene, strip) + 1);
359 /* We do +1 here to account for the channel thickness. Channel n has range of <n, n+1>. */
360 rect->ymax = std::max(rect->ymax, strip->channel + 1.0f);
361 }
362}
363
364void timeline_boundbox(const Scene *scene, const ListBase *seqbase, rctf *r_rect)
365{
366 timeline_init_boundbox(scene, r_rect);
367 timeline_expand_boundbox(scene, seqbase, r_rect);
368}
369
370static bool strip_exists_at_frame(const Scene *scene,
372 const int timeline_frame)
373{
374 for (Strip *strip : strips) {
375 if (time_strip_intersects_frame(scene, strip, timeline_frame)) {
376 return true;
377 }
378 }
379 return false;
380}
381
382void seq_time_gap_info_get(const Scene *scene,
383 ListBase *seqbase,
384 const int initial_frame,
385 GapInfo *r_gap_info)
386{
387 rctf rectf;
388 /* Get first and last frame. */
389 timeline_boundbox(scene, seqbase, &rectf);
390 const int sfra = int(rectf.xmin);
391 const int efra = int(rectf.xmax);
392 int timeline_frame = initial_frame;
393 r_gap_info->gap_exists = false;
394
395 blender::VectorSet strips = query_all_strips(seqbase);
396
397 if (!strip_exists_at_frame(scene, strips, initial_frame)) {
398 /* Search backward for gap_start_frame. */
399 for (; timeline_frame >= sfra; timeline_frame--) {
400 if (strip_exists_at_frame(scene, strips, timeline_frame)) {
401 break;
402 }
403 }
404 r_gap_info->gap_start_frame = timeline_frame + 1;
405 timeline_frame = initial_frame;
406 }
407 else {
408 /* Search forward for gap_start_frame. */
409 for (; timeline_frame <= efra; timeline_frame++) {
410 if (!strip_exists_at_frame(scene, strips, timeline_frame)) {
411 r_gap_info->gap_start_frame = timeline_frame;
412 break;
413 }
414 }
415 }
416 /* Search forward for gap_end_frame. */
417 for (; timeline_frame <= efra; timeline_frame++) {
418 if (strip_exists_at_frame(scene, strips, timeline_frame)) {
419 const int gap_end_frame = timeline_frame;
420 r_gap_info->gap_length = gap_end_frame - r_gap_info->gap_start_frame;
421 r_gap_info->gap_exists = true;
422 break;
423 }
424 }
425}
426
427bool time_strip_intersects_frame(const Scene *scene, const Strip *strip, const int timeline_frame)
428{
429 return (time_left_handle_frame_get(scene, strip) <= timeline_frame) &&
430 (time_right_handle_frame_get(scene, strip) > timeline_frame);
431}
432
433bool time_has_left_still_frames(const Scene *scene, const Strip *strip)
434{
435 return time_left_handle_frame_get(scene, strip) < time_start_frame_get(strip);
436}
437
438bool time_has_right_still_frames(const Scene *scene, const Strip *strip)
439{
440 return time_right_handle_frame_get(scene, strip) > time_content_end_frame_get(scene, strip);
441}
442
443bool time_has_still_frames(const Scene *scene, const Strip *strip)
444{
445 return time_has_right_still_frames(scene, strip) || time_has_left_still_frames(scene, strip);
446}
447
448int time_strip_length_get(const Scene *scene, const Strip *strip)
449{
450 const float scene_fps = float(scene->r.frs_sec) / float(scene->r.frs_sec_base);
451 if (retiming_is_active(strip)) {
452 const int last_key_frame = retiming_key_timeline_frame_get(
453 scene, strip, retiming_last_key_get(strip));
454 /* Last key is mapped to last frame index. Numbering starts from 0. */
455 const int sound_offset = time_get_rounded_sound_offset(strip, scene_fps);
456 return last_key_frame - time_start_frame_get(strip) - sound_offset;
457 }
458
459 return strip->len / time_media_playback_rate_factor_get(strip, scene_fps);
460}
461
462float time_start_frame_get(const Strip *strip)
463{
464 return strip->start;
465}
466
467void time_start_frame_set(const Scene *scene, Strip *strip, int timeline_frame)
468{
469 strip->start = timeline_frame;
473}
474
475float time_content_end_frame_get(const Scene *scene, const Strip *strip)
476{
477 return time_start_frame_get(strip) + time_strip_length_get(scene, strip);
478}
479
480int time_left_handle_frame_get(const Scene * /*scene*/, const Strip *strip)
481{
482 if (strip->input1 || strip->input2) {
483 return strip->startdisp;
484 }
485
486 return strip->start + strip->startofs;
487}
488
489int time_right_handle_frame_get(const Scene *scene, const Strip *strip)
490{
491 if (strip->input1 || strip->input2) {
492 return strip->enddisp;
493 }
494
495 return time_content_end_frame_get(scene, strip) - strip->endofs;
496}
497
498void time_left_handle_frame_set(const Scene *scene, Strip *strip, int timeline_frame)
499{
500 const float right_handle_orig_frame = time_right_handle_frame_get(scene, strip);
501
502 if (timeline_frame >= right_handle_orig_frame) {
503 timeline_frame = right_handle_orig_frame - 1;
504 }
505
506 float offset = timeline_frame - time_start_frame_get(strip);
507
508 if (transform_single_image_check(strip)) {
509 /* This strip has only 1 frame of content that is always stretched to the whole strip length.
510 * Move strip start left and adjust end offset to be negative (rightwards past the 1 frame). */
511 time_start_frame_set(scene, strip, timeline_frame);
512 strip->endofs += offset;
513 }
514 else {
515 strip->startofs = offset;
516 }
517
518 strip->startdisp = timeline_frame; /* Only to make files usable in older versions. */
519
523}
524
525void time_right_handle_frame_set(const Scene *scene, Strip *strip, int timeline_frame)
526{
527 const float left_handle_orig_frame = time_left_handle_frame_get(scene, strip);
528
529 if (timeline_frame <= left_handle_orig_frame) {
530 timeline_frame = left_handle_orig_frame + 1;
531 }
532
533 strip->endofs = time_content_end_frame_get(scene, strip) - timeline_frame;
534 strip->enddisp = timeline_frame; /* Only to make files usable in older versions. */
535
539}
540
542 Strip *strip,
543 int left_handle_timeline_frame,
544 int right_handle_timeline_frame)
545{
546 time_right_handle_frame_set(scene, strip, right_handle_timeline_frame);
547 time_left_handle_frame_set(scene, strip, left_handle_timeline_frame);
548}
549
550void strip_time_translate_handles(const Scene *scene, Strip *strip, const int offset)
551{
552 strip->startofs += offset;
553 strip->endofs -= offset;
554 strip->startdisp += offset; /* Only to make files usable in older versions. */
555 strip->enddisp -= offset; /* Only to make files usable in older versions. */
556
560}
561
562static void strip_time_slip_strip_ex(const Scene *scene,
563 Strip *strip,
564 int delta,
565 float subframe_delta,
566 bool slip_keyframes,
567 bool recursed)
568{
569 if (strip->type == STRIP_TYPE_SOUND_RAM && subframe_delta != 0.0f) {
570 strip->sound_offset += subframe_delta / scene->frames_per_second();
571 }
572
573 if (delta == 0 && (!slip_keyframes || subframe_delta == 0.0f)) {
574 return;
575 }
576
577 /* Skip effect strips where the length is dependent on another strip,
578 * as they are calculated with #strip_time_update_effects_strip_range. */
579 if (strip->input1 != nullptr || strip->input2 != nullptr) {
580 return;
581 }
582
583 /* Effects only have a start frame and a length, so unless we're inside
584 * a meta strip, there's no need to do anything. */
585 if (!recursed && strip->is_effect()) {
586 return;
587 }
588
589 /* Move strips inside meta strip. */
590 if (strip->type == STRIP_TYPE_META) {
591 /* If the meta strip has no contents, don't do anything. */
592 if (BLI_listbase_is_empty(&strip->seqbase)) {
593 return;
594 }
595
596 LISTBASE_FOREACH (Strip *, strip_child, &strip->seqbase) {
597 /* The keyframes of strips inside meta strips should always be moved. */
598 strip_time_slip_strip_ex(scene, strip_child, delta, subframe_delta, true, true);
599 }
600 }
601
602 strip->start = strip->start + delta;
603
604 if (slip_keyframes) {
605 float anim_offset = delta;
606 if (strip->type == STRIP_TYPE_SOUND_RAM) {
607 anim_offset += subframe_delta;
608 }
609 offset_animdata(scene, strip, anim_offset);
610 }
611
612 if (!recursed) {
613 strip->startofs = strip->startofs - delta;
614 strip->endofs = strip->endofs + delta;
615 }
616
617 /* Only to make files usable in older versions. */
618 strip->startdisp = time_left_handle_frame_get(scene, strip);
619 strip->enddisp = time_right_handle_frame_get(scene, strip);
620
623}
624
626 const Scene *scene, Strip *strip, int frame_delta, float subframe_delta, bool slip_keyframes)
627{
628 strip_time_slip_strip_ex(scene, strip, frame_delta, subframe_delta, slip_keyframes, false);
629}
630
631int time_get_rounded_sound_offset(const Strip *strip, const float frames_per_second)
632{
633 if (strip->type == STRIP_TYPE_SOUND_RAM && strip->sound != nullptr) {
634 return round_fl_to_int((strip->sound->offset_time + strip->sound_offset) * frames_per_second);
635 }
636 return 0;
637}
638
639} // namespace blender::seq
float BKE_movieclip_get_fps(struct MovieClip *clip)
void BKE_sound_move_scene_sound(const struct Scene *scene, void *handle, int startframe, int endframe, int frameskip, double audio_offset)
#define LISTBASE_FOREACH(type, var, list)
BLI_INLINE bool BLI_listbase_is_empty(const ListBase *lb)
MINLINE int round_fl_to_int(float a)
MINLINE float max_ff(float a, float b)
MINLINE int min_ii(int a, int b)
MINLINE float clamp_f(float value, float min, float max)
MINLINE int max_ii(int a, int b)
#define ELEM(...)
#define MAXFRAME
@ STRIP_TYPE_SCENE
@ STRIP_TYPE_MOVIECLIP
@ STRIP_TYPE_SOUND_RAM
@ STRIP_TYPE_IMAGE
@ STRIP_TYPE_MOVIE
@ STRIP_TYPE_META
@ SEQ_REVERSE_FRAMES
@ SEQ_AUTO_PLAYBACK_RATE
nullptr float
#define SELECT
#define fmodf(x, y)
#define abs
float MOV_get_fps(const MovieReader *anim)
bool render_is_muted(const ListBase *channels, const Strip *strip)
Definition render.cc:2110
Strip * lookup_meta_by_strip(Editing *ed, const Strip *key)
int time_right_handle_frame_get(const Scene *scene, const Strip *strip)
VectorSet< Strip * > query_all_strips(ListBase *seqbase)
Definition iterator.cc:143
ListBase * channels_displayed_get(const Editing *ed)
Definition channels.cc:28
float time_content_end_frame_get(const Scene *scene, const Strip *strip)
bool time_has_right_still_frames(const Scene *scene, const Strip *strip)
float time_media_playback_rate_factor_get(const Strip *strip, const float scene_fps)
Definition strip_time.cc:41
void timeline_boundbox(const Scene *scene, const ListBase *seqbase, rctf *r_rect)
bool time_has_left_still_frames(const Scene *scene, const Strip *strip)
static int metastrip_end_get(Strip *strip_meta)
int retiming_key_timeline_frame_get(const Scene *scene, const Strip *strip, const SeqRetimingKey *key)
float give_frame_index(const Scene *scene, const Strip *strip, float timeline_frame)
Definition strip_time.cc:52
Editing * editing_get(const Scene *scene)
Definition sequencer.cc:286
static bool strip_exists_at_frame(const Scene *scene, blender::Span< Strip * > strips, const int timeline_frame)
blender::Span< Strip * > SEQ_lookup_effects_by_strip(Editing *ed, const Strip *key)
float time_strip_fps_get(Scene *scene, Strip *strip)
int time_left_handle_frame_get(const Scene *, const Strip *strip)
void offset_animdata(const Scene *scene, Strip *strip, float ofs)
Definition animation.cc:42
void seq_time_gap_info_get(const Scene *scene, ListBase *seqbase, const int initial_frame, GapInfo *r_gap_info)
void strip_open_anim_file(Scene *scene, Strip *strip, bool openfile)
int time_get_rounded_sound_offset(const Strip *strip, const float frames_per_second)
float time_start_frame_get(const Strip *strip)
void strip_time_update_effects_strip_range(const Scene *scene, const blender::Span< Strip * > effects)
bool transform_single_image_check(const Strip *strip)
int time_strip_length_get(const Scene *scene, const Strip *strip)
bool retiming_is_active(const Strip *strip)
void timeline_expand_boundbox(const Scene *scene, const ListBase *seqbase, rctf *rect)
void time_update_meta_strip_range(const Scene *scene, Strip *strip_meta)
bool time_strip_intersects_frame(const Scene *scene, const Strip *strip, const int timeline_frame)
void time_slip_strip(const Scene *scene, Strip *strip, int frame_delta, float subframe_delta, bool slip_keyframes)
void strip_time_translate_handles(const Scene *scene, Strip *strip, const int offset)
void time_handles_frame_set(const Scene *scene, Strip *strip, int left_handle_timeline_frame, int right_handle_timeline_frame)
void time_start_frame_set(const Scene *scene, Strip *strip, int timeline_frame)
void strip_update_sound_bounds_recursive(const Scene *scene, Strip *strip_meta)
static void strip_time_slip_strip_ex(const Scene *scene, Strip *strip, int delta, float subframe_delta, bool slip_keyframes, bool recursed)
void timeline_init_boundbox(const Scene *scene, rctf *r_rect)
bool time_has_still_frames(const Scene *scene, const Strip *strip)
static void strip_update_sound_bounds_recursive_impl(const Scene *scene, Strip *strip_meta, int start, int end)
void time_left_handle_frame_set(const Scene *scene, Strip *strip, int timeline_frame)
static int metastrip_start_get(Strip *strip_meta)
Definition strip_time.cc:96
void time_right_handle_frame_set(const Scene *scene, Strip *strip, int timeline_frame)
SeqRetimingKey * retiming_last_key_get(const Strip *strip)
float strip_retiming_evaluate(const Strip *strip, const float frame_index)
int time_find_next_prev_edit(Scene *scene, int timeline_frame, const short side, const bool do_skip_mute, const bool do_center, const bool do_unselected)
void strip_time_effect_range_set(const Scene *scene, Strip *strip)
#define min(a, b)
Definition sort.cc:36
void * first
struct Editing * ed
struct RenderData r
struct MovieReader * anim
struct Strip * input1
struct Scene * scene
struct MovieClip * clip
struct bSound * sound
ListBase seqbase
float media_playback_rate
float sound_offset
struct Strip * input2
ListBase anims
double offset_time
float xmax
float xmin
float ymax
float ymin
i
Definition text_draw.cc:230
max
Definition text_draw.cc:251