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.5 2001/04/11 02:01:24 henri Exp $
7 * Authors: Shane Harper <shanegh@optusnet.com.au>
8 * Vincent Seguin <seguin@via.ecp.fr>
9 * Samuel Hocevar <sam@zoy.org>
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
24 *****************************************************************************/
26 #define MODULE_NAME xvideo
27 #include "modules_inner.h"
29 /*****************************************************************************
31 *****************************************************************************/
34 #include <errno.h> /* ENOMEM */
35 #include <stdlib.h> /* free() */
36 #include <string.h> /* strerror() */
38 #ifdef HAVE_MACHINE_PARAM_H
40 #include <machine/param.h>
41 #include <sys/types.h> /* typedef ushort */
45 #include <sys/shm.h> /* shmget(), shmctl() */
47 #include <X11/Xutil.h>
48 #include <X11/keysym.h>
49 #include <X11/extensions/XShm.h>
50 #include <X11/extensions/Xv.h>
51 #include <X11/extensions/Xvlib.h>
61 #include "video_output.h"
63 #include "interface.h"
66 #include "netutils.h" /* network_ChannelJoin */
70 /*****************************************************************************
71 * vout_sys_t: video output X11 method descriptor
72 *****************************************************************************
73 * This structure is part of the video output thread descriptor.
74 * It describes the X11 specific properties of an output thread. X11 video
75 * output is performed through regular resizable windows. Windows can be
76 * dynamically resized to adapt to the size of the streams.
77 *****************************************************************************/
78 typedef struct vout_sys_s
82 /* this plugin (currently) requires the SHM Ext... */
83 boolean_t b_shm; /* shared memory extension flag */
86 /* Internal settings and properties */
87 Display * p_display; /* display pointer */
88 int i_screen; /* screen number */
89 Window window; /* root window */
90 GC gc; /* graphic context instance handler */
93 /* Display buffers and shared memory information */
94 /* Note: only 1 buffer (I don't know why the X11 plugin had 2.) */
96 XShmSegmentInfo shm_info; /* shared memory zone information */
98 /* X11 generic properties */
100 Atom wm_delete_window;
102 int i_width; /* width of main window */
103 int i_height; /* height of main window */
105 /* Screen saver properties */
106 int i_ss_timeout; /* timeout */
107 int i_ss_interval; /* interval between changes */
108 int i_ss_blanking; /* blanking mode */
109 int i_ss_exposure; /* exposure mode */
111 /* Auto-hide cursor */
114 /* Mouse pointer properties */
115 boolean_t b_mouse; /* is the mouse pointer displayed ? */
119 /*****************************************************************************
121 *****************************************************************************/
122 static int vout_Probe ( probedata_t * );
123 static int vout_Create ( vout_thread_t * );
124 static int vout_Init ( vout_thread_t * );
125 static void vout_End ( vout_thread_t * );
126 static void vout_Destroy ( vout_thread_t * );
127 static int vout_Manage ( vout_thread_t * );
128 static void vout_Display ( vout_thread_t * );
129 static void vout_SetPalette( vout_thread_t *, u16 *, u16 *, u16 *, u16 * );
131 static int XVideoCreateWindow ( vout_thread_t * );
132 static int XVideoCreateShmImage ( vout_thread_t *, XvImage **,
133 XShmSegmentInfo *p_shm_info );
134 static void XVideoDestroyShmImage ( vout_thread_t *, XvImage *,
136 static void XVideoTogglePointer ( vout_thread_t * );
137 static void XVideoEnableScreenSaver ( vout_thread_t * );
138 static void XVideoDisableScreenSaver ( vout_thread_t * );
139 static void XVideoSetAttribute ( vout_thread_t *, char *, float );
141 static int XVideoCheckForXv ( Display * );
142 static int XVideoGetPort ( Display * );
143 static void XVideoOutputCoords ( const picture_t *, const boolean_t,
144 const int, const int,
145 int *, int *, int *, int * );
147 /*****************************************************************************
148 * Functions exported as capabilities. They are declared as static so that
149 * we don't pollute the namespace too much.
150 *****************************************************************************/
151 void _M( vout_getfunctions )( function_list_t * p_function_list )
153 p_function_list->pf_probe = vout_Probe;
154 p_function_list->functions.vout.pf_create = vout_Create;
155 p_function_list->functions.vout.pf_init = vout_Init;
156 p_function_list->functions.vout.pf_end = vout_End;
157 p_function_list->functions.vout.pf_destroy = vout_Destroy;
158 p_function_list->functions.vout.pf_manage = vout_Manage;
159 p_function_list->functions.vout.pf_display = vout_Display;
160 p_function_list->functions.vout.pf_setpalette = vout_SetPalette;
163 /*****************************************************************************
164 * vout_Probe: probe the video driver and return a score
165 *****************************************************************************
166 * This returns a score to the plugin manager so that it can select the best
168 *****************************************************************************/
169 static int vout_Probe( probedata_t *p_data )
171 if( TestMethod( VOUT_METHOD_VAR, "xvideo" ) )
179 /*****************************************************************************
180 * vout_Create: allocate XVideo video thread output method
181 *****************************************************************************
182 * This function allocate and initialize a X11 vout method. It uses some of the
183 * vout properties to choose the window size, and change them according to the
184 * actual properties of the display.
185 *****************************************************************************/
186 static int vout_Create( vout_thread_t *p_vout )
190 /* Allocate structure */
191 p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
192 if( p_vout->p_sys == NULL )
194 intf_ErrMsg( "vout error: %s", strerror(ENOMEM) );
198 /* Open display, unsing 'vlc_display' or DISPLAY environment variable */
199 psz_display = XDisplayName( main_GetPszVariable( VOUT_DISPLAY_VAR, NULL ) );
200 p_vout->p_sys->p_display = XOpenDisplay( psz_display );
202 if( p_vout->p_sys->p_display == NULL ) /* error */
204 intf_ErrMsg( "vout error: cannot open display %s", psz_display );
205 free( p_vout->p_sys );
208 p_vout->p_sys->i_screen = DefaultScreen( p_vout->p_sys->p_display );
210 if( !XVideoCheckForXv( p_vout->p_sys->p_display ) )
212 intf_ErrMsg( "vout error: no XVideo extension" );
213 XCloseDisplay( p_vout->p_sys->p_display );
214 free( p_vout->p_sys );
218 /* Spawn base window - this window will include the video output window,
219 * but also command buttons, subtitles and other indicators */
220 if( XVideoCreateWindow( p_vout ) )
222 intf_ErrMsg( "vout error: cannot create XVideo window" );
223 XCloseDisplay( p_vout->p_sys->p_display );
224 free( p_vout->p_sys );
228 if( (p_vout->p_sys->xv_port = XVideoGetPort( p_vout->p_sys->p_display ))<0 )
231 /* XXX The brightness and contrast values should be read from environment
232 * XXX variables... */
233 XVideoSetAttribute( p_vout, "XV_BRIGHTNESS", 0.5 );
234 XVideoSetAttribute( p_vout, "XV_CONTRAST", 0.5 );
236 p_vout->p_sys->b_mouse = 1;
238 /* Disable screen saver and return */
239 XVideoDisableScreenSaver( p_vout );
244 /*****************************************************************************
245 * vout_Init: initialize XVideo video thread output method
246 *****************************************************************************
247 * This function creates the XvImage needed by the output thread. It is called
248 * at the beginning of the thread, but also each time the window is resized.
249 *****************************************************************************/
250 static int vout_Init( vout_thread_t *p_vout )
255 /* FIXME : As of 2001-03-16, XFree4 for MacOS X does not support Xshm. */
256 p_vout->p_sys->b_shm = 0;
259 /* Create XvImage using XShm extension */
260 i_err = XVideoCreateShmImage( p_vout, &p_vout->p_sys->p_xvimage,
261 &p_vout->p_sys->shm_info );
264 intf_Msg( "vout: XShm video extension unavailable" );
265 /* p_vout->p_sys->b_shm = 0; */
267 p_vout->b_need_render = 0;
269 /* Set bytes per line and initialize buffers */
270 p_vout->i_bytes_per_line =
271 (p_vout->p_sys->p_xvimage->data_size) /
272 (p_vout->p_sys->p_xvimage->height);
274 /* vout_SetBuffers( p_vout, p_vout->p_sys->p_xvimage[0]->data,
275 * p_vout->p_sys->p_xvimage[1]->data ); */
276 p_vout->p_buffer[0].i_pic_x = 0;
277 p_vout->p_buffer[0].i_pic_y = 0;
278 p_vout->p_buffer[0].i_pic_width = 0;
279 p_vout->p_buffer[0].i_pic_height = 0;
281 /* The first area covers all the screen */
282 p_vout->p_buffer[0].i_areas = 1;
283 p_vout->p_buffer[0].pi_area_begin[0] = 0;
284 p_vout->p_buffer[0].pi_area_end[0] = p_vout->i_height - 1;
287 p_vout->p_buffer[0].p_data = p_vout->p_sys->p_xvimage->data;
291 /*****************************************************************************
292 * vout_End: terminate XVideo video thread output method
293 *****************************************************************************
294 * Destroy the XVideo xImages created by vout_Init. It is called at the end of
295 * the thread, but also each time the window is resized.
296 *****************************************************************************/
297 static void vout_End( vout_thread_t *p_vout )
299 XVideoDestroyShmImage( p_vout, p_vout->p_sys->p_xvimage,
300 &p_vout->p_sys->shm_info );
303 /*****************************************************************************
304 * vout_Destroy: destroy XVideo video thread output method
305 *****************************************************************************
306 * Terminate an output method created by vout_CreateOutputMethod
307 *****************************************************************************/
308 static void vout_Destroy( vout_thread_t *p_vout )
310 /* Enable screen saver */
311 XVideoEnableScreenSaver( p_vout );
314 XUnmapWindow( p_vout->p_sys->p_display, p_vout->p_sys->window );
315 XFreeGC( p_vout->p_sys->p_display, p_vout->p_sys->gc );
316 XDestroyWindow( p_vout->p_sys->p_display, p_vout->p_sys->window );
318 XCloseDisplay( p_vout->p_sys->p_display );
320 /* Destroy structure */
321 free( p_vout->p_sys );
324 /*****************************************************************************
325 * vout_Manage: handle X11 events
326 *****************************************************************************
327 * This function should be called regularly by video output thread. It manages
328 * X11 events and allows window resizing. It returns a non null value on
331 * XXX Should "factor-out" common code in this and the "same" fn in the x11
333 *****************************************************************************/
334 static int vout_Manage( vout_thread_t *p_vout )
336 XEvent xevent; /* X11 event */
337 boolean_t b_resized; /* window has been resized */
338 char i_key; /* ISO Latin-1 key */
341 /* Handle X11 events: ConfigureNotify events are parsed to know if the
342 * output window's size changed, MapNotify and UnmapNotify to know if the
343 * window is mapped (and if the display is useful), and ClientMessages
344 * to intercept window destruction requests */
346 while( XCheckWindowEvent( p_vout->p_sys->p_display, p_vout->p_sys->window,
347 StructureNotifyMask | KeyPressMask |
348 ButtonPressMask | ButtonReleaseMask |
349 PointerMotionMask, &xevent )
352 /* ConfigureNotify event: prepare */
353 if( (xevent.type == ConfigureNotify)
354 && ((xevent.xconfigure.width != p_vout->p_sys->i_width)
355 || (xevent.xconfigure.height != p_vout->p_sys->i_height)) )
357 /* Update dimensions */
360 p_vout->p_sys->i_width = xevent.xconfigure.width;
361 p_vout->p_sys->i_height = xevent.xconfigure.height;
364 /* MapNotify event: change window status and disable screen saver */
365 else if( xevent.type == MapNotify)
367 if( (p_vout != NULL) && !p_vout->b_active )
369 XVideoDisableScreenSaver( p_vout );
370 p_vout->b_active = 1;
373 /* UnmapNotify event: change window status and enable screen saver */
374 else if( xevent.type == UnmapNotify )
376 if( (p_vout != NULL) && p_vout->b_active )
378 XVideoEnableScreenSaver( p_vout );
379 p_vout->b_active = 0;
383 else if( xevent.type == KeyPress )
385 /* We may have keys like F1 trough F12, ESC ... */
386 x_key_symbol = XKeycodeToKeysym( p_vout->p_sys->p_display,
387 xevent.xkey.keycode, 0 );
388 switch( x_key_symbol )
391 p_main->p_intf->b_die = 1;
394 p_main->p_intf->b_menu_change = 1;
398 * The reason why I use this instead of XK_0 is that
399 * with XLookupString, we don't have to care about
402 if( XLookupString( &xevent.xkey, &i_key, 1, NULL, NULL ) )
404 /* FIXME: handle stuff here */
409 p_main->p_intf->b_die = 1;
412 network_ChannelJoin( 0 );
415 network_ChannelJoin( 1 );
418 network_ChannelJoin( 2 );
421 network_ChannelJoin( 3 );
424 network_ChannelJoin( 4 );
427 network_ChannelJoin( 5 );
430 network_ChannelJoin( 6 );
433 network_ChannelJoin( 7 );
436 network_ChannelJoin( 8 );
439 network_ChannelJoin( 9 );
442 if( intf_ProcessKey( p_main->p_intf,
445 intf_DbgMsg( "unhandled key '%c' (%i)",
446 (char)i_key, i_key );
455 else if( xevent.type == ButtonPress )
457 switch( ((XButtonEvent *)&xevent)->button )
460 /* in this part we will eventually manage
461 * clicks for DVD navigation for instance */
466 else if( xevent.type == ButtonRelease )
468 switch( ((XButtonEvent *)&xevent)->button )
471 /* FIXME: need locking ! */
472 p_main->p_intf->b_menu_change = 1;
477 else if( xevent.type == MotionNotify )
479 p_vout->p_sys->i_lastmoved = mdate();
480 if( ! p_vout->p_sys->b_mouse )
482 XVideoTogglePointer( p_vout );
490 intf_DbgMsg( "%p -> unhandled event type %d received",
491 p_vout, xevent.type );
496 /* ClientMessage event - only WM_PROTOCOLS with WM_DELETE_WINDOW data
497 * are handled - according to the man pages, the format is always 32
499 while( XCheckTypedEvent( p_vout->p_sys->p_display,
500 ClientMessage, &xevent ) )
502 if( (xevent.xclient.message_type == p_vout->p_sys->wm_protocols)
503 && (xevent.xclient.data.l[0] == p_vout->p_sys->wm_delete_window ) )
505 p_main->p_intf->b_die = 1;
509 intf_DbgMsg( "%p -> unhandled ClientMessage received", p_vout );
513 if( (p_vout->i_width != p_vout->p_sys->i_width) ||
514 (p_vout->i_height != p_vout->p_sys->i_height) )
516 /* If video output size has changed, change interface window size */
517 intf_DbgMsg( "resizing output window" );
518 p_vout->p_sys->i_width = p_vout->i_width;
519 p_vout->p_sys->i_height = p_vout->i_height;
520 XResizeWindow( p_vout->p_sys->p_display, p_vout->p_sys->window,
521 p_vout->p_sys->i_width, p_vout->p_sys->i_height );
524 if( (p_vout->i_changes & VOUT_GRAYSCALE_CHANGE))
526 /* FIXME: clear flags ?? */
532 if( p_vout->i_changes & VOUT_SIZE_CHANGE )
534 intf_DbgMsg( "vout: resizing window" );
535 p_vout->i_changes &= ~VOUT_SIZE_CHANGE;
538 XResizeWindow( p_vout->p_sys->p_display, p_vout->p_sys->window,
539 p_vout->i_width, p_vout->i_height );
541 /* Destroy XImages to change their size */
544 /* Recreate XImages. If SysInit failed, the thread cannot go on. */
545 if( vout_Init( p_vout ) )
547 intf_ErrMsg( "vout error: cannot resize display" );
551 intf_Msg( "vout: video display resized (%dx%d)",
552 p_vout->i_width, p_vout->i_height );
555 /* Autohide Cursour */
556 if( mdate() - p_vout->p_sys->i_lastmoved > 2000000 )
558 /* Hide the mouse automatically */
559 if( p_vout->p_sys->b_mouse )
561 XVideoTogglePointer( p_vout );
569 /*****************************************************************************
570 * vout_Display: displays previously rendered output
571 *****************************************************************************
572 * This function send the currently rendered image to X11 server, wait until
573 * it is displayed and switch the two rendering buffer, preparing next frame.
574 *****************************************************************************/
575 static void vout_Display( vout_thread_t *p_vout )
577 boolean_t b_draw = 1;
578 const int i_size = p_vout->i_width * p_vout->i_height;
580 switch( p_vout->p_rendered_pic->i_type )
582 case YUV_422_PICTURE:
583 intf_ErrMsg( "vout error: YUV_422_PICTURE not (yet) supported" );
587 case YUV_444_PICTURE:
588 intf_ErrMsg( "vout error: YUV_444_PICTURE not (yet) supported" );
592 case YUV_420_PICTURE:
593 memcpy( p_vout->p_sys->p_xvimage->data,
594 p_vout->p_rendered_pic->p_y, i_size );
595 memcpy( p_vout->p_sys->p_xvimage->data + ( i_size ),
596 p_vout->p_rendered_pic->p_v, i_size / 4 );
597 memcpy( p_vout->p_sys->p_xvimage->data + ( i_size ) + ( i_size / 4 ),
598 p_vout->p_rendered_pic->p_u, i_size / 4 );
604 int i_dummy, i_src_width, i_src_height,
605 i_dest_width, i_dest_height, i_dest_x, i_dest_y;
608 /* Could use p_vout->p_sys->i_width and p_vout->p_sys->i_height
609 *instead of calling XGetGeometry? */
610 XGetGeometry( p_vout->p_sys->p_display, p_vout->p_sys->window,
611 &window, &i_dummy, &i_dummy,
612 &i_src_width, &i_src_height, &i_dummy, &i_dummy );
614 XVideoOutputCoords( p_vout->p_rendered_pic, p_vout->b_scale,
615 i_src_width, i_src_height, &i_dest_x, &i_dest_y,
616 &i_dest_width, &i_dest_height);
618 XvShmPutImage( p_vout->p_sys->p_display, p_vout->p_sys->xv_port,
619 p_vout->p_sys->window, p_vout->p_sys->gc,
620 p_vout->p_sys->p_xvimage,
621 0 /*src_x*/, 0 /*src_y*/,
622 p_vout->p_rendered_pic->i_width,
623 p_vout->p_rendered_pic->i_height,
624 i_dest_x, i_dest_y, i_dest_width, i_dest_height,
629 static void vout_SetPalette( p_vout_thread_t p_vout,
630 u16 *red, u16 *green, u16 *blue, u16 *transp )
635 /* following functions are local */
637 /*****************************************************************************
638 * XVideoCheckForXv: check for the XVideo extension
639 *****************************************************************************/
640 static int XVideoCheckForXv( Display *dpy )
644 switch( XvQueryExtension( dpy, &i, &i, &i, &i, &i ) )
650 intf_ErrMsg( "vout error: XvBadExtension" );
654 intf_ErrMsg( "vout error: XvBadAlloc" );
658 intf_ErrMsg( "vout error: XvQueryExtension failed" );
663 /*****************************************************************************
664 * XVideoCreateWindow: open and set-up XVideo main window
665 *****************************************************************************/
666 static int XVideoCreateWindow( vout_thread_t *p_vout )
668 XSizeHints xsize_hints;
669 XSetWindowAttributes xwindow_attributes;
673 boolean_t b_configure_notify;
674 boolean_t b_map_notify;
676 /* Set main window's size */
677 p_vout->p_sys->i_width = main_GetIntVariable( VOUT_WIDTH_VAR,
678 VOUT_WIDTH_DEFAULT );
679 p_vout->p_sys->i_height = main_GetIntVariable( VOUT_HEIGHT_VAR,
680 VOUT_HEIGHT_DEFAULT );
682 /* Prepare window manager hints and properties */
683 xsize_hints.base_width = p_vout->p_sys->i_width;
684 xsize_hints.base_height = p_vout->p_sys->i_height;
685 xsize_hints.flags = PSize;
686 p_vout->p_sys->wm_protocols = XInternAtom( p_vout->p_sys->p_display,
687 "WM_PROTOCOLS", True );
688 p_vout->p_sys->wm_delete_window = XInternAtom( p_vout->p_sys->p_display,
689 "WM_DELETE_WINDOW", True );
691 /* Prepare window attributes */
692 xwindow_attributes.backing_store = Always; /* save the hidden part */
693 xwindow_attributes.background_pixel = BlackPixel( p_vout->p_sys->p_display,
694 p_vout->p_sys->i_screen );
696 xwindow_attributes.event_mask = ExposureMask | StructureNotifyMask;
698 /* Create the window and set hints - the window must receive ConfigureNotify
699 * events, and, until it is displayed, Expose and MapNotify events. */
700 p_vout->p_sys->window =
701 XCreateWindow( p_vout->p_sys->p_display,
702 DefaultRootWindow( p_vout->p_sys->p_display ),
704 p_vout->p_sys->i_width, p_vout->p_sys->i_height, 1,
706 CWBackingStore | CWBackPixel | CWEventMask,
707 &xwindow_attributes );
709 /* Set window manager hints and properties: size hints, command,
710 * window's name, and accepted protocols */
711 XSetWMNormalHints( p_vout->p_sys->p_display, p_vout->p_sys->window,
713 XSetCommand( p_vout->p_sys->p_display, p_vout->p_sys->window,
714 p_main->ppsz_argv, p_main->i_argc );
715 XStoreName( p_vout->p_sys->p_display, p_vout->p_sys->window,
716 VOUT_TITLE " (XVideo output)" );
718 if( (p_vout->p_sys->wm_protocols == None) /* use WM_DELETE_WINDOW */
719 || (p_vout->p_sys->wm_delete_window == None)
720 || !XSetWMProtocols( p_vout->p_sys->p_display, p_vout->p_sys->window,
721 &p_vout->p_sys->wm_delete_window, 1 ) )
723 /* WM_DELETE_WINDOW is not supported by window manager */
724 intf_Msg( "vout error: missing or bad window manager" );
727 /* Creation of a graphic context that doesn't generate a GraphicsExpose
728 * event when using functions like XCopyArea */
729 xgcvalues.graphics_exposures = False;
730 p_vout->p_sys->gc = XCreateGC( p_vout->p_sys->p_display,
731 p_vout->p_sys->window,
732 GCGraphicsExposures, &xgcvalues);
734 /* Send orders to server, and wait until window is displayed - three
735 * events must be received: a MapNotify event, an Expose event allowing
736 * drawing in the window, and a ConfigureNotify to get the window
737 * dimensions. Once those events have been received, only ConfigureNotify
738 * events need to be received. */
740 b_configure_notify = 0;
742 XMapWindow( p_vout->p_sys->p_display, p_vout->p_sys->window);
745 XNextEvent( p_vout->p_sys->p_display, &xevent);
746 if( (xevent.type == Expose)
747 && (xevent.xexpose.window == p_vout->p_sys->window) )
751 else if( (xevent.type == MapNotify)
752 && (xevent.xmap.window == p_vout->p_sys->window) )
756 else if( (xevent.type == ConfigureNotify)
757 && (xevent.xconfigure.window == p_vout->p_sys->window) )
759 b_configure_notify = 1;
760 p_vout->p_sys->i_width = xevent.xconfigure.width;
761 p_vout->p_sys->i_height = xevent.xconfigure.height;
763 } while( !( b_expose && b_configure_notify && b_map_notify ) );
765 XSelectInput( p_vout->p_sys->p_display, p_vout->p_sys->window,
766 StructureNotifyMask | KeyPressMask |
767 ButtonPressMask | ButtonReleaseMask |
770 /* At this stage, the window is open, displayed, and ready to
775 /*****************************************************************************
776 * XVideoCreateShmImage: create an XvImage using shared memory extension
777 *****************************************************************************
778 * Prepare an XvImage for display function.
779 * The order of the operations respects the recommandations of the mit-shm
780 * document by J.Corbet and K.Packard. Most of the parameters were copied from
782 *****************************************************************************/
783 static int XVideoCreateShmImage( vout_thread_t *p_vout, XvImage **pp_xvimage,
784 XShmSegmentInfo *p_shm_info)
786 #define GUID_YUV12_PLANAR 0x32315659
788 *pp_xvimage = XvShmCreateImage( p_vout->p_sys->p_display,
789 p_vout->p_sys->xv_port,
790 GUID_YUV12_PLANAR, 0,
791 p_vout->i_width, p_vout->i_height,
794 p_shm_info->shmid = shmget( IPC_PRIVATE, (*pp_xvimage)->data_size,
796 p_shm_info->shmaddr = (*pp_xvimage)->data = shmat( p_shm_info->shmid,
798 p_shm_info->readOnly = False;
800 shmctl( p_shm_info->shmid, IPC_RMID, 0 ); /* XXX */
802 if( !XShmAttach(p_vout->p_sys->p_display, p_shm_info) )
804 intf_ErrMsg( "vout error: XShmAttach failed" );
808 /* Send image to X server. This instruction is required, since having
809 * built a Shm XImage and not using it causes an error on XCloseDisplay */
810 XFlush( p_vout->p_sys->p_display );
815 /*****************************************************************************
816 * XVideoDestroyShmImage
817 *****************************************************************************
818 * Destroy XImage AND associated data. Detach shared memory segment from
819 * server and process, then free it. If pointer is NULL, the image won't be
820 * destroyed (see vout_ManageOutputMethod())
821 *****************************************************************************/
822 static void XVideoDestroyShmImage( vout_thread_t *p_vout, XvImage *p_xvimage,
823 XShmSegmentInfo *p_shm_info )
825 /* If pointer is NULL, do nothing */
826 if( p_xvimage == NULL )
831 XShmDetach( p_vout->p_sys->p_display, p_shm_info );/* detach from server */
833 XDestroyImage( p_ximage );
835 /* XvDestroyImage( p_xvimage ); XXX */
838 if( shmdt( p_shm_info->shmaddr ) ) /* detach shared memory from process */
839 { /* also automatic freeing... */
840 intf_ErrMsg( "vout error: cannot detach shared memory (%s)",
845 /*****************************************************************************
846 * XVideoEnableScreenSaver: enable screen saver
847 *****************************************************************************
848 * This function enable the screen saver on a display after it had been
849 * disabled by XDisableScreenSaver. Both functions use a counter mechanism to
850 * know wether the screen saver can be activated or not: if n successive calls
851 * are made to XDisableScreenSaver, n successive calls to XEnableScreenSaver
852 * will be required before the screen saver could effectively be activated.
853 *****************************************************************************/
854 void XVideoEnableScreenSaver( vout_thread_t *p_vout )
856 intf_DbgMsg( "intf: enabling screen saver" );
857 XSetScreenSaver( p_vout->p_sys->p_display, p_vout->p_sys->i_ss_timeout,
858 p_vout->p_sys->i_ss_interval,
859 p_vout->p_sys->i_ss_blanking,
860 p_vout->p_sys->i_ss_exposure );
863 /*****************************************************************************
864 * XVideoDisableScreenSaver: disable screen saver
865 *****************************************************************************
866 * See XEnableScreenSaver
867 *****************************************************************************/
868 void XVideoDisableScreenSaver( vout_thread_t *p_vout )
870 /* Save screen saver informations */
871 XGetScreenSaver( p_vout->p_sys->p_display, &p_vout->p_sys->i_ss_timeout,
872 &p_vout->p_sys->i_ss_interval,
873 &p_vout->p_sys->i_ss_blanking,
874 &p_vout->p_sys->i_ss_exposure );
876 /* Disable screen saver */
877 intf_DbgMsg( "intf: disabling screen saver" );
878 XSetScreenSaver( p_vout->p_sys->p_display, 0,
879 p_vout->p_sys->i_ss_interval,
880 p_vout->p_sys->i_ss_blanking,
881 p_vout->p_sys->i_ss_exposure );
884 /*****************************************************************************
885 * XVideoTogglePointer: hide or show the mouse pointer
886 *****************************************************************************
887 * This function hides the X pointer if it is visible by putting it at
888 * coordinates (32,32) and setting the pointer sprite to a blank one. To
889 * show it again, we disable the sprite and restore the original coordinates.
890 *****************************************************************************/
891 void XVideoTogglePointer( vout_thread_t *p_vout )
893 static Cursor cursor;
894 static boolean_t b_cursor = 0;
896 if( p_vout->p_sys->b_mouse )
898 p_vout->p_sys->b_mouse = 0;
903 Pixmap blank = XCreatePixmap( p_vout->p_sys->p_display,
904 DefaultRootWindow(p_vout->p_sys->p_display),
907 XParseColor( p_vout->p_sys->p_display,
908 XCreateColormap( p_vout->p_sys->p_display,
910 p_vout->p_sys->p_display ),
912 p_vout->p_sys->p_display,
913 p_vout->p_sys->i_screen ),
917 cursor = XCreatePixmapCursor( p_vout->p_sys->p_display,
918 blank, blank, &color, &color, 1, 1 );
922 XDefineCursor( p_vout->p_sys->p_display,
923 p_vout->p_sys->window, cursor );
927 p_vout->p_sys->b_mouse = 1;
929 XUndefineCursor( p_vout->p_sys->p_display, p_vout->p_sys->window );
933 /* This based on some code in SetBufferPicture... At the moment it's only
934 * used by the xvideo plugin, but others may want to use it. */
935 static void XVideoOutputCoords( const picture_t *p_pic, const boolean_t scale,
936 const int win_w, const int win_h,
937 int *dx, int *dy, int *w, int *h)
941 *w = p_pic->i_width; *h = p_pic->i_height;
946 switch( p_pic->i_aspect_ratio )
948 case AR_3_4_PICTURE: *h = win_w * 3 / 4; break;
949 case AR_16_9_PICTURE: *h = win_w * 9 / 16; break;
950 case AR_221_1_PICTURE: *h = win_w * 100 / 221; break;
951 case AR_SQUARE_PICTURE:
952 default: *h = win_w; break;
958 switch( p_pic->i_aspect_ratio )
960 case AR_3_4_PICTURE: *w = win_h * 4 / 3; break;
961 case AR_16_9_PICTURE: *w = win_h * 16 / 9; break;
962 case AR_221_1_PICTURE: *w = win_h * 221 / 100; break;
963 case AR_SQUARE_PICTURE:
964 default: *w = win_h; break;
969 /* Set picture position */
970 *dx = (win_w - *w) / 2;
971 *dy = (win_h - *h) / 2;
975 static int XVideoGetPort( Display *dpy )
978 XvAdaptorInfo *adaptor_info;
980 switch( XvQueryAdaptors( dpy, DefaultRootWindow( dpy ),
981 &i_adaptors, &adaptor_info ) )
987 intf_ErrMsg( "vout error: XvBadExtension for XvQueryAdaptors" );
991 intf_ErrMsg( "vout error: XvBadAlloc for XvQueryAdaptors" );
995 intf_ErrMsg( "vout error: XvQueryAdaptors failed" );
999 for( i=0; i < i_adaptors; ++i )
1000 if( ( adaptor_info[ i ].type & XvInputMask ) &&
1001 ( adaptor_info[ i ].type & XvImageMask ) )
1003 return adaptor_info[ i ].base_id;
1006 intf_ErrMsg( "vout error: didn't find an Xvideo image input port." );
1011 /*****************************************************************************
1012 * XVideoSetAttribute
1013 *****************************************************************************
1014 * This function can be used to set attributes, e.g. XV_BRIGHTNESS and
1015 * XV_CONTRAST. "value" should be in the range of 0 to 1.
1016 *****************************************************************************/
1017 static void XVideoSetAttribute( vout_thread_t *p_vout,
1018 char *attr_name, float f_value )
1021 XvAttribute *p_attrib;
1022 Display *p_dpy = p_vout->p_sys->p_display;
1023 int xv_port = p_vout->p_sys->xv_port;
1025 p_attrib = XvQueryPortAttributes( p_dpy, xv_port, &i_attrib );
1031 if( !strcmp( p_attrib[ i_attrib ].name, attr_name ) )
1033 int i_sv = f_value * ( p_attrib[ i_attrib ].max_value
1034 - p_attrib[ i_attrib ].min_value + 1 )
1035 + p_attrib[ i_attrib ].min_value;
1037 XvSetPortAttribute( p_dpy, xv_port,
1038 XInternAtom( p_dpy, attr_name, False ), i_sv );
1042 } while( i_attrib > 0 );