]> git.sesse.net Git - vlc/blobdiff - plugins/x11/vout_xvideo.c
* CPU detection under BeOS.
[vlc] / plugins / x11 / vout_xvideo.c
index 7b627a4e1bfdeb2f27e6f372c56a7b1691b47ac3..0f2a1ad9243650943c0ec0b747861cedce05d142 100644 (file)
@@ -1,8 +1,8 @@
 /*****************************************************************************
  * vout_xvideo.c: Xvideo video output display method
  *****************************************************************************
- * Copyright (C) 1998, 1999, 2000, 2001 VideoLAN
- * $Id: vout_xvideo.c,v 1.11 2001/04/26 03:55:44 sam Exp $
+ * Copyright (C) 1998-2001 VideoLAN
+ * $Id: vout_xvideo.c,v 1.40 2001/12/17 03:38:21 sam Exp $
  *
  * Authors: Shane Harper <shanegh@optusnet.com.au>
  *          Vincent Seguin <seguin@via.ecp.fr>
 #include <sys/ipc.h>
 #endif
 
+#ifndef WIN32
+#include <netinet/in.h>                               /* BSD: struct in_addr */
+#endif
+
 #include <sys/shm.h>                                   /* shmget(), shmctl() */
 #include <X11/Xlib.h>
 #include <X11/Xutil.h>
 #include <X11/extensions/XShm.h>
 #include <X11/extensions/Xv.h>
 #include <X11/extensions/Xvlib.h>
+#include <X11/extensions/dpms.h>
 
-#include "config.h"
 #include "common.h"
+#include "intf_msg.h"
 #include "threads.h"
 #include "mtime.h"
 #include "tests.h"
-#include "modules.h"
 
 #include "video.h"
 #include "video_output.h"
+#include "vout_common.h"
 
 #include "interface.h"
-#include "intf_msg.h"
-
 #include "netutils.h"                                 /* network_ChannelJoin */
 
-#include "main.h"
-
 #include "stream_control.h"                 /* needed by input_ext-intf.h... */
 #include "input_ext-intf.h"
 
+#include "modules.h"
+#include "modules_export.h"
 
+#define XVIDEO_MAX_DIRECTBUFFERS 5
 #define GUID_YUV12_PLANAR 0x32315659
 
-
-/*****************************************************************************
- * vout_sys_t: video output X11 method descriptor
- *****************************************************************************
- * This structure is part of the video output thread descriptor.
- * It describes the XVideo specific properties of an output thread.
- *****************************************************************************/
-typedef struct vout_sys_s
-{
-    /* User settings */
-#if 0
-    /* this plugin (currently) requires the SHM Ext... */
-    boolean_t           b_shm;               /* shared memory extension flag */
-#endif
-
-    /* Internal settings and properties */
-    Display *           p_display;                        /* display pointer */
-    int                 i_screen;                           /* screen number */
-    Window              window;                               /* root window */
-    GC                  gc;              /* graphic context instance handler */
-    Window              yuv_window;   /* sub-window for displaying yuv video
-                                                                        data */
-    GC                  yuv_gc;
-    int                 xv_port;
-
-    /* Display buffers and shared memory information */
-    /* Note: only 1 buffer... Xv ext does double buffering. */
-    XvImage *           p_xvimage;
-    int                 i_image_width;
-    int                 i_image_height;
-                                /* i_image_width & i_image_height reflect the
-                                 * size of the XvImage. They are used by
-                                 * vout_Display() to check if the image to be
-                                 * displayed can use the current XvImage. */
-    XShmSegmentInfo     shm_info;       /* shared memory zone information */
-
-    /* X11 generic properties */
-    Atom                wm_protocols;
-    Atom                wm_delete_window;
-
-    int                 i_window_width;              /* width of main window */
-    int                 i_window_height;            /* height of main window */
-
-
-    /* Screen saver properties */
-    int                 i_ss_timeout;                             /* timeout */
-    int                 i_ss_interval;           /* interval between changes */
-    int                 i_ss_blanking;                      /* blanking mode */
-    int                 i_ss_exposure;                      /* exposure mode */
-    
-    /* Mouse pointer properties */
-    boolean_t           b_mouse_pointer_visible;
-    mtime_t             i_time_mouse_last_moved; /* used to auto-hide pointer*/
-
-    /* Displaying fullscreen */
-    boolean_t           b_fullscreen;
-
-} vout_sys_t;
-
-/* Fullscreen needs to be able to hide the wm decorations */
-#define MWM_HINTS_DECORATIONS   (1L << 1)
-#define PROP_MWM_HINTS_ELEMENTS 5
-typedef struct mwmhints_s
-{
-    u32 flags;
-    u32 functions;
-    u32 decorations;
-    s32 input_mode;
-    u32 status;
-} mwmhints_t;
-
 /*****************************************************************************
  * Local prototypes
  *****************************************************************************/
@@ -153,30 +86,17 @@ static int  vout_Create    ( vout_thread_t * );
 static int  vout_Init      ( vout_thread_t * );
 static void vout_End       ( vout_thread_t * );
 static void vout_Destroy   ( vout_thread_t * );
-static int  vout_Manage    ( vout_thread_t * );
-static void vout_Display   ( vout_thread_t * );
-static void vout_SetPalette( vout_thread_t *, u16 *, u16 *, u16 *, u16 * );
-
-static int  XVideoCreateWindow       ( vout_thread_t * );
-static void XVideoDestroyWindow      ( vout_thread_t *p_vout );
-static int  XVideoUpdateImgSizeIfRequired( vout_thread_t *p_vout );
-static int  XVideoCreateShmImage     ( Display* dpy, int xv_port,
-                                       XvImage **pp_xvimage,
-                                       XShmSegmentInfo *p_shm_info,
-                                       int i_width, int i_height );
-static void XVideoDestroyShmImage    ( vout_thread_t *, XvImage *,
-                                       XShmSegmentInfo * );
-static void XVideoSetMousePointer    ( const vout_thread_t * );
-static void XVideoEnableScreenSaver  ( vout_thread_t * );
-static void XVideoDisableScreenSaver ( vout_thread_t * );
-/*static void XVideoSetAttribute       ( vout_thread_t *, char *, float );*/
+static void vout_Display   ( vout_thread_t *, picture_t * );
 
-static int  XVideoCheckForXv         ( Display * );
-static int  XVideoGetPort            ( Display * );
-static void XVideoOutputCoords       ( const picture_t *, const boolean_t,
-                                       const int, const int,
-                                       int *, int *, int *, int * );
-static void XVideoDisplay            ( vout_thread_t * );
+static int  XVideoNewPicture   ( vout_thread_t *, picture_t * );
+
+static XvImage *CreateShmImage ( Display *, int, XShmSegmentInfo *, int, int );
+static void     DestroyShmImage( Display *, XvImage *, XShmSegmentInfo * );
+
+static int  CheckForXVideo     ( Display * );
+static int  GetXVideoPort      ( Display * );
+
+/*static void XVideoSetAttribute       ( vout_thread_t *, char *, float );*/
 
 /*****************************************************************************
  * Functions exported as capabilities. They are declared as static so that
@@ -189,9 +109,9 @@ void _M( vout_getfunctions )( function_list_t * p_function_list )
     p_function_list->functions.vout.pf_init       = vout_Init;
     p_function_list->functions.vout.pf_end        = vout_End;
     p_function_list->functions.vout.pf_destroy    = vout_Destroy;
-    p_function_list->functions.vout.pf_manage     = vout_Manage;
+    p_function_list->functions.vout.pf_manage     = _M( vout_Manage );
     p_function_list->functions.vout.pf_display    = vout_Display;
-    p_function_list->functions.vout.pf_setpalette = vout_SetPalette;
+    p_function_list->functions.vout.pf_setpalette = NULL;
 }
 
 /*****************************************************************************
@@ -202,24 +122,55 @@ void _M( vout_getfunctions )( function_list_t * p_function_list )
  *****************************************************************************/
 static int vout_Probe( probedata_t *p_data )
 {
+    Display *p_display;                                   /* display pointer */
+    char    *psz_display;
+
+    /* Open display, unsing 'vlc_display' or DISPLAY environment variable */
+    psz_display = XDisplayName( main_GetPszVariable(VOUT_DISPLAY_VAR, NULL) );
+    p_display = XOpenDisplay( psz_display );
+    if( p_display == NULL )                                         /* error */
+    {
+        intf_WarnMsg( 3, "vout: Xvideo cannot open display %s", psz_display );
+        intf_WarnMsg( 3, "vout: Xvideo not supported" );
+        return( 0 );
+    }
+
+    if( !CheckForXVideo( p_display ) )
+    {
+        intf_WarnMsg( 3, "vout: Xvideo not supported" );
+        XCloseDisplay( p_display );
+        return( 0 );
+    }
+
+    if( GetXVideoPort( p_display ) < 0 )
+    {
+        intf_WarnMsg( 3, "vout: Xvideo not supported" );
+        XCloseDisplay( p_display );
+        return( 0 );
+    }
+
+    /* Clean-up everyting */
+    XCloseDisplay( p_display );
+
     if( TestMethod( VOUT_METHOD_VAR, "xvideo" ) )
     {
         return( 999 );
     }
 
-    return( 110 );
+    return( 150 );
 }
 
 /*****************************************************************************
  * vout_Create: allocate XVideo video thread output method
  *****************************************************************************
- * This function allocate and initialize a XVideo vout method. It uses some of
+ * This function allocates and initialize a XVideo vout method. It uses some of
  * the vout properties to choose the window size, and change them according to
  * the actual properties of the display.
  *****************************************************************************/
 static int vout_Create( vout_thread_t *p_vout )
 {
     char *psz_display;
+    XColor cursor_color;
 
     /* Allocate structure */
     p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
@@ -241,10 +192,7 @@ static int vout_Create( vout_thread_t *p_vout )
     }
     p_vout->p_sys->i_screen = DefaultScreen( p_vout->p_sys->p_display );
 
