Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/VLC/modules/video_output/xcb/   (VLC Media Plyer ©)  Datei vom 23.9.2026 mit Größe 12 kB image not shown  

Quelle  x11.c   Sprache: C

 

/**
 * @file x11.c
 * @brief X C Bindings video output module for VLC media player
 */

/*****************************************************************************
 * Copyright © 2009 Rémi Denis-Courmont
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/


#ifdef HAVE_CONFIG_H
# include <config.h>
#endif

#include <stdlib.h>
#include <assert.h>

#include <xcb/xcb.h>
#include <xcb/shm.h>

#include <vlc_common.h>
#include <vlc_fs.h>
#include <vlc_plugin.h>
#include <vlc_vout_display.h>

#include "pictures.h"
#include "events.h"

typedef struct vout_display_sys_t
{
    xcb_connection_t *conn;

    xcb_window_t window; /* drawable X window */
    xcb_gcontext_t gc; /* context to put images */
    xcb_shm_seg_t segment; /**< shared memory segment XID */
    bool attached;
    uint8_t depth; /* useful bits per pixel */
} vout_display_sys_t;

static void Prepare(vout_display_t *vd, picture_t *pic,
                    const struct vlc_render_subpicture *subpic,
                    vlc_tick_t date)
{
    vout_display_sys_t *sys = vd->sys;
    const picture_buffer_t *buf = pic->p_sys;
    xcb_connection_t *conn = sys->conn;

    sys->attached = false;

    if (sys->segment == 0)
        return; /* SHM extension not supported */
    if (buf->fd == -1)
        return; /* not a shareable picture buffer */

    int fd = vlc_dup(buf->fd);
    if (fd == -1)
        return;

    xcb_void_cookie_t c = xcb_shm_attach_fd_checked(conn, sys->segment, fd, 1);
    xcb_generic_error_t *e = xcb_request_check(conn, c);
    if (e != NULL) /* attach failure (likely remote access) */
    {
        free(e);
        return;
    }

    sys->attached = true;
    (void) subpic; (void) date;
}

/**
 * Sends an image to the X server.
 */

static void Display (vout_display_t *vd, picture_t *pic)
{
    vout_display_sys_t *sys = vd->sys;
    xcb_connection_t *conn = sys->conn;
    const picture_buffer_t *buf = pic->p_sys;
    xcb_shm_seg_t segment = sys->segment;
    xcb_void_cookie_t ck;

    vlc_xcb_Manage(vd->obj.logger, sys->conn);

    /* Black out the borders */
    xcb_rectangle_t rectv[4], *rect;
    unsigned int rectc = 0;

    if (vd->place->x > 0) {
        rect = &rectv[rectc++];
        rect->x = 0;
        rect->y = 0;
        rect->width = vd->place->x;
        rect->height = vd->cfg->display.height;
    }
    if (vd->place->x + vd->place->width < vd->cfg->display.width) {
        rect = &rectv[rectc++];
        rect->x = vd->place->x + vd->place->width;
        rect->y = 0;
        rect->width = vd->cfg->display.width - rect->x;
        rect->height = vd->cfg->display.height;
    }
    if (vd->place->y > 0) {
        rect = &rectv[rectc++];
        rect->x = vd->place->x;
        rect->y = 0;
        rect->width = vd->place->width;
        rect->height = vd->place->y;
    }
    if (vd->place->y + vd->place->height < vd->cfg->display.height) {
        rect = &rectv[rectc++];
        rect->x = vd->place->x;
        rect->y = vd->place->y + vd->place->height;
        rect->width = vd->place->width;
        rect->height = vd->cfg->display.height - rect->y;
    }

    xcb_poly_fill_rectangle(conn, sys->window, sys->gc, rectc, rectv);

    /* Draw the picture */
    if (sys->attached)
        ck = xcb_shm_put_image_checked(conn, sys->window, sys->gc,
              /* real width */ pic->p->i_pitch / pic->p->i_pixel_pitch,
             /* real height */ pic->p->i_lines,
                       /* x */ vd->fmt->i_x_offset,
                       /* y */ vd->fmt->i_y_offset,
                   /* width */ vd->fmt->i_visible_width,
                  /* height */ vd->fmt->i_visible_height,
                               vd->place->x, vd->place->y, sys->depth,
                               XCB_IMAGE_FORMAT_Z_PIXMAP, 0,
                               segment, buf->offset);
    else {
        const size_t offset = vd->fmt->i_x_offset * pic->p->i_pixel_pitch
                            + vd->fmt->i_y_offset * pic->p->i_pitch;
        unsigned int lines = pic->p->i_lines - vd->fmt->i_y_offset;

        if (vd->fmt->i_x_offset > 0) {
            /*
             * Draw the last line separately as the scan line padding would
             * potentially reach beyond the end of the picture buffer.
             */

            lines--;
            xcb_put_image(conn, XCB_IMAGE_FORMAT_Z_PIXMAP, sys->window,
                          sys->gc, pic->p->i_visible_pitch, 1,
                          vd->place->x, vd->place->y + vd->place->height - 1,
                          0, sys->depth, pic->p->i_visible_pitch,
                          pic->p->p_pixels + offset + lines * pic->p->i_pitch);
        }

        ck = xcb_put_image_checked(conn, XCB_IMAGE_FORMAT_Z_PIXMAP,
                                   sys->window, sys->gc,
                                   pic->p->i_pitch / pic->p->i_pixel_pitch,
                                   lines, vd->place->x, vd->place->y,
                                   0, sys->depth, pic->p->i_pitch * lines,
                                   pic->p->p_pixels + offset);

    }

    /* Wait for reply. This makes sure that the X server gets CPU time to
     * display the picture. xcb_flush() is *not* sufficient: especially
     * with shared memory the PUT requests are so short that many of them
     * can fit in X11 socket output buffer before the kernel preempts VLC.
     */

   xcb_generic_error_t *e = xcb_request_check(conn, ck);
   if (e != NULL) {
       msg_Err(vd, "%s: X11 error %d", "cannot put image", e->error_code);
       free(e);
   }

    /* FIXME might be WAY better to wait in some case (be carefull with
     * reset_pictures if done) + does not work with
     * vout_display wrapper. */


    if (sys->attached)
        xcb_shm_detach(conn, segment);
}

