Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Antalik <richardantalik@gmail.com>2022-06-29 13:45:59 +0300
committerRichard Antalik <richardantalik@gmail.com>2022-06-29 13:48:34 +0300
commit302b04a5a3fc0e767ac784424f78ce2edf5d2844 (patch)
treedef4de621fbb0a194b350da781f054c6aefbab35 /source/blender/sequencer/intern/strip_time.c
parentc51b8ec86364585c4088837c603b39752065bc34 (diff)
VSE: Improved Retiming system
Patch implements better way to control playback speed than it is possible to do with speed effect. Speed factor property can be set in Time panel. There are 2 layers of control: Option to retime movie to match scene FPS rate. Custom speed factor to control playback rate. Since playback rate is strip property, it is now possible to manipulate strip as normal one even if it is retimed. To facilitate manipulation, some functions need to consider speed factor and apply necessary corrections to strip offset or strip start. These corrections may need to be float numbers, so start and offsets must be float as well. Sound strips now use speed factor instead of pitch. This means, that strips will change length to match usable length. In addition, it is possible to group movie and sound strip and change speed of meta strip.
Diffstat (limited to 'source/blender/sequencer/intern/strip_time.c')
-rw-r--r--source/blender/sequencer/intern/strip_time.c193
1 files changed, 127 insertions, 66 deletions
diff --git a/source/blender/sequencer/intern/strip_time.c b/source/blender/sequencer/intern/strip_time.c
index 4d6efb1639b..d4357fe28b6 100644
--- a/source/blender/sequencer/intern/strip_time.c
+++ b/source/blender/sequencer/intern/strip_time.c
@@ -31,14 +31,32 @@
#include "strip_time.h"
#include "utils.h"
-float seq_give_frame_index(Sequence *seq, float timeline_frame)
+static float seq_time_media_playback_rate_factor_get(const Scene *scene, const Sequence *seq)
+{
+ if ((seq->flag & SEQ_AUTO_PLAYBACK_RATE) == 0) {
+ return 1.0f;
+ }
+ if (seq->media_playback_rate == 0.0f) {
+ return 1.0f;
+ }
+
+ float scene_playback_rate = (float)scene->r.frs_sec / scene->r.frs_sec_base;
+ return seq->media_playback_rate / scene_playback_rate;
+}
+
+static float seq_time_playback_rate_factor_get(const Scene *scene, const Sequence *seq)
+{
+ return seq_time_media_playback_rate_factor_get(scene, seq) * seq->speed_factor;
+}
+
+float seq_give_frame_index(const Scene *scene, Sequence *seq, float timeline_frame)
{
float frame_index;
- int sta = seq->start;
- int end = seq->start + seq->len - 1;
+ float sta = SEQ_time_start_frame_get(seq);
+ float end = SEQ_time_start_frame_get(seq) + SEQ_time_strip_length_get(scene, seq) - 1;
if (seq->type & SEQ_TYPE_EFFECT) {
- end = SEQ_time_right_handle_frame_get(seq);
+ end = SEQ_time_right_handle_frame_get(scene, seq);
}
if (end < sta) {
@@ -46,29 +64,16 @@ float seq_give_frame_index(Sequence *seq, float timeline_frame)
}
if (seq->flag & SEQ_REVERSE_FRAMES) {
- /* Reverse frame in this sequence. */
- if (timeline_frame <= sta) {
- frame_index = end - sta;
- }
- else if (timeline_frame >= end) {
- frame_index = 0;
- }
- else {
- frame_index = end - timeline_frame;
- }
+ frame_index = end - timeline_frame;
}
else {
- if (timeline_frame <= sta) {
- frame_index = 0;
- }
- else if (timeline_frame >= end) {
- frame_index = end - sta;
- }
- else {
- frame_index = timeline_frame - sta;
- }
+ frame_index = timeline_frame - sta;
}
+ /* Clamp frame index to strip frame range. */
+ frame_index = clamp_f(frame_index, 0, end - sta);
+ frame_index *= seq_time_playback_rate_factor_get(scene, seq);
+
if (seq->strobe < 1.0f) {
seq->strobe = 1.0f;
}
@@ -149,14 +154,14 @@ void SEQ_time_update_meta_strip_range(const Scene *scene, Sequence *seq_meta)
return;
}
- const int strip_start = SEQ_time_left_handle_frame_get(seq_meta);
- const int strip_end = SEQ_time_right_handle_frame_get(seq_meta);
+ const int strip_start = SEQ_time_left_handle_frame_get(scene, seq_meta);
+ const int strip_end = SEQ_time_right_handle_frame_get(scene, seq_meta);
int min = MAXFRAME * 2;
int max = -MAXFRAME * 2;
LISTBASE_FOREACH (Sequence *, seq, &seq_meta->seqbase) {
- min = min_ii(SEQ_time_left_handle_frame_get(seq), min);
- max = max_ii(SEQ_time_right_handle_frame_get(seq), max);
+ min = min_ii(SEQ_time_left_handle_frame_get(scene, seq), min);
+ max = max_ii(SEQ_time_right_handle_frame_get(scene, seq), max);
}
seq_meta->start = min + seq_meta->anim_startofs;
@@ -171,25 +176,25 @@ void SEQ_time_update_meta_strip_range(const Scene *scene, Sequence *seq_meta)
SEQ_time_right_handle_frame_set(scene, seq_meta, strip_end);
}
-void seq_time_effect_range_set(Sequence *seq)
+void seq_time_effect_range_set(const Scene *scene, Sequence *seq)
{
if (seq->seq1 == NULL && seq->seq2 == NULL) {
return;
}
if (seq->seq1 && seq->seq2) { /* 2 - input effect. */
- seq->startdisp = max_ii(SEQ_time_left_handle_frame_get(seq->seq1),
- SEQ_time_left_handle_frame_get(seq->seq2));
- seq->enddisp = min_ii(SEQ_time_right_handle_frame_get(seq->seq1),
- SEQ_time_right_handle_frame_get(seq->seq2));
+ seq->startdisp = max_ii(SEQ_time_left_handle_frame_get(scene, seq->seq1),
+ SEQ_time_left_handle_frame_get(scene, seq->seq2));
+ seq->enddisp = min_ii(SEQ_time_right_handle_frame_get(scene, seq->seq1),
+ SEQ_time_right_handle_frame_get(scene, seq->seq2));
}
else if (seq->seq1) { /* Single input effect. */
- seq->startdisp = SEQ_time_right_handle_frame_get(seq->seq1);
- seq->enddisp = SEQ_time_left_handle_frame_get(seq->seq1);
+ seq->startdisp = SEQ_time_right_handle_frame_get(scene, seq->seq1);
+ seq->enddisp = SEQ_time_left_handle_frame_get(scene, seq->seq1);
}
else if (seq->seq2) { /* Strip may be missing one of inputs. */
- seq->startdisp = SEQ_time_right_handle_frame_get(seq->seq2);
- seq->enddisp = SEQ_time_left_handle_frame_get(seq->seq2);
+ seq->startdisp = SEQ_time_right_handle_frame_get(scene, seq->seq2);
+ seq->enddisp = SEQ_time_left_handle_frame_get(scene, seq->seq2);
}
if (seq->startdisp > seq->enddisp) {
@@ -210,7 +215,7 @@ void seq_time_update_effects_strip_range(const Scene *scene, SeqCollection *effe
Sequence *seq;
/* First pass: Update length of immediate effects. */
SEQ_ITERATOR_FOREACH (seq, effects) {
- seq_time_effect_range_set(seq);
+ seq_time_effect_range_set(scene, seq);
}
/* Second pass: Recursive call to update effects in chain and in order, so they inherit length
@@ -255,14 +260,14 @@ int SEQ_time_find_next_prev_edit(Scene *scene,
}
if (do_center) {
- seq_frames[0] = (SEQ_time_left_handle_frame_get(seq) +
- SEQ_time_right_handle_frame_get(seq)) /
+ seq_frames[0] = (SEQ_time_left_handle_frame_get(scene, seq) +
+ SEQ_time_right_handle_frame_get(scene, seq)) /
2;
seq_frames_tot = 1;
}
else {
- seq_frames[0] = SEQ_time_left_handle_frame_get(seq);
- seq_frames[1] = SEQ_time_right_handle_frame_get(seq);
+ seq_frames[0] = SEQ_time_left_handle_frame_get(scene, seq);
+ seq_frames[1] = SEQ_time_right_handle_frame_get(scene, seq);
seq_frames_tot = 2;
}
@@ -339,18 +344,18 @@ void SEQ_timeline_init_boundbox(const Scene *scene, rctf *rect)
rect->ymax = 8.0f;
}
-void SEQ_timeline_expand_boundbox(const ListBase *seqbase, rctf *rect)
+void SEQ_timeline_expand_boundbox(const Scene *scene, const ListBase *seqbase, rctf *rect)
{
if (seqbase == NULL) {
return;
}
LISTBASE_FOREACH (Sequence *, seq, seqbase) {
- if (rect->xmin > SEQ_time_left_handle_frame_get(seq) - 1) {
- rect->xmin = SEQ_time_left_handle_frame_get(seq) - 1;
+ if (rect->xmin > SEQ_time_left_handle_frame_get(scene, seq) - 1) {
+ rect->xmin = SEQ_time_left_handle_frame_get(scene, seq) - 1;
}
- if (rect->xmax < SEQ_time_right_handle_frame_get(seq) + 1) {
- rect->xmax = SEQ_time_right_handle_frame_get(seq) + 1;
+ if (rect->xmax < SEQ_time_right_handle_frame_get(scene, seq) + 1) {
+ rect->xmax = SEQ_time_right_handle_frame_get(scene, seq) + 1;
}
if (rect->ymax < seq->machine) {
rect->ymax = seq->machine;
@@ -361,14 +366,16 @@ void SEQ_timeline_expand_boundbox(const ListBase *seqbase, rctf *rect)
void SEQ_timeline_boundbox(const Scene *scene, const ListBase *seqbase, rctf *rect)
{
SEQ_timeline_init_boundbox(scene, rect);
- SEQ_timeline_expand_boundbox(seqbase, rect);
+ SEQ_timeline_expand_boundbox(scene, seqbase, rect);
}
-static bool strip_exists_at_frame(SeqCollection *all_strips, const int timeline_frame)
+static bool strip_exists_at_frame(const Scene *scene,
+ SeqCollection *all_strips,
+ const int timeline_frame)
{
Sequence *seq;
SEQ_ITERATOR_FOREACH (seq, all_strips) {
- if (SEQ_time_strip_intersects_frame(seq, timeline_frame)) {
+ if (SEQ_time_strip_intersects_frame(scene, seq, timeline_frame)) {
return true;
}
}
@@ -390,10 +397,10 @@ void seq_time_gap_info_get(const Scene *scene,
SeqCollection *collection = SEQ_query_all_strips(seqbase);
- if (!strip_exists_at_frame(collection, initial_frame)) {
+ if (!strip_exists_at_frame(scene, collection, initial_frame)) {
/* Search backward for gap_start_frame. */
for (; timeline_frame >= sfra; timeline_frame--) {
- if (strip_exists_at_frame(collection, timeline_frame)) {
+ if (strip_exists_at_frame(scene, collection, timeline_frame)) {
break;
}
}
@@ -403,7 +410,7 @@ void seq_time_gap_info_get(const Scene *scene,
else {
/* Search forward for gap_start_frame. */
for (; timeline_frame <= efra; timeline_frame++) {
- if (!strip_exists_at_frame(collection, timeline_frame)) {
+ if (!strip_exists_at_frame(scene, collection, timeline_frame)) {
r_gap_info->gap_start_frame = timeline_frame;
break;
}
@@ -411,7 +418,7 @@ void seq_time_gap_info_get(const Scene *scene,
}
/* Search forward for gap_end_frame. */
for (; timeline_frame <= efra; timeline_frame++) {
- if (strip_exists_at_frame(collection, timeline_frame)) {
+ if (strip_exists_at_frame(scene, collection, timeline_frame)) {
const int gap_end_frame = timeline_frame;
r_gap_info->gap_length = gap_end_frame - r_gap_info->gap_start_frame;
r_gap_info->gap_exists = true;
@@ -420,28 +427,67 @@ void seq_time_gap_info_get(const Scene *scene,
}
}
-bool SEQ_time_strip_intersects_frame(const Sequence *seq, const int timeline_frame)
+bool SEQ_time_strip_intersects_frame(const Scene *scene,
+ const Sequence *seq,
+ const int timeline_frame)
+{
+ return (SEQ_time_left_handle_frame_get(scene, seq) <= timeline_frame) &&
+ (SEQ_time_right_handle_frame_get(scene, seq) > timeline_frame);
+}
+
+void SEQ_time_speed_factor_set(const Scene *scene, Sequence *seq, const float speed_factor)
+{
+ const float left_handle_frame = SEQ_time_left_handle_frame_get(scene, seq);
+ const float unity_start_offset = seq->startofs * seq->speed_factor;
+ const float unity_end_offset = seq->endofs * seq->speed_factor;
+
+ /* Left handle is pivot point for content scaling - it must always show same frame. */
+ seq->speed_factor = speed_factor;
+ seq->startofs = unity_start_offset / speed_factor;
+ seq->start = left_handle_frame - seq->startofs;
+ seq->endofs = unity_end_offset / speed_factor;
+
+ SEQ_time_update_meta_strip_range(scene, seq_sequence_lookup_meta_by_seq(scene, seq));
+ seq_time_update_effects_strip_range(scene, seq_sequence_lookup_effects_by_seq(scene, seq));
+}
+
+bool SEQ_time_has_left_still_frames(const Scene *scene, const Sequence *seq)
+{
+ return SEQ_time_left_handle_frame_get(scene, seq) < SEQ_time_start_frame_get(seq);
+}
+
+bool SEQ_time_has_right_still_frames(const Scene *scene, const Sequence *seq)
+{
+ return SEQ_time_right_handle_frame_get(scene, seq) >
+ SEQ_time_start_frame_get(seq) + SEQ_time_strip_length_get(scene, seq);
+}
+
+bool SEQ_time_has_still_frames(const Scene *scene, const Sequence *seq)
{
- return (SEQ_time_left_handle_frame_get(seq) <= timeline_frame) &&
- (SEQ_time_right_handle_frame_get(seq) > timeline_frame);
+ return SEQ_time_has_right_still_frames(scene, seq) || SEQ_time_has_left_still_frames(scene, seq);
}
-bool SEQ_time_has_left_still_frames(const Sequence *seq)
+/* Length of strip content in frames. This is number of original frames adjusted by playback rate
+ * factor */
+int SEQ_time_strip_length_get(const Scene *scene, const Sequence *seq)
{
- return seq->startofs < 0;
+ return seq->len / seq_time_playback_rate_factor_get(scene, seq);
}
-bool SEQ_time_has_right_still_frames(const Sequence *seq)
+/* Return timeline frame, where strip content starts. */
+float SEQ_time_start_frame_get(const Sequence *seq)
{
- return seq->endofs < 0;
+ return seq->start;
}
-bool SEQ_time_has_still_frames(const Sequence *seq)
+void SEQ_time_start_frame_set(const Scene *scene, Sequence *seq, int timeline_frame)
{
- return SEQ_time_has_right_still_frames(seq) || SEQ_time_has_left_still_frames(seq);
+ seq->start = timeline_frame;
+ SEQ_time_update_meta_strip_range(scene, seq_sequence_lookup_meta_by_seq(scene, seq));
+ seq_time_update_effects_strip_range(scene, seq_sequence_lookup_effects_by_seq(scene, seq));
}
-int SEQ_time_left_handle_frame_get(const Sequence *seq)
+int SEQ_time_left_handle_frame_get(const Scene *UNUSED(scene), const Sequence *seq)
{
if (seq->seq1 || seq->seq2) {
return seq->startdisp;
@@ -450,27 +496,42 @@ int SEQ_time_left_handle_frame_get(const Sequence *seq)
return seq->start + seq->startofs;
}
-int SEQ_time_right_handle_frame_get(const Sequence *seq)
+int SEQ_time_right_handle_frame_get(const Scene *scene, const Sequence *seq)
{
if (seq->seq1 || seq->seq2) {
return seq->enddisp;
}
- return seq->start + seq->len - seq->endofs;
+ return seq->start + SEQ_time_strip_length_get(scene, seq) - seq->endofs;
}
void SEQ_time_left_handle_frame_set(const Scene *scene, Sequence *seq, int val)
{
+ const float right_handle_orig_frame = SEQ_time_right_handle_frame_get(scene, seq);
+
+ if (val >= right_handle_orig_frame) {
+ val = right_handle_orig_frame - 1;
+ }
+
seq->startofs = val - seq->start;
seq->startdisp = val; /* Only to make files usable in older versions. */
+
SEQ_time_update_meta_strip_range(scene, seq_sequence_lookup_meta_by_seq(scene, seq));
seq_time_update_effects_strip_range(scene, seq_sequence_lookup_effects_by_seq(scene, seq));
}
void SEQ_time_right_handle_frame_set(const Scene *scene, Sequence *seq, int val)
{
- seq->endofs = seq->start + seq->len - val;
+ const float strip_content_end_frame = seq->start + SEQ_time_strip_length_get(scene, seq);
+ const float left_handle_orig_frame = SEQ_time_left_handle_frame_get(scene, seq);
+
+ if (val <= left_handle_orig_frame) {
+ val = left_handle_orig_frame + 1;
+ }
+
+ seq->endofs = strip_content_end_frame - val;
seq->enddisp = val; /* Only to make files usable in older versions. */
+
SEQ_time_update_meta_strip_range(scene, seq_sequence_lookup_meta_by_seq(scene, seq));
seq_time_update_effects_strip_range(scene, seq_sequence_lookup_effects_by_seq(scene, seq));
}