捕获QML绘图缓冲区,不显示

Dmi*_*try 7 opengl qt screen-capture qml qt5

我需要抓住每个QML(QtQuick 2)绘图框并通过网络发送它.目前我已经使用了下面列出的方法,但这种方法有两大缺点

1)由于Qt5文档,grabWindow()函数存在性能问题

2)它无法与隐藏的QML窗口一起使用

在QQuickWindow :: afterRendering之后可以立即获得OpenGL渲染缓冲区吗?使用FBO?共享opengl上下文?

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();
}
Run Code Online (Sandbox Code Playgroud)

Dmi*_*try 8

示例波纹管可以将任何qml内容抓取到FBO,然后通过信号将其作为图像发送.这种方法只有一个问题是可见性,抓取窗口必须是可见的才能成功抓取.如果有人知道如何防止这种情况,你可以帮助我并提供更高级的方法.

// 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());
  }
}
Run Code Online (Sandbox Code Playgroud)