]> git.sesse.net Git - vlc/blob - modules/video_output/directx/directx.c
3971dcc439cfaff93de734719812ba22e9f4ae69
[vlc] / modules / video_output / directx / directx.c
1 /*****************************************************************************
2  * vout.c: Windows DirectX video output display method
3  *****************************************************************************
4  * Copyright (C) 2001 VideoLAN
5  * $Id: directx.c,v 1.30 2003/12/23 02:11:27 gbazin Exp $
6  *
7  * Authors: Gildas Bazin <gbazin@netcourrier.com>
8  *
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.
13  *
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.
18  *
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., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble:
26  *
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.
30  *
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.
35  *
36  *****************************************************************************/
37 #include <errno.h>                                                 /* ENOMEM */
38 #include <stdlib.h>                                                /* free() */
39 #include <string.h>                                            /* strerror() */
40
41 #include <vlc/vlc.h>
42 #include <vlc/intf.h>
43 #include <vlc/vout.h>
44
45 #include <windows.h>
46 #include <ddraw.h>
47
48 #include <multimon.h>
49 #undef GetSystemMetrics
50
51 #ifndef MONITOR_DEFAULTTONEAREST
52 #   define MONITOR_DEFAULTTONEAREST 2
53 #endif
54
55 #include "vout.h"
56
57 /*****************************************************************************
58  * DirectDraw GUIDs.
59  * Defining them here allows us to get rid of the dxguid library during
60  * the linking stage.
61  *****************************************************************************/
62 #include <initguid.h>
63 DEFINE_GUID( IID_IDirectDraw2, 0xB3A6F3E0,0x2B43,0x11CF,0xA2,0xDE,0x00,0xAA,0x00,0xB9,0x33,0x56 );
64 DEFINE_GUID( IID_IDirectDrawSurface2, 0x57805885,0x6eec,0x11cf,0x94,0x41,0xa8,0x23,0x03,0xc1,0x0e,0x27 );
65
66 /*****************************************************************************
67  * Local prototypes.
68  *****************************************************************************/
69 static int  OpenVideo  ( vlc_object_t * );
70 static void CloseVideo ( vlc_object_t * );
71
72 static int  Init      ( vout_thread_t * );
73 static void End       ( vout_thread_t * );
74 static int  Manage    ( vout_thread_t * );
75 static void Display   ( vout_thread_t *, picture_t * );
76
77 static int  NewPictureVec  ( vout_thread_t *, picture_t *, int );
78 static void FreePictureVec ( vout_thread_t *, picture_t *, int );
79 static int  UpdatePictureStruct( vout_thread_t *, picture_t *, int );
80
81 static int  DirectXInitDDraw      ( vout_thread_t *p_vout );
82 static void DirectXCloseDDraw     ( vout_thread_t *p_vout );
83 static int  DirectXCreateDisplay  ( vout_thread_t *p_vout );
84 static void DirectXCloseDisplay   ( vout_thread_t *p_vout );
85 static int  DirectXCreateSurface  ( vout_thread_t *p_vout,
86                                     LPDIRECTDRAWSURFACE2 *, int, int, int );
87 static void DirectXCloseSurface   ( vout_thread_t *p_vout,
88                                     LPDIRECTDRAWSURFACE2 );
89 static int  DirectXCreateClipper  ( vout_thread_t *p_vout );
90 static void DirectXGetDDrawCaps   ( vout_thread_t *p_vout );
91 static int  DirectXLockSurface    ( vout_thread_t *p_vout, picture_t *p_pic );
92 static int  DirectXUnlockSurface  ( vout_thread_t *p_vout, picture_t *p_pic );
93
94 static DWORD DirectXFindColorkey( vout_thread_t *p_vout, uint32_t i_color );
95
96 /* Object variables callbacks */
97 static int OnTopCallback( vlc_object_t *, char const *,
98                           vlc_value_t, vlc_value_t, void * );
99
100 /*****************************************************************************
101  * Module descriptor
102  *****************************************************************************/
103 #define HW_YUV_TEXT N_("Use hardware YUV->RGB conversions")
104 #define HW_YUV_LONGTEXT N_( \
105     "Try to use hardware acceleration for YUV->RGB conversions. " \
106     "This option doesn't have any effect when using overlays." )
107 #define SYSMEM_TEXT N_("Use video buffers in system memory")
108 #define SYSMEM_LONGTEXT N_( \
109     "Create video buffers in system memory instead of video memory. This " \
110     "isn't recommended as usually using video memory allows to benefit from " \
111     "more hardware acceleration (like rescaling or YUV->RGB conversions). " \
112     "This option doesn't have any effect when using overlays." )
113 #define TRIPLEBUF_TEXT N_("Use triple buffering for overlays")
114 #define TRIPLEBUF_LONGTEXT N_( \
115     "Try to use triple bufferring when using YUV overlays. That results in " \
116     "much better video quality (no flickering)." )
117
118 vlc_module_begin();
119     add_category_hint( N_("Video"), NULL, VLC_FALSE );
120     add_bool( "directx-hw-yuv", 1, NULL, HW_YUV_TEXT, HW_YUV_LONGTEXT, VLC_TRUE );
121     add_bool( "directx-use-sysmem", 0, NULL, SYSMEM_TEXT, SYSMEM_LONGTEXT, VLC_TRUE );
122     add_bool( "directx-3buffering", 1, NULL, TRIPLEBUF_TEXT, TRIPLEBUF_LONGTEXT, VLC_TRUE );
123     set_description( _("DirectX video output") );
124     set_capability( "video output", 100 );
125     add_shortcut( "directx" );
126     set_callbacks( OpenVideo, CloseVideo );
127 vlc_module_end();
128
129 #if 0 /* FIXME */
130     /* check if we registered a window class because we need to
131      * unregister it */
132     WNDCLASS wndclass;
133     if( GetClassInfo( GetModuleHandle(NULL), "VLC DirectX", &wndclass ) )
134         UnregisterClass( "VLC DirectX", GetModuleHandle(NULL) );
135 #endif
136
137 /*****************************************************************************
138  * OpenVideo: allocate DirectX video thread output method
139  *****************************************************************************
140  * This function allocates and initialize the DirectX vout method.
141  *****************************************************************************/
142 static int OpenVideo( vlc_object_t *p_this )
143 {
144     vout_thread_t * p_vout = (vout_thread_t *)p_this;
145     vlc_value_t val, text;
146     HMODULE huser32;
147
148     /* Allocate structure */
149     p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
150     if( p_vout->p_sys == NULL )
151     {
152         msg_Err( p_vout, "out of memory" );
153         return VLC_ENOMEM;
154     }
155
156     /* Initialisations */
157     p_vout->pf_init = Init;
158     p_vout->pf_end = End;
159     p_vout->pf_manage = Manage;
160     p_vout->pf_render = NULL;
161     p_vout->pf_display = Display;
162
163     p_vout->p_sys->p_ddobject = NULL;
164     p_vout->p_sys->p_display = NULL;
165     p_vout->p_sys->p_current_surface = NULL;
166     p_vout->p_sys->p_clipper = NULL;
167     p_vout->p_sys->hwnd = NULL;
168     p_vout->p_sys->hparent = NULL;
169     p_vout->p_sys->i_changes = 0;
170
171     /* Multimonitor stuff */
172     p_vout->p_sys->hmonitor = NULL;
173     p_vout->p_sys->p_display_driver = NULL;
174     p_vout->p_sys->MonitorFromWindow = NULL;
175     p_vout->p_sys->GetMonitorInfo = NULL;
176     if( (huser32 = GetModuleHandle( "USER32" ) ) )
177     {
178         p_vout->p_sys->MonitorFromWindow =
179             GetProcAddress( huser32, "MonitorFromWindow" );
180         p_vout->p_sys->GetMonitorInfo =
181             GetProcAddress( huser32, "GetMonitorInfoA" );
182     }
183
184     var_Create( p_vout, "overlay", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
185     var_Create( p_vout, "directx-use-sysmem", VLC_VAR_BOOL|VLC_VAR_DOINHERIT );
186     var_Create( p_vout, "directx-hw-yuv", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
187     var_Create( p_vout, "directx-3buffering", VLC_VAR_BOOL|VLC_VAR_DOINHERIT );
188
189     p_vout->p_sys->b_cursor_hidden = 0;
190     p_vout->p_sys->i_lastmoved = mdate();
191
192     /* Set main window's size */
193     p_vout->p_sys->i_window_width = p_vout->i_window_width;
194     p_vout->p_sys->i_window_height = p_vout->i_window_height;
195
196     /* Create the DirectXEventThread, this thread is created by us to isolate
197      * the Win32 PeekMessage function calls. We want to do this because
198      * Windows can stay blocked inside this call for a long time, and when
199      * this happens it thus blocks vlc's video_output thread.
200      * DirectXEventThread will take care of the creation of the video
201      * window (because PeekMessage has to be called from the same thread which
202      * created the window). */
203     msg_Dbg( p_vout, "creating DirectXEventThread" );
204     p_vout->p_sys->p_event =
205         vlc_object_create( p_vout, sizeof(event_thread_t) );
206     p_vout->p_sys->p_event->p_vout = p_vout;
207     if( vlc_thread_create( p_vout->p_sys->p_event, "DirectX Events Thread",
208                            DirectXEventThread, 0, 1 ) )
209     {
210         msg_Err( p_vout, "cannot create DirectXEventThread" );
211         vlc_object_destroy( p_vout->p_sys->p_event );
212         p_vout->p_sys->p_event = NULL;
213         goto error;
214     }
215
216     if( p_vout->p_sys->p_event->b_error )
217     {
218         msg_Err( p_vout, "DirectXEventThread failed" );
219         goto error;
220     }
221
222     vlc_object_attach( p_vout->p_sys->p_event, p_vout );
223
224     msg_Dbg( p_vout, "DirectXEventThread running" );
225
226     /* Initialise DirectDraw */
227     if( DirectXInitDDraw( p_vout ) )
228     {
229         msg_Err( p_vout, "cannot initialize DirectDraw" );
230         goto error;
231     }
232
233     /* Create the directx display */
234     if( DirectXCreateDisplay( p_vout ) )
235     {
236         msg_Err( p_vout, "cannot initialize DirectDraw" );
237         goto error;
238     }
239
240     /* Add a variable to indicate if the window should be on top of others */
241     var_Create( p_vout, "video-on-top", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
242     text.psz_string = _("Always on top");
243     var_Change( p_vout, "video-on-top", VLC_VAR_SETTEXT, &text, NULL );
244     var_Get( p_vout, "video-on-top", &val );
245     p_vout->p_sys->b_on_top_change = val.b_bool; 
246     var_AddCallback( p_vout, "video-on-top", OnTopCallback, NULL );
247
248     return VLC_SUCCESS;
249
250  error:
251     CloseVideo( VLC_OBJECT(p_vout) );
252     return VLC_EGENERIC;
253 }
254
255 /*****************************************************************************
256  * Init: initialize DirectX video thread output method
257  *****************************************************************************
258  * This function create the directx surfaces needed by the output thread.
259  * It is called at the beginning of the thread.
260  *****************************************************************************/
261 static int Init( vout_thread_t *p_vout )
262 {
263     int i_chroma_backup;
264     vlc_value_t val;
265
266     /* Get a few default parameters */
267     var_Get( p_vout, "overlay", &val );
268     p_vout->p_sys->b_using_overlay = val.b_bool;
269     var_Get( p_vout, "directx-use-sysmem", &val );
270     p_vout->p_sys->b_use_sysmem = val.b_bool;
271     var_Get( p_vout, "directx-hw-yuv", &val );
272     p_vout->p_sys->b_hw_yuv = val.b_bool;
273     var_Get( p_vout, "directx-3buffering", &val );
274     p_vout->p_sys->b_3buf_overlay = val.b_bool;
275
276     /* Initialise DirectDraw if not already done.
277      * We do this here because on multi-monitor systems we may have to
278      * re-create the directdraw surfaces. */
279     if( !p_vout->p_sys->p_ddobject &&
280         DirectXInitDDraw( p_vout ) != VLC_SUCCESS )
281     {
282         msg_Err( p_vout, "cannot initialize DirectDraw" );
283         return VLC_EGENERIC;
284     }
285
286     /* Create the directx display */
287     if( !p_vout->p_sys->p_display &&
288         DirectXCreateDisplay( p_vout ) != VLC_SUCCESS )
289     {
290         msg_Err( p_vout, "cannot initialize DirectDraw" );
291         return VLC_EGENERIC;
292     }
293
294     /* Initialize the output structure.
295      * Since DirectDraw can do rescaling for us, stick to the default
296      * coordinates and aspect. */
297     p_vout->output.i_width  = p_vout->render.i_width;
298     p_vout->output.i_height = p_vout->render.i_height;
299     p_vout->output.i_aspect = p_vout->render.i_aspect;
300
301 #define MAX_DIRECTBUFFERS 1
302     /* Right now we use only 1 directbuffer because we don't want the
303      * video decoder to decode directly into direct buffers as they are
304      * created into video memory and video memory is _really_ slow */
305
306     /* Choose the chroma we will try first. */
307     switch( p_vout->render.i_chroma )
308     {
309         case VLC_FOURCC('Y','U','Y','2'):
310         case VLC_FOURCC('Y','U','N','V'):
311             p_vout->output.i_chroma = VLC_FOURCC('Y','U','Y','2');
312             break;
313         case VLC_FOURCC('U','Y','V','Y'):
314         case VLC_FOURCC('U','Y','N','V'):
315         case VLC_FOURCC('Y','4','2','2'):
316             p_vout->output.i_chroma = VLC_FOURCC('U','Y','V','Y');
317             break;
318         case VLC_FOURCC('Y','V','Y','U'):
319             p_vout->output.i_chroma = VLC_FOURCC('Y','V','Y','U');
320             break;
321         default:
322             p_vout->output.i_chroma = VLC_FOURCC('Y','V','1','2');
323             break;
324     }
325
326     NewPictureVec( p_vout, p_vout->p_picture, MAX_DIRECTBUFFERS );
327
328     i_chroma_backup = p_vout->output.i_chroma;
329
330     if( !I_OUTPUTPICTURES )
331     {
332         /* hmmm, it didn't work! Let's try commonly supported chromas */
333         if( p_vout->output.i_chroma != VLC_FOURCC('Y','V','1','2') )
334         {
335             p_vout->output.i_chroma = VLC_FOURCC('Y','V','1','2');
336             NewPictureVec( p_vout, p_vout->p_picture, MAX_DIRECTBUFFERS );
337         }
338         if( !I_OUTPUTPICTURES )
339         {
340             /* hmmm, it still didn't work! Let's try another one */
341             p_vout->output.i_chroma = VLC_FOURCC('Y','U','Y','2');
342             NewPictureVec( p_vout, p_vout->p_picture, MAX_DIRECTBUFFERS );
343         }
344     }
345
346     if( !I_OUTPUTPICTURES )
347     {
348         /* If it still didn't work then don't try to use an overlay */
349         p_vout->output.i_chroma = i_chroma_backup;
350         p_vout->p_sys->b_using_overlay = 0;
351         NewPictureVec( p_vout, p_vout->p_picture, MAX_DIRECTBUFFERS );
352     }
353
354     /* Change the window title bar text */
355     if( p_vout->p_sys->hparent ) ; /* Do nothing */
356     else PostMessage( p_vout->p_sys->hwnd, WM_VLC_CHANGE_TEXT, 0, 0 );
357
358     return VLC_SUCCESS;
359 }
360
361 /*****************************************************************************
362  * End: terminate Sys video thread output method
363  *****************************************************************************
364  * Terminate an output method created by Create.
365  * It is called at the end of the thread.
366  *****************************************************************************/
367 static void End( vout_thread_t *p_vout )
368 {
369     FreePictureVec( p_vout, p_vout->p_picture, I_OUTPUTPICTURES );
370
371     DirectXCloseDisplay( p_vout );
372     DirectXCloseDDraw( p_vout );
373
374     return;
375 }
376
377 /*****************************************************************************
378  * CloseVideo: destroy Sys video thread output method
379  *****************************************************************************
380  * Terminate an output method created by Create
381  *****************************************************************************/
382 static void CloseVideo( vlc_object_t *p_this )
383 {
384     vout_thread_t * p_vout = (vout_thread_t *)p_this;
385
386     msg_Dbg( p_vout, "CloseVideo" );
387
388     var_Destroy( p_vout, "video-on-top" );
389
390     if( p_vout->p_sys->p_event )
391     {
392         vlc_object_detach( p_vout->p_sys->p_event );
393
394         /* Kill DirectXEventThread */
395         p_vout->p_sys->p_event->b_die = VLC_TRUE;
396
397         /* we need to be sure DirectXEventThread won't stay stuck in
398          * GetMessage, so we send a fake message */
399         if( p_vout->p_sys->hwnd )
400         {
401             PostMessage( p_vout->p_sys->hwnd, WM_NULL, 0, 0);
402         }
403
404         vlc_thread_join( p_vout->p_sys->p_event );
405         vlc_object_destroy( p_vout->p_sys->p_event );
406     }
407
408     if( p_vout->p_sys )
409     {
410         free( p_vout->p_sys );
411         p_vout->p_sys = NULL;
412     }
413 }
414
415 /*****************************************************************************
416  * Manage: handle Sys events
417  *****************************************************************************
418  * This function should be called regularly by the video output thread.
419  * It returns a non null value if an error occured.
420  *****************************************************************************/
421 static int Manage( vout_thread_t *p_vout )
422 {
423     WINDOWPLACEMENT window_placement;
424
425     /* If we do not control our window, we check for geometry changes
426      * ourselves because the parent might not send us its events. */
427     if( p_vout->p_sys->hparent )
428     {
429         DirectXUpdateRects( p_vout, VLC_FALSE );
430     }
431
432     /*
433      * Position Change
434      */
435     if( p_vout->p_sys->i_changes & DX_POSITION_CHANGE )
436     {
437         if( p_vout->p_sys->b_using_overlay )
438             DirectXUpdateOverlay( p_vout );
439
440         /* Check if we are still on the same monitor */
441         if( p_vout->p_sys->MonitorFromWindow &&
442             p_vout->p_sys->hmonitor !=
443                 p_vout->p_sys->MonitorFromWindow( p_vout->p_sys->hwnd,
444                                                   MONITOR_DEFAULTTONEAREST ) )
445         {
446             /* This will force the vout core to recreate the picture buffers */
447             p_vout->i_changes |= VOUT_PICTURE_BUFFERS_CHANGE;
448         }
449
450         p_vout->p_sys->i_changes &= ~DX_POSITION_CHANGE;
451     }
452
453     /* We used to call the Win32 PeekMessage function here to read the window
454      * messages. But since window can stay blocked into this function for a
455      * long time (for example when you move your window on the screen), I
456      * decided to isolate PeekMessage in another thread. */
457
458     /*
459      * Fullscreen change
460      */
461     if( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE
462         || p_vout->p_sys->i_changes & VOUT_FULLSCREEN_CHANGE )
463     {
464         vlc_value_t val;
465
466         p_vout->b_fullscreen = ! p_vout->b_fullscreen;
467
468         /* We need to switch between Maximized and Normal sized window */
469         window_placement.length = sizeof(WINDOWPLACEMENT);
470         GetWindowPlacement( p_vout->p_sys->hwnd, &window_placement );
471         if( p_vout->b_fullscreen )
472         {
473             /* Maximized window */
474             window_placement.showCmd = SW_SHOWMAXIMIZED;
475             /* Change window style, no borders and no title bar */
476             SetWindowLong( p_vout->p_sys->hwnd, GWL_STYLE, WS_CLIPCHILDREN );
477
478         }
479         else
480         {
481             /* Normal window */
482             window_placement.showCmd = SW_SHOWNORMAL;
483             /* Change window style, borders and title bar */
484             SetWindowLong( p_vout->p_sys->hwnd, GWL_STYLE, WS_CLIPCHILDREN |
485                            WS_OVERLAPPEDWINDOW | WS_SIZEBOX | WS_VISIBLE );
486         }
487
488         SetWindowPlacement( p_vout->p_sys->hwnd, &window_placement );
489
490         /* Update the object variable and trigger callback */
491         val.b_bool = p_vout->b_fullscreen;
492         var_Set( p_vout, "fullscreen", val );
493
494         p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
495         p_vout->p_sys->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
496     }
497
498     /*
499      * Pointer change
500      */
501     if( (!p_vout->p_sys->b_cursor_hidden) &&
502         ( (mdate() - p_vout->p_sys->i_lastmoved) > 5000000 ) )
503     {
504         /* Hide the mouse automatically */
505         if( p_vout->p_sys->hwnd != p_vout->p_sys->hparent )
506         {
507             p_vout->p_sys->b_cursor_hidden = VLC_TRUE;
508             PostMessage( p_vout->p_sys->hwnd, WM_VLC_HIDE_MOUSE, 0, 0 );
509         }
510     }
511
512     /*
513      * "Always on top" status change
514      */
515     if( p_vout->p_sys->b_on_top_change )
516     {
517         vlc_value_t val;
518         HMENU hMenu = GetSystemMenu( p_vout->p_sys->hwnd, FALSE );
519
520         var_Get( p_vout, "video-on-top", &val );
521  
522         /* Set the window on top if necessary */
523         if( val.b_bool && !( GetWindowLong( p_vout->p_sys->hwnd, GWL_EXSTYLE )
524                            & WS_EX_TOPMOST ) )
525         {
526             CheckMenuItem( hMenu, IDM_TOGGLE_ON_TOP,
527                            MF_BYCOMMAND | MFS_CHECKED );
528             SetWindowPos( p_vout->p_sys->hwnd, HWND_TOPMOST, 0, 0, 0, 0,
529                           SWP_NOSIZE | SWP_NOMOVE );
530         }
531         else
532         /* The window shouldn't be on top */
533         if( !val.b_bool && ( GetWindowLong( p_vout->p_sys->hwnd, GWL_EXSTYLE )
534                            & WS_EX_TOPMOST ) )
535         {
536             CheckMenuItem( hMenu, IDM_TOGGLE_ON_TOP,
537                            MF_BYCOMMAND | MFS_UNCHECKED );
538             SetWindowPos( p_vout->p_sys->hwnd, HWND_NOTOPMOST, 0, 0, 0, 0,
539                           SWP_NOSIZE | SWP_NOMOVE );
540         }
541
542         p_vout->p_sys->b_on_top_change = VLC_FALSE;
543     }
544
545     /* Check if the event thread is still running */
546     if( p_vout->p_sys->p_event->b_die )
547     {
548         return VLC_EGENERIC; /* exit */
549     }
550
551     return VLC_SUCCESS;
552 }
553
554 /*****************************************************************************
555  * Display: displays previously rendered output
556  *****************************************************************************
557  * This function sends the currently rendered image to the display, wait until
558  * it is displayed and switch the two rendering buffers, preparing next frame.
559  *****************************************************************************/
560 static void Display( vout_thread_t *p_vout, picture_t *p_pic )
561 {
562     HRESULT dxresult;
563
564     if( (p_vout->p_sys->p_display == NULL) )
565     {
566         msg_Warn( p_vout, "no display!!" );
567         return;
568     }
569
570     /* Our surface can be lost so be sure to check this
571      * and restore it if need be */
572     if( IDirectDrawSurface2_IsLost( p_vout->p_sys->p_display )
573         == DDERR_SURFACELOST )
574     {
575         if( IDirectDrawSurface2_Restore( p_vout->p_sys->p_display ) == DD_OK &&
576             p_vout->p_sys->b_using_overlay )
577             DirectXUpdateOverlay( p_vout );
578     }
579
580     if( !p_vout->p_sys->b_using_overlay )
581     {
582         DDBLTFX  ddbltfx;
583
584         /* We ask for the "NOTEARING" option */
585         memset( &ddbltfx, 0, sizeof(DDBLTFX) );
586         ddbltfx.dwSize = sizeof(DDBLTFX);
587         ddbltfx.dwDDFX = DDBLTFX_NOTEARING;
588
589         /* Blit video surface to display */
590         dxresult = IDirectDrawSurface2_Blt( p_vout->p_sys->p_display,
591                                             &p_vout->p_sys->rect_dest_clipped,
592                                             p_pic->p_sys->p_surface,
593                                             &p_vout->p_sys->rect_src_clipped,
594                                             DDBLT_ASYNC, &ddbltfx );
595         if( dxresult != DD_OK )
596         {
597             msg_Warn( p_vout, "could not blit surface (error %li)", dxresult );
598             return;
599         }
600
601     }
602     else /* using overlay */
603     {
604         /* Flip the overlay buffers if we are using back buffers */
605         if( p_pic->p_sys->p_front_surface == p_pic->p_sys->p_surface )
606         {
607             return;
608         }
609
610         dxresult = IDirectDrawSurface2_Flip( p_pic->p_sys->p_front_surface,
611                                              NULL, DDFLIP_WAIT );
612         if( dxresult != DD_OK )
613         {
614             msg_Warn( p_vout, "could not flip overlay (error %li)", dxresult );
615         }
616
617         /* set currently displayed pic */
618         p_vout->p_sys->p_current_surface = p_pic->p_sys->p_front_surface;
619
620         /* Lock surface to get all the required info */
621         if( DirectXLockSurface( p_vout, p_pic ) )
622         {
623             /* AAARRGG */
624             msg_Warn( p_vout, "cannot lock surface" );
625             return;
626         }
627         DirectXUnlockSurface( p_vout, p_pic );
628     }
629 }
630
631 /* following functions are local */
632
633 /*****************************************************************************
634  * DirectXEnumCallback: Device enumeration
635  *****************************************************************************
636  * This callback function is called by DirectDraw once for each 
637  * available DirectDraw device.
638  *****************************************************************************/
639 BOOL WINAPI DirectXEnumCallback( GUID* p_guid, LPTSTR psz_desc,
640                                  LPTSTR psz_drivername, VOID* p_context,
641                                  HMONITOR hmon )
642 {
643     vout_thread_t *p_vout = (vout_thread_t *)p_context;
644     msg_Dbg( p_vout, "DirectXEnumCallback: %s, %s", psz_desc, psz_drivername );
645
646     if( hmon && hmon == p_vout->p_sys->hmonitor )
647     {
648         msg_Dbg( p_vout, "selecting %s, %s", psz_desc, psz_drivername );
649         p_vout->p_sys->p_display_driver = malloc( sizeof(GUID) );
650         if( p_vout->p_sys->p_display_driver )
651             memcpy( p_vout->p_sys->p_display_driver, p_guid, sizeof(GUID) );
652     }
653
654     return TRUE; /* Keep enumerating */
655 }
656
657 /*****************************************************************************
658  * DirectXInitDDraw: Takes care of all the DirectDraw initialisations
659  *****************************************************************************
660  * This function initialise and allocate resources for DirectDraw.
661  *****************************************************************************/
662 static int DirectXInitDDraw( vout_thread_t *p_vout )
663 {
664     HRESULT dxresult;
665     HRESULT (WINAPI *OurDirectDrawCreate)(GUID *,LPDIRECTDRAW *,IUnknown *);
666     HRESULT (WINAPI *OurDirectDrawEnumerateEx)( LPDDENUMCALLBACKEXA, LPVOID,
667                                                 DWORD );
668     LPDIRECTDRAW p_ddobject;
669
670     msg_Dbg( p_vout, "DirectXInitDDraw" );
671
672     /* Load direct draw DLL */
673     p_vout->p_sys->hddraw_dll = LoadLibrary("DDRAW.DLL");
674     if( p_vout->p_sys->hddraw_dll == NULL )
675     {
676         msg_Warn( p_vout, "DirectXInitDDraw failed loading ddraw.dll" );
677         goto error;
678     }
679
680     OurDirectDrawCreate =
681       (void *)GetProcAddress(p_vout->p_sys->hddraw_dll, "DirectDrawCreate");
682     if( OurDirectDrawCreate == NULL )
683     {
684         msg_Err( p_vout, "DirectXInitDDraw failed GetProcAddress" );
685         goto error;
686     }
687
688     OurDirectDrawEnumerateEx =
689       (void *)GetProcAddress( p_vout->p_sys->hddraw_dll,
690                               "DirectDrawEnumerateExA" );
691
692     if( OurDirectDrawEnumerateEx && p_vout->p_sys->MonitorFromWindow )
693     {
694         p_vout->p_sys->hmonitor =
695             p_vout->p_sys->MonitorFromWindow( p_vout->p_sys->hwnd,
696                                               MONITOR_DEFAULTTONEAREST );
697
698         /* Enumerate displays */
699         OurDirectDrawEnumerateEx( DirectXEnumCallback, p_vout, 
700                                   DDENUM_ATTACHEDSECONDARYDEVICES );
701     }
702
703     /* Initialize DirectDraw now */
704     dxresult = OurDirectDrawCreate( p_vout->p_sys->p_display_driver,
705                                     &p_ddobject, NULL );
706     if( dxresult != DD_OK )
707     {
708         msg_Err( p_vout, "DirectXInitDDraw cannot initialize DDraw" );
709         goto error;
710     }
711
712     /* Get the IDirectDraw2 interface */
713     dxresult = IDirectDraw_QueryInterface( p_ddobject, &IID_IDirectDraw2,
714                                         (LPVOID *)&p_vout->p_sys->p_ddobject );
715     /* Release the unused interface */
716     IDirectDraw_Release( p_ddobject );
717     if( dxresult != DD_OK )
718     {
719         msg_Err( p_vout, "cannot get IDirectDraw2 interface" );
720         goto error;
721     }
722
723     /* Set DirectDraw Cooperative level, ie what control we want over Windows
724      * display */
725     dxresult = IDirectDraw2_SetCooperativeLevel( p_vout->p_sys->p_ddobject,
726                                                  NULL, DDSCL_NORMAL );
727     if( dxresult != DD_OK )
728     {
729         msg_Err( p_vout, "cannot set direct draw cooperative level" );
730         goto error;
731     }
732
733     /* Get the size of the current display device */
734     if( p_vout->p_sys->hmonitor && p_vout->p_sys->GetMonitorInfo )
735     {
736         MONITORINFO monitor_info;
737         monitor_info.cbSize = sizeof( MONITORINFO );
738         p_vout->p_sys->GetMonitorInfo( p_vout->p_sys->hmonitor,
739                                        &monitor_info );
740         p_vout->p_sys->rect_display = monitor_info.rcMonitor;
741     }
742     else
743     {
744         p_vout->p_sys->rect_display.left = 0;
745         p_vout->p_sys->rect_display.top = 0;
746         p_vout->p_sys->rect_display.right  = GetSystemMetrics(SM_CXSCREEN);
747         p_vout->p_sys->rect_display.bottom = GetSystemMetrics(SM_CYSCREEN);
748     }
749
750     msg_Dbg( p_vout, "screen dimensions (%ix%i,%ix%i)",
751              p_vout->p_sys->rect_display.left,
752              p_vout->p_sys->rect_display.top,
753              p_vout->p_sys->rect_display.right,
754              p_vout->p_sys->rect_display.bottom );
755
756     /* Probe the capabilities of the hardware */
757     DirectXGetDDrawCaps( p_vout );
758
759     msg_Dbg( p_vout, "End DirectXInitDDraw" );
760     return VLC_SUCCESS;
761
762  error:
763     if( p_vout->p_sys->p_ddobject )
764         IDirectDraw2_Release( p_vout->p_sys->p_ddobject );
765     if( p_vout->p_sys->hddraw_dll )
766         FreeLibrary( p_vout->p_sys->hddraw_dll );
767     p_vout->p_sys->hddraw_dll = NULL;
768     p_vout->p_sys->p_ddobject = NULL;
769     return VLC_EGENERIC;
770 }
771
772 /*****************************************************************************
773  * DirectXCreateDisplay: create the DirectDraw display.
774  *****************************************************************************
775  * Create and initialize display according to preferences specified in the vout
776  * thread fields.
777  *****************************************************************************/
778 static int DirectXCreateDisplay( vout_thread_t *p_vout )
779 {
780     HRESULT              dxresult;
781     DDSURFACEDESC        ddsd;
782     LPDIRECTDRAWSURFACE  p_display;
783
784     msg_Dbg( p_vout, "DirectXCreateDisplay" );
785
786     /* Now get the primary surface. This surface is what you actually see
787      * on your screen */
788     memset( &ddsd, 0, sizeof( DDSURFACEDESC ));
789     ddsd.dwSize = sizeof(DDSURFACEDESC);
790     ddsd.dwFlags = DDSD_CAPS;
791     ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
792
793     dxresult = IDirectDraw2_CreateSurface( p_vout->p_sys->p_ddobject,
794                                            &ddsd, &p_display, NULL );
795     if( dxresult != DD_OK )
796     {
797         msg_Err( p_vout, "cannot get primary surface (error %li)", dxresult );
798         return VLC_EGENERIC;
799     }
800
801     dxresult = IDirectDrawSurface_QueryInterface( p_display,
802                                          &IID_IDirectDrawSurface2,
803                                          (LPVOID *)&p_vout->p_sys->p_display );
804     /* Release the old interface */
805     IDirectDrawSurface_Release( p_display );
806     if ( dxresult != DD_OK )
807     {
808         msg_Err( p_vout, "cannot query IDirectDrawSurface2 interface "
809                          "(error %li)", dxresult );
810         return VLC_EGENERIC;
811     }
812
813     /* The clipper will be used only in non-overlay mode */
814     DirectXCreateClipper( p_vout );
815
816     /* Make sure the colorkey will be painted */
817     p_vout->p_sys->i_colorkey = 1;
818     p_vout->p_sys->i_rgb_colorkey =
819         DirectXFindColorkey( p_vout, p_vout->p_sys->i_colorkey );
820
821     /* Create the actual brush */
822     SetClassLong( p_vout->p_sys->hvideownd, GCL_HBRBACKGROUND,
823                   (LONG)CreateSolidBrush( p_vout->p_sys->i_rgb_colorkey ) );
824     InvalidateRect( p_vout->p_sys->hvideownd, NULL, TRUE );
825     DirectXUpdateRects( p_vout, VLC_TRUE );
826
827     return VLC_SUCCESS;
828 }
829
830 /*****************************************************************************
831  * DirectXCreateClipper: Create a clipper that will be used when blitting the
832  *                       RGB surface to the main display.
833  *****************************************************************************
834  * This clipper prevents us to modify by mistake anything on the screen
835  * which doesn't belong to our window. For example when a part of our video
836  * window is hidden by another window.
837  *****************************************************************************/
838 static int DirectXCreateClipper( vout_thread_t *p_vout )
839 {
840     HRESULT dxresult;
841
842     msg_Dbg( p_vout, "DirectXCreateClipper" );
843
844     /* Create the clipper */
845     dxresult = IDirectDraw2_CreateClipper( p_vout->p_sys->p_ddobject, 0,
846                                            &p_vout->p_sys->p_clipper, NULL );
847     if( dxresult != DD_OK )
848     {
849         msg_Warn( p_vout, "cannot create clipper (error %li)", dxresult );
850         goto error;
851     }
852
853     /* Associate the clipper to the window */
854     dxresult = IDirectDrawClipper_SetHWnd( p_vout->p_sys->p_clipper, 0,
855                                            p_vout->p_sys->hvideownd );
856     if( dxresult != DD_OK )
857     {
858         msg_Warn( p_vout, "cannot attach clipper to window (error %li)",
859                           dxresult );
860         goto error;
861     }
862
863     /* associate the clipper with the surface */
864     dxresult = IDirectDrawSurface_SetClipper(p_vout->p_sys->p_display,
865                                              p_vout->p_sys->p_clipper);
866     if( dxresult != DD_OK )
867     {
868         msg_Warn( p_vout, "cannot attach clipper to surface (error %li)",
869                           dxresult );
870         goto error;
871     }
872
873     return VLC_SUCCESS;
874
875  error:
876     if( p_vout->p_sys->p_clipper )
877     {
878         IDirectDrawClipper_Release( p_vout->p_sys->p_clipper );
879     }
880     p_vout->p_sys->p_clipper = NULL;
881     return VLC_EGENERIC;
882 }
883
884 /*****************************************************************************
885  * DirectXCreateSurface: create an YUV overlay or RGB surface for the video.
886  *****************************************************************************
887  * The best method of display is with an YUV overlay because the YUV->RGB
888  * conversion is done in hardware.
889  * You can also create a plain RGB surface.
890  * ( Maybe we could also try an RGB overlay surface, which could have hardware
891  * scaling and which would also be faster in window mode because you don't
892  * need to do any blitting to the main display...)
893  *****************************************************************************/
894 static int DirectXCreateSurface( vout_thread_t *p_vout,
895                                  LPDIRECTDRAWSURFACE2 *pp_surface_final,
896                                  int i_chroma, int b_overlay,
897                                  int i_backbuffers )
898 {
899     HRESULT dxresult;
900     LPDIRECTDRAWSURFACE p_surface;
901     DDSURFACEDESC ddsd;
902
903     /* Create the video surface */
904     if( b_overlay )
905     {
906         /* Now try to create the YUV overlay surface.
907          * This overlay will be displayed on top of the primary surface.
908          * A color key is used to determine whether or not the overlay will be
909          * displayed, ie the overlay will be displayed in place of the primary
910          * surface wherever the primary surface will have this color.
911          * The video window has been created with a background of this color so
912          * the overlay will be only displayed on top of this window */
913
914         memset( &ddsd, 0, sizeof( DDSURFACEDESC ));
915         ddsd.dwSize = sizeof(DDSURFACEDESC);
916         ddsd.ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT);
917         ddsd.ddpfPixelFormat.dwFlags = DDPF_FOURCC;
918         ddsd.ddpfPixelFormat.dwFourCC = i_chroma;
919         ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
920         ddsd.dwFlags |= (i_backbuffers ? DDSD_BACKBUFFERCOUNT : 0);
921         ddsd.ddsCaps.dwCaps = DDSCAPS_OVERLAY | DDSCAPS_VIDEOMEMORY;
922         ddsd.ddsCaps.dwCaps |= (i_backbuffers ? DDSCAPS_COMPLEX | DDSCAPS_FLIP
923                                 : 0 );
924         ddsd.dwHeight = p_vout->render.i_height;
925         ddsd.dwWidth = p_vout->render.i_width;
926         ddsd.dwBackBufferCount = i_backbuffers;
927
928         dxresult = IDirectDraw2_CreateSurface( p_vout->p_sys->p_ddobject,
929                                                &ddsd, &p_surface, NULL );
930         if( dxresult != DD_OK )
931         {
932             *pp_surface_final = NULL;
933             return VLC_EGENERIC;
934         }
935     }
936
937     if( !b_overlay )
938     {
939         vlc_bool_t b_rgb_surface =
940             ( i_chroma == VLC_FOURCC('R','G','B','2') )
941           || ( i_chroma == VLC_FOURCC('R','V','1','5') )
942            || ( i_chroma == VLC_FOURCC('R','V','1','6') )
943             || ( i_chroma == VLC_FOURCC('R','V','2','4') )
944              || ( i_chroma == VLC_FOURCC('R','V','3','2') );
945
946         memset( &ddsd, 0, sizeof( DDSURFACEDESC ) );
947         ddsd.dwSize = sizeof(DDSURFACEDESC);
948         ddsd.ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT);
949         ddsd.dwFlags = DDSD_HEIGHT | DDSD_WIDTH | DDSD_CAPS;
950         ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
951         ddsd.dwHeight = p_vout->render.i_height;
952         ddsd.dwWidth = p_vout->render.i_width;
953
954         if( p_vout->p_sys->b_use_sysmem )
955             ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
956         else
957             ddsd.ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY;
958
959         if( !b_rgb_surface )
960         {
961             ddsd.dwFlags |= DDSD_PIXELFORMAT;
962             ddsd.ddpfPixelFormat.dwFlags = DDPF_FOURCC;
963             ddsd.ddpfPixelFormat.dwFourCC = i_chroma;
964         }
965
966         dxresult = IDirectDraw2_CreateSurface( p_vout->p_sys->p_ddobject,
967                                                &ddsd, &p_surface, NULL );
968         if( dxresult != DD_OK )
969         {
970             *pp_surface_final = NULL;
971             return VLC_EGENERIC;
972         }
973     }
974
975     /* Now that the surface is created, try to get a newer DirectX interface */
976     dxresult = IDirectDrawSurface_QueryInterface( p_surface,
977                                      &IID_IDirectDrawSurface2,
978                                      (LPVOID *)pp_surface_final );
979     IDirectDrawSurface_Release( p_surface );    /* Release the old interface */
980     if ( dxresult != DD_OK )
981     {
982         msg_Err( p_vout, "cannot query IDirectDrawSurface2 interface "
983                          "(error %li)", dxresult );
984         *pp_surface_final = NULL;
985         return VLC_EGENERIC;
986     }
987
988     if( b_overlay )
989     {
990         /* Check the overlay is useable as some graphics cards allow creating
991          * several overlays but only one can be used at one time. */
992         p_vout->p_sys->p_current_surface = *pp_surface_final;
993         if( DirectXUpdateOverlay( p_vout ) != VLC_SUCCESS )
994         {
995             IDirectDrawSurface2_Release( *pp_surface_final );
996             *pp_surface_final = NULL;
997             msg_Err( p_vout, "overlay unuseable (might already be in use)" );
998             return VLC_EGENERIC;
999         }
1000     }
1001
1002     return VLC_SUCCESS;
1003 }
1004
1005 /*****************************************************************************
1006  * DirectXUpdateOverlay: Move or resize overlay surface on video display.
1007  *****************************************************************************
1008  * This function is used to move or resize an overlay surface on the screen.
1009  * Ususally the overlay is moved by the user and thus, by a move or resize
1010  * event (in Manage).
1011  *****************************************************************************/
1012 int DirectXUpdateOverlay( vout_thread_t *p_vout )
1013 {
1014     DDOVERLAYFX     ddofx;
1015     DWORD           dwFlags;
1016     HRESULT         dxresult;
1017
1018     if( p_vout->p_sys->p_current_surface == NULL ||
1019         !p_vout->p_sys->b_using_overlay )
1020         return VLC_EGENERIC;
1021
1022     /* The new window dimensions should already have been computed by the
1023      * caller of this function */
1024
1025     /* Position and show the overlay */
1026     memset(&ddofx, 0, sizeof(DDOVERLAYFX));
1027     ddofx.dwSize = sizeof(DDOVERLAYFX);
1028     ddofx.dckDestColorkey.dwColorSpaceLowValue = p_vout->p_sys->i_colorkey;
1029     ddofx.dckDestColorkey.dwColorSpaceHighValue = p_vout->p_sys->i_colorkey;
1030
1031     dwFlags = DDOVER_SHOW | DDOVER_KEYDESTOVERRIDE;
1032
1033     dxresult = IDirectDrawSurface2_UpdateOverlay(
1034                                          p_vout->p_sys->p_current_surface,
1035                                          &p_vout->p_sys->rect_src_clipped,
1036                                          p_vout->p_sys->p_display,
1037                                          &p_vout->p_sys->rect_dest_clipped,
1038                                          dwFlags, &ddofx );
1039     if(dxresult != DD_OK)
1040     {
1041         msg_Warn( p_vout,
1042                   "DirectXUpdateOverlay cannot move or resize overlay" );
1043         return VLC_EGENERIC;
1044     }
1045
1046     return VLC_SUCCESS;
1047 }
1048
1049 /*****************************************************************************
1050  * DirectXCloseDDraw: Release the DDraw object allocated by DirectXInitDDraw
1051  *****************************************************************************
1052  * This function returns all resources allocated by DirectXInitDDraw.
1053  *****************************************************************************/
1054 static void DirectXCloseDDraw( vout_thread_t *p_vout )
1055 {
1056     msg_Dbg( p_vout, "DirectXCloseDDraw" );
1057     if( p_vout->p_sys->p_ddobject != NULL )
1058     {
1059         IDirectDraw2_Release(p_vout->p_sys->p_ddobject);
1060         p_vout->p_sys->p_ddobject = NULL;
1061     }
1062
1063     if( p_vout->p_sys->hddraw_dll != NULL )
1064     {
1065         FreeLibrary( p_vout->p_sys->hddraw_dll );
1066         p_vout->p_sys->hddraw_dll = NULL;
1067     }
1068
1069     if( p_vout->p_sys->p_display_driver != NULL )
1070     {
1071         free( p_vout->p_sys->p_display_driver );
1072         p_vout->p_sys->p_display_driver = NULL;
1073     }
1074
1075     p_vout->p_sys->hmonitor = NULL;
1076 }
1077
1078 /*****************************************************************************
1079  * DirectXCloseDisplay: close and reset the DirectX display device
1080  *****************************************************************************
1081  * This function returns all resources allocated by DirectXCreateDisplay.
1082  *****************************************************************************/
1083 static void DirectXCloseDisplay( vout_thread_t *p_vout )
1084 {
1085     msg_Dbg( p_vout, "DirectXCloseDisplay" );
1086
1087     if( p_vout->p_sys->p_clipper != NULL )
1088     {
1089         msg_Dbg( p_vout, "DirectXCloseDisplay clipper" );
1090         IDirectDrawClipper_Release( p_vout->p_sys->p_clipper );
1091         p_vout->p_sys->p_clipper = NULL;
1092     }
1093
1094     if( p_vout->p_sys->p_display != NULL )
1095     {
1096         msg_Dbg( p_vout, "DirectXCloseDisplay display" );
1097         IDirectDrawSurface2_Release( p_vout->p_sys->p_display );
1098         p_vout->p_sys->p_display = NULL;
1099     }
1100 }
1101
1102 /*****************************************************************************
1103  * DirectXCloseSurface: close the YUV overlay or RGB surface.
1104  *****************************************************************************
1105  * This function returns all resources allocated for the surface.
1106  *****************************************************************************/
1107 static void DirectXCloseSurface( vout_thread_t *p_vout,
1108                                  LPDIRECTDRAWSURFACE2 p_surface )
1109 {
1110     msg_Dbg( p_vout, "DirectXCloseSurface" );
1111     if( p_surface != NULL )
1112     {
1113         IDirectDrawSurface2_Release( p_surface );
1114     }
1115 }
1116
1117 /*****************************************************************************
1118  * NewPictureVec: allocate a vector of identical pictures
1119  *****************************************************************************
1120  * Returns 0 on success, -1 otherwise
1121  *****************************************************************************/
1122 static int NewPictureVec( vout_thread_t *p_vout, picture_t *p_pic,
1123                           int i_num_pics )
1124 {
1125     int i;
1126     int i_ret = VLC_SUCCESS;
1127     LPDIRECTDRAWSURFACE2 p_surface;
1128
1129     msg_Dbg( p_vout, "NewPictureVec overlay:%s chroma:%.4s",
1130              p_vout->p_sys->b_using_overlay ? "yes" : "no",
1131              (char *)&p_vout->output.i_chroma );
1132
1133     I_OUTPUTPICTURES = 0;
1134
1135     /* First we try to use an YUV overlay surface.
1136      * The overlay surface that we create won't be used to decode directly
1137      * into it because accessing video memory directly is way to slow (remember
1138      * that pictures are decoded macroblock per macroblock). Instead the video
1139      * will be decoded in picture buffers in system memory which will then be
1140      * memcpy() to the overlay surface. */
1141     if( p_vout->p_sys->b_using_overlay )
1142     {
1143         /* Triple buffering rocks! it doesn't have any processing overhead
1144          * (you don't have to wait for the vsync) and provides for a very nice
1145          * video quality (no tearing). */
1146         if( p_vout->p_sys->b_3buf_overlay )
1147             i_ret = DirectXCreateSurface( p_vout, &p_surface,
1148                                           p_vout->output.i_chroma,
1149                                           p_vout->p_sys->b_using_overlay,
1150                                           2 /* number of backbuffers */ );
1151
1152         if( !p_vout->p_sys->b_3buf_overlay || i_ret != VLC_SUCCESS )
1153         {
1154             /* Try to reduce the number of backbuffers */
1155             i_ret = DirectXCreateSurface( p_vout, &p_surface,
1156                                           p_vout->output.i_chroma,
1157                                           p_vout->p_sys->b_using_overlay,
1158                                           0 /* number of backbuffers */ );
1159         }
1160
1161         if( i_ret == VLC_SUCCESS )
1162         {
1163             DDSCAPS dds_caps;
1164             picture_t front_pic;
1165             picture_sys_t front_pic_sys;
1166             front_pic.p_sys = &front_pic_sys;
1167
1168             /* Allocate internal structure */
1169             p_pic[0].p_sys = malloc( sizeof( picture_sys_t ) );
1170             if( p_pic[0].p_sys == NULL )
1171             {
1172                 DirectXCloseSurface( p_vout, p_surface );
1173                 return VLC_ENOMEM;
1174             }
1175
1176             /* set front buffer */
1177             p_pic[0].p_sys->p_front_surface = p_surface;
1178
1179             /* Get the back buffer */
1180             memset( &dds_caps, 0, sizeof( DDSCAPS ) );
1181             dds_caps.dwCaps = DDSCAPS_BACKBUFFER;
1182             if( DD_OK != IDirectDrawSurface2_GetAttachedSurface(
1183                                                 p_surface, &dds_caps,
1184                                                 &p_pic[0].p_sys->p_surface ) )
1185             {
1186                 msg_Warn( p_vout, "NewPictureVec could not get back buffer" );
1187                 /* front buffer is the same as back buffer */
1188                 p_pic[0].p_sys->p_surface = p_surface;
1189             }
1190
1191
1192             p_vout->p_sys->p_current_surface = front_pic.p_sys->p_surface =
1193                 p_pic[0].p_sys->p_front_surface;
1194
1195             /* Reset the front buffer memory */
1196             if( DirectXLockSurface( p_vout, &front_pic ) == VLC_SUCCESS )
1197             {
1198                 int i,j;
1199                 for( i = 0; i < front_pic.i_planes; i++ )
1200                     for( j = 0; j < front_pic.p[i].i_lines; j++)
1201                         memset( front_pic.p[i].p_pixels + j *
1202                                 front_pic.p[i].i_pitch, 127,
1203                                 front_pic.p[i].i_visible_pitch );
1204
1205                 DirectXUnlockSurface( p_vout, &front_pic );
1206             }
1207
1208             DirectXUpdateOverlay( p_vout );
1209             I_OUTPUTPICTURES = 1;
1210             msg_Dbg( p_vout, "YUV overlay created successfully" );
1211         }
1212     }
1213
1214     /* As we can't have an overlay, we'll try to create a plain offscreen
1215      * surface. This surface will reside in video memory because there's a
1216      * better chance then that we'll be able to use some kind of hardware
1217      * acceleration like rescaling, blitting or YUV->RGB conversions.
1218      * We then only need to blit this surface onto the main display when we
1219      * want to display it */
1220     if( !p_vout->p_sys->b_using_overlay )
1221     {
1222         if( p_vout->p_sys->b_hw_yuv )
1223         {
1224             DWORD i_codes;
1225             DWORD *pi_codes;
1226             vlc_bool_t b_result = VLC_FALSE;
1227
1228             /* Check if the chroma is supported first. This is required
1229              * because a few buggy drivers don't mind creating the surface
1230              * even if they don't know about the chroma. */
1231             if( IDirectDraw2_GetFourCCCodes( p_vout->p_sys->p_ddobject,
1232                                              &i_codes, NULL ) == DD_OK )
1233             {
1234                 pi_codes = malloc( i_codes * sizeof(DWORD) );
1235                 if( pi_codes && IDirectDraw2_GetFourCCCodes(
1236                     p_vout->p_sys->p_ddobject, &i_codes, pi_codes ) == DD_OK )
1237                 {
1238                     for( i = 0; i < (int)i_codes; i++ )
1239                     {
1240                         if( p_vout->output.i_chroma == pi_codes[i] )
1241                         {
1242                             b_result = VLC_TRUE;
1243                             break;
1244                         }
1245                     }
1246                 }
1247             }
1248
1249             if( b_result )
1250                 i_ret = DirectXCreateSurface( p_vout, &p_surface,
1251                                               p_vout->output.i_chroma,
1252                                               0 /* no overlay */,
1253                                               0 /* no back buffers */ );
1254             else
1255                 p_vout->p_sys->b_hw_yuv = VLC_FALSE;
1256         }
1257
1258         if( i_ret || !p_vout->p_sys->b_hw_yuv )
1259         {
1260             /* Our last choice is to use a plain RGB surface */
1261             DDPIXELFORMAT ddpfPixelFormat;
1262
1263             ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT);
1264             IDirectDrawSurface2_GetPixelFormat( p_vout->p_sys->p_display,
1265                                                 &ddpfPixelFormat );
1266
1267             if( ddpfPixelFormat.dwFlags & DDPF_RGB )
1268             {
1269                 switch( ddpfPixelFormat.dwRGBBitCount )
1270                 {
1271                 case 8: /* FIXME: set the palette */
1272                     p_vout->output.i_chroma = VLC_FOURCC('R','G','B','2');
1273                     break;
1274                 case 15:
1275                     p_vout->output.i_chroma = VLC_FOURCC('R','V','1','5');
1276                     break;
1277                 case 16:
1278                     p_vout->output.i_chroma = VLC_FOURCC('R','V','1','6');
1279                     break;
1280                 case 24:
1281                     p_vout->output.i_chroma = VLC_FOURCC('R','V','2','4');
1282                     break;
1283                 case 32:
1284                     p_vout->output.i_chroma = VLC_FOURCC('R','V','3','2');
1285                     break;
1286                 default:
1287                     msg_Err( p_vout, "unknown screen depth" );
1288                     return VLC_EGENERIC;
1289                 }
1290                 p_vout->output.i_rmask = ddpfPixelFormat.dwRBitMask;
1291                 p_vout->output.i_gmask = ddpfPixelFormat.dwGBitMask;
1292                 p_vout->output.i_bmask = ddpfPixelFormat.dwBBitMask;
1293             }
1294
1295             p_vout->p_sys->b_hw_yuv = 0;
1296
1297             i_ret = DirectXCreateSurface( p_vout, &p_surface,
1298                                           p_vout->output.i_chroma,
1299                                           0 /* no overlay */,
1300                                           0 /* no back buffers */ );
1301
1302             if( i_ret && !p_vout->p_sys->b_use_sysmem )
1303             {
1304                 /* Give it a last try with b_use_sysmem enabled */
1305                 p_vout->p_sys->b_use_sysmem = 1;
1306
1307                 i_ret = DirectXCreateSurface( p_vout, &p_surface,
1308                                               p_vout->output.i_chroma,
1309                                               0 /* no overlay */,
1310                                               0 /* no back buffers */ );
1311             }
1312         }
1313
1314         if( i_ret == VLC_SUCCESS )
1315         {
1316             /* Allocate internal structure */
1317             p_pic[0].p_sys = malloc( sizeof( picture_sys_t ) );
1318             if( p_pic[0].p_sys == NULL )
1319             {
1320                 DirectXCloseSurface( p_vout, p_surface );
1321                 return VLC_ENOMEM;
1322             }
1323
1324             p_pic[0].p_sys->p_surface = p_pic[0].p_sys->p_front_surface
1325                 = p_surface;
1326
1327             I_OUTPUTPICTURES = 1;
1328
1329             msg_Dbg( p_vout, "created plain surface of chroma:%.4s",
1330                      (char *)&p_vout->output.i_chroma );
1331         }
1332     }
1333
1334
1335     /* Now that we've got all our direct-buffers, we can finish filling in the
1336      * picture_t structures */
1337     for( i = 0; i < I_OUTPUTPICTURES; i++ )
1338     {
1339         p_pic[i].i_status = DESTROYED_PICTURE;
1340         p_pic[i].i_type   = DIRECT_PICTURE;
1341         p_pic[i].pf_lock  = DirectXLockSurface;
1342         p_pic[i].pf_unlock = DirectXUnlockSurface;
1343         PP_OUTPUTPICTURE[i] = &p_pic[i];
1344
1345         if( DirectXLockSurface( p_vout, &p_pic[i] ) != VLC_SUCCESS )
1346         {
1347             /* AAARRGG */
1348             FreePictureVec( p_vout, p_pic, I_OUTPUTPICTURES );
1349             I_OUTPUTPICTURES = 0;
1350             msg_Err( p_vout, "cannot lock surface" );
1351             return VLC_EGENERIC;
1352         }
1353         DirectXUnlockSurface( p_vout, &p_pic[i] );
1354     }
1355
1356     msg_Dbg( p_vout, "End NewPictureVec (%s)",
1357              I_OUTPUTPICTURES ? "succeeded" : "failed" );
1358
1359     return VLC_SUCCESS;
1360 }
1361
1362 /*****************************************************************************
1363  * FreePicture: destroy a picture vector allocated with NewPictureVec
1364  *****************************************************************************
1365  *
1366  *****************************************************************************/
1367 static void FreePictureVec( vout_thread_t *p_vout, picture_t *p_pic,
1368                             int i_num_pics )
1369 {
1370     int i;
1371
1372     for( i = 0; i < i_num_pics; i++ )
1373     {
1374         DirectXCloseSurface( p_vout, p_pic[i].p_sys->p_front_surface );
1375
1376         for( i = 0; i < i_num_pics; i++ )
1377         {
1378             free( p_pic[i].p_sys );
1379         }
1380     }
1381
1382     p_vout->p_sys->p_current_surface = 0;
1383 }
1384
1385 /*****************************************************************************
1386  * UpdatePictureStruct: updates the internal data in the picture_t structure
1387  *****************************************************************************
1388  * This will setup stuff for use by the video_output thread
1389  *****************************************************************************/
1390 static int UpdatePictureStruct( vout_thread_t *p_vout, picture_t *p_pic,
1391                                 int i_chroma )
1392 {
1393     switch( p_vout->output.i_chroma )
1394     {
1395         case VLC_FOURCC('R','G','B','2'):
1396         case VLC_FOURCC('R','V','1','5'):
1397         case VLC_FOURCC('R','V','1','6'):
1398         case VLC_FOURCC('R','V','2','4'):
1399         case VLC_FOURCC('R','V','3','2'):
1400             p_pic->p->p_pixels = p_pic->p_sys->ddsd.lpSurface;
1401             p_pic->p->i_lines = p_vout->output.i_height;
1402             p_pic->p->i_pitch = p_pic->p_sys->ddsd.lPitch;
1403             switch( p_vout->output.i_chroma )
1404             {
1405                 case VLC_FOURCC('R','G','B','2'):
1406                     p_pic->p->i_pixel_pitch = 1;
1407                     break;
1408                 case VLC_FOURCC('R','V','1','5'):
1409                 case VLC_FOURCC('R','V','1','6'):
1410                     p_pic->p->i_pixel_pitch = 2;
1411                     break;
1412                 case VLC_FOURCC('R','V','2','4'):
1413                     p_pic->p->i_pixel_pitch = 3;
1414                     break;
1415                 case VLC_FOURCC('R','V','3','2'):
1416                     p_pic->p->i_pixel_pitch = 4;
1417                     break;
1418                 default:
1419                     return VLC_EGENERIC;
1420             }
1421             p_pic->p->i_visible_pitch = p_vout->output.i_width *
1422               p_pic->p->i_pixel_pitch;
1423             p_pic->i_planes = 1;
1424             break;
1425
1426         case VLC_FOURCC('Y','V','1','2'):
1427
1428             p_pic->Y_PIXELS = p_pic->p_sys->ddsd.lpSurface;
1429             p_pic->p[Y_PLANE].i_lines = p_vout->output.i_height;
1430             p_pic->p[Y_PLANE].i_pitch = p_pic->p_sys->ddsd.lPitch;
1431             p_pic->p[Y_PLANE].i_pixel_pitch = 1;
1432             p_pic->p[Y_PLANE].i_visible_pitch = p_vout->output.i_width *
1433               p_pic->p[Y_PLANE].i_pixel_pitch;
1434
1435             p_pic->V_PIXELS =  p_pic->Y_PIXELS
1436               + p_pic->p[Y_PLANE].i_lines * p_pic->p[Y_PLANE].i_pitch;
1437             p_pic->p[V_PLANE].i_lines = p_vout->output.i_height / 2;
1438             p_pic->p[V_PLANE].i_pitch = p_pic->p[Y_PLANE].i_pitch / 2;
1439             p_pic->p[V_PLANE].i_pixel_pitch = 1;
1440             p_pic->p[V_PLANE].i_visible_pitch = p_vout->output.i_width / 2 *
1441               p_pic->p[V_PLANE].i_pixel_pitch;
1442
1443             p_pic->U_PIXELS = p_pic->V_PIXELS
1444               + p_pic->p[V_PLANE].i_lines * p_pic->p[V_PLANE].i_pitch;
1445             p_pic->p[U_PLANE].i_lines = p_vout->output.i_height / 2;
1446             p_pic->p[U_PLANE].i_pitch = p_pic->p[Y_PLANE].i_pitch / 2;
1447             p_pic->p[U_PLANE].i_pixel_pitch = 1;
1448             p_pic->p[U_PLANE].i_visible_pitch = p_vout->output.i_width / 2 *
1449               p_pic->p[U_PLANE].i_pixel_pitch;
1450
1451             p_pic->i_planes = 3;
1452             break;
1453
1454         case VLC_FOURCC('I','Y','U','V'):
1455
1456             p_pic->Y_PIXELS = p_pic->p_sys->ddsd.lpSurface;
1457             p_pic->p[Y_PLANE].i_lines = p_vout->output.i_height;
1458             p_pic->p[Y_PLANE].i_pitch = p_pic->p_sys->ddsd.lPitch;
1459             p_pic->p[Y_PLANE].i_pixel_pitch = 1;
1460             p_pic->p[Y_PLANE].i_visible_pitch = p_vout->output.i_width *
1461               p_pic->p[Y_PLANE].i_pixel_pitch;
1462
1463             p_pic->U_PIXELS = p_pic->Y_PIXELS
1464               + p_pic->p[Y_PLANE].i_lines * p_pic->p[Y_PLANE].i_pitch;
1465             p_pic->p[U_PLANE].i_lines = p_vout->output.i_height / 2;
1466             p_pic->p[U_PLANE].i_pitch = p_pic->p[Y_PLANE].i_pitch / 2;
1467             p_pic->p[U_PLANE].i_pixel_pitch = 1;
1468             p_pic->p[U_PLANE].i_visible_pitch = p_vout->output.i_width / 2 *
1469               p_pic->p[U_PLANE].i_pixel_pitch;
1470
1471             p_pic->V_PIXELS =  p_pic->U_PIXELS
1472               + p_pic->p[U_PLANE].i_lines * p_pic->p[U_PLANE].i_pitch;
1473             p_pic->p[V_PLANE].i_lines = p_vout->output.i_height / 2;
1474             p_pic->p[V_PLANE].i_pitch = p_pic->p[Y_PLANE].i_pitch / 2;
1475             p_pic->p[V_PLANE].i_pixel_pitch = 1;
1476             p_pic->p[V_PLANE].i_visible_pitch = p_vout->output.i_width / 2 *
1477               p_pic->p[V_PLANE].i_pixel_pitch;
1478
1479             p_pic->i_planes = 3;
1480             break;
1481
1482         case VLC_FOURCC('Y','U','Y','2'):
1483
1484             p_pic->p->p_pixels = p_pic->p_sys->ddsd.lpSurface;
1485             p_pic->p->i_lines = p_vout->output.i_height;
1486             p_pic->p->i_pitch = p_pic->p_sys->ddsd.lPitch;
1487             p_pic->p->i_pixel_pitch = 2;
1488             p_pic->p->i_visible_pitch = p_vout->output.i_width *
1489               p_pic->p->i_pixel_pitch;
1490
1491             p_pic->i_planes = 1;
1492             break;
1493
1494         default:
1495             /* Unknown chroma, tell the guy to get lost */
1496             msg_Err( p_vout, "never heard of chroma 0x%.8x (%4.4s)",
1497                      p_vout->output.i_chroma,
1498                      (char*)&p_vout->output.i_chroma );
1499             return VLC_EGENERIC;
1500     }
1501
1502     return VLC_SUCCESS;
1503 }
1504
1505 /*****************************************************************************
1506  * DirectXGetDDrawCaps: Probe the capabilities of the hardware
1507  *****************************************************************************
1508  * It is nice to know which features are supported by the hardware so we can
1509  * find ways to optimize our rendering.
1510  *****************************************************************************/
1511 static void DirectXGetDDrawCaps( vout_thread_t *p_vout )
1512 {
1513     DDCAPS ddcaps;
1514     HRESULT dxresult;
1515
1516     /* This is just an indication of whether or not we'll support overlay,
1517      * but with this test we don't know if we support YUV overlay */
1518     memset( &ddcaps, 0, sizeof( DDCAPS ));
1519     ddcaps.dwSize = sizeof(DDCAPS);
1520     dxresult = IDirectDraw2_GetCaps( p_vout->p_sys->p_ddobject,
1521                                      &ddcaps, NULL );
1522     if(dxresult != DD_OK )
1523     {
1524         msg_Warn( p_vout, "cannot get caps" );
1525     }
1526     else
1527     {
1528         BOOL bHasOverlay, bHasOverlayFourCC, bCanDeinterlace,
1529              bHasColorKey, bCanStretch, bCanBltFourcc;
1530
1531         /* Determine if the hardware supports overlay surfaces */
1532         bHasOverlay = ((ddcaps.dwCaps & DDCAPS_OVERLAY) ==
1533                        DDCAPS_OVERLAY) ? TRUE : FALSE;
1534         /* Determine if the hardware supports overlay surfaces */
1535         bHasOverlayFourCC = ((ddcaps.dwCaps & DDCAPS_OVERLAYFOURCC) ==
1536                        DDCAPS_OVERLAYFOURCC) ? TRUE : FALSE;
1537         /* Determine if the hardware supports overlay deinterlacing */
1538         bCanDeinterlace = ((ddcaps.dwCaps & DDCAPS2_CANFLIPODDEVEN) ==
1539                        0 ) ? TRUE : FALSE;
1540         /* Determine if the hardware supports colorkeying */
1541         bHasColorKey = ((ddcaps.dwCaps & DDCAPS_COLORKEY) ==
1542                         DDCAPS_COLORKEY) ? TRUE : FALSE;
1543         /* Determine if the hardware supports scaling of the overlay surface */
1544         bCanStretch = ((ddcaps.dwCaps & DDCAPS_OVERLAYSTRETCH) ==
1545                        DDCAPS_OVERLAYSTRETCH) ? TRUE : FALSE;
1546         /* Determine if the hardware supports color conversion during a blit */
1547         bCanBltFourcc = ((ddcaps.dwCaps & DDCAPS_BLTFOURCC ) ==
1548                         DDCAPS_BLTFOURCC) ? TRUE : FALSE;
1549
1550         msg_Dbg( p_vout, "DirectDraw Capabilities: overlay=%i yuvoverlay=%i "
1551                          "can_deinterlace_overlay=%i colorkey=%i stretch=%i "
1552                          "bltfourcc=%i",
1553                          bHasOverlay, bHasOverlayFourCC, bCanDeinterlace,
1554                          bHasColorKey, bCanStretch, bCanBltFourcc );
1555
1556         /* Don't ask for troubles */
1557         if( !bCanBltFourcc ) p_vout->p_sys->b_hw_yuv = FALSE; 
1558     }
1559 }
1560
1561 /*****************************************************************************
1562  * DirectXLockSurface: Lock surface and get picture data pointer
1563  *****************************************************************************
1564  * This function locks a surface and get the surface descriptor which amongst
1565  * other things has the pointer to the picture data.
1566  *****************************************************************************/
1567 static int DirectXLockSurface( vout_thread_t *p_vout, picture_t *p_pic )
1568 {
1569     HRESULT dxresult;
1570
1571     /* Lock the surface to get a valid pointer to the picture buffer */
1572     memset( &p_pic->p_sys->ddsd, 0, sizeof( DDSURFACEDESC ));
1573     p_pic->p_sys->ddsd.dwSize = sizeof(DDSURFACEDESC);
1574     dxresult = IDirectDrawSurface2_Lock( p_pic->p_sys->p_surface,
1575                                          NULL, &p_pic->p_sys->ddsd,
1576                                          DDLOCK_NOSYSLOCK | DDLOCK_WAIT,
1577                                          NULL );
1578     if( dxresult != DD_OK )
1579     {
1580         if( dxresult == DDERR_INVALIDPARAMS )
1581         {
1582             /* DirectX 3 doesn't support the DDLOCK_NOSYSLOCK flag, resulting
1583              * in an invalid params error */
1584             dxresult = IDirectDrawSurface2_Lock( p_pic->p_sys->p_surface, NULL,
1585                                              &p_pic->p_sys->ddsd,
1586                                              DDLOCK_WAIT, NULL);
1587         }
1588         if( dxresult == DDERR_SURFACELOST )
1589         {
1590             /* Your surface can be lost so be sure
1591              * to check this and restore it if needed */
1592
1593             /* When using overlays with back-buffers, we need to restore
1594              * the front buffer so the back-buffers get restored as well. */
1595             if( p_vout->p_sys->b_using_overlay  )
1596                 IDirectDrawSurface2_Restore( p_pic->p_sys->p_front_surface );
1597             else
1598                 IDirectDrawSurface2_Restore( p_pic->p_sys->p_surface );
1599
1600             dxresult = IDirectDrawSurface2_Lock( p_pic->p_sys->p_surface, NULL,
1601                                                  &p_pic->p_sys->ddsd,
1602                                                  DDLOCK_WAIT, NULL);
1603             if( dxresult == DDERR_SURFACELOST )
1604                 msg_Dbg( p_vout, "DirectXLockSurface: DDERR_SURFACELOST" );
1605         }
1606         if( dxresult != DD_OK )
1607         {
1608             return VLC_EGENERIC;
1609         }
1610     }
1611
1612     /* Now we have a pointer to the surface memory, we can update our picture
1613      * structure. */
1614     if( UpdatePictureStruct( p_vout, p_pic, p_vout->output.i_chroma )
1615         != VLC_SUCCESS )
1616     {
1617         DirectXUnlockSurface( p_vout, p_pic );
1618         return VLC_EGENERIC;
1619     }
1620     else
1621         return VLC_SUCCESS;      
1622 }
1623
1624 /*****************************************************************************
1625  * DirectXUnlockSurface: Unlock a surface locked by DirectXLockSurface().
1626  *****************************************************************************/
1627 static int DirectXUnlockSurface( vout_thread_t *p_vout, picture_t *p_pic )
1628 {
1629     /* Unlock the Surface */
1630     if( IDirectDrawSurface2_Unlock( p_pic->p_sys->p_surface, NULL ) == DD_OK )
1631         return VLC_SUCCESS;
1632     else
1633         return VLC_EGENERIC;
1634 }
1635
1636 /*****************************************************************************
1637  * DirectXFindColorkey: Finds out the 32bits RGB pixel value of the colorkey
1638  *****************************************************************************/
1639 static DWORD DirectXFindColorkey( vout_thread_t *p_vout, uint32_t i_color )
1640 {
1641     DDSURFACEDESC ddsd;
1642     HRESULT dxresult;
1643     COLORREF i_rgb = 0;
1644     uint32_t i_pixel_backup;
1645     HDC hdc;
1646
1647     ddsd.dwSize = sizeof(ddsd);
1648     dxresult = IDirectDrawSurface2_Lock( p_vout->p_sys->p_display, NULL,
1649                                          &ddsd, DDLOCK_WAIT, NULL );
1650     if( dxresult != DD_OK ) return 0;
1651
1652     i_pixel_backup = *(uint32_t *)ddsd.lpSurface;
1653
1654     switch( ddsd.ddpfPixelFormat.dwRGBBitCount )
1655     {
1656     case 4:
1657         *(uint8_t *)ddsd.lpSurface = 0x11;
1658         break;
1659     case 8:
1660         *(uint8_t *)ddsd.lpSurface = 0x01;
1661         break;
1662     case 16:
1663         *(uint16_t *)ddsd.lpSurface = 0x01;
1664         break;
1665     case 24:
1666         *(uint32_t *)ddsd.lpSurface = 0x0100;
1667         break;
1668     case 32:
1669         *(uint32_t *)ddsd.lpSurface = 0x01;
1670         break;
1671     }
1672
1673     IDirectDrawSurface2_Unlock( p_vout->p_sys->p_display, NULL );
1674
1675     if( IDirectDrawSurface2_GetDC( p_vout->p_sys->p_display, &hdc ) == DD_OK )
1676     {
1677         i_rgb = GetPixel( hdc, 0, 0 );
1678         IDirectDrawSurface2_ReleaseDC( p_vout->p_sys->p_display, hdc );
1679     }
1680
1681     ddsd.dwSize = sizeof(ddsd);
1682     dxresult = IDirectDrawSurface2_Lock( p_vout->p_sys->p_display, NULL,
1683                                          &ddsd, DDLOCK_WAIT, NULL );
1684     if( dxresult != DD_OK ) return i_rgb;
1685
1686     *(uint32_t *)ddsd.lpSurface = i_pixel_backup;
1687
1688     IDirectDrawSurface2_Unlock( p_vout->p_sys->p_display, NULL );
1689
1690     return i_rgb;
1691 }
1692
1693 /*****************************************************************************
1694  * object variables callbacks: a bunch of object variables are used by the
1695  * interfaces to interact with the vout.
1696  *****************************************************************************/
1697 static int OnTopCallback( vlc_object_t *p_this, char const *psz_cmd,
1698                         vlc_value_t oldval, vlc_value_t newval, void *p_data )
1699 {
1700     vout_thread_t *p_vout = (vout_thread_t *)p_this;
1701     p_vout->p_sys->b_on_top_change = VLC_TRUE;
1702     return VLC_SUCCESS;
1703 }