Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qeglfsscreencapture.cpp
Go to the documentation of this file.
1// Copyright (C) 2023 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
5
9#include "private/qimagevideobuffer_p.h"
10#include "private/qvideoframe_p.h"
11
12#include <QtOpenGL/private/qopenglcompositor_p.h>
13#include <QtOpenGL/private/qopenglframebufferobject_p.h>
14
15#ifndef QT_NO_QUICK
16#include <QtQuick/qquickwindow.h>
17#endif
18
20
21class QEglfsScreenCapture::Grabber : public QFFmpegSurfaceCaptureGrabber
22{
23public:
24 Grabber(QEglfsScreenCapture &screenCapture, QScreen *screen)
26 {
27 addFrameCallback(screenCapture, &QEglfsScreenCapture::newVideoFrame);
28 connect(this, &Grabber::errorUpdated, &screenCapture, &QEglfsScreenCapture::updateError);
29 // Limit frame rate to 30 fps for performance reasons,
30 // to be reviewed at the next optimization round
31 setFrameRate(std::min(screen->refreshRate(), qreal(30.0)));
32 }
33
35
36 QVideoFrameFormat format() { return m_format; }
37
38protected:
40 {
41 auto nativeSize = QOpenGLCompositor::instance()->nativeTargetGeometry().size();
42 auto fbo = std::make_unique<QOpenGLFramebufferObject>(nativeSize);
43
44 if (!QOpenGLCompositor::instance()->grabToFrameBufferObject(
45 fbo.get(), QOpenGLCompositor::NotFlipped)) {
46 updateError(Error::InternalError, QLatin1String("Couldn't grab to framebuffer object"));
47 return {};
48 }
49
50 if (!fbo->isValid()) {
51 updateError(Error::InternalError, QLatin1String("Framebuffer object invalid"));
52 return {};
53 }
54
55 auto videoBuffer = std::make_unique<QOpenGLVideoBuffer>(std::move(fbo));
56
57 if (!m_format.isValid()) {
58 auto image = videoBuffer->ensureImageBuffer().underlyingImage();
59 m_format = { image.size(), QVideoFrameFormat::pixelFormatFromImageFormat(image.format()) };
60 m_format.setStreamFrameRate(frameRate());
61 }
62
63 return QVideoFramePrivate::createFrame(std::move(videoBuffer), m_format);
64 }
65
67};
68
69#ifndef QT_NO_QUICK
70class QEglfsScreenCapture::QuickGrabber : public Grabber
71{
72public:
73 QuickGrabber(QEglfsScreenCapture &screenCapture, QScreen *screen, QQuickWindow *quickWindow)
74 : Grabber(screenCapture, screen), m_quickWindow(quickWindow)
75 {
76 Q_ASSERT(m_quickWindow);
77 }
78
79protected:
81 {
82 if (!m_quickWindow) {
83 updateError(Error::InternalError, QLatin1String("Window deleted"));
84 return {};
85 }
86
87 QImage image = m_quickWindow->grabWindow();
88
89 if (image.isNull()) {
90 updateError(Error::InternalError, QLatin1String("Image invalid"));
91 return {};
92 }
93
94 if (!m_format.isValid()) {
95 m_format = { image.size(),
96 QVideoFrameFormat::pixelFormatFromImageFormat(image.format()) };
97 m_format.setStreamFrameRate(frameRate());
98 }
99
100 return QVideoFramePrivate::createFrame(
101 std::make_unique<QImageVideoBuffer>(std::move(image)), m_format);
102 }
103
104private:
105 QPointer<QQuickWindow> m_quickWindow;
106};
107#endif // QT_NO_QUICK
108
109QEglfsScreenCapture::QEglfsScreenCapture() : QPlatformSurfaceCapture(ScreenSource{}) { }
110
111QEglfsScreenCapture::~QEglfsScreenCapture() = default;
112
113QVideoFrameFormat QEglfsScreenCapture::frameFormat() const
114{
115 return m_grabber ? m_grabber->format() : QVideoFrameFormat();
116}
117
118bool QEglfsScreenCapture::setActiveInternal(bool active)
119{
120 if (static_cast<bool>(m_grabber) == active)
121 return true;
122
123 if (m_grabber)
124 m_grabber.reset();
125
126 if (!active)
127 return true;
128
129 m_grabber = createGrabber();
130
131 if (!m_grabber) {
132 // TODO: This could mean that the UI is not started yet, so we should wait and try again,
133 // and then give error if still not started. Might not be possible here.
134 return false;
135 }
136
137 m_grabber->start();
138 return true;
139}
140
141bool QEglfsScreenCapture::isSupported()
142{
143 return QGuiApplication::platformName() == QLatin1String("eglfs");
144}
145
146std::unique_ptr<QEglfsScreenCapture::Grabber> QEglfsScreenCapture::createGrabber()
147{
148 auto screen = source<ScreenSource>();
149 if (!checkScreenWithError(screen))
150 return nullptr;
151
152 QOpenGLCompositor *compositor = QOpenGLCompositor::instance();
153
154 if (compositor->context()) {
155 // Create OpenGL grabber
156 if (!compositor->targetWindow()) {
157 updateError(Error::CaptureFailed,
158 QLatin1String("Target window is not set for OpenGL compositor"));
159 return nullptr;
160 }
161
162 return std::make_unique<Grabber>(*this, screen);
163 }
164
165#ifndef QT_NO_QUICK
166 // Check for QQuickWindow
167 auto windows = QGuiApplication::topLevelWindows();
168 auto it = std::find_if(windows.begin(), windows.end(), [screen](QWindow *window) {
169 auto quickWindow = qobject_cast<QQuickWindow *>(window);
170 if (!quickWindow)
171 return false;
172
173 return quickWindow->screen() == screen;
174 });
175
176 if (it != windows.end()) {
177 // Create grabber that calls QQuickWindow::grabWindow
178 return std::make_unique<QuickGrabber>(*this, screen, qobject_cast<QQuickWindow *>(*it));
179 }
180#endif // QT_NO_QUICK
181
182 updateError(Error::CaptureFailed, QLatin1String("No existing OpenGL context or QQuickWindow"));
183 return nullptr;
184}
185
186QT_END_NAMESPACE
Grabber(QEglfsScreenCapture &screenCapture, QScreen *screen)
QuickGrabber(QEglfsScreenCapture &screenCapture, QScreen *screen, QQuickWindow *quickWindow)