Skip to content

Commit

Permalink
Add File > Export Frame...
Browse files Browse the repository at this point in the history
  • Loading branch information
ddennedy committed Jun 25, 2016
1 parent cf2c0ac commit 569faf7
Show file tree
Hide file tree
Showing 5 changed files with 110 additions and 1 deletion.
56 changes: 56 additions & 0 deletions src/glwidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
*/

#include <QtWidgets>
#include <QOpenGLFunctions_1_1>
#include <QOpenGLFunctions_3_2_Core>
#include <QUrl>
#include <QOffscreenSurface>
Expand Down Expand Up @@ -176,6 +177,7 @@ void GLWidget::initializeGL()
connect(m_frameRenderer, SIGNAL(textureReady(GLuint,GLuint,GLuint)), SLOT(updateTexture(GLuint,GLuint,GLuint)), Qt::DirectConnection);
else
connect(m_frameRenderer, SIGNAL(frameDisplayed(const SharedFrame&)), SLOT(onFrameDisplayed(const SharedFrame&)), Qt::QueuedConnection);
connect(m_frameRenderer, SIGNAL(imageReady()), SIGNAL(imageReady()));

m_initSem.release();
m_isInitialized = true;
Expand Down Expand Up @@ -680,6 +682,35 @@ QPoint GLWidget::offset() const
m_offset.y() - (MLT.profile().height() * m_zoom - height()) / 2);
}

QImage GLWidget::image() const
{
if (Settings.playerGPU()) {
return m_frameRenderer->image();
}
SharedFrame frame = m_frameRenderer->getDisplayFrame();
if (frame.is_valid()) {
int width = frame.get_image_width();
int height = frame.get_image_height();
QImage result(width, height, QImage::Format_ARGB32);
Mlt::Frame displayFrame(frame.clone(false, true));
mlt_image_format format = mlt_image_rgb24a;
const uchar *image = displayFrame.get_image(format, width, height);
if (image) {
QImage temp(width, height, QImage::Format_ARGB32);
memcpy(temp.scanLine(0), image, width * height * 4);
result = temp.rgbSwapped();
}
return result;
} else {
return QImage();
}
}

void GLWidget::requestImage() const
{
m_frameRenderer->requestImage();
}

void GLWidget::onFrameDisplayed(const SharedFrame &frame)
{
m_mutex.lock();
Expand Down Expand Up @@ -774,6 +805,7 @@ FrameRenderer::FrameRenderer(QOpenGLContext* shareContext, QSurface* surface)
, m_context(0)
, m_surface(surface)
, m_previousMSecs(QDateTime::currentMSecsSinceEpoch())
, m_imageRequested(false)
, m_gl32(0)
{
Q_ASSERT(shareContext);
Expand Down Expand Up @@ -844,6 +876,25 @@ void FrameRenderer::showFrame(Mlt::Frame frame)
#else
m_context->functions()->glFinish();
#endif // USE_GL_FENCE

if (m_imageRequested) {
m_imageRequested = false;
int imageSizeBytes = width * height * 4;
uchar* image = (uchar*) mlt_pool_alloc(imageSizeBytes);
QOpenGLFunctions_1_1* f = m_context->versionFunctions<QOpenGLFunctions_1_1>();

f->glBindTexture(GL_TEXTURE_2D, *textureId);
check_error(f);
f->glGetTexImage(GL_TEXTURE_2D, 0, GL_BGRA, GL_UNSIGNED_BYTE, image);
check_error(f);
f->glBindTexture(GL_TEXTURE_2D, 0);

m_image = QImage(width, height, QImage::Format_ARGB32);
memcpy(m_image.scanLine(0), image, imageSizeBytes);
mlt_pool_release(image);
emit imageReady();
}

emit textureReady(*textureId);
m_context->doneCurrent();

Expand Down Expand Up @@ -884,6 +935,11 @@ void FrameRenderer::showFrame(Mlt::Frame frame)
m_semaphore.release();
}

void FrameRenderer::requestImage()
{
m_imageRequested = true;
}

SharedFrame FrameRenderer::getDisplayFrame()
{
return m_displayFrame;
Expand Down
9 changes: 9 additions & 0 deletions src/glwidget.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ class GLWidget : public QQuickWidget, public Controller, protected QOpenGLFuncti
QRect rect() const { return m_rect; }
float zoom() const { return m_zoom * MLT.profile().width() / m_rect.width(); }
QPoint offset() const;
QImage image() const;
void requestImage() const;

public slots:
void onFrameDisplayed(const SharedFrame& frame);
Expand All @@ -103,6 +105,7 @@ public slots:
void rectChanged();
void zoomChanged();
void offsetChanged();
void imageReady();

private:
QRect m_rect;
Expand Down Expand Up @@ -172,13 +175,16 @@ class FrameRenderer : public QThread
QOpenGLContext* context() const { return m_context; }
SharedFrame getDisplayFrame();
Q_INVOKABLE void showFrame(Mlt::Frame frame);
void requestImage();
QImage image() const { return m_image; }

public slots:
void cleanup();

signals:
void textureReady(GLuint yName, GLuint uName = 0, GLuint vName = 0);
void frameDisplayed(const SharedFrame& frame);
void imageReady();

private:
QSemaphore m_semaphore;
Expand All @@ -187,6 +193,9 @@ public slots:
QOpenGLContext* m_context;
QSurface* m_surface;
qint64 m_previousMSecs;
bool m_imageRequested;
QImage m_image;

public:
GLuint m_renderTexture[3];
GLuint m_displayTexture[3];
Expand Down
35 changes: 35 additions & 0 deletions src/mainwindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3054,3 +3054,38 @@ void MainWindow::on_actionExportEDL_triggered()
}
}
}

