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)
122 /* FIXME: Hack to avoid unregistering our window class */
123 cannot_unload_broken_library()
127 /* check if we registered a window class because we need to
130 if (GetClassInfo(GetModuleHandle(NULL), "VLC DirectX", &wndclass))
131 UnregisterClass("VLC DirectX", GetModuleHandle(NULL));
134 /*****************************************************************************
136 *****************************************************************************/
138 struct picture_sys_t {
139 LPDIRECTDRAWSURFACE2 surface;
140 LPDIRECTDRAWSURFACE2 front_surface;
143 /*****************************************************************************
145 * Defining them here allows us to get rid of the dxguid library during
147 *****************************************************************************/
148 #include <initguid.h>
151 DEFINE_GUID(IID_IDirectDraw2, 0xB3A6F3E0,0x2B43,0x11CF,0xA2,0xDE,0x00,0xAA,0x00,0xB9,0x33,0x56);
152 DEFINE_GUID(IID_IDirectDrawSurface2, 0x57805885,0x6eec,0x11cf,0x94,0x41,0xa8,0x23,0x03,0xc1,0x0e,0x27);
154 static picture_pool_t *Pool (vout_display_t *, unsigned);
155 static void Display(vout_display_t *, picture_t *);
156 static int Control(vout_display_t *, int, va_list);
157 static void Manage (vout_display_t *);
160 static int WallpaperCallback(vlc_object_t *, char const *,
161 vlc_value_t, vlc_value_t, void *);
163 static int DirectXOpen(vout_display_t *, video_format_t *fmt);
164 static void DirectXClose(vout_display_t *);
166 static int DirectXLock(picture_t *);
167 static void DirectXUnlock(picture_t *);
169 static int DirectXUpdateOverlay(vout_display_t *, LPDIRECTDRAWSURFACE2 surface);
171 static void WallpaperChange(vout_display_t *vd, bool use_wallpaper);
173 /** This function allocates and initialize the DirectX vout display.
175 static int Open(vlc_object_t *object)
177 vout_display_t *vd = (vout_display_t *)object;
178 vout_display_sys_t *sys;
180 /* Allocate structure */
181 vd->sys = sys = calloc(1, sizeof(*sys));
185 /* Load direct draw DLL */
186 sys->hddraw_dll = LoadLibrary(_T("DDRAW.DLL"));
187 if (!sys->hddraw_dll) {
188 msg_Warn(vd, "DirectXInitDDraw failed loading ddraw.dll");
194 HMODULE huser32 = GetModuleHandle(_T("USER32"));
196 sys->MonitorFromWindow = (void*)GetProcAddress(huser32, _T("MonitorFromWindow"));
197 sys->GetMonitorInfo = (void*)GetProcAddress(huser32, _T("GetMonitorInfoA"));
199 sys->MonitorFromWindow = NULL;
200 sys->GetMonitorInfo = NULL;
204 sys->use_wallpaper = var_CreateGetBool(vd, "video-wallpaper");
206 sys->use_overlay = false;//var_CreateGetBool(vd, "overlay"); /* FIXME */
207 var_Create(vd, "directx-device", VLC_VAR_STRING | VLC_VAR_DOINHERIT);
214 video_format_t fmt = vd->fmt;
216 if (DirectXOpen(vd, &fmt))
220 vout_display_info_t info = vd->info;
222 info.has_double_click = true;
223 info.has_hide_mouse = true;
224 info.has_pictures_invalid = true;
225 info.has_event_thread = true;
227 /* Interaction TODO support starting with wallpaper mode */
228 vlc_mutex_init(&sys->lock);
229 sys->ch_wallpaper = sys->use_wallpaper;
230 sys->wallpaper_requested = sys->use_wallpaper;
231 sys->use_wallpaper = false;
234 val.psz_string = _("Wallpaper");
235 var_Change(vd, "video-wallpaper", VLC_VAR_SETTEXT, &val, NULL);
236 var_AddCallback(vd, "video-wallpaper", WallpaperCallback, NULL);
238 /* Setup vout_display now that everything is fine */
244 vd->display = Display;
245 vd->control = Control;
250 Close(VLC_OBJECT(vd));
254 /** Terminate a vout display created by Open.
256 static void Close(vlc_object_t *object)
258 vout_display_t *vd = (vout_display_t *)object;
259 vout_display_sys_t *sys = vd->sys;
261 var_DelCallback(vd, "video-wallpaper", WallpaperCallback, NULL);
262 vlc_mutex_destroy(&sys->lock);
264 /* Make sure the wallpaper is restored */
265 WallpaperChange(vd, false);
272 FreeLibrary(sys->hddraw_dll);
276 static picture_pool_t *Pool(vout_display_t *vd, unsigned count)
279 return vd->sys->pool;
281 static void Display(vout_display_t *vd, picture_t *picture)
283 vout_display_sys_t *sys = vd->sys;
285 assert(sys->display);
287 /* Our surface can be lost so be sure to check this
288 * and restore it if need be */
289 if (IDirectDrawSurface2_IsLost(sys->display) == DDERR_SURFACELOST) {
290 if (IDirectDrawSurface2_Restore(sys->display) == DD_OK) {
291 if (sys->use_overlay)
292 DirectXUpdateOverlay(vd, NULL);
297 DirectXUnlock(picture);
299 if (sys->use_overlay) {
300 /* Flip the overlay buffers if we are using back buffers */
301 if (picture->p_sys->surface != picture->p_sys->front_surface) {
302 HRESULT hr = IDirectDrawSurface2_Flip(picture->p_sys->front_surface,
305 msg_Warn(vd, "could not flip overlay (error %li)", hr);
308 /* Blit video surface to display with the NOTEARING option */
310 ZeroMemory(&ddbltfx, sizeof(ddbltfx));
311 ddbltfx.dwSize = sizeof(ddbltfx);
312 ddbltfx.dwDDFX = DDBLTFX_NOTEARING;
314 HRESULT hr = IDirectDrawSurface2_Blt(sys->display,
315 &sys->rect_dest_clipped,
316 picture->p_sys->surface,
317 &sys->rect_src_clipped,
318 DDBLT_ASYNC, &ddbltfx);
320 msg_Warn(vd, "could not blit surface (error %li)", hr);
322 DirectXLock(picture);
324 if (sys->is_first_display) {
325 IDirectDraw_WaitForVerticalBlank(sys->ddobject,
326 DDWAITVB_BLOCKBEGIN, NULL);
327 if (sys->use_overlay) {
328 HBRUSH brush = CreateSolidBrush(sys->i_rgb_colorkey);
329 /* set the colorkey as the backgound brush for the video window */
330 SetClassLongPtr(sys->hvideownd, GCLP_HBRBACKGROUND, (LONG_PTR)brush);
335 picture_Release(picture);
337 static int Control(vout_display_t *vd, int query, va_list args)
339 vout_display_sys_t *sys = vd->sys;
342 case VOUT_DISPLAY_RESET_PICTURES:
344 /* Make sure the wallpaper is restored */
345 if (sys->use_wallpaper) {
346 vlc_mutex_lock(&sys->lock);
347 if (!sys->ch_wallpaper) {
348 sys->ch_wallpaper = true;
349 sys->wallpaper_requested = true;
351 vlc_mutex_unlock(&sys->lock);
353 WallpaperChange(vd, false);
355 return DirectXOpen(vd, &vd->fmt);
357 return CommonControl(vd, query, args);
360 static void Manage(vout_display_t *vd)
362 vout_display_sys_t *sys = vd->sys;
366 if (sys->changes & DX_POSITION_CHANGE) {
368 if (sys->use_overlay)
369 DirectXUpdateOverlay(vd, NULL);
371 /* Check if we are still on the same monitor */
372 if (sys->MonitorFromWindow &&
373 sys->hmonitor != sys->MonitorFromWindow(sys->hwnd, MONITOR_DEFAULTTONEAREST)) {
374 vout_display_SendEventPicturesInvalid(vd);
377 sys->changes &= ~DX_POSITION_CHANGE;
380 /* Wallpaper mode change */
381 vlc_mutex_lock(&sys->lock);
382 const bool ch_wallpaper = sys->ch_wallpaper;
383 const bool wallpaper_requested = sys->wallpaper_requested;
384 sys->ch_wallpaper = false;
385 vlc_mutex_unlock(&sys->lock);
388 WallpaperChange(vd, wallpaper_requested);
392 static int DirectXOpenDDraw(vout_display_t *);
393 static void DirectXCloseDDraw(vout_display_t *);
395 static int DirectXOpenDisplay(vout_display_t *vd);
396 static void DirectXCloseDisplay(vout_display_t *vd);
398 static int DirectXCreatePool(vout_display_t *, bool *, video_format_t *);
399 static void DirectXDestroyPool(vout_display_t *);
401 static int DirectXOpen(vout_display_t *vd, video_format_t *fmt)
403 vout_display_sys_t *sys = vd->sys;
405 assert(!sys->ddobject);
406 assert(!sys->display);
407 assert(!sys->clipper);
409 /* Initialise DirectDraw */
410 if (DirectXOpenDDraw(vd)) {
411 msg_Err(vd, "cannot initialize DirectX DirectDraw");
415 /* Create the directx display */
416 if (DirectXOpenDisplay(vd)) {
417 msg_Err(vd, "cannot initialize DirectX DirectDraw");
420 UpdateRects(vd, NULL, NULL, true);
422 /* Create the picture pool */
423 if (DirectXCreatePool(vd, &sys->use_overlay, fmt)) {
424 msg_Err(vd, "cannot create any DirectX surface");
429 if (sys->use_overlay)
430 DirectXUpdateOverlay(vd, NULL);
431 EventThreadUseOverlay(sys->event, sys->use_overlay);
433 /* Change the window title bar text */
434 const char *fallback;
435 if (sys->use_overlay)
436 fallback = VOUT_TITLE " (hardware YUV overlay DirectX output)";
437 else if (vlc_fourcc_IsYUV(fmt->i_chroma))
438 fallback = VOUT_TITLE " (hardware YUV DirectX output)";
440 fallback = VOUT_TITLE " (software RGB DirectX output)";
441 EventThreadUpdateTitle(sys->event, fallback);
445 static void DirectXClose(vout_display_t *vd)
447 DirectXDestroyPool(vd);
448 DirectXCloseDisplay(vd);
449 DirectXCloseDDraw(vd);
453 static BOOL WINAPI DirectXOpenDDrawCallback(GUID *guid, LPTSTR desc,
454 LPTSTR drivername, VOID *context,
457 vout_display_t *vd = context;
458 vout_display_sys_t *sys = vd->sys;
460 /* This callback function is called by DirectDraw once for each
461 * available DirectDraw device.
463 * Returning TRUE keeps enumerating.
468 msg_Dbg(vd, "DirectXEnumCallback: %s, %s", desc, drivername);
470 char *device = var_GetString(vd, "directx-device");
472 /* Check for forced device */
473 if (device && *device && !strcmp(drivername, device)) {
474 MONITORINFO monitor_info;
475 monitor_info.cbSize = sizeof(MONITORINFO);
477 if (sys->GetMonitorInfo(hmon, &monitor_info)) {
480 /* Move window to the right screen */
481 GetWindowRect(sys->hwnd, &rect);
482 if (!IntersectRect(&rect, &rect, &monitor_info.rcWork)) {
483 rect.left = monitor_info.rcWork.left;
484 rect.top = monitor_info.rcWork.top;
485 msg_Dbg(vd, "DirectXEnumCallback: setting window "
486 "position to %ld,%ld", rect.left, rect.top);
487 SetWindowPos(sys->hwnd, NULL,
488 rect.left, rect.top, 0, 0,
489 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
492 sys->hmonitor = hmon;
496 if (hmon == sys->hmonitor) {
497 msg_Dbg(vd, "selecting %s, %s", desc, drivername);
499 free(sys->display_driver);
500 sys->display_driver = malloc(sizeof(*guid));
501 if (sys->display_driver)
502 *sys->display_driver = *guid;
508 * Probe the capabilities of the hardware
510 * It is nice to know which features are supported by the hardware so we can
511 * find ways to optimize our rendering.
513 static void DirectXGetDDrawCaps(vout_display_t *vd)
515 vout_display_sys_t *sys = vd->sys;
517 /* This is just an indication of whether or not we'll support overlay,
518 * but with this test we don't know if we support YUV overlay */
520 ZeroMemory(&ddcaps, sizeof(ddcaps));
521 ddcaps.dwSize = sizeof(ddcaps);
522 HRESULT hr = IDirectDraw2_GetCaps(sys->ddobject, &ddcaps, NULL);
524 msg_Warn(vd, "cannot get caps");
528 /* Determine if the hardware supports overlay surfaces */
529 const bool has_overlay = ddcaps.dwCaps & DDCAPS_OVERLAY;
530 /* Determine if the hardware supports overlay surfaces */
531 const bool has_overlay_fourcc = ddcaps.dwCaps & DDCAPS_OVERLAYFOURCC;
532 /* Determine if the hardware supports overlay deinterlacing */
533 const bool can_deinterlace = ddcaps.dwCaps & DDCAPS2_CANFLIPODDEVEN;
534 /* Determine if the hardware supports colorkeying */
535 const bool has_color_key = ddcaps.dwCaps & DDCAPS_COLORKEY;
536 /* Determine if the hardware supports scaling of the overlay surface */
537 const bool can_stretch = ddcaps.dwCaps & DDCAPS_OVERLAYSTRETCH;
538 /* Determine if the hardware supports color conversion during a blit */
539 sys->can_blit_fourcc = ddcaps.dwCaps & DDCAPS_BLTFOURCC;
540 /* Determine overlay source boundary alignment */
541 const bool align_boundary_src = ddcaps.dwCaps & DDCAPS_ALIGNBOUNDARYSRC;
542 /* Determine overlay destination boundary alignment */
543 const bool align_boundary_dest = ddcaps.dwCaps & DDCAPS_ALIGNBOUNDARYDEST;
544 /* Determine overlay destination size alignment */
545 const bool align_size_src = ddcaps.dwCaps & DDCAPS_ALIGNSIZESRC;
546 /* Determine overlay destination size alignment */
547 const bool align_size_dest = ddcaps.dwCaps & DDCAPS_ALIGNSIZEDEST;
549 msg_Dbg(vd, "DirectDraw Capabilities: overlay=%i yuvoverlay=%i "
550 "can_deinterlace_overlay=%i colorkey=%i stretch=%i "
552 has_overlay, has_overlay_fourcc, can_deinterlace,
553 has_color_key, can_stretch, sys->can_blit_fourcc);
555 if (align_boundary_src || align_boundary_dest || align_size_src || align_size_dest) {
556 if (align_boundary_src)
557 vd->sys->i_align_src_boundary = ddcaps.dwAlignBoundarySrc;
558 if (align_boundary_dest)
559 vd->sys->i_align_dest_boundary = ddcaps.dwAlignBoundaryDest;
561 vd->sys->i_align_src_size = ddcaps.dwAlignSizeSrc;
563 vd->sys->i_align_dest_size = ddcaps.dwAlignSizeDest;
566 "align_boundary_src=%i,%i align_boundary_dest=%i,%i "
567 "align_size_src=%i,%i align_size_dest=%i,%i",
568 align_boundary_src, vd->sys->i_align_src_boundary,
569 align_boundary_dest, vd->sys->i_align_dest_boundary,
570 align_size_src, vd->sys->i_align_src_size,
571 align_size_dest, vd->sys->i_align_dest_size);
578 static int DirectXOpenDDraw(vout_display_t *vd)
580 vout_display_sys_t *sys = vd->sys;
584 HRESULT (WINAPI *OurDirectDrawCreate)(GUID *,LPDIRECTDRAW *,IUnknown *);
585 OurDirectDrawCreate =
586 (void *)GetProcAddress(sys->hddraw_dll, _T("DirectDrawCreate"));
587 if (!OurDirectDrawCreate) {
588 msg_Err(vd, "DirectXInitDDraw failed GetProcAddress");
593 if (sys->MonitorFromWindow) {
594 HRESULT (WINAPI *OurDirectDrawEnumerateEx)(LPDDENUMCALLBACKEXA, LPVOID, DWORD);
595 OurDirectDrawEnumerateEx =
596 (void *)GetProcAddress(sys->hddraw_dll, _T("DirectDrawEnumerateExA"));
598 if (OurDirectDrawEnumerateEx) {
599 char *device = var_GetString(vd, "directx-device");
601 msg_Dbg(vd, "directx-device: %s", device);
605 sys->hmonitor = sys->MonitorFromWindow(sys->hwnd, MONITOR_DEFAULTTONEAREST);
607 /* Enumerate displays */
608 OurDirectDrawEnumerateEx(DirectXOpenDDrawCallback,
609 vd, DDENUM_ATTACHEDSECONDARYDEVICES);
613 /* Initialize DirectDraw now */
614 LPDIRECTDRAW ddobject;
615 hr = OurDirectDrawCreate(sys->display_driver, &ddobject, NULL);
617 msg_Err(vd, "DirectXInitDDraw cannot initialize DDraw");
621 /* Get the IDirectDraw2 interface */
622 hr = IDirectDraw_QueryInterface(ddobject, &IID_IDirectDraw2,
624 /* Release the unused interface */
625 IDirectDraw_Release(ddobject);
628 msg_Err(vd, "cannot get IDirectDraw2 interface");
629 sys->ddobject = NULL;
633 /* Set DirectDraw Cooperative level, ie what control we want over Windows
635 hr = IDirectDraw2_SetCooperativeLevel(sys->ddobject, NULL, DDSCL_NORMAL);
637 msg_Err(vd, "cannot set direct draw cooperative level");
641 /* Get the size of the current display device */
642 if (sys->hmonitor && sys->GetMonitorInfo) {
643 MONITORINFO monitor_info;
644 monitor_info.cbSize = sizeof(MONITORINFO);
645 sys->GetMonitorInfo(vd->sys->hmonitor, &monitor_info);
646 sys->rect_display = monitor_info.rcMonitor;
648 sys->rect_display.left = 0;
649 sys->rect_display.top = 0;
650 sys->rect_display.right = GetSystemMetrics(SM_CXSCREEN);
651 sys->rect_display.bottom = GetSystemMetrics(SM_CYSCREEN);
654 msg_Dbg(vd, "screen dimensions (%lix%li,%lix%li)",
655 sys->rect_display.left,
656 sys->rect_display.top,
657 sys->rect_display.right,
658 sys->rect_display.bottom);
660 /* Probe the capabilities of the hardware */
661 DirectXGetDDrawCaps(vd);
666 static void DirectXCloseDDraw(vout_display_t *vd)
668 vout_display_sys_t *sys = vd->sys;
670 IDirectDraw2_Release(sys->ddobject);
672 sys->ddobject = NULL;
674 free(sys->display_driver);
675 sys->display_driver = NULL;
677 sys->hmonitor = NULL;
681 * Create a clipper that will be used when blitting the RGB surface to the main display.
683 * This clipper prevents us to modify by mistake anything on the screen
684 * which doesn't belong to our window. For example when a part of our video
685 * window is hidden by another window.
687 static void DirectXCreateClipper(vout_display_t *vd)
689 vout_display_sys_t *sys = vd->sys;
692 /* Create the clipper */
693 hr = IDirectDraw2_CreateClipper(sys->ddobject, 0, &sys->clipper, NULL);
695 msg_Warn(vd, "cannot create clipper (error %li)", hr);
699 /* Associate the clipper to the window */
700 hr = IDirectDrawClipper_SetHWnd(sys->clipper, 0, sys->hvideownd);
702 msg_Warn(vd, "cannot attach clipper to window (error %li)", hr);
706 /* associate the clipper with the surface */
707 hr = IDirectDrawSurface_SetClipper(sys->display, sys->clipper);
710 msg_Warn(vd, "cannot attach clipper to surface (error %li)", hr);
718 IDirectDrawClipper_Release(sys->clipper);
723 * It finds out the 32bits RGB pixel value of the colorkey.
725 static uint32_t DirectXFindColorkey(vout_display_t *vd, uint32_t *color)
727 vout_display_sys_t *sys = vd->sys;
732 ddsd.dwSize = sizeof(ddsd);
733 hr = IDirectDrawSurface2_Lock(sys->display, NULL, &ddsd, DDLOCK_WAIT, NULL);
737 uint32_t backup = *(uint32_t *)ddsd.lpSurface;
739 switch (ddsd.ddpfPixelFormat.dwRGBBitCount) {
741 *(uint8_t *)ddsd.lpSurface = *color | (*color << 4);
744 *(uint8_t *)ddsd.lpSurface = *color;
748 *(uint16_t *)ddsd.lpSurface = *color;
751 /* Seems to be problematic so we'll just put black as the colorkey */
754 *(uint32_t *)ddsd.lpSurface = *color;
757 IDirectDrawSurface2_Unlock(sys->display, NULL);
762 if (IDirectDrawSurface2_GetDC(sys->display, &hdc) == DD_OK) {
763 rgb = GetPixel(hdc, 0, 0);
764 IDirectDrawSurface2_ReleaseDC(sys->display, hdc);
769 /* Restore the pixel value */
770 ddsd.dwSize = sizeof(ddsd);
771 if (IDirectDrawSurface2_Lock(sys->display, NULL, &ddsd, DDLOCK_WAIT, NULL) == DD_OK) {
772 *(uint32_t *)ddsd.lpSurface = backup;
773 IDirectDrawSurface2_Unlock(sys->display, NULL);
780 * Create and initialize display according to preferences specified in the vout
783 static int DirectXOpenDisplay(vout_display_t *vd)
785 vout_display_sys_t *sys = vd->sys;
788 /* Now get the primary surface. This surface is what you actually see
791 ZeroMemory(&ddsd, sizeof(ddsd));
792 ddsd.dwSize = sizeof(ddsd);
793 ddsd.dwFlags = DDSD_CAPS;
794 ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
796 LPDIRECTDRAWSURFACE display;
797 hr = IDirectDraw2_CreateSurface(sys->ddobject, &ddsd, &display, NULL);
799 msg_Err(vd, "cannot get primary surface (error %li)", hr);
803 hr = IDirectDrawSurface_QueryInterface(display, &IID_IDirectDrawSurface2,
805 /* Release the old interface */
806 IDirectDrawSurface_Release(display);
809 msg_Err(vd, "cannot query IDirectDrawSurface2 interface (error %li)", hr);
814 /* The clipper will be used only in non-overlay mode */
815 DirectXCreateClipper(vd);
817 /* Make sure the colorkey will be painted */
819 sys->i_rgb_colorkey = DirectXFindColorkey(vd, &sys->i_colorkey);
823 static void DirectXCloseDisplay(vout_display_t *vd)
825 vout_display_sys_t *sys = vd->sys;
827 if (sys->clipper != NULL)
828 IDirectDrawClipper_Release(sys->clipper);
830 if (sys->display != NULL)
831 IDirectDrawSurface2_Release(sys->display);
838 * Create an YUV overlay or RGB surface for the video.
840 * The best method of display is with an YUV overlay because the YUV->RGB
841 * conversion is done in hardware.
842 * You can also create a plain RGB surface.
843 * (Maybe we could also try an RGB overlay surface, which could have hardware
844 * scaling and which would also be faster in window mode because you don't
845 * need to do any blitting to the main display...)
847 static int DirectXCreateSurface(vout_display_t *vd,
848 LPDIRECTDRAWSURFACE2 *surface,
849 const video_format_t *fmt,
853 int backbuffer_count)
855 vout_display_sys_t *sys = vd->sys;
859 ZeroMemory(&ddsd, sizeof(ddsd));
860 ddsd.dwSize = sizeof(ddsd);
861 ddsd.ddpfPixelFormat.dwSize = sizeof(ddsd.ddpfPixelFormat);
862 ddsd.dwFlags = DDSD_HEIGHT | DDSD_WIDTH;
863 ddsd.dwWidth = fmt->i_width;
864 ddsd.dwHeight = fmt->i_height;
866 ddsd.dwFlags |= DDSD_PIXELFORMAT;
867 ddsd.ddpfPixelFormat.dwFlags = DDPF_FOURCC;
868 ddsd.ddpfPixelFormat.dwFourCC = fourcc;
871 ddsd.dwFlags |= DDSD_CAPS;
872 ddsd.ddsCaps.dwCaps = DDSCAPS_OVERLAY | DDSCAPS_VIDEOMEMORY;
873 if (backbuffer_count > 0)
874 ddsd.ddsCaps.dwCaps |= DDSCAPS_COMPLEX | DDSCAPS_FLIP;
876 if (backbuffer_count > 0) {
877 ddsd.dwFlags |= DDSD_BACKBUFFERCOUNT;
878 ddsd.dwBackBufferCount = backbuffer_count;
881 ddsd.dwFlags |= DDSD_CAPS;
882 ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
884 ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
886 ddsd.ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY;
889 /* Create the video surface */
890 LPDIRECTDRAWSURFACE surface_v1;
891 if (IDirectDraw2_CreateSurface(sys->ddobject, &ddsd, &surface_v1, NULL) != DD_OK)
894 /* Now that the surface is created, try to get a newer DirectX interface */
895 HRESULT hr = IDirectDrawSurface_QueryInterface(surface_v1,
896 &IID_IDirectDrawSurface2,
898 IDirectDrawSurface_Release(surface_v1);
900 msg_Err(vd, "cannot query IDirectDrawSurface2 interface (error %li)", hr);
905 /* Check the overlay is useable as some graphics cards allow creating
906 * several overlays but only one can be used at one time. */
907 if (DirectXUpdateOverlay(vd, *surface)) {
908 IDirectDrawSurface2_Release(*surface);
909 msg_Err(vd, "overlay unuseable (might already be in use)");
917 static void DirectXDestroySurface(LPDIRECTDRAWSURFACE2 surface)
919 IDirectDrawSurface2_Release(surface);
922 * This function locks a surface and get the surface descriptor.
924 static int DirectXLockSurface(LPDIRECTDRAWSURFACE2 front_surface,
925 LPDIRECTDRAWSURFACE2 surface,
930 DDSURFACEDESC ddsd_dummy;
934 ZeroMemory(ddsd, sizeof(*ddsd));
935 ddsd->dwSize = sizeof(*ddsd);
936 hr = IDirectDrawSurface2_Lock(surface, NULL, ddsd, DDLOCK_NOSYSLOCK | DDLOCK_WAIT, NULL);
938 if (hr == DDERR_INVALIDPARAMS) {
939 /* DirectX 3 doesn't support the DDLOCK_NOSYSLOCK flag, resulting
940 * in an invalid params error */
941 hr = IDirectDrawSurface2_Lock(surface, NULL, ddsd, DDLOCK_WAIT, NULL);
943 if (hr == DDERR_SURFACELOST) {
944 /* Your surface can be lost so be sure
945 * to check this and restore it if needed */
947 /* When using overlays with back-buffers, we need to restore
948 * the front buffer so the back-buffers get restored as well. */
949 if (front_surface != surface)
950 IDirectDrawSurface2_Restore(front_surface);
952 IDirectDrawSurface2_Restore(surface);
954 hr = IDirectDrawSurface2_Lock(surface, NULL, ddsd, DDLOCK_WAIT, NULL);
961 static void DirectXUnlockSurface(LPDIRECTDRAWSURFACE2 front_surface,
962 LPDIRECTDRAWSURFACE2 surface)
964 IDirectDrawSurface2_Unlock(surface, NULL);
966 static int DirectXCheckLockingSurface(LPDIRECTDRAWSURFACE2 front_surface,
967 LPDIRECTDRAWSURFACE2 surface)
969 if (DirectXLockSurface(front_surface, surface, NULL))
972 DirectXUnlockSurface(front_surface, surface);
983 static DWORD DirectXGetFourcc(vlc_fourcc_t codec)
985 static const dx_format_t dx_formats[] = {
986 { VLC_CODEC_YUYV, MAKEFOURCC('Y','U','Y','2') },
987 { VLC_CODEC_UYVY, MAKEFOURCC('U','Y','V','Y') },
988 { VLC_CODEC_YVYU, MAKEFOURCC('Y','V','Y','U') },
989 { VLC_CODEC_YV12, MAKEFOURCC('Y','V','1','2') },
990 { VLC_CODEC_I420, MAKEFOURCC('Y','V','1','2') },
991 { VLC_CODEC_J420, MAKEFOURCC('Y','V','1','2') },
995 for (unsigned i = 0; dx_formats[i].codec != 0; i++) {
996 if (dx_formats[i].codec == codec)
997 return dx_formats[i].fourcc;
1002 static int DirectXCreatePictureResourceYuvOverlay(vout_display_t *vd,
1003 const video_format_t *fmt,
1006 vout_display_sys_t *sys = vd->sys;
1008 bool allow_3buf = var_InheritBool(vd, "directx-3buffering");
1010 /* The overlay surface that we create won't be used to decode directly
1011 * into it because accessing video memory directly is way to slow (remember
1012 * that pictures are decoded macroblock per macroblock). Instead the video
1013 * will be decoded in picture buffers in system memory which will then be
1014 * memcpy() to the overlay surface. */
1015 LPDIRECTDRAWSURFACE2 front_surface;
1016 int ret = VLC_EGENERIC;
1018 /* Triple buffering rocks! it doesn't have any processing overhead
1019 * (you don't have to wait for the vsync) and provides for a very nice
1020 * video quality (no tearing). */
1021 ret = DirectXCreateSurface(vd, &front_surface, fmt, fourcc, true, false, 2);
1024 ret = DirectXCreateSurface(vd, &front_surface, fmt, fourcc, true, false, 0);
1026 return VLC_EGENERIC;
1027 msg_Dbg(vd, "YUV overlay surface created successfully");
1029 /* Get the back buffer */
1030 LPDIRECTDRAWSURFACE2 surface;
1032 ZeroMemory(&dds_caps, sizeof(dds_caps));
1033 dds_caps.dwCaps = DDSCAPS_BACKBUFFER;
1034 if (IDirectDrawSurface2_GetAttachedSurface(front_surface, &dds_caps, &surface) != DD_OK) {
1035 msg_Warn(vd, "Failed to get surface back buffer");
1036 /* front buffer is the same as back buffer */
1037 surface = front_surface;
1040 if (DirectXCheckLockingSurface(front_surface, surface)) {
1041 DirectXDestroySurface(front_surface);
1042 return VLC_EGENERIC;
1046 picture_resource_t *rsc = &sys->resource;
1047 rsc->p_sys->front_surface = front_surface;
1048 rsc->p_sys->surface = surface;
1051 static int DirectXCreatePictureResourceYuv(vout_display_t *vd,
1052 const video_format_t *fmt,
1055 vout_display_sys_t *sys = vd->sys;
1057 bool allow_sysmem = var_InheritBool(vd, "directx-use-sysmem");
1059 /* As we can't have an overlay, we'll try to create a plain offscreen
1060 * surface. This surface will reside in video memory because there's a
1061 * better chance then that we'll be able to use some kind of hardware
1062 * acceleration like rescaling, blitting or YUV->RGB conversions.
1063 * We then only need to blit this surface onto the main display when we
1064 * want to display it */
1066 /* Check if the chroma is supported first. This is required
1067 * because a few buggy drivers don't mind creating the surface
1068 * even if they don't know about the chroma. */
1070 if (IDirectDraw2_GetFourCCCodes(sys->ddobject, &count, NULL) != DD_OK)
1071 return VLC_EGENERIC;
1073 DWORD *list = calloc(count, sizeof(*list));
1076 if (IDirectDraw2_GetFourCCCodes(sys->ddobject, &count, list) != DD_OK) {
1078 return VLC_EGENERIC;
1081 for (index = 0; index < count; index++) {
1082 if (list[index] == fourcc)
1087 return VLC_EGENERIC;
1090 LPDIRECTDRAWSURFACE2 surface;
1091 if (DirectXCreateSurface(vd, &surface, fmt, fourcc, false, allow_sysmem, 0))
1092 return VLC_EGENERIC;
1093 msg_Dbg(vd, "YUV plain surface created successfully");
1095 if (DirectXCheckLockingSurface(surface, surface)) {
1096 DirectXDestroySurface(surface);
1097 return VLC_EGENERIC;
1101 picture_resource_t *rsc = &sys->resource;
1102 rsc->p_sys->front_surface = surface;
1103 rsc->p_sys->surface = surface;
1106 static int DirectXCreatePictureResourceRgb(vout_display_t *vd,
1107 video_format_t *fmt)
1109 vout_display_sys_t *sys = vd->sys;
1110 bool allow_sysmem = var_InheritBool(vd, "directx-use-sysmem");
1112 /* Our last choice is to use a plain RGB surface */
1113 DDPIXELFORMAT ddpfPixelFormat;
1114 ZeroMemory(&ddpfPixelFormat, sizeof(ddpfPixelFormat));
1115 ddpfPixelFormat.dwSize = sizeof(ddpfPixelFormat);
1117 IDirectDrawSurface2_GetPixelFormat(sys->display, &ddpfPixelFormat);
1118 if ((ddpfPixelFormat.dwFlags & DDPF_RGB) == 0)
1119 return VLC_EGENERIC;
1121 switch (ddpfPixelFormat.dwRGBBitCount) {
1123 fmt->i_chroma = VLC_CODEC_RGB8;
1126 fmt->i_chroma = VLC_CODEC_RGB15;
1129 fmt->i_chroma = VLC_CODEC_RGB16;
1132 fmt->i_chroma = VLC_CODEC_RGB24;
1135 fmt->i_chroma = VLC_CODEC_RGB32;
1138 msg_Err(vd, "unknown screen depth");
1139 return VLC_EGENERIC;
1141 fmt->i_rmask = ddpfPixelFormat.dwRBitMask;
1142 fmt->i_gmask = ddpfPixelFormat.dwGBitMask;
1143 fmt->i_bmask = ddpfPixelFormat.dwBBitMask;
1146 LPDIRECTDRAWSURFACE2 surface;
1147 int ret = DirectXCreateSurface(vd, &surface, fmt, 0, false, allow_sysmem, 0);
1148 if (ret && !allow_sysmem)
1149 ret = DirectXCreateSurface(vd, &surface, fmt, 0, false, true, 0);
1151 return VLC_EGENERIC;
1152 msg_Dbg(vd, "RGB plain surface created successfully");
1154 if (DirectXCheckLockingSurface(surface, surface)) {
1155 DirectXDestroySurface(surface);
1156 return VLC_EGENERIC;
1160 picture_resource_t *rsc = &sys->resource;
1161 rsc->p_sys->front_surface = surface;
1162 rsc->p_sys->surface = surface;
1166 static int DirectXCreatePictureResource(vout_display_t *vd,
1168 video_format_t *fmt)
1170 vout_display_sys_t *sys = vd->sys;
1173 picture_resource_t *rsc = &sys->resource;
1174 rsc->p_sys = calloc(1, sizeof(*rsc->p_sys));
1179 bool allow_hw_yuv = sys->can_blit_fourcc &&
1180 vlc_fourcc_IsYUV(fmt->i_chroma) &&
1181 var_InheritBool(vd, "directx-hw-yuv");
1182 bool allow_overlay = var_InheritBool(vd, "overlay");
1184 /* Try to use an yuv surface */
1186 const vlc_fourcc_t *list = vlc_fourcc_GetYUVFallback(fmt->i_chroma);
1187 /* Try with overlay first */
1188 for (unsigned pass = allow_overlay ? 0 : 1; pass < 2; pass++) {
1189 for (unsigned i = 0; list[i] != 0; i++) {
1190 const DWORD fourcc = DirectXGetFourcc(list[i]);
1195 if (DirectXCreatePictureResourceYuvOverlay(vd, fmt, fourcc))
1198 if (DirectXCreatePictureResourceYuv(vd, fmt, fourcc))
1202 *use_overlay = pass == 0;
1203 fmt->i_chroma = list[i];
1210 return DirectXCreatePictureResourceRgb(vd, fmt);
1212 static void DirectXDestroyPictureResource(vout_display_t *vd)
1214 vout_display_sys_t *sys = vd->sys;
1216 DirectXDestroySurface(sys->resource.p_sys->front_surface);
1219 static int DirectXLock(picture_t *picture)
1222 if (DirectXLockSurface(picture->p_sys->front_surface,
1223 picture->p_sys->surface, &ddsd))
1224 return VLC_EGENERIC;
1226 /* fill in buffer info in first plane */
1227 picture->p->p_pixels = ddsd.lpSurface;
1228 picture->p->i_pitch = ddsd.lPitch;
1229 picture->p->i_lines = picture->format.i_height;
1231 /* Fill chroma planes for planar YUV */
1232 if (picture->format.i_chroma == VLC_CODEC_I420 ||
1233 picture->format.i_chroma == VLC_CODEC_J420 ||
1234 picture->format.i_chroma == VLC_CODEC_YV12) {
1236 for (int n = 1; n < picture->i_planes; n++) {
1237 const plane_t *o = &picture->p[n-1];
1238 plane_t *p = &picture->p[n];
1240 p->p_pixels = o->p_pixels + o->i_lines * o->i_pitch;
1241 p->i_pitch = ddsd.lPitch / 2;
1242 p->i_lines = picture->format.i_height / 2;
1244 /* The dx buffer is always allocated as YV12 */
1245 if (vlc_fourcc_AreUVPlanesSwapped(picture->format.i_chroma, VLC_CODEC_YV12)) {
1246 uint8_t *p_tmp = picture->p[1].p_pixels;
1247 picture->p[1].p_pixels = picture->p[2].p_pixels;
1248 picture->p[2].p_pixels = p_tmp;
1253 static void DirectXUnlock(picture_t *picture)
1255 DirectXUnlockSurface(picture->p_sys->front_surface,
1256 picture->p_sys->surface);
1259 static int DirectXCreatePool(vout_display_t *vd,
1260 bool *use_overlay, video_format_t *fmt)
1262 vout_display_sys_t *sys = vd->sys;
1267 if (DirectXCreatePictureResource(vd, use_overlay, fmt))
1268 return VLC_EGENERIC;
1270 /* Create the associated picture */
1271 picture_resource_t *rsc = &sys->resource;
1272 for (int i = 0; i < PICTURE_PLANE_MAX; i++) {
1273 rsc->p[i].p_pixels = NULL;
1274 rsc->p[i].i_pitch = 0;
1275 rsc->p[i].i_lines = 0;
1277 picture_t *picture = picture_NewFromResource(fmt, rsc);
1279 DirectXDestroyPictureResource(vd);
1284 /* Wrap it into a picture pool */
1285 picture_pool_configuration_t cfg;
1286 memset(&cfg, 0, sizeof(cfg));
1287 cfg.picture_count = 1;
1288 cfg.picture = &picture;
1289 cfg.lock = DirectXLock;
1290 cfg.unlock = DirectXUnlock;
1292 sys->pool = picture_pool_NewExtended(&cfg);
1294 picture_Release(picture);
1295 DirectXDestroyPictureResource(vd);
1300 static void DirectXDestroyPool(vout_display_t *vd)
1302 vout_display_sys_t *sys = vd->sys;
1305 DirectXDestroyPictureResource(vd);
1306 picture_pool_Delete(sys->pool);
1312 * Move or resize overlay surface on video display.
1314 * This function is used to move or resize an overlay surface on the screen.
1315 * Ususally the overlay is moved by the user and thus, by a move or resize
1318 static int DirectXUpdateOverlay(vout_display_t *vd, LPDIRECTDRAWSURFACE2 surface)
1320 vout_display_sys_t *sys = vd->sys;
1322 RECT src = sys->rect_src_clipped;
1323 RECT dst = sys->rect_dest_clipped;
1325 if (sys->use_wallpaper) {
1326 src.left = vd->source.i_x_offset;
1327 src.top = vd->source.i_y_offset;
1328 src.right = vd->source.i_x_offset + vd->source.i_visible_width;
1329 src.bottom = vd->source.i_y_offset + vd->source.i_visible_height;
1330 AlignRect(&src, sys->i_align_src_boundary, sys->i_align_src_size);
1332 vout_display_cfg_t cfg = *vd->cfg;
1333 cfg.display.width = sys->rect_display.right;
1334 cfg.display.height = sys->rect_display.bottom;
1336 vout_display_place_t place;
1337 vout_display_PlacePicture(&place, &vd->source, &cfg, true);
1339 dst.left = sys->rect_display.left + place.x;
1340 dst.top = sys->rect_display.top + place.y;
1341 dst.right = dst.left + place.width;
1342 dst.bottom = dst.top + place.height;
1343 AlignRect(&dst, sys->i_align_dest_boundary, sys->i_align_dest_size);
1348 return VLC_EGENERIC;
1349 surface = sys->resource.p_sys->front_surface;
1352 /* The new window dimensions should already have been computed by the
1353 * caller of this function */
1355 /* Position and show the overlay */
1357 ZeroMemory(&ddofx, sizeof(ddofx));
1358 ddofx.dwSize = sizeof(ddofx);
1359 ddofx.dckDestColorkey.dwColorSpaceLowValue = sys->i_colorkey;
1360 ddofx.dckDestColorkey.dwColorSpaceHighValue = sys->i_colorkey;
1362 HRESULT hr = IDirectDrawSurface2_UpdateOverlay(surface,
1363 &src, sys->display, &dst,
1364 DDOVER_SHOW | DDOVER_KEYDESTOVERRIDE, &ddofx);
1366 msg_Warn(vd, "DirectDrawUpdateOverlay cannot move/resize overlay");
1367 return VLC_EGENERIC;
1373 static void WallpaperChange(vout_display_t *vd, bool use_wallpaper)
1375 vout_display_sys_t *sys = vd->sys;
1377 if (!sys->use_wallpaper == !use_wallpaper)
1380 HWND hwnd = FindWindow(_T("Progman"), NULL);
1382 hwnd = FindWindowEx(hwnd, NULL, _T("SHELLDLL_DefView"), NULL);
1384 hwnd = FindWindowEx(hwnd, NULL, _T("SysListView32"), NULL);
1386 msg_Warn(vd, "couldn't find \"SysListView32\" window, "
1387 "wallpaper mode not supported");
1391 msg_Dbg(vd, "wallpaper mode %s", use_wallpaper ? "enabled" : "disabled");
1392 sys->use_wallpaper = use_wallpaper;
1394 if (sys->use_wallpaper) {
1395 sys->color_bkg = ListView_GetBkColor(hwnd);
1396 sys->color_bkgtxt = ListView_GetTextBkColor(hwnd);
1398 ListView_SetBkColor(hwnd, sys->i_rgb_colorkey);
1399 ListView_SetTextBkColor(hwnd, sys->i_rgb_colorkey);
1401 ListView_SetBkColor(hwnd, sys->color_bkg);
1402 ListView_SetTextBkColor(hwnd, sys->color_bkgtxt);
1405 /* Update desktop */
1406 InvalidateRect(hwnd, NULL, TRUE);
1409 if (sys->use_overlay)
1410 DirectXUpdateOverlay(vd, NULL);
1414 static int WallpaperCallback(vlc_object_t *object, char const *cmd,
1415 vlc_value_t oldval, vlc_value_t newval, void *data)
1417 vout_display_t *vd = (vout_display_t *)object;
1418 vout_display_sys_t *sys = vd->sys;
1419 VLC_UNUSED(cmd); VLC_UNUSED(oldval); VLC_UNUSED(data);
1421 vlc_mutex_lock(&sys->lock);
1422 const bool ch_wallpaper = !sys->wallpaper_requested != !newval.b_bool;
1423 sys->ch_wallpaper |= ch_wallpaper;
1424 sys->wallpaper_requested = newval.b_bool;
1425 vlc_mutex_unlock(&sys->lock);
1427 /* FIXME we should have a way to export variable to be saved */
1429 playlist_t *p_playlist = pl_Get(vd);
1430 /* Modify playlist as well because the vout might have to be
1432 var_Create(p_playlist, "video-wallpaper", VLC_VAR_BOOL);
1433 var_SetBool(p_playlist, "video-wallpaper", newval.b_bool);
1438 /*****************************************************************************
1439 * config variable callback
1440 *****************************************************************************/
1441 static BOOL WINAPI DirectXEnumCallback2(GUID *guid, LPTSTR desc,
1442 LPTSTR drivername, VOID *context,
1445 VLC_UNUSED(guid); VLC_UNUSED(desc); VLC_UNUSED(hmon);
1447 module_config_t *item = context;
1449 item->ppsz_list = xrealloc(item->ppsz_list,
1450 (item->i_list+2) * sizeof(char *));
1451 item->ppsz_list_text = xrealloc(item->ppsz_list_text,
1452 (item->i_list+2) * sizeof(char *));
1454 item->ppsz_list[item->i_list] = strdup(drivername);
1455 item->ppsz_list_text[item->i_list] = NULL;
1457 item->ppsz_list[item->i_list] = NULL;
1458 item->ppsz_list_text[item->i_list] = NULL;
1460 return TRUE; /* Keep enumerating */
1463 static int FindDevicesCallback(vlc_object_t *object, char const *name,
1464 vlc_value_t newval, vlc_value_t oldval, void *data)
1466 VLC_UNUSED(newval); VLC_UNUSED(oldval); VLC_UNUSED(data);
1468 module_config_t *item = config_FindConfig(object, name);
1472 /* Clear-up the current list */
1473 if (item->i_list > 0) {
1475 /* Keep the first entry */
1476 for (i = 1; i < item->i_list; i++) {
1477 free(item->ppsz_list[i]);
1478 free(item->ppsz_list_text[i]);
1480 /* TODO: Remove when no more needed */
1481 item->ppsz_list[i] = NULL;
1482 item->ppsz_list_text[i] = NULL;
1486 /* Load direct draw DLL */
1487 HINSTANCE hddraw_dll = LoadLibrary(_T("DDRAW.DLL"));
1491 /* Enumerate displays */
1492 HRESULT (WINAPI *OurDirectDrawEnumerateEx)(LPDDENUMCALLBACKEXA,
1494 (void *)GetProcAddress(hddraw_dll, _T("DirectDrawEnumerateExA"));
1495 if (OurDirectDrawEnumerateEx)
1496 OurDirectDrawEnumerateEx(DirectXEnumCallback2, item,
1497 DDENUM_ATTACHEDSECONDARYDEVICES);
1499 FreeLibrary(hddraw_dll);
1501 /* Signal change to the interface */
1502 item->b_dirty = true;