* vout.c: Windows DirectX video output display method
*****************************************************************************
* Copyright (C) 2001 VideoLAN
- * $Id: directx.c,v 1.4 2002/10/22 21:10:28 sam Exp $
+ * $Id: directx.c,v 1.16 2003/03/30 18:14:39 gbazin Exp $
*
* Authors: Gildas Bazin <gbazin@netcourrier.com>
*
* surfaces that will be blitted onto the primary surface (display) to
* effectively display the pictures. This fallback method also enables us to
* display video in window mode.
- *
+ *
*****************************************************************************/
#include <errno.h> /* ENOMEM */
#include <stdlib.h> /* free() */
LPDIRECTDRAWSURFACE2 );
static int DirectXCreateClipper ( vout_thread_t *p_vout );
static void DirectXGetDDrawCaps ( vout_thread_t *p_vout );
-static int DirectXGetSurfaceDesc ( picture_t *p_pic );
+static int DirectXLockSurface ( vout_thread_t *p_vout, picture_t *p_pic );
+static int DirectXUnlockSurface ( vout_thread_t *p_vout, picture_t *p_pic );
/*****************************************************************************
* Module descriptor
*****************************************************************************/
+#define ON_TOP_TEXT N_("always on top")
+#define ON_TOP_LONGTEXT N_("place the directx window on top of other windows")
#define HW_YUV_TEXT N_("use hardware YUV->RGB conversions")
#define HW_YUV_LONGTEXT N_( \
"Try to use hardware acceleration for YUV->RGB conversions. " \
"isn't recommended as usually using video memory allows to benefit from " \
"more hardware acceleration (like rescaling or YUV->RGB conversions). " \
"This option doesn't have any effect when using overlays." )
+#define TRIPLEBUF_TEXT N_("use triple buffering for overlays")
+#define TRIPLEBUF_LONGTEXT N_( \
+ "Try to use triple bufferring when using YUV overlays. That results in " \
+ "much better video quality (no flickering)." )
vlc_module_begin();
- add_category_hint( N_("Video"), NULL );
- add_bool( "directx-hw-yuv", 1, NULL, HW_YUV_TEXT, HW_YUV_LONGTEXT );
- add_bool( "directx-use-sysmem", 0, NULL, SYSMEM_TEXT, SYSMEM_LONGTEXT );
- set_description( _("DirectX video module") );
+ add_category_hint( N_("Video"), NULL, VLC_FALSE );
+ add_bool( "directx-on-top", 0, NULL, ON_TOP_TEXT, ON_TOP_LONGTEXT, VLC_FALSE );
+ add_bool( "directx-hw-yuv", 1, NULL, HW_YUV_TEXT, HW_YUV_LONGTEXT, VLC_TRUE );
+ add_bool( "directx-use-sysmem", 0, NULL, SYSMEM_TEXT, SYSMEM_LONGTEXT, VLC_TRUE );
+ add_bool( "directx-3buffering", 1, NULL, TRIPLEBUF_TEXT, TRIPLEBUF_LONGTEXT, VLC_TRUE );
+ set_description( _("DirectX video output") );
set_capability( "video output", 100 );
add_shortcut( "directx" );
set_callbacks( OpenVideo, CloseVideo );
static int OpenVideo( vlc_object_t *p_this )
{
vout_thread_t * p_vout = (vout_thread_t *)p_this;
+ vlc_value_t val;
/* Allocate structure */
p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
if( p_vout->p_sys == NULL )
{
msg_Err( p_vout, "out of memory" );
- return 1;
+ return VLC_ENOMEM;
}
/* Initialisations */
p_vout->p_sys->p_clipper = NULL;
p_vout->p_sys->hbrush = NULL;
p_vout->p_sys->hwnd = NULL;
+ p_vout->p_sys->hparent = NULL;
p_vout->p_sys->i_changes = 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_GetInt( p_vout, "overlay" );
p_vout->p_sys->b_use_sysmem = config_GetInt( p_vout, "directx-use-sysmem");
p_vout->p_sys->b_hw_yuv = config_GetInt( p_vout, "directx-hw-yuv" );
+ p_vout->p_sys->b_3buf_overlay = config_GetInt( p_vout, "directx-3buffering" );
p_vout->p_sys->b_cursor_hidden = 0;
p_vout->p_sys->i_lastmoved = mdate();
p_vout->p_sys->p_event->p_vout = p_vout;
if( vlc_thread_create( p_vout->p_sys->p_event,
"DirectX Events Thread", DirectXEventThread,
- VLC_THREAD_PRIORITY_LOW, 1 ) )
+ 0, 1 ) )
{
msg_Err( p_vout, "cannot create DirectXEventThread" );
vlc_object_destroy( p_vout->p_sys->p_event );
goto error;
}
- return 0;
+ /* Add a variable to indicate if the window should be on top of others */
+ var_Create( p_vout, "directx-on-top", VLC_VAR_BOOL );
+ val.b_bool = config_GetInt( p_vout, "directx-on-top" );
+ var_Set( p_vout, "directx-on-top", val );
+
+ return VLC_SUCCESS;
error:
CloseVideo( VLC_OBJECT(p_vout) );
- return 1;
-
+ return VLC_EGENERIC;
}
/*****************************************************************************
if( !I_OUTPUTPICTURES )
{
/* hmmm, it didn't work! Let's try commonly supported chromas */
- p_vout->output.i_chroma = VLC_FOURCC('Y','V','1','2');
- NewPictureVec( p_vout, p_vout->p_picture, MAX_DIRECTBUFFERS );
+ if( p_vout->output.i_chroma != VLC_FOURCC('Y','V','1','2') )
+ {
+ p_vout->output.i_chroma = VLC_FOURCC('Y','V','1','2');
+ NewPictureVec( p_vout, p_vout->p_picture, MAX_DIRECTBUFFERS );
+ }
if( !I_OUTPUTPICTURES )
{
- /* hmmm, it didn't work! Let's try commonly supported chromas */
+ /* hmmm, it still didn't work! Let's try another one */
p_vout->output.i_chroma = VLC_FOURCC('Y','U','Y','2');
NewPictureVec( p_vout, p_vout->p_picture, MAX_DIRECTBUFFERS );
}
}
/* Change the window title bar text */
- if( p_vout->p_sys->b_using_overlay )
+ if( p_vout->p_sys->hparent )
+ ; /* Do nothing */
+ else if( p_vout->p_sys->b_using_overlay )
SetWindowText( p_vout->p_sys->hwnd,
VOUT_TITLE " (hardware YUV overlay DirectX output)" );
else if( p_vout->p_sys->b_hw_yuv )
else SetWindowText( p_vout->p_sys->hwnd,
VOUT_TITLE " (software RGB DirectX output)" );
- return 0;
+ return VLC_SUCCESS;
}
/*****************************************************************************
* Terminate an output method created by Create
*****************************************************************************/
static void CloseVideo( vlc_object_t *p_this )
-{
+{
vout_thread_t * p_vout = (vout_thread_t *)p_this;
-
+
msg_Dbg( p_vout, "CloseVideo" );
+ var_Destroy( p_vout, "directs-on-top" );
+
DirectXCloseDisplay( p_vout );
DirectXCloseDDraw( p_vout );
vlc_object_detach( p_vout->p_sys->p_event );
/* Kill DirectXEventThread */
- p_vout->p_sys->p_event->b_die = 1;
+ p_vout->p_sys->p_event->b_die = VLC_TRUE;
/* 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_thread_join( p_vout->p_sys->p_event );
vlc_object_destroy( p_vout->p_sys->p_event );
static int Manage( vout_thread_t *p_vout )
{
WINDOWPLACEMENT window_placement;
+ HWND hwnd;
+ HMENU hMenu;
+ vlc_value_t val;
+
+ /* If we do not control our window, we check for geometry changes
+ * ourselves because the parent might not send us its events. */
+ if( p_vout->p_sys->hparent )
+ {
+ DirectXUpdateRects( p_vout, VLC_FALSE );
+ }
/* 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
* decided to isolate PeekMessage in another thread. */
/*
- * Scale Change
+ * Scale Change
*/
if( p_vout->i_changes & VOUT_SCALE_CHANGE
- || p_vout->p_sys->i_changes & VOUT_SCALE_CHANGE)
+ || p_vout->p_sys->i_changes & VOUT_SCALE_CHANGE )
{
- msg_Dbg( p_vout, "Scale Change" );
+ msg_Dbg( p_vout, "scale change" );
if( !p_vout->p_sys->b_using_overlay )
InvalidateRect( p_vout->p_sys->hwnd, NULL, TRUE );
else
}
/*
- * Size Change
+ * Size Change
*/
if( p_vout->i_changes & VOUT_SIZE_CHANGE
|| p_vout->p_sys->i_changes & VOUT_SIZE_CHANGE )
{
- msg_Dbg( p_vout, "Size Change" );
+ msg_Dbg( p_vout, "size change" );
if( !p_vout->p_sys->b_using_overlay )
InvalidateRect( p_vout->p_sys->hwnd, NULL, TRUE );
else
( (mdate() - p_vout->p_sys->i_lastmoved) > 5000000 ) )
{
/* Hide the mouse automatically */
- p_vout->p_sys->b_cursor_hidden = 1;
- PostMessage( p_vout->p_sys->hwnd, WM_VLC_HIDE_MOUSE, 0, 0 );
+ if( p_vout->p_sys->hwnd != p_vout->p_sys->hparent )
+ {
+ p_vout->p_sys->b_cursor_hidden = VLC_TRUE;
+ PostMessage( p_vout->p_sys->hwnd, WM_VLC_HIDE_MOUSE, 0, 0 );
+ }
+ }
+
+ /*
+ * "Always on top" status change
+ */
+ hwnd = p_vout->p_sys->hwnd;
+ hMenu = GetSystemMenu( hwnd , FALSE );
+ var_Get( p_vout, "directx-on-top", &val );
+ if( val.b_bool )
+ {
+ /* Set the window on top if necessary */
+ if( !( GetWindowLong( hwnd, GWL_EXSTYLE ) & WS_EX_TOPMOST ) )
+ {
+ CheckMenuItem( hMenu, IDM_TOGGLE_ON_TOP,
+ MF_BYCOMMAND | MFS_CHECKED );
+ SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, 0, 0,
+ SWP_NOSIZE | SWP_NOMOVE );
+ }
+ }
+ else
+ {
+ /* The window shouldn't be on top */
+ if( GetWindowLong( hwnd, GWL_EXSTYLE ) & WS_EX_TOPMOST )
+ {
+ CheckMenuItem( hMenu, IDM_TOGGLE_ON_TOP,
+ MF_BYCOMMAND | MFS_UNCHECKED );
+ SetWindowPos( hwnd, HWND_NOTOPMOST, 0, 0, 0, 0,
+ SWP_NOSIZE | SWP_NOMOVE );
+ }
}
/* Check if the event thread is still running */
if( p_vout->p_sys->p_event->b_die )
- return 1; /* exit */
+ {
+ return VLC_EGENERIC; /* exit */
+ }
- return 0;
+ return VLC_SUCCESS;
}
/*****************************************************************************
return;
}
+ /* Our surface can be lost so be sure to check this
+ * and restore it if need be */
+ if( IDirectDrawSurface2_IsLost( p_vout->p_sys->p_display )
+ == DDERR_SURFACELOST )
+ {
+ if( IDirectDrawSurface2_Restore( p_vout->p_sys->p_display ) == DD_OK &&
+ p_vout->p_sys->b_using_overlay )
+ DirectXUpdateOverlay( p_vout );
+ }
+
if( !p_vout->p_sys->b_using_overlay )
{
DDBLTFX ddbltfx;
ddbltfx.dwDDFX = DDBLTFX_NOTEARING;
/* Blit video surface to 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,
- DDBLT_ASYNC, &ddbltfx );
- if ( dxresult == DDERR_SURFACELOST )
- {
- /* Our surface can be lost so be sure
- * to check this and restore it if needed */
- IDirectDrawSurface2_Restore( p_vout->p_sys->p_display );
-
- /* Now that the surface has been restored try to display again */
- 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,
- DDBLT_ASYNC, &ddbltfx );
- }
-
+ 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,
+ DDBLT_ASYNC, &ddbltfx );
if( dxresult != DD_OK )
{
- msg_Warn( p_vout, "could not Blit the surface" );
+ msg_Warn( p_vout, "could not blit surface (error %i)", dxresult );
return;
}
}
else /* using overlay */
{
-
/* 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 */
- 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 = IDirectDrawSurface2_Flip( p_pic->p_sys->p_front_surface,
- NULL, DDFLIP_WAIT );
- DirectXUpdateOverlay( p_vout );
- }
-
if( dxresult != DD_OK )
- msg_Warn( p_vout, "could not flip overlay surface" );
-
- if( !DirectXGetSurfaceDesc( p_pic ) )
{
- /* AAARRGG */
- msg_Err( p_vout, "cannot get surface desc" );
- return;
+ msg_Warn( p_vout, "could not flip overlay (error %i)", dxresult );
}
- if( !UpdatePictureStruct( p_vout, p_pic, p_vout->output.i_chroma ) )
+ /* set currently displayed pic */
+ p_vout->p_sys->p_current_surface = p_pic->p_sys->p_front_surface;
+
+ /* Lock surface to get all the required info */
+ if( DirectXLockSurface( p_vout, p_pic ) )
{
/* AAARRGG */
- msg_Err( p_vout, "invalid pic chroma" );
+ msg_Warn( p_vout, "cannot lock surface" );
return;
}
-
- /* set currently displayed pic */
- p_vout->p_sys->p_current_surface = p_pic->p_sys->p_front_surface;
+ DirectXUnlockSurface( p_vout, p_pic );
}
-
}
msg_Warn( p_vout, "DirectXInitDDraw failed loading ddraw.dll" );
goto error;
}
-
- OurDirectDrawCreate =
+
+ OurDirectDrawCreate =
(void *)GetProcAddress(p_vout->p_sys->hddraw_dll, "DirectDrawCreate");
if ( OurDirectDrawCreate == NULL )
{
DirectXGetDDrawCaps( p_vout );
msg_Dbg( p_vout, "End DirectXInitDDraw" );
- return 0;
+ return VLC_SUCCESS;
error:
if( p_vout->p_sys->p_ddobject )
FreeLibrary( p_vout->p_sys->hddraw_dll );
p_vout->p_sys->hddraw_dll = NULL;
p_vout->p_sys->p_ddobject = NULL;
- return 1;
+ return VLC_EGENERIC;
}
/*****************************************************************************
&p_display, NULL );
if( dxresult != DD_OK )
{
- msg_Err( p_vout, "cannot get direct draw primary surface" );
- return 1;
+ msg_Err( p_vout, "cannot get primary surface (error %i)", dxresult );
+ return VLC_EGENERIC;
}
dxresult = IDirectDrawSurface_QueryInterface( p_display,
IDirectDrawSurface_Release( p_display );
if ( dxresult != DD_OK )
{
- msg_Err( p_vout, "cannot get IDirectDrawSurface2 interface" );
- return 1;
+ msg_Err( p_vout, "cannot query IDirectDrawSurface2 interface "
+ "(error %i)", dxresult );
+ return VLC_EGENERIC;
}
/* The clipper will be used only in non-overlay mode */
dxresult = IDirectDrawSurface2_GetPixelFormat( p_vout->p_sys->p_display,
&pixel_format );
if( dxresult != DD_OK )
- msg_Warn( p_vout, "DirectXUpdateOverlay GetPixelFormat failed" );
+ {
+ msg_Warn( p_vout, "DirectXUpdateOverlay GetPixelFormat failed "
+ "(error %i)", dxresult );
+ }
p_vout->p_sys->i_colorkey = (DWORD)((( p_vout->p_sys->i_rgb_colorkey
* pixel_format.dwRBitMask) / 255)
- & pixel_format.dwRBitMask);
+ & pixel_format.dwRBitMask );
#endif
- return 0;
+ return VLC_SUCCESS;
}
&p_vout->p_sys->p_clipper, NULL );
if( dxresult != DD_OK )
{
- msg_Warn( p_vout, "DirectXCreateClipper cannot create clipper" );
+ msg_Warn( p_vout, "cannot create clipper (error %i)", dxresult );
goto error;
}
- /* associate the clipper to the window */
+ /* 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 )
{
- msg_Warn( p_vout,
- "DirectXCreateClipper cannot attach clipper to window" );
+ msg_Warn( p_vout, "cannot attach clipper to window (error %i)",
+ dxresult );
goto error;
}
p_vout->p_sys->p_clipper);
if( dxresult != DD_OK )
{
- msg_Warn( p_vout,
- "DirectXCreateClipper cannot attach clipper to surface" );
+ msg_Warn( p_vout, "cannot attach clipper to surface (error %i)",
+ dxresult );
goto error;
- }
+ }
- return 0;
+ return VLC_SUCCESS;
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;
-
+ return VLC_EGENERIC;
}
/*****************************************************************************
if( dxresult != DD_OK )
{
*pp_surface_final = NULL;
- return 0;
+ return VLC_EGENERIC;
}
}
if( dxresult != DD_OK )
{
*pp_surface_final = NULL;
- return 0;
+ return VLC_EGENERIC;
}
}
IDirectDrawSurface_Release( p_surface ); /* Release the old interface */
if ( dxresult != DD_OK )
{
- msg_Err( p_vout, "cannot get IDirectDrawSurface2 interface" );
+ msg_Err( p_vout, "cannot query IDirectDrawSurface2 interface "
+ "(error %i)", dxresult );
*pp_surface_final = NULL;
- return 0;
+ return VLC_EGENERIC;
}
- return 1;
+ return VLC_SUCCESS;
}
/*****************************************************************************
&p_vout->p_sys->rect_src_clipped,
p_vout->p_sys->p_display,
&p_vout->p_sys->rect_dest_clipped,
- dwFlags,
- &ddofx );
+ dwFlags, &ddofx );
if(dxresult != DD_OK)
{
msg_Warn( p_vout,
"DirectXUpdateOverlay cannot move or resize overlay" );
}
-
}
/*****************************************************************************
int i_num_pics )
{
int i;
- vlc_bool_t b_result_ok;
+ int i_ret = VLC_SUCCESS;
LPDIRECTDRAWSURFACE2 p_surface;
- msg_Dbg( p_vout, "NewPictureVec" );
+ msg_Dbg( p_vout, "NewPictureVec overlay:%s chroma:%.4s",
+ p_vout->p_sys->b_using_overlay ? "yes" : "no",
+ (char *)&p_vout->output.i_chroma );
I_OUTPUTPICTURES = 0;
/* 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). */
+ if( p_vout->p_sys->b_3buf_overlay )
+ i_ret = DirectXCreateSurface( p_vout, &p_surface,
+ p_vout->output.i_chroma,
+ p_vout->p_sys->b_using_overlay,
+ 2 /* number of backbuffers */ );
- 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 )
+ if( !p_vout->p_sys->b_3buf_overlay || i_ret != VLC_SUCCESS )
+ {
/* 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 */);
+ i_ret = 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 )
+ if( i_ret == VLC_SUCCESS )
{
DDSCAPS dds_caps;
picture_t front_pic;
if( p_pic[0].p_sys == NULL )
{
DirectXCloseSurface( p_vout, p_surface );
- return -1;
+ return VLC_ENOMEM;
}
/* set front buffer */
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 ) )
+ /* Reset the front buffer memory */
+ if( DirectXLockSurface( p_vout, &front_pic ) == VLC_SUCCESS )
{
int i,j;
for( i = 0; i < front_pic.i_planes; i++ )
memset( front_pic.p[i].p_pixels + j *
front_pic.p[i].i_pitch, 127,
front_pic.p[i].i_visible_pitch );
+
+ DirectXUnlockSurface( p_vout, &front_pic );
}
DirectXUpdateOverlay( p_vout );
I_OUTPUTPICTURES = 1;
- msg_Dbg( p_vout, "DirectX YUV overlay created successfully" );
+ msg_Dbg( p_vout, "YUV overlay created successfully" );
}
}
* want to display it */
if( !p_vout->p_sys->b_using_overlay )
{
-
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 */ );
+ {
+ i_ret = DirectXCreateSurface( p_vout, &p_surface,
+ p_vout->output.i_chroma,
+ 0 /* no overlay */,
+ 0 /* no back buffers */ );
+ }
- if( !p_vout->p_sys->b_hw_yuv || !b_result_ok )
+ if( i_ret || !p_vout->p_sys->b_hw_yuv )
{
/* Our last choice is to use a plain RGB surface */
DDPIXELFORMAT ddpfPixelFormat;
break;
default:
msg_Err( p_vout, "unknown screen depth" );
- return 0;
+ return VLC_EGENERIC;
}
p_vout->output.i_rmask = ddpfPixelFormat.dwRBitMask;
p_vout->output.i_gmask = ddpfPixelFormat.dwGBitMask;
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 */ );
+ i_ret = DirectXCreateSurface( p_vout, &p_surface,
+ p_vout->output.i_chroma,
+ 0 /* no overlay */,
+ 0 /* no back buffers */ );
+
+ if( i_ret && !p_vout->p_sys->b_use_sysmem )
+ {
+ /* Give it a last try with b_use_sysmem enabled */
+ p_vout->p_sys->b_use_sysmem = 1;
+
+ i_ret = DirectXCreateSurface( p_vout, &p_surface,
+ p_vout->output.i_chroma,
+ 0 /* no overlay */,
+ 0 /* no back buffers */ );
+ }
}
- if( b_result_ok )
+ if( i_ret == VLC_SUCCESS )
{
/* 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;
+ return VLC_ENOMEM;
}
+
p_pic[0].p_sys->p_surface = p_pic[0].p_sys->p_front_surface
= p_surface;
I_OUTPUTPICTURES = 1;
- msg_Dbg( p_vout, "DirectX plain surface created successfully" );
+ msg_Dbg( p_vout, "created plain surface of chroma:%.4s",
+ (char *)&p_vout->output.i_chroma );
}
}
{
p_pic[i].i_status = DESTROYED_PICTURE;
p_pic[i].i_type = DIRECT_PICTURE;
+ p_pic[i].pf_lock = DirectXLockSurface;
+ p_pic[i].pf_unlock = DirectXUnlockSurface;
PP_OUTPUTPICTURE[i] = &p_pic[i];
- if( !DirectXGetSurfaceDesc( &p_pic[i] ) )
+ if( DirectXLockSurface( p_vout, &p_pic[i] ) != VLC_SUCCESS )
{
/* 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 */
- msg_Err( p_vout, "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;
+ msg_Err( p_vout, "cannot lock surface" );
+ return VLC_EGENERIC;
}
+ DirectXUnlockSurface( p_vout, &p_pic[i] );
}
- msg_Dbg( p_vout, "End NewPictureVec");
- return 0;
+ msg_Dbg( p_vout, "End NewPictureVec (%s)",
+ I_OUTPUTPICTURES ? "succeeded" : "failed" );
+
+ return VLC_SUCCESS;
}
/*****************************************************************************
* FreePicture: destroy a picture vector allocated with NewPictureVec
*****************************************************************************
- *
+ *
*****************************************************************************/
static void FreePictureVec( vout_thread_t *p_vout, picture_t *p_pic,
int i_num_pics )
static int UpdatePictureStruct( vout_thread_t *p_vout, picture_t *p_pic,
int i_chroma )
{
-
switch( p_vout->output.i_chroma )
{
case VLC_FOURCC('R','G','B','2'):
p_pic->p->i_pixel_pitch = 4;
break;
default:
- return -1;
+ return VLC_EGENERIC;
}
p_pic->p->i_visible_pitch = p_vout->output.i_width *
p_pic->p->i_pixel_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_pitch = 1;
- p_pic->p[V_PLANE].i_visible_pitch = p_vout->output.i_width *
+ p_pic->p[V_PLANE].i_visible_pitch = p_vout->output.i_width / 2 *
p_pic->p[V_PLANE].i_pixel_pitch;
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_pitch = 1;
- p_pic->p[U_PLANE].i_visible_pitch = p_vout->output.i_width *
+ p_pic->p[U_PLANE].i_visible_pitch = p_vout->output.i_width / 2 *
p_pic->p[U_PLANE].i_pixel_pitch;
p_pic->i_planes = 3;
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_pitch = 1;
- p_pic->p[U_PLANE].i_visible_pitch = p_vout->output.i_width *
+ p_pic->p[U_PLANE].i_visible_pitch = p_vout->output.i_width / 2 *
p_pic->p[U_PLANE].i_pixel_pitch;
p_pic->V_PIXELS = p_pic->U_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_pitch = 1;
- p_pic->p[V_PLANE].i_visible_pitch = p_vout->output.i_width *
+ p_pic->p[V_PLANE].i_visible_pitch = p_vout->output.i_width / 2 *
p_pic->p[V_PLANE].i_pixel_pitch;
p_pic->i_planes = 3;
break;
default:
- /* Not supported */
- return 0;
-
+ /* Unknown chroma, tell the guy to get lost */
+ msg_Err( p_vout, "never heard of chroma 0x%.8x (%4.4s)",
+ p_vout->output.i_chroma,
+ (char*)&p_vout->output.i_chroma );
+ return VLC_EGENERIC;
}
- return 1;
+ return VLC_SUCCESS;
}
/*****************************************************************************
}
/*****************************************************************************
- * DirectXGetSurfaceDesc: Get some more information about the surface
+ * DirectXLockSurface: Lock surface and get picture data pointer
*****************************************************************************
- * This function get and stores the surface descriptor which among things
- * has the pointer to the picture data.
+ * This function locks a surface and get the surface descriptor which amongst
+ * other things has the pointer to the picture data.
*****************************************************************************/
-static int DirectXGetSurfaceDesc( picture_t *p_pic )
+static int DirectXLockSurface( vout_thread_t *p_vout, picture_t *p_pic )
{
HRESULT dxresult;
NULL, &p_pic->p_sys->ddsd,
DDLOCK_NOSYSLOCK | DDLOCK_WAIT,
NULL );
- if ( dxresult == DDERR_SURFACELOST )
+ if( dxresult != DD_OK )
{
- /* Your surface can be lost so be sure
- * to check this and restore it if needed */
- dxresult = IDirectDrawSurface2_Restore( p_pic->p_sys->p_surface );
- dxresult = IDirectDrawSurface2_Lock( p_pic->p_sys->p_surface, NULL,
+ if( dxresult == DDERR_INVALIDPARAMS )
+ {
+ /* DirectX 3 doesn't support the DDLOCK_NOSYSLOCK flag, resulting
+ * in an invalid params error */
+ dxresult = IDirectDrawSurface2_Lock( p_pic->p_sys->p_surface, NULL,
&p_pic->p_sys->ddsd,
- DDLOCK_NOSYSLOCK | DDLOCK_WAIT,
- NULL);
+ DDLOCK_WAIT, NULL);
+ }
+ if( dxresult == DDERR_SURFACELOST )
+ {
+ /* Your surface can be lost so be sure
+ * to check this and restore it if needed */
+
+ /* When using overlays with back-buffers, we need to restore
+ * the front buffer so the back-buffers get restored as well. */
+ if( p_vout->p_sys->b_using_overlay )
+ IDirectDrawSurface2_Restore( p_pic->p_sys->p_front_surface );
+ else
+ IDirectDrawSurface2_Restore( p_pic->p_sys->p_surface );
+
+ dxresult = IDirectDrawSurface2_Lock( p_pic->p_sys->p_surface, NULL,
+ &p_pic->p_sys->ddsd,
+ DDLOCK_WAIT, NULL);
+ if( dxresult == DDERR_SURFACELOST )
+ msg_Dbg( p_vout, "DirectXLockSurface: DDERR_SURFACELOST" );
+ }
+ if( dxresult != DD_OK )
+ {
+ return VLC_EGENERIC;
+ }
}
- if( dxresult != DD_OK )
+
+ /* Now we have a pointer to the surface memory, we can update our picture
+ * structure. */
+ if( UpdatePictureStruct( p_vout, p_pic, p_vout->output.i_chroma )
+ != VLC_SUCCESS )
{
-//X msg_Err( p_vout, "DirectXGetSurfaceDesc cannot lock surface" );
- return 0;
+ DirectXUnlockSurface( p_vout, p_pic );
+ return VLC_EGENERIC;
}
+ else
+ return VLC_SUCCESS;
+}
+/*****************************************************************************
+ * DirectXUnlockSurface: Unlock a surface locked by DirectXLockSurface().
+ *****************************************************************************/
+static int DirectXUnlockSurface( vout_thread_t *p_vout, picture_t *p_pic )
+{
/* Unlock the Surface */
- dxresult = IDirectDrawSurface2_Unlock( p_pic->p_sys->p_surface, NULL );
-
- return 1;
+ if( IDirectDrawSurface2_Unlock( p_pic->p_sys->p_surface, NULL ) == DD_OK )
+ return VLC_SUCCESS;
+ else
+ return VLC_EGENERIC;
}