/*****************************************************************************
* vout.c: Windows DirectX video output display method
*****************************************************************************
- * Copyright (C) 2001 VideoLAN
- * $Id: directx.c,v 1.7 2002/11/26 10:55:19 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
* 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() */
#include <windows.h>
#include <ddraw.h>
-#include "netutils.h"
+#include <multimon.h>
+#undef GetSystemMetrics
+
+#ifndef MONITOR_DEFAULTTONEAREST
+# define MONITOR_DEFAULTTONEAREST 2
+#endif
#include "vout.h"
LPDIRECTDRAWSURFACE2 );
static int DirectXCreateClipper ( vout_thread_t *p_vout );
static void DirectXGetDDrawCaps ( vout_thread_t *p_vout );
-static int DirectXGetSurfaceDesc ( vout_thread_t *p_vout, 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 );
+
+static DWORD DirectXFindColorkey( vout_thread_t *p_vout, uint32_t i_color );
+
+/* Object variables callbacks */
+static int FindDevicesCallback( vlc_object_t *, char const *,
+ vlc_value_t, vlc_value_t, void * );
/*****************************************************************************
* Module descriptor
*****************************************************************************/
-#define HW_YUV_TEXT N_("use hardware YUV->RGB conversions")
+#define HW_YUV_TEXT N_("Use hardware YUV->RGB conversions")
#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_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 WINDOW_TEXT N_("specify an existing window")
-#define WINDOW_LONGTEXT N_( \
- "Specify a window to use instead of opening a new one. This option is " \
- "DANGEROUS, use with care." )
+
+#define TRIPLEBUF_TEXT N_("Use triple buffering for overlays")
+#define TRIPLEBUF_LONGTEXT N_( \
+ "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 );
- add_bool( "directx-hw-yuv", 1, NULL, HW_YUV_TEXT, HW_YUV_LONGTEXT );
- add_bool( "directx-use-sysmem", 0, NULL, SYSMEM_TEXT, SYSMEM_LONGTEXT );
- add_integer( "directx-window", 0, NULL, WINDOW_TEXT, WINDOW_LONGTEXT );
- set_description( _("DirectX video module") );
+ 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" );
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;
+ HMODULE huser32;
/* Allocate structure */
p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
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->hbrush = 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;
- p_vout->p_sys->b_caps_overlay_clipping = 0;
+ vlc_mutex_init( p_vout, &p_vout->p_sys->lock );
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" );
+ SetRectEmpty( &p_vout->p_sys->rect_parent );
+
+ /* Multimonitor stuff */
+ p_vout->p_sys->hmonitor = NULL;
+ p_vout->p_sys->p_display_driver = NULL;
+ p_vout->p_sys->MonitorFromWindow = NULL;
+ p_vout->p_sys->GetMonitorInfo = NULL;
+ if( (huser32 = GetModuleHandle( "USER32" ) ) )
+ {
+ p_vout->p_sys->MonitorFromWindow =
+ GetProcAddress( huser32, "MonitorFromWindow" );
+ p_vout->p_sys->GetMonitorInfo =
+ GetProcAddress( huser32, "GetMonitorInfoA" );
+ }
+
+ var_Create( p_vout, "overlay", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
+ 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();
p_vout->p_sys->p_event =
vlc_object_create( p_vout, sizeof(event_thread_t) );
p_vout->p_sys->p_event->p_vout = p_vout;
- if( vlc_thread_create( p_vout->p_sys->p_event,
- "DirectX Events Thread", DirectXEventThread,
- 0, 1 ) )
+ if( vlc_thread_create( p_vout->p_sys->p_event, "DirectX Events Thread",
+ DirectXEventThread, 0, 1 ) )
{
msg_Err( p_vout, "cannot create DirectXEventThread" );
vlc_object_destroy( p_vout->p_sys->p_event );
goto error;
}
+ /* 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 );
+ var_Set( p_vout, "video-on-top", val );
+
return VLC_SUCCESS;
error:
static int Init( vout_thread_t *p_vout )
{
int i_chroma_backup;
+ vlc_value_t val;
+
+ /* Get a few default parameters */
+ var_Get( p_vout, "overlay", &val );
+ p_vout->p_sys->b_using_overlay = val.b_bool;
+ var_Get( p_vout, "directx-use-sysmem", &val );
+ p_vout->p_sys->b_use_sysmem = val.b_bool;
+ var_Get( p_vout, "directx-hw-yuv", &val );
+ p_vout->p_sys->b_hw_yuv = val.b_bool;
+ var_Get( p_vout, "directx-3buffering", &val );
+ p_vout->p_sys->b_3buf_overlay = val.b_bool;
+
+ /* Initialise DirectDraw if not already done.
+ * We do this here because on multi-monitor systems we may have to
+ * re-create the directdraw surfaces. */
+ if( !p_vout->p_sys->p_ddobject &&
+ DirectXInitDDraw( p_vout ) != VLC_SUCCESS )
+ {
+ msg_Err( p_vout, "cannot initialize DirectDraw" );
+ return VLC_EGENERIC;
+ }
+
+ /* Create the directx display */
+ if( !p_vout->p_sys->p_display &&
+ DirectXCreateDisplay( p_vout ) != VLC_SUCCESS )
+ {
+ msg_Err( p_vout, "cannot initialize DirectDraw" );
+ return VLC_EGENERIC;
+ }
/* Initialize the output structure.
* Since DirectDraw can do rescaling for us, stick to the default
}
/* Change the window title bar text */
- 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 )
- 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)" );
+ PostMessage( p_vout->p_sys->hwnd, WM_VLC_CHANGE_TEXT, 0, 0 );
return VLC_SUCCESS;
}
static void End( vout_thread_t *p_vout )
{
FreePictureVec( p_vout, p_vout->p_picture, I_OUTPUTPICTURES );
+
+ DirectXCloseDisplay( p_vout );
+ DirectXCloseDDraw( p_vout );
+
return;
}
* 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" );
- DirectXCloseDisplay( p_vout );
- DirectXCloseDDraw( p_vout );
+ msg_Dbg( p_vout, "CloseVideo" );
if( 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 )
{
- DirectXUpdateRects( p_vout, VLC_FALSE );
- }
+ RECT rect_parent;
+ POINT point;
- /* 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
- * long time (for example when you move your window on the screen), I
- * decided to isolate PeekMessage in another thread. */
+ vlc_mutex_unlock( &p_vout->p_sys->lock );
- /*
- * Scale Change
- */
- if( p_vout->i_changes & VOUT_SCALE_CHANGE
- || p_vout->p_sys->i_changes & VOUT_SCALE_CHANGE )
+ 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
{
- msg_Dbg( p_vout, "scale change" );
- 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_SCALE_CHANGE;
- p_vout->p_sys->i_changes &= ~VOUT_SCALE_CHANGE;
+ vlc_mutex_unlock( &p_vout->p_sys->lock );
}
/*
- * Size Change
+ * Position Change
*/
- if( p_vout->i_changes & VOUT_SIZE_CHANGE
- || p_vout->p_sys->i_changes & VOUT_SIZE_CHANGE )
+ if( p_vout->p_sys->i_changes & DX_POSITION_CHANGE )
{
- msg_Dbg( p_vout, "size change" );
- 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;
+ p_vout->p_sys->i_changes &= ~DX_POSITION_CHANGE;
+
+ /* Check if we are still on the same monitor */
+ if( p_vout->p_sys->MonitorFromWindow &&
+ p_vout->p_sys->hmonitor !=
+ p_vout->p_sys->MonitorFromWindow( p_vout->p_sys->hwnd,
+ MONITOR_DEFAULTTONEAREST ) )
+ {
+ /* This will force the vout core to recreate the picture buffers */
+ p_vout->i_changes |= VOUT_PICTURE_BUFFERS_CHANGE;
+ }
}
+ /* 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
+ * long time (for example when you move your window on the screen), I
+ * decided to isolate PeekMessage in another thread. */
+
/*
* Fullscreen change
*/
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;
/* We need to switch between Maximized and Normal sized window */
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, 0 );
-
+ 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_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 */
+ val.b_bool = p_vout->b_fullscreen;
+ var_Set( p_vout, "fullscreen", val );
+
p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
p_vout->p_sys->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
}
/*
* 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();
+ }
+ }
+
+ /*
+ * "Always on top" status change
+ */
+ if( p_vout->p_sys->b_on_top_change )
+ {
+ vlc_value_t val;
+ 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 ) )
+ {
+ CheckMenuItem( hMenu, IDM_TOGGLE_ON_TOP,
+ MF_BYCOMMAND | MFS_CHECKED );
+ SetWindowPos( p_vout->p_sys->hwnd, HWND_TOPMOST, 0, 0, 0, 0,
+ SWP_NOSIZE | SWP_NOMOVE );
+ }
+ else
+ /* The window shouldn't be on top */
+ if( !val.b_bool && ( GetWindowLong( p_vout->p_sys->hwnd, GWL_EXSTYLE )
+ & WS_EX_TOPMOST ) )
+ {
+ CheckMenuItem( hMenu, IDM_TOGGLE_ON_TOP,
+ MF_BYCOMMAND | MFS_UNCHECKED );
+ SetWindowPos( p_vout->p_sys->hwnd, HWND_NOTOPMOST, 0, 0, 0, 0,
+ SWP_NOSIZE | SWP_NOMOVE );
+ }
+
+ p_vout->p_sys->b_on_top_change = VLC_FALSE;
}
/* Check if the event thread is still running */
if( (p_vout->p_sys->p_display == NULL) )
{
- msg_Warn( p_vout, "no display!!" );
+ msg_Warn( p_vout, "no display!" );
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;
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 );
- }
-
if( dxresult != DD_OK )
{
- msg_Warn( p_vout, "could not blit surface (error %i)", dxresult );
+ msg_Warn( p_vout, "could not blit surface (error %li)", dxresult );
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 (error %i)", dxresult );
+ msg_Warn( p_vout, "could not flip overlay (error %li)", dxresult );
}
- if( DirectXGetSurfaceDesc( p_vout, p_pic ) )
+ /* 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, "cannot get surface desc" );
+ msg_Warn( p_vout, "cannot lock surface" );
return;
}
+ DirectXUnlockSurface( p_vout, p_pic );
+ }
+}
- if( UpdatePictureStruct( p_vout, p_pic, p_vout->output.i_chroma ) )
+/* following functions are local */
+
+/*****************************************************************************
+ * DirectXEnumCallback: Device enumeration
+ *****************************************************************************
+ * This callback function is called by DirectDraw once for each
+ * available DirectDraw device.
+ *****************************************************************************/
+BOOL WINAPI DirectXEnumCallback( GUID* p_guid, LPTSTR psz_desc,
+ LPTSTR psz_drivername, VOID* p_context,
+ 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 )
+ {
+ var_Get( p_vout, "directx-device", &device );
+
+ if( ( !device.psz_string || !*device.psz_string ) &&
+ hmon == p_vout->p_sys->hmonitor )
{
- /* AAARRGG */
- msg_Err( p_vout, "invalid pic chroma" );
- return;
+ 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 );
- /* set currently displayed pic */
- p_vout->p_sys->p_current_surface = p_pic->p_sys->p_front_surface;
- }
-}
+ 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 );
+ }
+ }
-/* following functions are local */
+ 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 )
+ memcpy( p_vout->p_sys->p_display_driver, p_guid, sizeof(GUID) );
+ }
+
+ return TRUE; /* Keep enumerating */
+}
/*****************************************************************************
* DirectXInitDDraw: Takes care of all the DirectDraw initialisations
*****************************************************************************/
static int DirectXInitDDraw( vout_thread_t *p_vout )
{
- HRESULT dxresult;
- HRESULT (WINAPI *OurDirectDrawCreate)(GUID *,LPDIRECTDRAW *,IUnknown *);
- LPDIRECTDRAW p_ddobject;
+ HRESULT dxresult;
+ HRESULT (WINAPI *OurDirectDrawCreate)(GUID *,LPDIRECTDRAW *,IUnknown *);
+ HRESULT (WINAPI *OurDirectDrawEnumerateEx)( LPDDENUMCALLBACKEXA, LPVOID,
+ DWORD );
+ LPDIRECTDRAW p_ddobject;
msg_Dbg( p_vout, "DirectXInitDDraw" );
- /* load direct draw DLL */
+ /* Load direct draw DLL */
p_vout->p_sys->hddraw_dll = LoadLibrary("DDRAW.DLL");
if( p_vout->p_sys->hddraw_dll == NULL )
{
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 )
+ if( OurDirectDrawCreate == NULL )
{
msg_Err( p_vout, "DirectXInitDDraw failed GetProcAddress" );
goto error;
}
+ OurDirectDrawEnumerateEx =
+ (void *)GetProcAddress( p_vout->p_sys->hddraw_dll,
+ "DirectDrawEnumerateExA" );
+
+ 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,
+ DDENUM_ATTACHEDSECONDARYDEVICES );
+ }
+
/* Initialize DirectDraw now */
- dxresult = OurDirectDrawCreate( NULL, &p_ddobject, NULL );
+ dxresult = OurDirectDrawCreate( p_vout->p_sys->p_display_driver,
+ &p_ddobject, NULL );
if( dxresult != DD_OK )
{
msg_Err( p_vout, "DirectXInitDDraw cannot initialize DDraw" );
/* 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 );
+ NULL, DDSCL_NORMAL );
if( dxresult != DD_OK )
{
msg_Err( p_vout, "cannot set direct draw cooperative level" );
goto error;
}
+ /* Get the size of the current display device */
+ if( p_vout->p_sys->hmonitor && p_vout->p_sys->GetMonitorInfo )
+ {
+ MONITORINFO monitor_info;
+ monitor_info.cbSize = sizeof( MONITORINFO );
+ p_vout->p_sys->GetMonitorInfo( p_vout->p_sys->hmonitor,
+ &monitor_info );
+ p_vout->p_sys->rect_display = monitor_info.rcMonitor;
+ }
+ else
+ {
+ p_vout->p_sys->rect_display.left = 0;
+ p_vout->p_sys->rect_display.top = 0;
+ p_vout->p_sys->rect_display.right = GetSystemMetrics(SM_CXSCREEN);
+ p_vout->p_sys->rect_display.bottom = GetSystemMetrics(SM_CYSCREEN);
+ }
+
+ msg_Dbg( p_vout, "screen dimensions (%ix%i,%ix%i)",
+ p_vout->p_sys->rect_display.left,
+ p_vout->p_sys->rect_display.top,
+ p_vout->p_sys->rect_display.right,
+ p_vout->p_sys->rect_display.bottom );
+
/* Probe the capabilities of the hardware */
DirectXGetDDrawCaps( p_vout );
HRESULT dxresult;
DDSURFACEDESC ddsd;
LPDIRECTDRAWSURFACE p_display;
- DDPIXELFORMAT pixel_format;
msg_Dbg( p_vout, "DirectXCreateDisplay" );
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
dxresult = IDirectDraw2_CreateSurface( p_vout->p_sys->p_ddobject,
- &ddsd,
- &p_display, NULL );
+ &ddsd, &p_display, NULL );
if( dxresult != DD_OK )
{
- msg_Err( p_vout, "cannot get primary surface (error %i)", dxresult );
+ msg_Err( p_vout, "cannot get primary surface (error %li)", dxresult );
return VLC_EGENERIC;
}
if ( dxresult != DD_OK )
{
msg_Err( p_vout, "cannot query IDirectDrawSurface2 interface "
- "(error %i)", dxresult );
+ "(error %li)", dxresult );
return VLC_EGENERIC;
}
/* The clipper will be used only in non-overlay mode */
DirectXCreateClipper( p_vout );
+ /* Make sure the colorkey will be painted */
+ p_vout->p_sys->i_colorkey = 1;
+ p_vout->p_sys->i_rgb_colorkey =
+ DirectXFindColorkey( p_vout, p_vout->p_sys->i_colorkey );
-#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 = IDirectDrawSurface2_GetPixelFormat( p_vout->p_sys->p_display,
- &pixel_format );
- if( dxresult != DD_OK )
- {
- 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 );
-#endif
+ /* Create the actual brush */
+ SetClassLong( p_vout->p_sys->hvideownd, GCL_HBRBACKGROUND,
+ (LONG)CreateSolidBrush( p_vout->p_sys->i_rgb_colorkey ) );
+ InvalidateRect( p_vout->p_sys->hvideownd, NULL, TRUE );
+ DirectXUpdateRects( p_vout, VLC_TRUE );
return VLC_SUCCESS;
}
-
/*****************************************************************************
* DirectXCreateClipper: Create a clipper that will be used when blitting the
* RGB surface to the main display.
&p_vout->p_sys->p_clipper, NULL );
if( dxresult != DD_OK )
{
- msg_Warn( p_vout, "cannot create clipper (error %i)", dxresult );
+ msg_Warn( p_vout, "cannot create clipper (error %li)", dxresult );
goto error;
}
/* Associate the clipper to the window */
- dxresult = IDirectDrawClipper_SetHWnd(p_vout->p_sys->p_clipper, 0,
- p_vout->p_sys->hwnd);
+ dxresult = IDirectDrawClipper_SetHWnd( p_vout->p_sys->p_clipper, 0,
+ p_vout->p_sys->hvideownd );
if( dxresult != DD_OK )
{
- msg_Warn( p_vout, "cannot attach clipper to window (error %i)",
+ msg_Warn( p_vout, "cannot attach clipper to window (error %li)",
dxresult );
goto error;
}
p_vout->p_sys->p_clipper);
if( dxresult != DD_OK )
{
- msg_Warn( p_vout, "cannot attach clipper to surface (error %i)",
+ msg_Warn( p_vout, "cannot attach clipper to surface (error %li)",
dxresult );
goto error;
- }
+ }
return VLC_SUCCESS;
ddsd.ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT);
ddsd.ddpfPixelFormat.dwFlags = DDPF_FOURCC;
ddsd.ddpfPixelFormat.dwFourCC = i_chroma;
- ddsd.dwFlags = DDSD_CAPS |
- DDSD_HEIGHT |
- DDSD_WIDTH |
- DDSD_PIXELFORMAT;
+ ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
ddsd.dwFlags |= (i_backbuffers ? DDSD_BACKBUFFERCOUNT : 0);
- ddsd.ddsCaps.dwCaps = DDSCAPS_OVERLAY |
- DDSCAPS_VIDEOMEMORY;
+ ddsd.ddsCaps.dwCaps = DDSCAPS_OVERLAY | DDSCAPS_VIDEOMEMORY;
ddsd.ddsCaps.dwCaps |= (i_backbuffers ? DDSCAPS_COMPLEX | DDSCAPS_FLIP
: 0 );
ddsd.dwHeight = p_vout->render.i_height;
ddsd.dwBackBufferCount = i_backbuffers;
dxresult = IDirectDraw2_CreateSurface( p_vout->p_sys->p_ddobject,
- &ddsd,
- &p_surface, NULL );
+ &ddsd, &p_surface, NULL );
if( dxresult != DD_OK )
{
*pp_surface_final = NULL;
memset( &ddsd, 0, sizeof( DDSURFACEDESC ) );
ddsd.dwSize = sizeof(DDSURFACEDESC);
ddsd.ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT);
- ddsd.dwFlags = DDSD_HEIGHT |
- DDSD_WIDTH |
- DDSD_CAPS;
+ ddsd.dwFlags = DDSD_HEIGHT | DDSD_WIDTH | DDSD_CAPS;
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
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 )
{
*pp_surface_final = NULL;
if ( dxresult != DD_OK )
{
msg_Err( p_vout, "cannot query IDirectDrawSurface2 interface "
- "(error %i)", dxresult );
+ "(error %li)", dxresult );
*pp_surface_final = NULL;
return VLC_EGENERIC;
}
+ if( b_overlay )
+ {
+ /* Check the overlay is useable as some graphics cards allow creating
+ * several overlays but only one can be used at one time. */
+ p_vout->p_sys->p_current_surface = *pp_surface_final;
+ if( DirectXUpdateOverlay( p_vout ) != VLC_SUCCESS )
+ {
+ IDirectDrawSurface2_Release( *pp_surface_final );
+ *pp_surface_final = NULL;
+ msg_Err( p_vout, "overlay unuseable (might already be in use)" );
+ return VLC_EGENERIC;
+ }
+ }
+
return VLC_SUCCESS;
}
* Ususally the overlay is moved by the user and thus, by a move or resize
* event (in Manage).
*****************************************************************************/
-void DirectXUpdateOverlay( vout_thread_t *p_vout )
+int DirectXUpdateOverlay( vout_thread_t *p_vout )
{
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 )
- return;
+ 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 */
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;
+ 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;
}
+ return VLC_SUCCESS;
}
/*****************************************************************************
FreeLibrary( p_vout->p_sys->hddraw_dll );
p_vout->p_sys->hddraw_dll = NULL;
}
+
+ if( p_vout->p_sys->p_display_driver != NULL )
+ {
+ free( p_vout->p_sys->p_display_driver );
+ p_vout->p_sys->p_display_driver = NULL;
+ }
+
+ p_vout->p_sys->hmonitor = NULL;
}
/*****************************************************************************
/* 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 */ );
- i_ret = DirectXCreateSurface( p_vout, &p_surface,
- p_vout->output.i_chroma,
- p_vout->p_sys->b_using_overlay,
- 2 /* number of backbuffers */ );
-
- if( i_ret != VLC_SUCCESS )
+ if( !p_vout->p_sys->b_3buf_overlay || i_ret != VLC_SUCCESS )
{
/* Try to reduce the number of backbuffers */
i_ret = DirectXCreateSurface( p_vout, &p_surface,
p_pic[0].p_sys->p_front_surface;
/* Reset the front buffer memory */
- if( !DirectXGetSurfaceDesc( p_vout, &front_pic ) &&
- !UpdatePictureStruct( p_vout, &front_pic,
- p_vout->output.i_chroma ) )
+ 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 );
{
if( p_vout->p_sys->b_hw_yuv )
{
- i_ret = DirectXCreateSurface( p_vout, &p_surface,
- p_vout->output.i_chroma,
- 0 /* no overlay */,
- 0 /* no back buffers */ );
+ DWORD i_codes;
+ DWORD *pi_codes;
+ vlc_bool_t b_result = VLC_FALSE;
+
+ /* Check if the chroma is supported first. This is required
+ * because a few buggy drivers don't mind creating the surface
+ * even if they don't know about the chroma. */
+ if( IDirectDraw2_GetFourCCCodes( p_vout->p_sys->p_ddobject,
+ &i_codes, NULL ) == DD_OK )
+ {
+ pi_codes = malloc( i_codes * sizeof(DWORD) );
+ if( pi_codes && IDirectDraw2_GetFourCCCodes(
+ p_vout->p_sys->p_ddobject, &i_codes, pi_codes ) == DD_OK )
+ {
+ for( i = 0; i < (int)i_codes; i++ )
+ {
+ if( p_vout->output.i_chroma == pi_codes[i] )
+ {
+ b_result = VLC_TRUE;
+ break;
+ }
+ }
+ }
+ }
+
+ if( b_result )
+ i_ret = DirectXCreateSurface( p_vout, &p_surface,
+ p_vout->output.i_chroma,
+ 0 /* no overlay */,
+ 0 /* no back buffers */ );
+ else
+ p_vout->p_sys->b_hw_yuv = VLC_FALSE;
}
if( i_ret || !p_vout->p_sys->b_hw_yuv )
DirectXCloseSurface( p_vout, p_surface );
return VLC_ENOMEM;
}
+
p_pic[0].p_sys->p_surface = p_pic[0].p_sys->p_front_surface
= p_surface;
{
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_vout, &p_pic[i] ) )
+ if( DirectXLockSurface( p_vout, &p_pic[i] ) != VLC_SUCCESS )
{
/* AAARRGG */
FreePictureVec( p_vout, p_pic, I_OUTPUTPICTURES );
I_OUTPUTPICTURES = 0;
+ msg_Err( p_vout, "cannot lock surface" );
return VLC_EGENERIC;
}
-
- 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 VLC_EGENERIC;
- }
+ DirectXUnlockSurface( p_vout, &p_pic[i] );
}
msg_Dbg( p_vout, "End NewPictureVec (%s)",
/*****************************************************************************
* FreePicture: destroy a picture vector allocated with NewPictureVec
*****************************************************************************
- *
+ *
*****************************************************************************/
static void FreePictureVec( vout_thread_t *p_vout, picture_t *p_pic,
int i_num_pics )
{
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 );
p_pic->p->i_pixel_pitch = 2;
break;
case VLC_FOURCC('R','V','2','4'):
+ p_pic->p->i_pixel_pitch = 3;
+ break;
case VLC_FOURCC('R','V','3','2'):
p_pic->p->i_pixel_pitch = 4;
break;
break;
default:
- /* Not supported */
+ /* 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;
}
}
else
{
- BOOL bHasOverlay, bHasOverlayFourCC, bCanClipOverlay,
- bHasColorKey, bCanStretch;
+ 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;
- /* Determine if the hardware supports overlay surfaces */
- bHasOverlayFourCC = ((ddcaps.dwCaps & DDCAPS_OVERLAYFOURCC) ==
- DDCAPS_OVERLAYFOURCC) ? TRUE : FALSE;
+ bHasOverlay = (ddcaps.dwCaps & DDCAPS_OVERLAY) ? 1 : 0;
/* Determine if the hardware supports overlay surfaces */
- bCanClipOverlay = ((ddcaps.dwCaps & DDCAPS_OVERLAYCANTCLIP) ==
- 0 ) ? TRUE : FALSE;
+ bHasOverlayFourCC = (ddcaps.dwCaps & DDCAPS_OVERLAYFOURCC) ? 1 : 0;
+ /* Determine if the hardware supports overlay deinterlacing */
+ 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) ? 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_clip_overlay=%i colorkey=%i stretch=%i",
- bHasOverlay, bHasOverlayFourCC, bCanClipOverlay,
- bHasColorKey, bCanStretch );
+ "can_deinterlace_overlay=%i colorkey=%i stretch=%i "
+ "bltfourcc=%i",
+ bHasOverlay, bHasOverlayFourCC, bCanDeinterlace,
+ bHasColorKey, bCanStretch, bCanBltFourcc );
- /* 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;
+ 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;
}
}
/*****************************************************************************
- * 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( vout_thread_t *p_vout, 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 )
{
- msg_Err( p_vout, "DirectXGetSurfaceDesc cannot lock surface" );
+ 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 );
+ if( IDirectDrawSurface2_Unlock( p_pic->p_sys->p_surface, NULL ) == DD_OK )
+ return VLC_SUCCESS;
+ else
+ return VLC_EGENERIC;
+}
+
+/*****************************************************************************
+ * DirectXFindColorkey: Finds out the 32bits RGB pixel value of the colorkey
+ *****************************************************************************/
+static DWORD DirectXFindColorkey( vout_thread_t *p_vout, uint32_t i_color )
+{
+ DDSURFACEDESC ddsd;
+ HRESULT dxresult;
+ COLORREF i_rgb = 0;
+ uint32_t i_pixel_backup;
+ HDC hdc;
+
+ ddsd.dwSize = sizeof(ddsd);
+ dxresult = IDirectDrawSurface2_Lock( p_vout->p_sys->p_display, NULL,
+ &ddsd, DDLOCK_WAIT, NULL );
+ if( dxresult != DD_OK ) return 0;
+
+ i_pixel_backup = *(uint32_t *)ddsd.lpSurface;
+
+ switch( ddsd.ddpfPixelFormat.dwRGBBitCount )
+ {
+ case 4:
+ *(uint8_t *)ddsd.lpSurface = 0x11;
+ break;
+ case 8:
+ *(uint8_t *)ddsd.lpSurface = 0x01;
+ break;
+ case 16:
+ *(uint16_t *)ddsd.lpSurface = 0x01;
+ break;
+ default:
+ *(uint32_t *)ddsd.lpSurface = 0x01;
+ break;
+ }
+
+ IDirectDrawSurface2_Unlock( p_vout->p_sys->p_display, NULL );
+
+ if( IDirectDrawSurface2_GetDC( p_vout->p_sys->p_display, &hdc ) == DD_OK )
+ {
+ i_rgb = GetPixel( hdc, 0, 0 );
+ IDirectDrawSurface2_ReleaseDC( p_vout->p_sys->p_display, hdc );
+ }
+
+ ddsd.dwSize = sizeof(ddsd);
+ dxresult = IDirectDrawSurface2_Lock( p_vout->p_sys->p_display, NULL,
+ &ddsd, DDLOCK_WAIT, NULL );
+ if( dxresult != DD_OK ) return i_rgb;
+
+ *(uint32_t *)ddsd.lpSurface = i_pixel_backup;
+
+ IDirectDrawSurface2_Unlock( p_vout->p_sys->p_display, NULL );
+
+ return i_rgb;
+}
+
+/*****************************************************************************
+ * config variable callback
+ *****************************************************************************/
+BOOL WINAPI DirectXEnumCallback2( GUID* p_guid, LPTSTR psz_desc,
+ LPTSTR psz_drivername, VOID* p_context,
+ HMONITOR hmon )
+{
+ 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;
}