Browse Source

Poll stream image thread cleanup from GUI loop

stream-multiview
evgeny 1 week ago
parent
commit
49d55a25a1
  1. 35
      tools/chatgui/src/stream_publish_engine.cpp
  2. 1
      tools/chatgui/src/stream_publish_engine.h

35
tools/chatgui/src/stream_publish_engine.cpp

@ -64,7 +64,7 @@ struct StreamPublishEngine::Impl {
std::mutex lock;
std::condition_variable wake;
std::thread videoThread, audioThread, joinThread;
std::thread imageThread, imageJoinThread;
std::unique_ptr<QThread> imageThread;
std::atomic<bool> workersJoined{false}, videoExited{false}, audioExited{false}, imageJoined{false};
bool stopping = false, finSent = false, destroying = false;
int64_t stopStarted = 0, stopReport = 0;
@ -156,13 +156,14 @@ StreamPublishEngine::StreamPublishEngine(QObject* parent) : QObject(parent), m(s
m_capture.close(); // Контекст нельзя освободить до завершения фонового закрытия устройства.
});
#ifdef HAVE_STREAM_CAPTURE
m->imageThread = std::thread([this] {
m->imageThread.reset(QThread::create([this] {
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "desktop image worker started tid=%llu", (unsigned long long)(quintptr)QThread::currentThreadId());
imageLoop();
m->imageProgress("release-thread-resources");
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "desktop image loop returned; releasing thread resources frames=%llu tid=%llu",
(unsigned long long)m->imageFrames.load(), (unsigned long long)(quintptr)QThread::currentThreadId());
});
}));
m->imageThread->start();
#else
m->imageJoined = true;
#endif
@ -177,15 +178,8 @@ StreamPublishEngine::~StreamPublishEngine() {
#ifdef HAVE_STREAM_CAPTURE
{ std::lock_guard<std::mutex> guard(m->lock); m->imageStop = true; m->imagePending = false; m->imageInput = {}; }
m->imageWake.notify_all();
m->imageJoinThread = std::thread([this] {
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "desktop image join begin stage=%s stage_age_ms=%lld",
m->imageStage.load(), (long long)((monotonicUs() - m->imageStageAt.load()) / 1000));
m->imageThread.join();
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "desktop image join complete; native thread resources released");
m->imageJoined = true;
});
#endif
if (!finishStop() || !m->imageJoined) {
if (!finishStop() || !finishImageStop()) {
// Qt освобождает thread-local графику через GUI. Даже при выходе приложения нельзя блокировать его join().
DEBUG_INFO(DEBUG_CATEGORY_VIDEO, "desktop publisher destruction waits for workers stopping=%d image_joined=%d image_stage=%s",
m->stopping, m->imageJoined.load(), m->imageStage.load());
@ -196,7 +190,8 @@ StreamPublishEngine::~StreamPublishEngine() {
if (firstPoll) {
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "desktop publisher destruction GUI timer active"); firstPoll = false;
}
if (finishStop() && m->imageJoined) { loop.quit(); return; }
const bool imageDone = finishImageStop();
if (finishStop() && imageDone) { loop.quit(); return; }
const int64_t now = monotonicUs();
if (now - reportAt < 5000000) return;
reportAt = now;
@ -213,7 +208,6 @@ StreamPublishEngine::~StreamPublishEngine() {
if (m->stopping || !m->imageJoined)
DEBUG_ERROR(DEBUG_CATEGORY_DEBUG, "desktop publisher destruction GUI loop exited before worker cleanup completed");
}
if (m->imageJoinThread.joinable()) m->imageJoinThread.join();
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "desktop publisher destruction complete elapsed_ms=%lld", (long long)((monotonicUs() - destroyAt) / 1000));
}
bool StreamPublishEngine::supported() {
@ -664,6 +658,21 @@ bool StreamPublishEngine::finishStop() {
return true;
}
/* Проверка QThread с нулевым таймаутом сохраняет GUI event loop доступным для native cleanup. */
bool StreamPublishEngine::finishImageStop() {
if (m->imageJoined) return true;
if (!m->imageThread) {
DEBUG_ERROR(DEBUG_CATEGORY_DEBUG, "desktop image worker missing before native thread completion");
return false;
}
if (!m->imageThread->wait(0)) return false;
m->imageThread.reset();
m->imageJoined = true;
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "desktop image native thread cleanup completed frames=%llu",
(unsigned long long)m->imageFrames.load());
return true;
}
uint64_t StreamPublishEngine::softwareEncodingRequest() const {
std::lock_guard<std::mutex> guard(m->lock); return m->softwareRequest;
}

1
tools/chatgui/src/stream_publish_engine.h

@ -82,6 +82,7 @@ private:
void publicationFailed(uint64_t id, const QString& error);
void tick();
bool finishStop();
bool finishImageStop();
void imageLoop();
void videoLoop(StreamPublishConfig initial);
void audioLoop();

Loading…
Cancel
Save