fixed export and timeline crashes and way better titler

This commit is contained in:
itsmattkc
2018-08-15 15:18:47 +10:00
parent e19eb0f54c
commit c519dbdf48
10 changed files with 269 additions and 44 deletions
+1 -1
View File
@@ -486,7 +486,7 @@ void ExportDialog::on_pushButton_clicked()
et->audio_enabled = ui->audioGroupbox->isChecked(); et->audio_enabled = ui->audioGroupbox->isChecked();
if (et->audio_enabled) { if (et->audio_enabled) {
et->audio_codec = format_acodecs.at(ui->acodecCombobox->currentIndex()); et->audio_codec = format_acodecs.at(ui->acodecCombobox->currentIndex());
et->audio_sampling_rate = 48000; et->audio_sampling_rate = ui->samplingRateSpinbox->value();
et->audio_bitrate = ui->audiobitrateSpinbox->value(); et->audio_bitrate = ui->audiobitrateSpinbox->value();
} }
+6 -2
View File
@@ -143,11 +143,11 @@ EffectRow::EffectRow(Effect *parent, QGridLayout *uilayout, const QString &n, in
ui->addWidget(new QLabel(name), row, 0); ui->addWidget(new QLabel(name), row, 0);
} }
EffectField* EffectRow::add_field(int type) { EffectField* EffectRow::add_field(int type, int colspan) {
EffectField* field = new EffectField(type); EffectField* field = new EffectField(type);
fields.append(field); fields.append(field);
QWidget* element = field->get_ui_element(); QWidget* element = field->get_ui_element();
ui->addWidget(element, ui_row, fields.size()); ui->addWidget(element, ui_row, fields.size(), 1, colspan);
return field; return field;
} }
@@ -287,6 +287,10 @@ const QString EffectField::get_font_name() {
return static_cast<FontCombobox*>(ui_element)->currentText(); return static_cast<FontCombobox*>(ui_element)->currentText();
} }
void EffectField::set_font_name(const QString& s) {
static_cast<FontCombobox*>(ui_element)->setCurrentText(s);
}
QColor EffectField::get_color_value() { QColor EffectField::get_color_value() {
return static_cast<ColorButton*>(ui_element)->get_color(); return static_cast<ColorButton*>(ui_element)->get_color();
} }
+2 -1
View File
@@ -59,6 +59,7 @@ public:
void set_bool_value(bool b); void set_bool_value(bool b);
const QString get_font_name(); const QString get_font_name();
void set_font_name(const QString& s);
QColor get_color_value(); QColor get_color_value();
void set_color_value(QColor color); void set_color_value(QColor color);
@@ -75,7 +76,7 @@ class EffectRow {
public: public:
EffectRow(Effect* parent, QGridLayout* uilayout, const QString& n, int row); EffectRow(Effect* parent, QGridLayout* uilayout, const QString& n, int row);
~EffectRow(); ~EffectRow();
EffectField* add_field(int type); EffectField* add_field(int type, int colspan = 1);
EffectField* field(int i); EffectField* field(int i);
int fieldCount(); int fieldCount();
void set_keyframe(int field, long time); void set_keyframe(int field, long time);
+17 -6
View File
@@ -7,6 +7,7 @@
#include <QFont> #include <QFont>
#include <QXmlStreamReader> #include <QXmlStreamReader>
#include <QXmlStreamWriter> #include <QXmlStreamWriter>
#include <QWidget>
class QSpinBox; class QSpinBox;
class QCheckBox; class QCheckBox;
class LabelSlider; class LabelSlider;
@@ -43,6 +44,7 @@ public:
TransformEffect(Clip* c); TransformEffect(Clip* c);
void refresh(); void refresh();
void process_gl(int* anchor_x, int* anchor_y); void process_gl(int* anchor_x, int* anchor_y);
Effect* copy(Clip *c);
EffectField* position_x; EffectField* position_x;
EffectField* position_y; EffectField* position_y;
@@ -97,8 +99,8 @@ public:
TextEffect(Clip* c); TextEffect(Clip* c);
~TextEffect(); ~TextEffect();
void post_gl(); void post_gl();
Effect* copy(Clip* c);
void refresh(); void refresh();
Effect* copy(Clip* c);
EffectField* text_val; EffectField* text_val;
EffectField* size_val; EffectField* size_val;
@@ -106,15 +108,24 @@ public:
EffectField* set_font_combobox; EffectField* set_font_combobox;
EffectField* halign_field; EffectField* halign_field;
EffectField* valign_field; EffectField* valign_field;
EffectField* word_wrap_field;
EffectField* outline_bool;
EffectField* outline_width;
EffectField* outline_color;
EffectField* shadow_bool;
EffectField* shadow_distance;
EffectField* shadow_color;
EffectField* shadow_softness;
EffectField* shadow_opacity;
private slots: private slots:
void update_texture(); void update_texture();
private: private:
void destroy_texture(); void destroy_texture();
QOpenGLTexture* texture; QOpenGLTexture* texture;
QImage pixmap; QFont font;
QFont font; QImage pixmap;
int width;
int height;
}; };
class SolidEffect : public Effect { class SolidEffect : public Effect {
+222 -27
View File
@@ -10,6 +10,7 @@
#include <QFontDatabase> #include <QFontDatabase>
#include <QComboBox> #include <QComboBox>
#include <QDebug> #include <QDebug>
#include <QWidget>
#include "ui/labelslider.h" #include "ui/labelslider.h"
#include "ui/collapsiblewidget.h" #include "ui/collapsiblewidget.h"
@@ -21,22 +22,16 @@
TextEffect::TextEffect(Clip *c) : TextEffect::TextEffect(Clip *c) :
Effect(c, EFFECT_TYPE_VIDEO, VIDEO_TEXT_EFFECT), Effect(c, EFFECT_TYPE_VIDEO, VIDEO_TEXT_EFFECT),
texture(NULL), texture(NULL)
width(0),
height(0)
{ {
EffectRow* text_row = add_row("Text:"); text_val = add_row("Text:")->add_field(EFFECT_FIELD_STRING, 2);
text_val = text_row->add_field(EFFECT_FIELD_STRING);
EffectRow* font_row = add_row("Font:"); set_font_combobox = add_row("Font:")->add_field(EFFECT_FIELD_FONT, 2);
set_font_combobox = font_row->add_field(EFFECT_FIELD_FONT);
EffectRow* size_row = add_row("Size:"); size_val = add_row("Size:")->add_field(EFFECT_FIELD_DOUBLE, 2);
size_val = size_row->add_field(EFFECT_FIELD_DOUBLE);
size_val->set_double_minimum_value(0); size_val->set_double_minimum_value(0);
EffectRow* color_row = add_row("Color:"); set_color_button = add_row("Color:")->add_field(EFFECT_FIELD_COLOR, 2);
set_color_button = color_row->add_field(EFFECT_FIELD_COLOR);
EffectRow* alignment_row = add_row("Alignment:"); EffectRow* alignment_row = add_row("Alignment:");
halign_field = alignment_row->add_field(EFFECT_FIELD_COMBO); halign_field = alignment_row->add_field(EFFECT_FIELD_COMBO);
@@ -49,10 +44,35 @@ TextEffect::TextEffect(Clip *c) :
valign_field->add_combo_item("Center", Qt::AlignVCenter); valign_field->add_combo_item("Center", Qt::AlignVCenter);
valign_field->add_combo_item("Bottom", Qt::AlignBottom); valign_field->add_combo_item("Bottom", Qt::AlignBottom);
word_wrap_field = add_row("Word Wrap:")->add_field(EFFECT_FIELD_BOOL, 2);
outline_bool = add_row("Outline:")->add_field(EFFECT_FIELD_BOOL, 2);
outline_color = add_row("Outline Color:")->add_field(EFFECT_FIELD_COLOR, 2);
outline_width = add_row("Outline Width:")->add_field(EFFECT_FIELD_DOUBLE, 2);
outline_width->set_double_minimum_value(0);
shadow_bool = add_row("Shadow:")->add_field(EFFECT_FIELD_BOOL, 2);
shadow_color = add_row("Shadow Color:")->add_field(EFFECT_FIELD_COLOR, 2);
shadow_distance = add_row("Shadow Distance:")->add_field(EFFECT_FIELD_DOUBLE, 2);
shadow_distance->set_double_minimum_value(0);
shadow_softness = add_row("Shadow Softness:")->add_field(EFFECT_FIELD_DOUBLE, 2);
shadow_softness->set_double_minimum_value(0);
shadow_opacity = add_row("Shadow Opacity:")->add_field(EFFECT_FIELD_DOUBLE, 2);
shadow_opacity->set_double_minimum_value(0);
shadow_opacity->set_double_maximum_value(100);
size_val->set_double_default_value(48); size_val->set_double_default_value(48);
text_val->set_string_value("Sample Text"); text_val->set_string_value("Sample Text");
halign_field->set_combo_index(1); halign_field->set_combo_index(1);
valign_field->set_combo_index(1); valign_field->set_combo_index(1);
word_wrap_field->set_bool_value(true);
outline_color->set_color_value(Qt::black);
shadow_color->set_color_value(Qt::black);
shadow_opacity->set_double_default_value(100);
shadow_softness->set_double_default_value(5);
shadow_distance->set_double_default_value(5);
shadow_opacity->set_double_default_value(80);
outline_width->set_double_default_value(2);
connect(text_val, SIGNAL(changed()), this, SLOT(update_texture())); connect(text_val, SIGNAL(changed()), this, SLOT(update_texture()));
connect(size_val, SIGNAL(changed()), this, SLOT(update_texture())); connect(size_val, SIGNAL(changed()), this, SLOT(update_texture()));
@@ -60,6 +80,15 @@ TextEffect::TextEffect(Clip *c) :
connect(set_font_combobox, SIGNAL(changed()), this, SLOT(update_texture())); connect(set_font_combobox, SIGNAL(changed()), this, SLOT(update_texture()));
connect(halign_field, SIGNAL(changed()), this, SLOT(update_texture())); connect(halign_field, SIGNAL(changed()), this, SLOT(update_texture()));
connect(valign_field, SIGNAL(changed()), this, SLOT(update_texture())); connect(valign_field, SIGNAL(changed()), this, SLOT(update_texture()));
connect(word_wrap_field, SIGNAL(changed()), this, SLOT(update_texture()));
connect(outline_bool, SIGNAL(changed()), this, SLOT(update_texture()));
connect(outline_color, SIGNAL(changed()), this, SLOT(update_texture()));
connect(outline_width, SIGNAL(changed()), this, SLOT(update_texture()));
connect(shadow_bool, SIGNAL(changed()), this, SLOT(update_texture()));
connect(shadow_color, SIGNAL(changed()), this, SLOT(update_texture()));
connect(shadow_distance, SIGNAL(changed()), this, SLOT(update_texture()));
connect(shadow_softness, SIGNAL(changed()), this, SLOT(update_texture()));
connect(shadow_opacity, SIGNAL(changed()), this, SLOT(update_texture()));
update_texture(); update_texture();
} }
@@ -76,26 +105,190 @@ void TextEffect::destroy_texture() {
texture->destroy(); texture->destroy();
} }
QImage blurred(const QImage& image, const QRect& rect, int radius, bool alphaOnly = false)
{
int tab[] = { 14, 10, 8, 6, 5, 5, 4, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2 };
int alpha = (radius < 1) ? 16 : (radius > 17) ? 1 : tab[radius-1];
QImage result = image.convertToFormat(QImage::Format_ARGB32_Premultiplied);
int r1 = rect.top();
int r2 = rect.bottom();
int c1 = rect.left();
int c2 = rect.right();
int bpl = result.bytesPerLine();
int rgba[4];
unsigned char* p;
int i1 = 0;
int i2 = 3;
if (alphaOnly)
i1 = i2 = (QSysInfo::ByteOrder == QSysInfo::BigEndian ? 0 : 3);
for (int col = c1; col <= c2; col++) {
p = result.scanLine(r1) + col * 4;
for (int i = i1; i <= i2; i++)
rgba[i] = p[i] << 4;
p += bpl;
for (int j = r1; j < r2; j++, p += bpl)
for (int i = i1; i <= i2; i++)
p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4;
}
for (int row = r1; row <= r2; row++) {
p = result.scanLine(row) + c1 * 4;
for (int i = i1; i <= i2; i++)
rgba[i] = p[i] << 4;
p += 4;
for (int j = c1; j < c2; j++, p += 4)
for (int i = i1; i <= i2; i++)
p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4;
}
for (int col = c1; col <= c2; col++) {
p = result.scanLine(r2) + col * 4;
for (int i = i1; i <= i2; i++)
rgba[i] = p[i] << 4;
p -= bpl;
for (int j = r1; j < r2; j++, p -= bpl)
for (int i = i1; i <= i2; i++)
p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4;
}
for (int row = r1; row <= r2; row++) {
p = result.scanLine(row) + c2 * 4;
for (int i = i1; i <= i2; i++)
rgba[i] = p[i] << 4;
p -= 4;
for (int j = c1; j < c2; j++, p -= 4)
for (int i = i1; i <= i2; i++)
p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4;
}
return result;
}
void TextEffect::update_texture() { void TextEffect::update_texture() {
if (parent_clip->sequence != NULL) { if (parent_clip->sequence != NULL) {
if (parent_clip->sequence->width != width || parent_clip->sequence->height != height) { if (pixmap.width() != parent_clip->sequence->width || pixmap.height() != parent_clip->sequence->height) {
width = parent_clip->sequence->width; pixmap = QImage(parent_clip->sequence->width, parent_clip->sequence->height, QImage::Format_ARGB32);
height = parent_clip->sequence->height;
pixmap = QImage(width, height, QImage::Format_ARGB32_Premultiplied);
} }
pixmap.fill(Qt::transparent); pixmap.fill(Qt::transparent);
QPainter p(&pixmap); QPainter p(&pixmap);
p.setRenderHint(QPainter::TextAntialiasing, true); p.setRenderHint(QPainter::Antialiasing);
// set font // set font
font.setStyleHint(QFont::Helvetica, QFont::PreferAntialias);
font.setFamily(set_font_combobox->get_font_name()); font.setFamily(set_font_combobox->get_font_name());
font.setPointSize(size_val->get_double_value()); font.setPointSize(size_val->get_double_value());
font.setStyleHint(QFont::Helvetica, QFont::PreferAntialias);
p.setFont(font); p.setFont(font);
QFontMetrics fm(font);
p.setPen(set_color_button->get_color_value()); QStringList lines = text_val->get_string_value().split('\n');
p.drawText(QRect(0, 0, width, height), halign_field->get_combo_data().toInt() | valign_field->get_combo_data().toInt() | Qt::TextWordWrap, text_val->get_string_value());
// word wrap function
if (word_wrap_field->get_bool_value()) {
for (int i=0;i<lines.size();i++) {
const QString& s = lines.at(i);
if (fm.width(s) > pixmap.width()) {
int last_space_index = 0;
for (int j=0;j<s.length();j++) {
if (s.at(j) == ' ') {
if (fm.width(s.left(j)) > pixmap.width()) {
break;
} else {
last_space_index = j;
}
}
}
if (last_space_index > 0) {
lines.insert(i+1, s.mid(last_space_index + 1));
lines[i] = s.left(last_space_index);
}
}
}
}
QPainterPath path;
int text_height = fm.height()*lines.size();
for (int i=0;i<lines.size();i++) {
int text_x, text_y;
switch (halign_field->get_combo_data().toInt()) {
case Qt::AlignLeft: text_x = 0; break;
case Qt::AlignHCenter: text_x = (pixmap.width()/2) - (fm.width(lines.at(i))/2); break;
case Qt::AlignRight: text_x = pixmap.width() - fm.width(lines.at(i)); break;
case Qt::AlignJustify:
// add spaces until the string is too big
text_x = 0;
while (fm.width(lines.at(i) < pixmap.width())) {
bool space = false;
QString spaced(lines.at(i));
for (int i=0;i<spaced.length();i++) {
if (spaced.at(i) == ' ') {
// insert a space
spaced.insert(i, ' ');
space = true;
// scan to next non-space
while (i < spaced.length() && spaced.at(i) == ' ') {
i++;
}
}
}
if (fm.width(spaced) > pixmap.width() || !space) {
break;
} else {
lines[i] = spaced;
}
}
break;
}
switch (valign_field->get_combo_data().toInt()) {
case Qt::AlignTop: text_y = (fm.height()*i)+fm.ascent(); break;
case Qt::AlignVCenter: text_y = ((pixmap.height()/2) - (text_height/2) - fm.descent()) + (fm.height()*(i+1)); break;
case Qt::AlignBottom: text_y = (pixmap.height() - text_height - fm.descent()) + (fm.height()*(i+1)); break;
}
path.addText(text_x, text_y, font, lines.at(i));
}
p.setPen(Qt::NoPen);
// draw shadow
if (shadow_bool->get_bool_value()) {
int shadow_offset = shadow_distance->get_double_value();
QColor col = shadow_color->get_color_value();
col.setAlphaF(shadow_opacity->get_double_value()*0.01);
p.setBrush(col);
p.drawPath(path);
QImage shadow = blurred(pixmap, pixmap.rect(), shadow_softness->get_double_value(), false);
p.drawImage(shadow_offset, shadow_offset, shadow);
}
// draw outline
int outline_width_val = outline_width->get_double_value();
if (outline_bool->get_bool_value() && outline_width_val > 0) {
QPen outline(outline_color->get_color_value());
outline.setWidth(outline_width_val);
p.setPen(outline);
}
// draw "master" text
p.setBrush(set_color_button->get_color_value());
p.drawPath(path);
p.end();
if (texture == NULL) { if (texture == NULL) {
texture = new QOpenGLTexture(pixmap); texture = new QOpenGLTexture(pixmap);
@@ -115,8 +308,8 @@ void TextEffect::post_gl() {
if (texture != NULL) { if (texture != NULL) {
texture->bind(); texture->bind();
int half_width = width/2; int half_width = pixmap.width()/2;
int half_height = height/2; int half_height = pixmap.height()/2;
glBegin(GL_QUADS); glBegin(GL_QUADS);
glTexCoord2f(0.0, 0.0); glTexCoord2f(0.0, 0.0);
@@ -134,10 +327,12 @@ void TextEffect::post_gl() {
} }
Effect* TextEffect::copy(Clip* c) { Effect* TextEffect::copy(Clip* c) {
/*TextEffect* e = new TextEffect(c); TextEffect* e = new TextEffect(c);
e->text_val->setPlainText(text_val->toPlainText()); e->text_val->set_string_value(text_val->get_string_value());
e->size_val->set_value(size_val->value()); e->size_val->set_double_value(size_val->get_double_value());
e->set_color_button->set_color(set_color_button->get_color()); e->set_color_button->set_color_value(set_color_button->get_color_value());
return e;*/ e->set_font_combobox->set_font_name(set_font_combobox->get_font_name());
return NULL; e->halign_field->set_combo_index(halign_field->get_combo_index());
e->valign_field->set_combo_index(valign_field->get_combo_index());
return e;
} }
+15
View File
@@ -77,6 +77,21 @@ TransformEffect::TransformEffect(Clip* c) : Effect(c, EFFECT_TYPE_VIDEO, VIDEO_T
connect(uniform_scale_box, SIGNAL(toggled(bool)), this, SLOT(toggle_uniform_scale(bool))); connect(uniform_scale_box, SIGNAL(toggled(bool)), this, SLOT(toggle_uniform_scale(bool)));
} }
Effect* TransformEffect::copy(Clip* c) {
TransformEffect* t = new TransformEffect(c);
t->position_x->set_double_value(position_x->get_double_value());
t->position_y->set_double_value(position_y->get_double_value());
t->scale_x->set_double_value(scale_x->get_double_value());
t->scale_y->set_double_value(scale_y->get_double_value());
t->uniform_scale_field->set_bool_value(uniform_scale_field->get_bool_value());
t->rotation->set_double_value(rotation->get_double_value());
t->anchor_x_box->set_double_value(anchor_x_box->get_double_value());
t->anchor_y_box->set_double_value(anchor_y_box->get_double_value());
t->opacity->set_double_value(opacity->get_double_value());
t->blend_mode_box->set_combo_index(blend_mode_box->get_combo_index());
return t;
}
void TransformEffect::refresh() { void TransformEffect::refresh() {
if (parent_clip->sequence != NULL) { if (parent_clip->sequence != NULL) {
double default_pos_x = parent_clip->sequence->width/2; double default_pos_x = parent_clip->sequence->width/2;
+3 -4
View File
@@ -24,10 +24,9 @@ VolumeEffect::VolumeEffect(Clip* c) : Effect(c, EFFECT_TYPE_AUDIO, AUDIO_VOLUME_
void VolumeEffect::refresh() {} void VolumeEffect::refresh() {}
Effect* VolumeEffect::copy(Clip* c) { Effect* VolumeEffect::copy(Clip* c) {
/*VolumeEffect* v = new VolumeEffect(c); VolumeEffect* v = new VolumeEffect(c);
v->volume_val->set_value(volume_val->value()); v->volume_val->set_double_value(volume_val->get_double_value());
return v;*/ return v;
return NULL;
} }
void VolumeEffect::process_audio(quint8* samples, int nb_bytes) { void VolumeEffect::process_audio(quint8* samples, int nb_bytes) {
+1 -1
View File
@@ -53,7 +53,7 @@ void ExportThread::run() {
panel_timeline->pause(); panel_timeline->pause();
// av_log_set_level(AV_LOG_DEBUG); // av_log_set_level(AV_LOG_DEBUG);
if (!panel_viewer->viewer_widget->context()->makeCurrent(&surface)) { if (!panel_viewer->viewer_widget->context()->makeCurrent(&surface)) {
qDebug() << "[ERROR] Make current failed"; qDebug() << "[ERROR] Make current failed";
ed->export_error = "could not make OpenGL context current"; ed->export_error = "could not make OpenGL context current";
return; return;
+1 -1
View File
@@ -1,6 +1,6 @@
#include "clip.h" #include "clip.h"
#include "project/effect.h" #include "effects/effect.h"
#include "effects/transition.h" #include "effects/transition.h"
#include "io/media.h" #include "io/media.h"
#include "playback/playback.h" #include "playback/playback.h"
+1 -1
View File
@@ -5,7 +5,7 @@
#include "panels/timeline.h" #include "panels/timeline.h"
#include "panels/project.h" #include "panels/project.h"
#include "project/sequence.h" #include "project/sequence.h"
#include "project/effect.h" #include "effects/effect.h"
#include "effects/transition.h" #include "effects/transition.h"
#include "playback/playback.h" #include "playback/playback.h"
#include "playback/audio.h" #include "playback/audio.h"