From 39f0ed6e7527508ab887de3955694646a40ec947 Mon Sep 17 00:00:00 2001 From: Alex Luccisano Date: Mon, 9 Sep 2024 09:41:41 -0400 Subject: [PATCH] shared/bpm: Fixed crash when using Stream Delay BPM initialization occurs with the first call to the `bpm_inject()` callback function. When Stream Delay is active, there is a case where the first call might never happen, specifically if a user stops the stream with the discard delay option before streaming begins. In such a case OBS will crash due to an uninitialized mutex being referenced in `bpm_destroy()`. Use `pthread_once()` in both the `bpm_inject()` callback and `bpm_destroy()` to ensure BPM initialization has occurred. --- shared/bpm/bpm-internal.h | 2 ++ shared/bpm/bpm.c | 16 ++++++++-------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/shared/bpm/bpm-internal.h b/shared/bpm/bpm-internal.h index 89d091d4b768c4..5017a7504f5429 100644 --- a/shared/bpm/bpm-internal.h +++ b/shared/bpm/bpm-internal.h @@ -98,7 +98,9 @@ struct output_metrics_link { struct metrics_data *metrics_tracks[MAX_OUTPUT_VIDEO_ENCODERS]; }; +static pthread_once_t bpm_once = PTHREAD_ONCE_INIT; static pthread_mutex_t bpm_metrics_mutex; + /* This DARRAY is used for creating an association between the output_t * and the BPM metrics track data for each output that requires BPM injection. */ diff --git a/shared/bpm/bpm.c b/shared/bpm/bpm.c index a95d19b0089aab..38a8a60b1d0440 100644 --- a/shared/bpm/bpm.c +++ b/shared/bpm/bpm.c @@ -565,10 +565,17 @@ static bool bpm_get_track(obs_output_t *output, size_t track, return found; } +static void bpm_init(void) +{ + pthread_mutex_init_value(&bpm_metrics_mutex); + da_init(bpm_metrics); +} + void bpm_destroy(obs_output_t *output) { int64_t idx = -1; + pthread_once(&bpm_once, bpm_init); pthread_mutex_lock(&bpm_metrics_mutex); // Walk the DARRAY looking for the index that matches the output @@ -600,12 +607,6 @@ void bpm_destroy(obs_output_t *output) pthread_mutex_unlock(&bpm_metrics_mutex); } -static void bpm_init(void) -{ - pthread_mutex_init_value(&bpm_metrics_mutex); - da_init(bpm_metrics); -} - /* bpm_inject() is the callback function that needs to be registered * with each output needing Broadcast Performance Metrics injected * into the video bitstream, using SEI (AVC/HEVC) and OBU (AV1) syntax. @@ -615,8 +616,7 @@ void bpm_inject(obs_output_t *output, struct encoder_packet *pkt, { UNUSED_PARAMETER(param); - static pthread_once_t once = PTHREAD_ONCE_INIT; - pthread_once(&once, bpm_init); + pthread_once(&bpm_once, bpm_init); if (!output || !pkt) { blog(LOG_DEBUG,