vlc | branch: master | Rémi Denis-Courmont <[email protected]> | Thu May 26 23:17:42 2011 +0300| [0738ce0d415e50ad6419d9596f975b3c64de19d6] | committer: Rémi Denis-Courmont
XCB/screen: use Composite to capture windows This enables capture of windows even when not entirely visible. > http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=0738ce0d415e50ad6419d9596f975b3c64de19d6 --- configure.ac | 2 + modules/access/Modules.am | 4 +- modules/access/screen/xcb.c | 133 ++++++++++++++++++++++++------------------ 3 files changed, 80 insertions(+), 59 deletions(-) diff --git a/configure.ac b/configure.ac index a3fcd46..97c1e24 100644 --- a/configure.ac +++ b/configure.ac @@ -3149,11 +3149,13 @@ AC_ARG_ENABLE(xvideo, ]) have_xcb="no" +have_xcb_composite="no" AS_IF([test "${enable_xcb}" != "no"], [ dnl libxcb PKG_CHECK_MODULES(XCB, [xcb]) have_xcb="yes" PKG_CHECK_MODULES(XCB_SHM, [xcb-shm]) + PKG_CHECK_MODULES(XCB_COMPOSITE, [xcb-composite]) AS_IF([test "${enable_xvideo}" != "no"], [ PKG_CHECK_MODULES(XCB_XV, [xcb-xv >= 1.1.90.1], [ diff --git a/modules/access/Modules.am b/modules/access/Modules.am index 8130a38..3183db7 100644 --- a/modules/access/Modules.am +++ b/modules/access/Modules.am @@ -115,9 +115,9 @@ libvlc_LTLIBRARIES += $(LTLIBaccess_shm) libxcb_screen_plugin_la_SOURCES = screen/xcb.c libxcb_screen_plugin_la_CFLAGS = $(AM_CFLAGS) \ - $(XCB_CFLAGS) + $(XCB_CFLAGS) $(XCB_COMPOSITE_CFLAGS) libxcb_screen_plugin_la_LIBADD = $(AM_LIBADD) \ - $(XCB_LIBS) + $(XCB_LIBS) $(XCB_COMPOSITE_LIBS) libxcb_screen_plugin_la_DEPENDENCIES = if HAVE_XCB libvlc_LTLIBRARIES += libxcb_screen_plugin.la diff --git a/modules/access/screen/xcb.c b/modules/access/screen/xcb.c index 1c95832..7c7f1a2 100644 --- a/modules/access/screen/xcb.c +++ b/modules/access/screen/xcb.c @@ -26,6 +26,7 @@ #include <stdarg.h> #include <assert.h> #include <xcb/xcb.h> +#include <xcb/composite.h> #include <vlc_common.h> #include <vlc_demux.h> #include <vlc_plugin.h> @@ -110,6 +111,7 @@ struct demux_sys_t mtime_t pts, interval; float rate; xcb_window_t window; + xcb_pixmap_t pixmap; int16_t x, y; uint16_t w, h; uint16_t cur_w, cur_h; @@ -176,11 +178,28 @@ static int Open (vlc_object_t *obj) goto error; } p_sys->window = ul; + + xcb_composite_query_version_reply_t *r = + xcb_composite_query_version_reply (conn, + xcb_composite_query_version (conn, 0, 4), NULL); + if (r == NULL || r->minor_version < 2) + { + msg_Err (obj, "X Composite extension not available"); + free (r); + goto error; + } + msg_Dbg (obj, "using Composite extension v%"PRIu32".%"PRIu32, + r->major_version, r->minor_version); + free (r); + + xcb_composite_redirect_window (conn, p_sys->window, + XCB_COMPOSITE_REDIRECT_AUTOMATIC); } else goto error; /* Window properties */ + p_sys->pixmap = xcb_generate_id (conn); p_sys->x = var_InheritInteger (obj, "screen-left"); p_sys->y = var_InheritInteger (obj, "screen-top"); p_sys->w = var_InheritInteger (obj, "screen-width"); @@ -291,55 +310,38 @@ static int Control (demux_t *demux, int query, va_list args) static void Demux (void *data) { demux_t *demux = data; - demux_sys_t *p_sys = demux->p_sys; - xcb_connection_t *conn = p_sys->conn; + demux_sys_t *sys = demux->p_sys; + xcb_connection_t *conn = sys->conn; + + /* Determine capture region */ + xcb_get_geometry_cookie_t gc; + xcb_query_pointer_cookie_t qc; - /* Update capture region (if needed) */ + gc = xcb_get_geometry (conn, sys->window); + if (sys->follow_mouse) + qc = xcb_query_pointer (conn, sys->window); - xcb_get_geometry_reply_t *geo = - xcb_get_geometry_reply (conn, - xcb_get_geometry (conn, p_sys->window), NULL); + xcb_get_geometry_reply_t *geo = xcb_get_geometry_reply (conn, gc, NULL); if (geo == NULL) { - msg_Err (demux, "bad X11 drawable 0x%08"PRIx32, p_sys->window); + msg_Err (demux, "bad X11 drawable 0x%08"PRIx32, sys->window); + if (sys->follow_mouse) + xcb_discard_reply (conn, gc.sequence); return; } - xcb_window_t root = geo->root; - int16_t x = p_sys->x, y = p_sys->y; - xcb_translate_coordinates_cookie_t tc; - xcb_query_pointer_cookie_t qc; - - if (p_sys->window != root) - tc = xcb_translate_coordinates (conn, p_sys->window, root, - x, y); - if (p_sys->follow_mouse) - qc = xcb_query_pointer (conn, p_sys->window); + /* FIXME: review for signed overflow */ + int16_t x = sys->x, y = sys->y; + uint16_t w = sys->w, h = sys->h; - uint16_t ow = geo->width - x; - uint16_t oh = geo->height - y; - uint16_t w = p_sys->w; - uint16_t h = p_sys->h; + uint16_t ow = geo->width - sys->x; + uint16_t oh = geo->height - sys->y; if (w == 0 || w > ow) w = ow; if (h == 0 || h > oh) h = oh; - uint8_t depth = geo->depth; - free (geo); - if (p_sys->window != root) - { - xcb_translate_coordinates_reply_t *coords = - xcb_translate_coordinates_reply (conn, tc, NULL); - if (coords != NULL) - { - x = coords->dst_x; - y = coords->dst_y; - free (coords); - } - } - - if (p_sys->follow_mouse) + if (sys->follow_mouse) { xcb_query_pointer_reply_t *ptr = xcb_query_pointer_reply (conn, qc, NULL); @@ -365,42 +367,59 @@ static void Demux (void *data) } } + /* Update elementary stream format (if needed) */ + if (w != sys->cur_w || h != sys->cur_h) + { + if (sys->es != NULL) + es_out_Del (demux->out, sys->es); + + /* Update composite pixmap */ + if (sys->window != geo->root) + { + xcb_free_pixmap (conn, sys->pixmap); /* no-op first time */ + xcb_composite_name_window_pixmap (conn, sys->window, sys->pixmap); + xcb_create_pixmap (conn, geo->depth, sys->pixmap, + geo->root, geo->width, geo->height); + } + + sys->es = InitES (demux, w, h, geo->depth); + if (sys->es != NULL) + { + sys->cur_w = w; + sys->cur_h = h; + } + } + /* Capture screen */ + xcb_drawable_t drawable = + (sys->window != geo->root) ? sys->pixmap : sys->window; + free (geo); + xcb_get_image_reply_t *img; img = xcb_get_image_reply (conn, - xcb_get_image (conn, XCB_IMAGE_FORMAT_Z_PIXMAP, root, + xcb_get_image (conn, XCB_IMAGE_FORMAT_Z_PIXMAP, drawable, x, y, w, h, ~0), NULL); if (img == NULL) + { + msg_Err (demux, "NO IMAGE"); return; + } block_t *block = block_heap_Alloc (img, xcb_get_image_data (img), xcb_get_image_data_length (img)); if (block == NULL) return; - /* Update elementary stream format (if needed) */ - if (w != p_sys->cur_w || h != p_sys->cur_h) - { - if (p_sys->es != NULL) - es_out_Del (demux->out, p_sys->es); - p_sys->es = InitES (demux, w, h, depth); - if (p_sys->es != NULL) - { - p_sys->cur_w = w; - p_sys->cur_h = h; - } - } - /* Send block - zero copy */ - if (p_sys->es != NULL) + if (sys->es != NULL) { - if (p_sys->pts == VLC_TS_INVALID) - p_sys->pts = mdate (); - block->i_pts = block->i_dts = p_sys->pts; + if (sys->pts == VLC_TS_INVALID) + sys->pts = mdate (); + block->i_pts = block->i_dts = sys->pts; - es_out_Control (demux->out, ES_OUT_SET_PCR, p_sys->pts); - es_out_Send (demux->out, p_sys->es, block); - p_sys->pts += p_sys->interval; + es_out_Control (demux->out, ES_OUT_SET_PCR, sys->pts); + es_out_Send (demux->out, sys->es, block); + sys->pts += sys->interval; } } _______________________________________________ vlc-commits mailing list [email protected] http://mailman.videolan.org/listinfo/vlc-commits
