From abba6bf8b492a8b6fea2051c0c6a90e0f99d427c Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Sat, 11 Aug 2018 14:24:12 +1000 Subject: [PATCH] improved effects, implemented audio transitions, fixed nested sequences --- effects/crossdissolvetransition.cpp | 23 +- effects/transition.cpp | 19 +- effects/transition.h | 13 +- icons/add-effect.png | Bin 0 -> 1334 bytes icons/add-transition.png | Bin 0 -> 1295 bytes icons/icons.qrc | 2 + io/config.cpp | 6 +- io/config.h | 1 + panels/effectcontrols.cpp | 2 + panels/effectcontrols.ui | 255 +++++++++++++++----- panels/viewer.ui | 200 +++++++++------- playback/cacher.cpp | 29 ++- ui/collapsiblewidget.cpp | 49 ++-- ui/collapsiblewidget.h | 1 + ui/timelinewidget.cpp | 352 ++++++++++++++-------------- ui/timelinewidget.h | 2 + ui/viewerwidget.cpp | 6 +- 17 files changed, 616 insertions(+), 344 deletions(-) create mode 100644 icons/add-effect.png create mode 100644 icons/add-transition.png diff --git a/effects/crossdissolvetransition.cpp b/effects/crossdissolvetransition.cpp index 12920bf2b..16b0c2640 100644 --- a/effects/crossdissolvetransition.cpp +++ b/effects/crossdissolvetransition.cpp @@ -2,12 +2,29 @@ #include -CrossDissolveTransition::CrossDissolveTransition() : Transition(VIDEO_DISSOLVE_TRANSITION, "Cross Dissolve") {} +CrossDissolveTransition::CrossDissolveTransition() : Transition(VIDEO_DISSOLVE_TRANSITION) {} -void CrossDissolveTransition::process_transition(float progress) { +void CrossDissolveTransition::process_transition(double progress) { float color[4]; glGetFloatv(GL_CURRENT_COLOR, color); - glColor4f(1.0, 1.0, 1.0, color[3]*progress); + glColor4f(1.0, 1.0, 1.0, color[3]*progress); +} + +void CrossDissolveTransition::process_audio(double range_start, double range_end, quint8* samples, int nb_samples, bool reverse) { + double interval = (range_end - range_start) / nb_samples; + + for (int i=0;i> 8); + samples[i] = (quint8) samp; + } } Transition* CrossDissolveTransition::copy() { diff --git a/effects/transition.cpp b/effects/transition.cpp index 8aeed8660..ece066f5d 100644 --- a/effects/transition.cpp +++ b/effects/transition.cpp @@ -1,21 +1,32 @@ #include "transition.h" #include "project/clip.h" +#include "io/config.h" #include -Transition::Transition(int i, QString n) : id(i), name(n) { - length = 30; - link = NULL; +QVector video_transition_names; +QVector audio_transition_names; + +void init_transitions() { + video_transition_names.resize(VIDEO_TRANSITION_COUNT); + audio_transition_names.resize(AUDIO_TRANSITION_COUNT); + + video_transition_names[VIDEO_DISSOLVE_TRANSITION] = "Cross Dissolve"; + + audio_transition_names[AUDIO_LINEAR_FADE_TRANSITION] = "Linear Fade"; } +Transition::Transition(int i) : id(i), name(video_transition_names[i]), length(config.default_transition_length), link(NULL) {} + Transition::~Transition() {} Transition* Transition::copy() { return NULL; } -void Transition::process_transition(float) {} +void Transition::process_transition(double) {} +void Transition::process_audio(double, double, quint8*, int, bool) {} Transition* create_transition(int transition_id, Clip* c) { if (c->track < 0) { diff --git a/effects/transition.h b/effects/transition.h index 39e282ecb..b163cea7e 100644 --- a/effects/transition.h +++ b/effects/transition.h @@ -15,23 +15,30 @@ enum AudioTransitions { AUDIO_TRANSITION_COUNT }; +void init_transitions(); + +extern QVector video_transition_names; +extern QVector audio_transition_names; + class Transition { public: - Transition(int, QString); + Transition(int); ~Transition(); int id; QString name; int length; Transition* link; - virtual void process_transition(float); + virtual void process_transition(double); + virtual void process_audio(double, double, quint8*, int, bool); virtual Transition* copy(); }; class CrossDissolveTransition : public Transition { public: CrossDissolveTransition(); - void process_transition(float); + void process_transition(double); + void process_audio(double, double, quint8*, int, bool); Transition* copy(); }; diff --git a/icons/add-effect.png b/icons/add-effect.png new file mode 100644 index 0000000000000000000000000000000000000000..10125a31dc441ed1585d35f3b0dd227d2725831c GIT binary patch literal 1334 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 FV1i46EiM26 literal 0 HcmV?d00001 diff --git a/icons/icons.qrc b/icons/icons.qrc index 3bbbc0ea9..4c80d9b23 100644 --- a/icons/icons.qrc +++ b/icons/icons.qrc @@ -36,5 +36,7 @@ zoomin-disabled.png zoomout.png zoomout-disabled.png + add-transition.png + add-effect.png diff --git a/io/config.cpp b/io/config.cpp index 8163d43fe..d3033a1b3 100644 --- a/io/config.cpp +++ b/io/config.cpp @@ -16,7 +16,8 @@ Config::Config() edit_tool_also_seeks(false), select_also_seeks(false), paste_seeks(true), - rectified_waveforms(false) + rectified_waveforms(false), + default_transition_length(30) { } @@ -55,6 +56,8 @@ void Config::load(QString path) { img_seq_formats = stream.text().toString(); } else if (stream.name() == "RectifiedWaveforms") { rectified_waveforms = (stream.text() == "1"); + } else if (stream.name() == "DefaultTransitionLength") { + rectified_waveforms = stream.text().toInt(); } } } @@ -110,6 +113,7 @@ void Config::save(QString path) { stream.writeTextElement("PasteSeeks", QString::number(paste_seeks)); stream.writeTextElement("ImageSequenceFormats", img_seq_formats); stream.writeTextElement("RectifiedWaveforms", QString::number(rectified_waveforms)); + stream.writeTextElement("DefaultTransitionLength", QString::number(default_transition_length)); stream.writeEndElement(); stream.writeEndDocument(); // doc diff --git a/io/config.h b/io/config.h index 9742d4f64..f18f53c1e 100644 --- a/io/config.h +++ b/io/config.h @@ -16,6 +16,7 @@ struct Config { bool paste_seeks; QString img_seq_formats; bool rectified_waveforms; + int default_transition_length; void load(QString path); void save(QString path); diff --git a/panels/effectcontrols.cpp b/panels/effectcontrols.cpp index 49b79c088..98ad273f7 100644 --- a/panels/effectcontrols.cpp +++ b/panels/effectcontrols.cpp @@ -7,6 +7,7 @@ #include "panels/panels.h" #include "effects/effects.h" +#include "effects/transition.h" #include "project/clip.h" #include "project/effect.h" #include "ui/collapsiblewidget.h" @@ -20,6 +21,7 @@ EffectControls::EffectControls(QWidget *parent) : { ui->setupUi(this); init_effects(); + init_transitions(); clear_effects(false); } diff --git a/panels/effectcontrols.ui b/panels/effectcontrols.ui index ee12219ff..c1b26eec2 100644 --- a/panels/effectcontrols.ui +++ b/panels/effectcontrols.ui @@ -50,7 +50,7 @@ 0 0 619 - 482 + 489 @@ -88,28 +88,106 @@ 0 - - - - 0 - 0 - - - - - 9 - - + - padding: 5px; -background: rgba(0, 0, 0, 0.25); - - - VIDEO EFFECTS - - - Qt::AlignCenter + #veHeader { + background: rgba(0, 0, 0, 0.25); +} + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Add Video Effect + + + + + + + :/icons/add-effect.png + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 0 + + + + + 9 + + + + VIDEO EFFECTS + + + Qt::AlignCenter + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Add Video Transition + + + + + + + :/icons/add-transition.png + + + + + @@ -133,16 +211,6 @@ background: rgba(0, 0, 0, 0.25); - - - - - - - [+] Add Video Effect - - - @@ -165,28 +233,106 @@ background: rgba(0, 0, 0, 0.25); 0 - - - - 0 - 0 - - - - - 9 - - + - padding: 5px; -background: rgba(0, 0, 0, 0.25); - - - AUDIO EFFECTS - - - Qt::AlignCenter + #aeHeader { + background: rgba(0, 0, 0, 0.25); +} + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Add Audio Effect + + + + + + + :/icons/add-effect.png + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 0 + + + + + 9 + + + + AUDIO EFFECTS + + + Qt::AlignCenter + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Add Audio Transition + + + + + + + :/icons/add-transition.png + + + + + @@ -210,13 +356,6 @@ background: rgba(0, 0, 0, 0.25); - - - - [+] Add Audio Effect - - - diff --git a/panels/viewer.ui b/panels/viewer.ui index f850d20c7..3511ef03a 100644 --- a/panels/viewer.ui +++ b/panels/viewer.ui @@ -80,92 +80,132 @@ 0 - - - 0 - + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 0 + + + + - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - true - - - - :/icons/prev.png - :/icons/prev-disabled.png:/icons/prev.png - + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + true + + + + :/icons/prev.png + :/icons/prev-disabled.png:/icons/prev.png + + + + + + + + :/icons/rew.png + :/icons/rew-disabled.png:/icons/rew.png + + + + + + + + :/icons/play.png + :/icons/play-disabled.png:/icons/play.png + + + + + + + + :/icons/ff.png + :/icons/ff-disabled.png + + + + + + + + + :/icons/next.png + :/icons/next-disabled.png:/icons/next.png + + + + - - - - :/icons/rew.png - :/icons/rew-disabled.png:/icons/rew.png - - - - - - - - :/icons/play.png - :/icons/play-disabled.png:/icons/play.png - - - - - - - - :/icons/ff.png - :/icons/ff-disabled.png - - - - - - - - - :/icons/next.png - :/icons/next-disabled.png:/icons/next.png - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - 0 - + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 0 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + diff --git a/playback/cacher.cpp b/playback/cacher.cpp index 12a578083..250a3b439 100644 --- a/playback/cacher.cpp +++ b/playback/cacher.cpp @@ -7,6 +7,8 @@ #include "playback/playback.h" #include "effects/effects.h" #include "panels/timeline.h" +#include "panels/project.h" +#include "effects/transition.h" extern "C" { #include @@ -26,7 +28,32 @@ void apply_audio_effects(Clip* c, AVFrame* frame, int nb_bytes) { if (e->is_enabled()) e->process_audio(frame->data[0], nb_bytes); } if (c->opening_transition != NULL) { - + if (c->media_type == MEDIA_TYPE_FOOTAGE) { + double transition_start = (c->clip_in / c->sequence->frame_rate); + double transition_end = transition_start + (c->opening_transition->length / c->sequence->frame_rate); + double range_start = (frame->pts * av_q2d(c->stream->time_base)); + double range_end = range_start + ((double) nb_bytes * 0.5 / frame->channels / frame->sample_rate); + if (range_end < transition_end) { + double adjustment = transition_end - transition_start; + double adjusted_range_start = (range_start - transition_start) / adjustment; + double adjusted_range_end = (range_end - transition_start) / adjustment; + c->opening_transition->process_audio(adjusted_range_start, adjusted_range_end, frame->data[0], nb_bytes, false); + } + } + } + if (c->closing_transition != NULL) { + if (c->media_type == MEDIA_TYPE_FOOTAGE) { + double transition_end = (c->clip_in + c->getLength()) / c->sequence->frame_rate; + double transition_start = transition_end - (c->closing_transition->length / c->sequence->frame_rate); + double range_start = (frame->pts * av_q2d(c->stream->time_base)); + double range_end = range_start + ((double) nb_bytes * 0.5 / frame->channels / frame->sample_rate); + if (range_start > transition_start) { + double adjustment = transition_end - transition_start; + double adjusted_range_start = (range_start - transition_start) / adjustment; + double adjusted_range_end = (range_end - transition_start) / adjustment; + c->closing_transition->process_audio(adjusted_range_start, adjusted_range_end, frame->data[0], nb_bytes, true); + } + } } } diff --git a/ui/collapsiblewidget.cpp b/ui/collapsiblewidget.cpp index 51546d4d1..5f9844e9c 100644 --- a/ui/collapsiblewidget.cpp +++ b/ui/collapsiblewidget.cpp @@ -9,23 +9,26 @@ #include #include #include +#include CollapsibleWidget::CollapsibleWidget(QWidget* parent) : QWidget(parent) { selected = false; layout = new QVBoxLayout(this); layout->setMargin(0); + layout->setSpacing(0); - title_bar = new CollapsibleWidgetHeader(); - title_bar->setFocusPolicy(Qt::ClickFocus); - title_bar->setAutoFillBackground(true); + title_bar = new CollapsibleWidgetHeader(); + title_bar->setFocusPolicy(Qt::ClickFocus); + title_bar->setAutoFillBackground(true); QHBoxLayout* title_bar_layout = new QHBoxLayout(); - title_bar->setLayout(title_bar_layout); - title_bar_layout->setMargin(0); + title_bar_layout->setMargin(5); + title_bar->setLayout(title_bar_layout); enabled_check = new QCheckBox(); enabled_check->setChecked(true); header = new QLabel(); - collapse_button = new QPushButton("-"); + collapse_button = new QPushButton("[-]"); + collapse_button->setStyleSheet("QPushButton { border: none; }"); collapse_button->setMaximumWidth(25); setText(""); title_bar_layout->addWidget(collapse_button); @@ -34,12 +37,7 @@ CollapsibleWidget::CollapsibleWidget(QWidget* parent) : QWidget(parent) { title_bar_layout->addStretch(); layout->addWidget(title_bar); - connect(title_bar, SIGNAL(select(bool, bool)), this, SLOT(header_click(bool, bool))); - - line = new QFrame(); - line->setFrameShape(QFrame::HLine); - line->setFrameShadow(QFrame::Sunken); - layout->addWidget(line); + connect(title_bar, SIGNAL(select(bool, bool)), this, SLOT(header_click(bool, bool))); contents = NULL; } @@ -48,12 +46,12 @@ void CollapsibleWidget::header_click(bool s, bool deselect) { selected = s; title_bar->selected = s; if (s) { - QPalette p = palette(); + QPalette p = palette(); p.setColor(QPalette::Background, QColor(255, 255, 255, 64)); - title_bar->setPalette(p); - } else { - title_bar->setPalette(palette()); - } + title_bar->setPalette(p); + } else { + title_bar->setPalette(palette()); + } if (deselect) emit deselect_others(this); } @@ -82,12 +80,10 @@ void CollapsibleWidget::on_enabled_change(bool b) { void CollapsibleWidget::on_visible_change() { contents->setVisible(!contents->isVisible()); - collapse_button->setText(contents->isVisible() ? "-" : "+"); + collapse_button->setText(contents->isVisible() ? "[-]" : "[+]"); } -CollapsibleWidgetHeader::CollapsibleWidgetHeader(QWidget* parent) : QWidget(parent) { - selected = false; -} +CollapsibleWidgetHeader::CollapsibleWidgetHeader(QWidget* parent) : QWidget(parent), selected(false) {} void CollapsibleWidgetHeader::mousePressEvent(QMouseEvent* event) { if (selected) { @@ -98,5 +94,14 @@ void CollapsibleWidgetHeader::mousePressEvent(QMouseEvent* event) { } else { selected = true; emit select(selected, !(event->modifiers() & Qt::ShiftModifier)); - } + } +} + +void CollapsibleWidgetHeader::paintEvent(QPaintEvent *event) { + QWidget::paintEvent(event); + QPainter p(this); + p.setPen(Qt::white); + int line_x = width() * 0.01; + int line_y = height() - 1; + p.drawLine(line_x, line_y, width() - line_x - line_x, line_y); } diff --git a/ui/collapsiblewidget.h b/ui/collapsiblewidget.h index 2989f2bf6..24b66a108 100644 --- a/ui/collapsiblewidget.h +++ b/ui/collapsiblewidget.h @@ -16,6 +16,7 @@ public: bool selected; protected: void mousePressEvent(QMouseEvent* event); + void paintEvent(QPaintEvent *event); signals: void select(bool, bool); }; diff --git a/ui/timelinewidget.cpp b/ui/timelinewidget.cpp index 6ff072bbd..2cfa5af90 100644 --- a/ui/timelinewidget.cpp +++ b/ui/timelinewidget.cpp @@ -468,7 +468,7 @@ void TimelineWidget::mousePressEvent(QMouseEvent *event) { panel_timeline->selections.append(ss); } } - } + } } } @@ -509,182 +509,191 @@ void TimelineWidget::mouseReleaseEvent(QMouseEvent *event) { bool repaint = false; if (panel_timeline->moving_proc) { - TimelineAction* ta = new TimelineAction(); + repaint = true; + if (panel_timeline->ghosts.size() > 0) { + const Ghost& first_ghost = panel_timeline->ghosts.at(0); + if (first_ghost.old_in != first_ghost.in + || first_ghost.old_out != first_ghost.out + || first_ghost.old_clip_in != first_ghost.clip_in + || first_ghost.old_track != first_ghost.track) { + TimelineAction* ta = new TimelineAction(); - // if we were RIPPLING, move all the clips - if (panel_timeline->tool == TIMELINE_TOOL_RIPPLE) { - long ripple_length, ripple_point; + // if we were RIPPLING, move all the clips + if (panel_timeline->tool == TIMELINE_TOOL_RIPPLE) { + long ripple_length, ripple_point; - // ripple_length becomes the length/number of frames we trimmed - // ripple point becomes the point to ripple (i.e. the point after or before which we move every clip) - const Ghost& first_ghost = panel_timeline->ghosts.at(0); - if (panel_timeline->trim_in_point) { - ripple_length = first_ghost.old_in - panel_timeline->ghosts.at(0).in; - ripple_point = first_ghost.old_in; - } else { - // if we're trimming an out-point - ripple_length = first_ghost.old_out - panel_timeline->ghosts.at(0).out; - ripple_point = first_ghost.old_out; - } - QVector ignore_clips; - for (int i=0;ighosts.size();i++) { - const Ghost& g = panel_timeline->ghosts.at(i); + // ripple_length becomes the length/number of frames we trimmed + // ripple point becomes the point to ripple (i.e. the point after or before which we move every clip) + if (panel_timeline->trim_in_point) { + ripple_length = first_ghost.old_in - panel_timeline->ghosts.at(0).in; + ripple_point = first_ghost.old_in; + } else { + // if we're trimming an out-point + ripple_length = first_ghost.old_out - panel_timeline->ghosts.at(0).out; + ripple_point = first_ghost.old_out; + } + QVector ignore_clips; + for (int i=0;ighosts.size();i++) { + const Ghost& g = panel_timeline->ghosts.at(i); - // push rippled clips forward if necessary - if (panel_timeline->trim_in_point) { - ignore_clips.append(g.clip); - panel_timeline->ghosts[i].in += ripple_length; - panel_timeline->ghosts[i].out += ripple_length; - } + // push rippled clips forward if necessary + if (panel_timeline->trim_in_point) { + ignore_clips.append(g.clip); + panel_timeline->ghosts[i].in += ripple_length; + panel_timeline->ghosts[i].out += ripple_length; + } - long comp_point = panel_timeline->trim_in_point ? g.old_in : g.old_out; - ripple_point = qMin(ripple_point, comp_point); - } - if (!panel_timeline->trim_in_point) ripple_length = -ripple_length; - ta->ripple(sequence, ripple_point, ripple_length, ignore_clips); - } + long comp_point = panel_timeline->trim_in_point ? g.old_in : g.old_out; + ripple_point = qMin(ripple_point, comp_point); + } + if (!panel_timeline->trim_in_point) ripple_length = -ripple_length; + ta->ripple(sequence, ripple_point, ripple_length, ignore_clips); + } - if (panel_timeline->tool == TIMELINE_TOOL_POINTER - && (event->modifiers() & Qt::AltModifier) - && panel_timeline->trim_target == -1) { // if holding alt (and not trimming), duplicate rather than move - // duplicate clips - QVector old_clips; - QVector new_clips; - QVector delete_areas; - for (int i=0;ighosts.size();i++) { - const Ghost& g = panel_timeline->ghosts.at(i); - if (g.old_in != g.in || g.old_out != g.out || g.track != g.old_track || g.clip_in != g.old_clip_in) { - // create copy of clip - Clip* c = sequence->get_clip(g.clip)->copy(sequence); + if (panel_timeline->tool == TIMELINE_TOOL_POINTER + && (event->modifiers() & Qt::AltModifier) + && panel_timeline->trim_target == -1) { // if holding alt (and not trimming), duplicate rather than move + // duplicate clips + QVector old_clips; + QVector new_clips; + QVector delete_areas; + for (int i=0;ighosts.size();i++) { + const Ghost& g = panel_timeline->ghosts.at(i); + if (g.old_in != g.in || g.old_out != g.out || g.track != g.old_track || g.clip_in != g.old_clip_in) { + // create copy of clip + Clip* c = sequence->get_clip(g.clip)->copy(sequence); - c->timeline_in = g.in; - c->timeline_out = g.out; - c->track = g.track; + c->timeline_in = g.in; + c->timeline_out = g.out; + c->track = g.track; - Selection s; - s.in = g.in; - s.out = g.out; - s.track = g.track; - delete_areas.append(s); + Selection s; + s.in = g.in; + s.out = g.out; + s.track = g.track; + delete_areas.append(s); - old_clips.append(g.clip); - new_clips.append(c); - } - } - if (new_clips.size() > 0) { - panel_timeline->delete_areas_and_relink(ta, delete_areas); + old_clips.append(g.clip); + new_clips.append(c); + } + } + if (new_clips.size() > 0) { + panel_timeline->delete_areas_and_relink(ta, delete_areas); - // relink duplicated clips - panel_timeline->relink_clips_using_ids(old_clips, new_clips); + // relink duplicated clips + panel_timeline->relink_clips_using_ids(old_clips, new_clips); - for (int i=0;iadd_clips(sequence, new_clips); - } - } - } else { - // move clips - if (panel_timeline->tool == TIMELINE_TOOL_POINTER) { - QVector delete_areas; - for (int i=0;ighosts.size();i++) { - // step 1 - set clips that are moving to "undeletable" (to avoid step 2 deleting any part of them) - const Ghost& g = panel_timeline->ghosts.at(i); + for (int i=0;iadd_clips(sequence, new_clips); + } + } + } else { + // move clips + if (panel_timeline->tool == TIMELINE_TOOL_POINTER) { + QVector delete_areas; + for (int i=0;ighosts.size();i++) { + // step 1 - set clips that are moving to "undeletable" (to avoid step 2 deleting any part of them) + const Ghost& g = panel_timeline->ghosts.at(i); - sequence->get_clip(g.clip)->undeletable = true; + sequence->get_clip(g.clip)->undeletable = true; - Selection s; - s.in = g.in; - s.out = g.out; - s.track = g.track; - delete_areas.append(s); - } - panel_timeline->delete_areas_and_relink(ta, delete_areas); - for (int i=0;ighosts.size();i++) { - sequence->get_clip(panel_timeline->ghosts[i].clip)->undeletable = false; - } - } - for (int i=0;ighosts.size();i++) { - Ghost& g = panel_timeline->ghosts[i]; + Selection s; + s.in = g.in; + s.out = g.out; + s.track = g.track; + delete_areas.append(s); + } + panel_timeline->delete_areas_and_relink(ta, delete_areas); + for (int i=0;ighosts.size();i++) { + sequence->get_clip(panel_timeline->ghosts[i].clip)->undeletable = false; + } + } + for (int i=0;ighosts.size();i++) { + Ghost& g = panel_timeline->ghosts[i]; - // step 3 - move clips - Clip* c = sequence->get_clip(g.clip); - if (g.transition == NULL) { - ta->increase_timeline_in(sequence, g.clip, g.in - g.old_in); - ta->increase_timeline_out(sequence, g.clip, g.out - g.old_out); - ta->increase_track(sequence, g.clip, g.track - g.old_track); - ta->increase_clip_in(sequence, g.clip, g.clip_in - g.old_clip_in); + // step 3 - move clips + Clip* c = sequence->get_clip(g.clip); + if (g.transition == NULL) { + ta->increase_timeline_in(sequence, g.clip, g.in - g.old_in); + ta->increase_timeline_out(sequence, g.clip, g.out - g.old_out); + ta->increase_track(sequence, g.clip, g.track - g.old_track); + ta->increase_clip_in(sequence, g.clip, g.clip_in - g.old_clip_in); - // adjust transitions if we need to - long new_clip_length = (g.out - g.in); - if (c->opening_transition != NULL) { - long max_open_length = new_clip_length; - if (c->closing_transition != NULL && !panel_timeline->trim_in_point) { - max_open_length -= c->closing_transition->length; - } - if (max_open_length <= 0) { - ta->delete_transition(sequence, g.clip, TA_OPENING_TRANSITION); - } else if (c->opening_transition->length > max_open_length) { - ta->modify_transition(sequence, g.clip, TA_OPENING_TRANSITION, max_open_length); - } - } - if (c->closing_transition != NULL) { - long max_open_length = new_clip_length; - if (c->opening_transition != NULL && panel_timeline->trim_in_point) { - max_open_length -= c->opening_transition->length; - } - if (max_open_length <= 0) { - ta->delete_transition(sequence, g.clip, TA_CLOSING_TRANSITION); - } else if (c->closing_transition->length > max_open_length) { - ta->modify_transition(sequence, g.clip, TA_CLOSING_TRANSITION, max_open_length); - } - } - } else { - bool is_opening_transition = (g.transition == c->opening_transition); - long new_transition_length = g.out - g.in; - ta->modify_transition( - sequence, - g.clip, - is_opening_transition ? TA_OPENING_TRANSITION : TA_CLOSING_TRANSITION, - new_transition_length - ); + // adjust transitions if we need to + long new_clip_length = (g.out - g.in); + if (c->opening_transition != NULL) { + long max_open_length = new_clip_length; + if (c->closing_transition != NULL && !panel_timeline->trim_in_point) { + max_open_length -= c->closing_transition->length; + } + if (max_open_length <= 0) { + ta->delete_transition(sequence, g.clip, TA_OPENING_TRANSITION); + } else if (c->opening_transition->length > max_open_length) { + ta->modify_transition(sequence, g.clip, TA_OPENING_TRANSITION, max_open_length); + } + } + if (c->closing_transition != NULL) { + long max_open_length = new_clip_length; + if (c->opening_transition != NULL && panel_timeline->trim_in_point) { + max_open_length -= c->opening_transition->length; + } + if (max_open_length <= 0) { + ta->delete_transition(sequence, g.clip, TA_CLOSING_TRANSITION); + } else if (c->closing_transition->length > max_open_length) { + ta->modify_transition(sequence, g.clip, TA_CLOSING_TRANSITION, max_open_length); + } + } + } else { + bool is_opening_transition = (g.transition == c->opening_transition); + long new_transition_length = g.out - g.in; + ta->modify_transition( + sequence, + g.clip, + is_opening_transition ? TA_OPENING_TRANSITION : TA_CLOSING_TRANSITION, + new_transition_length + ); - long clip_length = c->getLength(); - if (is_opening_transition) { - if (g.in != g.old_in) { - // if transition is going to make the clip bigger, make the clip bigger - ta->increase_timeline_in(sequence, g.clip, g.in - g.old_in); - clip_length -= (g.in - g.old_in); - ta->increase_clip_in(sequence, g.clip, g.clip_in - g.old_clip_in); - } + long clip_length = c->getLength(); + if (is_opening_transition) { + if (g.in != g.old_in) { + // if transition is going to make the clip bigger, make the clip bigger + ta->increase_timeline_in(sequence, g.clip, g.in - g.old_in); + clip_length -= (g.in - g.old_in); + ta->increase_clip_in(sequence, g.clip, g.clip_in - g.old_clip_in); + } - if (c->closing_transition != NULL) { - if (new_transition_length == clip_length) { - ta->delete_transition(sequence, g.clip, TA_CLOSING_TRANSITION); - } else if (new_transition_length > clip_length - c->closing_transition->length) { - ta->modify_transition(sequence, g.clip, TA_CLOSING_TRANSITION, clip_length - new_transition_length); - } - } - } else { - if (g.out != g.old_out) { - // if transition is going to make the clip bigger, make the clip bigger - ta->increase_timeline_out(sequence, g.clip, g.out - g.old_out); - clip_length += (g.out - g.old_out); - } + if (c->closing_transition != NULL) { + if (new_transition_length == clip_length) { + ta->delete_transition(sequence, g.clip, TA_CLOSING_TRANSITION); + } else if (new_transition_length > clip_length - c->closing_transition->length) { + ta->modify_transition(sequence, g.clip, TA_CLOSING_TRANSITION, clip_length - new_transition_length); + } + } + } else { + if (g.out != g.old_out) { + // if transition is going to make the clip bigger, make the clip bigger + ta->increase_timeline_out(sequence, g.clip, g.out - g.old_out); + clip_length += (g.out - g.old_out); + } - if (c->opening_transition != NULL) { - if (new_transition_length == clip_length) { - ta->delete_transition(sequence, g.clip, TA_OPENING_TRANSITION); - } else if (new_transition_length > clip_length - c->opening_transition->length) { - ta->modify_transition(sequence, g.clip, TA_OPENING_TRANSITION, clip_length - new_transition_length); - } - } - } - } - } - } + if (c->opening_transition != NULL) { + if (new_transition_length == clip_length) { + ta->delete_transition(sequence, g.clip, TA_OPENING_TRANSITION); + } else if (new_transition_length > clip_length - c->opening_transition->length) { + ta->modify_transition(sequence, g.clip, TA_OPENING_TRANSITION, clip_length - new_transition_length); + } + } + } + } + } + } - undo_stack.push(ta); + undo_stack.push(ta); - panel_timeline->redraw_all_clips(true); + panel_timeline->redraw_all_clips(true); + repaint = false; + } + } } else if (panel_timeline->selecting || panel_timeline->rect_select_proc) { repaint = true; } else if (panel_timeline->splitting) { @@ -1158,18 +1167,21 @@ void TimelineWidget::mouseMoveEvent(QMouseEvent *event) { if (!add && panel_timeline->tool == TIMELINE_TOOL_POINTER && (c->opening_transition != NULL || c->closing_transition != NULL)) { // check if any selections contain the whole clip or transition for (int j=0;jselections.size();j++) { - if (c->opening_transition != NULL - && panel_timeline->selections.at(j).in == c->timeline_in - && panel_timeline->selections.at(j).out == c->timeline_in + c->opening_transition->length) { - g.transition = c->opening_transition; - add = true; - break; - } else if (c->closing_transition != NULL - && panel_timeline->selections.at(j).in == c->timeline_out - c->closing_transition->length - && panel_timeline->selections.at(j).out == c->timeline_out) { - g.transition = c->closing_transition; - add = true; - break; + const Selection& s = panel_timeline->selections.at(j); + if (s.track == c->track) { + if (c->opening_transition != NULL + && s.in == c->timeline_in + && s.out == c->timeline_in + c->opening_transition->length) { + g.transition = c->opening_transition; + add = true; + break; + } else if (c->closing_transition != NULL + && s.in == c->timeline_out - c->closing_transition->length + && s.out == c->timeline_out) { + g.transition = c->closing_transition; + add = true; + break; + } } } } diff --git a/ui/timelinewidget.h b/ui/timelinewidget.h index d90c19cde..29b53b242 100644 --- a/ui/timelinewidget.h +++ b/ui/timelinewidget.h @@ -15,6 +15,8 @@ struct Clip; class Timeline; class TimelineAction; +bool same_sign(int a, int b); + class TimelineWidget : public QWidget { Q_OBJECT public: diff --git a/ui/viewerwidget.cpp b/ui/viewerwidget.cpp index 59723471a..c4a6eb0af 100644 --- a/ui/viewerwidget.cpp +++ b/ui/viewerwidget.cpp @@ -103,7 +103,7 @@ void ViewerWidget::compose_sequence(Clip* nest, bool render_audio) { Clip* c = s->get_clip(i); // if clip starts within one second and/or hasn't finished yet - if (c != NULL && !(nest != NULL && c->track != nest->track)) { + if (c != NULL && !(nest != NULL && !same_sign(c->track, nest->track))) { bool clip_is_active = false; switch (c->media_type) { @@ -158,6 +158,7 @@ void ViewerWidget::compose_sequence(Clip* nest, bool render_audio) { } else { switch (c->media_type) { case MEDIA_TYPE_FOOTAGE: + qDebug() << "clip"; if (c->stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { // start preparing cache get_clip_frame(c, playhead); @@ -215,7 +216,8 @@ void ViewerWidget::compose_sequence(Clip* nest, bool render_audio) { c->lock.unlock(); } break; - case MEDIA_TYPE_SEQUENCE: + case MEDIA_TYPE_SEQUENCE: + qDebug() << "nest"; compose_sequence(c, render_audio); c->run_video_post_effect_stack(); break;