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>2021-08-24 02:01:48 +0300
committerRichard Antalik <richardantalik@gmail.com>2021-08-24 02:10:12 +0300
commit929d7597b345027b848c2997720e52b89c46a0ff (patch)
treee0882cc98e552a713e1336e07c55159087b7fece /source/blender/sequencer/intern/effects.c
parenta57ba4147f1344e9379a271fc752036969574a2d (diff)
VSE: Cleanup speed effect math
Simplify logic of speed effect frame calculation by using discrete math where possible. Only `SEQ_SPEED_MULTIPLY` mode with animation requires frame map to be built. Frame map building was simplified by removing unused branches. Functional change: Animating strip in negative range will reverse playback. I assume this was limitation of previous system, where each frame map item was limited to be within correct frame range. Now frame map can contain values that point beyond usable range and they are limited by `seq_speed_effect_target_frame_get`. This way it is possible to control playback rate in both directions. Mostly fixes T89120 apart from offset handling. Reviewed By: mano-wii Differential Revision: https://developer.blender.org/D11939
Diffstat (limited to 'source/blender/sequencer/intern/effects.c')
-rw-r--r--source/blender/sequencer/intern/effects.c209
1 files changed, 76 insertions, 133 deletions
diff --git a/source/blender/sequencer/intern/effects.c b/source/blender/sequencer/intern/effects.c
index 3ca0555d9a5..93ff6b4bf9c 100644
--- a/source/blender/sequencer/intern/effects.c
+++ b/source/blender/sequencer/intern/effects.c
@@ -3069,8 +3069,6 @@ static void init_speed_effect(Sequence *seq)
seq->effectdata = MEM_callocN(sizeof(SpeedControlVars), "speedcontrolvars");
v = (SpeedControlVars *)seq->effectdata;
- v->frameMap = NULL;
- v->length = 0;
v->speed_control_type = SEQ_SPEED_STRETCH;
v->speed_fader = 1.0f;
v->speed_fader_length = 0.0f;
@@ -3080,9 +3078,7 @@ static void init_speed_effect(Sequence *seq)
static void load_speed_effect(Sequence *seq)
{
SpeedControlVars *v = (SpeedControlVars *)seq->effectdata;
-
v->frameMap = NULL;
- v->length = 0;
}
static int num_inputs_speed(void)
@@ -3105,7 +3101,6 @@ static void copy_speed_effect(Sequence *dst, Sequence *src, const int UNUSED(fla
dst->effectdata = MEM_dupallocN(src->effectdata);
v = (SpeedControlVars *)dst->effectdata;
v->frameMap = NULL;
- v->length = 0;
}
static int early_out_speed(Sequence *UNUSED(seq), float UNUSED(facf0), float UNUSED(facf1))
@@ -3127,164 +3122,112 @@ static int seq_effect_speed_get_strip_content_length(const Sequence *seq)
return seq->len;
}
-void seq_effect_speed_rebuild_map(Scene *scene, Sequence *seq, bool force)
+static FCurve *seq_effect_speed_speed_factor_curve_get(Scene *scene, Sequence *seq)
{
- int timeline_frame;
- float fallback_fac = 1.0f;
- SpeedControlVars *v = (SpeedControlVars *)seq->effectdata;
- FCurve *fcu = NULL;
-
- /* if not already done, load / initialize data */
- SEQ_effect_handle_get(seq);
+ return id_data_find_fcurve(&scene->id, seq, &RNA_Sequence, "speed_factor", 0, NULL);
+}
- if ((force == false) && (seq->len == v->length) && (v->frameMap != NULL)) {
- return;
- }
+/* Build frame map when speed in mode #SEQ_SPEED_MULTIPLY is animated.
+ * This is, because `target_frame` value is integrated over time. */
+void seq_effect_speed_rebuild_map(Scene *scene, Sequence *seq)
+{
if ((seq->seq1 == NULL) || (seq->len < 1)) {
- /* make coverity happy and check for (CID 598) input strip ... */
- return;
+ return; /* Make coverity happy and check for (CID 598) input strip... */
}
- /* XXX(campbell): new in 2.5x. should we use the animation system this way?
- * The fcurve is needed because many frames need evaluating at once. */
- switch (v->speed_control_type) {
- case SEQ_SPEED_MULTIPLY: {
- fcu = id_data_find_fcurve(&scene->id, seq, &RNA_Sequence, "speed_factor", 0, NULL);
- break;
- }
- case SEQ_SPEED_FRAME_NUMBER: {
- fcu = id_data_find_fcurve(&scene->id, seq, &RNA_Sequence, "speed_frame_number", 0, NULL);
- break;
- }
- case SEQ_SPEED_LENGTH: {
- fcu = id_data_find_fcurve(&scene->id, seq, &RNA_Sequence, "speed_length", 0, NULL);
- break;
- }
+ FCurve *fcu = seq_effect_speed_speed_factor_curve_get(scene, seq);
+ if (fcu == NULL) {
+ return;
}
- if (!v->frameMap || v->length != seq->len) {
- if (v->frameMap) {
- MEM_freeN(v->frameMap);
- }
-
- v->length = seq->len;
- v->frameMap = MEM_callocN(sizeof(float) * v->length, "speedcontrol frameMap");
+ SpeedControlVars *v = (SpeedControlVars *)seq->effectdata;
+ if (v->frameMap) {
+ MEM_freeN(v->frameMap);
}
- fallback_fac = 1.0;
+ const int effect_strip_length = seq->enddisp - seq->startdisp;
+ v->frameMap = MEM_mallocN(sizeof(float) * effect_strip_length, __func__);
+ v->frameMap[0] = 0.0f;
- const int target_strip_length = seq_effect_speed_get_strip_content_length(seq->seq1);
-
- if (v->speed_control_type == SEQ_SPEED_STRETCH) {
- if ((seq->seq1->enddisp != seq->seq1->start) && (target_strip_length != 0)) {
- fallback_fac = (float)target_strip_length / (float)(seq->seq1->enddisp - seq->seq1->start);
- fcu = NULL;
- }
- }
- else {
- /* if there is no fcurve, use value as simple multiplier */
- if (!fcu) {
- switch (v->speed_control_type) {
- case SEQ_SPEED_MULTIPLY: {
- fallback_fac = v->speed_fader;
- break;
- }
- case SEQ_SPEED_FRAME_NUMBER: {
- fallback_fac = v->speed_fader_frame_number;
- break;
- }
- case SEQ_SPEED_LENGTH: {
- fallback_fac = v->speed_fader_length;
- break;
- }
- }
- }
+ float target_frame = 0;
+ for (int frame_index = 1; frame_index < effect_strip_length; frame_index++) {
+ target_frame += evaluate_fcurve(fcu, seq->startdisp + frame_index);
+ v->frameMap[frame_index] = target_frame;
}
+}
- if (ELEM(v->speed_control_type, SEQ_SPEED_MULTIPLY, SEQ_SPEED_STRETCH)) {
- float cursor = 0;
- float facf;
-
- v->frameMap[0] = 0;
- v->lastValidFrame = 0;
-
- for (timeline_frame = 1; timeline_frame < v->length; timeline_frame++) {
- if (fcu) {
- facf = evaluate_fcurve(fcu, seq->startdisp + timeline_frame);
- }
- else {
- facf = fallback_fac;
- }
-
- cursor += facf;
-
- if (cursor >= target_strip_length) {
- v->frameMap[timeline_frame] = target_strip_length - 1;
- }
- else {
- v->frameMap[timeline_frame] = cursor;
- v->lastValidFrame = timeline_frame;
- }
- }
+static void seq_effect_speed_frame_map_ensure(Scene *scene, Sequence *seq, FCurve *fcu)
+{
+ SpeedControlVars *v = (SpeedControlVars *)seq->effectdata;
+ if (v->frameMap != NULL) {
+ return;
}
- else {
- float facf;
- v->lastValidFrame = 0;
- for (timeline_frame = 0; timeline_frame < v->length; timeline_frame++) {
+ seq_effect_speed_rebuild_map(scene, seq);
+}
- if (fcu) {
- facf = evaluate_fcurve(fcu, seq->startdisp + timeline_frame);
- }
- else {
- facf = fallback_fac;
- }
+/* Override timeline_frame when rendering speed effect input. */
+float seq_speed_effect_target_frame_get(Scene *scene,
+ Sequence *seq_speed,
+ float timeline_frame,
+ int input)
+{
+ if (seq_speed->seq1 == NULL) {
+ return 0.0f;
+ }
- if (v->speed_control_type == SEQ_SPEED_LENGTH) {
- facf *= target_strip_length;
- facf /= 100.0f;
- }
+ SEQ_effect_handle_get(seq_speed); /* Ensure, that data are initialized. */
+ int frame_index = seq_give_frame_index(seq_speed, timeline_frame);
+ SpeedControlVars *s = (SpeedControlVars *)seq_speed->effectdata;
+ const Sequence *source = seq_speed->seq1;
- if (facf >= target_strip_length) {
- facf = target_strip_length - 1;
+ float target_frame = 0.0f;
+ switch (s->speed_control_type) {
+ case SEQ_SPEED_STRETCH:
+ const float target_content_length = seq_effect_speed_get_strip_content_length(source);
+ const float target_strip_length = source->enddisp - source->startdisp;
+ const float ratio = target_content_length / target_strip_length;
+ target_frame = frame_index * ratio;
+ break;
+ case SEQ_SPEED_MULTIPLY:
+ FCurve *fcu = seq_effect_speed_speed_factor_curve_get(scene, seq_speed);
+ if (fcu != NULL) {
+ seq_effect_speed_frame_map_ensure(scene, seq_speed, fcu);
+ target_frame = s->frameMap[frame_index];
}
else {
- v->lastValidFrame = timeline_frame;
+ target_frame = frame_index * s->speed_fader;
}
- v->frameMap[timeline_frame] = facf;
- }
+ break;
+ case SEQ_SPEED_LENGTH:
+ target_frame = seq_effect_speed_get_strip_content_length(source) *
+ (s->speed_fader_length / 100.0f);
+ break;
+ case SEQ_SPEED_FRAME_NUMBER:
+ target_frame = s->speed_fader_frame_number;
+ break;
}
-}
-/* Override timeline_frame when rendering speed effect input. */
-float seq_speed_effect_target_frame_get(const SeqRenderData *context,
- Sequence *seq,
- float timeline_frame,
- int input)
-{
- int frame_index = seq_give_frame_index(seq, timeline_frame);
- SpeedControlVars *s = (SpeedControlVars *)seq->effectdata;
- seq_effect_speed_rebuild_map(context->scene, seq, false);
+ CLAMP(target_frame, 0, seq_effect_speed_get_strip_content_length(source));
+ target_frame += seq_speed->start;
/* No interpolation. */
if ((s->flags & SEQ_SPEED_USE_INTERPOLATION) == 0) {
- return seq->start + s->frameMap[frame_index];
+ return target_frame;
}
- /* We need to provide current and next image for interpolation. */
- if (input == 0) { /* Current frame. */
- return floor(seq->start + s->frameMap[frame_index]);
- }
- /* Next frame. */
- return ceil(seq->start + s->frameMap[frame_index]);
+ /* Interpolation is used, switch between current and next frame based on which input is
+ * requested. */
+ return input == 0 ? target_frame : ceil(target_frame);
}
-static float speed_effect_interpolation_ratio_get(SpeedControlVars *s,
- Sequence *seq,
+static float speed_effect_interpolation_ratio_get(Scene *scene,
+ Sequence *seq_speed,
float timeline_frame)
{
- int frame_index = seq_give_frame_index(seq, timeline_frame);
- return s->frameMap[frame_index] - floor(s->frameMap[frame_index]);
+ const float target_frame = seq_speed_effect_target_frame_get(
+ scene, seq_speed, timeline_frame, 0);
+ return target_frame - floor(target_frame);
}
static ImBuf *do_speed_effect(const SeqRenderData *context,
@@ -3302,7 +3245,7 @@ static ImBuf *do_speed_effect(const SeqRenderData *context,
if (s->flags & SEQ_SPEED_USE_INTERPOLATION) {
out = prepare_effect_imbufs(context, ibuf1, ibuf2, ibuf3);
- facf0 = facf1 = speed_effect_interpolation_ratio_get(s, seq, timeline_frame);
+ facf0 = facf1 = speed_effect_interpolation_ratio_get(context->scene, seq, timeline_frame);
/* Current frame is ibuf1, next frame is ibuf2. */
out = seq_render_effect_execute_threaded(
&cross_effect, context, NULL, timeline_frame, facf0, facf1, ibuf1, ibuf2, ibuf3);