Added plugin RemoteOSD, a VNC client as video-filter
authorMatthias Bauer <smile4you@gmx.ch>
Sun, 8 Jun 2008 07:41:49 +0000 (09:41 +0200)
committerRafaël Carré <funman@videolan.org>
Sun, 8 Jun 2008 23:49:07 +0000 (01:49 +0200)
Signed-off-by: Rafaël Carré <funman@videolan.org>
configure.ac
modules/video_filter/Modules.am
modules/video_filter/remoteosd.c [new file with mode: 0755]
modules/video_filter/remoteosd_rfbproto.h [new file with mode: 0755]

index 89b793f..bbcd5d4 100644 (file)
@@ -313,13 +313,13 @@ case "${host_os}" in
         VLC_ADD_LDFLAGS([vlc],[-mwindows])
         VLC_ADD_LIBS([activex mozilla],[-lgdi32])
         VLC_ADD_LIBS([cdda vcdx cddax sdl_image],[-lwinmm])
-        VLC_ADD_LIBS([access_http access_mms access_udp access_tcp access_ftp access_rtmp access_output_udp access_output_shout access_output_rtmp sap slp http stream_out_standard stream_out_rtp vod_rtsp access_realrtsp rtp telnet rc netsync gnutls growl_udp flac ts audioscrobbler lua],[-lws2_32])
+        VLC_ADD_LIBS([access_http access_mms access_udp access_tcp access_ftp access_rtmp access_output_udp access_output_shout access_output_rtmp sap slp http stream_out_standard stream_out_rtp vod_rtsp access_realrtsp rtp telnet rc netsync gnutls growl_udp flac ts audioscrobbler lua remoteosd],[-lws2_32])
     fi
     if test "${SYS}" = "mingwce"; then
         # add ws2 for closesocket, select, recv
         VLC_ADD_CPPFLAGS([libvlc vlc],[-Dmain(a,b)=maince(a,b)])
         VLC_ADD_LDFLAGS([libvlc vlc],[-e WinMainCRTStartup])
-        VLC_ADD_LIBS([libvlc access_http access_mms access_udp access_tcp access_ftp access_rtmp access_output_udp sap http netsync audioscrobbler growl rtp stream_out_rtp],[-lws2])
+        VLC_ADD_LIBS([libvlc access_http access_mms access_udp access_tcp access_ftp access_rtmp access_output_udp sap http netsync audioscrobbler growl rtp stream_out_rtp remoteosd],[-lws2])
         VLC_ADD_LIBS([libvlc],[-lmmtimer])
    fi
     ;;
@@ -518,7 +518,7 @@ AC_CHECK_FUNCS(connect,,[
 
 AC_CHECK_FUNCS(send,,[
   AC_CHECK_LIB(socket,send,[
-    VLC_ADD_LIBS([access_http access_mms access_udp access_tcp access_ftp access_rtmp sap access_output_udp access_output_rtmp stream_out_standard growl_udp],[-lsocket])
+    VLC_ADD_LIBS([access_http access_mms access_udp access_tcp access_ftp access_rtmp sap access_output_udp access_output_rtmp stream_out_standard growl_udp remoteosd],[-lsocket])
   ])
 ])
 
@@ -5338,6 +5338,24 @@ AS_IF([test "${enable_gnutls}" != "no"], [
   ])
 ])
 
+
+dnl
+dnl RemoteOSD plugin (VNC client as video filter)
+dnl
+AC_ARG_ENABLE(remoteosd,
+  [  --disable-remoteosd         RemoteOSD plugin (default enabled)])
+
+AS_IF([test "${enable_remoteosd}" != "no"], [
+  AS_IF([test "${have_libgcrypt}" = "yes"],[
+    VLC_ADD_PLUGIN([remoteosd])
+    VLC_ADD_LIBS([remoteosd], ${GCRYPT_LIBS})
+    VLC_ADD_CFLAGS([remoteosd], ${GCRYPT_CFLAGS})
+  ], [
+    AC_MSG_ERROR([libgcrypt support required for RemoteOSD plugin])
+  ])
+])
+
+
 dnl
 dnl update checking system
 dnl
index 4c83dca..70aa5b0 100644 (file)
@@ -16,6 +16,7 @@ SOURCES_rss = rss.c
 SOURCES_motiondetect = motiondetect.c
 SOURCES_rv32 = rv32.c
 SOURCES_osdmenu = osdmenu.c
+SOURCES_remoteosd = remoteosd.c remoteosd_rfbproto.h
 SOURCES_magnify = magnify.c
 SOURCES_wave = wave.c
 SOURCES_ripple = ripple.c
