static void Direct3DVoutReleaseScene ( vout_thread_t * );
static void Direct3DVoutRenderScene ( vout_thread_t *, picture_t * );
+static int DesktopCallback( vlc_object_t *p_this, char const *psz_cmd,
+ vlc_value_t oldval, vlc_value_t newval,
+ void *p_data );
+
/*****************************************************************************
* Module descriptor
*****************************************************************************/
return IsVistaOrAbove() ? OpenVideo( obj ) : VLC_EGENERIC;
}
+#define DESKTOP_TEXT N_("Enable desktop mode ")
+#define DESKTOP_LONGTEXT N_( \
+ "The desktop mode allows you to display the video on the desktop." )
+
vlc_module_begin ()
set_shortname( "Direct3D" )
set_category( CAT_VIDEO )
set_subcategory( SUBCAT_VIDEO_VOUT )
+
+ add_bool( "direct3d-desktop", false, NULL, DESKTOP_TEXT, DESKTOP_LONGTEXT,
+ true )
+
set_description( N_("DirectX 3D video output") )
set_capability( "video output", 50 )
add_shortcut( "direct3d" )
*****************************************************************************/
static int OpenVideo( vlc_object_t *p_this )
{
+ vlc_value_t val;
vout_thread_t * p_vout = (vout_thread_t *)p_this;
/* Allocate structure */
p_vout->pf_manage = Manage;
p_vout->pf_render = Direct3DVoutRenderScene;
p_vout->pf_display = FirstDisplay;
+ p_vout->pf_control = Control;
- p_vout->p_sys->hwnd = p_vout->p_sys->hvideownd = NULL;
- p_vout->p_sys->hparent = p_vout->p_sys->hfswnd = NULL;
- p_vout->p_sys->i_changes = 0;
- vlc_mutex_init( &p_vout->p_sys->lock );
- SetRectEmpty( &p_vout->p_sys->rect_display );
- SetRectEmpty( &p_vout->p_sys->rect_parent );
+ if( CommonInit( p_vout ) )
+ goto error;
+ p_vout->p_sys->b_desktop = false;
var_Create( p_vout, "directx-hw-yuv", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
var_Create( p_vout, "directx-device", 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->i_mouse_hide_timeout =
- var_GetInteger(p_vout, "mouse-hide-timeout") * 1000;
-
- var_Create( p_vout, "video-title", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
- var_Create( p_vout, "disable-screensaver", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
-
- /* Set main window's size */
- p_vout->p_sys->i_window_width = p_vout->i_window_width;
- p_vout->p_sys->i_window_height = p_vout->i_window_height;
-
- /* Create the Vout EventThread, this thread is created by us to isolate
- * the Win32 PeekMessage function calls. We want to do this because
- * Windows can stay blocked inside this call for a long time, and when
- * this happens it thus blocks vlc's video_output thread.
- * Vout EventThread will take care of the creation of the video
- * window (because PeekMessage has to be called from the same thread which
- * created the window). */
- msg_Dbg( p_vout, "creating Vout EventThread" );
- 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;
- p_vout->p_sys->p_event->window_ready = CreateEvent( NULL, TRUE, FALSE, NULL );
- if( vlc_thread_create( p_vout->p_sys->p_event, "Vout Events Thread",
- EventThread, 0 ) )
- {
- msg_Err( p_vout, "cannot create Vout EventThread" );
- CloseHandle( p_vout->p_sys->p_event->window_ready );
- vlc_object_release( p_vout->p_sys->p_event );
- p_vout->p_sys->p_event = NULL;
- goto error;
- }
- WaitForSingleObject( p_vout->p_sys->p_event->window_ready, INFINITE );
- CloseHandle( p_vout->p_sys->p_event->window_ready );
-
- if( p_vout->p_sys->p_event->b_error )
- {
- msg_Err( p_vout, "Vout EventThread failed" );
- goto error;
- }
-
- vlc_object_attach( p_vout->p_sys->p_event, p_vout );
-
- msg_Dbg( p_vout, "Vout EventThread running" );
-
- /* Variable to indicate if the window should be on top of others */
/* Trigger a callback right now */
- var_TriggerCallback( p_vout, "video-on-top" );
-
- /* disable screensaver by temporarily changing system settings */
- p_vout->p_sys->i_spi_lowpowertimeout = 0;
- p_vout->p_sys->i_spi_powerofftimeout = 0;
- p_vout->p_sys->i_spi_screensavetimeout = 0;
- if( var_GetBool( p_vout, "disable-screensaver" ) ) {
- msg_Dbg(p_vout, "disabling screen saver");
- SystemParametersInfo(SPI_GETLOWPOWERTIMEOUT,
- 0, &(p_vout->p_sys->i_spi_lowpowertimeout), 0);
- if( 0 != p_vout->p_sys->i_spi_lowpowertimeout ) {
- SystemParametersInfo(SPI_SETLOWPOWERTIMEOUT, 0, NULL, 0);
- }
- SystemParametersInfo(SPI_GETPOWEROFFTIMEOUT, 0,
- &(p_vout->p_sys->i_spi_powerofftimeout), 0);
- if( 0 != p_vout->p_sys->i_spi_powerofftimeout ) {
- SystemParametersInfo(SPI_SETPOWEROFFTIMEOUT, 0, NULL, 0);
- }
- SystemParametersInfo(SPI_GETSCREENSAVETIMEOUT, 0,
- &(p_vout->p_sys->i_spi_screensavetimeout), 0);
- if( 0 != p_vout->p_sys->i_spi_screensavetimeout ) {
- SystemParametersInfo(SPI_SETSCREENSAVETIMEOUT, 0, NULL, 0);
- }
- }
+ var_Create( p_vout, "direct3d-desktop", VLC_VAR_BOOL|VLC_VAR_DOINHERIT );
+ val.psz_string = _("Desktop");
+ var_Change( p_vout, "direct3d-desktop", VLC_VAR_SETTEXT, &val, NULL );
+ var_AddCallback( p_vout, "direct3d-desktop", DesktopCallback, NULL );
+ var_TriggerCallback( p_vout, "direct3d-desktop" );
+
return VLC_SUCCESS;
error:
Direct3DVoutRelease( p_vout );
- if( p_vout->b_fullscreen )
- {
- msg_Dbg( p_vout, "Quitting fullscreen" );
- Win32ToggleFullscreen( p_vout );
- /* Force fullscreen in the core for the next video */
- var_SetBool( p_vout, "fullscreen", true );
- }
-
- if( p_vout->p_sys->p_event )
- {
- vlc_object_detach( p_vout->p_sys->p_event );
-
- /* Kill Vout EventThread */
- vlc_object_kill( p_vout->p_sys->p_event );
-
- /* we need to be sure Vout EventThread 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_release( p_vout->p_sys->p_event );
- }
-
- vlc_mutex_destroy( &p_vout->p_sys->lock );
-
- /* restore screensaver system settings */
- if( 0 != p_vout->p_sys->i_spi_lowpowertimeout ) {
- SystemParametersInfo(SPI_SETLOWPOWERTIMEOUT,
- p_vout->p_sys->i_spi_lowpowertimeout, NULL, 0);
- }
- if( 0 != p_vout->p_sys->i_spi_powerofftimeout ) {
- SystemParametersInfo(SPI_SETPOWEROFFTIMEOUT,
- p_vout->p_sys->i_spi_powerofftimeout, NULL, 0);
- }
- if( 0 != p_vout->p_sys->i_spi_screensavetimeout ) {
- SystemParametersInfo(SPI_SETSCREENSAVETIMEOUT,
- p_vout->p_sys->i_spi_screensavetimeout, NULL, 0);
- }
+ CommonClean( p_vout );
free( p_vout->p_sys );
- p_vout->p_sys = NULL;
}
/*****************************************************************************
*****************************************************************************/
static int Manage( vout_thread_t *p_vout )
{
- /* If we do not control our window, we check for geometry changes
- * ourselves because the parent might not send us its events. */
- 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;
-
- SetWindowPos( p_vout->p_sys->hwnd, 0, 0, 0,
- rect_parent.right - rect_parent.left,
- rect_parent.bottom - rect_parent.top,
- SWP_NOZORDER );
- }
- }
- else
- {
- vlc_mutex_unlock( &p_vout->p_sys->lock );
- }
+ CommonManage( p_vout );
/*
* Position Change
p_vout->p_sys->i_changes &= ~DX_POSITION_CHANGE;
}
- /* autoscale toggle */
- if( p_vout->i_changes & VOUT_SCALE_CHANGE )
- {
- p_vout->i_changes &= ~VOUT_SCALE_CHANGE;
-
- p_vout->b_autoscale = var_GetBool( p_vout, "autoscale" );
- p_vout->i_zoom = (int) ZOOM_FP_FACTOR;
-
- UpdateRects( p_vout, true );
- }
-
- /* scaling factor */
- if( p_vout->i_changes & VOUT_ZOOM_CHANGE )
- {
- p_vout->i_changes &= ~VOUT_ZOOM_CHANGE;
-
- p_vout->b_autoscale = false;
- p_vout->i_zoom =
- (int)( ZOOM_FP_FACTOR * var_GetFloat( p_vout, "scale" ) );
- UpdateRects( p_vout, true );
- }
-
- /* Check for cropping / aspect changes */
- if( p_vout->i_changes & VOUT_CROP_CHANGE ||
- p_vout->i_changes & VOUT_ASPECT_CHANGE )
- {
- p_vout->i_changes &= ~VOUT_CROP_CHANGE;
- p_vout->i_changes &= ~VOUT_ASPECT_CHANGE;
-
- p_vout->fmt_out.i_x_offset = p_vout->fmt_in.i_x_offset;
- p_vout->fmt_out.i_y_offset = p_vout->fmt_in.i_y_offset;
- p_vout->fmt_out.i_visible_width = p_vout->fmt_in.i_visible_width;
- p_vout->fmt_out.i_visible_height = p_vout->fmt_in.i_visible_height;
- p_vout->fmt_out.i_aspect = p_vout->fmt_in.i_aspect;
- p_vout->fmt_out.i_sar_num = p_vout->fmt_in.i_sar_num;
- p_vout->fmt_out.i_sar_den = p_vout->fmt_in.i_sar_den;
- p_vout->output.i_aspect = p_vout->fmt_in.i_aspect;
- UpdateRects( p_vout, true );
- }
-
- /* 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
+ * Desktop mode change
*/
- if( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE
- || p_vout->p_sys->i_changes & VOUT_FULLSCREEN_CHANGE )
+ if( p_vout->p_sys->i_changes & DX_DESKTOP_CHANGE )
{
- Win32ToggleFullscreen( p_vout );
+ /* Close the direct3d instance attached to the current output window. */
+ End( p_vout );
- p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
- p_vout->p_sys->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
- }
+ ExitFullscreen( p_vout );
- /*
- * Pointer change
- */
- if( p_vout->b_fullscreen && !p_vout->p_sys->b_cursor_hidden &&
- (mdate() - p_vout->p_sys->i_lastmoved) >
- p_vout->p_sys->i_mouse_hide_timeout )
- {
- POINT point;
- HWND hwnd;
+ EventThreadStop( p_vout->p_sys->p_event );
- /* 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 )
- {
- PostMessage( p_vout->p_sys->hwnd, WM_VLC_HIDE_MOUSE, 0, 0 );
- }
- else
- {
- p_vout->p_sys->i_lastmoved = mdate();
- }
- }
+ /* Open the direct3d output and attaches it to the new window */
+ p_vout->p_sys->b_desktop = !p_vout->p_sys->b_desktop;
+ p_vout->pf_display = FirstDisplay;
- /*
- * "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 );
+ EventThreadStart( p_vout->p_sys->p_event );
- var_Get( p_vout, "video-on-top", &val );
+ Init( p_vout );
- /* 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 = false;
- }
-
- /* Check if the event thread is still running */
- if( !vlc_object_alive (p_vout->p_sys->p_event) )
- {
- return VLC_EGENERIC; /* exit */
+ /* Reset the flag */
+ p_vout->p_sys->i_changes &= ~DX_DESKTOP_CHANGE;
}
return VLC_SUCCESS;
*****************************************************************************/
static void Display( vout_thread_t *p_vout, picture_t *p_pic )
{
+ VLC_UNUSED( p_pic );
+
LPDIRECT3DDEVICE9 p_d3ddev = p_vout->p_sys->p_d3ddev;
+
// Present the back buffer contents to the display
// stretching and filtering happens here
HRESULT hr = IDirect3DDevice9_Present(p_d3ddev,
/* it sounds like vista does not support YUV surfaces at all */
switch( i_chroma )
{
- case VLC_FOURCC('U','Y','V','Y'):
- case VLC_FOURCC('U','Y','N','V'):
- case VLC_FOURCC('Y','4','2','2'):
+ case VLC_CODEC_UYVY:
{
static const D3DFORMAT formats[] =
{ D3DFMT_UYVY, D3DFMT_YUY2, D3DFMT_X8R8G8B8, D3DFMT_A8R8G8B8, D3DFMT_R5G6B5, D3DFMT_X1R5G5B5 };
return Direct3DVoutSelectFormat(p_vout, target, formats, sizeof(formats)/sizeof(D3DFORMAT));
}
- case VLC_FOURCC('I','4','2','0'):
- case VLC_FOURCC('I','4','2','2'):
- case VLC_FOURCC('Y','V','1','2'):
+ case VLC_CODEC_I420:
+ case VLC_CODEC_I422:
+ case VLC_CODEC_YV12:
{
/* typically 3D textures don't support planar format
** fallback to packed version and use CPU for the conversion
{ D3DFMT_YUY2, D3DFMT_UYVY, D3DFMT_X8R8G8B8, D3DFMT_A8R8G8B8, D3DFMT_R5G6B5, D3DFMT_X1R5G5B5 };
return Direct3DVoutSelectFormat(p_vout, target, formats, sizeof(formats)/sizeof(D3DFORMAT));
}
- case VLC_FOURCC('Y','U','Y','2'):
- case VLC_FOURCC('Y','U','N','V'):
+ case VLC_CODEC_YUYV:
{
static const D3DFORMAT formats[] =
{ D3DFMT_YUY2, D3DFMT_UYVY, D3DFMT_X8R8G8B8, D3DFMT_A8R8G8B8, D3DFMT_R5G6B5, D3DFMT_X1R5G5B5 };
switch( i_chroma )
{
- case VLC_FOURCC('R', 'V', '1', '5'):
+ case VLC_CODEC_RGB15:
{
static const D3DFORMAT formats[] =
{ D3DFMT_X1R5G5B5 };
return Direct3DVoutSelectFormat(p_vout, target, formats, sizeof(formats)/sizeof(D3DFORMAT));
}
- case VLC_FOURCC('R', 'V', '1', '6'):
+ case VLC_CODEC_RGB16:
{
static const D3DFORMAT formats[] =
{ D3DFMT_R5G6B5 };
return Direct3DVoutSelectFormat(p_vout, target, formats, sizeof(formats)/sizeof(D3DFORMAT));
}
- case VLC_FOURCC('R', 'V', '2', '4'):
+ case VLC_CODEC_RGB24:
{
static const D3DFORMAT formats[] =
{ D3DFMT_R8G8B8, D3DFMT_X8R8G8B8, D3DFMT_A8R8G8B8 };
return Direct3DVoutSelectFormat(p_vout, target, formats, sizeof(formats)/sizeof(D3DFORMAT));
}
- case VLC_FOURCC('R', 'V', '3', '2'):
+ case VLC_CODEC_RGB32:
{
static const D3DFORMAT formats[] =
{ D3DFMT_A8R8G8B8, D3DFMT_X8R8G8B8 };
switch( format )
{
case D3DFMT_YUY2:
- p_vout->output.i_chroma = VLC_FOURCC('Y', 'U', 'Y', '2');
+ p_vout->output.i_chroma = VLC_CODEC_YUYV;
break;
case D3DFMT_UYVY:
- p_vout->output.i_chroma = VLC_FOURCC('U', 'Y', 'V', 'Y');
+ p_vout->output.i_chroma = VLC_CODEC_UYVY;
break;
case D3DFMT_R8G8B8:
- p_vout->output.i_chroma = VLC_FOURCC('R', 'V', '2', '4');
+ p_vout->output.i_chroma = VLC_CODEC_RGB24;
p_vout->output.i_rmask = 0xff0000;
p_vout->output.i_gmask = 0x00ff00;
p_vout->output.i_bmask = 0x0000ff;
break;
case D3DFMT_X8R8G8B8:
case D3DFMT_A8R8G8B8:
- p_vout->output.i_chroma = VLC_FOURCC('R', 'V', '3', '2');
+ p_vout->output.i_chroma = VLC_CODEC_RGB32;
p_vout->output.i_rmask = 0x00ff0000;
p_vout->output.i_gmask = 0x0000ff00;
p_vout->output.i_bmask = 0x000000ff;
break;
case D3DFMT_R5G6B5:
- p_vout->output.i_chroma = VLC_FOURCC('R', 'V', '1', '6');
+ p_vout->output.i_chroma = VLC_CODEC_RGB16;
p_vout->output.i_rmask = (0x1fL)<<11;
p_vout->output.i_gmask = (0x3fL)<<5;
p_vout->output.i_bmask = (0x1fL)<<0;
break;
case D3DFMT_X1R5G5B5:
- p_vout->output.i_chroma = VLC_FOURCC('R', 'V', '1', '5');
+ p_vout->output.i_chroma = VLC_CODEC_RGB15;
p_vout->output.i_rmask = (0x1fL)<<10;
p_vout->output.i_gmask = (0x1fL)<<5;
p_vout->output.i_bmask = (0x1fL)<<0;
* picture_t structures */
switch( p_vout->output.i_chroma )
{
- case VLC_FOURCC('R','G','B','2'):
+ case VLC_CODEC_RGB8:
p_pic->p->i_lines = p_vout->output.i_height;
p_pic->p->i_visible_lines = p_vout->output.i_height;
p_pic->p->i_pixel_pitch = 1;
p_pic->p->i_pixel_pitch;
p_pic->i_planes = 1;
break;
- case VLC_FOURCC('R','V','1','5'):
- case VLC_FOURCC('R','V','1','6'):
+ case VLC_CODEC_RGB15:
+ case VLC_CODEC_RGB16:
p_pic->p->i_lines = p_vout->output.i_height;
p_pic->p->i_visible_lines = p_vout->output.i_height;
p_pic->p->i_pixel_pitch = 2;
p_pic->p->i_pixel_pitch;
p_pic->i_planes = 1;
break;
- case VLC_FOURCC('R','V','2','4'):
+ case VLC_CODEC_RGB24:
p_pic->p->i_lines = p_vout->output.i_height;
p_pic->p->i_visible_lines = p_vout->output.i_height;
p_pic->p->i_pixel_pitch = 3;
p_pic->p->i_pixel_pitch;
p_pic->i_planes = 1;
break;
- case VLC_FOURCC('R','V','3','2'):
+ case VLC_CODEC_RGB32:
p_pic->p->i_lines = p_vout->output.i_height;
p_pic->p->i_visible_lines = p_vout->output.i_height;
p_pic->p->i_pixel_pitch = 4;
p_pic->p->i_pixel_pitch;
p_pic->i_planes = 1;
break;
- case VLC_FOURCC('U','Y','V','Y'):
- case VLC_FOURCC('Y','U','Y','2'):
+ case VLC_CODEC_UYVY:
+ case VLC_CODEC_YUYV:
p_pic->p->i_lines = p_vout->output.i_height;
p_pic->p->i_visible_lines = p_vout->output.i_height;
p_pic->p->i_pixel_pitch = 2;
}
/* Update the vertex buffer */
- hr = IDirect3DVertexBuffer9_Lock(p_d3dvtc, 0, 0, (VOID **)(&p_vertices), D3DLOCK_DISCARD);
+ hr = IDirect3DVertexBuffer9_Lock(p_d3dvtc, 0, 0, (&p_vertices), D3DLOCK_DISCARD);
if( FAILED(hr) )
{
msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
}
}
+
+/*****************************************************************************
+ * DesktopCallback: desktop mode variable callback
+ *****************************************************************************/
+static int DesktopCallback( vlc_object_t *p_this, char const *psz_cmd,
+ vlc_value_t oldval, vlc_value_t newval,
+ void *p_data )
+{
+ VLC_UNUSED( psz_cmd );
+ VLC_UNUSED( oldval );
+ VLC_UNUSED( p_data );
+
+ vout_thread_t *p_vout = (vout_thread_t *)p_this;
+
+ if( (newval.b_bool && !p_vout->p_sys->b_desktop) ||
+ (!newval.b_bool && p_vout->p_sys->b_desktop) )
+ {
+ playlist_t *p_playlist = pl_Hold( p_vout );
+
+ if( p_playlist )
+ {
+ /* Modify playlist as well because the vout might have to be
+ * restarted */
+ var_Create( p_playlist, "direct3d-desktop", VLC_VAR_BOOL );
+ var_Set( p_playlist, "direct3d-desktop", newval );
+ pl_Release( p_vout );
+ }
+
+ p_vout->p_sys->i_changes |= DX_DESKTOP_CHANGE;
+ }
+
+ return VLC_SUCCESS;
+}