]> git.sesse.net Git - vlc/blob - plugins/x11/vout_xvideo.c
* Split ChangeLog into ChangeLog and ChangeLog.libdvdcss.
[vlc] / plugins / x11 / vout_xvideo.c
1 /*****************************************************************************
2  * vout_xvideo.c: Xvideo video output display method
3  *****************************************************************************
4  * Copyright (C) 1998, 1999, 2000, 2001 VideoLAN
5  * $Id: vout_xvideo.c,v 1.26 2001/08/22 14:23:57 sam Exp $
6  *
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>
11  *
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.
16  *
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.
21  *
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  *****************************************************************************/
26
27 #define MODULE_NAME xvideo
28 #include "modules_inner.h"
29
30 /*****************************************************************************
31  * Preamble
32  *****************************************************************************/
33 #include "defs.h"
34
35 #include <errno.h>                                                 /* ENOMEM */
36 #include <stdlib.h>                                                /* free() */
37 #include <string.h>                                            /* strerror() */
38
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
45
46 #ifndef WIN32
47 #include <netinet/in.h>                               /* BSD: struct in_addr */
48 #endif
49
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>
57
58 #include "config.h"
59 #include "common.h"
60 #include "threads.h"
61 #include "mtime.h"
62 #include "tests.h"
63
64 #include "video.h"
65 #include "video_output.h"
66
67 #include "interface.h"
68 #include "intf_msg.h"
69
70 #include "netutils.h"                                 /* network_ChannelJoin */
71
72 #include "main.h"
73
74 #include "stream_control.h"                 /* needed by input_ext-intf.h... */
75 #include "input_ext-intf.h"
76
77 #include "modules.h"
78 #include "modules_export.h"
79
80 #define GUID_YUV12_PLANAR 0x32315659
81
82
83 /*****************************************************************************
84  * vout_sys_t: video output X11 method descriptor
85  *****************************************************************************
86  * This structure is part of the video output thread descriptor.
87  * It describes the XVideo specific properties of an output thread.
88  *****************************************************************************/
89 typedef struct vout_sys_s
90 {
91     /* User settings */
92 #if 0
93     /* this plugin (currently) requires the SHM Ext... */
94     boolean_t           b_shm;               /* shared memory extension flag */
95 #endif
96
97     /* Internal settings and properties */
98     Display *           p_display;                        /* display pointer */
99     int                 i_screen;                           /* screen number */
100     Window              window;                               /* root window */
101     GC                  gc;              /* graphic context instance handler */
102     Window              yuv_window;   /* sub-window for displaying yuv video
103                                                                         data */
104     GC                  yuv_gc;
105     int                 xv_port;
106
107     /* Display buffers and shared memory information */
108     /* Note: only 1 buffer... Xv ext does double buffering. */
109     XvImage *           p_xvimage;
110     int                 i_image_width;
111     int                 i_image_height;
112                                 /* i_image_width & i_image_height reflect the
113                                  * size of the XvImage. They are used by
114                                  * vout_Display() to check if the image to be
115                                  * displayed can use the current XvImage. */
116     XShmSegmentInfo     shm_info;       /* shared memory zone information */
117
118     /* X11 generic properties */
119     Atom                wm_protocols;
120     Atom                wm_delete_window;
121
122     int                 i_window_width;              /* width of main window */
123     int                 i_window_height;            /* height of main window */
124
125
126     /* Screen saver properties */
127     int                 i_ss_timeout;                             /* timeout */
128     int                 i_ss_interval;           /* interval between changes */
129     int                 i_ss_blanking;                      /* blanking mode */
130     int                 i_ss_exposure;                      /* exposure mode */
131     
132     /* Mouse pointer properties */
133     boolean_t           b_mouse_pointer_visible;
134     mtime_t             i_time_mouse_last_moved; /* used to auto-hide pointer*/
135     Cursor              blank_cursor;                   /* the hidden cursor */
136     Pixmap              cursor_pixmap;
137
138 } vout_sys_t;
139
140 /* Fullscreen needs to be able to hide the wm decorations */
141 #define MWM_HINTS_DECORATIONS   (1L << 1)
142 #define PROP_MWM_HINTS_ELEMENTS 5
143 typedef struct mwmhints_s
144 {
145     u32 flags;
146     u32 functions;
147     u32 decorations;
148     s32 input_mode;
149     u32 status;
150 } mwmhints_t;
151
152 /*****************************************************************************
153  * Local prototypes
154  *****************************************************************************/
155 static int  vout_Probe     ( probedata_t * );
156 static int  vout_Create    ( vout_thread_t * );
157 static int  vout_Init      ( vout_thread_t * );
158 static void vout_End       ( vout_thread_t * );
159 static void vout_Destroy   ( vout_thread_t * );
160 static int  vout_Manage    ( vout_thread_t * );
161 static void vout_Display   ( vout_thread_t * );
162 static void vout_SetPalette( vout_thread_t *, u16 *, u16 *, u16 *, u16 * );
163
164 static int  XVideoCreateWindow       ( vout_thread_t * );
165 static void XVideoDestroyWindow      ( vout_thread_t *p_vout );
166 static int  XVideoUpdateImgSizeIfRequired( vout_thread_t *p_vout );
167 static int  XVideoCreateShmImage     ( Display* dpy, int xv_port,
168                                        XvImage **pp_xvimage,
169                                        XShmSegmentInfo *p_shm_info,
170                                        int i_width, int i_height );
171 static void XVideoDestroyShmImage    ( vout_thread_t *, XvImage *,
172                                        XShmSegmentInfo * );
173 static void X11ToggleMousePointer    ( vout_thread_t * );
174 static void XVideoEnableScreenSaver  ( vout_thread_t * );
175 static void XVideoDisableScreenSaver ( vout_thread_t * );
176 /*static void XVideoSetAttribute       ( vout_thread_t *, char *, float );*/
177
178 static int  XVideoCheckForXv         ( Display * );
179 static int  XVideoGetPort            ( Display * );
180 static void XVideoOutputCoords       ( const picture_t *, const boolean_t,
181                                        const int, const int,
182                                        int *, int *, int *, int * );
183 static void XVideoDisplay            ( vout_thread_t * );
184
185 /*****************************************************************************
186  * Functions exported as capabilities. They are declared as static so that
187  * we don't pollute the namespace too much.
188  *****************************************************************************/
189 void _M( vout_getfunctions )( function_list_t * p_function_list )
190 {
191     p_function_list->pf_probe = vout_Probe;
192     p_function_list->functions.vout.pf_create     = vout_Create;
193     p_function_list->functions.vout.pf_init       = vout_Init;
194     p_function_list->functions.vout.pf_end        = vout_End;
195     p_function_list->functions.vout.pf_destroy    = vout_Destroy;
196     p_function_list->functions.vout.pf_manage     = vout_Manage;
197     p_function_list->functions.vout.pf_display    = vout_Display;
198     p_function_list->functions.vout.pf_setpalette = vout_SetPalette;
199 }
200
201 /*****************************************************************************
202  * vout_Probe: probe the video driver and return a score
203  *****************************************************************************
204  * This returns a score to the plugin manager so that it can select the best
205  * plugin.
206  *****************************************************************************/
207 static int vout_Probe( probedata_t *p_data )
208 {
209     Display *p_display;                                   /* display pointer */
210     char    *psz_display;
211
212     /* Open display, unsing 'vlc_display' or DISPLAY environment variable */
213     psz_display = XDisplayName( main_GetPszVariable(VOUT_DISPLAY_VAR, NULL) );
214     p_display = XOpenDisplay( psz_display );
215     if( p_display == NULL )                                         /* error */
216     {
217         intf_WarnMsg( 3, "vout: Xvideo cannot open display %s", psz_display );
218         intf_WarnMsg( 3, "vout: Xvideo not supported" );
219         return( 0 );
220     }
221     
222     if( !XVideoCheckForXv( p_display ) )
223     {
224         intf_WarnMsg( 3, "vout: Xvideo not supported" );
225         XCloseDisplay( p_display );
226         return( 0 );
227     }
228
229     if( XVideoGetPort( p_display ) < 0 )
230     {
231         intf_WarnMsg( 3, "vout: Xvideo not supported" );
232         XCloseDisplay( p_display );
233         return( 0 );
234     }
235
236     /* Clean-up everyting */
237     XCloseDisplay( p_display );
238
239     if( TestMethod( VOUT_METHOD_VAR, "xvideo" ) )
240     {
241         return( 999 );
242     }
243
244     return( 150 );
245 }
246
247 /*****************************************************************************
248  * vout_Create: allocate XVideo video thread output method
249  *****************************************************************************
250  * This function allocate and initialize a XVideo vout method. It uses some of
251  * the vout properties to choose the window size, and change them according to
252  * the actual properties of the display.
253  *****************************************************************************/
254 static int vout_Create( vout_thread_t *p_vout )
255 {
256     char *psz_display;
257     XColor cursor_color;
258
259     /* Allocate structure */
260     p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
261     if( p_vout->p_sys == NULL )
262     {
263         intf_ErrMsg( "vout error: %s", strerror(ENOMEM) );
264         return( 1 );
265     }
266
267     /* Open display, unsing 'vlc_display' or DISPLAY environment variable */
268     psz_display = XDisplayName( main_GetPszVariable( VOUT_DISPLAY_VAR, NULL ) );
269     p_vout->p_sys->p_display = XOpenDisplay( psz_display );
270
271     if( p_vout->p_sys->p_display == NULL )                          /* error */
272     {
273         intf_ErrMsg( "vout error: cannot open display %s", psz_display );
274         free( p_vout->p_sys );
275         return( 1 );
276     }
277     p_vout->p_sys->i_screen = DefaultScreen( p_vout->p_sys->p_display );
278
279     p_vout->b_fullscreen
280         = main_GetIntVariable( VOUT_FULLSCREEN_VAR, VOUT_FULLSCREEN_DEFAULT );
281     
282     if( !XVideoCheckForXv( p_vout->p_sys->p_display ) )
283     {
284         intf_ErrMsg( "vout error: no XVideo extension" );
285         XCloseDisplay( p_vout->p_sys->p_display );
286         free( p_vout->p_sys );
287         return( 1 );
288     }
289
290     /* Check we have access to a video port */
291     if( (p_vout->p_sys->xv_port = XVideoGetPort(p_vout->p_sys->p_display)) <0 )
292     {
293         intf_ErrMsg( "vout error: cannot get XVideo port" );
294         XCloseDisplay( p_vout->p_sys->p_display );
295         free( p_vout->p_sys );
296         return 1;
297     }
298     intf_DbgMsg( "Using xv port %d" , p_vout->p_sys->xv_port );
299
300     /* Create blank cursor (for mouse cursor autohiding) */
301     p_vout->p_sys->b_mouse_pointer_visible = 1;
302     p_vout->p_sys->cursor_pixmap = XCreatePixmap( p_vout->p_sys->p_display,
303                                                   DefaultRootWindow(
304                                                      p_vout->p_sys->p_display),
305                                                   1, 1, 1 );
306     
307     XParseColor( p_vout->p_sys->p_display,
308                  XCreateColormap( p_vout->p_sys->p_display,
309                                   DefaultRootWindow(
310                                                     p_vout->p_sys->p_display ),
311                                   DefaultVisual(
312                                                 p_vout->p_sys->p_display,
313                                                 p_vout->p_sys->i_screen ),
314                                   AllocNone ),
315                  "black", &cursor_color );
316     
317     p_vout->p_sys->blank_cursor = XCreatePixmapCursor(
318                                       p_vout->p_sys->p_display,
319                                       p_vout->p_sys->cursor_pixmap,
320                                       p_vout->p_sys->cursor_pixmap,
321                                       &cursor_color,
322                                       &cursor_color, 1, 1 );    
323
324     /* Spawn base window - this window will include the video output window,
325      * but also command buttons, subtitles and other indicators */
326     if( XVideoCreateWindow( p_vout ) )
327     {
328         intf_ErrMsg( "vout error: cannot create XVideo window" );
329         XCloseDisplay( p_vout->p_sys->p_display );
330         free( p_vout->p_sys );
331         return( 1 );
332     }
333
334     /* p_vout->pf_setbuffers( p_vout, NULL, NULL ); */
335
336 #if 0
337     /* XXX The brightness and contrast values should be read from environment
338      * XXX variables... */
339     XVideoSetAttribute( p_vout, "XV_BRIGHTNESS", 0.5 );
340     XVideoSetAttribute( p_vout, "XV_CONTRAST",   0.5 );
341 #endif
342
343     /* Disable screen saver and return */
344     XVideoDisableScreenSaver( p_vout );
345
346     return( 0 );
347 }
348
349 /*****************************************************************************
350  * vout_Init: initialize XVideo video thread output method
351  *****************************************************************************/
352 static int vout_Init( vout_thread_t *p_vout )
353 {
354 #ifdef SYS_DARWIN
355     /* FIXME : As of 2001-03-16, XFree4 for MacOS X does not support Xshm. */
356     p_vout->p_sys->b_shm = 0;
357 #endif
358     p_vout->b_need_render = 0;
359     p_vout->p_sys->i_image_width = p_vout->p_sys->i_image_height = 0;
360
361     return( 0 );
362 }
363
364 /*****************************************************************************
365  * vout_End: terminate XVideo video thread output method
366  *****************************************************************************
367  * Destroy the XvImage. It is called at the end of the thread, but also each
368  * time the image is resized.
369  *****************************************************************************/
370 static void vout_End( vout_thread_t *p_vout )
371 {
372     XVideoDestroyShmImage( p_vout, p_vout->p_sys->p_xvimage,
373                            &p_vout->p_sys->shm_info );
374 }
375
376 /*****************************************************************************
377  * vout_Destroy: destroy XVideo video thread output method
378  *****************************************************************************
379  * Terminate an output method created by vout_Create
380  *****************************************************************************/
381 static void vout_Destroy( vout_thread_t *p_vout )
382 {
383     /* Restore cursor if it was blanked */
384     if( !p_vout->p_sys->b_mouse_pointer_visible )
385         X11ToggleMousePointer( p_vout );
386
387     /* Destroy blank cursor pixmap */
388     XFreePixmap( p_vout->p_sys->p_display, p_vout->p_sys->cursor_pixmap );
389
390     XVideoEnableScreenSaver( p_vout );
391     XVideoDestroyWindow( p_vout );
392     XCloseDisplay( p_vout->p_sys->p_display );
393
394     /* Destroy structure */
395     free( p_vout->p_sys );
396 }
397
398 /*****************************************************************************
399  * vout_Manage: handle X11 events
400  *****************************************************************************
401  * This function should be called regularly by video output thread. It manages
402  * X11 events and allows window resizing. It returns a non null value on
403  * error.
404  *
405  * XXX  Should "factor-out" common code in this and the "same" fn in the x11
406  * XXX  plugin!
407  *****************************************************************************/
408 static int vout_Manage( vout_thread_t *p_vout )
409 {
410     XEvent      xevent;                                         /* X11 event */
411     char        i_key;                                    /* ISO Latin-1 key */
412     KeySym      x_key_symbol;
413
414     /* Handle X11 events: ConfigureNotify events are parsed to know if the
415      * output window's size changed, MapNotify and UnmapNotify to know if the
416      * window is mapped (and if the display is useful), and ClientMessages
417      * to intercept window destruction requests */
418     while( XCheckWindowEvent( p_vout->p_sys->p_display, p_vout->p_sys->window,
419                               StructureNotifyMask | KeyPressMask |
420                               ButtonPressMask | ButtonReleaseMask | 
421                               PointerMotionMask, &xevent )
422            == True )
423     {
424         /* ConfigureNotify event: prepare  */
425         if( (xevent.type == ConfigureNotify)
426             /*&& ((xevent.xconfigure.width != p_vout->p_sys->i_window_width)
427                 || (xevent.xconfigure.height != p_vout->p_sys->i_window_height))*/ )
428         {
429             /* Update dimensions */
430             p_vout->p_sys->i_window_width = xevent.xconfigure.width;
431             p_vout->p_sys->i_window_height = xevent.xconfigure.height;
432         }
433         /* MapNotify event: change window status and disable screen saver */
434         else if( xevent.type == MapNotify)
435         {
436             if( (p_vout != NULL) && !p_vout->b_active )
437             {
438                 XVideoDisableScreenSaver( p_vout );
439                 p_vout->b_active = 1;
440             }
441         }
442         /* UnmapNotify event: change window status and enable screen saver */
443         else if( xevent.type == UnmapNotify )
444         {
445             if( (p_vout != NULL) && p_vout->b_active )
446             {
447                 XVideoEnableScreenSaver( p_vout );
448                 p_vout->b_active = 0;
449             }
450         }
451         /* Keyboard event */
452         else if( xevent.type == KeyPress )
453         {
454             /* We may have keys like F1 trough F12, ESC ... */
455             x_key_symbol = XKeycodeToKeysym( p_vout->p_sys->p_display,
456                                              xevent.xkey.keycode, 0 );
457             switch( x_key_symbol )
458             {
459                  case XK_Escape:
460                      p_main->p_intf->b_die = 1;
461                      break;
462                  case XK_Menu:
463                      p_main->p_intf->b_menu_change = 1;
464                      break;
465                  default:
466                      /* "Normal Keys"
467                       * The reason why I use this instead of XK_0 is that 
468                       * with XLookupString, we don't have to care about
469                       * keymaps. */
470
471                     if( XLookupString( &xevent.xkey, &i_key, 1, NULL, NULL ) )
472                     {
473                         switch( i_key )
474                         {
475                         case 'q':
476                         case 'Q':
477                             p_main->p_intf->b_die = 1;
478                             break;
479                         case 'f':
480                         case 'F':
481                             p_vout->i_changes |= VOUT_FULLSCREEN_CHANGE;
482                             break;
483                         case '0':
484                             network_ChannelJoin( 0 );
485                             break;
486                         case '1':
487                             network_ChannelJoin( 1 );
488                             break;
489                         case '2':
490                             network_ChannelJoin( 2 );
491                             break;
492                         case '3':
493                             network_ChannelJoin( 3 );
494                             break;
495                         case '4':
496                             network_ChannelJoin( 4 );
497                             break;
498                         case '5':
499                             network_ChannelJoin( 5 );
500                             break;
501                         case '6':
502                             network_ChannelJoin( 6 );
503                             break;
504                         case '7':
505                             network_ChannelJoin( 7 );
506                             break;
507                         case '8':
508                             network_ChannelJoin( 8 );
509                             break;
510                         case '9':
511                             network_ChannelJoin( 9 );
512                             break;
513                         default:
514                             if( intf_ProcessKey( p_main->p_intf, 
515                                                  (char )i_key ) )
516                             {
517                                intf_DbgMsg( "unhandled key '%c' (%i)", 
518                                             (char)i_key, i_key );
519                             }
520                             break;
521                         }
522                     }
523                 break;
524             }
525         }
526         /* Mouse click */
527         else if( xevent.type == ButtonPress )
528         {
529             switch( ((XButtonEvent *)&xevent)->button )
530             {
531                 case Button1:
532                     /* in this part we will eventually manage
533                      * clicks for DVD navigation for instance */
534                     break;
535             }
536         }
537         /* Mouse release */
538         else if( xevent.type == ButtonRelease )
539         {
540             switch( ((XButtonEvent *)&xevent)->button )
541             {
542                 case Button3:
543                     /* FIXME: need locking ! */
544                     p_main->p_intf->b_menu_change = 1;
545                     break;
546             }
547         }
548         /* Mouse move */
549         else if( xevent.type == MotionNotify )
550         {
551             p_vout->p_sys->i_time_mouse_last_moved = mdate();
552             if( !p_vout->p_sys->b_mouse_pointer_visible )
553                 X11ToggleMousePointer( p_vout ); 
554         }
555         /* Other event */
556         else
557         {
558             intf_WarnMsg( 3, "%p -> unhandled event type %d received",
559                          p_vout, xevent.type );
560         }
561     }
562
563     /* Handle events for YUV video output sub-window */
564     while( XCheckWindowEvent( p_vout->p_sys->p_display,
565                               p_vout->p_sys->yuv_window,
566                               ExposureMask, &xevent ) == True )
567     {
568         /* Window exposed (only handled if stream playback is paused) */
569         if( xevent.type == Expose )
570         {
571             if( ((XExposeEvent *)&xevent)->count == 0 )
572                 /* (if this is the last a collection of expose events...) */
573                 if( p_main->p_intf->p_input )
574                     if( PAUSE_S ==
575                             p_main->p_intf->p_input->stream.control.i_status )
576                         XVideoDisplay( p_vout );
577         }
578     }
579         
580     /* ClientMessage event - only WM_PROTOCOLS with WM_DELETE_WINDOW data
581      * are handled - according to the man pages, the format is always 32
582      * in this case */
583     while( XCheckTypedEvent( p_vout->p_sys->p_display,
584                              ClientMessage, &xevent ) )
585     {
586         if( (xevent.xclient.message_type == p_vout->p_sys->wm_protocols)
587             && (xevent.xclient.data.l[0] == p_vout->p_sys->wm_delete_window ) )
588         {
589             p_main->p_intf->b_die = 1;
590         }
591         else
592         {
593             intf_DbgMsg( "%p -> unhandled ClientMessage received", p_vout );
594         }
595     }
596
597     if ( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE )
598     {
599         intf_DbgMsg( "vout: changing full-screen status" );
600
601         p_vout->b_fullscreen = !p_vout->b_fullscreen;
602
603         /* Get rid of the old window */
604         XVideoDestroyWindow( p_vout );
605
606         /* And create a new one */
607         if( XVideoCreateWindow( p_vout ) )
608         {
609             intf_ErrMsg( "vout error: cannot create X11 window" );
610             XCloseDisplay( p_vout->p_sys->p_display );
611
612             free( p_vout->p_sys );
613             return( 1 );
614         }
615     }
616
617     
618     if( (p_vout->i_changes & VOUT_GRAYSCALE_CHANGE))
619     {
620         /* FIXME: clear flags ?? */
621     }
622
623     /*
624      * Size change
625      */
626     if( p_vout->i_changes & VOUT_SIZE_CHANGE )
627     {
628         intf_DbgMsg( "vout: resizing window" );
629         p_vout->i_changes &= ~VOUT_SIZE_CHANGE;
630         /* Nothing to do here...
631          * vout_Display() detects size changes of the image to be displayed and
632          * re-creates the XvImage.*/
633         intf_Msg( "vout: video display resized (%dx%d)",
634                   p_vout->i_width, p_vout->i_height );
635     }
636
637     /* Autohide Cursor */
638     if( p_vout->p_sys->b_mouse_pointer_visible &&
639         mdate() - p_vout->p_sys->i_time_mouse_last_moved > 2000000 )
640     {
641         X11ToggleMousePointer( p_vout );
642     }
643     
644     return 0;
645 }
646
647 /*****************************************************************************
648  * vout_Display: displays previously rendered output
649  *****************************************************************************
650  * This function sends the currently rendered image to X11 server.
651  * (The Xv extension takes care of "double-buffering".)
652  *****************************************************************************/
653 static void vout_Display( vout_thread_t *p_vout )
654 {
655     boolean_t b_draw = 1;
656     int i_size = p_vout->p_rendered_pic->i_width *
657                    p_vout->p_rendered_pic->i_height;
658
659     if( XVideoUpdateImgSizeIfRequired( p_vout ) )
660     {
661         return;
662     }
663
664     switch( p_vout->p_rendered_pic->i_type )
665     {
666     case YUV_422_PICTURE:
667         intf_ErrMsg( "vout error: YUV_422_PICTURE not (yet) supported" );
668         b_draw = 0;
669         break;
670
671     case YUV_444_PICTURE:
672         intf_ErrMsg( "vout error: YUV_444_PICTURE not (yet) supported" );
673         b_draw = 0;
674         break;
675
676     case YUV_420_PICTURE:
677         memcpy( p_vout->p_sys->p_xvimage->data,
678                 p_vout->p_rendered_pic->p_y, i_size );
679         memcpy( p_vout->p_sys->p_xvimage->data + ( i_size ),
680                 p_vout->p_rendered_pic->p_v, i_size / 4 );
681         memcpy( p_vout->p_sys->p_xvimage->data + ( i_size ) + ( i_size / 4 ),
682                 p_vout->p_rendered_pic->p_u, i_size / 4 );
683         break;
684     }
685
686     if( b_draw )
687     {
688         XVideoDisplay( p_vout );
689     }
690 }
691
692 static void vout_SetPalette( p_vout_thread_t p_vout,
693                              u16 *red, u16 *green, u16 *blue, u16 *transp )
694 {
695     return;
696 }
697
698 /* following functions are local */
699
700 /*****************************************************************************
701  * XVideoUpdateImgSizeIfRequired 
702  *****************************************************************************
703  * This function checks to see if the image to be displayed is of a different
704  * size to the last image displayed. If so, the old shm block must be
705  * destroyed and a new one created.
706  * Note: the "image size" is the size of the image to be passed to the Xv
707  * extension (which is probably different to the size of the output window).
708  *****************************************************************************/
709 static int XVideoUpdateImgSizeIfRequired( vout_thread_t *p_vout )
710 {
711     int i_img_width         = p_vout->p_rendered_pic->i_width;
712     int i_img_height        = p_vout->p_rendered_pic->i_height;
713
714     if( p_vout->p_sys->i_image_width != i_img_width
715             || p_vout->p_sys->i_image_height != i_img_height )
716     {
717         if( p_vout->p_sys->i_image_width != 0
718              && p_vout->p_sys->i_image_height != 0 )
719         {
720             /* Destroy XvImage to change its size */
721             vout_End( p_vout );
722         }
723
724         p_vout->p_sys->i_image_width  = i_img_width;
725         p_vout->p_sys->i_image_height = i_img_height;
726
727         /* Create XvImage using XShm extension */
728         if( XVideoCreateShmImage( p_vout->p_sys->p_display,
729                                   p_vout->p_sys->xv_port,
730                                   &p_vout->p_sys->p_xvimage,
731                                   &p_vout->p_sys->shm_info,
732                                   i_img_width, i_img_height ) )
733         {
734             intf_ErrMsg( "vout: failed to create xvimage." );
735             p_vout->p_sys->i_image_width = 0;
736             return( 1 );
737         }
738
739         /* Set bytes per line and initialize buffers */
740         p_vout->i_bytes_per_line =
741             (p_vout->p_sys->p_xvimage->data_size) /
742             (p_vout->p_sys->p_xvimage->height);
743
744     }
745
746     return( 0 );
747 }
748
749 /*****************************************************************************
750  * XVideoCheckForXv: check for the XVideo extension
751  *****************************************************************************/
752 static int XVideoCheckForXv( Display *dpy )
753 {
754     unsigned int i;
755
756     switch( XvQueryExtension( dpy, &i, &i, &i, &i, &i ) )
757     {
758         case Success:
759             return( 1 );
760
761         case XvBadExtension:
762             intf_WarnMsg( 3, "vout error: XvBadExtension" );
763             return( 0 );
764
765         case XvBadAlloc:
766             intf_WarnMsg( 3, "vout error: XvBadAlloc" );
767             return( 0 );
768
769         default:
770             intf_WarnMsg( 3, "vout error: XvQueryExtension failed" );
771             return( 0 );
772     }
773 }
774
775 /*****************************************************************************
776  * XVideoCreateWindow: open and set-up XVideo main window
777  *****************************************************************************/
778 static int XVideoCreateWindow( vout_thread_t *p_vout )
779 {
780     XSizeHints              xsize_hints;
781     XSetWindowAttributes    xwindow_attributes;
782     XGCValues               xgcvalues;
783     XEvent                  xevent;
784     Atom                    prop;
785     mwmhints_t              mwmhints;
786     
787     boolean_t               b_expose;
788     boolean_t               b_configure_notify;
789     boolean_t               b_map_notify;
790
791
792     /* Set main window's size */
793     /* If we're full screen, we're full screen! */
794     if( p_vout->b_fullscreen )
795     {
796         p_vout->p_sys->i_window_width = DisplayWidth( p_vout->p_sys->p_display,
797                                                       p_vout->p_sys->i_screen );
798         p_vout->p_sys->i_window_height =  DisplayHeight( p_vout->p_sys->p_display,
799                                                          p_vout->p_sys->i_screen );
800 /*      p_vout->i_width =  p_vout->p_sys->i_window_width;
801         p_vout->i_height = p_vout->p_sys->i_window_height; */
802     }
803     else
804     {
805         p_vout->p_sys->i_window_width =  main_GetIntVariable( VOUT_WIDTH_VAR,
806                                                        VOUT_WIDTH_DEFAULT );
807         p_vout->p_sys->i_window_height = main_GetIntVariable( VOUT_HEIGHT_VAR,
808                                                        VOUT_HEIGHT_DEFAULT );
809     }
810
811     /* Prepare window manager hints and properties */
812     xsize_hints.base_width          = p_vout->p_sys->i_window_width;
813     xsize_hints.base_height         = p_vout->p_sys->i_window_height;
814     xsize_hints.flags               = PSize;
815     p_vout->p_sys->wm_protocols     = XInternAtom( p_vout->p_sys->p_display,
816                                                    "WM_PROTOCOLS", True );
817     p_vout->p_sys->wm_delete_window = XInternAtom( p_vout->p_sys->p_display,
818                                                    "WM_DELETE_WINDOW", True );
819
820     /* Prepare window attributes */
821     xwindow_attributes.background_pixel = BlackPixel( p_vout->p_sys->p_display,
822                                                       p_vout->p_sys->i_screen );
823
824     xwindow_attributes.event_mask = ExposureMask | StructureNotifyMask;
825
826     /* Create the window and set hints - the window must receive ConfigureNotify
827      * events, and, until it is displayed, Expose and MapNotify events. */
828     p_vout->p_sys->window =
829             XCreateWindow( p_vout->p_sys->p_display,
830                            DefaultRootWindow( p_vout->p_sys->p_display ),
831                            0, 0,
832                            p_vout->p_sys->i_window_width,
833                            p_vout->p_sys->i_window_height, 1,
834                            0, InputOutput, 0,
835                            CWBackPixel | CWEventMask,
836                            &xwindow_attributes );
837
838     if ( p_vout->b_fullscreen )
839     {
840         prop = XInternAtom(p_vout->p_sys->p_display, "_MOTIF_WM_HINTS", False);
841         mwmhints.flags = MWM_HINTS_DECORATIONS;
842         mwmhints.decorations = 0;
843         XChangeProperty( p_vout->p_sys->p_display, p_vout->p_sys->window,
844                          prop, prop, 32, PropModeReplace,
845                          (unsigned char *)&mwmhints, PROP_MWM_HINTS_ELEMENTS );
846
847         XSetTransientForHint( p_vout->p_sys->p_display,
848                               p_vout->p_sys->window, None );
849         XRaiseWindow( p_vout->p_sys->p_display, p_vout->p_sys->window );
850     }
851
852     
853     /* Set window manager hints and properties: size hints, command,
854      * window's name, and accepted protocols */
855     XSetWMNormalHints( p_vout->p_sys->p_display, p_vout->p_sys->window,
856                        &xsize_hints );
857     XSetCommand( p_vout->p_sys->p_display, p_vout->p_sys->window,
858                  p_main->ppsz_argv, p_main->i_argc );
859     XStoreName( p_vout->p_sys->p_display, p_vout->p_sys->window,
860                 VOUT_TITLE " (XVideo output)" );
861
862     if( (p_vout->p_sys->wm_protocols == None)        /* use WM_DELETE_WINDOW */
863         || (p_vout->p_sys->wm_delete_window == None)
864         || !XSetWMProtocols( p_vout->p_sys->p_display, p_vout->p_sys->window,
865                              &p_vout->p_sys->wm_delete_window, 1 ) )
866     {
867         /* WM_DELETE_WINDOW is not supported by window manager */
868         intf_Msg( "vout error: missing or bad window manager" );
869     }
870
871     /* Creation of a graphic context that doesn't generate a GraphicsExpose
872      * event when using functions like XCopyArea */
873     xgcvalues.graphics_exposures = False;
874     p_vout->p_sys->gc = XCreateGC( p_vout->p_sys->p_display,
875                                    p_vout->p_sys->window,
876                                    GCGraphicsExposures, &xgcvalues);
877
878     /* Send orders to server, and wait until window is displayed - three
879      * events must be received: a MapNotify event, an Expose event allowing
880      * drawing in the window, and a ConfigureNotify to get the window
881      * dimensions. Once those events have been received, only ConfigureNotify
882      * events need to be received. */
883     b_expose = 0;
884     b_configure_notify = 0;
885     b_map_notify = 0;
886     XMapWindow( p_vout->p_sys->p_display, p_vout->p_sys->window);
887     do
888     {
889         XNextEvent( p_vout->p_sys->p_display, &xevent);
890         if( (xevent.type == Expose)
891             && (xevent.xexpose.window == p_vout->p_sys->window) )
892         {
893             b_expose = 1;
894         }
895         else if( (xevent.type == MapNotify)
896                  && (xevent.xmap.window == p_vout->p_sys->window) )
897         {
898             b_map_notify = 1;
899         }
900         else if( (xevent.type == ConfigureNotify)
901                  && (xevent.xconfigure.window == p_vout->p_sys->window) )
902         {
903             b_configure_notify = 1;
904             p_vout->p_sys->i_window_width = xevent.xconfigure.width;
905             p_vout->p_sys->i_window_height = xevent.xconfigure.height;
906         }
907     } while( !( b_expose && b_configure_notify && b_map_notify ) );
908
909     XSelectInput( p_vout->p_sys->p_display, p_vout->p_sys->window,
910                   StructureNotifyMask | KeyPressMask |
911                   ButtonPressMask | ButtonReleaseMask | 
912                   PointerMotionMask );
913
914     if( p_vout->b_fullscreen )
915     {
916         XSetInputFocus( p_vout->p_sys->p_display, p_vout->p_sys->window,
917                         RevertToNone, CurrentTime );
918         XMoveWindow( p_vout->p_sys->p_display, p_vout->p_sys->window, 0, 0 );
919     }
920
921     /* Create YUV output sub-window. */
922     p_vout->p_sys->yuv_window=XCreateSimpleWindow( p_vout->p_sys->p_display,
923                          p_vout->p_sys->window, 0, 0, 1, 1, 0,
924                          BlackPixel( p_vout->p_sys->p_display,
925                                          p_vout->p_sys->i_screen ),
926                          WhitePixel( p_vout->p_sys->p_display,
927                                          p_vout->p_sys->i_screen ) );
928  
929     p_vout->p_sys->yuv_gc = XCreateGC( p_vout->p_sys->p_display,
930                                         p_vout->p_sys->yuv_window,
931                                         GCGraphicsExposures, &xgcvalues );
932
933     XSetWindowBackground( p_vout->p_sys->p_display, p_vout->p_sys->yuv_window,
934              BlackPixel(p_vout->p_sys->p_display, p_vout->p_sys->i_screen ) );
935
936     XMapWindow( p_vout->p_sys->p_display, p_vout->p_sys->yuv_window );
937     XSelectInput( p_vout->p_sys->p_display, p_vout->p_sys->yuv_window,
938                   ExposureMask );
939
940     /* If the cursor was formerly blank than blank it again */
941     if( !p_vout->p_sys->b_mouse_pointer_visible )
942     {
943         X11ToggleMousePointer( p_vout );
944         X11ToggleMousePointer( p_vout );
945     }
946
947     return( 0 );
948 }
949
950 static void XVideoDestroyWindow( vout_thread_t *p_vout )
951 {
952     XFreeGC( p_vout->p_sys->p_display, p_vout->p_sys->yuv_gc );
953     XDestroyWindow( p_vout->p_sys->p_display, p_vout->p_sys->yuv_window );
954
955     XUnmapWindow( p_vout->p_sys->p_display, p_vout->p_sys->window );
956     XFreeGC( p_vout->p_sys->p_display, p_vout->p_sys->gc );
957     XDestroyWindow( p_vout->p_sys->p_display, p_vout->p_sys->window );
958 }
959
960 /*****************************************************************************
961  * XVideoCreateShmImage: create an XvImage using shared memory extension
962  *****************************************************************************
963  * Prepare an XvImage for display function.
964  * The order of the operations respects the recommandations of the mit-shm
965  * document by J.Corbet and K.Packard. Most of the parameters were copied from
966  * there.
967  *****************************************************************************/
968 static int XVideoCreateShmImage( Display* dpy, int xv_port,
969                                     XvImage **pp_xvimage,
970                                     XShmSegmentInfo *p_shm_info,
971                                     int i_width, int i_height )
972 {
973     *pp_xvimage = XvShmCreateImage( dpy, xv_port,
974                                     GUID_YUV12_PLANAR, 0,
975                                     i_width, i_height,
976                                     p_shm_info );
977     if( !(*pp_xvimage) )
978     {
979         intf_ErrMsg( "vout error: XvShmCreateImage failed." );
980         return( -1 );
981     }
982
983     p_shm_info->shmid    = shmget( IPC_PRIVATE, (*pp_xvimage)->data_size,
984                                    IPC_CREAT | 0777 );
985     if( p_shm_info->shmid < 0)                                      /* error */
986     {
987         intf_ErrMsg( "vout error: cannot allocate shared image data (%s)",
988                     strerror(errno));
989         return( 1 );
990     }
991
992     p_shm_info->shmaddr  = (*pp_xvimage)->data = shmat( p_shm_info->shmid,
993                                                         0, 0 );
994     p_shm_info->readOnly = False;
995
996 #if 0
997     /* Mark the shm segment to be removed when there will be no more
998      * attachements, so it is automatic on process exit or after shmdt */
999     shmctl( p_shm_info->shmid, IPC_RMID, 0 );
1000 #endif
1001
1002     if( !XShmAttach( dpy, p_shm_info ) )
1003     {
1004         intf_ErrMsg( "vout error: XShmAttach failed" );
1005         shmctl( p_shm_info->shmid, IPC_RMID, 0 );
1006         shmdt( p_shm_info->shmaddr );
1007         return( -1 );
1008     }
1009
1010     /* Send image to X server. This instruction is required, since having
1011      * built a Shm XImage and not using it causes an error on XCloseDisplay */
1012     XFlush( dpy );
1013
1014     return( 0 );
1015 }
1016
1017 /*****************************************************************************
1018  * XVideoDestroyShmImage
1019  *****************************************************************************
1020  * Destroy XImage AND associated data. Detach shared memory segment from
1021  * server and process, then free it. If pointer is NULL, the image won't be
1022  * destroyed (see vout_ManageOutputMethod())
1023  *****************************************************************************/
1024 static void XVideoDestroyShmImage( vout_thread_t *p_vout, XvImage *p_xvimage,
1025                                    XShmSegmentInfo *p_shm_info )
1026 {
1027     /* If pointer is NULL, do nothing */
1028     if( p_xvimage == NULL )
1029     {
1030         return;
1031     }
1032
1033     XShmDetach( p_vout->p_sys->p_display, p_shm_info );/* detach from server */
1034 #if 0
1035     XDestroyImage( p_ximage ); /* XXX */
1036 #endif
1037
1038     shmctl( p_shm_info->shmid, IPC_RMID, 0 );
1039
1040     if( shmdt( p_shm_info->shmaddr ) )  /* detach shared memory from process */
1041     {
1042         intf_ErrMsg( "vout error: cannot detach shared memory (%s)",
1043                      strerror(errno) );
1044     }
1045 }
1046
1047 /*****************************************************************************
1048  * XVideoEnableScreenSaver: enable screen saver
1049  *****************************************************************************
1050  * This function enable the screen saver on a display after it had been
1051  * disabled by XDisableScreenSaver. Both functions use a counter mechanism to
1052  * know wether the screen saver can be activated or not: if n successive calls
1053  * are made to XDisableScreenSaver, n successive calls to XEnableScreenSaver
1054  * will be required before the screen saver could effectively be activated.
1055  *****************************************************************************/
1056 void XVideoEnableScreenSaver( vout_thread_t *p_vout )
1057 {
1058     intf_DbgMsg( "intf: enabling screen saver" );
1059     XSetScreenSaver( p_vout->p_sys->p_display, p_vout->p_sys->i_ss_timeout,
1060                      p_vout->p_sys->i_ss_interval,
1061                      p_vout->p_sys->i_ss_blanking,
1062                      p_vout->p_sys->i_ss_exposure );
1063 }
1064
1065 /*****************************************************************************
1066  * XVideoDisableScreenSaver: disable screen saver
1067  *****************************************************************************
1068  * See XEnableScreenSaver
1069  *****************************************************************************/
1070 void XVideoDisableScreenSaver( vout_thread_t *p_vout )
1071 {
1072     /* Save screen saver informations */
1073     XGetScreenSaver( p_vout->p_sys->p_display, &p_vout->p_sys->i_ss_timeout,
1074                      &p_vout->p_sys->i_ss_interval,
1075                      &p_vout->p_sys->i_ss_blanking,
1076                      &p_vout->p_sys->i_ss_exposure );
1077
1078     /* Disable screen saver */
1079     intf_DbgMsg( "intf: disabling screen saver" );
1080     XSetScreenSaver( p_vout->p_sys->p_display, 0,
1081                      p_vout->p_sys->i_ss_interval,
1082                      p_vout->p_sys->i_ss_blanking,
1083                      p_vout->p_sys->i_ss_exposure );
1084 }
1085
1086 /*****************************************************************************
1087  * X11ToggleMousePointer: hide or show the mouse pointer
1088  *****************************************************************************
1089  * This function hides the X pointer if requested.
1090  *****************************************************************************/
1091 void X11ToggleMousePointer( vout_thread_t *p_vout )
1092 {
1093
1094     if( p_vout->p_sys->b_mouse_pointer_visible )
1095     {
1096         XDefineCursor( p_vout->p_sys->p_display,
1097                        p_vout->p_sys->window,
1098                        p_vout->p_sys->blank_cursor );
1099         p_vout->p_sys->b_mouse_pointer_visible = 0;
1100     }
1101     else
1102     {
1103         XUndefineCursor( p_vout->p_sys->p_display, p_vout->p_sys->window );
1104         p_vout->p_sys->b_mouse_pointer_visible = 1;
1105     }
1106 }
1107
1108 /* This based on some code in SetBufferPicture... At the moment it's only
1109  * used by the xvideo plugin, but others may want to use it. */
1110 static void XVideoOutputCoords( const picture_t *p_pic, const boolean_t scale,
1111                                 const int win_w, const int win_h,
1112                                 int *dx, int *dy, int *w, int *h)
1113 {
1114     if( !scale )
1115     {
1116         *w = p_pic->i_width; *h = p_pic->i_height;
1117     }
1118     else
1119     {
1120         *w = win_w;
1121         switch( p_pic->i_aspect_ratio )
1122         {
1123             case AR_3_4_PICTURE:
1124                 *h = win_w * 3 / 4;
1125                 break;
1126
1127             case AR_16_9_PICTURE:
1128                 *h = win_w * 9 / 16;
1129                 break;
1130
1131             case AR_221_1_PICTURE:
1132                 *h = win_w * 100 / 221;
1133                 break;
1134
1135             case AR_SQUARE_PICTURE:
1136             default:
1137                 *h = win_w * p_pic->i_height / p_pic->i_width;
1138                 break;
1139         }
1140
1141         if( *h > win_h )
1142         {
1143             *h = win_h;
1144             switch( p_pic->i_aspect_ratio )
1145             {
1146                 case AR_3_4_PICTURE:
1147                     *w = win_h * 4 / 3;
1148                     break;
1149
1150                 case AR_16_9_PICTURE:
1151                     *w = win_h * 16 / 9;
1152                     break;
1153
1154                 case AR_221_1_PICTURE:
1155                     *w = win_h * 221 / 100;
1156                     break;
1157
1158                 case AR_SQUARE_PICTURE:
1159                 default:
1160                     *w = win_h * p_pic->i_width / p_pic->i_height;
1161                     break;
1162             }
1163         }
1164     }
1165
1166     /* Set picture position */
1167     *dx = (win_w - *w) / 2;
1168     *dy = (win_h - *h) / 2;
1169 }
1170
1171
1172 /*****************************************************************************
1173  * XVideoGetPort: get YUV12 port
1174  *****************************************************************************
1175  * 
1176  *****************************************************************************/
1177 static int XVideoGetPort( Display *dpy )
1178 {
1179     XvAdaptorInfo *p_adaptor;
1180     int i_adaptor, i_num_adaptors, i_requested_adaptor;
1181     int i_selected_port;
1182
1183     switch( XvQueryAdaptors( dpy, DefaultRootWindow( dpy ),
1184                              &i_num_adaptors, &p_adaptor ) )
1185     {
1186         case Success:
1187             break;
1188
1189         case XvBadExtension:
1190             intf_WarnMsg( 3, "vout error: XvBadExtension for XvQueryAdaptors" );
1191             return( -1 );
1192
1193         case XvBadAlloc:
1194             intf_WarnMsg( 3, "vout error: XvBadAlloc for XvQueryAdaptors" );
1195             return( -1 );
1196
1197         default:
1198             intf_WarnMsg( 3, "vout error: XvQueryAdaptors failed" );
1199             return( -1 );
1200     }
1201
1202     i_selected_port = -1;
1203     i_requested_adaptor = main_GetIntVariable( VOUT_XVADAPTOR_VAR, -1 );
1204
1205     /* No special xv port has been requested so try all of them */
1206     for( i_adaptor = 0; i_adaptor < i_num_adaptors; ++i_adaptor )
1207     {
1208         int i_port;
1209
1210         /* If we requested an adaptor and it's not this one, we aren't
1211          * interested */
1212         if( i_requested_adaptor != -1 && i_adaptor != i_requested_adaptor )
1213         {
1214             continue;
1215         }
1216
1217         /* If the adaptor doesn't have the required properties, skip it */
1218         if( !( p_adaptor[ i_adaptor ].type & XvInputMask ) ||
1219             !( p_adaptor[ i_adaptor ].type & XvImageMask ) )
1220         {
1221             continue;
1222         }
1223
1224         for( i_port = p_adaptor[i_adaptor].base_id;
1225              i_port < p_adaptor[i_adaptor].base_id
1226                        + p_adaptor[i_adaptor].num_ports;
1227              i_port++ )
1228         {
1229             XvImageFormatValues *p_formats;
1230             int i_format, i_num_formats;
1231
1232             /* If we already found a port, we aren't interested */
1233             if( i_selected_port != -1 )
1234             {
1235                 continue;
1236             }
1237
1238             /* Check that port supports YUV12 planar format... */
1239             p_formats = XvListImageFormats( dpy, i_port, &i_num_formats );
1240
1241             for( i_format = 0; i_format < i_num_formats; i_format++ )
1242             {
1243                 XvEncodingInfo  *p_enc;
1244                 int             i_enc, i_num_encodings;
1245                 XvAttribute     *p_attr;
1246                 int             i_attr, i_num_attributes;
1247
1248                 if( p_formats[ i_format ].id != GUID_YUV12_PLANAR )
1249                 {
1250                     continue;
1251                 }
1252
1253                 /* Found a matching port, print a description of this port */
1254                 i_selected_port = i_port;
1255
1256                 intf_WarnMsg( 3, "vout: XVideoGetPort found adaptor %i port %i",
1257                                  i_adaptor, i_port);
1258                 intf_WarnMsg( 3, "  image format 0x%x (%4.4s) %s supported",
1259                                  p_formats[ i_format ].id,
1260                                  (char *)&p_formats[ i_format ].id,
1261                                  ( p_formats[ i_format ].format
1262                                     == XvPacked ) ? "packed" : "planar" );
1263
1264                 intf_WarnMsg( 4, " encoding list:" );
1265
1266                 if( XvQueryEncodings( dpy, i_port, &i_num_encodings, &p_enc )
1267                      != Success )
1268                 {
1269                     intf_WarnMsg( 4, "  XvQueryEncodings failed" );
1270                     continue;
1271                 }
1272
1273                 for( i_enc = 0; i_enc < i_num_encodings; i_enc++ )
1274                 {
1275                     intf_WarnMsg( 4, "  id=%ld, name=%s, size=%ldx%ld,"
1276                                      " numerator=%d, denominator=%d",
1277                                   p_enc[i_enc].encoding_id, p_enc[i_enc].name,
1278                                   p_enc[i_enc].width, p_enc[i_enc].height,
1279                                   p_enc[i_enc].rate.numerator,
1280                                   p_enc[i_enc].rate.denominator );
1281                 }
1282
1283                 if( p_enc != NULL )
1284                 {
1285                     XvFreeEncodingInfo( p_enc );
1286                 }
1287
1288                 intf_WarnMsg( 4, " attribute list:" );
1289                 p_attr = XvQueryPortAttributes( dpy, i_port,
1290                                                 &i_num_attributes );
1291                 for( i_attr = 0; i_attr < i_num_attributes; i_attr++ )
1292                 {
1293                     intf_WarnMsg( 4,
1294                           "  name=%s, flags=[%s%s ], min=%i, max=%i",
1295                           p_attr[i_attr].name,
1296                           (p_attr[i_attr].flags & XvGettable) ? " get" : "",
1297                           (p_attr[i_attr].flags & XvSettable) ? " set" : "",
1298                           p_attr[i_attr].min_value, p_attr[i_attr].max_value );
1299                 }
1300
1301                 if( p_attr != NULL )
1302                 {
1303                     XFree( p_attr );
1304                 }
1305             }
1306
1307             if( p_formats != NULL )
1308             {
1309                 XFree( p_formats );
1310             }
1311         }
1312     }
1313
1314     if( i_num_adaptors > 0 )
1315     {
1316         XvFreeAdaptorInfo( p_adaptor );
1317     }
1318
1319     if( i_selected_port == -1 )
1320     {
1321         if( i_requested_adaptor == -1 )
1322         {
1323             intf_WarnMsg( 3, "vout: no XVideo port found supporting YUV12" );
1324         }
1325         else
1326         {
1327             intf_WarnMsg( 3, "vout: XVideo adaptor %i does not support YUV12",
1328                              i_requested_adaptor );
1329         }
1330     }
1331
1332     return( i_selected_port );
1333 }
1334
1335
1336 /*****************************************************************************
1337  * XVideoDisplay: display image
1338  *****************************************************************************
1339  * This function displays the image stored in p_vout->p_sys->p_xvimage.
1340  * The image is scaled to fit in the output window (and to have the correct
1341  * aspect ratio).
1342  *****************************************************************************/
1343 static void XVideoDisplay( vout_thread_t *p_vout )
1344 {
1345     int     i_dest_width, i_dest_height, i_dest_x, i_dest_y;
1346
1347     if( !p_vout->p_sys->p_xvimage )
1348     {
1349         return;
1350     }
1351
1352     XVideoOutputCoords( p_vout->p_rendered_pic, p_vout->b_scale,
1353                         p_vout->p_sys->i_window_width,
1354                         p_vout->p_sys->i_window_height,
1355                         &i_dest_x, &i_dest_y,
1356                         &i_dest_width, &i_dest_height);
1357
1358     XvShmPutImage( p_vout->p_sys->p_display, p_vout->p_sys->xv_port,
1359                    p_vout->p_sys->yuv_window, p_vout->p_sys->gc,
1360                    p_vout->p_sys->p_xvimage,
1361                    0 /*src_x*/, 0 /*src_y*/,
1362                    p_vout->p_rendered_pic->i_width,
1363                    p_vout->p_rendered_pic->i_height,
1364                    0 /*dest_x*/, 0 /*dest_y*/, i_dest_width, i_dest_height,
1365                    False );
1366
1367     XResizeWindow( p_vout->p_sys->p_display, p_vout->p_sys->yuv_window,
1368                    i_dest_width, i_dest_height );
1369     XMoveWindow( p_vout->p_sys->p_display, p_vout->p_sys->yuv_window,
1370                  i_dest_x, i_dest_y );
1371
1372     /* Send the order to the X server */
1373     XSync( p_vout->p_sys->p_display, False );
1374 }
1375
1376 #if 0
1377 /*****************************************************************************
1378  * XVideoSetAttribute
1379  *****************************************************************************
1380  * This function can be used to set attributes, e.g. XV_BRIGHTNESS and
1381  * XV_CONTRAST. "f_value" should be in the range of 0 to 1.
1382  *****************************************************************************/
1383 static void XVideoSetAttribute( vout_thread_t *p_vout,
1384                                 char *attr_name, float f_value )
1385 {
1386     int             i_attrib;
1387     XvAttribute    *p_attrib;
1388     Display        *p_dpy   = p_vout->p_sys->p_display;
1389     int             xv_port = p_vout->p_sys->xv_port;
1390
1391     p_attrib = XvQueryPortAttributes( p_dpy, xv_port, &i_attrib );
1392
1393     do
1394     {
1395         i_attrib--;
1396
1397         if( i_attrib >= 0 && !strcmp( p_attrib[ i_attrib ].name, attr_name ) )
1398         {
1399             int i_sv = f_value * ( p_attrib[ i_attrib ].max_value
1400                                     - p_attrib[ i_attrib ].min_value + 1 )
1401                         + p_attrib[ i_attrib ].min_value;
1402
1403             XvSetPortAttribute( p_dpy, xv_port,
1404                             XInternAtom( p_dpy, attr_name, False ), i_sv );
1405             break;
1406         }
1407
1408     } while( i_attrib > 0 );
1409
1410     if( p_attrib )
1411         XFree( p_attrib );
1412 }
1413 #endif
1414