deps/obs-scripting: Add scripting support

Allows Lua/Python scripting support.
master
jp9000 2017-12-25 14:09:11 -08:00
parent fd9e5d45a3
commit 9eabfdbf1e
25 changed files with 6559 additions and 0 deletions

3
.gitignore vendored
View File

@ -45,6 +45,9 @@ install-sh
Makefile.in
Makefile
#python
__pycache__
#sphinx
/docs/sphinx/_build/*
!/docs/sphinx/_build/.gitignore

View File

@ -20,6 +20,7 @@ if(WIN32)
endif()
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/")
set(ENABLE_SCRIPTING OFF CACHE BOOL "" FORCE)
include(ObsHelpers)
include(ObsCpack)

1
deps/CMakeLists.txt vendored
View File

@ -12,6 +12,7 @@ endif()
add_subdirectory(media-playback)
add_subdirectory(file-updater)
add_subdirectory(obs-scripting)
if(WIN32)
add_subdirectory(blake2)

173
deps/obs-scripting/CMakeLists.txt vendored Normal file
View File

@ -0,0 +1,173 @@
cmake_minimum_required(VERSION 2.8)
project(obs-scripting)
if(MSVC)
set(obs-scripting_PLATFORM_DEPS
w32-pthreads)
endif()
find_package(Luajit QUIET)
find_package(PythonLibs QUIET 3.4)
find_package(SWIG QUIET 2)
set(COMPILE_PYTHON FALSE CACHE BOOL "" FORCE)
set(COMPILE_LUA FALSE CACHE BOOL "" FORCE)
if(NOT SWIG_FOUND)
message(STATUS "Scripting: SWIG not found; scripting disabled")
return()
endif()
if(NOT PYTHONLIBS_FOUND AND NOT LUAJIT_FOUND)
message(STATUS "Scripting: Neither Python 3 nor Luajit was found; scripting plugin disabled")
return()
endif()
if(NOT LUAJIT_FOUND)
message(STATUS "Scripting: Luajit not found; Luajit support disabled")
else()
message(STATUS "Scripting: Luajit supported")
set(COMPILE_LUA TRUE CACHE BOOL "" FORCE)
endif()
if(NOT PYTHONLIBS_FOUND)
message(STATUS "Scripting: Python 3 not found; Python support disabled")
set(PYTHON_FOUND FALSE)
set(PYTHONLIBS_FOUND FALSE)
else()
message(STATUS "Scripting: Python 3 supported")
set(PYTHON_FOUND TRUE)
set(COMPILE_PYTHON TRUE CACHE BOOL "" FORCE)
get_filename_component(PYTHON_LIB "${PYTHON_LIBRARIES}" NAME)
string(REGEX REPLACE "\\.[^.]*$" "" PYTHON_LIB ${PYTHON_LIB})
if(WIN32)
string(REGEX REPLACE "_d" "" PYTHON_LIB "${PYTHON_LIB}")
endif()
endif()
set(ENABLE_SCRIPTING ON CACHE BOOL "" FORCE)
if(UI_ENABLED)
set(EXTRA_LIBS obs-frontend-api)
include_directories(SYSTEM "${CMAKE_SOURCE_DIR}/UI/obs-frontend-api")
endif()
configure_file(
"${CMAKE_CURRENT_SOURCE_DIR}/obs-scripting-config.h.in"
"${CMAKE_CURRENT_BINARY_DIR}/obs-scripting-config.h")
include(${SWIG_USE_FILE})
include_directories(${CMAKE_SOURCE_DIR}/libobs)
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
include_directories(${CMAKE_CURRENT_BINARY_DIR})
if(PYTHONLIBS_FOUND)
include_directories(${PYTHON_INCLUDE_DIR})
set(obs-scripting-python_SOURCES
obs-scripting-python.c
)
set(obs-scripting-python_HEADERS
obs-scripting-python.h
obs-scripting-python-import.h
)
if(UI_ENABLED)
set(obs-scripting-python_SOURCES
${obs-scripting-python_SOURCES}
obs-scripting-python-frontend.c
)
endif()
if(WIN32 OR APPLE)
set(obs-scripting-python_SOURCES
${obs-scripting-python_SOURCES}
obs-scripting-python-import.c
)
else()
set(EXTRA_LIBS ${EXTRA_LIBS} ${PYTHON_LIBRARIES})
endif()
endif()
if(LUAJIT_FOUND)
include_directories(${LUAJIT_INCLUDE_DIR})
set(obs-scripting-lua_SOURCES
obs-scripting-lua.c
obs-scripting-lua-source.c
)
set(obs-scripting-lua_HEADERS
obs-scripting-lua.h
)
if(UI_ENABLED)
set(obs-scripting-lua_SOURCES
${obs-scripting-lua_SOURCES}
obs-scripting-lua-frontend.c
)
endif()
endif()
set(obs-scripting_SOURCES
obs-scripting.c
obs-scripting-logging.c
cstrcache.cpp
)
set(obs-scripting_HEADERS
${CMAKE_CURRENT_BINARY_DIR}/obs-scripting-config.h
obs-scripting.h
obs-scripting-callback.h
cstrcache.h
)
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/swig)
if(PYTHONLIBS_FOUND)
set(SWIG_PY_RUNTIME swig/swigpyrun.h)
add_custom_command(OUTPUT ${SWIG_PY_RUNTIME}
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
PRE_BUILD
COMMAND ${SWIG_EXECUTABLE} -python -external-runtime ${SWIG_PY_RUNTIME}
COMMENT "Scripting plugin: Building Python SWIG interface header"
)
set_source_files_properties(${SWIG_PY_RUNTIME} PROPERTIES GENERATED TRUE)
endif()
if(LUAJIT_FOUND)
set(SWIG_LUA_RUNTIME swig/swigluarun.h)
add_custom_command(OUTPUT ${SWIG_LUA_RUNTIME}
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
PRE_BUILD
COMMAND ${SWIG_EXECUTABLE} -lua -external-runtime ${SWIG_LUA_RUNTIME}
COMMENT "Scripting: Building Lua SWIG interface header"
)
set_source_files_properties(${SWIG_LUA_RUNTIME} PROPERTIES GENERATED TRUE)
endif()
add_library(obs-scripting SHARED
${obs-scripting_SOURCES}
${obs-scripting_HEADERS}
${obs-scripting-python_SOURCES}
${obs-scripting-python_HEADERS}
${obs-scripting-lua_SOURCES}
${obs-scripting-lua_HEADERS}
${SWIG_PY_RUNTIME}
${SWIG_LUA_RUNTIME}
)
target_link_libraries(obs-scripting
libobs
${LUAJIT_LIBRARIES}
${EXTRA_LIBS}
${obs-scripting_PLATFORM_DEPS}
)
if(PYTHONLIBS_FOUND)
add_subdirectory(obspython)
endif()
if(LUAJIT_FOUND)
add_subdirectory(obslua)
endif()
install_obs_core(obs-scripting)

28
deps/obs-scripting/cstrcache.cpp vendored Normal file
View File

@ -0,0 +1,28 @@
#include <unordered_map>
#include <string>
#include "cstrcache.h"
using namespace std;
struct const_string_table {
unordered_map<string, string> strings;
};
static struct const_string_table table;
const char *cstrcache_get(const char *str)
{
if (!str || !*str)
return "";
auto &strings = table.strings;
auto pair = strings.find(str);
if (pair == strings.end()) {
strings[str] = str;
pair = strings.find(str);
}
return pair->second.c_str();
}

13
deps/obs-scripting/cstrcache.h vendored Normal file
View File

@ -0,0 +1,13 @@
#pragma once
/* simple constant string cache table using STL unordered_map as storage */
#ifdef __cplusplus
extern "C" {
#endif
extern const char *cstrcache_get(const char *str);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,91 @@
/******************************************************************************
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/>.
******************************************************************************/
#pragma once
#include <callback/calldata.h>
#include <util/threading.h>
#include <util/bmem.h>
#include "obs-scripting-internal.h"
extern pthread_mutex_t detach_mutex;
extern struct script_callback *detached_callbacks;
struct script_callback {
struct script_callback *next;
struct script_callback **p_prev_next;
void (*on_remove)(void *p_cb);
obs_script_t *script;
calldata_t extra;
bool removed;
};
static inline void *add_script_callback(
struct script_callback **first,
obs_script_t *script,
size_t extra_size)
{
struct script_callback *cb = bzalloc(sizeof(*cb) + extra_size);
cb->script = script;
struct script_callback *next = *first;
cb->next = next;
cb->p_prev_next = first;
if (next) next->p_prev_next = &cb->next;
*first = cb;
return cb;
}
static inline void remove_script_callback(struct script_callback *cb)
{
cb->removed = true;
struct script_callback *next = cb->next;
if (next) next->p_prev_next = cb->p_prev_next;
*cb->p_prev_next = cb->next;
pthread_mutex_lock(&detach_mutex);
next = detached_callbacks;
cb->next = next;
if (next) next->p_prev_next = &cb->next;
cb->p_prev_next = &detached_callbacks;
detached_callbacks = cb;
pthread_mutex_unlock(&detach_mutex);
if (cb->on_remove)
cb->on_remove(cb);
}
static inline void just_free_script_callback(struct script_callback *cb)
{
calldata_free(&cb->extra);
bfree(cb);
}
static inline void free_script_callback(struct script_callback *cb)
{
pthread_mutex_lock(&detach_mutex);
struct script_callback *next = cb->next;
if (next) next->p_prev_next = cb->p_prev_next;
*cb->p_prev_next = cb->next;
pthread_mutex_unlock(&detach_mutex);
just_free_script_callback(cb);
}

View File

@ -0,0 +1,22 @@
#pragma once
#ifndef TRUE
#define TRUE 1
#endif
#ifndef ON
#define ON 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
#ifndef OFF
#define OFF 0
#endif
#define PYTHON_LIB "@PYTHON_LIB@"
#define COMPILE_LUA @LUAJIT_FOUND@
#define COMPILE_PYTHON @PYTHON_FOUND@
#define UI_ENABLED @UI_ENABLED@

View File

@ -0,0 +1,51 @@
/******************************************************************************
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/>.
******************************************************************************/
#pragma once
#include <util/dstr.h>
#include <callback/calldata.h>
#include "obs-scripting.h"
struct obs_script {
enum obs_script_lang type;
bool loaded;
obs_data_t *settings;
struct dstr path;
struct dstr file;
struct dstr desc;
};
struct script_callback;
typedef void (*defer_call_cb)(void *param);
extern void defer_call_post(defer_call_cb call, void *cb);
extern void script_log(obs_script_t *script, int level, const char *format, ...);
extern void script_log_va(obs_script_t *script, int level, const char *format,
va_list args);
#define script_error(script, format, ...) \
script_log(script, LOG_ERROR, format, ##__VA_ARGS__)
#define script_warn(script, format, ...) \
script_log(script, LOG_WARNING, format, ##__VA_ARGS__)
#define script_info(script, format, ...) \
script_log(script, LOG_INFO, format, ##__VA_ARGS__)
#define script_debug(script, format, ...) \
script_log(script, LOG_DEBUG, format, ##__VA_ARGS__)

View File

@ -0,0 +1,59 @@
/******************************************************************************
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-internal.h"
#include <util/platform.h>
static scripting_log_handler_t callback = NULL;
static void *param = NULL;
void script_log_va(obs_script_t *script, int level, const char *format,
va_list args)
{
char msg[2048];
const char *lang = "(Unknown)";
size_t start_len;
switch (script->type) {
case OBS_SCRIPT_LANG_UNKNOWN: lang = "(Unknown language)"; break;
case OBS_SCRIPT_LANG_LUA: lang = "Lua"; break;
case OBS_SCRIPT_LANG_PYTHON: lang = "Python"; break;
}
start_len = snprintf(msg, sizeof(msg), "[%s: %s] ",
lang, script->file.array);
vsnprintf(msg + start_len, sizeof(msg) - start_len, format, args);
if (callback)
callback(param, script, level, msg + start_len);
blog(level, "%s", msg);
}
void script_log(obs_script_t *script, int level, const char *format, ...)
{
va_list args;
va_start(args, format);
script_log_va(script, level, format, args);
va_end(args);
}
void obs_scripting_set_log_callback(scripting_log_handler_t handler,
void *log_param)
{
callback = handler;
param = log_param;
}

View File

@ -0,0 +1,315 @@
/******************************************************************************
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-module.h>
#include <obs-frontend-api.h>
#include "obs-scripting-lua.h"
#define ls_get_libobs_obj(type, lua_index, obs_obj) \
ls_get_libobs_obj_(script, #type " *", lua_index, obs_obj, \
NULL, __FUNCTION__, __LINE__)
#define ls_push_libobs_obj(type, obs_obj, ownership) \
ls_push_libobs_obj_(script, #type " *", obs_obj, ownership, \
NULL, __FUNCTION__, __LINE__)
#define call_func(func, args, rets) \
call_func_(script, cb->reg_idx, args, rets, #func, "frontend API")
/* ----------------------------------- */
static int get_scene_names(lua_State *script)
{
char **names = obs_frontend_get_scene_names();
char **name = names;
int i = 0;
lua_newtable(script);
while (name && *name) {
lua_pushstring(script, *name);
lua_rawseti(script, -2, i++);
name++;
}
bfree(names);
return 1;
}
static int get_scenes(lua_State *script)
{
struct obs_frontend_source_list list = {0};
obs_frontend_get_scenes(&list);
lua_createtable(script, (int)list.sources.num, 0);
for (size_t i = 0; i < list.sources.num; i++) {
obs_source_t *source = list.sources.array[i];
ls_push_libobs_obj(obs_source_t, source, false);
lua_rawseti(script, -2, (int)i++);
}
da_free(list.sources);
return 1;
}
static int get_current_scene(lua_State *script)
{
obs_source_t *source = obs_frontend_get_current_scene();
ls_push_libobs_obj(obs_source_t, source, false);
return 1;
}
static int set_current_scene(lua_State *script)
{
obs_source_t *source = NULL;
ls_get_libobs_obj(obs_source_t, 1, &source);
obs_frontend_set_current_scene(source);
return 0;
}
static int get_transitions(lua_State *script)
{
struct obs_frontend_source_list list = {0};
obs_frontend_get_transitions(&list);
lua_createtable(script, (int)list.sources.num, 0);
for (size_t i = 0; i < list.sources.num; i++) {
obs_source_t *source = list.sources.array[i];
ls_push_libobs_obj(obs_source_t, source, false);
lua_rawseti(script, -2, (int)i++);
}
da_free(list.sources);
return 1;
}
static int get_current_transition(lua_State *script)
{
obs_source_t *source = obs_frontend_get_current_transition();
ls_push_libobs_obj(obs_source_t, source, false);
return 1;
}
static int set_current_transition(lua_State *script)
{
obs_source_t *source = NULL;
ls_get_libobs_obj(obs_source_t, 1, &source);
obs_frontend_set_current_transition(source);
return 0;
}
static int get_scene_collections(lua_State *script)
{
char **names = obs_frontend_get_scene_collections();
char **name = names;
int i = 0;
lua_newtable(script);
while (name && *name) {
lua_pushstring(script, *name);
lua_rawseti(script, -2, i++);
name++;
}
bfree(names);
return 1;
}
static int get_current_scene_collection(lua_State *script)
{
char *name = obs_frontend_get_current_scene_collection();
lua_pushstring(script, name);
bfree(name);
return 1;
}
static int set_current_scene_collection(lua_State *script)
{
if (lua_isstring(script, 1)) {
const char *name = lua_tostring(script, 1);
obs_frontend_set_current_scene_collection(name);
}
return 0;
}
static int get_profiles(lua_State *script)
{
char **names = obs_frontend_get_profiles();
char **name = names;
int i = 0;
lua_newtable(script);
while (name && *name) {
lua_pushstring(script, *name);
lua_rawseti(script, -2, i++);
name++;
}
bfree(names);
return 1;
}
static int get_current_profile(lua_State *script)
{
char *name = obs_frontend_get_current_profile();
lua_pushstring(script, name);
bfree(name);
return 1;
}
static int set_current_profile(lua_State *script)
{
if (lua_isstring(script, 1)) {
const char *name = lua_tostring(script, 1);
obs_frontend_set_current_profile(name);
}
return 0;
}
/* ----------------------------------- */
static void frontend_event_callback(enum obs_frontend_event event, void *priv)
{
struct lua_obs_callback *cb = priv;
lua_State *script = cb->script;
if (cb->base.removed) {
obs_frontend_remove_event_callback(frontend_event_callback, cb);
return;
}
lock_callback();
lua_pushinteger(script, (int)event);
call_func(frontend_event_callback, 1, 0);
unlock_callback();
}
static int remove_event_callback(lua_State *script)
{
if (!verify_args1(script, is_function))
return 0;
struct lua_obs_callback *cb = find_lua_obs_callback(script, 1);
if (cb) {
remove_lua_obs_callback(cb);
}
return 0;
}
static void add_event_callback_defer(void *cb)
{
obs_frontend_add_event_callback(frontend_event_callback, cb);
}
static int add_event_callback(lua_State *script)
{
if (!verify_args1(script, is_function))
return 0;
struct lua_obs_callback *cb = add_lua_obs_callback(script, 1);
defer_call_post(add_event_callback_defer, cb);
return 0;
}
/* ----------------------------------- */
static void frontend_save_callback(obs_data_t *save_data, bool saving,
void *priv)
{
struct lua_obs_callback *cb = priv;
lua_State *script = cb->script;
if (cb->base.removed) {
obs_frontend_remove_save_callback(frontend_save_callback, cb);
return;
}
lock_callback();
ls_push_libobs_obj(obs_data_t, save_data, false);
lua_pushboolean(script, saving);
call_func(frontend_save_callback, 2, 0);
unlock_callback();
}
static int remove_save_callback(lua_State *script)
{
if (!verify_args1(script, is_function))
return 0;
struct lua_obs_callback *cb = find_lua_obs_callback(script, 1);
if (cb) {
remove_lua_obs_callback(cb);
}
return 0;
}
static void add_save_callback_defer(void *cb)
{
obs_frontend_add_save_callback(frontend_save_callback, cb);
}
static int add_save_callback(lua_State *script)
{
if (!verify_args1(script, is_function))
return 0;
struct lua_obs_callback *cb = add_lua_obs_callback(script, 1);
defer_call_post(add_save_callback_defer, cb);
return 0;
}
/* ----------------------------------- */
void add_lua_frontend_funcs(lua_State *script)
{
lua_getglobal(script, "obslua");
#define add_func(name) \
do { \
lua_pushstring(script, "obs_frontend_" #name); \
lua_pushcfunction(script, name); \
lua_rawset(script, -3); \
} while (false)
add_func(get_scene_names);
add_func(get_scenes);
add_func(get_current_scene);
add_func(set_current_scene);
add_func(get_transitions);
add_func(get_current_transition);
add_func(set_current_transition);
add_func(get_scene_collections);
add_func(get_current_scene_collection);
add_func(set_current_scene_collection);
add_func(get_profiles);
add_func(get_current_profile);
add_func(set_current_profile);
add_func(remove_event_callback);
add_func(add_event_callback);
add_func(remove_save_callback);
add_func(add_save_callback);
#undef add_func
lua_pop(script, 1);
}

View File

@ -0,0 +1,762 @@
/******************************************************************************
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,
const char *name, const char *func)
{
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;
}
static inline int get_table_int_(lua_State *script, int idx,
const char *name, const char *func)
{
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,
const char *name, int *p_reg_idx, const char *func)
{
*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__)
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)
{
swig_type_info *info = SWIG_TypeQuery(script, type);
if (info == NULL) {
warn("%s:%d: SWIG could not find type: %s%s%s",
func,
line,
id ? id : "",
id ? "::" : "",
type);
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",
func,
line,
id ? id : "",
id ? "::" : "",
type);
return false;
}
return true;
}
#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)
{
swig_type_info *info = SWIG_TypeQuery(script, type);
if (info == NULL) {
warn("%s:%d: SWIG could not find type: %s%s%s",
func,
line,
id ? id : "",
id ? "::" : "",
type);
return false;
}
SWIG_NewPointerObj(script, libobs_in, info, (int)ownership);
return true;
}
#define ls_push_libobs_obj(type, obs_obj, ownership) \
ls_push_libobs_obj_(ls->script, #type " *", obs_obj, ownership, \
ls->id, __FUNCTION__, __LINE__)
/* ========================================================================= */
struct obs_lua_data;
struct obs_lua_source {
struct obs_lua_script *data;
lua_State * script;
const char *id;
const char *display_name;
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;
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 {
obs_source_t * source;
struct obs_lua_source *ls;
int lua_data_ref;
struct obs_lua_data *next;
struct obs_lua_data **p_prev_next;
};
#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)
#define ls_push_data() \
lua_rawgeti(ls->script, LUA_REGISTRYINDEX, ld->lua_data_ref)
#define ls_pop(count) \
lua_pop(ls->script, count)
#define lock_script() \
struct obs_lua_script *__data = ls->data; \
struct obs_lua_script *__prev_script = current_lua_script; \
current_lua_script = __data; \
pthread_mutex_lock(&__data->mutex);
#define unlock_script() \
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) {
data = bmalloc(sizeof(*data));
data->source = source;
data->ls = ls;
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;
if (next) next->p_prev_next = &data->next;
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)
{
struct obs_lua_data * ld = data;
struct obs_lua_source *ls = ld->ls;
struct obs_lua_data * next;
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;
if (next) next->p_prev_next = ld->p_prev_next;
bfree(data);
pthread_mutex_unlock(&ls->definition_mutex);
}
static uint32_t obs_lua_source_get_width(void *data)
{
struct obs_lua_data * ld = data;
struct obs_lua_source *ls = ld->ls;
uint32_t width = 0;
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)
{
struct obs_lua_data * ld = data;
struct obs_lua_source *ls = ld->ls;
uint32_t height = 0;
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)
{
struct obs_lua_data * ld = data;
struct obs_lua_source *ls = ld->ls;
obs_properties_t * props = NULL;
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)
{
struct obs_lua_data * ld = data;
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);
}
#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(); \
}
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)
{
struct obs_lua_data * ld = data;
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)
{
struct obs_lua_data * ld = data;
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)
{
struct obs_lua_data * ld = data;
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)
{
struct obs_lua_data * ld = data;
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)
{
#define unref(name) \
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;
v->id = id;
info.id = v->id;
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);
}
if (!v->display_name ||
!*v->display_name ||
!*info.id ||
!info.output_flags)
goto fail;
#define get_callback(val) \
do { \
get_callback_from_table(script, -1, #val, &v->func_ ## val); \
info.val = obs_lua_source_ ## val; \
} 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",
&v->func_get_defaults);
if (!existing) {
ls.data = current_lua_script;
pthread_mutex_init(&ls.definition_mutex, NULL);
info.type_data = bmemdup(&ls, sizeof(ls));
info.free_type_data = obs_lua_source_free_type_data;
info.get_name = obs_lua_source_get_name;
info.get_defaults2 = obs_lua_source_get_defaults;
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;
if (next) next->p_prev_next = &v->next;
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;
obs_data_t *settings = obs_source_get_settings(
source);
ls_push_libobs_obj(obs_data_t, settings, false);
ls_push_libobs_obj(obs_source_t, source, false);
call_func(create, 2, 1);
ld->lua_data_ref = luaL_ref(ls->script,
LUA_REGISTRYINDEX);
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,
struct obs_lua_source *ls)
{
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);
}

1287
deps/obs-scripting/obs-scripting-lua.c vendored Normal file

File diff suppressed because it is too large Load Diff

262
deps/obs-scripting/obs-scripting-lua.h vendored Normal file
View File

@ -0,0 +1,262 @@
/******************************************************************************
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/>.
******************************************************************************/
#pragma once
/* ---------------------------- */
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable : 4244)
#pragma warning(disable : 4267)
#endif
#define SWIG_TYPE_TABLE obslua
#include "swig/swigluarun.h"
#ifdef _MSC_VER
#pragma warning(pop)
#endif
/* ---------------------------- */
#include <util/threading.h>
#include <util/base.h>
#include <util/bmem.h>
#include "obs-scripting-internal.h"
#include "obs-scripting-callback.h"
#define do_log(level, format, ...) \
blog(level, "[Lua] " format, ##__VA_ARGS__)
#define warn(format, ...) do_log(LOG_WARNING, format, ##__VA_ARGS__)
#define info(format, ...) do_log(LOG_INFO, format, ##__VA_ARGS__)
#define debug(format, ...) do_log(LOG_DEBUG, format, ##__VA_ARGS__)
/* ------------------------------------------------------------ */
struct obs_lua_script;
struct lua_obs_callback;
extern THREAD_LOCAL struct lua_obs_callback *current_lua_cb;
extern THREAD_LOCAL struct obs_lua_script *current_lua_script;
/* ------------------------------------------------------------ */
struct lua_obs_callback;
struct obs_lua_script {
obs_script_t base;
struct dstr dir;
struct dstr log_chunk;
pthread_mutex_t mutex;
lua_State *script;
struct script_callback *first_callback;
int update;
int get_properties;
int save;
int tick;
struct obs_lua_script *next_tick;
struct obs_lua_script **p_prev_next_tick;
bool defined_sources;
};
#define lock_callback() \
struct obs_lua_script *__last_script = current_lua_script; \
struct lua_obs_callback *__last_callback = current_lua_cb; \
current_lua_cb = cb; \
current_lua_script = (struct obs_lua_script *)cb->base.script; \
pthread_mutex_lock(&current_lua_script->mutex);
#define unlock_callback() \
pthread_mutex_unlock(&current_lua_script->mutex); \
current_lua_script = __last_script; \
current_lua_cb = __last_callback;
/* ------------------------------------------------ */
struct lua_obs_callback {
struct script_callback base;
lua_State *script;
int reg_idx;
};
static inline struct lua_obs_callback *add_lua_obs_callback_extra(
lua_State *script,
int stack_idx,
size_t extra_size)
{
struct obs_lua_script *data = current_lua_script;
struct lua_obs_callback *cb = add_script_callback(
&data->first_callback,
(obs_script_t *)data,
sizeof(*cb) + extra_size);
lua_pushvalue(script, stack_idx);
cb->reg_idx = luaL_ref(script, LUA_REGISTRYINDEX);
cb->script = script;
return cb;
}
static inline struct lua_obs_callback *add_lua_obs_callback(
lua_State *script, int stack_idx)
{
return add_lua_obs_callback_extra(script, stack_idx, 0);
}
static inline void *lua_obs_callback_extra_data(struct lua_obs_callback *cb)
{
return (void*)&cb[1];
}
static inline struct obs_lua_script *lua_obs_callback_script(
struct lua_obs_callback *cb)
{
return (struct obs_lua_script *)cb->base.script;
}
static inline struct lua_obs_callback *find_next_lua_obs_callback(
lua_State *script, struct lua_obs_callback *cb, int stack_idx)
{
struct obs_lua_script *data = current_lua_script;
cb = cb ? (struct lua_obs_callback *)cb->base.next
: (struct lua_obs_callback *)data->first_callback;
while (cb) {
lua_rawgeti(script, LUA_REGISTRYINDEX, cb->reg_idx);
bool match = lua_rawequal(script, -1, stack_idx);
lua_pop(script, 1);
if (match)
break;
cb = (struct lua_obs_callback *)cb->base.next;
}
return cb;
}
static inline struct lua_obs_callback *find_lua_obs_callback(
lua_State *script, int stack_idx)
{
return find_next_lua_obs_callback(script, NULL, stack_idx);
}
static inline void remove_lua_obs_callback(struct lua_obs_callback *cb)
{
remove_script_callback(&cb->base);
luaL_unref(cb->script, LUA_REGISTRYINDEX, cb->reg_idx);
}
static inline void just_free_lua_obs_callback(struct lua_obs_callback *cb)
{
just_free_script_callback(&cb->base);
}
static inline void free_lua_obs_callback(struct lua_obs_callback *cb)
{
free_script_callback(&cb->base);
}
/* ------------------------------------------------ */
static int is_ptr(lua_State *script, int idx)
{
return lua_isuserdata(script, idx) || lua_isnil(script, idx);
}
static int is_table(lua_State *script, int idx)
{
return lua_istable(script, idx);
}
static int is_function(lua_State *script, int idx)
{
return lua_isfunction(script, idx);
}
typedef int (*param_cb)(lua_State *script, int idx);
static inline bool verify_args1_(lua_State *script,
param_cb param1_check,
const char *func)
{
if (lua_gettop(script) != 1) {
warn("Wrong number of parameters for %s", func);
return false;
}
if (!param1_check(script, 1)) {
warn("Wrong parameter type for parameter %d of %s", 1, func);
return false;
}
return true;
}
#define verify_args1(script, param1_check) \
verify_args1_(script, param1_check, __FUNCTION__)
static inline bool call_func_(lua_State *script,
int reg_idx, int args, int rets,
const char *func, const char *display_name)
{
if (reg_idx == LUA_REFNIL)
return false;
struct obs_lua_script *data = current_lua_script;
lua_rawgeti(script, LUA_REGISTRYINDEX, reg_idx);
lua_insert(script, -1 - args);
if (lua_pcall(script, args, rets, 0) != 0) {
script_warn(&data->base, "Failed to call %s for %s: %s", func,
display_name,
lua_tostring(script, -1));
lua_pop(script, 1);
return false;
}
return true;
}
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);
bool ls_push_libobs_obj_(lua_State * script,
const char *type,
void * libobs_in,
bool ownership,
const char *id,
const char *func,
int line);
extern void add_lua_source_functions(lua_State *script);

