main.c 35.4 KB
Newer Older
1
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
2 3 4
 * main.c: main vlc source
 * Includes the main() function for vlc. Parses command line, start interface
 * and spawn threads.
5 6 7 8 9 10 11 12 13
 *****************************************************************************
 * Copyright (C) 1998, 1999, 2000 VideoLAN
 *
 * Authors:
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
14
 * 
15 16
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 18
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
19
 *
20 21 22
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
23
 *****************************************************************************/
Michel Kaempf's avatar
Michel Kaempf committed
24

25
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
26
 * Preamble
27
 *****************************************************************************/
28 29
#include "defs.h"

30 31 32
#include <signal.h>                               /* SIGHUP, SIGINT, SIGKILL */
#include <stdio.h>                                              /* sprintf() */

Benoit Steiner's avatar
 
Benoit Steiner committed
33
#ifdef HAVE_GETOPT_H
34 35 36
#include <getopt.h>                                              /* getopt() */
#endif

Sam Hocevar's avatar
 
Sam Hocevar committed
37 38 39 40
#ifdef SYS_DARWIN1_3
#include <Carbon/Carbon.h>                              /* Altivec detection */
#endif

Sam Hocevar's avatar
 
Sam Hocevar committed
41
#include <unistd.h>
42 43 44
#include <errno.h>                                                 /* ENOMEM */
#include <stdlib.h>                                  /* getenv(), strtol(),  */
#include <string.h>                                            /* strerror() */
Vincent Seguin's avatar
Vincent Seguin committed
45

Michel Kaempf's avatar
Michel Kaempf committed
46 47
#include "config.h"
#include "common.h"
Christophe Massiot's avatar
Christophe Massiot committed
48
#include "debug.h"
49
#include "threads.h"
Michel Kaempf's avatar
Michel Kaempf committed
50
#include "mtime.h"
51
#include "tests.h"                                              /* TestCPU() */
Sam Hocevar's avatar
 
Sam Hocevar committed
52
#include "modules.h"
Sam Hocevar's avatar
 
Sam Hocevar committed
53

54 55
#include "stream_control.h"
#include "input_ext-intf.h"
56

Vincent Seguin's avatar
Vincent Seguin committed
57
#include "intf_msg.h"
Sam Hocevar's avatar
 
Sam Hocevar committed
58
#include "intf_playlist.h"
Michel Kaempf's avatar
Michel Kaempf committed
59
#include "interface.h"
60

Vincent Seguin's avatar
Vincent Seguin committed
61
#include "audio_output.h"
62

Sam Hocevar's avatar
 
Sam Hocevar committed
63 64 65
#include "video.h"
#include "video_output.h"

66 67 68 69
#ifdef SYS_BEOS
#include "beos_specific.h"
#endif

Vincent Seguin's avatar
Vincent Seguin committed
70
#include "main.h"
Michel Kaempf's avatar
Michel Kaempf committed
71

72
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
73 74
 * Command line options constants. If something is changed here, be sure that
 * GetConfiguration and Usage are also changed.
75
 *****************************************************************************/
Michel Kaempf's avatar
Michel Kaempf committed
76 77 78 79

/* Long options return values - note that values corresponding to short options
 * chars, and in general any regular char, should be avoided */
#define OPT_NOAUDIO             150
Sam Hocevar's avatar
 
Sam Hocevar committed
80 81
#define OPT_STEREO              151
#define OPT_MONO                152
Michel Kaempf's avatar
Michel Kaempf committed
82 83

#define OPT_NOVIDEO             160
Sam Hocevar's avatar
 
Sam Hocevar committed
84 85 86 87 88 89
#define OPT_DISPLAY             161
#define OPT_WIDTH               162
#define OPT_HEIGHT              163
#define OPT_COLOR               164
#define OPT_FULLSCREEN          165
#define OPT_OVERLAY             166
Michel Kaempf's avatar
Michel Kaempf committed
90

91
#define OPT_VLANS               170
92 93
#define OPT_SERVER              171
#define OPT_PORT                172
94
#define OPT_BROADCAST           173
95

Sam Hocevar's avatar
 
Sam Hocevar committed
96 97 98 99
#define OPT_INPUT               180
#define OPT_MOTION              181
#define OPT_IDCT                182
#define OPT_YUV                 183
100

Sam Hocevar's avatar
 
Sam Hocevar committed
101 102
#define OPT_SYNCHRO             190
#define OPT_WARNING             191
103

104
/* Usage fashion */
105 106 107
#define USAGE                     0
#define SHORT_HELP                1
#define LONG_HELP                 2
108

Michel Kaempf's avatar
Michel Kaempf committed
109
/* Long options */
Benoit Steiner's avatar
 
