From ca865f80cc90f8189671a022d5e29083c660689a Mon Sep 17 00:00:00 2001 From: derrod Date: Sun, 3 Dec 2023 18:41:39 +0100 Subject: [PATCH] libobs: Pair video encoder with all audio encoders --- libobs/obs-encoder.c | 25 ++++++++++++++-------- libobs/obs-internal.h | 2 +- libobs/obs-output.c | 39 ++++++++++++++--------------------- libobs/obs-video-gpu-encode.c | 21 ++++++++++++++----- 4 files changed, 49 insertions(+), 38 deletions(-) diff --git a/libobs/obs-encoder.c b/libobs/obs-encoder.c index 2fc5a34a3..2733af83f 100644 --- a/libobs/obs-encoder.c +++ b/libobs/obs-encoder.c @@ -678,7 +678,7 @@ void obs_encoder_shutdown(obs_encoder_t *encoder) if (encoder->context.data) { encoder->info.destroy(encoder->context.data); encoder->context.data = NULL; - encoder->paired_encoder = NULL; + da_free(encoder->paired_encoders); encoder->first_received = false; encoder->offset_usec = 0; encoder->start_ts = 0; @@ -1371,13 +1371,15 @@ static void receive_video(void *param, struct video_data *frame) profile_start(receive_video_name); struct obs_encoder *encoder = param; - struct obs_encoder *pair = encoder->paired_encoder; + struct obs_encoder **paired = encoder->paired_encoders.array; struct encoder_frame enc_frame; - if (!encoder->first_received && pair) { - if (!pair->first_received || - pair->first_raw_ts > frame->timestamp) { - goto wait_for_audio; + if (!encoder->first_received && encoder->paired_encoders.num) { + for (size_t i = 0; i < encoder->paired_encoders.num; i++) { + if (!paired[i]->first_received || + paired[i]->first_raw_ts > frame->timestamp) { + goto wait_for_audio; + } } } @@ -1465,9 +1467,14 @@ static bool buffer_audio(struct obs_encoder *encoder, struct audio_data *data) size_t offset_size = 0; bool success = true; - if (!encoder->start_ts && encoder->paired_encoder) { + struct obs_encoder *paired_encoder = NULL; + /* Audio encoders can only be paired to one video encoder */ + if (encoder->paired_encoders.num) + paired_encoder = encoder->paired_encoders.array[0]; + + if (!encoder->start_ts && paired_encoder) { uint64_t end_ts = data->timestamp; - uint64_t v_start_ts = encoder->paired_encoder->start_ts; + uint64_t v_start_ts = paired_encoder->start_ts; /* no video yet, so don't start audio */ if (!v_start_ts) { @@ -1498,7 +1505,7 @@ static bool buffer_audio(struct obs_encoder *encoder, struct audio_data *data) start_from_buffer(encoder, v_start_ts); } - } else if (!encoder->start_ts && !encoder->paired_encoder) { + } else if (!encoder->start_ts && !paired_encoder) { encoder->start_ts = data->timestamp; } diff --git a/libobs/obs-internal.h b/libobs/obs-internal.h index 045f4bc6f..6e59fe60b 100644 --- a/libobs/obs-internal.h +++ b/libobs/obs-internal.h @@ -1248,7 +1248,7 @@ struct obs_encoder { * up at the specific timestamp. if this is the audio encoder, * it waits until it's ready to sync up with video */ bool first_received; - struct obs_encoder *paired_encoder; + DARRAY(struct obs_encoder *) paired_encoders; int64_t offset_usec; uint64_t first_raw_ts; uint64_t start_ts; diff --git a/libobs/obs-output.c b/libobs/obs-output.c index 2dd6ae4ad..ad048194c 100644 --- a/libobs/obs-output.c +++ b/libobs/obs-output.c @@ -2376,39 +2376,32 @@ static inline bool initialize_video_encoders(obs_output_t *output) return true; } -static inline obs_encoder_t *find_inactive_audio_encoder(obs_output_t *output) -{ - for (size_t i = 0; i < MAX_OUTPUT_AUDIO_ENCODERS; i++) { - struct obs_encoder *audio = output->audio_encoders[i]; - - if (audio && !audio->active && !audio->paired_encoder) - return audio; - } - - return NULL; -} - static inline void pair_encoders(obs_output_t *output) { size_t first_venc_idx; if (!get_first_video_encoder_index(output, &first_venc_idx)) return; struct obs_encoder *video = output->video_encoders[first_venc_idx]; - struct obs_encoder *audio = find_inactive_audio_encoder(output); - - if (video && audio) { - pthread_mutex_lock(&audio->init_mutex); - pthread_mutex_lock(&video->init_mutex); - - if (!audio->active && !video->active && - !video->paired_encoder && !audio->paired_encoder) { - audio->paired_encoder = video; - video->paired_encoder = audio; - } + pthread_mutex_lock(&video->init_mutex); + if (video->active) { pthread_mutex_unlock(&video->init_mutex); + return; + } + + for (size_t i = 0; i < MAX_OUTPUT_AUDIO_ENCODERS; i++) { + struct obs_encoder *audio = output->audio_encoders[i]; + if (!audio) + continue; + + pthread_mutex_lock(&audio->init_mutex); + if (!audio->active && !audio->paired_encoders.num) { + da_push_back(video->paired_encoders, &audio); + da_push_back(audio->paired_encoders, &video); + } pthread_mutex_unlock(&audio->init_mutex); } + pthread_mutex_unlock(&video->init_mutex); } bool obs_output_initialize_encoders(obs_output_t *output, uint32_t flags) diff --git a/libobs/obs-video-gpu-encode.c b/libobs/obs-video-gpu-encode.c index 892f152ab..40a1808a1 100644 --- a/libobs/obs-video-gpu-encode.c +++ b/libobs/obs-video-gpu-encode.c @@ -73,18 +73,29 @@ static void *gpu_encode_thread(struct obs_core_video_mix *video) uint32_t skip = 0; obs_encoder_t *encoder = encoders.array[i]; - struct obs_encoder *pair = encoder->paired_encoder; + struct obs_encoder **paired = + encoder->paired_encoders.array; + size_t num_paired = encoder->paired_encoders.num; pkt.timebase_num = encoder->timebase_num * encoder->frame_rate_divisor; pkt.timebase_den = encoder->timebase_den; pkt.encoder = encoder; - if (!encoder->first_received && pair) { - if (!pair->first_received || - pair->first_raw_ts > timestamp) { - continue; + if (!encoder->first_received && num_paired) { + bool wait_for_audio = false; + + for (size_t idx = 0; idx < num_paired; idx++) { + if (!paired[idx]->first_received || + paired[idx]->first_raw_ts > + timestamp) { + wait_for_audio = true; + break; + } } + + if (wait_for_audio) + continue; } if (video_pause_check(&encoder->pause, timestamp))