Browse Source

Include the cursor in X11 stream frames by default

stream-multiview
evgeny 6 days ago
parent
commit
5753177f29
  1. 31
      tools/chatgui/src/stream_publish_engine.cpp
  2. 2
      tools/chatgui/src/stream_publish_engine.h
  3. 1
      tools/chatgui/src/stream_screen_cursor.h

31
tools/chatgui/src/stream_publish_engine.cpp

@ -31,6 +31,9 @@ extern "C" {
#include <QWindowCapture>
#include <QVideoFrame>
#endif
#ifdef UTUN_STREAM_X11_CURSOR
#include "stream_screen_cursor.h"
#endif
namespace {
int64_t monotonicUs() { return std::chrono::duration_cast<std::chrono::microseconds>(
@ -75,6 +78,9 @@ struct StreamPublishEngine::Impl {
std::unique_ptr<QCamera> camera;
std::unique_ptr<QScreenCapture> screen;
std::unique_ptr<QTimer> screenGrabTimer;
#ifdef UTUN_STREAM_X11_CURSOR
std::unique_ptr<StreamScreenCursor> cursor;
#endif
std::unique_ptr<QWindowCapture> window;
QVideoFrame frame;
QVideoFrame previewFrame;
@ -141,6 +147,13 @@ QVariant StreamPublishEngine::previewFrame() const {
#endif
}
QList<int> StreamPublishEngine::codecs() const { std::lock_guard<std::mutex> guard(m->lock); return m->codecs; }
bool StreamPublishEngine::cursorSupported(const StreamVideoSource& source) {
#ifdef UTUN_STREAM_X11_CURSOR
return source.kind == StreamVideoSource::Screen && source.screen && source.id != "portal" && QGuiApplication::platformName() == "xcb";
#else
Q_UNUSED(source); return false;
#endif
}
bool StreamPublishEngine::muted() const { return m->muted.load(); }
void StreamPublishEngine::setMuted(bool muted) {
if (!m->running || !config().audio) {
@ -256,6 +269,9 @@ bool StreamPublishEngine::openSource(const StreamPublishConfig& config) {
}
// Qt X11 screen capture ищет root по имени и путает мониторы; QScreen захватывает именно выбранный экран.
if (selected && QGuiApplication::platformName() == "xcb") {
#ifdef UTUN_STREAM_X11_CURSOR
m->cursor = std::make_unique<StreamScreenCursor>(selected);
#endif
m->screenGrabTimer = std::make_unique<QTimer>(); m->screenGrabTimer->setTimerType(Qt::PreciseTimer);
connect(m->screenGrabTimer.get(), &QTimer::timeout, this, [this, generation, screen = QPointer<QScreen>(selected), failed] {
if (generation != m->sourceGeneration || !m->running) return;
@ -266,6 +282,12 @@ bool StreamPublishEngine::openSource(const StreamPublishConfig& config) {
m->screenGrabTimer->stop();
QMetaObject::invokeMethod(this, [failed] { failed(text("Video capture stopped")); }); return;
}
#ifdef UTUN_STREAM_X11_CURSOR
if (this->config().showCursor && !m->cursor->draw(image)) {
m->screenGrabTimer->stop();
QMetaObject::invokeMethod(this, [failed] { failed(text("Could not capture the mouse cursor")); }); return;
}
#endif
#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
QVideoFrame frame(image);
#else
@ -284,8 +306,8 @@ bool StreamPublishEngine::openSource(const StreamPublishConfig& config) {
frame.setStartTime(captured); m->sink->setVideoFrame(frame);
});
m->screenGrabTimer->start(std::max(1, 1000 / std::clamp(config.video.fps, 1, 60)));
DEBUG_INFO(DEBUG_CATEGORY_VIDEO, "desktop X11 screen grab started source=%s interval_ms=%d",
qPrintable(config.source.name), m->screenGrabTimer->interval());
DEBUG_INFO(DEBUG_CATEGORY_VIDEO, "desktop X11 screen grab started source=%s interval_ms=%d cursor=%d supported=%d",
qPrintable(config.source.name), m->screenGrabTimer->interval(), config.showCursor, cursorSupported(config.source));
} else {
m->screen = std::make_unique<QScreenCapture>();
m->screen->setScreen(selected);
@ -318,6 +340,9 @@ bool StreamPublishEngine::openSource(const StreamPublishConfig& config) {
void StreamPublishEngine::closeSource() {
#ifdef HAVE_STREAM_CAPTURE
m->screenGrabTimer.reset();
#ifdef UTUN_STREAM_X11_CURSOR
m->cursor.reset();
#endif
emit previewVideoChanged(QVariant());
if (m->sink) disconnect(m->sink.get(), nullptr, this, nullptr);
if (m->camera) { disconnect(m->camera.get(), nullptr, this, nullptr); m->camera->stop(); }
@ -367,6 +392,8 @@ bool StreamPublishEngine::reconfigure(const StreamPublishConfig& config) {
DEBUG_WARN(DEBUG_CATEGORY_STREAM, "desktop microphone selection changed during live publication");
emit errorOccurred(text("Change the microphone before starting the stream")); return false;
}
if (config.showCursor != previous.showCursor)
DEBUG_INFO(DEBUG_CATEGORY_VIDEO, "desktop cursor selected enabled=%d supported=%d", config.showCursor, cursorSupported(config.source));
bool sourceChange = !config.source.sameSource(previous.source) || (config.source.kind == StreamVideoSource::Camera
&& (config.video.width != previous.video.width || config.video.height != previous.video.height || config.video.fps != previous.video.fps));
{ std::lock_guard<std::mutex> guard(m->lock); m->wanted = config; m->generation++; m->started = monotonicUs();

2
tools/chatgui/src/stream_publish_engine.h

@ -34,6 +34,7 @@ struct StreamPublishConfig {
LiveVideoConfig video;
QString microphone;
bool audio = true;
bool showCursor = true;
bool nativeSize = false, automaticBitrate = false;
};
class StreamPublishEngine : public QObject {
@ -52,6 +53,7 @@ public:
QList<int> codecs() const;
static QList<StreamVideoSource> sources();
static bool supported();
static bool cursorSupported(const StreamVideoSource& source);
void setMuted(bool muted);
bool muted() const;
signals:

1
tools/chatgui/src/stream_screen_cursor.h

@ -6,6 +6,7 @@
#include <QScreen>
#include <QWindow>
struct _XDisplay;
class StreamScreenCursor {
public:
explicit StreamScreenCursor(QScreen* screen);

Loading…
Cancel
Save