xshm-input.c 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. /*
  2. Copyright (C) 2014 by Leonhard Oelke <[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 <stdio.h>
  15. #include <stdlib.h>
  16. #include <inttypes.h>
  17. #include <X11/Xlib.h>
  18. #include <X11/Xutil.h>
  19. #include <obs-module.h>
  20. #include "xcursor.h"
  21. #include "xhelpers.h"
  22. #define XSHM_DATA(voidptr) struct xshm_data *data = voidptr;
  23. struct xshm_data {
  24. Display *dpy;
  25. Screen *screen;
  26. int_fast32_t x_org, y_org;
  27. int_fast32_t width, height;
  28. xshm_t *xshm;
  29. texture_t texture;
  30. bool show_cursor;
  31. xcursor_t *cursor;
  32. bool use_xinerama;
  33. };
  34. /**
  35. * Resize the texture
  36. *
  37. * This will automatically create the texture if it does not exist
  38. */
  39. static void xshm_resize_texture(struct xshm_data *data)
  40. {
  41. obs_enter_graphics();
  42. if (data->texture)
  43. texture_destroy(data->texture);
  44. data->texture = gs_create_texture(data->width, data->height,
  45. GS_BGRA, 1, NULL, GS_DYNAMIC);
  46. obs_leave_graphics();
  47. }
  48. /**
  49. * Update the capture
  50. *
  51. * @return < 0 on error, 0 when size is unchanged, > 1 on size change
  52. */
  53. static int_fast32_t xshm_update_geometry(struct xshm_data *data,
  54. obs_data_t settings)
  55. {
  56. int_fast32_t old_width = data->width;
  57. int_fast32_t old_height = data->height;
  58. int_fast32_t screen = obs_data_getint(settings, "screen");
  59. if (data->use_xinerama) {
  60. if (xinerama_screen_geo(data->dpy, screen,
  61. &data->x_org, &data->y_org,
  62. &data->width, &data->height) < 0) {
  63. return -1;
  64. }
  65. data->screen = XDefaultScreenOfDisplay(data->dpy);
  66. }
  67. else {
  68. data->x_org = 0;
  69. data->y_org = 0;
  70. if (x11_screen_geo(data->dpy, screen,
  71. &data->width, &data->height) < 0) {
  72. return -1;
  73. }
  74. data->screen = XScreenOfDisplay(data->dpy, screen);
  75. }
  76. if (!data->width || !data->height) {
  77. blog(LOG_ERROR, "xshm-input: Failed to get geometry");
  78. return -1;
  79. }
  80. blog(LOG_INFO, "xshm-input: Geometry %"PRIdFAST32"x%"PRIdFAST32
  81. " @ %"PRIdFAST32",%"PRIdFAST32,
  82. data->width, data->height, data->x_org, data->y_org);
  83. if (old_width == data->width && old_height == data->height)
  84. return 0;
  85. return 1;
  86. }
  87. /**
  88. * Returns the name of the plugin
  89. */
  90. static const char* xshm_getname(void)
  91. {
  92. return obs_module_text("X11SharedMemoryScreenInput");
  93. }
  94. /**
  95. * Update the capture with changed settings
  96. */
  97. static void xshm_update(void *vptr, obs_data_t settings)
  98. {
  99. XSHM_DATA(vptr);
  100. data->show_cursor = obs_data_getbool(settings, "show_cursor");
  101. if (data->xshm)
  102. xshm_detach(data->xshm);
  103. if (xshm_update_geometry(data, settings) < 0) {
  104. blog(LOG_ERROR, "xshm-input: failed to update geometry !");
  105. return;
  106. }
  107. xshm_resize_texture(data);
  108. xcursor_offset(data->cursor, data->x_org, data->y_org);
  109. data->xshm = xshm_attach(data->dpy, data->screen,
  110. data->width, data->height);
  111. if (!data->xshm) {
  112. blog(LOG_ERROR, "xshm-input: failed to attach shm !");
  113. return;
  114. }
  115. }
  116. /**
  117. * Get the default settings for the capture
  118. */
  119. static void xshm_defaults(obs_data_t defaults)
  120. {
  121. obs_data_set_default_int(defaults, "screen", 0);
  122. obs_data_set_default_bool(defaults, "show_cursor", true);
  123. }
  124. /**
  125. * Get the properties for the capture
  126. */
  127. static obs_properties_t xshm_properties(void)
  128. {
  129. obs_properties_t props = obs_properties_create();
  130. int_fast32_t screen_max;
  131. Display *dpy = XOpenDisplay(NULL);
  132. screen_max = xinerama_is_active(dpy)
  133. ? xinerama_screen_count(dpy)
  134. : XScreenCount(dpy);
  135. screen_max = (screen_max) ? screen_max - 1 : 0;
  136. XCloseDisplay(dpy);
  137. obs_properties_add_int(props, "screen",
  138. obs_module_text("Screen"), 0, screen_max, 1);
  139. obs_properties_add_bool(props, "show_cursor",
  140. obs_module_text("CaptureCursor"));
  141. return props;
  142. }
  143. /**
  144. * Destroy the capture
  145. */
  146. static void xshm_destroy(void *vptr)
  147. {
  148. XSHM_DATA(vptr);
  149. if (!data)
  150. return;
  151. obs_enter_graphics();
  152. if (data->texture)
  153. texture_destroy(data->texture);
  154. if (data->cursor)
  155. xcursor_destroy(data->cursor);
  156. obs_leave_graphics();
  157. if (data->xshm)
  158. xshm_detach(data->xshm);
  159. if (data->dpy)
  160. XCloseDisplay(data->dpy);
  161. bfree(data);
  162. }
  163. /**
  164. * Create the capture
  165. */
  166. static void *xshm_create(obs_data_t settings, obs_source_t source)
  167. {
  168. UNUSED_PARAMETER(source);
  169. struct xshm_data *data = bzalloc(sizeof(struct xshm_data));
  170. data->dpy = XOpenDisplay(NULL);
  171. if (!data->dpy) {
  172. blog(LOG_ERROR, "xshm-input: Unable to open X display !");
  173. goto fail;
  174. }
  175. if (!XShmQueryExtension(data->dpy)) {
  176. blog(LOG_ERROR, "xshm-input: XShm extension not found !");
  177. goto fail;
  178. }
  179. data->use_xinerama = xinerama_is_active(data->dpy) ? true : false;
  180. obs_enter_graphics();
  181. data->cursor = xcursor_init(data->dpy);
  182. obs_leave_graphics();
  183. xshm_update(data, settings);
  184. return data;
  185. fail:
  186. xshm_destroy(data);
  187. return NULL;
  188. }
  189. /**
  190. * Prepare the capture data
  191. */
  192. static void xshm_video_tick(void *vptr, float seconds)
  193. {
  194. UNUSED_PARAMETER(seconds);
  195. XSHM_DATA(vptr);
  196. if (!data->xshm)
  197. return;
  198. obs_enter_graphics();
  199. XShmGetImage(data->dpy, XRootWindowOfScreen(data->screen),
  200. data->xshm->image, data->x_org, data->y_org, AllPlanes);
  201. texture_setimage(data->texture, (void *) data->xshm->image->data,
  202. data->width * 4, false);
  203. xcursor_tick(data->cursor);
  204. obs_leave_graphics();
  205. }
  206. /**
  207. * Render the capture data
  208. */
  209. static void xshm_video_render(void *vptr, effect_t effect)
  210. {
  211. XSHM_DATA(vptr);
  212. if (!data->xshm)
  213. return;
  214. eparam_t image = effect_getparambyname(effect, "image");
  215. effect_settexture(image, data->texture);
  216. gs_enable_blending(false);
  217. gs_draw_sprite(data->texture, 0, 0, 0);
  218. if (data->show_cursor)
  219. xcursor_render(data->cursor);
  220. gs_reset_blend_state();
  221. }
  222. /**
  223. * Width of the captured data
  224. */
  225. static uint32_t xshm_getwidth(void *vptr)
  226. {
  227. XSHM_DATA(vptr);
  228. return data->width;
  229. }
  230. /**
  231. * Height of the captured data
  232. */
  233. static uint32_t xshm_getheight(void *vptr)
  234. {
  235. XSHM_DATA(vptr);
  236. return data->height;
  237. }
  238. struct obs_source_info xshm_input = {
  239. .id = "xshm_input",
  240. .type = OBS_SOURCE_TYPE_INPUT,
  241. .output_flags = OBS_SOURCE_VIDEO,
  242. .get_name = xshm_getname,
  243. .create = xshm_create,
  244. .destroy = xshm_destroy,
  245. .update = xshm_update,
  246. .get_defaults = xshm_defaults,
  247. .get_properties = xshm_properties,
  248. .video_tick = xshm_video_tick,
  249. .video_render = xshm_video_render,
  250. .get_width = xshm_getwidth,
  251. .get_height = xshm_getheight
  252. };