diff --git a/release/scripts/startup/bl_ui/space_sequencer.py b/release/scripts/startup/bl_ui/space_sequencer.py index 7c7bb456473..34f0d33b26b 100644 --- a/release/scripts/startup/bl_ui/space_sequencer.py +++ b/release/scripts/startup/bl_ui/space_sequencer.py @@ -1806,6 +1806,10 @@ class SEQUENCER_PT_time(SequencerButtonsPanel, Panel): max_length = max(len(x) for x in length_list) max_factor = (1.9 - max_length) / 30 + split = layout.split(factor=0.5 + max_factor) + split.label(text="Speed Factor") + split.prop(strip, "speed_factor", text="") + layout.enabled = not strip.lock layout.active = not strip.mute diff --git a/source/blender/blenloader/intern/versioning_290.c b/source/blender/blenloader/intern/versioning_290.c index 2f6f0d5c9fa..b21f6e7b949 100644 --- a/source/blender/blenloader/intern/versioning_290.c +++ b/source/blender/blenloader/intern/versioning_290.c @@ -160,7 +160,7 @@ static void seq_convert_transform_crop(const Scene *scene, const uint32_t use_transform_flag = (1 << 16); const uint32_t use_crop_flag = (1 << 17); - const StripElem *s_elem = SEQ_render_give_stripelem(seq, seq->start); + const StripElem *s_elem = SEQ_render_give_stripelem(scene, seq, seq->start); if (s_elem != NULL) { image_size_x = s_elem->orig_width; image_size_y = s_elem->orig_height; @@ -285,7 +285,7 @@ static void seq_convert_transform_crop_2(const Scene *scene, Sequence *seq, const eSpaceSeq_Proxy_RenderSize render_size) { - const StripElem *s_elem = SEQ_render_give_stripelem(seq, seq->start); + const StripElem *s_elem = SEQ_render_give_stripelem(scene, seq, seq->start); if (s_elem == NULL) { return; } @@ -347,8 +347,10 @@ static void seq_convert_transform_crop_lb_2(const Scene *scene, } } -static void seq_update_meta_disp_range(Editing *ed) +static void seq_update_meta_disp_range(Scene *scene) { + Editing *ed = SEQ_editing_get(scene); + if (ed == NULL) { return; } @@ -360,9 +362,9 @@ static void seq_update_meta_disp_range(Editing *ed) } /* Update meta strip endpoints. */ - SEQ_transform_set_left_handle_frame(ms->parseq, ms->disp_range[0]); - SEQ_transform_set_right_handle_frame(ms->parseq, ms->disp_range[1]); - SEQ_transform_fix_single_image_seq_offsets(ms->parseq); + SEQ_transform_set_left_handle_frame(scene, ms->parseq, ms->disp_range[0]); + SEQ_transform_set_right_handle_frame(scene, ms->parseq, ms->disp_range[1]); + SEQ_transform_fix_single_image_seq_offsets(scene, ms->parseq); /* Recalculate effects using meta strip. */ LISTBASE_FOREACH (Sequence *, seq, ms->oldbasep) { @@ -647,7 +649,7 @@ void do_versions_after_linking_290(Main *bmain, ReportList *UNUSED(reports)) if (!MAIN_VERSION_ATLEAST(bmain, 293, 16)) { LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { - seq_update_meta_disp_range(SEQ_editing_get(scene)); + seq_update_meta_disp_range(scene); } /* Add a separate socket for Grid node X and Y size. */ diff --git a/source/blender/blenloader/intern/versioning_300.c b/source/blender/blenloader/intern/versioning_300.c index e6a214452fe..062bec528eb 100644 --- a/source/blender/blenloader/intern/versioning_300.c +++ b/source/blender/blenloader/intern/versioning_300.c @@ -984,6 +984,12 @@ static bool seq_meta_channels_ensure(Sequence *seq, void *UNUSED(user_data)) return true; } +static bool seq_speed_factor_set(Sequence *seq, void *UNUSED(user_data)) +{ + seq->speed_factor = 1.0f; + return true; +} + static void do_version_subsurface_methods(bNode *node) { if (node->type == SH_NODE_SUBSURFACE_SCATTERING) { @@ -2772,5 +2778,13 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain) */ { /* Keep this block, even when empty. */ + + LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { + Editing *ed = SEQ_editing_get(scene); + if (ed == NULL) { + continue; + } + SEQ_for_each_callback(&ed->seqbase, seq_speed_factor_set, NULL); + } } } diff --git a/source/blender/editors/animation/anim_ops.c b/source/blender/editors/animation/anim_ops.c index 5b0c5eac11b..2a9739c688f 100644 --- a/source/blender/editors/animation/anim_ops.c +++ b/source/blender/editors/animation/anim_ops.c @@ -111,10 +111,14 @@ static int seq_frame_apply_snap(bContext *C, Scene *scene, const int timeline_fr int best_distance = MAXFRAME; Sequence *seq; SEQ_ITERATOR_FOREACH (seq, strips) { - seq_frame_snap_update_best( - SEQ_transform_get_left_handle_frame(seq), timeline_frame, &best_frame, &best_distance); - seq_frame_snap_update_best( - SEQ_transform_get_right_handle_frame(seq), timeline_frame, &best_frame, &best_distance); + seq_frame_snap_update_best(SEQ_transform_get_left_handle_frame(scene, seq), + timeline_frame, + &best_frame, + &best_distance); + seq_frame_snap_update_best(SEQ_transform_get_right_handle_frame(scene, seq), + timeline_frame, + &best_frame, + &best_distance); } SEQ_collection_free(strips); diff --git a/source/blender/editors/space_sequencer/sequencer_add.c b/source/blender/editors/space_sequencer/sequencer_add.c index 9298eb83b46..f0bbdd6c695 100644 --- a/source/blender/editors/space_sequencer/sequencer_add.c +++ b/source/blender/editors/space_sequencer/sequencer_add.c @@ -672,8 +672,10 @@ static void sequencer_add_movie_clamp_sound_strip_length(Scene *scene, return; } - SEQ_transform_set_right_handle_frame(seq_sound, SEQ_transform_get_right_handle_frame(seq_movie)); - SEQ_transform_set_left_handle_frame(seq_sound, SEQ_transform_get_left_handle_frame(seq_movie)); + SEQ_transform_set_right_handle_frame( + scene, seq_sound, SEQ_transform_get_right_handle_frame(scene, seq_movie)); + SEQ_transform_set_left_handle_frame( + scene, seq_sound, SEQ_transform_get_left_handle_frame(scene, seq_movie)); SEQ_time_update_sequence(scene, seqbase, seq_sound); } @@ -1128,8 +1130,12 @@ static int sequencer_add_image_strip_calculate_length(wmOperator *op, return RNA_property_collection_length(op->ptr, RNA_struct_find_property(op->ptr, "files")); } -static void sequencer_add_image_strip_load_files( - wmOperator *op, Sequence *seq, SeqLoadData *load_data, const int minframe, const int numdigits) +static void sequencer_add_image_strip_load_files(wmOperator *op, + Scene *scene, + Sequence *seq, + SeqLoadData *load_data, + const int minframe, + const int numdigits) { const bool use_placeholders = RNA_boolean_get(op->ptr, "use_placeholders"); /* size of Strip->dir. */ @@ -1145,7 +1151,7 @@ static void sequencer_add_image_strip_load_files( size_t strip_frame = 0; RNA_BEGIN (op->ptr, itemptr, "files") { char *filename = RNA_string_get_alloc(&itemptr, "name", NULL, 0, NULL); - SEQ_add_image_load_file(seq, strip_frame, filename); + SEQ_add_image_load_file(scene, seq, strip_frame, filename); MEM_freeN(filename); strip_frame++; } @@ -1174,12 +1180,12 @@ static int sequencer_add_image_strip_exec(bContext *C, wmOperator *op) } Sequence *seq = SEQ_add_image_strip(CTX_data_main(C), scene, ed->seqbasep, &load_data); - sequencer_add_image_strip_load_files(op, seq, &load_data, minframe, numdigits); + sequencer_add_image_strip_load_files(op, scene, seq, &load_data, minframe, numdigits); SEQ_add_image_init_alpha_mode(seq); /* Adjust length. */ if (load_data.image.len == 1) { - SEQ_transform_set_right_handle_frame(seq, load_data.image.end_frame); + SEQ_transform_set_right_handle_frame(scene, seq, load_data.image.end_frame); SEQ_time_update_sequence(scene, SEQ_active_seqbase_get(ed), seq); } diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c index 4cb41c702da..e50c32537d6 100644 --- a/source/blender/editors/space_sequencer/sequencer_draw.c +++ b/source/blender/editors/space_sequencer/sequencer_draw.c @@ -992,22 +992,26 @@ static void draw_sequence_extensions_overlay( col[3] = SEQ_render_is_muted(channels, seq) ? MUTE_ALPHA : 200; UI_GetColorPtrShade3ubv(col, blend_col, 10); - if (seq->startofs) { + const float strip_content_start = SEQ_time_start_frame_get(seq); + const float strip_content_end = SEQ_time_start_frame_get(seq) + + SEQ_time_strip_length_get(scene, seq); + float right_handle_frame = SEQ_transform_get_right_handle_frame(scene, seq); + float left_handle_frame = SEQ_transform_get_left_handle_frame(scene, seq); + + if (left_handle_frame > strip_content_start) { immUniformColor4ubv(col); - immRectf(pos, (float)(seq->start), y1 - pixely, x1, y1 - SEQ_STRIP_OFSBOTTOM); + immRectf(pos, strip_content_start, y1 - pixely, x1, y1 - SEQ_STRIP_OFSBOTTOM); /* Outline. */ immUniformColor3ubv(blend_col); - imm_draw_box_wire_2d(pos, x1, y1 - pixely, (float)(seq->start), y1 - SEQ_STRIP_OFSBOTTOM); + imm_draw_box_wire_2d(pos, x1, y1 - pixely, strip_content_start, y1 - SEQ_STRIP_OFSBOTTOM); } - if (seq->endofs) { + if (right_handle_frame < strip_content_end) { immUniformColor4ubv(col); - immRectf(pos, x2, y2 + pixely, (float)(seq->start + seq->len), y2 + SEQ_STRIP_OFSBOTTOM); + immRectf(pos, x2, y2 + pixely, strip_content_end, y2 + SEQ_STRIP_OFSBOTTOM); - /* Outline. */ - immUniformColor3ubv(blend_col); - imm_draw_box_wire_2d( - pos, x2, y2 + pixely, (float)(seq->start + seq->len), y2 + SEQ_STRIP_OFSBOTTOM); + /* Outline. */ immUniformColor3ubv(blend_col); + imm_draw_box_wire_2d(pos, x2, y2 + pixely, strip_content_end, y2 + SEQ_STRIP_OFSBOTTOM); } GPU_blend(GPU_BLEND_NONE); } @@ -1096,26 +1100,34 @@ static void draw_seq_background(Scene *scene, /* Draw the main strip body. */ if (is_single_image) { immRectf(pos, - SEQ_transform_get_left_handle_frame(seq), + SEQ_transform_get_left_handle_frame(scene, seq), y1, - SEQ_transform_get_right_handle_frame(seq), + SEQ_transform_get_right_handle_frame(scene, seq), y2); } else { immRectf(pos, x1, y1, x2, y2); } + const float strip_content_start = SEQ_time_start_frame_get(seq); + const float strip_content_end = SEQ_time_start_frame_get(seq) + + SEQ_time_strip_length_get(scene, seq); + float right_handle_frame = SEQ_transform_get_right_handle_frame(scene, seq); + float left_handle_frame = SEQ_transform_get_left_handle_frame(scene, seq); + /* Draw background for hold still regions. */ - if (!is_single_image && (seq->startstill || seq->endstill)) { + if (!is_single_image) { UI_GetColorPtrShade3ubv(col, col, -35); immUniformColor4ubv(col); - if (seq->startstill) { - const float content_start = min_ff(seq->enddisp, seq->start); - immRectf(pos, seq->startdisp, y1, content_start, y2); + if (left_handle_frame < strip_content_start) { + const float content_start = min_ff(seq->enddisp, SEQ_time_start_frame_get(seq)); + immRectf(pos, left_handle_frame, y1, content_start, y2); } - if (seq->endstill) { - const float content_end = max_ff(seq->startdisp, seq->start + seq->len); + if (right_handle_frame > strip_content_end) { + const float content_end = max_ff(left_handle_frame, + SEQ_time_start_frame_get(seq) + + SEQ_time_strip_length_get(scene, seq)); immRectf(pos, content_end, y1, seq->enddisp, y2); } } @@ -1333,9 +1345,9 @@ static void draw_seq_strip(const bContext *C, SEQ_TIMELINE_SHOW_STRIP_COLOR_TAG); /* Draw strip body. */ - x1 = (seq->startstill) ? seq->start : seq->startdisp; + x1 = SEQ_transform_get_right_handle_frame(scene, seq); y1 = seq->machine + SEQ_STRIP_OFSBOTTOM; - x2 = (seq->endstill) ? (seq->start + seq->len) : seq->enddisp; + x2 = SEQ_transform_get_left_handle_frame(scene, seq); y2 = seq->machine + SEQ_STRIP_OFSTOP; /* Limit body to strip bounds. Meta strip can end up with content outside of strip range. */ @@ -1371,7 +1383,7 @@ static void draw_seq_strip(const bContext *C, /* Draw strip offsets when flag is enabled or during "solo preview". */ if (sseq->flag & SEQ_SHOW_OVERLAY) { - if (!is_single_image && (seq->startofs || seq->endofs) && pixely > 0) { + if (!is_single_image && pixely > 0) { if ((sseq->timeline_overlay.flag & SEQ_TIMELINE_SHOW_STRIP_OFFSETS) || (seq == special_seq_update)) { draw_sequence_extensions_overlay(scene, seq, pos, pixely, show_strip_color_tag); @@ -2313,7 +2325,9 @@ static void draw_seq_strips(const bContext *C, Editing *ed, ARegion *region) if (min_ii(seq->startdisp, seq->start) > v2d->cur.xmax) { continue; } - if (max_ii(seq->enddisp, seq->start + seq->len) < v2d->cur.xmin) { + if (max_ii(seq->enddisp, + SEQ_time_start_frame_get(seq) + SEQ_time_strip_length_get(scene, seq)) < + v2d->cur.xmin) { continue; } if (seq->machine + 1.0f < v2d->cur.ymin) { diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c index 0305ad279a0..aed89f381d6 100644 --- a/source/blender/editors/space_sequencer/sequencer_edit.c +++ b/source/blender/editors/space_sequencer/sequencer_edit.c @@ -362,13 +362,12 @@ static int sequencer_snap_exec(bContext *C, wmOperator *op) } else { if (seq->flag & SEQ_LEFTSEL) { - SEQ_transform_set_left_handle_frame(seq, snap_frame); + SEQ_transform_set_left_handle_frame(scene, seq, snap_frame); } else { /* SEQ_RIGHTSEL */ - SEQ_transform_set_right_handle_frame(seq, snap_frame); + SEQ_transform_set_right_handle_frame(scene, seq, snap_frame); } - SEQ_transform_handle_xlimits(seq, seq->flag & SEQ_LEFTSEL, seq->flag & SEQ_RIGHTSEL); - SEQ_transform_fix_single_image_seq_offsets(seq); + SEQ_transform_fix_single_image_seq_offsets(scene, seq); } SEQ_time_update_sequence(scene, seqbase, seq); } @@ -603,42 +602,9 @@ static bool sequencer_slip_recursively(Scene *scene, SlipData *data, int offset) /* Iterate in reverse so meta-strips are iterated after their children. */ for (int i = data->num_seq - 1; i >= 0; i--) { Sequence *seq = data->seq_array[i]; - int endframe; - - /* Offset seq start. */ - seq->start = data->ts[i].start + offset; if (data->trim[i]) { - /* Find the end-frame. */ - endframe = seq->start + seq->len; - - /* Compute the sequence offsets. */ - if (endframe > seq->enddisp) { - seq->endstill = 0; - seq->endofs = endframe - seq->enddisp; - changed = true; - } - else { - seq->endstill = seq->enddisp - endframe; - seq->endofs = 0; - changed = true; - } - - if (seq->start > seq->startdisp) { - seq->startstill = seq->start - seq->startdisp; - seq->startofs = 0; - changed = true; - } - else { - seq->startstill = 0; - seq->startofs = seq->startdisp - seq->start; - changed = true; - } - } - else { - /* No transform data (likely effect strip). Only move start and end. */ - seq->startdisp = data->ts[i].startdisp + offset; - seq->enddisp = data->ts[i].enddisp + offset; + SEQ_transform_content_start_set(scene, seq, data->ts[i].start + offset); changed = true; } @@ -650,11 +616,11 @@ static bool sequencer_slip_recursively(Scene *scene, SlipData *data, int offset) ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(scene)); SEQ_time_update_sequence(scene, seqbase, seq); } - } - if (changed) { - for (int i = data->num_seq - 1; i >= 0; i--) { - Sequence *seq = data->seq_array[i]; - SEQ_relations_invalidate_cache_preprocessed(scene, seq); + if (changed) { + for (int i = data->num_seq - 1; i >= 0; i--) { + Sequence *seq = data->seq_array[i]; + SEQ_relations_invalidate_cache_preprocessed(scene, seq); + } } } return changed; @@ -663,6 +629,7 @@ static bool sequencer_slip_recursively(Scene *scene, SlipData *data, int offset) /* Make sure, that each strip contains at least 1 frame of content. */ static void sequencer_slip_apply_limits(SlipData *data, int *offset) { + /* for (int i = 0; i < data->num_seq; i++) { if (data->trim[i]) { Sequence *seq = data->seq_array[i]; @@ -680,6 +647,7 @@ static void sequencer_slip_apply_limits(SlipData *data, int *offset) *offset += diff; } } + */ } static int sequencer_slip_exec(bContext *C, wmOperator *op) @@ -1869,12 +1837,12 @@ static int sequencer_separate_images_exec(bContext *C, wmOperator *op) /* TODO: remove f-curve and assign to split image strips. * The old animation system would remove the user of `seq->ipo`. */ - start_ofs = timeline_frame = SEQ_transform_get_left_handle_frame(seq); - frame_end = SEQ_transform_get_right_handle_frame(seq); + start_ofs = timeline_frame = SEQ_transform_get_left_handle_frame(scene, seq); + frame_end = SEQ_transform_get_right_handle_frame(scene, seq); while (timeline_frame < frame_end) { /* New seq. */ - se = SEQ_render_give_stripelem(seq, timeline_frame); + se = SEQ_render_give_stripelem(scene, seq, timeline_frame); seq_new = SEQ_sequence_dupli_recursive(scene, scene, seqbase, seq, SEQ_DUPE_UNIQUE_NAME); @@ -2384,7 +2352,7 @@ static int sequencer_rendersize_exec(bContext *C, wmOperator *UNUSED(op)) switch (active_seq->type) { case SEQ_TYPE_IMAGE: - se = SEQ_render_give_stripelem(active_seq, scene->r.cfra); + se = SEQ_render_give_stripelem(scene, active_seq, scene->r.cfra); break; case SEQ_TYPE_MOVIE: se = active_seq->strip->stripdata; @@ -2687,7 +2655,7 @@ static int sequencer_swap_data_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - if (SEQ_edit_sequence_swap(seq_act, seq_other, &error_msg) == 0) { + if (SEQ_edit_sequence_swap(scene, seq_act, seq_other, &error_msg) == 0) { BKE_report(op->reports, RPT_ERROR, error_msg); return OPERATOR_CANCELLED; } @@ -3049,8 +3017,8 @@ static int seq_cmp_time_startdisp_channel(const void *a, const void *b) Sequence *seq_a = (Sequence *)a; Sequence *seq_b = (Sequence *)b; - int seq_a_start = SEQ_transform_get_left_handle_frame(seq_a); - int seq_b_start = SEQ_transform_get_left_handle_frame(seq_b); + int seq_a_start = seq_a->startdisp; + int seq_b_start = seq_b->startdisp; /* If strips have the same start frame favor the one with a higher channel. */ if (seq_a_start == seq_b_start) { @@ -3385,7 +3353,7 @@ static int sequencer_strip_transform_fit_exec(bContext *C, wmOperator *op) for (seq = ed->seqbasep->first; seq; seq = seq->next) { if (seq->flag & SELECT && seq->type != SEQ_TYPE_SOUND_RAM) { const int timeline_frame = CFRA; - StripElem *strip_elem = SEQ_render_give_stripelem(seq, timeline_frame); + StripElem *strip_elem = SEQ_render_give_stripelem(scene, seq, timeline_frame); if (strip_elem == NULL) { continue; diff --git a/source/blender/editors/transform/transform_convert_sequencer.c b/source/blender/editors/transform/transform_convert_sequencer.c index 5964af7ed4b..f3c45b7562c 100644 --- a/source/blender/editors/transform/transform_convert_sequencer.c +++ b/source/blender/editors/transform/transform_convert_sequencer.c @@ -91,8 +91,8 @@ static void SeqTransInfo(TransInfo *t, Sequence *seq, int *r_count, int *r_flag) /* *** Extend Transform *** */ int cfra = CFRA; - int left = SEQ_transform_get_left_handle_frame(seq); - int right = SEQ_transform_get_right_handle_frame(seq); + int left = SEQ_transform_get_left_handle_frame(scene, seq); + int right = SEQ_transform_get_right_handle_frame(scene, seq); if (((seq->flag & SELECT) == 0 || SEQ_transform_is_locked(channels, seq))) { *r_count = 0; @@ -163,8 +163,13 @@ static int SeqTransCount(TransInfo *t, ListBase *seqbase) return tot; } -static TransData *SeqToTransData( - TransData *td, TransData2D *td2d, TransDataSeq *tdsq, Sequence *seq, int flag, int sel_flag) +static TransData *SeqToTransData(Scene *scene, + TransData *td, + TransData2D *td2d, + TransDataSeq *tdsq, + Sequence *seq, + int flag, + int sel_flag) { int start_left; @@ -173,16 +178,16 @@ static TransData *SeqToTransData( /* Use seq_tx_get_final_left() and an offset here * so transform has the left hand location of the strip. * tdsq->start_offset is used when flushing the tx data back */ - start_left = SEQ_transform_get_left_handle_frame(seq); + start_left = SEQ_transform_get_left_handle_frame(scene, seq); td2d->loc[0] = start_left; tdsq->start_offset = start_left - seq->start; /* use to apply the original location */ break; case SEQ_LEFTSEL: - start_left = SEQ_transform_get_left_handle_frame(seq); + start_left = SEQ_transform_get_left_handle_frame(scene, seq); td2d->loc[0] = start_left; break; case SEQ_RIGHTSEL: - td2d->loc[0] = SEQ_transform_get_right_handle_frame(seq); + td2d->loc[0] = SEQ_transform_get_right_handle_frame(scene, seq); break; } @@ -227,6 +232,7 @@ static int SeqToTransData_build( TransInfo *t, ListBase *seqbase, TransData *td, TransData2D *td2d, TransDataSeq *tdsq) { Sequence *seq; + Scene *scene = t->scene; int count, flag; int tot = 0; @@ -238,16 +244,16 @@ static int SeqToTransData_build( if (flag & SELECT) { if (flag & (SEQ_LEFTSEL | SEQ_RIGHTSEL)) { if (flag & SEQ_LEFTSEL) { - SeqToTransData(td++, td2d++, tdsq++, seq, flag, SEQ_LEFTSEL); + SeqToTransData(scene, td++, td2d++, tdsq++, seq, flag, SEQ_LEFTSEL); tot++; } if (flag & SEQ_RIGHTSEL) { - SeqToTransData(td++, td2d++, tdsq++, seq, flag, SEQ_RIGHTSEL); + SeqToTransData(scene, td++, td2d++, tdsq++, seq, flag, SEQ_RIGHTSEL); tot++; } } else { - SeqToTransData(td++, td2d++, tdsq++, seq, flag, SELECT); + SeqToTransData(scene, td++, td2d++, tdsq++, seq, flag, SELECT); tot++; } } @@ -489,11 +495,11 @@ static void seq_transform_handle_overwrite_trim(Scene *scene, continue; } if (overlap == STRIP_OVERLAP_LEFT_SIDE) { - SEQ_transform_set_left_handle_frame(seq, transformed->enddisp); + SEQ_transform_set_left_handle_frame(scene, seq, transformed->enddisp); } else { BLI_assert(overlap == STRIP_OVERLAP_RIGHT_SIDE); - SEQ_transform_set_right_handle_frame(seq, transformed->startdisp); + SEQ_transform_set_right_handle_frame(scene, seq, transformed->startdisp); } SEQ_time_update_sequence(scene, seqbasep, seq); @@ -881,6 +887,8 @@ static void flushTransSeq(TransInfo *t) TransDataSeq *tdsq = NULL; Sequence *seq; + Scene *scene = t->scene; + TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t); /* This is calculated for offsetting animation of effects that change position with inputs. @@ -904,7 +912,7 @@ static void flushTransSeq(TransInfo *t) case SELECT: { if (SEQ_transform_sequence_can_be_translated(seq)) { offset = new_frame - tdsq->start_offset - seq->start; - SEQ_transform_translate_sequence(t->scene, seq, offset); + SEQ_transform_translate_sequence(scene, seq, offset); if (abs(offset) > abs(max_offset)) { max_offset = offset; } @@ -915,10 +923,9 @@ static void flushTransSeq(TransInfo *t) } case SEQ_LEFTSEL: { /* No vertical transform. */ int old_startdisp = seq->startdisp; - SEQ_transform_set_left_handle_frame(seq, new_frame); - SEQ_transform_handle_xlimits(seq, tdsq->flag & SEQ_LEFTSEL, tdsq->flag & SEQ_RIGHTSEL); - SEQ_transform_fix_single_image_seq_offsets(seq); - SEQ_time_update_sequence(t->scene, seqbasep, seq); + SEQ_transform_set_left_handle_frame(scene, seq, new_frame); + SEQ_transform_fix_single_image_seq_offsets(scene, seq); + SEQ_time_update_sequence(scene, seqbasep, seq); if (abs(seq->startdisp - old_startdisp) > abs(max_offset)) { max_offset = seq->startdisp - old_startdisp; } @@ -926,10 +933,9 @@ static void flushTransSeq(TransInfo *t) } case SEQ_RIGHTSEL: { /* No vertical transform. */ int old_enddisp = seq->enddisp; - SEQ_transform_set_right_handle_frame(seq, new_frame); - SEQ_transform_handle_xlimits(seq, tdsq->flag & SEQ_LEFTSEL, tdsq->flag & SEQ_RIGHTSEL); - SEQ_transform_fix_single_image_seq_offsets(seq); - SEQ_time_update_sequence(t->scene, seqbasep, seq); + SEQ_transform_set_right_handle_frame(scene, seq, new_frame); + SEQ_transform_fix_single_image_seq_offsets(scene, seq); + SEQ_time_update_sequence(scene, seqbasep, seq); if (abs(seq->enddisp - old_enddisp) > abs(max_offset)) { max_offset = seq->enddisp - old_enddisp; } diff --git a/source/blender/makesdna/DNA_sequence_types.h b/source/blender/makesdna/DNA_sequence_types.h index d28550b5456..c8fd59578a4 100644 --- a/source/blender/makesdna/DNA_sequence_types.h +++ b/source/blender/makesdna/DNA_sequence_types.h @@ -151,17 +151,17 @@ typedef struct Sequence { * Start frame of contents of strip in absolute frame coordinates. * For metastrips start of first strip startdisp. */ - int start; + float start; /** * Frames after the first frame where display starts, * frames before the last frame where display ends. */ - int startofs, endofs; + float startofs, endofs; /** * Frames that use the first frame before data begins, * frames that use the last frame after data ends. */ - int startstill, endstill; + float startstill, endstill; /** Machine: the strip channel */ int machine; int _pad3; @@ -249,6 +249,11 @@ typedef struct Sequence { /* modifiers */ ListBase modifiers; + /* Playback rate of strip content in frames per second. */ + float media_playback_rate; + /* Multiply strip playback speed. */ + float speed_factor; + SequenceRuntime runtime; } Sequence; diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c index 51f62b62c8e..d800053b7e2 100644 --- a/source/blender/makesrna/intern/rna_sequencer.c +++ b/source/blender/makesrna/intern/rna_sequencer.c @@ -326,7 +326,7 @@ static void rna_Sequence_frame_change_update(Main *UNUSED(bmain), do_sequence_frame_change_update(scene, (Sequence *)ptr->data); } -static void rna_Sequence_start_frame_set(PointerRNA *ptr, int value) +static void rna_Sequence_start_frame_set(PointerRNA *ptr, float value) { Sequence *seq = (Sequence *)ptr->data; Scene *scene = (Scene *)ptr->owner_id; @@ -336,13 +336,27 @@ static void rna_Sequence_start_frame_set(PointerRNA *ptr, int value) SEQ_relations_invalidate_cache_composite(scene, seq); } +static void rna_Sequence_speed_factor_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *ptr) +{ + Sequence *seq = ptr->data; + SEQ_relations_framechange_update(scene, seq); +} + +static void rna_Sequence_speed_factor_set(PointerRNA *ptr, float value) +{ + Sequence *seq = (Sequence *)ptr->data; + Scene *scene = (Scene *)ptr->owner_id; + SEQ_time_speed_factor_set(scene, seq, value); +} + static void rna_Sequence_start_frame_final_set(PointerRNA *ptr, int value) { Sequence *seq = (Sequence *)ptr->data; Scene *scene = (Scene *)ptr->owner_id; - SEQ_transform_set_left_handle_frame(seq, value); - SEQ_transform_fix_single_image_seq_offsets(seq); + SEQ_relations_invalidate_cache_composite(scene, seq); + SEQ_transform_set_left_handle_frame(scene, seq, value); + SEQ_transform_fix_single_image_seq_offsets(scene, seq); do_sequence_frame_change_update(scene, seq); SEQ_relations_invalidate_cache_composite(scene, seq); } @@ -352,13 +366,14 @@ static void rna_Sequence_end_frame_final_set(PointerRNA *ptr, int value) Sequence *seq = (Sequence *)ptr->data; Scene *scene = (Scene *)ptr->owner_id; - SEQ_transform_set_right_handle_frame(seq, value); - SEQ_transform_fix_single_image_seq_offsets(seq); + SEQ_relations_invalidate_cache_composite(scene, seq); + SEQ_transform_set_right_handle_frame(scene, seq, value); + SEQ_transform_fix_single_image_seq_offsets(scene, seq); do_sequence_frame_change_update(scene, seq); SEQ_relations_invalidate_cache_composite(scene, seq); } -static void rna_Sequence_frame_offset_start_set(PointerRNA *ptr, int value) +static void rna_Sequence_frame_offset_start_set(PointerRNA *ptr, float value) { Sequence *seq = (Sequence *)ptr->data; Scene *scene = (Scene *)ptr->owner_id; @@ -367,7 +382,7 @@ static void rna_Sequence_frame_offset_start_set(PointerRNA *ptr, int value) seq->startofs = value; } -static void rna_Sequence_frame_offset_end_set(PointerRNA *ptr, int value) +static void rna_Sequence_frame_offset_end_set(PointerRNA *ptr, float value) { Sequence *seq = (Sequence *)ptr->data; Scene *scene = (Scene *)ptr->owner_id; @@ -435,7 +450,7 @@ static void rna_Sequence_anim_startofs_final_range( } static void rna_Sequence_frame_offset_start_range( - PointerRNA *ptr, int *min, int *max, int *UNUSED(softmin), int *UNUSED(softmax)) + PointerRNA *ptr, float *min, float *max, float *UNUSED(softmin), float *UNUSED(softmax)) { Sequence *seq = (Sequence *)ptr->data; *min = ELEM(seq->type, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SOUND_HD) ? 0 : INT_MIN; @@ -443,7 +458,7 @@ static void rna_Sequence_frame_offset_start_range( } static void rna_Sequence_frame_offset_end_range( - PointerRNA *ptr, int *min, int *max, int *UNUSED(softmin), int *UNUSED(softmax)) + PointerRNA *ptr, float *min, float *max, float *UNUSED(softmin), float *UNUSED(softmax)) { Sequence *seq = (Sequence *)ptr->data; *min = ELEM(seq->type, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SOUND_HD) ? 0 : INT_MIN; @@ -455,7 +470,9 @@ static void rna_Sequence_frame_length_set(PointerRNA *ptr, int value) Sequence *seq = (Sequence *)ptr->data; Scene *scene = (Scene *)ptr->owner_id; - SEQ_transform_set_right_handle_frame(seq, SEQ_transform_get_left_handle_frame(seq) + value); + SEQ_relations_invalidate_cache_composite(scene, seq); + SEQ_transform_set_right_handle_frame( + scene, seq, SEQ_transform_get_left_handle_frame(scene, seq) + value); do_sequence_frame_change_update(scene, seq); SEQ_relations_invalidate_cache_composite(scene, seq); } @@ -463,7 +480,9 @@ static void rna_Sequence_frame_length_set(PointerRNA *ptr, int value) static int rna_Sequence_frame_length_get(PointerRNA *ptr) { Sequence *seq = (Sequence *)ptr->data; - return SEQ_transform_get_right_handle_frame(seq) - SEQ_transform_get_left_handle_frame(seq); + Scene *scene = (Scene *)ptr->owner_id; + return SEQ_transform_get_right_handle_frame(scene, seq) - + SEQ_transform_get_left_handle_frame(scene, seq); } static int rna_Sequence_frame_editable(PointerRNA *ptr, const char **UNUSED(r_info)) @@ -1986,11 +2005,11 @@ static void rna_def_sequence(BlenderRNA *brna) RNA_def_property_ui_text( prop, "Length", "The length of the contents of this strip before the handles are applied"); - prop = RNA_def_property(srna, "frame_start", PROP_INT, PROP_TIME); - RNA_def_property_int_sdna(prop, NULL, "start"); + prop = RNA_def_property(srna, "frame_start", PROP_FLOAT, PROP_TIME); + RNA_def_property_float_sdna(prop, NULL, "start"); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_ui_text(prop, "Start Frame", "X position where the strip begins"); - RNA_def_property_int_funcs( + RNA_def_property_float_funcs( prop, NULL, "rna_Sequence_start_frame_set", NULL); /* overlap tests and calc_seq_disp */ RNA_def_property_editable_func(prop, "rna_Sequence_frame_editable"); RNA_def_property_update( @@ -2021,22 +2040,23 @@ static void rna_def_sequence(BlenderRNA *brna) RNA_def_property_update( prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update"); - prop = RNA_def_property(srna, "frame_offset_start", PROP_INT, PROP_TIME); - RNA_def_property_int_sdna(prop, NULL, "startofs"); + prop = RNA_def_property(srna, "frame_offset_start", PROP_FLOAT, PROP_TIME); + RNA_def_property_float_sdna(prop, NULL, "startofs"); // RNA_def_property_clear_flag(prop, PROP_EDITABLE); /* overlap tests */ RNA_def_property_ui_text(prop, "Start Offset", ""); - RNA_def_property_int_funcs( + RNA_def_property_float_funcs( prop, NULL, "rna_Sequence_frame_offset_start_set", "rna_Sequence_frame_offset_start_range"); RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_frame_change_update"); - prop = RNA_def_property(srna, "frame_offset_end", PROP_INT, PROP_TIME); - RNA_def_property_int_sdna(prop, NULL, "endofs"); + prop = RNA_def_property(srna, "frame_offset_end", PROP_FLOAT, PROP_TIME); + RNA_def_property_float_sdna(prop, NULL, "endofs"); // RNA_def_property_clear_flag(prop, PROP_EDITABLE); /* overlap tests */ RNA_def_property_ui_text(prop, "End Offset", ""); - RNA_def_property_int_funcs( + RNA_def_property_float_funcs( prop, NULL, "rna_Sequence_frame_offset_end_set", "rna_Sequence_frame_offset_end_range"); RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_frame_change_update"); +# if 0 prop = RNA_def_property(srna, "frame_still_start", PROP_INT, PROP_TIME); RNA_def_property_int_sdna(prop, NULL, "startstill"); // RNA_def_property_clear_flag(prop, PROP_EDITABLE); /* overlap tests */ @@ -2052,7 +2072,7 @@ static void rna_def_sequence(BlenderRNA *brna) RNA_def_property_ui_text(prop, "End Still", ""); RNA_def_property_int_funcs(prop, NULL, "rna_Sequence_frame_still_end_set", NULL); RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_frame_change_update"); - +# endif prop = RNA_def_property(srna, "channel", PROP_INT, PROP_UNSIGNED); RNA_def_property_int_sdna(prop, NULL, "machine"); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); @@ -2062,6 +2082,17 @@ static void rna_def_sequence(BlenderRNA *brna) RNA_def_property_update( prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update"); + prop = RNA_def_property(srna, "speed_factor", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "speed_factor"); + RNA_def_property_float_default(prop, 1.0f); + RNA_def_property_range(prop, 0.1f, FLT_MAX); + RNA_def_property_ui_range(prop, 1.0f, 100.0f, 10.0, 3); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + RNA_def_property_ui_text(prop, "Speed Factor", "Multiply playback speed"); + RNA_def_property_float_funcs( + prop, NULL, "rna_Sequence_speed_factor_set", NULL); /* overlap test */ + RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_speed_factor_update"); + prop = RNA_def_property(srna, "use_linear_modifiers", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_USE_LINEAR_MODIFIERS); RNA_def_property_ui_text(prop, diff --git a/source/blender/makesrna/intern/rna_sequencer_api.c b/source/blender/makesrna/intern/rna_sequencer_api.c index 36bc50e73fb..1e7cfa31d57 100644 --- a/source/blender/makesrna/intern/rna_sequencer_api.c +++ b/source/blender/makesrna/intern/rna_sequencer_api.c @@ -63,13 +63,21 @@ static void rna_Sequence_update_rnafunc(ID *id, Sequence *self, bool do_data) SEQ_time_update_sequence(scene, seqbase, self); } -static void rna_Sequence_swap_internal(Sequence *seq_self, +static StripElem *rna_Sequence_strip_elem_from_frame(ID *id, Sequence *self, int timeline_frame) +{ + Scene *scene = (Scene *)id; + return SEQ_render_give_stripelem(scene, self, timeline_frame); +} + +static void rna_Sequence_swap_internal(ID *id, + Sequence *seq_self, ReportList *reports, Sequence *seq_other) { const char *error_msg; + Scene *scene = (Scene *)id; - if (SEQ_edit_sequence_swap(seq_self, seq_other, &error_msg) == 0) { + if (SEQ_edit_sequence_swap(scene, seq_self, seq_other, &error_msg) == 0) { BKE_report(reports, RPT_ERROR, error_msg); } } @@ -262,7 +270,7 @@ static Sequence *rna_Sequences_new_image(ID *id, char dir[FILE_MAX], filename[FILE_MAX]; BLI_split_dirfile(file, dir, filename, sizeof(dir), sizeof(filename)); SEQ_add_image_set_directory(seq, dir); - SEQ_add_image_load_file(seq, 0, filename); + SEQ_add_image_load_file(scene, seq, 0, filename); SEQ_add_image_init_alpha_mode(seq); DEG_relations_tag_update(bmain); @@ -674,7 +682,8 @@ void RNA_api_sequence_strip(StructRNA *srna) RNA_def_function_ui_description(func, "Update the strip dimensions"); parm = RNA_def_boolean(func, "data", false, "Data", "Update strip data"); - func = RNA_def_function(srna, "strip_elem_from_frame", "SEQ_render_give_stripelem"); + func = RNA_def_function(srna, "strip_elem_from_frame", "rna_Sequence_strip_elem_from_frame"); + RNA_def_function_flag(func, FUNC_USE_SELF_ID); RNA_def_function_ui_description(func, "Return the strip element from a given frame or None"); parm = RNA_def_int(func, "frame", @@ -691,6 +700,7 @@ void RNA_api_sequence_strip(StructRNA *srna) RNA_def_pointer(func, "elem", "SequenceElement", "", "strip element of the current frame")); func = RNA_def_function(srna, "swap", "rna_Sequence_swap_internal"); + RNA_def_function_flag(func, FUNC_USE_REPORTS | FUNC_USE_SELF_ID); RNA_def_function_flag(func, FUNC_USE_REPORTS); parm = RNA_def_pointer(func, "other", "Sequence", "Other", ""); RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); diff --git a/source/blender/sequencer/SEQ_add.h b/source/blender/sequencer/SEQ_add.h index c195165a792..4e121c87710 100644 --- a/source/blender/sequencer/SEQ_add.h +++ b/source/blender/sequencer/SEQ_add.h @@ -176,7 +176,10 @@ void SEQ_add_image_set_directory(struct Sequence *seq, char *path); * \param strip_frame: frame index of strip to be changed * \param filename: image filename (only filename, not complete path) */ -void SEQ_add_image_load_file(struct Sequence *seq, size_t strip_frame, char *filename); +void SEQ_add_image_load_file(struct Scene *scene, + struct Sequence *seq, + size_t strip_frame, + char *filename); /** * Set image strip alpha mode * diff --git a/source/blender/sequencer/SEQ_edit.h b/source/blender/sequencer/SEQ_edit.h index 2f07d5ae940..ff9c387e527 100644 --- a/source/blender/sequencer/SEQ_edit.h +++ b/source/blender/sequencer/SEQ_edit.h @@ -16,7 +16,10 @@ struct Main; struct Scene; struct Sequence; -int SEQ_edit_sequence_swap(struct Sequence *seq_a, struct Sequence *seq_b, const char **error_str); +int SEQ_edit_sequence_swap(struct Scene *scene, + struct Sequence *seq_a, + struct Sequence *seq_b, + const char **error_str); /** * Move sequence to seqbase. * diff --git a/source/blender/sequencer/SEQ_effects.h b/source/blender/sequencer/SEQ_effects.h index e5af6f963e2..fa5d6d18736 100644 --- a/source/blender/sequencer/SEQ_effects.h +++ b/source/blender/sequencer/SEQ_effects.h @@ -55,7 +55,10 @@ struct SeqEffectHandle { int (*early_out)(struct Sequence *seq, float fac); /* sets the default `fac` value */ - void (*get_default_fac)(struct Sequence *seq, float timeline_frame, float *fac); + void (*get_default_fac)(const struct Scene *scene, + struct Sequence *seq, + float timeline_frame, + float *fac); /* execute the effect * sequence effects are only required to either support diff --git a/source/blender/sequencer/SEQ_relations.h b/source/blender/sequencer/SEQ_relations.h index 917f549f16d..dbb97dc5a6f 100644 --- a/source/blender/sequencer/SEQ_relations.h +++ b/source/blender/sequencer/SEQ_relations.h @@ -69,6 +69,10 @@ struct Sequence *SEQ_find_metastrip_by_sequence(ListBase *seqbase /* = ed->seqba struct Sequence *meta /* = NULL */, struct Sequence *seq); +void SEQ_relations_framechange_update(struct Scene *scene, struct Sequence *seq); +void SEQ_relations_framechange_update_recursive(struct Scene *scene, + const struct ListBase *seqbase); + #ifdef __cplusplus } #endif diff --git a/source/blender/sequencer/SEQ_render.h b/source/blender/sequencer/SEQ_render.h index a74eba5fc6f..e10bef88a93 100644 --- a/source/blender/sequencer/SEQ_render.h +++ b/source/blender/sequencer/SEQ_render.h @@ -112,7 +112,9 @@ void SEQ_render_new_render_data(struct Main *bmain, int for_render, SeqRenderData *r_context); int SEQ_render_evaluate_frame(struct ListBase *seqbase, int timeline_frame); -struct StripElem *SEQ_render_give_stripelem(struct Sequence *seq, int timeline_frame); +struct StripElem *SEQ_render_give_stripelem(const struct Scene *scene, + struct Sequence *seq, + int timeline_frame); void SEQ_render_imbuf_from_sequencer_space(struct Scene *scene, struct ImBuf *ibuf); void SEQ_render_pixel_from_sequencer_space_v4(struct Scene *scene, float pixel[4]); diff --git a/source/blender/sequencer/SEQ_time.h b/source/blender/sequencer/SEQ_time.h index b4adc950d6b..67ebbf08599 100644 --- a/source/blender/sequencer/SEQ_time.h +++ b/source/blender/sequencer/SEQ_time.h @@ -60,6 +60,12 @@ void SEQ_time_update_recursive(struct Scene *scene, struct Sequence *changed_seq */ bool SEQ_time_strip_intersects_frame(const struct Sequence *seq, int timeline_frame); void SEQ_time_update_meta_strip_range(struct Scene *scene, struct Sequence *seq_meta); +int SEQ_time_strip_length_get(const struct Scene *scene, const struct Sequence *seq); +void SEQ_time_speed_factor_set(struct Scene *scene, + struct Sequence *seq, + const float speed_factor); +float SEQ_time_start_frame_get(struct Sequence *seq); +float SEQ_time_start_offset_get(struct Scene *scene, struct Sequence *seq); #ifdef __cplusplus } diff --git a/source/blender/sequencer/SEQ_transform.h b/source/blender/sequencer/SEQ_transform.h index ea90a3ed372..12228ef9d3d 100644 --- a/source/blender/sequencer/SEQ_transform.h +++ b/source/blender/sequencer/SEQ_transform.h @@ -17,22 +17,17 @@ struct Scene; struct SeqCollection; struct Sequence; -int SEQ_transform_get_left_handle_frame(struct Sequence *seq); -int SEQ_transform_get_right_handle_frame(struct Sequence *seq); -void SEQ_transform_set_left_handle_frame(struct Sequence *seq, int val); -void SEQ_transform_set_right_handle_frame(struct Sequence *seq, int val); -/** - * Use to impose limits when dragging/extending - so impossible situations don't happen. - * Can't use the #SEQ_LEFTSEL and #SEQ_LEFTSEL directly because the strip may be in a meta-strip. - */ -void SEQ_transform_handle_xlimits(struct Sequence *seq, int leftflag, int rightflag); +int SEQ_transform_get_left_handle_frame(struct Scene *scene, struct Sequence *seq); +int SEQ_transform_get_right_handle_frame(struct Scene *scene, struct Sequence *seq); +void SEQ_transform_set_left_handle_frame(struct Scene *scene, struct Sequence *seq, int val); +void SEQ_transform_set_right_handle_frame(struct Scene *scene, struct Sequence *seq, int val); bool SEQ_transform_sequence_can_be_translated(struct Sequence *seq); /** * Used so we can do a quick check for single image seq * since they work a bit differently to normal image seq's (during transform). */ bool SEQ_transform_single_image_check(struct Sequence *seq); -void SEQ_transform_fix_single_image_seq_offsets(struct Sequence *seq); +void SEQ_transform_fix_single_image_seq_offsets(struct Scene *scene, struct Sequence *seq); bool SEQ_transform_test_overlap(struct ListBase *seqbasep, struct Sequence *test); bool SEQ_transform_test_overlap_seq_seq(struct Sequence *seq1, struct Sequence *seq2); void SEQ_transform_translate_sequence(struct Scene *scene, struct Sequence *seq, int delta); @@ -139,6 +134,9 @@ void SEQ_image_transform_bounding_box_from_collection(struct Scene *scene, bool apply_rotation, float r_min[2], float r_max[2]); +void SEQ_transform_content_start_set(struct Scene *scene, + struct Sequence *seq, + int timeline_frame); #ifdef __cplusplus } diff --git a/source/blender/sequencer/intern/effects.c b/source/blender/sequencer/intern/effects.c index d9d21ee3b05..28a7ca65e5e 100644 --- a/source/blender/sequencer/intern/effects.c +++ b/source/blender/sequencer/intern/effects.c @@ -49,6 +49,7 @@ #include "SEQ_proxy.h" #include "SEQ_relations.h" #include "SEQ_render.h" +#include "SEQ_time.h" #include "SEQ_utils.h" #include "BLF_api.h" @@ -2580,13 +2581,13 @@ static int early_out_speed(Sequence *UNUSED(seq), float UNUSED(fac)) * useful to use speed effect on these strips because they can be animated. This can be done by * using their length as is on timeline as content length. See T82698. */ -static int seq_effect_speed_get_strip_content_length(const Sequence *seq) +static int seq_effect_speed_get_strip_content_length(Scene *scene, const Sequence *seq) { if ((seq->type & SEQ_TYPE_EFFECT) != 0 && SEQ_effect_get_num_inputs(seq->type) == 0) { return seq->enddisp - seq->startdisp; } - return seq->len; + return SEQ_time_strip_length_get(scene, seq); } static FCurve *seq_effect_speed_speed_factor_curve_get(Scene *scene, Sequence *seq) @@ -2642,7 +2643,7 @@ float seq_speed_effect_target_frame_get(Scene *scene, } SEQ_effect_handle_get(seq_speed); /* Ensure, that data are initialized. */ - int frame_index = seq_give_frame_index(seq_speed, timeline_frame); + int frame_index = seq_give_frame_index(scene, seq_speed, timeline_frame); SpeedControlVars *s = (SpeedControlVars *)seq_speed->effectdata; const Sequence *source = seq_speed->seq1; @@ -2650,7 +2651,8 @@ float seq_speed_effect_target_frame_get(Scene *scene, switch (s->speed_control_type) { case SEQ_SPEED_STRETCH: { /* Only right handle controls effect speed! */ - const float target_content_length = seq_effect_speed_get_strip_content_length(source) - + const float target_content_length = seq_effect_speed_get_strip_content_length(scene, + source) - source->startofs; const float speed_effetct_length = seq_speed->enddisp - seq_speed->startdisp; const float ratio = frame_index / speed_effetct_length; @@ -2669,7 +2671,7 @@ float seq_speed_effect_target_frame_get(Scene *scene, break; } case SEQ_SPEED_LENGTH: - target_frame = seq_effect_speed_get_strip_content_length(source) * + target_frame = seq_effect_speed_get_strip_content_length(scene, source) * (s->speed_fader_length / 100.0f); break; case SEQ_SPEED_FRAME_NUMBER: @@ -2677,7 +2679,7 @@ float seq_speed_effect_target_frame_get(Scene *scene, break; } - CLAMP(target_frame, 0, seq_effect_speed_get_strip_content_length(source)); + CLAMP(target_frame, 0, seq_effect_speed_get_strip_content_length(scene, source)); target_frame += seq_speed->start; /* No interpolation. */ @@ -3502,15 +3504,21 @@ static int early_out_mul_input1(Sequence *UNUSED(seq), float fac) return EARLY_DO_EFFECT; } -static void get_default_fac_noop(Sequence *UNUSED(seq), float UNUSED(timeline_frame), float *fac) +static void get_default_fac_noop(const Scene *UNUSED(scene), + Sequence *UNUSED(seq), + float UNUSED(timeline_frame), + float *fac) { *fac = 1.0f; } -static void get_default_fac_fade(Sequence *seq, float timeline_frame, float *fac) +static void get_default_fac_fade(const Scene *scene, + Sequence *seq, + float timeline_frame, + float *fac) { *fac = (float)(timeline_frame - seq->startdisp); - *fac /= seq->len; + *fac /= SEQ_time_strip_length_get(scene, seq); } static struct ImBuf *init_execution(const SeqRenderData *context, diff --git a/source/blender/sequencer/intern/image_cache.c b/source/blender/sequencer/intern/image_cache.c index e1ff0ff64b3..cf69f3d3a7a 100644 --- a/source/blender/sequencer/intern/image_cache.c +++ b/source/blender/sequencer/intern/image_cache.c @@ -36,6 +36,7 @@ #include "SEQ_prefetch.h" #include "SEQ_relations.h" #include "SEQ_sequencer.h" +#include "SEQ_time.h" #include "disk_cache.h" #include "image_cache.h" @@ -132,21 +133,24 @@ static bool seq_cache_hashcmp(const void *a_, const void *b_) seq_cmp_render_data(&a->context, &b->context)); } -static float seq_cache_timeline_frame_to_frame_index(Sequence *seq, float timeline_frame, int type) +static float seq_cache_timeline_frame_to_frame_index(Scene *scene, + Sequence *seq, + float timeline_frame, + int type) { /* With raw images, map timeline_frame to strip input media frame range. This means that static * images or extended frame range of movies will only generate one cache entry. No special * treatment in converting frame index to timeline_frame is needed. */ if (ELEM(type, SEQ_CACHE_STORE_RAW, SEQ_CACHE_STORE_THUMBNAIL)) { - return seq_give_frame_index(seq, timeline_frame); + return seq_give_frame_index(scene, seq, timeline_frame); } - return timeline_frame - seq->start; + return timeline_frame - SEQ_time_start_frame_get(seq); } float seq_cache_frame_index_to_timeline_frame(Sequence *seq, float frame_index) { - return frame_index + seq->start; + return frame_index + SEQ_time_start_frame_get(seq); } static SeqCache *seq_cache_get_from_scene(Scene *scene) @@ -517,7 +521,8 @@ static void seq_cache_populate_key(SeqCacheKey *key, key->cache_owner = seq_cache_get_from_scene(context->scene); key->seq = seq; key->context = *context; - key->frame_index = seq_cache_timeline_frame_to_frame_index(seq, timeline_frame, type); + key->frame_index = seq_cache_timeline_frame_to_frame_index( + context->scene, seq, timeline_frame, type); key->timeline_frame = timeline_frame; key->type = type; key->link_prev = NULL; @@ -557,7 +562,7 @@ void seq_cache_free_temp_cache(Scene *scene, short id, int timeline_frame) if (key->is_temp_cache && key->task_id == id && key->type != SEQ_CACHE_STORE_THUMBNAIL) { /* Use frame_index here to avoid freeing raw images if they are used for multiple frames. */ float frame_index = seq_cache_timeline_frame_to_frame_index( - key->seq, timeline_frame, key->type); + scene, key->seq, timeline_frame, key->type); if (frame_index != key->frame_index || timeline_frame > key->seq->enddisp || timeline_frame < key->seq->startdisp) { BLI_ghash_remove(cache->hash, key, seq_cache_keyfree, seq_cache_valfree); diff --git a/source/blender/sequencer/intern/proxy.c b/source/blender/sequencer/intern/proxy.c index 91b69bfe01f..6c7958b1322 100644 --- a/source/blender/sequencer/intern/proxy.c +++ b/source/blender/sequencer/intern/proxy.c @@ -122,7 +122,7 @@ bool seq_proxy_get_custom_file_fname(Sequence *seq, char *name, const int view_i return true; } -static bool seq_proxy_get_fname(Editing *ed, +static bool seq_proxy_get_fname(Scene *scene, Sequence *seq, int timeline_frame, eSpaceSeq_Proxy_RenderSize render_size, @@ -131,6 +131,7 @@ static bool seq_proxy_get_fname(Editing *ed, { char dir[PROXY_MAXFILE]; char suffix[24] = {'\0'}; + Editing *ed = SEQ_editing_get(scene); StripProxy *proxy = seq->strip->proxy; if (proxy == NULL) { @@ -178,7 +179,7 @@ static bool seq_proxy_get_fname(Editing *ed, "%s/images/%d/%s_proxy%s", dir, proxy_size_number, - SEQ_render_give_stripelem(seq, timeline_frame)->name, + SEQ_render_give_stripelem(scene, seq, timeline_frame)->name, suffix); BLI_path_abs(name, BKE_main_blendfile_path_from_global()); strcat(name, ".jpg"); @@ -201,7 +202,6 @@ ImBuf *seq_proxy_fetch(const SeqRenderData *context, Sequence *seq, int timeline char name[PROXY_MAXFILE]; StripProxy *proxy = seq->strip->proxy; const eSpaceSeq_Proxy_RenderSize psize = context->preview_render_size; - Editing *ed = context->scene->ed; StripAnim *sanim; /* only use proxies, if they are enabled (even if present!) */ @@ -210,9 +210,11 @@ ImBuf *seq_proxy_fetch(const SeqRenderData *context, Sequence *seq, int timeline } if (proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_FILE) { - int frameno = (int)seq_give_frame_index(seq, timeline_frame) + seq->anim_startofs; + int frameno = (int)seq_give_frame_index(context->scene, seq, timeline_frame) + + seq->anim_startofs; if (proxy->anim == NULL) { - if (seq_proxy_get_fname(ed, seq, timeline_frame, psize, name, context->view_id) == 0) { + if (seq_proxy_get_fname( + context->scene, seq, timeline_frame, psize, name, context->view_id) == 0) { return NULL; } @@ -231,7 +233,8 @@ ImBuf *seq_proxy_fetch(const SeqRenderData *context, Sequence *seq, int timeline return IMB_anim_absolute(proxy->anim, frameno, IMB_TC_NONE, IMB_PROXY_NONE); } - if (seq_proxy_get_fname(ed, seq, timeline_frame, psize, name, context->view_id) == 0) { + if (seq_proxy_get_fname(context->scene, seq, timeline_frame, psize, name, context->view_id) == + 0) { return NULL; } @@ -259,9 +262,10 @@ static void seq_proxy_build_frame(const SeqRenderData *context, int quality; int rectx, recty; ImBuf *ibuf_tmp, *ibuf; - Editing *ed = context->scene->ed; + Scene *scene = context->scene; - if (!seq_proxy_get_fname(ed, seq, timeline_frame, proxy_render_size, name, context->view_id)) { + if (!seq_proxy_get_fname( + scene, seq, timeline_frame, proxy_render_size, name, context->view_id)) { return; } diff --git a/source/blender/sequencer/intern/render.c b/source/blender/sequencer/intern/render.c index 8d8a13be09e..5ba4dca5762 100644 --- a/source/blender/sequencer/intern/render.c +++ b/source/blender/sequencer/intern/render.c @@ -233,7 +233,7 @@ void seq_render_state_init(SeqRenderState *state) state->scene_parents = NULL; } -StripElem *SEQ_render_give_stripelem(Sequence *seq, int timeline_frame) +StripElem *SEQ_render_give_stripelem(const Scene *scene, Sequence *seq, int timeline_frame) { StripElem *se = seq->strip->stripdata; @@ -242,7 +242,7 @@ StripElem *SEQ_render_give_stripelem(Sequence *seq, int timeline_frame) * all other strips don't use this... */ - int frame_index = (int)seq_give_frame_index(seq, timeline_frame); + int frame_index = (int)seq_give_frame_index(scene, seq, timeline_frame); if (frame_index == -1 || se == NULL) { return NULL; @@ -795,7 +795,7 @@ static ImBuf *seq_render_effect_strip_impl(const SeqRenderData *context, } if (seq->flag & SEQ_USE_EFFECT_DEFAULT_FADE) { - sh.get_default_fac(seq, timeline_frame, &fac); + sh.get_default_fac(scene, seq, timeline_frame, &fac); } else { fcu = id_data_find_fcurve(&scene->id, seq, &RNA_Sequence, "effect_fader", 0, NULL); @@ -936,7 +936,7 @@ static ImBuf *seq_render_image_strip(const SeqRenderData *context, char prefix[FILE_MAX]; ImBuf *ibuf = NULL; - StripElem *s_elem = SEQ_render_give_stripelem(seq, timeline_frame); + StripElem *s_elem = SEQ_render_give_stripelem(context->scene, seq, timeline_frame); if (s_elem == NULL) { return NULL; } @@ -1024,7 +1024,8 @@ static ImBuf *seq_render_movie_strip_custom_file_proxy(const SeqRenderData *cont } } - int frameno = (int)seq_give_frame_index(seq, timeline_frame) + seq->anim_startofs; + int frameno = (int)seq_give_frame_index(context->scene, seq, timeline_frame) + + seq->anim_startofs; return IMB_anim_absolute(proxy->anim, frameno, IMB_TC_NONE, IMB_PROXY_NONE); } @@ -1622,7 +1623,7 @@ static ImBuf *do_render_strip_uncached(const SeqRenderData *context, bool *r_is_proxy_image) { ImBuf *ibuf = NULL; - float frame_index = seq_give_frame_index(seq, timeline_frame); + float frame_index = seq_give_frame_index(context->scene, seq, timeline_frame); int type = (seq->type & SEQ_TYPE_EFFECT) ? SEQ_TYPE_EFFECT : seq->type; switch (type) { case SEQ_TYPE_META: { diff --git a/source/blender/sequencer/intern/sequencer.c b/source/blender/sequencer/intern/sequencer.c index faa527786fd..983d7699606 100644 --- a/source/blender/sequencer/intern/sequencer.c +++ b/source/blender/sequencer/intern/sequencer.c @@ -130,6 +130,8 @@ Sequence *SEQ_sequence_alloc(ListBase *lb, int timeline_frame, int machine, int seq->scene_sound = NULL; seq->type = type; seq->blend_mode = SEQ_TYPE_ALPHAOVER; + seq->media_playback_rate = 0.0f; + seq->speed_factor = 1.0f; seq->strip = seq_strip_alloc(type); seq->stereo3d_format = MEM_callocN(sizeof(Stereo3dFormat), "Sequence Stereo Format"); diff --git a/source/blender/sequencer/intern/strip_add.c b/source/blender/sequencer/intern/strip_add.c index f8e26a56692..7bbfbaf3e25 100644 --- a/source/blender/sequencer/intern/strip_add.c +++ b/source/blender/sequencer/intern/strip_add.c @@ -174,7 +174,7 @@ Sequence *SEQ_add_effect_strip(Scene *scene, ListBase *seqbase, struct SeqLoadDa if (!load_data->effect.seq1) { seq->len = 1; /* Effect is generator, set non zero length. */ - SEQ_transform_set_right_handle_frame(seq, load_data->effect.end_frame); + SEQ_transform_set_right_handle_frame(scene, seq, load_data->effect.end_frame); } seq_add_set_name(scene, seq, load_data); @@ -188,9 +188,10 @@ void SEQ_add_image_set_directory(Sequence *seq, char *path) BLI_strncpy(seq->strip->dir, path, sizeof(seq->strip->dir)); } -void SEQ_add_image_load_file(Sequence *seq, size_t strip_frame, char *filename) +void SEQ_add_image_load_file(Scene *scene, Sequence *seq, size_t strip_frame, char *filename) { - StripElem *se = SEQ_render_give_stripelem(seq, seq->start + strip_frame); + StripElem *se = SEQ_render_give_stripelem( + scene, seq, SEQ_time_start_frame_get(seq) + strip_frame); BLI_strncpy(se->name, filename, sizeof(se->name)); } @@ -466,6 +467,12 @@ Sequence *SEQ_add_movie_strip(Main *bmain, Scene *scene, ListBase *seqbase, SeqL orig_height = IMB_anim_get_image_height(anim_arr[0]); SEQ_set_scale_to_fit( seq, orig_width, orig_height, scene->r.xsch, scene->r.ysch, load_data->fit_method); + + short frs_sec; + float frs_sec_base; + if (IMB_anim_get_fps(anim_arr[0], &frs_sec, &frs_sec_base, true)) { + seq->media_playback_rate = (float)frs_sec / frs_sec_base; + } } seq->len = MAX2(1, seq->len); @@ -656,9 +663,9 @@ void SEQ_add_reload_new_file(Main *bmain, Scene *scene, Sequence *seq, const boo free_proxy_seq(seq); if (lock_range) { - SEQ_transform_set_left_handle_frame(seq, prev_startdisp); - SEQ_transform_set_right_handle_frame(seq, prev_enddisp); - SEQ_transform_fix_single_image_seq_offsets(seq); + SEQ_transform_set_left_handle_frame(scene, seq, prev_startdisp); + SEQ_transform_set_right_handle_frame(scene, seq, prev_enddisp); + SEQ_transform_fix_single_image_seq_offsets(scene, seq); } ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(scene)); diff --git a/source/blender/sequencer/intern/strip_edit.c b/source/blender/sequencer/intern/strip_edit.c index 6c7bb71cb75..636e6be6093 100644 --- a/source/blender/sequencer/intern/strip_edit.c +++ b/source/blender/sequencer/intern/strip_edit.c @@ -37,11 +37,11 @@ #include "SEQ_transform.h" #include "SEQ_utils.h" -int SEQ_edit_sequence_swap(Sequence *seq_a, Sequence *seq_b, const char **error_str) +int SEQ_edit_sequence_swap(Scene *scene, Sequence *seq_a, Sequence *seq_b, const char **error_str) { char name[sizeof(seq_a->name)]; - if (seq_a->len != seq_b->len) { + if (SEQ_time_strip_length_get(scene, seq_a) != SEQ_time_strip_length_get(scene, seq_b)) { *error_str = N_("Strips must be the same length"); return 0; } @@ -274,77 +274,79 @@ bool SEQ_edit_move_strip_to_meta(Scene *scene, return true; } -static void seq_split_set_left_hold_offset(Sequence *seq, int timeline_frame) +static void seq_split_set_left_hold_offset(Scene *scene, Sequence *seq, int timeline_frame) { /* Adjust within range of extended stillframes before strip. */ if (timeline_frame < seq->start) { seq->start = timeline_frame - 1; - seq->anim_endofs += seq->len - 1; + seq->anim_endofs += SEQ_time_strip_length_get(scene, seq) - 1; seq->startstill = timeline_frame - seq->startdisp - 1; seq->endstill = 0; } /* Adjust within range of strip contents. */ - else if ((timeline_frame >= seq->start) && (timeline_frame <= (seq->start + seq->len))) { + else if ((timeline_frame >= seq->start) && + (timeline_frame <= (seq->start + SEQ_time_strip_length_get(scene, seq)))) { seq->endofs = 0; seq->endstill = 0; - seq->anim_endofs += (seq->start + seq->len) - timeline_frame; + seq->anim_endofs += (seq->start + SEQ_time_strip_length_get(scene, seq)) - timeline_frame; } /* Adjust within range of extended stillframes after strip. */ - else if ((seq->start + seq->len) < timeline_frame) { - seq->endstill = timeline_frame - seq->start - seq->len; + else if ((seq->start + SEQ_time_strip_length_get(scene, seq)) < timeline_frame) { + seq->endstill = timeline_frame - seq->start - SEQ_time_strip_length_get(scene, seq); } } -static void seq_split_set_right_hold_offset(Sequence *seq, int timeline_frame) +static void seq_split_set_right_hold_offset(Scene *scene, Sequence *seq, int timeline_frame) { /* Adjust within range of extended stillframes before strip. */ if (timeline_frame < seq->start) { seq->startstill = seq->start - timeline_frame; } /* Adjust within range of strip contents. */ - else if ((timeline_frame >= seq->start) && (timeline_frame <= (seq->start + seq->len))) { + else if ((timeline_frame >= seq->start) && + (timeline_frame <= (seq->start + SEQ_time_strip_length_get(scene, seq)))) { seq->anim_startofs += timeline_frame - seq->start; seq->start = timeline_frame; seq->startstill = 0; seq->startofs = 0; } /* Adjust within range of extended stillframes after strip. */ - else if ((seq->start + seq->len) < timeline_frame) { + else if ((seq->start + SEQ_time_strip_length_get(scene, seq)) < timeline_frame) { seq->start = timeline_frame; seq->startofs = 0; - seq->anim_startofs += seq->len - 1; + seq->anim_startofs += SEQ_time_strip_length_get(scene, seq) - 1; seq->endstill = seq->enddisp - timeline_frame - 1; seq->startstill = 0; } } -static void seq_split_set_right_offset(Sequence *seq, int timeline_frame) +static void seq_split_set_right_offset(Scene *scene, Sequence *seq, int timeline_frame) { /* Adjust within range of extended stillframes before strip. */ if (timeline_frame < seq->start) { seq->start = timeline_frame - 1; seq->startstill = timeline_frame - seq->startdisp - 1; - seq->endofs = seq->len - 1; + seq->endofs = SEQ_time_strip_length_get(scene, seq) - 1; } /* Adjust within range of extended stillframes after strip. */ - else if ((seq->start + seq->len) < timeline_frame) { + else if ((seq->start + SEQ_time_strip_length_get(scene, seq)) < timeline_frame) { seq->endstill -= seq->enddisp - timeline_frame; } - SEQ_transform_set_right_handle_frame(seq, timeline_frame); + SEQ_transform_set_right_handle_frame(scene, seq, timeline_frame); } -static void seq_split_set_left_offset(Sequence *seq, int timeline_frame) +static void seq_split_set_left_offset(Scene *scene, Sequence *seq, int timeline_frame) { /* Adjust within range of extended stillframes before strip. */ if (timeline_frame < seq->start) { seq->startstill = seq->start - timeline_frame; } /* Adjust within range of extended stillframes after strip. */ - if ((seq->start + seq->len) < timeline_frame) { - seq->start = timeline_frame - seq->len + 1; + if ((seq->start + SEQ_time_strip_length_get(scene, seq)) < timeline_frame) { + seq->start = timeline_frame - SEQ_time_strip_length_get(scene, seq) + 1; seq->endstill = seq->enddisp - timeline_frame - 1; } - SEQ_transform_set_left_handle_frame(seq, timeline_frame); + SEQ_transform_set_left_handle_frame(scene, seq, timeline_frame); } static bool seq_edit_split_effect_intersect_check(const Sequence *seq, const int timeline_frame) @@ -363,10 +365,10 @@ static void seq_edit_split_handle_strip_offsets(Main *bmain, if (seq_edit_split_effect_intersect_check(right_seq, timeline_frame)) { switch (method) { case SEQ_SPLIT_SOFT: - seq_split_set_left_offset(right_seq, timeline_frame); + seq_split_set_left_offset(scene, right_seq, timeline_frame); break; case SEQ_SPLIT_HARD: - seq_split_set_left_hold_offset(right_seq, timeline_frame); + seq_split_set_left_hold_offset(scene, right_seq, timeline_frame); SEQ_add_reload_new_file(bmain, scene, right_seq, false); break; } @@ -376,10 +378,10 @@ static void seq_edit_split_handle_strip_offsets(Main *bmain, if (seq_edit_split_effect_intersect_check(left_seq, timeline_frame)) { switch (method) { case SEQ_SPLIT_SOFT: - seq_split_set_right_offset(left_seq, timeline_frame); + seq_split_set_right_offset(scene, left_seq, timeline_frame); break; case SEQ_SPLIT_HARD: - seq_split_set_right_hold_offset(left_seq, timeline_frame); + seq_split_set_right_hold_offset(scene, left_seq, timeline_frame); SEQ_add_reload_new_file(bmain, scene, left_seq, false); break; } diff --git a/source/blender/sequencer/intern/strip_relations.c b/source/blender/sequencer/intern/strip_relations.c index 1899cc99263..a7afe721fcb 100644 --- a/source/blender/sequencer/intern/strip_relations.c +++ b/source/blender/sequencer/intern/strip_relations.c @@ -29,6 +29,7 @@ #include "SEQ_relations.h" #include "SEQ_sequencer.h" #include "SEQ_time.h" +#include "SEQ_transform.h" #include "effects.h" #include "image_cache.h" @@ -456,3 +457,23 @@ struct Sequence *SEQ_find_metastrip_by_sequence(ListBase *seqbase, Sequence *met return NULL; } + +void SEQ_relations_framechange_update(Scene *scene, Sequence *seq) +{ + Editing *ed = SEQ_editing_get(scene); + // const int frame_end = SEQ_transform_get_right_handle_frame(scene, seq); + SEQ_time_update_sequence(scene, &ed->seqbase, seq); + SEQ_cache_cleanup(scene); + // SEQ_transform_set_right_handle_frame(scene, seq, frame_end); + SEQ_time_update_sequence(scene, &ed->seqbase, seq); +} + +void SEQ_relations_framechange_update_recursive(Scene *scene, const ListBase *seqbase) +{ + LISTBASE_FOREACH (Sequence *, seq, seqbase) { + if (seq->type == SEQ_TYPE_META) { + SEQ_relations_framechange_update_recursive(scene, &seq->seqbase); + } + SEQ_relations_framechange_update(scene, seq); + } +} diff --git a/source/blender/sequencer/intern/strip_time.c b/source/blender/sequencer/intern/strip_time.c index a5341dbc528..b60f78bd0ba 100644 --- a/source/blender/sequencer/intern/strip_time.c +++ b/source/blender/sequencer/intern/strip_time.c @@ -30,11 +30,26 @@ #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->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; + int sta = SEQ_time_start_frame_get(seq); + int end = SEQ_time_start_frame_get(seq) + SEQ_time_strip_length_get(scene, seq) - 1; if (seq->type & SEQ_TYPE_EFFECT) { end = seq->enddisp; @@ -45,29 +60,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_i(frame_index, 0, end - sta); + frame_index *= seq_time_playback_rate_factor_get(scene, seq); + if (seq->strobe < 1.0f) { seq->strobe = 1.0f; } @@ -79,6 +81,13 @@ float seq_give_frame_index(Sequence *seq, float timeline_frame) return frame_index; } +/* 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->len / seq_time_playback_rate_factor_get(scene, seq); +} + static int metaseq_start(Sequence *metaseq) { return metaseq->start + metaseq->startofs; @@ -147,7 +156,7 @@ static void seq_time_update_sequence_bounds(Scene *scene, Sequence *seq) } seq->startdisp = seq->start + seq->startofs - seq->startstill; - seq->enddisp = seq->start + seq->len - seq->endofs + seq->endstill; + seq->enddisp = seq->start + SEQ_time_strip_length_get(scene, seq) - seq->endofs + seq->endstill; if (seq->type == SEQ_TYPE_META) { seq_update_sound_bounds_recursive(scene, seq); @@ -184,8 +193,8 @@ void SEQ_time_update_meta_strip_range(Scene *scene, Sequence *seq_meta) seq_time_update_meta_strip(scene, seq_meta); /* Prevent meta-strip to move in timeline. */ - SEQ_transform_set_left_handle_frame(seq_meta, seq_meta->startdisp); - SEQ_transform_set_right_handle_frame(seq_meta, seq_meta->enddisp); + SEQ_transform_set_left_handle_frame(scene, seq_meta, seq_meta->startdisp); + SEQ_transform_set_right_handle_frame(scene, seq_meta, seq_meta->enddisp); } void SEQ_time_update_sequence(Scene *scene, ListBase *seqbase, Sequence *seq) @@ -516,3 +525,59 @@ bool SEQ_time_strip_intersects_frame(const Sequence *seq, const int timeline_fra { return (seq->startdisp <= timeline_frame) && (seq->enddisp > timeline_frame); } + +/* When setting speed factor, image at left handle must not change. This means, that start of strip + * content must be moved accordingly. + * + * This needs to consider `playback_rate`??? Ideally, this would calculate everything from ground + * up, so there are no precision issues, but I don't think that is possible. + * + * So if this function can't handle precision issues, only other option is to use getters for strip + * start and offsets, that would take speed factor into account. This is possible though, because + * speed is single property of strip, that is easily accessible. + * + * Another important question though is, that how manipulation of these offsets will work? + * Is that shit even possible? + * + * So imagine setting speed from 1 to 2. + * - subsystem will assume length is 1/2 of normal + * - subsystem must assume left handle offset is half as well + * - And it must assume seq->start is twice as far so that left handle does not move. + * - strip length may or may not change, this can be treated relatively well. + * + * - when you move the handle though, it would have to calculate how strip should look like with + * speed changed, then calculate it back to where speed factor is not applied. + * + * Basically pivot point is left handle..... + * + * So if strip is defined as such: + * - start = 1 + * - offs = 100 + * - len = 50 + * - spd = 2 + * + * + * then for playback, calculated frame range is 100 - 200 + */ + +void SEQ_time_speed_factor_set(Scene *scene, Sequence *seq, const float speed_factor) +{ + seq->speed_factor = speed_factor; +} + +static float seq_time_retime_offset_get(Sequence *seq) +{ + const float new_start_offset_len = seq->startofs / seq->speed_factor; + return seq->startofs - new_start_offset_len; +} + +/* Return timeline frame, where strip content starts. */ +float SEQ_time_start_frame_get(Sequence *seq) +{ + return seq->start + seq_time_retime_offset_get(seq); +} + +float SEQ_time_start_offset_get(Scene *scene, Sequence *seq) +{ + return seq->startofs - seq_time_retime_offset_get(seq); +} diff --git a/source/blender/sequencer/intern/strip_time.h b/source/blender/sequencer/intern/strip_time.h index c96a016e646..9e272ccc64b 100644 --- a/source/blender/sequencer/intern/strip_time.h +++ b/source/blender/sequencer/intern/strip_time.h @@ -15,7 +15,7 @@ struct ListBase; struct Scene; struct Sequence; -float seq_give_frame_index(struct Sequence *seq, float timeline_frame); +float seq_give_frame_index(const struct Scene *scene, struct Sequence *seq, float timeline_frame); void seq_update_sound_bounds_recursive(struct Scene *scene, struct Sequence *metaseq); /* Describes gap between strips in timeline. */ diff --git a/source/blender/sequencer/intern/strip_transform.c b/source/blender/sequencer/intern/strip_transform.c index 2c9ab0a3335..f8ded081558 100644 --- a/source/blender/sequencer/intern/strip_transform.c +++ b/source/blender/sequencer/intern/strip_transform.c @@ -33,42 +33,122 @@ static int seq_tx_get_start(Sequence *seq) { return seq->start; } -static int seq_tx_get_end(Sequence *seq) +static int seq_tx_get_end(Scene *scene, Sequence *seq) { - return seq->start + seq->len; + return seq->start + SEQ_time_strip_length_get(scene, seq); } -int SEQ_transform_get_left_handle_frame(Sequence *seq) +/* Sounds cannot be extended past their endpoints. */ +static void seq_transform_handle_limit_sound(Sequence *seq) { - return (seq->start - seq->startstill) + seq->startofs; + if (seq->type == SEQ_TYPE_SOUND_RAM) { + seq->startstill = 0; + seq->endstill = 0; + } +} + +int SEQ_transform_get_left_handle_frame(Scene *scene, Sequence *seq) +{ + return seq->start - seq->startstill + seq->startofs; } -int SEQ_transform_get_right_handle_frame(Sequence *seq) +int SEQ_transform_get_right_handle_frame(Scene *scene, Sequence *seq) { - return ((seq->start + seq->len) + seq->endstill) - seq->endofs; + const float strip_content_frame_end = seq->start + SEQ_time_strip_length_get(scene, seq); + return strip_content_frame_end + seq->endstill - seq->endofs; } -void SEQ_transform_set_left_handle_frame(Sequence *seq, int val) +static void seq_startofs_offset(Sequence *seq, float offset) { - if (val < (seq)->start) { - seq->startstill = abs(val - (seq)->start); + seq->startofs += offset * seq->speed_factor; + /* Retimed strips must compensate `seq->start`, so content origin does not move. */ + if (seq->speed_factor != 1) { + seq->start -= offset * (seq->speed_factor - 1); + } +} + +static float seq_time_retime_offset_get(Sequence *seq) +{ + const float new_start_offset_len = seq->startofs / seq->speed_factor; + return seq->startofs - new_start_offset_len; +} + +void SEQ_transform_content_start_set(Scene *scene, Sequence *seq, int timeline_frame) +{ + float start_cur = SEQ_time_start_frame_get(seq); + float diff = timeline_frame - start_cur; + + printf("old start = %f \n", start_cur); + printf("target = %d \n", timeline_frame); + printf("offset = %f \n", diff); + + seq->startofs -= seq->startstill; + seq->endofs -= seq->endstill; + seq->startstill = 0; + seq->endstill = 0; + + seq->start += diff * seq->speed_factor; + seq->startofs -= diff * seq->speed_factor * 1.5; + seq->endofs += diff * seq->speed_factor; + // seq->start -= seq_time_retime_offset_get(seq); + if (seq->startofs < 0) { + seq->startstill -= seq->startofs; seq->startofs = 0; } + if (seq->endofs < 0) { + seq->endstill -= seq->endofs; + seq->endofs = 0; + } + + start_cur = SEQ_time_start_frame_get(seq); + printf("new start = %f \n", start_cur); + printf("startofd = %f \n", seq->startofs); + printf("startstill = %d \n", seq->startstill); + printf("================\n\n"); +} + +void SEQ_transform_set_left_handle_frame(Scene *scene, Sequence *seq, int val) +{ + float right_handle_orig_frame = SEQ_transform_get_right_handle_frame(scene, seq); + float left_handle_orig_frame = SEQ_transform_get_left_handle_frame(scene, seq); + + if (val >= right_handle_orig_frame) { + val = right_handle_orig_frame - 1; + } + + if (val < seq->start) { + /* Get rid of start offset first. */ + seq_startofs_offset(seq, -seq->startofs / seq->speed_factor); + /* Apply rest of necessary offset as still frames. */ + seq->startstill = seq->start - val; + } else { - seq->startofs = abs(val - (seq)->start); + seq_startofs_offset(seq, val - left_handle_orig_frame - seq->startstill); seq->startstill = 0; } + + /* With retimed strip, right handle position must be reset. */ + SEQ_transform_set_right_handle_frame(scene, seq, right_handle_orig_frame); + seq_transform_handle_limit_sound(seq); } -void SEQ_transform_set_right_handle_frame(Sequence *seq, int val) +void SEQ_transform_set_right_handle_frame(Scene *scene, Sequence *seq, int val) { - if (val > (seq)->start + (seq)->len) { - seq->endstill = abs(val - (seq->start + (seq)->len)); + const float strip_content_end_frame = seq->start + SEQ_time_strip_length_get(scene, seq); + float left_handle_orig_frame = SEQ_transform_get_left_handle_frame(scene, seq); + + if (val <= left_handle_orig_frame) { + val = left_handle_orig_frame + 1; + } + + if (val > strip_content_end_frame) { + seq->endstill = fabs(val - strip_content_end_frame); seq->endofs = 0; } else { - seq->endofs = abs(val - ((seq)->start + (seq)->len)); + seq->endofs = fabs(val - strip_content_end_frame); seq->endstill = 0; } + seq_transform_handle_limit_sound(seq); } bool SEQ_transform_single_image_check(Sequence *seq) @@ -119,50 +199,7 @@ bool SEQ_transform_seqbase_isolated_sel_check(ListBase *seqbase) return true; } -void SEQ_transform_handle_xlimits(Sequence *seq, int leftflag, int rightflag) -{ - if (leftflag) { - if (SEQ_transform_get_left_handle_frame(seq) >= SEQ_transform_get_right_handle_frame(seq)) { - SEQ_transform_set_left_handle_frame(seq, SEQ_transform_get_right_handle_frame(seq) - 1); - } - - if (SEQ_transform_single_image_check(seq) == 0) { - if (SEQ_transform_get_left_handle_frame(seq) >= seq_tx_get_end(seq)) { - SEQ_transform_set_left_handle_frame(seq, seq_tx_get_end(seq) - 1); - } - - /* TODO: This doesn't work at the moment. */ -#if 0 - if (seq_tx_get_start(seq) >= seq_tx_get_final_right(seq, 0)) { - int ofs; - ofs = seq_tx_get_start(seq) - seq_tx_get_final_right(seq, 0); - seq->start -= ofs; - seq_tx_set_final_left(seq, seq_tx_get_final_left(seq, 0) + ofs); - } -#endif - } - } - - if (rightflag) { - if (SEQ_transform_get_right_handle_frame(seq) <= SEQ_transform_get_left_handle_frame(seq)) { - SEQ_transform_set_right_handle_frame(seq, SEQ_transform_get_left_handle_frame(seq) + 1); - } - - if (SEQ_transform_single_image_check(seq) == 0) { - if (SEQ_transform_get_right_handle_frame(seq) <= seq_tx_get_start(seq)) { - SEQ_transform_set_right_handle_frame(seq, seq_tx_get_start(seq) + 1); - } - } - } - - /* sounds cannot be extended past their endpoints */ - if (seq->type == SEQ_TYPE_SOUND_RAM) { - seq->startstill = 0; - seq->endstill = 0; - } -} - -void SEQ_transform_fix_single_image_seq_offsets(Sequence *seq) +void SEQ_transform_fix_single_image_seq_offsets(Scene *scene, Sequence *seq) { int left, start, offset; if (!SEQ_transform_single_image_check(seq)) { @@ -171,12 +208,14 @@ void SEQ_transform_fix_single_image_seq_offsets(Sequence *seq) /* make sure the image is always at the start since there is only one, * adjusting its start should be ok */ - left = SEQ_transform_get_left_handle_frame(seq); + left = SEQ_transform_get_left_handle_frame(scene, seq); start = seq->start; if (start != left) { offset = left - start; - SEQ_transform_set_left_handle_frame(seq, SEQ_transform_get_left_handle_frame(seq) - offset); - SEQ_transform_set_right_handle_frame(seq, SEQ_transform_get_right_handle_frame(seq) - offset); + SEQ_transform_set_left_handle_frame( + scene, seq, SEQ_transform_get_left_handle_frame(scene, seq) - offset); + SEQ_transform_set_right_handle_frame( + scene, seq, SEQ_transform_get_right_handle_frame(scene, seq) - offset); seq->start += offset; } } @@ -227,8 +266,8 @@ void SEQ_transform_translate_sequence(Scene *evil_scene, Sequence *seq, int delt * start/end point in timeline. */ SEQ_time_update_meta_strip_range(evil_scene, seq); /* Move meta start/end points. */ - SEQ_transform_set_left_handle_frame(seq, seq->startdisp + delta); - SEQ_transform_set_right_handle_frame(seq, seq->enddisp + delta); + SEQ_transform_set_left_handle_frame(evil_scene, seq, seq->startdisp + delta); + SEQ_transform_set_right_handle_frame(evil_scene, seq, seq->enddisp + delta); } ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(evil_scene)); diff --git a/source/blender/sequencer/intern/utils.c b/source/blender/sequencer/intern/utils.c index da422c4228f..83cde8f470e 100644 --- a/source/blender/sequencer/intern/utils.c +++ b/source/blender/sequencer/intern/utils.c @@ -232,7 +232,7 @@ ListBase *SEQ_get_seqbase_from_sequence(Sequence *seq, int *r_offset) switch (seq->type) { case SEQ_TYPE_META: { seqbase = &seq->seqbase; - *r_offset = seq->start; + *r_offset = SEQ_time_start_frame_get(seq); break; } case SEQ_TYPE_SCENE: {