-    p_vout->p_sys->b_fullscreen
-        = main_GetIntVariable( VOUT_FULLSCREEN_VAR, VOUT_FULLSCREEN_DEFAULT );
-    
-    if( !XVideoCheckForXv( p_vout->p_sys->p_display ) )
+    if( !CheckForXVideo( p_vout->p_sys->p_display ) )
     {
         intf_ErrMsg( "vout error: no XVideo extension" );
         XCloseDisplay( p_vout->p_sys->p_display );
@@ -252,20 +200,51 @@ static int vout_Create( vout_thread_t *p_vout )
         return( 1 );
     }
 
+    /* Check we have access to a video port */
+    if( (p_vout->p_sys->i_xvport = GetXVideoPort(p_vout->p_sys->p_display)) <0 )
+    {
+        intf_ErrMsg( "vout error: cannot get XVideo port" );
+        XCloseDisplay( p_vout->p_sys->p_display );
+        free( p_vout->p_sys );
+        return 1;
+    }
+    intf_DbgMsg( "Using xv port %d" , p_vout->p_sys->xv_port );
+
+    /* Create blank cursor (for mouse cursor autohiding) */
+    p_vout->p_sys->b_mouse_pointer_visible = 1;
+    p_vout->p_sys->cursor_pixmap = XCreatePixmap( p_vout->p_sys->p_display,
+                                                  DefaultRootWindow(
+                                                     p_vout->p_sys->p_display),
+                                                  1, 1, 1 );
+
+    XParseColor( p_vout->p_sys->p_display,
+                 XCreateColormap( p_vout->p_sys->p_display,
+                                  DefaultRootWindow(
+                                                    p_vout->p_sys->p_display ),
+                                  DefaultVisual(
+                                                p_vout->p_sys->p_display,
+                                                p_vout->p_sys->i_screen ),
+                                  AllocNone ),
+                 "black", &cursor_color );
+
+    p_vout->p_sys->blank_cursor = XCreatePixmapCursor(
+                                      p_vout->p_sys->p_display,
+                                      p_vout->p_sys->cursor_pixmap,
+                                      p_vout->p_sys->cursor_pixmap,
+                                      &cursor_color,
+                                      &cursor_color, 1, 1 );
+
     /* Spawn base window - this window will include the video output window,
      * but also command buttons, subtitles and other indicators */
-    if( XVideoCreateWindow( p_vout ) )
+    if( _M( XCommonCreateWindow ) ( p_vout ) )
     {
-        intf_ErrMsg( "vout error: cannot create XVideo window" );
+        intf_ErrMsg( "vout error: no suitable Xvideo image input port" );
+        _M( XCommonDestroyWindow ) ( p_vout );
         XCloseDisplay( p_vout->p_sys->p_display );
         free( p_vout->p_sys );
         return( 1 );
     }
 
-    if( (p_vout->p_sys->xv_port = XVideoGetPort( p_vout->p_sys->p_display ))<0 )
-        return 1;
-    intf_DbgMsg( "Using xv port %d" , p_vout->p_sys->xv_port );
-
 #if 0
     /* XXX The brightness and contrast values should be read from environment
      * XXX variables... */
@@ -273,10 +252,8 @@ static int vout_Create( vout_thread_t *p_vout )
     XVideoSetAttribute( p_vout, "XV_CONTRAST",   0.5 );
 #endif
 
-    p_vout->p_sys->b_mouse_pointer_visible = 1;
-
     /* Disable screen saver and return */
-    XVideoDisableScreenSaver( p_vout );
+    _M( XCommonDisableScreenSaver ) ( p_vout );
 
     return( 0 );
 }
@@ -286,921 +263,485 @@ static int vout_Create( vout_thread_t *p_vout )
  *****************************************************************************/
 static int vout_Init( vout_thread_t *p_vout )
 {
-#ifdef SYS_DARWIN1_3
-    /* FIXME : As of 2001-03-16, XFree4 for MacOS X does not support Xshm. */
-    p_vout->p_sys->b_shm = 0;
-#endif
-    p_vout->b_need_render = 0;
-    p_vout->p_sys->i_image_width = p_vout->p_sys->i_image_height = 0;
-
-    return( 0 );
-}
+    int i_index;
+    picture_t *p_pic;
 
-/*****************************************************************************
- * vout_End: terminate XVideo video thread output method
- *****************************************************************************
- * Destroy the XvImage. It is called at the end of the thread, but also each
- * time the image is resized.
- *****************************************************************************/
-static void vout_End( vout_thread_t *p_vout )
-{
-    XVideoDestroyShmImage( p_vout, p_vout->p_sys->p_xvimage,
-                           &p_vout->p_sys->shm_info );
-}
+    I_OUTPUTPICTURES = 0;
 
-/*****************************************************************************
- * vout_Destroy: destroy XVideo video thread output method
- *****************************************************************************
- * Terminate an output method created by vout_Create
- *****************************************************************************/
-static void vout_Destroy( vout_thread_t *p_vout )
-{
-    XVideoEnableScreenSaver( p_vout );
-    XVideoDestroyWindow( p_vout );
-    XCloseDisplay( p_vout->p_sys->p_display );
+    /* Initialize the output structure */
+    switch( p_vout->render.i_chroma )
+    {
+        case YUV_420_PICTURE:
+            p_vout->output.i_chroma = p_vout->render.i_chroma;
+            p_vout->output.i_width  = p_vout->render.i_width;
+            p_vout->output.i_height = p_vout->render.i_height;
+            p_vout->output.i_aspect = p_vout->render.i_aspect;
+            break;
 
-    /* Destroy structure */
-    free( p_vout->p_sys );
-}
+        default:
+            return( 0 );
+    }
 
