work towards exports working on threaded gl

This commit is contained in:
itsmattkc
2019-01-16 21:23:23 +11:00
parent 803ecb7493
commit 0580fce981
13 changed files with 121 additions and 126 deletions
+59 -61
View File
@@ -57,7 +57,7 @@ enum ExportFormats {
ExportDialog::ExportDialog(QWidget *parent) :
QDialog(parent)
{
setWindowTitle(tr("Export \"%1\"").arg(sequence->name));
setWindowTitle(tr("Export \"%1\"").arg(sequence->name));
setup_ui();
rangeCombobox->setCurrentIndex(0);
@@ -320,12 +320,12 @@ void ExportDialog::format_changed(int index)
void ExportDialog::render_thread_finished() {
if (progressBar->value() < 100 && !cancelled) {
QMessageBox::critical(
this,
tr("Export Failed"),
tr("Export failed - %1").arg(export_error),
QMessageBox::Ok
);
QMessageBox::critical(
this,
tr("Export Failed"),
tr("Export failed - %1").arg(export_error),
QMessageBox::Ok
);
}
prep_ui_for_render(false);
panel_sequence_viewer->viewer_widget->makeCurrent();
@@ -342,12 +342,12 @@ void ExportDialog::prep_ui_for_render(bool r) {
void ExportDialog::export_action() {
if (widthSpinbox->value()%2 == 1 || heightSpinbox->value()%2 == 1) {
QMessageBox::critical(
this,
tr("Invalid dimensions"),
tr("Export width and height must both be even numbers/divisible by 2."),
QMessageBox::Ok
);
QMessageBox::critical(
this,
tr("Invalid dimensions"),
tr("Export width and height must both be even numbers/divisible by 2."),
QMessageBox::Ok
);
return;
}
@@ -399,12 +399,12 @@ void ExportDialog::export_action() {
break;
default:
qCritical() << "Invalid codec selection for an image sequence";
QMessageBox::critical(
this,
tr("Invalid codec"),
tr("Couldn't determine output parameters for the selected codec. This is a bug, please contact the developers."),
QMessageBox::Ok
);
QMessageBox::critical(
this,
tr("Invalid codec"),
tr("Couldn't determine output parameters for the selected codec. This is a bug, please contact the developers."),
QMessageBox::Ok
);
return;
}
break;
@@ -469,20 +469,20 @@ void ExportDialog::export_action() {
break;
default:
qCritical() << "Invalid format - this is a bug, please inform the developers";
QMessageBox::critical(
this,
tr("Invalid format"),
tr("Couldn't determine output format. This is a bug, please contact the developers."),
QMessageBox::Ok
);
QMessageBox::critical(
this,
tr("Invalid format"),
tr("Couldn't determine output format. This is a bug, please contact the developers."),
QMessageBox::Ok
);
return;
}
QString filename = QFileDialog::getSaveFileName(
this,
tr("Export Media"),
"",
format_strings[formatCombobox->currentIndex()] + " (*." + ext + ")"
);
QString filename = QFileDialog::getSaveFileName(
this,
tr("Export Media"),
"",
format_strings[formatCombobox->currentIndex()] + " (*." + ext + ")"
);
if (!filename.isEmpty()) {
if (!filename.endsWith("." + ext, Qt::CaseInsensitive)) {
filename += "." + ext;
@@ -506,11 +506,9 @@ void ExportDialog::export_action() {
closeActiveClips(sequence);
mainWindow->autorecover_interval();
mainWindow->set_rendering_state(true);
rendering = true;
panel_sequence_viewer->viewer_widget->context()->doneCurrent();
panel_sequence_viewer->viewer_widget->context()->moveToThread(et);
mainWindow->autorecover_interval();
prep_ui_for_render(true);
@@ -565,11 +563,11 @@ void ExportDialog::vcodec_changed(int index) {
compressionTypeCombobox->clear();
if ((format_vcodecs.size() > 0 && format_vcodecs.at(index) == AV_CODEC_ID_H264)) {
compressionTypeCombobox->setEnabled(true);
compressionTypeCombobox->addItem(tr("Quality-based (Constant Rate Factor)"), COMPRESSION_TYPE_CFR);
compressionTypeCombobox->addItem(tr("Quality-based (Constant Rate Factor)"), COMPRESSION_TYPE_CFR);
// compressionTypeCombobox->addItem("File size-based (Two-Pass)", COMPRESSION_TYPE_TARGETSIZE);
// compressionTypeCombobox->addItem("Average bitrate (Two-Pass)", COMPRESSION_TYPE_TARGETBR);
} else {
compressionTypeCombobox->addItem(tr("Constant Bitrate"), COMPRESSION_TYPE_CBR);
compressionTypeCombobox->addItem(tr("Constant Bitrate"), COMPRESSION_TYPE_CBR);
compressionTypeCombobox->setCurrentIndex(0);
compressionTypeCombobox->setEnabled(false);
}
@@ -582,17 +580,17 @@ void ExportDialog::comp_type_changed(int) {
switch (compressionTypeCombobox->currentData().toInt()) {
case COMPRESSION_TYPE_CBR:
case COMPRESSION_TYPE_TARGETBR:
videoBitrateLabel->setText(tr("Bitrate (Mbps):"));
videoBitrateLabel->setText(tr("Bitrate (Mbps):"));
videobitrateSpinbox->setValue(qMax(0.5, (double) qRound((0.01528 * sequence->height) - 4.5)));
break;
case COMPRESSION_TYPE_CFR:
videoBitrateLabel->setText(tr("Quality (CRF):"));
videoBitrateLabel->setText(tr("Quality (CRF):"));
videobitrateSpinbox->setValue(36);
videobitrateSpinbox->setMaximum(51);
videobitrateSpinbox->setToolTip(tr("Quality Factor:\n\n0 = lossless\n17-18 = visually lossless (compressed, but unnoticeable)\n23 = high quality\n51 = lowest quality possible"));
videobitrateSpinbox->setToolTip(tr("Quality Factor:\n\n0 = lossless\n17-18 = visually lossless (compressed, but unnoticeable)\n23 = high quality\n51 = lowest quality possible"));
break;
case COMPRESSION_TYPE_TARGETSIZE:
videoBitrateLabel->setText(tr("Target File Size (MB):"));
videoBitrateLabel->setText(tr("Target File Size (MB):"));
videobitrateSpinbox->setValue(100);
break;
}
@@ -601,57 +599,57 @@ void ExportDialog::comp_type_changed(int) {
void ExportDialog::setup_ui() {
QVBoxLayout* verticalLayout = new QVBoxLayout(this);
QHBoxLayout* format_layout = new QHBoxLayout();
QHBoxLayout* format_layout = new QHBoxLayout();
format_layout->addWidget(new QLabel(tr("Format:")));
format_layout->addWidget(new QLabel(tr("Format:")));
formatCombobox = new QComboBox(this);
format_layout->addWidget(formatCombobox);
format_layout->addWidget(formatCombobox);
verticalLayout->addLayout(format_layout);
verticalLayout->addLayout(format_layout);
QHBoxLayout* range_layout = new QHBoxLayout();
QHBoxLayout* range_layout = new QHBoxLayout();
range_layout->addWidget(new QLabel(tr("Range:")));
range_layout->addWidget(new QLabel(tr("Range:")));
rangeCombobox = new QComboBox(this);
rangeCombobox->addItem(tr("Entire Sequence"));
rangeCombobox->addItem(tr("In to Out"));
rangeCombobox->addItem(tr("Entire Sequence"));
rangeCombobox->addItem(tr("In to Out"));
range_layout->addWidget(rangeCombobox);
range_layout->addWidget(rangeCombobox);
verticalLayout->addLayout(range_layout);
verticalLayout->addLayout(range_layout);
videoGroupbox = new QGroupBox(this);
videoGroupbox->setTitle(tr("Video"));
videoGroupbox->setTitle(tr("Video"));
videoGroupbox->setFlat(false);
videoGroupbox->setCheckable(true);
QGridLayout* videoGridLayout = new QGridLayout(videoGroupbox);
videoGridLayout->addWidget(new QLabel(tr("Codec:")), 0, 0, 1, 1);
videoGridLayout->addWidget(new QLabel(tr("Codec:")), 0, 0, 1, 1);
vcodecCombobox = new QComboBox(videoGroupbox);
videoGridLayout->addWidget(vcodecCombobox, 0, 1, 1, 1);
videoGridLayout->addWidget(new QLabel(tr("Width:")), 1, 0, 1, 1);
videoGridLayout->addWidget(new QLabel(tr("Width:")), 1, 0, 1, 1);
widthSpinbox = new QSpinBox(videoGroupbox);
widthSpinbox->setMaximum(16777216);
videoGridLayout->addWidget(widthSpinbox, 1, 1, 1, 1);
videoGridLayout->addWidget(new QLabel(tr("Height:")), 2, 0, 1, 1);
videoGridLayout->addWidget(new QLabel(tr("Height:")), 2, 0, 1, 1);
heightSpinbox = new QSpinBox(videoGroupbox);
heightSpinbox->setMaximum(16777216);
videoGridLayout->addWidget(heightSpinbox, 2, 1, 1, 1);
videoGridLayout->addWidget(new QLabel(tr("Frame Rate:")), 3, 0, 1, 1);
videoGridLayout->addWidget(new QLabel(tr("Frame Rate:")), 3, 0, 1, 1);
framerateSpinbox = new QDoubleSpinBox(videoGroupbox);
framerateSpinbox->setMaximum(60);
framerateSpinbox->setValue(0);
videoGridLayout->addWidget(framerateSpinbox, 3, 1, 1, 1);
videoGridLayout->addWidget(new QLabel(tr("Compression Type:")), 4, 0, 1, 1);
compressionTypeCombobox = new QComboBox(videoGroupbox);
videoGridLayout->addWidget(new QLabel(tr("Compression Type:")), 4, 0, 1, 1);
compressionTypeCombobox = new QComboBox(videoGroupbox);
videoGridLayout->addWidget(compressionTypeCombobox, 4, 1, 1, 1);
videoBitrateLabel = new QLabel(videoGroupbox);
@@ -669,17 +667,17 @@ void ExportDialog::setup_ui() {
QGridLayout* audioGridLayout = new QGridLayout(audioGroupbox);
audioGridLayout->addWidget(new QLabel(tr("Codec:")), 0, 0, 1, 1);
audioGridLayout->addWidget(new QLabel(tr("Codec:")), 0, 0, 1, 1);
acodecCombobox = new QComboBox(audioGroupbox);
audioGridLayout->addWidget(acodecCombobox, 0, 1, 1, 1);
audioGridLayout->addWidget(new QLabel(tr("Sampling Rate:")), 1, 0, 1, 1);
audioGridLayout->addWidget(new QLabel(tr("Sampling Rate:")), 1, 0, 1, 1);
samplingRateSpinbox = new QSpinBox(audioGroupbox);
samplingRateSpinbox->setMaximum(96000);
samplingRateSpinbox->setValue(0);
audioGridLayout->addWidget(samplingRateSpinbox, 1, 1, 1, 1);
audioGridLayout->addWidget(new QLabel(tr("Bitrate (Kbps/CBR):")), 3, 0, 1, 1);
audioGridLayout->addWidget(new QLabel(tr("Bitrate (Kbps/CBR):")), 3, 0, 1, 1);
audiobitrateSpinbox = new QSpinBox(audioGroupbox);
audiobitrateSpinbox->setMaximum(320);
audiobitrateSpinbox->setValue(256);
+4 -19
View File
@@ -9,6 +9,7 @@
#include "playback/playback.h"
#include "playback/audio.h"
#include "dialogs/exportdialog.h"
#include "mainwindow.h"
#include "debug.h"
extern "C" {
@@ -111,7 +112,7 @@ bool ExportThread::setupVideo() {
vcodec_ctx->sample_aspect_ratio = {1, 1};
vcodec_ctx->pix_fmt = vcodec->pix_fmts[0]; // maybe be breakable code
vcodec_ctx->framerate = av_d2q(video_frame_rate, INT_MAX);
if (video_compression_type == COMPRESSION_TYPE_CBR) vcodec_ctx->bit_rate = video_bitrate * 1000000;
if (video_compression_type == COMPRESSION_TYPE_CBR) vcodec_ctx->bit_rate = qRound(video_bitrate * 1000000);
vcodec_ctx->time_base = av_inv_q(vcodec_ctx->framerate);
video_stream->time_base = vcodec_ctx->time_base;
@@ -312,12 +313,7 @@ bool ExportThread::setupContainer() {
void ExportThread::run() {
panel_sequence_viewer->pause();
if (!panel_sequence_viewer->viewer_widget->context()->makeCurrent(&surface)) {
qCritical() << "Make current failed";
ed->export_error = tr("could not make OpenGL context current");
return;
}
panel_sequence_viewer->seek(start_frame);
// copy filename
QByteArray ba = filename.toUtf8();
@@ -339,14 +335,9 @@ void ExportThread::run() {
}
}
panel_sequence_viewer->seek(start_frame);
panel_sequence_viewer->reset_all_audio();
QOpenGLFramebufferObject fbo(sequence->width, sequence->height, QOpenGLFramebufferObject::CombinedDepthStencil, GL_TEXTURE_RECTANGLE);
fbo.bind();
panel_sequence_viewer->viewer_widget->default_fbo = &fbo;
long file_audio_samples = 0;
qint64 start_time, frame_time, avg_time, eta, total_time = 0;
long remaining_frames, frame_count = 1;
@@ -415,8 +406,7 @@ void ExportThread::run() {
if (audio_enabled) apkt_alloc = true;
}
panel_sequence_viewer->viewer_widget->default_fbo = nullptr;
rendering = false;
mainWindow->set_rendering_state(false);
fbo.release();
@@ -478,9 +468,4 @@ void ExportThread::run() {
}
delete [] c_filename;
panel_sequence_viewer->viewer_widget->context()->doneCurrent();
panel_sequence_viewer->viewer_widget->context()->moveToThread(qApp->thread());
rendering = false;
}
+10 -1
View File
@@ -351,6 +351,15 @@ void MainWindow::load_css_from_file(const QString &fn) {
}
}
void MainWindow::set_rendering_state(bool rendering) {
audio_rendering = rendering;
if (rendering) {
autorecovery_timer.stop();
} else {
autorecovery_timer.start();
}
}
void MainWindow::show_about() {
AboutDialog a(this);
a.exec();
@@ -502,7 +511,7 @@ void MainWindow::new_project() {
}
void MainWindow::autorecover_interval() {
if (!rendering && isWindowModified()) {
if (isWindowModified()) {
panel_project->save_project(true);
qInfo() << "Auto-recovery project saved";
}
+3 -1
View File
@@ -23,7 +23,9 @@ public:
void load_shortcuts(const QString &fn, bool first = false);
void save_shortcuts(const QString &fn);
void load_css_from_file(const QString& fn);
void load_css_from_file(const QString& fn);
void set_rendering_state(bool rendering);
public slots:
void undo();
+2 -1
View File
@@ -29,6 +29,7 @@ bool audio_scrub = false;
QMutex audio_write_lock;
QAudioInput* audio_input = nullptr;
QFile output_recording;
bool audio_rendering = false;
bool recording = false;
qint8 audio_ibuffer[audio_ibuffer_size];
@@ -110,7 +111,7 @@ void clear_audio_ibuffer() {
}
int current_audio_freq() {
return rendering ? sequence->audio_frequency : audio_output->format().sampleRate();
return audio_rendering ? sequence->audio_frequency : audio_output->format().sampleRate();
}
int get_buffer_offset_from_frame(double framerate, long frame) {
+2 -1
View File
@@ -41,6 +41,8 @@ extern int audio_ibuffer_read;
extern long audio_ibuffer_frame;
extern double audio_ibuffer_timecode;
extern bool audio_scrub;
extern bool recording;
extern bool audio_rendering;
void clear_audio_ibuffer();
int current_audio_freq();
@@ -54,6 +56,5 @@ int get_buffer_offset_from_frame(double framerate, long frame);
bool start_recording();
void stop_recording();
QString get_recorded_audio_filename();
extern bool recording;
#endif // AUDIO_H
-2
View File
@@ -9,8 +9,6 @@ struct ClipCache;
struct Sequence;
struct AVFrame;
extern bool rendering;
long refactor_frame_number(long framenumber, double source_frame_rate, double target_frame_rate);
bool clip_uses_cacher(Clip* clip);
void open_clip(Clip* clip, bool multithreaded);
+4 -3
View File
@@ -118,7 +118,8 @@ GLuint compose_sequence(Viewer* viewer,
bool video,
bool render_audio,
Effect** gizmos,
bool& texture_failed) {
bool& texture_failed,
bool rendering) {
GLint current_fbo = 0;
if (video) {
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &current_fbo);
@@ -284,7 +285,7 @@ GLuint compose_sequence(Viewer* viewer,
// for nested sequences
if (c->media->get_type()== MEDIA_TYPE_SEQUENCE) {
nests.append(c);
textureID = compose_sequence(viewer, ctx, seq, nests, video, render_audio, gizmos, texture_failed);
textureID = compose_sequence(viewer, ctx, seq, nests, video, render_audio, gizmos, texture_failed, rendering);
nests.removeLast();
fbo_switcher = true;
}
@@ -455,7 +456,7 @@ GLuint compose_sequence(Viewer* viewer,
if (render_audio || (config.enable_audio_scrubbing && audio_scrub)) {
if (c->media != nullptr && c->media->get_type() == MEDIA_TYPE_SEQUENCE) {
nests.append(c);
compose_sequence(viewer, ctx, seq, nests, video, render_audio, gizmos, texture_failed);
compose_sequence(viewer, ctx, seq, nests, video, render_audio, gizmos, texture_failed, rendering);
nests.removeLast();
} else {
if (c->lock.tryLock()) {
+3 -1
View File
@@ -15,6 +15,8 @@ GLuint compose_sequence(Viewer* viewer,
QVector<Clip*>& nests,
bool video,
bool render_audio,
Effect **gizmos, bool &texture_failed);
Effect **gizmos,
bool &texture_failed,
bool rendering);
#endif // RENDERFUNCTIONS_H
+22 -10
View File
@@ -109,20 +109,33 @@ void RenderThread::paint() {
Effect* gizmos; // does nothing yet
QVector<Clip*> nests;
compose_sequence(nullptr, ctx, seq, nests, true, false, &gizmos, texture_failed);
compose_sequence(nullptr, ctx, seq, nests, true, false, &gizmos, texture_failed, false);
if (!save_fn.isEmpty()) {
if (texture_failed) {
// texture failed, try again
queued = true;
} else {
ctx->functions()->glBindFramebuffer(GL_READ_FRAMEBUFFER, frameBuffer);
QImage img(tex_width, tex_height, QImage::Format_RGBA8888);
glReadPixels(0, 0, tex_width, tex_height, GL_RGBA, GL_UNSIGNED_BYTE, img.bits());
img.mirrored(false, true).save(save_fn);
ctx->functions()->glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
save_fn = "";
}
}
glDisable(GL_DEPTH);
glDisable(GL_BLEND);
glDisable(GL_TEXTURE_2D);
}
void RenderThread::start_render(QOpenGLContext *share, Sequence *s, int idivider) {
if (s != seq && seq != nullptr) {
closeActiveClips(seq);
}
void RenderThread::start_render(QOpenGLContext *share, Sequence *s, const QString& save, int idivider) {
seq = s;
// stall any dependent actions
texture_failed = true;
if (share != nullptr && (ctx == nullptr || ctx->shareContext() != share_ctx)) {
share_ctx = share;
delete_ctx();
@@ -133,10 +146,9 @@ void RenderThread::start_render(QOpenGLContext *share, Sequence *s, int idivider
ctx->moveToThread(this);
}
if (seq != nullptr) {
queued = true;
waitCond.wakeAll();
}
save_fn = save;
queued = true;
waitCond.wakeAll();
}
bool RenderThread::did_texture_fail() {
+2 -1
View File
@@ -20,7 +20,7 @@ public:
GLuint frameBuffer;
GLuint texColorBuffer;
void paint();
void start_render(QOpenGLContext* share, Sequence* s, int idivider = 0);
void start_render(QOpenGLContext* share, Sequence* s, const QString &save = nullptr, int idivider = 0);
bool did_texture_fail();
void cancel();
signals:
@@ -42,6 +42,7 @@ private:
bool queued;
bool texture_failed;
bool running;
QString save_fn;
};
#endif // RENDERTHREAD_H
+10 -23
View File
@@ -23,7 +23,7 @@
#include "ui/timelinewidget.h"
#include "ui/renderfunctions.h"
#include "ui/renderthread.h"
#include "Ui/viewerwindow.h"
#include "ui/viewerwindow.h"
#include "mainwindow.h"
#include <QPainter>
@@ -50,7 +50,6 @@ extern "C" {
ViewerWidget::ViewerWidget(QWidget *parent) :
QOpenGLWidget(parent),
default_fbo(nullptr),
waveform(false),
waveform_zoom(1.0),
waveform_scroll(0),
@@ -84,7 +83,7 @@ ViewerWidget::~ViewerWidget() {
}
void ViewerWidget::delete_function() {
renderer->start_render(context(), nullptr);
closeActiveClips(viewer->seq);
}
void ViewerWidget::set_waveform_scroll(int s) {
@@ -149,22 +148,8 @@ void ViewerWidget::save_frame() {
if (!fn.endsWith(selected_ext, Qt::CaseInsensitive)) {
fn += selected_ext;
}
QOpenGLFramebufferObject fbo(viewer->seq->width, viewer->seq->height, QOpenGLFramebufferObject::CombinedDepthStencil, GL_TEXTURE_RECTANGLE);
rendering = true;
fbo.bind();
default_fbo = &fbo;
paintGL();
QImage img(viewer->seq->width, viewer->seq->height, QImage::Format_RGBA8888);
glReadPixels(0, 0, img.width(), img.height(), GL_RGBA, GL_UNSIGNED_BYTE, img.bits());
img.save(fn);
fbo.release();
default_fbo = nullptr;
rendering = false;
renderer->start_render(context(), viewer->seq, fn);
}
}
@@ -179,6 +164,8 @@ void ViewerWidget::fullscreen_menu_action(QAction *action) {
QScreen* selected_screen = QGuiApplication::screens().at(action->data().toInt());
window->showFullScreen();
window->setGeometry(selected_screen->geometry());
// HACK: window seems to show with distorted texture on first showing, so we queue an update after it's shown
QTimer::singleShot(100, window, SLOT(update()));
}
}
@@ -229,7 +216,7 @@ void ViewerWidget::frame_update() {
drawn_gizmos = false;
force_quit = false;
bool render_audio = (viewer->playing || rendering);
bool render_audio = (viewer->playing || audio_rendering);
// send context to other thread for drawing
doneCurrent();
@@ -238,7 +225,7 @@ void ViewerWidget::frame_update() {
// render the audio
QVector<Clip*> nests;
bool texture_failed;
compose_sequence(viewer, context(), viewer->seq, nests, false, render_audio, &gizmos, texture_failed);
compose_sequence(viewer, context(), viewer->seq, nests, false, render_audio, &gizmos, texture_failed, audio_rendering);
}
}
@@ -298,8 +285,8 @@ void ViewerWidget::move_gizmos(QMouseEvent *event, bool done) {
if (selected_gizmo != nullptr) {
double multiplier = double(viewer->seq->width) / double(width());
int x_movement = (event->pos().x() - drag_start_x)*multiplier;
int y_movement = (event->pos().y() - drag_start_y)*multiplier;
int x_movement = qRound((event->pos().x() - drag_start_x)*multiplier);
int y_movement = qRound((event->pos().y() - drag_start_y)*multiplier);
gizmos->gizmo_move(selected_gizmo, x_movement, y_movement, get_timecode(gizmos->parent_clip, gizmos->parent_clip->sequence->playhead), done);
@@ -479,7 +466,7 @@ void ViewerWidget::paintGL() {
// draw title/action safe area
if (config.show_title_safe_area && !rendering) {
if (config.show_title_safe_area) {
drawTitleSafeArea();
}
-2
View File
@@ -35,8 +35,6 @@ public:
Viewer* viewer;
ViewerContainer* container;
QOpenGLFramebufferObject* default_fbo;
bool waveform;
Clip* waveform_clip;
const FootageStream* waveform_ms;