summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMikko Hallamaa <mikko.hallamaa@qt.io>2024-02-05 17:30:15 +0100
committerQt Cherry-pick Bot <cherrypick_bot@qt-project.org>2024-02-28 19:13:41 +0000
commiteca23f9e967d281b555f6eddfd53fc1771d63ec8 (patch)
tree154abaa51491a00244d33399fcfc59af2f05c6e2
parent85da55a3f636f69e90e1589425928ebfcf1d3153 (diff)
eglfs: Implement screen capture for Qt Quick applications on EGLFS
Added a dedicated grabber for screen capture on a Qt Quick application on the EGLFS platform, which calls QQuickWindow::grabWindow(). Task-number: QTBUG-121836 Fixes: QTBUG-121678 Pick-to: 6.6 6.5 Change-Id: Ia2e43e4f5de7357282c8eae91d5341f112d02155 Reviewed-by: Jøger Hansegård <joger.hansegard@qt.io> Reviewed-by: Artem Dyomin <artem.dyomin@qt.io> (cherry picked from commit 5d7920086eeb2ee0678e110251e2ec96bc2cdea4) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
-rw-r--r--src/plugins/multimedia/ffmpeg/CMakeLists.txt1
-rw-r--r--src/plugins/multimedia/ffmpeg/qeglfsscreencapture.cpp108
-rw-r--r--src/plugins/multimedia/ffmpeg/qeglfsscreencapture_p.h4
3 files changed, 92 insertions, 21 deletions
diff --git a/src/plugins/multimedia/ffmpeg/CMakeLists.txt b/src/plugins/multimedia/ffmpeg/CMakeLists.txt
index a8637f133..6132a68a2 100644
--- a/src/plugins/multimedia/ffmpeg/CMakeLists.txt
+++ b/src/plugins/multimedia/ffmpeg/CMakeLists.txt
@@ -204,6 +204,7 @@ qt_internal_extend_target(QFFmpegMediaPlugin CONDITION QT_FEATURE_eglfs
qeglfsscreencapture.cpp qeglfsscreencapture_p.h
LIBRARIES
Qt::OpenGLPrivate
+ Qt::Quick
)
set_source_files_properties(qx11surfacecapture.cpp qx11capturablewindows.cpp # X headers
diff --git a/src/plugins/multimedia/ffmpeg/qeglfsscreencapture.cpp b/src/plugins/multimedia/ffmpeg/qeglfsscreencapture.cpp
index 2f9ad1add..6ff02d055 100644
--- a/src/plugins/multimedia/ffmpeg/qeglfsscreencapture.cpp
+++ b/src/plugins/multimedia/ffmpeg/qeglfsscreencapture.cpp
@@ -10,6 +10,8 @@
#include <QtOpenGL/private/qopenglcompositor_p.h>
+#include <QtQuick/qquickwindow.h>
+
QT_BEGIN_NAMESPACE
class QEglfsScreenCapture::Grabber : public QFFmpegSurfaceCaptureGrabber
@@ -22,13 +24,13 @@ public:
connect(this, &Grabber::errorUpdated, &screenCapture, &QEglfsScreenCapture::updateError);
// Limit frame rate to 30 fps for performance reasons, to be reviewed at the next optimization round
setFrameRate(std::min(screen->refreshRate(), 30.0));
- start();
}
~Grabber() override { stop(); }
QVideoFrameFormat format() { return m_format; }
+protected:
QVideoFrame grabFrame() override
{
QOpenGLCompositor *compositor = QOpenGLCompositor::instance();
@@ -52,10 +54,46 @@ public:
return QVideoFrame(new QImageVideoBuffer(std::move(img)), m_format);
}
-private:
QVideoFrameFormat m_format;
};
+class QEglfsScreenCapture::QuickGrabber : public Grabber
+{
+public:
+ QuickGrabber(QEglfsScreenCapture &screenCapture, QScreen *screen, QQuickWindow *quickWindow)
+ : Grabber(screenCapture, screen), m_quickWindow(quickWindow)
+ {
+ Q_ASSERT(m_quickWindow);
+ }
+
+protected:
+ QVideoFrame grabFrame() override
+ {
+ if (!m_quickWindow) {
+ updateError(Error::InternalError, QLatin1String("Window deleted"));
+ return {};
+ }
+
+ QImage image = m_quickWindow->grabWindow();
+
+ if (image.isNull()) {
+ updateError(Error::InternalError, QLatin1String("Image invalid"));
+ return {};
+ }
+
+ if (!m_format.isValid()) {
+ m_format = { image.size(),
+ QVideoFrameFormat::pixelFormatFromImageFormat(image.format()) };
+ m_format.setFrameRate(frameRate());
+ }
+
+ return QVideoFrame(new QImageVideoBuffer(std::move(image)), m_format);
+ }
+
+private:
+ QPointer<QQuickWindow> m_quickWindow;
+};
+
QEglfsScreenCapture::QEglfsScreenCapture() : QPlatformSurfaceCapture(ScreenSource{}) { }
QEglfsScreenCapture::~QEglfsScreenCapture() = default;
@@ -72,30 +110,20 @@ bool QEglfsScreenCapture::setActiveInternal(bool active)
if (m_grabber)
m_grabber.reset();
- else {
- auto screen = source<ScreenSource>();
- if (!checkScreenWithError(screen))
- return false;
-
- QOpenGLCompositor *compositor = QOpenGLCompositor::instance();
- if (!compositor->context()) {
- updateError(Error::CaptureFailed, QLatin1String("OpenGL context is not found"));
- return false;
- }
- if (!compositor->targetWindow()) {
- updateError(Error::CaptureFailed, QLatin1String("Target window is not set for OpenGL compositor"));
- return false;
- }
+ if (!active)
+ return true;
- // TODO Add check to differentiate between uninitialized UI and QML
- // If UI not started, wait and try again, and then give error if still not started.
- // If QML, give not supported error for now.
+ m_grabber = createGrabber();
- m_grabber = std::make_unique<Grabber>(*this, screen);
+ if (!m_grabber) {
+ // TODO: This could mean that the UI is not started yet, so we should wait and try again,
+ // and then give error if still not started. Might not be possible here.
+ return false;
}
- return static_cast<bool>(m_grabber) == active;
+ m_grabber->start();
+ return true;
}
bool QEglfsScreenCapture::isSupported()
@@ -103,4 +131,42 @@ bool QEglfsScreenCapture::isSupported()
return QGuiApplication::platformName() == QLatin1String("eglfs");
}
+std::unique_ptr<QEglfsScreenCapture::Grabber> QEglfsScreenCapture::createGrabber()
+{
+ auto screen = source<ScreenSource>();
+ if (!checkScreenWithError(screen))
+ return nullptr;
+
+ QOpenGLCompositor *compositor = QOpenGLCompositor::instance();
+
+ if (compositor->context()) {
+ // Create OpenGL grabber
+ if (!compositor->targetWindow()) {
+ updateError(Error::CaptureFailed,
+ QLatin1String("Target window is not set for OpenGL compositor"));
+ return nullptr;
+ }
+
+ return std::make_unique<Grabber>(*this, screen);
+ }
+
+ // Check for QQuickWindow
+ auto windows = QGuiApplication::topLevelWindows();
+ auto it = std::find_if(windows.begin(), windows.end(), [screen](QWindow *window) {
+ auto quickWindow = qobject_cast<QQuickWindow *>(window);
+ if (!quickWindow)
+ return false;
+
+ return quickWindow->screen() == screen;
+ });
+
+ if (it != windows.end()) {
+ // Create grabber that calls QQuickWindow::grabWindow
+ return std::make_unique<QuickGrabber>(*this, screen, qobject_cast<QQuickWindow *>(*it));
+ }
+
+ updateError(Error::CaptureFailed, QLatin1String("No existing OpenGL context or QQuickWindow"));
+ return nullptr;
+}
+
QT_END_NAMESPACE
diff --git a/src/plugins/multimedia/ffmpeg/qeglfsscreencapture_p.h b/src/plugins/multimedia/ffmpeg/qeglfsscreencapture_p.h
index bbef78428..3bc92c234 100644
--- a/src/plugins/multimedia/ffmpeg/qeglfsscreencapture_p.h
+++ b/src/plugins/multimedia/ffmpeg/qeglfsscreencapture_p.h
@@ -37,6 +37,10 @@ private:
private:
class Grabber;
+ class QuickGrabber;
+
+ std::unique_ptr<Grabber> createGrabber();
+
std::unique_ptr<Grabber> m_grabber;
};