Blender V5.0
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
10
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_listbase.h"
21#include "BLI_path_utils.hh"
22#include "BLI_string.h"
23#include "BLI_string_utf8.h"
24
25#include "BLT_translation.hh"
26
27#include "BKE_animsys.h"
28#include "BKE_image.hh"
29#include "BKE_library.hh"
30#include "BKE_main.hh"
31#include "BKE_scene.hh"
32
33#include "SEQ_channels.hh"
34#include "SEQ_edit.hh"
35#include "SEQ_iterator.hh"
36#include "SEQ_relations.hh"
37#include "SEQ_render.hh"
38#include "SEQ_select.hh"
39#include "SEQ_sequencer.hh"
40#include "SEQ_time.hh"
41#include "SEQ_utils.hh"
42
43#include "IMB_imbuf_types.hh"
44
45#include "MOV_read.hh"
46
47#include "multiview.hh"
48#include "proxy.hh"
49#include "sequencer.hh"
50#include "utils.hh"
51
52namespace blender::seq {
53
61
62static void seqbase_unique_name(ListBase *seqbasep, StripUniqueInfo *sui)
63{
64 LISTBASE_FOREACH (Strip *, strip, seqbasep) {
65 if ((sui->strip != strip) && STREQ(sui->name_dest, strip->name + 2)) {
66 /* STRIP_NAME_MAXSTR -4 for the number, -1 for \0, - 2 for r_prefix */
68 sui->name_dest, "%.*s.%03d", STRIP_NAME_MAXSTR - 4 - 1 - 2, sui->name_src, sui->count++);
69 sui->match = 1; /* be sure to re-scan */
70 }
71 }
72}
73
74static bool seqbase_unique_name_recursive_fn(Strip *strip, void *arg_pt)
75{
76 if (strip->seqbase.first) {
78 }
79 return true;
80}
81
82void strip_unique_name_set(Scene *scene, ListBase *seqbasep, Strip *strip)
83{
85 char *dot;
86 sui.strip = strip;
87 STRNCPY(sui.name_src, strip->name + 2);
88 STRNCPY(sui.name_dest, strip->name + 2);
89
90 sui.count = 1;
91 sui.match = 1; /* assume the worst to start the loop */
92
93 /* Strip off the suffix */
94 if ((dot = strrchr(sui.name_src, '.'))) {
95 *dot = '\0';
96 dot++;
97
98 if (*dot) {
99 sui.count = atoi(dot) + 1;
100 }
101 }
102
103 while (sui.match) {
104 sui.match = 0;
105 seqbase_unique_name(seqbasep, &sui);
107 }
108
109 edit_strip_name_set(scene, strip, sui.name_dest);
110}
111
112const char *get_default_stripname_by_type(int type)
113{
114 switch (type) {
115 case STRIP_TYPE_META:
117 case STRIP_TYPE_IMAGE:
118 return CTX_DATA_(BLT_I18NCONTEXT_ID_SEQUENCE, "Image");
119 case STRIP_TYPE_SCENE:
120 return CTX_DATA_(BLT_I18NCONTEXT_ID_SEQUENCE, "Scene");
121 case STRIP_TYPE_MOVIE:
122 return CTX_DATA_(BLT_I18NCONTEXT_ID_SEQUENCE, "Movie");
125 case STRIP_TYPE_MASK:
128 return CTX_DATA_(BLT_I18NCONTEXT_ID_SEQUENCE, "Audio");
129 case STRIP_TYPE_CROSS:
130 return CTX_DATA_(BLT_I18NCONTEXT_ID_SEQUENCE, "Crossfade");
132 return CTX_DATA_(BLT_I18NCONTEXT_ID_SEQUENCE, "Gamma Crossfade");
133 case STRIP_TYPE_ADD:
135 case STRIP_TYPE_SUB:
136 return CTX_DATA_(BLT_I18NCONTEXT_ID_SEQUENCE, "Subtract");
137 case STRIP_TYPE_MUL:
138 return CTX_DATA_(BLT_I18NCONTEXT_ID_SEQUENCE, "Multiply");
140 return CTX_DATA_(BLT_I18NCONTEXT_ID_SEQUENCE, "Alpha Over");
142 return CTX_DATA_(BLT_I18NCONTEXT_ID_SEQUENCE, "Alpha Under");
144 return CTX_DATA_(BLT_I18NCONTEXT_ID_SEQUENCE, "Color Mix");
145 case STRIP_TYPE_WIPE:
147 case STRIP_TYPE_GLOW:
149 case STRIP_TYPE_COLOR:
150 return CTX_DATA_(BLT_I18NCONTEXT_ID_SEQUENCE, "Color");
152 return CTX_DATA_(BLT_I18NCONTEXT_ID_SEQUENCE, "Multicam");
154 return CTX_DATA_(BLT_I18NCONTEXT_ID_SEQUENCE, "Adjustment");
155 case STRIP_TYPE_SPEED:
156 return CTX_DATA_(BLT_I18NCONTEXT_ID_SEQUENCE, "Speed");
158 return CTX_DATA_(BLT_I18NCONTEXT_ID_SEQUENCE, "Gaussian Blur");
159 case STRIP_TYPE_TEXT:
161 default:
162 return nullptr;
163 }
164}
165
166const char *strip_give_name(const Strip *strip)
167{
168 const char *name = get_default_stripname_by_type(strip->type);
169
170 if (!name) {
171 if (!strip->is_effect()) {
172 return strip->data->dirpath;
173 }
174
175 return DATA_("Effect");
176 }
177 return name;
178}
179
180ListBase *get_seqbase_from_strip(Strip *strip, ListBase **r_channels, int *r_offset)
181{
182 ListBase *seqbase = nullptr;
183
184 switch (strip->type) {
185 case STRIP_TYPE_META: {
186 seqbase = &strip->seqbase;
187 *r_channels = &strip->channels;
188 *r_offset = time_start_frame_get(strip);
189 break;
190 }
191 case STRIP_TYPE_SCENE: {
192 if (strip->flag & SEQ_SCENE_STRIPS && strip->scene) {
193 Editing *ed = editing_get(strip->scene);
194 if (ed) {
195 seqbase = &ed->seqbase;
196 *r_channels = &ed->channels;
197 *r_offset = strip->scene->r.sfra;
198 }
199 }
200 break;
201 }
202 }
203
204 return seqbase;
205}
206
207static void open_anim_filepath(Strip *strip, StripAnim *sanim, const char *filepath, bool openfile)
208{
209 /* Sequencer takes care of colorspace conversion of the result. The input is the best to be
210 * kept unchanged for the performance reasons. */
211 if (openfile) {
212 sanim->anim = openanim(filepath,
213 IB_byte_data | ((strip->flag & SEQ_FILTERY) ? IB_animdeinterlace : 0),
214 strip->streamindex,
215 true,
217 }
218 else {
219 sanim->anim = openanim_noload(filepath,
221 ((strip->flag & SEQ_FILTERY) ? IB_animdeinterlace : 0),
222 strip->streamindex,
223 true,
225 }
226}
227
228static bool use_proxy(Editing *ed, Strip *strip)
229{
230 StripProxy *proxy = strip->data->proxy;
231 return proxy && ((proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_DIR) != 0 ||
232 (ed->proxy_storage == SEQ_EDIT_PROXY_DIR_STORAGE));
233}
234
235static void proxy_dir_get(Editing *ed, Strip *strip, char r_proxy_dirpath[FILE_MAX])
236{
237 if (use_proxy(ed, strip)) {
238 if (ed->proxy_storage == SEQ_EDIT_PROXY_DIR_STORAGE) {
239 if (ed->proxy_dir[0] == 0) {
240 BLI_strncpy(r_proxy_dirpath, "//BL_proxy", FILE_MAX);
241 }
242 else {
243 BLI_strncpy(r_proxy_dirpath, ed->proxy_dir, FILE_MAX);
244 }
245 }
246 else {
247 BLI_strncpy(r_proxy_dirpath, strip->data->proxy->dirpath, FILE_MAX);
248 }
250 }
251}
252
253static void index_dir_set(Editing *ed, Strip *strip, StripAnim *sanim)
254{
255 if (sanim->anim == nullptr || !use_proxy(ed, strip)) {
256 return;
257 }
258
259 char proxy_dirpath[FILE_MAX];
260 proxy_dir_get(ed, strip, proxy_dirpath);
261 seq_proxy_index_dir_set(sanim->anim, proxy_dirpath);
262}
263
264static bool open_anim_file_multiview(Scene *scene, Strip *strip, const char *filepath)
265{
266 char prefix[FILE_MAX];
267 const char *ext = nullptr;
268 BKE_scene_multiview_view_prefix_get(scene, filepath, prefix, &ext);
269
270 if (strip->views_format != R_IMF_VIEWS_INDIVIDUAL || prefix[0] == '\0') {
271 return false;
272 }
273
274 Editing *ed = scene->ed;
275 bool is_multiview_loaded = false;
276 int totfiles = seq_num_files(scene, strip->views_format, true);
277
278 for (int i = 0; i < totfiles; i++) {
279 const char *suffix = BKE_scene_multiview_view_id_suffix_get(&scene->r, i);
280 char filepath_view[FILE_MAX];
281 SNPRINTF(filepath_view, "%s%s%s", prefix, suffix, ext);
282
283 StripAnim *sanim = MEM_mallocN<StripAnim>("Strip Anim");
284 /* Multiview files must be loaded, otherwise it is not possible to detect failure. */
285 open_anim_filepath(strip, sanim, filepath_view, true);
286
287 if (sanim->anim == nullptr) {
289 return false; /* Multiview render failed. */
290 }
291
292 index_dir_set(ed, strip, sanim);
293 BLI_addtail(&strip->anims, sanim);
294 MOV_set_multiview_suffix(sanim->anim, suffix);
295 is_multiview_loaded = true;
296 }
297
298 return is_multiview_loaded;
299}
300
301void strip_open_anim_file(Scene *scene, Strip *strip, bool openfile)
302{
303 if ((strip->anims.first != nullptr) && (((StripAnim *)strip->anims.first)->anim != nullptr) &&
304 !openfile)
305 {
306 return;
307 }
308
309 /* Reset all the previously created anims. */
311
312 Editing *ed = scene->ed;
313 char filepath[FILE_MAX];
315 filepath, sizeof(filepath), strip->data->dirpath, strip->data->stripdata->filename);
316 BLI_path_abs(filepath, ID_BLEND_PATH_FROM_GLOBAL(&scene->id));
317
318 bool is_multiview = (strip->flag & SEQ_USE_VIEWS) != 0 && (scene->r.scemode & R_MULTIVIEW) != 0;
319 bool multiview_is_loaded = false;
320
321 if (is_multiview) {
322 multiview_is_loaded = open_anim_file_multiview(scene, strip, filepath);
323 }
324
325 if (!is_multiview || !multiview_is_loaded) {
326 StripAnim *sanim = MEM_mallocN<StripAnim>("Strip Anim");
327 BLI_addtail(&strip->anims, sanim);
328 open_anim_filepath(strip, sanim, filepath, openfile);
329 index_dir_set(ed, strip, sanim);
330 }
331}
332
333const Strip *strip_topmost_get(const Scene *scene, int frame)
334{
335 Editing *ed = scene->ed;
336
337 if (!ed) {
338 return nullptr;
339 }
340
342 const Strip *best_strip = nullptr;
343 int best_channel = -1;
344
345 LISTBASE_FOREACH (const Strip *, strip, ed->current_strips()) {
346 if (render_is_muted(channels, strip) || !time_strip_intersects_frame(scene, strip, frame)) {
347 continue;
348 }
349 /* Only use strips that generate an image, not ones that combine
350 * other strips or apply some effect. */
351 if (ELEM(strip->type,
358 {
359 if (strip->channel > best_channel) {
360 best_strip = strip;
361 best_channel = strip->channel;
362 }
363 }
364 }
365 return best_strip;
366}
367
369{
370 Editing *ed = editing_get(scene);
371 ListBase *main_seqbase = &ed->seqbase;
372 Strip *strip_meta = lookup_meta_by_strip(ed, strip);
373
374 if (strip_meta != nullptr) {
375 return &strip_meta->seqbase;
376 }
377 if (BLI_findindex(main_seqbase, strip) != -1) {
378 return main_seqbase;
379 }
380 return nullptr;
381}
382
384{
385 Strip *istrip;
386
387 for (istrip = static_cast<Strip *>(seqbase->first); istrip; istrip = istrip->next) {
388 Strip *strip_found;
389 if ((istrip->data && istrip->data->stripdata) &&
390 ARRAY_HAS_ITEM(se, istrip->data->stripdata, istrip->len))
391 {
392 break;
393 }
394 if ((strip_found = strip_from_strip_elem(&istrip->seqbase, se))) {
395 istrip = strip_found;
396 break;
397 }
398 }
399
400 return istrip;
401}
402
403Strip *get_strip_by_name(ListBase *seqbase, const char *name, bool recursive)
404{
405 LISTBASE_FOREACH (Strip *, istrip, seqbase) {
406 if (STREQ(name, istrip->name + 2)) {
407 return istrip;
408 }
409 if (recursive && !BLI_listbase_is_empty(&istrip->seqbase)) {
410 Strip *rseq = get_strip_by_name(&istrip->seqbase, name, true);
411 if (rseq != nullptr) {
412 return rseq;
413 }
414 }
415 }
416
417 return nullptr;
418}
419
421{
422 Strip *strip_act = select_active_get(scene);
423
424 if (strip_act && strip_act->type == STRIP_TYPE_MASK) {
425 return strip_act->mask;
426 }
427
428 return nullptr;
429}
430
432{
433 if (strip->data && strip->data->stripdata) {
434 const char *filename = strip->data->stripdata->filename;
436 }
437}
438
439bool strip_has_valid_data(const Strip *strip)
440{
441 switch (strip->type) {
442 case STRIP_TYPE_MASK:
443 return (strip->mask != nullptr);
445 return (strip->clip != nullptr);
446 case STRIP_TYPE_SCENE:
447 return (strip->scene != nullptr);
449 return (strip->sound != nullptr);
450 }
451
452 return true;
453}
454
456{
457 switch (strip->type) {
458 case STRIP_TYPE_IMAGE:
459 case STRIP_TYPE_SCENE:
460 case STRIP_TYPE_MOVIE:
462 case STRIP_TYPE_MASK:
463 case STRIP_TYPE_COLOR:
464 case STRIP_TYPE_TEXT:
465 return true;
466 }
467 return false;
468}
469
470void set_scale_to_fit(const Strip *strip,
471 const int image_width,
472 const int image_height,
473 const int preview_width,
474 const int preview_height,
475 const eSeqImageFitMethod fit_method)
476{
478
479 switch (fit_method) {
480 case SEQ_SCALE_TO_FIT:
481 transform->scale_x = transform->scale_y = std::min(
482 float(preview_width) / float(image_width), float(preview_height) / float(image_height));
483
484 break;
486
487 transform->scale_x = transform->scale_y = std::max(
488 float(preview_width) / float(image_width), float(preview_height) / float(image_height));
489 break;
491 transform->scale_x = float(preview_width) / float(image_width);
492 transform->scale_y = float(preview_height) / float(image_height);
493 break;
495 transform->scale_x = 1.0f;
496 transform->scale_y = 1.0f;
497 break;
498 }
499}
500
501void ensure_unique_name(Strip *strip, Scene *scene)
502{
504
505 STRNCPY_UTF8(name, strip->name + 2);
506 strip_unique_name_set(scene, &scene->ed->seqbase, strip);
508 scene->adt,
509 nullptr,
510 "sequence_editor.strips_all",
511 name,
512 strip->name + 2,
513 0,
514 0,
515 false);
516
517 if (strip->type == STRIP_TYPE_META) {
518 LISTBASE_FOREACH (Strip *, strip_child, &strip->seqbase) {
519 ensure_unique_name(strip_child, scene);
520 }
521 }
522}
523
524} // namespace blender::seq
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)
MovieReader * openanim(const char *filepath, int ibuf_flags, int streamindex, bool keep_original_colorspace, char colorspace[IMA_MAX_SPACE])
char BKE_image_alpha_mode_from_extension_ex(const char *filepath)
MovieReader * openanim_noload(const char *filepath, int flags, int streamindex, bool keep_original_colorspace, char colorspace[IMA_MAX_SPACE])
const char * BKE_main_blendfile_path_from_global()
Definition main.cc:892
const char * BKE_scene_multiview_view_id_suffix_get(const RenderData *rd, int view_id)
Definition scene.cc:3154
void BKE_scene_multiview_view_prefix_get(Scene *scene, const char *filepath, char *r_prefix, const char **r_ext)
Definition scene.cc:3164
int BLI_findindex(const ListBase *listbase, const void *vlink) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:586
#define LISTBASE_FOREACH(type, var, list)
BLI_INLINE bool BLI_listbase_is_empty(const ListBase *lb)
void BLI_addtail(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:111
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 SNPRINTF(dst, format,...)
Definition BLI_string.h:604
char * STRNCPY(char(&dst)[N], const char *src)
Definition BLI_string.h:693
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:688
eSeqImageFitMethod
@ SEQ_SCALE_TO_FILL
@ SEQ_STRETCH_TO_FILL
@ SEQ_USE_ORIGINAL_SIZE
@ SEQ_SCALE_TO_FIT
@ R_IMF_VIEWS_INDIVIDUAL
@ R_MULTIVIEW
@ SEQ_EDIT_PROXY_DIR_STORAGE
@ SEQ_STORAGE_PROXY_CUSTOM_DIR
#define STRIP_NAME_MAXSTR
@ STRIP_TYPE_GAUSSIAN_BLUR
@ STRIP_TYPE_GAMCROSS
@ STRIP_TYPE_SCENE
@ STRIP_TYPE_MOVIECLIP
@ STRIP_TYPE_COLORMIX
@ STRIP_TYPE_WIPE
@ STRIP_TYPE_TEXT
@ STRIP_TYPE_SOUND_RAM
@ STRIP_TYPE_ADD
@ STRIP_TYPE_IMAGE
@ STRIP_TYPE_MOVIE
@ STRIP_TYPE_GLOW
@ STRIP_TYPE_SUB
@ STRIP_TYPE_MUL
@ STRIP_TYPE_SPEED
@ STRIP_TYPE_COLOR
@ STRIP_TYPE_ADJUSTMENT
@ STRIP_TYPE_META
@ STRIP_TYPE_MULTICAM
@ STRIP_TYPE_MASK
@ STRIP_TYPE_ALPHAUNDER
@ STRIP_TYPE_CROSS
@ STRIP_TYPE_ALPHAOVER
@ SEQ_FILTERY
@ SEQ_SCENE_STRIPS
@ SEQ_USE_VIEWS
@ IB_animdeinterlace
@ IB_byte_data
Read Guarded memory(de)allocation.
SIMD_FORCE_INLINE btVector3 transform(const btVector3 &point) const
nullptr float
dot(value.rgb, luminance_coefficients)") DEFINE_VALUE("REDUCE(lhs
void * MEM_mallocN(size_t len, const char *str)
Definition mallocn.cc:128
void MOV_set_multiview_suffix(MovieReader *anim, const char *suffix)
bool render_is_muted(const ListBase *channels, const Strip *strip)
Definition render.cc:2110
void relations_strip_free_anim(Strip *strip)
Strip * lookup_meta_by_strip(Editing *ed, const Strip *key)
void foreach_strip(ListBase *seqbase, ForEachFunc callback, void *user_data)
Definition iterator.cc:59
bool sequencer_strip_generates_image(Strip *strip)
static void open_anim_filepath(Strip *strip, StripAnim *sanim, const char *filepath, bool openfile)
ListBase * channels_displayed_get(const Editing *ed)
Definition channels.cc:28
const Strip * strip_topmost_get(const Scene *scene, int frame)
static bool use_proxy(Editing *ed, Strip *strip)
Editing * editing_get(const Scene *scene)
Definition sequencer.cc:286
Strip * strip_from_strip_elem(ListBase *seqbase, StripElem *se)
ListBase * get_seqbase_by_strip(const Scene *scene, Strip *strip)
void edit_strip_name_set(Scene *scene, Strip *strip, const char *new_name)
void strip_open_anim_file(Scene *scene, Strip *strip, bool openfile)
const char * strip_give_name(const Strip *strip)
float time_start_frame_get(const Strip *strip)
Strip * select_active_get(const Scene *scene)
bool strip_has_valid_data(const Strip *strip)
void seq_proxy_index_dir_set(MovieReader *anim, const char *base_dir)
Definition proxy.cc:626
bool time_strip_intersects_frame(const Scene *scene, const Strip *strip, const int timeline_frame)
const char * get_default_stripname_by_type(int type)
Strip * get_strip_by_name(ListBase *seqbase, const char *name, bool recursive)
static void seqbase_unique_name(ListBase *seqbasep, StripUniqueInfo *sui)
void strip_unique_name_set(Scene *scene, ListBase *seqbasep, Strip *strip)
static bool seqbase_unique_name_recursive_fn(Strip *strip, void *arg_pt)
static void index_dir_set(Editing *ed, Strip *strip, StripAnim *sanim)
void alpha_mode_from_file_extension(Strip *strip)
void ensure_unique_name(Strip *strip, Scene *scene)
Mask * active_mask_get(Scene *scene)
ListBase * get_seqbase_from_strip(Strip *strip, ListBase **r_channels, int *r_offset)
int seq_num_files(Scene *scene, char views_format, const bool is_multiview)
Definition multiview.cc:29
static void proxy_dir_get(Editing *ed, Strip *strip, char r_proxy_dirpath[FILE_MAX])
void set_scale_to_fit(const Strip *strip, const int image_width, const int image_height, const int preview_width, const int preview_height, const eSeqImageFitMethod fit_method)
static bool open_anim_file_multiview(Scene *scene, Strip *strip, const char *filepath)
const char * name
ListBase seqbase
void * first
struct Editing * ed
struct RenderData r
struct AnimData * adt
struct MovieReader * anim
StripProxy * proxy
StripTransform * transform
StripElem * stripdata
char dirpath[768]
ColorManagedColorspaceSettings colorspace_settings
char filename[256]
struct Mask * mask
StripData * data
struct Scene * scene
struct MovieClip * clip
struct bSound * sound
ListBase seqbase
struct Strip * next
short streamindex
char name[64]
ListBase channels
ListBase anims
i
Definition text_draw.cc:230