Blender V4.3
sequencer/intern/utils.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
2 * SPDX-FileCopyrightText: 2003-2009 Blender Authors
3 * SPDX-FileCopyrightText: 2005-2006 Peter Schlaile <peter [at] schlaile [dot] de>
4 *
5 * SPDX-License-Identifier: GPL-2.0-or-later */
6
11#include <algorithm>
12#include <cstdlib>
13#include <cstring>
14
15#include "MEM_guardedalloc.h"
16
17#include "DNA_scene_types.h"
18#include "DNA_sequence_types.h"
19
20#include "BLI_blenlib.h"
21#include "BLI_vector_set.hh"
22
23#include "BLT_translation.hh"
24
25#include "BKE_animsys.h"
26#include "BKE_image.hh"
27#include "BKE_main.hh"
28#include "BKE_scene.hh"
29
30#include "SEQ_channels.hh"
31#include "SEQ_edit.hh"
32#include "SEQ_iterator.hh"
33#include "SEQ_relations.hh"
34#include "SEQ_render.hh"
35#include "SEQ_select.hh"
36#include "SEQ_sequencer.hh"
37#include "SEQ_time.hh"
38#include "SEQ_utils.hh"
39
40#include "IMB_imbuf.hh"
41#include "IMB_imbuf_types.hh"
42
43#include "multiview.hh"
44#include "proxy.hh"
45#include "sequencer.hh"
46#include "utils.hh"
47
55
56static void seqbase_unique_name(ListBase *seqbasep, SeqUniqueInfo *sui)
57{
58 LISTBASE_FOREACH (Sequence *, seq, seqbasep) {
59 if ((sui->seq != seq) && STREQ(sui->name_dest, seq->name + 2)) {
60 /* SEQ_NAME_MAXSTR -4 for the number, -1 for \0, - 2 for r_prefix */
62 sui->name_dest, "%.*s.%03d", SEQ_NAME_MAXSTR - 4 - 1 - 2, sui->name_src, sui->count++);
63 sui->match = 1; /* be sure to re-scan */
64 }
65 }
66}
67
68static bool seqbase_unique_name_recursive_fn(Sequence *seq, void *arg_pt)
69{
70 if (seq->seqbase.first) {
72 }
73 return true;
74}
75
77{
78 SeqUniqueInfo sui;
79 char *dot;
80 sui.seq = seq;
81 STRNCPY(sui.name_src, seq->name + 2);
82 STRNCPY(sui.name_dest, seq->name + 2);
83
84 sui.count = 1;
85 sui.match = 1; /* assume the worst to start the loop */
86
87 /* Strip off the suffix */
88 if ((dot = strrchr(sui.name_src, '.'))) {
89 *dot = '\0';
90 dot++;
91
92 if (*dot) {
93 sui.count = atoi(dot) + 1;
94 }
95 }
96
97 while (sui.match) {
98 sui.match = 0;
99 seqbase_unique_name(seqbasep, &sui);
101 }
102
103 SEQ_edit_sequence_name_set(scene, seq, sui.name_dest);
104}
105
106static const char *give_seqname_by_type(int type)
107{
108 switch (type) {
109 case SEQ_TYPE_META:
111 case SEQ_TYPE_IMAGE:
112 return CTX_DATA_(BLT_I18NCONTEXT_ID_SEQUENCE, "Image");
113 case SEQ_TYPE_SCENE:
114 return CTX_DATA_(BLT_I18NCONTEXT_ID_SEQUENCE, "Scene");
115 case SEQ_TYPE_MOVIE:
116 return CTX_DATA_(BLT_I18NCONTEXT_ID_SEQUENCE, "Movie");
119 case SEQ_TYPE_MASK:
122 return CTX_DATA_(BLT_I18NCONTEXT_ID_SEQUENCE, "Audio");
123 case SEQ_TYPE_CROSS:
124 return CTX_DATA_(BLT_I18NCONTEXT_ID_SEQUENCE, "Cross");
126 return CTX_DATA_(BLT_I18NCONTEXT_ID_SEQUENCE, "Gamma Cross");
127 case SEQ_TYPE_ADD:
129 case SEQ_TYPE_SUB:
130 return CTX_DATA_(BLT_I18NCONTEXT_ID_SEQUENCE, "Subtract");
131 case SEQ_TYPE_MUL:
132 return CTX_DATA_(BLT_I18NCONTEXT_ID_SEQUENCE, "Multiply");
134 return CTX_DATA_(BLT_I18NCONTEXT_ID_SEQUENCE, "Alpha Over");
136 return CTX_DATA_(BLT_I18NCONTEXT_ID_SEQUENCE, "Alpha Under");
138 return CTX_DATA_(BLT_I18NCONTEXT_ID_SEQUENCE, "Over Drop");
140 return CTX_DATA_(BLT_I18NCONTEXT_ID_SEQUENCE, "Color Mix");
141 case SEQ_TYPE_WIPE:
143 case SEQ_TYPE_GLOW:
146 return CTX_DATA_(BLT_I18NCONTEXT_ID_SEQUENCE, "Transform");
147 case SEQ_TYPE_COLOR:
148 return CTX_DATA_(BLT_I18NCONTEXT_ID_SEQUENCE, "Color");
150 return CTX_DATA_(BLT_I18NCONTEXT_ID_SEQUENCE, "Multicam");
152 return CTX_DATA_(BLT_I18NCONTEXT_ID_SEQUENCE, "Adjustment");
153 case SEQ_TYPE_SPEED:
154 return CTX_DATA_(BLT_I18NCONTEXT_ID_SEQUENCE, "Speed");
156 return CTX_DATA_(BLT_I18NCONTEXT_ID_SEQUENCE, "Gaussian Blur");
157 case SEQ_TYPE_TEXT:
159 default:
160 return nullptr;
161 }
162}
163
164const char *SEQ_sequence_give_name(const Sequence *seq)
165{
166 const char *name = give_seqname_by_type(seq->type);
167
168 if (!name) {
169 if (!(seq->type & SEQ_TYPE_EFFECT)) {
170 return seq->strip->dirpath;
171 }
172
173 return DATA_("Effect");
174 }
175 return name;
176}
177
178ListBase *SEQ_get_seqbase_from_sequence(Sequence *seq, ListBase **r_channels, int *r_offset)
179{
180 ListBase *seqbase = nullptr;
181
182 switch (seq->type) {
183 case SEQ_TYPE_META: {
184 seqbase = &seq->seqbase;
185 *r_channels = &seq->channels;
186 *r_offset = SEQ_time_start_frame_get(seq);
187 break;
188 }
189 case SEQ_TYPE_SCENE: {
190 if (seq->flag & SEQ_SCENE_STRIPS && seq->scene) {
191 Editing *ed = SEQ_editing_get(seq->scene);
192 if (ed) {
193 seqbase = &ed->seqbase;
194 *r_channels = &ed->channels;
195 *r_offset = seq->scene->r.sfra;
196 }
197 }
198 break;
199 }
200 }
201
202 return seqbase;
203}
204
206 StripAnim *sanim,
207 const char *filepath,
208 bool openfile)
209{
210 if (openfile) {
211 sanim->anim = openanim(filepath,
212 IB_rect | ((seq->flag & SEQ_FILTERY) ? IB_animdeinterlace : 0),
213 seq->streamindex,
215 }
216 else {
217 sanim->anim = openanim_noload(filepath,
218 IB_rect | ((seq->flag & SEQ_FILTERY) ? IB_animdeinterlace : 0),
219 seq->streamindex,
221 }
222}
223
224static bool use_proxy(Editing *ed, Sequence *seq)
225{
226 StripProxy *proxy = seq->strip->proxy;
227 return proxy && ((proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_DIR) != 0 ||
229}
230
231static void proxy_dir_get(Editing *ed, Sequence *seq, size_t str_len, char *r_proxy_dirpath)
232{
233 if (use_proxy(ed, seq)) {
235 if (ed->proxy_dir[0] == 0) {
236 BLI_strncpy(r_proxy_dirpath, "//BL_proxy", str_len);
237 }
238 else {
239 BLI_strncpy(r_proxy_dirpath, ed->proxy_dir, str_len);
240 }
241 }
242 else {
243 BLI_strncpy(r_proxy_dirpath, seq->strip->proxy->dirpath, str_len);
244 }
246 }
247}
248
249static void index_dir_set(Editing *ed, Sequence *seq, StripAnim *sanim)
250{
251 if (sanim->anim == nullptr || !use_proxy(ed, seq)) {
252 return;
253 }
254
255 char proxy_dirpath[FILE_MAX];
256 proxy_dir_get(ed, seq, sizeof(proxy_dirpath), proxy_dirpath);
257 seq_proxy_index_dir_set(sanim->anim, proxy_dirpath);
258}
259
260static bool open_anim_file_multiview(Scene *scene, Sequence *seq, const char *filepath)
261{
262 char prefix[FILE_MAX];
263 const char *ext = nullptr;
264 BKE_scene_multiview_view_prefix_get(scene, filepath, prefix, &ext);
265
266 if (seq->views_format != R_IMF_VIEWS_INDIVIDUAL || prefix[0] == '\0') {
267 return false;
268 }
269
270 Editing *ed = scene->ed;
271 bool is_multiview_loaded = false;
272 int totfiles = seq_num_files(scene, seq->views_format, true);
273
274 for (int i = 0; i < totfiles; i++) {
275 const char *suffix = BKE_scene_multiview_view_id_suffix_get(&scene->r, i);
276 char filepath_view[FILE_MAX];
277 SNPRINTF(filepath_view, "%s%s%s", prefix, suffix, ext);
278
279 StripAnim *sanim = static_cast<StripAnim *>(MEM_mallocN(sizeof(StripAnim), "Strip Anim"));
280 /* Multiview files must be loaded, otherwise it is not possible to detect failure. */
281 open_anim_filepath(seq, sanim, filepath_view, true);
282
283 if (sanim->anim == nullptr) {
285 return false; /* Multiview render failed. */
286 }
287
288 index_dir_set(ed, seq, sanim);
289 BLI_addtail(&seq->anims, sanim);
290 IMB_suffix_anim(sanim->anim, suffix);
291 is_multiview_loaded = true;
292 }
293
294 return is_multiview_loaded;
295}
296
297void seq_open_anim_file(Scene *scene, Sequence *seq, bool openfile)
298{
299 if ((seq->anims.first != nullptr) && (((StripAnim *)seq->anims.first)->anim != nullptr) &&
300 !openfile)
301 {
302 return;
303 }
304
305 /* Reset all the previously created anims. */
307
308 Editing *ed = scene->ed;
309 char filepath[FILE_MAX];
310 BLI_path_join(filepath, sizeof(filepath), seq->strip->dirpath, seq->strip->stripdata->filename);
311 BLI_path_abs(filepath, ID_BLEND_PATH_FROM_GLOBAL(&scene->id));
312
313 bool is_multiview = (seq->flag & SEQ_USE_VIEWS) != 0 && (scene->r.scemode & R_MULTIVIEW) != 0;
314 bool multiview_is_loaded = false;
315
316 if (is_multiview) {
317 multiview_is_loaded = open_anim_file_multiview(scene, seq, filepath);
318 }
319
320 if (!is_multiview || !multiview_is_loaded) {
321 StripAnim *sanim = static_cast<StripAnim *>(MEM_mallocN(sizeof(StripAnim), "Strip Anim"));
322 BLI_addtail(&seq->anims, sanim);
323 open_anim_filepath(seq, sanim, filepath, openfile);
324 index_dir_set(ed, seq, sanim);
325 }
326}
327
328const Sequence *SEQ_get_topmost_sequence(const Scene *scene, int frame)
329{
330 Editing *ed = scene->ed;
331
332 if (!ed) {
333 return nullptr;
334 }
335
336 ListBase *channels = SEQ_channels_displayed_get(ed);
337 const Sequence *best_seq = nullptr;
338 int best_machine = -1;
339
340 LISTBASE_FOREACH (const Sequence *, seq, ed->seqbasep) {
341 if (SEQ_render_is_muted(channels, seq) || !SEQ_time_strip_intersects_frame(scene, seq, frame))
342 {
343 continue;
344 }
345 /* Only use strips that generate an image, not ones that combine
346 * other strips or apply some effect. */
347 if (ELEM(seq->type,
354 {
355 if (seq->machine > best_machine) {
356 best_seq = seq;
357 best_machine = seq->machine;
358 }
359 }
360 }
361 return best_seq;
362}
363
365{
366 Editing *ed = SEQ_editing_get(scene);
367 ListBase *main_seqbase = &ed->seqbase;
368 Sequence *seq_meta = seq_sequence_lookup_meta_by_seq(scene, seq);
369
370 if (seq_meta != nullptr) {
371 return &seq_meta->seqbase;
372 }
373 if (BLI_findindex(main_seqbase, seq) != -1) {
374 return main_seqbase;
375 }
376 return nullptr;
377}
378
380{
381 Sequence *iseq;
382
383 for (iseq = static_cast<Sequence *>(seqbase->first); iseq; iseq = iseq->next) {
384 Sequence *seq_found;
385 if ((iseq->strip && iseq->strip->stripdata) &&
386 ARRAY_HAS_ITEM(se, iseq->strip->stripdata, iseq->len))
387 {
388 break;
389 }
390 if ((seq_found = SEQ_sequence_from_strip_elem(&iseq->seqbase, se))) {
391 iseq = seq_found;
392 break;
393 }
394 }
395
396 return iseq;
397}
398
399Sequence *SEQ_get_sequence_by_name(ListBase *seqbase, const char *name, bool recursive)
400{
401 LISTBASE_FOREACH (Sequence *, iseq, seqbase) {
402 if (STREQ(name, iseq->name + 2)) {
403 return iseq;
404 }
405 if (recursive && !BLI_listbase_is_empty(&iseq->seqbase)) {
406 Sequence *rseq = SEQ_get_sequence_by_name(&iseq->seqbase, name, true);
407 if (rseq != nullptr) {
408 return rseq;
409 }
410 }
411 }
412
413 return nullptr;
414}
415
417{
418 Sequence *seq_act = SEQ_select_active_get(scene);
419
420 if (seq_act && seq_act->type == SEQ_TYPE_MASK) {
421 return seq_act->mask;
422 }
423
424 return nullptr;
425}
426
428{
429 if (seq->strip && seq->strip->stripdata) {
430 const char *filename = seq->strip->stripdata->filename;
432 }
433}
434
436{
437 switch (seq->type) {
438 case SEQ_TYPE_MASK:
439 return (seq->mask != nullptr);
441 return (seq->clip != nullptr);
442 case SEQ_TYPE_SCENE:
443 return (seq->scene != nullptr);
445 return (seq->sound != nullptr);
446 }
447
448 return true;
449}
450
452{
453 switch (seq->type) {
454 case SEQ_TYPE_IMAGE:
455 case SEQ_TYPE_SCENE:
456 case SEQ_TYPE_MOVIE:
458 case SEQ_TYPE_MASK:
459 case SEQ_TYPE_COLOR:
460 case SEQ_TYPE_TEXT:
461 return true;
462 }
463 return false;
464}
465
467 const int image_width,
468 const int image_height,
469 const int preview_width,
470 const int preview_height,
471 const eSeqImageFitMethod fit_method)
472{
473 StripTransform *transform = seq->strip->transform;
474
475 switch (fit_method) {
476 case SEQ_SCALE_TO_FIT:
477 transform->scale_x = transform->scale_y = std::min(
478 float(preview_width) / float(image_width), float(preview_height) / float(image_height));
479
480 break;
482
483 transform->scale_x = transform->scale_y = std::max(
484 float(preview_width) / float(image_width), float(preview_height) / float(image_height));
485 break;
487 transform->scale_x = float(preview_width) / float(image_width);
488 transform->scale_y = float(preview_height) / float(image_height);
489 break;
491 transform->scale_x = 1.0f;
492 transform->scale_y = 1.0f;
493 break;
494 }
495}
496
498{
499 char name[SEQ_NAME_MAXSTR];
500
501 STRNCPY_UTF8(name, seq->name + 2);
502 SEQ_sequence_base_unique_name_recursive(scene, &scene->ed->seqbase, seq);
504 scene->adt,
505 nullptr,
506 "sequence_editor.sequences_all",
507 name,
508 seq->name + 2,
509 0,
510 0,
511 false);
512
513 if (seq->type == SEQ_TYPE_META) {
514 LISTBASE_FOREACH (Sequence *, seq_child, &seq->seqbase) {
515 SEQ_ensure_unique_name(seq_child, scene);
516 }
517 }
518}
void BKE_animdata_fix_paths_rename(struct ID *owner_id, struct AnimData *adt, struct ID *ref_id, const char *prefix, const char *oldName, const char *newName, int oldSubscript, int newSubscript, bool verify_paths)
ImBufAnim * openanim_noload(const char *filepath, int flags, int streamindex, char colorspace[IMA_MAX_SPACE])
ImBufAnim * openanim(const char *filepath, int flags, int streamindex, char colorspace[IMA_MAX_SPACE])
char BKE_image_alpha_mode_from_extension_ex(const char *filepath)
const char * BKE_main_blendfile_path_from_global()
Definition main.cc:837
const char * BKE_scene_multiview_view_id_suffix_get(const RenderData *rd, int view_id)
Definition scene.cc:3142
void BKE_scene_multiview_view_prefix_get(Scene *scene, const char *filepath, char *r_prefix, const char **r_ext)
Definition scene.cc:3152
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
#define LISTBASE_FOREACH(type, var, list)
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:110
int BLI_findindex(const struct ListBase *listbase, const void *vlink) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
static constexpr int image_width
static constexpr int image_height
bool BLI_path_abs(char path[FILE_MAX], const char *basepath) ATTR_NONNULL(1
#define FILE_MAX
#define BLI_path_join(...)
#define STRNCPY(dst, src)
Definition BLI_string.h:593
#define SNPRINTF(dst, format,...)
Definition BLI_string.h:597
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy) ATTR_NONNULL(1
#define STRNCPY_UTF8(dst, src)
#define ARRAY_HAS_ITEM(arr_item, arr_start, arr_len)
#define ELEM(...)
#define STREQ(a, b)
#define BLT_I18NCONTEXT_ID_SEQUENCE
#define CTX_DATA_(context, msgid)
#define DATA_(msgid)
#define ID_BLEND_PATH_FROM_GLOBAL(_id)
Definition DNA_ID.h:649
eSeqImageFitMethod
@ SEQ_SCALE_TO_FILL
@ SEQ_STRETCH_TO_FILL
@ SEQ_USE_ORIGINAL_SIZE
@ SEQ_SCALE_TO_FIT
@ R_MULTIVIEW
@ R_IMF_VIEWS_INDIVIDUAL
@ SEQ_STORAGE_PROXY_CUSTOM_DIR
@ SEQ_TYPE_TRANSFORM
@ SEQ_TYPE_SOUND_RAM
@ SEQ_TYPE_CROSS
@ SEQ_TYPE_GLOW
@ SEQ_TYPE_COLORMIX
@ SEQ_TYPE_WIPE
@ SEQ_TYPE_META
@ SEQ_TYPE_OVERDROP
@ SEQ_TYPE_ALPHAUNDER
@ SEQ_TYPE_SCENE
@ SEQ_TYPE_GAMCROSS
@ SEQ_TYPE_MULTICAM
@ SEQ_TYPE_MOVIECLIP
@ SEQ_TYPE_MUL
@ SEQ_TYPE_GAUSSIAN_BLUR
@ SEQ_TYPE_ADD
@ SEQ_TYPE_ALPHAOVER
@ SEQ_TYPE_TEXT
@ SEQ_TYPE_IMAGE
@ SEQ_TYPE_SUB
@ SEQ_TYPE_SPEED
@ SEQ_TYPE_COLOR
@ SEQ_TYPE_EFFECT
@ SEQ_TYPE_MOVIE
@ SEQ_TYPE_MASK
@ SEQ_TYPE_ADJUSTMENT
#define SEQ_NAME_MAXSTR
@ SEQ_EDIT_PROXY_DIR_STORAGE
@ SEQ_FILTERY
@ SEQ_SCENE_STRIPS
@ SEQ_USE_VIEWS
void IMB_suffix_anim(ImBufAnim *anim, const char *suffix)
Contains defines and structs used throughout the imbuf module.
@ IB_animdeinterlace
@ IB_rect
Read Guarded memory(de)allocation.
ListBase * SEQ_channels_displayed_get(Editing *ed)
Definition channels.cc:23
additional_info("compositor_sum_squared_difference_float_shared") .push_constant(Type output_img float dot(value.rgb, luminance_coefficients)") .define("LOAD(value)"
draw_view in_light_buf[] float
void SEQ_for_each_callback(ListBase *seqbase, SeqForEachFunc callback, void *user_data)
Definition iterator.cc:43
void *(* MEM_mallocN)(size_t len, const char *str)
Definition mallocn.cc:44
int seq_num_files(Scene *scene, char views_format, const bool is_multiview)
Definition multiview.cc:27
void seq_proxy_index_dir_set(ImBufAnim *anim, const char *base_dir)
Definition proxy.cc:604
bool SEQ_render_is_muted(const ListBase *channels, const Sequence *seq)
Definition render.cc:2154
Sequence * seq_sequence_lookup_meta_by_seq(const Scene *scene, const Sequence *key)
bool sequencer_seq_generates_image(Sequence *seq)
const char * SEQ_sequence_give_name(const Sequence *seq)
static void proxy_dir_get(Editing *ed, Sequence *seq, size_t str_len, char *r_proxy_dirpath)
ListBase * SEQ_get_seqbase_by_seq(const Scene *scene, Sequence *seq)
Sequence * SEQ_get_sequence_by_name(ListBase *seqbase, const char *name, bool recursive)
void SEQ_sequence_base_unique_name_recursive(Scene *scene, ListBase *seqbasep, Sequence *seq)
static void seqbase_unique_name(ListBase *seqbasep, SeqUniqueInfo *sui)
void seq_open_anim_file(Scene *scene, Sequence *seq, bool openfile)
static const char * give_seqname_by_type(int type)
void SEQ_alpha_mode_from_file_extension(Sequence *seq)
ListBase * SEQ_get_seqbase_from_sequence(Sequence *seq, ListBase **r_channels, int *r_offset)
static bool open_anim_file_multiview(Scene *scene, Sequence *seq, const char *filepath)
static void open_anim_filepath(Sequence *seq, StripAnim *sanim, const char *filepath, bool openfile)
void SEQ_set_scale_to_fit(const Sequence *seq, const int image_width, const int image_height, const int preview_width, const int preview_height, const eSeqImageFitMethod fit_method)
Sequence * SEQ_sequence_from_strip_elem(ListBase *seqbase, StripElem *se)
static bool seqbase_unique_name_recursive_fn(Sequence *seq, void *arg_pt)
void SEQ_ensure_unique_name(Sequence *seq, Scene *scene)
bool SEQ_sequence_has_valid_data(const Sequence *seq)
const Sequence * SEQ_get_topmost_sequence(const Scene *scene, int frame)
Mask * SEQ_active_mask_get(Scene *scene)
static bool use_proxy(Editing *ed, Sequence *seq)
static void index_dir_set(Editing *ed, Sequence *seq, StripAnim *sanim)
Editing * SEQ_editing_get(const Scene *scene)
Definition sequencer.cc:262
void SEQ_edit_sequence_name_set(Scene *scene, Sequence *seq, const char *new_name)
void SEQ_relations_sequence_free_anim(Sequence *seq)
Sequence * SEQ_select_active_get(const Scene *scene)
bool SEQ_time_strip_intersects_frame(const Scene *scene, const Sequence *seq, const int timeline_frame)
float SEQ_time_start_frame_get(const Sequence *seq)
ListBase seqbase
ListBase * seqbasep
ListBase channels
char proxy_dir[1024]
void * first
struct RenderData r
char name_dest[SEQ_NAME_MAXSTR]
char name_src[SEQ_NAME_MAXSTR]
struct MovieClip * clip
struct Scene * scene
struct Mask * mask
ListBase channels
struct bSound * sound
struct Sequence * next
struct ImBufAnim * anim
char filename[256]
char dirpath[768]
ColorManagedColorspaceSettings colorspace_settings
char dirpath[768]
StripProxy * proxy
StripTransform * transform
StripElem * stripdata