[vlc-devel] [PATCH] Cursor integration on X11 video screenshots thanks to xfixes
Mehdi Lauters
mehdilauters at gmail.com
Mon May 21 12:01:10 CEST 2012
refactoring the cursor integration on video screenshot on X servers system
Sanity checks on cursor integration
---
modules/access/screen/xcb.c | 168 ++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 167 insertions(+), 1 deletions(-)
diff --git a/modules/access/screen/xcb.c b/modules/access/screen/xcb.c
index c31d380..c538c1e 100644
--- a/modules/access/screen/xcb.c
+++ b/modules/access/screen/xcb.c
@@ -27,6 +27,7 @@
#include <assert.h>
#include <xcb/xcb.h>
#include <xcb/composite.h>
+#include <xcb/xcbext.h>
#include <vlc_common.h>
#include <vlc_demux.h>
#include <vlc_plugin.h>
@@ -109,6 +110,7 @@ struct demux_sys_t
uint16_t w, h;
uint16_t cur_w, cur_h;
bool follow_mouse;
+ bool mouseCapture;
/* Timer does not use this, only input thread: */
vlc_timer_t timer;
};
@@ -158,6 +160,45 @@ static int Open (vlc_object_t *obj)
goto error;
}
p_sys->window = scr->root;
+
+ xcb_extension_t extension;
+ extension.name="XFIXES";
+ extension.global_id = 0;
+
+ // we don't have to free it later ( managed by the cache itself )
+ const xcb_query_extension_reply_t* xfixesPresence;
+
+ /// check if xfixes is available
+ xfixesPresence = xcb_get_extension_data (conn, &extension);
+ if(xfixesPresence->present == 1)
+ {
+ // initializing xfixes (to get the cursor image)
+ xcb_xfixes_query_version_cookie_t xfixesInitCookie;
+ xfixesInitCookie = xcb_xfixes_query_version(conn,XCB_XFIXES_MAJOR_VERSION,
+ XCB_XFIXES_MINOR_VERSION);
+
+ xcb_xfixes_query_version_request_t *xfixesInit;
+ xfixesInit = xcb_xfixes_query_version_reply(conn,
+ xfixesInitCookie,
+ NULL);
+ free(xfixesInit);
+
+ // check if we have a rgba screen
+ if(xcb_depth_visuals(scr->root_depth) == 32)
+ {
+ p_sys->mouseCapture = true;
+ }
+ else
+ {
+ msg_Warn (demux, "Screen depth not supported");
+ p_sys->mouseCapture = false;
+ }
+ }
+ else
+ {
+ msg_Warn (demux, "Xfixes extension not found: no cursor integration");
+ p_sys->mouseCapture = false;
+ }
}
else
/* Determine capture window */
@@ -295,6 +336,79 @@ static int Control (demux_t *demux, int query, va_list args)
return VLC_EGENERIC;
}
+int integrateCursor(uint8_t *screenImageData,xcb_get_geometry_reply_t *geo, xcb_xfixes_get_cursor_image_reply_t* cursorImgReply)
+{
+ uint8_t *pointerImageData;
+
+ // indices to browse images
+ int iScreen;
+ int iPointer=0;
+
+ // we get the cursor image data
+ pointerImageData = xcb_xfixes_get_cursor_image_cursor_image(cursorImgReply);
+
+ //indices to browse the pointer picture
+ int ixCursor=0,
+ iyCursor=0;
+
+ // top left corner of the pointer picture on the screen picture
+ int xMinScreen=cursorImgReply->x-cursorImgReply->xhot,
+
+ // top right corner of the pointer picture on the screen picture
+ yMinScreen=cursorImgReply->y-cursorImgReply->yhot,
+
+ // bottom left corner of the pointer picture on the screen picture
+ xMaxScreen=cursorImgReply->x+(cursorImgReply->width-cursorImgReply->xhot),
+
+ // bottom right corner of the pointer picture on the screen picture
+ yMaxScreen=cursorImgReply->y+(cursorImgReply->width-cursorImgReply->yhot);
+
+
+ // be sure that the entire pointer is on the screenshot
+ if(!(xMinScreen<0 || yMinScreen <0 || xMaxScreen > geo->width
+ || yMaxScreen > geo->height))
+ {
+
+ // we browse the screen picture
+ for(int ix=xMinScreen; // to center on the right point
+ ix<xMaxScreen;
+ ix++)
+ {
+ iyCursor=0;
+ for(int iy=yMinScreen; // to center on the right point
+ iy<yMaxScreen;
+ iy++)
+ {
+ //get the indice of the (ix,iy) pixel in the screen data buffer
+ iScreen=iy*geo->width+ix;
+
+
+ //get the relative indice of the cursor
+ iPointer=iyCursor*cursorImgReply->width+ixCursor;
+
+ // get the indice of the first color of the current pixel
+ iScreen=iScreen*4;
+ iPointer=iPointer*4;
+
+ // /!\ no transparency
+ if(((uint8_t *)pointerImageData)[iPointer+3]>100)
+ {
+ // copying pixels colors
+ screenImageData[iScreen]=pointerImageData[iPointer]; // r
+ screenImageData[iScreen+1]=pointerImageData[iPointer+1];//g
+ screenImageData[iScreen+2]=pointerImageData[iPointer+2];//b
+ }
+ iyCursor++;
+ }
+ ixCursor++;
+ }
+ }
+ else
+ {
+ return VLC_EGENERIC;
+ }
+ return VLC_SUCCESS;
+}
/**
* Processing callback
@@ -402,14 +516,66 @@ discard:
/* Capture screen */
xcb_drawable_t drawable =
(sys->window != geo->root) ? sys->pixmap : sys->window;
- free (geo);
xcb_get_image_reply_t *img;
img = xcb_get_image_reply (conn,
xcb_get_image (conn, XCB_IMAGE_FORMAT_Z_PIXMAP, drawable,
x, y, w, h, ~0), NULL);
if (img == NULL)
+ {
+ free (geo);
return;
+ }
+
+ if(sys->mouseCapture == true)
+ {
+ // we ask for pointer informations ( on the same screen or not )
+ // this information is not given by xcb_xfixes_get_cursor_image
+ xcb_query_pointer_cookie_t pointerCookie = xcb_query_pointer(conn, drawable);
+ xcb_query_pointer_reply_t * pointerReply = xcb_query_pointer_reply (conn,
+ pointerCookie,NULL);
+
+
+ if(pointerReply == NULL)
+ {
+ msg_Warn (demux, "unable to locate cursor");
+ }
+ else
+ {
+ // if the cursor is on the same screen
+ if(pointerReply->same_screen == 1)
+ {
+ // we get more information about the cursor
+ xcb_xfixes_get_cursor_image_cookie_t cursorCookie = xcb_xfixes_get_cursor_image(conn);
+ xcb_xfixes_get_cursor_image_reply_t* cursorImgReply = xcb_xfixes_get_cursor_image_reply (conn,
+ cursorCookie, NULL);
+
+ if(cursorImgReply != NULL)
+ {
+
+ // images data
+ uint8_t *screenImageData=NULL;
+
+ // we get screen image data
+ screenImageData = xcb_get_image_data (img);
+
+ if(integrateCursor(screenImageData,geo,cursorImgReply) != VLC_SUCCESS)
+ {
+ msg_Warn (demux, "Cursor not on the picture");
+ }
+
+ free(cursorImgReply);
+ }
+ else
+ {
+ msg_Warn (demux, "unable to find cursor image");
+ }
+ }
+ }
+
+ free(pointerReply);
+ }
+ free (geo);
uint8_t *data = xcb_get_image_data (img);
size_t datalen = xcb_get_image_data_length (img);
--
1.7.1
More information about the vlc-devel
mailing list