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