Benoit Steiner committed
110
#ifdef HAVE_GETOPT_H
Michel Kaempf's avatar
Michel Kaempf committed
111
static const struct option longopts[] =
112 113
{
    /*  name,               has_arg,    flag,   val */
Michel Kaempf's avatar
Michel Kaempf committed
114 115

    /* General/common options */
116
    {   "help",             0,          0,      'h' },
117
    {   "longhelp",         0,          0,      'H' },
118
    {   "version",          0,          0,      'v' },
Michel Kaempf's avatar
Michel Kaempf committed
119

Sam Hocevar's avatar
 
Sam Hocevar committed
120
    /* Interface options */
Sam Hocevar's avatar
 
Sam Hocevar committed
121
    {   "intf",             1,          0,      'I' },
Sam Hocevar's avatar
 
Sam Hocevar committed
122 123
    {   "warning",          1,          0,      OPT_WARNING },

Michel Kaempf's avatar
Michel Kaempf committed
124
    /* Audio options */
125
    {   "noaudio",          0,          0,      OPT_NOAUDIO },
Sam Hocevar's avatar
 
Sam Hocevar committed
126
    {   "aout",             1,          0,      'A' },
Michel Kaempf's avatar
Michel Kaempf committed
127
    {   "stereo",           0,          0,      OPT_STEREO },
128
    {   "mono",             0,          0,      OPT_MONO },
Michel Kaempf's avatar
Michel Kaempf committed
129 130

    /* Video options */
131
    {   "novideo",          0,          0,      OPT_NOVIDEO },
Sam Hocevar's avatar
 
Sam Hocevar committed
132
    {   "vout",             1,          0,      'V' },
133
    {   "display",          1,          0,      OPT_DISPLAY },
134
    {   "width",            1,          0,      OPT_WIDTH },
135 136 137
    {   "height",           1,          0,      OPT_HEIGHT },
    {   "grayscale",        0,          0,      'g' },
    {   "color",            0,          0,      OPT_COLOR },
Sam Hocevar's avatar
 
Sam Hocevar committed
138
    {   "motion",           1,          0,      OPT_MOTION },
Sam Hocevar's avatar
 
Sam Hocevar committed
139
    {   "idct",             1,          0,      OPT_IDCT },
140
    {   "yuv",              1,          0,      OPT_YUV },
Sam Hocevar's avatar
 
Sam Hocevar committed
141 142
    {   "fullscreen",       0,          0,      OPT_FULLSCREEN },
    {   "overlay",          0,          0,      OPT_OVERLAY },
Michel Kaempf's avatar
Michel Kaempf committed
143

144
    /* DVD options */
145 146
    {   "dvdtitle",         1,          0,      't' },
    {   "dvdchapter",       1,          0,      'T' },
147 148 149 150
    {   "dvdaudio",         1,          0,      'a' },
    {   "dvdchannel",       1,          0,      'c' },
    {   "dvdsubtitle",      1,          0,      's' },
    
151
    /* Input options */
Sam Hocevar's avatar
 
Sam Hocevar committed
152
    {   "input",            1,          0,      OPT_INPUT },
153
    {   "vlans",            0,          0,      OPT_VLANS },
154 155
    {   "server",           1,          0,      OPT_SERVER },
    {   "port",             1,          0,      OPT_PORT },
156
    {   "broadcast",        0,          0,      OPT_BROADCAST },
Michel Kaempf's avatar
Michel Kaempf committed
157

158 159
    /* Synchro options */
    {   "synchro",          1,          0,      OPT_SYNCHRO },
Michel Kaempf's avatar
Michel Kaempf committed
160 161 162 163
    {   0,                  0,          0,      0 }
};

/* Short options */
Sam Hocevar's avatar
 
Sam Hocevar committed
164
static const char *psz_shortopts = "hHvgt:T:a:s:c:I:A:V:";
165 166
#endif

Michel Kaempf's avatar
Michel Kaempf committed
167

168
/*****************************************************************************
Vincent Seguin's avatar
Vincent Seguin committed
169
 * Global variable program_data - this is the one and only, see main.h
170
 *****************************************************************************/
Vincent Seguin's avatar
Vincent Seguin committed
171
main_t *p_main;
Michel Kaempf's avatar
Michel Kaempf committed
172

173
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
174
 * Local prototypes
175
 *****************************************************************************/
Vincent Seguin's avatar
Vincent Seguin committed
176
static void SetDefaultConfiguration ( void );
177 178
static int  GetConfiguration        ( int i_argc, char *ppsz_argv[],
                                      char *ppsz_env[] );
Sam Hocevar's avatar
 
Sam Hocevar committed
179
static int  GetFilenames            ( int i_argc, char *ppsz_argv[] );
180
static void Usage                   ( int i_fashion );
Vincent Seguin's avatar
Vincent Seguin committed
181
static void Version                 ( void );
Vincent Seguin's avatar
Vincent Seguin committed
182

Michel Kaempf's avatar
Michel Kaempf committed
183
static void InitSignalHandler       ( void );
Benoit Steiner's avatar
 
Benoit Steiner committed
184 185
static void SimpleSignalHandler     ( int i_signal );
static void FatalSignalHandler      ( int i_signal );
Michel Kaempf's avatar
Michel Kaempf committed
186

Sam Hocevar's avatar
 
Sam Hocevar committed
187 188
static int  CPUCapabilities         ( void );

189
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
190
 * main: parse command line, start interface and spawn threads
191
 *****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
192 193
 * Steps during program execution are:
 *      -configuration parsing and messages interface initialization
194
 *      -opening of audio output device and some global modules
Michel Kaempf's avatar
Michel Kaempf committed
195
 *      -execution of interface, which exit on error or on user request
Vincent Seguin's avatar
Vincent Seguin committed
196
 *      -closing of audio output device and some global modules
197
 * On error, the spawned threads are canceled, and the open devices closed.
198
 *****************************************************************************/
Michel Kaempf's avatar
Michel Kaempf committed
199 200
int main( int i_argc, char *ppsz_argv[], char *ppsz_env[] )
{
201
    main_t  main_data;                      /* root of all data - see main.h */
202

203
    p_main = &main_data;                       /* set up the global variable */
Vincent Seguin's avatar
Vincent Seguin committed
204

205 206 207
    /*
     * System specific initialization code
     */
208
#ifdef SYS_BEOS
209
    beos_Create();
210 211
#endif

212
    p_main->i_cpu_capabilities = CPUCapabilities();
Sam Hocevar's avatar
 
Sam Hocevar committed
213
    
Michel Kaempf's avatar
Michel Kaempf committed
214
    /*
215
     * Test if our code is likely to run on this CPU 
216
     */
217 218 219
#if defined( __pentium__ ) || defined( __pentiumpro__ )
    if( ! TestCPU( CPU_CAPABILITY_586 ) )
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
220 221
        fprintf( stderr, "error: this program needs a Pentium CPU,\n"
                         "please try a version without Pentium support\n" );
222 223 224 225
        return( 1 );
    }
#endif

226
#ifdef HAVE_MMX
227
    if( ! TestCPU( CPU_CAPABILITY_MMX ) )
228
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
229 230
        fprintf( stderr, "error: this program needs MMX extensions,\n"
                         "please try a version without MMX support\n" );
231
        return( 1 );
232 233
    }
#endif
234 235 236 237

    /*
     * Initialize messages interface
     */
Vincent Seguin's avatar
Vincent Seguin committed
238
    p_main->p_msg = intf_MsgCreate();
239
    if( !p_main->p_msg )                         /* start messages interface */
Michel Kaempf's avatar
Michel Kaempf committed
240
    {
241
        fprintf( stderr, "error: can't initialize messages interface (%s)\n",
Sam Hocevar's avatar
 
Sam Hocevar committed
242
                 strerror(errno) );
243
        return( errno );
Michel Kaempf's avatar
Michel Kaempf committed
244
    }
245

Sam Hocevar's avatar
 
Sam Hocevar committed
246 247
    intf_MsgImm( COPYRIGHT_MESSAGE );

248
    /*
Sam Hocevar's avatar
 
Sam Hocevar committed
249
     * Read configuration
250
     */
Sam Hocevar's avatar
 
