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

midi

开发平台:

Unix_Linux

  1. /*****************************************************************************
  2.  * sdl.c: SDL video output display method
  3.  *****************************************************************************
  4.  * Copyright (C) 1998-2001 the VideoLAN team
  5.  * $Id: ac19b285905b9388cf81d8177d4b978912e1bfe7 $
  6.  *
  7.  * Authors: Samuel Hocevar <sam@zoy.org>
  8.  *          Pierre Baillet <oct@zoy.org>
  9.  *          Arnaud de Bossoreille de Ribou <bozo@via.ecp.fr>
  10.  *
  11.  * This program is free software; you can redistribute it and/or modify
  12.  * it under the terms of the GNU General Public License as published by
  13.  * the Free Software Foundation; either version 2 of the License, or
  14.  * (at your option) any later version.
  15.  *
  16.  * This program is distributed in the hope that it will be useful,
  17.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19.  * GNU General Public License for more details.
  20.  *
  21.  * You should have received a copy of the GNU General Public License
  22.  * along with this program; if not, write to the Free Software
  23.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  24.  *****************************************************************************/
  25. /*****************************************************************************
  26.  * Preamble
  27.  *****************************************************************************/
  28. #include <errno.h>                                                 /* ENOMEM */
  29. #ifdef HAVE_CONFIG_H
  30. # include "config.h"
  31. #endif
  32. #include <vlc_common.h>
  33. #include <vlc_plugin.h>
  34. #include <vlc_interface.h>
  35. #include <vlc_playlist.h>
  36. #include <vlc_vout.h>
  37. #include <vlc_keys.h>
  38. //#include <vlc_aout.h>
  39. #include <sys/types.h>
  40. #ifndef WIN32
  41. #   include <netinet/in.h>                            /* BSD: struct in_addr */
  42. #endif
  43. #include SDL_INCLUDE_FILE
  44. /* SDL is not able to crop overlays - so use only 1 direct buffer */
  45. #define SDL_MAX_DIRECTBUFFERS 1
  46. #define SDL_DEFAULT_BPP 16
  47. /*****************************************************************************
  48.  * vout_sys_t: video output SDL method descriptor
  49.  *****************************************************************************
  50.  * This structure is part of the video output thread descriptor.
  51.  * It describes the SDL specific properties of an output thread.
  52.  *****************************************************************************/
  53. struct vout_sys_t
  54. {
  55.     SDL_Surface *   p_display;                             /* display device */
  56.     int i_width;
  57.     int i_height;
  58. #if SDL_VERSION_ATLEAST(1,2,10)
  59.     unsigned int i_desktop_width;
  60.     unsigned int i_desktop_height;
  61. #endif
  62.     /* For YUV output */
  63.     SDL_Overlay * p_overlay;   /* An overlay we keep to grab the XVideo port */
  64.     /* For RGB output */
  65.     int i_surfaces;
  66.     bool  b_cursor;
  67.     bool  b_cursor_autohidden;
  68.     mtime_t     i_lastmoved;
  69.     mtime_t     i_mouse_hide_timeout;
  70.     mtime_t     i_lastpressed;                        /* to track dbl-clicks */
  71. };
  72. /*****************************************************************************
  73.  * picture_sys_t: direct buffer method descriptor
  74.  *****************************************************************************
  75.  * This structure is part of the picture descriptor, it describes the
  76.  * SDL specific properties of a direct buffer.
  77.  *****************************************************************************/
  78. struct picture_sys_t
  79. {
  80.     SDL_Overlay *p_overlay;
  81. };
  82. /*****************************************************************************
  83.  * Local prototypes
  84.  *****************************************************************************/
  85. static int  Open      ( vlc_object_t * );
  86. static void Close     ( vlc_object_t * );
  87. static int  Init      ( vout_thread_t * );
  88. static void End       ( vout_thread_t * );
  89. static int  Manage    ( vout_thread_t * );
  90. static void Display   ( vout_thread_t *, picture_t * );
  91. static int  OpenDisplay     ( vout_thread_t * );
  92. static void CloseDisplay    ( vout_thread_t * );
  93. static int  NewPicture      ( vout_thread_t *, picture_t * );
  94. static void SetPalette      ( vout_thread_t *,
  95.                               uint16_t *, uint16_t *, uint16_t * );
  96. static int ConvertKey( SDLKey );
  97. #define CHROMA_TEXT N_("SDL chroma format")
  98. #define CHROMA_LONGTEXT N_( 
  99.     "Force the SDL renderer to use a specific chroma format instead of " 
  100.     "trying to improve performances by using the most efficient one.")
  101. /*****************************************************************************
  102.  * Module descriptor
  103.  *****************************************************************************/
  104. vlc_module_begin ()
  105.     set_shortname( "SDL" )
  106.     set_category( CAT_VIDEO )
  107.     set_subcategory( SUBCAT_VIDEO_VOUT )
  108.     set_description( N_("Simple DirectMedia Layer video output") )
  109.     set_capability( "video output", 60 )
  110.     add_shortcut( "sdl" )
  111.     add_string( "sdl-chroma", NULL, NULL, CHROMA_TEXT, CHROMA_LONGTEXT, true )
  112.     set_callbacks( Open, Close )
  113. #if defined( __i386__ ) || defined( __x86_64__ )
  114.     /* On i386, SDL is linked against svgalib */
  115.     linked_with_a_crap_library_which_uses_atexit ()
  116. #endif
  117. vlc_module_end ()
  118. static vlc_mutex_t sdl_lock = VLC_STATIC_MUTEX;
  119. /*****************************************************************************
  120.  * OpenVideo: allocate SDL video thread output method
  121.  *****************************************************************************
  122.  * This function allocate and initialize a SDL vout method. It uses some of the
  123.  * vout properties to choose the correct mode, and change them according to the
  124.  * mode actually used.
  125.  *****************************************************************************/
  126. static int Open ( vlc_object_t *p_this )
  127. {
  128.     vout_thread_t * p_vout = (vout_thread_t *)p_this;
  129.     /* XXX: check for conflicts with the SDL audio output */
  130.     vlc_mutex_lock( &sdl_lock );
  131. #ifdef HAVE_SETENV
  132.     char *psz_method;
  133. #endif
  134.     p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
  135.     if( p_vout->p_sys == NULL )
  136.     {
  137.         vlc_mutex_unlock( &sdl_lock );
  138.         return VLC_ENOMEM;
  139.     }
  140.     memset( p_vout->p_sys, 0, sizeof( vout_sys_t ) );
  141.     /* Check if SDL video module has been initialized */
  142.     if( SDL_WasInit( SDL_INIT_VIDEO ) != 0 )
  143.     {
  144.         vlc_mutex_unlock( &sdl_lock );
  145.         free( p_vout->p_sys );
  146.         return VLC_EGENERIC;
  147.     }
  148.     /* Allocate structure */
  149.     p_vout->pf_init = Init;
  150.     p_vout->pf_end = End;
  151.     p_vout->pf_manage = Manage;
  152.     p_vout->pf_render = NULL;
  153.     p_vout->pf_display = Display;
  154.     p_vout->pf_control = NULL;
  155. #ifdef HAVE_SETENV
  156.     char* psz = psz_method = config_GetPsz( p_vout, "vout" );
  157.     if( psz_method )
  158.     {
  159.         while( *psz_method && *psz_method != ':' )
  160.         {
  161.             psz_method++;
  162.         }
  163.         if( *psz_method )
  164.         {
  165.             setenv( "SDL_VIDEODRIVER", psz_method + 1, 1 );
  166.         }
  167.     }
  168.     free( psz );
  169. #endif
  170.     /* Initialize library */
  171.     if( SDL_Init( SDL_INIT_VIDEO
  172. #ifndef WIN32
  173.     /* Win32 SDL implementation doesn't support SDL_INIT_EVENTTHREAD yet*/
  174.                 | SDL_INIT_EVENTTHREAD
  175. #endif
  176. #ifndef NDEBUG
  177.     /* In debug mode you may want vlc to dump a core instead of staying
  178.      * stuck */
  179.                 | SDL_INIT_NOPARACHUTE
  180. #endif
  181.                 ) < 0 )
  182.     {
  183.         msg_Err( p_vout, "cannot initialize SDL (%s)", SDL_GetError() );
  184.         free( p_vout->p_sys );
  185.         vlc_mutex_unlock( &sdl_lock );
  186.         return VLC_EGENERIC;
  187.     }
  188.     vlc_mutex_unlock( &sdl_lock );
  189.     /* Translate keys into unicode */
  190.     SDL_EnableUNICODE(1);
  191.     /* Get the desktop resolution */
  192. #if SDL_VERSION_ATLEAST(1,2,10)
  193.     /* FIXME: SDL has a problem with virtual desktop */
  194.     p_vout->p_sys->i_desktop_width = SDL_GetVideoInfo()->current_w;
  195.     p_vout->p_sys->i_desktop_height = SDL_GetVideoInfo()->current_h;
  196. #endif
  197.     /* Create the cursor */
  198.     p_vout->p_sys->b_cursor = 1;
  199.     p_vout->p_sys->b_cursor_autohidden = 0;
  200.     p_vout->p_sys->i_lastmoved = p_vout->p_sys->i_lastpressed = mdate();
  201.     p_vout->p_sys->i_mouse_hide_timeout =
  202.         var_GetInteger(p_vout, "mouse-hide-timeout") * 1000;
  203.     if( OpenDisplay( p_vout ) )
  204.     {
  205.         msg_Err( p_vout, "cannot set up SDL (%s)", SDL_GetError() );
  206.         SDL_QuitSubSystem( SDL_INIT_VIDEO );
  207.         free( p_vout->p_sys );
  208.         return VLC_EGENERIC;
  209.     }
  210.     return VLC_SUCCESS;
  211. }
  212. /*****************************************************************************
  213.  * Init: initialize SDL video thread output method
  214.  *****************************************************************************
  215.  * This function initialize the SDL display device.
  216.  *****************************************************************************/
  217. static int Init( vout_thread_t *p_vout )
  218. {
  219.     int i_index;
  220.     picture_t *p_pic;
  221.     p_vout->p_sys->i_surfaces = 0;
  222.     I_OUTPUTPICTURES = 0;
  223.     /* Initialize the output structure */
  224.     if( p_vout->p_sys->p_overlay == NULL )
  225.     {
  226.         /* All we have is an RGB image with square pixels */
  227.         p_vout->output.i_width  = p_vout->p_sys->i_width;
  228.         p_vout->output.i_height = p_vout->p_sys->i_height;
  229.         p_vout->output.i_aspect = p_vout->output.i_width
  230.                                    * VOUT_ASPECT_FACTOR
  231.                                    / p_vout->output.i_height;
  232.     }
  233.     else
  234.     {
  235.         /* We may need to convert the chroma, but at least we keep the
  236.          * aspect ratio */
  237.         p_vout->output.i_width  = p_vout->render.i_width;
  238.         p_vout->output.i_height = p_vout->render.i_height;
  239.         p_vout->output.i_aspect = p_vout->render.i_aspect;
  240.     }
  241.     /* Try to initialize SDL_MAX_DIRECTBUFFERS direct buffers */
  242.     while( I_OUTPUTPICTURES < SDL_MAX_DIRECTBUFFERS )
  243.     {
  244.         p_pic = NULL;
  245.         /* Find an empty picture slot */
  246.         for( i_index = 0 ; i_index < VOUT_MAX_PICTURES ; i_index++ )
  247.         {
  248.             if( p_vout->p_picture[ i_index ].i_status == FREE_PICTURE )
  249.             {
  250.                 p_pic = p_vout->p_picture + i_index;
  251.                 break;
  252.             }
  253.         }
  254.         /* Allocate the picture if we found one */
  255.         if( p_pic == NULL || NewPicture( p_vout, p_pic ) )
  256.         {
  257.             break;
  258.         }
  259.         p_pic->i_status = DESTROYED_PICTURE;
  260.         p_pic->i_type   = DIRECT_PICTURE;
  261.         PP_OUTPUTPICTURE[ I_OUTPUTPICTURES ] = p_pic;
  262.         I_OUTPUTPICTURES++;
  263.     }
  264.     return VLC_SUCCESS;
  265. }
  266. /*****************************************************************************
  267.  * End: terminate Sys video thread output method
  268.  *****************************************************************************
  269.  * Terminate an output method created by OpenVideo
  270.  *****************************************************************************/
  271. static void End( vout_thread_t *p_vout )
  272. {
  273.     int i_index;
  274.     /* Free the output buffers we allocated */
  275.     for( i_index = I_OUTPUTPICTURES ; i_index ; )
  276.     {
  277.         i_index--;
  278.         if( p_vout->p_sys->p_overlay == NULL )
  279.         {
  280.             /* RGB picture */
  281.         }
  282.         else
  283.         {
  284.             SDL_UnlockYUVOverlay(
  285.                     PP_OUTPUTPICTURE[ i_index ]->p_sys->p_overlay );
  286.             SDL_FreeYUVOverlay(
  287.                     PP_OUTPUTPICTURE[ i_index ]->p_sys->p_overlay );
  288.         }
  289.         free( PP_OUTPUTPICTURE[ i_index ]->p_sys );
  290.     }
  291. }
  292. /*****************************************************************************
  293.  * CloseVideo: destroy Sys video thread output method
  294.  *****************************************************************************
  295.  * Terminate an output method created by vout_SDLCreate
  296.  *****************************************************************************/
  297. static void Close ( vlc_object_t *p_this )
  298. {
  299.     vout_thread_t * p_vout = (vout_thread_t *)p_this;
  300.     CloseDisplay( p_vout );
  301.     SDL_QuitSubSystem( SDL_INIT_VIDEO );
  302.     free( p_vout->p_sys );
  303. }
  304. /*****************************************************************************
  305.  * Manage: handle Sys events
  306.  *****************************************************************************
  307.  * This function should be called regularly by video output thread. It returns
  308.  * a non null value if an error occurred.
  309.  *****************************************************************************/
  310. static int Manage( vout_thread_t *p_vout )
  311. {
  312.     SDL_Event event;                                            /* SDL event */
  313.     vlc_value_t val;
  314.     unsigned int i_width, i_height, i_x, i_y;
  315.     /* Process events */
  316.     while( SDL_PollEvent( &event ) )
  317.     {
  318.         switch( event.type )
  319.         {
  320.         /* Resizing of window */
  321.         case SDL_VIDEORESIZE:
  322.             p_vout->i_changes |= VOUT_SIZE_CHANGE;
  323.             p_vout->i_window_width = p_vout->p_sys->i_width = event.resize.w;
  324.             p_vout->i_window_height = p_vout->p_sys->i_height = event.resize.h;
  325.             break;
  326.         /* Mouse move */
  327.         case SDL_MOUSEMOTION:
  328.             vout_PlacePicture( p_vout, p_vout->p_sys->i_width,
  329.                                p_vout->p_sys->i_height,
  330.                                &i_x, &i_y, &i_width, &i_height );
  331.             /* Compute the x coordinate and check if the value is
  332.                in [0,p_vout->fmt_in.i_visible_width] */
  333.             val.i_int = ( event.motion.x - i_x ) *
  334.                         p_vout->fmt_in.i_visible_width / i_width +
  335.                         p_vout->fmt_in.i_x_offset;
  336.             if( (int)(event.motion.x - i_x) < 0 )
  337.                 val.i_int = 0;
  338.             else if( (unsigned int)val.i_int > p_vout->fmt_in.i_visible_width )
  339.                 val.i_int = p_vout->fmt_in.i_visible_width;
  340.             var_Set( p_vout, "mouse-x", val );
  341.             /* compute the y coordinate and check if the value is
  342.                in [0,p_vout->fmt_in.i_visible_height] */
  343.             val.i_int = ( event.motion.y - i_y ) *
  344.                         p_vout->fmt_in.i_visible_height / i_height +
  345.                         p_vout->fmt_in.i_y_offset;
  346.             if( (int)(event.motion.y - i_y) < 0 )
  347.                 val.i_int = 0;
  348.             else if( (unsigned int)val.i_int > p_vout->fmt_in.i_visible_height )
  349.                 val.i_int = p_vout->fmt_in.i_visible_height;
  350.             var_Set( p_vout, "mouse-y", val );
  351.             var_SetBool( p_vout, "mouse-moved", true );
  352.             if( p_vout->p_sys->b_cursor )
  353.             {
  354.                 if( p_vout->p_sys->b_cursor_autohidden )
  355.                 {
  356.                     p_vout->p_sys->b_cursor_autohidden = 0;
  357.                     SDL_ShowCursor( 1 );
  358.                 }
  359.                 else
  360.                 {
  361.                     p_vout->p_sys->i_lastmoved = mdate();
  362.                 }
  363.             }
  364.             break;
  365.         /* Mouse button released */
  366.         case SDL_MOUSEBUTTONUP:
  367.             switch( event.button.button )
  368.             {
  369.             case SDL_BUTTON_LEFT:
  370.                 {
  371.                     var_Get( p_vout, "mouse-button-down", &val );
  372.                     val.i_int &= ~1;
  373.                     var_Set( p_vout, "mouse-button-down", val );
  374.                     var_SetBool( p_vout, "mouse-clicked", true );
  375.                     var_SetBool( p_vout->p_libvlc, "intf-popupmenu", false );
  376.                 }
  377.                 break;
  378.             case SDL_BUTTON_MIDDLE:
  379.                 {
  380.                     var_Get( p_vout, "mouse-button-down", &val );
  381.                     val.i_int &= ~2;
  382.                     var_Set( p_vout, "mouse-button-down", val );
  383.                     var_Get( p_vout->p_libvlc, "intf-show", &val );
  384.                     val.b_bool = !val.b_bool;
  385.                     var_Set( p_vout->p_libvlc, "intf-show", val );
  386.                 }
  387.                 break;
  388.             case SDL_BUTTON_RIGHT:
  389.                 {
  390.                     var_Get( p_vout, "mouse-button-down", &val );
  391.                     val.i_int &= ~4;
  392.                     var_Set( p_vout, "mouse-button-down", val );
  393.                     var_SetBool( p_vout->p_libvlc, "intf-popupmenu", true );
  394.                 }
  395.                 break;
  396.             }
  397.             break;
  398.         /* Mouse button pressed */
  399.         case SDL_MOUSEBUTTONDOWN:
  400.             switch( event.button.button )
  401.             {
  402.             case SDL_BUTTON_LEFT:
  403.                 var_Get( p_vout, "mouse-button-down", &val );
  404.                 val.i_int |= 1;
  405.                 var_Set( p_vout, "mouse-button-down", val );
  406.                 /* detect double-clicks */
  407.                 if( ( mdate() - p_vout->p_sys->i_lastpressed ) < 300000 )
  408.                     p_vout->i_changes |= VOUT_FULLSCREEN_CHANGE;
  409.                 p_vout->p_sys->i_lastpressed = mdate();
  410.                 break;
  411.             case SDL_BUTTON_MIDDLE:
  412.                 var_Get( p_vout, "mouse-button-down", &val );
  413.                 val.i_int |= 2;
  414.                 var_Set( p_vout, "mouse-button-down", val );
  415.                 break;
  416.             case SDL_BUTTON_RIGHT:
  417.                 var_Get( p_vout, "mouse-button-down", &val );
  418.                 val.i_int |= 4;
  419.                 var_Set( p_vout, "mouse-button-down", val );
  420.                 break;
  421.             }
  422.             break;
  423.         /* Quit event (close the window) */
  424.         case SDL_QUIT:
  425.             {
  426. #if 0
  427.                 playlist_t *p_playlist = pl_Hold( p_vout );
  428.                 if( p_playlist != NULL )
  429.                 {
  430.                     playlist_Stop( p_playlist );
  431.                     pl_Release( p_vout );
  432.                 }
  433. #else
  434. #warning FIXME FIXME ?
  435. #endif
  436.             }
  437.             break;
  438.         /* Key pressed */
  439.         case SDL_KEYDOWN:
  440.             /* convert the key if possible */
  441.             val.i_int = ConvertKey( event.key.keysym.sym );
  442.             if( !val.i_int )
  443.             {
  444.                 /* Find the right caracter */
  445.                 if( ( event.key.keysym.unicode & 0xff80 ) == 0 )
  446.                 {
  447.                     val.i_int = event.key.keysym.unicode & 0x7f;
  448.                     /* FIXME: find a better solution than this
  449.                               hack to find the right caracter */
  450.                     if( val.i_int >= 1 && val.i_int <= 26 )
  451.                         val.i_int += 96;
  452.                     else if( val.i_int >= 65 && val.i_int <= 90 )
  453.                         val.i_int += 32;
  454.                 }
  455.             }
  456.             if( val.i_int )
  457.             {
  458.                 if( ( event.key.keysym.mod & KMOD_SHIFT ) )
  459.                 {
  460.                     val.i_int |= KEY_MODIFIER_SHIFT;
  461.                 }
  462.                 if( ( event.key.keysym.mod & KMOD_CTRL ) )
  463.                 {
  464.                     val.i_int |= KEY_MODIFIER_CTRL;
  465.                 }
  466.                 if( ( event.key.keysym.mod & KMOD_ALT ) )
  467.                 {
  468.                     val.i_int |= KEY_MODIFIER_ALT;
  469.                 }
  470.                 var_Set( p_vout->p_libvlc, "key-pressed", val );
  471.             }
  472.         default:
  473.             break;
  474.         }
  475.     }
  476.     /* Fullscreen change */
  477.     if( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE )
  478.     {
  479.         vlc_value_t val_fs;
  480.         /* Update the object variable and trigger callback */
  481.         val_fs.b_bool = !p_vout->b_fullscreen;
  482.         p_vout->b_fullscreen = !p_vout->b_fullscreen;
  483.         var_Set( p_vout, "fullscreen", val_fs );
  484.         /*TODO: add the "always on top" code here !*/
  485.         p_vout->p_sys->b_cursor_autohidden = 0;
  486.         SDL_ShowCursor( p_vout->p_sys->b_cursor &&
  487.                         ! p_vout->p_sys->b_cursor_autohidden );
  488.         p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
  489.         p_vout->i_changes |= VOUT_SIZE_CHANGE;
  490.     }
  491.     /* autoscale toggle */
  492.     if( p_vout->i_changes & VOUT_SCALE_CHANGE )
  493.     {
  494.         p_vout->i_changes &= ~VOUT_SCALE_CHANGE;
  495.         p_vout->b_autoscale = var_GetBool( p_vout, "autoscale" );
  496.         p_vout->i_zoom = (int) ZOOM_FP_FACTOR;
  497.         p_vout->i_changes |= VOUT_SIZE_CHANGE;
  498.     }
  499.     /* scaling factor (if no-autoscale) */
  500.     if( p_vout->i_changes & VOUT_ZOOM_CHANGE )
  501.     {
  502.         p_vout->i_changes &= ~VOUT_ZOOM_CHANGE;
  503.         p_vout->b_autoscale = false;
  504.         p_vout->i_zoom = (int)( ZOOM_FP_FACTOR * var_GetFloat( p_vout, "scale" ) );
  505.         p_vout->i_changes |= VOUT_SIZE_CHANGE;
  506.     }
  507.     /* Crop or Aspect Ratio Changes */
  508.     if( p_vout->i_changes & VOUT_CROP_CHANGE ||
  509.         p_vout->i_changes & VOUT_ASPECT_CHANGE )
  510.     {
  511.         p_vout->i_changes &= ~VOUT_CROP_CHANGE;
  512.         p_vout->i_changes &= ~VOUT_ASPECT_CHANGE;
  513.         p_vout->fmt_out.i_x_offset = p_vout->fmt_in.i_x_offset;
  514.         p_vout->fmt_out.i_y_offset = p_vout->fmt_in.i_y_offset;
  515.         p_vout->fmt_out.i_visible_width = p_vout->fmt_in.i_visible_width;
  516.         p_vout->fmt_out.i_visible_height = p_vout->fmt_in.i_visible_height;
  517.         p_vout->fmt_out.i_aspect = p_vout->fmt_in.i_aspect;
  518.         p_vout->fmt_out.i_sar_num = p_vout->fmt_in.i_sar_num;
  519.         p_vout->fmt_out.i_sar_den = p_vout->fmt_in.i_sar_den;
  520.         p_vout->output.i_aspect = p_vout->fmt_in.i_aspect;
  521.         p_vout->i_changes |= VOUT_SIZE_CHANGE;
  522.     }
  523.     /* Size change */
  524.     if( p_vout->i_changes & VOUT_SIZE_CHANGE )
  525.     {
  526.         msg_Dbg( p_vout, "video display resized (%dx%d)",
  527.                  p_vout->p_sys->i_width, p_vout->p_sys->i_height );
  528.         CloseDisplay( p_vout );
  529.         OpenDisplay( p_vout );
  530.         /* We don't need to signal the vout thread about the size change if
  531.          * we can handle rescaling ourselves */
  532.         if( p_vout->p_sys->p_overlay != NULL )
  533.             p_vout->i_changes &= ~VOUT_SIZE_CHANGE;
  534.     }
  535.     /* Pointer change */
  536.     if( ! p_vout->p_sys->b_cursor_autohidden &&
  537.         ( mdate() - p_vout->p_sys->i_lastmoved >
  538.             p_vout->p_sys->i_mouse_hide_timeout ) )
  539.     {
  540.         /* Hide the mouse automatically */
  541.         p_vout->p_sys->b_cursor_autohidden = 1;
  542.         SDL_ShowCursor( 0 );
  543.     }
  544.     return VLC_SUCCESS;
  545. }
  546. /*****************************************************************************
  547.  * Key events handling
  548.  *****************************************************************************/
  549. static const struct
  550. {
  551.     SDLKey sdl_key;
  552.     int i_vlckey;
  553. } sdlkeys_to_vlckeys[] =
  554. {
  555.     { SDLK_F1,  KEY_F1 },
  556.     { SDLK_F2,  KEY_F2 },
  557.     { SDLK_F3,  KEY_F3 },
  558.     { SDLK_F4,  KEY_F4 },
  559.     { SDLK_F5,  KEY_F5 },
  560.     { SDLK_F6,  KEY_F6 },
  561.     { SDLK_F7,  KEY_F7 },
  562.     { SDLK_F8,  KEY_F8 },
  563.     { SDLK_F9,  KEY_F9 },
  564.     { SDLK_F10, KEY_F10 },
  565.     { SDLK_F11, KEY_F11 },
  566.     { SDLK_F12, KEY_F12 },
  567.     { SDLK_RETURN, KEY_ENTER },
  568.     { SDLK_KP_ENTER, KEY_ENTER },
  569.     { SDLK_SPACE, KEY_SPACE },
  570.     { SDLK_ESCAPE, KEY_ESC },
  571.     { SDLK_MENU, KEY_MENU },
  572.     { SDLK_LEFT, KEY_LEFT },
  573.     { SDLK_RIGHT, KEY_RIGHT },
  574.     { SDLK_UP, KEY_UP },
  575.     { SDLK_DOWN, KEY_DOWN },
  576.     { SDLK_HOME, KEY_HOME },
  577.     { SDLK_END, KEY_END },
  578.     { SDLK_PAGEUP, KEY_PAGEUP },
  579.     { SDLK_PAGEDOWN,  KEY_PAGEDOWN },
  580.     { SDLK_INSERT, KEY_INSERT },
  581.     { SDLK_DELETE, KEY_DELETE },
  582.     /*TODO: find a equivalent for SDL 
  583.     { , KEY_MEDIA_NEXT_TRACK }
  584.     { , KEY_MEDIA_PREV_TRACK }
  585.     { , KEY_VOLUME_MUTE }
  586.     { , KEY_VOLUME_DOWN }
  587.     { , KEY_VOLUME_UP }
  588.     { , KEY_MEDIA_PLAY_PAUSE }
  589.     { , KEY_MEDIA_PLAY_PAUSE }*/
  590.     { 0, 0 }
  591. };
  592. static int ConvertKey( SDLKey sdl_key )
  593. {
  594.     int i;
  595.     for( i=0; sdlkeys_to_vlckeys[i].sdl_key != 0; i++ )
  596.     {
  597.         if( sdlkeys_to_vlckeys[i].sdl_key == sdl_key )
  598.         {
  599.             return sdlkeys_to_vlckeys[i].i_vlckey;
  600.         }
  601.     }
  602.     return 0;
  603. }
  604. /*****************************************************************************
  605.  * Display: displays previously rendered output
  606.  *****************************************************************************
  607.  * This function sends the currently rendered image to the display.
  608.  *****************************************************************************/
  609. static void Display( vout_thread_t *p_vout, picture_t *p_pic )
  610. {
  611.     unsigned int x, y, w, h;
  612.     SDL_Rect disp;
  613.     vout_PlacePicture( p_vout, p_vout->p_sys->i_width, p_vout->p_sys->i_height,
  614.                        &x, &y, &w, &h );
  615.     disp.x = x;
  616.     disp.y = y;
  617.     disp.w = w;
  618.     disp.h = h;
  619.     if( p_vout->p_sys->p_overlay == NULL )
  620.     {
  621.         /* RGB picture */
  622.         SDL_Flip( p_vout->p_sys->p_display );
  623.     }
  624.     else
  625.     {
  626.         /* Overlay picture */
  627.         SDL_UnlockYUVOverlay( p_pic->p_sys->p_overlay);
  628.         SDL_DisplayYUVOverlay( p_pic->p_sys->p_overlay , &disp );
  629.         SDL_LockYUVOverlay( p_pic->p_sys->p_overlay);
  630.     }
  631. }
  632. /* following functions are local */
  633. /*****************************************************************************
  634.  * OpenDisplay: open and initialize SDL device
  635.  *****************************************************************************
  636.  * Open and initialize display according to preferences specified in the vout
  637.  * thread fields.
  638.  *****************************************************************************/
  639. static int OpenDisplay( vout_thread_t *p_vout )
  640. {
  641.     uint32_t i_flags;
  642.     int i_bpp;
  643.     /* SDL fucked up fourcc definitions on bigendian machines */
  644.     uint32_t i_sdl_chroma;
  645.     char *psz_chroma = NULL;
  646.     uint32_t i_chroma = 0;
  647.     bool b_overlay = config_GetInt( p_vout, "overlay" );
  648.     /* Set main window's size */
  649. #if SDL_VERSION_ATLEAST(1,2,10)
  650.     p_vout->p_sys->i_width = p_vout->b_fullscreen ? p_vout->p_sys->i_desktop_width :
  651.                                                     p_vout->i_window_width;
  652.     p_vout->p_sys->i_height = p_vout->b_fullscreen ? p_vout->p_sys->i_desktop_height :
  653.                                                      p_vout->i_window_height;
  654. #else
  655.     p_vout->p_sys->i_width = p_vout->b_fullscreen ? p_vout->output.i_width :
  656.                                                     p_vout->i_window_width;
  657.     p_vout->p_sys->i_height = p_vout->b_fullscreen ? p_vout->output.i_height :
  658.                                                      p_vout->i_window_height;
  659. #endif
  660.     /* Initialize flags and cursor */
  661.     i_flags = SDL_ANYFORMAT | SDL_HWPALETTE | SDL_HWSURFACE | SDL_DOUBLEBUF;
  662.     i_flags |= p_vout->b_fullscreen ? SDL_FULLSCREEN : SDL_RESIZABLE;
  663.     i_bpp = SDL_VideoModeOK( p_vout->p_sys->i_width, p_vout->p_sys->i_height,
  664.                              SDL_DEFAULT_BPP, i_flags );
  665.     if( i_bpp == 0 )
  666.     {
  667.         msg_Err( p_vout, "no video mode available" );
  668.         return VLC_EGENERIC;
  669.     }
  670.     p_vout->p_sys->p_display = SDL_SetVideoMode( p_vout->p_sys->i_width,
  671.                                                  p_vout->p_sys->i_height,
  672.                                                  i_bpp, i_flags );
  673.     if( p_vout->p_sys->p_display == NULL )
  674.     {
  675.         msg_Err( p_vout, "cannot set video mode" );
  676.         return VLC_EGENERIC;
  677.     }
  678.     SDL_LockSurface( p_vout->p_sys->p_display );
  679.     if( ( psz_chroma = config_GetPsz( p_vout, "sdl-chroma" ) ) )
  680.     {
  681.         if( strlen( psz_chroma ) >= 4 )
  682.         {
  683.             memcpy(&i_chroma, psz_chroma, 4);
  684.             msg_Dbg( p_vout, "Forcing chroma to 0x%.8x (%4.4s)", i_chroma, (char*)&i_chroma );
  685.         }
  686.         else
  687.         {
  688.             free( psz_chroma );
  689.             psz_chroma = NULL;
  690.         }
  691.     }
  692.     if( b_overlay )
  693.     {
  694.         /* Choose the chroma we will try first. */
  695.         do
  696.         {
  697.             if( !psz_chroma ) i_chroma = 0;
  698.             switch( i_chroma ? i_chroma : p_vout->render.i_chroma )
  699.             {
  700.                 case VLC_FOURCC('Y','U','Y','2'):
  701.                 case VLC_FOURCC('Y','U','N','V'):
  702.                     p_vout->output.i_chroma = VLC_FOURCC('Y','U','Y','2');
  703.                     i_sdl_chroma = SDL_YUY2_OVERLAY;
  704.                     break;
  705.                 case VLC_FOURCC('U','Y','V','Y'):
  706.                 case VLC_FOURCC('U','Y','N','V'):
  707.                 case VLC_FOURCC('Y','4','2','2'):
  708.                     p_vout->output.i_chroma = VLC_FOURCC('U','Y','V','Y');
  709.                     i_sdl_chroma = SDL_UYVY_OVERLAY;
  710.                     break;
  711.                 case VLC_FOURCC('Y','V','Y','U'):
  712.                     p_vout->output.i_chroma = VLC_FOURCC('Y','V','Y','U');
  713.                     i_sdl_chroma = SDL_YVYU_OVERLAY;
  714.                     break;
  715.                 case VLC_FOURCC('Y','V','1','2'):
  716.                 case VLC_FOURCC('I','4','2','0'):
  717.                 case VLC_FOURCC('I','Y','U','V'):
  718.                 default:
  719.                     p_vout->output.i_chroma = VLC_FOURCC('Y','V','1','2');
  720.                     i_sdl_chroma = SDL_YV12_OVERLAY;
  721.                     break;
  722.             }
  723.             free( psz_chroma ); psz_chroma = NULL;
  724.             p_vout->p_sys->p_overlay =
  725.                 SDL_CreateYUVOverlay( 32, 32, i_sdl_chroma,
  726.                                       p_vout->p_sys->p_display );
  727.             /* FIXME: if the first overlay we find is software, don't stop,
  728.              * because we may find a hardware one later ... */
  729.         }
  730.         while( i_chroma && !p_vout->p_sys->p_overlay );
  731.         /* If this best choice failed, fall back to other chromas */
  732.         if( p_vout->p_sys->p_overlay == NULL )
  733.         {
  734.             p_vout->output.i_chroma = VLC_FOURCC('I','Y','U','V');
  735.             p_vout->p_sys->p_overlay =
  736.                 SDL_CreateYUVOverlay( 32, 32, SDL_IYUV_OVERLAY,
  737.                                       p_vout->p_sys->p_display );
  738.         }
  739.         if( p_vout->p_sys->p_overlay == NULL )
  740.         {
  741.             p_vout->output.i_chroma = VLC_FOURCC('Y','V','1','2');
  742.             p_vout->p_sys->p_overlay =
  743.                 SDL_CreateYUVOverlay( 32, 32, SDL_YV12_OVERLAY,
  744.                                       p_vout->p_sys->p_display );
  745.         }
  746.         if( p_vout->p_sys->p_overlay == NULL )
  747.         {
  748.             p_vout->output.i_chroma = VLC_FOURCC('Y','U','Y','2');
  749.             p_vout->p_sys->p_overlay =
  750.                 SDL_CreateYUVOverlay( 32, 32, SDL_YUY2_OVERLAY,
  751.                                       p_vout->p_sys->p_display );
  752.         }
  753.     }
  754.     if( p_vout->p_sys->p_overlay == NULL )
  755.     {
  756.         if( b_overlay )
  757.             msg_Warn( p_vout, "no SDL overlay for 0x%.8x (%4.4s)",
  758.                       p_vout->render.i_chroma,
  759.                       (char*)&p_vout->render.i_chroma );
  760.         else
  761.             msg_Warn( p_vout, "SDL overlay disabled by the user" );
  762.         switch( p_vout->p_sys->p_display->format->BitsPerPixel )
  763.         {
  764.             case 8:
  765.                 p_vout->output.i_chroma = VLC_FOURCC('R','G','B','2');
  766.                 p_vout->output.pf_setpalette = SetPalette;
  767.                 break;
  768.             case 15:
  769.                 p_vout->output.i_chroma = VLC_FOURCC('R','V','1','5');
  770.                 break;
  771.             case 16:
  772.                 p_vout->output.i_chroma = VLC_FOURCC('R','V','1','6');
  773.                 break;
  774.             case 24:
  775.                 p_vout->output.i_chroma = VLC_FOURCC('R','V','2','4');
  776.                 break;
  777.             case 32:
  778.                 p_vout->output.i_chroma = VLC_FOURCC('R','V','3','2');
  779.                 break;
  780.             default:
  781.                 msg_Err( p_vout, "unknown screen depth %i",
  782.                          p_vout->p_sys->p_display->format->BitsPerPixel );
  783.                 SDL_UnlockSurface( p_vout->p_sys->p_display );
  784.                 SDL_FreeSurface( p_vout->p_sys->p_display );
  785.                 return VLC_EGENERIC;
  786.         }
  787.         p_vout->output.i_rmask = p_vout->p_sys->p_display->format->Rmask;
  788.         p_vout->output.i_gmask = p_vout->p_sys->p_display->format->Gmask;
  789.         p_vout->output.i_bmask = p_vout->p_sys->p_display->format->Bmask;
  790.         SDL_WM_SetCaption( VOUT_TITLE " (software RGB SDL output)",
  791.                            VOUT_TITLE " (software RGB SDL output)" );
  792.     }
  793.     else
  794.     {
  795.         if( p_vout->p_sys->p_overlay->hw_overlay )
  796.         {
  797.             SDL_WM_SetCaption( VOUT_TITLE " (hardware YUV SDL output)",
  798.                                VOUT_TITLE " (hardware YUV SDL output)" );
  799.         }
  800.         else
  801.         {
  802.             SDL_WM_SetCaption( VOUT_TITLE " (software YUV SDL output)",
  803.                                VOUT_TITLE " (software YUV SDL output)" );
  804.         }
  805.     }
  806.     SDL_EventState( SDL_KEYUP, SDL_IGNORE );               /* ignore keys up */
  807.     return VLC_SUCCESS;
  808. }
  809. /*****************************************************************************
  810.  * CloseDisplay: close and reset SDL device
  811.  *****************************************************************************
  812.  * This function returns all resources allocated by OpenDisplay and restore
  813.  * the original state of the device.
  814.  *****************************************************************************/
  815. static void CloseDisplay( vout_thread_t *p_vout )
  816. {
  817.     SDL_FreeYUVOverlay( p_vout->p_sys->p_overlay );
  818.     SDL_UnlockSurface ( p_vout->p_sys->p_display );
  819.     SDL_FreeSurface( p_vout->p_sys->p_display );
  820. }
  821. /*****************************************************************************
  822.  * NewPicture: allocate a picture
  823.  *****************************************************************************
  824.  * Returns 0 on success, -1 otherwise
  825.  *****************************************************************************/
  826. static int NewPicture( vout_thread_t *p_vout, picture_t *p_pic )
  827. {
  828.     int i_width  = p_vout->output.i_width;
  829.     int i_height = p_vout->output.i_height;
  830.     if( p_vout->p_sys->p_overlay == NULL )
  831.     {
  832.         /* RGB picture */
  833.         if( p_vout->p_sys->i_surfaces )
  834.         {
  835.             /* We already allocated this surface, return */
  836.             return VLC_EGENERIC;
  837.         }
  838.         p_pic->p_sys = malloc( sizeof( picture_sys_t ) );
  839.         if( p_pic->p_sys == NULL )
  840.         {
  841.             return VLC_ENOMEM;
  842.         }
  843.         switch( p_vout->p_sys->p_display->format->BitsPerPixel )
  844.         {
  845.             case 8:
  846.                 p_pic->p->i_pixel_pitch = 1;
  847.                 break;
  848.             case 15:
  849.             case 16:
  850.                 p_pic->p->i_pixel_pitch = 2;
  851.                 break;
  852.             case 24:
  853.             case 32:
  854.                 p_pic->p->i_pixel_pitch = 4;
  855.                 break;
  856.             default:
  857.                 return VLC_EGENERIC;
  858.         }
  859.         p_pic->p->p_pixels = p_vout->p_sys->p_display->pixels;
  860.         p_pic->p->i_lines = p_vout->p_sys->p_display->h;
  861.         p_pic->p->i_visible_lines = p_vout->p_sys->p_display->h;
  862.         p_pic->p->i_pitch = p_vout->p_sys->p_display->pitch;
  863.         p_pic->p->i_visible_pitch =
  864.             p_pic->p->i_pixel_pitch * p_vout->p_sys->p_display->w;
  865.         p_vout->p_sys->i_surfaces++;
  866.         p_pic->i_planes = 1;
  867.     }
  868.     else
  869.     {
  870.         p_pic->p_sys = malloc( sizeof( picture_sys_t ) );
  871.         if( p_pic->p_sys == NULL )
  872.         {
  873.             return VLC_ENOMEM;
  874.         }
  875.         p_pic->p_sys->p_overlay =
  876.             SDL_CreateYUVOverlay( i_width, i_height,
  877.                                   p_vout->output.i_chroma,
  878.                                   p_vout->p_sys->p_display );
  879.         if( p_pic->p_sys->p_overlay == NULL )
  880.         {
  881.             free( p_pic->p_sys );
  882.             return VLC_EGENERIC;
  883.         }
  884.         SDL_LockYUVOverlay( p_pic->p_sys->p_overlay );
  885.         p_pic->Y_PIXELS = p_pic->p_sys->p_overlay->pixels[0];
  886.         p_pic->p[Y_PLANE].i_lines = p_pic->p_sys->p_overlay->h;
  887.         p_pic->p[Y_PLANE].i_visible_lines = p_pic->p_sys->p_overlay->h;
  888.         p_pic->p[Y_PLANE].i_pitch = p_pic->p_sys->p_overlay->pitches[0];
  889.         switch( p_vout->output.i_chroma )
  890.         {
  891.         case SDL_YV12_OVERLAY:
  892.             p_pic->p[Y_PLANE].i_pixel_pitch = 1;
  893.             p_pic->p[Y_PLANE].i_visible_pitch = p_pic->p_sys->p_overlay->w;
  894.             p_pic->U_PIXELS = p_pic->p_sys->p_overlay->pixels[2];
  895.             p_pic->p[U_PLANE].i_lines = p_pic->p_sys->p_overlay->h / 2;
  896.             p_pic->p[U_PLANE].i_visible_lines = p_pic->p_sys->p_overlay->h / 2;
  897.             p_pic->p[U_PLANE].i_pitch = p_pic->p_sys->p_overlay->pitches[2];
  898.             p_pic->p[U_PLANE].i_pixel_pitch = 1;
  899.             p_pic->p[U_PLANE].i_visible_pitch = p_pic->p_sys->p_overlay->w / 2;
  900.             p_pic->V_PIXELS = p_pic->p_sys->p_overlay->pixels[1];
  901.             p_pic->p[V_PLANE].i_lines = p_pic->p_sys->p_overlay->h / 2;
  902.             p_pic->p[V_PLANE].i_visible_lines = p_pic->p_sys->p_overlay->h / 2;
  903.             p_pic->p[V_PLANE].i_pitch = p_pic->p_sys->p_overlay->pitches[1];
  904.             p_pic->p[V_PLANE].i_pixel_pitch = 1;
  905.             p_pic->p[V_PLANE].i_visible_pitch = p_pic->p_sys->p_overlay->w / 2;
  906.             p_pic->i_planes = 3;
  907.             break;
  908.         case SDL_IYUV_OVERLAY:
  909.             p_pic->p[Y_PLANE].i_pixel_pitch = 1;
  910.             p_pic->p[Y_PLANE].i_visible_pitch = p_pic->p_sys->p_overlay->w;
  911.             p_pic->U_PIXELS = p_pic->p_sys->p_overlay->pixels[1];
  912.             p_pic->p[U_PLANE].i_lines = p_pic->p_sys->p_overlay->h / 2;
  913.             p_pic->p[U_PLANE].i_visible_lines = p_pic->p_sys->p_overlay->h / 2;
  914.             p_pic->p[U_PLANE].i_pitch = p_pic->p_sys->p_overlay->pitches[1];
  915.             p_pic->p[U_PLANE].i_pixel_pitch = 1;
  916.             p_pic->p[U_PLANE].i_visible_pitch = p_pic->p_sys->p_overlay->w / 2;
  917.             p_pic->V_PIXELS = p_pic->p_sys->p_overlay->pixels[2];
  918.             p_pic->p[V_PLANE].i_lines = p_pic->p_sys->p_overlay->h / 2;
  919.             p_pic->p[V_PLANE].i_visible_lines = p_pic->p_sys->p_overlay->h / 2;
  920.             p_pic->p[V_PLANE].i_pitch = p_pic->p_sys->p_overlay->pitches[2];
  921.             p_pic->p[V_PLANE].i_pixel_pitch = 1;
  922.             p_pic->p[V_PLANE].i_visible_pitch = p_pic->p_sys->p_overlay->w / 2;
  923.             p_pic->i_planes = 3;
  924.             break;
  925.         default:
  926.             p_pic->p[Y_PLANE].i_pixel_pitch = 2;
  927.             p_pic->p[U_PLANE].i_visible_pitch = p_pic->p_sys->p_overlay->w * 2;
  928.             p_pic->i_planes = 1;
  929.             break;
  930.         }
  931.     }
  932.     return VLC_SUCCESS;
  933. }
  934. /*****************************************************************************
  935.  * SetPalette: sets an 8 bpp palette
  936.  *****************************************************************************/
  937. static void SetPalette( vout_thread_t *p_vout,
  938.                         uint16_t *red, uint16_t *green, uint16_t *blue )
  939. {
  940.     SDL_Color colors[256];
  941.     int i;
  942.     /* Fill colors with color information */
  943.     for( i = 0; i < 256; i++ )
  944.     {
  945.         colors[ i ].r = red[ i ] >> 8;
  946.         colors[ i ].g = green[ i ] >> 8;
  947.         colors[ i ].b = blue[ i ] >> 8;
  948.     }
  949.     /* Set palette */
  950.     if( SDL_SetColors( p_vout->p_sys->p_display, colors, 0, 256 ) == 0 )
  951.     {
  952.         msg_Err( p_vout, "failed to set palette" );
  953.     }
  954. }