[Bf-blender-cvs] [929d7597b34] master: VSE: Cleanup speed effect math

Richard Antalik noreply at git.blender.org
Tue Aug 24 01:10:39 CEST 2021


Commit: 929d7597b345027b848c2997720e52b89c46a0ff
Author: Richard Antalik
Date:   Tue Aug 24 01:01:48 2021 +0200
Branches: master
https://developer.blender.org/rB929d7597b345027b848c2997720e52b89c46a0ff

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

===================================================================

M	source/blender/blenkernel/intern/scene.c
M	source/blender/makesdna/DNA_sequence_types.h
M	source/blender/sequencer/intern/effects.c
M	source/blender/sequencer/intern/effects.h
M	source/blender/sequencer/intern/render.c
M	source/blender/sequencer/intern/strip_relations.c

===================================================================

diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c
index 3fe00adc4d5..a6190efbf75 100644
--- a/source/blender/blenkernel/intern/scene.c
+++ b/source/blender/blenkernel/intern/scene.c
@@ -1176,11 +1176,6 @@ static void scene_blend_read_data(BlendDataReader *reader, ID *id)
         seq->flag |= SEQ_EFFECT_NOT_LOADED;
       }
 
-      if (seq->type == SEQ_TYPE_SPEED) {
-        SpeedControlVars *s = seq->effectdata;
-        s->frameMap = NULL;
-      }
-
       if (seq->type == SEQ_TYPE_TEXT) {
         TextVars *t = seq->effectdata;
         t->text_blf_id = SEQ_FONT_NOT_LOADED;
diff --git a/source/blender/makesdna/DNA_sequence_types.h b/source/blender/makesdna/DNA_sequence_types.h
index df18501d2ea..03c38eb71a0 100644
--- a/source/blender/makesdna/DNA_sequence_types.h
+++ b/source/blender/makesdna/DNA_sequence_types.h
@@ -339,11 +339,8 @@ typedef struct SpeedControlVars {
   float *frameMap;
   /* DEPRECATED, only used for versioning. */
   float globalSpeed;
-  /* DEPRECATED, only used for versioning. */
   int flags;
 
-  int length;
-  int lastValidFrame;
   int speed_control_type;
 
   float speed_fader;
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_i

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list