Browse Source

linux-pipewire: Use list-based format selector for video capture

Negotiation is now made with the user selected format.

Also fixes a typo in the name of a structure.
tytan652 9 months ago
parent
commit
c11253bb08

+ 117 - 141
plugins/linux-pipewire/camera-portal.c

@@ -44,6 +44,11 @@ struct camera_portal_source {
 	obs_pipewire_stream *obs_pw_stream;
 	obs_pipewire_stream *obs_pw_stream;
 	char *device_id;
 	char *device_id;
 
 
+	bool restart_stream;
+
+	enum spa_media_subtype subtype;
+	struct obs_pw_video_format format;
+
 	struct {
 	struct {
 		struct spa_rectangle rect;
 		struct spa_rectangle rect;
 		bool set;
 		bool set;
@@ -242,7 +247,7 @@ static bool update_device_id(struct camera_portal_source *camera_source, const c
 
 
 static void stream_camera(struct camera_portal_source *camera_source)
 static void stream_camera(struct camera_portal_source *camera_source)
 {
 {
-	struct obs_pipwire_connect_stream_info connect_info;
+	struct obs_pipewire_connect_stream_info connect_info;
 	const struct spa_rectangle *resolution = NULL;
 	const struct spa_rectangle *resolution = NULL;
 	const struct spa_fraction *framerate = NULL;
 	const struct spa_fraction *framerate = NULL;
 	struct camera_device *device;
 	struct camera_device *device;
@@ -261,11 +266,13 @@ static void stream_camera(struct camera_portal_source *camera_source)
 	if (camera_source->framerate.set)
 	if (camera_source->framerate.set)
 		framerate = &camera_source->framerate.fraction;
 		framerate = &camera_source->framerate.fraction;
 
 
-	connect_info = (struct obs_pipwire_connect_stream_info){
+	connect_info = (struct obs_pipewire_connect_stream_info){
 		.stream_name = "OBS PipeWire Camera",
 		.stream_name = "OBS PipeWire Camera",
 		.stream_properties = pw_properties_new(PW_KEY_MEDIA_TYPE, "Video", PW_KEY_MEDIA_CATEGORY, "Capture",
 		.stream_properties = pw_properties_new(PW_KEY_MEDIA_TYPE, "Video", PW_KEY_MEDIA_CATEGORY, "Capture",
 						       PW_KEY_MEDIA_ROLE, "Camera", NULL),
 						       PW_KEY_MEDIA_ROLE, "Camera", NULL),
 		.video = {
 		.video = {
+			.subtype = &camera_source->subtype,
+			.format = &camera_source->format,
 			.resolution = resolution,
 			.resolution = resolution,
 			.framerate = framerate,
 			.framerate = framerate,
 		}};
 		}};
@@ -277,14 +284,17 @@ static void stream_camera(struct camera_portal_source *camera_source)
 static void camera_format_list(struct camera_device *dev, obs_property_t *prop)
 static void camera_format_list(struct camera_device *dev, obs_property_t *prop)
 {
 {
 	struct param *p;
 	struct param *p;
-	enum video_format last_format = VIDEO_FORMAT_NONE;
+	obs_data_t *data = NULL;
 
 
 	obs_property_list_clear(prop);
 	obs_property_list_clear(prop);
 
 
 	spa_list_for_each(p, &dev->param_list, link)
 	spa_list_for_each(p, &dev->param_list, link)
 	{
 	{
-		struct obs_pw_video_format obs_pw_video_format;
-		uint32_t media_type, media_subtype, format;
+		struct dstr str = {};
+		uint32_t media_type, media_subtype;
+		uint32_t format = 0;
+		const char *format_name;
+		struct spa_rectangle resolution;
 
 
 		if (p->id != SPA_PARAM_EnumFormat || p->param == NULL)
 		if (p->id != SPA_PARAM_EnumFormat || p->param == NULL)
 			continue;
 			continue;
@@ -293,24 +303,42 @@ static void camera_format_list(struct camera_device *dev, obs_property_t *prop)
 			continue;
 			continue;
 		if (media_type != SPA_MEDIA_TYPE_video)
 		if (media_type != SPA_MEDIA_TYPE_video)
 			continue;
 			continue;
+
+		g_clear_pointer(&data, obs_data_release);
+
+		data = obs_data_create();
+
 		if (media_subtype == SPA_MEDIA_SUBTYPE_raw) {
 		if (media_subtype == SPA_MEDIA_SUBTYPE_raw) {
+			struct obs_pw_video_format obs_pw_video_format;
+
 			if (spa_pod_parse_object(p->param, SPA_TYPE_OBJECT_Format, NULL, SPA_FORMAT_VIDEO_format,
 			if (spa_pod_parse_object(p->param, SPA_TYPE_OBJECT_Format, NULL, SPA_FORMAT_VIDEO_format,
 						 SPA_POD_Id(&format)) < 0)
 						 SPA_POD_Id(&format)) < 0)
 				continue;
 				continue;
-		} else {
-			format = SPA_VIDEO_FORMAT_ENCODED;
-		}
 
 
-		if (!obs_pw_video_format_from_spa_format(format, &obs_pw_video_format))
+			if (!obs_pw_video_format_from_spa_format(format, &obs_pw_video_format))
+				continue;
+
+			obs_data_set_bool(data, "encoded", false);
+			obs_data_set_int(data, "video_format", format);
+
+			format_name = obs_pw_video_format.pretty_name;
+		} else {
 			continue;
 			continue;
+		}
 
 
-		if (obs_pw_video_format.video_format == last_format)
+		if (spa_pod_parse_object(p->param, SPA_TYPE_OBJECT_Format, format ? &format : NULL,
+					 SPA_FORMAT_VIDEO_size, SPA_POD_OPT_Rectangle(&resolution)) < 0)
 			continue;
 			continue;
 
 
-		last_format = obs_pw_video_format.video_format;
+		obs_data_set_int(data, "width", resolution.width);
+		obs_data_set_int(data, "height", resolution.height);
 
 
-		obs_property_list_add_int(prop, obs_pw_video_format.pretty_name, format);
+		dstr_printf(&str, "%ux%u - %s", resolution.width, resolution.height, format_name);
+		obs_property_list_add_string(prop, str.array, obs_data_get_json(data));
+		dstr_free(&str);
 	}
 	}
+
+	g_clear_pointer(&data, obs_data_release);
 }
 }
 
 
 static bool control_changed(void *data, obs_properties_t *props, obs_property_t *prop, obs_data_t *settings)
 static bool control_changed(void *data, obs_properties_t *props, obs_property_t *prop, obs_data_t *settings)
@@ -479,12 +507,11 @@ static bool device_selected(void *data, obs_properties_t *props, obs_property_t
 	if (device == NULL)
 	if (device == NULL)
 		return false;
 		return false;
 
 
-	if (update_device_id(camera_source, device_id))
-		stream_camera(camera_source);
+	camera_source->restart_stream = update_device_id(camera_source, device_id);
 
 
 	blog(LOG_INFO, "[camera-portal] Updating pixel formats");
 	blog(LOG_INFO, "[camera-portal] Updating pixel formats");
 
 
-	property = obs_properties_get(props, "pixelformat");
+	property = obs_properties_get(props, "format");
 	new_control_properties = obs_properties_create();
 	new_control_properties = obs_properties_create();
 	obs_properties_remove_by_name(props, "controls");
 	obs_properties_remove_by_name(props, "controls");
 
 
@@ -499,108 +526,6 @@ static bool device_selected(void *data, obs_properties_t *props, obs_property_t
 	return true;
 	return true;
 }
 }
 
 
-static int sort_resolutions(gconstpointer a, gconstpointer b)
-{
-	const struct spa_rectangle *resolution_a = a;
-	const struct spa_rectangle *resolution_b = b;
-	int64_t area_a = resolution_a->width * resolution_a->height;
-	int64_t area_b = resolution_b->width * resolution_b->height;
-
-	return area_a - area_b;
-}
-
-static void resolution_list(struct camera_device *dev, uint32_t pixelformat, obs_property_t *prop)
-{
-	struct spa_rectangle last_resolution = SPA_RECTANGLE(0, 0);
-	g_autoptr(GArray) resolutions = NULL;
-	struct param *p;
-	obs_data_t *data;
-
-	resolutions = g_array_new(FALSE, FALSE, sizeof(struct spa_rectangle));
-
-	spa_list_for_each(p, &dev->param_list, link)
-	{
-		struct obs_pw_video_format obs_pw_video_format;
-		struct spa_rectangle resolution;
-		uint32_t media_type, media_subtype, format;
-
-		if (p->id != SPA_PARAM_EnumFormat || p->param == NULL)
-			continue;
-
-		if (spa_format_parse(p->param, &media_type, &media_subtype) < 0)
-			continue;
-		if (media_type != SPA_MEDIA_TYPE_video)
-			continue;
-		if (media_subtype == SPA_MEDIA_SUBTYPE_raw) {
-			if (spa_pod_parse_object(p->param, SPA_TYPE_OBJECT_Format, NULL, SPA_FORMAT_VIDEO_format,
-						 SPA_POD_Id(&format)) < 0)
-				continue;
-		} else {
-			format = SPA_VIDEO_FORMAT_ENCODED;
-		}
-
-		if (!obs_pw_video_format_from_spa_format(format, &obs_pw_video_format))
-			continue;
-
-		if (obs_pw_video_format.video_format != pixelformat)
-			continue;
-
-		if (spa_pod_parse_object(p->param, SPA_TYPE_OBJECT_Format, NULL, SPA_FORMAT_VIDEO_size,
-					 SPA_POD_OPT_Rectangle(&resolution)) < 0)
-			continue;
-
-		if (resolution.width == last_resolution.width && resolution.height == last_resolution.height)
-			continue;
-
-		last_resolution = resolution;
-		g_array_append_val(resolutions, resolution);
-	}
-
-	g_array_sort(resolutions, sort_resolutions);
-
-	obs_property_list_clear(prop);
-
-	data = obs_data_create();
-	for (size_t i = 0; i < resolutions->len; i++) {
-		const struct spa_rectangle *resolution = &g_array_index(resolutions, struct spa_rectangle, i);
-		struct dstr str = {};
-
-		dstr_printf(&str, "%ux%u", resolution->width, resolution->height);
-
-		obs_data_set_int(data, "width", resolution->width);
-		obs_data_set_int(data, "height", resolution->height);
-
-		obs_property_list_add_string(prop, str.array, obs_data_get_json(data));
-
-		dstr_free(&str);
-	}
-	obs_data_release(data);
-}
-
-/*
- * Format selected callback
- */
-static bool format_selected(void *data, obs_properties_t *properties, obs_property_t *property, obs_data_t *settings)
-{
-	UNUSED_PARAMETER(property);
-	UNUSED_PARAMETER(settings);
-
-	struct camera_portal_source *camera_source = data;
-	struct camera_device *device;
-	obs_property_t *resolution;
-
-	blog(LOG_INFO, "[camera-portal] Selected format for '%s'", camera_source->device_id);
-
-	device = g_hash_table_lookup(connection->devices, camera_source->device_id);
-	if (device == NULL)
-		return false;
-
-	resolution = obs_properties_get(properties, "resolution");
-	resolution_list(device, obs_data_get_int(settings, "pixelformat"), resolution);
-
-	return true;
-}
-
 static int compare_framerates(gconstpointer a, gconstpointer b)
 static int compare_framerates(gconstpointer a, gconstpointer b)
 {
 {
 	const struct spa_fraction *framerate_a = a;
 	const struct spa_fraction *framerate_a = a;
@@ -760,47 +685,68 @@ static bool framerate_selected(void *data, obs_properties_t *properties, obs_pro
 }
 }
 
 
 /*
 /*
- * Resolution selected callback
+ * Format selected callback
  */
  */
-
-static bool parse_resolution(struct spa_rectangle *dest, const char *json)
+static bool parse_format(struct camera_portal_source *dest, const char *json)
 {
 {
 	obs_data_t *data = obs_data_create_from_json(json);
 	obs_data_t *data = obs_data_create_from_json(json);
+	bool ret = false;
 
 
 	if (!data)
 	if (!data)
 		return false;
 		return false;
 
 
-	dest->width = obs_data_get_int(data, "width");
-	dest->height = obs_data_get_int(data, "height");
+	if (obs_data_has_user_value(data, "video_format") && obs_data_has_user_value(data, "encoded")) {
+		struct obs_pw_video_format format;
+
+		if (obs_data_get_bool(data, "encoded")) {
+			dest->subtype = obs_data_get_int(data, "video_format");
+			ret = true;
+		} else if (obs_pw_video_format_from_spa_format(obs_data_get_int(data, "video_format"), &format)) {
+			dest->subtype = SPA_MEDIA_SUBTYPE_raw;
+			dest->format = format;
+			ret = true;
+		}
+
+		if (obs_data_has_user_value(data, "width") && obs_data_has_user_value(data, "height")) {
+			dest->resolution.rect.width = obs_data_get_int(data, "width");
+			dest->resolution.rect.height = obs_data_get_int(data, "height");
+			dest->resolution.set = true;
+		}
+	}
+
 	obs_data_release(data);
 	obs_data_release(data);
-	return true;
+	return ret;
 }
 }
 
 
-static bool resolution_selected(void *data, obs_properties_t *properties, obs_property_t *property,
-				obs_data_t *settings)
+static bool format_selected(void *data, obs_properties_t *properties, obs_property_t *property, obs_data_t *settings)
 {
 {
-	UNUSED_PARAMETER(properties);
 	UNUSED_PARAMETER(property);
 	UNUSED_PARAMETER(property);
 	UNUSED_PARAMETER(settings);
 	UNUSED_PARAMETER(settings);
 
 
 	struct camera_portal_source *camera_source = data;
 	struct camera_portal_source *camera_source = data;
-	struct spa_rectangle resolution;
 	struct camera_device *device;
 	struct camera_device *device;
+	enum spa_media_subtype last_subtype = camera_source->subtype;
+	enum spa_video_format last_format = camera_source->format.spa_format;
 
 
-	blog(LOG_INFO, "[camera-portal] Selected resolution for '%s'", camera_source->device_id);
+	blog(LOG_INFO, "[camera-portal] Selected format for '%s'", camera_source->device_id);
 
 
 	device = g_hash_table_lookup(connection->devices, camera_source->device_id);
 	device = g_hash_table_lookup(connection->devices, camera_source->device_id);
 	if (device == NULL)
 	if (device == NULL)
 		return false;
 		return false;
 
 
-	if (!parse_resolution(&resolution, obs_data_get_string(settings, "resolution")))
+	if (!parse_format(camera_source, obs_data_get_string(settings, "format")))
 		return false;
 		return false;
 
 
-	if (camera_source->obs_pw_stream)
-		obs_pipewire_stream_set_resolution(camera_source->obs_pw_stream, &resolution);
+	if (!camera_source->obs_pw_stream || camera_source->restart_stream || last_subtype != camera_source->subtype ||
+	    last_format != camera_source->format.spa_format) {
+		camera_source->restart_stream = false;
+		stream_camera(camera_source);
+	} else if (camera_source->obs_pw_stream) {
+		obs_pipewire_stream_set_resolution(camera_source->obs_pw_stream, &camera_source->resolution.rect);
+	}
 
 
 	property = obs_properties_get(properties, "framerate");
 	property = obs_properties_get(properties, "framerate");
-	framerate_list(device, obs_data_get_int(settings, "pixelformat"), &resolution, property);
+	framerate_list(device, camera_source->format.spa_format, &camera_source->resolution.rect, property);
 
 
 	return true;
 	return true;
 }
 }
@@ -1116,6 +1062,19 @@ static const char *pipewire_camera_get_name(void *data)
 	return obs_module_text("PipeWireCamera");
 	return obs_module_text("PipeWireCamera");
 }
 }
 
 
+static bool parse_resolution(struct spa_rectangle *dest, const char *json)
+{
+	obs_data_t *data = obs_data_create_from_json(json);
+
+	if (!data)
+		return false;
+
+	dest->width = obs_data_get_int(data, "width");
+	dest->height = obs_data_get_int(data, "height");
+	obs_data_release(data);
+	return true;
+}
+
 static void *pipewire_camera_create(obs_data_t *settings, obs_source_t *source)
 static void *pipewire_camera_create(obs_data_t *settings, obs_source_t *source)
 {
 {
 	struct camera_portal_source *camera_source;
 	struct camera_portal_source *camera_source;
@@ -1125,8 +1084,30 @@ static void *pipewire_camera_create(obs_data_t *settings, obs_source_t *source)
 	camera_source->device_id = bstrdup(obs_data_get_string(settings, "device_id"));
 	camera_source->device_id = bstrdup(obs_data_get_string(settings, "device_id"));
 	camera_source->framerate.set =
 	camera_source->framerate.set =
 		parse_framerate(&camera_source->framerate.fraction, obs_data_get_string(settings, "framerate"));
 		parse_framerate(&camera_source->framerate.fraction, obs_data_get_string(settings, "framerate"));
-	camera_source->resolution.set =
-		parse_resolution(&camera_source->resolution.rect, obs_data_get_string(settings, "resolution"));
+
+	if (obs_data_has_user_value(settings, "format")) {
+		parse_format(camera_source, obs_data_get_string(settings, "format"));
+	} else if (obs_pw_video_format_from_spa_format(obs_data_get_int(settings, "pixelformat"),
+						       &camera_source->format)) {
+		camera_source->subtype = SPA_MEDIA_SUBTYPE_raw;
+
+		camera_source->resolution.set =
+			parse_resolution(&camera_source->resolution.rect, obs_data_get_string(settings, "resolution"));
+
+		/* NOTE: We can convert to the new format only if resolution is available */
+		if (camera_source->resolution.set) {
+			obs_data_t *format = obs_data_create();
+
+			obs_data_set_bool(format, "encoded", false);
+			obs_data_set_int(format, "video_format", camera_source->format.spa_format);
+			obs_data_set_int(format, "width", camera_source->resolution.rect.width);
+			obs_data_set_int(format, "height", camera_source->resolution.rect.height);
+
+			obs_data_set_string(settings, "format", obs_data_get_json(format));
+
+			obs_data_release(format);
+		}
+	}
 
 
 	access_camera(camera_source);
 	access_camera(camera_source);
 
 
@@ -1156,7 +1137,6 @@ static obs_properties_t *pipewire_camera_get_properties(void *data)
 	struct camera_portal_source *camera_source = data;
 	struct camera_portal_source *camera_source = data;
 	obs_properties_t *controls_props;
 	obs_properties_t *controls_props;
 	obs_properties_t *props;
 	obs_properties_t *props;
-	obs_property_t *resolution_list;
 	obs_property_t *framerate_list;
 	obs_property_t *framerate_list;
 	obs_property_t *device_list;
 	obs_property_t *device_list;
 	obs_property_t *format_list;
 	obs_property_t *format_list;
@@ -1166,11 +1146,8 @@ static obs_properties_t *pipewire_camera_get_properties(void *data)
 	device_list = obs_properties_add_list(props, "device_id", obs_module_text("PipeWireCameraDevice"),
 	device_list = obs_properties_add_list(props, "device_id", obs_module_text("PipeWireCameraDevice"),
 					      OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_STRING);
 					      OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_STRING);
 
 
-	format_list = obs_properties_add_list(props, "pixelformat", obs_module_text("VideoFormat"), OBS_COMBO_TYPE_LIST,
-					      OBS_COMBO_FORMAT_INT);
-
-	resolution_list = obs_properties_add_list(props, "resolution", obs_module_text("Resolution"),
-						  OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_STRING);
+	format_list = obs_properties_add_list(props, "format", obs_module_text("VideoFormat"), OBS_COMBO_TYPE_LIST,
+					      OBS_COMBO_FORMAT_STRING);
 
 
 	framerate_list = obs_properties_add_list(props, "framerate", obs_module_text("FrameRate"), OBS_COMBO_TYPE_LIST,
 	framerate_list = obs_properties_add_list(props, "framerate", obs_module_text("FrameRate"), OBS_COMBO_TYPE_LIST,
 						 OBS_COMBO_FORMAT_STRING);
 						 OBS_COMBO_FORMAT_STRING);
@@ -1184,7 +1161,6 @@ static obs_properties_t *pipewire_camera_get_properties(void *data)
 
 
 	obs_property_set_modified_callback2(device_list, device_selected, camera_source);
 	obs_property_set_modified_callback2(device_list, device_selected, camera_source);
 	obs_property_set_modified_callback2(format_list, format_selected, camera_source);
 	obs_property_set_modified_callback2(format_list, format_selected, camera_source);
-	obs_property_set_modified_callback2(resolution_list, resolution_selected, camera_source);
 	obs_property_set_modified_callback2(framerate_list, framerate_selected, camera_source);
 	obs_property_set_modified_callback2(framerate_list, framerate_selected, camera_source);
 
 
 	return props;
 	return props;

+ 0 - 1
plugins/linux-pipewire/data/locale/en-US.ini

@@ -7,6 +7,5 @@ PipeWireSelectMonitor="Select Monitor"
 PipeWireSelectWindow="Select Window"
 PipeWireSelectWindow="Select Window"
 PipeWireWindowCapture="Window Capture (PipeWire)"
 PipeWireWindowCapture="Window Capture (PipeWire)"
 PipeWireSelectScreenCast="Open Selector"
 PipeWireSelectScreenCast="Open Selector"
-Resolution="Resolution"
 ShowCursor="Show Cursor"
 ShowCursor="Show Cursor"
 VideoFormat="Video Format"
 VideoFormat="Video Format"

+ 21 - 10
plugins/linux-pipewire/pipewire.c

@@ -484,17 +484,28 @@ static void init_format_info_sync(obs_pipewire_stream *obs_pw_stream)
 	bfree(drm_formats);
 	bfree(drm_formats);
 }
 }
 
 
-static void init_format_info(obs_pipewire_stream *obs_pw_stream)
+static void init_format_info(obs_pipewire_stream *obs_pw_stream, const struct obs_pw_video_format *selected_format)
 {
 {
-	uint32_t output_flags;
+	if (selected_format) {
+		struct format_info *info;
 
 
-	output_flags = obs_source_get_output_flags(obs_pw_stream->source);
+		da_init(obs_pw_stream->format_info);
 
 
-	if (output_flags & OBS_SOURCE_VIDEO) {
-		if (output_flags & OBS_SOURCE_ASYNC)
-			init_format_info_async(obs_pw_stream);
-		else
-			init_format_info_sync(obs_pw_stream);
+		info = da_push_back_new(obs_pw_stream->format_info);
+		da_init(info->modifiers);
+		info->spa_format = selected_format->spa_format;
+		info->drm_format = selected_format->drm_format;
+	} else {
+		uint32_t output_flags;
+
+		output_flags = obs_source_get_output_flags(obs_pw_stream->source);
+
+		if (output_flags & OBS_SOURCE_VIDEO) {
+			if (output_flags & OBS_SOURCE_ASYNC)
+				init_format_info_async(obs_pw_stream);
+			else
+				init_format_info_sync(obs_pw_stream);
+		}
 	}
 	}
 }
 }
 
 
@@ -1179,7 +1190,7 @@ void obs_pipewire_destroy(obs_pipewire *obs_pw)
 }
 }
 
 
 obs_pipewire_stream *obs_pipewire_connect_stream(obs_pipewire *obs_pw, obs_source_t *source, int pipewire_node,
 obs_pipewire_stream *obs_pipewire_connect_stream(obs_pipewire *obs_pw, obs_source_t *source, int pipewire_node,
-						 const struct obs_pipwire_connect_stream_info *connect_info)
+						 const struct obs_pipewire_connect_stream_info *connect_info)
 {
 {
 	struct spa_pod_builder pod_builder;
 	struct spa_pod_builder pod_builder;
 	const struct spa_pod **params = NULL;
 	const struct spa_pod **params = NULL;
@@ -1204,7 +1215,7 @@ obs_pipewire_stream *obs_pipewire_connect_stream(obs_pipewire *obs_pw, obs_sourc
 	if (obs_pw_stream->resolution.set)
 	if (obs_pw_stream->resolution.set)
 		obs_pw_stream->resolution.rect = *connect_info->video.resolution;
 		obs_pw_stream->resolution.rect = *connect_info->video.resolution;
 
 
-	init_format_info(obs_pw_stream);
+	init_format_info(obs_pw_stream, connect_info->video.format);
 
 
 	pw_thread_loop_lock(obs_pw->thread_loop);
 	pw_thread_loop_lock(obs_pw->thread_loop);
 
 

+ 4 - 2
plugins/linux-pipewire/pipewire.h

@@ -27,13 +27,15 @@
 typedef struct _obs_pipewire obs_pipewire;
 typedef struct _obs_pipewire obs_pipewire;
 typedef struct _obs_pipewire_stream obs_pipewire_stream;
 typedef struct _obs_pipewire_stream obs_pipewire_stream;
 
 
-struct obs_pipwire_connect_stream_info {
+struct obs_pipewire_connect_stream_info {
 	const char *stream_name;
 	const char *stream_name;
 	struct pw_properties *stream_properties;
 	struct pw_properties *stream_properties;
 	struct {
 	struct {
 		bool cursor_visible;
 		bool cursor_visible;
 	} screencast;
 	} screencast;
 	struct {
 	struct {
+		const enum spa_media_subtype *subtype;
+		const struct obs_pw_video_format *format;
 		const struct spa_rectangle *resolution;
 		const struct spa_rectangle *resolution;
 		const struct spa_fraction *framerate;
 		const struct spa_fraction *framerate;
 	} video;
 	} video;
@@ -46,7 +48,7 @@ void obs_pipewire_roundtrip(obs_pipewire *obs_pw);
 void obs_pipewire_destroy(obs_pipewire *obs_pw);
 void obs_pipewire_destroy(obs_pipewire *obs_pw);
 
 
 obs_pipewire_stream *obs_pipewire_connect_stream(obs_pipewire *obs_pw, obs_source_t *source, int pipewire_node,
 obs_pipewire_stream *obs_pipewire_connect_stream(obs_pipewire *obs_pw, obs_source_t *source, int pipewire_node,
-						 const struct obs_pipwire_connect_stream_info *connect_info);
+						 const struct obs_pipewire_connect_stream_info *connect_info);
 
 
 void obs_pipewire_stream_show(obs_pipewire_stream *obs_pw_stream);
 void obs_pipewire_stream_show(obs_pipewire_stream *obs_pw_stream);
 void obs_pipewire_stream_hide(obs_pipewire_stream *obs_pw_stream);
 void obs_pipewire_stream_hide(obs_pipewire_stream *obs_pw_stream);

+ 2 - 2
plugins/linux-pipewire/screencast-portal.c

@@ -153,7 +153,7 @@ static const char *capture_type_to_string(enum obs_portal_capture_type capture_t
 
 
 static void on_pipewire_remote_opened_cb(GObject *source, GAsyncResult *res, void *user_data)
 static void on_pipewire_remote_opened_cb(GObject *source, GAsyncResult *res, void *user_data)
 {
 {
-	struct obs_pipwire_connect_stream_info connect_info;
+	struct obs_pipewire_connect_stream_info connect_info;
 	struct screencast_portal_capture *capture;
 	struct screencast_portal_capture *capture;
 	g_autoptr(GUnixFDList) fd_list = NULL;
 	g_autoptr(GUnixFDList) fd_list = NULL;
 	g_autoptr(GVariant) result = NULL;
 	g_autoptr(GVariant) result = NULL;
@@ -183,7 +183,7 @@ static void on_pipewire_remote_opened_cb(GObject *source, GAsyncResult *res, voi
 	if (!capture->obs_pw)
 	if (!capture->obs_pw)
 		return;
 		return;
 
 
-	connect_info = (struct obs_pipwire_connect_stream_info){
+	connect_info = (struct obs_pipewire_connect_stream_info){
 		.stream_name = "OBS Studio",
 		.stream_name = "OBS Studio",
 		.stream_properties = pw_properties_new(PW_KEY_MEDIA_TYPE, "Video", PW_KEY_MEDIA_CATEGORY, "Capture",
 		.stream_properties = pw_properties_new(PW_KEY_MEDIA_TYPE, "Video", PW_KEY_MEDIA_CATEGORY, "Capture",
 						       PW_KEY_MEDIA_ROLE, "Screen", NULL),
 						       PW_KEY_MEDIA_ROLE, "Screen", NULL),