Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qgrabwindowsurfacecapture.cpp
Go to the documentation of this file.
1// Copyright (C) 2022 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
4#include "qvideoframe.h"
6#include "qscreencapture.h"
8
9#include "private/qimagevideobuffer_p.h"
10#include "private/qcapturablewindow_p.h"
11
12#include "qscreen.h"
13#include "qmutex.h"
14#include "qwaitcondition.h"
15#include "qpixmap.h"
16#include "qguiapplication.h"
17#include "qwindow.h"
18#include "qpointer.h"
19
20#include <QtCore/qloggingcategory.h>
21
23
24namespace {
25
26using WindowUPtr = std::unique_ptr<QWindow>;
27
28} // namespace
29
31{
32public:
37
39 : Grabber(capture, nullptr, std::move(window))
40 {
41 Q_ASSERT(m_window);
42 }
43
44 ~Grabber() override {
45 stop();
46
47 Q_ASSERT(!m_screenRemovingLocked);
48 }
49
51 {
52 QMutexLocker locker(&m_formatMutex);
53 while (!m_format)
54 m_waitForFormat.wait(&m_formatMutex);
55 return *m_format;
56 }
57
58private:
61 QGuiApplication::platformName() == QLatin1String("eglfs")
64 m_capture(capture),
65 m_screen(screen),
66 m_window(std::move(window))
67 {
68 connect(qApp, &QGuiApplication::screenRemoved, this, &Grabber::onScreenRemoved);
71 }
72
73 void onScreenRemoved(QScreen *screen)
74 {
75 /* The hack allows to lock screens removing while QScreen::grabWindow is in progress.
76 * The current solution works since QGuiApplication::screenRemoved is emitted from
77 * the destructor of QScreen before destruction members of the object.
78 * Note, QGuiApplication works with screens in the main thread, and any removing of a screen
79 * must be synchronized with grabbing thread.
80 */
81 QMutexLocker locker(&m_screenRemovingMutex);
82
83 if (m_screenRemovingLocked) {
84 qDebug() << "Screen" << screen->name()
85 << "is removed while screen window grabbing lock is active";
86 }
87
88 while (m_screenRemovingLocked)
89 m_screenRemovingWc.wait(&m_screenRemovingMutex);
90 }
91
92 void setScreenRemovingLocked(bool locked)
93 {
94 Q_ASSERT(locked != m_screenRemovingLocked);
95
96 {
97 QMutexLocker locker(&m_screenRemovingMutex);
98 m_screenRemovingLocked = locked;
99 }
100
101 if (!locked)
102 m_screenRemovingWc.wakeAll();
103 }
104
105 void updateFormat(const QVideoFrameFormat &format)
106 {
107 if (m_format && m_format->isValid())
108 return;
109
110 {
111 QMutexLocker locker(&m_formatMutex);
112 m_format = format;
113 }
114
115 m_waitForFormat.wakeAll();
116 }
117
119 {
120 setScreenRemovingLocked(true);
121 auto screenGuard = qScopeGuard(std::bind(&Grabber::setScreenRemovingLocked, this, false));
122
123 WId wid = m_window ? m_window->winId() : 0;
124 QScreen *screen = m_window ? m_window->screen() : m_screen ? m_screen.data() : nullptr;
125
126 if (!screen) {
128 return {};
129 }
130
132
133 QPixmap p = screen->grabWindow(wid);
134 auto buffer = std::make_unique<QImageVideoBuffer>(p.toImage());
135 const auto img = buffer->underlyingImage();
136
139 format.setStreamFrameRate(screen->refreshRate());
140 updateFormat(format);
141
142 if (!format.isValid()) {
144 "Failed to grab the screen content");
145 return {};
146 }
147
148 return QVideoFrame(buffer.release(), format);
149 }
150
151private:
152 QGrabWindowSurfaceCapture &m_capture;
153 QPointer<QScreen> m_screen;
154 WindowUPtr m_window;
155
156 QMutex m_formatMutex;
157 QWaitCondition m_waitForFormat;
158 std::optional<QVideoFrameFormat> m_format;
159
160 QMutex m_screenRemovingMutex;
161 bool m_screenRemovingLocked = false;
162 QWaitCondition m_screenRemovingWc;
163};
164
169
171
173{
174 if (m_grabber)
175 return m_grabber->format();
176 else
177 return {};
178}
179
181{
182 if (active == static_cast<bool>(m_grabber))
183 return true;
184
185 if (m_grabber)
186 m_grabber.reset();
187 else
188 std::visit([this](auto source) { activate(source); }, source());
189
190 return static_cast<bool>(m_grabber) == active;
191}
192
193void QGrabWindowSurfaceCapture::activate(ScreenSource screen)
194{
196 return;
197
198 m_grabber = std::make_unique<Grabber>(*this, screen);
199 m_grabber->start();
200}
201
202void QGrabWindowSurfaceCapture::activate(WindowSource window)
203{
205 auto wid = handle ? handle->id : 0;
206 if (auto wnd = WindowUPtr(QWindow::fromWinId(wid))) {
207 if (!wnd->screen()) {
209 "Window " + QString::number(wid) + " doesn't belong to any screen");
210 } else {
211 m_grabber = std::make_unique<Grabber>(*this, std::move(wnd));
212 m_grabber->start();
213 }
214 } else {
216 "Window " + QString::number(wid) + "doesn't exist or permissions denied");
217 }
218}
219
static const QCapturableWindowPrivate * handle(const QCapturableWindow &window)
void errorUpdated(QPlatformSurfaceCapture::Error error, const QString &description)
void addFrameCallback(Object &object, Method method)
void updateError(QPlatformSurfaceCapture::Error error, const QString &description={})
Grabber(QGrabWindowSurfaceCapture &capture, WindowUPtr window)
Grabber(QGrabWindowSurfaceCapture &capture, QScreen *screen)
QGrabWindowSurfaceCapture(Source initialSource)
~QGrabWindowSurfaceCapture() override
bool setActiveInternal(bool active) override
QVideoFrameFormat frameFormat() const override
\macro qGuiApp
void screenRemoved(QScreen *screen)
This signal is emitted whenever a screen is removed from the system.
\inmodule QtCore
Definition qmutex.h:313
\inmodule QtCore
Definition qmutex.h:281
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2960
Returns a copy of the pixmap that is transformed using the given transformation transform and transfo...
Definition qpixmap.h:27
void updateError(Error error, const QString &errorString)
std::variant< ScreenSource, WindowSource > Source
bool checkScreenWithError(ScreenSource &screen)
void newVideoFrame(const QVideoFrame &)
T * data() const noexcept
Definition qpointer.h:73
The QScreen class is used to query screen properties. \inmodule QtGui.
Definition qscreen.h:32
QPixmap grabWindow(WId window=0, int x=0, int y=0, int w=-1, int h=-1)
Creates and returns a pixmap constructed by grabbing the contents of the given window restricted by Q...
Definition qscreen.cpp:685
qreal refreshRate
the approximate vertical refresh rate of the screen in Hz
Definition qscreen.h:64
QString name
a user presentable string representing the screen
Definition qscreen.h:36
static QString number(int, int base=10)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:8084
The QVideoFrameFormat class specifies the stream format of a video presentation surface.
static PixelFormat pixelFormatFromImageFormat(QImage::Format format)
Returns a video pixel format equivalent to an image format.
The QVideoFrame class represents a frame of video data.
Definition qvideoframe.h:27
bool wait(QMutex *, QDeadlineTimer=QDeadlineTimer(QDeadlineTimer::Forever))
Combined button and popup list for selecting options.
std::unique_ptr< QWindow > WindowUPtr
#define qApp
#define qDebug
[1]
Definition qlogging.h:164
GLuint64 GLenum void * handle
GLenum GLuint buffer
GLint GLsizei GLsizei GLenum format
GLsizei GLsizei GLchar * source
GLint void * img
Definition qopenglext.h:233
GLfloat GLfloat p
[1]
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
QScopeGuard< typename std::decay< F >::type > qScopeGuard(F &&f)
[qScopeGuard]
Definition qscopeguard.h:60
QScreen * screen
[1]
Definition main.cpp:29
QObject::connect nullptr
aWidget window() -> setWindowTitle("New Window Title")
[2]