Sam Hocevar committed
251
    if( GetConfiguration( i_argc, ppsz_argv, ppsz_env ) )  /* parse cmd line */
Michel Kaempf's avatar
Michel Kaempf committed
252
    {
Vincent Seguin's avatar
Vincent Seguin committed
253
        intf_MsgDestroy();
254
        return( errno );
Michel Kaempf's avatar
Michel Kaempf committed
255
    }
Sam Hocevar's avatar
 
Sam Hocevar committed
256 257 258

    p_main->i_warning_level = main_GetIntVariable( INTF_WARNING_VAR,
                                                   INTF_WARNING_DEFAULT );
259

260
    /*
Sam Hocevar's avatar
 
Sam Hocevar committed
261
     * Initialize playlist and get commandline files
262
     */
Sam Hocevar's avatar
 
Sam Hocevar committed
263
    p_main->p_playlist = intf_PlaylistCreate( );
Sam Hocevar's avatar
 
Sam Hocevar committed
264
    if( !p_main->p_playlist )
265
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
266
        intf_ErrMsg( "playlist error: playlist initialization failed" );
267 268
        intf_MsgDestroy();
        return( errno );
269
    }
Sam Hocevar's avatar
 
Sam Hocevar committed
270
    intf_PlaylistInit( p_main->p_playlist );
271 272

    /*
Sam Hocevar's avatar
 
Sam Hocevar committed
273
     * Get input filenames given as commandline arguments
274
     */
Sam Hocevar's avatar
 
Sam Hocevar committed
275
    GetFilenames( i_argc, ppsz_argv );
Michel Kaempf's avatar
Michel Kaempf committed
276

Sam Hocevar's avatar
 
Sam Hocevar committed
277 278 279
    /*
     * Initialize module bank
     */
Sam Hocevar's avatar
 
Sam Hocevar committed
280 281
    p_main->p_bank = module_CreateBank( );
    if( !p_main->p_bank )
Sam Hocevar's avatar
 
Sam Hocevar committed
282
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
283
        intf_ErrMsg( "module error: module bank initialization failed" );
Sam Hocevar's avatar
 
Sam Hocevar committed
284
        intf_PlaylistDestroy( p_main->p_playlist );
Sam Hocevar's avatar
 
Sam Hocevar committed
285 286 287
        intf_MsgDestroy();
        return( errno );
    }
Sam Hocevar's avatar
 
Sam Hocevar committed
288
    module_InitBank( p_main->p_bank );
Sam Hocevar's avatar
 
Sam Hocevar committed
289

Michel Kaempf's avatar
Michel Kaempf committed
290 291 292
    /*
     * Initialize shared resources and libraries
     */
293 294
    /* FIXME: no VLANs */
#if 0
295
    if( p_main->b_vlans && input_VlanCreate() )
Michel Kaempf's avatar
Michel Kaempf committed
296
    {
297 298
        /* On error during vlans initialization, switch off vlans */
        intf_Msg( "Virtual LANs initialization failed : "
Sam Hocevar's avatar
 
Sam Hocevar committed
299
                  "vlans management is deactivated" );
300
        p_main->b_vlans = 0;
Michel Kaempf's avatar
Michel Kaempf committed
301
    }
302
#endif
303

Michel Kaempf's avatar
Michel Kaempf committed
304 305 306
    /*
     * Run interface
     */
307
    p_main->p_intf = intf_Create();
Sam Hocevar's avatar
 
Sam Hocevar committed
308 309 310 311
    if( !p_main->p_intf )
    {
        intf_ErrMsg( "intf error: interface initialization failed" );
        module_DestroyBank( p_main->p_bank );
Sam Hocevar's avatar
 
Sam Hocevar committed
312
        intf_PlaylistDestroy( p_main->p_playlist );
Sam Hocevar's avatar
 
Sam Hocevar committed
313 314 315
        intf_MsgDestroy();
        return( errno );
    }
316

Sam Hocevar's avatar
 
Sam Hocevar committed
317 318 319 320 321 322 323 324 325
    /*
     * Set signal handling policy for all threads
     */
    InitSignalHandler();

    /*
     * Open audio device and start aout thread
     */
    if( p_main->b_audio )
Vincent Seguin's avatar
Vincent Seguin committed
326
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
327 328
        p_main->p_aout = aout_CreateThread( NULL );
        if( p_main->p_aout == NULL )
329
        {
Sam Hocevar's avatar
 
Sam Hocevar committed
330 331 332 333
            /* On error during audio initialization, switch off audio */
            intf_ErrMsg( "aout error: audio initialization failed,"
                         " audio is deactivated" );
            p_main->b_audio = 0;
334
        }
Sam Hocevar's avatar
 
Sam Hocevar committed
335
    }
336

Sam Hocevar's avatar
 
Sam Hocevar committed
337
    /*
Sam Hocevar's avatar
 
Sam Hocevar committed
338
     * Open video device and start vout thread
Sam Hocevar's avatar
 
Sam Hocevar committed
339 340 341 342 343
     */
    if( p_main->b_video )
    {
        p_main->p_vout = vout_CreateThread( NULL );
        if( p_main->p_vout == NULL )
344
        {
Sam Hocevar's avatar
 
Sam Hocevar committed
345
            /* On error during video initialization, switch off video */
Sam Hocevar's avatar
 
Sam Hocevar committed
346 347 348
            intf_ErrMsg( "vout error: video initialization failed,"
                         " video is deactivated" );
            p_main->b_video = 0;
349
        }
Michel Kaempf's avatar
Michel Kaempf committed
350
    }
Michel Kaempf's avatar
Michel Kaempf committed
351

Sam Hocevar's avatar
 
Sam Hocevar committed
352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377
    /* Flush messages before entering the main loop */
    intf_FlushMsg();

    /*
     * This is the main loop
     */
    p_main->p_intf->pf_run( p_main->p_intf );

    intf_Destroy( p_main->p_intf );

    /*
     * Close video device
     */
    if( p_main->b_video )
    {
        vout_DestroyThread( p_main->p_vout, NULL );
    }

    /*
     * Close audio device
     */
    if( p_main->b_audio )
    {
        aout_DestroyThread( p_main->p_aout, NULL );
    }

Michel Kaempf's avatar
Michel Kaempf committed
378 379 380
    /*
     * Free shared resources and libraries
     */
381 382
    /* FIXME */
#if 0
383
    if( p_main->b_vlans )
384 385 386
    {
        input_VlanDestroy();
    }
