From cd5e954bb61789cd035ed6166bc279ce0be55fba Mon Sep 17 00:00:00 2001 From: Martin Pulec Date: Mon, 4 Nov 2013 15:09:02 +0100 Subject: [PATCH] Split screen capture module Split screen capture modules into platform specific files (X11 and OS X). --- configure.ac | 9 +- src/video_capture.c | 18 +- src/video_capture/screen_osx.c | 234 +++++++++++++++++++ src/video_capture/{screen.h => screen_osx.h} | 39 ++-- src/video_capture/{screen.c => screen_x11.c} | 144 +++--------- src/video_capture/screen_x11.h | 44 ++++ 6 files changed, 344 insertions(+), 144 deletions(-) create mode 100644 src/video_capture/screen_osx.c rename src/video_capture/{screen.h => screen_osx.h} (59%) rename src/video_capture/{screen.c => screen_x11.c} (77%) create mode 100644 src/video_capture/screen_x11.h diff --git a/configure.ac b/configure.ac index 50f63ac12..58ae54daa 100644 --- a/configure.ac +++ b/configure.ac @@ -1668,9 +1668,14 @@ esac if test $screen_cap = yes then - AC_DEFINE([HAVE_SCREEN_CAP], [1], [Build with screen_capture]) + AC_DEFINE([HAVE_SCREEN_CAP], [1], [Build with screen capture]) AC_SUBST(SCREEN_CAP_LIB_TARGET, "lib/ultragrid/vidcap_screen.so.$video_capture_abi_version") - SCREEN_CAP_OBJ="src/video_capture/screen.o" + if test $system = MacOSX; then + SCREEN_CAP_OBJ="src/video_capture/screen_osx.o" + else if test $system = Linux; then + SCREEN_CAP_OBJ="src/video_capture/screen_x11.o" + fi + fi LIB_TARGETS="$LIB_TARGETS $SCREEN_CAP_LIB_TARGET" LIB_OBJS="$LIB_OBJS $SCREEN_CAP_OBJ" fi diff --git a/src/video_capture.c b/src/video_capture.c index d17207e56..148d03b66 100644 --- a/src/video_capture.c +++ b/src/video_capture.c @@ -75,7 +75,8 @@ #include "video_capture/linsys.h" #include "video_capture/null.h" #include "video_capture/quicktime.h" -#include "video_capture/screen.h" +#include "video_capture/screen_osx.h" +#include "video_capture/screen_x11.h" #include "video_capture/swmix.h" #include "video_capture/testcard.h" #include "video_capture/testcard2.h" @@ -217,10 +218,17 @@ struct vidcap_device_api vidcap_device_table[] = { /* The screen capture card */ 0, "screen", - MK_NAME(vidcap_screen_probe), - MK_NAME(vidcap_screen_init), - MK_NAME(vidcap_screen_done), - MK_NAME(vidcap_screen_grab), +#ifdef HAVE_LINUX + MK_NAME(vidcap_screen_x11_probe), + MK_NAME(vidcap_screen_x11_init), + MK_NAME(vidcap_screen_x11_done), + MK_NAME(vidcap_screen_x11_grab), +#else + MK_NAME(vidcap_screen_osx_probe), + MK_NAME(vidcap_screen_osx_init), + MK_NAME(vidcap_screen_osx_done), + MK_NAME(vidcap_screen_osx_grab), +#endif // ! defined HAVE_LINUX NULL }, #endif /* HAVE_SCREEN */ diff --git a/src/video_capture/screen_osx.c b/src/video_capture/screen_osx.c new file mode 100644 index 000000000..2a9167f5f --- /dev/null +++ b/src/video_capture/screen_osx.c @@ -0,0 +1,234 @@ +/** + * @file screen_osx.c + * @author Martin Pulec + */ +/* + * Copyright (c) 2012-2013 CESNET, z.s.p.o. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, is permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of CESNET nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#include "config_unix.h" +#include "config_win32.h" +#endif /* HAVE_CONFIG_H */ + +#include "debug.h" +#include "host.h" +#include "video.h" +#include "video_capture.h" + +#include "tv.h" + +#include "video_capture/screen_osx.h" +#include "audio/audio.h" + +#include +#include +#include + +#include + +#include +#include +#include + +/* prototypes of functions defined in this module */ +static void show_help(void); + +static void show_help() +{ + printf("Screen capture\n"); + printf("Usage\n"); + printf("\t-t screen[:fps=]\n"); + printf("\t\t - preferred grabbing fps (otherwise unlimited)\n"); +} + +struct vidcap_screen_osx_state { + struct video_frame *frame; + struct tile *tile; + int frames; + struct timeval t, t0; + CGDirectDisplayID display; + + struct timeval prev_time; + + double fps; + + bool initialized; +}; + +static void initialize(struct vidcap_screen_osx_state *s) { + s->frame = vf_alloc(1); + s->tile = vf_get_tile(s->frame, 0); + + s->display = CGMainDisplayID(); + CGImageRef image = CGDisplayCreateImage(s->display); + + s->tile->width = CGImageGetWidth(image); + s->tile->height = CGImageGetHeight(image); + CFRelease(image); + + s->frame->color_spec = RGBA; + if(s->fps > 0.0) { + s->frame->fps = s->fps; + } else { + s->frame->fps = 30; + } + s->frame->interlacing = PROGRESSIVE; + s->tile->data_len = vc_get_linesize(s->tile->width, s->frame->color_spec) * s->tile->height; + + s->tile->data = (char *) malloc(s->tile->data_len); + + return; + + goto error; // dummy use (otherwise compiler would complain about unreachable code (Mac) +error: + fprintf(stderr, "[Screen cap.] Initialization failed!\n"); + exit_uv(128); +} + +struct vidcap_type * vidcap_screen_osx_probe(void) +{ + struct vidcap_type* vt; + + vt = (struct vidcap_type *) malloc(sizeof(struct vidcap_type)); + if (vt != NULL) { + vt->id = VIDCAP_SCREEN_ID; + vt->name = "screen"; + vt->description = "Grabbing screen"; + } + return vt; +} + +void * vidcap_screen_osx_init(const struct vidcap_params *params) +{ + struct vidcap_screen_osx_state *s; + + printf("vidcap_screen_init\n"); + + s = (struct vidcap_screen_osx_state *) malloc(sizeof(struct vidcap_screen_osx_state)); + if(s == NULL) { + printf("Unable to allocate screen capture state\n"); + return NULL; + } + + s->initialized = false; + + gettimeofday(&s->t0, NULL); + + s->fps = 0.0; + + s->frame = NULL; + s->tile = NULL; + + s->prev_time.tv_sec = + s->prev_time.tv_usec = 0; + + s->frames = 0; + + if(vidcap_params_get_fmt(params)) { + if (strcmp(vidcap_params_get_fmt(params), "help") == 0) { + show_help(); + return &vidcap_init_noerr; + } else if (strncasecmp(vidcap_params_get_fmt(params), "fps=", strlen("fps=")) == 0) { + s->fps = atoi(vidcap_params_get_fmt(params) + strlen("fps=")); + } + } + + return s; +} + +void vidcap_screen_osx_done(void *state) +{ + struct vidcap_screen_osx_state *s = (struct vidcap_screen_osx_state *) state; + + assert(s != NULL); + + if(s->tile) { + free(s->tile->data); + } + vf_free(s->frame); + free(s); +} + +struct video_frame * vidcap_screen_osx_grab(void *state, struct audio_frame **audio) +{ + struct vidcap_screen_osx_state *s = (struct vidcap_screen_osx_state *) state; + + if (!s->initialized) { + initialize(s); + s->initialized = true; + } + + *audio = NULL; + + CGImageRef image = CGDisplayCreateImage(s->display); + CFDataRef data = CGDataProviderCopyData(CGImageGetDataProvider(image)); + const unsigned char *pixels = CFDataGetBytePtr(data); + + int linesize = s->tile->width * 4; + int y; + unsigned char *dst = (unsigned char *) s->tile->data; + const unsigned char *src = (const unsigned char *) pixels; + for(y = 0; y < (int) s->tile->height; ++y) { + vc_copylineRGBA (dst, src, linesize, 16, 8, 0); + src += linesize; + dst += linesize; + } + + CFRelease(data); + CFRelease(image); + + if(s->fps > 0.0) { + struct timeval cur_time; + + gettimeofday(&cur_time, NULL); + while(tv_diff_usec(cur_time, s->prev_time) < 1000000.0 / s->frame->fps) { + gettimeofday(&cur_time, NULL); + } + s->prev_time = cur_time; + } + + gettimeofday(&s->t, NULL); + double seconds = tv_diff(s->t, s->t0); + if (seconds >= 5) { + float fps = s->frames / seconds; + fprintf(stderr, "[screen capture] %d frames in %g seconds = %g FPS\n", s->frames, seconds, fps); + s->t0 = s->t; + s->frames = 0; + } + + s->frames++; + + return s->frame; +} + diff --git a/src/video_capture/screen.h b/src/video_capture/screen_osx.h similarity index 59% rename from src/video_capture/screen.h rename to src/video_capture/screen_osx.h index a0bbc9649..1bc5e245a 100644 --- a/src/video_capture/screen.h +++ b/src/video_capture/screen_osx.h @@ -1,32 +1,23 @@ +/** + * @file screen_osx.h + * @author Martin Pulec + */ /* - * FILE: screen.h - * AUTHORS: Martin Benes - * Lukas Hejtmanek - * Petr Holub - * Milos Liska - * Jiri Matela - * Dalibor Matura <255899@mail.muni.cz> - * Ian Wesley-Smith - * - * Copyright (c) 2005-2010 CESNET z.s.p.o. + * Copyright (c) 2012-2013 CESNET, z.s.p.o. + * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, is permitted provided that the following conditions * are met: - * + * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * - * This product includes software developed by CESNET z.s.p.o. - * - * 4. Neither the name of the CESNET nor the names of its contributors may be + * + * 3. Neither the name of CESNET nor the names of its contributors may be * used to endorse or promote products derived from this software without * specific prior written permission. * @@ -42,12 +33,12 @@ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * */ + #define VIDCAP_SCREEN_ID 0x5645ba22 -struct vidcap_type *vidcap_screen_probe(void); -void *vidcap_screen_init(const struct vidcap_params *params); -void vidcap_screen_done(void *state); -struct video_frame *vidcap_screen_grab(void *state, struct audio_frame **audio); +struct vidcap_type *vidcap_screen_osx_probe(void); +void *vidcap_screen_osx_init(const struct vidcap_params *params); +void vidcap_screen_osx_done(void *state); +struct video_frame *vidcap_screen_osx_grab(void *state, struct audio_frame **audio); diff --git a/src/video_capture/screen.c b/src/video_capture/screen_x11.c similarity index 77% rename from src/video_capture/screen.c rename to src/video_capture/screen_x11.c index 8154c286a..86dad24a2 100644 --- a/src/video_capture/screen.c +++ b/src/video_capture/screen_x11.c @@ -1,32 +1,23 @@ +/** + * @file screen_x11.c + * @author Martin Pulec + */ /* - * FILE: screen.c - * AUTHORS: Martin Benes - * Lukas Hejtmanek - * Petr Holub - * Milos Liska - * Jiri Matela - * Dalibor Matura <255899@mail.muni.cz> - * Ian Wesley-Smith - * - * Copyright (c) 2005-2010 CESNET z.s.p.o. + * Copyright (c) 2012-2013 CESNET, z.s.p.o. + * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, is permitted provided that the following conditions * are met: - * + * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * - * This product includes software developed by CESNET z.s.p.o. - * - * 4. Neither the name of the CESNET nor the names of its contributors may be + * + * 3. Neither the name of CESNET nor the names of its contributors may be * used to endorse or promote products derived from this software without * specific prior written permission. * @@ -42,11 +33,8 @@ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * */ - -#include "host.h" #ifdef HAVE_CONFIG_H #include "config.h" #include "config_unix.h" @@ -60,37 +48,25 @@ #include "tv.h" -#include "video_capture/screen.h" +#include "video_capture/screen_x11.h" #include "audio/audio.h" #include #include #include -#include - -#ifdef HAVE_MACOSX -#include -#include -#include -#else #include #ifdef HAVE_XFIXES #include #endif // HAVE_XFIXES #include #include "x11_common.h" -#endif #define QUEUE_SIZE_MAX 3 /* prototypes of functions defined in this module */ static void show_help(void); -#ifdef HAVE_LINUX static void *grab_thread(void *args); -#endif // HAVE_LINUX - -static volatile bool should_exit = false; static void show_help() { @@ -100,25 +76,18 @@ static void show_help() printf("\t\t - preferred grabbing fps (otherwise unlimited)\n"); } -static struct vidcap_screen_state *state; - -#ifdef HAVE_LINUX struct grabbed_data; struct grabbed_data { XImage *data; struct grabbed_data *next; }; -#endif -struct vidcap_screen_state { +struct vidcap_screen_x11_state { struct video_frame *frame; struct tile *tile; int frames; struct timeval t, t0; -#ifdef HAVE_MACOSX - CGDirectDisplayID display; -#else Display *dpy; Window root; @@ -134,24 +103,18 @@ struct vidcap_screen_state { volatile bool should_exit_worker; pthread_t worker_id; -#endif struct timeval prev_time; double fps; + bool initialized; }; -pthread_once_t initialized = PTHREAD_ONCE_INIT; - -static void initialize() { - struct vidcap_screen_state *s = (struct vidcap_screen_state *) state; - +static void initialize(struct vidcap_screen_x11_state *s) { s->frame = vf_alloc(1); s->tile = vf_get_tile(s->frame, 0); - -#ifndef HAVE_MACOSX XWindowAttributes wa; x11_lock(); @@ -178,15 +141,6 @@ static void initialize() { s->should_exit_worker = false; -#else - s->display = CGMainDisplayID(); - CGImageRef image = CGDisplayCreateImage(s->display); - - s->tile->width = CGImageGetWidth(image); - s->tile->height = CGImageGetHeight(image); - CFRelease(image); -#endif - s->frame->color_spec = RGB; if(s->fps > 0.0) { s->frame->fps = s->fps; @@ -196,13 +150,9 @@ static void initialize() { s->frame->interlacing = PROGRESSIVE; s->tile->data_len = vc_get_linesize(s->tile->width, s->frame->color_spec) * s->tile->height; -#ifndef HAVE_MACOSX s->tile->data = (char *) malloc(s->tile->data_len); pthread_create(&s->worker_id, NULL, grab_thread, s); -#else - s->tile->data = (char *) malloc(s->tile->data_len); -#endif return; @@ -213,10 +163,9 @@ error: } -#ifdef HAVE_LINUX static void *grab_thread(void *args) { - struct vidcap_screen_state *s = args; + struct vidcap_screen_x11_state *s = args; while(!s->should_exit_worker) { struct grabbed_data *new_item = malloc(sizeof(struct grabbed_data)); @@ -285,9 +234,8 @@ static void *grab_thread(void *args) return NULL; } -#endif // HAVE_LINUX -struct vidcap_type * vidcap_screen_probe(void) +struct vidcap_type * vidcap_screen_x11_probe(void) { struct vidcap_type* vt; @@ -300,17 +248,18 @@ struct vidcap_type * vidcap_screen_probe(void) return vt; } -void * vidcap_screen_init(const struct vidcap_params *params) +void * vidcap_screen_x11_init(const struct vidcap_params *params) { - struct vidcap_screen_state *s; + struct vidcap_screen_x11_state *s; printf("vidcap_screen_init\n"); - state = s = (struct vidcap_screen_state *) malloc(sizeof(struct vidcap_screen_state)); + s = (struct vidcap_screen_x11_state *) malloc(sizeof(struct vidcap_screen_x11_state)); if(s == NULL) { printf("Unable to allocate screen capture state\n"); return NULL; } + s->initialized = false; gettimeofday(&s->t0, NULL); @@ -319,17 +268,14 @@ void * vidcap_screen_init(const struct vidcap_params *params) s->frame = NULL; s->tile = NULL; -#ifdef HAVE_LINUX s->worker_id = 0; #ifndef HAVE_XFIXES fprintf(stderr, "[Screen capture] Compiled without XFixes library, cursor won't be shown!\n"); #endif // ! HAVE_XFIXES -#endif // HAVE_LINUX s->prev_time.tv_sec = s->prev_time.tv_usec = 0; - s->frames = 0; if(vidcap_params_get_fmt(params)) { @@ -344,13 +290,11 @@ void * vidcap_screen_init(const struct vidcap_params *params) return s; } -static void vidcap_screen_finish(void *state) +static void vidcap_screen_x11_finish(void *state) { - struct vidcap_screen_state *s = (struct vidcap_screen_state *) state; + struct vidcap_screen_x11_state *s = (struct vidcap_screen_x11_state *) state; assert(s != NULL); - should_exit = true; -#ifdef HAVE_LINUX pthread_mutex_lock(&s->lock); if(s->boss_waiting) { pthread_cond_signal(&s->boss_cv); @@ -366,18 +310,16 @@ static void vidcap_screen_finish(void *state) if(s->worker_id) { pthread_join(s->worker_id, NULL); } -#endif // HAVE_LINUX } -void vidcap_screen_done(void *state) +void vidcap_screen_x11_done(void *state) { - struct vidcap_screen_state *s = (struct vidcap_screen_state *) state; + struct vidcap_screen_x11_state *s = (struct vidcap_screen_x11_state *) state; assert(s != NULL); - vidcap_screen_finish(state); + vidcap_screen_x11_finish(state); -#ifdef HAVE_LINUX pthread_mutex_lock(&s->lock); { while(s->queue_len > 0) { @@ -392,27 +334,22 @@ void vidcap_screen_done(void *state) if(s->tile) free(s->tile->data); -#endif - if(s->tile) { -#ifdef HAVE_MACOS_X - free(s->tile->data); -#endif - } vf_free(s->frame); free(s); } -struct video_frame * vidcap_screen_grab(void *state, struct audio_frame **audio) +struct video_frame * vidcap_screen_x11_grab(void *state, struct audio_frame **audio) { - struct vidcap_screen_state *s = (struct vidcap_screen_state *) state; + struct vidcap_screen_x11_state *s = (struct vidcap_screen_x11_state *) state; - pthread_once(&initialized, initialize); + if (!s->initialized) { + initialize(s); + s->initialized = true; + } *audio = NULL; -#ifndef HAVE_MACOSX - struct grabbed_data *item = NULL; pthread_mutex_lock(&s->lock); @@ -444,25 +381,6 @@ struct video_frame * vidcap_screen_grab(void *state, struct audio_frame **audio) XDestroyImage(item->data); free(item); -#else - CGImageRef image = CGDisplayCreateImage(s->display); - CFDataRef data = CGDataProviderCopyData(CGImageGetDataProvider(image)); - const unsigned char *pixels = CFDataGetBytePtr(data); - - int linesize = s->tile->width * 4; - int y; - unsigned char *dst = (unsigned char *) s->tile->data; - const unsigned char *src = (const unsigned char *) pixels; - for(y = 0; y < (int) s->tile->height; ++y) { - vc_copylineRGBA (dst, src, linesize, 16, 8, 0); - src += linesize; - dst += linesize; - } - - CFRelease(data); - CFRelease(image); - -#endif if(s->fps > 0.0) { struct timeval cur_time; diff --git a/src/video_capture/screen_x11.h b/src/video_capture/screen_x11.h new file mode 100644 index 000000000..908b08a7f --- /dev/null +++ b/src/video_capture/screen_x11.h @@ -0,0 +1,44 @@ +/** + * @file screen_x11.h + * @author Martin Pulec + */ +/* + * Copyright (c) 2012-2013 CESNET, z.s.p.o. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, is permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of CESNET nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#define VIDCAP_SCREEN_ID 0x5645ba22 + +struct vidcap_type *vidcap_screen_x11_probe(void); +void *vidcap_screen_x11_init(const struct vidcap_params *params); +void vidcap_screen_x11_done(void *state); +struct video_frame *vidcap_screen_x11_grab(void *state, struct audio_frame **audio); +