work on frei0r support

This commit is contained in:
itsmattkc
2019-01-20 12:07:22 +11:00
parent 5cc02956f3
commit 1c620af9f5
12 changed files with 318 additions and 193 deletions
+64
View File
@@ -0,0 +1,64 @@
#include "frei0reffect.h"
#include <QMessageBox>
#include <Windows.h>
typedef f0r_instance_t (*f0rConstructFunc)(unsigned int width, unsigned int height);
typedef int (*f0rInitFunc) ();
typedef void (*f0rDeinitFunc) ();
typedef void (*f0rUpdateFunc) (f0r_instance_t instance,
double time, const uint32_t* inframe, uint32_t* outframe);
typedef void (*f0rDestructFunc)(f0r_instance_t instance);
Frei0rEffect::Frei0rEffect(Clip *c, const EffectMeta *em) : Effect(c, em) {
enable_image = true;
add_row("Heck");
// Windows DLL loading routine
QString dll_fn = "E:/invert0r.dll";
LPCWSTR dll_fn_w = reinterpret_cast<const wchar_t*>(dll_fn.utf16());
modulePtr = LoadLibrary(dll_fn_w);
if(modulePtr == nullptr) {
DWORD dll_err = GetLastError();
qCritical() << "Failed to load VST" << dll_fn_w << "-" << dll_err;
QString msg_err = tr("Failed to load VST plugin \"%1\": %2").arg(dll_fn, QString::number(dll_err));
if (dll_err == 193) {
#ifdef _WIN64
msg_err += "\n\n" + tr("NOTE: You can't load 32-bit VST plugins into a 64-bit build of Olive. Please find a 64-bit version of this plugin or switch to a 32-bit build of Olive.");
#elif _WIN32
msg_err += "\n\n" + tr("NOTE: You can't load 64-bit VST plugins into a 32-bit build of Olive. Please find a 32-bit version of this plugin or switch to a 64-bit build of Olive.");
#endif
}
QMessageBox::critical(nullptr, tr("Error loading VST plugin"), msg_err);
return;
}
f0rConstructFunc construct = reinterpret_cast<f0rConstructFunc>(GetProcAddress(modulePtr, "f0r_construct"));
f0rInitFunc init = reinterpret_cast<f0rInitFunc>(GetProcAddress(modulePtr, "f0r_init"));
init();
instance = construct(1920, 1080);
}
Frei0rEffect::~Frei0rEffect() {
if (modulePtr != nullptr) {
FreeModule(modulePtr);
f0rDestructFunc destruct = reinterpret_cast<f0rDestructFunc>(GetProcAddress(modulePtr, "f0r_destruct"));
destruct(instance);
f0rDeinitFunc deinit = reinterpret_cast<f0rDeinitFunc>(GetProcAddress(modulePtr, "f0r_deinit"));
deinit();
}
}
void Frei0rEffect::process_image(double timecode, uint8_t *input, uint8_t *output, int size) {
f0rUpdateFunc update_func = reinterpret_cast<f0rUpdateFunc>(GetProcAddress(modulePtr, "f0r_update"));
update_func(instance, timecode, reinterpret_cast<uint32_t*>(input), reinterpret_cast<uint32_t*>(output));
}
+20
View File
@@ -0,0 +1,20 @@
#ifndef FREI0REFFECT_H
#define FREI0REFFECT_H
#include "project/effect.h"
#include <frei0r/frei0r.h>
class Frei0rEffect : public Effect {
Q_OBJECT
public:
Frei0rEffect(Clip* c, const EffectMeta* em);
~Frei0rEffect();
virtual void process_image(double timecode, uint8_t* input, uint8_t* output, int size);
private:
HMODULE modulePtr;
f0r_instance_t instance;
};
#endif // FREI0REFFECT_H
+9
View File
@@ -32,3 +32,12 @@ QString get_config_path() {
return QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation);
}
}
QList<QString> get_effects_paths() {
QList<QString> effects_paths;
effects_paths.append(get_app_dir() + "/effects");
effects_paths.append(get_app_dir() + "/../share/olive-editor/effects");
QString env_path(qgetenv("OLIVE_EFFECTS_PATH"));
if (!env_path.isEmpty()) effects_paths.append(env_path);
return effects_paths;
}
+1
View File
@@ -6,5 +6,6 @@
QString get_app_dir();
QString get_data_path();
QString get_config_path();
QList<QString> get_effects_paths();
#endif // PATH_H
+7 -4
View File
@@ -20,9 +20,7 @@ int main(int argc, char *argv[]) {
bool launch_fullscreen = false;
QString load_proj;
#ifndef NODEBUG
qInstallMessageHandler(debug_message_handler);
#endif
bool use_internal_logger = true;
if (argc > 1) {
for (int i=1;i<argc;i++) {
@@ -40,7 +38,8 @@ int main(int argc, char *argv[]) {
launch_fullscreen = true;
} else if (!strcmp(argv[i], "--disable-shaders")) {
shaders_are_enabled = false;
} else if (!strcmp(argv[i], "--no-debug")) {
use_internal_logger = false;
} else {
printf("[ERROR] Unknown argument '%s'\n", argv[1]);
return 1;
@@ -51,6 +50,10 @@ int main(int argc, char *argv[]) {
}
}
if (use_internal_logger) {
qInstallMessageHandler(debug_message_handler);
}
// init ffmpeg subsystem
av_register_all();
avfilter_register_all();
+6 -2
View File
@@ -128,7 +128,9 @@ SOURCES += \
ui/renderthread.cpp \
ui/renderfunctions.cpp \
ui/viewerwindow.cpp \
project/projectfilter.cpp
project/projectfilter.cpp \
effects/internal/frei0reffect.cpp \
project/effectloaders.cpp
HEADERS += \
mainwindow.h \
@@ -224,7 +226,9 @@ HEADERS += \
ui/renderthread.h \
ui/renderfunctions.h \
ui/viewerwindow.h \
project/projectfilter.h
project/projectfilter.h \
effects/internal/frei0reffect.h \
project/effectloaders.h
FORMS +=
+1
View File
@@ -9,6 +9,7 @@
#include "project/transition.h"
#include "io/config.h"
#include "grapheditor.h"
#include "project/effectloaders.h"
#include "debug.h"
#include <QScrollBar>
+18 -9
View File
@@ -255,26 +255,35 @@ void get_clip_frame(Clip* c, long playhead, bool& texture_failed) {
int nb_components = av_pix_fmt_desc_get(static_cast<enum AVPixelFormat>(c->pix_fmt))->nb_components;
glPixelStorei(GL_UNPACK_ROW_LENGTH, target_frame->linesize[0]/nb_components);
bool copied = false;
uint8_t* data = target_frame->data[0];
// 2 data buffers to ping-pong between
bool using_db_1 = true;
uint8_t* data_buffer_1 = target_frame->data[0];
uint8_t* data_buffer_2 = nullptr;
int frame_size;
for (int i=0;i<c->effects.size();i++) {
Effect* e = c->effects.at(i);
if (e->enable_image) {
if (!copied) {
if (data_buffer_1 == target_frame->data[0]) {
frame_size = target_frame->linesize[0]*target_frame->height;
data = new uint8_t[frame_size];
memcpy(data, target_frame->data[0], frame_size);
copied = true;
data_buffer_1 = new uint8_t[frame_size];
data_buffer_2 = new uint8_t[frame_size];
memcpy(data_buffer_1, target_frame->data[0], frame_size);
}
e->process_image(get_timecode(c, playhead), data, frame_size);
e->process_image(get_timecode(c, playhead), using_db_1 ? data_buffer_1 : data_buffer_2, using_db_1 ? data_buffer_2 : data_buffer_1, frame_size);
using_db_1 = !using_db_1;
}
}
c->texture->setData(0, get_gl_pix_fmt_from_av(c->pix_fmt), QOpenGLTexture::UInt8, data);
c->texture->setData(0, get_gl_pix_fmt_from_av(c->pix_fmt), QOpenGLTexture::UInt8, using_db_1 ? data_buffer_1 : data_buffer_2);
if (copied) delete [] data;
if (data_buffer_1 != target_frame->data[0]) {
delete [] data_buffer_1;
delete [] data_buffer_2;
}
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
}
+3 -175
View File
@@ -32,6 +32,7 @@
#include "effects/internal/vsthostwin.h"
#endif
#include "effects/internal/fillleftrighteffect.h"
#include "effects/internal/frei0reffect.h"
#include <QCheckBox>
#include <QGridLayout>
@@ -69,6 +70,7 @@ Effect* create_effect(Clip* c, const EffectMeta* em) {
#ifdef _WIN32
case EFFECT_INTERNAL_VST: return new VSTHostWin(c, em);
#endif
case EFFECT_INTERNAL_FREI0R: return new Frei0rEffect(c, em);
}
} else {
qCritical() << "Invalid effect data";
@@ -88,180 +90,6 @@ const EffectMeta* get_internal_meta(int internal_id, int type) {
return nullptr;
}
void load_internal_effects() {
if (!shaders_are_enabled) qWarning() << "Shaders are disabled, some effects may be nonfunctional";
EffectMeta em;
// internal effects
em.type = EFFECT_TYPE_EFFECT;
em.subtype = EFFECT_TYPE_AUDIO;
em.name = "Volume";
em.internal = EFFECT_INTERNAL_VOLUME;
effects.append(em);
em.name = "Pan";
em.internal = EFFECT_INTERNAL_PAN;
effects.append(em);
#ifdef _WIN32
em.name = "VST Plugin 2.x";
em.internal = EFFECT_INTERNAL_VST;
effects.append(em);
#endif
em.name = "Tone";
em.internal = EFFECT_INTERNAL_TONE;
effects.append(em);
em.name = "Noise";
em.internal = EFFECT_INTERNAL_NOISE;
effects.append(em);
em.name = "Fill Left/Right";
em.internal = EFFECT_INTERNAL_FILLLEFTRIGHT;
effects.append(em);
em.subtype = EFFECT_TYPE_VIDEO;
em.name = "Transform";
em.category = "Distort";
em.internal = EFFECT_INTERNAL_TRANSFORM;
effects.append(em);
em.name = "Corner Pin";
em.internal = EFFECT_INTERNAL_CORNERPIN;
effects.append(em);
/*em.name = "Mask";
em.internal = EFFECT_INTERNAL_MASK;
effects.append(em);*/
em.name = "Shake";
em.internal = EFFECT_INTERNAL_SHAKE;
effects.append(em);
em.name = "Text";
em.category = "Render";
em.internal = EFFECT_INTERNAL_TEXT;
effects.append(em);
em.name = "Timecode";
em.internal = EFFECT_INTERNAL_TIMECODE;
effects.append(em);
em.name = "Solid";
em.internal = EFFECT_INTERNAL_SOLID;
effects.append(em);
// internal transitions
em.type = EFFECT_TYPE_TRANSITION;
em.category = "";
em.name = "Cross Dissolve";
em.internal = TRANSITION_INTERNAL_CROSSDISSOLVE;
effects.append(em);
em.subtype = EFFECT_TYPE_AUDIO;
em.name = "Linear Fade";
em.internal = TRANSITION_INTERNAL_LINEARFADE;
effects.append(em);
em.name = "Exponential Fade";
em.internal = TRANSITION_INTERNAL_EXPONENTIALFADE;
effects.append(em);
em.name = "Logarithmic Fade";
em.internal = TRANSITION_INTERNAL_LOGARITHMICFADE;
effects.append(em);
}
QList<QString> get_effects_paths() {
QList<QString> effects_paths;
effects_paths.append(get_app_dir() + "/effects");
effects_paths.append(get_app_dir() + "/../share/olive-editor/effects");
QString env_path(qgetenv("OLIVE_EFFECTS_PATH"));
if (!env_path.isEmpty()) effects_paths.append(env_path);
return effects_paths;
}
void load_shader_effects() {
QList<QString> effects_paths = get_effects_paths();
for (int h=0;h<effects_paths.size();h++) {
const QString& effects_path = effects_paths.at(h);
QDir effects_dir(effects_path);
if (effects_dir.exists()) {
QList<QString> entries = effects_dir.entryList(QStringList("*.xml"), QDir::Files);
for (int i=0;i<entries.size();i++) {
QFile file(effects_path + "/" + entries.at(i));
if (!file.open(QIODevice::ReadOnly)) {
qCritical() << "Could not open" << entries.at(i);
return;
}
QXmlStreamReader reader(&file);
while (!reader.atEnd()) {
if (reader.name() == "effect") {
QString effect_name = "";
QString effect_cat = "";
const QXmlStreamAttributes attr = reader.attributes();
for (int j=0;j<attr.size();j++) {
if (attr.at(j).name() == "name") {
effect_name = attr.at(j).value().toString();
} else if (attr.at(j).name() == "category") {
effect_cat = attr.at(j).value().toString();
}
}
if (!effect_name.isEmpty()) {
EffectMeta em;
em.type = EFFECT_TYPE_EFFECT;
em.subtype = EFFECT_TYPE_VIDEO;
em.name = effect_name;
em.category = effect_cat;
em.filename = file.fileName();
em.path = effects_path;
em.internal = -1;
effects.append(em);
} else {
qCritical() << "Invalid effect found in" << entries.at(i);
}
break;
}
reader.readNext();
}
file.close();
}
}
}
}
void load_vst_effects() {
}
void init_effects() {
EffectInit* init_thread = new EffectInit();
QObject::connect(init_thread, SIGNAL(finished()), init_thread, SLOT(deleteLater()));
init_thread->start();
}
EffectInit::EffectInit() {
panel_effect_controls->effects_loaded.lock();
}
void EffectInit::run() {
qInfo() << "Initializing effects...";
load_internal_effects();
load_shader_effects();
load_vst_effects();
panel_effect_controls->effects_loaded.unlock();
qInfo() << "Finished initializing effects";
}
Effect::Effect(Clip* c, const EffectMeta *em) :
parent_clip(c),
meta(em),
@@ -866,7 +694,7 @@ void Effect::endEffect() {
bound = false;
}
void Effect::process_image(double, uint8_t *, int) {}
void Effect::process_image(double, uint8_t *input, uint8_t *output, int) {}
Effect* Effect::copy(Clip* c) {
Effect* copy = create_effect(c, meta);
+3 -3
View File
@@ -38,7 +38,6 @@ extern bool shaders_are_enabled;
extern QVector<EffectMeta> effects;
double log_volume(double linear);
void init_effects();
Effect* create_effect(Clip* c, const EffectMeta *em);
const EffectMeta* get_internal_meta(int internal_id, int type);
@@ -65,7 +64,8 @@ const EffectMeta* get_internal_meta(int internal_id, int type);
#define EFFECT_INTERNAL_FILLLEFTRIGHT 10
#define EFFECT_INTERNAL_VST 11
#define EFFECT_INTERNAL_CORNERPIN 12
#define EFFECT_INTERNAL_COUNT 13
#define EFFECT_INTERNAL_FREI0R 13
#define EFFECT_INTERNAL_COUNT 14
#define KEYFRAME_TYPE_LINEAR 0
#define KEYFRAME_TYPE_BEZIER 1
@@ -156,7 +156,7 @@ public:
const char* ffmpeg_filter;
virtual void process_image(double timecode, uint8_t* data, int size);
virtual void process_image(double timecode, uint8_t* input, uint8_t* output, int size);
virtual void process_shader(double timecode, GLTextureCoords&);
virtual void process_coords(double timecode, GLTextureCoords& coords, int data);
virtual GLuint process_superimpose(double timecode);
+178
View File
@@ -0,0 +1,178 @@
#include "effectloaders.h"
#include "project/effect.h"
#include "project/transition.h"
#include "io/path.h"
#include "panels/panels.h"
#include "panels/effectcontrols.h"
#include <QDir>
#include <QXmlStreamReader>
#include <QDebug>
void load_internal_effects() {
if (!shaders_are_enabled) qWarning() << "Shaders are disabled, some effects may be nonfunctional";
EffectMeta em;
// internal effects
em.type = EFFECT_TYPE_EFFECT;
em.subtype = EFFECT_TYPE_AUDIO;
em.name = "Volume";
em.internal = EFFECT_INTERNAL_VOLUME;
effects.append(em);
em.name = "Pan";
em.internal = EFFECT_INTERNAL_PAN;
effects.append(em);
#ifdef _WIN32
em.name = "VST Plugin 2.x";
em.internal = EFFECT_INTERNAL_VST;
effects.append(em);
#endif
em.name = "Tone";
em.internal = EFFECT_INTERNAL_TONE;
effects.append(em);
em.name = "Noise";
em.internal = EFFECT_INTERNAL_NOISE;
effects.append(em);
em.name = "Fill Left/Right";
em.internal = EFFECT_INTERNAL_FILLLEFTRIGHT;
effects.append(em);
em.subtype = EFFECT_TYPE_VIDEO;
// TEMPORARY begin
em.name = "Frei0r Plugin";
em.internal = EFFECT_INTERNAL_FREI0R;
effects.append(em);
// TEMPORARY end
em.name = "Transform";
em.category = "Distort";
em.internal = EFFECT_INTERNAL_TRANSFORM;
effects.append(em);
em.name = "Corner Pin";
em.internal = EFFECT_INTERNAL_CORNERPIN;
effects.append(em);
/*em.name = "Mask";
em.internal = EFFECT_INTERNAL_MASK;
effects.append(em);*/
em.name = "Shake";
em.internal = EFFECT_INTERNAL_SHAKE;
effects.append(em);
em.name = "Text";
em.category = "Render";
em.internal = EFFECT_INTERNAL_TEXT;
effects.append(em);
em.name = "Timecode";
em.internal = EFFECT_INTERNAL_TIMECODE;
effects.append(em);
em.name = "Solid";
em.internal = EFFECT_INTERNAL_SOLID;
effects.append(em);
// internal transitions
em.type = EFFECT_TYPE_TRANSITION;
em.category = "";
em.name = "Cross Dissolve";
em.internal = TRANSITION_INTERNAL_CROSSDISSOLVE;
effects.append(em);
em.subtype = EFFECT_TYPE_AUDIO;
em.name = "Linear Fade";
em.internal = TRANSITION_INTERNAL_LINEARFADE;
effects.append(em);
em.name = "Exponential Fade";
em.internal = TRANSITION_INTERNAL_EXPONENTIALFADE;
effects.append(em);
em.name = "Logarithmic Fade";
em.internal = TRANSITION_INTERNAL_LOGARITHMICFADE;
effects.append(em);
}
void load_shader_effects() {
QList<QString> effects_paths = get_effects_paths();
for (int h=0;h<effects_paths.size();h++) {
const QString& effects_path = effects_paths.at(h);
QDir effects_dir(effects_path);
if (effects_dir.exists()) {
QList<QString> entries = effects_dir.entryList(QStringList("*.xml"), QDir::Files);
for (int i=0;i<entries.size();i++) {
QFile file(effects_path + "/" + entries.at(i));
if (!file.open(QIODevice::ReadOnly)) {
qCritical() << "Could not open" << entries.at(i);
return;
}
QXmlStreamReader reader(&file);
while (!reader.atEnd()) {
if (reader.name() == "effect") {
QString effect_name = "";
QString effect_cat = "";
const QXmlStreamAttributes attr = reader.attributes();
for (int j=0;j<attr.size();j++) {
if (attr.at(j).name() == "name") {
effect_name = attr.at(j).value().toString();
} else if (attr.at(j).name() == "category") {
effect_cat = attr.at(j).value().toString();
}
}
if (!effect_name.isEmpty()) {
EffectMeta em;
em.type = EFFECT_TYPE_EFFECT;
em.subtype = EFFECT_TYPE_VIDEO;
em.name = effect_name;
em.category = effect_cat;
em.filename = file.fileName();
em.path = effects_path;
em.internal = -1;
effects.append(em);
} else {
qCritical() << "Invalid effect found in" << entries.at(i);
}
break;
}
reader.readNext();
}
file.close();
}
}
}
}
void init_effects() {
EffectInit* init_thread = new EffectInit();
QObject::connect(init_thread, SIGNAL(finished()), init_thread, SLOT(deleteLater()));
init_thread->start();
}
EffectInit::EffectInit() {
panel_effect_controls->effects_loaded.lock();
}
void EffectInit::run() {
qInfo() << "Initializing effects...";
load_internal_effects();
load_shader_effects();
panel_effect_controls->effects_loaded.unlock();
qInfo() << "Finished initializing effects";
}
+8
View File
@@ -0,0 +1,8 @@
#ifndef EFFECTLOADERS_H
#define EFFECTLOADERS_H
#include <QList>
void init_effects();
#endif // EFFECTLOADERS_H