Compare commits

...

9 Commits

Author SHA1 Message Date
Jonas Ådahl
1fd53c480f screen-cast/src: Remove follow up timeout source on disable
We failed to remove the timeout source when disabling, meaning that if a
follow up was scheduled, and shortly after we disabled the source, the
timeout would be invoked after the source was freed causing
use-after-free bugs.

Closes: https://gitlab.gnome.org/GNOME/mutter/-/issues/1337

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1365


(cherry picked from commit d67ba3ea65)
2020-07-10 13:26:19 +00:00
Jonas Ådahl
0c6ac287e6 screen-cast/src: Use G_USEC_PER_SEC instead of 1000000
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1351
2020-07-08 19:27:24 +02:00
Jonas Ådahl
e8052f169b screen-cast/src: Record follow up frame after timeout
During animation or other things that cause multiple frames in a row
being painted, we might skip recording frames if the max framerate is
reached.

Doing so means we might end up skipping the last frame in a series,
ending with the last frame we sent was not the last one, making things
appear to get stuck sometimes.

Handle this by creating a timeout if we ever throttle, and at the time
the timeout callback is triggered, make sure we eventually send an up to
date frame.

This is handle differently depending on the source type. A monitor
source type reports 1x1 pixel damage on each view its monitor overlaps,
while a window source type simply records a frame from the surface
directly, except without recording a timestamp, so that timestamps
always refer to when damage actually happened.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1351
2020-07-08 19:26:56 +02:00
Jonas Ådahl
449fa7bf81 screen-cast/src: Fix signedness of timestamp field
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1351
2020-07-08 15:13:06 +02:00
Jonas Ådahl
2d899596e2 screen-cast/src: Make record functions return an error when failing
Now that we don't use the record function to early out depending on
implicit state (don't record pixels if only cursor moved for example),
let it simply report an error when it fails, as we should no longer ever
return without pixels if nothing failed.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1351
2020-07-08 15:13:06 +02:00
Jonas Ådahl
cf88d64882 screen-cast: Let the reason for recording determine what to record
E.g. we'll have pointer movement that, if no painting is already
scheduled, should only send new cursor metadata without any new pixel
buffer. When this happens, tell next step to not record the pixels if
this was the case, instead of having it rediscover this itself.

Closes: https://gitlab.gnome.org/GNOME/mutter/-/issues/1323
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1351
2020-07-08 15:13:06 +02:00
Jonas Ådahl
92db8902d9 screen-cast/src: Add flag to maybe_record()
Will later be used to make recording avoid recording actual pixel
content if e.g. only the cursor moved.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1351
2020-07-08 15:13:06 +02:00
Jonas Ådahl
b1d45820ef screen-cast/window-stream-src: Fix indentation
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1351
2020-07-08 15:13:06 +02:00
Jonas Ådahl
d07335cd4c screen-cast-src: Make the two record vfuncs more similarly named
Both do more or less the same but with different methods - one puts
pixels into a buffer using the CPU, the other puts pixels into a buffer
using the GPU.

However, they are behaving slightly different, which they shouldn't.
Lets first address the misleading disconnect in naming, and later we'll
make them behave more similarly.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1351
2020-07-08 15:13:06 +02:00
4 changed files with 244 additions and 78 deletions

View File

@@ -121,8 +121,10 @@ stage_painted (MetaStage *stage,
gpointer user_data)
{
MetaScreenCastStreamSrc *src = META_SCREEN_CAST_STREAM_SRC (user_data);
MetaScreenCastRecordFlag flags;
meta_screen_cast_stream_src_maybe_record_frame (src);
flags = META_SCREEN_CAST_RECORD_FLAG_NONE;
meta_screen_cast_stream_src_maybe_record_frame (src, flags);
}
static MetaBackend *
@@ -181,6 +183,7 @@ sync_cursor_state (MetaScreenCastMonitorStreamSrc *monitor_src)
{
MetaScreenCastStreamSrc *src = META_SCREEN_CAST_STREAM_SRC (monitor_src);
ClutterStage *stage = get_stage (monitor_src);
MetaScreenCastRecordFlag flags;
if (!is_cursor_in_stream (monitor_src))
return;
@@ -188,7 +191,11 @@ sync_cursor_state (MetaScreenCastMonitorStreamSrc *monitor_src)
if (clutter_stage_is_redraw_queued (stage))
return;
meta_screen_cast_stream_src_maybe_record_frame (src);
if (meta_screen_cast_stream_src_pending_follow_up_frame (src))
return;
flags = META_SCREEN_CAST_RECORD_FLAG_CURSOR_ONLY;
meta_screen_cast_stream_src_maybe_record_frame (src, flags);
}
static void
@@ -362,8 +369,9 @@ meta_screen_cast_monitor_stream_src_disable (MetaScreenCastStreamSrc *src)
}
static gboolean
meta_screen_cast_monitor_stream_src_record_frame (MetaScreenCastStreamSrc *src,
uint8_t *data)
meta_screen_cast_monitor_stream_src_record_to_buffer (MetaScreenCastStreamSrc *src,
uint8_t *data,
GError **error)
{
MetaScreenCastMonitorStreamSrc *monitor_src =
META_SCREEN_CAST_MONITOR_STREAM_SRC (src);
@@ -372,9 +380,6 @@ meta_screen_cast_monitor_stream_src_record_frame (MetaScreenCastStreamSrc *src,
MetaLogicalMonitor *logical_monitor;
stage = get_stage (monitor_src);
if (!clutter_stage_is_redraw_queued (stage))
return FALSE;
monitor = get_monitor (monitor_src);
logical_monitor = meta_monitor_get_logical_monitor (monitor);
clutter_stage_capture_into (stage, FALSE, &logical_monitor->rect, data);
@@ -383,8 +388,9 @@ meta_screen_cast_monitor_stream_src_record_frame (MetaScreenCastStreamSrc *src,
}
static gboolean
meta_screen_cast_monitor_stream_src_blit_to_framebuffer (MetaScreenCastStreamSrc *src,
CoglFramebuffer *framebuffer)
meta_screen_cast_monitor_stream_src_record_to_framebuffer (MetaScreenCastStreamSrc *src,
CoglFramebuffer *framebuffer,
GError **error)
{
MetaScreenCastMonitorStreamSrc *monitor_src =
META_SCREEN_CAST_MONITOR_STREAM_SRC (src);
@@ -408,7 +414,6 @@ meta_screen_cast_monitor_stream_src_blit_to_framebuffer (MetaScreenCastStreamSrc
for (l = meta_renderer_get_views (renderer); l; l = l->next)
{
ClutterStageView *view = CLUTTER_STAGE_VIEW (l->data);
g_autoptr (GError) error = NULL;
CoglFramebuffer *view_framebuffer;
MetaRectangle view_layout;
int x, y;
@@ -429,12 +434,8 @@ meta_screen_cast_monitor_stream_src_blit_to_framebuffer (MetaScreenCastStreamSrc
x, y,
cogl_framebuffer_get_width (view_framebuffer),
cogl_framebuffer_get_height (view_framebuffer),
&error))
{
g_warning ("Error blitting view into DMABuf framebuffer: %s",
error->message);
return FALSE;
}
error))
return FALSE;
}
cogl_framebuffer_finish (framebuffer);
@@ -442,6 +443,44 @@ meta_screen_cast_monitor_stream_src_blit_to_framebuffer (MetaScreenCastStreamSrc
return TRUE;
}
static void
meta_screen_cast_monitor_stream_record_follow_up (MetaScreenCastStreamSrc *src)
{
MetaScreenCastMonitorStreamSrc *monitor_src =
META_SCREEN_CAST_MONITOR_STREAM_SRC (src);
MetaBackend *backend = get_backend (monitor_src);
MetaRenderer *renderer = meta_backend_get_renderer (backend);
ClutterStage *stage = get_stage (monitor_src);
MetaMonitor *monitor;
MetaLogicalMonitor *logical_monitor;
MetaRectangle logical_monitor_layout;
GList *l;
monitor = get_monitor (monitor_src);
logical_monitor = meta_monitor_get_logical_monitor (monitor);
logical_monitor_layout = meta_logical_monitor_get_layout (logical_monitor);
for (l = meta_renderer_get_views (renderer); l; l = l->next)
{
MetaRendererView *view = l->data;
MetaRectangle view_layout;
MetaRectangle damage;
clutter_stage_view_get_layout (CLUTTER_STAGE_VIEW (view), &view_layout);
if (!meta_rectangle_overlap (&logical_monitor_layout, &view_layout))
continue;
damage = (cairo_rectangle_int_t) {
.x = view_layout.x,
.y = view_layout.y,
.width = 1,
.height = 1,
};
clutter_actor_queue_redraw_with_clip (CLUTTER_ACTOR (stage), &damage);
}
}
static void
meta_screen_cast_monitor_stream_src_set_cursor_metadata (MetaScreenCastStreamSrc *src,
struct spa_meta_cursor *spa_meta_cursor)
@@ -562,9 +601,12 @@ meta_screen_cast_monitor_stream_src_class_init (MetaScreenCastMonitorStreamSrcCl
src_class->get_specs = meta_screen_cast_monitor_stream_src_get_specs;
src_class->enable = meta_screen_cast_monitor_stream_src_enable;
src_class->disable = meta_screen_cast_monitor_stream_src_disable;
src_class->record_frame = meta_screen_cast_monitor_stream_src_record_frame;
src_class->blit_to_framebuffer =
meta_screen_cast_monitor_stream_src_blit_to_framebuffer;
src_class->record_to_buffer =
meta_screen_cast_monitor_stream_src_record_to_buffer;
src_class->record_to_framebuffer =
meta_screen_cast_monitor_stream_src_record_to_framebuffer;
src_class->record_follow_up =
meta_screen_cast_monitor_stream_record_follow_up;
src_class->set_cursor_metadata =
meta_screen_cast_monitor_stream_src_set_cursor_metadata;
}

View File

@@ -91,7 +91,8 @@ typedef struct _MetaScreenCastStreamSrcPrivate
struct spa_video_info_raw video_format;
int video_stride;
uint64_t last_frame_timestamp_us;
int64_t last_frame_timestamp_us;
guint follow_up_frame_source_id;
GHashTable *dmabuf_handles;
@@ -109,6 +110,12 @@ G_DEFINE_TYPE_WITH_CODE (MetaScreenCastStreamSrc,
meta_screen_cast_stream_src_init_initable_iface)
G_ADD_PRIVATE (MetaScreenCastStreamSrc))
static inline uint32_t
us2ms (uint64_t us)
{
return (uint32_t) (us / 1000);
}
static void
meta_screen_cast_stream_src_get_specs (MetaScreenCastStreamSrc *src,
int *width,
@@ -135,23 +142,34 @@ meta_screen_cast_stream_src_get_videocrop (MetaScreenCastStreamSrc *src,
}
static gboolean
meta_screen_cast_stream_src_record_frame (MetaScreenCastStreamSrc *src,
uint8_t *data)
meta_screen_cast_stream_src_record_to_buffer (MetaScreenCastStreamSrc *src,
uint8_t *data,
GError **error)
{
MetaScreenCastStreamSrcClass *klass =
META_SCREEN_CAST_STREAM_SRC_GET_CLASS (src);
return klass->record_frame (src, data);
return klass->record_to_buffer (src, data, error);
}
static gboolean
meta_screen_cast_stream_src_blit_to_framebuffer (MetaScreenCastStreamSrc *src,
CoglFramebuffer *framebuffer)
meta_screen_cast_stream_src_record_to_framebuffer (MetaScreenCastStreamSrc *src,
CoglFramebuffer *framebuffer,
GError **error)
{
MetaScreenCastStreamSrcClass *klass =
META_SCREEN_CAST_STREAM_SRC_GET_CLASS (src);
return klass->blit_to_framebuffer (src, framebuffer);
return klass->record_to_framebuffer (src, framebuffer, error);
}
static void
meta_screen_cast_stream_src_record_follow_up (MetaScreenCastStreamSrc *src)
{
MetaScreenCastStreamSrcClass *klass =
META_SCREEN_CAST_STREAM_SRC_GET_CLASS (src);
klass->record_follow_up (src);
}
static void
@@ -409,9 +427,10 @@ maybe_record_cursor (MetaScreenCastStreamSrc *src,
}
static gboolean
do_record_frame (MetaScreenCastStreamSrc *src,
struct spa_buffer *spa_buffer,
uint8_t *data)
do_record_frame (MetaScreenCastStreamSrc *src,
struct spa_buffer *spa_buffer,
uint8_t *data,
GError **error)
{
MetaScreenCastStreamSrcPrivate *priv =
meta_screen_cast_stream_src_get_instance_private (src);
@@ -419,7 +438,7 @@ do_record_frame (MetaScreenCastStreamSrc *src,
if (spa_buffer->datas[0].data ||
spa_buffer->datas[0].type == SPA_DATA_MemFd)
{
return meta_screen_cast_stream_src_record_frame (src, data);
return meta_screen_cast_stream_src_record_to_buffer (src, data, error);
}
else if (spa_buffer->datas[0].type == SPA_DATA_DmaBuf)
{
@@ -429,14 +448,56 @@ do_record_frame (MetaScreenCastStreamSrc *src,
CoglFramebuffer *dmabuf_fbo =
cogl_dma_buf_handle_get_framebuffer (dmabuf_handle);
return meta_screen_cast_stream_src_blit_to_framebuffer (src, dmabuf_fbo);
return meta_screen_cast_stream_src_record_to_framebuffer (src,
dmabuf_fbo,
error);
}
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Unknown SPA buffer type %u", spa_buffer->datas[0].type);
return FALSE;
}
gboolean
meta_screen_cast_stream_src_pending_follow_up_frame (MetaScreenCastStreamSrc *src)
{
MetaScreenCastStreamSrcPrivate *priv =
meta_screen_cast_stream_src_get_instance_private (src);
return priv->follow_up_frame_source_id != 0;
}
static gboolean
follow_up_frame_cb (gpointer user_data)
{
MetaScreenCastStreamSrc *src = user_data;
MetaScreenCastStreamSrcPrivate *priv =
meta_screen_cast_stream_src_get_instance_private (src);
priv->follow_up_frame_source_id = 0;
meta_screen_cast_stream_src_record_follow_up (src);
return G_SOURCE_REMOVE;
}
static void
maybe_schedule_follow_up_frame (MetaScreenCastStreamSrc *src,
int64_t timeout_us)
{
MetaScreenCastStreamSrcPrivate *priv =
meta_screen_cast_stream_src_get_instance_private (src);
if (priv->follow_up_frame_source_id)
return;
priv->follow_up_frame_source_id = g_timeout_add (us2ms (timeout_us),
follow_up_frame_cb,
src);
}
void
meta_screen_cast_stream_src_maybe_record_frame (MetaScreenCastStreamSrc *src)
meta_screen_cast_stream_src_maybe_record_frame (MetaScreenCastStreamSrc *src,
MetaScreenCastRecordFlag flags)
{
MetaScreenCastStreamSrcPrivate *priv =
meta_screen_cast_stream_src_get_instance_private (src);
@@ -445,14 +506,29 @@ meta_screen_cast_stream_src_maybe_record_frame (MetaScreenCastStreamSrc *src)
struct spa_buffer *spa_buffer;
uint8_t *data = NULL;
uint64_t now_us;
g_autoptr (GError) error = NULL;
now_us = g_get_monotonic_time ();
if (priv->video_format.max_framerate.num > 0 &&
priv->last_frame_timestamp_us != 0 &&
(now_us - priv->last_frame_timestamp_us <
((1000000 * priv->video_format.max_framerate.denom) /
priv->video_format.max_framerate.num)))
return;
priv->last_frame_timestamp_us != 0)
{
int64_t min_interval_us;
int64_t time_since_last_frame_us;
min_interval_us =
((G_USEC_PER_SEC * priv->video_format.max_framerate.denom) /
priv->video_format.max_framerate.num);
time_since_last_frame_us = now_us - priv->last_frame_timestamp_us;
if (time_since_last_frame_us < min_interval_us)
{
int64_t timeout_us;
timeout_us = min_interval_us - time_since_last_frame_us;
maybe_schedule_follow_up_frame (src, timeout_us);
return;
}
}
if (!priv->pipewire_stream)
return;
@@ -470,34 +546,43 @@ meta_screen_cast_stream_src_maybe_record_frame (MetaScreenCastStreamSrc *src)
return;
}
if (do_record_frame (src, spa_buffer, data))
if (!(flags & META_SCREEN_CAST_RECORD_FLAG_CURSOR_ONLY))
{
struct spa_meta_region *spa_meta_video_crop;
spa_buffer->datas[0].chunk->size = spa_buffer->datas[0].maxsize;
spa_buffer->datas[0].chunk->stride = priv->video_stride;
/* Update VideoCrop if needed */
spa_meta_video_crop =
spa_buffer_find_meta_data (spa_buffer, SPA_META_VideoCrop,
sizeof (*spa_meta_video_crop));
if (spa_meta_video_crop)
g_clear_handle_id (&priv->follow_up_frame_source_id, g_source_remove);
if (do_record_frame (src, spa_buffer, data, &error))
{
if (meta_screen_cast_stream_src_get_videocrop (src, &crop_rect))
struct spa_meta_region *spa_meta_video_crop;
spa_buffer->datas[0].chunk->size = spa_buffer->datas[0].maxsize;
spa_buffer->datas[0].chunk->stride = priv->video_stride;
/* Update VideoCrop if needed */
spa_meta_video_crop =
spa_buffer_find_meta_data (spa_buffer, SPA_META_VideoCrop,
sizeof (*spa_meta_video_crop));
if (spa_meta_video_crop)
{
spa_meta_video_crop->region.position.x = crop_rect.x;
spa_meta_video_crop->region.position.y = crop_rect.y;
spa_meta_video_crop->region.size.width = crop_rect.width;
spa_meta_video_crop->region.size.height = crop_rect.height;
}
else
{
spa_meta_video_crop->region.position.x = 0;
spa_meta_video_crop->region.position.y = 0;
spa_meta_video_crop->region.size.width = priv->stream_width;
spa_meta_video_crop->region.size.height = priv->stream_height;
if (meta_screen_cast_stream_src_get_videocrop (src, &crop_rect))
{
spa_meta_video_crop->region.position.x = crop_rect.x;
spa_meta_video_crop->region.position.y = crop_rect.y;
spa_meta_video_crop->region.size.width = crop_rect.width;
spa_meta_video_crop->region.size.height = crop_rect.height;
}
else
{
spa_meta_video_crop->region.position.x = 0;
spa_meta_video_crop->region.position.y = 0;
spa_meta_video_crop->region.size.width = priv->stream_width;
spa_meta_video_crop->region.size.height = priv->stream_height;
}
}
}
else
{
g_warning ("Failed to record screen cast frame: %s", error->message);
spa_buffer->datas[0].chunk->size = 0;
}
}
else
{
@@ -539,6 +624,8 @@ meta_screen_cast_stream_src_disable (MetaScreenCastStreamSrc *src)
META_SCREEN_CAST_STREAM_SRC_GET_CLASS (src)->disable (src);
g_clear_handle_id (&priv->follow_up_frame_source_id, g_source_remove);
priv->is_enabled = FALSE;
}

View File

@@ -37,6 +37,12 @@
typedef struct _MetaScreenCastStream MetaScreenCastStream;
typedef enum _MetaScreenCastRecordFlag
{
META_SCREEN_CAST_RECORD_FLAG_NONE = 0,
META_SCREEN_CAST_RECORD_FLAG_CURSOR_ONLY = 1 << 0,
} MetaScreenCastRecordFlag;
#define META_TYPE_SCREEN_CAST_STREAM_SRC (meta_screen_cast_stream_src_get_type ())
G_DECLARE_DERIVABLE_TYPE (MetaScreenCastStreamSrc,
meta_screen_cast_stream_src,
@@ -53,17 +59,24 @@ struct _MetaScreenCastStreamSrcClass
float *frame_rate);
void (* enable) (MetaScreenCastStreamSrc *src);
void (* disable) (MetaScreenCastStreamSrc *src);
gboolean (* record_frame) (MetaScreenCastStreamSrc *src,
uint8_t *data);
gboolean (* blit_to_framebuffer) (MetaScreenCastStreamSrc *src,
CoglFramebuffer *framebuffer);
gboolean (* record_to_buffer) (MetaScreenCastStreamSrc *src,
uint8_t *data,
GError **error);
gboolean (* record_to_framebuffer) (MetaScreenCastStreamSrc *src,
CoglFramebuffer *framebuffer,
GError **error);
void (* record_follow_up) (MetaScreenCastStreamSrc *src);
gboolean (* get_videocrop) (MetaScreenCastStreamSrc *src,
MetaRectangle *crop_rect);
void (* set_cursor_metadata) (MetaScreenCastStreamSrc *src,
struct spa_meta_cursor *spa_meta_cursor);
};
void meta_screen_cast_stream_src_maybe_record_frame (MetaScreenCastStreamSrc *src);
void meta_screen_cast_stream_src_maybe_record_frame (MetaScreenCastStreamSrc *src,
MetaScreenCastRecordFlag flags);
gboolean meta_screen_cast_stream_src_pending_follow_up_frame (MetaScreenCastStreamSrc *src);
MetaScreenCastStream * meta_screen_cast_stream_src_get_stream (MetaScreenCastStreamSrc *src);

View File

@@ -327,8 +327,10 @@ screen_cast_window_damaged (MetaWindowActor *actor,
MetaScreenCastWindowStreamSrc *window_src)
{
MetaScreenCastStreamSrc *src = META_SCREEN_CAST_STREAM_SRC (window_src);
MetaScreenCastRecordFlag flags;
meta_screen_cast_stream_src_maybe_record_frame (src);
flags = META_SCREEN_CAST_RECORD_FLAG_CURSOR_ONLY;
meta_screen_cast_stream_src_maybe_record_frame (src, flags);
}
static void
@@ -365,6 +367,7 @@ static void
sync_cursor_state (MetaScreenCastWindowStreamSrc *window_src)
{
MetaScreenCastStreamSrc *src = META_SCREEN_CAST_STREAM_SRC (window_src);
MetaScreenCastRecordFlag flags;
if (!is_cursor_in_stream (window_src))
return;
@@ -372,7 +375,8 @@ sync_cursor_state (MetaScreenCastWindowStreamSrc *window_src)
if (meta_screen_cast_window_has_damage (window_src->screen_cast_window))
return;
meta_screen_cast_stream_src_maybe_record_frame (src);
flags = META_SCREEN_CAST_RECORD_FLAG_CURSOR_ONLY;
meta_screen_cast_stream_src_maybe_record_frame (src, flags);
}
static void
@@ -401,6 +405,7 @@ meta_screen_cast_window_stream_src_enable (MetaScreenCastStreamSrc *src)
MetaCursorTracker *cursor_tracker = meta_backend_get_cursor_tracker (backend);
MetaWindowActor *window_actor;
MetaScreenCastStream *stream;
MetaScreenCastRecordFlag flags;
window_actor = meta_window_actor_from_window (get_window (window_src));
if (!window_actor)
@@ -438,7 +443,8 @@ meta_screen_cast_window_stream_src_enable (MetaScreenCastStreamSrc *src)
break;
}
meta_screen_cast_stream_src_maybe_record_frame (src);
flags = META_SCREEN_CAST_RECORD_FLAG_NONE;
meta_screen_cast_stream_src_maybe_record_frame (src, flags);
}
static void
@@ -451,8 +457,9 @@ meta_screen_cast_window_stream_src_disable (MetaScreenCastStreamSrc *src)
}
static gboolean
meta_screen_cast_window_stream_src_record_frame (MetaScreenCastStreamSrc *src,
uint8_t *data)
meta_screen_cast_window_stream_src_record_to_buffer (MetaScreenCastStreamSrc *src,
uint8_t *data,
GError **error)
{
MetaScreenCastWindowStreamSrc *window_src =
META_SCREEN_CAST_WINDOW_STREAM_SRC (src);
@@ -463,8 +470,9 @@ meta_screen_cast_window_stream_src_record_frame (MetaScreenCastStreamSrc *src,
}
static gboolean
meta_screen_cast_window_stream_src_blit_to_framebuffer (MetaScreenCastStreamSrc *src,
CoglFramebuffer *framebuffer)
meta_screen_cast_window_stream_src_record_to_framebuffer (MetaScreenCastStreamSrc *src,
CoglFramebuffer *framebuffer,
GError **error)
{
MetaScreenCastWindowStreamSrc *window_src =
META_SCREEN_CAST_WINDOW_STREAM_SRC (src);
@@ -477,9 +485,13 @@ meta_screen_cast_window_stream_src_blit_to_framebuffer (MetaScreenCastStreamSrc
stream_rect.height = get_stream_height (window_src);
if (!meta_screen_cast_window_blit_to_framebuffer (window_src->screen_cast_window,
&stream_rect,
framebuffer))
return FALSE;
&stream_rect,
framebuffer))
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Failed to blit window content to framebuffer");
return FALSE;
}
stream = meta_screen_cast_stream_src_get_stream (src);
switch (meta_screen_cast_stream_get_cursor_mode (stream))
@@ -497,6 +509,15 @@ meta_screen_cast_window_stream_src_blit_to_framebuffer (MetaScreenCastStreamSrc
return TRUE;
}
static void
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);
}
static void
meta_screen_cast_window_stream_src_set_cursor_metadata (MetaScreenCastStreamSrc *src,
struct spa_meta_cursor *spa_meta_cursor)
@@ -580,9 +601,12 @@ meta_screen_cast_window_stream_src_class_init (MetaScreenCastWindowStreamSrcClas
src_class->get_specs = meta_screen_cast_window_stream_src_get_specs;
src_class->enable = meta_screen_cast_window_stream_src_enable;
src_class->disable = meta_screen_cast_window_stream_src_disable;
src_class->record_frame = meta_screen_cast_window_stream_src_record_frame;
src_class->blit_to_framebuffer =
meta_screen_cast_window_stream_src_blit_to_framebuffer;
src_class->record_to_buffer =
meta_screen_cast_window_stream_src_record_to_buffer;
src_class->record_to_framebuffer =
meta_screen_cast_window_stream_src_record_to_framebuffer;
src_class->record_follow_up =
meta_screen_cast_window_stream_record_follow_up;
src_class->get_videocrop = meta_screen_cast_window_stream_src_get_videocrop;
src_class->set_cursor_metadata = meta_screen_cast_window_stream_src_set_cursor_metadata;
}