X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=plugins%2Fx11%2Fvout_xvideo.c;h=0f2a1ad9243650943c0ec0b747861cedce05d142;hb=c1ba1b4951fe13f7b0138e54cc11df555c20252b;hp=84d5a7ec45c27e6e27bc1392e89c1e9a4533a1c6;hpb=3bc1ec7a6d61407263b5832dda198f47167fd3a7;p=vlc diff --git a/plugins/x11/vout_xvideo.c b/plugins/x11/vout_xvideo.c index 84d5a7ec45..0f2a1ad924 100644 --- a/plugins/x11/vout_xvideo.c +++ b/plugins/x11/vout_xvideo.c @@ -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.10 2001/04/25 09:31:14 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 * Vincent Seguin @@ -43,6 +43,10 @@ #include #endif +#ifndef WIN32 +#include /* BSD: struct in_addr */ +#endif + #include /* shmget(), shmctl() */ #include #include @@ -50,97 +54,30 @@ #include #include #include +#include -#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 */ - 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 */ - - /* Auto-hide cursor */ - mtime_t i_lastmoved; - - /* Mouse pointer properties */ - boolean_t b_mouse; /* is the mouse pointer displayed ? */ - - /* 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 *****************************************************************************/ @@ -149,28 +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 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 XVideoTogglePointer ( 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 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 @@ -183,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; } /***************************************************************************** @@ -196,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 ) ); @@ -235,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 ); @@ -246,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... */ @@ -267,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 = 1; - /* Disable screen saver and return */ - XVideoDisableScreenSaver( p_vout ); + _M( XCommonDisableScreenSaver ) ( p_vout ); return( 0 ); } @@ -280,339 +263,105 @@ 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; + int i_index; + picture_t *p_pic; - return( 0 ); -} + I_OUTPUTPICTURES = 0; -/***************************************************************************** - * 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 ); -} - -/***************************************************************************** - * vout_Destroy: destroy XVideo video thread output method - ***************************************************************************** - * Terminate an output method created by vout_CreateOutputMethod - *****************************************************************************/ -static void vout_Destroy( vout_thread_t *p_vout ) -{ - /* Enable screen saver */ - XVideoEnableScreenSaver( p_vout ); - - /* Destroy window */ - 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 ); - - 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_gofullscreen; /* user wants full-screen */ - char i_key; /* ISO Latin-1 key */ - KeySym x_key_symbol; - - b_gofullscreen = 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_gofullscreen = 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_lastmoved = mdate(); - if( ! p_vout->p_sys->b_mouse ) - { - XVideoTogglePointer( p_vout ); - } - } - -#ifdef DEBUG - /* Other event */ - else - { - intf_DbgMsg( "%p -> unhandled event type %d received", - p_vout, xevent.type ); - } -#endif - } - /* 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_gofullscreen ) - { - char *psz_display; - /* Open display, unsing 'vlc_display' or DISPLAY environment variable */ - psz_display = XDisplayName( main_GetPszVariable( VOUT_DISPLAY_VAR, NULL ) ); - - 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 */ - XUnmapWindow( p_vout->p_sys->p_display, p_vout->p_sys->window ); - XFreeGC( p_vout->p_sys->p_display, p_vout->p_sys->gc ); + 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 ); - } - - /* We've changed the size, update it */ - p_vout->i_changes |= VOUT_SIZE_CHANGE; + 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 ) +/***************************************************************************** + * 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; + + /* Free the direct buffers we allocated */ + for( i_index = I_OUTPUTPICTURES ; i_index ; ) { - intf_DbgMsg( "vout: resizing window" ); - p_vout->i_changes &= ~VOUT_SIZE_CHANGE; - /* Noting 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 ); + 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 ); } - - /* Autohide Cursor */ - if( p_vout->p_sys->b_mouse && - mdate() - p_vout->p_sys->i_lastmoved > 2000000 ) - XVideoTogglePointer( p_vout ); - - return 0; } /***************************************************************************** - * XVideoUpdateImgSizeIfRequired + * vout_Destroy: destroy XVideo video thread output method ***************************************************************************** - * 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). + * Terminate an output method created by vout_Create *****************************************************************************/ -static int XVideoUpdateImgSizeIfRequired( vout_thread_t *p_vout ) +static void vout_Destroy( vout_thread_t *p_vout ) { - int i_img_width = p_vout->p_rendered_pic->i_width; - int i_img_height = p_vout->p_rendered_pic->i_height; - - if( p_vout->p_sys->i_image_width != i_img_width - || p_vout->p_sys->i_image_height != i_img_height ) + /* Restore cursor if it was blanked */ + if( !p_vout->p_sys->b_mouse_pointer_visible ) { - 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 ); - } + _M( XCommonToggleMousePointer ) ( p_vout ); + } - /* 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); + /* Destroy blank cursor pixmap */ + XFreePixmap( p_vout->p_sys->p_display, p_vout->p_sys->cursor_pixmap ); - /* vout_SetBuffers( p_vout, p_vout->p_sys->p_xvimage->data ); */ - } - return( 0 ); + _M( XCommonEnableScreenSaver ) ( p_vout ); + _M( XCommonDestroyWindow ) ( p_vout ); + XCloseDisplay( p_vout->p_sys->p_display ); + + /* Destroy structure */ + free( p_vout->p_sys ); } /***************************************************************************** @@ -621,527 +370,379 @@ static int XVideoUpdateImgSizeIfRequired( vout_thread_t *p_vout ) * This function sends the currently rendered image to X11 server. * (The Xv extension takes care of "double-buffering".) *****************************************************************************/ -static void vout_Display( vout_thread_t *p_vout ) +static void vout_Display( vout_thread_t *p_vout, picture_t *p_pic ) { - 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 ) - { - 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; - } + int i_width, i_height, i_x, i_y; - if( b_draw ) - { - int i_dummy, - i_window_width = p_vout->p_sys->i_window_width, - i_window_height = p_vout->p_sys->i_window_height, - i_dest_width, i_dest_height, i_dest_x, i_dest_y; - Window window; + vout_PlacePicture( p_vout, p_vout->p_sys->i_width, p_vout->p_sys->i_height, + &i_x, &i_y, &i_width, &i_height ); -#if 1 - /* If I change the line above to "#if 0" I find on resizing the window - * that blue rectangles (used to specify where part of the YUV overlay - * used to be drawn) may remain around the edge of the video output. */ - XGetGeometry( p_vout->p_sys->p_display, p_vout->p_sys->window, - &window, &i_dummy, &i_dummy, - &i_window_width, &i_window_height, &i_dummy, &i_dummy ); -#endif + 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 ); - XVideoOutputCoords( p_vout->p_rendered_pic, p_vout->b_scale, - i_window_width, i_window_height, - &i_dest_x, &i_dest_y, - &i_dest_width, &i_dest_height); - - XvShmPutImage( p_vout->p_sys->p_display, p_vout->p_sys->xv_port, - p_vout->p_sys->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, - i_dest_x, i_dest_y, i_dest_width, i_dest_height, - True ); - } -} + XResizeWindow( p_vout->p_sys->p_display, p_vout->p_sys->yuv_window, + i_width, i_height ); -static void vout_SetPalette( p_vout_thread_t p_vout, - u16 *red, u16 *green, u16 *blue, u16 *transp ) -{ - return; + 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; - - - /* 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 - { - /* Set main window's size */ - 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.backing_store = Always; /* save the hidden part */ - 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, - CWBackingStore | 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 ); - /* At this stage, the window is open, displayed, and ready to - * receive data */ - return( 0 ); + /* 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); + + 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); + + 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; + + return 0; + + default: + /* Unknown chroma, tell the guy to get lost */ + p_pic->i_planes = 0; + + 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 + * GetXVideoPort: get YUV12 port ***************************************************************************** - * 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 ) +static int GetXVideoPort( Display *dpy ) { - 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 ); -} + XvAdaptorInfo *p_adaptor; + int i_adaptor, i_num_adaptors, i_requested_adaptor; + int i_selected_port; -/***************************************************************************** - * 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 ); -} + switch( XvQueryAdaptors( dpy, DefaultRootWindow( dpy ), + &i_num_adaptors, &p_adaptor ) ) + { + case Success: + break; -/***************************************************************************** - * XVideoTogglePointer: hide or show the mouse pointer - ***************************************************************************** - * This function hides the X pointer if it is visible by putting it at - * coordinates (32,32) and setting the pointer sprite to a blank one. To - * show it again, we disable the sprite and restore the original coordinates. - *****************************************************************************/ -void XVideoTogglePointer( vout_thread_t *p_vout ) -{ - static Cursor cursor; - static boolean_t b_cursor = 0; + case XvBadExtension: + intf_WarnMsg( 3, "vout error: XvBadExtension for XvQueryAdaptors" ); + return( -1 ); - if( p_vout->p_sys->b_mouse ) - { - p_vout->p_sys->b_mouse = 0; + case XvBadAlloc: + intf_WarnMsg( 3, "vout error: XvBadAlloc for XvQueryAdaptors" ); + return( -1 ); - if( !b_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 ); - - cursor = XCreatePixmapCursor( p_vout->p_sys->p_display, - blank, blank, &color, &color, 1, 1 ); - - b_cursor = 1; - } - XDefineCursor( p_vout->p_sys->p_display, - p_vout->p_sys->window, cursor ); + default: + intf_WarnMsg( 3, "vout error: XvQueryAdaptors failed" ); + return( -1 ); } - else - { - p_vout->p_sys->b_mouse = 1; - XUndefineCursor( p_vout->p_sys->p_display, p_vout->p_sys->window ); - } -} + i_selected_port = -1; + i_requested_adaptor = main_GetIntVariable( VOUT_XVADAPTOR_VAR, -1 ); -/* 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 ) + /* No special xv port has been requested so try all of them */ + for( i_adaptor = 0; i_adaptor < i_num_adaptors; ++i_adaptor ) { - *w = p_pic->i_width; *h = p_pic->i_height; - } - else - { - *w = win_w; - switch( p_pic->i_aspect_ratio ) + 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 ) ) { - 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; break; - } + continue; + } - if( *h > win_h ) + /* Check that port supports YUV12 planar format... */ + p_formats = XvListImageFormats( dpy, p_adaptor[i_adaptor].base_id, + &i_num_formats ); + + for( i_format = 0; i_format < i_num_formats; i_format++ ) { - *h = win_h; - switch( p_pic->i_aspect_ratio ) + XvEncodingInfo *p_enc; + int i_enc, i_num_encodings; + XvAttribute *p_attr; + int i_attr, i_num_attributes; + + /* If this is not the format we want, forget it */ + if( p_formats[ i_format ].id != GUID_YUV12_PLANAR ) { - 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; break; + continue; } - } - } - - /* Set picture position */ - *dx = (win_w - *w) / 2; - *dy = (win_h - *h) / 2; -} + /* 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; + } + } -static int XVideoGetPort( Display *dpy ) -{ - int i, i_adaptors; - int xv_port = -1; - XvAdaptorInfo *adaptor_info; - - switch( XvQueryAdaptors( dpy, DefaultRootWindow( dpy ), - &i_adaptors, &adaptor_info ) ) - { - case Success: - break; + /* If no free port was found, forget it */ + if( i_selected_port == -1 ) + { + continue; + } - case XvBadExtension: - intf_ErrMsg( "vout error: XvBadExtension for XvQueryAdaptors" ); - return( -1 ); + /* 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" ); - case XvBadAlloc: - intf_ErrMsg( "vout error: XvBadAlloc for XvQueryAdaptors" ); - return( -1 ); + intf_WarnMsg( 4, " encoding list:" ); - default: - intf_ErrMsg( "vout error: XvQueryAdaptors failed" ); - return( -1 ); - } + if( XvQueryEncodings( dpy, i_selected_port, + &i_num_encodings, &p_enc ) + != Success ) + { + intf_WarnMsg( 4, " XvQueryEncodings failed" ); + continue; + } - for( i=0; i < i_adaptors && xv_port == -1; ++i ) - if( ( adaptor_info[ i ].type & XvInputMask ) && - ( adaptor_info[ i ].type & XvImageMask ) ) - { - /* check that port supports YUV12 planar format... */ - int port = adaptor_info[ i ].base_id; - int i_num_formats, i; - XvImageFormatValues *imageFormats; + 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 ); + } - imageFormats = XvListImageFormats( dpy, port, &i_num_formats ); + if( p_enc != NULL ) + { + XvFreeEncodingInfo( p_enc ); + } - for( i=0; i < i_num_formats && xv_port == -1; ++i ) - if( imageFormats[ i ].id == GUID_YUV12_PLANAR ) - xv_port = port; + 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 ); + } - 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( p_attr != NULL ) + { + XFree( p_attr ); + } + } - if( imageFormats ) - XFree( imageFormats ); + if( p_formats != NULL ) + { + XFree( p_formats ); } - if( i_adaptors > 0 ) - XvFreeAdaptorInfo(adaptor_info); + } - if( xv_port == -1 ) - intf_ErrMsg( "vout error: didn't find a suitable Xvideo image input port." ); + if( i_num_adaptors > 0 ) + { + XvFreeAdaptorInfo( p_adaptor ); + } - return( xv_port ); -} + 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 /***************************************************************************** @@ -1155,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 { @@ -1170,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; } @@ -1181,3 +782,4 @@ static void XVideoSetAttribute( vout_thread_t *p_vout, XFree( p_attrib ); } #endif +