From 4a7d64b2aa41d76f8b71da30f871c674df589724 Mon Sep 17 00:00:00 2001 From: evgeny Date: Thu, 15 Oct 2026 00:31:03 +0200 Subject: [PATCH] Expose call camera preview and clear inactive remote video --- tools/chatgui/src/call_video_engine.cpp | 33 ++++++++++++++++++++++--- tools/chatgui/src/call_video_engine.h | 1 + 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/tools/chatgui/src/call_video_engine.cpp b/tools/chatgui/src/call_video_engine.cpp index 1c6c3eb9..458c7d21 100644 --- a/tools/chatgui/src/call_video_engine.cpp +++ b/tools/chatgui/src/call_video_engine.cpp @@ -33,6 +33,8 @@ struct CallVideoEngine::Impl { int64_t pts = -1, backend = -1, anchor = -1; QImage shown; uint64_t shownSerial = 0, deliveredSerial = 0; + int64_t previewPts = -1, previewAt = 0; + bool previewVisible = false; QString status; bool statusDirty = false; void report(const QString& text) { @@ -55,6 +57,23 @@ CallVideoEngine::CallVideoEngine(QObject* parent) : QObject(parent), m(std::make if (m->statusDirty) { status = m->status; m->statusDirty = false; report = true; } } if (changed) emit imageChanged(image); if (report) emit statusChanged(status); +#ifdef HAVE_STREAM_CAPTURE + QVideoFrame preview; bool clear = false; + int64_t now = nowUs(); + { std::lock_guard guard(m->lock); + if (!m->enabled && m->previewVisible) { m->previewVisible = false; clear = true; } + if (m->enabled && m->raw.isValid() && m->pts != m->previewPts && now - m->previewAt >= 100000) { + preview = m->raw; m->previewPts = m->pts; m->previewAt = now; + } } + if (clear) emit localImageChanged({}); + if (preview.isValid()) { + QImage local = preview.toImage(); + if (!local.isNull()) { + m->previewVisible = true; + emit localImageChanged(local.scaled(320, 240, Qt::KeepAspectRatio, Qt::SmoothTransformation)); + } else DEBUG_WARN(DEBUG_CATEGORY_CALL, "call camera preview conversion failed"); + } +#endif }); } CallVideoEngine::~CallVideoEngine() { stop(); } @@ -76,8 +95,9 @@ void CallVideoEngine::closeCamera() { if (m->sink) disconnect(m->sink.get(), nullptr, this, nullptr); if (m->camera) { disconnect(m->camera.get(), nullptr, this, nullptr); m->camera->stop(); } m->capture.reset(); m->camera.reset(); m->sink.reset(); - std::lock_guard guard(m->lock); m->raw = {}; m->pts = m->backend = m->anchor = -1; + { std::lock_guard guard(m->lock); m->raw = {}; m->pts = m->backend = m->anchor = -1; } #endif + m->previewPts = -1; m->previewVisible = false; emit localImageChanged({}); } void CallVideoEngine::stop() { m->running = false; m_timer.stop(); closeCamera(); @@ -231,7 +251,7 @@ void CallVideoEngine::receive() { struct Picture { int64_t pts; QImage image; }; std::deque pictures; CallVideoDecoder decoder; - uint64_t sourceEpoch = 0; int64_t lastShown = -1, report = 0; unsigned shown = 0; + uint64_t sourceEpoch = 0; int64_t lastShown = -1, report = 0, lastPictureAt = 0; unsigned shown = 0; uint64_t reportedGeneration = 0, rejectedGeneration = 0; while (m->running) { int64_t now = nowUs(); call_clock_snapshot clock{}; @@ -249,7 +269,14 @@ void CallVideoEngine::receive() { } pictures.pop_front(); } - if (!selected.isNull()) { std::lock_guard guard(m->lock); m->shown = selected; ++m->shownSerial; ++shown; } + if (!selected.isNull()) { + std::lock_guard guard(m->lock); m->shown = selected; ++m->shownSerial; ++shown; lastPictureAt = now; + } + } + // VIDEO_OFF пока отсутствует в протоколе: убираем застывшую картинку после прекращения показа. + if (lastPictureAt && now - lastPictureAt >= 5000000) { + std::lock_guard guard(m->lock); m->shown = {}; ++m->shownSerial; lastPictureAt = 0; + DEBUG_INFO(DEBUG_CATEGORY_CALL, "video playback hidden: no playable frame for 5s"); } if (pictures.size() < 16) { call_video_frame packet{}; diff --git a/tools/chatgui/src/call_video_engine.h b/tools/chatgui/src/call_video_engine.h index 6fd36a4d..babbee74 100644 --- a/tools/chatgui/src/call_video_engine.h +++ b/tools/chatgui/src/call_video_engine.h @@ -16,6 +16,7 @@ public: static QList> cameras(); signals: void imageChanged(const QImage& image); + void localImageChanged(const QImage& image); void statusChanged(const QString& status); private: struct Impl;