|
|
|
|
@ -34,6 +34,9 @@ extern "C" {
|
|
|
|
|
#ifdef UTUN_STREAM_X11_CURSOR |
|
|
|
|
#include "stream_screen_cursor.h" |
|
|
|
|
#endif |
|
|
|
|
#ifdef UTUN_STREAM_PORTAL |
|
|
|
|
#include "stream_portal_capture.h" |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
namespace { |
|
|
|
|
int64_t monotonicUs() { return std::chrono::duration_cast<std::chrono::microseconds>( |
|
|
|
|
@ -77,6 +80,9 @@ struct StreamPublishEngine::Impl {
|
|
|
|
|
std::unique_ptr<QVideoSink> sink; |
|
|
|
|
std::unique_ptr<QCamera> camera; |
|
|
|
|
std::unique_ptr<QScreenCapture> screen; |
|
|
|
|
#ifdef UTUN_STREAM_PORTAL |
|
|
|
|
std::unique_ptr<StreamPortalCapture> portal; |
|
|
|
|
#endif |
|
|
|
|
std::unique_ptr<QTimer> screenGrabTimer; |
|
|
|
|
#ifdef UTUN_STREAM_X11_CURSOR |
|
|
|
|
std::unique_ptr<StreamScreenCursor> cursor; |
|
|
|
|
@ -148,6 +154,9 @@ QVariant StreamPublishEngine::previewFrame() const {
|
|
|
|
|
} |
|
|
|
|
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_PORTAL |
|
|
|
|
if (source.kind == StreamVideoSource::Screen && source.id == "portal") return true; |
|
|
|
|
#endif |
|
|
|
|
#ifdef UTUN_STREAM_X11_CURSOR |
|
|
|
|
return source.kind == StreamVideoSource::Screen && source.screen && source.id != "portal" && QGuiApplication::platformName() == "xcb"; |
|
|
|
|
#else |
|
|
|
|
@ -267,6 +276,14 @@ bool StreamPublishEngine::openSource(const StreamPublishConfig& config) {
|
|
|
|
|
if (screen == config.source.screen && screenId(screen) == config.source.id) { selected = screen; break; } |
|
|
|
|
if (!selected) { DEBUG_ERROR(DEBUG_CATEGORY_VIDEO, "desktop screen disappeared"); return false; } |
|
|
|
|
} |
|
|
|
|
#ifdef UTUN_STREAM_PORTAL |
|
|
|
|
if (config.source.id == "portal") { |
|
|
|
|
m->portal = std::make_unique<StreamPortalCapture>(); |
|
|
|
|
connect(m->portal.get(), &StreamPortalCapture::frameReady, m->sink.get(), &QVideoSink::setVideoFrame); |
|
|
|
|
connect(m->portal.get(), &StreamPortalCapture::errorOccurred, this, failed, Qt::QueuedConnection); |
|
|
|
|
m->portal->start(config.showCursor); |
|
|
|
|
} else |
|
|
|
|
#endif |
|
|
|
|
// Qt X11 screen capture ищет root по имени и путает мониторы; QScreen захватывает именно выбранный экран.
|
|
|
|
|
if (selected && QGuiApplication::platformName() == "xcb") { |
|
|
|
|
#ifdef UTUN_STREAM_X11_CURSOR |
|
|
|
|
@ -340,6 +357,9 @@ bool StreamPublishEngine::openSource(const StreamPublishConfig& config) {
|
|
|
|
|
void StreamPublishEngine::closeSource() { |
|
|
|
|
#ifdef HAVE_STREAM_CAPTURE |
|
|
|
|
m->screenGrabTimer.reset(); |
|
|
|
|
#ifdef UTUN_STREAM_PORTAL |
|
|
|
|
m->portal.reset(); |
|
|
|
|
#endif |
|
|
|
|
#ifdef UTUN_STREAM_X11_CURSOR |
|
|
|
|
m->cursor.reset(); |
|
|
|
|
#endif |
|
|
|
|
@ -388,6 +408,10 @@ bool StreamPublishEngine::start(uint64_t group, const StreamPublishConfig& confi
|
|
|
|
|
bool StreamPublishEngine::reconfigure(const StreamPublishConfig& config) { |
|
|
|
|
if (!m->running) return false; |
|
|
|
|
StreamPublishConfig previous = this->config(); |
|
|
|
|
if (previous.source.id == "portal" && config.source.sameSource(previous.source) && config.showCursor != previous.showCursor) { |
|
|
|
|
DEBUG_WARN(DEBUG_CATEGORY_VIDEO, "Wayland capture cursor mode cannot change during a portal session"); |
|
|
|
|
emit errorOccurred(text("Change cursor visibility before starting screen sharing")); return false; |
|
|
|
|
} |
|
|
|
|
if (config.audio != previous.audio || config.microphone != previous.microphone) { |
|
|
|
|
DEBUG_WARN(DEBUG_CATEGORY_STREAM, "desktop microphone selection changed during live publication"); |
|
|
|
|
emit errorOccurred(text("Change the microphone before starting the stream")); return false; |
|
|
|
|
|