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

Quelle  render.c   Sprache: C

 

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

/*****************************************************************************
 * Copyright © 2009-2018 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 <math.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <assert.h>

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

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

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

typedef struct vout_display_sys_t {
    xcb_connection_t *conn;

    struct {
        xcb_pixmap_t source;
        xcb_pixmap_t crop;
        xcb_pixmap_t scale;
        xcb_pixmap_t subpic;
        xcb_pixmap_t subpic_crop;
        xcb_pixmap_t alpha;
        xcb_window_t dest;
    } drawable;
    struct {
        xcb_render_picture_t source;
        xcb_render_picture_t crop;
        xcb_render_picture_t scale;
        xcb_render_picture_t subpic;
        xcb_render_picture_t subpic_crop;
        xcb_render_picture_t alpha;
        xcb_render_picture_t dest;
    } picture;
    struct {
        xcb_render_pictformat_t argb;
        xcb_render_pictformat_t alpha;
    } format;

    xcb_gcontext_t gc;
    xcb_shm_seg_t segment;
    xcb_window_t root;
    char *filter;

    int32_t src_x;
    int32_t src_y;
    vlc_fourcc_t spu_chromas[2];
} vout_display_sys_t;

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

    if (segment == 0  /* SHM extension not supported */
     || buf->fd == -1 /* picture buffer not in shared memory */)
        return -1;

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

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

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

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

