* vout_xvideo.c: Xvideo video output display method
*****************************************************************************
* Copyright (C) 1998, 1999, 2000, 2001 VideoLAN
- * $Id: vout_xvideo.c,v 1.1 2001/04/01 06:21:44 sam Exp $
+ * $Id: vout_xvideo.c,v 1.13 2001/05/01 04:18:18 sam Exp $
*
* Authors: Shane Harper <shanegh@optusnet.com.au>
* Vincent Seguin <seguin@via.ecp.fr>
* Samuel Hocevar <sam@zoy.org>
+ * David Kennedy <dkennedy@tinytoad.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
#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"
+
+
+#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 X11 specific properties of an output thread. X11 video
- * output is performed through regular resizable windows. Windows can be
- * dynamically resized to adapt to the size of the streams.
+ * It describes the XVideo specific properties of an output thread.
*****************************************************************************/
typedef struct vout_sys_s
{
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 (I don't know why the X11 plugin had 2.) */
+ /* 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_width; /* width of main window */
- int i_height; /* height of main 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; /* is the mouse pointer displayed ? */
+ 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
*****************************************************************************/
static void vout_SetPalette( vout_thread_t *, u16 *, u16 *, u16 *, u16 * );
static int XVideoCreateWindow ( vout_thread_t * );
-static int XVideoCreateShmImage ( vout_thread_t *, XvImage **,
- XShmSegmentInfo *p_shm_info );
+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 XVideoTogglePointer ( vout_thread_t * );
+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 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 * );
/*****************************************************************************
* Functions exported as capabilities. They are declared as static so that
return( 999 );
}
- return( 90 );
+ return( 60 );
}
/*****************************************************************************
* vout_Create: allocate XVideo video thread output method
*****************************************************************************
- * This function allocate and initialize a X11 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.
+ * This function allocate 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 )
{
}
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 ) )
{
intf_ErrMsg( "vout error: no XVideo extension" );
return( 1 );
}
- p_vout->p_sys->b_mouse = 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... */
+ XVideoSetAttribute( p_vout, "XV_BRIGHTNESS", 0.5 );
+ 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 );
/*****************************************************************************
* vout_Init: initialize XVideo video thread output method
- *****************************************************************************
- * This function create the XImages needed by the output thread. It is called
- * at the beginning of the thread, but also each time the window is resized.
*****************************************************************************/
static int vout_Init( vout_thread_t *p_vout )
{
- int i_err;
-
#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;
- /* Create XImages using XShm extension */
- i_err = XVideoCreateShmImage( p_vout, &p_vout->p_sys->p_xvimage,
- &p_vout->p_sys->shm_info );
- if( i_err )
- {
- intf_Msg( "vout: XShm video extension unavailable" );
- /* p_vout->p_sys->b_shm = 0; */
- }
- p_vout->b_need_render = 0; /* = 1 if not using Xv extension. */
-
- /* 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);
-
- /* vout_SetBuffers( p_vout, p_vout->p_sys->p_xvimage[0]->data,
- * p_vout->p_sys->p_xvimage[1]->data ); */
- p_vout->p_buffer[0].i_pic_x = 0;
- p_vout->p_buffer[0].i_pic_y = 0;
- p_vout->p_buffer[0].i_pic_width = 0;
- p_vout->p_buffer[0].i_pic_height = 0;
-
- /* The first area covers all the screen */
- p_vout->p_buffer[0].i_areas = 1;
- p_vout->p_buffer[0].pi_area_begin[0] = 0;
- p_vout->p_buffer[0].pi_area_end[0] = p_vout->i_height - 1;
-
- /* Set addresses */
- p_vout->p_buffer[0].p_data = p_vout->p_sys->p_xvimage->data;
return( 0 );
}
/*****************************************************************************
* vout_End: terminate XVideo video thread output method
*****************************************************************************
- * Destroy the XVideo xImages created by vout_Init. It is called at the end of
- * the thread, but also each time the window is resized.
+ * 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 )
{
/*****************************************************************************
* vout_Destroy: destroy XVideo video thread output method
*****************************************************************************
- * Terminate an output method created by vout_CreateOutputMethod
+ * Terminate an output method created by vout_Create
*****************************************************************************/
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 );
-
+ XVideoDestroyWindow( p_vout );
XCloseDisplay( p_vout->p_sys->p_display );
/* Destroy structure */
static int vout_Manage( vout_thread_t *p_vout )
{
XEvent xevent; /* X11 event */
- boolean_t b_resized; /* window has been resized */
+ 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 */
- b_resized = 0;
while( XCheckWindowEvent( p_vout->p_sys->p_display, p_vout->p_sys->window,
StructureNotifyMask | KeyPressMask |
- ButtonPressMask | ButtonReleaseMask, &xevent )
+ ButtonPressMask | ButtonReleaseMask |
+ PointerMotionMask, &xevent )
== True )
{
/* ConfigureNotify event: prepare */
if( (xevent.type == ConfigureNotify)
- && ((xevent.xconfigure.width != p_vout->p_sys->i_width)
- || (xevent.xconfigure.height != p_vout->p_sys->i_height)) )
+ /*&& ((xevent.xconfigure.width != p_vout->p_sys->i_window_width)
+ || (xevent.xconfigure.height != p_vout->p_sys->i_window_height))*/ )
{
/* Update dimensions */
-#if 0 XXX XXX
- b_resized = 1;
- p_vout->p_sys->i_width = xevent.xconfigure.width;
- p_vout->p_sys->i_height = xevent.xconfigure.height;
-#endif XXX XXX
+ 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)
/* Keyboard event */
else if( xevent.type == KeyPress )
{
- if( XLookupString( &xevent.xkey, &i_key, 1, NULL, NULL ) )
+ /* 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 )
{
- /* FIXME: handle stuff here */
- switch( i_key )
- {
- case 'q':
- /* FIXME: need locking ! */
- p_main->p_intf->b_die = 1;
- break;
- }
+ 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;
+ }
+ }
+ break;
}
}
/* Mouse click */
/* in this part we will eventually manage
* clicks for DVD navigation for instance */
break;
-
- case Button2:
- XVideoTogglePointer( p_vout );
- break;
}
}
/* Mouse release */
break;
}
}
-#ifdef DEBUG
+ /* 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 );
+ }
/* Other event */
else
{
- intf_DbgMsg( "%p -> unhandled event type %d received",
+ intf_WarnMsg( 1, "%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 */
}
}
- if( (p_vout->i_width != p_vout->p_sys->i_width) ||
- (p_vout->i_height != p_vout->p_sys->i_height) )
+ if ( b_toggle_fullscreen )
{
- /* If video output size has changed, change interface window size */
- intf_DbgMsg( "resizing output window" );
- p_vout->p_sys->i_width = p_vout->i_width;
- p_vout->p_sys->i_height = p_vout->i_height;
- XResizeWindow( p_vout->p_sys->p_display, p_vout->p_sys->window,
- p_vout->p_sys->i_width, p_vout->p_sys->i_height );
+ intf_DbgMsg( "vout: changing full-screen status" );
+
+ p_vout->p_sys->b_fullscreen = !p_vout->p_sys->b_fullscreen;
+
+ /* Get rid of the old window */
+ XVideoDestroyWindow( p_vout );
+
+ /* And create a new one */
+ if( XVideoCreateWindow( p_vout ) )
+ {
+ intf_ErrMsg( "vout error: cannot create X11 window" );
+ XCloseDisplay( p_vout->p_sys->p_display );
+
+ free( p_vout->p_sys );
+ return( 1 );
+ }
}
+
if( (p_vout->i_changes & VOUT_GRAYSCALE_CHANGE))
{
/* FIXME: clear flags ?? */
{
intf_DbgMsg( "vout: resizing window" );
p_vout->i_changes &= ~VOUT_SIZE_CHANGE;
-
- /* Resize window */
- XResizeWindow( p_vout->p_sys->p_display, p_vout->p_sys->window,
- p_vout->i_width, p_vout->i_height );
-
- /* Destroy XImages to change their size */
- vout_End( p_vout );
-
- /* Recreate XImages. If SysInit failed, the thread cannot go on. */
- if( vout_Init( p_vout ) )
- {
- intf_ErrMsg( "vout error: cannot resize display" );
- return( 1 );
- }
-
+ /* 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 );
}
+ /* Autohide Cursor */
+ if( p_vout->p_sys->b_mouse_pointer_visible &&
+ mdate() - p_vout->p_sys->i_time_mouse_last_moved > 2000000 )
+ {
+ p_vout->p_sys->b_mouse_pointer_visible = 0;
+ XVideoSetMousePointer( p_vout );
+ }
+
return 0;
}
-
/*****************************************************************************
* vout_Display: displays previously rendered output
*****************************************************************************
- * This function send the currently rendered image to X11 server, wait until
- * it is displayed and switch the two rendering buffer, preparing next frame.
+ * 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 )
{
boolean_t b_draw = 1;
- const int i_size = p_vout->i_width * p_vout->i_height;
+ 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 )
{
}
if( b_draw )
- {
- int i_dummy, i_src_width, i_src_height,
- i_dest_width, i_dest_height, i_dest_x, i_dest_y;
- Window window;
-
- /* Could use p_vout->p_sys->i_width and p_vout->p_sys->i_height
- *instead of calling XGetGeometry? */
- XGetGeometry( p_vout->p_sys->p_display, p_vout->p_sys->window,
- &window, &i_dummy, &i_dummy,
- &i_src_width, &i_src_height, &i_dummy, &i_dummy );
-
- XVideoOutputCoords( p_vout->p_rendered_pic, p_vout->b_scale,
- i_src_width, i_src_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 );
- }
+ XVideoDisplay( p_vout );
}
static void vout_SetPalette( p_vout_thread_t p_vout,
/* following functions are local */
+/*****************************************************************************
+ * XVideoUpdateImgSizeIfRequired
+ *****************************************************************************
+ * 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).
+ *****************************************************************************/
+static int XVideoUpdateImgSizeIfRequired( 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 )
+ {
+ 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 );
+ }
+
+ /* 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);
+
+ /* vout_SetBuffers( p_vout, p_vout->p_sys->p_xvimage->data ); */
+ }
+
+ return( 0 );
+}
+
/*****************************************************************************
* XVideoCheckForXv: check for the XVideo extension
*****************************************************************************/
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 */
- p_vout->p_sys->i_width = main_GetIntVariable( VOUT_WIDTH_VAR,
- VOUT_WIDTH_DEFAULT );
- p_vout->p_sys->i_height = main_GetIntVariable( VOUT_HEIGHT_VAR,
- VOUT_HEIGHT_DEFAULT );
+ /* 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 );
+ }
/* Prepare window manager hints and properties */
- xsize_hints.base_width = p_vout->p_sys->i_width;
- xsize_hints.base_height = p_vout->p_sys->i_height;
+ 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 );
"WM_DELETE_WINDOW", True );
/* Prepare window attributes */
- xwindow_attributes.backing_store = Always; /* save the hidden part */
- xwindow_attributes.background_pixel = WhitePixel( p_vout->p_sys->p_display,
+ xwindow_attributes.background_pixel = BlackPixel( p_vout->p_sys->p_display,
p_vout->p_sys->i_screen );
xwindow_attributes.event_mask = ExposureMask | StructureNotifyMask;
XCreateWindow( p_vout->p_sys->p_display,
DefaultRootWindow( p_vout->p_sys->p_display ),
0, 0,
- p_vout->p_sys->i_width, p_vout->p_sys->i_height, 1,
+ p_vout->p_sys->i_window_width,
+ p_vout->p_sys->i_window_height, 1,
0, InputOutput, 0,
- CWBackingStore | CWBackPixel | CWEventMask,
+ CWBackPixel | CWEventMask,
&xwindow_attributes );
+ if ( p_vout->p_sys->b_fullscreen )
+ {
+ 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 );
+ }
+
+
/* 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,
&& (xevent.xconfigure.window == p_vout->p_sys->window) )
{
b_configure_notify = 1;
- p_vout->p_sys->i_width = xevent.xconfigure.width;
- p_vout->p_sys->i_height = xevent.xconfigure.height;
+ 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 ) );
XSelectInput( p_vout->p_sys->p_display, p_vout->p_sys->window,
StructureNotifyMask | KeyPressMask |
- ButtonPressMask | ButtonReleaseMask );
+ 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 );
+ }
+
+ /* 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 );
+
+ 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 ) );
+
+ 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 );
+
+
+ XVideoSetMousePointer( p_vout );
- /* At this stage, the window is open, displayed, and ready to
- * receive data */
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 );
+
+ 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 );
+}
+
/*****************************************************************************
- * XVideoCreateShmImage: create an XImage using shared memory extension
+ * XVideoCreateShmImage: create an XvImage using shared memory extension
*****************************************************************************
- * Prepare an XImage for DisplayX11ShmImage function.
+ * 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( vout_thread_t *p_vout, XvImage **pp_xvimage,
- XShmSegmentInfo *p_shm_info)
+static int XVideoCreateShmImage( Display* dpy, int xv_port,
+ XvImage **pp_xvimage,
+ XShmSegmentInfo *p_shm_info,
+ int i_width, int i_height )
{
- int i_adaptors;
- XvAdaptorInfo *adaptor_info;
-
- /* find xv_port... */
- switch( XvQueryAdaptors( p_vout->p_sys->p_display,
- DefaultRootWindow( p_vout->p_sys->p_display ),
- &i_adaptors, &adaptor_info ) )
- {
- case Success:
- break;
-
- case XvBadExtension:
- intf_ErrMsg( "vout error: XvBadExtension for XvQueryAdaptors" );
- return( -1 );
-
- case XvBadAlloc:
- intf_ErrMsg( "vout error: XvBadAlloc for XvQueryAdaptors" );
- return( -1 );
-
- default:
- intf_ErrMsg( "vout error: XvQueryAdaptors failed" );
- return( -1 );
- }
-
- /* XXX is this right? */
- p_vout->p_sys->xv_port = adaptor_info[ i_adaptors - 1 ].base_id;
-
- #define GUID_YUV12_PLANAR 0x32315659
-
- *pp_xvimage = XvShmCreateImage( p_vout->p_sys->p_display,
- p_vout->p_sys->xv_port,
+ *pp_xvimage = XvShmCreateImage( dpy, xv_port,
GUID_YUV12_PLANAR, 0,
- p_vout->i_width, p_vout->i_height,
+ i_width, i_height,
p_shm_info );
+ if( !(*pp_xvimage) )
+ {
+ intf_ErrMsg( "vout error: XvShmCreateImage failed." );
+ return( -1 );
+ }
p_shm_info->shmid = shmget( IPC_PRIVATE, (*pp_xvimage)->data_size,
IPC_CREAT | 0777 );
+ if( p_shm_info->shmid < 0) /* error */
+ {
+ intf_ErrMsg( "vout error: cannot allocate shared image data (%s)",
+ strerror(errno));
+ return( 1 );
+ }
+
p_shm_info->shmaddr = (*pp_xvimage)->data = shmat( p_shm_info->shmid,
0, 0 );
p_shm_info->readOnly = False;
- shmctl( p_shm_info->shmid, IPC_RMID, 0 ); /* XXX */
+ /* 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(p_vout->p_sys->p_display, p_shm_info) )
+ if( !XShmAttach( dpy, p_shm_info ) )
{
intf_ErrMsg( "vout error: XShmAttach failed" );
+ shmdt( p_shm_info->shmaddr );
return( -1 );
}
/* 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( p_vout->p_sys->p_display );
+ XFlush( dpy );
return( 0 );
}
XShmDetach( p_vout->p_sys->p_display, p_shm_info );/* detach from server */
#if 0
- XDestroyImage( p_ximage );
-#else
-/* XvDestroyImage( p_xvimage ); XXX */
+ XDestroyImage( p_ximage ); /* XXX */
#endif
if( shmdt( p_shm_info->shmaddr ) ) /* detach shared memory from process */
}
/*****************************************************************************
- * XVideoTogglePointer: hide or show the mouse pointer
+ * XVideoSetMousePointer: 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.
+ * This function hides the X pointer if requested.
*****************************************************************************/
-void XVideoTogglePointer( vout_thread_t *p_vout )
+void XVideoSetMousePointer( const vout_thread_t *p_vout )
{
- static Cursor cursor;
- static boolean_t b_cursor = 0;
+ static Cursor blank_cursor;
+ static boolean_t b_created_blank_cursor = 0;
- if( p_vout->p_sys->b_mouse )
+ if( !p_vout->p_sys->b_mouse_pointer_visible )
{
- p_vout->p_sys->b_mouse = 0;
-
- if( !b_cursor )
+ if( !b_created_blank_cursor )
{
XColor color;
Pixmap blank = XCreatePixmap( p_vout->p_sys->p_display,
AllocNone ),
"black", &color );
- cursor = XCreatePixmapCursor( p_vout->p_sys->p_display,
+ blank_cursor = XCreatePixmapCursor( p_vout->p_sys->p_display,
blank, blank, &color, &color, 1, 1 );
- b_cursor = 1;
+ b_created_blank_cursor = 1;
}
XDefineCursor( p_vout->p_sys->p_display,
- p_vout->p_sys->window, cursor );
+ p_vout->p_sys->window, blank_cursor );
}
else
{
- p_vout->p_sys->b_mouse = 1;
-
XUndefineCursor( p_vout->p_sys->p_display, p_vout->p_sys->window );
}
}
*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; break;
+ 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; break;
+ 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;
}
}
}
*dy = (win_h - *h) / 2;
}
+
+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;
+
+ case XvBadExtension:
+ intf_ErrMsg( "vout error: XvBadExtension for XvQueryAdaptors" );
+ return( -1 );
+
+ case XvBadAlloc:
+ intf_ErrMsg( "vout error: XvBadAlloc for XvQueryAdaptors" );
+ return( -1 );
+
+ default:
+ intf_ErrMsg( "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 ) )
+ {
+ /* check that port supports YUV12 planar format... */
+ int port = adaptor_info[ i ].base_id;
+ int i_num_formats, i;
+ XvImageFormatValues *imageFormats;
+
+ imageFormats = XvListImageFormats( dpy, port, &i_num_formats );
+
+ for( i=0; i < i_num_formats && xv_port == -1; ++i )
+ if( imageFormats[ i ].id == GUID_YUV12_PLANAR )
+ xv_port = port;
+
+ 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( imageFormats )
+ XFree( imageFormats );
+ }
+
+ if( i_adaptors > 0 )
+ XvFreeAdaptorInfo(adaptor_info);
+
+ if( xv_port == -1 )
+ intf_ErrMsg( "vout error: didn't find a suitable Xvideo image input port." );
+
+ return( xv_port );
+}
+
+
+/*****************************************************************************
+ * 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;
+
+ if( !p_vout->p_sys->p_xvimage ) return;
+
+ 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);
+
+ 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 );
+
+ 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 0
+/*****************************************************************************
+ * XVideoSetAttribute
+ *****************************************************************************
+ * This function can be used to set attributes, e.g. XV_BRIGHTNESS and
+ * XV_CONTRAST. "f_value" should be in the range of 0 to 1.
+ *****************************************************************************/
+static void XVideoSetAttribute( vout_thread_t *p_vout,
+ char *attr_name, float f_value )
+{
+ int i_attrib;
+ XvAttribute *p_attrib;
+ Display *p_dpy = p_vout->p_sys->p_display;
+ int xv_port = p_vout->p_sys->xv_port;
+
+ p_attrib = XvQueryPortAttributes( p_dpy, xv_port, &i_attrib );
+
+ do
+ {
+ i_attrib--;
+
+ if( i_attrib >= 0 && !strcmp( p_attrib[ i_attrib ].name, attr_name ) )
+ {
+ int i_sv = f_value * ( p_attrib[ i_attrib ].max_value
+ - 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 );
+ break;
+ }
+
+ } while( i_attrib > 0 );
+
+ if( p_attrib )
+ XFree( p_attrib );
+}
+#endif