static int ResetPictures(vout_display_t *vd, video_format_t *restrict f)
{
    video_format_t src;

    video_format_ApplyRotation(&src, vd->source);
    f->i_width  = src.i_width  * vd->place->width / src.i_visible_width;
    f->i_height = src.i_height * vd->place->height / src.i_visible_height;

    f->i_visible_width  = vd->place->width;
    f->i_visible_height = vd->place->height;
    f->i_x_offset = src.i_x_offset * vd->place->width / src.i_visible_width;
    f->i_y_offset = src.i_y_offset * vd->place->height / src.i_visible_height;
    return VLC_SUCCESS;
}

static int PlacementChanged(vout_display_t *vd, const vout_display_place_t *place)
{
    VLC_UNUSED(place);
    if (place->width  != vd->fmt->i_visible_width
     || place->height != vd->fmt->i_visible_height)
        return VLC_EGENERIC;

    return VLC_SUCCESS;
}

static int AspectChanged(vout_display_t *vd, const video_format_t *source)
{
    VLC_UNUSED(source);
    if (vd->place->width  != vd->fmt->i_visible_width
     || vd->place->height != vd->fmt->i_visible_height)
        return VLC_EGENERIC;

    return VLC_SUCCESS;
}

static int SetDisplaySize(vout_display_t *vd, unsigned width, unsigned height)
{
    vout_display_sys_t *sys = vd->sys;

    uint32_t mask = XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT;
    const uint32_t values[] = {
        width, height,
    };

    xcb_configure_window(sys->conn, sys->window, mask, values);

    if (vd->place->width  != vd->fmt->i_visible_width ||
        vd->place->height != vd->fmt->i_visible_height)
        return VLC_EGENERIC;

    return VLC_SUCCESS;
}

/**
 * Disconnect from the X server.
 */

static void Close(vout_display_t *vd)
{
    vout_display_sys_t *sys = vd->sys;

    /* colormap, window and context are garbage-collected by X */
    xcb_disconnect(sys->conn);
    free(sys);
}

static xcb_visualid_t DepthToFormat(const xcb_setup_t *setup,
                                    const xcb_depth_t *depth,
                                    video_format_t *restrict f)
{
    /* Check visual types for the selected depth */
    const xcb_visualtype_t *vt = xcb_depth_visuals(depth);

    for (int i = xcb_depth_visuals_length(depth); i > 0; i--, vt++)
        if (vlc_xcb_VisualToFormat(setup, depth->depth, vt, f))
            return vt->visual_id;

    return 0;
}

