Skip to content

Commit

Permalink
shared/bpm: Fixed crash when using Stream Delay
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
lexano-ivs authored and RytoEX committed Oct 4, 2024
1 parent cb02696 commit 39f0ed6
Show file tree
Hide file tree
Showing 2 changed files with 10 additions and 8 deletions.
2 changes: 2 additions & 0 deletions shared/bpm/bpm-internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*/
Expand Down
16 changes: 8 additions & 8 deletions shared/bpm/bpm.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand All @@ -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,
Expand Down

0 comments on commit 39f0ed6

Please sign in to comment.