restored swscale and updated opengl fx spec
This commit is contained in:
+117
-79
@@ -136,79 +136,111 @@ bool Effect::is_enabled() {
|
||||
return container->enabled_check->isChecked();
|
||||
}
|
||||
|
||||
void Effect::load(QXmlStreamReader& stream) {
|
||||
stream.readNext();
|
||||
/*for (int i=0;i<rows.size();i++) {
|
||||
EffectRow* row = rows.at(i);
|
||||
while (!stream->atEnd() && !(stream->name() == "effect" && stream->isEndElement())) {
|
||||
stream->readNext();
|
||||
if (stream->name() == "row" && stream->isStartElement()) {
|
||||
for (int j=0;j<row->fieldCount();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<EffectKeyframe> keys;
|
||||
while (!stream->atEnd() && (stream->name() == "field" && stream->isEndElement())) {
|
||||
stream->readNext();
|
||||
if (stream->name() == "key" && stream->isStartElement()) {
|
||||
EffectKeyframe kf;
|
||||
for (int k=0;k<stream->attributes().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<QColor>().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<QColor>().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;k<stream.attributes().size();k++) {
|
||||
const QXmlStreamAttribute& attr = stream.attributes().at(k);
|
||||
if (attr.name() == "enabled") {
|
||||
row->keyframing = (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;k<stream.attributes().size();k++) {
|
||||
const QXmlStreamAttribute& attr = stream.attributes().at(k);
|
||||
if (attr.name() == "frame") {
|
||||
keyframe_frame = attr.value().toLong();
|
||||
} else if (attr.name() == "type") {
|
||||
keyframe_type = attr.value().toInt();
|
||||
}
|
||||
}
|
||||
row->keyframe_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;k<stream.attributes().size();k++) {
|
||||
const QXmlStreamAttribute& attr = stream.attributes().at(k);
|
||||
if (attr.name() == "value") {
|
||||
field->set_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;j<row->fieldCount();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;k<field->keyframe_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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+22
-2
@@ -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();
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#include <QXmlStreamWriter>
|
||||
#include <QXmlStreamAttributes>
|
||||
|
||||
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}");
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
};
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -3,14 +3,12 @@
|
||||
|
||||
extern "C" {
|
||||
#include <libavformat/avformat.h>
|
||||
#include <libavfilter/avfilter.h>
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
// init ffmpeg subsystem
|
||||
av_register_all();
|
||||
avfilter_register_all();
|
||||
av_register_all();
|
||||
|
||||
QApplication a(argc, argv);
|
||||
MainWindow w;
|
||||
|
||||
@@ -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 += \
|
||||
|
||||
@@ -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() {
|
||||
|
||||
+144
-62
@@ -23,7 +23,7 @@
|
||||
<string>Effect Controls</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="dockWidgetContents">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_7">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
@@ -40,13 +40,10 @@
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QSplitter" name="splitter_2">
|
||||
<widget class="QSplitter" name="splitter">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="childrenCollapsible">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<widget class="QScrollArea" name="scrollArea">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Expanding">
|
||||
@@ -421,71 +418,156 @@
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
<widget class="QScrollArea" name="keyframeScroller">
|
||||
<widget class="QWidget" name="keyframeArea" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>1</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="verticalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarAlwaysOn</enum>
|
||||
</property>
|
||||
<property name="horizontalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarAlwaysOn</enum>
|
||||
</property>
|
||||
<property name="widgetResizable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<widget class="QWidget" name="scrollAreaWidgetContents_2">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>376</width>
|
||||
<height>475</height>
|
||||
</rect>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_7">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="TimelineHeader" name="headers" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>15</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="focusPolicy">
|
||||
<enum>Qt::ClickFocus</enum>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QScrollArea" name="keyframeHeaderScroller">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>15</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="verticalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarAlwaysOff</enum>
|
||||
</property>
|
||||
<property name="horizontalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarAlwaysOff</enum>
|
||||
</property>
|
||||
<property name="widgetResizable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<widget class="QWidget" name="scrollAreaWidgetContents_3">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>390</width>
|
||||
<height>16</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_8">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="TimelineHeader" name="headers" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>15</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="focusPolicy">
|
||||
<enum>Qt::ClickFocus</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="KeyframeView" name="keyframeView" native="true"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QScrollArea" name="keyframeScroller">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>1</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Plain</enum>
|
||||
</property>
|
||||
<property name="verticalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarAlwaysOn</enum>
|
||||
</property>
|
||||
<property name="horizontalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarAlwaysOn</enum>
|
||||
</property>
|
||||
<property name="widgetResizable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<widget class="QWidget" name="scrollAreaWidgetContents_2">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>378</width>
|
||||
<height>462</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="KeyframeView" name="keyframeView" native="true"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
+16
-10
@@ -373,7 +373,7 @@
|
||||
<property name="childrenCollapsible">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<widget class="QScrollArea" name="videoScrollArea">
|
||||
<widget class="ScrollArea" name="videoScrollArea">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
@@ -395,7 +395,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>807</width>
|
||||
<height>277</height>
|
||||
<height>163</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
@@ -424,7 +424,7 @@
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
<widget class="QScrollArea" name="audioScrollArea">
|
||||
<widget class="ScrollArea" name="audioScrollArea">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
@@ -446,7 +446,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>807</width>
|
||||
<height>263</height>
|
||||
<height>377</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
@@ -494,24 +494,30 @@
|
||||
</widget>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>TimelineWidget</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>ui/timelinewidget.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>TimelineHeader</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>ui/timelineheader.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>TimelineWidget</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>ui/timelinewidget.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>AudioMonitor</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>ui/audiomonitor.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>ScrollArea</class>
|
||||
<extends>QScrollArea</extends>
|
||||
<header>ui/scrollarea.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources>
|
||||
<include location="../icons/icons.qrc"/>
|
||||
|
||||
+21
-88
@@ -12,10 +12,6 @@
|
||||
|
||||
extern "C" {
|
||||
#include <libavformat/avformat.h>
|
||||
#include <libavutil/opt.h>
|
||||
#include <libavfilter/avfilter.h>
|
||||
#include <libavfilter/buffersrc.h>
|
||||
#include <libavfilter/buffersink.h>
|
||||
#include <libavcodec/avcodec.h>
|
||||
#include <libswscale/swscale.h>
|
||||
#include <libswresample/swresample.h>
|
||||
@@ -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<AVPixelFormat>(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;i<clip->cache_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<AVPixelFormat>(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);
|
||||
|
||||
@@ -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;i<c->effects.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;
|
||||
|
||||
+1
-2
@@ -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)
|
||||
{
|
||||
|
||||
+1
-7
@@ -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;
|
||||
|
||||
@@ -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),
|
||||
|
||||
+5
-3
@@ -6,6 +6,7 @@
|
||||
#include "panels/effectcontrols.h"
|
||||
#include "project/clip.h"
|
||||
#include "panels/timeline.h"
|
||||
#include "ui/timelineheader.h"
|
||||
|
||||
#include <QLabel>
|
||||
#include <QMouseEvent>
|
||||
@@ -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;k<row->keyframe_times.size();k++) {
|
||||
bool keyframe_selected = false;
|
||||
for (int l=0;l<selected_rows.size();l++) {
|
||||
// qDebug() << selected_rows.at(l) << rows.size() << selected_keyframes.at(l) << k;
|
||||
for (int l=0;l<selected_rows.size();l++) {
|
||||
if (selected_rows.at(l) == rows.size() && selected_keyframes.at(l) == k) {
|
||||
keyframe_selected = true;
|
||||
break;
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
struct Clip;
|
||||
class Effect;
|
||||
class EffectRow;
|
||||
class TimelineHeader;
|
||||
|
||||
class KeyframeView : public QWidget {
|
||||
Q_OBJECT
|
||||
@@ -14,6 +15,8 @@ public:
|
||||
KeyframeView(QWidget* parent = 0);
|
||||
QVector<Effect*> effects;
|
||||
|
||||
TimelineHeader* header;
|
||||
|
||||
long visible_in;
|
||||
long visible_out;
|
||||
private:
|
||||
|
||||
+1
-1
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
+19
-15
@@ -171,13 +171,20 @@ void ViewerWidget::compose_sequence(QVector<Clip*>& 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;j<c->effects.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<Clip*>& 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<Clip*>& 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();
|
||||
|
||||
Reference in New Issue
Block a user