blob: 2c5dacc122e7023c0afec174a4f08d9a94a85c14 [file] [log] [blame]
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001/*
Kristian Høgsberg96aa7da2011-09-15 15:43:14 -04002 * Copyright © 2008-2011 Kristian Høgsberg
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003 *
Bryce Harringtona0bbfea2015-06-11 15:35:43 -07004 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files (the
6 * "Software"), to deal in the Software without restriction, including
7 * without limitation the rights to use, copy, modify, merge, publish,
8 * distribute, sublicense, and/or sell copies of the Software, and to
9 * permit persons to whom the Software is furnished to do so, subject to
10 * the following conditions:
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040011 *
Bryce Harringtona0bbfea2015-06-11 15:35:43 -070012 * The above copyright notice and this permission notice (including the
13 * next paragraph) shall be included in all copies or substantial
14 * portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
20 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
21 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 * SOFTWARE.
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040024 */
25
Daniel Stonec228e232013-05-22 18:03:19 +030026#include "config.h"
27
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040028#include <stdlib.h>
Jussi Kukkonen649bbce2016-07-19 14:16:27 +030029#include <stdint.h>
Kristian Høgsberg5fb70bf2012-05-24 12:29:46 -040030#include <stdio.h>
Kristian Høgsbergf02a6492012-03-12 01:05:25 -040031#include <string.h>
Scott Moreau56456d62012-03-23 16:42:04 -060032#include <linux/input.h>
Kristian Høgsberg5fb70bf2012-05-24 12:29:46 -040033#include <fcntl.h>
34#include <unistd.h>
35#include <sys/uio.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040036
37#include "compositor.h"
Jon Cruz867d50e2015-06-15 15:37:10 -070038#include "shared/helpers.h"
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040039
Jon Cruz4678bab2015-06-15 15:37:07 -070040#include "wcap/wcap-decode.h"
Kristian Høgsberg894e0b52012-05-25 17:55:20 -040041
Kristian Høgsbergae2ba9b2012-06-20 00:05:46 -040042struct screenshooter_frame_listener {
43 struct wl_listener listener;
Jason Ekstrand6bd62942013-06-20 20:38:23 -050044 struct weston_buffer *buffer;
Giulio Camuffoe9022e72013-12-11 23:45:11 +010045 weston_screenshooter_done_func_t done;
46 void *data;
Scott Moreau062be7e2012-04-20 13:37:33 -060047};
48
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040049static void
Scott Moreau72c23722012-04-20 13:37:34 -060050copy_bgra_yflip(uint8_t *dst, uint8_t *src, int height, int stride)
Pekka Paalanen45fab0e2012-04-17 11:55:41 +030051{
52 uint8_t *end;
53
Scott Moreau72c23722012-04-20 13:37:34 -060054 end = dst + height * stride;
Pekka Paalanen45fab0e2012-04-17 11:55:41 +030055 while (dst < end) {
Scott Moreau72c23722012-04-20 13:37:34 -060056 memcpy(dst, src, stride);
57 dst += stride;
58 src -= stride;
Pekka Paalanen45fab0e2012-04-17 11:55:41 +030059 }
60}
61
62static void
Pekka Paalanen4fc5dd02013-05-22 18:03:05 +030063copy_bgra(uint8_t *dst, uint8_t *src, int height, int stride)
64{
65 /* TODO: optimize this out */
66 memcpy(dst, src, height * stride);
67}
68
69static void
Pekka Paalanena1d57db2012-04-17 15:02:08 +030070copy_row_swap_RB(void *vdst, void *vsrc, int bytes)
71{
72 uint32_t *dst = vdst;
73 uint32_t *src = vsrc;
74 uint32_t *end = dst + bytes / 4;
75
76 while (dst < end) {
77 uint32_t v = *src++;
78 /* A R G B */
79 uint32_t tmp = v & 0xff00ff00;
80 tmp |= (v >> 16) & 0x000000ff;
81 tmp |= (v << 16) & 0x00ff0000;
82 *dst++ = tmp;
83 }
84}
85
86static void
Scott Moreau72c23722012-04-20 13:37:34 -060087copy_rgba_yflip(uint8_t *dst, uint8_t *src, int height, int stride)
Pekka Paalanena1d57db2012-04-17 15:02:08 +030088{
89 uint8_t *end;
90
Scott Moreau72c23722012-04-20 13:37:34 -060091 end = dst + height * stride;
Pekka Paalanena1d57db2012-04-17 15:02:08 +030092 while (dst < end) {
Scott Moreau72c23722012-04-20 13:37:34 -060093 copy_row_swap_RB(dst, src, stride);
94 dst += stride;
95 src -= stride;
Pekka Paalanena1d57db2012-04-17 15:02:08 +030096 }
97}
98
99static void
Pekka Paalanen4fc5dd02013-05-22 18:03:05 +0300100copy_rgba(uint8_t *dst, uint8_t *src, int height, int stride)
101{
102 uint8_t *end;
103
104 end = dst + height * stride;
105 while (dst < end) {
106 copy_row_swap_RB(dst, src, stride);
107 dst += stride;
108 src += stride;
109 }
110}
111
112static void
Kristian Høgsbergae2ba9b2012-06-20 00:05:46 -0400113screenshooter_frame_notify(struct wl_listener *listener, void *data)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400114{
Kristian Høgsbergae2ba9b2012-06-20 00:05:46 -0400115 struct screenshooter_frame_listener *l =
116 container_of(listener,
117 struct screenshooter_frame_listener, listener);
Kristian Høgsberge0f832b2012-06-20 00:13:18 -0400118 struct weston_output *output = data;
Pekka Paalanen4fc5dd02013-05-22 18:03:05 +0300119 struct weston_compositor *compositor = output->compositor;
Scott Moreau72c23722012-04-20 13:37:34 -0600120 int32_t stride;
Kristian Høgsbergae2ba9b2012-06-20 00:05:46 -0400121 uint8_t *pixels, *d, *s;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400122
Kristian Høgsberg79af73e2012-08-03 15:45:23 -0400123 output->disable_planes--;
Kristian Høgsbergae2ba9b2012-06-20 00:05:46 -0400124 wl_list_remove(&listener->link);
Pekka Paalanen4fc5dd02013-05-22 18:03:05 +0300125 stride = l->buffer->width * (PIXMAN_FORMAT_BPP(compositor->read_format) / 8);
Kristian Høgsbergae2ba9b2012-06-20 00:05:46 -0400126 pixels = malloc(stride * l->buffer->height);
Kristian Høgsbergf02a6492012-03-12 01:05:25 -0400127
Kristian Høgsbergae2ba9b2012-06-20 00:05:46 -0400128 if (pixels == NULL) {
Giulio Camuffoe9022e72013-12-11 23:45:11 +0100129 l->done(l->data, WESTON_SCREENSHOOTER_NO_MEMORY);
Kristian Høgsbergae2ba9b2012-06-20 00:05:46 -0400130 free(l);
131 return;
132 }
133
Pekka Paalanen4fc5dd02013-05-22 18:03:05 +0300134 compositor->renderer->read_pixels(output,
135 compositor->read_format, pixels,
Hardeningff39efa2013-09-18 23:56:35 +0200136 0, 0, output->current_mode->width,
137 output->current_mode->height);
Kristian Høgsbergae2ba9b2012-06-20 00:05:46 -0400138
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500139 stride = wl_shm_buffer_get_stride(l->buffer->shm_buffer);
Kristian Høgsbergae2ba9b2012-06-20 00:05:46 -0400140
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500141 d = wl_shm_buffer_get_data(l->buffer->shm_buffer);
Kristian Høgsbergae2ba9b2012-06-20 00:05:46 -0400142 s = pixels + stride * (l->buffer->height - 1);
Pekka Paalanena1d57db2012-04-17 15:02:08 +0300143
Neil Robertse5051712013-11-13 15:44:06 +0000144 wl_shm_buffer_begin_access(l->buffer->shm_buffer);
145
Pekka Paalanen4fc5dd02013-05-22 18:03:05 +0300146 switch (compositor->read_format) {
John Kåre Alsakerf9e710b2012-11-13 19:10:22 +0100147 case PIXMAN_a8r8g8b8:
Vasily Khoruzhick26171852013-01-06 12:12:41 +0300148 case PIXMAN_x8r8g8b8:
Pekka Paalanen4fc5dd02013-05-22 18:03:05 +0300149 if (compositor->capabilities & WESTON_CAP_CAPTURE_YFLIP)
Hardeningff39efa2013-09-18 23:56:35 +0200150 copy_bgra_yflip(d, s, output->current_mode->height, stride);
Pekka Paalanen4fc5dd02013-05-22 18:03:05 +0300151 else
Hardeningff39efa2013-09-18 23:56:35 +0200152 copy_bgra(d, pixels, output->current_mode->height, stride);
Pekka Paalanena1d57db2012-04-17 15:02:08 +0300153 break;
Vasily Khoruzhick26171852013-01-06 12:12:41 +0300154 case PIXMAN_x8b8g8r8:
John Kåre Alsakerf9e710b2012-11-13 19:10:22 +0100155 case PIXMAN_a8b8g8r8:
Pekka Paalanen4fc5dd02013-05-22 18:03:05 +0300156 if (compositor->capabilities & WESTON_CAP_CAPTURE_YFLIP)
Hardeningff39efa2013-09-18 23:56:35 +0200157 copy_rgba_yflip(d, s, output->current_mode->height, stride);
Pekka Paalanen4fc5dd02013-05-22 18:03:05 +0300158 else
Hardeningff39efa2013-09-18 23:56:35 +0200159 copy_rgba(d, pixels, output->current_mode->height, stride);
Pekka Paalanena1d57db2012-04-17 15:02:08 +0300160 break;
161 default:
162 break;
163 }
Kristian Høgsbergf02a6492012-03-12 01:05:25 -0400164
Neil Robertse5051712013-11-13 15:44:06 +0000165 wl_shm_buffer_end_access(l->buffer->shm_buffer);
166
Giulio Camuffoe9022e72013-12-11 23:45:11 +0100167 l->done(l->data, WESTON_SCREENSHOOTER_SUCCESS);
Kristian Høgsbergae2ba9b2012-06-20 00:05:46 -0400168 free(pixels);
169 free(l);
Scott Moreau062be7e2012-04-20 13:37:33 -0600170}
171
Giulio Camuffoe9022e72013-12-11 23:45:11 +0100172WL_EXPORT int
173weston_screenshooter_shoot(struct weston_output *output,
174 struct weston_buffer *buffer,
175 weston_screenshooter_done_func_t done, void *data)
176{
177 struct screenshooter_frame_listener *l;
178
179 if (!wl_shm_buffer_get(buffer->resource)) {
180 done(data, WESTON_SCREENSHOOTER_BAD_BUFFER);
181 return -1;
182 }
183
184 buffer->shm_buffer = wl_shm_buffer_get(buffer->resource);
185 buffer->width = wl_shm_buffer_get_width(buffer->shm_buffer);
186 buffer->height = wl_shm_buffer_get_height(buffer->shm_buffer);
187
188 if (buffer->width < output->current_mode->width ||
189 buffer->height < output->current_mode->height) {
190 done(data, WESTON_SCREENSHOOTER_BAD_BUFFER);
191 return -1;
192 }
193
194 l = malloc(sizeof *l);
195 if (l == NULL) {
196 done(data, WESTON_SCREENSHOOTER_NO_MEMORY);
197 return -1;
198 }
199
200 l->buffer = buffer;
201 l->done = done;
202 l->data = data;
203 l->listener.notify = screenshooter_frame_notify;
204 wl_signal_add(&output->frame_signal, &l->listener);
205 output->disable_planes++;
206 weston_output_schedule_repaint(output);
207
208 return 0;
209}
210
Kristian Høgsberg5fb70bf2012-05-24 12:29:46 -0400211struct weston_recorder {
Kristian Høgsberg79af73e2012-08-03 15:45:23 -0400212 struct weston_output *output;
Kristian Høgsberg5fb70bf2012-05-24 12:29:46 -0400213 uint32_t *frame, *rect;
Pekka Paalanen4fc5dd02013-05-22 18:03:05 +0300214 uint32_t *tmpbuf;
Kristian Høgsberg5fb70bf2012-05-24 12:29:46 -0400215 uint32_t total;
216 int fd;
217 struct wl_listener frame_listener;
Ander Conselvan de Oliveirae22f3bb2013-12-17 14:18:01 +0200218 int count, destroying;
Kristian Høgsberg5fb70bf2012-05-24 12:29:46 -0400219};
220
221static uint32_t *
222output_run(uint32_t *p, uint32_t delta, int run)
223{
224 int i;
225
226 while (run > 0) {
227 if (run <= 0xe0) {
228 *p++ = delta | ((run - 1) << 24);
229 break;
230 }
231
232 i = 24 - __builtin_clz(run);
233 *p++ = delta | ((i + 0xe0) << 24);
234 run -= 1 << (7 + i);
235 }
236
237 return p;
238}
239
Kristian Høgsberg053be422012-05-29 12:15:47 -0400240static uint32_t
241component_delta(uint32_t next, uint32_t prev)
242{
243 unsigned char dr, dg, db;
244
245 dr = (next >> 16) - (prev >> 16);
246 dg = (next >> 8) - (prev >> 8);
247 db = (next >> 0) - (prev >> 0);
248
249 return (dr << 16) | (dg << 8) | (db << 0);
250}
251
Kristian Høgsberg5fb70bf2012-05-24 12:29:46 -0400252static void
Ander Conselvan de Oliveirae22f3bb2013-12-17 14:18:01 +0200253weston_recorder_destroy(struct weston_recorder *recorder);
254
255static void
Kristian Høgsberg5fb70bf2012-05-24 12:29:46 -0400256weston_recorder_frame_notify(struct wl_listener *listener, void *data)
257{
258 struct weston_recorder *recorder =
259 container_of(listener, struct weston_recorder, frame_listener);
Kristian Høgsberge0f832b2012-06-20 00:13:18 -0400260 struct weston_output *output = data;
Pekka Paalanen4fc5dd02013-05-22 18:03:05 +0300261 struct weston_compositor *compositor = output->compositor;
Kristian Høgsberge0f832b2012-06-20 00:13:18 -0400262 uint32_t msecs = output->frame_time;
Kristian Høgsberg5fb70bf2012-05-24 12:29:46 -0400263 pixman_box32_t *r;
Ander Conselvan de Oliveira41b829c2013-12-18 19:51:39 +0200264 pixman_region32_t damage, transformed_damage;
Kristian Høgsberg5fb70bf2012-05-24 12:29:46 -0400265 int i, j, k, n, width, height, run, stride;
266 uint32_t delta, prev, *d, *s, *p, next;
267 struct {
268 uint32_t msecs;
269 uint32_t nrects;
270 } header;
271 struct iovec v[2];
Pekka Paalanen4fc5dd02013-05-22 18:03:05 +0300272 int do_yflip;
273 int y_orig;
274 uint32_t *outbuf;
275
276 do_yflip = !!(compositor->capabilities & WESTON_CAP_CAPTURE_YFLIP);
277 if (do_yflip)
278 outbuf = recorder->rect;
279 else
280 outbuf = recorder->tmpbuf;
Kristian Høgsberg5fb70bf2012-05-24 12:29:46 -0400281
282 pixman_region32_init(&damage);
Ander Conselvan de Oliveira41b829c2013-12-18 19:51:39 +0200283 pixman_region32_init(&transformed_damage);
Ander Conselvan de Oliveirab8fcca92012-11-16 17:23:52 +0200284 pixman_region32_intersect(&damage, &output->region,
285 &output->previous_damage);
Ander Conselvan de Oliveira41b829c2013-12-18 19:51:39 +0200286 pixman_region32_translate(&damage, -output->x, -output->y);
287 weston_transformed_region(output->width, output->height,
288 output->transform, output->current_scale,
289 &damage, &transformed_damage);
290 pixman_region32_fini(&damage);
Kristian Høgsberg5fb70bf2012-05-24 12:29:46 -0400291
Ander Conselvan de Oliveira41b829c2013-12-18 19:51:39 +0200292 r = pixman_region32_rectangles(&transformed_damage, &n);
293 if (n == 0) {
294 pixman_region32_fini(&transformed_damage);
Kristian Høgsberg5fb70bf2012-05-24 12:29:46 -0400295 return;
Ander Conselvan de Oliveira41b829c2013-12-18 19:51:39 +0200296 }
Kristian Høgsbergf0377dd2012-11-14 20:28:30 -0500297
Kristian Høgsberg5fb70bf2012-05-24 12:29:46 -0400298 header.msecs = msecs;
299 header.nrects = n;
300 v[0].iov_base = &header;
301 v[0].iov_len = sizeof header;
302 v[1].iov_base = r;
303 v[1].iov_len = n * sizeof *r;
304 recorder->total += writev(recorder->fd, v, 2);
Hardeningff39efa2013-09-18 23:56:35 +0200305 stride = output->current_mode->width;
Kristian Høgsberg5fb70bf2012-05-24 12:29:46 -0400306
307 for (i = 0; i < n; i++) {
308 width = r[i].x2 - r[i].x1;
309 height = r[i].y2 - r[i].y1;
Pekka Paalanen4fc5dd02013-05-22 18:03:05 +0300310
311 if (do_yflip)
Hardeningff39efa2013-09-18 23:56:35 +0200312 y_orig = output->current_mode->height - r[i].y2;
Pekka Paalanen4fc5dd02013-05-22 18:03:05 +0300313 else
314 y_orig = r[i].y1;
315
316 compositor->renderer->read_pixels(output,
317 compositor->read_format, recorder->rect,
318 r[i].x1, y_orig, width, height);
Kristian Høgsberg5fb70bf2012-05-24 12:29:46 -0400319
Pekka Paalanen4fc5dd02013-05-22 18:03:05 +0300320 p = outbuf;
Kristian Høgsberg5fb70bf2012-05-24 12:29:46 -0400321 run = prev = 0; /* quiet gcc */
322 for (j = 0; j < height; j++) {
Pekka Paalanen4fc5dd02013-05-22 18:03:05 +0300323 if (do_yflip)
Tomohito Esaki9054e4c2015-07-07 19:06:05 +0900324 s = recorder->rect + width * j;
Pekka Paalanen4fc5dd02013-05-22 18:03:05 +0300325 else
Tomohito Esaki9054e4c2015-07-07 19:06:05 +0900326 s = recorder->rect + width * (height - j - 1);
327 y_orig = r[i].y2 - j - 1;
Pekka Paalanen4fc5dd02013-05-22 18:03:05 +0300328 d = recorder->frame + stride * y_orig + r[i].x1;
329
Kristian Høgsberg5fb70bf2012-05-24 12:29:46 -0400330 for (k = 0; k < width; k++) {
331 next = *s++;
Kristian Høgsberg053be422012-05-29 12:15:47 -0400332 delta = component_delta(next, *d);
Kristian Høgsberg5fb70bf2012-05-24 12:29:46 -0400333 *d++ = next;
334 if (run == 0 || delta == prev) {
335 run++;
336 } else {
337 p = output_run(p, prev, run);
338 run = 1;
Kristian Høgsberg5fb70bf2012-05-24 12:29:46 -0400339 }
Kristian Høgsberg9c9b3a42012-06-20 00:28:16 -0400340 prev = delta;
Kristian Høgsberg5fb70bf2012-05-24 12:29:46 -0400341 }
342 }
343
344 p = output_run(p, prev, run);
345
346 recorder->total += write(recorder->fd,
Pekka Paalanen4fc5dd02013-05-22 18:03:05 +0300347 outbuf, (p - outbuf) * 4);
Kristian Høgsberg5fb70bf2012-05-24 12:29:46 -0400348
349#if 0
350 fprintf(stderr,
351 "%dx%d at %d,%d rle from %d to %d bytes (%f) total %dM\n",
352 width, height, r[i].x1, r[i].y1,
Pekka Paalanen4fc5dd02013-05-22 18:03:05 +0300353 width * height * 4, (int) (p - outbuf) * 4,
354 (float) (p - outbuf) / (width * height),
Kristian Høgsbergf6f69d32012-06-18 17:10:19 -0400355 recorder->total / 1024 / 1024);
Kristian Høgsberg5fb70bf2012-05-24 12:29:46 -0400356#endif
357 }
358
Ander Conselvan de Oliveira41b829c2013-12-18 19:51:39 +0200359 pixman_region32_fini(&transformed_damage);
Pekka Paalanend0cbf182013-05-22 18:03:12 +0300360 recorder->count++;
Ander Conselvan de Oliveirae22f3bb2013-12-17 14:18:01 +0200361
362 if (recorder->destroying)
363 weston_recorder_destroy(recorder);
Kristian Høgsberg5fb70bf2012-05-24 12:29:46 -0400364}
365
366static void
Bryce W. Harringtonbfd74f42014-04-21 23:51:02 +0000367weston_recorder_free(struct weston_recorder *recorder)
368{
369 if (recorder == NULL)
370 return;
Marek Chalupaab9285b2014-12-10 11:50:46 +0100371
Bryce W. Harringtonbfd74f42014-04-21 23:51:02 +0000372 free(recorder->tmpbuf);
Marek Chalupaab9285b2014-12-10 11:50:46 +0100373 free(recorder->rect);
Bryce W. Harringtonbfd74f42014-04-21 23:51:02 +0000374 free(recorder->frame);
375 free(recorder);
376}
377
Giulio Camuffo26f62d42016-06-02 21:48:09 +0300378static struct weston_recorder *
Kristian Høgsberg5fb70bf2012-05-24 12:29:46 -0400379weston_recorder_create(struct weston_output *output, const char *filename)
380{
Pekka Paalanen4fc5dd02013-05-22 18:03:05 +0300381 struct weston_compositor *compositor = output->compositor;
Kristian Høgsberg5fb70bf2012-05-24 12:29:46 -0400382 struct weston_recorder *recorder;
383 int stride, size;
Kristian Høgsberg3b969602012-05-25 17:45:39 -0400384 struct { uint32_t magic, format, width, height; } header;
Pekka Paalanen4fc5dd02013-05-22 18:03:05 +0300385 int do_yflip;
386
387 do_yflip = !!(compositor->capabilities & WESTON_CAP_CAPTURE_YFLIP);
Kristian Høgsberg5fb70bf2012-05-24 12:29:46 -0400388
Bryce Harringtonde447612014-11-20 22:21:55 -0800389 recorder = zalloc(sizeof *recorder);
U. Artie Eoff13708a42014-01-15 09:36:00 -0800390 if (recorder == NULL) {
391 weston_log("%s: out of memory\n", __func__);
Giulio Camuffo26f62d42016-06-02 21:48:09 +0300392 return NULL;
U. Artie Eoff13708a42014-01-15 09:36:00 -0800393 }
394
Hardeningff39efa2013-09-18 23:56:35 +0200395 stride = output->current_mode->width;
396 size = stride * 4 * output->current_mode->height;
Peter Huttererf3d62272013-08-08 11:57:05 +1000397 recorder->frame = zalloc(size);
Kristian Høgsberg5fb70bf2012-05-24 12:29:46 -0400398 recorder->rect = malloc(size);
Kristian Høgsberg79af73e2012-08-03 15:45:23 -0400399 recorder->output = output;
Kristian Høgsberg5fb70bf2012-05-24 12:29:46 -0400400
Bryce W. Harringtonbfd74f42014-04-21 23:51:02 +0000401 if ((recorder->frame == NULL) || (recorder->rect == NULL)) {
402 weston_log("%s: out of memory\n", __func__);
Marek Chalupaab9285b2014-12-10 11:50:46 +0100403 goto err_recorder;
Bryce W. Harringtonbfd74f42014-04-21 23:51:02 +0000404 }
405
Marek Chalupaab9285b2014-12-10 11:50:46 +0100406 if (!do_yflip) {
Pekka Paalanen4fc5dd02013-05-22 18:03:05 +0300407 recorder->tmpbuf = malloc(size);
Marek Chalupaab9285b2014-12-10 11:50:46 +0100408 if (recorder->tmpbuf == NULL) {
409 weston_log("%s: out of memory\n", __func__);
410 goto err_recorder;
411 }
412 }
Pekka Paalanen4fc5dd02013-05-22 18:03:05 +0300413
Kristian Høgsberg3b969602012-05-25 17:45:39 -0400414 header.magic = WCAP_HEADER_MAGIC;
415
Pekka Paalanen4fc5dd02013-05-22 18:03:05 +0300416 switch (compositor->read_format) {
Alexander Larsson55765462013-05-29 12:01:32 +0200417 case PIXMAN_x8r8g8b8:
John Kåre Alsakerf9e710b2012-11-13 19:10:22 +0100418 case PIXMAN_a8r8g8b8:
Kristian Høgsberg3b969602012-05-25 17:45:39 -0400419 header.format = WCAP_FORMAT_XRGB8888;
420 break;
John Kåre Alsakerf9e710b2012-11-13 19:10:22 +0100421 case PIXMAN_a8b8g8r8:
Kristian Høgsberg3b969602012-05-25 17:45:39 -0400422 header.format = WCAP_FORMAT_XBGR8888;
423 break;
John Kåre Alsakerf9e710b2012-11-13 19:10:22 +0100424 default:
425 weston_log("unknown recorder format\n");
Marek Chalupaab9285b2014-12-10 11:50:46 +0100426 goto err_recorder;
Kristian Høgsberg3b969602012-05-25 17:45:39 -0400427 }
428
Rob Bradfordba1e2922012-12-05 18:47:04 +0000429 recorder->fd = open(filename,
430 O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0644);
431
432 if (recorder->fd < 0) {
433 weston_log("problem opening output file %s: %m\n", filename);
Marek Chalupaab9285b2014-12-10 11:50:46 +0100434 goto err_recorder;
Rob Bradfordba1e2922012-12-05 18:47:04 +0000435 }
436
Hardeningff39efa2013-09-18 23:56:35 +0200437 header.width = output->current_mode->width;
438 header.height = output->current_mode->height;
Kristian Høgsberg5fb70bf2012-05-24 12:29:46 -0400439 recorder->total += write(recorder->fd, &header, sizeof header);
440
441 recorder->frame_listener.notify = weston_recorder_frame_notify;
442 wl_signal_add(&output->frame_signal, &recorder->frame_listener);
Kristian Høgsberg79af73e2012-08-03 15:45:23 -0400443 output->disable_planes++;
Kristian Høgsberg5fb70bf2012-05-24 12:29:46 -0400444 weston_output_damage(output);
Marek Chalupaab9285b2014-12-10 11:50:46 +0100445
Giulio Camuffo26f62d42016-06-02 21:48:09 +0300446 return recorder;
Marek Chalupaab9285b2014-12-10 11:50:46 +0100447
448err_recorder:
449 weston_recorder_free(recorder);
Giulio Camuffo26f62d42016-06-02 21:48:09 +0300450 return NULL;
Kristian Høgsberg5fb70bf2012-05-24 12:29:46 -0400451}
452
453static void
454weston_recorder_destroy(struct weston_recorder *recorder)
455{
456 wl_list_remove(&recorder->frame_listener.link);
457 close(recorder->fd);
Kristian Høgsberg79af73e2012-08-03 15:45:23 -0400458 recorder->output->disable_planes--;
Bryce W. Harringtonbfd74f42014-04-21 23:51:02 +0000459 weston_recorder_free(recorder);
Kristian Høgsberg5fb70bf2012-05-24 12:29:46 -0400460}
461
Giulio Camuffo26f62d42016-06-02 21:48:09 +0300462WL_EXPORT struct weston_recorder *
463weston_recorder_start(struct weston_output *output, const char *filename)
Kristian Høgsberg5fb70bf2012-05-24 12:29:46 -0400464{
Giulio Camuffo26f62d42016-06-02 21:48:09 +0300465 struct wl_listener *listener;
Kristian Høgsberg5fb70bf2012-05-24 12:29:46 -0400466
Giulio Camuffo26f62d42016-06-02 21:48:09 +0300467 listener = wl_signal_get(&output->frame_signal,
468 weston_recorder_frame_notify);
Kristian Høgsberg5fb70bf2012-05-24 12:29:46 -0400469 if (listener) {
Giulio Camuffo26f62d42016-06-02 21:48:09 +0300470 weston_log("a recorder on output %s is already running\n",
471 output->name);
472 return NULL;
Kristian Høgsberg5fb70bf2012-05-24 12:29:46 -0400473 }
Kristian Høgsberg5fb70bf2012-05-24 12:29:46 -0400474
Giulio Camuffo26f62d42016-06-02 21:48:09 +0300475 weston_log("starting recorder for output %s, file %s\n",
476 output->name, filename);
477 return weston_recorder_create(output, filename);
Kristian Høgsberg02e79dc2012-04-12 09:55:26 -0400478}
479
Giulio Camuffoc6ab3d52013-12-11 23:45:12 +0100480WL_EXPORT void
Giulio Camuffo26f62d42016-06-02 21:48:09 +0300481weston_recorder_stop(struct weston_recorder *recorder)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400482{
Giulio Camuffo26f62d42016-06-02 21:48:09 +0300483 weston_log("stopping recorder, total file size %dM, %d frames\n",
484 recorder->total / (1024 * 1024), recorder->count);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400485
Giulio Camuffo26f62d42016-06-02 21:48:09 +0300486 recorder->destroying = 1;
487 weston_output_schedule_repaint(recorder->output);
Pekka Paalanen35ce06d2012-01-03 11:39:13 +0200488}