93 std::unique_ptr<Grabber> result(
new Grabber(capture));
94 return result->init(screen) ?
std::move(result) :
nullptr;
99 std::unique_ptr<Grabber> result(
new Grabber(capture));
100 return result->init(wid) ?
std::move(result) :
nullptr;
115 addFrameCallback(&capture, &QX11SurfaceCapture::newVideoFrame);
116 connect(
this, &Grabber::errorUpdated, &capture, &QX11SurfaceCapture::updateError);
118 m_userFrameRate = capture.frameRate();
124 m_display.reset(XOpenDisplay(
nullptr));
127 updateError(QPlatformSurfaceCapture::InternalError,
128 QStringLiteral(
"Cannot open X11 display"));
130 return m_display !=
nullptr;
135 const auto defaultRate = QGuiApplication::primaryScreen()
136 ? qMin(QGuiApplication::primaryScreen()->refreshRate(),
137 DefaultScreenCaptureFrameRate)
138 : DefaultScreenCaptureFrameRate;
139 setFrameRate(m_userFrameRate.value_or(defaultRate));
141 return createDisplay() && initWithXID(
static_cast<XID>(wid));
144 bool init(QScreen *screen)
147 updateError(QPlatformSurfaceCapture::NotFound, QStringLiteral(
"Screen Not Found"));
151 if (!createDisplay())
154 auto screenNumber = screenNumberByName(m_display.get(), screen->name());
156 if (screenNumber < 0)
159 setFrameRate(m_userFrameRate.value_or(
160 qMin(screen->refreshRate(), DefaultScreenCaptureFrameRate)));
162 return initWithXID(RootWindow(m_display.get(), screenNumber));
165 bool initWithXID(XID xid)
179 if (
std::exchange(m_attached,
false)) {
180 XShmDetach(m_display.get(), &m_shmInfo);
181 shmdt(m_shmInfo.shmaddr);
182 shmctl(m_shmInfo.shmid, IPC_RMID,
nullptr);
188 Q_ASSERT(!m_attached);
191 shmget(IPC_PRIVATE, m_xImage->bytes_per_line * m_xImage->height, IPC_CREAT | 0777);
193 if (m_shmInfo.shmid == -1)
196 m_shmInfo.readOnly =
false;
197 m_shmInfo.shmaddr = m_xImage->data = (
char *)shmat(m_shmInfo.shmid,
nullptr, 0);
199 m_attached = XShmAttach(m_display.get(), &m_shmInfo);
205 XWindowAttributes wndattr;
211 Visual *visual =
nullptr;
213 if (!XGetWindowAttributes(m_display.get(), win, &wndattr)) {
214 updateError(QPlatformSurfaceCapture::CaptureFailed,
215 QStringLiteral(
"Cannot get window attributes"));
219 if (wndattr.map_state != IsViewable) {
220 updateError(QPlatformSurfaceCapture::CaptureFailed,
221 QStringLiteral(
"Window is not viewable"));
224 width = wndattr.width;
225 height = wndattr.height;
226 depth = wndattr.depth;
227 visual = wndattr.visual;
229 if (win == wndattr.root)
234 Window root, *children;
235 unsigned int nchildren;
236 if (!XQueryTree(m_display.get(), win, &root, &win, &children, &nchildren)) {
237 updateError(QPlatformSurfaceCapture::CaptureFailed,
238 QStringLiteral(
"Cannot get parent window"));
241 if (children) XFree(children);
244 m_xOffset = qMax(0, -xPos);
245 m_yOffset = qMax(0, -yPos);
246 width = qMin(width, wndattr.width - xPos) - m_xOffset;
247 height = qMin(height, wndattr.height - yPos) - m_yOffset;
248 if (width <= 0 || height <= 0) {
249 updateError(QPlatformSurfaceCapture::CaptureFailed,
250 QStringLiteral(
"Window is completely out of the screen borders"));
256 if (!m_xImage || width != m_xImage->width || height != m_xImage->height
257 || depth != m_xImage->depth || visual->visualid != m_visualID) {
259 qCDebug(qLcX11SurfaceCapture) <<
"recreate ximage: " << width << height
260 << depth << visual->visualid;
265 m_visualID = wndattr.visual->visualid;
266 m_xImage.reset(XShmCreateImage(m_display.get(), visual, depth, ZPixmap,
267 nullptr, &m_shmInfo, width, height));
270 updateError(QPlatformSurfaceCapture::CaptureFailed,
271 QStringLiteral(
"Cannot create image"));
275 const auto pixelFormat = xImagePixelFormat(*m_xImage);
278 if (pixelFormat == QVideoFrameFormat::Format_Invalid) {
279 updateError(QPlatformSurfaceCapture::CaptureFailed,
280 QStringLiteral(
"Not handled pixel format, bpp=")
281 + QString::number(m_xImage->bits_per_pixel));
288 updateError(QPlatformSurfaceCapture::CaptureFailed,
289 QStringLiteral(
"Cannot attach shared memory"));
293 QVideoFrameFormat format(QSize(m_xImage->width, m_xImage->height), pixelFormat);
294 format.setStreamFrameRate(frameRate());
307 QByteArray data(m_xImage->bytes_per_line * m_xImage->height, Qt::Uninitialized);
309 const auto pixelSrc =
reinterpret_cast<
const uint32_t *>(m_xImage->data);
310 const auto pixelDst =
reinterpret_cast<uint32_t *>(data.data());
311 const auto pixelCount = data.size() / 4;
312 const auto xImageAlphaVaries =
false;
314 qCopyPixelsWithAlphaMask(pixelDst, pixelSrc, pixelCount, m_format.pixelFormat(),
317 auto buffer = std::make_unique<QMemoryVideoBuffer>(data, m_xImage->bytes_per_line);
318 return QVideoFramePrivate::createFrame(std::move(buffer), m_format);
324 for (
int i = 0; i < 10; i++) {
327 if (XShmGetImage(m_display.get(), m_xid, m_xImage.get(),
328 m_xOffset, m_yOffset, AllPlanes))
332 updateError(QPlatformSurfaceCapture::CaptureFailed,
334 "Cannot get ximage; the window geometry may be undergoing change"));
338 std::optional<QPlatformSurfaceCapture::Error> m_prevGrabberError;
342 std::unique_ptr<Display,
decltype(&XCloseDisplay)> m_display{
nullptr, &
XCloseDisplay };
343 std::unique_ptr<XImage,
decltype(&destroyXImage)> m_xImage{
nullptr, &
destroyXImage };
344 XShmSegmentInfo m_shmInfo{};
345 bool m_attached =
false;
346 VisualID m_visualID = None;
347 QVideoFrameFormat m_format;
348 std::optional<qreal> m_userFrameRate;