[vlc-commits] XCB/screen: use Composite to capture windows
Rémi Denis-Courmont
git at videolan.org
Thu May 26 22:19:02 CEST 2011
vlc | branch: master | Rémi Denis-Courmont <remi at remlab.net> | 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;
}
}
More information about the vlc-commits
mailing list