[vlc-commits] XCB/screen: use shared memory to reduce overhead (if available)
Rémi Denis-Courmont
git at videolan.org
Sat Jan 12 22:50:28 CET 2013
vlc | branch: master | Rémi Denis-Courmont <remi at remlab.net> | Sat Jan 12 23:49:55 2013 +0200| [b97a1a066883a126898467e02aff94c20daede53] | committer: Rémi Denis-Courmont
XCB/screen: use shared memory to reduce overhead (if available)
> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=b97a1a066883a126898467e02aff94c20daede53
---
modules/access/Modules.am | 4 +-
modules/access/screen/xcb.c | 133 +++++++++++++++++++++++++++++++++----------
2 files changed, 106 insertions(+), 31 deletions(-)
diff --git a/modules/access/Modules.am b/modules/access/Modules.am
index d4141b4..122bde2 100644
--- a/modules/access/Modules.am
+++ b/modules/access/Modules.am
@@ -160,9 +160,9 @@ endif
libxcb_screen_plugin_la_SOURCES = screen/xcb.c
libxcb_screen_plugin_la_CFLAGS = $(AM_CFLAGS) \
- $(XCB_CFLAGS) $(XCB_COMPOSITE_CFLAGS)
+ $(XCB_CFLAGS) $(XCB_COMPOSITE_CFLAGS) $(XCB_SHM_CFLAGS)
libxcb_screen_plugin_la_LIBADD = $(AM_LIBADD) \
- $(XCB_LIBS) $(XCB_COMPOSITE_LIBS)
+ $(XCB_LIBS) $(XCB_COMPOSITE_LIBS) $(XCB_SHM_LIBS)
if HAVE_XCB
libvlc_LTLIBRARIES += libxcb_screen_plugin.la
endif
diff --git a/modules/access/screen/xcb.c b/modules/access/screen/xcb.c
index 329922d..7045ce0 100644
--- a/modules/access/screen/xcb.c
+++ b/modules/access/screen/xcb.c
@@ -27,6 +27,10 @@
#include <assert.h>
#include <xcb/xcb.h>
#include <xcb/composite.h>
+#ifdef HAVE_SYS_SHM_H
+# include <sys/shm.h>
+# include <xcb/shm.h>
+#endif
#include <vlc_common.h>
#include <vlc_demux.h>
#include <vlc_plugin.h>
@@ -94,24 +98,43 @@ vlc_module_end ()
static void Demux (void *);
static int Control (demux_t *, int, va_list);
static es_out_id_t *InitES (demux_t *, uint_fast16_t, uint_fast16_t,
- uint_fast8_t);
+ uint_fast8_t, uint8_t *);
struct demux_sys_t
{
/* All owned by timer thread while timer is armed: */
- xcb_connection_t *conn;
- es_out_id_t *es;
- float rate;
- xcb_window_t window;
- xcb_pixmap_t pixmap;
- int16_t x, y;
- uint16_t w, h;
- uint16_t cur_w, cur_h;
+ xcb_connection_t *conn; /**< XCB connection */
+ es_out_id_t *es; /**< Window capture stream */
+ float rate; /**< Frame rate */
+ xcb_window_t window; /**< Captured window XID */
+ xcb_pixmap_t pixmap; /**< Pixmap for composited capture */
+ xcb_shm_seg_t segment; /**< SHM segment XID */
+ int16_t x, y; /**< Requested capture top-left coordinates */
+ uint16_t w, h; /**< Requested capture pixel dimensions */
+ uint8_t bpp; /**< Actual bytes per pixel *es */
+ bool shm; /**< Whether to use MIT-SHM */
bool follow_mouse;
+ uint16_t cur_w, cur_h; /**< Actual capture pixel dimensions */
/* Timer does not use this, only input thread: */
vlc_timer_t timer;
};
+/** Checks MIT-SHM shared memory support */
+static bool CheckSHM (xcb_connection_t *conn)
+{
+#ifdef HAVE_SYS_SHM_H
+ xcb_shm_query_version_cookie_t ck = xcb_shm_query_version (conn);
+ xcb_shm_query_version_reply_t *r;
+
+ r = xcb_shm_query_version_reply (conn, ck, NULL);
+ free (r);
+ return r != NULL;
+#else
+ (void) conn;
+ return false;
+#endif
+}
+
/**
* Probes and initializes.
*/
@@ -192,6 +215,8 @@ static int Open (vlc_object_t *obj)
/* Window properties */
p_sys->pixmap = xcb_generate_id (conn);
+ p_sys->segment = xcb_generate_id (conn);
+ p_sys->shm = CheckSHM (conn);
p_sys->w = var_InheritInteger (obj, "screen-width");
p_sys->h = var_InheritInteger (obj, "screen-height");
if (p_sys->w != 0 || p_sys->h != 0)
@@ -215,6 +240,7 @@ static int Open (vlc_object_t *obj)
p_sys->cur_w = 0;
p_sys->cur_h = 0;
+ p_sys->bpp = 0;
p_sys->es = NULL;
if (vlc_timer_create (&p_sys->timer, Demux, demux))
goto error;
@@ -390,11 +416,12 @@ discard:
geo->root, geo->width, geo->height);
}
- sys->es = InitES (demux, w, h, geo->depth);
+ sys->es = InitES (demux, w, h, geo->depth, &sys->bpp);
if (sys->es != NULL)
{
sys->cur_w = w;
sys->cur_h = h;
+ sys->bpp /= 8; /* bits -> bytes */
}
}
@@ -403,20 +430,69 @@ discard:
(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)
- return;
+ block_t *block = NULL;
+#if HAVE_SYS_SHM_H
+ if (sys->shm)
+ { /* Capture screen through shared memory */
+ size_t size = w * h * sys->bpp;
+ int id = shmget (IPC_PRIVATE, size, IPC_CREAT | 0777);
+ if (id == -1) /* XXX: fallback */
+ {
+ msg_Err (demux, "shared memory allocation error: %m");
+ goto noshm;
+ }
+
+ /* Attach the segment to X and capture */
+ xcb_shm_get_image_reply_t *img;
+ xcb_shm_get_image_cookie_t ck;
- uint8_t *data = xcb_get_image_data (img);
- size_t datalen = xcb_get_image_data_length (img);
- block_t *block = block_heap_Alloc (img, data + datalen - (uint8_t *)img);
+ xcb_shm_attach (conn, sys->segment, id, 0 /* read/write */);
+ ck = xcb_shm_get_image (conn, drawable, x, y, w, h, ~0,
+ XCB_IMAGE_FORMAT_Z_PIXMAP, sys->segment, 0);
+ xcb_shm_detach (conn, sys->segment);
+ img = xcb_shm_get_image_reply (conn, ck, NULL);
+ xcb_flush (conn); /* ensure eventual detach */
+
+ if (img == NULL)
+ {
+ shmctl (id, IPC_RMID, 0);
+ goto noshm;
+ }
+ free (img);
+
+ /* Attach the segment to VLC */
+ void *shm = shmat (id, NULL, 0 /* read/write */);
+ shmctl (id, IPC_RMID, 0);
+ if (-1 == (intptr_t)shm)
+ {
+ msg_Err (demux, "shared memory attachment error: %m");
+ return;
+ }
+
+ block = block_shm_Alloc (shm, size);
+ if (unlikely(block == NULL))
+ shmdt (shm);
+ }
+noshm:
+#endif
if (block == NULL)
- return;
- block->p_buffer = data;
- block->i_buffer = datalen;
+ { /* Capture screen through socket (fallback) */
+ 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)
+ return;
+
+ uint8_t *data = xcb_get_image_data (img);
+ size_t datalen = xcb_get_image_data_length (img);
+ block = block_heap_Alloc (img, data + datalen - (uint8_t *)img);
+ if (block == NULL)
+ return;
+ block->p_buffer = data;
+ block->i_buffer = datalen;
+ }
/* Send block - zero copy */
if (sys->es != NULL)
@@ -429,12 +505,12 @@ discard:
}
static es_out_id_t *InitES (demux_t *demux, uint_fast16_t width,
- uint_fast16_t height, uint_fast8_t depth)
+ uint_fast16_t height, uint_fast8_t depth,
+ uint8_t *bpp)
{
demux_sys_t *p_sys = demux->p_sys;
const xcb_setup_t *setup = xcb_get_setup (p_sys->conn);
uint32_t chroma = 0;
- uint8_t bpp;
for (const xcb_format_t *fmt = xcb_setup_pixmap_formats (setup),
*end = fmt + xcb_setup_pixmap_formats_length (setup);
@@ -442,7 +518,6 @@ static es_out_id_t *InitES (demux_t *demux, uint_fast16_t width,
{
if (fmt->depth != depth)
continue;
- bpp = fmt->depth;
switch (fmt->depth)
{
case 32:
@@ -451,10 +526,7 @@ static es_out_id_t *InitES (demux_t *demux, uint_fast16_t width,
break;
case 24:
if (fmt->bits_per_pixel == 32)
- {
chroma = VLC_CODEC_RGB32;
- bpp = 32;
- }
else if (fmt->bits_per_pixel == 24)
chroma = VLC_CODEC_RGB24;
break;
@@ -472,7 +544,10 @@ static es_out_id_t *InitES (demux_t *demux, uint_fast16_t width,
break;
}
if (chroma != 0)
+ {
+ *bpp = fmt->bits_per_pixel;
break;
+ }
}
if (!chroma)
@@ -485,7 +560,7 @@ static es_out_id_t *InitES (demux_t *demux, uint_fast16_t width,
es_format_Init (&fmt, VIDEO_ES, chroma);
fmt.video.i_chroma = chroma;
- fmt.video.i_bits_per_pixel = bpp;
+ fmt.video.i_bits_per_pixel = *bpp;
fmt.video.i_sar_num = fmt.video.i_sar_den = 1;
fmt.video.i_frame_rate = 1000 * p_sys->rate;
fmt.video.i_frame_rate_base = 1000;
More information about the vlc-commits
mailing list