Qt 6.x
The Qt SDK
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/qabstractvideobuffer_p.h"
10
11#include "qscreen.h"
12#include "qmutex.h"
13#include "qwaitcondition.h"
14#include "qpixmap.h"
15#include "qguiapplication.h"
16#include "private/qcapturablewindow_p.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
29{
30public:
32 : QAbstractVideoBuffer(QVideoFrame::NoHandle), m_image(std::move(image))
33 {
34 }
35
36 QVideoFrame::MapMode mapMode() const override { return m_mapMode; }
37
39 {
41 if (m_mapMode == QVideoFrame::NotMapped && !m_image.isNull() && mode != QVideoFrame::NotMapped) {
42 m_mapMode = mode;
43
44 mapData.nPlanes = 1;
45 mapData.bytesPerLine[0] = m_image.bytesPerLine();
46 mapData.data[0] = m_image.bits();
47 mapData.size[0] = m_image.sizeInBytes();
48 }
49
50 return mapData;
51 }
52
53 void unmap() override
54 {
55 m_mapMode = QVideoFrame::NotMapped;
56 }
57
60};
61
62} // namespace
63
65{
66public:
68 {
70 }
71
73 : Grabber(capture, nullptr, std::move(window))
74 {
75 Q_ASSERT(m_window);
76 }
77
78 ~Grabber() override {
79 stop();
80
81 Q_ASSERT(!m_screenRemovingLocked);
82 }
83
85 {
86 QMutexLocker locker(&m_formatMutex);
87 while (!m_format)
88 m_waitForFormat.wait(&m_formatMutex);
89 return *m_format;
90 }
91
92private:
94 : m_capture(capture), m_screen(screen), m_window(std::move(window))
95 {
96 connect(qApp, &QGuiApplication::screenRemoved, this, &Grabber::onScreenRemoved);
99 }
100
101 void onScreenRemoved(QScreen *screen)
102 {
103 /* The hack allows to lock screens removing while QScreen::grabWindow is in progress.
104 * The current solution works since QGuiApplication::screenRemoved is emitted from
105 * the destructor of QScreen before destruction members of the object.
106 * Note, QGuiApplication works with screens in the main thread, and any removing of a screen
107 * must be synchronized with grabbing thread.
108 */
109 QMutexLocker locker(&m_screenRemovingMutex);
110
111 if (m_screenRemovingLocked) {
112 qDebug() << "Screen" << screen->name()
113 << "is removed while screen window grabbing lock is active";
114 }
115
116 while (m_screenRemovingLocked)
117 m_screenRemovingWc.wait(&m_screenRemovingMutex);
118 }
119
120 void setScreenRemovingLocked(bool locked)
121 {
122 Q_ASSERT(locked != m_screenRemovingLocked);
123
124 {
125 QMutexLocker locker(&m_screenRemovingMutex);
126 m_screenRemovingLocked = locked;
127 }
128
129 if (!locked)
130 m_screenRemovingWc.wakeAll();
131 }
132
133 void updateFormat(const QVideoFrameFormat &format)
134 {
135 if (m_format && m_format->isValid())
136 return;
137
138 {
139 QMutexLocker locker(&m_formatMutex);
140 m_format = format;
141 }
142
143 m_waitForFormat.wakeAll();
144 }
145
147 {
148 setScreenRemovingLocked(true);
149 auto screenGuard = qScopeGuard(std::bind(&Grabber::setScreenRemovingLocked, this, false));
150
151 WId wid = m_window ? m_window->winId() : 0;
152 QScreen *screen = m_window ? m_window->screen() : m_screen ? m_screen.data() : nullptr;
153
154 if (!screen) {
156 return {};
157 }
158
160
161 QPixmap p = screen->grabWindow(wid);
162 QImage img = p.toImage();
163
166 format.setFrameRate(screen->refreshRate());
167 updateFormat(format);
168
169 if (!format.isValid()) {
171 "Failed to grab the screen content");
172 return {};
173 }
174
175 return QVideoFrame(new QImageVideoBuffer(std::move(img)), format);
176 }
177
178private:
179 QGrabWindowSurfaceCapture &m_capture;
180 QPointer<QScreen> m_screen;
181 WindowUPtr m_window;
182
183 QMutex m_formatMutex;
184 QWaitCondition m_waitForFormat;
185 std::optional<QVideoFrameFormat> m_format;
186
187 QMutex m_screenRemovingMutex;
188 bool m_screenRemovingLocked = false;
189 QWaitCondition m_screenRemovingWc;
190};
191
193 : QPlatformSurfaceCapture(initialSource)
194{
195}
196
198
200{
201 if (m_grabber)
202 return m_grabber->format();
203 else
204 return {};
205}
206
208{
209 if (active == static_cast<bool>(m_grabber))
210 return true;
211
212 if (m_grabber)
213 m_grabber.reset();
214 else
215 std::visit([this](auto source) { activate(source); }, source());
216
217 return static_cast<bool>(m_grabber) == active;
218}
219
220void QGrabWindowSurfaceCapture::activate(ScreenSource screen)
221{
223 return;
224
225 m_grabber = std::make_unique<Grabber>(*this, screen);
226 m_grabber->start();
227}
228
229void QGrabWindowSurfaceCapture::activate(WindowSource window)
230{
232 auto wid = handle ? handle->id : 0;
233 if (auto wnd = WindowUPtr(QWindow::fromWinId(wid))) {
234 if (!wnd->screen()) {
236 "Window " + QString::number(wid) + " doesn't belong to any screen");
237 } else {
238 m_grabber = std::make_unique<Grabber>(*this, std::move(wnd));
239 m_grabber->start();
240 }
241 } else {
243 "Window " + QString::number(wid) + "doesn't exist or permissions denied");
244 }
245}
246
The QAbstractVideoBuffer class is an abstraction for video data. \inmodule QtMultimedia.
static const QCapturableWindowPrivate * handle(const QCapturableWindow &window)
void addFrameCallback(Object &object, Method method)
void errorUpdated(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
void screenRemoved(QScreen *screen)
This signal is emitted whenever a screen is removed from the system.
\inmodule QtGui
Definition qimage.h:37
\inmodule QtCore
Definition qmutex.h:317
\inmodule QtCore
Definition qmutex.h:285
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2823
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 &)
\inmodule QtCore
Definition qpointer.h:18
T * data() const
Definition qpointer.h:56
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:7822
void unmap() override
Releases the memory mapped by the map() function.
MapData map(QVideoFrame::MapMode mode) override
Independently maps the planes of a video buffer to memory.
QVideoFrame::MapMode mapMode() const override
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:26
MapMode
Enumerates how a video buffer's data is mapped to system memory.
Definition qvideoframe.h:36
bool wait(QMutex *, QDeadlineTimer=QDeadlineTimer(QDeadlineTimer::Forever))
Combined button and popup list for selecting options.
std::unique_ptr< QWindow > WindowUPtr
Definition image.cpp:4
#define qApp
#define qDebug
[1]
Definition qlogging.h:160
GLuint64 GLenum void * handle
GLenum mode
GLint GLsizei GLsizei GLenum format
GLsizei GLsizei GLchar * source
GLint void * img
Definition qopenglext.h:233
GLfloat GLfloat p
[1]
static QAbstractVideoBuffer::MapData mapData(const camera_frame_nv12_t &frame, unsigned char *baseAddress)
#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]