387
#endif
Michel Kaempf's avatar
Michel Kaempf committed
388

Sam Hocevar's avatar
 
Sam Hocevar committed
389 390 391
    /*
     * Free module bank
     */
Sam Hocevar's avatar
 
Sam Hocevar committed
392
    module_DestroyBank( p_main->p_bank );
393 394 395 396

    /*
     * Free playlist
     */
Sam Hocevar's avatar
 
Sam Hocevar committed
397
    intf_PlaylistDestroy( p_main->p_playlist );
398

399
#ifdef SYS_BEOS
400 401 402 403
    /*
     * System specific cleaning code
     */
    beos_Destroy();
404 405
#endif

Michel Kaempf's avatar
Michel Kaempf committed
406 407 408
    /*
     * Terminate messages interface and program
     */
Sam Hocevar's avatar
 
Sam Hocevar committed
409
    intf_Msg( "intf: program terminated" );
Vincent Seguin's avatar
Vincent Seguin committed
410
    intf_MsgDestroy();
411

Michel Kaempf's avatar
Michel Kaempf committed
412 413 414
    return( 0 );
}

415
/*****************************************************************************
Vincent Seguin's avatar
Vincent Seguin committed
416
 * main_GetIntVariable: get the int value of an environment variable
417
 *****************************************************************************
Vincent Seguin's avatar
Vincent Seguin committed
418
 * This function is used to read some default parameters in modules.
419
 *****************************************************************************/
Vincent Seguin's avatar
Vincent Seguin committed
420 421
int main_GetIntVariable( char *psz_name, int i_default )
{
422 423 424
    char *      psz_env;                                /* environment value */
    char *      psz_end;                             /* end of parsing index */
    long int    i_value;                                            /* value */
Vincent Seguin's avatar
Vincent Seguin committed
425 426 427

    psz_env = getenv( psz_name );
    if( psz_env )
428
    {
429 430 431 432
        i_value = strtol( psz_env, &psz_end, 0 );
        if( (*psz_env != '\0') && (*psz_end == '\0') )
        {
            return( i_value );
433
        }
434
    }
Vincent Seguin's avatar
Vincent Seguin committed
435 436 437
    return( i_default );
}

438
/*****************************************************************************
Vincent Seguin's avatar
Vincent Seguin committed
439
 * main_GetPszVariable: get the string value of an environment variable
440
 *****************************************************************************
Vincent Seguin's avatar
Vincent Seguin committed
441
 * This function is used to read some default parameters in modules.
442
 *****************************************************************************/
Vincent Seguin's avatar
Vincent Seguin committed
443 444 445 446 447 448 449
char * main_GetPszVariable( char *psz_name, char *psz_default )
{
    char *psz_env;

    psz_env = getenv( psz_name );
    if( psz_env )
    {
450
        return( psz_env );
Vincent Seguin's avatar
Vincent Seguin committed
451
    }
452
    return( psz_default );
Vincent Seguin's avatar
Vincent Seguin committed
453 454
}

455
/*****************************************************************************
456
 * main_PutPszVariable: set the string value of an environment variable
457
 *****************************************************************************
458 459 460
 * This function is used to set some default parameters in modules. The use of
 * this function will cause some memory leak: since some systems use the pointer
 * passed to putenv to store the environment string, it can't be freed.
461
 *****************************************************************************/
462 463 464 465 466 467 468
void main_PutPszVariable( char *psz_name, char *psz_value )
{
    char *psz_env;

    psz_env = malloc( strlen(psz_name) + strlen(psz_value) + 2 );
    if( psz_env == NULL )
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
469 470
        intf_ErrMsg( "intf error: cannot create psz_env (%s)",
                     strerror(ENOMEM) );
471 472 473 474 475 476
    }
    else
    {
        sprintf( psz_env, "%s=%s", psz_name, psz_value );
        if( putenv( psz_env ) )
        {
Sam Hocevar's avatar
 
Sam Hocevar committed
477
            intf_ErrMsg( "intf error: cannot putenv (%s)", strerror(errno) );
478
        }
479 480 481
    }
}

482
/*****************************************************************************
483
 * main_PutIntVariable: set the integer value of an environment variable
484
 *****************************************************************************
485 486 487
 * This function is used to set some default parameters in modules. The use of
 * this function will cause some memory leak: since some systems use the pointer
 * passed to putenv to store the environment string, it can't be freed.
488
 *****************************************************************************/
489 490
void main_PutIntVariable( char *psz_name, int i_value )
{
491
    char psz_value[ 256 ];                               /* buffer for value */
492

493
    sprintf( psz_value, "%d", i_value );
494
    main_PutPszVariable( psz_name, psz_value );
495 496
}

Michel Kaempf's avatar
Michel Kaempf committed
497 498
/* following functions are local */

499
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
500
 * SetDefaultConfiguration: set default options
501
 *****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
502
 * This function is called by GetConfiguration before command line is parsed.
Vincent Seguin's avatar
Vincent Seguin committed
503 504 505
 * It sets all the default values required later by the program. At this stage,
 * most structure are not yet allocated, so initialization must be done using
 * environment.
506
 *****************************************************************************/
Vincent Seguin's avatar
Vincent Seguin committed
507
static void SetDefaultConfiguration( void )
Michel Kaempf's avatar
Michel Kaempf committed
508 509
{
    /*
510
     * All features are activated by default except vlans
Michel Kaempf's avatar
Michel Kaempf committed
511
     */
Vincent Seguin's avatar
Vincent Seguin committed
512 513
    p_main->b_audio  = 1;
    p_main->b_video  = 1;
514
    p_main->b_vlans  = 0;
Michel Kaempf's avatar
Michel Kaempf committed
515 516
}

517
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
518
 * GetConfiguration: parse command line
519
 *****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
520 521
 * Parse command line and configuration file for configuration. If the inline
 * help is requested, the function Usage() is called and the function returns
522
 * -1 (causing main() to exit). The messages interface is initialized at this
Vincent Seguin's avatar
Vincent Seguin committed
523 524
 * stage, but most structures are not allocated, so only environment should
 * be used.
525
 *****************************************************************************/
