* Fixed a warning for *BSD compilation.
[vlc.git] / plugins / x11 / vout_xvideo.c
blobac1de28bbef93cdb80c9e5ff23a0a4556bd69408
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.17 2001/05/25 13:20:09 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 /*****************************************************************************
31 * Preamble
32 *****************************************************************************/
33 #include "defs.h"
35 #include <errno.h> /* ENOMEM */
36 #include <stdlib.h> /* free() */
37 #include <string.h> /* strerror() */
39 #ifdef HAVE_MACHINE_PARAM_H
40 /* BSD */
41 #include <machine/param.h>
42 #include <sys/types.h> /* typedef ushort */
43 #include <sys/ipc.h>
44 #endif
46 #ifndef WIN32
47 #include <netinet/in.h> /* BSD: struct in_addr */
48 #endif
50 #include <sys/shm.h> /* shmget(), shmctl() */
51 #include <X11/Xlib.h>
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>
58 #include "config.h"
59 #include "common.h"
60 #include "threads.h"
61 #include "mtime.h"
62 #include "tests.h"
63 #include "modules.h"
65 #include "video.h"
66 #include "video_output.h"
68 #include "interface.h"
69 #include "intf_msg.h"
71 #include "netutils.h" /* network_ChannelJoin */
73 #include "main.h"
75 #include "stream_control.h" /* needed by input_ext-intf.h... */
76 #include "input_ext-intf.h"
79 #define GUID_YUV12_PLANAR 0x32315659
82 /*****************************************************************************
83 * vout_sys_t: video output X11 method descriptor
84 *****************************************************************************
85 * This structure is part of the video output thread descriptor.
86 * It describes the XVideo specific properties of an output thread.
87 *****************************************************************************/
88 typedef struct vout_sys_s
90 /* User settings */
91 #if 0
92 /* this plugin (currently) requires the SHM Ext... */
93 boolean_t b_shm; /* shared memory extension flag */
94 #endif
96 /* Internal settings and properties */
97 Display * p_display; /* display pointer */
98 int i_screen; /* screen number */
99 Window window; /* root window */
100 GC gc; /* graphic context instance handler */
101 Window yuv_window; /* sub-window for displaying yuv video
102 data */
103 GC yuv_gc;
104 int xv_port;
106 /* Display buffers and shared memory information */
107 /* Note: only 1 buffer... Xv ext does double buffering. */
108 XvImage * p_xvimage;
109 int i_image_width;
110 int i_image_height;
111 /* i_image_width & i_image_height reflect the
112 * size of the XvImage. They are used by
113 * vout_Display() to check if the image to be
114 * displayed can use the current XvImage. */
115 XShmSegmentInfo shm_info; /* shared memory zone information */
117 /* X11 generic properties */
118 Atom wm_protocols;
119 Atom wm_delete_window;
121 int i_window_width; /* width of main window */
122 int i_window_height; /* height of main window */
125 /* Screen saver properties */
126 int i_ss_timeout; /* timeout */
127 int i_ss_interval; /* interval between changes */
128 int i_ss_blanking; /* blanking mode */
129 int i_ss_exposure; /* exposure mode */
131 /* Mouse pointer properties */
132 boolean_t b_mouse_pointer_visible;
133 mtime_t i_time_mouse_last_moved; /* used to auto-hide pointer*/
135 } vout_sys_t;
137 /* Fullscreen needs to be able to hide the wm decorations */
138 #define MWM_HINTS_DECORATIONS (1L << 1)
139 #define PROP_MWM_HINTS_ELEMENTS 5
140 typedef struct mwmhints_s
142 u32 flags;
143 u32 functions;
144 u32 decorations;
145 s32 input_mode;
146 u32 status;
147 } mwmhints_t;
149 /*****************************************************************************
150 * Local prototypes
151 *****************************************************************************/
152 static int vout_Probe ( probedata_t * );
153 static int vout_Create ( vout_thread_t * );
154 static int vout_Init ( vout_thread_t * );
155 static void vout_End ( vout_thread_t * );
156 static void vout_Destroy ( vout_thread_t * );
157 static int vout_Manage ( vout_thread_t * );
158 static void vout_Display ( vout_thread_t * );
159 static void vout_SetPalette( vout_thread_t *, u16 *, u16 *, u16 *, u16 * );
161 static int XVideoCreateWindow ( vout_thread_t * );
162 static void XVideoDestroyWindow ( vout_thread_t *p_vout );
163 static int XVideoUpdateImgSizeIfRequired( vout_thread_t *p_vout );
164 static int XVideoCreateShmImage ( Display* dpy, int xv_port,
165 XvImage **pp_xvimage,
166 XShmSegmentInfo *p_shm_info,
167 int i_width, int i_height );
168 static void XVideoDestroyShmImage ( vout_thread_t *, XvImage *,
169 XShmSegmentInfo * );
170 static void XVideoSetMousePointer ( const vout_thread_t * );
171 static void XVideoEnableScreenSaver ( vout_thread_t * );
172 static void XVideoDisableScreenSaver ( vout_thread_t * );
173 /*static void XVideoSetAttribute ( vout_thread_t *, char *, float );*/
175 static int XVideoCheckForXv ( Display * );
176 static int XVideoGetPort ( Display * );
177 static void XVideoOutputCoords ( const picture_t *, const boolean_t,
178 const int, const int,
179 int *, int *, int *, int * );
180 static void XVideoDisplay ( vout_thread_t * );
182 /*****************************************************************************
183 * Functions exported as capabilities. They are declared as static so that
184 * we don't pollute the namespace too much.
185 *****************************************************************************/
186 void _M( vout_getfunctions )( function_list_t * p_function_list )
188 p_function_list->pf_probe = vout_Probe;
189 p_function_list->functions.vout.pf_create = vout_Create;
190 p_function_list->functions.vout.pf_init = vout_Init;
191 p_function_list->functions.vout.pf_end = vout_End;
192 p_function_list->functions.vout.pf_destroy = vout_Destroy;
193 p_function_list->functions.vout.pf_manage = vout_Manage;
194 p_function_list->functions.vout.pf_display = vout_Display;
195 p_function_list->functions.vout.pf_setpalette = vout_SetPalette;
198 /*****************************************************************************
199 * vout_Probe: probe the video driver and return a score
200 *****************************************************************************
201 * This returns a score to the plugin manager so that it can select the best
202 * plugin.
203 *****************************************************************************/
204 static int vout_Probe( probedata_t *p_data )
206 if( TestMethod( VOUT_METHOD_VAR, "xvideo" ) )
208 return( 999 );
211 return( 60 );
214 /*****************************************************************************
215 * vout_Create: allocate XVideo video thread output method
216 *****************************************************************************
217 * This function allocate and initialize a XVideo vout method. It uses some of
218 * the vout properties to choose the window size, and change them according to
219 * the actual properties of the display.
220 *****************************************************************************/
221 static int vout_Create( vout_thread_t *p_vout )
223 char *psz_display;
225 /* Allocate structure */
226 p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
227 if( p_vout->p_sys == NULL )
229 intf_ErrMsg( "vout error: %s", strerror(ENOMEM) );
230 return( 1 );
233 /* Open display, unsing 'vlc_display' or DISPLAY environment variable */
234 psz_display = XDisplayName( main_GetPszVariable( VOUT_DISPLAY_VAR, NULL ) );
235 p_vout->p_sys->p_display = XOpenDisplay( psz_display );
237 if( p_vout->p_sys->p_display == NULL ) /* error */
239 intf_ErrMsg( "vout error: cannot open display %s", psz_display );
240 free( p_vout->p_sys );
241 return( 1 );
243 p_vout->p_sys->i_screen = DefaultScreen( p_vout->p_sys->p_display );
245 p_vout->b_fullscreen
246 = main_GetIntVariable( VOUT_FULLSCREEN_VAR, VOUT_FULLSCREEN_DEFAULT );
248 if( !XVideoCheckForXv( p_vout->p_sys->p_display ) )
250 intf_ErrMsg( "vout error: no XVideo extension" );
251 XCloseDisplay( p_vout->p_sys->p_display );
252 free( p_vout->p_sys );
253 return( 1 );
256 /* Spawn base window - this window will include the video output window,
257 * but also command buttons, subtitles and other indicators */
258 if( XVideoCreateWindow( p_vout ) )
260 intf_ErrMsg( "vout error: cannot create XVideo window" );
261 XCloseDisplay( p_vout->p_sys->p_display );
262 free( p_vout->p_sys );
263 return( 1 );
266 if( (p_vout->p_sys->xv_port = XVideoGetPort( p_vout->p_sys->p_display ))<0 )
267 return 1;
268 intf_DbgMsg( "Using xv port %d" , p_vout->p_sys->xv_port );
270 #if 0
271 /* XXX The brightness and contrast values should be read from environment
272 * XXX variables... */
273 XVideoSetAttribute( p_vout, "XV_BRIGHTNESS", 0.5 );
274 XVideoSetAttribute( p_vout, "XV_CONTRAST", 0.5 );
275 #endif
277 p_vout->p_sys->b_mouse_pointer_visible = 1;
279 /* Disable screen saver and return */
280 XVideoDisableScreenSaver( p_vout );
282 return( 0 );
285 /*****************************************************************************
286 * vout_Init: initialize XVideo video thread output method
287 *****************************************************************************/
288 static int vout_Init( vout_thread_t *p_vout )
290 #ifdef SYS_DARWIN1_3
291 /* FIXME : As of 2001-03-16, XFree4 for MacOS X does not support Xshm. */
292 p_vout->p_sys->b_shm = 0;
293 #endif
294 p_vout->b_need_render = 0;
295 p_vout->p_sys->i_image_width = p_vout->p_sys->i_image_height = 0;
297 return( 0 );
300 /*****************************************************************************
301 * vout_End: terminate XVideo video thread output method
302 *****************************************************************************
303 * Destroy the XvImage. It is called at the end of the thread, but also each
304 * time the image is resized.
305 *****************************************************************************/
306 static void vout_End( vout_thread_t *p_vout )
308 XVideoDestroyShmImage( p_vout, p_vout->p_sys->p_xvimage,
309 &p_vout->p_sys->shm_info );
312 /*****************************************************************************
313 * vout_Destroy: destroy XVideo video thread output method
314 *****************************************************************************
315 * Terminate an output method created by vout_Create
316 *****************************************************************************/
317 static void vout_Destroy( vout_thread_t *p_vout )
319 XVideoEnableScreenSaver( p_vout );
320 XVideoDestroyWindow( p_vout );
321 XCloseDisplay( p_vout->p_sys->p_display );
323 /* Destroy structure */
324 free( p_vout->p_sys );
327 /*****************************************************************************
328 * vout_Manage: handle X11 events
329 *****************************************************************************
330 * This function should be called regularly by video output thread. It manages
331 * X11 events and allows window resizing. It returns a non null value on
332 * error.
334 * XXX Should "factor-out" common code in this and the "same" fn in the x11
335 * XXX plugin!
336 *****************************************************************************/
337 static int vout_Manage( vout_thread_t *p_vout )
339 XEvent xevent; /* X11 event */
340 char i_key; /* ISO Latin-1 key */
341 KeySym x_key_symbol;
343 /* Handle X11 events: ConfigureNotify events are parsed to know if the
344 * output window's size changed, MapNotify and UnmapNotify to know if the
345 * window is mapped (and if the display is useful), and ClientMessages
346 * to intercept window destruction requests */
347 while( XCheckWindowEvent( p_vout->p_sys->p_display, p_vout->p_sys->window,
348 StructureNotifyMask | KeyPressMask |
349 ButtonPressMask | ButtonReleaseMask |
350 PointerMotionMask, &xevent )
351 == True )
353 /* ConfigureNotify event: prepare */
354 if( (xevent.type == ConfigureNotify)
355 /*&& ((xevent.xconfigure.width != p_vout->p_sys->i_window_width)
356 || (xevent.xconfigure.height != p_vout->p_sys->i_window_height))*/ )
358 /* Update dimensions */
359 p_vout->p_sys->i_window_width = xevent.xconfigure.width;
360 p_vout->p_sys->i_window_height = xevent.xconfigure.height;
362 /* MapNotify event: change window status and disable screen saver */
363 else if( xevent.type == MapNotify)
365 if( (p_vout != NULL) && !p_vout->b_active )
367 XVideoDisableScreenSaver( p_vout );
368 p_vout->b_active = 1;
371 /* UnmapNotify event: change window status and enable screen saver */
372 else if( xevent.type == UnmapNotify )
374 if( (p_vout != NULL) && p_vout->b_active )
376 XVideoEnableScreenSaver( p_vout );
377 p_vout->b_active = 0;
380 /* Keyboard event */
381 else if( xevent.type == KeyPress )
383 /* We may have keys like F1 trough F12, ESC ... */
384 x_key_symbol = XKeycodeToKeysym( p_vout->p_sys->p_display,
385 xevent.xkey.keycode, 0 );
386 switch( x_key_symbol )
388 case XK_Escape:
389 p_main->p_intf->b_die = 1;
390 break;
391 case XK_Menu:
392 p_main->p_intf->b_menu_change = 1;
393 break;
394 default:
395 /* "Normal Keys"
396 * The reason why I use this instead of XK_0 is that
397 * with XLookupString, we don't have to care about
398 * keymaps. */
400 if( XLookupString( &xevent.xkey, &i_key, 1, NULL, NULL ) )
402 switch( i_key )
404 case 'q':
405 case 'Q':
406 p_main->p_intf->b_die = 1;
407 break;
408 case 'f':
409 case 'F':
410 p_vout->i_changes |= VOUT_FULLSCREEN_CHANGE;
411 break;
412 case '0':
413 network_ChannelJoin( 0 );
414 break;
415 case '1':
416 network_ChannelJoin( 1 );
417 break;
418 case '2':
419 network_ChannelJoin( 2 );
420 break;
421 case '3':
422 network_ChannelJoin( 3 );
423 break;
424 case '4':
425 network_ChannelJoin( 4 );
426 break;
427 case '5':
428 network_ChannelJoin( 5 );
429 break;
430 case '6':
431 network_ChannelJoin( 6 );
432 break;
433 case '7':
434 network_ChannelJoin( 7 );
435 break;
436 case '8':
437 network_ChannelJoin( 8 );
438 break;
439 case '9':
440 network_ChannelJoin( 9 );
441 break;
442 default:
443 if( intf_ProcessKey( p_main->p_intf,
444 (char )i_key ) )
446 intf_DbgMsg( "unhandled key '%c' (%i)",
447 (char)i_key, i_key );
449 break;
452 break;
455 /* Mouse click */
456 else if( xevent.type == ButtonPress )
458 switch( ((XButtonEvent *)&xevent)->button )
460 case Button1:
461 /* in this part we will eventually manage
462 * clicks for DVD navigation for instance */
463 break;
466 /* Mouse release */
467 else if( xevent.type == ButtonRelease )
469 switch( ((XButtonEvent *)&xevent)->button )
471 case Button3:
472 /* FIXME: need locking ! */
473 p_main->p_intf->b_menu_change = 1;
474 break;
477 /* Mouse move */
478 else if( xevent.type == MotionNotify )
480 p_vout->p_sys->i_time_mouse_last_moved = mdate();
481 p_vout->p_sys->b_mouse_pointer_visible = 1;
482 XVideoSetMousePointer( p_vout );
484 /* Other event */
485 else
487 intf_WarnMsg( 3, "%p -> unhandled event type %d received",
488 p_vout, xevent.type );
492 /* Handle events for YUV video output sub-window */
493 while( XCheckWindowEvent( p_vout->p_sys->p_display,
494 p_vout->p_sys->yuv_window,
495 ExposureMask, &xevent ) == True )
497 /* Window exposed (only handled if stream playback is paused) */
498 if( xevent.type == Expose )
500 if( ((XExposeEvent *)&xevent)->count == 0 )
501 /* (if this is the last a collection of expose events...) */
502 if( p_main->p_intf->p_input )
503 if( PAUSE_S ==
504 p_main->p_intf->p_input->stream.control.i_status )
505 XVideoDisplay( p_vout );
509 /* ClientMessage event - only WM_PROTOCOLS with WM_DELETE_WINDOW data
510 * are handled - according to the man pages, the format is always 32
511 * in this case */
512 while( XCheckTypedEvent( p_vout->p_sys->p_display,
513 ClientMessage, &xevent ) )
515 if( (xevent.xclient.message_type == p_vout->p_sys->wm_protocols)
516 && (xevent.xclient.data.l[0] == p_vout->p_sys->wm_delete_window ) )
518 p_main->p_intf->b_die = 1;
520 else
522 intf_DbgMsg( "%p -> unhandled ClientMessage received", p_vout );
526 if ( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE )
528 intf_DbgMsg( "vout: changing full-screen status" );
530 p_vout->b_fullscreen = !p_vout->b_fullscreen;
532 /* Get rid of the old window */
533 XVideoDestroyWindow( p_vout );
535 /* And create a new one */
536 if( XVideoCreateWindow( p_vout ) )
538 intf_ErrMsg( "vout error: cannot create X11 window" );
539 XCloseDisplay( p_vout->p_sys->p_display );
541 free( p_vout->p_sys );
542 return( 1 );
547 if( (p_vout->i_changes & VOUT_GRAYSCALE_CHANGE))
549 /* FIXME: clear flags ?? */
553 * Size change
555 if( p_vout->i_changes & VOUT_SIZE_CHANGE )
557 intf_DbgMsg( "vout: resizing window" );
558 p_vout->i_changes &= ~VOUT_SIZE_CHANGE;
559 /* Nothing to do here...
560 * vout_Display() detects size changes of the image to be displayed and
561 * re-creates the XvImage.*/
562 intf_Msg( "vout: video display resized (%dx%d)",
563 p_vout->i_width, p_vout->i_height );
566 /* Autohide Cursor */
567 if( p_vout->p_sys->b_mouse_pointer_visible &&
568 mdate() - p_vout->p_sys->i_time_mouse_last_moved > 2000000 )
570 p_vout->p_sys->b_mouse_pointer_visible = 0;
571 XVideoSetMousePointer( p_vout );
574 return 0;
577 /*****************************************************************************
578 * vout_Display: displays previously rendered output
579 *****************************************************************************
580 * This function sends the currently rendered image to X11 server.
581 * (The Xv extension takes care of "double-buffering".)
582 *****************************************************************************/
583 static void vout_Display( vout_thread_t *p_vout )
585 boolean_t b_draw = 1;
586 int i_size = p_vout->p_rendered_pic->i_width *
587 p_vout->p_rendered_pic->i_height;
589 if( XVideoUpdateImgSizeIfRequired( p_vout ) )
590 return;
592 switch( p_vout->p_rendered_pic->i_type )
594 case YUV_422_PICTURE:
595 intf_ErrMsg( "vout error: YUV_422_PICTURE not (yet) supported" );
596 b_draw = 0;
597 break;
599 case YUV_444_PICTURE:
600 intf_ErrMsg( "vout error: YUV_444_PICTURE not (yet) supported" );
601 b_draw = 0;
602 break;
604 case YUV_420_PICTURE:
605 memcpy( p_vout->p_sys->p_xvimage->data,
606 p_vout->p_rendered_pic->p_y, i_size );
607 memcpy( p_vout->p_sys->p_xvimage->data + ( i_size ),
608 p_vout->p_rendered_pic->p_v, i_size / 4 );
609 memcpy( p_vout->p_sys->p_xvimage->data + ( i_size ) + ( i_size / 4 ),
610 p_vout->p_rendered_pic->p_u, i_size / 4 );
611 break;
614 if( b_draw )
615 XVideoDisplay( p_vout );
618 static void vout_SetPalette( p_vout_thread_t p_vout,
619 u16 *red, u16 *green, u16 *blue, u16 *transp )
621 return;
624 /* following functions are local */
626 /*****************************************************************************
627 * XVideoUpdateImgSizeIfRequired
628 *****************************************************************************
629 * This function checks to see if the image to be displayed is of a different
630 * size to the last image displayed. If so, the old shm block must be
631 * destroyed and a new one created.
632 * Note: the "image size" is the size of the image to be passed to the Xv
633 * extension (which is probably different to the size of the output window).
634 *****************************************************************************/
635 static int XVideoUpdateImgSizeIfRequired( vout_thread_t *p_vout )
637 int i_img_width = p_vout->p_rendered_pic->i_width;
638 int i_img_height = p_vout->p_rendered_pic->i_height;
640 if( p_vout->p_sys->i_image_width != i_img_width
641 || p_vout->p_sys->i_image_height != i_img_height )
643 p_vout->p_sys->i_image_width = i_img_width;
644 p_vout->p_sys->i_image_height = i_img_height;
646 /* Destroy XvImage to change its size */
647 vout_End( p_vout );
648 /* Note: vout_End does nothing if no XvImage to destroy. */
650 /* Create XvImage using XShm extension */
651 if( XVideoCreateShmImage( p_vout->p_sys->p_display,
652 p_vout->p_sys->xv_port,
653 &p_vout->p_sys->p_xvimage,
654 &p_vout->p_sys->shm_info,
655 i_img_width, i_img_height ) )
657 intf_ErrMsg( "vout: failed to create xvimage." );
658 p_vout->p_sys->i_image_width = 0;
659 return( 1 );
662 /* Set bytes per line and initialize buffers */
663 p_vout->i_bytes_per_line =
664 (p_vout->p_sys->p_xvimage->data_size) /
665 (p_vout->p_sys->p_xvimage->height);
667 /* vout_SetBuffers( p_vout, p_vout->p_sys->p_xvimage->data ); */
670 return( 0 );
673 /*****************************************************************************
674 * XVideoCheckForXv: check for the XVideo extension
675 *****************************************************************************/
676 static int XVideoCheckForXv( Display *dpy )
678 unsigned int i;
680 switch( XvQueryExtension( dpy, &i, &i, &i, &i, &i ) )
682 case Success:
683 return( 1 );
685 case XvBadExtension:
686 intf_ErrMsg( "vout error: XvBadExtension" );
687 return( 0 );
689 case XvBadAlloc:
690 intf_ErrMsg( "vout error: XvBadAlloc" );
691 return( 0 );
693 default:
694 intf_ErrMsg( "vout error: XvQueryExtension failed" );
695 return( 0 );
699 /*****************************************************************************
700 * XVideoCreateWindow: open and set-up XVideo main window
701 *****************************************************************************/
702 static int XVideoCreateWindow( vout_thread_t *p_vout )
704 XSizeHints xsize_hints;
705 XSetWindowAttributes xwindow_attributes;
706 XGCValues xgcvalues;
707 XEvent xevent;
708 Atom prop;
709 mwmhints_t mwmhints;
711 boolean_t b_expose;
712 boolean_t b_configure_notify;
713 boolean_t b_map_notify;
716 /* Set main window's size */
717 /* If we're full screen, we're full screen! */
718 if( p_vout->b_fullscreen )
720 p_vout->p_sys->i_window_width = DisplayWidth( p_vout->p_sys->p_display,
721 p_vout->p_sys->i_screen );
722 p_vout->p_sys->i_window_height = DisplayHeight( p_vout->p_sys->p_display,
723 p_vout->p_sys->i_screen );
724 /* p_vout->i_width = p_vout->p_sys->i_window_width;
725 p_vout->i_height = p_vout->p_sys->i_window_height; */
727 else
729 p_vout->p_sys->i_window_width = main_GetIntVariable( VOUT_WIDTH_VAR,
730 VOUT_WIDTH_DEFAULT );
731 p_vout->p_sys->i_window_height = main_GetIntVariable( VOUT_HEIGHT_VAR,
732 VOUT_HEIGHT_DEFAULT );
735 /* Prepare window manager hints and properties */
736 xsize_hints.base_width = p_vout->p_sys->i_window_width;
737 xsize_hints.base_height = p_vout->p_sys->i_window_height;
738 xsize_hints.flags = PSize;
739 p_vout->p_sys->wm_protocols = XInternAtom( p_vout->p_sys->p_display,
740 "WM_PROTOCOLS", True );
741 p_vout->p_sys->wm_delete_window = XInternAtom( p_vout->p_sys->p_display,
742 "WM_DELETE_WINDOW", True );
744 /* Prepare window attributes */
745 xwindow_attributes.background_pixel = BlackPixel( p_vout->p_sys->p_display,
746 p_vout->p_sys->i_screen );
748 xwindow_attributes.event_mask = ExposureMask | StructureNotifyMask;
750 /* Create the window and set hints - the window must receive ConfigureNotify
751 * events, and, until it is displayed, Expose and MapNotify events. */
752 p_vout->p_sys->window =
753 XCreateWindow( p_vout->p_sys->p_display,
754 DefaultRootWindow( p_vout->p_sys->p_display ),
755 0, 0,
756 p_vout->p_sys->i_window_width,
757 p_vout->p_sys->i_window_height, 1,
758 0, InputOutput, 0,
759 CWBackPixel | CWEventMask,
760 &xwindow_attributes );
762 if ( p_vout->b_fullscreen )
764 prop = XInternAtom(p_vout->p_sys->p_display, "_MOTIF_WM_HINTS", False);
765 mwmhints.flags = MWM_HINTS_DECORATIONS;
766 mwmhints.decorations = 0;
767 XChangeProperty( p_vout->p_sys->p_display, p_vout->p_sys->window,
768 prop, prop, 32, PropModeReplace,
769 (unsigned char *)&mwmhints, PROP_MWM_HINTS_ELEMENTS );
771 XSetTransientForHint( p_vout->p_sys->p_display,
772 p_vout->p_sys->window, None );
773 XRaiseWindow( p_vout->p_sys->p_display, p_vout->p_sys->window );
777 /* Set window manager hints and properties: size hints, command,
778 * window's name, and accepted protocols */
779 XSetWMNormalHints( p_vout->p_sys->p_display, p_vout->p_sys->window,
780 &xsize_hints );
781 XSetCommand( p_vout->p_sys->p_display, p_vout->p_sys->window,
782 p_main->ppsz_argv, p_main->i_argc );
783 XStoreName( p_vout->p_sys->p_display, p_vout->p_sys->window,
784 VOUT_TITLE " (XVideo output)" );
786 if( (p_vout->p_sys->wm_protocols == None) /* use WM_DELETE_WINDOW */
787 || (p_vout->p_sys->wm_delete_window == None)
788 || !XSetWMProtocols( p_vout->p_sys->p_display, p_vout->p_sys->window,
789 &p_vout->p_sys->wm_delete_window, 1 ) )
791 /* WM_DELETE_WINDOW is not supported by window manager */
792 intf_Msg( "vout error: missing or bad window manager" );
795 /* Creation of a graphic context that doesn't generate a GraphicsExpose
796 * event when using functions like XCopyArea */
797 xgcvalues.graphics_exposures = False;
798 p_vout->p_sys->gc = XCreateGC( p_vout->p_sys->p_display,
799 p_vout->p_sys->window,
800 GCGraphicsExposures, &xgcvalues);
802 /* Send orders to server, and wait until window is displayed - three
803 * events must be received: a MapNotify event, an Expose event allowing
804 * drawing in the window, and a ConfigureNotify to get the window
805 * dimensions. Once those events have been received, only ConfigureNotify
806 * events need to be received. */
807 b_expose = 0;
808 b_configure_notify = 0;
809 b_map_notify = 0;
810 XMapWindow( p_vout->p_sys->p_display, p_vout->p_sys->window);
813 XNextEvent( p_vout->p_sys->p_display, &xevent);
814 if( (xevent.type == Expose)
815 && (xevent.xexpose.window == p_vout->p_sys->window) )
817 b_expose = 1;
819 else if( (xevent.type == MapNotify)
820 && (xevent.xmap.window == p_vout->p_sys->window) )
822 b_map_notify = 1;
824 else if( (xevent.type == ConfigureNotify)
825 && (xevent.xconfigure.window == p_vout->p_sys->window) )
827 b_configure_notify = 1;
828 p_vout->p_sys->i_window_width = xevent.xconfigure.width;
829 p_vout->p_sys->i_window_height = xevent.xconfigure.height;
831 } while( !( b_expose && b_configure_notify && b_map_notify ) );
833 XSelectInput( p_vout->p_sys->p_display, p_vout->p_sys->window,
834 StructureNotifyMask | KeyPressMask |
835 ButtonPressMask | ButtonReleaseMask |
836 PointerMotionMask );
838 if( p_vout->b_fullscreen )
840 XSetInputFocus( p_vout->p_sys->p_display, p_vout->p_sys->window,
841 RevertToNone, CurrentTime );
842 XMoveWindow( p_vout->p_sys->p_display, p_vout->p_sys->window, 0, 0 );
845 /* Create YUV output sub-window. */
846 p_vout->p_sys->yuv_window=XCreateSimpleWindow( p_vout->p_sys->p_display,
847 p_vout->p_sys->window, 0, 0, 1, 1, 0,
848 BlackPixel( p_vout->p_sys->p_display,
849 p_vout->p_sys->i_screen ),
850 WhitePixel( p_vout->p_sys->p_display,
851 p_vout->p_sys->i_screen ) );
853 p_vout->p_sys->yuv_gc = XCreateGC( p_vout->p_sys->p_display,
854 p_vout->p_sys->yuv_window,
855 GCGraphicsExposures, &xgcvalues );
857 XSetWindowBackground( p_vout->p_sys->p_display, p_vout->p_sys->yuv_window,
858 BlackPixel(p_vout->p_sys->p_display, p_vout->p_sys->i_screen ) );
860 XMapWindow( p_vout->p_sys->p_display, p_vout->p_sys->yuv_window );
861 XSelectInput( p_vout->p_sys->p_display, p_vout->p_sys->yuv_window,
862 ExposureMask );
865 XVideoSetMousePointer( p_vout );
867 return( 0 );
870 static void XVideoDestroyWindow( vout_thread_t *p_vout )
872 XFreeGC( p_vout->p_sys->p_display, p_vout->p_sys->yuv_gc );
873 XDestroyWindow( p_vout->p_sys->p_display, p_vout->p_sys->yuv_window );
875 XUnmapWindow( p_vout->p_sys->p_display, p_vout->p_sys->window );
876 XFreeGC( p_vout->p_sys->p_display, p_vout->p_sys->gc );
877 XDestroyWindow( p_vout->p_sys->p_display, p_vout->p_sys->window );
880 /*****************************************************************************
881 * XVideoCreateShmImage: create an XvImage using shared memory extension
882 *****************************************************************************
883 * Prepare an XvImage for display function.
884 * The order of the operations respects the recommandations of the mit-shm
885 * document by J.Corbet and K.Packard. Most of the parameters were copied from
886 * there.
887 *****************************************************************************/
888 static int XVideoCreateShmImage( Display* dpy, int xv_port,
889 XvImage **pp_xvimage,
890 XShmSegmentInfo *p_shm_info,
891 int i_width, int i_height )
893 *pp_xvimage = XvShmCreateImage( dpy, xv_port,
894 GUID_YUV12_PLANAR, 0,
895 i_width, i_height,
896 p_shm_info );
897 if( !(*pp_xvimage) )
899 intf_ErrMsg( "vout error: XvShmCreateImage failed." );
900 return( -1 );
903 p_shm_info->shmid = shmget( IPC_PRIVATE, (*pp_xvimage)->data_size,
904 IPC_CREAT | 0777 );
905 if( p_shm_info->shmid < 0) /* error */
907 intf_ErrMsg( "vout error: cannot allocate shared image data (%s)",
908 strerror(errno));
909 return( 1 );
912 p_shm_info->shmaddr = (*pp_xvimage)->data = shmat( p_shm_info->shmid,
913 0, 0 );
914 p_shm_info->readOnly = False;
916 /* Mark the shm segment to be removed when there will be no more
917 * attachements, so it is automatic on process exit or after shmdt */
918 shmctl( p_shm_info->shmid, IPC_RMID, 0 );
920 if( !XShmAttach( dpy, p_shm_info ) )
922 intf_ErrMsg( "vout error: XShmAttach failed" );
923 shmdt( p_shm_info->shmaddr );
924 return( -1 );
927 /* Send image to X server. This instruction is required, since having
928 * built a Shm XImage and not using it causes an error on XCloseDisplay */
929 XFlush( dpy );
931 return( 0 );
934 /*****************************************************************************
935 * XVideoDestroyShmImage
936 *****************************************************************************
937 * Destroy XImage AND associated data. Detach shared memory segment from
938 * server and process, then free it. If pointer is NULL, the image won't be
939 * destroyed (see vout_ManageOutputMethod())
940 *****************************************************************************/
941 static void XVideoDestroyShmImage( vout_thread_t *p_vout, XvImage *p_xvimage,
942 XShmSegmentInfo *p_shm_info )
944 /* If pointer is NULL, do nothing */
945 if( p_xvimage == NULL )
947 return;
950 XShmDetach( p_vout->p_sys->p_display, p_shm_info );/* detach from server */
951 #if 0
952 XDestroyImage( p_ximage ); /* XXX */
953 #endif
955 if( shmdt( p_shm_info->shmaddr ) ) /* detach shared memory from process */
956 { /* also automatic freeing... */
957 intf_ErrMsg( "vout error: cannot detach shared memory (%s)",
958 strerror(errno) );
962 /*****************************************************************************
963 * XVideoEnableScreenSaver: enable screen saver
964 *****************************************************************************
965 * This function enable the screen saver on a display after it had been
966 * disabled by XDisableScreenSaver. Both functions use a counter mechanism to
967 * know wether the screen saver can be activated or not: if n successive calls
968 * are made to XDisableScreenSaver, n successive calls to XEnableScreenSaver
969 * will be required before the screen saver could effectively be activated.
970 *****************************************************************************/
971 void XVideoEnableScreenSaver( vout_thread_t *p_vout )
973 intf_DbgMsg( "intf: enabling screen saver" );
974 XSetScreenSaver( p_vout->p_sys->p_display, p_vout->p_sys->i_ss_timeout,
975 p_vout->p_sys->i_ss_interval,
976 p_vout->p_sys->i_ss_blanking,
977 p_vout->p_sys->i_ss_exposure );
980 /*****************************************************************************
981 * XVideoDisableScreenSaver: disable screen saver
982 *****************************************************************************
983 * See XEnableScreenSaver
984 *****************************************************************************/
985 void XVideoDisableScreenSaver( vout_thread_t *p_vout )
987 /* Save screen saver informations */
988 XGetScreenSaver( p_vout->p_sys->p_display, &p_vout->p_sys->i_ss_timeout,
989 &p_vout->p_sys->i_ss_interval,
990 &p_vout->p_sys->i_ss_blanking,
991 &p_vout->p_sys->i_ss_exposure );
993 /* Disable screen saver */
994 intf_DbgMsg( "intf: disabling screen saver" );
995 XSetScreenSaver( p_vout->p_sys->p_display, 0,
996 p_vout->p_sys->i_ss_interval,
997 p_vout->p_sys->i_ss_blanking,
998 p_vout->p_sys->i_ss_exposure );
1001 /*****************************************************************************
1002 * XVideoSetMousePointer: hide or show the mouse pointer
1003 *****************************************************************************
1004 * This function hides the X pointer if requested.
1005 *****************************************************************************/
1006 void XVideoSetMousePointer( const vout_thread_t *p_vout )
1008 static Cursor blank_cursor;
1009 static boolean_t b_created_blank_cursor = 0;
1011 if( !p_vout->p_sys->b_mouse_pointer_visible )
1013 if( !b_created_blank_cursor )
1015 XColor color;
1016 Pixmap blank = XCreatePixmap( p_vout->p_sys->p_display,
1017 DefaultRootWindow(p_vout->p_sys->p_display),
1018 1, 1, 1 );
1020 XParseColor( p_vout->p_sys->p_display,
1021 XCreateColormap( p_vout->p_sys->p_display,
1022 DefaultRootWindow(
1023 p_vout->p_sys->p_display ),
1024 DefaultVisual(
1025 p_vout->p_sys->p_display,
1026 p_vout->p_sys->i_screen ),
1027 AllocNone ),
1028 "black", &color );
1030 blank_cursor = XCreatePixmapCursor( p_vout->p_sys->p_display,
1031 blank, blank, &color, &color, 1, 1 );
1033 b_created_blank_cursor = 1;
1035 XDefineCursor( p_vout->p_sys->p_display,
1036 p_vout->p_sys->window, blank_cursor );
1038 else
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)
1050 if( !scale )
1052 *w = p_pic->i_width; *h = p_pic->i_height;
1054 else
1056 *w = win_w;
1057 switch( p_pic->i_aspect_ratio )
1059 case AR_3_4_PICTURE:
1060 *h = win_w * 3 / 4;
1061 break;
1063 case AR_16_9_PICTURE:
1064 *h = win_w * 9 / 16;
1065 break;
1067 case AR_221_1_PICTURE:
1068 *h = win_w * 100 / 221;
1069 break;
1071 case AR_SQUARE_PICTURE:
1072 default:
1073 *h = win_w * p_pic->i_height / p_pic->i_width;
1074 break;
1077 if( *h > win_h )
1079 *h = win_h;
1080 switch( p_pic->i_aspect_ratio )
1082 case AR_3_4_PICTURE:
1083 *w = win_h * 4 / 3;
1084 break;
1086 case AR_16_9_PICTURE:
1087 *w = win_h * 16 / 9;
1088 break;
1090 case AR_221_1_PICTURE:
1091 *w = win_h * 221 / 100;
1092 break;
1094 case AR_SQUARE_PICTURE:
1095 default:
1096 *w = win_h * p_pic->i_width / p_pic->i_height;
1097 break;
1102 /* Set picture position */
1103 *dx = (win_w - *w) / 2;
1104 *dy = (win_h - *h) / 2;
1108 static int XVideoGetPort( Display *dpy )
1110 int i, i_adaptors;
1111 int xv_port = -1;
1112 XvAdaptorInfo *adaptor_info;
1114 switch( XvQueryAdaptors( dpy, DefaultRootWindow( dpy ),
1115 &i_adaptors, &adaptor_info ) )
1117 case Success:
1118 break;
1120 case XvBadExtension:
1121 intf_ErrMsg( "vout error: XvBadExtension for XvQueryAdaptors" );
1122 return( -1 );
1124 case XvBadAlloc:
1125 intf_ErrMsg( "vout error: XvBadAlloc for XvQueryAdaptors" );
1126 return( -1 );
1128 default:
1129 intf_ErrMsg( "vout error: XvQueryAdaptors failed" );
1130 return( -1 );
1133 for( i=0; i < i_adaptors && xv_port == -1; ++i )
1134 if( ( adaptor_info[ i ].type & XvInputMask ) &&
1135 ( adaptor_info[ i ].type & XvImageMask ) )
1137 /* check that port supports YUV12 planar format... */
1138 int port = adaptor_info[ i ].base_id;
1139 int i_num_formats, i;
1140 XvImageFormatValues *imageFormats;
1142 imageFormats = XvListImageFormats( dpy, port, &i_num_formats );
1144 for( i=0; i < i_num_formats && xv_port == -1; ++i )
1145 if( imageFormats[ i ].id == GUID_YUV12_PLANAR )
1146 xv_port = port;
1148 if( xv_port == -1 )
1149 intf_WarnMsg( 3, "vout: XVideo image input port %d "
1150 "does not support the YUV12 planar format which is "
1151 "currently required by the xvideo output plugin.",
1152 port );
1154 if( imageFormats )
1155 XFree( imageFormats );
1158 if( i_adaptors > 0 )
1159 XvFreeAdaptorInfo(adaptor_info);
1161 if( xv_port == -1 )
1162 intf_ErrMsg( "vout error: didn't find a suitable Xvideo image input port." );
1164 return( xv_port );
1168 /*****************************************************************************
1169 * XVideoDisplay: display image
1170 *****************************************************************************
1171 * This function displays the image stored in p_vout->p_sys->p_xvimage.
1172 * The image is scaled to fit in the output window (and to have the correct
1173 * aspect ratio).
1174 *****************************************************************************/
1175 static void XVideoDisplay( vout_thread_t *p_vout )
1177 int i_dest_width, i_dest_height, i_dest_x, i_dest_y;
1179 if( !p_vout->p_sys->p_xvimage ) return;
1181 XVideoOutputCoords( p_vout->p_rendered_pic, p_vout->b_scale,
1182 p_vout->p_sys->i_window_width,
1183 p_vout->p_sys->i_window_height,
1184 &i_dest_x, &i_dest_y,
1185 &i_dest_width, &i_dest_height);
1187 XvShmPutImage( p_vout->p_sys->p_display, p_vout->p_sys->xv_port,
1188 p_vout->p_sys->yuv_window, p_vout->p_sys->gc,
1189 p_vout->p_sys->p_xvimage,
1190 0 /*src_x*/, 0 /*src_y*/,
1191 p_vout->p_rendered_pic->i_width,
1192 p_vout->p_rendered_pic->i_height,
1193 0 /*dest_x*/, 0 /*dest_y*/, i_dest_width, i_dest_height,
1194 True );
1196 XResizeWindow( p_vout->p_sys->p_display, p_vout->p_sys->yuv_window,
1197 i_dest_width, i_dest_height );
1198 XMoveWindow( p_vout->p_sys->p_display, p_vout->p_sys->yuv_window,
1199 i_dest_x, i_dest_y );
1202 #if 0
1203 /*****************************************************************************
1204 * XVideoSetAttribute
1205 *****************************************************************************
1206 * This function can be used to set attributes, e.g. XV_BRIGHTNESS and
1207 * XV_CONTRAST. "f_value" should be in the range of 0 to 1.
1208 *****************************************************************************/
1209 static void XVideoSetAttribute( vout_thread_t *p_vout,
1210 char *attr_name, float f_value )
1212 int i_attrib;
1213 XvAttribute *p_attrib;
1214 Display *p_dpy = p_vout->p_sys->p_display;
1215 int xv_port = p_vout->p_sys->xv_port;
1217 p_attrib = XvQueryPortAttributes( p_dpy, xv_port, &i_attrib );
1221 i_attrib--;
1223 if( i_attrib >= 0 && !strcmp( p_attrib[ i_attrib ].name, attr_name ) )
1225 int i_sv = f_value * ( p_attrib[ i_attrib ].max_value
1226 - p_attrib[ i_attrib ].min_value + 1 )
1227 + p_attrib[ i_attrib ].min_value;
1229 XvSetPortAttribute( p_dpy, xv_port,
1230 XInternAtom( p_dpy, attr_name, False ), i_sv );
1231 break;
1234 } while( i_attrib > 0 );
1236 if( p_attrib )
1237 XFree( p_attrib );
1239 #endif