-/*****************************************************************************
- * vout_Manage: handle X11 events
- *****************************************************************************
- * This function should be called regularly by video output thread. It manages
- * X11 events and allows window resizing. It returns a non null value on
- * error.
- *
- * XXX  Should "factor-out" common code in this and the "same" fn in the x11
- * XXX  plugin!
- *****************************************************************************/
-static int vout_Manage( vout_thread_t *p_vout )
-{
-    XEvent      xevent;                                         /* X11 event */
-    boolean_t   b_toggle_fullscreen;               /* user wants full-screen */
-    char        i_key;                                    /* ISO Latin-1 key */
-    KeySym      x_key_symbol;
-
-    b_toggle_fullscreen = 0;
-
-    /* Handle X11 events: ConfigureNotify events are parsed to know if the
-     * output window's size changed, MapNotify and UnmapNotify to know if the
-     * window is mapped (and if the display is useful), and ClientMessages
-     * to intercept window destruction requests */
-    while( XCheckWindowEvent( p_vout->p_sys->p_display, p_vout->p_sys->window,
-                              StructureNotifyMask | KeyPressMask |
-                              ButtonPressMask | ButtonReleaseMask | 
-                              PointerMotionMask, &xevent )
-           == True )
+    /* Try to initialize up to XVIDEO_MAX_DIRECTBUFFERS direct buffers */
+    while( I_OUTPUTPICTURES < XVIDEO_MAX_DIRECTBUFFERS )
     {
-        /* ConfigureNotify event: prepare  */
-        if( (xevent.type == ConfigureNotify)
-            /*&& ((xevent.xconfigure.width != p_vout->p_sys->i_window_width)
-                || (xevent.xconfigure.height != p_vout->p_sys->i_window_height))*/ )
-        {
-            /* Update dimensions */
-            p_vout->p_sys->i_window_width = xevent.xconfigure.width;
-            p_vout->p_sys->i_window_height = xevent.xconfigure.height;
-        }
-        /* MapNotify event: change window status and disable screen saver */
-        else if( xevent.type == MapNotify)
-        {
-            if( (p_vout != NULL) && !p_vout->b_active )
-            {
-                XVideoDisableScreenSaver( p_vout );
-                p_vout->b_active = 1;
-            }
-        }
-        /* UnmapNotify event: change window status and enable screen saver */
-        else if( xevent.type == UnmapNotify )
-        {
-            if( (p_vout != NULL) && p_vout->b_active )
-            {
-                XVideoEnableScreenSaver( p_vout );
-                p_vout->b_active = 0;
-            }
-        }
-        /* Keyboard event */
-        else if( xevent.type == KeyPress )
+        p_pic = NULL;
+
+        /* Find an empty picture slot */
+        for( i_index = 0 ; i_index < VOUT_MAX_PICTURES ; i_index++ )
         {
-            /* We may have keys like F1 trough F12, ESC ... */
-            x_key_symbol = XKeycodeToKeysym( p_vout->p_sys->p_display,
-                                             xevent.xkey.keycode, 0 );
-            switch( x_key_symbol )
+            if( p_vout->p_picture[ i_index ].i_status == FREE_PICTURE )
             {
-                 case XK_Escape:
-                     p_main->p_intf->b_die = 1;
-                     break;
-                 case XK_Menu:
-                     p_main->p_intf->b_menu_change = 1;
-                     break;
-                 default:
-                     /* "Normal Keys"
-                      * The reason why I use this instead of XK_0 is that 
-                      * with XLookupString, we don't have to care about
-                      * keymaps. */
-
-                    if( XLookupString( &xevent.xkey, &i_key, 1, NULL, NULL ) )
-                    {
-                        switch( i_key )
-                        {
-                        case 'q':
-                        case 'Q':
-                            p_main->p_intf->b_die = 1;
-                            break;
-                        case 'f':
-                        case 'F':
-                            b_toggle_fullscreen = 1;
-                            break;
-                        case '0':
-                            network_ChannelJoin( 0 );
-                            break;
-                        case '1':
-                            network_ChannelJoin( 1 );
-                            break;
-                        case '2':
-                            network_ChannelJoin( 2 );
-                            break;
-                        case '3':
-                            network_ChannelJoin( 3 );
-                            break;
-                        case '4':
-                            network_ChannelJoin( 4 );
-                            break;
-                        case '5':
-                            network_ChannelJoin( 5 );
-                            break;
-                        case '6':
-                            network_ChannelJoin( 6 );
-                            break;
-                        case '7':
-                            network_ChannelJoin( 7 );
-                            break;
-                        case '8':
-                            network_ChannelJoin( 8 );
-                            break;
-                        case '9':
-                            network_ChannelJoin( 9 );
-                            break;
-                        default:
-                            if( intf_ProcessKey( p_main->p_intf, 
-                                                 (char )i_key ) )
-                            {
-                               intf_DbgMsg( "unhandled key '%c' (%i)", 
-                                            (char)i_key, i_key );
-                            }
-                            break;
-                        }
-                    }
+                p_pic = p_vout->p_picture + i_index;
                 break;
             }
         }
-        /* Mouse click */
-        else if( xevent.type == ButtonPress )
-        {
-            switch( ((XButtonEvent *)&xevent)->button )
-            {
-                case Button1:
-                    /* in this part we will eventually manage
-                     * clicks for DVD navigation for instance */
-                    break;
-            }
-        }
-        /* Mouse release */
-        else if( xevent.type == ButtonRelease )
-        {
-            switch( ((XButtonEvent *)&xevent)->button )
-            {
-                case Button3:
-                    /* FIXME: need locking ! */
-                    p_main->p_intf->b_menu_change = 1;
-                    break;
-            }
-        }
-        /* Mouse move */
-        else if( xevent.type == MotionNotify )
-        {
-            p_vout->p_sys->i_time_mouse_last_moved = mdate();
-            p_vout->p_sys->b_mouse_pointer_visible = 1; 
-            XVideoSetMousePointer( p_vout ); 
-        }
-#ifdef DEBUG
-        /* Other event */
-        else
-        {
-            intf_DbgMsg( "%p -> unhandled event type %d received",
-                         p_vout, xevent.type );
-        }
-#endif
-    }
 
-    /* Handle events for YUV video output sub-window */
-    while( XCheckWindowEvent( p_vout->p_sys->p_display,
-                              p_vout->p_sys->yuv_window,
-                              ExposureMask, &xevent ) == True )
-    {
-        /* Window exposed (only handled if stream playback is paused) */
-        if( xevent.type == Expose )
-        {
-            if( ((XExposeEvent *)&xevent)->count == 0 )
-                /* (if this is the last a collection of expose events...) */
-                if( p_main->p_intf->p_input )
-                    if( PAUSE_S ==
-                            p_main->p_intf->p_input->stream.control.i_status )
-                        XVideoDisplay( p_vout );
-        }
-    }
-        
-    /* ClientMessage event - only WM_PROTOCOLS with WM_DELETE_WINDOW data
-     * are handled - according to the man pages, the format is always 32
-     * in this case */
-    while( XCheckTypedEvent( p_vout->p_sys->p_display,
-                             ClientMessage, &xevent ) )
-    {
-        if( (xevent.xclient.message_type == p_vout->p_sys->wm_protocols)
-            && (xevent.xclient.data.l[0] == p_vout->p_sys->wm_delete_window ) )
+        /* Allocate the picture */
+        if( XVideoNewPicture( p_vout, p_pic ) )
         {
-            p_main->p_intf->b_die = 1;
-        }
-        else
-        {
-            intf_DbgMsg( "%p -> unhandled ClientMessage received", p_vout );
+            break;
         }
-    }
 
-    if ( b_toggle_fullscreen )
-    {
-        intf_DbgMsg( "vout: changing full-screen status" );
-
-        p_vout->p_sys->b_fullscreen = !p_vout->p_sys->b_fullscreen;
+        p_pic->i_status        = DESTROYED_PICTURE;
+        p_pic->i_type          = DIRECT_PICTURE;
 
-        /* Get rid of the old window */
-        XVideoDestroyWindow( p_vout );
+        p_pic->i_left_margin   =
+        p_pic->i_right_margin  =
+        p_pic->i_top_margin    =
+        p_pic->i_bottom_margin = 0;
 
-        /* And create a new one */
-        if( XVideoCreateWindow( p_vout ) )
-        {
-            intf_ErrMsg( "vout error: cannot create X11 window" );
-            XCloseDisplay( p_vout->p_sys->p_display );
+        PP_OUTPUTPICTURE[ I_OUTPUTPICTURES ] = p_pic;
 
-            free( p_vout->p_sys );
-            return( 1 );
-        }
+        I_OUTPUTPICTURES++;
     }
 
-    
-    if( (p_vout->i_changes & VOUT_GRAYSCALE_CHANGE))
-    {
-        /* FIXME: clear flags ?? */
-    }
+    return( 0 );
+}
 
