1 /*****************************************************************************
2 * remoteosd.c: remote osd over vnc filter module
3 *****************************************************************************
4 * Copyright (C) 2007-2008 Matthias Bauer
7 * Authors: Matthias Bauer <matthias dot bauer #_at_# gmx dot ch>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implid warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
24 /*****************************************************************************
25 * RemoteOSD uses the RFB-Protocol of VNC to display an On-Screen-Display
26 * menu generated by a streaming server as overlay for the streamed video.
28 * The streaming server that implements this is the ffnetdev plugin for VDR.
29 * VDR (VideoDiskRecorder) is an Linux based OpenSource harddisk recorder
31 * The VDR ffnetdev plugin emulates the hardware MPEG decoder and streams the
32 * video over the network instead of hardware video outputs.
33 * The OSD menu of VDR is offered with the RFB protocol to a VNC client.
35 * In fact this video-filter is a simple VNC client that could be also used to
36 * connect to a real VNC host.
37 * Only 8-bit color is supported at the moment.
38 * Using password protected VNC hosts is supported but not recommended, because
39 * you need to insert the used password in the plugin configuration page of
40 * VLC configuration in plain text and it's saved in plain text.
41 *****************************************************************************/
45 /*****************************************************************************
47 *****************************************************************************/
53 #include <vlc_common.h>
54 #include <vlc_plugin.h>
57 #include <vlc_filter.h>
58 #include <vlc_image.h>
61 #include <vlc_network.h>
62 #include <gcrypt.h> /* to encrypt password */
63 #include <vlc_gcrypt.h>
65 #include "remoteosd_rfbproto.h" /* type definitions of the RFB protocol for VNC */
67 /*****************************************************************************
69 *****************************************************************************/
70 #define READ_BUFFER_SIZE 1000000
72 #define RMTOSD_HOST_TEXT N_("VNC Host")
73 #define RMTOSD_HOST_LONGTEXT N_( \
74 "VNC hostname or IP address." )
76 #define RMTOSD_PORT_TEXT N_("VNC Port")
77 #define RMTOSD_PORT_LONGTEXT N_( \
80 #define RMTOSD_PASSWORD_TEXT N_("VNC Password")
81 #define RMTOSD_PASSWORD_LONGTEXT N_( \
84 #define RMTOSD_UPDATE_TEXT N_("VNC poll interval" )
85 #define RMTOSD_UPDATE_LONGTEXT N_( \
86 "In this interval an update from VNC is requested, default every 300 ms. ")
88 #define RMTOSD_POLL_TEXT N_("VNC polling")
89 #define RMTOSD_POLL_LONGTEXT N_( \
90 "Activate VNC polling. Do NOT activate for use as VDR ffnetdev client." )
92 #define RMTOSD_MOUSE_TEXT N_("Mouse events")
93 #define RMTOSD_MOUSE_LONGTEXT N_( \
94 "Send mouse events to VNC host. Not needed for use as VDR ffnetdev client." )
96 #define RMTOSD_KEYS_TEXT N_("Key events")
97 #define RMTOSD_KEYS_LONGTEXT N_( \
98 "Send key events to VNC host." )
100 #define RMTOSD_ALPHA_TEXT N_("Alpha transparency value (default 255)")
101 #define RMTOSD_ALPHA_LONGTEXT N_( \
102 "The transparency of the OSD VNC can be changed by giving a value " \
103 "between 0 and 255. A lower value specifies more transparency a higher " \
104 "means less transparency. The default is being not transparent " \
105 "(value 255) the minimum is fully transparent (value 0)." )
107 #define RMTOSD_CFG "rmtosd-"
109 #define RMTOSD_UPDATE_MIN 200
110 #define RMTOSD_UPDATE_DEFAULT 1000
111 #define RMTOSD_UPDATE_MAX 300
113 static int CreateFilter ( vlc_object_t
* );
114 static void DestroyFilter( vlc_object_t
* );
117 set_description( N_("Remote-OSD over VNC") )
118 set_capability( "sub filter", 100 )
119 set_shortname( N_("Remote-OSD") )
120 set_category( CAT_VIDEO
)
121 set_subcategory( SUBCAT_VIDEO_SUBPIC
)
122 add_shortcut( "rmtosd" )
123 set_callbacks( CreateFilter
, DestroyFilter
)
125 add_string( RMTOSD_CFG
"host", "myvdr", NULL
, RMTOSD_HOST_TEXT
,
126 RMTOSD_HOST_LONGTEXT
, false )
127 add_integer_with_range( RMTOSD_CFG
"port", 20001, 1, 0xFFFF, NULL
,
128 RMTOSD_PORT_TEXT
, RMTOSD_PORT_LONGTEXT
, false )
129 add_password( RMTOSD_CFG
"password", "", NULL
, RMTOSD_PASSWORD_TEXT
,
130 RMTOSD_PASSWORD_LONGTEXT
, false )
131 add_integer_with_range( RMTOSD_CFG
"update", RMTOSD_UPDATE_DEFAULT
,
132 RMTOSD_UPDATE_MIN
, RMTOSD_UPDATE_MAX
, NULL
, RMTOSD_UPDATE_TEXT
,
133 RMTOSD_UPDATE_LONGTEXT
, true )
134 add_bool( RMTOSD_CFG
"vnc-polling", false, NULL
,
135 RMTOSD_POLL_TEXT
, RMTOSD_POLL_LONGTEXT
, false )
136 add_bool( RMTOSD_CFG
"mouse-events", false, NULL
,
137 RMTOSD_MOUSE_TEXT
, RMTOSD_MOUSE_LONGTEXT
, false )
138 add_bool( RMTOSD_CFG
"key-events", false, NULL
,
139 RMTOSD_KEYS_TEXT
, RMTOSD_KEYS_LONGTEXT
, false )
140 add_integer_with_range( RMTOSD_CFG
"alpha", 255, 0, 255, NULL
,
141 RMTOSD_ALPHA_TEXT
, RMTOSD_ALPHA_LONGTEXT
, true )
146 /*****************************************************************************
148 *****************************************************************************/
149 #define CHALLENGESIZE 16
150 #define MAX_VNC_SERVER_NAME_LENGTH 255
152 /* subfilter functions */
153 static subpicture_t
*Filter( filter_t
*, mtime_t
);
155 static int MouseEvent( filter_t
*,
158 const video_format_t
* );
160 static int KeyEvent( vlc_object_t
*p_this
, char const *psz_var
,
161 vlc_value_t oldval
, vlc_value_t newval
, void *p_data
);
163 static void stop_osdvnc ( filter_t
*p_filter
);
165 static void* vnc_worker_thread ( vlc_object_t
*p_thread_obj
);
167 static void* update_request_thread( vlc_object_t
*p_thread_obj
);
169 static bool open_vnc_connection ( filter_t
*p_filter
);
171 static bool handshaking ( filter_t
*p_filter
);
173 static bool process_server_message ( filter_t
*p_filter
,
174 rfbServerToClientMsg
*msg
);
176 static inline void rgb_to_yuv( uint8_t *y
, uint8_t *u
, uint8_t *v
,
177 int r
, int g
, int b
);
179 static inline bool fill_rect( filter_sys_t
* p_sys
,
180 uint16_t i_x
, uint16_t i_y
,
181 uint16_t i_w
, uint16_t i_h
,
183 static inline bool copy_rect( filter_sys_t
* p_sys
,
184 uint16_t i_x
, uint16_t i_y
,
185 uint16_t i_w
, uint16_t i_h
,
186 uint16_t i_sx
, uint16_t i_sy
);
189 static inline bool raw_line( filter_sys_t
* p_sys
,
190 uint16_t i_x
, uint16_t i_y
,
193 static void vnc_encrypt_bytes( unsigned char *bytes
, char *passwd
);
196 /*****************************************************************************
198 *****************************************************************************/
200 /*****************************************************************************
202 *****************************************************************************/
205 bool b_need_update
; /* VNC picture is updated, do update the OSD*/
206 mtime_t i_vnc_poll_interval
; /* Update the OSD menu every n ms */
208 uint8_t i_alpha
; /* alpha transparency value */
210 char *psz_host
; /* VNC host */
213 char *psz_passwd
; /* VNC password */
215 bool b_vnc_poll
; /* Activate VNC polling ? */
216 bool b_vnc_mouse_events
; /* Send MouseEvents ? */
217 bool b_vnc_key_events
; /* Send KeyEvents ? */
219 bool b_connection_active
; /* Handshaking finished ? */
221 vlc_mutex_t lock
; /* To lock for read/write on picture */
223 picture_t
*p_pic
; /* The picture with OSD data from VNC */
225 vout_thread_t
*p_vout
; /* Pointer to video-out thread */
227 int i_socket
; /* Socket used for VNC */
229 uint16_t i_vnc_width
; /* The with of the VNC screen */
230 uint16_t i_vnc_height
; /* The height of the VNC screen */
231 uint32_t i_vnc_pixels
; /* The pixels of the VNC screen */
233 bool b_alpha_from_vnc
; /* Special ffnetdev alpha feature enabled ? */
235 char read_buffer
[READ_BUFFER_SIZE
];
239 vlc_object_t
* p_worker_thread
;
241 uint8_t ar_color_table_yuv
[256][4];
244 /*****************************************************************************
245 * CreateFilter: Create the filter and open the definition file
246 *****************************************************************************/
247 static int CreateFilter ( vlc_object_t
*p_this
)
249 filter_t
*p_filter
= (filter_t
*)p_this
;
250 filter_sys_t
*p_sys
= NULL
;
252 msg_Dbg( p_filter
, "Creating vnc osd filter..." );
254 p_filter
->p_sys
= p_sys
= calloc( 1, sizeof(*p_sys
) );
255 if( !p_filter
->p_sys
)
258 /* Populating struct */
259 vlc_mutex_init( &p_sys
->lock
);
260 p_sys
->b_continue
= true;
261 p_sys
->i_socket
= -1;
264 p_sys
->psz_host
= var_CreateGetString( p_this
, RMTOSD_CFG
"host" );
265 if( EMPTY_STR(p_sys
->psz_host
) )
267 msg_Err( p_filter
, "unable to get vnc host" );
271 p_sys
->psz_passwd
= var_CreateGetString( p_this
, RMTOSD_CFG
"password" );
272 if( !p_sys
->psz_passwd
)
274 msg_Err( p_filter
, "unable to get vnc password" );
278 p_sys
->i_port
= var_CreateGetIntegerCommand( p_this
, RMTOSD_CFG
"port" );
280 p_sys
->i_alpha
= var_CreateGetIntegerCommand( p_this
, RMTOSD_CFG
"alpha" );
282 /* in milliseconds, 0 disables polling, should not be lower than 100 */
283 p_sys
->i_vnc_poll_interval
= var_CreateGetIntegerCommand( p_this
,
284 RMTOSD_CFG
"update" );
285 if ( p_sys
->i_vnc_poll_interval
< 100)
287 p_sys
->i_vnc_poll_interval
= 100;
290 for ( int i
= 0; i
< 256; i
++ )
292 p_sys
->ar_color_table_yuv
[i
][0] = 255;
293 p_sys
->ar_color_table_yuv
[i
][1] = 255;
294 p_sys
->ar_color_table_yuv
[i
][2] = 255;
295 p_sys
->ar_color_table_yuv
[i
][3] = 255;
298 p_sys
->b_vnc_poll
= var_CreateGetBoolCommand( p_this
,
299 RMTOSD_CFG
"vnc-polling" );
300 p_sys
->b_vnc_mouse_events
= var_CreateGetBoolCommand( p_this
,
301 RMTOSD_CFG
"mouse-events" );
302 p_sys
->b_vnc_key_events
= var_CreateGetBoolCommand( p_this
,
303 RMTOSD_CFG
"key-events" );
305 /* Keep track of OSD Events */
306 p_sys
->b_need_update
= false;
308 /* Attach subpicture filter callback */
309 p_filter
->pf_sub_filter
= Filter
;
310 p_filter
->pf_sub_mouse
= MouseEvent
;
312 p_sys
->p_vout
= vlc_object_find( p_this
, VLC_OBJECT_VOUT
, FIND_PARENT
);
316 var_AddCallback( p_sys
->p_vout
->p_libvlc
, "key-pressed",
320 es_format_Init( &p_filter
->fmt_out
, SPU_ES
, VLC_CODEC_SPU
);
321 p_filter
->fmt_out
.i_priority
= 0;
325 /* create the vnc worker thread */
326 p_sys
->p_worker_thread
= vlc_object_create( p_this
,
327 sizeof( vlc_object_t
) );
328 vlc_object_attach( p_sys
->p_worker_thread
, p_this
);
329 if( vlc_thread_create( p_sys
->p_worker_thread
, "vnc worker thread",
330 vnc_worker_thread
, VLC_THREAD_PRIORITY_LOW
) )
332 vlc_object_release( p_sys
->p_worker_thread
);
333 msg_Err( p_filter
, "cannot spawn vnc message reader thread" );
337 msg_Dbg( p_filter
, "osdvnc filter started" );
342 msg_Err( p_filter
, "osdvnc filter discarded" );
344 stop_osdvnc( p_filter
);
346 vlc_mutex_destroy( &p_sys
->lock
);
347 free( p_sys
->psz_host
);
348 free( p_sys
->psz_passwd
);
354 /*****************************************************************************
355 * DestroyFilter: Make a clean exit of this plugin
356 *****************************************************************************/
357 static void DestroyFilter( vlc_object_t
*p_this
)
359 filter_t
*p_filter
= (filter_t
*)p_this
;
360 filter_sys_t
*p_sys
= p_filter
->p_sys
;
362 msg_Dbg( p_filter
, "DestroyFilter called." );
364 stop_osdvnc( p_filter
);
368 var_DelCallback( p_sys
->p_vout
->p_libvlc
, "key-pressed",
371 vlc_object_release( p_sys
->p_vout
);
374 var_Destroy( p_this
, RMTOSD_CFG
"host" );
375 var_Destroy( p_this
, RMTOSD_CFG
"port" );
376 var_Destroy( p_this
, RMTOSD_CFG
"password" );
377 var_Destroy( p_this
, RMTOSD_CFG
"update" );
378 var_Destroy( p_this
, RMTOSD_CFG
"vnc-polling" );
379 var_Destroy( p_this
, RMTOSD_CFG
"mouse-events" );
380 var_Destroy( p_this
, RMTOSD_CFG
"key-events" );
381 var_Destroy( p_this
, RMTOSD_CFG
"alpha" );
383 vlc_mutex_destroy( &p_sys
->lock
);
384 free( p_sys
->psz_host
);
385 free( p_sys
->psz_passwd
);
389 static void stop_osdvnc ( filter_t
*p_filter
)
391 filter_sys_t
*p_sys
= p_filter
->p_sys
;
393 /* It will unlock socket reading */
394 vlc_object_kill( p_filter
);
397 if( p_sys
->p_worker_thread
)
399 msg_Dbg( p_filter
, "joining worker_thread" );
400 vlc_object_kill( p_sys
->p_worker_thread
);
401 vlc_thread_join( p_sys
->p_worker_thread
);
402 vlc_object_release( p_sys
->p_worker_thread
);
403 msg_Dbg( p_filter
, "released worker_thread" );
406 msg_Dbg( p_filter
, "osdvnc stopped" );
409 static bool read_exact( filter_t
*p_filter
,
414 return i_bytes
== net_Read( p_filter
, i_socket
, NULL
,
415 (unsigned char*)p_readbuf
,
420 static bool write_exact( filter_t
*p_filter
,
425 return i_bytes
== net_Write( p_filter
, i_socket
, NULL
,
426 (unsigned char*)p_writebuf
, i_bytes
);
429 static bool open_vnc_connection ( filter_t
*p_filter
)
431 filter_sys_t
*p_sys
= p_filter
->p_sys
;
433 msg_Dbg( p_filter
, "Open socket to vnc server on %s:%u.",
434 p_sys
->psz_host
, p_sys
->i_port
);
436 p_sys
->i_socket
= net_ConnectTCP( p_filter
, p_sys
->psz_host
, p_sys
->i_port
);
438 if( p_sys
->i_socket
< 0 )
440 msg_Err( p_filter
, "Could not open socket" );
444 msg_Dbg( p_filter
, "socket is open." );
449 static bool handshaking ( filter_t
*p_filter
)
451 filter_sys_t
*p_sys
= p_filter
->p_sys
;
453 msg_Dbg( p_filter
, "Reading protocol version" );
455 rfbProtocolVersionMsg pv
;
456 if ( !read_exact( p_filter
, p_sys
->i_socket
, pv
,
457 sz_rfbProtocolVersionMsg
) )
459 msg_Err( p_filter
, "Could not read version message" );
462 pv
[sz_rfbProtocolVersionMsg
] = '\0'; /* pv size is sz_rfbProtocolVersionMsg+1 */
464 msg_Dbg( p_filter
, "Server version is %s", pv
);
466 strncpy(pv
, "RFB 003.003\n", sz_rfbProtocolVersionMsg
);
468 if( !write_exact(p_filter
, p_sys
->i_socket
, pv
,
469 sz_rfbProtocolVersionMsg
) )
471 msg_Err( p_filter
, "Could not write version message" );
475 msg_Dbg( p_filter
, "Reading authentication scheme" );
476 uint32_t i_authScheme
;
477 if( !read_exact( p_filter
, p_sys
->i_socket
, (char*)&i_authScheme
, 4 ) )
479 msg_Err( p_filter
, "Could not read authentication scheme" );
482 i_authScheme
= htonl(i_authScheme
);
484 msg_Dbg( p_filter
, "Authentication scheme = %x", i_authScheme
);
485 if ( i_authScheme
== rfbConnFailed
)
487 msg_Err( p_filter
, "Connection rejected by server" );
490 if (i_authScheme
== rfbVncAuth
)
492 unsigned char challenge
[CHALLENGESIZE
];
493 if ( !read_exact( p_filter
, p_sys
->i_socket
,
494 (char*)challenge
, CHALLENGESIZE
) )
496 msg_Err( p_filter
, "Could not read password challenge" );
500 vnc_encrypt_bytes( challenge
, p_sys
->psz_passwd
);
502 if( !write_exact(p_filter
, p_sys
->i_socket
,
503 (char*)challenge
, CHALLENGESIZE
) )
505 msg_Err( p_filter
, "Could not write password" );
508 uint32_t i_authResult
;
509 if( !read_exact( p_filter
, p_sys
->i_socket
, (char*)&i_authResult
, 4 ) )
511 msg_Err( p_filter
, "Could not read authentication result" );
514 i_authResult
= htonl(i_authResult
);
515 if (i_authResult
!= rfbVncAuthOK
)
517 msg_Err( p_filter
, "VNC authentication failed" );
522 msg_Dbg( p_filter
, "Writing client init message" );
525 if( !write_exact( p_filter
, p_sys
->i_socket
,
526 (char*)&ci
, sz_rfbClientInitMsg
) )
528 msg_Err( p_filter
, "Could not write client init message" );
532 msg_Dbg( p_filter
, "Reading server init message" );
534 if( !read_exact( p_filter
, p_sys
->i_socket
,
535 (char*)&si
, sz_rfbServerInitMsg
) )
537 msg_Err( p_filter
, "Could not read server init message" );
540 si
.framebufferWidth
= htons(si
.framebufferWidth
);
541 si
.framebufferHeight
= htons(si
.framebufferHeight
);
542 si
.format
.redMax
= htons(si
.format
.redMax
);
543 si
.format
.greenMax
= htons(si
.format
.greenMax
);
544 si
.format
.blueMax
= htons(si
.format
.blueMax
);
546 p_sys
->i_vnc_width
= si
.framebufferWidth
;
547 p_sys
->i_vnc_height
= si
.framebufferHeight
;
549 msg_Dbg( p_filter
, "Servers preferred pixelformat: "
550 "%ux%u, R(%u),G(%u),B(%u), %u bit, depht=%u, %s",
552 si
.framebufferHeight
,
556 si
.format
.bitsPerPixel
,
558 si
.format
.trueColour
? "TrueColor" : "Not-TrueColor");
560 uint32_t i_nameLength
= htonl(si
.nameLength
);
561 if( i_nameLength
> MAX_VNC_SERVER_NAME_LENGTH
)
563 msg_Err( p_filter
, "Server name too long" );
566 char s_ServerName
[MAX_VNC_SERVER_NAME_LENGTH
+1];
568 msg_Dbg( p_filter
, "Reading server name with size = %u", i_nameLength
);
569 if( !read_exact( p_filter
, p_sys
->i_socket
, s_ServerName
, i_nameLength
) )
571 msg_Err( p_filter
, "Could not read server name" );
574 s_ServerName
[i_nameLength
] = '\0';
576 if( strcmp( s_ServerName
, "VDR-OSD") == 0 )
578 msg_Dbg( p_filter
, "Server is a VDR" );
579 p_sys
->b_alpha_from_vnc
= true;
583 msg_Dbg( p_filter
, "Server is a normal VNC" );
584 p_sys
->b_alpha_from_vnc
= false;
588 msg_Dbg( p_filter
, "Server init message read properly" );
589 msg_Dbg( p_filter
, "Server name is %s", s_ServerName
);
591 msg_Dbg( p_filter
, "Writing SetPixelFormat message" );
593 rfbSetPixelFormatMsg sp
;
594 sp
.type
= rfbSetPixelFormat
;
595 sp
.pad1
= sp
.pad2
= 0;
596 sp
.format
.bitsPerPixel
= 8;
597 sp
.format
.depth
= 8 ;
598 sp
.format
.bigEndian
= 1;
599 sp
.format
.trueColour
= 0;
600 sp
.format
.redMax
= htons(31);
601 sp
.format
.greenMax
= htons(31);
602 sp
.format
.blueMax
= htons(31);
603 sp
.format
.redShift
= 10;
604 sp
.format
.greenShift
= 5;
605 sp
.format
.blueShift
= 0;
606 sp
.format
.pad1
= sp
.format
.pad2
= 0;
608 if( !write_exact( p_filter
, p_sys
->i_socket
,
609 (char*)&sp
, sz_rfbSetPixelFormatMsg
) )
611 msg_Err( p_filter
, "Could not write SetPixelFormat message" );
615 msg_Dbg( p_filter
, "Writing SetEncodings message" );
617 rfbSetEncodingsMsg se
;
618 se
.type
= rfbSetEncodings
;
620 se
.nEncodings
= htons( p_sys
->b_alpha_from_vnc
? 3 : 2 );
622 if( !write_exact( p_filter
, p_sys
->i_socket
,
623 (char*)&se
, sz_rfbSetEncodingsMsg
) )
625 msg_Err( p_filter
, "Could not write SetEncodings message begin" );
631 msg_Dbg( p_filter
, "Writing SetEncodings rfbEncodingCopyRect" );
632 i_encoding
= htonl(rfbEncodingCopyRect
);
633 if( !write_exact( p_filter
, p_sys
->i_socket
, (char*)&i_encoding
, 4) )
635 msg_Err( p_filter
, "Could not write encoding type rfbEncodingCopyRect." );
639 msg_Dbg( p_filter
, "Writing SetEncodings rfbEncodingRRE" );
640 i_encoding
= htonl(rfbEncodingRRE
);
641 if( !write_exact(p_filter
, p_sys
->i_socket
, (char*)&i_encoding
, 4) )
643 msg_Err( p_filter
, "Could not write encoding type rfbEncodingRRE." );
647 if( p_sys
->b_alpha_from_vnc
)
649 msg_Dbg( p_filter
, "Writing SetEncodings rfbEncSpecialUseAlpha" );
650 i_encoding
= 0x00F0FFFF; /* rfbEncSpecialUseAlpha is 0xFFFFF000
651 * before we swap it */
652 if( !write_exact(p_filter
, p_sys
->i_socket
, (char*)&i_encoding
, 4) )
654 msg_Err( p_filter
, "Could not write encoding type rfbEncSpecialUseAlpha." );
662 static void* vnc_worker_thread( vlc_object_t
*p_thread_obj
)
664 filter_t
* p_filter
= (filter_t
*)(p_thread_obj
->p_parent
);
665 filter_sys_t
*p_sys
= p_filter
->p_sys
;
666 vlc_object_t
*p_update_request_thread
;
667 int canc
= vlc_savecancel ();
669 msg_Dbg( p_filter
, "VNC worker thread started" );
671 if( !open_vnc_connection ( p_filter
) )
673 msg_Err( p_filter
, "Could not connect to vnc host" );
677 if( !handshaking ( p_filter
) )
679 msg_Err( p_filter
, "Error occured while handshaking vnc host" );
683 p_sys
->b_connection_active
= true; /* to enable sending key
684 * and mouse events to host */
686 /* Create an empty picture for VNC the data */
687 vlc_mutex_lock( &p_sys
->lock
);
688 p_sys
->p_pic
= picture_New( VLC_CODEC_YUVA
,
689 p_sys
->i_vnc_width
, p_sys
->i_vnc_height
, 1, 1 );
692 vlc_mutex_unlock( &p_sys
->lock
);
695 p_sys
->i_vnc_pixels
= p_sys
->i_vnc_width
* p_sys
->i_vnc_height
;
697 vlc_mutex_unlock( &p_sys
->lock
);
699 /* create the update request thread */
700 p_update_request_thread
= vlc_object_create( p_filter
,
701 sizeof( vlc_object_t
) );
702 vlc_object_attach( p_update_request_thread
, p_filter
);
703 if( vlc_thread_create( p_update_request_thread
,
704 "vnc update request thread",
705 update_request_thread
, VLC_THREAD_PRIORITY_LOW
) )
707 vlc_object_release( p_update_request_thread
);
708 msg_Err( p_filter
, "cannot spawn vnc update request thread" );
712 /* connection is initialized, now read and handle server messages */
713 while( vlc_object_alive( p_thread_obj
) )
715 rfbServerToClientMsg msg
;
718 memset( &msg
, 0, sizeof(msg
) );
720 if( !read_exact(p_filter
, p_sys
->i_socket
, (char*)&msg
, 1 ) )
722 msg_Err( p_filter
, "Error while waiting for next server message");
727 case rfbFramebufferUpdate
:
728 i_msgSize
= sz_rfbFramebufferUpdateMsg
;
730 case rfbSetColourMapEntries
:
731 i_msgSize
= sz_rfbSetColourMapEntriesMsg
;
734 i_msgSize
= sz_rfbBellMsg
;
736 case rfbServerCutText
:
737 i_msgSize
= sz_rfbServerCutTextMsg
;
739 case rfbReSizeFrameBuffer
:
740 i_msgSize
= sz_rfbReSizeFrameBufferMsg
;
744 msg_Err( p_filter
, "Invalid message %u received", msg
.type
);
751 if( --i_msgSize
> 0 )
753 if ( !read_exact( p_filter
, p_sys
->i_socket
,
754 ((char*)&msg
)+1, i_msgSize
) )
756 msg_Err( p_filter
, "Error while reading message of type %u",
761 process_server_message( p_filter
, &msg
);
764 msg_Dbg( p_filter
, "joining update_request_thread" );
765 vlc_object_kill( p_update_request_thread
);
766 vlc_thread_join( p_update_request_thread
);
767 vlc_object_release( p_update_request_thread
);
768 msg_Dbg( p_filter
, "released update_request_thread" );
772 vlc_mutex_lock( &p_sys
->lock
);
773 p_sys
->b_connection_active
= false;
775 if (p_sys
->i_socket
>= 0)
776 net_Close(p_sys
->i_socket
);
779 picture_Release( p_sys
->p_pic
);
781 /* It will hide the subtitle */
782 p_sys
->b_continue
= false;
783 p_sys
->b_need_update
= true;
784 vlc_mutex_unlock( &p_sys
->lock
);
786 msg_Dbg( p_filter
, "VNC message reader thread ended" );
787 vlc_restorecancel (canc
);
791 static void* update_request_thread( vlc_object_t
*p_thread_obj
)
793 filter_t
* p_filter
= (filter_t
*)(p_thread_obj
->p_parent
);
794 filter_sys_t
*p_sys
= p_filter
->p_sys
;
795 int canc
= vlc_savecancel ();
797 msg_Dbg( p_filter
, "VNC update request thread started" );
799 rfbFramebufferUpdateRequestMsg udr
;
800 udr
.type
= rfbFramebufferUpdateRequest
;
804 udr
.w
= htons(p_sys
->i_vnc_width
);
805 udr
.h
= htons(p_sys
->i_vnc_height
);
807 if( write_exact(p_filter
, p_sys
->i_socket
, (char*)&udr
,
808 sz_rfbFramebufferUpdateRequestMsg
) == false)
810 msg_Err( p_filter
, "Could not write rfbFramebufferUpdateRequestMsg." );
811 p_sys
->b_continue
= false;
816 mtime_t i_poll_interval_microsec
= p_sys
->i_vnc_poll_interval
* 1000;
818 if( p_sys
->b_vnc_poll
)
820 while( vlc_object_alive( p_thread_obj
) )
822 msleep( i_poll_interval_microsec
);
823 if( write_exact(p_filter
, p_sys
->i_socket
, (char*)&udr
,
824 sz_rfbFramebufferUpdateRequestMsg
) == false)
826 msg_Err( p_filter
, "Could not write rfbFramebufferUpdateRequestMsg." );
830 p_sys
->b_continue
= false;
834 msg_Dbg( p_filter
, "VNC polling disabled." );
837 msg_Dbg( p_filter
, "VNC update request thread ended" );
838 vlc_restorecancel (canc
);
842 static bool process_server_message ( filter_t
*p_filter
,
843 rfbServerToClientMsg
*msg
)
845 filter_sys_t
*p_sys
= p_filter
->p_sys
;
849 case rfbFramebufferUpdate
:
851 msg
->fu
.nRects
= htons(msg
->fu
.nRects
);
852 rfbFramebufferUpdateRectHeader hdr
;
854 for (int i_rect
= 0; i_rect
< msg
->fu
.nRects
; i_rect
++)
856 if (!read_exact(p_filter
, p_sys
->i_socket
, (char*)&hdr
,
857 sz_rfbFramebufferUpdateRectHeader
) )
859 msg_Err( p_filter
, "Could not read FrameBufferUpdate header" );
862 hdr
.r
.x
= htons(hdr
.r
.x
);
863 hdr
.r
.y
= htons(hdr
.r
.y
);
864 hdr
.r
.w
= htons(hdr
.r
.w
);
865 hdr
.r
.h
= htons(hdr
.r
.h
);
866 hdr
.encoding
= htonl(hdr
.encoding
);
868 switch (hdr
.encoding
)
873 for (i_line
= 0; i_line
< hdr
.r
.h
; i_line
++)
875 if ( !read_exact( p_filter
, p_sys
->i_socket
,
876 p_sys
->read_buffer
, hdr
.r
.w
) )
879 "Could not read FrameBufferUpdate line data" );
882 vlc_mutex_lock( &p_sys
->lock
);
883 if ( !raw_line( p_sys
, hdr
.r
.x
,
887 msg_Err( p_filter
, "raw_line failed." );
888 vlc_mutex_unlock( &p_sys
->lock
);
891 vlc_mutex_unlock( &p_sys
->lock
);
896 case rfbEncodingCopyRect
:
900 if ( !read_exact( p_filter
, p_sys
->i_socket
,
904 msg_Err( p_filter
, "Could not read rfbCopyRect" );
907 rect
.srcX
= htons( rect
.srcX
);
908 rect
.srcY
= htons( rect
.srcY
);
910 vlc_mutex_lock( &p_sys
->lock
);
911 if ( !copy_rect( p_sys
,
914 rect
.srcX
, rect
.srcY
) )
916 msg_Err( p_filter
, "copy_rect failed." );
917 vlc_mutex_unlock( &p_sys
->lock
);
920 vlc_mutex_unlock( &p_sys
->lock
);
927 if ( !read_exact( p_filter
, p_sys
->i_socket
,
931 msg_Err( p_filter
, "Could not read rfbRREHeader" );
935 if ( !read_exact(p_filter
, p_sys
->i_socket
,
936 (char*)&i_pixcolor
, 1 ) )
938 msg_Err( p_filter
, "Could not read RRE pixcolor" );
942 vlc_mutex_lock( &p_sys
->lock
);
943 if ( !fill_rect( p_sys
,
948 msg_Err( p_filter
, "main fill_rect failed." );
949 vlc_mutex_unlock( &p_sys
->lock
);
952 vlc_mutex_unlock( &p_sys
->lock
);
954 rrehdr
.nSubrects
= htonl(rrehdr
.nSubrects
);
956 int i_datasize
= rrehdr
.nSubrects
*
957 ( sizeof(i_pixcolor
) + sz_rfbRectangle
) ;
958 if ( i_datasize
> READ_BUFFER_SIZE
)
960 msg_Err( p_filter
, "Buffer too small, "
961 "need %u bytes", i_datasize
);
964 if ( !read_exact( p_filter
, p_sys
->i_socket
,
965 p_sys
->read_buffer
, i_datasize
) )
968 "Could not read RRE subrect data" );
973 rfbRectangle
* p_subrect
;
975 vlc_mutex_lock( &p_sys
->lock
);
977 i_subrect
< rrehdr
.nSubrects
; i_subrect
++)
979 i_pixcolor
= p_sys
->read_buffer
[i_offset
];
980 i_offset
+= sizeof(i_pixcolor
);
982 (rfbRectangle
*)(p_sys
->read_buffer
+ i_offset
);
983 i_offset
+= sz_rfbRectangle
;
985 if (!fill_rect( p_sys
,
986 htons(p_subrect
->x
) + hdr
.r
.x
,
987 htons(p_subrect
->y
) + hdr
.r
.y
,
993 "subrect %u fill_rect failed.", i_subrect
);
994 vlc_mutex_unlock( &p_sys
->lock
);
998 vlc_mutex_unlock( &p_sys
->lock
);
1005 vlc_mutex_lock( &p_sys
->lock
);
1006 p_sys
->b_need_update
= true;
1007 vlc_mutex_unlock( &p_sys
->lock
);
1011 case rfbSetColourMapEntries
:
1013 msg
->scme
.nColours
= htons(msg
->scme
.nColours
);
1014 msg
->scme
.firstColour
= htons(msg
->scme
.firstColour
);
1016 if ( p_sys
->b_alpha_from_vnc
== true )
1018 i_datasize
= 2 * msg
->scme
.nColours
* 4;
1022 i_datasize
= 2 * msg
->scme
.nColours
* 3;
1024 if ( i_datasize
> READ_BUFFER_SIZE
)
1026 msg_Err( p_filter
, "Buffer too small, need %u bytes",
1031 if ( !read_exact( p_filter
, p_sys
->i_socket
,
1032 p_sys
->read_buffer
, i_datasize
) )
1034 msg_Err( p_filter
, "Could not read color map data" );
1038 uint8_t i_red
, i_green
, i_blue
, i_alpha
, i_color_index
;
1039 uint16_t i_offset
= 0;
1042 for (int i
= 0; i
< msg
->scme
.nColours
; i
++)
1044 i_color_index
= i
+msg
->scme
.firstColour
;
1045 if ( p_sys
->b_alpha_from_vnc
== true )
1047 i_alpha
= p_sys
->read_buffer
[i_offset
];
1050 i_red
= p_sys
->read_buffer
[i_offset
];
1052 i_green
= p_sys
->read_buffer
[i_offset
];
1054 i_blue
= p_sys
->read_buffer
[i_offset
];
1056 rgb_to_yuv( &p_sys
->ar_color_table_yuv
[i_color_index
][0],
1057 &p_sys
->ar_color_table_yuv
[i_color_index
][1],
1058 &p_sys
->ar_color_table_yuv
[i_color_index
][2],
1062 p_sys
->ar_color_table_yuv
[i
][3] = i_alpha
;
1068 msg_Err( p_filter
, "rfbBell received" );
1071 case rfbServerCutText
:
1072 msg
->sct
.length
= htons(msg
->sct
.length
);
1073 if ( msg
->sct
.length
> READ_BUFFER_SIZE
)
1075 msg_Err( p_filter
, "Buffer too small, need %u bytes", msg
->sct
.length
);
1078 if ( !read_exact(p_filter
, p_sys
->i_socket
,
1079 p_sys
->read_buffer
, msg
->sct
.length
) )
1081 msg_Err( p_filter
, "Could not read Reading rfbServerCutText data" );
1086 case rfbReSizeFrameBuffer
:
1087 msg_Err( p_filter
, "Reading rfbReSizeFrameBuffer not implemented" );
1091 msg_Err( p_filter
, "Invalid message %u received", msg
->type
);
1097 /****************************************************************************
1098 * Filter: the whole thing
1099 ****************************************************************************
1100 * This function outputs subpictures at regular time intervals.
1101 ****************************************************************************/
1102 static subpicture_t
*Filter( filter_t
*p_filter
, mtime_t date
)
1104 filter_sys_t
*p_sys
= p_filter
->p_sys
;
1105 subpicture_t
*p_spu
;
1106 subpicture_region_t
*p_region
;
1110 if( !p_sys
->b_need_update
)
1115 vlc_mutex_lock( &p_sys
->lock
);
1117 p_pic
= p_sys
->p_pic
;
1121 vlc_mutex_unlock( &p_sys
->lock
);
1125 /* Allocate the subpicture internal data. */
1126 p_spu
= filter_NewSubpicture( p_filter
);
1129 vlc_mutex_unlock( &p_sys
->lock
);
1133 p_spu
->b_absolute
= false;
1134 p_spu
->i_start
= date
;
1136 p_spu
->b_ephemer
= true;
1138 if( !p_sys
->b_continue
)
1139 p_spu
->i_stop
= p_spu
->i_start
+ 1;
1141 /* Create new SPU region */
1142 memset( &fmt
, 0, sizeof(video_format_t
) );
1143 fmt
.i_chroma
= VLC_CODEC_YUVA
;
1144 fmt
.i_sar_num
= fmt
.i_sar_den
= 1;
1145 fmt
.i_width
= fmt
.i_visible_width
= p_pic
->p
[Y_PLANE
].i_visible_pitch
;
1146 fmt
.i_height
= fmt
.i_visible_height
= p_pic
->p
[Y_PLANE
].i_visible_lines
;
1147 fmt
.i_x_offset
= fmt
.i_y_offset
= 0;
1148 p_region
= subpicture_region_New( &fmt
);
1151 msg_Err( p_filter
, "cannot allocate SPU region" );
1152 p_filter
->pf_sub_buffer_del( p_filter
, p_spu
);
1153 vlc_mutex_unlock( &p_sys
->lock
);
1157 /* FIXME the copy is probably not needed anymore */
1158 picture_Copy( p_region
->p_picture
, p_pic
);
1160 p_sys
->b_need_update
= false;
1162 vlc_mutex_unlock( &p_sys
->lock
);
1164 /* set to one of the 9 relative locations */
1165 p_region
->i_align
= 0; /* Center */
1166 p_spu
->b_absolute
= false;
1169 p_spu
->i_original_picture_width
= 0; /*Let vout core do the horizontal scaling */
1170 p_spu
->i_original_picture_height
= fmt
.i_height
;
1172 p_spu
->p_region
= p_region
;
1174 p_spu
->i_alpha
= ( p_sys
->i_alpha
);
1180 static inline void rgb_to_yuv( uint8_t *y
, uint8_t *u
, uint8_t *v
,
1181 int r
, int g
, int b
)
1183 *y
= ( ( ( 66 * r
+ 129 * g
+ 25 * b
+ 128 ) >> 8 ) + 16 );
1184 *u
= ( ( -38 * r
- 74 * g
+ 112 * b
+ 128 ) >> 8 ) + 128 ;
1185 *v
= ( ( 112 * r
- 94 * g
- 18 * b
+ 128 ) >> 8 ) + 128 ;
1188 static inline bool fill_rect( filter_sys_t
* p_sys
,
1189 uint16_t i_x
, uint16_t i_y
,
1190 uint16_t i_w
, uint16_t i_h
,
1193 plane_t
*p_outY
= p_sys
->p_pic
->p
+Y_PLANE
;
1194 plane_t
*p_outU
= p_sys
->p_pic
->p
+U_PLANE
;
1195 plane_t
*p_outV
= p_sys
->p_pic
->p
+V_PLANE
;
1196 plane_t
*p_outA
= p_sys
->p_pic
->p
+A_PLANE
;
1197 int i_pitch
= p_outY
->i_pitch
;
1198 int i_lines
= p_outY
->i_lines
;
1199 if ( i_x
+ i_w
> i_pitch
)
1201 if ( i_y
+ i_h
> i_lines
)
1203 int i_line_offset
= i_y
* i_pitch
;
1204 uint8_t i_yuv_y
= p_sys
->ar_color_table_yuv
[i_color
][0];
1205 uint8_t i_yuv_u
= p_sys
->ar_color_table_yuv
[i_color
][1];
1206 uint8_t i_yuv_v
= p_sys
->ar_color_table_yuv
[i_color
][2];
1207 uint8_t i_alpha
= p_sys
->ar_color_table_yuv
[i_color
][3];
1208 for( int i_line
= 0; i_line
< i_h
; i_line
++ )
1210 for( int i_column
= 0; i_column
< i_w
; i_column
++ )
1212 int i_total_offset
= i_line_offset
+ i_x
+ i_column
;
1213 p_outY
->p_pixels
[ i_total_offset
] = i_yuv_y
;
1214 p_outU
->p_pixels
[ i_total_offset
] = i_yuv_u
;
1215 p_outV
->p_pixels
[ i_total_offset
] = i_yuv_v
;
1216 p_outA
->p_pixels
[ i_total_offset
] = i_alpha
;
1218 i_line_offset
+= i_pitch
;
1223 static inline bool copy_rect( filter_sys_t
* p_sys
,
1224 uint16_t i_x
, uint16_t i_y
,
1225 uint16_t i_w
, uint16_t i_h
,
1226 uint16_t i_sx
, uint16_t i_sy
)
1228 plane_t
*p_Y
= p_sys
->p_pic
->p
+Y_PLANE
;
1229 plane_t
*p_U
= p_sys
->p_pic
->p
+U_PLANE
;
1230 plane_t
*p_V
= p_sys
->p_pic
->p
+V_PLANE
;
1231 plane_t
*p_A
= p_sys
->p_pic
->p
+A_PLANE
;
1233 int i_pitch
= p_Y
->i_pitch
;
1234 int i_lines
= p_Y
->i_lines
;
1236 fprintf( stderr
, "copy_rect: (%d,%d)+(%d,%d) -> (%d,%d)\n", i_x
, i_y
, i_w
, i_h
, i_sx
, i_sy
);
1238 if( i_x
+ i_w
> i_pitch
|| i_sx
+ i_w
> i_pitch
)
1240 if( i_y
+ i_h
> i_lines
|| i_sy
+ i_h
> i_lines
)
1243 if( i_w
<= 0 || i_h
<= 0 )
1246 uint8_t *pb_buffer
= calloc( i_w
* i_h
, 4 );
1250 for( int i_line
= 0; i_line
< i_h
; i_line
++ )
1252 for( int i_column
= 0; i_column
< i_w
; i_column
++ )
1254 const int i_src_offset
= ( i_sy
+ i_line
) * i_pitch
+ i_sx
+ i_column
;
1255 const int i_tmp_offset
= ( 0 + i_line
) * i_w
+ 0 + i_column
;
1257 pb_buffer
[4*i_tmp_offset
+ 0] = p_Y
->p_pixels
[i_src_offset
];
1258 pb_buffer
[4*i_tmp_offset
+ 1] = p_U
->p_pixels
[i_src_offset
];
1259 pb_buffer
[4*i_tmp_offset
+ 2] = p_V
->p_pixels
[i_src_offset
];
1260 pb_buffer
[4*i_tmp_offset
+ 3] = p_A
->p_pixels
[i_src_offset
];
1264 for( int i_line
= 0; i_line
< i_h
; i_line
++ )
1266 for( int i_column
= 0; i_column
< i_w
; i_column
++ )
1268 const int i_tmp_offset
= ( 0 + i_line
) * i_w
+ 0 + i_column
;
1269 const int i_dst_offset
= ( i_y
+ i_line
) * i_pitch
+ i_x
+ i_column
;
1271 p_Y
->p_pixels
[i_dst_offset
] = pb_buffer
[4*i_tmp_offset
+ 0];
1272 p_U
->p_pixels
[i_dst_offset
] = pb_buffer
[4*i_tmp_offset
+ 1];
1273 p_V
->p_pixels
[i_dst_offset
] = pb_buffer
[4*i_tmp_offset
+ 2];
1274 p_A
->p_pixels
[i_dst_offset
] = pb_buffer
[4*i_tmp_offset
+ 3];
1282 static inline bool raw_line( filter_sys_t
* p_sys
,
1283 uint16_t i_x
, uint16_t i_y
,
1286 plane_t
*p_outY
= p_sys
->p_pic
->p
+Y_PLANE
;
1287 plane_t
*p_outU
= p_sys
->p_pic
->p
+U_PLANE
;
1288 plane_t
*p_outV
= p_sys
->p_pic
->p
+V_PLANE
;
1289 plane_t
*p_outA
= p_sys
->p_pic
->p
+A_PLANE
;
1290 int i_pitch
= p_outY
->i_pitch
;
1291 int i_lines
= p_outY
->i_lines
;
1292 if ( i_x
+ i_w
> i_pitch
)
1297 int i_line_offset
= i_y
* i_pitch
+ i_x
;
1299 for( int i_column
= 0; i_column
< i_w
; i_column
++ )
1301 int i_offset
= i_line_offset
+ i_column
;
1302 uint8_t i_color
= p_sys
->read_buffer
[i_column
];
1303 p_outY
->p_pixels
[ i_offset
] = p_sys
->ar_color_table_yuv
[i_color
][0];
1304 p_outU
->p_pixels
[ i_offset
] = p_sys
->ar_color_table_yuv
[i_color
][1];
1305 p_outV
->p_pixels
[ i_offset
] = p_sys
->ar_color_table_yuv
[i_color
][2];
1306 p_outA
->p_pixels
[ i_offset
] = p_sys
->ar_color_table_yuv
[i_color
][3];
1313 /*****************************************************************************
1314 * MouseEvent: callback for mouse events
1315 *****************************************************************************/
1316 static int MouseEvent( filter_t
*p_filter
,
1317 const vlc_mouse_t
*p_old
,
1318 const vlc_mouse_t
*p_new
,
1319 const video_format_t
*p_fmt
)
1321 filter_sys_t
*p_sys
= p_filter
->p_sys
;
1324 if( !p_sys
->b_vnc_mouse_events
)
1327 int i_v
= p_new
->i_pressed
;
1328 int i_x
= p_new
->i_x
;
1329 int i_y
= p_new
->i_y
;
1331 vlc_mutex_lock( &p_sys
->lock
);
1333 const int v_h
= p_fmt
->i_visible_height
;
1334 const int v_w
= p_sys
->i_vnc_width
* v_h
/ p_sys
->i_vnc_height
;
1335 const int v_x
= (p_fmt
->i_visible_width
-v_w
)/2;
1339 if( i_y
< 0 || i_x
< 0 || i_y
>= v_h
|| i_x
>= v_w
)
1341 vlc_mutex_unlock( &p_sys
->lock
);
1342 msg_Dbg( p_filter
, "invalid mouse event? x=%d y=%d btn=%x", i_x
, i_y
, i_v
);
1345 if( !p_sys
->b_connection_active
)
1347 vlc_mutex_unlock( &p_sys
->lock
);
1352 msg_Dbg( p_filter
, "mouse event x=%d y=%d btn=%x", i_x
, i_y
, i_v
);
1356 i_x
= i_x
* p_sys
->i_vnc_width
/ v_w
;
1357 i_y
= i_y
* p_sys
->i_vnc_height
/ v_h
;
1359 /* buttonMask bits 0-7 are buttons 1-8, 0=up, 1=down */
1360 rfbPointerEventMsg ev
;
1361 ev
.type
= rfbPointerEvent
;
1362 ev
.buttonMask
= i_v
;
1366 write_exact( p_filter
, p_sys
->i_socket
,
1367 (char*)&ev
, sz_rfbPointerEventMsg
);
1369 vlc_mutex_unlock( &p_sys
->lock
);
1371 return VLC_EGENERIC
;
1374 /*****************************************************************************
1375 * KeyEvent: callback for keyboard events
1376 *****************************************************************************/
1377 static int KeyEvent( vlc_object_t
*p_this
, char const *psz_var
,
1378 vlc_value_t oldval
, vlc_value_t newval
, void *p_data
)
1380 VLC_UNUSED(psz_var
); VLC_UNUSED(oldval
);
1382 filter_t
*p_filter
= (filter_t
*)p_data
;
1383 filter_sys_t
*p_sys
= p_filter
->p_sys
;
1385 if( !p_sys
->b_vnc_key_events
)
1388 msg_Dbg( p_this
, "key pressed (%"PRId64
") ", newval
.i_int
);
1390 if ( !newval
.i_int
)
1392 msg_Err( p_this
, "Received invalid key event 0" );
1393 return VLC_EGENERIC
;
1396 vlc_mutex_lock( &p_sys
->lock
);
1397 if( !p_sys
->b_connection_active
)
1399 vlc_mutex_unlock( &p_sys
->lock
);
1403 uint32_t i_key32
= newval
.i_int
;
1404 i_key32
= htonl(i_key32
);
1407 ev
.type
= rfbKeyEvent
;
1411 /* first key-down for modifier-keys */
1412 if (newval
.i_int
& KEY_MODIFIER_CTRL
)
1415 write_exact( p_filter
, p_sys
->i_socket
,
1416 (char*)&ev
, sz_rfbKeyEventMsg
);
1418 if (newval
.i_int
& KEY_MODIFIER_SHIFT
)
1421 write_exact( p_filter
, p_sys
->i_socket
,
1422 (char*)&ev
, sz_rfbKeyEventMsg
);
1424 if (newval
.i_int
& KEY_MODIFIER_ALT
)
1427 write_exact( p_filter
, p_sys
->i_socket
,
1428 (char*)&ev
, sz_rfbKeyEventMsg
);
1431 /* then key-down for the pressed key */
1433 write_exact( p_filter
, p_sys
->i_socket
,
1434 (char*)&ev
, sz_rfbKeyEventMsg
);
1438 /* then key-up for the pressed key */
1439 write_exact( p_filter
, p_sys
->i_socket
,
1440 (char*)&ev
, sz_rfbKeyEventMsg
);
1442 /* last key-down for modifier-keys */
1443 if (newval
.i_int
& KEY_MODIFIER_CTRL
)
1446 write_exact( p_filter
, p_sys
->i_socket
,
1447 (char*)&ev
, sz_rfbKeyEventMsg
);
1449 if (newval
.i_int
& KEY_MODIFIER_SHIFT
)
1452 write_exact( p_filter
, p_sys
->i_socket
,
1453 (char*)&ev
, sz_rfbKeyEventMsg
);
1455 if (newval
.i_int
& KEY_MODIFIER_ALT
)
1458 write_exact( p_filter
, p_sys
->i_socket
,
1459 (char*)&ev
, sz_rfbKeyEventMsg
);
1461 vlc_mutex_unlock( &p_sys
->lock
);
1466 static void vnc_encrypt_bytes( unsigned char *bytes
, char *passwd
)
1468 unsigned char key
[8];
1471 for (i
= 0; i
< 8; i
++)
1472 key
[i
] = i
< strlen( passwd
) ? passwd
[i
] : '\0';
1474 gcry_cipher_hd_t ctx
;
1475 gcry_cipher_open( &ctx
, GCRY_CIPHER_DES
, GCRY_CIPHER_MODE_ECB
,0);
1477 /* reverse bits of the key */
1478 for( i
= 0 ; i
< 8 ; i
++ )
1481 (((key
[i
] >> 6) & 0x01 ) << 1 ) +
1482 (((key
[i
] >> 5) & 0x01 ) << 2 ) +
1483 (((key
[i
] >> 4) & 0x01 ) << 3 ) +
1484 (((key
[i
] >> 3) & 0x01 ) << 4 ) +
1485 (((key
[i
] >> 2) & 0x01 ) << 5 ) +
1486 (((key
[i
] >> 1) & 0x01 ) << 6 ) +
1487 ((key
[i
] & 0x01) << 7 );
1489 gcry_cipher_setkey( ctx
, key
, 8 );
1490 gcry_cipher_encrypt( ctx
, bytes
, CHALLENGESIZE
, bytes
, CHALLENGESIZE
);
1491 gcry_cipher_close( ctx
);