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

midi

开发平台:

Unix_Linux

  1. /*****************************************************************************
  2.  * osdmenu.c: osd filter module
  3.  *****************************************************************************
  4.  * Copyright (C) 2004-2007 M2X
  5.  * $Id: 76214056519fe5ddb6ba84223963ea7e98bff044 $
  6.  *
  7.  * Authors: Jean-Paul Saman <jpsaman #_at_# m2x dot nl>
  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.  * Preamble
  25.  *****************************************************************************/
  26. #ifdef HAVE_CONFIG_H
  27. # include "config.h"
  28. #endif
  29. #include <vlc_common.h>
  30. #include <vlc_plugin.h>
  31. #include <vlc_vout.h>
  32. #include <vlc_filter.h>
  33. #include <vlc_osd.h>
  34. /*****************************************************************************
  35.  * Module descriptor
  36.  *****************************************************************************/
  37. /* FIXME: Future extension make the definition file in XML format. */
  38. #define OSD_FILE_TEXT N_("Configuration file")
  39. #define OSD_FILE_LONGTEXT N_( 
  40.     "Configuration file for the OSD Menu." )
  41. #define OSD_PATH_TEXT N_("Path to OSD menu images")
  42. #define OSD_PATH_LONGTEXT N_( 
  43.     "Path to the OSD menu images. This will override the path defined in the " 
  44.     "OSD configuration file." )
  45. #define POSX_TEXT N_("X coordinate")
  46. #define POSX_LONGTEXT N_("You can move the OSD menu by left-clicking on it." )
  47. #define POSY_TEXT N_("Y coordinate")
  48. #define POSY_LONGTEXT N_("You can move the OSD menu by left-clicking on it." )
  49. #define POS_TEXT N_("Menu position")
  50. #define POS_LONGTEXT N_( 
  51.   "You can enforce the OSD menu position on the video " 
  52.   "(0=center, 1=left, 2=right, 4=top, 8=bottom, you can " 
  53.   "also use combinations of these values, eg. 6 = top-right).")
  54. #define TIMEOUT_TEXT N_("Menu timeout")
  55. #define TIMEOUT_LONGTEXT N_( 
  56.     "OSD menu pictures get a default timeout of 15 seconds added to their " 
  57.     "remaining time. This will ensure that they are at least the specified " 
  58.     "time visible.")
  59. #define OSD_UPDATE_TEXT N_("Menu update interval" )
  60. #define OSD_UPDATE_LONGTEXT N_( 
  61.     "The default is to update the OSD menu picture every 200 ms. Shorten the" 
  62.     " update time for environments that experience transmissions errors. " 
  63.     "Be careful with this option as encoding OSD menu pictures is very " 
  64.     "computing intensive. The range is 0 - 1000 ms." )
  65. #define OSD_ALPHA_TEXT N_("Alpha transparency value (default 255)")
  66. #define OSD_ALPHA_LONGTEXT N_( 
  67.     "The transparency of the OSD menu can be changed by giving a value " 
  68.     "between 0 and 255. A lower value specifies more transparency a higher " 
  69.     "means less transparency. The default is being not transparent " 
  70.     "(value 255) the minimum is fully transparent (value 0)." )
  71. static const int pi_pos_values[] = { 0, 1, 2, 4, 8, 5, 6, 9, 10 };
  72. static const char *const ppsz_pos_descriptions[] =
  73. { N_("Center"), N_("Left"), N_("Right"), N_("Top"), N_("Bottom"),
  74.   N_("Top-Left"), N_("Top-Right"), N_("Bottom-Left"), N_("Bottom-Right") };
  75. /* subfilter functions */
  76. static int  CreateFilter ( vlc_object_t * );
  77. static void DestroyFilter( vlc_object_t * );
  78. static subpicture_t *Filter( filter_t *, mtime_t );
  79. static int OSDMenuUpdateEvent( vlc_object_t *, char const *,
  80.                     vlc_value_t, vlc_value_t, void * );
  81. static int OSDMenuVisibleEvent( vlc_object_t *, char const *,
  82.                     vlc_value_t, vlc_value_t, void * );
  83. static int OSDMenuCallback( vlc_object_t *, char const *,
  84.                             vlc_value_t, vlc_value_t, void * );
  85. static int MouseEvent( vlc_object_t *, char const *,
  86.                         vlc_value_t , vlc_value_t , void * );
  87. #define OSD_CFG "osdmenu-"
  88. #if defined( WIN32 ) || defined( UNDER_CE )
  89. #define OSD_DEFAULT_CFG "osdmenu/default.cfg"
  90. #else
  91. #define OSD_DEFAULT_CFG "share/osdmenu/default.cfg"
  92. #endif
  93. #define OSD_UPDATE_MIN     0
  94. #define OSD_UPDATE_DEFAULT 300
  95. #define OSD_UPDATE_MAX     1000
  96. vlc_module_begin ()
  97.     set_capability( "sub filter", 100 )
  98.     set_description( N_("On Screen Display menu") )
  99.     set_shortname( N_("OSD menu") )
  100.     add_shortcut( "osdmenu" )
  101.     set_category( CAT_VIDEO )
  102.     set_subcategory( SUBCAT_VIDEO_SUBPIC )
  103.     set_callbacks( CreateFilter, DestroyFilter )
  104.     add_integer( OSD_CFG "x", -1, NULL, POSX_TEXT, POSX_LONGTEXT, false )
  105.     add_integer( OSD_CFG "y", -1, NULL, POSY_TEXT, POSY_LONGTEXT, false )
  106.     add_integer( OSD_CFG "position", 8, NULL, POS_TEXT, POS_LONGTEXT,
  107.                  false )
  108.         change_integer_list( pi_pos_values, ppsz_pos_descriptions, NULL )
  109.     add_string( OSD_CFG "file", OSD_DEFAULT_CFG, NULL, OSD_FILE_TEXT,
  110.         OSD_FILE_LONGTEXT, false )
  111.     add_string( OSD_CFG "file-path", NULL, NULL, OSD_PATH_TEXT,
  112.         OSD_PATH_LONGTEXT, false )
  113.     add_integer( OSD_CFG "timeout", 15, NULL, TIMEOUT_TEXT,
  114.         TIMEOUT_LONGTEXT, false )
  115.     add_integer_with_range( OSD_CFG "update", OSD_UPDATE_DEFAULT,
  116.         OSD_UPDATE_MIN, OSD_UPDATE_MAX, NULL, OSD_UPDATE_TEXT,
  117.         OSD_UPDATE_LONGTEXT, true )
  118.     add_integer_with_range( OSD_CFG "alpha", 255, 0, 255, NULL,
  119.         OSD_ALPHA_TEXT, OSD_ALPHA_LONGTEXT, true )
  120. vlc_module_end ()
  121. /*****************************************************************************
  122.  * Sub filter code
  123.  *****************************************************************************/
  124. /*****************************************************************************
  125.  * Local prototypes
  126.  *****************************************************************************/
  127. struct filter_sys_t
  128. {
  129.     int          i_position;    /* relative positioning of SPU images */
  130.     int          i_x;           /* absolute positioning of SPU images */
  131.     int          i_y;           /* absolute positioning of SPU images */
  132.     mtime_t      i_last_date;   /* last mdate SPU object has been sent to SPU subsytem */
  133.     mtime_t      i_timeout;     /* duration SPU object is valid on the video output in seconds */
  134.     bool   b_absolute;    /* do we use absolute positioning or relative? */
  135.     bool   b_update;      /* Update OSD Menu by sending SPU objects */
  136.     bool   b_visible;     /* OSD Menu is visible */
  137.     mtime_t      i_update;      /* Update the OSD menu every n ms */
  138.     mtime_t      i_end_date;    /* End data of display OSD menu */
  139.     int          i_alpha;       /* alpha transparency value */
  140.     char        *psz_file;      /* OSD Menu configuration file */
  141.     char        *psz_path;      /* Path to OSD Menu pictures */
  142.     osd_menu_t  *p_menu;        /* pointer to OSD Menu object */
  143.     /* menu interaction */
  144.     vout_thread_t *p_vout;
  145.     bool  b_clicked;
  146.     uint32_t    i_mouse_x;
  147.     uint32_t    i_mouse_y;
  148. };
  149. /*****************************************************************************
  150.  * CreateFilter: Create the filter and open the definition file
  151.  *****************************************************************************/
  152. static int CreateFilter ( vlc_object_t *p_this )
  153. {
  154.     filter_t *p_filter = (filter_t *)p_this;
  155.     filter_sys_t *p_sys = NULL;
  156.     p_filter->p_sys = p_sys = (filter_sys_t *) malloc( sizeof(filter_sys_t) );
  157.     if( !p_filter->p_sys )
  158.         return VLC_ENOMEM;
  159.     memset( p_sys, 0, sizeof(filter_sys_t) );
  160.     /* Populating struct */
  161.     p_sys->psz_path = var_CreateGetString( p_this, OSD_CFG "file-path" );
  162.     p_sys->psz_file = var_CreateGetString( p_this, OSD_CFG "file" );
  163.     if( (p_sys->psz_file == NULL) ||
  164.         (*p_sys->psz_file == '') )
  165.     {
  166.         msg_Err( p_filter, "unable to get filename" );
  167.         goto error;
  168.     }
  169.     p_sys->i_x = var_CreateGetIntegerCommand( p_this, OSD_CFG "x" );
  170.     p_sys->i_y = var_CreateGetIntegerCommand( p_this, OSD_CFG "y" );
  171.     p_sys->i_position = var_CreateGetIntegerCommand( p_this, OSD_CFG "position" );
  172.     p_sys->i_alpha = var_CreateGetIntegerCommand( p_this, OSD_CFG "alpha" );
  173.     /* in micro seconds - divide by 2 to match user expectations */
  174.     p_sys->i_timeout = var_CreateGetIntegerCommand( p_this, OSD_CFG "timeout" );
  175.     p_sys->i_timeout = (mtime_t)(p_sys->i_timeout * 1000000) >> 2;
  176.     p_sys->i_update  = var_CreateGetIntegerCommand( p_this, OSD_CFG "update" );
  177.     p_sys->i_update = (mtime_t)(p_sys->i_update * 1000); /* in micro seconds */
  178.     var_AddCallback( p_filter, OSD_CFG "position", OSDMenuCallback, p_sys );
  179.     var_AddCallback( p_filter, OSD_CFG "timeout", OSDMenuCallback, p_sys );
  180.     var_AddCallback( p_filter, OSD_CFG "update", OSDMenuCallback, p_sys );
  181.     var_AddCallback( p_filter, OSD_CFG "alpha", OSDMenuCallback, p_sys );
  182.     /* Load the osd menu subsystem */
  183.     p_sys->p_menu = osd_MenuCreate( p_this, p_sys->psz_file );
  184.     if( p_sys->p_menu == NULL )
  185.         goto error;
  186.     /* FIXME: this plugin is not at all thread-safe w.r.t. callbacks */
  187.     p_sys->p_menu->i_position = p_sys->i_position;
  188.     /* Check if menu position was overridden */
  189.     p_sys->b_absolute = true;
  190.     if( (p_sys->i_x < 0) || (p_sys->i_y < 0) )
  191.     {
  192.         p_sys->b_absolute = false;
  193.         p_sys->p_menu->i_x = 0;
  194.         p_sys->p_menu->i_y = 0;
  195.     }
  196.     else
  197.     {
  198.         p_sys->p_menu->i_x = p_sys->i_x;
  199.         p_sys->p_menu->i_y = p_sys->i_y;
  200.     }
  201.     /* Set up p_filter */
  202.     p_sys->i_last_date = mdate();
  203.     /* Keep track of OSD Events */
  204.     p_sys->b_update  = false;
  205.     p_sys->b_visible = false;
  206.     p_sys->b_clicked = false;
  207.     /* Listen to osd menu core updates/visible settings. */
  208.     var_AddCallback( p_sys->p_menu, "osd-menu-update",
  209.                      OSDMenuUpdateEvent, p_filter );
  210.     var_AddCallback( p_sys->p_menu, "osd-menu-visible",
  211.                      OSDMenuVisibleEvent, p_filter );
  212.     /* Attach subpicture filter callback */
  213.     p_filter->pf_sub_filter = Filter;
  214.     p_sys->p_vout = vlc_object_find( p_this, VLC_OBJECT_VOUT, FIND_ANYWHERE );
  215.     if( p_sys->p_vout )
  216.     {
  217.         var_AddCallback( p_sys->p_vout, "mouse-x",
  218.                         MouseEvent, p_sys );
  219.         var_AddCallback( p_sys->p_vout, "mouse-y",
  220.                         MouseEvent, p_sys );
  221.         var_AddCallback( p_sys->p_vout, "mouse-clicked",
  222.                         MouseEvent, p_sys );
  223.     }
  224.     es_format_Init( &p_filter->fmt_out, SPU_ES, VLC_FOURCC( 's','p','u',' ' ) );
  225.     p_filter->fmt_out.i_priority = 0;
  226.     return VLC_SUCCESS;
  227. error:
  228.     msg_Err( p_filter, "osdmenu filter discarded" );
  229.     free( p_sys->psz_path );
  230.     free( p_sys->psz_file );
  231.     free( p_sys );
  232.     return VLC_EGENERIC;
  233. }
  234. /*****************************************************************************
  235.  * DestroyFilter: Make a clean exit of this plugin
  236.  *****************************************************************************/
  237. static void DestroyFilter( vlc_object_t *p_this )
  238. {
  239.     filter_t     *p_filter = (filter_t*)p_this;
  240.     filter_sys_t *p_sys = p_filter->p_sys;
  241.     var_DelCallback( p_filter, OSD_CFG "position", OSDMenuCallback, p_sys );
  242.     var_DelCallback( p_filter, OSD_CFG "timeout", OSDMenuCallback, p_sys );
  243.     var_DelCallback( p_filter, OSD_CFG "update", OSDMenuCallback, p_sys );
  244.     var_DelCallback( p_filter, OSD_CFG "alpha", OSDMenuCallback, p_sys );
  245.     if( p_sys ) /* FIXME: <-- WTF??? what about the 4 ones above? */
  246.     {
  247.         var_DelCallback( p_sys->p_menu, "osd-menu-update",
  248.                          OSDMenuUpdateEvent, p_filter );
  249.         var_DelCallback( p_sys->p_menu, "osd-menu-visible",
  250.                          OSDMenuVisibleEvent, p_filter );
  251.     }
  252.     if( p_sys && p_sys->p_vout )
  253.     {
  254.         var_DelCallback( p_sys->p_vout, "mouse-x",
  255.                         MouseEvent, p_sys );
  256.         var_DelCallback( p_sys->p_vout, "mouse-y",
  257.                         MouseEvent, p_sys );
  258.         var_DelCallback( p_sys->p_vout, "mouse-clicked",
  259.                         MouseEvent, p_sys );
  260.         vlc_object_release( p_sys->p_vout );
  261.         p_sys->p_vout = NULL;
  262.     }
  263.     var_Destroy( p_this, OSD_CFG "file-path" );
  264.     var_Destroy( p_this, OSD_CFG "file" );
  265.     var_Destroy( p_this, OSD_CFG "x" );
  266.     var_Destroy( p_this, OSD_CFG "y" );
  267.     var_Destroy( p_this, OSD_CFG "position" );
  268.     var_Destroy( p_this, OSD_CFG "timeout" );
  269.     var_Destroy( p_this, OSD_CFG "update" );
  270.     var_Destroy( p_this, OSD_CFG "alpha" );
  271.     if( p_sys )
  272.     {
  273.         osd_MenuDelete( p_filter, p_sys->p_menu );
  274.         free( p_sys->psz_path );
  275.         free( p_sys->psz_file );
  276.         free( p_sys );
  277.     }
  278. }
  279. /*****************************************************************************
  280.  * OSDMenuEvent: callback for OSD Menu events
  281.  *****************************************************************************/
  282. static int OSDMenuVisibleEvent( vlc_object_t *p_this, char const *psz_var,
  283.                     vlc_value_t oldval, vlc_value_t newval, void *p_data )
  284. {
  285.     VLC_UNUSED(p_this); VLC_UNUSED(psz_var); VLC_UNUSED(oldval);
  286.     VLC_UNUSED(newval);
  287.     filter_t *p_filter = (filter_t *) p_data;
  288.     p_filter->p_sys->b_visible = true;
  289.     p_filter->p_sys->b_update = true;
  290.     return VLC_SUCCESS;
  291. }
  292. static int OSDMenuUpdateEvent( vlc_object_t *p_this, char const *psz_var,
  293.                     vlc_value_t oldval, vlc_value_t newval, void *p_data )
  294. {
  295.     VLC_UNUSED(p_this); VLC_UNUSED(psz_var); VLC_UNUSED(oldval);
  296.     VLC_UNUSED(newval);
  297.     filter_t *p_filter = (filter_t *) p_data;
  298.     filter_sys_t *p_sys = p_filter->p_sys;
  299.     p_sys->b_update = p_sys->b_visible ? true : false;
  300.     p_sys->i_end_date = (mtime_t) 0;
  301.     return VLC_SUCCESS;
  302. }
  303. #if 0
  304. /*****************************************************************************
  305.  * create_text_region : compose a text region SPU
  306.  *****************************************************************************/
  307. static subpicture_region_t *create_text_region( filter_t *p_filter, subpicture_t *p_spu,
  308.     int i_width, int i_height, const char *psz_text )
  309. {
  310.     subpicture_region_t *p_region;
  311.     video_format_t       fmt;
  312.     /* Create new SPU region */
  313.     memset( &fmt, 0, sizeof(video_format_t) );
  314.     fmt.i_chroma = VLC_FOURCC( 'T','E','X','T' );
  315.     fmt.i_aspect = VOUT_ASPECT_FACTOR;
  316.     fmt.i_sar_num = fmt.i_sar_den = 1;
  317.     fmt.i_width = fmt.i_visible_width = i_width;
  318.     fmt.i_height = fmt.i_visible_height = i_height;
  319.     fmt.i_x_offset = fmt.i_y_offset = 0;
  320.     p_region = subpicture_region_New( &fmt );
  321.     if( !p_region )
  322.     {
  323.         msg_Err( p_filter, "cannot allocate another SPU region" );
  324.         return NULL;
  325.     }
  326.     p_region->psz_text = strdup( psz_text );
  327.     p_region->i_x = 0;
  328.     p_region->i_y = 40;
  329. #if 0
  330.     msg_Dbg( p_filter, "SPU text region position (%d,%d) (%d,%d) [%s]",
  331.         p_region->i_x, p_region->i_y,
  332.         p_region->fmt.i_width, p_region->fmt.i_height, p_region->psz_text );
  333. #endif
  334.     return p_region;
  335. }
  336. #endif
  337. /*****************************************************************************
  338.  * create_picture_region : compose a picture region SPU
  339.  *****************************************************************************/
  340. static subpicture_region_t *create_picture_region( filter_t *p_filter, subpicture_t *p_spu,
  341.     int i_width, int i_height, picture_t *p_pic )
  342. {
  343.     subpicture_region_t *p_region = NULL;
  344.     video_format_t       fmt;
  345.     video_palette_t      palette;
  346.     if( !p_spu ) return NULL;
  347.     /* Create new SPU region */
  348.     memset( &fmt, 0, sizeof(video_format_t) );
  349.     fmt.i_chroma = (p_pic == NULL) ? VLC_FOURCC('Y','U','V','P') : VLC_FOURCC('Y','U','V','A');
  350.     fmt.i_aspect = VOUT_ASPECT_FACTOR;
  351.     fmt.i_sar_num = fmt.i_sar_den = 1;
  352.     fmt.i_width = fmt.i_visible_width = i_width;
  353.     fmt.i_height = fmt.i_visible_height = i_height;
  354.     fmt.i_x_offset = fmt.i_y_offset = 0;
  355.     if( fmt.i_chroma == VLC_FOURCC('Y','U','V','P') )
  356.     {
  357.         fmt.p_palette = &palette;
  358.         fmt.p_palette->i_entries = 0;
  359.         fmt.i_visible_width = 0;
  360.         fmt.i_visible_height = 0;
  361.     }
  362.     p_region = subpicture_region_New( &fmt );
  363.     if( !p_region )
  364.     {
  365.         msg_Err( p_filter, "cannot allocate SPU region" );
  366.         p_filter->pf_sub_buffer_del( p_filter, p_spu );
  367.         return NULL;
  368.     }
  369.     /* FIXME the copy is probably not needed anymore */
  370.     if( p_pic )
  371.         picture_Copy( p_region->p_picture, p_pic );
  372.     p_region->i_x = 0;
  373.     p_region->i_y = 0;
  374.     p_region->i_align = p_filter->p_sys->i_position;
  375.     p_region->i_alpha = p_filter->p_sys->i_alpha;
  376. #if 0
  377.     msg_Dbg( p_filter, "SPU picture region position (%d,%d) (%d,%d) [%p]",
  378.         p_region->i_x, p_region->i_y,
  379.         p_region->fmt.i_width, p_region->fmt.i_height, p_pic );
  380. #endif
  381.     return p_region;
  382. }
  383. /****************************************************************************
  384.  * Filter: the whole thing
  385.  ****************************************************************************
  386.  * This function outputs subpictures at regular time intervals.
  387.  ****************************************************************************/
  388. static subpicture_t *Filter( filter_t *p_filter, mtime_t i_date )
  389. {
  390.     filter_sys_t *p_sys = p_filter->p_sys;
  391.     subpicture_t *p_spu = NULL;
  392.     subpicture_region_t *p_region = NULL;
  393.     int i_x, i_y;
  394.     if( !p_sys->b_update || (p_sys->i_update <= 0) )
  395.             return NULL;
  396.     /* Am I too early?
  397.     */
  398.     if( ( ( p_sys->i_last_date + p_sys->i_update ) > i_date ) &&
  399.         ( p_sys->i_end_date > 0 ) )
  400.         return NULL; /* we are too early, so wait */
  401.     /* Allocate the subpicture internal data. */
  402.     p_spu = filter_NewSubpicture( p_filter );
  403.     if( !p_spu )
  404.         return NULL;
  405.     p_spu->b_ephemer = true;
  406.     p_spu->b_fade = true;
  407.     if( p_filter->p_sys->p_menu->i_style == OSD_MENU_STYLE_CONCAT )
  408.         p_spu->b_absolute = true;
  409.     else
  410.         p_spu->b_absolute = p_sys->b_absolute;
  411.     /* Determine the duration of the subpicture */
  412.     if( p_sys->i_end_date > 0 )
  413.     {
  414.         /* Display the subpicture again. */
  415.         p_spu->i_stop = p_sys->i_end_date - i_date;
  416.         if( ( i_date + p_sys->i_update ) >= p_sys->i_end_date )
  417.             p_sys->b_update = false;
  418.     }
  419.     else
  420.     {
  421.         /* There is a new OSD picture to display */
  422.         p_spu->i_stop = i_date + p_sys->i_timeout;
  423.         p_sys->i_end_date = p_spu->i_stop;
  424.     }
  425.     p_sys->i_last_date = i_date;
  426.     p_spu->i_start = p_sys->i_last_date = i_date;
  427.     /* Send an empty subpicture to clear the display
  428.      * when OSD menu should be hidden and menu picture is not allocated.
  429.      */
  430.     if( !p_filter->p_sys->p_menu->p_state->p_pic ||
  431.         ( p_filter->p_sys->b_visible == false ) )
  432.     {
  433.         /* Create new spu regions and allocate an empty picture in it. */
  434.         p_region = create_picture_region( p_filter, p_spu,
  435.             p_filter->p_sys->p_menu->p_state->i_width,
  436.             p_filter->p_sys->p_menu->p_state->i_height,
  437.             NULL );
  438.         /* proper positioning of OSD menu image */
  439.         p_region->i_x = p_filter->p_sys->p_menu->p_state->i_x;
  440.         p_region->i_y = p_filter->p_sys->p_menu->p_state->i_y;
  441.         /* FIXME is it needed ?
  442.         p_region->i_align = p_sys->i_position;
  443.         */
  444.         p_spu->p_region = p_region;
  445.         p_spu->i_alpha = 0xFF; /* Picture is completely non transparent. */
  446.         return p_spu;
  447.     }
  448.     if( p_sys->p_vout && p_sys->b_clicked )
  449.     {
  450.         p_sys->b_clicked = false;
  451.         osd_MenuActivate( p_filter );
  452.     }
  453.     /* Create new spu regions
  454.     */
  455.     p_region = create_picture_region( p_filter, p_spu,
  456.         p_filter->p_sys->p_menu->p_state->i_width,
  457.         p_filter->p_sys->p_menu->p_state->i_height,
  458.         p_filter->p_sys->p_menu->p_state->p_pic );
  459.     if( !p_region )
  460.     {
  461.         p_filter->pf_sub_buffer_del( p_filter, p_spu );
  462.         return NULL;
  463.     }
  464.     p_spu->i_alpha = p_filter->p_sys->i_alpha;
  465.     /* proper positioning of OSD menu image */
  466.     if( p_filter->p_sys->p_menu->i_style == OSD_MENU_STYLE_CONCAT )
  467.     {
  468.         i_x = p_filter->p_sys->p_menu->p_button->i_x;
  469.         i_y = p_filter->p_sys->p_menu->p_button->i_y;
  470.     }
  471.     else
  472.     {
  473.         i_x = p_filter->p_sys->p_menu->p_state->i_x;
  474.         i_y = p_filter->p_sys->p_menu->p_state->i_y;
  475.     }
  476.     p_region->i_x = i_x;
  477.     p_region->i_y = i_y;
  478.     if( p_filter->p_sys->p_menu->i_style == OSD_MENU_STYLE_CONCAT )
  479.     {
  480.         subpicture_region_t *p_region_list = NULL;
  481.         subpicture_region_t *p_region_tail = NULL;
  482.         osd_menu_t *p_osd = p_filter->p_sys->p_menu;
  483.         osd_button_t *p_button = p_osd->p_button;
  484.         /* Construct the entire OSD from individual images */
  485.         while( p_button != NULL )
  486.         {
  487.             osd_button_t *p_tmp = NULL;
  488.             subpicture_region_t *p_new = NULL;
  489.             p_new = create_picture_region( p_filter, p_spu,
  490.                     p_button->p_current_state->p_pic->p[Y_PLANE].i_visible_pitch,
  491.                     p_button->p_current_state->p_pic->p[Y_PLANE].i_visible_lines,
  492.                     p_button->p_current_state->p_pic );
  493.             if( !p_new )
  494.             {
  495.                 /* Cleanup when bailing out */
  496.                 subpicture_region_ChainDelete( p_region_list );
  497.                 subpicture_region_Delete( p_region );
  498.                 p_filter->pf_sub_buffer_del( p_filter, p_spu );
  499.                 return NULL;
  500.             }
  501.             if( !p_region_list )
  502.             {
  503.                 p_region_list = p_new;
  504.                 p_region_tail = p_new;
  505.             }
  506.             else
  507.             {
  508.                 p_new->i_x = i_x+p_region_tail->fmt.i_visible_width;
  509.                 p_new->i_y = i_y+p_button->i_y;
  510.                 p_region_tail->p_next = p_new;
  511.                 p_region_tail = p_new;
  512.             }
  513.             p_tmp = p_button->p_next;
  514.             p_button = p_tmp;
  515.         };
  516.         p_region->p_next = p_region_list;
  517.     }
  518. #if 0
  519.     p_region->p_next = create_text_region( p_filter, p_spu,
  520.         p_filter->p_sys->p_menu->p_state->i_width, p_filter->p_sys->p_menu->p_state->i_height,
  521.         p_filter->p_sys->p_menu->p_state->p_visible->psz_action );
  522. #endif
  523.     p_spu->p_region = p_region;
  524.     return p_spu;
  525. }
  526. static int OSDMenuCallback( vlc_object_t *p_this, char const *psz_var,
  527.                             vlc_value_t oldval, vlc_value_t newval,
  528.                             void *p_data )
  529. {
  530.     VLC_UNUSED(p_this); VLC_UNUSED(oldval);
  531.     filter_sys_t *p_sys = (filter_sys_t *) p_data;
  532.     if( !p_sys )
  533.         return VLC_SUCCESS;
  534.     if( !strncmp( psz_var, OSD_CFG"position", 16) )
  535.     {
  536. #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
  537.         unsigned int i;
  538.         for( i=0; i < ARRAY_SIZE(pi_pos_values); i++ )
  539.         {
  540.             if( newval.i_int == pi_pos_values[i] )
  541.             {
  542.                 p_sys->i_position = newval.i_int % 11;
  543.                 break;
  544.             }
  545.         }
  546. #undef ARRAY_SIZE
  547.     }
  548.     else if( !strncmp( psz_var, OSD_CFG"x", 9) ||
  549.              !strncmp( psz_var, OSD_CFG"y", 9))
  550.     {
  551.         p_sys->b_absolute = true;
  552.         if( (p_sys->i_x < 0) || (p_sys->i_y < 0) )
  553.         {
  554.             p_sys->b_absolute = false;
  555.             p_sys->p_menu->i_x = 0;
  556.             p_sys->p_menu->i_y = 0;
  557.         }
  558.         else if( (p_sys->i_x >= 0) || (p_sys->i_y >= 0) )
  559.         {
  560.             p_sys->p_menu->i_x = p_sys->i_x;
  561.             p_sys->p_menu->i_y = p_sys->i_y;
  562.         }
  563.     }
  564.     else if( !strncmp( psz_var, OSD_CFG"update", 14) )
  565.         p_sys->i_update =  (mtime_t)(newval.i_int * 1000);
  566.     else if( !strncmp( psz_var, OSD_CFG"timeout", 15) )
  567.         p_sys->i_update = newval.i_int % 1000;
  568.     else if( !strncmp( psz_var, OSD_CFG"alpha", 13) )
  569.         p_sys->i_alpha = newval.i_int % 256;
  570.     p_sys->b_update = p_sys->b_visible ? true : false;
  571.     return VLC_SUCCESS;
  572. }
  573. /*****************************************************************************
  574.  * MouseEvent: callback for mouse events
  575.  *****************************************************************************/
  576. static int MouseEvent( vlc_object_t *p_this, char const *psz_var,
  577.                        vlc_value_t oldval, vlc_value_t newval, void *p_data )
  578. {
  579.     VLC_UNUSED(oldval); VLC_UNUSED(newval);
  580.     filter_sys_t *p_sys = (filter_sys_t *)p_data;
  581.     vout_thread_t *p_vout = (vout_thread_t*)p_sys->p_vout;
  582.     int i_x, i_y;
  583.     int i_v;
  584. #define MOUSE_DOWN    1
  585. #define MOUSE_CLICKED 2
  586. #define MOUSE_MOVE_X  4
  587. #define MOUSE_MOVE_Y  8
  588. #define MOUSE_MOVE    12
  589.     uint8_t mouse= 0;
  590.     int v_h = p_vout->output.i_height;
  591.     int v_w = p_vout->output.i_width;
  592.     if( psz_var[6] == 'x' ) mouse |= MOUSE_MOVE_X;
  593.     if( psz_var[6] == 'y' ) mouse |= MOUSE_MOVE_Y;
  594.     if( psz_var[6] == 'c' ) mouse |= MOUSE_CLICKED;
  595.     i_v = var_GetInteger( p_sys->p_vout, "mouse-button-down" );
  596.     if( i_v & 0x1 ) mouse |= MOUSE_DOWN;
  597.     i_y = var_GetInteger( p_sys->p_vout, "mouse-y" );
  598.     i_x = var_GetInteger( p_sys->p_vout, "mouse-x" );
  599.     if( i_y < 0 || i_x < 0 || i_y >= v_h || i_x >= v_w )
  600.         return VLC_SUCCESS;
  601.     if( mouse & MOUSE_CLICKED )
  602.     {
  603.         int i_scale_width, i_scale_height;
  604.         osd_button_t *p_button = NULL;
  605.         i_scale_width = p_vout->fmt_out.i_visible_width * 1000 /
  606.             p_vout->fmt_in.i_visible_width;
  607.         i_scale_height = p_vout->fmt_out.i_visible_height * 1000 /
  608.             p_vout->fmt_in.i_visible_height;
  609.         p_button = osd_ButtonFind( p_this, i_x, i_y, v_h, v_w,
  610.                                    i_scale_width, i_scale_height );
  611.         if( p_button )
  612.         {
  613.             osd_ButtonSelect( p_this, p_button );
  614.             p_sys->b_update = p_sys->b_visible ? true : false;
  615.             p_sys->b_clicked = true;
  616.             msg_Dbg( p_this, "mouse clicked %s (%d,%d)", p_button->psz_name, i_x, i_y );
  617.         }
  618.     }
  619.     return VLC_SUCCESS;
  620. }