1 /*****************************************************************************
2 * directx.c: Windows DirectDraw video output
3 *****************************************************************************
4 * Copyright (C) 2001-2009 the VideoLAN team
7 * Authors: Gildas Bazin <gbazin@videolan.org>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
24 /*****************************************************************************
27 * This plugin will use YUV overlay if supported, using overlay will result in
28 * the best video quality (hardware interpolation when rescaling the picture)
29 * and the fastest display as it requires less processing.
31 * If YUV overlay is not supported this plugin will use RGB offscreen video
32 * surfaces that will be blitted onto the primary surface (display) to
33 * effectively display the pictures. This fallback method also enables us to
34 * display video in window mode.
36 *****************************************************************************/
42 #include <vlc_common.h>
43 #include <vlc_plugin.h>
44 #include <vlc_vout_display.h>
45 #include <vlc_playlist.h> /* needed for wallpaper */
48 #include <commctrl.h> /* ListView_(Get|Set)* */
51 # include <multimon.h>
53 #undef GetSystemMetrics
55 #ifndef MONITOR_DEFAULTTONEAREST
56 # define MONITOR_DEFAULTTONEAREST 2
62 # error "Unicode mode not supported"
65 /*****************************************************************************
67 *****************************************************************************/
68 #define HW_YUV_TEXT N_("Use hardware YUV->RGB conversions")
69 #define HW_YUV_LONGTEXT N_(\
70 "Try to use hardware acceleration for YUV->RGB conversions. " \
71 "This option doesn't have any effect when using overlays.")
73 #define SYSMEM_TEXT N_("Use video buffers in system memory")
74 #define SYSMEM_LONGTEXT N_(\
75 "Create video buffers in system memory instead of video memory. This " \
76 "isn't recommended as usually using video memory allows to benefit from " \
77 "more hardware acceleration (like rescaling or YUV->RGB conversions). " \
78 "This option doesn't have any effect when using overlays.")
80 #define TRIPLEBUF_TEXT N_("Use triple buffering for overlays")
81 #define TRIPLEBUF_LONGTEXT N_(\
82 "Try to use triple buffering when using YUV overlays. That results in " \
83 "much better video quality (no flickering).")
85 #define DEVICE_TEXT N_("Name of desired display device")
86 #define DEVICE_LONGTEXT N_("In a multiple monitor configuration, you can " \
87 "specify the Windows device name of the display that you want the video " \
88 "window to open on. For example, \"\\\\.\\DISPLAY1\" or " \
89 "\"\\\\.\\DISPLAY2\".")
91 #define DX_HELP N_("Recommended video output for Windows XP. " \
92 "Incompatible with Vista's Aero interface" )
94 static const char * const device
[] = { "" };
95 static const char * const device_text
[] = { N_("Default") };
97 static int Open (vlc_object_t
*);
98 static void Close(vlc_object_t
*);
100 static int FindDevicesCallback(vlc_object_t
*, char const *,
101 vlc_value_t
, vlc_value_t
, void *);
103 set_shortname("DirectX")
104 set_description(N_("DirectX (DirectDraw) video output"))
106 set_category(CAT_VIDEO
)
107 set_subcategory(SUBCAT_VIDEO_VOUT
)
108 add_bool("directx-hw-yuv", true, NULL
, HW_YUV_TEXT
, HW_YUV_LONGTEXT
,
110 add_bool("directx-use-sysmem", false, NULL
, SYSMEM_TEXT
, SYSMEM_LONGTEXT
,
112 add_bool("directx-3buffering", true, NULL
, TRIPLEBUF_TEXT
,
113 TRIPLEBUF_LONGTEXT
, true)
114 add_string("directx-device", "", NULL
, DEVICE_TEXT
, DEVICE_LONGTEXT
, true)
115 change_string_list(device
, device_text
, FindDevicesCallback
)
116 change_action_add(FindDevicesCallback
, N_("Refresh list"))
118 set_capability("vout display", 100)
119 add_shortcut("directx")
120 set_callbacks(Open
, Close
)
123 /*****************************************************************************
125 *****************************************************************************/
127 struct picture_sys_t
{
128 LPDIRECTDRAWSURFACE2 surface
;
129 LPDIRECTDRAWSURFACE2 front_surface
;
133 /*****************************************************************************
135 * Defining them here allows us to get rid of the dxguid library during
137 *****************************************************************************/
138 #include <initguid.h>
141 DEFINE_GUID(IID_IDirectDraw2
, 0xB3A6F3E0,0x2B43,0x11CF,0xA2,0xDE,0x00,0xAA,0x00,0xB9,0x33,0x56);
142 DEFINE_GUID(IID_IDirectDrawSurface2
, 0x57805885,0x6eec,0x11cf,0x94,0x41,0xa8,0x23,0x03,0xc1,0x0e,0x27);
144 static picture_pool_t
*Pool (vout_display_t
*, unsigned);
145 static void Display(vout_display_t
*, picture_t
*);
146 static int Control(vout_display_t
*, int, va_list);
147 static void Manage (vout_display_t
*);
150 static int WallpaperCallback(vlc_object_t
*, char const *,
151 vlc_value_t
, vlc_value_t
, void *);
153 static int DirectXOpen(vout_display_t
*, video_format_t
*fmt
);
154 static void DirectXClose(vout_display_t
*);
156 static int DirectXLock(picture_t
*);
157 static void DirectXUnlock(picture_t
*);
159 static int DirectXUpdateOverlay(vout_display_t
*, LPDIRECTDRAWSURFACE2 surface
);
161 static void WallpaperChange(vout_display_t
*vd
, bool use_wallpaper
);
163 /** This function allocates and initialize the DirectX vout display.
165 static int Open(vlc_object_t
*object
)
167 vout_display_t
*vd
= (vout_display_t
*)object
;
168 vout_display_sys_t
*sys
;
170 /* Allocate structure */
171 vd
->sys
= sys
= calloc(1, sizeof(*sys
));
175 /* Load direct draw DLL */
176 sys
->hddraw_dll
= LoadLibrary(_T("DDRAW.DLL"));
177 if (!sys
->hddraw_dll
) {
178 msg_Warn(vd
, "DirectXInitDDraw failed loading ddraw.dll");
184 HMODULE huser32
= GetModuleHandle(_T("USER32"));
186 sys
->MonitorFromWindow
= (void*)GetProcAddress(huser32
, _T("MonitorFromWindow"));
187 sys
->GetMonitorInfo
= (void*)GetProcAddress(huser32
, _T("GetMonitorInfoA"));
189 sys
->MonitorFromWindow
= NULL
;
190 sys
->GetMonitorInfo
= NULL
;
194 sys
->use_wallpaper
= var_CreateGetBool(vd
, "video-wallpaper");
196 sys
->use_overlay
= false;//var_CreateGetBool(vd, "overlay"); /* FIXME */
197 sys
->restore_overlay
= false;
198 var_Create(vd
, "directx-device", VLC_VAR_STRING
| VLC_VAR_DOINHERIT
);
205 video_format_t fmt
= vd
->fmt
;
207 if (DirectXOpen(vd
, &fmt
))
211 vout_display_info_t info
= vd
->info
;
213 info
.has_double_click
= true;
214 info
.has_hide_mouse
= false;
215 info
.has_pictures_invalid
= true;
216 info
.has_event_thread
= true;
218 /* Interaction TODO support starting with wallpaper mode */
219 vlc_mutex_init(&sys
->lock
);
220 sys
->ch_wallpaper
= sys
->use_wallpaper
;
221 sys
->wallpaper_requested
= sys
->use_wallpaper
;
222 sys
->use_wallpaper
= false;
225 val
.psz_string
= _("Wallpaper");
226 var_Change(vd
, "video-wallpaper", VLC_VAR_SETTEXT
, &val
, NULL
);
227 var_AddCallback(vd
, "video-wallpaper", WallpaperCallback
, NULL
);
229 /* Setup vout_display now that everything is fine */
235 vd
->display
= Display
;
236 vd
->control
= Control
;
244 FreeLibrary(sys
->hddraw_dll
);
249 /** Terminate a vout display created by Open.
251 static void Close(vlc_object_t
*object
)
253 vout_display_t
*vd
= (vout_display_t
*)object
;
254 vout_display_sys_t
*sys
= vd
->sys
;
256 var_DelCallback(vd
, "video-wallpaper", WallpaperCallback
, NULL
);
257 vlc_mutex_destroy(&sys
->lock
);
259 /* Make sure the wallpaper is restored */
260 WallpaperChange(vd
, false);
267 FreeLibrary(sys
->hddraw_dll
);
271 static picture_pool_t
*Pool(vout_display_t
*vd
, unsigned count
)
274 return vd
->sys
->pool
;
276 static void Display(vout_display_t
*vd
, picture_t
*picture
)
278 vout_display_sys_t
*sys
= vd
->sys
;
280 assert(sys
->display
);
282 /* Our surface can be lost so be sure to check this
283 * and restore it if need be */
284 if (IDirectDrawSurface2_IsLost(sys
->display
) == DDERR_SURFACELOST
) {
285 if (IDirectDrawSurface2_Restore(sys
->display
) == DD_OK
) {
286 if (sys
->use_overlay
)
287 DirectXUpdateOverlay(vd
, NULL
);
290 if (sys
->restore_overlay
)
291 DirectXUpdateOverlay(vd
, NULL
);
294 DirectXUnlock(picture
);
296 if (sys
->use_overlay
) {
297 /* Flip the overlay buffers if we are using back buffers */
298 if (picture
->p_sys
->surface
!= picture
->p_sys
->front_surface
) {
299 HRESULT hr
= IDirectDrawSurface2_Flip(picture
->p_sys
->front_surface
,
302 msg_Warn(vd
, "could not flip overlay (error %li)", hr
);
305 /* Blit video surface to display with the NOTEARING option */
307 ZeroMemory(&ddbltfx
, sizeof(ddbltfx
));
308 ddbltfx
.dwSize
= sizeof(ddbltfx
);
309 ddbltfx
.dwDDFX
= DDBLTFX_NOTEARING
;
311 HRESULT hr
= IDirectDrawSurface2_Blt(sys
->display
,
312 &sys
->rect_dest_clipped
,
313 picture
->p_sys
->surface
,
314 &sys
->rect_src_clipped
,
315 DDBLT_ASYNC
, &ddbltfx
);
317 msg_Warn(vd
, "could not blit surface (error %li)", hr
);
319 DirectXLock(picture
);
321 if (sys
->is_first_display
) {
322 IDirectDraw_WaitForVerticalBlank(sys
->ddobject
,
323 DDWAITVB_BLOCKBEGIN
, NULL
);
324 if (sys
->use_overlay
) {
325 HBRUSH brush
= CreateSolidBrush(sys
->i_rgb_colorkey
);
326 /* set the colorkey as the backgound brush for the video window */
327 SetClassLongPtr(sys
->hvideownd
, GCLP_HBRBACKGROUND
, (LONG_PTR
)brush
);
332 picture_Release(picture
);
334 static int Control(vout_display_t
*vd
, int query
, va_list args
)
336 vout_display_sys_t
*sys
= vd
->sys
;
339 case VOUT_DISPLAY_RESET_PICTURES
:
341 /* Make sure the wallpaper is restored */
342 if (sys
->use_wallpaper
) {
343 vlc_mutex_lock(&sys
->lock
);
344 if (!sys
->ch_wallpaper
) {
345 sys
->ch_wallpaper
= true;
346 sys
->wallpaper_requested
= true;
348 vlc_mutex_unlock(&sys
->lock
);
350 WallpaperChange(vd
, false);
352 return DirectXOpen(vd
, &vd
->fmt
);
354 return CommonControl(vd
, query
, args
);
357 static void Manage(vout_display_t
*vd
)
359 vout_display_sys_t
*sys
= vd
->sys
;
363 if (sys
->changes
& DX_POSITION_CHANGE
) {
365 if (sys
->use_overlay
)
366 DirectXUpdateOverlay(vd
, NULL
);
368 /* Check if we are still on the same monitor */
369 if (sys
->MonitorFromWindow
&&
370 sys
->hmonitor
!= sys
->MonitorFromWindow(sys
->hwnd
, MONITOR_DEFAULTTONEAREST
)) {
371 vout_display_SendEventPicturesInvalid(vd
);
374 sys
->changes
&= ~DX_POSITION_CHANGE
;
377 /* Wallpaper mode change */
378 vlc_mutex_lock(&sys
->lock
);
379 const bool ch_wallpaper
= sys
->ch_wallpaper
;
380 const bool wallpaper_requested
= sys
->wallpaper_requested
;
381 sys
->ch_wallpaper
= false;
382 vlc_mutex_unlock(&sys
->lock
);
385 WallpaperChange(vd
, wallpaper_requested
);
388 if (sys
->restore_overlay
)
389 DirectXUpdateOverlay(vd
, NULL
);
393 static int DirectXOpenDDraw(vout_display_t
*);
394 static void DirectXCloseDDraw(vout_display_t
*);
396 static int DirectXOpenDisplay(vout_display_t
*vd
);
397 static void DirectXCloseDisplay(vout_display_t
*vd
);
399 static int DirectXCreatePool(vout_display_t
*, bool *, video_format_t
*);
400 static void DirectXDestroyPool(vout_display_t
*);
402 static int DirectXOpen(vout_display_t
*vd
, video_format_t
*fmt
)
404 vout_display_sys_t
*sys
= vd
->sys
;
406 assert(!sys
->ddobject
);
407 assert(!sys
->display
);
408 assert(!sys
->clipper
);
410 /* Initialise DirectDraw */
411 if (DirectXOpenDDraw(vd
)) {
412 msg_Err(vd
, "cannot initialize DirectX DirectDraw");
416 /* Create the directx display */
417 if (DirectXOpenDisplay(vd
)) {
418 msg_Err(vd
, "cannot initialize DirectX DirectDraw");
421 UpdateRects(vd
, NULL
, NULL
, true);
423 /* Create the picture pool */
424 if (DirectXCreatePool(vd
, &sys
->use_overlay
, fmt
)) {
425 msg_Err(vd
, "cannot create any DirectX surface");
430 if (sys
->use_overlay
)
431 DirectXUpdateOverlay(vd
, NULL
);
432 EventThreadUseOverlay(sys
->event
, sys
->use_overlay
);
434 /* Change the window title bar text */
435 const char *fallback
;
436 if (sys
->use_overlay
)
437 fallback
= VOUT_TITLE
" (hardware YUV overlay DirectX output)";
438 else if (vlc_fourcc_IsYUV(fmt
->i_chroma
))
439 fallback
= VOUT_TITLE
" (hardware YUV DirectX output)";
441 fallback
= VOUT_TITLE
" (software RGB DirectX output)";
442 EventThreadUpdateTitle(sys
->event
, fallback
);
446 static void DirectXClose(vout_display_t
*vd
)
448 DirectXDestroyPool(vd
);
449 DirectXCloseDisplay(vd
);
450 DirectXCloseDDraw(vd
);
454 static BOOL WINAPI
DirectXOpenDDrawCallback(GUID
*guid
, LPTSTR desc
,
455 LPTSTR drivername
, VOID
*context
,
458 vout_display_t
*vd
= context
;
459 vout_display_sys_t
*sys
= vd
->sys
;
461 /* This callback function is called by DirectDraw once for each
462 * available DirectDraw device.
464 * Returning TRUE keeps enumerating.
469 msg_Dbg(vd
, "DirectXEnumCallback: %s, %s", desc
, drivername
);
471 char *device
= var_GetString(vd
, "directx-device");
473 /* Check for forced device */
474 if (device
&& *device
&& !strcmp(drivername
, device
)) {
475 MONITORINFO monitor_info
;
476 monitor_info
.cbSize
= sizeof(MONITORINFO
);
478 if (sys
->GetMonitorInfo(hmon
, &monitor_info
)) {
481 /* Move window to the right screen */
482 GetWindowRect(sys
->hwnd
, &rect
);
483 if (!IntersectRect(&rect
, &rect
, &monitor_info
.rcWork
)) {
484 rect
.left
= monitor_info
.rcWork
.left
;
485 rect
.top
= monitor_info
.rcWork
.top
;
486 msg_Dbg(vd
, "DirectXEnumCallback: setting window "
487 "position to %ld,%ld", rect
.left
, rect
.top
);
488 SetWindowPos(sys
->hwnd
, NULL
,
489 rect
.left
, rect
.top
, 0, 0,
490 SWP_NOSIZE
| SWP_NOZORDER
| SWP_NOACTIVATE
);
493 sys
->hmonitor
= hmon
;
497 if (hmon
== sys
->hmonitor
) {
498 msg_Dbg(vd
, "selecting %s, %s", desc
, drivername
);
500 free(sys
->display_driver
);
501 sys
->display_driver
= malloc(sizeof(*guid
));
502 if (sys
->display_driver
)
503 *sys
->display_driver
= *guid
;
509 * Probe the capabilities of the hardware
511 * It is nice to know which features are supported by the hardware so we can
512 * find ways to optimize our rendering.
514 static void DirectXGetDDrawCaps(vout_display_t
*vd
)
516 vout_display_sys_t
*sys
= vd
->sys
;
518 /* This is just an indication of whether or not we'll support overlay,
519 * but with this test we don't know if we support YUV overlay */
521 ZeroMemory(&ddcaps
, sizeof(ddcaps
));
522 ddcaps
.dwSize
= sizeof(ddcaps
);
523 HRESULT hr
= IDirectDraw2_GetCaps(sys
->ddobject
, &ddcaps
, NULL
);
525 msg_Warn(vd
, "cannot get caps");
529 /* Determine if the hardware supports overlay surfaces */
530 const bool has_overlay
= ddcaps
.dwCaps
& DDCAPS_OVERLAY
;
531 /* Determine if the hardware supports overlay surfaces */
532 const bool has_overlay_fourcc
= ddcaps
.dwCaps
& DDCAPS_OVERLAYFOURCC
;
533 /* Determine if the hardware supports overlay deinterlacing */
534 const bool can_deinterlace
= ddcaps
.dwCaps
& DDCAPS2_CANFLIPODDEVEN
;
535 /* Determine if the hardware supports colorkeying */
536 const bool has_color_key
= ddcaps
.dwCaps
& DDCAPS_COLORKEY
;
537 /* Determine if the hardware supports scaling of the overlay surface */
538 const bool can_stretch
= ddcaps
.dwCaps
& DDCAPS_OVERLAYSTRETCH
;
539 /* Determine if the hardware supports color conversion during a blit */
540 sys
->can_blit_fourcc
= ddcaps
.dwCaps
& DDCAPS_BLTFOURCC
;
541 /* Determine overlay source boundary alignment */
542 const bool align_boundary_src
= ddcaps
.dwCaps
& DDCAPS_ALIGNBOUNDARYSRC
;
543 /* Determine overlay destination boundary alignment */
544 const bool align_boundary_dest
= ddcaps
.dwCaps
& DDCAPS_ALIGNBOUNDARYDEST
;
545 /* Determine overlay destination size alignment */
546 const bool align_size_src
= ddcaps
.dwCaps
& DDCAPS_ALIGNSIZESRC
;
547 /* Determine overlay destination size alignment */
548 const bool align_size_dest
= ddcaps
.dwCaps
& DDCAPS_ALIGNSIZEDEST
;
550 msg_Dbg(vd
, "DirectDraw Capabilities: overlay=%i yuvoverlay=%i "
551 "can_deinterlace_overlay=%i colorkey=%i stretch=%i "
553 has_overlay
, has_overlay_fourcc
, can_deinterlace
,
554 has_color_key
, can_stretch
, sys
->can_blit_fourcc
);
556 if (align_boundary_src
|| align_boundary_dest
|| align_size_src
|| align_size_dest
) {
557 if (align_boundary_src
)
558 vd
->sys
->i_align_src_boundary
= ddcaps
.dwAlignBoundarySrc
;
559 if (align_boundary_dest
)
560 vd
->sys
->i_align_dest_boundary
= ddcaps
.dwAlignBoundaryDest
;
562 vd
->sys
->i_align_src_size
= ddcaps
.dwAlignSizeSrc
;
564 vd
->sys
->i_align_dest_size
= ddcaps
.dwAlignSizeDest
;
567 "align_boundary_src=%i,%i align_boundary_dest=%i,%i "
568 "align_size_src=%i,%i align_size_dest=%i,%i",
569 align_boundary_src
, vd
->sys
->i_align_src_boundary
,
570 align_boundary_dest
, vd
->sys
->i_align_dest_boundary
,
571 align_size_src
, vd
->sys
->i_align_src_size
,
572 align_size_dest
, vd
->sys
->i_align_dest_size
);
579 static int DirectXOpenDDraw(vout_display_t
*vd
)
581 vout_display_sys_t
*sys
= vd
->sys
;
585 HRESULT (WINAPI
*OurDirectDrawCreate
)(GUID
*,LPDIRECTDRAW
*,IUnknown
*);
586 OurDirectDrawCreate
=
587 (void *)GetProcAddress(sys
->hddraw_dll
, _T("DirectDrawCreate"));
588 if (!OurDirectDrawCreate
) {
589 msg_Err(vd
, "DirectXInitDDraw failed GetProcAddress");
594 if (sys
->MonitorFromWindow
) {
595 HRESULT (WINAPI
*OurDirectDrawEnumerateEx
)(LPDDENUMCALLBACKEXA
, LPVOID
, DWORD
);
596 OurDirectDrawEnumerateEx
=
597 (void *)GetProcAddress(sys
->hddraw_dll
, _T("DirectDrawEnumerateExA"));
599 if (OurDirectDrawEnumerateEx
) {
600 char *device
= var_GetString(vd
, "directx-device");
602 msg_Dbg(vd
, "directx-device: %s", device
);
606 sys
->hmonitor
= sys
->MonitorFromWindow(sys
->hwnd
, MONITOR_DEFAULTTONEAREST
);
608 /* Enumerate displays */
609 OurDirectDrawEnumerateEx(DirectXOpenDDrawCallback
,
610 vd
, DDENUM_ATTACHEDSECONDARYDEVICES
);
614 /* Initialize DirectDraw now */
615 LPDIRECTDRAW ddobject
;
616 hr
= OurDirectDrawCreate(sys
->display_driver
, &ddobject
, NULL
);
618 msg_Err(vd
, "DirectXInitDDraw cannot initialize DDraw");
622 /* Get the IDirectDraw2 interface */
623 hr
= IDirectDraw_QueryInterface(ddobject
, &IID_IDirectDraw2
,
625 /* Release the unused interface */
626 IDirectDraw_Release(ddobject
);
629 msg_Err(vd
, "cannot get IDirectDraw2 interface");
630 sys
->ddobject
= NULL
;
634 /* Set DirectDraw Cooperative level, ie what control we want over Windows
636 hr
= IDirectDraw2_SetCooperativeLevel(sys
->ddobject
, NULL
, DDSCL_NORMAL
);
638 msg_Err(vd
, "cannot set direct draw cooperative level");
642 /* Get the size of the current display device */
643 if (sys
->hmonitor
&& sys
->GetMonitorInfo
) {
644 MONITORINFO monitor_info
;
645 monitor_info
.cbSize
= sizeof(MONITORINFO
);
646 sys
->GetMonitorInfo(vd
->sys
->hmonitor
, &monitor_info
);
647 sys
->rect_display
= monitor_info
.rcMonitor
;
649 sys
->rect_display
.left
= 0;
650 sys
->rect_display
.top
= 0;
651 sys
->rect_display
.right
= GetSystemMetrics(SM_CXSCREEN
);
652 sys
->rect_display
.bottom
= GetSystemMetrics(SM_CYSCREEN
);
655 msg_Dbg(vd
, "screen dimensions (%lix%li,%lix%li)",
656 sys
->rect_display
.left
,
657 sys
->rect_display
.top
,
658 sys
->rect_display
.right
,
659 sys
->rect_display
.bottom
);
661 /* Probe the capabilities of the hardware */
662 DirectXGetDDrawCaps(vd
);
667 static void DirectXCloseDDraw(vout_display_t
*vd
)
669 vout_display_sys_t
*sys
= vd
->sys
;
671 IDirectDraw2_Release(sys
->ddobject
);
673 sys
->ddobject
= NULL
;
675 free(sys
->display_driver
);
676 sys
->display_driver
= NULL
;
678 sys
->hmonitor
= NULL
;
682 * Create a clipper that will be used when blitting the RGB surface to the main display.
684 * This clipper prevents us to modify by mistake anything on the screen
685 * which doesn't belong to our window. For example when a part of our video
686 * window is hidden by another window.
688 static void DirectXCreateClipper(vout_display_t
*vd
)
690 vout_display_sys_t
*sys
= vd
->sys
;
693 /* Create the clipper */
694 hr
= IDirectDraw2_CreateClipper(sys
->ddobject
, 0, &sys
->clipper
, NULL
);
696 msg_Warn(vd
, "cannot create clipper (error %li)", hr
);
700 /* Associate the clipper to the window */
701 hr
= IDirectDrawClipper_SetHWnd(sys
->clipper
, 0, sys
->hvideownd
);
703 msg_Warn(vd
, "cannot attach clipper to window (error %li)", hr
);
707 /* associate the clipper with the surface */
708 hr
= IDirectDrawSurface_SetClipper(sys
->display
, sys
->clipper
);
711 msg_Warn(vd
, "cannot attach clipper to surface (error %li)", hr
);
719 IDirectDrawClipper_Release(sys
->clipper
);
724 * It finds out the 32bits RGB pixel value of the colorkey.
726 static uint32_t DirectXFindColorkey(vout_display_t
*vd
, uint32_t *color
)
728 vout_display_sys_t
*sys
= vd
->sys
;
733 ddsd
.dwSize
= sizeof(ddsd
);
734 hr
= IDirectDrawSurface2_Lock(sys
->display
, NULL
, &ddsd
, DDLOCK_WAIT
, NULL
);
738 uint32_t backup
= *(uint32_t *)ddsd
.lpSurface
;
740 switch (ddsd
.ddpfPixelFormat
.dwRGBBitCount
) {
742 *(uint8_t *)ddsd
.lpSurface
= *color
| (*color
<< 4);
745 *(uint8_t *)ddsd
.lpSurface
= *color
;
749 *(uint16_t *)ddsd
.lpSurface
= *color
;
752 /* Seems to be problematic so we'll just put black as the colorkey */
755 *(uint32_t *)ddsd
.lpSurface
= *color
;
758 IDirectDrawSurface2_Unlock(sys
->display
, NULL
);
763 if (IDirectDrawSurface2_GetDC(sys
->display
, &hdc
) == DD_OK
) {
764 rgb
= GetPixel(hdc
, 0, 0);
765 IDirectDrawSurface2_ReleaseDC(sys
->display
, hdc
);
770 /* Restore the pixel value */
771 ddsd
.dwSize
= sizeof(ddsd
);
772 if (IDirectDrawSurface2_Lock(sys
->display
, NULL
, &ddsd
, DDLOCK_WAIT
, NULL
) == DD_OK
) {
773 *(uint32_t *)ddsd
.lpSurface
= backup
;
774 IDirectDrawSurface2_Unlock(sys
->display
, NULL
);
781 * Create and initialize display according to preferences specified in the vout
784 static int DirectXOpenDisplay(vout_display_t
*vd
)
786 vout_display_sys_t
*sys
= vd
->sys
;
789 /* Now get the primary surface. This surface is what you actually see
792 ZeroMemory(&ddsd
, sizeof(ddsd
));
793 ddsd
.dwSize
= sizeof(ddsd
);
794 ddsd
.dwFlags
= DDSD_CAPS
;
795 ddsd
.ddsCaps
.dwCaps
= DDSCAPS_PRIMARYSURFACE
;
797 LPDIRECTDRAWSURFACE display
;
798 hr
= IDirectDraw2_CreateSurface(sys
->ddobject
, &ddsd
, &display
, NULL
);
800 msg_Err(vd
, "cannot get primary surface (error %li)", hr
);
804 hr
= IDirectDrawSurface_QueryInterface(display
, &IID_IDirectDrawSurface2
,
806 /* Release the old interface */
807 IDirectDrawSurface_Release(display
);
810 msg_Err(vd
, "cannot query IDirectDrawSurface2 interface (error %li)", hr
);
815 /* The clipper will be used only in non-overlay mode */
816 DirectXCreateClipper(vd
);
818 /* Make sure the colorkey will be painted */
820 sys
->i_rgb_colorkey
= DirectXFindColorkey(vd
, &sys
->i_colorkey
);
824 static void DirectXCloseDisplay(vout_display_t
*vd
)
826 vout_display_sys_t
*sys
= vd
->sys
;
828 if (sys
->clipper
!= NULL
)
829 IDirectDrawClipper_Release(sys
->clipper
);
831 if (sys
->display
!= NULL
)
832 IDirectDrawSurface2_Release(sys
->display
);
839 * Create an YUV overlay or RGB surface for the video.
841 * The best method of display is with an YUV overlay because the YUV->RGB
842 * conversion is done in hardware.
843 * You can also create a plain RGB surface.
844 * (Maybe we could also try an RGB overlay surface, which could have hardware
845 * scaling and which would also be faster in window mode because you don't
846 * need to do any blitting to the main display...)
848 static int DirectXCreateSurface(vout_display_t
*vd
,
849 LPDIRECTDRAWSURFACE2
*surface
,
850 const video_format_t
*fmt
,
854 int backbuffer_count
)
856 vout_display_sys_t
*sys
= vd
->sys
;
860 ZeroMemory(&ddsd
, sizeof(ddsd
));
861 ddsd
.dwSize
= sizeof(ddsd
);
862 ddsd
.ddpfPixelFormat
.dwSize
= sizeof(ddsd
.ddpfPixelFormat
);
863 ddsd
.dwFlags
= DDSD_HEIGHT
| DDSD_WIDTH
;
864 ddsd
.dwWidth
= fmt
->i_width
;
865 ddsd
.dwHeight
= fmt
->i_height
;
867 ddsd
.dwFlags
|= DDSD_PIXELFORMAT
;
868 ddsd
.ddpfPixelFormat
.dwFlags
= DDPF_FOURCC
;
869 ddsd
.ddpfPixelFormat
.dwFourCC
= fourcc
;
872 ddsd
.dwFlags
|= DDSD_CAPS
;
873 ddsd
.ddsCaps
.dwCaps
= DDSCAPS_OVERLAY
| DDSCAPS_VIDEOMEMORY
;
874 if (backbuffer_count
> 0)
875 ddsd
.ddsCaps
.dwCaps
|= DDSCAPS_COMPLEX
| DDSCAPS_FLIP
;
877 if (backbuffer_count
> 0) {
878 ddsd
.dwFlags
|= DDSD_BACKBUFFERCOUNT
;
879 ddsd
.dwBackBufferCount
= backbuffer_count
;
882 ddsd
.dwFlags
|= DDSD_CAPS
;
883 ddsd
.ddsCaps
.dwCaps
= DDSCAPS_OFFSCREENPLAIN
;
885 ddsd
.ddsCaps
.dwCaps
|= DDSCAPS_SYSTEMMEMORY
;
887 ddsd
.ddsCaps
.dwCaps
|= DDSCAPS_VIDEOMEMORY
;
890 /* Create the video surface */
891 LPDIRECTDRAWSURFACE surface_v1
;
892 if (IDirectDraw2_CreateSurface(sys
->ddobject
, &ddsd
, &surface_v1
, NULL
) != DD_OK
)
895 /* Now that the surface is created, try to get a newer DirectX interface */
896 HRESULT hr
= IDirectDrawSurface_QueryInterface(surface_v1
,
897 &IID_IDirectDrawSurface2
,
899 IDirectDrawSurface_Release(surface_v1
);
901 msg_Err(vd
, "cannot query IDirectDrawSurface2 interface (error %li)", hr
);
906 /* Check the overlay is useable as some graphics cards allow creating
907 * several overlays but only one can be used at one time. */
908 if (DirectXUpdateOverlay(vd
, *surface
)) {
909 IDirectDrawSurface2_Release(*surface
);
910 msg_Err(vd
, "overlay unuseable (might already be in use)");
918 static void DirectXDestroySurface(LPDIRECTDRAWSURFACE2 surface
)
920 IDirectDrawSurface2_Release(surface
);
923 * This function locks a surface and get the surface descriptor.
925 static int DirectXLockSurface(LPDIRECTDRAWSURFACE2 front_surface
,
926 LPDIRECTDRAWSURFACE2 surface
,
931 DDSURFACEDESC ddsd_dummy
;
935 ZeroMemory(ddsd
, sizeof(*ddsd
));
936 ddsd
->dwSize
= sizeof(*ddsd
);
937 hr
= IDirectDrawSurface2_Lock(surface
, NULL
, ddsd
, DDLOCK_NOSYSLOCK
| DDLOCK_WAIT
, NULL
);
939 if (hr
== DDERR_INVALIDPARAMS
) {
940 /* DirectX 3 doesn't support the DDLOCK_NOSYSLOCK flag, resulting
941 * in an invalid params error */
942 hr
= IDirectDrawSurface2_Lock(surface
, NULL
, ddsd
, DDLOCK_WAIT
, NULL
);
944 if (hr
== DDERR_SURFACELOST
) {
945 /* Your surface can be lost so be sure
946 * to check this and restore it if needed */
948 /* When using overlays with back-buffers, we need to restore
949 * the front buffer so the back-buffers get restored as well. */
950 if (front_surface
!= surface
)
951 IDirectDrawSurface2_Restore(front_surface
);
953 IDirectDrawSurface2_Restore(surface
);
955 hr
= IDirectDrawSurface2_Lock(surface
, NULL
, ddsd
, DDLOCK_WAIT
, NULL
);
962 static void DirectXUnlockSurface(LPDIRECTDRAWSURFACE2 front_surface
,
963 LPDIRECTDRAWSURFACE2 surface
)
965 IDirectDrawSurface2_Unlock(surface
, NULL
);
967 static int DirectXCheckLockingSurface(LPDIRECTDRAWSURFACE2 front_surface
,
968 LPDIRECTDRAWSURFACE2 surface
)
970 if (DirectXLockSurface(front_surface
, surface
, NULL
))
973 DirectXUnlockSurface(front_surface
, surface
);
984 static DWORD
DirectXGetFourcc(vlc_fourcc_t codec
)
986 static const dx_format_t dx_formats
[] = {
987 { VLC_CODEC_YUYV
, MAKEFOURCC('Y','U','Y','2') },
988 { VLC_CODEC_UYVY
, MAKEFOURCC('U','Y','V','Y') },
989 { VLC_CODEC_YVYU
, MAKEFOURCC('Y','V','Y','U') },
990 { VLC_CODEC_YV12
, MAKEFOURCC('Y','V','1','2') },
991 { VLC_CODEC_I420
, MAKEFOURCC('Y','V','1','2') },
992 { VLC_CODEC_J420
, MAKEFOURCC('Y','V','1','2') },
996 for (unsigned i
= 0; dx_formats
[i
].codec
!= 0; i
++) {
997 if (dx_formats
[i
].codec
== codec
)
998 return dx_formats
[i
].fourcc
;
1003 static int DirectXCreatePictureResourceYuvOverlay(vout_display_t
*vd
,
1004 const video_format_t
*fmt
,
1007 vout_display_sys_t
*sys
= vd
->sys
;
1009 bool allow_3buf
= var_InheritBool(vd
, "directx-3buffering");
1011 /* The overlay surface that we create won't be used to decode directly
1012 * into it because accessing video memory directly is way to slow (remember
1013 * that pictures are decoded macroblock per macroblock). Instead the video
1014 * will be decoded in picture buffers in system memory which will then be
1015 * memcpy() to the overlay surface. */
1016 LPDIRECTDRAWSURFACE2 front_surface
;
1017 int ret
= VLC_EGENERIC
;
1019 /* Triple buffering rocks! it doesn't have any processing overhead
1020 * (you don't have to wait for the vsync) and provides for a very nice
1021 * video quality (no tearing). */
1022 ret
= DirectXCreateSurface(vd
, &front_surface
, fmt
, fourcc
, true, false, 2);
1025 ret
= DirectXCreateSurface(vd
, &front_surface
, fmt
, fourcc
, true, false, 0);
1027 return VLC_EGENERIC
;
1028 msg_Dbg(vd
, "YUV overlay surface created successfully");
1030 /* Get the back buffer */
1031 LPDIRECTDRAWSURFACE2 surface
;
1033 ZeroMemory(&dds_caps
, sizeof(dds_caps
));
1034 dds_caps
.dwCaps
= DDSCAPS_BACKBUFFER
;
1035 if (IDirectDrawSurface2_GetAttachedSurface(front_surface
, &dds_caps
, &surface
) != DD_OK
) {
1036 msg_Warn(vd
, "Failed to get surface back buffer");
1037 /* front buffer is the same as back buffer */
1038 surface
= front_surface
;
1041 if (DirectXCheckLockingSurface(front_surface
, surface
)) {
1042 DirectXDestroySurface(front_surface
);
1043 return VLC_EGENERIC
;
1047 picture_resource_t
*rsc
= &sys
->resource
;
1048 rsc
->p_sys
->front_surface
= front_surface
;
1049 rsc
->p_sys
->surface
= surface
;
1050 rsc
->p_sys
->fallback
= NULL
;
1053 static int DirectXCreatePictureResourceYuv(vout_display_t
*vd
,
1054 const video_format_t
*fmt
,
1057 vout_display_sys_t
*sys
= vd
->sys
;
1059 bool allow_sysmem
= var_InheritBool(vd
, "directx-use-sysmem");
1061 /* As we can't have an overlay, we'll try to create a plain offscreen
1062 * surface. This surface will reside in video memory because there's a
1063 * better chance then that we'll be able to use some kind of hardware
1064 * acceleration like rescaling, blitting or YUV->RGB conversions.
1065 * We then only need to blit this surface onto the main display when we
1066 * want to display it */
1068 /* Check if the chroma is supported first. This is required
1069 * because a few buggy drivers don't mind creating the surface
1070 * even if they don't know about the chroma. */
1072 if (IDirectDraw2_GetFourCCCodes(sys
->ddobject
, &count
, NULL
) != DD_OK
)
1073 return VLC_EGENERIC
;
1075 DWORD
*list
= calloc(count
, sizeof(*list
));
1078 if (IDirectDraw2_GetFourCCCodes(sys
->ddobject
, &count
, list
) != DD_OK
) {
1080 return VLC_EGENERIC
;
1083 for (index
= 0; index
< count
; index
++) {
1084 if (list
[index
] == fourcc
)
1089 return VLC_EGENERIC
;
1092 LPDIRECTDRAWSURFACE2 surface
;
1093 if (DirectXCreateSurface(vd
, &surface
, fmt
, fourcc
, false, allow_sysmem
, 0))
1094 return VLC_EGENERIC
;
1095 msg_Dbg(vd
, "YUV plain surface created successfully");
1097 if (DirectXCheckLockingSurface(surface
, surface
)) {
1098 DirectXDestroySurface(surface
);
1099 return VLC_EGENERIC
;
1103 picture_resource_t
*rsc
= &sys
->resource
;
1104 rsc
->p_sys
->front_surface
= surface
;
1105 rsc
->p_sys
->surface
= surface
;
1106 rsc
->p_sys
->fallback
= NULL
;
1109 static int DirectXCreatePictureResourceRgb(vout_display_t
*vd
,
1110 video_format_t
*fmt
)
1112 vout_display_sys_t
*sys
= vd
->sys
;
1113 bool allow_sysmem
= var_InheritBool(vd
, "directx-use-sysmem");
1115 /* Our last choice is to use a plain RGB surface */
1116 DDPIXELFORMAT ddpfPixelFormat
;
1117 ZeroMemory(&ddpfPixelFormat
, sizeof(ddpfPixelFormat
));
1118 ddpfPixelFormat
.dwSize
= sizeof(ddpfPixelFormat
);
1120 IDirectDrawSurface2_GetPixelFormat(sys
->display
, &ddpfPixelFormat
);
1121 if ((ddpfPixelFormat
.dwFlags
& DDPF_RGB
) == 0)
1122 return VLC_EGENERIC
;
1124 switch (ddpfPixelFormat
.dwRGBBitCount
) {
1126 fmt
->i_chroma
= VLC_CODEC_RGB8
;
1129 fmt
->i_chroma
= VLC_CODEC_RGB15
;
1132 fmt
->i_chroma
= VLC_CODEC_RGB16
;
1135 fmt
->i_chroma
= VLC_CODEC_RGB24
;
1138 fmt
->i_chroma
= VLC_CODEC_RGB32
;
1141 msg_Err(vd
, "unknown screen depth");
1142 return VLC_EGENERIC
;
1144 fmt
->i_rmask
= ddpfPixelFormat
.dwRBitMask
;
1145 fmt
->i_gmask
= ddpfPixelFormat
.dwGBitMask
;
1146 fmt
->i_bmask
= ddpfPixelFormat
.dwBBitMask
;
1149 LPDIRECTDRAWSURFACE2 surface
;
1150 int ret
= DirectXCreateSurface(vd
, &surface
, fmt
, 0, false, allow_sysmem
, 0);
1151 if (ret
&& !allow_sysmem
)
1152 ret
= DirectXCreateSurface(vd
, &surface
, fmt
, 0, false, true, 0);
1154 return VLC_EGENERIC
;
1155 msg_Dbg(vd
, "RGB plain surface created successfully");
1157 if (DirectXCheckLockingSurface(surface
, surface
)) {
1158 DirectXDestroySurface(surface
);
1159 return VLC_EGENERIC
;
1163 picture_resource_t
*rsc
= &sys
->resource
;
1164 rsc
->p_sys
->front_surface
= surface
;
1165 rsc
->p_sys
->surface
= surface
;
1166 rsc
->p_sys
->fallback
= NULL
;
1170 static int DirectXCreatePictureResource(vout_display_t
*vd
,
1172 video_format_t
*fmt
)
1174 vout_display_sys_t
*sys
= vd
->sys
;
1177 picture_resource_t
*rsc
= &sys
->resource
;
1178 rsc
->p_sys
= calloc(1, sizeof(*rsc
->p_sys
));
1183 bool allow_hw_yuv
= sys
->can_blit_fourcc
&&
1184 vlc_fourcc_IsYUV(fmt
->i_chroma
) &&
1185 var_InheritBool(vd
, "directx-hw-yuv");
1186 bool allow_overlay
= var_InheritBool(vd
, "overlay");
1188 /* Try to use an yuv surface */
1190 const vlc_fourcc_t
*list
= vlc_fourcc_GetYUVFallback(fmt
->i_chroma
);
1191 /* Try with overlay first */
1192 for (unsigned pass
= allow_overlay
? 0 : 1; pass
< 2; pass
++) {
1193 for (unsigned i
= 0; list
[i
] != 0; i
++) {
1194 const DWORD fourcc
= DirectXGetFourcc(list
[i
]);
1199 if (DirectXCreatePictureResourceYuvOverlay(vd
, fmt
, fourcc
))
1202 if (DirectXCreatePictureResourceYuv(vd
, fmt
, fourcc
))
1206 *use_overlay
= pass
== 0;
1207 fmt
->i_chroma
= list
[i
];
1214 return DirectXCreatePictureResourceRgb(vd
, fmt
);
1216 static void DirectXDestroyPictureResource(vout_display_t
*vd
)
1218 vout_display_sys_t
*sys
= vd
->sys
;
1220 if (sys
->resource
.p_sys
->front_surface
!= sys
->resource
.p_sys
->surface
)
1221 DirectXDestroySurface(sys
->resource
.p_sys
->surface
);
1222 DirectXDestroySurface(sys
->resource
.p_sys
->front_surface
);
1223 if (sys
->resource
.p_sys
->fallback
)
1224 picture_Release(sys
->resource
.p_sys
->fallback
);
1227 static int DirectXLock(picture_t
*picture
)
1230 if (DirectXLockSurface(picture
->p_sys
->front_surface
,
1231 picture
->p_sys
->surface
, &ddsd
))
1232 return CommonUpdatePicture(picture
, &picture
->p_sys
->fallback
, NULL
, 0);
1234 CommonUpdatePicture(picture
, NULL
, ddsd
.lpSurface
, ddsd
.lPitch
);
1237 static void DirectXUnlock(picture_t
*picture
)
1239 DirectXUnlockSurface(picture
->p_sys
->front_surface
,
1240 picture
->p_sys
->surface
);
1243 static int DirectXCreatePool(vout_display_t
*vd
,
1244 bool *use_overlay
, video_format_t
*fmt
)
1246 vout_display_sys_t
*sys
= vd
->sys
;
1251 if (DirectXCreatePictureResource(vd
, use_overlay
, fmt
))
1252 return VLC_EGENERIC
;
1254 /* Create the associated picture */
1255 picture_resource_t
*rsc
= &sys
->resource
;
1256 for (int i
= 0; i
< PICTURE_PLANE_MAX
; i
++) {
1257 rsc
->p
[i
].p_pixels
= NULL
;
1258 rsc
->p
[i
].i_pitch
= 0;
1259 rsc
->p
[i
].i_lines
= 0;
1261 picture_t
*picture
= picture_NewFromResource(fmt
, rsc
);
1263 DirectXDestroyPictureResource(vd
);
1268 /* Wrap it into a picture pool */
1269 picture_pool_configuration_t cfg
;
1270 memset(&cfg
, 0, sizeof(cfg
));
1271 cfg
.picture_count
= 1;
1272 cfg
.picture
= &picture
;
1273 cfg
.lock
= DirectXLock
;
1274 cfg
.unlock
= DirectXUnlock
;
1276 sys
->pool
= picture_pool_NewExtended(&cfg
);
1278 picture_Release(picture
);
1279 DirectXDestroyPictureResource(vd
);
1284 static void DirectXDestroyPool(vout_display_t
*vd
)
1286 vout_display_sys_t
*sys
= vd
->sys
;
1289 DirectXDestroyPictureResource(vd
);
1290 picture_pool_Delete(sys
->pool
);
1296 * Move or resize overlay surface on video display.
1298 * This function is used to move or resize an overlay surface on the screen.
1299 * Ususally the overlay is moved by the user and thus, by a move or resize
1302 static int DirectXUpdateOverlay(vout_display_t
*vd
, LPDIRECTDRAWSURFACE2 surface
)
1304 vout_display_sys_t
*sys
= vd
->sys
;
1306 RECT src
= sys
->rect_src_clipped
;
1307 RECT dst
= sys
->rect_dest_clipped
;
1309 if (sys
->use_wallpaper
) {
1310 src
.left
= vd
->source
.i_x_offset
;
1311 src
.top
= vd
->source
.i_y_offset
;
1312 src
.right
= vd
->source
.i_x_offset
+ vd
->source
.i_visible_width
;
1313 src
.bottom
= vd
->source
.i_y_offset
+ vd
->source
.i_visible_height
;
1314 AlignRect(&src
, sys
->i_align_src_boundary
, sys
->i_align_src_size
);
1316 vout_display_cfg_t cfg
= *vd
->cfg
;
1317 cfg
.display
.width
= sys
->rect_display
.right
;
1318 cfg
.display
.height
= sys
->rect_display
.bottom
;
1320 vout_display_place_t place
;
1321 vout_display_PlacePicture(&place
, &vd
->source
, &cfg
, true);
1323 dst
.left
= sys
->rect_display
.left
+ place
.x
;
1324 dst
.top
= sys
->rect_display
.top
+ place
.y
;
1325 dst
.right
= dst
.left
+ place
.width
;
1326 dst
.bottom
= dst
.top
+ place
.height
;
1327 AlignRect(&dst
, sys
->i_align_dest_boundary
, sys
->i_align_dest_size
);
1332 return VLC_EGENERIC
;
1333 surface
= sys
->resource
.p_sys
->front_surface
;
1336 /* The new window dimensions should already have been computed by the
1337 * caller of this function */
1339 /* Position and show the overlay */
1341 ZeroMemory(&ddofx
, sizeof(ddofx
));
1342 ddofx
.dwSize
= sizeof(ddofx
);
1343 ddofx
.dckDestColorkey
.dwColorSpaceLowValue
= sys
->i_colorkey
;
1344 ddofx
.dckDestColorkey
.dwColorSpaceHighValue
= sys
->i_colorkey
;
1346 HRESULT hr
= IDirectDrawSurface2_UpdateOverlay(surface
,
1347 &src
, sys
->display
, &dst
,
1348 DDOVER_SHOW
| DDOVER_KEYDESTOVERRIDE
, &ddofx
);
1349 sys
->restore_overlay
= hr
!= DD_OK
;
1352 msg_Warn(vd
, "DirectDrawUpdateOverlay cannot move/resize overlay");
1353 return VLC_EGENERIC
;
1359 static void WallpaperChange(vout_display_t
*vd
, bool use_wallpaper
)
1361 vout_display_sys_t
*sys
= vd
->sys
;
1363 if (!sys
->use_wallpaper
== !use_wallpaper
)
1366 HWND hwnd
= FindWindow(_T("Progman"), NULL
);
1368 hwnd
= FindWindowEx(hwnd
, NULL
, _T("SHELLDLL_DefView"), NULL
);
1370 hwnd
= FindWindowEx(hwnd
, NULL
, _T("SysListView32"), NULL
);
1372 msg_Warn(vd
, "couldn't find \"SysListView32\" window, "
1373 "wallpaper mode not supported");
1377 msg_Dbg(vd
, "wallpaper mode %s", use_wallpaper
? "enabled" : "disabled");
1378 sys
->use_wallpaper
= use_wallpaper
;
1380 if (sys
->use_wallpaper
) {
1381 sys
->color_bkg
= ListView_GetBkColor(hwnd
);
1382 sys
->color_bkgtxt
= ListView_GetTextBkColor(hwnd
);
1384 ListView_SetBkColor(hwnd
, sys
->i_rgb_colorkey
);
1385 ListView_SetTextBkColor(hwnd
, sys
->i_rgb_colorkey
);
1387 ListView_SetBkColor(hwnd
, sys
->color_bkg
);
1388 ListView_SetTextBkColor(hwnd
, sys
->color_bkgtxt
);
1391 /* Update desktop */
1392 InvalidateRect(hwnd
, NULL
, TRUE
);
1395 if (sys
->use_overlay
)
1396 DirectXUpdateOverlay(vd
, NULL
);
1400 static int WallpaperCallback(vlc_object_t
*object
, char const *cmd
,
1401 vlc_value_t oldval
, vlc_value_t newval
, void *data
)
1403 vout_display_t
*vd
= (vout_display_t
*)object
;
1404 vout_display_sys_t
*sys
= vd
->sys
;
1405 VLC_UNUSED(cmd
); VLC_UNUSED(oldval
); VLC_UNUSED(data
);
1407 vlc_mutex_lock(&sys
->lock
);
1408 const bool ch_wallpaper
= !sys
->wallpaper_requested
!= !newval
.b_bool
;
1409 sys
->ch_wallpaper
|= ch_wallpaper
;
1410 sys
->wallpaper_requested
= newval
.b_bool
;
1411 vlc_mutex_unlock(&sys
->lock
);
1413 /* FIXME we should have a way to export variable to be saved */
1415 playlist_t
*p_playlist
= pl_Get(vd
);
1416 /* Modify playlist as well because the vout might have to be
1418 var_Create(p_playlist
, "video-wallpaper", VLC_VAR_BOOL
);
1419 var_SetBool(p_playlist
, "video-wallpaper", newval
.b_bool
);
1424 /*****************************************************************************
1425 * config variable callback
1426 *****************************************************************************/
1427 static BOOL WINAPI
DirectXEnumCallback2(GUID
*guid
, LPTSTR desc
,
1428 LPTSTR drivername
, VOID
*context
,
1431 VLC_UNUSED(guid
); VLC_UNUSED(desc
); VLC_UNUSED(hmon
);
1433 module_config_t
*item
= context
;
1435 item
->ppsz_list
= xrealloc(item
->ppsz_list
,
1436 (item
->i_list
+2) * sizeof(char *));
1437 item
->ppsz_list_text
= xrealloc(item
->ppsz_list_text
,
1438 (item
->i_list
+2) * sizeof(char *));
1440 item
->ppsz_list
[item
->i_list
] = strdup(drivername
);
1441 item
->ppsz_list_text
[item
->i_list
] = NULL
;
1443 item
->ppsz_list
[item
->i_list
] = NULL
;
1444 item
->ppsz_list_text
[item
->i_list
] = NULL
;
1446 return TRUE
; /* Keep enumerating */
1449 static int FindDevicesCallback(vlc_object_t
*object
, char const *name
,
1450 vlc_value_t newval
, vlc_value_t oldval
, void *data
)
1452 VLC_UNUSED(newval
); VLC_UNUSED(oldval
); VLC_UNUSED(data
);
1454 module_config_t
*item
= config_FindConfig(object
, name
);
1458 /* Clear-up the current list */
1459 if (item
->i_list
> 0) {
1461 /* Keep the first entry */
1462 for (i
= 1; i
< item
->i_list
; i
++) {
1463 free(item
->ppsz_list
[i
]);
1464 free(item
->ppsz_list_text
[i
]);
1466 /* TODO: Remove when no more needed */
1467 item
->ppsz_list
[i
] = NULL
;
1468 item
->ppsz_list_text
[i
] = NULL
;
1472 /* Load direct draw DLL */
1473 HINSTANCE hddraw_dll
= LoadLibrary(_T("DDRAW.DLL"));
1477 /* Enumerate displays */
1478 HRESULT (WINAPI
*OurDirectDrawEnumerateEx
)(LPDDENUMCALLBACKEXA
,
1480 (void *)GetProcAddress(hddraw_dll
, _T("DirectDrawEnumerateExA"));
1481 if (OurDirectDrawEnumerateEx
)
1482 OurDirectDrawEnumerateEx(DirectXEnumCallback2
, item
,
1483 DDENUM_ATTACHEDSECONDARYDEVICES
);
1485 FreeLibrary(hddraw_dll
);
1487 /* Signal change to the interface */
1488 item
->b_dirty
= true;