Example #1
0
/**
 * Probes and initializes.
 */
static int Open (vlc_object_t *obj)
{
    demux_t *demux = (demux_t *)obj;
    demux_sys_t *p_sys = malloc (sizeof (*p_sys));

    if (p_sys == NULL)
        return VLC_ENOMEM;
    demux->p_sys = p_sys;

    /* Connect to X server */
    char *display = var_InheritString (obj, "x11-display");
    int snum;
    xcb_connection_t *conn = xcb_connect (display, &snum);
    free (display);
    if (xcb_connection_has_error (conn))
    {
        free (p_sys);
        return VLC_EGENERIC;
    }
    p_sys->conn = conn;

   /* Find configured screen */
    if (!strcmp (demux->psz_access, "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))
        {
            if (snum == 0)
            {
               scr = i.data;
                break;
            }
            snum--;
        }
        if (scr == NULL)
        {
            msg_Err (obj, "bad X11 screen number");
            goto error;
        }
        p_sys->window = scr->root;
    }
    else
    /* Determine capture window */
    if (!strcmp (demux->psz_access, "window"))
    {
        char *end;
        unsigned long ul = strtoul (demux->psz_location, &end, 0);
        if (*end || ul > 0xffffffff)
        {
            msg_Err (obj, "bad X11 drawable %s", demux->psz_location);
            goto error;
        }
        p_sys->window = ul;

        xcb_composite_query_version_reply_t *r =
            xcb_composite_query_version_reply (conn,
                xcb_composite_query_version (conn, 0, 4), NULL);
        if (r == NULL || r->minor_version < 2)
        {
            msg_Err (obj, "X Composite extension not available");
            free (r);
            goto error;
        }
        msg_Dbg (obj, "using Composite extension v%"PRIu32".%"PRIu32,
                 r->major_version, r->minor_version);
        free (r);

        xcb_composite_redirect_window (conn, p_sys->window,
                                       XCB_COMPOSITE_REDIRECT_AUTOMATIC);
    }
    else
        goto error;

    /* 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)
        p_sys->follow_mouse = var_InheritBool (obj, "screen-follow-mouse");
    else /* Following mouse is meaningless if width&height are dynamic. */
        p_sys->follow_mouse = false;
    if (!p_sys->follow_mouse) /* X and Y are meaningless if following mouse */
    {
        p_sys->x = var_InheritInteger (obj, "screen-left");
        p_sys->y = var_InheritInteger (obj, "screen-top");
    }

    /* Initializes format */
    p_sys->rate = var_InheritFloat (obj, "screen-fps");
    if (!p_sys->rate)
        goto error;

    mtime_t interval = (float)CLOCK_FREQ / p_sys->rate;
    if (!interval)
        goto error;

    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;
    vlc_timer_schedule (p_sys->timer, false, 1, interval);

    /* Initializes demux */
    demux->pf_demux   = NULL;
    demux->pf_control = Control;
    return VLC_SUCCESS;

error:
    xcb_disconnect (p_sys->conn);
    free (p_sys);
    return VLC_EGENERIC;
}
Example #2
0
File: x11.c Project: paa/vlc
/**
 * Probe the X server.
 */
static int Open (vlc_object_t *obj)
{
    vout_display_t *vd = (vout_display_t *)obj;
    vout_display_sys_t *p_sys = malloc (sizeof (*p_sys));
    if (p_sys == NULL)
        return VLC_ENOMEM;

    vd->sys = p_sys;
    p_sys->pool = NULL;

    /* Get window, connect to X server */
    const xcb_screen_t *scr;
    p_sys->embed = GetWindow (vd, &p_sys->conn, &scr, &(uint8_t){ 0 });
    if (p_sys->embed == NULL)
    {
        free (p_sys);
        return VLC_EGENERIC;
    }

    const xcb_setup_t *setup = xcb_get_setup (p_sys->conn);
    p_sys->byte_order = setup->image_byte_order;

    /* Determine our pixel format */
    xcb_visualid_t vid = 0;
    p_sys->depth = 0;

    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 <= p_sys->depth)
            continue; /* no better than earlier format */

        video_format_t fmt_pic = vd->fmt;

        /* Check that the pixmap format is supported by VLC. */
        switch (fmt->depth)
        {
          case 32:
            if (fmt->bits_per_pixel != 32)
                continue;
#ifdef FIXED_VLC_RGBA_MASK
            fmt_pic.i_chroma = VLC_CODEC_RGBA;
            break;
#else
            msg_Dbg (vd, "X11 visual with alpha-channel not supported");
            continue;
#endif
          case 24:
            if (fmt->bits_per_pixel == 32)
                fmt_pic.i_chroma = VLC_CODEC_RGB32;
            else if (fmt->bits_per_pixel == 24)
                fmt_pic.i_chroma = VLC_CODEC_RGB24;
            else
                continue;
            break;
          case 16:
            if (fmt->bits_per_pixel != 16)
                continue;
            fmt_pic.i_chroma = VLC_CODEC_RGB16;
            break;
          case 15:
            if (fmt->bits_per_pixel != 16)
                continue;
            fmt_pic.i_chroma = VLC_CODEC_RGB15;
            break;
          case 8:
            if (fmt->bits_per_pixel != 8)
                continue;
            fmt_pic.i_chroma = VLC_CODEC_RGB8;
            break;
          default:
            continue;
        }

        /* VLC pads lines to 16 pixels internally */
        if ((fmt->bits_per_pixel << 4) % fmt->scanline_pad)
            continue;

        /* Byte sex is a non-issue for 8-bits. It can be worked around with
         * RGB masks for 24-bits. Too bad for 15-bits and 16-bits. */
        if (fmt->bits_per_pixel == 16 && setup->image_byte_order != ORDER)
            continue;

        /* Check that the selected screen supports this depth */
        const xcb_depth_t *d = FindDepth (scr, fmt->depth);
        if (d == NULL)
            continue;

        /* Find a visual type for the selected depth */
        const xcb_visualtype_t *vt = xcb_depth_visuals (d);

        /* First try True Color class */
        for (int i = xcb_depth_visuals_length (d); i > 0; i--)
        {
            if (vt->_class == XCB_VISUAL_CLASS_TRUE_COLOR)
            {
                fmt_pic.i_rmask = vt->red_mask;
                fmt_pic.i_gmask = vt->green_mask;
                fmt_pic.i_bmask = vt->blue_mask;
                goto found_visual;
            }
            vt++;
        }
        /* Then try Static Gray class */
        if (fmt->depth == 8)
            for (int i = xcb_depth_visuals_length (d); i > 0 && !vid; i--)
            {
                if (vt->_class == XCB_VISUAL_CLASS_STATIC_GRAY)
                    goto found_grey;
                vt++;
            }

        continue; /* Fail: unusable pixel format */

    found_grey:
       fmt_pic.i_chroma = VLC_CODEC_GREY;
    found_visual:
        p_sys->bpp = fmt->bits_per_pixel;
        p_sys->pad = fmt->scanline_pad;
        p_sys->depth = fmt->depth;
        vd->fmt = fmt_pic;
        vid = vt->visual_id;
    }

    if (!vid)
    {
        msg_Err (obj, "no supported pixel format & visual");
        goto error;
    }

    msg_Dbg (vd, "using X11 visual ID 0x%"PRIx32, vid);
    msg_Dbg (vd, " %"PRIu8" bits depth", p_sys->depth);
    msg_Dbg (vd, " %"PRIu8" bits per pixel", p_sys->bpp);
    msg_Dbg (vd, " %"PRIu8" bits line pad", p_sys->pad);

    /* Create colormap (needed to select non-default visual) */
    xcb_colormap_t cmap;
    if (vid != scr->root_visual)
    {
        cmap = xcb_generate_id (p_sys->conn);
        xcb_create_colormap (p_sys->conn, XCB_COLORMAP_ALLOC_NONE,
                             cmap, scr->root, vid);
    }
    else
        cmap = scr->default_colormap;

    /* Create window */
    unsigned width, height;
    if (GetWindowSize (p_sys->embed, p_sys->conn, &width, &height))
        goto error;

    p_sys->window = xcb_generate_id (p_sys->conn);
    p_sys->gc = xcb_generate_id (p_sys->conn);
    xcb_pixmap_t pixmap = xcb_generate_id (p_sys->conn);
    {
        const uint32_t mask =
            XCB_CW_BACK_PIXMAP |
            XCB_CW_BACK_PIXEL |
            XCB_CW_BORDER_PIXMAP |
            XCB_CW_BORDER_PIXEL |
            XCB_CW_EVENT_MASK |
            XCB_CW_COLORMAP;
        const uint32_t values[] = {
            /* XCB_CW_BACK_PIXMAP */
            pixmap,
            /* XCB_CW_BACK_PIXEL */
            scr->black_pixel,
            /* XCB_CW_BORDER_PIXMAP */
            pixmap,
            /* XCB_CW_BORDER_PIXEL */
            scr->black_pixel,
            /* XCB_CW_EVENT_MASK */
            XCB_EVENT_MASK_VISIBILITY_CHANGE,
            /* XCB_CW_COLORMAP */
            cmap,
        };
        xcb_void_cookie_t c;

        xcb_create_pixmap (p_sys->conn, p_sys->depth, pixmap, scr->root, 1, 1);
        c = xcb_create_window_checked (p_sys->conn, p_sys->depth,
                                       p_sys->window,
                                       p_sys->embed->handle.xid, 0, 0,
                                       width, height, 0,
                                       XCB_WINDOW_CLASS_INPUT_OUTPUT,
                                       vid, mask, values);
        xcb_map_window (p_sys->conn, p_sys->window);
        /* Create graphic context (I wonder why the heck do we need this) */
        xcb_create_gc (p_sys->conn, p_sys->gc, p_sys->window, 0, NULL);

        if (CheckError (vd, p_sys->conn, "cannot create X11 window", c))
            goto error;
    }
    msg_Dbg (vd, "using X11 window %08"PRIx32, p_sys->window);
    msg_Dbg (vd, "using X11 graphic context %08"PRIx32, p_sys->gc);
    p_sys->cursor = CreateBlankCursor (p_sys->conn, scr);

    p_sys->visible = false;

    CheckSHM (obj, p_sys->conn, &p_sys->shm);

    /* */
    vout_display_info_t info = vd->info;
    info.has_pictures_invalid = true;

    /* Setup vout_display_t once everything is fine */
    vd->info = info;

    vd->pool = Pool;
    vd->prepare = NULL;
    vd->display = Display;
    vd->control = Control;
    vd->manage = Manage;

    /* */
    vout_display_SendEventFullscreen (vd, false);
    vout_display_SendEventDisplaySize (vd, width, height, false);

    return VLC_SUCCESS;

error:
    Close (obj);
    return VLC_EGENERIC;
}