Vincent Seguin's avatar
Vincent Seguin committed
526
static int GetConfiguration( int i_argc, char *ppsz_argv[], char *ppsz_env[] )
Michel Kaempf's avatar
Michel Kaempf committed
527
{
Sam Hocevar's avatar
 
Sam Hocevar committed
528
    int c;
529
    char * p_pointer;
Michel Kaempf's avatar
Michel Kaempf committed
530 531

    /* Set default configuration and copy arguments */
Vincent Seguin's avatar
Vincent Seguin committed
532 533
    p_main->i_argc    = i_argc;
    p_main->ppsz_argv = ppsz_argv;
534
    p_main->ppsz_env  = ppsz_env;
Vincent Seguin's avatar
Vincent Seguin committed
535
    SetDefaultConfiguration();
Michel Kaempf's avatar
Michel Kaempf committed
536

537
    /* Get the executable name (similar to the basename command) */
538 539 540 541 542 543 544 545 546 547 548 549 550
    p_main->psz_arg0 = p_pointer = ppsz_argv[ 0 ];
    while( *p_pointer )
    {
        if( *p_pointer == '/' )
        {
            p_main->psz_arg0 = ++p_pointer;
        }
        else
        {
            ++p_pointer;
        }
    }

Vincent Seguin's avatar
Vincent Seguin committed
551
    /* Parse command line options */
Benoit Steiner's avatar
 
Benoit Steiner committed
552
#ifdef HAVE_GETOPT_H
Michel Kaempf's avatar
Michel Kaempf committed
553 554 555 556 557
    opterr = 0;
    while( ( c = getopt_long( i_argc, ppsz_argv, psz_shortopts, longopts, 0 ) ) != EOF )
    {
        switch( c )
        {
558 559
        /* General/common options */
        case 'h':                                              /* -h, --help */
560 561 562
            Usage( SHORT_HELP );
            return( -1 );
            break;
563
        case 'H':                                          /* -H, --longhelp */
564
            Usage( LONG_HELP );
Michel Kaempf's avatar
Michel Kaempf committed
565 566
            return( -1 );
            break;
567
        case 'v':                                           /* -v, --version */
Vincent Seguin's avatar
Vincent Seguin committed
568 569
            Version();
            return( -1 );
570
            break;
Michel Kaempf's avatar
Michel Kaempf committed
571

Sam Hocevar's avatar
 
Sam Hocevar committed
572
        /* Interface warning messages level */
Sam Hocevar's avatar
 
Sam Hocevar committed
573
	case 'I':                                              /* -I, --intf */
Sam Hocevar's avatar
 
Sam Hocevar committed
574 575 576 577 578 579
            main_PutPszVariable( INTF_METHOD_VAR, optarg );
            break;
        case OPT_WARNING:                                       /* --warning */
            main_PutIntVariable( INTF_WARNING_VAR, atoi(optarg) );
            break;

Michel Kaempf's avatar
Michel Kaempf committed
580
        /* Audio options */
581
        case OPT_NOAUDIO:                                       /* --noaudio */
582
            p_main->b_audio = 0;
Michel Kaempf's avatar
Michel Kaempf committed
583
            break;
Sam Hocevar's avatar
 
Sam Hocevar committed
584
        case 'A':                                              /* -A, --aout */
585 586
            main_PutPszVariable( AOUT_METHOD_VAR, optarg );
            break;
587
        case OPT_STEREO:                                         /* --stereo */
588
            main_PutIntVariable( AOUT_STEREO_VAR, 1 );
Michel Kaempf's avatar
Michel Kaempf committed
589
            break;
590
        case OPT_MONO:                                             /* --mono */
591
            main_PutIntVariable( AOUT_STEREO_VAR, 0 );
Michel Kaempf's avatar
Michel Kaempf committed
592 593 594
            break;

        /* Video options */
595
        case OPT_NOVIDEO:                                       /* --novideo */
Vincent Seguin's avatar
Vincent Seguin committed
596
            p_main->b_video = 0;
597
            break;
Sam Hocevar's avatar
 
Sam Hocevar committed
598
        case 'V':                                              /* -V, --vout */
599 600
            main_PutPszVariable( VOUT_METHOD_VAR, optarg );
            break;
601
        case OPT_DISPLAY:                                       /* --display */
602
            main_PutPszVariable( VOUT_DISPLAY_VAR, optarg );
603 604
            break;
        case OPT_WIDTH:                                           /* --width */
605
            main_PutPszVariable( VOUT_WIDTH_VAR, optarg );
606 607 608 609 610
            break;
        case OPT_HEIGHT:                                         /* --height */
            main_PutPszVariable( VOUT_HEIGHT_VAR, optarg );
            break;
        case 'g':                                         /* -g, --grayscale */
611
            main_PutIntVariable( VOUT_GRAYSCALE_VAR, 1 );
612 613
            break;
        case OPT_COLOR:                                           /* --color */
614
            main_PutIntVariable( VOUT_GRAYSCALE_VAR, 0 );
615
            break;
Sam Hocevar's avatar
 
Sam Hocevar committed
616
        case OPT_FULLSCREEN:                                 /* --fullscreen */
Sam Hocevar's avatar
 
Sam Hocevar committed
617 618
            main_PutIntVariable( VOUT_FULLSCREEN_VAR, 1 );
            break;
Sam Hocevar's avatar
 
Sam Hocevar committed
619
        case OPT_OVERLAY:                                       /* --overlay */
Sam Hocevar's avatar
 
Sam Hocevar committed
620 621
            main_PutIntVariable( VOUT_OVERLAY_VAR, 1 );
            break;
Sam Hocevar's avatar
 
Sam Hocevar committed
622
        case OPT_MOTION:                                         /* --motion */
Sam Hocevar's avatar
 
Sam Hocevar committed
623 624
            main_PutPszVariable( MOTION_METHOD_VAR, optarg );
            break;
Sam Hocevar's avatar
 
Sam Hocevar committed
625
        case OPT_IDCT:                                             /* --idct */
Sam Hocevar's avatar
 
Sam Hocevar committed
626 627
            main_PutPszVariable( IDCT_METHOD_VAR, optarg );
            break;
628 629 630
        case OPT_YUV:                                               /* --yuv */
            main_PutPszVariable( YUV_METHOD_VAR, optarg );
            break;
Michel Kaempf's avatar
Michel Kaempf committed
631

632
        /* DVD options */
633 634 635 636 637 638
        case 't':
            main_PutIntVariable( INPUT_TITLE_VAR, atoi(optarg) );
            break;
        case 'T':
            main_PutIntVariable( INPUT_CHAPTER_VAR, atoi(optarg) );
            break;
639
        case 'a':
640
            if ( ! strcmp(optarg, "ac3") )
Sam Hocevar's avatar
 
Sam Hocevar committed
641
                main_PutIntVariable( INPUT_AUDIO_VAR, REQUESTED_AC3 );
642
            else if ( ! strcmp(optarg, "lpcm") )
Sam Hocevar's avatar
 
Sam Hocevar committed
643
                main_PutIntVariable( INPUT_AUDIO_VAR, REQUESTED_LPCM );
644
            else if ( ! strcmp(optarg, "mpeg") )
Sam Hocevar's avatar
 
Sam Hocevar committed
645
                main_PutIntVariable( INPUT_AUDIO_VAR, REQUESTED_MPEG );
646
            else
Sam Hocevar's avatar
 
Sam Hocevar committed
647
                main_PutIntVariable( INPUT_AUDIO_VAR, REQUESTED_NOAUDIO );
648 649
            break;
        case 'c':
Sam Hocevar's avatar
 
Sam Hocevar committed
650
            main_PutIntVariable( INPUT_CHANNEL_VAR, atoi(optarg) );
651 652
            break;
        case 's':
Sam Hocevar's avatar
 
Sam Hocevar committed
653
            main_PutIntVariable( INPUT_SUBTITLE_VAR, atoi(optarg) );
654 655
            break;

656
        /* Input options */
Sam Hocevar's avatar
 
Sam Hocevar committed
657
        case OPT_INPUT:                                           /* --input */
Sam Hocevar's avatar
 
Sam Hocevar committed
658 659
            main_PutPszVariable( INPUT_METHOD_VAR, optarg );
            break;
660
        case OPT_VLANS:                                           /* --vlans */
661
            p_main->b_vlans = 1;
662 663
            break;
        case OPT_SERVER:                                         /* --server */
664
            main_PutPszVariable( INPUT_SERVER_VAR, optarg );
665 666
            break;
        case OPT_PORT:                                             /* --port */
667
            main_PutPszVariable( INPUT_PORT_VAR, optarg );
668
            break;
669 670 671
        case OPT_BROADCAST:                                   /* --broadcast */
            main_PutIntVariable( INPUT_BROADCAST_VAR, 1 );
            break;
672

673
        /* Synchro options */
674
        case OPT_SYNCHRO:                                      
675 676
            main_PutPszVariable( VPAR_SYNCHRO_VAR, optarg );
            break;
677
            
Michel Kaempf's avatar
Michel Kaempf committed
678
        /* Internal error: unknown option */
679
        case '?':
Michel Kaempf's avatar
Michel Kaempf committed
680
        default:
Sam Hocevar's avatar
 
Sam Hocevar committed
681
            intf_ErrMsg( "intf error: unknown option `%s'", ppsz_argv[optind - 1] );
682
            Usage( USAGE );
Michel Kaempf's avatar
Michel Kaempf committed
683 684 685 686
            return( EINVAL );
            break;
        }
    }
687
#endif
Sam Hocevar's avatar
 
Sam Hocevar committed
688 689 690 691 692 693 694 695 696 697 698
    return( 0 );
}

