diff --git a/io/exportthread.cpp b/io/exportthread.cpp index bd4de4ba8..dbe139642 100644 --- a/io/exportthread.cpp +++ b/io/exportthread.cpp @@ -6,6 +6,7 @@ #include "panels/timeline.h" #include "panels/viewer.h" #include "ui/viewerwidget.h" +#include "ui/renderthread.h" #include "playback/playback.h" #include "playback/audio.h" #include "dialogs/exportdialog.h" @@ -335,23 +336,24 @@ void ExportThread::run() { } } - QOpenGLFramebufferObject fbo(sequence->width, sequence->height, QOpenGLFramebufferObject::CombinedDepthStencil, GL_TEXTURE_RECTANGLE); - fbo.bind(); - long file_audio_samples = 0; qint64 start_time, frame_time, avg_time, eta, total_time = 0; long remaining_frames, frame_count = 1; + RenderThread* renderer = panel_sequence_viewer->viewer_widget->get_renderer(); + disconnect(renderer, SIGNAL(ready()), panel_sequence_viewer->viewer_widget, SLOT(queue_repaint())); + connect(renderer, SIGNAL(ready()), this, SLOT(wake())); + + mutex.lock(); + while (sequence->playhead <= end_frame && continueEncode) { start_time = QDateTime::currentMSecsSinceEpoch(); - panel_sequence_viewer->viewer_widget->paintGL(); + renderer->start_render(nullptr, sequence, nullptr, video_frame->data[0]); + waitCond.wait(&mutex); double timecode_secs = (double) (sequence->playhead-start_frame) / sequence->frame_rate; if (video_enabled) { - // get image from opengl - glReadPixels(0, 0, video_frame->linesize[0]/4, sequence->height, GL_RGBA, GL_UNSIGNED_BYTE, video_frame->data[0]); - // change pixel format sws_scale(sws_ctx, video_frame->data, video_frame->linesize, 0, video_frame->height, sws_frame->data, sws_frame->linesize); sws_frame->pts = qRound(timecode_secs/av_q2d(video_stream->time_base)); @@ -396,11 +398,16 @@ void ExportThread::run() { // qInfo() << "Encoded frame" << sequence->playhead << "- took" << frame_time << "ms (avg:" << avg_time << "ms, remaining:" << remaining_frames << ", ETA:" << eta << ")"; - emit progress_changed(qRound(((double) (sequence->playhead-start_frame) / (double) (end_frame-start_frame)) * 100), eta); + emit progress_changed(qRound((double(sequence->playhead-start_frame) / double(end_frame-start_frame)) * 100.0), eta); sequence->playhead++; frame_count++; } + disconnect(renderer, SIGNAL(ready()), this, SLOT(wake())); + connect(renderer, SIGNAL(ready()), panel_sequence_viewer->viewer_widget, SLOT(queue_repaint())); + + mutex.unlock(); + if (continueEncode) { if (video_enabled) vpkt_alloc = true; if (audio_enabled) apkt_alloc = true; @@ -408,8 +415,6 @@ void ExportThread::run() { mainWindow->set_rendering_state(false); - fbo.release(); - if (audio_enabled && continueEncode) { // flush swresample do { @@ -469,3 +474,7 @@ void ExportThread::run() { delete [] c_filename; } + +void ExportThread::wake() { + waitCond.wakeAll(); +} diff --git a/io/exportthread.h b/io/exportthread.h index 0710343db..8e4fc085f 100644 --- a/io/exportthread.h +++ b/io/exportthread.h @@ -3,6 +3,8 @@ #include #include +#include +#include class ExportDialog; struct AVFormatContext; @@ -52,19 +54,21 @@ public: bool continueEncode; signals: void progress_changed(int value, qint64 remaining_ms); +private slots: + void wake(); private: bool encode(AVFormatContext* ofmt_ctx, AVCodecContext* codec_ctx, AVFrame* frame, AVPacket* packet, AVStream* stream, bool rescale); bool setupVideo(); bool setupAudio(); bool setupContainer(); - AVFormatContext* fmt_ctx; + AVFormatContext* fmt_ctx; AVStream* video_stream; AVCodec* vcodec; AVCodecContext* vcodec_ctx; AVFrame* video_frame; AVFrame* sws_frame; - SwsContext* sws_ctx; + SwsContext* sws_ctx; AVStream* audio_stream; AVCodec* acodec; AVFrame* audio_frame; @@ -72,14 +76,17 @@ private: AVCodecContext* acodec_ctx; AVPacket video_pkt; AVPacket audio_pkt; - SwrContext* swr_ctx; + SwrContext* swr_ctx; - bool vpkt_alloc; - bool apkt_alloc; + bool vpkt_alloc; + bool apkt_alloc; int aframe_bytes; int ret; char* c_filename; + + QMutex mutex; + QWaitCondition waitCond; }; #endif // EXPORTTHREAD_H diff --git a/ui/renderthread.cpp b/ui/renderthread.cpp index 21dc7dbd4..eca133588 100644 --- a/ui/renderthread.cpp +++ b/ui/renderthread.cpp @@ -125,12 +125,19 @@ void RenderThread::paint() { } } + if (pixel_buffer != nullptr) { + ctx->functions()->glBindFramebuffer(GL_READ_FRAMEBUFFER, frameBuffer); + glReadPixels(0, 0, tex_width, tex_height, GL_RGBA, GL_UNSIGNED_BYTE, pixel_buffer); + ctx->functions()->glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); + pixel_buffer = nullptr; + } + glDisable(GL_DEPTH); glDisable(GL_BLEND); glDisable(GL_TEXTURE_2D); } -void RenderThread::start_render(QOpenGLContext *share, Sequence *s, const QString& save, int idivider) { +void RenderThread::start_render(QOpenGLContext *share, Sequence *s, const QString& save, GLvoid* pixels, int idivider) { seq = s; // stall any dependent actions @@ -147,6 +154,8 @@ void RenderThread::start_render(QOpenGLContext *share, Sequence *s, const QStrin } save_fn = save; + pixel_buffer = pixels; + queued = true; waitCond.wakeAll(); } diff --git a/ui/renderthread.h b/ui/renderthread.h index bc94e48b9..3f88ba026 100644 --- a/ui/renderthread.h +++ b/ui/renderthread.h @@ -20,7 +20,7 @@ public: GLuint frameBuffer; GLuint texColorBuffer; void paint(); - void start_render(QOpenGLContext* share, Sequence* s, const QString &save = nullptr, int idivider = 0); + void start_render(QOpenGLContext* share, Sequence* s, const QString &save = nullptr, GLvoid *pixels = nullptr, int idivider = 0); bool did_texture_fail(); void cancel(); signals: @@ -43,6 +43,7 @@ private: bool texture_failed; bool running; QString save_fn; + GLvoid *pixel_buffer; }; #endif // RENDERTHREAD_H diff --git a/ui/viewerwidget.cpp b/ui/viewerwidget.cpp index 8f7216247..c5ce7e080 100644 --- a/ui/viewerwidget.cpp +++ b/ui/viewerwidget.cpp @@ -229,6 +229,10 @@ void ViewerWidget::frame_update() { } } +RenderThread *ViewerWidget::get_renderer() { + return renderer; +} + //void ViewerWidget::resizeGL(int w, int h) //{ //} diff --git a/ui/viewerwidget.h b/ui/viewerwidget.h index 43bcc9714..3f7cb964b 100644 --- a/ui/viewerwidget.h +++ b/ui/viewerwidget.h @@ -44,6 +44,7 @@ public: bool force_quit; void frame_update(); + RenderThread* get_renderer(); public slots: void set_waveform_scroll(int s); protected: