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.9 2001/04/21 22:49:24 sam Exp $
7 * Authors: Shane Harper <shanegh@optusnet.com.au>
8 * Vincent Seguin <seguin@via.ecp.fr>
9 * Samuel Hocevar <sam@zoy.org>
10 * David Kennedy <dkennedy@tinytoad.com>
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
25 *****************************************************************************/
27 #define MODULE_NAME xvideo
28 #include "modules_inner.h"
30 /*****************************************************************************
32 *****************************************************************************/
35 #include <errno.h> /* ENOMEM */
36 #include <stdlib.h> /* free() */
37 #include <string.h> /* strerror() */
39 #ifdef HAVE_MACHINE_PARAM_H
41 #include <machine/param.h>
42 #include <sys/types.h> /* typedef ushort */
46 #include <sys/shm.h> /* shmget(), shmctl() */
48 #include <X11/Xutil.h>
49 #include <X11/keysym.h>
50 #include <X11/extensions/XShm.h>
51 #include <X11/extensions/Xv.h>
52 #include <X11/extensions/Xvlib.h>
62 #include "video_output.h"
64 #include "interface.h"
67 #include "netutils.h" /* network_ChannelJoin */
72 #define GUID_YUV12_PLANAR 0x32315659
75 /*****************************************************************************
76 * vout_sys_t: video output X11 method descriptor
77 *****************************************************************************
78 * This structure is part of the video output thread descriptor.
79 * It describes the XVideo specific properties of an output thread.
80 *****************************************************************************/
81 typedef struct vout_sys_s
85 /* this plugin (currently) requires the SHM Ext... */
86 boolean_t b_shm; /* shared memory extension flag */
89 /* Internal settings and properties */
90 Display * p_display; /* display pointer */
91 int i_screen; /* screen number */
92 Window window; /* root window */
93 GC gc; /* graphic context instance handler */
96 /* Display buffers and shared memory information */
97 /* Note: only 1 buffer... Xv ext does double buffering. */
101 /* i_image_width & i_image_height reflect the
102 * size of the XvImage. They are used by
103 * vout_Display() to check if the image to be
104 * displayed can use the current XvImage. */
105 XShmSegmentInfo shm_info; /* shared memory zone information */
107 /* X11 generic properties */
109 Atom wm_delete_window;
111 int i_window_width; /* width of main window */
112 int i_window_height; /* height of main window */
115 /* Screen saver properties */
116 int i_ss_timeout; /* timeout */
117 int i_ss_interval; /* interval between changes */
118 int i_ss_blanking; /* blanking mode */
119 int i_ss_exposure; /* exposure mode */
121 /* Auto-hide cursor */
124 /* Mouse pointer properties */
125 boolean_t b_mouse; /* is the mouse pointer displayed ? */
127 /* Displaying fullscreen */
128 boolean_t b_fullscreen;
132 /* Fullscreen needs to be able to hide the wm decorations */
133 #define MWM_HINTS_DECORATIONS (1L << 1)
134 #define PROP_MWM_HINTS_ELEMENTS 5
135 typedef struct mwmhints_s
144 /*****************************************************************************
146 *****************************************************************************/
147 static int vout_Probe ( probedata_t * );
148 static int vout_Create ( vout_thread_t * );
149 static int vout_Init ( vout_thread_t * );
150 static void vout_End ( vout_thread_t * );
151 static void vout_Destroy ( vout_thread_t * );
152 static int vout_Manage ( vout_thread_t * );
153 static void vout_Display ( vout_thread_t * );
154 static void vout_SetPalette( vout_thread_t *, u16 *, u16 *, u16 *, u16 * );
156 static int XVideoCreateWindow ( vout_thread_t * );
157 static int XVideoUpdateImgSizeIfRequired( vout_thread_t *p_vout );
158 static int XVideoCreateShmImage ( Display* dpy, int xv_port,
159 XvImage **pp_xvimage,
160 XShmSegmentInfo *p_shm_info,
161 int i_width, int i_height );
162 static void XVideoDestroyShmImage ( vout_thread_t *, XvImage *,
164 static void XVideoTogglePointer ( vout_thread_t * );
165 static void XVideoEnableScreenSaver ( vout_thread_t * );
166 static void XVideoDisableScreenSaver ( vout_thread_t * );
167 /*static void XVideoSetAttribute ( vout_thread_t *, char *, float );*/
169 static int XVideoCheckForXv ( Display * );
170 static int XVideoGetPort ( Display * );
171 static void XVideoOutputCoords ( const picture_t *, const boolean_t,
172 const int, const int,
173 int *, int *, int *, int * );
175 /*****************************************************************************
176 * Functions exported as capabilities. They are declared as static so that
177 * we don't pollute the namespace too much.
178 *****************************************************************************/
179 void _M( vout_getfunctions )( function_list_t * p_function_list )
181 p_function_list->pf_probe = vout_Probe;
182 p_function_list->functions.vout.pf_create = vout_Create;
183 p_function_list->functions.vout.pf_init = vout_Init;
184 p_function_list->functions.vout.pf_end = vout_End;
185 p_function_list->functions.vout.pf_destroy = vout_Destroy;
186 p_function_list->functions.vout.pf_manage = vout_Manage;
187 p_function_list->functions.vout.pf_display = vout_Display;
188 p_function_list->functions.vout.pf_setpalette = vout_SetPalette;
191 /*****************************************************************************
192 * vout_Probe: probe the video driver and return a score
193 *****************************************************************************
194 * This returns a score to the plugin manager so that it can select the best
196 *****************************************************************************/
197 static int vout_Probe( probedata_t *p_data )
199 if( TestMethod( VOUT_METHOD_VAR, "xvideo" ) )
207 /*****************************************************************************
208 * vout_Create: allocate XVideo video thread output method
209 *****************************************************************************
210 * This function allocate and initialize a XVideo vout method. It uses some of
211 * the vout properties to choose the window size, and change them according to
212 * the actual properties of the display.
213 *****************************************************************************/
214 static int vout_Create( vout_thread_t *p_vout )
218 /* Allocate structure */
219 p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
220 if( p_vout->p_sys == NULL )
222 intf_ErrMsg( "vout error: %s", strerror(ENOMEM) );
226 /* Open display, unsing 'vlc_display' or DISPLAY environment variable */
227 psz_display = XDisplayName( main_GetPszVariable( VOUT_DISPLAY_VAR, NULL ) );
228 p_vout->p_sys->p_display = XOpenDisplay( psz_display );
230 if( p_vout->p_sys->p_display == NULL ) /* error */
232 intf_ErrMsg( "vout error: cannot open display %s", psz_display );
233 free( p_vout->p_sys );
236 p_vout->p_sys->i_screen = DefaultScreen( p_vout->p_sys->p_display );
238 p_vout->p_sys->b_fullscreen
239 = main_GetIntVariable( VOUT_FULLSCREEN_VAR, VOUT_FULLSCREEN_DEFAULT );
241 if( !XVideoCheckForXv( p_vout->p_sys->p_display ) )
243 intf_ErrMsg( "vout error: no XVideo extension" );
244 XCloseDisplay( p_vout->p_sys->p_display );
245 free( p_vout->p_sys );
249 /* Spawn base window - this window will include the video output window,
250 * but also command buttons, subtitles and other indicators */
251 if( XVideoCreateWindow( p_vout ) )
253 intf_ErrMsg( "vout error: cannot create XVideo window" );
254 XCloseDisplay( p_vout->p_sys->p_display );
255 free( p_vout->p_sys );
259 if( (p_vout->p_sys->xv_port = XVideoGetPort( p_vout->p_sys->p_display ))<0 )
261 intf_DbgMsg( "Using xv port %d" , p_vout->p_sys->xv_port );
264 /* XXX The brightness and contrast values should be read from environment
265 * XXX variables... */
266 XVideoSetAttribute( p_vout, "XV_BRIGHTNESS", 0.5 );
267 XVideoSetAttribute( p_vout, "XV_CONTRAST", 0.5 );
270 p_vout->p_sys->b_mouse = 1;
272 /* Disable screen saver and return */
273 XVideoDisableScreenSaver( p_vout );
278 /*****************************************************************************
279 * vout_Init: initialize XVideo video thread output method
280 *****************************************************************************/
281 static int vout_Init( vout_thread_t *p_vout )
284 /* FIXME : As of 2001-03-16, XFree4 for MacOS X does not support Xshm. */
285 p_vout->p_sys->b_shm = 0;
287 p_vout->b_need_render = 0;
288 p_vout->p_sys->i_image_width = p_vout->p_sys->i_image_height = 0;
293 /*****************************************************************************
294 * vout_End: terminate XVideo video thread output method
295 *****************************************************************************
296 * Destroy the XvImage. It is called at the end of the thread, but also each
297 * time the image is resized.
298 *****************************************************************************/
299 static void vout_End( vout_thread_t *p_vout )
301 XVideoDestroyShmImage( p_vout, p_vout->p_sys->p_xvimage,
302 &p_vout->p_sys->shm_info );
305 /*****************************************************************************
306 * vout_Destroy: destroy XVideo video thread output method
307 *****************************************************************************
308 * Terminate an output method created by vout_CreateOutputMethod
309 *****************************************************************************/
310 static void vout_Destroy( vout_thread_t *p_vout )
312 /* Enable screen saver */
313 XVideoEnableScreenSaver( p_vout );
316 XUnmapWindow( p_vout->p_sys->p_display, p_vout->p_sys->window );
317 XFreeGC( p_vout->p_sys->p_display, p_vout->p_sys->gc );
318 XDestroyWindow( p_vout->p_sys->p_display, p_vout->p_sys->window );
320 XCloseDisplay( p_vout->p_sys->p_display );
322 /* Destroy structure */
323 free( p_vout->p_sys );
326 /*****************************************************************************
327 * vout_Manage: handle X11 events
328 *****************************************************************************
329 * This function should be called regularly by video output thread. It manages
330 * X11 events and allows window resizing. It returns a non null value on
333 * XXX Should "factor-out" common code in this and the "same" fn in the x11
335 *****************************************************************************/
336 static int vout_Manage( vout_thread_t *p_vout )
338 XEvent xevent; /* X11 event */
339 boolean_t b_gofullscreen; /* user wants full-screen */
340 char i_key; /* ISO Latin-1 key */
345 /* Handle X11 events: ConfigureNotify events are parsed to know if the
346 * output window's size changed, MapNotify and UnmapNotify to know if the
347 * window is mapped (and if the display is useful), and ClientMessages
348 * to intercept window destruction requests */
349 while( XCheckWindowEvent( p_vout->p_sys->p_display, p_vout->p_sys->window,
350 StructureNotifyMask | KeyPressMask |
351 ButtonPressMask | ButtonReleaseMask |
352 PointerMotionMask, &xevent )
355 /* ConfigureNotify event: prepare */
356 if( (xevent.type == ConfigureNotify)
357 /*&& ((xevent.xconfigure.width != p_vout->p_sys->i_window_width)
358 || (xevent.xconfigure.height != p_vout->p_sys->i_window_height))*/ )
360 /* Update dimensions */
361 p_vout->p_sys->i_window_width = xevent.xconfigure.width;
362 p_vout->p_sys->i_window_height = xevent.xconfigure.height;
364 /* MapNotify event: change window status and disable screen saver */
365 else if( xevent.type == MapNotify)
367 if( (p_vout != NULL) && !p_vout->b_active )
369 XVideoDisableScreenSaver( p_vout );
370 p_vout->b_active = 1;
373 /* UnmapNotify event: change window status and enable screen saver */
374 else if( xevent.type == UnmapNotify )
376 if( (p_vout != NULL) && p_vout->b_active )
378 XVideoEnableScreenSaver( p_vout );
379 p_vout->b_active = 0;
383 else if( xevent.type == KeyPress )
385 /* We may have keys like F1 trough F12, ESC ... */
386 x_key_symbol = XKeycodeToKeysym( p_vout->p_sys->p_display,
387 xevent.xkey.keycode, 0 );
388 switch( x_key_symbol )
391 p_main->p_intf->b_die = 1;
394 p_main->p_intf->b_menu_change = 1;
398 * The reason why I use this instead of XK_0 is that
399 * with XLookupString, we don't have to care about
402 if( XLookupString( &xevent.xkey, &i_key, 1, NULL, NULL ) )
408 p_main->p_intf->b_die = 1;
415 network_ChannelJoin( 0 );
418 network_ChannelJoin( 1 );
421 network_ChannelJoin( 2 );
424 network_ChannelJoin( 3 );
427 network_ChannelJoin( 4 );
430 network_ChannelJoin( 5 );
433 network_ChannelJoin( 6 );
436 network_ChannelJoin( 7 );
439 network_ChannelJoin( 8 );
442 network_ChannelJoin( 9 );
445 if( intf_ProcessKey( p_main->p_intf,
448 intf_DbgMsg( "unhandled key '%c' (%i)",
449 (char)i_key, i_key );
458 else if( xevent.type == ButtonPress )
460 switch( ((XButtonEvent *)&xevent)->button )
463 /* in this part we will eventually manage
464 * clicks for DVD navigation for instance */
469 else if( xevent.type == ButtonRelease )
471 switch( ((XButtonEvent *)&xevent)->button )
474 /* FIXME: need locking ! */
475 p_main->p_intf->b_menu_change = 1;
480 else if( xevent.type == MotionNotify )
482 p_vout->p_sys->i_lastmoved = mdate();
483 if( ! p_vout->p_sys->b_mouse )
485 XVideoTogglePointer( p_vout );
493 intf_DbgMsg( "%p -> unhandled event type %d received",
494 p_vout, xevent.type );
499 /* ClientMessage event - only WM_PROTOCOLS with WM_DELETE_WINDOW data
500 * are handled - according to the man pages, the format is always 32
502 while( XCheckTypedEvent( p_vout->p_sys->p_display,
503 ClientMessage, &xevent ) )
505 if( (xevent.xclient.message_type == p_vout->p_sys->wm_protocols)
506 && (xevent.xclient.data.l[0] == p_vout->p_sys->wm_delete_window ) )
508 p_main->p_intf->b_die = 1;
512 intf_DbgMsg( "%p -> unhandled ClientMessage received", p_vout );
516 if ( b_gofullscreen )
519 /* Open display, unsing 'vlc_display' or DISPLAY environment variable */
520 psz_display = XDisplayName( main_GetPszVariable( VOUT_DISPLAY_VAR, NULL ) );
522 intf_DbgMsg( "vout: changing full-screen status" );
524 p_vout->p_sys->b_fullscreen = !p_vout->p_sys->b_fullscreen;
526 /* Get rid of the old window */
527 XUnmapWindow( p_vout->p_sys->p_display, p_vout->p_sys->window );
528 XFreeGC( p_vout->p_sys->p_display, p_vout->p_sys->gc );
530 /* And create a new one */
531 if( XVideoCreateWindow( p_vout ) )
533 intf_ErrMsg( "vout error: cannot create X11 window" );
534 XCloseDisplay( p_vout->p_sys->p_display );
536 free( p_vout->p_sys );
540 /* We've changed the size, update it */
541 p_vout->i_changes |= VOUT_SIZE_CHANGE;
545 if( (p_vout->i_changes & VOUT_GRAYSCALE_CHANGE))
547 /* FIXME: clear flags ?? */
553 if( p_vout->i_changes & VOUT_SIZE_CHANGE )
555 intf_DbgMsg( "vout: resizing window" );
556 p_vout->i_changes &= ~VOUT_SIZE_CHANGE;
557 /* Noting to do here...
558 * vout_Display() detects size changes of the image to be displayed and
559 * re-creates the XvImage.*/
560 intf_Msg( "vout: video display resized (%dx%d)",
561 p_vout->i_width, p_vout->i_height );
564 /* Autohide Cursor */
565 if( p_vout->p_sys->b_mouse &&
566 mdate() - p_vout->p_sys->i_lastmoved > 2000000 )
567 XVideoTogglePointer( p_vout );
572 /*****************************************************************************
573 * XVideoUpdateImgSizeIfRequired
574 *****************************************************************************
575 * This function checks to see if the image to be displayed is of a different
576 * size to the last image displayed. If so, the old shm block must be
577 * destroyed and a new one created.
578 * Note: the "image size" is the size of the image to be passed to the Xv
579 * extension (which is probably different to the size of the output window).
580 *****************************************************************************/
581 static int XVideoUpdateImgSizeIfRequired( vout_thread_t *p_vout )
583 int i_img_width = p_vout->p_rendered_pic->i_width;
584 int i_img_height = p_vout->p_rendered_pic->i_height;
586 if( p_vout->p_sys->i_image_width != i_img_width
587 || p_vout->p_sys->i_image_height != i_img_height )
589 p_vout->p_sys->i_image_width = i_img_width;
590 p_vout->p_sys->i_image_height = i_img_height;
592 /* Destroy XvImage to change its size */
594 /* Note: vout_End does nothing if no XvImage to destroy. */
596 /* Create XvImage using XShm extension */
597 if( XVideoCreateShmImage( p_vout->p_sys->p_display,
598 p_vout->p_sys->xv_port,
599 &p_vout->p_sys->p_xvimage,
600 &p_vout->p_sys->shm_info,
601 i_img_width, i_img_height ) )
603 intf_ErrMsg( "vout: failed to create xvimage." );
604 p_vout->p_sys->i_image_width = 0;
608 /* Set bytes per line and initialize buffers */
609 p_vout->i_bytes_per_line =
610 (p_vout->p_sys->p_xvimage->data_size) /
611 (p_vout->p_sys->p_xvimage->height);
613 /* vout_SetBuffers( p_vout, p_vout->p_sys->p_xvimage->data ); */
618 /*****************************************************************************
619 * vout_Display: displays previously rendered output
620 *****************************************************************************
621 * This function sends the currently rendered image to X11 server.
622 * (The Xv extension takes care of "double-buffering".)
623 *****************************************************************************/
624 static void vout_Display( vout_thread_t *p_vout )
626 boolean_t b_draw = 1;
627 int i_size = p_vout->p_rendered_pic->i_width *
628 p_vout->p_rendered_pic->i_height;
630 if( XVideoUpdateImgSizeIfRequired( p_vout ) )
633 switch( p_vout->p_rendered_pic->i_type )
635 case YUV_422_PICTURE:
636 intf_ErrMsg( "vout error: YUV_422_PICTURE not (yet) supported" );
640 case YUV_444_PICTURE:
641 intf_ErrMsg( "vout error: YUV_444_PICTURE not (yet) supported" );
645 case YUV_420_PICTURE:
646 memcpy( p_vout->p_sys->p_xvimage->data,
647 p_vout->p_rendered_pic->p_y, i_size );
648 memcpy( p_vout->p_sys->p_xvimage->data + ( i_size ),
649 p_vout->p_rendered_pic->p_v, i_size / 4 );
650 memcpy( p_vout->p_sys->p_xvimage->data + ( i_size ) + ( i_size / 4 ),
651 p_vout->p_rendered_pic->p_u, i_size / 4 );
658 i_window_width = p_vout->p_sys->i_window_width,
659 i_window_height = p_vout->p_sys->i_window_height,
660 i_dest_width, i_dest_height, i_dest_x, i_dest_y;
664 /* If I change the line above to "#if 0" I find on resizing the window
665 * that blue rectangles (used to specify where part of the YUV overlay
666 * used to be drawn) may remain around the edge of the video output. */
667 XGetGeometry( p_vout->p_sys->p_display, p_vout->p_sys->window,
668 &window, &i_dummy, &i_dummy,
669 &i_window_width, &i_window_height, &i_dummy, &i_dummy );
672 XVideoOutputCoords( p_vout->p_rendered_pic, p_vout->b_scale,
673 i_window_width, i_window_height,
674 &i_dest_x, &i_dest_y,
675 &i_dest_width, &i_dest_height);
677 XvShmPutImage( p_vout->p_sys->p_display, p_vout->p_sys->xv_port,
678 p_vout->p_sys->window, p_vout->p_sys->gc,
679 p_vout->p_sys->p_xvimage,
680 0 /*src_x*/, 0 /*src_y*/,
681 p_vout->p_rendered_pic->i_width,
682 p_vout->p_rendered_pic->i_height,
683 i_dest_x, i_dest_y, i_dest_width, i_dest_height,
688 static void vout_SetPalette( p_vout_thread_t p_vout,
689 u16 *red, u16 *green, u16 *blue, u16 *transp )
694 /* following functions are local */
696 /*****************************************************************************
697 * XVideoCheckForXv: check for the XVideo extension
698 *****************************************************************************/
699 static int XVideoCheckForXv( Display *dpy )
703 switch( XvQueryExtension( dpy, &i, &i, &i, &i, &i ) )
709 intf_ErrMsg( "vout error: XvBadExtension" );
713 intf_ErrMsg( "vout error: XvBadAlloc" );
717 intf_ErrMsg( "vout error: XvQueryExtension failed" );
722 /*****************************************************************************
723 * XVideoCreateWindow: open and set-up XVideo main window
724 *****************************************************************************/
725 static int XVideoCreateWindow( vout_thread_t *p_vout )
727 XSizeHints xsize_hints;
728 XSetWindowAttributes xwindow_attributes;
735 boolean_t b_configure_notify;
736 boolean_t b_map_notify;
739 /* If we're full screen, we're full screen! */
740 if( p_vout->p_sys->b_fullscreen )
742 p_vout->p_sys->i_window_width = DisplayWidth( p_vout->p_sys->p_display,
743 p_vout->p_sys->i_screen );
744 p_vout->p_sys->i_window_height = DisplayHeight( p_vout->p_sys->p_display,
745 p_vout->p_sys->i_screen );
746 p_vout->i_width = p_vout->p_sys->i_window_width;
747 p_vout->i_height = p_vout->p_sys->i_window_height;
751 /* Set main window's size */
752 p_vout->p_sys->i_window_width = main_GetIntVariable( VOUT_WIDTH_VAR,
753 VOUT_WIDTH_DEFAULT );
754 p_vout->p_sys->i_window_height = main_GetIntVariable( VOUT_HEIGHT_VAR,
755 VOUT_HEIGHT_DEFAULT );
758 /* Prepare window manager hints and properties */
759 xsize_hints.base_width = p_vout->p_sys->i_window_width;
760 xsize_hints.base_height = p_vout->p_sys->i_window_height;
761 xsize_hints.flags = PSize;
762 p_vout->p_sys->wm_protocols = XInternAtom( p_vout->p_sys->p_display,
763 "WM_PROTOCOLS", True );
764 p_vout->p_sys->wm_delete_window = XInternAtom( p_vout->p_sys->p_display,
765 "WM_DELETE_WINDOW", True );
767 /* Prepare window attributes */
768 xwindow_attributes.backing_store = Always; /* save the hidden part */
769 xwindow_attributes.background_pixel = BlackPixel( p_vout->p_sys->p_display,
770 p_vout->p_sys->i_screen );
772 xwindow_attributes.event_mask = ExposureMask | StructureNotifyMask;
774 /* Create the window and set hints - the window must receive ConfigureNotify
775 * events, and, until it is displayed, Expose and MapNotify events. */
776 p_vout->p_sys->window =
777 XCreateWindow( p_vout->p_sys->p_display,
778 DefaultRootWindow( p_vout->p_sys->p_display ),
780 p_vout->p_sys->i_window_width,
781 p_vout->p_sys->i_window_height, 1,
783 CWBackingStore | CWBackPixel | CWEventMask,
784 &xwindow_attributes );
786 if ( p_vout->p_sys->b_fullscreen )
788 prop = XInternAtom(p_vout->p_sys->p_display, "_MOTIF_WM_HINTS", False);
789 mwmhints.flags = MWM_HINTS_DECORATIONS;
790 mwmhints.decorations = 0;
791 XChangeProperty( p_vout->p_sys->p_display, p_vout->p_sys->window,
792 prop, prop, 32, PropModeReplace,
793 (unsigned char *)&mwmhints, PROP_MWM_HINTS_ELEMENTS );
795 XSetTransientForHint( p_vout->p_sys->p_display,
796 p_vout->p_sys->window, None );
797 XRaiseWindow( p_vout->p_sys->p_display, p_vout->p_sys->window );
801 /* Set window manager hints and properties: size hints, command,
802 * window's name, and accepted protocols */
803 XSetWMNormalHints( p_vout->p_sys->p_display, p_vout->p_sys->window,
805 XSetCommand( p_vout->p_sys->p_display, p_vout->p_sys->window,
806 p_main->ppsz_argv, p_main->i_argc );
807 XStoreName( p_vout->p_sys->p_display, p_vout->p_sys->window,
808 VOUT_TITLE " (XVideo output)" );
810 if( (p_vout->p_sys->wm_protocols == None) /* use WM_DELETE_WINDOW */
811 || (p_vout->p_sys->wm_delete_window == None)
812 || !XSetWMProtocols( p_vout->p_sys->p_display, p_vout->p_sys->window,
813 &p_vout->p_sys->wm_delete_window, 1 ) )
815 /* WM_DELETE_WINDOW is not supported by window manager */
816 intf_Msg( "vout error: missing or bad window manager" );
819 /* Creation of a graphic context that doesn't generate a GraphicsExpose
820 * event when using functions like XCopyArea */
821 xgcvalues.graphics_exposures = False;
822 p_vout->p_sys->gc = XCreateGC( p_vout->p_sys->p_display,
823 p_vout->p_sys->window,
824 GCGraphicsExposures, &xgcvalues);
826 /* Send orders to server, and wait until window is displayed - three
827 * events must be received: a MapNotify event, an Expose event allowing
828 * drawing in the window, and a ConfigureNotify to get the window
829 * dimensions. Once those events have been received, only ConfigureNotify
830 * events need to be received. */
832 b_configure_notify = 0;
834 XMapWindow( p_vout->p_sys->p_display, p_vout->p_sys->window);
837 XNextEvent( p_vout->p_sys->p_display, &xevent);
838 if( (xevent.type == Expose)
839 && (xevent.xexpose.window == p_vout->p_sys->window) )
843 else if( (xevent.type == MapNotify)
844 && (xevent.xmap.window == p_vout->p_sys->window) )
848 else if( (xevent.type == ConfigureNotify)
849 && (xevent.xconfigure.window == p_vout->p_sys->window) )
851 b_configure_notify = 1;
852 p_vout->p_sys->i_window_width = xevent.xconfigure.width;
853 p_vout->p_sys->i_window_height = xevent.xconfigure.height;
855 } while( !( b_expose && b_configure_notify && b_map_notify ) );
857 XSelectInput( p_vout->p_sys->p_display, p_vout->p_sys->window,
858 StructureNotifyMask | KeyPressMask |
859 ButtonPressMask | ButtonReleaseMask |
862 if( p_vout->p_sys->b_fullscreen )
864 XSetInputFocus( p_vout->p_sys->p_display, p_vout->p_sys->window,
865 RevertToNone, CurrentTime );
866 XMoveWindow( p_vout->p_sys->p_display, p_vout->p_sys->window, 0, 0 );
869 /* At this stage, the window is open, displayed, and ready to
874 /*****************************************************************************
875 * XVideoCreateShmImage: create an XvImage using shared memory extension
876 *****************************************************************************
877 * Prepare an XvImage for display function.
878 * The order of the operations respects the recommandations of the mit-shm
879 * document by J.Corbet and K.Packard. Most of the parameters were copied from
881 *****************************************************************************/
882 static int XVideoCreateShmImage( Display* dpy, int xv_port,
883 XvImage **pp_xvimage,
884 XShmSegmentInfo *p_shm_info,
885 int i_width, int i_height )
887 *pp_xvimage = XvShmCreateImage( dpy, xv_port,
888 GUID_YUV12_PLANAR, 0,
893 intf_ErrMsg( "vout error: XvShmCreateImage failed." );
897 p_shm_info->shmid = shmget( IPC_PRIVATE, (*pp_xvimage)->data_size,
899 if( p_shm_info->shmid < 0) /* error */
901 intf_ErrMsg( "vout error: cannot allocate shared image data (%s)",
906 p_shm_info->shmaddr = (*pp_xvimage)->data = shmat( p_shm_info->shmid,
908 p_shm_info->readOnly = False;
910 /* Mark the shm segment to be removed when there will be no more
911 * attachements, so it is automatic on process exit or after shmdt */
912 shmctl( p_shm_info->shmid, IPC_RMID, 0 );
914 if( !XShmAttach( dpy, p_shm_info ) )
916 intf_ErrMsg( "vout error: XShmAttach failed" );
917 shmdt( p_shm_info->shmaddr );
921 /* Send image to X server. This instruction is required, since having
922 * built a Shm XImage and not using it causes an error on XCloseDisplay */
928 /*****************************************************************************
929 * XVideoDestroyShmImage
930 *****************************************************************************
931 * Destroy XImage AND associated data. Detach shared memory segment from
932 * server and process, then free it. If pointer is NULL, the image won't be
933 * destroyed (see vout_ManageOutputMethod())
934 *****************************************************************************/
935 static void XVideoDestroyShmImage( vout_thread_t *p_vout, XvImage *p_xvimage,
936 XShmSegmentInfo *p_shm_info )
938 /* If pointer is NULL, do nothing */
939 if( p_xvimage == NULL )
944 XShmDetach( p_vout->p_sys->p_display, p_shm_info );/* detach from server */
946 XDestroyImage( p_ximage ); /* XXX */
949 if( shmdt( p_shm_info->shmaddr ) ) /* detach shared memory from process */
950 { /* also automatic freeing... */
951 intf_ErrMsg( "vout error: cannot detach shared memory (%s)",
956 /*****************************************************************************
957 * XVideoEnableScreenSaver: enable screen saver
958 *****************************************************************************
959 * This function enable the screen saver on a display after it had been
960 * disabled by XDisableScreenSaver. Both functions use a counter mechanism to
961 * know wether the screen saver can be activated or not: if n successive calls
962 * are made to XDisableScreenSaver, n successive calls to XEnableScreenSaver
963 * will be required before the screen saver could effectively be activated.
964 *****************************************************************************/
965 void XVideoEnableScreenSaver( vout_thread_t *p_vout )
967 intf_DbgMsg( "intf: enabling screen saver" );
968 XSetScreenSaver( p_vout->p_sys->p_display, p_vout->p_sys->i_ss_timeout,
969 p_vout->p_sys->i_ss_interval,
970 p_vout->p_sys->i_ss_blanking,
971 p_vout->p_sys->i_ss_exposure );
974 /*****************************************************************************
975 * XVideoDisableScreenSaver: disable screen saver
976 *****************************************************************************
977 * See XEnableScreenSaver
978 *****************************************************************************/
979 void XVideoDisableScreenSaver( vout_thread_t *p_vout )
981 /* Save screen saver informations */
982 XGetScreenSaver( p_vout->p_sys->p_display, &p_vout->p_sys->i_ss_timeout,
983 &p_vout->p_sys->i_ss_interval,
984 &p_vout->p_sys->i_ss_blanking,
985 &p_vout->p_sys->i_ss_exposure );
987 /* Disable screen saver */
988 intf_DbgMsg( "intf: disabling screen saver" );
989 XSetScreenSaver( p_vout->p_sys->p_display, 0,
990 p_vout->p_sys->i_ss_interval,
991 p_vout->p_sys->i_ss_blanking,
992 p_vout->p_sys->i_ss_exposure );
995 /*****************************************************************************
996 * XVideoTogglePointer: hide or show the mouse pointer
997 *****************************************************************************
998 * This function hides the X pointer if it is visible by putting it at
999 * coordinates (32,32) and setting the pointer sprite to a blank one. To
1000 * show it again, we disable the sprite and restore the original coordinates.
1001 *****************************************************************************/
1002 void XVideoTogglePointer( vout_thread_t *p_vout )
1004 static Cursor cursor;
1005 static boolean_t b_cursor = 0;
1007 if( p_vout->p_sys->b_mouse )
1009 p_vout->p_sys->b_mouse = 0;
1014 Pixmap blank = XCreatePixmap( p_vout->p_sys->p_display,
1015 DefaultRootWindow(p_vout->p_sys->p_display),
1018 XParseColor( p_vout->p_sys->p_display,
1019 XCreateColormap( p_vout->p_sys->p_display,
1021 p_vout->p_sys->p_display ),
1023 p_vout->p_sys->p_display,
1024 p_vout->p_sys->i_screen ),
1028 cursor = XCreatePixmapCursor( p_vout->p_sys->p_display,
1029 blank, blank, &color, &color, 1, 1 );
1033 XDefineCursor( p_vout->p_sys->p_display,
1034 p_vout->p_sys->window, cursor );
1038 p_vout->p_sys->b_mouse = 1;
1040 XUndefineCursor( p_vout->p_sys->p_display, p_vout->p_sys->window );
1044 /* This based on some code in SetBufferPicture... At the moment it's only
1045 * used by the xvideo plugin, but others may want to use it. */
1046 static void XVideoOutputCoords( const picture_t *p_pic, const boolean_t scale,
1047 const int win_w, const int win_h,
1048 int *dx, int *dy, int *w, int *h)
1052 *w = p_pic->i_width; *h = p_pic->i_height;
1057 switch( p_pic->i_aspect_ratio )
1059 case AR_3_4_PICTURE: *h = win_w * 3 / 4; break;
1060 case AR_16_9_PICTURE: *h = win_w * 9 / 16; break;
1061 case AR_221_1_PICTURE: *h = win_w * 100 / 221; break;
1062 case AR_SQUARE_PICTURE:
1063 default: *h = win_w; break;
1069 switch( p_pic->i_aspect_ratio )
1071 case AR_3_4_PICTURE: *w = win_h * 4 / 3; break;
1072 case AR_16_9_PICTURE: *w = win_h * 16 / 9; break;
1073 case AR_221_1_PICTURE: *w = win_h * 221 / 100; break;
1074 case AR_SQUARE_PICTURE:
1075 default: *w = win_h; break;
1080 /* Set picture position */
1081 *dx = (win_w - *w) / 2;
1082 *dy = (win_h - *h) / 2;
1086 static int XVideoGetPort( Display *dpy )
1090 XvAdaptorInfo *adaptor_info;
1092 switch( XvQueryAdaptors( dpy, DefaultRootWindow( dpy ),
1093 &i_adaptors, &adaptor_info ) )
1098 case XvBadExtension:
1099 intf_ErrMsg( "vout error: XvBadExtension for XvQueryAdaptors" );
1103 intf_ErrMsg( "vout error: XvBadAlloc for XvQueryAdaptors" );
1107 intf_ErrMsg( "vout error: XvQueryAdaptors failed" );
1111 for( i=0; i < i_adaptors && xv_port == -1; ++i )
1112 if( ( adaptor_info[ i ].type & XvInputMask ) &&
1113 ( adaptor_info[ i ].type & XvImageMask ) )
1115 /* check that port supports YUV12 planar format... */
1116 int port = adaptor_info[ i ].base_id;
1117 int i_num_formats, i;
1118 XvImageFormatValues *imageFormats;
1120 imageFormats = XvListImageFormats( dpy, port, &i_num_formats );
1122 for( i=0; i < i_num_formats && xv_port == -1; ++i )
1123 if( imageFormats[ i ].id == GUID_YUV12_PLANAR )
1127 intf_WarnMsg( 3, "vout: XVideo image input port %d "
1128 "does not support the YUV12 planar format which is "
1129 "currently required by the xvideo output plugin.",
1133 XFree( imageFormats );
1136 if( i_adaptors > 0 )
1137 XvFreeAdaptorInfo(adaptor_info);
1140 intf_ErrMsg( "vout error: didn't find a suitable Xvideo image input port." );
1147 /*****************************************************************************
1148 * XVideoSetAttribute
1149 *****************************************************************************
1150 * This function can be used to set attributes, e.g. XV_BRIGHTNESS and
1151 * XV_CONTRAST. "f_value" should be in the range of 0 to 1.
1152 *****************************************************************************/
1153 static void XVideoSetAttribute( vout_thread_t *p_vout,
1154 char *attr_name, float f_value )
1157 XvAttribute *p_attrib;
1158 Display *p_dpy = p_vout->p_sys->p_display;
1159 int xv_port = p_vout->p_sys->xv_port;
1161 p_attrib = XvQueryPortAttributes( p_dpy, xv_port, &i_attrib );
1167 if( i_attrib >= 0 && !strcmp( p_attrib[ i_attrib ].name, attr_name ) )
1169 int i_sv = f_value * ( p_attrib[ i_attrib ].max_value
1170 - p_attrib[ i_attrib ].min_value + 1 )
1171 + p_attrib[ i_attrib ].min_value;
1173 XvSetPortAttribute( p_dpy, xv_port,
1174 XInternAtom( p_dpy, attr_name, False ), i_sv );
1178 } while( i_attrib > 0 );