]> git.sesse.net Git - vlc/blob - plugins/x11/vout_xvideo.c
0f2a1ad9243650943c0ec0b747861cedce05d142
[vlc] / plugins / x11 / vout_xvideo.c
1 /*****************************************************************************
2  * vout_xvideo.c: Xvideo video output display method
3  *****************************************************************************
4  * Copyright (C) 1998-2001 VideoLAN
5  * $Id: vout_xvideo.c,v 1.40 2001/12/17 03:38:21 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 #include <X11/extensions/dpms.h>
58
59 #include "common.h"
60 #include "intf_msg.h"
61 #include "threads.h"
62 #include "mtime.h"
63 #include "tests.h"
64
65 #include "video.h"
66 #include "video_output.h"
67 #include "vout_common.h"
68
69 #include "interface.h"
70 #include "netutils.h"                                 /* network_ChannelJoin */
71
72 #include "stream_control.h"                 /* needed by input_ext-intf.h... */
73 #include "input_ext-intf.h"
74
75 #include "modules.h"
76 #include "modules_export.h"
77
78 #define XVIDEO_MAX_DIRECTBUFFERS 5
79 #define GUID_YUV12_PLANAR 0x32315659
80
81 /*****************************************************************************
82  * Local prototypes
83  *****************************************************************************/
84 static int  vout_Probe     ( probedata_t * );
85 static int  vout_Create    ( vout_thread_t * );
86 static int  vout_Init      ( vout_thread_t * );
87 static void vout_End       ( vout_thread_t * );
88 static void vout_Destroy   ( vout_thread_t * );
89 static void vout_Display   ( vout_thread_t *, picture_t * );
90
91 static int  XVideoNewPicture   ( vout_thread_t *, picture_t * );
92
93 static XvImage *CreateShmImage ( Display *, int, XShmSegmentInfo *, int, int );
94 static void     DestroyShmImage( Display *, XvImage *, XShmSegmentInfo * );
95
96 static int  CheckForXVideo     ( Display * );
97 static int  GetXVideoPort      ( Display * );
98
99 /*static void XVideoSetAttribute       ( vout_thread_t *, char *, float );*/
100
101 /*****************************************************************************
102  * Functions exported as capabilities. They are declared as static so that
103  * we don't pollute the namespace too much.
104  *****************************************************************************/
105 void _M( vout_getfunctions )( function_list_t * p_function_list )
106 {
107     p_function_list->pf_probe = vout_Probe;
108     p_function_list->functions.vout.pf_create     = vout_Create;
109     p_function_list->functions.vout.pf_init       = vout_Init;
110     p_function_list->functions.vout.pf_end        = vout_End;
111     p_function_list->functions.vout.pf_destroy    = vout_Destroy;
112     p_function_list->functions.vout.pf_manage     = _M( vout_Manage );
113     p_function_list->functions.vout.pf_display    = vout_Display;
114     p_function_list->functions.vout.pf_setpalette = NULL;
115 }
116
117 /*****************************************************************************
118  * vout_Probe: probe the video driver and return a score
119  *****************************************************************************
120  * This returns a score to the plugin manager so that it can select the best
121  * plugin.
122  *****************************************************************************/
123 static int vout_Probe( probedata_t *p_data )
124 {
125     Display *p_display;                                   /* display pointer */
126     char    *psz_display;
127
128     /* Open display, unsing 'vlc_display' or DISPLAY environment variable */
129     psz_display = XDisplayName( main_GetPszVariable(VOUT_DISPLAY_VAR, NULL) );
130     p_display = XOpenDisplay( psz_display );
131     if( p_display == NULL )                                         /* error */
132     {
133         intf_WarnMsg( 3, "vout: Xvideo cannot open display %s", psz_display );
134         intf_WarnMsg( 3, "vout: Xvideo not supported" );
135         return( 0 );
136     }
137
138     if( !CheckForXVideo( p_display ) )
139     {
140         intf_WarnMsg( 3, "vout: Xvideo not supported" );
141         XCloseDisplay( p_display );
142         return( 0 );
143     }
144
145     if( GetXVideoPort( p_display ) < 0 )
146     {
147         intf_WarnMsg( 3, "vout: Xvideo not supported" );
148         XCloseDisplay( p_display );
149         return( 0 );
150     }
151
152     /* Clean-up everyting */
153     XCloseDisplay( p_display );
154
155     if( TestMethod( VOUT_METHOD_VAR, "xvideo" ) )
156     {
157         return( 999 );
158     }
159
160     return( 150 );
161 }
162
163 /*****************************************************************************
164  * vout_Create: allocate XVideo video thread output method
165  *****************************************************************************
166  * This function allocates and initialize a XVideo vout method. It uses some of
167  * the vout properties to choose the window size, and change them according to
168  * the actual properties of the display.
169  *****************************************************************************/
170 static int vout_Create( vout_thread_t *p_vout )
171 {
172     char *psz_display;
173     XColor cursor_color;
174
175     /* Allocate structure */
176     p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
177     if( p_vout->p_sys == NULL )
178     {
179         intf_ErrMsg( "vout error: %s", strerror(ENOMEM) );
180         return( 1 );
181     }
182
183     /* Open display, unsing 'vlc_display' or DISPLAY environment variable */
184     psz_display = XDisplayName( main_GetPszVariable( VOUT_DISPLAY_VAR, NULL ) );
185     p_vout->p_sys->p_display = XOpenDisplay( psz_display );
186
187     if( p_vout->p_sys->p_display == NULL )                          /* error */
188     {
189         intf_ErrMsg( "vout error: cannot open display %s", psz_display );
190         free( p_vout->p_sys );
191         return( 1 );
192     }
193     p_vout->p_sys->i_screen = DefaultScreen( p_vout->p_sys->p_display );
194
195     if( !CheckForXVideo( p_vout->p_sys->p_display ) )
196     {
197         intf_ErrMsg( "vout error: no XVideo extension" );
198         XCloseDisplay( p_vout->p_sys->p_display );
199         free( p_vout->p_sys );
200         return( 1 );
201     }
202
203     /* Check we have access to a video port */
204     if( (p_vout->p_sys->i_xvport = GetXVideoPort(p_vout->p_sys->p_display)) <0 )
205     {
206         intf_ErrMsg( "vout error: cannot get XVideo port" );
207         XCloseDisplay( p_vout->p_sys->p_display );
208         free( p_vout->p_sys );
209         return 1;
210     }
211     intf_DbgMsg( "Using xv port %d" , p_vout->p_sys->xv_port );
212
213     /* Create blank cursor (for mouse cursor autohiding) */
214     p_vout->p_sys->b_mouse_pointer_visible = 1;
215     p_vout->p_sys->cursor_pixmap = XCreatePixmap( p_vout->p_sys->p_display,
216                                                   DefaultRootWindow(
217                                                      p_vout->p_sys->p_display),
218                                                   1, 1, 1 );
219
220     XParseColor( p_vout->p_sys->p_display,
221                  XCreateColormap( p_vout->p_sys->p_display,
222                                   DefaultRootWindow(
223                                                     p_vout->p_sys->p_display ),
224                                   DefaultVisual(
225                                                 p_vout->p_sys->p_display,
226                                                 p_vout->p_sys->i_screen ),
227                                   AllocNone ),
228                  "black", &cursor_color );
229
230     p_vout->p_sys->blank_cursor = XCreatePixmapCursor(
231                                       p_vout->p_sys->p_display,
232                                       p_vout->p_sys->cursor_pixmap,
233                                       p_vout->p_sys->cursor_pixmap,
234                                       &cursor_color,
235                                       &cursor_color, 1, 1 );
236
237     /* Spawn base window - this window will include the video output window,
238      * but also command buttons, subtitles and other indicators */
239     if( _M( XCommonCreateWindow ) ( p_vout ) )
240     {
241         intf_ErrMsg( "vout error: no suitable Xvideo image input port" );
242         _M( XCommonDestroyWindow ) ( p_vout );
243         XCloseDisplay( p_vout->p_sys->p_display );
244         free( p_vout->p_sys );
245         return( 1 );
246     }
247
248 #if 0
249     /* XXX The brightness and contrast values should be read from environment
250      * XXX variables... */
251     XVideoSetAttribute( p_vout, "XV_BRIGHTNESS", 0.5 );
252     XVideoSetAttribute( p_vout, "XV_CONTRAST",   0.5 );
253 #endif
254
255     /* Disable screen saver and return */
256     _M( XCommonDisableScreenSaver ) ( p_vout );
257
258     return( 0 );
259 }
260
261 /*****************************************************************************
262  * vout_Init: initialize XVideo video thread output method
263  *****************************************************************************/
264 static int vout_Init( vout_thread_t *p_vout )
265 {
266     int i_index;
267     picture_t *p_pic;
268
269     I_OUTPUTPICTURES = 0;
270
271     /* Initialize the output structure */
272     switch( p_vout->render.i_chroma )
273     {
274         case YUV_420_PICTURE:
275             p_vout->output.i_chroma = p_vout->render.i_chroma;
276             p_vout->output.i_width  = p_vout->render.i_width;
277             p_vout->output.i_height = p_vout->render.i_height;
278             p_vout->output.i_aspect = p_vout->render.i_aspect;
279             break;
280
281         default:
282             return( 0 );
283     }
284
285     /* Try to initialize up to XVIDEO_MAX_DIRECTBUFFERS direct buffers */
286     while( I_OUTPUTPICTURES < XVIDEO_MAX_DIRECTBUFFERS )
287     {
288         p_pic = NULL;
289
290         /* Find an empty picture slot */
291         for( i_index = 0 ; i_index < VOUT_MAX_PICTURES ; i_index++ )
292         {
293             if( p_vout->p_picture[ i_index ].i_status == FREE_PICTURE )
294             {
295                 p_pic = p_vout->p_picture + i_index;
296                 break;
297             }
298         }
299
300         /* Allocate the picture */
301         if( XVideoNewPicture( p_vout, p_pic ) )
302         {
303             break;
304         }
305
306         p_pic->i_status        = DESTROYED_PICTURE;
307         p_pic->i_type          = DIRECT_PICTURE;
308
309         p_pic->i_left_margin   =
310         p_pic->i_right_margin  =
311         p_pic->i_top_margin    =
312         p_pic->i_bottom_margin = 0;
313
314         PP_OUTPUTPICTURE[ I_OUTPUTPICTURES ] = p_pic;
315
316         I_OUTPUTPICTURES++;
317     }
318
319     return( 0 );
320 }
321
322 /*****************************************************************************
323  * vout_End: terminate XVideo video thread output method
324  *****************************************************************************
325  * Destroy the XvImage. It is called at the end of the thread, but also each
326  * time the image is resized.
327  *****************************************************************************/
328 static void vout_End( vout_thread_t *p_vout )
329 {
330     int i_index;
331
332     /* Free the direct buffers we allocated */
333     for( i_index = I_OUTPUTPICTURES ; i_index ; )
334     {
335         i_index--;
336         DestroyShmImage( p_vout->p_sys->p_display,
337                          PP_OUTPUTPICTURE[ i_index ]->p_sys->p_xvimage,
338                          &PP_OUTPUTPICTURE[ i_index ]->p_sys->shminfo );
339         free( PP_OUTPUTPICTURE[ i_index ]->p_sys );
340     }
341 }
342
343 /*****************************************************************************
344  * vout_Destroy: destroy XVideo video thread output method
345  *****************************************************************************
346  * Terminate an output method created by vout_Create
347  *****************************************************************************/
348 static void vout_Destroy( vout_thread_t *p_vout )
349 {
350     /* Restore cursor if it was blanked */
351     if( !p_vout->p_sys->b_mouse_pointer_visible )
352     {
353         _M( XCommonToggleMousePointer ) ( p_vout );
354     }
355
356     /* Destroy blank cursor pixmap */
357     XFreePixmap( p_vout->p_sys->p_display, p_vout->p_sys->cursor_pixmap );
358
359     _M( XCommonEnableScreenSaver ) ( p_vout );
360     _M( XCommonDestroyWindow ) ( p_vout );
361     XCloseDisplay( p_vout->p_sys->p_display );
362
363     /* Destroy structure */
364     free( p_vout->p_sys );
365 }
366
367 /*****************************************************************************
368  * vout_Display: displays previously rendered output
369  *****************************************************************************
370  * This function sends the currently rendered image to X11 server.
371  * (The Xv extension takes care of "double-buffering".)
372  *****************************************************************************/
373 static void vout_Display( vout_thread_t *p_vout, picture_t *p_pic )
374 {
375     int i_width, i_height, i_x, i_y;
376
377     vout_PlacePicture( p_vout, p_vout->p_sys->i_width, p_vout->p_sys->i_height,
378                        &i_x, &i_y, &i_width, &i_height );
379
380     XvShmPutImage( p_vout->p_sys->p_display, p_vout->p_sys->i_xvport,
381                    p_vout->p_sys->yuv_window, p_vout->p_sys->gc,
382                    p_pic->p_sys->p_xvimage, 0 /*src_x*/, 0 /*src_y*/,
383                    p_vout->output.i_width, p_vout->output.i_height,
384                    0 /*dest_x*/, 0 /*dest_y*/, i_width, i_height,
385                    True );
386
387     XResizeWindow( p_vout->p_sys->p_display, p_vout->p_sys->yuv_window,
388                    i_width, i_height );
389
390     XMoveWindow( p_vout->p_sys->p_display, p_vout->p_sys->yuv_window,
391                  i_x, i_y );
392 }
393
394 /* following functions are local */
395
396 /*****************************************************************************
397  * CheckForXVideo: check for the XVideo extension
398  *****************************************************************************/
399 static int CheckForXVideo( Display *p_display )
400 {
401     unsigned int i;
402
403     switch( XvQueryExtension( p_display, &i, &i, &i, &i, &i ) )
404     {
405         case Success:
406             return( 1 );
407
408         case XvBadExtension:
409             intf_WarnMsg( 3, "vout error: XvBadExtension" );
410             return( 0 );
411
412         case XvBadAlloc:
413             intf_WarnMsg( 3, "vout error: XvBadAlloc" );
414             return( 0 );
415
416         default:
417             intf_WarnMsg( 3, "vout error: XvQueryExtension failed" );
418             return( 0 );
419     }
420 }
421
422 /*****************************************************************************
423  * XVideoNewPicture: allocate a picture
424  *****************************************************************************
425  * Returns 0 on success, -1 otherwise
426  *****************************************************************************/
427 static int XVideoNewPicture( vout_thread_t *p_vout, picture_t *p_pic )
428 {
429     int i_width  = p_vout->output.i_width;
430     int i_height = p_vout->output.i_height;
431
432     switch( p_vout->output.i_chroma )
433     {
434         case YUV_420_PICTURE:
435             /* We know this chroma, allocate a buffer which will be used
436              * directly by the decoder */
437             p_pic->p_sys = malloc( sizeof( picture_sys_t ) );
438
439             if( p_pic->p_sys == NULL )
440             {
441                 return -1;
442             }
443
444             /* Create XvImage using XShm extension */
445             p_pic->p_sys->p_xvimage =
446                 CreateShmImage( p_vout->p_sys->p_display,
447                                 p_vout->p_sys->i_xvport,
448                                 &p_pic->p_sys->shminfo,
449                                 p_vout->output.i_width,
450                                 p_vout->output.i_height );
451             if( p_pic->p_sys->p_xvimage == NULL )
452             {
453                 free( p_pic->p_sys );
454                 return -1;
455             }
456
457
458             /* Precalculate some values */
459             p_pic->i_size         = i_width * i_height;
460             p_pic->i_chroma_width = i_width / 2;
461             p_pic->i_chroma_size  = i_height * ( i_width / 2 );
462
463             /* FIXME: try to get the right i_bytes value from p_xvimage */
464             p_pic->planes[Y_PLANE].p_data  = p_pic->p_sys->p_xvimage->data;
465             p_pic->planes[Y_PLANE].i_bytes = p_pic->i_size * sizeof(u8);
466             p_pic->planes[Y_PLANE].i_line_bytes = i_width * sizeof(u8);
467
468             p_pic->planes[U_PLANE].p_data  = (u8*)p_pic->p_sys->p_xvimage->data
469                                                + p_pic->i_size * 5 / 4;
470             p_pic->planes[U_PLANE].i_bytes = p_pic->i_size * sizeof(u8) / 4;
471             p_pic->planes[U_PLANE].i_line_bytes = p_pic->i_chroma_width
472                                                    * sizeof(u8);
473
474             p_pic->planes[V_PLANE].p_data  = (u8*)p_pic->p_sys->p_xvimage->data
475                                                + p_pic->i_size;
476             p_pic->planes[V_PLANE].i_bytes = p_pic->i_size * sizeof(u8) / 4;
477             p_pic->planes[V_PLANE].i_line_bytes = p_pic->i_chroma_width
478                                                    * sizeof(u8);
479
480             p_pic->i_planes = 3;
481
482             return 0;
483
484         default:
485             /* Unknown chroma, tell the guy to get lost */
486             p_pic->i_planes = 0;
487
488             return -1;
489     }
490 }
491
492 /*****************************************************************************
493  * CreateShmImage: create an XvImage using shared memory extension
494  *****************************************************************************
495  * Prepare an XvImage for display function.
496  * The order of the operations respects the recommandations of the mit-shm
497  * document by J.Corbet and K.Packard. Most of the parameters were copied from
498  * there.
499  *****************************************************************************/
500 static XvImage *CreateShmImage( Display* p_display, int i_xvport,
501                                 XShmSegmentInfo *p_shminfo,
502                                 int i_width, int i_height )
503 {
504     XvImage *p_xvimage;
505
506     p_xvimage = XvShmCreateImage( p_display, i_xvport,
507                                   GUID_YUV12_PLANAR, 0,
508                                   i_width, i_height,
509                                   p_shminfo );
510     if( p_xvimage == NULL )
511     {
512         intf_ErrMsg( "vout error: XvShmCreateImage failed." );
513         return( NULL );
514     }
515
516     p_shminfo->shmid = shmget( IPC_PRIVATE, p_xvimage->data_size,
517                                IPC_CREAT | 0776 );
518     if( p_shminfo->shmid < 0 ) /* error */
519     {
520         intf_ErrMsg( "vout error: cannot allocate shared image data (%s)",
521                      strerror( errno ) );
522         return( NULL );
523     }
524
525     p_shminfo->shmaddr = p_xvimage->data = shmat( p_shminfo->shmid, 0, 0 );
526     p_shminfo->readOnly = False;
527
528     if( !XShmAttach( p_display, p_shminfo ) )
529     {
530         intf_ErrMsg( "vout error: XShmAttach failed" );
531         shmctl( p_shminfo->shmid, IPC_RMID, 0 );
532         shmdt( p_shminfo->shmaddr );
533         return( NULL );
534     }
535
536     /* Send image to X server. This instruction is required, since having
537      * built a Shm XImage and not using it causes an error on XCloseDisplay */
538     XSync( p_display, False );
539
540 #if 1
541     /* Mark the shm segment to be removed when there are no more
542      * attachements, so it is automatic on process exit or after shmdt */
543     shmctl( p_shminfo->shmid, IPC_RMID, 0 );
544 #endif
545
546     return( p_xvimage );
547 }
548
549 /*****************************************************************************
550  * DestroyShmImage
551  *****************************************************************************
552  * Destroy XImage AND associated data. Detach shared memory segment from
553  * server and process, then free it. If pointer is NULL, the image won't be
554  * destroyed (see vout_Manage())
555  *****************************************************************************/
556 static void DestroyShmImage( Display *p_display, XvImage *p_xvimage,
557                              XShmSegmentInfo *p_shminfo )
558 {
559     /* Detach from server */
560     XShmDetach( p_display, p_shminfo );
561     XSync( p_display, False );
562
563 #if 0
564     XDestroyImage( p_xvimage ); /* XXX */
565 #endif
566
567     XFree( p_xvimage );
568
569     if( shmdt( p_shminfo->shmaddr ) )   /* detach shared memory from process */
570     {
571         intf_ErrMsg( "vout error: cannot detach shared memory (%s)",
572                      strerror(errno) );
573     }
574 }
575
576 /*****************************************************************************
577  * GetXVideoPort: get YUV12 port
578  *****************************************************************************
579  * 
580  *****************************************************************************/
581 static int GetXVideoPort( Display *dpy )
582 {
583     XvAdaptorInfo *p_adaptor;
584     int i_adaptor, i_num_adaptors, i_requested_adaptor;
585     int i_selected_port;
586
587     switch( XvQueryAdaptors( dpy, DefaultRootWindow( dpy ),
588                              &i_num_adaptors, &p_adaptor ) )
589     {
590         case Success:
591             break;
592
593         case XvBadExtension:
594             intf_WarnMsg( 3, "vout error: XvBadExtension for XvQueryAdaptors" );
595             return( -1 );
596
597         case XvBadAlloc:
598             intf_WarnMsg( 3, "vout error: XvBadAlloc for XvQueryAdaptors" );
599             return( -1 );
600
601         default:
602             intf_WarnMsg( 3, "vout error: XvQueryAdaptors failed" );
603             return( -1 );
604     }
605
606     i_selected_port = -1;
607     i_requested_adaptor = main_GetIntVariable( VOUT_XVADAPTOR_VAR, -1 );
608
609     /* No special xv port has been requested so try all of them */
610     for( i_adaptor = 0; i_adaptor < i_num_adaptors; ++i_adaptor )
611     {
612         XvImageFormatValues *p_formats;
613         int i_format, i_num_formats;
614         int i_port;
615
616         /* If we requested an adaptor and it's not this one, we aren't
617          * interested */
618         if( i_requested_adaptor != -1 && i_adaptor != i_requested_adaptor )
619         {
620             continue;
621         }
622
623         /* If the adaptor doesn't have the required properties, skip it */
624         if( !( p_adaptor[ i_adaptor ].type & XvInputMask ) ||
625             !( p_adaptor[ i_adaptor ].type & XvImageMask ) )
626         {
627             continue;
628         }
629
630         /* Check that port supports YUV12 planar format... */
631         p_formats = XvListImageFormats( dpy, p_adaptor[i_adaptor].base_id,
632                                         &i_num_formats );
633
634         for( i_format = 0; i_format < i_num_formats; i_format++ )
635         {
636             XvEncodingInfo  *p_enc;
637             int             i_enc, i_num_encodings;
638             XvAttribute     *p_attr;
639             int             i_attr, i_num_attributes;
640
641             /* If this is not the format we want, forget it */
642             if( p_formats[ i_format ].id != GUID_YUV12_PLANAR )
643             {
644                 continue;
645             }
646
647             /* Look for the first available port supporting this format */
648             for( i_port = p_adaptor[i_adaptor].base_id;
649                  ( i_port < p_adaptor[i_adaptor].base_id
650                              + p_adaptor[i_adaptor].num_ports )
651                    && ( i_selected_port == -1 );
652                  i_port++ )
653             {
654                 if( XvGrabPort( dpy, i_port, CurrentTime ) == Success )
655                 {
656                     i_selected_port = i_port;
657                 }
658             }
659
660             /* If no free port was found, forget it */
661             if( i_selected_port == -1 )
662             {
663                 continue;
664             }
665
666             /* If we found a port, print information about it */
667             intf_WarnMsg( 3, "vout: GetXVideoPort found adaptor %i, port %i",
668                              i_adaptor, i_selected_port );
669             intf_WarnMsg( 3, "  image format 0x%x (%4.4s) %s supported",
670                              p_formats[ i_format ].id,
671                              (char *)&p_formats[ i_format ].id,
672                              ( p_formats[ i_format ].format
673                                 == XvPacked ) ? "packed" : "planar" );
674
675             intf_WarnMsg( 4, " encoding list:" );
676
677             if( XvQueryEncodings( dpy, i_selected_port,
678                                   &i_num_encodings, &p_enc )
679                  != Success )
680             {
681                 intf_WarnMsg( 4, "  XvQueryEncodings failed" );
682                 continue;
683             }
684
685             for( i_enc = 0; i_enc < i_num_encodings; i_enc++ )
686             {
687                 intf_WarnMsg( 4, "  id=%ld, name=%s, size=%ldx%ld,"
688                                  " numerator=%d, denominator=%d",
689                               p_enc[i_enc].encoding_id, p_enc[i_enc].name,
690                               p_enc[i_enc].width, p_enc[i_enc].height,
691                               p_enc[i_enc].rate.numerator,
692                               p_enc[i_enc].rate.denominator );
693             }
694
695             if( p_enc != NULL )
696             {
697                 XvFreeEncodingInfo( p_enc );
698             }
699
700             intf_WarnMsg( 4, " attribute list:" );
701             p_attr = XvQueryPortAttributes( dpy, i_selected_port,
702                                             &i_num_attributes );
703             for( i_attr = 0; i_attr < i_num_attributes; i_attr++ )
704             {
705                 intf_WarnMsg( 4,
706                       "  name=%s, flags=[%s%s ], min=%i, max=%i",
707                       p_attr[i_attr].name,
708                       (p_attr[i_attr].flags & XvGettable) ? " get" : "",
709                       (p_attr[i_attr].flags & XvSettable) ? " set" : "",
710                       p_attr[i_attr].min_value, p_attr[i_attr].max_value );
711             }
712
713             if( p_attr != NULL )
714             {
715                 XFree( p_attr );
716             }
717         }
718
719         if( p_formats != NULL )
720         {
721             XFree( p_formats );
722         }
723
724     }
725
726     if( i_num_adaptors > 0 )
727     {
728         XvFreeAdaptorInfo( p_adaptor );
729     }
730
731     if( i_selected_port == -1 )
732     {
733         if( i_requested_adaptor == -1 )
734         {
735             intf_WarnMsg( 3, "vout: no free XVideo port found for YV12" );
736         }
737         else
738         {
739             intf_WarnMsg( 3, "vout: XVideo adaptor %i does not have a free "
740                              "XVideo port for YV12", i_requested_adaptor );
741         }
742     }
743
744     return( i_selected_port );
745 }
746
747 #if 0
748 /*****************************************************************************
749  * XVideoSetAttribute
750  *****************************************************************************
751  * This function can be used to set attributes, e.g. XV_BRIGHTNESS and
752  * XV_CONTRAST. "f_value" should be in the range of 0 to 1.
753  *****************************************************************************/
754 static void XVideoSetAttribute( vout_thread_t *p_vout,
755                                 char *attr_name, float f_value )
756 {
757     int             i_attrib;
758     XvAttribute    *p_attrib;
759     Display        *p_display = p_vout->p_sys->p_display;
760     int             i_xvport  = p_vout->p_sys->i_xvport;
761
762     p_attrib = XvQueryPortAttributes( p_display, i_xvport, &i_attrib );
763
764     do
765     {
766         i_attrib--;
767
768         if( i_attrib >= 0 && !strcmp( p_attrib[ i_attrib ].name, attr_name ) )
769         {
770             int i_sv = f_value * ( p_attrib[ i_attrib ].max_value
771                                     - p_attrib[ i_attrib ].min_value + 1 )
772                         + p_attrib[ i_attrib ].min_value;
773
774             XvSetPortAttribute( p_display, i_xvport,
775                             XInternAtom( p_display, attr_name, False ), i_sv );
776             break;
777         }
778
779     } while( i_attrib > 0 );
780
781     if( p_attrib )
782         XFree( p_attrib );
783 }
784 #endif
785