1 /*****************************************************************************
2 * vout_xvideo.c: Xvideo video output display method
3 *****************************************************************************
4 * Copyright (C) 1998, 1999, 2000, 2001 VideoLAN
5 * $Id: vout_xvideo.c,v 1.7 2001/04/15 04:46:41 sam Exp $
7 * Authors: Shane Harper <shanegh@optusnet.com.au>
8 * Vincent Seguin <seguin@via.ecp.fr>
9 * Samuel Hocevar <sam@zoy.org>
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
24 *****************************************************************************/
26 #define MODULE_NAME xvideo
27 #include "modules_inner.h"
29 /*****************************************************************************
31 *****************************************************************************/
34 #include <errno.h> /* ENOMEM */
35 #include <stdlib.h> /* free() */
36 #include <string.h> /* strerror() */
38 #ifdef HAVE_MACHINE_PARAM_H
40 #include <machine/param.h>
41 #include <sys/types.h> /* typedef ushort */
45 #include <sys/shm.h> /* shmget(), shmctl() */
47 #include <X11/Xutil.h>
48 #include <X11/keysym.h>
49 #include <X11/extensions/XShm.h>
50 #include <X11/extensions/Xv.h>
51 #include <X11/extensions/Xvlib.h>
61 #include "video_output.h"
63 #include "interface.h"
66 #include "netutils.h" /* network_ChannelJoin */
71 #define GUID_YUV12_PLANAR 0x32315659
74 /*****************************************************************************
75 * vout_sys_t: video output X11 method descriptor
76 *****************************************************************************
77 * This structure is part of the video output thread descriptor.
78 * It describes the XVideo specific properties of an output thread.
79 *****************************************************************************/
80 typedef struct vout_sys_s
84 /* this plugin (currently) requires the SHM Ext... */
85 boolean_t b_shm; /* shared memory extension flag */
88 /* Internal settings and properties */
89 Display * p_display; /* display pointer */
90 int i_screen; /* screen number */
91 Window window; /* root window */
92 GC gc; /* graphic context instance handler */
95 /* Display buffers and shared memory information */
96 /* Note: only 1 buffer... Xv ext does double buffering. */
100 /* i_image_width & i_image_height reflect the
101 * size of the XvImage. They are used by
102 * vout_Display() to check if the image to be
103 * displayed can use the current XvImage. */
104 XShmSegmentInfo shm_info; /* shared memory zone information */
106 /* X11 generic properties */
108 Atom wm_delete_window;
110 int i_window_width; /* width of main window */
111 int i_window_height; /* height of main window */
114 /* Screen saver properties */
115 int i_ss_timeout; /* timeout */
116 int i_ss_interval; /* interval between changes */
117 int i_ss_blanking; /* blanking mode */
118 int i_ss_exposure; /* exposure mode */
120 /* Auto-hide cursor */
123 /* Mouse pointer properties */
124 boolean_t b_mouse; /* is the mouse pointer displayed ? */
128 /*****************************************************************************
130 *****************************************************************************/
131 static int vout_Probe ( probedata_t * );
132 static int vout_Create ( vout_thread_t * );
133 static int vout_Init ( vout_thread_t * );
134 static void vout_End ( vout_thread_t * );
135 static void vout_Destroy ( vout_thread_t * );
136 static int vout_Manage ( vout_thread_t * );
137 static void vout_Display ( vout_thread_t * );
138 static void vout_SetPalette( vout_thread_t *, u16 *, u16 *, u16 *, u16 * );
140 static int XVideoCreateWindow ( vout_thread_t * );
141 static int XVideoUpdateImgSizeIfRequired( vout_thread_t *p_vout );
142 static int XVideoCreateShmImage ( Display* dpy, int xv_port,
143 XvImage **pp_xvimage,
144 XShmSegmentInfo *p_shm_info,
145 int i_width, int i_height );
146 static void XVideoDestroyShmImage ( vout_thread_t *, XvImage *,
148 static void XVideoTogglePointer ( vout_thread_t * );
149 static void XVideoEnableScreenSaver ( vout_thread_t * );
150 static void XVideoDisableScreenSaver ( vout_thread_t * );
151 /*static void XVideoSetAttribute ( vout_thread_t *, char *, float );*/
153 static int XVideoCheckForXv ( Display * );
154 static int XVideoGetPort ( Display * );
155 static void XVideoOutputCoords ( const picture_t *, const boolean_t,
156 const int, const int,
157 int *, int *, int *, int * );
159 /*****************************************************************************
160 * Functions exported as capabilities. They are declared as static so that
161 * we don't pollute the namespace too much.
162 *****************************************************************************/
163 void _M( vout_getfunctions )( function_list_t * p_function_list )
165 p_function_list->pf_probe = vout_Probe;
166 p_function_list->functions.vout.pf_create = vout_Create;
167 p_function_list->functions.vout.pf_init = vout_Init;
168 p_function_list->functions.vout.pf_end = vout_End;
169 p_function_list->functions.vout.pf_destroy = vout_Destroy;
170 p_function_list->functions.vout.pf_manage = vout_Manage;
171 p_function_list->functions.vout.pf_display = vout_Display;
172 p_function_list->functions.vout.pf_setpalette = vout_SetPalette;
175 /*****************************************************************************
176 * vout_Probe: probe the video driver and return a score
177 *****************************************************************************
178 * This returns a score to the plugin manager so that it can select the best
180 *****************************************************************************/
181 static int vout_Probe( probedata_t *p_data )
183 if( TestMethod( VOUT_METHOD_VAR, "xvideo" ) )
191 /*****************************************************************************
192 * vout_Create: allocate XVideo video thread output method
193 *****************************************************************************
194 * This function allocate and initialize a XVideo vout method. It uses some of
195 * the vout properties to choose the window size, and change them according to
196 * the actual properties of the display.
197 *****************************************************************************/
198 static int vout_Create( vout_thread_t *p_vout )
202 /* Allocate structure */
203 p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
204 if( p_vout->p_sys == NULL )
206 intf_ErrMsg( "vout error: %s", strerror(ENOMEM) );
210 /* Open display, unsing 'vlc_display' or DISPLAY environment variable */
211 psz_display = XDisplayName( main_GetPszVariable( VOUT_DISPLAY_VAR, NULL ) );
212 p_vout->p_sys->p_display = XOpenDisplay( psz_display );
214 if( p_vout->p_sys->p_display == NULL ) /* error */
216 intf_ErrMsg( "vout error: cannot open display %s", psz_display );
217 free( p_vout->p_sys );
220 p_vout->p_sys->i_screen = DefaultScreen( p_vout->p_sys->p_display );
222 if( !XVideoCheckForXv( p_vout->p_sys->p_display ) )
224 intf_ErrMsg( "vout error: no XVideo extension" );
225 XCloseDisplay( p_vout->p_sys->p_display );
226 free( p_vout->p_sys );
230 /* Spawn base window - this window will include the video output window,
231 * but also command buttons, subtitles and other indicators */
232 if( XVideoCreateWindow( p_vout ) )
234 intf_ErrMsg( "vout error: cannot create XVideo window" );
235 XCloseDisplay( p_vout->p_sys->p_display );
236 free( p_vout->p_sys );
240 if( (p_vout->p_sys->xv_port = XVideoGetPort( p_vout->p_sys->p_display ))<0 )
242 intf_DbgMsg( 1, "Using xv port %d" , p_vout->p_sys->xv_port );
245 /* XXX The brightness and contrast values should be read from environment
246 * XXX variables... */
247 XVideoSetAttribute( p_vout, "XV_BRIGHTNESS", 0.5 );
248 XVideoSetAttribute( p_vout, "XV_CONTRAST", 0.5 );
251 p_vout->p_sys->b_mouse = 1;
253 /* Disable screen saver and return */
254 XVideoDisableScreenSaver( p_vout );
259 /*****************************************************************************
260 * vout_Init: initialize XVideo video thread output method
261 *****************************************************************************/
262 static int vout_Init( vout_thread_t *p_vout )
265 /* FIXME : As of 2001-03-16, XFree4 for MacOS X does not support Xshm. */
266 p_vout->p_sys->b_shm = 0;
268 p_vout->b_need_render = 0;
269 p_vout->p_sys->i_image_width = p_vout->p_sys->i_image_height = 0;
274 /*****************************************************************************
275 * vout_End: terminate XVideo video thread output method
276 *****************************************************************************
277 * Destroy the XvImage. It is called at the end of the thread, but also each
278 * time the image is resized.
279 *****************************************************************************/
280 static void vout_End( vout_thread_t *p_vout )
282 XVideoDestroyShmImage( p_vout, p_vout->p_sys->p_xvimage,
283 &p_vout->p_sys->shm_info );
286 /*****************************************************************************
287 * vout_Destroy: destroy XVideo video thread output method
288 *****************************************************************************
289 * Terminate an output method created by vout_CreateOutputMethod
290 *****************************************************************************/
291 static void vout_Destroy( vout_thread_t *p_vout )
293 /* Enable screen saver */
294 XVideoEnableScreenSaver( p_vout );
297 XUnmapWindow( p_vout->p_sys->p_display, p_vout->p_sys->window );
298 XFreeGC( p_vout->p_sys->p_display, p_vout->p_sys->gc );
299 XDestroyWindow( p_vout->p_sys->p_display, p_vout->p_sys->window );
301 XCloseDisplay( p_vout->p_sys->p_display );
303 /* Destroy structure */
304 free( p_vout->p_sys );
307 /*****************************************************************************
308 * vout_Manage: handle X11 events
309 *****************************************************************************
310 * This function should be called regularly by video output thread. It manages
311 * X11 events and allows window resizing. It returns a non null value on
314 * XXX Should "factor-out" common code in this and the "same" fn in the x11
316 *****************************************************************************/
317 static int vout_Manage( vout_thread_t *p_vout )
319 XEvent xevent; /* X11 event */
320 char i_key; /* ISO Latin-1 key */
323 /* Handle X11 events: ConfigureNotify events are parsed to know if the
324 * output window's size changed, MapNotify and UnmapNotify to know if the
325 * window is mapped (and if the display is useful), and ClientMessages
326 * to intercept window destruction requests */
327 while( XCheckWindowEvent( p_vout->p_sys->p_display, p_vout->p_sys->window,
328 StructureNotifyMask | KeyPressMask |
329 ButtonPressMask | ButtonReleaseMask |
330 PointerMotionMask, &xevent )
333 /* ConfigureNotify event: prepare */
334 if( (xevent.type == ConfigureNotify)
335 /*&& ((xevent.xconfigure.width != p_vout->p_sys->i_window_width)
336 || (xevent.xconfigure.height != p_vout->p_sys->i_window_height))*/ )
338 /* Update dimensions */
339 p_vout->p_sys->i_window_width = xevent.xconfigure.width;
340 p_vout->p_sys->i_window_height = xevent.xconfigure.height;
342 /* MapNotify event: change window status and disable screen saver */
343 else if( xevent.type == MapNotify)
345 if( (p_vout != NULL) && !p_vout->b_active )
347 XVideoDisableScreenSaver( p_vout );
348 p_vout->b_active = 1;
351 /* UnmapNotify event: change window status and enable screen saver */
352 else if( xevent.type == UnmapNotify )
354 if( (p_vout != NULL) && p_vout->b_active )
356 XVideoEnableScreenSaver( p_vout );
357 p_vout->b_active = 0;
361 else if( xevent.type == KeyPress )
363 /* We may have keys like F1 trough F12, ESC ... */
364 x_key_symbol = XKeycodeToKeysym( p_vout->p_sys->p_display,
365 xevent.xkey.keycode, 0 );
366 switch( x_key_symbol )
369 p_main->p_intf->b_die = 1;
372 p_main->p_intf->b_menu_change = 1;
376 * The reason why I use this instead of XK_0 is that
377 * with XLookupString, we don't have to care about
380 if( XLookupString( &xevent.xkey, &i_key, 1, NULL, NULL ) )
386 p_main->p_intf->b_die = 1;
389 network_ChannelJoin( 0 );
392 network_ChannelJoin( 1 );
395 network_ChannelJoin( 2 );
398 network_ChannelJoin( 3 );
401 network_ChannelJoin( 4 );
404 network_ChannelJoin( 5 );
407 network_ChannelJoin( 6 );
410 network_ChannelJoin( 7 );
413 network_ChannelJoin( 8 );
416 network_ChannelJoin( 9 );
419 if( intf_ProcessKey( p_main->p_intf,
422 intf_DbgMsg( "unhandled key '%c' (%i)",
423 (char)i_key, i_key );
432 else if( xevent.type == ButtonPress )
434 switch( ((XButtonEvent *)&xevent)->button )
437 /* in this part we will eventually manage
438 * clicks for DVD navigation for instance */
443 else if( xevent.type == ButtonRelease )
445 switch( ((XButtonEvent *)&xevent)->button )
448 /* FIXME: need locking ! */
449 p_main->p_intf->b_menu_change = 1;
454 else if( xevent.type == MotionNotify )
456 p_vout->p_sys->i_lastmoved = mdate();
457 if( ! p_vout->p_sys->b_mouse )
459 XVideoTogglePointer( p_vout );
467 intf_DbgMsg( "%p -> unhandled event type %d received",
468 p_vout, xevent.type );
473 /* ClientMessage event - only WM_PROTOCOLS with WM_DELETE_WINDOW data
474 * are handled - according to the man pages, the format is always 32
476 while( XCheckTypedEvent( p_vout->p_sys->p_display,
477 ClientMessage, &xevent ) )
479 if( (xevent.xclient.message_type == p_vout->p_sys->wm_protocols)
480 && (xevent.xclient.data.l[0] == p_vout->p_sys->wm_delete_window ) )
482 p_main->p_intf->b_die = 1;
486 intf_DbgMsg( "%p -> unhandled ClientMessage received", p_vout );
490 if( (p_vout->i_changes & VOUT_GRAYSCALE_CHANGE))
492 /* FIXME: clear flags ?? */
498 if( p_vout->i_changes & VOUT_SIZE_CHANGE )
500 intf_DbgMsg( "vout: resizing window" );
501 p_vout->i_changes &= ~VOUT_SIZE_CHANGE;
502 /* Noting to do here...
503 * vout_Display() detects size changes of the image to be displayed and
504 * re-creates the XvImage.*/
505 intf_Msg( "vout: video display resized (%dx%d)",
506 p_vout->i_width, p_vout->i_height );
509 /* Autohide Cursor */
510 if( p_vout->p_sys->b_mouse &&
511 mdate() - p_vout->p_sys->i_lastmoved > 2000000 )
512 XVideoTogglePointer( p_vout );
517 /*****************************************************************************
518 * XVideoUpdateImgSizeIfRequired
519 *****************************************************************************
520 * This function checks to see if the image to be displayed is of a different
521 * size to the last image displayed. If so, the old shm block must be
522 * destroyed and a new one created.
523 * Note: the "image size" is the size of the image to be passed to the Xv
524 * extension (which is probably different to the size of the output window).
525 *****************************************************************************/
526 static int XVideoUpdateImgSizeIfRequired( vout_thread_t *p_vout )
528 int i_img_width = p_vout->p_rendered_pic->i_width;
529 int i_img_height = p_vout->p_rendered_pic->i_height;
531 if( p_vout->p_sys->i_image_width != i_img_width
532 || p_vout->p_sys->i_image_height != i_img_height )
534 p_vout->p_sys->i_image_width = i_img_width;
535 p_vout->p_sys->i_image_height = i_img_height;
537 /* Destroy XvImage to change its size */
539 /* Note: vout_End does nothing if no XvImage to destroy. */
541 /* Create XvImage using XShm extension */
542 if( XVideoCreateShmImage( p_vout->p_sys->p_display,
543 p_vout->p_sys->xv_port,
544 &p_vout->p_sys->p_xvimage,
545 &p_vout->p_sys->shm_info,
546 i_img_width, i_img_height ) )
548 intf_ErrMsg( "vout: failed to create xvimage." );
549 p_vout->p_sys->i_image_width = 0;
553 /* Set bytes per line and initialize buffers */
554 p_vout->i_bytes_per_line =
555 (p_vout->p_sys->p_xvimage->data_size) /
556 (p_vout->p_sys->p_xvimage->height);
558 /* vout_SetBuffers( p_vout, p_vout->p_sys->p_xvimage->data ); */
563 /*****************************************************************************
564 * vout_Display: displays previously rendered output
565 *****************************************************************************
566 * This function sends the currently rendered image to X11 server.
567 * (The Xv extension takes care of "double-buffering".)
568 *****************************************************************************/
569 static void vout_Display( vout_thread_t *p_vout )
571 boolean_t b_draw = 1;
572 int i_size = p_vout->p_rendered_pic->i_width *
573 p_vout->p_rendered_pic->i_height;
575 if( XVideoUpdateImgSizeIfRequired( p_vout ) )
578 switch( p_vout->p_rendered_pic->i_type )
580 case YUV_422_PICTURE:
581 intf_ErrMsg( "vout error: YUV_422_PICTURE not (yet) supported" );
585 case YUV_444_PICTURE:
586 intf_ErrMsg( "vout error: YUV_444_PICTURE not (yet) supported" );
590 case YUV_420_PICTURE:
591 memcpy( p_vout->p_sys->p_xvimage->data,
592 p_vout->p_rendered_pic->p_y, i_size );
593 memcpy( p_vout->p_sys->p_xvimage->data + ( i_size ),
594 p_vout->p_rendered_pic->p_v, i_size / 4 );
595 memcpy( p_vout->p_sys->p_xvimage->data + ( i_size ) + ( i_size / 4 ),
596 p_vout->p_rendered_pic->p_u, i_size / 4 );
603 i_window_width = p_vout->p_sys->i_window_width,
604 i_window_height = p_vout->p_sys->i_window_height,
605 i_dest_width, i_dest_height, i_dest_x, i_dest_y;
609 /* If I change the line above to "#if 0" I find on resizing the window
610 * that blue rectangles (used to specify where part of the YUV overlay
611 * used to be drawn) may remain around the edge of the video output. */
612 XGetGeometry( p_vout->p_sys->p_display, p_vout->p_sys->window,
613 &window, &i_dummy, &i_dummy,
614 &i_window_width, &i_window_height, &i_dummy, &i_dummy );
617 XVideoOutputCoords( p_vout->p_rendered_pic, p_vout->b_scale,
618 i_window_width, i_window_height,
619 &i_dest_x, &i_dest_y,
620 &i_dest_width, &i_dest_height);
622 XvShmPutImage( p_vout->p_sys->p_display, p_vout->p_sys->xv_port,
623 p_vout->p_sys->window, p_vout->p_sys->gc,
624 p_vout->p_sys->p_xvimage,
625 0 /*src_x*/, 0 /*src_y*/,
626 p_vout->p_rendered_pic->i_width,
627 p_vout->p_rendered_pic->i_height,
628 i_dest_x, i_dest_y, i_dest_width, i_dest_height,
633 static void vout_SetPalette( p_vout_thread_t p_vout,
634 u16 *red, u16 *green, u16 *blue, u16 *transp )
639 /* following functions are local */
641 /*****************************************************************************
642 * XVideoCheckForXv: check for the XVideo extension
643 *****************************************************************************/
644 static int XVideoCheckForXv( Display *dpy )
648 switch( XvQueryExtension( dpy, &i, &i, &i, &i, &i ) )
654 intf_ErrMsg( "vout error: XvBadExtension" );
658 intf_ErrMsg( "vout error: XvBadAlloc" );
662 intf_ErrMsg( "vout error: XvQueryExtension failed" );
667 /*****************************************************************************
668 * XVideoCreateWindow: open and set-up XVideo main window
669 *****************************************************************************/
670 static int XVideoCreateWindow( vout_thread_t *p_vout )
672 XSizeHints xsize_hints;
673 XSetWindowAttributes xwindow_attributes;
677 boolean_t b_configure_notify;
678 boolean_t b_map_notify;
680 /* Set main window's size */
681 p_vout->p_sys->i_window_width = main_GetIntVariable( VOUT_WIDTH_VAR,
682 VOUT_WIDTH_DEFAULT );
683 p_vout->p_sys->i_window_height = main_GetIntVariable( VOUT_HEIGHT_VAR,
684 VOUT_HEIGHT_DEFAULT );
686 /* Prepare window manager hints and properties */
687 xsize_hints.base_width = p_vout->p_sys->i_window_width;
688 xsize_hints.base_height = p_vout->p_sys->i_window_height;
689 xsize_hints.flags = PSize;
690 p_vout->p_sys->wm_protocols = XInternAtom( p_vout->p_sys->p_display,
691 "WM_PROTOCOLS", True );
692 p_vout->p_sys->wm_delete_window = XInternAtom( p_vout->p_sys->p_display,
693 "WM_DELETE_WINDOW", True );
695 /* Prepare window attributes */
696 xwindow_attributes.backing_store = Always; /* save the hidden part */
697 xwindow_attributes.background_pixel = BlackPixel( p_vout->p_sys->p_display,
698 p_vout->p_sys->i_screen );
700 xwindow_attributes.event_mask = ExposureMask | StructureNotifyMask;
702 /* Create the window and set hints - the window must receive ConfigureNotify
703 * events, and, until it is displayed, Expose and MapNotify events. */
704 p_vout->p_sys->window =
705 XCreateWindow( p_vout->p_sys->p_display,
706 DefaultRootWindow( p_vout->p_sys->p_display ),
708 p_vout->p_sys->i_window_width,
709 p_vout->p_sys->i_window_height, 1,
711 CWBackingStore | CWBackPixel | CWEventMask,
712 &xwindow_attributes );
714 /* Set window manager hints and properties: size hints, command,
715 * window's name, and accepted protocols */
716 XSetWMNormalHints( p_vout->p_sys->p_display, p_vout->p_sys->window,
718 XSetCommand( p_vout->p_sys->p_display, p_vout->p_sys->window,
719 p_main->ppsz_argv, p_main->i_argc );
720 XStoreName( p_vout->p_sys->p_display, p_vout->p_sys->window,
721 VOUT_TITLE " (XVideo output)" );
723 if( (p_vout->p_sys->wm_protocols == None) /* use WM_DELETE_WINDOW */
724 || (p_vout->p_sys->wm_delete_window == None)
725 || !XSetWMProtocols( p_vout->p_sys->p_display, p_vout->p_sys->window,
726 &p_vout->p_sys->wm_delete_window, 1 ) )
728 /* WM_DELETE_WINDOW is not supported by window manager */
729 intf_Msg( "vout error: missing or bad window manager" );
732 /* Creation of a graphic context that doesn't generate a GraphicsExpose
733 * event when using functions like XCopyArea */
734 xgcvalues.graphics_exposures = False;
735 p_vout->p_sys->gc = XCreateGC( p_vout->p_sys->p_display,
736 p_vout->p_sys->window,
737 GCGraphicsExposures, &xgcvalues);
739 /* Send orders to server, and wait until window is displayed - three
740 * events must be received: a MapNotify event, an Expose event allowing
741 * drawing in the window, and a ConfigureNotify to get the window
742 * dimensions. Once those events have been received, only ConfigureNotify
743 * events need to be received. */
745 b_configure_notify = 0;
747 XMapWindow( p_vout->p_sys->p_display, p_vout->p_sys->window);
750 XNextEvent( p_vout->p_sys->p_display, &xevent);
751 if( (xevent.type == Expose)
752 && (xevent.xexpose.window == p_vout->p_sys->window) )
756 else if( (xevent.type == MapNotify)
757 && (xevent.xmap.window == p_vout->p_sys->window) )
761 else if( (xevent.type == ConfigureNotify)
762 && (xevent.xconfigure.window == p_vout->p_sys->window) )
764 b_configure_notify = 1;
765 p_vout->p_sys->i_window_width = xevent.xconfigure.width;
766 p_vout->p_sys->i_window_height = xevent.xconfigure.height;
768 } while( !( b_expose && b_configure_notify && b_map_notify ) );
770 XSelectInput( p_vout->p_sys->p_display, p_vout->p_sys->window,
771 StructureNotifyMask | KeyPressMask |
772 ButtonPressMask | ButtonReleaseMask |
775 /* At this stage, the window is open, displayed, and ready to
780 /*****************************************************************************
781 * XVideoCreateShmImage: create an XvImage using shared memory extension
782 *****************************************************************************
783 * Prepare an XvImage for display function.
784 * The order of the operations respects the recommandations of the mit-shm
785 * document by J.Corbet and K.Packard. Most of the parameters were copied from
787 *****************************************************************************/
788 static int XVideoCreateShmImage( Display* dpy, int xv_port,
789 XvImage **pp_xvimage,
790 XShmSegmentInfo *p_shm_info,
791 int i_width, int i_height )
793 *pp_xvimage = XvShmCreateImage( dpy, xv_port,
794 GUID_YUV12_PLANAR, 0,
799 intf_ErrMsg( "vout error: XvShmCreateImage failed." );
803 p_shm_info->shmid = shmget( IPC_PRIVATE, (*pp_xvimage)->data_size,
805 if( p_shm_info->shmid < 0) /* error */
807 intf_ErrMsg( "vout error: cannot allocate shared image data (%s)",
812 p_shm_info->shmaddr = (*pp_xvimage)->data = shmat( p_shm_info->shmid,
814 p_shm_info->readOnly = False;
816 /* Mark the shm segment to be removed when there will be no more
817 * attachements, so it is automatic on process exit or after shmdt */
818 shmctl( p_shm_info->shmid, IPC_RMID, 0 );
820 if( !XShmAttach( dpy, p_shm_info ) )
822 intf_ErrMsg( "vout error: XShmAttach failed" );
823 shmdt( p_shm_info->shmaddr );
827 /* Send image to X server. This instruction is required, since having
828 * built a Shm XImage and not using it causes an error on XCloseDisplay */
834 /*****************************************************************************
835 * XVideoDestroyShmImage
836 *****************************************************************************
837 * Destroy XImage AND associated data. Detach shared memory segment from
838 * server and process, then free it. If pointer is NULL, the image won't be
839 * destroyed (see vout_ManageOutputMethod())
840 *****************************************************************************/
841 static void XVideoDestroyShmImage( vout_thread_t *p_vout, XvImage *p_xvimage,
842 XShmSegmentInfo *p_shm_info )
844 /* If pointer is NULL, do nothing */
845 if( p_xvimage == NULL )
850 XShmDetach( p_vout->p_sys->p_display, p_shm_info );/* detach from server */
852 XDestroyImage( p_ximage ); /* XXX */
855 if( shmdt( p_shm_info->shmaddr ) ) /* detach shared memory from process */
856 { /* also automatic freeing... */
857 intf_ErrMsg( "vout error: cannot detach shared memory (%s)",
862 /*****************************************************************************
863 * XVideoEnableScreenSaver: enable screen saver
864 *****************************************************************************
865 * This function enable the screen saver on a display after it had been
866 * disabled by XDisableScreenSaver. Both functions use a counter mechanism to
867 * know wether the screen saver can be activated or not: if n successive calls
868 * are made to XDisableScreenSaver, n successive calls to XEnableScreenSaver
869 * will be required before the screen saver could effectively be activated.
870 *****************************************************************************/
871 void XVideoEnableScreenSaver( vout_thread_t *p_vout )
873 intf_DbgMsg( "intf: enabling screen saver" );
874 XSetScreenSaver( p_vout->p_sys->p_display, p_vout->p_sys->i_ss_timeout,
875 p_vout->p_sys->i_ss_interval,
876 p_vout->p_sys->i_ss_blanking,
877 p_vout->p_sys->i_ss_exposure );
880 /*****************************************************************************
881 * XVideoDisableScreenSaver: disable screen saver
882 *****************************************************************************
883 * See XEnableScreenSaver
884 *****************************************************************************/
885 void XVideoDisableScreenSaver( vout_thread_t *p_vout )
887 /* Save screen saver informations */
888 XGetScreenSaver( p_vout->p_sys->p_display, &p_vout->p_sys->i_ss_timeout,
889 &p_vout->p_sys->i_ss_interval,
890 &p_vout->p_sys->i_ss_blanking,
891 &p_vout->p_sys->i_ss_exposure );
893 /* Disable screen saver */
894 intf_DbgMsg( "intf: disabling screen saver" );
895 XSetScreenSaver( p_vout->p_sys->p_display, 0,
896 p_vout->p_sys->i_ss_interval,
897 p_vout->p_sys->i_ss_blanking,
898 p_vout->p_sys->i_ss_exposure );
901 /*****************************************************************************
902 * XVideoTogglePointer: hide or show the mouse pointer
903 *****************************************************************************
904 * This function hides the X pointer if it is visible by putting it at
905 * coordinates (32,32) and setting the pointer sprite to a blank one. To
906 * show it again, we disable the sprite and restore the original coordinates.
907 *****************************************************************************/
908 void XVideoTogglePointer( vout_thread_t *p_vout )
910 static Cursor cursor;
911 static boolean_t b_cursor = 0;
913 if( p_vout->p_sys->b_mouse )
915 p_vout->p_sys->b_mouse = 0;
920 Pixmap blank = XCreatePixmap( p_vout->p_sys->p_display,
921 DefaultRootWindow(p_vout->p_sys->p_display),
924 XParseColor( p_vout->p_sys->p_display,
925 XCreateColormap( p_vout->p_sys->p_display,
927 p_vout->p_sys->p_display ),
929 p_vout->p_sys->p_display,
930 p_vout->p_sys->i_screen ),
934 cursor = XCreatePixmapCursor( p_vout->p_sys->p_display,
935 blank, blank, &color, &color, 1, 1 );
939 XDefineCursor( p_vout->p_sys->p_display,
940 p_vout->p_sys->window, cursor );
944 p_vout->p_sys->b_mouse = 1;
946 XUndefineCursor( p_vout->p_sys->p_display, p_vout->p_sys->window );
950 /* This based on some code in SetBufferPicture... At the moment it's only
951 * used by the xvideo plugin, but others may want to use it. */
952 static void XVideoOutputCoords( const picture_t *p_pic, const boolean_t scale,
953 const int win_w, const int win_h,
954 int *dx, int *dy, int *w, int *h)
958 *w = p_pic->i_width; *h = p_pic->i_height;
963 switch( p_pic->i_aspect_ratio )
965 case AR_3_4_PICTURE: *h = win_w * 3 / 4; break;
966 case AR_16_9_PICTURE: *h = win_w * 9 / 16; break;
967 case AR_221_1_PICTURE: *h = win_w * 100 / 221; break;
968 case AR_SQUARE_PICTURE:
969 default: *h = win_w; break;
975 switch( p_pic->i_aspect_ratio )
977 case AR_3_4_PICTURE: *w = win_h * 4 / 3; break;
978 case AR_16_9_PICTURE: *w = win_h * 16 / 9; break;
979 case AR_221_1_PICTURE: *w = win_h * 221 / 100; break;
980 case AR_SQUARE_PICTURE:
981 default: *w = win_h; break;
986 /* Set picture position */
987 *dx = (win_w - *w) / 2;
988 *dy = (win_h - *h) / 2;
992 static int XVideoGetPort( Display *dpy )
996 XvAdaptorInfo *adaptor_info;
998 switch( XvQueryAdaptors( dpy, DefaultRootWindow( dpy ),
999 &i_adaptors, &adaptor_info ) )
1004 case XvBadExtension:
1005 intf_ErrMsg( "vout error: XvBadExtension for XvQueryAdaptors" );
1009 intf_ErrMsg( "vout error: XvBadAlloc for XvQueryAdaptors" );
1013 intf_ErrMsg( "vout error: XvQueryAdaptors failed" );
1017 for( i=0; i < i_adaptors && xv_port == -1; ++i )
1018 if( ( adaptor_info[ i ].type & XvInputMask ) &&
1019 ( adaptor_info[ i ].type & XvImageMask ) )
1021 /* check that port supports YUV12 planar format... */
1022 int port = adaptor_info[ i ].base_id;
1023 int i_num_formats, i;
1024 XvImageFormatValues *imageFormats;
1026 imageFormats = XvListImageFormats( dpy, port, &i_num_formats );
1028 for( i=0; i < i_num_formats && xv_port == -1; ++i )
1029 if( imageFormats[ i ].id == GUID_YUV12_PLANAR )
1033 intf_WarnMsg( 3, "vout: XVideo image input port %d "
1034 "does not support the YUV12 planar format which is "
1035 "currently required by the xvideo output plugin.",
1039 XFree( imageFormats );
1042 if( i_adaptors > 0 )
1043 XvFreeAdaptorInfo(adaptor_info);
1046 intf_ErrMsg( "vout error: didn't find a suitable Xvideo image input port." );
1053 /*****************************************************************************
1054 * XVideoSetAttribute
1055 *****************************************************************************
1056 * This function can be used to set attributes, e.g. XV_BRIGHTNESS and
1057 * XV_CONTRAST. "f_value" should be in the range of 0 to 1.
1058 *****************************************************************************/
1059 static void XVideoSetAttribute( vout_thread_t *p_vout,
1060 char *attr_name, float f_value )
1063 XvAttribute *p_attrib;
1064 Display *p_dpy = p_vout->p_sys->p_display;
1065 int xv_port = p_vout->p_sys->xv_port;
1067 p_attrib = XvQueryPortAttributes( p_dpy, xv_port, &i_attrib );
1073 if( i_attrib >= 0 && !strcmp( p_attrib[ i_attrib ].name, attr_name ) )
1075 int i_sv = f_value * ( p_attrib[ i_attrib ].max_value
1076 - p_attrib[ i_attrib ].min_value + 1 )
1077 + p_attrib[ i_attrib ].min_value;
1079 XvSetPortAttribute( p_dpy, xv_port,
1080 XInternAtom( p_dpy, attr_name, False ), i_sv );
1084 } while( i_attrib > 0 );