void MainWindow::on_actionExportFrame_triggered()
{
if (Settings.playerGPU()) {
Mlt::GLWidget* glw = qobject_cast<Mlt::GLWidget*>(MLT.videoWidget());
connect(glw, SIGNAL(imageReady()), SLOT(onGLWidgetImageReady()));
glw->requestImage();
MLT.refreshConsumer();
} else {
onGLWidgetImageReady();
}
}

void MainWindow::onGLWidgetImageReady()
{
Mlt::GLWidget* glw = qobject_cast<Mlt::GLWidget*>(MLT.videoWidget());
QImage image = glw->image();
if (Settings.playerGPU())
disconnect(glw, SIGNAL(imageReady()), this, 0);
if (!image.isNull()) {
QString path = Settings.savePath();
path.append("/.png");
QString saveFileName = QFileDialog::getSaveFileName(this, tr("Export Frame"), path);
if (!saveFileName.isEmpty()) {
QFileInfo fi(saveFileName);
if (fi.suffix().isEmpty())
saveFileName += ".png";
image.save(saveFileName);
Settings.setSavePath(fi.path());
m_recentDock->add(saveFileName);
}
} else {
showStatusMessage(tr("Unable to export frame."));
}
}
2 changes: 2 additions & 0 deletions src/mainwindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,8 @@ private slots:
void on_actionPaste_triggered();
void onClipCopied();
void on_actionExportEDL_triggered();
void on_actionExportFrame_triggered();
void onGLWidgetImageReady();
};

#define MAIN MainWindow::singleton()
Expand Down
9 changes: 8 additions & 1 deletion src/mainwindow.ui
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
<x>0</x>
<y>0</y>
<width>832</width>
<height>21</height>
<height>22</height>
</rect>
</property>
<widget class="QMenu" name="menuFile">
Expand All @@ -53,6 +53,8 @@
<addaction name="actionSave"/>
<addaction name="actionSave_As"/>
<addaction name="actionExportEDL"/>
<addaction name="actionExportFrame"/>
<addaction name="separator"/>
<addaction name="actionClose"/>
<addaction name="separator"/>
<addaction name="actionExit"/>
Expand Down Expand Up @@ -799,6 +801,11 @@
<string>Export EDL...</string>
</property>
</action>
<action name="actionExportFrame">
<property name="text">
<string>Export Frame...</string>
</property>
</action>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources>
Expand Down

0 comments on commit 569faf7

Please sign in to comment.