xshm-input.c 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  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 <stdlib.h>
  15. #include <stdio.h>
  16. #include <sys/shm.h>
  17. #include <X11/Xlib.h>
  18. #include <X11/Xutil.h>
  19. #include <X11/extensions/XShm.h>
  20. #include <obs.h>
  21. #include "xcursor.h"
  22. #define XSHM_DATA(voidptr) struct xshm_data *data = voidptr;
  23. struct xshm_data {
  24. Display *dpy;
  25. Window root_window;
  26. uint32_t width, height;
  27. int shm_attached;
  28. XShmSegmentInfo shm_info;
  29. XImage *image;
  30. texture_t texture;
  31. xcursor_t *cursor;
  32. };
  33. static const char* xshm_getname(const char* locale)
  34. {
  35. UNUSED_PARAMETER(locale);
  36. return "X11 Shared Memory Screen Input";
  37. }
  38. static void xshm_destroy(void *vptr)
  39. {
  40. XSHM_DATA(vptr);
  41. if (!data)
  42. return;
  43. gs_entercontext(obs_graphics());
  44. texture_destroy(data->texture);
  45. xcursor_destroy(data->cursor);
  46. gs_leavecontext();
  47. if (data->shm_attached)
  48. XShmDetach(data->dpy, &data->shm_info);
  49. if (data->shm_info.shmaddr != (char *) -1) {
  50. shmdt(data->shm_info.shmaddr);
  51. data->shm_info.shmaddr = (char *) -1;
  52. }
  53. if (data->shm_info.shmid != -1)
  54. shmctl(data->shm_info.shmid, IPC_RMID, NULL);
  55. if (data->image)
  56. XDestroyImage(data->image);
  57. if (data->dpy)
  58. XCloseDisplay(data->dpy);
  59. bfree(data);
  60. }
  61. static void *xshm_create(obs_data_t settings, obs_source_t source)
  62. {
  63. UNUSED_PARAMETER(settings);
  64. UNUSED_PARAMETER(source);
  65. struct xshm_data *data = bmalloc(sizeof(struct xshm_data));
  66. memset(data, 0, sizeof(struct xshm_data));
  67. data->dpy = XOpenDisplay(NULL);
  68. if (!data->dpy)
  69. goto fail;
  70. Screen *screen = XDefaultScreenOfDisplay(data->dpy);
  71. data->width = WidthOfScreen(screen);
  72. data->height = HeightOfScreen(screen);
  73. data->root_window = XRootWindowOfScreen(screen);
  74. Visual *visual = DefaultVisualOfScreen(screen);
  75. int depth = DefaultDepthOfScreen(screen);
  76. if (!XShmQueryExtension(data->dpy))
  77. goto fail;
  78. data->image = XShmCreateImage(data->dpy, visual, depth,
  79. ZPixmap, NULL, &data->shm_info, data->width, data->height);
  80. if (!data->image)
  81. goto fail;
  82. data->shm_info.shmid = shmget(IPC_PRIVATE,
  83. data->image->bytes_per_line * data->image->height,
  84. IPC_CREAT | 0700);
  85. if (data->shm_info.shmid < 0)
  86. goto fail;
  87. data->shm_info.shmaddr
  88. = data->image->data
  89. = (char *) shmat(data->shm_info.shmid, 0, 0);
  90. if (data->shm_info.shmaddr == (char *) -1)
  91. goto fail;
  92. data->shm_info.readOnly = False;
  93. if (!XShmAttach(data->dpy, &data->shm_info))
  94. goto fail;
  95. data->shm_attached = 1;
  96. if (!XShmGetImage(data->dpy, data->root_window, data->image,
  97. 0, 0, AllPlanes)) {
  98. goto fail;
  99. }
  100. gs_entercontext(obs_graphics());
  101. data->texture = gs_create_texture(data->width, data->height,
  102. GS_BGRA, 1, (const void**) &data->image->data, GS_DYNAMIC);
  103. data->cursor = xcursor_init(data->dpy);
  104. gs_leavecontext();
  105. if (!data->texture)
  106. goto fail;
  107. return data;
  108. fail:
  109. xshm_destroy(data);
  110. return NULL;
  111. }
  112. static void xshm_video_tick(void *vptr, float seconds)
  113. {
  114. UNUSED_PARAMETER(seconds);
  115. XSHM_DATA(vptr);
  116. gs_entercontext(obs_graphics());
  117. XShmGetImage(data->dpy, data->root_window, data->image,
  118. 0, 0, AllPlanes);
  119. texture_setimage(data->texture, (void *) data->image->data,
  120. data->width * 4, False);
  121. xcursor_tick(data->cursor);
  122. gs_leavecontext();
  123. }
  124. static void xshm_video_render(void *vptr, effect_t effect)
  125. {
  126. XSHM_DATA(vptr);
  127. eparam_t image = effect_getparambyname(effect, "image");
  128. effect_settexture(effect, image, data->texture);
  129. gs_enable_blending(False);
  130. gs_draw_sprite(data->texture, 0, 0, 0);
  131. xcursor_render(data->cursor);
  132. }
  133. static uint32_t xshm_getwidth(void *vptr)
  134. {
  135. XSHM_DATA(vptr);
  136. return texture_getwidth(data->texture);
  137. }
  138. static uint32_t xshm_getheight(void *vptr)
  139. {
  140. XSHM_DATA(vptr);
  141. return texture_getheight(data->texture);
  142. }
  143. struct obs_source_info xshm_input = {
  144. .id = "xshm_input",
  145. .type = OBS_SOURCE_TYPE_INPUT,
  146. .output_flags = OBS_SOURCE_VIDEO,
  147. .getname = xshm_getname,
  148. .create = xshm_create,
  149. .destroy = xshm_destroy,
  150. .video_tick = xshm_video_tick,
  151. .video_render = xshm_video_render,
  152. .getwidth = xshm_getwidth,
  153. .getheight = xshm_getheight
  154. };