1 /*****************************************************************************
2 * xcommon.c: Functions common to the X11 and XVideo plugins
3 *****************************************************************************
4 * Copyright (C) 1998-2001 VideoLAN
5 * $Id: xcommon.c,v 1.1 2001/12/30 07:09:56 sam Exp $
7 * Authors: Vincent Seguin <seguin@via.ecp.fr>
8 * Samuel Hocevar <sam@zoy.org>
9 * David Kennedy <dkennedy@tinytoad.com>
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 /*****************************************************************************
28 *****************************************************************************/
29 #include <errno.h> /* ENOMEM */
30 #include <stdlib.h> /* free() */
31 #include <string.h> /* strerror() */
33 #include <videolan/vlc.h>
35 #ifdef HAVE_MACHINE_PARAM_H
37 #include <machine/param.h>
38 #include <sys/types.h> /* typedef ushort */
43 #include <netinet/in.h> /* BSD: struct in_addr */
46 #include <sys/shm.h> /* shmget(), shmctl() */
48 #include <X11/Xutil.h>
49 #include <X11/keysym.h>
50 #include <X11/extensions/XShm.h>
52 #ifdef MODULE_NAME_IS_xvideo
53 # include <X11/extensions/Xv.h>
54 # include <X11/extensions/Xvlib.h>
55 # include <X11/extensions/dpms.h>
59 #include "video_output.h"
62 #include "interface.h"
63 #include "netutils.h" /* network_ChannelJoin */
65 #include "stream_control.h" /* needed by input_ext-intf.h... */
66 #include "input_ext-intf.h"
68 #ifdef MODULE_NAME_IS_xvideo
69 # define IMAGE_TYPE XvImage
70 # define EXTRA_ARGS int i_xvport, int i_format
71 # define EXTRA_ARGS_SHM int i_xvport, int i_format, XShmSegmentInfo *p_shm
72 # define DATA_SIZE p_image->data_size
73 /* There is nothing like XvDestroyImage */
74 # define IMAGE_FREE XFree
76 # define IMAGE_TYPE XImage
77 # define EXTRA_ARGS Visual *p_visual, int i_depth, int i_bytes_per_pixel
78 # define EXTRA_ARGS_SHM Visual *p_visual, int i_depth, XShmSegmentInfo *p_shm
79 # define DATA_SIZE (p_image->bytes_per_line * p_image->height)
80 # define IMAGE_FREE XDestroyImage
83 /*****************************************************************************
85 *****************************************************************************/
86 static int vout_Probe ( probedata_t * );
87 static int vout_Create ( vout_thread_t * );
88 static void vout_Destroy ( vout_thread_t * );
89 static void vout_Display ( vout_thread_t *, picture_t * );
90 static int vout_Manage ( vout_thread_t * );
91 static int vout_Init ( vout_thread_t * );
92 static void vout_End ( vout_thread_t * );
94 static int InitDisplay ( vout_thread_t * );
96 static int CreateWindow ( vout_thread_t * );
97 static void DestroyWindow ( vout_thread_t * );
99 static int NewPicture ( vout_thread_t *, picture_t * );
100 static void FreePicture ( vout_thread_t *, picture_t * );
102 static IMAGE_TYPE *CreateImage ( Display *, EXTRA_ARGS, int, int );
103 static IMAGE_TYPE *CreateShmImage ( Display *, EXTRA_ARGS_SHM, int, int );
105 static void EnableXScreenSaver ( vout_thread_t * );
106 static void DisableXScreenSaver ( vout_thread_t * );
108 static void CreateCursor ( vout_thread_t * );
109 static void DestroyCursor ( vout_thread_t * );
110 static void ToggleCursor ( vout_thread_t * );
112 #ifdef MODULE_NAME_IS_xvideo
113 static int XVideoGetPort ( Display *, int );
114 static void XVideoReleasePort ( Display *, int );
117 /*****************************************************************************
118 * vout_sys_t: video output method descriptor
119 *****************************************************************************
120 * This structure is part of the video output thread descriptor.
121 * It describes the X11 and XVideo specific properties of an output thread.
122 *****************************************************************************/
123 typedef struct vout_sys_s
125 /* Internal settings and properties */
126 Display * p_display; /* display pointer */
128 Visual * p_visual; /* visual pointer */
129 int i_screen; /* screen number */
130 Window window; /* root window */
131 GC gc; /* graphic context instance handler */
133 boolean_t b_shm; /* shared memory extension flag */
135 #ifdef MODULE_NAME_IS_xvideo
136 Window yuv_window; /* sub-window for displaying yuv video
141 Colormap colormap; /* colormap used (8bpp only) */
144 int i_bytes_per_pixel;
145 int i_bytes_per_line;
151 /* X11 generic properties */
153 Atom wm_delete_window;
155 int i_width; /* width of main window */
156 int i_height; /* height of main window */
158 /* Screen saver properties */
159 int i_ss_timeout; /* timeout */
160 int i_ss_interval; /* interval between changes */
161 int i_ss_blanking; /* blanking mode */
162 int i_ss_exposure; /* exposure mode */
164 /* Mouse pointer properties */
165 boolean_t b_mouse_pointer_visible;
166 mtime_t i_time_mouse_last_moved; /* used to auto-hide pointer*/
167 Cursor blank_cursor; /* the hidden cursor */
168 Pixmap cursor_pixmap;
172 /*****************************************************************************
173 * picture_sys_t: direct buffer method descriptor
174 *****************************************************************************
175 * This structure is part of the picture descriptor, it describes the
176 * XVideo specific properties of a direct buffer.
177 *****************************************************************************/
178 typedef struct picture_sys_s
180 IMAGE_TYPE * p_image;
182 XShmSegmentInfo shminfo; /* shared memory zone information */
186 /*****************************************************************************
187 * mwmhints_t: window manager hints
188 *****************************************************************************
189 * Fullscreen needs to be able to hide the wm decorations so we provide
190 * this structure to make it easier.
191 *****************************************************************************/
192 #define MWM_HINTS_DECORATIONS (1L << 1)
193 #define PROP_MWM_HINTS_ELEMENTS 5
194 typedef struct mwmhints_s
203 /*****************************************************************************
205 *****************************************************************************/
206 #ifdef MODULE_NAME_IS_xvideo
207 # define GUID_YUV12_PLANAR 0x32315659
208 # define MAX_DIRECTBUFFERS 5
210 # define MAX_DIRECTBUFFERS 2
213 /*****************************************************************************
214 * Seeking function TODO: put this in a generic location !
215 *****************************************************************************/
216 static __inline__ void vout_Seek( off_t i_seek )
218 #define area p_main->p_intf->p_input->stream.p_selected_area
219 off_t i_tell = area->i_tell;
221 i_tell += i_seek * (off_t)50 * p_main->p_intf->p_input->stream.i_mux_rate;
223 i_tell = ( i_tell <= 0/*area->i_start*/ ) ? 0/*area->i_start*/
224 : ( i_tell >= area->i_size ) ? area->i_size
227 input_Seek( p_main->p_intf->p_input, i_tell );
231 /*****************************************************************************
232 * Functions exported as capabilities. They are declared as static so that
233 * we don't pollute the namespace too much.
234 *****************************************************************************/
235 void _M( vout_getfunctions )( function_list_t * p_function_list )
237 p_function_list->pf_probe = vout_Probe;
238 p_function_list->functions.vout.pf_create = vout_Create;
239 p_function_list->functions.vout.pf_init = vout_Init;
240 p_function_list->functions.vout.pf_end = vout_End;
241 p_function_list->functions.vout.pf_destroy = vout_Destroy;
242 p_function_list->functions.vout.pf_manage = vout_Manage;
243 p_function_list->functions.vout.pf_display = vout_Display;
244 p_function_list->functions.vout.pf_setpalette = NULL;
247 /*****************************************************************************
248 * vout_Probe: probe the video driver and return a score
249 *****************************************************************************
250 * This function tries to initialize SDL and returns a score to the
251 * plugin manager so that it can select the best plugin.
252 *****************************************************************************/
253 static int vout_Probe( probedata_t *p_data )
255 Display *p_display; /* display pointer */
257 #ifdef MODULE_NAME_IS_xvideo
261 /* Open display, unsing 'vlc_display' or DISPLAY environment variable */
262 psz_display = XDisplayName( main_GetPszVariable(VOUT_DISPLAY_VAR, NULL) );
263 p_display = XOpenDisplay( psz_display );
264 if( p_display == NULL ) /* error */
266 intf_WarnMsg( 3, "vout: cannot open display %s", psz_display );
270 #ifdef MODULE_NAME_IS_xvideo
271 /* Check that there is an available XVideo port */
272 i_xvport = XVideoGetPort( p_display, GUID_YUV12_PLANAR );
275 intf_WarnMsg( 3, "vout: no XVideo port available" );
276 XCloseDisplay( p_display );
279 XVideoReleasePort( p_display, i_xvport );
282 /* Clean-up everyting */
283 XCloseDisplay( p_display );
285 #ifdef MODULE_NAME_IS_xvideo
292 /*****************************************************************************
293 * vout_Create: allocate X11 video thread output method
294 *****************************************************************************
295 * This function allocate and initialize a X11 vout method. It uses some of the
296 * vout properties to choose the window size, and change them according to the
297 * actual properties of the display.
298 *****************************************************************************/
299 static int vout_Create( vout_thread_t *p_vout )
303 /* Allocate structure */
304 p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
305 if( p_vout->p_sys == NULL )
307 intf_ErrMsg( "vout error: %s", strerror(ENOMEM) );
311 /* Open display, unsing 'vlc_display' or DISPLAY environment variable */
312 psz_display = XDisplayName( main_GetPszVariable( VOUT_DISPLAY_VAR, NULL ) );
313 p_vout->p_sys->p_display = XOpenDisplay( psz_display );
315 if( p_vout->p_sys->p_display == NULL ) /* error */
317 intf_ErrMsg( "vout error: cannot open display %s", psz_display );
318 free( p_vout->p_sys );
321 p_vout->p_sys->i_screen = DefaultScreen( p_vout->p_sys->p_display );
323 #ifdef MODULE_NAME_IS_xvideo
324 /* Check that we have access to an XVideo port */
325 p_vout->p_sys->i_xvport = XVideoGetPort( p_vout->p_sys->p_display,
327 if( p_vout->p_sys->i_xvport < 0 )
329 intf_ErrMsg( "vout error: cannot get XVideo port" );
330 XCloseDisplay( p_vout->p_sys->p_display );
331 free( p_vout->p_sys );
336 /* Spawn base window - this window will include the video output window,
337 * but also command buttons, subtitles and other indicators */
338 if( CreateWindow( p_vout ) )
340 intf_ErrMsg( "vout error: cannot create X11 window" );
341 XCloseDisplay( p_vout->p_sys->p_display );
342 free( p_vout->p_sys );
346 /* Open and initialize device. */
347 if( InitDisplay( p_vout ) )
349 intf_ErrMsg( "vout error: cannot initialize X11 display" );
350 XCloseDisplay( p_vout->p_sys->p_display );
351 free( p_vout->p_sys );
355 /* Create blank cursor (for mouse cursor autohiding) */
356 CreateCursor( p_vout );
358 p_vout->p_sys->b_mouse_pointer_visible = 1;
360 /* Disable screen saver and return */
361 DisableXScreenSaver( p_vout );
366 /*****************************************************************************
367 * vout_Destroy: destroy X11 video thread output method
368 *****************************************************************************
369 * Terminate an output method created by vout_CreateOutputMethod
370 *****************************************************************************/
371 static void vout_Destroy( vout_thread_t *p_vout )
373 /* Restore cursor if it was blanked */
374 if( !p_vout->p_sys->b_mouse_pointer_visible )
376 ToggleCursor( p_vout );
379 #ifdef MODULE_NAME_IS_xvideo
380 XVideoReleasePort( p_vout->p_sys->p_display, p_vout->p_sys->i_xvport );
383 /* Destroy colormap */
384 if( p_vout->p_sys->i_screen_depth == 8 )
386 XFreeColormap( p_vout->p_sys->p_display, p_vout->p_sys->colormap );
391 DestroyCursor( p_vout );
392 EnableXScreenSaver( p_vout );
393 DestroyWindow( p_vout );
395 XCloseDisplay( p_vout->p_sys->p_display );
397 /* Destroy structure */
398 free( p_vout->p_sys );
401 /*****************************************************************************
402 * vout_Init: initialize X11 video thread output method
403 *****************************************************************************
404 * This function create the XImages needed by the output thread. It is called
405 * at the beginning of the thread, but also each time the window is resized.
406 *****************************************************************************/
407 static int vout_Init( vout_thread_t *p_vout )
412 I_OUTPUTPICTURES = 0;
414 #ifdef MODULE_NAME_IS_xvideo
415 /* Initialize the output structure */
416 switch( p_vout->render.i_chroma )
418 case YUV_420_PICTURE:
419 p_vout->output.i_chroma = p_vout->render.i_chroma;
420 p_vout->output.i_width = p_vout->render.i_width;
421 p_vout->output.i_height = p_vout->render.i_height;
422 p_vout->output.i_aspect = p_vout->render.i_aspect;
429 /* Initialize the output structure: RGB with square pixels, whatever
430 * the input format is, since it's the only format we know */
431 p_vout->output.i_chroma = RGB_16BPP_PICTURE;
432 p_vout->output.i_width = p_vout->p_sys->i_width;
433 p_vout->output.i_height = p_vout->p_sys->i_height;
434 p_vout->output.i_aspect = p_vout->p_sys->i_width
435 * VOUT_ASPECT_FACTOR / p_vout->p_sys->i_height;
438 /* Try to initialize up to MAX_DIRECTBUFFERS direct buffers */
439 while( I_OUTPUTPICTURES < MAX_DIRECTBUFFERS )
443 /* Find an empty picture slot */
444 for( i_index = 0 ; i_index < VOUT_MAX_PICTURES ; i_index++ )
446 if( p_vout->p_picture[ i_index ].i_status == FREE_PICTURE )
448 p_pic = p_vout->p_picture + i_index;
453 /* Allocate the picture */
454 if( p_pic == NULL || NewPicture( p_vout, p_pic ) )
459 p_pic->i_status = DESTROYED_PICTURE;
460 p_pic->i_type = DIRECT_PICTURE;
462 p_pic->i_left_margin =
463 p_pic->i_right_margin =
464 p_pic->i_top_margin =
465 p_pic->i_bottom_margin = 0;
467 PP_OUTPUTPICTURE[ I_OUTPUTPICTURES ] = p_pic;
475 /*****************************************************************************
476 * vout_Display: displays previously rendered output
477 *****************************************************************************
478 * This function sends the currently rendered image to X11 server.
479 * (The Xv extension takes care of "double-buffering".)
480 *****************************************************************************/
481 static void vout_Display( vout_thread_t *p_vout, picture_t *p_pic )
483 int i_width, i_height, i_x, i_y;
485 vout_PlacePicture( p_vout, p_vout->p_sys->i_width, p_vout->p_sys->i_height,
486 &i_x, &i_y, &i_width, &i_height );
488 if( p_vout->p_sys->b_shm )
490 /* Display rendered image using shared memory extension */
491 #ifdef MODULE_NAME_IS_xvideo
492 XvShmPutImage( p_vout->p_sys->p_display, p_vout->p_sys->i_xvport,
493 p_vout->p_sys->yuv_window, p_vout->p_sys->gc,
494 p_pic->p_sys->p_image, 0 /*src_x*/, 0 /*src_y*/,
495 p_vout->output.i_width, p_vout->output.i_height,
496 0 /*dest_x*/, 0 /*dest_y*/, i_width, i_height,
497 False /* Don't put True here or you'll waste your CPU */ );
499 XShmPutImage( p_vout->p_sys->p_display, p_vout->p_sys->window,
500 p_vout->p_sys->gc, p_pic->p_sys->p_image,
501 0 /*src_x*/, 0 /*src_y*/, 0 /*dest_x*/, 0 /*dest_y*/,
502 p_vout->output.i_width, p_vout->output.i_height,
503 False /* Don't put True here ! */ );
508 /* Use standard XPutImage -- this is gonna be slow ! */
509 #ifdef MODULE_NAME_IS_xvideo
510 XvPutImage( p_vout->p_sys->p_display, p_vout->p_sys->i_xvport,
511 p_vout->p_sys->yuv_window, p_vout->p_sys->gc,
512 p_pic->p_sys->p_image, 0 /*src_x*/, 0 /*src_y*/,
513 p_vout->output.i_width, p_vout->output.i_height,
514 0 /*dest_x*/, 0 /*dest_y*/, i_width, i_height );
516 XPutImage( p_vout->p_sys->p_display, p_vout->p_sys->window,
517 p_vout->p_sys->gc, p_pic->p_sys->p_image,
518 0 /*src_x*/, 0 /*src_y*/, 0 /*dest_x*/, 0 /*dest_y*/,
519 p_vout->output.i_width, p_vout->output.i_height );
523 #ifdef MODULE_NAME_IS_xvideo
524 XResizeWindow( p_vout->p_sys->p_display, p_vout->p_sys->yuv_window,
526 XMoveWindow( p_vout->p_sys->p_display, p_vout->p_sys->yuv_window,
530 /* Force synchronization */
531 XSync( p_vout->p_sys->p_display, False );
534 /*****************************************************************************
535 * vout_Manage: handle X11 events
536 *****************************************************************************
537 * This function should be called regularly by video output thread. It manages
538 * X11 events and allows window resizing. It returns a non null value on
540 *****************************************************************************/
541 static int vout_Manage( vout_thread_t *p_vout )
543 XEvent xevent; /* X11 event */
544 boolean_t b_resized; /* window has been resized */
545 char i_key; /* ISO Latin-1 key */
548 /* Handle X11 events: ConfigureNotify events are parsed to know if the
549 * output window's size changed, MapNotify and UnmapNotify to know if the
550 * window is mapped (and if the display is useful), and ClientMessages
551 * to intercept window destruction requests */
554 while( XCheckWindowEvent( p_vout->p_sys->p_display, p_vout->p_sys->window,
555 StructureNotifyMask | KeyPressMask |
556 ButtonPressMask | ButtonReleaseMask |
557 PointerMotionMask | Button1MotionMask , &xevent )
560 /* ConfigureNotify event: prepare */
561 if( (xevent.type == ConfigureNotify)
562 && ((xevent.xconfigure.width != p_vout->p_sys->i_width)
563 || (xevent.xconfigure.height != p_vout->p_sys->i_height)) )
565 /* Update dimensions */
567 p_vout->p_sys->i_width = xevent.xconfigure.width;
568 p_vout->p_sys->i_height = xevent.xconfigure.height;
570 /* MapNotify event: change window status and disable screen saver */
571 else if( xevent.type == MapNotify)
573 if( (p_vout != NULL) && !p_vout->b_active )
575 DisableXScreenSaver( p_vout );
576 p_vout->b_active = 1;
579 /* UnmapNotify event: change window status and enable screen saver */
580 else if( xevent.type == UnmapNotify )
582 if( (p_vout != NULL) && p_vout->b_active )
584 EnableXScreenSaver( p_vout );
585 p_vout->b_active = 0;
589 else if( xevent.type == KeyPress )
591 /* We may have keys like F1 trough F12, ESC ... */
592 x_key_symbol = XKeycodeToKeysym( p_vout->p_sys->p_display,
593 xevent.xkey.keycode, 0 );
594 switch( x_key_symbol )
597 p_main->p_intf->b_die = 1;
600 p_main->p_intf->b_menu_change = 1;
615 input_Seek( p_main->p_intf->p_input,
616 p_main->p_intf->p_input->stream.p_selected_area->i_start );
619 input_Seek( p_main->p_intf->p_input,
620 p_main->p_intf->p_input->stream.p_selected_area->i_size );
629 input_SetStatus( p_main->p_intf->p_input,
630 INPUT_STATUS_PAUSE );
635 * The reason why I use this instead of XK_0 is that
636 * with XLookupString, we don't have to care about
639 if( XLookupString( &xevent.xkey, &i_key, 1, NULL, NULL ) )
641 /* FIXME: handle stuff here */
646 p_main->p_intf->b_die = 1;
650 p_vout->i_changes |= VOUT_FULLSCREEN_CHANGE;
653 case '0': network_ChannelJoin( 0 ); break;
654 case '1': network_ChannelJoin( 1 ); break;
655 case '2': network_ChannelJoin( 2 ); break;
656 case '3': network_ChannelJoin( 3 ); break;
657 case '4': network_ChannelJoin( 4 ); break;
658 case '5': network_ChannelJoin( 5 ); break;
659 case '6': network_ChannelJoin( 6 ); break;
660 case '7': network_ChannelJoin( 7 ); break;
661 case '8': network_ChannelJoin( 8 ); break;
662 case '9': network_ChannelJoin( 9 ); break;
665 intf_DbgMsg( "vout: unhandled key '%c' (%i)",
666 (char)i_key, i_key );
674 else if( xevent.type == ButtonPress )
676 switch( ((XButtonEvent *)&xevent)->button )
679 /* In this part we will eventually manage
680 * clicks for DVD navigation for instance. For the
681 * moment just pause the stream. */
682 input_SetStatus( p_main->p_intf->p_input,
683 INPUT_STATUS_PAUSE );
696 else if( xevent.type == ButtonRelease )
698 switch( ((XButtonEvent *)&xevent)->button )
701 /* FIXME: need locking ! */
702 p_main->p_intf->b_menu_change = 1;
707 else if( xevent.type == MotionNotify )
709 p_vout->p_sys->i_time_mouse_last_moved = mdate();
710 if( ! p_vout->p_sys->b_mouse_pointer_visible )
712 ToggleCursor( p_vout );
718 intf_WarnMsg( 3, "vout: unhandled event %d received", xevent.type );
722 #ifdef MODULE_NAME_IS_xvideo
723 /* Handle events for YUV video output sub-window */
724 while( XCheckWindowEvent( p_vout->p_sys->p_display,
725 p_vout->p_sys->yuv_window,
726 ExposureMask, &xevent ) == True )
728 /* Window exposed (only handled if stream playback is paused) */
729 if( xevent.type == Expose )
731 if( ((XExposeEvent *)&xevent)->count == 0 )
733 /* (if this is the last a collection of expose events...) */
734 if( p_main->p_intf->p_input != NULL )
737 p_main->p_intf->p_input->stream.control.i_status )
739 /* XVideoDisplay( p_vout )*/;
747 /* ClientMessage event - only WM_PROTOCOLS with WM_DELETE_WINDOW data
748 * are handled - according to the man pages, the format is always 32
750 while( XCheckTypedEvent( p_vout->p_sys->p_display,
751 ClientMessage, &xevent ) )
753 if( (xevent.xclient.message_type == p_vout->p_sys->wm_protocols)
754 && (xevent.xclient.data.l[0] == p_vout->p_sys->wm_delete_window ) )
756 p_main->p_intf->b_die = 1;
760 intf_DbgMsg( "vout: unhandled ClientMessage received" );
764 if ( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE )
766 p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
768 p_vout->b_fullscreen = !p_vout->b_fullscreen;
770 /* Get rid of the old window */
771 DestroyWindow( p_vout );
773 /* And create a new one */
774 if( CreateWindow( p_vout ) )
776 intf_ErrMsg( "vout error: cannot create X11 window" );
777 XCloseDisplay( p_vout->p_sys->p_display );
779 free( p_vout->p_sys );
785 #ifdef MODULE_NAME_IS_x11
787 * Handle vout window resizing
792 /* If interface window has been resized, change vout size */
793 intf_DbgMsg( "vout: resizing output window" );
794 p_vout->i_width = p_vout->p_sys->i_width;
795 p_vout->i_height = p_vout->p_sys->i_height;
796 p_vout->i_changes |= VOUT_SIZE_CHANGE;
798 else if( (p_vout->i_width != p_vout->p_sys->i_width) ||
799 (p_vout->i_height != p_vout->p_sys->i_height) )
801 /* If video output size has changed, change interface window size */
802 intf_DbgMsg( "vout: resizing output window" );
803 p_vout->p_sys->i_width = p_vout->i_width;
804 p_vout->p_sys->i_height = p_vout->i_height;
805 XResizeWindow( p_vout->p_sys->p_display, p_vout->p_sys->window,
806 p_vout->p_sys->i_width, p_vout->p_sys->i_height );
809 * Color/Grayscale or gamma change: in 8bpp, just change the colormap
811 if( (p_vout->i_changes & VOUT_GRAYSCALE_CHANGE)
812 && (p_vout->i_screen_depth == 8) )
814 /* FIXME: clear flags ?? */
820 if( p_vout->i_changes & VOUT_SIZE_CHANGE )
822 intf_DbgMsg( "vout info: resizing window" );
823 p_vout->i_changes &= ~VOUT_SIZE_CHANGE;
826 XResizeWindow( p_vout->p_sys->p_display, p_vout->p_sys->window,
827 p_vout->i_width, p_vout->i_height );
829 /* Destroy XImages to change their size */
832 /* Recreate XImages. If SysInit failed, the thread can't go on. */
833 if( vout_Init( p_vout ) )
835 intf_ErrMsg( "vout error: cannot resize display" );
839 /* Tell the video output thread that it will need to rebuild YUV
840 * tables. This is needed since conversion buffer size may have
842 p_vout->i_changes |= VOUT_YUV_CHANGE;
843 intf_Msg( "vout: video display resized (%dx%d)",
844 p_vout->i_width, p_vout->i_height);
851 if( p_vout->i_changes & VOUT_SIZE_CHANGE )
853 p_vout->i_changes &= ~VOUT_SIZE_CHANGE;
855 intf_WarnMsg( 3, "vout: video display resized (%dx%d)",
856 p_vout->p_sys->i_width,
857 p_vout->p_sys->i_height );
861 /* Autohide Cursour */
862 if( mdate() - p_vout->p_sys->i_time_mouse_last_moved > 2000000 )
864 /* Hide the mouse automatically */
865 if( p_vout->p_sys->b_mouse_pointer_visible )
867 ToggleCursor( p_vout );
874 /*****************************************************************************
875 * vout_End: terminate X11 video thread output method
876 *****************************************************************************
877 * Destroy the X11 XImages created by vout_Init. It is called at the end of
878 * the thread, but also each time the window is resized.
879 *****************************************************************************/
880 static void vout_End( vout_thread_t *p_vout )
884 /* Free the direct buffers we allocated */
885 for( i_index = I_OUTPUTPICTURES ; i_index ; )
888 FreePicture( p_vout, PP_OUTPUTPICTURE[ i_index ] );
892 /* following functions are local */
894 /*****************************************************************************
895 * CreateWindow: open and set-up X11 main window
896 *****************************************************************************/
897 static int CreateWindow( vout_thread_t *p_vout )
899 XSizeHints xsize_hints;
900 XSetWindowAttributes xwindow_attributes;
907 boolean_t b_configure_notify;
908 boolean_t b_map_notify;
910 /* If we're full screen, we're full screen! */
911 if( p_vout->b_fullscreen )
913 p_vout->p_sys->i_width =
914 DisplayWidth( p_vout->p_sys->p_display, p_vout->p_sys->i_screen );
915 p_vout->p_sys->i_height =
916 DisplayHeight( p_vout->p_sys->p_display, p_vout->p_sys->i_screen );
920 /* Set main window's size */
921 if( p_vout->render.i_height * p_vout->render.i_aspect
922 >= p_vout->render.i_width * VOUT_ASPECT_FACTOR )
924 p_vout->p_sys->i_width = p_vout->render.i_height
925 * p_vout->render.i_aspect / VOUT_ASPECT_FACTOR;
926 p_vout->p_sys->i_height = p_vout->render.i_height;
930 p_vout->p_sys->i_width = p_vout->render.i_width;
931 p_vout->p_sys->i_height = p_vout->render.i_width
932 * VOUT_ASPECT_FACTOR / p_vout->render.i_aspect;
936 if( p_vout->p_sys->i_width <= 300 && p_vout->p_sys->i_height <= 300 )
938 p_vout->p_sys->i_width <<= 1;
939 p_vout->p_sys->i_height <<= 1;
941 else if( p_vout->p_sys->i_width <= 400
942 && p_vout->p_sys->i_height <= 400 )
944 p_vout->p_sys->i_width += p_vout->p_sys->i_width >> 1;
945 p_vout->p_sys->i_height += p_vout->p_sys->i_height >> 1;
950 /* Prepare window manager hints and properties */
951 xsize_hints.base_width = p_vout->p_sys->i_width;
952 xsize_hints.base_height = p_vout->p_sys->i_height;
953 xsize_hints.flags = PSize;
954 p_vout->p_sys->wm_protocols = XInternAtom( p_vout->p_sys->p_display,
955 "WM_PROTOCOLS", True );
956 p_vout->p_sys->wm_delete_window = XInternAtom( p_vout->p_sys->p_display,
957 "WM_DELETE_WINDOW", True );
959 /* Prepare window attributes */
960 xwindow_attributes.backing_store = Always; /* save the hidden part */
961 xwindow_attributes.background_pixel = BlackPixel( p_vout->p_sys->p_display,
962 p_vout->p_sys->i_screen );
963 xwindow_attributes.event_mask = ExposureMask | StructureNotifyMask;
966 /* Create the window and set hints - the window must receive ConfigureNotify
967 * events, and, until it is displayed, Expose and MapNotify events. */
969 p_vout->p_sys->window =
970 XCreateWindow( p_vout->p_sys->p_display,
971 DefaultRootWindow( p_vout->p_sys->p_display ),
973 p_vout->p_sys->i_width,
974 p_vout->p_sys->i_height,
975 #ifdef MODULE_NAME_IS_x11
976 /* XXX - what's this ? */
982 CWBackingStore | CWBackPixel | CWEventMask,
983 &xwindow_attributes );
985 if ( p_vout->b_fullscreen )
987 prop = XInternAtom(p_vout->p_sys->p_display, "_MOTIF_WM_HINTS", False);
988 mwmhints.flags = MWM_HINTS_DECORATIONS;
989 mwmhints.decorations = 0;
990 XChangeProperty( p_vout->p_sys->p_display, p_vout->p_sys->window,
991 prop, prop, 32, PropModeReplace,
992 (unsigned char *)&mwmhints, PROP_MWM_HINTS_ELEMENTS );
994 XSetTransientForHint( p_vout->p_sys->p_display,
995 p_vout->p_sys->window, None );
996 XRaiseWindow( p_vout->p_sys->p_display, p_vout->p_sys->window );
999 /* Set window manager hints and properties: size hints, command,
1000 * window's name, and accepted protocols */
1001 XSetWMNormalHints( p_vout->p_sys->p_display, p_vout->p_sys->window,
1003 XSetCommand( p_vout->p_sys->p_display, p_vout->p_sys->window,
1004 p_main->ppsz_argv, p_main->i_argc );
1005 XStoreName( p_vout->p_sys->p_display, p_vout->p_sys->window,
1006 #ifdef MODULE_NAME_IS_x11
1007 VOUT_TITLE " (X11 output)"
1009 VOUT_TITLE " (XVideo output)"
1013 if( (p_vout->p_sys->wm_protocols == None) /* use WM_DELETE_WINDOW */
1014 || (p_vout->p_sys->wm_delete_window == None)
1015 || !XSetWMProtocols( p_vout->p_sys->p_display, p_vout->p_sys->window,
1016 &p_vout->p_sys->wm_delete_window, 1 ) )
1018 /* WM_DELETE_WINDOW is not supported by window manager */
1019 intf_Msg( "vout error: missing or bad window manager" );
1022 /* Creation of a graphic context that doesn't generate a GraphicsExpose
1023 * event when using functions like XCopyArea */
1024 xgcvalues.graphics_exposures = False;
1025 p_vout->p_sys->gc = XCreateGC( p_vout->p_sys->p_display,
1026 p_vout->p_sys->window,
1027 GCGraphicsExposures, &xgcvalues);
1029 /* Send orders to server, and wait until window is displayed - three
1030 * events must be received: a MapNotify event, an Expose event allowing
1031 * drawing in the window, and a ConfigureNotify to get the window
1032 * dimensions. Once those events have been received, only ConfigureNotify
1033 * events need to be received. */
1035 b_configure_notify = 0;
1037 XMapWindow( p_vout->p_sys->p_display, p_vout->p_sys->window);
1040 XNextEvent( p_vout->p_sys->p_display, &xevent);
1041 if( (xevent.type == Expose)
1042 && (xevent.xexpose.window == p_vout->p_sys->window) )
1046 else if( (xevent.type == MapNotify)
1047 && (xevent.xmap.window == p_vout->p_sys->window) )
1051 else if( (xevent.type == ConfigureNotify)
1052 && (xevent.xconfigure.window == p_vout->p_sys->window) )
1054 b_configure_notify = 1;
1055 p_vout->p_sys->i_width = xevent.xconfigure.width;
1056 p_vout->p_sys->i_height = xevent.xconfigure.height;
1058 } while( !( b_expose && b_configure_notify && b_map_notify ) );
1060 XSelectInput( p_vout->p_sys->p_display, p_vout->p_sys->window,
1061 StructureNotifyMask | KeyPressMask |
1062 ButtonPressMask | ButtonReleaseMask |
1063 PointerMotionMask );
1065 if( p_vout->b_fullscreen )
1067 XSetInputFocus( p_vout->p_sys->p_display, p_vout->p_sys->window,
1068 RevertToNone, CurrentTime );
1069 XMoveWindow( p_vout->p_sys->p_display, p_vout->p_sys->window, 0, 0 );
1072 #ifdef MODULE_NAME_IS_x11
1073 if( XDefaultDepth(p_vout->p_sys->p_display, p_vout->p_sys->i_screen) == 8 )
1075 /* Allocate a new palette */
1076 p_vout->p_sys->colormap =
1077 XCreateColormap( p_vout->p_sys->p_display,
1078 DefaultRootWindow( p_vout->p_sys->p_display ),
1079 DefaultVisual( p_vout->p_sys->p_display,
1080 p_vout->p_sys->i_screen ),
1083 xwindow_attributes.colormap = p_vout->p_sys->colormap;
1084 XChangeWindowAttributes( p_vout->p_sys->p_display,
1085 p_vout->p_sys->window,
1086 CWColormap, &xwindow_attributes );
1090 /* Create YUV output sub-window. */
1091 p_vout->p_sys->yuv_window = XCreateSimpleWindow( p_vout->p_sys->p_display,
1092 p_vout->p_sys->window, 0, 0, 1, 1, 0,
1093 BlackPixel( p_vout->p_sys->p_display,
1094 p_vout->p_sys->i_screen ),
1095 WhitePixel( p_vout->p_sys->p_display,
1096 p_vout->p_sys->i_screen ) );
1098 p_vout->p_sys->yuv_gc = XCreateGC( p_vout->p_sys->p_display,
1099 p_vout->p_sys->yuv_window,
1100 GCGraphicsExposures, &xgcvalues );
1102 XSetWindowBackground( p_vout->p_sys->p_display, p_vout->p_sys->yuv_window,
1103 BlackPixel(p_vout->p_sys->p_display, p_vout->p_sys->i_screen ) );
1105 XMapWindow( p_vout->p_sys->p_display, p_vout->p_sys->yuv_window );
1106 XSelectInput( p_vout->p_sys->p_display, p_vout->p_sys->yuv_window,
1110 /* If the cursor was formerly blank than blank it again */
1111 if( !p_vout->p_sys->b_mouse_pointer_visible )
1113 ToggleCursor( p_vout );
1114 ToggleCursor( p_vout );
1117 XSync( p_vout->p_sys->p_display, False );
1119 /* At this stage, the window is open, displayed, and ready to
1125 static void DestroyWindow( vout_thread_t *p_vout )
1127 XSync( p_vout->p_sys->p_display, False );
1129 #ifdef MODULE_NAME_IS_xvideo
1130 XFreeGC( p_vout->p_sys->p_display, p_vout->p_sys->yuv_gc );
1131 XDestroyWindow( p_vout->p_sys->p_display, p_vout->p_sys->yuv_window );
1134 XUnmapWindow( p_vout->p_sys->p_display, p_vout->p_sys->window );
1135 XFreeGC( p_vout->p_sys->p_display, p_vout->p_sys->gc );
1136 XDestroyWindow( p_vout->p_sys->p_display, p_vout->p_sys->window );
1139 /*****************************************************************************
1140 * NewPicture: allocate a picture
1141 *****************************************************************************
1142 * Returns 0 on success, -1 otherwise
1143 *****************************************************************************/
1144 static int NewPicture( vout_thread_t *p_vout, picture_t *p_pic )
1146 #define P p_pic->planes
1147 int i_width = p_vout->output.i_width;
1148 int i_height = p_vout->output.i_height;
1150 switch( p_vout->output.i_chroma )
1152 #ifdef MODULE_NAME_IS_xvideo
1153 case YUV_420_PICTURE:
1154 /* We know this chroma, allocate a buffer which will be used
1155 * directly by the decoder */
1156 p_pic->p_sys = malloc( sizeof( picture_sys_t ) );
1158 if( p_pic->p_sys == NULL )
1163 if( p_vout->p_sys->b_shm )
1165 /* Create XvImage using XShm extension */
1166 p_pic->p_sys->p_image =
1167 CreateShmImage( p_vout->p_sys->p_display,
1168 p_vout->p_sys->i_xvport,
1170 &p_pic->p_sys->shminfo,
1171 p_vout->output.i_width,
1172 p_vout->output.i_height );
1176 /* Create XvImage using XShm extension */
1177 p_pic->p_sys->p_image =
1178 CreateImage( p_vout->p_sys->p_display,
1179 p_vout->p_sys->i_xvport,
1181 p_vout->output.i_width,
1182 p_vout->output.i_height );
1185 if( p_pic->p_sys->p_image == NULL )
1187 free( p_pic->p_sys );
1191 /* FIXME: try to get the right i_bytes value from p_image */
1192 P[Y_PLANE].p_data = p_pic->p_sys->p_image->data;
1193 P[Y_PLANE].i_bytes = i_width * i_height;
1194 P[Y_PLANE].i_line_bytes = i_width;
1196 P[U_PLANE].p_data = P[Y_PLANE].p_data + i_width * i_height * 5 / 4;
1197 P[U_PLANE].i_bytes = i_width * i_height / 4;
1198 P[U_PLANE].i_line_bytes = i_width / 2;
1200 P[V_PLANE].p_data = P[Y_PLANE].p_data + i_width * i_height;
1201 P[V_PLANE].i_bytes = i_width * i_height / 4;
1202 P[V_PLANE].i_line_bytes = i_width / 2;
1204 p_pic->i_planes = 3;
1209 #ifdef MODULE_NAME_IS_x11
1210 case RGB_16BPP_PICTURE:
1211 p_pic->p_sys = malloc( sizeof( picture_sys_t ) );
1213 if( p_pic->p_sys == NULL )
1218 if( p_vout->p_sys->b_shm )
1220 p_pic->p_sys->p_image =
1221 CreateShmImage( p_vout->p_sys->p_display,
1222 p_vout->p_sys->p_visual,
1223 p_vout->p_sys->i_screen_depth,
1224 &p_pic->p_sys->shminfo,
1225 i_width, i_height );
1229 p_pic->p_sys->p_image =
1230 CreateImage( p_vout->p_sys->p_display,
1231 p_vout->p_sys->p_visual,
1232 p_vout->p_sys->i_screen_depth,
1233 p_vout->p_sys->i_bytes_per_pixel,
1234 i_width, i_height );
1237 if( p_pic->p_sys->p_image == NULL )
1239 free( p_pic->p_sys );
1243 /* FIXME: try to get the right i_bytes value from p_image */
1244 P[ RGB_PLANE ].p_data = p_pic->p_sys->p_image->data;
1245 P[ RGB_PLANE ].i_bytes = 2 * i_width * i_height;
1246 P[ RGB_PLANE ].i_line_bytes = 2 * i_width;
1248 p_pic->i_planes = 1;
1254 /* Unknown chroma, tell the guy to get lost */
1255 p_pic->i_planes = 0;
1262 /*****************************************************************************
1263 * FreePicture: destroy a picture allocated with NewPicture
1264 *****************************************************************************
1265 * Destroy XImage AND associated data. If using Shm, detach shared memory
1266 * segment from server and process, then free it. The XDestroyImage manpage
1267 * says that both the image structure _and_ the data pointed to by the
1268 * image structure are freed, so no need to free p_image->data.
1269 *****************************************************************************/
1270 static void FreePicture( vout_thread_t *p_vout, picture_t *p_pic )
1272 /* FIXME: check the operation order */
1274 if( p_vout->p_sys->b_shm )
1276 XShmDetach( p_vout->p_sys->p_display, &p_pic->p_sys->shminfo );
1278 shmctl( p_pic->p_sys->shminfo.shmid, IPC_RMID, 0 );
1279 if( shmdt( p_pic->p_sys->shminfo.shmaddr ) )
1281 intf_ErrMsg( "vout error: cannot detach shared memory (%s)",
1286 XSync( p_vout->p_sys->p_display, False );
1287 IMAGE_FREE( p_pic->p_sys->p_image );
1289 free( p_pic->p_sys );
1292 /*****************************************************************************
1293 * EnableXScreenSaver: enable screen saver
1294 *****************************************************************************
1295 * This function enable the screen saver on a display after it had been
1296 * disabled by XDisableXScreenSaver. Both functions use a counter mechanism to
1297 * know wether the screen saver can be activated or not: if n successive calls
1298 * are made to XDisableXScreenSaver, n successive calls to XEnableXScreenSaver
1299 * will be required before the screen saver could effectively be activated.
1300 *****************************************************************************/
1301 static void EnableXScreenSaver( vout_thread_t *p_vout )
1303 intf_DbgMsg( "vout: enabling screen saver" );
1304 XSetScreenSaver( p_vout->p_sys->p_display, p_vout->p_sys->i_ss_timeout,
1305 p_vout->p_sys->i_ss_interval,
1306 p_vout->p_sys->i_ss_blanking,
1307 p_vout->p_sys->i_ss_exposure );
1310 /*****************************************************************************
1311 * DisableXScreenSaver: disable screen saver
1312 *****************************************************************************
1313 * See XEnableXScreenSaver
1314 *****************************************************************************/
1315 static void DisableXScreenSaver( vout_thread_t *p_vout )
1317 /* Save screen saver informations */
1318 XGetScreenSaver( p_vout->p_sys->p_display, &p_vout->p_sys->i_ss_timeout,
1319 &p_vout->p_sys->i_ss_interval,
1320 &p_vout->p_sys->i_ss_blanking,
1321 &p_vout->p_sys->i_ss_exposure );
1323 /* Disable screen saver */
1324 intf_DbgMsg( "vout: disabling screen saver" );
1325 XSetScreenSaver( p_vout->p_sys->p_display, 0,
1326 p_vout->p_sys->i_ss_interval,
1327 p_vout->p_sys->i_ss_blanking,
1328 p_vout->p_sys->i_ss_exposure );
1330 #ifdef MODULE_NAME_IS_xvideo
1331 DPMSDisable( p_vout->p_sys->p_display );
1335 /*****************************************************************************
1336 * CreateCursor: create a blank mouse pointer
1337 *****************************************************************************/
1338 static void CreateCursor( vout_thread_t *p_vout )
1340 XColor cursor_color;
1342 p_vout->p_sys->cursor_pixmap =
1343 XCreatePixmap( p_vout->p_sys->p_display,
1344 DefaultRootWindow( p_vout->p_sys->p_display ),
1347 XParseColor( p_vout->p_sys->p_display,
1348 XCreateColormap( p_vout->p_sys->p_display,
1349 DefaultRootWindow( p_vout->p_sys->p_display ),
1350 DefaultVisual( p_vout->p_sys->p_display,
1351 p_vout->p_sys->i_screen ),
1353 "black", &cursor_color );
1355 p_vout->p_sys->blank_cursor =
1356 XCreatePixmapCursor( p_vout->p_sys->p_display,
1357 p_vout->p_sys->cursor_pixmap,
1358 p_vout->p_sys->cursor_pixmap,
1359 &cursor_color, &cursor_color, 1, 1 );
1362 /*****************************************************************************
1363 * DestroyCursor: destroy the blank mouse pointer
1364 *****************************************************************************/
1365 static void DestroyCursor( vout_thread_t *p_vout )
1367 XFreePixmap( p_vout->p_sys->p_display, p_vout->p_sys->cursor_pixmap );
1370 /*****************************************************************************
1371 * ToggleCursor: hide or show the mouse pointer
1372 *****************************************************************************
1373 * This function hides the X pointer if it is visible by putting it at
1374 * coordinates (32,32) and setting the pointer sprite to a blank one. To
1375 * show it again, we disable the sprite and restore the original coordinates.
1376 *****************************************************************************/
1377 static void ToggleCursor( vout_thread_t *p_vout )
1379 if( p_vout->p_sys->b_mouse_pointer_visible )
1381 XDefineCursor( p_vout->p_sys->p_display,
1382 p_vout->p_sys->window,
1383 p_vout->p_sys->blank_cursor );
1384 p_vout->p_sys->b_mouse_pointer_visible = 0;
1388 XUndefineCursor( p_vout->p_sys->p_display, p_vout->p_sys->window );
1389 p_vout->p_sys->b_mouse_pointer_visible = 1;
1393 #ifdef MODULE_NAME_IS_xvideo
1394 /*****************************************************************************
1395 * XVideoGetPort: get YUV12 port
1396 *****************************************************************************/
1397 static int XVideoGetPort( Display *dpy, int i_id )
1399 XvAdaptorInfo *p_adaptor;
1401 int i_adaptor, i_num_adaptors, i_requested_adaptor;
1402 int i_selected_port;
1404 switch( XvQueryExtension( dpy, &i, &i, &i, &i, &i ) )
1409 case XvBadExtension:
1410 intf_WarnMsg( 3, "vout error: XvBadExtension" );
1414 intf_WarnMsg( 3, "vout error: XvBadAlloc" );
1418 intf_WarnMsg( 3, "vout error: XvQueryExtension failed" );
1422 switch( XvQueryAdaptors( dpy, DefaultRootWindow( dpy ),
1423 &i_num_adaptors, &p_adaptor ) )
1428 case XvBadExtension:
1429 intf_WarnMsg( 3, "vout error: XvBadExtension for XvQueryAdaptors" );
1433 intf_WarnMsg( 3, "vout error: XvBadAlloc for XvQueryAdaptors" );
1437 intf_WarnMsg( 3, "vout error: XvQueryAdaptors failed" );
1441 i_selected_port = -1;
1442 i_requested_adaptor = main_GetIntVariable( VOUT_XVADAPTOR_VAR, -1 );
1444 /* No special xv port has been requested so try all of them */
1445 for( i_adaptor = 0; i_adaptor < i_num_adaptors; ++i_adaptor )
1447 XvImageFormatValues *p_formats;
1448 int i_format, i_num_formats;
1451 /* If we requested an adaptor and it's not this one, we aren't
1453 if( i_requested_adaptor != -1 && i_adaptor != i_requested_adaptor )
1458 /* If the adaptor doesn't have the required properties, skip it */
1459 if( !( p_adaptor[ i_adaptor ].type & XvInputMask ) ||
1460 !( p_adaptor[ i_adaptor ].type & XvImageMask ) )
1465 /* Check that port supports YUV12 planar format... */
1466 p_formats = XvListImageFormats( dpy, p_adaptor[i_adaptor].base_id,
1469 for( i_format = 0; i_format < i_num_formats; i_format++ )
1471 XvEncodingInfo *p_enc;
1472 int i_enc, i_num_encodings;
1473 XvAttribute *p_attr;
1474 int i_attr, i_num_attributes;
1476 /* If this is not the format we want, forget it */
1477 if( p_formats[ i_format ].id != i_id )
1482 /* Look for the first available port supporting this format */
1483 for( i_port = p_adaptor[i_adaptor].base_id;
1484 ( i_port < p_adaptor[i_adaptor].base_id
1485 + p_adaptor[i_adaptor].num_ports )
1486 && ( i_selected_port == -1 );
1489 if( XvGrabPort( dpy, i_port, CurrentTime ) == Success )
1491 i_selected_port = i_port;
1495 /* If no free port was found, forget it */
1496 if( i_selected_port == -1 )
1501 /* If we found a port, print information about it */
1502 intf_WarnMsg( 3, "vout: found adaptor %i, port %i, "
1503 "image format 0x%x (%4.4s) %s",
1504 i_adaptor, i_selected_port,
1505 p_formats[ i_format ].id,
1506 (char *)&p_formats[ i_format ].id,
1507 ( p_formats[ i_format ].format
1508 == XvPacked ) ? "packed" : "planar" );
1510 intf_WarnMsg( 10, " encoding list:" );
1512 if( XvQueryEncodings( dpy, i_selected_port,
1513 &i_num_encodings, &p_enc )
1516 intf_WarnMsg( 10, " XvQueryEncodings failed" );
1520 for( i_enc = 0; i_enc < i_num_encodings; i_enc++ )
1522 intf_WarnMsg( 10, " id=%ld, name=%s, size=%ldx%ld,"
1523 " numerator=%d, denominator=%d",
1524 p_enc[i_enc].encoding_id, p_enc[i_enc].name,
1525 p_enc[i_enc].width, p_enc[i_enc].height,
1526 p_enc[i_enc].rate.numerator,
1527 p_enc[i_enc].rate.denominator );
1532 XvFreeEncodingInfo( p_enc );
1535 intf_WarnMsg( 10, " attribute list:" );
1536 p_attr = XvQueryPortAttributes( dpy, i_selected_port,
1537 &i_num_attributes );
1538 for( i_attr = 0; i_attr < i_num_attributes; i_attr++ )
1541 " name=%s, flags=[%s%s ], min=%i, max=%i",
1542 p_attr[i_attr].name,
1543 (p_attr[i_attr].flags & XvGettable) ? " get" : "",
1544 (p_attr[i_attr].flags & XvSettable) ? " set" : "",
1545 p_attr[i_attr].min_value, p_attr[i_attr].max_value );
1548 if( p_attr != NULL )
1554 if( p_formats != NULL )
1561 if( i_num_adaptors > 0 )
1563 XvFreeAdaptorInfo( p_adaptor );
1566 if( i_selected_port == -1 )
1568 if( i_requested_adaptor == -1 )
1570 intf_WarnMsg( 3, "vout: no free XVideo port found for YV12" );
1574 intf_WarnMsg( 3, "vout: XVideo adaptor %i does not have a free "
1575 "XVideo port for YV12", i_requested_adaptor );
1579 return( i_selected_port );
1582 /*****************************************************************************
1583 * XVideoReleasePort: release YUV12 port
1584 *****************************************************************************/
1585 static void XVideoReleasePort( Display *dpy, int i_port )
1587 XvGrabPort( dpy, i_port, CurrentTime );
1591 /*****************************************************************************
1592 * InitDisplay: open and initialize X11 device
1593 *****************************************************************************
1594 * Create a window according to video output given size, and set other
1595 * properties according to the display properties.
1596 *****************************************************************************/
1597 static int InitDisplay( vout_thread_t *p_vout )
1599 #ifdef MODULE_NAME_IS_x11
1600 XPixmapFormatValues * p_formats; /* pixmap formats */
1601 XVisualInfo * p_xvisual; /* visuals informations */
1602 XVisualInfo xvisual_template; /* visual template */
1603 int i_count; /* array size */
1607 /* FIXME : As of 2001-03-16, XFree4 for MacOS X does not support Xshm. */
1608 p_vout->p_sys->b_shm = 0;
1610 p_vout->p_sys->b_shm = ( XShmQueryExtension( p_vout->p_sys->p_display )
1613 if( !p_vout->p_sys->b_shm )
1615 intf_WarnMsg( 1, "vout warning: XShm video extension is unavailable" );
1618 #ifdef MODULE_NAME_IS_xvideo
1619 /* XXX The brightness and contrast values should be read from environment
1620 * XXX variables... */
1622 XVideoSetAttribute( p_vout, "XV_BRIGHTNESS", 0.5 );
1623 XVideoSetAttribute( p_vout, "XV_CONTRAST", 0.5 );
1627 #ifdef MODULE_NAME_IS_x11
1628 /* Initialize structure */
1629 p_vout->p_sys->i_screen = DefaultScreen( p_vout->p_sys->p_display );
1631 /* Get screen depth */
1632 p_vout->p_sys->i_screen_depth = XDefaultDepth( p_vout->p_sys->p_display,
1633 p_vout->p_sys->i_screen );
1634 switch( p_vout->p_sys->i_screen_depth )
1638 * Screen depth is 8bpp. Use PseudoColor visual with private colormap.
1640 xvisual_template.screen = p_vout->p_sys->i_screen;
1641 xvisual_template.class = DirectColor;
1642 p_xvisual = XGetVisualInfo( p_vout->p_sys->p_display,
1643 VisualScreenMask | VisualClassMask,
1644 &xvisual_template, &i_count );
1645 if( p_xvisual == NULL )
1647 intf_ErrMsg( "vout error: no PseudoColor visual available" );
1650 p_vout->p_sys->i_bytes_per_pixel = 1;
1657 * Screen depth is higher than 8bpp. TrueColor visual is used.
1659 xvisual_template.screen = p_vout->p_sys->i_screen;
1660 xvisual_template.class = TrueColor;
1661 p_xvisual = XGetVisualInfo( p_vout->p_sys->p_display,
1662 VisualScreenMask | VisualClassMask,
1663 &xvisual_template, &i_count );
1664 if( p_xvisual == NULL )
1666 intf_ErrMsg( "vout error: no TrueColor visual available" );
1669 p_vout->p_sys->i_red_mask = p_xvisual->red_mask;
1670 p_vout->p_sys->i_green_mask = p_xvisual->green_mask;
1671 p_vout->p_sys->i_blue_mask = p_xvisual->blue_mask;
1673 /* There is no difference yet between 3 and 4 Bpp. The only way
1674 * to find the actual number of bytes per pixel is to list supported
1675 * pixmap formats. */
1676 p_formats = XListPixmapFormats( p_vout->p_sys->p_display, &i_count );
1677 p_vout->p_sys->i_bytes_per_pixel = 0;
1679 for( ; i_count-- ; p_formats++ )
1681 /* Under XFree4.0, the list contains pixmap formats available
1682 * through all video depths ; so we have to check against current
1684 if( p_formats->depth == p_vout->p_sys->i_screen_depth )
1686 if( p_formats->bits_per_pixel / 8
1687 > p_vout->p_sys->i_bytes_per_pixel )
1689 p_vout->p_sys->i_bytes_per_pixel = p_formats->bits_per_pixel / 8;
1695 p_vout->p_sys->p_visual = p_xvisual->visual;
1702 /*****************************************************************************
1703 * CreateShmImage: create an XImage or XvImage using shared memory extension
1704 *****************************************************************************
1705 * Prepare an XImage or XvImage for display function.
1706 * The order of the operations respects the recommandations of the mit-shm
1707 * document by J.Corbet and K.Packard. Most of the parameters were copied from
1709 *****************************************************************************/
1710 static IMAGE_TYPE * CreateShmImage( Display* p_display, EXTRA_ARGS_SHM,
1711 int i_width, int i_height )
1713 IMAGE_TYPE *p_image;
1715 /* Create XImage / XvImage */
1716 #ifdef MODULE_NAME_IS_xvideo
1717 p_image = XvShmCreateImage( p_display, i_xvport, i_format, 0,
1718 i_width, i_height, p_shm );
1720 p_image = XShmCreateImage( p_display, p_visual, i_depth, ZPixmap, 0,
1721 p_shm, i_width, i_height );
1723 if( p_image == NULL )
1725 intf_ErrMsg( "vout error: image creation failed." );
1729 /* Allocate shared memory segment - 0776 set the access permission
1730 * rights (like umask), they are not yet supported by all X servers */
1731 p_shm->shmid = shmget( IPC_PRIVATE, DATA_SIZE, IPC_CREAT | 0776 );
1732 if( p_shm->shmid < 0 )
1734 intf_ErrMsg( "vout error: cannot allocate shared image data (%s)",
1735 strerror( errno ) );
1736 IMAGE_FREE( p_image );
1740 /* Attach shared memory segment to process (read/write) */
1741 p_shm->shmaddr = p_image->data = shmat( p_shm->shmid, 0, 0 );
1742 if(! p_shm->shmaddr )
1744 intf_ErrMsg( "vout error: cannot attach shared memory (%s)",
1746 shmctl( p_shm->shmid, IPC_RMID, 0 ); /* free shared memory */
1747 IMAGE_FREE( p_image );
1751 /* Attach shared memory segment to X server */
1752 #ifdef MODULE_NAME_IS_xvideo
1753 p_shm->readOnly = False; /* XXX: What's this ? */
1755 p_shm->readOnly = True;
1757 if( XShmAttach( p_display, p_shm ) == False )
1759 intf_ErrMsg( "vout error: cannot attach shared memory to X server" );
1760 shmctl( p_shm->shmid, IPC_RMID, 0 );
1761 shmdt( p_shm->shmaddr );
1762 IMAGE_FREE( p_image );
1766 /* Send image to X server. This instruction is required, since having
1767 * built a Shm XImage and not using it causes an error on XCloseDisplay */
1768 XSync( p_display, False );
1771 /* Mark the shm segment to be removed when there are no more
1772 * attachements, so it is automatic on process exit or after shmdt */
1773 shmctl( p_shm->shmid, IPC_RMID, 0 );
1779 /*****************************************************************************
1780 * CreateImage: create an XImage or XvImage
1781 *****************************************************************************
1782 * Create a simple image used as a buffer.
1783 *****************************************************************************/
1784 static IMAGE_TYPE * CreateImage( Display *p_display, EXTRA_ARGS,
1785 int i_width, int i_height )
1787 byte_t * p_data; /* image data storage zone */
1788 IMAGE_TYPE *p_image;
1789 #ifdef MODULE_NAME_IS_x11
1790 int i_quantum; /* XImage quantum (see below) */
1791 int i_bytes_per_line;
1794 /* Allocate memory for image */
1795 #ifdef MODULE_NAME_IS_xvideo
1796 p_data = (byte_t *) malloc( i_width * i_height * 2 ); /* XXX */
1798 i_bytes_per_line = i_width * i_bytes_per_pixel;
1799 p_data = (byte_t *) malloc( i_bytes_per_line * i_height );
1803 intf_ErrMsg( "vout error: %s", strerror(ENOMEM));
1807 #ifdef MODULE_NAME_IS_x11
1808 /* Optimize the quantum of a scanline regarding its size - the quantum is
1809 a diviser of the number of bits between the start of two scanlines. */
1810 if( i_bytes_per_line & 0xf )
1814 else if( i_bytes_per_line & 0x10 )
1824 /* Create XImage. p_data will be automatically freed */
1825 #ifdef MODULE_NAME_IS_xvideo
1826 p_image = XvCreateImage( p_display, i_xvport, i_format,
1827 p_data, i_width, i_height );
1829 p_image = XCreateImage( p_display, p_visual, i_depth, ZPixmap, 0,
1830 p_data, i_width, i_height, i_quantum, 0 );
1832 if( p_image == NULL )
1834 intf_ErrMsg( "vout error: XCreateImage() failed" );