static void RenderRegion(vout_display_t *vd, const vlc_render_subpicture *subpic,
                         const struct subpicture_region_rendered *reg)
{
    vout_display_sys_t *sys = vd->sys;
    xcb_connection_t *conn = sys->conn;
    picture_t *pic = reg->p_picture;
    unsigned sw = reg->place.width;
    unsigned sh = reg->place.height;
    xcb_rectangle_t rects[] = { { 0, 0, sw, sh }, };
    VLC_UNUSED(subpic);

    xcb_create_pixmap(conn, 32, sys->drawable.subpic, sys->root,
        pic->format.i_width, pic->format.i_height);
    xcb_create_pixmap(conn, 32, sys->drawable.subpic_crop, sys->root, sw, sh);
    xcb_create_pixmap(conn, 8, sys->drawable.alpha, sys->root, sw, sh);
    xcb_render_create_picture(conn, sys->picture.subpic, sys->drawable.subpic,
                              sys->format.argb, 0, NULL);
    xcb_render_create_picture(conn, sys->picture.subpic_crop, sys->drawable.subpic_crop,
                              sys->format.argb, 0, NULL);
    xcb_render_create_picture(conn, sys->picture.alpha, sys->drawable.alpha,
                              sys->format.alpha, 0, NULL);

    /* Upload region (TODO: use FD passing for SPU?) */
    xcb_put_image(conn, XCB_IMAGE_FORMAT_Z_PIXMAP, sys->drawable.subpic,
                  sys->gc, pic->p->i_pitch / pic->p->i_pixel_pitch,
                  pic->p->i_lines, 0, 0, 0, 32,
                  pic->p->i_pitch * pic->p->i_lines, pic->p->p_pixels);

    /* Crop the picture with pixel accuracy */
    xcb_render_composite(conn, XCB_RENDER_PICT_OP_SRC,
                         sys->picture.subpic, XCB_RENDER_PICTURE_NONE,
                         sys->picture.subpic_crop,
                         reg->p_picture->format.i_x_offset, reg->p_picture->format.i_y_offset, 0, 0,
                         0, 0, reg->p_picture->format.i_visible_width, reg->p_picture->format.i_visible_height);

    /* Copy alpha channel */
    xcb_render_composite(conn, XCB_RENDER_PICT_OP_SRC,
                         sys->picture.subpic_crop, XCB_RENDER_PICTURE_NONE,
                         sys->picture.alpha, 0, 0, 0, 0, 0, 0, sw, sh);

    /* Force alpha channel to maximum (add 100% and clip).
     * This is to compensate RENDER expecting pre-multiplied RGB
     * while VLC uses straight RGB.
     */

    static const xcb_render_color_t alpha_one_color = { 0, 0, 0, 0xffff };

    xcb_render_fill_rectangles(conn, XCB_RENDER_PICT_OP_ADD,
                               sys->picture.subpic_crop, alpha_one_color,
                               ARRAY_SIZE(rects), rects);

    /* Multiply by region and subpicture alpha factors */
    static const float alpha_fixed = 0xffffp0f / 0xffp0f;
    xcb_render_color_t alpha_color = {
        0, 0, 0, lroundf(reg->i_alpha * alpha_fixed) };

    xcb_render_fill_rectangles(conn, XCB_RENDER_PICT_OP_IN_REVERSE,
                               sys->picture.subpic_crop, alpha_color,
                               ARRAY_SIZE(rects), rects);

    /* Mask in the original alpha channel then renver over the scaled pixmap.
     * Mask (pre)multiplies RGB channels and restores the alpha channel.
     */

    int_fast16_t dx = reg->place.x;
    int_fast16_t dy = reg->place.y;
    uint_fast16_t dw = reg->place.width;
    uint_fast16_t dh = reg->place.height;

    xcb_render_transform_t transform = {
        0, 0, 0,
        0, 0, 0,
        /* Multiply z by width and height to compensate for x and y above */
        0, 0, 10000,
    };
    transform.matrix11 = 10000 * reg->p_picture->format.i_visible_width  / reg->place.width;
    transform.matrix22 = 10000 * reg->p_picture->format.i_visible_height / reg->place.height;

    xcb_render_set_picture_transform(conn, sys->picture.subpic_crop, transform);
    xcb_render_set_picture_transform(conn, sys->picture.alpha,       transform);

    if (likely(sys->filter != NULL))
    {
        xcb_render_set_picture_filter(conn, sys->picture.subpic_crop,
                                      strlen(sys->filter), sys->filter,
                                      0, NULL);
        xcb_render_set_picture_filter(conn, sys->picture.alpha,
                                      strlen(sys->filter), sys->filter,
                                      0, NULL);
    }

    xcb_render_composite(conn, XCB_RENDER_PICT_OP_OVER,
                         sys->picture.subpic_crop, sys->picture.alpha,
                         sys->picture.scale,
                         0, 0, 0, 0,
                         dx, dy, dw, dh);

    xcb_render_free_picture(conn, sys->picture.alpha);
    xcb_render_free_picture(conn, sys->picture.subpic_crop);
    xcb_render_free_picture(conn, sys->picture.subpic);
    xcb_free_pixmap(conn, sys->drawable.alpha);
    xcb_free_pixmap(conn, sys->drawable.subpic_crop);
    xcb_free_pixmap(conn, sys->drawable.subpic);
}

