1 /*****************************************************************************
2 * directdraw.c: Windows DirectDraw video output
3 *****************************************************************************
4 * Copyright (C) 2001-2009 VLC authors and VideoLAN
7 * Authors: Gildas Bazin <gbazin@videolan.org>
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU Lesser General Public License as published by
11 * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this program; if not, write to the Free Software Foundation,
21 * 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 *****************************************************************************/
44 #include <vlc_common.h>
45 #include <vlc_plugin.h>
46 #include <vlc_vout_display.h>
47 #include <vlc_charset.h> /* FromT */
51 #include <commctrl.h> /* ListView_(Get|Set)* */
55 /* Unicode function "DirectDrawEnumerateExW" has been desactivated
56 since in some cases this function fails and the callbacks are not
57 called. If the Unicode mode is restored, one should modify the
58 prototype of the callbacks and call the FromT conversion function.
60 #define DIRECTDRAWENUMERATEEX_NAME "DirectDrawEnumerateExA"
62 /*****************************************************************************
64 *****************************************************************************/
65 #define HW_YUV_TEXT N_("Use hardware YUV->RGB conversions")
66 #define HW_YUV_LONGTEXT N_(\
67 "Try to use hardware acceleration for YUV->RGB conversions. " \
68 "This option doesn't have any effect when using overlays.")
70 #define OVERLAY_TEXT N_("Overlay video output")
71 #define OVERLAY_LONGTEXT N_(\
72 "Overlay is the hardware acceleration capability of your video card " \
73 "(ability to render video directly). VLC will try to use it by default.")
75 #define SYSMEM_TEXT N_("Use video buffers in system memory")
76 #define SYSMEM_LONGTEXT N_(\
77 "Create video buffers in system memory instead of video memory. This " \
78 "isn't recommended as usually using video memory allows benefiting from " \
79 "more hardware acceleration (like rescaling or YUV->RGB conversions). " \
80 "This option doesn't have any effect when using overlays.")
82 #define TRIPLEBUF_TEXT N_("Use triple buffering for overlays")
83 #define TRIPLEBUF_LONGTEXT N_(\
84 "Try to use triple buffering when using YUV overlays. That results in " \
85 "much better video quality (no flickering).")
87 #define DEVICE_TEXT N_("Name of desired display device")
88 #define DEVICE_LONGTEXT N_("In a multiple monitor configuration, you can " \
89 "specify the Windows device name of the display that you want the video " \
90 "window to open on. For example, \"\\\\.\\DISPLAY1\" or " \
91 "\"\\\\.\\DISPLAY2\".")
93 #define DX_HELP N_("Recommended video output for Windows XP. " \
94 "Incompatible with Vista's Aero interface" )
96 static int Open (vlc_object_t
*);
97 static void Close(vlc_object_t
*);
99 static int FindDevicesCallback(vlc_object_t
*, const char *,
102 set_shortname("DirectDraw")
103 set_description(N_("DirectX (DirectDraw) video output"))
105 set_category(CAT_VIDEO
)
106 set_subcategory(SUBCAT_VIDEO_VOUT
)
107 add_bool("directx-hw-yuv", true, HW_YUV_TEXT
, HW_YUV_LONGTEXT
,
109 add_bool("directx-overlay", true, OVERLAY_TEXT
, OVERLAY_LONGTEXT
, false)
110 add_bool("directx-use-sysmem", false, SYSMEM_TEXT
, SYSMEM_LONGTEXT
,
112 add_bool("directx-3buffering", true, TRIPLEBUF_TEXT
,
113 TRIPLEBUF_LONGTEXT
, true)
114 add_string("directx-device", "", DEVICE_TEXT
, DEVICE_LONGTEXT
, true)
115 change_string_cb(FindDevicesCallback
)
117 set_capability("vout display", 230)
118 add_shortcut("directx", "directdraw")
119 set_callbacks(Open
, Close
)
122 /*****************************************************************************
124 *****************************************************************************/
126 struct picture_sys_t
{
127 LPDIRECTDRAWSURFACE2 surface
;
128 LPDIRECTDRAWSURFACE2 front_surface
;
132 /*****************************************************************************
134 * Defining them here allows us to get rid of the dxguid library during
136 *****************************************************************************/
137 #include <initguid.h>
140 DEFINE_GUID(IID_IDirectDraw2
, 0xB3A6F3E0,0x2B43,0x11CF,0xA2,0xDE,0x00,0xAA,0x00,0xB9,0x33,0x56);
141 DEFINE_GUID(IID_IDirectDrawSurface2
, 0x57805885,0x6eec,0x11cf,0x94,0x41,0xa8,0x23,0x03,0xc1,0x0e,0x27);
143 static picture_pool_t
*Pool (vout_display_t
*, unsigned);
144 static void Display(vout_display_t
*, picture_t
*, subpicture_t
*);
145 static int Control(vout_display_t
*, int, va_list);
146 static void Manage (vout_display_t
*);
149 static int WallpaperCallback(vlc_object_t
*, char const *,
150 vlc_value_t
, vlc_value_t
, void *);
152 static int DirectXOpen(vout_display_t
*, video_format_t
*fmt
);
153 static void DirectXClose(vout_display_t
*);
155 static int DirectXLock(picture_t
*);
156 static void DirectXUnlock(picture_t
*);
158 static int DirectXUpdateOverlay(vout_display_t
*, LPDIRECTDRAWSURFACE2 surface
);
160 static void WallpaperChange(vout_display_t
*vd
, bool use_wallpaper
);
162 /** This function allocates and initialize the DirectX vout display.
164 static int Open(vlc_object_t
*object
)
166 vout_display_t
*vd
= (vout_display_t
*)object
;
167 vout_display_sys_t
*sys
;
169 /* Allocate structure */
170 vd
->sys
= sys
= calloc(1, sizeof(*sys
));
174 /* Load direct draw DLL */
175 sys
->hddraw_dll
= LoadLibrary(_T("DDRAW.DLL"));
176 if (!sys
->hddraw_dll
) {
177 msg_Warn(vd
, "DirectXInitDDraw failed loading ddraw.dll");
183 sys
->use_wallpaper
= var_CreateGetBool(vd
, "video-wallpaper");
185 sys
->use_overlay
= false;//var_CreateGetBool(vd, "overlay"); /* FIXME */
186 sys
->restore_overlay
= false;
187 var_Create(vd
, "directx-device", VLC_VAR_STRING
| VLC_VAR_DOINHERIT
);
194 video_format_t fmt
= vd
->fmt
;
196 if (DirectXOpen(vd
, &fmt
))
200 vout_display_info_t info
= vd
->info
;
202 info
.has_double_click
= true;
203 info
.has_hide_mouse
= false;
204 info
.has_pictures_invalid
= true;
205 info
.has_event_thread
= true;
207 /* Interaction TODO support starting with wallpaper mode */
208 vlc_mutex_init(&sys
->lock
);
209 sys
->ch_wallpaper
= sys
->use_wallpaper
;
210 sys
->wallpaper_requested
= sys
->use_wallpaper
;
211 sys
->use_wallpaper
= false;
214 val
.psz_string
= _("Wallpaper");
215 var_Change(vd
, "video-wallpaper", VLC_VAR_SETTEXT
, &val
, NULL
);
216 var_AddCallback(vd
, "video-wallpaper", WallpaperCallback
, NULL
);
218 /* Setup vout_display now that everything is fine */
219 video_format_Clean(&vd
->fmt
);
220 video_format_Copy(&vd
->fmt
, &fmt
);
225 vd
->display
= Display
;
226 vd
->control
= Control
;
234 FreeLibrary(sys
->hddraw_dll
);
239 /** Terminate a vout display created by Open.
241 static void Close(vlc_object_t
*object
)
243 vout_display_t
*vd
= (vout_display_t
*)object
;
244 vout_display_sys_t
*sys
= vd
->sys
;
246 var_DelCallback(vd
, "video-wallpaper", WallpaperCallback
, NULL
);
247 vlc_mutex_destroy(&sys
->lock
);
249 /* Make sure the wallpaper is restored */
250 WallpaperChange(vd
, false);
257 FreeLibrary(sys
->hddraw_dll
);
261 static picture_pool_t
*Pool(vout_display_t
*vd
, unsigned count
)
264 return vd
->sys
->pool
;
266 static void Display(vout_display_t
*vd
, picture_t
*picture
, subpicture_t
*subpicture
)
268 vout_display_sys_t
*sys
= vd
->sys
;
270 assert(sys
->display
);
272 /* Our surface can be lost so be sure to check this
273 * and restore it if need be */
274 if (IDirectDrawSurface2_IsLost(sys
->display
) == DDERR_SURFACELOST
) {
275 if (IDirectDrawSurface2_Restore(sys
->display
) == DD_OK
) {
276 if (sys
->use_overlay
)
277 DirectXUpdateOverlay(vd
, NULL
);
280 if (sys
->restore_overlay
)
281 DirectXUpdateOverlay(vd
, NULL
);
284 DirectXUnlock(picture
);
286 if (sys
->use_overlay
) {
287 /* Flip the overlay buffers if we are using back buffers */
288 if (picture
->p_sys
->surface
!= picture
->p_sys
->front_surface
) {
289 HRESULT hr
= IDirectDrawSurface2_Flip(picture
->p_sys
->front_surface
,
292 msg_Warn(vd
, "could not flip overlay (error %li)", hr
);
295 /* Blit video surface to display with the NOTEARING option */
297 ZeroMemory(&ddbltfx
, sizeof(ddbltfx
));
298 ddbltfx
.dwSize
= sizeof(ddbltfx
);
299 ddbltfx
.dwDDFX
= DDBLTFX_NOTEARING
;
301 HRESULT hr
= IDirectDrawSurface2_Blt(sys
->display
,
302 &sys
->rect_dest_clipped
,
303 picture
->p_sys
->surface
,
304 &sys
->rect_src_clipped
,
305 DDBLT_ASYNC
, &ddbltfx
);
307 msg_Warn(vd
, "could not blit surface (error %li)", hr
);
309 DirectXLock(picture
);
311 if (sys
->is_first_display
) {
312 IDirectDraw_WaitForVerticalBlank(sys
->ddobject
,
313 DDWAITVB_BLOCKBEGIN
, NULL
);
314 if (sys
->use_overlay
) {
315 HBRUSH brush
= CreateSolidBrush(sys
->i_rgb_colorkey
);
316 /* set the colorkey as the backgound brush for the video window */
317 SetClassLongPtr(sys
->hvideownd
, GCLP_HBRBACKGROUND
, (LONG_PTR
)brush
);
322 picture_Release(picture
);
323 VLC_UNUSED(subpicture
);
325 static int Control(vout_display_t
*vd
, int query
, va_list args
)
327 vout_display_sys_t
*sys
= vd
->sys
;
330 case VOUT_DISPLAY_RESET_PICTURES
:
332 /* Make sure the wallpaper is restored */
333 if (sys
->use_wallpaper
) {
334 vlc_mutex_lock(&sys
->lock
);
335 if (!sys
->ch_wallpaper
) {
336 sys
->ch_wallpaper
= true;
337 sys
->wallpaper_requested
= true;
339 vlc_mutex_unlock(&sys
->lock
);
341 WallpaperChange(vd
, false);
343 return DirectXOpen(vd
, &vd
->fmt
);
345 return CommonControl(vd
, query
, args
);
348 static void Manage(vout_display_t
*vd
)
350 vout_display_sys_t
*sys
= vd
->sys
;
354 if (sys
->changes
& DX_POSITION_CHANGE
) {
356 if (sys
->use_overlay
)
357 DirectXUpdateOverlay(vd
, NULL
);
359 /* Check if we are still on the same monitor */
360 HMONITOR hmon
= MonitorFromWindow(sys
->hwnd
, MONITOR_DEFAULTTONEAREST
);
361 if (sys
->hmonitor
!= hmon
) {
362 vout_display_SendEventPicturesInvalid(vd
);
365 sys
->changes
&= ~DX_POSITION_CHANGE
;
368 /* Wallpaper mode change */
369 vlc_mutex_lock(&sys
->lock
);
370 const bool ch_wallpaper
= sys
->ch_wallpaper
;
371 const bool wallpaper_requested
= sys
->wallpaper_requested
;
372 sys
->ch_wallpaper
= false;
373 vlc_mutex_unlock(&sys
->lock
);
376 WallpaperChange(vd
, wallpaper_requested
);
379 if (sys
->restore_overlay
)
380 DirectXUpdateOverlay(vd
, NULL
);
384 static int DirectXOpenDDraw(vout_display_t
*);
385 static void DirectXCloseDDraw(vout_display_t
*);
387 static int DirectXOpenDisplay(vout_display_t
*vd
);
388 static void DirectXCloseDisplay(vout_display_t
*vd
);
390 static int DirectXCreatePool(vout_display_t
*, bool *, video_format_t
*);
391 static void DirectXDestroyPool(vout_display_t
*);
393 static int DirectXOpen(vout_display_t
*vd
, video_format_t
*fmt
)
395 vout_display_sys_t
*sys
= vd
->sys
;
397 assert(!sys
->ddobject
);
398 assert(!sys
->display
);
399 assert(!sys
->clipper
);
401 /* Initialise DirectDraw */
402 if (DirectXOpenDDraw(vd
)) {
403 msg_Err(vd
, "cannot initialize DirectX DirectDraw");
407 /* Create the directx display */
408 if (DirectXOpenDisplay(vd
)) {
409 msg_Err(vd
, "cannot initialize DirectX DirectDraw");
412 UpdateRects(vd
, NULL
, NULL
, true);
414 /* Create the picture pool */
415 if (DirectXCreatePool(vd
, &sys
->use_overlay
, fmt
)) {
416 msg_Err(vd
, "cannot create any DirectX surface");
421 if (sys
->use_overlay
)
422 DirectXUpdateOverlay(vd
, NULL
);
423 EventThreadUseOverlay(sys
->event
, sys
->use_overlay
);
425 /* Change the window title bar text */
426 const char *fallback
;
427 if (sys
->use_overlay
)
428 fallback
= VOUT_TITLE
" (hardware YUV overlay DirectX output)";
429 else if (vlc_fourcc_IsYUV(fmt
->i_chroma
))
430 fallback
= VOUT_TITLE
" (hardware YUV DirectX output)";
432 fallback
= VOUT_TITLE
" (software RGB DirectX output)";
433 EventThreadUpdateTitle(sys
->event
, fallback
);
437 static void DirectXClose(vout_display_t
*vd
)
439 DirectXDestroyPool(vd
);
440 DirectXCloseDisplay(vd
);
441 DirectXCloseDDraw(vd
);
445 static BOOL WINAPI
DirectXOpenDDrawCallback(GUID
*guid
, LPSTR desc
,
446 LPSTR drivername
, VOID
*context
,
449 vout_display_t
*vd
= context
;
450 vout_display_sys_t
*sys
= vd
->sys
;
452 /* This callback function is called by DirectDraw once for each
453 * available DirectDraw device.
455 * Returning TRUE keeps enumerating.
460 char *psz_drivername
= drivername
;
461 char *psz_desc
= desc
;
463 msg_Dbg(vd
, "DirectXEnumCallback: %s, %s", psz_desc
, psz_drivername
);
465 char *device
= var_GetString(vd
, "directx-device");
467 /* Check for forced device */
468 if (device
&& *device
&& !strcmp(psz_drivername
, device
)) {
469 MONITORINFO monitor_info
;
470 monitor_info
.cbSize
= sizeof(MONITORINFO
);
472 if (GetMonitorInfoA(hmon
, &monitor_info
)) {
475 /* Move window to the right screen */
476 GetWindowRect(sys
->hwnd
, &rect
);
477 if (!IntersectRect(&rect
, &rect
, &monitor_info
.rcWork
)) {
478 rect
.left
= monitor_info
.rcWork
.left
;
479 rect
.top
= monitor_info
.rcWork
.top
;
480 msg_Dbg(vd
, "DirectXEnumCallback: setting window "
481 "position to %ld,%ld", rect
.left
, rect
.top
);
482 SetWindowPos(sys
->hwnd
, NULL
,
483 rect
.left
, rect
.top
, 0, 0,
484 SWP_NOSIZE
| SWP_NOZORDER
| SWP_NOACTIVATE
);
487 sys
->hmonitor
= hmon
;
491 if (hmon
== sys
->hmonitor
) {
492 msg_Dbg(vd
, "selecting %s, %s", psz_desc
, psz_drivername
);
494 free(sys
->display_driver
);
495 sys
->display_driver
= malloc(sizeof(*guid
));
496 if (sys
->display_driver
)
497 *sys
->display_driver
= *guid
;
503 * Probe the capabilities of the hardware
505 * It is nice to know which features are supported by the hardware so we can
506 * find ways to optimize our rendering.
508 static void DirectXGetDDrawCaps(vout_display_t
*vd
)
510 vout_display_sys_t
*sys
= vd
->sys
;
512 /* This is just an indication of whether or not we'll support overlay,
513 * but with this test we don't know if we support YUV overlay */
515 ZeroMemory(&ddcaps
, sizeof(ddcaps
));
516 ddcaps
.dwSize
= sizeof(ddcaps
);
517 HRESULT hr
= IDirectDraw2_GetCaps(sys
->ddobject
, &ddcaps
, NULL
);
519 msg_Warn(vd
, "cannot get caps");
523 /* Determine if the hardware supports overlay surfaces */
524 const bool has_overlay
= ddcaps
.dwCaps
& DDCAPS_OVERLAY
;
525 /* Determine if the hardware supports overlay surfaces */
526 const bool has_overlay_fourcc
= ddcaps
.dwCaps
& DDCAPS_OVERLAYFOURCC
;
527 /* Determine if the hardware supports overlay deinterlacing */
528 const bool can_deinterlace
= ddcaps
.dwCaps
& DDCAPS2_CANFLIPODDEVEN
;
529 /* Determine if the hardware supports colorkeying */
530 const bool has_color_key
= ddcaps
.dwCaps
& DDCAPS_COLORKEY
;
531 /* Determine if the hardware supports scaling of the overlay surface */
532 const bool can_stretch
= ddcaps
.dwCaps
& DDCAPS_OVERLAYSTRETCH
;
533 /* Determine if the hardware supports color conversion during a blit */
534 sys
->can_blit_fourcc
= ddcaps
.dwCaps
& DDCAPS_BLTFOURCC
;
535 /* Determine overlay source boundary alignment */
536 const bool align_boundary_src
= ddcaps
.dwCaps
& DDCAPS_ALIGNBOUNDARYSRC
;
537 /* Determine overlay destination boundary alignment */
538 const bool align_boundary_dest
= ddcaps
.dwCaps
& DDCAPS_ALIGNBOUNDARYDEST
;
539 /* Determine overlay destination size alignment */
540 const bool align_size_src
= ddcaps
.dwCaps
& DDCAPS_ALIGNSIZESRC
;
541 /* Determine overlay destination size alignment */
542 const bool align_size_dest
= ddcaps
.dwCaps
& DDCAPS_ALIGNSIZEDEST
;
544 msg_Dbg(vd
, "DirectDraw Capabilities: overlay=%i yuvoverlay=%i "
545 "can_deinterlace_overlay=%i colorkey=%i stretch=%i "
547 has_overlay
, has_overlay_fourcc
, can_deinterlace
,
548 has_color_key
, can_stretch
, sys
->can_blit_fourcc
);
550 if (align_boundary_src
|| align_boundary_dest
|| align_size_src
|| align_size_dest
) {
551 if (align_boundary_src
)
552 vd
->sys
->i_align_src_boundary
= ddcaps
.dwAlignBoundarySrc
;
553 if (align_boundary_dest
)
554 vd
->sys
->i_align_dest_boundary
= ddcaps
.dwAlignBoundaryDest
;
556 vd
->sys
->i_align_src_size
= ddcaps
.dwAlignSizeSrc
;
558 vd
->sys
->i_align_dest_size
= ddcaps
.dwAlignSizeDest
;
561 "align_boundary_src=%i,%i align_boundary_dest=%i,%i "
562 "align_size_src=%i,%i align_size_dest=%i,%i",
563 align_boundary_src
, vd
->sys
->i_align_src_boundary
,
564 align_boundary_dest
, vd
->sys
->i_align_dest_boundary
,
565 align_size_src
, vd
->sys
->i_align_src_size
,
566 align_size_dest
, vd
->sys
->i_align_dest_size
);
573 static int DirectXOpenDDraw(vout_display_t
*vd
)
575 vout_display_sys_t
*sys
= vd
->sys
;
579 HRESULT (WINAPI
*OurDirectDrawCreate
)(GUID
*,LPDIRECTDRAW
*,IUnknown
*);
580 OurDirectDrawCreate
=
581 (void *)GetProcAddress(sys
->hddraw_dll
, "DirectDrawCreate");
582 if (!OurDirectDrawCreate
) {
583 msg_Err(vd
, "DirectXInitDDraw failed GetProcAddress");
588 HRESULT (WINAPI
*OurDirectDrawEnumerateEx
)(LPDDENUMCALLBACKEXA
, LPVOID
, DWORD
);
589 OurDirectDrawEnumerateEx
=
590 (void *)GetProcAddress(sys
->hddraw_dll
, DIRECTDRAWENUMERATEEX_NAME
);
592 if (OurDirectDrawEnumerateEx
) {
593 char *device
= var_GetString(vd
, "directx-device");
595 msg_Dbg(vd
, "directx-device: %s", device
);
599 sys
->hmonitor
= MonitorFromWindow(sys
->hwnd
, MONITOR_DEFAULTTONEAREST
);
601 /* Enumerate displays */
602 OurDirectDrawEnumerateEx(DirectXOpenDDrawCallback
,
603 vd
, DDENUM_ATTACHEDSECONDARYDEVICES
);
606 /* Initialize DirectDraw now */
607 LPDIRECTDRAW ddobject
;
608 hr
= OurDirectDrawCreate(sys
->display_driver
, &ddobject
, NULL
);
610 msg_Err(vd
, "DirectXInitDDraw cannot initialize DDraw");
614 /* Get the IDirectDraw2 interface */
616 hr
= IDirectDraw_QueryInterface(ddobject
, &IID_IDirectDraw2
,
618 /* Release the unused interface */
619 IDirectDraw_Release(ddobject
);
622 msg_Err(vd
, "cannot get IDirectDraw2 interface");
623 sys
->ddobject
= NULL
;
628 /* Set DirectDraw Cooperative level, ie what control we want over Windows
630 hr
= IDirectDraw2_SetCooperativeLevel(sys
->ddobject
, NULL
, DDSCL_NORMAL
);
632 msg_Err(vd
, "cannot set direct draw cooperative level");
636 /* Get the size of the current display device */
638 MONITORINFO monitor_info
;
639 monitor_info
.cbSize
= sizeof(MONITORINFO
);
640 GetMonitorInfoA(vd
->sys
->hmonitor
, &monitor_info
);
641 sys
->rect_display
= monitor_info
.rcMonitor
;
643 sys
->rect_display
.left
= 0;
644 sys
->rect_display
.top
= 0;
645 sys
->rect_display
.right
= GetSystemMetrics(SM_CXSCREEN
);
646 sys
->rect_display
.bottom
= GetSystemMetrics(SM_CYSCREEN
);
649 msg_Dbg(vd
, "screen dimensions (%lix%li,%lix%li)",
650 sys
->rect_display
.left
,
651 sys
->rect_display
.top
,
652 sys
->rect_display
.right
,
653 sys
->rect_display
.bottom
);
655 /* Probe the capabilities of the hardware */
656 DirectXGetDDrawCaps(vd
);
661 static void DirectXCloseDDraw(vout_display_t
*vd
)
663 vout_display_sys_t
*sys
= vd
->sys
;
665 IDirectDraw2_Release(sys
->ddobject
);
667 sys
->ddobject
= NULL
;
669 free(sys
->display_driver
);
670 sys
->display_driver
= NULL
;
672 sys
->hmonitor
= NULL
;
676 * Create a clipper that will be used when blitting the RGB surface to the main display.
678 * This clipper prevents us to modify by mistake anything on the screen
679 * which doesn't belong to our window. For example when a part of our video
680 * window is hidden by another window.
682 static void DirectXCreateClipper(vout_display_t
*vd
)
684 vout_display_sys_t
*sys
= vd
->sys
;
687 /* Create the clipper */
688 hr
= IDirectDraw2_CreateClipper(sys
->ddobject
, 0, &sys
->clipper
, NULL
);
690 msg_Warn(vd
, "cannot create clipper (error %li)", hr
);
694 /* Associate the clipper to the window */
695 hr
= IDirectDrawClipper_SetHWnd(sys
->clipper
, 0, sys
->hvideownd
);
697 msg_Warn(vd
, "cannot attach clipper to window (error %li)", hr
);
701 /* associate the clipper with the surface */
702 hr
= IDirectDrawSurface_SetClipper(sys
->display
, sys
->clipper
);
705 msg_Warn(vd
, "cannot attach clipper to surface (error %li)", hr
);
713 IDirectDrawClipper_Release(sys
->clipper
);
718 * It finds out the 32bits RGB pixel value of the colorkey.
720 static uint32_t DirectXFindColorkey(vout_display_t
*vd
, uint32_t *color
)
722 vout_display_sys_t
*sys
= vd
->sys
;
727 ddsd
.dwSize
= sizeof(ddsd
);
728 hr
= IDirectDrawSurface2_Lock(sys
->display
, NULL
, &ddsd
, DDLOCK_WAIT
, NULL
);
732 uint32_t backup
= *(uint32_t *)ddsd
.lpSurface
;
734 switch (ddsd
.ddpfPixelFormat
.dwRGBBitCount
) {
736 *(uint8_t *)ddsd
.lpSurface
= *color
| (*color
<< 4);
739 *(uint8_t *)ddsd
.lpSurface
= *color
;
743 *(uint16_t *)ddsd
.lpSurface
= *color
;
746 /* Seems to be problematic so we'll just put black as the colorkey */
749 *(uint32_t *)ddsd
.lpSurface
= *color
;
752 IDirectDrawSurface2_Unlock(sys
->display
, NULL
);
757 if (IDirectDrawSurface2_GetDC(sys
->display
, &hdc
) == DD_OK
) {
758 rgb
= GetPixel(hdc
, 0, 0);
759 IDirectDrawSurface2_ReleaseDC(sys
->display
, hdc
);
764 /* Restore the pixel value */
765 ddsd
.dwSize
= sizeof(ddsd
);
766 if (IDirectDrawSurface2_Lock(sys
->display
, NULL
, &ddsd
, DDLOCK_WAIT
, NULL
) == DD_OK
) {
767 *(uint32_t *)ddsd
.lpSurface
= backup
;
768 IDirectDrawSurface2_Unlock(sys
->display
, NULL
);
775 * Create and initialize display according to preferences specified in the vout
778 static int DirectXOpenDisplay(vout_display_t
*vd
)
780 vout_display_sys_t
*sys
= vd
->sys
;
783 /* Now get the primary surface. This surface is what you actually see
786 ZeroMemory(&ddsd
, sizeof(ddsd
));
787 ddsd
.dwSize
= sizeof(ddsd
);
788 ddsd
.dwFlags
= DDSD_CAPS
;
789 ddsd
.ddsCaps
.dwCaps
= DDSCAPS_PRIMARYSURFACE
;
791 LPDIRECTDRAWSURFACE display
;
792 hr
= IDirectDraw2_CreateSurface(sys
->ddobject
, &ddsd
, &display
, NULL
);
794 msg_Err(vd
, "cannot get primary surface (error %li)", hr
);
799 hr
= IDirectDrawSurface_QueryInterface(display
, &IID_IDirectDrawSurface2
,
801 /* Release the old interface */
802 IDirectDrawSurface_Release(display
);
805 msg_Err(vd
, "cannot query IDirectDrawSurface2 interface (error %li)", hr
);
811 /* The clipper will be used only in non-overlay mode */
812 DirectXCreateClipper(vd
);
814 /* Make sure the colorkey will be painted */
816 sys
->i_rgb_colorkey
= DirectXFindColorkey(vd
, &sys
->i_colorkey
);
820 static void DirectXCloseDisplay(vout_display_t
*vd
)
822 vout_display_sys_t
*sys
= vd
->sys
;
824 if (sys
->clipper
!= NULL
)
825 IDirectDrawClipper_Release(sys
->clipper
);
827 if (sys
->display
!= NULL
)
828 IDirectDrawSurface2_Release(sys
->display
);
835 * Create an YUV overlay or RGB surface for the video.
837 * The best method of display is with an YUV overlay because the YUV->RGB
838 * conversion is done in hardware.
839 * You can also create a plain RGB surface.
840 * (Maybe we could also try an RGB overlay surface, which could have hardware
841 * scaling and which would also be faster in window mode because you don't
842 * need to do any blitting to the main display...)
844 static int DirectXCreateSurface(vout_display_t
*vd
,
845 LPDIRECTDRAWSURFACE2
*surface
,
846 const video_format_t
*fmt
,
850 int backbuffer_count
)
852 vout_display_sys_t
*sys
= vd
->sys
;
856 ZeroMemory(&ddsd
, sizeof(ddsd
));
857 ddsd
.dwSize
= sizeof(ddsd
);
858 ddsd
.ddpfPixelFormat
.dwSize
= sizeof(ddsd
.ddpfPixelFormat
);
859 ddsd
.dwFlags
= DDSD_HEIGHT
| DDSD_WIDTH
;
860 ddsd
.dwWidth
= fmt
->i_width
;
861 ddsd
.dwHeight
= fmt
->i_height
;
863 ddsd
.dwFlags
|= DDSD_PIXELFORMAT
;
864 ddsd
.ddpfPixelFormat
.dwFlags
= DDPF_FOURCC
;
865 ddsd
.ddpfPixelFormat
.dwFourCC
= fourcc
;
867 ddsd
.dwFlags
|= DDSD_CAPS
;
869 ddsd
.ddsCaps
.dwCaps
= DDSCAPS_OVERLAY
| DDSCAPS_VIDEOMEMORY
;
870 if (backbuffer_count
> 0) {
871 ddsd
.ddsCaps
.dwCaps
|= DDSCAPS_COMPLEX
| DDSCAPS_FLIP
;
872 ddsd
.dwFlags
|= DDSD_BACKBUFFERCOUNT
;
873 ddsd
.dwBackBufferCount
= backbuffer_count
;
876 ddsd
.ddsCaps
.dwCaps
= DDSCAPS_OFFSCREENPLAIN
;
878 ddsd
.ddsCaps
.dwCaps
|= DDSCAPS_SYSTEMMEMORY
;
880 ddsd
.ddsCaps
.dwCaps
|= DDSCAPS_VIDEOMEMORY
;
883 /* Create the video surface */
884 LPDIRECTDRAWSURFACE surface_v1
;
885 HRESULT hr
= IDirectDraw2_CreateSurface(sys
->ddobject
, &ddsd
, &surface_v1
, NULL
);
886 if (hr
== DDERR_INVALIDCAPS
)
888 msg_Dbg(vd
, "failed to create a DirectDrawSurface with invalid caps %lx", ddsd
.ddsCaps
.dwCaps
);
893 msg_Dbg(vd
, "failed to create a DirectDrawSurface (error %li)", hr
);
897 /* Now that the surface is created, try to get a newer DirectX interface */
898 hr
= IDirectDrawSurface_QueryInterface(surface_v1
,
899 &IID_IDirectDrawSurface2
,
901 IDirectDrawSurface_Release(surface_v1
);
903 msg_Err(vd
, "cannot query IDirectDrawSurface2 interface (error %li)", hr
);
908 /* Check the overlay is useable as some graphics cards allow creating
909 * several overlays but only one can be used at one time. */
910 if (DirectXUpdateOverlay(vd
, *surface
)) {
911 IDirectDrawSurface2_Release(*surface
);
912 msg_Err(vd
, "overlay unuseable (might already be in use)");
920 static void DirectXDestroySurface(LPDIRECTDRAWSURFACE2 surface
)
922 IDirectDrawSurface2_Release(surface
);
925 * This function locks a surface and get the surface descriptor.
927 static int DirectXLockSurface(LPDIRECTDRAWSURFACE2 front_surface
,
928 LPDIRECTDRAWSURFACE2 surface
,
933 DDSURFACEDESC ddsd_dummy
;
937 ZeroMemory(ddsd
, sizeof(*ddsd
));
938 ddsd
->dwSize
= sizeof(*ddsd
);
939 hr
= IDirectDrawSurface2_Lock(surface
, NULL
, ddsd
, DDLOCK_NOSYSLOCK
| DDLOCK_WAIT
, NULL
);
941 if (hr
== DDERR_INVALIDPARAMS
) {
942 /* DirectX 3 doesn't support the DDLOCK_NOSYSLOCK flag, resulting
943 * in an invalid params error */
944 hr
= IDirectDrawSurface2_Lock(surface
, NULL
, ddsd
, DDLOCK_WAIT
, NULL
);
946 if (hr
== DDERR_SURFACELOST
) {
947 /* Your surface can be lost so be sure
948 * to check this and restore it if needed */
950 /* When using overlays with back-buffers, we need to restore
951 * the front buffer so the back-buffers get restored as well. */
952 if (front_surface
!= surface
)
953 IDirectDrawSurface2_Restore(front_surface
);
955 IDirectDrawSurface2_Restore(surface
);
957 hr
= IDirectDrawSurface2_Lock(surface
, NULL
, ddsd
, DDLOCK_WAIT
, NULL
);
964 static void DirectXUnlockSurface(LPDIRECTDRAWSURFACE2 front_surface
,
965 LPDIRECTDRAWSURFACE2 surface
)
967 VLC_UNUSED(front_surface
);
968 IDirectDrawSurface2_Unlock(surface
, NULL
);
970 static int DirectXCheckLockingSurface(LPDIRECTDRAWSURFACE2 front_surface
,
971 LPDIRECTDRAWSURFACE2 surface
)
973 if (DirectXLockSurface(front_surface
, surface
, NULL
))
976 DirectXUnlockSurface(front_surface
, surface
);
987 static DWORD
DirectXGetFourcc(vlc_fourcc_t codec
)
989 static const dx_format_t dx_formats
[] = {
990 { VLC_CODEC_YUYV
, MAKEFOURCC('Y','U','Y','2') },
991 { VLC_CODEC_UYVY
, MAKEFOURCC('U','Y','V','Y') },
992 { VLC_CODEC_YVYU
, MAKEFOURCC('Y','V','Y','U') },
993 { VLC_CODEC_YV12
, MAKEFOURCC('Y','V','1','2') },
994 { VLC_CODEC_I420
, MAKEFOURCC('Y','V','1','2') },
995 { VLC_CODEC_J420
, MAKEFOURCC('Y','V','1','2') },
999 for (unsigned i
= 0; dx_formats
[i
].codec
!= 0; i
++) {
1000 if (dx_formats
[i
].codec
== codec
)
1001 return dx_formats
[i
].fourcc
;
1006 static int DirectXCreatePictureResourceYuvOverlay(vout_display_t
*vd
,
1007 const video_format_t
*fmt
,
1010 vout_display_sys_t
*sys
= vd
->sys
;
1012 bool allow_3buf
= var_InheritBool(vd
, "directx-3buffering");
1014 /* The overlay surface that we create won't be used to decode directly
1015 * into it because accessing video memory directly is way to slow (remember
1016 * that pictures are decoded macroblock per macroblock). Instead the video
1017 * will be decoded in picture buffers in system memory which will then be
1018 * memcpy() to the overlay surface. */
1019 LPDIRECTDRAWSURFACE2 front_surface
;
1020 int ret
= VLC_EGENERIC
;
1022 /* Triple buffering rocks! it doesn't have any processing overhead
1023 * (you don't have to wait for the vsync) and provides for a very nice
1024 * video quality (no tearing). */
1025 ret
= DirectXCreateSurface(vd
, &front_surface
, fmt
, fourcc
, true, false, 2);
1028 ret
= DirectXCreateSurface(vd
, &front_surface
, fmt
, fourcc
, true, false, 0);
1030 return VLC_EGENERIC
;
1031 msg_Dbg(vd
, "YUV overlay surface (%4.4s) created successfully", (const char *)&fourcc
);
1033 /* Get the back buffer */
1034 LPDIRECTDRAWSURFACE2 surface
;
1036 ZeroMemory(&dds_caps
, sizeof(dds_caps
));
1037 dds_caps
.dwCaps
= DDSCAPS_BACKBUFFER
;
1038 if (IDirectDrawSurface2_GetAttachedSurface(front_surface
, &dds_caps
, &surface
) != DD_OK
) {
1039 msg_Warn(vd
, "Failed to get surface back buffer");
1040 /* front buffer is the same as back buffer */
1041 surface
= front_surface
;
1044 if (DirectXCheckLockingSurface(front_surface
, surface
)) {
1045 DirectXDestroySurface(front_surface
);
1046 return VLC_EGENERIC
;
1050 picture_sys_t
*picsys
= sys
->picsys
;
1051 picsys
->front_surface
= front_surface
;
1052 picsys
->surface
= surface
;
1053 picsys
->fallback
= NULL
;
1056 static int DirectXCreatePictureResourceYuv(vout_display_t
*vd
,
1057 const video_format_t
*fmt
,
1060 vout_display_sys_t
*sys
= vd
->sys
;
1062 bool allow_sysmem
= var_InheritBool(vd
, "directx-use-sysmem");
1064 /* As we can't have an overlay, we'll try to create a plain offscreen
1065 * surface. This surface will reside in video memory because there's a
1066 * better chance then that we'll be able to use some kind of hardware
1067 * acceleration like rescaling, blitting or YUV->RGB conversions.
1068 * We then only need to blit this surface onto the main display when we
1069 * want to display it */
1071 /* Check if the chroma is supported first. This is required
1072 * because a few buggy drivers don't mind creating the surface
1073 * even if they don't know about the chroma. */
1075 if (IDirectDraw2_GetFourCCCodes(sys
->ddobject
, &count
, NULL
) != DD_OK
)
1076 return VLC_EGENERIC
;
1078 DWORD
*list
= calloc(count
, sizeof(*list
));
1081 if (IDirectDraw2_GetFourCCCodes(sys
->ddobject
, &count
, list
) != DD_OK
) {
1083 return VLC_EGENERIC
;
1086 for (index
= 0; index
< count
; index
++) {
1087 if (list
[index
] == fourcc
)
1092 return VLC_EGENERIC
;
1095 LPDIRECTDRAWSURFACE2 surface
;
1096 if (DirectXCreateSurface(vd
, &surface
, fmt
, fourcc
, false, allow_sysmem
, 0))
1097 return VLC_EGENERIC
;
1098 msg_Dbg(vd
, "YUV plain surface (%4.4s) created successfully", (const char *)&fourcc
);
1100 if (DirectXCheckLockingSurface(surface
, surface
)) {
1101 DirectXDestroySurface(surface
);
1102 return VLC_EGENERIC
;
1106 picture_sys_t
*picsys
= sys
->picsys
;
1107 picsys
->front_surface
= surface
;
1108 picsys
->surface
= surface
;
1109 picsys
->fallback
= NULL
;
1112 static int DirectXCreatePictureResourceRgb(vout_display_t
*vd
,
1113 video_format_t
*fmt
)
1115 vout_display_sys_t
*sys
= vd
->sys
;
1116 bool allow_sysmem
= var_InheritBool(vd
, "directx-use-sysmem");
1118 /* Our last choice is to use a plain RGB surface */
1119 DDPIXELFORMAT ddpfPixelFormat
;
1120 ZeroMemory(&ddpfPixelFormat
, sizeof(ddpfPixelFormat
));
1121 ddpfPixelFormat
.dwSize
= sizeof(ddpfPixelFormat
);
1123 IDirectDrawSurface2_GetPixelFormat(sys
->display
, &ddpfPixelFormat
);
1124 if ((ddpfPixelFormat
.dwFlags
& DDPF_RGB
) == 0)
1125 return VLC_EGENERIC
;
1127 switch (ddpfPixelFormat
.dwRGBBitCount
) {
1129 fmt
->i_chroma
= VLC_CODEC_RGB8
;
1132 fmt
->i_chroma
= VLC_CODEC_RGB15
;
1135 fmt
->i_chroma
= VLC_CODEC_RGB16
;
1138 fmt
->i_chroma
= VLC_CODEC_RGB24
;
1141 fmt
->i_chroma
= VLC_CODEC_RGB32
;
1144 msg_Err(vd
, "unknown screen depth");
1145 return VLC_EGENERIC
;
1147 fmt
->i_rmask
= ddpfPixelFormat
.dwRBitMask
;
1148 fmt
->i_gmask
= ddpfPixelFormat
.dwGBitMask
;
1149 fmt
->i_bmask
= ddpfPixelFormat
.dwBBitMask
;
1152 LPDIRECTDRAWSURFACE2 surface
;
1153 int ret
= DirectXCreateSurface(vd
, &surface
, fmt
, 0, false, allow_sysmem
, 0);
1154 if (ret
&& !allow_sysmem
)
1155 ret
= DirectXCreateSurface(vd
, &surface
, fmt
, 0, false, true, 0);
1157 return VLC_EGENERIC
;
1158 msg_Dbg(vd
, "RGB plain surface (%4.4s) created successfully", (const char *)&fmt
->i_chroma
);
1160 if (DirectXCheckLockingSurface(surface
, surface
)) {
1161 DirectXDestroySurface(surface
);
1162 return VLC_EGENERIC
;
1166 picture_sys_t
*picsys
= sys
->picsys
;
1167 picsys
->front_surface
= surface
;
1168 picsys
->surface
= surface
;
1169 picsys
->fallback
= NULL
;
1173 static int DirectXCreatePictureResource(vout_display_t
*vd
,
1175 video_format_t
*fmt
)
1177 vout_display_sys_t
*sys
= vd
->sys
;
1180 picture_sys_t
*picsys
= calloc(1, sizeof(*picsys
));
1181 if (unlikely(picsys
== NULL
))
1183 sys
->picsys
= picsys
;
1186 bool allow_hw_yuv
= sys
->can_blit_fourcc
&&
1187 vlc_fourcc_IsYUV(fmt
->i_chroma
) &&
1188 var_InheritBool(vd
, "directx-hw-yuv");
1189 bool allow_overlay
= var_InheritBool(vd
, "directx-overlay");
1191 /* Try to use an yuv surface */
1193 const vlc_fourcc_t
*list
= vlc_fourcc_GetYUVFallback(fmt
->i_chroma
);
1194 /* Try with overlay first */
1195 for (unsigned pass
= allow_overlay
? 0 : 1; pass
< 2; pass
++) {
1196 for (unsigned i
= 0; list
[i
] != 0; i
++) {
1197 const DWORD fourcc
= DirectXGetFourcc(list
[i
]);
1202 if (DirectXCreatePictureResourceYuvOverlay(vd
, fmt
, fourcc
))
1205 msg_Dbg(vd
, "Failed to create YUV overlay surface %4.4s", (const char*)&fourcc
);
1210 if (DirectXCreatePictureResourceYuv(vd
, fmt
, fourcc
))
1213 msg_Dbg(vd
, "Failed to create YUV surface %4.4s", (const char*)&fourcc
);
1219 *use_overlay
= pass
== 0;
1220 fmt
->i_chroma
= list
[i
];
1227 return DirectXCreatePictureResourceRgb(vd
, fmt
);
1229 static void DirectXDestroyPictureResource(vout_display_t
*vd
)
1231 vout_display_sys_t
*sys
= vd
->sys
;
1233 if (sys
->picsys
->front_surface
!= sys
->picsys
->surface
)
1234 DirectXDestroySurface(sys
->picsys
->surface
);
1235 DirectXDestroySurface(sys
->picsys
->front_surface
);
1236 if (sys
->picsys
->fallback
)
1237 picture_Release(sys
->picsys
->fallback
);
1240 static int DirectXLock(picture_t
*picture
)
1243 if (DirectXLockSurface(picture
->p_sys
->front_surface
,
1244 picture
->p_sys
->surface
, &ddsd
))
1245 return CommonUpdatePicture(picture
, &picture
->p_sys
->fallback
, NULL
, 0);
1247 CommonUpdatePicture(picture
, NULL
, ddsd
.lpSurface
, ddsd
.lPitch
);
1250 static void DirectXUnlock(picture_t
*picture
)
1252 DirectXUnlockSurface(picture
->p_sys
->front_surface
,
1253 picture
->p_sys
->surface
);
1256 static int DirectXCreatePool(vout_display_t
*vd
,
1257 bool *use_overlay
, video_format_t
*fmt
)
1259 vout_display_sys_t
*sys
= vd
->sys
;
1264 if (DirectXCreatePictureResource(vd
, use_overlay
, fmt
))
1265 return VLC_EGENERIC
;
1267 /* Create the associated picture */
1268 picture_resource_t resource
= { .p_sys
= sys
->picsys
};
1269 picture_t
*picture
= picture_NewFromResource(fmt
, &resource
);
1271 DirectXDestroyPictureResource(vd
);
1276 /* Wrap it into a picture pool */
1277 picture_pool_configuration_t cfg
;
1278 memset(&cfg
, 0, sizeof(cfg
));
1279 cfg
.picture_count
= 1;
1280 cfg
.picture
= &picture
;
1281 cfg
.lock
= DirectXLock
;
1282 cfg
.unlock
= DirectXUnlock
;
1284 sys
->pool
= picture_pool_NewExtended(&cfg
);
1286 picture_Release(picture
);
1287 DirectXDestroyPictureResource(vd
);
1292 static void DirectXDestroyPool(vout_display_t
*vd
)
1294 vout_display_sys_t
*sys
= vd
->sys
;
1297 DirectXDestroyPictureResource(vd
);
1298 picture_pool_Release(sys
->pool
);
1304 * Move or resize overlay surface on video display.
1306 * This function is used to move or resize an overlay surface on the screen.
1307 * Ususally the overlay is moved by the user and thus, by a move or resize
1310 static int DirectXUpdateOverlay(vout_display_t
*vd
, LPDIRECTDRAWSURFACE2 surface
)
1312 vout_display_sys_t
*sys
= vd
->sys
;
1314 RECT src
= sys
->rect_src_clipped
;
1315 RECT dst
= sys
->rect_dest_clipped
;
1317 if (sys
->use_wallpaper
) {
1318 src
.left
= vd
->source
.i_x_offset
;
1319 src
.top
= vd
->source
.i_y_offset
;
1320 src
.right
= vd
->source
.i_x_offset
+ vd
->source
.i_visible_width
;
1321 src
.bottom
= vd
->source
.i_y_offset
+ vd
->source
.i_visible_height
;
1322 AlignRect(&src
, sys
->i_align_src_boundary
, sys
->i_align_src_size
);
1324 vout_display_cfg_t cfg
= *vd
->cfg
;
1325 cfg
.display
.width
= sys
->rect_display
.right
;
1326 cfg
.display
.height
= sys
->rect_display
.bottom
;
1328 vout_display_place_t place
;
1329 vout_display_PlacePicture(&place
, &vd
->source
, &cfg
, true);
1331 dst
.left
= sys
->rect_display
.left
+ place
.x
;
1332 dst
.top
= sys
->rect_display
.top
+ place
.y
;
1333 dst
.right
= dst
.left
+ place
.width
;
1334 dst
.bottom
= dst
.top
+ place
.height
;
1335 AlignRect(&dst
, sys
->i_align_dest_boundary
, sys
->i_align_dest_size
);
1340 return VLC_EGENERIC
;
1341 surface
= sys
->picsys
->front_surface
;
1344 /* The new window dimensions should already have been computed by the
1345 * caller of this function */
1347 /* Position and show the overlay */
1349 ZeroMemory(&ddofx
, sizeof(ddofx
));
1350 ddofx
.dwSize
= sizeof(ddofx
);
1351 ddofx
.dckDestColorkey
.dwColorSpaceLowValue
= sys
->i_colorkey
;
1352 ddofx
.dckDestColorkey
.dwColorSpaceHighValue
= sys
->i_colorkey
;
1354 HRESULT hr
= IDirectDrawSurface2_UpdateOverlay(surface
,
1355 &src
, sys
->display
, &dst
,
1356 DDOVER_SHOW
| DDOVER_KEYDESTOVERRIDE
| DDOVER_DDFX
,
1358 sys
->restore_overlay
= hr
!= DD_OK
;
1361 msg_Warn(vd
, "DirectDrawUpdateOverlay cannot move/resize overlay. (hr=0x%lX)", hr
);
1362 return VLC_EGENERIC
;
1368 static void WallpaperChange(vout_display_t
*vd
, bool use_wallpaper
)
1370 vout_display_sys_t
*sys
= vd
->sys
;
1372 if (!sys
->use_wallpaper
== !use_wallpaper
)
1375 HWND hwnd
= FindWindow(_T("Progman"), NULL
);
1377 hwnd
= FindWindowEx(hwnd
, NULL
, _T("SHELLDLL_DefView"), NULL
);
1379 hwnd
= FindWindowEx(hwnd
, NULL
, _T("SysListView32"), NULL
);
1381 msg_Warn(vd
, "couldn't find \"SysListView32\" window, "
1382 "wallpaper mode not supported");
1386 msg_Dbg(vd
, "wallpaper mode %s", use_wallpaper
? "enabled" : "disabled");
1387 sys
->use_wallpaper
= use_wallpaper
;
1389 if (sys
->use_wallpaper
) {
1390 sys
->color_bkg
= ListView_GetBkColor(hwnd
);
1391 sys
->color_bkgtxt
= ListView_GetTextBkColor(hwnd
);
1393 ListView_SetBkColor(hwnd
, sys
->i_rgb_colorkey
);
1394 ListView_SetTextBkColor(hwnd
, sys
->i_rgb_colorkey
);
1396 ListView_SetBkColor(hwnd
, sys
->color_bkg
);
1397 ListView_SetTextBkColor(hwnd
, sys
->color_bkgtxt
);
1400 /* Update desktop */
1401 InvalidateRect(hwnd
, NULL
, TRUE
);
1404 if (sys
->use_overlay
)
1405 DirectXUpdateOverlay(vd
, NULL
);
1409 static int WallpaperCallback(vlc_object_t
*object
, char const *cmd
,
1410 vlc_value_t oldval
, vlc_value_t newval
, void *data
)
1412 vout_display_t
*vd
= (vout_display_t
*)object
;
1413 vout_display_sys_t
*sys
= vd
->sys
;
1414 VLC_UNUSED(cmd
); VLC_UNUSED(oldval
); VLC_UNUSED(data
);
1416 vlc_mutex_lock(&sys
->lock
);
1417 const bool ch_wallpaper
= !sys
->wallpaper_requested
!= !newval
.b_bool
;
1418 sys
->ch_wallpaper
|= ch_wallpaper
;
1419 sys
->wallpaper_requested
= newval
.b_bool
;
1420 vlc_mutex_unlock(&sys
->lock
);
1431 /*****************************************************************************
1432 * config variable callback
1433 *****************************************************************************/
1434 static BOOL WINAPI
DirectXEnumCallback2(GUID
*guid
, LPSTR desc
,
1435 LPSTR drivername
, VOID
*data
,
1438 enum_context_t
*ctx
= data
;
1440 VLC_UNUSED(guid
); VLC_UNUSED(desc
); VLC_UNUSED(hmon
);
1442 char *psz_drivername
= drivername
;
1443 ctx
->values
= xrealloc(ctx
->values
, (ctx
->count
+ 1) * sizeof(char *));
1444 ctx
->descs
= xrealloc(ctx
->descs
, (ctx
->count
+ 1) * sizeof(char *));
1446 ctx
->values
[ctx
->count
] = strdup(psz_drivername
);
1447 ctx
->descs
[ctx
->count
] = strdup(psz_drivername
);
1450 return TRUE
; /* Keep enumerating */
1453 static int FindDevicesCallback(vlc_object_t
*object
, const char *name
,
1454 char ***values
, char ***descs
)
1458 ctx
.values
= xmalloc(sizeof(char *));
1459 ctx
.descs
= xmalloc(sizeof(char *));
1460 ctx
.values
[0] = strdup("");
1461 ctx
.descs
[0] = strdup(_("Default"));
1464 /* Load direct draw DLL */
1465 HINSTANCE hddraw_dll
= LoadLibrary(_T("DDRAW.DLL"));
1466 if (hddraw_dll
!= NULL
)
1468 /* Enumerate displays */
1469 HRESULT (WINAPI
*OurDirectDrawEnumerateEx
)(LPDDENUMCALLBACKEXA
,
1471 (void *)GetProcAddress(hddraw_dll
, DIRECTDRAWENUMERATEEX_NAME
);
1472 if (OurDirectDrawEnumerateEx
!= NULL
)
1473 OurDirectDrawEnumerateEx(DirectXEnumCallback2
, &ctx
,
1474 DDENUM_ATTACHEDSECONDARYDEVICES
);
1475 FreeLibrary(hddraw_dll
);
1481 *values
= ctx
.values
;