remoteosd.c
上传用户:kjfoods
上传日期:2020-07-06
资源大小:29949k
文件大小:51k
源码类别:

midi

开发平台:

Unix_Linux

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