📄 modules.c
字号:
/***************************************************************************** * modules.c : Builtin and plugin modules management functions ***************************************************************************** * Copyright (C) 2001-2007 the VideoLAN team * $Id: 9ff601b3a6aa5916a564b14758292fdc99d412df $ * * Authors: Sam Hocevar <sam@zoy.org> * Ethan C. Baldridge <BaldridgeE@cadmus.com> * Hans-Peter Jansen <hpj@urpla.net> * Gildas Bazin <gbazin@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. *****************************************************************************/#ifdef HAVE_CONFIG_H# include "config.h"#endif#include <vlc_common.h>#include <vlc_plugin.h>#include "libvlc.h"/* Some faulty libcs have a broken struct dirent when _FILE_OFFSET_BITS * is set to 64. Don't try to be cleverer. */#ifdef _FILE_OFFSET_BITS#undef _FILE_OFFSET_BITS#endif#include <stdlib.h> /* free(), strtol() */#include <stdio.h> /* sprintf() */#include <string.h> /* strdup() */#include <assert.h>#ifdef HAVE_DIRENT_H# include <dirent.h>#endif#ifdef HAVE_SYS_TYPES_H# include <sys/types.h>#endif#ifdef HAVE_SYS_STAT_H# include <sys/stat.h>#endif#ifdef HAVE_UNISTD_H# include <unistd.h>#endif#if !defined(HAVE_DYNAMIC_PLUGINS) /* no support for plugins */#elif defined(HAVE_DL_DYLD)# if defined(HAVE_MACH_O_DYLD_H)# include <mach-o/dyld.h># endif#elif defined(HAVE_DL_BEOS)# if defined(HAVE_IMAGE_H)# include <image.h># endif#elif defined(HAVE_DL_WINDOWS)# include <windows.h>#elif defined(HAVE_DL_DLOPEN)# if defined(HAVE_DLFCN_H) /* Linux, BSD, Hurd */# include <dlfcn.h># endif# if defined(HAVE_SYS_DL_H)# include <sys/dl.h># endif#elif defined(HAVE_DL_SHL_LOAD)# if defined(HAVE_DL_H)# include <dl.h># endif#endif#include "config/configuration.h"#include "vlc_charset.h"#include "vlc_arrays.h"#include "modules/modules.h"#include "modules/builtin.h"/***************************************************************************** * Local prototypes *****************************************************************************/#ifdef HAVE_DYNAMIC_PLUGINSstatic void AllocateAllPlugins ( vlc_object_t * );static void AllocatePluginDir ( vlc_object_t *, const char *, int );static int AllocatePluginFile ( vlc_object_t *, char *, int64_t, int64_t );static module_t * AllocatePlugin( vlc_object_t *, char * );#endifstatic int AllocateBuiltinModule( vlc_object_t *, int ( * ) ( module_t * ) );static void DeleteModule ( module_t *, bool );#ifdef HAVE_DYNAMIC_PLUGINSstatic void DupModule ( module_t * );static void UndupModule ( module_t * );#endif/** * Init bank * * Creates a module bank structure which will be filled later * on with all the modules found. * \param p_this vlc object structure * \return nothing */void __module_InitBank( vlc_object_t *p_this ){ module_bank_t *p_bank = NULL; libvlc_global_data_t *p_libvlc_global = vlc_global(); vlc_mutex_t *lock = var_AcquireMutex( "libvlc" ); if( p_libvlc_global->p_module_bank == NULL ) { p_bank = vlc_custom_create( p_this, sizeof(module_bank_t), VLC_OBJECT_GENERIC, "module bank"); p_bank->i_usage = 1; p_bank->i_cache = p_bank->i_loaded_cache = 0; p_bank->pp_cache = p_bank->pp_loaded_cache = NULL; p_bank->b_cache = p_bank->b_cache_dirty = p_bank->b_cache_delete = false; /* Everything worked, attach the object */ p_libvlc_global->p_module_bank = p_bank; vlc_object_attach( p_bank, p_libvlc_global ); /* Fills the module bank structure with the main module infos. * This is very useful as it will allow us to consider the main * library just as another module, and for instance the configuration * options of main will be available in the module bank structure just * as for every other module. */ AllocateBuiltinModule( p_this, vlc_entry__main ); } else p_libvlc_global->p_module_bank->i_usage++; vlc_mutex_unlock( lock );}/** * End bank * * Unloads all unused plugin modules and empties the module * bank in case of success. * \param p_this vlc object structure * \return nothing */void __module_EndBank( vlc_object_t *p_this ){ module_t * p_next = NULL; libvlc_global_data_t *p_libvlc_global = vlc_global(); vlc_mutex_t *lock = var_AcquireMutex( "libvlc" ); if( !p_libvlc_global->p_module_bank ) { vlc_mutex_unlock( lock ); return; } if( --p_libvlc_global->p_module_bank->i_usage ) { vlc_mutex_unlock( lock ); return; } vlc_mutex_unlock( lock ); /* Save the configuration */ config_AutoSaveConfigFile( p_this );#ifdef HAVE_DYNAMIC_PLUGINS# define p_bank p_libvlc_global->p_module_bank if( p_bank->b_cache ) CacheSave( p_this ); while( p_bank->i_loaded_cache-- ) { if( p_bank->pp_loaded_cache[p_bank->i_loaded_cache] ) { DeleteModule( p_bank->pp_loaded_cache[p_bank->i_loaded_cache]->p_module, p_bank->pp_loaded_cache[p_bank->i_loaded_cache]->b_used ); free( p_bank->pp_loaded_cache[p_bank->i_loaded_cache]->psz_file ); free( p_bank->pp_loaded_cache[p_bank->i_loaded_cache] ); p_bank->pp_loaded_cache[p_bank->i_loaded_cache] = NULL; } } if( p_bank->pp_loaded_cache ) { free( p_bank->pp_loaded_cache ); p_bank->pp_loaded_cache = NULL; } while( p_bank->i_cache-- ) { free( p_bank->pp_cache[p_bank->i_cache]->psz_file ); free( p_bank->pp_cache[p_bank->i_cache] ); p_bank->pp_cache[p_bank->i_cache] = NULL; } if( p_bank->pp_cache ) { free( p_bank->pp_cache ); p_bank->pp_cache = NULL; }# undef p_bank#endif vlc_object_detach( p_libvlc_global->p_module_bank ); while( vlc_internals( p_libvlc_global->p_module_bank )->i_children ) { p_next = (module_t *)vlc_internals( p_libvlc_global->p_module_bank )->pp_children[0]; DeleteModule( p_next, true ); } vlc_object_release( p_libvlc_global->p_module_bank ); p_libvlc_global->p_module_bank = NULL;}/** * Load all modules which we built with. * * Fills the module bank structure with the builtin modules. * \param p_this vlc object structure * \return nothing */void __module_LoadBuiltins( vlc_object_t * p_this ){ libvlc_global_data_t *p_libvlc_global = vlc_global(); vlc_mutex_t *lock = var_AcquireMutex( "libvlc" ); if( p_libvlc_global->p_module_bank->b_builtins ) { vlc_mutex_unlock( lock ); return; } p_libvlc_global->p_module_bank->b_builtins = true; vlc_mutex_unlock( lock ); msg_Dbg( p_this, "checking builtin modules" ); ALLOCATE_ALL_BUILTINS();}/** * Load all plugins * * Load all plugin modules we can find. * Fills the module bank structure with the plugin modules. * \param p_this vlc object structure * \return nothing */void __module_LoadPlugins( vlc_object_t * p_this ){#ifdef HAVE_DYNAMIC_PLUGINS libvlc_global_data_t *p_libvlc_global = vlc_global(); vlc_mutex_t *lock = var_AcquireMutex( "libvlc" ); if( p_libvlc_global->p_module_bank->b_plugins ) { vlc_mutex_unlock( lock ); return; } p_libvlc_global->p_module_bank->b_plugins = true; vlc_mutex_unlock( lock ); msg_Dbg( p_this, "checking plugin modules" ); if( config_GetInt( p_this, "plugins-cache" ) ) p_libvlc_global->p_module_bank->b_cache = true; if( p_libvlc_global->p_module_bank->b_cache || p_libvlc_global->p_module_bank->b_cache_delete ) CacheLoad( p_this ); AllocateAllPlugins( p_this );#endif}/** * Checks whether a module implements a capability. * * \param m the module * \param cap the capability to check * \return TRUE if the module have the capability */bool module_IsCapable( const module_t *m, const char *cap ){ return !strcmp( m->psz_capability, cap );}/** * Get the internal name of a module * * \param m the module * \return the module name */const char *module_GetObjName( const module_t *m ){ return m->psz_object_name;}/** * Get the human-friendly name of a module. * * \param m the module * \param long_name TRUE to have the long name of the module * \return the short or long name of the module */const char *module_GetName( const module_t *m, bool long_name ){ if( long_name && ( m->psz_longname != NULL) ) return m->psz_longname; return m->psz_shortname ?: m->psz_object_name;}/** * Get the help for a module * * \param m the module * \return the help */const char *module_GetHelp( const module_t *m ){ return m->psz_help;}/** * module Need * * Return the best module function, given a capability list. * \param p_this the vlc object * \param psz_capability list of capabilities needed * \param psz_name name of the module asked * \param b_strict TRUE yto use the strict mode * \return the module or NULL in case of a failure */module_t * __module_Need( vlc_object_t *p_this, const char *psz_capability, const char *psz_name, bool b_strict ){ typedef struct module_list_t module_list_t; stats_TimerStart( p_this, "module_Need()", STATS_TIMER_MODULE_NEED ); struct module_list_t { module_t *p_module; int i_score; bool b_force; module_list_t *p_next; }; module_list_t *p_list, *p_first, *p_tmp; vlc_list_t *p_all; int i_which_module, i_index = 0; module_t *p_module; int i_shortcuts = 0; char *psz_shortcuts = NULL, *psz_var = NULL, *psz_alias = NULL; bool b_force_backup = p_this->b_force; /* Deal with variables */ if( psz_name && psz_name[0] == '$' ) { psz_name = psz_var = var_CreateGetString( p_this, psz_name + 1 ); } /* Count how many different shortcuts were asked for */ if( psz_name && *psz_name ) { char *psz_parser, *psz_last_shortcut; /* If the user wants none, give him none. */ if( !strcmp( psz_name, "none" ) ) { free( psz_var ); stats_TimerStop( p_this, STATS_TIMER_MODULE_NEED ); stats_TimerDump( p_this, STATS_TIMER_MODULE_NEED ); stats_TimerClean( p_this, STATS_TIMER_MODULE_NEED ); return NULL; } i_shortcuts++; psz_shortcuts = psz_last_shortcut = strdup( psz_name ); for( psz_parser = psz_shortcuts; *psz_parser; psz_parser++ ) { if( *psz_parser == ',' ) { *psz_parser = '\0'; i_shortcuts++; psz_last_shortcut = psz_parser + 1; } } /* Check if the user wants to override the "strict" mode */ if( psz_last_shortcut ) { if( !strcmp(psz_last_shortcut, "none") ) { b_strict = true; i_shortcuts--; } else if( !strcmp(psz_last_shortcut, "any") ) { b_strict = false; i_shortcuts--; } } } /* Sort the modules and test them */ p_all = vlc_list_find( p_this, VLC_OBJECT_MODULE, FIND_ANYWHERE ); p_list = malloc( p_all->i_count * sizeof( module_list_t ) ); p_first = NULL; unsigned i_cpu = vlc_CPU(); /* Parse the module list for capabilities and probe each of them */ for( i_which_module = 0; i_which_module < p_all->i_count; i_which_module++ ) { int i_shortcut_bonus = 0; p_module = (module_t *)p_all->p_values[i_which_module].p_object; /* Test that this module can do what we need */ if( !module_IsCapable( p_module, psz_capability ) ) { /* Don't recurse through the sub-modules because vlc_list_find() * will list them anyway. */ continue; } /* Test if we have the required CPU */ if( (p_module->i_cpu & i_cpu) != p_module->i_cpu ) { continue; } /* If we required a shortcut, check this plugin provides it. */ if( i_shortcuts > 0 ) { bool b_trash; const char *psz_name = psz_shortcuts; /* Let's drop modules with a <= 0 score (unless they are * explicitly requested) */ b_trash = p_module->i_score <= 0; for( unsigned i_short = i_shortcuts; i_short > 0; i_short-- ) { for( unsigned i = 0; p_module->pp_shortcuts[i]; i++ ) { char *c; if( ( c = strchr( psz_name, '@' ) ) ? !strncasecmp( psz_name, p_module->pp_shortcuts[i], c-psz_name ) : !strcasecmp( psz_name, p_module->pp_shortcuts[i] ) ) { /* Found it */ if( c && c[1] )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -