Blender V5.0
vse_effect_speed.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2024 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include "BKE_fcurve.hh"
10
11#include "DNA_scene_types.h"
12#include "DNA_sequence_types.h"
13
14#include "IMB_imbuf.hh"
15
16#include "RNA_prototypes.hh"
17
18#include "SEQ_render.hh"
19#include "SEQ_time.hh"
20
21#include "effects.hh"
22#include "render.hh"
23
24namespace blender::seq {
25
26static void init_speed_effect(Strip *strip)
27{
28 if (strip->effectdata) {
29 MEM_freeN(strip->effectdata);
30 }
31
33 strip->effectdata = v;
34
35 v->speed_control_type = SEQ_SPEED_STRETCH;
36 v->speed_fader = 1.0f;
37 v->speed_fader_length = 0.0f;
38 v->speed_fader_frame_number = 0.0f;
39}
40
41static void load_speed_effect(Strip *strip)
42{
44 v->frameMap = nullptr;
45}
46
47static int num_inputs_speed()
48{
49 return 1;
50}
51
52static void free_speed_effect(Strip *strip, const bool /*do_id_user*/)
53{
55 if (v->frameMap) {
56 MEM_freeN(v->frameMap);
57 }
59}
60
61static void copy_speed_effect(Strip *dst, const Strip *src, const int /*flag*/)
62{
66 v->frameMap = nullptr;
67}
68
69static StripEarlyOut early_out_speed(const Strip * /*strip*/, float /*fac*/)
70{
72}
73
75{
76 return id_data_find_fcurve(&scene->id, strip, &RNA_Strip, "speed_factor", 0, nullptr);
77}
78
80{
81 const int effect_strip_length = time_right_handle_frame_get(scene, strip) -
82 time_left_handle_frame_get(scene, strip);
83
84 if ((strip->input1 == nullptr) || (effect_strip_length < 1)) {
85 return; /* Make COVERITY happy and check for (CID 598) input strip. */
86 }
87
88 const FCurve *fcu = strip_effect_speed_speed_factor_curve_get(scene, strip);
89 if (fcu == nullptr) {
90 return;
91 }
92
94 if (v->frameMap) {
95 MEM_freeN(v->frameMap);
96 }
97
98 v->frameMap = MEM_malloc_arrayN<float>(size_t(effect_strip_length), __func__);
99 v->frameMap[0] = 0.0f;
100
101 float target_frame = 0;
102 for (int frame_index = 1; frame_index < effect_strip_length; frame_index++) {
103 target_frame += evaluate_fcurve(fcu, time_left_handle_frame_get(scene, strip) + frame_index);
104 const int target_frame_max = time_strip_length_get(scene, strip->input1);
105 CLAMP(target_frame, 0, target_frame_max);
106 v->frameMap[frame_index] = target_frame;
107 }
108}
109
111{
113 if (v->frameMap != nullptr) {
114 return;
115 }
116
117 strip_effect_speed_rebuild_map(scene, strip);
118}
119
121 Strip *strip_speed,
122 float timeline_frame,
123 int input)
124{
125 if (strip_speed->input1 == nullptr) {
126 return 0.0f;
127 }
128
129 strip_effect_handle_get(strip_speed); /* Ensure, that data are initialized. */
130 int frame_index = round_fl_to_int(give_frame_index(scene, strip_speed, timeline_frame));
131 SpeedControlVars *s = (SpeedControlVars *)strip_speed->effectdata;
132 const Strip *source = strip_speed->input1;
133
134 float target_frame = 0.0f;
135 switch (s->speed_control_type) {
136 case SEQ_SPEED_STRETCH: {
137 /* Only right handle controls effect speed! */
138 const float target_content_length = time_strip_length_get(scene, source) - source->startofs;
139 const float speed_effetct_length = time_right_handle_frame_get(scene, strip_speed) -
140 time_left_handle_frame_get(scene, strip_speed);
141 const float ratio = frame_index / speed_effetct_length;
142 target_frame = target_content_length * ratio;
143 break;
144 }
145 case SEQ_SPEED_MULTIPLY: {
146 const FCurve *fcu = strip_effect_speed_speed_factor_curve_get(scene, strip_speed);
147 if (fcu != nullptr) {
148 strip_effect_speed_frame_map_ensure(scene, strip_speed);
149 target_frame = s->frameMap[frame_index];
150 }
151 else {
152 target_frame = frame_index * s->speed_fader;
153 }
154 break;
155 }
156 case SEQ_SPEED_LENGTH:
157 target_frame = time_strip_length_get(scene, source) * (s->speed_fader_length / 100.0f);
158 break;
160 target_frame = s->speed_fader_frame_number;
161 break;
162 }
163
164 CLAMP(target_frame, 0, time_strip_length_get(scene, source));
165 target_frame += strip_speed->start;
166
167 /* No interpolation. */
168 if ((s->flags & SEQ_SPEED_USE_INTERPOLATION) == 0) {
169 return target_frame;
170 }
171
172 /* Interpolation is used, switch between current and next frame based on which input is
173 * requested. */
174 return input == 0 ? target_frame : ceil(target_frame);
175}
176
178 Strip *strip_speed,
179 float timeline_frame)
180{
181 const float target_frame = strip_speed_effect_target_frame_get(
182 scene, strip_speed, timeline_frame, 0);
183 return target_frame - floor(target_frame);
184}
185
186static ImBuf *do_speed_effect(const RenderData *context,
188 Strip *strip,
189 float timeline_frame,
190 float fac,
191 ImBuf *ibuf1,
192 ImBuf *ibuf2)
193{
194 const SpeedControlVars *s = (SpeedControlVars *)strip->effectdata;
196 ImBuf *out;
197
199 fac = speed_effect_interpolation_ratio_get(context->scene, strip, timeline_frame);
200 /* Current frame is ibuf1, next frame is ibuf2. */
201 out = cross_effect.execute(context, state, nullptr, timeline_frame, fac, ibuf1, ibuf2);
202 return out;
203 }
204
205 /* No interpolation. */
206 return IMB_dupImBuf(ibuf1);
207}
208
219
220} // namespace blender::seq
float evaluate_fcurve(const FCurve *fcu, float evaltime)
FCurve * id_data_find_fcurve(ID *id, void *data, StructRNA *type, const char *prop_name, int index, bool *r_driven)
MINLINE int round_fl_to_int(float a)
#define CLAMP(a, b, c)
@ SEQ_SPEED_STRETCH
@ SEQ_SPEED_MULTIPLY
@ SEQ_SPEED_LENGTH
@ SEQ_SPEED_FRAME_NUMBER
@ STRIP_TYPE_CROSS
@ SEQ_SPEED_USE_INTERPOLATION
ImBuf * IMB_dupImBuf(const ImBuf *ibuf1)
#define MEM_SAFE_FREE(v)
ATTR_WARN_UNUSED_RESULT const BMVert * v
#define input
#define out
#define floor
#define ceil
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void * MEM_malloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:133
void * MEM_dupallocN(const void *vmemh)
Definition mallocn.cc:143
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
static ulong state[N]
int time_right_handle_frame_get(const Scene *scene, const Strip *strip)
static float speed_effect_interpolation_ratio_get(Scene *scene, Strip *strip_speed, float timeline_frame)
EffectHandle strip_effect_handle_get(Strip *strip)
Definition effects.cc:290
static void free_speed_effect(Strip *strip, const bool)
float give_frame_index(const Scene *scene, const Strip *strip, float timeline_frame)
Definition strip_time.cc:52
static void copy_speed_effect(Strip *dst, const Strip *src, const int)
int time_left_handle_frame_get(const Scene *, const Strip *strip)
static void init_speed_effect(Strip *strip)
static ImBuf * do_speed_effect(const RenderData *context, SeqRenderState *state, Strip *strip, float timeline_frame, float fac, ImBuf *ibuf1, ImBuf *ibuf2)
static FCurve * strip_effect_speed_speed_factor_curve_get(Scene *scene, Strip *strip)
int time_strip_length_get(const Scene *scene, const Strip *strip)
static void strip_effect_speed_frame_map_ensure(Scene *scene, Strip *strip)
float strip_speed_effect_target_frame_get(Scene *scene, Strip *strip_speed, float timeline_frame, int input)
void speed_effect_get_handle(EffectHandle &rval)
void strip_effect_speed_rebuild_map(Scene *scene, Strip *strip)
EffectHandle effect_handle_get(StripType strip_type)
Definition effects.cc:159
static StripEarlyOut early_out_speed(const Strip *, float)
static void load_speed_effect(Strip *strip)
static int num_inputs_speed()
struct Strip * input1
void * effectdata
void(* copy)(Strip *dst, const Strip *src, int flag)
ImBuf *(* execute)(const RenderData *context, SeqRenderState *state, Strip *strip, float timeline_frame, float fac, ImBuf *ibuf1, ImBuf *ibuf2)
void(* free)(Strip *strip, bool do_id_user)
StripEarlyOut(* early_out)(const Strip *strip, float fac)
void(* load)(Strip *seqconst)
void(* init)(Strip *strip)