vlc | branch: master | Rémi Denis-Courmont <[email protected]> | 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; _______________________________________________ vlc-commits mailing list [email protected] http://mailman.videolan.org/listinfo/vlc-commits
