91 std::unique_ptr<Grabber> result(
new Grabber(capture));
92 return result->init(screen) ?
std::move(result) :
nullptr;
97 std::unique_ptr<Grabber> result(
new Grabber(capture));
98 return result->init(wid) ?
std::move(result) :
nullptr;
111 Grabber(QX11SurfaceCapture &capture)
113 addFrameCallback(capture, &QX11SurfaceCapture::newVideoFrame);
114 connect(
this, &Grabber::errorUpdated, &capture, &QX11SurfaceCapture::updateError);
120 m_display.reset(XOpenDisplay(
nullptr));
123 updateError(QPlatformSurfaceCapture::InternalError,
124 QLatin1String(
"Cannot open X11 display"));
126 return m_display !=
nullptr;
131 if (
auto screen = QGuiApplication::primaryScreen())
132 setFrameRate(screen->refreshRate());
134 return createDisplay() && initWithXID(
static_cast<XID>(wid));
137 bool init(QScreen *screen)
140 updateError(QPlatformSurfaceCapture::NotFound, QLatin1String(
"Screen Not Found"));
144 if (!createDisplay())
147 auto screenNumber = screenNumberByName(m_display.get(), screen->name());
149 if (screenNumber < 0)
152 setFrameRate(screen->refreshRate());
154 return initWithXID(RootWindow(m_display.get(), screenNumber));
157 bool initWithXID(XID xid)
171 if (
std::exchange(m_attached,
false)) {
172 XShmDetach(m_display.get(), &m_shmInfo);
173 shmdt(m_shmInfo.shmaddr);
174 shmctl(m_shmInfo.shmid, IPC_RMID,
nullptr);
180 Q_ASSERT(!m_attached);
183 shmget(IPC_PRIVATE, m_xImage->bytes_per_line * m_xImage->height, IPC_CREAT | 0777);
185 if (m_shmInfo.shmid == -1)
188 m_shmInfo.readOnly =
false;
189 m_shmInfo.shmaddr = m_xImage->data = (
char *)shmat(m_shmInfo.shmid,
nullptr, 0);
191 m_attached = XShmAttach(m_display.get(), &m_shmInfo);
196 XWindowAttributes wndattr = {};
197 if (XGetWindowAttributes(m_display.get(), m_xid, &wndattr) == 0) {
198 updateError(QPlatformSurfaceCapture::CaptureFailed,
199 QLatin1String(
"Cannot get window attributes"));
210 if (!m_xImage || wndattr.width != m_xImage->width || wndattr.height != m_xImage->height
211 || wndattr.depth != m_xImage->depth || wndattr.visual->visualid != m_visualID) {
213 qCDebug(qLcX11SurfaceCapture) <<
"recreate ximage: " << wndattr.width << wndattr.height
214 << wndattr.depth << wndattr.visual->visualid;
219 m_visualID = wndattr.visual->visualid;
220 m_xImage.reset(XShmCreateImage(m_display.get(), wndattr.visual, wndattr.depth, ZPixmap,
221 nullptr, &m_shmInfo, wndattr.width, wndattr.height));
224 updateError(QPlatformSurfaceCapture::CaptureFailed,
225 QLatin1String(
"Cannot create image"));
229 const auto pixelFormat = xImagePixelFormat(*m_xImage);
232 if (pixelFormat == QVideoFrameFormat::Format_Invalid) {
233 updateError(QPlatformSurfaceCapture::CaptureFailed,
234 QLatin1String(
"Not handled pixel format, bpp=")
235 + QString::number(m_xImage->bits_per_pixel));
242 updateError(QPlatformSurfaceCapture::CaptureFailed,
243 QLatin1String(
"Cannot attach shared memory"));
247 QVideoFrameFormat format(QSize(m_xImage->width, m_xImage->height), pixelFormat);
248 format.setStreamFrameRate(frameRate());
261 if (!XShmGetImage(m_display.get(), m_xid, m_xImage.get(), m_xOffset, m_yOffset,
263 updateError(QPlatformSurfaceCapture::CaptureFailed,
265 "Cannot get ximage; the window may be out of the screen borders"));
269 QByteArray data(m_xImage->bytes_per_line * m_xImage->height, Qt::Uninitialized);
271 const auto pixelSrc =
reinterpret_cast<
const uint32_t *>(m_xImage->data);
272 const auto pixelDst =
reinterpret_cast<uint32_t *>(data.data());
273 const auto pixelCount = data.size() / 4;
274 const auto xImageAlphaVaries =
false;
276 qCopyPixelsWithAlphaMask(pixelDst, pixelSrc, pixelCount, m_format.pixelFormat(),
279 auto buffer = std::make_unique<QMemoryVideoBuffer>(data, m_xImage->bytes_per_line);
280 return QVideoFramePrivate::createFrame(std::move(buffer), m_format);
284 std::optional<QPlatformSurfaceCapture::Error> m_prevGrabberError;
288 std::unique_ptr<Display,
decltype(&XCloseDisplay)> m_display{
nullptr, &
XCloseDisplay };
289 std::unique_ptr<XImage,
decltype(&destroyXImage)> m_xImage{
nullptr, &
destroyXImage };
290 XShmSegmentInfo m_shmInfo;
291 bool m_attached =
false;
292 VisualID m_visualID = None;
293 QVideoFrameFormat m_format;