diff --git a/plugins/linux-capture/pipewire.c b/plugins/linux-capture/pipewire.c index 3f13a383e..147d35d31 100644 --- a/plugins/linux-capture/pipewire.c +++ b/plugins/linux-capture/pipewire.c @@ -85,6 +85,8 @@ struct _obs_pipewire_data { struct pw_stream *stream; struct spa_hook stream_listener; + struct spa_source *reneg; + struct spa_video_info format; struct { @@ -545,6 +547,48 @@ static void clear_format_info(obs_pipewire_data *obs_pw) da_free(obs_pw->format_info); } +static void remove_modifier_from_format(obs_pipewire_data *obs_pw, + uint32_t spa_format, uint64_t modifier) +{ + for (size_t i = 0; i < obs_pw->format_info.num; i++) { + if (obs_pw->format_info.array[i].spa_format != spa_format) + continue; + + int idx = da_find(obs_pw->format_info.array[i].modifiers, + &modifier, 0); + while (idx != -1) { + da_erase(obs_pw->format_info.array[i].modifiers, idx); + idx = da_find(obs_pw->format_info.array[i].modifiers, + &modifier, 0); + } + } +} + +static void renegotiate_format(void *data, uint64_t expirations) +{ + UNUSED_PARAMETER(expirations); + obs_pipewire_data *obs_pw = (obs_pipewire_data *)data; + const struct spa_pod **params = NULL; + + blog(LOG_DEBUG, "[pipewire] Renegotiating stream ..."); + + pw_thread_loop_lock(obs_pw->thread_loop); + + uint8_t params_buffer[2048]; + struct spa_pod_builder pod_builder = + SPA_POD_BUILDER_INIT(params_buffer, sizeof(params_buffer)); + uint32_t n_params; + if (!build_format_params(obs_pw, &pod_builder, ¶ms, &n_params)) { + teardown_pipewire(obs_pw); + pw_thread_loop_unlock(obs_pw->thread_loop); + return; + } + + pw_stream_update_params(obs_pw->stream, params, n_params); + pw_thread_loop_unlock(obs_pw->thread_loop); + bfree(params); +} + /* ------------------------------------------------- */ static void on_process_cb(void *user_data) @@ -622,6 +666,15 @@ static void on_process_cb(void *user_data) obs_pw->format.info.raw.size.height, drm_format, GS_BGRX, planes, fds, strides, offsets, modifierless ? NULL : modifiers); + + if (obs_pw->texture == NULL) { + remove_modifier_from_format( + obs_pw, obs_pw->format.info.raw.format, + obs_pw->format.info.raw.modifier); + pw_loop_signal_event( + pw_thread_loop_get_loop(obs_pw->thread_loop), + obs_pw->reneg); + } } else { blog(LOG_DEBUG, "[pipewire] Buffer has memory texture"); enum gs_color_format obs_format; @@ -869,6 +922,12 @@ static void play_pipewire_stream(obs_pipewire_data *obs_pw) pw_core_add_listener(obs_pw->core, &obs_pw->core_listener, &core_events, obs_pw); + /* Signal to renegotiate */ + obs_pw->reneg = + pw_loop_add_event(pw_thread_loop_get_loop(obs_pw->thread_loop), + renegotiate_format, obs_pw); + blog(LOG_DEBUG, "[pipewire] registered event %p", obs_pw->reneg); + // Dispatch to receive the info core event obs_pw->server_version_sync = pw_core_sync(obs_pw->core, PW_ID_CORE, obs_pw->server_version_sync);