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.26 2001/08/22 14:23:57 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 */
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*/
135 Cursor blank_cursor; /* the hidden cursor */
136 Pixmap cursor_pixmap;
140 /* Fullscreen needs to be able to hide the wm decorations */
141 #define MWM_HINTS_DECORATIONS (1L << 1)
142 #define PROP_MWM_HINTS_ELEMENTS 5
143 typedef struct mwmhints_s
152 /*****************************************************************************
154 *****************************************************************************/
155 static int vout_Probe ( probedata_t * );
156 static int vout_Create ( vout_thread_t * );
157 static int vout_Init ( vout_thread_t * );
158 static void vout_End ( vout_thread_t * );
159 static void vout_Destroy ( vout_thread_t * );
160 static int vout_Manage ( vout_thread_t * );
161 static void vout_Display ( vout_thread_t * );
162 static void vout_SetPalette( vout_thread_t *, u16 *, u16 *, u16 *, u16 * );
164 static int XVideoCreateWindow ( vout_thread_t * );
165 static void XVideoDestroyWindow ( vout_thread_t *p_vout );
166 static int XVideoUpdateImgSizeIfRequired( vout_thread_t *p_vout );
167 static int XVideoCreateShmImage ( Display* dpy, int xv_port,
168 XvImage **pp_xvimage,
169 XShmSegmentInfo *p_shm_info,
170 int i_width, int i_height );
171 static void XVideoDestroyShmImage ( vout_thread_t *, XvImage *,
173 static void X11ToggleMousePointer ( vout_thread_t * );
174 static void XVideoEnableScreenSaver ( vout_thread_t * );
175 static void XVideoDisableScreenSaver ( vout_thread_t * );
176 /*static void XVideoSetAttribute ( vout_thread_t *, char *, float );*/
178 static int XVideoCheckForXv ( Display * );
179 static int XVideoGetPort ( Display * );
180 static void XVideoOutputCoords ( const picture_t *, const boolean_t,
181 const int, const int,
182 int *, int *, int *, int * );
183 static void XVideoDisplay ( vout_thread_t * );
185 /*****************************************************************************
186 * Functions exported as capabilities. They are declared as static so that
187 * we don't pollute the namespace too much.
188 *****************************************************************************/
189 void _M( vout_getfunctions )( function_list_t * p_function_list )
191 p_function_list->pf_probe = vout_Probe;
192 p_function_list->functions.vout.pf_create = vout_Create;
193 p_function_list->functions.vout.pf_init = vout_Init;
194 p_function_list->functions.vout.pf_end = vout_End;
195 p_function_list->functions.vout.pf_destroy = vout_Destroy;
196 p_function_list->functions.vout.pf_manage = vout_Manage;
197 p_function_list->functions.vout.pf_display = vout_Display;
198 p_function_list->functions.vout.pf_setpalette = vout_SetPalette;
201 /*****************************************************************************
202 * vout_Probe: probe the video driver and return a score
203 *****************************************************************************
204 * This returns a score to the plugin manager so that it can select the best
206 *****************************************************************************/
207 static int vout_Probe( probedata_t *p_data )
209 Display *p_display; /* display pointer */
212 /* Open display, unsing 'vlc_display' or DISPLAY environment variable */
213 psz_display = XDisplayName( main_GetPszVariable(VOUT_DISPLAY_VAR, NULL) );
214 p_display = XOpenDisplay( psz_display );
215 if( p_display == NULL ) /* error */
217 intf_WarnMsg( 3, "vout: Xvideo cannot open display %s", psz_display );
218 intf_WarnMsg( 3, "vout: Xvideo not supported" );
222 if( !XVideoCheckForXv( p_display ) )
224 intf_WarnMsg( 3, "vout: Xvideo not supported" );
225 XCloseDisplay( p_display );
229 if( XVideoGetPort( p_display ) < 0 )
231 intf_WarnMsg( 3, "vout: Xvideo not supported" );
232 XCloseDisplay( p_display );
236 /* Clean-up everyting */
237 XCloseDisplay( p_display );
239 if( TestMethod( VOUT_METHOD_VAR, "xvideo" ) )
247 /*****************************************************************************
248 * vout_Create: allocate XVideo video thread output method
249 *****************************************************************************
250 * This function allocate and initialize a XVideo vout method. It uses some of
251 * the vout properties to choose the window size, and change them according to
252 * the actual properties of the display.
253 *****************************************************************************/
254 static int vout_Create( vout_thread_t *p_vout )
259 /* Allocate structure */
260 p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
261 if( p_vout->p_sys == NULL )
263 intf_ErrMsg( "vout error: %s", strerror(ENOMEM) );
267 /* Open display, unsing 'vlc_display' or DISPLAY environment variable */
268 psz_display = XDisplayName( main_GetPszVariable( VOUT_DISPLAY_VAR, NULL ) );
269 p_vout->p_sys->p_display = XOpenDisplay( psz_display );
271 if( p_vout->p_sys->p_display == NULL ) /* error */
273 intf_ErrMsg( "vout error: cannot open display %s", psz_display );
274 free( p_vout->p_sys );
277 p_vout->p_sys->i_screen = DefaultScreen( p_vout->p_sys->p_display );
280 = main_GetIntVariable( VOUT_FULLSCREEN_VAR, VOUT_FULLSCREEN_DEFAULT );
282 if( !XVideoCheckForXv( p_vout->p_sys->p_display ) )
284 intf_ErrMsg( "vout error: no XVideo extension" );
285 XCloseDisplay( p_vout->p_sys->p_display );
286 free( p_vout->p_sys );
290 /* Check we have access to a video port */
291 if( (p_vout->p_sys->xv_port = XVideoGetPort(p_vout->p_sys->p_display)) <0 )
293 intf_ErrMsg( "vout error: cannot get XVideo port" );
294 XCloseDisplay( p_vout->p_sys->p_display );
295 free( p_vout->p_sys );
298 intf_DbgMsg( "Using xv port %d" , p_vout->p_sys->xv_port );
300 /* Create blank cursor (for mouse cursor autohiding) */
301 p_vout->p_sys->b_mouse_pointer_visible = 1;
302 p_vout->p_sys->cursor_pixmap = XCreatePixmap( p_vout->p_sys->p_display,
304 p_vout->p_sys->p_display),
307 XParseColor( p_vout->p_sys->p_display,
308 XCreateColormap( p_vout->p_sys->p_display,
310 p_vout->p_sys->p_display ),
312 p_vout->p_sys->p_display,
313 p_vout->p_sys->i_screen ),
315 "black", &cursor_color );
317 p_vout->p_sys->blank_cursor = XCreatePixmapCursor(
318 p_vout->p_sys->p_display,
319 p_vout->p_sys->cursor_pixmap,
320 p_vout->p_sys->cursor_pixmap,
322 &cursor_color, 1, 1 );
324 /* Spawn base window - this window will include the video output window,
325 * but also command buttons, subtitles and other indicators */
326 if( XVideoCreateWindow( p_vout ) )
328 intf_ErrMsg( "vout error: cannot create XVideo window" );
329 XCloseDisplay( p_vout->p_sys->p_display );
330 free( p_vout->p_sys );
334 /* p_vout->pf_setbuffers( p_vout, NULL, NULL ); */
337 /* XXX The brightness and contrast values should be read from environment
338 * XXX variables... */
339 XVideoSetAttribute( p_vout, "XV_BRIGHTNESS", 0.5 );
340 XVideoSetAttribute( p_vout, "XV_CONTRAST", 0.5 );
343 /* Disable screen saver and return */
344 XVideoDisableScreenSaver( p_vout );
349 /*****************************************************************************
350 * vout_Init: initialize XVideo video thread output method
351 *****************************************************************************/
352 static int vout_Init( vout_thread_t *p_vout )
355 /* FIXME : As of 2001-03-16, XFree4 for MacOS X does not support Xshm. */
356 p_vout->p_sys->b_shm = 0;
358 p_vout->b_need_render = 0;
359 p_vout->p_sys->i_image_width = p_vout->p_sys->i_image_height = 0;
364 /*****************************************************************************
365 * vout_End: terminate XVideo video thread output method
366 *****************************************************************************
367 * Destroy the XvImage. It is called at the end of the thread, but also each
368 * time the image is resized.
369 *****************************************************************************/
370 static void vout_End( vout_thread_t *p_vout )
372 XVideoDestroyShmImage( p_vout, p_vout->p_sys->p_xvimage,
373 &p_vout->p_sys->shm_info );
376 /*****************************************************************************
377 * vout_Destroy: destroy XVideo video thread output method
378 *****************************************************************************
379 * Terminate an output method created by vout_Create
380 *****************************************************************************/
381 static void vout_Destroy( vout_thread_t *p_vout )
383 /* Restore cursor if it was blanked */
384 if( !p_vout->p_sys->b_mouse_pointer_visible )
385 X11ToggleMousePointer( p_vout );
387 /* Destroy blank cursor pixmap */
388 XFreePixmap( p_vout->p_sys->p_display, p_vout->p_sys->cursor_pixmap );
390 XVideoEnableScreenSaver( p_vout );
391 XVideoDestroyWindow( p_vout );
392 XCloseDisplay( p_vout->p_sys->p_display );
394 /* Destroy structure */
395 free( p_vout->p_sys );
398 /*****************************************************************************
399 * vout_Manage: handle X11 events
400 *****************************************************************************
401 * This function should be called regularly by video output thread. It manages
402 * X11 events and allows window resizing. It returns a non null value on
405 * XXX Should "factor-out" common code in this and the "same" fn in the x11
407 *****************************************************************************/
408 static int vout_Manage( vout_thread_t *p_vout )
410 XEvent xevent; /* X11 event */
411 char i_key; /* ISO Latin-1 key */
414 /* Handle X11 events: ConfigureNotify events are parsed to know if the
415 * output window's size changed, MapNotify and UnmapNotify to know if the
416 * window is mapped (and if the display is useful), and ClientMessages
417 * to intercept window destruction requests */
418 while( XCheckWindowEvent( p_vout->p_sys->p_display, p_vout->p_sys->window,
419 StructureNotifyMask | KeyPressMask |
420 ButtonPressMask | ButtonReleaseMask |
421 PointerMotionMask, &xevent )
424 /* ConfigureNotify event: prepare */
425 if( (xevent.type == ConfigureNotify)
426 /*&& ((xevent.xconfigure.width != p_vout->p_sys->i_window_width)
427 || (xevent.xconfigure.height != p_vout->p_sys->i_window_height))*/ )
429 /* Update dimensions */
430 p_vout->p_sys->i_window_width = xevent.xconfigure.width;
431 p_vout->p_sys->i_window_height = xevent.xconfigure.height;
433 /* MapNotify event: change window status and disable screen saver */
434 else if( xevent.type == MapNotify)
436 if( (p_vout != NULL) && !p_vout->b_active )
438 XVideoDisableScreenSaver( p_vout );
439 p_vout->b_active = 1;
442 /* UnmapNotify event: change window status and enable screen saver */
443 else if( xevent.type == UnmapNotify )
445 if( (p_vout != NULL) && p_vout->b_active )
447 XVideoEnableScreenSaver( p_vout );
448 p_vout->b_active = 0;
452 else if( xevent.type == KeyPress )
454 /* We may have keys like F1 trough F12, ESC ... */
455 x_key_symbol = XKeycodeToKeysym( p_vout->p_sys->p_display,
456 xevent.xkey.keycode, 0 );
457 switch( x_key_symbol )
460 p_main->p_intf->b_die = 1;
463 p_main->p_intf->b_menu_change = 1;
467 * The reason why I use this instead of XK_0 is that
468 * with XLookupString, we don't have to care about
471 if( XLookupString( &xevent.xkey, &i_key, 1, NULL, NULL ) )
477 p_main->p_intf->b_die = 1;
481 p_vout->i_changes |= VOUT_FULLSCREEN_CHANGE;
484 network_ChannelJoin( 0 );
487 network_ChannelJoin( 1 );
490 network_ChannelJoin( 2 );
493 network_ChannelJoin( 3 );
496 network_ChannelJoin( 4 );
499 network_ChannelJoin( 5 );
502 network_ChannelJoin( 6 );
505 network_ChannelJoin( 7 );
508 network_ChannelJoin( 8 );
511 network_ChannelJoin( 9 );
514 if( intf_ProcessKey( p_main->p_intf,
517 intf_DbgMsg( "unhandled key '%c' (%i)",
518 (char)i_key, i_key );
527 else if( xevent.type == ButtonPress )
529 switch( ((XButtonEvent *)&xevent)->button )
532 /* in this part we will eventually manage
533 * clicks for DVD navigation for instance */
538 else if( xevent.type == ButtonRelease )
540 switch( ((XButtonEvent *)&xevent)->button )
543 /* FIXME: need locking ! */
544 p_main->p_intf->b_menu_change = 1;
549 else if( xevent.type == MotionNotify )
551 p_vout->p_sys->i_time_mouse_last_moved = mdate();
552 if( !p_vout->p_sys->b_mouse_pointer_visible )
553 X11ToggleMousePointer( p_vout );
558 intf_WarnMsg( 3, "%p -> unhandled event type %d received",
559 p_vout, xevent.type );
563 /* Handle events for YUV video output sub-window */
564 while( XCheckWindowEvent( p_vout->p_sys->p_display,
565 p_vout->p_sys->yuv_window,
566 ExposureMask, &xevent ) == True )
568 /* Window exposed (only handled if stream playback is paused) */
569 if( xevent.type == Expose )
571 if( ((XExposeEvent *)&xevent)->count == 0 )
572 /* (if this is the last a collection of expose events...) */
573 if( p_main->p_intf->p_input )
575 p_main->p_intf->p_input->stream.control.i_status )
576 XVideoDisplay( p_vout );
580 /* ClientMessage event - only WM_PROTOCOLS with WM_DELETE_WINDOW data
581 * are handled - according to the man pages, the format is always 32
583 while( XCheckTypedEvent( p_vout->p_sys->p_display,
584 ClientMessage, &xevent ) )
586 if( (xevent.xclient.message_type == p_vout->p_sys->wm_protocols)
587 && (xevent.xclient.data.l[0] == p_vout->p_sys->wm_delete_window ) )
589 p_main->p_intf->b_die = 1;
593 intf_DbgMsg( "%p -> unhandled ClientMessage received", p_vout );
597 if ( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE )
599 intf_DbgMsg( "vout: changing full-screen status" );
601 p_vout->b_fullscreen = !p_vout->b_fullscreen;
603 /* Get rid of the old window */
604 XVideoDestroyWindow( p_vout );
606 /* And create a new one */
607 if( XVideoCreateWindow( p_vout ) )
609 intf_ErrMsg( "vout error: cannot create X11 window" );
610 XCloseDisplay( p_vout->p_sys->p_display );
612 free( p_vout->p_sys );
618 if( (p_vout->i_changes & VOUT_GRAYSCALE_CHANGE))
620 /* FIXME: clear flags ?? */
626 if( p_vout->i_changes & VOUT_SIZE_CHANGE )
628 intf_DbgMsg( "vout: resizing window" );
629 p_vout->i_changes &= ~VOUT_SIZE_CHANGE;
630 /* Nothing to do here...
631 * vout_Display() detects size changes of the image to be displayed and
632 * re-creates the XvImage.*/
633 intf_Msg( "vout: video display resized (%dx%d)",
634 p_vout->i_width, p_vout->i_height );
637 /* Autohide Cursor */
638 if( p_vout->p_sys->b_mouse_pointer_visible &&
639 mdate() - p_vout->p_sys->i_time_mouse_last_moved > 2000000 )
641 X11ToggleMousePointer( p_vout );
647 /*****************************************************************************
648 * vout_Display: displays previously rendered output
649 *****************************************************************************
650 * This function sends the currently rendered image to X11 server.
651 * (The Xv extension takes care of "double-buffering".)
652 *****************************************************************************/
653 static void vout_Display( vout_thread_t *p_vout )
655 boolean_t b_draw = 1;
656 int i_size = p_vout->p_rendered_pic->i_width *
657 p_vout->p_rendered_pic->i_height;
659 if( XVideoUpdateImgSizeIfRequired( p_vout ) )
664 switch( p_vout->p_rendered_pic->i_type )
666 case YUV_422_PICTURE:
667 intf_ErrMsg( "vout error: YUV_422_PICTURE not (yet) supported" );
671 case YUV_444_PICTURE:
672 intf_ErrMsg( "vout error: YUV_444_PICTURE not (yet) supported" );
676 case YUV_420_PICTURE:
677 memcpy( p_vout->p_sys->p_xvimage->data,
678 p_vout->p_rendered_pic->p_y, i_size );
679 memcpy( p_vout->p_sys->p_xvimage->data + ( i_size ),
680 p_vout->p_rendered_pic->p_v, i_size / 4 );
681 memcpy( p_vout->p_sys->p_xvimage->data + ( i_size ) + ( i_size / 4 ),
682 p_vout->p_rendered_pic->p_u, i_size / 4 );
688 XVideoDisplay( p_vout );
692 static void vout_SetPalette( p_vout_thread_t p_vout,
693 u16 *red, u16 *green, u16 *blue, u16 *transp )
698 /* following functions are local */
700 /*****************************************************************************
701 * XVideoUpdateImgSizeIfRequired
702 *****************************************************************************
703 * This function checks to see if the image to be displayed is of a different
704 * size to the last image displayed. If so, the old shm block must be
705 * destroyed and a new one created.
706 * Note: the "image size" is the size of the image to be passed to the Xv
707 * extension (which is probably different to the size of the output window).
708 *****************************************************************************/
709 static int XVideoUpdateImgSizeIfRequired( vout_thread_t *p_vout )
711 int i_img_width = p_vout->p_rendered_pic->i_width;
712 int i_img_height = p_vout->p_rendered_pic->i_height;
714 if( p_vout->p_sys->i_image_width != i_img_width
715 || p_vout->p_sys->i_image_height != i_img_height )
717 if( p_vout->p_sys->i_image_width != 0
718 && p_vout->p_sys->i_image_height != 0 )
720 /* Destroy XvImage to change its size */
724 p_vout->p_sys->i_image_width = i_img_width;
725 p_vout->p_sys->i_image_height = i_img_height;
727 /* Create XvImage using XShm extension */
728 if( XVideoCreateShmImage( p_vout->p_sys->p_display,
729 p_vout->p_sys->xv_port,
730 &p_vout->p_sys->p_xvimage,
731 &p_vout->p_sys->shm_info,
732 i_img_width, i_img_height ) )
734 intf_ErrMsg( "vout: failed to create xvimage." );
735 p_vout->p_sys->i_image_width = 0;
739 /* Set bytes per line and initialize buffers */
740 p_vout->i_bytes_per_line =
741 (p_vout->p_sys->p_xvimage->data_size) /
742 (p_vout->p_sys->p_xvimage->height);
749 /*****************************************************************************
750 * XVideoCheckForXv: check for the XVideo extension
751 *****************************************************************************/
752 static int XVideoCheckForXv( Display *dpy )
756 switch( XvQueryExtension( dpy, &i, &i, &i, &i, &i ) )
762 intf_WarnMsg( 3, "vout error: XvBadExtension" );
766 intf_WarnMsg( 3, "vout error: XvBadAlloc" );
770 intf_WarnMsg( 3, "vout error: XvQueryExtension failed" );
775 /*****************************************************************************
776 * XVideoCreateWindow: open and set-up XVideo main window
777 *****************************************************************************/
778 static int XVideoCreateWindow( vout_thread_t *p_vout )
780 XSizeHints xsize_hints;
781 XSetWindowAttributes xwindow_attributes;
788 boolean_t b_configure_notify;
789 boolean_t b_map_notify;
792 /* Set main window's size */
793 /* If we're full screen, we're full screen! */
794 if( p_vout->b_fullscreen )
796 p_vout->p_sys->i_window_width = DisplayWidth( p_vout->p_sys->p_display,
797 p_vout->p_sys->i_screen );
798 p_vout->p_sys->i_window_height = DisplayHeight( p_vout->p_sys->p_display,
799 p_vout->p_sys->i_screen );
800 /* p_vout->i_width = p_vout->p_sys->i_window_width;
801 p_vout->i_height = p_vout->p_sys->i_window_height; */
805 p_vout->p_sys->i_window_width = main_GetIntVariable( VOUT_WIDTH_VAR,
806 VOUT_WIDTH_DEFAULT );
807 p_vout->p_sys->i_window_height = main_GetIntVariable( VOUT_HEIGHT_VAR,
808 VOUT_HEIGHT_DEFAULT );
811 /* Prepare window manager hints and properties */
812 xsize_hints.base_width = p_vout->p_sys->i_window_width;
813 xsize_hints.base_height = p_vout->p_sys->i_window_height;
814 xsize_hints.flags = PSize;
815 p_vout->p_sys->wm_protocols = XInternAtom( p_vout->p_sys->p_display,
816 "WM_PROTOCOLS", True );
817 p_vout->p_sys->wm_delete_window = XInternAtom( p_vout->p_sys->p_display,
818 "WM_DELETE_WINDOW", True );
820 /* Prepare window attributes */
821 xwindow_attributes.background_pixel = BlackPixel( p_vout->p_sys->p_display,
822 p_vout->p_sys->i_screen );
824 xwindow_attributes.event_mask = ExposureMask | StructureNotifyMask;
826 /* Create the window and set hints - the window must receive ConfigureNotify
827 * events, and, until it is displayed, Expose and MapNotify events. */
828 p_vout->p_sys->window =
829 XCreateWindow( p_vout->p_sys->p_display,
830 DefaultRootWindow( p_vout->p_sys->p_display ),
832 p_vout->p_sys->i_window_width,
833 p_vout->p_sys->i_window_height, 1,
835 CWBackPixel | CWEventMask,
836 &xwindow_attributes );
838 if ( p_vout->b_fullscreen )
840 prop = XInternAtom(p_vout->p_sys->p_display, "_MOTIF_WM_HINTS", False);
841 mwmhints.flags = MWM_HINTS_DECORATIONS;
842 mwmhints.decorations = 0;
843 XChangeProperty( p_vout->p_sys->p_display, p_vout->p_sys->window,
844 prop, prop, 32, PropModeReplace,
845 (unsigned char *)&mwmhints, PROP_MWM_HINTS_ELEMENTS );
847 XSetTransientForHint( p_vout->p_sys->p_display,
848 p_vout->p_sys->window, None );
849 XRaiseWindow( p_vout->p_sys->p_display, p_vout->p_sys->window );
853 /* Set window manager hints and properties: size hints, command,
854 * window's name, and accepted protocols */
855 XSetWMNormalHints( p_vout->p_sys->p_display, p_vout->p_sys->window,
857 XSetCommand( p_vout->p_sys->p_display, p_vout->p_sys->window,
858 p_main->ppsz_argv, p_main->i_argc );
859 XStoreName( p_vout->p_sys->p_display, p_vout->p_sys->window,
860 VOUT_TITLE " (XVideo output)" );
862 if( (p_vout->p_sys->wm_protocols == None) /* use WM_DELETE_WINDOW */
863 || (p_vout->p_sys->wm_delete_window == None)
864 || !XSetWMProtocols( p_vout->p_sys->p_display, p_vout->p_sys->window,
865 &p_vout->p_sys->wm_delete_window, 1 ) )
867 /* WM_DELETE_WINDOW is not supported by window manager */
868 intf_Msg( "vout error: missing or bad window manager" );
871 /* Creation of a graphic context that doesn't generate a GraphicsExpose
872 * event when using functions like XCopyArea */
873 xgcvalues.graphics_exposures = False;
874 p_vout->p_sys->gc = XCreateGC( p_vout->p_sys->p_display,
875 p_vout->p_sys->window,
876 GCGraphicsExposures, &xgcvalues);
878 /* Send orders to server, and wait until window is displayed - three
879 * events must be received: a MapNotify event, an Expose event allowing
880 * drawing in the window, and a ConfigureNotify to get the window
881 * dimensions. Once those events have been received, only ConfigureNotify
882 * events need to be received. */
884 b_configure_notify = 0;
886 XMapWindow( p_vout->p_sys->p_display, p_vout->p_sys->window);
889 XNextEvent( p_vout->p_sys->p_display, &xevent);
890 if( (xevent.type == Expose)
891 && (xevent.xexpose.window == p_vout->p_sys->window) )
895 else if( (xevent.type == MapNotify)
896 && (xevent.xmap.window == p_vout->p_sys->window) )
900 else if( (xevent.type == ConfigureNotify)
901 && (xevent.xconfigure.window == p_vout->p_sys->window) )
903 b_configure_notify = 1;
904 p_vout->p_sys->i_window_width = xevent.xconfigure.width;
905 p_vout->p_sys->i_window_height = xevent.xconfigure.height;
907 } while( !( b_expose && b_configure_notify && b_map_notify ) );
909 XSelectInput( p_vout->p_sys->p_display, p_vout->p_sys->window,
910 StructureNotifyMask | KeyPressMask |
911 ButtonPressMask | ButtonReleaseMask |
914 if( p_vout->b_fullscreen )
916 XSetInputFocus( p_vout->p_sys->p_display, p_vout->p_sys->window,
917 RevertToNone, CurrentTime );
918 XMoveWindow( p_vout->p_sys->p_display, p_vout->p_sys->window, 0, 0 );
921 /* Create YUV output sub-window. */
922 p_vout->p_sys->yuv_window=XCreateSimpleWindow( p_vout->p_sys->p_display,
923 p_vout->p_sys->window, 0, 0, 1, 1, 0,
924 BlackPixel( p_vout->p_sys->p_display,
925 p_vout->p_sys->i_screen ),
926 WhitePixel( p_vout->p_sys->p_display,
927 p_vout->p_sys->i_screen ) );
929 p_vout->p_sys->yuv_gc = XCreateGC( p_vout->p_sys->p_display,
930 p_vout->p_sys->yuv_window,
931 GCGraphicsExposures, &xgcvalues );
933 XSetWindowBackground( p_vout->p_sys->p_display, p_vout->p_sys->yuv_window,
934 BlackPixel(p_vout->p_sys->p_display, p_vout->p_sys->i_screen ) );
936 XMapWindow( p_vout->p_sys->p_display, p_vout->p_sys->yuv_window );
937 XSelectInput( p_vout->p_sys->p_display, p_vout->p_sys->yuv_window,
940 /* If the cursor was formerly blank than blank it again */
941 if( !p_vout->p_sys->b_mouse_pointer_visible )
943 X11ToggleMousePointer( p_vout );
944 X11ToggleMousePointer( p_vout );
950 static void XVideoDestroyWindow( vout_thread_t *p_vout )
952 XFreeGC( p_vout->p_sys->p_display, p_vout->p_sys->yuv_gc );
953 XDestroyWindow( p_vout->p_sys->p_display, p_vout->p_sys->yuv_window );
955 XUnmapWindow( p_vout->p_sys->p_display, p_vout->p_sys->window );
956 XFreeGC( p_vout->p_sys->p_display, p_vout->p_sys->gc );
957 XDestroyWindow( p_vout->p_sys->p_display, p_vout->p_sys->window );
960 /*****************************************************************************
961 * XVideoCreateShmImage: create an XvImage using shared memory extension
962 *****************************************************************************
963 * Prepare an XvImage for display function.
964 * The order of the operations respects the recommandations of the mit-shm
965 * document by J.Corbet and K.Packard. Most of the parameters were copied from
967 *****************************************************************************/
968 static int XVideoCreateShmImage( Display* dpy, int xv_port,
969 XvImage **pp_xvimage,
970 XShmSegmentInfo *p_shm_info,
971 int i_width, int i_height )
973 *pp_xvimage = XvShmCreateImage( dpy, xv_port,
974 GUID_YUV12_PLANAR, 0,
979 intf_ErrMsg( "vout error: XvShmCreateImage failed." );
983 p_shm_info->shmid = shmget( IPC_PRIVATE, (*pp_xvimage)->data_size,
985 if( p_shm_info->shmid < 0) /* error */
987 intf_ErrMsg( "vout error: cannot allocate shared image data (%s)",
992 p_shm_info->shmaddr = (*pp_xvimage)->data = shmat( p_shm_info->shmid,
994 p_shm_info->readOnly = False;
997 /* Mark the shm segment to be removed when there will be no more
998 * attachements, so it is automatic on process exit or after shmdt */
999 shmctl( p_shm_info->shmid, IPC_RMID, 0 );
1002 if( !XShmAttach( dpy, p_shm_info ) )
1004 intf_ErrMsg( "vout error: XShmAttach failed" );
1005 shmctl( p_shm_info->shmid, IPC_RMID, 0 );
1006 shmdt( p_shm_info->shmaddr );
1010 /* Send image to X server. This instruction is required, since having
1011 * built a Shm XImage and not using it causes an error on XCloseDisplay */
1017 /*****************************************************************************
1018 * XVideoDestroyShmImage
1019 *****************************************************************************
1020 * Destroy XImage AND associated data. Detach shared memory segment from
1021 * server and process, then free it. If pointer is NULL, the image won't be
1022 * destroyed (see vout_ManageOutputMethod())
1023 *****************************************************************************/
1024 static void XVideoDestroyShmImage( vout_thread_t *p_vout, XvImage *p_xvimage,
1025 XShmSegmentInfo *p_shm_info )
1027 /* If pointer is NULL, do nothing */
1028 if( p_xvimage == NULL )
1033 XShmDetach( p_vout->p_sys->p_display, p_shm_info );/* detach from server */
1035 XDestroyImage( p_ximage ); /* XXX */
1038 shmctl( p_shm_info->shmid, IPC_RMID, 0 );
1040 if( shmdt( p_shm_info->shmaddr ) ) /* detach shared memory from process */
1042 intf_ErrMsg( "vout error: cannot detach shared memory (%s)",
1047 /*****************************************************************************
1048 * XVideoEnableScreenSaver: enable screen saver
1049 *****************************************************************************
1050 * This function enable the screen saver on a display after it had been
1051 * disabled by XDisableScreenSaver. Both functions use a counter mechanism to
1052 * know wether the screen saver can be activated or not: if n successive calls
1053 * are made to XDisableScreenSaver, n successive calls to XEnableScreenSaver
1054 * will be required before the screen saver could effectively be activated.
1055 *****************************************************************************/
1056 void XVideoEnableScreenSaver( vout_thread_t *p_vout )
1058 intf_DbgMsg( "intf: enabling screen saver" );
1059 XSetScreenSaver( p_vout->p_sys->p_display, p_vout->p_sys->i_ss_timeout,
1060 p_vout->p_sys->i_ss_interval,
1061 p_vout->p_sys->i_ss_blanking,
1062 p_vout->p_sys->i_ss_exposure );
1065 /*****************************************************************************
1066 * XVideoDisableScreenSaver: disable screen saver
1067 *****************************************************************************
1068 * See XEnableScreenSaver
1069 *****************************************************************************/
1070 void XVideoDisableScreenSaver( vout_thread_t *p_vout )
1072 /* Save screen saver informations */
1073 XGetScreenSaver( p_vout->p_sys->p_display, &p_vout->p_sys->i_ss_timeout,
1074 &p_vout->p_sys->i_ss_interval,
1075 &p_vout->p_sys->i_ss_blanking,
1076 &p_vout->p_sys->i_ss_exposure );
1078 /* Disable screen saver */
1079 intf_DbgMsg( "intf: disabling screen saver" );
1080 XSetScreenSaver( p_vout->p_sys->p_display, 0,
1081 p_vout->p_sys->i_ss_interval,
1082 p_vout->p_sys->i_ss_blanking,
1083 p_vout->p_sys->i_ss_exposure );
1086 /*****************************************************************************
1087 * X11ToggleMousePointer: hide or show the mouse pointer
1088 *****************************************************************************
1089 * This function hides the X pointer if requested.
1090 *****************************************************************************/
1091 void X11ToggleMousePointer( vout_thread_t *p_vout )
1094 if( p_vout->p_sys->b_mouse_pointer_visible )
1096 XDefineCursor( p_vout->p_sys->p_display,
1097 p_vout->p_sys->window,
1098 p_vout->p_sys->blank_cursor );
1099 p_vout->p_sys->b_mouse_pointer_visible = 0;
1103 XUndefineCursor( p_vout->p_sys->p_display, p_vout->p_sys->window );
1104 p_vout->p_sys->b_mouse_pointer_visible = 1;
1108 /* This based on some code in SetBufferPicture... At the moment it's only
1109 * used by the xvideo plugin, but others may want to use it. */
1110 static void XVideoOutputCoords( const picture_t *p_pic, const boolean_t scale,
1111 const int win_w, const int win_h,
1112 int *dx, int *dy, int *w, int *h)
1116 *w = p_pic->i_width; *h = p_pic->i_height;
1121 switch( p_pic->i_aspect_ratio )
1123 case AR_3_4_PICTURE:
1127 case AR_16_9_PICTURE:
1128 *h = win_w * 9 / 16;
1131 case AR_221_1_PICTURE:
1132 *h = win_w * 100 / 221;
1135 case AR_SQUARE_PICTURE:
1137 *h = win_w * p_pic->i_height / p_pic->i_width;
1144 switch( p_pic->i_aspect_ratio )
1146 case AR_3_4_PICTURE:
1150 case AR_16_9_PICTURE:
1151 *w = win_h * 16 / 9;
1154 case AR_221_1_PICTURE:
1155 *w = win_h * 221 / 100;
1158 case AR_SQUARE_PICTURE:
1160 *w = win_h * p_pic->i_width / p_pic->i_height;
1166 /* Set picture position */
1167 *dx = (win_w - *w) / 2;
1168 *dy = (win_h - *h) / 2;
1172 /*****************************************************************************
1173 * XVideoGetPort: get YUV12 port
1174 *****************************************************************************
1176 *****************************************************************************/
1177 static int XVideoGetPort( Display *dpy )
1179 XvAdaptorInfo *p_adaptor;
1180 int i_adaptor, i_num_adaptors, i_requested_adaptor;
1181 int i_selected_port;
1183 switch( XvQueryAdaptors( dpy, DefaultRootWindow( dpy ),
1184 &i_num_adaptors, &p_adaptor ) )
1189 case XvBadExtension:
1190 intf_WarnMsg( 3, "vout error: XvBadExtension for XvQueryAdaptors" );
1194 intf_WarnMsg( 3, "vout error: XvBadAlloc for XvQueryAdaptors" );
1198 intf_WarnMsg( 3, "vout error: XvQueryAdaptors failed" );
1202 i_selected_port = -1;
1203 i_requested_adaptor = main_GetIntVariable( VOUT_XVADAPTOR_VAR, -1 );
1205 /* No special xv port has been requested so try all of them */
1206 for( i_adaptor = 0; i_adaptor < i_num_adaptors; ++i_adaptor )
1210 /* If we requested an adaptor and it's not this one, we aren't
1212 if( i_requested_adaptor != -1 && i_adaptor != i_requested_adaptor )
1217 /* If the adaptor doesn't have the required properties, skip it */
1218 if( !( p_adaptor[ i_adaptor ].type & XvInputMask ) ||
1219 !( p_adaptor[ i_adaptor ].type & XvImageMask ) )
1224 for( i_port = p_adaptor[i_adaptor].base_id;
1225 i_port < p_adaptor[i_adaptor].base_id
1226 + p_adaptor[i_adaptor].num_ports;
1229 XvImageFormatValues *p_formats;
1230 int i_format, i_num_formats;
1232 /* If we already found a port, we aren't interested */
1233 if( i_selected_port != -1 )
1238 /* Check that port supports YUV12 planar format... */
1239 p_formats = XvListImageFormats( dpy, i_port, &i_num_formats );
1241 for( i_format = 0; i_format < i_num_formats; i_format++ )
1243 XvEncodingInfo *p_enc;
1244 int i_enc, i_num_encodings;
1245 XvAttribute *p_attr;
1246 int i_attr, i_num_attributes;
1248 if( p_formats[ i_format ].id != GUID_YUV12_PLANAR )
1253 /* Found a matching port, print a description of this port */
1254 i_selected_port = i_port;
1256 intf_WarnMsg( 3, "vout: XVideoGetPort found adaptor %i port %i",
1258 intf_WarnMsg( 3, " image format 0x%x (%4.4s) %s supported",
1259 p_formats[ i_format ].id,
1260 (char *)&p_formats[ i_format ].id,
1261 ( p_formats[ i_format ].format
1262 == XvPacked ) ? "packed" : "planar" );
1264 intf_WarnMsg( 4, " encoding list:" );
1266 if( XvQueryEncodings( dpy, i_port, &i_num_encodings, &p_enc )
1269 intf_WarnMsg( 4, " XvQueryEncodings failed" );
1273 for( i_enc = 0; i_enc < i_num_encodings; i_enc++ )
1275 intf_WarnMsg( 4, " id=%ld, name=%s, size=%ldx%ld,"
1276 " numerator=%d, denominator=%d",
1277 p_enc[i_enc].encoding_id, p_enc[i_enc].name,
1278 p_enc[i_enc].width, p_enc[i_enc].height,
1279 p_enc[i_enc].rate.numerator,
1280 p_enc[i_enc].rate.denominator );
1285 XvFreeEncodingInfo( p_enc );
1288 intf_WarnMsg( 4, " attribute list:" );
1289 p_attr = XvQueryPortAttributes( dpy, i_port,
1290 &i_num_attributes );
1291 for( i_attr = 0; i_attr < i_num_attributes; i_attr++ )
1294 " name=%s, flags=[%s%s ], min=%i, max=%i",
1295 p_attr[i_attr].name,
1296 (p_attr[i_attr].flags & XvGettable) ? " get" : "",
1297 (p_attr[i_attr].flags & XvSettable) ? " set" : "",
1298 p_attr[i_attr].min_value, p_attr[i_attr].max_value );
1301 if( p_attr != NULL )
1307 if( p_formats != NULL )
1314 if( i_num_adaptors > 0 )
1316 XvFreeAdaptorInfo( p_adaptor );
1319 if( i_selected_port == -1 )
1321 if( i_requested_adaptor == -1 )
1323 intf_WarnMsg( 3, "vout: no XVideo port found supporting YUV12" );
1327 intf_WarnMsg( 3, "vout: XVideo adaptor %i does not support YUV12",
1328 i_requested_adaptor );
1332 return( i_selected_port );
1336 /*****************************************************************************
1337 * XVideoDisplay: display image
1338 *****************************************************************************
1339 * This function displays the image stored in p_vout->p_sys->p_xvimage.
1340 * The image is scaled to fit in the output window (and to have the correct
1342 *****************************************************************************/
1343 static void XVideoDisplay( vout_thread_t *p_vout )
1345 int i_dest_width, i_dest_height, i_dest_x, i_dest_y;
1347 if( !p_vout->p_sys->p_xvimage )
1352 XVideoOutputCoords( p_vout->p_rendered_pic, p_vout->b_scale,
1353 p_vout->p_sys->i_window_width,
1354 p_vout->p_sys->i_window_height,
1355 &i_dest_x, &i_dest_y,
1356 &i_dest_width, &i_dest_height);
1358 XvShmPutImage( p_vout->p_sys->p_display, p_vout->p_sys->xv_port,
1359 p_vout->p_sys->yuv_window, p_vout->p_sys->gc,
1360 p_vout->p_sys->p_xvimage,
1361 0 /*src_x*/, 0 /*src_y*/,
1362 p_vout->p_rendered_pic->i_width,
1363 p_vout->p_rendered_pic->i_height,
1364 0 /*dest_x*/, 0 /*dest_y*/, i_dest_width, i_dest_height,
1367 XResizeWindow( p_vout->p_sys->p_display, p_vout->p_sys->yuv_window,
1368 i_dest_width, i_dest_height );
1369 XMoveWindow( p_vout->p_sys->p_display, p_vout->p_sys->yuv_window,
1370 i_dest_x, i_dest_y );
1372 /* Send the order to the X server */
1373 XSync( p_vout->p_sys->p_display, False );
1377 /*****************************************************************************
1378 * XVideoSetAttribute
1379 *****************************************************************************
1380 * This function can be used to set attributes, e.g. XV_BRIGHTNESS and
1381 * XV_CONTRAST. "f_value" should be in the range of 0 to 1.
1382 *****************************************************************************/
1383 static void XVideoSetAttribute( vout_thread_t *p_vout,
1384 char *attr_name, float f_value )
1387 XvAttribute *p_attrib;
1388 Display *p_dpy = p_vout->p_sys->p_display;
1389 int xv_port = p_vout->p_sys->xv_port;
1391 p_attrib = XvQueryPortAttributes( p_dpy, xv_port, &i_attrib );
1397 if( i_attrib >= 0 && !strcmp( p_attrib[ i_attrib ].name, attr_name ) )
1399 int i_sv = f_value * ( p_attrib[ i_attrib ].max_value
1400 - p_attrib[ i_attrib ].min_value + 1 )
1401 + p_attrib[ i_attrib ].min_value;
1403 XvSetPortAttribute( p_dpy, xv_port,
1404 XInternAtom( p_dpy, attr_name, False ), i_sv );
1408 } while( i_attrib > 0 );