Use clutter_stage_capture instead of cogl's read_pixels

There is no longer any guarantee that there'll be one single
framebuffer to read pixels from. In order to still read pixels from the
stage, use the new clutter_stage_capture API.

https://bugzilla.gnome.org/show_bug.cgi?id=768979
This commit is contained in:
Jonas Ådahl 2016-06-27 15:57:28 +08:00
parent 0dac0ad516
commit f5c058a036
2 changed files with 57 additions and 41 deletions

View File

@ -389,11 +389,17 @@ recorder_draw_cursor (ShellRecorder *recorder,
/* Retrieve a frame and feed it into the pipeline /* Retrieve a frame and feed it into the pipeline
*/ */
static void static void
recorder_record_frame (ShellRecorder *recorder) recorder_record_frame (ShellRecorder *recorder,
gboolean paint)
{ {
GstBuffer *buffer; GstBuffer *buffer;
guint8 *data; ClutterCapture *captures;
int n_captures;
cairo_surface_t *image;
guint size; guint size;
uint8_t *data;
GstMemory *memory;
int i;
GstClock *clock; GstClock *clock;
GstClockTime now, base_time; GstClockTime now, base_time;
@ -425,21 +431,31 @@ recorder_record_frame (ShellRecorder *recorder)
return; return;
recorder->last_frame_time = now; recorder->last_frame_time = now;
size = recorder->area.width * recorder->area.height * 4; clutter_stage_capture (recorder->stage, paint, &recorder->area,
&captures, &n_captures);
data = g_malloc (size); if (n_captures == 0)
cogl_framebuffer_read_pixels (cogl_get_draw_framebuffer (), return;
recorder->area.x,
recorder->area.y, /*
recorder->area.width, * TODO: Deal with each capture region separately, instead of dropping
recorder->area.height, * anything except the first one.
CLUTTER_CAIRO_FORMAT_ARGB32, */
data);
image = captures[0].image;
data = cairo_image_surface_get_data (image);
size = captures[0].rect.width * captures[0].rect.height * 4;
/* TODO: Capture more than the first framebuffer. */
for (i = 1; i < n_captures; i++)
cairo_surface_destroy (captures[i].image);
g_free (captures);
buffer = gst_buffer_new(); buffer = gst_buffer_new();
gst_buffer_insert_memory (buffer, -1, memory = gst_memory_new_wrapped (0, data, size, 0, size,
gst_memory_new_wrapped (0, data, size, 0, image,
size, data, g_free)); (GDestroyNotify) cairo_surface_destroy);
gst_buffer_insert_memory (buffer, -1, memory);
GST_BUFFER_PTS(buffer) = now; GST_BUFFER_PTS(buffer) = now;
@ -463,7 +479,7 @@ recorder_on_stage_paint (ClutterActor *actor,
ShellRecorder *recorder) ShellRecorder *recorder)
{ {
if (recorder->state == RECORDER_STATE_RECORDING) if (recorder->state == RECORDER_STATE_RECORDING)
recorder_record_frame (recorder); recorder_record_frame (recorder, FALSE);
} }
static void static void
@ -1561,7 +1577,7 @@ shell_recorder_close (ShellRecorder *recorder)
/* We want to record one more frame since some time may have /* We want to record one more frame since some time may have
* elapsed since the last frame * elapsed since the last frame
*/ */
clutter_actor_paint (CLUTTER_ACTOR (recorder->stage)); recorder_record_frame (recorder, TRUE);
recorder_remove_update_pointer_timeout (recorder); recorder_remove_update_pointer_timeout (recorder);
recorder_close_pipeline (recorder); recorder_close_pipeline (recorder);

View File

@ -210,41 +210,40 @@ write_screenshot_thread (GTask *result,
static void static void
do_grab_screenshot (ShellScreenshot *screenshot, do_grab_screenshot (ShellScreenshot *screenshot,
ClutterStage *stage,
int x, int x,
int y, int y,
int width, int width,
int height) int height)
{ {
CoglBitmap *bitmap;
ClutterBackend *backend;
CoglContext *context;
int stride;
guchar *data;
ShellScreenshotPrivate *priv = screenshot->priv; ShellScreenshotPrivate *priv = screenshot->priv;
ClutterCapture *captures;
int n_captures;
int i;
backend = clutter_get_default_backend (); clutter_stage_capture (stage, FALSE,
context = clutter_backend_get_cogl_context (backend); &(cairo_rectangle_int_t) {
.x = x,
.y = y,
.width = width,
.height = height
},
&captures,
&n_captures);
priv->image = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, if (n_captures == 0)
width, height); return;
/*
* TODO: Deal with each capture region separately, instead of dropping
* anything except the first one.
*/
priv->image = captures[0].image;
data = cairo_image_surface_get_data (priv->image); for (i = 1; i < n_captures; i++)
stride = cairo_image_surface_get_stride (priv->image); cairo_surface_destroy (captures[i].image);
bitmap = cogl_bitmap_new_for_data (context, g_free (captures);
width,
height,
CLUTTER_CAIRO_FORMAT_ARGB32,
stride,
data);
cogl_framebuffer_read_pixels_into_bitmap (cogl_get_draw_framebuffer (),
x, y,
COGL_READ_PIXELS_COLOR_BUFFER,
bitmap);
cairo_surface_mark_dirty (priv->image);
cogl_object_unref (bitmap);
} }
static void static void
@ -312,7 +311,7 @@ grab_screenshot (ClutterActor *stage,
screen = shell_global_get_screen (priv->global); screen = shell_global_get_screen (priv->global);
meta_screen_get_size (screen, &width, &height); meta_screen_get_size (screen, &width, &height);
do_grab_screenshot (screenshot, 0, 0, width, height); do_grab_screenshot (screenshot, CLUTTER_STAGE (stage), 0, 0, width, height);
if (meta_screen_get_n_monitors (screen) > 1) if (meta_screen_get_n_monitors (screen) > 1)
{ {
@ -381,6 +380,7 @@ grab_area_screenshot (ClutterActor *stage,
ShellScreenshotPrivate *priv = screenshot->priv; ShellScreenshotPrivate *priv = screenshot->priv;
do_grab_screenshot (screenshot, do_grab_screenshot (screenshot,
CLUTTER_STAGE (stage),
priv->screenshot_area.x, priv->screenshot_area.x,
priv->screenshot_area.y, priv->screenshot_area.y,
priv->screenshot_area.width, priv->screenshot_area.width,