/*****************************************************************************
 * GetFilenames: parse command line options which are not flags
 *****************************************************************************
 * Parse command line for input files.
 *****************************************************************************/
static int GetFilenames( int i_argc, char *ppsz_argv[] )
{
    int i_opt;
Michel Kaempf's avatar
Michel Kaempf committed
699

Sam Hocevar's avatar
 
Sam Hocevar committed
700
    /* We assume that the remaining parameters are filenames */
Vincent Seguin's avatar
Vincent Seguin committed
701 702
    for( i_opt = optind; i_opt < i_argc; i_opt++ )
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
703 704
        intf_PlaylistAdd( p_main->p_playlist, PLAYLIST_END,
                          ppsz_argv[ i_opt ] );
Vincent Seguin's avatar
Vincent Seguin committed
705
    }
Sam Hocevar's avatar
 
Sam Hocevar committed
706

Michel Kaempf's avatar
Michel Kaempf committed
707 708 709
    return( 0 );
}

710
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
711
 * Usage: print program usage
712
 *****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
713
 * Print a short inline help. Message interface is initialized at this stage.
714
 *****************************************************************************/
715
static void Usage( int i_fashion )
Michel Kaempf's avatar
Michel Kaempf committed
716
{
Vincent Seguin's avatar
Vincent Seguin committed
717
    /* Usage */
Sam Hocevar's avatar
 
Sam Hocevar committed
718 719
    intf_MsgImm( "Usage: %s [options] [parameters] [file]...",
                 p_main->psz_arg0 );
720 721 722

    if( i_fashion == USAGE )
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
723 724
        intf_MsgImm( "Try `%s --help' for more information.",
                     p_main->psz_arg0 );
725 726 727
        return;
    }

Vincent Seguin's avatar
Vincent Seguin committed
728
    /* Options */
Sam Hocevar's avatar
 
Sam Hocevar committed
729
    intf_MsgImm( "\nOptions:"
Sam Hocevar's avatar
 
Sam Hocevar committed
730
          "\n  -I, --intf <module>            \tinterface method"
Sam Hocevar's avatar
 
Sam Hocevar committed
731 732
          "\n      --warning <level>          \tdisplay warning messages"
          "\n"
Sam Hocevar's avatar
 
Sam Hocevar committed
733
          "\n      --noaudio                  \tdisable audio"
Sam Hocevar's avatar
 
Sam Hocevar committed
734
          "\n  -A, --aout <module>            \taudio output method"
Sam Hocevar's avatar
 
Sam Hocevar committed
735 736 737
          "\n      --stereo, --mono           \tstereo/mono audio"
          "\n"
          "\n      --novideo                  \tdisable video"
Sam Hocevar's avatar
 
Sam Hocevar committed
738
          "\n  -V, --vout <module>            \tvideo output method"
Sam Hocevar's avatar
 
Sam Hocevar committed
739 740 741 742 743 744 745 746 747 748 749
          "\n      --display <display>        \tdisplay string"
          "\n      --width <w>, --height <h>  \tdisplay dimensions"
          "\n  -g, --grayscale                \tgrayscale output"
          "\n      --fullscreen               \tfullscreen output"
          "\n      --overlay                  \taccelerated display"
          "\n      --color                    \tcolor output"
          "\n      --motion <module>          \tmotion compensation method"
          "\n      --idct <module>            \tIDCT method"
          "\n      --yuv <module>             \tYUV method"
          "\n      --synchro <type>           \tforce synchro algorithm"
          "\n"
750 751
          "\n  -t, --dvdtitle <num>           \tchoose DVD title"
          "\n  -T, --dvdchapter <num>         \tchoose DVD chapter"
Sam Hocevar's avatar
 
Sam Hocevar committed
752 753 754 755 756 757 758 759 760 761 762 763 764
          "\n  -a, --dvdaudio <type>          \tchoose DVD audio type"
          "\n  -c, --dvdchannel <channel>     \tchoose DVD audio channel"
          "\n  -s, --dvdsubtitle <channel>    \tchoose DVD subtitle channel"
          "\n"
          "\n      --input                    \tinput method"
          "\n      --vlans                    \tenable vlans"
          "\n      --server <host>            \tvideo server address"
          "\n      --port <port>              \tvideo server port"
          "\n      --broadcast                \tlisten to a broadcast"
          "\n"
          "\n  -h, --help                     \tprint help and exit"
          "\n  -H, --longhelp                 \tprint long help and exit"
          "\n  -v, --version                  \toutput version information and exit" );
