screen-cast-stream-src: Export damaged video regions

This change will export the damaged regions (when available) out
to the pipewire client. This change is currently specific to
virtual streams only (where I was able to test the change) and
maintains the current behavior for other screencast stream types.

Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2775>
This commit is contained in:
Salman 2023-02-03 19:33:57 +00:00 committed by Marge Bot
parent 6223742996
commit 776e3f329d
6 changed files with 126 additions and 17 deletions

View File

@ -169,7 +169,7 @@ sync_cursor_state (MetaScreenCastAreaStreamSrc *area_src)
return;
flags = META_SCREEN_CAST_RECORD_FLAG_CURSOR_ONLY;
meta_screen_cast_stream_src_maybe_record_frame (src, flags);
meta_screen_cast_stream_src_maybe_record_frame (src, flags, NULL);
}
static void
@ -239,7 +239,7 @@ maybe_record_frame_on_idle (gpointer user_data)
area_src->maybe_record_idle_id = 0;
flags = META_SCREEN_CAST_RECORD_FLAG_NONE;
meta_screen_cast_stream_src_maybe_record_frame (src, flags);
meta_screen_cast_stream_src_maybe_record_frame (src, flags, NULL);
return G_SOURCE_REMOVE;
}
@ -544,7 +544,7 @@ meta_screen_cast_area_stream_record_follow_up (MetaScreenCastStreamSrc *src)
g_clear_handle_id (&area_src->maybe_record_idle_id, g_source_remove);
flags = META_SCREEN_CAST_RECORD_FLAG_NONE;
meta_screen_cast_stream_src_maybe_record_frame (src, flags);
meta_screen_cast_stream_src_maybe_record_frame (src, flags, NULL);
}
static void

View File

@ -143,7 +143,7 @@ maybe_record_frame_on_idle (gpointer user_data)
monitor_src->maybe_record_idle_id = 0;
flags = META_SCREEN_CAST_RECORD_FLAG_NONE;
meta_screen_cast_stream_src_maybe_record_frame (src, flags);
meta_screen_cast_stream_src_maybe_record_frame (src, flags, NULL);
return G_SOURCE_REMOVE;
}
@ -185,7 +185,7 @@ before_stage_painted (MetaStage *stage,
return;
flags = META_SCREEN_CAST_RECORD_FLAG_DMABUF_ONLY;
meta_screen_cast_stream_src_maybe_record_frame (src, flags);
meta_screen_cast_stream_src_maybe_record_frame (src, flags, NULL);
}
static gboolean
@ -264,7 +264,7 @@ sync_cursor_state (MetaScreenCastMonitorStreamSrc *monitor_src)
return;
flags = META_SCREEN_CAST_RECORD_FLAG_CURSOR_ONLY;
meta_screen_cast_stream_src_maybe_record_frame (src, flags);
meta_screen_cast_stream_src_maybe_record_frame (src, flags, NULL);
}
static void

View File

