QML drawing buffer capture, no display

I need to capture every QML drawing frame (QtQuick 2) and send it over the network. At the moment, I used the method below, but this method has two big drawbacks

1) Due to the Qt5 documentation, the grabWindow () function has performance issues

2) It cannot work with a hidden QML window

Is it possible to get the OpenGL rendering buffer right after QQuickWindow :: afterRendering? Using TSF? General opengl context?

class Grab: public QObject { public: Grab( QQuickWindow * wnd ) : wnd_(wnd) {} public slots: void Grabme() { QImage image = wnd_->grabWindow(); } private: QQuickWindow *wnd_; }; int main(int argc, char *argv[]) { QGuiApplication app(argc, argv); QtQuick2ApplicationViewer viewer; viewer.setMainQmlFile(QStringLiteral("qml/grab1/main.qml")); viewer.showExpanded(); Grab grab( &viewer ); QObject::connect( &viewer, &QtQuick2ApplicationViewer::frameSwapped, &grab, &Grab::Grabme, Qt::DirectConnection ); return app.exec(); } 
+6
source share
2 answers

The example below can capture any qml content in FBO, and then send it as an image via a signal. Only one problem with this approach is visibility; the capture window must be visible for successful capture. If anyone knows how to prevent this, you can help me and provide a more advanced approach.

 // main.cpp int main(int argc, char* argv[]) { QApplication app(argc, argv); GrabWindow grab; grab.setResizeMode( QQuickView::SizeViewToRootObject ); grab.setSource( QUrl::fromLocalFile("qml/main.qml") ); grab.setFlags( Qt::Popup ); grab.show(); return app.exec(); } // grabwindow.hpp #pragma once #include <QOpenGLFramebufferObject> #include <QScopedPointer> #include <QQuickView> #include <QImage> class GrabWindow: public QQuickView { Q_OBJECT signals: void changeImage( const QImage &image ); public: GrabWindow( QWindow * parent = 0 ); private slots: void afterRendering(); void beforeRendering(); private: QScopedPointer<QOpenGLFramebufferObject> fbo_; }; // grabwindow.cpp #include "grabwindow.hpp" #include <limits> GrabWindow::GrabWindow( QWindow * parent ) : QQuickView( parent ) { setClearBeforeRendering( false ); setPosition( std::numeric_limits<unsigned short>::max(), std::numeric_limits<unsigned short>::max() ); connect( this, SIGNAL( afterRendering() ), SLOT( afterRendering() ), Qt::DirectConnection ); connect( this, SIGNAL( beforeRendering() ), SLOT( beforeRendering() ), Qt::DirectConnection ); } void GrabWindow::afterRendering() { if( !fbo_.isNull() ) { emit changeImage( fbo_->toImage() ); } } void GrabWindow::beforeRendering() { if (!fbo_) { fbo_.reset(new QOpenGLFramebufferObject( size(), QOpenGLFramebufferObject::NoAttachment) ); setRenderTarget(fbo_.data()); } } 
+8
source

I managed to find a trick to make grabWindow () work when the window is not visible. The trick is to set the window visibility: Window.Minimized and flags: Qt.Tool . The window is not displayed to the user, but for the internal elements of Qt, it seems to be visible, and a call to the grabWindow() method works as expected. Remember to call this method only after the scene has been initialized.

The only problem with this solution (which I came across) is that if the color property is set to color , then the captured content has a black background.

+2
source

Source: https://habr.com/ru/post/947464/


All Articles