static void Prepare(vout_display_t *vd, picture_t *pic,
                    const vlc_render_subpicture *subpic,
                    vlc_tick_t date)
{
    const video_format_t *fmt = vd->source;
    const vout_display_place_t *place = vd->place;
    vout_display_sys_t *sys = vd->sys;
    xcb_connection_t *conn = sys->conn;

    size_t offset = PictureAttach(vd, pic);
    if (offset != (size_t)-1) {
        xcb_shm_put_image(conn, sys->drawable.source, sys->gc,
                          pic->p->i_pitch / pic->p->i_pixel_pitch,
                          pic->p->i_lines, 0, 0,
                          pic->p->i_pitch / pic->p->i_pixel_pitch,
                          pic->p->i_lines, 0, 0, 32, XCB_IMAGE_FORMAT_Z_PIXMAP,
                          0, sys->segment, offset);
    } else {
        xcb_put_image(conn, XCB_IMAGE_FORMAT_Z_PIXMAP, sys->drawable.source,
                      sys->gc, pic->p->i_pitch / pic->p->i_pixel_pitch,
                      pic->p->i_lines, 0, 0, 0, 32,
                      pic->p->i_pitch * pic->p->i_lines, pic->p->p_pixels);
    }

    /* Crop the picture with pixel accuracy */
    xcb_render_composite(conn, XCB_RENDER_PICT_OP_SRC,
                         sys->picture.source, XCB_RENDER_PICTURE_NONE,
                         sys->picture.crop,
                         fmt->i_x_offset, fmt->i_y_offset, 0, 0,
                         0, 0, fmt->i_visible_width, fmt->i_visible_height);

    /* Blank background */
    static const xcb_render_color_t black_color = { 0, 0, 0, 0xffff };
    xcb_rectangle_t rects[] = {
        { 0, 0, vd->cfg->display.width, vd->cfg->display.height },
    };

    xcb_render_fill_rectangles(conn, XCB_RENDER_PICT_OP_SRC,
                               sys->picture.scale, black_color,
                               ARRAY_SIZE(rects), rects);

    /* Scale and orient the picture */
    xcb_render_composite(conn, XCB_RENDER_PICT_OP_SRC,
                         sys->picture.crop, XCB_RENDER_PICTURE_NONE,
                         sys->picture.scale, sys->src_x, sys->src_y, 0, 0,
                         place->x, place->y,
                         place->width, place->height);
    if (offset != (size_t)-1)
        PictureDetach(vd);

    /* Blend subpictures */
    if (subpic != NULL)
    {
        const struct subpicture_region_rendered *r;
        vlc_vector_foreach(r, &subpic->regions)
            RenderRegion(vd, subpic, r);
    }

    xcb_flush(conn);
    (void) date;
}

static void Display(vout_display_t *vd, picture_t *pic)
{
    vout_display_sys_t *sys = vd->sys;
    xcb_connection_t *conn = sys->conn;
    xcb_void_cookie_t ck;

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

    /* Copy the scaled picture into the target picture, in other words
     * copy the rendered pixmap into the window.
     */

    ck = xcb_render_composite_checked(conn, XCB_RENDER_PICT_OP_SRC,
                                      sys->picture.scale,
                                      XCB_RENDER_PICTURE_NONE,
                                      sys->picture.dest, 0, 0, 0, 0, 0, 0,
                                      vd->cfg->display.width,
                                      vd->cfg->display.height);

    xcb_generic_error_t *e = xcb_request_check(conn, ck);
    if (e != NULL) { /* Not all errors will be detected here. */
        msg_Dbg(vd, "%s: RENDER error %d", "cannot composite",
                e->error_code);
        free(e);
    }
    (void) pic;
}