-    /*
-     * Size change
-     */
-    if( p_vout->i_changes & VOUT_SIZE_CHANGE )
-    {
-        intf_DbgMsg( "vout: resizing window" );
-        p_vout->i_changes &= ~VOUT_SIZE_CHANGE;
-        /* Nothing to do here...
-         * vout_Display() detects size changes of the image to be displayed and
-         * re-creates the XvImage.*/
-        intf_Msg( "vout: video display resized (%dx%d)",
-                  p_vout->i_width, p_vout->i_height );
-    }
+/*****************************************************************************
+ * vout_End: terminate XVideo video thread output method
+ *****************************************************************************
+ * Destroy the XvImage. It is called at the end of the thread, but also each
+ * time the image is resized.
+ *****************************************************************************/
+static void vout_End( vout_thread_t *p_vout )
+{
+    int i_index;
 
-    /* Autohide Cursor */
-    if( p_vout->p_sys->b_mouse_pointer_visible &&
-        mdate() - p_vout->p_sys->i_time_mouse_last_moved > 2000000 )
+    /* Free the direct buffers we allocated */
+    for( i_index = I_OUTPUTPICTURES ; i_index ; )
     {
-        p_vout->p_sys->b_mouse_pointer_visible = 0; 
-        XVideoSetMousePointer( p_vout );
+        i_index--;
+        DestroyShmImage( p_vout->p_sys->p_display,
+                         PP_OUTPUTPICTURE[ i_index ]->p_sys->p_xvimage,
+                         &PP_OUTPUTPICTURE[ i_index ]->p_sys->shminfo );
+        free( PP_OUTPUTPICTURE[ i_index ]->p_sys );
     }
-    
-    return 0;
 }
 
 /*****************************************************************************
- * vout_Display: displays previously rendered output
+ * vout_Destroy: destroy XVideo video thread output method
  *****************************************************************************
- * This function sends the currently rendered image to X11 server.
- * (The Xv extension takes care of "double-buffering".)
+ * Terminate an output method created by vout_Create
  *****************************************************************************/
-static void vout_Display( vout_thread_t *p_vout )
+static void vout_Destroy( vout_thread_t *p_vout )
 {
-    boolean_t b_draw = 1;
-    int i_size = p_vout->p_rendered_pic->i_width *
-                   p_vout->p_rendered_pic->i_height;
-
-    if( XVideoUpdateImgSizeIfRequired( p_vout ) )
-        return;
-
-    switch( p_vout->p_rendered_pic->i_type )
+    /* Restore cursor if it was blanked */
+    if( !p_vout->p_sys->b_mouse_pointer_visible )
     {
-    case YUV_422_PICTURE:
-        intf_ErrMsg( "vout error: YUV_422_PICTURE not (yet) supported" );
-        b_draw = 0;
-        break;
-
-    case YUV_444_PICTURE:
-        intf_ErrMsg( "vout error: YUV_444_PICTURE not (yet) supported" );
-        b_draw = 0;
-        break;
-
-    case YUV_420_PICTURE:
-        memcpy( p_vout->p_sys->p_xvimage->data,
-                p_vout->p_rendered_pic->p_y, i_size );
-        memcpy( p_vout->p_sys->p_xvimage->data + ( i_size ),
-                p_vout->p_rendered_pic->p_v, i_size / 4 );
-        memcpy( p_vout->p_sys->p_xvimage->data + ( i_size ) + ( i_size / 4 ),
-                p_vout->p_rendered_pic->p_u, i_size / 4 );
-        break;
+        _M( XCommonToggleMousePointer ) ( p_vout );
     }
 
-    if( b_draw )
-        XVideoDisplay( p_vout );
-}
+    /* Destroy blank cursor pixmap */
+    XFreePixmap( p_vout->p_sys->p_display, p_vout->p_sys->cursor_pixmap );
 
-static void vout_SetPalette( p_vout_thread_t p_vout,
-                             u16 *red, u16 *green, u16 *blue, u16 *transp )
-{
-    return;
-}
+    _M( XCommonEnableScreenSaver ) ( p_vout );
+    _M( XCommonDestroyWindow ) ( p_vout );
+    XCloseDisplay( p_vout->p_sys->p_display );
 
-/* following functions are local */
+    /* Destroy structure */
+    free( p_vout->p_sys );
+}
 
 /*****************************************************************************
- * XVideoUpdateImgSizeIfRequired 
+ * vout_Display: displays previously rendered output
  *****************************************************************************
- * This function checks to see if the image to be displayed is of a different
- * size to the last image displayed. If so, the old shm block must be
- * destroyed and a new one created.
- * Note: the "image size" is the size of the image to be passed to the Xv
- * extension (which is probably different to the size of the output window).
+ * This function sends the currently rendered image to X11 server.
+ * (The Xv extension takes care of "double-buffering".)
  *****************************************************************************/
-static int XVideoUpdateImgSizeIfRequired( vout_thread_t *p_vout )
+static void vout_Display( vout_thread_t *p_vout, picture_t *p_pic )
 {
-    int i_img_width         = p_vout->p_rendered_pic->i_width;
-    int i_img_height        = p_vout->p_rendered_pic->i_height;
+    int i_width, i_height, i_x, i_y;
 
-    if( p_vout->p_sys->i_image_width != i_img_width
-            || p_vout->p_sys->i_image_height != i_img_height )
-    {
-        p_vout->p_sys->i_image_width  = i_img_width;
-        p_vout->p_sys->i_image_height = i_img_height;
-
-        /* Destroy XvImage to change its size */
-        vout_End( p_vout );
-            /* Note: vout_End does nothing if no XvImage to destroy. */
-
-        /* Create XvImage using XShm extension */
-        if( XVideoCreateShmImage( p_vout->p_sys->p_display,
-                                  p_vout->p_sys->xv_port,
-                                  &p_vout->p_sys->p_xvimage,
-                                  &p_vout->p_sys->shm_info,
-                                  i_img_width, i_img_height ) )
-        {
-            intf_ErrMsg( "vout: failed to create xvimage." );
-            p_vout->p_sys->i_image_width = 0;
-            return( 1 );
-        }
+    vout_PlacePicture( p_vout, p_vout->p_sys->i_width, p_vout->p_sys->i_height,
+                       &i_x, &i_y, &i_width, &i_height );
 
-        /* Set bytes per line and initialize buffers */
-        p_vout->i_bytes_per_line =
-            (p_vout->p_sys->p_xvimage->data_size) /
-            (p_vout->p_sys->p_xvimage->height);
+    XvShmPutImage( p_vout->p_sys->p_display, p_vout->p_sys->i_xvport,
+                   p_vout->p_sys->yuv_window, p_vout->p_sys->gc,
+                   p_pic->p_sys->p_xvimage, 0 /*src_x*/, 0 /*src_y*/,
+                   p_vout->output.i_width, p_vout->output.i_height,
+                   0 /*dest_x*/, 0 /*dest_y*/, i_width, i_height,
+                   True );
 
-        /* vout_SetBuffers( p_vout, p_vout->p_sys->p_xvimage->data ); */
-    }
+    XResizeWindow( p_vout->p_sys->p_display, p_vout->p_sys->yuv_window,
+                   i_width, i_height );
 
-    return( 0 );
+    XMoveWindow( p_vout->p_sys->p_display, p_vout->p_sys->yuv_window,
+                 i_x, i_y );
 }
 
+/* following functions are local */
+
 /*****************************************************************************
- * XVideoCheckForXv: check for the XVideo extension
+ * CheckForXVideo: check for the XVideo extension
  *****************************************************************************/
