* vout_xvideo.c: Xvideo video output display method
*****************************************************************************
* Copyright (C) 1998, 1999, 2000, 2001 VideoLAN
- * $Id: vout_xvideo.c,v 1.7 2001/04/15 04:46:41 sam Exp $
+ * $Id: vout_xvideo.c,v 1.18 2001/05/30 17:03:12 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 <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 "threads.h"
#include "mtime.h"
#include "tests.h"
-#include "modules.h"
#include "video.h"
#include "video_output.h"
#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 GUID_YUV12_PLANAR 0x32315659
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 */
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 ? */
+ boolean_t b_mouse_pointer_visible;
+ mtime_t i_time_mouse_last_moved; /* used to auto-hide pointer*/
} 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 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,
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 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 );
}
/*****************************************************************************
}
p_vout->p_sys->i_screen = DefaultScreen( p_vout->p_sys->p_display );
+ p_vout->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" );
if( (p_vout->p_sys->xv_port = XVideoGetPort( p_vout->p_sys->p_display ))<0 )
return 1;
- intf_DbgMsg( 1, "Using xv port %d" , p_vout->p_sys->xv_port );
+ 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
XVideoSetAttribute( p_vout, "XV_CONTRAST", 0.5 );
#endif
- p_vout->p_sys->b_mouse = 1;
+ p_vout->p_sys->b_mouse_pointer_visible = 1;
/* Disable screen saver and return */
XVideoDisableScreenSaver( 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 */
case 'Q':
p_main->p_intf->b_die = 1;
break;
+ case 'f':
+ case 'F':
+ p_vout->i_changes |= VOUT_FULLSCREEN_CHANGE;
+ break;
case '0':
network_ChannelJoin( 0 );
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 );
- }
+ 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",
+ intf_WarnMsg( 3, "%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_changes & VOUT_FULLSCREEN_CHANGE )
+ {
+ intf_DbgMsg( "vout: changing full-screen status" );
+
+ p_vout->b_fullscreen = !p_vout->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;
- /* Noting to do here...
+ /* 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)",
}
/* Autohide Cursor */
- if( p_vout->p_sys->b_mouse &&
- mdate() - p_vout->p_sys->i_lastmoved > 2000000 )
- XVideoTogglePointer( p_vout );
-
- return 0;
-}
-
-/*****************************************************************************
- * 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 )
+ if( p_vout->p_sys->b_mouse_pointer_visible &&
+ mdate() - p_vout->p_sys->i_time_mouse_last_moved > 2000000 )
{
- 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 ); */
+ p_vout->p_sys->b_mouse_pointer_visible = 0;
+ XVideoSetMousePointer( p_vout );
}
- return( 0 );
+
+ return 0;
}
/*****************************************************************************
}
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;
-
-#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
-
- 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 );
- }
+ 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);
+
+ /* p_vout->pf_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_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 );
+ /* If we're full screen, we're full screen! */
+ if( p_vout->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_window_width;
"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 );
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->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,
ButtonPressMask | ButtonReleaseMask |
PointerMotionMask );
- /* At this stage, the window is open, displayed, and ready to
- * receive data */
+ if( p_vout->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 );
+
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 XvImage using shared memory extension
*****************************************************************************
}
/*****************************************************************************
- * 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;
}
}
}
}
+/*****************************************************************************
+ * 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