92 std::unique_ptr<Grabber> result(
new Grabber(capture));
93 return result->init(screen) ?
std::move(result) :
nullptr;
98 std::unique_ptr<Grabber> result(
new Grabber(capture));
99 return result->init(wid) ?
std::move(result) :
nullptr;
112 Grabber(QX11SurfaceCapture &capture)
114 addFrameCallback(capture, &QX11SurfaceCapture::newVideoFrame);
115 connect(
this, &Grabber::errorUpdated, &capture, &QX11SurfaceCapture::updateError);
121 m_display.reset(XOpenDisplay(
nullptr));
124 updateError(QPlatformSurfaceCapture::InternalError,
125 QStringLiteral(
"Cannot open X11 display"));
127 return m_display !=
nullptr;
132 if (
auto screen = QGuiApplication::primaryScreen())
133 setFrameRate(screen->refreshRate());
135 return createDisplay() && initWithXID(
static_cast<XID>(wid));
138 bool init(QScreen *screen)
141 updateError(QPlatformSurfaceCapture::NotFound, QStringLiteral(
"Screen Not Found"));
145 if (!createDisplay())
148 auto screenNumber = screenNumberByName(m_display.get(), screen->name());
150 if (screenNumber < 0)
153 setFrameRate(screen->refreshRate());
155 return initWithXID(RootWindow(m_display.get(), screenNumber));
158 bool initWithXID(XID xid)
172 if (
std::exchange(m_attached,
false)) {
173 XShmDetach(m_display.get(), &m_shmInfo);
174 shmdt(m_shmInfo.shmaddr);
175 shmctl(m_shmInfo.shmid, IPC_RMID,
nullptr);
181 Q_ASSERT(!m_attached);
184 shmget(IPC_PRIVATE, m_xImage->bytes_per_line * m_xImage->height, IPC_CREAT | 0777);
186 if (m_shmInfo.shmid == -1)
189 m_shmInfo.readOnly =
false;
190 m_shmInfo.shmaddr = m_xImage->data = (
char *)shmat(m_shmInfo.shmid,
nullptr, 0);
192 m_attached = XShmAttach(m_display.get(), &m_shmInfo);
198 XWindowAttributes wndattr;
204 Visual *visual =
nullptr;
206 if (!XGetWindowAttributes(m_display.get(), win, &wndattr)) {
207 updateError(QPlatformSurfaceCapture::CaptureFailed,
208 QStringLiteral(
"Cannot get window attributes"));
212 width = wndattr.width;
213 height = wndattr.height;
214 depth = wndattr.depth;
215 visual = wndattr.visual;
217 if (win == wndattr.root)
222 Window root, *children;
223 unsigned int nchildren;
224 if (!XQueryTree(m_display.get(), win, &root, &win, &children, &nchildren)) {
225 updateError(QPlatformSurfaceCapture::CaptureFailed,
226 QStringLiteral(
"Cannot get parent window"));
229 if (children) XFree(children);
232 m_xOffset = qMax(0, -xPos);
233 m_yOffset = qMax(0, -yPos);
234 width = qMin(width, wndattr.width - xPos) - m_xOffset;
235 height = qMin(height, wndattr.height - yPos) - m_yOffset;
236 if (width <= 0 || height <= 0) {
237 updateError(QPlatformSurfaceCapture::CaptureFailed,
238 QStringLiteral(
"Window is completely out of the screen borders"));
244 if (!m_xImage || width != m_xImage->width || height != m_xImage->height
245 || depth != m_xImage->depth || visual->visualid != m_visualID) {
247 qCDebug(qLcX11SurfaceCapture) <<
"recreate ximage: " << width << height
248 << depth << visual->visualid;
253 m_visualID = wndattr.visual->visualid;
254 m_xImage.reset(XShmCreateImage(m_display.get(), visual, depth, ZPixmap,
255 nullptr, &m_shmInfo, width, height));
258 updateError(QPlatformSurfaceCapture::CaptureFailed,
259 QStringLiteral(
"Cannot create image"));
263 const auto pixelFormat = xImagePixelFormat(*m_xImage);
266 if (pixelFormat == QVideoFrameFormat::Format_Invalid) {
267 updateError(QPlatformSurfaceCapture::CaptureFailed,
268 QStringLiteral(
"Not handled pixel format, bpp=")
269 + QString::number(m_xImage->bits_per_pixel));
276 updateError(QPlatformSurfaceCapture::CaptureFailed,
277 QStringLiteral(
"Cannot attach shared memory"));
281 QVideoFrameFormat format(QSize(m_xImage->width, m_xImage->height), pixelFormat);
282 format.setStreamFrameRate(frameRate());
295 if (!XShmGetImage(m_display.get(), m_xid, m_xImage.get(), m_xOffset, m_yOffset,
297 updateError(QPlatformSurfaceCapture::CaptureFailed,
299 "Cannot get ximage; the window geometry may be undergoing change"));
303 QByteArray data(m_xImage->bytes_per_line * m_xImage->height, Qt::Uninitialized);
305 const auto pixelSrc =
reinterpret_cast<
const uint32_t *>(m_xImage->data);
306 const auto pixelDst =
reinterpret_cast<uint32_t *>(data.data());
307 const auto pixelCount = data.size() / 4;
308 const auto xImageAlphaVaries =
false;
310 qCopyPixelsWithAlphaMask(pixelDst, pixelSrc, pixelCount, m_format.pixelFormat(),
313 auto buffer = std::make_unique<QMemoryVideoBuffer>(data, m_xImage->bytes_per_line);
314 return QVideoFramePrivate::createFrame(std::move(buffer), m_format);
318 std::optional<QPlatformSurfaceCapture::Error> m_prevGrabberError;
322 std::unique_ptr<Display,
decltype(&XCloseDisplay)> m_display{
nullptr, &
XCloseDisplay };
323 std::unique_ptr<XImage,
decltype(&destroyXImage)> m_xImage{
nullptr, &
destroyXImage };
324 XShmSegmentInfo m_shmInfo;
325 bool m_attached =
false;
326 VisualID m_visualID = None;
327 QVideoFrameFormat m_format;