Commit f6d06e15 authored by Laurent Aimar's avatar Laurent Aimar

Converted direct3d to vout display.

It also fixes a few remaining race conditions.
parent 4a1df8f1
......@@ -8,10 +8,10 @@ SOURCES_directx = \
SOURCES_direct3d = \
direct3d.c \
vout.h \
events_vo.h \
events_vo.c \
common_vo.c \
common.h \
events.h \
events.c \
common.c \
$(NULL)
SOURCES_glwin32 = \
......
......@@ -29,9 +29,10 @@
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <assert.h>
#include <vlc_common.h>
#include <vlc_vout.h>
#include <vlc_vout_display.h>
#include <vlc_vout_window.h>
#include <windows.h>
......@@ -48,7 +49,7 @@
#include <GL/gl.h>
#endif
#include "vout.h"
#include "common.h"
#ifndef UNDER_CE
#include <vlc_windows_interfaces.h>
......@@ -59,230 +60,151 @@
//WINSHELLAPI BOOL WINAPI SHFullScreen(HWND hwndRequester, DWORD dwState);
#endif
static int vaControlParentWindow( vout_thread_t *, int, va_list );
static int CommonControlSetFullscreen(vout_display_t *, bool is_fullscreen);
static void DisableScreensaver(vout_display_t *);
static void RestoreScreensaver(vout_display_t *);
/* */
int CommonInit( vout_thread_t *p_vout )
int CommonInit(vout_display_t *vd)
{
vout_sys_t *p_sys = p_vout->p_sys;
p_sys->hwnd = NULL;
p_sys->hvideownd = NULL;
p_sys->hparent = NULL;
p_sys->hfswnd = NULL;
p_sys->i_changes = 0;
SetRectEmpty( &p_sys->rect_display );
SetRectEmpty( &p_sys->rect_parent );
var_Create( p_vout, "video-title", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
/* Set main window's size */
vout_window_cfg_t wnd_cfg;
memset( &wnd_cfg, 0, sizeof(wnd_cfg) );
wnd_cfg.type = VOUT_WINDOW_TYPE_HWND;
wnd_cfg.x = 0;
wnd_cfg.y = 0;
wnd_cfg.width = p_vout->i_window_width;
wnd_cfg.height = p_vout->i_window_height;
p_sys->p_event = EventThreadCreate( p_vout, &wnd_cfg );
if( !p_sys->p_event )
vout_display_sys_t *sys = vd->sys;
sys->hwnd = NULL;
sys->hvideownd = NULL;
sys->hparent = NULL;
sys->hfswnd = NULL;
sys->changes = 0;
SetRectEmpty(&sys->rect_display);
SetRectEmpty(&sys->rect_parent);
sys->is_first_display = true;
sys->is_on_top = false;
var_Create(vd, "video-title", VLC_VAR_STRING | VLC_VAR_DOINHERIT);
var_Create(vd, "video-deco", VLC_VAR_BOOL | VLC_VAR_DOINHERIT);
/* FIXME remove mouse hide from msw */
var_Create(vd, "mouse-hide-timeout", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
/* */
sys->event = EventThreadCreate(vd);
if (!sys->event)
return VLC_EGENERIC;
event_cfg_t cfg;
memset(&cfg, 0, sizeof(cfg));
#ifdef MODULE_NAME_IS_direct3d
cfg.use_desktop = p_vout->p_sys->b_desktop;
cfg.use_desktop = sys->use_desktop;
#endif
#ifdef MODULE_NAME_IS_directx
cfg.use_overlay = p_vout->p_sys->b_using_overlay;
cfg.use_overlay = sys->b_using_overlay;
#endif
cfg.win.type = VOUT_WINDOW_TYPE_HWND;
cfg.win.x = 0;
cfg.win.y = 0;
cfg.win.width = vd->cfg->display.width;
cfg.win.height = vd->cfg->display.height;
event_hwnd_t hwnd;
if( EventThreadStart( p_sys->p_event, &hwnd, &cfg ) )
if (EventThreadStart(sys->event, &hwnd, &cfg))
return VLC_EGENERIC;
p_sys->parent_window = hwnd.parent_window;
p_sys->hparent = hwnd.hparent;
p_sys->hwnd = hwnd.hwnd;
p_sys->hvideownd = hwnd.hvideownd;
p_sys->hfswnd = hwnd.hfswnd;
sys->parent_window = hwnd.parent_window;
sys->hparent = hwnd.hparent;
sys->hwnd = hwnd.hwnd;
sys->hvideownd = hwnd.hvideownd;
sys->hfswnd = hwnd.hfswnd;
/* Variable to indicate if the window should be on top of others */
/* Trigger a callback right now */
var_TriggerCallback( p_vout, "video-on-top" );
if (vd->cfg->is_fullscreen) {
if (CommonControlSetFullscreen(vd, true))
vout_display_SendEventFullscreen(vd, false);
}
/* Why not with glwin32 */
#if !defined(UNDER_CE) && !defined(MODULE_NAME_IS_glwin32)
var_Create( p_vout, "disable-screensaver", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
DisableScreensaver ( p_vout );
var_Create(vd, "disable-screensaver", VLC_VAR_BOOL | VLC_VAR_DOINHERIT);
DisableScreensaver (vd);
#endif
return VLC_SUCCESS;
}
/* */
void CommonClean( vout_thread_t *p_vout )
void CommonClean(vout_display_t *vd)
{
vout_sys_t *p_sys = p_vout->p_sys;
vout_display_sys_t *sys = vd->sys;
ExitFullscreen( p_vout );
if( p_sys->p_event )
{
EventThreadStop( p_sys->p_event );
EventThreadDestroy( p_sys->p_event );
if (sys->event) {
EventThreadStop(sys->event);
EventThreadDestroy(sys->event);
}
#if !defined(UNDER_CE) && !defined(MODULE_NAME_IS_glwin32)
RestoreScreensaver( p_vout );
RestoreScreensaver(vd);
#endif
}
void CommonManage( vout_thread_t *p_vout )
void CommonManage(vout_display_t *vd)
{
vout_display_sys_t *sys = vd->sys;
/* 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. */
/* 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 && !p_vout->b_fullscreen )
{
if (sys->hparent && !vd->cfg->is_fullscreen) {
RECT rect_parent;
POINT point;
GetClientRect( p_vout->p_sys->hparent, &rect_parent );
GetClientRect(sys->hparent, &rect_parent);
point.x = point.y = 0;
ClientToScreen( p_vout->p_sys->hparent, &point );
OffsetRect( &rect_parent, point.x, point.y );
ClientToScreen(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;
if (!EqualRect(&rect_parent, &sys->rect_parent)) {
sys->rect_parent = rect_parent;
/* FIXME I find such #ifdef quite weirds. Are they really needed ? */
#if defined(MODULE_NAME_IS_direct3d)
SetWindowPos( p_vout->p_sys->hwnd, 0, 0, 0,
SetWindowPos(sys->hwnd, 0, 0, 0,
rect_parent.right - rect_parent.left,
rect_parent.bottom - rect_parent.top,
SWP_NOZORDER );
UpdateRects( p_vout, true );
SWP_NOZORDER);
UpdateRects(vd, NULL, NULL, true);
#else
/* This one is to force the update even if only
* the position has changed */
SetWindowPos( p_vout->p_sys->hwnd, 0, 1, 1,
SetWindowPos(sys->hwnd, 0, 1, 1,
rect_parent.right - rect_parent.left,
rect_parent.bottom - rect_parent.top, 0 );
rect_parent.bottom - rect_parent.top, 0);
SetWindowPos( p_vout->p_sys->hwnd, 0, 0, 0,
SetWindowPos(sys->hwnd, 0, 0, 0,
rect_parent.right - rect_parent.left,
rect_parent.bottom - rect_parent.top, 0 );
rect_parent.bottom - rect_parent.top, 0);
#if defined(MODULE_NAME_IS_wingdi) || defined(MODULE_NAME_IS_wingapi)
unsigned int i_x, i_y, i_width, i_height;
vout_PlacePicture( p_vout, rect_parent.right - rect_parent.left,
vout_PlacePicture(vd, rect_parent.right - rect_parent.left,
rect_parent.bottom - rect_parent.top,
&i_x, &i_y, &i_width, &i_height );
&i_x, &i_y, &i_width, &i_height);
SetWindowPos( p_vout->p_sys->hvideownd, HWND_TOP,
i_x, i_y, i_width, i_height, 0 );
SetWindowPos(sys->hvideownd, HWND_TOP,
i_x, i_y, i_width, i_height, 0);
#endif
#endif
}
}
/* */
p_vout->p_sys->i_changes |= EventThreadRetreiveChanges( p_vout->p_sys->p_event );
/* 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
*/
if( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE
|| p_vout->p_sys->i_changes & VOUT_FULLSCREEN_CHANGE )
{
Win32ToggleFullscreen( p_vout );
if (EventThreadGetAndResetHasMoved(sys->event))
UpdateRects(vd, NULL, NULL, false);
p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
p_vout->p_sys->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
}
/*
* Pointer change
*/
EventThreadMouseAutoHide( p_vout->p_sys->p_event );
/*
* "Always on top" status change
*/
if( p_vout->p_sys->b_on_top_change )
{
HMENU hMenu = GetSystemMenu( p_vout->p_sys->hwnd, FALSE );
bool b = var_GetBool( p_vout, "video-on-top" );
/* Set the window on top if necessary */
if( b && !( 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( !b && ( 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;
}
/* Pointer change */
EventThreadMouseAutoHide(sys->event);
}
/*****************************************************************************
......@@ -292,67 +214,81 @@ void CommonManage( vout_thread_t *p_vout )
* its job is to update the source and destination RECTs used to display the
* picture.
*****************************************************************************/
void UpdateRects( vout_thread_t *p_vout, bool b_force )
void UpdateRects(vout_display_t *vd,
const vout_display_cfg_t *cfg,
const video_format_t *source,
bool is_forced)
{
#define rect_src p_vout->p_sys->rect_src
#define rect_src_clipped p_vout->p_sys->rect_src_clipped
#define rect_dest p_vout->p_sys->rect_dest
#define rect_dest_clipped p_vout->p_sys->rect_dest_clipped
unsigned int i_width, i_height, i_x, i_y;
vout_display_sys_t *sys = vd->sys;
#define rect_src sys->rect_src
#define rect_src_clipped sys->rect_src_clipped
#define rect_dest sys->rect_dest
#define rect_dest_clipped sys->rect_dest_clipped
RECT rect;
POINT point;
/* Retrieve the window size */
GetClientRect( p_vout->p_sys->hwnd, &rect );
GetClientRect(sys->hwnd, &rect);
/* Retrieve the window position */
point.x = point.y = 0;
ClientToScreen( p_vout->p_sys->hwnd, &point );
ClientToScreen(sys->hwnd, &point);
/* If nothing changed, we can return */
bool b_changed;
EventThreadUpdateWindowPosition( p_vout->p_sys->p_event, &b_changed,
bool has_changed;
EventThreadUpdateWindowPosition(sys->event, &has_changed,
point.x, point.y,
rect.right, rect.bottom );
if( !b_force && !b_changed )
rect.right, rect.bottom);
if (!is_forced && !has_changed)
return;
/* */
if (!cfg)
cfg = vd->cfg;
if (!source)
source = &vd->source;
/* Update the window position and size */
vout_PlacePicture( p_vout, rect.right, rect.bottom,
&i_x, &i_y, &i_width, &i_height );
vout_display_cfg_t place_cfg = *cfg;
place_cfg.display.width = rect.right;
place_cfg.display.height = rect.bottom;
vout_display_place_t place;
vout_display_PlacePicture(&place, source, &place_cfg, true);
if( p_vout->p_sys->hvideownd )
SetWindowPos( p_vout->p_sys->hvideownd, 0,
i_x, i_y, i_width, i_height,
SWP_NOCOPYBITS|SWP_NOZORDER|SWP_ASYNCWINDOWPOS );
EventThreadUpdateSourceAndPlace(sys->event, source, &place);
if (sys->hvideownd)
SetWindowPos(sys->hvideownd, 0,
place.x, place.y, place.width, place.height,
SWP_NOCOPYBITS|SWP_NOZORDER|SWP_ASYNCWINDOWPOS);
/* Destination image position and dimensions */
#if defined(MODULE_NAME_IS_direct3d)
rect_dest.left = 0;
rect_dest.right = i_width;
rect_dest.right = place.width;
rect_dest.top = 0;
rect_dest.bottom = i_height;
rect_dest.bottom = place.height;
#else
rect_dest.left = point.x + i_x;
rect_dest.right = rect_dest.left + i_width;
rect_dest.top = point.y + i_y;
rect_dest.bottom = rect_dest.top + i_height;
rect_dest.left = point.x + place.x;
rect_dest.right = rect_dest.left + place.width;
rect_dest.top = point.y + place.y;
rect_dest.bottom = rect_dest.top + place.height;
#ifdef MODULE_NAME_IS_directx
/* Apply overlay hardware constraints */
if( p_vout->p_sys->b_using_overlay )
{
if( p_vout->p_sys->i_align_dest_boundary )
rect_dest.left = ( rect_dest.left +
p_vout->p_sys->i_align_dest_boundary / 2 ) &
~p_vout->p_sys->i_align_dest_boundary;
if( p_vout->p_sys->i_align_dest_size )
rect_dest.right = (( rect_dest.right - rect_dest.left +
p_vout->p_sys->i_align_dest_size / 2 ) &
~p_vout->p_sys->i_align_dest_size) + rect_dest.left;
if (sys->b_using_overlay) {
if (sys->i_align_dest_boundary)
rect_dest.left = (rect_dest.left +
sys->i_align_dest_boundary / 2) &
~sys->i_align_dest_boundary;
if (sys->i_align_dest_size)
rect_dest.right = ((rect_dest.right -
rect_dest.left +
sys->i_align_dest_size / 2) &
~sys->i_align_dest_size) + rect_dest.left;
}
#endif
......@@ -364,18 +300,17 @@ void UpdateRects( vout_thread_t *p_vout, bool b_force )
* It is also needed for d3d to avoid exceding our surface size */
/* Clip the destination window */
if( !IntersectRect( &rect_dest_clipped, &rect_dest,
&p_vout->p_sys->rect_display ) )
{
SetRectEmpty( &rect_src_clipped );
if (!IntersectRect(&rect_dest_clipped, &rect_dest,
&sys->rect_display)) {
SetRectEmpty(&rect_src_clipped);
return;
}
#ifndef NDEBUG
msg_Dbg( p_vout, "DirectXUpdateRects image_dst_clipped coords:"
msg_Dbg(vd, "DirectXUpdateRects image_dst_clipped coords:"
" %li,%li,%li,%li",
rect_dest_clipped.left, rect_dest_clipped.top,
rect_dest_clipped.right, rect_dest_clipped.bottom );
rect_dest_clipped.right, rect_dest_clipped.bottom);
#endif
#else
......@@ -386,49 +321,48 @@ void UpdateRects( vout_thread_t *p_vout, bool b_force )
#endif
/* the 2 following lines are to fix a bug when clicking on the desktop */
if( (rect_dest_clipped.right - rect_dest_clipped.left)==0 ||
(rect_dest_clipped.bottom - rect_dest_clipped.top)==0 )
{
SetRectEmpty( &rect_src_clipped );
if ((rect_dest_clipped.right - rect_dest_clipped.left) == 0 ||
(rect_dest_clipped.bottom - rect_dest_clipped.top) == 0) {
SetRectEmpty(&rect_src_clipped);
return;
}
/* src image dimensions */
rect_src.left = 0;
rect_src.top = 0;
rect_src.right = p_vout->render.i_width;
rect_src.bottom = p_vout->render.i_height;
rect_src.right = source->i_width;
rect_src.bottom = source->i_height;
/* Clip the source image */
rect_src_clipped.left = p_vout->fmt_out.i_x_offset +
rect_src_clipped.left = source->i_x_offset +
(rect_dest_clipped.left - rect_dest.left) *
p_vout->fmt_out.i_visible_width / (rect_dest.right - rect_dest.left);
rect_src_clipped.right = p_vout->fmt_out.i_x_offset +
p_vout->fmt_out.i_visible_width -
source->i_visible_width / (rect_dest.right - rect_dest.left);
rect_src_clipped.right = source->i_x_offset +
source->i_visible_width -
(rect_dest.right - rect_dest_clipped.right) *
p_vout->fmt_out.i_visible_width / (rect_dest.right - rect_dest.left);
rect_src_clipped.top = p_vout->fmt_out.i_y_offset +
source->i_visible_width / (rect_dest.right - rect_dest.left);
rect_src_clipped.top = source->i_y_offset +
(rect_dest_clipped.top - rect_dest.top) *
p_vout->fmt_out.i_visible_height / (rect_dest.bottom - rect_dest.top);
rect_src_clipped.bottom = p_vout->fmt_out.i_y_offset +
p_vout->fmt_out.i_visible_height -
source->i_visible_height / (rect_dest.bottom - rect_dest.top);
rect_src_clipped.bottom = source->i_y_offset +
source->i_visible_height -
(rect_dest.bottom - rect_dest_clipped.bottom) *
p_vout->fmt_out.i_visible_height / (rect_dest.bottom - rect_dest.top);
source->i_visible_height / (rect_dest.bottom - rect_dest.top);
#ifdef MODULE_NAME_IS_directx
/* Apply overlay hardware constraints */
if( p_vout->p_sys->b_using_overlay )
{
if( p_vout->p_sys->i_align_src_boundary )
rect_src_clipped.left = ( rect_src_clipped.left +
p_vout->p_sys->i_align_src_boundary / 2 ) &
~p_vout->p_sys->i_align_src_boundary;
if( p_vout->p_sys->i_align_src_size )
rect_src_clipped.right = (( rect_src_clipped.right -
rect_src_clipped.left +
p_vout->p_sys->i_align_src_size / 2 ) &
~p_vout->p_sys->i_align_src_size) + rect_src_clipped.left;
if (sys->b_using_overlay) {
if (sys->i_align_src_boundary)
rect_src_clipped.left =
(rect_src_clipped.left +
sys->i_align_src_boundary / 2) &
~sys->i_align_src_boundary;
if (sys->i_align_src_size)
rect_src_clipped.right =
((rect_src_clipped.right - rect_src_clipped.left +
sys->i_align_src_size / 2) &
~sys->i_align_src_size) + rect_src_clipped.left;
}
#elif defined(MODULE_NAME_IS_direct3d)
/* Needed at least with YUV content */
......@@ -439,59 +373,57 @@ void UpdateRects( vout_thread_t *p_vout, bool b_force )
#endif
#ifndef NDEBUG
msg_Dbg( p_vout, "DirectXUpdateRects image_src_clipped"
msg_Dbg(vd, "DirectXUpdateRects image_src_clipped"
" coords: %li,%li,%li,%li",
rect_src_clipped.left, rect_src_clipped.top,
rect_src_clipped.right, rect_src_clipped.bottom );
rect_src_clipped.right, rect_src_clipped.bottom);
#endif
#ifdef MODULE_NAME_IS_directx
/* The destination coordinates need to be relative to the current
* directdraw primary surface (display) */
rect_dest_clipped.left -= p_vout->p_sys->rect_display.left;
rect_dest_clipped.right -= p_vout->p_sys->rect_display.left;
rect_dest_clipped.top -= p_vout->p_sys->rect_display.top;
rect_dest_clipped.bottom -= p_vout->p_sys->rect_display.top;
rect_dest_clipped.left -= sys->rect_display.left;
rect_dest_clipped.right -= sys->rect_display.left;
rect_dest_clipped.top -= sys->rect_display.top;
rect_dest_clipped.bottom -= sys->rect_display.top;
if( p_vout->p_sys->b_using_overlay )
DirectDrawUpdateOverlay( p_vout );
if (sys->b_using_overlay)
DirectDrawUpdateOverlay(vd);
#endif
#ifndef UNDER_CE
/* Windows 7 taskbar thumbnail code */
LPTASKBARLIST3 p_taskbl;
LPTASKBARLIST3 taskbl;
OSVERSIONINFO winVer;
winVer.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
if( GetVersionEx(&winVer) && winVer.dwMajorVersion > 5 )
{
CoInitialize( 0 );
if (GetVersionEx(&winVer) && winVer.dwMajorVersion > 5) {
CoInitialize(0);
if( S_OK == CoCreateInstance( &clsid_ITaskbarList,
if (S_OK == CoCreateInstance(&clsid_ITaskbarList,
NULL, CLSCTX_INPROC_SERVER,
&IID_ITaskbarList3,
&p_taskbl) )
{
&taskbl)) {
RECT rect_video, rect_parent, rect_relative;
HWND hroot = GetAncestor(p_vout->p_sys->hwnd,GA_ROOT);
HWND hroot = GetAncestor(sys->hwnd,GA_ROOT);
p_taskbl->vt->HrInit(p_taskbl);
GetWindowRect(p_vout->p_sys->hvideownd, &rect_video);
taskbl->vt->HrInit(taskbl);
GetWindowRect(sys->hvideownd, &rect_video);
GetWindowRect(hroot, &rect_parent);
rect_relative.left = rect_video.left - rect_parent.left - 8;
rect_relative.right = rect_video.right - rect_video.left + rect_relative.left;
rect_relative.top = rect_video.top - rect_parent.top - 10;
rect_relative.bottom = rect_video.bottom - rect_video.top + rect_relative.top - 25;
if (S_OK != p_taskbl->vt->SetThumbnailClip(p_taskbl, hroot, &rect_relative))
msg_Err( p_vout, "SetThumbNailClip failed");
if (S_OK != taskbl->vt->SetThumbnailClip(taskbl, hroot, &rect_relative))
msg_Err(vd, "SetThumbNailClip failed");
p_taskbl->vt->Release(p_taskbl);
taskbl->vt->Release(taskbl);
}
CoUninitialize();
}
#endif
/* Signal the change in size/position */
p_vout->p_sys->i_changes |= DX_POSITION_CHANGE;
sys->changes |= DX_POSITION_CHANGE;
#undef rect_src
#undef rect_src_clipped
......@@ -499,254 +431,238 @@ void UpdateRects( vout_thread_t *p_vout, bool b_force )
#undef rect_dest_clipped
}
/*****************************************************************************
* Control: control facility for the vout
*****************************************************************************/
int Control( vout_thread_t *p_vout, int i_query, va_list args )
static int CommonControlSetFullscreen(vout_display_t *vd, bool is_fullscreen)
{
RECT rect_window;
switch( i_query )
{
case VOUT_SET_SIZE:
if( p_vout->p_sys->parent_window )
return vaControlParentWindow( p_vout, i_query, args );
/* Update dimensions */
rect_window.top = rect_window.left = 0;
rect_window.right = va_arg( args, unsigned int );
rect_window.bottom = va_arg( args, unsigned int );
if( !rect_window.right ) rect_window.right = p_vout->i_window_width;
if( !rect_window.bottom ) rect_window.bottom = p_vout->i_window_height;
AdjustWindowRect( &rect_window, EventThreadGetWindowStyle( p_vout->p_sys->p_event ), 0 );
SetWindowPos( p_vout->p_sys->hwnd, 0, 0, 0,
rect_window.right - rect_window.left,
rect_window.bottom - rect_window.top, SWP_NOMOVE );
return VLC_SUCCESS;
case VOUT_SET_STAY_ON_TOP:
if( p_vout->p_sys->hparent && !var_GetBool( p_vout, "fullscreen" ) )
return vaControlParentWindow( p_vout, i_query, args );
p_vout->p_sys->b_on_top_change = true;
return VLC_SUCCESS;
default:
return VLC_EGENERIC;
}
}
vout_display_sys_t *sys = vd->sys;
/* Internal wrapper over GetWindowPlacement */
static WINDOWPLACEMENT getWindowState(HWND hwnd)
{
WINDOWPLACEMENT window_placement;
window_placement.length = sizeof(WINDOWPLACEMENT);
GetWindowPlacement( hwnd, &window_placement );
return window_placement;
}
/* Internal wrapper to call vout_ControlWindow for hparent */
static int vaControlParentWindow( vout_thread_t *p_vout, int i_query,
va_list args )
{
switch( i_query )
{
case VOUT_SET_SIZE:
{
const unsigned i_width = va_arg(args, unsigned);
const unsigned i_height = va_arg(args, unsigned);
return vout_window_SetSize( p_vout->p_sys->parent_window, i_width, i_height );
}
case VOUT_SET_STAY_ON_TOP:
{
const bool is_on_top = va_arg(args, int);
return vout_window_SetOnTop( p_vout->p_sys->parent_window, is_on_top );
}
default:
#ifdef MODULE_NAME_IS_direct3d
if (sys->use_desktop && is_fullscreen)
return VLC_EGENERIC;
}
}
#if 0
static int ControlParentWindow( vout_thread_t *p_vout, int i_query, ... )
{
va_list args;
int ret;
va_start( args, i_query );
ret = vaControlParentWindow( p_vout, i_query, args );
va_end( args );
return ret;
}
#endif
void ExitFullscreen( vout_thread_t *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 (sys->parent_window)
return vout_window_SetFullScreen(sys->parent_window, is_fullscreen);
void Win32ToggleFullscreen( vout_thread_t *p_vout )
{
HWND hwnd = (p_vout->p_sys->hparent && p_vout->p_sys->hfswnd) ?
p_vout->p_sys->hfswnd : p_vout->p_sys->hwnd;
/* */
HWND hwnd = sys->hparent && sys->hfswnd ? sys->hfswnd : sys->hwnd;
/* Save the current windows placement/placement to restore
when fullscreen is over */
WINDOWPLACEMENT window_placement = getWindowState( hwnd );
p_vout->b_fullscreen = ! p_vout->b_fullscreen;
WINDOWPLACEMENT window_placement;
window_placement.length = sizeof(WINDOWPLACEMENT);
GetWindowPlacement(hwnd, &window_placement);
/* We want to go to Fullscreen */
if( p_vout->b_fullscreen )
{
msg_Dbg( p_vout, "entering fullscreen mode" );
if (is_fullscreen) {
msg_Dbg(vd, "entering fullscreen mode");
/* Change window style, no borders and no title bar */
int i_style = WS_CLIPCHILDREN | WS_VISIBLE;
SetWindowLong( hwnd, GWL_STYLE, i_style );
SetWindowLong(hwnd, GWL_STYLE, WS_CLIPCHILDREN | WS_VISIBLE);
if( p_vout->p_sys->hparent )
{
if (sys->hparent) {
#ifdef UNDER_CE
POINT point = {0,0};
RECT rect;
ClientToScreen( p_vout->p_sys->hwnd, &point );
GetClientRect( p_vout->p_sys->hwnd, &rect );
SetWindowPos( hwnd, 0, point.x, point.y,
ClientToScreen(sys->hwnd, &point);
GetClientRect(sys->hwnd, &rect);
SetWindowPos(hwnd, 0, point.x, point.y,
rect.right, rect.bottom,
SWP_NOZORDER|SWP_FRAMECHANGED );
SWP_NOZORDER|SWP_FRAMECHANGED);
#else
/* Retrieve current window position so fullscreen will happen
*on the right screen */
HMONITOR hmon = MonitorFromWindow(p_vout->p_sys->hparent,
HMONITOR hmon = MonitorFromWindow(sys->hparent,
MONITOR_DEFAULTTONEAREST);
MONITORINFO mi;
mi.cbSize = sizeof(MONITORINFO);
if (GetMonitorInfo(hmon, &mi))
SetWindowPos( hwnd, 0,
SetWindowPos(hwnd, 0,
mi.rcMonitor.left,
mi.rcMonitor.top,
mi.rcMonitor.right - mi.rcMonitor.left,
mi.rcMonitor.bottom - mi.rcMonitor.top,
SWP_NOZORDER|SWP_FRAMECHANGED );
SWP_NOZORDER|SWP_FRAMECHANGED);
#endif
}
else
{
} else {
/* Maximize non embedded window */
ShowWindow( hwnd, SW_SHOWMAXIMIZED );
ShowWindow(hwnd, SW_SHOWMAXIMIZED);
}
if( p_vout->p_sys->hparent )
{
if (sys->hparent) {
/* Hide the previous window */
RECT rect;
GetClientRect( hwnd, &rect );
SetParent( p_vout->p_sys->hwnd, hwnd );
SetWindowPos( p_vout->p_sys->hwnd, 0, 0, 0,
GetClientRect(hwnd, &rect);
SetParent(sys->hwnd, hwnd);
SetWindowPos(sys->hwnd, 0, 0, 0,
rect.right, rect.bottom,
SWP_NOZORDER|SWP_FRAMECHANGED );
SWP_NOZORDER|SWP_FRAMECHANGED);
#ifdef UNDER_CE
HWND topLevelParent = GetParent( p_vout->p_sys->hparent );
HWND topLevelParent = GetParent(sys->hparent);
#else
HWND topLevelParent = GetAncestor( p_vout->p_sys->hparent, GA_ROOT );
HWND topLevelParent = GetAncestor(sys->hparent, GA_ROOT);
#endif
ShowWindow( topLevelParent, SW_HIDE );
ShowWindow(topLevelParent, SW_HIDE);
}
SetForegroundWindow(hwnd);
} else {
msg_Dbg(vd, "leaving fullscreen mode");
SetForegroundWindow( hwnd );
}
else
{
msg_Dbg( p_vout, "leaving fullscreen mode" );
/* Change window style, no borders and no title bar */
SetWindowLong( hwnd, GWL_STYLE, EventThreadGetWindowStyle( p_vout->p_sys->p_event ) );
SetWindowLong(hwnd, GWL_STYLE, EventThreadGetWindowStyle(sys->event));
if( p_vout->p_sys->hparent )
{
if (sys->hparent) {
RECT rect;
GetClientRect( p_vout->p_sys->hparent, &rect );
SetParent( p_vout->p_sys->hwnd, p_vout->p_sys->hparent );
SetWindowPos( p_vout->p_sys->hwnd, 0, 0, 0,
GetClientRect(sys->hparent, &rect);
SetParent(sys->hwnd, sys->hparent);
SetWindowPos(sys->hwnd, 0, 0, 0,
rect.right, rect.bottom,
SWP_NOZORDER|SWP_FRAMECHANGED );
SWP_NOZORDER|SWP_FRAMECHANGED);
#ifdef UNDER_CE
HWND topLevelParent = GetParent( p_vout->p_sys->hparent );
HWND topLevelParent = GetParent(sys->hparent);
#else
HWND topLevelParent = GetAncestor( p_vout->p_sys->hparent, GA_ROOT );
HWND topLevelParent = GetAncestor(sys->hparent, GA_ROOT);
#endif
ShowWindow( topLevelParent, SW_SHOW );
SetForegroundWindow( p_vout->p_sys->hparent );
ShowWindow( hwnd, SW_HIDE );
}
else
{
ShowWindow(topLevelParent, SW_SHOW);
SetForegroundWindow(sys->hparent);
ShowWindow(hwnd, SW_HIDE);
} else {
/* return to normal window for non embedded vout */
SetWindowPlacement( hwnd, &window_placement );
ShowWindow( hwnd, SW_SHOWNORMAL );
SetWindowPlacement(hwnd, &window_placement);
ShowWindow(hwnd, SW_SHOWNORMAL);
}
/* Make sure the mouse cursor is displayed */
EventThreadMouseShow( p_vout->p_sys->p_event );
EventThreadMouseShow(sys->event);
}
return VLC_SUCCESS;
}
int CommonControl(vout_display_t *vd, int query, va_list args)
{
vout_display_sys_t *sys = vd->sys;
switch (query) {
case VOUT_DISPLAY_CHANGE_DISPLAY_SIZE: /* const vout_display_cfg_t *p_cfg, int is_forced */
case VOUT_DISPLAY_CHANGE_DISPLAY_FILLED: /* const vout_display_cfg_t *p_cfg */
case VOUT_DISPLAY_CHANGE_ZOOM: /* const vout_display_cfg_t *p_cfg */
case VOUT_DISPLAY_CHANGE_SOURCE_ASPECT: /* const video_format_t *p_source */
case VOUT_DISPLAY_CHANGE_SOURCE_CROP: { /* const video_format_t *p_source */
const vout_display_cfg_t *cfg;
const video_format_t *source;
bool is_forced = true;
if (query == VOUT_DISPLAY_CHANGE_SOURCE_CROP ||
query == VOUT_DISPLAY_CHANGE_SOURCE_ASPECT) {
cfg = vd->cfg;
source = va_arg(args, const video_format_t *);
} else {
cfg = va_arg(args, const vout_display_cfg_t *);
source = &vd->source;
if (query == VOUT_DISPLAY_CHANGE_DISPLAY_SIZE)
is_forced = va_arg(args, int);
}
if (query == VOUT_DISPLAY_CHANGE_DISPLAY_SIZE && is_forced) {
/* Update dimensions */
if (sys->parent_window) {
vout_window_SetSize(sys->parent_window, cfg->display.width, cfg->display.height);
} else {
RECT rect_window;
rect_window.top = 0;
rect_window.left = 0;
rect_window.right = cfg->display.width;
rect_window.bottom = cfg->display.height;
AdjustWindowRect(&rect_window, EventThreadGetWindowStyle(sys->event), 0);
SetWindowPos(sys->hwnd, 0, 0, 0,
rect_window.right - rect_window.left,
rect_window.bottom - rect_window.top, SWP_NOMOVE);
}
}
UpdateRects(vd, cfg, source, is_forced);
return VLC_SUCCESS;
}
case VOUT_DISPLAY_CHANGE_ON_TOP: { /* int b_on_top */
const bool is_on_top = va_arg(args, int);
#ifdef MODULE_NAME_IS_direct3d
if (sys->use_desktop && is_on_top)
return VLC_EGENERIC;
#endif
if (sys->parent_window) {
if (vout_window_SetOnTop(sys->parent_window, is_on_top))
return VLC_EGENERIC;
} else {
HMENU hMenu = GetSystemMenu(sys->hwnd, FALSE);
if (is_on_top && !(GetWindowLong(sys->hwnd, GWL_EXSTYLE) & WS_EX_TOPMOST)) {
CheckMenuItem(hMenu, IDM_TOGGLE_ON_TOP, MF_BYCOMMAND | MFS_CHECKED);
SetWindowPos(sys->hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
} else if (!is_on_top && (GetWindowLong(sys->hwnd, GWL_EXSTYLE) & WS_EX_TOPMOST)) {
CheckMenuItem(hMenu, IDM_TOGGLE_ON_TOP, MF_BYCOMMAND | MFS_UNCHECKED);
SetWindowPos(sys->hwnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE);
}
}
sys->is_on_top = is_on_top;
return VLC_SUCCESS;
}
case VOUT_DISPLAY_CHANGE_FULLSCREEN: { /* const vout_display_cfg_t *p_cfg */
const vout_display_cfg_t *cfg = va_arg(args, const vout_display_cfg_t *);
return CommonControlSetFullscreen(vd, cfg->is_fullscreen);
}
/* Update the object variable and trigger callback */
var_SetBool( p_vout, "fullscreen", p_vout->b_fullscreen );
case VOUT_DISPLAY_RESET_PICTURES:
case VOUT_DISPLAY_HIDE_MOUSE:
assert(0);
default:
return VLC_EGENERIC;
}
}
#ifndef UNDER_CE
void DisableScreensaver( vout_thread_t *p_vout )
static void DisableScreensaver(vout_display_t *vd)
{
vout_display_sys_t *sys = vd->sys;
/* 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 ) {
sys->i_spi_lowpowertimeout = 0;
sys->i_spi_powerofftimeout = 0;
sys->i_spi_screensavetimeout = 0;
if (var_GetBool(vd, "disable-screensaver")) {
msg_Dbg(vd, "disabling screen saver");
SystemParametersInfo(SPI_GETLOWPOWERTIMEOUT, 0,
&sys->i_spi_lowpowertimeout, 0);
if (0 != 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 ) {
&sys->i_spi_powerofftimeout, 0);
if (0 != 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 ) {
&sys->i_spi_screensavetimeout, 0);
if (0 != sys->i_spi_screensavetimeout) {
SystemParametersInfo(SPI_SETSCREENSAVETIMEOUT, 0, NULL, 0);
}
}
}
void RestoreScreensaver( vout_thread_t *p_vout )
static void RestoreScreensaver(vout_display_t *vd)
{
vout_display_sys_t *sys = vd->sys;
/* restore screensaver system settings */
if( 0 != p_vout->p_sys->i_spi_lowpowertimeout ) {
if (0 != sys->i_spi_lowpowertimeout) {
SystemParametersInfo(SPI_SETLOWPOWERTIMEOUT,
p_vout->p_sys->i_spi_lowpowertimeout, NULL, 0);
sys->i_spi_lowpowertimeout, NULL, 0);
}
if( 0 != p_vout->p_sys->i_spi_powerofftimeout ) {
if (0 != sys->i_spi_powerofftimeout) {
SystemParametersInfo(SPI_SETPOWEROFFTIMEOUT,
p_vout->p_sys->i_spi_powerofftimeout, NULL, 0);
sys->i_spi_powerofftimeout, NULL, 0);
}
if( 0 != p_vout->p_sys->i_spi_screensavetimeout ) {
if (0 != sys->i_spi_screensavetimeout) {
SystemParametersInfo(SPI_SETSCREENSAVETIMEOUT,
p_vout->p_sys->i_spi_screensavetimeout, NULL, 0);
sys->i_spi_screensavetimeout, NULL, 0);
}
}
#endif
......
/*****************************************************************************
* common.h: Windows video output header file
*****************************************************************************
* Copyright (C) 2001-2009 the VideoLAN team
* $Id$
*
* Authors: Gildas Bazin <gbazin@videolan.org>
* Damien Fouilleul <damienf@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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
/*****************************************************************************
* event_thread_t: event thread
*****************************************************************************/
#include <vlc_picture_pool.h>
#include "events.h"
#ifdef MODULE_NAME_IS_wingapi
typedef struct GXDisplayProperties {
DWORD cxWidth;
DWORD cyHeight;
long cbxPitch;
long cbyPitch;
long cBPP;
DWORD ffFormat;
} GXDisplayProperties;
typedef struct GXScreenRect {
DWORD dwTop;
DWORD dwLeft;
DWORD dwWidth;
DWORD dwHeight;
} GXScreenRect;
# define GX_FULLSCREEN 0x01
# define GX_NORMALKEYS 0x02
# define GX_LANDSCAPEKEYS 0x03
# ifndef kfLandscape
# define kfLandscape 0x8
# define kfPalette 0x10
# define kfDirect 0x20
# define kfDirect555 0x40
# define kfDirect565 0x80
# define kfDirect888 0x100
# define kfDirect444 0x200
# define kfDirectInverted 0x400
# endif
#endif
/*****************************************************************************
* vout_sys_t: video output method descriptor
*****************************************************************************
* This structure is part of the video output thread descriptor.
* It describes the module specific properties of an output thread.
*****************************************************************************/
struct vout_display_sys_t
{
/* */
event_thread_t *event;
/* */
HWND hwnd; /* Handle of the main window */
HWND hvideownd; /* Handle of the video sub-window */
struct vout_window_t *parent_window; /* Parent window VLC object */
HWND hparent; /* Handle of the parent window */
HWND hfswnd; /* Handle of the fullscreen window */
/* Multi-monitor support */
HMONITOR hmonitor; /* handle of the current monitor */
GUID *p_display_driver;
HMONITOR (WINAPI* MonitorFromWindow)(HWND, DWORD);
BOOL (WINAPI* GetMonitorInfo)(HMONITOR, LPMONITORINFO);
/* size of the display */
RECT rect_display;
int display_depth;
/* size of the overall window (including black bands) */
RECT rect_parent;
unsigned changes; /* changes made to the video display */
/* Misc */
bool is_first_display;
bool is_on_top;
#ifndef UNDER_CE
/* screensaver system settings to be restored when vout is closed */
UINT i_spi_lowpowertimeout;
UINT i_spi_powerofftimeout;
UINT i_spi_screensavetimeout;
#endif
/* Coordinates of src and dest images (used when blitting to display) */
RECT rect_src;
RECT rect_src_clipped;
RECT rect_dest;
RECT rect_dest_clipped;
bool allow_hw_yuv; /* Should we use hardware YUV->RGB conversions */
#ifdef MODULE_NAME_IS_directx
/* Overlay alignment restrictions */
int i_align_src_boundary;
int i_align_src_size;
int i_align_dest_boundary;
int i_align_dest_size;
bool b_wallpaper; /* show as desktop wallpaper ? */
bool b_using_overlay; /* Are we using an overlay surface */
bool b_use_sysmem; /* Should we use system memory for surfaces */
bool b_3buf_overlay; /* Should we use triple buffered overlays */
/* DDraw capabilities */
int b_caps_overlay_clipping;
unsigned int i_rgb_colorkey; /* colorkey in RGB used by the overlay */
unsigned int i_colorkey; /* colorkey used by the overlay */
COLORREF color_bkg;
COLORREF color_bkgtxt;
LPDIRECTDRAW2 p_ddobject; /* DirectDraw object */
LPDIRECTDRAWSURFACE2 p_display; /* Display device */
LPDIRECTDRAWSURFACE2 p_current_surface; /* surface currently displayed */
LPDIRECTDRAWCLIPPER p_clipper; /* clipper used for blitting */
HINSTANCE hddraw_dll; /* handle of the opened ddraw dll */
vlc_mutex_t lock;
#endif
#ifdef MODULE_NAME_IS_glwin32
HDC hGLDC;
HGLRC hGLRC;
#endif
#ifdef MODULE_NAME_IS_direct3d
/* show video on desktop window ? */
bool use_desktop;
struct {
bool is_fullscreen;
bool is_on_top;
RECT win;
} desktop_save;
vout_display_cfg_t cfg_saved; /* configuration used before going into desktop mode */
// core objects
HINSTANCE hd3d9_dll; /* handle of the opened d3d9 dll */
LPDIRECT3D9 d3dobj;
LPDIRECT3DDEVICE9 d3ddev;
D3DPRESENT_PARAMETERS d3dpp;
// scene objects
LPDIRECT3DTEXTURE9 d3dtex;
LPDIRECT3DVERTEXBUFFER9 d3dvtc;
picture_resource_t resource;
picture_pool_t *pool;
/* */
bool reset_device;
bool reopen_device;
/* It protects the following variables */
vlc_mutex_t lock;
bool ch_desktop;
bool desktop_requested;
#endif
#ifdef MODULE_NAME_IS_wingdi
int i_depth;
/* Our offscreen bitmap and its framebuffer */
HDC off_dc;
HBITMAP off_bitmap;
uint8_t * p_pic_buffer;
int i_pic_pitch;
int i_pic_pixel_pitch;
BITMAPINFO bitmapinfo;
RGBQUAD red;
RGBQUAD green;
RGBQUAD blue;
#endif
#ifdef MODULE_NAME_IS_wingapi
int i_depth;
int render_width;
int render_height;
/* Our offscreen bitmap and its framebuffer */
HDC off_dc;
HBITMAP off_bitmap;
uint8_t * p_pic_buffer;
int i_pic_pitch;
int i_pic_pixel_pitch;
BITMAPINFO bitmapinfo;
RGBQUAD red;
RGBQUAD green;
RGBQUAD blue;
HINSTANCE gapi_dll; /* handle of the opened gapi dll */
/* GAPI functions */
int (*GXOpenDisplay)(HWND hWnd, DWORD dwFlags);
int (*GXCloseDisplay)();
void *(*GXBeginDraw)();
int (*GXEndDraw)();
GXDisplayProperties (*GXGetDisplayProperties)();
int (*GXSuspend)();
int (*GXResume)();
#endif
};
#ifdef MODULE_NAME_IS_wingapi
# define GXOpenDisplay p_vout->p_sys->GXOpenDisplay
# define GXCloseDisplay p_vout->p_sys->GXCloseDisplay
# define GXBeginDraw p_vout->p_sys->GXBeginDraw
# define GXEndDraw p_vout->p_sys->GXEndDraw
# define GXGetDisplayProperties p_vout->p_sys->GXGetDisplayProperties
# define GXSuspend p_vout->p_sys->GXSuspend
# define GXResume p_vout->p_sys->GXResume
#endif
/*****************************************************************************
* Prototypes from directx.c
*****************************************************************************/
int DirectDrawUpdateOverlay(vout_display_t *);
/*****************************************************************************
* Prototypes from common.c
*****************************************************************************/
int CommonInit(vout_display_t *);
void CommonClean(vout_display_t *);
void CommonManage(vout_display_t *);
int CommonControl(vout_display_t *, int , va_list );
void UpdateRects (vout_display_t *,
const vout_display_cfg_t *,
const video_format_t *,
bool is_forced);
/*****************************************************************************
* Constants
*****************************************************************************/
#define IDM_TOGGLE_ON_TOP WM_USER + 1
#define DX_POSITION_CHANGE 0x1000
#define DX_WALLPAPER_CHANGE 0x2000
#define DX_DESKTOP_CHANGE 0x4000
/*****************************************************************************
* WinCE helpers
*****************************************************************************/
#ifdef UNDER_CE
#define AdjustWindowRect(a,b,c)
#ifndef GCL_HBRBACKGROUND
# define GCL_HBRBACKGROUND (-10)
#endif
//#define FindWindowEx(a,b,c,d) 0
#define GetWindowPlacement(a,b)
#define SetWindowPlacement(a,b)
/*typedef struct _WINDOWPLACEMENT {
UINT length;
UINT flags;
UINT showCmd;
POINT ptMinPosition;
POINT ptMaxPosition;
RECT rcNormalPosition;
} WINDOWPLACEMENT;*/
#ifndef WM_NCMOUSEMOVE
# define WM_NCMOUSEMOVE 160
#endif
#ifndef CS_OWNDC
# define CS_OWNDC 32
#endif
#ifndef SC_SCREENSAVE
# define SC_SCREENSAVE 0xF140
#endif
#ifndef SC_MONITORPOWER
# define SC_MONITORPOWER 0xF170
#endif
#ifndef WM_NCPAINT
# define WM_NCPAINT 133
#endif
#ifndef WS_OVERLAPPEDWINDOW
# define WS_OVERLAPPEDWINDOW 0xcf0000
#endif
#ifndef WS_EX_NOPARENTNOTIFY
# define WS_EX_NOPARENTNOTIFY 4
#endif
#ifndef WS_EX_APPWINDOW
#define WS_EX_APPWINDOW 0x40000
#endif
//#define SetWindowLongPtr SetWindowLong
//#define GetWindowLongPtr GetWindowLong
//#define GWLP_USERDATA GWL_USERDATA
#endif //UNDER_CE
......@@ -40,7 +40,7 @@
#include <vlc_common.h>
#include <vlc_plugin.h>
#include <vlc_playlist.h>
#include <vlc_vout.h>
#include <vlc_vout_display.h>
#include <windows.h>
#include <d3d9.h>
......@@ -63,20 +63,19 @@ vlc_module_begin ()
set_category(CAT_VIDEO)
set_subcategory(SUBCAT_VIDEO_VOUT)
add_bool("direct3d-desktop", false, NULL, DESKTOP_TEXT, DESKTOP_LONGTEXT,
true)
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")
set_capability("vout display", 50)
add_shortcut("direct3d_xp")
set_callbacks(OpenVideoXP, Close)
/* FIXME: Hack to avoid unregistering our window class */
linked_with_a_crap_library_which_uses_atexit ()
linked_with_a_crap_library_which_uses_atexit()
add_submodule()
set_capability("video output", 150)
add_shortcut("direct3d")
add_shortcut("direct3d_vista")
set_callbacks(OpenVideoVista, Close)
vlc_module_end ()
......@@ -91,92 +90,106 @@ vlc_module_end ()
/*****************************************************************************
* Local prototypes.
*****************************************************************************/
static int Open(vlc_object_t *);
static int Init (vout_thread_t *);
static void End (vout_thread_t *);
static int Manage (vout_thread_t *);
static void Display (vout_thread_t *, picture_t *);
static void FirstDisplay(vout_thread_t *, picture_t *);
static int Direct3DCreate (vout_thread_t *);
static void Direct3DRelease (vout_thread_t *);
struct picture_sys_t
{
LPDIRECT3DSURFACE9 surface;
};
static int Direct3DOpen (vout_thread_t *);
static void Direct3DClose (vout_thread_t *);
static int Open(vlc_object_t *);
static int Direct3DResetDevice(vout_thread_t *);
static picture_t *Get (vout_display_t *);
static void Prepare(vout_display_t *, picture_t *);
static void Display(vout_display_t *, picture_t *);
static int Control(vout_display_t *, int, va_list);
static void Manage (vout_display_t *);
static int Direct3DCreatePictures (vout_thread_t *, size_t);
static void Direct3DReleasePictures (vout_thread_t *);
static int Direct3DCreate (vout_display_t *);
static int Direct3DReset (vout_display_t *);
static void Direct3DDestroy(vout_display_t *);
static int Direct3DLockSurface (vout_thread_t *, picture_t *);
static int Direct3DUnlockSurface(vout_thread_t *, picture_t *);
static int Direct3DOpen (vout_display_t *, video_format_t *);
static void Direct3DClose(vout_display_t *);
static int Direct3DCreateScene (vout_thread_t *);
static void Direct3DReleaseScene (vout_thread_t *);
static void Direct3DRenderScene (vout_thread_t *, picture_t *);
static void Direct3DRenderScene(vout_display_t *vd, LPDIRECT3DSURFACE9 surface);
/* */
static int DesktopCallback(vlc_object_t *, char const *, vlc_value_t, vlc_value_t, void *);
typedef struct
{
FLOAT x,y,z; // vertex untransformed position
FLOAT rhw; // eye distance
D3DCOLOR diffuse; // diffuse color
FLOAT tu, tv; // texture relative coordinates
} CUSTOMVERTEX;
#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZRHW|D3DFVF_DIFFUSE|D3DFVF_TEX1)
/**
* It creates a Direct3D vout display.
*/
static int Open(vlc_object_t *object)
{
vout_thread_t *p_vout = (vout_thread_t *)object;
vout_sys_t *p_sys;
vout_display_t *vd = (vout_display_t *)object;
vout_display_sys_t *sys;
/* Allocate structure */
p_vout->p_sys = p_sys = calloc(1, sizeof(vout_sys_t));
if (!p_sys)
vd->sys = sys = calloc(1, sizeof(vout_display_sys_t));
if (!sys)
return VLC_ENOMEM;
if (VLC_SUCCESS != Direct3DCreate(p_vout)) {
msg_Err(p_vout, "Direct3D could not be initialized !");
Direct3DRelease(p_vout);
free(p_sys);
if (Direct3DCreate(vd)) {
msg_Err(vd, "Direct3D could not be initialized");
Direct3DDestroy(vd);
free(sys);
return VLC_EGENERIC;
}
p_sys->b_desktop = false;
/* Initialisations */
p_vout->pf_init = Init;
p_vout->pf_end = End;
p_vout->pf_manage = Manage;
p_vout->pf_render = Direct3DRenderScene;
p_vout->pf_display = FirstDisplay;
p_vout->pf_control = Control;
sys->use_desktop = var_CreateGetBool(vd, "direct3d-desktop");
sys->reset_device = false;
sys->reset_device = false;
sys->allow_hw_yuv = var_CreateGetBool(vd, "directx-hw-yuv");
sys->desktop_save.is_fullscreen = vd->cfg->is_fullscreen;
sys->desktop_save.is_on_top = false;
sys->desktop_save.win.left = 0;
sys->desktop_save.win.right = vd->cfg->display.width;
sys->desktop_save.win.top = 0;
sys->desktop_save.win.bottom = vd->cfg->display.height;
if (CommonInit(vd))
goto error;
if (CommonInit(p_vout))
/* */
video_format_t fmt;
if (Direct3DOpen(vd, &fmt)) {
msg_Err(vd, "Direct3D could not be opened");
goto error;
}
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);
/* */
vout_display_info_t info = vd->info;
info.is_slow = true;
info.has_double_click = true;
info.has_hide_mouse = true;
info.has_pictures_invalid = true;
/* Interaction */
vlc_mutex_init(&sys->lock);
sys->ch_desktop = false;
sys->desktop_requested = sys->use_desktop;
/* Trigger a callback right now */
var_Create(p_vout, "direct3d-desktop", VLC_VAR_BOOL|VLC_VAR_DOINHERIT);
vlc_value_t val;
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");
var_Change(vd, "direct3d-desktop", VLC_VAR_SETTEXT, &val, NULL);
var_AddCallback(vd, "direct3d-desktop", DesktopCallback, NULL);
return VLC_SUCCESS;
/* Setup vout_display now that everything is fine */
vd->fmt = fmt;
vd->info = info;
vd->get = Get;
vd->prepare = Prepare;
vd->display = Display;
vd->control = Control;
vd->manage = Manage;
/* Fix state in case of desktop mode */
if (sys->use_desktop && vd->cfg->is_fullscreen)
vout_display_SendEventFullscreen(vd, false);
return VLC_SUCCESS;
error:
Close(VLC_OBJECT(p_vout));
Close(VLC_OBJECT(vd));
return VLC_EGENERIC;
}
......@@ -204,92 +217,212 @@ static int OpenVideoVista(vlc_object_t *obj)
*/
static void Close(vlc_object_t *object)
{
vout_thread_t * p_vout = (vout_thread_t *)object;
vout_display_t * vd = (vout_display_t *)object;
var_DelCallback(vd, "direct3d-desktop", DesktopCallback, NULL);
Direct3DClose(vd);
CommonClean(p_vout);
CommonClean(vd);
Direct3DRelease(p_vout);
Direct3DDestroy(vd);
free(p_vout->p_sys);
free(vd->sys);
}
/*****************************************************************************
* Init: initialize Direct3D video thread output method
*****************************************************************************/
static int Init(vout_thread_t *p_vout)
/* */
static picture_t *Get(vout_display_t *vd)
{
vout_sys_t *p_sys = p_vout->p_sys;
int i_ret;
vout_display_sys_t *sys = vd->sys;
p_sys->b_hw_yuv = var_GetBool(p_vout, "directx-hw-yuv");
if (!sys->pool)
return NULL;
return picture_pool_Get(sys->pool);
}
/* Initialise Direct3D */
if (Direct3DOpen(p_vout)) {
msg_Err(p_vout, "cannot initialize Direct3D");
return VLC_EGENERIC;
static int Direct3DLockSurface(picture_t *);
static void Direct3DUnlockSurface(picture_t *);
static void Prepare(vout_display_t *vd, picture_t *picture)
{
LPDIRECT3DSURFACE9 surface = picture->p_sys->surface;
#if 0
picture_Release(picture);
Direct3DRenderScene(vd, surface);
#else
/* FIXME it is a bit ugly, we need the surface to be unlocked for
* rendering.
* The clean way would be to release the picture (and ensure that
* the vout doesn't keep a reference). But because of the vout
* wrapper, we can't */
Direct3DUnlockSurface(picture);
Direct3DRenderScene(vd, surface);
Direct3DLockSurface(picture);
#endif
}
static void Display(vout_display_t *vd, picture_t *picture)
{
vout_display_sys_t *sys = vd->sys;
LPDIRECT3DDEVICE9 d3ddev = sys->d3ddev;
// Present the back buffer contents to the display
// No stretching should happen here !
const RECT src = sys->rect_dest_clipped;
const RECT dst = sys->rect_dest_clipped;
HRESULT hr = IDirect3DDevice9_Present(d3ddev, &src, &dst, NULL, NULL);
if (FAILED(hr)) {
msg_Dbg(vd, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
}
if (sys->is_first_display) {
/* Video window is initially hidden, show it now since we got a
* picture to show.
*/
SetWindowPos(vd->sys->hvideownd, 0, 0, 0, 0, 0,
SWP_ASYNCWINDOWPOS|
SWP_FRAMECHANGED|
SWP_SHOWWINDOW|
SWP_NOMOVE|
SWP_NOSIZE|
SWP_NOZORDER);
sys->is_first_display = false;
}
/* Initialize the output structure.
* Since Direct3D can do rescaling for us, stick to the default
* coordinates and aspect. */
p_vout->output.i_width = p_vout->render.i_width;
p_vout->output.i_height = p_vout->render.i_height;
p_vout->output.i_aspect = p_vout->render.i_aspect;
p_vout->fmt_out = p_vout->fmt_in;
UpdateRects(p_vout, true);
#if 0
VLC_UNUSED(picture);
#else
/* XXX See Prepare() */
picture_Release(picture);
#endif
}
static int ControlResetDevice(vout_display_t *vd)
{
return Direct3DReset(vd);
}
static int ControlReopenDevice(vout_display_t *vd)
{
vout_display_sys_t *sys = vd->sys;
if (!sys->use_desktop) {
/* Save non-desktop state */
sys->desktop_save.is_fullscreen = vd->cfg->is_fullscreen;
sys->desktop_save.is_on_top = sys->is_on_top;
/* create picture pool */
p_vout->output.i_chroma = 0;
i_ret = Direct3DCreatePictures(p_vout, 1);
if (i_ret) {
msg_Err(p_vout, "Direct3D picture pool initialization failed !");
return i_ret;
WINDOWPLACEMENT wp = { .length = sizeof(wp), };
GetWindowPlacement(sys->hparent ? sys->hparent : sys->hwnd, &wp);
sys->desktop_save.win = wp.rcNormalPosition;
}
/* create scene */
i_ret = Direct3DCreateScene(p_vout);
if (i_ret) {
msg_Err(p_vout, "Direct3D scene initialization failed !");
Direct3DReleasePictures(p_vout);
return i_ret;
/* */
Direct3DClose(vd);
EventThreadStop(sys->event);
/* */
vlc_mutex_lock(&sys->lock);
sys->use_desktop = sys->desktop_requested;
sys->ch_desktop = false;
vlc_mutex_unlock(&sys->lock);
/* */
event_cfg_t cfg;
memset(&cfg, 0, sizeof(cfg));
cfg.use_desktop = sys->use_desktop;
if (!sys->use_desktop) {
cfg.win.type = VOUT_WINDOW_TYPE_HWND;
cfg.win.x = sys->desktop_save.win.left;
cfg.win.y = sys->desktop_save.win.top;
cfg.win.width = sys->desktop_save.win.right - sys->desktop_save.win.left;
cfg.win.height = sys->desktop_save.win.bottom - sys->desktop_save.win.top;
}
/* Change the window title bar text */
EventThreadUpdateTitle(p_sys->p_event, VOUT_TITLE " (Direct3D output)");
event_hwnd_t hwnd;
if (EventThreadStart(sys->event, &hwnd, &cfg)) {
msg_Err(vd, "Failed to restart event thread");
return VLC_EGENERIC;
}
sys->parent_window = hwnd.parent_window;
sys->hparent = hwnd.hparent;
sys->hwnd = hwnd.hwnd;
sys->hvideownd = hwnd.hvideownd;
sys->hfswnd = hwnd.hfswnd;
SetRectEmpty(&sys->rect_parent);
p_vout->fmt_out.i_chroma = p_vout->output.i_chroma;
/* */
video_format_t fmt;
if (Direct3DOpen(vd, &fmt)) {
CommonClean(vd);
msg_Err(vd, "Failed to reopen device");
return VLC_EGENERIC;
}
vd->fmt = fmt;
sys->is_first_display = true;
if (sys->use_desktop) {
/* Disable fullscreen/on_top while using desktop */
if (sys->desktop_save.is_fullscreen)
vout_display_SendEventFullscreen(vd, false);
if (sys->desktop_save.is_on_top)
vout_display_SendEventOnTop(vd, false);
} else {
/* Restore fullscreen/on_top */
if (sys->desktop_save.is_fullscreen)
vout_display_SendEventFullscreen(vd, true);
if (sys->desktop_save.is_on_top)
vout_display_SendEventOnTop(vd, true);
}
return VLC_SUCCESS;
}
/*****************************************************************************
* End: terminate Sys video thread output method
*****************************************************************************
* Terminate an output method created by Create.
* It is called at the end of the thread.
*****************************************************************************/
static void End(vout_thread_t *p_vout)
static int Control(vout_display_t *vd, int query, va_list args)
{
Direct3DReleaseScene(p_vout);
Direct3DReleasePictures(p_vout);
Direct3DClose(p_vout);
vout_display_sys_t *sys = vd->sys;
switch (query) {
case VOUT_DISPLAY_RESET_PICTURES:
/* FIXME what to do here in case of failure */
if (sys->reset_device) {
if (ControlResetDevice(vd)) {
msg_Err(vd, "Failed to reset device");
return VLC_EGENERIC;
}
sys->reset_device = false;
} else if(sys->reopen_device) {
if (ControlReopenDevice(vd)) {
msg_Err(vd, "Failed to reopen device");
return VLC_EGENERIC;
}
sys->reopen_device = false;
}
return VLC_SUCCESS;
default:
return CommonControl(vd, query, args);
}
}
/*****************************************************************************
* Manage: handle Sys events
*****************************************************************************
* This function should be called regularly by the video output thread.
* It returns a non null value if an error occurred.
*****************************************************************************/
static int Manage(vout_thread_t *p_vout)
static void Manage (vout_display_t *vd)
{
vout_sys_t *p_sys = p_vout->p_sys;
vout_display_sys_t *sys = vd->sys;
CommonManage(p_vout);
CommonManage(vd);
/* Desktop mode change */
vlc_mutex_lock(&sys->lock);
const bool ch_desktop = sys->ch_desktop;
sys->ch_desktop = false;
vlc_mutex_unlock(&sys->lock);
if (ch_desktop) {
sys->reopen_device = true;
vout_display_SendEventPicturesInvalid(vd);
}
#if 0
/*
* Position Change
*/
if (p_sys->i_changes & DX_POSITION_CHANGE) {
if (sys->changes & DX_POSITION_CHANGE) {
#if 0 /* need that when bicubic filter is available */
RECT rect;
UINT width, height;
......@@ -300,139 +433,54 @@ static int Manage(vout_thread_t *p_vout)
if (width != p_sys->d3dpp.BackBufferWidth || height != p_sys->d3dpp.BackBufferHeight)
{
msg_Dbg(p_vout, "resizing device back buffers to (%lux%lu)", width, height);
msg_Dbg(vd, "resizing device back buffers to (%lux%lu)", width, height);
// need to reset D3D device to resize back buffer
if (VLC_SUCCESS != Direct3DResetDevice(p_vout, width, height))
if (VLC_SUCCESS != Direct3DResetDevice(vd, width, height))
return VLC_EGENERIC;
}
#endif
p_sys->i_changes &= ~DX_POSITION_CHANGE;
sys->changes &= ~DX_POSITION_CHANGE;
}
/*
* Desktop mode change
*/
if (p_sys->i_changes & DX_DESKTOP_CHANGE) {
/* Close the direct3d instance attached to the current output window. */
End(p_vout);
ExitFullscreen(p_vout);
EventThreadStop(p_sys->p_event);
/* Open the direct3d output and attaches it to the new window */
p_sys->b_desktop = !p_sys->b_desktop;
p_vout->pf_display = FirstDisplay;
event_cfg_t cfg;
memset(&cfg, 0, sizeof(cfg));
cfg.use_desktop = p_sys->b_desktop;
event_hwnd_t hwnd;
EventThreadStart(p_sys->p_event, &hwnd, &cfg);
p_sys->parent_window = hwnd.parent_window;
p_sys->hparent = hwnd.hparent;
p_sys->hwnd = hwnd.hwnd;
p_sys->hvideownd = hwnd.hvideownd;
p_sys->hfswnd = hwnd.hfswnd;
Init(p_vout);
/* Reset the flag */
p_sys->i_changes &= ~DX_DESKTOP_CHANGE;
}
return VLC_SUCCESS;
}
/*****************************************************************************
* Display: displays previously rendered output
*****************************************************************************
* This function sends the currently rendered image to the display, wait until
* it is displayed and switch the two rendering buffers, preparing next frame.
*****************************************************************************/
static void Display(vout_thread_t *p_vout, picture_t *p_pic)
{
vout_sys_t *p_sys = p_vout->p_sys;
LPDIRECT3DDEVICE9 p_d3ddev = p_sys->p_d3ddev;
VLC_UNUSED(p_pic);
// Present the back buffer contents to the display
// No stretching should happen here !
RECT src = p_sys->rect_dest_clipped;
RECT dst = p_sys->rect_dest_clipped;
HRESULT hr = IDirect3DDevice9_Present(p_d3ddev, &src, &dst,
NULL, NULL);
if (FAILED(hr))
msg_Dbg(p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
#endif
}
/*
** this function is only used once when the first picture is received
** this function will show the video window once a picture is ready
*/
static void FirstDisplay(vout_thread_t *p_vout, picture_t *p_pic)
{
/* get initial picture presented through D3D */
Display(p_vout, p_pic);
/*
** Video window is initially hidden, show it now since we got a
** picture to show.
/**
* It initializes an instance of Direct3D9
*/
SetWindowPos(p_vout->p_sys->hvideownd, 0, 0, 0, 0, 0,
SWP_ASYNCWINDOWPOS|
SWP_FRAMECHANGED|
SWP_SHOWWINDOW|
SWP_NOMOVE|
SWP_NOSIZE|
SWP_NOZORDER);
/* use and restores proper display function for further pictures */
p_vout->pf_display = Display;
}
/*****************************************************************************
* DirectD3DVoutCreate: Initialize and instance of Direct3D9
*****************************************************************************
* This function initialize Direct3D and analyze available resources from
* default adapter.
*****************************************************************************/
static int Direct3DCreate(vout_thread_t *p_vout)
static int Direct3DCreate(vout_display_t *vd)
{
vout_sys_t *p_sys = p_vout->p_sys;
vout_display_sys_t *sys = vd->sys;
p_sys->hd3d9_dll = LoadLibrary(TEXT("D3D9.DLL"));
if (!p_sys->hd3d9_dll) {
msg_Warn(p_vout, "cannot load d3d9.dll, aborting");
sys->hd3d9_dll = LoadLibrary(TEXT("D3D9.DLL"));
if (!sys->hd3d9_dll) {
msg_Warn(vd, "cannot load d3d9.dll, aborting");
return VLC_EGENERIC;
}
LPDIRECT3D9 (WINAPI *OurDirect3DCreate9)(UINT SDKVersion);
OurDirect3DCreate9 =
(void *)GetProcAddress(p_sys->hd3d9_dll, TEXT("Direct3DCreate9"));
(void *)GetProcAddress(sys->hd3d9_dll, TEXT("Direct3DCreate9"));
if (!OurDirect3DCreate9) {
msg_Err(p_vout, "Cannot locate reference to Direct3DCreate9 ABI in DLL");
msg_Err(vd, "Cannot locate reference to Direct3DCreate9 ABI in DLL");
return VLC_EGENERIC;
}
/* Create the D3D object. */
LPDIRECT3D9 p_d3dobj = OurDirect3DCreate9(D3D_SDK_VERSION);
if (!p_d3dobj) {
msg_Err(p_vout, "Could not create Direct3D9 instance.");
LPDIRECT3D9 d3dobj = OurDirect3DCreate9(D3D_SDK_VERSION);
if (!d3dobj) {
msg_Err(vd, "Could not create Direct3D9 instance.");
return VLC_EGENERIC;
}
p_sys->p_d3dobj = p_d3dobj;
sys->d3dobj = d3dobj;
/*
** Get device capabilities
*/
D3DCAPS9 d3dCaps;
ZeroMemory(&d3dCaps, sizeof(d3dCaps));
HRESULT hr = IDirect3D9_GetDeviceCaps(p_d3dobj, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &d3dCaps);
HRESULT hr = IDirect3D9_GetDeviceCaps(d3dobj, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &d3dCaps);
if (FAILED(hr)) {
msg_Err(p_vout, "Could not read adapter capabilities. (hr=0x%lX)", hr);
msg_Err(vd, "Could not read adapter capabilities. (hr=0x%lX)", hr);
return VLC_EGENERIC;
}
/* TODO: need to test device capabilities and select the right render function */
......@@ -440,45 +488,49 @@ static int Direct3DCreate(vout_thread_t *p_vout)
return VLC_SUCCESS;
}
/*****************************************************************************
* DirectD3DVoutRelease: release an instance of Direct3D9
*****************************************************************************/
static void Direct3DRelease(vout_thread_t *p_vout)
/**
* It releases an instance of Direct3D9
*/
static void Direct3DDestroy(vout_display_t *vd)
{
vout_sys_t *p_sys = p_vout->p_sys;
vout_display_sys_t *sys = vd->sys;
if (p_sys->p_d3dobj)
IDirect3D9_Release(p_sys->p_d3dobj);
if (p_sys->hd3d9_dll)
FreeLibrary(p_sys->hd3d9_dll);
if (sys->d3dobj)
IDirect3D9_Release(sys->d3dobj);
if (sys->hd3d9_dll)
FreeLibrary(sys->hd3d9_dll);
p_sys->p_d3dobj = NULL;
p_sys->hd3d9_dll = NULL;
sys->d3dobj = NULL;
sys->hd3d9_dll = NULL;
}
static int Direct3DFillPresentationParameters(vout_thread_t *p_vout)
/**
* It setup vout_display_sys_t::d3dpp and vout_display_sys_t::rect_display
* from the default adapter.
*/
static int Direct3DFillPresentationParameters(vout_display_t *vd)
{
vout_sys_t *p_sys = p_vout->p_sys;
LPDIRECT3D9 p_d3dobj = p_sys->p_d3dobj;
D3DDISPLAYMODE d3ddm;
HRESULT hr;
vout_display_sys_t *sys = vd->sys;
/*
** Get the current desktop display mode, so we can set up a back
** buffer of the same format
*/
hr = IDirect3D9_GetAdapterDisplayMode(p_d3dobj, D3DADAPTER_DEFAULT, &d3ddm);
D3DDISPLAYMODE d3ddm;
HRESULT hr = IDirect3D9_GetAdapterDisplayMode(sys->d3dobj,
D3DADAPTER_DEFAULT, &d3ddm);
if (FAILED(hr)) {
msg_Err(p_vout, "Could not read adapter display mode. (hr=0x%lX)", hr);
msg_Err(vd, "Could not read adapter display mode. (hr=0x%lX)", hr);
return VLC_EGENERIC;
}
/* Set up the structure used to create the D3DDevice. */
D3DPRESENT_PARAMETERS *d3dpp = &p_vout->p_sys->d3dpp;
D3DPRESENT_PARAMETERS *d3dpp = &vd->sys->d3dpp;
ZeroMemory(d3dpp, sizeof(D3DPRESENT_PARAMETERS));
d3dpp->Flags = D3DPRESENTFLAG_VIDEO;
d3dpp->Windowed = TRUE;
d3dpp->hDeviceWindow = p_vout->p_sys->hvideownd;
d3dpp->hDeviceWindow = vd->sys->hvideownd;
d3dpp->BackBufferWidth = d3ddm.Width;
d3dpp->BackBufferHeight = d3ddm.Height;
d3dpp->SwapEffect = D3DSWAPEFFECT_COPY;
......@@ -488,17 +540,17 @@ static int Direct3DFillPresentationParameters(vout_thread_t *p_vout)
d3dpp->BackBufferCount = 1;
d3dpp->EnableAutoDepthStencil = FALSE;
const unsigned i_adapter_count = IDirect3D9_GetAdapterCount(p_d3dobj);
for( unsigned i = 1; i < i_adapter_count; i++ )
{
hr = IDirect3D9_GetAdapterDisplayMode(p_d3dobj, i, &d3ddm );
if( FAILED(hr) )
const unsigned adapter_count = IDirect3D9_GetAdapterCount(sys->d3dobj);
for (unsigned i = 1; i < adapter_count; i++) {
hr = IDirect3D9_GetAdapterDisplayMode(sys->d3dobj, i, &d3ddm);
if (FAILED(hr))
continue;
d3dpp->BackBufferWidth = __MAX(d3dpp->BackBufferWidth, d3ddm.Width);
d3dpp->BackBufferHeight = __MAX(d3dpp->BackBufferHeight, d3ddm.Height);
}
RECT *display = &p_vout->p_sys->rect_display;
/* */
RECT *display = &vd->sys->rect_display;
display->left = 0;
display->top = 0;
display->right = d3dpp->BackBufferWidth;
......@@ -507,108 +559,152 @@ static int Direct3DFillPresentationParameters(vout_thread_t *p_vout)
return VLC_SUCCESS;
}
/*****************************************************************************
* DirectD3DVoutOpen: Takes care of all the Direct3D9 initialisations
*****************************************************************************
* This function creates Direct3D device
* this must be called from the vout thread for performance reason, as
* all Direct3D Device APIs are used in a non multithread safe environment
*****************************************************************************/
static int Direct3DOpen(vout_thread_t *p_vout)
/* */
static int Direct3DCreateResources (vout_display_t *, video_format_t *);
static void Direct3DDestroyResources(vout_display_t *);
/**
* It creates a Direct3D device and the associated resources.
*/
static int Direct3DOpen(vout_display_t *vd, video_format_t *fmt)
{
vout_sys_t *p_sys = p_vout->p_sys;
LPDIRECT3D9 p_d3dobj = p_sys->p_d3dobj;
LPDIRECT3DDEVICE9 p_d3ddev;
HRESULT hr;
vout_display_sys_t *sys = vd->sys;
LPDIRECT3D9 d3dobj = sys->d3dobj;
if (Direct3DFillPresentationParameters(p_vout))
if (Direct3DFillPresentationParameters(vd))
return VLC_EGENERIC;
// Create the D3DDevice
hr = IDirect3D9_CreateDevice(p_d3dobj, D3DADAPTER_DEFAULT,
D3DDEVTYPE_HAL, p_sys->hvideownd,
LPDIRECT3DDEVICE9 d3ddev;
HRESULT hr = IDirect3D9_CreateDevice(d3dobj, D3DADAPTER_DEFAULT,
D3DDEVTYPE_HAL, sys->hvideownd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING|
D3DCREATE_MULTITHREADED,
&p_sys->d3dpp, &p_d3ddev);
&sys->d3dpp, &d3ddev);
if (FAILED(hr)) {
msg_Err(p_vout, "Could not create the D3D device! (hr=0x%lX)", hr);
msg_Err(vd, "Could not create the D3D device! (hr=0x%lX)", hr);
return VLC_EGENERIC;
}
p_sys->p_d3ddev = p_d3ddev;
sys->d3ddev = d3ddev;
UpdateRects(vd, NULL, NULL, true);
msg_Dbg(p_vout, "Direct3D device adapter successfully initialized");
if (Direct3DCreateResources(vd, fmt)) {
msg_Err(vd, "Failed to allocate resources");
return VLC_EGENERIC;
}
/* Change the window title bar text */
EventThreadUpdateTitle(sys->event, VOUT_TITLE " (Direct3D output)");
msg_Dbg(vd, "Direct3D device adapter successfully initialized");
return VLC_SUCCESS;
}
/*****************************************************************************
* DirectD3DClose: release the Direct3D9 device
*****************************************************************************/
static void Direct3DClose(vout_thread_t *p_vout)
/**
* It releases the Direct3D9 device and its resources.
*/
static void Direct3DClose(vout_display_t *vd)
{
vout_sys_t *p_sys = p_vout->p_sys;
vout_display_sys_t *sys = vd->sys;
Direct3DDestroyResources(vd);
if (p_sys->p_d3ddev)
IDirect3DDevice9_Release(p_sys->p_d3ddev);
if (sys->d3ddev)
IDirect3DDevice9_Release(sys->d3ddev);
p_sys->p_d3ddev = NULL;
p_sys->hmonitor = NULL;
sys->d3ddev = NULL;
sys->hmonitor = NULL;
}
/*****************************************************************************
* DirectD3DClose: reset the Direct3D9 device
*****************************************************************************
* All resources must be deallocated before the reset occur, they will be
* realllocated once the reset has been performed successfully
*****************************************************************************/
static int Direct3DResetDevice(vout_thread_t *p_vout)
/**
* It reset the Direct3D9 device and its resources.
*/
static int Direct3DReset(vout_display_t *vd)
{
vout_sys_t *p_sys = p_vout->p_sys;
LPDIRECT3DDEVICE9 p_d3ddev = p_sys->p_d3ddev;
HRESULT hr;
vout_display_sys_t *sys = vd->sys;
LPDIRECT3DDEVICE9 d3ddev = sys->d3ddev;
if (Direct3DFillPresentationParameters(p_vout))
if (Direct3DFillPresentationParameters(vd))
return VLC_EGENERIC;
// release all D3D objects
Direct3DReleaseScene(p_vout);
Direct3DReleasePictures(p_vout);
/* release all D3D objects */
Direct3DDestroyResources(vd);
hr = IDirect3DDevice9_Reset(p_d3ddev, &p_sys->d3dpp);
/* */
HRESULT hr = IDirect3DDevice9_Reset(d3ddev, &sys->d3dpp);
if (FAILED(hr)) {
msg_Err(p_vout, "%s failed ! (hr=%08lX)", __FUNCTION__, hr);
msg_Err(vd, "%s failed ! (hr=%08lX)", __FUNCTION__, hr);
return VLC_EGENERIC;
}
// re-create them
if (Direct3DCreatePictures(p_vout, 1) || Direct3DCreateScene(p_vout)) {
msg_Dbg(p_vout, "%s failed !", __FUNCTION__);
UpdateRects(vd, NULL, NULL, true);
/* re-create them */
if (Direct3DCreateResources(vd, &vd->fmt)) {
msg_Dbg(vd, "%s failed !", __FUNCTION__);
return VLC_EGENERIC;
}
return VLC_SUCCESS;
}
static int Direct3DCheckFormat(vout_thread_t *p_vout,
D3DFORMAT target, D3DFORMAT format)
/* */
static int Direct3DCreatePool(vout_display_t *vd, video_format_t *fmt);
static void Direct3DDestroyPool(vout_display_t *vd);
static int Direct3DCreateScene(vout_display_t *vd);
static void Direct3DDestroyScene(vout_display_t *vd);
/**
* It creates the picture and scene resources.
*/
static int Direct3DCreateResources(vout_display_t *vd, video_format_t *fmt)
{
vout_sys_t *p_sys = p_vout->p_sys;
LPDIRECT3D9 p_d3dobj = p_sys->p_d3dobj;
if (Direct3DCreatePool(vd, fmt)) {
msg_Err(vd, "Direct3D picture pool initialization failed");
return VLC_EGENERIC;
}
if (Direct3DCreateScene(vd)) {
msg_Err(vd, "Direct3D scene initialization failed !");
return VLC_EGENERIC;
}
return VLC_SUCCESS;
}
/**
* It destroys the picture and scene resources.
*/
static void Direct3DDestroyResources(vout_display_t *vd)
{
Direct3DDestroyScene(vd);
Direct3DDestroyPool(vd);
}
/**
* It tests if the conversion from src to dst is supported.
*/
static int Direct3DCheckConversion(vout_display_t *vd,
D3DFORMAT src, D3DFORMAT dst)
{
vout_display_sys_t *sys = vd->sys;
LPDIRECT3D9 d3dobj = sys->d3dobj;
HRESULT hr;
/* test whether device can create a surface of that format */
hr = IDirect3D9_CheckDeviceFormat(p_d3dobj, D3DADAPTER_DEFAULT,
D3DDEVTYPE_HAL, target, 0,
D3DRTYPE_SURFACE, format);
hr = IDirect3D9_CheckDeviceFormat(d3dobj, D3DADAPTER_DEFAULT,
D3DDEVTYPE_HAL, dst, 0,
D3DRTYPE_SURFACE, src);
if (SUCCEEDED(hr)) {
/* test whether device can perform color-conversion
** from that format to target format
*/
hr = IDirect3D9_CheckDeviceFormatConversion(p_d3dobj,
hr = IDirect3D9_CheckDeviceFormatConversion(d3dobj,
D3DADAPTER_DEFAULT,
D3DDEVTYPE_HAL,
format, target);
src, dst);
}
if (!SUCCEEDED(hr)) {
if (D3DERR_NOTAVAILABLE != hr)
msg_Err(p_vout, "Could not query adapter supported formats. (hr=0x%lX)", hr);
msg_Err(vd, "Could not query adapter supported formats. (hr=0x%lX)", hr);
return VLC_EGENERIC;
}
return VLC_SUCCESS;
......@@ -617,14 +713,14 @@ static int Direct3DCheckFormat(vout_thread_t *p_vout,
typedef struct
{
const char *name;
D3DFORMAT format;
vlc_fourcc_t fourcc;
D3DFORMAT format; /* D3D format */
vlc_fourcc_t fourcc; /* VLC fourcc */
uint32_t rmask;
uint32_t gmask;
uint32_t bmask;
} d3d_format_t;
static const d3d_format_t p_d3d_formats[] = {
static const d3d_format_t d3d_formats[] = {
/* YV12 is always used for planar 420, the planes are then swapped in Lock() */
{ "YV12", MAKEFOURCC('Y','V','1','2'), VLC_CODEC_YV12, 0,0,0 },
{ "YV12", MAKEFOURCC('Y','V','1','2'), VLC_CODEC_I420, 0,0,0 },
......@@ -640,33 +736,35 @@ static const d3d_format_t p_d3d_formats[] = {
{ NULL, 0, 0, 0,0,0}
};
static const d3d_format_t *Direct3DFindFormat(vout_thread_t *p_vout, vlc_fourcc_t i_chroma, D3DFORMAT target)
/**
* It returns the format (closest to chroma) that can be converted to target */
static const d3d_format_t *Direct3DFindFormat(vout_display_t *vd, vlc_fourcc_t chroma, D3DFORMAT target)
{
vout_sys_t *p_sys = p_vout->p_sys;
vout_display_sys_t *sys = vd->sys;
for (unsigned pass = 0; pass < 2; pass++) {
const vlc_fourcc_t *p_chromas;
const vlc_fourcc_t *list;
if (pass == 0 && p_sys->b_hw_yuv && vlc_fourcc_IsYUV(i_chroma))
p_chromas = vlc_fourcc_GetYUVFallback(i_chroma);
if (pass == 0 && sys->allow_hw_yuv && vlc_fourcc_IsYUV(chroma))
list = vlc_fourcc_GetYUVFallback(chroma);
else if (pass == 1)
p_chromas = vlc_fourcc_GetRGBFallback(i_chroma);
list = vlc_fourcc_GetRGBFallback(chroma);
else
continue;
for (unsigned i = 0; p_chromas[i] != 0; i++) {
for (unsigned j = 0; p_d3d_formats[j].name; j++) {
const d3d_format_t *p_format = &p_d3d_formats[j];
for (unsigned i = 0; list[i] != 0; i++) {
for (unsigned j = 0; d3d_formats[j].name; j++) {
const d3d_format_t *format = &d3d_formats[j];
if (p_format->fourcc != p_chromas[i])
if (format->fourcc != list[i])
continue;
msg_Warn(p_vout, "trying surface pixel format: %s",
p_format->name);
if (!Direct3DCheckFormat(p_vout, target, p_format->format)) {
msg_Dbg(p_vout, "selected surface pixel format is %s",
p_format->name);
return p_format;
msg_Warn(vd, "trying surface pixel format: %s",
format->name);
if (!Direct3DCheckConversion(vd, format->format, target)) {
msg_Dbg(vd, "selected surface pixel format is %s",
format->name);
return format;
}
}
}
......@@ -674,474 +772,402 @@ static const d3d_format_t *Direct3DFindFormat(vout_thread_t *p_vout, vlc_fourcc_
return NULL;
}
/*****************************************************************************
* Direct3DCreatePictures: allocate a vector of identical pictures
*****************************************************************************
* Each picture has an associated offscreen surface in video memory
* depending on hardware capabilities the picture chroma will be as close
* as possible to the orginal render chroma to reduce CPU conversion overhead
* and delegate this work to video card GPU
*****************************************************************************/
static int Direct3DCreatePictures(vout_thread_t *p_vout, size_t i_num_pics)
{
vout_sys_t *p_sys = p_vout->p_sys;
LPDIRECT3DDEVICE9 p_d3ddev = p_sys->p_d3ddev;
HRESULT hr;
size_t c;
// if vout is already running, use current chroma, otherwise choose from upstream
vlc_fourcc_t i_chroma = p_vout->output.i_chroma ? p_vout->output.i_chroma
: p_vout->render.i_chroma;
I_OUTPUTPICTURES = 0;
/*
** find the appropriate D3DFORMAT for the render chroma, the format will be the closest to
** the requested chroma which is usable by the hardware in an offscreen surface, as they
** typically support more formats than textures
/**
* It locks the surface associated to the picture and get the surface
* descriptor which amongst other things has the pointer to the picture
* data and its pitch.
*/
const d3d_format_t *p_format = Direct3DFindFormat(p_vout, i_chroma, p_sys->d3dpp.BackBufferFormat);
if (!p_format) {
msg_Err(p_vout, "surface pixel format is not supported.");
return VLC_EGENERIC;
}
p_vout->output.i_chroma = p_format->fourcc;
p_vout->output.i_rmask = p_format->rmask;
p_vout->output.i_gmask = p_format->gmask;
p_vout->output.i_bmask = p_format->bmask;
/* */
for (c = 0; c < i_num_pics;) {
LPDIRECT3DSURFACE9 p_d3dsurf;
picture_t *p_pic = p_vout->p_picture+c;
hr = IDirect3DDevice9_CreateOffscreenPlainSurface(p_d3ddev,
p_vout->render.i_width,
p_vout->render.i_height,
p_format->format,
D3DPOOL_DEFAULT,
&p_d3dsurf,
NULL);
static int Direct3DLockSurface(picture_t *picture)
{
/* Lock the surface to get a valid pointer to the picture buffer */
D3DLOCKED_RECT d3drect;
HRESULT hr = IDirect3DSurface9_LockRect(picture->p_sys->surface, &d3drect, NULL, 0);
if (FAILED(hr)) {
msg_Err(p_vout, "Failed to create picture surface. (hr=0x%lx)", hr);
Direct3DReleasePictures(p_vout);
//msg_Dbg(vd, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
return VLC_EGENERIC;
}
/* fill surface with black color */
IDirect3DDevice9_ColorFill(p_d3ddev, p_d3dsurf, NULL, D3DCOLOR_ARGB(0xFF, 0, 0, 0));
/* fill in buffer info in first plane */
picture->p->p_pixels = d3drect.pBits;
picture->p->i_pitch = d3drect.Pitch;
/* */
video_format_Setup(&p_pic->format, p_vout->output.i_chroma, p_vout->output.i_width, p_vout->output.i_height, p_vout->output.i_aspect);
/* assign surface to internal structure */
p_pic->p_sys = (void *)p_d3dsurf;
/* Now that we've got our direct-buffer, we can finish filling in the
* picture_t structures */
switch (p_vout->output.i_chroma) {
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_visible_pitch = p_vout->output.i_width *
p_pic->p->i_pixel_pitch;
p_pic->i_planes = 1;
break;
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_visible_pitch = p_vout->output.i_width *
p_pic->p->i_pixel_pitch;
p_pic->i_planes = 1;
break;
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_visible_pitch = p_vout->output.i_width *
p_pic->p->i_pixel_pitch;
p_pic->i_planes = 1;
break;
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_visible_pitch = p_vout->output.i_width *
p_pic->p->i_pixel_pitch;
p_pic->i_planes = 1;
break;
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;
p_pic->p->i_visible_pitch = p_vout->output.i_width *
p_pic->p->i_pixel_pitch;
p_pic->i_planes = 1;
break;
case VLC_CODEC_I420:
case VLC_CODEC_J420:
case VLC_CODEC_YV12:
p_pic->i_planes = 3;
for (int n = 0; n < p_pic->i_planes; n++)
{
const unsigned d = 1 + (n > 0);
plane_t *p = &p_pic->p[n];
/* Fill chroma planes for planar YUV */
if (picture->format.i_chroma == VLC_CODEC_I420 ||
picture->format.i_chroma == VLC_CODEC_J420 ||
picture->format.i_chroma == VLC_CODEC_YV12) {
p->i_pixel_pitch = 1;
p->i_lines =
p->i_visible_lines = p_vout->output.i_height / d;
p->i_visible_pitch = p_vout->output.i_width / d;
for (int n = 1; n < picture->i_planes; n++) {
const plane_t *o = &picture->p[n-1];
plane_t *p = &picture->p[n];
p->p_pixels = o->p_pixels + o->i_lines * o->i_pitch;
p->i_pitch = d3drect.Pitch / 2;
}
break;
default:
Direct3DReleasePictures(p_vout);
return VLC_EGENERIC;
/* The d3d buffer is always allocated as YV12 */
if (vlc_fourcc_AreUVPlanesSwapped(picture->format.i_chroma, VLC_CODEC_YV12)) {
uint8_t *p_tmp = picture->p[1].p_pixels;
picture->p[1].p_pixels = picture->p[2].p_pixels;
picture->p[2].p_pixels = p_tmp;
}
p_pic->i_status = DESTROYED_PICTURE;
p_pic->i_type = DIRECT_PICTURE;
p_pic->b_slow = true;
p_pic->pf_lock = Direct3DLockSurface;
p_pic->pf_unlock = Direct3DUnlockSurface;
PP_OUTPUTPICTURE[c] = p_pic;
I_OUTPUTPICTURES = ++c;
}
msg_Dbg(p_vout, "%u Direct3D pictures created successfully", c);
return VLC_SUCCESS;
}
/*****************************************************************************
* Direct3DReleasePictures: destroy a picture vector
*****************************************************************************
* release all video resources used for pictures
*****************************************************************************/
static void Direct3DReleasePictures(vout_thread_t *p_vout)
/**
* It unlocks the surface associated to the picture.
*/
static void Direct3DUnlockSurface(picture_t *picture)
{
size_t i_num_pics = I_OUTPUTPICTURES;
size_t c;
for (c = 0; c < i_num_pics; c++) {
picture_t *p_pic = &p_vout->p_picture[c];
if (!p_pic->p_sys)
continue;
LPDIRECT3DSURFACE9 p_d3dsurf = (LPDIRECT3DSURFACE9)p_pic->p_sys;
if (p_d3dsurf)
IDirect3DSurface9_Release(p_d3dsurf);
p_pic->p_sys = NULL;
/* Unlock the Surface */
HRESULT hr = IDirect3DSurface9_UnlockRect(picture->p_sys->surface);
if (FAILED(hr)) {
//msg_Dbg(vd, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
}
msg_Dbg(p_vout, "%u Direct3D pictures released.", c);
I_OUTPUTPICTURES = 0;
}
/*****************************************************************************
* Direct3DLockSurface: Lock surface and get picture data pointer
*****************************************************************************
* This function locks a surface and get the surface descriptor which amongst
* other things has the pointer to the picture data.
*****************************************************************************/
static int Direct3DLockSurface(vout_thread_t *p_vout, picture_t *p_pic)
/**
* It creates the pool of picture (only 1).
*
* Each picture has an associated offscreen surface in video memory
* depending on hardware capabilities the picture chroma will be as close
* as possible to the orginal render chroma to reduce CPU conversion overhead
* and delegate this work to video card GPU
*/
static int Direct3DCreatePool(vout_display_t *vd, video_format_t *fmt)
{
LPDIRECT3DSURFACE9 p_d3dsurf = (LPDIRECT3DSURFACE9)p_pic->p_sys;
vout_display_sys_t *sys = vd->sys;
LPDIRECT3DDEVICE9 d3ddev = sys->d3ddev;
if (!p_d3dsurf)
/* */
*fmt = vd->source;
/* Find the appropriate D3DFORMAT for the render chroma, the format will be the closest to
* the requested chroma which is usable by the hardware in an offscreen surface, as they
* typically support more formats than textures */
const d3d_format_t *d3dfmt = Direct3DFindFormat(vd, fmt->i_chroma, sys->d3dpp.BackBufferFormat);
if (!d3dfmt) {
msg_Err(vd, "surface pixel format is not supported.");
return VLC_EGENERIC;
/* Lock the surface to get a valid pointer to the picture buffer */
D3DLOCKED_RECT d3drect;
HRESULT hr = IDirect3DSurface9_LockRect(p_d3dsurf, &d3drect, NULL, 0);
}
fmt->i_chroma = d3dfmt->fourcc;
fmt->i_rmask = d3dfmt->rmask;
fmt->i_gmask = d3dfmt->gmask;
fmt->i_bmask = d3dfmt->bmask;
/* We create one picture.
* It is useless to create more as we can't be used for direct rendering */
/* Create a surface */
LPDIRECT3DSURFACE9 surface;
HRESULT hr = IDirect3DDevice9_CreateOffscreenPlainSurface(d3ddev,
fmt->i_width,
fmt->i_height,
d3dfmt->format,
D3DPOOL_DEFAULT,
&surface,
NULL);
if (FAILED(hr)) {
msg_Dbg(p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
msg_Err(vd, "Failed to create picture surface. (hr=0x%lx)", hr);
return VLC_EGENERIC;
}
/* fill surface with black color */
IDirect3DDevice9_ColorFill(d3ddev, surface, NULL, D3DCOLOR_ARGB(0xFF, 0, 0, 0));
/* fill in buffer info in first plane */
p_pic->p->p_pixels = d3drect.pBits;
p_pic->p->i_pitch = d3drect.Pitch;
/* Fill chroma planes for planar YUV */
if (p_pic->format.i_chroma == VLC_CODEC_I420 ||
p_pic->format.i_chroma == VLC_CODEC_J420 ||
p_pic->format.i_chroma == VLC_CODEC_YV12) {
for (int n = 1; n < p_pic->i_planes; n++) {
const plane_t *o = &p_pic->p[n-1];
plane_t *p = &p_pic->p[n];
p->p_pixels = o->p_pixels + o->i_lines * o->i_pitch;
p->i_pitch = d3drect.Pitch / 2;
/* Create the associated picture */
picture_resource_t *rsc = &sys->resource;
rsc->p_sys = malloc(sizeof(*rsc->p_sys));
if (!rsc->p_sys) {
IDirect3DSurface9_Release(surface);
return VLC_ENOMEM;
}
/* The d3d buffer is always allocated as YV12 */
if (vlc_fourcc_AreUVPlanesSwapped(p_pic->format.i_chroma, VLC_CODEC_YV12)) {
uint8_t *p_tmp = p_pic->p[1].p_pixels;
p_pic->p[1].p_pixels = p_pic->p[2].p_pixels;
p_pic->p[2].p_pixels = p_tmp;
rsc->p_sys->surface = surface;
for (int i = 0; i < PICTURE_PLANE_MAX; i++) {
rsc->p[i].p_pixels = NULL;
rsc->p[i].i_pitch = 0;
rsc->p[i].i_lines = fmt->i_height / (i > 0 ? 2 : 1);
}
picture_t *picture = picture_NewFromResource(fmt, rsc);
if (!picture) {
IDirect3DSurface9_Release(surface);
free(rsc->p_sys);
return VLC_ENOMEM;
}
/* Wrap it into a picture pool */
picture_pool_configuration_t pool_cfg;
memset(&pool_cfg, 0, sizeof(pool_cfg));
pool_cfg.picture_count = 1;
pool_cfg.picture = &picture;
pool_cfg.lock = Direct3DLockSurface;
pool_cfg.unlock = Direct3DUnlockSurface;
sys->pool = picture_pool_NewExtended(&pool_cfg);
if (!sys->pool) {
picture_Release(picture);
IDirect3DSurface9_Release(surface);
return VLC_ENOMEM;
}
return VLC_SUCCESS;
}
/*****************************************************************************
* Direct3DUnlockSurface: Unlock a surface locked by Direct3DLockSurface().
*****************************************************************************/
static int Direct3DUnlockSurface(vout_thread_t *p_vout, picture_t *p_pic)
/**
* It destroys the pool of picture and its resources.
*/
static void Direct3DDestroyPool(vout_display_t *vd)
{
LPDIRECT3DSURFACE9 p_d3dsurf = (LPDIRECT3DSURFACE9)p_pic->p_sys;
vout_display_sys_t *sys = vd->sys;
if (!p_d3dsurf)
return VLC_EGENERIC;
if (sys->pool) {
picture_resource_t *rsc = &sys->resource;
IDirect3DSurface9_Release(rsc->p_sys->surface);
/* Unlock the Surface */
HRESULT hr = IDirect3DSurface9_UnlockRect(p_d3dsurf);
if (FAILED(hr)) {
msg_Dbg(p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
return VLC_EGENERIC;
picture_pool_Delete(sys->pool);
}
return VLC_SUCCESS;
sys->pool = NULL;
}
/*****************************************************************************
* Direct3DCreateScene: allocate and initialize a 3D scene
*****************************************************************************
* for advanced blending/filtering a texture needs be used in a 3D scene.
*****************************************************************************/
static int Direct3DCreateScene(vout_thread_t *p_vout)
/* */
typedef struct
{
vout_sys_t *p_sys = p_vout->p_sys;
LPDIRECT3DDEVICE9 p_d3ddev = p_sys->p_d3ddev;
LPDIRECT3DTEXTURE9 p_d3dtex;
LPDIRECT3DVERTEXBUFFER9 p_d3dvtc;
FLOAT x,y,z; // vertex untransformed position
FLOAT rhw; // eye distance
D3DCOLOR diffuse; // diffuse color
FLOAT tu, tv; // texture relative coordinates
} CUSTOMVERTEX;
#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZRHW|D3DFVF_DIFFUSE|D3DFVF_TEX1)
/**
* It allocates and initializes the resources needed to render the scene.
*/
static int Direct3DCreateScene(vout_display_t *vd)
{
vout_display_sys_t *sys = vd->sys;
LPDIRECT3DDEVICE9 d3ddev = sys->d3ddev;
HRESULT hr;
/*
** Create a texture for use when rendering a scene
** for performance reason, texture format is identical to backbuffer
** which would usually be a RGB format
* Create a texture for use when rendering a scene
* for performance reason, texture format is identical to backbuffer
* which would usually be a RGB format
*/
hr = IDirect3DDevice9_CreateTexture(p_d3ddev,
p_sys->d3dpp.BackBufferWidth,
p_sys->d3dpp.BackBufferHeight,
LPDIRECT3DTEXTURE9 d3dtex;
hr = IDirect3DDevice9_CreateTexture(d3ddev,
sys->d3dpp.BackBufferWidth,
sys->d3dpp.BackBufferHeight,
1,
D3DUSAGE_RENDERTARGET,
p_sys->d3dpp.BackBufferFormat,
sys->d3dpp.BackBufferFormat,
D3DPOOL_DEFAULT,
&p_d3dtex,
&d3dtex,
NULL);
if (FAILED(hr)) {
msg_Err(p_vout, "Failed to create texture. (hr=0x%lx)", hr);
msg_Err(vd, "Failed to create texture. (hr=0x%lx)", hr);
return VLC_EGENERIC;
}
/*
** Create a vertex buffer for use when rendering scene
*/
hr = IDirect3DDevice9_CreateVertexBuffer(p_d3ddev,
LPDIRECT3DVERTEXBUFFER9 d3dvtc;
hr = IDirect3DDevice9_CreateVertexBuffer(d3ddev,
sizeof(CUSTOMVERTEX)*4,
D3DUSAGE_DYNAMIC|D3DUSAGE_WRITEONLY,
D3DFVF_CUSTOMVERTEX,
D3DPOOL_DEFAULT,
&p_d3dvtc,
&d3dvtc,
NULL);
if (FAILED(hr)) {
msg_Err(p_vout, "Failed to create vertex buffer. (hr=0x%lx)", hr);
IDirect3DTexture9_Release(p_d3dtex);
msg_Err(vd, "Failed to create vertex buffer. (hr=0x%lx)", hr);
IDirect3DTexture9_Release(d3dtex);
return VLC_EGENERIC;
}
p_sys->p_d3dtex = p_d3dtex;
p_sys->p_d3dvtc = p_d3dvtc;
/* */
sys->d3dtex = d3dtex;
sys->d3dvtc = d3dvtc;
// Texture coordinates outside the range [0.0, 1.0] are set
// to the texture color at 0.0 or 1.0, respectively.
IDirect3DDevice9_SetSamplerState(p_d3ddev, 0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
IDirect3DDevice9_SetSamplerState(p_d3ddev, 0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
IDirect3DDevice9_SetSamplerState(d3ddev, 0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
IDirect3DDevice9_SetSamplerState(d3ddev, 0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
// Set linear filtering quality
IDirect3DDevice9_SetSamplerState(p_d3ddev, 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
IDirect3DDevice9_SetSamplerState(p_d3ddev, 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
IDirect3DDevice9_SetSamplerState(d3ddev, 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
IDirect3DDevice9_SetSamplerState(d3ddev, 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
// set maximum ambient light
IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_AMBIENT, D3DCOLOR_XRGB(255,255,255));
IDirect3DDevice9_SetRenderState(d3ddev, D3DRS_AMBIENT, D3DCOLOR_XRGB(255,255,255));
// Turn off culling
IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_CULLMODE, D3DCULL_NONE);
IDirect3DDevice9_SetRenderState(d3ddev, D3DRS_CULLMODE, D3DCULL_NONE);
// Turn off the zbuffer
IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_ZENABLE, D3DZB_FALSE);
IDirect3DDevice9_SetRenderState(d3ddev, D3DRS_ZENABLE, D3DZB_FALSE);
// Turn off lights
IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_LIGHTING, FALSE);
IDirect3DDevice9_SetRenderState(d3ddev, D3DRS_LIGHTING, FALSE);
// Enable dithering
IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_DITHERENABLE, TRUE);
IDirect3DDevice9_SetRenderState(d3ddev, D3DRS_DITHERENABLE, TRUE);
// disable stencil
IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_STENCILENABLE, FALSE);
IDirect3DDevice9_SetRenderState(d3ddev, D3DRS_STENCILENABLE, FALSE);
// manage blending
IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_ALPHABLENDENABLE, TRUE);
IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_SRCBLEND,D3DBLEND_SRCALPHA);
IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_DESTBLEND,D3DBLEND_INVSRCALPHA);
IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_ALPHATESTENABLE,TRUE);
IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_ALPHAREF, 0x10);
IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_ALPHAFUNC,D3DCMP_GREATER);
IDirect3DDevice9_SetRenderState(d3ddev, D3DRS_ALPHABLENDENABLE, TRUE);
IDirect3DDevice9_SetRenderState(d3ddev, D3DRS_SRCBLEND,D3DBLEND_SRCALPHA);
IDirect3DDevice9_SetRenderState(d3ddev, D3DRS_DESTBLEND,D3DBLEND_INVSRCALPHA);
IDirect3DDevice9_SetRenderState(d3ddev, D3DRS_ALPHATESTENABLE,TRUE);
IDirect3DDevice9_SetRenderState(d3ddev, D3DRS_ALPHAREF, 0x10);
IDirect3DDevice9_SetRenderState(d3ddev, D3DRS_ALPHAFUNC,D3DCMP_GREATER);
// Set texture states
IDirect3DDevice9_SetTextureStageState(p_d3ddev, 0, D3DTSS_COLOROP,D3DTOP_MODULATE);
IDirect3DDevice9_SetTextureStageState(p_d3ddev, 0, D3DTSS_COLORARG1,D3DTA_TEXTURE);
IDirect3DDevice9_SetTextureStageState(p_d3ddev, 0, D3DTSS_COLORARG2,D3DTA_DIFFUSE);
IDirect3DDevice9_SetTextureStageState(d3ddev, 0, D3DTSS_COLOROP,D3DTOP_MODULATE);
IDirect3DDevice9_SetTextureStageState(d3ddev, 0, D3DTSS_COLORARG1,D3DTA_TEXTURE);
IDirect3DDevice9_SetTextureStageState(d3ddev, 0, D3DTSS_COLORARG2,D3DTA_DIFFUSE);
// turn off alpha operation
IDirect3DDevice9_SetTextureStageState(p_d3ddev, 0, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
IDirect3DDevice9_SetTextureStageState(d3ddev, 0, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
msg_Dbg(p_vout, "Direct3D scene created successfully");
msg_Dbg(vd, "Direct3D scene created successfully");
return VLC_SUCCESS;
}
/*****************************************************************************
* Direct3DReleaseScene
*****************************************************************************/
static void Direct3DReleaseScene(vout_thread_t *p_vout)
/**
* It releases the scene resources.
*/
static void Direct3DDestroyScene(vout_display_t *vd)
{
vout_sys_t *p_sys = p_vout->p_sys;
vout_display_sys_t *sys = vd->sys;
LPDIRECT3DVERTEXBUFFER9 p_d3dvtc = p_sys->p_d3dvtc;
if (p_d3dvtc)
IDirect3DVertexBuffer9_Release(p_d3dvtc);
LPDIRECT3DVERTEXBUFFER9 d3dvtc = sys->d3dvtc;
if (d3dvtc)
IDirect3DVertexBuffer9_Release(d3dvtc);
LPDIRECT3DTEXTURE9 p_d3dtex = p_sys->p_d3dtex;
if (p_d3dtex)
IDirect3DTexture9_Release(p_d3dtex);
LPDIRECT3DTEXTURE9 d3dtex = sys->d3dtex;
if (d3dtex)
IDirect3DTexture9_Release(d3dtex);
p_sys->p_d3dvtc = NULL;
p_sys->p_d3dtex = NULL;
msg_Dbg(p_vout, "Direct3D scene released successfully");
sys->d3dvtc = NULL;
sys->d3dtex = NULL;
msg_Dbg(vd, "Direct3D scene released successfully");
}
/*****************************************************************************
* Render: copy picture surface into a texture and render into a scene
*****************************************************************************
/**
* It copies picture surface into a texture and renders into a scene.
*
* This function is intented for higher end 3D cards, with pixel shader support
* and at least 64 MB of video RAM.
*****************************************************************************/
static void Direct3DRenderScene(vout_thread_t *p_vout, picture_t *p_pic)
*/
static void Direct3DRenderScene(vout_display_t *vd, LPDIRECT3DSURFACE9 surface)
{
vout_sys_t *p_sys = p_vout->p_sys;
LPDIRECT3DDEVICE9 p_d3ddev = p_sys->p_d3ddev;
vout_display_sys_t *sys = vd->sys;
LPDIRECT3DDEVICE9 d3ddev = sys->d3ddev;
HRESULT hr;
// check if device is still available
hr = IDirect3DDevice9_TestCooperativeLevel(p_d3ddev);
hr = IDirect3DDevice9_TestCooperativeLevel(d3ddev);
if (FAILED(hr)) {
if (hr != D3DERR_DEVICENOTRESET || Direct3DResetDevice(p_vout)) {
// device is not usable at present (lost device, out of video mem ?)
return;
if (hr == D3DERR_DEVICENOTRESET && !sys->reset_device) {
vout_display_SendEventPicturesInvalid(vd);
sys->reset_device = true;
}
return;
}
/* */
LPDIRECT3DTEXTURE9 p_d3dtex = p_sys->p_d3dtex;
LPDIRECT3DVERTEXBUFFER9 p_d3dvtc = p_sys->p_d3dvtc;
LPDIRECT3DTEXTURE9 d3dtex = sys->d3dtex;
LPDIRECT3DVERTEXBUFFER9 d3dvtc = sys->d3dvtc;
/* Clear the backbuffer and the zbuffer */
hr = IDirect3DDevice9_Clear(p_d3ddev, 0, NULL, D3DCLEAR_TARGET,
hr = IDirect3DDevice9_Clear(d3ddev, 0, NULL, D3DCLEAR_TARGET,
D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
if (FAILED(hr)) {
msg_Dbg(p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
msg_Dbg(vd, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
return;
}
/* retrieve picture surface */
LPDIRECT3DSURFACE9 p_d3dsrc = (LPDIRECT3DSURFACE9)p_pic->p_sys;
if (!p_d3dsrc) {
msg_Dbg(p_vout, "no surface to render ?");
LPDIRECT3DSURFACE9 d3dsrc = surface;
if (!d3dsrc) {
msg_Dbg(vd, "no surface to render ?");
return;
}
/* retrieve texture top-level surface */
LPDIRECT3DSURFACE9 p_d3ddest;
hr = IDirect3DTexture9_GetSurfaceLevel(p_d3dtex, 0, &p_d3ddest);
LPDIRECT3DSURFACE9 d3ddest;
hr = IDirect3DTexture9_GetSurfaceLevel(d3dtex, 0, &d3ddest);
if (FAILED(hr)) {
msg_Dbg(p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
msg_Dbg(vd, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
return;
}
/* Copy picture surface into texture surface
* color space conversion and scaling happen here */
RECT src = p_vout->p_sys->rect_src_clipped;
RECT dst = p_vout->p_sys->rect_dest_clipped;
RECT src = vd->sys->rect_src_clipped;
RECT dst = vd->sys->rect_dest_clipped;
hr = IDirect3DDevice9_StretchRect(p_d3ddev, p_d3dsrc, &src, p_d3ddest, &dst, D3DTEXF_LINEAR);
IDirect3DSurface9_Release(p_d3ddest);
hr = IDirect3DDevice9_StretchRect(d3ddev, d3dsrc, &src, d3ddest, &dst, D3DTEXF_LINEAR);
IDirect3DSurface9_Release(d3ddest);
if (FAILED(hr)) {
msg_Dbg(p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
msg_Dbg(vd, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
return;
}
/* Update the vertex buffer */
CUSTOMVERTEX *p_vertices;
hr = IDirect3DVertexBuffer9_Lock(p_d3dvtc, 0, 0, (&p_vertices), D3DLOCK_DISCARD);
CUSTOMVERTEX *vertices;
hr = IDirect3DVertexBuffer9_Lock(d3dvtc, 0, 0, &vertices, D3DLOCK_DISCARD);
if (FAILED(hr)) {
msg_Dbg(p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
msg_Dbg(vd, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
return;
}
/* Setup vertices */
float f_width = (float)p_vout->p_sys->d3dpp.BackBufferWidth;
float f_height = (float)p_vout->p_sys->d3dpp.BackBufferHeight;
const float f_width = vd->sys->d3dpp.BackBufferWidth;
const float f_height = vd->sys->d3dpp.BackBufferHeight;
/* -0.5f is a "feature" of DirectX and it seems to apply to Direct3d also */
/* http://www.sjbrown.co.uk/2003/05/01/fix-directx-rasterisation/ */
p_vertices[0].x = -0.5f; // left
p_vertices[0].y = -0.5f; // top
p_vertices[0].z = 0.0f;
p_vertices[0].diffuse = D3DCOLOR_ARGB(255, 255, 255, 255);
p_vertices[0].rhw = 1.0f;
p_vertices[0].tu = 0.0f;
p_vertices[0].tv = 0.0f;
p_vertices[1].x = f_width - 0.5f; // right
p_vertices[1].y = -0.5f; // top
p_vertices[1].z = 0.0f;
p_vertices[1].diffuse = D3DCOLOR_ARGB(255, 255, 255, 255);
p_vertices[1].rhw = 1.0f;
p_vertices[1].tu = 1.0f;
p_vertices[1].tv = 0.0f;
p_vertices[2].x = f_width - 0.5f; // right
p_vertices[2].y = f_height - 0.5f; // bottom
p_vertices[2].z = 0.0f;
p_vertices[2].diffuse = D3DCOLOR_ARGB(255, 255, 255, 255);
p_vertices[2].rhw = 1.0f;
p_vertices[2].tu = 1.0f;
p_vertices[2].tv = 1.0f;
p_vertices[3].x = -0.5f; // left
p_vertices[3].y = f_height - 0.5f; // bottom
p_vertices[3].z = 0.0f;
p_vertices[3].diffuse = D3DCOLOR_ARGB(255, 255, 255, 255);
p_vertices[3].rhw = 1.0f;
p_vertices[3].tu = 0.0f;
p_vertices[3].tv = 1.0f;
hr= IDirect3DVertexBuffer9_Unlock(p_d3dvtc);
vertices[0].x = -0.5f; // left
vertices[0].y = -0.5f; // top
vertices[0].z = 0.0f;
vertices[0].diffuse = D3DCOLOR_ARGB(255, 255, 255, 255);
vertices[0].rhw = 1.0f;
vertices[0].tu = 0.0f;
vertices[0].tv = 0.0f;
vertices[1].x = f_width - 0.5f; // right
vertices[1].y = -0.5f; // top
vertices[1].z = 0.0f;
vertices[1].diffuse = D3DCOLOR_ARGB(255, 255, 255, 255);
vertices[1].rhw = 1.0f;
vertices[1].tu = 1.0f;
vertices[1].tv = 0.0f;
vertices[2].x = f_width - 0.5f; // right
vertices[2].y = f_height - 0.5f; // bottom
vertices[2].z = 0.0f;
vertices[2].diffuse = D3DCOLOR_ARGB(255, 255, 255, 255);
vertices[2].rhw = 1.0f;
vertices[2].tu = 1.0f;
vertices[2].tv = 1.0f;
vertices[3].x = -0.5f; // left
vertices[3].y = f_height - 0.5f; // bottom
vertices[3].z = 0.0f;
vertices[3].diffuse = D3DCOLOR_ARGB(255, 255, 255, 255);
vertices[3].rhw = 1.0f;
vertices[3].tu = 0.0f;
vertices[3].tv = 1.0f;
hr= IDirect3DVertexBuffer9_Unlock(d3dvtc);
if (FAILED(hr)) {
msg_Dbg(p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
msg_Dbg(vd, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
return;
}
// Begin the scene
hr = IDirect3DDevice9_BeginScene(p_d3ddev);
hr = IDirect3DDevice9_BeginScene(d3ddev);
if (FAILED(hr)) {
msg_Dbg(p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
msg_Dbg(vd, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
return;
}
......@@ -1149,41 +1175,41 @@ static void Direct3DRenderScene(vout_thread_t *p_vout, picture_t *p_pic)
// which govern how textures get blended together (in the case of multiple
// textures) and lighting information. In this case, we are modulating
// (blending) our texture with the diffuse color of the vertices.
hr = IDirect3DDevice9_SetTexture(p_d3ddev, 0, (LPDIRECT3DBASETEXTURE9)p_d3dtex);
hr = IDirect3DDevice9_SetTexture(d3ddev, 0, (LPDIRECT3DBASETEXTURE9)d3dtex);
if (FAILED(hr)) {
msg_Dbg(p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
IDirect3DDevice9_EndScene(p_d3ddev);
msg_Dbg(vd, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
IDirect3DDevice9_EndScene(d3ddev);
return;
}
// Render the vertex buffer contents
hr = IDirect3DDevice9_SetStreamSource(p_d3ddev, 0, p_d3dvtc, 0, sizeof(CUSTOMVERTEX));
hr = IDirect3DDevice9_SetStreamSource(d3ddev, 0, d3dvtc, 0, sizeof(CUSTOMVERTEX));
if (FAILED(hr)) {
msg_Dbg(p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
IDirect3DDevice9_EndScene(p_d3ddev);
msg_Dbg(vd, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
IDirect3DDevice9_EndScene(d3ddev);
return;
}
// we use FVF instead of vertex shader
hr = IDirect3DDevice9_SetFVF(p_d3ddev, D3DFVF_CUSTOMVERTEX);
hr = IDirect3DDevice9_SetFVF(d3ddev, D3DFVF_CUSTOMVERTEX);
if (FAILED(hr)) {
msg_Dbg(p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
IDirect3DDevice9_EndScene(p_d3ddev);
msg_Dbg(vd, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
IDirect3DDevice9_EndScene(d3ddev);
return;
}
// draw rectangle
hr = IDirect3DDevice9_DrawPrimitive(p_d3ddev, D3DPT_TRIANGLEFAN, 0, 2);
hr = IDirect3DDevice9_DrawPrimitive(d3ddev, D3DPT_TRIANGLEFAN, 0, 2);
if (FAILED(hr)) {
msg_Dbg(p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
IDirect3DDevice9_EndScene(p_d3ddev);
msg_Dbg(vd, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
IDirect3DDevice9_EndScene(d3ddev);
return;
}
// End the scene
hr = IDirect3DDevice9_EndScene(p_d3ddev);
hr = IDirect3DDevice9_EndScene(d3ddev);
if (FAILED(hr)) {
msg_Dbg(p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
msg_Dbg(vd, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
return;
}
}
......@@ -1195,24 +1221,28 @@ static int DesktopCallback(vlc_object_t *object, char const *psz_cmd,
vlc_value_t oldval, vlc_value_t newval,
void *p_data)
{
vout_display_t *vd = (vout_display_t *)object;
vout_display_sys_t *sys = vd->sys;
VLC_UNUSED(psz_cmd);
VLC_UNUSED(oldval);
VLC_UNUSED(p_data);
vout_thread_t *p_vout = (vout_thread_t *)object;
if ((newval.b_bool && !p_vout->p_sys->b_desktop) ||
(!newval.b_bool && p_vout->p_sys->b_desktop)) {
vlc_mutex_lock(&sys->lock);
const bool ch_desktop = !sys->desktop_requested != !newval.b_bool;
sys->ch_desktop |= ch_desktop;
sys->desktop_requested = newval.b_bool;
vlc_mutex_unlock(&sys->lock);
playlist_t *p_playlist = pl_Hold(p_vout);
/* FIXME we should have a way to export variable to be saved */
if (ch_desktop) {
playlist_t *p_playlist = pl_Hold(vd);
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);
var_SetBool(p_playlist, "direct3d-desktop", newval.b_bool);
pl_Release(vd);
}
p_vout->p_sys->i_changes |= DX_DESKTOP_CHANGE;
}
return VLC_SUCCESS;
}
......@@ -31,8 +31,7 @@
#endif
#include <vlc_common.h>
#include <vlc_playlist.h>
#include <vlc_vout.h>
#include <vlc_vout_display.h>
#include <vlc_vout_window.h>
#include <windows.h>
......@@ -52,7 +51,7 @@
#endif
#include <vlc_keys.h>
#include "vout.h"
#include "common.h"
#ifdef UNDER_CE
#include <aygshell.h>
......@@ -75,7 +74,7 @@
struct event_thread_t
{
vout_thread_t *p_vout;
vout_display_t *vd;
/* */
vlc_thread_t thread;
......@@ -100,26 +99,22 @@ struct event_thread_t
int i_window_style;
vout_window_cfg_t wnd_cfg;
/* */
unsigned i_changes;
/* */
vout_window_t *parent_window;
HWND hparent;
HWND hwnd;
HWND hvideownd;
HWND hfswnd;
video_format_t source;
vout_display_place_t place;
bool has_moved;
};
static int DirectXCreateWindow( event_thread_t * );
static void DirectXCloseWindow ( event_thread_t * );
static long FAR PASCAL DirectXEventProc( HWND, UINT, WPARAM, LPARAM );
static void DirectXPopupMenu( event_thread_t *p_event, bool b_open )
{
var_SetBool( p_event->p_vout->p_libvlc, "intf-popupmenu", b_open );
}
static int DirectXConvertKey( int i_key );
/*****************************************************************************
......@@ -133,11 +128,9 @@ static int DirectXConvertKey( int i_key );
static void *EventThread( void *p_this )
{
event_thread_t *p_event = (event_thread_t *)p_this;
vout_thread_t *p_vout = p_event->p_vout;
vout_display_t *vd = p_event->vd;
MSG msg;
POINT old_mouse_pos = {0,0}, mouse_pos;
vlc_value_t val;
unsigned int i_width, i_height, i_x, i_y;
HMODULE hkernel32;
int canc = vlc_savecancel ();
......@@ -173,7 +166,7 @@ static void *EventThread( void *p_this )
/* Prevent monitor from powering off */
OurSetThreadExecutionState( ES_DISPLAY_REQUIRED | ES_CONTINUOUS );
else
msg_Dbg( p_vout, "no support for SetThreadExecutionState()" );
msg_Dbg( vd, "no support for SetThreadExecutionState()" );
}
#endif
......@@ -181,6 +174,9 @@ static void *EventThread( void *p_this )
/* GetMessage will sleep if there's no message in the queue */
for( ;; )
{
vout_display_place_t place;
video_format_t source;
if( !GetMessage( &msg, 0, 0, 0 ) )
{
vlc_mutex_lock( &p_event->lock );
......@@ -199,37 +195,30 @@ static void *EventThread( void *p_this )
/* */
switch( msg.message )
{
case WM_MOUSEMOVE:
vlc_mutex_lock( &p_event->lock );
vout_PlacePicture( p_event->p_vout,
p_event->wnd_cfg.width,
p_event->wnd_cfg.height,
&i_x, &i_y, &i_width, &i_height );
place = p_event->place;
source = p_event->source;
vlc_mutex_unlock( &p_event->lock );
if( place.width > 0 && place.height > 0 )
{
if( msg.hwnd == p_event->hvideownd )
{
/* Child window */
i_x = i_y = 0;
place.x = 0;
place.y = 0;
}
if( i_width && i_height )
{
val.i_int = ( GET_X_LPARAM(msg.lParam) - i_x ) *
p_event->p_vout->fmt_in.i_visible_width / i_width +
p_event->p_vout->fmt_in.i_x_offset;
var_Set( p_event->p_vout, "mouse-x", val );
val.i_int = ( GET_Y_LPARAM(msg.lParam) - i_y ) *
p_event->p_vout->fmt_in.i_visible_height / i_height +
p_event->p_vout->fmt_in.i_y_offset;
var_Set( p_event->p_vout, "mouse-y", val );
var_SetBool( p_event->p_vout, "mouse-moved", true );
const int x = source.i_x_offset +
(int64_t)(GET_X_LPARAM(msg.lParam) - place.x) * source.i_width / place.width;
const int y = source.i_y_offset +
(int64_t)(GET_Y_LPARAM(msg.lParam) - place.y) * source.i_height / place.height;
vout_display_SendEventMouseMoved(vd, x, y);
}
/* Fall through */
case WM_NCMOUSEMOVE:
GetCursorPos( &mouse_pos );
/* FIXME, why this >2 limits ? */
if( (abs(mouse_pos.x - old_mouse_pos.x) > 2 ||
(abs(mouse_pos.y - old_mouse_pos.y)) > 2 ) )
{
......@@ -238,132 +227,114 @@ static void *EventThread( void *p_this )
if( p_event->b_cursor_hidden )
{
p_event->b_cursor_hidden = 0;
p_event->b_cursor_hidden = false;
ShowCursor( TRUE );
}
}
break;
case WM_VLC_HIDE_MOUSE:
if( p_event->b_cursor_hidden ) break;
if( p_event->b_cursor_hidden )
break;
p_event->b_cursor_hidden = true;
GetCursorPos( &old_mouse_pos );
ShowCursor( FALSE );
break;
case WM_VLC_SHOW_MOUSE:
if( !p_event->b_cursor_hidden ) break;
if( !p_event->b_cursor_hidden )
break;
p_event->b_cursor_hidden = false;
GetCursorPos( &old_mouse_pos );
ShowCursor( TRUE );
break;
case WM_LBUTTONDOWN:
var_Get( p_event->p_vout, "mouse-button-down", &val );
val.i_int |= 1;
var_Set( p_event->p_vout, "mouse-button-down", val );
DirectXPopupMenu( p_event, false );
vout_display_SendEventMousePressed(vd, MOUSE_BUTTON_LEFT);
break;
case WM_LBUTTONUP:
var_Get( p_event->p_vout, "mouse-button-down", &val );
val.i_int &= ~1;
var_Set( p_event->p_vout, "mouse-button-down", val );
var_SetBool( p_event->p_vout, "mouse-clicked", true );
vout_display_SendEventMouseReleased(vd, MOUSE_BUTTON_LEFT);
break;
case WM_LBUTTONDBLCLK:
vlc_mutex_lock( &p_event->lock );
p_event->i_changes |= VOUT_FULLSCREEN_CHANGE;
vlc_mutex_unlock( &p_event->lock );
vout_display_SendEventMouseDoubleClick(vd);
break;
case WM_MBUTTONDOWN:
var_Get( p_event->p_vout, "mouse-button-down", &val );
val.i_int |= 2;
var_Set( p_event->p_vout, "mouse-button-down", val );
DirectXPopupMenu( p_event, false );
vout_display_SendEventMousePressed(vd, MOUSE_BUTTON_CENTER);
break;
case WM_MBUTTONUP:
var_Get( p_event->p_vout, "mouse-button-down", &val );
val.i_int &= ~2;
var_Set( p_event->p_vout, "mouse-button-down", val );
vout_display_SendEventMouseReleased(vd, MOUSE_BUTTON_CENTER);
break;
case WM_RBUTTONDOWN:
var_Get( p_event->p_vout, "mouse-button-down", &val );
val.i_int |= 4;
var_Set( p_event->p_vout, "mouse-button-down", val );
DirectXPopupMenu( p_event, false );
vout_display_SendEventMousePressed(vd, MOUSE_BUTTON_RIGHT);
break;
case WM_RBUTTONUP:
var_Get( p_event->p_vout, "mouse-button-down", &val );
val.i_int &= ~4;
var_Set( p_event->p_vout, "mouse-button-down", val );
DirectXPopupMenu( p_event, true );
vout_display_SendEventMouseReleased(vd, MOUSE_BUTTON_RIGHT);
break;
case WM_KEYDOWN:
case WM_SYSKEYDOWN:
{
/* The key events are first processed here and not translated
* into WM_CHAR events because we need to know the status of the
* modifier keys. */
val.i_int = DirectXConvertKey( msg.wParam );
if( !val.i_int )
int i_key = DirectXConvertKey( msg.wParam );
if( !i_key )
{
/* This appears to be a "normal" (ascii) key */
val.i_int = tolower( MapVirtualKey( msg.wParam, 2 ) );
i_key = tolower( MapVirtualKey( msg.wParam, 2 ) );
}
if( val.i_int )
if( i_key )
{
if( GetKeyState(VK_CONTROL) & 0x8000 )
{
val.i_int |= KEY_MODIFIER_CTRL;
i_key |= KEY_MODIFIER_CTRL;
}
if( GetKeyState(VK_SHIFT) & 0x8000 )
{
val.i_int |= KEY_MODIFIER_SHIFT;
i_key |= KEY_MODIFIER_SHIFT;
}
if( GetKeyState(VK_MENU) & 0x8000 )
{
val.i_int |= KEY_MODIFIER_ALT;
i_key |= KEY_MODIFIER_ALT;
}
var_Set( p_vout->p_libvlc, "key-pressed", val );
vout_display_SendEventKey(vd, i_key);
}
break;
}
case WM_MOUSEWHEEL:
{
int i_key;
if( GET_WHEEL_DELTA_WPARAM( msg.wParam ) > 0 )
{
val.i_int = KEY_MOUSEWHEELUP;
i_key = KEY_MOUSEWHEELUP;
}
else
{
val.i_int = KEY_MOUSEWHEELDOWN;
i_key = KEY_MOUSEWHEELDOWN;
}
if( val.i_int )
if( i_key )
{
if( GetKeyState(VK_CONTROL) & 0x8000 )
{
val.i_int |= KEY_MODIFIER_CTRL;
i_key |= KEY_MODIFIER_CTRL;
}
if( GetKeyState(VK_SHIFT) & 0x8000 )
{
val.i_int |= KEY_MODIFIER_SHIFT;
i_key |= KEY_MODIFIER_SHIFT;
}
if( GetKeyState(VK_MENU) & 0x8000 )
{
val.i_int |= KEY_MODIFIER_ALT;
i_key |= KEY_MODIFIER_ALT;
}
var_Set( p_vout->p_libvlc, "key-pressed", val );
vout_display_SendEventKey(vd, i_key);
}
break;
}
case WM_VLC_CHANGE_TEXT:
{
......@@ -405,11 +376,11 @@ static void *EventThread( void *p_this )
/* Check for WM_QUIT if we created the window */
if( !p_event->hparent && msg.message == WM_QUIT )
{
msg_Warn( p_vout, "WM_QUIT... should not happen!!" );
msg_Warn( vd, "WM_QUIT... should not happen!!" );
p_event->hwnd = NULL; /* Window already destroyed */
}
msg_Dbg( p_vout, "DirectXEventThread terminating" );
msg_Dbg( vd, "DirectXEventThread terminating" );
DirectXCloseWindow( p_event );
vlc_restorecancel(canc);
......@@ -428,7 +399,7 @@ static void *EventThread( void *p_this )
*****************************************************************************/
static int DirectXCreateWindow( event_thread_t *p_event )
{
vout_thread_t *p_vout = p_event->p_vout;
vout_display_t *vd = p_event->vd;
HINSTANCE hInstance;
HMENU hMenu;
RECT rect_window;
......@@ -437,7 +408,7 @@ static int DirectXCreateWindow( event_thread_t *p_event )
char vlc_path[MAX_PATH+1];
int i_style, i_stylex;
msg_Dbg( p_vout, "DirectXCreateWindow" );
msg_Dbg( vd, "DirectXCreateWindow" );
/* Get this module's instance */
hInstance = GetModuleHandle(NULL);
......@@ -447,7 +418,7 @@ static int DirectXCreateWindow( event_thread_t *p_event )
{
#endif
/* If an external window was specified, we'll draw in it. */
p_event->parent_window = vout_window_New( VLC_OBJECT(p_vout), NULL, &p_event->wnd_cfg );
p_event->parent_window = vout_display_NewWindow(vd, &p_event->wnd_cfg );
if( p_event->parent_window )
p_event->hparent = p_event->parent_window->handle.hwnd;
else
......@@ -461,7 +432,8 @@ static int DirectXCreateWindow( event_thread_t *p_event )
if( hwnd ) hwnd = FindWindowEx( hwnd, NULL, _T("SHELLDLL_DefView"), NULL );
if( hwnd ) hwnd = FindWindowEx( hwnd, NULL, _T("SysListView32"), NULL );
if( !hwnd )
msg_Err( p_vout, "Couldn't find desktop icon window. Desktop mode can't be established." );
msg_Err( vd, "Couldn't find desktop icon window. Desktop mode can't be established." );
p_event->parent_window = NULL;
p_event->hparent = hwnd;
}
#endif
......@@ -498,7 +470,7 @@ static int DirectXCreateWindow( event_thread_t *p_event )
* then fine, otherwise return with an error. */
if( !GetClassInfo( hInstance, _T("VLC DirectX"), &wndclass ) )
{
msg_Err( p_vout, "DirectXCreateWindow RegisterClass FAILED (err=%lu)", GetLastError() );
msg_Err( vd, "DirectXCreateWindow RegisterClass FAILED (err=%lu)", GetLastError() );
return VLC_EGENERIC;
}
}
......@@ -514,7 +486,7 @@ static int DirectXCreateWindow( event_thread_t *p_event )
* then fine, otherwise return with an error. */
if( !GetClassInfo( hInstance, _T("VLC DirectX video"), &wndclass ) )
{
msg_Err( p_vout, "DirectXCreateWindow RegisterClass FAILED (err=%lu)", GetLastError() );
msg_Err( vd, "DirectXCreateWindow RegisterClass FAILED (err=%lu)", GetLastError() );
return VLC_EGENERIC;
}
}
......@@ -528,7 +500,7 @@ static int DirectXCreateWindow( event_thread_t *p_event )
rect_window.right = rect_window.left + p_event->wnd_cfg.width;
rect_window.bottom = rect_window.top + p_event->wnd_cfg.height;
if( var_GetBool( p_vout, "video-deco" ) )
if( var_GetBool( vd, "video-deco" ) )
{
/* Open with window decoration */
AdjustWindowRect( &rect_window, WS_OVERLAPPEDWINDOW|WS_SIZEBOX, 0 );
......@@ -567,11 +539,11 @@ static int DirectXCreateWindow( event_thread_t *p_event )
p_event->hparent, /* parent window */
NULL, /* no menu in this window */
hInstance, /* handle of this program instance */
(LPVOID)p_event ); /* send p_vout to WM_CREATE */
(LPVOID)p_event ); /* send vd to WM_CREATE */
if( !p_event->hwnd )
{
msg_Warn( p_vout, "DirectXCreateWindow create window FAILED (err=%lu)", GetLastError() );
msg_Warn( vd, "DirectXCreateWindow create window FAILED (err=%lu)", GetLastError() );
return VLC_EGENERIC;
}
......@@ -610,20 +582,21 @@ static int DirectXCreateWindow( event_thread_t *p_event )
/* Create video sub-window. This sub window will always exactly match
* the size of the video, which allows us to use crazy overlay colorkeys
* without having them shown outside of the video area. */
/* FIXME vd->source.i_width/i_height seems wrong */
p_event->hvideownd =
CreateWindow( _T("VLC DirectX video"), _T(""), /* window class */
WS_CHILD, /* window style, not visible initially */
0, 0,
p_vout->render.i_width, /* default width */
p_vout->render.i_height, /* default height */
vd->source.i_width, /* default width */
vd->source.i_height, /* default height */
p_event->hwnd, /* parent window */
NULL, hInstance,
(LPVOID)p_event ); /* send p_vout to WM_CREATE */
(LPVOID)p_event ); /* send vd to WM_CREATE */
if( !p_event->hvideownd )
msg_Warn( p_vout, "can't create video sub-window" );
msg_Warn( vd, "can't create video sub-window" );
else
msg_Dbg( p_vout, "created video sub-window" );
msg_Dbg( vd, "created video sub-window" );
/* Now display the window */
ShowWindow( p_event->hwnd, SW_SHOW );
......@@ -638,16 +611,17 @@ static int DirectXCreateWindow( event_thread_t *p_event )
*****************************************************************************/
static void DirectXCloseWindow( event_thread_t *p_event )
{
vout_thread_t *p_vout = p_event->p_vout;
msg_Dbg( p_vout, "DirectXCloseWindow" );
vout_display_t *vd = p_event->vd;
msg_Dbg( vd, "DirectXCloseWindow" );
DestroyWindow( p_event->hwnd );
if( p_event->hfswnd ) DestroyWindow( p_event->hfswnd );
if( p_event->hfswnd )
DestroyWindow( p_event->hfswnd );
#ifdef MODULE_NAME_IS_direct3d
if( !p_event->use_desktop )
#endif
vout_window_Delete( p_event->parent_window );
vout_display_DeleteWindow( vd, p_event->parent_window );
p_event->hwnd = NULL;
/* We don't unregister the Window Class because it could lead to race
......@@ -673,7 +647,7 @@ static long FAR PASCAL DirectXEventProc( HWND hwnd, UINT message,
if( message == WM_CREATE )
{
/* Store p_vout for future use */
/* Store vd for future use */
p_event = (event_thread_t *)((CREATESTRUCT *)lParam)->lpCreateParams;
SetWindowLongPtr( hwnd, GWLP_USERDATA, (LONG_PTR)p_event );
return TRUE;
......@@ -689,14 +663,14 @@ static long FAR PASCAL DirectXEventProc( HWND hwnd, UINT message,
return DefWindowProc(hwnd, message, wParam, lParam);
}
}
vout_thread_t *p_vout = p_event->p_vout;
vout_display_t *vd = p_event->vd;
#ifndef UNDER_CE
/* Catch the screensaver and the monitor turn-off */
if( message == WM_SYSCOMMAND &&
( (wParam & 0xFFF0) == SC_SCREENSAVE || (wParam & 0xFFF0) == SC_MONITORPOWER ) )
{
//if( p_vout ) msg_Dbg( p_vout, "WinProc WM_SYSCOMMAND screensaver" );
//if( vd ) msg_Dbg( vd, "WinProc WM_SYSCOMMAND screensaver" );
return 0; /* this stops them from happening */
}
#endif
......@@ -751,24 +725,19 @@ static long FAR PASCAL DirectXEventProc( HWND hwnd, UINT message,
{
case WM_WINDOWPOSCHANGED:
UpdateRects( p_vout, true );
vlc_mutex_lock( &p_event->lock );
p_event->has_moved = true;
vlc_mutex_unlock( &p_event->lock );
return 0;
/* the user wants to close the window */
case WM_CLOSE:
{
playlist_t * p_playlist = pl_Hold( p_vout );
if( p_playlist )
{
playlist_Stop( p_playlist );
pl_Release( p_vout );
}
vout_display_SendEventClose(vd);
return 0;
}
/* the window has been closed so shut down everything now */
case WM_DESTROY:
msg_Dbg( p_vout, "WinProc WM_DESTROY" );
msg_Dbg( vd, "WinProc WM_DESTROY" );
/* just destroy the window */
PostQuitMessage( 0 );
return 0;
......@@ -778,12 +747,13 @@ static long FAR PASCAL DirectXEventProc( HWND hwnd, UINT message,
{
case IDM_TOGGLE_ON_TOP: /* toggle the "on top" status */
{
msg_Dbg( p_vout, "WinProc WM_SYSCOMMAND: IDM_TOGGLE_ON_TOP");
/* Change the current value */
var_ToggleBool( p_vout, "video-on-top" );
msg_Dbg(vd, "WinProc WM_SYSCOMMAND: IDM_TOGGLE_ON_TOP");
HMENU hMenu = GetSystemMenu(vd->sys->hwnd, FALSE);
vout_display_SendEventOnTop(vd, (GetMenuState(hMenu, IDM_TOGGLE_ON_TOP, MF_BYCOMMAND) & MF_CHECKED) == 0);
return 0;
}
default:
break;
}
break;
......@@ -816,13 +786,11 @@ static long FAR PASCAL DirectXEventProc( HWND hwnd, UINT message,
GXResume();
#endif
#ifdef UNDER_CE
/* FIXME vd->cfg is not lock[ed/able] */
#warning "FIXME: race condition"
if( p_event->hparent &&
hwnd != p_event->hfswnd && p_vout->b_fullscreen )
{
vlc_mutex_lock( &p_event->lock );
p_event->i_changes |= VOUT_FULLSCREEN_CHANGE;
vlc_mutex_unlock( &p_event->lock );
}
hwnd != p_event->hfswnd && vd->cfg->is_fullscreen )
vout_display_SendEventFullscreen(vd, false);
if( hwnd == p_event->hfswnd )
{
......@@ -839,7 +807,7 @@ static long FAR PASCAL DirectXEventProc( HWND hwnd, UINT message,
return 0;
default:
//msg_Dbg( p_vout, "WinProc WM Default %i", message );
//msg_Dbg( vd, "WinProc WM Default %i", message );
break;
}
......@@ -915,10 +883,7 @@ static int DirectXConvertKey( int i_key )
void EventThreadMouseAutoHide( event_thread_t *p_event )
{
vout_thread_t *p_vout = p_event->p_vout;
if( p_vout->b_fullscreen &&
!p_event->b_cursor_hidden &&
if (!p_event->b_cursor_hidden &&
(mdate() - p_event->i_lastmoved) > p_event->i_mouse_hide_timeout )
{
/* Hide the cursor only if it is inside our window */
......@@ -942,7 +907,7 @@ void EventThreadMouseShow( event_thread_t *p_event )
}
void EventThreadUpdateTitle( event_thread_t *p_event, const char *psz_fallback )
{
char *psz_title = var_GetNonEmptyString( p_event->p_vout, "video-title" );
char *psz_title = var_GetNonEmptyString( p_event->vd, "video-title" );
if( !psz_title )
psz_title = strdup( psz_fallback );
if( !psz_title )
......@@ -955,15 +920,6 @@ void EventThreadUpdateTitle( event_thread_t *p_event, const char *psz_fallback )
PostMessage( p_event->hwnd, WM_VLC_CHANGE_TEXT, 0, 0 );
}
unsigned EventThreadRetreiveChanges( event_thread_t *p_event )
{
vlc_mutex_lock( &p_event->lock );
unsigned i_changes = p_event->i_changes;
p_event->i_changes = 0;
vlc_mutex_unlock( &p_event->lock );
return i_changes;
}
int EventThreadGetWindowStyle( event_thread_t *p_event )
{
/* No need to lock, it is serialized by EventThreadStart */
......@@ -986,14 +942,33 @@ void EventThreadUpdateWindowPosition( event_thread_t *p_event, bool *pb_changed,
vlc_mutex_unlock( &p_event->lock );
}
void EventThreadUpdateSourceAndPlace( event_thread_t *p_event,
const video_format_t *p_source,
const vout_display_place_t *p_place )
{
vlc_mutex_lock( &p_event->lock );
p_event->source = *p_source;
p_event->place = *p_place;
vlc_mutex_unlock( &p_event->lock );
}
void EventThreadUseOverlay( event_thread_t *p_event, bool b_used )
{
vlc_mutex_lock( &p_event->lock );
p_event->use_overlay = b_used;
vlc_mutex_unlock( &p_event->lock );
}
bool EventThreadGetAndResetHasMoved( event_thread_t *p_event )
{
vlc_mutex_lock( &p_event->lock );
const bool has_moved = p_event->has_moved;
p_event->has_moved = false;
vlc_mutex_unlock( &p_event->lock );
return has_moved;
}
event_thread_t *EventThreadCreate( vout_thread_t *p_vout, const vout_window_cfg_t *p_wnd_cfg )
event_thread_t *EventThreadCreate( vout_display_t *vd)
{
/* Create the Vout EventThread, this thread is created by us to isolate
* the Win32 PeekMessage function calls. We want to do this because
......@@ -1002,21 +977,22 @@ event_thread_t *EventThreadCreate( vout_thread_t *p_vout, const vout_window_cfg_
* 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" );
msg_Dbg( vd, "creating Vout EventThread" );
event_thread_t *p_event = malloc( sizeof(*p_event) );
if( !p_event )
return NULL;
p_event->p_vout = p_vout;
p_event->vd = vd;
vlc_mutex_init( &p_event->lock );
vlc_cond_init( &p_event->wait );
p_event->b_cursor_hidden = false;
p_event->i_lastmoved = mdate();
p_event->i_mouse_hide_timeout =
var_GetInteger(p_vout, "mouse-hide-timeout") * 1000;
var_GetInteger(vd, "mouse-hide-timeout") * 1000;
p_event->psz_title = NULL;
p_event->wnd_cfg = *p_wnd_cfg;
p_event->source = vd->source;
vout_display_PlacePicture(&p_event->place, &vd->source, vd->cfg, true);
return p_event;
}
......@@ -1033,8 +1009,9 @@ int EventThreadStart( event_thread_t *p_event, event_hwnd_t *p_hwnd, const event
{
p_event->use_desktop = p_cfg->use_desktop;
p_event->use_overlay = p_cfg->use_overlay;
p_event->wnd_cfg = p_cfg->win;
p_event->i_changes = 0;
p_event->has_moved = false;
p_event->b_ready = false;
p_event->b_done = false;
......@@ -1043,7 +1020,7 @@ int EventThreadStart( event_thread_t *p_event, event_hwnd_t *p_hwnd, const event
if( vlc_clone( &p_event->thread, EventThread, p_event,
VLC_THREAD_PRIORITY_LOW ) )
{
msg_Err( p_event->p_vout, "cannot create Vout EventThread" );
msg_Err( p_event->vd, "cannot create Vout EventThread" );
return VLC_EGENERIC;
}
......@@ -1059,12 +1036,10 @@ int EventThreadStart( event_thread_t *p_event, event_hwnd_t *p_hwnd, const event
p_event->b_ready = false;
return VLC_EGENERIC;
}
msg_Dbg( p_event->p_vout, "Vout EventThread running" );
msg_Dbg( p_event->vd, "Vout EventThread running" );
if( !p_event->use_desktop )
/* */
p_hwnd->parent_window = p_event->parent_window;
else
p_hwnd->parent_window = NULL;
p_hwnd->hparent = p_event->hparent;
p_hwnd->hwnd = p_event->hwnd;
p_hwnd->hvideownd = p_event->hvideownd;
......
......@@ -32,6 +32,8 @@ typedef struct event_thread_t event_thread_t;
typedef struct {
bool use_desktop; /* direct3d */
bool use_overlay; /* directx */
vout_window_cfg_t win;
} event_cfg_t;
typedef struct {
......@@ -42,7 +44,7 @@ typedef struct {
HWND hfswnd;
} event_hwnd_t;
event_thread_t *EventThreadCreate( vout_thread_t *, const vout_window_cfg_t * );
event_thread_t *EventThreadCreate( vout_display_t *);
void EventThreadDestroy( event_thread_t * );
int EventThreadStart( event_thread_t *, event_hwnd_t *, const event_cfg_t * );
void EventThreadStop( event_thread_t * );
......@@ -50,8 +52,12 @@ void EventThreadStop( event_thread_t * );
void EventThreadMouseAutoHide( event_thread_t * );
void EventThreadMouseShow( event_thread_t * );
void EventThreadUpdateTitle( event_thread_t *, const char *psz_fallback );
unsigned EventThreadRetreiveChanges( event_thread_t * );
int EventThreadGetWindowStyle( event_thread_t * );
void EventThreadUpdateWindowPosition( event_thread_t *, bool *pb_changed,
int x, int y, int w, int h );
void EventThreadUpdateSourceAndPlace( event_thread_t *p_event,
const video_format_t *p_source,
const vout_display_place_t *p_place );
void EventThreadUseOverlay( event_thread_t *, bool b_used );
bool EventThreadGetAndResetHasMoved( event_thread_t * );
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment