]> git.sesse.net Git - vlc/blob - src/interface/main.c
. d�tection d'un processeur MMX.
[vlc] / src / interface / main.c
1 /*****************************************************************************
2  * main.c: main vlc source
3  * (c)1998 VideoLAN
4  *****************************************************************************
5  * Includes the main() function for vlc. Parses command line, start interface
6  * and spawn threads.
7  *****************************************************************************/
8
9 /*****************************************************************************
10  * Preamble
11  *****************************************************************************/
12 #include <errno.h>
13 #include <getopt.h>
14 #include <signal.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18
19 #include <sys/soundcard.h>                                 /* audio_output.h */
20
21 #include "config.h"
22 #include "common.h"
23 #include "mtime.h"
24 #include "vlc_thread.h"
25 #include "input_vlan.h"
26 #include "intf_msg.h"
27 #include "interface.h"
28 #include "audio_output.h"
29 #include "main.h"
30
31 /*****************************************************************************
32  * Command line options constants. If something is changed here, be sure that
33  * GetConfiguration and Usage are also changed.
34  *****************************************************************************/
35
36 /* Long options return values - note that values corresponding to short options
37  * chars, and in general any regular char, should be avoided */
38 #define OPT_NOAUDIO             150
39 #define OPT_STEREO              151
40 #define OPT_MONO                152
41
42 #define OPT_NOVIDEO             160
43 #define OPT_DISPLAY             161
44 #define OPT_WIDTH               162
45 #define OPT_HEIGHT              163
46 #define OPT_COLOR               164
47
48 #define OPT_NOVLANS             170
49 #define OPT_SERVER              171
50 #define OPT_PORT                172
51
52 /* Long options */
53 static const struct option longopts[] =
54 {
55     /*  name,               has_arg,    flag,   val */
56
57     /* General/common options */
58     {   "help",             0,          0,      'h' },
59     {   "version",          0,          0,      'v' },
60
61     /* Audio options */
62     {   "noaudio",          0,          0,      OPT_NOAUDIO },
63     {   "stereo",           0,          0,      OPT_STEREO },
64     {   "mono",             0,          0,      OPT_MONO },
65
66     /* Video options */
67     {   "novideo",          0,          0,      OPT_NOVIDEO },
68     {   "display",          1,          0,      OPT_DISPLAY },
69     {   "width",            1,          0,      OPT_WIDTH },
70     {   "height",           1,          0,      OPT_HEIGHT },
71     {   "grayscale",        0,          0,      'g' },
72     {   "color",            0,          0,      OPT_COLOR },
73
74     /* Input options */
75     {   "novlans",          0,          0,      OPT_NOVLANS },
76     {   "server",           1,          0,      OPT_SERVER },
77     {   "port",             1,          0,      OPT_PORT },
78
79     {   0,                  0,          0,      0 }
80 };
81
82 /* Short options */
83 static const char *psz_shortopts = "hvg";
84
85 /*****************************************************************************
86  * Global variable program_data - this is the one and only, see main.h
87  *****************************************************************************/
88 main_t *p_main;
89
90 /*****************************************************************************
91  * Local prototypes
92  *****************************************************************************/
93 static void SetDefaultConfiguration ( void );
94 static int  GetConfiguration        ( int i_argc, char *ppsz_argv[], char *ppsz_env[] );
95 static void Usage                   ( void );
96 static void Version                 ( void );
97
98 static void InitSignalHandler       ( void );
99 static void SignalHandler           ( int i_signal );
100 static int  TestMMX                 ( void );
101
102 /*****************************************************************************
103  * main: parse command line, start interface and spawn threads
104  *****************************************************************************
105  * Steps during program execution are:
106  *      -configuration parsing and messages interface initialization
107  *      -openning of audio output device and some global modules
108  *      -execution of interface, which exit on error or on user request
109  *      -closing of audio output device and some global modules
110  * On error, the spawned threads are cancelled, and the openned devices closed.
111  *****************************************************************************/
112 int main( int i_argc, char *ppsz_argv[], char *ppsz_env[] )
113 {
114     main_t  main_data;                      /* root of all data - see main.h */
115     p_main = &main_data;                       /* set up the global variable */
116
117     /*
118      * Read configuration, initialize messages interface and set up program
119      */
120 #ifdef HAVE_MMX
121     if( !TestMMX() )
122     {
123         fprintf( stderr, "Sorry, this program needs an MMX processor. Please run the non-MMX version.\n" );
124         return(0);
125     }
126 #endif
127     p_main->p_msg = intf_MsgCreate();
128     if( !p_main->p_msg )                         /* start messages interface */
129     {
130         fprintf(stderr, "critical error: can't initialize messages interface (%s)\n",
131                 strerror(errno));
132         return(errno);
133     }
134     if( GetConfiguration( i_argc, ppsz_argv, ppsz_env ) )/* parse command line */
135     {
136         intf_MsgDestroy();
137         return(errno);
138     }
139     intf_MsgImm( COPYRIGHT_MESSAGE "\n" );          /* print welcome message */
140
141     /*
142      * Initialize shared resources and libraries
143      */
144     if( main_data.b_vlans && input_VlanCreate() )
145     {
146         /* On error during vlans initialization, switch of vlans */
147         intf_Msg("Virtual LANs initialization failed : vlans management is desactivated\n");
148         main_data.b_vlans = 0;
149     }
150
151     /*
152      * Open audio device and start aout thread
153      */
154     if( main_data.b_audio )
155     {
156         main_data.p_aout = aout_CreateThread( NULL );
157         if( main_data.p_aout == NULL )
158         {
159             /* On error during audio initialization, switch of audio */
160             intf_Msg("Audio initialization failed : audio is desactivated\n");
161             main_data.b_audio = 0;
162         }
163     }
164
165     /*
166      * Run interface
167      */
168     main_data.p_intf = intf_Create();
169     if( main_data.p_intf != NULL )
170     {
171         InitSignalHandler();               /* prepare signals for interception */
172         intf_Run( main_data.p_intf );
173         intf_Destroy( main_data.p_intf );
174     }
175
176     /*
177      * Close audio device
178      */
179     if( main_data.b_audio )
180     {
181         aout_DestroyThread( main_data.p_aout, NULL );
182     }
183
184     /*
185      * Free shared resources and libraries
186      */
187     if( main_data.b_vlans )
188     {
189         input_VlanDestroy();
190     }
191
192     /*
193      * Terminate messages interface and program
194      */
195     intf_Msg( "Program terminated.\n" );
196     intf_MsgDestroy();
197     return( 0 );
198 }
199
200 /*****************************************************************************
201  * main_GetIntVariable: get the int value of an environment variable
202  *****************************************************************************
203  * This function is used to read some default parameters in modules.
204  *****************************************************************************/
205 int main_GetIntVariable( char *psz_name, int i_default )
206 {
207     char *      psz_env;                                /* environment value */
208     char *      psz_end;                             /* end of parsing index */
209     long int    i_value;                                            /* value */
210
211     psz_env = getenv( psz_name );
212     if( psz_env )
213     {
214         i_value = strtol( psz_env, &psz_end, 0 );
215         if( (*psz_env != '\0') && (*psz_end == '\0') )
216         {
217             return( i_value );
218         }
219     }   
220     return( i_default );
221 }
222
223 /*****************************************************************************
224  * main_GetPszVariable: get the string value of an environment variable
225  *****************************************************************************
226  * This function is used to read some default parameters in modules.
227  *****************************************************************************/
228 char * main_GetPszVariable( char *psz_name, char *psz_default )
229 {
230     char *psz_env;
231
232     psz_env = getenv( psz_name );
233     if( psz_env )
234     {
235         return( psz_env );
236     }
237     return( psz_default );
238 }
239
240 /*****************************************************************************
241  * main_PutPszVariable: set the string value of an environment variable
242  *****************************************************************************
243  * This function is used to set some default parameters in modules. The use of
244  * this function will cause some memory leak: since some systems use the pointer
245  * passed to putenv to store the environment string, it can't be freed.
246  *****************************************************************************/
247 void main_PutPszVariable( char *psz_name, char *psz_value )
248 {
249     char *psz_env;
250
251     psz_env = malloc( strlen(psz_name) + strlen(psz_value) + 2 );
252     if( psz_env == NULL )
253     {
254         intf_ErrMsg("error: %s\n", strerror(ENOMEM));
255     }
256     else
257     {
258         sprintf( psz_env, "%s=%s", psz_name, psz_value );
259         if( putenv( psz_env ) )
260         {
261             intf_ErrMsg("error: %s\n", strerror(errno));
262         }
263     }
264 }
265
266 /*****************************************************************************
267  * main_PutIntVariable: set the integer value of an environment variable
268  *****************************************************************************
269  * This function is used to set some default parameters in modules. The use of
270  * this function will cause some memory leak: since some systems use the pointer
271  * passed to putenv to store the environment string, it can't be freed.
272  *****************************************************************************/
273 void main_PutIntVariable( char *psz_name, int i_value )
274 {
275     char psz_value[ 256 ];                               /* buffer for value */
276
277     sprintf(psz_value, "%d", i_value );
278     main_PutPszVariable( psz_name, psz_value );
279 }
280
281 /* following functions are local */
282
283 /*****************************************************************************
284  * SetDefaultConfiguration: set default options
285  *****************************************************************************
286  * This function is called by GetConfiguration before command line is parsed.
287  * It sets all the default values required later by the program. At this stage,
288  * most structure are not yet allocated, so initialization must be done using
289  * environment.
290  *****************************************************************************/
291 static void SetDefaultConfiguration( void )
292 {
293     /*
294      * All features are activated by default
295      */
296     p_main->b_audio  = 1;
297     p_main->b_video  = 1;
298     p_main->b_vlans  = 1;
299 }
300
301 /*****************************************************************************
302  * GetConfiguration: parse command line
303  *****************************************************************************
304  * Parse command line and configuration file for configuration. If the inline
305  * help is requested, the function Usage() is called and the function returns
306  * -1 (causing main() to exit). The messages interface is initialized at this
307  * stage, but most structures are not allocated, so only environment should
308  * be used.
309  *****************************************************************************/
310 static int GetConfiguration( int i_argc, char *ppsz_argv[], char *ppsz_env[] )
311 {
312     int c, i_opt;
313
314     /* Set default configuration and copy arguments */
315     p_main->i_argc    = i_argc;
316     p_main->ppsz_argv = ppsz_argv;
317     p_main->ppsz_env  = ppsz_env;
318     SetDefaultConfiguration();
319
320     /* Parse command line options */
321     opterr = 0;
322     while( ( c = getopt_long( i_argc, ppsz_argv, psz_shortopts, longopts, 0 ) ) != EOF )
323     {
324         switch( c )
325         {
326         /* General/common options */
327         case 'h':                                              /* -h, --help */
328             Usage();
329             return( -1 );
330             break;
331         case 'v':                                           /* -v, --version */
332             Version();
333             return( -1 );
334             break;
335
336         /* Audio options */
337         case OPT_NOAUDIO:                                       /* --noaudio */
338             p_main->b_audio = 0;
339             break;
340         case OPT_STEREO:                                         /* --stereo */
341             main_PutIntVariable( AOUT_STEREO_VAR, 1 );
342             break;
343         case OPT_MONO:                                             /* --mono */
344             main_PutIntVariable( AOUT_STEREO_VAR, 0 );
345             break;
346
347         /* Video options */
348         case OPT_NOVIDEO:                                       /* --novideo */
349             p_main->b_video = 0;
350             break;
351         case OPT_DISPLAY:                                       /* --display */
352             main_PutPszVariable( VOUT_DISPLAY_VAR, optarg );
353             break;
354         case OPT_WIDTH:                                           /* --width */
355             main_PutPszVariable( VOUT_WIDTH_VAR, optarg );
356             break;
357         case OPT_HEIGHT:                                         /* --height */
358             main_PutPszVariable( VOUT_HEIGHT_VAR, optarg );
359             break;
360
361         case 'g':                                         /* -g, --grayscale */
362             main_PutIntVariable( VOUT_GRAYSCALE_VAR, 1 );
363             break;
364         case OPT_COLOR:                                           /* --color */
365             main_PutIntVariable( VOUT_GRAYSCALE_VAR, 0 );
366             break;
367
368         /* Input options */
369         case OPT_NOVLANS:                                       /* --novlans */
370             p_main->b_vlans = 0;
371             break;
372         case OPT_SERVER:                                         /* --server */
373             main_PutPszVariable( INPUT_SERVER_VAR, optarg );
374             break;
375         case OPT_PORT:                                             /* --port */
376             main_PutPszVariable( INPUT_PORT_VAR, optarg );
377             break;
378         
379         /* Internal error: unknown option */
380         case '?':
381         default:
382             intf_ErrMsg("intf error: unknown option '%s'\n", ppsz_argv[optind - 1]);
383             return( EINVAL );
384             break;
385         }
386     }
387
388     /* Parse command line parameters - no check is made for these options */
389     for( i_opt = optind; i_opt < i_argc; i_opt++ )
390     {
391         putenv( ppsz_argv[ i_opt ] );
392     }
393     return( 0 );
394 }
395
396 /*****************************************************************************
397  * Usage: print program usage
398  *****************************************************************************
399  * Print a short inline help. Message interface is initialized at this stage.
400  *****************************************************************************/
401 static void Usage( void )
402 {
403     intf_Msg(COPYRIGHT_MESSAGE "\n");
404
405     /* Usage */
406     intf_Msg("usage: vlc [options...] [parameters]\n" );
407
408     /* Options */
409     intf_Msg("Options:\n" \
410              "  -h, --help, -v, --version         \tprint usage or version\n" \
411              "  --noaudio, --novideo              \tdisable audio/video\n" \
412              "  --stereo, --mono                  \tstereo/mono audio\n" \
413              "  --display <display>               \tdisplay string\n" \
414              "  --width <w>, --height <h>         \tdisplay dimensions\n" \
415              "  -g, --grayscale, --color          \tgrayscale/color video\n" \
416              "  --novlans                         \tdisable vlans\n" \
417              "  --server <host>, --port <port>    \tvideo server adress\n" \
418              );
419
420     /* Interface parameters */
421     intf_Msg("Interface parameters:\n" \
422              "  " INTF_INIT_SCRIPT_VAR "=<filename>             \tinitialization script\n" \
423              "  " INTF_CHANNELS_VAR "=<filename>            \tchannels list\n"\
424              );
425
426     /* Audio parameters */
427     intf_Msg("Audio parameters:\n" \
428              "  " AOUT_DSP_VAR "=<filename>              \tdsp device path\n" \
429              "  " AOUT_STEREO_VAR "={1|0}                \tstereo or mono output\n" \
430              "  " AOUT_RATE_VAR "=<rate>             \toutput rate\n" \
431              );
432
433     /* Video parameters */
434     intf_Msg("Video parameters:\n" \
435              "  " VOUT_DISPLAY_VAR "=<display name>      \tdisplay used\n" \
436              "  " VOUT_WIDTH_VAR "=<width>               \tdisplay width\n" \
437              "  " VOUT_HEIGHT_VAR "=<height>             \tdislay height\n" \
438              "  " VOUT_FB_DEV_VAR "=<filename>           \tframebuffer device path\n" \
439              "  " VOUT_GRAYSCALE_VAR "={1|0}             \tgrayscale or color output\n" \
440              );
441
442     /* Input parameters */
443     intf_Msg("Input parameters:\n" \
444              "  " INPUT_SERVER_VAR "=<hostname>          \tvideo server\n" \
445              "  " INPUT_PORT_VAR "=<port>            \tvideo server port\n" \
446              "  " INPUT_IFACE_VAR "=<interface>          \tnetwork interface\n" \
447              "  " INPUT_VLAN_SERVER_VAR "=<hostname>     \tvlan server\n" \
448              "  " INPUT_VLAN_PORT_VAR "=<port>           \tvlan server port\n"\
449              );
450 }
451
452 /*****************************************************************************
453  * Version: print complete program version
454  *****************************************************************************
455  * Print complete program version and build number.
456  *****************************************************************************/
457 static void Version( void )
458 {
459     intf_Msg(VERSION_MESSAGE "\n\n");
460     intf_Msg("This is free software; see the documentation or contact <videolan@via.ecp.fr>\n" \
461              "for use and copying conditions.\n" \
462              "\n" \
463              "This software is protected by the international copyright laws, and is\n" \
464              "provided without any warranty, including the implied warranties of\n" \
465              "merchantibility and fitness for a particular purpose.\n" \
466             );
467 }
468
469 /*****************************************************************************
470  * InitSignalHandler: system signal handler initialization
471  *****************************************************************************
472  * Set the signal handlers. SIGTERM is not intercepted, because we need at
473  * at least a method to kill the program when all other methods failed, and
474  * when we don't want to use SIGKILL.
475  *****************************************************************************/
476 static void InitSignalHandler( void )
477 {
478     /* Termination signals */
479     signal( SIGHUP,  SignalHandler );
480     signal( SIGINT,  SignalHandler );
481     signal( SIGQUIT, SignalHandler );
482 }
483
484 /*****************************************************************************
485  * SignalHandler: system signal handler
486  *****************************************************************************
487  * This function is called when a signal is received by the program. It tries to
488  * end the program in a clean way.
489  *****************************************************************************/
490 static void SignalHandler( int i_signal )
491 {
492     /* Once a signal has been trapped, the termination sequence will be armed and
493      * following signals will be ignored to avoid sending messages to an interface
494      * having been destroyed */
495     signal( SIGHUP,  SIG_IGN );
496     signal( SIGINT,  SIG_IGN );
497     signal( SIGQUIT, SIG_IGN );
498
499     /* Acknowledge the signal received */
500     intf_ErrMsgImm("intf: signal %d received\n", i_signal );
501
502     /* Try to terminate everything - this is done by requesting the end of the
503      * interface thread */
504     p_main->p_intf->b_die = 1;
505 }
506
507 #ifdef HAVE_MMX
508 /*****************************************************************************
509  * TestMMX: tests if the processor has MMX support.
510  *****************************************************************************
511  * This function is called if HAVE_MMX is enabled, to check whether the
512  * cpu really supports MMX.
513  *****************************************************************************/
514 static int TestMMX( void )
515 {
516     int reg, dummy;
517
518     /* test for a 386 cpu */
519     asm volatile ( "pushfl
520                     popl %%eax
521                     movl %%eax, %%ecx
522                     xorl $0x40000, %%eax
523                     pushl %%eax
524                     popfl
525                     pushfl
526                     popl %%eax
527                     xorl %%ecx, %%eax
528                     andl $0x40000, %%eax"
529                  : "=a" ( reg ) );
530     
531     if( !reg )
532         return( 0 );
533
534     /* test for a 486 cpu */
535     asm volatile ( "movl %%ecx, %%eax
536                     xorl $0x200000, %%eax
537                     pushl %%eax
538                     popfl
539                     pushfl
540                     popl %%eax
541                     xorl %%ecx, %%eax
542                     pushl %%ecx 
543                     popfl
544                     andl $0x200000, %%eax"
545                  : "=a" ( reg ) );
546     
547     if( !reg )
548         return( 0 );
549
550     /* the cpu supports the CPUID instruction - get its level */
551     asm volatile ( "cpuid"
552                  : "=a" ( reg ),
553                    "=b" ( dummy ),
554                    "=c" ( dummy ),
555                    "=d" ( dummy )
556                  : "a"  ( 0 ) ); /* level 0 */
557
558     /* this shouldn't happen on a normal cpu */
559     if( !reg )
560         return( 0 );
561
562     /* test for the MMX flag */
563     asm volatile ( "cpuid
564                     andl $0x00800000, %%edx" /* X86_FEATURE_MMX */
565                  : "=a" ( dummy ),
566                    "=b" ( dummy ),
567                    "=c" ( dummy ),
568                    "=d" ( reg )
569                  : "a"  ( 1 ) ); /* level 1 */
570
571     if( !reg )
572         return( 0 );
573
574     return( 1 );
575 }
576 #endif