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