Clarify GUI ownership and preserve video queue payload lifetime
This commit is contained in:
1 parent
d0232e4c6e
commit
8c22df8f8e
3 files changed
+13
-10
No files matched your search
@@ -53,7 +53,7 @@ struct CallVideoEngine::Impl {
|
||||
QByteArray cameraId;
|
||||
bool captureActive = false;
|
||||
uint64_t captured = 0;
|
||||
std::atomic<uint64_t> publicationEpoch{0}, pendingSerial{0}, ackSerial{0};
|
||||
std::atomic<uint64_t> pendingSerial{0}, ackSerial{0};
|
||||
std::atomic<int64_t> presentedAt{0};
|
||||
bool presentationDriven = false;
|
||||
uint64_t publicationSerial = 0;
|
||||
@@ -136,7 +136,7 @@ CallVideoEngine::CallVideoEngine(QObject* parent) : QObject(parent), m(std::make
|
||||
}
|
||||
CallVideoEngine::~CallVideoEngine() { stop(); delete m->guiNotifier; }
|
||||
void CallVideoEngine::setPresentationDriven(bool enabled) {
|
||||
std::lock_guard<std::mutex> guard(m->lock); m->presentationDriven = enabled;
|
||||
m->presentationDriven = enabled;
|
||||
}
|
||||
void CallVideoEngine::imagePresented(quint64 serial) {
|
||||
if (!serial || serial != m->pendingSerial.load(std::memory_order_acquire) || serial == m->ackSerial.load()) return;
|
||||
@@ -158,7 +158,10 @@ void CallVideoEngine::deliverImage() {
|
||||
QImage image;
|
||||
if (m->publicationVideo) {
|
||||
const auto* slot = m->pictures.readSlot();
|
||||
if (!slot) { DEBUG_ERROR(DEBUG_CATEGORY_CALL, "video GUI missing published slot serial=%llu", (unsigned long long)serial); return; }
|
||||
if (!slot) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CALL, "video GUI missing published slot serial=%llu; stopping video", (unsigned long long)serial);
|
||||
stop(); return;
|
||||
}
|
||||
image = slot->image;
|
||||
}
|
||||
const int64_t now = nowUs(), wait = now - queued;
|
||||
@@ -228,7 +231,7 @@ void CallVideoEngine::stop() {
|
||||
if (m->tx.joinable()) m->tx.join();
|
||||
if (m->rx.joinable()) m->rx.join();
|
||||
if (m->id) call_video_port_close(m->id);
|
||||
++m->publicationEpoch; m->pendingSerial = 0; m->paintWaitMax = 0;
|
||||
m->pendingSerial = 0; m->paintWaitMax = 0;
|
||||
while (const auto* event = m->logEvents.readSlot()) { call_video_playout_log_event(event); m->logEvents.release(); }
|
||||
m->id = 0; m->enabled = false; emit imageChanged({}, 0);
|
||||
}
|
||||
|
||||
@@ -14,8 +14,8 @@ public:
|
||||
void start(quint64 id);
|
||||
void stop();
|
||||
void setVideo(bool enabled, const QByteArray& camera, int width, int height, int codec);
|
||||
void setPresentationDriven(bool enabled); // Окно подтверждает рисование; без окна достаточно доставки signal.
|
||||
void imagePresented(quint64 serial);
|
||||
void setPresentationDriven(bool enabled); // GUI-поток: окно подтверждает рисование, иначе достаточно доставки signal.
|
||||
void imagePresented(quint64 serial); // GUI-поток; повторный/старый ACK безопасно игнорируется.
|
||||
signals:
|
||||
void camerasChanged(const CallCameraDevices& devices);
|
||||
void imageChanged(const QImage& image, quint64 serial);
|
||||
|
||||
@@ -10,18 +10,18 @@
|
||||
template<class T, unsigned Capacity> class CallVideoQueue {
|
||||
static_assert(Capacity > 0);
|
||||
static_assert(std::atomic<uint64_t>::is_always_lock_free);
|
||||
std::array<T, Capacity> slots{};
|
||||
std::array<T, Capacity> entries{};
|
||||
alignas(64) std::atomic<uint64_t> written{0};
|
||||
alignas(64) std::atomic<uint64_t> consumed{0};
|
||||
public:
|
||||
T* writeSlot() {
|
||||
const uint64_t tail = written.load(std::memory_order_relaxed);
|
||||
return tail - consumed.load(std::memory_order_acquire) < Capacity ? &slots[tail % Capacity] : nullptr;
|
||||
return tail - consumed.load(std::memory_order_acquire) < Capacity ? &entries[tail % Capacity] : nullptr;
|
||||
}
|
||||
void publish() { written.fetch_add(1, std::memory_order_release); }
|
||||
const T* readSlot() const {
|
||||
const uint64_t head = consumed.load(std::memory_order_relaxed);
|
||||
return head < written.load(std::memory_order_acquire) ? &slots[head % Capacity] : nullptr;
|
||||
return head < written.load(std::memory_order_acquire) ? &entries[head % Capacity] : nullptr;
|
||||
}
|
||||
void release() { consumed.fetch_add(1, std::memory_order_release); }
|
||||
// Вызывается только producer/consumer: собственный индекс во время снимка не меняется.
|
||||
@@ -30,7 +30,7 @@ public:
|
||||
return static_cast<unsigned>(written.load(std::memory_order_acquire) - head);
|
||||
}
|
||||
void reset() {
|
||||
for (auto& slot : slots) slot = {};
|
||||
for (auto& slot : entries) slot = {};
|
||||
written.store(0, std::memory_order_relaxed); consumed.store(0, std::memory_order_relaxed);
|
||||
}
|
||||
};
|
||||
Reference in new issue
Block a user