举个例子来说明插件的加载,以核心插件为例,它在libvlc_new中执行,流程如下:
上图中的vlc_entry__core是一个函数指针,定义在modules.h中:
/** Core module */
int vlc_entry__core (int (*)(void *, void *, int, ...), void *);
那么vlc_entry__core 定义在哪里呢,为什么调用它会跳到libvlc_module.c的vlc_module_begin()那里,我们先来看下vlc_module_begin()的代码:
vlc_module_begin ()
set_category( CAT_AUDIO )
set_subcategory( SUBCAT_AUDIO_GENERAL )
add_category_hint( N_("Audio"), AOUT_CAT_LONGTEXT , false )
中间的设置非常多!!!
vlc_module_end ()
vlc_module_begin 实际上是一个宏,如下:
#define vlc_module_begin() \
EXTERN_SYMBOL DLL_SYMBOL \
int CDECL_SYMBOL __VLC_SYMBOL(vlc_entry) (vlc_set_cb, void *); \
EXTERN_SYMBOL DLL_SYMBOL \
int CDECL_SYMBOL __VLC_SYMBOL(vlc_entry) (vlc_set_cb vlc_set, void *opaque) \
{ \
module_t *module; \
module_config_t *config = NULL; \
if (vlc_plugin_set (VLC_MODULE_CREATE, &module)) \
goto error; \
if (vlc_module_set (VLC_MODULE_NAME, (MODULE_STRING))) \
goto error;
其中EXTERN_SYMBOL等大部分的宏展开其实都为空,把空的去掉是怎样的:
int __VLC_SYMBOL(vlc_entry) (vlc_set_cb, void *);
int __VLC_SYMBOL(vlc_entry) (vlc_set_cb vlc_set, void *opaque) \
{ \
module_t *module; \
module_config_t *config = NULL; \
if (vlc_plugin_set (VLC_MODULE_CREATE, &module)) \
goto error; \
if (vlc_module_set (VLC_MODULE_NAME, (MODULE_STRING))) \
goto error;
其中__VLC_SYMBOL为
#define CONCATENATE( y, z ) CRUDE_HACK( y, z )
#define CRUDE_HACK( y, z ) y##__##z
# define __VLC_SYMBOL( symbol ) CONCATENATE( symbol, MODULE_NAME )
而MODULE_NAME 为
#define MODULE_NAME core
看下全部展开:
int vlc_entry__core (vlc_set_cb, void *);
int vlc_entry__core (vlc_set_cb vlc_set, void *opaque) \
{ \
module_t *module; \
module_config_t *config = NULL; \
if (vlc_plugin_set (VLC_MODULE_CREATE, &module)) \
goto error; \
if (vlc_module_set (VLC_MODULE_NAME, (MODULE_STRING))) \
goto error;
这下应该明白了,vlc_module_begin实际上就是vlc_entry__core。
再看下vlc_module_end,这个比较简单:
#define vlc_module_end() \
(void) config; \
return 0; \
error: \
return -1; \
} \