• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* GStreamer
2  * Copyright (C) <2007> Thijs Vermeir <thijsvermeir@gmail.com>
3  * Copyright (C) <2006> Andre Moreira Magalhaes <andre.magalhaes@indt.org.br>
4  * Copyright (C) <2004> David A. Schleef <ds@schleef.org>
5  * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
20  * Boston, MA 02110-1301, USA.
21  */
22 
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26 
27 #include "gstrfbsrc.h"
28 
29 #include <gst/video/video.h>
30 
31 #include <string.h>
32 #include <stdlib.h>
33 #ifdef HAVE_X11
34 #include <X11/Xlib.h>
35 #endif
36 
37 enum
38 {
39   PROP_0,
40   PROP_HOST,
41   PROP_PORT,
42   PROP_VERSION,
43   PROP_PASSWORD,
44   PROP_OFFSET_X,
45   PROP_OFFSET_Y,
46   PROP_WIDTH,
47   PROP_HEIGHT,
48   PROP_INCREMENTAL,
49   PROP_USE_COPYRECT,
50   PROP_SHARED,
51   PROP_VIEWONLY
52 };
53 
54 GST_DEBUG_CATEGORY_STATIC (rfbsrc_debug);
55 GST_DEBUG_CATEGORY (rfbdecoder_debug);
56 #define GST_CAT_DEFAULT rfbsrc_debug
57 
58 static GstStaticPadTemplate gst_rfb_src_template =
59     GST_STATIC_PAD_TEMPLATE ("src",
60     GST_PAD_SRC,
61     GST_PAD_ALWAYS,
62     GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("RGB")
63         "; " GST_VIDEO_CAPS_MAKE ("BGR")
64         "; " GST_VIDEO_CAPS_MAKE ("RGBx")
65         "; " GST_VIDEO_CAPS_MAKE ("BGRx")
66         "; " GST_VIDEO_CAPS_MAKE ("xRGB")
67         "; " GST_VIDEO_CAPS_MAKE ("xBGR")));
68 
69 static void gst_rfb_src_finalize (GObject * object);
70 static void gst_rfb_src_set_property (GObject * object, guint prop_id,
71     const GValue * value, GParamSpec * pspec);
72 static void gst_rfb_src_get_property (GObject * object, guint prop_id,
73     GValue * value, GParamSpec * pspec);
74 
75 static gboolean gst_rfb_src_negotiate (GstBaseSrc * bsrc);
76 static gboolean gst_rfb_src_stop (GstBaseSrc * bsrc);
77 static gboolean gst_rfb_src_event (GstBaseSrc * bsrc, GstEvent * event);
78 static gboolean gst_rfb_src_unlock (GstBaseSrc * bsrc);
79 static gboolean gst_rfb_src_decide_allocation (GstBaseSrc * bsrc,
80     GstQuery * query);
81 static GstFlowReturn gst_rfb_src_fill (GstPushSrc * psrc, GstBuffer * outbuf);
82 
83 #define gst_rfb_src_parent_class parent_class
84 G_DEFINE_TYPE (GstRfbSrc, gst_rfb_src, GST_TYPE_PUSH_SRC);
85 GST_ELEMENT_REGISTER_DEFINE (rfbsrc, "rfbsrc", GST_RANK_NONE, GST_TYPE_RFB_SRC);
86 
87 static void
gst_rfb_src_class_init(GstRfbSrcClass * klass)88 gst_rfb_src_class_init (GstRfbSrcClass * klass)
89 {
90   GObjectClass *gobject_class;
91   GstBaseSrcClass *gstbasesrc_class;
92   GstElementClass *gstelement_class;
93   GstPushSrcClass *gstpushsrc_class;
94 
95 
96   GST_DEBUG_CATEGORY_INIT (rfbsrc_debug, "rfbsrc", 0, "rfb src element");
97   GST_DEBUG_CATEGORY_INIT (rfbdecoder_debug, "rfbdecoder", 0, "rfb decoder");
98 
99   gobject_class = (GObjectClass *) klass;
100   gstbasesrc_class = (GstBaseSrcClass *) klass;
101   gstpushsrc_class = (GstPushSrcClass *) klass;
102 
103   gobject_class->finalize = gst_rfb_src_finalize;
104   gobject_class->set_property = gst_rfb_src_set_property;
105   gobject_class->get_property = gst_rfb_src_get_property;
106 
107   g_object_class_install_property (gobject_class, PROP_HOST,
108       g_param_spec_string ("host", "Host to connect to", "Host to connect to",
109           "127.0.0.1", G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
110   g_object_class_install_property (gobject_class, PROP_PORT,
111       g_param_spec_int ("port", "Port", "Port",
112           1, 65535, 5900, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
113   g_object_class_install_property (gobject_class, PROP_VERSION,
114       g_param_spec_string ("version", "RFB protocol version",
115           "RFB protocol version", "3.3",
116           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
117   g_object_class_install_property (gobject_class, PROP_PASSWORD,
118       g_param_spec_string ("password", "Password for authentication",
119           "Password for authentication", "",
120           G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
121   g_object_class_install_property (gobject_class, PROP_OFFSET_X,
122       g_param_spec_int ("offset-x", "x offset for screen scrapping",
123           "x offset for screen scrapping", 0, 65535, 0,
124           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
125   g_object_class_install_property (gobject_class, PROP_OFFSET_Y,
126       g_param_spec_int ("offset-y", "y offset for screen scrapping",
127           "y offset for screen scrapping", 0, 65535, 0,
128           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
129   g_object_class_install_property (gobject_class, PROP_WIDTH,
130       g_param_spec_int ("width", "width of screen", "width of screen", 0, 65535,
131           0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
132   g_object_class_install_property (gobject_class, PROP_HEIGHT,
133       g_param_spec_int ("height", "height of screen", "height of screen", 0,
134           65535, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
135   g_object_class_install_property (gobject_class, PROP_INCREMENTAL,
136       g_param_spec_boolean ("incremental", "Incremental updates",
137           "Incremental updates", TRUE,
138           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
139   g_object_class_install_property (gobject_class, PROP_USE_COPYRECT,
140       g_param_spec_boolean ("use-copyrect", "Use copyrect encoding",
141           "Use copyrect encoding", FALSE,
142           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
143   g_object_class_install_property (gobject_class, PROP_SHARED,
144       g_param_spec_boolean ("shared", "Share desktop with other clients",
145           "Share desktop with other clients", TRUE,
146           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
147   g_object_class_install_property (gobject_class, PROP_VIEWONLY,
148       g_param_spec_boolean ("view-only", "Only view the desktop",
149           "only view the desktop", FALSE,
150           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
151 
152   gstbasesrc_class->negotiate = GST_DEBUG_FUNCPTR (gst_rfb_src_negotiate);
153   gstbasesrc_class->stop = GST_DEBUG_FUNCPTR (gst_rfb_src_stop);
154   gstbasesrc_class->event = GST_DEBUG_FUNCPTR (gst_rfb_src_event);
155   gstbasesrc_class->unlock = GST_DEBUG_FUNCPTR (gst_rfb_src_unlock);
156   gstpushsrc_class->fill = GST_DEBUG_FUNCPTR (gst_rfb_src_fill);
157   gstbasesrc_class->decide_allocation =
158       GST_DEBUG_FUNCPTR (gst_rfb_src_decide_allocation);
159 
160   gstelement_class = GST_ELEMENT_CLASS (klass);
161 
162   gst_element_class_add_static_pad_template (gstelement_class,
163       &gst_rfb_src_template);
164 
165   gst_element_class_set_static_metadata (gstelement_class, "Rfb source",
166       "Source/Video",
167       "Creates a rfb video stream",
168       "David A. Schleef <ds@schleef.org>, "
169       "Andre Moreira Magalhaes <andre.magalhaes@indt.org.br>, "
170       "Thijs Vermeir <thijsvermeir@gmail.com>");
171 }
172 
173 static void
gst_rfb_src_init(GstRfbSrc * src)174 gst_rfb_src_init (GstRfbSrc * src)
175 {
176   GstBaseSrc *bsrc = GST_BASE_SRC (src);
177 
178   gst_pad_use_fixed_caps (GST_BASE_SRC_PAD (bsrc));
179   gst_base_src_set_live (bsrc, TRUE);
180   gst_base_src_set_format (bsrc, GST_FORMAT_TIME);
181 
182   src->host = g_strdup ("127.0.0.1");
183   src->port = 5900;
184   src->version_major = 3;
185   src->version_minor = 3;
186 
187   src->incremental_update = TRUE;
188 
189   src->view_only = FALSE;
190 
191   src->decoder = rfb_decoder_new ();
192 }
193 
194 static void
gst_rfb_src_finalize(GObject * object)195 gst_rfb_src_finalize (GObject * object)
196 {
197   GstRfbSrc *src = GST_RFB_SRC (object);
198 
199   g_free (src->host);
200 
201   if (src->decoder) {
202     rfb_decoder_free (src->decoder);
203     src->decoder = NULL;
204   }
205 
206   G_OBJECT_CLASS (parent_class)->finalize (object);
207 }
208 
209 static void
gst_rfb_property_set_version(GstRfbSrc * src,gchar * value)210 gst_rfb_property_set_version (GstRfbSrc * src, gchar * value)
211 {
212   gchar *major;
213   gchar *minor;
214 
215   g_return_if_fail (src != NULL);
216   g_return_if_fail (value != NULL);
217 
218   major = g_strdup (value);
219   minor = g_strrstr (value, ".");
220 
221   g_return_if_fail (minor != NULL);
222 
223   *minor++ = 0;
224 
225   g_return_if_fail (g_ascii_isdigit (*major) == TRUE);
226   g_return_if_fail (g_ascii_isdigit (*minor) == TRUE);
227 
228   src->version_major = g_ascii_digit_value (*major);
229   src->version_minor = g_ascii_digit_value (*minor);
230 
231   GST_DEBUG ("Version major : %d", src->version_major);
232   GST_DEBUG ("Version minor : %d", src->version_minor);
233 
234   g_free (major);
235   g_free (value);
236 }
237 
238 static gchar *
gst_rfb_property_get_version(GstRfbSrc * src)239 gst_rfb_property_get_version (GstRfbSrc * src)
240 {
241   return g_strdup_printf ("%d.%d", src->version_major, src->version_minor);
242 }
243 
244 static void
gst_rfb_src_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)245 gst_rfb_src_set_property (GObject * object, guint prop_id,
246     const GValue * value, GParamSpec * pspec)
247 {
248   GstRfbSrc *src = GST_RFB_SRC (object);
249 
250   switch (prop_id) {
251     case PROP_HOST:
252       src->host = g_value_dup_string (value);;
253       break;
254     case PROP_PORT:
255       src->port = g_value_get_int (value);
256       break;
257     case PROP_VERSION:
258       gst_rfb_property_set_version (src, g_value_dup_string (value));
259       break;
260     case PROP_PASSWORD:
261       g_free (src->decoder->password);
262       src->decoder->password = g_value_dup_string (value);
263       break;
264     case PROP_OFFSET_X:
265       src->decoder->offset_x = g_value_get_int (value);
266       break;
267     case PROP_OFFSET_Y:
268       src->decoder->offset_y = g_value_get_int (value);
269       break;
270     case PROP_WIDTH:
271       src->decoder->rect_width = g_value_get_int (value);
272       break;
273     case PROP_HEIGHT:
274       src->decoder->rect_height = g_value_get_int (value);
275       break;
276     case PROP_INCREMENTAL:
277       src->incremental_update = g_value_get_boolean (value);
278       break;
279     case PROP_USE_COPYRECT:
280       src->decoder->use_copyrect = g_value_get_boolean (value);
281       break;
282     case PROP_SHARED:
283       src->decoder->shared_flag = g_value_get_boolean (value);
284       break;
285     case PROP_VIEWONLY:
286       src->view_only = g_value_get_boolean (value);
287       break;
288     default:
289       break;
290   }
291 }
292 
293 static void
gst_rfb_src_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)294 gst_rfb_src_get_property (GObject * object, guint prop_id,
295     GValue * value, GParamSpec * pspec)
296 {
297   GstRfbSrc *src = GST_RFB_SRC (object);
298   gchar *version;
299 
300   switch (prop_id) {
301     case PROP_HOST:
302       g_value_set_string (value, src->host);
303       break;
304     case PROP_PORT:
305       g_value_set_int (value, src->port);
306       break;
307     case PROP_VERSION:
308       version = gst_rfb_property_get_version (src);
309       g_value_set_string (value, version);
310       g_free (version);
311       break;
312     case PROP_OFFSET_X:
313       g_value_set_int (value, src->decoder->offset_x);
314       break;
315     case PROP_OFFSET_Y:
316       g_value_set_int (value, src->decoder->offset_y);
317       break;
318     case PROP_WIDTH:
319       g_value_set_int (value, src->decoder->rect_width);
320       break;
321     case PROP_HEIGHT:
322       g_value_set_int (value, src->decoder->rect_height);
323       break;
324     case PROP_INCREMENTAL:
325       g_value_set_boolean (value, src->incremental_update);
326       break;
327     case PROP_USE_COPYRECT:
328       g_value_set_boolean (value, src->decoder->use_copyrect);
329       break;
330     case PROP_SHARED:
331       g_value_set_boolean (value, src->decoder->shared_flag);
332       break;
333     case PROP_VIEWONLY:
334       g_value_set_boolean (value, src->view_only);
335       break;
336     default:
337       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
338       break;
339   }
340 }
341 
342 static gboolean
gst_rfb_src_decide_allocation(GstBaseSrc * bsrc,GstQuery * query)343 gst_rfb_src_decide_allocation (GstBaseSrc * bsrc, GstQuery * query)
344 {
345   GstBufferPool *pool = NULL;
346   guint size, min = 1, max = 0;
347   GstStructure *config;
348   GstCaps *caps;
349   GstVideoInfo info;
350   gboolean ret;
351 
352   gst_query_parse_allocation (query, &caps, NULL);
353 
354   if (!caps || !gst_video_info_from_caps (&info, caps))
355     return FALSE;
356 
357   while (gst_query_get_n_allocation_pools (query) > 0) {
358     gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max);
359 
360     /* TODO We restrict to the exact size as we don't support strides or
361      * special padding */
362     if (size == info.size)
363       break;
364 
365     gst_query_remove_nth_allocation_pool (query, 0);
366     gst_object_unref (pool);
367     pool = NULL;
368   }
369 
370   if (pool == NULL) {
371     /* we did not get a pool, make one ourselves then */
372     pool = gst_video_buffer_pool_new ();
373     size = info.size;
374     min = 1;
375     max = 0;
376 
377     if (gst_query_get_n_allocation_pools (query) > 0)
378       gst_query_set_nth_allocation_pool (query, 0, pool, size, min, max);
379     else
380       gst_query_add_allocation_pool (query, pool, size, min, max);
381   }
382 
383   config = gst_buffer_pool_get_config (pool);
384   gst_buffer_pool_config_set_params (config, caps, size, min, max);
385 
386   ret = gst_buffer_pool_set_config (pool, config);
387   gst_object_unref (pool);
388 
389   return ret;
390 }
391 
392 static gboolean
gst_rfb_src_negotiate(GstBaseSrc * bsrc)393 gst_rfb_src_negotiate (GstBaseSrc * bsrc)
394 {
395   GstRfbSrc *src = GST_RFB_SRC (bsrc);
396   RfbDecoder *decoder;
397   GstCaps *caps;
398   GstVideoInfo vinfo;
399   GstVideoFormat vformat;
400   guint32 red_mask, green_mask, blue_mask;
401   gchar *stream_id = NULL;
402   GstEvent *stream_start = NULL;
403 
404   decoder = src->decoder;
405 
406   if (decoder->inited)
407     return TRUE;
408 
409   GST_DEBUG_OBJECT (src, "connecting to host %s on port %d",
410       src->host, src->port);
411   if (!rfb_decoder_connect_tcp (decoder, src->host, src->port)) {
412     if (decoder->error != NULL) {
413       GST_ELEMENT_ERROR (src, RESOURCE, READ,
414           ("Could not connect to VNC server %s on port %d: %s", src->host,
415               src->port, decoder->error->message), (NULL));
416     } else {
417       GST_ELEMENT_ERROR (src, RESOURCE, READ,
418           ("Could not connect to VNC server %s on port %d", src->host,
419               src->port), (NULL));
420     }
421     return FALSE;
422   }
423 
424   while (!decoder->inited) {
425     if (!rfb_decoder_iterate (decoder)) {
426       if (decoder->error != NULL) {
427         GST_ELEMENT_ERROR (src, RESOURCE, READ,
428             ("Failed to setup VNC connection to host %s on port %d: %s",
429                 src->host, src->port, decoder->error->message), (NULL));
430       } else {
431         GST_ELEMENT_ERROR (src, RESOURCE, READ,
432             ("Failed to setup VNC connection to host %s on port %d", src->host,
433                 src->port), (NULL));
434       }
435       return FALSE;
436     }
437   }
438 
439   stream_id = gst_pad_create_stream_id_printf (GST_BASE_SRC_PAD (bsrc),
440       GST_ELEMENT (src), "%s:%d", src->host, src->port);
441   stream_start = gst_event_new_stream_start (stream_id);
442   g_free (stream_id);
443   gst_pad_push_event (GST_BASE_SRC_PAD (bsrc), stream_start);
444 
445   decoder->rect_width =
446       (decoder->rect_width ? decoder->rect_width : decoder->width);
447   decoder->rect_height =
448       (decoder->rect_height ? decoder->rect_height : decoder->height);
449 
450   decoder->decoder_private = src;
451 
452   /* calculate some many used values */
453   decoder->bytespp = decoder->bpp / 8;
454   decoder->line_size = decoder->rect_width * decoder->bytespp;
455 
456   GST_DEBUG_OBJECT (src, "setting caps width to %d and height to %d",
457       decoder->rect_width, decoder->rect_height);
458 
459   red_mask = decoder->red_max << decoder->red_shift;
460   green_mask = decoder->green_max << decoder->green_shift;
461   blue_mask = decoder->blue_max << decoder->blue_shift;
462 
463   vformat = gst_video_format_from_masks (decoder->depth, decoder->bpp,
464       decoder->big_endian ? G_BIG_ENDIAN : G_LITTLE_ENDIAN,
465       red_mask, green_mask, blue_mask, 0);
466 
467   gst_video_info_init (&vinfo);
468 
469   gst_video_info_set_format (&vinfo, vformat, decoder->rect_width,
470       decoder->rect_height);
471 
472   decoder->frame = g_malloc (vinfo.size);
473   if (decoder->use_copyrect)
474     decoder->prev_frame = g_malloc (vinfo.size);
475 
476   caps = gst_video_info_to_caps (&vinfo);
477 
478   gst_base_src_set_caps (bsrc, caps);
479 
480   gst_caps_unref (caps);
481 
482   return TRUE;
483 }
484 
485 static gboolean
gst_rfb_src_stop(GstBaseSrc * bsrc)486 gst_rfb_src_stop (GstBaseSrc * bsrc)
487 {
488   GstRfbSrc *src = GST_RFB_SRC (bsrc);
489 
490   rfb_decoder_disconnect (src->decoder);
491 
492   if (src->decoder->frame) {
493     g_free (src->decoder->frame);
494     src->decoder->frame = NULL;
495   }
496 
497   if (src->decoder->prev_frame) {
498     g_free (src->decoder->prev_frame);
499     src->decoder->prev_frame = NULL;
500   }
501 
502   return TRUE;
503 }
504 
505 static GstFlowReturn
gst_rfb_src_fill(GstPushSrc * psrc,GstBuffer * outbuf)506 gst_rfb_src_fill (GstPushSrc * psrc, GstBuffer * outbuf)
507 {
508   GstRfbSrc *src = GST_RFB_SRC (psrc);
509   RfbDecoder *decoder = src->decoder;
510   GstMapInfo info;
511 
512   rfb_decoder_send_update_request (decoder, src->incremental_update,
513       decoder->offset_x, decoder->offset_y, decoder->rect_width,
514       decoder->rect_height);
515 
516   while (decoder->state != NULL) {
517     if (!rfb_decoder_iterate (decoder)) {
518       if (decoder->error != NULL) {
519         GST_ELEMENT_ERROR (src, RESOURCE, READ,
520             ("Error on VNC connection to host %s on port %d: %s",
521                 src->host, src->port, decoder->error->message), (NULL));
522       } else {
523         GST_ELEMENT_ERROR (src, RESOURCE, READ,
524             ("Error on setup VNC connection to host %s on port %d", src->host,
525                 src->port), (NULL));
526       }
527       return GST_FLOW_ERROR;
528     }
529   }
530 
531   if (!gst_buffer_map (outbuf, &info, GST_MAP_WRITE)) {
532     GST_ELEMENT_ERROR (src, RESOURCE, WRITE,
533         ("Could not map the output frame"), (NULL));
534     return GST_FLOW_ERROR;
535   }
536 
537   memcpy (info.data, decoder->frame, info.size);
538 
539   GST_BUFFER_PTS (outbuf) =
540       gst_clock_get_time (GST_ELEMENT_CLOCK (src)) -
541       GST_ELEMENT_CAST (src)->base_time;
542 
543   gst_buffer_unmap (outbuf, &info);
544 
545   return GST_FLOW_OK;
546 }
547 
548 static gboolean
gst_rfb_src_event(GstBaseSrc * bsrc,GstEvent * event)549 gst_rfb_src_event (GstBaseSrc * bsrc, GstEvent * event)
550 {
551   GstRfbSrc *src = GST_RFB_SRC (bsrc);
552   gdouble x, y;
553   gint button;
554   const GstStructure *structure;
555   const gchar *event_type;
556   gboolean key_event, key_press;
557 
558   key_event = FALSE;
559 
560   switch (GST_EVENT_TYPE (event)) {
561     case GST_EVENT_NAVIGATION:
562 
563       /* if in view_only mode ignore the navigation event */
564       if (src->view_only)
565         break;
566 
567       structure = gst_event_get_structure (event);
568       event_type = gst_structure_get_string (structure, "event");
569 
570       if (strcmp (event_type, "key-press") == 0) {
571         key_event = key_press = TRUE;
572       } else if (strcmp (event_type, "key-release") == 0) {
573         key_event = TRUE;
574         key_press = FALSE;
575       }
576 
577       if (key_event) {
578 #ifdef HAVE_X11
579         const gchar *key;
580         KeySym key_sym;
581 
582         key = gst_structure_get_string (structure, "key");
583         key_sym = XStringToKeysym (key);
584 
585         if (key_sym != NoSymbol)
586           rfb_decoder_send_key_event (src->decoder, key_sym, key_press);
587 #endif
588         break;
589       }
590 
591       gst_structure_get_double (structure, "pointer_x", &x);
592       gst_structure_get_double (structure, "pointer_y", &y);
593       gst_structure_get_int (structure, "button", &button);
594 
595       /* we need to take care of the offset's */
596       x += src->decoder->offset_x;
597       y += src->decoder->offset_y;
598 
599       if (strcmp (event_type, "mouse-move") == 0) {
600         GST_LOG_OBJECT (src, "sending mouse-move event "
601             "button_mask=%d, x=%d, y=%d", src->button_mask, (gint) x, (gint) y);
602         rfb_decoder_send_pointer_event (src->decoder, src->button_mask,
603             (gint) x, (gint) y);
604       } else if (strcmp (event_type, "mouse-button-release") == 0) {
605         src->button_mask &= ~(1 << (button - 1));
606         GST_LOG_OBJECT (src, "sending mouse-button-release event "
607             "button_mask=%d, x=%d, y=%d", src->button_mask, (gint) x, (gint) y);
608         rfb_decoder_send_pointer_event (src->decoder, src->button_mask,
609             (gint) x, (gint) y);
610       } else if (strcmp (event_type, "mouse-button-press") == 0) {
611         src->button_mask |= (1 << (button - 1));
612         GST_LOG_OBJECT (src, "sending mouse-button-press event "
613             "button_mask=%d, x=%d, y=%d", src->button_mask, (gint) x, (gint) y);
614         rfb_decoder_send_pointer_event (src->decoder, src->button_mask,
615             (gint) x, (gint) y);
616       }
617       break;
618     default:
619       break;
620   }
621 
622   return TRUE;
623 }
624 
625 static gboolean
gst_rfb_src_unlock(GstBaseSrc * bsrc)626 gst_rfb_src_unlock (GstBaseSrc * bsrc)
627 {
628   GstRfbSrc *src = GST_RFB_SRC (bsrc);
629   g_cancellable_cancel (src->decoder->cancellable);
630   return TRUE;
631 }
632 
633 static gboolean
plugin_init(GstPlugin * plugin)634 plugin_init (GstPlugin * plugin)
635 {
636   return GST_ELEMENT_REGISTER (rfbsrc, plugin);
637 }
638 
639 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
640     GST_VERSION_MINOR,
641     rfbsrc,
642     "Connects to a VNC server and decodes RFB stream",
643     plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
644