include/vlc_messages.h \
include/vlc_meta.h \
include/vlc_objects.h \
+ include/vlc_osd.h \
include/vlc_playlist.h \
include/vlc_spu.h \
include/vlc_stream.h \
src/stream_output/announce.c \
src/stream_output/sap.c \
src/stream_output/acl.c \
+ src/osd/osd.c \
+ src/osd/osd_widgets.c \
+ src/osd/osd_parser.c \
src/misc/charset.c \
src/misc/httpd.c \
src/misc/tls.c \
cp $$i $(top_builddir)/vlc-${VERSION}/skins/ || true ; \
done
+ mkdir -p "$(srcdir)/vlc-${VERSION}/osdmenu"
+ mkdir -p "$(srcdir)/vlc-${VERSION}/osdmenu/dvd"
+ mkdir -p "$(srcdir)/vlc-${VERSION}/osdmenu/dvd/selected"
+ mkdir -p "$(srcdir)/vlc-${VERSION}/osdmenu/dvd/unselect"
+ mkdir -p "$(srcdir)/vlc-${VERSION}/osdmenu/dvd/selection"
+ mkdir -p "$(srcdir)/vlc-${VERSION}/osdmenu/dvd/volume"
+ for i in $(srcdir)/share/osdmenu/*.*; do \
+ cp $$i $(srcdir)/vlc-${VERSION}/osdmenu/ || true ; \
+ unix2dos $(srcdir)/vlc-${VERSION}/osdmenu/`basename $$i` ; \
+ done
+ for i in $(srcdir)/share/osdmenu/dvd/*.*; do \
+ cp $$i $(srcdir)/vlc-${VERSION}/osdmenu/dvd || true ; \
+ done
+ for i in $(srcdir)/share/osdmenu/dvd/unselect/*.*; do \
+ cp $$i $(srcdir)/vlc-${VERSION}/osdmenu/dvd/unselect || true ; \
+ done
+ for i in $(srcdir)/share/osdmenu/dvd/selected/*.*; do \
+ cp $$i $(srcdir)/vlc-${VERSION}/osdmenu/dvd/selected/ || true ; \
+ done
+ for i in $(srcdir)/share/osdmenu/dvd/selection/*.*; do \
+ cp $$i $(srcdir)/vlc-${VERSION}/osdmenu/dvd/selection/ || true ; \
+ done
+ for i in $(srcdir)/share/osdmenu/dvd/volume/*.*; do \
+ cp $$i $(srcdir)/vlc-${VERSION}/osdmenu/dvd/volume/ || true ; \
+ done
+
+ mkdir -p "$(srcdir)/vlc-${VERSION}/osdmenu/default"
+ mkdir -p "$(srcdir)/vlc-${VERSION}/osdmenu/default/selected"
+ mkdir -p "$(srcdir)/vlc-${VERSION}/osdmenu/default/selection"
+ mkdir -p "$(srcdir)/vlc-${VERSION}/osdmenu/default/volume"
+ for i in $(srcdir)/share/osdmenu/default/*.*; do \
+ cp $$i $(srcdir)/vlc-${VERSION}/osdmenu/default || true ; \
+ done
+ for i in $(srcdir)/share/osdmenu/default/selected/*.*; do \
+ cp $$i $(srcdir)/vlc-${VERSION}/osdmenu/default/selected/ || true ; \
+ done
+ for i in $(srcdir)/share/osdmenu/default/selection/*.*; do \
+ cp $$i $(srcdir)/vlc-${VERSION}/osdmenu/default/selection/ || true ; \
+ done
+ for i in $(srcdir)/share/osdmenu/default/volume/*.*; do \
+ cp $$i $(srcdir)/vlc-${VERSION}/osdmenu/default/volume/ || true ; \
+ done
+
mkdir -p "$(top_builddir)/vlc-${VERSION}/http/admin"
mkdir -p "$(top_builddir)/vlc-${VERSION}/http/vlm"
cp $(srcdir)/share/http/*.html $(top_builddir)/vlc-${VERSION}/http/ ;
AC_CHECK_LIB(png, png_set_rows, [
VLC_ADD_LDFLAGS([png],[-lpng -lz])
VLC_ADD_PLUGINS([png])
+ VLC_ADD_PLUGINS([osdmenu])
AC_DEFINE(HAVE_LIBPNG, [], [Define if you have the PNG library: libpng])],
[],[-lz])
LDFLAGS="${LDFLAGS_save}"
/*****************************************************************************
* stream_output.h : stream output module
*****************************************************************************
- * Copyright (C) 2002 the VideoLAN team
+ * Copyright (C) 2002-2005 the VideoLAN team
* $Id$
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
* Laurent Aimar <fenrir@via.ecp.fr>
* Eric Petit <titer@videolan.org>
+ * Jean-Paul Saman <jpsaman #_at_# m2x.nl>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
sout_cfg_t *p_cfg;
char *psz_next;
+ /* Subpicture unit */
+ spu_t *p_spu;
+
/* add, remove a stream */
sout_stream_id_t *(*pf_add)( sout_stream_t *, es_format_t * );
int (*pf_del)( sout_stream_t *, sout_stream_id_t * );
typedef struct opengl_t opengl_t;
typedef struct opengl_sys_t opengl_sys_t;
+/* osdmenu */
+typedef struct osd_menu_t osd_menu_t;
+typedef struct osd_state_t osd_state_t;
+typedef struct osd_event_t osd_event_t;
+typedef struct osd_button_t osd_button_t;
+typedef struct osd_menu_state_t osd_menu_state_t;
+
/* VLM */
typedef struct vlm_t vlm_t;
typedef struct vlm_message_t vlm_message_t;
#define VLC_OBJECT_TLS (-25)
#define VLC_OBJECT_SD (-26)
#define VLC_OBJECT_XML (-27)
+#define VLC_OBJECT_OSDMENU (-28)
#define VLC_OBJECT_GENERIC (-666)
--- /dev/null
+/*****************************************************************************\r
+ * osd.h - OSD menu definitions and function prototypes\r
+ *****************************************************************************\r
+ * Copyright (C) 2004-2005 M2X\r
+ * $Id: osd.h 9451 2004-12-01 01:07:08Z jpsaman $\r
+ *\r
+ * Authors: Jean-Paul Saman <jpsaman #_at_# m2x dot nl>\r
+ *\r
+ * This program is free software; you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation; either version 2 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with this program; if not, write to the Free Software\r
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.\r
+ *****************************************************************************/\r
+\r
+/**\r
+ * \file\r
+ * The OSD menu core creates the OSD menu structure in memory. It parses a \r
+ * configuration file that defines all elements that are part of the menu. The \r
+ * core also handles all actions and menu structure updates on behalf of video \r
+ * subpicture filters.\r
+ *\r
+ * The file modules/video_filters/osdmenu.c implements a subpicture filter that\r
+ * specifies the final information on positioning of the current state image. \r
+ * A subpicture filter is called each time a video picture has to be rendered, it\r
+ * also gives a start and end date to the subpicture. The subpicture can be streamed\r
+ * if used inside a transcoding command. For example:\r
+ *\r
+ * vlc dvdsimple:///dev/dvd --extraintf rc\r
+ * --sout='#transcode{osdenc=dvbsub,osdcoded=YUVP,sfilter=osdmenu} \r
+ * --osdmenu-file share/osdmenu/dvd.cfg\r
+ *\r
+ * Each OSD menu element, called "action", defines a hotkey action. Each action \r
+ * can have several states (unselect, select, pressed). Each state has an image \r
+ * that represents the state visually. The commands "menu right", "menu left", \r
+ * "menu up" and "menu down" are used to navigate through the OSD menu structure.\r
+ * The commands "menu on" or "menu show" and "menu off" or "menu hide" respectively\r
+ * show and hide the OSD menu subpictures.\r
+ *\r
+ * There is one special element called "range". A range is an arbritary range\r
+ * of state images that can be browsed using "menu up" and "menu down" commands\r
+ * on the rc interface. \r
+ * \r
+ * The OSD menu configuration file uses a very simple syntax and basic parser. \r
+ * A configuration file has the ".cfg". An example is "share/osdmenu/dvd256.cfg".\r
+ */\r
+ \r
+#ifndef _VLC_OSD_H\r
+#define _VLC_OSD_H 1\r
+\r
+#include "vlc_video.h"\r
+\r
+# ifdef __cplusplus\r
+extern "C" {\r
+# endif\r
+\r
+/**\r
+ * The OSD Menu configuration file format.\r
+ *\r
+ * The configuration file syntax is very basic and so is its parser. See the\r
+ * BNF formal representation below:\r
+ *\r
+ * The keywords FILENAME and PATHNAME represent the filename and pathname specification\r
+ * that is valid for the Operating System VLC is compiled for. \r
+ *\r
+ * The hotkey actions that are supported by VLC are documented in the file src/libvlc. The\r
+ * file include/vlc_keys.h defines some hotkey internals.\r
+ *\r
+ * CONFIG_FILE = FILENAME '.cfg'\r
+ * WS = [ ' ' | '\t' ]+\r
+ * OSDMEN_PATH = PATHNAME\r
+ * DIR = 'dir' WS OSDMENU_PATH '\n'\r
+ * STATE = [ 'unselect' | 'select' | 'pressed' ]\r
+ * HOTKEY_ACTION = 'key-' [ 'a' .. 'z', 'A' .. 'Z', '-' ]+\r
+ * \r
+ * ACTION_TYPE = 'type' 'volume' '\n'\r
+ * ACTION_BLOCK_START = 'action' WS HOTKEY_ACTION WS '('POS','POS')' '\n'\r
+ * ACTION_BLOCK_END = 'end' '\n'\r
+ * ACTION_STATE = STATE WS FILENAME '\n'\r
+ * ACTION_RANGE_START = 'range' WS HOTKEY_ACTION WS DEFAULT_INDEX '\n'\r
+ * ACTION_RANGE_END = 'end' '\n'\r
+ * ACTION_RANGE_STATE = FILENAME '\n'\r
+ *\r
+ * ACTION_BLOCK_RANGE = ACTION_RANGE_START [WS ACTION_RANGE_STATE]+ WS ACTION_RANGE_END\r
+ * ACTION_BLOCK = ACTION_BLOCK_START [WS ACTION_TYPE*] [ [WS ACTION_STATE]+3 | [WS ACTION_BLOCK_RANGE]+1 ] ACTION_BLOCK_END\r
+ * CONFIG_FILE_CONTENTS = DIR [ACTION_BLOCK]+\r
+ *\r
+ */ \r
+\r
+/**\r
+ * OSD menu button states\r
+ *\r
+ * Every button has three states, either it is unselected, selected or pressed.\r
+ * An OSD menu skin can associate images with each state.\r
+ *\r
+ * OSD_BUTTON_UNSELECT 0\r
+ * OSD_BUTTON_SELECT 1\r
+ * OSD_BUTTON_PRESSED 2\r
+ */\r
+#define OSD_BUTTON_UNSELECT 0\r
+#define OSD_BUTTON_SELECT 1\r
+#define OSD_BUTTON_PRESSED 2\r
+\r
+/**\r
+ * OSD State object\r
+ *\r
+ * The OSD state object holds the state and associated images for a particular state\r
+ * on the screen. The picture is displayed when this state is the active state.\r
+ */\r
+struct osd_state_t\r
+{\r
+ osd_state_t *p_next; /*< pointer to next state */\r
+ osd_state_t *p_prev; /*< pointer to previous state */\r
+ picture_t *p_pic; /*< picture of state */\r
+ \r
+ char *psz_state; /*< state name */\r
+ int i_state; /*< state index */ \r
+};\r
+\r
+/** \r
+ * OSD Button object\r
+ *\r
+ * An OSD Button has different states. Each state has an image for display. \r
+ */\r
+struct osd_button_t\r
+{\r
+ osd_button_t *p_next; /*< pointer to next button */\r
+ osd_button_t *p_prev; /*< pointer to previous button */\r
+ osd_button_t *p_up; /*< pointer to up button */\r
+ osd_button_t *p_down; /*< pointer to down button */\r
+ \r
+ osd_state_t *p_current_state; /*< pointer to current state image */\r
+ osd_state_t *p_states; /*< doubly linked list of states */\r
+ picture_t *p_feedback; /*< feedback picture */\r
+ \r
+ char *psz_name; /*< name of button */\r
+ \r
+ /* These member should probably be a struct hotkey */\r
+ char *psz_action; /*< hotkey action name on button*/\r
+ char *psz_action_down; /*< hotkey action name on range buttons for command "menu down" */\r
+ /* end of hotkey specifics */\r
+ \r
+ int i_x; /*< x-position of button visible state image */\r
+ int i_y; /*< y-position of button visible state image */ \r
+ \r
+ /* range style button */ \r
+ vlc_bool_t b_range; /*< button should be interpreted as range */\r
+ int i_ranges; /*< number of states */\r
+};\r
+\r
+/** \r
+ * OSD Menu State object\r
+ *\r
+ * Represents the current state as displayed. \r
+ */\r
+/* Represent the menu state */\r
+struct osd_menu_state_t\r
+{\r
+ int i_x; /*< x position of spu region */\r
+ int i_y; /*< y position of spu region */\r
+ int i_width; /*< width of spu region */\r
+ int i_height; /*< height of spu region */ \r
+ \r
+ picture_t *p_pic; /*< pointer to picture to display */\r
+ osd_button_t *p_visible; /*< shortcut to visible button */\r
+ \r
+ vlc_bool_t b_menu_visible; /*< menu currently visible? */\r
+ vlc_bool_t b_update; /*< update OSD Menu when VLC_TRUE */\r
+ \r
+ /* quick hack to volume state. */\r
+ osd_button_t *p_volume; /*< pointer to volume range object. */\r
+};\r
+\r
+/**\r
+ * OSD Menu object\r
+ *\r
+ * The main OSD Menu object, which holds a linked list to all buttons\r
+ * and images that defines the menu. The p_state variable represents the\r
+ * current state of the OSD Menu.\r
+ */\r
+struct osd_menu_t\r
+{\r
+ VLC_COMMON_MEMBERS\r
+ \r
+ int i_x; /*< x-position of OSD Menu on the video screen */ \r
+ int i_y; /*< y-position of OSD Menu on the video screen */ \r
+ int i_width; /*< width of OSD Menu on the video screen */ \r
+ int i_height; /*< height of OSD Menu on the video screen */ \r
+ \r
+ char *psz_path; /*< directory where OSD menu images are stored */\r
+ osd_button_t *p_button; /*< doubly linked list of buttons */\r
+ osd_menu_state_t *p_state; /*< current state of OSD menu */\r
+ \r
+ /* quick link in the linked list. */\r
+ osd_button_t *p_last_button; /*< pointer to last button in the list */\r
+};\r
+\r
+/**\r
+ * Initialize an osd_menu_t object\r
+ *\r
+ * This functions has to be called before any call to other osd_menu_t* functions.\r
+ * It creates the osd_menu object and holds a pointer to it during its lifetime.\r
+ */\r
+VLC_EXPORT( osd_menu_t *, __osd_MenuCreate, ( vlc_object_t *, const char * ) );\r
+\r
+/**\r
+ * Delete the osd_menu_t object\r
+ *\r
+ * This functions has to be called to release the associated module and memory\r
+ * for the osdmenu. After return of this function the pointer to osd_menu_t* is invalid.\r
+ */\r
+VLC_EXPORT( void, __osd_MenuDelete, ( vlc_object_t *, osd_menu_t * ) );\r
+\r
+/**\r
+ * Change state on an osd_button_t.\r
+ *\r
+ * This function selects the specified state and returns a pointer to it. The \r
+ * following states are currently supported: \r
+ * \see OSD_BUTTON_UNSELECT\r
+ * \see OSD_BUTTON_SELECT \r
+ * \see OSD_BUTTON_PRESSED \r
+ */\r
+VLC_EXPORT( osd_state_t *, __osd_StateChange, ( osd_state_t *, const int ) );\r
+\r
+#define osd_MenuCreate(object,file) __osd_MenuCreate( VLC_OBJECT(object), file )\r
+#define osd_MenuDelete(object,osd) __osd_MenuDelete( VLC_OBJECT(object), osd )\r
+#define osd_StateChange(object,value) __osd_StateChange( object, value )\r
+\r
+/**\r
+ * Show the OSD menu.\r
+ *\r
+ * Show the OSD menu on the video output or mux it into the stream. \r
+ * Every change to the OSD menu will now be visible in the output. An output \r
+ * can be a video output window or a stream (\see stream output)\r
+ */\r
+VLC_EXPORT( void, __osd_MenuShow, ( vlc_object_t * ) ); \r
+\r
+/**\r
+ * Hide the OSD menu.\r
+ *\r
+ * Stop showing the OSD menu on the video output or mux it into the stream.\r
+ */\r
+VLC_EXPORT( void, __osd_MenuHide, ( vlc_object_t * ) );\r
+\r
+/**\r
+ * Activate the action of this OSD menu item.\r
+ *\r
+ * The rc interface command "menu select" triggers the sending of an hotkey action\r
+ * to the hotkey interface. The hotkey that belongs to the current highlighted \r
+ * OSD menu item will be used.\r
+ */\r
+VLC_EXPORT( void, __osd_MenuActivate, ( vlc_object_t * ) );\r
+\r
+#define osd_MenuShow(object) __osd_MenuShow( VLC_OBJECT(object) )\r
+#define osd_MenuHide(object) __osd_MenuHide( VLC_OBJECT(object) )\r
+#define osd_MenuActivate(object) __osd_MenuActivate( VLC_OBJECT(object) )\r
+\r
+/**\r
+ * Next OSD menu item\r
+ *\r
+ * Select the next OSD menu item to be highlighted.\r
+ * Note: The actual position on screen of the menu item is determined by the the\r
+ * OSD menu configuration file.\r
+ */\r
+VLC_EXPORT( void, __osd_MenuNext, ( vlc_object_t * ) ); \r
+\r
+/**\r
+ * Previous OSD menu item\r
+ *\r
+ * Select the previous OSD menu item to be highlighted.\r
+ * Note: The actual position on screen of the menu item is determined by the the\r
+ * OSD menu configuration file.\r
+ */\r
+VLC_EXPORT( void, __osd_MenuPrev, ( vlc_object_t * ) );\r
+\r
+/**\r
+ * OSD menu item above\r
+ *\r
+ * Select the OSD menu item above the current item to be highlighted. \r
+ * Note: The actual position on screen of the menu item is determined by the the\r
+ * OSD menu configuration file.\r
+ */\r
+VLC_EXPORT( void, __osd_MenuUp, ( vlc_object_t * ) );\r
+\r
+/**\r
+ * OSD menu item below\r
+ *\r
+ * Select the next OSD menu item below the current item to be highlighted.\r
+ * Note: The actual position on screen of the menu item is determined by the the\r
+ * OSD menu configuration file.\r
+ */\r
+VLC_EXPORT( void, __osd_MenuDown, ( vlc_object_t * ) );\r
+\r
+#define osd_MenuNext(object) __osd_MenuNext( VLC_OBJECT(object) )\r
+#define osd_MenuPrev(object) __osd_MenuPrev( VLC_OBJECT(object) )\r
+#define osd_MenuUp(object) __osd_MenuUp( VLC_OBJECT(object) )\r
+#define osd_MenuDown(object) __osd_MenuDown( VLC_OBJECT(object) )\r
+\r
+/**\r
+ * Turn Volume Up\r
+ *\r
+ * Use the OSD menu to turn the audio volume up.\r
+ */\r
+VLC_EXPORT( void, __osd_VolumeUp, ( vlc_object_t * ) );\r
+\r
+/**\r
+ * Turn Volume Down\r
+ *\r
+ * Use the OSD menu to turn the audio volume down.\r
+ */\r
+VLC_EXPORT( void, __osd_VolumeDown, ( vlc_object_t * ) );\r
+\r
+#define osd_VolumeUp(object) __osd_VolumeUp( VLC_OBJECT(object) )\r
+#define osd_VolumeDown(object) __osd_VolumeDown( VLC_OBJECT(object) )\r
+\r
+/**\r
+ * Retrieve a non modifyable pointer to the OSD Menu state\r
+ *\r
+ */\r
+static inline const osd_menu_state_t *osd_GetMenuState( osd_menu_t *p_osd )\r
+{\r
+ return( p_osd->p_state );\r
+}\r
+\r
+/**\r
+ * Get the last key press received by the OSD Menu\r
+ *\r
+ * Returns 0 when no key has been pressed or the value of the key pressed.\r
+ */\r
+static inline vlc_bool_t osd_GetKeyPressed( osd_menu_t *p_osd )\r
+{\r
+ return( p_osd->p_state->b_update );\r
+} \r
+\r
+/**\r
+ * Set the key pressed to a value.\r
+ *\r
+ * Assign a new key value to the last key pressed on the OSD Menu.\r
+ */\r
+static inline void osd_SetKeyPressed( vlc_object_t *p_this, int i_value )\r
+{\r
+ vlc_value_t val;\r
+ \r
+ val.i_int = i_value; \r
+ var_Set( p_this, "key-pressed", val ); \r
+}\r
+\r
+/**\r
+ * Update the OSD Menu visibility flag.\r
+ *\r
+ * VLC_TRUE means OSD Menu should be shown. VLC_FALSE means OSD Menu should not be shown.\r
+ */\r
+static inline void osd_SetMenuVisible( osd_menu_t *p_osd, vlc_bool_t b_value )\r
+{\r
+ vlc_value_t val;\r
+ \r
+ val.b_bool = p_osd->p_state->b_menu_visible = b_value; \r
+ var_Set( p_osd, "osd-menu-visible", val );\r
+}\r
+\r
+/**\r
+ * Update the OSD Menu update flag\r
+ *\r
+ * If the OSD Menu should be updated then set the update flag to VLC_TRUE, else to VLC_FALSE.\r
+ */\r
+static inline void osd_SetMenuUpdate( osd_menu_t *p_osd, vlc_bool_t b_value )\r
+{\r
+ vlc_value_t val;\r
+ \r
+ val.b_bool = p_osd->p_state->b_update = b_value;\r
+ var_Set( p_osd, "osd-menu-update", val );\r
+} \r
+\r
+/**\r
+ * Default feedback images\r
+ *\r
+ * Functions that provide the default OSD feedback images on hotkey commands. These feedback\r
+ * images are also part of the osd_button_t object. The types are declared in the include file\r
+ * include/osd.h\r
+ * @see osd.h \r
+ */\r
+VLC_EXPORT( picture_t *, osd_Slider, ( int i_width, int i_height, int i_position, short i_type ) );\r
+VLC_EXPORT( picture_t *, osd_Icon, ( int i_width, int i_height, short i_type ) );\r
+\r
+/**\r
+ * Loading and parse the OSD Configuration file\r
+ *\r
+ * These functions load/unload the OSD menu configuration file and create/destroy the\r
+ * themable OSD menu structure on the OSD object.\r
+ */\r
+VLC_EXPORT( int, osd_ConfigLoader, ( vlc_object_t *, const char *, osd_menu_t ** ) );\r
+VLC_EXPORT( void, osd_ConfigUnload, ( vlc_object_t *, osd_menu_t ** ) );\r
+\r
+# ifdef __cplusplus\r
+}\r
+# endif\r
+\r
+#endif /* _VLC_OSD_H */\r
char * (*__vlc_fix_readdir_charset_inner) (vlc_object_t *, const char *);
int (*vlc_scandir_inner) (const char *name, struct dirent ***namelist, int (*filter) ( const struct dirent * ), int (*compar) ( const struct dirent **, const struct dirent ** ));
int (*vlc_alphasort_inner) (const struct dirent **a, const struct dirent **b);
+ osd_state_t * (*__osd_StateChange_inner) (osd_state_t *, const int);
+ picture_t * (*osd_Slider_inner) (int i_width, int i_height, int i_position, short i_type);
+ void (*osd_ConfigUnload_inner) (vlc_object_t *, osd_menu_t **);
+ void (*__osd_MenuShow_inner) (vlc_object_t *);
+ picture_t * (*osd_Icon_inner) (int i_width, int i_height, short i_type);
+ void (*__osd_VolumeDown_inner) (vlc_object_t *);
+ void (*__osd_MenuNext_inner) (vlc_object_t *);
+ void (*__osd_MenuDelete_inner) (vlc_object_t *, osd_menu_t *);
+ void (*__osd_MenuHide_inner) (vlc_object_t *);
+ int (*osd_ConfigLoader_inner) (vlc_object_t *, const char *, osd_menu_t **);
+ void (*__osd_MenuUp_inner) (vlc_object_t *);
+ void (*__osd_MenuDown_inner) (vlc_object_t *);
+ osd_menu_t * (*__osd_MenuCreate_inner) (vlc_object_t *, const char *);
+ void (*__osd_MenuPrev_inner) (vlc_object_t *);
+ void (*__osd_VolumeUp_inner) (vlc_object_t *);
+ void (*__osd_MenuActivate_inner) (vlc_object_t *);
};
# if defined (__PLUGIN__)
# define aout_FiltersCreatePipeline (p_symbols)->aout_FiltersCreatePipeline_inner
# define __vlc_fix_readdir_charset (p_symbols)->__vlc_fix_readdir_charset_inner
# define vlc_scandir (p_symbols)->vlc_scandir_inner
# define vlc_alphasort (p_symbols)->vlc_alphasort_inner
+# define __osd_StateChange (p_symbols)->__osd_StateChange_inner
+# define osd_Slider (p_symbols)->osd_Slider_inner
+# define osd_ConfigUnload (p_symbols)->osd_ConfigUnload_inner
+# define __osd_MenuShow (p_symbols)->__osd_MenuShow_inner
+# define osd_Icon (p_symbols)->osd_Icon_inner
+# define __osd_VolumeDown (p_symbols)->__osd_VolumeDown_inner
+# define __osd_MenuNext (p_symbols)->__osd_MenuNext_inner
+# define __osd_MenuDelete (p_symbols)->__osd_MenuDelete_inner
+# define __osd_MenuHide (p_symbols)->__osd_MenuHide_inner
+# define osd_ConfigLoader (p_symbols)->osd_ConfigLoader_inner
+# define __osd_MenuUp (p_symbols)->__osd_MenuUp_inner
+# define __osd_MenuDown (p_symbols)->__osd_MenuDown_inner
+# define __osd_MenuCreate (p_symbols)->__osd_MenuCreate_inner
+# define __osd_MenuPrev (p_symbols)->__osd_MenuPrev_inner
+# define __osd_VolumeUp (p_symbols)->__osd_VolumeUp_inner
+# define __osd_MenuActivate (p_symbols)->__osd_MenuActivate_inner
# elif defined (HAVE_DYNAMIC_PLUGINS) && !defined (__BUILTIN__)
/******************************************************************
* STORE_SYMBOLS: store VLC APIs into p_symbols for plugin access.
((p_symbols)->__vlc_fix_readdir_charset_inner) = __vlc_fix_readdir_charset; \
((p_symbols)->vlc_scandir_inner) = vlc_scandir; \
((p_symbols)->vlc_alphasort_inner) = vlc_alphasort; \
+ ((p_symbols)->__osd_StateChange_inner) = __osd_StateChange; \
+ ((p_symbols)->osd_Slider_inner) = osd_Slider; \
+ ((p_symbols)->osd_ConfigUnload_inner) = osd_ConfigUnload; \
+ ((p_symbols)->__osd_MenuShow_inner) = __osd_MenuShow; \
+ ((p_symbols)->osd_Icon_inner) = osd_Icon; \
+ ((p_symbols)->__osd_VolumeDown_inner) = __osd_VolumeDown; \
+ ((p_symbols)->__osd_MenuNext_inner) = __osd_MenuNext; \
+ ((p_symbols)->__osd_MenuDelete_inner) = __osd_MenuDelete; \
+ ((p_symbols)->__osd_MenuHide_inner) = __osd_MenuHide; \
+ ((p_symbols)->osd_ConfigLoader_inner) = osd_ConfigLoader; \
+ ((p_symbols)->__osd_MenuUp_inner) = __osd_MenuUp; \
+ ((p_symbols)->__osd_MenuDown_inner) = __osd_MenuDown; \
+ ((p_symbols)->__osd_MenuCreate_inner) = __osd_MenuCreate; \
+ ((p_symbols)->__osd_MenuPrev_inner) = __osd_MenuPrev; \
+ ((p_symbols)->__osd_VolumeUp_inner) = __osd_VolumeUp; \
+ ((p_symbols)->__osd_MenuActivate_inner) = __osd_MenuActivate; \
(p_symbols)->net_ConvertIPv4_deprecated = NULL; \
(p_symbols)->vlc_fix_readdir_charset_deprecated = NULL; \
* opie: interface for Opie using QT/Embedded library.
+ * osdmenu: video_filter for displaying and streaming a On Screen Display menu
+
* oss: audio output module using the OSS /dev/dsp interface.
* packetizer_copy: Simple copy packetizer
return VLC_SUCCESS;
}
+/* FIXME: this routine is a hack to convert VLC_FOURCC('Y','U','V','A')
+ * into VLC_FOURCC('Y','U','V','P')
+ */
+static subpicture_t *YuvaYuvp( encoder_t *p_enc, subpicture_t *p_subpic )
+{
+ subpicture_region_t *p_region = NULL;
+
+ for( p_region = p_subpic->p_region; p_region; p_region = p_region->p_next )
+ {
+ video_format_t *p_fmt = &p_region->fmt;
+ int i = 0, j = 0, n = 0, p = 0;
+ int i_max_entries = 256;
+
+#ifdef RANDOM_DITHERING
+ int i_seed = 0xdeadbeef; /* random seed */
+#else
+ int *pi_delta;
+#endif
+ int i_pixels = p_region->picture.p[0].i_visible_lines
+ * p_region->picture.p[0].i_pitch;
+ int i_iterator = p_region->picture.p[0].i_visible_lines * 3 / 4
+ * p_region->picture.p[0].i_pitch
+ + p_region->picture.p[0].i_pitch * 1 / 3;
+ int i_tolerance = 0;
+
+ p_fmt->i_chroma = VLC_FOURCC('Y','U','V','P');
+ p_fmt->p_palette = (video_palette_t *) malloc( sizeof( video_palette_t ) );
+ p_fmt->p_palette->i_entries = 0;
+
+ /* Find best iterator using Euclide’s algorithm */
+ for( ; i_iterator > 1 ; i_iterator-- )
+ {
+ int a = i_pixels;
+ int b = i_iterator;
+ int c;
+
+ while( b )
+ {
+ c = a % b;
+ a = b;
+ b = c;
+ }
+
+ if( a == 1 )
+ {
+ break;
+ }
+ }
+
+ /* Count colors, build best palette */
+ for( i_tolerance = 0; i_tolerance < 128; i_tolerance++ )
+ {
+ vlc_bool_t b_success = VLC_TRUE;
+ p_fmt->p_palette->i_entries = 0;
+
+ for( i = 0; i < i_pixels ; )
+ {
+ uint8_t y, u, v, a;
+ y = p_region->picture.p[0].p_pixels[i];
+ u = p_region->picture.p[1].p_pixels[i];
+ v = p_region->picture.p[2].p_pixels[i];
+ a = p_region->picture.p[3].p_pixels[i];
+ for( j = 0; j < p_fmt->p_palette->i_entries; j++ )
+ {
+ if( abs((int)p_fmt->p_palette->palette[j][0] - (int)y) <= i_tolerance &&
+ abs((int)p_fmt->p_palette->palette[j][1] - (int)u) <= i_tolerance &&
+ abs((int)p_fmt->p_palette->palette[j][2] - (int)v) <= i_tolerance &&
+ abs((int)p_fmt->p_palette->palette[j][3] - (int)a) <= i_tolerance / 2 )
+ {
+ break;
+ }
+ }
+ if( j == p_fmt->p_palette->i_entries )
+ {
+ p_fmt->p_palette->palette[j][0] = y;
+ p_fmt->p_palette->palette[j][1] = u;
+ p_fmt->p_palette->palette[j][2] = v;
+ p_fmt->p_palette->palette[j][3] = a;
+ p_fmt->p_palette->i_entries++;
+ }
+ if( p_fmt->p_palette->i_entries >= i_max_entries )
+ {
+ b_success = VLC_FALSE;
+ break;
+ }
+ i += i_iterator;
+ if( i > i_pixels )
+ {
+ i -= i_pixels;
+ }
+ }
+
+ if( b_success )
+ {
+ break;
+ }
+ }
+
+#if DEBUG_DVBSUB
+ msg_Dbg( p_enc, "best palette has %d colors", p_fmt->p_palette->i_entries );
+#endif
+
+#ifndef RANDOM_DITHERING
+ pi_delta = malloc( ( p_region->picture.p[0].i_pitch + 1 )
+ * sizeof(int) * 4 );
+ for( i = 0; i < (p_region->picture.p[0].i_pitch + 1) * 4 ; i++ )
+ {
+ pi_delta[ i ] = 0;
+ }
+#endif
+
+ /* Fill image with our new colours */
+ for( p = 0; p < p_region->picture.p[0].i_visible_lines ; p++ )
+ {
+ int i_ydelta = 0, i_udelta = 0, i_vdelta = 0, i_adelta = 0;
+
+ for( n = 0; n < p_region->picture.p[0].i_pitch ; n++ )
+ {
+ int i_offset = p * p_region->picture.p[0].i_pitch + n;
+ int y, u, v, a;
+ int i_mindist, i_best;
+
+ y = (int)p_region->picture.p[0].p_pixels[i_offset];
+ u = (int)p_region->picture.p[1].p_pixels[i_offset];
+ v = (int)p_region->picture.p[2].p_pixels[i_offset];
+ a = (int)p_region->picture.p[3].p_pixels[i_offset];
+
+ /* Add dithering compensation */
+#ifdef RANDOM_DITHERING
+ y += ((i_seed & 0xff) - 0x80) * i_tolerance / 0x80;
+ u += (((i_seed >> 8) & 0xff) - 0x80) * i_tolerance / 0x80;
+ v += (((i_seed >> 16) & 0xff) - 0x80) * i_tolerance / 0x80;
+ a += (((i_seed >> 24) & 0xff) - 0x80) * i_tolerance / 0x80;
+#else
+ y += i_ydelta + pi_delta[ n * 4 ];
+ u += i_udelta + pi_delta[ n * 4 + 1 ];
+ v += i_vdelta + pi_delta[ n * 4 + 2 ];
+ a += i_adelta + pi_delta[ n * 4 + 3 ];
+#endif
+
+ /* Find best colour in palette */
+ for( i_mindist = 99999999, i_best = 0, j = 0; j < p_fmt->p_palette->i_entries; j++ )
+ {
+ int i_dist = 0;
+
+ i_dist += abs((int)p_fmt->p_palette->palette[j][0] - y);
+ i_dist += abs((int)p_fmt->p_palette->palette[j][1] - u);
+ i_dist += abs((int)p_fmt->p_palette->palette[j][2] - v);
+ i_dist += 2 * abs((int)p_fmt->p_palette->palette[j][3] - a);
+
+ if( i_dist < i_mindist )
+ {
+ i_mindist = i_dist;
+ i_best = j;
+ }
+ }
+
+ /* Set pixel to best color */
+ p_region->picture.p[0].p_pixels[i_offset] = i_best;
+
+ /* Update dithering state */
+#ifdef RANDOM_DITHERING
+ i_seed = (i_seed * 0x1283837) ^ 0x789479 ^ (i_seed >> 13);
+#else
+ i_ydelta = y - (int)p_fmt->p_palette->palette[i_best][0];
+ i_udelta = u - (int)p_fmt->p_palette->palette[i_best][1];
+ i_vdelta = v - (int)p_fmt->p_palette->palette[i_best][2];
+ i_adelta = a - (int)p_fmt->p_palette->palette[i_best][3];
+ pi_delta[ n * 4 ] = i_ydelta * 3 / 8;
+ pi_delta[ n * 4 + 1 ] = i_udelta * 3 / 8;
+ pi_delta[ n * 4 + 2 ] = i_vdelta * 3 / 8;
+ pi_delta[ n * 4 + 3 ] = i_adelta * 3 / 8;
+ i_ydelta = i_ydelta * 5 / 8;
+ i_udelta = i_udelta * 5 / 8;
+ i_vdelta = i_vdelta * 5 / 8;
+ i_adelta = i_adelta * 5 / 8;
+#endif
+ }
+ }
+#ifndef RANDOM_DITHERING
+ free( pi_delta );
+#endif
+
+ /* pad palette */
+ for( i = p_fmt->p_palette->i_entries; i < i_max_entries; i++ )
+ {
+ p_fmt->p_palette->palette[i][0] = 0;
+ p_fmt->p_palette->palette[i][1] = 0;
+ p_fmt->p_palette->palette[i][2] = 0;
+ p_fmt->p_palette->palette[i][3] = 0;
+ }
+ p_fmt->p_palette->i_entries = i_max_entries;
+#if DEBUG_DVBSUB
+ msg_Dbg( p_enc, "best palette has %d colors", p_fmt->p_palette->i_entries );
+#endif
+ }
+ return p_subpic;
+} /* End of hack */
+
/****************************************************************************
* Encode: the whole thing
****************************************************************************/
static block_t *Encode( encoder_t *p_enc, subpicture_t *p_subpic )
{
+ subpicture_t *p_temp = NULL;
+ subpicture_region_t *p_region = NULL;
bs_t bits, *s = &bits;
block_t *p_block;
- if( !p_subpic || !p_subpic->p_region ) return 0;
-
+ if( !p_subpic || !p_subpic->p_region ) return NULL;
+
+ /* FIXME: this is a hack to convert VLC_FOURCC('Y','U','V','A') into
+ * VLC_FOURCC('Y','U','V','P')
+ */
+ p_region = p_subpic->p_region;
+ if( p_region->fmt.i_chroma == VLC_FOURCC('Y','U','V','A') )
+ {
+ p_temp = YuvaYuvp( p_enc, p_subpic );
+ if( !p_temp )
+ {
+ msg_Dbg( p_enc, "no picture in subpicture" );
+ return NULL;
+ }
+ p_region = p_subpic->p_region;
+ }
+ /* Sanity check */
+ if( !p_region ) return NULL;
+ if( p_region->fmt.i_chroma != VLC_FOURCC('T','E','X','T') &&
+ p_region->fmt.i_chroma != VLC_FOURCC('Y','U','V','P') ) return NULL;
+
+ if( p_region->fmt.p_palette &&
+ ( p_region->fmt.p_palette->i_entries != 4 ) &&
+ ( p_region->fmt.p_palette->i_entries != 16 ) &&
+ ( p_region->fmt.p_palette->i_entries != 256 ) )
+ {
+ msg_Err( p_enc, "subpicture palette (%d) not handled",
+ p_region->fmt.p_palette->i_entries );
+ return NULL;
+ }
+ /* End of hack */
+
#if DEBUG_DVBSUB
msg_Dbg( p_enc, "encoding subpicture" );
#endif
* $Id$
*
* Author: Peter Surda <shurdeek@panorama.sth.ac.at>
+ * Jean-Paul Saman <jpsaman #_at_# m2x _replaceWith#dot_ nl>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
#include <vlc/intf.h>
#include <vlc/aout.h>
#include <vlc/vout.h>
+#include <vlc_osd.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#define MAX_LINE_LENGTH 256
+#define STATUS_CHANGE "status change: "
/*****************************************************************************
* Local prototypes
static void Deactivate ( vlc_object_t * );
static void Run ( intf_thread_t * );
+static void Help ( intf_thread_t *, vlc_bool_t );
+
static vlc_bool_t ReadCommand( intf_thread_t *, char *, int * );
static playlist_item_t *parse_MRL( intf_thread_t *, char * );
vlc_value_t, vlc_value_t, void * );
static int AudioConfig ( vlc_object_t *, char const *,
vlc_value_t, vlc_value_t, void * );
+static int Menu ( vlc_object_t *, char const *,
+ vlc_value_t, vlc_value_t, void * );
+
+/* Status Callbacks */
+static int TimeOffsetChanged( vlc_object_t *, char const *,
+ vlc_value_t, vlc_value_t , void * );
+static int VolumeChanged ( vlc_object_t *, char const *,
+ vlc_value_t, vlc_value_t, void * );
+static int StateChanged ( vlc_object_t *, char const *,
+ vlc_value_t, vlc_value_t, void * );
+static int RateChanged ( vlc_object_t *, char const *,
+ vlc_value_t, vlc_value_t, void * );
struct intf_sys_t
{
int i_socket;
char *psz_unix_path;
+ /* status changes */
+ vlc_mutex_t status_lock;
+ playlist_status_t i_last_state;
+
#ifdef WIN32
HANDLE hConsoleIn;
vlc_bool_t b_quiet;
{
va_list args;
va_start( args, psz_fmt );
- if( p_intf->p_sys->i_socket == -1 ) vprintf( psz_fmt, args );
+ if( p_intf->p_sys->i_socket == -1 )
+ vprintf( psz_fmt, args );
else
- { net_vaPrintf( p_intf, p_intf->p_sys->i_socket, NULL, psz_fmt, args );
- net_Printf( VLC_OBJECT(p_intf), p_intf->p_sys->i_socket, NULL, "\r" ); }
+ {
+ net_vaPrintf( p_intf, p_intf->p_sys->i_socket, NULL, psz_fmt, args );
+ net_Printf( VLC_OBJECT(p_intf), p_intf->p_sys->i_socket, NULL, "\r" );
+ }
va_end( args );
}
intf_thread_t *p_intf = (intf_thread_t*)p_this;
playlist_t *p_playlist;
char *psz_host, *psz_unix_path;
- int *pi_socket = NULL;
+ int *pi_socket = NULL;
#if defined(HAVE_ISATTY) && !defined(WIN32)
/* Check that stdin is a TTY */
p_intf->p_sys->pi_socket_listen = pi_socket;
p_intf->p_sys->i_socket = -1;
p_intf->p_sys->psz_unix_path = psz_unix_path;
-
+ vlc_mutex_init( p_intf, &p_intf->p_sys->status_lock );
+ p_intf->p_sys->i_last_state = PLAYLIST_STOPPED;
+
/* Non-buffered stdout */
setvbuf( stdout, (char *)NULL, _IOLBF, 0 );
#endif
free( p_intf->p_sys->psz_unix_path );
}
+ vlc_mutex_destroy( &p_intf->p_sys->status_lock );
free( p_intf->p_sys );
}
var_AddCallback( p_intf, "logo-position", Other, NULL );
var_Create( p_intf, "logo-transparency", VLC_VAR_INTEGER | VLC_VAR_ISCOMMAND );
var_AddCallback( p_intf, "logo-transparency", Other, NULL );
-
-
+
+ /* OSD menu commands */
+ var_Create( p_intf, "menu", VLC_VAR_STRING | VLC_VAR_ISCOMMAND );
+ var_AddCallback( p_intf, "menu", Menu, NULL );
+
+ /* DVD commands */
var_Create( p_intf, "pause", VLC_VAR_VOID | VLC_VAR_ISCOMMAND );
var_AddCallback( p_intf, "pause", Input, NULL );
var_Create( p_intf, "seek", VLC_VAR_INTEGER | VLC_VAR_ISCOMMAND );
var_AddCallback( p_intf, "fastforward", Input, NULL );
var_Create( p_intf, "rewind", VLC_VAR_VOID | VLC_VAR_ISCOMMAND );
var_AddCallback( p_intf, "rewind", Input, NULL );
-
+ var_Create( p_intf, "faster", VLC_VAR_VOID | VLC_VAR_ISCOMMAND );
+ var_AddCallback( p_intf, "faster", Input, NULL );
+ var_Create( p_intf, "slower", VLC_VAR_VOID | VLC_VAR_ISCOMMAND );
+ var_AddCallback( p_intf, "slower", Input, NULL );
+ var_Create( p_intf, "normal", VLC_VAR_VOID | VLC_VAR_ISCOMMAND );
+ var_AddCallback( p_intf, "normal", Input, NULL );
+
+ /* audio commands */
var_Create( p_intf, "volume", VLC_VAR_STRING | VLC_VAR_ISCOMMAND );
var_AddCallback( p_intf, "volume", Volume, NULL );
var_Create( p_intf, "volup", VLC_VAR_STRING | VLC_VAR_ISCOMMAND );
var_Create( p_intf, "achan", VLC_VAR_STRING | VLC_VAR_ISCOMMAND );
var_AddCallback( p_intf, "achan", AudioConfig, NULL );
+ /* status callbacks */
+ /* Listen to audio volume updates */
+ var_AddCallback( p_intf->p_vlc, "audio-volume", VolumeChanged, p_intf );
+
#ifdef WIN32
/* Get the file descriptor of the console input */
p_intf->p_sys->hConsoleIn = GetStdHandle(STD_INPUT_HANDLE);
FIND_PARENT );
}
}
+ /* New input has been registered */
+ if( p_input )
+ {
+ if( !p_input->b_dead || !p_input->b_die )
+ {
+ msg_rc( STATUS_CHANGE "( New input: %s )\r\n", p_input->input.p_item->psz_uri );
+ msg_rc( STATUS_CHANGE "( audio volume: %d )\r\n", config_GetInt( p_intf, "volume" ));
+ }
+ var_AddCallback( p_input, "state", StateChanged, p_intf );
+ var_AddCallback( p_input, "rate-faster", RateChanged, p_intf );
+ var_AddCallback( p_input, "rate-slower", RateChanged, p_intf );
+ var_AddCallback( p_input, "rate", RateChanged, p_intf );
+ var_AddCallback( p_input, "time-offset", TimeOffsetChanged, p_intf );
+ }
}
else if( p_input->b_dead )
{
+ var_DelCallback( p_input, "state", StateChanged, p_intf );
+ var_DelCallback( p_input, "rate-faster", RateChanged, p_intf );
+ var_DelCallback( p_input, "rate-slower", RateChanged, p_intf );
+ var_DelCallback( p_input, "rate", RateChanged, p_intf );
+ var_DelCallback( p_input, "time-offset", TimeOffsetChanged, p_intf );
vlc_object_release( p_input );
p_input = NULL;
+
+ if( p_playlist )
+ {
+ vlc_mutex_lock( &p_playlist->object_lock );
+ p_intf->p_sys->i_last_state = (int) PLAYLIST_STOPPED;
+ msg_rc( STATUS_CHANGE "( stop state: 0 )\r\n" );
+ vlc_mutex_unlock( &p_playlist->object_lock );
+ }
+ }
+
+ if( (p_input != NULL) && !p_input->b_dead && !p_input->b_die &&
+ (p_playlist != NULL) )
+ {
+ vlc_mutex_lock( &p_playlist->object_lock );
+ if( (p_intf->p_sys->i_last_state != p_playlist->status.i_status) &&
+ (p_playlist->status.i_status == PLAYLIST_STOPPED) )
+ {
+ p_intf->p_sys->i_last_state = PLAYLIST_STOPPED;
+ msg_rc( STATUS_CHANGE "( stop state: 0 )\r\n" );
+ }
+ else if( (p_intf->p_sys->i_last_state != p_playlist->status.i_status) &&
+ (p_playlist->status.i_status == PLAYLIST_RUNNING) )
+ {
+ p_intf->p_sys->i_last_state = p_playlist->status.i_status;
+ msg_rc( STATUS_CHANGE "( play state: 1 )\r\n" );
+ }
+ else if( (p_intf->p_sys->i_last_state != p_playlist->status.i_status) &&
+ (p_playlist->status.i_status == PLAYLIST_PAUSED) )
+ {
+ p_intf->p_sys->i_last_state = p_playlist->status.i_status;
+ msg_rc( STATUS_CHANGE "( pause state: 2 )\r\n" );
+ }
+ vlc_mutex_unlock( &p_playlist->object_lock );
}
if( p_input && b_showpos )
else
{
msg_rc( "1\n" );
+
+ /* FIXME: This is a hack */
+ /* Replay the current state of the system. */
+ msg_rc( STATUS_CHANGE "( New input: %s )\r\n", p_input->input.p_item->psz_uri );
+ msg_rc( STATUS_CHANGE "( audio volume: %d )\r\n", config_GetInt( p_intf, "volume" ));
+
+ if( p_playlist )
+ {
+ vlc_mutex_lock( &p_playlist->object_lock );
+ switch( p_playlist->status.i_status )
+ {
+ case PLAYLIST_STOPPED:
+ msg_rc( STATUS_CHANGE "( stop state: 0 )\r\n" );
+ break;
+ case PLAYLIST_RUNNING:
+ msg_rc( STATUS_CHANGE "( play state: %d )\r\n", var_GetInteger( p_input, "state" ) );
+ break;
+ case PLAYLIST_PAUSED:
+ msg_rc( STATUS_CHANGE "( pause state: 2 )\r\n" );
+ break;
+ default:
+ msg_rc( STATUS_CHANGE "( state unknown )\r\n" );
+ break;
+ }
+ vlc_mutex_unlock( &p_playlist->object_lock );
+ } /* End of current playlist status */
}
}
else if( !strcmp( psz_cmd, "get_time" ) )
if( !strcmp( psz_cmd, "longhelp" ) || !strncmp( psz_cmd, "H", 1 ) )
b_longhelp = VLC_TRUE;
else b_longhelp = VLC_FALSE;
-
- msg_rc(_("+----[ Remote control commands ]\n"));
- msg_rc( "| \n");
- msg_rc(_("| add XYZ . . . . . . . . . . add XYZ to playlist\n"));
- msg_rc(_("| playlist . . . show items currently in playlist\n"));
- msg_rc(_("| play . . . . . . . . . . . . . . . . play stream\n"));
- msg_rc(_("| stop . . . . . . . . . . . . . . . . stop stream\n"));
- msg_rc(_("| next . . . . . . . . . . . . next playlist item\n"));
- msg_rc(_("| prev . . . . . . . . . . previous playlist item\n"));
- msg_rc(_("| goto . . . . . . . . . . . . goto item at index\n"));
- msg_rc(_("| title [X] . . . . set/get title in current item\n"));
- msg_rc(_("| title_n . . . . . . next title in current item\n"));
- msg_rc(_("| title_p . . . . previous title in current item\n"));
- msg_rc(_("| chapter [X] . . set/get chapter in current item\n"));
- msg_rc(_("| chapter_n . . . . next chapter in current item\n"));
- msg_rc(_("| chapter_p . . previous chapter in current item\n"));
- msg_rc( "| \n");
- msg_rc(_("| seek X . seek in seconds, for instance `seek 12'\n"));
- msg_rc(_("| pause . . . . . . . . . . . . . . toggle pause\n"));
- msg_rc(_("| fastforward . . . . . . . set to maximum rate\n"));
- msg_rc(_("| rewind . . . . . . . . . . set to minimum rate\n"));
- msg_rc(_("| f . . . . . . . . . . . . . . toggle fullscreen\n"));
- msg_rc(_("| info . . . information about the current stream\n"));
- msg_rc( "| \n");
- msg_rc(_("| volume [X] . . . . . . . . set/get audio volume\n"));
- msg_rc(_("| volup [X] . . . . . raise audio volume X steps\n"));
- msg_rc(_("| voldown [X] . . . . lower audio volume X steps\n"));
- msg_rc(_("| adev [X] . . . . . . . . . set/get audio device\n"));
- msg_rc(_("| achan [X]. . . . . . . . set/get audio channels\n"));
- msg_rc( "| \n");
-
- if (b_longhelp)
- {
- msg_rc(_("| marq-marquee STRING . . overlay STRING in video\n"));
- msg_rc(_("| marq-x X . . . . . . . . . . . .offset from left\n"));
- msg_rc(_("| marq-y Y . . . . . . . . . . . . offset from top\n"));
- msg_rc(_("| marq-position #. . . .relative position control\n"));
- msg_rc(_("| marq-color # . . . . . . . . . . font color, RGB\n"));
- msg_rc(_("| marq-opacity # . . . . . . . . . . . . . opacity\n"));
- msg_rc(_("| marq-timeout T. . . . . . . . . . timeout, in ms\n"));
- msg_rc(_("| marq-size # . . . . . . . . font size, in pixels\n"));
- msg_rc( "| \n");
- msg_rc(_("| time-format STRING . . . overlay STRING in video\n"));
- msg_rc(_("| time-x X . . . . . . . . . . . .offset from left\n"));
- msg_rc(_("| time-y Y . . . . . . . . . . . . offset from top\n"));
- msg_rc(_("| time-position #. . . . . . . . relative position\n"));
- msg_rc(_("| time-color # . . . . . . . . . . font color, RGB\n"));
- msg_rc(_("| time-opacity # . . . . . . . . . . . . . opacity\n"));
- msg_rc(_("| time-size # . . . . . . . . font size, in pixels\n"));
- msg_rc( "| \n");
- msg_rc(_("| logo-file STRING . . . the overlay file path/name\n"));
- msg_rc(_("| logo-x X . . . . . . . . . . . .offset from left\n"));
- msg_rc(_("| logo-y Y . . . . . . . . . . . . offset from top\n"));
- msg_rc(_("| logo-position #. . . . . . . . relative position\n"));
- msg_rc(_("| logo-transparency #. . . . . . . . .transparency\n"));
- msg_rc( "| \n");
- msg_rc(_("| mosaic-alpha # . . . . . . . . . . . . . . alpha\n"));
- msg_rc(_("| mosaic-height #. . . . . . . . . . . . . .height\n"));
- msg_rc(_("| mosaic-width # . . . . . . . . . . . . . . width\n"));
- msg_rc(_("| mosaic-xoffset # . . . .top left corner position\n"));
- msg_rc(_("| mosaic-yoffset # . . . .top left corner position\n"));
- msg_rc(_("| mosaic-align 0..2,4..6,8..10. . .mosaic alignment\n"));
- msg_rc(_("| mosaic-vborder # . . . . . . . . vertical border\n"));
- msg_rc(_("| mosaic-hborder # . . . . . . . horizontal border\n"));
- msg_rc(_("| mosaic-position {0=auto,1=fixed} . . . .position\n"));
- msg_rc(_("| mosaic-rows #. . . . . . . . . . .number of rows\n"));
- msg_rc(_("| mosaic-cols #. . . . . . . . . . .number of cols\n"));
- msg_rc(_("| mosaic-keep-aspect-ratio {0,1} . . .aspect ratio\n"));
- msg_rc( "| \n");
- }
- msg_rc(_("| help . . . . . . . . . . . . . this help message\n"));
- msg_rc(_("| longhelp . . . . . . . . . a longer help message\n"));
- msg_rc(_("| logout . . . . . exit (if in socket connection)\n"));
- msg_rc(_("| quit . . . . . . . . . . . . . . . . . quit vlc\n"));
- msg_rc( "| \n");
- msg_rc(_("+----[ end of help ]\n"));
+
+ Help( p_intf, b_longhelp );
}
else switch( psz_cmd[0] )
{
i_size = 0; p_buffer[0] = 0;
}
+ msg_rc( STATUS_CHANGE "( stop state: 0 )\r\n" );
+ msg_rc( STATUS_CHANGE "( quit )\r\n" );
+
if( p_input )
{
+ var_DelCallback( p_input, "state", StateChanged, p_intf );
+ var_DelCallback( p_input, "rate-faster", RateChanged, p_intf );
+ var_DelCallback( p_input, "rate-slower", RateChanged, p_intf );
+ var_DelCallback( p_input, "rate", RateChanged, p_intf );
+ var_DelCallback( p_input, "time-offset", TimeOffsetChanged, p_intf );
vlc_object_release( p_input );
p_input = NULL;
}
vlc_object_release( p_playlist );
p_playlist = NULL;
}
+
+ var_DelCallback( p_intf->p_vlc, "audio-volume", VolumeChanged, p_intf );
+}
+
+static void Help( intf_thread_t *p_intf, vlc_bool_t b_longhelp)
+{
+ msg_rc(_("+----[ Remote control commands ]\n"));
+ msg_rc( "| \n");
+ msg_rc(_("| add XYZ . . . . . . . . . . add XYZ to playlist\n"));
+ msg_rc(_("| playlist . . . show items currently in playlist\n"));
+ msg_rc(_("| play . . . . . . . . . . . . . . . . play stream\n"));
+ msg_rc(_("| stop . . . . . . . . . . . . . . . . stop stream\n"));
+ msg_rc(_("| next . . . . . . . . . . . . next playlist item\n"));
+ msg_rc(_("| prev . . . . . . . . . . previous playlist item\n"));
+ msg_rc(_("| goto . . . . . . . . . . . . goto item at index\n"));
+ msg_rc(_("| title [X] . . . . set/get title in current item\n"));
+ msg_rc(_("| title_n . . . . . . next title in current item\n"));
+ msg_rc(_("| title_p . . . . previous title in current item\n"));
+ msg_rc(_("| chapter [X] . . set/get chapter in current item\n"));
+ msg_rc(_("| chapter_n . . . . next chapter in current item\n"));
+ msg_rc(_("| chapter_p . . previous chapter in current item\n"));
+ msg_rc( "| \n");
+ msg_rc(_("| seek X . seek in seconds, for instance `seek 12'\n"));
+ msg_rc(_("| pause . . . . . . . . . . . . . . toggle pause\n"));
+ msg_rc(_("| fastforward . . . . . . . set to maximum rate\n"));
+ msg_rc(_("| rewind . . . . . . . . . . set to minimum rate\n"));
+ msg_rc(_("| faster . . . . . . . . faster playing of stream\n"));
+ msg_rc(_("| slower . . . . . . . . slower playing of stream\n"));
+ msg_rc(_("| normal . . . . . . . . normal playing of stream\n"));
+ msg_rc(_("| f . . . . . . . . . . . . . . toggle fullscreen\n"));
+ msg_rc(_("| info . . . information about the current stream\n"));
+ msg_rc( "| \n");
+ msg_rc(_("| volume [X] . . . . . . . . set/get audio volume\n"));
+ msg_rc(_("| volup [X] . . . . . raise audio volume X steps\n"));
+ msg_rc(_("| voldown [X] . . . . lower audio volume X steps\n"));
+ msg_rc(_("| adev [X] . . . . . . . . . set/get audio device\n"));
+ msg_rc(_("| achan [X]. . . . . . . . set/get audio channels\n"));
+ msg_rc(_("| menu [on|off|up|down|left|right|select] use menu\n"));
+ msg_rc( "| \n");
+
+ if (b_longhelp)
+ {
+ msg_rc(_("| marq-marquee STRING . . overlay STRING in video\n"));
+ msg_rc(_("| marq-x X . . . . . . . . . . . .offset from left\n"));
+ msg_rc(_("| marq-y Y . . . . . . . . . . . . offset from top\n"));
+ msg_rc(_("| marq-position #. . . .relative position control\n"));
+ msg_rc(_("| marq-color # . . . . . . . . . . font color, RGB\n"));
+ msg_rc(_("| marq-opacity # . . . . . . . . . . . . . opacity\n"));
+ msg_rc(_("| marq-timeout T. . . . . . . . . . timeout, in ms\n"));
+ msg_rc(_("| marq-size # . . . . . . . . font size, in pixels\n"));
+ msg_rc( "| \n");
+ msg_rc(_("| time-format STRING . . . overlay STRING in video\n"));
+ msg_rc(_("| time-x X . . . . . . . . . . . .offset from left\n"));
+ msg_rc(_("| time-y Y . . . . . . . . . . . . offset from top\n"));
+ msg_rc(_("| time-position #. . . . . . . . relative position\n"));
+ msg_rc(_("| time-color # . . . . . . . . . . font color, RGB\n"));
+ msg_rc(_("| time-opacity # . . . . . . . . . . . . . opacity\n"));
+ msg_rc(_("| time-size # . . . . . . . . font size, in pixels\n"));
+ msg_rc( "| \n");
+ msg_rc(_("| logo-file STRING . . . the overlay file path/name\n"));
+ msg_rc(_("| logo-x X . . . . . . . . . . . .offset from left\n"));
+ msg_rc(_("| logo-y Y . . . . . . . . . . . . offset from top\n"));
+ msg_rc(_("| logo-position #. . . . . . . . relative position\n"));
+ msg_rc(_("| logo-transparency #. . . . . . . . .transparency\n"));
+ msg_rc( "| \n");
+ msg_rc(_("| mosaic-alpha # . . . . . . . . . . . . . . alpha\n"));
+ msg_rc(_("| mosaic-height #. . . . . . . . . . . . . .height\n"));
+ msg_rc(_("| mosaic-width # . . . . . . . . . . . . . . width\n"));
+ msg_rc(_("| mosaic-xoffset # . . . .top left corner position\n"));
+ msg_rc(_("| mosaic-yoffset # . . . .top left corner position\n"));
+ msg_rc(_("| mosaic-align 0..2,4..6,8..10. . .mosaic alignment\n"));
+ msg_rc(_("| mosaic-vborder # . . . . . . . . vertical border\n"));
+ msg_rc(_("| mosaic-hborder # . . . . . . . horizontal border\n"));
+ msg_rc(_("| mosaic-position {0=auto,1=fixed} . . . .position\n"));
+ msg_rc(_("| mosaic-rows #. . . . . . . . . . .number of rows\n"));
+ msg_rc(_("| mosaic-cols #. . . . . . . . . . .number of cols\n"));
+ msg_rc(_("| mosaic-keep-aspect-ratio {0,1} . . .aspect ratio\n"));
+ msg_rc( "| \n");
+ }
+ msg_rc(_("| help . . . . . . . . . . . . . this help message\n"));
+ msg_rc(_("| longhelp . . . . . . . . . a longer help message\n"));
+ msg_rc(_("| logout . . . . . exit (if in socket connection)\n"));
+ msg_rc(_("| quit . . . . . . . . . . . . . . . . . quit vlc\n"));
+ msg_rc( "| \n");
+ msg_rc(_("+----[ end of help ]\n"));
+}
+
+/********************************************************************
+ * Status callback routines
+ ********************************************************************/
+static int TimeOffsetChanged( vlc_object_t *p_this, char const *psz_cmd,
+ vlc_value_t oldval, vlc_value_t newval, void *p_data )
+{
+ intf_thread_t *p_intf = (intf_thread_t*)p_data;
+ input_thread_t *p_input = NULL;
+
+ vlc_mutex_lock( &p_intf->p_sys->status_lock );
+ p_input = vlc_object_find( p_intf, VLC_OBJECT_INPUT, FIND_ANYWHERE );
+ if( p_input )
+ {
+ msg_rc( STATUS_CHANGE "( time-offset: %d )\r\n", var_GetInteger( p_input, "time-offset" ) );
+ vlc_object_release( p_input );
+ }
+ vlc_mutex_unlock( &p_intf->p_sys->status_lock );
+ return VLC_SUCCESS;
}
+static int VolumeChanged( vlc_object_t *p_this, char const *psz_cmd,
+ vlc_value_t oldval, vlc_value_t newval, void *p_data )
+{
+ intf_thread_t *p_intf = (intf_thread_t*)p_data;
+
+ vlc_mutex_lock( &p_intf->p_sys->status_lock );
+ msg_rc( STATUS_CHANGE "( audio volume: %d )\r\n", newval.i_int );
+ vlc_mutex_unlock( &p_intf->p_sys->status_lock );
+ return VLC_SUCCESS;
+}
+
+static int StateChanged( vlc_object_t *p_this, char const *psz_cmd,
+ vlc_value_t oldval, vlc_value_t newval, void *p_data )
+{
+ intf_thread_t *p_intf = (intf_thread_t*)p_data;
+ playlist_t *p_playlist = NULL;
+ input_thread_t *p_input = NULL;
+
+ vlc_mutex_lock( &p_intf->p_sys->status_lock );
+ p_input = vlc_object_find( p_intf, VLC_OBJECT_INPUT, FIND_ANYWHERE );
+ if( p_input )
+ {
+ p_playlist = vlc_object_find( p_input, VLC_OBJECT_PLAYLIST, FIND_PARENT );
+ if( p_playlist )
+ {
+ char cmd[5] = "";
+ switch( p_playlist->status.i_status )
+ {
+ case PLAYLIST_STOPPED:
+ strncpy( &cmd[0], "stop", 4);
+ cmd[4] = '\0';
+ break;
+ case PLAYLIST_RUNNING:
+ strncpy( &cmd[0], "play", 4);
+ cmd[4] = '\0';
+ break;
+ case PLAYLIST_PAUSED:
+ strncpy( &cmd[0], "pause", 5);
+ cmd[5] = '\0';
+ break;
+ } /* var_GetInteger( p_input, "state" ) */
+ msg_rc( STATUS_CHANGE "( %s state: %d )\r\n", &cmd[0], newval.i_int );
+ vlc_object_release( p_playlist );
+ }
+ vlc_object_release( p_input );
+ }
+ vlc_mutex_unlock( &p_intf->p_sys->status_lock );
+ return VLC_SUCCESS;
+}
+
+static int RateChanged( vlc_object_t *p_this, char const *psz_cmd,
+ vlc_value_t oldval, vlc_value_t newval, void *p_data )
+{
+ intf_thread_t *p_intf = (intf_thread_t*)p_data;
+ input_thread_t *p_input = NULL;
+
+ vlc_mutex_lock( &p_intf->p_sys->status_lock );
+ p_input = vlc_object_find( p_intf, VLC_OBJECT_INPUT, FIND_ANYWHERE );
+ if( p_input )
+ {
+ msg_rc( STATUS_CHANGE "( new rate: %d )\r\n", var_GetInteger( p_input, "rate" ) );
+ vlc_object_release( p_input );
+ }
+ vlc_mutex_unlock( &p_intf->p_sys->status_lock );
+ return VLC_SUCCESS;
+}
+
+/********************************************************************
+ * Command routines
+ ********************************************************************/
static int Input( vlc_object_t *p_this, char const *psz_cmd,
vlc_value_t oldval, vlc_value_t newval, void *p_data )
{
p_input = vlc_object_find( p_this, VLC_OBJECT_INPUT, FIND_ANYWHERE );
if( !p_input ) return VLC_ENOOBJ;
+ var_Get( p_input, "state", &val );
+ if( ( ( val.i_int == PAUSE_S ) || ( val.i_int == PLAYLIST_PAUSED ) ) &&
+ ( strcmp( psz_cmd, "pause" ) != 0 ) )
+ {
+ msg_rc( _("press pause to continue\r\n") );
+ vlc_object_release( p_input );
+ return VLC_EGENERIC;
+ }
+
/* Parse commands that only require an input */
if( !strcmp( psz_cmd, "pause" ) )
{
}
else if ( !strcmp( psz_cmd, "fastforward" ) )
{
- val.i_int = INPUT_RATE_MAX;
-
- var_Set( p_input, "rate", val );
+ val.i_int = config_GetInt( p_intf, "key-jump+3sec" );
+ var_Set( p_intf->p_vlc, "key-pressed", val );
+
vlc_object_release( p_input );
return VLC_SUCCESS;
}
else if ( !strcmp( psz_cmd, "rewind" ) )
{
- val.i_int = INPUT_RATE_MIN;
+ val.i_int = config_GetInt( p_intf, "key-jump-3sec" );
+ var_Set( p_intf->p_vlc, "key-pressed", val );
+
+ vlc_object_release( p_input );
+ return VLC_SUCCESS;
+ }
+ else if ( !strcmp( psz_cmd, "faster" ) )
+ {
+ val.b_bool = VLC_TRUE;
+
+ var_Set( p_input, "rate-faster", val );
+ vlc_object_release( p_input );
+ return VLC_SUCCESS;
+ }
+ else if ( !strcmp( psz_cmd, "slower" ) )
+ {
+ val.b_bool = VLC_TRUE;
+
+ var_Set( p_input, "rate-slower", val );
+ vlc_object_release( p_input );
+ return VLC_SUCCESS;
+ }
+ else if ( !strcmp( psz_cmd, "normal" ) )
+ {
+ val.i_int = INPUT_RATE_DEFAULT;
var_Set( p_input, "rate", val );
vlc_object_release( p_input );
return VLC_ENOOBJ;
}
+ if( p_playlist->p_input )
+ {
+ vlc_value_t val;
+ var_Get( p_playlist->p_input, "state", &val );
+ if( ( ( val.i_int == PAUSE_S ) || ( val.i_int == PLAYLIST_PAUSED ) ) &&
+ ( strcmp( psz_cmd, "pause" ) != 0 ) )
+ {
+ msg_rc( _("press pause to continue\r\n") );
+ vlc_object_release( p_playlist );
+ return VLC_EGENERIC;
+ }
+ }
+
/* Parse commands that require a playlist */
if( !strcmp( psz_cmd, "prev" ) )
{
}
else if( !strcmp( psz_cmd, "play" ) )
{
- playlist_Play( p_playlist );
+ if( p_playlist->p_input )
+ {
+ vlc_value_t val;
+
+ var_Get( p_playlist->p_input, "rate", &val );
+ if( val.i_int != INPUT_RATE_DEFAULT )
+ {
+ val.i_int = INPUT_RATE_DEFAULT;
+ var_Set( p_playlist->p_input, "rate", val );
+ }
+ else
+ {
+ playlist_Play( p_playlist );
+ }
+ }
}
else if (!strcmp( psz_cmd, "goto" ) )
{
vlc_value_t oldval, vlc_value_t newval, void *p_data )
{
intf_thread_t *p_intf = (intf_thread_t*)p_this;
- vlc_object_t *p_pl;
- vlc_value_t val;
- vlc_object_t *p_inp;
+ vlc_object_t *p_playlist;
+ vlc_value_t val;
+ vlc_object_t *p_input;
- p_pl = vlc_object_find( p_this, VLC_OBJECT_PLAYLIST,
- FIND_ANYWHERE );
- if( !p_pl )
+ p_playlist = vlc_object_find( p_this, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
+ if( !p_playlist )
{
return VLC_ENOOBJ;
}
- p_inp = vlc_object_find( p_this, VLC_OBJECT_INPUT,
- FIND_ANYWHERE );
- if( !p_inp )
+ p_input = vlc_object_find( p_this, VLC_OBJECT_INPUT, FIND_ANYWHERE );
+ if( !p_input )
{
- vlc_object_release( p_pl );
+ vlc_object_release( p_playlist );
return VLC_ENOOBJ;
}
+ if( p_input )
+ {
+ var_Get( p_input, "state", &val );
+ if( ( ( val.i_int == PAUSE_S ) || ( val.i_int == PLAYLIST_PAUSED ) ) &&
+ ( strcmp( psz_cmd, "pause" ) != 0 ) )
+ {
+ msg_rc( _("press pause to continue\r\n") );
+ vlc_object_release( p_playlist );
+ vlc_object_release( p_input );
+ return VLC_EGENERIC;
+ }
+ }
+
/* Parse miscellaneous commands */
if( !strcmp( psz_cmd, "marq-marquee" ) )
{
if( strlen( newval.psz_string ) > 0 )
{
val.psz_string = newval.psz_string;
- var_Set( p_inp->p_libvlc, "marq-marquee", val );
+ var_Set( p_input->p_libvlc, "marq-marquee", val );
}
else
{
val.psz_string = "";
- var_Set( p_inp->p_libvlc, "marq-marquee", val);
+ var_Set( p_input->p_libvlc, "marq-marquee", val);
}
}
else if( !strcmp( psz_cmd, "marq-x" ) )
if( strlen( newval.psz_string ) > 0)
{
val.i_int = atoi( newval.psz_string );
- var_Set( p_inp->p_libvlc, "marq-x", val );
+ var_Set( p_input->p_libvlc, "marq-x", val );
}
}
else if( !strcmp( psz_cmd, "marq-y" ) )
if( strlen( newval.psz_string ) > 0)
{
val.i_int = atoi( newval.psz_string );
- var_Set( p_inp->p_libvlc, "marq-y", val );
+ var_Set( p_input->p_libvlc, "marq-y", val );
}
}
else if( !strcmp( psz_cmd, "marq-position" ) )
if( strlen( newval.psz_string ) > 0)
{
val.i_int = atoi( newval.psz_string );
- var_Set( p_inp->p_libvlc, "marq-position", val );
+ var_Set( p_input->p_libvlc, "marq-position", val );
}
}
else if( !strcmp( psz_cmd, "marq-color" ) )
if( strlen( newval.psz_string ) > 0)
{
val.i_int = strtol( newval.psz_string, NULL, 0 );
- var_Set( p_inp->p_libvlc, "marq-color", val );
+ var_Set( p_input->p_libvlc, "marq-color", val );
}
}
else if( !strcmp( psz_cmd, "marq-opacity" ) )
if( strlen( newval.psz_string ) > 0)
{
val.i_int = strtol( newval.psz_string, NULL, 0 );
- var_Set( p_inp->p_libvlc, "marq-opacity", val );
+ var_Set( p_input->p_libvlc, "marq-opacity", val );
}
}
else if( !strcmp( psz_cmd, "marq-size" ) )
if( strlen( newval.psz_string ) > 0)
{
val.i_int = atoi( newval.psz_string );
- var_Set( p_inp->p_libvlc, "marq-size", val );
+ var_Set( p_input->p_libvlc, "marq-size", val );
}
}
else if( !strcmp( psz_cmd, "marq-timeout" ) )
if( strlen( newval.psz_string ) > 0)
{
val.i_int = atoi( newval.psz_string );
- var_Set( p_inp, "marq-timeout", val );
+ var_Set( p_input, "marq-timeout", val );
}
}
else if( !strcmp( psz_cmd, "mosaic-alpha" ) )
if( strlen( newval.psz_string ) > 0)
{
val.i_int = atoi( newval.psz_string );
- var_Set( p_inp->p_libvlc, "mosaic-alpha", val );
+ var_Set( p_input->p_libvlc, "mosaic-alpha", val );
}
}
else if( !strcmp( psz_cmd, "mosaic-height" ) )
if( strlen( newval.psz_string ) > 0)
{
val.i_int = atoi( newval.psz_string );
- var_Set( p_inp->p_libvlc, "mosaic-height", val );
+ var_Set( p_input->p_libvlc, "mosaic-height", val );
}
}
else if( !strcmp( psz_cmd, "mosaic-width" ) )
if( strlen( newval.psz_string ) > 0)
{
val.i_int = atoi( newval.psz_string );
- var_Set( p_inp->p_libvlc, "mosaic-width", val );
+ var_Set( p_input->p_libvlc, "mosaic-width", val );
}
}
else if( !strcmp( psz_cmd, "mosaic-xoffset" ) )
if( strlen( newval.psz_string ) > 0)
{
val.i_int = atoi( newval.psz_string );
- var_Set( p_inp->p_libvlc, "mosaic-xoffset", val );
+ var_Set( p_input->p_libvlc, "mosaic-xoffset", val );
}
}
else if( !strcmp( psz_cmd, "mosaic-yoffset" ) )
if( strlen( newval.psz_string ) > 0)
{
val.i_int = atoi( newval.psz_string );
- var_Set( p_inp->p_libvlc, "mosaic-yoffset", val );
+ var_Set( p_input->p_libvlc, "mosaic-yoffset", val );
}
}
else if( !strcmp( psz_cmd, "mosaic-align" ) )
if( strlen( newval.psz_string ) > 0 )
{
val.i_int = atoi( newval.psz_string );
- var_Set( p_inp->p_libvlc, "mosaic-align", val );
+ var_Set( p_input->p_libvlc, "mosaic-align", val );
}
}
else if( !strcmp( psz_cmd, "mosaic-vborder" ) )
if( strlen( newval.psz_string ) > 0)
{
val.i_int = atoi( newval.psz_string );
- var_Set( p_inp->p_libvlc, "mosaic-vborder", val );
+ var_Set( p_input->p_libvlc, "mosaic-vborder", val );
}
}
else if( !strcmp( psz_cmd, "mosaic-hborder" ) )
if( strlen( newval.psz_string ) > 0)
{
val.i_int = atoi( newval.psz_string );
- var_Set( p_inp->p_libvlc, "mosaic-hborder", val );
+ var_Set( p_input->p_libvlc, "mosaic-hborder", val );
}
}
else if( !strcmp( psz_cmd, "mosaic-position" ) )
if( strlen( newval.psz_string ) > 0)
{
val.i_int = atoi( newval.psz_string );
- var_Set( p_inp->p_libvlc, "mosaic-position", val );
+ var_Set( p_input->p_libvlc, "mosaic-position", val );
}
}
else if( !strcmp( psz_cmd, "mosaic-rows" ) )
if( strlen( newval.psz_string ) > 0)
{
val.i_int = atoi( newval.psz_string );
- var_Set( p_inp->p_libvlc, "mosaic-rows", val );
+ var_Set( p_input->p_libvlc, "mosaic-rows", val );
}
}
else if( !strcmp( psz_cmd, "mosaic-cols" ) )
if( strlen( newval.psz_string ) > 0)
{
val.i_int = atoi( newval.psz_string );
- var_Set( p_inp->p_libvlc, "mosaic-cols", val );
+ var_Set( p_input->p_libvlc, "mosaic-cols", val );
}
}
else if( !strcmp( psz_cmd, "mosaic-keep-aspect-ratio" ) )
if( strlen( newval.psz_string ) > 0)
{
val.i_int = atoi( newval.psz_string );
- var_Set( p_inp->p_libvlc, "mosaic-keep-aspect-ratio", val );
+ var_Set( p_input->p_libvlc, "mosaic-keep-aspect-ratio", val );
}
}
else if( !strcmp( psz_cmd, "time-format" ) )
if( strlen( newval.psz_string ) > 0 )
{
val.psz_string = newval.psz_string;
- var_Set( p_inp->p_libvlc, "time-format", val );
+ var_Set( p_input->p_libvlc, "time-format", val );
}
else
{
- val.psz_string = "";
- var_Set( p_inp->p_libvlc, "time-format", val);
+ val.psz_string = "";
+ var_Set( p_input->p_libvlc, "time-format", val);
}
}
else if( !strcmp( psz_cmd, "time-x" ) )
if( strlen( newval.psz_string ) > 0)
{
val.i_int = atoi( newval.psz_string );
- var_Set( p_inp->p_libvlc, "time-x", val );
+ var_Set( p_input->p_libvlc, "time-x", val );
}
}
else if( !strcmp( psz_cmd, "time-y" ) )
if( strlen( newval.psz_string ) > 0)
{
val.i_int = atoi( newval.psz_string );
- var_Set( p_inp->p_libvlc, "time-y", val );
+ var_Set( p_input->p_libvlc, "time-y", val );
}
}
else if( !strcmp( psz_cmd, "time-position" ) )
if( strlen( newval.psz_string ) > 0)
{
val.i_int = atoi( newval.psz_string );
- var_Set( p_inp->p_libvlc, "time-position", val );
+ var_Set( p_input->p_libvlc, "time-position", val );
}
}
else if( !strcmp( psz_cmd, "time-color" ) )
if( strlen( newval.psz_string ) > 0)
{
val.i_int = strtol( newval.psz_string, NULL, 0 );
- var_Set( p_inp->p_libvlc, "time-color", val );
+ var_Set( p_input->p_libvlc, "time-color", val );
}
}
else if( !strcmp( psz_cmd, "time-opacity" ) )
if( strlen( newval.psz_string ) > 0)
{
val.i_int = strtol( newval.psz_string, NULL, 0 );
- var_Set( p_inp->p_libvlc, "time-opacity", val );
+ var_Set( p_input->p_libvlc, "time-opacity", val );
}
}
else if( !strcmp( psz_cmd, "time-size" ) )
if( strlen( newval.psz_string ) > 0)
{
val.i_int = atoi( newval.psz_string );
- var_Set( p_inp->p_libvlc, "time-size", val );
+ var_Set( p_input->p_libvlc, "time-size", val );
}
}
else if( !strcmp( psz_cmd, "logo-file" ) )
if( strlen( newval.psz_string ) > 0 )
{
val.psz_string = newval.psz_string;
- var_Set( p_inp->p_libvlc, "logo-file", val );
+ var_Set( p_input->p_libvlc, "logo-file", val );
}
}
else if( !strcmp( psz_cmd, "logo-x" ) )
if( strlen( newval.psz_string ) > 0)
{
val.i_int = atoi( newval.psz_string );
- var_Set( p_inp->p_libvlc, "logo-x", val );
+ var_Set( p_input->p_libvlc, "logo-x", val );
}
}
else if( !strcmp( psz_cmd, "logo-y" ) )
if( strlen( newval.psz_string ) > 0)
{
val.i_int = atoi( newval.psz_string );
- var_Set( p_inp->p_libvlc, "logo-y", val );
+ var_Set( p_input->p_libvlc, "logo-y", val );
}
}
else if( !strcmp( psz_cmd, "logo-position" ) )
if( strlen( newval.psz_string ) > 0)
{
val.i_int = atoi( newval.psz_string );
- var_Set( p_inp->p_libvlc, "logo-position", val );
+ var_Set( p_input->p_libvlc, "logo-position", val );
}
}
else if( !strcmp( psz_cmd, "logo-transparency" ) )
if( strlen( newval.psz_string ) > 0)
{
val.i_int = strtol( newval.psz_string, NULL, 0 );
- var_Set( p_inp->p_libvlc, "logo-transparency", val );
+ var_Set( p_input->p_libvlc, "logo-transparency", val );
}
}
msg_rc( "unknown command!\n" );
}
- vlc_object_release( p_pl );
- vlc_object_release( p_inp );
+ vlc_object_release( p_playlist );
+ vlc_object_release( p_input );
return VLC_SUCCESS;
}
static int Quit( vlc_object_t *p_this, char const *psz_cmd,
vlc_value_t oldval, vlc_value_t newval, void *p_data )
{
+ playlist_t *p_playlist;
+
+ p_playlist = vlc_object_find( p_this, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
+ if( p_playlist )
+ {
+ playlist_Stop( p_playlist );
+ vlc_object_release( p_playlist );
+ }
p_this->p_vlc->b_die = VLC_TRUE;
return VLC_SUCCESS;
}
{
/* Set. */
audio_volume_t i_volume = atoi( newval.psz_string );
- if ( i_volume > AOUT_VOLUME_MAX )
+ if ( (i_volume > (audio_volume_t)AOUT_VOLUME_MAX) )
{
msg_rc( "Volume must be in the range %d-%d\n", AOUT_VOLUME_MIN,
AOUT_VOLUME_MAX );
i_error = VLC_EBADVAR;
}
- else i_error = aout_VolumeSet( p_this, i_volume );
+ else
+ {
+ if( i_volume == AOUT_VOLUME_MIN )
+ {
+ vlc_value_t keyval;
+
+ keyval.i_int = config_GetInt( p_intf, "key-vol-mute" );
+ var_Set( p_intf->p_vlc, "key-pressed", keyval );
+ }
+ i_error = aout_VolumeSet( p_this, i_volume );
+ }
}
else
{
}
else
{
- msg_rc( "Volume is %d\n", i_volume );
+ msg_rc( STATUS_CHANGE "( audio volume: %d )\r\n", i_volume );
i_error = VLC_SUCCESS;
}
}
{
if ( aout_VolumeUp( p_this, i_nb_steps, &i_volume ) < 0 )
i_error = VLC_EGENERIC;
+ osd_VolumeUp( p_this );
}
else
{
if ( aout_VolumeDown( p_this, i_nb_steps, &i_volume ) < 0 )
i_error = VLC_EGENERIC;
+ osd_VolumeDown( p_this );
}
- if ( !i_error ) msg_rc( "Volume is %d\n", i_volume );
+ if ( !i_error ) msg_rc( STATUS_CHANGE "( audio volume: %d )\r\n", i_volume );
return i_error;
}
return i_error;
}
+/* OSD menu commands */
+static int Menu( vlc_object_t *p_this, char const *psz_cmd,
+ vlc_value_t oldval, vlc_value_t newval, void *p_data )
+{
+ intf_thread_t *p_intf = (intf_thread_t*)p_this;
+ playlist_t *p_playlist = NULL;
+ vlc_value_t val;
+ int i_error = VLC_EGENERIC;
+
+ if ( !*newval.psz_string )
+ {
+ msg_rc( "please provide one of the following paramaters\r\n[on|off|up|down|left|right|select]\r\n" );
+ return i_error;
+ }
+
+ p_playlist = vlc_object_find( p_this, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
+ if( !p_playlist )
+ return VLC_ENOOBJ;
+
+ if( p_playlist->p_input )
+ {
+ var_Get( p_playlist->p_input, "state", &val );
+ if( ( ( val.i_int == PAUSE_S ) || ( val.i_int == PLAYLIST_PAUSED ) ) &&
+ ( strcmp( newval.psz_string, "select" ) != 0 ) )
+ {
+ msg_rc( _("press menu select to continue\r\n") );
+ vlc_object_release( p_playlist );
+ return VLC_EGENERIC;
+ }
+ vlc_object_release( p_playlist );
+ }
+
+ val.psz_string = strdup( newval.psz_string );
+ if( !strcmp( val.psz_string, "on" ) || !strcmp( val.psz_string, "show" ))
+ osd_MenuShow( p_this );
+ else if( !strcmp( val.psz_string, "off" ) || !strcmp( val.psz_string, "hide" ) )
+ osd_MenuHide( p_this );
+ else if( !strcmp( val.psz_string, "up" ) )
+ osd_MenuUp( p_this );
+ else if( !strcmp( val.psz_string, "down" ) )
+ osd_MenuDown( p_this );
+ else if( !strcmp( val.psz_string, "left" ) )
+ osd_MenuPrev( p_this );
+ else if( !strcmp( val.psz_string, "right" ) )
+ osd_MenuNext( p_this );
+ else if( !strcmp( val.psz_string, "select" ) )
+ osd_MenuActivate( p_this );
+ else
+ {
+ msg_rc( "please provide one of the following paramaters\r\n[on|off|up|down|left|right|select]\r\n" );
+ if( val.psz_string ) free( val.psz_string );
+ return i_error;
+ }
+
+ i_error = VLC_SUCCESS;
+ if( val.psz_string ) free( val.psz_string );
+ return i_error;
+}
+
#ifdef WIN32
vlc_bool_t ReadWin32( intf_thread_t *p_intf, char *p_buffer, int *pi_size )
{
*
* Authors: Laurent Aimar <fenrir@via.ecp.fr>
* Gildas Bazin <gbazin@videolan.org>
+ * Jean-Paul Saman <jpsaman #_at_# m2x dot nl>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
static int transcode_spu_process( sout_stream_t *, sout_stream_id_t *,
block_t *, block_t ** );
+static int transcode_osd_new ( sout_stream_t *, sout_stream_id_t * );
+static void transcode_osd_close ( sout_stream_t *, sout_stream_id_t * );
+static int transcode_osd_process( sout_stream_t *, sout_stream_id_t *,
+ block_t *, block_t ** );
+
static int EncoderThread( struct sout_stream_sys_t * p_sys );
static int pi_channels_maps[6] =
sout_cfg_t *p_spu_cfg;
spu_t *p_spu;
+ /* OSD Menu */
+ sout_stream_id_t *id_osd; /* extension for streaming OSD menus */
+ vlc_fourcc_t i_osdcodec; /* codec osd menu (0 if not transcode) */
+ char *psz_osdenc;
+ sout_cfg_t *p_osd_cfg;
+ vlc_bool_t b_osd; /* VLC_TRUE when osd es is registered */
+
/* Sync */
vlc_bool_t b_master_sync;
mtime_t i_master_drift;
if( p_sys->i_acodec )
{
+ if( (strncmp( (char *)&p_sys->i_acodec, "mp3", 3) == 0) &&
+ (p_sys->i_channels > 2) )
+ {
+ msg_Warn( p_stream, "%d channels invalid for mp3, forcing to 2",
+ p_sys->i_channels );
+ p_sys->i_channels = 2;
+ }
msg_Dbg( p_stream, "codec audio=%4.4s %dHz %d channels %dKb/s",
(char *)&p_sys->i_acodec, p_sys->i_sample_rate,
p_sys->i_channels, p_sys->i_abitrate / 1000 );
}
/* Subpictures transcoding parameters */
- p_sys->p_spu = 0;
+ p_sys->p_spu = NULL;
p_sys->psz_senc = NULL;
p_sys->p_spu_cfg = NULL;
p_sys->i_scodec = 0;
}
if( val.psz_string ) free( val.psz_string );
+ /* OSD menu transcoding parameters */
+ p_sys->psz_osdenc = NULL;
+ p_sys->p_osd_cfg = NULL;
+ p_sys->i_osdcodec = 0;
+ p_sys->b_osd = VLC_FALSE;
+ if( config_GetInt( p_stream, "osd" ) )
+ {
+/* vlc_value_t val;*/
+ char *psz_next;
+
+ psz_next = sout_CfgCreate( &p_sys->psz_osdenc,
+ &p_sys->p_osd_cfg, strdup( "dvbsub") );
+ if( psz_next ) free( psz_next );
+
+ p_sys->i_osdcodec = VLC_FOURCC('Y','U','V','P' );
+
+ msg_Dbg( p_stream, "codec osd=%4.4s", (char *)&p_sys->i_osdcodec );
+
+/* val.psz_string = strdup("osdmenu");
+ if( !p_sys->p_spu )
+ {
+ p_sys->p_spu = spu_Create( p_stream );
+ var_Create( p_sys->p_spu, "sub-filter", VLC_VAR_STRING );
+ spu_Init( p_sys->p_spu );
+ }
+ var_Set( p_sys->p_spu, "sub-filter", val );
+ if( val.psz_string ) free( val.psz_string );*/
+ }
+
+ /* Audio settings */
var_Get( p_stream, SOUT_CFG_PREFIX "audio-sync", &val );
p_sys->b_master_sync = val.b_bool;
if( p_sys->f_fps > 0 ) p_sys->b_master_sync = VLC_TRUE;
if( p_sys->psz_senc ) free( p_sys->psz_senc );
if( p_sys->p_spu ) spu_Destroy( p_sys->p_spu );
+
+ while( p_sys->p_osd_cfg != NULL )
+ {
+ sout_cfg_t *p_next = p_sys->p_osd_cfg->p_next;
+
+ if( p_sys->p_osd_cfg->psz_name )
+ free( p_sys->p_osd_cfg->psz_name );
+ if( p_sys->p_osd_cfg->psz_value )
+ free( p_sys->p_osd_cfg->psz_value );
+ free( p_sys->p_osd_cfg );
+
+ p_sys->p_osd_cfg = p_next;
+ }
+ if( p_sys->psz_osdenc ) free( p_sys->psz_osdenc );
vlc_object_destroy( p_sys );
}
date_t interpolated_pts;
};
-
static sout_stream_id_t *Add( sout_stream_t *p_stream, es_format_t *p_fmt )
{
sout_stream_sys_t *p_sys = p_stream->p_sys;
if( !id->id ) goto error;
}
+ if( config_GetInt( p_stream, "osd" ) )
+ {
+ /* Create a fake OSD menu elementary stream */
+ if( !p_sys->b_osd && (p_sys->i_osdcodec != 0 || p_sys->psz_osdenc) )
+ {
+ if( transcode_osd_new( p_stream, p_sys->id_osd ) )
+ {
+ msg_Err( p_stream, "cannot create osd chain" );
+ goto error;
+ }
+ p_sys->b_osd = VLC_TRUE;
+ }
+ }
return id;
error:
{
sout_stream_sys_t *p_sys = p_stream->p_sys;
+ if( config_GetInt( p_stream, "osd" ) && p_sys->b_osd )
+ transcode_osd_close( p_stream, p_sys->id_osd );
+
if( id->b_transcode )
{
switch( id->p_decoder->fmt_in.i_cat )
block_t *p_buffer )
{
sout_stream_sys_t *p_sys = p_stream->p_sys;
- block_t *p_out;
+ block_t *p_out = NULL;
if( !id->b_transcode && id->id )
{
+ /* Transcode OSD menu pictures. */
+ if( p_sys->b_osd )
+ {
+ transcode_osd_process( p_stream, id, p_buffer, &p_out );
+ }
return p_sys->p_out->pf_send( p_sys->p_out, id->id, p_buffer );
}
else if( !id->b_transcode )
id->p_decoder->pf_decode_audio = 0;
id->p_decoder->pf_aout_buffer_new = audio_new_buffer;
id->p_decoder->pf_aout_buffer_del = audio_del_buffer;
- //id->p_decoder->p_cfg = p_sys->p_video_cfg;
+ /* id->p_decoder->p_cfg = p_sys->p_audio_cfg; */
id->p_decoder->p_module =
module_Need( id->p_decoder, "decoder", "$codec", 0 );
for( i = 0; i < PICTURE_RING_SIZE; i++ )
id->p_decoder->p_owner->pp_pics[i] = 0;
id->p_decoder->p_owner->p_sys = p_sys;
- //id->p_decoder->p_cfg = p_sys->p_video_cfg;
+ /* id->p_decoder->p_cfg = p_sys->p_video_cfg; */
id->p_decoder->p_module =
module_Need( id->p_decoder, "decoder", "$codec", 0 );
id->p_decoder->pf_spu_buffer_new = spu_new_buffer;
id->p_decoder->pf_spu_buffer_del = spu_del_buffer;
id->p_decoder->p_owner = (decoder_owner_sys_t *)p_stream;
- //id->p_decoder->p_cfg = p_sys->p_spu_cfg;
+ /* id->p_decoder->p_cfg = p_sys->p_spu_cfg; */
id->p_decoder->p_module =
module_Need( id->p_decoder, "decoder", "$codec", 0 );
sout_stream_t *p_stream = (sout_stream_t *)p_dec->p_owner;
spu_DestroySubpicture( p_stream->p_sys->p_spu, p_subpic );
}
+
+/*
+ * OSD menu
+ */
+static int transcode_osd_new( sout_stream_t *p_stream, sout_stream_id_t *id )
+{
+ sout_stream_sys_t *p_sys = p_stream->p_sys;
+ es_format_t fmt;
+
+ fmt.i_cat = SPU_ES;
+ fmt.i_id = 0xbd1f; /* pid ?? */
+ fmt.i_group = 3; /* pmt entry ?? */
+ fmt.i_codec = VLC_FOURCC( 'Y', 'U', 'V', 'A' );
+ fmt.psz_language = strdup( "osd" );
+
+ id = malloc( sizeof( sout_stream_id_t ) );
+ memset( id, 0, sizeof(sout_stream_id_t) );
+
+ id->id = NULL;
+ id->p_decoder = NULL;
+ id->p_encoder = NULL;
+
+ /* Create encoder object */
+ id->p_encoder = vlc_object_create( p_stream, VLC_OBJECT_ENCODER );
+ if( !id->p_encoder )
+ {
+ msg_Err( p_stream, "out of memory" );
+ goto error;
+ }
+ vlc_object_attach( id->p_encoder, p_stream );
+ id->p_encoder->p_module = NULL;
+
+ /* Create fake destination format */
+ es_format_Init( &id->p_encoder->fmt_out, fmt.i_cat, 0 );
+ id->p_encoder->fmt_out.i_id = fmt.i_id;
+ id->p_encoder->fmt_out.i_group = fmt.i_group;
+ id->p_encoder->fmt_out.psz_language = strdup( fmt.psz_language );
+
+ if( p_sys->i_osdcodec != 0 || p_sys->psz_osdenc )
+ {
+ msg_Dbg( p_stream, "creating osdmenu transcoding from fcc=`%4.4s' "
+ "to fcc=`%4.4s'", (char*)&fmt.i_codec,
+ (char*)&p_sys->i_osdcodec );
+
+ /* Complete destination format */
+ id->p_encoder->fmt_out.i_codec = p_sys->i_osdcodec;
+
+ /*
+ * Open encoder
+ */
+
+ /* Initialization of encoder format structures */
+ es_format_Init( &id->p_encoder->fmt_in, fmt.i_cat, fmt.i_codec );
+ id->p_encoder->fmt_in.psz_language = strdup( fmt.psz_language );
+
+ id->p_encoder->p_cfg = p_sys->p_osd_cfg;
+
+ id->p_encoder->p_module =
+ module_Need( id->p_encoder, "encoder", p_sys->psz_osdenc, VLC_TRUE );
+
+ if( !id->p_encoder->p_module )
+ {
+ msg_Err( p_stream, "cannot find encoder" );
+ goto error;
+ }
+
+ /* open output stream */
+ id->id = p_sys->p_out->pf_add( p_sys->p_out, &id->p_encoder->fmt_out );
+ id->b_transcode = VLC_TRUE;
+
+ if( !id->id ) goto error;
+ }
+ else
+ {
+ msg_Dbg( p_stream, "not transcoding a stream (fcc=`%4.4s')",
+ (char*)&fmt.i_codec );
+ id->id = p_sys->p_out->pf_add( p_sys->p_out, &fmt );
+ id->b_transcode = VLC_FALSE;
+
+ if( !id->id ) goto error;
+ }
+
+ p_sys->id_osd = id;
+ p_sys->b_osd = VLC_TRUE;
+
+ if( !p_sys->p_spu )
+ {
+ p_sys->p_spu = spu_Create( p_stream );
+ if( spu_Init( p_sys->p_spu ) != VLC_SUCCESS )
+ msg_Err( p_sys, "spu initialisation failed" );
+ }
+
+ if( fmt.psz_language )
+ free( fmt.psz_language );
+
+ return VLC_SUCCESS;
+
+ error:
+ msg_Err( p_stream, "starting osd encoding thread failed" );
+ if( id->p_encoder->p_module )
+ module_Unneed( id->p_encoder, id->p_encoder->p_module );
+ if( id->p_encoder )
+ {
+ vlc_object_detach( id->p_encoder );
+ vlc_object_destroy( id->p_encoder );
+ }
+ if( fmt.psz_language ) free( fmt.psz_language );
+ if( id ) free( id );
+ p_sys->id_osd = NULL;
+ p_sys->b_osd = VLC_FALSE;
+ return VLC_EGENERIC;
+}
+
+static void transcode_osd_close( sout_stream_t *p_stream, sout_stream_id_t *id)
+{
+ sout_stream_sys_t *p_sys = p_stream->p_sys;
+
+ /* Close encoder */
+ if( p_sys->b_osd && id )
+ {
+ if( id->p_encoder->p_module )
+ module_Unneed( id->p_encoder, id->p_encoder->p_module );
+
+ if( id->id ) p_sys->p_out->pf_del( p_sys->p_out, id->id );
+
+ if( id->p_encoder )
+ {
+ vlc_object_detach( id->p_encoder );
+ vlc_object_destroy( id->p_encoder );
+ }
+ }
+ p_sys->b_osd = VLC_FALSE;
+ if( id ) free( id );
+}
+
+static int transcode_osd_process( sout_stream_t *p_stream,
+ sout_stream_id_t *id,
+ block_t *in, block_t **out )
+{
+ sout_stream_sys_t *p_sys = p_stream->p_sys;
+ subpicture_t *p_subpic = NULL;
+
+ /* Check if we have a subpicture to send */
+ if( p_sys->p_spu && in->i_dts > 0)
+ {
+ p_subpic = spu_SortSubpictures( p_sys->p_spu, in->i_dts );
+ }
+ else
+ {
+ msg_Warn( p_stream, "spu channel not initialized, doing it now" );
+ if( !p_sys->p_spu )
+ {
+ p_sys->p_spu = spu_Create( p_stream );
+ if( spu_Init( p_sys->p_spu ) != VLC_SUCCESS )
+ msg_Err( p_stream, "spu initialisation failed" );
+ }
+ }
+
+ if( p_subpic )
+ {
+ block_t *p_block = NULL;
+
+ if( p_sys->b_master_sync && p_sys->i_master_drift )
+ {
+ p_subpic->i_start -= p_sys->i_master_drift;
+ if( p_subpic->i_stop ) p_subpic->i_stop -= p_sys->i_master_drift;
+ }
+
+ p_block = p_sys->id_osd->p_encoder->pf_encode_sub( p_sys->id_osd->p_encoder, p_subpic );
+ if( p_block )
+ {
+ p_block->i_dts = p_block->i_pts = in->i_dts;
+ block_ChainAppend( out, p_block );
+ if( *out )
+ {
+ if( p_sys->p_out->pf_send( p_sys->p_out, p_sys->id_osd->id, *out ) == VLC_SUCCESS )
+ spu_DestroySubpicture( p_sys->p_spu, p_subpic );
+ }
+ return VLC_SUCCESS;
+ }
+ }
+ return VLC_EGENERIC;
+}
SOURCES_rss = rss.c
SOURCES_motiondetect = motiondetect.c
SOURCES_rv32 = rv32.c
+SOURCES_osdmenu = osdmenu.c
noinst_HEADERS += filter_common.h
--- /dev/null
+/*****************************************************************************
+ * osdmenu.c: osd filter module
+ *****************************************************************************
+ * Copyright (C) 2004-2005 M2X
+ * $Id: osdmenu.c 11131 2005-05-23 11:04:07Z hartman $
+ *
+ * Authors: Jean-Paul Saman <jpsaman #_at_# m2x dot nl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implid warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Preamble
+ *****************************************************************************/
+#include <stdlib.h>
+#include <string.h>
+#include <vlc/vlc.h>
+#include <vlc/input.h>
+
+#include <vlc_filter.h>
+#include <vlc_video.h>
+
+#include <osd.h>
+#include <vlc_osd.h>
+
+/*****************************************************************************
+ * Module descriptor
+ *****************************************************************************/
+
+/* FIXME: Future extension make the definition file in XML format. */
+#define OSD_FILE_TEXT N_("OSD menu configuration file")
+#define OSD_FILE_LONGTEXT N_( \
+ "An OSD menu configuration file that menu actions with button images" )
+
+#define OSD_PATH_TEXT N_("Path to OSD menu images")
+#define OSD_PATH_LONGTEXT N_( \
+ "Specify another path to the OSD menu images. This will override the path as defined in the " \
+ "OSD configuration file." )
+
+#define POSX_TEXT N_("X coordinate of the OSD menu")
+#define POSX_LONGTEXT N_("You can move the OSD menu by left-clicking on it." )
+
+#define POSY_TEXT N_("Y coordinate of the OSD menu")
+#define POSY_LONGTEXT N_("You can move the OSD menu by left-clicking on it." )
+
+#define POS_TEXT N_("OSD menu position")
+#define POS_LONGTEXT N_( \
+ "You can enforce the OSD menu position on the video " \
+ "(0=center, 1=left, 2=right, 4=top, 8=bottom, you can " \
+ "also use combinations of these values).")
+
+#define TIMEOUT_TEXT N_("Timeout of OSD menu")
+#define TIMEOUT_LONGTEXT N_( \
+ "OSD menu pictures get a default timeout of 15 seconds added to their remaining time." \
+ "This will ensure that they are at least the specified time visible.")
+
+static int pi_pos_values[] = { 0, 1, 2, 4, 8, 5, 6, 9, 10 };
+static char *ppsz_pos_descriptions[] =
+{ N_("Center"), N_("Left"), N_("Right"), N_("Top"), N_("Bottom"),
+ N_("Top-Left"), N_("Top-Right"), N_("Bottom-Left"), N_("Bottom-Right") };
+
+/* subfilter functions */
+static int CreateFilter ( vlc_object_t * );
+static void DestroyFilter( vlc_object_t * );
+static subpicture_t *Filter( filter_t *, mtime_t );
+static int OSDMenuUpdateEvent( vlc_object_t *, char const *,
+ vlc_value_t, vlc_value_t, void * );
+static int OSDMenuVisibleEvent( vlc_object_t *, char const *,
+ vlc_value_t, vlc_value_t, void * );
+
+#define OSD_CFG "osdmenu-"
+
+vlc_module_begin();
+ add_integer( OSD_CFG "x", -1, NULL, POSX_TEXT, POSX_LONGTEXT, VLC_FALSE );
+ add_integer( OSD_CFG "y", -1, NULL, POSY_TEXT, POSY_LONGTEXT, VLC_FALSE );
+ add_integer( OSD_CFG "position", 8, NULL, POS_TEXT, POS_LONGTEXT, VLC_FALSE );
+ change_integer_list( pi_pos_values, ppsz_pos_descriptions, 0 );
+ add_string( OSD_CFG "file", NULL, NULL, OSD_FILE_TEXT, OSD_FILE_LONGTEXT, VLC_FALSE );
+ add_string( OSD_CFG "file-path", NULL, NULL, OSD_PATH_TEXT, OSD_PATH_LONGTEXT, VLC_FALSE );
+ add_integer( OSD_CFG "timeout", 0, NULL, TIMEOUT_TEXT, TIMEOUT_LONGTEXT, VLC_FALSE );
+
+ set_capability( "sub filter", 100 );
+ set_description( N_("On Screen Display menu subfilter") );
+ set_shortname( N_("OSD menu") );
+ add_shortcut( "osdmenu" );
+ set_category( CAT_VIDEO );
+ set_subcategory( SUBCAT_VIDEO_SUBPIC );
+ set_callbacks( CreateFilter, DestroyFilter );
+vlc_module_end();
+
+/*****************************************************************************
+ * Sub filter code
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Local prototypes
+ *****************************************************************************/
+struct filter_sys_t
+{
+ vlc_mutex_t lock;
+
+ int position; /* relative positioning of SPU images */
+ mtime_t i_last_date; /* last mdate SPU object has been sent to SPU subsytem */
+ int i_timeout; /* duration SPU object is valid on the video output in seconds */
+
+ vlc_bool_t b_absolute; /* do we use absolute positioning or relative? */
+ vlc_bool_t b_update; /* Update OSD Menu by sending SPU objects */
+ vlc_bool_t b_visible; /* OSD Menu is visible */
+
+ char *psz_file; /* OSD Menu configuration file */
+ osd_menu_t *p_menu; /* pointer to OSD Menu object */
+};
+
+/*****************************************************************************
+ * CreateFilter: Create the filter and open the definition file
+ *****************************************************************************/
+static int CreateFilter ( vlc_object_t *p_this )
+{
+ filter_t *p_filter = (filter_t *)p_this;
+ vlc_value_t val;
+ int posx, posy;
+
+ p_filter->p_sys = (filter_sys_t *) malloc( sizeof( filter_sys_t ) );
+ if( !p_filter->p_sys )
+ {
+ msg_Err( p_filter, "out of memory" );
+ return VLC_ENOMEM;
+ }
+
+ /* Populating struct */
+ p_filter->p_sys->p_menu = NULL;
+ p_filter->p_sys->psz_file = NULL;
+
+ vlc_mutex_init( p_filter, &p_filter->p_sys->lock );
+
+ p_filter->p_sys->psz_file = config_GetPsz( p_filter, OSD_CFG "file" );
+ if( p_filter->p_sys->psz_file == NULL || *p_filter->p_sys->psz_file == '\0' )
+ {
+ msg_Err( p_filter, "unable to get filename" );
+ goto error;
+ }
+
+ var_Create( p_this, OSD_CFG "position", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
+ var_Get( p_this, OSD_CFG "position", &val );
+ p_filter->p_sys->position = val.i_int;
+ var_Create( p_this, OSD_CFG "x", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
+ var_Get( p_this, OSD_CFG "x", &val );
+ posx = val.i_int;
+ var_Create( p_this, OSD_CFG "y", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
+ var_Get( p_this, OSD_CFG "y", &val );
+ posy = val.i_int;
+ var_Create( p_this, OSD_CFG "timeout", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
+ var_Get( p_this, OSD_CFG "timeout", &val );
+ p_filter->p_sys->i_timeout = val.i_int; /* in seconds */
+
+ /* Load the osd menu subsystem */
+ p_filter->p_sys->p_menu = osd_MenuCreate( p_this, p_filter->p_sys->psz_file );
+ if( p_filter->p_sys->p_menu == NULL )
+ goto error;
+
+ /* Check if menu position was overridden */
+ p_filter->p_sys->b_absolute = VLC_TRUE;
+
+ if( posx < 0 || posy < 0)
+ {
+ p_filter->p_sys->b_absolute = VLC_FALSE;
+ p_filter->p_sys->p_menu->i_x = 0;
+ p_filter->p_sys->p_menu->i_y = 0;
+ }
+ else if( posx >= 0 || posy >= 0 )
+ {
+ p_filter->p_sys->p_menu->i_x = posx;
+ p_filter->p_sys->p_menu->i_y = posy;
+ }
+ else if( p_filter->p_sys->p_menu->i_x < 0 || p_filter->p_sys->p_menu->i_y < 0 )
+ {
+ p_filter->p_sys->b_absolute = VLC_FALSE;
+ p_filter->p_sys->p_menu->i_x = 0;
+ p_filter->p_sys->p_menu->i_y = 0;
+ }
+
+ /* Set up p_filter */
+ p_filter->p_sys->i_last_date = mdate();
+
+ /* Keep track of OSD Events */
+ p_filter->p_sys->b_update = VLC_FALSE;
+ p_filter->p_sys->b_visible = VLC_FALSE;
+
+ var_AddCallback( p_filter->p_sys->p_menu, "osd-menu-update", OSDMenuUpdateEvent, p_filter );
+ var_AddCallback( p_filter->p_sys->p_menu, "osd-menu-visible", OSDMenuVisibleEvent, p_filter );
+
+ /* Attach subpicture filter callback */
+ p_filter->pf_sub_filter = Filter;
+
+ es_format_Init( &p_filter->fmt_out, SPU_ES, VLC_FOURCC( 's','p','u',' ' ) );
+ p_filter->fmt_out.i_priority = 0;
+
+ msg_Dbg( p_filter, "successfully loaded osdmenu filter" );
+ return VLC_SUCCESS;
+
+error:
+ msg_Err( p_filter, "osdmenu filter discarded" );
+ vlc_mutex_destroy( &p_filter->p_sys->lock );
+ if( p_filter->p_sys->p_menu )
+ {
+ osd_MenuDelete( p_this, p_filter->p_sys->p_menu );
+ p_filter->p_sys->p_menu = NULL;
+ }
+ if( p_filter->p_sys->psz_file ) free( p_filter->p_sys->psz_file );
+ if( p_filter->p_sys ) free( p_filter->p_sys );
+ return VLC_EGENERIC;
+}
+
+/*****************************************************************************
+ * DestroyFilter: Make a clean exit of this plugin
+ *****************************************************************************/
+static void DestroyFilter( vlc_object_t *p_this )
+{
+ filter_t *p_filter = (filter_t*)p_this;
+ filter_sys_t *p_sys = p_filter->p_sys;
+
+ var_Destroy( p_this, OSD_CFG "file" );
+ var_Destroy( p_this, OSD_CFG "x" );
+ var_Destroy( p_this, OSD_CFG "y" );
+ var_Destroy( p_this, OSD_CFG "position" );
+ var_Destroy( p_this, OSD_CFG "timeout" );
+
+ var_DelCallback( p_sys->p_menu, "osd-menu-update", OSDMenuUpdateEvent, p_filter );
+ var_DelCallback( p_sys->p_menu, "osd-menu-visible", OSDMenuVisibleEvent, p_filter );
+
+ osd_MenuDelete( p_filter, p_sys->p_menu );
+
+ vlc_mutex_destroy( &p_filter->p_sys->lock );
+ if( p_sys->psz_file) free( p_sys->psz_file );
+ if( p_sys ) free( p_sys );
+
+ msg_Dbg( p_filter, "osdmenu filter destroyed" );
+}
+
+/*****************************************************************************
+ * OSDMenuEvent: callback for OSD Menu events
+ *****************************************************************************/
+static int OSDMenuVisibleEvent( vlc_object_t *p_this, char const *psz_var,
+ vlc_value_t oldval, vlc_value_t newval, void *p_data )
+{
+ filter_t *p_filter = (filter_t *) p_data;
+
+ p_filter->p_sys->b_visible = VLC_TRUE;
+ return VLC_SUCCESS;
+}
+
+static int OSDMenuUpdateEvent( vlc_object_t *p_this, char const *psz_var,
+ vlc_value_t oldval, vlc_value_t newval, void *p_data )
+{
+ filter_t *p_filter = (filter_t *) p_data;
+
+ p_filter->p_sys->b_update = VLC_TRUE;
+ return VLC_SUCCESS;
+}
+
+#if 0
+/*****************************************************************************
+ * create_text_region : compose a text region SPU
+ *****************************************************************************/
+static subpicture_region_t *create_text_region( filter_t *p_filter, subpicture_t *p_spu,
+ int i_width, int i_height, const char *psz_text )
+{
+ subpicture_region_t *p_region;
+ video_format_t fmt;
+
+ /* Create new SPU region */
+ memset( &fmt, 0, sizeof(video_format_t) );
+ fmt.i_chroma = VLC_FOURCC( 'T','E','X','T' );
+ fmt.i_aspect = VOUT_ASPECT_FACTOR;
+ fmt.i_sar_num = fmt.i_sar_den = 1;
+ fmt.i_width = fmt.i_visible_width = i_width;
+ fmt.i_height = fmt.i_visible_height = i_height;
+ fmt.i_x_offset = fmt.i_y_offset = 0;
+ p_region = p_spu->pf_create_region( VLC_OBJECT(p_filter), &fmt );
+ if( !p_region )
+ {
+ msg_Err( p_filter, "cannot allocate another SPU region" );
+ return NULL;
+ }
+ p_region->psz_text = strdup( psz_text );
+ p_region->i_x = 0;
+ p_region->i_y = 40;
+#if 1
+ msg_Dbg( p_filter, "SPU text region position (%d,%d) (%d,%d) [%s]",
+ p_region->i_x, p_region->i_y,
+ p_region->fmt.i_width, p_region->fmt.i_height, p_region->psz_text );
+#endif
+ return p_region;
+}
+#endif
+
+/*****************************************************************************
+ * create_picture_region : compose a text region SPU
+ *****************************************************************************/
+static subpicture_region_t *create_picture_region( filter_t *p_filter, subpicture_t *p_spu,
+ int i_width, int i_height, picture_t *p_pic )
+{
+ subpicture_region_t *p_region;
+ video_format_t fmt;
+
+ /* Create new SPU region */
+ memset( &fmt, 0, sizeof(video_format_t) );
+ fmt.i_chroma = VLC_FOURCC('Y','U','V','A');
+ fmt.i_aspect = VOUT_ASPECT_FACTOR;
+ fmt.i_sar_num = fmt.i_sar_den = 1;
+ fmt.i_width = fmt.i_visible_width = i_width;
+ fmt.i_height = fmt.i_visible_height = i_height;
+ fmt.i_x_offset = fmt.i_y_offset = 0;
+ p_region = p_spu->pf_create_region( VLC_OBJECT(p_filter), &fmt );
+ if( !p_region )
+ {
+ msg_Err( p_filter, "cannot allocate SPU region" );
+ p_filter->pf_sub_buffer_del( p_filter, p_spu );
+ return NULL;
+ }
+ vout_CopyPicture( p_filter, &p_region->picture, p_pic );
+ p_region->i_x = 0;
+ p_region->i_y = 0;
+
+#if 0
+ msg_Dbg( p_filter, "SPU picture region position (%d,%d) (%d,%d) [%p]",
+ p_region->i_x, p_region->i_y,
+ p_region->fmt.i_width, p_region->fmt.i_height, p_pic );
+#endif
+ return p_region;
+}
+
+/****************************************************************************
+ * Filter: the whole thing
+ ****************************************************************************
+ * This function outputs subpictures at regular time intervals.
+ ****************************************************************************/
+static subpicture_t *Filter( filter_t *p_filter, mtime_t i_date )
+{
+ filter_sys_t *p_sys = p_filter->p_sys;
+ subpicture_t *p_spu;
+ subpicture_region_t *p_region;
+
+ if( !p_filter->p_sys->b_update ) return NULL;
+
+ p_filter->p_sys->i_last_date = i_date;
+ p_filter->p_sys->b_update = VLC_FALSE;
+
+ /* Allocate the subpicture internal data. */
+ p_spu = p_filter->pf_sub_buffer_new( p_filter );
+ if( !p_spu ) return NULL;
+
+ p_spu->b_absolute = p_sys->b_absolute;
+ p_spu->i_start = p_sys->i_last_date = i_date;
+ /* this never works why ? */
+ p_spu->i_stop = (p_sys->i_timeout == 0) ? 0 : i_date + (mtime_t)(p_sys->i_timeout * 1000000);
+ p_spu->b_ephemer = VLC_TRUE;
+ p_spu->b_fade = VLC_TRUE;
+ p_spu->i_flags = p_sys->position;
+ p_filter->p_sys->b_update = VLC_FALSE;
+
+ /* Send an empty subpicture to clear the display
+ * when OSD menu should be hidden and menu picture is not allocated.
+ */
+ if( !p_filter->p_sys->p_menu->p_state->p_pic )
+ return p_spu;
+ if( p_filter->p_sys->b_visible == VLC_FALSE )
+ return p_spu;
+
+ /* Create new spu regions */
+ p_region = create_picture_region( p_filter, p_spu,
+ p_filter->p_sys->p_menu->p_state->i_width, p_filter->p_sys->p_menu->p_state->i_height,
+ p_filter->p_sys->p_menu->p_state->p_pic );
+ #if 0
+ p_region->p_next = create_text_region( p_filter, p_spu,
+ p_filter->p_sys->p_menu->p_state->i_width, p_filter->p_sys->p_menu->p_state->i_height,
+ p_filter->p_sys->p_menu->p_state->p_visible->psz_action );
+ #endif
+
+ /* proper positioning of OSD menu image */
+ p_spu->i_x = p_filter->p_sys->p_menu->p_state->i_x;
+ p_spu->i_y = p_filter->p_sys->p_menu->p_state->i_y;
+
+ p_spu->p_region = p_region;
+ return p_spu;
+}
-DIST_SUBDIRS = interface playlist input audio_output video_output stream_output misc
+DIST_SUBDIRS = interface playlist input audio_output video_output stream_output misc osd
EXTRA_DIST = misc/modules_builtin.h.in
#include "vlc_vlm.h"
#include "vlc_image.h"
+#include "vlc_osd.h"
#if defined( _MSC_VER ) && defined( UNDER_CE )
# include "modules_builtin_evc.h"
#include "vlc_vod.h"
#include "vlc_tls.h"
#include "vlc_xml.h"
+#include "vlc_osd.h"
/*****************************************************************************
* Local prototypes
i_size = sizeof( announce_handler_t );
psz_type = "announce handler";
break;
+ case VLC_OBJECT_OSDMENU:
+ i_size = sizeof( osd_menu_t );
+ psz_type = "osd menu";
+ break;
default:
i_size = i_type > 0
? i_type > (int)sizeof(vlc_object_t)
--- /dev/null
+/*****************************************************************************\r
+ * osd.c - The OSD Menu core code.\r
+ *****************************************************************************\r
+ * Copyright (C) 2005 M2X\r
+ * $Id: osd.c 9451 2004-12-01 01:07:08Z jpsaman $\r
+ *\r
+ * Authors: Jean-Paul Saman <jpsaman #_at_# m2x dot nl>\r
+ *\r
+ * This program is free software; you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation; either version 2 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with this program; if not, write to the Free Software\r
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.\r
+ *****************************************************************************/\r
+\r
+/*****************************************************************************\r
+ * Preamble\r
+ *****************************************************************************/\r
+#include <stdlib.h>\r
+#include <string.h>\r
+\r
+#include <vlc/vlc.h>\r
+#include <vlc_keys.h>\r
+#include <vlc_osd.h>\r
+\r
+#undef OSD_MENU_DEBUG\r
+\r
+/*****************************************************************************\r
+ * Local prototypes\r
+ *****************************************************************************/\r
+\r
+static void osd_UpdateState( osd_menu_state_t *, int, int, int, int, picture_t * );\r
+static inline osd_state_t *osd_VolumeStateChange( osd_state_t *, int );\r
+\r
+osd_menu_t *__osd_MenuCreate( vlc_object_t *p_this, const char *psz_file )\r
+{\r
+ osd_menu_t *p_osd = NULL;\r
+ vlc_value_t lockval;\r
+ int i_volume = 0;\r
+ int i_steps = 0;\r
+\r
+ /* to be sure to avoid multiple creation */\r
+ var_Create( p_this->p_libvlc, "osd_mutex", VLC_VAR_MUTEX );\r
+ var_Get( p_this->p_libvlc, "osd_mutex", &lockval );\r
+ vlc_mutex_lock( lockval.p_address );\r
+ \r
+ if( ( p_osd = vlc_object_find( p_this, VLC_OBJECT_OSDMENU, FIND_ANYWHERE ) ) == NULL )\r
+ {\r
+ vlc_value_t val;\r
+ \r
+ msg_Dbg( p_this, "creating osd menu object" );\r
+ if( ( p_osd = vlc_object_create( p_this, VLC_OBJECT_OSDMENU ) ) == NULL )\r
+ {\r
+ msg_Err( p_this, "out of memory" );\r
+ vlc_mutex_unlock( lockval.p_address );\r
+ return NULL;\r
+ }\r
+\r
+ /* Parse configuration file */\r
+ if( osd_ConfigLoader( p_this, psz_file, &p_osd ) )\r
+ goto error;\r
+ \r
+ /* Setup default button (first button) */\r
+ p_osd->p_state->p_visible = p_osd->p_button;\r
+ p_osd->p_state->p_visible->p_current_state =\r
+ osd_StateChange( p_osd->p_state->p_visible->p_states, OSD_BUTTON_SELECT );\r
+ p_osd->i_width = p_osd->p_state->p_visible->p_current_state->p_pic->p[Y_PLANE].i_visible_pitch;\r
+ p_osd->i_height = p_osd->p_state->p_visible->p_current_state->p_pic->p[Y_PLANE].i_visible_lines;\r
+\r
+ /* Update the volume state images to match the current volume */\r
+ i_volume = config_GetInt( p_this, "volume" );\r
+ i_steps = (i_volume / AOUT_VOLUME_STEP / 3); /* 3 is a magic number for 32 volume decrease steps */\r
+ p_osd->p_state->p_volume->p_current_state = osd_VolumeStateChange( p_osd->p_state->p_volume->p_states, i_steps );\r
+\r
+ /* Initialize OSD state */\r
+ osd_UpdateState( p_osd->p_state, p_osd->i_x, p_osd->i_y,\r
+ p_osd->i_width, p_osd->i_height, NULL );\r
+ \r
+ vlc_object_yield( p_osd );\r
+ vlc_object_attach( p_osd, p_this->p_vlc );\r
+ \r
+ /* Signal when an update of OSD menu is needed */\r
+ var_Create( p_osd, "osd-menu-update", VLC_VAR_BOOL );\r
+ var_Create( p_osd, "osd-menu-visible", VLC_VAR_BOOL );\r
+\r
+ val.b_bool = VLC_FALSE;\r
+ var_Set( p_osd, "osd-menu-update", val );\r
+ var_Set( p_osd, "osd-menu-visible", val ); \r
+ }\r
+ vlc_mutex_unlock( lockval.p_address );\r
+ return p_osd;\r
+ \r
+error:\r
+ msg_Err( p_this, "creating osd menu object failed" );\r
+ vlc_mutex_unlock( lockval.p_address );\r
+ vlc_object_destroy( p_osd );\r
+ return NULL; \r
+}\r
+\r
+void __osd_MenuDelete( vlc_object_t *p_this, osd_menu_t *p_osd )\r
+{\r
+ vlc_value_t lockval;\r
+\r
+ if( !p_osd || !p_this ) return;\r
+ \r
+ var_Get( p_this->p_libvlc, "osd_mutex", &lockval );\r
+ vlc_mutex_lock( lockval.p_address );\r
+\r
+ vlc_object_release( p_osd ); \r
+ if( p_osd->i_refcount > 0 )\r
+ {\r
+ vlc_mutex_unlock( lockval.p_address ); \r
+ return;\r
+ } \r
+\r
+ var_Destroy( p_osd, "osd-menu-visible" );\r
+ var_Destroy( p_osd, "osd-menu-update" );\r
+ \r
+ osd_ConfigUnload( p_this, &p_osd );\r
+ vlc_object_detach( p_osd );\r
+ vlc_object_destroy( p_osd );\r
+ p_osd = NULL;\r
+ \r
+ vlc_mutex_unlock( lockval.p_address ); \r
+}\r
+\r
+osd_state_t *__osd_StateChange( osd_state_t *p_states, const int i_state )\r
+{\r
+ osd_state_t *p_current = p_states;\r
+ osd_state_t *p_temp = NULL;\r
+ int i = 0;\r
+\r
+ for( i=0; p_current != NULL; i++ )\r
+ {\r
+ if( p_current->i_state == i_state )\r
+ return p_current;\r
+ p_temp = p_current->p_next;\r
+ p_current = p_temp;\r
+ }\r
+ return p_states;\r
+}\r
+\r
+/* The volume can be modified in another interface while the OSD Menu \r
+ * has not been instantiated yet. This routines updates the "volume OSD menu item"\r
+ * to reflect the current state of the GUI.\r
+ */\r
+static inline osd_state_t *osd_VolumeStateChange( osd_state_t *p_current, int i_steps )\r
+{\r
+ osd_state_t *p_temp = NULL;\r
+ int i;\r
+ \r
+ for( i=0; (i < i_steps) && (p_current != NULL); i++ )\r
+ { \r
+ p_temp = p_current->p_next;\r
+ if( !p_temp ) return p_current;\r
+ p_current = p_temp;\r
+ }\r
+ return (!p_temp) ? p_current : p_temp;\r
+}\r
+\r
+/* Update the state of the OSD Menu */\r
+static void osd_UpdateState( osd_menu_state_t *p_state, int i_x, int i_y,\r
+ int i_width, int i_height, picture_t *p_pic )\r
+{\r
+ p_state->i_x = i_x;\r
+ p_state->i_y = i_y;\r
+ p_state->i_width = i_width;\r
+ p_state->i_height = i_height;\r
+ p_state->p_pic = p_pic;\r
+}\r
+\r
+void __osd_MenuShow( vlc_object_t *p_this )\r
+{\r
+ osd_menu_t *p_osd = NULL;\r
+ osd_button_t *p_button = NULL;\r
+ vlc_value_t lockval;\r
+ \r
+ if( ( p_osd = vlc_object_find( p_this, VLC_OBJECT_OSDMENU, FIND_ANYWHERE ) ) == NULL )\r
+ {\r
+ msg_Err( p_this, "osd_MenuNext failed" );\r
+ return;\r
+ } \r
+\r
+ var_Get( p_this->p_libvlc, "osd_mutex", &lockval );\r
+ vlc_mutex_lock( lockval.p_address );\r
+\r
+#if defined(OSD_MENU_DEBUG)\r
+ msg_Dbg( p_osd, "menu on" );\r
+#endif \r
+ p_button = p_osd->p_state->p_visible;\r
+ if( p_button )\r
+ { \r
+ if( !p_button->b_range ) \r
+ p_button->p_current_state = osd_StateChange( p_button->p_states, OSD_BUTTON_UNSELECT );\r
+ p_osd->p_state->p_visible = p_osd->p_button;\r
+ \r
+ if( !p_osd->p_state->p_visible->b_range ) \r
+ p_osd->p_state->p_visible->p_current_state =\r
+ osd_StateChange( p_osd->p_state->p_visible->p_states, OSD_BUTTON_SELECT );\r
+ \r
+ osd_UpdateState( p_osd->p_state,\r
+ p_osd->p_state->p_visible->i_x, p_osd->p_state->p_visible->i_y,\r
+ p_osd->p_state->p_visible->p_current_state->p_pic->p[Y_PLANE].i_visible_pitch,\r
+ p_osd->p_state->p_visible->p_current_state->p_pic->p[Y_PLANE].i_visible_lines,\r
+ p_osd->p_state->p_visible->p_current_state->p_pic ); \r
+ osd_SetMenuUpdate( p_osd, VLC_TRUE );\r
+ }\r
+ osd_SetMenuVisible( p_osd, VLC_TRUE );\r
+ \r
+ vlc_object_release( (vlc_object_t*) p_osd );\r
+ vlc_mutex_unlock( lockval.p_address );\r
+}\r
+ \r
+void __osd_MenuHide( vlc_object_t *p_this )\r
+{\r
+ osd_menu_t *p_osd = NULL;\r
+ vlc_value_t lockval;\r
+ \r
+ if( ( p_osd = vlc_object_find( p_this, VLC_OBJECT_OSDMENU, FIND_ANYWHERE ) ) == NULL )\r
+ {\r
+ msg_Err( p_this, "osd_MenuNext failed" );\r
+ return;\r
+ }\r
+ \r
+ var_Get( p_this->p_libvlc, "osd_mutex", &lockval );\r
+ vlc_mutex_lock( lockval.p_address );\r
+\r
+#if defined(OSD_MENU_DEBUG)\r
+ msg_Dbg( p_osd, "menu off" );\r
+#endif\r
+ osd_UpdateState( p_osd->p_state,\r
+ p_osd->p_state->i_x, p_osd->p_state->i_y,\r
+ p_osd->p_state->p_visible->p_current_state->p_pic->p[Y_PLANE].i_visible_pitch,\r
+ p_osd->p_state->p_visible->p_current_state->p_pic->p[Y_PLANE].i_visible_lines,\r
+ NULL );\r
+ osd_SetMenuUpdate( p_osd, VLC_TRUE );\r
+\r
+ vlc_object_release( (vlc_object_t*) p_osd );\r
+ vlc_mutex_unlock( lockval.p_address );\r
+}\r
+\r
+void __osd_MenuActivate( vlc_object_t *p_this )\r
+{\r
+ osd_menu_t *p_osd = NULL;\r
+ osd_button_t *p_button = NULL;\r
+ vlc_value_t lockval;\r
+ \r
+ if( ( p_osd = vlc_object_find( p_this, VLC_OBJECT_OSDMENU, FIND_ANYWHERE ) ) == NULL )\r
+ {\r
+ msg_Err( p_this, "osd_MenuNext failed" );\r
+ return;\r
+ }\r
+ \r
+ var_Get( p_this->p_libvlc, "osd_mutex", &lockval );\r
+ vlc_mutex_lock( lockval.p_address );\r
+ \r
+#if defined(OSD_MENU_DEBUG)\r
+ msg_Dbg( p_osd, "select" );\r
+#endif\r
+ p_button = p_osd->p_state->p_visible;\r
+ /*\r
+ * Is there a menu item above or below? If so, then select it.\r
+ */\r
+ if( p_button && p_button->p_up)\r
+ {\r
+ vlc_object_release( (vlc_object_t*) p_osd );\r
+ vlc_mutex_unlock( lockval.p_address );\r
+ __osd_MenuUp( p_this ); /* "menu select" means go to menu item above. */\r
+ return;\r
+ } \r
+ if( p_button && p_button->p_down)\r
+ { \r
+ vlc_object_release( (vlc_object_t*) p_osd );\r
+ vlc_mutex_unlock( lockval.p_address );\r
+ __osd_MenuDown( p_this ); /* "menu select" means go to menu item below. */\r
+ return;\r
+ }\r
+\r
+ if( p_button && !p_button->b_range )\r
+ {\r
+ p_button->p_current_state = osd_StateChange( p_button->p_states, OSD_BUTTON_PRESSED );\r
+ osd_UpdateState( p_osd->p_state,\r
+ p_button->i_x, p_button->i_y,\r
+ p_osd->p_state->p_visible->p_current_state->p_pic->p[Y_PLANE].i_visible_pitch,\r
+ p_osd->p_state->p_visible->p_current_state->p_pic->p[Y_PLANE].i_visible_lines,\r
+ p_button->p_current_state->p_pic );\r
+ osd_SetMenuUpdate( p_osd, VLC_TRUE );\r
+ osd_SetMenuVisible( p_osd, VLC_TRUE );\r
+ osd_SetKeyPressed( VLC_OBJECT(p_osd->p_vlc), config_GetInt( p_osd, p_button->psz_action ) );\r
+#if defined(OSD_MENU_DEBUG)\r
+ msg_Dbg( p_osd, "select (%d, %s)", config_GetInt( p_osd, p_button->psz_action ), p_button->psz_action );\r
+#endif\r
+ }\r
+ vlc_object_release( (vlc_object_t*) p_osd );\r
+ vlc_mutex_unlock( lockval.p_address ); \r
+} \r
+\r
+void __osd_MenuNext( vlc_object_t *p_this )\r
+{\r
+ osd_menu_t *p_osd = NULL;\r
+ osd_button_t *p_button = NULL;\r
+ vlc_value_t lockval;\r
+ \r
+ if( ( p_osd = vlc_object_find( p_this, VLC_OBJECT_OSDMENU, FIND_ANYWHERE ) ) == NULL )\r
+ {\r
+ msg_Err( p_this, "osd_MenuNext failed" );\r
+ return;\r
+ }\r
+ \r
+ var_Get( p_this->p_libvlc, "osd_mutex", &lockval );\r
+ vlc_mutex_lock( lockval.p_address );\r
+ \r
+ p_button = p_osd->p_state->p_visible;\r
+ if( p_button )\r
+ {\r
+ if( !p_button->b_range ) \r
+ p_button->p_current_state = osd_StateChange( p_button->p_states, OSD_BUTTON_UNSELECT );\r
+ if( p_button->p_next )\r
+ p_osd->p_state->p_visible = p_button->p_next;\r
+ else\r
+ p_osd->p_state->p_visible = p_osd->p_button;\r
+ \r
+ if( !p_osd->p_state->p_visible->b_range ) \r
+ p_osd->p_state->p_visible->p_current_state =\r
+ osd_StateChange( p_osd->p_state->p_visible->p_states, OSD_BUTTON_SELECT );\r
+ \r
+ osd_UpdateState( p_osd->p_state, \r
+ p_osd->p_state->p_visible->i_x, p_osd->p_state->p_visible->i_y,\r
+ p_osd->p_state->p_visible->p_current_state->p_pic->p[Y_PLANE].i_visible_pitch,\r
+ p_osd->p_state->p_visible->p_current_state->p_pic->p[Y_PLANE].i_visible_lines,\r
+ p_osd->p_state->p_visible->p_current_state->p_pic );\r
+ osd_SetMenuUpdate( p_osd, VLC_TRUE );\r
+ }\r
+#if defined(OSD_MENU_DEBUG)\r
+ msg_Dbg( p_osd, "direction right [button %s]", p_osd->p_state->p_visible->psz_action ); \r
+#endif\r
+ \r
+ vlc_object_release( (vlc_object_t*) p_osd );\r
+ vlc_mutex_unlock( lockval.p_address );\r
+}\r
+\r
+void __osd_MenuPrev( vlc_object_t *p_this )\r
+{\r
+ osd_menu_t *p_osd = NULL;\r
+ osd_button_t *p_button = NULL;\r
+ vlc_value_t lockval;\r
+ \r
+ if( ( p_osd = vlc_object_find( p_this, VLC_OBJECT_OSDMENU, FIND_ANYWHERE ) ) == NULL )\r
+ {\r
+ msg_Err( p_this, "osd_MenuPrev failed" );\r
+ return;\r
+ }\r
+\r
+ var_Get( p_this->p_libvlc, "osd_mutex", &lockval );\r
+ vlc_mutex_lock( lockval.p_address );\r
+ \r
+ p_button = p_osd->p_state->p_visible;\r
+ if( p_button )\r
+ { \r
+ if( !p_button->b_range ) \r
+ p_button->p_current_state = osd_StateChange( p_button->p_states, OSD_BUTTON_UNSELECT );\r
+ if( p_button->p_prev )\r
+ p_osd->p_state->p_visible = p_button->p_prev;\r
+ else\r
+ p_osd->p_state->p_visible = p_osd->p_last_button; \r
+ \r
+ if( !p_osd->p_state->p_visible->b_range ) \r
+ p_osd->p_state->p_visible->p_current_state =\r
+ osd_StateChange( p_osd->p_state->p_visible->p_states, OSD_BUTTON_SELECT );\r
+ \r
+ osd_UpdateState( p_osd->p_state, \r
+ p_osd->p_state->p_visible->i_x, p_osd->p_state->p_visible->i_y,\r
+ p_osd->p_state->p_visible->p_current_state->p_pic->p[Y_PLANE].i_visible_pitch,\r
+ p_osd->p_state->p_visible->p_current_state->p_pic->p[Y_PLANE].i_visible_lines,\r
+ p_osd->p_state->p_visible->p_current_state->p_pic );\r
+ osd_SetMenuUpdate( p_osd, VLC_TRUE );\r
+ }\r
+#if defined(OSD_MENU_DEBUG)\r
+ msg_Dbg( p_osd, "direction left [button %s]", p_osd->p_state->p_visible->psz_action ); \r
+#endif\r
+ \r
+ vlc_object_release( (vlc_object_t*) p_osd );\r
+ vlc_mutex_unlock( lockval.p_address );\r
+}\r
+\r
+void __osd_MenuUp( vlc_object_t *p_this )\r
+{\r
+ osd_menu_t *p_osd = NULL;\r
+ osd_button_t *p_button = NULL;\r
+ vlc_value_t lockval;\r
+#if defined(OSD_MENU_DEBUG) \r
+ vlc_value_t val;\r
+#endif\r
+ \r
+ if( ( p_osd = vlc_object_find( p_this, VLC_OBJECT_OSDMENU, FIND_ANYWHERE ) ) == NULL )\r
+ {\r
+ msg_Err( p_this, "osd_MenuDown failed" );\r
+ return;\r
+ }\r
+ \r
+ var_Get( p_this->p_libvlc, "osd_mutex", &lockval );\r
+ vlc_mutex_lock( lockval.p_address );\r
+\r
+ p_button = p_osd->p_state->p_visible;\r
+ if( p_button )\r
+ {\r
+ if( !p_button->b_range ) \r
+ {\r
+ p_button->p_current_state = osd_StateChange( p_button->p_states, OSD_BUTTON_SELECT );\r
+ if( p_button->p_up )\r
+ p_osd->p_state->p_visible = p_button->p_up; \r
+ }\r
+ \r
+ if( p_button->b_range && p_osd->p_state->p_visible->b_range ) \r
+ { \r
+ osd_state_t *p_temp = p_osd->p_state->p_visible->p_current_state;\r
+ if( p_temp && p_temp->p_next )\r
+ p_osd->p_state->p_visible->p_current_state = p_temp->p_next;\r
+ }\r
+ else if( !p_osd->p_state->p_visible->b_range )\r
+ { \r
+ p_osd->p_state->p_visible->p_current_state =\r
+ osd_StateChange( p_osd->p_state->p_visible->p_states, OSD_BUTTON_SELECT );\r
+ } \r
+ \r
+ osd_UpdateState( p_osd->p_state, \r
+ p_osd->p_state->p_visible->i_x, p_osd->p_state->p_visible->i_y,\r
+ p_osd->p_state->p_visible->p_current_state->p_pic->p[Y_PLANE].i_visible_pitch,\r
+ p_osd->p_state->p_visible->p_current_state->p_pic->p[Y_PLANE].i_visible_lines,\r
+ p_osd->p_state->p_visible->p_current_state->p_pic );\r
+ osd_SetMenuUpdate( p_osd, VLC_TRUE );\r
+ /* If this is a range style action with associated images of only one state, \r
+ * then perform "menu select" on every menu navigation\r
+ */\r
+ if( p_button->b_range ) \r
+ {\r
+ osd_SetKeyPressed( VLC_OBJECT(p_osd->p_vlc), config_GetInt(p_osd, p_button->psz_action) );\r
+#if defined(OSD_MENU_DEBUG)\r
+ msg_Dbg( p_osd, "select (%d, %s)", val.i_int, p_button->psz_action );\r
+#endif\r
+ }\r
+ }\r
+#if defined(OSD_MENU_DEBUG)\r
+ msg_Dbg( p_osd, "direction up [button %s]", p_osd->p_state->p_visible->psz_action ); \r
+#endif \r
+ \r
+ vlc_object_release( (vlc_object_t*) p_osd );\r
+ vlc_mutex_unlock( lockval.p_address );\r
+}\r
+\r
+void __osd_MenuDown( vlc_object_t *p_this )\r
+{\r
+ osd_menu_t *p_osd = NULL;\r
+ osd_button_t *p_button = NULL;\r
+ vlc_value_t lockval;\r
+#if defined(OSD_MENU_DEBUG) \r
+ vlc_value_t val;\r
+#endif\r
+ \r
+ if( ( p_osd = vlc_object_find( p_this, VLC_OBJECT_OSDMENU, FIND_ANYWHERE ) ) == NULL )\r
+ {\r
+ msg_Err( p_this, "osd_MenuDown failed" );\r
+ return;\r
+ }\r
+ \r
+ var_Get( p_this->p_libvlc, "osd_mutex", &lockval );\r
+ vlc_mutex_lock( lockval.p_address );\r
+ \r
+ p_button = p_osd->p_state->p_visible;\r
+ if( p_button )\r
+ {\r
+ if( !p_button->b_range ) \r
+ {\r
+ p_button->p_current_state = osd_StateChange( p_button->p_states, OSD_BUTTON_SELECT );\r
+ if( p_button->p_down )\r
+ p_osd->p_state->p_visible = p_button->p_down;\r
+ }\r
+ \r
+ if( p_button->b_range && p_osd->p_state->p_visible->b_range ) \r
+ {\r
+ osd_state_t *p_temp = p_osd->p_state->p_visible->p_current_state;\r
+ if( p_temp && p_temp->p_prev )\r
+ p_osd->p_state->p_visible->p_current_state = p_temp->p_prev;\r
+ }\r
+ else if( !p_osd->p_state->p_visible->b_range )\r
+ {\r
+ p_osd->p_state->p_visible->p_current_state =\r
+ osd_StateChange( p_osd->p_state->p_visible->p_states, OSD_BUTTON_SELECT );\r
+ }\r
+\r
+ osd_UpdateState( p_osd->p_state, \r
+ p_osd->p_state->p_visible->i_x, p_osd->p_state->p_visible->i_y,\r
+ p_osd->p_state->p_visible->p_current_state->p_pic->p[Y_PLANE].i_visible_pitch,\r
+ p_osd->p_state->p_visible->p_current_state->p_pic->p[Y_PLANE].i_visible_lines,\r
+ p_osd->p_state->p_visible->p_current_state->p_pic );\r
+ osd_SetMenuUpdate( p_osd, VLC_TRUE );\r
+ /* If this is a range style action with associated images of only one state, \r
+ * then perform "menu select" on every menu navigation\r
+ */\r
+ if( p_button->b_range ) \r
+ {\r
+ osd_SetKeyPressed( VLC_OBJECT(p_osd->p_vlc), config_GetInt(p_osd, p_button->psz_action_down) );\r
+#if defined(OSD_MENU_DEBUG)\r
+ msg_Dbg( p_osd, "select (%d, %s)", val.i_int, p_button->psz_action_down );\r
+#endif\r
+ }\r
+ }\r
+#if defined(OSD_MENU_DEBUG)\r
+ msg_Dbg( p_osd, "direction down [button %s]", p_osd->p_state->p_visible->psz_action ); \r
+#endif \r
+\r
+ vlc_object_release( (vlc_object_t*) p_osd );\r
+ vlc_mutex_unlock( lockval.p_address );\r
+}\r
+\r
+/**\r
+ * Audio volume up\r
+ *\r
+ * The OSD Menu audio volume bar is updated to reflect the new audio volume. Call this function\r
+ * when the audio volume is updated outside the OSD menu command "menu up".\r
+ */\r
+void __osd_VolumeUp( vlc_object_t *p_this )\r
+{\r
+ osd_menu_t *p_osd = NULL;\r
+ osd_button_t *p_button = NULL;\r
+ vlc_value_t lockval;\r
+ int i_volume = 0;\r
+ int i_steps = 0;\r
+ \r
+ if( ( p_osd = vlc_object_find( p_this, VLC_OBJECT_OSDMENU, FIND_ANYWHERE ) ) == NULL )\r
+ {\r
+ msg_Err( p_this, "osd_VolumeUp failed" );\r
+ return;\r
+ }\r
+ \r
+ var_Get( p_this->p_libvlc, "osd_mutex", &lockval );\r
+ vlc_mutex_lock( lockval.p_address );\r
+\r
+ /* Update the volume state images to match the current volume */\r
+ i_volume = config_GetInt( p_this, "volume" );\r
+ i_steps = (i_volume / AOUT_VOLUME_STEP / 3); /* 3 is a magic number for 32 volume decrease steps */\r
+ p_osd->p_state->p_volume->p_current_state = osd_VolumeStateChange( p_osd->p_state->p_volume->p_states, i_steps );\r
+ \r
+ p_button = p_osd->p_state->p_volume;\r
+ if( p_osd->p_state->p_volume ) \r
+ p_osd->p_state->p_visible = p_osd->p_state->p_volume;\r
+ if( p_button && p_button->b_range )\r
+ {\r
+ osd_state_t *p_temp = p_button->p_current_state;\r
+ if( p_temp->p_next )\r
+ p_button->p_current_state = p_temp->p_next;\r
+ \r
+ osd_UpdateState( p_osd->p_state, \r
+ p_button->i_x, p_button->i_y,\r
+ p_button->p_current_state->p_pic->p[Y_PLANE].i_visible_pitch,\r
+ p_button->p_current_state->p_pic->p[Y_PLANE].i_visible_lines,\r
+ p_button->p_current_state->p_pic );\r
+ osd_SetMenuUpdate( p_osd, VLC_TRUE );\r
+ osd_SetMenuVisible( p_osd, VLC_TRUE );\r
+ }\r
+ vlc_object_release( (vlc_object_t*) p_osd );\r
+ vlc_mutex_unlock( lockval.p_address );\r
+}\r
+\r
+/**\r
+ * Audio volume down\r
+ *\r
+ * The OSD Menu audio volume bar is updated to reflect the new audio volume. Call this function\r
+ * when the audio volume is updated outside the OSD menu command "menu down".\r
+ */\r
+void __osd_VolumeDown( vlc_object_t *p_this )\r
+{\r
+ osd_menu_t *p_osd = NULL;\r
+ osd_button_t *p_button = NULL;\r
+ vlc_value_t lockval;\r
+ int i_volume = 0;\r
+ int i_steps = 0;\r
+ \r
+ if( ( p_osd = vlc_object_find( p_this, VLC_OBJECT_OSDMENU, FIND_ANYWHERE ) ) == NULL )\r
+ {\r
+ msg_Err( p_this, "osd_VolumeDown failed" );\r
+ return;\r
+ }\r
+ \r
+ var_Get( p_this->p_libvlc, "osd_mutex", &lockval );\r
+ vlc_mutex_lock( lockval.p_address );\r
+\r
+ /* Update the volume state images to match the current volume */\r
+ i_volume = config_GetInt( p_this, "volume" );\r
+ i_steps = (i_volume / AOUT_VOLUME_STEP / 3); /* 3 is a magic number for 32 volume decrease steps */\r
+ p_osd->p_state->p_volume->p_current_state = osd_VolumeStateChange( p_osd->p_state->p_volume->p_states, i_steps );\r
+\r
+ p_button = p_osd->p_state->p_volume;\r
+ if( p_osd->p_state->p_volume ) \r
+ p_osd->p_state->p_visible = p_osd->p_state->p_volume; \r
+ if( p_button && p_button->b_range )\r
+ {\r
+ osd_state_t *p_temp = p_button->p_current_state;\r
+ if( p_temp && p_temp->p_prev )\r
+ p_button->p_current_state = p_temp->p_prev;\r
+\r
+ osd_UpdateState( p_osd->p_state, \r
+ p_button->i_x, p_button->i_y,\r
+ p_button->p_current_state->p_pic->p[Y_PLANE].i_visible_pitch,\r
+ p_button->p_current_state->p_pic->p[Y_PLANE].i_visible_lines,\r
+ p_button->p_current_state->p_pic );\r
+ osd_SetMenuUpdate( p_osd, VLC_TRUE );\r
+ osd_SetMenuVisible( p_osd, VLC_TRUE );\r
+ }\r
+ vlc_object_release( (vlc_object_t*) p_osd );\r
+ vlc_mutex_unlock( lockval.p_address );\r
+}\r
--- /dev/null
+/*****************************************************************************\r
+ * osd_parser.c - The OSD Menu parser core code.\r
+ *****************************************************************************\r
+ * Copyright (C) 2005 M2X\r
+ * $Id: osd_parser.c 9451 2004-12-01 01:07:08Z jpsaman $\r
+ *\r
+ * Authors: Jean-Paul Saman <jpsaman #_at_# m2x dot nl>\r
+ *\r
+ * This program is free software; you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation; either version 2 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with this program; if not, write to the Free Software\r
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.\r
+ *****************************************************************************/\r
+\r
+/*****************************************************************************\r
+ * Preamble\r
+ *****************************************************************************/\r
+#include <stdlib.h>\r
+#include <string.h>\r
+\r
+#include <vlc/vlc.h>\r
+#include <vlc_config.h>\r
+//#include <vlc_es.h>\r
+#include <vlc_video.h>\r
+\r
+#include <vlc_keys.h>\r
+#include <vlc_image.h>\r
+#include <vlc_osd.h>\r
+\r
+\r
+#undef OSD_MENU_DEBUG\r
+\r
+/*****************************************************************************\r
+ * Local prototypes\r
+ *****************************************************************************/\r
+static const char *ppsz_button_states[] = { "unselect", "select", "pressed" };\r
+\r
+/* OSD Menu structure support routines */\r
+static osd_menu_t *osd_MenuNew( osd_menu_t *, const char *, int, int );\r
+static osd_button_t *osd_ButtonNew( const char *, int, int );\r
+static osd_state_t *osd_StateNew( vlc_object_t *, const char *, const char * );\r
+\r
+static void osd_MenuFree ( vlc_object_t *, osd_menu_t * );\r
+static void osd_ButtonFree( vlc_object_t *, osd_button_t * );\r
+static void osd_StatesFree( vlc_object_t *, osd_state_t * );\r
+\r
+static picture_t *osd_LoadImage( vlc_object_t *, const char *);\r
+\r
+#if 0\r
+/*****************************************************************************\r
+ * osd_YuvaYuvp\r
+ *****************************************************************************/\r
+static picture_t *osd_YuvaYuvp( vlc_object_t *p_this, picture_t *p_picture )\r
+{\r
+ video_format_t *p_fmt = NULL;\r
+ int i = 0, j = 0, n = 0, p = 0;\r
+ int i_max_entries = 256;\r
+\r
+#ifdef RANDOM_DITHERING\r
+ int i_seed = 0xdeadbeef; /* random seed */\r
+#else\r
+ int *pi_delta = NULL;\r
+#endif\r
+ int i_pixels = p_picture->p[0].i_visible_lines\r
+ * p_picture->p[0].i_pitch;\r
+ int i_iterator = p_picture->p[0].i_visible_lines * 3 / 4\r
+ * p_picture->p[0].i_pitch\r
+ + p_picture->p[0].i_pitch * 1 / 3;\r
+ int i_tolerance = 0;\r
+\r
+ p_fmt = (video_format_t*) malloc( sizeof( video_format_t ) );\r
+ if( !p_fmt )\r
+ {\r
+ msg_Err( p_this, "couldn't allocate video_format_t ... aborting YUVA to YUVP conversion of picture" );\r
+ return p_picture;\r
+ }\r
+ p_fmt->i_chroma = VLC_FOURCC('Y','U','V','P');\r
+ p_fmt->p_palette = (video_palette_t *) malloc( sizeof( video_palette_t ) );\r
+ if( !p_fmt->p_palette )\r
+ {\r
+ msg_Err( p_this, "couldn't allocate video_palette_t ... aborting YUVA to YUVP conversion of picture" );\r
+ free( p_fmt );\r
+ return p_picture; \r
+ } \r
+ p_fmt->p_palette->i_entries = 0;\r
+\r
+ /* Find best iterator using Euclide’s algorithm */\r
+ for( ; i_iterator > 1 ; i_iterator-- )\r
+ {\r
+ int a = i_pixels;\r
+ int b = i_iterator;\r
+ int c;\r
+\r
+ while( b )\r
+ {\r
+ c = a % b;\r
+ a = b;\r
+ b = c;\r
+ }\r
+\r
+ if( a == 1 )\r
+ {\r
+ break;\r
+ }\r
+ }\r
+\r
+ /* Count colors, build best palette */\r
+ for( i_tolerance = 0; i_tolerance < 128; i_tolerance++ )\r
+ {\r
+ vlc_bool_t b_success = VLC_TRUE;\r
+ p_fmt->p_palette->i_entries = 0;\r
+\r
+ for( i = 0; i < i_pixels ; )\r
+ {\r
+ uint8_t y = 0, u = 0, v = 0, a = 0;\r
+ y = p_picture->p[0].p_pixels[i];\r
+ u = p_picture->p[1].p_pixels[i];\r
+ v = p_picture->p[2].p_pixels[i];\r
+ a = p_picture->p[3].p_pixels[i];\r
+ for( j = 0; j < p_fmt->p_palette->i_entries; j++ )\r
+ {\r
+ if( abs((int)p_fmt->p_palette->palette[j][0] - (int)y) <= i_tolerance &&\r
+ abs((int)p_fmt->p_palette->palette[j][1] - (int)u) <= i_tolerance &&\r
+ abs((int)p_fmt->p_palette->palette[j][2] - (int)v) <= i_tolerance &&\r
+ abs((int)p_fmt->p_palette->palette[j][3] - (int)a) <= i_tolerance / 2 )\r
+ {\r
+ break;\r
+ }\r
+ }\r
+ if( j == p_fmt->p_palette->i_entries )\r
+ {\r
+ p_fmt->p_palette->palette[j][0] = y;\r
+ p_fmt->p_palette->palette[j][1] = u;\r
+ p_fmt->p_palette->palette[j][2] = v;\r
+ p_fmt->p_palette->palette[j][3] = a;\r
+ p_fmt->p_palette->i_entries++;\r
+ }\r
+ if( p_fmt->p_palette->i_entries >= i_max_entries )\r
+ {\r
+ b_success = VLC_FALSE;\r
+ break;\r
+ }\r
+ i += i_iterator;\r
+ if( i > i_pixels )\r
+ {\r
+ i -= i_pixels;\r
+ }\r
+ }\r
+\r
+ if( b_success )\r
+ {\r
+ break;\r
+ }\r
+ }\r
+\r
+#if OSD_MENU_DEBUG\r
+ msg_Dbg( p_this, "best palette has %d colors", p_fmt->p_palette->i_entries );\r
+#endif\r
+\r
+#ifndef RANDOM_DITHERING\r
+ pi_delta = malloc( ( p_picture->p[0].i_pitch + 1 ) * sizeof(int) * 4 );\r
+ if( !pi_delta )\r
+ {\r
+ msg_Err( p_this, "couldn't allocate video_palette_t ... aborting YUVA to YUVP conversion of picture" );\r
+ free( p_fmt->p_palette );\r
+ free( p_fmt );\r
+ return p_picture; \r
+ } \r
+ \r
+ for( i = 0; i < (p_picture->p[0].i_pitch + 1) * 4 ; i++ )\r
+ {\r
+ pi_delta[ i ] = 0;\r
+ }\r
+#endif\r
+\r
+ /* Fill image with our new colours */\r
+ for( p = 0; p < p_picture->p[0].i_visible_lines ; p++ )\r
+ {\r
+ int i_ydelta = 0, i_udelta = 0, i_vdelta = 0, i_adelta = 0;\r
+\r
+ for( n = 0; n < p_picture->p[0].i_pitch ; n++ )\r
+ {\r
+ int i_offset = p * p_picture->p[0].i_pitch + n;\r
+ int y, u, v, a;\r
+ int i_mindist, i_best;\r
+\r
+ y = (int)p_picture->p[0].p_pixels[i_offset];\r
+ u = (int)p_picture->p[1].p_pixels[i_offset];\r
+ v = (int)p_picture->p[2].p_pixels[i_offset];\r
+ a = (int)p_picture->p[3].p_pixels[i_offset];\r
+\r
+ /* Add dithering compensation */\r
+#ifdef RANDOM_DITHERING\r
+ y += ((i_seed & 0xff) - 0x80) * i_tolerance / 0x80;\r
+ u += (((i_seed >> 8) & 0xff) - 0x80) * i_tolerance / 0x80;\r
+ v += (((i_seed >> 16) & 0xff) - 0x80) * i_tolerance / 0x80;\r
+ a += (((i_seed >> 24) & 0xff) - 0x80) * i_tolerance / 0x80;\r
+#else\r
+ y += i_ydelta + pi_delta[ n * 4 ];\r
+ u += i_udelta + pi_delta[ n * 4 + 1 ];\r
+ v += i_vdelta + pi_delta[ n * 4 + 2 ];\r
+ a += i_adelta + pi_delta[ n * 4 + 3 ];\r
+#endif\r
+\r
+ /* Find best colour in palette */\r
+ for( i_mindist = 99999999, i_best = 0, j = 0; j < p_fmt->p_palette->i_entries; j++ )\r
+ {\r
+ int i_dist = 0;\r
+\r
+ i_dist += abs((int)p_fmt->p_palette->palette[j][0] - y);\r
+ i_dist += abs((int)p_fmt->p_palette->palette[j][1] - u);\r
+ i_dist += abs((int)p_fmt->p_palette->palette[j][2] - v);\r
+ i_dist += 2 * abs((int)p_fmt->p_palette->palette[j][3] - a);\r
+\r
+ if( i_dist < i_mindist )\r
+ {\r
+ i_mindist = i_dist;\r
+ i_best = j;\r
+ }\r
+ }\r
+\r
+ /* Set pixel to best color */\r
+ p_picture->p[0].p_pixels[i_offset] = i_best;\r
+\r
+ /* Update dithering state */\r
+#ifdef RANDOM_DITHERING\r
+ i_seed = (i_seed * 0x1283837) ^ 0x789479 ^ (i_seed >> 13);\r
+#else\r
+ i_ydelta = y - (int)p_fmt->p_palette->palette[i_best][0];\r
+ i_udelta = u - (int)p_fmt->p_palette->palette[i_best][1];\r
+ i_vdelta = v - (int)p_fmt->p_palette->palette[i_best][2];\r
+ i_adelta = a - (int)p_fmt->p_palette->palette[i_best][3];\r
+ pi_delta[ n * 4 ] = i_ydelta * 3 / 8;\r
+ pi_delta[ n * 4 + 1 ] = i_udelta * 3 / 8;\r
+ pi_delta[ n * 4 + 2 ] = i_vdelta * 3 / 8;\r
+ pi_delta[ n * 4 + 3 ] = i_adelta * 3 / 8;\r
+ i_ydelta = i_ydelta * 5 / 8;\r
+ i_udelta = i_udelta * 5 / 8;\r
+ i_vdelta = i_vdelta * 5 / 8;\r
+ i_adelta = i_adelta * 5 / 8;\r
+#endif\r
+ }\r
+ }\r
+\r
+#ifndef RANDOM_DITHERING\r
+ free( pi_delta );\r
+#endif\r
+\r
+ /* pad palette */\r
+ for( i = p_fmt->p_palette->i_entries; i < i_max_entries; i++ )\r
+ {\r
+ p_fmt->p_palette->palette[i][0] = 0;\r
+ p_fmt->p_palette->palette[i][1] = 0;\r
+ p_fmt->p_palette->palette[i][2] = 0;\r
+ p_fmt->p_palette->palette[i][3] = 0;\r
+ }\r
+ p_fmt->p_palette->i_entries = i_max_entries;\r
+#if OSD_MENU_DEBUG\r
+ msg_Dbg( p_this, "best palette has %d colors", p_fmt->p_palette->i_entries );\r
+#endif\r
+\r
+ p_picture->format.i_chroma = VLC_FOURCC('Y','U','V','P');\r
+ if( p_picture->format.p_palette )\r
+ free( p_picture->format.p_palette );\r
+ p_picture->format.p_palette = p_fmt->p_palette;\r
+ free( p_fmt );\r
+ return p_picture;\r
+}\r
+#endif\r
+/*****************************************************************************\r
+ * osd_LoadImage: loads the logo image into memory\r
+ *****************************************************************************/\r
+static picture_t *osd_LoadImage( vlc_object_t *p_this, const char *psz_filename )\r
+{\r
+ picture_t *p_pic = NULL;\r
+ image_handler_t *p_image;\r
+ video_format_t fmt_in = {0}, fmt_out = {0};\r
+\r
+ fmt_out.i_chroma = VLC_FOURCC('Y','U','V','A');\r
+ p_image = image_HandlerCreate( p_this );\r
+ if( p_image )\r
+ {\r
+ p_pic = image_ReadUrl( p_image, psz_filename, &fmt_in, &fmt_out );\r
+ image_HandlerDelete( p_image );\r
+#if 0 \r
+ p_pic = osd_YuvaYuvp( p_this, p_pic );\r
+#endif\r
+ }\r
+ else msg_Err( p_this, "unable to handle this chroma" );\r
+\r
+ return p_pic;\r
+}\r
+\r
+/*****************************************************************************\r
+ * Create a new Menu structure\r
+ *****************************************************************************/\r
+static osd_menu_t *osd_MenuNew( osd_menu_t *p_menu, const char *psz_path, int i_x, int i_y )\r
+{\r
+ if( !p_menu ) return NULL;\r
+ \r
+ p_menu->p_state = (osd_menu_state_t *) malloc( sizeof( osd_menu_state_t ) );\r
+ if( !p_menu->p_state )\r
+ msg_Err( p_menu, "memory allocation for OSD Menu state failed." );\r
+\r
+ if( psz_path != NULL )\r
+ p_menu->psz_path = strdup( psz_path );\r
+ else\r
+ p_menu->psz_path = NULL;\r
+ p_menu->i_x = i_x;\r
+ p_menu->i_y = i_y;\r
+ \r
+ return p_menu; \r
+}\r
+\r
+/*****************************************************************************\r
+ * Free the menu\r
+ *****************************************************************************/\r
+static void osd_MenuFree( vlc_object_t *p_this, osd_menu_t *p_menu )\r
+{\r
+ msg_Dbg( p_this, "freeing menu" );\r
+ osd_ButtonFree( p_this, p_menu->p_button );\r
+ p_menu->p_button = NULL;\r
+ p_menu->p_last_button = NULL;\r
+ if( p_menu->psz_path ) free( p_menu->psz_path );\r
+ p_menu->psz_path = NULL;\r
+ if( p_menu->p_state ) free( p_menu->p_state );\r
+ p_menu->p_state = NULL;\r
+}\r
+\r
+/*****************************************************************************\r
+ * Create a new button\r
+ *****************************************************************************/\r
+static osd_button_t *osd_ButtonNew( const char *psz_action, int i_x, int i_y )\r
+{\r
+ osd_button_t *p_button = NULL;\r
+ p_button = (osd_button_t*) malloc( sizeof(osd_button_t) );\r
+ if( !p_button )\r
+ return NULL;\r
+ \r
+ memset( p_button, 0, sizeof(osd_button_t) );\r
+ p_button->psz_action = strdup(psz_action);\r
+ p_button->psz_action_down = NULL;\r
+ p_button->p_feedback = NULL;\r
+ p_button->i_x = i_x;\r
+ p_button->i_y = i_y;\r
+ \r
+ return p_button;\r
+}\r
+\r
+/*****************************************************************************\r
+ * Free a button\r
+ *****************************************************************************/ \r
+static void osd_ButtonFree( vlc_object_t *p_this, osd_button_t *p_button )\r
+{\r
+ osd_button_t *p_current = p_button;\r
+ osd_button_t *p_next = NULL;\r
+ osd_button_t *p_prev = NULL;\r
+ \r
+ /* First walk to the end. */\r
+ while( p_current->p_next )\r
+ {\r
+ p_next = p_current->p_next;\r
+ p_current = p_next; \r
+ }\r
+ /* Then free end first and walk to the start. */\r
+ while( p_current->p_prev )\r
+ {\r
+ msg_Dbg( p_this, "+ freeing button %s [%p]", p_current->psz_action, p_current );\r
+ p_prev = p_current->p_prev;\r
+ p_current = p_prev;\r
+ if( p_current->p_next )\r
+ {\r
+ if( p_current->p_next->psz_name ) \r
+ free( p_current->p_next->psz_name );\r
+ if( p_current->p_next->psz_action )\r
+ free( p_current->p_next->psz_action );\r
+ if( p_current->p_next->psz_action_down )\r
+ free( p_current->p_next->psz_action_down );\r
+ if( p_current->p_feedback && p_current->p_feedback->p_data_orig )\r
+ free( p_current->p_feedback->p_data_orig );\r
+ if( p_current->p_feedback )\r
+ free( p_current->p_feedback );\r
+ \r
+ p_current->p_next->psz_action_down = NULL;\r
+ p_current->p_next->psz_action = NULL;\r
+ p_current->p_next->psz_name = NULL;\r
+ p_current->p_feedback = NULL;\r
+ \r
+ /* Free all states first */ \r
+ if( p_current->p_next->p_states ) \r
+ osd_StatesFree( p_this, p_current->p_next->p_states );\r
+ p_current->p_next->p_states = NULL; \r
+ if( p_current->p_next) free( p_current->p_next );\r
+ p_current->p_next = NULL; \r
+ } \r
+ \r
+ if( p_current->p_up )\r
+ {\r
+ if( p_current->p_up->psz_name ) \r
+ free( p_current->p_up->psz_name );\r
+ if( p_current->p_up->psz_action )\r
+ free( p_current->p_up->psz_action );\r
+ if( p_current->p_up->psz_action_down )\r
+ free( p_current->p_up->psz_action_down );\r
+ if( p_current->p_feedback && p_current->p_feedback->p_data_orig )\r
+ free( p_current->p_feedback->p_data_orig );\r
+ if( p_current->p_feedback )\r
+ free( p_current->p_feedback );\r
+ \r
+ p_current->p_up->psz_action_down = NULL;\r
+ p_current->p_up->psz_action = NULL;\r
+ p_current->p_up->psz_name = NULL;\r
+ p_current->p_feedback = NULL;\r
+ \r
+ /* Free all states first */ \r
+ if( p_current->p_up->p_states ) \r
+ osd_StatesFree( p_this, p_current->p_up->p_states );\r
+ p_current->p_up->p_states = NULL; \r
+ if( p_current->p_up ) free( p_current->p_up );\r
+ p_current->p_up = NULL; \r
+ }\r
+ } \r
+ /* Free the last one. */\r
+ if( p_button ) \r
+ {\r
+ msg_Dbg( p_this, "+ freeing button %s [%p]", p_button->psz_action, p_button ); \r
+ if( p_button->psz_name ) free( p_button->psz_name );\r
+ if( p_button->psz_action ) free( p_button->psz_action );\r
+ if( p_button->psz_action_down ) free( p_button->psz_action_down ); \r
+ if( p_current->p_feedback && p_current->p_feedback->p_data_orig )\r
+ free( p_current->p_feedback->p_data_orig );\r
+ if( p_current->p_feedback )\r
+ free( p_current->p_feedback );\r
+ \r
+ p_button->psz_name = NULL;\r
+ p_button->psz_action = NULL;\r
+ p_button->psz_action_down = NULL;\r
+ p_current->p_feedback = NULL;\r
+ \r
+ if( p_button->p_states )\r
+ osd_StatesFree( p_this, p_button->p_states );\r
+ p_button->p_states = NULL; \r
+ free( p_button );\r
+ p_button = NULL;\r
+ }\r
+}\r
+\r
+/*****************************************************************************\r
+ * Create a new state image\r
+ *****************************************************************************/\r
+static osd_state_t *osd_StateNew( vlc_object_t *p_this, const char *psz_file, const char *psz_state )\r
+{\r
+ osd_state_t *p_state = NULL;\r
+ p_state = (osd_state_t*) malloc( sizeof(osd_state_t) );\r
+ if( !p_state )\r
+ return NULL;\r
+ \r
+ memset( p_state, 0, sizeof(osd_state_t) ); \r
+ p_state->p_pic = osd_LoadImage( p_this, psz_file );\r
+\r
+ if( psz_state )\r
+ {\r
+ p_state->psz_state = strdup( psz_state );\r
+ if( strncmp( ppsz_button_states[0], psz_state, strlen(ppsz_button_states[0]) ) == 0 )\r
+ p_state->i_state = OSD_BUTTON_UNSELECT;\r
+ else if( strncmp( ppsz_button_states[1], psz_state, strlen(ppsz_button_states[1]) ) == 0 )\r
+ p_state->i_state = OSD_BUTTON_SELECT;\r
+ else if( strncmp( ppsz_button_states[2], psz_state, strlen(ppsz_button_states[2]) ) == 0 )\r
+ p_state->i_state = OSD_BUTTON_PRESSED;\r
+ }\r
+ return p_state;\r
+}\r
+\r
+/*****************************************************************************\r
+ * Free state images\r
+ *****************************************************************************/\r
+static void osd_StatesFree( vlc_object_t *p_this, osd_state_t *p_states )\r
+{\r
+ osd_state_t *p_state = p_states;\r
+ osd_state_t *p_next = NULL;\r
+ osd_state_t *p_prev = NULL;\r
+ \r
+ while( p_state->p_next )\r
+ {\r
+ p_next = p_state->p_next;\r
+ p_state = p_next;\r
+ }\r
+ /* Then free end first and walk to the start. */\r
+ while( p_state->p_prev )\r
+ {\r
+ msg_Dbg( p_this, " |- freeing state %s [%p]", p_state->psz_state, p_state );\r
+ p_prev = p_state->p_prev;\r
+ p_state = p_prev;\r
+ if( p_state->p_next )\r
+ {\r
+ if( p_state->p_next->p_pic && p_state->p_next->p_pic->p_data_orig )\r
+ free( p_state->p_next->p_pic->p_data_orig );\r
+ if( p_state->p_next->p_pic ) free( p_state->p_next->p_pic );\r
+ p_state->p_next->p_pic = NULL; \r
+ if( p_state->p_next->psz_state ) free( p_state->p_next->psz_state );\r
+ p_state->p_next->psz_state = NULL;\r
+ free( p_state->p_next );\r
+ p_state->p_next = NULL; \r
+ }\r
+ }\r
+ /* Free the last one. */\r
+ if( p_states )\r
+ {\r
+ msg_Dbg( p_this, " |- freeing state %s [%p]", p_state->psz_state, p_states );\r
+ if( p_states->p_pic && p_states->p_pic->p_data_orig )\r
+ free( p_states->p_pic->p_data_orig );\r
+ if( p_states->p_pic ) free( p_states->p_pic );\r
+ p_states->p_pic = NULL;\r
+ if( p_state->psz_state ) free( p_state->psz_state );\r
+ p_state->psz_state = NULL;\r
+ free( p_states );\r
+ p_states = NULL;\r
+ }\r
+}\r
+\r
+/*****************************************************************************\r
+ * osd_ConfigLoader: Load and parse osd text configurationfile\r
+ *****************************************************************************/\r
+int osd_ConfigLoader( vlc_object_t *p_this, const char *psz_file,\r
+ osd_menu_t **p_menu )\r
+{\r
+ osd_button_t *p_current = NULL; /* button currently processed */\r
+ osd_button_t *p_prev = NULL; /* previous processed button */ \r
+\r
+#define MAX_FILE_PATH 256 \r
+ FILE *fd = NULL;\r
+ int result = 0;\r
+ \r
+ msg_Dbg( p_this, "opening osd definition file %s", psz_file );\r
+ fd = fopen( psz_file, "r" );\r
+ if( !fd ) \r
+ {\r
+ msg_Err( p_this, "failed opening osd definition file %s", psz_file );\r
+ return VLC_EGENERIC;\r
+ }\r
+ \r
+ /* Read first line */ \r
+ if( !feof( fd ) )\r
+ {\r
+ char action[25] = "";\r
+ char path[MAX_FILE_PATH] = "";\r
+ char *psz_path = NULL;\r
+ size_t i_len = 0;\r
+\r
+ /* override images path ? */\r
+ psz_path = config_GetPsz( p_this, "osdmenu-file-path" );\r
+ if( psz_path == NULL )\r
+ { \r
+ result = fscanf(fd, "%24s %255s", &action[0], &path[0] );\r
+ }\r
+ else\r
+ {\r
+ /* psz_path is not null and therefor &path[0] cannot be NULL \r
+ * it might be null terminated.\r
+ */\r
+ strncpy( &path[0], psz_path, MAX_FILE_PATH );\r
+ free( psz_path );\r
+ psz_path = NULL;\r
+ }\r
+ /* NULL terminate before asking the length of path[] */\r
+ path[MAX_FILE_PATH-1] = '\0';\r
+ i_len = strlen(&path[0]);\r
+ if( i_len == MAX_FILE_PATH )\r
+ i_len--; /* truncate to prevent buffer overflow */\r
+#if defined(WIN32) || defined(UNDER_CE)\r
+ if( (i_len > 0) && path[i_len] != '\\' )\r
+ path[i_len] = '\\';\r
+#else \r
+ if( (i_len > 0) && path[i_len] != '/' )\r
+ path[i_len] = '/';\r
+#endif\r
+ path[i_len+1] = '\0';\r
+ if( result == 0 || result == EOF )\r
+ goto error; \r
+ msg_Dbg( p_this, "%s=%s", &action[0], &path[0] );\r
+ \r
+ if( i_len == 0 )\r
+ *p_menu = osd_MenuNew( *p_menu, NULL, 0, 0 );\r
+ else\r
+ *p_menu = osd_MenuNew( *p_menu, &path[0], 0, 0 );\r
+ }\r
+ \r
+ if( !*p_menu )\r
+ goto error;\r
+ \r
+ /* read successive lines */\r
+ while( !feof( fd ) )\r
+ { \r
+ osd_state_t *p_state_current = NULL; /* button state currently processed */\r
+ osd_state_t *p_state_prev = NULL; /* previous state processed button */ \r
+ \r
+ char cmd[25] = ""; \r
+ char action[25] = "";\r
+ char state[25] = "";\r
+ char file[256] = "";\r
+ char path[512] = ""; \r
+ int i_x = 0;\r
+ int i_y = 0;\r
+\r
+ result = fscanf( fd, "%24s %24s (%d,%d)", &cmd[0], &action[0], &i_x, &i_y );\r
+ if( result == 0 )\r
+ goto error; \r
+ if( strncmp( &cmd[0], "action", 6 ) != 0 )\r
+ break;\r
+ msg_Dbg( p_this, " + %s hotkey=%s (%d,%d)", &cmd[0], &action[0], i_x, i_y ); \r
+ \r
+ p_prev = p_current;\r
+ p_current = osd_ButtonNew( &action[0], i_x, i_y ); \r
+ if( !p_current )\r
+ goto error;\r
+ \r
+ if( p_prev )\r
+ p_prev->p_next = p_current; \r
+ else\r
+ (*p_menu)->p_button = p_current; \r
+ p_current->p_prev = p_prev;\r
+ \r
+ /* parse all states */\r
+ while( !feof( fd ) )\r
+ {\r
+ char type[25] = "";\r
+ \r
+ result = fscanf( fd, "\t%24s", &state[0] ); \r
+ if( result == 0 )\r
+ goto error;\r
+ \r
+ /* FIXME: We only parse one level deep now */ \r
+ if( strncmp( &state[0], "action", 6 ) == 0 )\r
+ {\r
+ osd_button_t *p_up = NULL;\r
+ \r
+ result = fscanf( fd, "%24s (%d,%d)", &action[0], &i_x, &i_y );\r
+ if( result == 0 )\r
+ goto error;\r
+ /* create new button */ \r
+ p_up = osd_ButtonNew( &action[0], i_x, i_y ); \r
+ if( !p_up ) \r
+ goto error;\r
+ /* Link to list */ \r
+ p_up->p_down = p_current;\r
+ p_current->p_up = p_up; \r
+ msg_Dbg( p_this, " + (menu up) hotkey=%s (%d,%d)", &action[0], i_x, i_y );\r
+ /* Parse type state */\r
+ result = fscanf( fd, "\t%24s %24s", &cmd[0], &type[0] ); \r
+ if( result == 0 )\r
+ goto error;\r
+ if( strncmp( &cmd[0], "type", 4 ) == 0 )\r
+ { \r
+ if( strncmp( &type[0], "volume", 6 ) == 0 )\r
+ {\r
+ (*p_menu)->p_state->p_volume = p_up;\r
+ msg_Dbg( p_this, " + type=%s", &type[0] );\r
+ }\r
+ }\r
+ /* Parse range state */\r
+ result = fscanf( fd, "\t%24s", &state[0] ); \r
+ if( result == 0 )\r
+ goto error;\r
+ /* Parse the range state */ \r
+ if( strncmp( &state[0], "range", 5 ) == 0 )\r
+ {\r
+ osd_state_t *p_range_current = NULL; /* range state currently processed */\r
+ osd_state_t *p_range_prev = NULL; /* previous state processed range */ \r
+ int i_index = 0;\r
+ \r
+ p_up->b_range = VLC_TRUE;\r
+ \r
+ result = fscanf( fd, "\t%24s", &action[0] ); \r
+ if( result == 0 )\r
+ goto error;\r
+ \r
+ result = fscanf( fd, "\t%d", &i_index ); \r
+ if( result == 0 )\r
+ goto error;\r
+ \r
+ msg_Dbg( p_this, " + (menu up) hotkey down %s, file=%s%s", &action[0], (*p_menu)->psz_path, &file[0] );\r
+ \r
+ if( p_up->psz_action_down ) free( p_up->psz_action_down );\r
+ p_up->psz_action_down = strdup( &action[0] ); \r
+ \r
+ /* Parse range contstruction :\r
+ * range <hotkey> \r
+ * <state1> <file1>\r
+ *\r
+ * <stateN> <fileN>\r
+ * end \r
+ */ \r
+ while( !feof( fd ) )\r
+ {\r
+ result = fscanf( fd, "\t%255s", &file[0] ); \r
+ if( result == 0 )\r
+ goto error;\r
+ if( strncmp( &file[0], "end", 3 ) == 0 )\r
+ break;\r
+ \r
+ p_range_prev = p_range_current;\r
+ \r
+ if( (*p_menu)->psz_path )\r
+ {\r
+ size_t i_path_size = strlen( (*p_menu)->psz_path );\r
+ size_t i_file_size = strlen( &file[0] );\r
+ \r
+ strncpy( &path[0], (*p_menu)->psz_path, i_path_size );\r
+ strncpy( &path[i_path_size], &file[0], 512 - (i_path_size + i_file_size) );\r
+ path[ i_path_size + i_file_size ] = '\0';\r
+ \r
+ p_range_current = osd_StateNew( p_this, &path[0], "pressed" );\r
+ }\r
+ else /* absolute paths are used. */\r
+ p_range_current = osd_StateNew( p_this, &file[0], "pressed" );\r
+ \r
+ if( !p_range_current || !p_range_current->p_pic )\r
+ goto error;\r
+ \r
+ /* increment the number of ranges for this button */ \r
+ p_up->i_ranges++;\r
+ \r
+ if( p_range_prev )\r
+ p_range_prev->p_next = p_range_current;\r
+ else\r
+ p_up->p_states = p_range_current; \r
+ p_range_current->p_prev = p_range_prev;\r
+ \r
+ msg_Dbg( p_this, " |- range=%d, file=%s%s", \r
+ p_up->i_ranges, \r
+ (*p_menu)->psz_path, &file[0] ); \r
+ }\r
+ if( i_index > 0 )\r
+ { \r
+ osd_state_t *p_range = NULL;\r
+ \r
+ /* Find the default index for state range */ \r
+ p_range = p_up->p_states;\r
+ while( (--i_index > 0) && p_range->p_next )\r
+ {\r
+ osd_state_t *p_temp = NULL;\r
+ p_temp = p_range->p_next;\r
+ p_range = p_temp;\r
+ }\r
+ p_up->p_current_state = p_range;\r
+ } \r
+ else p_up->p_current_state = p_up->p_states;\r
+ \r
+ } \r
+ result = fscanf( fd, "\t%24s", &state[0] ); \r
+ if( result == 0 )\r
+ goto error; \r
+ if( strncmp( &state[0], "end", 3 ) != 0 )\r
+ goto error;\r
+ \r
+ /* Continue at the beginning of the while() */\r
+ continue;\r
+ }\r
+ \r
+ /* Parse the range state */ \r
+ if( strncmp( &state[0], "range", 5 ) == 0 )\r
+ {\r
+ osd_state_t *p_range_current = NULL; /* range state currently processed */\r
+ osd_state_t *p_range_prev = NULL; /* previous state processed range */ \r
+ int i_index = 0;\r
+ \r
+ p_current->b_range = VLC_TRUE;\r
+\r
+ result = fscanf( fd, "\t%24s", &action[0] ); \r
+ if( result == 0 )\r
+ goto error;\r
+ \r
+ result = fscanf( fd, "\t%d", &i_index ); \r
+ if( result == 0 )\r
+ goto error;\r
+ \r
+ msg_Dbg( p_this, " + hotkey down %s, file=%s%s", &action[0], (*p_menu)->psz_path, &file[0] ); \r
+ if( p_current->psz_action_down ) free( p_current->psz_action_down );\r
+ p_current->psz_action_down = strdup( &action[0] ); \r
+ \r
+ /* Parse range contstruction :\r
+ * range <hotkey> \r
+ * <state1> <file1>\r
+ *\r
+ * <stateN> <fileN>\r
+ * end \r
+ */ \r
+ while( !feof( fd ) )\r
+ {\r
+ result = fscanf( fd, "\t%255s", &file[0] ); \r
+ if( result == 0 )\r
+ goto error;\r
+ if( strncmp( &file[0], "end", 3 ) == 0 )\r
+ break;\r
+ \r
+ p_range_prev = p_range_current;\r
+ \r
+ if( (*p_menu)->psz_path )\r
+ {\r
+ size_t i_path_size = strlen( (*p_menu)->psz_path );\r
+ size_t i_file_size = strlen( &file[0] );\r
+ \r
+ strncpy( &path[0], (*p_menu)->psz_path, i_path_size );\r
+ strncpy( &path[i_path_size], &file[0], 512 - (i_path_size + i_file_size) );\r
+ path[ i_path_size + i_file_size ] = '\0';\r
+ \r
+ p_range_current = osd_StateNew( p_this, &path[0], "pressed" );\r
+ }\r
+ else /* absolute paths are used. */\r
+ p_range_current = osd_StateNew( p_this, &file[0], "pressed" );\r
+ \r
+ if( !p_range_current || !p_range_current->p_pic )\r
+ goto error;\r
+ \r
+ /* increment the number of ranges for this button */ \r
+ p_current->i_ranges++;\r
+ \r
+ if( p_range_prev )\r
+ p_range_prev->p_next = p_range_current;\r
+ else\r
+ p_current->p_states = p_range_current; \r
+ p_range_current->p_prev = p_range_prev;\r
+ \r
+ msg_Dbg( p_this, " |- range=%d, file=%s%s", \r
+ p_current->i_ranges, \r
+ (*p_menu)->psz_path, &file[0] ); \r
+ }\r
+ if( i_index > 0 )\r
+ { \r
+ osd_state_t *p_range = NULL;\r
+ \r
+ /* Find the default index for state range */ \r
+ p_range = p_current->p_states;\r
+ while( (--i_index > 0) && p_range->p_next )\r
+ {\r
+ osd_state_t *p_temp = NULL;\r
+ p_temp = p_range->p_next;\r
+ p_range = p_temp;\r
+ }\r
+ p_current->p_current_state = p_range;\r
+ } \r
+ else p_current->p_current_state = p_current->p_states;\r
+ /* Continue at the beginning of the while() */\r
+ continue;\r
+ } \r
+ if( strncmp( &state[0], "end", 3 ) == 0 )\r
+ break;\r
+ \r
+ result = fscanf( fd, "\t%255s", &file[0] ); \r
+ if( result == 0 )\r
+ goto error; \r
+ \r
+ p_state_prev = p_state_current;\r
+\r
+ if( ( strncmp( ppsz_button_states[0], &state[0], strlen(ppsz_button_states[0]) ) != 0 ) &&\r
+ ( strncmp( ppsz_button_states[1], &state[0], strlen(ppsz_button_states[1]) ) != 0 ) &&\r
+ ( strncmp( ppsz_button_states[2], &state[0], strlen(ppsz_button_states[2]) ) != 0 ) )\r
+ {\r
+ msg_Err( p_this, "invalid button state %s for button %s expected %d: unselect, select or pressed)",\r
+ &state[0], &action[0], strlen(&state[0]));\r
+ goto error;\r
+ }\r
+ \r
+ if( (*p_menu)->psz_path )\r
+ {\r
+ size_t i_path_size = strlen( (*p_menu)->psz_path );\r
+ size_t i_file_size = strlen( &file[0] );\r
+ \r
+ strncpy( &path[0], (*p_menu)->psz_path, i_path_size );\r
+ strncpy( &path[i_path_size], &file[0], 512 - (i_path_size + i_file_size) );\r
+ path[ i_path_size + i_file_size ] = '\0';\r
+ \r
+ p_state_current = osd_StateNew( p_this, &path[0], &state[0] );\r
+ }\r
+ else /* absolute paths are used. */\r
+ p_state_current = osd_StateNew( p_this, &file[0], &state[0] );\r
+ \r
+ if( !p_state_current || !p_state_current->p_pic )\r
+ goto error;\r
+ \r
+ if( p_state_prev )\r
+ p_state_prev->p_next = p_state_current;\r
+ else\r
+ p_current->p_states = p_state_current; \r
+ p_state_current->p_prev = p_state_prev;\r
+ \r
+ msg_Dbg( p_this, " |- state=%s, file=%s%s", &state[0], (*p_menu)->psz_path, &file[0] );\r
+ }\r
+ p_current->p_current_state = p_current->p_states;\r
+ }\r
+\r
+ /* Find the last button and store its pointer. \r
+ * The OSD menu behaves like a roundrobin list.\r
+ */ \r
+ p_current = (*p_menu)->p_button;\r
+ while( p_current && p_current->p_next )\r
+ {\r
+ osd_button_t *p_temp = NULL;\r
+ p_temp = p_current->p_next;\r
+ p_current = p_temp;\r
+ }\r
+ (*p_menu)->p_last_button = p_current;\r
+ fclose( fd );\r
+ return 0;\r
+ \r
+#undef MAX_FILE_PATH \r
+error:\r
+ msg_Err( p_this, "parsing file failed (returned %d)", result );\r
+ fclose( fd );\r
+ return 1; \r
+}\r
+\r
+/*****************************************************************************\r
+ * osd_ConfigUnload: Load and parse osd text configurationfile\r
+ *****************************************************************************/\r
+void osd_ConfigUnload( vlc_object_t *p_this, osd_menu_t **p_osd)\r
+{\r
+ msg_Dbg( p_this, "unloading OSD menu structure" );\r
+ osd_MenuFree( p_this, *p_osd );\r
+}\r
--- /dev/null
+/*****************************************************************************\r
+ * osd_widgets.c : OSD widgets manipulation functions\r
+ *****************************************************************************\r
+ * Copyright (C) 2005 M2X\r
+ * Copyright (C) 2004 VideoLAN (Centrale Réseaux) and its contributors\r
+ *\r
+ * $Id: osd_widgets.c 9274 2004-11-10 15:16:51Z gbazin $\r
+ *\r
+ * Author: Jean-Paul Saman <jpsaman #_at_# m2x dot nl>\r
+ *\r
+ * Based on: src/video_output/video_widgets.c\r
+ * from: Yoann Peronneau <yoann@videolan.org>\r
+ *\r
+ * This program is free software; you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation; either version 2 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with this program; if not, write to the Free Software\r
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.\r
+ *****************************************************************************/\r
+\r
+/*****************************************************************************\r
+ * Preamble\r
+ *****************************************************************************/\r
+#include <stdlib.h> /* free() */\r
+#include <vlc/vlc.h>\r
+#include <vlc/vout.h>\r
+#include <osd.h>\r
+\r
+#define STYLE_EMPTY 0\r
+#define STYLE_FILLED 1\r
+\r
+/*****************************************************************************\r
+ * Local prototypes\r
+ *****************************************************************************/\r
+static void DrawRect( picture_t *, int, int, int, int, short );\r
+static void DrawTriangle( picture_t *, int, int, int, int, short );\r
+static picture_t *osd_CreatePicture( int, int );\r
+\r
+/*****************************************************************************\r
+ * Draws a rectangle at the given position in the subpic.\r
+ * It may be filled (fill == STYLE_FILLED) or empty (fill == STYLE_EMPTY).\r
+ *****************************************************************************/\r
+static void DrawRect( picture_t *p_picture, int i_x1, int i_y1,\r
+ int i_x2, int i_y2, short fill )\r
+{\r
+ int x, y;\r
+ uint8_t *p_a = p_picture->A_PIXELS;\r
+ int i_pitch = p_picture->Y_PITCH;\r
+\r
+ if( fill == STYLE_FILLED )\r
+ {\r
+ for( y = i_y1; y <= i_y2; y++ )\r
+ {\r
+ for( x = i_x1; x <= i_x2; x++ )\r
+ {\r
+ p_a[ x + i_pitch * y ] = 0xff;\r
+ }\r
+ }\r
+ }\r
+ else\r
+ {\r
+ for( y = i_y1; y <= i_y2; y++ )\r
+ {\r
+ p_a[ i_x1 + i_pitch * y ] = 0xff;\r
+ p_a[ i_x2 + i_pitch * y ] = 0xff;\r
+ }\r
+ for( x = i_x1; x <= i_x2; x++ )\r
+ {\r
+ p_a[ x + i_pitch * i_y1 ] = 0xff;\r
+ p_a[ x + i_pitch * i_y2 ] = 0xff;\r
+ }\r
+ }\r
+}\r
+\r
+/*****************************************************************************\r
+ * Draws a triangle at the given position in the subpic.\r
+ * It may be filled (fill == STYLE_FILLED) or empty (fill == STYLE_EMPTY).\r
+ *****************************************************************************/\r
+static void DrawTriangle( picture_t *p_picture, int i_x1, int i_y1,\r
+ int i_x2, int i_y2, short fill )\r
+{\r
+ int x, y, i_mid, h;\r
+ uint8_t *p_a = p_picture->A_PIXELS;\r
+ int i_pitch = p_picture->Y_PITCH;\r
+\r
+ i_mid = i_y1 + ( ( i_y2 - i_y1 ) >> 1 );\r
+\r
+ if( i_x2 >= i_x1 )\r
+ {\r
+ if( fill == STYLE_FILLED )\r
+ {\r
+ for( y = i_y1; y <= i_mid; y++ )\r
+ {\r
+ h = y - i_y1;\r
+ for( x = i_x1; x <= i_x1 + h && x <= i_x2; x++ )\r
+ {\r
+ p_a[ x + i_pitch * y ] = 0xff;\r
+ p_a[ x + i_pitch * ( i_y2 - h ) ] = 0xff;\r
+ }\r
+ }\r
+ }\r
+ else\r
+ {\r
+ for( y = i_y1; y <= i_mid; y++ )\r
+ {\r
+ h = y - i_y1;\r
+ p_a[ i_x1 + i_pitch * y ] = 0xff;\r
+ p_a[ i_x1 + h + i_pitch * y ] = 0xff;\r
+ p_a[ i_x1 + i_pitch * ( i_y2 - h ) ] = 0xff;\r
+ p_a[ i_x1 + h + i_pitch * ( i_y2 - h ) ] = 0xff;\r
+ }\r
+ }\r
+ }\r
+ else\r
+ {\r
+ if( fill == STYLE_FILLED )\r
+ {\r
+ for( y = i_y1; y <= i_mid; y++ )\r
+ {\r
+ h = y - i_y1;\r
+ for( x = i_x1; x >= i_x1 - h && x >= i_x2; x-- )\r
+ {\r
+ p_a[ x + i_pitch * y ] = 0xff;\r
+ p_a[ x + i_pitch * ( i_y2 - h ) ] = 0xff;\r
+ }\r
+ }\r
+ }\r
+ else\r
+ {\r
+ for( y = i_y1; y <= i_mid; y++ )\r
+ {\r
+ h = y - i_y1;\r
+ p_a[ i_x1 + i_pitch * y ] = 0xff;\r
+ p_a[ i_x1 - h + i_pitch * y ] = 0xff;\r
+ p_a[ i_x1 + i_pitch * ( i_y2 - h ) ] = 0xff;\r
+ p_a[ i_x1 - h + i_pitch * ( i_y2 - h ) ] = 0xff;\r
+ }\r
+ }\r
+ }\r
+}\r
+\r
+/*****************************************************************************\r
+ * Create Picture: creates picture\r
+ *****************************************************************************/\r
+static picture_t *osd_CreatePicture( int i_width, int i_height )\r
+{\r
+ picture_t *p_picture = NULL;\r
+ uint8_t *p_y, *p_u, *p_v, *p_a;\r
+ int i_pitch;\r
+\r
+ p_picture = (picture_t*) malloc( sizeof(picture_t) );\r
+ if( p_picture == NULL )\r
+ {\r
+ return NULL;\r
+ }\r
+ /* Clear the memory */\r
+ memset( p_picture, 0, sizeof(picture_t) );\r
+\r
+ p_y = p_picture->Y_PIXELS;\r
+ p_u = p_picture->U_PIXELS;\r
+ p_v = p_picture->V_PIXELS;\r
+ p_a = p_picture->A_PIXELS;\r
+ i_pitch = p_picture->Y_PITCH;\r
+\r
+ /* Initialize the region pixels (only the alpha will be changed later) */\r
+ memset( p_y, 0xff, i_pitch * i_height );\r
+ memset( p_u, 0x80, i_pitch * i_height );\r
+ memset( p_v, 0x80, i_pitch * i_height );\r
+ memset( p_a, 0x00, i_pitch * i_height );\r
+\r
+ return p_picture;\r
+}\r
+\r
+/*****************************************************************************\r
+ * Displays an OSD slider.\r
+ * Types are: OSD_HOR_SLIDER and OSD_VERT_SLIDER.\r
+ *****************************************************************************/\r
+picture_t *osd_Slider( int i_width, int i_height, int i_position, short i_type )\r
+{\r
+ picture_t *p_picture;\r
+ int i_x_margin, i_y_margin, i_x, i_y;\r
+\r
+ p_picture = osd_CreatePicture( i_width, i_height );\r
+ if( p_picture == NULL )\r
+ return NULL;\r
+\r
+ i_y_margin = i_height / 10;\r
+ i_x_margin = i_y_margin;\r
+ if( i_type == OSD_HOR_SLIDER )\r
+ {\r
+ i_width = i_width - 2 * i_x_margin;\r
+ i_height = i_height / 20;\r
+ i_x = i_x_margin;\r
+ i_y = i_height - i_y_margin - i_height;\r
+ }\r
+ else\r
+ {\r
+ i_width = i_width / 40;\r
+ i_height = i_height - 2 * i_y_margin;\r
+ i_x = i_width - i_x_margin - i_width;\r
+ i_y = i_y_margin;\r
+ }\r
+\r
+ if( i_type == OSD_HOR_SLIDER )\r
+ {\r
+ int i_x_pos = ( i_width - 2 ) * i_position / 100;\r
+ DrawRect( p_picture, i_x_pos - 1, 2, i_x_pos + 1,\r
+ i_height - 3, STYLE_FILLED );\r
+ DrawRect( p_picture, 0, 0, i_width - 1, i_height - 1, STYLE_EMPTY );\r
+ }\r
+ else if( i_type == OSD_VERT_SLIDER )\r
+ {\r
+ int i_y_pos = i_height / 2;\r
+ DrawRect( p_picture, 2, i_height - ( i_height - 2 ) * i_position / 100,\r
+ i_width - 3, i_height - 3, STYLE_FILLED );\r
+ DrawRect( p_picture, 1, i_y_pos, 1, i_y_pos, STYLE_FILLED );\r
+ DrawRect( p_picture, i_width - 2, i_y_pos,\r
+ i_width - 2, i_y_pos, STYLE_FILLED );\r
+ DrawRect( p_picture, 0, 0, i_width - 1, i_height - 1, STYLE_EMPTY );\r
+ }\r
+\r
+ return p_picture;\r
+}\r
+\r
+/*****************************************************************************\r
+ * Displays an OSD icon.\r
+ * Types are: OSD_PLAY_ICON, OSD_PAUSE_ICON, OSD_SPEAKER_ICON, OSD_MUTE_ICON\r
+ *****************************************************************************/\r
+picture_t *osd_Icon( int i_width, int i_height, short i_type )\r
+{\r
+ picture_t *p_picture = NULL;\r
+ int i_x_margin, i_y_margin, i_x, i_y;\r
+\r
+ p_picture = osd_CreatePicture( i_width, i_height );\r
+ if( p_picture == NULL )\r
+ return NULL;\r
+\r
+ i_y_margin = i_height / 15;\r
+ i_x_margin = i_y_margin;\r
+ i_x = i_width - i_x_margin - i_width;\r
+ i_y = i_y_margin;\r
+\r
+ if( i_type == OSD_PAUSE_ICON )\r
+ {\r
+ int i_bar_width = i_width / 3;\r
+ DrawRect( p_picture, 0, 0, i_bar_width - 1, i_height -1, STYLE_FILLED );\r
+ DrawRect( p_picture, i_width - i_bar_width, 0,\r
+ i_width - 1, i_height - 1, STYLE_FILLED );\r
+ }\r
+ else if( i_type == OSD_PLAY_ICON )\r
+ {\r
+ int i_mid = i_height >> 1;\r
+ int i_delta = ( i_width - i_mid ) >> 1;\r
+ int i_y2 = ( ( i_height - 1 ) >> 1 ) * 2;\r
+ DrawTriangle( p_picture, i_delta, 0, i_width - i_delta, i_y2,\r
+ STYLE_FILLED );\r
+ }\r
+ else if( i_type == OSD_SPEAKER_ICON || i_type == OSD_MUTE_ICON )\r
+ {\r
+ int i_mid = i_height >> 1;\r
+ int i_delta = ( i_width - i_mid ) >> 1;\r
+ int i_y2 = ( ( i_height - 1 ) >> 1 ) * 2;\r
+ DrawRect( p_picture, i_delta, i_mid / 2, i_width - i_delta,\r
+ i_height - 1 - i_mid / 2, STYLE_FILLED );\r
+ DrawTriangle( p_picture, i_width - i_delta, 0, i_delta, i_y2,\r
+ STYLE_FILLED );\r
+ if( i_type == OSD_MUTE_ICON )\r
+ {\r
+ uint8_t *p_a = p_picture->A_PIXELS;\r
+ int i_pitch = p_picture->Y_PITCH;\r
+ int i;\r
+ for( i = 1; i < i_pitch; i++ )\r
+ {\r
+ int k = i + ( i_height - i - 1 ) * i_pitch;\r
+ p_a[ k ] = 0xff - p_a[ k ];\r
+ }\r
+ }\r
+ }\r
+ \r
+ return p_picture;\r
+}\r