static void CreateBuffers(vout_display_t *vd)
{
    const video_format_t *fmt = vd->source;
    vout_display_sys_t *sys = vd->sys;
    xcb_connection_t *conn = sys->conn;

    xcb_create_pixmap(conn, 32, sys->drawable.crop, sys->root,
                      fmt->i_visible_width, fmt->i_visible_height);
    xcb_create_pixmap(conn, 32, sys->drawable.scale, sys->root,
                      vd->cfg->display.width, vd->cfg->display.height);
    xcb_render_create_picture(conn, sys->picture.crop, sys->drawable.crop,
                              sys->format.argb, 0, NULL);
    xcb_render_create_picture(conn, sys->picture.scale, sys->drawable.scale,
                              sys->format.argb, 0, NULL);

    const vout_display_place_t *place = vd->place;

    /* Homogeneous coordinates transform from destination(place)
     * to source(fmt) */

    int32_t ax = place->height; /* multiply x instead of dividing y */
    int32_t ay = place->width; /* multiply y instead of dividing x */
    int32_t bx = 0;
    int32_t by = 0;

    switch (fmt->orientation) {
        case ORIENT_TOP_LEFT:
        case ORIENT_LEFT_TOP:
            break;
        case ORIENT_TOP_RIGHT:
        case ORIENT_RIGHT_TOP:
            ax *= -1;
            bx -= place->width;
            break;
        case ORIENT_BOTTOM_LEFT:
        case ORIENT_LEFT_BOTTOM:
            ay *= -1;
            by -= place->height;
            break;
        case ORIENT_BOTTOM_RIGHT:
        case ORIENT_RIGHT_BOTTOM:
            ax *= -1;
            ay *= -1;
            bx -= place->width;
            by -= place->height;
            break;
    }

    sys->src_x = bx;
    sys->src_y = by;

    xcb_render_transform_t transform = {
        0, 0, 0,
        0, 0, 0,
        /* Multiply z by width and height to compensate for x and y above */
        0, 0, place->width * place->height,
    };

    if (ORIENT_IS_SWAP(fmt->orientation)) {
        transform.matrix12 = ay * fmt->i_visible_width;
        transform.matrix21 = ax * fmt->i_visible_height;
    } else {
        transform.matrix11 = ax * fmt->i_visible_width;
        transform.matrix22 = ay * fmt->i_visible_height;
    }

    xcb_render_set_picture_transform(conn, sys->picture.crop, transform);

    if (likely(sys->filter != NULL))
        xcb_render_set_picture_filter(conn, sys->picture.crop,
                                      strlen(sys->filter), sys->filter,
                                      0, NULL);
}

static void DeleteBuffers(vout_display_t *vd)
{
    vout_display_sys_t *sys = vd->sys;
    xcb_connection_t *conn = sys->conn;

    xcb_render_free_picture(conn, sys->picture.scale);
    xcb_render_free_picture(conn, sys->picture.crop);
    xcb_free_pixmap(conn, sys->drawable.scale);
    xcb_free_pixmap(conn, sys->drawable.crop);
}

static int UpdateOutput(vout_display_t *vd)
{
    vout_display_sys_t *sys = vd->sys;

    DeleteBuffers(vd);
    CreateBuffers(vd);
    xcb_flush(sys->conn);
    return VLC_SUCCESS;
}

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

    /* Update the window size */
    uint32_t mask = XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT;
    const uint32_t values[] = {
        width, height
    };

    xcb_configure_window(sys->conn, sys->drawable.dest, mask, values);
    DeleteBuffers(vd);
    CreateBuffers(vd);
    xcb_flush(sys->conn);
    return VLC_SUCCESS;
}

static int PlacementChanged(vout_display_t *vd, const vout_display_place_t *place)
{
    VLC_UNUSED(place);
    return UpdateOutput(vd);
}

static int AspectChanged(vout_display_t *vd, const video_format_t *source)
{
    VLC_UNUSED(source);
    return PlacementChanged(vd, NULL);
}

/**
 * Check that the X server supports the RENDER extension.
 */

static bool CheckRender(vout_display_t *vd, xcb_connection_t *conn)
{
    xcb_render_query_version_reply_t *r;
    xcb_render_query_version_cookie_t ck;
    bool ok = false;

    ck = xcb_render_query_version(conn, 0, 11);
    r = xcb_render_query_version_reply(conn, ck, NULL);

    if (r == NULL)
        msg_Err(vd, "RENDER extension not available");
    else if (r->major_version > 0)
        msg_Dbg(vd, "RENDER extension v%"PRIu32".%"PRIu32" unknown",
                r->major_version, r->minor_version);
    else if (r->major_version == 0 && r->minor_version < 6)
        msg_Dbg(vd, "RENDER extension v%"PRIu32".%"PRIu32" too old",
                r->major_version, r->minor_version);
    else {
        msg_Dbg(vd, "using RENDER extension v%"PRIu32".%"PRIu32,
                r->major_version, r->minor_version);
        ok = true;
    }
    free(r);
    return ok;
}

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

    free(sys->filter);
    xcb_disconnect(sys->conn);
}

