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
*/
static void
recorder_record_frame (ShellRecorder *recorder)
recorder_record_frame (ShellRecorder *recorder,
gboolean paint)
{
GstBuffer *buffer;
guint8 *data;
ClutterCapture *captures;
int n_captures;
cairo_surface_t *image;
guint size;
uint8_t *data;
GstMemory *memory;
int i;
GstClock *clock;
GstClockTime now, base_time;
@ -425,21 +431,31 @@ recorder_record_frame (ShellRecorder *recorder)
return;
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);
cogl_framebuffer_read_pixels (cogl_get_draw_framebuffer (),
recorder->area.x,
recorder->area.y,
recorder->area.width,
recorder->area.height,
CLUTTER_CAIRO_FORMAT_ARGB32,
data);
if (n_captures == 0)
return;
/*
* TODO: Deal with each capture region separately, instead of dropping
* anything except the first one.
*/
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();
gst_buffer_insert_memory (buffer, -1,
gst_memory_new_wrapped (0, data, size, 0,
size, data, g_free));
memory = gst_memory_new_wrapped (0, data, size, 0, size,
image,
(GDestroyNotify) cairo_surface_destroy);
gst_buffer_insert_memory (buffer, -1, memory);
GST_BUFFER_PTS(buffer) = now;
@ -463,7 +479,7 @@ recorder_on_stage_paint (ClutterActor *actor,
ShellRecorder *recorder)
{
if (recorder->state == RECORDER_STATE_RECORDING)
recorder_record_frame (recorder);
recorder_record_frame (recorder, FALSE);
}
static void
@ -1561,7 +1577,7 @@ shell_recorder_close (ShellRecorder *recorder)
/* We want to record one more frame since some time may have
* elapsed since the last frame
*/
clutter_actor_paint (CLUTTER_ACTOR (recorder->stage));
recorder_record_frame (recorder, TRUE);
recorder_remove_update_pointer_timeout (recorder);
recorder_close_pipeline (recorder);

View File

@ -210,41 +210,40 @@ write_screenshot_thread (GTask *result,
static void
do_grab_screenshot (ShellScreenshot *screenshot,
ClutterStage *stage,
int x,
int y,
int width,
int height)
{
CoglBitmap *bitmap;
ClutterBackend *backend;
CoglContext *context;
int stride;
guchar *data;
ShellScreenshotPrivate *priv = screenshot->priv;
ClutterCapture *captures;
int n_captures;
int i;
backend = clutter_get_default_backend ();
context = clutter_backend_get_cogl_context (backend);
clutter_stage_capture (stage, FALSE,
&(cairo_rectangle_int_t) {
.x = x,
.y = y,
.width = width,
.height = height
},
&captures,
&n_captures);
priv->image = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
width, height);
if (n_captures == 0)
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);
stride = cairo_image_surface_get_stride (priv->image);
for (i = 1; i < n_captures; i++)
cairo_surface_destroy (captures[i].image);
bitmap = cogl_bitmap_new_for_data (context,
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);
g_free (captures);
}
static void
@ -312,7 +311,7 @@ grab_screenshot (ClutterActor *stage,
screen = shell_global_get_screen (priv->global);
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)
{
@ -381,6 +380,7 @@ grab_area_screenshot (ClutterActor *stage,
ShellScreenshotPrivate *priv = screenshot->priv;
do_grab_screenshot (screenshot,
CLUTTER_STAGE (stage),
priv->screenshot_area.x,
priv->screenshot_area.y,
priv->screenshot_area.width,