From 2f30d77a12f8a9af41f8103f91b6bc008ea5286e Mon Sep 17 00:00:00 2001 From: Vincent Seguin Date: Mon, 31 Jan 2000 16:56:37 +0000 Subject: [PATCH] =?UTF-8?q?Changement=20de=20cha=EF=BF=BDne=20configurable?= =?UTF-8?q?=20depuis=20un=20fichier=20texte.=20Quelques=20corrections=20es?= =?UTF-8?q?thetiques=20dans=20vout.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/common.h | 2 + include/config.h | 4 + include/interface.h | 5 +- src/interface/interface.c | 326 +++++++++++++++++++++++++++++--- src/interface/intf_cmd.c | 16 +- src/interface/main.c | 18 +- src/video_output/video_output.c | 6 +- vlc.channels | 3 + 8 files changed, 330 insertions(+), 50 deletions(-) create mode 100644 vlc.channels diff --git a/include/common.h b/include/common.h index b20e251334..d40741f295 100644 --- a/include/common.h +++ b/include/common.h @@ -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; diff --git a/include/config.h b/include/config.h index 74d1d66094..a6f1004db7 100644 --- a/include/config.h +++ b/include/config.h @@ -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 diff --git a/include/interface.h b/include/interface.h index b15869b48a..3791abb631 100644 --- a/include/interface.h +++ b/include/interface.h @@ -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 ); diff --git a/src/interface/interface.c b/src/interface/interface.c index b76caaff37..c329d99feb 100644 --- a/src/interface/interface.c +++ b/src/interface/interface.c @@ -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 ); +} diff --git a/src/interface/intf_cmd.c b/src/interface/intf_cmd.c index af02111a27..186536b72f 100644 --- a/src/interface/intf_cmd.c +++ b/src/interface/intf_cmd.c @@ -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 } diff --git a/src/interface/main.c b/src/interface/main.c index b13c868a71..07bc65bb3a 100644 --- a/src/interface/main.c +++ b/src/interface/main.c @@ -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 \tdisplay string\n" \ " --width , --height \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 "= \tinitialization script\n" \ + " " INTF_CHANNELS_VAR "= \tchannels list\n" \ ); /* Audio parameters */ @@ -440,17 +439,6 @@ static void Usage( void ) " " INPUT_VLAN_SERVER_VAR "= \tvlan server\n" \ " " INPUT_VLAN_PORT_VAR "= \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" \ - ); } /******************************************************************************* diff --git a/src/video_output/video_output.c b/src/video_output/video_output.c index 369e8fdfaf..9f571dc038 100644 --- a/src/video_output/video_output.c +++ b/src/video_output/video_output.c @@ -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, diff --git a/vlc.channels b/vlc.channels new file mode 100644 index 0000000000..776f3b4362 --- /dev/null +++ b/vlc.channels @@ -0,0 +1,3 @@ +0;Ptyx (caribou);20;caribou.via.ecp.fr; +1;Sam (bofh);20;bofh.via.ecp.fr; +2;Polux (dressler);20;dressler.via.ecp.fr;