2018-02-19 19:54:37 +00:00
|
|
|
/******************************************************************************
|
|
|
|
Copyright (C) 2017 by Hugh Bailey <jim@obsproject.com>
|
|
|
|
|
|
|
|
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, see <http://www.gnu.org/licenses/>.
|
|
|
|
******************************************************************************/
|
|
|
|
|
|
|
|
#include "obs-scripting-lua.h"
|
|
|
|
#include "cstrcache.h"
|
|
|
|
|
|
|
|
#include <obs-module.h>
|
|
|
|
|
|
|
|
/* ========================================================================= */
|
|
|
|
|
|
|
|
static inline const char *get_table_string_(lua_State *script, int idx,
|
2019-09-22 21:19:10 +00:00
|
|
|
const char *name, const char *func)
|
2018-02-19 19:54:37 +00:00
|
|
|
{
|
|
|
|
const char *str = "";
|
|
|
|
|
|
|
|
lua_pushstring(script, name);
|
|
|
|
lua_gettable(script, idx - 1);
|
|
|
|
if (!lua_isstring(script, -1))
|
|
|
|
warn("%s: no item '%s' of type %s", func, name, "string");
|
|
|
|
else
|
|
|
|
str = cstrcache_get(lua_tostring(script, -1));
|
|
|
|
lua_pop(script, 1);
|
|
|
|
|
|
|
|
return str;
|
|
|
|
}
|
|
|
|
|
2019-09-22 21:19:10 +00:00
|
|
|
static inline int get_table_int_(lua_State *script, int idx, const char *name,
|
|
|
|
const char *func)
|
2018-02-19 19:54:37 +00:00
|
|
|
{
|
|
|
|
int val = 0;
|
|
|
|
|
|
|
|
lua_pushstring(script, name);
|
|
|
|
lua_gettable(script, idx - 1);
|
|
|
|
val = (int)lua_tointeger(script, -1);
|
|
|
|
lua_pop(script, 1);
|
|
|
|
|
|
|
|
UNUSED_PARAMETER(func);
|
|
|
|
|
|
|
|
return val;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void get_callback_from_table_(lua_State *script, int idx,
|
2019-09-22 21:19:10 +00:00
|
|
|
const char *name, int *p_reg_idx,
|
|
|
|
const char *func)
|
2018-02-19 19:54:37 +00:00
|
|
|
{
|
|
|
|
*p_reg_idx = LUA_REFNIL;
|
|
|
|
|
|
|
|
lua_pushstring(script, name);
|
|
|
|
lua_gettable(script, idx - 1);
|
|
|
|
if (!lua_isfunction(script, -1)) {
|
|
|
|
if (!lua_isnil(script, -1)) {
|
|
|
|
warn("%s: item '%s' is not a function", func, name);
|
|
|
|
}
|
|
|
|
lua_pop(script, 1);
|
|
|
|
} else {
|
|
|
|
*p_reg_idx = luaL_ref(script, LUA_REGISTRYINDEX);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#define get_table_string(script, idx, name) \
|
|
|
|
get_table_string_(script, idx, name, __FUNCTION__)
|
|
|
|
#define get_table_int(script, idx, name) \
|
|
|
|
get_table_int_(script, idx, name, __FUNCTION__)
|
|
|
|
#define get_callback_from_table(script, idx, name, p_reg_idx) \
|
|
|
|
get_callback_from_table_(script, idx, name, p_reg_idx, __FUNCTION__)
|
|
|
|
|
2019-09-22 21:19:10 +00:00
|
|
|
bool ls_get_libobs_obj_(lua_State *script, const char *type, int lua_idx,
|
|
|
|
void *libobs_out, const char *id, const char *func,
|
|
|
|
int line)
|
2018-02-19 19:54:37 +00:00
|
|
|
{
|
|
|
|
swig_type_info *info = SWIG_TypeQuery(script, type);
|
|
|
|
if (info == NULL) {
|
2019-09-22 21:19:10 +00:00
|
|
|
warn("%s:%d: SWIG could not find type: %s%s%s", func, line,
|
|
|
|
id ? id : "", id ? "::" : "", type);
|
2018-02-19 19:54:37 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
int ret = SWIG_ConvertPtr(script, lua_idx, libobs_out, info, 0);
|
|
|
|
if (!SWIG_IsOK(ret)) {
|
|
|
|
warn("%s:%d: SWIG failed to convert lua object to obs "
|
|
|
|
"object: %s%s%s",
|
2019-09-22 21:19:10 +00:00
|
|
|
func, line, id ? id : "", id ? "::" : "", type);
|
2018-02-19 19:54:37 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-09-22 21:19:10 +00:00
|
|
|
#define ls_get_libobs_obj(type, lua_index, obs_obj) \
|
|
|
|
ls_get_libobs_obj_(ls->script, #type " *", lua_index, obs_obj, ls->id, \
|
|
|
|
__FUNCTION__, __LINE__)
|
|
|
|
|
|
|
|
bool ls_push_libobs_obj_(lua_State *script, const char *type, void *libobs_in,
|
|
|
|
bool ownership, const char *id, const char *func,
|
|
|
|
int line)
|
2018-02-19 19:54:37 +00:00
|
|
|
{
|
|
|
|
swig_type_info *info = SWIG_TypeQuery(script, type);
|
|
|
|
if (info == NULL) {
|
2019-09-22 21:19:10 +00:00
|
|
|
warn("%s:%d: SWIG could not find type: %s%s%s", func, line,
|
|
|
|
id ? id : "", id ? "::" : "", type);
|
2018-02-19 19:54:37 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
SWIG_NewPointerObj(script, libobs_in, info, (int)ownership);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-09-22 21:19:10 +00:00
|
|
|
#define ls_push_libobs_obj(type, obs_obj, ownership) \
|
2018-02-19 19:54:37 +00:00
|
|
|
ls_push_libobs_obj_(ls->script, #type " *", obs_obj, ownership, \
|
2019-09-22 21:19:10 +00:00
|
|
|
ls->id, __FUNCTION__, __LINE__)
|
2018-02-19 19:54:37 +00:00
|
|
|
|
|
|
|
/* ========================================================================= */
|
|
|
|
|
|
|
|
struct obs_lua_data;
|
|
|
|
|
|
|
|
struct obs_lua_source {
|
|
|
|
struct obs_lua_script *data;
|
|
|
|
|
2019-09-22 21:19:10 +00:00
|
|
|
lua_State *script;
|
2018-02-19 19:54:37 +00:00
|
|
|
const char *id;
|
|
|
|
const char *display_name;
|
2019-09-22 21:19:10 +00:00
|
|
|
int func_create;
|
|
|
|
int func_destroy;
|
|
|
|
int func_get_width;
|
|
|
|
int func_get_height;
|
|
|
|
int func_get_defaults;
|
|
|
|
int func_get_properties;
|
|
|
|
int func_update;
|
|
|
|
int func_activate;
|
|
|
|
int func_deactivate;
|
|
|
|
int func_show;
|
|
|
|
int func_hide;
|
|
|
|
int func_video_tick;
|
|
|
|
int func_video_render;
|
|
|
|
int func_save;
|
|
|
|
int func_load;
|
2018-02-19 19:54:37 +00:00
|
|
|
|
|
|
|
pthread_mutex_t definition_mutex;
|
|
|
|
struct obs_lua_data *first_source;
|
|
|
|
|
|
|
|
struct obs_lua_source *next;
|
|
|
|
struct obs_lua_source **p_prev_next;
|
|
|
|
};
|
|
|
|
|
|
|
|
extern pthread_mutex_t lua_source_def_mutex;
|
|
|
|
struct obs_lua_source *first_source_def = NULL;
|
|
|
|
|
|
|
|
struct obs_lua_data {
|
2019-09-22 21:19:10 +00:00
|
|
|
obs_source_t *source;
|
2018-02-19 19:54:37 +00:00
|
|
|
struct obs_lua_source *ls;
|
2019-09-22 21:19:10 +00:00
|
|
|
int lua_data_ref;
|
2018-02-19 19:54:37 +00:00
|
|
|
|
|
|
|
struct obs_lua_data *next;
|
|
|
|
struct obs_lua_data **p_prev_next;
|
|
|
|
};
|
|
|
|
|
2019-09-22 21:19:10 +00:00
|
|
|
#define call_func(name, args, rets) \
|
|
|
|
call_func_(ls->script, ls->func_##name, args, rets, #name, \
|
|
|
|
ls->display_name)
|
|
|
|
#define have_func(name) (ls->func_##name != LUA_REFNIL)
|
2018-02-19 19:54:37 +00:00
|
|
|
#define ls_push_data() \
|
|
|
|
lua_rawgeti(ls->script, LUA_REGISTRYINDEX, ld->lua_data_ref)
|
2019-09-22 21:19:10 +00:00
|
|
|
#define ls_pop(count) lua_pop(ls->script, count)
|
|
|
|
#define lock_script() \
|
|
|
|
struct obs_lua_script *__data = ls->data; \
|
2018-02-19 19:54:37 +00:00
|
|
|
struct obs_lua_script *__prev_script = current_lua_script; \
|
2019-09-22 21:19:10 +00:00
|
|
|
current_lua_script = __data; \
|
2018-02-19 19:54:37 +00:00
|
|
|
pthread_mutex_lock(&__data->mutex);
|
2019-09-22 21:19:10 +00:00
|
|
|
#define unlock_script() \
|
2018-02-19 19:54:37 +00:00
|
|
|
pthread_mutex_unlock(&__data->mutex); \
|
|
|
|
current_lua_script = __prev_script;
|
|
|
|
|
|
|
|
static const char *obs_lua_source_get_name(void *type_data)
|
|
|
|
{
|
|
|
|
struct obs_lua_source *ls = type_data;
|
|
|
|
return ls->display_name;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void *obs_lua_source_create(obs_data_t *settings, obs_source_t *source)
|
|
|
|
{
|
|
|
|
struct obs_lua_source *ls = obs_source_get_type_data(source);
|
|
|
|
struct obs_lua_data *data = NULL;
|
|
|
|
|
|
|
|
pthread_mutex_lock(&ls->definition_mutex);
|
|
|
|
if (!ls->script)
|
|
|
|
goto fail;
|
|
|
|
if (!have_func(create))
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
lock_script();
|
|
|
|
|
|
|
|
ls_push_libobs_obj(obs_data_t, settings, false);
|
|
|
|
ls_push_libobs_obj(obs_source_t, source, false);
|
|
|
|
call_func(create, 2, 1);
|
|
|
|
|
|
|
|
int lua_data_ref = luaL_ref(ls->script, LUA_REGISTRYINDEX);
|
|
|
|
if (lua_data_ref != LUA_REFNIL) {
|
2019-09-22 21:19:10 +00:00
|
|
|
data = bmalloc(sizeof(*data));
|
|
|
|
data->source = source;
|
|
|
|
data->ls = ls;
|
2018-02-19 19:54:37 +00:00
|
|
|
data->lua_data_ref = lua_data_ref;
|
|
|
|
}
|
|
|
|
|
|
|
|
unlock_script();
|
|
|
|
|
|
|
|
if (data) {
|
|
|
|
struct obs_lua_data *next = ls->first_source;
|
|
|
|
data->next = next;
|
|
|
|
data->p_prev_next = &ls->first_source;
|
2019-09-22 21:19:10 +00:00
|
|
|
if (next)
|
|
|
|
next->p_prev_next = &data->next;
|
2018-02-19 19:54:37 +00:00
|
|
|
ls->first_source = data;
|
|
|
|
}
|
|
|
|
|
|
|
|
fail:
|
|
|
|
pthread_mutex_unlock(&ls->definition_mutex);
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void call_destroy(struct obs_lua_data *ld)
|
|
|
|
{
|
|
|
|
struct obs_lua_source *ls = ld->ls;
|
|
|
|
|
|
|
|
ls_push_data();
|
|
|
|
call_func(destroy, 1, 0);
|
|
|
|
luaL_unref(ls->script, LUA_REGISTRYINDEX, ld->lua_data_ref);
|
|
|
|
ld->lua_data_ref = LUA_REFNIL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void obs_lua_source_destroy(void *data)
|
|
|
|
{
|
2019-09-22 21:19:10 +00:00
|
|
|
struct obs_lua_data *ld = data;
|
2018-02-19 19:54:37 +00:00
|
|
|
struct obs_lua_source *ls = ld->ls;
|
2019-09-22 21:19:10 +00:00
|
|
|
struct obs_lua_data *next;
|
2018-02-19 19:54:37 +00:00
|
|
|
|
|
|
|
pthread_mutex_lock(&ls->definition_mutex);
|
|
|
|
if (!ls->script)
|
|
|
|
goto fail;
|
|
|
|
if (!have_func(destroy))
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
lock_script();
|
|
|
|
call_destroy(ld);
|
|
|
|
unlock_script();
|
|
|
|
|
|
|
|
fail:
|
|
|
|
next = ld->next;
|
|
|
|
*ld->p_prev_next = next;
|
2019-09-22 21:19:10 +00:00
|
|
|
if (next)
|
|
|
|
next->p_prev_next = ld->p_prev_next;
|
2018-02-19 19:54:37 +00:00
|
|
|
|
|
|
|
bfree(data);
|
|
|
|
pthread_mutex_unlock(&ls->definition_mutex);
|
|
|
|
}
|
|
|
|
|
|
|
|
static uint32_t obs_lua_source_get_width(void *data)
|
|
|
|
{
|
2019-09-22 21:19:10 +00:00
|
|
|
struct obs_lua_data *ld = data;
|
|
|
|
struct obs_lua_source *ls = ld->ls;
|
|
|
|
uint32_t width = 0;
|
2018-02-19 19:54:37 +00:00
|
|
|
|
|
|
|
pthread_mutex_lock(&ls->definition_mutex);
|
|
|
|
if (!ls->script)
|
|
|
|
goto fail;
|
|
|
|
if (!have_func(get_width))
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
lock_script();
|
|
|
|
|
|
|
|
ls_push_data();
|
|
|
|
if (call_func(get_width, 1, 1)) {
|
|
|
|
width = (uint32_t)lua_tointeger(ls->script, -1);
|
|
|
|
ls_pop(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
unlock_script();
|
|
|
|
|
|
|
|
fail:
|
|
|
|
pthread_mutex_unlock(&ls->definition_mutex);
|
|
|
|
return width;
|
|
|
|
}
|
|
|
|
|
|
|
|
static uint32_t obs_lua_source_get_height(void *data)
|
|
|
|
{
|
2019-09-22 21:19:10 +00:00
|
|
|
struct obs_lua_data *ld = data;
|
|
|
|
struct obs_lua_source *ls = ld->ls;
|
|
|
|
uint32_t height = 0;
|
2018-02-19 19:54:37 +00:00
|
|
|
|
|
|
|
pthread_mutex_lock(&ls->definition_mutex);
|
|
|
|
if (!ls->script)
|
|
|
|
goto fail;
|
|
|
|
if (!have_func(get_height))
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
lock_script();
|
|
|
|
|
|
|
|
ls_push_data();
|
|
|
|
if (call_func(get_height, 1, 1)) {
|
|
|
|
height = (uint32_t)lua_tointeger(ls->script, -1);
|
|
|
|
ls_pop(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
unlock_script();
|
|
|
|
|
|
|
|
fail:
|
|
|
|
pthread_mutex_unlock(&ls->definition_mutex);
|
|
|
|
return height;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void obs_lua_source_get_defaults(void *type_data, obs_data_t *settings)
|
|
|
|
{
|
|
|
|
struct obs_lua_source *ls = type_data;
|
|
|
|
|
|
|
|
pthread_mutex_lock(&ls->definition_mutex);
|
|
|
|
if (!ls->script)
|
|
|
|
goto fail;
|
|
|
|
if (!have_func(get_defaults))
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
lock_script();
|
|
|
|
|
|
|
|
ls_push_libobs_obj(obs_data_t, settings, false);
|
|
|
|
call_func(get_defaults, 1, 0);
|
|
|
|
|
|
|
|
unlock_script();
|
|
|
|
|
|
|
|
fail:
|
|
|
|
pthread_mutex_unlock(&ls->definition_mutex);
|
|
|
|
}
|
|
|
|
|
|
|
|
static obs_properties_t *obs_lua_source_get_properties(void *data)
|
|
|
|
{
|
2019-09-22 21:19:10 +00:00
|
|
|
struct obs_lua_data *ld = data;
|
|
|
|
struct obs_lua_source *ls = ld->ls;
|
|
|
|
obs_properties_t *props = NULL;
|
2018-02-19 19:54:37 +00:00
|
|
|
|
|
|
|
pthread_mutex_lock(&ls->definition_mutex);
|
|
|
|
if (!ls->script)
|
|
|
|
goto fail;
|
|
|
|
if (!have_func(get_properties))
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
lock_script();
|
|
|
|
|
|
|
|
ls_push_data();
|
|
|
|
if (call_func(get_properties, 1, 1)) {
|
|
|
|
ls_get_libobs_obj(obs_properties_t, -1, &props);
|
|
|
|
ls_pop(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
unlock_script();
|
|
|
|
|
|
|
|
fail:
|
|
|
|
pthread_mutex_unlock(&ls->definition_mutex);
|
|
|
|
return props;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void obs_lua_source_update(void *data, obs_data_t *settings)
|
|
|
|
{
|
2019-09-22 21:19:10 +00:00
|
|
|
struct obs_lua_data *ld = data;
|
2018-02-19 19:54:37 +00:00
|
|
|
struct obs_lua_source *ls = ld->ls;
|
|
|
|
|
|
|
|
pthread_mutex_lock(&ls->definition_mutex);
|
|
|
|
if (!ls->script)
|
|
|
|
goto fail;
|
|
|
|
if (!have_func(update))
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
lock_script();
|
|
|
|
|
|
|
|
ls_push_data();
|
|
|
|
ls_push_libobs_obj(obs_data_t, settings, false);
|
|
|
|
call_func(update, 2, 0);
|
|
|
|
|
|
|
|
unlock_script();
|
|
|
|
|
|
|
|
fail:
|
|
|
|
pthread_mutex_unlock(&ls->definition_mutex);
|
|
|
|
}
|
|
|
|
|
2019-09-22 21:19:10 +00:00
|
|
|
#define DEFINE_VOID_DATA_CALLBACK(name) \
|
|
|
|
static void obs_lua_source_##name(void *data) \
|
|
|
|
{ \
|
|
|
|
struct obs_lua_data *ld = data; \
|
|
|
|
struct obs_lua_source *ls = ld->ls; \
|
|
|
|
if (!have_func(name)) \
|
|
|
|
return; \
|
|
|
|
lock_script(); \
|
|
|
|
ls_push_data(); \
|
|
|
|
call_func(name, 1, 0); \
|
|
|
|
unlock_script(); \
|
2018-02-19 19:54:37 +00:00
|
|
|
}
|
|
|
|
DEFINE_VOID_DATA_CALLBACK(activate)
|
|
|
|
DEFINE_VOID_DATA_CALLBACK(deactivate)
|
|
|
|
DEFINE_VOID_DATA_CALLBACK(show)
|
|
|
|
DEFINE_VOID_DATA_CALLBACK(hide)
|
|
|
|
#undef DEFINE_VOID_DATA_CALLBACK
|
|
|
|
|
|
|
|
static void obs_lua_source_video_tick(void *data, float seconds)
|
|
|
|
{
|
2019-09-22 21:19:10 +00:00
|
|
|
struct obs_lua_data *ld = data;
|
2018-02-19 19:54:37 +00:00
|
|
|
struct obs_lua_source *ls = ld->ls;
|
|
|
|
|
|
|
|
pthread_mutex_lock(&ls->definition_mutex);
|
|
|
|
if (!ls->script)
|
|
|
|
goto fail;
|
|
|
|
if (!have_func(video_tick))
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
lock_script();
|
|
|
|
|
|
|
|
ls_push_data();
|
|
|
|
lua_pushnumber(ls->script, (double)seconds);
|
|
|
|
call_func(video_tick, 2, 0);
|
|
|
|
|
|
|
|
unlock_script();
|
|
|
|
|
|
|
|
fail:
|
|
|
|
pthread_mutex_unlock(&ls->definition_mutex);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void obs_lua_source_video_render(void *data, gs_effect_t *effect)
|
|
|
|
{
|
2019-09-22 21:19:10 +00:00
|
|
|
struct obs_lua_data *ld = data;
|
2018-02-19 19:54:37 +00:00
|
|
|
struct obs_lua_source *ls = ld->ls;
|
|
|
|
|
|
|
|
pthread_mutex_lock(&ls->definition_mutex);
|
|
|
|
if (!ls->script)
|
|
|
|
goto fail;
|
|
|
|
if (!have_func(video_render))
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
lock_script();
|
|
|
|
|
|
|
|
ls_push_data();
|
|
|
|
ls_push_libobs_obj(gs_effect_t, effect, false);
|
|
|
|
call_func(video_render, 2, 0);
|
|
|
|
|
|
|
|
unlock_script();
|
|
|
|
|
|
|
|
fail:
|
|
|
|
pthread_mutex_unlock(&ls->definition_mutex);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void obs_lua_source_save(void *data, obs_data_t *settings)
|
|
|
|
{
|
2019-09-22 21:19:10 +00:00
|
|
|
struct obs_lua_data *ld = data;
|
2018-02-19 19:54:37 +00:00
|
|
|
struct obs_lua_source *ls = ld->ls;
|
|
|
|
|
|
|
|
pthread_mutex_lock(&ls->definition_mutex);
|
|
|
|
if (!ls->script)
|
|
|
|
goto fail;
|
|
|
|
if (!have_func(save))
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
lock_script();
|
|
|
|
|
|
|
|
ls_push_data();
|
|
|
|
ls_push_libobs_obj(obs_data_t, settings, false);
|
|
|
|
call_func(save, 2, 0);
|
|
|
|
|
|
|
|
unlock_script();
|
|
|
|
|
|
|
|
fail:
|
|
|
|
pthread_mutex_unlock(&ls->definition_mutex);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void obs_lua_source_load(void *data, obs_data_t *settings)
|
|
|
|
{
|
2019-09-22 21:19:10 +00:00
|
|
|
struct obs_lua_data *ld = data;
|
2018-02-19 19:54:37 +00:00
|
|
|
struct obs_lua_source *ls = ld->ls;
|
|
|
|
|
|
|
|
pthread_mutex_lock(&ls->definition_mutex);
|
|
|
|
if (!ls->script)
|
|
|
|
goto fail;
|
|
|
|
if (!have_func(load))
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
lock_script();
|
|
|
|
|
|
|
|
ls_push_data();
|
|
|
|
ls_push_libobs_obj(obs_data_t, settings, false);
|
|
|
|
call_func(load, 2, 0);
|
|
|
|
|
|
|
|
unlock_script();
|
|
|
|
|
|
|
|
fail:
|
|
|
|
pthread_mutex_unlock(&ls->definition_mutex);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void source_type_unload(struct obs_lua_source *ls)
|
|
|
|
{
|
2019-09-22 21:19:10 +00:00
|
|
|
#define unref(name) \
|
2018-02-19 19:54:37 +00:00
|
|
|
luaL_unref(ls->script, LUA_REGISTRYINDEX, name); \
|
|
|
|
name = LUA_REFNIL
|
|
|
|
|
|
|
|
unref(ls->func_create);
|
|
|
|
unref(ls->func_destroy);
|
|
|
|
unref(ls->func_get_width);
|
|
|
|
unref(ls->func_get_height);
|
|
|
|
unref(ls->func_get_defaults);
|
|
|
|
unref(ls->func_get_properties);
|
|
|
|
unref(ls->func_update);
|
|
|
|
unref(ls->func_activate);
|
|
|
|
unref(ls->func_deactivate);
|
|
|
|
unref(ls->func_show);
|
|
|
|
unref(ls->func_hide);
|
|
|
|
unref(ls->func_video_tick);
|
|
|
|
unref(ls->func_video_render);
|
|
|
|
unref(ls->func_save);
|
|
|
|
unref(ls->func_load);
|
|
|
|
#undef unref
|
|
|
|
}
|
|
|
|
|
|
|
|
static void obs_lua_source_free_type_data(void *type_data)
|
|
|
|
{
|
|
|
|
struct obs_lua_source *ls = type_data;
|
|
|
|
|
|
|
|
pthread_mutex_lock(&ls->definition_mutex);
|
|
|
|
|
|
|
|
if (ls->script) {
|
|
|
|
lock_script();
|
|
|
|
source_type_unload(ls);
|
|
|
|
unlock_script();
|
|
|
|
ls->script = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
pthread_mutex_unlock(&ls->definition_mutex);
|
|
|
|
pthread_mutex_destroy(&ls->definition_mutex);
|
|
|
|
bfree(ls);
|
|
|
|
}
|
|
|
|
|
|
|
|
EXPORT void obs_enable_source_type(const char *name, bool enable);
|
|
|
|
|
|
|
|
static inline struct obs_lua_source *find_existing(const char *id)
|
|
|
|
{
|
|
|
|
struct obs_lua_source *existing = NULL;
|
|
|
|
|
|
|
|
pthread_mutex_lock(&lua_source_def_mutex);
|
|
|
|
struct obs_lua_source *ls = first_source_def;
|
|
|
|
while (ls) {
|
|
|
|
/* can compare pointers here due to string table */
|
|
|
|
if (ls->id == id) {
|
|
|
|
existing = ls;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
ls = ls->next;
|
|
|
|
}
|
|
|
|
pthread_mutex_unlock(&lua_source_def_mutex);
|
|
|
|
|
|
|
|
return existing;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int obs_lua_register_source(lua_State *script)
|
|
|
|
{
|
|
|
|
struct obs_lua_source ls = {0};
|
|
|
|
struct obs_lua_source *existing = NULL;
|
|
|
|
struct obs_lua_source *v = NULL;
|
|
|
|
struct obs_source_info info = {0};
|
|
|
|
const char *id;
|
|
|
|
|
|
|
|
if (!verify_args1(script, is_table))
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
id = get_table_string(script, -1, "id");
|
|
|
|
if (!id || !*id)
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
/* redefinition */
|
|
|
|
existing = find_existing(id);
|
|
|
|
if (existing) {
|
|
|
|
if (existing->script) {
|
|
|
|
existing = NULL;
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
pthread_mutex_lock(&existing->definition_mutex);
|
|
|
|
}
|
|
|
|
|
|
|
|
v = existing ? existing : &ls;
|
|
|
|
|
|
|
|
v->script = script;
|
2019-09-22 21:19:10 +00:00
|
|
|
v->id = id;
|
2018-02-19 19:54:37 +00:00
|
|
|
|
2019-09-22 21:19:10 +00:00
|
|
|
info.id = v->id;
|
2018-02-19 19:54:37 +00:00
|
|
|
info.type = (enum obs_source_type)get_table_int(script, -1, "type");
|
|
|
|
|
|
|
|
info.output_flags = get_table_int(script, -1, "output_flags");
|
|
|
|
|
|
|
|
lua_pushstring(script, "get_name");
|
|
|
|
lua_gettable(script, -2);
|
|
|
|
if (lua_pcall(script, 0, 1, 0) == 0) {
|
|
|
|
v->display_name = cstrcache_get(lua_tostring(script, -1));
|
|
|
|
lua_pop(script, 1);
|
|
|
|
}
|
|
|
|
|
2019-09-22 21:19:10 +00:00
|
|
|
if (!v->display_name || !*v->display_name || !*info.id ||
|
2018-02-19 19:54:37 +00:00
|
|
|
!info.output_flags)
|
|
|
|
goto fail;
|
|
|
|
|
2019-09-22 21:19:10 +00:00
|
|
|
#define get_callback(val) \
|
|
|
|
do { \
|
|
|
|
get_callback_from_table(script, -1, #val, &v->func_##val); \
|
|
|
|
info.val = obs_lua_source_##val; \
|
2018-02-19 19:54:37 +00:00
|
|
|
} while (false)
|
|
|
|
|
|
|
|
get_callback(create);
|
|
|
|
get_callback(destroy);
|
|
|
|
get_callback(get_width);
|
|
|
|
get_callback(get_height);
|
|
|
|
get_callback(get_properties);
|
|
|
|
get_callback(update);
|
|
|
|
get_callback(activate);
|
|
|
|
get_callback(deactivate);
|
|
|
|
get_callback(show);
|
|
|
|
get_callback(hide);
|
|
|
|
get_callback(video_tick);
|
|
|
|
get_callback(video_render);
|
|
|
|
get_callback(save);
|
|
|
|
get_callback(load);
|
|
|
|
#undef get_callback
|
|
|
|
|
|
|
|
get_callback_from_table(script, -1, "get_defaults",
|
2019-09-22 21:19:10 +00:00
|
|
|
&v->func_get_defaults);
|
2018-02-19 19:54:37 +00:00
|
|
|
|
|
|
|
if (!existing) {
|
|
|
|
ls.data = current_lua_script;
|
|
|
|
|
2019-09-22 21:19:10 +00:00
|
|
|
pthread_mutexattr_t mutexattr;
|
|
|
|
pthread_mutexattr_init(&mutexattr);
|
|
|
|
pthread_mutexattr_settype(&mutexattr, PTHREAD_MUTEX_RECURSIVE);
|
|
|
|
pthread_mutex_init(&ls.definition_mutex, &mutexattr);
|
|
|
|
pthread_mutexattr_destroy(&mutexattr);
|
|
|
|
|
|
|
|
info.type_data = bmemdup(&ls, sizeof(ls));
|
2018-02-19 19:54:37 +00:00
|
|
|
info.free_type_data = obs_lua_source_free_type_data;
|
2019-09-22 21:19:10 +00:00
|
|
|
info.get_name = obs_lua_source_get_name;
|
|
|
|
info.get_defaults2 = obs_lua_source_get_defaults;
|
2018-02-19 19:54:37 +00:00
|
|
|
obs_register_source(&info);
|
|
|
|
|
|
|
|
pthread_mutex_lock(&lua_source_def_mutex);
|
|
|
|
v = info.type_data;
|
|
|
|
|
|
|
|
struct obs_lua_source *next = first_source_def;
|
|
|
|
v->next = next;
|
2019-09-22 21:19:10 +00:00
|
|
|
if (next)
|
|
|
|
next->p_prev_next = &v->next;
|
2018-02-19 19:54:37 +00:00
|
|
|
v->p_prev_next = &first_source_def;
|
|
|
|
first_source_def = v;
|
|
|
|
|
|
|
|
pthread_mutex_unlock(&lua_source_def_mutex);
|
|
|
|
} else {
|
|
|
|
existing->script = script;
|
|
|
|
existing->data = current_lua_script;
|
|
|
|
obs_enable_source_type(id, true);
|
|
|
|
|
|
|
|
struct obs_lua_data *ld = v->first_source;
|
|
|
|
while (ld) {
|
|
|
|
struct obs_lua_source *ls = v;
|
|
|
|
|
|
|
|
if (have_func(create)) {
|
|
|
|
obs_source_t *source = ld->source;
|
2019-09-22 21:19:10 +00:00
|
|
|
obs_data_t *settings =
|
|
|
|
obs_source_get_settings(source);
|
2018-02-19 19:54:37 +00:00
|
|
|
|
|
|
|
ls_push_libobs_obj(obs_data_t, settings, false);
|
|
|
|
ls_push_libobs_obj(obs_source_t, source, false);
|
|
|
|
call_func(create, 2, 1);
|
|
|
|
|
2019-09-22 21:19:10 +00:00
|
|
|
ld->lua_data_ref =
|
|
|
|
luaL_ref(ls->script, LUA_REGISTRYINDEX);
|
2018-02-19 19:54:37 +00:00
|
|
|
obs_data_release(settings);
|
|
|
|
}
|
|
|
|
|
|
|
|
ld = ld->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fail:
|
|
|
|
if (existing) {
|
|
|
|
pthread_mutex_unlock(&existing->definition_mutex);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ========================================================================= */
|
|
|
|
|
|
|
|
void add_lua_source_functions(lua_State *script)
|
|
|
|
{
|
|
|
|
lua_getglobal(script, "obslua");
|
|
|
|
|
|
|
|
lua_pushstring(script, "obs_register_source");
|
|
|
|
lua_pushcfunction(script, obs_lua_register_source);
|
|
|
|
lua_rawset(script, -3);
|
|
|
|
|
|
|
|
lua_pop(script, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void undef_source_type(struct obs_lua_script *data,
|
2019-09-22 21:19:10 +00:00
|
|
|
struct obs_lua_source *ls)
|
2018-02-19 19:54:37 +00:00
|
|
|
{
|
|
|
|
pthread_mutex_lock(&ls->definition_mutex);
|
|
|
|
pthread_mutex_lock(&data->mutex);
|
|
|
|
|
|
|
|
obs_enable_source_type(ls->id, false);
|
|
|
|
|
|
|
|
struct obs_lua_data *ld = ls->first_source;
|
|
|
|
while (ld) {
|
|
|
|
call_destroy(ld);
|
|
|
|
ld = ld->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
source_type_unload(ls);
|
|
|
|
ls->script = NULL;
|
|
|
|
|
|
|
|
pthread_mutex_unlock(&data->mutex);
|
|
|
|
pthread_mutex_unlock(&ls->definition_mutex);
|
|
|
|
}
|
|
|
|
|
|
|
|
void undef_lua_script_sources(struct obs_lua_script *data)
|
|
|
|
{
|
|
|
|
pthread_mutex_lock(&lua_source_def_mutex);
|
|
|
|
|
|
|
|
struct obs_lua_source *def = first_source_def;
|
|
|
|
while (def) {
|
|
|
|
if (def->script == data->script)
|
|
|
|
undef_source_type(data, def);
|
|
|
|
def = def->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
pthread_mutex_unlock(&lua_source_def_mutex);
|
|
|
|
}
|