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