blob: 60b33e465399c5e1d1fd30bb8bad5f5112159c99 [file] [log] [blame]
Jan Schmidt27301372006-02-20 21:19:59 +00001/* GStreamer
2 *
Thomas Vander Stichele7e18cca2006-04-28 16:15:20 +00003 * Copyright (C) 2006 Zaheer Merali <zaheerabbas at merali dot org>
4 *
Jan Schmidt27301372006-02-20 21:19:59 +00005 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
19 */
20
Zaheer Abbas Merali46ef8312006-03-31 16:32:47 +000021/**
22 * SECTION:element-ximagesrc
Zaheer Abbas Merali46ef8312006-03-31 16:32:47 +000023 *
Zaheer Abbas Merali46ef8312006-03-31 16:32:47 +000024 * This element captures your X Display and creates raw RGB video. It uses
25 * the XDamage extension if available to only capture areas of the screen that
26 * have changed since the last frame. It uses the XFixes extension if
Thomas Vander Stichele7e18cca2006-04-28 16:15:20 +000027 * available to also capture your mouse pointer. By default it will fixate to
28 * 25 frames per second.
Stefan Kost63353072009-01-29 10:10:08 +020029 *
30 * <refsect2>
Zaheer Abbas Merali46ef8312006-03-31 16:32:47 +000031 * <title>Example pipelines</title>
Stefan Kost63353072009-01-29 10:10:08 +020032 * |[
Wim Taymans1dada152012-03-05 12:03:01 +010033 * gst-launch ximagesrc ! video/x-raw,framerate=5/1 ! ffmpegcolorspace ! theoraenc ! oggmux ! filesink location=desktop.ogg
Stefan Kost63353072009-01-29 10:10:08 +020034 * ]| Encodes your X display to an Ogg theora video at 5 frames per second.
Zaheer Abbas Merali46ef8312006-03-31 16:32:47 +000035 * </refsect2>
Zaheer Abbas Merali46ef8312006-03-31 16:32:47 +000036 */
37
Jan Schmidt27301372006-02-20 21:19:59 +000038#ifdef HAVE_CONFIG_H
39#include "config.h"
40#endif
Thomas Vander Stichele2caa4612006-04-28 18:57:09 +000041#include "gstximagesrc.h"
Jan Schmidt27301372006-02-20 21:19:59 +000042
43#include <string.h>
44#include <stdlib.h>
45
46#include <X11/Xlib.h>
47#include <X11/Xutil.h>
48
Zaheer Abbas Merali329c7472006-04-07 15:27:40 +000049#include <gst/gst.h>
50#include <gst/gst-i18n-plugin.h>
Wim Taymans1dada152012-03-05 12:03:01 +010051#include <gst/video/video.h>
Zaheer Abbas Merali329c7472006-04-07 15:27:40 +000052
Tim-Philipp Müller66f6e122011-12-12 02:30:45 +000053#include "gst/glib-compat-private.h"
54
Thomas Vander Stichele977f5cf2006-04-28 16:51:33 +000055GST_DEBUG_CATEGORY_STATIC (gst_debug_ximage_src);
56#define GST_CAT_DEFAULT gst_debug_ximage_src
Jan Schmidt27301372006-02-20 21:19:59 +000057
Jan Schmidt27301372006-02-20 21:19:59 +000058static GstStaticPadTemplate t =
59GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
Wim Taymans1dada152012-03-05 12:03:01 +010060 GST_STATIC_CAPS ("video/x-raw, "
Jan Schmidt27301372006-02-20 21:19:59 +000061 "framerate = (fraction) [ 0, MAX ], "
Zaheer Abbas Meralif84de0e2006-03-31 17:52:36 +000062 "width = (int) [ 1, MAX ], " "height = (int) [ 1, MAX ], "
63 "pixel-aspect-ratio = (fraction) [ 0, MAX ]"));
Jan Schmidt27301372006-02-20 21:19:59 +000064
65enum
66{
67 PROP_0,
68 PROP_DISPLAY_NAME,
Zaheer Abbas Merali4a4c3062006-03-17 16:34:36 +000069 PROP_SCREEN_NUM,
Zaheer Abbas Meralie6c882b2006-07-08 19:03:54 +000070 PROP_SHOW_POINTER,
Zaheer Abbas Meralie0855a02006-07-08 22:41:25 +000071 PROP_USE_DAMAGE,
72 PROP_STARTX,
73 PROP_STARTY,
74 PROP_ENDX,
Vincent Penquerc'h7ac31b32010-11-29 12:36:06 +000075 PROP_ENDY,
76 PROP_REMOTE,
Vincent Penquerc'h82927d62011-09-20 12:11:47 +010077 PROP_XID,
78 PROP_XNAME,
Jan Schmidt27301372006-02-20 21:19:59 +000079};
80
Wim Taymans9e276e42011-07-10 14:56:00 +020081#define gst_ximage_src_parent_class parent_class
82G_DEFINE_TYPE (GstXImageSrc, gst_ximage_src, GST_TYPE_PUSH_SRC);
Jan Schmidt27301372006-02-20 21:19:59 +000083
Wim Taymansa32d9442012-03-11 19:06:37 +010084static GstCaps *gst_ximage_src_fixate (GstBaseSrc * bsrc, GstCaps * caps);
Thomas Vander Stichele977f5cf2006-04-28 16:51:33 +000085static void gst_ximage_src_clear_bufpool (GstXImageSrc * ximagesrc);
Jan Schmidt27301372006-02-20 21:19:59 +000086
87/* Called when a buffer is returned from the pipeline */
88static void
Wim Taymansd90a3882011-02-24 13:51:32 +010089gst_ximage_src_return_buf (GstXImageSrc * ximagesrc, GstBuffer * ximage)
Jan Schmidt27301372006-02-20 21:19:59 +000090{
Wim Taymans9c08bde2011-02-27 19:43:13 +010091 GstMetaXImage *meta = GST_META_XIMAGE_GET (ximage);
Wim Taymansd90a3882011-02-24 13:51:32 +010092
Jan Schmidt27301372006-02-20 21:19:59 +000093 /* If our geometry changed we can't reuse that image. */
Wim Taymansf229f4d2011-02-25 16:29:38 +010094 if ((meta->width != ximagesrc->width) || (meta->height != ximagesrc->height)) {
Jan Schmidt27301372006-02-20 21:19:59 +000095 GST_DEBUG_OBJECT (ximagesrc,
96 "destroy image %p as its size changed %dx%d vs current %dx%d",
Wim Taymansf229f4d2011-02-25 16:29:38 +010097 ximage, meta->width, meta->height, ximagesrc->width, ximagesrc->height);
Wim Taymans15848062012-01-19 11:33:53 +010098 g_mutex_lock (&ximagesrc->x_lock);
Jan Schmidt27301372006-02-20 21:19:59 +000099 gst_ximageutil_ximage_destroy (ximagesrc->xcontext, ximage);
Wim Taymans15848062012-01-19 11:33:53 +0100100 g_mutex_unlock (&ximagesrc->x_lock);
Jan Schmidt27301372006-02-20 21:19:59 +0000101 } else {
102 /* In that case we can reuse the image and add it to our image pool. */
103 GST_LOG_OBJECT (ximagesrc, "recycling image %p in pool", ximage);
104 /* need to increment the refcount again to recycle */
Wim Taymansd90a3882011-02-24 13:51:32 +0100105 gst_buffer_ref (ximage);
Wim Taymans15848062012-01-19 11:33:53 +0100106 g_mutex_lock (&ximagesrc->pool_lock);
Vincent Penquerc'h26993422011-08-09 09:05:31 +0100107 GST_BUFFER_FLAGS (GST_BUFFER (ximage)) = 0; /* clear out any flags from the previous use */
Jan Schmidt27301372006-02-20 21:19:59 +0000108 ximagesrc->buffer_pool = g_slist_prepend (ximagesrc->buffer_pool, ximage);
Wim Taymans15848062012-01-19 11:33:53 +0100109 g_mutex_unlock (&ximagesrc->pool_lock);
Jan Schmidt27301372006-02-20 21:19:59 +0000110 }
111}
112
Vincent Penquerc'h82927d62011-09-20 12:11:47 +0100113static Window
114gst_ximage_src_find_window (GstXImageSrc * src, Window root, const char *name)
115{
116 Window *children;
117 Window window = 0, root_return, parent_return;
118 unsigned int nchildren;
119 char *tmpname;
120 int n, status;
121
122 status = XFetchName (src->xcontext->disp, root, &tmpname);
123 if (status && !strcmp (name, tmpname))
124 return root;
125
126 status =
127 XQueryTree (src->xcontext->disp, root, &root_return, &parent_return,
128 &children, &nchildren);
129 if (!status || !children)
130 return (Window) 0;
131
132 for (n = 0; n < nchildren; ++n) {
133 window = gst_ximage_src_find_window (src, children[n], name);
134 if (window != 0)
135 break;
136 }
137
138 XFree (children);
139 return window;
140}
141
Jan Schmidt27301372006-02-20 21:19:59 +0000142static gboolean
Thomas Vander Stichele977f5cf2006-04-28 16:51:33 +0000143gst_ximage_src_open_display (GstXImageSrc * s, const gchar * name)
Jan Schmidt27301372006-02-20 21:19:59 +0000144{
Thomas Vander Stichele977f5cf2006-04-28 16:51:33 +0000145 g_return_val_if_fail (GST_IS_XIMAGE_SRC (s), FALSE);
Jan Schmidt27301372006-02-20 21:19:59 +0000146
147 if (s->xcontext != NULL)
148 return TRUE;
149
Wim Taymans15848062012-01-19 11:33:53 +0100150 g_mutex_lock (&s->x_lock);
Jan Schmidt27301372006-02-20 21:19:59 +0000151 s->xcontext = ximageutil_xcontext_get (GST_ELEMENT (s), name);
Zaheer Abbas Merali3c316332007-03-01 10:44:36 +0000152 if (s->xcontext == NULL) {
Wim Taymans15848062012-01-19 11:33:53 +0100153 g_mutex_unlock (&s->x_lock);
Zaheer Abbas Merali3c316332007-03-01 10:44:36 +0000154 GST_ELEMENT_ERROR (s, RESOURCE, OPEN_READ,
155 ("Could not open X display for reading"),
156 ("NULL returned from getting xcontext"));
157 return FALSE;
158 }
Jan Schmidt27301372006-02-20 21:19:59 +0000159 s->width = s->xcontext->width;
160 s->height = s->xcontext->height;
161
Jan Schmidt27301372006-02-20 21:19:59 +0000162 s->xwindow = s->xcontext->root;
Vincent Penquerc'h82927d62011-09-20 12:11:47 +0100163 if (s->xid != 0 || s->xname) {
164 int status;
165 XWindowAttributes attrs;
166 Window window;
167
168 if (s->xid != 0) {
169 status = XGetWindowAttributes (s->xcontext->disp, s->xid, &attrs);
170 if (status) {
Stas Sergeev73fac4e2011-09-29 18:41:53 +0400171 GST_DEBUG_OBJECT (s, "Found window XID %" G_GUINT64_FORMAT, s->xid);
Vincent Penquerc'h82927d62011-09-20 12:11:47 +0100172 s->xwindow = s->xid;
173 goto window_found;
174 } else {
Stas Sergeev73fac4e2011-09-29 18:41:53 +0400175 GST_WARNING_OBJECT (s, "Failed to get window %" G_GUINT64_FORMAT
176 " attributes", s->xid);
Vincent Penquerc'h82927d62011-09-20 12:11:47 +0100177 }
178 }
179
180 if (s->xname) {
181 GST_DEBUG_OBJECT (s, "Looking for window %s", s->xname);
182 window = gst_ximage_src_find_window (s, s->xcontext->root, s->xname);
183 if (window != 0) {
Stas Sergeev73fac4e2011-09-29 18:41:53 +0400184 GST_DEBUG_OBJECT (s, "Found window named %s, ", s->xname);
Vincent Penquerc'h82927d62011-09-20 12:11:47 +0100185 status = XGetWindowAttributes (s->xcontext->disp, window, &attrs);
186 if (status) {
187 s->xwindow = window;
188 goto window_found;
189 } else {
Stas Sergeev73fac4e2011-09-29 18:41:53 +0400190 GST_WARNING_OBJECT (s, "Failed to get window attributes for "
191 "window named %s", s->xname);
Vincent Penquerc'h82927d62011-09-20 12:11:47 +0100192 }
193 }
194 }
195
196 GST_INFO_OBJECT (s, "Using root window");
197 goto use_root_window;
198
199 window_found:
200 g_assert (s->xwindow != 0);
201 s->width = attrs.width;
202 s->height = attrs.height;
Stas Sergeev73fac4e2011-09-29 18:41:53 +0400203 GST_INFO_OBJECT (s, "Using default window size of %dx%d",
Vincent Penquerc'h82927d62011-09-20 12:11:47 +0100204 s->width, s->height);
205 }
206use_root_window:
Jan Schmidt27301372006-02-20 21:19:59 +0000207
208#ifdef HAVE_XFIXES
209 /* check if xfixes supported */
210 {
211 int error_base;
212
213 if (XFixesQueryExtension (s->xcontext->disp, &s->fixes_event_base,
214 &error_base)) {
215 s->have_xfixes = TRUE;
216 GST_DEBUG_OBJECT (s, "X Server supports XFixes");
217 } else {
Zaheer Abbas Merali4a4c3062006-03-17 16:34:36 +0000218
Jan Schmidt27301372006-02-20 21:19:59 +0000219 GST_DEBUG_OBJECT (s, "X Server does not support XFixes");
220 }
221 }
222
223#ifdef HAVE_XDAMAGE
224 /* check if xdamage is supported */
225 {
226 int error_base;
227 long evmask = NoEventMask;
228
Jan Schmidt361c3c92008-02-12 13:34:52 +0000229 s->have_xdamage = FALSE;
230 s->damage = None;
231 s->damage_copy_gc = None;
232 s->damage_region = None;
233
Jan Schmidt27301372006-02-20 21:19:59 +0000234 if (XDamageQueryExtension (s->xcontext->disp, &s->damage_event_base,
235 &error_base)) {
236 s->damage =
Eric Anholt28713ec2007-05-11 16:11:04 +0000237 XDamageCreate (s->xcontext->disp, s->xwindow, XDamageReportNonEmpty);
Jan Schmidt27301372006-02-20 21:19:59 +0000238 if (s->damage != None) {
239 s->damage_region = XFixesCreateRegion (s->xcontext->disp, NULL, 0);
240 if (s->damage_region != None) {
241 XGCValues values;
242
243 GST_DEBUG_OBJECT (s, "Using XDamage extension");
244 values.subwindow_mode = IncludeInferiors;
245 s->damage_copy_gc = XCreateGC (s->xcontext->disp,
246 s->xwindow, GCSubwindowMode, &values);
247 XSelectInput (s->xcontext->disp, s->xwindow, evmask);
248
249 s->have_xdamage = TRUE;
250 } else {
251 XDamageDestroy (s->xcontext->disp, s->damage);
252 s->damage = None;
253 }
254 } else
255 GST_DEBUG_OBJECT (s, "Could not attach to XDamage");
256 } else {
257 GST_DEBUG_OBJECT (s, "X Server does not have XDamage extension");
258 }
259 }
260#endif
261#endif
262
Wim Taymans15848062012-01-19 11:33:53 +0100263 g_mutex_unlock (&s->x_lock);
Jan Schmidt27301372006-02-20 21:19:59 +0000264
265 if (s->xcontext == NULL)
266 return FALSE;
267
268 return TRUE;
269}
270
271static gboolean
Thomas Vander Stichele977f5cf2006-04-28 16:51:33 +0000272gst_ximage_src_start (GstBaseSrc * basesrc)
Jan Schmidt27301372006-02-20 21:19:59 +0000273{
Thomas Vander Stichele977f5cf2006-04-28 16:51:33 +0000274 GstXImageSrc *s = GST_XIMAGE_SRC (basesrc);
Jan Schmidt27301372006-02-20 21:19:59 +0000275
276 s->last_frame_no = -1;
Zaheer Abbas Merali20bc2902007-05-11 10:31:27 +0000277#ifdef HAVE_XDAMAGE
Wim Taymans419ede22008-10-03 15:54:07 +0000278 if (s->last_ximage)
279 gst_buffer_unref (GST_BUFFER_CAST (s->last_ximage));
Zaheer Abbas Merali20bc2902007-05-11 10:31:27 +0000280 s->last_ximage = NULL;
281#endif
daniel fischere359a412007-06-11 11:41:56 +0000282 return gst_ximage_src_open_display (s, s->display_name);
Jan Schmidt27301372006-02-20 21:19:59 +0000283}
284
285static gboolean
Thomas Vander Stichele977f5cf2006-04-28 16:51:33 +0000286gst_ximage_src_stop (GstBaseSrc * basesrc)
Jan Schmidt27301372006-02-20 21:19:59 +0000287{
Thomas Vander Stichele977f5cf2006-04-28 16:51:33 +0000288 GstXImageSrc *src = GST_XIMAGE_SRC (basesrc);
Jan Schmidt27301372006-02-20 21:19:59 +0000289
Edward Herveyd0777d82008-10-08 09:29:00 +0000290#ifdef HAVE_XDAMAGE
Wim Taymans419ede22008-10-03 15:54:07 +0000291 if (src->last_ximage)
292 gst_buffer_unref (GST_BUFFER_CAST (src->last_ximage));
293 src->last_ximage = NULL;
Edward Herveyd0777d82008-10-08 09:29:00 +0000294#endif
Wim Taymans419ede22008-10-03 15:54:07 +0000295
Thomas Vander Stichele977f5cf2006-04-28 16:51:33 +0000296 gst_ximage_src_clear_bufpool (src);
Jan Schmidt27301372006-02-20 21:19:59 +0000297
Edward Herveyd0777d82008-10-08 09:29:00 +0000298#ifdef HAVE_XFIXES
Wim Taymans419ede22008-10-03 15:54:07 +0000299 if (src->cursor_image)
300 XFree (src->cursor_image);
301 src->cursor_image = NULL;
Edward Herveyd0777d82008-10-08 09:29:00 +0000302#endif
Wim Taymans419ede22008-10-03 15:54:07 +0000303
Jan Schmidt27301372006-02-20 21:19:59 +0000304 if (src->xcontext) {
Wim Taymans15848062012-01-19 11:33:53 +0100305 g_mutex_lock (&src->x_lock);
Jan Schmidtababb872008-02-12 11:09:08 +0000306
307#ifdef HAVE_XDAMAGE
308 if (src->damage_copy_gc != None) {
309 XFreeGC (src->xcontext->disp, src->damage_copy_gc);
310 src->damage_copy_gc = None;
311 }
312 if (src->damage_region != None) {
313 XFixesDestroyRegion (src->xcontext->disp, src->damage_region);
314 src->damage_region = None;
315 }
316 if (src->damage != None) {
317 XDamageDestroy (src->xcontext->disp, src->damage);
318 src->damage = None;
319 }
320#endif
321
Jan Schmidt27301372006-02-20 21:19:59 +0000322 ximageutil_xcontext_clear (src->xcontext);
323 src->xcontext = NULL;
Wim Taymans15848062012-01-19 11:33:53 +0100324 g_mutex_unlock (&src->x_lock);
Jan Schmidt27301372006-02-20 21:19:59 +0000325 }
326
327 return TRUE;
328}
329
330static gboolean
Thomas Vander Stichele977f5cf2006-04-28 16:51:33 +0000331gst_ximage_src_unlock (GstBaseSrc * basesrc)
Jan Schmidt27301372006-02-20 21:19:59 +0000332{
Thomas Vander Stichele977f5cf2006-04-28 16:51:33 +0000333 GstXImageSrc *src = GST_XIMAGE_SRC (basesrc);
Jan Schmidt27301372006-02-20 21:19:59 +0000334
335 /* Awaken the create() func if it's waiting on the clock */
336 GST_OBJECT_LOCK (src);
337 if (src->clock_id) {
338 GST_DEBUG_OBJECT (src, "Waking up waiting clock");
339 gst_clock_id_unschedule (src->clock_id);
340 }
341 GST_OBJECT_UNLOCK (src);
342
343 return TRUE;
344}
345
346static gboolean
Thomas Vander Stichele977f5cf2006-04-28 16:51:33 +0000347gst_ximage_src_recalc (GstXImageSrc * src)
Jan Schmidt27301372006-02-20 21:19:59 +0000348{
349 if (!src->xcontext)
350 return FALSE;
351
Zaheer Abbas Merali5900db92006-04-07 15:53:43 +0000352 /* Maybe later we can check the display hasn't changed size */
Jan Schmidt27301372006-02-20 21:19:59 +0000353 /* We could use XQueryPointer to get only the current window. */
354 return TRUE;
355}
356
Jan Schmidt27301372006-02-20 21:19:59 +0000357#ifdef HAVE_XFIXES
358static void
359composite_pixel (GstXContext * xcontext, guchar * dest, guchar * src)
360{
361 guint8 r = src[2];
362 guint8 g = src[1];
363 guint8 b = src[0];
364 guint8 a = src[3];
Zaheer Abbas Meralic03f02f2006-03-31 15:21:35 +0000365 guint8 dr, dg, db;
Jan Schmidt27301372006-02-20 21:19:59 +0000366 guint32 color;
Zaheer Abbas Meralic03f02f2006-03-31 15:21:35 +0000367 gint r_shift, r_max, r_shift_out;
368 gint g_shift, g_max, g_shift_out;
369 gint b_shift, b_max, b_shift_out;
Jan Schmidt27301372006-02-20 21:19:59 +0000370
371 switch (xcontext->bpp) {
372 case 8:
373 color = *dest;
374 break;
375 case 16:
Tim-Philipp Müller3d1e70c2006-12-24 11:36:31 +0000376 color = GUINT16_FROM_LE (*(guint16 *) (dest));
Jan Schmidt27301372006-02-20 21:19:59 +0000377 break;
378 case 32:
379 color = GUINT32_FROM_LE (*(guint32 *) (dest));
380 break;
381 default:
Zaheer Abbas Merali329c7472006-04-07 15:27:40 +0000382 /* Should not reach here */
Tim-Philipp Müllerbcdeaa62007-12-26 16:03:57 +0000383 g_return_if_reached ();
Jan Schmidt27301372006-02-20 21:19:59 +0000384 }
385
Zaheer Abbas Merali329c7472006-04-07 15:27:40 +0000386 /* possible optimisation:
387 * move the code that finds shift and max in the _link function */
Jan Schmidt27301372006-02-20 21:19:59 +0000388 for (r_shift = 0; !(xcontext->visual->red_mask & (1 << r_shift)); r_shift++);
389 for (g_shift = 0; !(xcontext->visual->green_mask & (1 << g_shift));
390 g_shift++);
391 for (b_shift = 0; !(xcontext->visual->blue_mask & (1 << b_shift)); b_shift++);
392
Zaheer Abbas Meralic03f02f2006-03-31 15:21:35 +0000393 for (r_shift_out = 0; !(xcontext->visual->red_mask & (1 << r_shift_out));
394 r_shift_out++);
395 for (g_shift_out = 0; !(xcontext->visual->green_mask & (1 << g_shift_out));
396 g_shift_out++);
397 for (b_shift_out = 0; !(xcontext->visual->blue_mask & (1 << b_shift_out));
398 b_shift_out++);
399
400
Jan Schmidt27301372006-02-20 21:19:59 +0000401 r_max = (xcontext->visual->red_mask >> r_shift);
402 b_max = (xcontext->visual->blue_mask >> b_shift);
403 g_max = (xcontext->visual->green_mask >> g_shift);
404
405#define RGBXXX_R(x) (((x)>>r_shift) & (r_max))
406#define RGBXXX_G(x) (((x)>>g_shift) & (g_max))
407#define RGBXXX_B(x) (((x)>>b_shift) & (b_max))
408
409 dr = (RGBXXX_R (color) * 255) / r_max;
410 dg = (RGBXXX_G (color) * 255) / g_max;
411 db = (RGBXXX_B (color) * 255) / b_max;
412
413 dr = (r * a + (0xff - a) * dr) / 0xff;
414 dg = (g * a + (0xff - a) * dg) / 0xff;
415 db = (b * a + (0xff - a) * db) / 0xff;
416
Zaheer Abbas Meralic03f02f2006-03-31 15:21:35 +0000417 color = (((dr * r_max) / 255) << r_shift_out) +
418 (((dg * g_max) / 255) << g_shift_out) +
419 (((db * b_max) / 255) << b_shift_out);
Jan Schmidt27301372006-02-20 21:19:59 +0000420
421 switch (xcontext->bpp) {
422 case 8:
423 *dest = color;
424 break;
425 case 16:
426 *(guint16 *) (dest) = color;
427 break;
428 case 32:
429 *(guint32 *) (dest) = color;
430 break;
431 default:
432 g_warning ("bpp %d not supported\n", xcontext->bpp);
433 }
434}
435#endif
436
Matej Knopp1e5dd9e2011-11-21 20:31:31 +0100437#ifdef HAVE_XDAMAGE
Wim Taymans9e276e42011-07-10 14:56:00 +0200438static void
439copy_buffer (GstBuffer * dest, GstBuffer * src)
440{
Wim Taymansb4630dd2012-01-24 14:38:58 +0100441 GstMapInfo map;
Wim Taymans9e276e42011-07-10 14:56:00 +0200442
Wim Taymansb4630dd2012-01-24 14:38:58 +0100443 gst_buffer_map (src, &map, GST_MAP_READ);
444 gst_buffer_fill (dest, 0, map.data, map.size);
445 gst_buffer_unmap (src, &map);
Wim Taymans9e276e42011-07-10 14:56:00 +0200446}
Matej Knopp1e5dd9e2011-11-21 20:31:31 +0100447#endif
Wim Taymans9e276e42011-07-10 14:56:00 +0200448
Jan Schmidt27301372006-02-20 21:19:59 +0000449/* Retrieve an XImageSrcBuffer, preferably from our
450 * pool of existing images and populate it from the window */
Wim Taymansd90a3882011-02-24 13:51:32 +0100451static GstBuffer *
Thomas Vander Stichele977f5cf2006-04-28 16:51:33 +0000452gst_ximage_src_ximage_get (GstXImageSrc * ximagesrc)
Jan Schmidt27301372006-02-20 21:19:59 +0000453{
Wim Taymansd90a3882011-02-24 13:51:32 +0100454 GstBuffer *ximage = NULL;
Wim Taymansf229f4d2011-02-25 16:29:38 +0100455 GstMetaXImage *meta;
Jan Schmidt27301372006-02-20 21:19:59 +0000456
Wim Taymans15848062012-01-19 11:33:53 +0100457 g_mutex_lock (&ximagesrc->pool_lock);
Jan Schmidt27301372006-02-20 21:19:59 +0000458 while (ximagesrc->buffer_pool != NULL) {
459 ximage = ximagesrc->buffer_pool->data;
460
Wim Taymans9c08bde2011-02-27 19:43:13 +0100461 meta = GST_META_XIMAGE_GET (ximage);
Wim Taymansd90a3882011-02-24 13:51:32 +0100462
Wim Taymansf229f4d2011-02-25 16:29:38 +0100463 if ((meta->width != ximagesrc->width) ||
464 (meta->height != ximagesrc->height)) {
Jan Schmidt27301372006-02-20 21:19:59 +0000465 gst_ximage_buffer_free (ximage);
466 }
467
468 ximagesrc->buffer_pool = g_slist_delete_link (ximagesrc->buffer_pool,
469 ximagesrc->buffer_pool);
470 }
Wim Taymans15848062012-01-19 11:33:53 +0100471 g_mutex_unlock (&ximagesrc->pool_lock);
Jan Schmidt27301372006-02-20 21:19:59 +0000472
473 if (ximage == NULL) {
Jan Schmidt27301372006-02-20 21:19:59 +0000474 GST_DEBUG_OBJECT (ximagesrc, "creating image (%dx%d)",
475 ximagesrc->width, ximagesrc->height);
476
Wim Taymans15848062012-01-19 11:33:53 +0100477 g_mutex_lock (&ximagesrc->x_lock);
Jan Schmidt27301372006-02-20 21:19:59 +0000478 ximage = gst_ximageutil_ximage_new (ximagesrc->xcontext,
479 GST_ELEMENT (ximagesrc), ximagesrc->width, ximagesrc->height,
Thomas Vander Stichele977f5cf2006-04-28 16:51:33 +0000480 (BufferReturnFunc) (gst_ximage_src_return_buf));
Jan Schmidt27301372006-02-20 21:19:59 +0000481 if (ximage == NULL) {
482 GST_ELEMENT_ERROR (ximagesrc, RESOURCE, WRITE, (NULL),
Sebastian Dröge34d42e42010-06-16 19:30:25 +0200483 ("could not create a %dx%d ximage", ximagesrc->width,
484 ximagesrc->height));
Wim Taymans15848062012-01-19 11:33:53 +0100485 g_mutex_unlock (&ximagesrc->x_lock);
Jan Schmidt27301372006-02-20 21:19:59 +0000486 return NULL;
487 }
488
Wim Taymans15848062012-01-19 11:33:53 +0100489 g_mutex_unlock (&ximagesrc->x_lock);
Jan Schmidt27301372006-02-20 21:19:59 +0000490 }
491
Thomas Vander Stichele977f5cf2006-04-28 16:51:33 +0000492 g_return_val_if_fail (GST_IS_XIMAGE_SRC (ximagesrc), NULL);
Wim Taymansd90a3882011-02-24 13:51:32 +0100493
Wim Taymans9c08bde2011-02-27 19:43:13 +0100494 meta = GST_META_XIMAGE_GET (ximage);
Wim Taymansd90a3882011-02-24 13:51:32 +0100495
Jan Schmidt27301372006-02-20 21:19:59 +0000496#ifdef HAVE_XDAMAGE
Eric Anholt28713ec2007-05-11 16:11:04 +0000497 if (ximagesrc->have_xdamage && ximagesrc->use_damage &&
498 ximagesrc->last_ximage != NULL) {
Jan Schmidt27301372006-02-20 21:19:59 +0000499 XEvent ev;
500
Zaheer Abbas Merali20bc2902007-05-11 10:31:27 +0000501 /* have_frame is TRUE when either the entire screen has been
502 * grabbed or when the last image has been copied */
503 gboolean have_frame = FALSE;
504
Jan Schmidt27301372006-02-20 21:19:59 +0000505 GST_DEBUG_OBJECT (ximagesrc, "Retrieving screen using XDamage");
506
507 do {
508 XNextEvent (ximagesrc->xcontext->disp, &ev);
Eric Anholt28713ec2007-05-11 16:11:04 +0000509
Jan Schmidt27301372006-02-20 21:19:59 +0000510 if (ev.type == ximagesrc->damage_event_base + XDamageNotify) {
Eric Anholt28713ec2007-05-11 16:11:04 +0000511 XserverRegion parts;
512 XRectangle *rects;
513 int nrects;
Jan Schmidt27301372006-02-20 21:19:59 +0000514
Eric Anholt28713ec2007-05-11 16:11:04 +0000515 parts = XFixesCreateRegion (ximagesrc->xcontext->disp, 0, 0);
516 XDamageSubtract (ximagesrc->xcontext->disp, ximagesrc->damage, None,
517 parts);
518 /* Now copy out all of the damaged rectangles. */
519 rects = XFixesFetchRegion (ximagesrc->xcontext->disp, parts, &nrects);
520 if (rects != NULL) {
521 int i;
Jan Schmidt27301372006-02-20 21:19:59 +0000522
Eric Anholt28713ec2007-05-11 16:11:04 +0000523 if (!have_frame) {
Zaheer Abbas Meralie0855a02006-07-08 22:41:25 +0000524 GST_LOG_OBJECT (ximagesrc,
Tim-Philipp Müller736a4842011-11-22 01:40:39 +0000525 "Copying from last frame ximage->size: %" G_GSIZE_FORMAT,
Wim Taymans9e276e42011-07-10 14:56:00 +0200526 gst_buffer_get_size (ximage));
527 copy_buffer (ximage, ximagesrc->last_ximage);
Eric Anholt28713ec2007-05-11 16:11:04 +0000528 have_frame = TRUE;
Zaheer Abbas Meralie0855a02006-07-08 22:41:25 +0000529 }
Eric Anholt28713ec2007-05-11 16:11:04 +0000530 for (i = 0; i < nrects; i++) {
531 GST_LOG_OBJECT (ximagesrc,
532 "Damaged sub-region @ %d,%d size %dx%d reported",
533 rects[i].x, rects[i].y, rects[i].width, rects[i].height);
534
535 /* if we only want a small area, clip this damage region to
536 * area we want */
537 if (ximagesrc->endx > ximagesrc->startx &&
538 ximagesrc->endy > ximagesrc->starty) {
539 /* see if damage area intersects */
Vincent Penquerc'hfbd95812010-11-27 17:15:32 +0000540 if (rects[i].x + rects[i].width - 1 < ximagesrc->startx ||
Eric Anholt28713ec2007-05-11 16:11:04 +0000541 rects[i].x > ximagesrc->endx) {
542 /* trivial reject */
Vincent Penquerc'hfbd95812010-11-27 17:15:32 +0000543 } else if (rects[i].y + rects[i].height - 1 < ximagesrc->starty ||
Eric Anholt28713ec2007-05-11 16:11:04 +0000544 rects[i].y > ximagesrc->endy) {
545 /* trivial reject */
546 } else {
547 /* find intersect region */
548 int startx, starty, width, height;
549
550 startx = (rects[i].x < ximagesrc->startx) ? ximagesrc->startx :
551 rects[i].x;
552 starty = (rects[i].y < ximagesrc->starty) ? ximagesrc->starty :
553 rects[i].y;
Vincent Penquerc'hfbd95812010-11-27 17:15:32 +0000554 width = (rects[i].x + rects[i].width - 1 < ximagesrc->endx) ?
Eric Anholt28713ec2007-05-11 16:11:04 +0000555 rects[i].x + rects[i].width - startx :
Vincent Penquerc'hfbd95812010-11-27 17:15:32 +0000556 ximagesrc->endx - startx + 1;
557 height = (rects[i].y + rects[i].height - 1 < ximagesrc->endy) ?
Eric Anholt28713ec2007-05-11 16:11:04 +0000558 rects[i].y + rects[i].height - starty : ximagesrc->endy -
Vincent Penquerc'hfbd95812010-11-27 17:15:32 +0000559 starty + 1;
Eric Anholt28713ec2007-05-11 16:11:04 +0000560
561 GST_LOG_OBJECT (ximagesrc,
562 "Retrieving damaged sub-region @ %d,%d size %dx%d as intersect region",
563 startx, starty, width, height);
564 XGetSubImage (ximagesrc->xcontext->disp, ximagesrc->xwindow,
565 startx, starty, width, height, AllPlanes, ZPixmap,
Wim Taymansf229f4d2011-02-25 16:29:38 +0100566 meta->ximage, startx - ximagesrc->startx,
Eric Anholt28713ec2007-05-11 16:11:04 +0000567 starty - ximagesrc->starty);
568 }
569 } else {
570
571 GST_LOG_OBJECT (ximagesrc,
572 "Retrieving damaged sub-region @ %d,%d size %dx%d",
573 rects[i].x, rects[i].y, rects[i].width, rects[i].height);
574
575 XGetSubImage (ximagesrc->xcontext->disp, ximagesrc->xwindow,
576 rects[i].x, rects[i].y,
577 rects[i].width, rects[i].height,
Wim Taymansf229f4d2011-02-25 16:29:38 +0100578 AllPlanes, ZPixmap, meta->ximage, rects[i].x, rects[i].y);
Eric Anholt28713ec2007-05-11 16:11:04 +0000579 }
580 }
581 free (rects);
Jan Schmidt27301372006-02-20 21:19:59 +0000582 }
583 }
584 } while (XPending (ximagesrc->xcontext->disp));
Zaheer Abbas Merali20bc2902007-05-11 10:31:27 +0000585 if (!have_frame) {
586 GST_LOG_OBJECT (ximagesrc,
Tim-Philipp Müller736a4842011-11-22 01:40:39 +0000587 "Copying from last frame ximage->size: %" G_GSIZE_FORMAT,
Wim Taymans9e276e42011-07-10 14:56:00 +0200588 gst_buffer_get_size (ximage));
589 copy_buffer (ximage, ximagesrc->last_ximage);
Zaheer Abbas Merali20bc2902007-05-11 10:31:27 +0000590 }
Zaheer Abbas Meralic03f02f2006-03-31 15:21:35 +0000591#ifdef HAVE_XFIXES
Zaheer Abbas Meralie0855a02006-07-08 22:41:25 +0000592 /* re-get area where last mouse pointer was but only if in our clipping
593 * bounds */
Zaheer Abbas Meralic03f02f2006-03-31 15:21:35 +0000594 if (ximagesrc->cursor_image) {
595 gint x, y, width, height;
596
597 x = ximagesrc->cursor_image->x - ximagesrc->cursor_image->xhot;
598 y = ximagesrc->cursor_image->y - ximagesrc->cursor_image->yhot;
599 width = ximagesrc->cursor_image->width;
600 height = ximagesrc->cursor_image->height;
601
602 /* bounds checking */
603 if (x < 0)
604 x = 0;
605 if (y < 0)
606 y = 0;
Zaheer Abbas Meralie0855a02006-07-08 22:41:25 +0000607 if (x + width > ximagesrc->xcontext->width)
608 width = ximagesrc->xcontext->width - x;
609 if (y + height > ximagesrc->xcontext->height)
610 height = ximagesrc->xcontext->height - y;
Zaheer Abbas Meralic03f02f2006-03-31 15:21:35 +0000611 g_assert (x >= 0);
612 g_assert (y >= 0);
Zaheer Abbas Meralie0855a02006-07-08 22:41:25 +0000613 GST_DEBUG_OBJECT (ximagesrc,
614 "Cursor was at (%d,%d) width: %d, height: %d and our range is: (%d,%d) - (%d,%d)",
615 x, y, width, height, ximagesrc->startx, ximagesrc->starty,
616 ximagesrc->endx, ximagesrc->endy);
617 /* only get where cursor last was, if it is in our range */
618 if (ximagesrc->endx > ximagesrc->startx &&
619 ximagesrc->endy > ximagesrc->starty) {
620 /* check bounds */
621 if (x + width < ximagesrc->startx || x > ximagesrc->endx) {
622 /* trivial reject */
623 } else if (y + height < ximagesrc->starty || y > ximagesrc->endy) {
624 /* trivial reject */
625 } else {
626 /* find intersect region */
627 int startx, starty, iwidth, iheight;
Zaheer Abbas Meralic03f02f2006-03-31 15:21:35 +0000628
Zaheer Abbas Meralie0855a02006-07-08 22:41:25 +0000629 startx = (x < ximagesrc->startx) ? ximagesrc->startx : x;
630 starty = (y < ximagesrc->starty) ? ximagesrc->starty : y;
631 iwidth = (x + width < ximagesrc->endx) ?
632 x + width - startx : ximagesrc->endx - startx;
633 iheight = (y + height < ximagesrc->endy) ?
634 y + height - starty : ximagesrc->endy - starty;
635 GST_DEBUG_OBJECT (ximagesrc, "Removing cursor from %d,%d", x, y);
636 XGetSubImage (ximagesrc->xcontext->disp, ximagesrc->xwindow,
637 startx, starty, iwidth, iheight, AllPlanes, ZPixmap,
Wim Taymansf229f4d2011-02-25 16:29:38 +0100638 meta->ximage, startx - ximagesrc->startx,
Zaheer Abbas Meralie0855a02006-07-08 22:41:25 +0000639 starty - ximagesrc->starty);
640 }
641 } else {
642
643 GST_DEBUG_OBJECT (ximagesrc, "Removing cursor from %d,%d", x, y);
644 XGetSubImage (ximagesrc->xcontext->disp, ximagesrc->xwindow,
Wim Taymansf229f4d2011-02-25 16:29:38 +0100645 x, y, width, height, AllPlanes, ZPixmap, meta->ximage, x, y);
Zaheer Abbas Meralie0855a02006-07-08 22:41:25 +0000646 }
Zaheer Abbas Meralic03f02f2006-03-31 15:21:35 +0000647 }
648#endif
649
650
Jan Schmidt27301372006-02-20 21:19:59 +0000651 } else {
652#endif
653
654#ifdef HAVE_XSHM
655 if (ximagesrc->xcontext->use_xshm) {
656 GST_DEBUG_OBJECT (ximagesrc, "Retrieving screen using XShm");
657 XShmGetImage (ximagesrc->xcontext->disp, ximagesrc->xwindow,
Wim Taymansf229f4d2011-02-25 16:29:38 +0100658 meta->ximage, ximagesrc->startx, ximagesrc->starty, AllPlanes);
Jan Schmidt27301372006-02-20 21:19:59 +0000659
660 } else
661#endif /* HAVE_XSHM */
662 {
Stas Sergeev73fac4e2011-09-29 18:41:53 +0400663 GST_DEBUG_OBJECT (ximagesrc, "Retrieving screen using XGetImage");
Vincent Penquerc'h7ac31b32010-11-29 12:36:06 +0000664 if (ximagesrc->remote) {
665 XGetSubImage (ximagesrc->xcontext->disp, ximagesrc->xwindow,
666 ximagesrc->startx, ximagesrc->starty, ximagesrc->width,
Wim Taymansf229f4d2011-02-25 16:29:38 +0100667 ximagesrc->height, AllPlanes, ZPixmap, meta->ximage, 0, 0);
Vincent Penquerc'h7ac31b32010-11-29 12:36:06 +0000668 } else {
Wim Taymansf229f4d2011-02-25 16:29:38 +0100669 meta->ximage =
Vincent Penquerc'h7ac31b32010-11-29 12:36:06 +0000670 XGetImage (ximagesrc->xcontext->disp, ximagesrc->xwindow,
671 ximagesrc->startx, ximagesrc->starty, ximagesrc->width,
672 ximagesrc->height, AllPlanes, ZPixmap);
673 }
Jan Schmidt27301372006-02-20 21:19:59 +0000674 }
675#ifdef HAVE_XDAMAGE
676 }
677#endif
678
679#ifdef HAVE_XFIXES
680 if (ximagesrc->show_pointer && ximagesrc->have_xfixes) {
Jan Schmidt27301372006-02-20 21:19:59 +0000681
682 GST_DEBUG_OBJECT (ximagesrc, "Using XFixes to draw cursor");
683 /* get cursor */
Wim Taymans419ede22008-10-03 15:54:07 +0000684 if (ximagesrc->cursor_image)
685 XFree (ximagesrc->cursor_image);
Zaheer Abbas Meralic03f02f2006-03-31 15:21:35 +0000686 ximagesrc->cursor_image = XFixesGetCursorImage (ximagesrc->xcontext->disp);
687 if (ximagesrc->cursor_image != NULL) {
Jan Schmidt27301372006-02-20 21:19:59 +0000688 int cx, cy, i, j, count;
Zaheer Abbas Meralie0855a02006-07-08 22:41:25 +0000689 int startx, starty, iwidth, iheight;
Zaheer Abbas Meralie0855a02006-07-08 22:41:25 +0000690 gboolean cursor_in_image = TRUE;
Jan Schmidt27301372006-02-20 21:19:59 +0000691
Zaheer Abbas Meralic03f02f2006-03-31 15:21:35 +0000692 cx = ximagesrc->cursor_image->x - ximagesrc->cursor_image->xhot;
Zaheer Abbas Merali1614e032006-06-29 11:05:14 +0000693 if (cx < 0)
694 cx = 0;
Zaheer Abbas Meralic03f02f2006-03-31 15:21:35 +0000695 cy = ximagesrc->cursor_image->y - ximagesrc->cursor_image->yhot;
Zaheer Abbas Merali1614e032006-06-29 11:05:14 +0000696 if (cy < 0)
697 cy = 0;
Zaheer Abbas Meralic03f02f2006-03-31 15:21:35 +0000698 count = ximagesrc->cursor_image->width * ximagesrc->cursor_image->height;
Jan Schmidt27301372006-02-20 21:19:59 +0000699
Zaheer Abbas Meralie0855a02006-07-08 22:41:25 +0000700 /* only get where cursor last was, if it is in our range */
701 if (ximagesrc->endx > ximagesrc->startx &&
702 ximagesrc->endy > ximagesrc->starty) {
703 /* check bounds */
704 if (cx + ximagesrc->cursor_image->width < ximagesrc->startx ||
705 cx > ximagesrc->endx) {
706 /* trivial reject */
707 cursor_in_image = FALSE;
708 } else if (cy + ximagesrc->cursor_image->height < ximagesrc->starty ||
709 cy > ximagesrc->endy) {
710 /* trivial reject */
711 cursor_in_image = FALSE;
712 } else {
713 /* find intersect region */
Jan Schmidt27301372006-02-20 21:19:59 +0000714
Zaheer Abbas Meralie0855a02006-07-08 22:41:25 +0000715 startx = (cx < ximagesrc->startx) ? ximagesrc->startx : cx;
716 starty = (cy < ximagesrc->starty) ? ximagesrc->starty : cy;
717 iwidth = (cx + ximagesrc->cursor_image->width < ximagesrc->endx) ?
718 cx + ximagesrc->cursor_image->width - startx :
719 ximagesrc->endx - startx;
720 iheight = (cy + ximagesrc->cursor_image->height < ximagesrc->endy) ?
721 cy + ximagesrc->cursor_image->height - starty :
722 ximagesrc->endy - starty;
Zaheer Abbas Meralie0855a02006-07-08 22:41:25 +0000723 }
724 } else {
725 startx = cx;
726 starty = cy;
727 iwidth = ximagesrc->cursor_image->width;
728 iheight = ximagesrc->cursor_image->height;
729 }
Jan Schmidt27301372006-02-20 21:19:59 +0000730
Zaheer Abbas Meralie0855a02006-07-08 22:41:25 +0000731 if (cursor_in_image) {
732 GST_DEBUG_OBJECT (ximagesrc, "Cursor is in image so trying to draw it");
733 for (i = 0; i < count; i++)
734 ximagesrc->cursor_image->pixels[i] =
735 GUINT_TO_LE (ximagesrc->cursor_image->pixels[i]);
Zaheer Abbas Meralie0855a02006-07-08 22:41:25 +0000736 /* copy those pixels across */
Eric Anholt28713ec2007-05-11 16:11:04 +0000737 for (j = starty;
738 j < starty + iheight && j < ximagesrc->starty + ximagesrc->height;
Zaheer Abbas Merali20bc2902007-05-11 10:31:27 +0000739 j++) {
Eric Anholt28713ec2007-05-11 16:11:04 +0000740 for (i = startx;
741 i < startx + iwidth && i < ximagesrc->startx + ximagesrc->width;
Zaheer Abbas Merali20bc2902007-05-11 10:31:27 +0000742 i++) {
Zaheer Abbas Meralie0855a02006-07-08 22:41:25 +0000743 guint8 *src, *dest;
744
745 src =
746 (guint8 *) & (ximagesrc->cursor_image->pixels[((j -
747 cy) * ximagesrc->cursor_image->width + (i - cx))]);
748 dest =
Wim Taymansf229f4d2011-02-25 16:29:38 +0100749 (guint8 *) & (meta->ximage->data[((j -
Zaheer Abbas Meralie0855a02006-07-08 22:41:25 +0000750 ximagesrc->starty) * ximagesrc->width + (i -
751 ximagesrc->startx)) * (ximagesrc->xcontext->bpp /
752 8)]);
753
754 composite_pixel (ximagesrc->xcontext, (guint8 *) dest,
755 (guint8 *) src);
756 }
Jan Schmidt27301372006-02-20 21:19:59 +0000757 }
758 }
759 }
760 }
761#endif
Zaheer Abbas Merali20bc2902007-05-11 10:31:27 +0000762#ifdef HAVE_XDAMAGE
763 if (ximagesrc->have_xdamage && ximagesrc->use_damage) {
764 /* need to ref ximage to put in last_ximage */
Wim Taymans9e276e42011-07-10 14:56:00 +0200765 gst_buffer_ref (ximage);
Zaheer Abbas Merali20bc2902007-05-11 10:31:27 +0000766 if (ximagesrc->last_ximage) {
Wim Taymans9e276e42011-07-10 14:56:00 +0200767 gst_buffer_unref (ximagesrc->last_ximage);
Zaheer Abbas Merali20bc2902007-05-11 10:31:27 +0000768 }
769 ximagesrc->last_ximage = ximage;
770 GST_LOG_OBJECT (ximagesrc, "reffing current buffer for last_ximage");
771 }
772#endif
Jan Schmidt27301372006-02-20 21:19:59 +0000773 return ximage;
774}
775
776static GstFlowReturn
Thomas Vander Stichele977f5cf2006-04-28 16:51:33 +0000777gst_ximage_src_create (GstPushSrc * bs, GstBuffer ** buf)
Jan Schmidt27301372006-02-20 21:19:59 +0000778{
Thomas Vander Stichele977f5cf2006-04-28 16:51:33 +0000779 GstXImageSrc *s = GST_XIMAGE_SRC (bs);
Wim Taymansd90a3882011-02-24 13:51:32 +0100780 GstBuffer *image;
Jan Schmidt27301372006-02-20 21:19:59 +0000781 GstClockTime base_time;
782 GstClockTime next_capture_ts;
783 GstClockTime dur;
784 gint64 next_frame_no;
785
Thomas Vander Stichele977f5cf2006-04-28 16:51:33 +0000786 if (!gst_ximage_src_recalc (s)) {
Zaheer Abbas Merali329c7472006-04-07 15:27:40 +0000787 GST_ELEMENT_ERROR (s, RESOURCE, FAILED,
Thomas Vander Stichele7e18cca2006-04-28 16:15:20 +0000788 (_("Changing resolution at runtime is not yet supported.")), (NULL));
Jan Schmidt27301372006-02-20 21:19:59 +0000789 return GST_FLOW_ERROR;
790 }
791
792 if (s->fps_n <= 0 || s->fps_d <= 0)
793 return GST_FLOW_NOT_NEGOTIATED; /* FPS must be > 0 */
794
Thomas Vander Stichele7e18cca2006-04-28 16:15:20 +0000795 /* Now, we might need to wait for the next multiple of the fps
Jan Schmidt27301372006-02-20 21:19:59 +0000796 * before capturing */
797
798 GST_OBJECT_LOCK (s);
Jan Schmidt7f83d022007-03-04 14:56:53 +0000799 if (GST_ELEMENT_CLOCK (s) == NULL) {
800 GST_OBJECT_UNLOCK (s);
801 GST_ELEMENT_ERROR (s, RESOURCE, FAILED,
802 (_("Cannot operate without a clock")), (NULL));
803 return GST_FLOW_ERROR;
804 }
805
Jan Schmidt27301372006-02-20 21:19:59 +0000806 base_time = GST_ELEMENT_CAST (s)->base_time;
807 next_capture_ts = gst_clock_get_time (GST_ELEMENT_CLOCK (s));
808 next_capture_ts -= base_time;
809
810 /* Figure out which 'frame number' position we're at, based on the cur time
811 * and frame rate */
812 next_frame_no = gst_util_uint64_scale (next_capture_ts,
813 s->fps_n, GST_SECOND * s->fps_d);
814 if (next_frame_no == s->last_frame_no) {
815 GstClockID id;
816 GstClockReturn ret;
817
818 /* Need to wait for the next frame */
819 next_frame_no += 1;
820
821 /* Figure out what the next frame time is */
822 next_capture_ts = gst_util_uint64_scale (next_frame_no,
823 s->fps_d * GST_SECOND, s->fps_n);
824
825 id = gst_clock_new_single_shot_id (GST_ELEMENT_CLOCK (s),
826 next_capture_ts + base_time);
827 s->clock_id = id;
828
829 /* release the object lock while waiting */
830 GST_OBJECT_UNLOCK (s);
831
832 GST_DEBUG_OBJECT (s, "Waiting for next frame time %" G_GUINT64_FORMAT,
833 next_capture_ts);
834 ret = gst_clock_id_wait (id, NULL);
835 GST_OBJECT_LOCK (s);
836
837 gst_clock_id_unref (id);
838 s->clock_id = NULL;
839 if (ret == GST_CLOCK_UNSCHEDULED) {
840 /* Got woken up by the unlock function */
841 GST_OBJECT_UNLOCK (s);
Wim Taymans9365f122012-02-08 16:34:00 +0100842 return GST_FLOW_FLUSHING;
Jan Schmidt27301372006-02-20 21:19:59 +0000843 }
844 /* Duration is a complete 1/fps frame duration */
845 dur = gst_util_uint64_scale_int (GST_SECOND, s->fps_d, s->fps_n);
846 } else {
847 GstClockTime next_frame_ts;
848
849 GST_DEBUG_OBJECT (s, "No need to wait for next frame time %"
850 G_GUINT64_FORMAT " next frame = %" G_GINT64_FORMAT " prev = %"
851 G_GINT64_FORMAT, next_capture_ts, next_frame_no, s->last_frame_no);
852 next_frame_ts = gst_util_uint64_scale (next_frame_no + 1,
853 s->fps_d * GST_SECOND, s->fps_n);
854 /* Frame duration is from now until the next expected capture time */
855 dur = next_frame_ts - next_capture_ts;
856 }
857 s->last_frame_no = next_frame_no;
858 GST_OBJECT_UNLOCK (s);
859
Thomas Vander Stichele977f5cf2006-04-28 16:51:33 +0000860 image = gst_ximage_src_ximage_get (s);
Jan Schmidt27301372006-02-20 21:19:59 +0000861 if (!image)
862 return GST_FLOW_ERROR;
863
Wim Taymans9e276e42011-07-10 14:56:00 +0200864 *buf = image;
Jan Schmidt27301372006-02-20 21:19:59 +0000865 GST_BUFFER_TIMESTAMP (*buf) = next_capture_ts;
866 GST_BUFFER_DURATION (*buf) = dur;
867
868 return GST_FLOW_OK;
869}
870
871static void
Thomas Vander Stichele977f5cf2006-04-28 16:51:33 +0000872gst_ximage_src_set_property (GObject * object, guint prop_id,
Jan Schmidt27301372006-02-20 21:19:59 +0000873 const GValue * value, GParamSpec * pspec)
874{
Thomas Vander Stichele977f5cf2006-04-28 16:51:33 +0000875 GstXImageSrc *src = GST_XIMAGE_SRC (object);
Jan Schmidt27301372006-02-20 21:19:59 +0000876
877 switch (prop_id) {
878 case PROP_DISPLAY_NAME:
879
880 g_free (src->display_name);
881 src->display_name = g_strdup (g_value_get_string (value));
Jan Schmidt27301372006-02-20 21:19:59 +0000882 break;
883 case PROP_SCREEN_NUM:
884 src->screen_num = g_value_get_uint (value);
Jan Schmidt27301372006-02-20 21:19:59 +0000885 break;
Zaheer Abbas Merali4a4c3062006-03-17 16:34:36 +0000886 case PROP_SHOW_POINTER:
887 src->show_pointer = g_value_get_boolean (value);
888 break;
Zaheer Abbas Meralie6c882b2006-07-08 19:03:54 +0000889 case PROP_USE_DAMAGE:
890 src->use_damage = g_value_get_boolean (value);
891 break;
Zaheer Abbas Meralie0855a02006-07-08 22:41:25 +0000892 case PROP_STARTX:
893 src->startx = g_value_get_uint (value);
894 break;
895 case PROP_STARTY:
896 src->starty = g_value_get_uint (value);
897 break;
898 case PROP_ENDX:
899 src->endx = g_value_get_uint (value);
900 break;
901 case PROP_ENDY:
902 src->endy = g_value_get_uint (value);
903 break;
Vincent Penquerc'h7ac31b32010-11-29 12:36:06 +0000904 case PROP_REMOTE:
905 src->remote = g_value_get_boolean (value);
906 break;
Vincent Penquerc'h82927d62011-09-20 12:11:47 +0100907 case PROP_XID:
908 if (src->xcontext != NULL) {
909 g_warning ("ximagesrc window ID must be set before opening display");
910 break;
911 }
912 src->xid = g_value_get_uint64 (value);
913 break;
914 case PROP_XNAME:
915 if (src->xcontext != NULL) {
916 g_warning ("ximagesrc window name must be set before opening display");
917 break;
918 }
919 g_free (src->xname);
920 src->xname = g_strdup (g_value_get_string (value));
921 break;
Jan Schmidt27301372006-02-20 21:19:59 +0000922 default:
923 break;
924 }
925}
926
927static void
Thomas Vander Stichele977f5cf2006-04-28 16:51:33 +0000928gst_ximage_src_get_property (GObject * object, guint prop_id, GValue * value,
Jan Schmidt27301372006-02-20 21:19:59 +0000929 GParamSpec * pspec)
930{
Thomas Vander Stichele977f5cf2006-04-28 16:51:33 +0000931 GstXImageSrc *src = GST_XIMAGE_SRC (object);
Jan Schmidt27301372006-02-20 21:19:59 +0000932
933 switch (prop_id) {
934 case PROP_DISPLAY_NAME:
935 if (src->xcontext)
936 g_value_set_string (value, DisplayString (src->xcontext->disp));
937 else
938 g_value_set_string (value, src->display_name);
939
940 break;
941 case PROP_SCREEN_NUM:
942 g_value_set_uint (value, src->screen_num);
943 break;
Zaheer Abbas Merali4a4c3062006-03-17 16:34:36 +0000944 case PROP_SHOW_POINTER:
945 g_value_set_boolean (value, src->show_pointer);
946 break;
Zaheer Abbas Meralie6c882b2006-07-08 19:03:54 +0000947 case PROP_USE_DAMAGE:
948 g_value_set_boolean (value, src->use_damage);
Zaheer Abbas Meralie0855a02006-07-08 22:41:25 +0000949 break;
950 case PROP_STARTX:
951 g_value_set_uint (value, src->startx);
952 break;
953 case PROP_STARTY:
954 g_value_set_uint (value, src->starty);
955 break;
956 case PROP_ENDX:
957 g_value_set_uint (value, src->endx);
958 break;
959 case PROP_ENDY:
960 g_value_set_uint (value, src->endy);
961 break;
Vincent Penquerc'h7ac31b32010-11-29 12:36:06 +0000962 case PROP_REMOTE:
Edward Herveyd2a43eb2010-12-22 21:27:11 +0100963 g_value_set_boolean (value, src->remote);
Vincent Penquerc'h7ac31b32010-11-29 12:36:06 +0000964 break;
Vincent Penquerc'h82927d62011-09-20 12:11:47 +0100965 case PROP_XID:
966 g_value_set_uint64 (value, src->xid);
967 break;
968 case PROP_XNAME:
969 g_value_set_string (value, src->xname);
970 break;
Jan Schmidt27301372006-02-20 21:19:59 +0000971 default:
972 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
973 break;
974 }
975}
976
977static void
Thomas Vander Stichele977f5cf2006-04-28 16:51:33 +0000978gst_ximage_src_clear_bufpool (GstXImageSrc * ximagesrc)
Jan Schmidt27301372006-02-20 21:19:59 +0000979{
Wim Taymans15848062012-01-19 11:33:53 +0100980 g_mutex_lock (&ximagesrc->pool_lock);
Jan Schmidt27301372006-02-20 21:19:59 +0000981 while (ximagesrc->buffer_pool != NULL) {
Wim Taymansd90a3882011-02-24 13:51:32 +0100982 GstBuffer *ximage = ximagesrc->buffer_pool->data;
Jan Schmidt27301372006-02-20 21:19:59 +0000983
984 gst_ximage_buffer_free (ximage);
985
986 ximagesrc->buffer_pool = g_slist_delete_link (ximagesrc->buffer_pool,
987 ximagesrc->buffer_pool);
988 }
Wim Taymans15848062012-01-19 11:33:53 +0100989 g_mutex_unlock (&ximagesrc->pool_lock);
Jan Schmidt27301372006-02-20 21:19:59 +0000990}
991
992static void
Thomas Vander Stichele977f5cf2006-04-28 16:51:33 +0000993gst_ximage_src_dispose (GObject * object)
Jan Schmidt27301372006-02-20 21:19:59 +0000994{
995 /* Drop references in the buffer_pool */
Thomas Vander Stichele977f5cf2006-04-28 16:51:33 +0000996 gst_ximage_src_clear_bufpool (GST_XIMAGE_SRC (object));
Jan Schmidt5ab0aa12007-03-04 15:28:30 +0000997
998 G_OBJECT_CLASS (parent_class)->dispose (object);
Jan Schmidt27301372006-02-20 21:19:59 +0000999}
1000
1001static void
Thomas Vander Stichele977f5cf2006-04-28 16:51:33 +00001002gst_ximage_src_finalize (GObject * object)
Jan Schmidt27301372006-02-20 21:19:59 +00001003{
Thomas Vander Stichele977f5cf2006-04-28 16:51:33 +00001004 GstXImageSrc *src = GST_XIMAGE_SRC (object);
Jan Schmidt27301372006-02-20 21:19:59 +00001005
1006 if (src->xcontext)
1007 ximageutil_xcontext_clear (src->xcontext);
1008
Vincent Penquerc'h82927d62011-09-20 12:11:47 +01001009 g_free (src->xname);
Wim Taymans15848062012-01-19 11:33:53 +01001010 g_mutex_clear (&src->pool_lock);
1011 g_mutex_clear (&src->x_lock);
Jan Schmidt27301372006-02-20 21:19:59 +00001012
1013 G_OBJECT_CLASS (parent_class)->finalize (object);
1014}
1015
1016static GstCaps *
Wim Taymans9e276e42011-07-10 14:56:00 +02001017gst_ximage_src_get_caps (GstBaseSrc * bs, GstCaps * filter)
Jan Schmidt27301372006-02-20 21:19:59 +00001018{
Thomas Vander Stichele977f5cf2006-04-28 16:51:33 +00001019 GstXImageSrc *s = GST_XIMAGE_SRC (bs);
Jan Schmidt27301372006-02-20 21:19:59 +00001020 GstXContext *xcontext;
Edward Hervey0cb5b422009-04-18 18:11:00 +02001021 gint width, height;
Wim Taymans1dada152012-03-05 12:03:01 +01001022 GstVideoFormat format;
Jan Schmidt27301372006-02-20 21:19:59 +00001023
daniel fischere359a412007-06-11 11:41:56 +00001024 if ((!s->xcontext) && (!gst_ximage_src_open_display (s, s->display_name)))
Wim Taymanse310ee82012-03-27 16:41:06 +02001025 return gst_pad_get_pad_template_caps (GST_BASE_SRC (s)->srcpad);
Jan Schmidt27301372006-02-20 21:19:59 +00001026
Thomas Vander Stichele977f5cf2006-04-28 16:51:33 +00001027 if (!gst_ximage_src_recalc (s))
Wim Taymanse310ee82012-03-27 16:41:06 +02001028 return gst_pad_get_pad_template_caps (GST_BASE_SRC (s)->srcpad);
Jan Schmidt27301372006-02-20 21:19:59 +00001029
1030 xcontext = s->xcontext;
Vincent Penquerc'h82927d62011-09-20 12:11:47 +01001031 width = s->xcontext->width;
1032 height = s->xcontext->height;
1033 if (s->xwindow != 0) {
1034 XWindowAttributes attrs;
1035 int status = XGetWindowAttributes (s->xcontext->disp, s->xwindow, &attrs);
1036 if (status) {
1037 width = attrs.width;
1038 height = attrs.height;
1039 }
1040 }
Vincent Penquerc'hfbd95812010-11-27 17:15:32 +00001041
1042 /* property comments say 0 means right/bottom, means we can't capture
1043 the top left pixel alone */
1044 if (s->endx == 0)
1045 s->endx = width - 1;
1046 if (s->endy == 0)
1047 s->endy = height - 1;
1048
1049 if (s->endx >= s->startx && s->endy >= s->starty) {
Zaheer Abbas Meralie0855a02006-07-08 22:41:25 +00001050 /* this means user has put in values */
1051 if (s->startx < xcontext->width && s->endx < xcontext->width &&
Sebastian Dröge9d5e5ea2012-03-06 14:22:43 +01001052 s->starty < xcontext->height && s->endy < xcontext->height) {
Zaheer Abbas Meralie0855a02006-07-08 22:41:25 +00001053 /* values are fine */
Vincent Penquerc'hfbd95812010-11-27 17:15:32 +00001054 s->width = width = s->endx - s->startx + 1;
1055 s->height = height = s->endy - s->starty + 1;
Zaheer Abbas Meralie0855a02006-07-08 22:41:25 +00001056 } else {
1057 GST_WARNING
1058 ("User put in co-ordinates overshooting the X resolution, setting to full screen");
1059 s->startx = 0;
1060 s->starty = 0;
Vincent Penquerc'hfbd95812010-11-27 17:15:32 +00001061 s->endx = width - 1;
1062 s->endy = height - 1;
Zaheer Abbas Meralie0855a02006-07-08 22:41:25 +00001063 }
1064 } else {
1065 GST_WARNING ("User put in bogus co-ordinates, setting to full screen");
1066 s->startx = 0;
1067 s->starty = 0;
Vincent Penquerc'hfbd95812010-11-27 17:15:32 +00001068 s->endx = width - 1;
1069 s->endy = height - 1;
Zaheer Abbas Meralie0855a02006-07-08 22:41:25 +00001070 }
1071 GST_DEBUG ("width = %d, height=%d", width, height);
Wim Taymans1dada152012-03-05 12:03:01 +01001072
1073 format =
1074 gst_video_format_from_masks (xcontext->depth, xcontext->bpp,
1075 xcontext->endianness, xcontext->r_mask_output, xcontext->g_mask_output,
1076 xcontext->b_mask_output, 0);
1077
1078 return gst_caps_new_simple ("video/x-raw",
1079 "format", G_TYPE_STRING, gst_video_format_to_string (format),
Zaheer Abbas Meralie0855a02006-07-08 22:41:25 +00001080 "width", G_TYPE_INT, width,
1081 "height", G_TYPE_INT, height,
Zaheer Abbas Meralif84de0e2006-03-31 17:52:36 +00001082 "framerate", GST_TYPE_FRACTION_RANGE, 1, G_MAXINT, G_MAXINT, 1,
1083 "pixel-aspect-ratio", GST_TYPE_FRACTION_RANGE, 1, G_MAXINT, G_MAXINT, 1,
1084 NULL);
Jan Schmidt27301372006-02-20 21:19:59 +00001085}
1086
1087static gboolean
Thomas Vander Stichele977f5cf2006-04-28 16:51:33 +00001088gst_ximage_src_set_caps (GstBaseSrc * bs, GstCaps * caps)
Jan Schmidt27301372006-02-20 21:19:59 +00001089{
Thomas Vander Stichele977f5cf2006-04-28 16:51:33 +00001090 GstXImageSrc *s = GST_XIMAGE_SRC (bs);
Jan Schmidt27301372006-02-20 21:19:59 +00001091 GstStructure *structure;
1092 const GValue *new_fps;
1093
1094 /* If not yet opened, disallow setcaps until later */
1095 if (!s->xcontext)
1096 return FALSE;
1097
1098 /* The only thing that can change is the framerate downstream wants */
1099 structure = gst_caps_get_structure (caps, 0);
1100 new_fps = gst_structure_get_value (structure, "framerate");
1101 if (!new_fps)
1102 return FALSE;
1103
1104 /* Store this FPS for use when generating buffers */
1105 s->fps_n = gst_value_get_fraction_numerator (new_fps);
1106 s->fps_d = gst_value_get_fraction_denominator (new_fps);
1107
1108 GST_DEBUG_OBJECT (s, "peer wants %d/%d fps", s->fps_n, s->fps_d);
1109
1110 return TRUE;
1111}
1112
Wim Taymansa32d9442012-03-11 19:06:37 +01001113static GstCaps *
Wim Taymans88e398b2011-11-10 11:03:18 +01001114gst_ximage_src_fixate (GstBaseSrc * bsrc, GstCaps * caps)
Jan Schmidt27301372006-02-20 21:19:59 +00001115{
1116 gint i;
1117 GstStructure *structure;
1118
Wim Taymansa32d9442012-03-11 19:06:37 +01001119 caps = gst_caps_make_writable (caps);
1120
Jan Schmidt27301372006-02-20 21:19:59 +00001121 for (i = 0; i < gst_caps_get_size (caps); ++i) {
1122 structure = gst_caps_get_structure (caps, i);
1123
1124 gst_structure_fixate_field_nearest_fraction (structure, "framerate", 25, 1);
1125 }
Wim Taymansa32d9442012-03-11 19:06:37 +01001126 caps = GST_BASE_SRC_CLASS (parent_class)->fixate (bsrc, caps);
1127
1128 return caps;
Jan Schmidt27301372006-02-20 21:19:59 +00001129}
1130
1131static void
Thomas Vander Stichele977f5cf2006-04-28 16:51:33 +00001132gst_ximage_src_class_init (GstXImageSrcClass * klass)
Jan Schmidt27301372006-02-20 21:19:59 +00001133{
1134 GObjectClass *gc = G_OBJECT_CLASS (klass);
Wim Taymans9e276e42011-07-10 14:56:00 +02001135 GstElementClass *ec = GST_ELEMENT_CLASS (klass);
Jan Schmidt27301372006-02-20 21:19:59 +00001136 GstBaseSrcClass *bc = GST_BASE_SRC_CLASS (klass);
1137 GstPushSrcClass *push_class = GST_PUSH_SRC_CLASS (klass);
1138
Thomas Vander Stichele977f5cf2006-04-28 16:51:33 +00001139 gc->set_property = gst_ximage_src_set_property;
1140 gc->get_property = gst_ximage_src_get_property;
1141 gc->dispose = gst_ximage_src_dispose;
1142 gc->finalize = gst_ximage_src_finalize;
Jan Schmidt27301372006-02-20 21:19:59 +00001143
1144 g_object_class_install_property (gc, PROP_DISPLAY_NAME,
Tim-Philipp Müllerf62efef2006-07-25 17:54:25 +00001145 g_param_spec_string ("display-name", "Display", "X Display Name", NULL,
Stefan Kost77b656e2010-10-13 17:13:04 +03001146 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
Jan Schmidt27301372006-02-20 21:19:59 +00001147 g_object_class_install_property (gc, PROP_SCREEN_NUM,
Tim-Philipp Müllerf62efef2006-07-25 17:54:25 +00001148 g_param_spec_uint ("screen-num", "Screen number", "X Screen Number",
Stefan Kost77b656e2010-10-13 17:13:04 +03001149 0, G_MAXINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
Zaheer Abbas Merali4a4c3062006-03-17 16:34:36 +00001150 g_object_class_install_property (gc, PROP_SHOW_POINTER,
Tim-Philipp Müllerf62efef2006-07-25 17:54:25 +00001151 g_param_spec_boolean ("show-pointer", "Show Mouse Pointer",
Thomas Vander Stichele7e18cca2006-04-28 16:15:20 +00001152 "Show mouse pointer (if XFixes extension enabled)", TRUE,
Stefan Kost77b656e2010-10-13 17:13:04 +03001153 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
Tim-Philipp Müllerf62efef2006-07-25 17:54:25 +00001154 /**
1155 * GstXImageSrc:use-damage
1156 *
1157 * Use XDamage (if the XDamage extension is enabled)
1158 *
1159 * Since: 0.10.4
1160 **/
Zaheer Abbas Meralie0855a02006-07-08 22:41:25 +00001161 g_object_class_install_property (gc, PROP_USE_DAMAGE,
Tim-Philipp Müllerf62efef2006-07-25 17:54:25 +00001162 g_param_spec_boolean ("use-damage", "Use XDamage",
Zaheer Abbas Meralie6c882b2006-07-08 19:03:54 +00001163 "Use XDamage (if XDamage extension enabled)", TRUE,
Stefan Kost77b656e2010-10-13 17:13:04 +03001164 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
Tim-Philipp Müllerf62efef2006-07-25 17:54:25 +00001165 /**
1166 * GstXImageSrc:startx
1167 *
1168 * X coordinate of top left corner of area to be recorded
1169 * (0 for top left of screen)
1170 *
1171 * Since: 0.10.4
1172 **/
Zaheer Abbas Meralie0855a02006-07-08 22:41:25 +00001173 g_object_class_install_property (gc, PROP_STARTX,
1174 g_param_spec_uint ("startx", "Start X co-ordinate",
1175 "X coordinate of top left corner of area to be recorded (0 for top left of screen)",
Stefan Kost77b656e2010-10-13 17:13:04 +03001176 0, G_MAXINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
Tim-Philipp Müllerf62efef2006-07-25 17:54:25 +00001177 /**
1178 * GstXImageSrc:starty
1179 *
1180 * Y coordinate of top left corner of area to be recorded
1181 * (0 for top left of screen)
1182 *
1183 * Since: 0.10.4
1184 **/
Zaheer Abbas Meralie0855a02006-07-08 22:41:25 +00001185 g_object_class_install_property (gc, PROP_STARTY,
1186 g_param_spec_uint ("starty", "Start Y co-ordinate",
1187 "Y coordinate of top left corner of area to be recorded (0 for top left of screen)",
1188 0, G_MAXINT, 0, G_PARAM_READWRITE));
Tim-Philipp Müllerf62efef2006-07-25 17:54:25 +00001189 /**
1190 * GstXImageSrc:endx
1191 *
1192 * X coordinate of bottom right corner of area to be recorded
1193 * (0 for bottom right of screen)
1194 *
1195 * Since: 0.10.4
1196 **/
Zaheer Abbas Meralie0855a02006-07-08 22:41:25 +00001197 g_object_class_install_property (gc, PROP_ENDX,
1198 g_param_spec_uint ("endx", "End X",
1199 "X coordinate of bottom right corner of area to be recorded (0 for bottom right of screen)",
1200 0, G_MAXINT, 0, G_PARAM_READWRITE));
Tim-Philipp Müllerf62efef2006-07-25 17:54:25 +00001201 /**
1202 * GstXImageSrc:endy
1203 *
1204 * Y coordinate of bottom right corner of area to be recorded
1205 * (0 for bottom right of screen)
1206 *
1207 * Since: 0.10.4
1208 **/
Zaheer Abbas Meralie0855a02006-07-08 22:41:25 +00001209 g_object_class_install_property (gc, PROP_ENDY,
1210 g_param_spec_uint ("endy", "End Y",
1211 "Y coordinate of bottom right corner of area to be recorded (0 for bottom right of screen)",
1212 0, G_MAXINT, 0, G_PARAM_READWRITE));
Jan Schmidt27301372006-02-20 21:19:59 +00001213
Vincent Penquerc'h7ac31b32010-11-29 12:36:06 +00001214 /**
1215 * GstXImageSrc:remote
1216 *
1217 * Whether the X display is remote. The element will try to use alternate calls
1218 * known to work better with remote displays.
1219 *
1220 * Since: 0.10.26
1221 **/
1222 g_object_class_install_property (gc, PROP_REMOTE,
1223 g_param_spec_boolean ("remote", "Remote dispay",
1224 "Whether the display is remote", FALSE,
1225 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
Vincent Penquerc'h82927d62011-09-20 12:11:47 +01001226 /**
1227 * GstXImageSrc:xid
1228 *
1229 * The XID of the window to capture. 0 for the root window (default).
1230 *
1231 * Since: 0.10.31
1232 **/
1233 g_object_class_install_property (gc, PROP_XID,
1234 g_param_spec_uint64 ("xid", "Window XID",
1235 "Window XID to capture from", 0, G_MAXUINT64, 0,
1236 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
Vincent Penquerc'h82927d62011-09-20 12:11:47 +01001237 /**
1238 * GstXImageSrc:xname
1239 *
1240 * The name of the window to capture, if any.
1241 *
1242 * Since: 0.10.31
1243 **/
1244 g_object_class_install_property (gc, PROP_XNAME,
1245 g_param_spec_string ("xname", "Window name",
1246 "Window name to capture from", NULL,
1247 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
Vincent Penquerc'h7ac31b32010-11-29 12:36:06 +00001248
Wim Taymans9e276e42011-07-10 14:56:00 +02001249 gst_element_class_set_details_simple (ec, "Ximage video source",
1250 "Source/Video",
1251 "Creates a screenshot video stream",
1252 "Lutz Mueller <lutz@users.sourceforge.net>, "
1253 "Jan Schmidt <thaytan@mad.scientist.com>, "
1254 "Zaheer Merali <zaheerabbas at merali dot org>");
1255 gst_element_class_add_pad_template (ec, gst_static_pad_template_get (&t));
Jan Schmidt27301372006-02-20 21:19:59 +00001256
Wim Taymans88e398b2011-11-10 11:03:18 +01001257 bc->fixate = gst_ximage_src_fixate;
Thomas Vander Stichele977f5cf2006-04-28 16:51:33 +00001258 bc->get_caps = gst_ximage_src_get_caps;
1259 bc->set_caps = gst_ximage_src_set_caps;
1260 bc->start = gst_ximage_src_start;
1261 bc->stop = gst_ximage_src_stop;
1262 bc->unlock = gst_ximage_src_unlock;
Wim Taymans88e398b2011-11-10 11:03:18 +01001263 push_class->create = gst_ximage_src_create;
Jan Schmidt27301372006-02-20 21:19:59 +00001264}
1265
1266static void
Wim Taymans9e276e42011-07-10 14:56:00 +02001267gst_ximage_src_init (GstXImageSrc * ximagesrc)
Jan Schmidt27301372006-02-20 21:19:59 +00001268{
Thadeu Lima de Souza Cascardoaa26b092010-02-23 21:06:55 -03001269 gst_base_src_set_format (GST_BASE_SRC (ximagesrc), GST_FORMAT_TIME);
Jan Schmidt27301372006-02-20 21:19:59 +00001270 gst_base_src_set_live (GST_BASE_SRC (ximagesrc), TRUE);
Jan Schmidt27301372006-02-20 21:19:59 +00001271
Wim Taymans15848062012-01-19 11:33:53 +01001272 g_mutex_init (&ximagesrc->pool_lock);
1273 g_mutex_init (&ximagesrc->x_lock);
Zaheer Abbas Merali4a4c3062006-03-17 16:34:36 +00001274 ximagesrc->show_pointer = TRUE;
Zaheer Abbas Meralie6c882b2006-07-08 19:03:54 +00001275 ximagesrc->use_damage = TRUE;
Zaheer Abbas Meralie0855a02006-07-08 22:41:25 +00001276 ximagesrc->startx = 0;
1277 ximagesrc->starty = 0;
1278 ximagesrc->endx = 0;
1279 ximagesrc->endy = 0;
Vincent Penquerc'h7ac31b32010-11-29 12:36:06 +00001280 ximagesrc->remote = FALSE;
Jan Schmidt27301372006-02-20 21:19:59 +00001281}
1282
1283static gboolean
1284plugin_init (GstPlugin * plugin)
1285{
1286 gboolean ret;
1287
Thomas Vander Stichele977f5cf2006-04-28 16:51:33 +00001288 GST_DEBUG_CATEGORY_INIT (gst_debug_ximage_src, "ximagesrc", 0,
Jan Schmidt27301372006-02-20 21:19:59 +00001289 "ximagesrc element debug");
1290
1291 ret = gst_element_register (plugin, "ximagesrc", GST_RANK_NONE,
Thomas Vander Stichele977f5cf2006-04-28 16:51:33 +00001292 GST_TYPE_XIMAGE_SRC);
Jan Schmidt27301372006-02-20 21:19:59 +00001293
1294 return ret;
1295}
1296
1297GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
1298 GST_VERSION_MINOR,
1299 "ximagesrc",
Thomas Vander Stichele7e18cca2006-04-28 16:15:20 +00001300 "X11 video input plugin using standard Xlib calls",
1301 plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN);