43
43
volatile sig_atomic_t running = 1;
45
//In android, waiting for a future is causing the gl/egl context to become invalid
46
//possibly due to assumptions in libhybris/android linker.
47
//A TLS allocation in the main thread is forced with this variable which seems to push
48
//the gl/egl context TLS into a slot where the future wait code does not overwrite it.
49
thread_local int tls_hack[2];
50
std::future<void> write_frame_to_file(
51
std::vector<char> const& frame_data, int frame_number, GLenum format)
55
[&frame_data, frame_number, format]
62
ss << (format == GL_BGRA_EXT ? ".bgra" : ".rgba");
63
std::ofstream f(ss.str());
64
f.write(frame_data.data(), frame_data.size());
68
GLenum read_pixels(mir::geometry::Size const& size, void* buffer)
56
void read_pixels(GLenum format, mir::geometry::Size const& size, void* buffer)
70
58
auto width = size.width.as_uint32_t();
71
59
auto height = size.height.as_uint32_t();
73
GLenum format = GL_BGRA_EXT;
75
61
glReadPixels(0, 0, width, height, format, GL_UNSIGNED_BYTE, buffer);
77
if (glGetError() != GL_NO_ERROR)
80
glReadPixels(0, 0, width, height, format, GL_UNSIGNED_BYTE, buffer);
136
114
std::cout << "Usage " << std::endl
137
115
<< " -m <Mir server socket>" << std::endl
138
116
<< " -o <Output id>" << std::endl
117
<< " -n <Number of frames to capture>" << std::endl
118
<< " default (-1) is to capture infinite frames" << std::endl
139
119
<< " -h: this help text" << std::endl;
185
165
throw std::runtime_error("Failed to make screencast surface current");
169
glReadPixels(0, 0, 1, 1, GL_BGRA_EXT, GL_UNSIGNED_BYTE, &a_pixel);
170
if (glGetError() == GL_NO_ERROR)
171
read_pixel_format = GL_BGRA_EXT;
173
read_pixel_format = GL_RGBA;
200
187
throw std::runtime_error("Failed to swap screencast surface buffers");
190
GLenum pixel_read_format()
192
return read_pixel_format;
203
195
EGLDisplay egl_display;
204
196
EGLContext egl_context;
205
197
EGLSurface egl_surface;
206
198
EGLConfig egl_config;
199
GLenum read_pixel_format;
209
202
void do_screencast(MirConnection* connection, MirScreencast* screencast,
203
uint32_t output_id, int32_t number_of_captures)
212
205
static int const rgba_pixel_size{4};
216
209
frame_size.width.as_uint32_t() *
217
210
frame_size.height.as_uint32_t();
220
212
std::vector<char> frame_data(frame_size_bytes, 0);
221
std::future<void> frame_written_future =
222
std::async(std::launch::deferred, []{});
224
214
EGLSetup egl_setup{connection, screencast};
215
auto format = egl_setup.pixel_read_format();
217
std::stringstream ss;
218
ss << "/tmp/mir_screencast_" ;
219
ss << frame_size.width << "x" << frame_size.height;
220
ss << (format == GL_BGRA_EXT ? ".bgra" : ".rgba");
221
std::ofstream video_file(ss.str());
223
while (running && (number_of_captures != 0))
228
frame_written_future.wait();
225
read_pixels(format, frame_size, frame_data.data());
230
auto format = read_pixels(frame_size, frame_data.data());
231
frame_written_future = write_frame_to_file(frame_data, frame_number, format);
227
auto write_out_future = std::async(
229
[&video_file, &frame_data] {
230
video_file.write(frame_data.data(), frame_data.size());
233
233
egl_setup.swap_buffers();
235
write_out_future.wait();
237
if (number_of_captures > 0)
238
number_of_captures--;
245
249
char const* socket_file = nullptr;
246
250
uint32_t output_id = mir_display_output_id_invalid;
248
while ((arg = getopt (argc, argv, "hm:o:")) != -1)
251
int32_t number_of_captures = -1;
253
//avoid unused warning/error
256
while ((arg = getopt (argc, argv, "hm:o:n:")) != -1)
261
number_of_captures = std::stoi(std::string(optarg));
253
264
socket_file = optarg;
301
312
if (screencast == nullptr)
302
313
throw std::runtime_error("Failed to create screencast");
304
do_screencast(connection.get(), screencast.get(), output_id);
315
do_screencast(connection.get(), screencast.get(), output_id, number_of_captures);
306
317
return EXIT_SUCCESS;
319
catch(std::invalid_argument const& e)
321
std::cerr << "Invalid Argument" << std::endl;
308
325
catch(std::exception const& e)
310
327
std::cerr << e.what() << std::endl;
312
328
return EXIT_FAILURE;