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