Michel Kaempf's avatar
Michel Kaempf committed
765

766 767 768
    if( i_fashion == SHORT_HELP )
        return;

Vincent Seguin's avatar
Vincent Seguin committed
769
    /* Interface parameters */
Sam Hocevar's avatar
 
Sam Hocevar committed
770
    intf_MsgImm( "\nInterface parameters:"
Sam Hocevar's avatar
 
Sam Hocevar committed
771
        "\n  " INTF_METHOD_VAR "=<method name>          \tinterface method"
Sam Hocevar's avatar
 
Sam Hocevar committed
772
        "\n  " INTF_INIT_SCRIPT_VAR "=<filename>               \tinitialization script"
Sam Hocevar's avatar
 
Sam Hocevar committed
773 774
        "\n  " INTF_CHANNELS_VAR "=<filename>            \tchannels list"
        "\n  " INTF_WARNING_VAR "=<level>                \twarning level" );
Vincent Seguin's avatar
Vincent Seguin committed
775 776

    /* Audio parameters */
Sam Hocevar's avatar
 
Sam Hocevar committed
777 778 779 780 781
    intf_MsgImm( "\nAudio parameters:"
        "\n  " AOUT_METHOD_VAR "=<method name>        \taudio method"
        "\n  " AOUT_DSP_VAR "=<filename>              \tdsp device path"
        "\n  " AOUT_STEREO_VAR "={1|0}                \tstereo or mono output"
        "\n  " AOUT_RATE_VAR "=<rate>             \toutput rate" );
Vincent Seguin's avatar
Vincent Seguin committed
782 783

    /* Video parameters */
Sam Hocevar's avatar
 
Sam Hocevar committed
784 785 786 787 788 789 790 791 792 793 794 795 796
    intf_MsgImm( "\nVideo parameters:"
        "\n  " VOUT_METHOD_VAR "=<method name>        \tdisplay method"
        "\n  " VOUT_DISPLAY_VAR "=<display name>      \tdisplay used"
        "\n  " VOUT_WIDTH_VAR "=<width>               \tdisplay width"
        "\n  " VOUT_HEIGHT_VAR "=<height>             \tdislay height"
        "\n  " VOUT_FB_DEV_VAR "=<filename>           \tframebuffer device path"
        "\n  " VOUT_GRAYSCALE_VAR "={1|0}             \tgrayscale or color output"
        "\n  " VOUT_FULLSCREEN_VAR "={1|0}            \tfullscreen"
        "\n  " VOUT_OVERLAY_VAR "={1|0}               \toverlay"
        "\n  " MOTION_METHOD_VAR "=<method name>      \tmotion compensation method"
        "\n  " IDCT_METHOD_VAR "=<method name>        \tIDCT method"
        "\n  " YUV_METHOD_VAR "=<method name>         \tYUV method"
        "\n  " VPAR_SYNCHRO_VAR "={I|I+|IP|IP+|IPB}   \tsynchro algorithm" );
Vincent Seguin's avatar
Vincent Seguin committed
797

798
    /* DVD parameters */
Sam Hocevar's avatar
 
Sam Hocevar committed
799 800
    intf_MsgImm( "\nDVD parameters:"
        "\n  " INPUT_DVD_DEVICE_VAR "=<device>           \tDVD device"
Sam Hocevar's avatar
 
Sam Hocevar committed
801 802 803 804 805
        "\n  " INPUT_TITLE_VAR "=<title>             \ttitle number"
        "\n  " INPUT_CHAPTER_VAR "=<chapter>         \tchapter number"
        "\n  " INPUT_AUDIO_VAR "={ac3|lpcm|mpeg|off} \taudio type"
        "\n  " INPUT_CHANNEL_VAR "=[0-15]            \taudio channel"
        "\n  " INPUT_SUBTITLE_VAR "=[0-31]           \tsubtitle channel" );
806

807
    /* Input parameters */
Sam Hocevar's avatar
 
Sam Hocevar committed
808
    intf_MsgImm( "\nInput parameters:"
Sam Hocevar's avatar
 
Sam Hocevar committed
809 810 811 812 813 814
        "\n  " INPUT_SERVER_VAR "=<hostname>          \tvideo server"
        "\n  " INPUT_PORT_VAR "=<port>            \tvideo server port"
        "\n  " INPUT_IFACE_VAR "=<interface>          \tnetwork interface"
        "\n  " INPUT_BROADCAST_VAR "={1|0}            \tbroadcast mode"
        "\n  " INPUT_VLAN_SERVER_VAR "=<hostname>     \tvlan server"
        "\n  " INPUT_VLAN_PORT_VAR "=<port>           \tvlan server port" );
815

Michel Kaempf's avatar
Michel Kaempf committed
816 817
}

818
/*****************************************************************************
Vincent Seguin's avatar
Vincent Seguin committed
819
 * Version: print complete program version
820
 *****************************************************************************
Vincent Seguin's avatar
Vincent Seguin committed
821
 * Print complete program version and build number.
822
 *****************************************************************************/
Vincent Seguin's avatar
Vincent Seguin committed
823 824
static void Version( void )
{
Sam Hocevar's avatar
 
Sam Hocevar committed
825 826 827 828 829
    intf_MsgImm( VERSION_MESSAGE
        "This program comes with NO WARRANTY, to the extent permitted by law.\n"
        "You may redistribute it under the terms of the GNU General Public License;\n"
        "see the file named COPYING for details.\n"
        "Written by the VideoLAN team at Ecole Centrale, Paris." );
830
}
Vincent Seguin's avatar
Vincent Seguin committed
831