View File

@ -0,0 +1,361 @@
/******************************************************************************
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-module.h>
#include <obs-frontend-api.h>
#include "obs-scripting-python.h"
#define libobs_to_py(type, obs_obj, ownership, py_obj) \
libobs_to_py_(#type " *", obs_obj, ownership, py_obj, \
NULL, __func__, __LINE__)
#define py_to_libobs(type, py_obj, libobs_out) \
py_to_libobs_(#type " *", py_obj, libobs_out, \
NULL, __func__, __LINE__)
/* ----------------------------------- */
static PyObject *get_scene_names(PyObject *self, PyObject *args)
{
char **names = obs_frontend_get_scene_names();
char **name = names;
PyObject *list = PyList_New(0);
while (name && *name) {
PyObject *py_name = PyUnicode_FromString(*name);
if (py_name) {
PyList_Append(list, py_name);
Py_DECREF(py_name);
}
name++;
}
UNUSED_PARAMETER(self);
UNUSED_PARAMETER(args);
bfree(names);
return list;
}
static PyObject *get_scenes(PyObject *self, PyObject *args)
{
struct obs_frontend_source_list list = {0};
obs_frontend_get_scenes(&list);
PyObject *ret = PyList_New(0);
for (size_t i = 0; i < list.sources.num; i++) {
obs_source_t *source = list.sources.array[i];
PyObject *py_source;
if (libobs_to_py(obs_source_t, source, false, &py_source)) {
PyList_Append(ret, py_source);
Py_DECREF(py_source);
}
}
UNUSED_PARAMETER(self);
UNUSED_PARAMETER(args);
da_free(list.sources);
return ret;
}
static PyObject *get_current_scene(PyObject *self, PyObject *args)
{
obs_source_t *source = obs_frontend_get_current_scene();
PyObject *py_source;
if (!libobs_to_py(obs_source_t, source, false, &py_source)) {
obs_source_release(source);
return python_none();
}
UNUSED_PARAMETER(self);
UNUSED_PARAMETER(args);
return py_source;
}
static PyObject *set_current_scene(PyObject *self, PyObject *args)
{
PyObject *py_source;
obs_source_t *source = NULL;
if (!parse_args(args, "O", &py_source))
return python_none();
if (!py_to_libobs(obs_source_t, py_source, &source))
return python_none();
UNUSED_PARAMETER(self);
obs_frontend_set_current_scene(source);
return python_none();
}
static PyObject *get_transitions(PyObject *self, PyObject *args)
{
struct obs_frontend_source_list list = {0};
obs_frontend_get_transitions(&list);
PyObject *ret = PyList_New(0);
for (size_t i = 0; i < list.sources.num; i++) {
obs_source_t *source = list.sources.array[i];
PyObject *py_source;
if (libobs_to_py(obs_source_t, source, false, &py_source)) {
PyList_Append(ret, py_source);
Py_DECREF(py_source);
}
}
UNUSED_PARAMETER(self);
UNUSED_PARAMETER(args);
da_free(list.sources);
return ret;
}
static PyObject *get_current_transition(PyObject *self, PyObject *args)
{
obs_source_t *source = obs_frontend_get_current_transition();
PyObject *py_source;
if (!libobs_to_py(obs_source_t, source, false, &py_source)) {
obs_source_release(source);
return python_none();
}
UNUSED_PARAMETER(self);
UNUSED_PARAMETER(args);
return py_source;
}
static PyObject *set_current_transition(PyObject *self, PyObject *args)
{
PyObject *py_source;
obs_source_t *source = NULL;
if (!parse_args(args, "O", &py_source))
return python_none();
if (!py_to_libobs(obs_source_t, py_source, &source))
return python_none();
UNUSED_PARAMETER(self);
obs_frontend_set_current_transition(source);
return python_none();
}
static PyObject *get_scene_collections(PyObject *self, PyObject *args)
{
char **names = obs_frontend_get_scene_collections();
char **name = names;
PyObject *list = PyList_New(0);
while (name && *name) {
PyObject *py_name = PyUnicode_FromString(*name);
if (py_name) {
PyList_Append(list, py_name);
Py_DECREF(py_name);
}
name++;
}
UNUSED_PARAMETER(self);
UNUSED_PARAMETER(args);
bfree(names);
return list;
}
static PyObject *get_current_scene_collection(PyObject *self, PyObject *args)
{
char *name = obs_frontend_get_current_scene_collection();
PyObject *ret = PyUnicode_FromString(name);
bfree(name);
UNUSED_PARAMETER(self);
UNUSED_PARAMETER(args);
return ret;
}
static PyObject *set_current_scene_collection(PyObject *self, PyObject *args)
{
const char *name;
if (!parse_args(args, "s", &name))
return python_none();
UNUSED_PARAMETER(self);
obs_frontend_set_current_scene_collection(name);
return python_none();
}
static PyObject *get_profiles(PyObject *self, PyObject *args)
{
char **names = obs_frontend_get_profiles();
char **name = names;
PyObject *list = PyList_New(0);
while (name && *name) {
PyObject *py_name = PyUnicode_FromString(*name);
if (py_name) {
PyList_Append(list, py_name);
Py_DECREF(py_name);
}
name++;
}
UNUSED_PARAMETER(self);
UNUSED_PARAMETER(args);
bfree(names);
return list;
}
static PyObject *get_current_profile(PyObject *self, PyObject *args)
{
char *name = obs_frontend_get_current_profile();
PyObject *ret = PyUnicode_FromString(name);
bfree(name);
UNUSED_PARAMETER(self);
UNUSED_PARAMETER(args);
return ret;
}
static PyObject *set_current_profile(PyObject *self, PyObject *args)
{
const char *name;
if (!parse_args(args, "s", &name))
return python_none();
UNUSED_PARAMETER(self);
obs_frontend_set_current_profile(name);
return python_none();
}
/* ----------------------------------- */
static void frontend_save_callback(obs_data_t *save_data, bool saving,
void *priv)
{
struct python_obs_callback *cb = priv;
if (cb->base.removed) {
obs_frontend_remove_save_callback(frontend_save_callback, cb);
return;
}
lock_python();
PyObject *py_save_data;
if (libobs_to_py(obs_data_t, save_data, false, &py_save_data)) {
PyObject *args = Py_BuildValue("(Op)", py_save_data, saving);
struct python_obs_callback *last_cb = cur_python_cb;
cur_python_cb = cb;
cur_python_script = (struct obs_python_script *)cb->base.script;
PyObject *py_ret = PyObject_CallObject(cb->func, args);
Py_XDECREF(py_ret);
py_error();
cur_python_script = NULL;
cur_python_cb = last_cb;
Py_XDECREF(args);
Py_XDECREF(py_save_data);
}
unlock_python();
}
static PyObject *remove_save_callback(PyObject *self, PyObject *args)
{
struct obs_python_script *script = cur_python_script;
PyObject *py_cb = NULL;
UNUSED_PARAMETER(self);
if (!parse_args(args, "O", &py_cb))
return python_none();
if (!py_cb || !PyFunction_Check(py_cb))
return python_none();
struct python_obs_callback *cb = find_python_obs_callback(script, py_cb);
if (cb) remove_python_obs_callback(cb);
return python_none();
}
static void add_save_callback_defer(void *cb)
{
obs_frontend_add_save_callback(frontend_save_callback, cb);
}
static PyObject *add_save_callback(PyObject *self, PyObject *args)
{
struct obs_python_script *script = cur_python_script;
PyObject *py_cb = NULL;
UNUSED_PARAMETER(self);
if (!parse_args(args, "O", &py_cb))
return python_none();
if (!py_cb || !PyFunction_Check(py_cb))
return python_none();
struct python_obs_callback *cb = add_python_obs_callback(script, py_cb);
defer_call_post(add_save_callback_defer, cb);
return python_none();
}
/* ----------------------------------- */
void add_python_frontend_funcs(PyObject *module)
{
static PyMethodDef funcs[] = {
#define DEF_FUNC(c) {"obs_frontend_" #c, c, METH_VARARGS, NULL}
DEF_FUNC(get_scene_names),
DEF_FUNC(get_scenes),
DEF_FUNC(get_current_scene),
DEF_FUNC(set_current_scene),
DEF_FUNC(get_transitions),
DEF_FUNC(get_current_transition),
DEF_FUNC(set_current_transition),
DEF_FUNC(get_scene_collections),
DEF_FUNC(get_current_scene_collection),
DEF_FUNC(set_current_scene_collection),
DEF_FUNC(get_profiles),
DEF_FUNC(get_current_profile),
DEF_FUNC(set_current_profile),
DEF_FUNC(remove_save_callback),
DEF_FUNC(add_save_callback),
#undef DEF_FUNC
{0}
};
add_functions_to_py_module(module, funcs);
}

