screen-cast-stream-src: Use dynamic buffer allocations

In order to allow arbitrary number of formats, modifiers and other
parameters. This makes the code more robust and easier to adapt.

Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3617>
This commit is contained in:
Robert Mader 2024-03-04 11:54:26 +01:00 committed by Marge Bot
parent 774d0ad0bc
commit 77186c2063

View File

@ -28,6 +28,7 @@
#include <spa/param/props.h> #include <spa/param/props.h>
#include <spa/param/format-utils.h> #include <spa/param/format-utils.h>
#include <spa/param/video/format-utils.h> #include <spa/param/video/format-utils.h>
#include <spa/pod/dynamic.h>
#include <spa/utils/result.h> #include <spa/utils/result.h>
#include <stdint.h> #include <stdint.h>
#include <sys/mman.h> #include <sys/mman.h>
@ -162,60 +163,67 @@ cogl_pixel_format_from_spa_video_format (enum spa_video_format spa_format,
} }
static struct spa_pod * static struct spa_pod *
push_format_object (struct spa_pod_builder *pod_builder, push_format_object (enum spa_video_format format,
enum spa_video_format format,
uint64_t *modifiers, uint64_t *modifiers,
int n_modifiers, int n_modifiers,
gboolean fixate_modifier, gboolean fixate_modifier,
...) ...)
{ {
struct spa_pod_frame pod_frames[2]; struct spa_pod_dynamic_builder pod_builder;
struct spa_pod_frame pod_frame;
va_list args; va_list args;
spa_pod_builder_push_object (pod_builder, &pod_frames[0], spa_pod_dynamic_builder_init (&pod_builder, NULL, 0, 1024);
SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat);
spa_pod_builder_add (pod_builder, spa_pod_builder_push_object (&pod_builder.b,
&pod_frame,
SPA_TYPE_OBJECT_Format,
SPA_PARAM_EnumFormat);
spa_pod_builder_add (&pod_builder.b,
SPA_FORMAT_mediaType, SPA_FORMAT_mediaType,
SPA_POD_Id (SPA_MEDIA_TYPE_video), SPA_POD_Id (SPA_MEDIA_TYPE_video),
0); 0);
spa_pod_builder_add (pod_builder, spa_pod_builder_add (&pod_builder.b,
SPA_FORMAT_mediaSubtype, SPA_FORMAT_mediaSubtype,
SPA_POD_Id (SPA_MEDIA_SUBTYPE_raw), SPA_POD_Id (SPA_MEDIA_SUBTYPE_raw),
0); 0);
spa_pod_builder_add (pod_builder, spa_pod_builder_add (&pod_builder.b,
SPA_FORMAT_VIDEO_format, SPA_POD_Id (format), SPA_FORMAT_VIDEO_format,
SPA_POD_Id (format),
0); 0);
if (n_modifiers > 0) if (n_modifiers > 0)
{ {
if (fixate_modifier) if (fixate_modifier)
{ {
spa_pod_builder_prop (pod_builder, spa_pod_builder_prop (&pod_builder.b,
SPA_FORMAT_VIDEO_modifier, SPA_FORMAT_VIDEO_modifier,
SPA_POD_PROP_FLAG_MANDATORY); SPA_POD_PROP_FLAG_MANDATORY);
spa_pod_builder_long (pod_builder, modifiers[0]); spa_pod_builder_long (&pod_builder.b, modifiers[0]);
} }
else else
{ {
struct spa_pod_frame pod_frame_mods;
int i; int i;
spa_pod_builder_prop (pod_builder, spa_pod_builder_prop (&pod_builder.b,
SPA_FORMAT_VIDEO_modifier, SPA_FORMAT_VIDEO_modifier,
(SPA_POD_PROP_FLAG_MANDATORY | (SPA_POD_PROP_FLAG_MANDATORY |
SPA_POD_PROP_FLAG_DONT_FIXATE)); SPA_POD_PROP_FLAG_DONT_FIXATE));
spa_pod_builder_push_choice (pod_builder, &pod_frames[1], spa_pod_builder_push_choice (&pod_builder.b,
&pod_frame_mods,
SPA_CHOICE_Enum, SPA_CHOICE_Enum,
0); 0);
spa_pod_builder_long (pod_builder, modifiers[0]); spa_pod_builder_long (&pod_builder.b, modifiers[0]);
for (i = 0; i < n_modifiers; i++) for (i = 0; i < n_modifiers; i++)
spa_pod_builder_long (pod_builder, modifiers[i]); spa_pod_builder_long (&pod_builder.b, modifiers[i]);
spa_pod_builder_pop (pod_builder, &pod_frames[1]); spa_pod_builder_pop (&pod_builder.b, &pod_frame_mods);
} }
} }
va_start (args, fixate_modifier); va_start (args, fixate_modifier);
spa_pod_builder_addv (pod_builder, args); spa_pod_builder_addv (&pod_builder.b, args);
va_end (args); va_end (args);
return spa_pod_builder_pop (pod_builder, &pod_frames[0]); return spa_pod_builder_pop (&pod_builder.b, &pod_frame);
} }
static void static void
@ -973,9 +981,7 @@ meta_screen_cast_stream_src_close (MetaScreenCastStreamSrc *src)
static void static void
build_format_params (MetaScreenCastStreamSrc *src, build_format_params (MetaScreenCastStreamSrc *src,
struct spa_pod_builder *pod_builder, GPtrArray *params)
const struct spa_pod **params,
uint32_t *n_params)
{ {
MetaScreenCastStream *stream = MetaScreenCastStream *stream =
meta_screen_cast_stream_src_get_stream (src); meta_screen_cast_stream_src_get_stream (src);
@ -997,6 +1003,7 @@ build_format_params (MetaScreenCastStreamSrc *src,
struct spa_fraction default_framerate = DEFAULT_FRAME_RATE; struct spa_fraction default_framerate = DEFAULT_FRAME_RATE;
struct spa_fraction min_framerate = MIN_FRAME_RATE; struct spa_fraction min_framerate = MIN_FRAME_RATE;
struct spa_fraction max_framerate = MAX_FRAME_RATE; struct spa_fraction max_framerate = MAX_FRAME_RATE;
struct spa_pod *pod;
int width; int width;
int height; int height;
float frame_rate; float frame_rate;
@ -1045,8 +1052,7 @@ build_format_params (MetaScreenCastStreamSrc *src,
if (modifiers->len == 0) if (modifiers->len == 0)
continue; continue;
params[(*n_params)++] = push_format_object ( pod = push_format_object (
pod_builder,
spa_video_formats[i], (uint64_t *) modifiers->data, modifiers->len, FALSE, spa_video_formats[i], (uint64_t *) modifiers->data, modifiers->len, FALSE,
SPA_FORMAT_VIDEO_size, SPA_POD_CHOICE_RANGE_Rectangle (&default_size, SPA_FORMAT_VIDEO_size, SPA_POD_CHOICE_RANGE_Rectangle (&default_size,
&min_size, &min_size,
@ -1057,11 +1063,11 @@ build_format_params (MetaScreenCastStreamSrc *src,
&min_framerate, &min_framerate,
&max_framerate), &max_framerate),
0); 0);
g_ptr_array_add (params, g_steal_pointer (&pod));
} }
for (i = 0; i < n_spa_video_formats; i++) for (i = 0; i < n_spa_video_formats; i++)
{ {
params[(*n_params)++] = push_format_object ( pod = push_format_object (
pod_builder,
spa_video_formats[i], NULL, 0, FALSE, spa_video_formats[i], NULL, 0, FALSE,
SPA_FORMAT_VIDEO_size, SPA_POD_CHOICE_RANGE_Rectangle (&default_size, SPA_FORMAT_VIDEO_size, SPA_POD_CHOICE_RANGE_Rectangle (&default_size,
&min_size, &min_size,
@ -1072,6 +1078,7 @@ build_format_params (MetaScreenCastStreamSrc *src,
&min_framerate, &min_framerate,
&max_framerate), &max_framerate),
0); 0);
g_ptr_array_add (params, g_steal_pointer (&pod));
} }
} }
@ -1080,14 +1087,14 @@ renegotiate_pipewire_stream (MetaScreenCastStreamSrc *src)
{ {
MetaScreenCastStreamSrcPrivate *priv = MetaScreenCastStreamSrcPrivate *priv =
meta_screen_cast_stream_src_get_instance_private (src); meta_screen_cast_stream_src_get_instance_private (src);
uint8_t buffer[1024]; g_autoptr (GPtrArray) params = NULL;
struct spa_pod_builder pod_builder;
const struct spa_pod *params[4];
uint32_t n_params = 0;
pod_builder = SPA_POD_BUILDER_INIT (buffer, sizeof (buffer)); params = g_ptr_array_new_full (16, (GDestroyNotify) free);
build_format_params (src, &pod_builder, params, &n_params); build_format_params (src, params);
pw_stream_update_params (priv->pipewire_stream, params, n_params);
pw_stream_update_params (priv->pipewire_stream,
(const struct spa_pod **) params->pdata,
params->len);
} }
static void static void
@ -1131,20 +1138,23 @@ on_stream_state_changed (void *data,
} }
static void static void
add_video_damage_meta_param (struct spa_pod_builder *pod_builder, add_video_damage_meta_param (GPtrArray *params)
const struct spa_pod **params,
int idx)
{ {
struct spa_pod_dynamic_builder pod_builder;
struct spa_pod *pod;
const size_t meta_region_size = sizeof (struct spa_meta_region); const size_t meta_region_size = sizeof (struct spa_meta_region);
params[idx] = spa_pod_builder_add_object ( spa_pod_dynamic_builder_init (&pod_builder, NULL, 0, 1024);
pod_builder,
pod = spa_pod_builder_add_object (
&pod_builder.b,
SPA_TYPE_OBJECT_ParamMeta, SPA_PARAM_Meta, SPA_TYPE_OBJECT_ParamMeta, SPA_PARAM_Meta,
SPA_PARAM_META_type, SPA_POD_Id (SPA_META_VideoDamage), SPA_PARAM_META_type, SPA_POD_Id (SPA_META_VideoDamage),
SPA_PARAM_META_size, SPA_PARAM_META_size,
SPA_POD_CHOICE_RANGE_Int (meta_region_size * NUM_DAMAGED_RECTS, SPA_POD_CHOICE_RANGE_Int (meta_region_size * NUM_DAMAGED_RECTS,
meta_region_size * 1, meta_region_size * 1,
meta_region_size * NUM_DAMAGED_RECTS)); meta_region_size * NUM_DAMAGED_RECTS));
g_ptr_array_add (params, g_steal_pointer (&pod));
} }
static void static void
@ -1157,20 +1167,20 @@ on_stream_param_changed (void *data,
meta_screen_cast_stream_src_get_instance_private (src); meta_screen_cast_stream_src_get_instance_private (src);
MetaScreenCastStreamSrcClass *klass = MetaScreenCastStreamSrcClass *klass =
META_SCREEN_CAST_STREAM_SRC_GET_CLASS (src); META_SCREEN_CAST_STREAM_SRC_GET_CLASS (src);
uint8_t params_buffer[1024]; struct spa_pod_dynamic_builder pod_builder;
struct spa_pod_builder pod_builder; struct spa_pod *pod;
const struct spa_pod *params[5]; g_autoptr (GPtrArray) params = NULL;
uint32_t n_params = 0;
int buffer_types; int buffer_types;
const struct spa_pod_prop *prop_modifier; const struct spa_pod_prop *prop_modifier;
if (!format || id != SPA_PARAM_Format) if (!format || id != SPA_PARAM_Format)
return; return;
params = g_ptr_array_new_full (16, (GDestroyNotify) free);
spa_format_video_raw_parse (format, spa_format_video_raw_parse (format,
&priv->video_format); &priv->video_format);
pod_builder = SPA_POD_BUILDER_INIT (params_buffer, sizeof (params_buffer));
prop_modifier = spa_pod_find_prop (format, NULL, SPA_FORMAT_VIDEO_modifier); prop_modifier = spa_pod_find_prop (format, NULL, SPA_FORMAT_VIDEO_modifier);
if (prop_modifier) if (prop_modifier)
@ -1227,8 +1237,7 @@ on_stream_param_changed (void *data,
priv->video_format.size.height, priv->video_format.size.height,
&preferred_modifier)) &preferred_modifier))
{ {
params[n_params++] = push_format_object ( pod = push_format_object (
&pod_builder,
priv->video_format.format, &preferred_modifier, 1, TRUE, priv->video_format.format, &preferred_modifier, 1, TRUE,
SPA_FORMAT_VIDEO_size, SPA_POD_Rectangle (&priv->video_format.size), SPA_FORMAT_VIDEO_size, SPA_POD_Rectangle (&priv->video_format.size),
SPA_FORMAT_VIDEO_framerate, SPA_POD_Fraction (&SPA_FRACTION (0, 1)), SPA_FORMAT_VIDEO_framerate, SPA_POD_Fraction (&SPA_FRACTION (0, 1)),
@ -1237,43 +1246,56 @@ on_stream_param_changed (void *data,
&MIN_FRAME_RATE, &MIN_FRAME_RATE,
&priv->video_format.max_framerate), &priv->video_format.max_framerate),
0); 0);
g_ptr_array_add (params, g_steal_pointer (&pod));
} }
build_format_params (src, &pod_builder, params, &n_params); build_format_params (src, params);
pw_stream_update_params (priv->pipewire_stream, params, n_params); pw_stream_update_params (priv->pipewire_stream,
(const struct spa_pod **) params->pdata,
params->len);
return; return;
} }
params[n_params++] = spa_pod_builder_add_object ( spa_pod_dynamic_builder_init (&pod_builder, NULL, 0, 1024);
&pod_builder, pod = spa_pod_builder_add_object (
&pod_builder.b,
SPA_TYPE_OBJECT_ParamBuffers, SPA_PARAM_Buffers, SPA_TYPE_OBJECT_ParamBuffers, SPA_PARAM_Buffers,
SPA_PARAM_BUFFERS_buffers, SPA_POD_CHOICE_RANGE_Int (16, 2, 16), SPA_PARAM_BUFFERS_buffers, SPA_POD_CHOICE_RANGE_Int (16, 2, 16),
SPA_PARAM_BUFFERS_blocks, SPA_POD_Int (1), SPA_PARAM_BUFFERS_blocks, SPA_POD_Int (1),
SPA_PARAM_BUFFERS_align, SPA_POD_Int (16), SPA_PARAM_BUFFERS_align, SPA_POD_Int (16),
SPA_PARAM_BUFFERS_dataType, SPA_POD_CHOICE_FLAGS_Int (buffer_types)); SPA_PARAM_BUFFERS_dataType, SPA_POD_CHOICE_FLAGS_Int (buffer_types));
g_ptr_array_add (params, g_steal_pointer (&pod));
params[n_params++] = spa_pod_builder_add_object ( spa_pod_dynamic_builder_init (&pod_builder, NULL, 0, 1024);
&pod_builder, pod = spa_pod_builder_add_object (
&pod_builder.b,
SPA_TYPE_OBJECT_ParamMeta, SPA_PARAM_Meta, SPA_TYPE_OBJECT_ParamMeta, SPA_PARAM_Meta,
SPA_PARAM_META_type, SPA_POD_Id (SPA_META_VideoCrop), SPA_PARAM_META_type, SPA_POD_Id (SPA_META_VideoCrop),
SPA_PARAM_META_size, SPA_POD_Int (sizeof (struct spa_meta_region))); SPA_PARAM_META_size, SPA_POD_Int (sizeof (struct spa_meta_region)));
g_ptr_array_add (params, g_steal_pointer (&pod));
params[n_params++] = spa_pod_builder_add_object ( spa_pod_dynamic_builder_init (&pod_builder, NULL, 0, 1024);
&pod_builder, pod = spa_pod_builder_add_object (
&pod_builder.b,
SPA_TYPE_OBJECT_ParamMeta, SPA_PARAM_Meta, SPA_TYPE_OBJECT_ParamMeta, SPA_PARAM_Meta,
SPA_PARAM_META_type, SPA_POD_Id (SPA_META_Cursor), SPA_PARAM_META_type, SPA_POD_Id (SPA_META_Cursor),
SPA_PARAM_META_size, SPA_POD_Int (CURSOR_META_SIZE (384, 384))); SPA_PARAM_META_size, SPA_POD_Int (CURSOR_META_SIZE (384, 384)));
g_ptr_array_add (params, g_steal_pointer (&pod));
params[n_params++] = spa_pod_builder_add_object ( spa_pod_dynamic_builder_init (&pod_builder, NULL, 0, 1024);
&pod_builder, pod = spa_pod_builder_add_object (
&pod_builder.b,
SPA_TYPE_OBJECT_ParamMeta, SPA_PARAM_Meta, SPA_TYPE_OBJECT_ParamMeta, SPA_PARAM_Meta,
SPA_PARAM_META_type, SPA_POD_Id (SPA_META_Header), SPA_PARAM_META_type, SPA_POD_Id (SPA_META_Header),
SPA_PARAM_META_size, SPA_POD_Int (sizeof (struct spa_meta_header))); SPA_PARAM_META_size, SPA_POD_Int (sizeof (struct spa_meta_header)));
g_ptr_array_add (params, g_steal_pointer (&pod));
add_video_damage_meta_param (&pod_builder, params, n_params++); add_video_damage_meta_param (params);
pw_stream_update_params (priv->pipewire_stream, params, n_params); pw_stream_update_params (priv->pipewire_stream,
(const struct spa_pod **) params->pdata,
params->len);
if (klass->notify_params_updated) if (klass->notify_params_updated)
klass->notify_params_updated (src, &priv->video_format); klass->notify_params_updated (src, &priv->video_format);
@ -1462,11 +1484,7 @@ create_pipewire_stream (MetaScreenCastStreamSrc *src,
MetaScreenCastStreamSrcPrivate *priv = MetaScreenCastStreamSrcPrivate *priv =
meta_screen_cast_stream_src_get_instance_private (src); meta_screen_cast_stream_src_get_instance_private (src);
struct pw_stream *pipewire_stream; struct pw_stream *pipewire_stream;
uint8_t buffer[1024]; g_autoptr (GPtrArray) params = NULL;
struct spa_pod_builder pod_builder =
SPA_POD_BUILDER_INIT (buffer, sizeof (buffer));
const struct spa_pod *params[4];
uint32_t n_params = 0;
int result; int result;
priv->node_id = SPA_ID_INVALID; priv->node_id = SPA_ID_INVALID;
@ -1482,7 +1500,8 @@ create_pipewire_stream (MetaScreenCastStreamSrc *src,
return NULL; return NULL;
} }
build_format_params (src, &pod_builder, params, &n_params); params = g_ptr_array_new_full (16, (GDestroyNotify) free);
build_format_params (src, params);
pw_stream_add_listener (pipewire_stream, pw_stream_add_listener (pipewire_stream,
&priv->pipewire_stream_listener, &priv->pipewire_stream_listener,
@ -1494,7 +1513,9 @@ create_pipewire_stream (MetaScreenCastStreamSrc *src,
SPA_ID_INVALID, SPA_ID_INVALID,
(PW_STREAM_FLAG_DRIVER | (PW_STREAM_FLAG_DRIVER |
PW_STREAM_FLAG_ALLOC_BUFFERS), PW_STREAM_FLAG_ALLOC_BUFFERS),
params, n_params); (const struct spa_pod **) params->pdata,
params->len);
if (result != 0) if (result != 0)
{ {
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,