| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314 |
- /*
- Copyright (C) 2014 by Leonhard Oelke <[email protected]>
- 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 <stdio.h>
- #include <stdlib.h>
- #include <inttypes.h>
- #include <X11/Xlib.h>
- #include <X11/Xutil.h>
- #include <obs-module.h>
- #include "xcursor.h"
- #include "xhelpers.h"
- #define XSHM_DATA(voidptr) struct xshm_data *data = voidptr;
- struct xshm_data {
- Display *dpy;
- Screen *screen;
- int_fast32_t x_org, y_org;
- int_fast32_t width, height;
- xshm_t *xshm;
- texture_t texture;
- bool show_cursor;
- xcursor_t *cursor;
- bool use_xinerama;
- };
- /**
- * Resize the texture
- *
- * This will automatically create the texture if it does not exist
- */
- static void xshm_resize_texture(struct xshm_data *data)
- {
- obs_enter_graphics();
- if (data->texture)
- texture_destroy(data->texture);
- data->texture = gs_create_texture(data->width, data->height,
- GS_BGRA, 1, NULL, GS_DYNAMIC);
- obs_leave_graphics();
- }
- /**
- * Update the capture
- *
- * @return < 0 on error, 0 when size is unchanged, > 1 on size change
- */
- static int_fast32_t xshm_update_geometry(struct xshm_data *data,
- obs_data_t settings)
- {
- int_fast32_t old_width = data->width;
- int_fast32_t old_height = data->height;
- int_fast32_t screen = obs_data_getint(settings, "screen");
- if (data->use_xinerama) {
- if (xinerama_screen_geo(data->dpy, screen,
- &data->x_org, &data->y_org,
- &data->width, &data->height) < 0) {
- return -1;
- }
- data->screen = XDefaultScreenOfDisplay(data->dpy);
- }
- else {
- data->x_org = 0;
- data->y_org = 0;
- if (x11_screen_geo(data->dpy, screen,
- &data->width, &data->height) < 0) {
- return -1;
- }
- data->screen = XScreenOfDisplay(data->dpy, screen);
- }
- if (!data->width || !data->height) {
- blog(LOG_ERROR, "xshm-input: Failed to get geometry");
- return -1;
- }
- blog(LOG_INFO, "xshm-input: Geometry %"PRIdFAST32"x%"PRIdFAST32
- " @ %"PRIdFAST32",%"PRIdFAST32,
- data->width, data->height, data->x_org, data->y_org);
- if (old_width == data->width && old_height == data->height)
- return 0;
- return 1;
- }
- /**
- * Returns the name of the plugin
- */
- static const char* xshm_getname(void)
- {
- return obs_module_text("X11SharedMemoryScreenInput");
- }
- /**
- * Update the capture with changed settings
- */
- static void xshm_update(void *vptr, obs_data_t settings)
- {
- XSHM_DATA(vptr);
- data->show_cursor = obs_data_getbool(settings, "show_cursor");
- if (data->xshm)
- xshm_detach(data->xshm);
- if (xshm_update_geometry(data, settings) < 0) {
- blog(LOG_ERROR, "xshm-input: failed to update geometry !");
- return;
- }
- xshm_resize_texture(data);
- xcursor_offset(data->cursor, data->x_org, data->y_org);
- data->xshm = xshm_attach(data->dpy, data->screen,
- data->width, data->height);
- if (!data->xshm) {
- blog(LOG_ERROR, "xshm-input: failed to attach shm !");
- return;
- }
- }
- /**
- * Get the default settings for the capture
- */
- static void xshm_defaults(obs_data_t defaults)
- {
- obs_data_set_default_int(defaults, "screen", 0);
- obs_data_set_default_bool(defaults, "show_cursor", true);
- }
- /**
- * Get the properties for the capture
- */
- static obs_properties_t xshm_properties(void)
- {
- obs_properties_t props = obs_properties_create();
- int_fast32_t screen_max;
- Display *dpy = XOpenDisplay(NULL);
- screen_max = xinerama_is_active(dpy)
- ? xinerama_screen_count(dpy)
- : XScreenCount(dpy);
- screen_max = (screen_max) ? screen_max - 1 : 0;
- XCloseDisplay(dpy);
- obs_properties_add_int(props, "screen",
- obs_module_text("Screen"), 0, screen_max, 1);
- obs_properties_add_bool(props, "show_cursor",
- obs_module_text("CaptureCursor"));
- return props;
- }
- /**
- * Destroy the capture
- */
- static void xshm_destroy(void *vptr)
- {
- XSHM_DATA(vptr);
- if (!data)
- return;
- obs_enter_graphics();
- if (data->texture)
- texture_destroy(data->texture);
- if (data->cursor)
- xcursor_destroy(data->cursor);
- obs_leave_graphics();
- if (data->xshm)
- xshm_detach(data->xshm);
- if (data->dpy)
- XCloseDisplay(data->dpy);
- bfree(data);
- }
- /**
- * Create the capture
- */
- static void *xshm_create(obs_data_t settings, obs_source_t source)
- {
- UNUSED_PARAMETER(source);
- struct xshm_data *data = bzalloc(sizeof(struct xshm_data));
- data->dpy = XOpenDisplay(NULL);
- if (!data->dpy) {
- blog(LOG_ERROR, "xshm-input: Unable to open X display !");
- goto fail;
- }
- if (!XShmQueryExtension(data->dpy)) {
- blog(LOG_ERROR, "xshm-input: XShm extension not found !");
- goto fail;
- }
- data->use_xinerama = xinerama_is_active(data->dpy) ? true : false;
- obs_enter_graphics();
- data->cursor = xcursor_init(data->dpy);
- obs_leave_graphics();
- xshm_update(data, settings);
- return data;
- fail:
- xshm_destroy(data);
- return NULL;
- }
- /**
- * Prepare the capture data
- */
- static void xshm_video_tick(void *vptr, float seconds)
- {
- UNUSED_PARAMETER(seconds);
- XSHM_DATA(vptr);
- if (!data->xshm)
- return;
- obs_enter_graphics();
- XShmGetImage(data->dpy, XRootWindowOfScreen(data->screen),
- data->xshm->image, data->x_org, data->y_org, AllPlanes);
- texture_setimage(data->texture, (void *) data->xshm->image->data,
- data->width * 4, false);
- xcursor_tick(data->cursor);
- obs_leave_graphics();
- }
- /**
- * Render the capture data
- */
- static void xshm_video_render(void *vptr, effect_t effect)
- {
- XSHM_DATA(vptr);
- if (!data->xshm)
- return;
- eparam_t image = effect_getparambyname(effect, "image");
- effect_settexture(image, data->texture);
- gs_enable_blending(false);
- gs_draw_sprite(data->texture, 0, 0, 0);
- if (data->show_cursor)
- xcursor_render(data->cursor);
- gs_reset_blend_state();
- }
- /**
- * Width of the captured data
- */
- static uint32_t xshm_getwidth(void *vptr)
- {
- XSHM_DATA(vptr);
- return data->width;
- }
- /**
- * Height of the captured data
- */
- static uint32_t xshm_getheight(void *vptr)
- {
- XSHM_DATA(vptr);
- return data->height;
- }
- struct obs_source_info xshm_input = {
- .id = "xshm_input",
- .type = OBS_SOURCE_TYPE_INPUT,
- .output_flags = OBS_SOURCE_VIDEO,
- .get_name = xshm_getname,
- .create = xshm_create,
- .destroy = xshm_destroy,
- .update = xshm_update,
- .get_defaults = xshm_defaults,
- .get_properties = xshm_properties,
- .video_tick = xshm_video_tick,
- .video_render = xshm_video_render,
- .get_width = xshm_getwidth,
- .get_height = xshm_getheight
- };
|