View File

@ -0,0 +1,149 @@
/******************************************************************************
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 <util/dstr.h>
#include <util/platform.h>
#define NO_REDEFS
#include "obs-scripting-python-import.h"
#include "obs-scripting-config.h"
#ifdef _MSC_VER
#pragma warning(disable : 4152)
#endif
#ifdef _WIN32
#define SO_EXT ".dll"
#elif __APPLE__
#define SO_EXT ".dylib"
#endif
bool import_python(const char *python_path)
{
struct dstr lib_path;
bool success = false;
void *lib;
if (!python_path)
python_path = "";
dstr_init_copy(&lib_path, python_path);
dstr_replace(&lib_path, "\\", "/");
if (!dstr_is_empty(&lib_path)) {
dstr_cat(&lib_path, "/");
}
dstr_cat(&lib_path, PYTHON_LIB SO_EXT);
lib = os_dlopen(lib_path.array);
if (!lib) {
blog(LOG_WARNING, "[Python] Could not load library: %s",
lib_path.array);
goto fail;
}
#define IMPORT_FUNC(x) \
do { \
Import_##x = os_dlsym(lib, #x); \
if (!Import_##x) { \
blog(LOG_WARNING, "[Python] Failed to import: %s", \
#x); \
goto fail; \
} \
} while (false)
IMPORT_FUNC(PyType_Ready);
IMPORT_FUNC(PyObject_GenericGetAttr);
IMPORT_FUNC(PyObject_IsTrue);
IMPORT_FUNC(Py_DecRef);
IMPORT_FUNC(PyObject_Malloc);
IMPORT_FUNC(PyObject_Free);
IMPORT_FUNC(PyObject_Init);
IMPORT_FUNC(PyUnicode_FromFormat);
IMPORT_FUNC(PyUnicode_Concat);
IMPORT_FUNC(PyLong_FromVoidPtr);
IMPORT_FUNC(PyBool_FromLong);
IMPORT_FUNC(PyGILState_Ensure);
IMPORT_FUNC(PyGILState_GetThisThreadState);
IMPORT_FUNC(PyErr_SetString);
IMPORT_FUNC(PyErr_Occurred);
IMPORT_FUNC(PyErr_Fetch);
IMPORT_FUNC(PyErr_Restore);
IMPORT_FUNC(PyErr_WriteUnraisable);
IMPORT_FUNC(PyArg_UnpackTuple);
IMPORT_FUNC(Py_BuildValue);
IMPORT_FUNC(PyRun_SimpleStringFlags);
IMPORT_FUNC(PyErr_Print);
IMPORT_FUNC(Py_SetPythonHome);
IMPORT_FUNC(Py_Initialize);
IMPORT_FUNC(Py_Finalize);
IMPORT_FUNC(Py_IsInitialized);
IMPORT_FUNC(PyEval_InitThreads);
IMPORT_FUNC(PyEval_ThreadsInitialized);
IMPORT_FUNC(PyEval_ReleaseThread);
IMPORT_FUNC(PySys_SetArgv);
IMPORT_FUNC(PyImport_ImportModule);
IMPORT_FUNC(PyObject_CallFunctionObjArgs);
IMPORT_FUNC(_Py_NotImplementedStruct);
IMPORT_FUNC(PyExc_TypeError);
IMPORT_FUNC(PyExc_RuntimeError);
IMPORT_FUNC(PyObject_GetAttr);
IMPORT_FUNC(PyUnicode_FromString);
IMPORT_FUNC(PyDict_GetItemString);
IMPORT_FUNC(PyDict_SetItemString);
IMPORT_FUNC(PyCFunction_NewEx);
IMPORT_FUNC(PyModule_GetDict);
IMPORT_FUNC(PyModule_GetNameObject);
IMPORT_FUNC(PyModule_AddObject);
IMPORT_FUNC(PyModule_AddStringConstant);
IMPORT_FUNC(PyImport_Import);
IMPORT_FUNC(PyObject_CallObject);
IMPORT_FUNC(_Py_FalseStruct);
IMPORT_FUNC(_Py_TrueStruct);
IMPORT_FUNC(PyGILState_Release);
IMPORT_FUNC(PyList_Append);
IMPORT_FUNC(PySys_GetObject);
IMPORT_FUNC(PyImport_ReloadModule);
IMPORT_FUNC(PyObject_GetAttrString);
IMPORT_FUNC(PyCapsule_New);
IMPORT_FUNC(PyCapsule_GetPointer);
IMPORT_FUNC(PyArg_ParseTuple);
IMPORT_FUNC(PyFunction_Type);
IMPORT_FUNC(PyObject_SetAttr);
IMPORT_FUNC(_PyObject_New);
IMPORT_FUNC(PyCapsule_Import);
IMPORT_FUNC(PyErr_Clear);
IMPORT_FUNC(PyObject_Call);
IMPORT_FUNC(PyList_New);
IMPORT_FUNC(PyList_Size);
IMPORT_FUNC(PyList_GetItem);
IMPORT_FUNC(PyUnicode_AsUTF8String);
IMPORT_FUNC(PyLong_FromUnsignedLongLong);
IMPORT_FUNC(PyArg_VaParse);
IMPORT_FUNC(_Py_NoneStruct);
#undef IMPORT_FUNC
success = true;
fail:
if (!success && lib)
os_dlclose(lib);
dstr_free(&lib_path);
return success;
}

View File

@ -0,0 +1,198 @@
/******************************************************************************
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/>.
******************************************************************************/
#pragma once
#include <util/c99defs.h>
#if defined(_WIN32) || defined(__APPLE__)
#define RUNTIME_LINK 1
#define Py_NO_ENABLE_SHARED
#else
#define RUNTIME_LINK 0
#endif
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable : 4115)
#endif
#if defined(_WIN32) && defined(_DEBUG)
# undef _DEBUG
# include <Python.h>
# define _DEBUG
#else
# include <Python.h>
#endif
#ifdef _MSC_VER
#pragma warning(pop)
#endif
#if RUNTIME_LINK
#ifdef NO_REDEFS
#define PY_EXTERN
#else
#define PY_EXTERN extern
#endif
PY_EXTERN int (*Import_PyType_Ready)(PyTypeObject *);
PY_EXTERN PyObject *(*Import_PyObject_GenericGetAttr)(PyObject *, PyObject *);
PY_EXTERN int (*Import_PyObject_IsTrue)(PyObject *);
PY_EXTERN void (*Import_Py_DecRef)(PyObject *);
PY_EXTERN void *(*Import_PyObject_Malloc)(size_t size);
PY_EXTERN void (*Import_PyObject_Free)(void *ptr);
PY_EXTERN PyObject *(*Import_PyObject_Init)(PyObject *, PyTypeObject *);
PY_EXTERN PyObject *(*Import_PyUnicode_FromFormat)(const char *format, ...);
PY_EXTERN PyObject *(*Import_PyUnicode_Concat)(PyObject *left, PyObject *right);
PY_EXTERN PyObject *(*Import_PyLong_FromVoidPtr)(void *);
PY_EXTERN PyObject *(*Import_PyBool_FromLong)(long);
PY_EXTERN PyGILState_STATE (*Import_PyGILState_Ensure)(void);
PY_EXTERN PyThreadState *(*Import_PyGILState_GetThisThreadState)(void);
PY_EXTERN void (*Import_PyErr_SetString)(PyObject *exception, const char *string);
PY_EXTERN PyObject *(*Import_PyErr_Occurred)(void);
PY_EXTERN void (*Import_PyErr_Fetch)(PyObject **, PyObject **, PyObject **);
PY_EXTERN void (*Import_PyErr_Restore)(PyObject *, PyObject *, PyObject *);
PY_EXTERN void (*Import_PyErr_WriteUnraisable)(PyObject *);
PY_EXTERN int (*Import_PyArg_UnpackTuple)(PyObject *, const char *, Py_ssize_t, Py_ssize_t, ...);
PY_EXTERN PyObject *(*Import_Py_BuildValue)(const char *, ...);
PY_EXTERN int (*Import_PyRun_SimpleStringFlags)(const char *, PyCompilerFlags *);
PY_EXTERN void (*Import_PyErr_Print)(void);
PY_EXTERN void (*Import_Py_SetPythonHome)(wchar_t *);
PY_EXTERN void (*Import_Py_Initialize)(void);
PY_EXTERN void (*Import_Py_Finalize)(void);
PY_EXTERN int (*Import_Py_IsInitialized)(void);
PY_EXTERN void (*Import_PyEval_InitThreads)(void);
PY_EXTERN int (*Import_PyEval_ThreadsInitialized)(void);
PY_EXTERN void (*Import_PyEval_ReleaseThread)(PyThreadState *tstate);
PY_EXTERN void (*Import_PySys_SetArgv)(int, wchar_t **);
PY_EXTERN PyObject *(*Import_PyImport_ImportModule)(const char *name);
PY_EXTERN PyObject *(*Import_PyObject_CallFunctionObjArgs)(PyObject *callable, ...);
PY_EXTERN PyObject (*Import__Py_NotImplementedStruct);
PY_EXTERN PyObject *(*Import_PyExc_TypeError);
PY_EXTERN PyObject *(*Import_PyExc_RuntimeError);
PY_EXTERN PyObject *(*Import_PyObject_GetAttr)(PyObject *, PyObject *);
PY_EXTERN PyObject *(*Import_PyUnicode_FromString)(const char *u);
PY_EXTERN PyObject *(*Import_PyDict_GetItemString)(PyObject *dp, const char *key);
PY_EXTERN int (*Import_PyDict_SetItemString)(PyObject *dp, const char *key, PyObject *item);
PY_EXTERN PyObject *(*Import_PyCFunction_NewEx)(PyMethodDef *, PyObject *, PyObject *);
PY_EXTERN PyObject *(*Import_PyModule_GetDict)(PyObject *);
PY_EXTERN PyObject *(*Import_PyModule_GetNameObject)(PyObject *);
PY_EXTERN int (*Import_PyModule_AddObject)(PyObject *, const char *, PyObject *);
PY_EXTERN int (*Import_PyModule_AddStringConstant)(PyObject *, const char *, const char *);
PY_EXTERN PyObject *(*Import_PyImport_Import)(PyObject *name);
PY_EXTERN PyObject *(*Import_PyObject_CallObject)(PyObject *callable_object, PyObject *args);
PY_EXTERN struct _longobject (*Import__Py_FalseStruct);
PY_EXTERN struct _longobject (*Import__Py_TrueStruct);
PY_EXTERN void (*Import_PyGILState_Release)(PyGILState_STATE);
PY_EXTERN int (*Import_PyList_Append)(PyObject *, PyObject *);
PY_EXTERN PyObject *(*Import_PySys_GetObject)(const char *);
PY_EXTERN PyObject *(*Import_PyImport_ReloadModule)(PyObject *m);
PY_EXTERN PyObject *(*Import_PyObject_GetAttrString)(PyObject *, const char *);
PY_EXTERN PyObject *(*Import_PyCapsule_New)(void *pointer, const char *name, PyCapsule_Destructor destructor);
PY_EXTERN void *(*Import_PyCapsule_GetPointer)(PyObject *capsule, const char *name);
PY_EXTERN int (*Import_PyArg_ParseTuple)(PyObject *, const char *, ...);
PY_EXTERN PyTypeObject (*Import_PyFunction_Type);
PY_EXTERN int (*Import_PyObject_SetAttr)(PyObject *, PyObject *, PyObject *);
PY_EXTERN PyObject *(*Import__PyObject_New)(PyTypeObject *);
PY_EXTERN void *(*Import_PyCapsule_Import)(const char *name, int no_block);
PY_EXTERN void (*Import_PyErr_Clear)(void);
PY_EXTERN PyObject *(*Import_PyObject_Call)(PyObject *callable_object, PyObject *args, PyObject *kwargs);
PY_EXTERN PyObject *(*Import_PyList_New)(Py_ssize_t size);
PY_EXTERN Py_ssize_t (*Import_PyList_Size)(PyObject *);
PY_EXTERN PyObject *(*Import_PyList_GetItem)(PyObject *, Py_ssize_t);
PY_EXTERN PyObject *(*Import_PyUnicode_AsUTF8String)(PyObject *unicode);
PY_EXTERN PyObject *(*Import_PyLong_FromUnsignedLongLong)(unsigned long long);
PY_EXTERN int (*Import_PyArg_VaParse)(PyObject *, const char *, va_list);
PY_EXTERN PyObject (*Import__Py_NoneStruct);
extern bool import_python(const char *python_path);
# ifndef NO_REDEFS
# define PyType_Ready Import_PyType_Ready
# define PyObject_GenericGetAttr Import_PyObject_GenericGetAttr
# define PyObject_IsTrue Import_PyObject_IsTrue
# define Py_DecRef Import_Py_DecRef
# define PyObject_Malloc Import_PyObject_Malloc
# define PyObject_Free Import_PyObject_Free
# define PyObject_Init Import_PyObject_Init
# define PyUnicode_FromFormat Import_PyUnicode_FromFormat
# define PyUnicode_Concat Import_PyUnicode_Concat
# define PyLong_FromVoidPtr Import_PyLong_FromVoidPtr
# define PyBool_FromLong Import_PyBool_FromLong
# define PyGILState_Ensure Import_PyGILState_Ensure
# define PyGILState_GetThisThreadState Import_PyGILState_GetThisThreadState
# define PyErr_SetString Import_PyErr_SetString
# define PyErr_Occurred Import_PyErr_Occurred
# define PyErr_Fetch Import_PyErr_Fetch
# define PyErr_Restore Import_PyErr_Restore
# define PyErr_WriteUnraisable Import_PyErr_WriteUnraisable
# define PyArg_UnpackTuple Import_PyArg_UnpackTuple
# define Py_BuildValue Import_Py_BuildValue
# define PyRun_SimpleStringFlags Import_PyRun_SimpleStringFlags
# define PyErr_Print Import_PyErr_Print
# define Py_SetPythonHome Import_Py_SetPythonHome
# define Py_Initialize Import_Py_Initialize
# define Py_Finalize Import_Py_Finalize
# define Py_IsInitialized Import_Py_IsInitialized
# define PyEval_InitThreads Import_PyEval_InitThreads
# define PyEval_ThreadsInitialized Import_PyEval_ThreadsInitialized
# define PyEval_ReleaseThread Import_PyEval_ReleaseThread
# define PySys_SetArgv Import_PySys_SetArgv
# define PyImport_ImportModule Import_PyImport_ImportModule
# define PyObject_CallFunctionObjArgs Import_PyObject_CallFunctionObjArgs
# define _Py_NotImplementedStruct (*Import__Py_NotImplementedStruct)
# define PyExc_TypeError (*Import_PyExc_TypeError)
# define PyExc_RuntimeError (*Import_PyExc_RuntimeError)
# define PyObject_GetAttr Import_PyObject_GetAttr
# define PyUnicode_FromString Import_PyUnicode_FromString
# define PyDict_GetItemString Import_PyDict_GetItemString
# define PyDict_SetItemString Import_PyDict_SetItemString
# define PyCFunction_NewEx Import_PyCFunction_NewEx
# define PyModule_GetDict Import_PyModule_GetDict
# define PyModule_GetNameObject Import_PyModule_GetNameObject
# define PyModule_AddObject Import_PyModule_AddObject
# define PyModule_AddStringConstant Import_PyModule_AddStringConstant
# define PyImport_Import Import_PyImport_Import
# define PyObject_CallObject Import_PyObject_CallObject
# define _Py_FalseStruct (*Import__Py_FalseStruct)
# define _Py_TrueStruct (*Import__Py_TrueStruct)
# define PyGILState_Release Import_PyGILState_Release
# define PyList_Append Import_PyList_Append
# define PySys_GetObject Import_PySys_GetObject
# define PyImport_ReloadModule Import_PyImport_ReloadModule
# define PyObject_GetAttrString Import_PyObject_GetAttrString
# define PyCapsule_New Import_PyCapsule_New
# define PyCapsule_GetPointer Import_PyCapsule_GetPointer
# define PyArg_ParseTuple Import_PyArg_ParseTuple
# define PyFunction_Type (*Import_PyFunction_Type)
# define PyObject_SetAttr Import_PyObject_SetAttr
# define _PyObject_New Import__PyObject_New
# define PyCapsule_Import Import_PyCapsule_Import
# define PyErr_Clear Import_PyErr_Clear
# define PyObject_Call Import_PyObject_Call
# define PyList_New Import_PyList_New
# define PyList_Size Import_PyList_Size
# define PyList_GetItem Import_PyList_GetItem
# define PyUnicode_AsUTF8String Import_PyUnicode_AsUTF8String
# define PyLong_FromUnsignedLongLong Import_PyLong_FromUnsignedLongLong
# define PyArg_VaParse Import_PyArg_VaParse
# define _Py_NoneStruct (*Import__Py_NoneStruct)
# endif
#endif

