Solved QML Desktop Streaming
-
Hi, I have the following problem: I need to capture part of the desktop, specifically of the second monitor, given an x, an y, the width and the height. My question is: is it possible to stream a part of desktop and show it inside a box in a qml project.
My first thought is to somehow find a c++ function that allows to do screenshot of my second monitor and after importing it inside qml I would call it like every 0.2 seconds with Timer to do screenshot and show it in a box in QML.Thank you.
-
You can use
QScreen::grabWindow
for that.To use that in QML, you could feed this in a
VideoOutput
.To do that you would have to put your
QObject
derived class instance as thesource
of theVideoOutput
: http://doc.qt.io/qt-5/qml-qtmultimedia-videooutput.html#source-prop
Your class needs to have aQ_PROPERTY(QAbstractVideoSurface* videoSurface READ videoSurface WRITE setVideoSurface NOTIFY videoSurfaceChange)
In your
setVideoSurface
method, you need to call thestart
method ofQAbstractVideoSurface
with a correct format (your size and the pixelformat, pixelformat should beQVideoFrame::Format_ARGB32
for desktop I guess).And then when you want to update the
VideoOutput
(via aQTimer
for example), you call thepresent
method ofQAbstractVideoSurface
with aQVideoFrame
you constructed from theQPixmap
you got inQScreen::grabWindow
. -
Thank you for the instructions, I'm new to all of this so I hope to get to the bottom of this :D
-
Hi, I need some help. I really don't have idea how to do it. This is what I have done so far:
videostream.h#ifndef VIDEOSTREAM_H #define VIDEOSTREAM_H #include <QObject> #include <QAbstractVideoSurface> class videoStream: public QObject { Q_OBJECT Q_PROPERTY(QAbstractVideoSurface* videoSurface READ videoSurface WRITE setVideoSurface NOTIFY videoSurfaceChange) public: explicit videoStream(QObject *parent = nullptr); QAbstractVideoSurface* videoSurface(); void setVideoSurface(const QAbstractVideoSurface &videoSurface); void updateScreen(); signals: void videoSurfaceChange(); private: QAbstractVideoSurface* m_videoSurface; }; #endif // VIDEOSTREAM_H
videoStream.cpp
#include "videostream.h" #include <QVideoSurfaceFormat> #include <QSize> #include <QGuiApplication> #include <QWidget> #include <QWindow> videoStream::videoStream(QObject *parent): QObject(parent) { } QAbstractVideoSurface* videoStream::videoSurface() { return m_videoSurface; } void videoStream::setVideoSurface(const QAbstractVideoSurface &videoSurface) { QVideoSurfaceFormat* qvideosurfaceformat; qvideosurfaceformat=new QVideoSurfaceFormat(QSize(800,600),QVideoFrame::Format_ARGB32); videoSurface.start(&qvideosurfaceformat); } void videoStream::updateScreen(){ QScreen *screen = QGuiApplication::primaryScreen(); if (QWindow *window = QWidget::windowHandle()) screen = window->QWindow::screen(); if (!screen) return; m_videoSurface->present(screen->grabWindow(0)); }
main.cpp
#include <QGuiApplication> #include <QQmlApplicationEngine> #include "videostream.h" int main(int argc, char *argv[]) { QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QGuiApplication app(argc, argv); qmlRegisterType<BackEnd>("videostream", 1, 0, "VideoStream"); QQmlApplicationEngine engine; engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); if (engine.rootObjects().isEmpty()) return -1; return app.exec(); }
main.qml
import QtQuick 2.9 import QtQuick.Window 2.2 import QtMultimedia 5.9 import videostream 1.0 Window { visible: true width: 640 height: 480 title: qsTr("Hello World") VideoStream{ id:video_stream } Rectangle { width: 800 height: 600 VideoOutput { id: videoOutput source: video_stream.videoStream anchors.fill: parent } } Timer { interval: 500; running: true; repeat: true onTriggered: video_stream.updateScreen } }
A part from errors with these lines
videoSurface.start(&qvideosurfaceformat); if (QWindow *window = QWidget::windowHandle()) m_videoSurface->present(screen->grabWindow(0));
I have no idea what should I do
-
Nevermind, thanks anyway. I simply solved it by using QScreen::grabWindow inside QQuickImageProvider and with a Timer inside QML I request and show the image every 33ms to have 30 frames per second of the screen.