xvideo.c
上传用户:kjfoods
上传日期:2020-07-06
资源大小:29949k
文件大小:20k
源码类别:

midi

开发平台:

Unix_Linux

  1. /**
  2.  * @file xvideo.c
  3.  * @brief X C Bindings video output module for VLC media player
  4.  */
  5. /*****************************************************************************
  6.  * Copyright © 2009 Rémi Denis-Courmont
  7.  *
  8.  * This library is free software; you can redistribute it and/or
  9.  * modify it under the terms of the GNU General Public License
  10.  * as published by the Free Software Foundation; either version 2.0
  11.  * of the License, or (at your option) any later version.
  12.  *
  13.  * This library is distributed in the hope that it will be useful,
  14.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16.  * GNU General Public License for more details.
  17.  *
  18.  * You should have received a copy of the GNU Lesser General Public
  19.  * License along with this library; if not, write to the Free Software
  20.  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  21.  ****************************************************************************/
  22. #ifdef HAVE_CONFIG_H
  23. # include <config.h>
  24. #endif
  25. #include <stdlib.h>
  26. #include <assert.h>
  27. #include <xcb/xcb.h>
  28. #include <xcb/shm.h>
  29. #include <xcb/xv.h>
  30. #include <vlc_common.h>
  31. #include <vlc_plugin.h>
  32. #include <vlc_vout.h>
  33. #include <vlc_window.h>
  34. #include "xcb_vlc.h"
  35. #define DISPLAY_TEXT N_("X11 display")
  36. #define DISPLAY_LONGTEXT N_( 
  37.     "X11 hardware display to use. By default VLC will " 
  38.     "use the value of the DISPLAY environment variable.")
  39. #define SHM_TEXT N_("Use shared memory")
  40. #define SHM_LONGTEXT N_( 
  41.     "Use shared memory to communicate between VLC and the X server.")
  42. static int  Open (vlc_object_t *);
  43. static void Close (vlc_object_t *);
  44. /*
  45.  * Module descriptor
  46.  */
  47. vlc_module_begin ()
  48.     set_shortname (N_("XVideo"))
  49.     set_description (N_("(Experimental) XVideo output"))
  50.     set_category (CAT_VIDEO)
  51.     set_subcategory (SUBCAT_VIDEO_VOUT)
  52.     set_capability ("video output", 0)
  53.     set_callbacks (Open, Close)
  54.     add_string ("x11-display", NULL, NULL,
  55.                 DISPLAY_TEXT, DISPLAY_LONGTEXT, true)
  56.     add_bool ("x11-shm", true, NULL, SHM_TEXT, SHM_LONGTEXT, true)
  57.     add_shortcut ("xcb-xv")
  58. vlc_module_end ()
  59. struct vout_sys_t
  60. {
  61.     xcb_connection_t *conn;
  62.     xcb_xv_query_adaptors_reply_t *adaptors;
  63.     vout_window_t *embed;/* VLC window */
  64.     xcb_window_t window; /* drawable X window */
  65.     xcb_gcontext_t gc;   /* context to put images */
  66.     xcb_xv_port_t port;  /* XVideo port */
  67.     uint32_t id;         /* XVideo format */
  68.     uint16_t width;      /* display width */
  69.     uint16_t height;     /* display height */
  70.     uint32_t data_size;  /* picture byte size (for non-SHM) */
  71.     bool shm;            /* whether to use MIT-SHM */
  72. };
  73. static int Init (vout_thread_t *);
  74. static void Deinit (vout_thread_t *);
  75. static void Display (vout_thread_t *, picture_t *);
  76. static int Manage (vout_thread_t *);
  77. static int Control (vout_thread_t *, int, va_list);
  78. int CheckError (vout_thread_t *vout, const char *str, xcb_void_cookie_t ck)
  79. {
  80.     xcb_generic_error_t *err;
  81.     err = xcb_request_check (vout->p_sys->conn, ck);
  82.     if (err)
  83.     {
  84.         msg_Err (vout, "%s: X11 error %d", str, err->error_code);
  85.         return VLC_EGENERIC;
  86.     }
  87.     return VLC_SUCCESS;
  88. }
  89. /**
  90.  * Check that the X server supports the XVideo extension.
  91.  */
  92. static bool CheckXVideo (vout_thread_t *vout, xcb_connection_t *conn)
  93. {
  94.     xcb_xv_query_extension_reply_t *r;
  95.     xcb_xv_query_extension_cookie_t ck = xcb_xv_query_extension (conn);
  96.     bool ok = false;
  97.     r = xcb_xv_query_extension_reply (conn, ck, NULL);
  98.     if (r != NULL)
  99.     {   /* We need XVideo 2.2 for PutImage */
  100.         if ((r->major > 2) || (r->major == 2 && r->minor >= 2))
  101.         {
  102.             msg_Dbg (vout, "using XVideo extension v%"PRIu8".%"PRIu8,
  103.                      r->major, r->minor);
  104.             ok = true;
  105.         }
  106.         else
  107.             msg_Dbg (vout, "XVideo extension too old (v%"PRIu8".%"PRIu8,
  108.                      r->major, r->minor);
  109.         free (r);
  110.     }
  111.     else
  112.         msg_Dbg (vout, "XVideo extension not available");
  113.     return ok;
  114. }
  115. /**
  116.  * Get a list of XVideo adaptors for a given window.
  117.  */
  118. static xcb_xv_query_adaptors_reply_t *GetAdaptors (vout_window_t *wnd,
  119.                                                    xcb_connection_t *conn)
  120. {
  121.     xcb_xv_query_adaptors_cookie_t ck;
  122.     ck = xcb_xv_query_adaptors (conn, wnd->handle.xid);
  123.     return xcb_xv_query_adaptors_reply (conn, ck, NULL);
  124. }
  125. #define p_vout vout
  126. /**
  127.  * Probe the X server.
  128.  */
  129. static int Open (vlc_object_t *obj)
  130. {
  131.     vout_thread_t *vout = (vout_thread_t *)obj;
  132.     vout_sys_t *p_sys = malloc (sizeof (*p_sys));
  133.     if (p_sys == NULL)
  134.         return VLC_ENOMEM;
  135.     vout->p_sys = p_sys;
  136.     /* Connect to X */
  137.     p_sys->conn = Connect (obj);
  138.     if (p_sys->conn == NULL)
  139.     {
  140.         free (p_sys);
  141.         return VLC_EGENERIC;
  142.     }
  143.     if (!CheckXVideo (vout, p_sys->conn))
  144.     {
  145.         msg_Warn (vout, "Please enable XVideo 2.2 for faster video display");
  146.         xcb_disconnect (p_sys->conn);
  147.         free (p_sys);
  148.         return VLC_EGENERIC;
  149.     }
  150.     const xcb_screen_t *screen;
  151.     p_sys->embed = GetWindow (vout, p_sys->conn, &screen, &p_sys->shm);
  152.     if (p_sys->embed == NULL)
  153.     {
  154.         xcb_disconnect (p_sys->conn);
  155.         free (p_sys);
  156.         return VLC_EGENERIC;
  157.     }
  158.     /* Cache adaptors infos */
  159.     p_sys->adaptors = GetAdaptors (p_sys->embed, p_sys->conn);
  160.     if (p_sys->adaptors == NULL)
  161.         goto error;
  162.     /* Create window */
  163.     {
  164.         const uint32_t mask =
  165.             /* XCB_CW_EVENT_MASK */
  166.             XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE |
  167.             XCB_EVENT_MASK_POINTER_MOTION;
  168.         xcb_void_cookie_t c;
  169.         xcb_window_t window = xcb_generate_id (p_sys->conn);
  170.         c = xcb_create_window_checked (p_sys->conn, screen->root_depth, window,
  171.                                        p_sys->embed->handle.xid, 0, 0, 1, 1, 0,
  172.                                        XCB_WINDOW_CLASS_INPUT_OUTPUT,
  173.                                        screen->root_visual,
  174.                                        XCB_CW_EVENT_MASK, &mask);
  175.         if (CheckError (vout, "cannot create X11 window", c))
  176.             goto error;
  177.         p_sys->window = window;
  178.         msg_Dbg (vout, "using X11 window %08"PRIx32, p_sys->window);
  179.         xcb_map_window (p_sys->conn, window);
  180.     }
  181.     p_sys->gc = xcb_generate_id (p_sys->conn);
  182.     xcb_create_gc (p_sys->conn, p_sys->gc, p_sys->window, 0, NULL);
  183.     msg_Dbg (vout, "using X11 graphic context %08"PRIx32, p_sys->gc);
  184.     vout->pf_init = Init;
  185.     vout->pf_end = Deinit;
  186.     vout->pf_display = Display;
  187.     vout->pf_manage = Manage;
  188.     vout->pf_control = Control;
  189.     return VLC_SUCCESS;
  190. error:
  191.     Close (obj);
  192.     return VLC_EGENERIC;
  193. }
  194. /**
  195.  * Disconnect from the X server.
  196.  */
  197. static void Close (vlc_object_t *obj)
  198. {
  199.     vout_thread_t *vout = (vout_thread_t *)obj;
  200.     vout_sys_t *p_sys = vout->p_sys;
  201.     free (p_sys->adaptors);
  202.     vout_ReleaseWindow (p_sys->embed);
  203.     xcb_disconnect (p_sys->conn);
  204.     free (p_sys);
  205. }
  206. static vlc_fourcc_t ParseFormat (vout_thread_t *vout,
  207.                                  const xcb_xv_image_format_info_t *restrict f)
  208. {
  209.     if (f->byte_order != ORDER && f->bpp != 8)
  210.         return 0; /* Argh! */
  211.     switch (f->type)
  212.     {
  213.       case XCB_XV_IMAGE_FORMAT_INFO_TYPE_RGB:
  214.         switch (f->num_planes)
  215.         {
  216.           case 1:
  217.             switch (f->bpp)
  218.             {
  219.               case 32:
  220.                 if (f->depth == 24)
  221.                     return VLC_FOURCC ('R', 'V', '3', '2');
  222.                 break;
  223.               case 24:
  224.                 if (f->depth == 24)
  225.                     return VLC_FOURCC ('R', 'V', '2', '4');
  226.                 break;
  227.               case 16:
  228.                 if (f->depth == 16)
  229.                     return VLC_FOURCC ('R', 'V', '1', '6');
  230.                 if (f->depth == 15)
  231.                     return VLC_FOURCC ('R', 'V', '1', '5');
  232.                 break;
  233.               case 8:
  234.                 if (f->depth == 8)
  235.                     return VLC_FOURCC ('R', 'G', 'B', '2');
  236.                 break;
  237.             }
  238.             break;
  239.         }
  240.         msg_Err (vout, "unknown XVideo RGB format %"PRIx32" (%.4s)",
  241.                  f->id, f->guid);
  242.         msg_Dbg (vout, " %"PRIu8" planes, %"PRIu8" bits/pixel, "
  243.                  "depth %"PRIu8, f->num_planes, f->bpp, f->depth);
  244.         break;
  245.       case XCB_XV_IMAGE_FORMAT_INFO_TYPE_YUV:
  246.         if (f->u_sample_bits != f->v_sample_bits
  247.          || f->vhorz_u_period != f->vhorz_v_period
  248.          || f->vvert_u_period != f->vvert_v_period
  249.          || f->y_sample_bits != 8 || f->u_sample_bits != 8
  250.          || f->vhorz_y_period != 1 || f->vvert_y_period != 1)
  251.             goto bad;
  252.         switch (f->num_planes)
  253.         {
  254.           case 1:
  255.             switch (f->bpp)
  256.             {
  257.               /*untested: case 24:
  258.                 if (f->vhorz_u_period == 1 && f->vvert_u_period == 1)
  259.                     return VLC_FOURCC ('I', '4', '4', '4');
  260.                 break;*/
  261.               case 16:
  262.                 if (f->vhorz_u_period == 2 && f->vvert_u_period == 1)
  263.                 {
  264.                     if (!strcmp ((const char *)f->vcomp_order, "YUYV"))
  265.                         return VLC_FOURCC ('Y', 'U', 'Y', '2');
  266.                     if (!strcmp ((const char *)f->vcomp_order, "UYVY"))
  267.                         return VLC_FOURCC ('U', 'Y', 'V', 'Y');
  268.                 }
  269.                 break;
  270.             }
  271.             break;
  272.           case 3:
  273.             switch (f->bpp)
  274.             {
  275.               case 12:
  276.                 if (f->vhorz_u_period == 2 && f->vvert_u_period == 2)
  277.                 {
  278.                     if (!strcmp ((const char *)f->vcomp_order, "YVU"))
  279.                         return VLC_FOURCC ('Y', 'V', '1', '2');
  280.                     if (!strcmp ((const char *)f->vcomp_order, "YUV"))
  281.                         return VLC_FOURCC ('I', '4', '2', '0');
  282.                 }
  283.             }
  284.             break;
  285.         }
  286.     bad:
  287.         msg_Err (vout, "unknown XVideo YUV format %"PRIx32" (%.4s)", f->id,
  288.                  f->guid);
  289.         msg_Dbg (vout, " %"PRIu8" planes, %"PRIu32" bits/pixel, "
  290.                  "%"PRIu32"/%"PRIu32"/%"PRIu32" bits/sample", f->num_planes,
  291.                  f->bpp, f->y_sample_bits, f->u_sample_bits, f->v_sample_bits);
  292.         msg_Dbg (vout, " period: %"PRIu32"/%"PRIu32"/%"PRIu32"x"
  293.                  "%"PRIu32"/%"PRIu32"/%"PRIu32,
  294.                  f->vhorz_y_period, f->vhorz_u_period, f->vhorz_v_period,
  295.                  f->vvert_y_period, f->vvert_u_period, f->vvert_v_period);
  296.         msg_Warn (vout, " order: %.32s", f->vcomp_order);
  297.         break;
  298.     }
  299.     return 0;
  300. }
  301. static const xcb_xv_image_format_info_t *
  302. FindFormat (vout_thread_t *vout, vlc_fourcc_t chroma, xcb_xv_port_t port,
  303.             const xcb_xv_list_image_formats_reply_t *list,
  304.             xcb_xv_query_image_attributes_reply_t **restrict pa)
  305. {
  306.     xcb_connection_t *conn = vout->p_sys->conn;
  307.     const xcb_xv_image_format_info_t *f, *end;
  308.     f = xcb_xv_list_image_formats_format (list);
  309.     end = f + xcb_xv_list_image_formats_format_length (list);
  310.     for (; f < end; f++)
  311.     {
  312.         if (chroma != ParseFormat (vout, f))
  313.             continue;
  314.         xcb_xv_query_image_attributes_reply_t *i;
  315.         i = xcb_xv_query_image_attributes_reply (conn,
  316.             xcb_xv_query_image_attributes (conn, port, f->id,
  317.                 vout->fmt_in.i_width, vout->fmt_in.i_height), NULL);
  318.         if (i == NULL)
  319.             continue;
  320.         if (i->width != vout->fmt_in.i_width
  321.          || i->height != vout->fmt_in.i_height)
  322.         {
  323.             msg_Warn (vout, "incompatible size %ux%u -> %"PRIu32"x%"PRIu32,
  324.                       vout->fmt_in.i_width, vout->fmt_in.i_height,
  325.                       i->width, i->height);
  326.             free (i);
  327.             continue;
  328.         }
  329.         *pa = i;
  330.         return f;
  331.     }
  332.     return NULL;
  333. }
  334. /**
  335.  * Allocate drawable window and picture buffers.
  336.  */
  337. static int Init (vout_thread_t *vout)
  338. {
  339.     vout_sys_t *p_sys = vout->p_sys;
  340.     xcb_xv_query_image_attributes_reply_t *att = NULL;
  341.     bool swap_planes = false; /* whether X wants V before U */
  342.     /* FIXME: check max image size */
  343.     xcb_xv_adaptor_info_iterator_t it;
  344.     for (it = xcb_xv_query_adaptors_info_iterator (p_sys->adaptors);
  345.          it.rem > 0;
  346.          xcb_xv_adaptor_info_next (&it))
  347.     {
  348.         const xcb_xv_adaptor_info_t *a = it.data;
  349.         /* FIXME: Open() should fail if none of the ports are usable to VLC */
  350.         if (!(a->type & XCB_XV_TYPE_IMAGE_MASK))
  351.             continue;
  352.         xcb_xv_list_image_formats_reply_t *r;
  353.         r = xcb_xv_list_image_formats_reply (p_sys->conn,
  354.             xcb_xv_list_image_formats (p_sys->conn, a->base_id), NULL);
  355.         if (r == NULL)
  356.             continue;
  357.         const xcb_xv_image_format_info_t *fmt;
  358.         /* Video chroma in preference order */
  359.         const vlc_fourcc_t chromas[] = {
  360.             vout->fmt_in.i_chroma,
  361.             VLC_FOURCC ('Y', 'U', 'Y', '2'),
  362.             VLC_FOURCC ('R', 'V', '2', '4'),
  363.             VLC_FOURCC ('R', 'V', '1', '5'),
  364.         };
  365.         for (size_t i = 0; i < sizeof (chromas) / sizeof (chromas[0]); i++)
  366.         {
  367.             vlc_fourcc_t chroma = chromas[i];
  368.             fmt = FindFormat (vout, chroma, a->base_id, r, &att);
  369.             if (fmt != NULL)
  370.             {
  371.                 vout->output.i_chroma = chroma;
  372.                 goto found_format;
  373.             }
  374.         }
  375.         free (r);
  376.         continue;
  377.     found_format:
  378.         /* TODO: grab port */
  379.         p_sys->port = a->base_id;
  380.         msg_Dbg (vout, "using port %"PRIu32, p_sys->port);
  381.         p_sys->id = fmt->id;
  382.         msg_Dbg (vout, "using image format 0x%"PRIx32, p_sys->id);
  383.         if (fmt->type == XCB_XV_IMAGE_FORMAT_INFO_TYPE_RGB)
  384.         {
  385.             vout->fmt_out.i_rmask = vout->output.i_rmask = fmt->red_mask;
  386.             vout->fmt_out.i_gmask = vout->output.i_gmask = fmt->green_mask;
  387.             vout->fmt_out.i_bmask = vout->output.i_bmask = fmt->blue_mask;
  388.         }
  389.         else
  390.         if (fmt->num_planes == 3)
  391.             swap_planes = !strcmp ((const char *)fmt->vcomp_order, "YVU");
  392.         free (r);
  393.         goto found_adaptor;
  394.     }
  395.     msg_Err (vout, "no available XVideo adaptor");
  396.     return VLC_EGENERIC; /* no usable adaptor */
  397.     /* Allocate picture buffers */
  398.     const uint32_t *offsets;
  399. found_adaptor:
  400.     offsets = xcb_xv_query_image_attributes_offsets (att);
  401.     p_sys->data_size = att->data_size;
  402.     I_OUTPUTPICTURES = 0;
  403.     for (size_t index = 0; I_OUTPUTPICTURES < 2; index++)
  404.     {
  405.         picture_t *pic = vout->p_picture + index;
  406.         if (index > sizeof (vout->p_picture) / sizeof (pic))
  407.             break;
  408.         if (pic->i_status != FREE_PICTURE)
  409.             continue;
  410.         vout_InitPicture (vout, pic, vout->output.i_chroma,
  411.                           att->width, att->height,
  412.                           vout->fmt_in.i_aspect);
  413.         if (PictureAlloc (vout, pic, att->data_size,
  414.                           p_sys->shm ? p_sys->conn : NULL))
  415.             break;
  416.         /* Allocate further planes as specified by XVideo */
  417.         /* We assume that offsets[0] is zero */
  418.         for (int i = 1; i < pic->i_planes; i++)
  419.              pic->p[i].p_pixels =
  420.                  pic->p->p_pixels + offsets[swap_planes ? (3 - i) : i];
  421.         PP_OUTPUTPICTURE[I_OUTPUTPICTURES++] = pic;
  422.     }
  423.     free (att);
  424.     unsigned x, y, width, height;
  425.     if (GetWindowSize (p_sys->embed, p_sys->conn, &width, &height))
  426.         return VLC_EGENERIC;
  427.     vout_PlacePicture (vout, width, height, &x, &y, &width, &height);
  428.     const uint32_t values[] = { x, y, width, height, };
  429.     xcb_configure_window (p_sys->conn, p_sys->window,
  430.                           XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y |
  431.                           XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT,
  432.                           values);
  433.     xcb_flush (p_sys->conn);
  434.     p_sys->height = height;
  435.     p_sys->width = width;
  436.     vout->fmt_out.i_chroma = vout->output.i_chroma;
  437.     vout->fmt_out.i_visible_width = vout->fmt_in.i_visible_width;
  438.     vout->fmt_out.i_visible_height = vout->fmt_in.i_visible_height;
  439.     vout->fmt_out.i_sar_num = vout->fmt_out.i_sar_den = 1;
  440.     vout->output.i_width = vout->fmt_out.i_width = vout->fmt_in.i_width;
  441.     vout->output.i_height = vout->fmt_out.i_height = vout->fmt_in.i_height;
  442.     vout->fmt_out.i_x_offset = vout->fmt_in.i_x_offset;
  443.     vout->fmt_out.i_y_offset = vout->fmt_in.i_y_offset;
  444.     assert (height > 0);
  445.     vout->output.i_aspect = vout->fmt_out.i_aspect =
  446.         width * VOUT_ASPECT_FACTOR / height;
  447.     return VLC_SUCCESS;
  448. }
  449. /**
  450.  * Free picture buffers.
  451.  */
  452. static void Deinit (vout_thread_t *vout)
  453. {
  454.     vout_sys_t *p_sys = vout->p_sys;
  455.     for (int i = 0; i < I_OUTPUTPICTURES; i++)
  456.         PictureFree (PP_OUTPUTPICTURE[i], p_sys->conn);
  457. }
  458. /**
  459.  * Sends an image to the X server.
  460.  */
  461. static void Display (vout_thread_t *vout, picture_t *pic)
  462. {
  463.     vout_sys_t *p_sys = vout->p_sys;
  464.     xcb_shm_seg_t segment = (uintptr_t)pic->p_sys;
  465.     if (segment)
  466.         xcb_xv_shm_put_image (p_sys->conn, p_sys->port, p_sys->window,
  467.                               p_sys->gc, segment, p_sys->id, 0,
  468.                               /* Src: */ vout->fmt_out.i_x_offset,
  469.                               vout->fmt_out.i_y_offset,
  470.                               vout->fmt_out.i_visible_width,
  471.                               vout->fmt_out.i_visible_height,
  472.                               /* Dst: */ 0, 0, p_sys->width, p_sys->height,
  473.                               /* Memory: */
  474.                               pic->p->i_pitch / pic->p->i_pixel_pitch,
  475.                               pic->p->i_lines, false);
  476.     else
  477.         xcb_xv_put_image (p_sys->conn, p_sys->port, p_sys->window,
  478.                           p_sys->gc, p_sys->id,
  479.                           vout->fmt_out.i_x_offset, vout->fmt_out.i_y_offset,
  480.                           vout->fmt_out.i_visible_width,
  481.                           vout->fmt_out.i_visible_height,
  482.                           0, 0, p_sys->width, p_sys->height,
  483.                           vout->fmt_out.i_width, vout->fmt_out.i_height,
  484.                           p_sys->data_size, pic->p->p_pixels);
  485.     xcb_flush (p_sys->conn);
  486. }
  487. /**
  488.  * Process incoming X events.
  489.  */
  490. static int Manage (vout_thread_t *vout)
  491. {
  492.     vout_sys_t *p_sys = vout->p_sys;
  493.     xcb_generic_event_t *ev;
  494.     while ((ev = xcb_poll_for_event (p_sys->conn)) != NULL)
  495.         ProcessEvent (vout, p_sys->conn, p_sys->window, ev);
  496.     if (xcb_connection_has_error (p_sys->conn))
  497.     {
  498.         msg_Err (vout, "X server failure");
  499.         return VLC_EGENERIC;
  500.     }
  501.     CommonManage (vout);
  502.     if (vout->i_changes & VOUT_SIZE_CHANGE)
  503.     {   /* TODO: factor this code with XV and X11 Init() */
  504.         unsigned x, y, width, height;
  505.         if (GetWindowSize (p_sys->embed, p_sys->conn, &width, &height))
  506.             return VLC_EGENERIC;
  507.         vout_PlacePicture (vout, width, height, &x, &y, &width, &height);
  508.         const uint32_t values[] = { x, y, width, height, };
  509.         xcb_configure_window (p_sys->conn, p_sys->window, XCB_CONFIG_WINDOW_X |
  510.                               XCB_CONFIG_WINDOW_Y | XCB_CONFIG_WINDOW_WIDTH |
  511.                               XCB_CONFIG_WINDOW_HEIGHT, values);
  512.         vout->p_sys->width = width; // XXX: <-- this is useless, as the zoom is
  513.         vout->p_sys->height = height; // handled with VOUT_SET_SIZE anyway.
  514.         vout->i_changes &= ~VOUT_SIZE_CHANGE;
  515.     }
  516.     return VLC_SUCCESS;
  517. }
  518. void
  519. HandleParentStructure (vout_thread_t *vout, xcb_connection_t *conn,
  520.                        xcb_window_t xid, xcb_configure_notify_event_t *ev)
  521. {
  522.     unsigned width, height, x, y;
  523.     vout_PlacePicture (vout, ev->width, ev->height, &x, &y, &width, &height);
  524.     /* Move the picture within the window */
  525.     const uint32_t values[] = { x, y, width, height, };
  526.     xcb_configure_window (conn, xid,
  527.                           XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y
  528.                         | XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT,
  529.                           values);
  530.     vout->p_sys->width = width;
  531.     vout->p_sys->height = height;
  532. }
  533. static int Control (vout_thread_t *vout, int query, va_list ap)
  534. {
  535.     return vout_ControlWindow (vout->p_sys->embed, query, ap);
  536. }