xshm-input.c 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  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. gs_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. gs_texture_destroy(data->texture);
  44. data->texture = gs_texture_create(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_get_int(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_get_bool(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 *unused)
  128. {
  129. UNUSED_PARAMETER(unused);
  130. obs_properties_t *props = obs_properties_create();
  131. int_fast32_t screen_max;
  132. Display *dpy = XOpenDisplay(NULL);
  133. screen_max = xinerama_is_active(dpy)
  134. ? xinerama_screen_count(dpy)
  135. : XScreenCount(dpy);
  136. screen_max = (screen_max) ? screen_max - 1 : 0;
  137. XCloseDisplay(dpy);
  138. obs_properties_add_int(props, "screen",
  139. obs_module_text("Screen"), 0, screen_max, 1);
  140. obs_properties_add_bool(props, "show_cursor",
  141. obs_module_text("CaptureCursor"));
  142. return props;
  143. }
  144. /**
  145. * Destroy the capture
  146. */
  147. static void xshm_destroy(void *vptr)
  148. {
  149. XSHM_DATA(vptr);
  150. if (!data)
  151. return;
  152. obs_enter_graphics();
  153. if (data->texture)
  154. gs_texture_destroy(data->texture);
  155. if (data->cursor)
  156. xcursor_destroy(data->cursor);
  157. obs_leave_graphics();
  158. if (data->xshm)
  159. xshm_detach(data->xshm);
  160. if (data->dpy)
  161. XCloseDisplay(data->dpy);
  162. bfree(data);
  163. }
  164. /**
  165. * Create the capture
  166. */
  167. static void *xshm_create(obs_data_t *settings, obs_source_t *source)
  168. {
  169. UNUSED_PARAMETER(source);
  170. struct xshm_data *data = bzalloc(sizeof(struct xshm_data));
  171. data->dpy = XOpenDisplay(NULL);
  172. if (!data->dpy) {
  173. blog(LOG_ERROR, "xshm-input: Unable to open X display !");
  174. goto fail;
  175. }
  176. if (!XShmQueryExtension(data->dpy)) {
  177. blog(LOG_ERROR, "xshm-input: XShm extension not found !");
  178. goto fail;
  179. }
  180. data->use_xinerama = xinerama_is_active(data->dpy) ? true : false;
  181. obs_enter_graphics();
  182. data->cursor = xcursor_init(data->dpy);
  183. obs_leave_graphics();
  184. xshm_update(data, settings);
  185. return data;
  186. fail:
  187. xshm_destroy(data);
  188. return NULL;
  189. }
  190. /**
  191. * Prepare the capture data
  192. */
  193. static void xshm_video_tick(void *vptr, float seconds)
  194. {
  195. UNUSED_PARAMETER(seconds);
  196. XSHM_DATA(vptr);
  197. if (!data->xshm)
  198. return;
  199. obs_enter_graphics();
  200. XShmGetImage(data->dpy, XRootWindowOfScreen(data->screen),
  201. data->xshm->image, data->x_org, data->y_org, AllPlanes);
  202. gs_texture_set_image(data->texture, (void *) data->xshm->image->data,
  203. data->width * 4, false);
  204. xcursor_tick(data->cursor);
  205. obs_leave_graphics();
  206. }
  207. /**
  208. * Render the capture data
  209. */
  210. static void xshm_video_render(void *vptr, gs_effect_t *effect)
  211. {
  212. XSHM_DATA(vptr);
  213. if (!data->xshm)
  214. return;
  215. gs_eparam_t *image = gs_effect_get_param_by_name(effect, "image");
  216. gs_effect_set_texture(image, data->texture);
  217. gs_enable_blending(false);
  218. gs_draw_sprite(data->texture, 0, 0, 0);
  219. if (data->show_cursor)
  220. xcursor_render(data->cursor);
  221. gs_reset_blend_state();
  222. }
  223. /**
  224. * Width of the captured data
  225. */
  226. static uint32_t xshm_getwidth(void *vptr)
  227. {
  228. XSHM_DATA(vptr);
  229. return data->width;
  230. }
  231. /**
  232. * Height of the captured data
  233. */
  234. static uint32_t xshm_getheight(void *vptr)
  235. {
  236. XSHM_DATA(vptr);
  237. return data->height;
  238. }
  239. struct obs_source_info xshm_input = {
  240. .id = "xshm_input",
  241. .type = OBS_SOURCE_TYPE_INPUT,
  242. .output_flags = OBS_SOURCE_VIDEO,
  243. .get_name = xshm_getname,
  244. .create = xshm_create,
  245. .destroy = xshm_destroy,
  246. .update = xshm_update,
  247. .get_defaults = xshm_defaults,
  248. .get_properties = xshm_properties,
  249. .video_tick = xshm_video_tick,
  250. .video_render = xshm_video_render,
  251. .get_width = xshm_getwidth,
  252. .get_height = xshm_getheight
  253. };