-static int XVideoCheckForXv( Display *dpy )
+static int CheckForXVideo( Display *p_display )
 {
     unsigned int i;
 
-    switch( XvQueryExtension( dpy, &i, &i, &i, &i, &i ) )
+    switch( XvQueryExtension( p_display, &i, &i, &i, &i, &i ) )
     {
         case Success:
             return( 1 );
 
         case XvBadExtension:
-            intf_ErrMsg( "vout error: XvBadExtension" );
+            intf_WarnMsg( 3, "vout error: XvBadExtension" );
             return( 0 );
 
         case XvBadAlloc:
-            intf_ErrMsg( "vout error: XvBadAlloc" );
+            intf_WarnMsg( 3, "vout error: XvBadAlloc" );
             return( 0 );
 
         default:
-            intf_ErrMsg( "vout error: XvQueryExtension failed" );
+            intf_WarnMsg( 3, "vout error: XvQueryExtension failed" );
             return( 0 );
     }
 }
 
 /*****************************************************************************
- * XVideoCreateWindow: open and set-up XVideo main window
+ * XVideoNewPicture: allocate a picture
+ *****************************************************************************
+ * Returns 0 on success, -1 otherwise
  *****************************************************************************/
-static int XVideoCreateWindow( vout_thread_t *p_vout )
+static int XVideoNewPicture( vout_thread_t *p_vout, picture_t *p_pic )
 {
-    XSizeHints              xsize_hints;
-    XSetWindowAttributes    xwindow_attributes;
-    XGCValues               xgcvalues;
-    XEvent                  xevent;
-    Atom                    prop;
-    mwmhints_t              mwmhints;
-    
-    boolean_t               b_expose;
-    boolean_t               b_configure_notify;
-    boolean_t               b_map_notify;
-
-
-    /* Set main window's size */
-    /* If we're full screen, we're full screen! */
-    if( p_vout->p_sys->b_fullscreen )
-    {
-        p_vout->p_sys->i_window_width = DisplayWidth( p_vout->p_sys->p_display,
-                                                      p_vout->p_sys->i_screen );
-        p_vout->p_sys->i_window_height =  DisplayHeight( p_vout->p_sys->p_display,
-                                                         p_vout->p_sys->i_screen );
-/*      p_vout->i_width =  p_vout->p_sys->i_window_width;
-        p_vout->i_height = p_vout->p_sys->i_window_height; */
-    }
-    else
-    {
-        p_vout->p_sys->i_window_width =  main_GetIntVariable( VOUT_WIDTH_VAR,
-                                                       VOUT_WIDTH_DEFAULT );
-        p_vout->p_sys->i_window_height = main_GetIntVariable( VOUT_HEIGHT_VAR,
-                                                       VOUT_HEIGHT_DEFAULT );
-    }
+    int i_width  = p_vout->output.i_width;
+    int i_height = p_vout->output.i_height;
 
-    /* Prepare window manager hints and properties */
-    xsize_hints.base_width          = p_vout->p_sys->i_window_width;
-    xsize_hints.base_height         = p_vout->p_sys->i_window_height;
-    xsize_hints.flags               = PSize;
-    p_vout->p_sys->wm_protocols     = XInternAtom( p_vout->p_sys->p_display,
-                                                   "WM_PROTOCOLS", True );
-    p_vout->p_sys->wm_delete_window = XInternAtom( p_vout->p_sys->p_display,
-                                                   "WM_DELETE_WINDOW", True );
-
-    /* Prepare window attributes */
-    xwindow_attributes.background_pixel = BlackPixel( p_vout->p_sys->p_display,
-                                                      p_vout->p_sys->i_screen );
-
-    xwindow_attributes.event_mask = ExposureMask | StructureNotifyMask;
-
-    /* Create the window and set hints - the window must receive ConfigureNotify
-     * events, and, until it is displayed, Expose and MapNotify events. */
-    p_vout->p_sys->window =
-            XCreateWindow( p_vout->p_sys->p_display,
-                           DefaultRootWindow( p_vout->p_sys->p_display ),
-                           0, 0,
-                           p_vout->p_sys->i_window_width,
-                           p_vout->p_sys->i_window_height, 1,
-                           0, InputOutput, 0,
-                           CWBackPixel | CWEventMask,
-                           &xwindow_attributes );
-
-    if ( p_vout->p_sys->b_fullscreen )
+    switch( p_vout->output.i_chroma )
     {
-        prop = XInternAtom(p_vout->p_sys->p_display, "_MOTIF_WM_HINTS", False);
-        mwmhints.flags = MWM_HINTS_DECORATIONS;
-        mwmhints.decorations = 0;
-        XChangeProperty( p_vout->p_sys->p_display, p_vout->p_sys->window,
-                         prop, prop, 32, PropModeReplace,
-                         (unsigned char *)&mwmhints, PROP_MWM_HINTS_ELEMENTS );
-
-        XSetTransientForHint( p_vout->p_sys->p_display,
-                              p_vout->p_sys->window, None );
-        XRaiseWindow( p_vout->p_sys->p_display, p_vout->p_sys->window );
-    }
+        case YUV_420_PICTURE:
+            /* We know this chroma, allocate a buffer which will be used
+             * directly by the decoder */
+            p_pic->p_sys = malloc( sizeof( picture_sys_t ) );
 
-    
-    /* Set window manager hints and properties: size hints, command,
-     * window's name, and accepted protocols */
-    XSetWMNormalHints( p_vout->p_sys->p_display, p_vout->p_sys->window,
-                       &xsize_hints );
-    XSetCommand( p_vout->p_sys->p_display, p_vout->p_sys->window,
-                 p_main->ppsz_argv, p_main->i_argc );
-    XStoreName( p_vout->p_sys->p_display, p_vout->p_sys->window,
-                VOUT_TITLE " (XVideo output)" );
-
-    if( (p_vout->p_sys->wm_protocols == None)        /* use WM_DELETE_WINDOW */
-        || (p_vout->p_sys->wm_delete_window == None)
-        || !XSetWMProtocols( p_vout->p_sys->p_display, p_vout->p_sys->window,
-                             &p_vout->p_sys->wm_delete_window, 1 ) )
-    {
-        /* WM_DELETE_WINDOW is not supported by window manager */
-        intf_Msg( "vout error: missing or bad window manager" );
-    }
+            if( p_pic->p_sys == NULL )
+            {
+                return -1;
+            }
 
-    /* Creation of a graphic context that doesn't generate a GraphicsExpose
-     * event when using functions like XCopyArea */
-    xgcvalues.graphics_exposures = False;
-    p_vout->p_sys->gc = XCreateGC( p_vout->p_sys->p_display,
-                                   p_vout->p_sys->window,
-                                   GCGraphicsExposures, &xgcvalues);
-
-    /* Send orders to server, and wait until window is displayed - three
-     * events must be received: a MapNotify event, an Expose event allowing
-     * drawing in the window, and a ConfigureNotify to get the window
-     * dimensions. Once those events have been received, only ConfigureNotify
-     * events need to be received. */
-    b_expose = 0;
-    b_configure_notify = 0;
-    b_map_notify = 0;
-    XMapWindow( p_vout->p_sys->p_display, p_vout->p_sys->window);
-    do
-    {
-        XNextEvent( p_vout->p_sys->p_display, &xevent);
-        if( (xevent.type == Expose)
-            && (xevent.xexpose.window == p_vout->p_sys->window) )
-        {
-            b_expose = 1;
-        }
-        else if( (xevent.type == MapNotify)
-                 && (xevent.xmap.window == p_vout->p_sys->window) )
-        {
-            b_map_notify = 1;
-        }
-        else if( (xevent.type == ConfigureNotify)
-                 && (xevent.xconfigure.window == p_vout->p_sys->window) )
-        {
-            b_configure_notify = 1;
-            p_vout->p_sys->i_window_width = xevent.xconfigure.width;
-            p_vout->p_sys->i_window_height = xevent.xconfigure.height;
-        }
-    } while( !( b_expose && b_configure_notify && b_map_notify ) );
+            /* Create XvImage using XShm extension */
+            p_pic->p_sys->p_xvimage =
+                CreateShmImage( p_vout->p_sys->p_display,
+                                p_vout->p_sys->i_xvport,
+                                &p_pic->p_sys->shminfo,
+                                p_vout->output.i_width,
+                                p_vout->output.i_height );
+            if( p_pic->p_sys->p_xvimage == NULL )
+            {
+                free( p_pic->p_sys );
+                return -1;
+            }
 
-    XSelectInput( p_vout->p_sys->p_display, p_vout->p_sys->window,
-                  StructureNotifyMask | KeyPressMask |
-                  ButtonPressMask | ButtonReleaseMask | 
-                  PointerMotionMask );
 
-    if( p_vout->p_sys->b_fullscreen )
-    {
-        XSetInputFocus( p_vout->p_sys->p_display, p_vout->p_sys->window,
-                        RevertToNone, CurrentTime );
-        XMoveWindow( p_vout->p_sys->p_display, p_vout->p_sys->window, 0, 0 );
-    }
+            /* Precalculate some values */
+            p_pic->i_size         = i_width * i_height;
+            p_pic->i_chroma_width = i_width / 2;
+            p_pic->i_chroma_size  = i_height * ( i_width / 2 );
 
-    /* Create YUV output sub-window. */
-    p_vout->p_sys->yuv_window=XCreateSimpleWindow( p_vout->p_sys->p_display,
-                         p_vout->p_sys->window, 0, 0, 1, 1, 0,
-                         BlackPixel( p_vout->p_sys->p_display,
-                                         p_vout->p_sys->i_screen ),
-                         WhitePixel( p_vout->p_sys->p_display,
-                                         p_vout->p_sys->i_screen ) );
-    p_vout->p_sys->yuv_gc = XCreateGC( p_vout->p_sys->p_display,
-                                        p_vout->p_sys->yuv_window,
-                                        GCGraphicsExposures, &xgcvalues );
+            /* FIXME: try to get the right i_bytes value from p_xvimage */
+            p_pic->planes[Y_PLANE].p_data  = p_pic->p_sys->p_xvimage->data;
+            p_pic->planes[Y_PLANE].i_bytes = p_pic->i_size * sizeof(u8);
+            p_pic->planes[Y_PLANE].i_line_bytes = i_width * sizeof(u8);
 
-    XSetWindowBackground( p_vout->p_sys->p_display, p_vout->p_sys->yuv_window,
-             BlackPixel(p_vout->p_sys->p_display, p_vout->p_sys->i_screen ) );
+            p_pic->planes[U_PLANE].p_data  = (u8*)p_pic->p_sys->p_xvimage->data
+                                               + p_pic->i_size * 5 / 4;
+            p_pic->planes[U_PLANE].i_bytes = p_pic->i_size * sizeof(u8) / 4;
+            p_pic->planes[U_PLANE].i_line_bytes = p_pic->i_chroma_width
+                                                   * sizeof(u8);
 
-    XMapWindow( p_vout->p_sys->p_display, p_vout->p_sys->yuv_window );
-    XSelectInput( p_vout->p_sys->p_display, p_vout->p_sys->yuv_window,
-                  ExposureMask );
+            p_pic->planes[V_PLANE].p_data  = (u8*)p_pic->p_sys->p_xvimage->data
+                                               + p_pic->i_size;
+            p_pic->planes[V_PLANE].i_bytes = p_pic->i_size * sizeof(u8) / 4;
+            p_pic->planes[V_PLANE].i_line_bytes = p_pic->i_chroma_width
+                                                   * sizeof(u8);
 
+            p_pic->i_planes = 3;
 
-    XVideoSetMousePointer( p_vout );
+            return 0;
 
-    return( 0 );
-}
-
-static void XVideoDestroyWindow( vout_thread_t *p_vout )
-{
-    XFreeGC( p_vout->p_sys->p_display, p_vout->p_sys->yuv_gc );
-    XDestroyWindow( p_vout->p_sys->p_display, p_vout->p_sys->yuv_window );
+        default:
+            /* Unknown chroma, tell the guy to get lost */
+            p_pic->i_planes = 0;
 
-    XUnmapWindow( p_vout->p_sys->p_display, p_vout->p_sys->window );
-    XFreeGC( p_vout->p_sys->p_display, p_vout->p_sys->gc );
-    XDestroyWindow( p_vout->p_sys->p_display, p_vout->p_sys->window );
+            return -1;
+    }
 }
 
 /*****************************************************************************
- * XVideoCreateShmImage: create an XvImage using shared memory extension
+ * CreateShmImage: create an XvImage using shared memory extension
  *****************************************************************************
  * Prepare an XvImage for display function.
  * The order of the operations respects the recommandations of the mit-shm
  * document by J.Corbet and K.Packard. Most of the parameters were copied from
  * there.
  *****************************************************************************/
