Fix VSE clamping strip content length incorrectly

When movie framerate does not match scene, content length was clamped to strip
length in scen framerate. This also caused issues with retiming which behaved in
similar way. Retiming was modified to use frame index of strip content, so even
when scene framerate is changed, retiming data is preserved in correct
proportions. This means, that handles are mapped to time in seconds rather than
to frames.
This commit is contained in:
2023-03-03 22:25:39 +01:00
parent a95eaf0ec1
commit b4100ed377
7 changed files with 62 additions and 33 deletions

View File

@@ -65,16 +65,17 @@ static float strip_y_rescale(const Sequence *seq, const float y_value)
return (y_value * y_range) + seq->machine + SEQ_STRIP_OFSBOTTOM;
}
static float handle_x_get(const Sequence *seq, const SeqRetimingHandle *handle)
static float handle_x_get(const Scene *scene, const Sequence *seq, const SeqRetimingHandle *handle)
{
const SeqRetimingHandle *last_handle = SEQ_retiming_last_handle_get(seq);
const bool is_last_handle = (handle == last_handle);
return SEQ_time_start_frame_get(seq) + handle->strip_frame_index + (is_last_handle ? 1 : 0);
return SEQ_retiming_handle_timeline_frame_get(scene, seq, handle) + (is_last_handle ? 1 : 0);
}
static const SeqRetimingHandle *mouse_over_handle_get(const Sequence *seq,
static const SeqRetimingHandle *mouse_over_handle_get(const Scene *scene,
const Sequence *seq,
const View2D *v2d,
const int mval[2])
{
@@ -84,7 +85,7 @@ static const SeqRetimingHandle *mouse_over_handle_get(const Sequence *seq,
MutableSpan handles = SEQ_retiming_handles_get(seq);
for (const SeqRetimingHandle &handle : handles) {
int distance = round_fl_to_int(
fabsf(UI_view2d_view_to_region_x(v2d, handle_x_get(seq, &handle)) - mval[0]));
fabsf(UI_view2d_view_to_region_x(v2d, handle_x_get(scene, seq, &handle)) - mval[0]));
if (distance < RETIME_HANDLE_MOUSEOVER_THRESHOLD && distance < best_distance) {
best_distance = distance;
@@ -316,7 +317,7 @@ static void retime_handle_draw(const bContext *C,
const SeqRetimingHandle *handle)
{
const Scene *scene = CTX_data_scene(C);
const float handle_x = handle_x_get(seq, handle);
const float handle_x = handle_x_get(scene, seq, handle);
if (handle_x == SEQ_time_left_handle_frame_get(scene, seq)) {
return;
@@ -371,7 +372,8 @@ static void retime_speed_text_draw(const bContext *C,
int next_handle_index = SEQ_retiming_handle_index_get(seq, handle) + 1;
const SeqRetimingHandle *next_handle = &SEQ_retiming_handles_get(seq)[next_handle_index];
if (handle_x_get(seq, next_handle) < start_frame || handle_x_get(seq, handle) > end_frame) {
if (handle_x_get(scene, seq, next_handle) < start_frame ||
handle_x_get(scene, seq, handle) > end_frame) {
return; /* Label out of strip bounds. */
}
@@ -383,9 +385,10 @@ static void retime_speed_text_draw(const bContext *C,
const float width = pixels_to_view_width(C, BLF_width(BLF_default(), label_str, label_len));
const float xmin = max_ff(SEQ_time_left_handle_frame_get(scene, seq), handle_x_get(seq, handle));
const float xmin = max_ff(SEQ_time_left_handle_frame_get(scene, seq),
handle_x_get(scene, seq, handle));
const float xmax = min_ff(SEQ_time_right_handle_frame_get(scene, seq),
handle_x_get(seq, next_handle));
handle_x_get(scene, seq, next_handle));
const float text_x = (xmin + xmax - width) / 2;
const float text_y = strip_y_rescale(seq, 0) + pixels_to_view_height(C, 5);
@@ -437,14 +440,15 @@ static int gizmo_retime_handle_test_select(bContext *C, wmGizmo *gz, const int m
Sequence *seq = active_seq_from_context(C);
SEQ_retiming_data_ensure(CTX_data_scene(C), seq);
const SeqRetimingHandle *handle = mouse_over_handle_get(seq, UI_view2d_fromcontext(C), mval);
const SeqRetimingHandle *handle = mouse_over_handle_get(
scene, seq, UI_view2d_fromcontext(C), mval);
const int handle_index = SEQ_retiming_handle_index_get(seq, handle);
if (handle == nullptr) {
return -1;
}
if (handle_x_get(seq, handle) == SEQ_time_left_handle_frame_get(scene, seq) ||
if (handle_x_get(scene, seq, handle) == SEQ_time_left_handle_frame_get(scene, seq) ||
handle_index == 0) {
return -1;
}
@@ -456,7 +460,7 @@ static int gizmo_retime_handle_test_select(bContext *C, wmGizmo *gz, const int m
}
gizmo->mouse_over_seq = seq;
gizmo->mouse_over_handle_x = handle_x_get(seq, handle);
gizmo->mouse_over_handle_x = handle_x_get(scene, seq, handle);
wmGizmoOpElem *op_elem = WM_gizmo_operator_get(gz, 0);
RNA_int_set(&op_elem->ptr, "handle_index", handle_index);
@@ -511,14 +515,15 @@ static int gizmo_retime_remove_test_select(bContext *C, wmGizmo *gz, const int m
Sequence *seq = active_seq_from_context(C);
SEQ_retiming_data_ensure(CTX_data_scene(C), seq);
const SeqRetimingHandle *handle = mouse_over_handle_get(seq, UI_view2d_fromcontext(C), mval);
const SeqRetimingHandle *handle = mouse_over_handle_get(
scene, seq, UI_view2d_fromcontext(C), mval);
const int handle_index = SEQ_retiming_handle_index_get(seq, handle);
if (handle == nullptr) {
return -1;
}
if (handle_x_get(seq, handle) == SEQ_time_left_handle_frame_get(scene, seq) ||
if (handle_x_get(scene, seq, handle) == SEQ_time_left_handle_frame_get(scene, seq) ||
handle_index == 0) {
return -1; /* Ignore first handle. */
}

View File

@@ -111,6 +111,7 @@ static SeqRetimingHandle *closest_retiming_handle_get(const bContext *C,
const float mouse_x)
{
const View2D *v2d = UI_view2d_fromcontext(C);
const Scene *scene = CTX_data_scene(C);
int best_distance = INT_MAX;
SeqRetimingHandle *closest_handle = nullptr;
@@ -119,7 +120,8 @@ static SeqRetimingHandle *closest_retiming_handle_get(const bContext *C,
for (int i = 0; i < SEQ_retiming_handles_count(seq); i++) {
SeqRetimingHandle *handle = seq->retiming_handles + i;
const int distance = round_fl_to_int(fabsf(handle->strip_frame_index - mouse_x_view));
const int distance = round_fl_to_int(
fabsf(SEQ_retiming_handle_timeline_frame_get(scene, seq, handle) - mouse_x_view));
if (distance < distance_threshold && distance < best_distance) {
best_distance = distance;
@@ -143,7 +145,7 @@ static int sequencer_retiming_handle_move_invoke(bContext *C, wmOperator *op, co
/* Ensure retiming handle at left handle position. This way user gets more predictable result
* when strips have offsets. */
const int left_handle_frame = SEQ_time_left_handle_frame_get(scene, seq);
if (SEQ_retiming_add_handle(seq, left_handle_frame) != nullptr) {
if (SEQ_retiming_add_handle(scene, seq, left_handle_frame) != nullptr) {
handle_index++; /* Advance index, because new handle was created. */
}
@@ -184,9 +186,9 @@ static int sequencer_retiming_handle_move_modal(bContext *C, wmOperator *op, con
SeqRetimingHandle *handle_prev = handle - 1;
/* Limit retiming handle movement. */
int xmin = SEQ_time_start_frame_get(seq) + handle_prev->strip_frame_index + 1;
int xmin = SEQ_retiming_handle_timeline_frame_get(scene, seq, handle_prev) + 1;
mouse_x = max_ff(xmin, mouse_x);
offset = mouse_x - (SEQ_time_start_frame_get(seq) + handle->strip_frame_index);
offset = mouse_x - SEQ_retiming_handle_timeline_frame_get(scene, seq, handle);
SEQ_retiming_offset_handle(scene, seq, handle, offset);
@@ -261,7 +263,7 @@ static int sequesequencer_retiming_handle_add_exec(bContext *C, wmOperator *op)
bool inserted = false;
const float end_frame = seq->start + SEQ_time_strip_length_get(scene, seq);
if (seq->start < timeline_frame && end_frame > timeline_frame) {
SEQ_retiming_add_handle(seq, timeline_frame);
SEQ_retiming_add_handle(scene, seq, timeline_frame);
inserted = true;
}

View File

@@ -644,7 +644,7 @@ static SeqRetimingHandle *rna_Sequence_retiming_handles_add(ID *id,
{
Scene *scene = (Scene *)id;
SeqRetimingHandle *handle = SEQ_retiming_add_handle(seq, timeline_frame);
SeqRetimingHandle *handle = SEQ_retiming_add_handle(scene, seq, timeline_frame);
SEQ_relations_invalidate_cache_raw(scene, seq);
WM_main_add_notifier(NC_SCENE | ND_SEQUENCER, NULL);

View File

@@ -26,7 +26,9 @@ bool SEQ_retiming_is_allowed(const struct Sequence *seq);
* This function always reallocates memory, so when function is used all stored pointers will
* become invalid.
*/
struct SeqRetimingHandle *SEQ_retiming_add_handle(struct Sequence *seq, const int timeline_frame);
struct SeqRetimingHandle *SEQ_retiming_add_handle(struct Scene *scene,
struct Sequence *seq,
const int timeline_frame);
struct SeqRetimingHandle *SEQ_retiming_last_handle_get(const struct Sequence *seq);
void SEQ_retiming_remove_handle(struct Sequence *seq, struct SeqRetimingHandle *handle);
void SEQ_retiming_offset_handle(const struct Scene *scene,
@@ -38,6 +40,9 @@ float SEQ_retiming_handle_speed_get(const struct Scene *scene,
const struct SeqRetimingHandle *handle);
int SEQ_retiming_handle_index_get(const struct Sequence *seq,
const struct SeqRetimingHandle *handle);
float SEQ_retiming_handle_timeline_frame_get(const struct Scene *scene,
const struct Sequence *seq,
const struct SeqRetimingHandle *handle);
#ifdef __cplusplus
}
#endif

View File

@@ -126,7 +126,7 @@ bool SEQ_retiming_is_allowed(const Sequence *seq)
SEQ_TYPE_MASK);
}
float seq_retiming_evaluate(const Sequence *seq, const int frame_index)
float seq_retiming_evaluate(const Scene *scene, const Sequence *seq, const int frame_index)
{
const SeqRetimingHandle *previous_handle = retiming_find_segment_start_handle(seq, frame_index);
const SeqRetimingHandle *next_handle = previous_handle + 1;
@@ -144,13 +144,15 @@ float seq_retiming_evaluate(const Sequence *seq, const int frame_index)
const float segment_fac = segment_frame_index / float(segment_length);
const float target_diff = next_handle->retiming_factor - previous_handle->retiming_factor;
return previous_handle->retiming_factor + (target_diff * segment_fac);
return previous_handle->retiming_factor +
(target_diff * segment_fac) * seq_time_media_playback_rate_factor_get(scene, seq);
}
SeqRetimingHandle *SEQ_retiming_add_handle(Sequence *seq, const int timeline_frame)
SeqRetimingHandle *SEQ_retiming_add_handle(Scene *scene, Sequence *seq, const int timeline_frame)
{
float frame_index = timeline_frame - SEQ_time_start_frame_get(seq);
float value = seq_retiming_evaluate(seq, frame_index);
float frame_index = (timeline_frame - SEQ_time_start_frame_get(seq)) *
seq_time_media_playback_rate_factor_get(scene, seq);
float value = seq_retiming_evaluate(scene, seq, frame_index);
const SeqRetimingHandle *closest_handle = retiming_find_segment_start_handle(seq, frame_index);
if (closest_handle->strip_frame_index == frame_index) {
@@ -195,7 +197,7 @@ void SEQ_retiming_offset_handle(const Scene *scene,
MutableSpan handles = SEQ_retiming_handles_get(seq);
for (; handle < handles.end(); handle++) {
handle->strip_frame_index += offset;
handle->strip_frame_index += offset * seq_time_media_playback_rate_factor_get(scene, seq);
}
SEQ_time_update_meta_strip_range(scene, seq_sequence_lookup_meta_by_seq(scene, seq));
@@ -245,3 +247,11 @@ float SEQ_retiming_handle_speed_get(const Scene *scene,
const float speed = float(fragment_length_retimed) / float(fragment_length_original);
return speed;
}
float SEQ_retiming_handle_timeline_frame_get(const Scene *scene,
const Sequence *seq,
const SeqRetimingHandle *handle)
{
return SEQ_time_start_frame_get(seq) +
handle->strip_frame_index / seq_time_media_playback_rate_factor_get(scene, seq);
}

View File

@@ -59,7 +59,7 @@ int seq_time_strip_original_content_length_get(const Scene *scene, const Sequenc
return seq->len;
}
return seq->len / seq_time_media_playback_rate_factor_get(scene, seq);
return seq->len;
}
float seq_give_frame_index(const Scene *scene, Sequence *seq, float timeline_frame)
@@ -84,16 +84,19 @@ float seq_give_frame_index(const Scene *scene, Sequence *seq, float timeline_fra
frame_index = timeline_frame - sta;
}
frame_index = max_ff(frame_index, 0);
if (SEQ_retiming_is_active(seq)) {
const float retiming_factor = seq_retiming_evaluate(seq, frame_index);
const float retiming_factor = seq_retiming_evaluate(scene, seq, frame_index);
frame_index = retiming_factor * (length - 1);
}
else {
frame_index *= seq_time_media_playback_rate_factor_get(scene, seq);
/* Clamp frame index to strip frame range. */
frame_index = clamp_f(frame_index, 0, end - sta);
}
/* Clamp frame index to strip content frame range. */
frame_index = clamp_f(frame_index, 0, length);
if (seq->strobe < 1.0f) {
seq->strobe = 1.0f;
}
@@ -507,10 +510,12 @@ int SEQ_time_strip_length_get(const Scene *scene, const Sequence *seq)
if (SEQ_retiming_is_active(seq)) {
SeqRetimingHandle *handle_start = seq->retiming_handles;
SeqRetimingHandle *handle_end = seq->retiming_handles + (SEQ_retiming_handles_count(seq) - 1);
return handle_end->strip_frame_index - handle_start->strip_frame_index + 1;
return handle_end->strip_frame_index / seq_time_media_playback_rate_factor_get(scene, seq) -
(handle_start->strip_frame_index + 1) /
seq_time_media_playback_rate_factor_get(scene, seq);
}
return seq_time_strip_original_content_length_get(scene, seq);
return seq->len / seq_time_media_playback_rate_factor_get(scene, seq);
}
float SEQ_time_start_frame_get(const Sequence *seq)

View File

@@ -45,7 +45,9 @@ float seq_time_media_playback_rate_factor_get(const struct Scene *scene,
const struct Sequence *seq);
int seq_time_strip_original_content_length_get(const struct Scene *scene,
const struct Sequence *seq);
float seq_retiming_evaluate(const struct Sequence *seq, const int frame_index);
float seq_retiming_evaluate(const struct Scene *scene,
const struct Sequence *seq,
const int frame_index);
#ifdef __cplusplus
}