virtualcam-module: Stop thread on Stop call

This causes the thread to only start when the IMediaFilter::Run/Pause
calls have been made, and stop whenever either the IMediaFilter::Stop
call has been made, or on destruction, whichever comes first.

This potentially will work around a suspected race condition that
appears to be in the WebRTC library where the filter's library will be
released while the filter is in the process of being destroyed, which
can take longer than usual if the join takes too long. Basically, fixes
a reported crash (that doesn't appear to technically be our fault) when
the filter is used with browsers when the virtualcam is deactivating in
web browsers.
This commit is contained in:
jp9000 2022-02-27 22:19:30 -08:00
parent 139e6ed69e
commit 865eecb739
2 changed files with 58 additions and 9 deletions

View file

@ -45,6 +45,17 @@ VCamFilter::VCamFilter()
in_obs = !!wcsstr(file, obs_process);
/* ---------------------------------------- */
AddRef();
}
inline void VCamFilter::ActuallyStart()
{
if (th.joinable()) {
return;
}
/* ---------------------------------------- */
/* add last/current obs res/interval */
@ -103,21 +114,32 @@ VCamFilter::VCamFilter()
}
/* ---------------------------------------- */
/* Actually start */
ResetEvent(thread_stop);
th = std::thread([this] { Thread(); });
SetEvent(thread_start);
}
AddRef();
inline void VCamFilter::ActuallyStop()
{
if (!th.joinable()) {
return;
}
SetEvent(thread_stop);
th.join();
video_queue_close(vq);
if (placeholder.scaled_data) {
free(placeholder.scaled_data);
placeholder.scaled_data = nullptr;
}
}
VCamFilter::~VCamFilter()
{
SetEvent(thread_stop);
if (th.joinable())
th.join();
video_queue_close(vq);
if (placeholder.scaled_data)
free(placeholder.scaled_data);
ActuallyStop();
}
const wchar_t *VCamFilter::FilterName() const
@ -134,7 +156,29 @@ STDMETHODIMP VCamFilter::Pause()
return hr;
}
SetEvent(thread_start);
ActuallyStart();
return S_OK;
}
STDMETHODIMP VCamFilter::Run(REFERENCE_TIME tStart)
{
HRESULT hr = OutputFilter::Run(tStart);
if (FAILED(hr)) {
return hr;
}
ActuallyStart();
return S_OK;
}
STDMETHODIMP VCamFilter::Stop()
{
HRESULT hr = OutputFilter::Stop();
if (FAILED(hr)) {
return hr;
}
ActuallyStop();
return S_OK;
}

View file

@ -52,6 +52,9 @@ class VCamFilter : public DShow::OutputFilter {
void UpdatePlaceholder(void);
const int GetOutputBufferSize(void);
inline void ActuallyStart();
inline void ActuallyStop();
protected:
const wchar_t *FilterName() const override;
@ -60,4 +63,6 @@ public:
~VCamFilter() override;
STDMETHODIMP Pause() override;
STDMETHODIMP Stop() override;
STDMETHODIMP Run(REFERENCE_TIME tStart) override;
};