/*****************************************************************************
* vout.c: Windows DirectX video output display method
*****************************************************************************
- * Copyright (C) 2001 VideoLAN
- * $Id: directx.c,v 1.30 2003/12/23 02:11:27 gbazin Exp $
+ * Copyright (C) 2001-2004 VideoLAN
+ * $Id$
*
- * Authors: Gildas Bazin <gbazin@netcourrier.com>
+ * Authors: Gildas Bazin <gbazin@videolan.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
static DWORD DirectXFindColorkey( vout_thread_t *p_vout, uint32_t i_color );
/* Object variables callbacks */
-static int OnTopCallback( vlc_object_t *, char const *,
- vlc_value_t, vlc_value_t, void * );
+static int FindDevicesCallback( vlc_object_t *, char const *,
+ vlc_value_t, vlc_value_t, void * );
/*****************************************************************************
* Module descriptor
#define HW_YUV_LONGTEXT N_( \
"Try to use hardware acceleration for YUV->RGB conversions. " \
"This option doesn't have any effect when using overlays." )
+
#define SYSMEM_TEXT N_("Use video buffers in system memory")
#define SYSMEM_LONGTEXT N_( \
"Create video buffers in system memory instead of video memory. This " \
"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 " \
+ "Try to use triple buffering when using YUV overlays. That results in " \
"much better video quality (no flickering)." )
+#define DEVICE_TEXT N_("Name of desired display device")
+#define DEVICE_LONGTEXT N_("In a multiple monitor configuration, you can " \
+ "specify the Windows device name of the display that you want the video " \
+ "window to open on. For example, \"\\\\.\\DISPLAY1\" or " \
+ "\"\\\\.\\DISPLAY2\"." )
+
+static char *ppsz_dev[] = { "" };
+static char *ppsz_dev_text[] = { N_("Default") };
+
vlc_module_begin();
- add_category_hint( N_("Video"), NULL, 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 );
+ 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 );
+
+ add_string( "directx-device", "", NULL, DEVICE_TEXT, DEVICE_LONGTEXT,
+ VLC_TRUE );
+ change_string_list( ppsz_dev, ppsz_dev_text, FindDevicesCallback );
+ change_action_add( FindDevicesCallback, N_("Refresh list") );
+
set_description( _("DirectX video output") );
set_capability( "video output", 100 );
add_shortcut( "directx" );
static int OpenVideo( vlc_object_t *p_this )
{
vout_thread_t * p_vout = (vout_thread_t *)p_this;
- vlc_value_t val, text;
+ vlc_value_t val;
HMODULE huser32;
/* Allocate structure */
msg_Err( p_vout, "out of memory" );
return VLC_ENOMEM;
}
+ memset( p_vout->p_sys, 0, sizeof( vout_sys_t ) );
/* Initialisations */
p_vout->pf_init = Init;
p_vout->p_sys->p_display = NULL;
p_vout->p_sys->p_current_surface = NULL;
p_vout->p_sys->p_clipper = NULL;
- p_vout->p_sys->hwnd = NULL;
+ p_vout->p_sys->hwnd = p_vout->p_sys->hvideownd = NULL;
p_vout->p_sys->hparent = NULL;
p_vout->p_sys->i_changes = 0;
+ vlc_mutex_init( p_vout, &p_vout->p_sys->lock );
+ SetRectEmpty( &p_vout->p_sys->rect_display );
+ SetRectEmpty( &p_vout->p_sys->rect_parent );
/* Multimonitor stuff */
p_vout->p_sys->hmonitor = NULL;
var_Create( p_vout, "directx-use-sysmem", VLC_VAR_BOOL|VLC_VAR_DOINHERIT );
var_Create( p_vout, "directx-hw-yuv", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
var_Create( p_vout, "directx-3buffering", VLC_VAR_BOOL|VLC_VAR_DOINHERIT );
+ var_Create( p_vout, "directx-device", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
+ var_Create( p_vout, "video-title", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
p_vout->p_sys->b_cursor_hidden = 0;
p_vout->p_sys->i_lastmoved = mdate();
goto error;
}
- /* Add a variable to indicate if the window should be on top of others */
- var_Create( p_vout, "video-on-top", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
- text.psz_string = _("Always on top");
- var_Change( p_vout, "video-on-top", VLC_VAR_SETTEXT, &text, NULL );
+ /* Variable to indicate if the window should be on top of others */
+ /* Trigger a callback right now */
var_Get( p_vout, "video-on-top", &val );
- p_vout->p_sys->b_on_top_change = val.b_bool;
- var_AddCallback( p_vout, "video-on-top", OnTopCallback, NULL );
+ var_Set( p_vout, "video-on-top", val );
return VLC_SUCCESS;
}
/* Change the window title bar text */
- if( p_vout->p_sys->hparent ) ; /* Do nothing */
- else PostMessage( p_vout->p_sys->hwnd, WM_VLC_CHANGE_TEXT, 0, 0 );
+ PostMessage( p_vout->p_sys->hwnd, WM_VLC_CHANGE_TEXT, 0, 0 );
return VLC_SUCCESS;
}
msg_Dbg( p_vout, "CloseVideo" );
- var_Destroy( p_vout, "video-on-top" );
-
if( p_vout->p_sys->p_event )
{
vlc_object_detach( p_vout->p_sys->p_event );
vlc_object_destroy( p_vout->p_sys->p_event );
}
+ vlc_mutex_destroy( &p_vout->p_sys->lock );
+
if( p_vout->p_sys )
{
free( p_vout->p_sys );
/* 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 )
+ vlc_mutex_lock( &p_vout->p_sys->lock );
+ if( p_vout->p_sys->hparent && !p_vout->b_fullscreen )
+ {
+ RECT rect_parent;
+ POINT point;
+
+ vlc_mutex_unlock( &p_vout->p_sys->lock );
+
+ GetClientRect( p_vout->p_sys->hparent, &rect_parent );
+ point.x = point.y = 0;
+ ClientToScreen( p_vout->p_sys->hparent, &point );
+ OffsetRect( &rect_parent, point.x, point.y );
+
+ if( !EqualRect( &rect_parent, &p_vout->p_sys->rect_parent ) )
+ {
+ p_vout->p_sys->rect_parent = rect_parent;
+
+ /* This one is to force the update even if only
+ * the position has changed */
+ SetWindowPos( p_vout->p_sys->hwnd, 0, 1, 1,
+ rect_parent.right - rect_parent.left,
+ rect_parent.bottom - rect_parent.top, 0 );
+
+ SetWindowPos( p_vout->p_sys->hwnd, 0, 0, 0,
+ rect_parent.right - rect_parent.left,
+ rect_parent.bottom - rect_parent.top, 0 );
+ }
+ }
+ else
{
- DirectXUpdateRects( p_vout, VLC_FALSE );
+ vlc_mutex_unlock( &p_vout->p_sys->lock );
}
/*
*/
if( p_vout->p_sys->i_changes & DX_POSITION_CHANGE )
{
- if( p_vout->p_sys->b_using_overlay )
- DirectXUpdateOverlay( p_vout );
+ p_vout->p_sys->i_changes &= ~DX_POSITION_CHANGE;
/* Check if we are still on the same monitor */
if( p_vout->p_sys->MonitorFromWindow &&
/* This will force the vout core to recreate the picture buffers */
p_vout->i_changes |= VOUT_PICTURE_BUFFERS_CHANGE;
}
-
- p_vout->p_sys->i_changes &= ~DX_POSITION_CHANGE;
}
/* We used to call the Win32 PeekMessage function here to read the window
if( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE
|| p_vout->p_sys->i_changes & VOUT_FULLSCREEN_CHANGE )
{
+ int i_style = 0;
vlc_value_t val;
p_vout->b_fullscreen = ! p_vout->b_fullscreen;
GetWindowPlacement( p_vout->p_sys->hwnd, &window_placement );
if( p_vout->b_fullscreen )
{
+ if( p_vout->p_sys->hparent )
+ {
+ SetParent( p_vout->p_sys->hwnd, GetDesktopWindow() );
+ SetForegroundWindow( p_vout->p_sys->hwnd );
+ }
+
/* Maximized window */
window_placement.showCmd = SW_SHOWMAXIMIZED;
/* Change window style, no borders and no title bar */
- SetWindowLong( p_vout->p_sys->hwnd, GWL_STYLE, WS_CLIPCHILDREN );
-
+ i_style = WS_CLIPCHILDREN;
}
else
{
+ if( p_vout->p_sys->hparent )
+ {
+ SetParent( p_vout->p_sys->hwnd, p_vout->p_sys->hparent );
+ i_style = WS_CLIPCHILDREN | WS_VISIBLE | WS_CHILD;
+ }
+ else
+ {
+ i_style = WS_CLIPCHILDREN | WS_OVERLAPPEDWINDOW |
+ WS_SIZEBOX | WS_VISIBLE;
+ }
+
/* Normal window */
window_placement.showCmd = SW_SHOWNORMAL;
- /* Change window style, borders and title bar */
- SetWindowLong( p_vout->p_sys->hwnd, GWL_STYLE, WS_CLIPCHILDREN |
- WS_OVERLAPPEDWINDOW | WS_SIZEBOX | WS_VISIBLE );
+
+ /* Make sure the mouse cursor is displayed */
+ PostMessage( p_vout->p_sys->hwnd, WM_VLC_SHOW_MOUSE, 0, 0 );
}
+ /* Change window style, borders and title bar */
+ SetWindowLong( p_vout->p_sys->hwnd, GWL_STYLE, i_style );
SetWindowPlacement( p_vout->p_sys->hwnd, &window_placement );
/* Update the object variable and trigger callback */
/*
* Pointer change
*/
- if( (!p_vout->p_sys->b_cursor_hidden) &&
- ( (mdate() - p_vout->p_sys->i_lastmoved) > 5000000 ) )
+ if( p_vout->b_fullscreen && !p_vout->p_sys->b_cursor_hidden &&
+ (mdate() - p_vout->p_sys->i_lastmoved) > 5000000 )
{
- /* Hide the mouse automatically */
- if( p_vout->p_sys->hwnd != p_vout->p_sys->hparent )
+ POINT point;
+ HWND hwnd;
+
+ /* Hide the cursor only if it is inside our window */
+ GetCursorPos( &point );
+ hwnd = WindowFromPoint(point);
+ if( hwnd == p_vout->p_sys->hwnd || hwnd == p_vout->p_sys->hvideownd )
{
- p_vout->p_sys->b_cursor_hidden = VLC_TRUE;
PostMessage( p_vout->p_sys->hwnd, WM_VLC_HIDE_MOUSE, 0, 0 );
}
+ else
+ {
+ p_vout->p_sys->i_lastmoved = mdate();
+ }
}
/*
HMENU hMenu = GetSystemMenu( p_vout->p_sys->hwnd, FALSE );
var_Get( p_vout, "video-on-top", &val );
-
+
/* Set the window on top if necessary */
if( val.b_bool && !( GetWindowLong( p_vout->p_sys->hwnd, GWL_EXSTYLE )
& WS_EX_TOPMOST ) )
if( (p_vout->p_sys->p_display == NULL) )
{
- msg_Warn( p_vout, "no display!!" );
+ msg_Warn( p_vout, "no display!" );
return;
}
/*****************************************************************************
* DirectXEnumCallback: Device enumeration
*****************************************************************************
- * This callback function is called by DirectDraw once for each
+ * This callback function is called by DirectDraw once for each
* available DirectDraw device.
*****************************************************************************/
BOOL WINAPI DirectXEnumCallback( GUID* p_guid, LPTSTR psz_desc,
HMONITOR hmon )
{
vout_thread_t *p_vout = (vout_thread_t *)p_context;
+ vlc_value_t device;
+
msg_Dbg( p_vout, "DirectXEnumCallback: %s, %s", psz_desc, psz_drivername );
- if( hmon && hmon == p_vout->p_sys->hmonitor )
+ if( hmon )
{
+ var_Get( p_vout, "directx-device", &device );
+
+ if( ( !device.psz_string || !*device.psz_string ) &&
+ hmon == p_vout->p_sys->hmonitor )
+ {
+ if( device.psz_string ) free( device.psz_string );
+ }
+ else if( strcmp( psz_drivername, device.psz_string ) == 0 )
+ {
+ MONITORINFO monitor_info;
+ monitor_info.cbSize = sizeof( MONITORINFO );
+
+ if( p_vout->p_sys->GetMonitorInfo( hmon, &monitor_info ) )
+ {
+ RECT rect;
+
+ /* Move window to the right screen */
+ GetWindowRect( p_vout->p_sys->hwnd, &rect );
+ if( !IntersectRect( &rect, &rect, &monitor_info.rcWork ) )
+ {
+ rect.left = monitor_info.rcWork.left;
+ rect.top = monitor_info.rcWork.top;
+ msg_Dbg( p_vout, "DirectXEnumCallback: Setting window "
+ "position to %d,%d", rect.left, rect.top );
+ SetWindowPos( p_vout->p_sys->hwnd, NULL,
+ rect.left, rect.top, 0, 0,
+ SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE );
+ }
+ }
+
+ p_vout->p_sys->hmonitor = hmon;
+ if( device.psz_string ) free( device.psz_string );
+ }
+ else
+ {
+ if( device.psz_string ) free( device.psz_string );
+ return TRUE; /* Keep enumerating */
+ }
+
msg_Dbg( p_vout, "selecting %s, %s", psz_desc, psz_drivername );
p_vout->p_sys->p_display_driver = malloc( sizeof(GUID) );
if( p_vout->p_sys->p_display_driver )
if( OurDirectDrawEnumerateEx && p_vout->p_sys->MonitorFromWindow )
{
+ vlc_value_t device;
+
+ var_Get( p_vout, "directx-device", &device );
+ if( device.psz_string )
+ {
+ msg_Dbg( p_vout, "directx-device: %s", device.psz_string );
+ free( device.psz_string );
+ }
+
p_vout->p_sys->hmonitor =
p_vout->p_sys->MonitorFromWindow( p_vout->p_sys->hwnd,
MONITOR_DEFAULTTONEAREST );
/* Enumerate displays */
- OurDirectDrawEnumerateEx( DirectXEnumCallback, p_vout,
+ OurDirectDrawEnumerateEx( DirectXEnumCallback, p_vout,
DDENUM_ATTACHEDSECONDARYDEVICES );
}
DDOVERLAYFX ddofx;
DWORD dwFlags;
HRESULT dxresult;
+ RECT rect_src = p_vout->p_sys->rect_src_clipped;
+ RECT rect_dest = p_vout->p_sys->rect_dest_clipped;
- if( p_vout->p_sys->p_current_surface == NULL ||
- !p_vout->p_sys->b_using_overlay )
+ if( !p_vout->p_sys->b_using_overlay ) return VLC_EGENERIC;
+
+ vlc_mutex_lock( &p_vout->p_sys->lock );
+ if( p_vout->p_sys->p_current_surface == NULL )
+ {
+ vlc_mutex_unlock( &p_vout->p_sys->lock );
return VLC_EGENERIC;
+ }
/* The new window dimensions should already have been computed by the
* caller of this function */
dwFlags = DDOVER_SHOW | DDOVER_KEYDESTOVERRIDE;
dxresult = IDirectDrawSurface2_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 );
+ p_vout->p_sys->p_current_surface,
+ &rect_src, p_vout->p_sys->p_display, &rect_dest,
+ dwFlags, &ddofx );
+
+ vlc_mutex_unlock( &p_vout->p_sys->lock );
+
if(dxresult != DD_OK)
{
- msg_Warn( p_vout,
- "DirectXUpdateOverlay cannot move or resize overlay" );
+ msg_Warn( p_vout, "DirectXUpdateOverlay cannot move/resize overlay" );
return VLC_EGENERIC;
}
{
int i;
+ vlc_mutex_lock( &p_vout->p_sys->lock );
+ p_vout->p_sys->p_current_surface = 0;
+ vlc_mutex_unlock( &p_vout->p_sys->lock );
+
for( i = 0; i < i_num_pics; i++ )
{
DirectXCloseSurface( p_vout, p_pic[i].p_sys->p_front_surface );
free( p_pic[i].p_sys );
}
}
-
- p_vout->p_sys->p_current_surface = 0;
}
/*****************************************************************************
}
else
{
- BOOL bHasOverlay, bHasOverlayFourCC, bCanDeinterlace,
- bHasColorKey, bCanStretch, bCanBltFourcc;
+ vlc_bool_t bHasOverlay, bHasOverlayFourCC, bCanDeinterlace,
+ bHasColorKey, bCanStretch, bCanBltFourcc,
+ bAlignBoundarySrc, bAlignBoundaryDest,
+ bAlignSizeSrc, bAlignSizeDest;
/* Determine if the hardware supports overlay surfaces */
- bHasOverlay = ((ddcaps.dwCaps & DDCAPS_OVERLAY) ==
- DDCAPS_OVERLAY) ? TRUE : FALSE;
+ bHasOverlay = (ddcaps.dwCaps & DDCAPS_OVERLAY) ? 1 : 0;
/* Determine if the hardware supports overlay surfaces */
- bHasOverlayFourCC = ((ddcaps.dwCaps & DDCAPS_OVERLAYFOURCC) ==
- DDCAPS_OVERLAYFOURCC) ? TRUE : FALSE;
+ bHasOverlayFourCC = (ddcaps.dwCaps & DDCAPS_OVERLAYFOURCC) ? 1 : 0;
/* Determine if the hardware supports overlay deinterlacing */
- bCanDeinterlace = ((ddcaps.dwCaps & DDCAPS2_CANFLIPODDEVEN) ==
- 0 ) ? TRUE : FALSE;
+ bCanDeinterlace = (ddcaps.dwCaps & DDCAPS2_CANFLIPODDEVEN) ? 1 : 0;
/* Determine if the hardware supports colorkeying */
- bHasColorKey = ((ddcaps.dwCaps & DDCAPS_COLORKEY) ==
- DDCAPS_COLORKEY) ? TRUE : FALSE;
+ bHasColorKey = (ddcaps.dwCaps & DDCAPS_COLORKEY) ? 1 : 0;
/* Determine if the hardware supports scaling of the overlay surface */
- bCanStretch = ((ddcaps.dwCaps & DDCAPS_OVERLAYSTRETCH) ==
- DDCAPS_OVERLAYSTRETCH) ? TRUE : FALSE;
+ bCanStretch = (ddcaps.dwCaps & DDCAPS_OVERLAYSTRETCH) ? 1 : 0;
/* Determine if the hardware supports color conversion during a blit */
- bCanBltFourcc = ((ddcaps.dwCaps & DDCAPS_BLTFOURCC ) ==
- DDCAPS_BLTFOURCC) ? TRUE : FALSE;
-
+ bCanBltFourcc = (ddcaps.dwCaps & DDCAPS_BLTFOURCC) ? 1 : 0;
+ /* Determine overlay source boundary alignment */
+ bAlignBoundarySrc = (ddcaps.dwCaps & DDCAPS_ALIGNBOUNDARYSRC) ? 1 : 0;
+ /* Determine overlay destination boundary alignment */
+ bAlignBoundaryDest = (ddcaps.dwCaps & DDCAPS_ALIGNBOUNDARYDEST) ? 1:0;
+ /* Determine overlay destination size alignment */
+ bAlignSizeSrc = (ddcaps.dwCaps & DDCAPS_ALIGNSIZESRC) ? 1 : 0;
+ /* Determine overlay destination size alignment */
+ bAlignSizeDest = (ddcaps.dwCaps & DDCAPS_ALIGNSIZEDEST) ? 1 : 0;
+
msg_Dbg( p_vout, "DirectDraw Capabilities: overlay=%i yuvoverlay=%i "
"can_deinterlace_overlay=%i colorkey=%i stretch=%i "
"bltfourcc=%i",
bHasOverlay, bHasOverlayFourCC, bCanDeinterlace,
bHasColorKey, bCanStretch, bCanBltFourcc );
+ if( bAlignBoundarySrc || bAlignBoundaryDest ||
+ bAlignSizeSrc || bAlignSizeDest )
+ {
+ if( bAlignBoundarySrc ) p_vout->p_sys->i_align_src_boundary =
+ ddcaps.dwAlignBoundarySrc;
+ if( bAlignBoundaryDest ) p_vout->p_sys->i_align_dest_boundary =
+ ddcaps.dwAlignBoundaryDest;
+ if( bAlignSizeDest ) p_vout->p_sys->i_align_src_size =
+ ddcaps.dwAlignSizeSrc;
+ if( bAlignSizeDest ) p_vout->p_sys->i_align_dest_size =
+ ddcaps.dwAlignSizeDest;
+
+ msg_Dbg( p_vout, "align_boundary_src=%i,%i "
+ "align_boundary_dest=%i,%i "
+ "align_size_src=%i,%i align_size_dest=%i,%i",
+ bAlignBoundarySrc, p_vout->p_sys->i_align_src_boundary,
+ bAlignBoundaryDest, p_vout->p_sys->i_align_dest_boundary,
+ bAlignSizeSrc, p_vout->p_sys->i_align_src_size,
+ bAlignSizeDest, p_vout->p_sys->i_align_dest_size );
+ }
+
/* Don't ask for troubles */
- if( !bCanBltFourcc ) p_vout->p_sys->b_hw_yuv = FALSE;
+ if( !bCanBltFourcc ) p_vout->p_sys->b_hw_yuv = FALSE;
}
}
return VLC_EGENERIC;
}
else
- return VLC_SUCCESS;
+ return VLC_SUCCESS;
}
/*****************************************************************************
case 16:
*(uint16_t *)ddsd.lpSurface = 0x01;
break;
- case 24:
- *(uint32_t *)ddsd.lpSurface = 0x0100;
- break;
- case 32:
+ default:
*(uint32_t *)ddsd.lpSurface = 0x01;
break;
}
}
/*****************************************************************************
- * object variables callbacks: a bunch of object variables are used by the
- * interfaces to interact with the vout.
+ * config variable callback
*****************************************************************************/
-static int OnTopCallback( vlc_object_t *p_this, char const *psz_cmd,
- vlc_value_t oldval, vlc_value_t newval, void *p_data )
+BOOL WINAPI DirectXEnumCallback2( GUID* p_guid, LPTSTR psz_desc,
+ LPTSTR psz_drivername, VOID* p_context,
+ HMONITOR hmon )
{
- vout_thread_t *p_vout = (vout_thread_t *)p_this;
- p_vout->p_sys->b_on_top_change = VLC_TRUE;
+ module_config_t *p_item = (module_config_t *)p_context;
+
+ p_item->ppsz_list =
+ (char **)realloc( p_item->ppsz_list,
+ (p_item->i_list+2) * sizeof(char *) );
+ p_item->ppsz_list_text =
+ (char **)realloc( p_item->ppsz_list_text,
+ (p_item->i_list+2) * sizeof(char *) );
+
+ p_item->ppsz_list[p_item->i_list] = strdup( psz_drivername );
+ p_item->ppsz_list_text[p_item->i_list] = NULL;
+ p_item->i_list++;
+ p_item->ppsz_list[p_item->i_list] = NULL;
+ p_item->ppsz_list_text[p_item->i_list] = NULL;
+
+ return TRUE; /* Keep enumerating */
+}
+
+static int FindDevicesCallback( vlc_object_t *p_this, char const *psz_name,
+ vlc_value_t newval, vlc_value_t oldval, void *d)
+{
+ HRESULT (WINAPI *OurDirectDrawEnumerateEx)( LPDDENUMCALLBACKEXA, LPVOID,
+ DWORD );
+ HINSTANCE hddraw_dll;
+
+ module_config_t *p_item;
+ int i;
+
+ p_item = config_FindConfig( p_this, psz_name );
+ if( !p_item ) return VLC_SUCCESS;
+
+ /* Clear-up the current list */
+ if( p_item->i_list )
+ {
+ /* Keep the first entry */
+ for( i = 1; i < p_item->i_list; i++ )
+ {
+ free( p_item->ppsz_list[i] );
+ free( p_item->ppsz_list_text[i] );
+ }
+ /* TODO: Remove when no more needed */
+ p_item->ppsz_list[i] = NULL;
+ p_item->ppsz_list_text[i] = NULL;
+ }
+ p_item->i_list = 1;
+
+ /* Load direct draw DLL */
+ hddraw_dll = LoadLibrary("DDRAW.DLL");
+ if( hddraw_dll == NULL ) return VLC_SUCCESS;
+
+ OurDirectDrawEnumerateEx =
+ (void *)GetProcAddress( hddraw_dll, "DirectDrawEnumerateExA" );
+
+ if( OurDirectDrawEnumerateEx )
+ {
+ /* Enumerate displays */
+ OurDirectDrawEnumerateEx( DirectXEnumCallback2, p_item,
+ DDENUM_ATTACHEDSECONDARYDEVICES );
+ }
+
+ FreeLibrary( hddraw_dll );
+
return VLC_SUCCESS;
}