Blender V4.5
sequencer.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#define DNA_DEPRECATED_ALLOW
12
13#include "BKE_duplilist.hh"
14#include "BLI_assert.h"
15#include "BLI_map.hh"
16#include "DNA_listBase.h"
17#include "SEQ_transform.hh"
18#include <cstddef>
19
20#include "MEM_guardedalloc.h"
21
22#include "DNA_scene_types.h"
23#include "DNA_sequence_types.h"
24#include "DNA_sound_types.h"
25
26#include "BLI_listbase.h"
27#include "BLI_path_utils.hh"
28
29#include "BKE_fcurve.hh"
30#include "BKE_idprop.hh"
31#include "BKE_lib_id.hh"
32#include "BKE_main.hh"
33#include "BKE_scene.hh"
34#include "BKE_sound.h"
35
36#include "DEG_depsgraph.hh"
37
38#include "MOV_read.hh"
39
40#include "SEQ_channels.hh"
41#include "SEQ_connect.hh"
42#include "SEQ_edit.hh"
43#include "SEQ_effects.hh"
44#include "SEQ_iterator.hh"
45#include "SEQ_modifier.hh"
46#include "SEQ_proxy.hh"
47#include "SEQ_relations.hh"
48#include "SEQ_retiming.hh"
49#include "SEQ_select.hh"
50#include "SEQ_sequencer.hh"
51#include "SEQ_sound.hh"
53#include "SEQ_time.hh"
54#include "SEQ_utils.hh"
55
56#include "BLO_read_write.hh"
57
61#include "prefetch.hh"
62#include "sequencer.hh"
63#include "utils.hh"
64
65namespace blender::seq {
66
67/* -------------------------------------------------------------------- */
70
72{
73 StripProxy *strip_proxy = MEM_callocN<StripProxy>("StripProxy");
74 strip_proxy->quality = 50;
76 strip_proxy->tc = SEQ_PROXY_TC_RECORD_RUN;
77 return strip_proxy;
78}
79
80static StripData *seq_strip_alloc(int type)
81{
83
84 if (type != STRIP_TYPE_SOUND_RAM) {
85 data->transform = MEM_callocN<StripTransform>("StripTransform");
86 data->transform->scale_x = 1;
87 data->transform->scale_y = 1;
88 data->transform->origin[0] = 0.5f;
89 data->transform->origin[1] = 0.5f;
90 data->transform->filter = SEQ_TRANSFORM_FILTER_AUTO;
91 data->crop = MEM_callocN<StripCrop>("StripCrop");
92 }
93
94 data->us = 1;
95 return data;
96}
97
99{
100 data->us--;
101 if (data->us > 0) {
102 return;
103 }
104 if (data->us < 0) {
105 printf("error: negative users in strip\n");
106 return;
107 }
108
109 if (data->stripdata) {
110 MEM_freeN(data->stripdata);
111 }
112
113 if (data->proxy) {
114 if (data->proxy->anim) {
115 MOV_close(data->proxy->anim);
116 }
117
118 MEM_freeN(data->proxy);
119 }
120 if (data->crop) {
121 MEM_freeN(data->crop);
122 }
123 if (data->transform) {
124 MEM_freeN(data->transform);
125 }
126
128}
129
130Strip *strip_alloc(ListBase *lb, int timeline_frame, int channel, int type)
131{
132 Strip *strip;
133
134 strip = MEM_callocN<Strip>("addseq");
135 BLI_addtail(lb, strip);
136
137 *((short *)strip->name) = ID_SEQ;
138 strip->name[2] = 0;
139
140 strip->flag = SELECT;
141 strip->start = timeline_frame;
142 strip_channel_set(strip, channel);
143 strip->sat = 1.0;
144 strip->mul = 1.0;
145 strip->blend_opacity = 100.0;
146 strip->volume = 1.0f;
147 strip->scene_sound = nullptr;
148 strip->type = type;
149 strip->media_playback_rate = 0.0f;
150 strip->speed_factor = 1.0f;
151
152 if (strip->type == STRIP_TYPE_ADJUSTMENT) {
154 }
155 else {
157 }
158
159 strip->data = seq_strip_alloc(type);
160 strip->stereo3d_format = MEM_callocN<Stereo3dFormat>("Sequence Stereo Format");
161
163
164 if (strip->type == STRIP_TYPE_META) {
165 channels_ensure(&strip->channels);
166 }
167
169
170 return strip;
171}
172
173/* only give option to skip cache locally (static func) */
174static void seq_strip_free_ex(Scene *scene,
175 Strip *strip,
176 const bool do_cache,
177 const bool do_id_user)
178{
179 if (strip->data) {
180 seq_free_strip(strip->data);
181 }
182
184
185 if (strip->type & STRIP_TYPE_EFFECT) {
187 sh.free(strip, do_id_user);
188 }
189
190 if (strip->sound && do_id_user) {
191 id_us_min((ID *)strip->sound);
192 }
193
194 if (strip->stereo3d_format) {
196 }
197
198 /* clipboard has no scene and will never have a sound handle or be active
199 * same goes to sequences copy for proxy rebuild job
200 */
201 if (scene) {
202 Editing *ed = scene->ed;
203
204 if (ed->act_strip == strip) {
205 ed->act_strip = nullptr;
206 }
207
210 }
211 }
212
213 if (strip->prop) {
214 IDP_FreePropertyContent_ex(strip->prop, do_id_user);
215 MEM_freeN(strip->prop);
216 }
217 if (strip->system_properties) {
220 }
221
222 /* free modifiers */
223 modifier_clear(strip);
224
225 if (is_strip_connected(strip)) {
226 disconnect(strip);
227 }
228
229 /* free cached data used by this strip,
230 * also invalidate cache for all dependent sequences
231 *
232 * be _very_ careful here, invalidating cache loops over the scene sequences and
233 * assumes the listbase is valid for all strips,
234 * this may not be the case if lists are being freed.
235 * this is optional SEQ_relations_invalidate_cache
236 */
237 if (do_cache) {
238 if (scene) {
239 relations_invalidate_cache_raw(scene, strip);
240 }
241 }
242 if (strip->type == STRIP_TYPE_META) {
243 channels_free(&strip->channels);
244 }
245
246 if (strip->retiming_keys != nullptr) {
247 MEM_freeN(strip->retiming_keys);
248 strip->retiming_keys = nullptr;
249 strip->retiming_keys_num = 0;
250 }
251
252 MEM_freeN(strip);
253}
254
255void strip_free(Scene *scene, Strip *strip)
256{
257 seq_strip_free_ex(scene, strip, true, true);
258}
259
260void seq_free_strip_recurse(Scene *scene, Strip *strip, const bool do_id_user)
261{
262 Strip *istrip, *istrip_next;
263
264 for (istrip = static_cast<Strip *>(strip->seqbase.first); istrip; istrip = istrip_next) {
265 istrip_next = istrip->next;
266 seq_free_strip_recurse(scene, istrip, do_id_user);
267 }
268
269 seq_strip_free_ex(scene, strip, false, do_id_user);
270}
271
273{
274 return scene->ed;
275}
276
278{
279 if (scene->ed == nullptr) {
280 Editing *ed;
281
282 ed = scene->ed = MEM_callocN<Editing>("addseq");
283 ed->seqbasep = &ed->seqbase;
285 ed->show_missing_media_flag = SEQ_EDIT_SHOW_MISSING_MEDIA;
286 ed->displayed_channels = &ed->channels;
287 channels_ensure(ed->displayed_channels);
288 }
289
290 return scene->ed;
291}
292
293void editing_free(Scene *scene, const bool do_id_user)
294{
295 Editing *ed = scene->ed;
296
297 if (ed == nullptr) {
298 return;
299 }
300
301 seq_prefetch_free(scene);
302
303 /* handle cache freeing above */
304 LISTBASE_FOREACH_MUTABLE (Strip *, strip, &ed->seqbase) {
305 seq_free_strip_recurse(scene, strip, do_id_user);
306 }
307
308 BLI_freelistN(&ed->metastack);
315 channels_free(&ed->channels);
316
317 MEM_freeN(ed);
318
319 scene->ed = nullptr;
320}
321
323{
324 if (strip->type & STRIP_TYPE_EFFECT) {
325 strip->input1 = strip_map.lookup_default(strip->input1, strip->input1);
326 strip->input2 = strip_map.lookup_default(strip->input2, strip->input2);
327 }
328
330 smd->mask_strip = strip_map.lookup_default(smd->mask_strip, smd->mask_strip);
331 }
332
333 if (is_strip_connected(strip)) {
335 con->strip_ref = strip_map.lookup_default(con->strip_ref, con->strip_ref);
336 }
337 }
338
339 if (strip->type == STRIP_TYPE_META) {
340 LISTBASE_FOREACH (Strip *, strip_n, &strip->seqbase) {
341 seq_new_fix_links_recursive(strip_n, strip_map);
342 }
343 }
344}
345
361
363{
365 if (tool_settings == nullptr) {
367 tool_settings = scene->toolsettings->sequencer_tool_settings;
368 }
369
370 return tool_settings;
371}
372
374{
375 MEM_freeN(tool_settings);
376}
377
379{
380 const SequencerToolSettings *tool_settings = tool_settings_ensure(scene);
381 return eSeqImageFitMethod(tool_settings->fit_method);
382}
383
385{
386 const SequencerToolSettings *tool_settings = tool_settings_ensure(scene);
387 return tool_settings->snap_mode;
388}
389
391{
392 const SequencerToolSettings *tool_settings = tool_settings_ensure(scene);
393 return tool_settings->snap_flag;
394}
395
397{
398 const SequencerToolSettings *tool_settings = tool_settings_ensure(scene);
399 return tool_settings->snap_distance;
400}
401
403{
404 SequencerToolSettings *tool_settings = tool_settings_ensure(scene);
405 tool_settings->fit_method = fit_method;
406}
407
409{
410 const SequencerToolSettings *tool_settings = tool_settings_ensure(scene);
411 return eSeqOverlapMode(tool_settings->overlap_mode);
412}
413
415{
416 const SequencerToolSettings *tool_settings = tool_settings_ensure(scene);
417 return tool_settings->pivot_point;
418}
419
421{
422 if (ed == nullptr) {
423 return nullptr;
424 }
425
426 return ed->seqbasep;
427}
428
430{
431 ed->seqbasep = seqbase;
432}
433
434static MetaStack *seq_meta_stack_alloc(const Scene *scene, Strip *strip_meta)
435{
436 Editing *ed = editing_get(scene);
437
438 MetaStack *ms = MEM_mallocN<MetaStack>("metastack");
439 BLI_addhead(&ed->metastack, ms);
440 ms->parent_strip = strip_meta;
441
442 /* Reference to previously displayed timeline data. */
443 Strip *higher_level_meta = lookup_meta_by_strip(ed, strip_meta);
444 ms->oldbasep = higher_level_meta ? &higher_level_meta->seqbase : &ed->seqbase;
445 ms->old_channels = higher_level_meta ? &higher_level_meta->channels : &ed->channels;
446
449 return ms;
450}
451
453{
454 if (ed == nullptr) {
455 return nullptr;
456 }
457
458 return static_cast<MetaStack *>(ed->metastack.last);
459}
460
461void meta_stack_set(const Scene *scene, Strip *dst)
462{
463 Editing *ed = editing_get(scene);
464 /* Clear metastack */
465 BLI_freelistN(&ed->metastack);
466
467 if (dst != nullptr) {
468 /* Allocate meta stack in a way, that represents meta hierarchy in timeline. */
469 seq_meta_stack_alloc(scene, dst);
470 Strip *meta_parent = dst;
471 while ((meta_parent = lookup_meta_by_strip(ed, meta_parent))) {
472 seq_meta_stack_alloc(scene, meta_parent);
473 }
474
477 }
478 else {
479 /* Go to top level, exiting meta strip. */
480 active_seqbase_set(ed, &ed->seqbase);
481 channels_displayed_set(ed, &ed->channels);
482 }
483}
484
486{
488 Strip *meta_parent = ms->parent_strip;
491 BLI_remlink(&ed->metastack, ms);
492 MEM_freeN(ms);
493 return meta_parent;
494}
495
497
498/* -------------------------------------------------------------------- */
501
502static Strip *strip_duplicate(const Scene *scene_src,
503 Scene *scene_dst,
504 ListBase *new_seq_list,
505 Strip *strip,
506 int dupe_flag,
507 const int flag,
509{
510 Strip *strip_new = static_cast<Strip *>(MEM_dupallocN(strip));
511 strip_map.add(strip, strip_new);
512
513 if ((flag & LIB_ID_CREATE_NO_MAIN) == 0) {
515 }
516
517 strip_new->data = static_cast<StripData *>(MEM_dupallocN(strip->data));
518
519 strip_new->stereo3d_format = static_cast<Stereo3dFormat *>(
521
522 /* XXX: add F-Curve duplication stuff? */
523
524 if (strip->data->crop) {
525 strip_new->data->crop = static_cast<StripCrop *>(MEM_dupallocN(strip->data->crop));
526 }
527
528 if (strip->data->transform) {
529 strip_new->data->transform = static_cast<StripTransform *>(
530 MEM_dupallocN(strip->data->transform));
531 }
532
533 if (strip->data->proxy) {
534 strip_new->data->proxy = static_cast<StripProxy *>(MEM_dupallocN(strip->data->proxy));
535 strip_new->data->proxy->anim = nullptr;
536 }
537
538 if (strip->prop) {
539 strip_new->prop = IDP_CopyProperty_ex(strip->prop, flag);
540 }
541 if (strip->system_properties) {
543 }
544
545 if (strip_new->modifiers.first) {
546 BLI_listbase_clear(&strip_new->modifiers);
547
548 modifier_list_copy(strip_new, strip);
549 }
550
551 if (is_strip_connected(strip)) {
552 BLI_listbase_clear(&strip_new->connections);
553 connections_duplicate(&strip_new->connections, &strip->connections);
554 }
555
556 if (strip->type == STRIP_TYPE_META) {
557 strip_new->data->stripdata = nullptr;
558
559 BLI_listbase_clear(&strip_new->seqbase);
560 BLI_listbase_clear(&strip_new->channels);
561 channels_duplicate(&strip_new->channels, &strip->channels);
562 }
563 else if (strip->type == STRIP_TYPE_SCENE) {
564 strip_new->data->stripdata = nullptr;
565 if (strip->scene_sound) {
566 strip_new->scene_sound = BKE_sound_scene_add_scene_sound_defaults(scene_dst, strip_new);
567 }
568 }
569 else if (strip->type == STRIP_TYPE_MOVIECLIP) {
570 /* avoid assert */
571 }
572 else if (strip->type == STRIP_TYPE_MASK) {
573 /* avoid assert */
574 }
575 else if (strip->type == STRIP_TYPE_MOVIE) {
576 strip_new->data->stripdata = static_cast<StripElem *>(MEM_dupallocN(strip->data->stripdata));
577 BLI_listbase_clear(&strip_new->anims);
578 }
579 else if (strip->type == STRIP_TYPE_SOUND_RAM) {
580 strip_new->data->stripdata = static_cast<StripElem *>(MEM_dupallocN(strip->data->stripdata));
581 strip_new->scene_sound = nullptr;
583 id_us_plus((ID *)strip_new->sound);
584 }
585 }
586 else if (strip->type == STRIP_TYPE_IMAGE) {
587 strip_new->data->stripdata = static_cast<StripElem *>(MEM_dupallocN(strip->data->stripdata));
588 }
589 else if (strip->type & STRIP_TYPE_EFFECT) {
590 EffectHandle sh;
591 sh = strip_effect_handle_get(strip);
592 if (sh.copy) {
593 sh.copy(strip_new, strip, flag);
594 }
595
596 strip_new->data->stripdata = nullptr;
597 }
598 else {
599 /* sequence type not handled in duplicate! Expect a crash now... */
601 }
602
603 /* When using #STRIP_DUPE_UNIQUE_NAME, it is mandatory to add new strips in relevant container
604 * (scene or meta's one), *before* checking for unique names. Otherwise the meta's list is empty
605 * and hence we miss all sequencer strips in that meta that have already been duplicated,
606 * (see #55668). Note that unique name check itself could be done at a later step in calling
607 * code, once all sequencer strips have been duplicated (that was first, simpler solution),
608 * but then handling of animation data will be broken (see #60194). */
609 if (new_seq_list != nullptr) {
610 BLI_addtail(new_seq_list, strip_new);
611 }
612
613 if (scene_src == scene_dst) {
614 if (dupe_flag & STRIP_DUPE_UNIQUE_NAME) {
615 strip_unique_name_set(scene_dst, &scene_dst->ed->seqbase, strip_new);
616 }
617 }
618
619 if (strip->retiming_keys != nullptr) {
620 strip_new->retiming_keys = static_cast<SeqRetimingKey *>(MEM_dupallocN(strip->retiming_keys));
621 strip_new->retiming_keys_num = strip->retiming_keys_num;
622 }
623
624 return strip_new;
625}
626
628 Scene *scene_dst,
629 ListBase *new_seq_list,
630 Strip *strip,
631 const int dupe_flag,
633{
634 Strip *strip_new = strip_duplicate(
635 scene_src, scene_dst, new_seq_list, strip, dupe_flag, 0, strip_map);
636 if (strip->type == STRIP_TYPE_META) {
637 LISTBASE_FOREACH (Strip *, s, &strip->seqbase) {
639 scene_src, scene_dst, &strip_new->seqbase, s, dupe_flag, strip_map);
640 }
641 }
642 return strip_new;
643}
644
646 const Scene *scene_src, Scene *scene_dst, ListBase *new_seq_list, Strip *strip, int dupe_flag)
647{
649
651 scene_src, scene_dst, new_seq_list, strip, dupe_flag, strip_map);
652
653 seq_new_fix_links_recursive(strip_new, strip_map);
654 if (is_strip_connected(strip_new)) {
655 cut_one_way_connections(strip_new);
656 }
657
658 return strip_new;
659}
660
661static void seqbase_dupli_recursive(const Scene *scene_src,
662 Scene *scene_dst,
663 ListBase *nseqbase,
664 const ListBase *seqbase,
665 int dupe_flag,
666 const int flag,
668{
669 LISTBASE_FOREACH (Strip *, strip, seqbase) {
670 if ((strip->flag & SELECT) == 0 && (dupe_flag & STRIP_DUPE_ALL) == 0) {
671 continue;
672 }
673
674 Strip *strip_new = strip_duplicate(
675 scene_src, scene_dst, nseqbase, strip, dupe_flag, flag, strip_map);
676 BLI_assert(strip_new != nullptr);
677
678 if (strip->type == STRIP_TYPE_META) {
679 /* Always include meta all strip children. */
680 int dupe_flag_recursive = dupe_flag | STRIP_DUPE_ALL;
681 seqbase_dupli_recursive(scene_src,
682 scene_dst,
683 &strip_new->seqbase,
684 &strip->seqbase,
685 dupe_flag_recursive,
686 flag,
687 strip_map);
688 }
689 }
690}
691
692void seqbase_duplicate_recursive(const Scene *scene_src,
693 Scene *scene_dst,
694 ListBase *nseqbase,
695 const ListBase *seqbase,
696 int dupe_flag,
697 const int flag)
698{
700
701 seqbase_dupli_recursive(scene_src, scene_dst, nseqbase, seqbase, dupe_flag, flag, strip_map);
702
703 /* Fix effect, modifier, and connected strip links. */
704 LISTBASE_FOREACH (Strip *, strip, nseqbase) {
705 seq_new_fix_links_recursive(strip, strip_map);
706 }
707 /* One-way connections cannot be cut until after all connections are resolved. */
708 LISTBASE_FOREACH (Strip *, strip, nseqbase) {
709 if (is_strip_connected(strip)) {
711 }
712 }
713}
714
716{
717 return strip->channel >= 1 && strip->channel <= MAX_CHANNELS;
718}
719
726
728
729static bool seq_set_strip_done_cb(Strip *strip, void * /*userdata*/)
730{
731 if (strip->data) {
732 strip->data->done = false;
733 }
734 return true;
735}
736
737static bool strip_write_data_cb(Strip *strip, void *userdata)
738{
739 BlendWriter *writer = (BlendWriter *)userdata;
740 BLO_write_struct(writer, Strip, strip);
741 if (strip->data && strip->data->done == 0) {
742 /* Write strip with 'done' at 0 because read-file. */
743
744 /* TODO this doesn't depend on the `Strip` data to be present? */
745 if (strip->effectdata) {
746 switch (strip->type) {
747 case STRIP_TYPE_COLOR:
749 break;
750 case STRIP_TYPE_SPEED:
752 break;
753 case STRIP_TYPE_WIPE:
754 BLO_write_struct(writer, WipeVars, strip->effectdata);
755 break;
756 case STRIP_TYPE_GLOW:
757 BLO_write_struct(writer, GlowVars, strip->effectdata);
758 break;
761 break;
764 break;
765 case STRIP_TYPE_TEXT:
766 BLO_write_struct(writer, TextVars, strip->effectdata);
767 break;
770 break;
771 }
772 }
773
775
776 StripData *data = strip->data;
778 if (data->crop) {
779 BLO_write_struct(writer, StripCrop, data->crop);
780 }
781 if (data->transform) {
782 BLO_write_struct(writer, StripTransform, data->transform);
783 }
784 if (data->proxy) {
785 BLO_write_struct(writer, StripProxy, data->proxy);
786 }
787 if (strip->type == STRIP_TYPE_IMAGE) {
789 writer, StripElem, MEM_allocN_len(data->stripdata) / sizeof(StripElem), data->stripdata);
790 }
791 else if (ELEM(strip->type, STRIP_TYPE_MOVIE, STRIP_TYPE_SOUND_RAM)) {
792 BLO_write_struct(writer, StripElem, data->stripdata);
793 }
794
795 data->done = true;
796 }
797
798 if (strip->prop) {
799 IDP_BlendWrite(writer, strip->prop);
800 }
801 /* Never write system_properties in Blender 4.5, will be reset to `nullptr` by reading code (by
802 * the matching call to #BLO_read_struct). */
803
804 modifier_blend_write(writer, &strip->modifiers);
805
806 LISTBASE_FOREACH (SeqTimelineChannel *, channel, &strip->channels) {
807 BLO_write_struct(writer, SeqTimelineChannel, channel);
808 }
809
811 BLO_write_struct(writer, StripConnection, con);
812 }
813
814 if (strip->retiming_keys != nullptr) {
815 int size = retiming_keys_count(strip);
817 }
818
819 return true;
820}
821
822void blend_write(BlendWriter *writer, ListBase *seqbase)
823{
824 /* reset write flags */
825 for_each_callback(seqbase, seq_set_strip_done_cb, nullptr);
826
827 for_each_callback(seqbase, strip_write_data_cb, writer);
828}
829
830static bool strip_read_data_cb(Strip *strip, void *user_data)
831{
832 BlendDataReader *reader = (BlendDataReader *)user_data;
833
834 /* Runtime data cleanup. */
835 strip->scene_sound = nullptr;
836 BLI_listbase_clear(&strip->anims);
837
838 /* Do as early as possible, so that other parts of reading can rely on valid session UID. */
840
841 BLO_read_struct(reader, Strip, &strip->input1);
842 BLO_read_struct(reader, Strip, &strip->input2);
843
844 if (strip->effectdata) {
845 switch (strip->type) {
846 case STRIP_TYPE_COLOR:
847 BLO_read_struct(reader, SolidColorVars, &strip->effectdata);
848 break;
849 case STRIP_TYPE_SPEED:
851 break;
852 case STRIP_TYPE_WIPE:
853 BLO_read_struct(reader, WipeVars, &strip->effectdata);
854 break;
855 case STRIP_TYPE_GLOW:
856 BLO_read_struct(reader, GlowVars, &strip->effectdata);
857 break;
859 BLO_read_struct(reader, TransformVars, &strip->effectdata);
860 break;
863 break;
864 case STRIP_TYPE_TEXT:
865 BLO_read_struct(reader, TextVars, &strip->effectdata);
866 break;
868 BLO_read_struct(reader, ColorMixVars, &strip->effectdata);
869 break;
870 default:
872 strip->effectdata = nullptr;
873 break;
874 }
875 }
876
878
879 if (strip->type & STRIP_TYPE_EFFECT) {
880 strip->flag |= SEQ_EFFECT_NOT_LOADED;
881 }
882
883 if (strip->type == STRIP_TYPE_TEXT) {
884 TextVars *t = static_cast<TextVars *>(strip->effectdata);
886 t->runtime = nullptr;
887 }
888
889 BLO_read_struct(reader, IDProperty, &strip->prop);
890 IDP_BlendDataRead(reader, &strip->prop);
892 IDP_BlendDataRead(reader, &strip->system_properties);
893
894 BLO_read_struct(reader, StripData, &strip->data);
895 if (strip->data && strip->data->done == 0) {
896 strip->data->done = true;
897
898 /* `STRIP_TYPE_SOUND_HD` case needs to be kept here, for backward compatibility. */
899 if (ELEM(strip->type,
904 {
905 /* FIXME In #STRIP_TYPE_IMAGE case, there is currently no available information about the
906 * length of the stored array of #StripElem.
907 *
908 * This is 'not a problem' because the reading code only checks that the loaded buffer is at
909 * least large enough for the requested data (here a single #StripElem item), and always
910 * assign the whole read memory (without any truncating). But relying on this behavior is
911 * weak and should be addressed. */
912 BLO_read_struct(reader, StripElem, &strip->data->stripdata);
913 }
914 else {
915 strip->data->stripdata = nullptr;
916 }
917 BLO_read_struct(reader, StripCrop, &strip->data->crop);
918 BLO_read_struct(reader, StripTransform, &strip->data->transform);
919 BLO_read_struct(reader, StripProxy, &strip->data->proxy);
920 if (strip->data->proxy) {
921 strip->data->proxy->anim = nullptr;
922 }
923 else if (strip->flag & SEQ_USE_PROXY) {
924 proxy_set(strip, true);
925 }
926
927 /* need to load color balance to it could be converted to modifier */
928 BLO_read_struct(reader, StripColorBalance, &strip->data->color_balance);
929 }
930
931 modifier_blend_read_data(reader, &strip->modifiers);
932
935 if (con->strip_ref) {
936 BLO_read_struct(reader, Strip, &con->strip_ref);
937 }
938 }
939
941
942 if (strip->retiming_keys != nullptr) {
943 const int size = retiming_keys_count(strip);
945 }
946
947 return true;
948}
949void blend_read(BlendDataReader *reader, ListBase *seqbase)
950{
951 for_each_callback(seqbase, strip_read_data_cb, reader);
952}
953
954static bool strip_doversion_250_sound_proxy_update_cb(Strip *strip, void *user_data)
955{
956 Main *bmain = static_cast<Main *>(user_data);
957 if (strip->type == STRIP_TYPE_SOUND_HD) {
958 char filepath_abs[FILE_MAX];
959 BLI_path_join(filepath_abs,
960 sizeof(filepath_abs),
961 strip->data->dirpath,
962 strip->data->stripdata->filename);
963 BLI_path_abs(filepath_abs, BKE_main_blendfile_path(bmain));
964 strip->sound = BKE_sound_new_file(bmain, filepath_abs);
965 strip->type = STRIP_TYPE_SOUND_RAM;
966 }
967 return true;
968}
969
974
975/* Depsgraph update functions. */
976
977static bool seq_mute_sound_strips_cb(Strip *strip, void *user_data)
978{
979 Scene *scene = (Scene *)user_data;
980 if (strip->scene_sound != nullptr) {
982 strip->scene_sound = nullptr;
983 }
984 return true;
985}
986
987/* Adds sound of strip to the `scene->sound_scene` - "sound timeline". */
988static void strip_update_mix_sounds(Scene *scene, Strip *strip)
989{
990 if (strip->scene_sound != nullptr) {
991 return;
992 }
993
994 if (strip->sound != nullptr) {
995 /* Adds `strip->sound->playback_handle` to `scene->sound_scene` */
996 strip->scene_sound = BKE_sound_add_scene_sound_defaults(scene, strip);
997 }
998 else if (strip->type == STRIP_TYPE_SCENE && strip->scene != nullptr) {
999 /* Adds `strip->scene->sound_scene` to `scene->sound_scene`. */
1002 }
1003}
1004
1005static void strip_update_sound_properties(const Scene *scene, const Strip *strip)
1006{
1007 const int frame = BKE_scene_frame_get(scene);
1009 strip->scene_sound, frame, strip->volume, (strip->flag & SEQ_AUDIO_VOLUME_ANIMATED) != 0);
1012 strip->scene_sound, frame, strip->pan, (strip->flag & SEQ_AUDIO_PAN_ANIMATED) != 0);
1013}
1014
1016{
1017 void *sound_handle = strip->sound->playback_handle;
1018 if (!BLI_listbase_is_empty(&strip->modifiers)) {
1019 LISTBASE_FOREACH (StripModifierData *, smd, &strip->modifiers) {
1020 sound_handle = sound_modifier_recreator(strip, smd, sound_handle);
1021 }
1022 }
1023
1024 /* Assign modified sound back to `strip`. */
1025 BKE_sound_update_sequence_handle(strip->scene_sound, sound_handle);
1026}
1027
1028static bool must_update_strip_sound(Scene *scene, Strip *strip)
1029{
1030 return (scene->id.recalc & (ID_RECALC_AUDIO | ID_RECALC_SYNC_TO_EVAL)) != 0 ||
1032}
1033
1034static void seq_update_sound_strips(Scene *scene, Strip *strip)
1035{
1036 if (strip->sound == nullptr || !must_update_strip_sound(scene, strip)) {
1037 return;
1038 }
1039 /* Ensure strip is playing correct sound. */
1042}
1043
1044static bool scene_sequencer_is_used(const Scene *scene, ListBase *seqbase)
1045{
1046 bool sequencer_is_used = false;
1047 LISTBASE_FOREACH (Strip *, strip_iter, seqbase) {
1048 if (strip_iter->scene == scene && (strip_iter->flag & SEQ_SCENE_STRIPS) != 0) {
1049 sequencer_is_used = true;
1050 }
1051 if (strip_iter->type == STRIP_TYPE_META) {
1052 sequencer_is_used |= scene_sequencer_is_used(scene, &strip_iter->seqbase);
1053 }
1054 }
1055
1056 return sequencer_is_used;
1057}
1058
1059static void seq_update_scene_strip_sound(const Scene *scene, Strip *strip)
1060{
1061 if (strip->type != STRIP_TYPE_SCENE || strip->scene == nullptr) {
1062 return;
1063 }
1064
1065 /* Set `strip->scene` volume.
1066 * NOTE: Currently this doesn't work well, when this property is animated. Scene strip volume is
1067 * also controlled by `strip_update_sound_properties()` via `strip->volume` which works if
1068 * animated.
1069 *
1070 * Ideally, the entire `BKE_scene_update_sound()` will happen from a dependency graph, so
1071 * then it is no longer needed to do such manual forced updates. */
1073
1074 /* Mute sound when all scene strips using particular scene are not rendering sequencer strips. */
1075 bool sequencer_is_used = scene_sequencer_is_used(strip->scene, &scene->ed->seqbase);
1076
1077 if (!sequencer_is_used && strip->scene->sound_scene != nullptr && strip->scene->ed != nullptr) {
1079 }
1080}
1081
1082static bool strip_sound_update_cb(Strip *strip, void *user_data)
1083{
1084 Scene *scene = (Scene *)user_data;
1085
1086 strip_update_mix_sounds(scene, strip);
1087
1088 if (strip->scene_sound == nullptr) {
1089 return true;
1090 }
1091
1092 seq_update_sound_strips(scene, strip);
1093 seq_update_scene_strip_sound(scene, strip);
1094 strip_update_sound_properties(scene, strip);
1095 return true;
1096}
1097
1098void eval_strips(Depsgraph *depsgraph, Scene *scene, ListBase *seqbase)
1099{
1100 DEG_debug_print_eval(depsgraph, __func__, scene->id.name, scene);
1102
1104
1105 edit_update_muting(scene->ed);
1107}
1108
1109} // namespace blender::seq
#define IDP_BlendDataRead(reader, prop)
void IDP_FreePropertyContent_ex(IDProperty *prop, bool do_id_user)
Definition idprop.cc:1205
IDProperty * IDP_CopyProperty_ex(const IDProperty *prop, int flag) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition idprop.cc:855
void IDP_BlendWrite(BlendWriter *writer, const IDProperty *prop)
Definition idprop.cc:1453
@ LIB_ID_CREATE_NO_USER_REFCOUNT
@ LIB_ID_CREATE_NO_MAIN
void id_us_plus(ID *id)
Definition lib_id.cc:353
void id_us_min(ID *id)
Definition lib_id.cc:361
const char * BKE_main_blendfile_path(const Main *bmain) ATTR_NONNULL()
Definition main.cc:877
float BKE_scene_frame_get(const Scene *scene)
Definition scene.cc:2381
void BKE_sound_set_scene_sound_pan_at_frame(void *handle, int frame, float pan, char animated)
void BKE_sound_set_scene_volume(struct Scene *scene, float volume)
struct bSound * BKE_sound_new_file(struct Main *bmain, const char *filepath)
void BKE_sound_ensure_scene(struct Scene *scene)
void * BKE_sound_scene_add_scene_sound_defaults(struct Scene *scene, struct Strip *sequence)
void * BKE_sound_add_scene_sound_defaults(struct Scene *scene, struct Strip *sequence)
void BKE_sound_set_scene_sound_volume_at_frame(void *handle, int frame, float volume, char animated)
void BKE_sound_update_scene_sound(void *handle, struct bSound *sound)
void BKE_sound_update_sequence_handle(void *handle, void *sound_handle)
void BKE_sound_remove_scene_sound(struct Scene *scene, void *handle)
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define BLI_assert(a)
Definition BLI_assert.h:46
#define LISTBASE_FOREACH(type, var, list)
BLI_INLINE void BLI_listbase_clear(ListBase *lb)
BLI_INLINE bool BLI_listbase_is_empty(const ListBase *lb)
#define LISTBASE_FOREACH_MUTABLE(type, var, list)
void void BLI_freelistN(ListBase *listbase) ATTR_NONNULL(1)
Definition listbase.cc:497
void BLI_addtail(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:111
void BLI_remlink(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:131
void BLI_addhead(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:91
bool BLI_path_abs(char path[FILE_MAX], const char *basepath) ATTR_NONNULL(1
#define FILE_MAX
#define BLI_path_join(...)
#define ELEM(...)
#define BLO_write_struct(writer, struct_name, data_ptr)
#define BLO_write_struct_array(writer, struct_name, array_size, data_ptr)
#define BLO_read_struct_list(reader, struct_name, list)
#define BLO_read_struct_array(reader, struct_name, array_size, ptr_p)
#define BLO_read_struct(reader, struct_name, ptr_p)
void DEG_debug_print_eval(Depsgraph *depsgraph, const char *function_name, const char *object_name, const void *object_address)
@ ID_RECALC_AUDIO
Definition DNA_ID.h:1040
@ ID_RECALC_SYNC_TO_EVAL
Definition DNA_ID.h:1026
These structs are the foundation for all linked lists in the library system.
eSeqImageFitMethod
@ SEQ_SCALE_TO_FIT
@ SEQ_SNAP_TO_STRIPS
@ SEQ_SNAP_TO_MARKERS
@ SEQ_SNAP_TO_PREVIEW_CENTER
@ SEQ_SNAP_TO_STRIPS_PREVIEW
@ SEQ_SNAP_TO_PREVIEW_BORDERS
@ SEQ_SNAP_TO_STRIP_HOLD
@ SEQ_SNAP_TO_RETIMING
@ SEQ_SNAP_TO_CURRENT_FRAME
eSeqOverlapMode
@ SEQ_OVERLAP_SHUFFLE
@ SEQ_CACHE_STORE_RAW
@ SEQ_CACHE_STORE_FINAL_OUT
@ SEQ_EFFECT_NOT_LOADED
@ SEQ_SCENE_STRIPS
@ SEQ_USE_PROXY
@ SEQ_AUDIO_VOLUME_ANIMATED
@ SEQ_AUDIO_PAN_ANIMATED
@ SEQ_EDIT_SHOW_MISSING_MEDIA
@ SEQ_TRANSFORM_FILTER_AUTO
@ STRIP_TYPE_GAUSSIAN_BLUR
@ STRIP_TYPE_SCENE
@ STRIP_TYPE_MOVIECLIP
@ STRIP_TYPE_COLORMIX
@ STRIP_TYPE_WIPE
@ STRIP_TYPE_TEXT
@ STRIP_TYPE_SOUND_HD
@ STRIP_TYPE_SOUND_RAM
@ STRIP_TYPE_TRANSFORM
@ STRIP_TYPE_IMAGE
@ STRIP_TYPE_MOVIE
@ STRIP_TYPE_GLOW
@ STRIP_TYPE_SPEED
@ STRIP_TYPE_EFFECT
@ STRIP_TYPE_COLOR
@ STRIP_TYPE_ADJUSTMENT
@ STRIP_TYPE_META
@ STRIP_TYPE_MASK
@ STRIP_TYPE_CROSS
@ STRIP_TYPE_ALPHAOVER
@ STRIP_COLOR_NONE
@ SEQ_PROXY_TC_RECORD_RUN_NO_GAPS
@ SEQ_PROXY_TC_RECORD_RUN
#define STRIP_FONT_NOT_LOADED
@ V3D_AROUND_LOCAL_ORIGINS
Read Guarded memory(de)allocation.
#define STRIP_DUPE_UNIQUE_NAME
#define STRIP_DUPE_ALL
BMesh const char void * data
BPy_StructRNA * depsgraph
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
bool add(const Key &key, const Value &value)
Definition BLI_map.hh:295
Value lookup_default(const Key &key, const Value &default_value) const
Definition BLI_map.hh:570
#define SELECT
#define printf(...)
#define ID_SEQ
void * MEM_mallocN(size_t len, const char *str)
Definition mallocn.cc:128
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void * MEM_dupallocN(const void *vmemh)
Definition mallocn.cc:143
size_t(* MEM_allocN_len)(const void *vmemh)
Definition mallocn.cc:36
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
void MOV_close(MovieReader *anim)
Definition movie_read.cc:58
static StripData * seq_strip_alloc(int type)
Definition sequencer.cc:80
void relations_strip_free_anim(Strip *strip)
void channels_displayed_set(Editing *ed, ListBase *channels)
Definition channels.cc:33
static void seq_update_sound_strips(Scene *scene, Strip *strip)
Strip * lookup_meta_by_strip(Editing *ed, const Strip *key)
int time_right_handle_frame_get(const Scene *scene, const Strip *strip)
SequencerToolSettings * tool_settings_init()
Definition sequencer.cc:346
static Strip * strip_duplicate_recursive_impl(const Scene *scene_src, Scene *scene_dst, ListBase *new_seq_list, Strip *strip, const int dupe_flag, blender::Map< Strip *, Strip * > &strip_map)
Definition sequencer.cc:627
bool disconnect(Strip *strip)
EffectHandle strip_effect_handle_get(Strip *strip)
Definition effects.cc:249
void eval_strips(Depsgraph *depsgraph, Scene *scene, ListBase *seqbase)
void sound_update_bounds_all(Scene *scene)
static void strip_update_mix_sounds(Scene *scene, Strip *strip)
Definition sequencer.cc:988
eSeqImageFitMethod tool_settings_fit_method_get(Scene *scene)
Definition sequencer.cc:378
int retiming_keys_count(const Strip *strip)
static bool scene_sequencer_is_used(const Scene *scene, ListBase *seqbase)
static void seq_update_scene_strip_sound(const Scene *scene, Strip *strip)
void doversion_250_sound_proxy_update(Main *bmain, Editing *ed)
Definition sequencer.cc:970
void channels_ensure(ListBase *channels)
Definition channels.cc:38
void strip_channel_set(Strip *strip, int channel)
void media_presence_free(Scene *scene)
SequencerToolSettings * tool_settings_copy(SequencerToolSettings *tool_settings)
Definition sequencer.cc:720
static bool must_update_strip_sound(Scene *scene, Strip *strip)
void blend_write(BlendWriter *writer, ListBase *seqbase)
Definition sequencer.cc:822
void tool_settings_free(SequencerToolSettings *tool_settings)
Definition sequencer.cc:373
Editing * editing_get(const Scene *scene)
Definition sequencer.cc:272
void meta_stack_set(const Scene *scene, Strip *dst)
Definition sequencer.cc:461
StripProxy * seq_strip_proxy_alloc()
Definition sequencer.cc:71
void seq_prefetch_free(Scene *scene)
Definition prefetch.cc:368
void active_seqbase_set(Editing *ed, ListBase *seqbase)
Definition sequencer.cc:429
static bool strip_sound_update_cb(Strip *strip, void *user_data)
int time_left_handle_frame_get(const Scene *, const Strip *strip)
static void seq_free_strip(StripData *data)
Definition sequencer.cc:98
void seq_free_strip_recurse(Scene *scene, Strip *strip, const bool do_id_user)
Definition sequencer.cc:260
static void strip_update_sound_modifiers(Strip *strip)
void relations_invalidate_cache_raw(Scene *scene, Strip *strip)
static bool seq_set_strip_done_cb(Strip *strip, void *)
Definition sequencer.cc:729
void strip_free(Scene *scene, Strip *strip)
Definition sequencer.cc:255
void cut_one_way_connections(Strip *strip)
static void seq_strip_free_ex(Scene *scene, Strip *strip, const bool do_cache, const bool do_id_user)
Definition sequencer.cc:174
MetaStack * meta_stack_active_get(const Editing *ed)
Definition sequencer.cc:452
Editing * editing_ensure(Scene *scene)
Definition sequencer.cc:277
void proxy_set(Strip *strip, bool value)
Definition proxy.cc:601
Strip * strip_duplicate_recursive(const Scene *scene_src, Scene *scene_dst, ListBase *new_seq_list, Strip *strip, int dupe_flag)
Definition sequencer.cc:645
static bool seq_mute_sound_strips_cb(Strip *strip, void *user_data)
Definition sequencer.cc:977
static MetaStack * seq_meta_stack_alloc(const Scene *scene, Strip *strip_meta)
Definition sequencer.cc:434
static bool strip_doversion_250_sound_proxy_update_cb(Strip *strip, void *user_data)
Definition sequencer.cc:954
void final_image_cache_destroy(Scene *scene)
void editing_free(Scene *scene, const bool do_id_user)
Definition sequencer.cc:293
constexpr int MAX_CHANNELS
static void strip_update_sound_properties(const Scene *scene, const Strip *strip)
void * sound_modifier_recreator(Strip *strip, StripModifierData *smd, void *sound)
void for_each_callback(ListBase *seqbase, ForEachFunc callback, void *user_data)
Definition iterator.cc:59
static bool strip_write_data_cb(Strip *strip, void *userdata)
Definition sequencer.cc:737
bool is_strip_connected(const Strip *strip)
void modifier_blend_read_data(BlendDataReader *reader, ListBase *lb)
static Strip * strip_duplicate(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)
Definition sequencer.cc:502
int tool_settings_pivot_point_get(Scene *scene)
Definition sequencer.cc:414
void edit_update_muting(Editing *ed)
void retiming_sound_animation_data_set(const Scene *scene, const Strip *strip)
void tool_settings_fit_method_set(Scene *scene, eSeqImageFitMethod fit_method)
Definition sequencer.cc:402
void channels_duplicate(ListBase *channels_dst, ListBase *channels_src)
Definition channels.cc:49
void modifier_clear(Strip *strip)
bool is_valid_strip_channel(const Strip *strip)
Definition sequencer.cc:715
short tool_settings_snap_flag_get(Scene *scene)
Definition sequencer.cc:390
SequencerToolSettings * tool_settings_ensure(Scene *scene)
Definition sequencer.cc:362
static bool strip_read_data_cb(Strip *strip, void *user_data)
Definition sequencer.cc:830
int tool_settings_snap_distance_get(Scene *scene)
Definition sequencer.cc:396
static void seqbase_dupli_recursive(const Scene *scene_src, Scene *scene_dst, ListBase *nseqbase, const ListBase *seqbase, int dupe_flag, const int flag, blender::Map< Strip *, Strip * > &strip_map)
Definition sequencer.cc:661
void intra_frame_cache_destroy(Scene *scene)
void source_image_cache_destroy(Scene *scene)
static void strip_lookup_free(StripLookup **lookup)
void strip_unique_name_set(Scene *scene, ListBase *seqbasep, Strip *strip)
void relations_session_uid_generate(Strip *strip)
void modifier_list_copy(Strip *strip_new, Strip *strip)
void channels_free(ListBase *channels)
Definition channels.cc:58
static void seq_new_fix_links_recursive(Strip *strip, blender::Map< Strip *, Strip * > strip_map)
Definition sequencer.cc:322
ListBase * active_seqbase_get(const Editing *ed)
Definition sequencer.cc:420
short tool_settings_snap_mode_get(Scene *scene)
Definition sequencer.cc:384
void connections_duplicate(ListBase *connections_dst, ListBase *connections_src)
Strip * meta_stack_pop(Editing *ed)
Definition sequencer.cc:485
void blend_read(BlendDataReader *reader, ListBase *seqbase)
Definition sequencer.cc:949
Strip * strip_alloc(ListBase *lb, int timeline_frame, int channel, int type)
Definition sequencer.cc:130
void seqbase_duplicate_recursive(const Scene *scene_src, Scene *scene_dst, ListBase *nseqbase, const ListBase *seqbase, int dupe_flag, const int flag)
Definition sequencer.cc:692
void thumbnail_cache_destroy(Scene *scene)
eSeqOverlapMode tool_settings_overlap_mode_get(Scene *scene)
Definition sequencer.cc:408
void modifier_blend_write(BlendWriter *writer, ListBase *modbase)
ListBase seqbase
Definition DNA_ID.h:404
unsigned int recalc
Definition DNA_ID.h:427
char name[66]
Definition DNA_ID.h:415
void * first
ListBase * old_channels
ListBase * oldbasep
void * sound_scene
struct ToolSettings * toolsettings
struct Editing * ed
struct AudioData audio
StripProxy * proxy
StripCrop * crop
StripTransform * transform
StripElem * stripdata
char dirpath[768]
char filename[256]
struct MovieReader * anim
struct Stereo3dFormat * stereo3d_format
void * scene_sound
struct Strip * input1
int8_t color_tag
int retiming_keys_num
float pitch pan
ListBase connections
StripData * data
struct IDProperty * prop
struct Scene * scene
void * effectdata
struct bSound * sound
ListBase seqbase
float speed_factor
float media_playback_rate
struct SeqRetimingKey * retiming_keys
struct IDProperty * system_properties
struct Strip * next
float blend_opacity
char name[64]
ListBase modifiers
struct Strip * input2
ListBase channels
ListBase anims
TextVarsRuntime * runtime
struct SequencerToolSettings * sequencer_tool_settings
void * playback_handle
void(* copy)(Strip *dst, const Strip *src, int flag)
void(* free)(Strip *strip, bool do_id_user)
uint8_t flag
Definition wm_window.cc:139