[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