@ -51,6 +51,7 @@
(sizeof (struct spa_meta_cursor) + \
sizeof (struct spa_meta_bitmap) + width * height * 4)
#define NUM_DAMAGED_RECTS 32
#define DEFAULT_SIZE SPA_RECTANGLE (1280, 720)
#define MIN_SIZE SPA_RECTANGLE (1, 1)
#define MAX_SIZE SPA_RECTANGLE (16384, 16386)
@ -107,6 +108,8 @@ typedef struct _MetaScreenCastStreamSrcPrivate
guint follow_up_frame_source_id;
GHashTable *dmabuf_handles;
cairo_region_t *redraw_clip;
} MetaScreenCastStreamSrcPrivate;
static struct spa_pod *
@ -602,9 +605,81 @@ meta_screen_cast_stream_src_calculate_stride (MetaScreenCastStreamSrc *src,
return priv->video_stride;
}
static void
maybe_add_damaged_regions_metadata (MetaScreenCastStreamSrc *src,
struct spa_buffer *spa_buffer)
{
MetaScreenCastStreamSrcPrivate *priv;
struct spa_meta *spa_meta_video_damage;
struct spa_meta_region *meta_region;
spa_meta_video_damage =
spa_buffer_find_meta (spa_buffer, SPA_META_VideoDamage);
if (!spa_meta_video_damage)
return;
priv = meta_screen_cast_stream_src_get_instance_private (src);
if (!priv->redraw_clip)
{
spa_meta_for_each (meta_region, spa_meta_video_damage)
{
meta_region->region = SPA_REGION (0, 0, priv->video_format.size.width,
priv->video_format.size.height);
break;
}
}
else
{
int i;
int n_rectangles;
int num_buffers_available;
i = 0;
n_rectangles = cairo_region_num_rectangles (priv->redraw_clip);
num_buffers_available = 0;
spa_meta_for_each (meta_region, spa_meta_video_damage)
{
++num_buffers_available;
}
if (num_buffers_available < n_rectangles)
{
spa_meta_for_each (meta_region, spa_meta_video_damage)
{
g_warning ("Not enough buffers (%d) to accomodate damaged "
"regions (%d)", num_buffers_available, n_rectangles);
meta_region->region = SPA_REGION (0, 0,
priv->video_format.size.width,
priv->video_format.size.height);
break;
}
}
else
{
spa_meta_for_each (meta_region, spa_meta_video_damage)
{
cairo_rectangle_int_t rect;
cairo_region_get_rectangle (priv->redraw_clip, i, &rect);
meta_region->region = SPA_REGION (rect.x, rect.y,
rect.width, rect.height);
if (++i == n_rectangles)
break;
}
}
}
g_clear_pointer (&priv->redraw_clip, cairo_region_destroy);
}
void
meta_screen_cast_stream_src_maybe_record_frame (MetaScreenCastStreamSrc *src,
MetaScreenCastRecordFlag flags)
MetaScreenCastRecordFlag flags,
const cairo_region_t *redraw_clip)
{
MetaScreenCastStreamSrcPrivate *priv =
meta_screen_cast_stream_src_get_instance_private (src);
@ -616,6 +691,17 @@ meta_screen_cast_stream_src_maybe_record_frame (MetaScreenCastStreamSrc *src,
uint64_t now_us;
g_autoptr (GError) error = NULL;
/* Accumulate the damaged region since we might not schedule a frame capture
* eventually but once we do, we should report all the previous damaged areas.
*/
if (redraw_clip)
{
if (priv->redraw_clip)
cairo_region_union (priv->redraw_clip, redraw_clip);
else
priv->redraw_clip = cairo_region_copy (redraw_clip);
}
now_us = g_get_monotonic_time ();
if (priv->video_format.max_framerate.num > 0 &&
priv->last_frame_timestamp_us != 0)
@ -646,7 +732,7 @@ meta_screen_cast_stream_src_maybe_record_frame (MetaScreenCastStreamSrc *src,
meta_topic (META_DEBUG_SCREEN_CAST, "Recording %s frame on stream %u",
flags & META_SCREEN_CAST_RECORD_FLAG_CURSOR_ONLY ?
"cursor" : "full",
"cursor" : "full",
priv->node_id);
buffer = pw_stream_dequeue_buffer (priv->pipewire_stream);
@ -681,6 +767,7 @@ meta_screen_cast_stream_src_maybe_record_frame (MetaScreenCastStreamSrc *src,
g_clear_handle_id (&priv->follow_up_frame_source_id, g_source_remove);
if (do_record_frame (src, flags, spa_buffer, data, &error))
{
maybe_add_damaged_regions_metadata (src, spa_buffer);
struct spa_data *spa_data = &spa_buffer->datas[0];
struct spa_meta_region *spa_meta_video_crop;
@ -823,6 +910,23 @@ on_stream_state_changed (void *data,
}
}
static void
add_video_damage_meta_param (struct spa_pod_builder *pod_builder,
const struct spa_pod **params,
int idx)
{
const size_t meta_region_size = sizeof (struct spa_meta_region);
params[idx] = spa_pod_builder_add_object (
pod_builder,
SPA_TYPE_OBJECT_ParamMeta, SPA_PARAM_Meta,
SPA_PARAM_META_type, SPA_POD_Id (SPA_META_VideoDamage),
SPA_PARAM_META_size,
SPA_POD_CHOICE_RANGE_Int (meta_region_size * NUM_DAMAGED_RECTS,
meta_region_size * 1,
meta_region_size * NUM_DAMAGED_RECTS));
}
static void
on_stream_param_changed (void *data,
uint32_t id,
@ -836,7 +940,7 @@ on_stream_param_changed (void *data,
uint8_t params_buffer[1024];
int32_t width, height, stride, size;
struct spa_pod_builder pod_builder;
const struct spa_pod *params[4];
const struct spa_pod *params[5];
int n_params = 0;
const int bpp = 4;
int buffer_types;
@ -888,7 +992,9 @@ on_stream_param_changed (void *data,
SPA_PARAM_META_type, SPA_POD_Id (SPA_META_Header),
SPA_PARAM_META_size, SPA_POD_Int (sizeof (struct spa_meta_header)));
pw_stream_update_params (priv->pipewire_stream, params, G_N_ELEMENTS (params));
add_video_damage_meta_param (&pod_builder, params, n_params++);
pw_stream_update_params (priv->pipewire_stream, params, n_params);
if (klass->notify_params_updated)
klass->notify_params_updated (src, &priv->video_format);

View File

@ -85,7 +85,8 @@ void meta_screen_cast_stream_src_close (MetaScreenCastStreamSrc *src);
gboolean meta_screen_cast_stream_src_is_enabled (MetaScreenCastStreamSrc *src);
void meta_screen_cast_stream_src_maybe_record_frame (MetaScreenCastStreamSrc *src,
MetaScreenCastRecordFlag flags);
MetaScreenCastRecordFlag flags,
const cairo_region_t *redraw_clip);
gboolean meta_screen_cast_stream_src_pending_follow_up_frame (MetaScreenCastStreamSrc *src);

View File

@ -123,7 +123,7 @@ sync_cursor_state (MetaScreenCastVirtualStreamSrc *virtual_src)
return;
flags = META_SCREEN_CAST_RECORD_FLAG_CURSOR_ONLY;
meta_screen_cast_stream_src_maybe_record_frame (src, flags);
meta_screen_cast_stream_src_maybe_record_frame (src, flags, NULL);
}
static void
@ -190,9 +190,11 @@ actors_painted (MetaStage *stage,
{
MetaScreenCastStreamSrc *src = META_SCREEN_CAST_STREAM_SRC (user_data);
MetaScreenCastRecordFlag flags;
const cairo_region_t *redraw_clip = NULL;
flags = META_SCREEN_CAST_RECORD_FLAG_NONE;
meta_screen_cast_stream_src_maybe_record_frame (src, flags);
redraw_clip = clutter_paint_context_get_redraw_clip (paint_context);
meta_screen_cast_stream_src_maybe_record_frame (src, flags, redraw_clip);
}
static void

View File

@ -373,7 +373,7 @@ screen_cast_window_damaged (MetaWindowActor *actor,
MetaScreenCastRecordFlag flags;
flags = META_SCREEN_CAST_RECORD_FLAG_NONE;
meta_screen_cast_stream_src_maybe_record_frame (src, flags);
meta_screen_cast_stream_src_maybe_record_frame (src, flags, NULL);
}
static void
@ -394,7 +394,7 @@ sync_cursor_state (MetaScreenCastWindowStreamSrc *window_src)
return;
flags = META_SCREEN_CAST_RECORD_FLAG_CURSOR_ONLY;
meta_screen_cast_stream_src_maybe_record_frame (src, flags);
meta_screen_cast_stream_src_maybe_record_frame (src, flags, NULL);
}
static void
@ -477,7 +477,7 @@ meta_screen_cast_window_stream_src_enable (MetaScreenCastStreamSrc *src)
}
flags = META_SCREEN_CAST_RECORD_FLAG_NONE;
meta_screen_cast_stream_src_maybe_record_frame (src, flags);
meta_screen_cast_stream_src_maybe_record_frame (src, flags, NULL);
}
static void
@ -551,7 +551,7 @@ meta_screen_cast_window_stream_record_follow_up (MetaScreenCastStreamSrc *src)
MetaScreenCastRecordFlag flags;
flags = META_SCREEN_CAST_RECORD_FLAG_NONE;
meta_screen_cast_stream_src_maybe_record_frame (src, flags);
meta_screen_cast_stream_src_maybe_record_frame (src, flags, NULL);
}
static void