Commit e9947bec authored by Clément Stenac's avatar Clément Stenac

Split libvlc.c:

* instances creation/deletion stuff to libvlc-common.c
* implementation of the old libvlc API to libvlc.c
parent fcfc11bd
......@@ -31,6 +31,21 @@ extern "C" {
#include <vlc/vlc.h>
/***************************************************************************
* Internal creation and destruction functions
***************************************************************************/
libvlc_int_t *libvlc_InternalCreate();
int libvlc_InternalInit( libvlc_int_t *, int, char *ppsz_argv[] );
int libvlc_InternalCleanup( libvlc_int_t * );
int libvlc_InternalDestroy( libvlc_int_t *, vlc_bool_t );
int libvlc_InternalAddIntf( libvlc_int_t *, char const *, vlc_bool_t,
vlc_bool_t, int, char ** );
/***************************************************************************
* Opaque structures for libvlc API
***************************************************************************/
struct libvlc_instance_t
{
libvlc_int_t *p_libvlc_int;
......
......@@ -252,6 +252,7 @@ SOURCES_libvlc_getopt = \
SOURCES_libvlc_common = \
libvlc.c \
libvlc-common.c \
libvlc.h \
interface/interface.c \
interface/intf_eject.c \
......
/*****************************************************************************
* libvlc-common.c: libvlc instances creation and deletion
*****************************************************************************
* Copyright (C) 1998-2006 the VideoLAN team
* $Id$
*
* Authors: Vincent Seguin <seguin@via.ecp.fr>
* Samuel Hocevar <sam@zoy.org>
* Gildas Bazin <gbazin@videolan.org>
* Derk-Jan Hartman <hartman at videolan dot org>
* Rémi Denis-Courmont <rem # videolan : org>
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* 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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
/** \file
* This file contains functions to create and destroy libvlc instances
*/
/*****************************************************************************
* Pretend we are a builtin module
*****************************************************************************/
#define MODULE_NAME main
#define MODULE_PATH main
#define __BUILTIN__
/*****************************************************************************
* Preamble
*****************************************************************************/
#include <vlc/vlc.h>
#include <libvlc_internal.h>
#include <vlc/input.h>
#include <errno.h> /* ENOMEM */
#include <stdio.h> /* sprintf() */
#include <string.h> /* strerror() */
#include <stdlib.h> /* free() */
#ifndef WIN32
# include <netinet/in.h> /* BSD: struct in_addr */
#endif
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#elif defined( WIN32 ) && !defined( UNDER_CE )
# include <io.h>
#endif
#ifdef WIN32 /* optind, getopt(), included in unistd.h */
# include "extras/getopt.h"
#endif
#ifdef HAVE_LOCALE_H
# include <locale.h>
#endif
#ifdef HAVE_HAL
# include <hal/libhal.h>
#endif
#include "vlc_cpu.h" /* CPU detection */
#include "os_specific.h"
#include "vlc_error.h"
#include "vlc_playlist.h"
#include "vlc_interface.h"
#include "audio_output.h"
#include "vlc_video.h"
#include "video_output.h"
#include "stream_output.h"
#include "charset.h"
#include "libvlc.h"
/*****************************************************************************
* The evil global variable. We handle it with care, don't worry.
*****************************************************************************/
static libvlc_global_data_t libvlc_global;
static libvlc_global_data_t * p_libvlc_global;
static libvlc_int_t * p_static_vlc;
/*****************************************************************************
* Local prototypes
*****************************************************************************/
void LocaleInit( vlc_object_t * );
void LocaleDeinit( void );
static void SetLanguage ( char const * );
static int GetFilenames ( libvlc_int_t *, int, char *[] );
static void Help ( libvlc_int_t *, char const *psz_help_name );
static void Usage ( libvlc_int_t *, char const *psz_module_name );
static void ListModules ( libvlc_int_t * );
static void Version ( void );
#ifdef WIN32
static void ShowConsole ( vlc_bool_t );
static void PauseConsole ( void );
#endif
static int ConsoleWidth ( void );
static int VerboseCallback( vlc_object_t *, char const *,
vlc_value_t, vlc_value_t, void * );
static void InitDeviceValues( libvlc_int_t * );
/*****************************************************************************
* vlc_current_object: return the current object.
*****************************************************************************
* If i_object is non-zero, return the corresponding object. Otherwise,
* return the statically allocated p_vlc object.
*****************************************************************************/
libvlc_int_t * vlc_current_object( int i_object )
{
if( i_object )
{
return vlc_object_get( p_libvlc_global, i_object );
}
return p_static_vlc;
}
/**
* Allocate a libvlc instance, initialize global data if needed
* It also initializes the threading system
*/
libvlc_int_t * libvlc_InternalCreate( void )
{
int i_ret;
libvlc_int_t * p_libvlc = NULL;
vlc_value_t lockval;
/* &libvlc_global never changes,
* so we can safely call this multiple times. */
p_libvlc_global = &libvlc_global;
/* vlc_threads_init *must* be the first internal call! No other call is
* allowed before the thread system has been initialized. */
i_ret = vlc_threads_init( p_libvlc_global );
if( i_ret < 0 ) return NULL;
/* Now that the thread system is initialized, we don't have much, but
* at least we have var_Create */
var_Create( p_libvlc_global, "libvlc", VLC_VAR_MUTEX );
var_Get( p_libvlc_global, "libvlc", &lockval );
vlc_mutex_lock( lockval.p_address );
if( !libvlc_global.b_ready )
{
char *psz_env;
/* Guess what CPU we have */
libvlc_global.i_cpu = CPUCapabilities();
/* Find verbosity from VLC_VERBOSE environment variable */
psz_env = getenv( "VLC_VERBOSE" );
libvlc_global.i_verbose = psz_env ? atoi( psz_env ) : -1;
#if defined( HAVE_ISATTY ) && !defined( WIN32 )
libvlc_global.b_color = isatty( 2 ); /* 2 is for stderr */
#else
libvlc_global.b_color = VLC_FALSE;
#endif
/* Initialize message queue */
msg_Create( p_libvlc_global );
/* Announce who we are */
msg_Dbg( p_libvlc_global, COPYRIGHT_MESSAGE );
msg_Dbg( p_libvlc_global, "libvlc was configured with %s",
CONFIGURE_LINE );
/* The module bank will be initialized later */
libvlc_global.p_module_bank = NULL;
libvlc_global.b_ready = VLC_TRUE;
}
vlc_mutex_unlock( lockval.p_address );
var_Destroy( p_libvlc_global, "libvlc" );
/* Allocate a libvlc instance object */
p_libvlc = vlc_object_create( p_libvlc_global, VLC_OBJECT_LIBVLC );
if( p_libvlc == NULL ) return NULL;
p_libvlc->thread_id = 0;
p_libvlc->p_playlist = NULL;
p_libvlc->psz_object_name = "libvlc";
/* Initialize mutexes */
vlc_mutex_init( p_libvlc, &p_libvlc->config_lock );
#ifdef __APPLE__
vlc_mutex_init( p_libvlc, &p_libvlc->quicktime_lock );
vlc_thread_set_priority( p_libvlc, VLC_THREAD_PRIORITY_LOW );
#endif
/* Store our newly allocated structure in the global list */
vlc_object_attach( p_libvlc, p_libvlc_global );
/* Store data for the non-reentrant API */
p_static_vlc = p_libvlc;
return p_libvlc;
}
/**
* Initialize a libvlc instance
* This function initializes a previously allocated libvlc instance:
* - CPU detection
* - gettext initialization
* - message queue, module bank and playlist initialization
* - configuration and commandline parsing
*/
int libvlc_InternalInit( libvlc_int_t *p_libvlc, int i_argc, char *ppsz_argv[] )
{
char p_capabilities[200];
char * p_tmp;
char * psz_modules;
char * psz_parser;
char * psz_control;
vlc_bool_t b_exit = VLC_FALSE;
int i_ret = VLC_EEXIT;
module_t *p_help_module;
playlist_t *p_playlist;
vlc_value_t val;
#if defined( ENABLE_NLS ) \
&& ( defined( HAVE_GETTEXT ) || defined( HAVE_INCLUDED_GETTEXT ) )
# if defined (WIN32) || defined (__APPLE__)
char * psz_language;
#endif
#endif
/* System specific initialization code */
system_Init( p_libvlc, &i_argc, ppsz_argv );
/* Get the executable name (similar to the basename command) */
if( i_argc > 0 )
{
p_libvlc->psz_object_name = p_tmp = ppsz_argv[ 0 ];
while( *p_tmp )
{
if( *p_tmp == '/' ) p_libvlc->psz_object_name = ++p_tmp;
else ++p_tmp;
}
}
else
{
p_libvlc->psz_object_name = "vlc";
}
/*
* Support for gettext
*/
SetLanguage( "" );
/*
* Global iconv, must be done after setlocale()
* so that vlc_current_charset() works.
*/
LocaleInit( (vlc_object_t *)p_libvlc );
/* Translate "C" to the language code: "fr", "en_GB", "nl", "ru"... */
msg_Dbg( p_libvlc, "translation test: code is \"%s\"", _("C") );
/* Initialize the module bank and load the configuration of the
* main module. We need to do this at this stage to be able to display
* a short help if required by the user. (short help == main module
* options) */
module_InitBank( p_libvlc );
/* Hack: insert the help module here */
p_help_module = vlc_object_create( p_libvlc, VLC_OBJECT_MODULE );
if( p_help_module == NULL )
{
module_EndBank( p_libvlc );
return VLC_EGENERIC;
}
p_help_module->psz_object_name = "help";
p_help_module->psz_longname = N_("Help options");
config_Duplicate( p_help_module, p_help_config );
vlc_object_attach( p_help_module, libvlc_global.p_module_bank );
/* End hack */
if( config_LoadCmdLine( p_libvlc, &i_argc, ppsz_argv, VLC_TRUE ) )
{
vlc_object_detach( p_help_module );
config_Free( p_help_module );
vlc_object_destroy( p_help_module );
module_EndBank( p_libvlc );
return VLC_EGENERIC;
}
/* Check for short help option */
if( config_GetInt( p_libvlc, "help" ) )
{
Help( p_libvlc, "help" );
b_exit = VLC_TRUE;
i_ret = VLC_EEXITSUCCESS;
}
/* Check for version option */
else if( config_GetInt( p_libvlc, "version" ) )
{
Version();
b_exit = VLC_TRUE;
i_ret = VLC_EEXITSUCCESS;
}
/* Set the config file stuff */
p_libvlc->psz_homedir = config_GetHomeDir();
p_libvlc->psz_userdir = config_GetUserDir();
if( p_libvlc->psz_userdir == NULL )
p_libvlc->psz_userdir = strdup(p_libvlc->psz_homedir);
p_libvlc->psz_configfile = config_GetPsz( p_libvlc, "config" );
if( p_libvlc->psz_configfile != NULL && p_libvlc->psz_configfile[0] == '~'
&& p_libvlc->psz_configfile[1] == '/' )
{
char *psz = malloc( strlen(p_libvlc->psz_userdir)
+ strlen(p_libvlc->psz_configfile) );
/* This is incomplete : we should also support the ~cmassiot/ syntax. */
sprintf( psz, "%s/%s", p_libvlc->psz_userdir,
p_libvlc->psz_configfile + 2 );
free( p_libvlc->psz_configfile );
p_libvlc->psz_configfile = psz;
}
/* Check for plugins cache options */
if( config_GetInt( p_libvlc, "reset-plugins-cache" ) )
{
libvlc_global.p_module_bank->b_cache_delete = VLC_TRUE;
}
/* Hack: remove the help module here */
vlc_object_detach( p_help_module );
/* End hack */
/* Will be re-done properly later on */
p_libvlc->p_libvlc_global->i_verbose = config_GetInt( p_libvlc, "verbose" );
/* Check for daemon mode */
#ifndef WIN32
if( config_GetInt( p_libvlc, "daemon" ) )
{
#if HAVE_DAEMON
if( daemon( 1, 0) != 0 )
{
msg_Err( p_libvlc, "Unable to fork vlc to daemon mode" );
b_exit = VLC_TRUE;
}
p_libvlc->p_libvlc_global->b_daemon = VLC_TRUE;
/* lets check if we need to write the pidfile */
char * psz_pidfile = config_GetPsz( p_libvlc, "pidfile" );
if( psz_pidfile != NULL )
{
FILE *pidfile;
pid_t i_pid = getpid ();
msg_Dbg( p_libvlc, "PID is %d, writing it to %s",
i_pid, psz_pidfile );
pidfile = utf8_fopen( psz_pidfile,"w" );
if( pidfile != NULL )
{
utf8_fprintf( pidfile, "%d", (int)i_pid );
fclose( pidfile );
}
else
{
msg_Err( p_libvlc, "cannot open pid file for writing: %s (%s)",
psz_pidfile, strerror(errno) );
}
}
free( psz_pidfile );
#else
pid_t i_pid;
if( ( i_pid = fork() ) < 0 )
{
msg_Err( p_libvlc, "unable to fork vlc to daemon mode" );
b_exit = VLC_TRUE;
}
else if( i_pid )
{
/* This is the parent, exit right now */
msg_Dbg( p_libvlc, "closing parent process" );
b_exit = VLC_TRUE;
i_ret = VLC_EEXITSUCCESS;
}
else
{
/* We are the child */
msg_Dbg( p_libvlc, "daemon spawned" );
close( STDIN_FILENO );
close( STDOUT_FILENO );
close( STDERR_FILENO );
p_libvlc->p_libvlc_global->b_daemon = VLC_TRUE;
}
#endif
}
#endif
if( b_exit )
{
config_Free( p_help_module );
vlc_object_destroy( p_help_module );
module_EndBank( p_libvlc );
return i_ret;
}
/* Check for translation config option */
#if defined( ENABLE_NLS ) \
&& ( defined( HAVE_GETTEXT ) || defined( HAVE_INCLUDED_GETTEXT ) )
# if defined (WIN32) || defined (__APPLE__)
/* This ain't really nice to have to reload the config here but it seems
* the only way to do it. */
config_LoadConfigFile( p_libvlc, "main" );
config_LoadCmdLine( p_libvlc, &i_argc, ppsz_argv, VLC_TRUE );
/* Check if the user specified a custom language */
psz_language = config_GetPsz( p_libvlc, "language" );
if( psz_language && *psz_language && strcmp( psz_language, "auto" ) )
{
vlc_bool_t b_cache_delete = libvlc_global.p_module_bank->b_cache_delete;
/* Reset the default domain */
SetLanguage( psz_language );
/* Translate "C" to the language code: "fr", "en_GB", "nl", "ru"... */
msg_Dbg( p_libvlc, "translation test: code is \"%s\"", _("C") );
module_EndBank( p_libvlc );
module_InitBank( p_libvlc );
config_LoadConfigFile( p_libvlc, "main" );
config_LoadCmdLine( p_libvlc, &i_argc, ppsz_argv, VLC_TRUE );
libvlc_global.p_module_bank->b_cache_delete = b_cache_delete;
}
if( psz_language ) free( psz_language );
# endif
#endif
/*
* Load the builtins and plugins into the module_bank.
* We have to do it before config_Load*() because this also gets the
* list of configuration options exported by each module and loads their
* default values.
*/
module_LoadBuiltins( p_libvlc );
module_LoadPlugins( p_libvlc );
if( p_libvlc->b_die )
{
b_exit = VLC_TRUE;
}
msg_Dbg( p_libvlc, "module bank initialized, found %i modules",
libvlc_global.p_module_bank->i_children );
/* Hack: insert the help module here */
vlc_object_attach( p_help_module, libvlc_global.p_module_bank );
/* End hack */
/* Check for help on modules */
if( (p_tmp = config_GetPsz( p_libvlc, "module" )) )
{
Help( p_libvlc, p_tmp );
free( p_tmp );
b_exit = VLC_TRUE;
i_ret = VLC_EEXITSUCCESS;
}
/* Check for long help option */
else if( config_GetInt( p_libvlc, "longhelp" ) )
{
Help( p_libvlc, "longhelp" );
b_exit = VLC_TRUE;
i_ret = VLC_EEXITSUCCESS;
}
/* Check for module list option */
else if( config_GetInt( p_libvlc, "list" ) )
{
ListModules( p_libvlc );
b_exit = VLC_TRUE;
i_ret = VLC_EEXITSUCCESS;
}
/* Check for config file options */
if( config_GetInt( p_libvlc, "reset-config" ) )
{
vlc_object_detach( p_help_module );
config_ResetAll( p_libvlc );
config_LoadCmdLine( p_libvlc, &i_argc, ppsz_argv, VLC_TRUE );
config_SaveConfigFile( p_libvlc, NULL );
vlc_object_attach( p_help_module, libvlc_global.p_module_bank );
}
if( config_GetInt( p_libvlc, "save-config" ) )
{
vlc_object_detach( p_help_module );
config_LoadConfigFile( p_libvlc, NULL );
config_LoadCmdLine( p_libvlc, &i_argc, ppsz_argv, VLC_TRUE );
config_SaveConfigFile( p_libvlc, NULL );
vlc_object_attach( p_help_module, libvlc_global.p_module_bank );
}
/* Hack: remove the help module here */
vlc_object_detach( p_help_module );
/* End hack */
if( b_exit )
{
config_Free( p_help_module );
vlc_object_destroy( p_help_module );
module_EndBank( p_libvlc );
return i_ret;
}
/*
* Init device values
*/
InitDeviceValues( p_libvlc );
/*
* Override default configuration with config file settings
*/
config_LoadConfigFile( p_libvlc, NULL );
/* Hack: insert the help module here */
vlc_object_attach( p_help_module, libvlc_global.p_module_bank );
/* End hack */
/*
* Override configuration with command line settings
*/
if( config_LoadCmdLine( p_libvlc, &i_argc, ppsz_argv, VLC_FALSE ) )
{
#ifdef WIN32
ShowConsole( VLC_FALSE );
/* Pause the console because it's destroyed when we exit */
fprintf( stderr, "The command line options couldn't be loaded, check "
"that they are valid.\n" );
PauseConsole();
#endif
vlc_object_detach( p_help_module );
config_Free( p_help_module );
vlc_object_destroy( p_help_module );
module_EndBank( p_libvlc );
return VLC_EGENERIC;
}
/* Hack: remove the help module here */
vlc_object_detach( p_help_module );
config_Free( p_help_module );
vlc_object_destroy( p_help_module );
/* End hack */
/*
* System specific configuration
*/
system_Configure( p_libvlc, &i_argc, ppsz_argv );
/*
* Message queue options
*/
var_Create( p_libvlc, "verbose", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
if( config_GetInt( p_libvlc, "quiet" ) )
{
val.i_int = -1;
var_Set( p_libvlc, "verbose", val );
}
var_AddCallback( p_libvlc, "verbose", VerboseCallback, NULL );
var_Change( p_libvlc, "verbose", VLC_VAR_TRIGGER_CALLBACKS, NULL, NULL );
libvlc_global.b_color = libvlc_global.b_color &&
config_GetInt( p_libvlc, "color" );
/*
* Output messages that may still be in the queue
*/
msg_Flush( p_libvlc );
/* p_libvlc initialization. FIXME ? */
if( !config_GetInt( p_libvlc, "fpu" ) )
libvlc_global.i_cpu &= ~CPU_CAPABILITY_FPU;
#if defined( __i386__ ) || defined( __x86_64__ )
if( !config_GetInt( p_libvlc, "mmx" ) )
libvlc_global.i_cpu &= ~CPU_CAPABILITY_MMX;
if( !config_GetInt( p_libvlc, "3dn" ) )
libvlc_global.i_cpu &= ~CPU_CAPABILITY_3DNOW;
if( !config_GetInt( p_libvlc, "mmxext" ) )
libvlc_global.i_cpu &= ~CPU_CAPABILITY_MMXEXT;
if( !config_GetInt( p_libvlc, "sse" ) )
libvlc_global.i_cpu &= ~CPU_CAPABILITY_SSE;
if( !config_GetInt( p_libvlc, "sse2" ) )
libvlc_global.i_cpu &= ~CPU_CAPABILITY_SSE2;
#endif
#if defined( __powerpc__ ) || defined( __ppc__ ) || defined( __ppc64__ )
if( !config_GetInt( p_libvlc, "altivec" ) )
libvlc_global.i_cpu &= ~CPU_CAPABILITY_ALTIVEC;
#endif
#define PRINT_CAPABILITY( capability, string ) \
if( libvlc_global.i_cpu & capability ) \
{ \
strncat( p_capabilities, string " ", \
sizeof(p_capabilities) - strlen(p_capabilities) ); \
p_capabilities[sizeof(p_capabilities) - 1] = '\0'; \
}
p_capabilities[0] = '\0';
PRINT_CAPABILITY( CPU_CAPABILITY_486, "486" );
PRINT_CAPABILITY( CPU_CAPABILITY_586, "586" );
PRINT_CAPABILITY( CPU_CAPABILITY_PPRO, "Pentium Pro" );
PRINT_CAPABILITY( CPU_CAPABILITY_MMX, "MMX" );