Commit 2f30d77a authored by Vincent Seguin's avatar Vincent Seguin

Changement de cha�ne configurable depuis un fichier texte.

Quelques corrections esthetiques dans vout.
parent c80107b2
......@@ -39,11 +39,13 @@ struct intf_thread_s;
struct intf_sys_s;
struct intf_console_s;
struct intf_msg_s;
struct intf_channel_s;
typedef struct intf_thread_s * p_intf_thread_t;
typedef struct intf_sys_s * p_intf_sys_t;
typedef struct intf_console_s * p_intf_console_t;
typedef struct intf_msg_s * p_intf_msg_t;
typedef struct intf_channel_s * p_intf_channel_t;
/* Input */
struct input_thread_s;
......
......@@ -100,6 +100,10 @@
#define INTF_INIT_SCRIPT_VAR "vlc_init"
#define INTF_INIT_SCRIPT_DEFAULT "vlc.init"
/* Environment variable used to store channels file and default value */
#define INTF_CHANNELS_VAR "vlc_channels"
#define INTF_CHANNELS_DEFAULT "vlc.channels"
/* Base delay in micro second for interface sleeps */
#define INTF_IDLE_SLEEP 100000
......
......@@ -34,6 +34,9 @@ typedef struct intf_thread_s
p_intf_console_t p_console; /* console */
p_intf_sys_t p_sys; /* system interface */
/* Channels array - NULL if not used */
p_intf_channel_t p_channel; /* description of channels */
/* Main threads - NULL if not active */
p_vout_thread_t p_vout;
p_input_thread_t p_input;
......@@ -46,6 +49,6 @@ intf_thread_t * intf_Create ( void );
void intf_Run ( intf_thread_t * p_intf );
void intf_Destroy ( intf_thread_t * p_intf );
int intf_SelectInput ( intf_thread_t * p_intf, int i_index );
int intf_SelectChannel ( intf_thread_t * p_intf, int i_channel );
int intf_ProcessKey ( intf_thread_t * p_intf, int i_key );
......@@ -31,6 +31,34 @@
#include "intf_sys.h"
/*******************************************************************************
* intf_channel_t: channel description
*******************************************************************************
* A 'channel' is a descriptor of an input method. It is used to switch easily
* from source to source without having to specify the whole input thread
* configuration. The channels array, stored in the interface thread object, is
* loaded in intf_Create, and unloaded in intf_Destroy.
*******************************************************************************/
typedef struct intf_channel_s
{
/* Channel description */
int i_channel; /* channel number, -1 for end of array */
char * psz_description; /* channel description (owned) */
/* Input configuration */
int i_input_method; /* input method descriptor */
char * psz_input_source; /* source string (owned) */
int i_input_port; /* port */
int i_input_vlan; /* vlan */
} intf_channel_t;
/*******************************************************************************
* Local prototypes
*******************************************************************************/
static int LoadChannels ( intf_thread_t *p_intf, char *psz_filename );
static void UnloadChannels ( intf_thread_t *p_intf );
static int ParseChannel ( intf_channel_t *p_channel, char *psz_str );
/*******************************************************************************
* intf_Create: prepare interface before main loop
*******************************************************************************
......@@ -54,6 +82,11 @@ intf_thread_t* intf_Create( void )
p_intf->p_vout = NULL;
p_intf->p_input = NULL;
/* Load channels - the pointer will be set to NULL on failure. The
* return value is ignored since the program can work without
* channels */
LoadChannels( p_intf, main_GetPszVariable( INTF_CHANNELS_VAR, INTF_CHANNELS_DEFAULT ));
/* Start interfaces */
p_intf->p_console = intf_ConsoleCreate();
if( p_intf->p_console == NULL )
......@@ -126,39 +159,55 @@ void intf_Destroy( intf_thread_t *p_intf )
/* Destroy interfaces */
intf_SysDestroy( p_intf );
intf_ConsoleDestroy( p_intf->p_console );
/* Unload channels */
UnloadChannels( p_intf );
/* Free structure */
free( p_intf );
}
/*******************************************************************************
* intf_SelectInput: change input stream
* intf_SelectChannel: change channel
*******************************************************************************
* Kill existing input, if any, and try to open a new one, using an input
* configuration table.
*******************************************************************************/
int intf_SelectInput( intf_thread_t * p_intf, int i_index )
int intf_SelectChannel( intf_thread_t * p_intf, int i_channel )
{
intf_DbgMsg("\n");
/* If VLANs are not active, return with an error */
if( !p_main->b_vlans )
{
intf_ErrMsg("error: VLANs are not activated\n");
return( 1 );
}
intf_channel_t * p_channel; /* channel */
/* Kill existing input, if any */
if( p_intf->p_input != NULL )
{
input_DestroyThread( p_intf->p_input, NULL );
/* Look for channel in array */
if( p_intf->p_channel != NULL )
{
for( p_channel = p_intf->p_channel; p_channel->i_channel != -1; p_channel++ )
{
if( p_channel->i_channel == i_channel )
{
/*
* Change channel
*/
/* Kill existing input, if any */
if( p_intf->p_input != NULL )
{
input_DestroyThread( p_intf->p_input, NULL );
}
intf_Msg("Channel %d: %s\n", i_channel, p_channel->psz_description );
/* Open a new input */
p_intf->p_input = input_CreateThread( p_channel->i_input_method, p_channel->psz_input_source,
p_channel->i_input_port, p_channel->i_input_vlan,
p_intf->p_vout, p_main->p_aout, NULL );
return( p_intf->p_input == NULL );
}
}
}
/* Open a new input */
intf_Msg("Switching to channel %d\n", i_index );
p_intf->p_input = input_CreateThread( INPUT_METHOD_TS_VLAN_BCAST, NULL, 0, i_index,
p_intf->p_vout, p_main->p_aout, NULL );
return( p_intf->p_input == NULL );
/* Channel does not exist */
intf_Msg("Channel %d does not exist\n", i_channel );
return( 1 );
}
/*******************************************************************************
......@@ -186,10 +235,9 @@ int intf_ProcessKey( intf_thread_t *p_intf, int i_key )
case '7':
case '8':
case '9':
if( intf_SelectInput( p_intf, i_key - '0' ) )
{
intf_ErrMsg("error: can not open channel %d\n", i_key - '0');
}
/* Change channel - return code is ignored since SelectChannel displays
* its own error messages */
intf_SelectChannel( p_intf, i_key - '0' );
break;
case '+': /* volume + */
// ??
......@@ -262,5 +310,235 @@ int intf_ProcessKey( intf_thread_t *p_intf, int i_key )
return( 0 );
}
/* following functions are local */
/*******************************************************************************
* LoadChannels: load channels description from a file
*******************************************************************************
* This structe describes all interface-specific data of the main (interface)
* thread.
* Each line of the file is a semicolon separated list of the following
* fields :
* integer channel number
* string channel description
* integer input method (see input.h)
* string input source
* integer input port
* integer input vlan
* The last field must end with a semicolon.
* Comments and empty lines are not explicitely allowed, but lines with parsing
* errors are ignored without warning.
*******************************************************************************/
static int LoadChannels( intf_thread_t *p_intf, char *psz_filename )
{
FILE * p_file; /* file */
intf_channel_t * p_channel; /* current channel */
char psz_line[INTF_MAX_CMD_SIZE]; /* line buffer */
int i_index; /* channel or field index */
/* Set default value */
p_intf->p_channel = NULL;
/* Open file */
p_file = fopen( psz_filename, "r" );
if( p_file == NULL )
{
intf_ErrMsg("error: can't open %s (%s)\n", psz_filename, strerror(errno));
return( 1 );
}
/* First pass: count number of lines */
for( i_index = 0; fgets( psz_line, INTF_MAX_CMD_SIZE, p_file ) != NULL; i_index++ )
{
;
}
if( i_index != 0 )
{
/* Allocate array and rewind - some of the lines may be invalid, and the
* array will probably be larger than the actual number of channels, but
* it has no consequence. */
p_intf->p_channel = malloc( sizeof( intf_channel_t ) * i_index );
if( p_intf->p_channel == NULL )
{
intf_ErrMsg("error: %s\n", strerror(ENOMEM));
fclose( p_file );
return( 1 );
}
p_channel = p_intf->p_channel;
rewind( p_file );
/* Second pass: read channels descriptions */
while( fgets( psz_line, INTF_MAX_CMD_SIZE, p_file ) != NULL )
{
if( !ParseChannel( p_channel, psz_line ) )
{
intf_DbgMsg("channel [%d] %s : method %d (%s:%d vlan %d)\n",
p_channel->i_channel, p_channel->psz_description,
p_channel->i_input_method, p_channel->psz_input_source,
p_channel->i_input_port, p_channel->i_input_vlan );
p_channel++;
}
}
/* Add marker at the end of the array */
p_channel->i_channel = -1;
}
/* Close file */
fclose( p_file );
return( 0 );
}
/******************************************************************************
* UnloadChannels: unload channels description
******************************************************************************
* This function free all resources allocated by LoadChannels, if any.
******************************************************************************/
static void UnloadChannels( intf_thread_t *p_intf )
{
int i_channel; /* channel index */
if( p_intf->p_channel != NULL )
{
/* Free allocated strings */
for( i_channel = 0;
p_intf->p_channel[ i_channel ].i_channel != -1;
i_channel++ )
{
if( p_intf->p_channel[ i_channel ].psz_description != NULL )
{
free( p_intf->p_channel[ i_channel ].psz_description );
}
if( p_intf->p_channel[ i_channel ].psz_input_source != NULL )
{
free( p_intf->p_channel[ i_channel ].psz_input_source );
}
}
/* Free array */
free( p_intf->p_channel );
p_intf->p_channel = NULL;
}
}
/*******************************************************************************
* ParseChannel: parse a channel description line
*******************************************************************************
* See LoadChannels. This function return non 0 on parsing error.
*******************************************************************************/
static int ParseChannel( intf_channel_t *p_channel, char *psz_str )
{
char * psz_index; /* current character */
char * psz_end; /* end pointer for strtol */
int i_field; /* field number, -1 on error */
int i_field_length; /* field length, for text fields */
/* Set some default fields */
p_channel->i_channel = 0;
p_channel->psz_description = NULL;
p_channel->i_input_method = 0;
p_channel->psz_input_source = NULL;
p_channel->i_input_port = 0;
p_channel->i_input_vlan = 0;
/* Parse string */
i_field = 0;
for( psz_index = psz_str; (i_field != -1) && (*psz_index != '\0'); psz_index++ )
{
if( *psz_index == ';' )
{
/* Mark end of field */
*psz_index = '\0';
/* Parse field */
switch( i_field++ )
{
case 0: /* channel number */
p_channel->i_channel = strtol( psz_str, &psz_end, 0);
if( (*psz_str == '\0') || (*psz_end != '\0') )
{
i_field = -1;
}
break;
case 1: /* channel description */
i_field_length = strlen( psz_str );
if( i_field_length != 0 )
{
p_channel->psz_description = malloc( i_field_length + 1 );
if( p_channel->psz_description == NULL )
{
intf_ErrMsg("error: %s\n", strerror( ENOMEM ));
i_field = -1;
}
else
{
strcpy( p_channel->psz_description, psz_str );
}
}
break;
case 2: /* input method */
p_channel->i_input_method = strtol( psz_str, &psz_end, 0);
if( (*psz_str == '\0') || (*psz_end != '\0') )
{
i_field = -1;
}
break;
case 3: /* input source */
i_field_length = strlen( psz_str );
if( i_field_length != 0 )
{
p_channel->psz_input_source = malloc( i_field_length + 1 );
if( p_channel->psz_input_source == NULL )
{
intf_ErrMsg("error: %s\n", strerror( ENOMEM ));
i_field = -1;
}
else
{
strcpy( p_channel->psz_input_source, psz_str );
}
}
break;
case 4: /* input port */
p_channel->i_input_port = strtol( psz_str, &psz_end, 0);
if( (*psz_str == '\0') || (*psz_end != '\0') )
{
i_field = -1;
}
break;
case 5: /* input vlan */
p_channel->i_channel = strtol( psz_str, &psz_end, 0);
if( (*psz_str == '\0') || (*psz_end != '\0') )
{
i_field = -1;
}
break;
/* ... following fields are ignored */
}
/* Set new beginning of field */
psz_str = psz_index + 1;
}
}
/* At least the first three fields must be parsed sucessfully for function
* success. Other parsing errors are returned using i_field = -1. */
if( i_field < 3 )
{
/* Function fails. Free allocated strings */
if( p_channel->psz_description != NULL )
{
free( p_channel->psz_description );
}
if( p_channel->psz_input_source != NULL )
{
free( p_channel->psz_input_source );
}
return( 1 );
}
/* Return success */
return( 0 );
}
......@@ -69,7 +69,7 @@ int intf_ExecCommand( char *psz_cmd )
int i_index; /* multi-purposes index */
int i_return; /* command return value */
intf_DbgMsg("intf debug: command `%s'\n", psz_cmd);
intf_DbgMsg("command `%s'\n", psz_cmd);
/* Parse command line (separate arguments). If nothing has been found,
* the function returns without error */
......@@ -110,7 +110,7 @@ int intf_ExecCommand( char *psz_cmd )
{
case INTF_FATAL_ERROR: /* fatal error */
/* Print message and terminates the interface thread */
intf_ErrMsg( "intf fatal: in command `%s'\n", psz_argv[0] );
intf_ErrMsg( "fatal error in command `%s'\n", psz_argv[0] );
p_main->p_intf->b_die = 1;
break;
......@@ -118,7 +118,7 @@ int intf_ExecCommand( char *psz_cmd )
/* Print message, flush messages queue and exit. Note that this
* error should be very rare since it does not even try to cancel other
* threads... */
intf_ErrMsg("intf critical: in command `%s'. Please report this error !\n", psz_argv[0] );
intf_ErrMsg("critical error in command `%s'. Please report this error !\n", psz_argv[0] );
intf_FlushMsg();
exit( INTF_CRITICAL_ERROR );
break;
......@@ -153,7 +153,7 @@ int intf_ExecScript( char *psz_filename )
p_file = fopen( psz_filename, "r" );
if( p_file == NULL )
{
intf_ErrMsg("intf error: %s: %s\n", psz_filename, strerror(errno));
intf_ErrMsg("warning: %s: %s\n", psz_filename, strerror(errno));
return( -1 );
}
......@@ -180,7 +180,7 @@ int intf_ExecScript( char *psz_filename )
}
if( !feof( p_file ) )
{
intf_ErrMsg("intf error: %s: %s\n", psz_filename, strerror(errno));
intf_ErrMsg("error: %s: %s\n", psz_filename, strerror(errno));
return( -1 );
}
......@@ -393,7 +393,7 @@ static int CheckCommandArguments( intf_arg_t argv[INTF_MAX_ARGS], int i_argc,
return( 1 );
}
intf_DbgMsg("intf debug: argument flags=0x%x (index=%d) name=%s str=%s int=%d float=%f\n",
intf_DbgMsg("argument flags=0x%x (index=%d) name=%s str=%s int=%d float=%f\n",
argv[i_arg].i_flags,
argv[i_arg].i_index,
(argv[i_arg].i_flags & INTF_NAMED_ARG) ? argv[i_arg].ps_name : "NA",
......@@ -462,7 +462,7 @@ static int ConvertArgument( intf_arg_t *p_arg, int i_flags, char *psz_str )
#ifdef DEBUG
else /* error: missing type specifier */
{
intf_ErrMsg("intf error: missing type specifier for `%s' (0x%x)\n", psz_str, i_flags);
intf_ErrMsg("error: missing type specifier for `%s' (0x%x)\n", psz_str, i_flags);
return( 1 );
}
#endif
......@@ -531,7 +531,7 @@ static void ParseFormatString( intf_arg_t format[INTF_MAX_ARGS], char *psz_forma
break;
#ifdef DEBUG
default: /* error which should never happen: incorrect format */
intf_DbgMsg("intf error: incorrect format string `%s'\n", psz_format);
intf_DbgMsg("error: incorrect format string `%s'\n", psz_format);
break;
#endif
}
......
......@@ -399,11 +399,9 @@ static void Usage( void )
/* Options */
intf_Msg("Options:\n" \
" -h, --help \tprint usage\n" \
" -v, --version \tprint program version\n" \
" --noaudio \tdisable audio\n" \
" -h, --help, -v, --version \tprint usage or version\n" \
" --noaudio, --novideo \tdisable audio/video\n" \
" --stereo, --mono \tstereo/mono audio\n" \
" --novideo \tdisable video\n" \
" --display <display> \tdisplay string\n" \
" --width <w>, --height <h> \tdisplay dimensions\n" \
" -g, --grayscale, --color \tgrayscale/color video\n" \
......@@ -414,6 +412,7 @@ static void Usage( void )
/* Interface parameters */
intf_Msg("Interface parameters:\n" \
" " INTF_INIT_SCRIPT_VAR "=<filename> \tinitialization script\n" \
" " INTF_CHANNELS_VAR "=<filename> \tchannels list\n" \
);
/* Audio parameters */
......@@ -440,17 +439,6 @@ static void Usage( void )
" " INPUT_VLAN_SERVER_VAR "=<hostname> \tvlan server\n" \
" " INPUT_VLAN_PORT_VAR "=<port> \tvlan server port\n" \
);
/* Interfaces keys */
intf_Msg("Interface keys: most interfaces accept the following commands:\n" \
" [space] \ttoggle interface\n"
" [esc], q \tquit\n" \
" 0 - 9 \tselect channel\n" \
" +, -, m \tchange volume, mute\n" \
" g, G, c \tchange gamma, toggle grayscale\n" \
" i \ttoggle info printing\n" \
" s \ttoggle picture scaling\n" \
);
}
/*******************************************************************************
......
......@@ -808,7 +808,6 @@ static void RunThread( vout_thread_t *p_vout)
}
else if( p_vout->b_active ) /* idle or interface screen alone */
{
//?? clear: SetBufferPicture( p_vout, NULL );
if( p_vout->b_interface && 0 /* && ?? intf_change */ )
{
/* Interface has changed, so a new rendering is required - force
......@@ -1403,6 +1402,8 @@ static void RenderPictureInfo( vout_thread_t *p_vout, picture_t *p_pic )
* nothing has been rendered, or 1 if something has been changed on the screen.
* Note that if you absolutely want something to be printed, you will have
* to force it by setting the last idle date to 0.
* Unlike other rendering functions, this one calls the SetBufferPicture
* function when needed.
******************************************************************************/
static int RenderIdle( vout_thread_t *p_vout )
{
......@@ -1416,10 +1417,11 @@ static int RenderIdle( vout_thread_t *p_vout )
if( (current_date - p_vout->last_display_date) > VOUT_IDLE_DELAY &&
(current_date - p_vout->last_idle_date) > VOUT_IDLE_DELAY )
{
SetBufferPicture( p_vout, NULL );
vout_TextSize( p_vout->p_large_font, WIDE_TEXT | OUTLINED_TEXT, psz_text,
&i_width, &i_height );
if( !Align( p_vout, &i_x, &i_y, i_width, i_height, CENTER_RALIGN, CENTER_RALIGN ) )
{
{
vout_Print( p_vout->p_large_font,
p_vout->p_buffer[ p_vout->i_buffer_index ].p_data +
i_x * p_vout->i_bytes_per_pixel + i_y * p_vout->i_bytes_per_line,
......
0;Ptyx (caribou);20;caribou.via.ecp.fr;
1;Sam (bofh);20;bofh.via.ecp.fr;
2;Polux (dressler);20;dressler.via.ecp.fr;
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment