diff --git a/io/clipboard.cpp b/io/clipboard.cpp index b02761d5e..8a699e379 100644 --- a/io/clipboard.cpp +++ b/io/clipboard.cpp @@ -5,14 +5,18 @@ int clipboard_type = CLIPBOARD_TYPE_CLIP; QVector clipboard; +QVector clipboard_transitions; void clear_clipboard() { - for (int i=0;i(clipboard.at(i)); - } else if (clipboard_type == CLIPBOARD_TYPE_EFFECT) { - delete static_cast(clipboard.at(i)); - } - } - clipboard.clear(); + for (int i=0;i(clipboard.at(i)); + } else if (clipboard_type == CLIPBOARD_TYPE_EFFECT) { + delete static_cast(clipboard.at(i)); + } + } + for (int i=0;clipboard_transitions.size();i++) { + delete clipboard_transitions.at(i); + } + clipboard.clear(); } diff --git a/io/clipboard.h b/io/clipboard.h index d76b7fa59..700841e95 100644 --- a/io/clipboard.h +++ b/io/clipboard.h @@ -3,10 +3,13 @@ #include +class Transition; + #define CLIPBOARD_TYPE_CLIP 0 #define CLIPBOARD_TYPE_EFFECT 1 extern int clipboard_type; +extern QVector clipboard_transitions; extern QVector clipboard; void clear_clipboard(); diff --git a/panels/timeline.cpp b/panels/timeline.cpp index 849d637ab..d455be47a 100644 --- a/panels/timeline.cpp +++ b/panels/timeline.cpp @@ -838,8 +838,6 @@ void Timeline::copy(bool del) { Clip* copied_clip = c->copy(NULL); - copied_clip->cached_fr = sequence->frame_rate; - // copy linked IDs (we correct these later in paste()) copied_clip->linked = c->linked; diff --git a/project/clip.cpp b/project/clip.cpp index 65fbdb50a..213a53858 100644 --- a/project/clip.cpp +++ b/project/clip.cpp @@ -10,6 +10,7 @@ #include "project/sequence.h" #include "panels/timeline.h" #include "project/media.h" +#include "io/clipboard.h" #include "undo.h" extern "C" { @@ -17,69 +18,70 @@ extern "C" { } Clip::Clip(Sequence* s) : - sequence(s), - enabled(true), - clip_in(0), - timeline_in(0), - timeline_out(0), - track(0), - media(NULL), - speed(1.0), - reverse(false), - maintain_audio_pitch(false), - autoscale(config.autoscale_by_default), - opening_transition(-1), - closing_transition(-1), - undeletable(false), - replaced(false), - ignore_reverse(false), - use_existing_frame(false), + sequence(s), + enabled(true), + clip_in(0), + timeline_in(0), + timeline_out(0), + track(0), + media(NULL), + speed(1.0), + reverse(false), + maintain_audio_pitch(false), + autoscale(config.autoscale_by_default), + opening_transition(-1), + closing_transition(-1), + undeletable(false), + replaced(false), + ignore_reverse(false), + use_existing_frame(false), filter_graph(NULL), - fbo(NULL), - opts(NULL) + fbo(NULL), + opts(NULL) { pkt = av_packet_alloc(); - reset(); + reset(); } Clip* Clip::copy(Sequence* s) { - Clip* copy = new Clip(s); + Clip* copy = new Clip(s); - copy->enabled = enabled; - copy->name = QString(name); - copy->clip_in = clip_in; - copy->timeline_in = timeline_in; - copy->timeline_out = timeline_out; - copy->track = track; - copy->color_r = color_r; - copy->color_g = color_g; + copy->enabled = enabled; + copy->name = QString(name); + copy->clip_in = clip_in; + copy->timeline_in = timeline_in; + copy->timeline_out = timeline_out; + copy->track = track; + copy->color_r = color_r; + copy->color_g = color_g; copy->color_b = color_b; - copy->media = media; - copy->media_stream = media_stream; - copy->autoscale = autoscale; + copy->media = media; + copy->media_stream = media_stream; + copy->autoscale = autoscale; copy->speed = speed; copy->maintain_audio_pitch = maintain_audio_pitch; copy->reverse = reverse; - for (int i=0;ieffects.append(effects.at(i)->copy(copy)); - } + for (int i=0;ieffects.append(effects.at(i)->copy(copy)); + } - // TODO make a replacemennt for this somehow - if (get_opening_transition() != NULL && get_opening_transition()->secondary_clip == NULL) copy->opening_transition = get_opening_transition()->copy(copy, NULL); - if (get_closing_transition() != NULL && get_closing_transition()->secondary_clip == NULL) copy->closing_transition = get_closing_transition()->copy(copy, NULL); + copy->cached_fr = (this->sequence == NULL) ? cached_fr : this->sequence->frame_rate; + + if (get_opening_transition() != NULL && get_opening_transition()->secondary_clip == NULL) copy->opening_transition = get_opening_transition()->copy(copy, NULL); + if (get_closing_transition() != NULL && get_closing_transition()->secondary_clip == NULL) copy->closing_transition = get_closing_transition()->copy(copy, NULL); copy->recalculateMaxLength(); - return copy; + return copy; } void Clip::reset() { - audio_just_reset = false; - open = false; - finished_opening = false; + audio_just_reset = false; + open = false; + finished_opening = false; pkt_written = false; - audio_reset = false; + audio_reset = false; frame_sample_index = -1; audio_buffer_write = false; texture_frame = -1; @@ -88,42 +90,42 @@ void Clip::reset() { codec = NULL; codecCtx = NULL; texture = NULL; - last_invalid_ts = -1; + last_invalid_ts = -1; } void Clip::reset_audio() { - if (media == NULL || media->get_type() == MEDIA_TYPE_FOOTAGE) { - audio_reset = true; - frame_sample_index = -1; - audio_buffer_write = 0; - } else if (media->get_type() == MEDIA_TYPE_SEQUENCE) { - Sequence* nested_sequence = media->to_sequence(); - for (int i=0;iclips.size();i++) { - Clip* c = nested_sequence->clips.at(i); - if (c != NULL) c->reset_audio(); - } - } + if (media == NULL || media->get_type() == MEDIA_TYPE_FOOTAGE) { + audio_reset = true; + frame_sample_index = -1; + audio_buffer_write = 0; + } else if (media->get_type() == MEDIA_TYPE_SEQUENCE) { + Sequence* nested_sequence = media->to_sequence(); + for (int i=0;iclips.size();i++) { + Clip* c = nested_sequence->clips.at(i); + if (c != NULL) c->reset_audio(); + } + } } void Clip::refresh() { // validates media if it was replaced - if (replaced && media != NULL && media->get_type() == MEDIA_TYPE_FOOTAGE) { - Footage* m = media->to_footage(); + if (replaced && media != NULL && media->get_type() == MEDIA_TYPE_FOOTAGE) { + Footage* m = media->to_footage(); - if (track < 0 && m->video_tracks.size() > 0) { - media_stream = m->video_tracks.at(0)->file_index; - } else if (track >= 0 && m->audio_tracks.size() > 0) { - media_stream = m->audio_tracks.at(0)->file_index; - } + if (track < 0 && m->video_tracks.size() > 0) { + media_stream = m->video_tracks.at(0)->file_index; + } else if (track >= 0 && m->audio_tracks.size() > 0) { + media_stream = m->audio_tracks.at(0)->file_index; + } } replaced = false; - // reinitializes all effects... just in case - for (int i=0;irefresh(); } - recalculateMaxLength(); + recalculateMaxLength(); } void Clip::queue_clear() { @@ -142,79 +144,87 @@ void Clip::queue_remove_earliest() { } } av_frame_free(&queue[earliest_frame]); - queue.removeAt(earliest_frame); + queue.removeAt(earliest_frame); } Transition* Clip::get_opening_transition() { - if (opening_transition > -1) { - return this->sequence->transitions.at(opening_transition); - } - return NULL; + if (opening_transition > -1) { + if (this->sequence == NULL) { + return clipboard_transitions.at(opening_transition); + } else { + return this->sequence->transitions.at(opening_transition); + } + } + return NULL; } Transition* Clip::get_closing_transition() { - if (closing_transition > -1) { - return this->sequence->transitions.at(closing_transition); - } - return NULL; + if (closing_transition > -1) { + if (this->sequence == NULL) { + return clipboard_transitions.at(closing_transition); + } else { + return this->sequence->transitions.at(closing_transition); + } + } + return NULL; } Clip::~Clip() { - if (open) { + if (open) { close_clip(this); - // make sure clip has closed before clip is destroyed - if (multithreaded && media != NULL && media->get_type() == MEDIA_TYPE_FOOTAGE) { - cacher->wait(); - } - } + // make sure clip has closed before clip is destroyed + if (multithreaded && media != NULL && media->get_type() == MEDIA_TYPE_FOOTAGE) { + cacher->wait(); + } + } - if (opening_transition != -1) this->sequence->hard_delete_transition(this, TA_OPENING_TRANSITION); - if (closing_transition != -1) this->sequence->hard_delete_transition(this, TA_CLOSING_TRANSITION); + if (opening_transition != -1) this->sequence->hard_delete_transition(this, TA_OPENING_TRANSITION); + if (closing_transition != -1) this->sequence->hard_delete_transition(this, TA_CLOSING_TRANSITION); - for (int i=0;isecondary_clip != NULL) { - // we must be the secondary clip, so return (timeline in - length) - return clip_in - get_opening_transition()->get_true_length(); - } - return clip_in; + if (get_opening_transition() != NULL && get_opening_transition()->secondary_clip != NULL) { + // we must be the secondary clip, so return (timeline in - length) + return clip_in - get_opening_transition()->get_true_length(); + } + return clip_in; } long Clip::get_timeline_in_with_transition() { - if (get_opening_transition() != NULL && get_opening_transition()->secondary_clip != NULL) { - // we must be the secondary clip, so return (timeline in - length) - return timeline_in - get_opening_transition()->get_true_length(); - } - return timeline_in; + if (get_opening_transition() != NULL && get_opening_transition()->secondary_clip != NULL) { + // we must be the secondary clip, so return (timeline in - length) + return timeline_in - get_opening_transition()->get_true_length(); + } + return timeline_in; } long Clip::get_timeline_out_with_transition() { - if (get_closing_transition() != NULL && get_closing_transition()->secondary_clip != NULL) { - // we must be the primary clip, so return (timeline out + length2) - return timeline_out + get_closing_transition()->get_true_length(); - } else { - return timeline_out; - } + if (get_closing_transition() != NULL && get_closing_transition()->secondary_clip != NULL) { + // we must be the primary clip, so return (timeline out + length2) + return timeline_out + get_closing_transition()->get_true_length(); + } else { + return timeline_out; + } } // timeline functions long Clip::getLength() { - return timeline_out - timeline_in; + return timeline_out - timeline_in; } double Clip::getMediaFrameRate() { - Q_ASSERT(track < 0); - if (media != NULL) { - double rate = media->get_frame_rate(media_stream); - if (!qIsNaN(rate)) return rate; - } - if (sequence != NULL) return sequence->frame_rate; + Q_ASSERT(track < 0); + if (media != NULL) { + double rate = media->get_frame_rate(media_stream); + if (!qIsNaN(rate)) return rate; + } + if (sequence != NULL) return sequence->frame_rate; return qSNaN(); } @@ -224,29 +234,29 @@ void Clip::recalculateMaxLength() { fr /= speed; - calculated_length = LONG_MAX; + calculated_length = LONG_MAX; - if (media != NULL) { - switch (media->get_type()) { - case MEDIA_TYPE_FOOTAGE: - { - Footage* m = media->to_footage(); - FootageStream* ms = m->get_stream_from_file_index(track < 0, media_stream); - if (ms != NULL && ms->infinite_length) { - calculated_length = LONG_MAX; - } else { - calculated_length = m->get_length_in_frames(fr); - } - } - break; - case MEDIA_TYPE_SEQUENCE: - { - Sequence* s = media->to_sequence(); - calculated_length = refactor_frame_number(s->getEndFrame(), s->frame_rate, fr); - } - break; - } - } + if (media != NULL) { + switch (media->get_type()) { + case MEDIA_TYPE_FOOTAGE: + { + Footage* m = media->to_footage(); + FootageStream* ms = m->get_stream_from_file_index(track < 0, media_stream); + if (ms != NULL && ms->infinite_length) { + calculated_length = LONG_MAX; + } else { + calculated_length = m->get_length_in_frames(fr); + } + } + break; + case MEDIA_TYPE_SEQUENCE: + { + Sequence* s = media->to_sequence(); + calculated_length = refactor_frame_number(s->getEndFrame(), s->frame_rate, fr); + } + break; + } + } } } @@ -256,16 +266,16 @@ long Clip::getMaximumLength() { int Clip::getWidth() { if (media == NULL && sequence != NULL) return sequence->width; - switch (media->get_type()) { + switch (media->get_type()) { case MEDIA_TYPE_FOOTAGE: { - FootageStream* ms = media->to_footage()->get_stream_from_file_index(track < 0, media_stream); + FootageStream* ms = media->to_footage()->get_stream_from_file_index(track < 0, media_stream); if (ms != NULL) return ms->video_width; - if (sequence != NULL) return sequence->width; + if (sequence != NULL) return sequence->width; } case MEDIA_TYPE_SEQUENCE: { - Sequence* s = media->to_sequence(); + Sequence* s = media->to_sequence(); return s->width; } } @@ -274,16 +284,16 @@ int Clip::getWidth() { int Clip::getHeight() { if (media == NULL && sequence != NULL) return sequence->height; - switch (media->get_type()) { + switch (media->get_type()) { case MEDIA_TYPE_FOOTAGE: { - FootageStream* ms = media->to_footage()->get_stream_from_file_index(track < 0, media_stream); + FootageStream* ms = media->to_footage()->get_stream_from_file_index(track < 0, media_stream); if (ms != NULL) return ms->video_height; - if (sequence != NULL) return sequence->height; + if (sequence != NULL) return sequence->height; } case MEDIA_TYPE_SEQUENCE: { - Sequence* s = media->to_sequence(); + Sequence* s = media->to_sequence(); return s->height; } } @@ -292,11 +302,11 @@ int Clip::getHeight() { void Clip::refactor_frame_rate(ComboAction* ca, double multiplier, bool change_timeline_points) { if (change_timeline_points) { - move_clip(ca, this, - qRound((double) timeline_in * multiplier), - qRound((double) timeline_out * multiplier), - qRound((double) clip_in * multiplier), - track); + move_clip(ca, this, + qRound((double) timeline_in * multiplier), + qRound((double) timeline_out * multiplier), + qRound((double) clip_in * multiplier), + track); } for (int i=0;i Transition::Transition(Clip* c, Clip* s, const EffectMeta* em) : - Effect(c, em), secondary_clip(s), - length(30) + Effect(c, em), secondary_clip(s), + length(30) { - length_field = add_row("Length:", false)->add_field(EFFECT_FIELD_DOUBLE, "length"); - connect(length_field, SIGNAL(changed()), this, SLOT(set_length_from_slider())); - length_field->set_double_default_value(30); - length_field->set_double_minimum_value(0); + length_field = add_row("Length:", false)->add_field(EFFECT_FIELD_DOUBLE, "length"); + connect(length_field, SIGNAL(changed()), this, SLOT(set_length_from_slider())); + length_field->set_double_default_value(30); + length_field->set_double_minimum_value(0); - LabelSlider* length_ui_ele = static_cast(length_field->ui_element); - length_ui_ele->set_display_type(LABELSLIDER_FRAMENUMBER); - length_ui_ele->set_frame_rate(parent_clip->sequence->frame_rate); + LabelSlider* length_ui_ele = static_cast(length_field->ui_element); + length_ui_ele->set_display_type(LABELSLIDER_FRAMENUMBER); + length_ui_ele->set_frame_rate(parent_clip->sequence == NULL ? parent_clip->cached_fr : parent_clip->sequence->frame_rate); } int Transition::copy(Clip *c, Clip* s) { - int copy_index = create_transition(c, s, meta); - c->sequence->transitions.at(copy_index)->length = length; - return copy_index; + return create_transition(c, s, meta, length); } void Transition::set_length(long l) { - length = l; - length_field->set_double_value(l); + length = l; + length_field->set_double_value(l); } long Transition::get_true_length() { - return length; + return length; } long Transition::get_length() { - if (secondary_clip != NULL) { - return length * 2; - } - return length; + if (secondary_clip != NULL) { + return length * 2; + } + return length; } void Transition::set_length_from_slider() { - set_length(length_field->get_double_value(0)); - update_ui(false); + set_length(length_field->get_double_value(0)); + update_ui(false); } Transition* get_transition_from_meta(Clip* c, Clip* s, const EffectMeta* em) { - if (!em->filename.isEmpty()) { - // load effect from file - return new Transition(c, s, em); - } else if (em->internal >= 0 && em->internal < TRANSITION_INTERNAL_COUNT) { - // must be an internal effect - switch (em->internal) { - case TRANSITION_INTERNAL_CROSSDISSOLVE: return new CrossDissolveTransition(c, s, em); - case TRANSITION_INTERNAL_LINEARFADE: return new LinearFadeTransition(c, s, em); - case TRANSITION_INTERNAL_EXPONENTIALFADE: return new ExponentialFadeTransition(c, s, em); - case TRANSITION_INTERNAL_LOGARITHMICFADE: return new LogarithmicFadeTransition(c, s, em); - case TRANSITION_INTERNAL_CUBE: return new CubeTransition(c, s, em); - } - } else { - dout << "[ERROR] Invalid transition data"; - QMessageBox::critical(mainWindow, "Invalid transition", "No candidate for transition '" + em->name + "'. This transition may be corrupt. Try reinstalling it or Olive."); - } - return NULL; + if (!em->filename.isEmpty()) { + // load effect from file + return new Transition(c, s, em); + } else if (em->internal >= 0 && em->internal < TRANSITION_INTERNAL_COUNT) { + // must be an internal effect + switch (em->internal) { + case TRANSITION_INTERNAL_CROSSDISSOLVE: return new CrossDissolveTransition(c, s, em); + case TRANSITION_INTERNAL_LINEARFADE: return new LinearFadeTransition(c, s, em); + case TRANSITION_INTERNAL_EXPONENTIALFADE: return new ExponentialFadeTransition(c, s, em); + case TRANSITION_INTERNAL_LOGARITHMICFADE: return new LogarithmicFadeTransition(c, s, em); + case TRANSITION_INTERNAL_CUBE: return new CubeTransition(c, s, em); + } + } else { + dout << "[ERROR] Invalid transition data"; + QMessageBox::critical(mainWindow, "Invalid transition", "No candidate for transition '" + em->name + "'. This transition may be corrupt. Try reinstalling it or Olive."); + } + return NULL; } -int create_transition(Clip* c, Clip* s, const EffectMeta* em) { - Transition* t = get_transition_from_meta(c, s, em); - if (t != NULL) { - c->sequence->transitions.append(t); - return c->sequence->transitions.size() - 1; - } - return -1; +int create_transition(Clip* c, Clip* s, const EffectMeta* em, long length) { + Transition* t = get_transition_from_meta(c, s, em); + if (length >= 0) t->set_length(length); + if (t != NULL) { + QVector& transition_list = (c->sequence == NULL) ? clipboard_transitions : c->sequence->transitions; + transition_list.append(t); + return transition_list.size() - 1; + } + return -1; } diff --git a/project/transition.h b/project/transition.h index 2f9df63f4..29e2e2493 100644 --- a/project/transition.h +++ b/project/transition.h @@ -14,22 +14,22 @@ #define TRANSITION_INTERNAL_CUBE 4 #define TRANSITION_INTERNAL_COUNT 5 -int create_transition(Clip* c, Clip* s, const EffectMeta* em); +int create_transition(Clip* c, Clip* s, const EffectMeta* em, long length = -1); class Transition : public Effect { - Q_OBJECT + Q_OBJECT public: - Transition(Clip* c, Clip* s, const EffectMeta* em); - int copy(Clip* c, Clip* s); - Clip* secondary_clip; - void set_length(long l); - long get_true_length(); - long get_length(); + Transition(Clip* c, Clip* s, const EffectMeta* em); + int copy(Clip* c, Clip* s); + Clip* secondary_clip; + void set_length(long l); + long get_true_length(); + long get_length(); private slots: - void set_length_from_slider(); + void set_length_from_slider(); private: - long length; // used only for transitions - EffectField* length_field; + long length; // used only for transitions + EffectField* length_field; }; #endif // TRANSITION_H