~ubuntu-branches/ubuntu/utopic/mir/utopic-proposed

« back to all changes in this revision

Viewing changes to src/utils/screencast.cpp

  • Committer: Package Import Robot
  • Author(s): Ubuntu daily release
  • Date: 2014-03-10 19:28:46 UTC
  • mto: This revision was merged to the branch mainline in revision 63.
  • Revision ID: package-import@ubuntu.com-20140310192846-rq9qm3ec26yrelo2
Tags: upstream-0.1.6+14.04.20140310
ImportĀ upstreamĀ versionĀ 0.1.6+14.04.20140310

Show diffs side-by-side

added added

removed removed

Lines of Context:
42
42
 
43
43
volatile sig_atomic_t running = 1;
44
44
 
 
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
 
45
51
void shutdown(int)
46
52
{
47
53
    running = 0;
48
54
}
49
55
 
50
 
std::future<void> write_frame_to_file(
51
 
    std::vector<char> const& frame_data, int frame_number, GLenum format)
52
 
{
53
 
    return std::async(
54
 
        std::launch::async,
55
 
        [&frame_data, frame_number, format]
56
 
        {
57
 
            std::stringstream ss;
58
 
            ss << "/tmp/mir_" ;
59
 
            ss.width(5);
60
 
            ss.fill('0');
61
 
            ss << frame_number;
62
 
            ss << (format == GL_BGRA_EXT ? ".bgra" : ".rgba");
63
 
            std::ofstream f(ss.str());
64
 
            f.write(frame_data.data(), frame_data.size());
65
 
        });
66
 
}
67
 
 
68
 
GLenum read_pixels(mir::geometry::Size const& size, void* buffer)
 
56
void read_pixels(GLenum format, mir::geometry::Size const& size, void* buffer)
69
57
{
70
58
    auto width = size.width.as_uint32_t();
71
59
    auto height = size.height.as_uint32_t();
72
60
 
73
 
    GLenum format = GL_BGRA_EXT;
74
 
 
75
61
    glReadPixels(0, 0, width, height, format, GL_UNSIGNED_BYTE, buffer);
76
 
 
77
 
    if (glGetError() != GL_NO_ERROR)
78
 
    {
79
 
        format = GL_RGBA;
80
 
        glReadPixels(0, 0, width, height, format, GL_UNSIGNED_BYTE, buffer);
81
 
    }
82
 
 
83
 
    return format;
84
62
}
85
63
 
86
64
 
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;
140
120
}
141
121
 
184
164
        {
185
165
            throw std::runtime_error("Failed to make screencast surface current");
186
166
        }
 
167
 
 
168
        uint32_t a_pixel;
 
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;
 
172
        else
 
173
            read_pixel_format = GL_RGBA;
187
174
    }
188
175
 
189
176
    ~EGLSetup()
200
187
            throw std::runtime_error("Failed to swap screencast surface buffers");
201
188
    }
202
189
 
 
190
    GLenum pixel_read_format()
 
191
    {
 
192
        return read_pixel_format;
 
193
    }
 
194
 
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;
207
200
};
208
201
 
209
202
void do_screencast(MirConnection* connection, MirScreencast* screencast,
210
 
                   uint32_t output_id)
 
203
                   uint32_t output_id, int32_t number_of_captures)
211
204
{
212
205
    static int const rgba_pixel_size{4};
213
206
 
216
209
                                  frame_size.width.as_uint32_t() *
217
210
                                  frame_size.height.as_uint32_t();
218
211
 
219
 
    int frame_number{0};
220
212
    std::vector<char> frame_data(frame_size_bytes, 0);
221
 
    std::future<void> frame_written_future =
222
 
        std::async(std::launch::deferred, []{});
223
213
 
224
214
    EGLSetup egl_setup{connection, screencast};
225
 
 
226
 
    while (running)
 
215
    auto format = egl_setup.pixel_read_format();
 
216
 
 
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());
 
222
 
 
223
    while (running && (number_of_captures != 0))
227
224
    {
228
 
        frame_written_future.wait();
 
225
        read_pixels(format, frame_size, frame_data.data());
229
226
 
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(
 
228
                std::launch::async,
 
229
                [&video_file, &frame_data] {
 
230
                    video_file.write(frame_data.data(), frame_data.size());
 
231
                });
232
232
 
233
233
        egl_setup.swap_buffers();
234
 
        ++frame_number;
 
234
 
 
235
        write_out_future.wait();
 
236
 
 
237
        if (number_of_captures > 0)
 
238
            number_of_captures--;
235
239
    }
236
240
}
237
241
 
244
248
    opterr = 0;
245
249
    char const* socket_file = nullptr;
246
250
    uint32_t output_id = mir_display_output_id_invalid;
247
 
 
248
 
    while ((arg = getopt (argc, argv, "hm:o:")) != -1)
 
251
    int32_t number_of_captures = -1;
 
252
 
 
253
    //avoid unused warning/error
 
254
    tls_hack[0] = 0;
 
255
 
 
256
    while ((arg = getopt (argc, argv, "hm:o:n:")) != -1)
249
257
    {
250
258
        switch (arg)
251
259
        {
 
260
        case 'n':
 
261
            number_of_captures = std::stoi(std::string(optarg)); 
 
262
            break;
252
263
        case 'm':
253
264
            socket_file = optarg;
254
265
            break;
301
312
    if (screencast == nullptr)
302
313
        throw std::runtime_error("Failed to create screencast");
303
314
 
304
 
    do_screencast(connection.get(), screencast.get(), output_id);
 
315
    do_screencast(connection.get(), screencast.get(), output_id, number_of_captures);
305
316
 
306
317
    return EXIT_SUCCESS;
307
318
}
 
319
catch(std::invalid_argument const& e)
 
320
{
 
321
    std::cerr << "Invalid Argument" << std::endl;
 
322
    print_usage();
 
323
    return EXIT_FAILURE;
 
324
}
308
325
catch(std::exception const& e)
309
326
{
310
327
    std::cerr << e.what() << std::endl;
311
 
 
312
328
    return EXIT_FAILURE;
313
329
}