-static int XVideoCreateShmImage( Display* dpy, int xv_port,
-                                    XvImage **pp_xvimage,
-                                    XShmSegmentInfo *p_shm_info,
-                                    int i_width, int i_height )
+static XvImage *CreateShmImage( Display* p_display, int i_xvport,
+                                XShmSegmentInfo *p_shminfo,
+                                int i_width, int i_height )
 {
-    *pp_xvimage = XvShmCreateImage( dpy, xv_port,
-                                    GUID_YUV12_PLANAR, 0,
-                                    i_width, i_height,
-                                    p_shm_info );
-    if( !(*pp_xvimage) )
+    XvImage *p_xvimage;
+
+    p_xvimage = XvShmCreateImage( p_display, i_xvport,
+                                  GUID_YUV12_PLANAR, 0,
+                                  i_width, i_height,
+                                  p_shminfo );
+    if( p_xvimage == NULL )
     {
         intf_ErrMsg( "vout error: XvShmCreateImage failed." );
-        return( -1 );
+        return( NULL );
     }
 
-    p_shm_info->shmid    = shmget( IPC_PRIVATE, (*pp_xvimage)->data_size,
-                                   IPC_CREAT | 0777 );
-    if( p_shm_info->shmid < 0)                                      /* error */
+    p_shminfo->shmid = shmget( IPC_PRIVATE, p_xvimage->data_size,
+                               IPC_CREAT | 0776 );
+    if( p_shminfo->shmid < 0 ) /* error */
     {
         intf_ErrMsg( "vout error: cannot allocate shared image data (%s)",
-                    strerror(errno));
-        return( 1 );
+                     strerror( errno ) );
+        return( NULL );
     }
 
-    p_shm_info->shmaddr  = (*pp_xvimage)->data = shmat( p_shm_info->shmid,
-                                                        0, 0 );
-    p_shm_info->readOnly = False;
+    p_shminfo->shmaddr = p_xvimage->data = shmat( p_shminfo->shmid, 0, 0 );
+    p_shminfo->readOnly = False;
 
-    /* Mark the shm segment to be removed when there will be no more
-     * attachements, so it is automatic on process exit or after shmdt */
-    shmctl( p_shm_info->shmid, IPC_RMID, 0 );
-
-    if( !XShmAttach( dpy, p_shm_info ) )
+    if( !XShmAttach( p_display, p_shminfo ) )
     {
         intf_ErrMsg( "vout error: XShmAttach failed" );
-        shmdt( p_shm_info->shmaddr );
-        return( -1 );
+        shmctl( p_shminfo->shmid, IPC_RMID, 0 );
+        shmdt( p_shminfo->shmaddr );
+        return( NULL );
     }
 
     /* Send image to X server. This instruction is required, since having
      * built a Shm XImage and not using it causes an error on XCloseDisplay */
-    XFlush( dpy );
+    XSync( p_display, False );
 
-    return( 0 );
+#if 1
+    /* Mark the shm segment to be removed when there are no more
+     * attachements, so it is automatic on process exit or after shmdt */
+    shmctl( p_shminfo->shmid, IPC_RMID, 0 );
+#endif
+
+    return( p_xvimage );
 }
 
 /*****************************************************************************
- * XVideoDestroyShmImage
+ * DestroyShmImage
  *****************************************************************************
  * Destroy XImage AND associated data. Detach shared memory segment from
  * server and process, then free it. If pointer is NULL, the image won't be
- * destroyed (see vout_ManageOutputMethod())
+ * destroyed (see vout_Manage())
  *****************************************************************************/
