From db06a1c12acb50422d61055fc7053e95048d6bb6 Mon Sep 17 00:00:00 2001 From: Ilya Melamed Date: Sat, 5 May 2018 11:38:32 -0700 Subject: [PATCH] win-dshow: Allow synchronous create/update Allows the ability to (optionally) synchronously create/update a directshow device source rather than always asynchronously update the device. This is useful if creating/destroying scenes/sources very quickly, and helps minimize the risk of creating new directshow sources that use the same device, yet may not activate because an existing source may already exist. To use, set "synchronous_activate" to true in its settings when updating or creating. Note that this setting will be erased after it's used, and will not be saved to user settings, so it must be set each time in order to be used. Closes obsproject/obs-studio#1228 --- plugins/win-dshow/win-dshow.cpp | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/plugins/win-dshow/win-dshow.cpp b/plugins/win-dshow/win-dshow.cpp index d18413fbf..03bdbba91 100644 --- a/plugins/win-dshow/win-dshow.cpp +++ b/plugins/win-dshow/win-dshow.cpp @@ -150,6 +150,7 @@ public: enum class Action { None, Activate, + ActivateBlock, Deactivate, Shutdown, ConfigVideo, @@ -179,6 +180,7 @@ struct DShowInput { obs_source_audio audio; WinHandle semaphore; + WinHandle activated_event; WinHandle thread; CriticalSection mutex; vector actions; @@ -190,6 +192,16 @@ struct DShowInput { ReleaseSemaphore(semaphore, 1, nullptr); } + inline void QueueActivate(obs_data_t *settings) + { + bool block = obs_data_get_bool(settings, "synchronous_activate"); + QueueAction(block ? Action::ActivateBlock : Action::Activate); + if (block) { + obs_data_erase(settings, "synchronous_activate"); + WaitForSingleObject(activated_event, INFINITE); + } + } + inline DShowInput(obs_source_t *source_, obs_data_t *settings) : source (source_), device (InitGraph::False) @@ -204,6 +216,10 @@ struct DShowInput { if (!semaphore) throw "Failed to create semaphore"; + activated_event = CreateEvent(nullptr, false, false, nullptr); + if (!activated_event) + throw "Failed to create activated_event"; + thread = CreateThread(nullptr, 0, DShowThread, this, 0, nullptr); if (!thread) @@ -215,7 +231,7 @@ struct DShowInput { if (obs_data_get_bool(settings, "active")) { bool showing = obs_source_showing(source); if (!deactivateWhenNotShowing || showing) - QueueAction(Action::Activate); + QueueActivate(settings); active = true; } @@ -304,13 +320,18 @@ void DShowInput::DShowLoop() switch (action) { case Action::Activate: + case Action::ActivateBlock: { + bool block = action == Action::ActivateBlock; + obs_data_t *settings; settings = obs_source_get_settings(source); if (!Activate(settings)) { obs_source_output_video(source, nullptr); } + if (block) + SetEvent(activated_event); obs_data_release(settings); break; } @@ -1075,9 +1096,7 @@ static void UpdateDShowInput(void *data, obs_data_t *settings) { DShowInput *input = reinterpret_cast(data); if (input->active) - input->QueueAction(Action::Activate); - - UNUSED_PARAMETER(settings); + input->QueueActivate(settings); } static void GetDShowDefaults(obs_data_t *settings)