improved effects, implemented audio transitions, fixed nested sequences

This commit is contained in:
itsmattkc
2018-08-11 14:24:12 +10:00
parent d4825761dd
commit abba6bf8b4
17 changed files with 616 additions and 344 deletions
+20 -3
View File
@@ -2,12 +2,29 @@
#include <QOpenGLFunctions>
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<nb_samples;i+=2) {
qint16 samp = (qint16) (((samples[i+1] & 0xFF) << 8) | (samples[i] & 0xFF));
if (reverse) {
samp *= 1 - (range_start + (interval * i));
} else {
samp *= range_start + (interval * i);
}
samples[i+1] = (quint8) (samp >> 8);
samples[i] = (quint8) samp;
}
}
Transition* CrossDissolveTransition::copy() {
+15 -4
View File
@@ -1,21 +1,32 @@
#include "transition.h"
#include "project/clip.h"
#include "io/config.h"
#include <QDebug>
Transition::Transition(int i, QString n) : id(i), name(n) {
length = 30;
link = NULL;
QVector<QString> video_transition_names;
QVector<QString> 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) {
+10 -3
View File
@@ -15,23 +15,30 @@ enum AudioTransitions {
AUDIO_TRANSITION_COUNT
};
void init_transitions();
extern QVector<QString> video_transition_names;
extern QVector<QString> 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();
};
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

+2
View File
@@ -36,5 +36,7 @@
<file>zoomin-disabled.png</file>
<file>zoomout.png</file>
<file>zoomout-disabled.png</file>
<file>add-transition.png</file>
<file>add-effect.png</file>
</qresource>
</RCC>
+5 -1
View File
@@ -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
+1
View File
@@ -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);
+2
View File
@@ -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);
}
+197 -58
View File
@@ -50,7 +50,7 @@
<x>0</x>
<y>0</y>
<width>619</width>
<height>482</height>
<height>489</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
@@ -88,28 +88,106 @@
<number>0</number>
</property>
<item>
<widget class="QLabel" name="label">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<pointsize>9</pointsize>
</font>
</property>
<widget class="QWidget" name="veHeader" native="true">
<property name="styleSheet">
<string notr="true">padding: 5px;
background: rgba(0, 0, 0, 0.25);</string>
</property>
<property name="text">
<string>VIDEO EFFECTS</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
<string notr="true">#veHeader {
background: rgba(0, 0, 0, 0.25);
}</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QPushButton" name="add_video_effect_button">
<property name="toolTip">
<string>Add Video Effect</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset>
<normalon>:/icons/add-effect.png</normalon>
</iconset>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="label">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<pointsize>9</pointsize>
</font>
</property>
<property name="text">
<string>VIDEO EFFECTS</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="pushButton_2">
<property name="toolTip">
<string>Add Video Transition</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset>
<normalon>:/icons/add-transition.png</normalon>
</iconset>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
@@ -133,16 +211,6 @@ background: rgba(0, 0, 0, 0.25);</string>
</layout>
</widget>
</item>
<item>
<widget class="QPushButton" name="add_video_effect_button">
<property name="styleSheet">
<string notr="true"/>
</property>
<property name="text">
<string>[+] Add Video Effect</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
@@ -165,28 +233,106 @@ background: rgba(0, 0, 0, 0.25);</string>
<number>0</number>
</property>
<item>
<widget class="QLabel" name="label_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<pointsize>9</pointsize>
</font>
</property>
<widget class="QWidget" name="aeHeader" native="true">
<property name="styleSheet">
<string notr="true">padding: 5px;
background: rgba(0, 0, 0, 0.25);</string>
</property>
<property name="text">
<string>AUDIO EFFECTS</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
<string notr="true">#aeHeader {
background: rgba(0, 0, 0, 0.25);
}</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QPushButton" name="add_audio_effect_button">
<property name="toolTip">
<string>Add Audio Effect</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset>
<normalon>:/icons/add-effect.png</normalon>
</iconset>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="label_3">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<pointsize>9</pointsize>
</font>
</property>
<property name="text">
<string>AUDIO EFFECTS</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_4">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="pushButton_3">
<property name="toolTip">
<string>Add Audio Transition</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset>
<normalon>:/icons/add-transition.png</normalon>
</iconset>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
@@ -210,13 +356,6 @@ background: rgba(0, 0, 0, 0.25);</string>
</layout>
</widget>
</item>
<item>
<widget class="QPushButton" name="add_audio_effect_button">
<property name="text">
<string>[+] Add Audio Effect</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
+120 -80
View File
@@ -80,92 +80,132 @@
<number>0</number>
</property>
<item>
<widget class="QLabel" name="currentTimecode">
<property name="text">
<string>0</string>
</property>
<widget class="QWidget" name="widget" native="true">
<layout class="QHBoxLayout" name="horizontalLayout_3">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="currentTimecode">
<property name="text">
<string>0</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="pushButton">
<property name="enabled">
<bool>true</bool>
</property>
<property name="icon">
<iconset resource="../icons/icons.qrc">
<normaloff>:/icons/prev.png</normaloff>
<disabledoff>:/icons/prev-disabled.png</disabledoff>:/icons/prev.png</iconset>
</property>
<widget class="QWidget" name="widget_2" native="true">
<layout class="QHBoxLayout" name="horizontalLayout_4">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QPushButton" name="pushButton">
<property name="enabled">
<bool>true</bool>
</property>
<property name="icon">
<iconset resource="../icons/icons.qrc">
<normaloff>:/icons/prev.png</normaloff>
<disabledoff>:/icons/prev-disabled.png</disabledoff>:/icons/prev.png</iconset>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton_2">
<property name="icon">
<iconset resource="../icons/icons.qrc">
<normaloff>:/icons/rew.png</normaloff>
<disabledoff>:/icons/rew-disabled.png</disabledoff>:/icons/rew.png</iconset>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton_3">
<property name="icon">
<iconset resource="../icons/icons.qrc">
<normaloff>:/icons/play.png</normaloff>
<disabledoff>:/icons/play-disabled.png</disabledoff>:/icons/play.png</iconset>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton_4">
<property name="icon">
<iconset>
<normalon>:/icons/ff.png</normalon>
<disabledoff>:/icons/ff-disabled.png</disabledoff>
</iconset>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton_5">
<property name="icon">
<iconset resource="../icons/icons.qrc">
<normaloff>:/icons/next.png</normaloff>
<disabledoff>:/icons/next-disabled.png</disabledoff>:/icons/next.png</iconset>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton_2">
<property name="icon">
<iconset resource="../icons/icons.qrc">
<normaloff>:/icons/rew.png</normaloff>
<disabledoff>:/icons/rew-disabled.png</disabledoff>:/icons/rew.png</iconset>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton_3">
<property name="icon">
<iconset resource="../icons/icons.qrc">
<normaloff>:/icons/play.png</normaloff>
<disabledoff>:/icons/play-disabled.png</disabledoff>:/icons/play.png</iconset>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton_4">
<property name="icon">
<iconset>
<normalon>:/icons/ff.png</normalon>
<disabledoff>:/icons/ff-disabled.png</disabledoff>
</iconset>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton_5">
<property name="icon">
<iconset resource="../icons/icons.qrc">
<normaloff>:/icons/next.png</normaloff>
<disabledoff>:/icons/next-disabled.png</disabledoff>:/icons/next.png</iconset>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="endTimecode">
<property name="text">
<string>0</string>
</property>
<widget class="QWidget" name="widget_3" native="true">
<layout class="QHBoxLayout" name="horizontalLayout_5">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="endTimecode">
<property name="text">
<string>0</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
+28 -1
View File
@@ -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 <libavformat/avformat.h>
@@ -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);
}
}
}
}
+27 -22
View File
@@ -9,23 +9,26 @@
#include <QPushButton>
#include <QMouseEvent>
#include <QWidget>
#include <QPainter>
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("<untitled>");
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);
}
+1
View File
@@ -16,6 +16,7 @@ public:
bool selected;
protected:
void mousePressEvent(QMouseEvent* event);
void paintEvent(QPaintEvent *event);
signals:
void select(bool, bool);
};
+182 -170
View File
@@ -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<int> ignore_clips;
for (int i=0;i<panel_timeline->ghosts.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<int> ignore_clips;
for (int i=0;i<panel_timeline->ghosts.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<int> old_clips;
QVector<Clip*> new_clips;
QVector<Selection> delete_areas;
for (int i=0;i<panel_timeline->ghosts.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<int> old_clips;
QVector<Clip*> new_clips;
QVector<Selection> delete_areas;
for (int i=0;i<panel_timeline->ghosts.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;i<new_clips.size();i++) {
ta->add_clips(sequence, new_clips);
}
}
} else {
// move clips
if (panel_timeline->tool == TIMELINE_TOOL_POINTER) {
QVector<Selection> delete_areas;
for (int i=0;i<panel_timeline->ghosts.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;i<new_clips.size();i++) {
ta->add_clips(sequence, new_clips);
}
}
} else {
// move clips
if (panel_timeline->tool == TIMELINE_TOOL_POINTER) {
QVector<Selection> delete_areas;
for (int i=0;i<panel_timeline->ghosts.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;i<panel_timeline->ghosts.size();i++) {
sequence->get_clip(panel_timeline->ghosts[i].clip)->undeletable = false;
}
}
for (int i=0;i<panel_timeline->ghosts.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;i<panel_timeline->ghosts.size();i++) {
sequence->get_clip(panel_timeline->ghosts[i].clip)->undeletable = false;
}
}
for (int i=0;i<panel_timeline->ghosts.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;j<panel_timeline->selections.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;
}
}
}
}
+2
View File
@@ -15,6 +15,8 @@ struct Clip;
class Timeline;
class TimelineAction;
bool same_sign(int a, int b);
class TimelineWidget : public QWidget {
Q_OBJECT
public:
+4 -2
View File
@@ -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;