-static void XVideoDestroyShmImage( vout_thread_t *p_vout, XvImage *p_xvimage,
-                                   XShmSegmentInfo *p_shm_info )
+static void DestroyShmImage( Display *p_display, XvImage *p_xvimage,
+                             XShmSegmentInfo *p_shminfo )
 {
-    /* If pointer is NULL, do nothing */
-    if( p_xvimage == NULL )
-    {
-        return;
-    }
+    /* Detach from server */
+    XShmDetach( p_display, p_shminfo );
+    XSync( p_display, False );
 
-    XShmDetach( p_vout->p_sys->p_display, p_shm_info );/* detach from server */
 #if 0
-    XDestroyImage( p_ximage ); /* XXX */
+    XDestroyImage( p_xvimage ); /* XXX */
 #endif
 
-    if( shmdt( p_shm_info->shmaddr ) )  /* detach shared memory from process */
-    {                                   /* also automatic freeing...         */
+    XFree( p_xvimage );
+
+    if( shmdt( p_shminfo->shmaddr ) )   /* detach shared memory from process */
+    {
         intf_ErrMsg( "vout error: cannot detach shared memory (%s)",
                      strerror(errno) );
     }
 }
 
 /*****************************************************************************
- * XVideoEnableScreenSaver: enable screen saver
- *****************************************************************************
- * This function enable the screen saver on a display after it had been
- * disabled by XDisableScreenSaver. Both functions use a counter mechanism to
- * know wether the screen saver can be activated or not: if n successive calls
- * are made to XDisableScreenSaver, n successive calls to XEnableScreenSaver
- * will be required before the screen saver could effectively be activated.
- *****************************************************************************/
-void XVideoEnableScreenSaver( vout_thread_t *p_vout )
-{
-    intf_DbgMsg( "intf: enabling screen saver" );
-    XSetScreenSaver( p_vout->p_sys->p_display, p_vout->p_sys->i_ss_timeout,
-                     p_vout->p_sys->i_ss_interval,
-                     p_vout->p_sys->i_ss_blanking,
-                     p_vout->p_sys->i_ss_exposure );
-}
-
-/*****************************************************************************
- * XVideoDisableScreenSaver: disable screen saver
- *****************************************************************************
- * See XEnableScreenSaver
- *****************************************************************************/
-void XVideoDisableScreenSaver( vout_thread_t *p_vout )
-{
-    /* Save screen saver informations */
-    XGetScreenSaver( p_vout->p_sys->p_display, &p_vout->p_sys->i_ss_timeout,
-                     &p_vout->p_sys->i_ss_interval,
-                     &p_vout->p_sys->i_ss_blanking,
-                     &p_vout->p_sys->i_ss_exposure );
-
-    /* Disable screen saver */
-    intf_DbgMsg( "intf: disabling screen saver" );
-    XSetScreenSaver( p_vout->p_sys->p_display, 0,
-                     p_vout->p_sys->i_ss_interval,
-                     p_vout->p_sys->i_ss_blanking,
-                     p_vout->p_sys->i_ss_exposure );
-}
-
-/*****************************************************************************
- * XVideoSetMousePointer: hide or show the mouse pointer
+ * GetXVideoPort: get YUV12 port
  *****************************************************************************
- * This function hides the X pointer if requested.
+ * 
  *****************************************************************************/
-void XVideoSetMousePointer( const vout_thread_t *p_vout )
-{
-    static Cursor blank_cursor;
-    static boolean_t b_created_blank_cursor = 0;
-
-    if( !p_vout->p_sys->b_mouse_pointer_visible )
-    {
-        if( !b_created_blank_cursor )
-        {
-            XColor color;
-            Pixmap blank = XCreatePixmap( p_vout->p_sys->p_display,
-                               DefaultRootWindow(p_vout->p_sys->p_display),
-                               1, 1, 1 );
-
-            XParseColor( p_vout->p_sys->p_display,
-                         XCreateColormap( p_vout->p_sys->p_display,
-                                          DefaultRootWindow(
-                                                  p_vout->p_sys->p_display ),
-                                          DefaultVisual(
-                                                  p_vout->p_sys->p_display,
-                                                  p_vout->p_sys->i_screen ),
-                                          AllocNone ),
-                         "black", &color );
-
-            blank_cursor = XCreatePixmapCursor( p_vout->p_sys->p_display,
-                           blank, blank, &color, &color, 1, 1 );
-
-            b_created_blank_cursor = 1;
-        }
-        XDefineCursor( p_vout->p_sys->p_display,
-                       p_vout->p_sys->window, blank_cursor );
-    }
-    else
-    {
-        XUndefineCursor( p_vout->p_sys->p_display, p_vout->p_sys->window );
-    }
-}
-
-/* This based on some code in SetBufferPicture... At the moment it's only
- * used by the xvideo plugin, but others may want to use it. */
-static void XVideoOutputCoords( const picture_t *p_pic, const boolean_t scale,
-                                const int win_w, const int win_h,
-                                int *dx, int *dy, int *w, int *h)
-{
-    if( !scale )
-    {
-        *w = p_pic->i_width; *h = p_pic->i_height;
-    }
-    else
-    {
-        *w = win_w;
-        switch( p_pic->i_aspect_ratio )
-        {
-            case AR_3_4_PICTURE:
-                *h = win_w * 3 / 4;
-                break;
-
-            case AR_16_9_PICTURE:
-                *h = win_w * 9 / 16;
-                break;
-
-           case AR_221_1_PICTURE:
-                *h = win_w * 100 / 221;
-                break;
-
-            case AR_SQUARE_PICTURE:
-            default:
-                *h = win_w * p_pic->i_height / p_pic->i_width;
-                break;
-        }
-
-        if( *h > win_h )
-        {
-            *h = win_h;
-            switch( p_pic->i_aspect_ratio )
-            {
-                case AR_3_4_PICTURE:
-                    *w = win_h * 4 / 3;
-                    break;
-
-                case AR_16_9_PICTURE:
-                    *w = win_h * 16 / 9;
-                    break;
-
-                case AR_221_1_PICTURE:
-                    *w = win_h * 221 / 100;
-                    break;
-
-                case AR_SQUARE_PICTURE:
-                default:
-                    *w = win_h * p_pic->i_width / p_pic->i_height;
-                    break;
-            }
-        }
-    }
-
-    /* Set picture position */
-    *dx = (win_w - *w) / 2;
-    *dy = (win_h - *h) / 2;
-}
-
-
-static int XVideoGetPort( Display *dpy )
+static int GetXVideoPort( Display *dpy )
 {
-    int            i, i_adaptors;
-    int            xv_port = -1;
-    XvAdaptorInfo *adaptor_info;
+    XvAdaptorInfo *p_adaptor;
+    int i_adaptor, i_num_adaptors, i_requested_adaptor;
+    int i_selected_port;
 
     switch( XvQueryAdaptors( dpy, DefaultRootWindow( dpy ),
-                             &i_adaptors, &adaptor_info ) )
+                             &i_num_adaptors, &p_adaptor ) )
     {
         case Success:
             break;
 
         case XvBadExtension:
-            intf_ErrMsg( "vout error: XvBadExtension for XvQueryAdaptors" );
+            intf_WarnMsg( 3, "vout error: XvBadExtension for XvQueryAdaptors" );
             return( -1 );
 
         case XvBadAlloc:
-            intf_ErrMsg( "vout error: XvBadAlloc for XvQueryAdaptors" );
+            intf_WarnMsg( 3, "vout error: XvBadAlloc for XvQueryAdaptors" );
             return( -1 );
 
         default:
-            intf_ErrMsg( "vout error: XvQueryAdaptors failed" );
+            intf_WarnMsg( 3, "vout error: XvQueryAdaptors failed" );
             return( -1 );
     }
 