/* Convert RENDER picture format to VLC video chroma */
static vlc_fourcc_t ParseFormat(const xcb_setup_t *setup,
                                const xcb_render_pictforminfo_t *pfi)
{
    if (pfi->type != XCB_RENDER_PICT_TYPE_DIRECT)
        return 0;

    const xcb_format_t *pixfmt = vlc_xcb_DepthToPixmapFormat(setup,
                                                             pfi->depth);
    if (unlikely(pixfmt == NULL))
        return 0;

    const uint_fast8_t bpp = pixfmt->bits_per_pixel;
    const xcb_render_directformat_t *d = &pfi->direct;

    switch (pfi->depth) {
        case 32:
            if (bpp == 32 && d->red_mask == 0xff && d->green_mask == 0xff
             && d->blue_mask == 0xff && d->alpha_mask == 0xff) {
#ifdef WORDS_BIGENDIAN
                if (d->red_shift == 24 && d->green_shift == 16
                 && d->blue_shift == 8)
                    return VLC_CODEC_RGBA;
                if (d->red_shift == 8 && d->green_shift == 16
                 && d->blue_shift == 24)
                    return VLC_CODEC_BGRA;
                if (d->red_shift == 16 && d->green_shift == 8
                 && d->blue_shift == 0)
                    return VLC_CODEC_ARGB;
                if (d->red_shift == 0 && d->green_shift == 8
                 && d->blue_shift == 16)
                    return VLC_CODEC_ABGR;
#else
                if (d->red_shift == 0 && d->green_shift == 8
                 && d->blue_shift == 16)
                    return VLC_CODEC_RGBA;
                if (d->red_shift == 16 && d->green_shift == 8
                 && d->blue_shift == 0)
                    return VLC_CODEC_BGRA;
                if (d->red_shift == 8 && d->green_shift == 16
                 && d->blue_shift == 24)
                    return VLC_CODEC_ARGB;
                if (d->red_shift == 24 && d->green_shift == 16
                 && d->blue_shift == 8)
                    return VLC_CODEC_ABGR;
#endif
            }
            break;
#if 0
        /* TODO 30 bits HDR */
        case 24:
            if (bpp == 32 && d->red_mask == 0xff && d->green_mask == 0xff
             && d->blue_mask == 0xff && d->alpha_mask == 0x00)
                return VLC_CODEC_RGB32;
            if (bpp == 24 && d->red_mask == 0xff && d->green_mask == 0xff
             && d->blue_mask == 0xff && d->alpha_mask == 0x00)
                return VLC_CODEC_RGB24;
            break;
        case 16:
            if (bpp == 16 && d->red_mask == 0x1f && d->green_mask == 0x3f
             && d->blue_mask == 0x1f && d->alpha_mask == 0x00)
                return VLC_CODEC_RGB16;
            break;
        case 15:
            if (bpp == 16 && d->red_mask == 0x1f && d->green_mask == 0x1f
             && d->blue_mask == 0x1f && d->alpha_mask == 0x00)
                return VLC_CODEC_RGB15;
            break;
#endif
    }

    return 0;
}

/* Find the RENDER screen for the X11 screen */
static const xcb_render_pictscreen_t *
FindPictScreen(const xcb_setup_t *setup, const xcb_screen_t *scr,
               const xcb_render_query_pict_formats_reply_t *r)
{
    xcb_screen_iterator_t si = xcb_setup_roots_iterator(setup);
    unsigned n = 0;

    while (si.data != scr) {
        assert(si.rem > 0);
        n++;
        xcb_screen_next(&si);
    }

    xcb_render_pictscreen_iterator_t rsi =
        xcb_render_query_pict_formats_screens_iterator(r);

    while (n > 0) {
        if (unlikely(rsi.rem == 0))
            return NULL; /* buggy server */

        n--;
        xcb_render_pictscreen_next(&rsi);
    }
    return rsi.data;
}

