9

各 QML (QtQuick 2) 描画フレームを取得し、ネットワーク経由で送信する必要があります。現時点では以下の方法を使用していますが、この方法には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();
}
4

3 に答える 3

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());
  }
}
于 2013-07-05T07:09:18.940 に答える
2

ウィンドウが「見えない」ときにgrabWindow()を機能させるトリックを見つけることができました。トリックは、ウィンドウvisibility: Window.Minimizedflags: Qt.Tool. ウィンドウはユーザーには表示されませんが、Qt の内部には表示されているように見え、grabWindow()メソッド呼び出しは期待どおりに機能します。シーンが初期化された後にのみ、そのメソッドを呼び出すことを忘れないでください。

このソリューションの唯一の問題 (私が遭遇した) は、ウィンドウのcolorプロパティが に設定されているtransparent場合、キャプチャされたコンテンツの背景が黒くなることです。

于 2014-05-22T17:43:31.847 に答える
1

Qt 5.X の以降のバージョンでは、ソフトウェア レンダー バックエンドも使用できます。次の例では、ウィンドウや OpenGL のトリックを表示せずに、バックグラウンドで任意のシーンをレンダリングします。

// main.cpp
#include <QGuiApplication>
#include <QQmlEngine>
#include <QQmlComponent>
#include <QQuickItem>
#include <QQuickWindow>
#include <QQuickRenderControl>

int main(int argc, char *argv[])
{
    const char *source = "qrc:/main.qml";
    if (argc > 1) source = argv[1];

    QQuickWindow::setSceneGraphBackend(QSGRendererInterface::Software);

    QGuiApplication app{argc, argv};

    QQuickRenderControl renderControl;

    QQuickWindow window{&renderControl};

    QQmlEngine engine;

    QQmlComponent component{
        &engine,
        QUrl{QString::fromUtf8(source)}
    };

    QQuickItem *rootItem = qobject_cast<QQuickItem *>(component.create());
    window.contentItem()->setSize(rootItem->size());
    rootItem->setParentItem(window.contentItem());

    window.resize(rootItem->size().width(), rootItem->size().height());

    QImage image = renderControl.grab();
    image.save("output.png");

    return 0;
}
于 2021-04-21T00:18:26.467 に答える