天天看點

weston:client:screenshoot

總體三部分:

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, &registry_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);