总体三部分:
client: screenshot.c
server: screenshooter.c + gl-renderer.c + weston-screenshooter.c
client很简单,总共三百行代码,标准注册流程的代码就不拿出来了。
int main(int argc, char *argv[])
{
wl_list_init(&sh_data.output_list);
//创建一个outputlist。管理多个output
...
wl_registry_add_listener(registry, ®istry_listener, &sh_data);
wl_display_dispatch(display);
wl_display_roundtrip(display);
//注意这里注册上监听的第一次动作要完成一次roundtrip
...
weston_screenshooter_add_listener(sh_data.screenshooter,
&screenshooter_listener,
&sh_data);
//这个listener主要是保证截屏完成,server发过来一个done事件。
if (screenshot_set_buffer_size(&buff_size, &sh_data.output_list))
return -1;
//根据之前的output算出需要的shmbuffer的大小。
wl_list_for_each(output, &sh_data.output_list, link) {
output->buffer =
screenshot_create_shm_buffer(output->width,
output->height,
&output->data,
sh_data.shm);
//创建buffer,与server完成共享。
weston_screenshooter_take_shot(sh_data.screenshooter,
output->output,
output->buffer);
//和server交互的操作。在weston-screenshooter.c里面。
sh_data.buffer_copy_done = 0;
while (!sh_data.buffer_copy_done)
wl_display_roundtrip(display);
//如果没接收到done。就一直转圈圈等。
}
screenshot_write_png(&buff_size, &sh_data.output_list);
}
static void
handle_global(void *data, struct wl_registry *registry,
uint32_t name, const char *interface, uint32_t version)
{
static struct screenshooter_output *output;
struct screenshooter_data *sh_data = data;
if (strcmp(interface, "wl_output") == 0) {
output = xmalloc(sizeof *output);
output->output = wl_registry_bind(registry, name,
&wl_output_interface, 1);
wl_list_insert(&sh_data->output_list, &output->link);
wl_output_add_listener(output->output, &output_listener, output);
} else if (strcmp(interface, "wl_shm") == 0) {
sh_data->shm = wl_registry_bind(registry, name, &wl_shm_interface, 1);
} else if (strcmp(interface, "weston_screenshooter") == 0) {
sh_data->screenshooter = wl_registry_bind(registry, name,
&weston_screenshooter_interface,
1);
}
}
handle里面绑了shm,output和screenshooter三个必要的服务。
screeenshot.c里面的 weston_screenshooter_take_shot对应的是weston-screenshooter.c里面的如下部分:
static void
screenshooter_take_shot(struct wl_client *client,
struct wl_resource *resource,
struct wl_resource *output_resource,
struct wl_resource *buffer_resource)
{
struct weston_output *output =
weston_head_from_resource(output_resource)->output;
struct weston_buffer *buffer =
weston_buffer_from_resource(buffer_resource);
if (buffer == NULL) {
wl_resource_post_no_memory(resource);
return;
}
weston_screenshooter_shoot(output, buffer, screenshooter_done, resource);
}
struct weston_screenshooter_interface screenshooter_implementation = {
screenshooter_take_shot
};
weston_screenshooter_shoot里面主要如下:
l->buffer = buffer;
l->output = output;
l->done = done;
l->data = data;
l->listener.notify = screenshooter_frame_notify;
wl_signal_add(&output->frame_signal, &l->listener);
weston_output_disable_planes_incr(output);
weston_output_schedule_repaint(output);
先讲一下和这个weston_output_disable_planes_incr和weston_output_disable_planes_decr
这俩函数是用来保证protected surface的。也就是hdcp相关的功能。可以具体看注释,代码。
最重要就是绑定这个screenshooter_frame_notify
出发是在repaint-output的swapbuffer之前,最重要的就是:
compositor->renderer->read_pixels(output,
compositor->read_format, pixels,
0, 0, output->current_mode->width,
output->current_mode->height);
对应的实现:
if (use_output(output) < 0)
return -1;
glPixelStorei(GL_PACK_ALIGNMENT, 1);
glReadPixels(x, y, width, height, gl_format,
GL_UNSIGNED_BYTE, pixels);