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.23 2001/07/30 18:56:36 gbazin 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 */
47 #include <netinet/in.h> /* BSD: struct in_addr */
50 #include <sys/shm.h> /* shmget(), shmctl() */
52 #include <X11/Xutil.h>
53 #include <X11/keysym.h>
54 #include <X11/extensions/XShm.h>
55 #include <X11/extensions/Xv.h>
56 #include <X11/extensions/Xvlib.h>
65 #include "video_output.h"
67 #include "interface.h"
70 #include "netutils.h" /* network_ChannelJoin */
74 #include "stream_control.h" /* needed by input_ext-intf.h... */
75 #include "input_ext-intf.h"
78 #include "modules_export.h"
80 #define GUID_YUV12_PLANAR 0x32315659
83 /*****************************************************************************
84 * vout_sys_t: video output X11 method descriptor
85 *****************************************************************************
86 * This structure is part of the video output thread descriptor.
87 * It describes the XVideo specific properties of an output thread.
88 *****************************************************************************/
89 typedef struct vout_sys_s
93 /* this plugin (currently) requires the SHM Ext... */
94 boolean_t b_shm; /* shared memory extension flag */
97 /* Internal settings and properties */
98 Display * p_display; /* display pointer */
99 int i_screen; /* screen number */
100 Window window; /* root window */
101 GC gc; /* graphic context instance handler */
102 Window yuv_window; /* sub-window for displaying yuv video
107 /* Display buffers and shared memory information */
108 /* Note: only 1 buffer... Xv ext does double buffering. */
112 /* i_image_width & i_image_height reflect the
113 * size of the XvImage. They are used by
114 * vout_Display() to check if the image to be
115 * displayed can use the current XvImage. */
116 XShmSegmentInfo shm_info; /* shared memory zone information */
118 /* X11 generic properties */
120 Atom wm_delete_window;
122 int i_window_width; /* width of main window */
123 int i_window_height; /* height of main window */
126 /* Screen saver properties */
127 int i_ss_timeout; /* timeout */
128 int i_ss_interval; /* interval between changes */
129 int i_ss_blanking; /* blanking mode */
130 int i_ss_exposure; /* exposure mode */
132 /* Mouse pointer properties */
133 boolean_t b_mouse_pointer_visible;
134 mtime_t i_time_mouse_last_moved; /* used to auto-hide pointer*/
138 /* Fullscreen needs to be able to hide the wm decorations */
139 #define MWM_HINTS_DECORATIONS (1L << 1)
140 #define PROP_MWM_HINTS_ELEMENTS 5
141 typedef struct mwmhints_s
150 /*****************************************************************************
152 *****************************************************************************/
153 static int vout_Probe ( probedata_t * );
154 static int vout_Create ( vout_thread_t * );
155 static int vout_Init ( vout_thread_t * );
156 static void vout_End ( vout_thread_t * );
157 static void vout_Destroy ( vout_thread_t * );
158 static int vout_Manage ( vout_thread_t * );
159 static void vout_Display ( vout_thread_t * );
160 static void vout_SetPalette( vout_thread_t *, u16 *, u16 *, u16 *, u16 * );
162 static int XVideoCreateWindow ( vout_thread_t * );
163 static void XVideoDestroyWindow ( vout_thread_t *p_vout );
164 static int XVideoUpdateImgSizeIfRequired( vout_thread_t *p_vout );
165 static int XVideoCreateShmImage ( Display* dpy, int xv_port,
166 XvImage **pp_xvimage,
167 XShmSegmentInfo *p_shm_info,
168 int i_width, int i_height );
169 static void XVideoDestroyShmImage ( vout_thread_t *, XvImage *,
171 static void XVideoSetMousePointer ( const vout_thread_t * );
172 static void XVideoEnableScreenSaver ( vout_thread_t * );
173 static void XVideoDisableScreenSaver ( vout_thread_t * );
174 /*static void XVideoSetAttribute ( vout_thread_t *, char *, float );*/
176 static int XVideoCheckForXv ( Display * );
177 static int XVideoGetPort ( Display * );
178 static void XVideoOutputCoords ( const picture_t *, const boolean_t,
179 const int, const int,
180 int *, int *, int *, int * );
181 static void XVideoDisplay ( vout_thread_t * );
183 /*****************************************************************************
184 * Functions exported as capabilities. They are declared as static so that
185 * we don't pollute the namespace too much.
186 *****************************************************************************/
187 void _M( vout_getfunctions )( function_list_t * p_function_list )
189 p_function_list->pf_probe = vout_Probe;
190 p_function_list->functions.vout.pf_create = vout_Create;
191 p_function_list->functions.vout.pf_init = vout_Init;
192 p_function_list->functions.vout.pf_end = vout_End;
193 p_function_list->functions.vout.pf_destroy = vout_Destroy;
194 p_function_list->functions.vout.pf_manage = vout_Manage;
195 p_function_list->functions.vout.pf_display = vout_Display;
196 p_function_list->functions.vout.pf_setpalette = vout_SetPalette;
199 /*****************************************************************************
200 * vout_Probe: probe the video driver and return a score
201 *****************************************************************************
202 * This returns a score to the plugin manager so that it can select the best
204 *****************************************************************************/
205 static int vout_Probe( probedata_t *p_data )
207 Display *p_display; /* display pointer */
210 /* Open display, unsing 'vlc_display' or DISPLAY environment variable */
211 psz_display = XDisplayName( main_GetPszVariable(VOUT_DISPLAY_VAR, NULL) );
212 p_display = XOpenDisplay( psz_display );
213 if( p_display == NULL ) /* error */
215 intf_WarnMsg( 3, "vout: Xvideo cannot open display %s", psz_display );
216 intf_WarnMsg( 3, "vout: Xvideo not supported" );
220 if( !XVideoCheckForXv( p_display ) )
222 intf_WarnMsg( 3, "vout: Xvideo not supported" );
223 XCloseDisplay( p_display );
227 if( XVideoGetPort( p_display ) < 0 )
229 intf_WarnMsg( 3, "vout: Xvideo not supported" );
230 XCloseDisplay( p_display );
234 /* Clean-up everyting */
235 XCloseDisplay( p_display );
237 if( TestMethod( VOUT_METHOD_VAR, "xvideo" ) )
245 /*****************************************************************************
246 * vout_Create: allocate XVideo video thread output method
247 *****************************************************************************
248 * This function allocate and initialize a XVideo vout method. It uses some of
249 * the vout properties to choose the window size, and change them according to
250 * the actual properties of the display.
251 *****************************************************************************/
252 static int vout_Create( vout_thread_t *p_vout )
256 /* Allocate structure */
257 p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
258 if( p_vout->p_sys == NULL )
260 intf_ErrMsg( "vout error: %s", strerror(ENOMEM) );
264 /* Open display, unsing 'vlc_display' or DISPLAY environment variable */
265 psz_display = XDisplayName( main_GetPszVariable( VOUT_DISPLAY_VAR, NULL ) );
266 p_vout->p_sys->p_display = XOpenDisplay( psz_display );
268 if( p_vout->p_sys->p_display == NULL ) /* error */
270 intf_ErrMsg( "vout error: cannot open display %s", psz_display );
271 free( p_vout->p_sys );
274 p_vout->p_sys->i_screen = DefaultScreen( p_vout->p_sys->p_display );
277 = main_GetIntVariable( VOUT_FULLSCREEN_VAR, VOUT_FULLSCREEN_DEFAULT );
279 if( !XVideoCheckForXv( p_vout->p_sys->p_display ) )
281 intf_ErrMsg( "vout error: no XVideo extension" );
282 XCloseDisplay( p_vout->p_sys->p_display );
283 free( p_vout->p_sys );
287 /* Spawn base window - this window will include the video output window,
288 * but also command buttons, subtitles and other indicators */
289 if( XVideoCreateWindow( p_vout ) )
291 intf_ErrMsg( "vout error: cannot create XVideo window" );
292 XCloseDisplay( p_vout->p_sys->p_display );
293 free( p_vout->p_sys );
297 if( (p_vout->p_sys->xv_port = XVideoGetPort( p_vout->p_sys->p_display ))<0 )
299 intf_ErrMsg( "vout error: cannot get XVideo port" );
300 XVideoDestroyWindow( p_vout );
301 XCloseDisplay( p_vout->p_sys->p_display );
302 free( p_vout->p_sys );
305 intf_DbgMsg( "Using xv port %d" , p_vout->p_sys->xv_port );
308 /* XXX The brightness and contrast values should be read from environment
309 * XXX variables... */
310 XVideoSetAttribute( p_vout, "XV_BRIGHTNESS", 0.5 );
311 XVideoSetAttribute( p_vout, "XV_CONTRAST", 0.5 );
314 p_vout->p_sys->b_mouse_pointer_visible = 1;
316 /* Disable screen saver and return */
317 XVideoDisableScreenSaver( p_vout );
322 /*****************************************************************************
323 * vout_Init: initialize XVideo video thread output method
324 *****************************************************************************/
325 static int vout_Init( vout_thread_t *p_vout )
328 /* FIXME : As of 2001-03-16, XFree4 for MacOS X does not support Xshm. */
329 p_vout->p_sys->b_shm = 0;
331 p_vout->b_need_render = 0;
332 p_vout->p_sys->i_image_width = p_vout->p_sys->i_image_height = 0;
337 /*****************************************************************************
338 * vout_End: terminate XVideo video thread output method
339 *****************************************************************************
340 * Destroy the XvImage. It is called at the end of the thread, but also each
341 * time the image is resized.
342 *****************************************************************************/
343 static void vout_End( vout_thread_t *p_vout )
345 XVideoDestroyShmImage( p_vout, p_vout->p_sys->p_xvimage,
346 &p_vout->p_sys->shm_info );
349 /*****************************************************************************
350 * vout_Destroy: destroy XVideo video thread output method
351 *****************************************************************************
352 * Terminate an output method created by vout_Create
353 *****************************************************************************/
354 static void vout_Destroy( vout_thread_t *p_vout )
356 XVideoEnableScreenSaver( p_vout );
357 XVideoDestroyWindow( p_vout );
358 XCloseDisplay( p_vout->p_sys->p_display );
360 /* Destroy structure */
361 free( p_vout->p_sys );
364 /*****************************************************************************
365 * vout_Manage: handle X11 events
366 *****************************************************************************
367 * This function should be called regularly by video output thread. It manages
368 * X11 events and allows window resizing. It returns a non null value on
371 * XXX Should "factor-out" common code in this and the "same" fn in the x11
373 *****************************************************************************/
374 static int vout_Manage( vout_thread_t *p_vout )
376 XEvent xevent; /* X11 event */
377 char i_key; /* ISO Latin-1 key */
380 /* Handle X11 events: ConfigureNotify events are parsed to know if the
381 * output window's size changed, MapNotify and UnmapNotify to know if the
382 * window is mapped (and if the display is useful), and ClientMessages
383 * to intercept window destruction requests */
384 while( XCheckWindowEvent( p_vout->p_sys->p_display, p_vout->p_sys->window,
385 StructureNotifyMask | KeyPressMask |
386 ButtonPressMask | ButtonReleaseMask |
387 PointerMotionMask, &xevent )
390 /* ConfigureNotify event: prepare */
391 if( (xevent.type == ConfigureNotify)
392 /*&& ((xevent.xconfigure.width != p_vout->p_sys->i_window_width)
393 || (xevent.xconfigure.height != p_vout->p_sys->i_window_height))*/ )
395 /* Update dimensions */
396 p_vout->p_sys->i_window_width = xevent.xconfigure.width;
397 p_vout->p_sys->i_window_height = xevent.xconfigure.height;
399 /* MapNotify event: change window status and disable screen saver */
400 else if( xevent.type == MapNotify)
402 if( (p_vout != NULL) && !p_vout->b_active )
404 XVideoDisableScreenSaver( p_vout );
405 p_vout->b_active = 1;
408 /* UnmapNotify event: change window status and enable screen saver */
409 else if( xevent.type == UnmapNotify )
411 if( (p_vout != NULL) && p_vout->b_active )
413 XVideoEnableScreenSaver( p_vout );
414 p_vout->b_active = 0;
418 else if( xevent.type == KeyPress )
420 /* We may have keys like F1 trough F12, ESC ... */
421 x_key_symbol = XKeycodeToKeysym( p_vout->p_sys->p_display,
422 xevent.xkey.keycode, 0 );
423 switch( x_key_symbol )
426 p_main->p_intf->b_die = 1;
429 p_main->p_intf->b_menu_change = 1;
433 * The reason why I use this instead of XK_0 is that
434 * with XLookupString, we don't have to care about
437 if( XLookupString( &xevent.xkey, &i_key, 1, NULL, NULL ) )
443 p_main->p_intf->b_die = 1;
447 p_vout->i_changes |= VOUT_FULLSCREEN_CHANGE;
450 network_ChannelJoin( 0 );
453 network_ChannelJoin( 1 );
456 network_ChannelJoin( 2 );
459 network_ChannelJoin( 3 );
462 network_ChannelJoin( 4 );
465 network_ChannelJoin( 5 );
468 network_ChannelJoin( 6 );
471 network_ChannelJoin( 7 );
474 network_ChannelJoin( 8 );
477 network_ChannelJoin( 9 );
480 if( intf_ProcessKey( p_main->p_intf,
483 intf_DbgMsg( "unhandled key '%c' (%i)",
484 (char)i_key, i_key );
493 else if( xevent.type == ButtonPress )
495 switch( ((XButtonEvent *)&xevent)->button )
498 /* in this part we will eventually manage
499 * clicks for DVD navigation for instance */
504 else if( xevent.type == ButtonRelease )
506 switch( ((XButtonEvent *)&xevent)->button )
509 /* FIXME: need locking ! */
510 p_main->p_intf->b_menu_change = 1;
515 else if( xevent.type == MotionNotify )
517 p_vout->p_sys->i_time_mouse_last_moved = mdate();
518 p_vout->p_sys->b_mouse_pointer_visible = 1;
519 XVideoSetMousePointer( p_vout );
524 intf_WarnMsg( 3, "%p -> unhandled event type %d received",
525 p_vout, xevent.type );
529 /* Handle events for YUV video output sub-window */
530 while( XCheckWindowEvent( p_vout->p_sys->p_display,
531 p_vout->p_sys->yuv_window,
532 ExposureMask, &xevent ) == True )
534 /* Window exposed (only handled if stream playback is paused) */
535 if( xevent.type == Expose )
537 if( ((XExposeEvent *)&xevent)->count == 0 )
538 /* (if this is the last a collection of expose events...) */
539 if( p_main->p_intf->p_input )
541 p_main->p_intf->p_input->stream.control.i_status )
542 XVideoDisplay( p_vout );
546 /* ClientMessage event - only WM_PROTOCOLS with WM_DELETE_WINDOW data
547 * are handled - according to the man pages, the format is always 32
549 while( XCheckTypedEvent( p_vout->p_sys->p_display,
550 ClientMessage, &xevent ) )
552 if( (xevent.xclient.message_type == p_vout->p_sys->wm_protocols)
553 && (xevent.xclient.data.l[0] == p_vout->p_sys->wm_delete_window ) )
555 p_main->p_intf->b_die = 1;
559 intf_DbgMsg( "%p -> unhandled ClientMessage received", p_vout );
563 if ( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE )
565 intf_DbgMsg( "vout: changing full-screen status" );
567 p_vout->b_fullscreen = !p_vout->b_fullscreen;
569 /* Get rid of the old window */
570 XVideoDestroyWindow( p_vout );
572 /* And create a new one */
573 if( XVideoCreateWindow( p_vout ) )
575 intf_ErrMsg( "vout error: cannot create X11 window" );
576 XCloseDisplay( p_vout->p_sys->p_display );
578 free( p_vout->p_sys );
584 if( (p_vout->i_changes & VOUT_GRAYSCALE_CHANGE))
586 /* FIXME: clear flags ?? */
592 if( p_vout->i_changes & VOUT_SIZE_CHANGE )
594 intf_DbgMsg( "vout: resizing window" );
595 p_vout->i_changes &= ~VOUT_SIZE_CHANGE;
596 /* Nothing to do here...
597 * vout_Display() detects size changes of the image to be displayed and
598 * re-creates the XvImage.*/
599 intf_Msg( "vout: video display resized (%dx%d)",
600 p_vout->i_width, p_vout->i_height );
603 /* Autohide Cursor */
604 if( p_vout->p_sys->b_mouse_pointer_visible &&
605 mdate() - p_vout->p_sys->i_time_mouse_last_moved > 2000000 )
607 p_vout->p_sys->b_mouse_pointer_visible = 0;
608 XVideoSetMousePointer( p_vout );
614 /*****************************************************************************
615 * vout_Display: displays previously rendered output
616 *****************************************************************************
617 * This function sends the currently rendered image to X11 server.
618 * (The Xv extension takes care of "double-buffering".)
619 *****************************************************************************/
620 static void vout_Display( vout_thread_t *p_vout )
622 boolean_t b_draw = 1;
623 int i_size = p_vout->p_rendered_pic->i_width *
624 p_vout->p_rendered_pic->i_height;
626 if( XVideoUpdateImgSizeIfRequired( p_vout ) )
631 switch( p_vout->p_rendered_pic->i_type )
633 case YUV_422_PICTURE:
634 intf_ErrMsg( "vout error: YUV_422_PICTURE not (yet) supported" );
638 case YUV_444_PICTURE:
639 intf_ErrMsg( "vout error: YUV_444_PICTURE not (yet) supported" );
643 case YUV_420_PICTURE:
644 memcpy( p_vout->p_sys->p_xvimage->data,
645 p_vout->p_rendered_pic->p_y, i_size );
646 memcpy( p_vout->p_sys->p_xvimage->data + ( i_size ),
647 p_vout->p_rendered_pic->p_v, i_size / 4 );
648 memcpy( p_vout->p_sys->p_xvimage->data + ( i_size ) + ( i_size / 4 ),
649 p_vout->p_rendered_pic->p_u, i_size / 4 );
655 XVideoDisplay( p_vout );
659 static void vout_SetPalette( p_vout_thread_t p_vout,
660 u16 *red, u16 *green, u16 *blue, u16 *transp )
665 /* following functions are local */
667 /*****************************************************************************
668 * XVideoUpdateImgSizeIfRequired
669 *****************************************************************************
670 * This function checks to see if the image to be displayed is of a different
671 * size to the last image displayed. If so, the old shm block must be
672 * destroyed and a new one created.
673 * Note: the "image size" is the size of the image to be passed to the Xv
674 * extension (which is probably different to the size of the output window).
675 *****************************************************************************/
676 static int XVideoUpdateImgSizeIfRequired( vout_thread_t *p_vout )
678 int i_img_width = p_vout->p_rendered_pic->i_width;
679 int i_img_height = p_vout->p_rendered_pic->i_height;
681 if( p_vout->p_sys->i_image_width != i_img_width
682 || p_vout->p_sys->i_image_height != i_img_height )
684 if( p_vout->p_sys->i_image_width != 0
685 && p_vout->p_sys->i_image_height != 0 )
687 /* Destroy XvImage to change its size */
691 p_vout->p_sys->i_image_width = i_img_width;
692 p_vout->p_sys->i_image_height = i_img_height;
694 /* Create XvImage using XShm extension */
695 if( XVideoCreateShmImage( p_vout->p_sys->p_display,
696 p_vout->p_sys->xv_port,
697 &p_vout->p_sys->p_xvimage,
698 &p_vout->p_sys->shm_info,
699 i_img_width, i_img_height ) )
701 intf_ErrMsg( "vout: failed to create xvimage." );
702 p_vout->p_sys->i_image_width = 0;
706 /* Set bytes per line and initialize buffers */
707 p_vout->i_bytes_per_line =
708 (p_vout->p_sys->p_xvimage->data_size) /
709 (p_vout->p_sys->p_xvimage->height);
711 /* p_vout->pf_setbuffers( p_vout, p_vout->p_sys->p_xvimage->data ); */
717 /*****************************************************************************
718 * XVideoCheckForXv: check for the XVideo extension
719 *****************************************************************************/
720 static int XVideoCheckForXv( Display *dpy )
724 switch( XvQueryExtension( dpy, &i, &i, &i, &i, &i ) )
730 intf_WarnMsg( 3, "vout error: XvBadExtension" );
734 intf_WarnMsg( 3, "vout error: XvBadAlloc" );
738 intf_WarnMsg( 3, "vout error: XvQueryExtension failed" );
743 /*****************************************************************************
744 * XVideoCreateWindow: open and set-up XVideo main window
745 *****************************************************************************/
746 static int XVideoCreateWindow( vout_thread_t *p_vout )
748 XSizeHints xsize_hints;
749 XSetWindowAttributes xwindow_attributes;
756 boolean_t b_configure_notify;
757 boolean_t b_map_notify;
760 /* Set main window's size */
761 /* If we're full screen, we're full screen! */
762 if( p_vout->b_fullscreen )
764 p_vout->p_sys->i_window_width = DisplayWidth( p_vout->p_sys->p_display,
765 p_vout->p_sys->i_screen );
766 p_vout->p_sys->i_window_height = DisplayHeight( p_vout->p_sys->p_display,
767 p_vout->p_sys->i_screen );
768 /* p_vout->i_width = p_vout->p_sys->i_window_width;
769 p_vout->i_height = p_vout->p_sys->i_window_height; */
773 p_vout->p_sys->i_window_width = main_GetIntVariable( VOUT_WIDTH_VAR,
774 VOUT_WIDTH_DEFAULT );
775 p_vout->p_sys->i_window_height = main_GetIntVariable( VOUT_HEIGHT_VAR,
776 VOUT_HEIGHT_DEFAULT );
779 /* Prepare window manager hints and properties */
780 xsize_hints.base_width = p_vout->p_sys->i_window_width;
781 xsize_hints.base_height = p_vout->p_sys->i_window_height;
782 xsize_hints.flags = PSize;
783 p_vout->p_sys->wm_protocols = XInternAtom( p_vout->p_sys->p_display,
784 "WM_PROTOCOLS", True );
785 p_vout->p_sys->wm_delete_window = XInternAtom( p_vout->p_sys->p_display,
786 "WM_DELETE_WINDOW", True );
788 /* Prepare window attributes */
789 xwindow_attributes.background_pixel = BlackPixel( p_vout->p_sys->p_display,
790 p_vout->p_sys->i_screen );
792 xwindow_attributes.event_mask = ExposureMask | StructureNotifyMask;
794 /* Create the window and set hints - the window must receive ConfigureNotify
795 * events, and, until it is displayed, Expose and MapNotify events. */
796 p_vout->p_sys->window =
797 XCreateWindow( p_vout->p_sys->p_display,
798 DefaultRootWindow( p_vout->p_sys->p_display ),
800 p_vout->p_sys->i_window_width,
801 p_vout->p_sys->i_window_height, 1,
803 CWBackPixel | CWEventMask,
804 &xwindow_attributes );
806 if ( p_vout->b_fullscreen )
808 prop = XInternAtom(p_vout->p_sys->p_display, "_MOTIF_WM_HINTS", False);
809 mwmhints.flags = MWM_HINTS_DECORATIONS;
810 mwmhints.decorations = 0;
811 XChangeProperty( p_vout->p_sys->p_display, p_vout->p_sys->window,
812 prop, prop, 32, PropModeReplace,
813 (unsigned char *)&mwmhints, PROP_MWM_HINTS_ELEMENTS );
815 XSetTransientForHint( p_vout->p_sys->p_display,
816 p_vout->p_sys->window, None );
817 XRaiseWindow( p_vout->p_sys->p_display, p_vout->p_sys->window );
821 /* Set window manager hints and properties: size hints, command,
822 * window's name, and accepted protocols */
823 XSetWMNormalHints( p_vout->p_sys->p_display, p_vout->p_sys->window,
825 XSetCommand( p_vout->p_sys->p_display, p_vout->p_sys->window,
826 p_main->ppsz_argv, p_main->i_argc );
827 XStoreName( p_vout->p_sys->p_display, p_vout->p_sys->window,
828 VOUT_TITLE " (XVideo output)" );
830 if( (p_vout->p_sys->wm_protocols == None) /* use WM_DELETE_WINDOW */
831 || (p_vout->p_sys->wm_delete_window == None)
832 || !XSetWMProtocols( p_vout->p_sys->p_display, p_vout->p_sys->window,
833 &p_vout->p_sys->wm_delete_window, 1 ) )
835 /* WM_DELETE_WINDOW is not supported by window manager */
836 intf_Msg( "vout error: missing or bad window manager" );
839 /* Creation of a graphic context that doesn't generate a GraphicsExpose
840 * event when using functions like XCopyArea */
841 xgcvalues.graphics_exposures = False;
842 p_vout->p_sys->gc = XCreateGC( p_vout->p_sys->p_display,
843 p_vout->p_sys->window,
844 GCGraphicsExposures, &xgcvalues);
846 /* Send orders to server, and wait until window is displayed - three
847 * events must be received: a MapNotify event, an Expose event allowing
848 * drawing in the window, and a ConfigureNotify to get the window
849 * dimensions. Once those events have been received, only ConfigureNotify
850 * events need to be received. */
852 b_configure_notify = 0;
854 XMapWindow( p_vout->p_sys->p_display, p_vout->p_sys->window);
857 XNextEvent( p_vout->p_sys->p_display, &xevent);
858 if( (xevent.type == Expose)
859 && (xevent.xexpose.window == p_vout->p_sys->window) )
863 else if( (xevent.type == MapNotify)
864 && (xevent.xmap.window == p_vout->p_sys->window) )
868 else if( (xevent.type == ConfigureNotify)
869 && (xevent.xconfigure.window == p_vout->p_sys->window) )
871 b_configure_notify = 1;
872 p_vout->p_sys->i_window_width = xevent.xconfigure.width;
873 p_vout->p_sys->i_window_height = xevent.xconfigure.height;
875 } while( !( b_expose && b_configure_notify && b_map_notify ) );
877 XSelectInput( p_vout->p_sys->p_display, p_vout->p_sys->window,
878 StructureNotifyMask | KeyPressMask |
879 ButtonPressMask | ButtonReleaseMask |
882 if( p_vout->b_fullscreen )
884 XSetInputFocus( p_vout->p_sys->p_display, p_vout->p_sys->window,
885 RevertToNone, CurrentTime );
886 XMoveWindow( p_vout->p_sys->p_display, p_vout->p_sys->window, 0, 0 );
889 /* Create YUV output sub-window. */
890 p_vout->p_sys->yuv_window=XCreateSimpleWindow( p_vout->p_sys->p_display,
891 p_vout->p_sys->window, 0, 0, 1, 1, 0,
892 BlackPixel( p_vout->p_sys->p_display,
893 p_vout->p_sys->i_screen ),
894 WhitePixel( p_vout->p_sys->p_display,
895 p_vout->p_sys->i_screen ) );
897 p_vout->p_sys->yuv_gc = XCreateGC( p_vout->p_sys->p_display,
898 p_vout->p_sys->yuv_window,
899 GCGraphicsExposures, &xgcvalues );
901 XSetWindowBackground( p_vout->p_sys->p_display, p_vout->p_sys->yuv_window,
902 BlackPixel(p_vout->p_sys->p_display, p_vout->p_sys->i_screen ) );
904 XMapWindow( p_vout->p_sys->p_display, p_vout->p_sys->yuv_window );
905 XSelectInput( p_vout->p_sys->p_display, p_vout->p_sys->yuv_window,
909 XVideoSetMousePointer( p_vout );
914 static void XVideoDestroyWindow( vout_thread_t *p_vout )
916 XFreeGC( p_vout->p_sys->p_display, p_vout->p_sys->yuv_gc );
917 XDestroyWindow( p_vout->p_sys->p_display, p_vout->p_sys->yuv_window );
919 XUnmapWindow( p_vout->p_sys->p_display, p_vout->p_sys->window );
920 XFreeGC( p_vout->p_sys->p_display, p_vout->p_sys->gc );
921 XDestroyWindow( p_vout->p_sys->p_display, p_vout->p_sys->window );
924 /*****************************************************************************
925 * XVideoCreateShmImage: create an XvImage using shared memory extension
926 *****************************************************************************
927 * Prepare an XvImage for display function.
928 * The order of the operations respects the recommandations of the mit-shm
929 * document by J.Corbet and K.Packard. Most of the parameters were copied from
931 *****************************************************************************/
932 static int XVideoCreateShmImage( Display* dpy, int xv_port,
933 XvImage **pp_xvimage,
934 XShmSegmentInfo *p_shm_info,
935 int i_width, int i_height )
937 *pp_xvimage = XvShmCreateImage( dpy, xv_port,
938 GUID_YUV12_PLANAR, 0,
943 intf_ErrMsg( "vout error: XvShmCreateImage failed." );
947 p_shm_info->shmid = shmget( IPC_PRIVATE, (*pp_xvimage)->data_size,
949 if( p_shm_info->shmid < 0) /* error */
951 intf_ErrMsg( "vout error: cannot allocate shared image data (%s)",
956 p_shm_info->shmaddr = (*pp_xvimage)->data = shmat( p_shm_info->shmid,
958 p_shm_info->readOnly = False;
961 /* Mark the shm segment to be removed when there will be no more
962 * attachements, so it is automatic on process exit or after shmdt */
963 shmctl( p_shm_info->shmid, IPC_RMID, 0 );
966 if( !XShmAttach( dpy, p_shm_info ) )
968 intf_ErrMsg( "vout error: XShmAttach failed" );
969 shmctl( p_shm_info->shmid, IPC_RMID, 0 );
970 shmdt( p_shm_info->shmaddr );
974 /* Send image to X server. This instruction is required, since having
975 * built a Shm XImage and not using it causes an error on XCloseDisplay */
981 /*****************************************************************************
982 * XVideoDestroyShmImage
983 *****************************************************************************
984 * Destroy XImage AND associated data. Detach shared memory segment from
985 * server and process, then free it. If pointer is NULL, the image won't be
986 * destroyed (see vout_ManageOutputMethod())
987 *****************************************************************************/
988 static void XVideoDestroyShmImage( vout_thread_t *p_vout, XvImage *p_xvimage,
989 XShmSegmentInfo *p_shm_info )
991 /* If pointer is NULL, do nothing */
992 if( p_xvimage == NULL )
997 XShmDetach( p_vout->p_sys->p_display, p_shm_info );/* detach from server */
999 XDestroyImage( p_ximage ); /* XXX */
1002 shmctl( p_shm_info->shmid, IPC_RMID, 0 );
1004 if( shmdt( p_shm_info->shmaddr ) ) /* detach shared memory from process */
1006 intf_ErrMsg( "vout error: cannot detach shared memory (%s)",
1011 /*****************************************************************************
1012 * XVideoEnableScreenSaver: enable screen saver
1013 *****************************************************************************
1014 * This function enable the screen saver on a display after it had been
1015 * disabled by XDisableScreenSaver. Both functions use a counter mechanism to
1016 * know wether the screen saver can be activated or not: if n successive calls
1017 * are made to XDisableScreenSaver, n successive calls to XEnableScreenSaver
1018 * will be required before the screen saver could effectively be activated.
1019 *****************************************************************************/
1020 void XVideoEnableScreenSaver( vout_thread_t *p_vout )
1022 intf_DbgMsg( "intf: enabling screen saver" );
1023 XSetScreenSaver( p_vout->p_sys->p_display, p_vout->p_sys->i_ss_timeout,
1024 p_vout->p_sys->i_ss_interval,
1025 p_vout->p_sys->i_ss_blanking,
1026 p_vout->p_sys->i_ss_exposure );
1029 /*****************************************************************************
1030 * XVideoDisableScreenSaver: disable screen saver
1031 *****************************************************************************
1032 * See XEnableScreenSaver
1033 *****************************************************************************/
1034 void XVideoDisableScreenSaver( vout_thread_t *p_vout )
1036 /* Save screen saver informations */
1037 XGetScreenSaver( p_vout->p_sys->p_display, &p_vout->p_sys->i_ss_timeout,
1038 &p_vout->p_sys->i_ss_interval,
1039 &p_vout->p_sys->i_ss_blanking,
1040 &p_vout->p_sys->i_ss_exposure );
1042 /* Disable screen saver */
1043 intf_DbgMsg( "intf: disabling screen saver" );
1044 XSetScreenSaver( p_vout->p_sys->p_display, 0,
1045 p_vout->p_sys->i_ss_interval,
1046 p_vout->p_sys->i_ss_blanking,
1047 p_vout->p_sys->i_ss_exposure );
1050 /*****************************************************************************
1051 * XVideoSetMousePointer: hide or show the mouse pointer
1052 *****************************************************************************
1053 * This function hides the X pointer if requested.
1054 *****************************************************************************/
1055 void XVideoSetMousePointer( const vout_thread_t *p_vout )
1057 static Cursor blank_cursor;
1058 static boolean_t b_created_blank_cursor = 0;
1060 if( !p_vout->p_sys->b_mouse_pointer_visible )
1062 if( !b_created_blank_cursor )
1065 Pixmap blank = XCreatePixmap( p_vout->p_sys->p_display,
1066 DefaultRootWindow(p_vout->p_sys->p_display),
1069 XParseColor( p_vout->p_sys->p_display,
1070 XCreateColormap( p_vout->p_sys->p_display,
1072 p_vout->p_sys->p_display ),
1074 p_vout->p_sys->p_display,
1075 p_vout->p_sys->i_screen ),
1079 blank_cursor = XCreatePixmapCursor( p_vout->p_sys->p_display,
1080 blank, blank, &color, &color, 1, 1 );
1082 b_created_blank_cursor = 1;
1084 XDefineCursor( p_vout->p_sys->p_display,
1085 p_vout->p_sys->window, blank_cursor );
1089 XUndefineCursor( p_vout->p_sys->p_display, p_vout->p_sys->window );
1093 /* This based on some code in SetBufferPicture... At the moment it's only
1094 * used by the xvideo plugin, but others may want to use it. */
1095 static void XVideoOutputCoords( const picture_t *p_pic, const boolean_t scale,
1096 const int win_w, const int win_h,
1097 int *dx, int *dy, int *w, int *h)
1101 *w = p_pic->i_width; *h = p_pic->i_height;
1106 switch( p_pic->i_aspect_ratio )
1108 case AR_3_4_PICTURE:
1112 case AR_16_9_PICTURE:
1113 *h = win_w * 9 / 16;
1116 case AR_221_1_PICTURE:
1117 *h = win_w * 100 / 221;
1120 case AR_SQUARE_PICTURE:
1122 *h = win_w * p_pic->i_height / p_pic->i_width;
1129 switch( p_pic->i_aspect_ratio )
1131 case AR_3_4_PICTURE:
1135 case AR_16_9_PICTURE:
1136 *w = win_h * 16 / 9;
1139 case AR_221_1_PICTURE:
1140 *w = win_h * 221 / 100;
1143 case AR_SQUARE_PICTURE:
1145 *w = win_h * p_pic->i_width / p_pic->i_height;
1151 /* Set picture position */
1152 *dx = (win_w - *w) / 2;
1153 *dy = (win_h - *h) / 2;
1157 static int XVideoGetPort( Display *dpy )
1161 XvAdaptorInfo *adaptor_info;
1163 switch( XvQueryAdaptors( dpy, DefaultRootWindow( dpy ),
1164 &i_adaptors, &adaptor_info ) )
1169 case XvBadExtension:
1170 intf_WarnMsg( 3, "vout error: XvBadExtension for XvQueryAdaptors" );
1174 intf_WarnMsg( 3, "vout error: XvBadAlloc for XvQueryAdaptors" );
1178 intf_WarnMsg( 3, "vout error: XvQueryAdaptors failed" );
1182 for( i=0; i < i_adaptors && xv_port == -1; ++i )
1184 if( ( adaptor_info[ i ].type & XvInputMask ) &&
1185 ( adaptor_info[ i ].type & XvImageMask ) )
1187 /* check that port supports YUV12 planar format... */
1188 int port = adaptor_info[ i ].base_id;
1189 int i_num_formats, i;
1190 XvImageFormatValues *imageFormats;
1192 imageFormats = XvListImageFormats( dpy, port, &i_num_formats );
1194 for( i=0; i < i_num_formats && xv_port == -1; ++i )
1196 if( imageFormats[ i ].id == GUID_YUV12_PLANAR )
1204 intf_WarnMsg( 3, "vout: XVideo image input port %d "
1205 "does not support the YUV12 planar format which is "
1206 "currently required by the xvideo output plugin",
1212 XFree( imageFormats );
1217 if( i_adaptors > 0 )
1219 XvFreeAdaptorInfo(adaptor_info);
1224 intf_WarnMsg( 3, "vout: no suitable Xvideo image input port" );
1231 /*****************************************************************************
1232 * XVideoDisplay: display image
1233 *****************************************************************************
1234 * This function displays the image stored in p_vout->p_sys->p_xvimage.
1235 * The image is scaled to fit in the output window (and to have the correct
1237 *****************************************************************************/
1238 static void XVideoDisplay( vout_thread_t *p_vout )
1240 int i_dest_width, i_dest_height, i_dest_x, i_dest_y;
1242 if( !p_vout->p_sys->p_xvimage )
1247 XVideoOutputCoords( p_vout->p_rendered_pic, p_vout->b_scale,
1248 p_vout->p_sys->i_window_width,
1249 p_vout->p_sys->i_window_height,
1250 &i_dest_x, &i_dest_y,
1251 &i_dest_width, &i_dest_height);
1253 XvShmPutImage( p_vout->p_sys->p_display, p_vout->p_sys->xv_port,
1254 p_vout->p_sys->yuv_window, p_vout->p_sys->gc,
1255 p_vout->p_sys->p_xvimage,
1256 0 /*src_x*/, 0 /*src_y*/,
1257 p_vout->p_rendered_pic->i_width,
1258 p_vout->p_rendered_pic->i_height,
1259 0 /*dest_x*/, 0 /*dest_y*/, i_dest_width, i_dest_height,
1262 XResizeWindow( p_vout->p_sys->p_display, p_vout->p_sys->yuv_window,
1263 i_dest_width, i_dest_height );
1264 XMoveWindow( p_vout->p_sys->p_display, p_vout->p_sys->yuv_window,
1265 i_dest_x, i_dest_y );
1267 /* Send the order to the X server */
1268 XSync( p_vout->p_sys->p_display, False );
1272 /*****************************************************************************
1273 * XVideoSetAttribute
1274 *****************************************************************************
1275 * This function can be used to set attributes, e.g. XV_BRIGHTNESS and
1276 * XV_CONTRAST. "f_value" should be in the range of 0 to 1.
1277 *****************************************************************************/
1278 static void XVideoSetAttribute( vout_thread_t *p_vout,
1279 char *attr_name, float f_value )
1282 XvAttribute *p_attrib;
1283 Display *p_dpy = p_vout->p_sys->p_display;
1284 int xv_port = p_vout->p_sys->xv_port;
1286 p_attrib = XvQueryPortAttributes( p_dpy, xv_port, &i_attrib );
1292 if( i_attrib >= 0 && !strcmp( p_attrib[ i_attrib ].name, attr_name ) )
1294 int i_sv = f_value * ( p_attrib[ i_attrib ].max_value
1295 - p_attrib[ i_attrib ].min_value + 1 )
1296 + p_attrib[ i_attrib ].min_value;
1298 XvSetPortAttribute( p_dpy, xv_port,
1299 XInternAtom( p_dpy, attr_name, False ), i_sv );
1303 } while( i_attrib > 0 );