Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Thread safety fixes to address potential crashes and freezes #52

Merged
merged 9 commits into from
Feb 8, 2023
Prev Previous commit
Next Next commit
Narrow lock scopes and explain locking strategy
  • Loading branch information
y2kcyborg committed Feb 4, 2023
commit 81a47784b728d75fdd8462069d8f0d7dc23a2f6f
69 changes: 46 additions & 23 deletions source/win-spout-output.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ struct spout_output
obs_output_t* output;
const char* senderName;
bool output_started;
// mutex guards accesses to rest of context variables,
// and any methods on spoutDX* sender.
// Calling obs methods on obs_output_t* output seems thread-safe.
// trying to avoid calling obs methods while holding our own mutex.
pthread_mutex_t mutex;
};

Expand Down Expand Up @@ -103,23 +107,26 @@ bool win_spout_output_start(void* data)

pthread_mutex_lock(&context->mutex);

const char *senderName = context->senderName;
context->sender->SetSenderName(context->senderName);

int32_t width = (int32_t)obs_output_get_width(context->output);
int32_t height = (int32_t)obs_output_get_height(context->output);
obs_output_t *output = context->output;

video_t* video = obs_output_video(context->output);
pthread_mutex_unlock(&context->mutex);

int32_t width = (int32_t)obs_output_get_width(output);
int32_t height = (int32_t)obs_output_get_height(output);

video_t* video = obs_output_video(output);
if (!video)
{
blog(LOG_ERROR, "Trying to start with no video!");
pthread_mutex_unlock(&context->mutex);
return false;
}

if (!obs_output_can_begin_data_capture(context->output, 0))
if (!obs_output_can_begin_data_capture(output, 0))
{
blog(LOG_ERROR, "Unable to begin data capture!");
pthread_mutex_unlock(&context->mutex);
return false;
}

Expand All @@ -129,19 +136,24 @@ bool win_spout_output_start(void* data)
info.width = width;
info.height = height;

obs_output_set_video_conversion(context->output, &info);
obs_output_set_video_conversion(output, &info);

context->output_started = obs_output_begin_data_capture(context->output, 0);
bool started = obs_output_begin_data_capture(output, 0);

if (!context->output_started)
{
pthread_mutex_lock(&context->mutex);

context->output_started = started;

pthread_mutex_unlock(&context->mutex);

if (!started) {
blog(LOG_ERROR, "Unable to start capture!");
} else {
blog(LOG_INFO,
"Creating capture with name: %s, width: %i, height: %i",
context->senderName, width, height);
}
else
blog(LOG_INFO, "Creating capture with name: %s, width: %i, height: %i", context->senderName, width, height);

bool started = context->output_started;
pthread_mutex_unlock(&context->mutex);
return started;
}

Expand All @@ -152,16 +164,20 @@ void win_spout_output_stop(void* data, uint64_t ts)
spout_output* context = (spout_output*)data;

pthread_mutex_lock(&context->mutex);
bool started = context->output_started;
pthread_mutex_unlock(&context->mutex);

if (context->output_started)
if (started)
{
context->output_started = false;

obs_output_end_data_capture(context->output);

pthread_mutex_lock(&context->mutex);

context->sender->ReleaseSender();
}
context->output_started = false;

pthread_mutex_unlock(&context->mutex);
pthread_mutex_unlock(&context->mutex);
}
}

void win_spout_output_rawvideo(void* data, struct video_data* frame)
Expand All @@ -170,16 +186,23 @@ void win_spout_output_rawvideo(void* data, struct video_data* frame)

pthread_mutex_lock(&context->mutex);

if (!context->output_started)
bool started = context->output_started;
obs_output_t *output = context->output;

pthread_mutex_unlock(&context->mutex);

if (!started)
{
pthread_mutex_unlock(&context->mutex);
return;
}

int32_t width = (int32_t)obs_output_get_width(context->output);
int32_t height = (int32_t)obs_output_get_height(context->output);
int32_t width = (int32_t)obs_output_get_width(output);
int32_t height = (int32_t)obs_output_get_height(output);

pthread_mutex_lock(&context->mutex);

context->sender->SendImage(frame->data[0], width, height);

pthread_mutex_unlock(&context->mutex);
}

Expand Down