From 82927d6bddf4212fb0a2dc99dbb7cd89be941592 Mon Sep 17 00:00:00 2001 From: Vincent Penquerc'h Date: Tue, 20 Sep 2011 12:11:47 +0100 Subject: [PATCH] ximagesrc: add xid and xname properties to allow capturing a particular window A particular window may be selected using the new xid (X-Window XID, eg a pointer) and xname (window title) properties. If both are specified, the XID is used in preference, falling back to xname if not found. Default (if none of xid and xname are specified, or if no such window is found) is to capture the root window. https://bugzilla.gnome.org/show_bug.cgi?id=546932 --- sys/ximage/gstximagesrc.c | 136 ++++++++++++++++++++++++++++++++++++-- sys/ximage/gstximagesrc.h | 4 ++ 2 files changed, 135 insertions(+), 5 deletions(-) diff --git a/sys/ximage/gstximagesrc.c b/sys/ximage/gstximagesrc.c index 94d4bcd1f4..b09c1abd59 100644 --- a/sys/ximage/gstximagesrc.c +++ b/sys/ximage/gstximagesrc.c @@ -71,6 +71,8 @@ enum PROP_ENDX, PROP_ENDY, PROP_REMOTE, + PROP_XID, + PROP_XNAME, }; GST_BOILERPLATE (GstXImageSrc, gst_ximage_src, GstPushSrc, GST_TYPE_PUSH_SRC); @@ -105,6 +107,35 @@ gst_ximage_src_return_buf (GstXImageSrc * ximagesrc, } } +static Window +gst_ximage_src_find_window (GstXImageSrc * src, Window root, const char *name) +{ + Window *children; + Window window = 0, root_return, parent_return; + unsigned int nchildren; + char *tmpname; + int n, status; + + status = XFetchName (src->xcontext->disp, root, &tmpname); + if (status && !strcmp (name, tmpname)) + return root; + + status = + XQueryTree (src->xcontext->disp, root, &root_return, &parent_return, + &children, &nchildren); + if (!status || !children) + return (Window) 0; + + for (n = 0; n < nchildren; ++n) { + window = gst_ximage_src_find_window (src, children[n], name); + if (window != 0) + break; + } + + XFree (children); + return window; +} + static gboolean gst_ximage_src_open_display (GstXImageSrc * s, const gchar * name) { @@ -125,8 +156,49 @@ gst_ximage_src_open_display (GstXImageSrc * s, const gchar * name) s->width = s->xcontext->width; s->height = s->xcontext->height; - /* Always capture root window, for now */ s->xwindow = s->xcontext->root; + if (s->xid != 0 || s->xname) { + int status; + XWindowAttributes attrs; + Window window; + + if (s->xid != 0) { + status = XGetWindowAttributes (s->xcontext->disp, s->xid, &attrs); + if (status) { + GST_DEBUG_OBJECT (s, "Found window XID %p", s->xid); + s->xwindow = s->xid; + goto window_found; + } else { + GST_WARNING_OBJECT (s, "Failed to get window %p attributes", s->xid); + } + } + + if (s->xname) { + GST_DEBUG_OBJECT (s, "Looking for window %s", s->xname); + window = gst_ximage_src_find_window (s, s->xcontext->root, s->xname); + if (window != 0) { + GST_DEBUG_OBJECT (s, "Found window named %s as %p, ", s->xname, window); + status = XGetWindowAttributes (s->xcontext->disp, window, &attrs); + if (status) { + s->xwindow = window; + goto window_found; + } else { + GST_WARNING_OBJECT (s, "Failed to get window %p attributes", window); + } + } + } + + GST_INFO_OBJECT (s, "Using root window"); + goto use_root_window; + + window_found: + g_assert (s->xwindow != 0); + s->width = attrs.width; + s->height = attrs.height; + GST_INFO_OBJECT (s, "Using default window %p, size of %dx%d", s->xwindow, + s->width, s->height); + } +use_root_window: #ifdef HAVE_XFIXES /* check if xfixes supported */ @@ -592,7 +664,8 @@ gst_ximage_src_ximage_get (GstXImageSrc * ximagesrc) } else #endif /* HAVE_XSHM */ { - GST_DEBUG_OBJECT (ximagesrc, "Retrieving screen using XGetImage"); + GST_DEBUG_OBJECT (ximagesrc, + "Retrieving screen using XGetImage, window %p", ximagesrc->xwindow); if (ximagesrc->remote) { XGetSubImage (ximagesrc->xcontext->disp, ximagesrc->xwindow, ximagesrc->startx, ximagesrc->starty, ximagesrc->width, @@ -836,6 +909,21 @@ gst_ximage_src_set_property (GObject * object, guint prop_id, case PROP_REMOTE: src->remote = g_value_get_boolean (value); break; + case PROP_XID: + if (src->xcontext != NULL) { + g_warning ("ximagesrc window ID must be set before opening display"); + break; + } + src->xid = g_value_get_uint64 (value); + break; + case PROP_XNAME: + if (src->xcontext != NULL) { + g_warning ("ximagesrc window name must be set before opening display"); + break; + } + g_free (src->xname); + src->xname = g_strdup (g_value_get_string (value)); + break; default: break; } @@ -879,6 +967,12 @@ gst_ximage_src_get_property (GObject * object, guint prop_id, GValue * value, case PROP_REMOTE: g_value_set_boolean (value, src->remote); break; + case PROP_XID: + g_value_set_uint64 (value, src->xid); + break; + case PROP_XNAME: + g_value_set_string (value, src->xname); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -931,6 +1025,7 @@ gst_ximage_src_finalize (GObject * object) if (src->xcontext) ximageutil_xcontext_clear (src->xcontext); + g_free (src->xname); g_mutex_free (src->pool_lock); g_mutex_free (src->x_lock); @@ -955,9 +1050,16 @@ gst_ximage_src_get_caps (GstBaseSrc * bs) (s)->srcpad)); xcontext = s->xcontext; - - width = xcontext->width; - height = xcontext->height; + width = s->xcontext->width; + height = s->xcontext->height; + if (s->xwindow != 0) { + XWindowAttributes attrs; + int status = XGetWindowAttributes (s->xcontext->disp, s->xwindow, &attrs); + if (status) { + width = attrs.width; + height = attrs.height; + } + } /* property comments say 0 means right/bottom, means we can't capture the top left pixel alone */ @@ -1138,6 +1240,30 @@ gst_ximage_src_class_init (GstXImageSrcClass * klass) "Whether the display is remote", FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + /** + * GstXImageSrc:xid + * + * The XID of the window to capture. 0 for the root window (default). + * + * Since: 0.10.31 + **/ + g_object_class_install_property (gc, PROP_XID, + g_param_spec_uint64 ("xid", "Window XID", + "Window XID to capture from", 0, G_MAXUINT64, 0, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + /** + * GstXImageSrc:xname + * + * The name of the window to capture, if any. + * + * Since: 0.10.31 + **/ + g_object_class_install_property (gc, PROP_XNAME, + g_param_spec_string ("xname", "Window name", + "Window name to capture from", NULL, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + parent_class = g_type_class_peek_parent (klass); push_class->create = gst_ximage_src_create; diff --git a/sys/ximage/gstximagesrc.h b/sys/ximage/gstximagesrc.h index f436df68fb..e58513c1ec 100644 --- a/sys/ximage/gstximagesrc.h +++ b/sys/ximage/gstximagesrc.h @@ -56,6 +56,10 @@ struct _GstXImageSrc gchar *display_name; guint screen_num; + /* Window selection */ + guint64 xid; + gchar *xname; + /* Desired output framerate */ gint fps_n; gint fps_d;