static xcb_visualid_t ScreenToFormat(const xcb_setup_t *setup,
                                     const xcb_screen_t *screen,
                                     uint8_t *restrict bits,
                                     const video_format_t *source,
                                     video_format_t *restrict fmtp)
{
    xcb_visualid_t visual = 0;

    *bits = 0;

    for (xcb_depth_iterator_t it = xcb_screen_allowed_depths_iterator(screen);
         it.rem > 0;
         xcb_depth_next(&it))
    {
        const xcb_depth_t *depth = it.data;
        video_format_t fmt;
        xcb_visualid_t vid;

        if (depth->depth <= *bits)
            continue; /* no better than earlier depth */

        video_format_ApplyRotation(&fmt, source);
        vid = DepthToFormat(setup, depth, &fmt);
        if (vid != 0)
        {
            *bits = depth->depth;
            *fmtp = fmt;
            visual = vid;
        }
    }
    return visual;
}

static const struct vlc_display_operations ops = {
    .close = Close,
    .prepare = Prepare,
    .display = Display,
    .set_display_size = SetDisplaySize,
    .reset_pictures = ResetPictures,
    .video_place_changed = PlacementChanged,
    .set_source_aspect = AspectChanged,
    .set_source_crop = AspectChanged,
};

/**
 * Probe the X server.
 */

static int Open (vout_display_t *vd,
                 video_format_t *fmtp, vlc_video_context *context)
{
    vout_display_sys_t *sys = malloc (sizeof (*sys));
    if (unlikely(sys == NULL))
        return VLC_ENOMEM;

    vd->sys = sys;

    /* Get window, connect to X server */
    struct vlc_logger *log = vd->obj.logger;
    xcb_connection_t *conn;
    const xcb_screen_t *scr;
    int ret = vlc_xcb_parent_Create(log, vd->cfg->window, &conn, &scr);
    if (ret != VLC_SUCCESS)
    {
        free (sys);
        return ret;
    }
    sys->conn = conn;

    const xcb_setup_t *setup = xcb_get_setup (conn);

    /* Determine our pixel format */
    xcb_visualid_t vid = ScreenToFormat(setup, scr, &sys->depth, vd->source, fmtp);
    if (vid == 0) {
        msg_Err(vd, "no supported visual & pixel format");
        goto error;
    }

    msg_Dbg(vd, "using X11 visual ID 0x%"PRIx32, vid);
    msg_Dbg(vd, " %"PRIu8" bits depth", sys->depth);

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

    /* Create window */
    const uint32_t mask =
        XCB_CW_BACK_PIXEL |
        XCB_CW_BORDER_PIXEL |
        XCB_CW_BIT_GRAVITY |
        XCB_CW_EVENT_MASK |
        XCB_CW_COLORMAP;
    const uint32_t values[] = {
        /* XCB_CW_BACK_PIXEL */
        scr->black_pixel,
        /* XCB_CW_BORDER_PIXEL */
        scr->black_pixel,
        /* XCB_CW_BIT_GRAVITY */
        XCB_GRAVITY_NORTH_WEST,
        /* XCB_CW_EVENT_MASK */
        0,
        /* XCB_CW_COLORMAP */
        cmap,
    };

    sys->window = xcb_generate_id (conn);
    sys->gc = xcb_generate_id (conn);
    xcb_create_window(conn, sys->depth, sys->window,
                      vd->cfg->window->handle.xid,
                      0, 0, vd->cfg->display.width, vd->cfg->display.height, 0,
                      XCB_WINDOW_CLASS_INPUT_OUTPUT, vid, mask, values);
    xcb_map_window(conn, sys->window);
    /* Create graphic context (I wonder why the heck do we need this) */
    xcb_create_gc(conn, sys->gc, sys->window, 0, NULL);

    msg_Dbg (vd, "using X11 window %08"PRIx32, sys->window);
    msg_Dbg (vd, "using X11 graphic context %08"PRIx32, sys->gc);

    if (XCB_shm_Check (VLC_OBJECT(vd), conn))
        sys->segment = xcb_generate_id(conn);
    else
        sys->segment = 0;

    /* Setup vout_display_t once everything is fine */
    ResetPictures(vd, fmtp);
    vd->ops = &ops;

    (void) context;
    return VLC_SUCCESS;

error:
    Close (vd);
    return VLC_EGENERIC;
}

/*
 * Module descriptor
 */

vlc_module_begin()
    set_shortname(N_("X11"))
    set_description(N_("X11 video output (XCB)"))
    set_subcategory(SUBCAT_VIDEO_VOUT)
    set_callback_display(Open, 100)
    add_shortcut("xcb-x11", "x11")
vlc_module_end()

Messung
CHZG
84989893

¤ Dauer der Verarbeitung: 0.2 Sekunden  (vorverarbeitet am  2026-11-04) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover


Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.