From 576161b18673ef5cd5833330d4bfbf1266c3f624 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 24 Jul 2013 06:51:04 +0000 Subject: [PATCH] fix [#36262] Paste strip with video or sound content from another file crashes Blender existing code was very stupid. - all ID pointers for clipboard strips are handled uniformly. - clipboard stores a duplicate ID pointer which are restored on paste. - restoring pointers... -- use ID's that are still in the database (copy&paste within the same file). -- fallback to name lookup. -- fallback to loading them from the original filepath (movie-clip and sound only). also fix bug pasting where initialing the sound wasn't done if there was no frame-offset. --- .../scripts/startup/bl_ui/space_sequencer.py | 13 +- source/blender/blenkernel/BKE_sequencer.h | 6 +- source/blender/blenkernel/intern/mask.c | 2 - source/blender/blenkernel/intern/movieclip.c | 2 - source/blender/blenkernel/intern/sequencer.c | 124 ++++++++++++++---- source/blender/blenloader/intern/readfile.c | 26 ++-- .../editors/space_sequencer/sequencer_edit.c | 16 ++- 7 files changed, 136 insertions(+), 53 deletions(-) diff --git a/release/scripts/startup/bl_ui/space_sequencer.py b/release/scripts/startup/bl_ui/space_sequencer.py index 3477353ba0d..79191637080 100644 --- a/release/scripts/startup/bl_ui/space_sequencer.py +++ b/release/scripts/startup/bl_ui/space_sequencer.py @@ -671,13 +671,14 @@ class SEQUENCER_PT_sound(SequencerButtonsPanel, Panel): layout.separator() layout.prop(strip, "filepath", text="") - row = layout.row() - if sound.packed_file: - row.operator("sound.unpack", icon='PACKAGE', text="Unpack") - else: - row.operator("sound.pack", icon='UGLYPACKAGE', text="Pack") + if sound is not None: + row = layout.row() + if sound.packed_file: + row.operator("sound.unpack", icon='PACKAGE', text="Unpack") + else: + row.operator("sound.pack", icon='UGLYPACKAGE', text="Pack") - row.prop(sound, "use_memory_cache") + row.prop(sound, "use_memory_cache") layout.prop(strip, "show_waveform") layout.prop(strip, "volume") diff --git a/source/blender/blenkernel/BKE_sequencer.h b/source/blender/blenkernel/BKE_sequencer.h index 4494d127082..749b04d7328 100644 --- a/source/blender/blenkernel/BKE_sequencer.h +++ b/source/blender/blenkernel/BKE_sequencer.h @@ -208,6 +208,10 @@ int BKE_sequencer_recursive_apply(struct Sequence *seq, int (*apply_func)(struct void BKE_sequencer_free_clipboard(void); +void BKE_sequence_clipboard_pointers_free(struct Sequence *seq); +void BKE_sequence_clipboard_pointers_store(struct Sequence *seq); +void BKE_sequence_clipboard_pointers_restore(struct Sequence *seq, struct Main *bmain); + void BKE_sequence_free(struct Scene *scene, struct Sequence *seq); const char *BKE_sequence_give_name(struct Sequence *seq); void BKE_sequence_calc(struct Scene *scene, struct Sequence *seq); @@ -319,8 +323,6 @@ void BKE_sequence_base_dupli_recursive(struct Scene *scene, struct Scene *scene_ bool BKE_sequence_is_valid_check(struct Sequence *seq); void BKE_sequencer_clear_scene_in_allseqs(struct Main *bmain, struct Scene *sce); -void BKE_sequencer_clear_movieclip_in_clipboard(struct MovieClip *clip); -void BKE_sequencer_clear_mask_in_clipboard(struct Mask *mask); struct Sequence *BKE_sequence_get_by_name(struct ListBase *seqbase, const char *name, int recursive); diff --git a/source/blender/blenkernel/intern/mask.c b/source/blender/blenkernel/intern/mask.c index b3c5ceefb2d..21e7fb3116e 100644 --- a/source/blender/blenkernel/intern/mask.c +++ b/source/blender/blenkernel/intern/mask.c @@ -939,8 +939,6 @@ void BKE_mask_free(Main *bmain, Mask *mask) SpaceLink *sl; Scene *scene; - BKE_sequencer_clear_mask_in_clipboard(mask); - for (scr = bmain->screen.first; scr; scr = scr->id.next) { for (area = scr->areabase.first; area; area = area->next) { for (sl = area->spacedata.first; sl; sl = sl->next) { diff --git a/source/blender/blenkernel/intern/movieclip.c b/source/blender/blenkernel/intern/movieclip.c index ef3b7ca0bdf..e8550e12e4f 100644 --- a/source/blender/blenkernel/intern/movieclip.c +++ b/source/blender/blenkernel/intern/movieclip.c @@ -1395,8 +1395,6 @@ void BKE_movieclip_build_proxy_frame_for_ibuf(MovieClip *clip, ImBuf *ibuf, stru void BKE_movieclip_free(MovieClip *clip) { - BKE_sequencer_clear_movieclip_in_clipboard(clip); - free_buffers(clip); BKE_tracking_free(&clip->tracking); diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c index b080cfcff2f..1dba2bd8eb9 100644 --- a/source/blender/blenkernel/intern/sequencer.c +++ b/source/blender/blenkernel/intern/sequencer.c @@ -65,6 +65,7 @@ #include "BKE_fcurve.h" #include "BKE_scene.h" #include "BKE_mask.h" +#include "BKE_library.h" #include "RNA_access.h" @@ -265,6 +266,7 @@ static void seq_free_clipboard_recursive(Sequence *seq_parent) seq_free_clipboard_recursive(seq); } + BKE_sequence_clipboard_pointers_free(seq_parent); BKE_sequence_free_ex(NULL, seq_parent, FALSE); } @@ -279,6 +281,101 @@ void BKE_sequencer_free_clipboard(void) seqbase_clipboard.first = seqbase_clipboard.last = NULL; } +/* -------------------------------------------------------------------- */ +/* Manage pointers in the clipboard. + * note that these pointers should _never_ be access in the sequencer, + * they are only for storage while in the clipboard + * notice 'newid' is used for temp pointer storage here, validate on access. + */ +#define ID_PT (*id_pt) +static void seqclipboard_ptr_free(ID **id_pt) +{ + if (ID_PT) { + BLI_assert(ID_PT->newid != NULL); + MEM_freeN(ID_PT); + ID_PT = NULL; + } +} +static void seqclipboard_ptr_store(ID **id_pt) +{ + if (ID_PT) { + ID *id_prev = ID_PT; + ID_PT = MEM_dupallocN(ID_PT); + ID_PT->newid = id_prev; + } +} +static void seqclipboard_ptr_restore(Main *bmain, ID **id_pt) +{ + if (ID_PT) { + const ListBase *lb = which_libbase(bmain, GS(ID_PT->name)); + void *id_restore; + + BLI_assert(ID_PT->newid != NULL); + if (BLI_findindex(lb, (ID_PT)->newid) != -1) { + /* the pointer is still valid */ + id_restore = (ID_PT)->newid; + } + else { + /* the pointer of the same name still exists */ + id_restore = BLI_findstring(lb, (ID_PT)->name + 2, offsetof(ID, name) + 2); + } + + if (id_restore == NULL) { + /* check for a data with the same filename */ + switch (GS(ID_PT->name)) { + case ID_SO: + { + id_restore = BLI_findstring(lb, ((bSound *)ID_PT)->name, offsetof(bSound, name)); + if (id_restore == NULL) { + id_restore = sound_new_file(bmain, ((bSound *)ID_PT)->name); + (ID_PT)->newid = id_restore; /* reuse next time */ + } + break; + } + case ID_MC: + { + id_restore = BLI_findstring(lb, ((MovieClip *)ID_PT)->name, offsetof(MovieClip, name)); + if (id_restore == NULL) { + id_restore = BKE_movieclip_file_add(bmain, ((MovieClip *)ID_PT)->name); + (ID_PT)->newid = id_restore; /* reuse next time */ + } + break; + } + } + } + + ID_PT = id_restore; + } +} +#undef ID_PT + +void BKE_sequence_clipboard_pointers_free(Sequence *seq) +{ + seqclipboard_ptr_free((ID **)&seq->scene); + seqclipboard_ptr_free((ID **)&seq->scene_camera); + seqclipboard_ptr_free((ID **)&seq->clip); + seqclipboard_ptr_free((ID **)&seq->mask); + seqclipboard_ptr_free((ID **)&seq->sound); +} +void BKE_sequence_clipboard_pointers_store(Sequence *seq) +{ + seqclipboard_ptr_store((ID **)&seq->scene); + seqclipboard_ptr_store((ID **)&seq->scene_camera); + seqclipboard_ptr_store((ID **)&seq->clip); + seqclipboard_ptr_store((ID **)&seq->mask); + seqclipboard_ptr_store((ID **)&seq->sound); +} +void BKE_sequence_clipboard_pointers_restore(Sequence *seq, Main *bmain) +{ + seqclipboard_ptr_restore(bmain, (ID **)&seq->scene); + seqclipboard_ptr_restore(bmain, (ID **)&seq->scene_camera); + seqclipboard_ptr_restore(bmain, (ID **)&seq->clip); + seqclipboard_ptr_restore(bmain, (ID **)&seq->mask); + seqclipboard_ptr_restore(bmain, (ID **)&seq->sound); +} +/* end clipboard pointer mess */ + + Editing *BKE_sequencer_editing_ensure(Scene *scene) { if (scene->ed == NULL) { @@ -818,33 +915,6 @@ void BKE_sequencer_clear_scene_in_allseqs(Main *bmain, Scene *scene) BKE_sequencer_base_recursive_apply(&scene_iter->ed->seqbase, clear_scene_in_allseqs_cb, scene); } } - - /* also clear clipboard */ - BKE_sequencer_base_recursive_apply(&seqbase_clipboard, clear_scene_in_allseqs_cb, scene); -} - -static int clear_movieclip_in_clipboard_cb(Sequence *seq, void *arg_pt) -{ - if (seq->clip == (MovieClip *)arg_pt) - seq->clip = NULL; - return 1; -} - -void BKE_sequencer_clear_movieclip_in_clipboard(MovieClip *clip) -{ - BKE_sequencer_base_recursive_apply(&seqbase_clipboard, clear_movieclip_in_clipboard_cb, clip); -} - -static int clear_mask_in_clipboard_cb(Sequence *seq, void *arg_pt) -{ - if (seq->mask == (Mask *)arg_pt) - seq->mask = NULL; - return 1; -} - -void BKE_sequencer_clear_mask_in_clipboard(Mask *mask) -{ - BKE_sequencer_base_recursive_apply(&seqbase_clipboard, clear_mask_in_clipboard_cb, mask); } typedef struct SeqUniqueInfo { diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 3d944300443..1ed22a53251 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -5803,21 +5803,23 @@ static void *restore_pointer_by_name(Main *mainp, ID *id, int user) return NULL; } +static void lib_link_seq_clipboard_pt_restore(ID *id, Main *newmain) +{ + if (id) { + /* clipboard must ensure this */ + BLI_assert(id->newid != NULL); + id->newid = restore_pointer_by_name(newmain, (ID *)id->newid, 1); + } +} static int lib_link_seq_clipboard_cb(Sequence *seq, void *arg_pt) { Main *newmain = (Main *)arg_pt; - - if (seq->sound) { - seq->sound = restore_pointer_by_name(newmain, (ID *)seq->sound, 0); - seq->sound->id.us++; - } - - if (seq->scene) - seq->scene = restore_pointer_by_name(newmain, (ID *)seq->scene, 1); - - if (seq->scene_camera) - seq->scene_camera = restore_pointer_by_name(newmain, (ID *)seq->scene_camera, 1); - + + lib_link_seq_clipboard_pt_restore((ID *)seq->scene, newmain); + lib_link_seq_clipboard_pt_restore((ID *)seq->scene_camera, newmain); + lib_link_seq_clipboard_pt_restore((ID *)seq->clip, newmain); + lib_link_seq_clipboard_pt_restore((ID *)seq->mask, newmain); + lib_link_seq_clipboard_pt_restore((ID *)seq->sound, newmain); return 1; } diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c index 8981a28834e..955a9c78c56 100644 --- a/source/blender/editors/space_sequencer/sequencer_edit.c +++ b/source/blender/editors/space_sequencer/sequencer_edit.c @@ -2721,7 +2721,6 @@ static void seq_copy_del_sound(Scene *scene, Sequence *seq) } } -/* TODO, validate scenes */ static int sequencer_copy_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); @@ -2766,6 +2765,11 @@ static int sequencer_copy_exec(bContext *C, wmOperator *op) for (seq = seqbase_clipboard.first; seq; seq = seq->next) { seq_copy_del_sound(scene, seq); } + + /* duplicate pointers */ + for (seq = seqbase_clipboard.first; seq; seq = seq->next) { + BKE_sequence_clipboard_pointers_store(seq); + } } return OPERATOR_FINISHED; @@ -2790,6 +2794,7 @@ void SEQUENCER_OT_copy(wmOperatorType *ot) static int sequencer_paste_exec(bContext *C, wmOperator *UNUSED(op)) { + Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); Editing *ed = BKE_sequencer_editing_get(scene, TRUE); /* create if needed */ ListBase nseqbase = {NULL, NULL}; @@ -2805,10 +2810,17 @@ static int sequencer_paste_exec(bContext *C, wmOperator *UNUSED(op)) if (ofs) { for (iseq = nseqbase.first; iseq; iseq = iseq->next) { BKE_sequence_translate(scene, iseq, ofs); - BKE_sequence_sound_init(scene, iseq); } } + for (iseq = nseqbase.first; iseq; iseq = iseq->next) { + BKE_sequence_clipboard_pointers_restore(iseq, bmain); + } + + for (iseq = nseqbase.first; iseq; iseq = iseq->next) { + BKE_sequence_sound_init(scene, iseq); + } + iseq_first = nseqbase.first; BLI_movelisttolist(ed->seqbasep, &nseqbase);