From bdf6b893ab90996474cbaa1e2c522aceefbe0120 Mon Sep 17 00:00:00 2001 From: Michael Fabian 'Xaymar' Dirks Date: Wed, 3 Apr 2019 02:58:54 +0200 Subject: [PATCH] source-mirror: Fix a dead lock issue and use a queue system This fixes a dead lock due to attempting to lock the same filter mutex twice, causing libOBS to completely lock up on every mutex. This extends the fix for 4fc25cfd8df99d60fbea70d1bf921d0d96baffc3. Additionally this switches to a proper queue system for audio, so we no longer cause audio stuttering or audio skipping. --- source/sources/source-mirror.cpp | 99 +++++++++++++++++++++++--------- source/sources/source-mirror.hpp | 23 +++++--- 2 files changed, 88 insertions(+), 34 deletions(-) diff --git a/source/sources/source-mirror.cpp b/source/sources/source-mirror.cpp index edbb50f..bc76b4c 100644 --- a/source/sources/source-mirror.cpp +++ b/source/sources/source-mirror.cpp @@ -363,10 +363,6 @@ source::mirror::mirror_instance::mirror_instance(obs_data_t*, obs_source_t* src) std::make_shared(this->m_scene, std::make_shared(this->m_self, false, false)); // Initialize Audio Rendering - this->m_audio_data.resize(MAX_AUDIO_CHANNELS); - for (size_t idx = 0; idx < this->m_audio_data.size(); idx++) { - this->m_audio_data[idx].resize(AUDIO_OUTPUT_FRAMES); - } this->m_audio_thread = std::thread(std::bind(&source::mirror::mirror_instance::audio_output_cb, this)); } @@ -389,6 +385,9 @@ source::mirror::mirror_instance::~mirror_instance() uint32_t source::mirror::mirror_instance::get_width() { if (m_source) { + if ((obs_source_get_output_flags(this->m_source->get()) & OBS_SOURCE_VIDEO) == 0) { + return 0; + } if (this->m_rescale_enabled && this->m_rescale_width > 0 && !this->m_rescale_keep_orig_size) { return this->m_rescale_width; } else { @@ -401,6 +400,9 @@ uint32_t source::mirror::mirror_instance::get_width() uint32_t source::mirror::mirror_instance::get_height() { if (m_source) { + if ((obs_source_get_output_flags(this->m_source->get()) & OBS_SOURCE_VIDEO) == 0) { + return 0; + } if (this->m_rescale_enabled && this->m_rescale_height > 0 && !this->m_rescale_keep_orig_size) { return this->m_rescale_height; } else { @@ -570,14 +572,35 @@ void source::mirror::mirror_instance::video_render(gs_effect_t* effect) void source::mirror::mirror_instance::audio_output_cb() { - std::unique_lock ulock(this->m_audio_lock); + std::unique_lock ulock(this->m_audio_lock_outputter); while (!this->m_audio_kill_thread) { - if (this->m_audio_have_output) { - obs_source_output_audio(this->m_self, &this->m_audio_output); - this->m_audio_have_output = false; - } this->m_audio_notify.wait(ulock, [this]() { return this->m_audio_have_output || this->m_audio_kill_thread; }); + + if (this->m_audio_have_output) { // Get used audio element + std::shared_ptr mad; + { + std::lock_guard capture_lock(this->m_audio_lock_capturer); + if (m_audio_data_queue.size() > 0) { + mad = m_audio_data_queue.front(); + m_audio_data_queue.pop(); + } + if (m_audio_data_queue.size() == 0) { + this->m_audio_have_output = false; + } + } + + if (mad) { + ulock.unlock(); + obs_source_output_audio(this->m_self, &mad->audio); + ulock.lock(); + + { + std::lock_guard capture_lock(this->m_audio_lock_capturer); + m_audio_data_free_queue.push(mad); + } + } + } } } @@ -611,7 +634,6 @@ void source::mirror::mirror_instance::on_source_rename(obs::source* source, std: void source::mirror::mirror_instance::on_audio_data(obs::source*, const audio_data* audio, bool) { - std::unique_lock ulock(this->m_audio_lock); if (!this->m_audio_enabled) { return; } @@ -625,24 +647,49 @@ void source::mirror::mirror_instance::on_audio_data(obs::source*, const audio_da return; } - std::bitset<8> layout; - for (size_t plane = 0; plane < MAX_AV_PLANES; plane++) { - float* samples = (float*)audio->data[plane]; - if (!samples) { - this->m_audio_output.data[plane] = nullptr; - continue; + std::shared_ptr mad; + { // Get free audio data element. + std::lock_guard capture_lock(this->m_audio_lock_capturer); + if (m_audio_data_free_queue.size() > 0) { + mad = m_audio_data_free_queue.front(); + m_audio_data_free_queue.pop(); + } else { + mad = std::make_shared(); + mad->data.resize(MAX_AUDIO_CHANNELS); + for (size_t idx = 0; idx < mad->data.size(); idx++) { + mad->data[idx].resize(AUDIO_OUTPUT_FRAMES); + } } - layout.set(plane); - - memcpy(this->m_audio_data[plane].data(), audio->data[plane], audio->frames * sizeof(float_t)); - this->m_audio_output.data[plane] = reinterpret_cast(this->m_audio_data[plane].data()); } - this->m_audio_output.format = aoi->format; - this->m_audio_output.frames = audio->frames; - this->m_audio_output.timestamp = audio->timestamp; - this->m_audio_output.samples_per_sec = aoi->samples_per_sec; - this->m_audio_output.speakers = aoi->speakers; - this->m_audio_have_output = true; + { // Copy data + std::bitset<8> layout; + for (size_t plane = 0; plane < MAX_AV_PLANES; plane++) { + float* samples = (float*)audio->data[plane]; + if (!samples) { + mad->audio.data[plane] = nullptr; + continue; + } + layout.set(plane); + + memcpy(mad->data[plane].data(), audio->data[plane], audio->frames * sizeof(float_t)); + mad->audio.data[plane] = reinterpret_cast(mad->data[plane].data()); + } + mad->audio.format = aoi->format; + mad->audio.frames = audio->frames; + mad->audio.timestamp = audio->timestamp; + mad->audio.samples_per_sec = aoi->samples_per_sec; + mad->audio.speakers = aoi->speakers; + } + + { // Push used audio data element. + std::lock_guard capture_lock(this->m_audio_lock_capturer); + m_audio_data_queue.push(mad); + } + + { // Signal other side. + std::lock_guard output_lock(this->m_audio_lock_outputter); + this->m_audio_have_output = true; + } this->m_audio_notify.notify_all(); } diff --git a/source/sources/source-mirror.hpp b/source/sources/source-mirror.hpp index f7ad9c2..6db61d4 100644 --- a/source/sources/source-mirror.hpp +++ b/source/sources/source-mirror.hpp @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include "gfx/gfx-source-texture.hpp" @@ -76,6 +77,11 @@ namespace source { static void save(void*, obs_data_t*); }; + struct mirror_audio_data { + obs_source_audio audio; + std::vector> data; + }; + class mirror_instance { bool m_active; obs_source_t* m_self; @@ -96,14 +102,15 @@ namespace source { obs_bounds_type m_rescale_bounds; // Audio Rendering - bool m_audio_enabled; - std::mutex m_audio_lock; - std::condition_variable m_audio_notify; - obs_source_audio m_audio_output; - std::vector> m_audio_data; - std::thread m_audio_thread; - bool m_audio_kill_thread; - bool m_audio_have_output; + bool m_audio_enabled; + std::condition_variable m_audio_notify; + std::thread m_audio_thread; + bool m_audio_kill_thread; + bool m_audio_have_output; + std::mutex m_audio_lock_outputter; + std::mutex m_audio_lock_capturer; + std::queue> m_audio_data_queue; + std::queue> m_audio_data_free_queue; // Input std::shared_ptr m_source;