diff --git a/effects/effect.cpp b/effects/effect.cpp index 1e2cd9b02..be1bd5113 100644 --- a/effects/effect.cpp +++ b/effects/effect.cpp @@ -136,79 +136,111 @@ bool Effect::is_enabled() { return container->enabled_check->isChecked(); } -void Effect::load(QXmlStreamReader& stream) { - stream.readNext(); - /*for (int i=0;iatEnd() && !(stream->name() == "effect" && stream->isEndElement())) { - stream->readNext(); - if (stream->name() == "row" && stream->isStartElement()) { - for (int j=0;jfieldCount();j++) { - EffectField* field = row->field(j); - while (!stream->atEnd() && !(stream->name() == "effect" && stream->isEndElement())) { - stream->readNext(); - if (stream->name() == "field" && stream->isStartElement()) { - // read all keyframes - QVector keys; - while (!stream->atEnd() && (stream->name() == "field" && stream->isEndElement())) { - stream->readNext(); - if (stream->name() == "key" && stream->isStartElement()) { - EffectKeyframe kf; - for (int k=0;kattributes().size();k++) { - const QXmlStreamAttribute& attr = stream->attributes().at(k); - if (attr.name() == "frame") { - kf.frame = attr.value().toLong(); - } else if (attr.name() == "type") { - kf.type = attr.value().toInt(); - } else if (attr.name() == "value") { - switch (field->type) { - case EFFECT_FIELD_DOUBLE: - kf.data = attr.value().toDouble(); - break; - case EFFECT_FIELD_COLOR: - { - kf.data = QColor(attr.value().toString()); - } - break; - case EFFECT_FIELD_STRING: - kf.data = attr.value().toString(); - break; - case EFFECT_FIELD_BOOL: - kf.data = (stream->text() == "1"); - break; - case EFFECT_FIELD_COMBO: - kf.data = (stream->text().toInt()); - break; - case EFFECT_FIELD_FONT: - kf.data = (stream->text().toString()); - break; - } - } - } - keys.append(kf); - } - } - field->keyframes = keys; - break; - } - } - } - break; - } - } - }*/ +QVariant load_data_from_string(int type, const QString& string) { + switch (type) { + case EFFECT_FIELD_DOUBLE: return string.toDouble(); break; + case EFFECT_FIELD_COLOR: return QColor(string); break; + case EFFECT_FIELD_STRING: return string; break; + case EFFECT_FIELD_BOOL: return (string == "1"); break; + case EFFECT_FIELD_COMBO: return string.toInt(); break; + case EFFECT_FIELD_FONT: return string; break; + } + return QVariant(); } -QString save_data(int type, const QVariant& data) { - switch (type) { - case EFFECT_FIELD_DOUBLE: return QString::number(data.toDouble()); break; - case EFFECT_FIELD_COLOR: return data.value().name(); break; - case EFFECT_FIELD_STRING: return data.toString(); break; - case EFFECT_FIELD_BOOL: return QString::number(data.toBool()); break; - case EFFECT_FIELD_COMBO: return QString::number(data.toInt()); break; - case EFFECT_FIELD_FONT: return data.toString(); break; - } - return QString(); +QString save_data_to_string(int type, const QVariant& data) { + switch (type) { + case EFFECT_FIELD_DOUBLE: return QString::number(data.toDouble()); break; + case EFFECT_FIELD_COLOR: return data.value().name(); break; + case EFFECT_FIELD_STRING: return data.toString(); break; + case EFFECT_FIELD_BOOL: return QString::number(data.toBool()); break; + case EFFECT_FIELD_COMBO: return QString::number(data.toInt()); break; + case EFFECT_FIELD_FONT: return data.toString(); break; + } + return QString(); +} + +void Effect::load(QXmlStreamReader& stream) { + int row_count = 0; + + while (!stream.atEnd() && !(stream.name() == "effect" && stream.isEndElement())) { + stream.readNext(); + if (stream.name() == "row" && stream.isStartElement()) { + if (row_count < rows.size()) { + EffectRow* row = rows.at(row_count); + int field_count = 0; + + while (!stream.atEnd() && !(stream.name() == "row" && stream.isEndElement())) { + stream.readNext(); + + // read keyframes + if (stream.name() == "keyframes" && stream.isStartElement()) { + for (int k=0;kkeyframing = (attr.value() == "1"); + break; + } + } + if (row->keyframing) { + stream.readNext(); + while (!stream.atEnd() && !(stream.name() == "keyframes" && stream.isEndElement())) { + if (stream.name() == "key" && stream.isStartElement()) { + long keyframe_frame; + int keyframe_type; + for (int k=0;kkeyframe_times.append(keyframe_frame); + row->keyframe_types.append(keyframe_type); + } + stream.readNext(); + } + } + stream.readNext(); + } + + // read field + if (stream.name() == "field" && stream.isStartElement()) { + if (field_count < row->fieldCount()) { + EffectField* field = row->field(field_count); + + for (int k=0;kset_current_data(load_data_from_string(field->type, attr.value().toString())); + break; + } + } + + while (!stream.atEnd() && !(stream.name() == "field" && stream.isEndElement())) { + stream.readNext(); + + // read all keyframes + if (stream.name() == "key" && stream.isStartElement()) { + stream.readNext(); + field->keyframe_data.append(load_data_from_string(field->type, stream.text().toString())); + } + } + } else { + qDebug() << "[ERROR] Too many fields for effect" << id << "row" << row_count << ". Project might be corrupt. (Got" << field_count << ", expected <" << row->fieldCount()-1 << ")"; + } + field_count++; + break; + } + } + + } else { + qDebug() << "[ERROR] Too many rows for effect" << id << ". Project might be corrupt. (Got" << row_count << ", expected <" << rows.size()-1 << ")"; + } + row_count++; + } + } } void Effect::save(QXmlStreamWriter& stream) { @@ -227,9 +259,9 @@ void Effect::save(QXmlStreamWriter& stream) { for (int j=0;jfieldCount();j++) { EffectField* field = row->field(j); stream.writeStartElement("field"); // field - stream.writeAttribute("value", save_data(field->type, field->get_current_data())); + stream.writeAttribute("value", save_data_to_string(field->type, field->get_current_data())); for (int k=0;kkeyframe_data.size();k++) { - stream.writeTextElement("key", save_data(field->type, field->keyframe_data.at(k))); + stream.writeTextElement("key", save_data_to_string(field->type, field->keyframe_data.at(k))); } stream.writeEndElement(); // field } @@ -243,8 +275,8 @@ Effect* Effect::copy(Clip* c) { return copy; } -void Effect::process_image(long, QImage&) {} -void Effect::process_gl(long, QOpenGLShaderProgram&, int*, int*) {} +void Effect::process_image(long, uint8_t*, int, int) {} +void Effect::process_gl(long frame, QOpenGLShaderProgram& shaders, GLTextureCoords& coords) {} void Effect::process_audio(uint8_t*, int) {} /* Effect Row Definitions */ @@ -261,6 +293,7 @@ EffectRow::EffectRow(Effect *parent, QGridLayout *uilayout, const QString &n, in // DEBUG STARTS QPushButton* nkf = new QPushButton(); + nkf->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Expanding); connect(nkf, SIGNAL(clicked(bool)), this, SLOT(set_keyframe_now())); ui->addWidget(nkf, row, 5); // DEBUG ENDS @@ -337,7 +370,7 @@ EffectField::EffectField(EffectRow *parent, int t) : parent_row(parent), type(t) QTextEdit* edit = new QTextEdit(); edit->setUndoRedoEnabled(true); ui_element = edit; - connect(edit, SIGNAL(textChanged()), this, SLOT(uiElementChange())); + connect(edit->document(), SIGNAL(contentsChanged()), this, SLOT(uiElementChange())); } break; case EFFECT_FIELD_BOOL: @@ -432,9 +465,14 @@ void EffectField::get_keyframe_data(long frame, int* before, int* after, double* *before = after_keyframe_index; *after = after_keyframe_index; } - } else { - *before = before_keyframe_index; - *after = before_keyframe_index; + } else { + if (before_keyframe_index > -1) { + *before = before_keyframe_index; + *after = before_keyframe_index; + } else { + *before = after_keyframe_time; + *after = after_keyframe_time; + } } } diff --git a/effects/effect.h b/effects/effect.h index 97bb8df09..5a7b90cdd 100644 --- a/effects/effect.h +++ b/effects/effect.h @@ -53,6 +53,26 @@ Effect* create_effect(int effect_id, Clip* c); #define EFFECT_KEYFRAME_HOLD 1 #define EFFECT_KEYFRAME_BEZIER 2 +struct GLTextureCoords { + int vertexTopLeftX; + int vertexTopLeftY; + int vertexTopRightX; + int vertexTopRightY; + int vertexBottomLeftX; + int vertexBottomLeftY; + int vertexBottomRightX; + int vertexBottomRightY; + + double textureTopLeftX; + double textureTopLeftY; + double textureTopRightX; + double textureTopRightY; + double textureBottomRightX; + double textureBottomRightY; + double textureBottomLeftX; + double textureBottomLeftY; +}; + class EffectField : public QObject { Q_OBJECT public: @@ -163,8 +183,8 @@ public: const char* ffmpeg_filter; - virtual void process_image(long frame, QImage& img); - virtual void process_gl(long frame, QOpenGLShaderProgram& shader_prog, int* anchor_x, int* anchor_y); + virtual void process_image(long frame, uint8_t* data, int width, int height); + virtual void process_gl(long frame, QOpenGLShaderProgram& shaders, GLTextureCoords& coords); virtual void process_audio(quint8* samples, int nb_bytes); public slots: void field_changed(); diff --git a/effects/video/inverteffect.cpp b/effects/video/inverteffect.cpp index cf9a1dbf2..9728800cd 100644 --- a/effects/video/inverteffect.cpp +++ b/effects/video/inverteffect.cpp @@ -8,7 +8,7 @@ #include #include -InvertEffect::InvertEffect(Clip* c) : Effect(c, EFFECT_TYPE_VIDEO, VIDEO_INVERT_EFFECT), vert_shader(QOpenGLShader::Vertex), frag_shader(QOpenGLShader::Fragment) { +InvertEffect::InvertEffect(Clip* c) : Effect(c, EFFECT_TYPE_VIDEO, VIDEO_INVERT_EFFECT) { enable_opengl = true; EffectRow* amount_row = add_row("Amount:"); @@ -22,12 +22,8 @@ InvertEffect::InvertEffect(Clip* c) : Effect(c, EFFECT_TYPE_VIDEO, VIDEO_INVERT_ connect(amount_val, SIGNAL(changed()), this, SLOT(field_changed())); } -void InvertEffect::process_gl(long p, QOpenGLShaderProgram& shader_prog, int* anchor_x, int* anchor_y) { - double value = amount_val->get_double_value(p)*0.01; - - vert_shader.compileSourceCode("varying vec2 vTexCoord;\nvoid main() {\n\tvTexCoord = gl_MultiTexCoord0.xy;\n\tgl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n}"); - frag_shader.compileSourceCode("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) + "), 1);\n}"); - - shader_prog.addShader(&vert_shader); - shader_prog.addShader(&frag_shader); +void InvertEffect::process_gl(long frame, QOpenGLShaderProgram& shaders, GLTextureCoords&) { + double value = amount_val->get_double_value(frame)*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) + "), 1);\n}"); } diff --git a/effects/video/inverteffect.h b/effects/video/inverteffect.h index fa46f8ea3..4007ed5f2 100644 --- a/effects/video/inverteffect.h +++ b/effects/video/inverteffect.h @@ -9,12 +9,9 @@ class InvertEffect : public Effect { Q_OBJECT public: InvertEffect(Clip* c); - void process_gl(long p, QOpenGLShaderProgram& shader_prog, int *anchor_x, int *anchor_y); - - EffectField* amount_val; + void process_gl(long frame, QOpenGLShaderProgram& shaders, GLTextureCoords& coords); private: - QOpenGLShader vert_shader; - QOpenGLShader frag_shader; + EffectField* amount_val; }; #endif // INVERTEFFECT_H diff --git a/effects/video/shakeeffect.cpp b/effects/video/shakeeffect.cpp index 4176acd94..6800d82d5 100644 --- a/effects/video/shakeeffect.cpp +++ b/effects/video/shakeeffect.cpp @@ -49,9 +49,9 @@ void ShakeEffect::refresh() { } } -void ShakeEffect::process_gl(long p, QOpenGLShaderProgram&, int*, int*) { +void ShakeEffect::process_gl(long frame, QOpenGLShaderProgram& shaders, GLTextureCoords& coords) { if (shake_progress > shake_limit) { - double ival = intensity_val->get_double_value(p); + double ival = intensity_val->get_double_value(frame); if ((int)ival > 0) { prev_x = next_x; prev_y = next_y; @@ -81,7 +81,7 @@ void ShakeEffect::process_gl(long p, QOpenGLShaderProgram&, int*, int*) { offset_x = 0; offset_y = 0; } - double rot_val = rotation_val->get_double_value(p); + double rot_val = rotation_val->get_double_value(frame); if ((int)rot_val > 0) { prev_rot = next_rot; next_rot = (qrand() % (int) (rot_val * 2)) - rot_val; diff --git a/effects/video/shakeeffect.h b/effects/video/shakeeffect.h index d5f4725c3..209163962 100644 --- a/effects/video/shakeeffect.h +++ b/effects/video/shakeeffect.h @@ -7,7 +7,7 @@ class ShakeEffect : public Effect { Q_OBJECT public: ShakeEffect(Clip* c); - void process_gl(long p, QOpenGLShaderProgram& shader_prog, int* anchor_x, int* anchor_y); + void process_gl(long frame, QOpenGLShaderProgram& shaders, GLTextureCoords& coords); EffectField* intensity_val; EffectField* rotation_val; diff --git a/effects/video/solideffect.cpp b/effects/video/solideffect.cpp index 0b2d2bbdc..94c2444e6 100644 --- a/effects/video/solideffect.cpp +++ b/effects/video/solideffect.cpp @@ -16,7 +16,7 @@ #define SMPTE_LOWER_BARS 4 SolidEffect::SolidEffect(Clip* c) : Effect(c, EFFECT_TYPE_VIDEO, VIDEO_SOLID_EFFECT) { - enable_image = true; + enable_opengl = true; solid_type = add_row("Type:")->add_field(EFFECT_FIELD_COMBO); solid_type->add_combo_item("Solid Color", SOLID_TYPE_COLOR); @@ -40,7 +40,12 @@ void SolidEffect::enable_color() { solid_color_field->set_enabled(solid_type->get_combo_data(-1) == SOLID_TYPE_COLOR); } -void SolidEffect::process_image(long frame, QImage& img) { +void SolidEffect::process_gl(long frame, QOpenGLShaderProgram& shaders, GLTextureCoords& coords) { + +} + +void SolidEffect::process_image(long frame, uint8_t* data, int w, int h) { + QImage img(data, w, h, QImage::Format_RGBA8888); // create QImage wrapper QPainter p(&img); int width = img.width(); int height = img.height(); diff --git a/effects/video/solideffect.h b/effects/video/solideffect.h index 3892e66be..de065835b 100644 --- a/effects/video/solideffect.h +++ b/effects/video/solideffect.h @@ -10,7 +10,8 @@ public: EffectField* solid_type; EffectField* solid_color_field; EffectField* opacity_field; - void process_image(long p, QImage &img); + void process_gl(long frame, QOpenGLShaderProgram& shaders, GLTextureCoords& coords); + void process_image(long p, uint8_t* data, int width, int height); private slots: void enable_color(); }; diff --git a/effects/video/texteffect.cpp b/effects/video/texteffect.cpp index 8c058a350..873ce16af 100644 --- a/effects/video/texteffect.cpp +++ b/effects/video/texteffect.cpp @@ -242,7 +242,8 @@ void blurred2(QImage& result, const QRect& rect, int radius, bool alphaOnly = fa } } -void TextEffect::process_image(long frame, QImage& img) { +void TextEffect::process_image(long frame, uint8_t* data, int w, int h) { + QImage img(data, w, h, QImage::Format_RGBA8888); QPainter p(&img); p.setRenderHint(QPainter::Antialiasing); int width = img.width(); diff --git a/effects/video/texteffect.h b/effects/video/texteffect.h index b22173d50..ca53fee71 100644 --- a/effects/video/texteffect.h +++ b/effects/video/texteffect.h @@ -9,7 +9,7 @@ class TextEffect : public Effect { Q_OBJECT public: TextEffect(Clip* c); - void process_image(long frame, QImage& img); + void process_image(long frame, uint8_t* data, int width, int height); EffectField* text_val; EffectField* size_val; diff --git a/effects/video/transformeffect.cpp b/effects/video/transformeffect.cpp index 9d189c39e..1d5c21737 100644 --- a/effects/video/transformeffect.cpp +++ b/effects/video/transformeffect.cpp @@ -121,13 +121,21 @@ void TransformEffect::toggle_uniform_scale(bool enabled) { scale_y->set_enabled(!enabled); } -void TransformEffect::process_gl(long frame, QOpenGLShaderProgram&, int* anchor_x, int* anchor_y) { +void TransformEffect::process_gl(long frame, QOpenGLShaderProgram&, GLTextureCoords& coords) { // position glTranslatef(position_x->get_double_value(frame)-(parent_clip->sequence->width/2), position_y->get_double_value(frame)-(parent_clip->sequence->height/2), 0); // anchor point - *anchor_x += (anchor_x_box->get_double_value(frame)-default_anchor_x); - *anchor_y += (anchor_y_box->get_double_value(frame)-default_anchor_y); + int anchor_x_offset = (anchor_x_box->get_double_value(frame)-default_anchor_x); + int anchor_y_offset = (anchor_y_box->get_double_value(frame)-default_anchor_y); + coords.vertexTopLeftX += anchor_x_offset; + coords.vertexTopRightX += anchor_x_offset; + coords.vertexBottomLeftX += anchor_x_offset; + coords.vertexBottomRightX += anchor_x_offset; + coords.vertexTopLeftY += anchor_y_offset; + coords.vertexTopRightY += anchor_y_offset; + coords.vertexBottomLeftY += anchor_y_offset; + coords.vertexBottomRightY += anchor_y_offset; // rotation glRotatef(rotation->get_double_value(frame), 0, 0, 1); diff --git a/effects/video/transformeffect.h b/effects/video/transformeffect.h index 1f5d06672..c0f71a684 100644 --- a/effects/video/transformeffect.h +++ b/effects/video/transformeffect.h @@ -8,7 +8,7 @@ class TransformEffect : public Effect { public: TransformEffect(Clip* c); void refresh(); - void process_gl(long p, QOpenGLShaderProgram& shader_prog, int* anchor_x, int* anchor_y); + void process_gl(long frame, QOpenGLShaderProgram& shaders, GLTextureCoords& coords); EffectField* position_x; EffectField* position_y; diff --git a/main.cpp b/main.cpp index 0ae2d7fde..02fed7c16 100644 --- a/main.cpp +++ b/main.cpp @@ -3,14 +3,12 @@ extern "C" { #include - #include } int main(int argc, char *argv[]) { // init ffmpeg subsystem - av_register_all(); - avfilter_register_all(); + av_register_all(); QApplication a(argc, argv); MainWindow w; diff --git a/olive.pro b/olive.pro index 2120a858f..4657973b9 100644 --- a/olive.pro +++ b/olive.pro @@ -134,16 +134,16 @@ win32 { LIBS += -L../ffmpeg/lib -lopengl32 INCLUDEPATH = ../ffmpeg/include RC_FILE = icons/win.rc - LIBS += -lavutil -lavformat -lavcodec -lavfilter -lswscale -lswresample + LIBS += -lavutil -lavformat -lavcodec -lswscale -lswresample } mac { - LIBS += -L/usr/local/lib -lavutil -lavformat -lavcodec -lavfilter -lswscale -lswresample + LIBS += -L/usr/local/lib -lavutil -lavformat -lavcodec -lswscale -lswresample INCLUDEPATH = /usr/local/include } linux { - LIBS += -lavutil -lavformat -lavcodec -lavfilter -lswscale -lswresample + LIBS += -lavutil -lavformat -lavcodec -lswscale -lswresample } RESOURCES += \ diff --git a/panels/effectcontrols.cpp b/panels/effectcontrols.cpp index e5b904767..adced628a 100644 --- a/panels/effectcontrols.cpp +++ b/panels/effectcontrols.cpp @@ -35,7 +35,10 @@ EffectControls::EffectControls(QWidget *parent) : ui->effects_area->keyframe_area = ui->keyframeView; ui->effects_area->header = ui->headers; + ui->keyframeView->header = ui->headers; + connect(ui->keyframeScroller->verticalScrollBar(), SIGNAL(valueChanged(int)), ui->scrollArea->verticalScrollBar(), SLOT(setValue(int))); + connect(ui->keyframeScroller->horizontalScrollBar(), SIGNAL(valueChanged(int)), ui->keyframeHeaderScroller->horizontalScrollBar(), SLOT(setValue(int))); } EffectControls::~EffectControls() { diff --git a/panels/effectcontrols.ui b/panels/effectcontrols.ui index 401449ca6..ef35b45db 100644 --- a/panels/effectcontrols.ui +++ b/panels/effectcontrols.ui @@ -23,7 +23,7 @@ Effect Controls - + 0 @@ -40,13 +40,10 @@ 0 - + Qt::Horizontal - - false - @@ -421,71 +418,156 @@ - + - + 1 0 - - Qt::ScrollBarAlwaysOn - - - Qt::ScrollBarAlwaysOn - - - true - - - - - 0 - 0 - 376 - 475 - + + + 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 0 - 0 - - - - - 0 - 15 - - - - Qt::ClickFocus + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + 16777215 + 15 + + + + Qt::ScrollBarAlwaysOff + + + Qt::ScrollBarAlwaysOff + + + true + + + + + 0 + 0 + 390 + 16 + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + 0 + 15 + + + + Qt::ClickFocus + + + + - - - - - - + + + + + + + 1 + 0 + + + + QFrame::NoFrame + + + QFrame::Plain + + + Qt::ScrollBarAlwaysOn + + + Qt::ScrollBarAlwaysOn + + + true + + + + + 0 + 0 + 378 + 462 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + + diff --git a/panels/timeline.ui b/panels/timeline.ui index b7aaa8d9f..693493d2d 100644 --- a/panels/timeline.ui +++ b/panels/timeline.ui @@ -373,7 +373,7 @@ false - + QFrame::NoFrame @@ -395,7 +395,7 @@ 0 0 807 - 277 + 163 @@ -424,7 +424,7 @@ - + QFrame::NoFrame @@ -446,7 +446,7 @@ 0 0 807 - 263 + 377 @@ -494,24 +494,30 @@ - - TimelineWidget - QWidget -
ui/timelinewidget.h
- 1 -
TimelineHeader QWidget
ui/timelineheader.h
1
+ + TimelineWidget + QWidget +
ui/timelinewidget.h
+ 1 +
AudioMonitor QWidget
ui/audiomonitor.h
1
+ + ScrollArea + QScrollArea +
ui/scrollarea.h
+ 1 +
diff --git a/playback/cacher.cpp b/playback/cacher.cpp index 0422ab0f2..cbd64284f 100644 --- a/playback/cacher.cpp +++ b/playback/cacher.cpp @@ -12,10 +12,6 @@ extern "C" { #include - #include - #include - #include - #include #include #include #include @@ -188,55 +184,14 @@ void cache_video_worker(Clip* c, long playhead, ClipCache* cache) { int i = 0; - /* swscale solution - might be faster? but AVFilter solution is more "future-proof" if (!c->reached_end) { while (i < c->cache_size) { - time = QDateTime::currentMSecsSinceEpoch(); retrieve_next_frame_raw_data(c, cache->frames[i]); - qDebug() << (QDateTime::currentMSecsSinceEpoch() - time); if (c->reached_end) break; i++; } } - */ - /* AVFilter solution - not definitely slower, may allow for cool things later */ - if (!c->reached_end) { - while (i < c->cache_size) { - av_frame_unref(cache->frames[i]); - - int ret = (c->filter_graph == NULL) ? AVERROR(EAGAIN) : av_buffersink_get_frame(c->buffersink_ctx, cache->frames[i]); - - if (ret < 0) { - if (ret == AVERROR(EAGAIN)) { - ret = retrieve_next_frame(c, c->frame); - if (ret >= 0) { - if ((ret = av_buffersrc_add_frame_flags(c->buffersrc_ctx, c->frame, AV_BUFFERSRC_FLAG_KEEP_REF)) < 0) { - qDebug() << "[ERROR] Could not feed filtergraph -" << ret; - error = true; - break; - } - } else { - if (ret == AVERROR_EOF) { - c->reached_end = true; - } else { - qDebug() << "[WARNING] Raw frame data could not be retrieved." << ret; - error = true; - } - break; - } - } else { - if (ret != AVERROR_EOF) { - qDebug() << "[ERROR] Could not pull from filtergraph"; - error = true; - } - break; - } - } else { - i++; - } - } - } cache->write_count = i; if (!error) { @@ -344,10 +299,10 @@ void open_clip_worker(Clip* clip) { if (clip->stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { // set up swscale context - primarily used for colorspace conversion // as "scaling" is actually done by OpenGL -// int dstW = ceil(clip->stream->codecpar->width/2)*2; -// int dstH = ceil(clip->stream->codecpar->height/2)*2; + int dstW = ceil(clip->stream->codecpar->width/2)*2; + int dstH = ceil(clip->stream->codecpar->height/2)*2; - /*clip->sws_ctx = sws_getContext( + clip->sws_ctx = sws_getContext( clip->stream->codecpar->width, clip->stream->codecpar->height, static_cast(clip->stream->codecpar->format), @@ -358,7 +313,7 @@ void open_clip_worker(Clip* clip) { NULL, NULL, NULL - );*/ + ); // create memory cache for video clip->cache_size = (ms->infinite_length) ? 1 : ceil(av_q2d(av_guess_frame_rate(clip->formatCtx, clip->stream, NULL))/4); // cache is half a second in total @@ -368,48 +323,28 @@ void open_clip_worker(Clip* clip) { clip->cache_B.frames = new AVFrame* [clip->cache_size]; for (int i=0;icache_size;i++) { clip->cache_A.frames[i] = av_frame_alloc(); + av_frame_make_writable(clip->cache_A.frames[i]); + clip->cache_A.frames[i]->width = dstW; + clip->cache_A.frames[i]->height = dstH; + clip->cache_A.frames[i]->format = dest_format; + if (av_frame_get_buffer(clip->cache_A.frames[i], 0)) { + qDebug() << "[ERROR] Could not allocate buffer for sws_frame"; + } + clip->cache_A.frames[i]->linesize[0] = dstW*4; + clip->cache_B.frames[i] = av_frame_alloc(); + av_frame_make_writable(clip->cache_B.frames[i]); + clip->cache_B.frames[i]->width = dstW; + clip->cache_B.frames[i]->height = dstH; + clip->cache_B.frames[i]->format = dest_format; + if (av_frame_get_buffer(clip->cache_B.frames[i], 0)) { + qDebug() << "[ERROR] Could not allocate buffer for sws_frame"; + } + clip->cache_B.frames[i]->linesize[0] = dstW*4; } clip->comp_frame_size = clip->stream->codecpar->width * clip->stream->codecpar->height * 4; clip->comp_frame = new uchar[clip->comp_frame_size]; - - // alloc temporary scale frame - /*clip->sws_frame = av_frame_alloc(); - av_frame_make_writable(clip->sws_frame); - clip->sws_frame->width = dstW; - clip->sws_frame->height = dstH; - clip->sws_frame->format = dest_format; - if (av_frame_get_buffer(clip->sws_frame, 0)) { - qDebug() << "[ERROR] Could not allocate buffer for sws_frame"; - } - clip->sws_frame->linesize[0] = clip->stream->codecpar->width*4;*/ - - clip->filter_graph = avfilter_graph_alloc(); - char args[512]; - snprintf(args, sizeof(args), - "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d", - clip->stream->codecpar->width, clip->stream->codecpar->height, clip->stream->codecpar->format, - clip->stream->time_base.num, clip->stream->time_base.den, - clip->stream->codecpar->sample_aspect_ratio.num, clip->stream->codecpar->sample_aspect_ratio.den); - avfilter_graph_create_filter(&clip->buffersrc_ctx, avfilter_get_by_name("buffer"), "in", args, NULL, clip->filter_graph); - avfilter_graph_create_filter(&clip->buffersink_ctx, avfilter_get_by_name("buffersink"), "out", NULL, NULL, clip->filter_graph); - enum AVPixelFormat pix_fmts[] = { static_cast(dest_format), AV_PIX_FMT_NONE }; - av_opt_set_int_list(clip->buffersink_ctx, "pix_fmts", pix_fmts, AV_PIX_FMT_NONE, AV_OPT_SEARCH_CHILDREN); - - avfilter_link(clip->buffersrc_ctx, 0, clip->buffersink_ctx, 0); - - avfilter_graph_config(clip->filter_graph, NULL); - - /* old AVFilter code, looks like it'll be unusable - AVFilterContext* gblur_ctx; - avfilter_graph_create_filter(&gblur_ctx, avfilter_get_by_name("gblur"), "ol_gblur", "sigma=20:steps=1", NULL, c->filter_graph); - avfilter_graph_create_filter(&gblur_ctx, avfilter_get_by_name("negate"), "ol_gblur", NULL, NULL, clip->filter_graph); - avfilter_graph_create_filter(&gblur_ctx, avfilter_get_by_name("null"), "ol_gblur", NULL, NULL, clip->filter_graph); - avfilter_link(clip->buffersrc_ctx, 0, gblur_ctx, 0); - avfilter_link(gblur_ctx, 0, clip->buffersink_ctx, 0); - avfilter_link(clip->buffersrc_ctx, 0, clip->buffersink_ctx, 0); - */ } else if (clip->stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { // if FFmpeg can't pick up the channel layout (usually WAV), assume // based on channel count (doesn't support surround sound sources yet) @@ -480,8 +415,6 @@ void close_clip_worker(Clip* clip) { // sws_freeContext(clip->sws_ctx); // TODO will eventually be in audio too -// av_frame_free(&clip->sws_frame); - avfilter_graph_free(&clip->filter_graph); delete [] clip->comp_frame; } else if (clip->stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { swr_free(&clip->swr_ctx); diff --git a/playback/playback.cpp b/playback/playback.cpp index 9dd9a7414..ad386aa9a 100644 --- a/playback/playback.cpp +++ b/playback/playback.cpp @@ -166,11 +166,11 @@ bool get_clip_frame(Clip* c, long playhead) { c->texture->allocateStorage(QOpenGLTexture::RGBA, QOpenGLTexture::UInt8); } + memcpy(c->comp_frame, current_frame->data[0], c->comp_frame_size); - QImage img(c->comp_frame, current_frame->width, current_frame->height, QImage::Format_RGBA8888); for (int i=0;ieffects.size();i++) { if (c->effects.at(i)->enable_image) { - c->effects.at(i)->process_image(sequence_clip_time, img); + c->effects.at(i)->process_image(sequence_clip_time, c->comp_frame, current_frame->width, current_frame->height); } } @@ -248,7 +248,7 @@ void retrieve_next_frame_raw_data(Clip* c, AVFrame* output) { int ret = retrieve_next_frame(c, c->frame); if (ret >= 0) { if (c->stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { -// sws_scale(c->sws_ctx, c->frame->data, c->frame->linesize, 0, c->stream->codecpar->height, output->data, output->linesize); + sws_scale(c->sws_ctx, c->frame->data, c->frame->linesize, 0, c->stream->codecpar->height, output->data, output->linesize); // output->pts = c->frame->best_effort_timestamp; } else if (c->stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { output->pts = c->frame->pts; diff --git a/project/clip.cpp b/project/clip.cpp index 0f64573fc..1d47d92f1 100644 --- a/project/clip.cpp +++ b/project/clip.cpp @@ -25,8 +25,7 @@ Clip::Clip(Sequence* s) : media(NULL), opening_transition(NULL), closing_transition(NULL), - pkt(new AVPacket()), - filter_graph(NULL), + pkt(new AVPacket()), replaced(false), texture(NULL) { diff --git a/project/clip.h b/project/clip.h index 08724a1fc..162b046e2 100644 --- a/project/clip.h +++ b/project/clip.h @@ -18,8 +18,6 @@ struct AVCodec; struct AVCodecContext; struct AVFrame; struct AVPacket; -struct AVFilterGraph; -struct AVFilterContext; struct SwsContext; struct SwrContext; class QOpenGLTexture; @@ -81,11 +79,7 @@ struct Clip AVFrame* frame; uchar* comp_frame; int comp_frame_size; - - // ffmpeg filters - AVFilterGraph* filter_graph; - AVFilterContext* buffersink_ctx; - AVFilterContext* buffersrc_ctx; + SwsContext* sws_ctx; bool pkt_written; bool reached_end; diff --git a/project/undo.cpp b/project/undo.cpp index c1f96a846..4e5994d38 100644 --- a/project/undo.cpp +++ b/project/undo.cpp @@ -34,10 +34,6 @@ QUndoStack undo_stack; #define TA_MODIFY_TRANSITION 11 #define TA_DELETE_TRANSITION 12 -extern "C" { - #include "libavfilter/avfilter.h" -} - TimelineAction::TimelineAction() : done(false), change_seq(false), diff --git a/ui/keyframeview.cpp b/ui/keyframeview.cpp index 36d05e1da..db91f4c65 100644 --- a/ui/keyframeview.cpp +++ b/ui/keyframeview.cpp @@ -6,6 +6,7 @@ #include "panels/effectcontrols.h" #include "project/clip.h" #include "panels/timeline.h" +#include "ui/timelineheader.h" #include #include @@ -21,7 +22,9 @@ KeyframeView::KeyframeView(QWidget *parent) : QWidget(parent), mousedown(false), void KeyframeView::paintEvent(QPaintEvent*) { QPainter p(this); - setMinimumWidth(getScreenPointFromFrame(panel_effect_controls->zoom, visible_out - visible_in)); + int width = getScreenPointFromFrame(panel_effect_controls->zoom, visible_out - visible_in); + setMinimumWidth(width); + header->setMinimumWidth(width); rowY.clear(); rows.clear(); @@ -37,8 +40,7 @@ void KeyframeView::paintEvent(QPaintEvent*) { int keyframe_y = label->y() + (label->height()>>1) + mapFrom(panel_effect_controls, contents->mapTo(panel_effect_controls, contents->pos())).y() - e->container->title_bar->height(); for (int k=0;kkeyframe_times.size();k++) { bool keyframe_selected = false; - for (int l=0;l effects; + TimelineHeader* header; + long visible_in; long visible_out; private: diff --git a/ui/labelslider.cpp b/ui/labelslider.cpp index 05d07a5e6..85a847903 100644 --- a/ui/labelslider.cpp +++ b/ui/labelslider.cpp @@ -29,7 +29,7 @@ void LabelSlider::set_value(double v, bool userSet) { internal_value = v; } - setText(QString::number(internal_value)); + setText(QString::number(internal_value, 'f', 1)); if (userSet) emit valueChanged(); } } diff --git a/ui/viewerwidget.cpp b/ui/viewerwidget.cpp index 884a9d716..7568c9a44 100644 --- a/ui/viewerwidget.cpp +++ b/ui/viewerwidget.cpp @@ -171,13 +171,20 @@ void ViewerWidget::compose_sequence(QVector& nests, bool render_audio) { int half_height = sequence->height/2; if (flip) half_height = -half_height; glOrtho(-half_width, half_width, half_height, -half_height, -1, 1); - int anchor_x = ms->video_width/2; - int anchor_y = ms->video_height/2; + + GLTextureCoords coords; + coords.vertexTopLeftX = coords.vertexBottomLeftX = -ms->video_width/2; + coords.vertexTopLeftY = coords.vertexTopRightY = -ms->video_height/2; + coords.vertexTopRightX = coords.vertexBottomRightX = ms->video_width/2; + coords.vertexBottomLeftY = coords.vertexBottomRightY = ms->video_height/2; + 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;jeffects.size();j++) { - if (c->effects.at(j)->enable_opengl && c->effects.at(j)->is_enabled()) c->effects.at(j)->process_gl(panel_timeline->playhead-c->timeline_in+c->clip_in, shader, &anchor_x, &anchor_y); + if (c->effects.at(j)->enable_opengl && c->effects.at(j)->is_enabled()) + c->effects.at(j)->process_gl(panel_timeline->playhead-c->timeline_in+c->clip_in, shader, coords); } if (c->opening_transition != NULL) { @@ -192,10 +199,7 @@ void ViewerWidget::compose_sequence(QVector& nests, bool render_audio) { if (transition_progress < c->closing_transition->length) { c->closing_transition->process_transition((double)transition_progress/(double)c->closing_transition->length); } - } - - int anchor_right = ms->video_width - anchor_x; - int anchor_bottom = ms->video_height - anchor_y; + } bool use_gl_shaders = shader.link(); if (use_gl_shaders) shader.bind(); @@ -203,14 +207,14 @@ void ViewerWidget::compose_sequence(QVector& nests, bool render_audio) { c->texture->bind(); glBegin(GL_QUADS); - glTexCoord2f(0.0, 0.0); - glVertex2f(-anchor_x, -anchor_y); - glTexCoord2f(1.0, 0.0); - glVertex2f(anchor_right, -anchor_y); - glTexCoord2f(1.0, 1.0); - glVertex2f(anchor_right, anchor_bottom); - glTexCoord2f(0.0, 1.0); - glVertex2f(-anchor_x, anchor_bottom); + glTexCoord2f(coords.textureTopLeftX, coords.textureTopLeftY); // top left + glVertex2f(coords.vertexTopLeftX, coords.vertexTopLeftY); // top left + glTexCoord2f(coords.textureTopRightX, coords.textureTopRightY); // top right + glVertex2f(coords.vertexTopRightX, coords.vertexTopRightY); // top right + glTexCoord2f(coords.textureBottomRightX, coords.textureBottomRightY); // bottom right + glVertex2f(coords.vertexBottomRightX, coords.vertexBottomRightY); // bottom right + glTexCoord2f(coords.textureBottomLeftX, coords.textureBottomLeftY); // bottom left + glVertex2f(coords.vertexBottomLeftX, coords.vertexBottomLeftY); // bottom left glEnd(); c->texture->release();