2023-05-31 16:19:06 +02:00
|
|
|
/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
|
2023-08-16 00:20:26 +10:00
|
|
|
* SPDX-FileCopyrightText: 2003-2009 Blender Authors
|
2023-05-31 16:19:06 +02:00
|
|
|
* SPDX-FileCopyrightText: 2005-2006 Peter Schlaile <peter [at] schlaile [dot] de>
|
|
|
|
|
*
|
|
|
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
2008-12-15 05:21:44 +00:00
|
|
|
|
2019-02-18 08:08:12 +11:00
|
|
|
/** \file
|
|
|
|
|
* \ingroup bke
|
2011-02-27 20:40:57 +00:00
|
|
|
*/
|
|
|
|
|
|
2025-03-31 18:59:22 +02:00
|
|
|
#define DNA_DEPRECATED_ALLOW
|
|
|
|
|
|
2024-10-08 22:28:36 +02:00
|
|
|
#include "BKE_duplilist.hh"
|
|
|
|
|
#include "BLI_assert.h"
|
|
|
|
|
#include "BLI_map.hh"
|
|
|
|
|
#include "DNA_listBase.h"
|
2025-03-20 18:11:08 +01:00
|
|
|
#include "SEQ_transform.hh"
|
2024-10-08 22:28:36 +02:00
|
|
|
#include <cstddef>
|
2021-08-20 16:30:34 +02:00
|
|
|
|
2008-12-15 05:21:44 +00:00
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
|
|
2020-03-19 09:33:03 +01:00
|
|
|
#include "DNA_scene_types.h"
|
|
|
|
|
#include "DNA_sequence_types.h"
|
2021-08-20 16:30:34 +02:00
|
|
|
#include "DNA_sound_types.h"
|
2009-01-12 19:02:08 +00:00
|
|
|
|
2020-03-19 09:33:03 +01:00
|
|
|
#include "BLI_listbase.h"
|
2024-09-26 21:13:39 +10:00
|
|
|
#include "BLI_path_utils.hh"
|
2015-04-06 10:40:12 -03:00
|
|
|
|
2024-03-05 18:39:08 +01:00
|
|
|
#include "BKE_fcurve.hh"
|
2024-03-26 12:57:30 -04:00
|
|
|
#include "BKE_idprop.hh"
|
2024-01-15 12:44:04 -05:00
|
|
|
#include "BKE_lib_id.hh"
|
2023-12-01 19:43:16 +01:00
|
|
|
#include "BKE_main.hh"
|
2024-02-10 19:16:25 +01:00
|
|
|
#include "BKE_scene.hh"
|
2020-11-16 05:02:30 +01:00
|
|
|
#include "BKE_sound.h"
|
2011-01-07 19:18:31 +00:00
|
|
|
|
2023-09-22 03:18:17 +02:00
|
|
|
#include "DEG_depsgraph.hh"
|
2008-12-15 05:21:44 +00:00
|
|
|
|
2024-12-20 13:23:08 +01:00
|
|
|
#include "MOV_read.hh"
|
|
|
|
|
|
2023-11-02 01:05:06 +01:00
|
|
|
#include "SEQ_channels.hh"
|
2024-08-22 14:54:42 +02:00
|
|
|
#include "SEQ_connect.hh"
|
2023-11-02 01:05:06 +01:00
|
|
|
#include "SEQ_edit.hh"
|
|
|
|
|
#include "SEQ_effects.hh"
|
|
|
|
|
#include "SEQ_iterator.hh"
|
|
|
|
|
#include "SEQ_modifier.hh"
|
|
|
|
|
#include "SEQ_proxy.hh"
|
|
|
|
|
#include "SEQ_relations.hh"
|
VSE: Improve retiming UI
Currently retiming is quite awkward, when you need to retime multiple
strips strips in sync. It is possible to use meta strips, but this is
still not great. This is resolved by implementing selection.
General changes:
Gizmos are removed, since they are designed to operate only on active
strip and don't support selection.
Transform operator code is implemented for retiming data, which allows
more sophisticated manipulation.
Instead of drawing marker-like symbols, keyframes are drawn to
represent retiming data. Retiming handles are now called keys. To have
consistent names, DNA structures have been renamed.
Retiming data is drawn on strip as overlay.
UI changes:
Retiming tool is removed. To edit retiming data, press Ctrl + R, select
a key and move it. When retiming is edited, retiming menu and
context menu shows more relevant features, like making transitions.
Strip and retiming key selection can not be combined. It is possible to
use box select operator to select keys, if any key is selected.
Otherwise strips are selected.
Adding retiming keys is possible with I shortcut or from menu.
Retiming keys are always drawn at strip left and right boundary. These
keys do not really exist until they are selected. This is to simplify
retiming of strips that are resized. These keys are called "fake keys"
in code.
API changes:
Functions, properties and types related to retiming handles are renamed
to retiming keys:
retiming_handle_add() -> retiming_key_add()
retiming_handle_move() -> retiming_key_move()
retiming_handle_remove() -> retiming_key_remove()
retiming_handles -> retiming_keys
RetimingHandle -> RetimingKey
Retiming editing "mode" is activated by setting `Sequence.show_retiming_keys`.
Pull Request: https://projects.blender.org/blender/blender/pulls/109044
2023-09-27 01:45:59 +02:00
|
|
|
#include "SEQ_retiming.hh"
|
2023-11-02 01:05:06 +01:00
|
|
|
#include "SEQ_select.hh"
|
|
|
|
|
#include "SEQ_sequencer.hh"
|
|
|
|
|
#include "SEQ_sound.hh"
|
VSE: Faster and more consistent thumbnails
Implementing part of design outlined in #126087.
- VSE thumbnail cache has a new implementation, hopefully simpler
and easier to understand.
- Instead of cache key being a VSE strip, frame index, plus
complicated logic for cache items linking etc.,
- The cache is keyed by media file path (if multiple strips
use the same input file, they will share cache entries), frame
index within media file, and any extra data (e.g. steam index
for multi-steam videos)
- Much reduced cache flickering and strange/weird thumbnail choices.
- Likewise, thumbnails no longer disappear-and-reload on operations
like Undo, dragging new video strip into timeline, or F12 render.
- Thumbnails now load faster.
- Images use dedicated/faster thumbnail loading routines when a
format can do that (e.g. JPG and EXR can).
- Movies reuse ffmpeg decoding context for neighboring strips
that use the same file (as often happens when cutting footage)
- Thumbnail requests are processed on several threads now too.
Images and more detail in PR.
Pull Request: https://projects.blender.org/blender/blender/pulls/126405
2024-08-29 08:27:12 +02:00
|
|
|
#include "SEQ_thumbnail_cache.hh"
|
2023-11-02 01:05:06 +01:00
|
|
|
#include "SEQ_time.hh"
|
|
|
|
|
#include "SEQ_utils.hh"
|
2017-10-25 11:02:52 -02:00
|
|
|
|
2023-08-28 15:01:05 +02:00
|
|
|
#include "BLO_read_write.hh"
|
2021-08-20 16:30:34 +02:00
|
|
|
|
2023-11-02 01:05:06 +01:00
|
|
|
#include "image_cache.hh"
|
|
|
|
|
#include "prefetch.hh"
|
|
|
|
|
#include "sequencer.hh"
|
|
|
|
|
#include "utils.hh"
|
2009-08-09 21:16:39 +00:00
|
|
|
|
2025-03-06 06:22:14 +01:00
|
|
|
namespace blender::seq {
|
|
|
|
|
|
2020-11-16 05:02:30 +01:00
|
|
|
/* -------------------------------------------------------------------- */
|
2020-11-16 16:48:41 +11:00
|
|
|
/** \name Allocate / Free Functions
|
2020-11-16 05:02:30 +01:00
|
|
|
* \{ */
|
2009-12-18 13:28:03 +00:00
|
|
|
|
2023-07-20 20:11:08 +10:00
|
|
|
StripProxy *seq_strip_proxy_alloc()
|
2022-01-25 17:05:33 +01:00
|
|
|
{
|
2025-03-10 17:16:43 +01:00
|
|
|
StripProxy *strip_proxy = MEM_callocN<StripProxy>("StripProxy");
|
2022-01-25 17:05:33 +01:00
|
|
|
strip_proxy->quality = 50;
|
2024-05-06 17:56:56 +02:00
|
|
|
strip_proxy->build_tc_flags = SEQ_PROXY_TC_RECORD_RUN | SEQ_PROXY_TC_RECORD_RUN_NO_GAPS;
|
2022-01-25 17:05:33 +01:00
|
|
|
strip_proxy->tc = SEQ_PROXY_TC_RECORD_RUN;
|
|
|
|
|
return strip_proxy;
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-20 18:02:31 +01:00
|
|
|
static StripData *seq_strip_alloc(int type)
|
2009-12-18 13:28:03 +00:00
|
|
|
{
|
2025-03-10 17:16:43 +01:00
|
|
|
StripData *data = MEM_callocN<StripData>("strip");
|
2010-07-06 16:44:05 +00:00
|
|
|
|
2025-01-07 16:10:36 +01:00
|
|
|
if (type != STRIP_TYPE_SOUND_RAM) {
|
2025-03-10 17:16:43 +01:00
|
|
|
data->transform = MEM_callocN<StripTransform>("StripTransform");
|
2024-12-20 18:02:31 +01:00
|
|
|
data->transform->scale_x = 1;
|
|
|
|
|
data->transform->scale_y = 1;
|
|
|
|
|
data->transform->origin[0] = 0.5f;
|
|
|
|
|
data->transform->origin[1] = 0.5f;
|
|
|
|
|
data->transform->filter = SEQ_TRANSFORM_FILTER_AUTO;
|
2025-03-10 17:16:43 +01:00
|
|
|
data->crop = MEM_callocN<StripCrop>("StripCrop");
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2010-07-06 16:44:05 +00:00
|
|
|
|
2024-12-20 18:02:31 +01:00
|
|
|
data->us = 1;
|
|
|
|
|
return data;
|
2002-10-12 11:37:38 +00:00
|
|
|
}
|
|
|
|
|
|
2024-12-20 18:02:31 +01:00
|
|
|
static void seq_free_strip(StripData *data)
|
2008-12-15 05:21:44 +00:00
|
|
|
{
|
2024-12-20 18:02:31 +01:00
|
|
|
data->us--;
|
|
|
|
|
if (data->us > 0) {
|
2012-08-08 11:15:36 +00:00
|
|
|
return;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2024-12-20 18:02:31 +01:00
|
|
|
if (data->us < 0) {
|
2008-12-15 05:21:44 +00:00
|
|
|
printf("error: negative users in strip\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-20 18:02:31 +01:00
|
|
|
if (data->stripdata) {
|
|
|
|
|
MEM_freeN(data->stripdata);
|
2008-12-15 05:21:44 +00:00
|
|
|
}
|
|
|
|
|
|
2024-12-20 18:02:31 +01:00
|
|
|
if (data->proxy) {
|
|
|
|
|
if (data->proxy->anim) {
|
|
|
|
|
MOV_close(data->proxy->anim);
|
2009-06-08 20:08:19 +00:00
|
|
|
}
|
|
|
|
|
|
2024-12-20 18:02:31 +01:00
|
|
|
MEM_freeN(data->proxy);
|
2008-12-15 05:21:44 +00:00
|
|
|
}
|
2024-12-20 18:02:31 +01:00
|
|
|
if (data->crop) {
|
|
|
|
|
MEM_freeN(data->crop);
|
2008-12-15 05:21:44 +00:00
|
|
|
}
|
2024-12-20 18:02:31 +01:00
|
|
|
if (data->transform) {
|
|
|
|
|
MEM_freeN(data->transform);
|
2008-12-15 05:21:44 +00:00
|
|
|
}
|
|
|
|
|
|
2024-12-20 18:02:31 +01:00
|
|
|
MEM_freeN(data);
|
2008-12-15 05:21:44 +00:00
|
|
|
}
|
|
|
|
|
|
2025-03-06 13:04:39 +01:00
|
|
|
Strip *sequence_alloc(ListBase *lb, int timeline_frame, int machine, int type)
|
2020-11-16 05:02:30 +01:00
|
|
|
{
|
2025-01-07 14:09:45 +01:00
|
|
|
Strip *strip;
|
2020-11-16 05:02:30 +01:00
|
|
|
|
2025-03-10 17:16:43 +01:00
|
|
|
strip = MEM_callocN<Strip>("addseq");
|
2025-01-07 14:09:45 +01:00
|
|
|
BLI_addtail(lb, strip);
|
2020-11-16 05:02:30 +01:00
|
|
|
|
2025-01-07 14:09:45 +01:00
|
|
|
*((short *)strip->name) = ID_SEQ;
|
|
|
|
|
strip->name[2] = 0;
|
2020-11-16 05:02:30 +01:00
|
|
|
|
2025-01-07 14:09:45 +01:00
|
|
|
strip->flag = SELECT;
|
|
|
|
|
strip->start = timeline_frame;
|
2025-03-20 18:11:08 +01:00
|
|
|
strip_channel_set(strip, machine);
|
2025-01-07 14:09:45 +01:00
|
|
|
strip->sat = 1.0;
|
|
|
|
|
strip->mul = 1.0;
|
|
|
|
|
strip->blend_opacity = 100.0;
|
|
|
|
|
strip->volume = 1.0f;
|
|
|
|
|
strip->scene_sound = nullptr;
|
|
|
|
|
strip->type = type;
|
|
|
|
|
strip->media_playback_rate = 0.0f;
|
|
|
|
|
strip->speed_factor = 1.0f;
|
2022-05-23 23:05:54 +02:00
|
|
|
|
2025-01-07 16:10:36 +01:00
|
|
|
if (strip->type == STRIP_TYPE_ADJUSTMENT) {
|
|
|
|
|
strip->blend_mode = STRIP_TYPE_CROSS;
|
2022-05-23 23:05:54 +02:00
|
|
|
}
|
|
|
|
|
else {
|
2025-01-07 16:10:36 +01:00
|
|
|
strip->blend_mode = STRIP_TYPE_ALPHAOVER;
|
2022-05-23 23:05:54 +02:00
|
|
|
}
|
2020-11-16 05:02:30 +01:00
|
|
|
|
2025-01-07 14:09:45 +01:00
|
|
|
strip->data = seq_strip_alloc(type);
|
2025-03-10 17:16:43 +01:00
|
|
|
strip->stereo3d_format = MEM_callocN<Stereo3dFormat>("Sequence Stereo Format");
|
2020-11-16 05:02:30 +01:00
|
|
|
|
2025-01-07 16:05:12 +01:00
|
|
|
strip->color_tag = STRIP_COLOR_NONE;
|
2021-09-29 14:29:32 +02:00
|
|
|
|
2025-01-07 16:10:36 +01:00
|
|
|
if (strip->type == STRIP_TYPE_META) {
|
2025-03-06 13:04:39 +01:00
|
|
|
channels_ensure(&strip->channels);
|
2022-04-04 12:52:48 +02:00
|
|
|
}
|
|
|
|
|
|
2025-03-06 13:04:39 +01:00
|
|
|
relations_session_uid_generate(strip);
|
2020-11-16 05:02:30 +01:00
|
|
|
|
2025-01-07 14:09:45 +01:00
|
|
|
return strip;
|
2020-11-16 05:02:30 +01:00
|
|
|
}
|
|
|
|
|
|
2012-09-06 09:23:38 +00:00
|
|
|
/* only give option to skip cache locally (static func) */
|
2020-12-19 05:57:27 +01:00
|
|
|
static void seq_sequence_free_ex(Scene *scene,
|
2025-01-07 14:09:45 +01:00
|
|
|
Strip *strip,
|
2018-05-11 11:21:30 +02:00
|
|
|
const bool do_cache,
|
2022-01-19 14:12:23 +01:00
|
|
|
const bool do_id_user)
|
2008-12-15 05:21:44 +00:00
|
|
|
{
|
2025-01-07 14:09:45 +01:00
|
|
|
if (strip->data) {
|
|
|
|
|
seq_free_strip(strip->data);
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2008-12-15 05:21:44 +00:00
|
|
|
|
2025-03-06 13:04:39 +01:00
|
|
|
relations_sequence_free_anim(strip);
|
2009-08-09 21:16:39 +00:00
|
|
|
|
2025-01-07 16:10:36 +01:00
|
|
|
if (strip->type & STRIP_TYPE_EFFECT) {
|
2025-03-06 13:04:39 +01:00
|
|
|
EffectHandle sh = effect_handle_get(strip);
|
2025-01-07 14:09:45 +01:00
|
|
|
sh.free(strip, do_id_user);
|
2009-07-08 17:41:45 +00:00
|
|
|
}
|
2008-12-15 05:21:44 +00:00
|
|
|
|
2025-01-07 14:09:45 +01:00
|
|
|
if (strip->sound && do_id_user) {
|
|
|
|
|
id_us_min((ID *)strip->sound);
|
2011-05-16 17:14:47 +00:00
|
|
|
}
|
|
|
|
|
|
2025-01-07 14:09:45 +01:00
|
|
|
if (strip->stereo3d_format) {
|
|
|
|
|
MEM_freeN(strip->stereo3d_format);
|
2015-04-06 10:40:12 -03:00
|
|
|
}
|
|
|
|
|
|
2012-12-17 08:45:44 +00:00
|
|
|
/* clipboard has no scene and will never have a sound handle or be active
|
|
|
|
|
* same goes to sequences copy for proxy rebuild job
|
|
|
|
|
*/
|
2012-03-24 06:18:31 +00:00
|
|
|
if (scene) {
|
2009-12-17 16:28:45 +00:00
|
|
|
Editing *ed = scene->ed;
|
|
|
|
|
|
2025-01-07 14:09:45 +01:00
|
|
|
if (ed->act_seq == strip) {
|
2023-07-20 09:46:24 +02:00
|
|
|
ed->act_seq = nullptr;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2009-12-17 16:28:45 +00:00
|
|
|
|
2025-01-07 16:10:36 +01:00
|
|
|
if (strip->scene_sound && ELEM(strip->type, STRIP_TYPE_SOUND_RAM, STRIP_TYPE_SCENE)) {
|
2025-01-07 14:09:45 +01:00
|
|
|
BKE_sound_remove_scene_sound(scene, strip->scene_sound);
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2010-07-13 09:31:28 +00:00
|
|
|
}
|
2010-07-03 21:13:08 +00:00
|
|
|
|
2025-01-07 14:09:45 +01:00
|
|
|
if (strip->prop) {
|
|
|
|
|
IDP_FreePropertyContent_ex(strip->prop, do_id_user);
|
|
|
|
|
MEM_freeN(strip->prop);
|
2015-04-02 21:05:12 +11:00
|
|
|
}
|
|
|
|
|
|
2012-08-19 15:41:56 +00:00
|
|
|
/* free modifiers */
|
2025-03-06 13:04:39 +01:00
|
|
|
modifier_clear(strip);
|
2012-08-19 15:41:56 +00:00
|
|
|
|
2025-03-06 13:04:39 +01:00
|
|
|
if (is_strip_connected(strip)) {
|
|
|
|
|
disconnect(strip);
|
2024-08-22 14:54:42 +02:00
|
|
|
}
|
|
|
|
|
|
2012-08-27 09:01:36 +00:00
|
|
|
/* free cached data used by this strip,
|
|
|
|
|
* also invalidate cache for all dependent sequences
|
2012-09-06 04:45:25 +00:00
|
|
|
*
|
|
|
|
|
* be _very_ careful here, invalidating cache loops over the scene sequences and
|
2019-04-27 12:07:07 +10:00
|
|
|
* assumes the listbase is valid for all strips,
|
|
|
|
|
* this may not be the case if lists are being freed.
|
2020-12-19 05:57:27 +01:00
|
|
|
* this is optional SEQ_relations_invalidate_cache
|
2012-08-27 09:01:36 +00:00
|
|
|
*/
|
2012-09-06 04:45:25 +00:00
|
|
|
if (do_cache) {
|
|
|
|
|
if (scene) {
|
2025-03-06 13:04:39 +01:00
|
|
|
relations_invalidate_cache_raw(scene, strip);
|
2012-09-06 04:45:25 +00:00
|
|
|
}
|
|
|
|
|
}
|
2025-01-07 16:10:36 +01:00
|
|
|
if (strip->type == STRIP_TYPE_META) {
|
2025-03-06 13:04:39 +01:00
|
|
|
channels_free(&strip->channels);
|
2022-04-04 12:52:48 +02:00
|
|
|
}
|
2012-08-12 18:24:01 +00:00
|
|
|
|
2025-01-07 14:09:45 +01:00
|
|
|
if (strip->retiming_keys != nullptr) {
|
|
|
|
|
MEM_freeN(strip->retiming_keys);
|
|
|
|
|
strip->retiming_keys = nullptr;
|
|
|
|
|
strip->retiming_keys_num = 0;
|
2023-06-14 04:47:53 +02:00
|
|
|
}
|
|
|
|
|
|
2025-01-07 14:09:45 +01:00
|
|
|
MEM_freeN(strip);
|
2008-12-15 05:21:44 +00:00
|
|
|
}
|
|
|
|
|
|
2025-03-06 13:04:39 +01:00
|
|
|
void sequence_free(Scene *scene, Strip *strip)
|
2012-09-06 09:23:38 +00:00
|
|
|
{
|
2025-01-07 14:09:45 +01:00
|
|
|
seq_sequence_free_ex(scene, strip, true, true);
|
2012-09-06 09:23:38 +00:00
|
|
|
}
|
|
|
|
|
|
2025-01-07 14:09:45 +01:00
|
|
|
void seq_free_sequence_recurse(Scene *scene, Strip *strip, const bool do_id_user)
|
== Sequencer ==
This patch adds:
* support for proxy building again (missing feature from Blender 2.49)
additionally to the way, Blender 2.49 worked, you can select several
strips at once and make Blender build proxies in the background (using
the job system)
Also a new thing: movie proxies are now build into AVI files, and
the proxy system is moved into ImBuf-library, so that other parts
of blender can also benefit from it.
* Timecode support: to fix seeking issues with files, that have
a) varying frame rates
b) very large GOP lengths
c) are broken inbetween
d) use different time code tracks
the proxy builder can now also build timecode indices, which are
used (optionally) for seeking.
For the first time, it is possible, to do frame exact seeking on
all file types.
* Support for different video-streams in one video file (can be
selected in sequencer, other parts of blender can also use it,
but UI has to be added accordingly)
* IMPORTANT: this patch *requires* ffmpeg 0.7 or newer, since
older versions don't support the pkt_pts field, that is essential
for building timecode indices.
Windows and Mac libs are already updated, Linux-users have to build
their own ffmpeg verions until distros keep up.
2011-08-28 14:46:03 +00:00
|
|
|
{
|
2025-01-06 14:19:24 +01:00
|
|
|
Strip *iseq, *iseq_next;
|
== Sequencer ==
This patch adds:
* support for proxy building again (missing feature from Blender 2.49)
additionally to the way, Blender 2.49 worked, you can select several
strips at once and make Blender build proxies in the background (using
the job system)
Also a new thing: movie proxies are now build into AVI files, and
the proxy system is moved into ImBuf-library, so that other parts
of blender can also benefit from it.
* Timecode support: to fix seeking issues with files, that have
a) varying frame rates
b) very large GOP lengths
c) are broken inbetween
d) use different time code tracks
the proxy builder can now also build timecode indices, which are
used (optionally) for seeking.
For the first time, it is possible, to do frame exact seeking on
all file types.
* Support for different video-streams in one video file (can be
selected in sequencer, other parts of blender can also use it,
but UI has to be added accordingly)
* IMPORTANT: this patch *requires* ffmpeg 0.7 or newer, since
older versions don't support the pkt_pts field, that is essential
for building timecode indices.
Windows and Mac libs are already updated, Linux-users have to build
their own ffmpeg verions until distros keep up.
2011-08-28 14:46:03 +00:00
|
|
|
|
2025-01-07 14:09:45 +01:00
|
|
|
for (iseq = static_cast<Strip *>(strip->seqbase.first); iseq; iseq = iseq_next) {
|
2020-11-16 05:02:30 +01:00
|
|
|
iseq_next = iseq->next;
|
2022-01-19 14:12:23 +01:00
|
|
|
seq_free_sequence_recurse(scene, iseq, do_id_user);
|
2015-04-06 10:40:12 -03:00
|
|
|
}
|
|
|
|
|
|
2025-01-07 14:09:45 +01:00
|
|
|
seq_sequence_free_ex(scene, strip, false, do_id_user);
|
2020-11-16 05:02:30 +01:00
|
|
|
}
|
2015-04-06 10:40:12 -03:00
|
|
|
|
2025-03-06 13:04:39 +01:00
|
|
|
Editing *editing_get(const Scene *scene)
|
2020-11-16 05:02:30 +01:00
|
|
|
{
|
|
|
|
|
return scene->ed;
|
|
|
|
|
}
|
2019-09-29 16:17:48 -07:00
|
|
|
|
2025-03-06 13:04:39 +01:00
|
|
|
Editing *editing_ensure(Scene *scene)
|
2020-11-16 05:02:30 +01:00
|
|
|
{
|
2023-07-20 09:46:24 +02:00
|
|
|
if (scene->ed == nullptr) {
|
2020-11-16 05:02:30 +01:00
|
|
|
Editing *ed;
|
2015-04-06 10:40:12 -03:00
|
|
|
|
2025-03-10 17:16:43 +01:00
|
|
|
ed = scene->ed = MEM_callocN<Editing>("addseq");
|
2020-11-16 05:02:30 +01:00
|
|
|
ed->seqbasep = &ed->seqbase;
|
2023-07-20 09:46:24 +02:00
|
|
|
ed->cache = nullptr;
|
2024-05-02 16:36:11 +02:00
|
|
|
ed->cache_flag = (SEQ_CACHE_STORE_FINAL_OUT | SEQ_CACHE_STORE_RAW);
|
2024-04-24 19:54:44 +02:00
|
|
|
ed->show_missing_media_flag = SEQ_EDIT_SHOW_MISSING_MEDIA;
|
2022-04-04 16:27:37 +02:00
|
|
|
ed->displayed_channels = &ed->channels;
|
2025-03-06 13:04:39 +01:00
|
|
|
channels_ensure(ed->displayed_channels);
|
2015-04-06 10:40:12 -03:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-11-16 05:02:30 +01:00
|
|
|
return scene->ed;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2025-03-06 13:04:39 +01:00
|
|
|
void editing_free(Scene *scene, const bool do_id_user)
|
2020-11-16 05:02:30 +01:00
|
|
|
{
|
|
|
|
|
Editing *ed = scene->ed;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-07-20 09:46:24 +02:00
|
|
|
if (ed == nullptr) {
|
2020-11-16 05:02:30 +01:00
|
|
|
return;
|
2016-01-08 18:30:26 +13:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-12-19 05:57:27 +01:00
|
|
|
seq_prefetch_free(scene);
|
|
|
|
|
seq_cache_destruct(scene);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-08-20 16:30:34 +02:00
|
|
|
/* handle cache freeing above */
|
2025-01-07 14:09:45 +01:00
|
|
|
LISTBASE_FOREACH_MUTABLE (Strip *, strip, &ed->seqbase) {
|
|
|
|
|
seq_free_sequence_recurse(scene, strip, do_id_user);
|
2020-11-16 05:02:30 +01:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-11-16 05:02:30 +01:00
|
|
|
BLI_freelistN(&ed->metastack);
|
2025-03-06 13:04:39 +01:00
|
|
|
strip_lookup_free(ed);
|
2024-04-24 19:54:44 +02:00
|
|
|
blender::seq::media_presence_free(scene);
|
VSE: Faster and more consistent thumbnails
Implementing part of design outlined in #126087.
- VSE thumbnail cache has a new implementation, hopefully simpler
and easier to understand.
- Instead of cache key being a VSE strip, frame index, plus
complicated logic for cache items linking etc.,
- The cache is keyed by media file path (if multiple strips
use the same input file, they will share cache entries), frame
index within media file, and any extra data (e.g. steam index
for multi-steam videos)
- Much reduced cache flickering and strange/weird thumbnail choices.
- Likewise, thumbnails no longer disappear-and-reload on operations
like Undo, dragging new video strip into timeline, or F12 render.
- Thumbnails now load faster.
- Images use dedicated/faster thumbnail loading routines when a
format can do that (e.g. JPG and EXR can).
- Movies reuse ffmpeg decoding context for neighboring strips
that use the same file (as often happens when cutting footage)
- Thumbnail requests are processed on several threads now too.
Images and more detail in PR.
Pull Request: https://projects.blender.org/blender/blender/pulls/126405
2024-08-29 08:27:12 +02:00
|
|
|
blender::seq::thumbnail_cache_destroy(scene);
|
2025-03-06 13:04:39 +01:00
|
|
|
channels_free(&ed->channels);
|
VSE: Improve retiming UI
Currently retiming is quite awkward, when you need to retime multiple
strips strips in sync. It is possible to use meta strips, but this is
still not great. This is resolved by implementing selection.
General changes:
Gizmos are removed, since they are designed to operate only on active
strip and don't support selection.
Transform operator code is implemented for retiming data, which allows
more sophisticated manipulation.
Instead of drawing marker-like symbols, keyframes are drawn to
represent retiming data. Retiming handles are now called keys. To have
consistent names, DNA structures have been renamed.
Retiming data is drawn on strip as overlay.
UI changes:
Retiming tool is removed. To edit retiming data, press Ctrl + R, select
a key and move it. When retiming is edited, retiming menu and
context menu shows more relevant features, like making transitions.
Strip and retiming key selection can not be combined. It is possible to
use box select operator to select keys, if any key is selected.
Otherwise strips are selected.
Adding retiming keys is possible with I shortcut or from menu.
Retiming keys are always drawn at strip left and right boundary. These
keys do not really exist until they are selected. This is to simplify
retiming of strips that are resized. These keys are called "fake keys"
in code.
API changes:
Functions, properties and types related to retiming handles are renamed
to retiming keys:
retiming_handle_add() -> retiming_key_add()
retiming_handle_move() -> retiming_key_move()
retiming_handle_remove() -> retiming_key_remove()
retiming_handles -> retiming_keys
RetimingHandle -> RetimingKey
Retiming editing "mode" is activated by setting `Sequence.show_retiming_keys`.
Pull Request: https://projects.blender.org/blender/blender/pulls/109044
2023-09-27 01:45:59 +02:00
|
|
|
|
2020-11-16 05:02:30 +01:00
|
|
|
MEM_freeN(ed);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-07-20 09:46:24 +02:00
|
|
|
scene->ed = nullptr;
|
2020-11-16 05:02:30 +01:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2025-01-07 14:09:45 +01:00
|
|
|
static void seq_new_fix_links_recursive(Strip *strip, blender::Map<Strip *, Strip *> strip_map)
|
2020-11-16 05:02:30 +01:00
|
|
|
{
|
2025-01-07 16:10:36 +01:00
|
|
|
if (strip->type & STRIP_TYPE_EFFECT) {
|
2025-01-07 14:09:45 +01:00
|
|
|
strip->seq1 = strip_map.lookup_default(strip->seq1, strip->seq1);
|
|
|
|
|
strip->seq2 = strip_map.lookup_default(strip->seq2, strip->seq2);
|
2009-11-14 19:26:58 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2025-01-07 14:09:45 +01:00
|
|
|
LISTBASE_FOREACH (SequenceModifierData *, smd, &strip->modifiers) {
|
2024-10-08 22:28:36 +02:00
|
|
|
smd->mask_sequence = strip_map.lookup_default(smd->mask_sequence, smd->mask_sequence);
|
2020-11-16 05:02:30 +01:00
|
|
|
}
|
2024-08-22 14:54:42 +02:00
|
|
|
|
2025-03-06 13:04:39 +01:00
|
|
|
if (is_strip_connected(strip)) {
|
2025-01-13 18:16:48 +01:00
|
|
|
LISTBASE_FOREACH (StripConnection *, con, &strip->connections) {
|
|
|
|
|
con->strip_ref = strip_map.lookup_default(con->strip_ref, con->strip_ref);
|
2024-10-08 22:28:36 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-07 16:10:36 +01:00
|
|
|
if (strip->type == STRIP_TYPE_META) {
|
2025-01-07 14:09:45 +01:00
|
|
|
LISTBASE_FOREACH (Strip *, seqn, &strip->seqbase) {
|
2024-10-08 22:28:36 +02:00
|
|
|
seq_new_fix_links_recursive(seqn, strip_map);
|
2024-08-22 14:54:42 +02:00
|
|
|
}
|
|
|
|
|
}
|
2009-11-14 19:26:58 +00:00
|
|
|
}
|
2020-12-16 20:34:26 +01:00
|
|
|
|
2025-03-06 13:04:39 +01:00
|
|
|
SequencerToolSettings *tool_settings_init()
|
2020-12-16 20:34:26 +01:00
|
|
|
{
|
2025-03-10 17:16:43 +01:00
|
|
|
SequencerToolSettings *tool_settings = MEM_callocN<SequencerToolSettings>(
|
|
|
|
|
"Sequencer tool settings");
|
2020-12-16 20:34:26 +01:00
|
|
|
tool_settings->fit_method = SEQ_SCALE_TO_FIT;
|
2021-07-01 11:02:30 +10:00
|
|
|
tool_settings->snap_mode = SEQ_SNAP_TO_STRIPS | SEQ_SNAP_TO_CURRENT_FRAME |
|
2024-11-06 05:43:34 +01:00
|
|
|
SEQ_SNAP_TO_STRIP_HOLD | SEQ_SNAP_TO_MARKERS | SEQ_SNAP_TO_RETIMING |
|
2024-07-06 15:24:52 +02:00
|
|
|
SEQ_SNAP_TO_PREVIEW_BORDERS | SEQ_SNAP_TO_PREVIEW_CENTER |
|
|
|
|
|
SEQ_SNAP_TO_STRIPS_PREVIEW;
|
2021-06-29 20:12:19 +02:00
|
|
|
tool_settings->snap_distance = 15;
|
2021-08-27 12:59:46 +02:00
|
|
|
tool_settings->overlap_mode = SEQ_OVERLAP_SHUFFLE;
|
2021-09-21 09:38:30 +02:00
|
|
|
tool_settings->pivot_point = V3D_AROUND_LOCAL_ORIGINS;
|
2021-08-27 12:59:46 +02:00
|
|
|
|
2020-12-16 20:34:26 +01:00
|
|
|
return tool_settings;
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-06 13:04:39 +01:00
|
|
|
SequencerToolSettings *tool_settings_ensure(Scene *scene)
|
2021-05-25 15:02:31 +02:00
|
|
|
{
|
|
|
|
|
SequencerToolSettings *tool_settings = scene->toolsettings->sequencer_tool_settings;
|
2023-07-20 09:46:24 +02:00
|
|
|
if (tool_settings == nullptr) {
|
2025-03-06 13:04:39 +01:00
|
|
|
scene->toolsettings->sequencer_tool_settings = tool_settings_init();
|
2021-05-25 15:02:31 +02:00
|
|
|
tool_settings = scene->toolsettings->sequencer_tool_settings;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return tool_settings;
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-06 13:04:39 +01:00
|
|
|
void tool_settings_free(SequencerToolSettings *tool_settings)
|
2020-12-16 20:34:26 +01:00
|
|
|
{
|
|
|
|
|
MEM_freeN(tool_settings);
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-06 13:04:39 +01:00
|
|
|
eSeqImageFitMethod tool_settings_fit_method_get(Scene *scene)
|
2020-12-16 20:34:26 +01:00
|
|
|
{
|
2025-03-06 13:04:39 +01:00
|
|
|
const SequencerToolSettings *tool_settings = tool_settings_ensure(scene);
|
2023-07-20 09:46:24 +02:00
|
|
|
return eSeqImageFitMethod(tool_settings->fit_method);
|
2020-12-16 20:34:26 +01:00
|
|
|
}
|
|
|
|
|
|
2025-03-06 13:04:39 +01:00
|
|
|
short tool_settings_snap_mode_get(Scene *scene)
|
2021-06-29 20:12:19 +02:00
|
|
|
{
|
2025-03-06 13:04:39 +01:00
|
|
|
const SequencerToolSettings *tool_settings = tool_settings_ensure(scene);
|
2021-06-29 20:12:19 +02:00
|
|
|
return tool_settings->snap_mode;
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-06 13:04:39 +01:00
|
|
|
short tool_settings_snap_flag_get(Scene *scene)
|
2021-06-29 20:12:19 +02:00
|
|
|
{
|
2025-03-06 13:04:39 +01:00
|
|
|
const SequencerToolSettings *tool_settings = tool_settings_ensure(scene);
|
2021-06-29 20:12:19 +02:00
|
|
|
return tool_settings->snap_flag;
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-06 13:04:39 +01:00
|
|
|
int tool_settings_snap_distance_get(Scene *scene)
|
2021-06-29 20:12:19 +02:00
|
|
|
{
|
2025-03-06 13:04:39 +01:00
|
|
|
const SequencerToolSettings *tool_settings = tool_settings_ensure(scene);
|
2021-06-29 20:12:19 +02:00
|
|
|
return tool_settings->snap_distance;
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-06 13:04:39 +01:00
|
|
|
void tool_settings_fit_method_set(Scene *scene, eSeqImageFitMethod fit_method)
|
2020-12-16 20:34:26 +01:00
|
|
|
{
|
2025-03-06 13:04:39 +01:00
|
|
|
SequencerToolSettings *tool_settings = tool_settings_ensure(scene);
|
2020-12-16 20:34:26 +01:00
|
|
|
tool_settings->fit_method = fit_method;
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-06 13:04:39 +01:00
|
|
|
eSeqOverlapMode tool_settings_overlap_mode_get(Scene *scene)
|
2021-08-27 12:59:46 +02:00
|
|
|
{
|
2025-03-06 13:04:39 +01:00
|
|
|
const SequencerToolSettings *tool_settings = tool_settings_ensure(scene);
|
2023-07-20 09:46:24 +02:00
|
|
|
return eSeqOverlapMode(tool_settings->overlap_mode);
|
2021-08-27 12:59:46 +02:00
|
|
|
}
|
|
|
|
|
|
2025-03-06 13:04:39 +01:00
|
|
|
int tool_settings_pivot_point_get(Scene *scene)
|
2021-09-21 09:38:30 +02:00
|
|
|
{
|
2025-03-06 13:04:39 +01:00
|
|
|
const SequencerToolSettings *tool_settings = tool_settings_ensure(scene);
|
2021-09-21 09:38:30 +02:00
|
|
|
return tool_settings->pivot_point;
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-06 13:04:39 +01:00
|
|
|
ListBase *active_seqbase_get(const Editing *ed)
|
2020-12-17 02:11:22 +01:00
|
|
|
{
|
2023-07-20 09:46:24 +02:00
|
|
|
if (ed == nullptr) {
|
|
|
|
|
return nullptr;
|
2020-12-17 02:11:22 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ed->seqbasep;
|
|
|
|
|
}
|
2021-03-02 12:34:03 +01:00
|
|
|
|
2025-03-06 13:04:39 +01:00
|
|
|
void seqbase_active_set(Editing *ed, ListBase *seqbase)
|
2021-03-02 12:34:03 +01:00
|
|
|
{
|
|
|
|
|
ed->seqbasep = seqbase;
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-07 16:03:11 +01:00
|
|
|
static MetaStack *seq_meta_stack_alloc(const Scene *scene, Strip *strip_meta)
|
2021-03-02 12:34:03 +01:00
|
|
|
{
|
2025-03-06 13:04:39 +01:00
|
|
|
Editing *ed = editing_get(scene);
|
2022-06-27 19:29:41 +02:00
|
|
|
|
2025-03-10 17:16:43 +01:00
|
|
|
MetaStack *ms = MEM_mallocN<MetaStack>("metastack");
|
2022-06-27 19:29:41 +02:00
|
|
|
BLI_addhead(&ed->metastack, ms);
|
2025-01-07 16:03:11 +01:00
|
|
|
ms->parseq = strip_meta;
|
2022-06-27 19:29:41 +02:00
|
|
|
|
|
|
|
|
/* Reference to previously displayed timeline data. */
|
2025-03-24 19:11:44 +01:00
|
|
|
Strip *higher_level_meta = lookup_meta_by_strip(ed, strip_meta);
|
2022-06-27 19:29:41 +02:00
|
|
|
ms->oldbasep = higher_level_meta ? &higher_level_meta->seqbase : &ed->seqbase;
|
|
|
|
|
ms->old_channels = higher_level_meta ? &higher_level_meta->channels : &ed->channels;
|
|
|
|
|
|
2025-03-06 13:04:39 +01:00
|
|
|
ms->disp_range[0] = time_left_handle_frame_get(scene, ms->parseq);
|
|
|
|
|
ms->disp_range[1] = time_right_handle_frame_get(scene, ms->parseq);
|
2021-03-02 12:34:03 +01:00
|
|
|
return ms;
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-06 13:04:39 +01:00
|
|
|
MetaStack *meta_stack_active_get(const Editing *ed)
|
2021-03-02 12:34:03 +01:00
|
|
|
{
|
2023-07-20 09:46:24 +02:00
|
|
|
if (ed == nullptr) {
|
|
|
|
|
return nullptr;
|
2021-12-20 02:15:23 +01:00
|
|
|
}
|
|
|
|
|
|
2023-07-20 09:46:24 +02:00
|
|
|
return static_cast<MetaStack *>(ed->metastack.last);
|
2021-03-02 12:34:03 +01:00
|
|
|
}
|
|
|
|
|
|
2025-03-06 13:04:39 +01:00
|
|
|
void meta_stack_set(const Scene *scene, Strip *dst_seq)
|
2022-06-27 19:29:41 +02:00
|
|
|
{
|
2025-03-06 13:04:39 +01:00
|
|
|
Editing *ed = editing_get(scene);
|
2022-06-27 19:29:41 +02:00
|
|
|
/* Clear metastack */
|
|
|
|
|
BLI_freelistN(&ed->metastack);
|
|
|
|
|
|
2023-07-20 09:46:24 +02:00
|
|
|
if (dst_seq != nullptr) {
|
2022-06-27 19:29:41 +02:00
|
|
|
/* Allocate meta stack in a way, that represents meta hierarchy in timeline. */
|
2022-09-02 20:30:23 +02:00
|
|
|
seq_meta_stack_alloc(scene, dst_seq);
|
2025-01-06 14:19:24 +01:00
|
|
|
Strip *meta_parent = dst_seq;
|
2025-03-24 19:11:44 +01:00
|
|
|
while ((meta_parent = lookup_meta_by_strip(ed, meta_parent))) {
|
2022-06-27 19:29:41 +02:00
|
|
|
seq_meta_stack_alloc(scene, meta_parent);
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-06 13:04:39 +01:00
|
|
|
seqbase_active_set(ed, &dst_seq->seqbase);
|
|
|
|
|
channels_displayed_set(ed, &dst_seq->channels);
|
2022-06-27 19:29:41 +02:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* Go to top level, exiting meta strip. */
|
2025-03-06 13:04:39 +01:00
|
|
|
seqbase_active_set(ed, &ed->seqbase);
|
|
|
|
|
channels_displayed_set(ed, &ed->channels);
|
2022-06-27 19:29:41 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-06 13:04:39 +01:00
|
|
|
Strip *meta_stack_pop(Editing *ed)
|
2022-06-27 19:29:41 +02:00
|
|
|
{
|
2025-03-06 13:04:39 +01:00
|
|
|
MetaStack *ms = meta_stack_active_get(ed);
|
2025-01-06 14:19:24 +01:00
|
|
|
Strip *meta_parent = ms->parseq;
|
2025-03-06 13:04:39 +01:00
|
|
|
seqbase_active_set(ed, ms->oldbasep);
|
|
|
|
|
channels_displayed_set(ed, ms->old_channels);
|
2022-06-27 19:29:41 +02:00
|
|
|
BLI_remlink(&ed->metastack, ms);
|
|
|
|
|
MEM_freeN(ms);
|
|
|
|
|
return meta_parent;
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-16 05:02:30 +01:00
|
|
|
/** \} */
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-11-16 05:02:30 +01:00
|
|
|
/* -------------------------------------------------------------------- */
|
2020-11-16 16:48:41 +11:00
|
|
|
/** \name Duplicate Functions
|
2020-11-16 05:02:30 +01:00
|
|
|
* \{ */
|
2021-12-14 15:49:31 +11:00
|
|
|
|
2025-01-07 16:03:11 +01:00
|
|
|
static Strip *strip_dupli(const Scene *scene_src,
|
|
|
|
|
Scene *scene_dst,
|
|
|
|
|
ListBase *new_seq_list,
|
|
|
|
|
Strip *strip,
|
|
|
|
|
int dupe_flag,
|
|
|
|
|
const int flag,
|
|
|
|
|
blender::Map<Strip *, Strip *> &strip_map)
|
2010-06-24 10:04:18 +00:00
|
|
|
{
|
2025-01-07 14:09:45 +01:00
|
|
|
Strip *seqn = static_cast<Strip *>(MEM_dupallocN(strip));
|
|
|
|
|
strip_map.add(strip, seqn);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-07-30 11:58:18 +02:00
|
|
|
if ((flag & LIB_ID_CREATE_NO_MAIN) == 0) {
|
2025-03-06 13:04:39 +01:00
|
|
|
relations_session_uid_generate(seqn);
|
2020-07-30 11:58:18 +02:00
|
|
|
}
|
|
|
|
|
|
2025-01-07 14:09:45 +01:00
|
|
|
seqn->data = static_cast<StripData *>(MEM_dupallocN(strip->data));
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2025-01-07 14:09:45 +01:00
|
|
|
seqn->stereo3d_format = static_cast<Stereo3dFormat *>(MEM_dupallocN(strip->stereo3d_format));
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-08-08 11:15:36 +00:00
|
|
|
/* XXX: add F-Curve duplication stuff? */
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2025-01-07 14:09:45 +01:00
|
|
|
if (strip->data->crop) {
|
|
|
|
|
seqn->data->crop = static_cast<StripCrop *>(MEM_dupallocN(strip->data->crop));
|
2010-06-24 10:04:18 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2025-01-07 14:09:45 +01:00
|
|
|
if (strip->data->transform) {
|
|
|
|
|
seqn->data->transform = static_cast<StripTransform *>(MEM_dupallocN(strip->data->transform));
|
2010-06-24 10:04:18 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2025-01-07 14:09:45 +01:00
|
|
|
if (strip->data->proxy) {
|
|
|
|
|
seqn->data->proxy = static_cast<StripProxy *>(MEM_dupallocN(strip->data->proxy));
|
2024-12-20 18:02:31 +01:00
|
|
|
seqn->data->proxy->anim = nullptr;
|
2010-06-24 10:04:18 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2025-01-07 14:09:45 +01:00
|
|
|
if (strip->prop) {
|
|
|
|
|
seqn->prop = IDP_CopyProperty_ex(strip->prop, flag);
|
2015-04-02 21:05:12 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-08-19 15:41:56 +00:00
|
|
|
if (seqn->modifiers.first) {
|
2014-02-08 06:07:10 +11:00
|
|
|
BLI_listbase_clear(&seqn->modifiers);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2025-03-06 13:04:39 +01:00
|
|
|
modifier_list_copy(seqn, strip);
|
2012-08-19 15:41:56 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2025-03-06 13:04:39 +01:00
|
|
|
if (is_strip_connected(strip)) {
|
2024-08-22 14:54:42 +02:00
|
|
|
BLI_listbase_clear(&seqn->connections);
|
2025-03-06 13:04:39 +01:00
|
|
|
connections_duplicate(&seqn->connections, &strip->connections);
|
2024-08-22 14:54:42 +02:00
|
|
|
}
|
|
|
|
|
|
2025-01-07 16:10:36 +01:00
|
|
|
if (strip->type == STRIP_TYPE_META) {
|
2024-12-20 18:02:31 +01:00
|
|
|
seqn->data->stripdata = nullptr;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-02-08 06:07:10 +11:00
|
|
|
BLI_listbase_clear(&seqn->seqbase);
|
2022-04-04 12:52:48 +02:00
|
|
|
BLI_listbase_clear(&seqn->channels);
|
2025-03-06 13:04:39 +01:00
|
|
|
channels_duplicate(&seqn->channels, &strip->channels);
|
2012-03-24 06:18:31 +00:00
|
|
|
}
|
2025-01-07 16:10:36 +01:00
|
|
|
else if (strip->type == STRIP_TYPE_SCENE) {
|
2024-12-20 18:02:31 +01:00
|
|
|
seqn->data->stripdata = nullptr;
|
2025-01-07 14:09:45 +01:00
|
|
|
if (strip->scene_sound) {
|
2017-08-10 13:00:01 +02:00
|
|
|
seqn->scene_sound = BKE_sound_scene_add_scene_sound_defaults(scene_dst, seqn);
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2012-03-24 06:18:31 +00:00
|
|
|
}
|
2025-01-07 16:10:36 +01:00
|
|
|
else if (strip->type == STRIP_TYPE_MOVIECLIP) {
|
2013-07-24 07:11:00 +00:00
|
|
|
/* avoid assert */
|
|
|
|
|
}
|
2025-01-07 16:10:36 +01:00
|
|
|
else if (strip->type == STRIP_TYPE_MASK) {
|
2013-07-24 07:11:00 +00:00
|
|
|
/* avoid assert */
|
|
|
|
|
}
|
2025-01-07 16:10:36 +01:00
|
|
|
else if (strip->type == STRIP_TYPE_MOVIE) {
|
2025-01-07 14:09:45 +01:00
|
|
|
seqn->data->stripdata = static_cast<StripElem *>(MEM_dupallocN(strip->data->stripdata));
|
2015-04-06 10:40:12 -03:00
|
|
|
BLI_listbase_clear(&seqn->anims);
|
2012-03-24 06:18:31 +00:00
|
|
|
}
|
2025-01-07 16:10:36 +01:00
|
|
|
else if (strip->type == STRIP_TYPE_SOUND_RAM) {
|
2025-01-07 14:09:45 +01:00
|
|
|
seqn->data->stripdata = static_cast<StripElem *>(MEM_dupallocN(strip->data->stripdata));
|
2023-07-20 09:46:24 +02:00
|
|
|
seqn->scene_sound = nullptr;
|
Refactor ID copying (and to some extent, ID freeing).
This will allow much finer controll over how we copy data-blocks, from
full copy in Main database, to "lighter" ones (out of Main, inside an
already allocated datablock, etc.).
This commit also transfers a llot of what was previously handled by
per-ID-type custom code to generic ID handling code in BKE_library.
Hopefully will avoid in future inconsistencies and missing bits we had
all over the codebase in the past.
It also adds missing copying handling for a few types, most notably
Scene (which where using a fully customized handling previously).
Note that the type of allocation used during copying (regular in Main,
allocated but outside of Main, or not allocated by ID handling code at
all) is stored in ID's, which allows to handle them correctly when
freeing. This needs to be taken care of with caution when doing 'weird'
unusual things with ID copying and/or allocation!
As a final note, while rather noisy, this commit will hopefully not
break too much existing branches, old 'API' has been kept for the main
part, as a wrapper around new code. Cleaning it up will happen later.
Design task : T51804
Phab Diff: D2714
2017-08-07 16:39:55 +02:00
|
|
|
if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
|
|
|
|
|
id_us_plus((ID *)seqn->sound);
|
|
|
|
|
}
|
2012-03-24 06:18:31 +00:00
|
|
|
}
|
2025-01-07 16:10:36 +01:00
|
|
|
else if (strip->type == STRIP_TYPE_IMAGE) {
|
2025-01-07 14:09:45 +01:00
|
|
|
seqn->data->stripdata = static_cast<StripElem *>(MEM_dupallocN(strip->data->stripdata));
|
2012-03-24 06:18:31 +00:00
|
|
|
}
|
2025-01-07 16:10:36 +01:00
|
|
|
else if (strip->type & STRIP_TYPE_EFFECT) {
|
2025-03-06 13:04:39 +01:00
|
|
|
EffectHandle sh;
|
|
|
|
|
sh = effect_handle_get(strip);
|
2019-04-22 09:39:35 +10:00
|
|
|
if (sh.copy) {
|
2025-01-07 14:09:45 +01:00
|
|
|
sh.copy(seqn, strip, flag);
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2024-12-20 18:02:31 +01:00
|
|
|
seqn->data->stripdata = nullptr;
|
2012-03-24 06:18:31 +00:00
|
|
|
}
|
|
|
|
|
else {
|
2013-07-24 07:11:00 +00:00
|
|
|
/* sequence type not handled in duplicate! Expect a crash now... */
|
2021-03-24 12:38:08 +11:00
|
|
|
BLI_assert_unreachable();
|
2010-06-24 10:04:18 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2025-01-07 16:33:39 +01:00
|
|
|
/* When using #STRIP_DUPE_UNIQUE_NAME, it is mandatory to add new sequences in relevant container
|
2019-01-11 19:48:56 +01:00
|
|
|
* (scene or meta's one), *before* checking for unique names. Otherwise the meta's list is empty
|
2023-05-24 11:21:18 +10:00
|
|
|
* and hence we miss all sequence-strips in that meta that have already been duplicated,
|
|
|
|
|
* (see #55668). Note that unique name check itself could be done at a later step in calling
|
|
|
|
|
* code, once all sequence-strips have bee duplicated (that was first, simpler solution),
|
|
|
|
|
* but then handling of animation data will be broken (see #60194). */
|
2023-07-20 09:46:24 +02:00
|
|
|
if (new_seq_list != nullptr) {
|
2019-01-11 19:48:56 +01:00
|
|
|
BLI_addtail(new_seq_list, seqn);
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2017-08-10 13:00:01 +02:00
|
|
|
if (scene_src == scene_dst) {
|
2025-01-07 16:33:39 +01:00
|
|
|
if (dupe_flag & STRIP_DUPE_UNIQUE_NAME) {
|
2025-03-06 13:04:39 +01:00
|
|
|
sequence_base_unique_name_recursive(scene_dst, &scene_dst->ed->seqbase, seqn);
|
2017-08-10 12:56:32 +02:00
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2025-01-07 14:09:45 +01:00
|
|
|
if (strip->retiming_keys != nullptr) {
|
|
|
|
|
seqn->retiming_keys = static_cast<SeqRetimingKey *>(MEM_dupallocN(strip->retiming_keys));
|
|
|
|
|
seqn->retiming_keys_num = strip->retiming_keys_num;
|
2023-06-14 04:47:53 +02:00
|
|
|
}
|
|
|
|
|
|
2010-06-24 10:04:18 +00:00
|
|
|
return seqn;
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-06 14:19:24 +01:00
|
|
|
static Strip *sequence_dupli_recursive_do(const Scene *scene_src,
|
|
|
|
|
Scene *scene_dst,
|
|
|
|
|
ListBase *new_seq_list,
|
2025-01-07 14:09:45 +01:00
|
|
|
Strip *strip,
|
2025-01-06 14:19:24 +01:00
|
|
|
const int dupe_flag,
|
|
|
|
|
blender::Map<Strip *, Strip *> &strip_map)
|
2010-06-24 10:04:18 +00:00
|
|
|
{
|
2025-01-07 16:03:11 +01:00
|
|
|
Strip *seqn = strip_dupli(scene_src, scene_dst, new_seq_list, strip, dupe_flag, 0, strip_map);
|
2025-01-07 16:10:36 +01:00
|
|
|
if (strip->type == STRIP_TYPE_META) {
|
2025-01-07 14:09:45 +01:00
|
|
|
LISTBASE_FOREACH (Strip *, s, &strip->seqbase) {
|
2024-10-08 22:28:36 +02:00
|
|
|
sequence_dupli_recursive_do(scene_src, scene_dst, &seqn->seqbase, s, dupe_flag, strip_map);
|
2010-06-24 10:04:18 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2019-01-11 19:48:56 +01:00
|
|
|
return seqn;
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-06 13:04:39 +01:00
|
|
|
Strip *sequence_dupli_recursive(
|
2025-01-07 14:09:45 +01:00
|
|
|
const Scene *scene_src, Scene *scene_dst, ListBase *new_seq_list, Strip *strip, int dupe_flag)
|
2019-01-11 19:48:56 +01:00
|
|
|
{
|
2025-01-06 14:19:24 +01:00
|
|
|
blender::Map<Strip *, Strip *> strip_map;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2025-01-06 14:19:24 +01:00
|
|
|
Strip *seqn = sequence_dupli_recursive_do(
|
2025-01-07 14:09:45 +01:00
|
|
|
scene_src, scene_dst, new_seq_list, strip, dupe_flag, strip_map);
|
2024-10-08 22:28:36 +02:00
|
|
|
|
|
|
|
|
seq_new_fix_links_recursive(seqn, strip_map);
|
2025-03-06 13:04:39 +01:00
|
|
|
if (is_strip_connected(seqn)) {
|
|
|
|
|
cut_one_way_connections(seqn);
|
2024-08-22 14:54:42 +02:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2010-06-24 10:04:18 +00:00
|
|
|
return seqn;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2024-10-08 22:28:36 +02:00
|
|
|
static void seqbase_dupli_recursive(const Scene *scene_src,
|
|
|
|
|
Scene *scene_dst,
|
|
|
|
|
ListBase *nseqbase,
|
|
|
|
|
const ListBase *seqbase,
|
|
|
|
|
int dupe_flag,
|
|
|
|
|
const int flag,
|
2025-01-06 14:19:24 +01:00
|
|
|
blender::Map<Strip *, Strip *> &strip_map)
|
2024-10-08 22:28:36 +02:00
|
|
|
{
|
2025-01-07 14:09:45 +01:00
|
|
|
LISTBASE_FOREACH (Strip *, strip, seqbase) {
|
2025-01-07 16:33:39 +01:00
|
|
|
if ((strip->flag & SELECT) == 0 && (dupe_flag & STRIP_DUPE_ALL) == 0) {
|
2024-10-08 22:28:36 +02:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-07 16:03:11 +01:00
|
|
|
Strip *seqn = strip_dupli(scene_src, scene_dst, nseqbase, strip, dupe_flag, flag, strip_map);
|
2024-10-08 22:28:36 +02:00
|
|
|
BLI_assert(seqn != nullptr);
|
|
|
|
|
|
2025-01-07 16:10:36 +01:00
|
|
|
if (strip->type == STRIP_TYPE_META) {
|
2024-10-08 22:28:36 +02:00
|
|
|
/* Always include meta all strip children. */
|
2025-01-07 16:33:39 +01:00
|
|
|
int dupe_flag_recursive = dupe_flag | STRIP_DUPE_ALL;
|
2024-10-08 22:28:36 +02:00
|
|
|
seqbase_dupli_recursive(scene_src,
|
|
|
|
|
scene_dst,
|
|
|
|
|
&seqn->seqbase,
|
2025-01-07 14:09:45 +01:00
|
|
|
&strip->seqbase,
|
2024-10-08 22:28:36 +02:00
|
|
|
dupe_flag_recursive,
|
|
|
|
|
flag,
|
|
|
|
|
strip_map);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-06 13:04:39 +01:00
|
|
|
void sequence_base_dupli_recursive(const Scene *scene_src,
|
|
|
|
|
Scene *scene_dst,
|
|
|
|
|
ListBase *nseqbase,
|
|
|
|
|
const ListBase *seqbase,
|
|
|
|
|
int dupe_flag,
|
|
|
|
|
const int flag)
|
2010-06-24 10:04:18 +00:00
|
|
|
{
|
2025-01-06 14:19:24 +01:00
|
|
|
blender::Map<Strip *, Strip *> strip_map;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2024-10-08 22:28:36 +02:00
|
|
|
seqbase_dupli_recursive(scene_src, scene_dst, nseqbase, seqbase, dupe_flag, flag, strip_map);
|
2020-04-26 23:35:56 +02:00
|
|
|
|
2024-08-22 14:54:42 +02:00
|
|
|
/* Fix effect, modifier, and connected strip links. */
|
2025-01-07 14:09:45 +01:00
|
|
|
LISTBASE_FOREACH (Strip *, strip, nseqbase) {
|
|
|
|
|
seq_new_fix_links_recursive(strip, strip_map);
|
2015-04-20 11:51:43 +02:00
|
|
|
}
|
2024-08-22 14:54:42 +02:00
|
|
|
/* One-way connections cannot be cut until after all connections are resolved. */
|
2025-01-07 14:09:45 +01:00
|
|
|
LISTBASE_FOREACH (Strip *, strip, nseqbase) {
|
2025-03-06 13:04:39 +01:00
|
|
|
if (is_strip_connected(strip)) {
|
|
|
|
|
cut_one_way_connections(strip);
|
2024-08-22 14:54:42 +02:00
|
|
|
}
|
|
|
|
|
}
|
2010-06-24 10:04:18 +00:00
|
|
|
}
|
2021-09-28 10:33:42 +02:00
|
|
|
|
2025-03-06 13:04:39 +01:00
|
|
|
bool is_valid_strip_channel(const Strip *strip)
|
2021-09-28 10:33:42 +02:00
|
|
|
{
|
2025-03-06 13:04:39 +01:00
|
|
|
return strip->machine >= 1 && strip->machine <= MAX_CHANNELS;
|
2021-09-28 10:33:42 +02:00
|
|
|
}
|
|
|
|
|
|
2025-03-06 13:04:39 +01:00
|
|
|
SequencerToolSettings *tool_settings_copy(SequencerToolSettings *tool_settings)
|
2020-12-16 20:34:26 +01:00
|
|
|
{
|
2023-07-20 09:46:24 +02:00
|
|
|
SequencerToolSettings *tool_settings_copy = static_cast<SequencerToolSettings *>(
|
|
|
|
|
MEM_dupallocN(tool_settings));
|
2020-12-16 20:34:26 +01:00
|
|
|
return tool_settings_copy;
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-16 05:02:30 +01:00
|
|
|
/** \} */
|
2021-08-20 16:30:34 +02:00
|
|
|
|
2025-01-07 14:09:45 +01:00
|
|
|
static bool seq_set_strip_done_cb(Strip *strip, void * /*userdata*/)
|
2021-08-20 16:30:34 +02:00
|
|
|
{
|
2025-01-07 14:09:45 +01:00
|
|
|
if (strip->data) {
|
|
|
|
|
strip->data->done = false;
|
2021-08-20 16:30:34 +02:00
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-07 16:03:11 +01:00
|
|
|
static bool strip_write_data_cb(Strip *strip, void *userdata)
|
2021-08-20 16:30:34 +02:00
|
|
|
{
|
|
|
|
|
BlendWriter *writer = (BlendWriter *)userdata;
|
2025-01-07 14:09:45 +01:00
|
|
|
BLO_write_struct(writer, Strip, strip);
|
|
|
|
|
if (strip->data && strip->data->done == 0) {
|
2021-08-26 12:27:14 +10:00
|
|
|
/* Write strip with 'done' at 0 because read-file. */
|
2021-08-20 16:30:34 +02:00
|
|
|
|
2021-08-26 12:27:14 +10:00
|
|
|
/* TODO this doesn't depend on the `Strip` data to be present? */
|
2025-01-07 14:09:45 +01:00
|
|
|
if (strip->effectdata) {
|
|
|
|
|
switch (strip->type) {
|
2025-01-07 16:10:36 +01:00
|
|
|
case STRIP_TYPE_COLOR:
|
2025-01-07 14:09:45 +01:00
|
|
|
BLO_write_struct(writer, SolidColorVars, strip->effectdata);
|
2021-08-20 16:30:34 +02:00
|
|
|
break;
|
2025-01-07 16:10:36 +01:00
|
|
|
case STRIP_TYPE_SPEED:
|
2025-01-07 14:09:45 +01:00
|
|
|
BLO_write_struct(writer, SpeedControlVars, strip->effectdata);
|
2021-08-20 16:30:34 +02:00
|
|
|
break;
|
2025-01-07 16:10:36 +01:00
|
|
|
case STRIP_TYPE_WIPE:
|
2025-01-07 14:09:45 +01:00
|
|
|
BLO_write_struct(writer, WipeVars, strip->effectdata);
|
2021-08-20 16:30:34 +02:00
|
|
|
break;
|
2025-01-07 16:10:36 +01:00
|
|
|
case STRIP_TYPE_GLOW:
|
2025-01-07 14:09:45 +01:00
|
|
|
BLO_write_struct(writer, GlowVars, strip->effectdata);
|
2021-08-20 16:30:34 +02:00
|
|
|
break;
|
2025-01-07 16:10:36 +01:00
|
|
|
case STRIP_TYPE_TRANSFORM:
|
2025-01-07 14:09:45 +01:00
|
|
|
BLO_write_struct(writer, TransformVars, strip->effectdata);
|
2021-08-20 16:30:34 +02:00
|
|
|
break;
|
2025-01-07 16:10:36 +01:00
|
|
|
case STRIP_TYPE_GAUSSIAN_BLUR:
|
2025-01-07 14:09:45 +01:00
|
|
|
BLO_write_struct(writer, GaussianBlurVars, strip->effectdata);
|
2021-08-20 16:30:34 +02:00
|
|
|
break;
|
2025-01-07 16:10:36 +01:00
|
|
|
case STRIP_TYPE_TEXT:
|
2025-01-07 14:09:45 +01:00
|
|
|
BLO_write_struct(writer, TextVars, strip->effectdata);
|
2021-08-20 16:30:34 +02:00
|
|
|
break;
|
2025-01-07 16:10:36 +01:00
|
|
|
case STRIP_TYPE_COLORMIX:
|
2025-01-07 14:09:45 +01:00
|
|
|
BLO_write_struct(writer, ColorMixVars, strip->effectdata);
|
2021-08-20 16:30:34 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-07 14:09:45 +01:00
|
|
|
BLO_write_struct(writer, Stereo3dFormat, strip->stereo3d_format);
|
2021-08-20 16:30:34 +02:00
|
|
|
|
2025-01-07 14:09:45 +01:00
|
|
|
StripData *data = strip->data;
|
2024-12-20 18:02:31 +01:00
|
|
|
BLO_write_struct(writer, StripData, data);
|
|
|
|
|
if (data->crop) {
|
|
|
|
|
BLO_write_struct(writer, StripCrop, data->crop);
|
2021-08-20 16:30:34 +02:00
|
|
|
}
|
2024-12-20 18:02:31 +01:00
|
|
|
if (data->transform) {
|
|
|
|
|
BLO_write_struct(writer, StripTransform, data->transform);
|
2021-08-20 16:30:34 +02:00
|
|
|
}
|
2024-12-20 18:02:31 +01:00
|
|
|
if (data->proxy) {
|
|
|
|
|
BLO_write_struct(writer, StripProxy, data->proxy);
|
2021-08-20 16:30:34 +02:00
|
|
|
}
|
2025-01-07 16:10:36 +01:00
|
|
|
if (strip->type == STRIP_TYPE_IMAGE) {
|
2024-12-20 18:02:31 +01:00
|
|
|
BLO_write_struct_array(
|
|
|
|
|
writer, StripElem, MEM_allocN_len(data->stripdata) / sizeof(StripElem), data->stripdata);
|
2021-08-20 16:30:34 +02:00
|
|
|
}
|
2025-01-07 16:10:36 +01:00
|
|
|
else if (ELEM(strip->type, STRIP_TYPE_MOVIE, STRIP_TYPE_SOUND_RAM)) {
|
2024-12-20 18:02:31 +01:00
|
|
|
BLO_write_struct(writer, StripElem, data->stripdata);
|
2021-08-20 16:30:34 +02:00
|
|
|
}
|
|
|
|
|
|
2024-12-20 18:02:31 +01:00
|
|
|
data->done = true;
|
2021-08-20 16:30:34 +02:00
|
|
|
}
|
|
|
|
|
|
2025-01-07 14:09:45 +01:00
|
|
|
if (strip->prop) {
|
|
|
|
|
IDP_BlendWrite(writer, strip->prop);
|
2021-08-20 16:30:34 +02:00
|
|
|
}
|
|
|
|
|
|
2025-03-06 13:04:39 +01:00
|
|
|
modifier_blend_write(writer, &strip->modifiers);
|
2022-04-04 12:52:48 +02:00
|
|
|
|
2025-01-07 14:09:45 +01:00
|
|
|
LISTBASE_FOREACH (SeqTimelineChannel *, channel, &strip->channels) {
|
2022-04-04 12:52:48 +02:00
|
|
|
BLO_write_struct(writer, SeqTimelineChannel, channel);
|
|
|
|
|
}
|
2023-06-14 04:47:53 +02:00
|
|
|
|
2025-01-13 18:16:48 +01:00
|
|
|
LISTBASE_FOREACH (StripConnection *, con, &strip->connections) {
|
|
|
|
|
BLO_write_struct(writer, StripConnection, con);
|
2024-08-22 14:54:42 +02:00
|
|
|
}
|
|
|
|
|
|
2025-01-07 14:09:45 +01:00
|
|
|
if (strip->retiming_keys != nullptr) {
|
2025-03-06 13:04:39 +01:00
|
|
|
int size = retiming_keys_count(strip);
|
2025-01-07 14:09:45 +01:00
|
|
|
BLO_write_struct_array(writer, SeqRetimingKey, size, strip->retiming_keys);
|
2023-06-14 04:47:53 +02:00
|
|
|
}
|
|
|
|
|
|
2021-08-20 16:30:34 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-06 13:04:39 +01:00
|
|
|
void blend_write(BlendWriter *writer, ListBase *seqbase)
|
2021-08-20 16:30:34 +02:00
|
|
|
{
|
|
|
|
|
/* reset write flags */
|
2025-03-06 13:04:39 +01:00
|
|
|
for_each_callback(seqbase, seq_set_strip_done_cb, nullptr);
|
2021-08-20 16:30:34 +02:00
|
|
|
|
2025-03-06 13:04:39 +01:00
|
|
|
for_each_callback(seqbase, strip_write_data_cb, writer);
|
2021-08-20 16:30:34 +02:00
|
|
|
}
|
|
|
|
|
|
2025-01-07 16:03:11 +01:00
|
|
|
static bool strip_read_data_cb(Strip *strip, void *user_data)
|
2021-08-20 16:30:34 +02:00
|
|
|
{
|
|
|
|
|
BlendDataReader *reader = (BlendDataReader *)user_data;
|
|
|
|
|
|
2023-08-15 14:49:11 +02:00
|
|
|
/* Runtime data cleanup. */
|
2025-01-07 14:09:45 +01:00
|
|
|
strip->scene_sound = nullptr;
|
|
|
|
|
BLI_listbase_clear(&strip->anims);
|
2023-08-15 14:49:11 +02:00
|
|
|
|
2024-01-22 13:47:13 +01:00
|
|
|
/* Do as early as possible, so that other parts of reading can rely on valid session UID. */
|
2025-03-06 13:04:39 +01:00
|
|
|
relations_session_uid_generate(strip);
|
2021-08-20 16:30:34 +02:00
|
|
|
|
2025-01-07 14:09:45 +01:00
|
|
|
BLO_read_struct(reader, Strip, &strip->seq1);
|
|
|
|
|
BLO_read_struct(reader, Strip, &strip->seq2);
|
2021-08-20 16:30:34 +02:00
|
|
|
|
2025-01-07 14:09:45 +01:00
|
|
|
if (strip->effectdata) {
|
|
|
|
|
switch (strip->type) {
|
2025-01-07 16:10:36 +01:00
|
|
|
case STRIP_TYPE_COLOR:
|
2025-01-07 14:09:45 +01:00
|
|
|
BLO_read_struct(reader, SolidColorVars, &strip->effectdata);
|
2024-07-31 19:22:50 +02:00
|
|
|
break;
|
2025-01-07 16:10:36 +01:00
|
|
|
case STRIP_TYPE_SPEED:
|
2025-01-07 14:09:45 +01:00
|
|
|
BLO_read_struct(reader, SpeedControlVars, &strip->effectdata);
|
2024-07-31 19:22:50 +02:00
|
|
|
break;
|
2025-01-07 16:10:36 +01:00
|
|
|
case STRIP_TYPE_WIPE:
|
2025-01-07 14:09:45 +01:00
|
|
|
BLO_read_struct(reader, WipeVars, &strip->effectdata);
|
2024-07-31 19:22:50 +02:00
|
|
|
break;
|
2025-01-07 16:10:36 +01:00
|
|
|
case STRIP_TYPE_GLOW:
|
2025-01-07 14:09:45 +01:00
|
|
|
BLO_read_struct(reader, GlowVars, &strip->effectdata);
|
2024-07-31 19:22:50 +02:00
|
|
|
break;
|
2025-01-07 16:10:36 +01:00
|
|
|
case STRIP_TYPE_TRANSFORM:
|
2025-01-07 14:09:45 +01:00
|
|
|
BLO_read_struct(reader, TransformVars, &strip->effectdata);
|
2024-07-31 19:22:50 +02:00
|
|
|
break;
|
2025-01-07 16:10:36 +01:00
|
|
|
case STRIP_TYPE_GAUSSIAN_BLUR:
|
2025-01-07 14:09:45 +01:00
|
|
|
BLO_read_struct(reader, GaussianBlurVars, &strip->effectdata);
|
2024-07-31 19:22:50 +02:00
|
|
|
break;
|
2025-01-07 16:10:36 +01:00
|
|
|
case STRIP_TYPE_TEXT:
|
2025-01-07 14:09:45 +01:00
|
|
|
BLO_read_struct(reader, TextVars, &strip->effectdata);
|
2024-07-31 19:22:50 +02:00
|
|
|
break;
|
2025-01-07 16:10:36 +01:00
|
|
|
case STRIP_TYPE_COLORMIX:
|
2025-01-07 14:09:45 +01:00
|
|
|
BLO_read_struct(reader, ColorMixVars, &strip->effectdata);
|
2024-07-31 19:22:50 +02:00
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
BLI_assert_unreachable();
|
2025-01-07 14:09:45 +01:00
|
|
|
strip->effectdata = nullptr;
|
2024-07-31 19:22:50 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-07 14:09:45 +01:00
|
|
|
BLO_read_struct(reader, Stereo3dFormat, &strip->stereo3d_format);
|
2021-08-20 16:30:34 +02:00
|
|
|
|
2025-01-07 16:10:36 +01:00
|
|
|
if (strip->type & STRIP_TYPE_EFFECT) {
|
2025-01-07 14:09:45 +01:00
|
|
|
strip->flag |= SEQ_EFFECT_NOT_LOADED;
|
2021-08-20 16:30:34 +02:00
|
|
|
}
|
|
|
|
|
|
2025-01-07 16:10:36 +01:00
|
|
|
if (strip->type == STRIP_TYPE_TEXT) {
|
2025-01-07 14:09:45 +01:00
|
|
|
TextVars *t = static_cast<TextVars *>(strip->effectdata);
|
2025-01-07 16:33:39 +01:00
|
|
|
t->text_blf_id = STRIP_FONT_NOT_LOADED;
|
2024-12-19 15:48:06 +01:00
|
|
|
t->runtime = nullptr;
|
2021-08-20 16:30:34 +02:00
|
|
|
}
|
|
|
|
|
|
2025-01-07 14:09:45 +01:00
|
|
|
BLO_read_struct(reader, IDProperty, &strip->prop);
|
|
|
|
|
IDP_BlendDataRead(reader, &strip->prop);
|
2021-08-20 16:30:34 +02:00
|
|
|
|
2025-01-07 14:09:45 +01:00
|
|
|
BLO_read_struct(reader, StripData, &strip->data);
|
|
|
|
|
if (strip->data && strip->data->done == 0) {
|
|
|
|
|
strip->data->done = true;
|
2021-08-20 16:30:34 +02:00
|
|
|
|
2025-01-07 16:10:36 +01:00
|
|
|
/* `STRIP_TYPE_SOUND_HD` case needs to be kept here, for backward compatibility. */
|
|
|
|
|
if (ELEM(strip->type,
|
|
|
|
|
STRIP_TYPE_IMAGE,
|
|
|
|
|
STRIP_TYPE_MOVIE,
|
|
|
|
|
STRIP_TYPE_SOUND_RAM,
|
|
|
|
|
STRIP_TYPE_SOUND_HD))
|
|
|
|
|
{
|
|
|
|
|
/* FIXME In #STRIP_TYPE_IMAGE case, there is currently no available information about the
|
2024-08-04 13:45:06 +10:00
|
|
|
* length of the stored array of #StripElem.
|
2024-07-31 19:22:50 +02:00
|
|
|
*
|
|
|
|
|
* This is 'not a problem' because the reading code only checks that the loaded buffer is at
|
|
|
|
|
* least large enough for the requested data (here a single #StripElem item), and always
|
|
|
|
|
* assign the whole read memory (without any truncating). But relying on this behavior is
|
|
|
|
|
* weak and should be addressed. */
|
2025-01-07 14:09:45 +01:00
|
|
|
BLO_read_struct(reader, StripElem, &strip->data->stripdata);
|
2021-08-20 16:30:34 +02:00
|
|
|
}
|
|
|
|
|
else {
|
2025-01-07 14:09:45 +01:00
|
|
|
strip->data->stripdata = nullptr;
|
2021-08-20 16:30:34 +02:00
|
|
|
}
|
2025-01-07 14:09:45 +01:00
|
|
|
BLO_read_struct(reader, StripCrop, &strip->data->crop);
|
|
|
|
|
BLO_read_struct(reader, StripTransform, &strip->data->transform);
|
|
|
|
|
BLO_read_struct(reader, StripProxy, &strip->data->proxy);
|
|
|
|
|
if (strip->data->proxy) {
|
|
|
|
|
strip->data->proxy->anim = nullptr;
|
2021-08-20 16:30:34 +02:00
|
|
|
}
|
2025-01-07 14:09:45 +01:00
|
|
|
else if (strip->flag & SEQ_USE_PROXY) {
|
2025-03-06 13:04:39 +01:00
|
|
|
proxy_set(strip, true);
|
2021-08-20 16:30:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* need to load color balance to it could be converted to modifier */
|
2025-01-07 14:09:45 +01:00
|
|
|
BLO_read_struct(reader, StripColorBalance, &strip->data->color_balance);
|
2021-08-20 16:30:34 +02:00
|
|
|
}
|
|
|
|
|
|
2025-03-06 13:04:39 +01:00
|
|
|
modifier_blend_read_data(reader, &strip->modifiers);
|
2022-04-04 12:52:48 +02:00
|
|
|
|
2025-01-13 18:16:48 +01:00
|
|
|
BLO_read_struct_list(reader, StripConnection, &strip->connections);
|
|
|
|
|
LISTBASE_FOREACH (StripConnection *, con, &strip->connections) {
|
|
|
|
|
if (con->strip_ref) {
|
|
|
|
|
BLO_read_struct(reader, Strip, &con->strip_ref);
|
2024-08-22 14:54:42 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-07 14:09:45 +01:00
|
|
|
BLO_read_struct_list(reader, SeqTimelineChannel, &strip->channels);
|
2023-06-14 04:47:53 +02:00
|
|
|
|
2025-01-07 14:09:45 +01:00
|
|
|
if (strip->retiming_keys != nullptr) {
|
2025-03-06 13:04:39 +01:00
|
|
|
const int size = retiming_keys_count(strip);
|
2025-01-07 14:09:45 +01:00
|
|
|
BLO_read_struct_array(reader, SeqRetimingKey, size, &strip->retiming_keys);
|
2023-06-14 04:47:53 +02:00
|
|
|
}
|
|
|
|
|
|
2021-08-20 16:30:34 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
2025-03-06 13:04:39 +01:00
|
|
|
void blend_read(BlendDataReader *reader, ListBase *seqbase)
|
2021-08-20 16:30:34 +02:00
|
|
|
{
|
2025-03-06 13:04:39 +01:00
|
|
|
for_each_callback(seqbase, strip_read_data_cb, reader);
|
2021-08-20 16:30:34 +02:00
|
|
|
}
|
|
|
|
|
|
2025-01-07 16:03:11 +01:00
|
|
|
static bool strip_doversion_250_sound_proxy_update_cb(Strip *strip, void *user_data)
|
2023-08-15 14:49:11 +02:00
|
|
|
{
|
|
|
|
|
Main *bmain = static_cast<Main *>(user_data);
|
2025-01-07 16:10:36 +01:00
|
|
|
if (strip->type == STRIP_TYPE_SOUND_HD) {
|
2023-08-15 14:49:11 +02:00
|
|
|
char filepath_abs[FILE_MAX];
|
2025-01-07 14:09:45 +01:00
|
|
|
BLI_path_join(filepath_abs,
|
|
|
|
|
sizeof(filepath_abs),
|
|
|
|
|
strip->data->dirpath,
|
|
|
|
|
strip->data->stripdata->filename);
|
2023-08-15 14:49:11 +02:00
|
|
|
BLI_path_abs(filepath_abs, BKE_main_blendfile_path(bmain));
|
2025-01-07 14:09:45 +01:00
|
|
|
strip->sound = BKE_sound_new_file(bmain, filepath_abs);
|
2025-01-07 16:10:36 +01:00
|
|
|
strip->type = STRIP_TYPE_SOUND_RAM;
|
2023-08-15 14:49:11 +02:00
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-06 13:04:39 +01:00
|
|
|
void doversion_250_sound_proxy_update(Main *bmain, Editing *ed)
|
2023-08-15 14:49:11 +02:00
|
|
|
{
|
2025-03-06 13:04:39 +01:00
|
|
|
for_each_callback(&ed->seqbase, strip_doversion_250_sound_proxy_update_cb, bmain);
|
2023-08-15 14:49:11 +02:00
|
|
|
}
|
|
|
|
|
|
2021-08-20 16:30:34 +02:00
|
|
|
/* Depsgraph update functions. */
|
|
|
|
|
|
2025-01-07 14:09:45 +01:00
|
|
|
static bool seq_mute_sound_strips_cb(Strip *strip, void *user_data)
|
2021-08-20 16:30:34 +02:00
|
|
|
{
|
|
|
|
|
Scene *scene = (Scene *)user_data;
|
2025-01-07 14:09:45 +01:00
|
|
|
if (strip->scene_sound != nullptr) {
|
|
|
|
|
BKE_sound_remove_scene_sound(scene, strip->scene_sound);
|
|
|
|
|
strip->scene_sound = nullptr;
|
2021-08-20 16:30:34 +02:00
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-17 17:02:17 +01:00
|
|
|
/* Adds sound of strip to the `scene->sound_scene` - "sound timeline". */
|
2025-01-07 16:03:11 +01:00
|
|
|
static void strip_update_mix_sounds(Scene *scene, Strip *strip)
|
2021-08-20 16:30:34 +02:00
|
|
|
{
|
2025-01-07 14:09:45 +01:00
|
|
|
if (strip->scene_sound != nullptr) {
|
2023-12-17 17:02:17 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-07 14:09:45 +01:00
|
|
|
if (strip->sound != nullptr) {
|
|
|
|
|
/* Adds `strip->sound->playback_handle` to `scene->sound_scene` */
|
|
|
|
|
strip->scene_sound = BKE_sound_add_scene_sound_defaults(scene, strip);
|
2023-12-17 17:02:17 +01:00
|
|
|
}
|
2025-01-07 16:10:36 +01:00
|
|
|
else if (strip->type == STRIP_TYPE_SCENE && strip->scene != nullptr) {
|
2025-01-07 14:09:45 +01:00
|
|
|
/* Adds `strip->scene->sound_scene` to `scene->sound_scene`. */
|
|
|
|
|
BKE_sound_ensure_scene(strip->scene);
|
|
|
|
|
strip->scene_sound = BKE_sound_scene_add_scene_sound_defaults(scene, strip);
|
2023-12-17 17:02:17 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-07 16:03:11 +01:00
|
|
|
static void strip_update_sound_properties(const Scene *scene, const Strip *strip)
|
2023-12-17 17:02:17 +01:00
|
|
|
{
|
2024-01-31 18:57:06 +01:00
|
|
|
const int frame = BKE_scene_frame_get(scene);
|
|
|
|
|
BKE_sound_set_scene_sound_volume_at_frame(
|
2025-01-07 14:09:45 +01:00
|
|
|
strip->scene_sound, frame, strip->volume, (strip->flag & SEQ_AUDIO_VOLUME_ANIMATED) != 0);
|
2025-03-06 13:04:39 +01:00
|
|
|
retiming_sound_animation_data_set(scene, strip);
|
2024-01-31 18:57:06 +01:00
|
|
|
BKE_sound_set_scene_sound_pan_at_frame(
|
2025-01-07 14:09:45 +01:00
|
|
|
strip->scene_sound, frame, strip->pan, (strip->flag & SEQ_AUDIO_PAN_ANIMATED) != 0);
|
2023-12-17 17:02:17 +01:00
|
|
|
}
|
|
|
|
|
|
2025-01-07 16:03:11 +01:00
|
|
|
static void strip_update_sound_modifiers(Strip *strip)
|
2023-12-17 17:02:17 +01:00
|
|
|
{
|
2025-01-07 14:09:45 +01:00
|
|
|
void *sound_handle = strip->sound->playback_handle;
|
|
|
|
|
if (!BLI_listbase_is_empty(&strip->modifiers)) {
|
|
|
|
|
LISTBASE_FOREACH (SequenceModifierData *, smd, &strip->modifiers) {
|
2025-03-06 13:04:39 +01:00
|
|
|
sound_handle = sound_modifier_recreator(strip, smd, sound_handle);
|
2021-08-20 16:30:34 +02:00
|
|
|
}
|
|
|
|
|
}
|
2023-12-17 17:02:17 +01:00
|
|
|
|
2025-01-07 14:09:45 +01:00
|
|
|
/* Assign modified sound back to `strip`. */
|
|
|
|
|
BKE_sound_update_sequence_handle(strip->scene_sound, sound_handle);
|
2023-12-17 17:02:17 +01:00
|
|
|
}
|
|
|
|
|
|
2025-01-07 14:09:45 +01:00
|
|
|
static bool must_update_strip_sound(Scene *scene, Strip *strip)
|
2023-12-19 17:38:29 +01:00
|
|
|
{
|
2024-02-19 15:54:08 +01:00
|
|
|
return (scene->id.recalc & (ID_RECALC_AUDIO | ID_RECALC_SYNC_TO_EVAL)) != 0 ||
|
2025-01-07 14:09:45 +01:00
|
|
|
(strip->sound->id.recalc & (ID_RECALC_AUDIO | ID_RECALC_SYNC_TO_EVAL)) != 0;
|
2023-12-19 17:38:29 +01:00
|
|
|
}
|
|
|
|
|
|
2025-01-07 14:09:45 +01:00
|
|
|
static void seq_update_sound_strips(Scene *scene, Strip *strip)
|
2023-12-17 17:02:17 +01:00
|
|
|
{
|
2025-01-07 14:09:45 +01:00
|
|
|
if (strip->sound == nullptr || !must_update_strip_sound(scene, strip)) {
|
2023-12-17 17:02:17 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
/* Ensure strip is playing correct sound. */
|
2025-01-07 14:09:45 +01:00
|
|
|
BKE_sound_update_scene_sound(strip->scene_sound, strip->sound);
|
2025-01-07 16:03:11 +01:00
|
|
|
strip_update_sound_modifiers(strip);
|
2023-12-17 17:02:17 +01:00
|
|
|
}
|
|
|
|
|
|
2024-11-12 17:28:20 +01:00
|
|
|
static bool scene_sequencer_is_used(const Scene *scene, ListBase *seqbase)
|
|
|
|
|
{
|
|
|
|
|
bool sequencer_is_used = false;
|
2025-01-07 16:03:11 +01:00
|
|
|
LISTBASE_FOREACH (Strip *, strip_iter, seqbase) {
|
|
|
|
|
if (strip_iter->scene == scene && (strip_iter->flag & SEQ_SCENE_STRIPS) != 0) {
|
2024-11-12 17:28:20 +01:00
|
|
|
sequencer_is_used = true;
|
|
|
|
|
}
|
2025-01-07 16:10:36 +01:00
|
|
|
if (strip_iter->type == STRIP_TYPE_META) {
|
2025-01-07 16:03:11 +01:00
|
|
|
sequencer_is_used |= scene_sequencer_is_used(scene, &strip_iter->seqbase);
|
2024-11-12 17:28:20 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return sequencer_is_used;
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-07 14:09:45 +01:00
|
|
|
static void seq_update_scene_strip_sound(const Scene *scene, Strip *strip)
|
2023-12-17 17:02:17 +01:00
|
|
|
{
|
2025-01-07 16:10:36 +01:00
|
|
|
if (strip->type != STRIP_TYPE_SCENE || strip->scene == nullptr) {
|
2023-12-17 17:02:17 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-07 14:09:45 +01:00
|
|
|
/* Set `strip->scene` volume.
|
2024-05-03 11:32:43 +10:00
|
|
|
* NOTE: Currently this doesn't work well, when this property is animated. Scene strip volume is
|
2025-01-07 16:03:11 +01:00
|
|
|
* also controlled by `strip_update_sound_properties()` via `strip->volume` which works if
|
2025-01-07 14:09:45 +01:00
|
|
|
* animated.
|
2023-12-17 17:02:17 +01:00
|
|
|
*
|
|
|
|
|
* Ideally, the entire `BKE_scene_update_sound()` will happen from a dependency graph, so
|
|
|
|
|
* then it is no longer needed to do such manual forced updates. */
|
2025-01-07 14:09:45 +01:00
|
|
|
BKE_sound_set_scene_volume(strip->scene, strip->scene->audio.volume);
|
2023-12-17 17:02:17 +01:00
|
|
|
|
2024-11-12 17:28:20 +01:00
|
|
|
/* Mute sound when all scene strips using particular scene are not rendering sequencer strips. */
|
2025-01-07 14:09:45 +01:00
|
|
|
bool sequencer_is_used = scene_sequencer_is_used(strip->scene, &scene->ed->seqbase);
|
2024-11-12 17:28:20 +01:00
|
|
|
|
2025-01-07 14:09:45 +01:00
|
|
|
if (!sequencer_is_used && strip->scene->sound_scene != nullptr && strip->scene->ed != nullptr) {
|
2025-03-06 13:04:39 +01:00
|
|
|
for_each_callback(&strip->scene->ed->seqbase, seq_mute_sound_strips_cb, strip->scene);
|
2023-12-17 17:02:17 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-07 16:03:11 +01:00
|
|
|
static bool strip_sound_update_cb(Strip *strip, void *user_data)
|
2023-12-17 17:02:17 +01:00
|
|
|
{
|
|
|
|
|
Scene *scene = (Scene *)user_data;
|
|
|
|
|
|
2025-01-07 16:03:11 +01:00
|
|
|
strip_update_mix_sounds(scene, strip);
|
2023-12-17 17:02:17 +01:00
|
|
|
|
2025-01-07 14:09:45 +01:00
|
|
|
if (strip->scene_sound == nullptr) {
|
2023-12-17 17:02:17 +01:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-07 14:09:45 +01:00
|
|
|
seq_update_sound_strips(scene, strip);
|
|
|
|
|
seq_update_scene_strip_sound(scene, strip);
|
2025-01-07 16:03:11 +01:00
|
|
|
strip_update_sound_properties(scene, strip);
|
2021-08-20 16:30:34 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-06 13:04:39 +01:00
|
|
|
void eval_sequences(Depsgraph *depsgraph, Scene *scene, ListBase *seqbase)
|
2021-08-20 16:30:34 +02:00
|
|
|
{
|
|
|
|
|
DEG_debug_print_eval(depsgraph, __func__, scene->id.name, scene);
|
|
|
|
|
BKE_sound_ensure_scene(scene);
|
|
|
|
|
|
2025-03-06 13:04:39 +01:00
|
|
|
for_each_callback(seqbase, strip_sound_update_cb, scene);
|
2021-08-20 16:30:34 +02:00
|
|
|
|
2025-03-06 13:04:39 +01:00
|
|
|
edit_update_muting(scene->ed);
|
|
|
|
|
sound_update_bounds_all(scene);
|
2021-08-20 16:30:34 +02:00
|
|
|
}
|
2025-03-06 06:22:14 +01:00
|
|
|
|
|
|
|
|
} // namespace blender::seq
|