832
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
833
 * InitSignalHandler: system signal handler initialization
834
 *****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
835
 * Set the signal handlers. SIGTERM is not intercepted, because we need at
836
 * at least a method to kill the program when all other methods failed, and
Michel Kaempf's avatar
Michel Kaempf committed
837
 * when we don't want to use SIGKILL.
838
 *****************************************************************************/
Michel Kaempf's avatar
Michel Kaempf committed
839 840
static void InitSignalHandler( void )
{
Vincent Seguin's avatar
Vincent Seguin committed
841
    /* Termination signals */
Benoit Steiner's avatar
 
Benoit Steiner committed
842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859
    signal( SIGHUP,  FatalSignalHandler );
    signal( SIGINT,  FatalSignalHandler );
    signal( SIGQUIT, FatalSignalHandler );

    /* Other signals */
    signal( SIGALRM, SimpleSignalHandler );
    signal( SIGPIPE, SimpleSignalHandler );
}


/*****************************************************************************
 * SimpleSignalHandler: system signal handler
 *****************************************************************************
 * This function is called when a non fatal signal is received by the program.
 *****************************************************************************/
static void SimpleSignalHandler( int i_signal )
{
    /* Acknowledge the signal received */
Sam Hocevar's avatar
 
Sam Hocevar committed
860
    intf_WarnMsg( 0, "intf: ignoring signal %d", i_signal );
Michel Kaempf's avatar
Michel Kaempf committed
861 862
}

Benoit Steiner's avatar
 
Benoit Steiner committed
863

864
/*****************************************************************************
Benoit Steiner's avatar
 
Benoit Steiner committed
865
 * FatalSignalHandler: system signal handler
866
 *****************************************************************************
Benoit Steiner's avatar
 
Benoit Steiner committed
867 868
 * This function is called when a fatal signal is received by the program.
 * It tries to end the program in a clean way.
869
 *****************************************************************************/
Benoit Steiner's avatar
 
Benoit Steiner committed
870
static void FatalSignalHandler( int i_signal )
Michel Kaempf's avatar
Michel Kaempf committed
871
{
Sam Hocevar's avatar
 
Sam Hocevar committed
872 873 874
    /* Once a signal has been trapped, the termination sequence will be
     * armed and following signals will be ignored to avoid sending messages
     * to an interface having been destroyed */
Vincent Seguin's avatar
Vincent Seguin committed
875 876 877 878 879
    signal( SIGHUP,  SIG_IGN );
    signal( SIGINT,  SIG_IGN );
    signal( SIGQUIT, SIG_IGN );

    /* Acknowledge the signal received */
Sam Hocevar's avatar
 
Sam Hocevar committed
880
    intf_ErrMsgImm( "intf error: signal %d received, exiting", i_signal );
Vincent Seguin's avatar
Vincent Seguin committed
881

882
    /* Try to terminate everything - this is done by requesting the end of the
Vincent Seguin's avatar
Vincent Seguin committed
883 884 885 886
     * interface thread */
    p_main->p_intf->b_die = 1;
}

Sam Hocevar's avatar
 
Sam Hocevar committed
887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004
/*****************************************************************************
 * CPUCapabilities: list the processors MMX support and other capabilities
 *****************************************************************************
 * This function is called to list extensions the CPU may have.
 *****************************************************************************/
static int CPUCapabilities( void )
{
    int i_capabilities = CPU_CAPABILITY_NONE;

#if defined( SYS_BEOS )
    i_capabilities |= CPU_CAPABILITY_486
                      | CPU_CAPABILITY_586
                      | CPU_CAPABILITY_MMX;

#elif defined( SYS_DARWIN1_3 )
    OSErr err;
    long l_attributes = 0;

    err = Gestalt( gestaltPowerPCProcessorFeatures, &l_attributes );

    if( err == noErr &&
         ( (1 << gestaltPowerPCHasVectorInstructions) & l_attributes ) )
    {
        i_capabilities |= CPU_CAPABILITY_ALTIVEC;
    }

#elif defined( __i386__ )
    unsigned int  i_eax, i_ebx, i_ecx, i_edx;
    boolean_t     b_amd;

#   define cpuid( a )              \
    asm volatile ( "cpuid"         \
                 : "=a" ( i_eax ), \
                   "=b" ( i_ebx ), \
                   "=c" ( i_ecx ), \
                   "=d" ( i_edx )  \
                 : "a"  ( a )      \
                 : "cc" );         \

    /* test for a 486 CPU */
    asm volatile ( "pushfl
                    popl %%eax
                    movl %%eax, %%ebx
                    xorl $0x200000, %%eax
                    pushl %%eax
                    popfl
                    pushfl
                    popl %%eax"
                 : "=a" ( i_eax ),
                   "=b" ( i_ebx )
                 :
                 : "cc" );

    if( i_eax == i_ebx )
    {
        return( i_capabilities );
    }

    i_capabilities |= CPU_CAPABILITY_486;

    /* the CPU supports the CPUID instruction - get its level */
    cpuid( 0x00000000 );

    if( !i_eax )
    {
        return( i_capabilities );
    }

    /* FIXME: this isn't correct, since some 486s have cpuid */
    i_capabilities |= CPU_CAPABILITY_586;

    /* borrowed from mpeg2dec */
    b_amd = ( i_ebx == 0x68747541 ) && ( i_ecx == 0x444d4163 )
                    && ( i_edx == 0x69746e65 );

    /* test for the MMX flag */
    cpuid( 0x00000001 );

    if( ! (i_edx & 0x00800000) )
    {
        return( i_capabilities );
    }

    i_capabilities |= CPU_CAPABILITY_MMX;

    if( i_edx & 0x02000000 )
    {
        i_capabilities |= CPU_CAPABILITY_MMXEXT;
    }
    
    /* test for additional capabilities */
    cpuid( 0x80000000 );

    if( i_eax < 0x80000001 )
    {
        return( i_capabilities );
    }

    /* list these additional capabilities */
    cpuid( 0x80000001 );

    if( i_edx & 0x80000000 )
    {
        i_capabilities |= CPU_CAPABILITY_3DNOW;
    }

    if( b_amd && ( i_edx & 0x00400000 ) )
    {
        i_capabilities |= CPU_CAPABILITY_MMXEXT;
    }

#else
    /* default behaviour */

#endif
    return( i_capabilities );
}