diff --git a/tools/chatgui/src/stream_publish_engine.cpp b/tools/chatgui/src/stream_publish_engine.cpp index a8a6ce9a..03519728 100644 --- a/tools/chatgui/src/stream_publish_engine.cpp +++ b/tools/chatgui/src/stream_publish_engine.cpp @@ -57,6 +57,24 @@ QByteArray screenId(QScreen* screen) { return QJsonDocument(QJsonArray{screen->name(), screen->manufacturer(), screen->model(), screen->serialNumber(), duplicate}) .toJson(QJsonDocument::Compact); } +#ifdef UTUN_STREAM_WIN_CURSOR +QVideoFrame previewFrameFromImage(const QImage& source) { +#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0) + return QVideoFrame(source); +#else + QImage image = source.convertToFormat(QImage::Format_RGBA8888); + QVideoFrame frame(QVideoFrameFormat(image.size(), QVideoFrameFormat::Format_RGBA8888)); + if (!frame.map(QVideoFrame::WriteOnly)) { + DEBUG_WARN(DEBUG_CATEGORY_VIDEO, "desktop preview frame map failed size=%dx%d", image.width(), image.height()); + return {}; + } + for (int y = 0; y < image.height(); y++) + std::memcpy(frame.bits(0) + y * frame.bytesPerLine(0), image.constScanLine(y), image.width() * 4); + frame.unmap(); + return frame; +#endif +} +#endif #endif } struct StreamPublishEngine::Impl { @@ -318,7 +336,9 @@ bool StreamPublishEngine::openSource(const StreamPublishConfig& config) { } int fps = std::clamp(m->wanted.video.fps, 1, 60); convert = !m->lastImageCaptureAt || callbackAt - m->lastImageCaptureAt >= 1000000 / fps; +#ifndef UTUN_STREAM_WIN_CURSOR m->previewFrame = frame; +#endif if (!convert) { m->wake.notify_all(); return; } m->lastImageCaptureAt = callbackAt; if (m->framePts < 0 && m->wanted.source.id == "portal") m->started = monotonicUs(); @@ -510,6 +530,9 @@ void StreamPublishEngine::imageLoop() { QMetaObject::invokeMethod(this, [this, generation] { sourceFailed(generation, text("Could not capture the mouse cursor")); }); continue; } + QVideoFrame preview = previewFrameFromImage(image); + if (!preview.isValid()) DEBUG_WARN(DEBUG_CATEGORY_VIDEO, "desktop preview frame unavailable generation=%llu", + (unsigned long long)generation); #endif #if QT_VERSION >= QT_VERSION_CHECK(6, 7, 0) if (frame.rotation() != QtVideo::Rotation::None) image = image.transformed(QTransform().rotate(static_cast(frame.rotation()))); @@ -522,6 +545,9 @@ void StreamPublishEngine::imageLoop() { std::lock_guard guard(m->lock); if (m->imageStop) return; if (!m->running || generation != m->sourceGeneration) continue; +#ifdef UTUN_STREAM_WIN_CURSOR + if (preview.isValid()) m->previewFrame = std::move(preview); +#endif if (m->framePts < 0 && m->wanted.source.id == "portal") m->started = monotonicUs(); m->latestImage = image; m->frame = std::move(image); m->framePts = pts; m->frameGeneration = m->generation; if (!m->convertedCaptureFrames++) DEBUG_INFO(DEBUG_CATEGORY_VIDEO,