/* Find an X11 visual for a RENDER picture format */
static xcb_visualid_t
FindVisual(const xcb_setup_t *setup, const xcb_screen_t *scr,
           const xcb_render_query_pict_formats_reply_t *r,
           xcb_render_pictformat_t fmt_id)
{
    const xcb_render_pictscreen_t *rs = FindPictScreen(setup, scr, r);
    if (rs == NULL)
        return 0;

    xcb_render_pictdepth_iterator_t rdi =
        xcb_render_pictscreen_depths_iterator(rs);

    while (rdi.rem > 0) {
        const xcb_render_pictdepth_t *rd = rdi.data;
        xcb_render_pictvisual_iterator_t rvi =
            xcb_render_pictdepth_visuals_iterator(rd);

        while (rvi.rem > 0) {
            const xcb_render_pictvisual_t *pv = rvi.data;

            if (pv->format == fmt_id)
                return pv->visual;

            xcb_render_pictvisual_next(&rvi);
        }
        xcb_render_pictdepth_next(&rdi);
    }
    return 0;
}

static const struct vlc_display_operations ops = {
    .close = Close,
    .prepare = Prepare,
    .display = Display,
    .set_display_size = SetDisplaySize,
    .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 *ctx)
{
    vlc_object_t *obj = VLC_OBJECT(vd);
    struct vlc_logger *log = obj->logger;

    vout_display_sys_t *sys = vlc_obj_malloc(obj, sizeof (*sys));
    if (unlikely(sys == NULL))
        return VLC_ENOMEM;

    vd->sys = sys;

    /* Connect to X */
    xcb_connection_t *conn;
    const xcb_screen_t *screen;

    int ret = vlc_xcb_parent_Create(log, vd->cfg->window, &conn, &screen);
    if (ret != VLC_SUCCESS)
        return ret;

    sys->conn = conn;
    sys->root = screen->root;
    sys->format.argb = 0;
    sys->format.alpha = 0;

    if (!CheckRender(vd, conn))
        goto error;

    xcb_render_query_pict_formats_cookie_t pic_fmt_ck =
        xcb_render_query_pict_formats(conn);
    xcb_render_query_pict_formats_reply_t *pic_fmt_r =
        xcb_render_query_pict_formats_reply(conn, pic_fmt_ck, NULL);
    if (pic_fmt_r == NULL)
        goto error;

    const xcb_setup_t *setup = xcb_get_setup(conn);
    const xcb_render_pictforminfo_t *const pic_fmts =
        xcb_render_query_pict_formats_formats(pic_fmt_r);
    xcb_visualid_t visual = 0;

    for (unsigned i = 0; i < pic_fmt_r->num_formats; i++) {
        const xcb_render_pictforminfo_t *const pic_fmt = pic_fmts + i;

        if (pic_fmt->depth == 8 && pic_fmt->direct.alpha_mask == 0xff) {
            /* Alpha mask format */
            sys->format.alpha = pic_fmt->id;
            continue;
        }

        xcb_visualid_t vid = FindVisual(setup, screen, pic_fmt_r, pic_fmt->id);
        if (vid == 0)
            continue;

        /* Use only ARGB for now. 32-bits is guaranteed to work. */
        if (pic_fmt->depth != 32)
            continue;

        vlc_fourcc_t chroma = ParseFormat(setup, pic_fmt);
        if (chroma == 0)
            continue;

        fmtp->i_chroma = chroma;
        sys->format.argb = pic_fmt->id;
        visual = vid;
    }

    free(pic_fmt_r);

    if (unlikely(sys->format.argb == 0 || sys->format.alpha == 0))
        goto error; /* Buggy server */

    msg_Dbg(obj, "using RENDER picture format %u", sys->format.argb);
    msg_Dbg(obj, "using X11 visual 0x%"PRIx32, visual);

    char *filter = var_InheritString(obj, "x11-render-filter");
    if (filter != NULL) {
        msg_Dbg(obj, "using filter \"%s\"", filter);
        sys->filter = ToCharset("ISO 8859-1", filter, &(size_t){ 0 });
        free(filter);
    } else
        sys->filter = NULL;

    sys->drawable.source = xcb_generate_id(conn);
    sys->drawable.crop = xcb_generate_id(conn);
    sys->drawable.scale = xcb_generate_id(conn);
    sys->drawable.subpic = xcb_generate_id(conn);
    sys->drawable.subpic_crop = xcb_generate_id(conn);
    sys->drawable.alpha = xcb_generate_id(conn);
    sys->drawable.dest = xcb_generate_id(conn);
    sys->picture.source = xcb_generate_id(conn);
    sys->picture.crop = xcb_generate_id(conn);
    sys->picture.scale = xcb_generate_id(conn);
    sys->picture.subpic = xcb_generate_id(conn);
    sys->picture.subpic_crop = xcb_generate_id(conn);
    sys->picture.alpha = xcb_generate_id(conn);
    sys->picture.dest = xcb_generate_id(conn);
    sys->gc = xcb_generate_id(conn);

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

    xcb_colormap_t cmap = xcb_generate_id(conn);
    uint32_t cw_mask =
        XCB_CW_BORDER_PIXEL |
        XCB_CW_EVENT_MASK |
        XCB_CW_COLORMAP;
    const uint32_t cw_list[] = {
        /* XCB_CW_BORDER_PIXEL */
        screen->black_pixel,
        /* XCB_CW_EVENT_MASK */
        0,
        /* XCB_CW_COLORMAP */
        cmap,
    };

    xcb_create_colormap(conn, XCB_COLORMAP_ALLOC_NONE, cmap, screen->root,
                        visual);
    xcb_create_pixmap(conn, 32, sys->drawable.source, screen->root,
                      vd->source->i_width, vd->source->i_height);
    xcb_create_gc(conn, sys->gc, sys->drawable.source, 0, NULL);
    xcb_create_window(conn, 32, sys->drawable.dest, vd->cfg->window->handle.xid,
                      0, 0, vd->cfg->display.width, vd->cfg->display.height, 0,
                      XCB_WINDOW_CLASS_INPUT_OUTPUT, visual, cw_mask, cw_list);
    xcb_render_create_picture(conn, sys->picture.source, sys->drawable.source,
                              sys->format.argb, 0, NULL);
    xcb_render_create_picture(conn, sys->picture.dest, sys->drawable.dest,
                              sys->format.argb, 0, NULL);
    CreateBuffers(vd);
    xcb_map_window(conn, sys->drawable.dest);

    sys->spu_chromas[0] = fmtp->i_chroma;
    sys->spu_chromas[1] = 0;

    vd->info.subpicture_chromas = sys->spu_chromas;
    vd->ops = &ops;

    (void) ctx;
    return VLC_SUCCESS;

error:
    xcb_disconnect(conn);
    return VLC_EGENERIC;
}

static const char *filter_names[] = {
    "nearest", "bilinear", "fast", "good", "best",
};

static const char *filter_descs[] = {
    N_("Nearest neighbor (bad quality)"),
    N_("Bilinear"), N_("Fast"), N_("Good"), N_("Best"),
};

vlc_module_begin()
    set_shortname(N_("RENDER"))
    set_description(N_("X11 RENDER video output (XCB)"))
    set_subcategory(SUBCAT_VIDEO_VOUT)
    set_callback_display(Open, 200)
    add_shortcut("x11-render", "xcb-render", "render")
    add_string("x11-render-filter", "good", N_("Scaling mode"),
               NULL)
        change_string_list(filter_names, filter_descs)
vlc_module_end()

Messung
CHZG
829910093

¤ Dauer der Verarbeitung: 0.4 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.