1
0

obs-scripting-lua-source.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743
  1. /******************************************************************************
  2. Copyright (C) 2017 by Hugh Bailey <[email protected]>
  3. This program is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation, either version 2 of the License, or
  6. (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program. If not, see <http://www.gnu.org/licenses/>.
  13. ******************************************************************************/
  14. #include "obs-scripting-lua.h"
  15. #include "cstrcache.h"
  16. #include <obs-module.h>
  17. /* ========================================================================= */
  18. static inline const char *get_table_string_(lua_State *script, int idx,
  19. const char *name, const char *func)
  20. {
  21. const char *str = "";
  22. lua_pushstring(script, name);
  23. lua_gettable(script, idx - 1);
  24. if (!lua_isstring(script, -1))
  25. warn("%s: no item '%s' of type %s", func, name, "string");
  26. else
  27. str = cstrcache_get(lua_tostring(script, -1));
  28. lua_pop(script, 1);
  29. return str;
  30. }
  31. static inline int get_table_int_(lua_State *script, int idx, const char *name,
  32. const char *func)
  33. {
  34. int val = 0;
  35. lua_pushstring(script, name);
  36. lua_gettable(script, idx - 1);
  37. val = (int)lua_tointeger(script, -1);
  38. lua_pop(script, 1);
  39. UNUSED_PARAMETER(func);
  40. return val;
  41. }
  42. static inline void get_callback_from_table_(lua_State *script, int idx,
  43. const char *name, int *p_reg_idx,
  44. const char *func)
  45. {
  46. *p_reg_idx = LUA_REFNIL;
  47. lua_pushstring(script, name);
  48. lua_gettable(script, idx - 1);
  49. if (!lua_isfunction(script, -1)) {
  50. if (!lua_isnil(script, -1)) {
  51. warn("%s: item '%s' is not a function", func, name);
  52. }
  53. lua_pop(script, 1);
  54. } else {
  55. *p_reg_idx = luaL_ref(script, LUA_REGISTRYINDEX);
  56. }
  57. }
  58. #define get_table_string(script, idx, name) \
  59. get_table_string_(script, idx, name, __FUNCTION__)
  60. #define get_table_int(script, idx, name) \
  61. get_table_int_(script, idx, name, __FUNCTION__)
  62. #define get_callback_from_table(script, idx, name, p_reg_idx) \
  63. get_callback_from_table_(script, idx, name, p_reg_idx, __FUNCTION__)
  64. bool ls_get_libobs_obj_(lua_State *script, const char *type, int lua_idx,
  65. void *libobs_out, const char *id, const char *func,
  66. int line)
  67. {
  68. swig_type_info *info = SWIG_TypeQuery(script, type);
  69. if (info == NULL) {
  70. warn("%s:%d: SWIG could not find type: %s%s%s", func, line,
  71. id ? id : "", id ? "::" : "", type);
  72. return false;
  73. }
  74. int ret = SWIG_ConvertPtr(script, lua_idx, libobs_out, info, 0);
  75. if (!SWIG_IsOK(ret)) {
  76. warn("%s:%d: SWIG failed to convert lua object to obs "
  77. "object: %s%s%s",
  78. func, line, id ? id : "", id ? "::" : "", type);
  79. return false;
  80. }
  81. return true;
  82. }
  83. #define ls_get_libobs_obj(type, lua_index, obs_obj) \
  84. ls_get_libobs_obj_(ls->script, #type " *", lua_index, obs_obj, ls->id, \
  85. __FUNCTION__, __LINE__)
  86. bool ls_push_libobs_obj_(lua_State *script, const char *type, void *libobs_in,
  87. bool ownership, const char *id, const char *func,
  88. int line)
  89. {
  90. swig_type_info *info = SWIG_TypeQuery(script, type);
  91. if (info == NULL) {
  92. warn("%s:%d: SWIG could not find type: %s%s%s", func, line,
  93. id ? id : "", id ? "::" : "", type);
  94. return false;
  95. }
  96. SWIG_NewPointerObj(script, libobs_in, info, (int)ownership);
  97. return true;
  98. }
  99. #define ls_push_libobs_obj(type, obs_obj, ownership) \
  100. ls_push_libobs_obj_(ls->script, #type " *", obs_obj, ownership, \
  101. ls->id, __FUNCTION__, __LINE__)
  102. /* ========================================================================= */
  103. struct obs_lua_data;
  104. struct obs_lua_source {
  105. struct obs_lua_script *data;
  106. lua_State *script;
  107. const char *id;
  108. const char *display_name;
  109. int func_create;
  110. int func_destroy;
  111. int func_get_width;
  112. int func_get_height;
  113. int func_get_defaults;
  114. int func_get_properties;
  115. int func_update;
  116. int func_activate;
  117. int func_deactivate;
  118. int func_show;
  119. int func_hide;
  120. int func_video_tick;
  121. int func_video_render;
  122. int func_save;
  123. int func_load;
  124. pthread_mutex_t definition_mutex;
  125. struct obs_lua_data *first_source;
  126. struct obs_lua_source *next;
  127. struct obs_lua_source **p_prev_next;
  128. };
  129. extern pthread_mutex_t lua_source_def_mutex;
  130. struct obs_lua_source *first_source_def = NULL;
  131. struct obs_lua_data {
  132. obs_source_t *source;
  133. struct obs_lua_source *ls;
  134. int lua_data_ref;
  135. struct obs_lua_data *next;
  136. struct obs_lua_data **p_prev_next;
  137. };
  138. #define call_func(name, args, rets) \
  139. call_func_(ls->script, ls->func_##name, args, rets, #name, \
  140. ls->display_name)
  141. #define have_func(name) (ls->func_##name != LUA_REFNIL)
  142. #define ls_push_data() \
  143. lua_rawgeti(ls->script, LUA_REGISTRYINDEX, ld->lua_data_ref)
  144. #define ls_pop(count) lua_pop(ls->script, count)
  145. #define lock_script() \
  146. struct obs_lua_script *__data = ls->data; \
  147. struct obs_lua_script *__prev_script = current_lua_script; \
  148. current_lua_script = __data; \
  149. pthread_mutex_lock(&__data->mutex);
  150. #define unlock_script() \
  151. pthread_mutex_unlock(&__data->mutex); \
  152. current_lua_script = __prev_script;
  153. static const char *obs_lua_source_get_name(void *type_data)
  154. {
  155. struct obs_lua_source *ls = type_data;
  156. return ls->display_name;
  157. }
  158. static void *obs_lua_source_create(obs_data_t *settings, obs_source_t *source)
  159. {
  160. struct obs_lua_source *ls = obs_source_get_type_data(source);
  161. struct obs_lua_data *data = NULL;
  162. pthread_mutex_lock(&ls->definition_mutex);
  163. if (!ls->script)
  164. goto fail;
  165. if (!have_func(create))
  166. goto fail;
  167. lock_script();
  168. ls_push_libobs_obj(obs_data_t, settings, false);
  169. ls_push_libobs_obj(obs_source_t, source, false);
  170. call_func(create, 2, 1);
  171. int lua_data_ref = luaL_ref(ls->script, LUA_REGISTRYINDEX);
  172. if (lua_data_ref != LUA_REFNIL) {
  173. data = bmalloc(sizeof(*data));
  174. data->source = source;
  175. data->ls = ls;
  176. data->lua_data_ref = lua_data_ref;
  177. }
  178. unlock_script();
  179. if (data) {
  180. struct obs_lua_data *next = ls->first_source;
  181. data->next = next;
  182. data->p_prev_next = &ls->first_source;
  183. if (next)
  184. next->p_prev_next = &data->next;
  185. ls->first_source = data;
  186. }
  187. fail:
  188. pthread_mutex_unlock(&ls->definition_mutex);
  189. return data;
  190. }
  191. static void call_destroy(struct obs_lua_data *ld)
  192. {
  193. struct obs_lua_source *ls = ld->ls;
  194. ls_push_data();
  195. call_func(destroy, 1, 0);
  196. luaL_unref(ls->script, LUA_REGISTRYINDEX, ld->lua_data_ref);
  197. ld->lua_data_ref = LUA_REFNIL;
  198. }
  199. static void obs_lua_source_destroy(void *data)
  200. {
  201. struct obs_lua_data *ld = data;
  202. struct obs_lua_source *ls = ld->ls;
  203. struct obs_lua_data *next;
  204. pthread_mutex_lock(&ls->definition_mutex);
  205. if (!ls->script)
  206. goto fail;
  207. if (!have_func(destroy))
  208. goto fail;
  209. lock_script();
  210. call_destroy(ld);
  211. unlock_script();
  212. fail:
  213. next = ld->next;
  214. *ld->p_prev_next = next;
  215. if (next)
  216. next->p_prev_next = ld->p_prev_next;
  217. bfree(data);
  218. pthread_mutex_unlock(&ls->definition_mutex);
  219. }
  220. static uint32_t obs_lua_source_get_width(void *data)
  221. {
  222. struct obs_lua_data *ld = data;
  223. struct obs_lua_source *ls = ld->ls;
  224. uint32_t width = 0;
  225. pthread_mutex_lock(&ls->definition_mutex);
  226. if (!ls->script)
  227. goto fail;
  228. if (!have_func(get_width))
  229. goto fail;
  230. lock_script();
  231. ls_push_data();
  232. if (call_func(get_width, 1, 1)) {
  233. width = (uint32_t)lua_tointeger(ls->script, -1);
  234. ls_pop(1);
  235. }
  236. unlock_script();
  237. fail:
  238. pthread_mutex_unlock(&ls->definition_mutex);
  239. return width;
  240. }
  241. static uint32_t obs_lua_source_get_height(void *data)
  242. {
  243. struct obs_lua_data *ld = data;
  244. struct obs_lua_source *ls = ld->ls;
  245. uint32_t height = 0;
  246. pthread_mutex_lock(&ls->definition_mutex);
  247. if (!ls->script)
  248. goto fail;
  249. if (!have_func(get_height))
  250. goto fail;
  251. lock_script();
  252. ls_push_data();
  253. if (call_func(get_height, 1, 1)) {
  254. height = (uint32_t)lua_tointeger(ls->script, -1);
  255. ls_pop(1);
  256. }
  257. unlock_script();
  258. fail:
  259. pthread_mutex_unlock(&ls->definition_mutex);
  260. return height;
  261. }
  262. static void obs_lua_source_get_defaults(void *type_data, obs_data_t *settings)
  263. {
  264. struct obs_lua_source *ls = type_data;
  265. pthread_mutex_lock(&ls->definition_mutex);
  266. if (!ls->script)
  267. goto fail;
  268. if (!have_func(get_defaults))
  269. goto fail;
  270. lock_script();
  271. ls_push_libobs_obj(obs_data_t, settings, false);
  272. call_func(get_defaults, 1, 0);
  273. unlock_script();
  274. fail:
  275. pthread_mutex_unlock(&ls->definition_mutex);
  276. }
  277. static obs_properties_t *obs_lua_source_get_properties(void *data)
  278. {
  279. struct obs_lua_data *ld = data;
  280. struct obs_lua_source *ls = ld->ls;
  281. obs_properties_t *props = NULL;
  282. pthread_mutex_lock(&ls->definition_mutex);
  283. if (!ls->script)
  284. goto fail;
  285. if (!have_func(get_properties))
  286. goto fail;
  287. lock_script();
  288. ls_push_data();
  289. if (call_func(get_properties, 1, 1)) {
  290. ls_get_libobs_obj(obs_properties_t, -1, &props);
  291. ls_pop(1);
  292. }
  293. unlock_script();
  294. fail:
  295. pthread_mutex_unlock(&ls->definition_mutex);
  296. return props;
  297. }
  298. static void obs_lua_source_update(void *data, obs_data_t *settings)
  299. {
  300. struct obs_lua_data *ld = data;
  301. struct obs_lua_source *ls = ld->ls;
  302. pthread_mutex_lock(&ls->definition_mutex);
  303. if (!ls->script)
  304. goto fail;
  305. if (!have_func(update))
  306. goto fail;
  307. lock_script();
  308. ls_push_data();
  309. ls_push_libobs_obj(obs_data_t, settings, false);
  310. call_func(update, 2, 0);
  311. unlock_script();
  312. fail:
  313. pthread_mutex_unlock(&ls->definition_mutex);
  314. }
  315. #define DEFINE_VOID_DATA_CALLBACK(name) \
  316. static void obs_lua_source_##name(void *data) \
  317. { \
  318. struct obs_lua_data *ld = data; \
  319. struct obs_lua_source *ls = ld->ls; \
  320. if (!have_func(name)) \
  321. return; \
  322. lock_script(); \
  323. ls_push_data(); \
  324. call_func(name, 1, 0); \
  325. unlock_script(); \
  326. }
  327. DEFINE_VOID_DATA_CALLBACK(activate)
  328. DEFINE_VOID_DATA_CALLBACK(deactivate)
  329. DEFINE_VOID_DATA_CALLBACK(show)
  330. DEFINE_VOID_DATA_CALLBACK(hide)
  331. #undef DEFINE_VOID_DATA_CALLBACK
  332. static void obs_lua_source_video_tick(void *data, float seconds)
  333. {
  334. struct obs_lua_data *ld = data;
  335. struct obs_lua_source *ls = ld->ls;
  336. pthread_mutex_lock(&ls->definition_mutex);
  337. if (!ls->script)
  338. goto fail;
  339. if (!have_func(video_tick))
  340. goto fail;
  341. lock_script();
  342. ls_push_data();
  343. lua_pushnumber(ls->script, (double)seconds);
  344. call_func(video_tick, 2, 0);
  345. unlock_script();
  346. fail:
  347. pthread_mutex_unlock(&ls->definition_mutex);
  348. }
  349. static void obs_lua_source_video_render(void *data, gs_effect_t *effect)
  350. {
  351. struct obs_lua_data *ld = data;
  352. struct obs_lua_source *ls = ld->ls;
  353. pthread_mutex_lock(&ls->definition_mutex);
  354. if (!ls->script)
  355. goto fail;
  356. if (!have_func(video_render))
  357. goto fail;
  358. lock_script();
  359. ls_push_data();
  360. ls_push_libobs_obj(gs_effect_t, effect, false);
  361. call_func(video_render, 2, 0);
  362. unlock_script();
  363. fail:
  364. pthread_mutex_unlock(&ls->definition_mutex);
  365. }
  366. static void obs_lua_source_save(void *data, obs_data_t *settings)
  367. {
  368. struct obs_lua_data *ld = data;
  369. struct obs_lua_source *ls = ld->ls;
  370. pthread_mutex_lock(&ls->definition_mutex);
  371. if (!ls->script)
  372. goto fail;
  373. if (!have_func(save))
  374. goto fail;
  375. lock_script();
  376. ls_push_data();
  377. ls_push_libobs_obj(obs_data_t, settings, false);
  378. call_func(save, 2, 0);
  379. unlock_script();
  380. fail:
  381. pthread_mutex_unlock(&ls->definition_mutex);
  382. }
  383. static void obs_lua_source_load(void *data, obs_data_t *settings)
  384. {
  385. struct obs_lua_data *ld = data;
  386. struct obs_lua_source *ls = ld->ls;
  387. pthread_mutex_lock(&ls->definition_mutex);
  388. if (!ls->script)
  389. goto fail;
  390. if (!have_func(load))
  391. goto fail;
  392. lock_script();
  393. ls_push_data();
  394. ls_push_libobs_obj(obs_data_t, settings, false);
  395. call_func(load, 2, 0);
  396. unlock_script();
  397. fail:
  398. pthread_mutex_unlock(&ls->definition_mutex);
  399. }
  400. static void source_type_unload(struct obs_lua_source *ls)
  401. {
  402. #define unref(name) \
  403. luaL_unref(ls->script, LUA_REGISTRYINDEX, name); \
  404. name = LUA_REFNIL
  405. unref(ls->func_create);
  406. unref(ls->func_destroy);
  407. unref(ls->func_get_width);
  408. unref(ls->func_get_height);
  409. unref(ls->func_get_defaults);
  410. unref(ls->func_get_properties);
  411. unref(ls->func_update);
  412. unref(ls->func_activate);
  413. unref(ls->func_deactivate);
  414. unref(ls->func_show);
  415. unref(ls->func_hide);
  416. unref(ls->func_video_tick);
  417. unref(ls->func_video_render);
  418. unref(ls->func_save);
  419. unref(ls->func_load);
  420. #undef unref
  421. }
  422. static void obs_lua_source_free_type_data(void *type_data)
  423. {
  424. struct obs_lua_source *ls = type_data;
  425. pthread_mutex_lock(&ls->definition_mutex);
  426. if (ls->script) {
  427. lock_script();
  428. source_type_unload(ls);
  429. unlock_script();
  430. ls->script = NULL;
  431. }
  432. pthread_mutex_unlock(&ls->definition_mutex);
  433. pthread_mutex_destroy(&ls->definition_mutex);
  434. bfree(ls);
  435. }
  436. EXPORT void obs_enable_source_type(const char *name, bool enable);
  437. static inline struct obs_lua_source *find_existing(const char *id)
  438. {
  439. struct obs_lua_source *existing = NULL;
  440. pthread_mutex_lock(&lua_source_def_mutex);
  441. struct obs_lua_source *ls = first_source_def;
  442. while (ls) {
  443. /* can compare pointers here due to string table */
  444. if (ls->id == id) {
  445. existing = ls;
  446. break;
  447. }
  448. ls = ls->next;
  449. }
  450. pthread_mutex_unlock(&lua_source_def_mutex);
  451. return existing;
  452. }
  453. static int obs_lua_register_source(lua_State *script)
  454. {
  455. struct obs_lua_source ls = {0};
  456. struct obs_lua_source *existing = NULL;
  457. struct obs_lua_source *v = NULL;
  458. struct obs_source_info info = {0};
  459. const char *id;
  460. if (!verify_args1(script, is_table))
  461. goto fail;
  462. id = get_table_string(script, -1, "id");
  463. if (!id || !*id)
  464. goto fail;
  465. /* redefinition */
  466. existing = find_existing(id);
  467. if (existing) {
  468. if (existing->script) {
  469. existing = NULL;
  470. goto fail;
  471. }
  472. pthread_mutex_lock(&existing->definition_mutex);
  473. }
  474. v = existing ? existing : &ls;
  475. v->script = script;
  476. v->id = id;
  477. info.id = v->id;
  478. info.type = (enum obs_source_type)get_table_int(script, -1, "type");
  479. info.output_flags = get_table_int(script, -1, "output_flags");
  480. lua_pushstring(script, "get_name");
  481. lua_gettable(script, -2);
  482. if (lua_pcall(script, 0, 1, 0) == 0) {
  483. v->display_name = cstrcache_get(lua_tostring(script, -1));
  484. lua_pop(script, 1);
  485. }
  486. if (!v->display_name || !*v->display_name || !*info.id ||
  487. !info.output_flags)
  488. goto fail;
  489. #define get_callback(val) \
  490. do { \
  491. get_callback_from_table(script, -1, #val, &v->func_##val); \
  492. info.val = obs_lua_source_##val; \
  493. } while (false)
  494. get_callback(create);
  495. get_callback(destroy);
  496. get_callback(get_width);
  497. get_callback(get_height);
  498. get_callback(get_properties);
  499. get_callback(update);
  500. get_callback(activate);
  501. get_callback(deactivate);
  502. get_callback(show);
  503. get_callback(hide);
  504. get_callback(video_tick);
  505. get_callback(video_render);
  506. get_callback(save);
  507. get_callback(load);
  508. #undef get_callback
  509. get_callback_from_table(script, -1, "get_defaults",
  510. &v->func_get_defaults);
  511. if (!existing) {
  512. ls.data = current_lua_script;
  513. pthread_mutex_init_recursive(&ls.definition_mutex);
  514. info.type_data = bmemdup(&ls, sizeof(ls));
  515. info.free_type_data = obs_lua_source_free_type_data;
  516. info.get_name = obs_lua_source_get_name;
  517. info.get_defaults2 = obs_lua_source_get_defaults;
  518. obs_register_source(&info);
  519. pthread_mutex_lock(&lua_source_def_mutex);
  520. v = info.type_data;
  521. struct obs_lua_source *next = first_source_def;
  522. v->next = next;
  523. if (next)
  524. next->p_prev_next = &v->next;
  525. v->p_prev_next = &first_source_def;
  526. first_source_def = v;
  527. pthread_mutex_unlock(&lua_source_def_mutex);
  528. } else {
  529. existing->script = script;
  530. existing->data = current_lua_script;
  531. obs_enable_source_type(id, true);
  532. struct obs_lua_data *ld = v->first_source;
  533. while (ld) {
  534. struct obs_lua_source *ls = v;
  535. if (have_func(create)) {
  536. obs_source_t *source = ld->source;
  537. obs_data_t *settings =
  538. obs_source_get_settings(source);
  539. ls_push_libobs_obj(obs_data_t, settings, false);
  540. ls_push_libobs_obj(obs_source_t, source, false);
  541. call_func(create, 2, 1);
  542. ld->lua_data_ref =
  543. luaL_ref(ls->script, LUA_REGISTRYINDEX);
  544. obs_data_release(settings);
  545. }
  546. ld = ld->next;
  547. }
  548. }
  549. fail:
  550. if (existing) {
  551. pthread_mutex_unlock(&existing->definition_mutex);
  552. }
  553. return 0;
  554. }
  555. /* ========================================================================= */
  556. void add_lua_source_functions(lua_State *script)
  557. {
  558. lua_getglobal(script, "obslua");
  559. lua_pushstring(script, "obs_register_source");
  560. lua_pushcfunction(script, obs_lua_register_source);
  561. lua_rawset(script, -3);
  562. lua_pop(script, 1);
  563. }
  564. static inline void undef_source_type(struct obs_lua_script *data,
  565. struct obs_lua_source *ls)
  566. {
  567. pthread_mutex_lock(&ls->definition_mutex);
  568. pthread_mutex_lock(&data->mutex);
  569. obs_enable_source_type(ls->id, false);
  570. struct obs_lua_data *ld = ls->first_source;
  571. while (ld) {
  572. call_destroy(ld);
  573. ld = ld->next;
  574. }
  575. source_type_unload(ls);
  576. ls->script = NULL;
  577. pthread_mutex_unlock(&data->mutex);
  578. pthread_mutex_unlock(&ls->definition_mutex);
  579. }
  580. void undef_lua_script_sources(struct obs_lua_script *data)
  581. {
  582. pthread_mutex_lock(&lua_source_def_mutex);
  583. struct obs_lua_source *def = first_source_def;
  584. while (def) {
  585. if (def->script == data->script)
  586. undef_source_type(data, def);
  587. def = def->next;
  588. }
  589. pthread_mutex_unlock(&lua_source_def_mutex);
  590. }