* vout_directx.c: Windows DirectX video output display method
*****************************************************************************
* Copyright (C) 2001 VideoLAN
- * $Id: vout_directx.c,v 1.30 2002/04/05 01:05:22 gbazin Exp $
+ * $Id: vout_directx.c,v 1.36.2.2 2002/10/03 16:44:41 gbazin Exp $
*
* Authors: Gildas Bazin <gbazin@netcourrier.com>
*
*
* 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) 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.
+ * effectively display the pictures. This fallback method also enables us to
+ * display video in window mode.
*
*****************************************************************************/
#include <errno.h> /* ENOMEM */
*****************************************************************************/
#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 );
+DEFINE_GUID( IID_IDirectDrawSurface2, 0x57805885,0x6eec,0x11cf,0x94,0x41,0xa8,0x23,0x03,0xc1,0x0e,0x27 );
/*****************************************************************************
* Local prototypes.
static int DirectXCreateDisplay ( vout_thread_t *p_vout );
static void DirectXCloseDisplay ( vout_thread_t *p_vout );
static int DirectXCreateSurface ( vout_thread_t *p_vout,
- LPDIRECTDRAWSURFACE3 *, int, int );
+ LPDIRECTDRAWSURFACE2 *, int, int, int );
static void DirectXCloseSurface ( vout_thread_t *p_vout,
- LPDIRECTDRAWSURFACE3 );
+ LPDIRECTDRAWSURFACE2 );
static int DirectXCreateClipper ( vout_thread_t *p_vout );
static void DirectXGetDDrawCaps ( vout_thread_t *p_vout );
static int DirectXGetSurfaceDesc ( picture_t *p_pic );
if( p_vout->p_sys == NULL )
{
intf_ErrMsg( "vout error: can't create p_sys (%s)", strerror(ENOMEM) );
- return( 1 );
+ return 1;
}
/* Initialisations */
p_vout->p_sys->b_event_thread_die = 0;
p_vout->p_sys->b_caps_overlay_clipping = 0;
SetRectEmpty( &p_vout->p_sys->rect_display );
- p_vout->p_sys->b_using_overlay = !config_GetIntVariable( "nooverlay" );
+ p_vout->p_sys->b_using_overlay = config_GetIntVariable( "overlay" );
+ p_vout->p_sys->b_use_sysmem = config_GetIntVariable( "directx-use-sysmem");
+ p_vout->p_sys->b_hw_yuv = config_GetIntVariable( "directx-hw-yuv" );
- p_vout->p_sys->b_cursor = 1;
-
- p_vout->p_sys->b_cursor_autohidden = 0;
+ p_vout->p_sys->b_cursor_hidden = 0;
p_vout->p_sys->i_lastmoved = mdate();
/* Set main window's size */
{
intf_ErrMsg( "vout error: can't create DirectXEventThread" );
intf_ErrMsg("vout error: %s", strerror(ENOMEM));
- free( p_vout->p_sys );
- return( 1 );
+ goto error;
}
/* We need to wait for the actual creation of the thread and window */
if( p_vout->p_sys->i_event_thread_status != THREAD_READY )
{
intf_ErrMsg( "vout error: DirectXEventThread failed" );
- free( p_vout->p_sys );
- return( 1 );
+ goto error;
}
intf_WarnMsg( 3, "vout: vout_Create DirectXEventThread running" );
-
/* Initialise DirectDraw */
if( DirectXInitDDraw( p_vout ) )
{
intf_ErrMsg( "vout error: can't initialise DirectDraw" );
-
- /* Kill DirectXEventThread */
- p_vout->p_sys->b_event_thread_die = 1;
- /* we need to be sure DirectXEventThread won't stay stuck in
- * GetMessage, so we send a fake message */
- PostMessage( p_vout->p_sys->hwnd, WM_CHAR, (WPARAM)'^', 0);
- vlc_thread_join( p_vout->p_sys->event_thread_id );
-
- return ( 1 );
+ goto error;
}
/* Create the directx display */
if( DirectXCreateDisplay( p_vout ) )
{
intf_ErrMsg( "vout error: can't initialise DirectDraw" );
- DirectXCloseDDraw( p_vout );
-
- /* Kill DirectXEventThread */
- p_vout->p_sys->b_event_thread_die = 1;
- /* we need to be sure DirectXEventThread won't stay stuck in
- * GetMessage, so we send a fake message */
- PostMessage( p_vout->p_sys->hwnd, WM_CHAR, (WPARAM)'^', 0);
- vlc_thread_join( p_vout->p_sys->event_thread_id );
-
- return ( 1 );
+ goto error;
}
- /* 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;
- return( 0 );
+ error:
+ vout_Destroy( p_vout );
+ return 1;
}
/*****************************************************************************
*****************************************************************************/
static int vout_Init( vout_thread_t *p_vout )
{
+ int i_chroma_backup;
/* Initialize the output structure.
* Since DirectDraw can do rescaling for us, stick to the default
p_vout->output.i_aspect = p_vout->render.i_aspect;
#define MAX_DIRECTBUFFERS 1
+ /* Right now we use only 1 directbuffer because we don't want the
+ * video decoder to decode directly into direct buffers as they are
+ * created into video memory and video memory is _really_ slow */
+
+ /* Choose the chroma we will try first. */
+ switch( p_vout->render.i_chroma )
+ {
+ case FOURCC_YUY2:
+ case FOURCC_YUNV:
+ p_vout->output.i_chroma = FOURCC_YUY2;
+ break;
+ case FOURCC_UYVY:
+ case FOURCC_UYNV:
+ case FOURCC_Y422:
+ p_vout->output.i_chroma = FOURCC_UYVY;
+ break;
+ case FOURCC_YVYU:
+ p_vout->output.i_chroma = FOURCC_YVYU;
+ break;
+ default:
+ p_vout->output.i_chroma = FOURCC_YV12;
+ break;
+ }
NewPictureVec( p_vout, p_vout->p_picture, MAX_DIRECTBUFFERS );
+ i_chroma_backup = p_vout->output.i_chroma;
+
+ if( !I_OUTPUTPICTURES )
+ {
+ /* hmmm, it didn't work! Let's try commonly supported chromas */
+ p_vout->output.i_chroma = FOURCC_YV12;
+ NewPictureVec( p_vout, p_vout->p_picture, MAX_DIRECTBUFFERS );
+ if( !I_OUTPUTPICTURES )
+ {
+ /* hmmm, it didn't work! Let's try commonly supported chromas */
+ p_vout->output.i_chroma = FOURCC_YUY2;
+ NewPictureVec( p_vout, p_vout->p_picture, MAX_DIRECTBUFFERS );
+ }
+ }
+
+ if( !I_OUTPUTPICTURES )
+ {
+ /* If it still didn't work then don't try to use an overlay */
+ p_vout->output.i_chroma = i_chroma_backup;
+ p_vout->p_sys->b_using_overlay = 0;
+ NewPictureVec( p_vout, p_vout->p_picture, MAX_DIRECTBUFFERS );
+ }
+
/* Change the window title bar text */
if( p_vout->p_sys->b_using_overlay )
SetWindowText( p_vout->p_sys->hwnd,
- "VLC DirectX (using hardware overlay)" );
+ VOUT_TITLE " (hardware YUV overlay DirectX output)" );
+ else if( p_vout->p_sys->b_hw_yuv )
+ SetWindowText( p_vout->p_sys->hwnd,
+ VOUT_TITLE " (hardware YUV DirectX output)" );
+ else SetWindowText( p_vout->p_sys->hwnd,
+ VOUT_TITLE " (software RGB DirectX output)" );
- return( 0 );
+ return 0;
}
/*****************************************************************************
static void vout_Destroy( vout_thread_t *p_vout )
{
intf_WarnMsg( 3, "vout: vout_Destroy" );
+
DirectXCloseDisplay( p_vout );
DirectXCloseDDraw( p_vout );
/* Kill DirectXEventThread */
+ vlc_mutex_lock( &p_vout->p_sys->event_thread_lock );
p_vout->p_sys->b_event_thread_die = 1;
- /* we need to be sure DirectXEventThread won't stay stuck in GetMessage,
- * so we send a fake message */
- if( p_vout->p_sys->i_event_thread_status == THREAD_READY &&
- p_vout->p_sys->hwnd )
+
+ if( p_vout->p_sys->i_event_thread_status == THREAD_READY )
{
- PostMessage( p_vout->p_sys->hwnd, WM_CHAR, (WPARAM)'^', 0);
+ /* we need to be sure DirectXEventThread won't stay stuck in
+ * GetMessage, so we send a fake message */
+ if( p_vout->p_sys->hwnd )
+ PostMessage( p_vout->p_sys->hwnd, WM_NULL, 0, 0);
+
+ vlc_mutex_unlock( &p_vout->p_sys->event_thread_lock );
vlc_thread_join( p_vout->p_sys->event_thread_id );
}
+ else
+ vlc_mutex_unlock( &p_vout->p_sys->event_thread_lock );
if( p_vout->p_sys != NULL )
{
/*
* Pointer change
*/
- if( ! p_vout->p_sys->b_cursor_autohidden &&
- ( mdate() - p_vout->p_sys->i_lastmoved > 5000000 ) )
+ if( (!p_vout->p_sys->b_cursor_hidden) &&
+ ( (mdate() - p_vout->p_sys->i_lastmoved) > 5000000 ) )
{
/* Hide the mouse automatically */
- p_vout->p_sys->b_cursor_autohidden = 1;
- ShowCursor( FALSE );
+ p_vout->p_sys->b_cursor_hidden = 1;
+ PostMessage( p_vout->p_sys->hwnd, WM_VLC_HIDE_MOUSE, 0, 0 );
}
-#if 0
- if( p_vout->i_changes & VOUT_CURSOR_CHANGE
- || p_vout->p_sys->i_changes & VOUT_CURSOR_CHANGE )
- {
- p_vout->p_sys->b_cursor = ! p_vout->p_sys->b_cursor;
-
- ShowCursor( p_vout->p_sys->b_cursor &&
- ! p_vout->p_sys->b_cursor_autohidden );
-
- 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 );
+ return 0;
}
/*****************************************************************************
/* We ask for the "NOTEARING" option */
memset( &ddbltfx, 0, sizeof(DDBLTFX) );
ddbltfx.dwSize = sizeof(DDBLTFX);
- ddbltfx.dwDDFX = DDBLTFX_NOTEARING | DDBLT_ASYNC;
+ ddbltfx.dwDDFX = DDBLTFX_NOTEARING;
/* Blit video surface to display */
- dxresult = IDirectDrawSurface3_Blt(p_vout->p_sys->p_display,
+ dxresult = IDirectDrawSurface2_Blt(p_vout->p_sys->p_display,
&p_vout->p_sys->rect_dest_clipped,
p_pic->p_sys->p_surface,
&p_vout->p_sys->rect_src_clipped,
- 0, &ddbltfx );
+ DDBLT_ASYNC, &ddbltfx );
if ( dxresult == DDERR_SURFACELOST )
{
/* Our surface can be lost so be sure
* to check this and restore it if needed */
- IDirectDrawSurface3_Restore( p_vout->p_sys->p_display );
+ IDirectDrawSurface2_Restore( p_vout->p_sys->p_display );
/* Now that the surface has been restored try to display again */
- dxresult = IDirectDrawSurface3_Blt(p_vout->p_sys->p_display,
+ dxresult = IDirectDrawSurface2_Blt(p_vout->p_sys->p_display,
&p_vout->p_sys->rect_dest_clipped,
p_pic->p_sys->p_surface,
&p_vout->p_sys->rect_src_clipped,
- 0, &ddbltfx );
+ DDBLT_ASYNC, &ddbltfx );
}
if( dxresult != DD_OK )
else /* using overlay */
{
-#if 0
- /* Flip the overlay buffers */
- dxresult = IDirectDrawSurface3_Flip( p_pic->p_sys->p_front_surface,
+ /* Flip the overlay buffers if we are using back buffers */
+ if( p_pic->p_sys->p_front_surface == p_pic->p_sys->p_surface )
+ return;
+
+ dxresult = IDirectDrawSurface2_Flip( p_pic->p_sys->p_front_surface,
NULL, DDFLIP_WAIT );
if ( dxresult == DDERR_SURFACELOST )
{
/* Our surface can be lost so be sure
* to check this and restore it if needed */
- IDirectDrawSurface3_Restore( p_vout->p_sys->p_display );
- IDirectDrawSurface3_Restore( p_pic->p_sys->p_front_surface );
+ IDirectDrawSurface2_Restore( p_vout->p_sys->p_display );
+ IDirectDrawSurface2_Restore( p_pic->p_sys->p_front_surface );
/* Now that the surface has been restored try to display again */
- dxresult = IDirectDrawSurface3_Flip( p_pic->p_sys->p_front_surface,
+ dxresult = IDirectDrawSurface2_Flip( p_pic->p_sys->p_front_surface,
NULL, DDFLIP_WAIT );
DirectXUpdateOverlay( p_vout );
}
if( dxresult != DD_OK )
intf_WarnMsg( 8, "vout: couldn't flip overlay surface" );
-#endif
+
if( !DirectXGetSurfaceDesc( p_pic ) )
{
if( p_vout->p_sys->hddraw_dll == NULL )
{
intf_WarnMsg( 3, "vout: DirectXInitDDraw failed loading ddraw.dll" );
- return( 1 );
+ goto error;
}
OurDirectDrawCreate =
if ( OurDirectDrawCreate == NULL )
{
intf_ErrMsg( "vout error: DirectXInitDDraw failed GetProcAddress" );
- FreeLibrary( p_vout->p_sys->hddraw_dll );
- p_vout->p_sys->hddraw_dll = NULL;
- return( 1 );
+ goto error;
}
/* Initialize DirectDraw now */
if( dxresult != DD_OK )
{
intf_ErrMsg( "vout error: DirectXInitDDraw can't initialize DDraw" );
- p_vout->p_sys->p_ddobject = NULL;
- FreeLibrary( p_vout->p_sys->hddraw_dll );
- p_vout->p_sys->hddraw_dll = NULL;
- return( 1 );
- }
-
- /* Set DirectDraw Cooperative level, ie what control we want over Windows
- * display */
- dxresult = IDirectDraw_SetCooperativeLevel( p_ddobject,
- p_vout->p_sys->hwnd, DDSCL_NORMAL );
- if( dxresult != DD_OK )
- {
- intf_ErrMsg( "vout error: can't set direct draw cooperative level." );
- IDirectDraw_Release( p_ddobject );
- p_vout->p_sys->p_ddobject = NULL;
- FreeLibrary( p_vout->p_sys->hddraw_dll );
- p_vout->p_sys->hddraw_dll = NULL;
- return( 1 );
+ goto error;
}
/* Get the IDirectDraw2 interface */
dxresult = IDirectDraw_QueryInterface( p_ddobject, &IID_IDirectDraw2,
(LPVOID *)&p_vout->p_sys->p_ddobject );
+ /* Release the unused interface */
+ IDirectDraw_Release( p_ddobject );
if( dxresult != DD_OK )
{
intf_ErrMsg( "vout error: can't get IDirectDraw2 interface." );
- IDirectDraw_Release( p_ddobject );
- p_vout->p_sys->p_ddobject = NULL;
- FreeLibrary( p_vout->p_sys->hddraw_dll );
- p_vout->p_sys->hddraw_dll = NULL;
- return( 1 );
+ goto error;
}
- else
+
+ /* Set DirectDraw Cooperative level, ie what control we want over Windows
+ * display */
+ dxresult = IDirectDraw2_SetCooperativeLevel( p_vout->p_sys->p_ddobject,
+ p_vout->p_sys->hwnd, DDSCL_NORMAL );
+ if( dxresult != DD_OK )
{
- /* Release the unused interface */
- IDirectDraw_Release( p_ddobject );
+ intf_ErrMsg( "vout error: can't set direct draw cooperative level." );
+ goto error;
}
/* Probe the capabilities of the hardware */
DirectXGetDDrawCaps( p_vout );
intf_WarnMsg( 3, "vout: End DirectXInitDDraw" );
- return( 0 );
+ return 0;
+
+ error:
+ if( p_vout->p_sys->p_ddobject )
+ IDirectDraw2_Release( p_vout->p_sys->p_ddobject );
+ if( p_vout->p_sys->hddraw_dll )
+ FreeLibrary( p_vout->p_sys->hddraw_dll );
+ p_vout->p_sys->hddraw_dll = NULL;
+ p_vout->p_sys->p_ddobject = NULL;
+ return 1;
}
/*****************************************************************************
if( dxresult != DD_OK )
{
intf_ErrMsg( "vout error: can't get direct draw primary surface." );
- p_vout->p_sys->p_display = NULL;
- return( 1 );
+ return 1;
}
dxresult = IDirectDrawSurface_QueryInterface( p_display,
- &IID_IDirectDrawSurface3,
+ &IID_IDirectDrawSurface2,
(LPVOID *)&p_vout->p_sys->p_display );
+ /* Release the old interface */
+ IDirectDrawSurface_Release( p_display );
if ( dxresult != DD_OK )
{
- intf_ErrMsg( "vout error: can't get IDirectDrawSurface3 interface." );
- IDirectDrawSurface_Release( p_display );
- p_vout->p_sys->p_display = NULL;
- return( 1 );
- }
- else
- {
- /* Release the old interface */
- IDirectDrawSurface_Release( p_display );
+ intf_ErrMsg( "vout error: can't get IDirectDrawSurface2 interface." );
+ return 1;
}
-
/* The clipper will be used only in non-overlay mode */
DirectXCreateClipper( p_vout );
/* 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,
+ dxresult = IDirectDrawSurface2_GetPixelFormat( p_vout->p_sys->p_display,
&pixel_format );
if( dxresult != DD_OK )
intf_WarnMsg( 3, "vout: DirectXUpdateOverlay GetPixelFormat failed" );
& pixel_format.dwRBitMask);
#endif
- return( 0 );
+ return 0;
}
if( dxresult != DD_OK )
{
intf_WarnMsg( 3, "vout: DirectXCreateClipper can't create clipper." );
- p_vout->p_sys->p_clipper = NULL;
- return( 1 );
+ goto error;
}
/* associate the clipper to the window */
{
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 );
+ goto error;
}
/* associate the clipper with the surface */
{
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 );
+ goto error;
}
- return( 0 );
+ return 0;
+
+ error:
+ if( p_vout->p_sys->p_clipper )
+ IDirectDrawClipper_Release( p_vout->p_sys->p_clipper );
+ p_vout->p_sys->p_clipper = NULL;
+ return 1;
}
/*****************************************************************************
* need to do any blitting to the main display...)
*****************************************************************************/
static int DirectXCreateSurface( vout_thread_t *p_vout,
- LPDIRECTDRAWSURFACE3 *pp_surface_final,
- int i_chroma, int b_overlay )
+ LPDIRECTDRAWSURFACE2 *pp_surface_final,
+ int i_chroma, int b_overlay,
+ int i_backbuffers )
{
HRESULT dxresult;
LPDIRECTDRAWSURFACE p_surface;
DDSURFACEDESC ddsd;
- intf_WarnMsg( 3, "vout: DirectXCreateSurface" );
-
/* Create the video surface */
if( b_overlay )
{
ddsd.dwFlags = DDSD_CAPS |
DDSD_HEIGHT |
DDSD_WIDTH |
- //DDSD_BACKBUFFERCOUNT |
DDSD_PIXELFORMAT;
+ ddsd.dwFlags |= (i_backbuffers ? DDSD_BACKBUFFERCOUNT : 0);
ddsd.ddsCaps.dwCaps = DDSCAPS_OVERLAY |
- //DDSCAPS_COMPLEX |
- //DDSCAPS_FLIP |
DDSCAPS_VIDEOMEMORY;
+ ddsd.ddsCaps.dwCaps |= (i_backbuffers ? DDSCAPS_COMPLEX | DDSCAPS_FLIP
+ : 0 );
ddsd.dwHeight = p_vout->render.i_height;
ddsd.dwWidth = p_vout->render.i_width;
- ddsd.dwBackBufferCount = 1; /* One back buffer */
+ ddsd.dwBackBufferCount = i_backbuffers;
dxresult = IDirectDraw2_CreateSurface( p_vout->p_sys->p_ddobject,
&ddsd,
&p_surface, NULL );
- if( dxresult == DD_OK )
- {
- intf_WarnMsg( 3,"vout: DirectX YUV overlay created successfully" );
- }
- else
+ if( dxresult != DD_OK )
{
- intf_ErrMsg( "vout error: can't create YUV overlay surface." );
*pp_surface_final = NULL;
return 0;
}
if( !b_overlay )
{
- /* Now try to create a plain RGB surface. */
+ boolean_t b_rgb_surface = ( i_chroma == FOURCC_RGB2 ) ||
+ ( i_chroma == FOURCC_RV15 ) || ( i_chroma == FOURCC_RV16 ) ||
+ ( i_chroma == FOURCC_RV24 ) || ( i_chroma == FOURCC_RV32 );
+
memset( &ddsd, 0, sizeof( DDSURFACEDESC ) );
ddsd.dwSize = sizeof(DDSURFACEDESC);
+ ddsd.ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT);
ddsd.dwFlags = DDSD_HEIGHT |
DDSD_WIDTH |
DDSD_CAPS;
- ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN |
- DDSCAPS_SYSTEMMEMORY;
+ ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
ddsd.dwHeight = p_vout->render.i_height;
ddsd.dwWidth = p_vout->render.i_width;
+ if( p_vout->p_sys->b_use_sysmem )
+ ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
+ else
+ ddsd.ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY;
+
+ if( !b_rgb_surface )
+ {
+ ddsd.dwFlags |= DDSD_PIXELFORMAT;
+ ddsd.ddpfPixelFormat.dwFlags = DDPF_FOURCC;
+ ddsd.ddpfPixelFormat.dwFourCC = i_chroma;
+ }
+
dxresult = IDirectDraw2_CreateSurface( p_vout->p_sys->p_ddobject,
&ddsd,
&p_surface, NULL );
- if( dxresult == DD_OK )
- {
- intf_WarnMsg( 3,"vout: DirectX RGB surface created successfully" );
- }
- else
+ if( dxresult != DD_OK )
{
- intf_ErrMsg( "vout error: can't create RGB surface." );
*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,
+ &IID_IDirectDrawSurface2,
(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." );
+ intf_ErrMsg( "vout error: can't get IDirectDrawSurface2 interface." );
*pp_surface_final = NULL;
return 0;
}
return 1;
}
-
/*****************************************************************************
* DirectXUpdateOverlay: Move or resize overlay surface on video display.
*****************************************************************************
if( p_vout->p_sys->p_current_surface == NULL ||
!p_vout->p_sys->b_using_overlay )
- {
- intf_WarnMsg( 5, "vout: DirectXUpdateOverlay no overlay !!" );
return;
- }
/* The new window dimensions should already have been computed by the
* caller of this function */
if( !p_vout->p_sys->b_caps_overlay_clipping )
dwFlags |= DDOVER_KEYDESTOVERRIDE;
- dxresult = IDirectDrawSurface3_UpdateOverlay(
+ dxresult = IDirectDrawSurface2_UpdateOverlay(
p_vout->p_sys->p_current_surface,
&p_vout->p_sys->rect_src_clipped,
p_vout->p_sys->p_display,
if( p_vout->p_sys->p_clipper != NULL )
{
intf_WarnMsg( 3, "vout: DirectXCloseDisplay clipper" );
- IDirectDraw2_Release( p_vout->p_sys->p_clipper );
+ IDirectDrawClipper_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 );
+ IDirectDrawSurface2_Release( p_vout->p_sys->p_display );
p_vout->p_sys->p_display = NULL;
}
}
* This function returns all resources allocated for the surface.
*****************************************************************************/
static void DirectXCloseSurface( vout_thread_t *p_vout,
- LPDIRECTDRAWSURFACE3 p_surface )
+ LPDIRECTDRAWSURFACE2 p_surface )
{
intf_WarnMsg( 3, "vout: DirectXCloseSurface" );
if( p_surface != NULL )
{
- IDirectDraw2_Release( p_surface );
+ IDirectDrawSurface2_Release( p_surface );
}
}
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( )
- {
- case 8: /* FIXME: set the palette */
- p_vout->output.i_chroma = FOURCC_RGB2; 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_RV24; break;
- case 32:
- p_vout->output.i_chroma = FOURCC_RV32; break;
- default:
- intf_ErrMsg( "vout error: unknown screen depth" );
- return( 0 );
- }
-#endif
+ boolean_t b_result_ok;
+ LPDIRECTDRAWSURFACE2 p_surface;
intf_WarnMsg( 3, "vout: NewPictureVec" );
I_OUTPUTPICTURES = 0;
- /* chroma asked for */
- p_vout->output.i_chroma = p_vout->render.i_chroma;
-
- /* hack */
-#if 1
- if( p_vout->render.i_chroma == FOURCC_I420 )
- p_vout->output.i_chroma = FOURCC_YV12;
-#endif
-
- /* 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. */
+ /* First we try to use an YUV overlay surface.
+ * The overlay surface that we create won't be used to decode directly
+ * into it because accessing video memory directly is way to slow (remember
+ * that pictures are decoded macroblock per macroblock). Instead the video
+ * will be decoded in picture buffers in system memory which will then be
+ * memcpy() to the overlay surface. */
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 ) )
+ /* Triple buffering rocks! it doesn't have any processing overhead
+ * (you don't have to wait for the vsync) and provides for a very nice
+ * video quality (no tearing). */
+
+ b_result_ok = DirectXCreateSurface( p_vout, &p_surface,
+ p_vout->output.i_chroma,
+ p_vout->p_sys->b_using_overlay,
+ 2 /* number of backbuffers */ );
+
+ if( !b_result_ok )
+ /* Try to reduce the number of backbuffers */
+ b_result_ok = DirectXCreateSurface( p_vout, &p_surface,
+ p_vout->output.i_chroma,
+ p_vout->p_sys->b_using_overlay,
+ 0 /* number of backbuffers */);
+
+ if( b_result_ok )
{
DDSCAPS dds_caps;
+ picture_t front_pic;
+ picture_sys_t front_pic_sys;
+ front_pic.p_sys = &front_pic_sys;
/* Allocate internal structure */
p_pic[0].p_sys = malloc( sizeof( picture_sys_t ) );
p_pic[0].p_sys->p_front_surface = p_surface;
/* Get the back buffer */
- memset( &dds_caps, 0, sizeof( DDSCAPS ));
+ memset( &dds_caps, 0, sizeof( DDSCAPS ) );
dds_caps.dwCaps = DDSCAPS_BACKBUFFER;
- if( DD_OK != IDirectDrawSurface3_GetAttachedSurface(
+ if( DD_OK != IDirectDrawSurface2_GetAttachedSurface(
p_surface, &dds_caps,
&p_pic[0].p_sys->p_surface ) )
{
}
- p_vout->p_sys->p_current_surface= p_pic[0].p_sys->p_front_surface;
+ p_vout->p_sys->p_current_surface = front_pic.p_sys->p_surface =
+ p_pic[0].p_sys->p_front_surface;
+
+ /* reset the front buffer memory */
+ if( DirectXGetSurfaceDesc( &front_pic ) &&
+ UpdatePictureStruct( p_vout, &front_pic,
+ p_vout->output.i_chroma ) )
+ {
+ int i,j;
+ for( i = 0; i < front_pic.i_planes; i++ )
+ for( j = 0; j < front_pic.p[i].i_lines; j++)
+ memset( front_pic.p[i].p_pixels + j *
+ front_pic.p[i].i_pitch, 127,
+ front_pic.p[i].i_visible_bytes );
+ }
+
DirectXUpdateOverlay( p_vout );
I_OUTPUTPICTURES = 1;
+ intf_WarnMsg( 3,"vout: DirectX YUV overlay created successfully" );
}
- else p_vout->p_sys->b_using_overlay = 0;
}
- /* As we can't have overlays, we'll 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 */
+ /* As we can't have an overlay, we'll try to create a plain offscreen
+ * surface. This surface will reside in video memory because there's a
+ * better chance then that we'll be able to use some kind of hardware
+ * acceleration like rescaling, blitting or YUV->RGB conversions.
+ * We then only need to blit this surface onto the main display when we
+ * want to display it */
if( !p_vout->p_sys->b_using_overlay )
{
- /* FixMe */
- p_vout->output.i_chroma = FOURCC_RV16;
- p_vout->output.i_rmask = 0x001f;
- p_vout->output.i_gmask = 0x03e0;
- p_vout->output.i_bmask = 0x7c00;
+ b_result_ok = 0;
- for( i = 0; i < i_num_pics; i++ )
+ if( p_vout->p_sys->b_hw_yuv )
+ b_result_ok = DirectXCreateSurface( p_vout, &p_surface,
+ p_vout->output.i_chroma,
+ p_vout->p_sys->b_using_overlay,
+ 0 /* no back buffers */ );
+
+ if( !p_vout->p_sys->b_hw_yuv || !b_result_ok )
{
- if( DirectXCreateSurface( p_vout, &p_surface,
- p_vout->output.i_chroma,
- p_vout->p_sys->b_using_overlay ) )
+ /* Our last choice is to use a plain RGB surface */
+ DDPIXELFORMAT ddpfPixelFormat;
+
+ ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT);
+ IDirectDrawSurface2_GetPixelFormat( p_vout->p_sys->p_display,
+ &ddpfPixelFormat );
+
+ if( ddpfPixelFormat.dwFlags & DDPF_RGB )
{
- /* Allocate internal structure */
- p_pic[i].p_sys = malloc( sizeof( picture_sys_t ) );
- if( p_pic[i].p_sys == NULL )
+ switch( ddpfPixelFormat.dwRGBBitCount )
{
- DirectXCloseSurface( p_vout, p_surface );
- FreePictureVec( p_vout, p_pic, I_OUTPUTPICTURES );
- I_OUTPUTPICTURES = 0;
- return -1;
+ case 8: /* FIXME: set the palette */
+ p_vout->output.i_chroma = FOURCC_RGB2; 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_RV24; break;
+ case 32:
+ p_vout->output.i_chroma = FOURCC_RV32; break;
+ default:
+ intf_ErrMsg( "vout error: unknown screen depth" );
+ return 0;
}
- p_pic[i].p_sys->p_surface = p_surface;
- p_pic[i].p_sys->p_front_surface = NULL;
- I_OUTPUTPICTURES++;
+ p_vout->output.i_rmask = ddpfPixelFormat.dwRBitMask;
+ p_vout->output.i_gmask = ddpfPixelFormat.dwGBitMask;
+ p_vout->output.i_bmask = ddpfPixelFormat.dwBBitMask;
+ }
+
+ p_vout->p_sys->b_hw_yuv = 0;
+
+ b_result_ok = DirectXCreateSurface( p_vout, &p_surface,
+ p_vout->output.i_chroma,
+ p_vout->p_sys->b_using_overlay,
+ 0 /* no back buffers */ );
+ }
+ if( b_result_ok )
+ {
+ /* 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;
}
- else break;
+ p_pic[0].p_sys->p_surface = p_pic[0].p_sys->p_front_surface
+ = p_surface;
+
+ I_OUTPUTPICTURES = 1;
+
+ intf_WarnMsg( 3, "vout: DirectX plain surface created "
+ "successfully" );
}
}
for( i = 0; i < i_num_pics; i++ )
{
-#if 0
- if( p_pic->p_sys->p_front_surface &&
- ( p_pic->p_sys->p_surface != p_pic->p_sys->p_front_surface ) )
- DirectXCloseSurface( p_vout, p_pic[i].p_sys->p_front_surface );
-#endif
-
- DirectXCloseSurface( p_vout, p_pic[i].p_sys->p_surface );
+ DirectXCloseSurface( p_vout, p_pic[i].p_sys->p_front_surface );
for( i = 0; i < i_num_pics; i++ )
{
switch( p_vout->output.i_chroma )
{
+ case FOURCC_RGB2:
+ case FOURCC_RV15:
+ case FOURCC_RV16:
+ case FOURCC_RV24:
+ case FOURCC_RV32:
+ 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->b_margin = 0;
+ p_pic->i_planes = 1;
+ switch( p_vout->output.i_chroma )
+ {
+ case FOURCC_RGB2:
+ p_pic->p->i_pixel_bytes = 1;
+ break;
+ case FOURCC_RV15:
+ case FOURCC_RV16:
+ p_pic->p->i_pixel_bytes = 2;
+ break;
+ case FOURCC_RV24:
+ case FOURCC_RV32:
+ p_pic->p->i_pixel_bytes = 4;
+ break;
+ default:
+ return -1;
+ }
+ p_pic->p->i_visible_bytes = p_vout->output.i_width *
+ p_pic->p->i_pixel_bytes;
+ break;
+
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].i_visible_bytes = p_vout->output.i_width *
+ p_pic->p[Y_PLANE].i_pixel_bytes;
p_pic->p[Y_PLANE].b_margin = 0;
p_pic->V_PIXELS = p_pic->Y_PIXELS
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].i_visible_bytes = p_vout->output.i_width *
+ p_pic->p[V_PLANE].i_pixel_bytes;
p_pic->p[V_PLANE].b_margin = 0;
p_pic->U_PIXELS = p_pic->V_PIXELS
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].i_visible_bytes = p_vout->output.i_width *
+ p_pic->p[U_PLANE].i_pixel_bytes;
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->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->i_planes = 1;
- break;
-
- case FOURCC_I420:
+ case FOURCC_IYUV:
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].i_visible_bytes = p_vout->output.i_width *
+ p_pic->p[Y_PLANE].i_pixel_bytes;
p_pic->p[Y_PLANE].b_margin = 0;
p_pic->U_PIXELS = p_pic->Y_PIXELS
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].i_visible_bytes = p_vout->output.i_width *
+ p_pic->p[U_PLANE].i_pixel_bytes;
p_pic->p[U_PLANE].b_margin = 0;
- p_pic->V_PIXELS = p_pic->U_PIXELS
+ 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[Y_PLANE].i_pitch / 2;
p_pic->p[V_PLANE].i_pixel_bytes = 1;
+ p_pic->p[V_PLANE].i_visible_bytes = p_vout->output.i_width *
+ p_pic->p[V_PLANE].i_pixel_bytes;
p_pic->p[V_PLANE].b_margin = 0;
p_pic->i_planes = 3;
break;
-#if 0
- 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->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->p_image->pitches[0];
- p_pic->p->i_pixel_bytes = 4;
- p_pic->p->b_margin = 0;
+ p_pic->p->i_pitch = p_pic->p_sys->ddsd.lPitch;
+ p_pic->p->i_pixel_bytes = 2;
+ p_pic->p->i_visible_bytes = p_vout->output.i_width *
+ p_pic->p->i_pixel_bytes;
+ p_pic->p->b_margin = 1;
p_pic->i_planes = 1;
break;
-#endif
default:
/* Not supported */
*****************************************************************************/
static int DirectXGetSurfaceDesc( picture_t *p_pic )
{
- HRESULT dxresult;
+ 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,
+ dxresult = IDirectDrawSurface2_Lock( p_pic->p_sys->p_surface,
NULL, &p_pic->p_sys->ddsd,
- DDLOCK_NOSYSLOCK,
+ 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,
+ dxresult = IDirectDrawSurface2_Restore( p_pic->p_sys->p_surface );
+ dxresult = IDirectDrawSurface2_Lock( p_pic->p_sys->p_surface, NULL,
&p_pic->p_sys->ddsd,
DDLOCK_NOSYSLOCK | DDLOCK_WAIT,
NULL);
}
/* Unlock the Surface */
- dxresult = IDirectDrawSurface3_Unlock( p_pic->p_sys->p_surface, NULL );
+ dxresult = IDirectDrawSurface2_Unlock( p_pic->p_sys->p_surface, NULL );
return 1;
}