]> git.sesse.net Git - vlc/blob - src/libvlc.c
* ./src/misc/objects.c: two big changes in the object API: now objects can
[vlc] / src / libvlc.c
1 /*****************************************************************************
2  * libvlc.c: main libvlc source
3  *****************************************************************************
4  * Copyright (C) 1998-2002 VideoLAN
5  * $Id: libvlc.c,v 1.25 2002/08/12 09:34:15 sam Exp $
6  *
7  * Authors: Vincent Seguin <seguin@via.ecp.fr>
8  *          Samuel Hocevar <sam@zoy.org>
9  *          Gildas Bazin <gbazin@netcourrier.com>
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
24  *****************************************************************************/
25
26 /*****************************************************************************
27  * Pretend we are a builtin module
28  *****************************************************************************/
29 #define MODULE_NAME main
30 #define MODULE_PATH main
31 #define __BUILTIN__
32
33 /*****************************************************************************
34  * Preamble
35  *****************************************************************************/
36 #include <errno.h>                                                 /* ENOMEM */
37 #include <stdio.h>                                              /* sprintf() */
38 #include <string.h>                                            /* strerror() */
39 #include <stdlib.h>                                                /* free() */
40 #include <signal.h>                               /* SIGHUP, SIGINT, SIGKILL */
41
42 #include <vlc/vlc.h>
43
44 #ifdef HAVE_GETOPT_LONG
45 #   ifdef HAVE_GETOPT_H
46 #       include <getopt.h>                                       /* getopt() */
47 #   endif
48 #else
49 #   include "GNUgetopt/getopt.h"
50 #endif
51
52 #ifndef WIN32
53 #   include <netinet/in.h>                            /* BSD: struct in_addr */
54 #endif
55
56 #ifdef HAVE_UNISTD_H
57 #   include <unistd.h>
58 #elif defined( _MSC_VER ) && defined( _WIN32 )
59 #   include <io.h>
60 #endif
61
62 #ifdef HAVE_LOCALE_H
63 #   include <locale.h>
64 #endif
65
66 #include "vlc_cpu.h"                                        /* CPU detection */
67 #include "os_specific.h"
68
69 #include "netutils.h"                                 /* network_ChannelJoin */
70
71 #include "stream_control.h"
72 #include "input_ext-intf.h"
73
74 #include "vlc_playlist.h"
75 #include "interface.h"
76
77 #include "audio_output.h"
78
79 #include "video.h"
80 #include "video_output.h"
81
82 #include "libvlc.h"
83
84 /*****************************************************************************
85  * The evil global variables. We handle them with care, don't worry.
86  *****************************************************************************/
87
88 /* This global lock is used for critical sections - don't abuse it! */
89 static vlc_mutex_t global_lock;
90 void *             p_global_data;
91
92 /* A list of all the currently allocated vlc objects */
93 static int volatile i_vlc = 0;
94 static int volatile i_unique = 0;
95 static vlc_t ** volatile pp_vlc = NULL;
96
97 /*****************************************************************************
98  * Local prototypes
99  *****************************************************************************/
100 static int  GetFilenames  ( vlc_t *, int, char *[] );
101 static void Usage         ( vlc_t *, const char *psz_module_name );
102 static void ListModules   ( vlc_t * );
103 static void Version       ( void );
104
105 #ifndef WIN32
106 static void InitSignalHandler   ( void );
107 static void SimpleSignalHandler ( int i_signal );
108 static void FatalSignalHandler  ( int i_signal );
109 #endif
110
111 #ifdef WIN32
112 static void ShowConsole   ( void );
113 #endif
114
115 /*****************************************************************************
116  * vlc_create: allocate a vlc_t structure, and initialize libvlc if needed.
117  *****************************************************************************
118  * This function allocates a vlc_t structure and returns NULL in case of
119  * failure. Also, the thread system and the signal handlers are initialized.
120  *****************************************************************************/
121 vlc_error_t vlc_create( void )
122 {
123     vlc_t * p_vlc = vlc_create_r();
124     return p_vlc ? VLC_SUCCESS : VLC_EGENERIC;
125 }
126
127 vlc_t * vlc_create_r( void )
128 {
129     vlc_t * p_vlc = NULL;
130
131     /* Allocate the main structure */
132     p_vlc = vlc_object_create( p_vlc, VLC_OBJECT_ROOT );
133     if( p_vlc == NULL )
134     {
135         return NULL;
136     }
137
138     p_vlc->psz_object_name = "root";
139
140     p_vlc->p_global_lock = &global_lock;
141     p_vlc->pp_global_data = &p_global_data;
142
143     p_vlc->b_verbose = VLC_FALSE;
144     p_vlc->b_quiet = VLC_FALSE; /* FIXME: delay message queue output! */
145
146     /* Initialize the threads system */
147     vlc_threads_init( p_vlc );
148
149     /* Initialize mutexes */
150     vlc_mutex_init( p_vlc, &p_vlc->config_lock );
151     vlc_mutex_init( p_vlc, &p_vlc->structure_lock );
152
153     /* Set signal handling policy for all threads */
154 #ifndef WIN32
155     InitSignalHandler( );
156 #endif
157
158     /* Store our newly allocated structure in the global list */
159     vlc_mutex_lock( p_vlc->p_global_lock );
160     pp_vlc = realloc( pp_vlc, (i_vlc+1) * sizeof( vlc_t * ) );
161     pp_vlc[ i_vlc ] = p_vlc;
162     i_vlc++;
163     p_vlc->i_unique = i_unique;
164     i_unique++;
165     vlc_mutex_unlock( p_vlc->p_global_lock );
166
167     /* Update the handle status */
168     p_vlc->i_status = VLC_STATUS_CREATED;
169
170     return p_vlc;
171 }
172
173 /*****************************************************************************
174  * vlc_init: initialize a vlc_t structure.
175  *****************************************************************************
176  * This function initializes a previously allocated vlc_t structure:
177  *  - CPU detection
178  *  - gettext initialization
179  *  - message queue, module bank and playlist initialization
180  *  - configuration and commandline parsing
181  *****************************************************************************/
182 vlc_error_t vlc_init( int i_argc, char *ppsz_argv[] )
183 {
184     return vlc_init_r( ( i_vlc == 1 ) ? *pp_vlc : NULL, i_argc, ppsz_argv );
185 }
186
187 vlc_error_t vlc_init_r( vlc_t *p_vlc, int i_argc, char *ppsz_argv[] )
188 {
189     char p_capabilities[200];
190     char *p_tmp;
191     module_t        *p_help_module;
192     playlist_t      *p_playlist;
193
194     /* Check that the handle is valid */
195     if( !p_vlc || p_vlc->i_status != VLC_STATUS_CREATED )
196     {
197         fprintf( stderr, "error: invalid status (!CREATED)\n" );
198         return VLC_ESTATUS;
199     }
200
201     fprintf( stderr, COPYRIGHT_MESSAGE "\n" );
202
203     /* Guess what CPU we have */
204     p_vlc->i_cpu = CPUCapabilities( p_vlc );
205
206     /*
207      * Support for gettext
208      */
209 #if defined( ENABLE_NLS ) && defined ( HAVE_GETTEXT )
210 #   if defined( HAVE_LOCALE_H ) && defined( HAVE_LC_MESSAGES )
211     if( !setlocale( LC_MESSAGES, "" ) )
212     {
213         fprintf( stderr, "warning: unsupported locale settings\n" );
214     }
215
216     setlocale( LC_CTYPE, "" );
217 #   endif
218
219     if( !bindtextdomain( PACKAGE, LOCALEDIR ) )
220     {
221         fprintf( stderr, "warning: no domain %s in directory %s\n",
222                  PACKAGE, LOCALEDIR );
223     }
224
225     textdomain( PACKAGE );
226 #endif
227
228     /*
229      * System specific initialization code
230      */
231     system_Init( p_vlc, &i_argc, ppsz_argv );
232
233     /*
234      * Initialize message queue
235      */
236     msg_Create( p_vlc );
237
238     /* Get the executable name (similar to the basename command) */
239     if( i_argc > 0 )
240     {
241         p_vlc->psz_object_name = p_tmp = ppsz_argv[ 0 ];
242         while( *p_tmp )
243         {
244             if( *p_tmp == '/' ) p_vlc->psz_object_name = ++p_tmp;
245             else ++p_tmp;
246         }
247     }
248     else
249     {
250         p_vlc->psz_object_name = "vlc";
251     }
252
253     /* Announce who we are */
254     msg_Dbg( p_vlc, COPYRIGHT_MESSAGE );
255     msg_Dbg( p_vlc, "libvlc was configured with %s", CONFIGURE_LINE );
256
257     /*
258      * Initialize the module bank and and load the configuration of the main
259      * module. We need to do this at this stage to be able to display a short
260      * help if required by the user. (short help == main module options)
261      */
262     module_InitBank( p_vlc );
263     module_LoadMain( p_vlc );
264
265     /* Hack: insert the help module here */
266     p_help_module = vlc_object_create( p_vlc, VLC_OBJECT_MODULE );
267     if( p_help_module == NULL )
268     {
269         module_EndBank( p_vlc );
270         msg_Destroy( p_vlc );
271         return VLC_EGENERIC;
272     }
273     p_help_module->psz_object_name = "help";
274     config_Duplicate( p_help_module, p_help_config );
275     p_help_module->next = p_vlc->p_module_bank->first;
276     p_vlc->p_module_bank->first = p_help_module;
277     /* End hack */
278
279     if( config_LoadCmdLine( p_vlc, &i_argc, ppsz_argv, VLC_TRUE ) )
280     {
281         p_vlc->p_module_bank->first = p_help_module->next;
282         config_Free( p_help_module );
283         vlc_object_destroy( p_help_module );
284         module_EndBank( p_vlc );
285         msg_Destroy( p_vlc );
286         return VLC_EGENERIC;
287     }
288
289     /* Check for short help option */
290     if( config_GetInt( p_vlc, "help" ) )
291     {
292         fprintf( stderr, _("Usage: %s [options] [parameters] [file]...\n"),
293                          p_vlc->psz_object_name );
294
295         Usage( p_vlc, "help" );
296         Usage( p_vlc, "main" );
297         p_vlc->p_module_bank->first = p_help_module->next;
298         config_Free( p_help_module );
299         vlc_object_destroy( p_help_module );
300         module_EndBank( p_vlc );
301         msg_Destroy( p_vlc );
302         return VLC_EEXIT;
303     }
304
305     /* Check for version option */
306     if( config_GetInt( p_vlc, "version" ) )
307     {
308         Version();
309         p_vlc->p_module_bank->first = p_help_module->next;
310         config_Free( p_help_module );
311         vlc_object_destroy( p_help_module );
312         module_EndBank( p_vlc );
313         msg_Destroy( p_vlc );
314         return VLC_EEXIT;
315     }
316
317     /* Hack: remove the help module here */
318     p_vlc->p_module_bank->first = p_help_module->next;
319     /* End hack */
320
321     /*
322      * Load the builtins and plugins into the module_bank.
323      * We have to do it before config_Load*() because this also gets the
324      * list of configuration options exported by each module and loads their
325      * default values.
326      */
327     module_LoadBuiltins( p_vlc );
328     module_LoadPlugins( p_vlc );
329     msg_Dbg( p_vlc, "module bank initialized, found %i modules",
330                     p_vlc->p_module_bank->i_count );
331
332     /* Hack: insert the help module here */
333     p_help_module->next = p_vlc->p_module_bank->first;
334     p_vlc->p_module_bank->first = p_help_module;
335     /* End hack */
336
337     /* Check for help on modules */
338     if( (p_tmp = config_GetPsz( p_vlc, "module" )) )
339     {
340         Usage( p_vlc, p_tmp );
341         free( p_tmp );
342         p_vlc->p_module_bank->first = p_help_module->next;
343         config_Free( p_help_module );
344         vlc_object_destroy( p_help_module );
345         module_EndBank( p_vlc );
346         msg_Destroy( p_vlc );
347         return VLC_EGENERIC;
348     }
349
350     /* Check for long help option */
351     if( config_GetInt( p_vlc, "longhelp" ) )
352     {
353         Usage( p_vlc, NULL );
354         p_vlc->p_module_bank->first = p_help_module->next;
355         config_Free( p_help_module );
356         vlc_object_destroy( p_help_module );
357         module_EndBank( p_vlc );
358         msg_Destroy( p_vlc );
359         return VLC_EEXIT;
360     }
361
362     /* Check for module list option */
363     if( config_GetInt( p_vlc, "list" ) )
364     {
365         ListModules( p_vlc );
366         p_vlc->p_module_bank->first = p_help_module->next;
367         config_Free( p_help_module );
368         vlc_object_destroy( p_help_module );
369         module_EndBank( p_vlc );
370         msg_Destroy( p_vlc );
371         return VLC_EEXIT;
372     }
373
374     /* Hack: remove the help module here */
375     p_vlc->p_module_bank->first = p_help_module->next;
376     config_Free( p_help_module );
377     vlc_object_destroy( p_help_module );
378     /* End hack */
379
380     /*
381      * Override default configuration with config file settings
382      */
383     p_vlc->psz_homedir = config_GetHomeDir();
384     config_LoadConfigFile( p_vlc, NULL );
385
386     /*
387      * Override configuration with command line settings
388      */
389     if( config_LoadCmdLine( p_vlc, &i_argc, ppsz_argv, VLC_FALSE ) )
390     {
391 #ifdef WIN32
392         ShowConsole();
393         /* Pause the console because it's destroyed when we exit */
394         fprintf( stderr, "The command line options couldn't be loaded, check "
395                  "that they are valid.\nPress the RETURN key to continue..." );
396         getchar();
397 #endif
398         module_EndBank( p_vlc );
399         msg_Destroy( p_vlc );
400         return VLC_EGENERIC;
401     }
402
403     /*
404      * System specific configuration
405      */
406     system_Configure( p_vlc );
407
408     /*
409      * Output messages that may still be in the queue
410      */
411     p_vlc->b_verbose = config_GetInt( p_vlc, "verbose" );
412     p_vlc->b_quiet = config_GetInt( p_vlc, "quiet" );
413     p_vlc->b_color = config_GetInt( p_vlc, "color" );
414     msg_Flush( p_vlc );
415
416     /* p_vlc inititalization. FIXME ? */
417     p_vlc->i_desync = config_GetInt( p_vlc, "desync" ) * (mtime_t)1000;
418 #if defined( __i386__ )
419     if( !config_GetInt( p_vlc, "mmx" ) )
420         p_vlc->i_cpu &= ~CPU_CAPABILITY_MMX;
421     if( !config_GetInt( p_vlc, "3dn" ) )
422         p_vlc->i_cpu &= ~CPU_CAPABILITY_3DNOW;
423     if( !config_GetInt( p_vlc, "mmxext" ) )
424         p_vlc->i_cpu &= ~CPU_CAPABILITY_MMXEXT;
425     if( !config_GetInt( p_vlc, "sse" ) )
426         p_vlc->i_cpu &= ~CPU_CAPABILITY_SSE;
427 #endif
428 #if defined( __powerpc__ ) || defined( SYS_DARWIN )
429     if( !config_GetInt( p_vlc, "altivec" ) )
430         p_vlc->i_cpu &= ~CPU_CAPABILITY_ALTIVEC;
431 #endif
432
433 #define PRINT_CAPABILITY( capability, string )                              \
434     if( p_vlc->i_cpu & capability )                                         \
435     {                                                                       \
436         strncat( p_capabilities, string " ",                                \
437                  sizeof(p_capabilities) - strlen(p_capabilities) );         \
438         p_capabilities[sizeof(p_capabilities) - 1] = '\0';                  \
439     }
440
441     p_capabilities[0] = '\0';
442     PRINT_CAPABILITY( CPU_CAPABILITY_486, "486" );
443     PRINT_CAPABILITY( CPU_CAPABILITY_586, "586" );
444     PRINT_CAPABILITY( CPU_CAPABILITY_PPRO, "Pentium Pro" );
445     PRINT_CAPABILITY( CPU_CAPABILITY_MMX, "MMX" );
446     PRINT_CAPABILITY( CPU_CAPABILITY_3DNOW, "3DNow!" );
447     PRINT_CAPABILITY( CPU_CAPABILITY_MMXEXT, "MMXEXT" );
448     PRINT_CAPABILITY( CPU_CAPABILITY_SSE, "SSE" );
449     PRINT_CAPABILITY( CPU_CAPABILITY_ALTIVEC, "AltiVec" );
450     PRINT_CAPABILITY( CPU_CAPABILITY_FPU, "FPU" );
451     msg_Dbg( p_vlc, "CPU has capabilities %s", p_capabilities );
452
453     /*
454      * Choose the best memcpy module
455      */
456     p_vlc->p_memcpy_module = module_Need( p_vlc, "memcpy", "$memcpy" );
457
458     if( p_vlc->pf_memcpy == NULL )
459     {
460         p_vlc->pf_memcpy = memcpy;
461     }
462
463     if( p_vlc->pf_memset == NULL )
464     {
465         p_vlc->pf_memset = memset;
466     }
467
468     /*
469      * Initialize shared resources and libraries
470      */
471     if( config_GetInt( p_vlc, "network-channel" )
472          && network_ChannelCreate( p_vlc ) )
473     {
474         /* On error during Channels initialization, switch off channels */
475         msg_Warn( p_vlc,
476                   "channels initialization failed, deactivating channels" );
477         config_PutInt( p_vlc, "network-channel", VLC_FALSE );
478     }
479
480     /*
481      * Initialize playlist and get commandline files
482      */
483     p_playlist = playlist_Create( p_vlc );
484     if( !p_playlist )
485     {
486         msg_Err( p_vlc, "playlist initialization failed" );
487         if( p_vlc->p_memcpy_module != NULL )
488         {
489             module_Unneed( p_vlc, p_vlc->p_memcpy_module );
490         }
491         module_EndBank( p_vlc );
492         msg_Destroy( p_vlc );
493         return VLC_EGENERIC;
494     }
495
496     /* Update the handle status */
497     p_vlc->i_status = VLC_STATUS_STOPPED;
498
499     /*
500      * Get input filenames given as commandline arguments
501      */
502     GetFilenames( p_vlc, i_argc, ppsz_argv );
503
504     return VLC_SUCCESS;
505 }
506
507 /*****************************************************************************
508  * vlc_run: run vlc
509  *****************************************************************************
510  * XXX: This function opens an interface plugin and runs it. If b_block is set
511  * to 0, vlc_add_intf will return immediately and let the interface run in a
512  * separate thread. If b_block is set to 1, vlc_add_intf will continue until
513  * user requests to quit.
514  *****************************************************************************/
515 vlc_error_t vlc_run( void )
516 {
517     return vlc_run_r( ( i_vlc == 1 ) ? *pp_vlc : NULL );
518 }
519
520 vlc_error_t vlc_run_r( vlc_t *p_vlc )
521 {
522     /* Check that the handle is valid */
523     if( !p_vlc || p_vlc->i_status != VLC_STATUS_STOPPED )
524     {
525         fprintf( stderr, "error: invalid status (!STOPPED)\n" );
526         return VLC_ESTATUS;
527     }
528
529     /* Update the handle status */
530     p_vlc->i_status = VLC_STATUS_RUNNING;
531
532     return VLC_SUCCESS;
533 }
534
535 /*****************************************************************************
536  * vlc_add_intf: add an interface
537  *****************************************************************************
538  * This function opens an interface plugin and runs it. If b_block is set
539  * to 0, vlc_add_intf will return immediately and let the interface run in a
540  * separate thread. If b_block is set to 1, vlc_add_intf will continue until
541  * user requests to quit.
542  *****************************************************************************/
543 vlc_error_t vlc_add_intf( const char *psz_module, vlc_bool_t b_block )
544 {
545     return vlc_add_intf_r( ( i_vlc == 1 ) ? *pp_vlc : NULL,
546                            psz_module, b_block );
547 }
548
549 vlc_error_t vlc_add_intf_r( vlc_t *p_vlc, const char *psz_module,
550                                           vlc_bool_t b_block )
551 {
552     vlc_error_t err;
553     intf_thread_t *p_intf;
554     char *psz_oldmodule = NULL;
555
556     /* Check that the handle is valid */
557     if( !p_vlc || p_vlc->i_status != VLC_STATUS_RUNNING )
558     {
559         fprintf( stderr, "error: invalid status (!RUNNING)\n" );
560         return VLC_ESTATUS;
561     }
562
563     if( psz_module )
564     {
565         psz_oldmodule = config_GetPsz( p_vlc, "intf" );
566         config_PutPsz( p_vlc, "intf", psz_module );
567     }
568
569     /* Try to create the interface */
570     p_intf = intf_Create( p_vlc );
571
572     if( psz_module )
573     {
574         config_PutPsz( p_vlc, "intf", psz_oldmodule );
575         if( psz_oldmodule )
576         {
577             free( psz_oldmodule );
578         }
579     }
580
581     if( p_intf == NULL )
582     {
583         msg_Err( p_vlc, "interface initialization failed" );
584         return VLC_EGENERIC;
585     }
586
587     /* Try to run the interface */
588     p_intf->b_block = b_block;
589     err = intf_RunThread( p_intf );
590     if( err )
591     {
592         vlc_object_detach( p_intf );
593         intf_Destroy( p_intf );
594         return err;
595     }
596
597     return VLC_SUCCESS;
598 }
599
600 /*****************************************************************************
601  * vlc_stop: stop playing.
602  *****************************************************************************
603  * This function requests the interface threads to finish, waits for their
604  * termination, and destroys their structure.
605  *****************************************************************************/
606 vlc_error_t vlc_stop( void )
607 {
608     return vlc_stop_r( ( i_vlc == 1 ) ? *pp_vlc : NULL );
609 }
610
611 vlc_error_t vlc_stop_r( vlc_t *p_vlc )
612 {
613     intf_thread_t *p_intf;
614     playlist_t    *p_playlist;
615     vout_thread_t *p_vout;
616     aout_instance_t *p_aout;
617
618     /* Check that the handle is valid */
619     if( !p_vlc || p_vlc->i_status != VLC_STATUS_RUNNING )
620     {
621         fprintf( stderr, "error: invalid status (!RUNNING)\n" );
622         return VLC_ESTATUS;
623     }
624
625     /*
626      * Ask the interfaces to stop and destroy them
627      */
628     msg_Dbg( p_vlc, "removing all interfaces" );
629     while( (p_intf = vlc_object_find( p_vlc, VLC_OBJECT_INTF, FIND_CHILD )) )
630     {
631         intf_StopThread( p_intf );
632         vlc_object_detach( p_intf );
633         vlc_object_release( p_intf );
634         intf_Destroy( p_intf );
635     }
636
637     /*
638      * Free playlists
639      */
640     msg_Dbg( p_vlc, "removing all playlists" );
641     while( (p_playlist = vlc_object_find( p_vlc, VLC_OBJECT_PLAYLIST,
642                                           FIND_CHILD )) )
643     {
644         vlc_object_detach( p_playlist );
645         vlc_object_release( p_playlist );
646         playlist_Destroy( p_playlist );
647     }
648
649     /*
650      * Free video outputs
651      */
652     msg_Dbg( p_vlc, "removing all video outputs" );
653     while( (p_vout = vlc_object_find( p_vlc, VLC_OBJECT_VOUT, FIND_CHILD )) )
654     {
655         vlc_object_detach( p_vout );
656         vlc_object_release( p_vout );
657         vout_DestroyThread( p_vout );
658     }
659
660     /*
661      * Free audio outputs
662      */
663     msg_Dbg( p_vlc, "removing all audio outputs" );
664     while( (p_aout = vlc_object_find( p_vlc, VLC_OBJECT_AOUT, FIND_CHILD )) )
665     {
666         vlc_object_detach( (vlc_object_t *)p_aout );
667         vlc_object_release( (vlc_object_t *)p_aout );
668         aout_DeleteInstance( p_aout );
669     }
670
671     /* Update the handle status */
672     p_vlc->i_status = VLC_STATUS_STOPPED;
673
674     return VLC_SUCCESS;
675 }
676
677 /*****************************************************************************
678  * vlc_end: uninitialize everything.
679  *****************************************************************************
680  * This function uninitializes every vlc component that was activated in
681  * vlc_init: audio and video outputs, playlist, module bank and message queue.
682  *****************************************************************************/
683 vlc_error_t vlc_end( void )
684 {
685     return vlc_end_r( ( i_vlc == 1 ) ? *pp_vlc : NULL );
686 }
687
688 vlc_error_t vlc_end_r( vlc_t *p_vlc )
689 {
690     /* Check that the handle is valid */
691     if( !p_vlc || p_vlc->i_status != VLC_STATUS_STOPPED )
692     {
693         fprintf( stderr, "error: invalid status (!STOPPED)\n" );
694         return VLC_ESTATUS;
695     }
696
697     /*
698      * Go back into channel 0 which is the network
699      */
700     if( config_GetInt( p_vlc, "network-channel" ) && p_vlc->p_channel )
701     {
702         network_ChannelJoin( p_vlc, COMMON_CHANNEL );
703     }
704
705     /*
706      * Free allocated memory
707      */
708     if( p_vlc->p_memcpy_module != NULL )
709     {
710         module_Unneed( p_vlc, p_vlc->p_memcpy_module );
711     }
712
713     free( p_vlc->psz_homedir );
714
715     /*
716      * Free module bank
717      */
718     module_EndBank( p_vlc );
719
720     /*
721      * System specific cleaning code
722      */
723     system_End( p_vlc );
724
725     /*
726      * Terminate messages interface and program
727      */
728     msg_Destroy( p_vlc );
729
730     /* Update the handle status */
731     p_vlc->i_status = VLC_STATUS_CREATED;
732
733     return VLC_SUCCESS;
734 }
735
736 /*****************************************************************************
737  * vlc_destroy: free allocated resources.
738  *****************************************************************************
739  * This function frees the previously allocated vlc_t structure.
740  *****************************************************************************/
741 vlc_error_t vlc_destroy( void )
742 {
743     return vlc_destroy_r( ( i_vlc == 1 ) ? *pp_vlc : NULL );
744 }
745
746 vlc_error_t vlc_destroy_r( vlc_t *p_vlc )
747 {
748     int i_index;
749
750     /* Check that the handle is valid */
751     if( !p_vlc || p_vlc->i_status != VLC_STATUS_CREATED )
752     {
753         fprintf( stderr, "error: invalid status (!CREATED)\n" );
754         return VLC_ESTATUS;
755     }
756
757     /* Update the handle status, just in case */
758     p_vlc->i_status = VLC_STATUS_NONE;
759
760     /* Remove our structure from the global list */
761     vlc_mutex_lock( p_vlc->p_global_lock );
762     for( i_index = 0 ; i_index < i_vlc ; i_index++ )
763     {
764         if( pp_vlc[ i_index ] == p_vlc )
765         {
766             break;
767         }
768     }
769
770     if( i_index == i_vlc )
771     {
772         fprintf( stderr, "error: trying to unregister %p which is not in "
773                          "the list\n", (void *)p_vlc );
774         vlc_mutex_unlock( p_vlc->p_global_lock );
775         vlc_object_destroy( p_vlc );
776         return VLC_EGENERIC;
777     }
778
779     for( i_index++ ; i_index < i_vlc ; i_index++ )
780     {
781         pp_vlc[ i_index - 1 ] = pp_vlc[ i_index ];
782     }
783
784     i_vlc--;
785     if( i_vlc )
786     {
787         pp_vlc = realloc( pp_vlc, i_vlc * sizeof( vlc_t * ) );
788     }
789     else
790     {
791         free( pp_vlc );
792         pp_vlc = NULL;
793     }
794     vlc_mutex_unlock( p_vlc->p_global_lock );
795
796     /* Stop thread system: last one out please shut the door! */
797     vlc_threads_end( p_vlc );
798
799     /* Destroy mutexes */
800     vlc_mutex_destroy( &p_vlc->structure_lock );
801     vlc_mutex_destroy( &p_vlc->config_lock );
802
803     vlc_object_destroy( p_vlc );
804
805     return VLC_SUCCESS;
806 }
807
808 vlc_status_t vlc_status( void )
809 {
810     return vlc_status_r( ( i_vlc == 1 ) ? *pp_vlc : NULL );
811 }
812
813 vlc_status_t vlc_status_r( vlc_t *p_vlc )
814 {
815     if( !p_vlc )
816     {
817         return VLC_STATUS_NONE;
818     }
819
820     return p_vlc->i_status;
821 }
822
823 vlc_error_t vlc_add_target( const char *psz_target, int i_mode, int i_pos )
824 {
825     return vlc_add_target_r( ( i_vlc == 1 ) ? *pp_vlc : NULL,
826                              psz_target, i_mode, i_pos );
827 }
828
829 vlc_error_t vlc_add_target_r( vlc_t *p_vlc, const char *psz_target,
830                                             int i_mode, int i_pos )
831 {
832     vlc_error_t err;
833     playlist_t *p_playlist;
834
835     if( !p_vlc || ( p_vlc->i_status != VLC_STATUS_STOPPED
836                      && p_vlc->i_status != VLC_STATUS_RUNNING ) )
837     {
838         fprintf( stderr, "error: invalid status (!STOPPED&&!RUNNING)\n" );
839         return VLC_ESTATUS;
840     }
841
842     p_playlist = vlc_object_find( p_vlc, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
843
844     if( p_playlist == NULL )
845     {
846         msg_Dbg( p_vlc, "no playlist present, creating one" );
847         p_playlist = playlist_Create( p_vlc );
848
849         if( p_playlist == NULL )
850         {
851             return VLC_EGENERIC;
852         }
853
854         vlc_object_yield( p_playlist );
855     }
856
857     err = playlist_Add( p_playlist, psz_target, i_mode, i_pos );
858
859     vlc_object_release( p_playlist );
860
861     return err;
862 }
863
864 /* following functions are local */
865
866 /*****************************************************************************
867  * GetFilenames: parse command line options which are not flags
868  *****************************************************************************
869  * Parse command line for input files.
870  *****************************************************************************/
871 static int GetFilenames( vlc_t *p_vlc, int i_argc, char *ppsz_argv[] )
872 {
873     int i_opt;
874
875     /* We assume that the remaining parameters are filenames */
876     for( i_opt = optind; i_opt < i_argc; i_opt++ )
877     {
878         vlc_add_target_r( p_vlc, ppsz_argv[ i_opt ],
879                           PLAYLIST_APPEND, PLAYLIST_END );
880     }
881
882     return VLC_SUCCESS;
883 }
884
885 /*****************************************************************************
886  * Usage: print program usage
887  *****************************************************************************
888  * Print a short inline help. Message interface is initialized at this stage.
889  *****************************************************************************/
890 static void Usage( vlc_t *p_this, const char *psz_module_name )
891 {
892 #define FORMAT_STRING "      --%s%s%s%s%s%s%s %s%s\n"
893     /* option name -------------'     | | | |  | |
894      * <bra --------------------------' | | |  | |
895      * option type or "" ---------------' | |  | |
896      * ket> ------------------------------' |  | |
897      * padding spaces ----------------------'  | |
898      * comment --------------------------------' |
899      * comment suffix ---------------------------'
900      *
901      * The purpose of having bra and ket is that we might i18n them as well.
902      */
903 #define LINE_START 8
904 #define PADDING_SPACES 25
905     module_t *p_module;
906     module_config_t *p_item;
907     char psz_spaces[PADDING_SPACES+LINE_START+1];
908     char psz_format[sizeof(FORMAT_STRING)];
909
910     memset( psz_spaces, ' ', PADDING_SPACES+LINE_START );
911     psz_spaces[PADDING_SPACES+LINE_START] = '\0';
912
913     strcpy( psz_format, FORMAT_STRING );
914
915 #ifdef WIN32
916     ShowConsole();
917 #endif
918
919     /* Enumerate the config for each module */
920     for( p_module = p_this->p_vlc->p_module_bank->first ;
921          p_module != NULL ;
922          p_module = p_module->next )
923     {
924         vlc_bool_t b_help_module = !strcmp( "help", p_module->psz_object_name );
925
926         if( psz_module_name && strcmp( psz_module_name,
927                                        p_module->psz_object_name ) )
928         {
929             continue;
930         }
931
932         /* Ignore modules without config options */
933         if( !p_module->i_config_items )
934         {
935             continue;
936         }
937
938         /* Print module name */
939         fprintf( stderr, _("%s module options:\n\n"),
940                          p_module->psz_object_name );
941
942         for( p_item = p_module->p_config;
943              p_item->i_type != CONFIG_HINT_END;
944              p_item++ )
945         {
946             char *psz_bra = NULL, *psz_type = NULL, *psz_ket = NULL;
947             char *psz_suf = "", *psz_prefix = NULL;
948             int i;
949
950             switch( p_item->i_type )
951             {
952             case CONFIG_HINT_CATEGORY:
953             case CONFIG_HINT_USAGE:
954                 fprintf( stderr, " %s\n", p_item->psz_text );
955                 break;
956
957             case CONFIG_ITEM_STRING:
958             case CONFIG_ITEM_FILE:
959             case CONFIG_ITEM_MODULE: /* We could also have "=<" here */
960                 if( !p_item->ppsz_list )
961                 {
962                     psz_bra = " <"; psz_type = _("string"); psz_ket = ">";
963                     break;
964                 }
965                 else
966                 {
967                     psz_bra = " [";
968                     psz_type = malloc( 1000 );
969                     memset( psz_type, 0, 1000 );
970                     for( i=0; p_item->ppsz_list[i]; i++ )
971                     {
972                         strcat( psz_type, p_item->ppsz_list[i] );
973                         strcat( psz_type, "|" );
974                     }
975                     psz_type[ strlen( psz_type ) - 1 ] = '\0';
976                     psz_ket = "]";
977                     break;
978                 }
979             case CONFIG_ITEM_INTEGER:
980                 psz_bra = " <"; psz_type = _("integer"); psz_ket = ">";
981                 break;
982             case CONFIG_ITEM_FLOAT:
983                 psz_bra = " <"; psz_type = _("float"); psz_ket = ">";
984                 break;
985             case CONFIG_ITEM_BOOL:
986                 psz_bra = ""; psz_type = ""; psz_ket = "";
987                 if( !b_help_module )
988                 {
989                     psz_suf = p_item->i_value ? _(" (default enabled)") :
990                                                 _(" (default disabled)");
991                 }
992                 break;
993             }
994
995             /* Add short option */
996             if( p_item->i_short )
997             {
998                 psz_format[2] = '-';
999                 psz_format[3] = p_item->i_short;
1000                 psz_format[4] = ',';
1001             }
1002             else
1003             {
1004                 psz_format[2] = ' ';
1005                 psz_format[3] = ' ';
1006                 psz_format[4] = ' ';
1007             }
1008
1009             if( psz_type )
1010             {
1011                 i = PADDING_SPACES - strlen( p_item->psz_name )
1012                      - strlen( psz_bra ) - strlen( psz_type )
1013                      - strlen( psz_ket ) - 1;
1014                 if( p_item->i_type == CONFIG_ITEM_BOOL
1015                      && !b_help_module )
1016                 {
1017                     vlc_bool_t b_dash = VLC_FALSE;
1018                     psz_prefix = p_item->psz_name;
1019                     while( *psz_prefix )
1020                     {
1021                         if( *psz_prefix++ == '-' )
1022                         {
1023                             b_dash = VLC_TRUE;
1024                             break;
1025                         }
1026                     }
1027
1028                     if( b_dash )
1029                     {
1030                         psz_prefix = ", --no-";
1031                         i -= strlen( p_item->psz_name ) + strlen( ", --no-" );
1032                     }
1033                     else
1034                     {
1035                         psz_prefix = ", --no";
1036                         i -= strlen( p_item->psz_name ) + strlen( ", --no" );
1037                     }
1038                 }
1039
1040                 if( i < 0 )
1041                 {
1042                     i = 0;
1043                     psz_spaces[i] = '\n';
1044                 }
1045                 else
1046                 {
1047                     psz_spaces[i] = '\0';
1048                 }
1049
1050                 if( p_item->i_type == CONFIG_ITEM_BOOL &&
1051                     !b_help_module )
1052                 {
1053                     fprintf( stderr, psz_format, p_item->psz_name, psz_prefix,
1054                              p_item->psz_name, psz_bra, psz_type, psz_ket,
1055                              psz_spaces, p_item->psz_text, psz_suf );
1056                 }
1057                 else
1058                 {
1059                     fprintf( stderr, psz_format, p_item->psz_name, "", "",
1060                              psz_bra, psz_type, psz_ket, psz_spaces,
1061                              p_item->psz_text, psz_suf );
1062                 }
1063                 psz_spaces[i] = ' ';
1064                 if ( p_item->ppsz_list )
1065                 {
1066                     free( psz_type );
1067                 }
1068             }
1069         }
1070
1071         fprintf( stderr, "\n" );
1072
1073     }
1074
1075 #ifdef WIN32        /* Pause the console because it's destroyed when we exit */
1076         fprintf( stderr, _("\nPress the RETURN key to continue...\n") );
1077         getchar();
1078 #endif
1079 }
1080
1081 /*****************************************************************************
1082  * ListModules: list the available modules with their description
1083  *****************************************************************************
1084  * Print a list of all available modules (builtins and plugins) and a short
1085  * description for each one.
1086  *****************************************************************************/
1087 static void ListModules( vlc_t *p_this )
1088 {
1089     module_t *p_module;
1090     char psz_spaces[22];
1091
1092     memset( psz_spaces, ' ', 22 );
1093
1094 #ifdef WIN32
1095     ShowConsole();
1096 #endif
1097
1098     /* Usage */
1099     fprintf( stderr, _("Usage: %s [options] [parameters] [file]...\n\n"),
1100                      p_this->p_vlc->psz_object_name );
1101
1102     fprintf( stderr, _("[module]              [description]\n") );
1103
1104     /* Enumerate each module */
1105     for( p_module = p_this->p_vlc->p_module_bank->first ;
1106          p_module != NULL ;
1107          p_module = p_module->next )
1108     {
1109         int i;
1110
1111         /* Nasty hack, but right now I'm too tired to think about a nice
1112          * solution */
1113         i = 22 - strlen( p_module->psz_object_name ) - 1;
1114         if( i < 0 ) i = 0;
1115         psz_spaces[i] = 0;
1116
1117         fprintf( stderr, "  %s%s %s\n", p_module->psz_object_name, psz_spaces,
1118                   p_module->psz_longname );
1119
1120         psz_spaces[i] = ' ';
1121
1122     }
1123
1124 #ifdef WIN32        /* Pause the console because it's destroyed when we exit */
1125         fprintf( stderr, _("\nPress the RETURN key to continue...\n") );
1126         getchar();
1127 #endif
1128 }
1129
1130 /*****************************************************************************
1131  * Version: print complete program version
1132  *****************************************************************************
1133  * Print complete program version and build number.
1134  *****************************************************************************/
1135 static void Version( void )
1136 {
1137 #ifdef WIN32
1138     ShowConsole();
1139 #endif
1140
1141     fprintf( stderr, VERSION_MESSAGE "\n" );
1142     fprintf( stderr,
1143       _("This program comes with NO WARRANTY, to the extent permitted by "
1144         "law.\nYou may redistribute it under the terms of the GNU General "
1145         "Public License;\nsee the file named COPYING for details.\n"
1146         "Written by the VideoLAN team at Ecole Centrale, Paris.\n") );
1147
1148 #ifdef WIN32        /* Pause the console because it's destroyed when we exit */
1149     fprintf( stderr, _("\nPress the RETURN key to continue...\n") );
1150     getchar();
1151 #endif
1152 }
1153
1154 /*****************************************************************************
1155  * ShowConsole: On Win32, create an output console for debug messages
1156  *****************************************************************************
1157  * This function is useful only on Win32.
1158  *****************************************************************************/
1159 #ifdef WIN32 /*  */
1160 static void ShowConsole( void )
1161 {
1162     AllocConsole();
1163     freopen( "CONOUT$", "w", stdout );
1164     freopen( "CONOUT$", "w", stderr );
1165     freopen( "CONIN$", "r", stdin );
1166     return;
1167 }
1168 #endif
1169
1170 #ifndef WIN32
1171 /*****************************************************************************
1172  * InitSignalHandler: system signal handler initialization
1173  *****************************************************************************
1174  * Set the signal handlers. SIGTERM is not intercepted, because we need at
1175  * at least a method to kill the program when all other methods failed, and
1176  * when we don't want to use SIGKILL.
1177  *****************************************************************************/
1178 static void InitSignalHandler( void )
1179 {
1180     /* Termination signals */
1181     signal( SIGINT,  FatalSignalHandler );
1182     signal( SIGHUP,  FatalSignalHandler );
1183     signal( SIGQUIT, FatalSignalHandler );
1184
1185     /* Other signals */
1186     signal( SIGALRM, SimpleSignalHandler );
1187     signal( SIGPIPE, SimpleSignalHandler );
1188 }
1189
1190 /*****************************************************************************
1191  * SimpleSignalHandler: system signal handler
1192  *****************************************************************************
1193  * This function is called when a non fatal signal is received by the program.
1194  *****************************************************************************/
1195 static void SimpleSignalHandler( int i_signal )
1196 {
1197     int i_index;
1198
1199     /* Acknowledge the signal received and warn all the p_vlc structures */
1200     vlc_mutex_lock( &global_lock );
1201     for( i_index = 0 ; i_index < i_vlc ; i_index++ )
1202     {
1203         msg_Warn( pp_vlc[ i_index ], "ignoring signal %d", i_signal );
1204     }
1205     vlc_mutex_unlock( &global_lock );
1206 }
1207
1208 /*****************************************************************************
1209  * FatalSignalHandler: system signal handler
1210  *****************************************************************************
1211  * This function is called when a fatal signal is received by the program.
1212  * It tries to end the program in a clean way.
1213  *****************************************************************************/
1214 static void FatalSignalHandler( int i_signal )
1215 {
1216     static mtime_t abort_time = 0;
1217     static volatile vlc_bool_t b_die = VLC_FALSE;
1218     int i_index;
1219
1220     /* Once a signal has been trapped, the termination sequence will be
1221      * armed and following signals will be ignored to avoid sending messages
1222      * to an interface having been destroyed */
1223
1224     if( !b_die )
1225     {
1226         b_die = VLC_TRUE;
1227         abort_time = mdate();
1228
1229         fprintf( stderr, "signal %d received, terminating libvlc - do it "
1230                          "again in case your process gets stuck\n", i_signal );
1231
1232         /* Try to terminate everything - this is done by requesting the end of
1233          * all the p_vlc structures */
1234         for( i_index = 0 ; i_index < i_vlc ; i_index++ )
1235         {
1236             /* Acknowledge the signal received */
1237             pp_vlc[ i_index ]->b_die = VLC_TRUE;
1238         }
1239     }
1240     else if( mdate() > abort_time + 1000000 )
1241     {
1242         /* If user asks again 1 second later, die badly */
1243         signal( SIGINT,  SIG_IGN );
1244         signal( SIGHUP,  SIG_IGN );
1245         signal( SIGQUIT, SIG_IGN );
1246
1247         fprintf( stderr, "user insisted too much, dying badly\n" );
1248
1249         exit( 1 );
1250     }
1251 }
1252 #endif
1253