diff --git a/modules/video_filter/remoteosd.c b/modules/video_filter/remoteosd.c
new file mode 100755 (executable)
index 0000000..239d3b7
--- /dev/null
@@ -0,0 +1,1425 @@
+/*****************************************************************************
+ * remoteosd.c: remote osd over vnc filter module
+ *****************************************************************************
+ * Copyright (C) 2007-2008 Matthias Bauer
+ * $Id$
+ *
+ * Authors: Matthias Bauer <matthias dot bauer #_at_# gmx dot ch>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implid warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+/*****************************************************************************
+ * RemoteOSD uses the RFB-Protocol of VNC to display an On-Screen-Display
+ * menu generated by a streaming server as overlay for the streamed video.
+ *
+ * The streaming server that implements this is the ffnetdev plugin for VDR.
+ * VDR (VideoDiskRecorder) is an Linux based OpenSource harddisk recorder
+ * software.
+ * The VDR ffnetdev plugin emulates the hardware MPEG decoder and streams the
+ * video over the network instead of hardware video outputs.
+ * The OSD menu of VDR is offered with the RFB protocol to a VNC client.
+ *
+ * In fact this video-filter is a simple VNC client that could be also used to
+ * connect to a real VNC host.
+ * Only 8-bit color is supported at the moment.
+ * Using password protected VNC hosts is supported but not recommended, because
+ * you need to insert the used password in the plugin configuration page of
+ * VLC configuration in plain text and it's saved in plain text.
+ *****************************************************************************/
+
+//#define VNC_DEBUG
+
+/*****************************************************************************
+ * Preamble
+ *****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <vlc_common.h>
+#include <vlc_plugin.h>
+#include <vlc_vout.h>
+
+#include "vlc_filter.h"
+#include "filter_common.h"
+#include "vlc_image.h"
+#include "vlc_osd.h"
+#include "vlc_keys.h"
+
+#include <vlc_network.h>
+#include <gcrypt.h>              /* to encrypt password */
+#include <vlc_gcrypt.h>
+
+#define CHALLENGESIZE 16
+#define MAX_VNC_SERVER_NAME_LENGTH 255
+
+#include "remoteosd_rfbproto.h" /* type definitions of the RFB protocol for VNC */
+
+/*****************************************************************************
+ * Local prototypes
+ *****************************************************************************/
+/* subfilter functions */
+static int  CreateFilter ( vlc_object_t * );
+static void DestroyFilter( vlc_object_t * );
+static subpicture_t *Filter( filter_t *, mtime_t );
+
+static int MouseEvent ( vlc_object_t *p_this, char const *psz_var,
+                        vlc_value_t oldval, vlc_value_t newval, void *p_data );
+
+static int KeyEvent( vlc_object_t *p_this, char const *psz_var,
+                     vlc_value_t oldval, vlc_value_t newval, void *p_data );
+
+static void stop_osdvnc ( filter_t *p_filter );
+
+static void vnc_worker_thread ( vlc_object_t *p_thread_obj );
+
+static void update_request_thread( vlc_object_t *p_thread_obj );
+
+static bool open_vnc_connection ( filter_t *p_filter );
+
+static bool handshaking ( filter_t *p_filter );
+
+static bool process_server_message ( filter_t *p_filter,
+                                     rfbServerToClientMsg *msg );
+
+static bool read_exact( filter_t *p_filter,
+                        int i_socket,
+                        char* p_readbuf,
+                        int i_bytes );
+
+static bool write_exact( filter_t *p_filter,
+                         int i_socket,
+                         char* p_writebuf,
+                         int i_bytes );
+
+static inline void rgb_to_yuv( uint8_t *y, uint8_t *u, uint8_t *v,
+                               int r, int g, int b );
+
+static inline bool fill_rect( filter_sys_t* p_sys,
+                              uint16_t i_x, uint16_t i_y,
+                              uint16_t i_w, uint16_t i_h,
+                              uint8_t i_color );
+
+static inline bool raw_line(  filter_sys_t* p_sys,
+                              uint16_t i_x, uint16_t i_y,
+                              uint16_t i_w );
+
+static void vnc_encrypt_bytes( unsigned char *bytes, char *passwd );
+
+
+/*****************************************************************************
+ * Module descriptor
+ *****************************************************************************/
+#define READ_BUFFER_SIZE 1000000
+
+#define RMTOSD_HOST_TEXT N_("VNC Host")
+#define RMTOSD_HOST_LONGTEXT N_( \
+    "VNC hostname or IP address." )
+
+#define RMTOSD_PORT_TEXT N_("VNC Port")
+#define RMTOSD_PORT_LONGTEXT N_( \
+    "VNC portnumber." )
+
+#define RMTOSD_PASSWORD_TEXT N_("VNC Password")
+#define RMTOSD_PASSWORD_LONGTEXT N_( \
+    "VNC password." )
+
+#define RMTOSD_UPDATE_TEXT N_("VNC poll interval" )
+#define RMTOSD_UPDATE_LONGTEXT N_( \
+    "In this interval an update from VNC is requested, default every 300 ms. ")
+
+#define RMTOSD_POLL_TEXT N_("VNC polling")
+#define RMTOSD_POLL_LONGTEXT N_( \
+    "Activate VNC polling. Do NOT activate for use as VDR ffnetdev client." )
+
+#define RMTOSD_MOUSE_TEXT N_("Mouse events")
+#define RMTOSD_MOUSE_LONGTEXT N_( \
+    "Send mouse events to VNC host. Not needed for use as VDR ffnetdev client." )
+
+#define RMTOSD_KEYS_TEXT N_("Key events")
+#define RMTOSD_KEYS_LONGTEXT N_( \
+    "Send key events to VNC host." )
+
+#define RMTOSD_ALPHA_TEXT N_("Alpha transparency value (default 255)")
+#define RMTOSD_ALPHA_LONGTEXT N_( \
+    "The transparency of the OSD VNC can be changed by giving a value " \
+    "between 0 and 255. A lower value specifies more transparency a higher " \
+    "means less transparency. The default is being not transparent " \
+    "(value 255) the minimum is fully transparent (value 0)." )
+
+#define RMTOSD_CFG "rmtosd-"
+
+#define RMTOSD_UPDATE_MIN     200
+#define RMTOSD_UPDATE_DEFAULT 1000
+#define RMTOSD_UPDATE_MAX     300
+
+
+vlc_module_begin();
+    set_description( N_("Remote-OSD over VNC") );
+    set_capability( "sub filter", 100 );
+    set_shortname( N_("Remote-OSD") );
+    set_category( CAT_VIDEO );
+    set_subcategory( SUBCAT_VIDEO_SUBPIC );
+    add_shortcut( "rmtosd" );
+    set_callbacks( CreateFilter, DestroyFilter );
+
+    add_string( RMTOSD_CFG "host", "myvdr", NULL, RMTOSD_HOST_TEXT,
+        RMTOSD_HOST_LONGTEXT, false );
+    add_integer_with_range( RMTOSD_CFG "port", 20001, 1, 0xFFFF, NULL,
+        RMTOSD_PORT_TEXT, RMTOSD_PORT_LONGTEXT, false );
+    add_password( RMTOSD_CFG "password", "", NULL, RMTOSD_PASSWORD_TEXT,
+        RMTOSD_PASSWORD_LONGTEXT, false );
+    add_integer_with_range( RMTOSD_CFG "update", RMTOSD_UPDATE_DEFAULT,
+        RMTOSD_UPDATE_MIN, RMTOSD_UPDATE_MAX, NULL, RMTOSD_UPDATE_TEXT,
+        RMTOSD_UPDATE_LONGTEXT, true );
+    add_bool( RMTOSD_CFG "vnc-polling", 0, NULL,
+              RMTOSD_POLL_TEXT , RMTOSD_POLL_LONGTEXT, false );
+    add_bool( RMTOSD_CFG "mouse-events", 0, NULL,
+              RMTOSD_MOUSE_TEXT , RMTOSD_MOUSE_LONGTEXT, false );
+    add_bool( RMTOSD_CFG "key-events", 0, NULL,
+              RMTOSD_KEYS_TEXT , RMTOSD_KEYS_LONGTEXT, false );
+    add_integer_with_range( RMTOSD_CFG "alpha", 255, 0, 255, NULL,
+        RMTOSD_ALPHA_TEXT, RMTOSD_ALPHA_LONGTEXT, true );
+
+vlc_module_end();
+
+/*****************************************************************************
+ * Sub filter code
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Local prototypes
+ *****************************************************************************/
+struct filter_sys_t
+{
+    VLC_COMMON_MEMBERS
+
+    bool          b_need_update;       /* VNC picture is updated, do update the OSD*/
+    mtime_t       i_vnc_poll_interval; /* Update the OSD menu every n ms */
+
+    uint8_t       i_alpha;             /* alpha transparency value */
+
+    char          *psz_host;           /* VNC host */
+    int           i_port;
+
+    char          *psz_passwd;         /* VNC password */
+
+    bool          b_vnc_poll;          /* Activate VNC polling ? */
+    bool          b_vnc_mouse_events;  /* Send MouseEvents ? */
+    bool          b_vnc_key_events;    /* Send KeyEvents ? */
+
+    bool          b_connection_active; /* Handshaking finished ? */
+
+    vlc_mutex_t   lock;                /* To lock for read/write on picture */
+
+    picture_t     *p_pic;              /* The picture with OSD data from VNC */
+
+    vout_thread_t *p_vout;             /* Pointer to video-out thread */
+
+    int           i_socket;            /* Socket used for VNC */
+
+    uint16_t      i_vnc_width;          /* The with of the VNC screen */
+    uint16_t      i_vnc_height;         /* The height of the VNC screen */
+       uint32_t      i_vnc_pixels;         /* The pixels of the VNC screen */
+
+    bool    b_alpha_from_vnc;    /* Special ffnetdev alpha feature enabled ? */
+
+    char          read_buffer[READ_BUFFER_SIZE];
+
+    bool          b_continue;
+
+    vlc_object_t* p_worker_thread;
+    vlc_object_t* p_update_request_thread;
+
+    uint8_t       ar_color_table_yuv[256][4];
+};
+
+/*****************************************************************************
+ * CreateFilter: Create the filter and open the definition file
+ *****************************************************************************/
+static int CreateFilter ( vlc_object_t *p_this )
+{
+    filter_t *p_filter = (filter_t *)p_this;
+    filter_sys_t *p_sys = NULL;
+
+    msg_Dbg( p_filter, "Creating vnc osd filter..." );
+
+    p_filter->p_sys = p_sys = (filter_sys_t *) malloc( sizeof(filter_sys_t) );
+    if( !p_filter->p_sys )
+    {
+        msg_Err( p_filter, "out of memory" );
+        return VLC_ENOMEM;
+    }
+    memset( p_sys, 0, sizeof(filter_sys_t) );
+
+    /* Populating struct */
+    vlc_mutex_init( &p_sys->lock );
+    p_sys->b_continue = true;
+    p_sys->i_socket = -1;
+
+    p_sys->psz_host = var_CreateGetString( p_this, RMTOSD_CFG "host" );
+    if( EMPTY_STR(p_sys->psz_host) )
+    {
+        msg_Err( p_filter, "unable to get vnc host" );
+        goto error;
+    }
+
+    p_sys->psz_passwd = var_CreateGetString( p_this, RMTOSD_CFG "password" );
+    if( !p_sys->psz_passwd )
+    {
+        msg_Err( p_filter, "unable to get vnc password" );
+        goto error;
+    }
+
+    p_sys->i_port = var_CreateGetIntegerCommand( p_this, RMTOSD_CFG "port" );
+
+    p_sys->i_alpha = var_CreateGetIntegerCommand( p_this, RMTOSD_CFG "alpha" );
+
+    /* in miliseconds, 0 disables polling, should not be lower than 100 */
+    p_sys->i_vnc_poll_interval  = var_CreateGetIntegerCommand( p_this,
+                                                       RMTOSD_CFG "update" );
+    if ( p_sys->i_vnc_poll_interval < 100)
+    {
+       p_sys->i_vnc_poll_interval = 100;
+    }
+
+    for ( int i = 0; i < 256; i++ )
+    {
+        p_sys->ar_color_table_yuv[i][0] = 255;
+        p_sys->ar_color_table_yuv[i][1] = 255;
+        p_sys->ar_color_table_yuv[i][2] = 255;
+        p_sys->ar_color_table_yuv[i][3] = 255;
+    }
+
+    p_sys->b_vnc_poll = var_CreateGetBoolCommand( p_this,
+                                            RMTOSD_CFG "vnc-polling" );
+    p_sys->b_vnc_mouse_events = var_CreateGetBoolCommand( p_this,
+                                            RMTOSD_CFG "mouse-events" );
+    p_sys->b_vnc_key_events = var_CreateGetBoolCommand( p_this,
+                                            RMTOSD_CFG "key-events" );
+
+    /* Keep track of OSD Events */
+    p_sys->b_need_update  = false;
+
+    /* Attach subpicture filter callback */
+    p_filter->pf_sub_filter = Filter;
+
+    p_sys->p_vout = vlc_object_find( p_this, VLC_OBJECT_VOUT, FIND_PARENT );
+
+    if( p_sys->p_vout )
+    {
+        var_AddCallback( p_sys->p_vout, "mouse-moved",
+                         MouseEvent, p_this );
+        var_AddCallback( p_sys->p_vout, "mouse-button-down",
+                         MouseEvent, p_this );
+        var_AddCallback( p_sys->p_vout->p_libvlc, "key-pressed",
+                         KeyEvent, p_this );
+    }
+
+    es_format_Init( &p_filter->fmt_out, SPU_ES, VLC_FOURCC( 's','p','u',' ' ) );
+    p_filter->fmt_out.i_priority = 0;
+
+    /* create the vnc worker thread */
+    p_sys->p_worker_thread = vlc_object_create( p_this, VLC_OBJECT_GENERIC );
+    vlc_object_attach( p_sys->p_worker_thread, p_this );
+    if( vlc_thread_create( p_sys->p_worker_thread, "vnc worker thread",
+                           vnc_worker_thread,
+                           VLC_THREAD_PRIORITY_LOW, false ) )
+    {
+        vlc_object_detach( p_sys->p_worker_thread );
+        vlc_object_release( p_sys->p_worker_thread );
+        p_sys->p_worker_thread = NULL;
+        msg_Err( p_filter, "cannot spawn vnc message reader thread" );
+        goto error;
+    }
+
+    msg_Dbg( p_filter, "osdvnc filter started" );
+
+    return VLC_SUCCESS;
+
+error:
+    msg_Err( p_filter, "osdvnc filter discarded" );
+
+    p_sys->b_continue = false;
+
+    stop_osdvnc( p_filter );
+
+    free( p_sys->psz_host );
+    free( p_sys->psz_passwd );
+    free( p_sys );
+
+    return VLC_EGENERIC;
+}
+
+/*****************************************************************************
+ * DestroyFilter: Make a clean exit of this plugin
+ *****************************************************************************/
+static void DestroyFilter( vlc_object_t *p_this )
+{
+    filter_t     *p_filter = (filter_t*)p_this;
+    filter_sys_t *p_sys = p_filter->p_sys;
+
+    msg_Dbg( p_filter, "DestroyFilter called." );
+
+    stop_osdvnc( p_filter );
+
+    if( p_sys->p_vout )
+    {
+        var_DelCallback( p_sys->p_vout, "mouse-moved",
+                         MouseEvent, p_this );
+        var_DelCallback( p_sys->p_vout, "mouse-button-down",
+                         MouseEvent, p_this );
+        var_DelCallback( p_sys->p_vout->p_libvlc, "key-pressed",
+                         KeyEvent, p_this );
+
+        vlc_object_release( p_sys->p_vout );
+        p_sys->p_vout = NULL;
+    }
+
+    var_Destroy( p_this, RMTOSD_CFG "host" );
+    var_Destroy( p_this, RMTOSD_CFG "port" );
+    var_Destroy( p_this, RMTOSD_CFG "password" );
+    var_Destroy( p_this, RMTOSD_CFG "update" );
+    var_Destroy( p_this, RMTOSD_CFG "vnc-polling" );
+    var_Destroy( p_this, RMTOSD_CFG "mouse-events" );
+    var_Destroy( p_this, RMTOSD_CFG "key-events" );
+    var_Destroy( p_this, RMTOSD_CFG "alpha" );
+
+    free( p_sys->psz_host );
+    free( p_sys->psz_passwd );
+    free( p_sys );
+}
+
+static void stop_osdvnc ( filter_t *p_filter )
+{
+    filter_sys_t *p_sys = p_filter->p_sys;
+
+    if (p_sys->i_socket >= 0)
+    {
+        net_Close(p_sys->i_socket);
+    }
+    p_sys->b_continue = false; /* this causes the threads to stop */
+
+    if ( p_sys->p_worker_thread )
+    {
+        msg_Dbg( p_filter, "joining worker_thread" );
+        vlc_thread_join( p_sys->p_worker_thread );
+        vlc_object_detach( p_sys->p_worker_thread );
+        vlc_object_release( p_sys->p_worker_thread );
+        msg_Dbg( p_filter, "released worker_thread" );
+    }
+
+    if ( p_sys->p_update_request_thread )
+    {
+        msg_Dbg( p_filter, "joining update_request_thread" );
+        vlc_thread_join( p_sys->p_update_request_thread );
+        vlc_object_detach( p_sys->p_update_request_thread );
+        vlc_object_release( p_sys->p_update_request_thread );
+        msg_Dbg( p_filter, "released update_request_thread" );
+    }
+
+    msg_Dbg( p_filter, "osdvnc stopped" );
+}
+
+static bool read_exact( filter_t *p_filter,
+                        int i_socket,
+                        char* p_readbuf,
+                        int i_bytes )
+{
+    return i_bytes == net_Read( p_filter, i_socket, NULL,
+                                  (unsigned char*)p_readbuf,
+                                  i_bytes, true );
+}
+
+
+static bool write_exact( filter_t *p_filter,
+                         int i_socket,
+                         char* p_writebuf,
+                         int i_bytes )
+{
+    return i_bytes == net_Write( p_filter, i_socket, NULL,
+                                  (unsigned char*)p_writebuf, i_bytes );
+}
+
+static bool open_vnc_connection ( filter_t *p_filter )
+{
+    filter_sys_t *p_sys = p_filter->p_sys;
+
+    msg_Dbg( p_filter, "Open socket to vnc server on %s:%u.",
+              p_sys->psz_host, p_sys->i_port );
+
+    p_sys->i_socket = net_ConnectTCP( p_filter, p_sys->psz_host, p_sys->i_port );
+
+    if( p_sys->i_socket < 0 )
+    {
+        msg_Err( p_filter, "Could not open socket" );
+        return false;
+    }
+
+    msg_Dbg( p_filter, "socket is open." );
+
+    return true;
+}
+
+static bool handshaking ( filter_t *p_filter )
+{
+    filter_sys_t *p_sys = p_filter->p_sys;
+
+    msg_Dbg( p_filter, "Reading protocol version" );
+
+    rfbProtocolVersionMsg pv;
+    if ( !read_exact( p_filter, p_sys->i_socket, pv,
+                      sz_rfbProtocolVersionMsg ) )
+    {
+        msg_Err( p_filter, "Could not read version message" );
+        return false;
+    }
+    pv[sz_rfbProtocolVersionMsg] = '\0'; /* pv size is sz_rfbProtocolVersionMsg+1 */
+
+    msg_Dbg( p_filter, "Server version is %s", pv );
+
+    strncpy(pv, "RFB 003.003\n", sz_rfbProtocolVersionMsg);
+
+    if( !write_exact(p_filter, p_sys->i_socket, pv,
+                     sz_rfbProtocolVersionMsg) )
+    {
+        msg_Err( p_filter, "Could not write version message" );
+        return false;
+    }
+
+    msg_Dbg( p_filter, "Reading authentication scheme" );
+    uint32_t i_authScheme;
+    if( !read_exact( p_filter, p_sys->i_socket, (char*)&i_authScheme, 4 ) )
+    {
+        msg_Err( p_filter, "Could not read authentication scheme" );
+        return false;
+    }
+    i_authScheme = htonl(i_authScheme);
+
+    msg_Dbg( p_filter, "Authentication scheme = %x", i_authScheme );
+    if ( i_authScheme == rfbConnFailed )
+    {
+        msg_Err( p_filter, "Connection rejected by server" );
+        return false;
+    }
+    if (i_authScheme == rfbVncAuth)
+    {
+        unsigned char challenge[CHALLENGESIZE];
+        if ( !read_exact( p_filter, p_sys->i_socket,
+                          (char*)challenge, CHALLENGESIZE ) )
+        {
+            msg_Err( p_filter, "Could not read password challenge" );
+            return false;
+        }
+
+        vnc_encrypt_bytes( challenge, p_sys->psz_passwd );
+
+        if( !write_exact(p_filter, p_sys->i_socket,
+                         (char*)challenge, CHALLENGESIZE ) )
+        {
+            msg_Err( p_filter, "Could not write password" );
+            return false;
+        }
+        uint32_t i_authResult;
+        if( !read_exact( p_filter, p_sys->i_socket, (char*)&i_authResult, 4 ) )
+        {
+            msg_Err( p_filter, "Could not read authentication result" );
+            return false;
+        }
+        i_authResult = htonl(i_authResult);
+        if (i_authResult != rfbVncAuthOK)
+        {
+            msg_Err( p_filter, "VNC authentication failed" );
+            return false;
+        }
+    }
+
+    msg_Dbg( p_filter, "Writing client init message" );
+    rfbClientInitMsg ci;
+    ci.shared = 1;
+    if( !write_exact( p_filter, p_sys->i_socket,
+                      (char*)&ci, sz_rfbClientInitMsg ) )
+    {
+        msg_Err( p_filter, "Could not write client init message" );
+        return false;
+    }
+
+    msg_Dbg( p_filter, "Reading server init message" );
+    rfbServerInitMsg si;
+    if( !read_exact( p_filter, p_sys->i_socket,
+                     (char*)&si, sz_rfbServerInitMsg ) )
+    {
+        msg_Err( p_filter, "Could not read server init message" );
+        return false;
+    }
+    si.framebufferWidth = htons(si.framebufferWidth);
+    si.framebufferHeight = htons(si.framebufferHeight);
+    si.format.redMax = htons(si.format.redMax);
+    si.format.greenMax = htons(si.format.greenMax);
+    si.format.blueMax = htons(si.format.blueMax);
+
+    p_sys->i_vnc_width = si.framebufferWidth;
+    p_sys->i_vnc_height = si.framebufferHeight;
+
+    msg_Dbg( p_filter, "Servers preferred pixelformat: "
+                        "%ux%u, R(%u),G(%u),B(%u), %u bit, depht=%u, %s",
+                        si.framebufferWidth,
+                        si.framebufferHeight,
+                        si.format.redMax,
+                        si.format.greenMax,
+                        si.format.blueMax,
+                        si.format.bitsPerPixel,
+                        si.format.depth,
+                        si.format.trueColour ? "TrueColor" : "Not-TrueColor");
+
+    uint32_t i_nameLength = htonl(si.nameLength);
+    if( i_nameLength > MAX_VNC_SERVER_NAME_LENGTH )
+    {
+        msg_Err( p_filter, "Server name too long" );
+        return false;
+    }
+    char s_ServerName[MAX_VNC_SERVER_NAME_LENGTH+1];
+
+    msg_Dbg( p_filter, "Reading server name with size = %u", i_nameLength );
+    if( !read_exact( p_filter, p_sys->i_socket, s_ServerName, i_nameLength ) )
+    {
+        msg_Err( p_filter, "Could not read server name" );
+        return false;
+    }
+    s_ServerName[i_nameLength] = '\0';
+
+    if( strcmp( s_ServerName, "VDR-OSD") == 0 )
+    {
+        msg_Dbg( p_filter, "Server is a VDR" );
+        p_sys->b_alpha_from_vnc = true;
+    }
+    else
+    {
+        msg_Dbg( p_filter, "Server is a normal VNC" );
+        p_sys->b_alpha_from_vnc = false;
+    }
+
+
+    msg_Dbg( p_filter, "Server init message read properly" );
+    msg_Dbg( p_filter, "Server name is %s", s_ServerName );
+
+    msg_Dbg( p_filter, "Writing SetPixelFormat message" );
+
+    rfbSetPixelFormatMsg sp;
+    sp.type = rfbSetPixelFormat;
+    sp.format.bitsPerPixel = 8;
+    sp.format.depth = 8 ;
+    sp.format.bigEndian = 1;
+    sp.format.trueColour = 0;
+    sp.format.redMax = htons(31);
+    sp.format.greenMax = htons(31);
+    sp.format.blueMax = htons(31);
+    sp.format.redShift = 10;
+    sp.format.greenShift = 5;
+    sp.format.blueShift = 0;
+
+    if( !write_exact( p_filter, p_sys->i_socket,
+                      (char*)&sp, sz_rfbSetPixelFormatMsg) )
+    {
+        msg_Err( p_filter, "Could not write SetPixelFormat message" );
+        return false;
+    }
+
+    msg_Dbg( p_filter, "Writing SetEncodings message" );
+
+    rfbSetEncodingsMsg se;
+    se.type = rfbSetEncodings;
+    se.nEncodings = htons( p_sys->b_alpha_from_vnc ? 3 : 2 );
+
+    if( !write_exact( p_filter, p_sys->i_socket,
+                      (char*)&se, sz_rfbSetEncodingsMsg) )
+    {
+        msg_Err( p_filter, "Could not write SetEncodings message begin" );
+        return false;
+    }
+
+    uint32_t i_encoding;
+
+    msg_Dbg( p_filter, "Writing SetEncodings rfbEncodingCopyRect" );
+    i_encoding = htonl(rfbEncodingCopyRect);
+    if( !write_exact( p_filter, p_sys->i_socket, (char*)&i_encoding, 4) )
+    {
+        msg_Err( p_filter, "Could not write encoding type rfbEncodingCopyRect." );
+        return false;
+    }
+
+    msg_Dbg( p_filter, "Writing SetEncodings rfbEncodingRRE" );
+    i_encoding = htonl(rfbEncodingRRE);
+    if( !write_exact(p_filter, p_sys->i_socket, (char*)&i_encoding, 4) )
+    {
+        msg_Err( p_filter, "Could not write encoding type rfbEncodingRRE." );
+        return false;
+    }
+
+    if( p_sys->b_alpha_from_vnc )
+    {
+        msg_Dbg( p_filter, "Writing SetEncodings rfbEncSpecialUseAlpha" );
+        i_encoding = 0x00F0FFFF; /* rfbEncSpecialUseAlpha is 0xFFFFF000
+                                  * before we swap it */
+        if( !write_exact(p_filter, p_sys->i_socket, (char*)&i_encoding, 4) )
+        {
+            msg_Err( p_filter, "Could not write encoding type rfbEncSpecialUseAlpha." );
+            return false;
+        }
+    }
+    return true;
+
+}
+
+static void vnc_worker_thread( vlc_object_t *p_thread_obj )
+{
+    filter_t* p_filter = (filter_t*)(p_thread_obj->p_parent);
+    filter_sys_t *p_sys = p_filter->p_sys;
+
+    msg_Dbg( p_filter, "VNC worker thread started" );
+
+    if ( open_vnc_connection ( p_filter ) == false )
+    {
+        msg_Err( p_filter, "Could not connect to vnc host" );
+        return;
+    }
+
+    if ( handshaking ( p_filter ) == false )
+    {
+        msg_Err( p_filter, "Error occured while handshaking vnc host" );
+        return;
+    }
+
+    p_sys->b_connection_active = true; /* to enable sending key
+                                            * and mouse events to host */
+
+    /* Create an empty picture for VNC the data */
+    vlc_mutex_lock( &p_sys->lock );
+    p_sys->p_pic = malloc( sizeof(picture_t) );
+    if( !p_sys->p_pic )
+    {
+        vlc_mutex_unlock( &p_sys->lock );
+        return;
+    }
+    vout_AllocatePicture( VLC_OBJECT(p_filter), p_sys->p_pic,
+                          VLC_FOURCC('Y','U','V','A'),
+                          p_sys->i_vnc_width,
+                          p_sys->i_vnc_height,
+                          VOUT_ASPECT_FACTOR );
+    if( !p_sys->p_pic->i_planes )
+    {
+        free( p_sys->p_pic );
+        p_sys->p_pic = NULL;
+        vlc_mutex_unlock( &p_sys->lock );
+        return;
+    }
+       p_sys->i_vnc_pixels = p_sys->i_vnc_width * p_sys->i_vnc_height;
+
+    vlc_mutex_unlock( &p_sys->lock );
+
+    /* create the update request thread */
+    p_sys->p_update_request_thread = vlc_object_create( p_filter,
+                                                        VLC_OBJECT_GENERIC );
+    vlc_object_attach( p_sys->p_update_request_thread, p_filter );
+    if( vlc_thread_create( p_sys->p_update_request_thread,
+                           "vnc update request thread",
+                           update_request_thread,
+                           VLC_THREAD_PRIORITY_LOW, false ) )
+    {
+        vlc_object_detach( p_sys->p_update_request_thread );
+        vlc_object_release( p_sys->p_update_request_thread );
+        p_sys->p_update_request_thread = NULL;
+        msg_Err( p_filter, "cannot spawn vnc update request thread" );
+        return;
+    }
+
+    /* connection is initialized, now read and handle server messages */
+
+    int i_msgSize;
+
+    rfbServerToClientMsg msg;
+
+    while (p_sys->b_continue)
+    {
+       msg.type = 0;
+       if ( !read_exact(p_filter, p_sys->i_socket, (char*)&msg, 1 ) )
+       {
+           msg_Err( p_filter, "Error while waiting for next server message");
+           p_sys->b_continue = false;
+       }
+       else
+       {
+           switch (msg.type)
+           {
+              case rfbFramebufferUpdate:
+                i_msgSize = sz_rfbFramebufferUpdateMsg;
+                break;
+              case rfbSetColourMapEntries:
+                i_msgSize = sz_rfbSetColourMapEntriesMsg;
+                break;
+              case rfbBell:
+                i_msgSize = sz_rfbBellMsg;
+                break;
+              case rfbServerCutText:
+                i_msgSize = sz_rfbServerCutTextMsg;
+                break;
+              case rfbReSizeFrameBuffer:
+                i_msgSize = sz_rfbReSizeFrameBufferMsg;
+                break;
+              default:
+                i_msgSize = 0;
+                msg_Err( p_filter, "Invalid message %u received", msg.type );
+                p_sys->b_continue = false;
+           }
+           if (p_sys->b_continue == true)
+           {
+               if (--i_msgSize > 0)
+               {
+                   if ( !read_exact( p_filter, p_sys->i_socket,
+                                     ((char*)&msg)+1, i_msgSize ) )
+                   {
+                       msg_Err( p_filter, "Error while reading message of type %u",
+                                msg.type );
+                       p_sys->b_continue = false;
+                   }
+                   else
+                   {
+                       process_server_message( p_filter, &msg);
+                   }
+               }
+               else
+               {
+                   process_server_message( p_filter, &msg);
+               }
+           }
+
+       }
+
+       if (p_sys->p_worker_thread->b_die ||
+           p_sys->p_worker_thread->b_error)
+       {
+           p_sys->b_continue = false;
+       }
+
+    }
+
+    msg_Dbg( p_filter, "VNC message reader thread ended" );
+
+}
+
+static void update_request_thread( vlc_object_t *p_thread_obj )
+{
+    filter_t* p_filter = (filter_t*)(p_thread_obj->p_parent);
+    filter_sys_t *p_sys = p_filter->p_sys;
+
+    msg_Dbg( p_filter, "VNC update request thread started" );
+
+    rfbFramebufferUpdateRequestMsg udr;
+    udr.type = rfbFramebufferUpdateRequest;
+    udr.incremental = 0;
+    udr.x = 0;
+    udr.y = 0;
+    udr.w = htons(p_sys->i_vnc_width);
+    udr.h = htons(p_sys->i_vnc_height);
+
+    if( write_exact(p_filter, p_sys->i_socket, (char*)&udr,
+           sz_rfbFramebufferUpdateRequestMsg) == false)
+    {
+        msg_Err( p_filter, "Could not write rfbFramebufferUpdateRequestMsg." );
+        p_sys->b_continue = false;
+    }
+
+    udr.incremental = 1;
+    mtime_t i_poll_interval_microsec = p_sys->i_vnc_poll_interval * 1000;
+
+    if (p_sys->b_vnc_poll)
+    {
+        while ( p_sys->b_continue == true )
+        {
+            msleep( i_poll_interval_microsec );
+            if( write_exact(p_filter, p_sys->i_socket, (char*)&udr,
+                   sz_rfbFramebufferUpdateRequestMsg) == false)
+            {
+                msg_Err( p_filter, "Could not write rfbFramebufferUpdateRequestMsg." );
+                p_sys->b_continue = false;
+            }
+            if (p_sys->p_update_request_thread->b_die ||
+                p_sys->p_update_request_thread->b_error)
+            {
+                p_sys->b_continue = false;
+            }
+        }
+    }
+    else
+    {
+        msg_Dbg( p_filter, "VNC polling disabled." );
+    }
+    msg_Dbg( p_filter, "VNC update request thread ended" );
+}
+
+static bool process_server_message ( filter_t *p_filter,
+                                     rfbServerToClientMsg *msg )
+{
+    filter_sys_t *p_sys = p_filter->p_sys;
+
+    switch (msg->type)
+    {
+    case rfbFramebufferUpdate:
+        {
+            msg->fu.nRects = htons(msg->fu.nRects);
+            rfbFramebufferUpdateRectHeader hdr;
+
+            for (int i_rect = 0; i_rect < msg->fu.nRects; i_rect++)
+            {
+                if (!read_exact(p_filter, p_sys->i_socket, (char*)&hdr,
+                    sz_rfbFramebufferUpdateRectHeader ) )
+                {
+                    msg_Err( p_filter, "Could not read FrameBufferUpdate header" );
+                    return false;
+                }
+                hdr.r.x = htons(hdr.r.x);
+                hdr.r.y = htons(hdr.r.y);
+                hdr.r.w = htons(hdr.r.w);
+                hdr.r.h = htons(hdr.r.h);
+                hdr.encoding = htonl(hdr.encoding);
+
+                switch (hdr.encoding)
+                {
+                case rfbEncodingRaw:
+                    {
+                        int i_line;
+                        for (i_line = 0; i_line < hdr.r.h; i_line++)
+                        {
+                            if ( !read_exact( p_filter, p_sys->i_socket,
+                                    p_sys->read_buffer, hdr.r.w ) )
+                            {
+                                msg_Err( p_filter,
+                                 "Could not read FrameBufferUpdate line data" );
+                               return false;
+                            }
+                            vlc_mutex_lock( &p_sys->lock );
+                            if ( !raw_line( p_sys, hdr.r.x,
+                                            hdr.r.y + i_line,
+                                            hdr.r.w ) )
+                            {
+                                msg_Err( p_filter, "raw_line failed." );
+                                vlc_mutex_unlock( &p_sys->lock );
+                                return false;
+                            }
+                            vlc_mutex_unlock( &p_sys->lock );
+                        }
+                    }
+                    break;
+
+                case rfbEncodingCopyRect:
+                    {
+                        msg_Err( p_filter,
+                          "Rect in unsupported encoding rfbEncodingCopyRect" );
+                        return false;
+                    }
+
+                case rfbEncodingRRE:
+                    {
+                        rfbRREHeader rrehdr;
+                        if ( !read_exact( p_filter, p_sys->i_socket,
+                                          (char*)&rrehdr,
+                                          sz_rfbRREHeader ) )
+                        {
+                            msg_Err( p_filter, "Could not read rfbRREHeader" );
+                            return false;
+                        }
+                        uint8_t i_pixcolor;
+                        if ( !read_exact(p_filter, p_sys->i_socket,
+                                         (char*)&i_pixcolor, 1 ) )
+                        {
+                            msg_Err( p_filter, "Could not read RRE pixcolor" );
+                            return false;
+                        }
+
+                        vlc_mutex_lock( &p_sys->lock );
+                        if ( !fill_rect( p_sys,
+                                        hdr.r.x, hdr.r.y,
+                                        hdr.r.w, hdr.r.h,
+                                        i_pixcolor) )
+                        {
+                            msg_Err( p_filter, "main fill_rect failed." );
+                            vlc_mutex_unlock( &p_sys->lock );
+                            return false;
+                        }
+                        vlc_mutex_unlock( &p_sys->lock );
+
+                        rrehdr.nSubrects = htonl(rrehdr.nSubrects);
+
+                        int i_datasize = rrehdr.nSubrects *
+                                     ( sizeof(i_pixcolor) + sz_rfbRectangle ) ;
+                        if ( i_datasize > READ_BUFFER_SIZE )
+                        {
+                            msg_Err( p_filter, "Buffer too small, "
+                                     "need %u bytes", i_datasize );
+                            return false;
+                        }
+                        if ( !read_exact( p_filter, p_sys->i_socket,
+                                       p_sys->read_buffer, i_datasize ) )
+                        {
+                            msg_Err( p_filter,
+                                     "Could not read RRE subrect data" );
+                            return false;
+                        }
+
+                        uint32_t i_subrect;
+                        rfbRectangle* p_subrect;
+                        int i_offset = 0;
+                        vlc_mutex_lock( &p_sys->lock );
+                        for ( i_subrect = 0;
+                              i_subrect < rrehdr.nSubrects; i_subrect++)
+                        {
+                            i_pixcolor = p_sys->read_buffer[i_offset];
+                            i_offset += sizeof(i_pixcolor);
+                            p_subrect =
+                               (rfbRectangle*)(p_sys->read_buffer + i_offset);
+                            i_offset += sz_rfbRectangle;
+
+                            if (!fill_rect( p_sys,
+                                            htons(p_subrect->x) + hdr.r.x,
+                                            htons(p_subrect->y) + hdr.r.y,
+                                            htons(p_subrect->w),
+                                            htons(p_subrect->h),
+                                            i_pixcolor) )
+                            {
+                                msg_Err( p_filter,
+                                    "subrect %u fill_rect failed.", i_subrect );
+                                vlc_mutex_unlock( &p_sys->lock );
+                                return false;
+                            }
+                        }
+                        vlc_mutex_unlock( &p_sys->lock );
+                    }
+                    break;
+
+                }
+
+            }
+            vlc_mutex_lock( &p_sys->lock );
+            p_sys->b_need_update = true;
+            vlc_mutex_unlock( &p_sys->lock );
+        }
+        return true;
+
+    case rfbSetColourMapEntries:
+        {
+            msg->scme.nColours = htons(msg->scme.nColours);
+            msg->scme.firstColour = htons(msg->scme.firstColour);
+            int i_datasize;
+            if ( p_sys->b_alpha_from_vnc == true )
+            {
+                i_datasize = 2 * msg->scme.nColours * 4;
+            }
+            else
+            {
+                i_datasize = 2 * msg->scme.nColours * 3;
+            }
+            if ( i_datasize > READ_BUFFER_SIZE )
+            {
+                msg_Err( p_filter, "Buffer too small, need %u bytes",
+                                   i_datasize );
+                return false;
+            }
+
+            if ( !read_exact( p_filter, p_sys->i_socket,
+                              p_sys->read_buffer, i_datasize ) )
+            {
+                msg_Err( p_filter, "Could not read color map data" );
+                return false;
+            }
+
+            uint8_t i_red, i_green, i_blue, i_alpha, i_color_index;
+            uint16_t i_offset = 0;
+            i_alpha = 255;
+
+            for (int i = 0; i < msg->scme.nColours; i++)
+            {
+                i_color_index = i+msg->scme.firstColour;
+                if ( p_sys->b_alpha_from_vnc == true )
+                {
+                    i_alpha = p_sys->read_buffer[i_offset];
+                    i_offset += 2;
+                }
+                i_red   = p_sys->read_buffer[i_offset];
+                i_offset += 2;
+                i_green = p_sys->read_buffer[i_offset];
+                i_offset += 2;
+                i_blue  = p_sys->read_buffer[i_offset];
+                i_offset += 2;
+                rgb_to_yuv( &p_sys->ar_color_table_yuv[i_color_index][0],
+                            &p_sys->ar_color_table_yuv[i_color_index][1],
+                            &p_sys->ar_color_table_yuv[i_color_index][2],
+                            i_red,
+                            i_green,
+                            i_blue );
+                p_sys->ar_color_table_yuv[i][3] = i_alpha;
+            }
+        }
+        return true;
+
+    case rfbBell:
+        msg_Err( p_filter, "rfbBell received" );
+        return true;
+
+    case rfbServerCutText:
+        msg->sct.length = htons(msg->sct.length);
+        if ( msg->sct.length > READ_BUFFER_SIZE )
+        {
+            msg_Err( p_filter, "Buffer too small, need %u bytes", msg->sct.length );
+            return false;
+        }
+        if ( !read_exact(p_filter, p_sys->i_socket,
+                         p_sys->read_buffer, msg->sct.length ) )
+        {
+            msg_Err( p_filter, "Could not read Reading rfbServerCutText data" );
+            return false;
+        }
+        return true;
+
+    case rfbReSizeFrameBuffer:
+        msg_Err( p_filter, "Reading rfbReSizeFrameBuffer not implemented" );
+        return false;
+
+    default:
+        msg_Err( p_filter, "Invalid message %u received", msg->type );
+        return false;
+    }
+    return false;
+}
+
+/****************************************************************************
+ * Filter: the whole thing
+ ****************************************************************************
+ * This function outputs subpictures at regular time intervals.
+ ****************************************************************************/
+static subpicture_t *Filter( filter_t *p_filter, mtime_t date )
+{
+    filter_sys_t *p_sys = p_filter->p_sys;
+    subpicture_t *p_spu;
+    subpicture_region_t *p_region;
+    video_format_t fmt;
+    picture_t *p_pic;
+
+    if( !p_sys->b_need_update )
+    {
+        return NULL;
+    }
+
+    vlc_mutex_lock( &p_sys->lock );
+
+    p_pic = p_sys->p_pic;
+
+    if( !p_pic )
+    {
+        vlc_mutex_unlock( &p_sys->lock );
+        return NULL;
+    }
+
+    /* Allocate the subpicture internal data. */
+    p_spu = p_filter->pf_sub_buffer_new( p_filter );
+    if( !p_spu )
+    {
+        vlc_mutex_unlock( &p_sys->lock );
+        return NULL;
+    }
+
+    p_spu->b_absolute = false;
+    p_spu->i_start = date;
+    p_spu->i_stop = 0;
+    p_spu->b_ephemer = true;
+
+    /* Create new SPU region */
+    memset( &fmt, 0, sizeof(video_format_t) );
+    fmt.i_chroma = VLC_FOURCC('Y','U','V','A');
+    fmt.i_aspect = VOUT_ASPECT_FACTOR;
+    fmt.i_sar_num = fmt.i_sar_den = 1;
+    fmt.i_width = fmt.i_visible_width = p_pic->p[Y_PLANE].i_visible_pitch;
+    fmt.i_height = fmt.i_visible_height = p_pic->p[Y_PLANE].i_visible_lines;
+    fmt.i_x_offset = fmt.i_y_offset = 0;
+    p_region = p_spu->pf_create_region( VLC_OBJECT(p_filter), &fmt );
+    if( !p_region )
+    {
+        msg_Err( p_filter, "cannot allocate SPU region" );
+        p_filter->pf_sub_buffer_del( p_filter, p_spu );
+        vlc_mutex_unlock( &p_sys->lock );
+        return NULL;
+    }
+
+    vout_CopyPicture( p_filter, &p_region->picture, p_pic );
+
+    p_sys->b_need_update = false;
+
+    vlc_mutex_unlock( &p_sys->lock );
+
+    /* set to one of the 9 relative locations */
+    p_region->i_align = 0; //=CENTER
+    p_spu->b_absolute = false;
+
+
+    p_spu->i_x = 0;
+    p_spu->i_y = 0;
+
+    p_spu->p_region = p_region;
+
+    p_spu->i_alpha = ( p_sys->i_alpha );
+
+    return p_spu;
+}
+
+
+static inline void rgb_to_yuv( uint8_t *y, uint8_t *u, uint8_t *v,
+                               int r, int g, int b )
+{
+    *y = ( ( (  66 * r + 129 * g +  25 * b + 128 ) >> 8 ) + 16 );
+    *u =   ( ( -38 * r -  74 * g + 112 * b + 128 ) >> 8 ) + 128 ;
+    *v =   ( ( 112 * r -  94 * g -  18 * b + 128 ) >> 8 ) + 128 ;
+}
+
+static inline bool fill_rect( filter_sys_t* p_sys,
+                              uint16_t i_x, uint16_t i_y,
+                              uint16_t i_w, uint16_t i_h,
+                              uint8_t i_color)
+{
+    plane_t *p_outY = p_sys->p_pic->p+Y_PLANE;
+    plane_t *p_outU = p_sys->p_pic->p+U_PLANE;
+    plane_t *p_outV = p_sys->p_pic->p+V_PLANE;
+    plane_t *p_outA = p_sys->p_pic->p+A_PLANE;
+    int i_pitch = p_outY->i_pitch;
+    int i_lines = p_outY->i_lines;
+    if ( i_x + i_w > i_pitch)
+        return false;
+    if ( i_y + i_h > i_lines)
+        return false;
+    int i_line_offset = i_y * i_pitch;
+    uint8_t i_yuv_y = p_sys->ar_color_table_yuv[i_color][0];
+    uint8_t i_yuv_u = p_sys->ar_color_table_yuv[i_color][1];
+    uint8_t i_yuv_v = p_sys->ar_color_table_yuv[i_color][2];
+    uint8_t i_alpha = p_sys->ar_color_table_yuv[i_color][3];
+    for( int i_line = 0; i_line < i_h; i_line++ )
+    {
+        for( int i_column = 0; i_column < i_w; i_column++ )
+        {
+            int i_total_offset = i_line_offset + i_x + i_column;
+            p_outY->p_pixels[ i_total_offset ] = i_yuv_y;
+            p_outU->p_pixels[ i_total_offset ] = i_yuv_u;
+            p_outV->p_pixels[ i_total_offset ] = i_yuv_v;
+            p_outA->p_pixels[ i_total_offset ] = i_alpha;
+        }
+        i_line_offset += i_pitch;
+    }
+    return true;
+}
+
+static inline bool raw_line(  filter_sys_t* p_sys,
+                              uint16_t i_x, uint16_t i_y,
+                              uint16_t i_w )
+{
+    plane_t *p_outY = p_sys->p_pic->p+Y_PLANE;
+    plane_t *p_outU = p_sys->p_pic->p+U_PLANE;
+    plane_t *p_outV = p_sys->p_pic->p+V_PLANE;
+    plane_t *p_outA = p_sys->p_pic->p+A_PLANE;
+    int i_pitch = p_outY->i_pitch;
+    int i_lines = p_outY->i_lines;
+    if ( i_x + i_w > i_pitch)
+        return false;
+    if ( i_y > i_lines)
+        return false;
+
+    int i_line_offset = i_y * i_pitch + i_x;
+
+    for( int i_column = 0; i_column < i_w; i_column++ )
+    {
+        int i_offset = i_line_offset + i_column;
+        uint8_t i_color = p_sys->read_buffer[i_column];
+        p_outY->p_pixels[ i_offset ] = p_sys->ar_color_table_yuv[i_color][0];
+        p_outU->p_pixels[ i_offset ] = p_sys->ar_color_table_yuv[i_color][1];
+        p_outV->p_pixels[ i_offset ] = p_sys->ar_color_table_yuv[i_color][2];
+        p_outA->p_pixels[ i_offset ] = p_sys->ar_color_table_yuv[i_color][3];
+    }
+
+    return true;
+}
+
+
+/*****************************************************************************
+ * MouseEvent: callback for mouse events
+ *****************************************************************************/
+static int MouseEvent( vlc_object_t *p_this, char const *psz_var,
+                       vlc_value_t oldval, vlc_value_t newval, void *p_data )
+{
+    VLC_UNUSED(oldval); VLC_UNUSED(newval); VLC_UNUSED(psz_var);
+
+    filter_t *p_filter = (filter_t *)p_data;
+    filter_sys_t *p_sys = p_filter->p_sys;
+
+    if( !p_sys->b_connection_active )
+        return VLC_SUCCESS;
+
+    if( !p_sys->b_vnc_mouse_events )
+        return VLC_SUCCESS;
+
+    vout_thread_t *p_vout = (vout_thread_t*)p_sys->p_vout;
+    int i_x, i_y;
+    int i_v;
+
+    int v_h = p_vout->output.i_height;
+    int v_w = p_vout->output.i_width;
+
+    i_v = var_GetInteger( p_sys->p_vout, "mouse-button-down" );
+    i_y = var_GetInteger( p_sys->p_vout, "mouse-y" );
+    i_x = var_GetInteger( p_sys->p_vout, "mouse-x" );
+
+    if( i_y < 0 || i_x < 0 || i_y >= v_h || i_x >= v_w )
+    {
+       msg_Dbg( p_this, "invalid mouse event? x=%d y=%d btn=%x", i_x, i_y, i_v );
+       return VLC_SUCCESS;
+    }
+#ifdef VNC_DEBUG
+    msg_Dbg( p_this, "mouse event x=%d y=%d btn=%x", i_x, i_y, i_v );
+#endif
+
+    /* FIXME: calculate x and y coordinates for scaled output */
+
+    /* buttonMask bits 0-7 are buttons 1-8, 0=up, 1=down */
+    rfbPointerEventMsg ev;
+    ev.type = rfbPointerEvent;
+    ev.buttonMask = i_v;
+    ev.x = htons(i_x);
+    ev.y = htons(i_y);
+
+    write_exact( p_filter, p_sys->i_socket,
+                 (char*)&ev, sz_rfbPointerEventMsg);
+
+    return VLC_SUCCESS;
+}
+
+/*****************************************************************************
+ * KeyEvent: callback for keyboard events
+ *****************************************************************************/
+static int KeyEvent( vlc_object_t *p_this, char const *psz_var,
+                     vlc_value_t oldval, vlc_value_t newval, void *p_data )
+{
+    VLC_UNUSED(psz_var); VLC_UNUSED(oldval);
+
+    filter_t *p_filter = (filter_t *)p_data;
+    filter_sys_t *p_sys = p_filter->p_sys;
+
+    if( !p_sys->b_connection_active )
+        return VLC_SUCCESS;
+
+    if( !p_sys->b_vnc_key_events )
+        return VLC_SUCCESS;
+
+    msg_Dbg( p_this, "key pressed (%d) ", newval.i_int );
+
+    if ( !newval.i_int )
+    {
+        msg_Err( p_this, "Received invalid key event %d", newval.i_int );
+        return VLC_EGENERIC;
+    }
+
+    uint32_t i_key32 = newval.i_int;
+    i_key32 = htonl(i_key32);
+    rfbKeyEventMsg ev;
+    ev.type = rfbKeyEvent;
+    ev.down = 1;
+
+    /* first key-down for modifier-keys */
+    if (newval.i_int & KEY_MODIFIER_CTRL)
+    {
+        ev.key = 0xffe3;
+        write_exact( p_filter, p_sys->i_socket,
+                     (char*)&ev, sz_rfbKeyEventMsg);
+    }
+    if (newval.i_int & KEY_MODIFIER_SHIFT)
+    {
+        ev.key = 0xffe1;
+        write_exact( p_filter, p_sys->i_socket,
+                     (char*)&ev, sz_rfbKeyEventMsg);
+    }
+    if (newval.i_int & KEY_MODIFIER_ALT)
+    {
+        ev.key = 0xffe9;
+        write_exact( p_filter, p_sys->i_socket,
+                     (char*)&ev, sz_rfbKeyEventMsg);
+    }
+
+    /* then key-down for the pressed key */
+    ev.key = i_key32;
+    write_exact( p_filter, p_sys->i_socket,
+                 (char*)&ev, sz_rfbKeyEventMsg);
+
+    ev.down = 0;
+
+    /* then key-up for the pressed key */
+    write_exact( p_filter, p_sys->i_socket,
+                 (char*)&ev, sz_rfbKeyEventMsg);
+
+    /* last key-down for modifier-keys */
+    if (newval.i_int & KEY_MODIFIER_CTRL)
+    {
+        ev.key = 0xffe3;
+        write_exact( p_filter, p_sys->i_socket,
+                     (char*)&ev, sz_rfbKeyEventMsg);
+    }
+    if (newval.i_int & KEY_MODIFIER_SHIFT)
+    {
+        ev.key = 0xffe1;
+        write_exact( p_filter, p_sys->i_socket,
+                     (char*)&ev, sz_rfbKeyEventMsg);
+    }
+    if (newval.i_int & KEY_MODIFIER_ALT)
+    {
+       ev.key = 0xffe9;
+       write_exact( p_filter, p_sys->i_socket,
+                    (char*)&ev, sz_rfbKeyEventMsg);
+    }
+
+    return VLC_SUCCESS;
+}
+
+static void vnc_encrypt_bytes( unsigned char *bytes, char *passwd )
+{
+    unsigned char key[8];
+    unsigned int i;
+
+    for (i = 0; i < 8; i++)
+        key[i] = i < strlen( passwd ) ? passwd[i] : '\0';
+
+    gcry_cipher_hd_t ctx;
+    gcry_cipher_open( &ctx, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB,0);
+
+    /* reverse bits of the key */
+    for( i = 0 ; i < 8 ; i ++ )
+        key[i] =
+            (key[i] >> 7) +
+            (((key[i] >> 6) & 0x01 ) << 1 ) +
+            (((key[i] >> 5) & 0x01 ) << 2 ) +
+            (((key[i] >> 4) & 0x01 ) << 3 ) +
+            (((key[i] >> 3) & 0x01 ) << 4 ) +
+            (((key[i] >> 2) & 0x01 ) << 5 ) +
+            (((key[i] >> 1) & 0x01 ) << 6 ) +
+            ((key[i] & 0x01) << 7 );
+
+    gcry_cipher_setkey( ctx, key, 8 );
+    gcry_cipher_encrypt( ctx, bytes, CHALLENGESIZE, bytes, CHALLENGESIZE );
+    gcry_cipher_close( ctx );
+}
diff --git a/modules/video_filter/remoteosd_rfbproto.h b/modules/video_filter/remoteosd_rfbproto.h
new file mode 100755 (executable)
index 0000000..c8ca85b
--- /dev/null
@@ -0,0 +1,729 @@
+/*
+ *  Copyright (C) 2002 RealVNC Ltd.  All Rights Reserved.
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ */
+
+/*
+ * rfbproto.h - header file for the RFB protocol version 3.3
+ *
+ * Uses types CARD<n> for an n-bit unsigned integer, INT<n> for an n-bit signed
+ * integer (for n = 8, 16 and 32).
+ *
+ * All multiple byte integers are in big endian (network) order (most
+ * significant byte first).  Unless noted otherwise there is no special
+ * alignment of protocol structures.
+ *
+ *
+ * Once the initial handshaking is done, all messages start with a type byte,
+ * (usually) followed by message-specific data.  The order of definitions in
+ * this file is as follows:
+ *
+ *  (1) Structures used in several types of message.
+ *  (2) Structures used in the initial handshaking.
+ *  (3) Message types.
+ *  (4) Encoding types.
+ *  (5) For each message type, the form of the data following the type byte.
+ *      Sometimes this is defined by a single structure but the more complex
+ *      messages have to be explained by comments.
+ */
+
+/*****************************************************************************
+ *
+ * Structures used in several messages
+ *
+ *****************************************************************************/
+
+#include "inttypes.h"
+#define CARD8  uint8_t
+#define CARD16 uint16_t
+#define CARD32 uint32_t
+
+/*-----------------------------------------------------------------------------
+ * Structure used to specify a rectangle.  This structure is a multiple of 4
+ * bytes so that it can be interspersed with 32-bit pixel data without
+ * affecting alignment.
+ */
+typedef struct {
+    CARD16 x;
+    CARD16 y;
+    CARD16 w;
+    CARD16 h;
+} rfbRectangle;
+
+#define sz_rfbRectangle 8
+
+
+/*-----------------------------------------------------------------------------
+ * Structure used to specify pixel format.
+ */
+
+typedef struct {
+
+    CARD8 bitsPerPixel;                /* 8,16,32 only */
+
+    CARD8 depth;               /* 8 to 32 */
+
+    CARD8 bigEndian;           /* True if multi-byte pixels are interpreted
+                                  as big endian, or if single-bit-per-pixel
+                                  has most significant bit of the byte
+                                  corresponding to first (leftmost) pixel. Of
+                                  course this is meaningless for 8 bits/pix */
+
+    CARD8 trueColour;          /* If false then we need a "colour map" to
+                                  convert pixels to RGB.  If true, xxxMax and
+                                  xxxShift specify bits used for red, green
+                                  and blue */
+
+    /* the following fields are only meaningful if trueColour is true */
+
+    CARD16 redMax;             /* maximum red value (= 2^n - 1 where n is the
+                                  number of bits used for red). Note this
+                                  value is always in big endian order. */
+
+    CARD16 greenMax;           /* similar for green */
+
+    CARD16 blueMax;            /* and blue */
+
+    CARD8 redShift;            /* number of shifts needed to get the red
+                                  value in a pixel to the least significant
+                                  bit. To find the red value from a given
+                                  pixel, do the following:
+                                  1) Swap pixel value according to bigEndian
+                                     (e.g. if bigEndian is false and host byte
+                                     order is big endian, then swap).
+                                  2) Shift right by redShift.
+                                  3) AND with redMax (in host byte order).
+                                  4) You now have the red value between 0 and
+                                     redMax. */
+
+    CARD8 greenShift;          /* similar for green */
+
+    CARD8 blueShift;           /* and blue */
+
+    CARD8 pad1;
+    CARD16 pad2;
+
+} rfbPixelFormat;
+
+#define sz_rfbPixelFormat 16
+
+
+
+/*****************************************************************************
+ *
+ * Initial handshaking messages
+ *
+ *****************************************************************************/
+
+/*-----------------------------------------------------------------------------
+ * Protocol Version
+ *
+ * The server always sends 12 bytes to start which identifies the latest RFB
+ * protocol version number which it supports.  These bytes are interpreted
+ * as a string of 12 ASCII characters in the format "RFB xxx.yyy\n" where
+ * xxx and yyy are the major and minor version numbers (for version 3.3
+ * this is "RFB 003.003\n").
+ *
+ * The client then replies with a similar 12-byte message giving the version
+ * number of the protocol which should actually be used (which may be different
+ * to that quoted by the server).
+ *
+ * It is intended that both clients and servers may provide some level of
+ * backwards compatibility by this mechanism.  Servers in particular should
+ * attempt to provide backwards compatibility, and even forwards compatibility
+ * to some extent.  For example if a client demands version 3.1 of the
+ * protocol, a 3.0 server can probably assume that by ignoring requests for
+ * encoding types it doesn't understand, everything will still work OK.  This
+ * will probably not be the case for changes in the major version number.
+ *
+ * The format string below can be used in sprintf or sscanf to generate or
+ * decode the version string respectively.
+ */
+
+#define rfbProtocolVersionFormat "RFB %03d.%03d\n"
+#define rfbProtocolMajorVersion 3
+#define rfbProtocolMinorVersion 3
+
+typedef char rfbProtocolVersionMsg[13];        /* allow extra byte for null */
+
+#define sz_rfbProtocolVersionMsg 12
+
+
+/*-----------------------------------------------------------------------------
+ * Authentication
+ *
+ * Once the protocol version has been decided, the server then sends a 32-bit
+ * word indicating whether any authentication is needed on the connection.
+ * The value of this word determines the authentication scheme in use.  For
+ * version 3.0 of the protocol this may have one of the following values:
+ */
+
+#define rfbConnFailed 0
+#define rfbNoAuth 1
+#define rfbVncAuth 2
+
+/*
+ * rfbConnFailed:      For some reason the connection failed (e.g. the server
+ *                     cannot support the desired protocol version).  This is
+ *                     followed by a string describing the reason (where a
+ *                     string is specified as a 32-bit length followed by that
+ *                     many ASCII characters).
+ *
+ * rfbNoAuth:          No authentication is needed.
+ *
+ * rfbVncAuth:         The VNC authentication scheme is to be used.  A 16-byte
+ *                     challenge follows, which the client encrypts as
+ *                     appropriate using the password and sends the resulting
+ *                     16-byte response.  If the response is correct, the
+ *                     server sends the 32-bit word rfbVncAuthOK.  If a simple
+ *                     failure happens, the server sends rfbVncAuthFailed and
+ *                     closes the connection. If the server decides that too
+ *                     many failures have occurred, it sends rfbVncAuthTooMany
+ *                     and closes the connection.  In the latter case, the
+ *                     server should not allow an immediate reconnection by
+ *                     the client.
+ */
+
+#define rfbVncAuthOK 0
+#define rfbVncAuthFailed 1
+#define rfbVncAuthTooMany 2
+
+
+/*-----------------------------------------------------------------------------
+ * Client Initialisation Message
+ *
+ * Once the client and server are sure that they're happy to talk to one
+ * another, the client sends an initialisation message.  At present this
+ * message only consists of a boolean indicating whether the server should try
+ * to share the desktop by leaving other clients connected, or give exclusive
+ * access to this client by disconnecting all other clients.
+ */
+
+typedef struct {
+    CARD8 shared;
+} rfbClientInitMsg;
+
+#define sz_rfbClientInitMsg 1
+
+
+/*-----------------------------------------------------------------------------
+ * Server Initialisation Message
+ *
+ * After the client initialisation message, the server sends one of its own.
+ * This tells the client the width and height of the server's framebuffer,
+ * its pixel format and the name associated with the desktop.
+ */
+
+typedef struct {
+    CARD16 framebufferWidth;
+    CARD16 framebufferHeight;
+    rfbPixelFormat format;     /* the server's preferred pixel format */
+    CARD32 nameLength;
+    /* followed by char name[nameLength] */
+} rfbServerInitMsg;
+
+#define sz_rfbServerInitMsg (8 + sz_rfbPixelFormat)
+
+
+/*
+ * Following the server initialisation message it's up to the client to send
+ * whichever protocol messages it wants.  Typically it will send a
+ * SetPixelFormat message and a SetEncodings message, followed by a
+ * FramebufferUpdateRequest.  From then on the server will send
+ * FramebufferUpdate messages in response to the client's
+ * FramebufferUpdateRequest messages.  The client should send
+ * FramebufferUpdateRequest messages with incremental set to true when it has
+ * finished processing one FramebufferUpdate and is ready to process another.
+ * With a fast client, the rate at which FramebufferUpdateRequests are sent
+ * should be regulated to avoid hogging the network.
+ */
+
+
+
+/*****************************************************************************
+ *
+ * Message types
+ *
+ *****************************************************************************/
+
+/* server -> client */
+
+#define rfbFramebufferUpdate 0
+#define rfbSetColourMapEntries 1
+#define rfbBell 2
+#define rfbServerCutText 3
+#define rfbReSizeFrameBuffer 0xF
+
+
+/* client -> server */
+
+#define rfbSetPixelFormat 0
+#define rfbFixColourMapEntries 1       /* not currently supported */
+#define rfbSetEncodings 2
+#define rfbFramebufferUpdateRequest 3
+#define rfbKeyEvent 4
+#define rfbPointerEvent 5
+#define rfbClientCutText 6
+#define rfbSetScaleFactor 0xF
+
+
+
+
+/*****************************************************************************
+ *
+ * Encoding types
+ *
+ *****************************************************************************/
+
+#define rfbEncodingRaw 0
+#define rfbEncodingCopyRect 1
+#define rfbEncodingRRE 2
+#define rfbEncodingCoRRE 4
+#define rfbEncodingHextile 5
+#define rfbEncodingZRLE 16
+
+
+
+/*****************************************************************************
+ *
+ * Server -> client message definitions
+ *
+ *****************************************************************************/
+
+
+/*-----------------------------------------------------------------------------
+ * FramebufferUpdate - a block of rectangles to be copied to the framebuffer.
+ *
+ * This message consists of a header giving the number of rectangles of pixel
+ * data followed by the rectangles themselves.  The header is padded so that
+ * together with the type byte it is an exact multiple of 4 bytes (to help
+ * with alignment of 32-bit pixels):
+ */
+
+typedef struct {
+    CARD8 type;                        /* always rfbFramebufferUpdate */
+    CARD8 pad;
+    CARD16 nRects;
+    /* followed by nRects rectangles */
+} rfbFramebufferUpdateMsg;
+
+#define sz_rfbFramebufferUpdateMsg 4
+
+/*
+ * Each rectangle of pixel data consists of a header describing the position
+ * and size of the rectangle and a type word describing the encoding of the
+ * pixel data, followed finally by the pixel data.  Note that if the client has
+ * not sent a SetEncodings message then it will only receive raw pixel data.
+ * Also note again that this structure is a multiple of 4 bytes.
+ */
+
+typedef struct {
+    rfbRectangle r;
+    CARD32 encoding;   /* one of the encoding types rfbEncoding... */
+} rfbFramebufferUpdateRectHeader;
+
+#define sz_rfbFramebufferUpdateRectHeader (sz_rfbRectangle + 4)
+
+
+/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * Raw Encoding.  Pixels are sent in top-to-bottom scanline order,
+ * left-to-right within a scanline with no padding in between.
+ */
+
+
+/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * CopyRect Encoding.  The pixels are specified simply by the x and y position
+ * of the source rectangle.
+ */
+
+typedef struct {
+    CARD16 srcX;
+    CARD16 srcY;
+} rfbCopyRect;
+
+#define sz_rfbCopyRect 4
+
+
+/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * RRE - Rise-and-Run-length Encoding.  We have an rfbRREHeader structure
+ * giving the number of subrectangles following.  Finally the data follows in
+ * the form [<bgpixel><subrect><subrect>...] where each <subrect> is
+ * [<pixel><rfbRectangle>].
+ */
+
+typedef struct {
+    CARD32 nSubrects;
+} rfbRREHeader;
+
+#define sz_rfbRREHeader 4
+
+
+/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * CoRRE - Compact RRE Encoding.  We have an rfbRREHeader structure giving
+ * the number of subrectangles following.  Finally the data follows in the form
+ * [<bgpixel><subrect><subrect>...] where each <subrect> is
+ * [<pixel><rfbCoRRERectangle>].  This means that
+ * the whole rectangle must be at most 255x255 pixels.
+ */
+
+typedef struct {
+    CARD8 x;
+    CARD8 y;
+    CARD8 w;
+    CARD8 h;
+} rfbCoRRERectangle;
+
+#define sz_rfbCoRRERectangle 4
+
+
+/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * Hextile Encoding.  The rectangle is divided up into "tiles" of 16x16 pixels,
+ * starting at the top left going in left-to-right, top-to-bottom order.  If
+ * the width of the rectangle is not an exact multiple of 16 then the width of
+ * the last tile in each row will be correspondingly smaller.  Similarly if the
+ * height is not an exact multiple of 16 then the height of each tile in the
+ * final row will also be smaller.  Each tile begins with a "subencoding" type
+ * byte, which is a mask made up of a number of bits.  If the Raw bit is set
+ * then the other bits are irrelevant; w*h pixel values follow (where w and h
+ * are the width and height of the tile).  Otherwise the tile is encoded in a
+ * similar way to RRE, except that the position and size of each subrectangle
+ * can be specified in just two bytes.  The other bits in the mask are as
+ * follows:
+ *
+ * BackgroundSpecified - if set, a pixel value follows which specifies
+ *    the background colour for this tile.  The first non-raw tile in a
+ *    rectangle must have this bit set.  If this bit isn't set then the
+ *    background is the same as the last tile.
+ *
+ * ForegroundSpecified - if set, a pixel value follows which specifies
+ *    the foreground colour to be used for all subrectangles in this tile.
+ *    If this bit is set then the SubrectsColoured bit must be zero.
+ *
+ * AnySubrects - if set, a single byte follows giving the number of
+ *    subrectangles following.  If not set, there are no subrectangles (i.e.
+ *    the whole tile is just solid background colour).
+ *
+ * SubrectsColoured - if set then each subrectangle is preceded by a pixel
+ *    value giving the colour of that subrectangle.  If not set, all
+ *    subrectangles are the same colour, the foreground colour;  if the
+ *    ForegroundSpecified bit wasn't set then the foreground is the same as
+ *    the last tile.
+ *
+ * The position and size of each subrectangle is specified in two bytes.  The
+ * Pack macros below can be used to generate the two bytes from x, y, w, h,
+ * and the Extract macros can be used to extract the x, y, w, h values from
+ * the two bytes.
+ */
+
+#define rfbHextileRaw                  (1 << 0)
+#define rfbHextileBackgroundSpecified  (1 << 1)
+#define rfbHextileForegroundSpecified  (1 << 2)
+#define rfbHextileAnySubrects          (1 << 3)
+#define rfbHextileSubrectsColoured     (1 << 4)
+
+#define rfbHextilePackXY(x,y) (((x) << 4) | (y))
+#define rfbHextilePackWH(w,h) ((((w)-1) << 4) | ((h)-1))
+#define rfbHextileExtractX(byte) ((byte) >> 4)
+#define rfbHextileExtractY(byte) ((byte) & 0xf)
+#define rfbHextileExtractW(byte) (((byte) >> 4) + 1)
+#define rfbHextileExtractH(byte) (((byte) & 0xf) + 1)
+
+
+/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * ZRLE - encoding combining Zlib compression, tiling, palettisation and
+ * run-length encoding.
+ */
+
+typedef struct {
+    CARD32 length;
+} rfbZRLEHeader;
+
+#define sz_rfbZRLEHeader 4
+
+#define rfbZRLETileWidth 64
+#define rfbZRLETileHeight 64
+
+
+/*-----------------------------------------------------------------------------
+ * SetColourMapEntries - these messages are only sent if the pixel
+ * format uses a "colour map" (i.e. trueColour false) and the client has not
+ * fixed the entire colour map using FixColourMapEntries.  In addition they
+ * will only start being sent after the client has sent its first
+ * FramebufferUpdateRequest.  So if the client always tells the server to use
+ * trueColour then it never needs to process this type of message.
+ */
+
+typedef struct {
+    CARD8 type;                        /* always rfbSetColourMapEntries */
+    CARD8 pad;
+    CARD16 firstColour;
+    CARD16 nColours;
+
+    /* Followed by nColours * 3 * CARD16
+       r1, g1, b1, r2, g2, b2, r3, g3, b3, ..., rn, bn, gn */
+
+} rfbSetColourMapEntriesMsg;
+
+#define sz_rfbSetColourMapEntriesMsg 6
+
+
+
+/*-----------------------------------------------------------------------------
+ * Bell - ring a bell on the client if it has one.
+ */
+
+typedef struct {
+    CARD8 type;                        /* always rfbBell */
+} rfbBellMsg;
+
+#define sz_rfbBellMsg 1
+
+
+
+/*-----------------------------------------------------------------------------
+ * ServerCutText - the server has new text in its cut buffer.
+ */
+
+typedef struct {
+    CARD8 type;                        /* always rfbServerCutText */
+    CARD8 pad1;
+    CARD16 pad2;
+    CARD32 length;
+    /* followed by char text[length] */
+} rfbServerCutTextMsg;
+
+#define sz_rfbServerCutTextMsg 8
+
+/*-----------------------------------------------------------------------------
+ * ReSizeFrameBuffer - tell the RFB client to alter its framebuffer, either
+ * due to a resize of the server desktop or a client-requested scaling factor.
+ * The pixel format remains unchanged.
+ */
+
+typedef struct {
+    CARD8 type;                 /* always rfbReSizeFrameBuffer */
+        CARD8 pad1;
+        CARD16 desktop_w;       /* Desktop width */
+        CARD16 desktop_h;       /* Desktop height */
+        CARD16 buffer_w;        /* FrameBuffer width */
+        CARD16 buffer_h;        /* Framebuffer height */
+    CARD16 pad2;
+
+} rfbReSizeFrameBufferMsg;
+
+#define sz_rfbReSizeFrameBufferMsg (12)
+
+
+
+/*-----------------------------------------------------------------------------
+ * Union of all server->client messages.
+ */
+
+typedef union {
+    CARD8 type;
+    rfbFramebufferUpdateMsg fu;
+    rfbSetColourMapEntriesMsg scme;
+    rfbBellMsg b;
+    rfbServerCutTextMsg sct;
+    rfbReSizeFrameBufferMsg rsfb;
+} rfbServerToClientMsg;
+
+
+
+/*****************************************************************************
+ *
+ * Message definitions (client -> server)
+ *
+ *****************************************************************************/
+
+
+/*-----------------------------------------------------------------------------
+ * SetPixelFormat - tell the RFB server the format in which the client wants
+ * pixels sent.
+ */
+
+typedef struct {
+    CARD8 type;                        /* always rfbSetPixelFormat */
+    CARD8 pad1;
+    CARD16 pad2;
+    rfbPixelFormat format;
+} rfbSetPixelFormatMsg;
+
+#define sz_rfbSetPixelFormatMsg (sz_rfbPixelFormat + 4)
+
+
+/*-----------------------------------------------------------------------------
+ * FixColourMapEntries - when the pixel format uses a "colour map", fix
+ * read-only colour map entries.
+ *
+ *    ***************** NOT CURRENTLY SUPPORTED *****************
+ */
+
+typedef struct {
+    CARD8 type;                        /* always rfbFixColourMapEntries */
+    CARD8 pad;
+    CARD16 firstColour;
+    CARD16 nColours;
+
+    /* Followed by nColours * 3 * CARD16
+       r1, g1, b1, r2, g2, b2, r3, g3, b3, ..., rn, bn, gn */
+
+} rfbFixColourMapEntriesMsg;
+
+#define sz_rfbFixColourMapEntriesMsg 6
+
+
+/*-----------------------------------------------------------------------------
+ * SetEncodings - tell the RFB server which encoding types we accept.  Put them
+ * in order of preference, if we have any.  We may always receive raw
+ * encoding, even if we don't specify it here.
+ */
+
+typedef struct {
+    CARD8 type;                        /* always rfbSetEncodings */
+    CARD8 pad;
+    CARD16 nEncodings;
+    /* followed by nEncodings * CARD32 encoding types */
+} rfbSetEncodingsMsg;
+
+#define sz_rfbSetEncodingsMsg 4
+
+/*-----------------------------------------------------------------------------
+ * SetScaleFactor - tell the RFB server to alter the scale factor for the
+ * client buffer.
+ */
+
+typedef struct {
+       CARD8 type;                 /* always rfbSetScaleFactor */
+       CARD8 scale;                /* Scale factor (positive non-zero integer) */
+       CARD16 pad2;
+} rfbSetScaleFactorMsg;
+
+#define sz_rfbSetScaleFactorMsg (4)
+
+/*-----------------------------------------------------------------------------
+ * FramebufferUpdateRequest - request for a framebuffer update.  If incremental
+ * is true then the client just wants the changes since the last update.  If
+ * false then it wants the whole of the specified rectangle.
+ */
+
+typedef struct {
+    CARD8 type;                        /* always rfbFramebufferUpdateRequest */
+    CARD8 incremental;
+    CARD16 x;
+    CARD16 y;
+    CARD16 w;
+    CARD16 h;
+} rfbFramebufferUpdateRequestMsg;
+
+#define sz_rfbFramebufferUpdateRequestMsg 10
+
+
+/*-----------------------------------------------------------------------------
+ * KeyEvent - key press or release
+ *
+ * Keys are specified using the "keysym" values defined by the X Window System.
+ * For most ordinary keys, the keysym is the same as the corresponding ASCII
+ * value.  Other common keys are:
+ *
+ * BackSpace           0xff08
+ * Tab                 0xff09
+ * Return or Enter     0xff0d
+ * Escape              0xff1b
+ * Insert              0xff63
+ * Delete              0xffff
+ * Home                        0xff50
+ * End                 0xff57
+ * Page Up             0xff55
+ * Page Down           0xff56
+ * Left                        0xff51
+ * Up                  0xff52
+ * Right               0xff53
+ * Down                        0xff54
+ * F1                  0xffbe
+ * F2                  0xffbf
+ * ...                 ...
+ * F12                 0xffc9
+ * Shift               0xffe1
+ * Control             0xffe3
+ * Meta                        0xffe7
+ * Alt                 0xffe9
+ */
+
+typedef struct {
+    CARD8 type;                        /* always rfbKeyEvent */
+    CARD8 down;                        /* true if down (press), false if up */
+    CARD16 pad;
+    CARD32 key;                        /* key is specified as an X keysym */
+} rfbKeyEventMsg;
+
+#define sz_rfbKeyEventMsg 8
+
+
+/*-----------------------------------------------------------------------------
+ * PointerEvent - mouse/pen move and/or button press.
+ */
+
+typedef struct {
+    CARD8 type;                        /* always rfbPointerEvent */
+    CARD8 buttonMask;          /* bits 0-7 are buttons 1-8, 0=up, 1=down */
+    CARD16 x;
+    CARD16 y;
+} rfbPointerEventMsg;
+
+#define rfbButton1Mask 1
+#define rfbButton2Mask 2
+#define rfbButton3Mask 4
+#define rfbButton4Mask 8
+#define rfbButton5Mask 16
+#define rfbWheelUpMask rfbButton4Mask
+#define rfbWheelDownMask rfbButton5Mask
+
+#define sz_rfbPointerEventMsg 6
+
+
+
+/*-----------------------------------------------------------------------------
+ * ClientCutText - the client has new text in its cut buffer.
+ */
+
+typedef struct {
+    CARD8 type;                        /* always rfbClientCutText */
+    CARD8 pad1;
+    CARD16 pad2;
+    CARD32 length;
+    /* followed by char text[length] */
+} rfbClientCutTextMsg;
+
+#define sz_rfbClientCutTextMsg 8
+
+/*-----------------------------------------------------------------------------
+ * Union of all client->server messages.
+ */
+
+typedef union {
+    CARD8 type;
+    rfbSetPixelFormatMsg spf;
+    rfbSetScaleFactorMsg ssf;
+    rfbFixColourMapEntriesMsg fcme;
+    rfbSetEncodingsMsg se;
+    rfbFramebufferUpdateRequestMsg fur;
+    rfbKeyEventMsg ke;
+    rfbPointerEventMsg pe;
+    rfbClientCutTextMsg cct;
+} rfbClientToServerMsg;