improved effects

This commit is contained in:
itsmattkc
2018-08-24 13:31:32 +10:00
parent 5a129929c4
commit 48867ba239
22 changed files with 199 additions and 139 deletions
+7 -2
View File
@@ -147,7 +147,11 @@ void Effect::field_changed() {
}
bool Effect::is_enabled() {
return container->enabled_check->isChecked();
return container->enabled_check->isChecked();
}
void Effect::set_enabled(bool b) {
container->enabled_check->setChecked(b);
}
QVariant load_data_from_string(int type, const QString& string) {
@@ -290,8 +294,9 @@ Effect* Effect::copy(Clip* c) {
}
void Effect::process_image(double, uint8_t*, int, int) {}
void Effect::process_gl(double, QOpenGLShaderProgram&, GLTextureCoords&) {}
void Effect::process_gl(double, GLTextureCoords&) {}
void Effect::process_audio(double, double, quint8*, int, int) {}
void Effect::clean_gl() {}
/* Effect Row Definitions */
+3 -1
View File
@@ -180,6 +180,7 @@ public:
int row_count();
bool is_enabled();
void set_enabled(bool b);
virtual void refresh();
@@ -195,7 +196,8 @@ public:
const char* ffmpeg_filter;
virtual void process_image(double timecode, uint8_t* data, int width, int height);
virtual void process_gl(double timecode, QOpenGLShaderProgram& shaders, GLTextureCoords& coords);
virtual void process_gl(double timecode, GLTextureCoords& coords);
virtual void clean_gl();
virtual void process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int channel_count);
public slots:
void field_changed();
+21 -3
View File
@@ -1,15 +1,33 @@
#include "chromakeyeffect.h"
ChromaKeyEffect::ChromaKeyEffect(Clip* c) : Effect(c, EFFECT_TYPE_VIDEO, VIDEO_CHROMAKEY_EFFECT) {
ChromaKeyEffect::ChromaKeyEffect(Clip* c) : Effect(c, EFFECT_TYPE_VIDEO, VIDEO_CHROMAKEY_EFFECT), vert(QOpenGLShader::Vertex), frag(QOpenGLShader::Fragment) {
enable_opengl = true;
color_field = add_row("Color:")->add_field(EFFECT_FIELD_COLOR);
tolerance_field = add_row("Tolerance:")->add_field(EFFECT_FIELD_DOUBLE);
color_field->set_color_value(Qt::green);
tolerance_field->set_double_default_value(50);
tolerance_field->set_double_default_value(10);
tolerance_field->set_double_minimum_value(0);
tolerance_field->set_double_maximum_value(100);
vert.compileSourceCode("varying vec2 vTexCoord;\nvoid main() {\n\tvTexCoord = gl_MultiTexCoord0.xy;\n\tgl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n}");
frag.compileSourceCode("uniform vec4 keyColor;\nuniform float threshold;\nuniform sampler2D myTexture;\nvarying vec2 vTexCoord;\nvoid main(void) {\n\tvec4 textureColor = texture2D(myTexture, vTexCoord);\nfloat diff = length(keyColor - textureColor);\nif (diff < threshold) {gl_FragColor = vec4(0, 0, 0, 0);} else {gl_FragColor = textureColor;}\n}");
program.addShader(&vert);
program.addShader(&frag);
program.link();
connect(color_field, SIGNAL(changed()), this, SLOT(field_changed()));
connect(tolerance_field, SIGNAL(changed()), this, SLOT(field_changed()));
}
void ChromaKeyEffect::process_gl(double timecode, QOpenGLShaderProgram &shaders, GLTextureCoords&) {
void ChromaKeyEffect::process_gl(double timecode, GLTextureCoords&) {
program.bind();
program.setUniformValue("keyColor", color_field->get_color_value(timecode));
program.setUniformValue("threshold", (GLfloat) (tolerance_field->get_double_value(timecode)*0.01));
}
void ChromaKeyEffect::clean_gl() {
program.release();
}
+5 -1
View File
@@ -6,10 +6,14 @@
class ChromaKeyEffect : public Effect {
public:
ChromaKeyEffect(Clip* c);
void process_gl(double timecode, QOpenGLShaderProgram &shaders, GLTextureCoords &coords);
void process_gl(double timecode, GLTextureCoords &coords);
void clean_gl();
private:
EffectField* color_field;
EffectField* tolerance_field;
QOpenGLShaderProgram program;
QOpenGLShader vert;
QOpenGLShader frag;
};
#endif // CHROMAKEYEFFECT_H
+1 -1
View File
@@ -23,7 +23,7 @@ CropEffect::CropEffect(Clip *c) : Effect(c, EFFECT_TYPE_VIDEO, VIDEO_CROP_EFFECT
connect(bottom_field, SIGNAL(changed()), this, SLOT(field_changed()));
}
void CropEffect::process_gl(double timecode, QOpenGLShaderProgram&, GLTextureCoords &coords) {
void CropEffect::process_gl(double timecode, GLTextureCoords &coords) {
// store initial coord data
int left = coords.vertexTopLeftX;
int top = coords.vertexTopLeftY;
+1 -1
View File
@@ -7,7 +7,7 @@ class CropEffect : public Effect
{
public:
CropEffect(Clip* c);
void process_gl(double timecode, QOpenGLShaderProgram &shaders, GLTextureCoords &coords);
void process_gl(double timecode, GLTextureCoords &coords);
private:
EffectField* left_field;
EffectField* top_field;
+1 -1
View File
@@ -10,7 +10,7 @@ FlipEffect::FlipEffect(Clip *c) : Effect(c, EFFECT_TYPE_VIDEO, VIDEO_FLIP_EFFECT
connect(vertical_field, SIGNAL(changed()), this, SLOT(field_changed()));
}
void FlipEffect::process_gl(double timecode, QOpenGLShaderProgram &, GLTextureCoords &coords) {
void FlipEffect::process_gl(double timecode, GLTextureCoords &coords) {
if (horizontal_field->get_bool_value(timecode)) {
double tlX = coords.textureTopLeftX;
double blX = coords.textureBottomLeftX;
+1 -1
View File
@@ -7,7 +7,7 @@ class FlipEffect : public Effect
{
public:
FlipEffect(Clip* c);
void process_gl(double timecode, QOpenGLShaderProgram &shaders, GLTextureCoords &coords);
void process_gl(double timecode, GLTextureCoords &coords);
private:
EffectField* horizontal_field;
EffectField* vertical_field;
+13 -4
View File
@@ -1,12 +1,21 @@
#include "gaussianblureffect.h"
GaussianBlurEffect::GaussianBlurEffect(Clip *c) : Effect(c, EFFECT_TYPE_VIDEO, VIDEO_GAUSSIANBLUR_EFFECT) {
GaussianBlurEffect::GaussianBlurEffect(Clip *c) : Effect(c, EFFECT_TYPE_VIDEO, VIDEO_GAUSSIANBLUR_EFFECT), frag(QOpenGLShader::Fragment), vert(QOpenGLShader::Vertex) {
enable_opengl = true;
vert.compileSourceCode("varying vec2 vTexCoord;\nvoid main() {\n\tvTexCoord = gl_MultiTexCoord0.xy;\n\tgl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n}");
frag.compileSourceCode("uniform mediump float amount_val;\nuniform sampler2D myTexture;\nvarying vec2 vTexCoord;\nvoid main(void) {\n\tvec4 textureColor = texture2D(myTexture, vTexCoord);\n\tgl_FragColor = vec4(textureColor.r+((1.0-textureColor.r-textureColor.r)*amount_val), textureColor.g+((1.0-textureColor.g-textureColor.g)*amount_val), textureColor.b+((1.0-textureColor.b-textureColor.b)*amount_val), textureColor.a);\n}");
program.addShader(&frag);
program.addShader(&vert);
program.link();
}
void GaussianBlurEffect::process_gl(double timecode, QOpenGLShaderProgram &shaders, GLTextureCoords &coords) {
shaders.addShaderFromSourceCode(QOpenGLShader::Vertex, "attribute vec2 position;\nvoid main() {\ngl_Position = vec4(position, 1, 1);\n}");
shaders.addShaderFromSourceCode(QOpenGLShader::Fragment, "uniform vec3 iResolution;\nuniform sampler2D iChannel0;\nuniform bool flip;\nuniform vec2 direction;\nvoid main() {\nvec2 uv = vec2(gl_FragCoord.xy / iResolution.xy);\nif (flip) uv.y = 1.0 - uv.y;\nvec4 color = vec4(0.0);\nvec2 off1 = vec2(1.3846153846) * direction;\nvec2 off2 = vec2(3.2307692308) * direction;\ncolor += texture2D(image, uv) * 0.2270270270;\ncolor += texture2D(image, uv + (off1 / resolution)) * 0.3162162162;\ncolor += texture2D(image, uv - (off1 / resolution)) * 0.3162162162;\ncolor += texture2D(image, uv + (off2 / resolution)) * 0.0702702703;\ncolor += texture2D(image, uv - (off2 / resolution)) * 0.0702702703;\ngl_FragColor = color;}");
void GaussianBlurEffect::process_gl(double timecode, GLTextureCoords &coords) {
program.bind();
}
void GaussianBlurEffect::clean_gl() {
program.release();
}
+6 -1
View File
@@ -7,7 +7,12 @@ class GaussianBlurEffect : public Effect
{
public:
GaussianBlurEffect(Clip* c);
void process_gl(double timecode, QOpenGLShaderProgram &shaders, GLTextureCoords &coords);
void process_gl(double timecode, GLTextureCoords &coords);
void clean_gl();
private:
QOpenGLShaderProgram program;
QOpenGLShader vert;
QOpenGLShader frag;
};
#endif // GAUSSIANBLUREFFECT_H
+15 -5
View File
@@ -4,11 +4,12 @@
#include <QLabel>
#include <QGridLayout>
#include <QOpenGLFunctions>
#include <QXmlStreamReader>
#include <QXmlStreamWriter>
#include <QXmlStreamAttributes>
InvertEffect::InvertEffect(Clip* c) : Effect(c, EFFECT_TYPE_VIDEO, VIDEO_INVERT_EFFECT) {
InvertEffect::InvertEffect(Clip* c) : Effect(c, EFFECT_TYPE_VIDEO, VIDEO_INVERT_EFFECT), vert(QOpenGLShader::Vertex), frag(QOpenGLShader::Fragment) {
enable_opengl = true;
EffectRow* amount_row = add_row("Amount:");
@@ -20,10 +21,19 @@ InvertEffect::InvertEffect(Clip* c) : Effect(c, EFFECT_TYPE_VIDEO, VIDEO_INVERT_
amount_val->set_double_default_value(100);
connect(amount_val, SIGNAL(changed()), this, SLOT(field_changed()));
vert.compileSourceCode("varying vec2 vTexCoord;\nvoid main() {\n\tvTexCoord = gl_MultiTexCoord0.xy;\n\tgl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n}");
frag.compileSourceCode("uniform mediump float amount_val;\nuniform sampler2D myTexture;\nvarying vec2 vTexCoord;\nvoid main(void) {\n\tvec4 textureColor = texture2D(myTexture, vTexCoord);\n\tgl_FragColor = vec4(textureColor.r+((1.0-textureColor.r-textureColor.r)*amount_val), textureColor.g+((1.0-textureColor.g-textureColor.g)*amount_val), textureColor.b+((1.0-textureColor.b-textureColor.b)*amount_val), textureColor.a);\n}");
program.addShader(&vert);
program.addShader(&frag);
program.link();
}
void InvertEffect::process_gl(double timecode, QOpenGLShaderProgram& shaders, GLTextureCoords&) {
double value = amount_val->get_double_value(timecode)*0.01;
shaders.addShaderFromSourceCode(QOpenGLShader::Vertex, "varying vec2 vTexCoord;\nvoid main() {\n\tvTexCoord = gl_MultiTexCoord0.xy;\n\tgl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n}");
shaders.addShaderFromSourceCode(QOpenGLShader::Fragment, "uniform sampler2D myTexture;\nvarying vec2 vTexCoord;\nvoid main(void) {\n\tvec4 textureColor = texture2D(myTexture, vTexCoord);\n\tgl_FragColor = vec4(textureColor.r+((1.0-textureColor.r-textureColor.r)*" + QString::number(value, 'f', 2) + "), textureColor.g+((1.0-textureColor.g-textureColor.g)*" + QString::number(value, 'f', 2) + "), textureColor.b+((1.0-textureColor.b-textureColor.b)*" + QString::number(value, 'f', 2) + "), textureColor.a);\n}");
void InvertEffect::process_gl(double timecode, GLTextureCoords&) {
program.bind();
program.setUniformValue("amount_val", (GLfloat) (amount_val->get_double_value(timecode)*0.01));
}
void InvertEffect::clean_gl() {
program.release();
}
+5 -1
View File
@@ -9,9 +9,13 @@ class InvertEffect : public Effect {
Q_OBJECT
public:
InvertEffect(Clip* c);
void process_gl(double timecode, QOpenGLShaderProgram& shaders, GLTextureCoords& coords);
void process_gl(double timecode, GLTextureCoords& coords);
void clean_gl();
private:
EffectField* amount_val;
QOpenGLShader frag;
QOpenGLShader vert;
QOpenGLShaderProgram program;
};
#endif // INVERTEFFECT_H
+1 -1
View File
@@ -49,7 +49,7 @@ void ShakeEffect::refresh() {
}
}
void ShakeEffect::process_gl(double timecode, QOpenGLShaderProgram&, GLTextureCoords&) {
void ShakeEffect::process_gl(double timecode, GLTextureCoords&) {
if (shake_progress > shake_limit) {
double ival = intensity_val->get_double_value(timecode);
if ((int)ival > 0) {
+1 -1
View File
@@ -7,7 +7,7 @@ class ShakeEffect : public Effect {
Q_OBJECT
public:
ShakeEffect(Clip* c);
void process_gl(double timecode, QOpenGLShaderProgram& shaders, GLTextureCoords& coords);
void process_gl(double timecode, GLTextureCoords& coords);
EffectField* intensity_val;
EffectField* rotation_val;
+1 -1
View File
@@ -40,7 +40,7 @@ void SolidEffect::enable_color() {
solid_color_field->set_enabled(solid_type->get_combo_data(-1) == SOLID_TYPE_COLOR);
}
void SolidEffect::process_gl(double timecode, QOpenGLShaderProgram& shaders, GLTextureCoords& coords) {
void SolidEffect::process_gl(double timecode, GLTextureCoords& coords) {
}
+1 -1
View File
@@ -10,7 +10,7 @@ public:
EffectField* solid_type;
EffectField* solid_color_field;
EffectField* opacity_field;
void process_gl(double timecode, QOpenGLShaderProgram& shaders, GLTextureCoords& coords);
void process_gl(double timecode, GLTextureCoords& coords);
void process_image(long p, uint8_t* data, int width, int height);
private slots:
void enable_color();
+1 -1
View File
@@ -121,7 +121,7 @@ void TransformEffect::toggle_uniform_scale(bool enabled) {
scale_y->set_enabled(!enabled);
}
void TransformEffect::process_gl(double timecode, QOpenGLShaderProgram&, GLTextureCoords& coords) {
void TransformEffect::process_gl(double timecode, GLTextureCoords& coords) {
// position
glTranslatef(position_x->get_double_value(timecode)-(parent_clip->sequence->width/2), position_y->get_double_value(timecode)-(parent_clip->sequence->height/2), 0);
+1 -1
View File
@@ -8,7 +8,7 @@ class TransformEffect : public Effect {
public:
TransformEffect(Clip* c);
void refresh();
void process_gl(double timecode, QOpenGLShaderProgram& shaders, GLTextureCoords& coords);
void process_gl(double timecode, GLTextureCoords& coords);
EffectField* position_x;
EffectField* position_y;
+9 -4
View File
@@ -844,15 +844,19 @@ bool Project::load_worker(QFile& f, QXmlStreamReader& stream, int type) {
stream.readNext();
if (stream.name() == "effect" && stream.isStartElement()) {
int effect_id = -1;
bool effect_enabled = true;
for (int j=0;j<stream.attributes().size();j++) {
const QXmlStreamAttribute& attr = stream.attributes().at(j);
if (attr.name().toString() == QLatin1String("id")) {
effect_id = attr.value().toInt();
break;
}
if (attr.name() == "id") {
effect_id = attr.value().toInt();
} else if (attr.name() == "enabled") {
effect_enabled = (attr.value() == "1");
}
}
if (effect_id != -1) {
Effect* e = create_effect(effect_id, c);
e->set_enabled(effect_enabled);
// stream.writeAttribute("enabled", QString::number(e->is_enabled()));
e->load(stream);
c->effects.append(e);
}
@@ -1111,6 +1115,7 @@ void Project::save_folder(QXmlStreamWriter& stream, QTreeWidgetItem* parent, int
stream.writeStartElement("effect"); // effect
Effect* e = c->effects.at(k);
stream.writeAttribute("id", QString::number(e->id));
stream.writeAttribute("enabled", QString::number(e->is_enabled()));
e->save(stream);
stream.writeEndElement(); // effect
}
+11 -9
View File
@@ -304,16 +304,18 @@ void Timeline::redraw_all_clips(bool changed) {
}
void Timeline::select_all() {
selections.clear();
for (int i=0;i<sequence->clip_count();i++) {
Clip* c = sequence->get_clip(i);
Selection s;
s.in = c->timeline_in;
s.out = c->timeline_out;
s.track = c->track;
if (c != NULL) selections.append(s);
if (sequence != NULL) {
selections.clear();
for (int i=0;i<sequence->clip_count();i++) {
Clip* c = sequence->get_clip(i);
Selection s;
s.in = c->timeline_in;
s.out = c->timeline_out;
s.track = c->track;
if (c != NULL) selections.append(s);
}
repaint_timeline();
}
repaint_timeline();
}
void Timeline::delete_in_out(bool ripple) {
+87 -90
View File
@@ -80,108 +80,105 @@ bool get_clip_frame(Clip* c, long playhead) {
long clip_time = refactor_frame_number(sequence_clip_time, c->sequence->frame_rate, av_q2d(av_guess_frame_rate(c->formatCtx, c->stream, c->frame)));
// do we need to update the texture?
MediaStream* ms = static_cast<Media*>(c->media)->get_stream_from_file_index(c->media_stream);
if ((!ms->infinite_length/* && c->texture_frame != clip_time*/) ||
(ms->infinite_length && c->texture_frame == -1)) {
AVFrame* current_frame = NULL;
bool no_frame = false;
MediaStream* ms = static_cast<Media*>(c->media)->get_stream_from_file_index(c->media_stream);
// get frame data
if (ms->infinite_length) { // if clip is a still frame, we only need one
if (c->cache_A.written) {
// retrieve cached frame
current_frame = c->cache_A.frames[0];
} else if (c->lock.tryLock()) {
// grab image
cache_clip(c, 0, true, false, false, NULL);
c->lock.unlock();
}
} else {
// keeping a RAM cache improves performance, however it's detrimental when rendering
// determine which cache contains the requested frame
bool using_cache_A = false;
bool using_cache_B = false;
AVFrame** cache = NULL;
long cache_offset = 0;
bool cache_needs_reset = false;
AVFrame* current_frame = NULL;
bool no_frame = false;
if (c->cache_A.written && clip_time >= c->cache_A.offset && clip_time < c->cache_A.offset + c->cache_size) {
if (clip_time < c->cache_A.offset + c->cache_A.write_count) {
if (c->cache_A.mutex.tryLock()) { // lock in case cacher is still writing to it
using_cache_A = true;
c->cache_A.unread = false;
cache = c->cache_A.frames;
cache_offset = c->cache_A.offset;
c->cache_A.mutex.unlock();
}
} else {
no_frame = true;
}
} else if (c->cache_B.written && clip_time >= c->cache_B.offset && clip_time < c->cache_B.offset + c->cache_size) {
if (clip_time < c->cache_B.offset + c->cache_B.write_count) {
if (c->cache_B.mutex.tryLock()) { // lock in case cacher is still writing to it
using_cache_B = true;
c->cache_B.unread = false;
cache = c->cache_B.frames;
cache_offset = c->cache_B.offset;
c->cache_B.mutex.unlock();
}
} else {
no_frame = true;
// get frame data
if (ms->infinite_length) { // if clip is a still frame, we only need one
if (c->cache_A.written) {
// retrieve cached frame
current_frame = c->cache_A.frames[0];
} else if (c->lock.tryLock()) {
// grab image
cache_clip(c, 0, true, false, false, NULL);
c->lock.unlock();
}
} else {
// keeping a RAM cache improves performance, however it's detrimental when rendering
// determine which cache contains the requested frame
bool using_cache_A = false;
bool using_cache_B = false;
AVFrame** cache = NULL;
long cache_offset = 0;
bool cache_needs_reset = false;
if (c->cache_A.written && clip_time >= c->cache_A.offset && clip_time < c->cache_A.offset + c->cache_size) {
if (clip_time < c->cache_A.offset + c->cache_A.write_count) {
if (c->cache_A.mutex.tryLock()) { // lock in case cacher is still writing to it
using_cache_A = true;
c->cache_A.unread = false;
cache = c->cache_A.frames;
cache_offset = c->cache_A.offset;
c->cache_A.mutex.unlock();
}
} else {
// this is technically bad, unless we just seeked
c->cache_A.unread = c->cache_B.unread = false;
cache_needs_reset = true;
no_frame = true;
}
} else if (c->cache_B.written && clip_time >= c->cache_B.offset && clip_time < c->cache_B.offset + c->cache_size) {
if (clip_time < c->cache_B.offset + c->cache_B.write_count) {
if (c->cache_B.mutex.tryLock()) { // lock in case cacher is still writing to it
using_cache_B = true;
c->cache_B.unread = false;
cache = c->cache_B.frames;
cache_offset = c->cache_B.offset;
c->cache_B.mutex.unlock();
}
} else {
no_frame = true;
}
} else {
// this is technically bad, unless we just seeked
c->cache_A.unread = c->cache_B.unread = false;
cache_needs_reset = true;
}
if (!no_frame) {
if (cache != NULL) {
current_frame = cache[clip_time - cache_offset];
}
if (!no_frame) {
if (cache != NULL) {
current_frame = cache[clip_time - cache_offset];
}
// determine whether we should start filling the other cache
if (!using_cache_A || !using_cache_B) {
if (c->lock.tryLock()) {
bool write_A = (!using_cache_A && !c->cache_A.unread);
bool write_B = (!using_cache_B && !c->cache_B.unread);
if (write_A || write_B) {
// if we have no cache and need to seek, start us at the current playhead, otherwise start at the end of the current cache
cache_clip(c, (cache_needs_reset) ? clip_time : cache_offset + c->cache_size, write_A, write_B, cache_needs_reset, NULL);
}
c->lock.unlock();
// determine whether we should start filling the other cache
if (!using_cache_A || !using_cache_B) {
if (c->lock.tryLock()) {
bool write_A = (!using_cache_A && !c->cache_A.unread);
bool write_B = (!using_cache_B && !c->cache_B.unread);
if (write_A || write_B) {
// if we have no cache and need to seek, start us at the current playhead, otherwise start at the end of the current cache
cache_clip(c, (cache_needs_reset) ? clip_time : cache_offset + c->cache_size, write_A, write_B, cache_needs_reset, NULL);
}
c->lock.unlock();
}
}
}
}
if (current_frame != NULL) {
// set up opengl texture
if (c->texture == NULL) {
c->texture = new QOpenGLTexture(QOpenGLTexture::Target2D);
c->texture->setSize(current_frame->width, current_frame->height);
c->texture->setFormat(QOpenGLTexture::RGBA8_UNorm);
c->texture->setMipLevels(c->texture->maximumMipLevels());
c->texture->setMinMagFilters(QOpenGLTexture::Linear, QOpenGLTexture::Linear);
c->texture->allocateStorage(QOpenGLTexture::RGBA, QOpenGLTexture::UInt8);
}
memcpy(c->comp_frame, current_frame->data[0], c->comp_frame_size);
for (int i=0;i<c->effects.size();i++) {
if (c->effects.at(i)->enable_image) {
c->effects.at(i)->process_image(sequence_clip_time, c->comp_frame, current_frame->width, current_frame->height);
}
}
c->texture->setData(0, QOpenGLTexture::RGBA, QOpenGLTexture::UInt8, c->comp_frame);
c->texture_frame = clip_time;
return true;
} else if (!no_frame) {
texture_failed = true;
qDebug() << "[ERROR] Failed to retrieve frame from cache (R:" << clip_time << "| A:" << c->cache_A.offset << "-" << c->cache_A.offset+c->cache_size-1 << "| B:" << c->cache_B.offset << "-" << c->cache_B.offset+c->cache_size-1 << "| WA:" << c->cache_A.written << "| WB:" << c->cache_B.written << ")";
if (current_frame != NULL) {
// set up opengl texture
if (c->texture == NULL) {
c->texture = new QOpenGLTexture(QOpenGLTexture::Target2D);
c->texture->setSize(current_frame->width, current_frame->height);
c->texture->setFormat(QOpenGLTexture::RGBA8_UNorm);
c->texture->setMipLevels(c->texture->maximumMipLevels());
c->texture->setMinMagFilters(QOpenGLTexture::Linear, QOpenGLTexture::Linear);
c->texture->allocateStorage(QOpenGLTexture::RGBA, QOpenGLTexture::UInt8);
}
memcpy(c->comp_frame, current_frame->data[0], c->comp_frame_size);
for (int i=0;i<c->effects.size();i++) {
if (c->effects.at(i)->enable_image) {
c->effects.at(i)->process_image(sequence_clip_time, c->comp_frame, current_frame->width, current_frame->height);
}
}
c->texture->setData(0, QOpenGLTexture::RGBA, QOpenGLTexture::UInt8, c->comp_frame);
c->texture_frame = clip_time;
return true;
} else if (!no_frame) {
texture_failed = true;
qDebug() << "[ERROR] Failed to retrieve frame from cache (R:" << clip_time << "| A:" << c->cache_A.offset << "-" << c->cache_A.offset+c->cache_size-1 << "| B:" << c->cache_B.offset << "-" << c->cache_B.offset+c->cache_size-1 << "| WA:" << c->cache_A.written << "| WB:" << c->cache_B.written << ")";
}
}
return false;
+7 -8
View File
@@ -180,11 +180,9 @@ void ViewerWidget::compose_sequence(QVector<Clip*>& nests, bool render_audio) {
coords.textureTopLeftY = coords.textureTopRightY = coords.textureTopLeftX = coords.textureBottomLeftX = 0;
coords.textureBottomLeftY = coords.textureBottomRightY = coords.textureTopRightX = coords.textureBottomRightX = 1.0;
QOpenGLShaderProgram shader;
for (int j=0;j<c->effects.size();j++) {
if (c->effects.at(j)->enable_opengl && c->effects.at(j)->is_enabled()) {
c->effects.at(j)->process_gl(((double)(panel_timeline->playhead-c->timeline_in+c->clip_in)/(double)sequence->frame_rate), shader, coords);
c->effects.at(j)->process_gl(((double)(panel_timeline->playhead-c->timeline_in+c->clip_in)/(double)sequence->frame_rate), coords);
}
}
@@ -202,9 +200,6 @@ void ViewerWidget::compose_sequence(QVector<Clip*>& nests, bool render_audio) {
}
}
bool use_gl_shaders = shader.link();
if (use_gl_shaders) shader.bind();
c->texture->bind();
glBegin(GL_QUADS);
@@ -218,9 +213,13 @@ void ViewerWidget::compose_sequence(QVector<Clip*>& nests, bool render_audio) {
glVertex2f(coords.vertexBottomLeftX, coords.vertexBottomLeftY); // bottom left
glEnd();
c->texture->release();
c->texture->release();
if (use_gl_shaders) shader.release();
for (int j=0;j<c->effects.size();j++) {
if (c->effects.at(j)->enable_opengl && c->effects.at(j)->is_enabled()) {
c->effects.at(j)->clean_gl();
}
}
}
} else if (render_audio &&
c->stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO &&