2022-02-11 09:07:11 +11:00
|
|
|
/* SPDX-License-Identifier: GPL-2.0-or-later
|
2022-02-09 16:21:21 +11:00
|
|
|
* Copyright 2001-2002 NaN Holding BV. All rights reserved.
|
|
|
|
|
* 2003-2009 Blender Foundation.
|
2022-02-11 09:07:11 +11:00
|
|
|
* 2005-2006 Peter Schlaile <peter [at] schlaile [dot] de> */
|
2020-11-16 05:02:30 +01:00
|
|
|
|
|
|
|
|
/** \file
|
|
|
|
|
* \ingroup bke
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "DNA_scene_types.h"
|
|
|
|
|
#include "DNA_sequence_types.h"
|
|
|
|
|
|
|
|
|
|
#include "BLI_listbase.h"
|
|
|
|
|
#include "BLI_math.h"
|
|
|
|
|
|
|
|
|
|
#include "BKE_movieclip.h"
|
|
|
|
|
#include "BKE_scene.h"
|
|
|
|
|
#include "BKE_sound.h"
|
|
|
|
|
|
2021-07-06 19:48:06 +02:00
|
|
|
#include "DNA_sound_types.h"
|
2020-11-16 05:02:30 +01:00
|
|
|
#include "IMB_imbuf.h"
|
|
|
|
|
|
2022-04-04 12:52:48 +02:00
|
|
|
#include "SEQ_channels.h"
|
VSE: Fix rendering inconsistency
Fix issue described in T87678, which was partially a bug and partially
change in intended(at least as far as I can tell) behaior.
Function `evaluate_seq_frame_gen` that was partially responsible for
filtering strips in stack for rendering wasn't working correctly.
Intended functionality seems to be removing all effect inputs from stack
as it is unlikely that user would want these to be blended in. However
there was logic to exclude effects placed into same input, which because
of weak implementation caused, that any effect input, that is effect as
well will be considered to be part of stack to be blended in.
This bug was apparently used to produce effects like glow over original
image.
Even though this is originally unintended, I have kept this logic, but
I have made it explicit.
Another change is request made in T87678 to make it possible to keep
effect inputs as part of stack when they are placed above the effect,
which would imply that blending is intended. This change is again
explicitly defined.
Whole implementation has been refactored, so logic is consolidated
and code should be as explicit as possible and more readable.
`must_render_strip function` may be still quite hard to read, not sure
if I can make it nicer.
Last change is for remove gaps feature code - it used same rendering
code, which may be reason why its logic was split in first place.
Now it uses sequencer iterator, which will definitely be faster than
original code, but I could have used `LISTBASE_FOREACH` in this case.
Reviewed By: sergey
Differential Revision: https://developer.blender.org/D11301
2021-05-19 22:59:33 +02:00
|
|
|
#include "SEQ_iterator.h"
|
2020-12-19 06:44:57 +01:00
|
|
|
#include "SEQ_render.h"
|
2020-11-16 05:02:30 +01:00
|
|
|
#include "SEQ_sequencer.h"
|
2020-12-19 06:44:57 +01:00
|
|
|
#include "SEQ_time.h"
|
2021-05-11 12:25:54 +02:00
|
|
|
#include "SEQ_transform.h"
|
2020-11-16 05:02:30 +01:00
|
|
|
|
2022-06-02 01:39:40 +02:00
|
|
|
#include "sequencer.h"
|
2020-11-16 05:02:30 +01:00
|
|
|
#include "strip_time.h"
|
|
|
|
|
#include "utils.h"
|
|
|
|
|
|
2022-06-29 12:45:59 +02:00
|
|
|
static float seq_time_media_playback_rate_factor_get(const Scene *scene, const Sequence *seq)
|
|
|
|
|
{
|
|
|
|
|
if ((seq->flag & SEQ_AUTO_PLAYBACK_RATE) == 0) {
|
|
|
|
|
return 1.0f;
|
|
|
|
|
}
|
|
|
|
|
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)
|
2020-11-16 05:02:30 +01:00
|
|
|
{
|
|
|
|
|
float frame_index;
|
2022-06-29 12:45:59 +02:00
|
|
|
float sta = SEQ_time_start_frame_get(seq);
|
|
|
|
|
float end = SEQ_time_start_frame_get(seq) + SEQ_time_strip_length_get(scene, seq) - 1;
|
2020-11-16 05:02:30 +01:00
|
|
|
|
|
|
|
|
if (seq->type & SEQ_TYPE_EFFECT) {
|
2022-06-29 12:45:59 +02:00
|
|
|
end = SEQ_time_right_handle_frame_get(scene, seq);
|
2020-11-16 05:02:30 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (end < sta) {
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (seq->flag & SEQ_REVERSE_FRAMES) {
|
2022-06-29 12:45:59 +02:00
|
|
|
frame_index = end - timeline_frame;
|
2020-11-16 05:02:30 +01:00
|
|
|
}
|
|
|
|
|
else {
|
2022-06-29 12:45:59 +02:00
|
|
|
frame_index = timeline_frame - sta;
|
2020-11-16 05:02:30 +01:00
|
|
|
}
|
|
|
|
|
|
2022-06-29 12:45:59 +02:00
|
|
|
/* Clamp frame index to strip frame range. */
|
|
|
|
|
frame_index = clamp_f(frame_index, 0, end - sta);
|
|
|
|
|
frame_index *= seq_time_playback_rate_factor_get(scene, seq);
|
|
|
|
|
|
2020-11-16 05:02:30 +01:00
|
|
|
if (seq->strobe < 1.0f) {
|
|
|
|
|
seq->strobe = 1.0f;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (seq->strobe > 1.0f) {
|
|
|
|
|
frame_index -= fmodf((double)frame_index, (double)seq->strobe);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return frame_index;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int metaseq_start(Sequence *metaseq)
|
|
|
|
|
{
|
|
|
|
|
return metaseq->start + metaseq->startofs;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int metaseq_end(Sequence *metaseq)
|
|
|
|
|
{
|
|
|
|
|
return metaseq->start + metaseq->len - metaseq->endofs;
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-02 01:39:40 +02:00
|
|
|
static void seq_update_sound_bounds_recursive_impl(const Scene *scene,
|
2020-11-16 05:02:30 +01:00
|
|
|
Sequence *metaseq,
|
|
|
|
|
int start,
|
|
|
|
|
int end)
|
|
|
|
|
{
|
|
|
|
|
Sequence *seq;
|
|
|
|
|
|
2021-07-23 16:56:00 +10:00
|
|
|
/* For sound we go over full meta tree to update bounds of the sound strips,
|
|
|
|
|
* since sound is played outside of evaluating the imbufs. */
|
2020-11-16 05:02:30 +01:00
|
|
|
for (seq = metaseq->seqbase.first; seq; seq = seq->next) {
|
|
|
|
|
if (seq->type == SEQ_TYPE_META) {
|
|
|
|
|
seq_update_sound_bounds_recursive_impl(
|
|
|
|
|
scene, seq, max_ii(start, metaseq_start(seq)), min_ii(end, metaseq_end(seq)));
|
|
|
|
|
}
|
|
|
|
|
else if (ELEM(seq->type, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SCENE)) {
|
|
|
|
|
if (seq->scene_sound) {
|
|
|
|
|
int startofs = seq->startofs;
|
|
|
|
|
int endofs = seq->endofs;
|
|
|
|
|
if (seq->startofs + seq->start < start) {
|
|
|
|
|
startofs = start - seq->start;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (seq->start + seq->len - seq->endofs > end) {
|
|
|
|
|
endofs = seq->start + seq->len - end;
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-16 01:25:27 +02:00
|
|
|
double offset_time = 0.0f;
|
|
|
|
|
if (seq->sound != NULL) {
|
|
|
|
|
offset_time = seq->sound->offset_time;
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-16 05:02:30 +01:00
|
|
|
BKE_sound_move_scene_sound(scene,
|
|
|
|
|
seq->scene_sound,
|
|
|
|
|
seq->start + startofs,
|
|
|
|
|
seq->start + seq->len - endofs,
|
2021-07-06 19:48:06 +02:00
|
|
|
startofs + seq->anim_startofs,
|
2021-10-16 01:25:27 +02:00
|
|
|
offset_time);
|
2020-11-16 05:02:30 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-02 01:39:40 +02:00
|
|
|
void seq_update_sound_bounds_recursive(const Scene *scene, Sequence *metaseq)
|
2020-11-16 05:02:30 +01:00
|
|
|
{
|
|
|
|
|
seq_update_sound_bounds_recursive_impl(
|
|
|
|
|
scene, metaseq, metaseq_start(metaseq), metaseq_end(metaseq));
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-02 01:39:40 +02:00
|
|
|
/* Update meta strip content start and end, update sound playback range. */
|
|
|
|
|
void SEQ_time_update_meta_strip_range(const Scene *scene, Sequence *seq_meta)
|
2020-11-16 05:02:30 +01:00
|
|
|
{
|
2022-06-02 01:39:40 +02:00
|
|
|
if (seq_meta == NULL) {
|
|
|
|
|
return;
|
2020-11-16 05:02:30 +01:00
|
|
|
}
|
|
|
|
|
|
2021-05-11 12:25:54 +02:00
|
|
|
if (BLI_listbase_is_empty(&seq_meta->seqbase)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-29 12:45:59 +02:00
|
|
|
const int strip_start = SEQ_time_left_handle_frame_get(scene, seq_meta);
|
|
|
|
|
const int strip_end = SEQ_time_right_handle_frame_get(scene, seq_meta);
|
2022-06-02 01:39:40 +02:00
|
|
|
|
2021-05-11 12:25:54 +02:00
|
|
|
int min = MAXFRAME * 2;
|
|
|
|
|
int max = -MAXFRAME * 2;
|
|
|
|
|
LISTBASE_FOREACH (Sequence *, seq, &seq_meta->seqbase) {
|
2022-06-29 12:45:59 +02:00
|
|
|
min = min_ii(SEQ_time_left_handle_frame_get(scene, seq), min);
|
|
|
|
|
max = max_ii(SEQ_time_right_handle_frame_get(scene, seq), max);
|
2021-05-11 12:25:54 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
seq_meta->start = min + seq_meta->anim_startofs;
|
|
|
|
|
seq_meta->len = max - min;
|
|
|
|
|
seq_meta->len -= seq_meta->anim_startofs;
|
|
|
|
|
seq_meta->len -= seq_meta->anim_endofs;
|
|
|
|
|
|
|
|
|
|
seq_update_sound_bounds_recursive(scene, seq_meta);
|
|
|
|
|
|
2021-05-14 17:35:22 +10:00
|
|
|
/* Prevent meta-strip to move in timeline. */
|
2022-06-02 01:39:40 +02:00
|
|
|
SEQ_time_left_handle_frame_set(scene, seq_meta, strip_start);
|
|
|
|
|
SEQ_time_right_handle_frame_set(scene, seq_meta, strip_end);
|
2021-05-11 12:25:54 +02:00
|
|
|
}
|
|
|
|
|
|
2022-06-29 12:45:59 +02:00
|
|
|
void seq_time_effect_range_set(const Scene *scene, Sequence *seq)
|
2020-11-16 05:02:30 +01:00
|
|
|
{
|
2022-06-13 18:26:52 +02:00
|
|
|
if (seq->seq1 == NULL && seq->seq2 == NULL) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-02 01:39:40 +02:00
|
|
|
if (seq->seq1 && seq->seq2) { /* 2 - input effect. */
|
2022-06-29 12:45:59 +02:00
|
|
|
seq->startdisp = max_ii(SEQ_time_left_handle_frame_get(scene, seq->seq1),
|
|
|
|
|
SEQ_time_left_handle_frame_get(scene, seq->seq2));
|
|
|
|
|
seq->enddisp = min_ii(SEQ_time_right_handle_frame_get(scene, seq->seq1),
|
|
|
|
|
SEQ_time_right_handle_frame_get(scene, seq->seq2));
|
2020-11-16 05:02:30 +01:00
|
|
|
}
|
2022-06-02 01:39:40 +02:00
|
|
|
else if (seq->seq1) { /* Single input effect. */
|
2022-06-29 12:45:59 +02:00
|
|
|
seq->startdisp = SEQ_time_right_handle_frame_get(scene, seq->seq1);
|
|
|
|
|
seq->enddisp = SEQ_time_left_handle_frame_get(scene, seq->seq1);
|
2020-11-16 05:02:30 +01:00
|
|
|
}
|
2022-06-02 01:39:40 +02:00
|
|
|
else if (seq->seq2) { /* Strip may be missing one of inputs. */
|
2022-06-29 12:45:59 +02:00
|
|
|
seq->startdisp = SEQ_time_right_handle_frame_get(scene, seq->seq2);
|
|
|
|
|
seq->enddisp = SEQ_time_left_handle_frame_get(scene, seq->seq2);
|
2021-10-07 00:10:37 +02:00
|
|
|
}
|
2021-05-11 12:25:54 +02:00
|
|
|
|
2022-06-02 01:39:40 +02:00
|
|
|
if (seq->startdisp > seq->enddisp) {
|
|
|
|
|
SWAP(int, seq->startdisp, seq->enddisp);
|
2020-11-16 05:02:30 +01:00
|
|
|
}
|
2021-10-07 00:10:37 +02:00
|
|
|
|
2022-06-02 01:39:40 +02:00
|
|
|
/* Values unusable for effects, these should be always 0. */
|
|
|
|
|
seq->startofs = seq->endofs = seq->anim_startofs = seq->anim_endofs = 0;
|
2022-07-08 17:44:24 +02:00
|
|
|
seq->start = seq->startdisp;
|
|
|
|
|
seq->len = seq->enddisp - seq->startdisp;
|
2020-11-16 05:02:30 +01:00
|
|
|
}
|
|
|
|
|
|
2022-06-02 01:39:40 +02:00
|
|
|
/* Update strip startdisp and enddisp (n-input effects have no len to calculate these). */
|
|
|
|
|
void seq_time_update_effects_strip_range(const Scene *scene, SeqCollection *effects)
|
2021-11-15 20:23:57 +01:00
|
|
|
{
|
2022-06-02 01:39:40 +02:00
|
|
|
if (effects == NULL) {
|
|
|
|
|
return;
|
2021-11-15 20:23:57 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Sequence *seq;
|
2022-06-02 01:39:40 +02:00
|
|
|
/* First pass: Update length of immediate effects. */
|
|
|
|
|
SEQ_ITERATOR_FOREACH (seq, effects) {
|
2022-06-29 12:45:59 +02:00
|
|
|
seq_time_effect_range_set(scene, seq);
|
2021-11-15 20:23:57 +01:00
|
|
|
}
|
|
|
|
|
|
2022-06-02 01:39:40 +02:00
|
|
|
/* Second pass: Recursive call to update effects in chain and in order, so they inherit length
|
|
|
|
|
* correctly. */
|
|
|
|
|
SEQ_ITERATOR_FOREACH (seq, effects) {
|
|
|
|
|
seq_time_update_effects_strip_range(scene, seq_sequence_lookup_effects_by_seq(scene, seq));
|
2021-11-15 20:23:57 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-19 05:57:27 +01:00
|
|
|
int SEQ_time_find_next_prev_edit(Scene *scene,
|
|
|
|
|
int timeline_frame,
|
|
|
|
|
const short side,
|
|
|
|
|
const bool do_skip_mute,
|
|
|
|
|
const bool do_center,
|
|
|
|
|
const bool do_unselected)
|
2020-11-16 05:02:30 +01:00
|
|
|
{
|
2021-09-02 11:29:32 +10:00
|
|
|
Editing *ed = SEQ_editing_get(scene);
|
2022-04-04 12:52:48 +02:00
|
|
|
ListBase *channels = SEQ_channels_displayed_get(ed);
|
2020-11-16 05:02:30 +01:00
|
|
|
Sequence *seq;
|
|
|
|
|
|
|
|
|
|
int dist, best_dist, best_frame = timeline_frame;
|
|
|
|
|
int seq_frames[2], seq_frames_tot;
|
|
|
|
|
|
|
|
|
|
/* In case where both is passed,
|
|
|
|
|
* frame just finds the nearest end while frame_left the nearest start. */
|
|
|
|
|
|
|
|
|
|
best_dist = MAXFRAME * 2;
|
|
|
|
|
|
|
|
|
|
if (ed == NULL) {
|
|
|
|
|
return timeline_frame;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (seq = ed->seqbasep->first; seq; seq = seq->next) {
|
|
|
|
|
int i;
|
|
|
|
|
|
2022-04-04 12:52:48 +02:00
|
|
|
if (do_skip_mute && SEQ_render_is_muted(channels, seq)) {
|
2020-11-16 05:02:30 +01:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (do_unselected && (seq->flag & SELECT)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (do_center) {
|
2022-06-29 12:45:59 +02:00
|
|
|
seq_frames[0] = (SEQ_time_left_handle_frame_get(scene, seq) +
|
|
|
|
|
SEQ_time_right_handle_frame_get(scene, seq)) /
|
2022-06-02 01:39:40 +02:00
|
|
|
2;
|
2020-11-16 05:02:30 +01:00
|
|
|
seq_frames_tot = 1;
|
|
|
|
|
}
|
|
|
|
|
else {
|
2022-06-29 12:45:59 +02:00
|
|
|
seq_frames[0] = SEQ_time_left_handle_frame_get(scene, seq);
|
|
|
|
|
seq_frames[1] = SEQ_time_right_handle_frame_get(scene, seq);
|
2020-11-16 05:02:30 +01:00
|
|
|
|
|
|
|
|
seq_frames_tot = 2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < seq_frames_tot; i++) {
|
|
|
|
|
const int seq_frame = seq_frames[i];
|
|
|
|
|
|
|
|
|
|
dist = MAXFRAME * 2;
|
|
|
|
|
|
|
|
|
|
switch (side) {
|
|
|
|
|
case SEQ_SIDE_LEFT:
|
|
|
|
|
if (seq_frame < timeline_frame) {
|
|
|
|
|
dist = timeline_frame - seq_frame;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case SEQ_SIDE_RIGHT:
|
|
|
|
|
if (seq_frame > timeline_frame) {
|
|
|
|
|
dist = seq_frame - timeline_frame;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case SEQ_SIDE_BOTH:
|
|
|
|
|
dist = abs(seq_frame - timeline_frame);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (dist < best_dist) {
|
|
|
|
|
best_frame = seq_frame;
|
|
|
|
|
best_dist = dist;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return best_frame;
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-19 05:57:27 +01:00
|
|
|
float SEQ_time_sequence_get_fps(Scene *scene, Sequence *seq)
|
2020-11-16 05:02:30 +01:00
|
|
|
{
|
|
|
|
|
switch (seq->type) {
|
|
|
|
|
case SEQ_TYPE_MOVIE: {
|
|
|
|
|
seq_open_anim_file(scene, seq, true);
|
|
|
|
|
if (BLI_listbase_is_empty(&seq->anims)) {
|
|
|
|
|
return 0.0f;
|
|
|
|
|
}
|
|
|
|
|
StripAnim *strip_anim = seq->anims.first;
|
|
|
|
|
if (strip_anim->anim == NULL) {
|
|
|
|
|
return 0.0f;
|
|
|
|
|
}
|
|
|
|
|
short frs_sec;
|
|
|
|
|
float frs_sec_base;
|
|
|
|
|
if (IMB_anim_get_fps(strip_anim->anim, &frs_sec, &frs_sec_base, true)) {
|
|
|
|
|
return (float)frs_sec / frs_sec_base;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case SEQ_TYPE_MOVIECLIP:
|
|
|
|
|
if (seq->clip != NULL) {
|
|
|
|
|
return BKE_movieclip_get_fps(seq->clip);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case SEQ_TYPE_SCENE:
|
|
|
|
|
if (seq->scene != NULL) {
|
|
|
|
|
return (float)seq->scene->r.frs_sec / seq->scene->r.frs_sec_base;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
return 0.0f;
|
|
|
|
|
}
|
2020-12-15 21:42:06 +01:00
|
|
|
|
2021-10-25 06:47:51 +02:00
|
|
|
void SEQ_timeline_init_boundbox(const Scene *scene, rctf *rect)
|
2020-12-15 21:42:06 +01:00
|
|
|
{
|
2020-12-17 02:11:22 +01:00
|
|
|
rect->xmin = scene->r.sfra;
|
|
|
|
|
rect->xmax = scene->r.efra + 1;
|
|
|
|
|
rect->ymin = 0.0f;
|
|
|
|
|
rect->ymax = 8.0f;
|
2021-10-25 06:47:51 +02:00
|
|
|
}
|
2020-12-17 02:11:22 +01:00
|
|
|
|
2022-06-29 12:45:59 +02:00
|
|
|
void SEQ_timeline_expand_boundbox(const Scene *scene, const ListBase *seqbase, rctf *rect)
|
2021-10-25 06:47:51 +02:00
|
|
|
{
|
2020-12-17 02:11:22 +01:00
|
|
|
if (seqbase == NULL) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2020-12-15 21:42:06 +01:00
|
|
|
|
|
|
|
|
LISTBASE_FOREACH (Sequence *, seq, seqbase) {
|
2022-06-29 12:45:59 +02:00
|
|
|
if (rect->xmin > SEQ_time_left_handle_frame_get(scene, seq) - 1) {
|
|
|
|
|
rect->xmin = SEQ_time_left_handle_frame_get(scene, seq) - 1;
|
2020-12-15 21:42:06 +01:00
|
|
|
}
|
2022-06-29 12:45:59 +02:00
|
|
|
if (rect->xmax < SEQ_time_right_handle_frame_get(scene, seq) + 1) {
|
|
|
|
|
rect->xmax = SEQ_time_right_handle_frame_get(scene, seq) + 1;
|
2020-12-15 21:42:06 +01:00
|
|
|
}
|
2022-04-04 12:52:48 +02:00
|
|
|
if (rect->ymax < seq->machine) {
|
2022-04-28 16:07:57 +02:00
|
|
|
rect->ymax = seq->machine;
|
2020-12-15 21:42:06 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-25 06:47:51 +02:00
|
|
|
void SEQ_timeline_boundbox(const Scene *scene, const ListBase *seqbase, rctf *rect)
|
|
|
|
|
{
|
|
|
|
|
SEQ_timeline_init_boundbox(scene, rect);
|
2022-06-29 12:45:59 +02:00
|
|
|
SEQ_timeline_expand_boundbox(scene, seqbase, rect);
|
2021-10-25 06:47:51 +02:00
|
|
|
}
|
|
|
|
|
|
2022-06-29 12:45:59 +02:00
|
|
|
static bool strip_exists_at_frame(const Scene *scene,
|
|
|
|
|
SeqCollection *all_strips,
|
|
|
|
|
const int timeline_frame)
|
VSE: Fix rendering inconsistency
Fix issue described in T87678, which was partially a bug and partially
change in intended(at least as far as I can tell) behaior.
Function `evaluate_seq_frame_gen` that was partially responsible for
filtering strips in stack for rendering wasn't working correctly.
Intended functionality seems to be removing all effect inputs from stack
as it is unlikely that user would want these to be blended in. However
there was logic to exclude effects placed into same input, which because
of weak implementation caused, that any effect input, that is effect as
well will be considered to be part of stack to be blended in.
This bug was apparently used to produce effects like glow over original
image.
Even though this is originally unintended, I have kept this logic, but
I have made it explicit.
Another change is request made in T87678 to make it possible to keep
effect inputs as part of stack when they are placed above the effect,
which would imply that blending is intended. This change is again
explicitly defined.
Whole implementation has been refactored, so logic is consolidated
and code should be as explicit as possible and more readable.
`must_render_strip function` may be still quite hard to read, not sure
if I can make it nicer.
Last change is for remove gaps feature code - it used same rendering
code, which may be reason why its logic was split in first place.
Now it uses sequencer iterator, which will definitely be faster than
original code, but I could have used `LISTBASE_FOREACH` in this case.
Reviewed By: sergey
Differential Revision: https://developer.blender.org/D11301
2021-05-19 22:59:33 +02:00
|
|
|
{
|
|
|
|
|
Sequence *seq;
|
|
|
|
|
SEQ_ITERATOR_FOREACH (seq, all_strips) {
|
2022-06-29 12:45:59 +02:00
|
|
|
if (SEQ_time_strip_intersects_frame(scene, seq, timeline_frame)) {
|
VSE: Fix rendering inconsistency
Fix issue described in T87678, which was partially a bug and partially
change in intended(at least as far as I can tell) behaior.
Function `evaluate_seq_frame_gen` that was partially responsible for
filtering strips in stack for rendering wasn't working correctly.
Intended functionality seems to be removing all effect inputs from stack
as it is unlikely that user would want these to be blended in. However
there was logic to exclude effects placed into same input, which because
of weak implementation caused, that any effect input, that is effect as
well will be considered to be part of stack to be blended in.
This bug was apparently used to produce effects like glow over original
image.
Even though this is originally unintended, I have kept this logic, but
I have made it explicit.
Another change is request made in T87678 to make it possible to keep
effect inputs as part of stack when they are placed above the effect,
which would imply that blending is intended. This change is again
explicitly defined.
Whole implementation has been refactored, so logic is consolidated
and code should be as explicit as possible and more readable.
`must_render_strip function` may be still quite hard to read, not sure
if I can make it nicer.
Last change is for remove gaps feature code - it used same rendering
code, which may be reason why its logic was split in first place.
Now it uses sequencer iterator, which will definitely be faster than
original code, but I could have used `LISTBASE_FOREACH` in this case.
Reviewed By: sergey
Differential Revision: https://developer.blender.org/D11301
2021-05-19 22:59:33 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-15 21:42:06 +01:00
|
|
|
void seq_time_gap_info_get(const Scene *scene,
|
|
|
|
|
ListBase *seqbase,
|
|
|
|
|
const int initial_frame,
|
|
|
|
|
GapInfo *r_gap_info)
|
|
|
|
|
{
|
|
|
|
|
rctf rectf;
|
|
|
|
|
/* Get first and last frame. */
|
|
|
|
|
SEQ_timeline_boundbox(scene, seqbase, &rectf);
|
|
|
|
|
const int sfra = (int)rectf.xmin;
|
|
|
|
|
const int efra = (int)rectf.xmax;
|
|
|
|
|
int timeline_frame = initial_frame;
|
|
|
|
|
r_gap_info->gap_exists = false;
|
|
|
|
|
|
VSE: Fix rendering inconsistency
Fix issue described in T87678, which was partially a bug and partially
change in intended(at least as far as I can tell) behaior.
Function `evaluate_seq_frame_gen` that was partially responsible for
filtering strips in stack for rendering wasn't working correctly.
Intended functionality seems to be removing all effect inputs from stack
as it is unlikely that user would want these to be blended in. However
there was logic to exclude effects placed into same input, which because
of weak implementation caused, that any effect input, that is effect as
well will be considered to be part of stack to be blended in.
This bug was apparently used to produce effects like glow over original
image.
Even though this is originally unintended, I have kept this logic, but
I have made it explicit.
Another change is request made in T87678 to make it possible to keep
effect inputs as part of stack when they are placed above the effect,
which would imply that blending is intended. This change is again
explicitly defined.
Whole implementation has been refactored, so logic is consolidated
and code should be as explicit as possible and more readable.
`must_render_strip function` may be still quite hard to read, not sure
if I can make it nicer.
Last change is for remove gaps feature code - it used same rendering
code, which may be reason why its logic was split in first place.
Now it uses sequencer iterator, which will definitely be faster than
original code, but I could have used `LISTBASE_FOREACH` in this case.
Reviewed By: sergey
Differential Revision: https://developer.blender.org/D11301
2021-05-19 22:59:33 +02:00
|
|
|
SeqCollection *collection = SEQ_query_all_strips(seqbase);
|
|
|
|
|
|
2022-06-29 12:45:59 +02:00
|
|
|
if (!strip_exists_at_frame(scene, collection, initial_frame)) {
|
2020-12-15 21:42:06 +01:00
|
|
|
/* Search backward for gap_start_frame. */
|
|
|
|
|
for (; timeline_frame >= sfra; timeline_frame--) {
|
2022-06-29 12:45:59 +02:00
|
|
|
if (strip_exists_at_frame(scene, collection, timeline_frame)) {
|
2020-12-15 21:42:06 +01:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
r_gap_info->gap_start_frame = timeline_frame + 1;
|
|
|
|
|
timeline_frame = initial_frame;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* Search forward for gap_start_frame. */
|
|
|
|
|
for (; timeline_frame <= efra; timeline_frame++) {
|
2022-06-29 12:45:59 +02:00
|
|
|
if (!strip_exists_at_frame(scene, collection, timeline_frame)) {
|
2020-12-15 21:42:06 +01:00
|
|
|
r_gap_info->gap_start_frame = timeline_frame;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/* Search forward for gap_end_frame. */
|
|
|
|
|
for (; timeline_frame <= efra; timeline_frame++) {
|
2022-06-29 12:45:59 +02:00
|
|
|
if (strip_exists_at_frame(scene, collection, timeline_frame)) {
|
2020-12-15 21:42:06 +01:00
|
|
|
const int gap_end_frame = timeline_frame;
|
|
|
|
|
r_gap_info->gap_length = gap_end_frame - r_gap_info->gap_start_frame;
|
|
|
|
|
r_gap_info->gap_exists = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-06-02 21:41:38 +02:00
|
|
|
|
2022-06-29 12:45:59 +02:00
|
|
|
bool SEQ_time_strip_intersects_frame(const Scene *scene,
|
|
|
|
|
const Sequence *seq,
|
|
|
|
|
const int timeline_frame)
|
|
|
|
|
{
|
|
|
|
|
return (SEQ_time_left_handle_frame_get(scene, seq) <= timeline_frame) &&
|
|
|
|
|
(SEQ_time_right_handle_frame_get(scene, seq) > timeline_frame);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SEQ_time_speed_factor_set(const Scene *scene, Sequence *seq, const float speed_factor)
|
|
|
|
|
{
|
|
|
|
|
|
2022-06-30 18:26:14 +02:00
|
|
|
if (seq->type == SEQ_TYPE_SOUND_RAM) {
|
|
|
|
|
seq->speed_factor = speed_factor;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
const float left_handle_frame = SEQ_time_left_handle_frame_get(scene, seq);
|
|
|
|
|
const float unity_start_offset = seq->startofs * seq->speed_factor;
|
|
|
|
|
const float unity_end_offset = seq->endofs * seq->speed_factor;
|
|
|
|
|
/* Left handle is pivot point for content scaling - it must always show same frame. */
|
|
|
|
|
seq->speed_factor = speed_factor;
|
|
|
|
|
seq->startofs = unity_start_offset / speed_factor;
|
|
|
|
|
seq->start = left_handle_frame - seq->startofs;
|
|
|
|
|
seq->endofs = unity_end_offset / speed_factor;
|
|
|
|
|
}
|
2022-06-29 12:45:59 +02:00
|
|
|
|
|
|
|
|
SEQ_time_update_meta_strip_range(scene, seq_sequence_lookup_meta_by_seq(scene, seq));
|
|
|
|
|
seq_time_update_effects_strip_range(scene, seq_sequence_lookup_effects_by_seq(scene, seq));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool SEQ_time_has_left_still_frames(const Scene *scene, const Sequence *seq)
|
|
|
|
|
{
|
|
|
|
|
return SEQ_time_left_handle_frame_get(scene, seq) < SEQ_time_start_frame_get(seq);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool SEQ_time_has_right_still_frames(const Scene *scene, const Sequence *seq)
|
|
|
|
|
{
|
|
|
|
|
return SEQ_time_right_handle_frame_get(scene, seq) >
|
|
|
|
|
SEQ_time_start_frame_get(seq) + SEQ_time_strip_length_get(scene, seq);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool SEQ_time_has_still_frames(const Scene *scene, const Sequence *seq)
|
2021-06-02 21:41:38 +02:00
|
|
|
{
|
2022-06-29 12:45:59 +02:00
|
|
|
return SEQ_time_has_right_still_frames(scene, seq) || SEQ_time_has_left_still_frames(scene, seq);
|
2021-06-02 21:41:38 +02:00
|
|
|
}
|
2022-05-18 21:26:47 +02:00
|
|
|
|
2022-06-29 12:45:59 +02:00
|
|
|
/* 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)
|
2022-05-18 21:26:47 +02:00
|
|
|
{
|
2022-06-30 18:26:14 +02:00
|
|
|
if (seq->type == SEQ_TYPE_SOUND_RAM) {
|
|
|
|
|
return seq->len;
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-29 12:45:59 +02:00
|
|
|
return seq->len / seq_time_playback_rate_factor_get(scene, seq);
|
2022-05-18 21:26:47 +02:00
|
|
|
}
|
|
|
|
|
|
2022-06-29 12:45:59 +02:00
|
|
|
/* Return timeline frame, where strip content starts. */
|
|
|
|
|
float SEQ_time_start_frame_get(const Sequence *seq)
|
2022-05-18 21:26:47 +02:00
|
|
|
{
|
2022-06-29 12:45:59 +02:00
|
|
|
return seq->start;
|
2022-05-18 21:26:47 +02:00
|
|
|
}
|
|
|
|
|
|
2022-06-29 12:45:59 +02:00
|
|
|
void SEQ_time_start_frame_set(const Scene *scene, Sequence *seq, int timeline_frame)
|
2022-05-18 21:26:47 +02:00
|
|
|
{
|
2022-06-29 12:45:59 +02:00
|
|
|
seq->start = timeline_frame;
|
|
|
|
|
SEQ_time_update_meta_strip_range(scene, seq_sequence_lookup_meta_by_seq(scene, seq));
|
|
|
|
|
seq_time_update_effects_strip_range(scene, seq_sequence_lookup_effects_by_seq(scene, seq));
|
2022-05-18 21:26:47 +02:00
|
|
|
}
|
2022-05-18 21:43:14 +02:00
|
|
|
|
2022-06-29 12:45:59 +02:00
|
|
|
int SEQ_time_left_handle_frame_get(const Scene *UNUSED(scene), const Sequence *seq)
|
2022-05-18 21:43:14 +02:00
|
|
|
{
|
2022-06-02 01:39:40 +02:00
|
|
|
if (seq->seq1 || seq->seq2) {
|
|
|
|
|
return seq->startdisp;
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-18 21:43:14 +02:00
|
|
|
return seq->start + seq->startofs;
|
|
|
|
|
}
|
2022-06-02 01:39:40 +02:00
|
|
|
|
2022-06-29 12:45:59 +02:00
|
|
|
int SEQ_time_right_handle_frame_get(const Scene *scene, const Sequence *seq)
|
2022-05-18 21:43:14 +02:00
|
|
|
{
|
2022-06-02 01:39:40 +02:00
|
|
|
if (seq->seq1 || seq->seq2) {
|
|
|
|
|
return seq->enddisp;
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-29 12:45:59 +02:00
|
|
|
return seq->start + SEQ_time_strip_length_get(scene, seq) - seq->endofs;
|
2022-05-18 21:43:14 +02:00
|
|
|
}
|
|
|
|
|
|
2022-06-02 01:39:40 +02:00
|
|
|
void SEQ_time_left_handle_frame_set(const Scene *scene, Sequence *seq, int val)
|
2022-05-18 21:43:14 +02:00
|
|
|
{
|
2022-06-29 12:45:59 +02:00
|
|
|
const float right_handle_orig_frame = SEQ_time_right_handle_frame_get(scene, seq);
|
|
|
|
|
|
|
|
|
|
if (val >= right_handle_orig_frame) {
|
|
|
|
|
val = right_handle_orig_frame - 1;
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-18 21:43:14 +02:00
|
|
|
seq->startofs = val - seq->start;
|
2022-06-02 01:39:40 +02:00
|
|
|
seq->startdisp = val; /* Only to make files usable in older versions. */
|
2022-06-29 12:45:59 +02:00
|
|
|
|
2022-06-02 01:39:40 +02:00
|
|
|
SEQ_time_update_meta_strip_range(scene, seq_sequence_lookup_meta_by_seq(scene, seq));
|
|
|
|
|
seq_time_update_effects_strip_range(scene, seq_sequence_lookup_effects_by_seq(scene, seq));
|
2022-05-18 21:43:14 +02:00
|
|
|
}
|
|
|
|
|
|
2022-06-02 01:39:40 +02:00
|
|
|
void SEQ_time_right_handle_frame_set(const Scene *scene, Sequence *seq, int val)
|
2022-05-18 21:43:14 +02:00
|
|
|
{
|
2022-06-29 12:45:59 +02:00
|
|
|
const float strip_content_end_frame = seq->start + SEQ_time_strip_length_get(scene, seq);
|
|
|
|
|
const float left_handle_orig_frame = SEQ_time_left_handle_frame_get(scene, seq);
|
|
|
|
|
|
|
|
|
|
if (val <= left_handle_orig_frame) {
|
|
|
|
|
val = left_handle_orig_frame + 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
seq->endofs = strip_content_end_frame - val;
|
2022-06-02 01:39:40 +02:00
|
|
|
seq->enddisp = val; /* Only to make files usable in older versions. */
|
2022-06-29 12:45:59 +02:00
|
|
|
|
2022-06-02 01:39:40 +02:00
|
|
|
SEQ_time_update_meta_strip_range(scene, seq_sequence_lookup_meta_by_seq(scene, seq));
|
|
|
|
|
seq_time_update_effects_strip_range(scene, seq_sequence_lookup_effects_by_seq(scene, seq));
|
2022-05-18 21:43:14 +02:00
|
|
|
}
|