diff --git a/modules/access/screen/xcb.c b/modules/access/screen/xcb.c index 76cead425bf314a96543880d2d6f358634587c5d..0a464e8b0aa3a418656b4bee1b2b2ef0db958f4c 100644 --- a/modules/access/screen/xcb.c +++ b/modules/access/screen/xcb.c @@ -100,16 +100,19 @@ 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); struct demux_sys_t { xcb_connection_t *conn; es_out_id_t *es; - es_format_t fmt; mtime_t pts, interval; - xcb_window_t root, window; + float rate; + xcb_window_t window; int16_t x, y; uint16_t w, h; + uint16_t cur_w, cur_h; bool follow_mouse; /* fmt, es and pts are protected by the lock. The rest is read-only. */ vlc_mutex_t lock; @@ -141,30 +144,30 @@ static int Open (vlc_object_t *obj) } p_sys->conn = conn; - /* Find configured screen */ - const xcb_setup_t *setup = xcb_get_setup (conn); - const xcb_screen_t *scr = NULL; - for (xcb_screen_iterator_t i = xcb_setup_roots_iterator (setup); - i.rem > 0; xcb_screen_next (&i)) + /* Find configured screen */ + if (!strcmp (demux->psz_access, "screen")) { - if (snum == 0) + const xcb_setup_t *setup = xcb_get_setup (conn); + const xcb_screen_t *scr = NULL; + for (xcb_screen_iterator_t i = xcb_setup_roots_iterator (setup); + i.rem > 0; xcb_screen_next (&i)) { - scr = i.data; - break; + if (snum == 0) + { + scr = i.data; + break; + } + snum--; } - snum--; - } - if (scr == NULL) - { - msg_Err (obj, "bad X11 screen number"); - goto error; + if (scr == NULL) + { + msg_Err (obj, "bad X11 screen number"); + goto error; + } + p_sys->window = scr->root; } - - /* Determine capture window */ - p_sys->root = scr->root; - if (!strcmp (demux->psz_access, "screen")) - p_sys->window = p_sys->root; else + /* Determine capture window */ if (!strcmp (demux->psz_access, "window")) { char *end; @@ -186,68 +189,17 @@ static int Open (vlc_object_t *obj) p_sys->h = var_CreateGetInteger (obj, "screen-height"); p_sys->follow_mouse = var_CreateGetBool (obj, "screen-follow-mouse"); - 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); - fmt < end; fmt++) - { - if (fmt->depth != scr->root_depth) - continue; - bpp = fmt->depth; - switch (fmt->depth) - { - case 32: - if (fmt->bits_per_pixel == 32) - chroma = VLC_CODEC_RGBA; - 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; - case 16: - if (fmt->bits_per_pixel == 16) - chroma = VLC_CODEC_RGB16; - break; - case 15: - if (fmt->bits_per_pixel == 16) - chroma = VLC_CODEC_RGB15; - break; - case 8: /* XXX: screw grey scale! */ - if (fmt->bits_per_pixel == 8) - chroma = VLC_CODEC_RGB8; - break; - } - if (chroma != 0) - break; - } - - if (!chroma) - { - msg_Err (obj, "unsupported pixmap formats"); - goto error; - } - /* Initializes format */ - float rate = var_CreateGetFloat (obj, "screen-fps"); - if (!rate) + p_sys->rate = var_CreateGetFloat (obj, "screen-fps"); + if (!p_sys->rate) goto error; - p_sys->interval = (float)CLOCK_FREQ / rate; + p_sys->interval = (float)CLOCK_FREQ / p_sys->rate; if (!p_sys->interval) goto error; var_Create (obj, "screen-caching", VLC_VAR_INTEGER|VLC_VAR_DOINHERIT); - es_format_Init (&p_sys->fmt, VIDEO_ES, chroma); - p_sys->fmt.video.i_chroma = chroma; - p_sys->fmt.video.i_bits_per_pixel = bpp; - p_sys->fmt.video.i_sar_num = p_sys->fmt.video.i_sar_den = 1; - p_sys->fmt.video.i_frame_rate = 1000 * rate; - p_sys->fmt.video.i_frame_rate_base = 1000; + p_sys->cur_w = 0; + p_sys->cur_h = 0; p_sys->es = NULL; p_sys->pts = VLC_TS_INVALID; vlc_mutex_init (&p_sys->lock); @@ -362,24 +314,27 @@ static void Demux (void *data) xcb_connection_t *conn = p_sys->conn; /* Update capture region (if needed) */ - xcb_get_geometry_cookie_t gc = xcb_get_geometry (conn, p_sys->window); + + xcb_get_geometry_reply_t *geo = + xcb_get_geometry_reply (conn, + xcb_get_geometry (conn, p_sys->window), NULL); + if (geo == NULL) + { + msg_Err (demux, "bad X11 drawable 0x%08"PRIx32, p_sys->window); + return; + } + + xcb_window_t root = geo->root; int16_t x = p_sys->x, y = p_sys->y; xcb_translate_coordinates_cookie_t tc; xcb_query_pointer_cookie_t qc; - if (p_sys->window != p_sys->root) - tc = xcb_translate_coordinates (conn, p_sys->window, p_sys->root, + if (p_sys->window != root) + tc = xcb_translate_coordinates (conn, p_sys->window, root, x, y); if (p_sys->follow_mouse) qc = xcb_query_pointer (conn, p_sys->window); - xcb_get_geometry_reply_t *geo = xcb_get_geometry_reply (conn, gc, NULL); - if (geo == NULL) - { - msg_Err (demux, "bad X11 drawable 0x%08"PRIx32, p_sys->window); - return; - } - uint16_t ow = geo->width - x; uint16_t oh = geo->height - y; uint16_t w = p_sys->w; @@ -388,9 +343,10 @@ static void Demux (void *data) w = ow; if (h == 0 || h > oh) h = oh; + uint8_t depth = geo->depth; free (geo); - if (p_sys->window != p_sys->root) + if (p_sys->window != root) { xcb_translate_coordinates_reply_t *coords = xcb_translate_coordinates_reply (conn, tc, NULL); @@ -429,7 +385,7 @@ static void Demux (void *data) xcb_get_image_reply_t *img; img = xcb_get_image_reply (conn, - xcb_get_image (conn, XCB_IMAGE_FORMAT_Z_PIXMAP, p_sys->root, + xcb_get_image (conn, XCB_IMAGE_FORMAT_Z_PIXMAP, root, x, y, w, h, ~0), NULL); if (img == NULL) return; @@ -441,14 +397,16 @@ static void Demux (void *data) return; vlc_mutex_lock (&p_sys->lock); - if (w != p_sys->fmt.video.i_visible_width - || h != p_sys->fmt.video.i_visible_height) + if (w != p_sys->cur_w || h != p_sys->cur_h) { if (p_sys->es != NULL) es_out_Del (demux->out, p_sys->es); - p_sys->fmt.video.i_visible_width = p_sys->fmt.video.i_width = w; - p_sys->fmt.video.i_visible_height = p_sys->fmt.video.i_height = h; - p_sys->es = es_out_Add (demux->out, &p_sys->fmt); + p_sys->es = InitES (demux, w, h, depth); + if (p_sys->es != NULL) + { + p_sys->cur_w = w; + p_sys->cur_h = h; + } } /* Capture screen */ @@ -464,3 +422,70 @@ static void Demux (void *data) } vlc_mutex_unlock (&p_sys->lock); } + +static es_out_id_t *InitES (demux_t *demux, uint_fast16_t width, + uint_fast16_t height, uint_fast8_t depth) +{ + 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); + fmt < end; fmt++) + { + if (fmt->depth != depth) + continue; + bpp = fmt->depth; + switch (fmt->depth) + { + case 32: + if (fmt->bits_per_pixel == 32) + chroma = VLC_CODEC_RGBA; + 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; + case 16: + if (fmt->bits_per_pixel == 16) + chroma = VLC_CODEC_RGB16; + break; + case 15: + if (fmt->bits_per_pixel == 16) + chroma = VLC_CODEC_RGB15; + break; + case 8: /* XXX: screw grey scale! */ + if (fmt->bits_per_pixel == 8) + chroma = VLC_CODEC_RGB8; + break; + } + if (chroma != 0) + break; + } + + if (!chroma) + { + msg_Err (demux, "unsupported pixmap formats"); + return NULL; + } + + es_format_t fmt; + + es_format_Init (&fmt, VIDEO_ES, chroma); + fmt.video.i_chroma = chroma; + 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; + fmt.video.i_visible_width = fmt.video.i_width = width; + fmt.video.i_visible_height = fmt.video.i_height = height; + + return es_out_Add (demux->out, &fmt); +}