obs模块化原理
2024-03-20
28
0
OBS是模块化设计,各个模块按照约定提供相应的导出函数,并且以DLL的形式存于模块所在的路径。
OBS加载模块时,每个模块分配一个obs_module结构体。
struct obs_module {
char *mod_name; //模块的名称
const char *file; //模块的文件名
char *bin_path; //dll完整路径
char *data_path; //资源数据路径
void *module; //HMODULE
bool loaded; //load函数的返回值
//dll导出的函数,未写名的为可选函数,写名的为必须存在的函数
bool (*load)(void); //函数名必须为obs_module_load
void (*unload)(void);
void (*post_load)(void);
void (*set_locale)(const char *locale);
bool (*get_string)(const char *lookup_string, const char **translated_string);
void (*free_locale)(void);
uint32_t (*ver)(void); //函数名必须为obs_module_ver
void (*set_pointer)(obs_module_t *module); //函数名必须为obs_module_set_pointer
const char *(*name)(void);
const char *(*description)(void);
const char *(*author)(void);
//下个模块,链表
struct obs_module *next;
};
使用函数load_module_exports解析导出函数。有些函数是必须的,有些函数是可选的。
static int load_module_exports(struct obs_module *mod, const char *path)
{
mod->load = os_dlsym(mod->module, "obs_module_load");
if (!mod->load)
return req_func_not_found("obs_module_load", path);
mod->set_pointer = os_dlsym(mod->module, "obs_module_set_pointer");
if (!mod->set_pointer)
return req_func_not_found("obs_module_set_pointer", path);
mod->ver = os_dlsym(mod->module, "obs_module_ver");
if (!mod->ver)
return req_func_not_found("obs_module_ver", path);
/* optional exports */
mod->unload = os_dlsym(mod->module, "obs_module_unload");
mod->post_load = os_dlsym(mod->module, "obs_module_post_load");
mod->set_locale = os_dlsym(mod->module, "obs_module_set_locale");
mod->free_locale = os_dlsym(mod->module, "obs_module_free_locale");
mod->name = os_dlsym(mod->module, "obs_module_name");
mod->description = os_dlsym(mod->module, "obs_module_description");
mod->author = os_dlsym(mod->module, "obs_module_author");
mod->get_string = os_dlsym(mod->module, "obs_module_get_string");
return MODULE_SUCCESS;
}
模块初始化时使用obs_open_module来初始化模块。
int obs_open_module(obs_module_t **module, const char *path,
const char *data_path)
{
struct obs_module mod = {0};
//Windows下本质为LoadLibray,不过为了处理DLL依赖的资源,需要设置SetDllDirectoryW
mod.module = os_dlopen(path);
if (!mod.module) {
blog(LOG_WARNING, "Module '%s' not loaded", path);
return MODULE_FILE_NOT_FOUND;
}
//加载导出函数
errorcode = load_module_exports(&mod, path);
if (errorcode != MODULE_SUCCESS)
return errorcode;
mod.bin_path = bstrdup(path);
mod.file = strrchr(mod.bin_path, '/');
mod.file = (!mod.file) ? mod.bin_path : (mod.file + 1);
mod.mod_name = get_module_name(mod.file);
mod.data_path = bstrdup(data_path);
mod.next = obs->first_module;
if (mod.file) {
blog(LOG_DEBUG, "Loading module: %s", mod.file);
}
*module = bmemdup(&mod, sizeof(mod));
obs->first_module = (*module);
mod.set_pointer(*module);
if (mod.set_locale)
mod.set_locale(obs->locale);
return MODULE_SUCCESS;
}
而obs_open_module则由load_all_callback函数实现:
static void load_all_callback(void *param, const struct obs_module_info2 *info)
{
...
int code = obs_open_module(&module, info->bin_path, info->data_path);
...
if (!obs_init_module(module))
free_module(module);
}
obs_init_module函数的功能就是调用obs_module结构体中导出的函数load。
调用顺序
- main
- run_program
- OBSBasic::OBSInit()
- obs_load_all_modules2
- obs_find_modules2(load_all_callback, &fail_info);
- obs_load_all_modules2
- OBSBasic::OBSInit()
- run_program
所以由obs_find_modules2扫描模块路径下的所有模块,并调用load_all_callback加载模块。