]> git.sesse.net Git - vlc/blob - src/interface/main.c
* ./plugins/chroma/i420_rgb8.c: fixed a warning.
[vlc] / src / interface / main.c
1 /*****************************************************************************
2  * main.c: main vlc source
3  * Includes the main() function for vlc. Parses command line, start interface
4  * and spawn threads.
5  *****************************************************************************
6  * Copyright (C) 1998-2001 VideoLAN
7  * $Id: main.c,v 1.165 2002/03/19 00:30:44 sam Exp $
8  *
9  * Authors: Vincent Seguin <seguin@via.ecp.fr>
10  *          Samuel Hocevar <sam@zoy.org>
11  *          Gildas Bazin <gbazin@netcourrier.com>
12  *
13  * This program is free software; you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License as published by
15  * the Free Software Foundation; either version 2 of the License, or
16  * (at your option) any later version.
17  * 
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
26  *****************************************************************************/
27
28 /*****************************************************************************
29  * Preamble
30  *****************************************************************************/
31 #include <signal.h>                               /* SIGHUP, SIGINT, SIGKILL */
32 #include <stdio.h>                                              /* sprintf() */
33 #include <setjmp.h>                                       /* longjmp, setjmp */
34
35 #include <videolan/vlc.h>
36
37 #ifdef HAVE_GETOPT_LONG
38 #   ifdef HAVE_GETOPT_H
39 #       include <getopt.h>                                       /* getopt() */
40 #   endif
41 #else
42 #   include "GNUgetopt/getopt.h"
43 #endif
44
45 #ifdef SYS_DARWIN
46 #   include <mach/mach.h>                               /* Altivec detection */
47 #   include <mach/mach_error.h>       /* some day the header files||compiler *
48                                                        will define it for us */
49 #   include <mach/bootstrap.h>
50 #endif
51
52 #ifndef WIN32
53 #   include <netinet/in.h>                            /* BSD: struct in_addr */
54 #endif
55
56 #ifdef HAVE_UNISTD_H
57 #   include <unistd.h>
58 #elif defined( _MSC_VER ) && defined( _WIN32 )
59 #   include <io.h>
60 #endif
61
62 #ifdef HAVE_LOCALE_H
63 #    include <locale.h>
64 #endif
65
66 #include <errno.h>                                                 /* ENOMEM */
67 #include <stdlib.h>                                  /* getenv(), strtol(),  */
68 #include <string.h>                                            /* strerror() */
69 #include <fcntl.h>                                       /* open(), O_WRONLY */
70 #include <sys/stat.h>                                             /* S_IREAD */
71
72 #include "netutils.h"                                 /* network_ChannelJoin */
73
74 #include "stream_control.h"
75 #include "input_ext-intf.h"
76
77 #include "intf_playlist.h"
78 #include "interface.h"
79
80 #include "audio_output.h"
81
82 #include "video.h"
83 #include "video_output.h"
84
85 #include "debug.h"
86
87 /*****************************************************************************
88  * Configuration options for the main program. Each plugin will also separatly
89  * define its own configuration options.
90  * Look into configuration.h if you need to know more about the following
91  * macros.
92  * 
93  *****************************************************************************/
94 #define BUILTIN
95 #define MODULE_NAME main
96 #include "modules_inner.h"                        /* for configuration stuff */
97
98
99 #define INTF_TEXT "interface method"
100 #define INTF_LONGTEXT "This option allows you to select the interface used by"\
101                       " vlc.\nNote that the default behaviour is to" \
102                       " automatically select the best method available"
103
104 #define WARNING_TEXT "warning level (or use -v, -vv, etc...)"
105 #define WARNING_LONGTEXT "Increasing the warning level will allow you to see" \
106                          " more debug messages and can sometimes help you to" \
107                          " troubleshoot a problem"
108
109 #define STATS_TEXT "output statistics"
110 #define STATS_LONGTEXT "Enabling the stats mode will flood your log console" \
111                        " with various statistics messages"
112
113 #define INTF_PATH_TEXT "interface default search path"
114 #define INTF_PATH_LONGTEXT "This option allows you to set the default path" \
115                            "that the interface will open when looking for a" \
116                            " file"
117
118 #define AOUT_TEXT "audio output method"
119 #define AOUT_LONGTEXT "This option allows you to select the audio" \
120                       " audio output method used by vlc.\nNote that the" \
121                       " default behaviour is to automatically select the best"\
122                       " method available"
123
124 #define NOAUDIO_TEXT "disable audio"
125 #define NOAUDIO_LONGTEXT "This will completely disable the audio output. The" \
126                          " audio decoding stage shouldn't even be done, so it"\
127                          " can allow you to save some processing power"
128
129 #define MONO_TEXT "mono audio"
130 #define MONO_LONGTEXT "This will force a mono audio output"
131
132 #define VOLUME_TEXT "audio output volume"
133 #define VOLUME_LONGTEXT "You can set the default audio output volume here," \
134                         " in a range from 0 to 1024"
135
136 #define FORMAT_TEXT "audio output format"
137 #define FORMAT_LONGTEXT "You can force the audio output format here.\n" \
138                         "0 -> 16 bits signed native endian (default)\n" \
139                         "1 ->  8 bits unsigned\n"                       \
140                         "2 -> 16 bits signed little endian\n"           \
141                         "3 -> 16 bits signed big endian\n"              \
142                         "4 ->  8 bits signed\n"                         \
143                         "5 -> 16 bits unsigned little endian\n"         \
144                         "6 -> 16 bits unsigned big endian\n"            \
145                         "7 -> mpeg2 audio (unsupported)\n"              \
146                         "8 -> ac3 pass-through"
147                          
148 #define RATE_TEXT "audio output frequency (Hz)"
149 #define RATE_LONGTEXT "You can force the audio output frequency here.\n"    \
150                       "Common values are 48000, 44100, 32000, 22050,"       \
151                       " 16000, 11025, 8000"
152
153 #define DESYNC_TEXT "Compensate desynchronization of audio (in ms)"
154 #define DESYNC_LONGTEXT "This option allows you to delay the audio output." \
155                         "This can be handy if you notice a lag between the" \
156                         " video and the audio"
157
158 #define VOUT_TEXT "video output method"
159 #define VOUT_LONGTEXT "This option allows you to select the video output" \
160                       "method used by vlc.\nNote that the default behaviour" \
161                       "is to automatically select the best method available"
162
163 #define NOVIDEO_TEXT "disable video"
164 #define NOVIDEO_LONGTEXT "This will completely disable the video output. The" \
165                          "video decoding stage shouldn't even be done, so it" \
166                          "can allow you to save some processing power"
167
168 #define DISPLAY_TEXT "display identifier"
169 #define DISPLAY_LONGTEXT NULL
170
171 #define WIDTH_TEXT "video width"
172 #define WIDTH_LONGTEXT "You can enforce the video width here.\nNote" \
173                        "that by default vlc will adapt to the video properties"
174
175 #define HEIGHT_TEXT "video height"
176 #define HEIGHT_LONGTEXT NULL
177
178 #define GRAYSCALE_TEXT "grayscale video output"
179 #define GRAYSCALE_LONGTEXT NULL
180
181 #define FULLSCREEN_TEXT "fullscreen video output"
182 #define FULLSCREEN_LONGTEXT NULL
183
184 #define NOOVERLAY_TEXT "disable accelerated display"
185 #define NOOVERLAY_LONGTEXT NULL
186
187 #define SPUMARGIN_TEXT "force SPU position"
188 #define SPUMARGIN_LONGTEXT NULL
189
190 #define FILTER_TEXT "video filter module"
191 #define FILTER_LONGTEXT NULL
192
193 #define INPUT_TEXT "input method"
194 #define INPUT_LONGTEXT NULL
195
196 #define SERVER_PORT_TEXT "server port"
197 #define SERVER_PORT_LONGTEXT NULL
198
199 #define NETCHANNEL_TEXT "enable network channel mode"
200 #define NETCHANNEL_LONGTEXT NULL
201
202 #define CHAN_SERV_TEXT "channel server address"
203 #define CHAN_SERV_LONGTEXT NULL
204
205 #define CHAN_PORT_TEXT "channel server port"
206 #define CHAN_PORT_LONGTEXT NULL
207
208 #define IFACE_TEXT "network interface"
209 #define IFACE_LONGTEXT NULL
210
211 #define INPUT_AUDIO_TEXT "choose audio"
212 #define INPUT_AUDIO_LONGTEXT NULL
213
214 #define INPUT_CHAN_TEXT "choose channel"
215 #define INPUT_CHAN_LONGTEXT NULL
216
217 #define INPUT_SUBT_TEXT "choose subtitles"
218 #define INPUT_SUBT_LONGTEXT NULL
219
220 #define DVD_DEV_TEXT "DVD device"
221 #define DVD_DEV_LONGTEXT NULL
222
223 #define VCD_DEV_TEXT "VCD device"
224 #define VCD_DEV_LONGTEXT NULL
225
226 #define IPV6_TEXT "force IPv6"
227 #define IPV6_LONGTEXT NULL
228
229 #define IPV4_TEXT "force IPv4"
230 #define IPV4_LONGTEXT NULL
231
232 #define ADEC_MPEG_TEXT "choose MPEG audio decoder"
233 #define ADEC_MPEG_LONGTEXT NULL
234
235 #define ADEC_AC3_TEXT "choose AC3 audio decoder"
236 #define ADEC_AC3_LONGTEXT NULL
237
238 #define VDEC_SMP_TEXT "use additional processors"
239 #define VDEC_SMP_LONGTEXT NULL
240
241 #define VPAR_SYNCHRO_TEXT "force synchro algorithm {I|I+|IP|IP+|IPB}"
242 #define VPAR_SYNCHRO_LONGTEXT NULL
243
244 #define NOMMX_TEXT "disable CPU's MMX support"
245 #define NOMMX_LONGTEXT NULL
246
247 #define NO3DN_TEXT "disable CPU's 3D Now! support"
248 #define NO3DN_LONGTEXT NULL
249
250 #define NOMMXEXT_TEXT "disable CPU's MMX EXT support"
251 #define NOMMXEXT_LONGTEXT NULL
252
253 #define NOSSE_TEXT "disable CPU's SSE support"
254 #define NOSSE_LONGTEXT NULL
255
256 #define NOALTIVEC_TEXT "disable CPU's AltiVec support"
257 #define NOALTIVEC_LONGTEXT NULL
258
259 #define PLAYLIST_LAUNCH_TEXT "launch playlist on startup"
260 #define PLAYLIST_LAUNCH_LONGTEXT NULL
261
262 #define PLAYLIST_ENQUEUE_TEXT "enqeue playlist as default"
263 #define PLAYLIST_ENQUEUE_LONGTEXT NULL
264
265 #define PLAYLIST_LOOP_TEXT "loop playlist on end"
266 #define PLAYLIST_LOOP_LONGTEXT NULL
267
268 #define MEMCPY_TEXT "memory copy method"
269 #define MEMCPY_LONGTEXT NULL
270
271 /* Quick usage guide
272 MODULE_CONFIG_START
273 MODULE_CONFIG_STOP
274 ADD_CATEGORY_HINT( text, longtext )
275 ADD_SUBCATEGORY_HINT( text, longtext )
276 ADD_STRING( option_name, value, p_callback, text, longtext )
277 ADD_FILE( option_name, psz_value, p_callback, text, longtext )
278 ADD_PLUGIN( option_name, psz_value, i_capability, p_callback, text, longtext )
279 ADD_INTEGER( option_name, i_value, p_callback, text, longtext )
280 ADD_BOOL( option_name, p_callback, text, longtext )
281 */
282
283 MODULE_CONFIG_START
284
285 /* Interface options */
286 ADD_CATEGORY_HINT( "Interface", NULL)
287 ADD_PLUGIN  ( "intf", MODULE_CAPABILITY_INTF, NULL, NULL, INTF_TEXT, INTF_LONGTEXT )
288 ADD_INTEGER ( "warning", 0, NULL, WARNING_TEXT, WARNING_LONGTEXT )
289 ADD_BOOL    ( "stats", NULL, STATS_TEXT, STATS_LONGTEXT )
290 ADD_STRING  ( "search_path", NULL, NULL, INTF_PATH_TEXT, INTF_PATH_LONGTEXT )
291
292 /* Audio options */
293 ADD_CATEGORY_HINT( "Audio", NULL)
294 ADD_PLUGIN  ( "aout", MODULE_CAPABILITY_AOUT, NULL, NULL, AOUT_TEXT, AOUT_LONGTEXT )
295 ADD_BOOL    ( "noaudio", NULL, NOAUDIO_TEXT, NOAUDIO_LONGTEXT )
296 ADD_BOOL    ( "mono", NULL, MONO_TEXT, MONO_LONGTEXT )
297 ADD_INTEGER ( "volume", VOLUME_DEFAULT, NULL, VOLUME_TEXT, VOLUME_LONGTEXT )
298 ADD_INTEGER ( "rate", 44100, NULL, RATE_TEXT, RATE_LONGTEXT )
299 ADD_INTEGER ( "desync", 0, NULL, DESYNC_TEXT, DESYNC_LONGTEXT )
300 ADD_INTEGER ( "aout_format", 0, NULL, FORMAT_TEXT,
301               FORMAT_LONGTEXT )
302
303 /* Video options */
304 ADD_CATEGORY_HINT( "Video", NULL )
305 ADD_PLUGIN  ( "vout", MODULE_CAPABILITY_VOUT, NULL, NULL, VOUT_TEXT, VOUT_LONGTEXT )
306 ADD_BOOL    ( "novideo", NULL, NOVIDEO_TEXT, NOVIDEO_LONGTEXT )
307 ADD_STRING  ( "display", NULL, NULL, DISPLAY_TEXT, DISPLAY_LONGTEXT )
308 ADD_INTEGER ( "width", 720, NULL, WIDTH_TEXT, WIDTH_LONGTEXT )
309 ADD_INTEGER ( "height", 576, NULL, HEIGHT_TEXT, HEIGHT_LONGTEXT )
310 ADD_BOOL    ( "grayscale", NULL, GRAYSCALE_TEXT, GRAYSCALE_LONGTEXT )
311 ADD_BOOL    ( "fullscreen", NULL, FULLSCREEN_TEXT, FULLSCREEN_LONGTEXT )
312 ADD_BOOL    ( "nooverlay", NULL, NOOVERLAY_TEXT, NOOVERLAY_LONGTEXT )
313 ADD_INTEGER ( "spumargin", -1, NULL, SPUMARGIN_TEXT, SPUMARGIN_LONGTEXT )
314 ADD_PLUGIN  ( "filter", MODULE_CAPABILITY_VOUT, NULL, NULL, FILTER_TEXT, FILTER_LONGTEXT )
315
316 /* Input options */
317 ADD_CATEGORY_HINT( "Input", NULL )
318 ADD_STRING  ( "input", NULL, NULL, INPUT_TEXT, INPUT_LONGTEXT )
319 ADD_INTEGER ( "server_port", 1234, NULL, SERVER_PORT_TEXT, SERVER_PORT_LONGTEXT )
320 ADD_BOOL    ( "network_channel", NULL, NETCHANNEL_TEXT, NETCHANNEL_LONGTEXT )
321 ADD_STRING  ( "channel_server", "localhost", NULL, CHAN_SERV_TEXT, CHAN_SERV_LONGTEXT )
322 ADD_INTEGER ( "channel_port", 6010, NULL, CHAN_PORT_TEXT, CHAN_PORT_LONGTEXT )
323 ADD_STRING  ( "iface", "eth0", NULL, IFACE_TEXT, IFACE_LONGTEXT )
324
325 ADD_INTEGER ( "input_audio", -1, NULL, INPUT_AUDIO_TEXT, INPUT_AUDIO_LONGTEXT )
326 ADD_INTEGER ( "input_channel", -1, NULL, INPUT_CHAN_TEXT, INPUT_CHAN_LONGTEXT )
327 ADD_INTEGER ( "input_subtitle", -1, NULL, INPUT_SUBT_TEXT, INPUT_SUBT_LONGTEXT )
328
329 ADD_STRING  ( "dvd_device", "/dev/dvd", NULL, DVD_DEV_TEXT, DVD_DEV_LONGTEXT )
330 ADD_STRING  ( "vcd_device", "/dev/cdrom", NULL, VCD_DEV_TEXT, VCD_DEV_LONGTEXT )
331 ADD_BOOL    ( "ipv6", NULL, IPV6_TEXT, IPV6_LONGTEXT )
332 ADD_BOOL    ( "ipv4", NULL, IPV4_TEXT, IPV4_LONGTEXT )
333
334 /* Decoder options */
335 ADD_CATEGORY_HINT( "Decoders", NULL )
336 ADD_PLUGIN  ( "mpeg_adec", MODULE_CAPABILITY_DECODER, NULL, NULL, ADEC_MPEG_TEXT, ADEC_MPEG_LONGTEXT )
337 ADD_PLUGIN  ( "ac3_adec", MODULE_CAPABILITY_DECODER, NULL, NULL, ADEC_AC3_TEXT, ADEC_AC3_LONGTEXT )
338 ADD_INTEGER ( "vdec_smp", 0, NULL, VDEC_SMP_TEXT, VDEC_SMP_LONGTEXT )
339 ADD_STRING  ( "vpar_synchro", NULL, NULL, VPAR_SYNCHRO_TEXT, VPAR_SYNCHRO_LONGTEXT )
340
341 /* CPU options */
342 ADD_CATEGORY_HINT( "CPU", NULL )
343 ADD_BOOL    ( "nommx", NULL, NOMMX_TEXT, NOMMX_LONGTEXT )
344 ADD_BOOL    ( "no3dn", NULL, NO3DN_TEXT, NO3DN_LONGTEXT )
345 ADD_BOOL    ( "nommxext", NULL, NOMMXEXT_TEXT, NOMMXEXT_LONGTEXT )
346 ADD_BOOL    ( "nosse", NULL, NOSSE_TEXT, NOSSE_LONGTEXT )
347 ADD_BOOL    ( "noaltivec", NULL, NOALTIVEC_TEXT, NOALTIVEC_LONGTEXT )
348
349 /* Playlist options */
350 ADD_CATEGORY_HINT( "Playlist", NULL )
351 ADD_BOOL    ( "playlist_launch", NULL, PLAYLIST_LAUNCH_TEXT, PLAYLIST_LAUNCH_LONGTEXT )
352 ADD_BOOL    ( "playlist_enqueue", NULL, PLAYLIST_ENQUEUE_TEXT, PLAYLIST_ENQUEUE_LONGTEXT )
353 ADD_BOOL    ( "playlist_loop", NULL, PLAYLIST_LOOP_TEXT, PLAYLIST_LOOP_LONGTEXT )
354
355 /* Misc options */
356 ADD_CATEGORY_HINT( "Miscellaneous", NULL )
357 ADD_PLUGIN  ( "memcpy", MODULE_CAPABILITY_MEMCPY, NULL, NULL, MEMCPY_TEXT, MEMCPY_LONGTEXT )
358
359 MODULE_CONFIG_STOP
360
361 MODULE_INIT_START
362     SET_DESCRIPTION( "Main program" )
363     ADD_CAPABILITY( MAIN, 100/*whatever*/ )
364 MODULE_INIT_STOP
365
366 MODULE_ACTIVATE_START
367 MODULE_ACTIVATE_STOP
368
369 MODULE_DEACTIVATE_START
370 MODULE_DEACTIVATE_STOP
371
372 /* Hack for help options */
373 static module_t help_module;
374 static module_config_t p_help_config[] = {
375     { MODULE_CONFIG_ITEM_BOOL, "help", "print help (or use -h)",
376       NULL, NULL, 0, NULL, NULL, 0 },
377     { MODULE_CONFIG_ITEM_BOOL, "longhelp", "print detailed help (or use -H)",
378       NULL, NULL, 0, NULL, NULL, 0 },
379     { MODULE_CONFIG_ITEM_BOOL, "list", "print a list of available plugins "
380       "(or use -l)", NULL, NULL, 0, NULL, NULL, 0 },
381     { MODULE_CONFIG_ITEM_STRING, "plugin", "print help on plugin (or use -p)",
382       NULL, NULL, 0, NULL, &help_module.config_lock, 0 },
383     { MODULE_CONFIG_ITEM_BOOL, "version", "print version information",
384       NULL, NULL, 0, NULL, NULL, 0 },
385     { MODULE_CONFIG_HINT_END, NULL, NULL, NULL, NULL, 0, NULL, NULL, 0 } };
386
387
388 /*****************************************************************************
389  * End configuration.
390  *****************************************************************************/
391
392 /*****************************************************************************
393  * Global variables - these are the only ones, see main.h and modules.h
394  *****************************************************************************/
395 main_t        *p_main;
396 module_bank_t *p_module_bank;
397 input_bank_t  *p_input_bank;
398 aout_bank_t   *p_aout_bank;
399 vout_bank_t   *p_vout_bank;
400
401 /*****************************************************************************
402  * Local prototypes
403  *****************************************************************************/
404 static int  GetConfigurationFromCmdLine ( int *pi_argc, char *ppsz_argv[],
405                                           boolean_t b_ignore_errors );
406 static int  GetFilenames                ( int i_argc, char *ppsz_argv[] );
407 static void Usage                       ( const char *psz_module_name );
408 static void ListModules                 ( void );
409 static void Version                     ( void );
410
411 static void InitSignalHandler           ( void );
412 static void SimpleSignalHandler         ( int i_signal );
413 static void FatalSignalHandler          ( int i_signal );
414 static void IllegalSignalHandler        ( int i_signal );
415 static u32  CPUCapabilities             ( void );
416
417 #ifdef WIN32
418 static void ShowConsole                 ( void );
419 #endif
420
421 static jmp_buf env;
422 static int     i_illegal;
423 static char   *psz_capability;
424
425 /*****************************************************************************
426  * main: parse command line, start interface and spawn threads
427  *****************************************************************************
428  * Steps during program execution are:
429  *      -configuration parsing and messages interface initialization
430  *      -opening of audio output device and some global modules
431  *      -execution of interface, which exit on error or on user request
432  *      -closing of audio output device and some global modules
433  * On error, the spawned threads are canceled, and the open devices closed.
434  *****************************************************************************/
435 int main( int i_argc, char *ppsz_argv[], char *ppsz_env[] )
436 {
437     main_t        main_data;                /* root of all data - see main.h */
438     module_bank_t module_bank;
439     input_bank_t  input_bank;
440     aout_bank_t   aout_bank;
441     vout_bank_t   vout_bank;
442     char *psz_plugin;
443     char *p_tmp;
444
445     p_main        = &main_data;               /* set up the global variables */
446     p_module_bank = &module_bank;
447     p_input_bank  = &input_bank;
448     p_aout_bank   = &aout_bank;
449     p_vout_bank   = &vout_bank;
450
451     p_main->i_warning_level = 0;
452
453 #if defined( ENABLE_NLS ) && defined ( HAVE_GETTEXT )
454     /*
455      * Support for getext
456      */
457 #if defined( HAVE_LOCALE_H ) && defined( HAVE_LC_MESSAGES )
458     if( !setlocale( LC_MESSAGES, "" ) )
459     {
460         fprintf( stderr, "warning: unsupported locale.\n" );
461     }
462 #endif
463
464     if( !bindtextdomain( PACKAGE, LOCALEDIR ) )
465     {
466         fprintf( stderr, "warning: no domain %s in directory %s\n",
467                  PACKAGE, LOCALEDIR );
468     }
469
470     textdomain( PACKAGE );
471 #endif
472
473     /*
474      * Initialize threads system
475      */
476     vlc_threads_init();
477
478     /*
479      * Test if our code is likely to run on this CPU
480      */
481     p_main->i_cpu_capabilities = CPUCapabilities();
482
483     /*
484      * System specific initialization code
485      */
486 #if defined( SYS_BEOS ) || defined( SYS_DARWIN ) || defined( WIN32 )
487     system_Init( &i_argc, ppsz_argv, ppsz_env );
488
489 #elif defined( SYS_LINUX )
490 #   ifdef DEBUG
491     /* Activate malloc checking routines to detect heap corruptions. */
492     putenv( "MALLOC_CHECK_=2" );
493     putenv( "GNOME_DISABLE_CRASH_DIALOG=1" );
494 #   endif
495 #endif
496
497     /*
498      * Initialize messages interface
499      */
500     intf_MsgCreate();
501
502     intf_Msg( COPYRIGHT_MESSAGE "\n" );
503
504
505     /* Get the executable name (similar to the basename command) */
506     p_main->psz_arg0 = p_tmp = ppsz_argv[ 0 ];
507     while( *p_tmp )
508     {
509         if( *p_tmp == '/' ) p_main->psz_arg0 = ++p_tmp;
510         else ++p_tmp;
511     }
512
513     /*
514      * Initialize the module bank and and load the configuration of the main
515      * module. We need to do this at this stage to be able to display a short
516      * help if required by the user. (short help == main module options)
517      */
518     module_InitBank();
519     module_LoadMain();
520
521     /* Hack: insert the help module here */
522     help_module.psz_name = "help";
523     help_module.i_config_lines = sizeof(p_help_config) /
524                                      sizeof(module_config_t);
525     help_module.i_config_items = help_module.i_config_lines - 1;
526     vlc_mutex_init( &help_module.config_lock );
527     help_module.p_config = p_help_config;
528     help_module.next = p_module_bank->first;
529     p_module_bank->first = &help_module;
530     /* end hack */
531
532     if( GetConfigurationFromCmdLine( &i_argc, ppsz_argv, 1 ) )
533     {
534         intf_MsgDestroy();
535         return( errno );
536     }
537
538     /* Check for short help option */
539     if( config_GetIntVariable( "help" ) )
540     {
541         intf_Msg( "Usage: %s [options] [parameters] [file]...\n",
542                   p_main->psz_arg0 );
543
544         Usage( "help" );
545         Usage( "main" );
546         return( -1 );
547     }
548
549     /* Check for version option */
550     if( config_GetIntVariable( "version" ) )
551     {
552         Version();
553         return( -1 );
554     }
555
556     /* Hack: remove the help module here */
557     p_module_bank->first = help_module.next;
558     /* end hack */
559
560     /*
561      * Load the builtins and plugins into the module_bank.
562      * We have to do it before GetConfiguration() because this also gets the
563      * list of configuration options exported by each plugin and loads their
564      * default values.
565      */
566     module_LoadBuiltins();
567     module_LoadPlugins();
568     intf_WarnMsg( 2, "module: module bank initialized, found %i modules",
569                   p_module_bank->i_count );
570
571     /* Hack: insert the help module here */
572     help_module.next = p_module_bank->first;
573     p_module_bank->first = &help_module;
574     /* end hack */
575
576     /* Check for help on plugins */
577     if( (p_tmp = config_GetPszVariable( "plugin" )) )
578     {
579         Usage( p_tmp );
580         free( p_tmp );
581         return( -1 );
582     }
583
584     /* Check for long help option */
585     if( config_GetIntVariable( "longhelp" ) )
586     {
587         Usage( NULL );
588         return( -1 );
589     }
590
591     /* Check for plugin list option */
592     if( config_GetIntVariable( "list" ) )
593     {
594         ListModules();
595         return( -1 );
596     }
597
598     /* Hack: remove the help module here */
599     p_module_bank->first = help_module.next;
600     /* end hack */
601
602
603     /*
604      * Override default configuration with config file settings
605      */
606     vlc_mutex_init( &p_main->config_lock );
607     config_LoadConfigFile( NULL );
608
609     /*
610      * Override configuration with command line settings
611      */
612     if( GetConfigurationFromCmdLine( &i_argc, ppsz_argv, 0 ) )
613     {
614         intf_MsgDestroy();
615         return( errno );
616     }
617
618
619     /* p_main inititalization. FIXME ? */
620     p_main->i_desync = (mtime_t)config_GetIntVariable( "desync" )
621       * (mtime_t)1000;
622     p_main->b_stats = config_GetIntVariable( "stats" );
623     p_main->b_audio = !config_GetIntVariable( "noaudio" );
624     p_main->b_stereo= !config_GetIntVariable( "mono" );
625     p_main->b_video = !config_GetIntVariable( "novideo" );
626     if( config_GetIntVariable( "nommx" ) )
627         p_main->i_cpu_capabilities &= ~CPU_CAPABILITY_MMX;
628     if( config_GetIntVariable( "no3dn" ) )
629         p_main->i_cpu_capabilities &= ~CPU_CAPABILITY_3DNOW;
630     if( config_GetIntVariable( "nommxext" ) )
631         p_main->i_cpu_capabilities &= ~CPU_CAPABILITY_MMXEXT;
632     if( config_GetIntVariable( "nosse" ) )
633         p_main->i_cpu_capabilities &= ~CPU_CAPABILITY_SSE;
634     if( config_GetIntVariable( "noaltivec" ) )
635         p_main->i_cpu_capabilities &= ~CPU_CAPABILITY_ALTIVEC;
636
637
638     if( p_main->b_stats )
639     {
640         char          p_capabilities[200];
641         p_capabilities[0] = '\0';
642
643 #define PRINT_CAPABILITY( capability, string )                              \
644         if( p_main->i_cpu_capabilities & capability )                       \
645         {                                                                   \
646             strncat( p_capabilities, string " ",                            \
647                      sizeof(p_capabilities) - strlen(p_capabilities) );     \
648             p_capabilities[sizeof(p_capabilities) - 1] = '\0';              \
649         }
650
651         PRINT_CAPABILITY( CPU_CAPABILITY_486, "486" );
652         PRINT_CAPABILITY( CPU_CAPABILITY_586, "586" );
653         PRINT_CAPABILITY( CPU_CAPABILITY_PPRO, "Pentium Pro" );
654         PRINT_CAPABILITY( CPU_CAPABILITY_MMX, "MMX" );
655         PRINT_CAPABILITY( CPU_CAPABILITY_3DNOW, "3DNow!" );
656         PRINT_CAPABILITY( CPU_CAPABILITY_MMXEXT, "MMXEXT" );
657         PRINT_CAPABILITY( CPU_CAPABILITY_SSE, "SSE" );
658         PRINT_CAPABILITY( CPU_CAPABILITY_ALTIVEC, "Altivec" );
659         PRINT_CAPABILITY( CPU_CAPABILITY_FPU, "FPU" );
660         intf_StatMsg( "info: CPU has capabilities : %s", p_capabilities );
661     }
662
663     /*
664      * Initialize playlist and get commandline files
665      */
666     p_main->p_playlist = intf_PlaylistCreate();
667     if( !p_main->p_playlist )
668     {
669         intf_ErrMsg( "playlist error: playlist initialization failed" );
670         intf_MsgDestroy();
671         return( errno );
672     }
673     intf_PlaylistInit( p_main->p_playlist );
674
675     /*
676      * Get input filenames given as commandline arguments
677      */
678     GetFilenames( i_argc, ppsz_argv );
679
680     /*
681      * Initialize input, aout and vout banks
682      */
683     input_InitBank();
684     aout_InitBank();
685     vout_InitBank();
686
687     /*
688      * Choose the best memcpy module
689      */
690     psz_plugin = config_GetPszVariable( "memcpy" );
691     p_main->p_memcpy_module = module_Need( MODULE_CAPABILITY_MEMCPY, NULL,
692                                            psz_plugin );
693     if( psz_plugin ) free( psz_plugin );
694     if( p_main->p_memcpy_module == NULL )
695     {
696         intf_ErrMsg( "intf error: no suitable memcpy module, "
697                      "using libc default" );
698         p_main->pf_memcpy = memcpy;
699     }
700     else
701     {
702         p_main->pf_memcpy = p_main->p_memcpy_module->p_functions
703                                   ->memcpy.functions.memcpy.pf_memcpy;
704     }
705
706     /*
707      * Initialize shared resources and libraries
708      */
709     if( config_GetIntVariable( "network_channel" ) &&
710         network_ChannelCreate() )
711     {
712         /* On error during Channels initialization, switch off channels */
713         intf_ErrMsg( "intf error: channels initialization failed, " 
714                                  "deactivating channels" );
715         config_PutIntVariable( "network_channel", 0 );
716     }
717
718     /*
719      * Try to run the interface
720      */
721     p_main->p_intf = intf_Create();
722     if( p_main->p_intf == NULL )
723     {
724         intf_ErrMsg( "intf error: interface initialization failed" );
725     }
726     else
727     {
728         /*
729          * Set signal handling policy for all threads
730          */
731         InitSignalHandler();
732
733         /*
734          * This is the main loop
735          */
736         p_main->p_intf->pf_run( p_main->p_intf );
737
738         /*
739          * Finished, destroy the interface
740          */
741         intf_Destroy( p_main->p_intf );
742
743         /*
744          * Go back into channel 0 which is the network
745          */
746         if( config_GetIntVariable( "network_channel" ) )
747         {
748             network_ChannelJoin( COMMON_CHANNEL );
749         }
750     }
751
752     /*
753      * Free input, aout and vout banks
754      */
755     input_EndBank();
756     vout_EndBank();
757     aout_EndBank();
758
759     /*
760      * Free playlist
761      */
762     intf_PlaylistDestroy( p_main->p_playlist );
763
764     /*
765      * Free memcpy module if it was allocated
766      */
767     if( p_main->p_memcpy_module != NULL )
768     {
769         module_Unneed( p_main->p_memcpy_module );
770     }
771
772     /*
773      * Free module bank
774      */
775     module_EndBank();
776
777     /*
778      * System specific cleaning code
779      */
780 #if defined( SYS_BEOS ) || defined( SYS_DARWIN ) || defined( WIN32 )
781     system_End();
782 #endif
783
784
785     /*
786      * Terminate messages interface and program
787      */
788     intf_WarnMsg( 1, "intf: program terminated" );
789     intf_MsgDestroy();
790
791     /*
792      * Stop threads system
793      */
794     vlc_threads_end( );
795
796     return 0;
797 }
798
799
800 /* following functions are local */
801
802 /*****************************************************************************
803  * GetConfigurationFromCmdLine: parse command line
804  *****************************************************************************
805  * Parse command line for configuration. If the inline help is requested, the
806  * function Usage() is called and the function returns -1 (causing main() to
807  * exit).
808  * Now that the module_bank has been initialized, we can dynamically
809  * generate the longopts structure used by getops. We have to do it this way
810  * because we don't know (and don't want to know) in advance the configuration
811  * options used (ie. exported) by each module.
812  *****************************************************************************/
813 static int GetConfigurationFromCmdLine( int *pi_argc, char *ppsz_argv[],
814                                         boolean_t b_ignore_errors )
815 {
816     int i_cmd, i, i_index, i_longopts_size;
817     module_t *p_module;
818     struct option *p_longopts;
819
820     /* Short options */
821     const char *psz_shortopts = "hHvlp:";
822
823     /* Set default configuration and copy arguments */
824     p_main->i_argc    = *pi_argc;
825     p_main->ppsz_argv = ppsz_argv;
826
827     p_main->p_channel = NULL;
828
829 #ifdef SYS_DARWIN
830     /* When vlc.app is run by double clicking in Mac OS X, the 2nd arg
831      * is the PSN - process serial number (a unique PID-ish thingie)
832      * still ok for real Darwin & when run from command line */
833     if ( (*pi_argc > 1) && (strncmp( ppsz_argv[ 1 ] , "-psn" , 4 ) == 0) )
834                                         /* for example -psn_0_9306113 */
835     {
836         /* GDMF!... I can't do this or else the MacOSX window server will
837          * not pick up the PSN and not register the app and we crash...
838          * hence the following kludge otherwise we'll get confused w/ argv[1]
839          * being an input file name */
840 #if 0
841         ppsz_argv[ 1 ] = NULL;
842 #endif
843         *pi_argc = *pi_argc - 1;
844         pi_argc--;
845         return( 0 );
846     }
847 #endif
848
849
850     /*
851      * Generate the longopts structure used by getopt_long
852      */
853     i_longopts_size = 0;
854     for( p_module = p_module_bank->first;
855          p_module != NULL ;
856          p_module = p_module->next )
857     {
858         /* count the number of exported configuration options (to allocate
859          * longopts). */
860         i_longopts_size += p_module->i_config_items;
861     }
862
863     p_longopts = (struct option *)malloc( sizeof(struct option)
864                                           * (i_longopts_size + 1) );
865     if( p_longopts == NULL )
866     {
867         intf_ErrMsg( "GetConfigurationFromCmdLine error: "
868                      "can't allocate p_longopts" );
869         return( -1 );
870     }
871
872     /* Fill the longopts structure */
873     i_index = 0;
874     for( p_module = p_module_bank->first ;
875          p_module != NULL ;
876          p_module = p_module->next )
877     {
878         for( i = 0; i < p_module->i_config_lines; i++ )
879         {
880             if( p_module->p_config[i].i_type & MODULE_CONFIG_HINT )
881                 /* ignore hints */
882                 continue;
883             p_longopts[i_index].name = p_module->p_config[i].psz_name;
884             p_longopts[i_index].has_arg =
885                 (p_module->p_config[i].i_type == MODULE_CONFIG_ITEM_BOOL)?
886                                                no_argument : required_argument;
887             p_longopts[i_index].flag = 0;
888             p_longopts[i_index].val = 0;
889             i_index++;
890         }
891     }
892     /* Close the longopts structure */
893     memset( &p_longopts[i_index], 0, sizeof(struct option) );
894
895
896     /*
897      * Parse the command line options
898      */
899     opterr = 0;
900     optind = 1;
901     while( ( i_cmd = getopt_long( *pi_argc, ppsz_argv, psz_shortopts,
902                                   p_longopts, &i_index ) ) != EOF )
903     {
904
905         if( i_cmd == 0 )
906         {
907             /* A long option has been recognized */
908
909             module_config_t *p_conf;
910
911             /* Store the configuration option */
912             p_conf = config_FindConfig( p_longopts[i_index].name );
913
914             switch( p_conf->i_type )
915             {
916             case MODULE_CONFIG_ITEM_STRING:
917             case MODULE_CONFIG_ITEM_FILE:
918             case MODULE_CONFIG_ITEM_PLUGIN:
919                 config_PutPszVariable( p_longopts[i_index].name, optarg );
920                 break;
921             case MODULE_CONFIG_ITEM_INTEGER:
922                 config_PutIntVariable( p_longopts[i_index].name, atoi(optarg));
923                 break;
924             case MODULE_CONFIG_ITEM_BOOL:
925                 config_PutIntVariable( p_longopts[i_index].name, 1 );
926                 break;
927             }
928
929             continue;
930         }
931
932         /* short options handled here for now */
933         switch( i_cmd )
934         {
935
936         /* General/common options */
937         case 'h':                                              /* -h, --help */
938             config_PutIntVariable( "help", 1 );
939             break;
940         case 'H':                                          /* -H, --longhelp */
941             config_PutIntVariable( "longhelp", 1 );
942             break;
943         case 'l':                                              /* -l, --list */
944             config_PutIntVariable( "list", 1 );
945             break;
946         case 'p':                                            /* -p, --plugin */
947             config_PutPszVariable( "plugin", optarg );
948             break;
949         case 'v':                                           /* -v, --verbose */
950             p_main->i_warning_level++;
951             break;
952
953         /* Internal error: unknown option */
954         case '?':
955         default:
956
957             if( !b_ignore_errors )
958             {
959                 intf_ErrMsg( "intf error: unknown option `%s'",
960                              ppsz_argv[optind-1] );
961                 intf_Msg( "Try `%s --help' for more information.\n",
962                           p_main->psz_arg0 );
963
964 #ifdef WIN32        /* Pause the console because it's destroyed when we exit */
965                 intf_Msg( "\nPress the RETURN key to continue..." );
966                 getchar();
967 #endif
968                 free( p_longopts );
969                 return( EINVAL );
970             }
971         }
972
973     }
974
975     if( p_main->i_warning_level < 0 )
976     {
977         p_main->i_warning_level = 0;
978     }
979
980     free( p_longopts );
981     return( 0 );
982 }
983
984 /*****************************************************************************
985  * GetFilenames: parse command line options which are not flags
986  *****************************************************************************
987  * Parse command line for input files.
988  *****************************************************************************/
989 static int GetFilenames( int i_argc, char *ppsz_argv[] )
990 {
991     int i_opt;
992
993     /* We assume that the remaining parameters are filenames */
994     for( i_opt = optind; i_opt < i_argc; i_opt++ )
995     {
996         intf_PlaylistAdd( p_main->p_playlist, PLAYLIST_END,
997                           ppsz_argv[ i_opt ] );
998     }
999
1000     return( 0 );
1001 }
1002
1003 /*****************************************************************************
1004  * Usage: print program usage
1005  *****************************************************************************
1006  * Print a short inline help. Message interface is initialized at this stage.
1007  *****************************************************************************/
1008 static void Usage( const char *psz_module_name )
1009 {
1010     int i;
1011     module_t *p_module;
1012     char psz_spaces[30];
1013
1014     memset( psz_spaces, 32, 30 );
1015
1016 #ifdef WIN32
1017     ShowConsole();
1018 #endif
1019
1020     /* Enumerate the config of each module */
1021     for( p_module = p_module_bank->first ;
1022          p_module != NULL ;
1023          p_module = p_module->next )
1024     {
1025
1026         if( psz_module_name && strcmp( psz_module_name, p_module->psz_name ) )
1027             continue;
1028
1029         /* ignore plugins without config options */
1030         if( !p_module->i_config_items ) continue;
1031
1032         /* print module name */
1033         intf_Msg( "%s options:\n", p_module->psz_name );
1034
1035         for( i = 0; i < p_module->i_config_lines; i++ )
1036         {
1037             int j;
1038
1039             switch( p_module->p_config[i].i_type )
1040             {
1041             case MODULE_CONFIG_HINT_CATEGORY:
1042                 intf_Msg( " %s", p_module->p_config[i].psz_text );
1043                 break;
1044
1045             case MODULE_CONFIG_ITEM_STRING:
1046             case MODULE_CONFIG_ITEM_FILE:
1047             case MODULE_CONFIG_ITEM_PLUGIN:
1048                 /* Nasty hack, but right now I'm too tired to think about
1049                  * a nice solution */
1050                 j = 25 - strlen( p_module->p_config[i].psz_name )
1051                     - strlen(" <string>") - 1;
1052                 if( j < 0 ) j = 0; psz_spaces[j] = 0;
1053
1054                 intf_Msg( "  --%s <string>%s %s",
1055                           p_module->p_config[i].psz_name, psz_spaces,
1056                           p_module->p_config[i].psz_text );
1057                 psz_spaces[j] = 32;
1058                 break;
1059             case MODULE_CONFIG_ITEM_INTEGER:
1060                 /* Nasty hack, but right now I'm too tired to think about
1061                  * a nice solution */
1062                 j = 25 - strlen( p_module->p_config[i].psz_name )
1063                     - strlen(" <integer>") - 1;
1064                 if( j < 0 ) j = 0; psz_spaces[j] = 0;
1065
1066                 intf_Msg( "  --%s <integer>%s %s",
1067                           p_module->p_config[i].psz_name, psz_spaces,
1068                           p_module->p_config[i].psz_text );
1069                 psz_spaces[j] = 32;
1070                 break;
1071             case MODULE_CONFIG_ITEM_BOOL:
1072                 /* Nasty hack, but right now I'm too tired to think about
1073                  * a nice solution */
1074                 j = 25 - strlen( p_module->p_config[i].psz_name ) - 1;
1075                 if( j < 0 ) j = 0; psz_spaces[j] = 0;
1076
1077                 intf_Msg( "  --%s%s %s",
1078                           p_module->p_config[i].psz_name, psz_spaces,
1079                           p_module->p_config[i].psz_text );
1080                 psz_spaces[j] = 32;
1081                 break;
1082             }
1083         }
1084
1085         /* Yet another nasty hack.
1086          * Maybe we could use MODULE_CONFIG_ITEM_END to display tail messages
1087          * for each module?? */
1088         if( !strcmp( "main", p_module->psz_name ) )
1089             intf_Msg( "\nPlaylist items:"
1090                 "\n  *.mpg, *.vob                   \tPlain MPEG-1/2 files"
1091                 "\n  [dvd:][device][@raw_device][@[title][,[chapter][,angle]]]"
1092                 "\n                                 \tDVD device"
1093                 "\n  [vcd:][device][@[title][,[chapter]]"
1094                 "\n                                 \tVCD device"
1095                 "\n  udpstream:[<server>[:<server port>]][@[<bind address>]"
1096                       "[:<bind port>]]"
1097                 "\n                                 \tUDP stream sent by VLS"
1098                 "\n  vlc:loop                       \tLoop execution of the "
1099                       "playlist"
1100                 "\n  vlc:pause                      \tPause execution of "
1101                       "playlist items"
1102                 "\n  vlc:quit                       \tQuit VLC" );
1103
1104         intf_Msg( "" );
1105
1106     }
1107
1108 #ifdef WIN32        /* Pause the console because it's destroyed when we exit */
1109         intf_Msg( "\nPress the RETURN key to continue..." );
1110         getchar();
1111 #endif
1112 }
1113
1114 /*****************************************************************************
1115  * ListModules: list the available modules with their description
1116  *****************************************************************************
1117  * Print a list of all available modules (builtins and plugins) and a short
1118  * description for each one.
1119  *****************************************************************************/
1120 static void ListModules( void )
1121 {
1122     module_t *p_module;
1123     char psz_spaces[20];
1124
1125     memset( psz_spaces, 32, 20 );
1126
1127 #ifdef WIN32
1128     ShowConsole();
1129 #endif
1130
1131     /* Usage */
1132     intf_Msg( "Usage: %s [options] [parameters] [file]...\n",
1133               p_main->psz_arg0 );
1134
1135     intf_Msg( "[plugin]              [description]" );
1136
1137     /* Enumerate each module */
1138     for( p_module = p_module_bank->first ;
1139          p_module != NULL ;
1140          p_module = p_module->next )
1141     {
1142         int i;
1143
1144         /* Nasty hack, but right now I'm too tired to think about a nice
1145          * solution */
1146         i = 20 - strlen( p_module->psz_name ) - 1;
1147         if( i < 0 ) i = 0;
1148         psz_spaces[i] = 0;
1149
1150         intf_Msg( "  %s%s %s", p_module->psz_name, psz_spaces,
1151                   p_module->psz_longname );
1152
1153         psz_spaces[i] = 32;
1154
1155     }
1156
1157 #ifdef WIN32        /* Pause the console because it's destroyed when we exit */
1158         intf_Msg( "\nPress the RETURN key to continue..." );
1159         getchar();
1160 #endif
1161 }
1162
1163 /*****************************************************************************
1164  * Version: print complete program version
1165  *****************************************************************************
1166  * Print complete program version and build number.
1167  *****************************************************************************/
1168 static void Version( void )
1169 {
1170 #ifdef WIN32
1171     ShowConsole();
1172 #endif
1173     intf_Msg( VERSION_MESSAGE
1174         "This program comes with NO WARRANTY, to the extent permitted by law.\n"
1175         "You may redistribute it under the terms of the GNU General Public License;\n"
1176         "see the file named COPYING for details.\n"
1177         "Written by the VideoLAN team at Ecole Centrale, Paris." );
1178 #ifdef WIN32        /* Pause the console because it's destroyed when we exit */
1179         intf_Msg( "\nPress the RETURN key to continue..." );
1180         getchar();
1181 #endif
1182 }
1183
1184 /*****************************************************************************
1185  * InitSignalHandler: system signal handler initialization
1186  *****************************************************************************
1187  * Set the signal handlers. SIGTERM is not intercepted, because we need at
1188  * at least a method to kill the program when all other methods failed, and
1189  * when we don't want to use SIGKILL.
1190  *****************************************************************************/
1191 static void InitSignalHandler( void )
1192 {
1193     /* Termination signals */
1194 #ifndef WIN32
1195     signal( SIGINT,  FatalSignalHandler );
1196     signal( SIGHUP,  FatalSignalHandler );
1197     signal( SIGQUIT, FatalSignalHandler );
1198
1199     /* Other signals */
1200     signal( SIGALRM, SimpleSignalHandler );
1201     signal( SIGPIPE, SimpleSignalHandler );
1202 #endif
1203 }
1204
1205 /*****************************************************************************
1206  * SimpleSignalHandler: system signal handler
1207  *****************************************************************************
1208  * This function is called when a non fatal signal is received by the program.
1209  *****************************************************************************/
1210 static void SimpleSignalHandler( int i_signal )
1211 {
1212     /* Acknowledge the signal received */
1213     intf_WarnMsg( 0, "intf: ignoring signal %d", i_signal );
1214 }
1215
1216 /*****************************************************************************
1217  * FatalSignalHandler: system signal handler
1218  *****************************************************************************
1219  * This function is called when a fatal signal is received by the program.
1220  * It tries to end the program in a clean way.
1221  *****************************************************************************/
1222 static void FatalSignalHandler( int i_signal )
1223 {
1224     /* Once a signal has been trapped, the termination sequence will be
1225      * armed and following signals will be ignored to avoid sending messages
1226      * to an interface having been destroyed */
1227 #ifndef WIN32
1228     signal( SIGINT,  SIG_IGN );
1229     signal( SIGHUP,  SIG_IGN );
1230     signal( SIGQUIT, SIG_IGN );
1231 #endif
1232
1233     /* Acknowledge the signal received */
1234     intf_ErrMsg( "intf error: signal %d received, exiting", i_signal );
1235
1236     /* Try to terminate everything - this is done by requesting the end of the
1237      * interface thread */
1238     p_main->p_intf->b_die = 1;
1239 }
1240
1241 /*****************************************************************************
1242  * IllegalSignalHandler: system signal handler
1243  *****************************************************************************
1244  * This function is called when an illegal instruction signal is received by
1245  * the program. We use this function to test OS and CPU capabilities
1246  *****************************************************************************/
1247 static void IllegalSignalHandler( int i_signal )
1248 {
1249     /* Acknowledge the signal received */
1250     i_illegal = 1;
1251
1252 #ifdef HAVE_SIGRELSE
1253     sigrelse( i_signal );
1254 #endif
1255
1256     fprintf( stderr, "warning: your CPU has %s instructions, but not your "
1257                      "operating system.\n", psz_capability );
1258     fprintf( stderr, "         some optimizations will be disabled unless "
1259                      "you upgrade your OS\n" );
1260 #ifdef SYS_LINUX
1261     fprintf( stderr, "         (for instance Linux kernel 2.4.x or later)" );
1262 #endif
1263
1264     longjmp( env, 1 );
1265 }
1266
1267 /*****************************************************************************
1268  * CPUCapabilities: list the processors MMX support and other capabilities
1269  *****************************************************************************
1270  * This function is called to list extensions the CPU may have.
1271  *****************************************************************************/
1272 static u32 CPUCapabilities( void )
1273 {
1274     volatile u32 i_capabilities = CPU_CAPABILITY_NONE;
1275
1276 #if defined( SYS_DARWIN )
1277     struct host_basic_info hi;
1278     kern_return_t          ret;
1279     host_name_port_t       host;
1280
1281     int i_size;
1282     char *psz_name, *psz_subname;
1283
1284     i_capabilities |= CPU_CAPABILITY_FPU;
1285
1286     /* Should 'never' fail? */
1287     host = mach_host_self();
1288
1289     i_size = sizeof( hi ) / sizeof( int );
1290     ret = host_info( host, HOST_BASIC_INFO, ( host_info_t )&hi, &i_size );
1291
1292     if( ret != KERN_SUCCESS )
1293     {
1294         fprintf( stderr, "error: couldn't get CPU information\n" );
1295         return( i_capabilities );
1296     }
1297
1298     slot_name( hi.cpu_type, hi.cpu_subtype, &psz_name, &psz_subname );
1299     /* FIXME: need better way to detect newer proccessors.
1300      * could do strncmp(a,b,5), but that's real ugly */
1301     if( !strcmp(psz_name, "ppc7400") || !strcmp(psz_name, "ppc7450") )
1302     {
1303         i_capabilities |= CPU_CAPABILITY_ALTIVEC;
1304     }
1305
1306     return( i_capabilities );
1307
1308 #elif defined( __i386__ )
1309     volatile unsigned int  i_eax, i_ebx, i_ecx, i_edx;
1310     volatile boolean_t     b_amd;
1311
1312     /* Needed for x86 CPU capabilities detection */
1313 #   define cpuid( a )                      \
1314         asm volatile ( "pushl %%ebx\n\t"   \
1315                        "cpuid\n\t"         \
1316                        "movl %%ebx,%1\n\t" \
1317                        "popl %%ebx\n\t"    \
1318                      : "=a" ( i_eax ),     \
1319                        "=r" ( i_ebx ),     \
1320                        "=c" ( i_ecx ),     \
1321                        "=d" ( i_edx )      \
1322                      : "a"  ( a )          \
1323                      : "cc" );
1324
1325     i_capabilities |= CPU_CAPABILITY_FPU;
1326
1327 #   if defined( CAN_COMPILE_SSE ) || defined ( CAN_COMPILE_3DNOW )
1328     signal( SIGILL, IllegalSignalHandler );
1329 #   endif
1330
1331     /* test for a 486 CPU */
1332     asm volatile ( "pushl %%ebx\n\t"
1333                    "pushfl\n\t"
1334                    "popl %%eax\n\t"
1335                    "movl %%eax, %%ebx\n\t"
1336                    "xorl $0x200000, %%eax\n\t"
1337                    "pushl %%eax\n\t"
1338                    "popfl\n\t"
1339                    "pushfl\n\t"
1340                    "popl %%eax\n\t"
1341                    "movl %%ebx,%1\n\t"
1342                    "popl %%ebx\n\t"
1343                  : "=a" ( i_eax ),
1344                    "=r" ( i_ebx )
1345                  :
1346                  : "cc" );
1347
1348     if( i_eax == i_ebx )
1349     {
1350 #   if defined( CAN_COMPILE_SSE ) || defined ( CAN_COMPILE_3DNOW )
1351         signal( SIGILL, NULL );
1352 #   endif
1353         return( i_capabilities );
1354     }
1355
1356     i_capabilities |= CPU_CAPABILITY_486;
1357
1358     /* the CPU supports the CPUID instruction - get its level */
1359     cpuid( 0x00000000 );
1360
1361     if( !i_eax )
1362     {
1363 #   if defined( CAN_COMPILE_SSE ) || defined ( CAN_COMPILE_3DNOW )
1364         signal( SIGILL, NULL );
1365 #   endif
1366         return( i_capabilities );
1367     }
1368
1369     /* FIXME: this isn't correct, since some 486s have cpuid */
1370     i_capabilities |= CPU_CAPABILITY_586;
1371
1372     /* borrowed from mpeg2dec */
1373     b_amd = ( i_ebx == 0x68747541 ) && ( i_ecx == 0x444d4163 )
1374                     && ( i_edx == 0x69746e65 );
1375
1376     /* test for the MMX flag */
1377     cpuid( 0x00000001 );
1378
1379     if( ! (i_edx & 0x00800000) )
1380     {
1381 #   if defined( CAN_COMPILE_SSE ) || defined ( CAN_COMPILE_3DNOW )
1382         signal( SIGILL, NULL );
1383 #   endif
1384         return( i_capabilities );
1385     }
1386
1387     i_capabilities |= CPU_CAPABILITY_MMX;
1388
1389     if( i_edx & 0x02000000 )
1390     {
1391         i_capabilities |= CPU_CAPABILITY_MMXEXT;
1392
1393 #   ifdef CAN_COMPILE_SSE
1394         /* We test if OS support the SSE instructions */
1395         psz_capability = "SSE";
1396         i_illegal = 0;
1397         if( setjmp( env ) == 0 )
1398         {
1399             /* Test a SSE instruction */
1400             __asm__ __volatile__ ( "xorps %%xmm0,%%xmm0\n" : : );
1401         }
1402
1403         if( i_illegal == 0 )
1404         {
1405             i_capabilities |= CPU_CAPABILITY_SSE;
1406         }
1407 #   endif
1408     }
1409
1410     /* test for additional capabilities */
1411     cpuid( 0x80000000 );
1412
1413     if( i_eax < 0x80000001 )
1414     {
1415 #   if defined( CAN_COMPILE_SSE ) || defined ( CAN_COMPILE_3DNOW )
1416         signal( SIGILL, NULL );
1417 #   endif
1418         return( i_capabilities );
1419     }
1420
1421     /* list these additional capabilities */
1422     cpuid( 0x80000001 );
1423
1424 #   ifdef CAN_COMPILE_3DNOW
1425     if( i_edx & 0x80000000 )
1426     {
1427         psz_capability = "3D Now!";
1428         i_illegal = 0;
1429         if( setjmp( env ) == 0 )
1430         {
1431             /* Test a 3D Now! instruction */
1432             __asm__ __volatile__ ( "pfadd %%mm0,%%mm0\n" "femms\n" : : );
1433         }
1434
1435         if( i_illegal == 0 )
1436         {
1437             i_capabilities |= CPU_CAPABILITY_3DNOW;
1438         }
1439     }
1440 #   endif
1441
1442     if( b_amd && ( i_edx & 0x00400000 ) )
1443     {
1444         i_capabilities |= CPU_CAPABILITY_MMXEXT;
1445     }
1446
1447 #   if defined( CAN_COMPILE_SSE ) || defined ( CAN_COMPILE_3DNOW )
1448     signal( SIGILL, NULL );
1449 #   endif
1450     return( i_capabilities );
1451
1452 #elif defined( __powerpc__ )
1453
1454     i_capabilities |= CPU_CAPABILITY_FPU;
1455
1456 #   ifdef CAN_COMPILE_ALTIVEC
1457     signal( SIGILL, IllegalSignalHandler );
1458
1459     psz_capability = "AltiVec";
1460     i_illegal = 0;
1461     if( setjmp( env ) == 0 )
1462     {
1463         asm volatile ("mtspr 256, %0\n\t"
1464                       "vand %%v0, %%v0, %%v0"
1465                       :
1466                       : "r" (-1));
1467     }
1468
1469     if( i_illegal == 0 )
1470     {
1471         i_capabilities |= CPU_CAPABILITY_ALTIVEC;
1472     }
1473
1474     signal( SIGILL, NULL );
1475 #   endif
1476
1477     return( i_capabilities );
1478
1479 #else
1480     /* default behaviour */
1481     return( i_capabilities );
1482
1483 #endif
1484 }
1485
1486 /*****************************************************************************
1487  * ShowConsole: On Win32, create an output console for debug messages
1488  *****************************************************************************
1489  * This function is usefull only on Win32.
1490  *****************************************************************************/
1491 #ifdef WIN32 /*  */
1492 static void ShowConsole( void )
1493 {
1494     AllocConsole();
1495     freopen( "CONOUT$", "w", stdout );
1496     freopen( "CONOUT$", "w", stderr );
1497     freopen( "CONIN$", "r", stdin );
1498     return;
1499 }
1500 #endif