(API Change) Refactor module handling
Changed API: - char *obs_find_plugin_file(const char *sub_path); Changed to: char *obs_module_file(const char *file); Cahnge it so you no longer need to specify a sub-path such as: obs_find_plugin_file("module_name/file.ext") Instead, now automatically handle the module data path so all you need to do is: obs_module_file("file.ext") - int obs_load_module(const char *name); Changed to: int obs_open_module(obs_module_t *module, const char *path, const char *data_path); bool obs_init_module(obs_module_t module); Change the module loading API so that if the front-end chooses, it can load modules directly from a specified path, and associate a data directory with it on the spot. The module will not be initialized immediately; obs_init_module must be called on the module pointer in order to fully initialize the module. This is done so a module can be disabled by the front-end if the it so chooses. New API: - void obs_add_module_path(const char *bin, const char *data); These functions allow you to specify new module search paths to add, and allow you to search through them, or optionally just load all modules from them. If the string %module% is included, it will replace it with the module's name when that string is used as a lookup. Data paths are now directly added to the module's internal storage structure, and when obs_find_module_file is used, it will look up the pointer to the obs_module structure and get its data directory that way. Example: obs_add_module_path("/opt/obs/my-modules/%module%/bin", "/opt/obs/my-modules/%module%/data"); This would cause it to additionally look for the binary of a hypthetical module named "foo" at /opt/obs/my-modules/foo/bin/foo.so (or libfoo.so), and then look for the data in /opt/obs/my-modules/foo/data. This gives the front-end more flexibility for handling third-party plugin modules, or handling all plugin modules in a custom way. - void obs_find_modules(obs_find_module_callback_t callback, void *param); This searches the existing paths for modules and calls the callback function when any are found. Useful for plugin management and custom handling of the paths by the front-end if desired. - void obs_load_all_modules(void); Search through the paths and both loads and initializes all modules automatically without custom handling. - void obs_enum_modules(obs_enum_module_callback_t callback, void *param); Enumerates currently opened modules.master
parent
c2a0b9c00d
commit
59ea3becf2
|
@ -31,28 +31,23 @@ const char *get_module_extension(void)
|
|||
return ".so";
|
||||
}
|
||||
|
||||
// support both foo.so and libfoo.so for now
|
||||
static const char *plugin_patterns[] = {
|
||||
OBS_INSTALL_PREFIX "obs-plugins/%s.so",
|
||||
OBS_INSTALL_PREFIX "obs-plugins/lib%s.so",
|
||||
"../obs-plugins/%s.so",
|
||||
"../obs-plugins/lib%s.so"
|
||||
static const char *module_bin[] = {
|
||||
"../obs-plugins",
|
||||
OBS_INSTALL_PREFIX "obs-plugins",
|
||||
};
|
||||
|
||||
static const int plugin_patterns_size =
|
||||
sizeof(plugin_patterns)/sizeof(plugin_patterns[0]);
|
||||
static const char *module_data[] = {
|
||||
"../data/obs-plugins/%module%",
|
||||
OBS_INSTALL_DATA_PATH "obs-plugins/%module%",
|
||||
};
|
||||
|
||||
char *find_plugin(const char *plugin)
|
||||
static const int module_patterns_size =
|
||||
sizeof(module_bin)/sizeof(module_bin[0]);
|
||||
|
||||
void add_default_module_paths(void)
|
||||
{
|
||||
struct dstr path;
|
||||
dstr_init(&path);
|
||||
for(int i = 0; i < plugin_patterns_size; i++) {
|
||||
dstr_printf(&path, plugin_patterns[i], plugin);
|
||||
if(!access(path.array, F_OK))
|
||||
break;
|
||||
}
|
||||
|
||||
return path.array;
|
||||
for (int i = 0; i < module_patterns_size; i++)
|
||||
obs_add_module_path(module_bin[i], module_data[i]);
|
||||
}
|
||||
|
||||
char *find_libobs_data_file(const char *file)
|
||||
|
@ -63,14 +58,6 @@ char *find_libobs_data_file(const char *file)
|
|||
return path.array;
|
||||
}
|
||||
|
||||
char *obs_find_plugin_file(const char *file)
|
||||
{
|
||||
struct dstr path;
|
||||
dstr_init_copy(&path, OBS_INSTALL_DATA_PATH "/obs-plugins/");
|
||||
dstr_cat(&path, file);
|
||||
return path.array;
|
||||
}
|
||||
|
||||
static void log_processor_name(void)
|
||||
{
|
||||
char *name = NULL;
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "util/circlebuf.h"
|
||||
#include "util/dstr.h"
|
||||
#include "util/threading.h"
|
||||
#include "util/platform.h"
|
||||
#include "callback/signal.h"
|
||||
#include "callback/proc.h"
|
||||
|
||||
|
@ -50,13 +51,49 @@ struct draw_callback {
|
|||
/* modules */
|
||||
|
||||
struct obs_module {
|
||||
char *name;
|
||||
const char *file;
|
||||
char *bin_path;
|
||||
char *data_path;
|
||||
void *module;
|
||||
void (*set_locale)(const char *locale);
|
||||
bool loaded;
|
||||
|
||||
bool (*load)(uint32_t libobs_ver);
|
||||
void (*unload)(void);
|
||||
void (*set_locale)(const char *locale);
|
||||
void (*free_locale)(void);
|
||||
uint32_t (*ver)(void);
|
||||
void (*set_pointer)(obs_module_t module);
|
||||
const char *(*name)(void);
|
||||
const char *(*description)(void);
|
||||
const char *(*author)(void);
|
||||
|
||||
struct obs_module *next;
|
||||
};
|
||||
|
||||
extern void free_module(struct obs_module *mod);
|
||||
|
||||
struct obs_module_path {
|
||||
char *bin;
|
||||
char *data;
|
||||
};
|
||||
|
||||
static inline void free_module_path(struct obs_module_path *omp)
|
||||
{
|
||||
if (omp) {
|
||||
bfree(omp->bin);
|
||||
bfree(omp->data);
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool check_path(const char *data, const char *path,
|
||||
struct dstr *output)
|
||||
{
|
||||
dstr_copy(output, path);
|
||||
dstr_cat(output, data);
|
||||
|
||||
return os_file_exists(output->array);
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* views */
|
||||
|
@ -161,7 +198,9 @@ struct obs_core_data {
|
|||
};
|
||||
|
||||
struct obs_core {
|
||||
DARRAY(struct obs_module) modules;
|
||||
struct obs_module *first_module;
|
||||
DARRAY(struct obs_module_path) module_paths;
|
||||
|
||||
DARRAY(struct obs_source_info) input_types;
|
||||
DARRAY(struct obs_source_info) filter_types;
|
||||
DARRAY(struct obs_source_info) transition_types;
|
||||
|
|
|
@ -22,7 +22,6 @@
|
|||
#include "obs-internal.h"
|
||||
#include "obs-module.h"
|
||||
|
||||
extern char *find_plugin(const char *plugin);
|
||||
extern const char *get_module_extension(void);
|
||||
|
||||
static inline int req_func_not_found(const char *name, const char *path)
|
||||
|
@ -33,76 +32,313 @@ static inline int req_func_not_found(const char *name, const char *path)
|
|||
return MODULE_MISSING_EXPORTS;
|
||||
}
|
||||
|
||||
#define LOAD_REQ_SIZE_FUNC(func, module, path) \
|
||||
func = os_dlsym(module, #func); \
|
||||
if (!func) \
|
||||
return req_func_not_found(#func, path)
|
||||
|
||||
static int call_module_load(void *module, const char *path)
|
||||
static int load_module_exports(struct obs_module *mod, const char *path)
|
||||
{
|
||||
bool (*obs_module_load)(uint32_t obs_ver) = NULL;
|
||||
|
||||
obs_module_load = os_dlsym(module, "obs_module_load");
|
||||
if (!obs_module_load)
|
||||
mod->load = os_dlsym(mod->module, "obs_module_load");
|
||||
if (!mod->load)
|
||||
return req_func_not_found("obs_module_load", path);
|
||||
|
||||
if (!obs_module_load(LIBOBS_API_VER)) {
|
||||
blog(LOG_ERROR, "Module '%s' failed to load: "
|
||||
"obs_module_load failed", path);
|
||||
return MODULE_ERROR;
|
||||
}
|
||||
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->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");
|
||||
return MODULE_SUCCESS;
|
||||
}
|
||||
|
||||
int obs_load_module(const char *path)
|
||||
int obs_open_module(obs_module_t *module, const char *path,
|
||||
const char *data_path)
|
||||
{
|
||||
struct obs_module mod;
|
||||
char *plugin_path = find_plugin(path);
|
||||
struct obs_module mod = {0};
|
||||
int errorcode;
|
||||
|
||||
mod.module = os_dlopen(plugin_path);
|
||||
bfree(plugin_path);
|
||||
if (!module || !path || !obs)
|
||||
return MODULE_ERROR;
|
||||
|
||||
mod.module = os_dlopen(path);
|
||||
if (!mod.module) {
|
||||
blog(LOG_WARNING, "Module '%s' not found", path);
|
||||
return MODULE_FILE_NOT_FOUND;
|
||||
}
|
||||
|
||||
errorcode = call_module_load(mod.module, path);
|
||||
if (errorcode != MODULE_SUCCESS) {
|
||||
os_dlclose(mod.module);
|
||||
errorcode = load_module_exports(&mod, path);
|
||||
if (errorcode != MODULE_SUCCESS)
|
||||
return errorcode;
|
||||
}
|
||||
|
||||
mod.name = bstrdup(path);
|
||||
mod.set_locale = os_dlsym(mod.module, "obs_module_set_locale");
|
||||
mod.bin_path = bstrdup(path);
|
||||
mod.file = strrchr(mod.bin_path, '/');
|
||||
mod.file = (!mod.file) ? mod.bin_path : (mod.file + 1);
|
||||
mod.data_path = bstrdup(data_path);
|
||||
mod.next = obs->first_module;
|
||||
|
||||
*module = bmemdup(&mod, sizeof(mod));
|
||||
obs->first_module = (*module);
|
||||
mod.set_pointer(*module);
|
||||
|
||||
if (mod.set_locale)
|
||||
mod.set_locale(obs->locale);
|
||||
|
||||
da_push_back(obs->modules, &mod);
|
||||
return MODULE_SUCCESS;
|
||||
}
|
||||
|
||||
bool obs_init_module(obs_module_t module)
|
||||
{
|
||||
if (!module || !obs)
|
||||
return false;
|
||||
if (module->loaded)
|
||||
return true;
|
||||
|
||||
module->loaded = module->load(LIBOBS_API_VER);
|
||||
if (!module->loaded)
|
||||
blog(LOG_WARNING, "Failed to initialize module '%s'",
|
||||
module->file);
|
||||
|
||||
return module->loaded;
|
||||
}
|
||||
|
||||
char *obs_find_module_file(obs_module_t module, const char *file)
|
||||
{
|
||||
struct dstr output = {0};
|
||||
|
||||
if (!module)
|
||||
return NULL;
|
||||
|
||||
dstr_copy(&output, module->data_path);
|
||||
if (!dstr_isempty(&output) && dstr_end(&output) != '/')
|
||||
dstr_cat_ch(&output, '/');
|
||||
dstr_cat(&output, file);
|
||||
|
||||
if (!os_file_exists(output.array))
|
||||
dstr_free(&output);
|
||||
return output.array;
|
||||
}
|
||||
|
||||
void obs_add_module_path(const char *bin, const char *data)
|
||||
{
|
||||
struct obs_module_path omp;
|
||||
|
||||
if (!obs || !bin || !data) return;
|
||||
|
||||
omp.bin = bstrdup(bin);
|
||||
omp.data = bstrdup(data);
|
||||
da_push_back(obs->module_paths, &omp);
|
||||
}
|
||||
|
||||
static void load_all_callback(void *param, const struct obs_module_info *info)
|
||||
{
|
||||
obs_module_t module;
|
||||
|
||||
int code = obs_open_module(&module, info->bin_path, info->data_path);
|
||||
if (code != MODULE_SUCCESS) {
|
||||
blog(LOG_DEBUG, "Failed to load module file '%s': %d",
|
||||
info->bin_path, code);
|
||||
return;
|
||||
}
|
||||
|
||||
obs_init_module(module);
|
||||
|
||||
UNUSED_PARAMETER(param);
|
||||
}
|
||||
|
||||
void obs_load_all_modules(void)
|
||||
{
|
||||
obs_find_modules(load_all_callback, NULL);
|
||||
}
|
||||
|
||||
static inline void make_data_dir(struct dstr *parsed_data_dir,
|
||||
const char *data_dir, const char *name)
|
||||
{
|
||||
dstr_copy(parsed_data_dir, data_dir);
|
||||
dstr_replace(parsed_data_dir, "%module%", name);
|
||||
if (dstr_end(parsed_data_dir) == '/')
|
||||
dstr_resize(parsed_data_dir, parsed_data_dir->len - 1);
|
||||
}
|
||||
|
||||
static char *make_data_directory(const char *module_name, const char *data_dir)
|
||||
{
|
||||
struct dstr parsed_data_dir = {0};
|
||||
bool found = false;
|
||||
|
||||
make_data_dir(&parsed_data_dir, data_dir, module_name);
|
||||
|
||||
found = os_file_exists(parsed_data_dir.array);
|
||||
|
||||
if (!found && astrcmpi_n(module_name, "lib", 3) == 0) {
|
||||
make_data_dir(&parsed_data_dir, data_dir, module_name + 3);
|
||||
found = os_file_exists(parsed_data_dir.array);
|
||||
}
|
||||
|
||||
if (!found)
|
||||
dstr_free(&parsed_data_dir);
|
||||
|
||||
return parsed_data_dir.array;
|
||||
}
|
||||
|
||||
static bool parse_binary_from_directory(struct dstr *parsed_bin_path,
|
||||
const char *bin_path, const char *file)
|
||||
{
|
||||
struct dstr directory = {0};
|
||||
bool found = true;
|
||||
|
||||
dstr_copy(&directory, bin_path);
|
||||
dstr_replace(&directory, "%module%", file);
|
||||
if (dstr_end(&directory) != '/')
|
||||
dstr_cat_ch(&directory, '/');
|
||||
|
||||
dstr_copy_dstr(parsed_bin_path, &directory);
|
||||
dstr_cat(parsed_bin_path, file);
|
||||
dstr_cat(parsed_bin_path, get_module_extension());
|
||||
|
||||
if (!os_file_exists(parsed_bin_path->array)) {
|
||||
/* if the file doesn't exist, check with 'lib' prefix */
|
||||
dstr_copy_dstr(parsed_bin_path, &directory);
|
||||
dstr_cat(parsed_bin_path, "lib");
|
||||
dstr_cat(parsed_bin_path, file);
|
||||
dstr_cat(parsed_bin_path, get_module_extension());
|
||||
|
||||
/* if neither exist, don't include this as a library */
|
||||
if (!os_file_exists(parsed_bin_path->array)) {
|
||||
dstr_free(parsed_bin_path);
|
||||
found = false;
|
||||
}
|
||||
}
|
||||
|
||||
dstr_free(&directory);
|
||||
return found;
|
||||
}
|
||||
|
||||
static void process_found_module(struct obs_module_path *omp,
|
||||
const char *path, bool directory,
|
||||
obs_find_module_callback_t callback, void *param)
|
||||
{
|
||||
struct obs_module_info info;
|
||||
struct dstr name = {0};
|
||||
struct dstr parsed_bin_path = {0};
|
||||
const char *file;
|
||||
char *parsed_data_dir;
|
||||
bool bin_found = true;
|
||||
|
||||
file = strrchr(path, '/');
|
||||
file = file ? (file + 1) : path;
|
||||
|
||||
dstr_copy(&name, file);
|
||||
if (!directory) {
|
||||
char *ext = strrchr(name.array, '.');
|
||||
if (ext)
|
||||
dstr_resize(&name, ext - name.array);
|
||||
|
||||
dstr_copy(&parsed_bin_path, path);
|
||||
} else {
|
||||
bin_found = parse_binary_from_directory(&parsed_bin_path,
|
||||
omp->bin, file);
|
||||
}
|
||||
|
||||
parsed_data_dir = make_data_directory(name.array, omp->data);
|
||||
|
||||
if (parsed_data_dir && bin_found) {
|
||||
info.bin_path = parsed_bin_path.array;
|
||||
info.data_path = parsed_data_dir;
|
||||
callback(param, &info);
|
||||
}
|
||||
|
||||
bfree(parsed_data_dir);
|
||||
dstr_free(&name);
|
||||
dstr_free(&parsed_bin_path);
|
||||
}
|
||||
|
||||
static void find_modules_in_path(struct obs_module_path *omp,
|
||||
obs_find_module_callback_t callback, void *param)
|
||||
{
|
||||
struct dstr search_path = {0};
|
||||
char *module_start;
|
||||
bool search_directories = false;
|
||||
os_glob_t gi;
|
||||
|
||||
dstr_copy(&search_path, omp->bin);
|
||||
|
||||
module_start = strstr(search_path.array, "%module%");
|
||||
if (module_start) {
|
||||
dstr_resize(&search_path, module_start - search_path.array);
|
||||
search_directories = true;
|
||||
}
|
||||
|
||||
if (!dstr_isempty(&search_path) && dstr_end(&search_path) != '/')
|
||||
dstr_cat_ch(&search_path, '/');
|
||||
|
||||
dstr_cat_ch(&search_path, '*');
|
||||
if (!search_directories)
|
||||
dstr_cat(&search_path, get_module_extension());
|
||||
|
||||
if (os_glob(search_path.array, 0, &gi) == 0) {
|
||||
for (size_t i = 0; i < gi->gl_pathc; i++) {
|
||||
if (search_directories == gi->gl_pathv[i].directory)
|
||||
process_found_module(omp,
|
||||
gi->gl_pathv[i].path,
|
||||
search_directories,
|
||||
callback, param);
|
||||
}
|
||||
|
||||
os_globfree(gi);
|
||||
}
|
||||
|
||||
dstr_free(&search_path);
|
||||
}
|
||||
|
||||
void obs_find_modules(obs_find_module_callback_t callback, void *param)
|
||||
{
|
||||
if (!obs)
|
||||
return;
|
||||
|
||||
for (size_t i = 0; i < obs->module_paths.num; i++) {
|
||||
struct obs_module_path *omp = obs->module_paths.array + i;
|
||||
find_modules_in_path(omp, callback, param);
|
||||
}
|
||||
}
|
||||
|
||||
void obs_enum_modules(obs_enum_module_callback_t callback, void *param)
|
||||
{
|
||||
struct obs_module *module;
|
||||
if (!obs)
|
||||
return;
|
||||
|
||||
module = obs->first_module;
|
||||
while (module) {
|
||||
callback(param, module);
|
||||
module = module->next;
|
||||
}
|
||||
}
|
||||
|
||||
void free_module(struct obs_module *mod)
|
||||
{
|
||||
if (!mod)
|
||||
return;
|
||||
|
||||
if (mod->module) {
|
||||
void (*module_unload)(void);
|
||||
if (mod->free_locale)
|
||||
mod->free_locale();
|
||||
|
||||
module_unload = os_dlsym(mod->module, "obs_module_unload");
|
||||
if (module_unload)
|
||||
module_unload();
|
||||
if (mod->loaded && mod->unload)
|
||||
mod->unload();
|
||||
|
||||
os_dlclose(mod->module);
|
||||
}
|
||||
|
||||
bfree(mod->name);
|
||||
bfree(mod->bin_path);
|
||||
bfree(mod->data_path);
|
||||
bfree(mod);
|
||||
}
|
||||
|
||||
lookup_t obs_module_load_locale(const char *module, const char *default_locale,
|
||||
lookup_t obs_module_load_locale(obs_module_t module, const char *default_locale,
|
||||
const char *locale)
|
||||
{
|
||||
struct dstr str = {0};
|
||||
|
@ -113,12 +349,11 @@ lookup_t obs_module_load_locale(const char *module, const char *default_locale,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
dstr_copy(&str, module);
|
||||
dstr_cat(&str, "/locale/");
|
||||
dstr_copy(&str, "locale/");
|
||||
dstr_cat(&str, default_locale);
|
||||
dstr_cat(&str, ".ini");
|
||||
|
||||
char *file = obs_find_plugin_file(str.array);
|
||||
char *file = obs_find_module_file(module, str.array);
|
||||
if (file)
|
||||
lookup = text_lookup_create(file);
|
||||
|
||||
|
@ -126,23 +361,22 @@ lookup_t obs_module_load_locale(const char *module, const char *default_locale,
|
|||
|
||||
if (!lookup) {
|
||||
blog(LOG_WARNING, "Failed to load '%s' text for module: '%s'",
|
||||
default_locale, module);
|
||||
default_locale, module->file);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (astrcmpi(locale, default_locale) == 0)
|
||||
goto cleanup;
|
||||
|
||||
dstr_copy(&str, module);
|
||||
dstr_cat(&str, "/locale/");
|
||||
dstr_copy(&str, "/locale/");
|
||||
dstr_cat(&str, locale);
|
||||
dstr_cat(&str, ".ini");
|
||||
|
||||
file = obs_find_plugin_file(str.array);
|
||||
file = obs_find_module_file(module, str.array);
|
||||
|
||||
if (!text_lookup_add(lookup, file))
|
||||
blog(LOG_WARNING, "Failed to load '%s' text for module: '%s'",
|
||||
locale, module);
|
||||
locale, module->file);
|
||||
|
||||
bfree(file);
|
||||
cleanup:
|
||||
|
|
|
@ -32,8 +32,15 @@
|
|||
*/
|
||||
|
||||
/** Required: Declares a libobs module. */
|
||||
#define OBS_DECLARE_MODULE() \
|
||||
MODULE_EXPORT uint32_t obs_module_ver(void); \
|
||||
#define OBS_DECLARE_MODULE() \
|
||||
static obs_module_t obs_module_pointer; \
|
||||
MODULE_EXPORT void obs_module_set_pointer(obs_module_t module); \
|
||||
void obs_module_set_pointer(obs_module_t module) \
|
||||
{ \
|
||||
obs_module_pointer = module; \
|
||||
} \
|
||||
obs_module_t obs_current_module(void) {return obs_module_pointer;} \
|
||||
MODULE_EXPORT uint32_t obs_module_ver(void); \
|
||||
uint32_t obs_module_ver(void) {return LIBOBS_API_VER;}
|
||||
|
||||
/**
|
||||
|
@ -53,11 +60,10 @@ MODULE_EXPORT void obs_module_unload(void);
|
|||
/** Called to set the current locale data for the module. */
|
||||
MODULE_EXPORT void obs_module_set_locale(const char *locale);
|
||||
|
||||
/**
|
||||
* Optional: Use this macro in a module to use default locale handling. Use
|
||||
* the OBS_MODULE_FREE_DEFAULT_LOCALE macro in obs_module_unload to free the
|
||||
* locale data when the module unloads.
|
||||
*/
|
||||
/** Called to free the current locale data for the module. */
|
||||
MODULE_EXPORT void obs_module_free_locale(void);
|
||||
|
||||
/** Optional: Use this macro in a module to use default locale handling. */
|
||||
#define OBS_MODULE_USE_DEFAULT_LOCALE(module_name, default_locale) \
|
||||
lookup_t obs_module_lookup = NULL; \
|
||||
const char *obs_module_text(const char *val) \
|
||||
|
@ -69,7 +75,8 @@ MODULE_EXPORT void obs_module_set_locale(const char *locale);
|
|||
void obs_module_set_locale(const char *locale) \
|
||||
{ \
|
||||
if (obs_module_lookup) text_lookup_destroy(obs_module_lookup); \
|
||||
obs_module_lookup = obs_module_load_locale(module_name, \
|
||||
obs_module_lookup = obs_module_load_locale( \
|
||||
obs_current_module(), \
|
||||
default_locale, locale); \
|
||||
}
|
||||
|
||||
|
@ -79,6 +86,16 @@ MODULE_EXPORT void obs_module_set_locale(const char *locale);
|
|||
/** Helper function for looking up locale if default locale handler was used */
|
||||
extern const char *obs_module_text(const char *lookup_string);
|
||||
|
||||
/** Helper function that returns the current module */
|
||||
extern obs_module_t obs_current_module(void);
|
||||
|
||||
/**
|
||||
* Returns the location to a module data file associated with the current
|
||||
* module. Free with bfree when complete. Equivalent to:
|
||||
* obs_find_module_file(obs_current_modile(), file);
|
||||
*/
|
||||
#define obs_module_file(file) obs_find_module_file(obs_current_module(), file)
|
||||
|
||||
/**
|
||||
* Optional: Declares the author(s) of the module
|
||||
*
|
||||
|
@ -88,5 +105,8 @@ extern const char *obs_module_text(const char *lookup_string);
|
|||
MODULE_EXPORT const char *obs_module_author(void); \
|
||||
const char *obs_module_author(void) {return name;}
|
||||
|
||||
/** Optional: Returns the full name of the module */
|
||||
MODULE_EXPORT const char *obs_module_name(void);
|
||||
|
||||
/** Optional: Returns a description of the module */
|
||||
MODULE_EXPORT const char *obs_module_description(void);
|
||||
|
|
109
libobs/obs-nix.c
109
libobs/obs-nix.c
|
@ -22,77 +22,36 @@
|
|||
#include <sys/sysinfo.h>
|
||||
#include <sys/utsname.h>
|
||||
#include "util/dstr.h"
|
||||
#include "obs.h"
|
||||
#include "obs-internal.h"
|
||||
|
||||
const char *get_module_extension(void)
|
||||
{
|
||||
return ".so";
|
||||
}
|
||||
|
||||
static inline bool check_path(const char* data, const char *path,
|
||||
struct dstr * output)
|
||||
#ifdef __LP64__
|
||||
#define BIT_STRING "64bit"
|
||||
#else
|
||||
#define BIT_STRING "32bit"
|
||||
#endif
|
||||
|
||||
static const char *module_bin[] = {
|
||||
"../../obs-plugins/" BIT_STRING,
|
||||
OBS_INSTALL_PREFIX "lib/obs-plugins",
|
||||
};
|
||||
|
||||
static const char *module_data[] = {
|
||||
OBS_DATA_PATH "/obs-plugins/%module%",
|
||||
OBS_INSTALL_DATA_PATH "/obs-plugins/%module%",
|
||||
};
|
||||
|
||||
static const int module_patterns_size =
|
||||
sizeof(module_bin)/sizeof(module_bin[0]);
|
||||
|
||||
void add_default_module_paths(void)
|
||||
{
|
||||
dstr_copy(output, path);
|
||||
dstr_cat(output, data);
|
||||
|
||||
blog(LOG_INFO, "Attempting path: %s\n", output->array);
|
||||
|
||||
return access(output->array, R_OK) == 0;
|
||||
}
|
||||
|
||||
static inline bool check_lib_path(const char* data, const char *path,
|
||||
struct dstr *output)
|
||||
{
|
||||
bool result = false;
|
||||
struct dstr tmp;
|
||||
|
||||
dstr_init(&tmp);
|
||||
dstr_cat(&tmp, data);
|
||||
dstr_cat(&tmp, ".so");
|
||||
result = check_path(tmp.array, path, output);
|
||||
|
||||
dstr_free(&tmp);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* /usr/local/lib/obs-plugins
|
||||
* /usr/lib/obs-plugins
|
||||
*/
|
||||
char *find_plugin(const char *plugin)
|
||||
{
|
||||
struct dstr output;
|
||||
dstr_init(&output);
|
||||
|
||||
if(sizeof(void*) == 4) {
|
||||
if (check_lib_path(plugin, "../../obs-plugins/32bit/", &output))
|
||||
return output.array;
|
||||
|
||||
if (check_lib_path(plugin, "../../obs-plugins/32bit/lib", &output))
|
||||
return output.array;
|
||||
} else {
|
||||
if (check_lib_path(plugin, "../../obs-plugins/64bit/", &output))
|
||||
return output.array;
|
||||
|
||||
if (check_lib_path(plugin, "../../obs-plugins/64bit/lib", &output))
|
||||
return output.array;
|
||||
}
|
||||
|
||||
if (OBS_INSTALL_PREFIX [0] != 0) {
|
||||
if (check_lib_path(plugin,
|
||||
OBS_INSTALL_PREFIX "lib/obs-plugins/",
|
||||
&output))
|
||||
return output.array;
|
||||
|
||||
if (check_lib_path(plugin,
|
||||
OBS_INSTALL_PREFIX "lib/obs-plugins/lib",
|
||||
&output))
|
||||
return output.array;
|
||||
}
|
||||
|
||||
dstr_free(&output);
|
||||
return NULL;
|
||||
for (int i = 0; i < module_patterns_size; i++)
|
||||
obs_add_module_path(module_bin[i], module_data[i]);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -117,28 +76,6 @@ char *find_libobs_data_file(const char *file)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* /usr/local/share/obs-plugins
|
||||
* /usr/share/obs-plugins
|
||||
*/
|
||||
char *obs_find_plugin_file(const char *file)
|
||||
{
|
||||
struct dstr output;
|
||||
dstr_init(&output);
|
||||
|
||||
if (check_path(file, OBS_DATA_PATH "/obs-plugins/", &output))
|
||||
return output.array;
|
||||
|
||||
if (OBS_INSTALL_PREFIX [0] != 0) {
|
||||
if (check_path(file, OBS_INSTALL_DATA_PATH "/obs-plugins/",
|
||||
&output))
|
||||
return output.array;
|
||||
}
|
||||
|
||||
dstr_free(&output);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void log_processor_info(void)
|
||||
{
|
||||
FILE *fp;
|
||||
|
|
|
@ -27,57 +27,32 @@ const char *get_module_extension(void)
|
|||
return ".dll";
|
||||
}
|
||||
|
||||
static inline bool check_path(const char* data, const char *path,
|
||||
struct dstr * output)
|
||||
{
|
||||
dstr_copy(output, path);
|
||||
dstr_cat(output, data);
|
||||
|
||||
blog(LOG_DEBUG, "Attempting path: %s\n", output->array);
|
||||
|
||||
return os_file_exists(output->array);
|
||||
}
|
||||
|
||||
static inline bool check_lib_path(const char* data, const char *path,
|
||||
struct dstr *output)
|
||||
{
|
||||
bool result = false;
|
||||
struct dstr tmp;
|
||||
|
||||
dstr_init_copy(&tmp, data);
|
||||
dstr_cat(&tmp, ".dll");
|
||||
result = check_path(tmp.array, path, output);
|
||||
|
||||
dstr_free(&tmp);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* on windows, plugin files are located in [base directory]/plugins/[bit] */
|
||||
char *find_plugin(const char *plugin)
|
||||
{
|
||||
struct dstr path;
|
||||
dstr_init(&path);
|
||||
|
||||
#ifdef _WIN64
|
||||
if (check_lib_path(plugin, "obs-plugins/64bit/", &path))
|
||||
#define BIT_STRING "64bit"
|
||||
#else
|
||||
if (check_lib_path(plugin, "obs-plugins/32bit/", &path))
|
||||
#define BIT_STRING "32bit"
|
||||
#endif
|
||||
return path.array;
|
||||
|
||||
#ifdef _WIN64
|
||||
if (check_lib_path(plugin, "../../obs-plugins/64bit/", &path))
|
||||
#else
|
||||
if (check_lib_path(plugin, "../../obs-plugins/32bit/", &path))
|
||||
#endif
|
||||
return path.array;
|
||||
static const char *module_bin[] = {
|
||||
"obs-plugins/" BIT_STRING,
|
||||
"../../obs-plugins/" BIT_STRING,
|
||||
};
|
||||
|
||||
dstr_free(&path);
|
||||
return NULL;
|
||||
static const char *module_data[] = {
|
||||
"data/%module%",
|
||||
"../../data/obs-plugins/%module%"
|
||||
};
|
||||
|
||||
static const int module_patterns_size =
|
||||
sizeof(module_bin)/sizeof(module_bin[0]);
|
||||
|
||||
void add_default_module_paths(void)
|
||||
{
|
||||
for (int i = 0; i < module_patterns_size; i++)
|
||||
obs_add_module_path(module_bin[i], module_data[i]);
|
||||
}
|
||||
|
||||
/* on windows, points to [base directory]/libobs */
|
||||
/* on windows, points to [base directory]/data/libobs */
|
||||
char *find_libobs_data_file(const char *file)
|
||||
{
|
||||
struct dstr path;
|
||||
|
@ -93,22 +68,6 @@ char *find_libobs_data_file(const char *file)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/* on windows, data files should always be in [base directory]/data */
|
||||
char *obs_find_plugin_file(const char *file)
|
||||
{
|
||||
struct dstr path;
|
||||
dstr_init(&path);
|
||||
|
||||
if (check_path(file, "data/obs-plugins/", &path))
|
||||
return path.array;
|
||||
|
||||
if (check_path(file, "../../data/obs-plugins/", &path))
|
||||
return path.array;
|
||||
|
||||
dstr_free(&path);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void log_processor_info(void)
|
||||
{
|
||||
HKEY key;
|
||||
|
|
26
libobs/obs.c
26
libobs/obs.c
|
@ -24,6 +24,7 @@
|
|||
|
||||
struct obs_core *obs = NULL;
|
||||
|
||||
extern void add_default_module_paths(void);
|
||||
extern char *find_libobs_data_file(const char *file);
|
||||
|
||||
static inline void make_gs_init_data(struct gs_init_data *gid,
|
||||
|
@ -540,6 +541,7 @@ static bool obs_init(const char *locale)
|
|||
|
||||
obs->locale = bstrdup(locale);
|
||||
obs_register_source(&scene_info);
|
||||
add_default_module_paths();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -561,6 +563,8 @@ bool obs_startup(const char *locale)
|
|||
|
||||
void obs_shutdown(void)
|
||||
{
|
||||
struct obs_module *module;
|
||||
|
||||
if (!obs)
|
||||
return;
|
||||
|
||||
|
@ -582,9 +586,17 @@ void obs_shutdown(void)
|
|||
proc_handler_destroy(obs->procs);
|
||||
signal_handler_destroy(obs->signals);
|
||||
|
||||
for (size_t i = 0; i < obs->modules.num; i++)
|
||||
free_module(obs->modules.array+i);
|
||||
da_free(obs->modules);
|
||||
module = obs->first_module;
|
||||
while (module) {
|
||||
struct obs_module *next = module->next;
|
||||
free_module(module);
|
||||
module = next;
|
||||
}
|
||||
obs->first_module = NULL;
|
||||
|
||||
for (size_t i = 0; i < obs->module_paths.num; i++)
|
||||
free_module_path(obs->module_paths.array+i);
|
||||
da_free(obs->module_paths);
|
||||
|
||||
bfree(obs->locale);
|
||||
bfree(obs);
|
||||
|
@ -603,6 +615,7 @@ uint32_t obs_get_version(void)
|
|||
|
||||
void obs_set_locale(const char *locale)
|
||||
{
|
||||
struct obs_module *module;
|
||||
if (!obs)
|
||||
return;
|
||||
|
||||
|
@ -610,11 +623,12 @@ void obs_set_locale(const char *locale)
|
|||
bfree(obs->locale);
|
||||
obs->locale = bstrdup(locale);
|
||||
|
||||
for (size_t i = 0; i < obs->modules.num; i++) {
|
||||
struct obs_module *module = obs->modules.array+i;
|
||||
|
||||
module = obs->first_module;
|
||||
while (module) {
|
||||
if (module->set_locale)
|
||||
module->set_locale(locale);
|
||||
|
||||
module = module->next;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
86
libobs/obs.h
86
libobs/obs.h
|
@ -45,6 +45,7 @@ struct obs_scene_item;
|
|||
struct obs_output;
|
||||
struct obs_encoder;
|
||||
struct obs_service;
|
||||
struct obs_module;
|
||||
|
||||
typedef struct obs_display *obs_display_t;
|
||||
typedef struct obs_view *obs_view_t;
|
||||
|
@ -54,6 +55,7 @@ typedef struct obs_scene_item *obs_sceneitem_t;
|
|||
typedef struct obs_output *obs_output_t;
|
||||
typedef struct obs_encoder *obs_encoder_t;
|
||||
typedef struct obs_service *obs_service_t;
|
||||
typedef struct obs_module *obs_module_t;
|
||||
|
||||
#include "obs-source.h"
|
||||
#include "obs-encoder.h"
|
||||
|
@ -257,18 +259,82 @@ EXPORT bool obs_get_video_info(struct obs_video_info *ovi);
|
|||
EXPORT bool obs_get_audio_info(struct audio_output_info *ai);
|
||||
|
||||
/**
|
||||
* Loads a plugin module
|
||||
* Opens a plugin module directly from a specific path.
|
||||
*
|
||||
* A plugin module contains exports for inputs/fitlers/transitions/outputs.
|
||||
* See obs-source.h and obs-output.h for more information on the exports to
|
||||
* use.
|
||||
* If the module already exists then the function will return successful, and
|
||||
* the module parameter will be given the pointer to the existing module.
|
||||
*
|
||||
* This does not initialize the module, it only loads the module image. To
|
||||
* initialize the module, call obs_init_module.
|
||||
*
|
||||
* @param module The pointer to the created module.
|
||||
* @param path Specifies the path to the module library file. If the
|
||||
* extension is not specified, it will use the extension
|
||||
* appropriate to the operating system.
|
||||
* @param data_path Specifies the path to the directory where the module's
|
||||
* data files are stored.
|
||||
* @returns MODULE_SUCCESS if successful
|
||||
* MODULE_ERROR if a generic error occurred
|
||||
* MODULE_FILE_NOT_FOUND if the module was not found
|
||||
* MODULE_MISSING_EXPORTS if required exports are missing
|
||||
* MODULE_INCOMPATIBLE_VER if incompatible version
|
||||
*/
|
||||
EXPORT int obs_load_module(const char *path);
|
||||
EXPORT int obs_open_module(obs_module_t *module, const char *path,
|
||||
const char *data_path);
|
||||
|
||||
/**
|
||||
* Initializes the module, which calls its obs_module_load export. If the
|
||||
* module is alrady loaded, then this function does nothing and returns
|
||||
* successful.
|
||||
*/
|
||||
EXPORT bool obs_init_module(obs_module_t module);
|
||||
|
||||
/**
|
||||
* Adds a module search path to be used with obs_find_modules. If the search
|
||||
* path strings contain %module%, that text will be replaced with the module
|
||||
* name when used.
|
||||
*
|
||||
* @param bin Specifies the module's binary directory search path.
|
||||
* @param data Specifies the module's data directory search path.
|
||||
*/
|
||||
EXPORT void obs_add_module_path(const char *bin, const char *data);
|
||||
|
||||
/** Automatically loads all modules from module paths (convenience function) */
|
||||
EXPORT void obs_load_all_modules(void);
|
||||
|
||||
struct obs_module_info {
|
||||
const char *bin_path;
|
||||
const char *data_path;
|
||||
};
|
||||
|
||||
typedef void (*obs_find_module_callback_t)(void *param,
|
||||
const struct obs_module_info *info);
|
||||
|
||||
/** Finds all modules within the search paths added by obs_add_module_path. */
|
||||
EXPORT void obs_find_modules(obs_find_module_callback_t callback, void *param);
|
||||
|
||||
typedef void (*obs_enum_module_callback_t)(void *param, obs_module_t module);
|
||||
|
||||
/** Enumerates all loaded modules */
|
||||
EXPORT void obs_enum_modules(obs_enum_module_callback_t callback, void *param);
|
||||
|
||||
/** Helper function for using default module locale */
|
||||
EXPORT lookup_t obs_module_load_locale(const char *module,
|
||||
EXPORT lookup_t obs_module_load_locale(obs_module_t module,
|
||||
const char *default_locale, const char *locale);
|
||||
|
||||
/**
|
||||
* Returns the location of a plugin module data file.
|
||||
*
|
||||
* @note Modules should use obs_module_file function defined in obs-module.h
|
||||
* as a more elegant means of getting their files without having to
|
||||
* specify the module parameter.
|
||||
*
|
||||
* @param module The module associated with the file to locate
|
||||
* @param file The file to locate
|
||||
* @return Path string, or NULL if not found. Use bfree to free string.
|
||||
*/
|
||||
EXPORT char *obs_find_module_file(obs_module_t module, const char *file);
|
||||
|
||||
/**
|
||||
* Enumerates all available inputs source types.
|
||||
*
|
||||
|
@ -368,14 +434,6 @@ EXPORT obs_encoder_t obs_get_encoder_by_name(const char *name);
|
|||
/** Gets an service by its name. */
|
||||
EXPORT obs_service_t obs_get_service_by_name(const char *name);
|
||||
|
||||
/**
|
||||
* Returns the location of a plugin data file.
|
||||
*
|
||||
* file: Name of file to locate. For example, "myplugin/mydata.data"
|
||||
* returns: Path string, or NULL if not found. Use bfree to free string.
|
||||
*/
|
||||
EXPORT char *obs_find_plugin_file(const char *file);
|
||||
|
||||
/** Returns the default effect for generic RGB/YUV drawing */
|
||||
EXPORT effect_t obs_get_default_effect(void);
|
||||
|
||||
|
|
|
@ -534,28 +534,7 @@ void OBSBasic::OBSInit()
|
|||
|
||||
InitOBSCallbacks();
|
||||
|
||||
/* TODO: this is a test, all modules will be searched for and loaded
|
||||
* automatically later */
|
||||
obs_load_module("image-source");
|
||||
// obs_load_module("test-input");
|
||||
obs_load_module("obs-ffmpeg");
|
||||
obs_load_module("obs-libfdk");
|
||||
obs_load_module("obs-x264");
|
||||
obs_load_module("obs-outputs");
|
||||
obs_load_module("rtmp-services");
|
||||
#ifdef __APPLE__
|
||||
obs_load_module("mac-avcapture");
|
||||
obs_load_module("mac-capture");
|
||||
#elif _WIN32
|
||||
obs_load_module("win-wasapi");
|
||||
obs_load_module("win-capture");
|
||||
obs_load_module("win-dshow");
|
||||
#else
|
||||
obs_load_module("linux-xshm");
|
||||
obs_load_module("linux-xcomposite");
|
||||
obs_load_module("linux-pulseaudio");
|
||||
obs_load_module("linux-v4l2");
|
||||
#endif
|
||||
obs_load_all_modules();
|
||||
|
||||
if (!InitOutputs())
|
||||
throw "Failed to initialize outputs";
|
||||
|
|
|
@ -181,8 +181,7 @@ static void *display_capture_create(obs_data_t settings,
|
|||
if (!dc->sampler)
|
||||
goto fail;
|
||||
|
||||
char *effect_file = obs_find_plugin_file(
|
||||
"mac-capture/draw_rect.effect");
|
||||
char *effect_file = obs_module_file("draw_rect.effect");
|
||||
dc->draw_effect = gs_create_effect_from_file(effect_file, NULL);
|
||||
bfree(effect_file);
|
||||
if (!dc->draw_effect)
|
||||
|
|
|
@ -207,7 +207,7 @@ static obs_properties_t rtmp_common_properties(void)
|
|||
obs_module_text("Service"),
|
||||
OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_STRING);
|
||||
|
||||
file = obs_find_plugin_file("rtmp-services/services.json");
|
||||
file = obs_module_file("services.json");
|
||||
if (file) {
|
||||
json_t *root = build_service_list(list, file);
|
||||
obs_properties_set_param(ppts, root, properties_data_destroy);
|
||||
|
@ -305,7 +305,7 @@ static bool rtmp_common_initialize(void *data, obs_output_t output)
|
|||
struct rtmp_common *service = data;
|
||||
char *file;
|
||||
|
||||
file = obs_find_plugin_file("rtmp-services/services.json");
|
||||
file = obs_module_file("services.json");
|
||||
if (file) {
|
||||
json_t *root = open_json_file(file);
|
||||
if (root) {
|
||||
|
|
|
@ -216,7 +216,7 @@ effect_t create_opaque_effect(void)
|
|||
char *effect_file;
|
||||
char *error_string = NULL;
|
||||
|
||||
effect_file = obs_find_plugin_file("win-capture/opaque.effect");
|
||||
effect_file = obs_module_file("opaque.effect");
|
||||
if (!effect_file) {
|
||||
blog(LOG_ERROR, "[create_opaque_effect] Could not find "
|
||||
"opaque effect file");
|
||||
|
|
|
@ -62,9 +62,8 @@ static void CreateOBS(NSView *view)
|
|||
static SceneContext SetupScene()
|
||||
{
|
||||
/* ------------------------------------------------------ */
|
||||
/* load module */
|
||||
if (obs_load_module("test-input") != 0)
|
||||
throw "Couldn't load module";
|
||||
/* load modules */
|
||||
obs_load_all_modules();
|
||||
|
||||
/* ------------------------------------------------------ */
|
||||
/* create source */
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#include <obs.h>
|
||||
#include <obs-module.h>
|
||||
|
||||
struct test_filter {
|
||||
obs_source_t source;
|
||||
|
@ -31,7 +31,7 @@ static void *filter_create(obs_data_t settings, obs_source_t source)
|
|||
|
||||
gs_entercontext(obs_graphics());
|
||||
|
||||
effect_file = obs_find_plugin_file("test-input/test.effect");
|
||||
effect_file = obs_module_file("test.effect");
|
||||
|
||||
tf->source = source;
|
||||
tf->whatever = gs_create_effect_from_file(effect_file, NULL);
|
||||
|
|
|
@ -152,9 +152,8 @@ int WINAPI WinMain(HINSTANCE instance, HINSTANCE prevInstance, LPSTR cmdLine,
|
|||
CreateOBS(hwnd);
|
||||
|
||||
/* ------------------------------------------------------ */
|
||||
/* load module */
|
||||
if (obs_load_module("test-input") != 0)
|
||||
throw "Couldn't load module";
|
||||
/* load modules */
|
||||
obs_load_all_modules();
|
||||
|
||||
/* ------------------------------------------------------ */
|
||||
/* create source */
|
||||
|
|
Loading…
Reference in New Issue