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

midi

开发平台:

Unix_Linux

  1. /**
  2.  * @file common.c
  3.  * @brief Common code for XCB video output plugins
  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 <sys/types.h>
  28. #include <sys/shm.h>
  29. #include <xcb/xcb.h>
  30. #include <xcb/shm.h>
  31. #include <vlc_common.h>
  32. #include <vlc_vout.h>
  33. #include <vlc_window.h>
  34. #include "xcb_vlc.h"
  35. /**
  36.  * Connect to the X server.
  37.  */
  38. xcb_connection_t *Connect (vlc_object_t *obj)
  39. {
  40.     char *display = var_CreateGetNonEmptyString (obj, "x11-display");
  41.     xcb_connection_t *conn = xcb_connect (display, NULL);
  42.     free (display);
  43.     if (xcb_connection_has_error (conn) /*== NULL*/)
  44.     {
  45.         msg_Err (obj, "cannot connect to X server");
  46.         xcb_disconnect (conn);
  47.         return NULL;
  48.     }
  49.     return conn;
  50. }
  51. /**
  52.  * Create a VLC video X window object, find the corresponding X server screen,
  53.  * and probe the MIT-SHM extension.
  54.  */
  55. vout_window_t *GetWindow (vout_thread_t *obj,
  56.                           xcb_connection_t *conn,
  57.                           const xcb_screen_t **restrict pscreen,
  58.                           bool *restrict pshm)
  59. {
  60.     /* Get window */
  61.     xcb_window_t root;
  62.     vout_window_t *wnd = vout_RequestXWindow (obj, &(int){ 0 }, &(int){ 0 },
  63.                                         &(unsigned){ 0 }, &(unsigned){ 0 });
  64.     if (wnd == NULL)
  65.     {
  66.         msg_Err (obj, "parent window not available");
  67.         return NULL;
  68.     }
  69.     else
  70.     {
  71.         xcb_get_geometry_reply_t *geo;
  72.         xcb_get_geometry_cookie_t ck;
  73.         ck = xcb_get_geometry (conn, wnd->handle.xid);
  74.         geo = xcb_get_geometry_reply (conn, ck, NULL);
  75.         if (geo == NULL)
  76.         {
  77.             msg_Err (obj, "parent window not valid");
  78.             goto error;
  79.         }
  80.         root = geo->root;
  81.         free (geo);
  82.         /* Subscribe to parent window resize events */
  83.         const uint32_t value = XCB_EVENT_MASK_STRUCTURE_NOTIFY;
  84.         xcb_change_window_attributes (conn, wnd->handle.xid,
  85.                                       XCB_CW_EVENT_MASK, &value);
  86.     }
  87.     /* Find the selected screen */
  88.     const xcb_setup_t *setup = xcb_get_setup (conn);
  89.     xcb_screen_t *screen = NULL;
  90.     for (xcb_screen_iterator_t i = xcb_setup_roots_iterator (setup);
  91.          i.rem > 0 && screen == NULL; xcb_screen_next (&i))
  92.     {
  93.         if (i.data->root == root)
  94.             screen = i.data;
  95.     }
  96.     if (screen == NULL)
  97.     {
  98.         msg_Err (obj, "parent window screen not found");
  99.         goto error;
  100.     }
  101.     msg_Dbg (obj, "using screen 0x%"PRIx32, root);
  102.     /* Check MIT-SHM shared memory support */
  103.     bool shm = var_CreateGetBool (obj, "x11-shm") > 0;
  104.     if (shm)
  105.     {
  106.         xcb_shm_query_version_cookie_t ck;
  107.         xcb_shm_query_version_reply_t *r;
  108.         ck = xcb_shm_query_version (conn);
  109.         r = xcb_shm_query_version_reply (conn, ck, NULL);
  110.         if (!r)
  111.         {
  112.             msg_Err (obj, "shared memory (MIT-SHM) not available");
  113.             msg_Warn (obj, "display will be slow");
  114.             shm = false;
  115.         }
  116.         free (r);
  117.     }
  118.     *pscreen = screen;
  119.     *pshm = shm;
  120.     return wnd;
  121. error:
  122.     vout_ReleaseWindow (wnd);
  123.     return NULL;
  124. }
  125. /**
  126.  * Gets the size of an X window.
  127.  */
  128. int GetWindowSize (struct vout_window_t *wnd, xcb_connection_t *conn,
  129.                    unsigned *restrict width, unsigned *restrict height)
  130. {
  131.     xcb_get_geometry_cookie_t ck = xcb_get_geometry (conn, wnd->handle.xid);
  132.     xcb_get_geometry_reply_t *geo = xcb_get_geometry_reply (conn, ck, NULL);
  133.     if (!geo)
  134.         return -1;
  135.     *width = geo->width;
  136.     *height = geo->height;
  137.     free (geo);
  138.     return 0;
  139. }
  140. /**
  141.  * Initialize a picture buffer as shared memory, according to the video output
  142.  * format. If a XCB connection pointer is supplied, the segment is attached to
  143.  * the X server (MIT-SHM extension).
  144.  */
  145. int PictureAlloc (vout_thread_t *vout, picture_t *pic, size_t size,
  146.                   xcb_connection_t *conn)
  147. {
  148.     assert (pic->i_status == FREE_PICTURE);
  149.     /* Allocate shared memory segment */
  150.     int id = shmget (IPC_PRIVATE, size, IPC_CREAT | 0700);
  151.     if (id == -1)
  152.     {
  153.         msg_Err (vout, "shared memory allocation error: %m");
  154.         return VLC_EGENERIC;
  155.     }
  156.     /* Attach the segment to VLC */
  157.     void *shm = shmat (id, NULL, 0 /* read/write */);
  158.     if (-1 == (intptr_t)shm)
  159.     {
  160.         msg_Err (vout, "shared memory attachment error: %m");
  161.         shmctl (id, IPC_RMID, 0);
  162.         return VLC_EGENERIC;
  163.     }
  164.     xcb_shm_seg_t segment;
  165.     if (conn != NULL)
  166.     {
  167.         /* Attach the segment to X */
  168.         xcb_void_cookie_t ck;
  169.         segment = xcb_generate_id (conn);
  170.         ck = xcb_shm_attach_checked (conn, segment, id, 1);
  171.         if (CheckError (vout, "shared memory server-side error", ck))
  172.         {
  173.             msg_Info (vout, "using buggy X11 server - SSH proxying?");
  174.             segment = 0;
  175.         }
  176.     }
  177.     else
  178.         segment = 0;
  179.     shmctl (id, IPC_RMID, 0);
  180.     pic->p_sys = (void *)(uintptr_t)segment;
  181.     pic->p->p_pixels = shm;
  182.     pic->i_status = DESTROYED_PICTURE;
  183.     pic->i_type = DIRECT_PICTURE;
  184.     return VLC_SUCCESS;
  185. }
  186. /**
  187.  * Release picture private data: detach the shared memory segment.
  188.  */
  189. void PictureFree (picture_t *pic, xcb_connection_t *conn)
  190. {
  191.     xcb_shm_seg_t segment = (uintptr_t)pic->p_sys;
  192.     if (segment != 0)
  193.     {
  194.         assert (conn != NULL);
  195.         xcb_shm_detach (conn, segment);
  196.     }
  197.     shmdt (pic->p->p_pixels);
  198. }
  199. /**
  200.  * Video output thread management stuff.
  201.  * FIXME: Much of this should move to core
  202.  */
  203. void CommonManage (vout_thread_t *vout)
  204. {
  205.     if (vout->i_changes & VOUT_SCALE_CHANGE)
  206.     {
  207.         vout->b_autoscale = var_GetBool (vout, "autoscale");
  208.         vout->i_zoom = ZOOM_FP_FACTOR;
  209.         vout->i_changes &= ~VOUT_SCALE_CHANGE;
  210.         vout->i_changes |= VOUT_SIZE_CHANGE;
  211.     }
  212.     if (vout->i_changes & VOUT_ZOOM_CHANGE)
  213.     {
  214.         vout->b_autoscale = false;
  215.         vout->i_zoom = var_GetFloat (vout, "scale") * ZOOM_FP_FACTOR;
  216.         vout->i_changes &= ~VOUT_ZOOM_CHANGE;
  217.         vout->i_changes |= VOUT_SIZE_CHANGE;
  218.     }
  219.     if (vout->i_changes & VOUT_CROP_CHANGE)
  220.     {
  221.         vout->fmt_out.i_x_offset = vout->fmt_in.i_x_offset;
  222.         vout->fmt_out.i_y_offset = vout->fmt_in.i_y_offset;
  223.         vout->fmt_out.i_visible_width = vout->fmt_in.i_visible_width;
  224.         vout->fmt_out.i_visible_height = vout->fmt_in.i_visible_height;
  225.         vout->i_changes &= ~VOUT_CROP_CHANGE;
  226.         vout->i_changes |= VOUT_SIZE_CHANGE;
  227.     }
  228.     if (vout->i_changes & VOUT_ASPECT_CHANGE)
  229.     {
  230.         vout->fmt_out.i_aspect = vout->fmt_in.i_aspect;
  231.         vout->fmt_out.i_sar_num = vout->fmt_in.i_sar_num;
  232.         vout->fmt_out.i_sar_den = vout->fmt_in.i_sar_den;
  233.         vout->output.i_aspect = vout->fmt_in.i_aspect;
  234.         vout->i_changes &= ~VOUT_ASPECT_CHANGE;
  235.         vout->i_changes |= VOUT_SIZE_CHANGE;
  236.     }
  237. }