-    for( i=0; i < i_adaptors && xv_port == -1; ++i )
-        if( ( adaptor_info[ i ].type & XvInputMask ) &&
-            ( adaptor_info[ i ].type & XvImageMask ) )
+    i_selected_port = -1;
+    i_requested_adaptor = main_GetIntVariable( VOUT_XVADAPTOR_VAR, -1 );
+
+    /* No special xv port has been requested so try all of them */
+    for( i_adaptor = 0; i_adaptor < i_num_adaptors; ++i_adaptor )
+    {
+        XvImageFormatValues *p_formats;
+        int i_format, i_num_formats;
+        int i_port;
+
+        /* If we requested an adaptor and it's not this one, we aren't
+         * interested */
+        if( i_requested_adaptor != -1 && i_adaptor != i_requested_adaptor )
+       {
+            continue;
+       }
+
+       /* If the adaptor doesn't have the required properties, skip it */
+        if( !( p_adaptor[ i_adaptor ].type & XvInputMask ) ||
+            !( p_adaptor[ i_adaptor ].type & XvImageMask ) )
         {
-            /* check that port supports YUV12 planar format... */
-            int port = adaptor_info[ i ].base_id;
-            int i_num_formats, i;
-            XvImageFormatValues *imageFormats;
+            continue;
+       }
 
-            imageFormats = XvListImageFormats( dpy, port, &i_num_formats );
+        /* Check that port supports YUV12 planar format... */
+        p_formats = XvListImageFormats( dpy, p_adaptor[i_adaptor].base_id,
+                                        &i_num_formats );
 
-            for( i=0; i < i_num_formats && xv_port == -1; ++i )
-                if( imageFormats[ i ].id == GUID_YUV12_PLANAR )
-                    xv_port = port;
+        for( i_format = 0; i_format < i_num_formats; i_format++ )
+        {
+            XvEncodingInfo  *p_enc;
+            int             i_enc, i_num_encodings;
+            XvAttribute     *p_attr;
+            int             i_attr, i_num_attributes;
 
-            if( xv_port == -1 )
-                intf_WarnMsg( 3, "vout: XVideo image input port %d "
-                        "does not support the YUV12 planar format which is "
-                        "currently required by the xvideo output plugin.",
-                        port );
+            /* If this is not the format we want, forget it */
+            if( p_formats[ i_format ].id != GUID_YUV12_PLANAR )
+            {
+                continue;
+            }
 
-            if( imageFormats )
-                XFree( imageFormats );
-        }
+            /* Look for the first available port supporting this format */
+            for( i_port = p_adaptor[i_adaptor].base_id;
+                 ( i_port < p_adaptor[i_adaptor].base_id
+                             + p_adaptor[i_adaptor].num_ports )
+                   && ( i_selected_port == -1 );
+                 i_port++ )
+            {
+                if( XvGrabPort( dpy, i_port, CurrentTime ) == Success )
+                {
+                    i_selected_port = i_port;
+                }
+            }
 
-    if( i_adaptors > 0 )
-        XvFreeAdaptorInfo(adaptor_info);
+            /* If no free port was found, forget it */
+            if( i_selected_port == -1 )
+            {
+                continue;
+            }
 
-    if( xv_port == -1 )
-        intf_ErrMsg( "vout error: didn't find a suitable Xvideo image input port." );
+            /* If we found a port, print information about it */
+            intf_WarnMsg( 3, "vout: GetXVideoPort found adaptor %i, port %i",
+                             i_adaptor, i_selected_port );
+            intf_WarnMsg( 3, "  image format 0x%x (%4.4s) %s supported",
+                             p_formats[ i_format ].id,
+                             (char *)&p_formats[ i_format ].id,
+                             ( p_formats[ i_format ].format
+                                == XvPacked ) ? "packed" : "planar" );
 
-    return( xv_port );
-}
+            intf_WarnMsg( 4, " encoding list:" );
 
+            if( XvQueryEncodings( dpy, i_selected_port,
+                                  &i_num_encodings, &p_enc )
+                 != Success )
+            {
+                intf_WarnMsg( 4, "  XvQueryEncodings failed" );
+                continue;
+            }
 
-/*****************************************************************************
- * XVideoDisplay: display image
- *****************************************************************************
- * This function displays the image stored in p_vout->p_sys->p_xvimage.
- * The image is scaled to fit in the output window (and to have the correct
- * aspect ratio).
- *****************************************************************************/
-static void XVideoDisplay( vout_thread_t *p_vout )
-{
-    int     i_dest_width, i_dest_height, i_dest_x, i_dest_y;
+            for( i_enc = 0; i_enc < i_num_encodings; i_enc++ )
+            {
+                intf_WarnMsg( 4, "  id=%ld, name=%s, size=%ldx%ld,"
+                                 " numerator=%d, denominator=%d",
+                              p_enc[i_enc].encoding_id, p_enc[i_enc].name,
+                              p_enc[i_enc].width, p_enc[i_enc].height,
+                              p_enc[i_enc].rate.numerator,
+                              p_enc[i_enc].rate.denominator );
+            }
 
-    if( !p_vout->p_sys->p_xvimage ) return;
+            if( p_enc != NULL )
+            {
+                XvFreeEncodingInfo( p_enc );
+            }
 
-    XVideoOutputCoords( p_vout->p_rendered_pic, p_vout->b_scale,
-                        p_vout->p_sys->i_window_width,
-                        p_vout->p_sys->i_window_height,
-                        &i_dest_x, &i_dest_y,
-                        &i_dest_width, &i_dest_height);
+            intf_WarnMsg( 4, " attribute list:" );
+            p_attr = XvQueryPortAttributes( dpy, i_selected_port,
+                                            &i_num_attributes );
+            for( i_attr = 0; i_attr < i_num_attributes; i_attr++ )
+            {
+                intf_WarnMsg( 4,
+                      "  name=%s, flags=[%s%s ], min=%i, max=%i",
+                      p_attr[i_attr].name,
+                      (p_attr[i_attr].flags & XvGettable) ? " get" : "",
+                      (p_attr[i_attr].flags & XvSettable) ? " set" : "",
+                      p_attr[i_attr].min_value, p_attr[i_attr].max_value );
+            }
 
-    XvShmPutImage( p_vout->p_sys->p_display, p_vout->p_sys->xv_port,
-                   p_vout->p_sys->yuv_window, p_vout->p_sys->gc,
-                   p_vout->p_sys->p_xvimage,
-                   0 /*src_x*/, 0 /*src_y*/,
-                   p_vout->p_rendered_pic->i_width,
-                   p_vout->p_rendered_pic->i_height,
-                   0 /*dest_x*/, 0 /*dest_y*/, i_dest_width, i_dest_height,
-                   True );
+            if( p_attr != NULL )
+            {
+                XFree( p_attr );
+            }
+        }
+
+        if( p_formats != NULL )
+        {
+            XFree( p_formats );
+        }
+
+    }
+
+    if( i_num_adaptors > 0 )
+    {
+        XvFreeAdaptorInfo( p_adaptor );
+    }
 
-     XResizeWindow( p_vout->p_sys->p_display, p_vout->p_sys->yuv_window,
-             i_dest_width, i_dest_height );
-     XMoveWindow( p_vout->p_sys->p_display, p_vout->p_sys->yuv_window,
-             i_dest_x, i_dest_y );
+    if( i_selected_port == -1 )
+    {
+        if( i_requested_adaptor == -1 )
+        {
+            intf_WarnMsg( 3, "vout: no free XVideo port found for YV12" );
+        }
+        else
+        {
+            intf_WarnMsg( 3, "vout: XVideo adaptor %i does not have a free "
+                             "XVideo port for YV12", i_requested_adaptor );
+        }
+    }
+
+    return( i_selected_port );
 }
 
 #if 0
@@ -1215,10 +756,10 @@ static void XVideoSetAttribute( vout_thread_t *p_vout,
 {
     int             i_attrib;
     XvAttribute    *p_attrib;
-    Display        *p_dpy   = p_vout->p_sys->p_display;
-    int             xv_port = p_vout->p_sys->xv_port;
+    Display        *p_display = p_vout->p_sys->p_display;
+    int             i_xvport  = p_vout->p_sys->i_xvport;
 
-    p_attrib = XvQueryPortAttributes( p_dpy, xv_port, &i_attrib );
+    p_attrib = XvQueryPortAttributes( p_display, i_xvport, &i_attrib );
 
     do
     {
@@ -1230,8 +771,8 @@ static void XVideoSetAttribute( vout_thread_t *p_vout,
                                     - p_attrib[ i_attrib ].min_value + 1 )
                         + p_attrib[ i_attrib ].min_value;
 
-            XvSetPortAttribute( p_dpy, xv_port,
-                            XInternAtom( p_dpy, attr_name, False ), i_sv );
+            XvSetPortAttribute( p_display, i_xvport,
+                            XInternAtom( p_display, attr_name, False ), i_sv );
             break;
         }
 
@@ -1241,3 +782,4 @@ static void XVideoSetAttribute( vout_thread_t *p_vout,
         XFree( p_attrib );
 }
 #endif
+