1705
deps/obs-scripting/obs-scripting-python.c vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,244 @@
/******************************************************************************
Copyright (C) 2015 by Andrew Skinner <obs@theandyroid.com>
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/>.
******************************************************************************/
#pragma once
/* ---------------------------- */
#define SWIG_TYPE_TABLE obspython
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable : 4100)
#pragma warning(disable : 4115)
#pragma warning(disable : 4204)
#endif
#include "obs-scripting-python-import.h"
#include <structmember.h>
#include "swig/swigpyrun.h"
#ifdef _MSC_VER
#pragma warning(pop)
#endif
/* ---------------------------- */
#include "obs-scripting-internal.h"
#include "obs-scripting-callback.h"
#ifdef _WIN32
#define __func__ __FUNCTION__
#else
#include <dlfcn.h>
#endif
#include <callback/calldata.h>
#include <util/threading.h>
#include <util/base.h>
#define do_log(level, format, ...) \
blog(level, "[Python] " format, ##__VA_ARGS__)
#define warn(format, ...) do_log(LOG_WARNING, format, ##__VA_ARGS__)
#define info(format, ...) do_log(LOG_INFO, format, ##__VA_ARGS__)
#define debug(format, ...) do_log(LOG_DEBUG, format, ##__VA_ARGS__)
/* ------------------------------------------------------------ */
struct python_obs_callback;
struct obs_python_script {
obs_script_t base;
struct dstr dir;
struct dstr name;
PyObject *module;
PyObject *save;
PyObject *update;
PyObject *get_properties;
struct script_callback *first_callback;
PyObject *tick;
struct obs_python_script *next_tick;
struct obs_python_script **p_prev_next_tick;
};
/* ------------------------------------------------------------ */
struct python_obs_callback {
struct script_callback base;
PyObject *func;
};
static inline struct python_obs_callback *add_python_obs_callback_extra(
struct obs_python_script *script,
PyObject *func,
size_t extra_size)
{
struct python_obs_callback *cb = add_script_callback(
&script->first_callback,
(obs_script_t *)script,
sizeof(*cb) + extra_size);
Py_XINCREF(func);
cb->func = func;
return cb;
}
static inline struct python_obs_callback *add_python_obs_callback(
struct obs_python_script *script,
PyObject *func)
{
return add_python_obs_callback_extra(script, func, 0);
}
static inline void *python_obs_callback_extra_data(
struct python_obs_callback *cb)
{
return (void*)&cb[1];
}
static inline struct obs_python_script *python_obs_callback_script(
struct python_obs_callback *cb)
{
return (struct obs_python_script *)cb->base.script;
}
static inline struct python_obs_callback *find_next_python_obs_callback(
struct obs_python_script *script,
struct python_obs_callback *cb, PyObject *func)
{
cb = cb ? (struct python_obs_callback *)cb->base.next
: (struct python_obs_callback *)script->first_callback;
while (cb) {
if (cb->func == func)
break;
cb = (struct python_obs_callback *)cb->base.next;
}
return cb;
}
static inline struct python_obs_callback *find_python_obs_callback(
struct obs_python_script *script,
PyObject *func)
{
return find_next_python_obs_callback(script, NULL, func);
}
static inline void remove_python_obs_callback(struct python_obs_callback *cb)
{
remove_script_callback(&cb->base);
Py_XDECREF(cb->func);
cb->func = NULL;
}
static inline void just_free_python_obs_callback(struct python_obs_callback *cb)
{
just_free_script_callback(&cb->base);
}
static inline void free_python_obs_callback(struct python_obs_callback *cb)
{
free_script_callback(&cb->base);
}
/* ------------------------------------------------------------ */
static int parse_args_(PyObject *args, const char *func, const char *format, ...)
{
char new_format[128];
va_list va_args;
int ret;
snprintf(new_format, sizeof(new_format), "%s:%s", format, func);
va_start(va_args, format);
ret = PyArg_VaParse(args, new_format, va_args);
va_end(va_args);
return ret;
}
#define parse_args(args, format, ...) \
parse_args_(args, __FUNCTION__, format, ##__VA_ARGS__)
static inline bool py_error_(const char *func, int line)
{
if (PyErr_Occurred()) {
warn("Python failure in %s:%d:", func, line);
PyErr_Print();
return true;
}
return false;
}
#define py_error() py_error_(__FUNCTION__, __LINE__)
#define lock_python() \
PyGILState_STATE gstate = PyGILState_Ensure()
#define unlock_python() \
PyGILState_Release(gstate)
struct py_source;
typedef struct py_source py_source_t;
extern PyObject* py_libobs;
extern struct python_obs_callback *cur_python_cb;
extern struct obs_python_script *cur_python_script;
extern void py_to_obs_source_info(py_source_t *py_info);
extern PyObject *py_obs_register_source(PyObject *self, PyObject *args);
extern PyObject *py_obs_get_script_config_path(PyObject *self, PyObject *args);
extern void add_functions_to_py_module(PyObject *module,
PyMethodDef *method_list);
/* ------------------------------------------------------------ */
/* Warning: the following functions expect python to be locked! */
extern bool py_to_libobs_(const char *type,
PyObject * py_in,
void * libobs_out,
const char *id,
const char *func,
int line);
extern bool libobs_to_py_(const char *type,
void * libobs_in,
bool ownership,
PyObject ** py_out,
const char *id,
const char *func,
int line);
extern bool py_call(PyObject *call, PyObject **ret, const char *arg_def, ...);
extern bool py_import_script(const char *name);
static inline PyObject *python_none(void)
{
PyObject *none = Py_None;
Py_INCREF(none);
return none;
}

455
deps/obs-scripting/obs-scripting.c vendored Normal file
View File

@ -0,0 +1,455 @@
/******************************************************************************
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.h>
#include <util/dstr.h>
#include <util/platform.h>
#include <util/threading.h>
#include <util/circlebuf.h>
#include "obs-scripting-internal.h"
#include "obs-scripting-callback.h"
#include "obs-scripting-config.h"
#if COMPILE_LUA
extern obs_script_t *obs_lua_script_create(const char *path,
obs_data_t *settings);
extern bool obs_lua_script_load(obs_script_t *s);
extern void obs_lua_script_unload(obs_script_t *s);
extern void obs_lua_script_destroy(obs_script_t *s);
extern void obs_lua_load(void);
extern void obs_lua_unload(void);
extern obs_properties_t *obs_lua_script_get_properties(obs_script_t *script);
extern void obs_lua_script_update(obs_script_t *script, obs_data_t *settings);
extern void obs_lua_script_save(obs_script_t *script);
#endif
#if COMPILE_PYTHON
extern obs_script_t *obs_python_script_create(const char *path,
obs_data_t *settings);
extern bool obs_python_script_load(obs_script_t *s);
extern void obs_python_script_unload(obs_script_t *s);
extern void obs_python_script_destroy(obs_script_t *s);
extern void obs_python_load(void);
extern void obs_python_unload(void);
extern obs_properties_t *obs_python_script_get_properties(obs_script_t *script);
extern void obs_python_script_update(obs_script_t *script, obs_data_t *settings);
extern void obs_python_script_save(obs_script_t *script);
#endif
pthread_mutex_t detach_mutex;
struct script_callback *detached_callbacks;
static struct dstr file_filter = {0};
static bool scripting_loaded = false;
static const char *supported_formats[] = {
#if COMPILE_LUA
"lua",
#endif
#if COMPILE_PYTHON
"py",
#endif
NULL
};
/* -------------------------------------------- */
static pthread_mutex_t defer_call_mutex;
static struct circlebuf defer_call_queue;
static bool defer_call_exit = false;
static os_sem_t *defer_call_semaphore;
static pthread_t defer_call_thread;
struct defer_call {
defer_call_cb call;
void *cb;
};
static void *defer_thread(void *unused)
{
UNUSED_PARAMETER(unused);
while (os_sem_wait(defer_call_semaphore) == 0) {
struct defer_call info;
pthread_mutex_lock(&defer_call_mutex);
if (defer_call_exit) {
pthread_mutex_unlock(&defer_call_mutex);
return NULL;
}
circlebuf_pop_front(&defer_call_queue, &info, sizeof(info));
pthread_mutex_unlock(&defer_call_mutex);
info.call(info.cb);
}
return NULL;
}
void defer_call_post(defer_call_cb call, void *cb)
{
struct defer_call info;
info.call = call;
info.cb = cb;
pthread_mutex_lock(&defer_call_mutex);
if (!defer_call_exit)
circlebuf_push_back(&defer_call_queue, &info, sizeof(info));
pthread_mutex_unlock(&defer_call_mutex);
os_sem_post(defer_call_semaphore);
}
/* -------------------------------------------- */
bool obs_scripting_load(void)
{
circlebuf_init(&defer_call_queue);
if (pthread_mutex_init(&detach_mutex, NULL) != 0) {
return false;
}
if (pthread_mutex_init(&defer_call_mutex, NULL) != 0) {
pthread_mutex_destroy(&detach_mutex);
return false;
}
if (os_sem_init(&defer_call_semaphore, 0) != 0) {
pthread_mutex_destroy(&defer_call_mutex);
pthread_mutex_destroy(&detach_mutex);
return false;
}
if (pthread_create(&defer_call_thread, NULL, defer_thread, NULL) != 0) {
os_sem_destroy(defer_call_semaphore);
pthread_mutex_destroy(&defer_call_mutex);
pthread_mutex_destroy(&detach_mutex);
return false;
}
#if COMPILE_LUA
obs_lua_load();
#endif
#if COMPILE_PYTHON
obs_python_load();
obs_scripting_load_python(NULL);
#endif
scripting_loaded = true;
return true;
}
void obs_scripting_unload(void)
{
if (!scripting_loaded)
return;
/* ---------------------- */
#if COMPILE_LUA
obs_lua_unload();
#endif
#if COMPILE_PYTHON
obs_python_unload();
#endif
dstr_free(&file_filter);
/* ---------------------- */
int total_detached = 0;
pthread_mutex_lock(&detach_mutex);
struct script_callback *cur = detached_callbacks;
while (cur) {
struct script_callback *next = cur->next;
just_free_script_callback(cur);
cur = next;
++total_detached;
}
pthread_mutex_unlock(&detach_mutex);
pthread_mutex_destroy(&detach_mutex);
blog(LOG_INFO, "[Scripting] Total detached callbacks: %d",
total_detached);
/* ---------------------- */
pthread_mutex_lock(&defer_call_mutex);
/* TODO */
defer_call_exit = true;
circlebuf_free(&defer_call_queue);
pthread_mutex_unlock(&defer_call_mutex);
os_sem_post(defer_call_semaphore);
pthread_join(defer_call_thread, NULL);
pthread_mutex_destroy(&defer_call_mutex);
os_sem_destroy(defer_call_semaphore);
}
const char **obs_scripting_supported_formats(void)
{
return supported_formats;
}
static inline bool pointer_valid(const void *x, const char *name,
const char *func)
{
if (!x) {
blog(LOG_WARNING, "obs-scripting: [%s] %s is null",
func, name);
return false;
}
return true;
}
#define ptr_valid(x) pointer_valid(x, #x, __FUNCTION__)
obs_script_t *obs_script_create(const char *path, obs_data_t *settings)
{
obs_script_t *script = NULL;
const char *ext;
if (!scripting_loaded)
return NULL;
if (!ptr_valid(path))
return NULL;
ext = strrchr(path, '.');
if (!ext)
return NULL;
#if COMPILE_LUA
if (strcmp(ext, ".lua") == 0) {
script = obs_lua_script_create(path, settings);
} else
#endif
#if COMPILE_PYTHON
if (strcmp(ext, ".py") == 0) {
script = obs_python_script_create(path, settings);
} else
#endif
{
blog(LOG_WARNING, "Unsupported/unknown script type: %s", path);
}
return script;
}
const char *obs_script_get_description(const obs_script_t *script)
{
return ptr_valid(script) ? script->desc.array : NULL;
}
const char *obs_script_get_path(const obs_script_t *script)
{
const char *path = ptr_valid(script) ? script->path.array : "";
return path ? path : "";
}
const char *obs_script_get_file(const obs_script_t *script)
{
const char *file = ptr_valid(script) ? script->file.array : "";
return file ? file : "";
}
enum obs_script_lang obs_script_get_lang(const obs_script_t *script)
{
return ptr_valid(script) ? script->type : OBS_SCRIPT_LANG_UNKNOWN;
}
obs_data_t *obs_script_get_settings(obs_script_t *script)
{
obs_data_t *settings;
if (!ptr_valid(script))
return NULL;
settings = script->settings;
obs_data_addref(settings);
return settings;
}
obs_properties_t *obs_script_get_properties(obs_script_t *script)
{
obs_properties_t *props = NULL;
if (!ptr_valid(script))
return NULL;
#if COMPILE_LUA
if (script->type == OBS_SCRIPT_LANG_LUA) {
props = obs_lua_script_get_properties(script);
goto out;
}
#endif
#if COMPILE_PYTHON
if (script->type == OBS_SCRIPT_LANG_PYTHON) {
props = obs_python_script_get_properties(script);
goto out;
}
#endif
out:
if (!props)
props = obs_properties_create();
return props;
}
obs_data_t *obs_script_save(obs_script_t *script)
{
obs_data_t *settings;
if (!ptr_valid(script))
return NULL;
#if COMPILE_LUA
if (script->type == OBS_SCRIPT_LANG_LUA) {
obs_lua_script_save(script);
goto out;
}
#endif
#if COMPILE_PYTHON
if (script->type == OBS_SCRIPT_LANG_PYTHON) {
obs_python_script_save(script);
goto out;
}
#endif
out:
settings = script->settings;
obs_data_addref(settings);
return settings;
}
static void clear_queue_signal(void *p_event)
{
os_event_t *event = p_event;
os_event_signal(event);
}
static void clear_call_queue(void)
{
os_event_t *event;
if (os_event_init(&event, OS_EVENT_TYPE_AUTO) != 0)
return;
defer_call_post(clear_queue_signal, event);
os_event_wait(event);
os_event_destroy(event);
}
void obs_script_update(obs_script_t *script, obs_data_t *settings)
{
if (!ptr_valid(script))
return;
#if COMPILE_LUA
if (script->type == OBS_SCRIPT_LANG_LUA) {
obs_lua_script_update(script, settings);
}
#endif
#if COMPILE_PYTHON
if (script->type == OBS_SCRIPT_LANG_PYTHON) {
obs_python_script_update(script, settings);
}
#endif
}
bool obs_script_reload(obs_script_t *script)
{
if (!scripting_loaded)
return false;
if (!ptr_valid(script))
return false;
#if COMPILE_LUA
if (script->type == OBS_SCRIPT_LANG_LUA) {
obs_lua_script_unload(script);
clear_call_queue();
obs_lua_script_load(script);
goto out;
}
#endif
#if COMPILE_PYTHON
if (script->type == OBS_SCRIPT_LANG_PYTHON) {
obs_python_script_unload(script);
clear_call_queue();
obs_python_script_load(script);
goto out;
}
#endif
out:
return script->loaded;
}
bool obs_script_loaded(const obs_script_t *script)
{
return ptr_valid(script) ? script->loaded : false;
}
void obs_script_destroy(obs_script_t *script)
{
if (!script)
return;
#if COMPILE_LUA
if (script->type == OBS_SCRIPT_LANG_LUA) {
obs_lua_script_unload(script);
obs_lua_script_destroy(script);
return;
}
#endif
#if COMPILE_PYTHON
if (script->type == OBS_SCRIPT_LANG_PYTHON) {
obs_python_script_unload(script);
obs_python_script_destroy(script);
return;
}
#endif
}
#if !COMPILE_PYTHON
bool obs_scripting_load_python(const char *python_path)
{
UNUSED_PARAMETER(python_path);
return false;
}
bool obs_scripting_python_loaded(void)
{
return false;
}
bool obs_scripting_python_runtime_linked(void)
{
return (bool)true;
}
#endif

73
deps/obs-scripting/obs-scripting.h vendored Normal file
View File

@ -0,0 +1,73 @@
/******************************************************************************
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/>.
******************************************************************************/
#pragma once
#include <stdarg.h>
#include <util/c99defs.h>
#include <obs-data.h>
#include <obs-properties.h>
#ifdef __cplusplus
extern "C" {
#endif
struct obs_script;
typedef struct obs_script obs_script_t;
enum obs_script_lang {
OBS_SCRIPT_LANG_UNKNOWN,
OBS_SCRIPT_LANG_LUA,
OBS_SCRIPT_LANG_PYTHON
};
EXPORT bool obs_scripting_load(void);
EXPORT void obs_scripting_unload(void);
EXPORT const char **obs_scripting_supported_formats(void);
typedef void (*scripting_log_handler_t)(
void *p,
obs_script_t *script,
int lvl,
const char *msg);
EXPORT void obs_scripting_set_log_callback(
scripting_log_handler_t handler, void *param);
EXPORT bool obs_scripting_python_runtime_linked(void);
EXPORT bool obs_scripting_python_loaded(void);
EXPORT bool obs_scripting_load_python(const char *python_path);
EXPORT obs_script_t *obs_script_create(const char *path, obs_data_t *settings);
EXPORT void obs_script_destroy(obs_script_t *script);
EXPORT const char *obs_script_get_description(const obs_script_t *script);
EXPORT const char *obs_script_get_path(const obs_script_t *script);
EXPORT const char *obs_script_get_file(const obs_script_t *script);
EXPORT enum obs_script_lang obs_script_get_lang(const obs_script_t *script);
EXPORT obs_properties_t *obs_script_get_properties(obs_script_t *script);
EXPORT obs_data_t *obs_script_save(obs_script_t *script);
EXPORT obs_data_t *obs_script_get_settings(obs_script_t *script);
EXPORT void obs_script_update(obs_script_t *script, obs_data_t *settings);
EXPORT bool obs_script_loaded(const obs_script_t *script);
EXPORT bool obs_script_reload(obs_script_t *script);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,41 @@
cmake_minimum_required(VERSION 2.8)
project(obslua)
find_package(SWIG 2 REQUIRED)
include(${SWIG_USE_FILE})
add_definitions(-DSWIG_TYPE_TABLE=obslua -DSWIG_LUA_INTERPRETER_NO_DEBUG)
if(MSVC)
add_compile_options("/wd4054")
add_compile_options("/wd4197")
add_compile_options("/wd4244")
add_compile_options("/wd4267")
endif()
include_directories(SYSTEM "${CMAKE_SOURCE_DIR}/libobs")
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
SWIG_ADD_MODULE(obslua lua obslua.i ../cstrcache.cpp ../cstrcache.h)
SWIG_LINK_LIBRARIES(obslua obs-scripting libobs ${LUA_LIBRARIES} ${EXTRA_LIBS})
function(install_plugin_bin_swig target additional_target)
if(APPLE)
set(_bit_suffix "")
elseif(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(_bit_suffix "64bit/")
else()
set(_bit_suffix "32bit/")
endif()
set_target_properties(${additional_target} PROPERTIES
PREFIX "")
add_custom_command(TARGET ${additional_target} POST_BUILD
COMMAND "${CMAKE_COMMAND}" -E copy
"$<TARGET_FILE:${additional_target}>"
"${OBS_OUTPUT_DIR}/$<CONFIGURATION>/bin/${_bit_suffix}$<TARGET_FILE_NAME:${additional_target}>"
VERBATIM)
endfunction()
install_plugin_bin_swig(obs-scripting obslua)

99
deps/obs-scripting/obslua/obslua.i vendored Normal file
View File

@ -0,0 +1,99 @@
%module obslua
%{
#define SWIG_FILE_WITH_INIT
#define DEPRECATED_START
#define DEPRECATED_END
#include <graphics/graphics.h>
#include <graphics/vec4.h>
#include <graphics/vec3.h>
#include <graphics/vec2.h>
#include <graphics/quat.h>
#include <obs.h>
#include <obs-hotkey.h>
#include <obs-source.h>
#include <obs-data.h>
#include <obs-properties.h>
#include <obs-interaction.h>
#include <callback/calldata.h>
#include <callback/proc.h>
#include <callback/signal.h>
#include <util/bmem.h>
#include <util/base.h>
#include "cstrcache.h"
#include "obs-scripting-config.h"
#if UI_ENABLED
#include "obs-frontend-api.h"
#endif
%}
#define DEPRECATED_START
#define DEPRECATED_END
#define EXPORT
%rename(blog) wrap_blog;
%inline %{
static inline void wrap_blog(int log_level, const char *message)
{
blog(log_level, "%s", message);
}
%}
%include "stdint.i"
/* Used to free when using %newobject functions. E.G.:
* %newobject obs_module_get_config_path; */
%typemap(newfree) char * "bfree($1);";
%ignore blog;
%ignore blogva;
%ignore bcrash;
%ignore obs_source_info;
%ignore obs_register_source_s(const struct obs_source_info *info, size_t size);
%ignore obs_output_set_video(obs_output_t *output, video_t *video);
%ignore obs_output_video(const obs_output_t *output);
%ignore obs_add_tick_callback;
%ignore obs_remove_tick_callback;
%ignore obs_add_main_render_callback;
%ignore obs_remove_main_render_callback;
%ignore obs_enum_sources;
%ignore obs_properties_add_button;
%ignore obs_property_set_modified_callback;
%ignore signal_handler_connect;
%ignore signal_handler_disconnect;
%ignore signal_handler_connect_global;
%ignore signal_handler_disconnect_global;
%ignore signal_handler_remove_current;
%ignore obs_hotkey_register_frontend;
%ignore obs_hotkey_register_encoder;
%ignore obs_hotkey_register_output;
%ignore obs_hotkey_register_service;
%ignore obs_hotkey_register_source;
%ignore obs_hotkey_pair_register_frontend;
%ignore obs_hotkey_pair_register_encoder;
%ignore obs_hotkey_pair_register_output;
%ignore obs_hotkey_pair_register_service;
%ignore obs_hotkey_pair_register_source;
%include "graphics/graphics.h"
%include "graphics/vec4.h"
%include "graphics/vec3.h"
%include "graphics/vec2.h"
%include "graphics/quat.h"
%include "obs-data.h"
%include "obs-source.h"
%include "obs-properties.h"
%include "obs-interaction.h"
%include "obs-hotkey.h"
%include "obs.h"
%include "callback/calldata.h"
%include "callback/proc.h"
%include "callback/signal.h"
%include "util/bmem.h"
%include "util/base.h"
%include "obs-scripting-config.h"
#if UI_ENABLED
%include "obs-frontend-api.h"
#endif

View File

@ -0,0 +1,60 @@
cmake_minimum_required(VERSION 2.8)
project(obspython)
find_package(SWIG 2 REQUIRED)
include(${SWIG_USE_FILE})
add_definitions(-DSWIG_TYPE_TABLE=obspython -DMS_NO_COREDLL -DPy_ENABLE_SHARED=1 -DSWIG_PYTHON_INTERPRETER_NO_DEBUG)
if(MSVC)
add_compile_options("/wd4054")
add_compile_options("/wd4100")
add_compile_options("/wd4115")
add_compile_options("/wd4197")
add_compile_options("/wd4701")
endif()
include_directories(${PYTHON_INCLUDE_DIR})
include_directories(SYSTEM "${CMAKE_SOURCE_DIR}/libobs")
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
#add_definitions( -DSWIG_TYPE_TABLE=libobs )
SET_SOURCE_FILES_PROPERTIES(obspython.i PROPERTIES SWIG_FLAGS "-modern")
SET_SOURCE_FILES_PROPERTIES(obspython.i PROPERTIES SWIG_FLAGS "-builtin")
SET_SOURCE_FILES_PROPERTIES(obspython.i PROPERTIES SWIG_FLAGS "-modernargs")
SET_SOURCE_FILES_PROPERTIES(obspython.i PROPERTIES SWIG_FLAGS "-includeall")
SET_SOURCE_FILES_PROPERTIES(obspython.i PROPERTIES SWIG_FLAGS "-importall")
SET_SOURCE_FILES_PROPERTIES(obspython.i PROPERTIES SWIG_FLAGS "-py3")
if(WIN32)
string(REGEX REPLACE "_d" "" PYTHON_LIBRARIES "${PYTHON_LIBRARIES}")
endif()
SWIG_ADD_MODULE(obspython python obspython.i ../cstrcache.cpp ../cstrcache.h)
SWIG_LINK_LIBRARIES(obspython obs-scripting libobs ${PYTHON_LIBRARIES})
function(install_plugin_bin_swig target additional_target)
if(APPLE)
set(_bit_suffix "")
elseif(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(_bit_suffix "64bit/")
else()
set(_bit_suffix "32bit/")
endif()
set_target_properties(${additional_target} PROPERTIES
PREFIX "")
add_custom_command(TARGET ${additional_target} POST_BUILD
COMMAND "${CMAKE_COMMAND}" -E copy
"${CMAKE_CURRENT_BINARY_DIR}/obspython.py"
"${OBS_OUTPUT_DIR}/$<CONFIGURATION>/bin/${_bit_suffix}/obspython.py"
VERBATIM)
add_custom_command(TARGET ${additional_target} POST_BUILD
COMMAND "${CMAKE_COMMAND}" -E copy
"$<TARGET_FILE:${additional_target}>"
"${OBS_OUTPUT_DIR}/$<CONFIGURATION>/bin/${_bit_suffix}$<TARGET_FILE_NAME:${additional_target}>"
VERBATIM)
endfunction()
install_plugin_bin_swig(obs-scripting _obspython)

106
deps/obs-scripting/obspython/obspython.i vendored Normal file
View File

@ -0,0 +1,106 @@
%module(threads="1") obspython
%nothread;
%{
#define SWIG_FILE_WITH_INIT
#define DEPRECATED_START
#define DEPRECATED_END
#include <graphics/graphics.h>
#include <graphics/vec4.h>
#include <graphics/vec3.h>
#include <graphics/vec2.h>
#include <graphics/quat.h>
#include <obs.h>
#include <obs-hotkey.h>
#include <obs-source.h>
#include <obs-data.h>
#include <obs-properties.h>
#include <obs-interaction.h>
#include <callback/calldata.h>
#include <callback/decl.h>
#include <callback/proc.h>
#include <callback/signal.h>
#include <util/bmem.h>
#include <util/base.h>
#include "obs-scripting-config.h"
#if UI_ENABLED
#include "obs-frontend-api.h"
#endif
%}
#define DEPRECATED_START
#define DEPRECATED_END
#define EXPORT
%rename(blog) wrap_blog;
%inline %{
static inline void wrap_blog(int log_level, const char *message)
{
blog(log_level, "%s", message);
}
%}
%include "stdint.i"
/* Used to free when using %newobject functions. E.G.:
* %newobject obs_module_get_config_path; */
%typemap(newfree) char * "bfree($1);";
%ignore blog;
%ignore blogva;
%ignore bcrash;
%ignore obs_source_info;
%ignore obs_register_source_s(const struct obs_source_info *info, size_t size);
%ignore obs_output_set_video(obs_output_t *output, video_t *video);
%ignore obs_output_video(const obs_output_t *output);
%ignore obs_add_tick_callback;
%ignore obs_remove_tick_callback;
%ignore obs_add_main_render_callback;
%ignore obs_remove_main_render_callback;
%ignore obs_enum_sources;
%ignore obs_properties_add_button;
%ignore obs_property_set_modified_callback;
%ignore signal_handler_connect;
%ignore signal_handler_disconnect;
%ignore signal_handler_connect_global;
%ignore signal_handler_disconnect_global;
%ignore signal_handler_remove_current;
%ignore obs_hotkey_register_frontend;
%ignore obs_hotkey_register_encoder;
%ignore obs_hotkey_register_output;
%ignore obs_hotkey_register_service;
%ignore obs_hotkey_register_source;
%ignore obs_hotkey_pair_register_frontend;
%ignore obs_hotkey_pair_register_encoder;
%ignore obs_hotkey_pair_register_output;
%ignore obs_hotkey_pair_register_service;
%ignore obs_hotkey_pair_register_source;
%include "graphics/graphics.h"
%include "graphics/vec4.h"
%include "graphics/vec3.h"
%include "graphics/vec2.h"
%include "graphics/quat.h"
%include "obs-data.h"
%include "obs-source.h"
%include "obs-properties.h"
%include "obs-interaction.h"
%include "obs-hotkey.h"
%include "obs.h"
%include "callback/calldata.h"
%include "callback/proc.h"
%include "callback/signal.h"
%include "util/bmem.h"
%include "util/base.h"
%include "obs-scripting-config.h"
#if UI_ENABLED
%include "obs-frontend-api.h"
#endif
/* declare these manually because mutex + GIL = deadlocks */
%thread;
void obs_enter_graphics(void); //Should only block on entering mutex
%nothread;
%include "obs.h"