/***************************************************************************** * main.c: main vlc source * Includes the main() function for vlc. Parses command line, start interface * and spawn threads. ***************************************************************************** * Copyright (C) 1998-2001 VideoLAN * $Id: main.c,v 1.156 2002/02/26 18:25:40 gbazin Exp $ * * Authors: Vincent Seguin <seguin@via.ecp.fr> * Samuel Hocevar <sam@zoy.org> * Gildas Bazin <gbazin@netcourrier.com> * * 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 implied 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 <signal.h> /* SIGHUP, SIGINT, SIGKILL */ #include <stdio.h> /* sprintf() */ #include <setjmp.h> /* longjmp, setjmp */ #include <videolan/vlc.h> #ifdef HAVE_GETOPT_LONG # ifdef HAVE_GETOPT_H # include <getopt.h> /* getopt() */ # endif #else # include "GNUgetopt/getopt.h" #endif #ifdef SYS_DARWIN # include <mach/mach.h> /* Altivec detection */ # include <mach/mach_error.h> /* some day the header files||compiler * will define it for us */ # include <mach/bootstrap.h> #endif #ifndef WIN32 # include <netinet/in.h> /* BSD: struct in_addr */ #endif #ifdef HAVE_UNISTD_H # include <unistd.h> #elif defined( _MSC_VER ) && defined( _WIN32 ) # include <io.h> #endif #ifdef HAVE_LOCALE_H # include <locale.h> #endif #include <errno.h> /* ENOMEM */ #include <stdlib.h> /* getenv(), strtol(), */ #include <string.h> /* strerror() */ #include <fcntl.h> /* open(), O_WRONLY */ #include <sys/stat.h> /* S_IREAD */ #include "netutils.h" /* network_ChannelJoin */ #include "stream_control.h" #include "input_ext-intf.h" #include "intf_playlist.h" #include "interface.h" #include "audio_output.h" #include "video.h" #include "video_output.h" #include "debug.h" /***************************************************************************** * Configuration options for the main program. Each plugin will also separatly * define its own configuration options. * Look into configuration.h if you need to know more about the following * macros. * *****************************************************************************/ #define BUILTIN #define MODULE_NAME main #include "modules_inner.h" /* for configuration stuff */ /* Quick usage guide MODULE_CONFIG_START MODULE_CONFIG_STOP ADD_CATEGORY_HINT( text, longtext ) ADD_SUBCATEGORY_HINT( text, longtext ) ADD_STRING( option_name, value, p_callback, text, longtext ) ADD_FILE( option_name, psz_value, p_callback, text, longtext ) ADD_PLUGIN( option_name, psz_value, i_capability, p_callback, text, longtext ) ADD_INTEGER( option_name, i_value, p_callback, text, longtext ) ADD_BOOL( option_name, p_callback, text, longtext ) */ MODULE_CONFIG_START /* Help options */ ADD_CATEGORY_HINT( "Help Options", NULL ) ADD_BOOL ( "help", NULL,"print help and exit (or use -h)", NULL ) ADD_BOOL ( "longhelp", NULL, "print long help version and exit (or use -H)", NULL ) ADD_BOOL ( "list", NULL, "list available plugins (or use -l)", NULL ) ADD_STRING ( "pluginhelp", NULL, NULL,"print help on a plugin and exit",NULL ) ADD_BOOL ( "version", NULL, "output version information and exit", NULL ) /* Interface options */ ADD_CATEGORY_HINT( "Interface Options", NULL) ADD_PLUGIN ( INTF_METHOD_VAR, MODULE_CAPABILITY_INTF, NULL, NULL, "interface method", NULL ) ADD_INTEGER ( INTF_WARNING_VAR, 0, NULL, "warning level (or use -v)", NULL ) ADD_BOOL ( INTF_STATS_VAR, NULL, "output statistics", NULL ) ADD_STRING ( INTF_PATH_VAR, NULL, NULL, "interface default search path", NULL) /* Audio Options */ ADD_CATEGORY_HINT( "Audio Options", NULL) ADD_BOOL ( AOUT_NOAUDIO_VAR, NULL, "disable audio", NULL ) ADD_PLUGIN ( AOUT_METHOD_VAR, MODULE_CAPABILITY_AOUT, NULL, NULL, "audio output method", NULL ) ADD_BOOL ( AOUT_MONO_VAR, NULL, "mono audio", NULL ) ADD_INTEGER ( AOUT_VOLUME_VAR, VOLUME_DEFAULT, NULL, "VLC output volume", NULL) ADD_INTEGER ( AOUT_RATE_VAR, 44100, NULL, "VLC output frequency", NULL ) ADD_INTEGER ( AOUT_DESYNC_VAR, 0, NULL, "Compensate desynchronization of the " "audio (in ms)", NULL ) /* Video options */ ADD_CATEGORY_HINT( "Video Options", NULL ) ADD_BOOL ( VOUT_NOVIDEO_VAR, NULL, "disable video", NULL ) ADD_PLUGIN ( VOUT_METHOD_VAR, MODULE_CAPABILITY_VOUT, NULL, NULL, "video output method", NULL ) ADD_STRING ( VOUT_DISPLAY_VAR, NULL, NULL, "display string", NULL ) ADD_INTEGER ( VOUT_WIDTH_VAR, 720, NULL, "display width", NULL ) ADD_INTEGER ( VOUT_HEIGHT_VAR, 576, NULL, "display height", NULL ) ADD_BOOL ( VOUT_GRAYSCALE_VAR, NULL, "grayscale output", NULL ) ADD_BOOL ( VOUT_FULLSCREEN_VAR, NULL, "fullscreen output", NULL ) ADD_BOOL ( VOUT_NOOVERLAY_VAR, NULL, "disable accelerated display", NULL ) ADD_PLUGIN ( VOUT_FILTER_VAR, MODULE_CAPABILITY_VOUT, NULL, NULL, "video filter module", NULL ) ADD_INTEGER ( VOUT_SPUMARGIN_VAR, -1, NULL, "force SPU position", NULL ) /* Input options */ ADD_CATEGORY_HINT( "Input Options", NULL ) ADD_STRING ( INPUT_METHOD_VAR, NULL, NULL, "input method", NULL ) ADD_INTEGER ( INPUT_PORT_VAR, 1234, NULL, "server port", NULL ) ADD_BOOL ( INPUT_NETWORK_CHANNEL_VAR, NULL, "enable network channel mode", NULL ) ADD_STRING ( INPUT_CHANNEL_SERVER_VAR, "localhost", NULL, "channel server address", NULL ) ADD_INTEGER ( INPUT_CHANNEL_PORT_VAR, 6010, NULL, "channel server port", NULL ) ADD_STRING ( INPUT_IFACE_VAR, "eth0", NULL, "network interface", NULL ) ADD_INTEGER ( INPUT_TITLE_VAR, -1, NULL, "choose title", NULL ) ADD_INTEGER ( INPUT_CHAPTER_VAR, -1, NULL, "choose chapter", NULL ) ADD_INTEGER ( INPUT_ANGLE_VAR, -1, NULL, "chosse angle", NULL ) ADD_INTEGER ( INPUT_AUDIO_VAR, -1, NULL, "choose audio", NULL ) ADD_INTEGER ( INPUT_CHANNEL_VAR, -1, NULL, "choose channel", NULL ) ADD_INTEGER ( INPUT_SUBTITLE_VAR, -1, NULL, "choose subtitles", NULL ) ADD_STRING ( INPUT_DVD_DEVICE_VAR, "/dev/dvd", NULL, "DVD device", NULL ) ADD_STRING ( INPUT_VCD_DEVICE_VAR, "/dev/cdrom", NULL, "VCD device", NULL ) /* Decoder options */ ADD_CATEGORY_HINT( "Decoders Options", NULL ) ADD_PLUGIN ( ADEC_MPEG_VAR, MODULE_CAPABILITY_DECODER, NULL, NULL, "choose MPEG audio decoder", NULL ) ADD_PLUGIN ( ADEC_AC3_VAR, MODULE_CAPABILITY_DECODER, NULL, NULL, "choose AC3 audio decoder", NULL ) ADD_INTEGER ( VDEC_SMP_VAR, 0, NULL, "use additional processors", NULL ) ADD_STRING ( VPAR_SYNCHRO_VAR, NULL, NULL, "force synchro algorithm " "{I|I+|IP|IP+|IPB}", NULL ) /* CPU options */ ADD_CATEGORY_HINT( "CPU Options Options", NULL ) ADD_BOOL ( NOMMX_VAR, NULL, "disable CPU's MMX support", NULL ) ADD_BOOL ( NO3DN_VAR, NULL, "disable CPU's 3D Now! support", NULL ) ADD_BOOL ( NOMMXEXT_VAR, NULL, "disable CPU's MMX EXT support", NULL ) ADD_BOOL ( NOSSE_VAR, NULL, "disable CPU's SSE support", NULL ) ADD_BOOL ( NOALTIVEC_VAR, NULL, "disable CPU's AltiVec support", NULL ) /* Playlist options */ ADD_BOOL ( PLAYLIST_STARTUP_VAR, NULL, "launch playlist on startup", NULL ) ADD_BOOL ( PLAYLIST_ENQUEUE_VAR, NULL, "enqueue playlist as default", NULL ) ADD_BOOL ( PLAYLIST_LOOP_VAR, NULL, "loop on playlist end", NULL ) /* Misc options */ ADD_CATEGORY_HINT( "Miscellaneous Options", NULL ) ADD_PLUGIN ( MEMCPY_METHOD_VAR, MODULE_CAPABILITY_MEMCPY, NULL, NULL, "memory copy method", NULL ) MODULE_CONFIG_STOP MODULE_INIT_START SET_DESCRIPTION( "Main program" ) ADD_CAPABILITY( MAIN, 100/*whatever*/ ) MODULE_INIT_STOP MODULE_ACTIVATE_START MODULE_ACTIVATE_STOP MODULE_DEACTIVATE_START MODULE_DEACTIVATE_STOP /***************************************************************************** * End configuration. *****************************************************************************/ /***************************************************************************** * Global variables - these are the only ones, see main.h and modules.h *****************************************************************************/ main_t *p_main; module_bank_t *p_module_bank; input_bank_t *p_input_bank; aout_bank_t *p_aout_bank; vout_bank_t *p_vout_bank; /***************************************************************************** * Local prototypes *****************************************************************************/ static int GetConfigurationFromFile ( void ){return 0;}; static int GetConfigurationFromCmdLine ( int *pi_argc, char *ppsz_argv[], boolean_t b_ignore_errors ); static int GetFilenames ( int i_argc, char *ppsz_argv[] ); static void Usage ( const char *psz_module_name ); static void ListModules ( void ); static void Version ( void ); static void InitSignalHandler ( void ); static void SimpleSignalHandler ( int i_signal ); static void FatalSignalHandler ( int i_signal ); static void IllegalSignalHandler ( int i_signal ); static u32 CPUCapabilities ( void ); #ifdef WIN32 static void ShowConsole ( void ); #endif static jmp_buf env; static int i_illegal; static char *psz_capability; /***************************************************************************** * main: parse command line, start interface and spawn threads ***************************************************************************** * Steps during program execution are: * -configuration parsing and messages interface initialization * -opening of audio output device and some global modules * -execution of interface, which exit on error or on user request * -closing of audio output device and some global modules * On error, the spawned threads are canceled, and the open devices closed. *****************************************************************************/ int main( int i_argc, char *ppsz_argv[], char *ppsz_env[] ) { main_t main_data; /* root of all data - see main.h */ module_bank_t module_bank; input_bank_t input_bank; aout_bank_t aout_bank; vout_bank_t vout_bank; char *p_tmp; p_main = &main_data; /* set up the global variables */ p_module_bank = &module_bank; p_input_bank = &input_bank; p_aout_bank = &aout_bank; p_vout_bank = &vout_bank; p_main->i_warning_level = 0; #if defined( ENABLE_NLS ) && defined ( HAVE_GETTEXT ) /* * Support for getext */ #if defined( HAVE_LOCALE_H ) && defined( HAVE_LC_MESSAGES ) if( !setlocale( LC_MESSAGES, "" ) ) { fprintf( stderr, "warning: unsupported locale.\n" ); } #endif if( !bindtextdomain( PACKAGE, LOCALEDIR ) ) { fprintf( stderr, "warning: no domain %s in directory %s\n", PACKAGE, LOCALEDIR ); } textdomain( PACKAGE ); #endif /* * Initialize threads system */ vlc_threads_init( ); /* * Test if our code is likely to run on this CPU */ p_main->i_cpu_capabilities = CPUCapabilities(); /* * System specific initialization code */ #if defined( SYS_BEOS ) || defined( SYS_DARWIN ) || defined( WIN32 ) system_Init( &i_argc, ppsz_argv, ppsz_env ); #elif defined( SYS_LINUX ) # ifdef DEBUG /* Activate malloc checking routines to detect heap corruptions. */ putenv( "MALLOC_CHECK_=2" ); # endif #endif /* * Initialize messages interface */ intf_MsgCreate(); intf_Msg( COPYRIGHT_MESSAGE "\n" ); /* Get the executable name (similar to the basename command) */ p_main->psz_arg0 = p_tmp = ppsz_argv[ 0 ]; while( *p_tmp ) { if( *p_tmp == '/' ) p_main->psz_arg0 = ++p_tmp; else ++p_tmp; } /* * Initialize the module bank and and load the configuration of the main * module. We need to do this at this stage to be able to display a short * help if required by the user. (short help == main module options) */ module_InitBank(); module_LoadMain(); if( GetConfigurationFromCmdLine( &i_argc, ppsz_argv, 1 ) ) { intf_MsgDestroy(); return( errno ); } /* Check for short help option */ if( config_GetIntVariable( "help" ) ) { Usage( "main" ); return( -1 ); } /* Check for version option */ if( config_GetIntVariable( "version" ) ) { Version(); return( -1 ); } /* * Load the builtins and plugins into the module_bank. * We have to do it before GetConfiguration() because this also gets the * list of configuration options exported by each plugin and loads their * default values. */ module_LoadBuiltins(); module_LoadPlugins(); intf_WarnMsg( 2, "module: module bank initialized, found %i modules", p_module_bank->i_count ); /* Check for help on plugins */ if( (p_tmp = config_GetPszVariable( "pluginhelp" )) ) { Usage( p_tmp ); free( p_tmp ); return( -1 ); } /* Check for long help option */ if( config_GetIntVariable( "longhelp" ) ) { Usage( NULL ); return( -1 ); } /* Check for plugin list option */ if( config_GetIntVariable( "list" ) ) { ListModules(); return( -1 ); } /* * Override default configuration with config file settings */ if( GetConfigurationFromFile() ) { intf_MsgDestroy(); return( errno ); } /* * Override configuration with command line settings */ if( GetConfigurationFromCmdLine( &i_argc, ppsz_argv, 0 ) ) { intf_MsgDestroy(); return( errno ); } /* p_main inititalization. FIXME ? */ p_main->i_desync = (mtime_t)config_GetIntVariable( AOUT_DESYNC_VAR ) * (mtime_t)1000; p_main->b_stats = config_GetIntVariable( INTF_STATS_VAR ); p_main->b_audio = !config_GetIntVariable( AOUT_NOAUDIO_VAR ); p_main->b_stereo= !config_GetIntVariable( AOUT_MONO_VAR ); p_main->b_video = !config_GetIntVariable( VOUT_NOVIDEO_VAR ); if( config_GetIntVariable( NOMMX_VAR ) ) p_main->i_cpu_capabilities &= ~CPU_CAPABILITY_MMX; if( config_GetIntVariable( NO3DN_VAR ) ) p_main->i_cpu_capabilities &= ~CPU_CAPABILITY_3DNOW; if( config_GetIntVariable( NOMMXEXT_VAR ) ) p_main->i_cpu_capabilities &= ~CPU_CAPABILITY_MMXEXT; if( config_GetIntVariable( NOSSE_VAR ) ) p_main->i_cpu_capabilities &= ~CPU_CAPABILITY_SSE; if( config_GetIntVariable( NOALTIVEC_VAR ) ) p_main->i_cpu_capabilities &= ~CPU_CAPABILITY_ALTIVEC; if( p_main->b_stats ) { char p_capabilities[200]; p_capabilities[0] = '\0'; #define PRINT_CAPABILITY( capability, string ) \ if( p_main->i_cpu_capabilities & capability ) \ { \ strncat( p_capabilities, string " ", \ sizeof(p_capabilities) - strlen(p_capabilities) ); \ p_capabilities[sizeof(p_capabilities) - 1] = '\0'; \ } PRINT_CAPABILITY( CPU_CAPABILITY_486, "486" ); PRINT_CAPABILITY( CPU_CAPABILITY_586, "586" ); PRINT_CAPABILITY( CPU_CAPABILITY_PPRO, "Pentium Pro" ); PRINT_CAPABILITY( CPU_CAPABILITY_MMX, "MMX" ); PRINT_CAPABILITY( CPU_CAPABILITY_3DNOW, "3DNow!" ); PRINT_CAPABILITY( CPU_CAPABILITY_MMXEXT, "MMXEXT" ); PRINT_CAPABILITY( CPU_CAPABILITY_SSE, "SSE" ); PRINT_CAPABILITY( CPU_CAPABILITY_ALTIVEC, "Altivec" ); PRINT_CAPABILITY( CPU_CAPABILITY_FPU, "FPU" ); intf_StatMsg( "info: CPU has capabilities : %s", p_capabilities ); } /* * Initialize playlist and get commandline files */ p_main->p_playlist = intf_PlaylistCreate(); if( !p_main->p_playlist ) { intf_ErrMsg( "playlist error: playlist initialization failed" ); intf_MsgDestroy(); return( errno ); } intf_PlaylistInit( p_main->p_playlist ); /* * Get input filenames given as commandline arguments */ GetFilenames( i_argc, ppsz_argv ); /* * Initialize input, aout and vout banks */ input_InitBank(); aout_InitBank(); vout_InitBank(); /* * Choose the best memcpy module */ p_main->p_memcpy_module = module_Need( MODULE_CAPABILITY_MEMCPY, NULL, NULL ); if( p_main->p_memcpy_module == NULL ) { intf_ErrMsg( "intf error: no suitable memcpy module, " "using libc default" ); p_main->pf_memcpy = memcpy; } else { p_main->pf_memcpy = p_main->p_memcpy_module->p_functions ->memcpy.functions.memcpy.pf_memcpy; } /* * Initialize shared resources and libraries */ if( config_GetIntVariable( INPUT_NETWORK_CHANNEL_VAR ) && network_ChannelCreate() ) { /* On error during Channels initialization, switch off channels */ intf_ErrMsg( "intf error: channels initialization failed, " "deactivating channels" ); config_PutIntVariable( INPUT_NETWORK_CHANNEL_VAR, 0 ); } /* * Try to run the interface */ p_main->p_intf = intf_Create(); if( p_main->p_intf == NULL ) { intf_ErrMsg( "intf error: interface initialization failed" ); } else { /* * Set signal handling policy for all threads */ InitSignalHandler(); /* * This is the main loop */ p_main->p_intf->pf_run( p_main->p_intf ); /* * Finished, destroy the interface */ intf_Destroy( p_main->p_intf ); /* * Go back into channel 0 which is the network */ if( config_GetIntVariable( INPUT_NETWORK_CHANNEL_VAR ) ) { network_ChannelJoin( COMMON_CHANNEL ); } } /* * Free input, aout and vout banks */ input_EndBank(); vout_EndBank(); aout_EndBank(); /* * Free playlist */ intf_PlaylistDestroy( p_main->p_playlist ); /* * Free memcpy module if it was allocated */ if( p_main->p_memcpy_module != NULL ) { module_Unneed( p_main->p_memcpy_module ); } /* * Free module bank */ module_EndBank(); /* * System specific cleaning code */ #if defined( SYS_BEOS ) || defined( SYS_DARWIN ) || defined( WIN32 ) system_End(); #endif /* * Terminate messages interface and program */ intf_WarnMsg( 1, "intf: program terminated" ); intf_MsgDestroy(); /* * Stop threads system */ vlc_threads_end( ); return 0; } /* following functions are local */ /***************************************************************************** * GetConfigurationFromCmdLine: parse command line ***************************************************************************** * Parse command line for configuration. If the inline help is requested, the * function Usage() is called and the function returns -1 (causing main() to * exit). * Now that the module_bank has been initialized, we can dynamically * generate the longopts structure used by getops. We have to do it this way * because we don't know (and don't want to know) in advance the configuration * options used (ie. exported) by each module. *****************************************************************************/ static int GetConfigurationFromCmdLine( int *pi_argc, char *ppsz_argv[], boolean_t b_ignore_errors ) { int i_cmd, i, i_index, i_longopts_size; module_t *p_module; struct option *p_longopts; /* Short options */ const char *psz_shortopts = "hHvl"; /* Set default configuration and copy arguments */ p_main->i_argc = *pi_argc; p_main->ppsz_argv = ppsz_argv; p_main->p_channel = NULL; #ifdef SYS_DARWIN /* When vlc.app is run by double clicking in Mac OS X, the 2nd arg * is the PSN - process serial number (a unique PID-ish thingie) * still ok for real Darwin & when run from command line */ if ( (*pi_argc > 1) && (strncmp( ppsz_argv[ 1 ] , "-psn" , 4 ) == 0) ) /* for example -psn_0_9306113 */ { /* GDMF!... I can't do this or else the MacOSX window server will * not pick up the PSN and not register the app and we crash... * hence the following kludge otherwise we'll get confused w/ argv[1] * being an input file name */ #if 0 ppsz_argv[ 1 ] = NULL; #endif *pi_argc = *pi_argc - 1; pi_argc--; return( 0 ); } #endif /* * Generate the longopts structure used by getopt_long */ i_longopts_size = 0; for( p_module = p_module_bank->first ; p_module != NULL ; p_module = p_module->next ) { /* count the number of exported configuration options (to allocate * longopts). The i_config_options we use is an approximation of the * real number of options (it also includes markers like: category ...) * but it is enough for our purpose */ i_longopts_size += p_module->i_config_options -1; } p_longopts = (struct option *)malloc( sizeof(struct option) * (i_longopts_size + 1) ); if( p_longopts == NULL ) { intf_ErrMsg( "GetConfigurationFromCmdLine error: " "can't allocate p_longopts" ); return( -1 ); } /* Fill the longopts structure */ i_index = 0; for( p_module = p_module_bank->first ; p_module != NULL ; p_module = p_module->next ) { for( i = 1; i < (p_module->i_config_options -1); i++ ) { if( (p_module->p_config[i].i_type == MODULE_CONFIG_ITEM_CATEGORY)|| (p_module->p_config[i].i_type == MODULE_CONFIG_ITEM_SUBCATEGORY)|| (p_module->p_config[i].i_type == MODULE_CONFIG_ITEM_SUBCATEGORY_END) ) continue; p_longopts[i_index].name = p_module->p_config[i].psz_name; p_longopts[i_index].has_arg = (p_module->p_config[i].i_type == MODULE_CONFIG_ITEM_BOOL)? no_argument : required_argument; p_longopts[i_index].flag = 0; p_longopts[i_index].val = 0; i_index++; } } /* Close the longopts structure */ memset( &p_longopts[i_index], 0, sizeof(struct option) ); /* * Parse the command line options */ opterr = 0; optind = 1; while( ( i_cmd = getopt_long( *pi_argc, ppsz_argv, psz_shortopts, p_longopts, &i_index ) ) != EOF ) { if( i_cmd == 0 ) { /* A long option has been recognized */ module_config_t *p_config; /* Store the configuration option */ p_config = config_FindConfig( p_longopts[i_index].name ); switch( p_config->i_type ) { case MODULE_CONFIG_ITEM_STRING: case MODULE_CONFIG_ITEM_FILE: case MODULE_CONFIG_ITEM_PLUGIN: config_PutPszVariable( p_longopts[i_index].name, optarg ); break; case MODULE_CONFIG_ITEM_INTEGER: config_PutIntVariable( p_longopts[i_index].name, atoi(optarg)); break; case MODULE_CONFIG_ITEM_BOOL: config_PutIntVariable( p_longopts[i_index].name, 1 ); break; } continue; } /* short options handled here for now */ switch( i_cmd ) { /* General/common options */ case 'h': /* -h, --help */ config_PutIntVariable( "help", 1 ); break; case 'H': /* -H, --longhelp */ config_PutIntVariable( "longhelp", 1 ); break; case 'l': /* -l, --list */ config_PutIntVariable( "list", 1 ); break; case 'v': /* -v, --verbose */ p_main->i_warning_level++; break; /* Internal error: unknown option */ case '?': default: if( !b_ignore_errors ) { intf_ErrMsg( "intf error: unknown option `%s'", ppsz_argv[optind] ); intf_Msg( "Try `%s --help' for more information.\n", p_main->psz_arg0 ); #ifdef WIN32 /* Pause the console because it's destroyed when we exit */ intf_Msg( "\nPress the RETURN key to continue..." ); getchar(); #endif free( p_longopts ); return( EINVAL ); break; } } } if( p_main->i_warning_level < 0 ) { p_main->i_warning_level = 0; } free( p_longopts ); return( 0 ); } /***************************************************************************** * GetFilenames: parse command line options which are not flags ***************************************************************************** * Parse command line for input files. *****************************************************************************/ static int GetFilenames( int i_argc, char *ppsz_argv[] ) { int i_opt; /* We assume that the remaining parameters are filenames */ for( i_opt = optind; i_opt < i_argc; i_opt++ ) { intf_PlaylistAdd( p_main->p_playlist, PLAYLIST_END, ppsz_argv[ i_opt ] ); } return( 0 ); } /***************************************************************************** * Usage: print program usage ***************************************************************************** * Print a short inline help. Message interface is initialized at this stage. *****************************************************************************/ static void Usage( const char *psz_module_name ) { int i; module_t *p_module; char psz_spaces[30]; memset( psz_spaces, 32, 30 ); #ifdef WIN32 ShowConsole(); #endif /* Usage */ intf_Msg( "Usage: %s [options] [parameters] [file]...\n", p_main->psz_arg0 ); /* Enumerate the config of each module */ for( p_module = p_module_bank->first ; p_module != NULL ; p_module = p_module->next ) { if( psz_module_name && strcmp( psz_module_name, p_module->psz_name ) ) continue; /* print module name */ intf_Msg( "%s configuration:\n", p_module->psz_name ); for( i = 0; i < (p_module->i_config_options -1); i++ ) { int j; switch( p_module->p_config[i].i_type ) { case MODULE_CONFIG_ITEM_CATEGORY: intf_Msg( " %s", p_module->p_config[i].psz_text ); break; case MODULE_CONFIG_ITEM_STRING: case MODULE_CONFIG_ITEM_FILE: case MODULE_CONFIG_ITEM_PLUGIN: /* Nasty hack, but right now I'm too tired to think about * a nice solution */ j = 25 - strlen( p_module->p_config[i].psz_name ) - strlen(" <string>") - 1; if( j < 0 ) j = 0; psz_spaces[j] = 0; intf_Msg( " --%s <string>%s %s", p_module->p_config[i].psz_name, psz_spaces, p_module->p_config[i].psz_text ); psz_spaces[j] = 32; break; case MODULE_CONFIG_ITEM_INTEGER: /* Nasty hack, but right now I'm too tired to think about * a nice solution */ j = 25 - strlen( p_module->p_config[i].psz_name ) - strlen(" <integer>") - 1; if( j < 0 ) j = 0; psz_spaces[j] = 0; intf_Msg( " --%s <integer>%s %s", p_module->p_config[i].psz_name, psz_spaces, p_module->p_config[i].psz_text ); psz_spaces[j] = 32; break; default: /* Nasty hack, but right now I'm too tired to think about * a nice solution */ j = 25 - strlen( p_module->p_config[i].psz_name ) - 1; if( j < 0 ) j = 0; psz_spaces[j] = 0; intf_Msg( " --%s%s %s", p_module->p_config[i].psz_name, psz_spaces, p_module->p_config[i].psz_text ); psz_spaces[j] = 32; break; } } /* Yet another nasty hack. * Maybe we could use MODULE_CONFIG_ITEM_END to display tail messages * for each module?? */ if( !strcmp( "main", p_module->psz_name ) ) intf_Msg( "\nPlaylist items:" "\n *.mpg, *.vob \tPlain MPEG-1/2 files" "\n dvd:<device>[@<raw device>] \tDVD device" "\n vcd:<device> \tVCD device" "\n udpstream:[<server>[:<server port>]][@[<bind address>]" "[:<bind port>]]" "\n \tUDP stream sent by VLS" "\n vlc:loop \tLoop execution of the " "playlist" "\n vlc:pause \tPause execution of " "playlist items" "\n vlc:quit \tQuit VLC" ); intf_Msg( "" ); } #ifdef WIN32 /* Pause the console because it's destroyed when we exit */ intf_Msg( "\nPress the RETURN key to continue..." ); getchar(); #endif } /***************************************************************************** * ListModules: list the available modules with their description ***************************************************************************** * Print a list of all available modules (builtins and plugins) and a short * description for each one. *****************************************************************************/ static void ListModules( void ) { module_t *p_module; char psz_spaces[20]; memset( psz_spaces, 32, 20 ); #ifdef WIN32 ShowConsole(); #endif /* Usage */ intf_Msg( "Usage: %s [options] [parameters] [file]...\n", p_main->psz_arg0 ); intf_Msg( "[plugin] [description]" ); /* Enumerate each module */ for( p_module = p_module_bank->first ; p_module != NULL ; p_module = p_module->next ) { int i; /* Nasty hack, but right now I'm too tired to think about a nice * solution */ i = 20 - strlen( p_module->psz_name ) - 1; if( i < 0 ) i = 0; psz_spaces[i] = 0; intf_Msg( " %s%s %s", p_module->psz_name, psz_spaces, p_module->psz_longname ); psz_spaces[i] = 32; } #ifdef WIN32 /* Pause the console because it's destroyed when we exit */ intf_Msg( "\nPress the RETURN key to continue..." ); getchar(); #endif } /***************************************************************************** * Version: print complete program version ***************************************************************************** * Print complete program version and build number. *****************************************************************************/ static void Version( void ) { #ifdef WIN32 ShowConsole(); #endif intf_Msg( VERSION_MESSAGE "This program comes with NO WARRANTY, to the extent permitted by law.\n" "You may redistribute it under the terms of the GNU General Public License;\n" "see the file named COPYING for details.\n" "Written by the VideoLAN team at Ecole Centrale, Paris." ); #ifdef WIN32 /* Pause the console because it's destroyed when we exit */ intf_Msg( "\nPress the RETURN key to continue..." ); getchar(); #endif } /***************************************************************************** * InitSignalHandler: system signal handler initialization ***************************************************************************** * Set the signal handlers. SIGTERM is not intercepted, because we need at * at least a method to kill the program when all other methods failed, and * when we don't want to use SIGKILL. *****************************************************************************/ static void InitSignalHandler( void ) { /* Termination signals */ #ifndef WIN32 signal( SIGINT, FatalSignalHandler ); signal( SIGHUP, FatalSignalHandler ); signal( SIGQUIT, FatalSignalHandler ); /* Other signals */ signal( SIGALRM, SimpleSignalHandler ); signal( SIGPIPE, SimpleSignalHandler ); #endif } /***************************************************************************** * SimpleSignalHandler: system signal handler ***************************************************************************** * This function is called when a non fatal signal is received by the program. *****************************************************************************/ static void SimpleSignalHandler( int i_signal ) { /* Acknowledge the signal received */ intf_WarnMsg( 0, "intf: ignoring signal %d", i_signal ); } /***************************************************************************** * FatalSignalHandler: system signal handler ***************************************************************************** * This function is called when a fatal signal is received by the program. * It tries to end the program in a clean way. *****************************************************************************/ static void FatalSignalHandler( int i_signal ) { /* Once a signal has been trapped, the termination sequence will be * armed and following signals will be ignored to avoid sending messages * to an interface having been destroyed */ #ifndef WIN32 signal( SIGINT, SIG_IGN ); signal( SIGHUP, SIG_IGN ); signal( SIGQUIT, SIG_IGN ); #endif /* Acknowledge the signal received */ intf_ErrMsg( "intf error: signal %d received, exiting", i_signal ); /* Try to terminate everything - this is done by requesting the end of the * interface thread */ p_main->p_intf->b_die = 1; } /***************************************************************************** * IllegalSignalHandler: system signal handler ***************************************************************************** * This function is called when an illegal instruction signal is received by * the program. We use this function to test OS and CPU capabilities *****************************************************************************/ static void IllegalSignalHandler( int i_signal ) { /* Acknowledge the signal received */ i_illegal = 1; #ifdef HAVE_SIGRELSE sigrelse( i_signal ); #endif fprintf( stderr, "warning: your CPU has %s instructions, but not your " "operating system.\n", psz_capability ); fprintf( stderr, " some optimizations will be disabled unless " "you upgrade your OS\n" ); #ifdef SYS_LINUX fprintf( stderr, " (for instance Linux kernel 2.4.x or later)" ); #endif longjmp( env, 1 ); } /***************************************************************************** * CPUCapabilities: list the processors MMX support and other capabilities ***************************************************************************** * This function is called to list extensions the CPU may have. *****************************************************************************/ static u32 CPUCapabilities( void ) { volatile u32 i_capabilities = CPU_CAPABILITY_NONE; #if defined( SYS_DARWIN ) struct host_basic_info hi; kern_return_t ret; host_name_port_t host; int i_size; char *psz_name, *psz_subname; i_capabilities |= CPU_CAPABILITY_FPU; /* Should 'never' fail? */ host = mach_host_self(); i_size = sizeof( hi ) / sizeof( int ); ret = host_info( host, HOST_BASIC_INFO, ( host_info_t )&hi, &i_size ); if( ret != KERN_SUCCESS ) { fprintf( stderr, "error: couldn't get CPU information\n" ); return( i_capabilities ); } slot_name( hi.cpu_type, hi.cpu_subtype, &psz_name, &psz_subname ); /* FIXME: need better way to detect newer proccessors. * could do strncmp(a,b,5), but that's real ugly */ if( !strcmp(psz_name, "ppc7400") || !strcmp(psz_name, "ppc7450") ) { i_capabilities |= CPU_CAPABILITY_ALTIVEC; } return( i_capabilities ); #elif defined( __i386__ ) volatile unsigned int i_eax, i_ebx, i_ecx, i_edx; volatile boolean_t b_amd; /* Needed for x86 CPU capabilities detection */ # define cpuid( a ) \ asm volatile ( "pushl %%ebx\n\t" \ "cpuid\n\t" \ "movl %%ebx,%1\n\t" \ "popl %%ebx\n\t" \ : "=a" ( i_eax ), \ "=r" ( i_ebx ), \ "=c" ( i_ecx ), \ "=d" ( i_edx ) \ : "a" ( a ) \ : "cc" ); i_capabilities |= CPU_CAPABILITY_FPU; # if defined( CAN_COMPILE_SSE ) || defined ( CAN_COMPILE_3DNOW ) signal( SIGILL, IllegalSignalHandler ); # endif /* test for a 486 CPU */ asm volatile ( "pushl %%ebx\n\t" "pushfl\n\t" "popl %%eax\n\t" "movl %%eax, %%ebx\n\t" "xorl $0x200000, %%eax\n\t" "pushl %%eax\n\t" "popfl\n\t" "pushfl\n\t" "popl %%eax\n\t" "movl %%ebx,%1\n\t" "popl %%ebx\n\t" : "=a" ( i_eax ), "=r" ( i_ebx ) : : "cc" ); if( i_eax == i_ebx ) { # if defined( CAN_COMPILE_SSE ) || defined ( CAN_COMPILE_3DNOW ) signal( SIGILL, NULL ); # endif return( i_capabilities ); } i_capabilities |= CPU_CAPABILITY_486; /* the CPU supports the CPUID instruction - get its level */ cpuid( 0x00000000 ); if( !i_eax ) { # if defined( CAN_COMPILE_SSE ) || defined ( CAN_COMPILE_3DNOW ) signal( SIGILL, NULL ); # endif return( i_capabilities ); } /* FIXME: this isn't correct, since some 486s have cpuid */ i_capabilities |= CPU_CAPABILITY_586; /* borrowed from mpeg2dec */ b_amd = ( i_ebx == 0x68747541 ) && ( i_ecx == 0x444d4163 ) && ( i_edx == 0x69746e65 ); /* test for the MMX flag */ cpuid( 0x00000001 ); if( ! (i_edx & 0x00800000) ) { # if defined( CAN_COMPILE_SSE ) || defined ( CAN_COMPILE_3DNOW ) signal( SIGILL, NULL ); # endif return( i_capabilities ); } i_capabilities |= CPU_CAPABILITY_MMX; if( i_edx & 0x02000000 ) { i_capabilities |= CPU_CAPABILITY_MMXEXT; # ifdef CAN_COMPILE_SSE /* We test if OS support the SSE instructions */ psz_capability = "SSE"; i_illegal = 0; if( setjmp( env ) == 0 ) { /* Test a SSE instruction */ __asm__ __volatile__ ( "xorps %%xmm0,%%xmm0\n" : : ); } if( i_illegal == 0 ) { i_capabilities |= CPU_CAPABILITY_SSE; } # endif } /* test for additional capabilities */ cpuid( 0x80000000 ); if( i_eax < 0x80000001 ) { # if defined( CAN_COMPILE_SSE ) || defined ( CAN_COMPILE_3DNOW ) signal( SIGILL, NULL ); # endif return( i_capabilities ); } /* list these additional capabilities */ cpuid( 0x80000001 ); # ifdef CAN_COMPILE_3DNOW if( i_edx & 0x80000000 ) { psz_capability = "3D Now!"; i_illegal = 0; if( setjmp( env ) == 0 ) { /* Test a 3D Now! instruction */ __asm__ __volatile__ ( "pfadd %%mm0,%%mm0\n" "femms\n" : : ); } if( i_illegal == 0 ) { i_capabilities |= CPU_CAPABILITY_3DNOW; } } # endif if( b_amd && ( i_edx & 0x00400000 ) ) { i_capabilities |= CPU_CAPABILITY_MMXEXT; } # if defined( CAN_COMPILE_SSE ) || defined ( CAN_COMPILE_3DNOW ) signal( SIGILL, NULL ); # endif return( i_capabilities ); #elif defined( __powerpc__ ) i_capabilities |= CPU_CAPABILITY_FPU; # ifdef CAN_COMPILE_ALTIVEC signal( SIGILL, IllegalSignalHandler ); psz_capability = "AltiVec"; i_illegal = 0; if( setjmp( env ) == 0 ) { asm volatile ("mtspr 256, %0\n\t" "vand %%v0, %%v0, %%v0" : : "r" (-1)); } if( i_illegal == 0 ) { i_capabilities |= CPU_CAPABILITY_ALTIVEC; } signal( SIGILL, NULL ); # endif return( i_capabilities ); #else /* default behaviour */ return( i_capabilities ); #endif } /***************************************************************************** * ShowConsole: On Win32, create an output console for debug messages ***************************************************************************** * This function is usefull only on Win32. *****************************************************************************/ #ifdef WIN32 /* */ static void ShowConsole( void ) { AllocConsole(); freopen( "CONOUT$", "w", stdout ); freopen( "CONOUT$", "w", stderr ); freopen( "CONIN$", "r", stdin ); return; } #endif