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;