]> git.sesse.net Git - vlc/blob - modules/video_filter/remoteosd.c
RemoteOSD: avoid vlc_object_find()
[vlc] / modules / video_filter / remoteosd.c
1 /*****************************************************************************
2  * remoteosd.c: remote osd over vnc filter module
3  *****************************************************************************
4  * Copyright (C) 2007-2008 Matthias Bauer
5  * $Id$
6  *
7  * Authors: Matthias Bauer <matthias dot bauer #_at_# gmx dot ch>
8  *
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.
13  *
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.
18  *
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  *****************************************************************************/
23
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.
27  *
28  * The streaming server that implements this is the ffnetdev plugin for VDR.
29  * VDR (VideoDiskRecorder) is an Linux based OpenSource harddisk recorder
30  * software.
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.
34  *
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  *****************************************************************************/
42
43 //#define VNC_DEBUG
44
45 /*****************************************************************************
46  * Preamble
47  *****************************************************************************/
48
49 #ifdef HAVE_CONFIG_H
50 # include "config.h"
51 #endif
52
53 #include <vlc_common.h>
54 #include <vlc_plugin.h>
55 #include <vlc_vout.h>
56
57 #include <vlc_filter.h>
58 #include <vlc_image.h>
59 #include <vlc_keys.h>
60
61 #include <vlc_network.h>
62 #include <gcrypt.h>              /* to encrypt password */
63 #include <vlc_gcrypt.h>
64
65 #include "remoteosd_rfbproto.h" /* type definitions of the RFB protocol for VNC */
66
67 /*****************************************************************************
68  * Module descriptor
69  *****************************************************************************/
70 #define READ_BUFFER_SIZE 1000000
71
72 #define RMTOSD_HOST_TEXT N_("VNC Host")
73 #define RMTOSD_HOST_LONGTEXT N_( \
74     "VNC hostname or IP address." )
75
76 #define RMTOSD_PORT_TEXT N_("VNC Port")
77 #define RMTOSD_PORT_LONGTEXT N_( \
78     "VNC port number." )
79
80 #define RMTOSD_PASSWORD_TEXT N_("VNC Password")
81 #define RMTOSD_PASSWORD_LONGTEXT N_( \
82     "VNC password." )
83
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. ")
87
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." )
91
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." )
95
96 #define RMTOSD_KEYS_TEXT N_("Key events")
97 #define RMTOSD_KEYS_LONGTEXT N_( \
98     "Send key events to VNC host." )
99
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)." )
106
107 #define RMTOSD_CFG "rmtosd-"
108
109 #define RMTOSD_UPDATE_MIN     200
110 #define RMTOSD_UPDATE_DEFAULT 1000
111 #define RMTOSD_UPDATE_MAX     300
112
113 static int  CreateFilter ( vlc_object_t * );
114 static void DestroyFilter( vlc_object_t * );
115
116 vlc_module_begin ()
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 )
124
125     add_string( RMTOSD_CFG "host", "myvdr", 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", "", 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,
135               RMTOSD_POLL_TEXT , RMTOSD_POLL_LONGTEXT, false )
136     add_bool( RMTOSD_CFG "mouse-events", false,
137               RMTOSD_MOUSE_TEXT , RMTOSD_MOUSE_LONGTEXT, false )
138     add_bool( RMTOSD_CFG "key-events", false,
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 )
142
143 vlc_module_end ()
144
145
146 /*****************************************************************************
147  * Local prototypes
148  *****************************************************************************/
149 #define CHALLENGESIZE 16
150 #define MAX_VNC_SERVER_NAME_LENGTH 255
151
152 /* subfilter functions */
153 static subpicture_t *Filter( filter_t *, mtime_t );
154
155 static int MouseEvent( filter_t *,
156                        const vlc_mouse_t *,
157                        const vlc_mouse_t *,
158                        const video_format_t * );
159
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 );
162
163 static void stop_osdvnc ( filter_t *p_filter );
164
165 static void* vnc_worker_thread ( vlc_object_t *p_thread_obj );
166
167 static void* update_request_thread( vlc_object_t *p_thread_obj );
168
169 static bool open_vnc_connection ( filter_t *p_filter );
170
171 static bool handshaking ( filter_t *p_filter );
172
173 static bool process_server_message ( filter_t *p_filter,
174                                      rfbServerToClientMsg *msg );
175
176 static inline void rgb_to_yuv( uint8_t *y, uint8_t *u, uint8_t *v,
177                                int r, int g, int b );
178
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,
182                               uint8_t i_color );
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 );
187
188
189 static inline bool raw_line(  filter_sys_t* p_sys,
190                               uint16_t i_x, uint16_t i_y,
191                               uint16_t i_w );
192
193 static void vnc_encrypt_bytes( unsigned char *bytes, char *passwd );
194
195
196 /*****************************************************************************
197  * Sub filter code
198  *****************************************************************************/
199
200 /*****************************************************************************
201  * Local prototypes
202  *****************************************************************************/
203 struct filter_sys_t
204 {
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 */
207
208     uint8_t       i_alpha;             /* alpha transparency value */
209
210     char          *psz_host;           /* VNC host */
211     int           i_port;
212
213     char          *psz_passwd;         /* VNC password */
214
215     bool          b_vnc_poll;          /* Activate VNC polling ? */
216     bool          b_vnc_mouse_events;  /* Send MouseEvents ? */
217     bool          b_vnc_key_events;    /* Send KeyEvents ? */
218
219     bool          b_connection_active; /* Handshaking finished ? */
220
221     vlc_mutex_t   lock;                /* To lock for read/write on picture */
222
223     picture_t     *p_pic;              /* The picture with OSD data from VNC */
224
225     int           i_socket;            /* Socket used for VNC */
226
227     uint16_t      i_vnc_width;          /* The with of the VNC screen */
228     uint16_t      i_vnc_height;         /* The height of the VNC screen */
229         uint32_t      i_vnc_pixels;         /* The pixels of the VNC screen */
230
231     bool    b_alpha_from_vnc;    /* Special ffnetdev alpha feature enabled ? */
232
233     char          read_buffer[READ_BUFFER_SIZE];
234
235     bool          b_continue;
236
237     vlc_object_t* p_worker_thread;
238
239     uint8_t       ar_color_table_yuv[256][4];
240 };
241
242 /*****************************************************************************
243  * CreateFilter: Create the filter and open the definition file
244  *****************************************************************************/
245 static int CreateFilter ( vlc_object_t *p_this )
246 {
247     filter_t *p_filter = (filter_t *)p_this;
248     filter_sys_t *p_sys = NULL;
249
250     msg_Dbg( p_filter, "Creating vnc osd filter..." );
251
252     p_filter->p_sys = p_sys = calloc( 1, sizeof(*p_sys) );
253     if( !p_filter->p_sys )
254         return VLC_ENOMEM;
255
256     /* Populating struct */
257     vlc_mutex_init( &p_sys->lock );
258     p_sys->b_continue = true;
259     p_sys->i_socket = -1;
260     p_sys->p_pic = NULL;
261
262     p_sys->psz_host = var_CreateGetString( p_this, RMTOSD_CFG "host" );
263     if( EMPTY_STR(p_sys->psz_host) )
264     {
265         msg_Err( p_filter, "unable to get vnc host" );
266         goto error;
267     }
268
269     p_sys->psz_passwd = var_CreateGetString( p_this, RMTOSD_CFG "password" );
270     if( !p_sys->psz_passwd )
271     {
272         msg_Err( p_filter, "unable to get vnc password" );
273         goto error;
274     }
275
276     p_sys->i_port = var_CreateGetIntegerCommand( p_this, RMTOSD_CFG "port" );
277
278     p_sys->i_alpha = var_CreateGetIntegerCommand( p_this, RMTOSD_CFG "alpha" );
279
280     /* in milliseconds, 0 disables polling, should not be lower than 100 */
281     p_sys->i_vnc_poll_interval  = var_CreateGetIntegerCommand( p_this,
282                                                        RMTOSD_CFG "update" );
283     if ( p_sys->i_vnc_poll_interval < 100)
284     {
285        p_sys->i_vnc_poll_interval = 100;
286     }
287
288     for ( int i = 0; i < 256; i++ )
289     {
290         p_sys->ar_color_table_yuv[i][0] = 255;
291         p_sys->ar_color_table_yuv[i][1] = 255;
292         p_sys->ar_color_table_yuv[i][2] = 255;
293         p_sys->ar_color_table_yuv[i][3] = 255;
294     }
295
296     p_sys->b_vnc_poll = var_CreateGetBoolCommand( p_this,
297                                             RMTOSD_CFG "vnc-polling" );
298     p_sys->b_vnc_mouse_events = var_CreateGetBoolCommand( p_this,
299                                             RMTOSD_CFG "mouse-events" );
300     p_sys->b_vnc_key_events = var_CreateGetBoolCommand( p_this,
301                                             RMTOSD_CFG "key-events" );
302
303     /* Keep track of OSD Events */
304     p_sys->b_need_update  = false;
305
306     /* Attach subpicture filter callback */
307     p_filter->pf_sub_filter = Filter;
308     p_filter->pf_sub_mouse  = MouseEvent;
309
310     var_AddCallback( p_filter->p_libvlc, "key-pressed", KeyEvent, p_this );
311
312     es_format_Init( &p_filter->fmt_out, SPU_ES, VLC_CODEC_SPU );
313     p_filter->fmt_out.i_priority = 0;
314
315     vlc_gcrypt_init();
316
317     /* create the vnc worker thread */
318     p_sys->p_worker_thread = vlc_object_create( p_this,
319                                                 sizeof( vlc_object_t ) );
320     vlc_object_attach( p_sys->p_worker_thread, p_this );
321     if( vlc_thread_create( p_sys->p_worker_thread,
322                            vnc_worker_thread, VLC_THREAD_PRIORITY_LOW ) )
323     {
324         vlc_object_release( p_sys->p_worker_thread );
325         msg_Err( p_filter, "cannot spawn vnc message reader thread" );
326         goto error;
327     }
328
329     msg_Dbg( p_filter, "osdvnc filter started" );
330
331     return VLC_SUCCESS;
332
333 error:
334     msg_Err( p_filter, "osdvnc filter discarded" );
335
336     stop_osdvnc( p_filter );
337
338     vlc_mutex_destroy( &p_sys->lock );
339     free( p_sys->psz_host );
340     free( p_sys->psz_passwd );
341     free( p_sys );
342
343     return VLC_EGENERIC;
344 }
345
346 /*****************************************************************************
347  * DestroyFilter: Make a clean exit of this plugin
348  *****************************************************************************/
349 static void DestroyFilter( vlc_object_t *p_this )
350 {
351     filter_t     *p_filter = (filter_t*)p_this;
352     filter_sys_t *p_sys = p_filter->p_sys;
353
354     msg_Dbg( p_filter, "DestroyFilter called." );
355
356     stop_osdvnc( p_filter );
357
358     var_DelCallback( p_filter->p_libvlc, "key-pressed", KeyEvent, p_this );
359
360     var_Destroy( p_this, RMTOSD_CFG "host" );
361     var_Destroy( p_this, RMTOSD_CFG "port" );
362     var_Destroy( p_this, RMTOSD_CFG "password" );
363     var_Destroy( p_this, RMTOSD_CFG "update" );
364     var_Destroy( p_this, RMTOSD_CFG "vnc-polling" );
365     var_Destroy( p_this, RMTOSD_CFG "mouse-events" );
366     var_Destroy( p_this, RMTOSD_CFG "key-events" );
367     var_Destroy( p_this, RMTOSD_CFG "alpha" );
368
369     vlc_mutex_destroy( &p_sys->lock );
370     free( p_sys->psz_host );
371     free( p_sys->psz_passwd );
372     free( p_sys );
373 }
374
375 static void stop_osdvnc ( filter_t *p_filter )
376 {
377     filter_sys_t *p_sys = p_filter->p_sys;
378
379     /* It will unlock socket reading */
380     vlc_object_kill( p_filter );
381
382     /* */
383     if( p_sys->p_worker_thread )
384     {
385         msg_Dbg( p_filter, "joining worker_thread" );
386         vlc_object_kill( p_sys->p_worker_thread );
387         vlc_thread_join( p_sys->p_worker_thread );
388         vlc_object_release( p_sys->p_worker_thread );
389         msg_Dbg( p_filter, "released worker_thread" );
390     }
391
392     msg_Dbg( p_filter, "osdvnc stopped" );
393 }
394
395 static bool read_exact( filter_t *p_filter,
396                         int i_socket,
397                         char* p_readbuf,
398                         int i_bytes )
399 {
400     return i_bytes == net_Read( p_filter, i_socket, NULL,
401                                   (unsigned char*)p_readbuf,
402                                   i_bytes, true );
403 }
404
405
406 static bool write_exact( filter_t *p_filter,
407                          int i_socket,
408                          char* p_writebuf,
409                          int i_bytes )
410 {
411     return i_bytes == net_Write( p_filter, i_socket, NULL,
412                                   (unsigned char*)p_writebuf, i_bytes );
413 }
414
415 static bool open_vnc_connection ( filter_t *p_filter )
416 {
417     filter_sys_t *p_sys = p_filter->p_sys;
418
419     msg_Dbg( p_filter, "Open socket to vnc server on %s:%u.",
420               p_sys->psz_host, p_sys->i_port );
421
422     p_sys->i_socket = net_ConnectTCP( p_filter, p_sys->psz_host, p_sys->i_port );
423
424     if( p_sys->i_socket < 0 )
425     {
426         msg_Err( p_filter, "Could not open socket" );
427         return false;
428     }
429
430     msg_Dbg( p_filter, "socket is open." );
431
432     return true;
433 }
434
435 static bool handshaking ( filter_t *p_filter )
436 {
437     filter_sys_t *p_sys = p_filter->p_sys;
438
439     msg_Dbg( p_filter, "Reading protocol version" );
440
441     rfbProtocolVersionMsg pv;
442     if ( !read_exact( p_filter, p_sys->i_socket, pv,
443                       sz_rfbProtocolVersionMsg ) )
444     {
445         msg_Err( p_filter, "Could not read version message" );
446         return false;
447     }
448     pv[sz_rfbProtocolVersionMsg] = '\0'; /* pv size is sz_rfbProtocolVersionMsg+1 */
449
450     msg_Dbg( p_filter, "Server version is %s", pv );
451
452     strncpy(pv, "RFB 003.003\n", sz_rfbProtocolVersionMsg);
453
454     if( !write_exact(p_filter, p_sys->i_socket, pv,
455                      sz_rfbProtocolVersionMsg) )
456     {
457         msg_Err( p_filter, "Could not write version message" );
458         return false;
459     }
460
461     msg_Dbg( p_filter, "Reading authentication scheme" );
462     uint32_t i_authScheme;
463     if( !read_exact( p_filter, p_sys->i_socket, (char*)&i_authScheme, 4 ) )
464     {
465         msg_Err( p_filter, "Could not read authentication scheme" );
466         return false;
467     }
468     i_authScheme = htonl(i_authScheme);
469
470     msg_Dbg( p_filter, "Authentication scheme = %x", i_authScheme );
471     if ( i_authScheme == rfbConnFailed )
472     {
473         msg_Err( p_filter, "Connection rejected by server" );
474         return false;
475     }
476     if (i_authScheme == rfbVncAuth)
477     {
478         unsigned char challenge[CHALLENGESIZE];
479         if ( !read_exact( p_filter, p_sys->i_socket,
480                           (char*)challenge, CHALLENGESIZE ) )
481         {
482             msg_Err( p_filter, "Could not read password challenge" );
483             return false;
484         }
485
486         vnc_encrypt_bytes( challenge, p_sys->psz_passwd );
487
488         if( !write_exact(p_filter, p_sys->i_socket,
489                          (char*)challenge, CHALLENGESIZE ) )
490         {
491             msg_Err( p_filter, "Could not write password" );
492             return false;
493         }
494         uint32_t i_authResult;
495         if( !read_exact( p_filter, p_sys->i_socket, (char*)&i_authResult, 4 ) )
496         {
497             msg_Err( p_filter, "Could not read authentication result" );
498             return false;
499         }
500         i_authResult = htonl(i_authResult);
501         if (i_authResult != rfbVncAuthOK)
502         {
503             msg_Err( p_filter, "VNC authentication failed" );
504             return false;
505         }
506     }
507
508     msg_Dbg( p_filter, "Writing client init message" );
509     rfbClientInitMsg ci;
510     ci.shared = 1;
511     if( !write_exact( p_filter, p_sys->i_socket,
512                       (char*)&ci, sz_rfbClientInitMsg ) )
513     {
514         msg_Err( p_filter, "Could not write client init message" );
515         return false;
516     }
517
518     msg_Dbg( p_filter, "Reading server init message" );
519     rfbServerInitMsg si;
520     if( !read_exact( p_filter, p_sys->i_socket,
521                      (char*)&si, sz_rfbServerInitMsg ) )
522     {
523         msg_Err( p_filter, "Could not read server init message" );
524         return false;
525     }
526     si.framebufferWidth = htons(si.framebufferWidth);
527     si.framebufferHeight = htons(si.framebufferHeight);
528     si.format.redMax = htons(si.format.redMax);
529     si.format.greenMax = htons(si.format.greenMax);
530     si.format.blueMax = htons(si.format.blueMax);
531
532     p_sys->i_vnc_width = si.framebufferWidth;
533     p_sys->i_vnc_height = si.framebufferHeight;
534
535     msg_Dbg( p_filter, "Servers preferred pixelformat: "
536                         "%ux%u, R(%u),G(%u),B(%u), %u bit, depht=%u, %s",
537                         si.framebufferWidth,
538                         si.framebufferHeight,
539                         si.format.redMax,
540                         si.format.greenMax,
541                         si.format.blueMax,
542                         si.format.bitsPerPixel,
543                         si.format.depth,
544                         si.format.trueColour ? "TrueColor" : "Not-TrueColor");
545
546     uint32_t i_nameLength = htonl(si.nameLength);
547     if( i_nameLength > MAX_VNC_SERVER_NAME_LENGTH )
548     {
549         msg_Err( p_filter, "Server name too long" );
550         return false;
551     }
552     char s_ServerName[MAX_VNC_SERVER_NAME_LENGTH+1];
553
554     msg_Dbg( p_filter, "Reading server name with size = %u", i_nameLength );
555     if( !read_exact( p_filter, p_sys->i_socket, s_ServerName, i_nameLength ) )
556     {
557         msg_Err( p_filter, "Could not read server name" );
558         return false;
559     }
560     s_ServerName[i_nameLength] = '\0';
561
562     if( strcmp( s_ServerName, "VDR-OSD") == 0 )
563     {
564         msg_Dbg( p_filter, "Server is a VDR" );
565         p_sys->b_alpha_from_vnc = true;
566     }
567     else
568     {
569         msg_Dbg( p_filter, "Server is a normal VNC" );
570         p_sys->b_alpha_from_vnc = false;
571     }
572
573
574     msg_Dbg( p_filter, "Server init message read properly" );
575     msg_Dbg( p_filter, "Server name is %s", s_ServerName );
576
577     msg_Dbg( p_filter, "Writing SetPixelFormat message" );
578
579     rfbSetPixelFormatMsg sp;
580     sp.type = rfbSetPixelFormat;
581     sp.pad1 = sp.pad2 = 0;
582     sp.format.bitsPerPixel = 8;
583     sp.format.depth = 8 ;
584     sp.format.bigEndian = 1;
585     sp.format.trueColour = 0;
586     sp.format.redMax = htons(31);
587     sp.format.greenMax = htons(31);
588     sp.format.blueMax = htons(31);
589     sp.format.redShift = 10;
590     sp.format.greenShift = 5;
591     sp.format.blueShift = 0;
592     sp.format.pad1 = sp.format.pad2 = 0;
593
594     if( !write_exact( p_filter, p_sys->i_socket,
595                       (char*)&sp, sz_rfbSetPixelFormatMsg) )
596     {
597         msg_Err( p_filter, "Could not write SetPixelFormat message" );
598         return false;
599     }
600
601     msg_Dbg( p_filter, "Writing SetEncodings message" );
602
603     rfbSetEncodingsMsg se;
604     se.type = rfbSetEncodings;
605     se.pad = 0;
606     se.nEncodings = htons( p_sys->b_alpha_from_vnc ? 3 : 2 );
607
608     if( !write_exact( p_filter, p_sys->i_socket,
609                       (char*)&se, sz_rfbSetEncodingsMsg) )
610     {
611         msg_Err( p_filter, "Could not write SetEncodings message begin" );
612         return false;
613     }
614
615     uint32_t i_encoding;
616
617     msg_Dbg( p_filter, "Writing SetEncodings rfbEncodingCopyRect" );
618     i_encoding = htonl(rfbEncodingCopyRect);
619     if( !write_exact( p_filter, p_sys->i_socket, (char*)&i_encoding, 4) )
620     {
621         msg_Err( p_filter, "Could not write encoding type rfbEncodingCopyRect." );
622         return false;
623     }
624
625     msg_Dbg( p_filter, "Writing SetEncodings rfbEncodingRRE" );
626     i_encoding = htonl(rfbEncodingRRE);
627     if( !write_exact(p_filter, p_sys->i_socket, (char*)&i_encoding, 4) )
628     {
629         msg_Err( p_filter, "Could not write encoding type rfbEncodingRRE." );
630         return false;
631     }
632
633     if( p_sys->b_alpha_from_vnc )
634     {
635         msg_Dbg( p_filter, "Writing SetEncodings rfbEncSpecialUseAlpha" );
636         i_encoding = 0x00F0FFFF; /* rfbEncSpecialUseAlpha is 0xFFFFF000
637                                   * before we swap it */
638         if( !write_exact(p_filter, p_sys->i_socket, (char*)&i_encoding, 4) )
639         {
640             msg_Err( p_filter, "Could not write encoding type rfbEncSpecialUseAlpha." );
641             return false;
642         }
643     }
644     return true;
645
646 }
647
648 static void* vnc_worker_thread( vlc_object_t *p_thread_obj )
649 {
650     filter_t* p_filter = (filter_t*)(p_thread_obj->p_parent);
651     filter_sys_t *p_sys = p_filter->p_sys;
652     vlc_object_t *p_update_request_thread;
653     int canc = vlc_savecancel ();
654
655     msg_Dbg( p_filter, "VNC worker thread started" );
656
657     if( !open_vnc_connection ( p_filter ) )
658     {
659         msg_Err( p_filter, "Could not connect to vnc host" );
660         goto exit;
661     }
662
663     if( !handshaking ( p_filter ) )
664     {
665         msg_Err( p_filter, "Error occured while handshaking vnc host" );
666         goto exit;
667     }
668
669     p_sys->b_connection_active = true; /* to enable sending key
670                                             * and mouse events to host */
671
672     /* Create an empty picture for VNC the data */
673     vlc_mutex_lock( &p_sys->lock );
674     p_sys->p_pic = picture_New( VLC_CODEC_YUVA,
675                                 p_sys->i_vnc_width, p_sys->i_vnc_height, 1, 1 );
676     if( !p_sys->p_pic )
677     {
678         vlc_mutex_unlock( &p_sys->lock );
679         goto exit;
680     }
681         p_sys->i_vnc_pixels = p_sys->i_vnc_width * p_sys->i_vnc_height;
682
683     vlc_mutex_unlock( &p_sys->lock );
684
685     /* create the update request thread */
686     p_update_request_thread = vlc_object_create( p_filter,
687                                                  sizeof( vlc_object_t ) );
688     vlc_object_attach( p_update_request_thread, p_filter );
689     if( vlc_thread_create( p_update_request_thread,
690                            update_request_thread, VLC_THREAD_PRIORITY_LOW ) )
691     {
692         vlc_object_release( p_update_request_thread );
693         msg_Err( p_filter, "cannot spawn vnc update request thread" );
694         goto exit;
695     }
696
697     /* connection is initialized, now read and handle server messages */
698     while( vlc_object_alive( p_thread_obj ) )
699     {
700         rfbServerToClientMsg msg;
701         int i_msgSize;
702
703         memset( &msg, 0, sizeof(msg) );
704
705         if( !read_exact(p_filter, p_sys->i_socket, (char*)&msg, 1 ) )
706         {
707             msg_Err( p_filter, "Error while waiting for next server message");
708             break;
709         }
710         switch (msg.type)
711         {
712         case rfbFramebufferUpdate:
713             i_msgSize = sz_rfbFramebufferUpdateMsg;
714             break;
715         case rfbSetColourMapEntries:
716             i_msgSize = sz_rfbSetColourMapEntriesMsg;
717             break;
718         case rfbBell:
719             i_msgSize = sz_rfbBellMsg;
720             break;
721         case rfbServerCutText:
722             i_msgSize = sz_rfbServerCutTextMsg;
723             break;
724         case rfbReSizeFrameBuffer:
725             i_msgSize = sz_rfbReSizeFrameBufferMsg;
726             break;
727         default:
728             i_msgSize = 0;
729             msg_Err( p_filter, "Invalid message %u received", msg.type );
730             break;
731         }
732
733         if( i_msgSize <= 0 )
734             break;
735
736         if( --i_msgSize > 0 )
737         {
738             if ( !read_exact( p_filter, p_sys->i_socket,
739                               ((char*)&msg)+1, i_msgSize ) )
740             {
741                 msg_Err( p_filter, "Error while reading message of type %u",
742                          msg.type );
743                 break;
744             }
745         }
746         process_server_message( p_filter, &msg);
747     }
748
749     msg_Dbg( p_filter, "joining update_request_thread" );
750     vlc_object_kill( p_update_request_thread );
751     vlc_thread_join( p_update_request_thread );
752     vlc_object_release( p_update_request_thread );
753     msg_Dbg( p_filter, "released update_request_thread" );
754
755 exit:
756
757     vlc_mutex_lock( &p_sys->lock );
758     p_sys->b_connection_active = false;
759
760     if (p_sys->i_socket >= 0)
761         net_Close(p_sys->i_socket);
762
763     if( p_sys->p_pic )
764         picture_Release( p_sys->p_pic );
765
766     /* It will hide the subtitle */
767     p_sys->b_continue = false;
768     p_sys->b_need_update = true;
769     vlc_mutex_unlock( &p_sys->lock );
770
771     msg_Dbg( p_filter, "VNC message reader thread ended" );
772     vlc_restorecancel (canc);
773     return NULL;
774 }
775
776 static void* update_request_thread( vlc_object_t *p_thread_obj )
777 {
778     filter_t* p_filter = (filter_t*)(p_thread_obj->p_parent);
779     filter_sys_t *p_sys = p_filter->p_sys;
780     int canc = vlc_savecancel ();
781
782     msg_Dbg( p_filter, "VNC update request thread started" );
783
784     rfbFramebufferUpdateRequestMsg udr;
785     udr.type = rfbFramebufferUpdateRequest;
786     udr.incremental = 0;
787     udr.x = 0;
788     udr.y = 0;
789     udr.w = htons(p_sys->i_vnc_width);
790     udr.h = htons(p_sys->i_vnc_height);
791
792     if( !write_exact(p_filter, p_sys->i_socket, (char*)&udr,
793                      sz_rfbFramebufferUpdateRequestMsg) )
794     {
795         msg_Err( p_filter, "Could not write rfbFramebufferUpdateRequestMsg." );
796         p_sys->b_continue = false;
797         return NULL;
798     }
799
800     udr.incremental = 1;
801     mtime_t i_poll_interval_microsec = p_sys->i_vnc_poll_interval * 1000;
802
803     if( p_sys->b_vnc_poll)
804     {
805         while( vlc_object_alive( p_thread_obj ) )
806         {
807             msleep( i_poll_interval_microsec );
808             if( !write_exact(p_filter, p_sys->i_socket, (char*)&udr,
809                              sz_rfbFramebufferUpdateRequestMsg))
810             {
811                 msg_Err( p_filter, "Could not write rfbFramebufferUpdateRequestMsg." );
812                 break;
813             }
814         }
815         p_sys->b_continue = false;
816     }
817     else
818     {
819         msg_Dbg( p_filter, "VNC polling disabled." );
820     }
821
822     msg_Dbg( p_filter, "VNC update request thread ended" );
823     vlc_restorecancel (canc);
824     return NULL;
825 }
826
827 static bool process_server_message ( filter_t *p_filter,
828                                      rfbServerToClientMsg *msg )
829 {
830     filter_sys_t *p_sys = p_filter->p_sys;
831
832     switch (msg->type)
833     {
834     case rfbFramebufferUpdate:
835         {
836             msg->fu.nRects = htons(msg->fu.nRects);
837             rfbFramebufferUpdateRectHeader hdr;
838
839             for (int i_rect = 0; i_rect < msg->fu.nRects; i_rect++)
840             {
841                 if (!read_exact(p_filter, p_sys->i_socket, (char*)&hdr,
842                     sz_rfbFramebufferUpdateRectHeader ) )
843                 {
844                     msg_Err( p_filter, "Could not read FrameBufferUpdate header" );
845                     return false;
846                 }
847                 hdr.r.x = htons(hdr.r.x);
848                 hdr.r.y = htons(hdr.r.y);
849                 hdr.r.w = htons(hdr.r.w);
850                 hdr.r.h = htons(hdr.r.h);
851                 hdr.encoding = htonl(hdr.encoding);
852
853                 switch (hdr.encoding)
854                 {
855                 case rfbEncodingRaw:
856                     {
857                         int i_line;
858                         for (i_line = 0; i_line < hdr.r.h; i_line++)
859                         {
860                             if ( !read_exact( p_filter, p_sys->i_socket,
861                                     p_sys->read_buffer, hdr.r.w ) )
862                             {
863                                 msg_Err( p_filter,
864                                  "Could not read FrameBufferUpdate line data" );
865                                return false;
866                             }
867                             vlc_mutex_lock( &p_sys->lock );
868                             if ( !raw_line( p_sys, hdr.r.x,
869                                             hdr.r.y + i_line,
870                                             hdr.r.w ) )
871                             {
872                                 msg_Err( p_filter, "raw_line failed." );
873                                 vlc_mutex_unlock( &p_sys->lock );
874                                 return false;
875                             }
876                             vlc_mutex_unlock( &p_sys->lock );
877                         }
878                     }
879                     break;
880
881                 case rfbEncodingCopyRect:
882                     {
883                         rfbCopyRect rect;
884
885                         if ( !read_exact( p_filter, p_sys->i_socket,
886                                           (char*)&rect,
887                                           sz_rfbCopyRect ) )
888                         {
889                             msg_Err( p_filter, "Could not read rfbCopyRect" );
890                             return false;
891                         }
892                         rect.srcX = htons( rect.srcX );
893                         rect.srcY = htons( rect.srcY );
894
895                         vlc_mutex_lock( &p_sys->lock );
896                         if ( !copy_rect( p_sys,
897                                          hdr.r.x,   hdr.r.y,
898                                          hdr.r.w,   hdr.r.h,
899                                          rect.srcX, rect.srcY ) )
900                         {
901                             msg_Err( p_filter, "copy_rect failed." );
902                             vlc_mutex_unlock( &p_sys->lock );
903                             return false;
904                         }
905                         vlc_mutex_unlock( &p_sys->lock );
906                     }
907                     break;
908
909                 case rfbEncodingRRE:
910                     {
911                         rfbRREHeader rrehdr;
912                         if ( !read_exact( p_filter, p_sys->i_socket,
913                                           (char*)&rrehdr,
914                                           sz_rfbRREHeader ) )
915                         {
916                             msg_Err( p_filter, "Could not read rfbRREHeader" );
917                             return false;
918                         }
919                         uint8_t i_pixcolor;
920                         if ( !read_exact(p_filter, p_sys->i_socket,
921                                          (char*)&i_pixcolor, 1 ) )
922                         {
923                             msg_Err( p_filter, "Could not read RRE pixcolor" );
924                             return false;
925                         }
926
927                         vlc_mutex_lock( &p_sys->lock );
928                         if ( !fill_rect( p_sys,
929                                         hdr.r.x, hdr.r.y,
930                                         hdr.r.w, hdr.r.h,
931                                         i_pixcolor) )
932                         {
933                             msg_Err( p_filter, "main fill_rect failed." );
934                             vlc_mutex_unlock( &p_sys->lock );
935                             return false;
936                         }
937                         vlc_mutex_unlock( &p_sys->lock );
938
939                         rrehdr.nSubrects = htonl(rrehdr.nSubrects);
940
941                         int i_datasize = rrehdr.nSubrects *
942                                      ( sizeof(i_pixcolor) + sz_rfbRectangle ) ;
943                         if ( i_datasize > READ_BUFFER_SIZE )
944                         {
945                             msg_Err( p_filter, "Buffer too small, "
946                                      "need %u bytes", i_datasize );
947                             return false;
948                         }
949                         if ( !read_exact( p_filter, p_sys->i_socket,
950                                        p_sys->read_buffer, i_datasize ) )
951                         {
952                             msg_Err( p_filter,
953                                      "Could not read RRE subrect data" );
954                             return false;
955                         }
956
957                         uint32_t i_subrect;
958                         rfbRectangle* p_subrect;
959                         int i_offset = 0;
960                         vlc_mutex_lock( &p_sys->lock );
961                         for ( i_subrect = 0;
962                               i_subrect < rrehdr.nSubrects; i_subrect++)
963                         {
964                             i_pixcolor = p_sys->read_buffer[i_offset];
965                             i_offset += sizeof(i_pixcolor);
966                             p_subrect =
967                                (rfbRectangle*)(p_sys->read_buffer + i_offset);
968                             i_offset += sz_rfbRectangle;
969
970                             if (!fill_rect( p_sys,
971                                             htons(p_subrect->x) + hdr.r.x,
972                                             htons(p_subrect->y) + hdr.r.y,
973                                             htons(p_subrect->w),
974                                             htons(p_subrect->h),
975                                             i_pixcolor) )
976                             {
977                                 msg_Err( p_filter,
978                                     "subrect %u fill_rect failed.", i_subrect );
979                                 vlc_mutex_unlock( &p_sys->lock );
980                                 return false;
981                             }
982                         }
983                         vlc_mutex_unlock( &p_sys->lock );
984                     }
985                     break;
986
987                 }
988
989             }
990             vlc_mutex_lock( &p_sys->lock );
991             p_sys->b_need_update = true;
992             vlc_mutex_unlock( &p_sys->lock );
993         }
994         return true;
995
996     case rfbSetColourMapEntries:
997         {
998             msg->scme.nColours = htons(msg->scme.nColours);
999             msg->scme.firstColour = htons(msg->scme.firstColour);
1000             int i_datasize;
1001             if ( p_sys->b_alpha_from_vnc )
1002             {
1003                 i_datasize = 2 * msg->scme.nColours * 4;
1004             }
1005             else
1006             {
1007                 i_datasize = 2 * msg->scme.nColours * 3;
1008             }
1009             if ( i_datasize > READ_BUFFER_SIZE )
1010             {
1011                 msg_Err( p_filter, "Buffer too small, need %u bytes",
1012                                    i_datasize );
1013                 return false;
1014             }
1015
1016             if ( !read_exact( p_filter, p_sys->i_socket,
1017                               p_sys->read_buffer, i_datasize ) )
1018             {
1019                 msg_Err( p_filter, "Could not read color map data" );
1020                 return false;
1021             }
1022
1023             uint8_t i_red, i_green, i_blue, i_alpha, i_color_index;
1024             uint16_t i_offset = 0;
1025             i_alpha = 255;
1026
1027             for (int i = 0; i < msg->scme.nColours; i++)
1028             {
1029                 i_color_index = i+msg->scme.firstColour;
1030                 if ( p_sys->b_alpha_from_vnc )
1031                 {
1032                     i_alpha = p_sys->read_buffer[i_offset];
1033                     i_offset += 2;
1034                 }
1035                 i_red   = p_sys->read_buffer[i_offset];
1036                 i_offset += 2;
1037                 i_green = p_sys->read_buffer[i_offset];
1038                 i_offset += 2;
1039                 i_blue  = p_sys->read_buffer[i_offset];
1040                 i_offset += 2;
1041                 rgb_to_yuv( &p_sys->ar_color_table_yuv[i_color_index][0],
1042                             &p_sys->ar_color_table_yuv[i_color_index][1],
1043                             &p_sys->ar_color_table_yuv[i_color_index][2],
1044                             i_red,
1045                             i_green,
1046                             i_blue );
1047                 p_sys->ar_color_table_yuv[i][3] = i_alpha;
1048             }
1049         }
1050         return true;
1051
1052     case rfbBell:
1053         msg_Err( p_filter, "rfbBell received" );
1054         return true;
1055
1056     case rfbServerCutText:
1057         msg->sct.length = htons(msg->sct.length);
1058         if ( msg->sct.length > READ_BUFFER_SIZE )
1059         {
1060             msg_Err( p_filter, "Buffer too small, need %u bytes", msg->sct.length );
1061             return false;
1062         }
1063         if ( !read_exact(p_filter, p_sys->i_socket,
1064                          p_sys->read_buffer, msg->sct.length ) )
1065         {
1066             msg_Err( p_filter, "Could not read Reading rfbServerCutText data" );
1067             return false;
1068         }
1069         return true;
1070
1071     case rfbReSizeFrameBuffer:
1072         msg_Err( p_filter, "Reading rfbReSizeFrameBuffer not implemented" );
1073         return false;
1074
1075     default:
1076         msg_Err( p_filter, "Invalid message %u received", msg->type );
1077         return false;
1078     }
1079     return false;
1080 }
1081
1082 /****************************************************************************
1083  * Filter: the whole thing
1084  ****************************************************************************
1085  * This function outputs subpictures at regular time intervals.
1086  ****************************************************************************/
1087 static subpicture_t *Filter( filter_t *p_filter, mtime_t date )
1088 {
1089     filter_sys_t *p_sys = p_filter->p_sys;
1090     subpicture_t *p_spu;
1091     subpicture_region_t *p_region;
1092     video_format_t fmt;
1093     picture_t *p_pic;
1094
1095     if( !p_sys->b_need_update )
1096     {
1097         return NULL;
1098     }
1099
1100     vlc_mutex_lock( &p_sys->lock );
1101
1102     p_pic = p_sys->p_pic;
1103
1104     if( !p_pic )
1105     {
1106         vlc_mutex_unlock( &p_sys->lock );
1107         return NULL;
1108     }
1109
1110     /* Allocate the subpicture internal data. */
1111     p_spu = filter_NewSubpicture( p_filter );
1112     if( !p_spu )
1113     {
1114         vlc_mutex_unlock( &p_sys->lock );
1115         return NULL;
1116     }
1117
1118     p_spu->b_absolute = false;
1119     p_spu->i_start = date;
1120     p_spu->i_stop = 0;
1121     p_spu->b_ephemer = true;
1122
1123     if( !p_sys->b_continue )
1124         p_spu->i_stop = p_spu->i_start + 1;
1125
1126     /* Create new SPU region */
1127     memset( &fmt, 0, sizeof(video_format_t) );
1128     fmt.i_chroma = VLC_CODEC_YUVA;
1129     fmt.i_sar_num = fmt.i_sar_den = 1;
1130     fmt.i_width = fmt.i_visible_width = p_pic->p[Y_PLANE].i_visible_pitch;
1131     fmt.i_height = fmt.i_visible_height = p_pic->p[Y_PLANE].i_visible_lines;
1132     fmt.i_x_offset = fmt.i_y_offset = 0;
1133     p_region = subpicture_region_New( &fmt );
1134     if( !p_region )
1135     {
1136         msg_Err( p_filter, "cannot allocate SPU region" );
1137         p_filter->pf_sub_buffer_del( p_filter, p_spu );
1138         vlc_mutex_unlock( &p_sys->lock );
1139         return NULL;
1140     }
1141
1142     /* FIXME the copy is probably not needed anymore */
1143     picture_Copy( p_region->p_picture, p_pic );
1144
1145     p_sys->b_need_update = false;
1146
1147     vlc_mutex_unlock( &p_sys->lock );
1148
1149     /* set to one of the 9 relative locations */
1150     p_region->i_align = 0; /* Center */
1151     p_spu->b_absolute = false;
1152
1153
1154     p_spu->i_original_picture_width = 0; /*Let vout core do the horizontal scaling */
1155     p_spu->i_original_picture_height = fmt.i_height;
1156
1157     p_spu->p_region = p_region;
1158
1159     p_spu->i_alpha = ( p_sys->i_alpha );
1160
1161     return p_spu;
1162 }
1163
1164
1165 static inline void rgb_to_yuv( uint8_t *y, uint8_t *u, uint8_t *v,
1166                                int r, int g, int b )
1167 {
1168     *y = ( ( (  66 * r + 129 * g +  25 * b + 128 ) >> 8 ) + 16 );
1169     *u =   ( ( -38 * r -  74 * g + 112 * b + 128 ) >> 8 ) + 128 ;
1170     *v =   ( ( 112 * r -  94 * g -  18 * b + 128 ) >> 8 ) + 128 ;
1171 }
1172
1173 static inline bool fill_rect( filter_sys_t* p_sys,
1174                               uint16_t i_x, uint16_t i_y,
1175                               uint16_t i_w, uint16_t i_h,
1176                               uint8_t i_color)
1177 {
1178     plane_t *p_outY = p_sys->p_pic->p+Y_PLANE;
1179     plane_t *p_outU = p_sys->p_pic->p+U_PLANE;
1180     plane_t *p_outV = p_sys->p_pic->p+V_PLANE;
1181     plane_t *p_outA = p_sys->p_pic->p+A_PLANE;
1182     int i_pitch = p_outY->i_pitch;
1183     int i_lines = p_outY->i_lines;
1184     if ( i_x + i_w > i_pitch)
1185         return false;
1186     if ( i_y + i_h > i_lines)
1187         return false;
1188     int i_line_offset = i_y * i_pitch;
1189     uint8_t i_yuv_y = p_sys->ar_color_table_yuv[i_color][0];
1190     uint8_t i_yuv_u = p_sys->ar_color_table_yuv[i_color][1];
1191     uint8_t i_yuv_v = p_sys->ar_color_table_yuv[i_color][2];
1192     uint8_t i_alpha = p_sys->ar_color_table_yuv[i_color][3];
1193     for( int i_line = 0; i_line < i_h; i_line++ )
1194     {
1195         for( int i_column = 0; i_column < i_w; i_column++ )
1196         {
1197             int i_total_offset = i_line_offset + i_x + i_column;
1198             p_outY->p_pixels[ i_total_offset ] = i_yuv_y;
1199             p_outU->p_pixels[ i_total_offset ] = i_yuv_u;
1200             p_outV->p_pixels[ i_total_offset ] = i_yuv_v;
1201             p_outA->p_pixels[ i_total_offset ] = i_alpha;
1202         }
1203         i_line_offset += i_pitch;
1204     }
1205     return true;
1206 }
1207
1208 static inline bool copy_rect( filter_sys_t* p_sys,
1209                               uint16_t i_x, uint16_t i_y,
1210                               uint16_t i_w, uint16_t i_h,
1211                               uint16_t i_sx, uint16_t i_sy )
1212 {
1213     plane_t *p_Y = p_sys->p_pic->p+Y_PLANE;
1214     plane_t *p_U = p_sys->p_pic->p+U_PLANE;
1215     plane_t *p_V = p_sys->p_pic->p+V_PLANE;
1216     plane_t *p_A = p_sys->p_pic->p+A_PLANE;
1217
1218     int i_pitch = p_Y->i_pitch;
1219     int i_lines = p_Y->i_lines;
1220
1221     fprintf( stderr, "copy_rect: (%d,%d)+(%d,%d) -> (%d,%d)\n", i_x, i_y, i_w, i_h, i_sx, i_sy );
1222
1223     if( i_x + i_w > i_pitch || i_sx + i_w > i_pitch )
1224         return false;
1225     if( i_y + i_h > i_lines || i_sy + i_h > i_lines)
1226         return false;
1227
1228     if( i_w <= 0 || i_h <= 0 )
1229         return true;
1230
1231     uint8_t *pb_buffer = calloc( i_w * i_h, 4 );
1232     if( !pb_buffer )
1233         return false;
1234
1235     for( int i_line = 0; i_line < i_h; i_line++ )
1236     {
1237         for( int i_column = 0; i_column < i_w; i_column++ )
1238         {
1239             const int i_src_offset = ( i_sy + i_line ) * i_pitch + i_sx + i_column;
1240             const int i_tmp_offset = (    0 + i_line ) *     i_w +    0 + i_column;
1241
1242             pb_buffer[4*i_tmp_offset + 0] = p_Y->p_pixels[i_src_offset];
1243             pb_buffer[4*i_tmp_offset + 1] = p_U->p_pixels[i_src_offset];
1244             pb_buffer[4*i_tmp_offset + 2] = p_V->p_pixels[i_src_offset];
1245             pb_buffer[4*i_tmp_offset + 3] = p_A->p_pixels[i_src_offset];
1246         }
1247     }
1248
1249     for( int i_line = 0; i_line < i_h; i_line++ )
1250     {
1251         for( int i_column = 0; i_column < i_w; i_column++ )
1252         {
1253             const int i_tmp_offset = (   0 + i_line ) *     i_w +   0 + i_column;
1254             const int i_dst_offset = ( i_y + i_line ) * i_pitch + i_x + i_column;
1255
1256             p_Y->p_pixels[i_dst_offset] = pb_buffer[4*i_tmp_offset + 0];
1257             p_U->p_pixels[i_dst_offset] = pb_buffer[4*i_tmp_offset + 1];
1258             p_V->p_pixels[i_dst_offset] = pb_buffer[4*i_tmp_offset + 2];
1259             p_A->p_pixels[i_dst_offset] = pb_buffer[4*i_tmp_offset + 3];
1260         }
1261     }
1262     free( pb_buffer );
1263     return true;
1264
1265 }
1266
1267 static inline bool raw_line(  filter_sys_t* p_sys,
1268                               uint16_t i_x, uint16_t i_y,
1269                               uint16_t i_w )
1270 {
1271     plane_t *p_outY = p_sys->p_pic->p+Y_PLANE;
1272     plane_t *p_outU = p_sys->p_pic->p+U_PLANE;
1273     plane_t *p_outV = p_sys->p_pic->p+V_PLANE;
1274     plane_t *p_outA = p_sys->p_pic->p+A_PLANE;
1275     int i_pitch = p_outY->i_pitch;
1276     int i_lines = p_outY->i_lines;
1277     if ( i_x + i_w > i_pitch)
1278         return false;
1279     if ( i_y > i_lines)
1280         return false;
1281
1282     int i_line_offset = i_y * i_pitch + i_x;
1283
1284     for( int i_column = 0; i_column < i_w; i_column++ )
1285     {
1286         int i_offset = i_line_offset + i_column;
1287         uint8_t i_color = p_sys->read_buffer[i_column];
1288         p_outY->p_pixels[ i_offset ] = p_sys->ar_color_table_yuv[i_color][0];
1289         p_outU->p_pixels[ i_offset ] = p_sys->ar_color_table_yuv[i_color][1];
1290         p_outV->p_pixels[ i_offset ] = p_sys->ar_color_table_yuv[i_color][2];
1291         p_outA->p_pixels[ i_offset ] = p_sys->ar_color_table_yuv[i_color][3];
1292     }
1293
1294     return true;
1295 }
1296
1297
1298 /*****************************************************************************
1299  * MouseEvent: callback for mouse events
1300  *****************************************************************************/
1301 static int MouseEvent( filter_t *p_filter,
1302                        const vlc_mouse_t *p_old,
1303                        const vlc_mouse_t *p_new,
1304                        const video_format_t *p_fmt )
1305 {
1306     filter_sys_t *p_sys = p_filter->p_sys;
1307     VLC_UNUSED(p_old);
1308
1309     if( !p_sys->b_vnc_mouse_events )
1310         return VLC_SUCCESS;
1311
1312     int i_v = p_new->i_pressed;
1313     int i_x = p_new->i_x;
1314     int i_y = p_new->i_y;
1315
1316     vlc_mutex_lock( &p_sys->lock );
1317
1318     const int v_h = p_fmt->i_visible_height;
1319     const int v_w = p_sys->i_vnc_width * v_h / p_sys->i_vnc_height;
1320     const int v_x = (p_fmt->i_visible_width-v_w)/2;
1321
1322     i_x -= v_x;
1323
1324     if( i_y < 0 || i_x < 0 || i_y >= v_h || i_x >= v_w )
1325     {
1326         vlc_mutex_unlock( &p_sys->lock );
1327         msg_Dbg( p_filter, "invalid mouse event? x=%d y=%d btn=%x", i_x, i_y, i_v );
1328         return VLC_SUCCESS;
1329     }
1330     if( !p_sys->b_connection_active )
1331     {
1332         vlc_mutex_unlock( &p_sys->lock );
1333         return VLC_SUCCESS;
1334     }
1335
1336 #ifdef VNC_DEBUG
1337     msg_Dbg( p_filter, "mouse event x=%d y=%d btn=%x", i_x, i_y, i_v );
1338 #endif
1339
1340     /* */
1341     i_x = i_x * p_sys->i_vnc_width / v_w;
1342     i_y = i_y * p_sys->i_vnc_height / v_h;
1343
1344     /* buttonMask bits 0-7 are buttons 1-8, 0=up, 1=down */
1345     rfbPointerEventMsg ev;
1346     ev.type = rfbPointerEvent;
1347     ev.buttonMask = i_v;
1348     ev.x = htons(i_x);
1349     ev.y = htons(i_y);
1350
1351     write_exact( p_filter, p_sys->i_socket,
1352                  (char*)&ev, sz_rfbPointerEventMsg);
1353
1354     vlc_mutex_unlock( &p_sys->lock );
1355
1356     return VLC_EGENERIC;
1357 }
1358
1359 /*****************************************************************************
1360  * KeyEvent: callback for keyboard events
1361  *****************************************************************************/
1362 static int KeyEvent( vlc_object_t *p_this, char const *psz_var,
1363                      vlc_value_t oldval, vlc_value_t newval, void *p_data )
1364 {
1365     VLC_UNUSED(psz_var); VLC_UNUSED(oldval);
1366
1367     filter_t *p_filter = (filter_t *)p_data;
1368     filter_sys_t *p_sys = p_filter->p_sys;
1369
1370     if( !p_sys->b_vnc_key_events )
1371         return VLC_SUCCESS;
1372
1373     msg_Dbg( p_this, "key pressed (%"PRId64") ", newval.i_int );
1374
1375     if ( !newval.i_int )
1376     {
1377         msg_Err( p_this, "Received invalid key event 0" );
1378         return VLC_EGENERIC;
1379     }
1380
1381     vlc_mutex_lock( &p_sys->lock );
1382     if( !p_sys->b_connection_active )
1383     {
1384         vlc_mutex_unlock( &p_sys->lock );
1385         return VLC_SUCCESS;
1386     }
1387
1388     uint32_t i_key32 = newval.i_int;
1389     i_key32 = htonl(i_key32);
1390     rfbKeyEventMsg ev;
1391
1392     ev.type = rfbKeyEvent;
1393     ev.down = 1;
1394     ev.pad = 0;
1395
1396     /* first key-down for modifier-keys */
1397     if (newval.i_int & KEY_MODIFIER_CTRL)
1398     {
1399         ev.key = 0xffe3;
1400         write_exact( p_filter, p_sys->i_socket,
1401                      (char*)&ev, sz_rfbKeyEventMsg);
1402     }
1403     if (newval.i_int & KEY_MODIFIER_SHIFT)
1404     {
1405         ev.key = 0xffe1;
1406         write_exact( p_filter, p_sys->i_socket,
1407                      (char*)&ev, sz_rfbKeyEventMsg);
1408     }
1409     if (newval.i_int & KEY_MODIFIER_ALT)
1410     {
1411         ev.key = 0xffe9;
1412         write_exact( p_filter, p_sys->i_socket,
1413                      (char*)&ev, sz_rfbKeyEventMsg);
1414     }
1415
1416     /* then key-down for the pressed key */
1417     ev.key = i_key32;
1418     write_exact( p_filter, p_sys->i_socket,
1419                  (char*)&ev, sz_rfbKeyEventMsg);
1420
1421     ev.down = 0;
1422
1423     /* then key-up for the pressed key */
1424     write_exact( p_filter, p_sys->i_socket,
1425                  (char*)&ev, sz_rfbKeyEventMsg);
1426
1427     /* last key-down for modifier-keys */
1428     if (newval.i_int & KEY_MODIFIER_CTRL)
1429     {
1430         ev.key = 0xffe3;
1431         write_exact( p_filter, p_sys->i_socket,
1432                      (char*)&ev, sz_rfbKeyEventMsg);
1433     }
1434     if (newval.i_int & KEY_MODIFIER_SHIFT)
1435     {
1436         ev.key = 0xffe1;
1437         write_exact( p_filter, p_sys->i_socket,
1438                      (char*)&ev, sz_rfbKeyEventMsg);
1439     }
1440     if (newval.i_int & KEY_MODIFIER_ALT)
1441     {
1442        ev.key = 0xffe9;
1443        write_exact( p_filter, p_sys->i_socket,
1444                     (char*)&ev, sz_rfbKeyEventMsg);
1445     }
1446     vlc_mutex_unlock( &p_sys->lock );
1447
1448     return VLC_SUCCESS;
1449 }
1450
1451 static void vnc_encrypt_bytes( unsigned char *bytes, char *passwd )
1452 {
1453     unsigned char key[8];
1454     unsigned int i;
1455
1456     for (i = 0; i < 8; i++)
1457         key[i] = i < strlen( passwd ) ? passwd[i] : '\0';
1458
1459     gcry_cipher_hd_t ctx;
1460     gcry_cipher_open( &ctx, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB,0);
1461
1462     /* reverse bits of the key */
1463     for( i = 0 ; i < 8 ; i ++ )
1464         key[i] =
1465             (key[i] >> 7) +
1466             (((key[i] >> 6) & 0x01 ) << 1 ) +
1467             (((key[i] >> 5) & 0x01 ) << 2 ) +
1468             (((key[i] >> 4) & 0x01 ) << 3 ) +
1469             (((key[i] >> 3) & 0x01 ) << 4 ) +
1470             (((key[i] >> 2) & 0x01 ) << 5 ) +
1471             (((key[i] >> 1) & 0x01 ) << 6 ) +
1472             ((key[i] & 0x01) << 7 );
1473
1474     gcry_cipher_setkey( ctx, key, 8 );
1475     gcry_cipher_encrypt( ctx, bytes, CHALLENGESIZE, bytes, CHALLENGESIZE );
1476     gcry_cipher_close( ctx );
1477 }
1478