added more functionality to transition tool

This commit is contained in:
itsmattkc
2018-11-06 18:30:38 +11:00
parent 047176c64d
commit 11d10ef329
27 changed files with 456 additions and 330 deletions
+51 -11
View File
@@ -29,6 +29,10 @@
#include "effects/internal/volumeeffect.h"
#include "effects/internal/paneffect.h"
#include "effects/internal/shakeeffect.h"
#include "effects/internal/crossdissolvetransition.h"
#include "effects/internal/linearfadetransition.h"
#include "effects/internal/exponentialfadetransition.h"
#include "effects/internal/logarithmicfadetransition.h"
#include <QCheckBox>
#include <QGridLayout>
@@ -52,14 +56,18 @@ Effect* create_effect(Clip* c, const EffectMeta* em) {
} else if (em->internal >= 0 && em->internal < EFFECT_INTERNAL_COUNT) {
// must be an internal effect
switch (em->internal) {
case EFFECT_INTERNAL_TRANSFORM: return new TransformEffect(c, em); break;
case EFFECT_INTERNAL_TEXT: return new TextEffect(c, em); break;
case EFFECT_INTERNAL_SOLID: return new SolidEffect(c, em); break;
case EFFECT_INTERNAL_NOISE: return new AudioNoiseEffect(c, em); break;
case EFFECT_INTERNAL_VOLUME: return new VolumeEffect(c, em); break;
case EFFECT_INTERNAL_PAN: return new PanEffect(c, em); break;
case EFFECT_INTERNAL_TONE: return new ToneEffect(c, em); break;
case EFFECT_INTERNAL_SHAKE: return new ShakeEffect(c, em); break;
case EFFECT_INTERNAL_TRANSFORM: return new TransformEffect(c, em);
case EFFECT_INTERNAL_TEXT: return new TextEffect(c, em);
case EFFECT_INTERNAL_SOLID: return new SolidEffect(c, em);
case EFFECT_INTERNAL_NOISE: return new AudioNoiseEffect(c, em);
case EFFECT_INTERNAL_VOLUME: return new VolumeEffect(c, em);
case EFFECT_INTERNAL_PAN: return new PanEffect(c, em);
case EFFECT_INTERNAL_TONE: return new ToneEffect(c, em);
case EFFECT_INTERNAL_SHAKE: return new ShakeEffect(c, em);
case EFFECT_INTERNAL_CROSSDISSOLVE: return new CrossDissolveTransition(c, em);
case EFFECT_INTERNAL_LINEARFADE: return new LinearFadeTransition(c, em);
case EFFECT_INTERNAL_EXPONENTIALFADE: return new ExponentialFadeTransition(c, em);
case EFFECT_INTERNAL_LOGARITHMICFADE: return new LogarithmicFadeTransition(c, em);
}
} else {
dout << "[ERROR] Invalid effect data";
@@ -85,6 +93,9 @@ const EffectMeta* get_internal_meta(int internal_id) {
void load_internal_effects() {
EffectMeta em;
// internal effects
em.type = EFFECT_TYPE_EFFECT;
em.name = "Volume";
em.internal = EFFECT_INTERNAL_VOLUME;
audio_effects.append(em);
@@ -120,6 +131,27 @@ void load_internal_effects() {
em.category = "Distort";
em.internal = EFFECT_INTERNAL_SHAKE;
video_effects.append(em);
// internal transitions
em.type = EFFECT_TYPE_TRANSITION;
em.category = "";
em.name = "Cross Dissolve";
em.internal = EFFECT_INTERNAL_CROSSDISSOLVE;
video_effects.append(em);
em.name = "Linear Fade";
em.internal = EFFECT_INTERNAL_LINEARFADE;
audio_effects.append(em);
em.name = "Exponential Fade";
em.internal = EFFECT_INTERNAL_EXPONENTIALFADE;
audio_effects.append(em);
em.name = "Logarithmic Fade";
em.internal = EFFECT_INTERNAL_LOGARITHMICFADE;
audio_effects.append(em);
}
void load_shader_effects() {
@@ -203,7 +235,9 @@ Effect::Effect(Clip* c, const EffectMeta *em) :
isOpen(false),
glslProgram(NULL),
texture(NULL),
bound(false)
bound(false),
tlink(NULL),
length(30)
{
// set up base UI
container = new CollapsibleWidget();
@@ -536,7 +570,9 @@ QString save_data_to_string(int type, const QVariant& data) {
void Effect::load(QXmlStreamReader& stream) {
int row_count = 0;
while (!stream.atEnd() && !(stream.name() == "effect" && stream.isEndElement())) {
QString tag = stream.name().toString();
while (!stream.atEnd() && !(stream.name() == tag && stream.isEndElement())) {
stream.readNext();
if (stream.name() == "row" && stream.isStartElement()) {
if (row_count < rows.size()) {
@@ -552,7 +588,6 @@ void Effect::load(QXmlStreamReader& stream) {
const QXmlStreamAttribute& attr = stream.attributes().at(k);
if (attr.name() == "enabled") {
row->setKeyframing(attr.value() == "1");
break;
}
}
if (row->isKeyframing()) {
@@ -638,6 +673,10 @@ void Effect::load(QXmlStreamReader& stream) {
}
void Effect::save(QXmlStreamWriter& stream) {
stream.writeAttribute("name", meta->name);
stream.writeAttribute("enabled", QString::number(is_enabled()));
stream.writeAttribute("length", QString::number(length));
for (int i=0;i<rows.size();i++) {
EffectRow* row = rows.at(i);
stream.writeStartElement("row"); // row
@@ -716,6 +755,7 @@ void Effect::endEffect() {
Effect* Effect::copy(Clip* c) {
Effect* copy = create_effect(c, meta);
copy->set_enabled(is_enabled());
copy->length = length;
copy_field_keyframes(copy);
return copy;
}
+17 -2
View File
@@ -29,6 +29,7 @@ struct EffectMeta {
QString category;
QString filename;
int internal;
int type;
};
extern QVector<EffectMeta> video_effects;
@@ -44,6 +45,8 @@ extern QMutex effects_loaded;
#define EFFECT_TYPE_INVALID 0
#define EFFECT_TYPE_VIDEO 1
#define EFFECT_TYPE_AUDIO 2
#define EFFECT_TYPE_EFFECT 3
#define EFFECT_TYPE_TRANSITION 4
#define EFFECT_FIELD_DOUBLE 0
#define EFFECT_FIELD_COLOR 1
@@ -64,7 +67,16 @@ extern QMutex effects_loaded;
#define EFFECT_INTERNAL_PAN 5
#define EFFECT_INTERNAL_TONE 6
#define EFFECT_INTERNAL_SHAKE 7
#define EFFECT_INTERNAL_COUNT 8
#define EFFECT_INTERNAL_CROSSDISSOLVE 8
#define EFFECT_INTERNAL_LINEARFADE 9
#define EFFECT_INTERNAL_EXPONENTIALFADE 10
#define EFFECT_INTERNAL_LOGARITHMICFADE 11
#define EFFECT_INTERNAL_COUNT 12
#define TRAN_TYPE_OPEN 1
#define TRAN_TYPE_CLOSE 2
#define TRAN_TYPE_OPENWLINK 3
#define TRAN_TYPE_CLOSEWLINK 4
struct GLTextureCoords {
int vertexTopLeftX;
@@ -193,6 +205,9 @@ public:
QString name;
CollapsibleWidget* container;
long length; // only used for transitions
Effect* tlink;
EffectRow* add_row(const QString &name);
EffectRow* row(int i);
int row_count();
@@ -205,7 +220,7 @@ public:
Effect* copy(Clip* c);
void copy_field_keyframes(Effect *e);
void load(QXmlStreamReader& stream);
void load(QXmlStreamReader& stream);
void save(QXmlStreamWriter& stream);
// glsl handling
+5 -11
View File
@@ -1,19 +1,13 @@
#include "../transition.h"
#include "crossdissolvetransition.h"
#include <QOpenGLFunctions>
// TODO port to GLSL?
CrossDissolveTransition::CrossDissolveTransition(Clip* c, const EffectMeta* em) : Effect(c, em) {
enable_coords = true;
}
CrossDissolveTransition::CrossDissolveTransition() : Transition(VIDEO_DISSOLVE_TRANSITION) {}
void CrossDissolveTransition::process_transition(double progress) {
void CrossDissolveTransition::process_coords(double progress, GLTextureCoords&) {
float color[4];
glGetFloatv(GL_CURRENT_COLOR, color);
glColor4f(1.0, 1.0, 1.0, color[3]*progress);
}
Transition* CrossDissolveTransition::copy() {
Transition* t = new CrossDissolveTransition();
t->length = length;
return t;
}
@@ -0,0 +1,12 @@
#ifndef CROSSDISSOLVETRANSITION_H
#define CROSSDISSOLVETRANSITION_H
#include "../effect.h"
class CrossDissolveTransition : public Effect {
public:
CrossDissolveTransition(Clip* c, const EffectMeta* em);
void process_coords(double timecode, GLTextureCoords &);
};
#endif // CROSSDISSOLVETRANSITION_H
@@ -0,0 +1,37 @@
#include "exponentialfadetransition.h"
#include <QtMath>
ExponentialFadeTransition::ExponentialFadeTransition(Clip* c, const EffectMeta* em) : Effect(c, em) {}
void ExponentialFadeTransition::process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int type) {
double interval = (timecode_end-timecode_start)/nb_bytes;
for (int i=0;i<nb_bytes;i+=2) {
qint16 samp = (qint16) (((samples[i+1] & 0xFF) << 8) | (samples[i] & 0xFF));
/*switch (type) {
case TRAN_TYPE_OPEN:
case TRAN_TYPE_OPENWLINK:
samp *= qSqrt(timecode_start + (interval * i));
break;
case TRAN_TYPE_CLOSE:
case TRAN_TYPE_CLOSEWLINK:
samp *= qSqrt(1 - (timecode_start + (interval * i)));
break;
}*/
switch (type) {
case TRAN_TYPE_OPEN:
case TRAN_TYPE_OPENWLINK:
samp *= qPow(timecode_start + (interval * i), 2);
break;
case TRAN_TYPE_CLOSE:
case TRAN_TYPE_CLOSEWLINK:
samp *= qPow(1 - (timecode_start + (interval * i)), 2);
break;
}
samples[i+1] = (quint8) (samp >> 8);
samples[i] = (quint8) samp;
}
}
@@ -0,0 +1,12 @@
#ifndef EXPONENTIALFADETRANSITION_H
#define EXPONENTIALFADETRANSITION_H
#include "../effect.h"
class ExponentialFadeTransition : public Effect {
public:
ExponentialFadeTransition(Clip* c, const EffectMeta* em);
void process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int channel_count);
};
#endif // LINEARFADETRANSITION_H
+14 -15
View File
@@ -1,26 +1,25 @@
#include "../transition.h"
#include "linearfadetransition.h"
LinearFadeTransition::LinearFadeTransition() : Transition(AUDIO_LINEAR_FADE_TRANSITION) {}
LinearFadeTransition::LinearFadeTransition(Clip* c, const EffectMeta* em) : Effect(c, em) {}
void LinearFadeTransition::process_audio(double range_start, double range_end, quint8* samples, int nb_samples, bool reverse) {
double interval = (range_end - range_start) / nb_samples;
void LinearFadeTransition::process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int type) {
double interval = (timecode_end-timecode_start)/nb_bytes;
for (int i=0;i<nb_samples;i+=2) {
for (int i=0;i<nb_bytes;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);
switch (type) {
case TRAN_TYPE_OPEN:
case TRAN_TYPE_OPENWLINK:
samp *= timecode_start + (interval * i);
break;
case TRAN_TYPE_CLOSE:
case TRAN_TYPE_CLOSEWLINK:
samp *= 1 - (timecode_start + (interval * i));
break;
}
samples[i+1] = (quint8) (samp >> 8);
samples[i] = (quint8) samp;
}
}
Transition* LinearFadeTransition::copy() {
Transition* t = new LinearFadeTransition();
t->length = length;
return t;
}
+12
View File
@@ -0,0 +1,12 @@
#ifndef LINEARFADETRANSITION_H
#define LINEARFADETRANSITION_H
#include "../effect.h"
class LinearFadeTransition : public Effect {
public:
LinearFadeTransition(Clip* c, const EffectMeta* em);
void process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int channel_count);
};
#endif // LINEARFADETRANSITION_H
@@ -0,0 +1,27 @@
#include "logarithmicfadetransition.h"
#include <QtMath>
LogarithmicFadeTransition::LogarithmicFadeTransition(Clip* c, const EffectMeta* em) : Effect(c, em) {}
void LogarithmicFadeTransition::process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int type) {
double interval = (timecode_end-timecode_start)/nb_bytes;
for (int i=0;i<nb_bytes;i+=2) {
qint16 samp = (qint16) (((samples[i+1] & 0xFF) << 8) | (samples[i] & 0xFF));
switch (type) {
case TRAN_TYPE_OPEN:
case TRAN_TYPE_OPENWLINK:
samp *= qSqrt(timecode_start + (interval * i));
break;
case TRAN_TYPE_CLOSE:
case TRAN_TYPE_CLOSEWLINK:
samp *= qSqrt(1 - (timecode_start + (interval * i)));
break;
}
samples[i+1] = (quint8) (samp >> 8);
samples[i] = (quint8) samp;
}
}
@@ -0,0 +1,12 @@
#ifndef LOGARITHMICFADETRANSITION_H
#define LOGARITHMICFADETRANSITION_H
#include "../effect.h"
class LogarithmicFadeTransition : public Effect {
public:
LogarithmicFadeTransition(Clip* c, const EffectMeta* em);
void process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int channel_count);
};
#endif // LOGARITHMICFADETRANSITION_H
-42
View File
@@ -1,42 +0,0 @@
#include "transition.h"
#include "project/clip.h"
#include "io/config.h"
#include "debug.h"
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(double) {}
void Transition::process_audio(double, double, quint8*, int, bool) {}
Transition* create_transition(int transition_id, Clip* c) {
if (c->track < 0) {
switch (transition_id) {
case VIDEO_DISSOLVE_TRANSITION: return new CrossDissolveTransition();
}
} else {
switch (transition_id) {
case AUDIO_LINEAR_FADE_TRANSITION: return new LinearFadeTransition();
}
}
dout << "[ERROR] Invalid transition ID";
return NULL;
}
-53
View File
@@ -1,53 +0,0 @@
#ifndef TRANSITION_H
#define TRANSITION_H
#include <QString>
struct Clip;
enum VideoTransitions {
VIDEO_DISSOLVE_TRANSITION,
VIDEO_TRANSITION_COUNT
};
enum AudioTransitions {
AUDIO_LINEAR_FADE_TRANSITION,
AUDIO_TRANSITION_COUNT
};
class Transition
{
public:
Transition(int);
~Transition();
int id;
QString name;
int length;
Transition* link;
virtual void process_transition(double);
virtual void process_audio(double, double, quint8*, int, bool);
virtual Transition* copy();
};
void init_transitions();
Transition* create_transition(int transition_id, Clip* c);
extern QVector<QString> video_transition_names;
extern QVector<QString> audio_transition_names;
// Video Transitions
class CrossDissolveTransition : public Transition {
public:
CrossDissolveTransition();
void process_transition(double);
Transition* copy();
};
// Audio Transitions
class LinearFadeTransition : public Transition {
public:
LinearFadeTransition();
void process_audio(double, double, quint8*, int, bool);
Transition* copy();
};
#endif // TRANSITION_H
+8 -4
View File
@@ -51,7 +51,6 @@ SOURCES += \
io/previewgenerator.cpp \
ui/labelslider.cpp \
dialogs/preferencesdialog.cpp \
effects/transition.cpp \
ui/audiomonitor.cpp \
project/undo.cpp \
ui/scrollarea.cpp \
@@ -81,7 +80,9 @@ SOURCES += \
effects/internal/toneeffect.cpp \
effects/internal/volumeeffect.cpp \
effects/internal/crossdissolvetransition.cpp \
effects/internal/shakeeffect.cpp
effects/internal/shakeeffect.cpp \
effects/internal/exponentialfadetransition.cpp \
effects/internal/logarithmicfadetransition.cpp
HEADERS += \
mainwindow.h \
@@ -111,7 +112,6 @@ HEADERS += \
io/previewgenerator.h \
ui/labelslider.h \
dialogs/preferencesdialog.h \
effects/transition.h \
ui/audiomonitor.h \
project/undo.h \
ui/scrollarea.h \
@@ -141,7 +141,11 @@ HEADERS += \
effects/internal/paneffect.h \
effects/internal/toneeffect.h \
effects/internal/volumeeffect.h \
effects/internal/shakeeffect.h
effects/internal/shakeeffect.h \
effects/internal/linearfadetransition.h \
effects/internal/crossdissolvetransition.h \
effects/internal/exponentialfadetransition.h \
effects/internal/logarithmicfadetransition.h
FORMS += \
mainwindow.ui \
+47 -45
View File
@@ -8,7 +8,6 @@
#include "panels/panels.h"
#include "effects/effect.h"
#include "effects/transition.h"
#include "project/clip.h"
#include "effects/effect.h"
#include "ui/collapsiblewidget.h"
@@ -27,8 +26,7 @@ EffectControls::EffectControls(QWidget *parent) :
ui(new Ui::EffectControls)
{
ui->setupUi(this);
init_effects();
init_transitions();
init_effects();
clear_effects(false);
ui->headers->viewer = panel_sequence_viewer;
ui->headers->snapping = false;
@@ -66,15 +64,16 @@ void EffectControls::menu_select(QAction* q) {
for (int i=0;i<selected_clips.size();i++) {
Clip* c = sequence->clips.at(selected_clips.at(i));
if ((c->track < 0) == video_menu) {
const EffectMeta* meta = reinterpret_cast<const EffectMeta*>(q->data().value<quintptr>());
if (transition_menu) {
if (c->opening_transition == NULL) {
ca->append(new AddTransitionCommand(c, q->data().toInt(), TA_OPENING_TRANSITION));
ca->append(new AddTransitionCommand(c, meta, TA_OPENING_TRANSITION, 30));
}
if (c->closing_transition == NULL) {
ca->append(new AddTransitionCommand(c, q->data().toInt(), TA_CLOSING_TRANSITION));
ca->append(new AddTransitionCommand(c, meta, TA_CLOSING_TRANSITION, 30));
}
} else {
ca->append(new AddEffectCommand(c, reinterpret_cast<EffectMeta*>(q->data().value<quintptr>())));
ca->append(new AddEffectCommand(c, meta));
}
}
}
@@ -149,7 +148,7 @@ void EffectControls::show_effect_menu(bool video, bool transitions) {
video_menu = video;
transition_menu = transitions;
if (transition_menu) {
/*if (transition_menu) {
// TODO old effect/transition code grandfathered in, to be updated
int lim;
@@ -181,64 +180,67 @@ void EffectControls::show_effect_menu(bool video, bool transitions) {
}
connect(&effects_menu, SIGNAL(triggered(QAction*)), this, SLOT(menu_select(QAction*)));
effects_menu.exec(QCursor::pos());
} else {
} else {*/
effects_loaded.lock();
QVector<EffectMeta>& effect_list = (video) ? video_effects : audio_effects;
QMenu effects_menu(this);
for (int i=0;i<effect_list.size();i++) {
const EffectMeta& em = effect_list.at(i);
QAction* action = new QAction(&effects_menu);
action->setText(em.name);
action->setData(reinterpret_cast<quintptr>(&em));
QMenu* parent = &effects_menu;
if (!em.category.isEmpty()) {
bool found = false;
for (int j=0;j<effects_menu.actions().size();j++) {
QAction* action = effects_menu.actions().at(j);
if (action->menu() != NULL) {
if (action->menu()->title() == em.category) {
parent = action->menu();
found = true;
break;
}
}
}
if (!found) {
parent = new QMenu(&effects_menu);
parent->setTitle(em.category);
if (em.type == EFFECT_TYPE_TRANSITION == transition_menu) {
QAction* action = new QAction(&effects_menu);
action->setText(em.name);
action->setData(reinterpret_cast<quintptr>(&em));
QMenu* parent = &effects_menu;
if (!em.category.isEmpty()) {
bool found = false;
for (int i=0;i<effects_menu.actions().size();i++) {
QAction* comp_action = effects_menu.actions().at(i);
if (comp_action->text() > em.category) {
effects_menu.insertMenu(comp_action, parent);
found = true;
break;
for (int j=0;j<effects_menu.actions().size();j++) {
QAction* action = effects_menu.actions().at(j);
if (action->menu() != NULL) {
if (action->menu()->title() == em.category) {
parent = action->menu();
found = true;
break;
}
}
}
if (!found) effects_menu.addMenu(parent);
}
}
if (!found) {
parent = new QMenu(&effects_menu);
parent->setTitle(em.category);
bool found = false;
for (int i=0;i<parent->actions().size();i++) {
QAction* comp_action = parent->actions().at(i);
if (comp_action->text() > action->text()) {
parent->insertAction(comp_action, action);
found = true;
break;
bool found = false;
for (int i=0;i<effects_menu.actions().size();i++) {
QAction* comp_action = effects_menu.actions().at(i);
if (comp_action->text() > em.category) {
effects_menu.insertMenu(comp_action, parent);
found = true;
break;
}
}
if (!found) effects_menu.addMenu(parent);
}
}
bool found = false;
for (int i=0;i<parent->actions().size();i++) {
QAction* comp_action = parent->actions().at(i);
if (comp_action->text() > action->text()) {
parent->insertAction(comp_action, action);
found = true;
break;
}
}
if (!found) parent->addAction(action);
}
if (!found) parent->addAction(action);
}
effects_loaded.unlock();
connect(&effects_menu, SIGNAL(triggered(QAction*)), this, SLOT(menu_select(QAction*)));
effects_menu.exec(QCursor::pos());
}
//}
}
void EffectControls::clear_effects(bool clear_cache) {
+84 -75
View File
@@ -10,7 +10,6 @@
#include "panels/timeline.h"
#include "project/sequence.h"
#include "effects/effect.h"
#include "effects/transition.h"
#include "io/previewgenerator.h"
#include "project/undo.h"
#include "mainwindow.h"
@@ -360,7 +359,6 @@ void Project::delete_selected_media() {
}
for (int i=0;i<items.size();i++) {
ca->append(new DeleteMediaCommand(items.at(i)));
if (get_type_from_tree(items.at(i)) == MEDIA_TYPE_SEQUENCE) {
@@ -982,70 +980,78 @@ bool Project::load_worker(QFile& f, QXmlStreamReader& stream, int type) {
}
}
}
} else if (stream.name() == "effects") {
while (!(stream.name() == "effects" && stream.isEndElement()) && !stream.atEnd()) {
stream.readNext();
if (stream.name() == "effect" && stream.isStartElement()) {
int effect_id = -1;
QString effect_name;
bool effect_enabled = true;
for (int j=0;j<stream.attributes().size();j++) {
const QXmlStreamAttribute& attr = stream.attributes().at(j);
if (attr.name() == "id") {
effect_id = attr.value().toInt();
} else if (attr.name() == "enabled") {
effect_enabled = (attr.value() == "1");
} else if (attr.name() == "name") {
effect_name = attr.value().toString();
}
}
} else if (stream.isStartElement() && (stream.name() == "effect" || stream.name() == "opening" || stream.name() == "closing")) {
int effect_id = -1;
QString effect_name;
bool effect_enabled = true;
int effect_length = -1;
for (int j=0;j<stream.attributes().size();j++) {
const QXmlStreamAttribute& attr = stream.attributes().at(j);
if (attr.name() == "id") {
effect_id = attr.value().toInt();
} else if (attr.name() == "enabled") {
effect_enabled = (attr.value() == "1");
} else if (attr.name() == "name") {
effect_name = attr.value().toString();
} else if (attr.name() == "length") {
effect_length = attr.value().toInt();
}
}
// backwards compatibility with 180820
if (effect_id != -1) {
switch (effect_id) {
case 0: effect_name = (c->track < 0) ? "Transform" : "Volume"; break;
case 1: effect_name = (c->track < 0) ? "Shake" : "Pan"; break;
case 2: effect_name = (c->track < 0) ? "Text" : "Noise"; break;
case 3: effect_name = (c->track < 0) ? "Solid" : "Tone"; break;
case 4: effect_name = "Invert"; break;
case 5: effect_name = "Chroma Key"; break;
case 6: effect_name = "Gaussian Blur"; break;
case 7: effect_name = "Crop"; break;
case 8: effect_name = "Flip"; break;
case 9: effect_name = "Box Blur"; break;
case 10: effect_name = "Wave"; break;
case 11: effect_name = "Temperature"; break;
}
// backwards compatibility with 180820
if (stream.name() == "effect" && effect_id != -1) {
switch (effect_id) {
case 0: effect_name = (c->track < 0) ? "Transform" : "Volume"; break;
case 1: effect_name = (c->track < 0) ? "Shake" : "Pan"; break;
case 2: effect_name = (c->track < 0) ? "Text" : "Noise"; break;
case 3: effect_name = (c->track < 0) ? "Solid" : "Tone"; break;
case 4: effect_name = "Invert"; break;
case 5: effect_name = "Chroma Key"; break;
case 6: effect_name = "Gaussian Blur"; break;
case 7: effect_name = "Crop"; break;
case 8: effect_name = "Flip"; break;
case 9: effect_name = "Box Blur"; break;
case 10: effect_name = "Wave"; break;
case 11: effect_name = "Temperature"; break;
}
}
// wait for effects to be loaded
effects_loaded.lock();
const EffectMeta* meta = NULL;
// find effect with this name
if (!effect_name.isEmpty()) {
QVector<EffectMeta>& effect_list = (c->track < 0) ? video_effects : audio_effects;
for (int j=0;j<effect_list.size();j++) {
if (effect_list.at(j).name == effect_name) {
meta = &effect_list.at(j);
break;
}
}
}
// wait for effects to be loaded
effects_loaded.lock();
effects_loaded.unlock();
const EffectMeta* meta = NULL;
if (meta == NULL) {
dout << "[WARNING] An effect used by this project is missing. It was not loaded.";
} else {
QString tag = stream.name().toString();
// find effect with this name
if (!effect_name.isEmpty()) {
QVector<EffectMeta>& effect_list = (c->track < 0) ? video_effects : audio_effects;
for (int j=0;j<effect_list.size();j++) {
if (effect_list.at(j).name == effect_name) {
meta = &effect_list.at(j);
break;
}
}
}
Effect* e = create_effect(c, meta);
if (effect_length > -1) e->length = effect_length;
e->set_enabled(effect_enabled);
e->load(stream);
if (meta == NULL) {
dout << "[WARNING] An effect used by this project is missing. It was not loaded.";
} else {
Effect* e = create_effect(c, meta);
e->set_enabled(effect_enabled);
e->load(stream);
c->effects.append(e);
}
effects_loaded.unlock();
}
}
if (tag == "opening") {
c->opening_transition = e;
} else if (tag == "closing") {
c->closing_transition = e;
} else {
c->effects.append(e);
}
}
}
}
}
@@ -1290,12 +1296,7 @@ void Project::save_folder(QXmlStreamWriter& stream, QTreeWidgetItem* parent, int
stream.writeAttribute("in", QString::number(c->timeline_in));
stream.writeAttribute("out", QString::number(c->timeline_out));
stream.writeAttribute("track", QString::number(c->track));
if (c->opening_transition != NULL) {
stream.writeAttribute("opening", QString::number(c->opening_transition->id));
}
if (c->closing_transition != NULL) {
stream.writeAttribute("closing", QString::number(c->closing_transition->id));
}
stream.writeAttribute("r", QString::number(c->color_r));
stream.writeAttribute("g", QString::number(c->color_g));
stream.writeAttribute("b", QString::number(c->color_b));
@@ -1324,16 +1325,24 @@ void Project::save_folder(QXmlStreamWriter& stream, QTreeWidgetItem* parent, int
}
stream.writeEndElement(); // linked
stream.writeStartElement("effects"); // effects
for (int k=0;k<c->effects.size();k++) {
stream.writeStartElement("effect"); // effect
Effect* e = c->effects.at(k);
stream.writeAttribute("name", e->meta->name);
stream.writeAttribute("enabled", QString::number(e->is_enabled()));
e->save(stream);
stream.writeEndElement(); // effect
}
stream.writeEndElement(); // effects
stream.writeStartElement("effect"); // effect
c->effects.at(k)->save(stream);
stream.writeEndElement(); // effect
}
if (c->opening_transition != NULL) {
stream.writeStartElement("opening");
c->opening_transition->save(stream);
stream.writeEndElement(); // opening
}
if (c->closing_transition != NULL) {
stream.writeStartElement("closing"); // closing
c->closing_transition->save(stream);
stream.writeEndElement(); // closing
}
stream.writeEndElement(); // clip
}
}
+42 -5
View File
@@ -12,10 +12,11 @@
#include "panels/viewer.h"
#include "playback/cacher.h"
#include "playback/playback.h"
#include "effects/transition.h"
#include "ui_viewer.h"
#include "project/undo.h"
#include "io/config.h"
#include "effects/effect.h"
#include "debug.h"
#include <QTime>
#include <QScrollBar>
@@ -159,11 +160,11 @@ void Timeline::add_transition() {
Clip* c = sequence->clips.at(i);
if (c != NULL && is_clip_selected(c, true)) {
if (c->opening_transition == NULL) {
ca->append(new AddTransitionCommand(c, 0, TA_OPENING_TRANSITION));
ca->append(new AddTransitionCommand(c, get_internal_meta(EFFECT_INTERNAL_LINEARFADE), TA_OPENING_TRANSITION, 30));
adding = true;
}
if (c->closing_transition == NULL) {
ca->append(new AddTransitionCommand(c, 0, TA_OPENING_TRANSITION));
ca->append(new AddTransitionCommand(c, get_internal_meta(EFFECT_INTERNAL_LINEARFADE), TA_OPENING_TRANSITION, 30));
adding = true;
}
}
@@ -1192,8 +1193,44 @@ void Timeline::on_recordButton_clicked() {
}
void Timeline::on_toolTransitionButton_clicked() {
decheck_tool_buttons(sender());
creating = false;
QMenu transition_menu(this);
for (int i=0;i<video_effects.size();i++) {
const EffectMeta& em = video_effects.at(i);
if (em.type == EFFECT_TYPE_TRANSITION) {
QAction* a = transition_menu.addAction(em.name);
a->setObjectName("v");
a->setData(reinterpret_cast<quintptr>(&em));
}
}
transition_menu.addSeparator();
for (int i=0;i<audio_effects.size();i++) {
const EffectMeta& em = audio_effects.at(i);
if (em.type == EFFECT_TYPE_TRANSITION) {
QAction* a = transition_menu.addAction(em.name);
a->setObjectName("a");
a->setData(reinterpret_cast<quintptr>(&em));
}
}
connect(&transition_menu, SIGNAL(triggered(QAction*)), this, SLOT(transition_menu_select(QAction*)));
transition_menu.exec(QCursor::pos());
}
void Timeline::transition_menu_select(QAction* a) {
transition_tool_meta = reinterpret_cast<const EffectMeta*>(a->data().value<quintptr>());
if (a->objectName() == "v") {
transition_tool_side = -1;
} else {
transition_tool_side = 1;
}
decheck_tool_buttons(sender());
ui->timeline_area->setCursor(Qt::CrossCursor);
tool = TIMELINE_TOOL_TRANSITION;
creating = false;
}
+7 -2
View File
@@ -21,7 +21,8 @@ class QPushButton;
class SourceTable;
class ViewerWidget;
class ComboAction;
class Transition;
class Effect;
struct EffectMeta;
struct Sequence;
struct Clip;
struct Media;
@@ -57,7 +58,7 @@ struct Ghost {
bool trimming;
// transition trimming
Transition* transition;
Effect* transition;
};
namespace Ui {
@@ -169,6 +170,8 @@ public:
bool transition_tool_proc;
int transition_tool_clip;
int transition_tool_type;
const EffectMeta* transition_tool_meta;
int transition_tool_side;
// clipboard
QVector<Clip*> clip_clipboard;
@@ -209,6 +212,8 @@ private slots:
void on_toolTransitionButton_clicked();
void transition_menu_select(QAction*);
private:
QVector<QPushButton*> tool_buttons;
void decheck_tool_buttons(QObject* sender);
+4 -6
View File
@@ -8,7 +8,6 @@
#include "effects/effect.h"
#include "panels/timeline.h"
#include "panels/project.h"
#include "effects/transition.h"
#include "debug.h"
extern "C" {
@@ -47,24 +46,24 @@ void apply_audio_effects(Clip* c, double timecode_start, AVFrame* frame, int nb_
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 transition_end = ((c->clip_in + c->opening_transition->length) / c->sequence->frame_rate);
if (timecode_end < transition_end) {
double adjustment = transition_end - transition_start;
double adjusted_range_start = (timecode_start - transition_start) / adjustment;
double adjusted_range_end = (timecode_end - transition_start) / adjustment;
c->opening_transition->process_audio(adjusted_range_start, adjusted_range_end, frame->data[0], nb_bytes, false);
c->opening_transition->process_audio(adjusted_range_start, adjusted_range_end, frame->data[0], nb_bytes, TRAN_TYPE_OPEN);
}
}
}
if (c->closing_transition != NULL) {
if (c->media_type == MEDIA_TYPE_FOOTAGE) {
double transition_start = (c->clip_in + c->getLength() - c->closing_transition->length) / c->sequence->frame_rate;
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);
if (timecode_start > transition_start) {
double adjustment = transition_end - transition_start;
double adjusted_range_start = (timecode_start - transition_start) / adjustment;
double adjusted_range_end = (timecode_end - transition_start) / adjustment;
c->closing_transition->process_audio(adjusted_range_start, adjusted_range_end, frame->data[0], nb_bytes, true);
c->closing_transition->process_audio(adjusted_range_start, adjusted_range_end, frame->data[0], nb_bytes, TRAN_TYPE_CLOSE);
}
}
}
@@ -485,7 +484,6 @@ void cache_video_worker(Clip* c, long playhead) {
}
void reset_cache(Clip* c, long target_frame) {
dout << "reset called";
// if we seek to a whole other place in the timeline, we'll need to reset the cache with new values
switch (c->media_type) {
case MEDIA_TYPE_FOOTAGE:
+6 -7
View File
@@ -1,7 +1,6 @@
#include "clip.h"
#include "effects/effect.h"
#include "effects/transition.h"
#include "io/media.h"
#include "io/config.h"
#include "playback/playback.h"
@@ -65,8 +64,8 @@ Clip* Clip::copy(Sequence* s) {
copy->effects.append(effects.at(i)->copy(copy));
}
if (opening_transition != NULL) copy->opening_transition = opening_transition->copy();
if (closing_transition != NULL) copy->closing_transition = closing_transition->copy();
if (opening_transition != NULL) copy->opening_transition = opening_transition->copy(copy);
if (closing_transition != NULL) copy->closing_transition = closing_transition->copy(copy);
copy->recalculateMaxLength();
@@ -164,16 +163,16 @@ Clip::~Clip() {
}
long Clip::get_timeline_in_with_transition() {
if (opening_transition != NULL && opening_transition->link != NULL) {
return timeline_in - opening_transition->link->length;
if (opening_transition != NULL && opening_transition->tlink != NULL) {
return timeline_in - opening_transition->tlink->length;
} else {
return timeline_in;
}
}
long Clip::get_timeline_out_with_transition() {
if (closing_transition != NULL && closing_transition->link != NULL) {
return timeline_out + closing_transition->link->length;
if (closing_transition != NULL && closing_transition->tlink != NULL) {
return timeline_out + closing_transition->tlink->length;
} else {
return timeline_out;
}
+2 -3
View File
@@ -10,7 +10,6 @@
class Cacher;
class Effect;
class Transition;
class QOpenGLFramebufferObject;
class ComboAction;
struct Sequence;
@@ -73,8 +72,8 @@ struct Clip
// other variables (should be deep copied/duplicated in copy())
QList<Effect*> effects;
QVector<int> linked;
Transition* opening_transition;
Transition* closing_transition;
Effect* opening_transition;
Effect* closing_transition;
// media handling
AVFormatContext* formatCtx;
-1
View File
@@ -1,7 +1,6 @@
#include "sequence.h"
#include "project/clip.h"
#include "effects/transition.h"
Sequence::Sequence() :
playhead(0),
+4 -5
View File
@@ -16,7 +16,6 @@
#include "effects/effect.h"
#include "io/media.h"
#include "playback/cacher.h"
#include "effects/transition.h"
#include "ui/labelslider.h"
#include "ui/viewerwidget.h"
#include "project/marker.h"
@@ -194,7 +193,7 @@ void SetTimelineInOutCommand::redo() {
mainWindow->setWindowModified(true);
}
AddEffectCommand::AddEffectCommand(Clip* c, EffectMeta *e) :
AddEffectCommand::AddEffectCommand(Clip* c, const EffectMeta *e) :
clip(c),
meta(e),
ref(NULL),
@@ -221,7 +220,7 @@ void AddEffectCommand::redo() {
mainWindow->setWindowModified(true);
}
AddTransitionCommand::AddTransitionCommand(Clip* c, int itransition, int itype, int ilength) :
AddTransitionCommand::AddTransitionCommand(Clip* c, const EffectMeta *itransition, int itype, int ilength) :
clip(c),
transition(itransition),
type(itype),
@@ -242,10 +241,10 @@ void AddTransitionCommand::undo() {
void AddTransitionCommand::redo() {
if (type == TA_OPENING_TRANSITION) {
clip->opening_transition = create_transition(transition, clip);
clip->opening_transition = create_effect(clip, transition);
if (length > 0) clip->opening_transition->length = length;
} else {
clip->closing_transition = create_transition(transition, clip);
clip->closing_transition = create_effect(clip, transition);
if (length > 0) clip->closing_transition->length = length;
}
mainWindow->setWindowModified(true);
+5 -5
View File
@@ -91,13 +91,13 @@ private:
class AddEffectCommand : public QUndoCommand {
public:
AddEffectCommand(Clip* c, EffectMeta* e);
AddEffectCommand(Clip* c, const EffectMeta* e);
~AddEffectCommand();
void undo();
void redo();
private:
Clip* clip;
EffectMeta* meta;
const EffectMeta* meta;
Effect* ref;
bool done;
bool old_project_changed;
@@ -105,12 +105,12 @@ private:
class AddTransitionCommand : public QUndoCommand {
public:
AddTransitionCommand(Clip* c, int itransition, int itype, int ilength = 0);
AddTransitionCommand(Clip* c, const EffectMeta* itransition, int itype, int ilength);
void undo();
void redo();
private:
Clip* clip;
int transition;
const EffectMeta* transition;
int type;
int length;
bool old_project_changed;
@@ -138,7 +138,7 @@ public:
private:
Clip* clip;
int type;
Transition* transition;
Effect* transition;
bool old_project_changed;
};
+18 -12
View File
@@ -18,7 +18,6 @@
#include "debug.h"
#include "effects/effect.h"
#include "effects/transition.h"
#include "effects/internal/solideffect.h"
#include "effects/internal/texteffect.h"
@@ -1206,9 +1205,9 @@ void TimelineWidget::mouseReleaseEvent(QMouseEvent *event) {
panel_timeline->delete_areas_and_relink(ca, areas);
ca->append(new MoveClipAction(c, qMin(transition_start, c->timeline_in), qMax(transition_end, c->timeline_out), c->clip_in, c->track));
}
}
ca->append(new AddTransitionCommand(c, 0, panel_timeline->transition_tool_type, transition_end - transition_start));
ca->append(new AddTransitionCommand(c, panel_timeline->transition_tool_meta, panel_timeline->transition_tool_type, transition_end - transition_start));
push_undo = true;
}
@@ -2100,15 +2099,22 @@ void TimelineWidget::mouseMoveEvent(QMouseEvent *event) {
panel_timeline->transition_tool_proc = true;
}
} else {
panel_timeline->transition_tool_clip = getClipIndexFromCoords(panel_timeline->cursor_frame, panel_timeline->cursor_track);
int mouse_clip = getClipIndexFromCoords(panel_timeline->cursor_frame, panel_timeline->cursor_track);
if (mouse_clip > -1) {
Clip* c = sequence->clips.at(mouse_clip);
if (same_sign(c->track, panel_timeline->transition_tool_side)) {
panel_timeline->transition_tool_clip = mouse_clip;
long halfway = c->timeline_in + (c->getLength()/2);
if (panel_timeline->cursor_frame > halfway) {
panel_timeline->transition_tool_type = TA_CLOSING_TRANSITION;
} else {
panel_timeline->transition_tool_type = TA_OPENING_TRANSITION;
}
}
}
if (panel_timeline->transition_tool_clip > -1) {
Clip* c = sequence->clips.at(panel_timeline->transition_tool_clip);
long halfway = c->timeline_in + (c->getLength()/2);
if (panel_timeline->cursor_frame > halfway) {
panel_timeline->transition_tool_type = TA_CLOSING_TRANSITION;
} else {
panel_timeline->transition_tool_type = TA_OPENING_TRANSITION;
}
}
}
@@ -2323,7 +2329,7 @@ void TimelineWidget::paintEvent(QPaintEvent*) {
// draw clip transitions
for (int i=0;i<2;i++) {
Transition* t = (i == 0) ? clip->opening_transition : clip->closing_transition;
Effect* t = (i == 0) ? clip->opening_transition : clip->closing_transition;
if (t != NULL) {
int transition_width = getScreenPointFromFrame(panel_timeline->zoom, t->length);
int transition_height = clip_rect.height();
+1 -4
View File
@@ -76,10 +76,7 @@ private:
int scroll;
SetSelectionsCommand* selection_command;
/*QVector<QTreeWidgetItem*> file_import_items;
QVector<Media*> file_import_media;*/
SetSelectionsCommand* selection_command;
signals:
public slots:
+26 -22
View File
@@ -6,7 +6,6 @@
#include "panels/project.h"
#include "project/sequence.h"
#include "effects/effect.h"
#include "effects/transition.h"
#include "playback/playback.h"
#include "playback/audio.h"
#include "io/media.h"
@@ -198,6 +197,26 @@ GLuint ViewerWidget::draw_clip(QOpenGLFramebufferObject* fbo, GLuint texture) {
return fbo->texture();
}
void ViewerWidget::process_effect(Clip* c, Effect* e, double timecode, GLTextureCoords& coords, GLuint& composite_texture, bool& fbo_switcher) {
if (e->is_enabled()) {
if (e->enable_coords) {
e->process_coords(timecode, coords);
}
if (e->enable_shader || e->enable_superimpose) {
e->startEffect();
if (e->enable_shader) {
e->process_shader(timecode);
}
composite_texture = draw_clip(c->fbo[fbo_switcher], composite_texture);
if (e->enable_superimpose) {
GLuint superimpose_texture = e->process_superimpose(timecode);
if (superimpose_texture != 0) draw_clip(c->fbo[fbo_switcher], superimpose_texture);
}
fbo_switcher = !fbo_switcher;
}
}
}
GLuint ViewerWidget::compose_sequence(Clip* nest, bool render_audio) {
Sequence* s = viewer->seq;
long playhead = s->playhead;
@@ -359,39 +378,24 @@ GLuint ViewerWidget::compose_sequence(Clip* nest, bool render_audio) {
}
// EFFECT CODE START
double timecode = ((double)(playhead-c->timeline_in+c->clip_in)/(double)c->sequence->frame_rate);
for (int j=0;j<c->effects.size();j++) {
Effect* e = c->effects.at(j);
if (e->is_enabled()) {
double timecode = ((double)(playhead-c->timeline_in+c->clip_in)/(double)c->sequence->frame_rate);
if (e->enable_coords) {
e->process_coords(timecode, coords);
}
if (e->enable_shader || e->enable_superimpose) {
e->startEffect();
if (e->enable_shader) {
e->process_shader(timecode);
}
composite_texture = draw_clip(c->fbo[fbo_switcher], composite_texture);
if (e->enable_superimpose) {
GLuint superimpose_texture = e->process_superimpose(timecode);
if (superimpose_texture != 0) draw_clip(c->fbo[fbo_switcher], superimpose_texture);
}
fbo_switcher = !fbo_switcher;
}
}
process_effect(c, c->effects.at(j), timecode, coords, composite_texture, fbo_switcher);
}
if (c->opening_transition != NULL) {
int transition_progress = playhead - c->timeline_in;
if (transition_progress < c->opening_transition->length) {
c->opening_transition->process_transition((double)transition_progress/(double)c->opening_transition->length);
process_effect(c, c->opening_transition, (double)transition_progress/(double)c->opening_transition->length, coords, composite_texture, fbo_switcher);
//c->opening_transition->process_transition((double)transition_progress/(double)c->opening_transition->length);
}
}
if (c->closing_transition != NULL) {
int transition_progress = c->closing_transition->length - (playhead - c->timeline_in - c->getLength() + c->closing_transition->length);
if (transition_progress < c->closing_transition->length) {
c->closing_transition->process_transition((double)transition_progress/(double)c->closing_transition->length);
process_effect(c, c->closing_transition, (double)transition_progress/(double)c->closing_transition->length, coords, composite_texture, fbo_switcher);
//c->closing_transition->process_transition((double)transition_progress/(double)c->closing_transition->length);
}
}
+3
View File
@@ -13,6 +13,8 @@ class Viewer;
struct Clip;
struct MediaStream;
class QOpenGLFramebufferObject;
class Effect;
struct GLTextureCoords;
class ViewerWidget : public QOpenGLWidget
{
@@ -42,6 +44,7 @@ private:
void seek_from_click(int x);
GLuint compose_sequence(Clip *nest, bool render_audio);
GLuint draw_clip(QOpenGLFramebufferObject *clip, GLuint texture);
void process_effect(Clip* c, Effect* e, double timecode, GLTextureCoords& coords, GLuint& composite_texture, bool& fbo_switcher);
private slots:
void retry();
void deleteFunction();