* vout_directx.c: Windows DirectX video output display method
*****************************************************************************
* Copyright (C) 2001 VideoLAN
- * $Id: vout_directx.c,v 1.18 2002/01/04 14:01:34 sam Exp $
+ * $Id: vout_directx.c,v 1.19 2002/01/17 23:02:45 gbazin Exp $
*
* Authors: Gildas Bazin <gbazin@netcourrier.com>
*
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
*****************************************************************************/
-/* ToDo:
- *
- * Double buffering
- *
- * Port this plugin to Video Output IV
- */
-
/*****************************************************************************
* Preamble:
*
* the best video quality (hardware interpolation when rescaling the picture)
* and the fastest display as it requires less processing.
*
- * If YUV overlay is not supported the plugin will use an RGB offscreen video
- * surface that will be blitted onto the primary surface (display) to
- * effectively display the picture. this fallback method enables us to display
+ * If YUV overlay is not supported this plugin will use RGB offscreen video
+ * surfaces that will be blitted onto the primary surface (display) to
+ * effectively display the pictures. this fallback method enables us to display
* video in window mode.
- * Another fallback method (which isn't implemented yet) would be to use the
- * primary surface as the video buffer. This would allow for better
- * performance but this is restricted to fullscreen video. In short,
- * implementing this is not considered high priority.
+ * Another fallback method (which isn't implemented) would be take the
+ * exclusive control of the screen so we could spare the blitting process and
+ * decode directly to video memory. This should theoretically allow for better
+ * performance (although on my system it is actually slower) but this is
+ * restricted to fullscreen video.
*
*****************************************************************************/
#include <errno.h> /* ENOMEM */
#include <windows.h>
#include <windowsx.h>
-#if defined( _MSC_VER )
-# include <ddraw.h>
-#else
-# include <directx.h>
-#endif
+#include <ddraw.h>
#include "netutils.h"
#include "vout_directx.h"
+/*****************************************************************************
+ * DirectDraw GUIDs.
+ * Defining them here allows us to get rid of the dxguid library during
+ * the linking stage.
+ *****************************************************************************/
+#include <initguid.h>
+DEFINE_GUID( IID_IDirectDraw2, 0xB3A6F3E0,0x2B43,0x11CF,0xA2,0xDE,0x00,0xAA,0x00,0xB9,0x33,0x56 );
+DEFINE_GUID( IID_IDirectDrawSurface3, 0xDA044E00,0x69B2,0x11D0,0xA1,0xD5,0x00,0xAA,0x00,0xB8,0xDF,0xBB );
+
/*****************************************************************************
* Local prototypes.
*****************************************************************************/
static int vout_Probe ( probedata_t *p_data );
-static int vout_Create ( struct vout_thread_s * );
-static int vout_Init ( struct vout_thread_s * );
-static void vout_End ( struct vout_thread_s * );
-static void vout_Destroy ( struct vout_thread_s * );
-static int vout_Manage ( struct vout_thread_s * );
-static void vout_Display ( struct vout_thread_s * );
-static void vout_SetPalette( p_vout_thread_t p_vout, u16 *red, u16 *green,
- u16 *blue, u16 *transp );
+static int vout_Create ( vout_thread_t * );
+static void vout_Destroy ( vout_thread_t * );
+static int vout_Init ( vout_thread_t * );
+static void vout_End ( vout_thread_t * );
+static int vout_Manage ( vout_thread_t * );
+static void vout_Render ( vout_thread_t *, picture_t * );
+static void vout_Display ( vout_thread_t *, picture_t * );
+
+static int NewPictureVec ( vout_thread_t *, picture_t *, int );
+static void FreePictureVec ( vout_thread_t *, picture_t *, int );
+static int UpdatePictureStruct( vout_thread_t *, picture_t *, int );
static int DirectXInitDDraw ( vout_thread_t *p_vout );
-static int DirectXCreateDisplay ( vout_thread_t *p_vout );
-static int DirectXCreateSurface ( vout_thread_t *p_vout );
-static int DirectXCreateClipper ( vout_thread_t *p_vout );
-static int DirectXUpdateOverlay ( vout_thread_t *p_vout );
static void DirectXCloseDDraw ( vout_thread_t *p_vout );
+static int DirectXCreateDisplay ( vout_thread_t *p_vout );
static void DirectXCloseDisplay ( vout_thread_t *p_vout );
-static void DirectXCloseSurface ( vout_thread_t *p_vout );
-static void DirectXKeepAspectRatio( vout_thread_t *p_vout, RECT *coordinates );
+static int DirectXCreateSurface ( vout_thread_t *p_vout,
+ LPDIRECTDRAWSURFACE3 *, int, int );
+static void DirectXCloseSurface ( vout_thread_t *p_vout,
+ LPDIRECTDRAWSURFACE3 );
+static int DirectXCreateClipper ( vout_thread_t *p_vout );
+static void DirectXGetDDrawCaps ( vout_thread_t *p_vout );
+static int DirectXGetSurfaceDesc ( picture_t *p_pic );
/*****************************************************************************
* Functions exported as capabilities. They are declared as static so that
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_render = vout_Render;
p_function_list->functions.vout.pf_display = vout_Display;
- p_function_list->functions.vout.pf_setpalette = vout_SetPalette;
}
/*****************************************************************************
static int vout_Probe( probedata_t *p_data )
{
- if( TestMethod( VOUT_METHOD_VAR, "directx" ) )
- {
- return( 999 );
- }
-
/* Check that at least DirectX5 is installed on the computer */
/* Fixme */
/* Initialisations */
p_vout->p_sys->p_ddobject = NULL;
p_vout->p_sys->p_display = NULL;
- p_vout->p_sys->p_surface = NULL;
+ p_vout->p_sys->p_current_surface = NULL;
p_vout->p_sys->p_clipper = NULL;
p_vout->p_sys->hbrush = NULL;
p_vout->p_sys->hwnd = NULL;
p_vout->p_sys->i_changes = 0;
p_vout->p_sys->b_event_thread_die = 0;
- p_vout->p_sys->b_display_enabled = 0;
+ p_vout->p_sys->b_caps_overlay_clipping = 0;
+ SetRectEmpty( &p_vout->p_sys->rect_display );
+ p_vout->p_sys->b_using_overlay =
+ !main_GetIntVariable( VOUT_NOOVERLAY_VAR, VOUT_NOOVERLAY_DEFAULT );
- p_vout->p_sys->b_cursor = 1; /* TODO should be done with a main_GetInt.. */
+ p_vout->p_sys->b_cursor = 1;
p_vout->p_sys->b_cursor_autohidden = 0;
p_vout->p_sys->i_lastmoved = mdate();
- p_vout->b_fullscreen = main_GetIntVariable( VOUT_FULLSCREEN_VAR,
- VOUT_FULLSCREEN_DEFAULT );
+ /* Set main window's size */
+ if( p_vout->render.i_height * p_vout->render.i_aspect
+ >= p_vout->render.i_width * VOUT_ASPECT_FACTOR )
+ {
+ p_vout->p_sys->i_window_width = p_vout->render.i_height
+ * p_vout->render.i_aspect / VOUT_ASPECT_FACTOR;
+ p_vout->p_sys->i_window_height = p_vout->render.i_height;
+ }
+ else
+ {
+ p_vout->p_sys->i_window_width = p_vout->render.i_width;
+ p_vout->p_sys->i_window_height = p_vout->render.i_width
+ * VOUT_ASPECT_FACTOR / p_vout->render.i_aspect;
+ }
+
#if 0
- p_vout->b_need_render = !main_GetIntVariable( VOUT_OVERLAY_VAR,
- VOUT_OVERLAY_DEFAULT );
-#else
- p_vout->b_need_render = 0; /* default = overlay */
-#endif
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 );
- /* We don't know yet the dimensions of the video so the best guess is to
- * pick the same as the window */
- p_vout->p_sys->i_image_width = p_vout->p_sys->i_window_width;
- p_vout->p_sys->i_image_height = p_vout->p_sys->i_window_height;
+#endif
-
/* Set locks and condition variables */
vlc_mutex_init( &p_vout->p_sys->event_thread_lock );
vlc_cond_init( &p_vout->p_sys->event_thread_wait );
return( 1 );
}
+ intf_WarnMsg( 3, "vout: vout_Create DirectXEventThread running" );
- intf_WarnMsg( 3, "vout : vout_Create DirectXEventThread running" );
/* Initialise DirectDraw */
if( DirectXInitDDraw( p_vout ) )
return ( 1 );
}
+ /* Attach the current thread input queue to the events thread qeue.
+ * This allows us to hide or show the cursor in vout_Manage() */
+ ShowCursor( TRUE ); ShowCursor( FALSE ); /* create input queue */
+ AttachThreadInput( GetCurrentThreadId(),
+ GetWindowThreadProcessId( p_vout->p_sys->hwnd, NULL ),
+ 1 );
+
return( 0 );
}
/*****************************************************************************
* vout_Init: initialize DirectX video thread output method
*****************************************************************************
- *
+ * This function create the directx surfaces needed by the output thread.
+ * It is called at the beginning of the thread.
*****************************************************************************/
static int vout_Init( vout_thread_t *p_vout )
{
+
+ /* Initialize the output structure.
+ * Since DirectDraw can do rescaling for us, stick to the default
+ * coordinates and aspect. */
+ 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;
+
+#define MAX_DIRECTBUFFERS 1
+
+ NewPictureVec( p_vout, p_vout->p_picture, MAX_DIRECTBUFFERS );
+
return( 0 );
}
*****************************************************************************/
static void vout_End( vout_thread_t *p_vout )
{
+ FreePictureVec( p_vout, p_vout->p_picture, I_OUTPUTPICTURES );
return;
}
/*****************************************************************************
* vout_Manage: handle Sys events
*****************************************************************************
- * This function should be called regularly by video output thread. It returns
- * a non null value if an error occured.
+ * This function should be called regularly by the video output thread.
+ * It returns a non null value if an error occured.
*****************************************************************************/
static int vout_Manage( vout_thread_t *p_vout )
{
WINDOWPLACEMENT window_placement;
- extern int b_directx_update_overlay;
/* We used to call the Win32 PeekMessage function here to read the window
* messages. But since window can stay blocked into this function for a
|| p_vout->p_sys->i_changes & VOUT_SCALE_CHANGE)
{
intf_WarnMsg( 3, "vout: vout_Manage Scale Change" );
- if( p_vout->b_need_render )
+ if( !p_vout->p_sys->b_using_overlay )
InvalidateRect( p_vout->p_sys->hwnd, NULL, TRUE );
- if( DirectXUpdateOverlay( p_vout ) )
- /* failed so try again next time */
- PostMessage( p_vout->p_sys->hwnd, WM_CHAR, (WPARAM)'S', 0);
+ else
+ DirectXUpdateOverlay( p_vout );
p_vout->i_changes &= ~VOUT_SCALE_CHANGE;
p_vout->p_sys->i_changes &= ~VOUT_SCALE_CHANGE;
}
* Size Change
*/
if( p_vout->i_changes & VOUT_SIZE_CHANGE
- || p_vout->p_sys->i_changes & VOUT_SIZE_CHANGE
- || b_directx_update_overlay )
+ || p_vout->p_sys->i_changes & VOUT_SIZE_CHANGE )
{
intf_WarnMsg( 3, "vout: vout_Manage Size Change" );
- if( DirectXUpdateOverlay( p_vout ) )
- /* failed so try again next time */
- PostMessage( p_vout->p_sys->hwnd, WM_APP, 0, 0);
+ if( !p_vout->p_sys->b_using_overlay )
+ InvalidateRect( p_vout->p_sys->hwnd, NULL, TRUE );
+ else
+ DirectXUpdateOverlay( p_vout );
p_vout->i_changes &= ~VOUT_SIZE_CHANGE;
p_vout->p_sys->i_changes &= ~VOUT_SIZE_CHANGE;
- b_directx_update_overlay = 0;
- }
-
- /*
- * YUV Change
- */
- if( p_vout->i_changes & VOUT_YUV_CHANGE
- || p_vout->p_sys->i_changes & VOUT_YUV_CHANGE )
- {
- p_vout->b_need_render = ! p_vout->b_need_render;
-
- /* Need to reopen display */
- DirectXCloseSurface( p_vout );
- if( DirectXCreateSurface( p_vout ) )
- {
- intf_ErrMsg( "error: can't reopen display after YUV change" );
- return( 1 );
- }
-
- /* Repaint the window background (needed by the overlay surface) */
- if( !p_vout->b_need_render )
- {
- InvalidateRect( p_vout->p_sys->hwnd, NULL, TRUE );
- p_vout->p_sys->b_display_enabled = 1;
- if( DirectXUpdateOverlay( p_vout ) )
- /* failed so try again next time */
- PostMessage( p_vout->p_sys->hwnd, WM_APP, 0, 0);
- }
- p_vout->i_changes &= ~VOUT_YUV_CHANGE;
- p_vout->p_sys->i_changes &= ~VOUT_YUV_CHANGE;
}
/*
ShowCursor( FALSE );
}
+#if 0
if( p_vout->i_changes & VOUT_CURSOR_CHANGE
|| p_vout->p_sys->i_changes & VOUT_CURSOR_CHANGE )
{
p_vout->i_changes &= ~VOUT_CURSOR_CHANGE;
p_vout->p_sys->i_changes &= ~VOUT_CURSOR_CHANGE;
}
+#endif
+
+ /* Check if the event thread is still running */
+ if( p_vout->p_sys->b_event_thread_die )
+ return 1; /* exit */
return( 0 );
}
/*****************************************************************************
- * vout_SetPalette: sets an 8 bpp palette
- *****************************************************************************
- * This function sets the palette given as an argument. It does not return
- * anything, but could later send information on which colors it was unable
- * to set.
+ * vout_Render: render previously calculated output
*****************************************************************************/
-static void vout_SetPalette( p_vout_thread_t p_vout, u16 *red, u16 *green,
- u16 *blue, u16 *transp)
+static void vout_Render( vout_thread_t *p_vout, picture_t *p_pic )
{
- /* Nothing yet */
- return;
+ ;
}
/*****************************************************************************
* vout_Display: displays previously rendered output
*****************************************************************************
- * This function send the currently rendered image to the display, wait until
- * it is displayed and switch the two rendering buffer, preparing next frame.
+ * This function sends the currently rendered image to the display, wait until
+ * it is displayed and switch the two rendering buffers, preparing next frame.
*****************************************************************************/
-static void vout_Display( vout_thread_t *p_vout )
+static void vout_Display( vout_thread_t *p_vout, picture_t *p_pic )
{
- DDSURFACEDESC ddsd;
- HRESULT dxresult;
+ HRESULT dxresult;
- int i;
- int i_image_width;
- int i_image_height;
+ intf_WarnMsg( 8, "vout: vout_Display" );
if( (p_vout->p_sys->p_display == NULL) )
{
return;
}
- /* if the size of the decoded pictures has changed then we close the
- * video surface (which doesn't have the right size anymore). */
- i_image_width = ( p_vout->p_rendered_pic ) ?
- p_vout->p_rendered_pic->i_width : p_vout->p_sys->i_image_width;
- i_image_height = ( p_vout->p_rendered_pic ) ?
- p_vout->p_rendered_pic->i_height : p_vout->p_sys->i_image_height;
-
- if( p_vout->p_sys->i_image_width != i_image_width
- || p_vout->p_sys->i_image_height != i_image_height )
- {
- intf_WarnMsg( 3, "vout: video surface size changed" );
- p_vout->p_sys->i_image_width = i_image_width;
- p_vout->p_sys->i_image_height = i_image_height;
- DirectXCloseSurface( p_vout );
- }
-
- if( p_vout->b_need_render )
+ if( !p_vout->p_sys->b_using_overlay )
{
- RECT rect_window;
- POINT point_window;
DDBLTFX ddbltfx;
-
- /* Nothing yet */
- if( p_vout->p_sys->p_surface == NULL )
- {
- intf_WarnMsg( 3, "vout: no video surface, open one..." );
- if( DirectXCreateSurface( p_vout ) )
- {
- intf_WarnMsg( 3, "vout: cannot open a new video surface !!" );
- return;
- }
- /* Display the surface */
- p_vout->p_sys->b_display_enabled = 1;
- }
-
- /* Now get the coordinates of the window. We don't actually want the
- * window coordinates but these of the usable surface inside the window
- * By specification GetClientRect will always set rect_window.left and
- * rect_window.top to 0 because the Client area is always relative to
- * the container window */
- GetClientRect(p_vout->p_sys->hwnd, &rect_window);
-
- point_window.x = 0;
- point_window.y = 0;
- ClientToScreen(p_vout->p_sys->hwnd, &point_window);
- rect_window.left = point_window.x;
- rect_window.top = point_window.y;
-
- point_window.x = rect_window.right;
- point_window.y = rect_window.bottom;
- ClientToScreen(p_vout->p_sys->hwnd, &point_window);
- rect_window.right = point_window.x;
- rect_window.bottom = point_window.y;
-
- /* We want to keep the aspect ratio of the video */
-#if 0
- if( p_vout->b_scale )
- {
- DirectXKeepAspectRatio( p_vout, &rect_window );
- }
-#endif
/* We ask for the "NOTEARING" option */
memset( &ddbltfx, 0, sizeof(DDBLTFX) );
ddbltfx.dwSize = sizeof(DDBLTFX);
- ddbltfx.dwDDFX = DDBLTFX_NOTEARING;
+ ddbltfx.dwDDFX = DDBLTFX_NOTEARING | DDBLT_ASYNC;
/* Blit video surface to display */
dxresult = IDirectDrawSurface3_Blt(p_vout->p_sys->p_display,
- &rect_window,
- p_vout->p_sys->p_surface,
+ &p_vout->p_sys->rect_dest,
+ p_pic->p_sys->p_surface,
NULL,
0, &ddbltfx );
if( dxresult != DD_OK )
}
}
- else
+ else /* using overlay */
{
- /*
- * p_vout->p_rendered_pic->p_y/u/v contains the YUV buffers to
- * render
- */
- /* TODO: support for streams other than 4:2:0 */
- if( p_vout->p_sys->p_surface == NULL )
- {
- intf_WarnMsg( 3, "vout: no video surface, open one..." );
- if( DirectXCreateSurface( p_vout ) )
- {
- intf_WarnMsg( 3, "vout: cannot open a new video surface !!" );
- return;
- }
- }
+ /* Flip the overlay buffers */
+ //dxresult = IDirectDrawSurface3_Flip(p_pic->p_sys->p_surface, NULL, 0 );
- /* Lock the overlay surface */
- memset( &ddsd, 0, sizeof( DDSURFACEDESC ));
- ddsd.dwSize = sizeof(DDSURFACEDESC);
- dxresult = IDirectDrawSurface3_Lock(p_vout->p_sys->p_surface, NULL,
- &ddsd, DDLOCK_NOSYSLOCK, NULL);
- if ( dxresult == DDERR_SURFACELOST )
+ if( !DirectXGetSurfaceDesc( p_pic ) )
{
- /* Your surface can be lost (thanks to windows) so be sure
- * to check this and restore it if needed */
- dxresult = IDirectDrawSurface3_Restore( p_vout->p_sys->p_surface );
- dxresult = IDirectDrawSurface3_Lock( p_vout->p_sys->p_surface,
- NULL, &ddsd, DDLOCK_NOSYSLOCK
- | DDLOCK_WAIT, NULL);
- }
- if( dxresult != DD_OK )
- {
- intf_WarnMsg( 3, "vout: could not lock the surface" );
+ /* AAARRGG */
+ intf_ErrMsg( "vout error: vout_Display cannot get surface desc" );
return;
}
- /* Now we can do the actual image copy.
- * The copy has to be done line by line because of the special case
- * when the Pitch does not equal the width of the picture */
- for( i=0; i < ddsd.dwHeight/2; i++)
- {
-#ifdef NONAMELESSUNION
- /* copy Y, we copy two lines at once */
- memcpy(ddsd.lpSurface + i*2*ddsd.u1.lPitch,
- p_vout->p_rendered_pic->p_y + i*2*i_image_width,
- i_image_width);
- memcpy(ddsd.lpSurface + (i*2+1)*ddsd.u1.lPitch,
- p_vout->p_rendered_pic->p_y + (i*2+1)*i_image_width,
- i_image_width);
- /* then V */
- memcpy((ddsd.lpSurface + ddsd.dwHeight * ddsd.u1.lPitch)
- + i * ddsd.u1.lPitch/2,
- p_vout->p_rendered_pic->p_v + i*i_image_width/2,
- i_image_width/2);
- /* and U */
- memcpy((ddsd.lpSurface + ddsd.dwHeight * ddsd.u1.lPitch)
- + (ddsd.dwHeight * ddsd.u1.lPitch/4)
- + i * ddsd.u1.lPitch/2,
- p_vout->p_rendered_pic->p_u + i*i_image_width/2,
- i_image_width/2);
-#else
- /* copy Y, we copy two lines at once */
- memcpy((u8*)ddsd.lpSurface + i*2*ddsd.lPitch,
- p_vout->p_rendered_pic->p_y + i*2*i_image_width,
- i_image_width);
- memcpy((u8*)ddsd.lpSurface + (i*2+1)*ddsd.lPitch,
- p_vout->p_rendered_pic->p_y + (i*2+1)*i_image_width,
- i_image_width);
- /* then V */
- memcpy(((u8*)ddsd.lpSurface + ddsd.dwHeight * ddsd.lPitch)
- + i * ddsd.lPitch/2,
- p_vout->p_rendered_pic->p_v + i*i_image_width/2,
- i_image_width/2);
- /* and U */
- memcpy(((u8*)ddsd.lpSurface + ddsd.dwHeight * ddsd.lPitch)
- + (ddsd.dwHeight * ddsd.lPitch/4)
- + i * ddsd.lPitch/2,
- p_vout->p_rendered_pic->p_u + i*i_image_width/2,
- i_image_width/2);
-#endif /* NONAMELESSUNION */
-
- }
-
- /* Unlock the Surface */
- dxresult = IDirectDrawSurface3_Unlock(p_vout->p_sys->p_surface,
- ddsd.lpSurface );
-
- /* If display not enabled yet then enable */
- if( !p_vout->p_sys->b_display_enabled )
+ if( !UpdatePictureStruct( p_vout, p_pic, p_vout->output.i_chroma ) )
{
- p_vout->p_sys->b_display_enabled = 1;
- DirectXUpdateOverlay( p_vout );
+ /* AAARRGG */
+ intf_ErrMsg( "vout error: vout_Display unvalid pic chroma" );
+ return;
}
+ /* set currently displayed pic !!! faux*/
+ p_vout->p_sys->p_current_surface = p_pic->p_sys->p_surface;
}
- /* The first time this function is called it enables the display */
- p_vout->p_sys->b_display_enabled = 1;
-
+ intf_WarnMsg( 8, "vout: vout_Display End" );
}
IDirectDraw_Release( p_ddobject );
}
+ /* Probe the capabilities of the hardware */
+ DirectXGetDDrawCaps( p_vout );
+
intf_WarnMsg( 3, "vout: End DirectXInitDDraw" );
return( 0 );
}
HRESULT dxresult;
DDSURFACEDESC ddsd;
LPDIRECTDRAWSURFACE p_display;
- DDPIXELFORMAT ddpfPixelFormat;
+ DDPIXELFORMAT pixel_format;
intf_WarnMsg( 3, "vout: DirectXCreateDisplay" );
- /* Now create the primary surface. This surface is what you actually see
+ /* Now get the primary surface. This surface is what you actually see
* on your screen */
memset( &ddsd, 0, sizeof( DDSURFACEDESC ));
ddsd.dwSize = sizeof(DDSURFACEDESC);
&p_display, NULL );
if( dxresult != DD_OK )
{
- intf_ErrMsg( "vout error: can't create direct draw primary surface." );
+ intf_ErrMsg( "vout error: can't get direct draw primary surface." );
p_vout->p_sys->p_display = NULL;
return( 1 );
}
}
- /* We need to fill in some information for the video output thread.
- * We do this here because it must be done before the video_output
- * thread enters its main loop - and DirectXCreateSurface can be called
- * after that ! */
- ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT);
- IDirectDrawSurface3_GetPixelFormat( p_vout->p_sys->p_display,
- &ddpfPixelFormat );
-#ifdef NONAMELESSUNION
- p_vout->i_screen_depth = ddpfPixelFormat.u1.dwRGBBitCount;
- p_vout->i_bytes_per_pixel = ddpfPixelFormat.u1.dwRGBBitCount/8;
-
- p_vout->i_red_mask = ddpfPixelFormat.u2.dwRBitMask;
- p_vout->i_green_mask = ddpfPixelFormat.u3.dwGBitMask;
- p_vout->i_blue_mask = ddpfPixelFormat.u4.dwBBitMask;
-#else
- p_vout->i_screen_depth = ddpfPixelFormat.dwRGBBitCount;
- p_vout->i_bytes_per_pixel = ddpfPixelFormat.dwRGBBitCount/8;
-
- p_vout->i_red_mask = ddpfPixelFormat.dwRBitMask;
- p_vout->i_green_mask = ddpfPixelFormat.dwGBitMask;
- p_vout->i_blue_mask = ddpfPixelFormat.dwBBitMask;
-#endif /* NONAMELESSUNION */
-
- /* Create a video surface. This function will try to create an
- * YUV overlay first and if it can't it will create a simple RGB surface */
- if( DirectXCreateSurface( p_vout ) )
+ /* The clipper will be used only in non-overlay mode */
+ DirectXCreateClipper( p_vout );
+
+
+#if 1
+ /* compute the colorkey pixel value from the RGB value we've got */
+ memset( &pixel_format, 0, sizeof( DDPIXELFORMAT ));
+ pixel_format.dwSize = sizeof( DDPIXELFORMAT );
+ dxresult = IDirectDrawSurface3_GetPixelFormat( p_vout->p_sys->p_display,
+ &pixel_format );
+ if( dxresult != DD_OK )
+ intf_WarnMsg( 3, "vout: DirectXUpdateOverlay GetPixelFormat failed" );
+ p_vout->p_sys->i_colorkey = (DWORD)((( p_vout->p_sys->i_rgb_colorkey
+ * pixel_format.dwRBitMask) / 255)
+ & pixel_format.dwRBitMask);
+#endif
+
+ return( 0 );
+}
+
+
+/*****************************************************************************
+ * DirectXCreateClipper: Create a clipper that will be used when blitting the
+ * RGB surface to the main display.
+ *****************************************************************************
+ * This clipper prevents us to modify by mistake anything on the screen
+ * which doesn't belong to our window. For example when a part of our video
+ * window is hidden by another window.
+ *****************************************************************************/
+static int DirectXCreateClipper( vout_thread_t *p_vout )
+{
+ HRESULT dxresult;
+
+ intf_WarnMsg( 3, "vout: DirectXCreateClipper" );
+
+ /* Create the clipper */
+ dxresult = IDirectDraw2_CreateClipper( p_vout->p_sys->p_ddobject, 0,
+ &p_vout->p_sys->p_clipper, NULL );
+ if( dxresult != DD_OK )
{
- intf_ErrMsg( "vout error: can't create a video surface." );
- IDirectDrawSurface3_Release( p_vout->p_sys->p_display );
- p_vout->p_sys->p_display = NULL;
+ intf_WarnMsg( 3, "vout: DirectXCreateClipper can't create clipper." );
+ p_vout->p_sys->p_clipper = NULL;
return( 1 );
}
-
+
+ /* associate the clipper to the window */
+ dxresult = IDirectDrawClipper_SetHWnd(p_vout->p_sys->p_clipper, 0,
+ p_vout->p_sys->hwnd);
+ if( dxresult != DD_OK )
+ {
+ intf_WarnMsg( 3,
+ "vout: DirectXCreateClipper can't attach clipper to window." );
+ IDirectDrawSurface_Release( p_vout->p_sys->p_clipper );
+ p_vout->p_sys->p_clipper = NULL;
+ return( 1 );
+ }
+
+ /* associate the clipper with the surface */
+ dxresult = IDirectDrawSurface_SetClipper(p_vout->p_sys->p_display,
+ p_vout->p_sys->p_clipper);
+ if( dxresult != DD_OK )
+ {
+ intf_WarnMsg( 3,
+ "vout: DirectXCreateClipper can't attach clipper to surface." );
+ IDirectDrawSurface_Release( p_vout->p_sys->p_clipper );
+ p_vout->p_sys->p_clipper = NULL;
+ return( 1 );
+ }
+
return( 0 );
}
* DirectXCreateSurface: create an YUV overlay or RGB surface for the video.
*****************************************************************************
* The best method of display is with an YUV overlay because the YUV->RGB
- * conversion is done in hardware, so we'll try to create this surface first.
- * If we fail, we'll try to create a plain RGB surface.
+ * conversion is done in hardware.
+ * You can also create a plain RGB surface.
* ( Maybe we could also try an RGB overlay surface, which could have hardware
* scaling and which would also be faster in window mode because you don't
* need to do any blitting to the main display...)
*****************************************************************************/
-static int DirectXCreateSurface( vout_thread_t *p_vout )
+static int DirectXCreateSurface( vout_thread_t *p_vout,
+ LPDIRECTDRAWSURFACE3 *pp_surface_final,
+ int i_chroma, int b_overlay )
{
HRESULT dxresult;
- DDSURFACEDESC ddsd;
LPDIRECTDRAWSURFACE p_surface;
- DDCAPS ddcaps;
+ DDSURFACEDESC ddsd;
intf_WarnMsg( 3, "vout: DirectXCreateSurface" );
- /* Disable display */
- p_vout->p_sys->b_display_enabled = 0;
-
-#if 1
- /* Probe the capabilities of the hardware */
- /* This is just an indication of whether or not we'll support overlay,
- * but with this test we don't know if we support YUV overlay */
- memset( &ddcaps, 0, sizeof( DDCAPS ));
- ddcaps.dwSize = sizeof(DDCAPS);
- dxresult = IDirectDraw2_GetCaps( p_vout->p_sys->p_ddobject,
- &ddcaps, NULL );
- if(dxresult != DD_OK )
- {
- intf_WarnMsg( 3,"vout error: can't get caps." );
- }
- else
- {
- BOOL bHasOverlay, bHasColorKey, bCanStretch;
-
- /* Determine if the hardware supports overlay surfaces */
- bHasOverlay = ((ddcaps.dwCaps & DDCAPS_OVERLAY) ==
- DDCAPS_OVERLAY) ? TRUE : FALSE;
- /* Determine if the hardware supports colorkeying */
- bHasColorKey = ((ddcaps.dwCaps & DDCAPS_COLORKEY) ==
- DDCAPS_COLORKEY) ? TRUE : FALSE;
- /* Determine if the hardware supports scaling of the overlay surface */
- bCanStretch = ((ddcaps.dwCaps & DDCAPS_OVERLAYSTRETCH) ==
- DDCAPS_OVERLAYSTRETCH) ? TRUE : FALSE;
- intf_WarnMsg( 3, "vout: Dx Caps: overlay=%i colorkey=%i stretch=%i",
- bHasOverlay, bHasColorKey, bCanStretch );
-
-#if 0
- if( !bHasOverlay ) p_vout->b_need_render = 1;
-#endif
- }
-#endif
-
-
/* Create the video surface */
- if( !p_vout->b_need_render )
+ if( b_overlay )
{
/* Now try to create the YUV overlay surface.
* This overlay will be displayed on top of the primary surface.
ddsd.dwSize = sizeof(DDSURFACEDESC);
ddsd.ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT);
ddsd.ddpfPixelFormat.dwFlags = DDPF_FOURCC;
- ddsd.ddpfPixelFormat.dwFourCC = mmioFOURCC('Y','V','1','2');
-#ifdef NONAMELESSUNION
- ddsd.ddpfPixelFormat.u1.dwYUVBitCount = 16;
-#else
- ddsd.ddpfPixelFormat.dwYUVBitCount = 16;
-#endif
+ ddsd.ddpfPixelFormat.dwFourCC = i_chroma;
ddsd.dwFlags = DDSD_CAPS |
DDSD_HEIGHT |
DDSD_WIDTH |
+ //DDSD_BACKBUFFERCOUNT |
DDSD_PIXELFORMAT;
- ddsd.ddsCaps.dwCaps = DDSCAPS_OVERLAY | DDSCAPS_VIDEOMEMORY;
- ddsd.dwHeight = p_vout->p_sys->i_image_height;
- ddsd.dwWidth = p_vout->p_sys->i_image_width;
- ddsd.dwBackBufferCount = 1; /* One back buffer */
+ ddsd.ddsCaps.dwCaps = DDSCAPS_OVERLAY |
+ // DDSCAPS_COMPLEX |
+ //DDSCAPS_FLIP |
+ DDSCAPS_VIDEOMEMORY;
+ ddsd.dwHeight = p_vout->render.i_height;
+ ddsd.dwWidth = p_vout->render.i_width;
+ ddsd.dwBackBufferCount = 0; /* One back buffer */
dxresult = IDirectDraw2_CreateSurface( p_vout->p_sys->p_ddobject,
- &ddsd, &p_surface, NULL );
+ &ddsd,
+ &p_surface, NULL );
if( dxresult == DD_OK )
{
intf_WarnMsg( 3,"vout: DirectX YUV overlay created successfully" );
else
{
intf_ErrMsg( "vout error: can't create YUV overlay surface." );
- p_vout->b_need_render = 1;
+ *pp_surface_final = NULL;
+ return 0;
}
}
- if( p_vout->b_need_render )
+ if( !b_overlay )
{
/* Now try to create a plain RGB surface. */
- memset( &ddsd, 0, sizeof( DDSURFACEDESC ));
+ memset( &ddsd, 0, sizeof( DDSURFACEDESC ) );
ddsd.dwSize = sizeof(DDSURFACEDESC);
ddsd.dwFlags = DDSD_HEIGHT |
DDSD_WIDTH |
DDSD_CAPS;
- ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
- ddsd.dwHeight = p_vout->p_sys->i_image_height;
- ddsd.dwWidth = p_vout->p_sys->i_image_width;
+ ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN |
+ DDSCAPS_SYSTEMMEMORY;
+ ddsd.dwHeight = p_vout->render.i_height;
+ ddsd.dwWidth = p_vout->render.i_width;
dxresult = IDirectDraw2_CreateSurface( p_vout->p_sys->p_ddobject,
- &ddsd, &p_surface, NULL );
+ &ddsd,
+ &p_surface, NULL );
if( dxresult == DD_OK )
{
intf_WarnMsg( 3,"vout: DirectX RGB surface created successfully" );
else
{
intf_ErrMsg( "vout error: can't create RGB surface." );
- p_vout->p_sys->p_surface = NULL;
- return( 1 );
+ *pp_surface_final = NULL;
+ return 0;
}
}
/* Now that the surface is created, try to get a newer DirectX interface */
dxresult = IDirectDrawSurface_QueryInterface( p_surface,
- &IID_IDirectDrawSurface3,
- (LPVOID *)&p_vout->p_sys->p_surface );
+ &IID_IDirectDrawSurface3,
+ (LPVOID *)pp_surface_final );
+ IDirectDrawSurface_Release( p_surface ); /* Release the old interface */
if ( dxresult != DD_OK )
{
intf_ErrMsg( "vout error: can't get IDirectDrawSurface3 interface." );
- IDirectDrawSurface_Release( p_surface );
- p_vout->p_sys->p_surface = NULL;
- return( 1 );
- }
- else
- {
- /* Release the old interface */
- IDirectDrawSurface_Release( p_surface );
- }
-
- if( !p_vout->b_need_render )
- {
- /* Hide the overlay for now */
- IDirectDrawSurface3_UpdateOverlay(p_vout->p_sys->p_surface,
- NULL,
- p_vout->p_sys->p_display,
- NULL,
- DDOVER_HIDE,
- NULL);
+ *pp_surface_final = NULL;
+ return 0;
}
- else
- {
- DirectXCreateClipper( p_vout );
- }
-
-
- /* From now on, do some initialisation for video_output */
-
- /* if we want a valid pointer to the surface memory, we must lock
- * the surface */
-
- memset( &ddsd, 0, sizeof( DDSURFACEDESC ));
- ddsd.dwSize = sizeof(DDSURFACEDESC);
- dxresult = IDirectDrawSurface3_Lock( p_vout->p_sys->p_surface, NULL, &ddsd,
- DDLOCK_NOSYSLOCK | DDLOCK_WAIT, NULL);
- if ( dxresult == DDERR_SURFACELOST )
- {
- /* Your surface can be lost so be sure
- * to check this and restore it if needed */
- dxresult = IDirectDrawSurface3_Restore( p_vout->p_sys->p_surface );
- dxresult = IDirectDrawSurface3_Lock( p_vout->p_sys->p_surface,
- NULL, &ddsd, DDLOCK_NOSYSLOCK
- | DDLOCK_WAIT, NULL);
- }
- if( dxresult != DD_OK )
- {
- intf_ErrMsg( "vout: DirectXCreateDisplay could not lock the surface" );
- return( 1 );
- }
-
- /* Set the pointer to the surface memory */
- p_vout->p_sys->p_directx_buf[ 0 ] = ddsd.lpSurface;
- /* back buffer, none for now */
- p_vout->p_sys->p_directx_buf[ 1 ] = ddsd.lpSurface;
-
- /* Set thread information */
- p_vout->i_width = ddsd.dwWidth;
- p_vout->i_height = ddsd.dwHeight;
-#ifdef NONAMELESSUNION
- p_vout->i_bytes_per_line = ddsd.u1.lPitch;
-#else
- p_vout->i_bytes_per_line = ddsd.lPitch;
-#endif /* NONAMELESSUNION */
-
-
- if( p_vout->b_need_render )
- {
- /* For an RGB surface we need to fill in some more info */
-#ifdef NONAMELESSUNION
- p_vout->i_screen_depth = ddsd.ddpfPixelFormat.u1.dwRGBBitCount;
- p_vout->i_bytes_per_pixel = ddsd.ddpfPixelFormat.u1.dwRGBBitCount/8;
-
- p_vout->i_red_mask = ddsd.ddpfPixelFormat.u2.dwRBitMask;
- p_vout->i_green_mask = ddsd.ddpfPixelFormat.u3.dwGBitMask;
- p_vout->i_blue_mask = ddsd.ddpfPixelFormat.u4.dwBBitMask;
-#else
- p_vout->i_screen_depth = ddsd.ddpfPixelFormat.dwRGBBitCount;
- p_vout->i_bytes_per_pixel = ddsd.ddpfPixelFormat.dwRGBBitCount/8;
-
- p_vout->i_red_mask = ddsd.ddpfPixelFormat.dwRBitMask;
- p_vout->i_green_mask = ddsd.ddpfPixelFormat.dwGBitMask;
- p_vout->i_blue_mask = ddsd.ddpfPixelFormat.dwBBitMask;
-
-#endif /* NONAMELESSUNION */
- }
-
- /* Unlock the Surface */
- dxresult = IDirectDrawSurface3_Unlock(p_vout->p_sys->p_surface,
- ddsd.lpSurface );
-
- /* Set and initialize buffers */
- p_vout->pf_setbuffers( p_vout, p_vout->p_sys->p_directx_buf[ 0 ],
- p_vout->p_sys->p_directx_buf[ 1 ] );
-
- return ( 0 );
-}
-
-
-/*****************************************************************************
- * DirectXCreateClipper: Create a clipper that will be used when blitting the
- * RGB surface to the main display.
- *****************************************************************************
- * This clipper prevents us to modify by mistake anything on the screen
- * which doesn't belong to our window. For example when a part of our video
- * window is hidden by another window.
- *****************************************************************************/
-static int DirectXCreateClipper( vout_thread_t *p_vout )
-{
- HRESULT dxresult;
-
- intf_WarnMsg( 3, "vout: DirectXCreateClipper" );
-
- /* Create the clipper */
- dxresult = IDirectDraw2_CreateClipper( p_vout->p_sys->p_ddobject, 0,
- &p_vout->p_sys->p_clipper, NULL );
- if( dxresult != DD_OK )
- {
- intf_WarnMsg( 3, "vout: DirectXCreateClipper can't create clipper." );
- IDirectDrawSurface_Release( p_vout->p_sys->p_clipper );
- p_vout->p_sys->p_clipper = NULL;
- return( 1 );
- }
-
- /* associate the clipper to the window */
- dxresult = IDirectDrawClipper_SetHWnd(p_vout->p_sys->p_clipper, 0,
- p_vout->p_sys->hwnd);
- if( dxresult != DD_OK )
- {
- intf_WarnMsg( 3,
- "vout: DirectXCreateClipper can't attach clipper to window." );
- IDirectDrawSurface_Release( p_vout->p_sys->p_clipper );
- p_vout->p_sys->p_clipper = NULL;
- return( 1 );
- }
-
- /* associate the clipper with the surface */
- dxresult = IDirectDrawSurface_SetClipper(p_vout->p_sys->p_display,
- p_vout->p_sys->p_clipper);
- if( dxresult != DD_OK )
- {
- intf_WarnMsg( 3,
- "vout: DirectXCreateClipper can't attach clipper to surface." );
- IDirectDrawSurface_Release( p_vout->p_sys->p_clipper );
- p_vout->p_sys->p_clipper = NULL;
- return( 1 );
- }
-
- return( 0 );
+ return 1;
}
* Ususally the overlay is moved by the user and thus, by a move or resize
* event (in vout_Manage).
*****************************************************************************/
-static int DirectXUpdateOverlay( vout_thread_t *p_vout )
+void DirectXUpdateOverlay( vout_thread_t *p_vout )
{
DDOVERLAYFX ddofx;
- RECT rect_window, rect_window_backup, rect_image;
- POINT point_window;
DWORD dwFlags;
HRESULT dxresult;
- DWORD dw_colorkey;
- DDPIXELFORMAT pixel_format;
- DDSURFACEDESC ddsd;
-
- if( p_vout->p_sys->p_surface == NULL || p_vout->b_need_render )
- {
- intf_WarnMsg( 3, "vout: DirectXUpdateOverlay no overlay !!" );
- return( 0 );
- }
- if( !p_vout->p_rendered_pic )
+ if( p_vout->p_sys->p_current_surface == NULL ||
+ !p_vout->p_sys->b_using_overlay )
{
- intf_WarnMsg( 3, "vout: DirectXUpdateOverlay p_rendered_pic=NULL !" );
- return( 1 );
- }
-
- if( !p_vout->p_sys->b_display_enabled )
- {
- return( 0 );
- }
-
- /* Now get the coordinates of the window. We don't actually want the
- * window coordinates but these of the usable surface inside the window.
- * By specification GetClientRect will always set rect_window.left and
- * rect_window.top to 0 because the Client area is always relative to the
- * container window */
- GetClientRect(p_vout->p_sys->hwnd, &rect_window);
-
- point_window.x = 0;
- point_window.y = 0;
- ClientToScreen(p_vout->p_sys->hwnd, &point_window);
- rect_window.left = point_window.x;
- rect_window.top = point_window.y;
-
- point_window.x = rect_window.right;
- point_window.y = rect_window.bottom;
- ClientToScreen(p_vout->p_sys->hwnd, &point_window);
- rect_window.right = point_window.x;
- rect_window.bottom = point_window.y;
-
-
- /* We want to keep the aspect ratio of the video */
- if( p_vout->b_scale )
- {
- DirectXKeepAspectRatio( p_vout, &rect_window );
+ intf_WarnMsg( 5, "vout: DirectXUpdateOverlay no overlay !!" );
+ return;
}
- /* It seems we can't feed the UpdateOverlay directdraw function with
- * negative values so we have to clip the computed rectangles */
- memset( &ddsd, 0, sizeof( DDSURFACEDESC ));
- ddsd.dwSize = sizeof(DDSURFACEDESC);
- ddsd.dwFlags = DDSD_HEIGHT | DDSD_WIDTH;
- IDirectDraw2_GetDisplayMode( p_vout->p_sys->p_ddobject, &ddsd );
-
- rect_window_backup = rect_window;
-
- /* Clip the destination window */
- rect_window.left = (rect_window.left < 0) ? 0 : rect_window.left;
- rect_window.right = (rect_window.right < 0) ? 0 : rect_window.right;
- rect_window.top = (rect_window.top < 0) ? 0 : rect_window.top;
- rect_window.bottom = (rect_window.bottom < 0) ? 0 : rect_window.bottom;
-
- rect_window.left = (rect_window.left > ddsd.dwWidth) ? ddsd.dwWidth
- : rect_window.left;
- rect_window.right = (rect_window.right > ddsd.dwWidth) ? ddsd.dwWidth
- : rect_window.right;
- rect_window.top = (rect_window.top > ddsd.dwHeight) ? ddsd.dwHeight
- : rect_window.top;
- rect_window.bottom = (rect_window.bottom > ddsd.dwHeight) ? ddsd.dwHeight
- : rect_window.bottom;
-
- intf_WarnMsg( 3, "vout: DirectXUpdateOverlay window coords: %i,%i,%i,%i",
- rect_window.left, rect_window.top,
- rect_window.right, rect_window.bottom);
-
- /* the 2 following lines are to fix a bug when click on Windows desktop */
- if( (rect_window.right-rect_window.left)==0 ||
- (rect_window.bottom-rect_window.top)==0 ) return 0;
-
- /* Clip the source image */
- rect_image.left = ( rect_window.left == rect_window_backup.left ) ? 0
- : labs(rect_window_backup.left - rect_window.left) *
- p_vout->p_rendered_pic->i_width /
- (rect_window_backup.right - rect_window_backup.left);
- rect_image.right = ( rect_window.right == rect_window_backup.right ) ?
- p_vout->p_rendered_pic->i_width
- : p_vout->p_rendered_pic->i_width -
- labs(rect_window_backup.right - rect_window.right) *
- p_vout->p_rendered_pic->i_width /
- (rect_window_backup.right - rect_window_backup.left);
- rect_image.top = ( rect_window.top == rect_window_backup.top ) ? 0
- : labs(rect_window_backup.top - rect_window.top) *
- p_vout->p_rendered_pic->i_height /
- (rect_window_backup.bottom - rect_window_backup.top);
- rect_image.bottom = ( rect_window.bottom == rect_window_backup.bottom ) ?
- p_vout->p_rendered_pic->i_height
- : p_vout->p_rendered_pic->i_height -
- labs(rect_window_backup.bottom - rect_window.bottom) *
- p_vout->p_rendered_pic->i_height /
- (rect_window_backup.bottom - rect_window_backup.top);
-
- intf_WarnMsg( 3, "vout: DirectXUpdateOverlay image coords: %i,%i,%i,%i",
- rect_image.left, rect_image.top,
- rect_image.right, rect_image.bottom);
-
- /* compute the colorkey pixel value from the RGB value we've got */
- memset( &pixel_format, 0, sizeof( DDPIXELFORMAT ));
- pixel_format.dwSize = sizeof( DDPIXELFORMAT );
- dxresult = IDirectDrawSurface3_GetPixelFormat( p_vout->p_sys->p_display,
- &pixel_format );
- if( dxresult != DD_OK )
- intf_WarnMsg( 3, "vout: DirectXUpdateOverlay GetPixelFormat failed" );
- dw_colorkey = (DWORD)p_vout->p_sys->i_colorkey;
-#ifdef NONAMELESSUNION
- dw_colorkey = (DWORD)((( dw_colorkey * pixel_format.u2.dwRBitMask) / 255)
- & pixel_format.u2.dwRBitMask);
-#else
- dw_colorkey = (DWORD)((( dw_colorkey * pixel_format.dwRBitMask) / 255)
- & pixel_format.dwRBitMask);
-#endif
+ /* The new window dimensions should already have been computed by the
+ * caller of this function */
/* Position and show the overlay */
memset(&ddofx, 0, sizeof(DDOVERLAYFX));
ddofx.dwSize = sizeof(DDOVERLAYFX);
- ddofx.dckDestColorkey.dwColorSpaceLowValue = dw_colorkey;
- ddofx.dckDestColorkey.dwColorSpaceHighValue = dw_colorkey;
-
- dwFlags = DDOVER_KEYDESTOVERRIDE | DDOVER_SHOW;
-
- dxresult = IDirectDrawSurface3_UpdateOverlay(p_vout->p_sys->p_surface,
- &rect_image,
- p_vout->p_sys->p_display,
- &rect_window,
- dwFlags,
- &ddofx);
+ ddofx.dckDestColorkey.dwColorSpaceLowValue = p_vout->p_sys->i_colorkey;
+ ddofx.dckDestColorkey.dwColorSpaceHighValue = p_vout->p_sys->i_colorkey;
+
+ dwFlags = DDOVER_SHOW;
+ if( !p_vout->p_sys->b_caps_overlay_clipping )
+ dwFlags |= DDOVER_KEYDESTOVERRIDE;
+
+ dxresult = IDirectDrawSurface3_UpdateOverlay(
+ p_vout->p_sys->p_current_surface,
+ &p_vout->p_sys->rect_src_clipped,
+ p_vout->p_sys->p_display,
+ &p_vout->p_sys->rect_dest_clipped,
+ dwFlags,
+ &ddofx );
if(dxresult != DD_OK)
{
intf_WarnMsg( 3,
"vout: DirectXUpdateOverlay can't move or resize overlay" );
}
- return ( 0 );
}
/*****************************************************************************
static void DirectXCloseDisplay( vout_thread_t *p_vout )
{
intf_WarnMsg( 3, "vout: DirectXCloseDisplay" );
- if( p_vout->p_sys->p_display != NULL )
+
+ if( p_vout->p_sys->p_clipper != NULL )
{
- DirectXCloseSurface( p_vout );
+ intf_WarnMsg( 3, "vout: DirectXCloseDisplay clipper" );
+ IDirectDraw2_Release( p_vout->p_sys->p_clipper );
+ p_vout->p_sys->p_clipper = NULL;
+ }
+ if( p_vout->p_sys->p_display != NULL )
+ {
intf_WarnMsg( 3, "vout: DirectXCloseDisplay display" );
IDirectDraw2_Release( p_vout->p_sys->p_display );
p_vout->p_sys->p_display = NULL;
/*****************************************************************************
* DirectXCloseSurface: close the YUV overlay or RGB surface.
*****************************************************************************
- * This function returns all resources allocated by the surface.
- * We also call this function when the decoded picture change its dimensions
- * (in that case we close the overlay surface and reopen another with the
- * right dimensions).
+ * This function returns all resources allocated for the surface.
*****************************************************************************/
-static void DirectXCloseSurface( vout_thread_t *p_vout )
+static void DirectXCloseSurface( vout_thread_t *p_vout,
+ LPDIRECTDRAWSURFACE3 p_surface )
{
intf_WarnMsg( 3, "vout: DirectXCloseSurface" );
- if( p_vout->p_sys->p_surface != NULL )
+ if( p_surface != NULL )
{
- intf_WarnMsg( 3, "vout: DirectXCloseSurface surface" );
- IDirectDraw2_Release( p_vout->p_sys->p_surface );
- p_vout->p_sys->p_surface = NULL;
+ IDirectDraw2_Release( p_surface );
}
+}
- if( p_vout->p_sys->p_clipper != NULL )
+/*****************************************************************************
+ * NewPictureVec: allocate a vector of identical pictures
+ *****************************************************************************
+ * Returns 0 on success, -1 otherwise
+ *****************************************************************************/
+static int NewPictureVec( vout_thread_t *p_vout, picture_t *p_pic,
+ int i_num_pics )
+{
+ int i;
+ LPDIRECTDRAWSURFACE3 p_surface;
+
+#if 0
+ /* We couldn't use an YUV overlay so we need to indicate to video_output
+ * which format we are falling back to */
+ switch( )
{
- intf_WarnMsg( 3, "vout: DirectXCloseSurface clipper" );
- IDirectDraw2_Release( p_vout->p_sys->p_clipper );
- p_vout->p_sys->p_clipper = NULL;
+ case 8: /* FIXME: set the palette */
+ p_vout->output.i_chroma = FOURCC_BI_RGB; break;
+ case 15:
+ p_vout->output.i_chroma = FOURCC_RV15; break;
+ case 16:
+ p_vout->output.i_chroma = FOURCC_RV16; break;
+ case 24:
+ p_vout->output.i_chroma = FOURCC_BI_BITFIELDS; break;
+ case 32:
+ p_vout->output.i_chroma = FOURCC_BI_BITFIELDS; break;
+ default:
+ intf_ErrMsg( "vout error: unknown screen depth" );
+ return( 0 );
+ }
+#endif
+
+ intf_WarnMsg( 3, "vout: NewPictureVec" );
+
+ I_OUTPUTPICTURES = 0;
+
+ /* chroma asked for */
+ p_vout->output.i_chroma = p_vout->render.i_chroma;
+
+ /* hack */
+ if( p_vout->render.i_chroma == FOURCC_I420 )
+ p_vout->output.i_chroma = FOURCC_YV12;
+
+ /* First we try to create an overlay surface.
+ * It looks like with most hardware it's not possible to create several
+ * overlay surfaces, and even if it was I bet it would be slower anyway to
+ * use them as direct buffers because they usually reside in video memory
+ * which is quite slow.
+ * So the overlay surface (with a back-buffer) that we create won't be used
+ * to decode directly into it but instead picture buffers in system memory
+ * will be blitted to it. */
+ if( p_vout->p_sys->b_using_overlay )
+ {
+ if( DirectXCreateSurface( p_vout, &p_surface, p_vout->output.i_chroma,
+ p_vout->p_sys->b_using_overlay ) )
+ {
+ /* Allocate internal structure */
+ p_pic[0].p_sys = malloc( sizeof( picture_sys_t ) );
+ if( p_pic[0].p_sys == NULL )
+ {
+ DirectXCloseSurface( p_vout, p_surface );
+ return -1;
+ }
+ p_pic[0].p_sys->p_surface = p_surface;
+ p_vout->p_sys->p_current_surface = p_surface;
+ DirectXUpdateOverlay( p_vout );
+ I_OUTPUTPICTURES = 1;
+ }
+ else p_vout->p_sys->b_using_overlay = 0;
+ }
+
+ /* As we can't have overlays, will try to create plain RBG surfaces in
+ * system memory. These surfaces will then be blitted onto the primary
+ * surface (display) so they can be displayed */
+ if( !p_vout->p_sys->b_using_overlay )
+ {
+ /* FixMe */
+ p_vout->output.i_chroma = FOURCC_RV16;
+
+ for( i = 0; i < i_num_pics; i++ )
+ {
+ if( DirectXCreateSurface( p_vout, &p_surface,
+ p_vout->output.i_chroma,
+ p_vout->p_sys->b_using_overlay ) )
+ {
+ /* Allocate internal structure */
+ p_pic[i].p_sys = malloc( sizeof( picture_sys_t ) );
+ if( p_pic[i].p_sys == NULL )
+ {
+ DirectXCloseSurface( p_vout, p_surface );
+ FreePictureVec( p_vout, p_pic, I_OUTPUTPICTURES );
+ I_OUTPUTPICTURES = 0;
+ return -1;
+ }
+ p_pic[i].p_sys->p_surface = p_surface;
+ I_OUTPUTPICTURES++;
+
+ }
+ else break;
+ }
+ }
+
+
+ /* Now that we've got all our direct-buffers, we can finish filling in the
+ * picture_t structures */
+ for( i = 0; i < I_OUTPUTPICTURES; i++ )
+ {
+ p_pic[i].i_status = DESTROYED_PICTURE;
+ p_pic[i].i_type = DIRECT_PICTURE;
+ PP_OUTPUTPICTURE[i] = &p_pic[i];
+
+ if( !DirectXGetSurfaceDesc( &p_pic[i] ) )
+ {
+ /* AAARRGG */
+ FreePictureVec( p_vout, p_pic, I_OUTPUTPICTURES );
+ I_OUTPUTPICTURES = 0;
+ return -1;
+ }
+
+ if( !UpdatePictureStruct(p_vout, &p_pic[i], p_vout->output.i_chroma) )
+ {
+
+ /* Unknown chroma, tell the guy to get lost */
+ intf_ErrMsg( "vout error: never heard of chroma 0x%.8x (%4.4s)",
+ p_vout->output.i_chroma,
+ (char*)&p_vout->output.i_chroma );
+ FreePictureVec( p_vout, p_pic, I_OUTPUTPICTURES );
+ I_OUTPUTPICTURES = 0;
+ return -1;
+ }
}
- /* Disable any display */
- p_vout->p_sys->b_display_enabled = 0;
+ intf_WarnMsg( 3, "vout: End NewPictureVec");
+ return 0;
}
/*****************************************************************************
- * DirectXKeepAspectRatio:
+ * FreePicture: destroy a picture vector allocated with NewPictureVec
*****************************************************************************
- * This function adjusts the coordinates of the video rectangle to keep the
- * aspect/ratio of the video.
+ *
*****************************************************************************/
-static void DirectXKeepAspectRatio( vout_thread_t *p_vout, RECT *rect_window )
+static void FreePictureVec( vout_thread_t *p_vout, picture_t *p_pic,
+ int i_num_pics )
{
+ int i;
+
+ for( i = 0; i < i_num_pics; i++ )
+ {
+ DirectXCloseSurface( p_vout, p_pic[i].p_sys->p_surface );
- if( !p_vout->p_rendered_pic ) return;
-
- switch( p_vout->p_rendered_pic->i_aspect )
- {
- case AR_16_9_PICTURE:
- if( ((rect_window->right-rect_window->left)*9)
- > ((rect_window->bottom-rect_window->top)*16) )
- {
- int temp;
- temp = (rect_window->bottom-rect_window->top)*16/9;
- temp = (rect_window->right-rect_window->left) - temp;
- rect_window->left += (temp/2);
- rect_window->right -= (temp/2);
- }
- else
+ for( i = 0; i < i_num_pics; i++ )
{
- int temp;
- temp = (rect_window->right-rect_window->left)*9/16;
- temp = (rect_window->bottom-rect_window->top) - temp;
- rect_window->top += (temp/2);
- rect_window->bottom -= (temp/2);
+ free( p_pic[i].p_sys );
}
- break;
-
- case AR_221_1_PICTURE:
- if( ((rect_window->right-rect_window->left)*100)
- > ((rect_window->bottom-rect_window->top)*221) )
- {
- int temp;
- temp = (rect_window->bottom-rect_window->top)*221/100;
- temp = (rect_window->right-rect_window->left) - temp;
- rect_window->left += (temp/2);
- rect_window->right -= (temp/2);
- }
- else
- {
- int temp;
- temp = (rect_window->right-rect_window->left)*100/221;
- temp = (rect_window->bottom-rect_window->top) - temp;
- rect_window->top += (temp/2);
- rect_window->bottom -= (temp/2);
- }
- break;
-
- case AR_3_4_PICTURE:
- if( ((rect_window->right-rect_window->left)*3)
- > ((rect_window->bottom-rect_window->top)*4) )
- {
- int temp;
- temp = (rect_window->bottom-rect_window->top)*4/3;
- temp = (rect_window->right-rect_window->left) - temp;
- rect_window->left += (temp/2);
- rect_window->right -= (temp/2);
- }
- else
- {
- int temp;
- temp = (rect_window->right-rect_window->left)*3/4;
- temp = (rect_window->bottom-rect_window->top) - temp;
- rect_window->top += (temp/2);
- rect_window->bottom -= (temp/2);
- }
- break;
-
- case AR_SQUARE_PICTURE:
- default:
- if( (rect_window->right-rect_window->left)
- > (rect_window->bottom-rect_window->top) )
- {
- int temp;
- temp = (rect_window->bottom-rect_window->top);
- temp = (rect_window->right-rect_window->left) - temp;
- rect_window->left += (temp/2);
- rect_window->right -= (temp/2);
- }
+ }
+}
+
+/*****************************************************************************
+ * UpdatePictureStruct: updates the internal data in the picture_t structure
+ *****************************************************************************
+ * This will setup stuff for use by the video_output thread
+ *****************************************************************************/
+static int UpdatePictureStruct( vout_thread_t *p_vout, picture_t *p_pic,
+ int i_chroma )
+{
+
+ switch( p_vout->output.i_chroma )
+ {
+
+ case FOURCC_YV12:
+
+ p_pic->Y_PIXELS = p_pic->p_sys->ddsd.lpSurface;
+ p_pic->p[Y_PLANE].i_lines = p_vout->output.i_height;
+ p_pic->p[Y_PLANE].i_pitch = p_pic->p_sys->ddsd.lPitch;
+ p_pic->p[Y_PLANE].i_pixel_bytes = 1;
+ p_pic->p[Y_PLANE].b_margin = 0;
+
+ p_pic->V_PIXELS = p_pic->Y_PIXELS
+ + p_pic->p[Y_PLANE].i_lines * p_pic->p[Y_PLANE].i_pitch;
+ p_pic->p[V_PLANE].i_lines = p_vout->output.i_height / 2;
+ p_pic->p[V_PLANE].i_pitch = p_pic->p[Y_PLANE].i_pitch / 2;
+ p_pic->p[V_PLANE].i_pixel_bytes = 1;
+ p_pic->p[V_PLANE].b_margin = 0;
+
+ p_pic->U_PIXELS = p_pic->V_PIXELS
+ + p_pic->p[V_PLANE].i_lines * p_pic->p[V_PLANE].i_pitch;
+ p_pic->p[U_PLANE].i_lines = p_vout->output.i_height / 2;
+ p_pic->p[U_PLANE].i_pitch = p_pic->p[Y_PLANE].i_pitch / 2;
+ p_pic->p[U_PLANE].i_pixel_bytes = 1;
+ p_pic->p[U_PLANE].b_margin = 0;
+
+ p_pic->i_planes = 3;
+ break;
+
+ case FOURCC_RV16:
+
+ p_pic->p->p_pixels = p_pic->p_sys->ddsd.lpSurface;
+ p_pic->p->i_lines = p_vout->output.i_height;
+ p_pic->p->i_pitch = p_pic->p_sys->ddsd.lPitch;
+ p_pic->p->i_pixel_bytes = 2;
+ p_pic->p->b_margin = 0;
+
+ p_pic->p->i_red_mask = 0x001f;
+ p_pic->p->i_green_mask = 0x03e0;
+ p_pic->p->i_blue_mask = 0x7c00;
+
+ p_pic->i_planes = 1;
+ break;
+
+ case FOURCC_RV15:
+
+ p_pic->p->p_pixels = p_pic->p_sys->ddsd.lpSurface;
+ p_pic->p->i_lines = p_vout->output.i_height;
+ p_pic->p->i_pitch = p_pic->p_sys->ddsd.lPitch;
+ p_pic->p->i_pixel_bytes = 2;
+ p_pic->p->b_margin = 0;
+
+ p_pic->p->i_red_mask = 0x001f;
+ p_pic->p->i_green_mask = 0x07e0;
+ p_pic->p->i_blue_mask = 0xf800;
+
+ p_pic->i_planes = 1;
+ break;
+#if 0
+ case FOURCC_I420:
+
+ p_pic->Y_PIXELS = p_pic->p_sys->ddsd.lpSurface;
+ p_pic->p[Y_PLANE].i_lines = p_vout->output.i_height;
+ p_pic->p[Y_PLANE].i_pitch = p_pic->p_sys->ddsd.lPitch;
+ p_pic->p[Y_PLANE].i_pixel_bytes = 1;
+ p_pic->p[Y_PLANE].b_margin = 0;
+
+ p_pic->U_PIXELS = p_pic->Y_PIXELS
+ + p_pic->p[Y_PLANE].i_lines * p_pic->p[Y_PLANE].i_pitch;
+ p_pic->p[U_PLANE].i_lines = p_vout->output.i_height / 2;
+ p_pic->p[U_PLANE].i_pitch = p_pic->p[Y_PLANE].i_pitch / 2;
+ p_pic->p[U_PLANE].i_pixel_bytes = 1;
+ p_pic->p[U_PLANE].b_margin = 0;
+
+ p_pic->V_PIXELS = p_pic->U_PIXELS
+ + p_pic->p[U_PLANE].i_lines * p_pic->p[U_PLANE].i_pitch;
+ p_pic->p[V_PLANE].i_lines = p_vout->output.i_height / 2;
+ p_pic->p[V_PLANE].i_pitch = p_pic->p[U_PLANE].i_pitch;
+ p_pic->p[V_PLANE].i_pixel_bytes = 1;
+ p_pic->p[V_PLANE].b_margin = 0;
+
+ p_pic->i_planes = 3;
+ break;
+
+ case FOURCC_Y211:
+
+ p_pic->p->p_pixels = p_pic->p_sys->p_image->data
+ + p_pic->p_sys->p_image->offsets[0];
+ p_pic->p->i_lines = p_vout->output.i_height;
+ /* XXX: this just looks so plain wrong... check it out ! */
+ p_pic->p->i_pitch = p_pic->p_sys->p_image->pitches[0] / 4;
+ p_pic->p->i_pixel_bytes = 4;
+ p_pic->p->b_margin = 0;
+
+ p_pic->i_planes = 1;
+ break;
+
+ case FOURCC_YUY2:
+ case FOURCC_UYVY:
+
+ p_pic->p->p_pixels = p_pic->p_sys->p_image->data
+ + p_pic->p_sys->p_image->offsets[0];
+ p_pic->p->i_lines = p_vout->output.i_height;
+ p_pic->p->i_pitch = p_pic->p_sys->p_image->pitches[0];
+ p_pic->p->i_pixel_bytes = 4;
+ p_pic->p->b_margin = 0;
+
+ p_pic->i_planes = 1;
+ break;
+#endif
+
+ default:
+ /* Not supported */
+ return 0;
+
+ }
+
+ return 1;
+}
+
+/*****************************************************************************
+ * DirectXGetDDrawCaps: Probe the capabilities of the hardware
+ *****************************************************************************
+ * It is nice to know which features are supported by the hardware so we can
+ * find ways to optimize our rendering.
+ *****************************************************************************/
+static void DirectXGetDDrawCaps( vout_thread_t *p_vout )
+{
+ DDCAPS ddcaps;
+ HRESULT dxresult;
+
+ /* This is just an indication of whether or not we'll support overlay,
+ * but with this test we don't know if we support YUV overlay */
+ memset( &ddcaps, 0, sizeof( DDCAPS ));
+ ddcaps.dwSize = sizeof(DDCAPS);
+ dxresult = IDirectDraw2_GetCaps( p_vout->p_sys->p_ddobject,
+ &ddcaps, NULL );
+ if(dxresult != DD_OK )
+ {
+ intf_WarnMsg( 3,"vout error: can't get caps." );
+ }
else
- {
- int temp;
- temp = (rect_window->right-rect_window->left);
- temp = (rect_window->bottom-rect_window->top) - temp;
- rect_window->top += (temp/2);
- rect_window->bottom -= (temp/2);
- }
- break;
-
- }
+ {
+ BOOL bHasOverlay, bHasOverlayFourCC, bCanClipOverlay,
+ bHasColorKey, bCanStretch;
+
+ /* Determine if the hardware supports overlay surfaces */
+ bHasOverlay = ((ddcaps.dwCaps & DDCAPS_OVERLAY) ==
+ DDCAPS_OVERLAY) ? TRUE : FALSE;
+ /* Determine if the hardware supports overlay surfaces */
+ bHasOverlayFourCC = ((ddcaps.dwCaps & DDCAPS_OVERLAYFOURCC) ==
+ DDCAPS_OVERLAYFOURCC) ? TRUE : FALSE;
+ /* Determine if the hardware supports overlay surfaces */
+ bCanClipOverlay = ((ddcaps.dwCaps & DDCAPS_OVERLAYCANTCLIP) ==
+ 0 ) ? TRUE : FALSE;
+ /* Determine if the hardware supports colorkeying */
+ bHasColorKey = ((ddcaps.dwCaps & DDCAPS_COLORKEY) ==
+ DDCAPS_COLORKEY) ? TRUE : FALSE;
+ /* Determine if the hardware supports scaling of the overlay surface */
+ bCanStretch = ((ddcaps.dwCaps & DDCAPS_OVERLAYSTRETCH) ==
+ DDCAPS_OVERLAYSTRETCH) ? TRUE : FALSE;
+ intf_WarnMsg( 3, "vout: DirectDraw Capabilities:" );
+ intf_WarnMsg( 3, " overlay=%i yuvoverlay=%i can_clip_overlay=%i "
+ "colorkey=%i stretch=%i",
+ bHasOverlay, bHasOverlayFourCC, bCanClipOverlay,
+ bHasColorKey, bCanStretch );
+
+ /* Overlay clipping support is interesting for us as it means we can
+ * get rid of the colorkey alltogether */
+ p_vout->p_sys->b_caps_overlay_clipping = bCanClipOverlay;
+
+ }
+}
+
+/*****************************************************************************
+ * DirectXGetSurfaceDesc: Get some more information about the surface
+ *****************************************************************************
+ * This function get and stores the surface descriptor which among things
+ * has the pointer to the picture data.
+ *****************************************************************************/
+static int DirectXGetSurfaceDesc( picture_t *p_pic )
+{
+ HRESULT dxresult;
+
+ /* Lock the surface to get a valid pointer to the picture buffer */
+ memset( &p_pic->p_sys->ddsd, 0, sizeof( DDSURFACEDESC ));
+ p_pic->p_sys->ddsd.dwSize = sizeof(DDSURFACEDESC);
+ dxresult = IDirectDrawSurface3_Lock( p_pic->p_sys->p_surface,
+ NULL, &p_pic->p_sys->ddsd,
+ DDLOCK_NOSYSLOCK | DDLOCK_WAIT,
+ NULL );
+ if ( dxresult == DDERR_SURFACELOST )
+ {
+ /* Your surface can be lost so be sure
+ * to check this and restore it if needed */
+ dxresult = IDirectDrawSurface3_Restore( p_pic->p_sys->p_surface );
+ dxresult = IDirectDrawSurface3_Lock( p_pic->p_sys->p_surface, NULL,
+ &p_pic->p_sys->ddsd,
+ DDLOCK_NOSYSLOCK | DDLOCK_WAIT,
+ NULL);
+ }
+ if( dxresult != DD_OK )
+ {
+ intf_ErrMsg( "vout: DirectXGetSurfaceDesc can't lock surface" );
+ return 0;
+ }
+
+ /* Unlock the Surface */
+ dxresult = IDirectDrawSurface3_Unlock( p_pic->p_sys->p_surface, NULL );
+ return 1;
}
* vout_events.c: Windows DirectX video output events handler
*****************************************************************************
* Copyright (C) 2001 VideoLAN
- * $Id: vout_events.c,v 1.7 2001/12/30 07:09:54 sam Exp $
+ * $Id: vout_events.c,v 1.8 2002/01/17 23:02:45 gbazin Exp $
*
* Authors: Gildas Bazin <gbazin@netcourrier.com>
*
#include <windows.h>
#include <windowsx.h>
+#include <shellapi.h>
-#if defined( _MSC_VER )
-# include <ddraw.h>
-#else
-# include <directx.h>
-#endif
+#include <ddraw.h>
#include "interface.h"
*****************************************************************************/
static int DirectXCreateWindow( vout_thread_t *p_vout );
static void DirectXCloseWindow ( vout_thread_t *p_vout );
+static void DirectXUpdateRects( vout_thread_t *p_vout );
static long FAR PASCAL DirectXEventProc ( HWND hwnd, UINT message,
WPARAM wParam, LPARAM lParam );
-/*****************************************************************************
- * Global variables.
- * I really hate them, but here I don't have any choice. And anyway, this
- * shouldn't really affect reentrancy.
- * This variable is used to know if we have to update the overlay position
- * and size. This is to fix the bug we've got when the Windows option, to show
- * the content of a window when you drag it, is enabled.
- *****************************************************************************/
-int b_directx_update_overlay = 0;
-
/*****************************************************************************
* DirectXEventThread: Create video window & handle its messages
*****************************************************************************
void DirectXEventThread( vout_thread_t *p_vout )
{
MSG msg;
- boolean_t b_dispatch_msg = TRUE;
/* Initialisation */
vlc_mutex_unlock( &p_vout->p_sys->event_thread_lock );
/* Main loop */
- while( !p_vout->b_die && !p_vout->p_sys->b_event_thread_die )
+ /* GetMessage will sleep if there's no message in the queue */
+ while( GetMessage( &msg, p_vout->p_sys->hwnd, 0, 0 ) )
{
- /* GetMessage will sleep if there's no message in the queue */
- if( GetMessage( &msg, NULL, 0, 0 ) >= 0 )
+ /* Check if we are asked to exit */
+ if( p_vout->b_die || p_vout->p_sys->b_event_thread_die )
+ break;
+
+ switch( msg.message )
{
- switch( msg.message )
+
+#if 0
+ case WM_PAINT:
+ intf_WarnMsg( 4, "vout: vout_Manage WM_PAINT" );
+ break;
+
+ case WM_ERASEBKGND:
+ intf_WarnMsg( 4, "vout: vout_Manage WM_ERASEBKGND" );
+ break;
+#endif
+
+ case WM_MOUSEMOVE:
+ if( p_vout->p_sys->b_cursor )
{
-
- case WM_CLOSE:
- intf_WarnMsg( 3, "vout: vout_Manage WM_CLOSE" );
- break;
-
- case WM_QUIT:
- intf_WarnMsg( 3, "vout: vout_Manage WM_QUIT" );
- p_vout->p_sys->b_event_thread_die = 1;
- p_main->p_intf->b_die = 1;
- break;
-
- case WM_MOVE:
- intf_WarnMsg( 3, "vout: vout_Manage WM_MOVE" );
- if( !p_vout->b_need_render )
+ if( p_vout->p_sys->b_cursor_autohidden )
{
- p_vout->p_sys->i_changes |= VOUT_SIZE_CHANGE;
+ p_vout->p_sys->b_cursor_autohidden = 0;
+ p_vout->p_sys->i_lastmoved = mdate();
+ ShowCursor( TRUE );
}
- /* don't create a never ending loop */
- b_dispatch_msg = FALSE;
- break;
-
- case WM_APP:
- intf_WarnMsg( 3, "vout: vout_Manage WM_APP" );
- if( !p_vout->b_need_render )
+ else
{
- p_vout->p_sys->i_changes |= VOUT_SIZE_CHANGE;
+ p_vout->p_sys->i_lastmoved = mdate();
}
- /* size change has been handled (to fix a bug)*/
- b_directx_update_overlay = 0;
- /* don't create a never ending loop */
- b_dispatch_msg = FALSE;
+ }
+ break;
+
+ case WM_RBUTTONUP:
+ intf_WarnMsg( 4, "vout: vout_Manage WM_RBUTTONUP" );
+ p_main->p_intf->b_menu_change = 1;
+ break;
+
+ case WM_KEYDOWN:
+ /* the key events are first processed here. The next
+ * message processed by this main message loop will be the
+ * char translation of the key event */
+ intf_WarnMsg( 3, "vout: vout_Manage WM_KEYDOWN" );
+ switch( msg.wParam )
+ {
+ case VK_ESCAPE:
+ case VK_F12:
+ PostQuitMessage( 0 );
break;
-
-#if 0
- case WM_PAINT:
- intf_WarnMsg( 4, "vout: vout_Manage WM_PAINT" );
+ }
+ TranslateMessage(&msg);
+ break;
+
+ case WM_CHAR:
+ intf_WarnMsg( 3, "vout: vout_Manage WM_CHAR" );
+ switch( msg.wParam )
+ {
+ case 'q':
+ case 'Q':
+ PostQuitMessage( 0 );
break;
-
- case WM_ERASEBKGND:
- intf_WarnMsg( 4, "vout: vout_Manage WM_ERASEBKGND" );
+
+ case 'f': /* switch to fullscreen */
+ case 'F':
+ p_vout->p_sys->i_changes |= VOUT_FULLSCREEN_CHANGE;
break;
-#endif
-
- case WM_MOUSEMOVE:
- intf_WarnMsg( 4, "vout: vout_Manage WM_MOUSEMOVE" );
- if( p_vout->p_sys->b_cursor )
- {
- if( p_vout->p_sys->b_cursor_autohidden )
- {
- p_vout->p_sys->b_cursor_autohidden = 0;
- p_vout->p_sys->i_lastmoved = mdate();
- ShowCursor( TRUE );
- }
- else
- {
- p_vout->p_sys->i_lastmoved = mdate();
- }
- }
+
+ case 'c': /* toggle grayscale */
+ case 'C':
+ p_vout->b_grayscale = ! p_vout->b_grayscale;
+ p_vout->p_sys->i_changes |= VOUT_GRAYSCALE_CHANGE;
break;
-
- case WM_RBUTTONUP:
- intf_WarnMsg( 4, "vout: vout_Manage WM_RBUTTONUP" );
- p_main->p_intf->b_menu_change = 1;
+
+ case 'i': /* toggle info */
+ case 'I':
+ p_vout->b_info = ! p_vout->b_info;
+ p_vout->p_sys->i_changes |= VOUT_INFO_CHANGE;
break;
- case WM_KEYDOWN:
- /* the key events are first processed here. The next
- * message processed by this main message loop will be the
- * char translation of the key event */
- intf_WarnMsg( 3, "vout: vout_Manage WM_KEYDOWN" );
- switch( msg.wParam )
- {
- case VK_ESCAPE:
- case VK_F12:
- PostQuitMessage( 0 );
- break;
- }
- TranslateMessage(&msg);
- b_dispatch_msg = FALSE;
+ case 's': /* toggle scaling */
+ case 'S':
+ p_vout->b_scale = ! p_vout->b_scale;
+ p_vout->p_sys->i_changes |= VOUT_SCALE_CHANGE;
break;
-
- case WM_CHAR:
- intf_WarnMsg( 3, "vout: vout_Manage WM_CHAR" );
- switch( msg.wParam )
- {
- case 'q':
- case 'Q':
- PostQuitMessage( 0 );
- break;
-
- case 'f': /* switch to fullscreen */
- case 'F':
- p_vout->p_sys->i_changes |= VOUT_FULLSCREEN_CHANGE;
- break;
-
- case 'y': /* switch to hard YUV */
- case 'Y':
- p_vout->p_sys->i_changes |= VOUT_YUV_CHANGE;
- break;
-
- case 'c': /* toggle grayscale */
- case 'C':
- p_vout->b_grayscale = ! p_vout->b_grayscale;
- p_vout->p_sys->i_changes |= VOUT_GRAYSCALE_CHANGE;
- break;
-
- case 'i': /* toggle info */
- case 'I':
- p_vout->b_info = ! p_vout->b_info;
- p_vout->p_sys->i_changes |= VOUT_INFO_CHANGE;
- break;
-
- case 's': /* toggle scaling */
- case 'S':
- p_vout->b_scale = ! p_vout->b_scale;
- p_vout->p_sys->i_changes |= VOUT_SCALE_CHANGE;
- break;
-
- case ' ': /* toggle interface */
- p_vout->b_interface = ! p_vout->b_interface;
- p_vout->p_sys->i_changes |= VOUT_INTF_CHANGE;
- 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 )msg.wParam ) )
- {
- intf_DbgMsg( "unhandled key '%c' (%i)",
- (char)msg.wParam, msg.wParam );
- }
- break;
- }
-
-#if 0
- default:
- intf_WarnMsg( 4, "vout: vout_Manage WM Default %i",
- msg.message );
+
+ case ' ': /* toggle interface */
+ p_vout->b_interface = ! p_vout->b_interface;
+ p_vout->p_sys->i_changes |= VOUT_INTF_CHANGE;
break;
-#endif
- } /* End Switch */
+ 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;
- /* don't create a never ending loop */
- if( b_dispatch_msg )
- {
- TranslateMessage(&msg);
- DispatchMessage(&msg);
+ default:
+ intf_DbgMsg( "unhandled key '%c' (%i)",
+ (char)msg.wParam, msg.wParam );
+ break;
}
- b_dispatch_msg = TRUE;
- } /* if( GetMessage() ) */
- else
- {
- intf_ErrMsg("vout error: GetMessage failed in DirectXEventThread");
- p_vout->p_sys->b_event_thread_die = 1;
- } /* End if( GetMessage() ) */
+ default:
+ /* Messages we don't handle directly are dispatched to the
+ * window procedure */
+#if 0
+ intf_WarnMsg( 5, "vout: vout_Manage unhandled message",
+ msg.message );
+#endif
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ break;
+ } /* End Switch */
} /* End Main loop */
- /* Destroy the window */
- DirectXCloseWindow( p_vout );
+ if( msg.message == WM_QUIT )
+ {
+ intf_WarnMsg( 3, "vout: DirectXEventThread WM_QUIT" );
+ p_vout->p_sys->hwnd = NULL; /* Window already destroyed */
+
+ /* exit application */
+ p_main->p_intf->b_die = 1;
+ }
+
+ intf_WarnMsg( 3, "vout: DirectXEventThread Terminating" );
- /* Set thread Status */
- p_vout->p_sys->i_event_thread_status = THREAD_OVER;
+ /* clear the changes formerly signaled */
+ p_vout->p_sys->i_changes = 0;
+ DirectXCloseWindow( p_vout );
}
RECT rect_window;
COLORREF colorkey;
HDC hdc;
+ HICON vlc_icon = NULL;
+ char vlc_path[_MAX_PATH+1];
intf_WarnMsg( 3, "vout: DirectXCreateWindow" );
/* the first step is to find the colorkey we want to use. The difficulty
* comes from the potential dithering (depends on the display depth)
* because we need to know the real RGB value of the chosen colorkey */
- hdc = GetDC( GetDesktopWindow() );
+ hdc = GetDC( NULL );
for( colorkey = 5; colorkey < 0xFF /*all shades of red*/; colorkey++ )
{
if( colorkey == GetNearestColor( hdc, colorkey ) )
break;
}
intf_WarnMsg(3,"vout: DirectXCreateWindow background color:%i", colorkey);
- ReleaseDC( p_vout->p_sys->hwnd, hdc );
/* create the actual brush */
p_vout->p_sys->hbrush = CreateSolidBrush(colorkey);
- p_vout->p_sys->i_colorkey = (int)colorkey;
+ p_vout->p_sys->i_rgb_colorkey = (int)colorkey;
+
+ /* Get the current size of the display and its colour depth */
+ p_vout->p_sys->rect_display.right = GetDeviceCaps( hdc, HORZRES );
+ p_vout->p_sys->rect_display.bottom = GetDeviceCaps( hdc, VERTRES );
+ p_vout->p_sys->i_display_depth = GetDeviceCaps( hdc, BITSPIXEL );
+ intf_WarnMsg( 3, "vout: Screen dimensions %ix%i colour depth %i",
+ p_vout->p_sys->rect_display.right,
+ p_vout->p_sys->rect_display.bottom,
+ p_vout->p_sys->i_display_depth );
+
+ ReleaseDC( p_vout->p_sys->hwnd, hdc );
+
+ /* Get the Icon from the main app */
+ if( GetModuleFileName( NULL, vlc_path, _MAX_PATH ) )
+ {
+ vlc_icon = ExtractIcon( hInstance, vlc_path, 0 );
+ }
+ if( !vlc_icon )
+ vlc_icon = LoadIcon( NULL, IDI_APPLICATION );
+
/* fill in the window class structure */
wc.cbSize = sizeof(WNDCLASSEX);
wc.cbClsExtra = 0; /* no extra class data */
wc.cbWndExtra = 0; /* no extra window data */
wc.hInstance = hInstance; /* instance */
- wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); /* load the vlc icon */
+ wc.hIcon = CopyIcon( vlc_icon ); /* load the vlc icon */
wc.hCursor = LoadCursor(NULL, IDC_ARROW); /* load a default cursor */
wc.hbrBackground = p_vout->p_sys->hbrush; /* background color */
wc.lpszMenuName = NULL; /* no menu */
wc.lpszClassName = "VLC DirectX"; /* use a special class */
- wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); /* load the vlc icon */
+ wc.hIconSm = CopyIcon( vlc_icon ); /* load the vlc icon */
/* register the window class */
if (!RegisterClassEx(&wc))
p_vout->p_sys->hwnd = CreateWindow("VLC DirectX",/* name of window class */
"VLC DirectX", /* window title bar text */
WS_OVERLAPPEDWINDOW
- | WS_SIZEBOX | WS_VISIBLE, /* window style */
+ | WS_SIZEBOX, /* window style */
10, /* default X coordinate */
10, /* default Y coordinate */
rect_window.right - rect_window.left, /* window width */
return (1);
}
+ /* store a p_vout pointer into the window local storage (for later use
+ * in DirectXEventProc).
+ * We need to use SetWindowLongPtr when it is available in mingw */
+ SetWindowLong( p_vout->p_sys->hwnd, GWL_USERDATA, (LONG)p_vout );
+
/* now display the window */
ShowWindow(p_vout->p_sys->hwnd, SW_SHOW);
}
}
+/*****************************************************************************
+ * DirectXUpdateRects:
+ *****************************************************************************
+ * This function is called when the window position and size is changed, and
+ * its job is to update the source and destination RECTs used to display the
+ * picture.
+ *****************************************************************************/
+static void DirectXUpdateRects( vout_thread_t *p_vout )
+{
+ int i_width, i_height, i_x, i_y;
+
+#define rect_src p_vout->p_sys->rect_src
+#define rect_src_clipped p_vout->p_sys->rect_src_clipped
+#define rect_dest p_vout->p_sys->rect_dest
+#define rect_dest_clipped p_vout->p_sys->rect_dest_clipped
+#define rect_display p_vout->p_sys->rect_display
+
+ vout_PlacePicture( p_vout, p_vout->p_sys->i_window_width,
+ p_vout->p_sys->i_window_height,
+ &i_x, &i_y, &i_width, &i_height );
+
+ /* Destination image position and dimensions */
+ rect_dest.left = i_x + p_vout->p_sys->i_window_x;
+ rect_dest.top = i_y + p_vout->p_sys->i_window_y;
+ rect_dest.right = rect_dest.left + i_width;
+ rect_dest.bottom = rect_dest.top + i_height;
+
+
+ /* UpdateOverlay directdraw function doesn't automatically clip to the
+ * display size so we need to do it otherwise it will fails */
+
+ /* Clip the destination window */
+ IntersectRect( &rect_dest_clipped, &rect_dest, &rect_display );
+
+ intf_WarnMsg( 3, "vout: DirectXUpdateRects image_dst_clipped coords:"
+ " %i,%i,%i,%i",
+ rect_dest_clipped.left, rect_dest_clipped.top,
+ rect_dest_clipped.right, rect_dest_clipped.bottom);
+
+ /* the 2 following lines are to fix a bug when clicking on the desktop */
+ if( (rect_dest_clipped.right - rect_dest_clipped.left)==0 ||
+ (rect_dest_clipped.bottom - rect_dest_clipped.top)==0 )
+ {
+ SetRectEmpty( &rect_src_clipped );
+ return;
+ }
+
+ /* src image dimensions */
+ rect_src.left = 0;
+ rect_src.top = 0;
+ rect_src.right = p_vout->render.i_width;
+ rect_src.bottom = p_vout->render.i_height;
+
+ /* Clip the source image */
+ rect_src_clipped.left = (rect_dest_clipped.left - rect_dest.left) *
+ p_vout->render.i_width / (rect_dest.right - rect_dest.left);
+ rect_src_clipped.right = p_vout->render.i_width -
+ (rect_dest.right - rect_dest_clipped.right) * p_vout->render.i_width /
+ (rect_dest.right - rect_dest.left);
+ rect_src_clipped.top = (rect_dest_clipped.top - rect_dest.top) *
+ p_vout->render.i_height / (rect_dest.bottom - rect_dest.top);
+ rect_src_clipped.bottom = p_vout->render.i_height -
+ (rect_dest.bottom - rect_dest_clipped.bottom) * p_vout->render.i_height /
+ (rect_dest.bottom - rect_dest.top);
+
+ intf_WarnMsg( 3, "vout: DirectXUpdateRects image_src_clipped"
+ " coords: %i,%i,%i,%i",
+ rect_src_clipped.left, rect_src_clipped.top,
+ rect_src_clipped.right, rect_src_clipped.bottom);
+
+#undef rect_src
+#undef rect_src_clipped
+#undef rect_dest
+#undef rect_dest_clipped
+#undef rect_display
+}
+
/*****************************************************************************
* DirectXEventProc: This is the window event processing function.
*****************************************************************************
* function to it. The aim of this function is to manage "Queued Messages" and
* "Nonqueued Messages".
* Queued Messages are those picked up and retransmitted by vout_Manage
- * (using the GetMessage function).
+ * (using the GetMessage and DispatchMessage functions).
* Nonqueued Messages are those that Windows will send directly to this
- * function (like WM_DESTROY, WM_WINDOWPOSCHANGED...)
+ * procedure (like WM_DESTROY, WM_WINDOWPOSCHANGED...)
*****************************************************************************/
static long FAR PASCAL DirectXEventProc( HWND hwnd, UINT message,
WPARAM wParam, LPARAM lParam )
{
+ vout_thread_t *p_vout;
+
switch( message )
{
-#if 0
- case WM_APP:
- intf_WarnMsg( 3, "vout: WinProc WM_APP" );
+ case WM_WINDOWPOSCHANGED:
+ {
+ RECT rect_window;
+ POINT point_window;
+
+ p_vout = (vout_thread_t *)GetWindowLong( hwnd, GWL_USERDATA );
+
+ /* update the window position */
+ point_window.x = 0;
+ point_window.y = 0;
+ ClientToScreen( hwnd, &point_window );
+ p_vout->p_sys->i_window_x = point_window.x;
+ p_vout->p_sys->i_window_y = point_window.y;
+
+ /* update the window size */
+ GetClientRect( hwnd, &rect_window );
+ p_vout->p_sys->i_window_width = rect_window.right;
+ p_vout->p_sys->i_window_height = rect_window.bottom;
+ intf_WarnMsg( 3, "vout: WinProc WM_WINDOWPOSCHANGED %i,%i,%i,%i",
+ p_vout->p_sys->i_window_x, p_vout->p_sys->i_window_y,
+ p_vout->p_sys->i_window_width,
+ p_vout->p_sys->i_window_height );
+
+ DirectXUpdateRects( p_vout );
+ if( p_vout->p_sys->b_using_overlay )
+ DirectXUpdateOverlay( p_vout );
+
+ /* signal the size change */
+ p_vout->p_sys->i_changes |= VOUT_SIZE_CHANGE;
+
+ return 0;
+ }
break;
case WM_ACTIVATE:
- intf_WarnMsg( 4, "vout: WinProc WM_ACTIVED" );
+ intf_WarnMsg( 4, "vout: WinProc WM_ACTIVE" );
break;
case WM_CREATE:
case WM_CLOSE:
intf_WarnMsg( 4, "vout: WinProc WM_CLOSE" );
break;
-#endif
/* the window has been closed so shut down everything now */
case WM_DESTROY:
break;
#if 0
- case WM_MOVE:
- intf_WarnMsg( 4, "vout: WinProc WM_MOVE" );
- break;
-
- case WM_SIZE:
- intf_WarnMsg( 4, "vout: WinProc WM_SIZE" );
- break;
-
- case WM_MOVING:
- intf_WarnMsg( 4, "vout: WinProc WM_MOVING" );
- break;
-
- case WM_ENTERSIZEMOVE:
- intf_WarnMsg( 4, "vout: WinProc WM_ENTERSIZEMOVE" );
- break;
-
- case WM_SIZING:
- intf_WarnMsg( 4, "vout: WinProc WM_SIZING" );
- break;
-#endif
-
- case WM_WINDOWPOSCHANGED:
- intf_WarnMsg( 3, "vout: WinProc WM_WINDOWPOSCHANGED" );
- b_directx_update_overlay = 1;
- PostMessage( hwnd, WM_APP, 0, 0);
- break;
-
-#if 0
- case WM_WINDOWPOSCHANGING:
- intf_WarnMsg( 3, "vout: WinProc WM_WINDOWPOSCHANGING" );
- break;
-
- case WM_PAINT:
- intf_WarnMsg( 4, "vout: WinProc WM_PAINT" );
- break;
-
- case WM_ERASEBKGND:
- intf_WarnMsg( 4, "vout: WinProc WM_ERASEBKGND" );
- break;
-
default:
intf_WarnMsg( 4, "vout: WinProc WM Default %i", message );
break;