]> git.sesse.net Git - vlc/blob - plugins/directx/vout_directx.c
* DirectX plugin by Gildas Bazin <gbazin@netcourrier.com>.
[vlc] / plugins / directx / vout_directx.c
1 /*****************************************************************************
2  * vout_directx.c: Windows DirectX video output display method
3  *****************************************************************************
4  * Copyright (C) 1998, 1999, 2000 VideoLAN
5  * $Id: vout_directx.c,v 1.1 2001/06/02 01:09:03 sam 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 #define MODULE_NAME directx
25 #include "modules_inner.h"
26
27 /* This is a list of what needs to be fixed:
28  *
29  * For now, this plugin only works when YUV overlay is supported (which it
30  * should be nowadays on most of the video cards under Windows)...
31  *
32  * The overlay doesn't use double-buffering.
33  *
34  * Use Shane Harper's optimizations for YUV
35  */
36
37 /*****************************************************************************
38  * Preamble
39  *
40  *****************************************************************************/
41 #include "defs.h"
42
43 #include <errno.h>                                                 /* ENOMEM */
44 #include <stdlib.h>                                                /* free() */
45 #include <string.h>                                            /* strerror() */
46
47 #include <windows.h>
48 #include <directx.h>
49
50 #include "config.h"
51 #include "common.h"
52 #include "threads.h"
53 #include "mtime.h"
54 #include "tests.h"
55 #include "netutils.h"
56
57 #include "video.h"
58 #include "video_output.h"
59
60 #include "intf_msg.h"
61 #include "interface.h"
62 #include "main.h"
63
64 #include "modules.h"
65 #include "modules_export.h"
66
67 #define OVERLAY_COLOR_KEY 1       /* color on top of which the overlay will be
68                                    * displayed. 1 should be almost black but
69                                    * not black (which is too common a color) */
70
71 /*****************************************************************************
72  * vout_sys_t: video output DirectX method descriptor
73  *****************************************************************************
74  * This structure is part of the video output thread descriptor.
75  * It describes the DirectX specific properties of an output thread.
76  *****************************************************************************/
77 typedef struct vout_sys_s
78 {
79
80     LPDIRECTDRAW          p_ddobject;                   /* DirectDraw object */
81     LPDIRECTDRAWSURFACE   p_display;                       /* display device */
82     LPDIRECTDRAWSURFACE   p_overlay;                       /* overlay device */
83     LPDIRECTDRAWCLIPPER   p_clipper;                              /* clipper */
84     HWND                  hwnd;                        /* Handle of the main */
85                                                                    /* window */
86
87     int         i_image_width;                  /* size of the decoded image */
88     int         i_image_height;
89     int         i_window_width;               /* size of the displayed image */
90     int         i_window_height;
91
92     boolean_t   b_display_enabled;
93     boolean_t   b_overlay;
94     boolean_t   b_cursor;
95
96     boolean_t   b_cursor_autohidden;
97     mtime_t     i_lastmoved;
98
99     char       *p_windx_buf[2];                        /* Buffer information */
100
101 } vout_sys_t;
102
103 /*****************************************************************************
104  * Local prototypes.
105  *****************************************************************************/
106 static int  vout_Probe     ( probedata_t *p_data );
107 static int  vout_Create    ( struct vout_thread_s * );
108 static int  vout_Init      ( struct vout_thread_s * );
109 static void vout_End       ( struct vout_thread_s * );
110 static void vout_Destroy   ( struct vout_thread_s * );
111 static int  vout_Manage    ( struct vout_thread_s * );
112 static void vout_Display   ( struct vout_thread_s * );
113 static void vout_SetPalette( p_vout_thread_t p_vout, u16 *red, u16 *green,
114                              u16 *blue, u16 *transp );
115
116 static int  WinDXCreateWindow     ( vout_thread_t *p_vout );
117 static int  WinDXInitDDraw        ( vout_thread_t *p_vout );
118 static int  WinDXCreateDisplay    ( vout_thread_t *p_vout );
119 static int  WinDXCreateYUVOverlay ( vout_thread_t *p_vout );
120 static int  WinDXUpdateOverlay    ( vout_thread_t *p_vout );
121 static int  WinDXClipOverlay      ( vout_thread_t *p_vout );
122 static void WinDXCloseDDraw       ( vout_thread_t *p_vout );
123 static void WinDXCloseWindow      ( vout_thread_t *p_vout );
124 static void WinDXCloseDisplay     ( vout_thread_t *p_vout );
125 static void WinDXCloseYUVOverlay  ( vout_thread_t *p_vout );
126
127 /*****************************************************************************
128  * Functions exported as capabilities. They are declared as static so that
129  * we don't pollute the namespace too much.
130  *****************************************************************************/
131 void _M( vout_getfunctions )( function_list_t * p_function_list )
132 {
133     p_function_list->pf_probe = vout_Probe;
134     p_function_list->functions.vout.pf_create     = vout_Create;
135     p_function_list->functions.vout.pf_init       = vout_Init;
136     p_function_list->functions.vout.pf_end        = vout_End;
137     p_function_list->functions.vout.pf_destroy    = vout_Destroy;
138     p_function_list->functions.vout.pf_manage     = vout_Manage;
139     p_function_list->functions.vout.pf_display    = vout_Display;
140     p_function_list->functions.vout.pf_setpalette = vout_SetPalette;
141 }
142
143 /*****************************************************************************
144  * vout_Probe: probe the video driver and return a score
145  *****************************************************************************
146  * This function tries to initialize Windows DirectX and returns a score to
147  * the plugin manager so that it can select the best plugin.
148  *****************************************************************************/
149 static int vout_Probe( probedata_t *p_data )
150 {
151     if( TestMethod( VOUT_METHOD_VAR, "directx" ) )
152     {
153         return( 999 );
154     }
155
156     return( 400 );
157 }
158
159 /*****************************************************************************
160  * vout_Create: allocate DirectX video thread output method
161  *****************************************************************************
162  * This function allocates and initialize the DirectX vout method.
163  *****************************************************************************/
164 static int vout_Create( vout_thread_t *p_vout )
165 {
166     /* Allocate structure */
167     p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
168     if( p_vout->p_sys == NULL )
169     {
170         intf_ErrMsg( "vout error: can't create p_sys (%s)", strerror(ENOMEM) );
171         return( 1 );
172     }
173
174     p_vout->p_sys->b_cursor = 1; /* TODO should be done with a main_GetInt.. */
175
176     p_vout->p_sys->b_cursor_autohidden = 0;
177     p_vout->p_sys->b_display_enabled = 0;
178
179     p_vout->p_sys->i_lastmoved = mdate();
180
181     p_vout->b_fullscreen = main_GetIntVariable( VOUT_FULLSCREEN_VAR,
182                                                 VOUT_FULLSCREEN_DEFAULT );
183     p_vout->p_sys->b_overlay = main_GetIntVariable( VOUT_OVERLAY_VAR,
184                                                     VOUT_OVERLAY_DEFAULT );
185     p_vout->p_sys->i_window_width = main_GetIntVariable( VOUT_WIDTH_VAR,
186                                                          VOUT_WIDTH_DEFAULT );
187     p_vout->p_sys->i_window_height = main_GetIntVariable( VOUT_HEIGHT_VAR,
188                                                          VOUT_HEIGHT_DEFAULT );
189     /* We don't know yet the dimensions of the video so the best guess is to
190      * pick the same as the window */
191     p_vout->p_sys->i_image_width = p_vout->p_sys->i_window_width;
192     p_vout->p_sys->i_image_height = p_vout->p_sys->i_window_height;
193
194     /* Create a window for the video */
195     /* Creating a window under Windows also initializes the thread's event
196      * message qeue */
197     if( WinDXCreateWindow( p_vout ) )
198     {
199         intf_ErrMsg( "vout error: can't create window" );
200         free( p_vout->p_sys );
201         return ( 1 );
202     }
203
204     /* Initialise DirectDraw */
205     if( WinDXInitDDraw( p_vout ) )
206     {
207         intf_ErrMsg( "vout error: can't initialise DirectDraw" );
208         WinDXCloseWindow( p_vout );
209         free( p_vout->p_sys );
210         return ( 1 );
211     }
212
213     /* create the directx display */
214     if( WinDXCreateDisplay( p_vout ) )
215     {
216         intf_ErrMsg( "vout error: can't initialise DirectDraw" );
217         WinDXCloseDDraw( p_vout );
218         WinDXCloseWindow( p_vout );
219         free( p_vout->p_sys );
220         return ( 1 );
221     }
222
223     return( 0 );
224 }
225
226 /*****************************************************************************
227  * vout_Init: initialize DirectX video thread output method
228  *****************************************************************************
229  *
230  *****************************************************************************/
231 static int vout_Init( vout_thread_t *p_vout )
232 {
233     return( 0 );
234 }
235
236 /*****************************************************************************
237  * vout_End: terminate Sys video thread output method
238  *****************************************************************************
239  * Terminate an output method created by vout_Create.
240  * It is called at the end of the thread.
241  *****************************************************************************/
242 static void vout_End( vout_thread_t *p_vout )
243 {
244     return;
245 }
246
247 /*****************************************************************************
248  * vout_Destroy: destroy Sys video thread output method
249  *****************************************************************************
250  * Terminate an output method created by vout_Create
251  *****************************************************************************/
252 static void vout_Destroy( vout_thread_t *p_vout )
253 {
254     WinDXCloseDisplay( p_vout );
255     WinDXCloseDDraw( p_vout );
256     WinDXCloseWindow( p_vout );
257
258     if( p_vout->p_sys != NULL )
259     {
260         free( p_vout->p_sys );
261         p_vout->p_sys = NULL;
262     }
263
264 }
265
266 /*****************************************************************************
267  * vout_Manage: handle Sys events
268  *****************************************************************************
269  * This function should be called regularly by video output thread. It returns
270  * a non null value if an error occured.
271  *****************************************************************************/
272 static int vout_Manage( vout_thread_t *p_vout )
273 {
274     MSG msg;
275     WINDOWPLACEMENT window_placement;
276
277     while( PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE ) )
278     {
279         if( GetMessage(&msg, NULL, 0, 0) >= 0 )
280         {
281             switch( msg.message )
282             {
283                 case WM_QUIT:
284                     intf_WarnMsg( 3, "vout: WinDX vout_Manage WM_QUIT" );
285                     p_main->p_intf->b_die = 1;
286                     break;
287
288                 case WM_MOVE:
289                     intf_WarnMsg( 3, "vout: WinDX vout_Manage WM_MOVE" );
290                     if( !p_vout->b_need_render )
291                     {
292                         WinDXUpdateOverlay( p_vout );
293                     }
294                     /* don't create a never ending loop */
295                     return( 0 );
296                     break;
297
298                 case WM_PAINT:
299                     intf_WarnMsg( 3, "vout: WinDX vout_Manage WM_PAINT" );
300                     if( !p_vout->b_need_render )
301                     {
302                         WinDXClipOverlay( p_vout );
303                     }
304                     /* don't create a never ending loop */
305                     return( 0 );
306                     break;
307
308                 case WM_CHAR:
309                     intf_WarnMsg( 3, "vout: WinDX WinProc WM_CHAR" );
310                     switch( msg.wParam )
311                     {
312                         case 'q':
313                         case 'Q':
314                             p_main->p_intf->b_die = 1;
315                             break;
316
317                         case 'f':
318                         case 'F':
319                             p_vout->i_changes |= VOUT_FULLSCREEN_CHANGE;
320                             break;
321
322                         case '0': network_ChannelJoin( 0 ); break;
323                         case '1': network_ChannelJoin( 1 ); break;
324                         case '2': network_ChannelJoin( 2 ); break;
325                         case '3': network_ChannelJoin( 3 ); break;
326                         case '4': network_ChannelJoin( 4 ); break;
327                         case '5': network_ChannelJoin( 5 ); break;
328                         case '6': network_ChannelJoin( 6 ); break;
329                         case '7': network_ChannelJoin( 7 ); break;
330                         case '8': network_ChannelJoin( 8 ); break;
331                         case '9': network_ChannelJoin( 9 ); break;
332
333                         default:
334                             if( intf_ProcessKey( p_main->p_intf,
335                                                  (char )msg.wParam ) )
336                             {
337                                intf_DbgMsg( "unhandled key '%c' (%i)",
338                                             (char)msg.wParam, msg.wParam );
339                             }
340                             break;
341                     }
342
343                 default:
344                 break;
345             }
346             TranslateMessage(&msg);
347             DispatchMessage(&msg);
348         }
349         else
350         {
351             return( 1 );
352         }
353
354     }
355
356
357     /*
358      * Fullscreen change
359      */
360     if( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE )
361     {
362         p_vout->b_fullscreen = ! p_vout->b_fullscreen;
363
364         /* We need to switch between Maximized and Normal sized window */
365         window_placement.length = sizeof(WINDOWPLACEMENT);
366         GetWindowPlacement( p_vout->p_sys->hwnd, &window_placement );
367         if( p_vout->b_fullscreen )
368         {
369             /* Maximized window */
370             window_placement.showCmd = SW_SHOWMAXIMIZED;
371             /* Change window style, no borders and no title bar */
372             SetWindowLong( p_vout->p_sys->hwnd, GWL_STYLE, 0 );
373
374         }
375         else
376         {
377             /* Normal window */
378             window_placement.showCmd = SW_SHOWNORMAL;
379             /* Change window style, borders and title bar */
380             SetWindowLong( p_vout->p_sys->hwnd, GWL_STYLE,
381                            WS_OVERLAPPEDWINDOW | WS_SIZEBOX | WS_VISIBLE );
382         }
383
384         SetWindowPlacement( p_vout->p_sys->hwnd, &window_placement );
385         /*WinDXUpdateOverlay( p_vout );*/
386
387         p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
388     }
389
390     return( 0 );
391 }
392
393 /*****************************************************************************
394  * vout_SetPalette: sets an 8 bpp palette
395  *****************************************************************************
396  * This function sets the palette given as an argument. It does not return
397  * anything, but could later send information on which colors it was unable
398  * to set.
399  *****************************************************************************/
400 static void vout_SetPalette( p_vout_thread_t p_vout, u16 *red, u16 *green,
401                          u16 *blue, u16 *transp)
402 {
403     /* Nothing yet */
404     return;
405 }
406
407 /*****************************************************************************
408  * vout_Display: displays previously rendered output
409  *****************************************************************************
410  * This function send the currently rendered image to the display, wait until
411  * it is displayed and switch the two rendering buffer, preparing next frame.
412  *****************************************************************************/
413 static void vout_Display( vout_thread_t *p_vout )
414 {
415     DDSURFACEDESC ddsd;
416     HRESULT       dxresult;
417     int           i;
418     int           i_image_width  = p_vout->p_rendered_pic->i_width;
419     int           i_image_height = p_vout->p_rendered_pic->i_height;
420
421
422     if( (p_vout->p_sys->p_display == NULL) )
423     {
424         intf_WarnMsg( 3, "vout error: WinDX no display!!" );
425         return;
426     }
427
428     /* The first time this function is called it enables the display */
429     p_vout->p_sys->b_display_enabled = 1;
430
431     if( p_vout->b_need_render )
432     {
433         /* Nothing yet */
434     }
435     else
436     {
437         /*
438          * p_vout->p_rendered_pic->p_y/u/v contains the YUV buffers to
439          * render
440          */
441         /* TODO: support for streams other than 4:2:0 */
442
443         /* if the size of the decoded pictures has changed then we close the
444          * YUVOverlay (which doesn't have the right size anymore). */
445         if( p_vout->p_sys->i_image_width != i_image_width
446             || p_vout->p_sys->i_image_height != i_image_height )
447         {
448             intf_WarnMsg( 3, "vout: WinDX overlay size changed" );
449             p_vout->p_sys->i_image_width = i_image_width;
450             p_vout->p_sys->i_image_height = i_image_height;
451             WinDXCloseYUVOverlay( p_vout );
452         }
453
454         if( p_vout->p_sys->p_overlay == NULL )
455         {
456             intf_WarnMsg( 3, "vout: WinDX no overlay, open one..." );
457             if( WinDXCreateYUVOverlay( p_vout ) )
458             {
459                 intf_WarnMsg( 3, "vout: WinDX cannot open a new overlay !!" );
460                 return;
461             }
462             /* Display the Overlay */
463             p_vout->p_sys->b_display_enabled = 1;
464             WinDXUpdateOverlay( p_vout );
465         }
466
467         /* Lock the overlay surface */
468         memset( &ddsd, 0, sizeof( DDSURFACEDESC ));
469         ddsd.dwSize = sizeof(DDSURFACEDESC);
470         dxresult = IDirectDrawSurface_Lock(p_vout->p_sys->p_overlay, NULL,
471                                            &ddsd, DDLOCK_NOSYSLOCK, NULL);
472         if ( dxresult == DDERR_SURFACELOST )
473         {
474             /* Your surface can be lost (thanks to windows) so be sure
475              * to check this and restore it if needed */
476             dxresult = IDirectDrawSurface_Restore( p_vout->p_sys->p_overlay );
477             dxresult = IDirectDrawSurface_Lock( p_vout->p_sys->p_overlay,
478                                                 NULL, &ddsd, DDLOCK_NOSYSLOCK
479                                                 | DDLOCK_WAIT, NULL);
480         }
481         if( dxresult != DD_OK )
482         {
483             intf_WarnMsg( 3, "vout: WinDX could not lock the surface" );
484             return;
485         }
486
487         /* Now we can do the actual image copy.
488          * The copy has to be done line by line because of the special case
489          * when the Pitch does not equal the width of the picture */
490         for( i=0; i < ddsd.dwHeight/2; i++)
491         {
492             /* copy Y, we copy two lines at once */
493             memcpy(ddsd.lpSurface + i*2*ddsd.u1.lPitch,
494                    p_vout->p_rendered_pic->p_y + i*2*i_image_width,
495                    i_image_width);
496             memcpy(ddsd.lpSurface + (i*2+1)*ddsd.u1.lPitch,
497                    p_vout->p_rendered_pic->p_y + (i*2+1)*i_image_width,
498                    i_image_width);
499             /* then V */
500             memcpy((ddsd.lpSurface + ddsd.dwHeight * ddsd.u1.lPitch)
501                       + i * ddsd.u1.lPitch/2,
502                    p_vout->p_rendered_pic->p_v + i*i_image_width/2,
503                    i_image_width/2);
504             /* and U */
505             memcpy((ddsd.lpSurface + ddsd.dwHeight * ddsd.u1.lPitch)
506                       + (ddsd.dwHeight * ddsd.u1.lPitch/4)
507                       + i * ddsd.u1.lPitch/2,
508                    p_vout->p_rendered_pic->p_u + i*i_image_width/2,
509                    i_image_width/2);
510         }
511
512         /* Unlock the Surface */
513         dxresult = IDirectDrawSurface_Unlock(p_vout->p_sys->p_overlay,
514                                              ddsd.lpSurface );
515
516     }
517
518 }
519
520
521 /* following functions are local */
522
523
524 /*****************************************************************************
525  * WinDXEventProc: This is the window event processing function.
526  *****************************************************************************
527  * On Windows, when you create a window you have to attach an event processing
528  * function to it. The aim of this function is to manage "Queued Messages" and
529  * "Nonqueued Messages".
530  * Queued Messages are those picked up and retransmitted by vout_Manage
531  * (using the GetMessage function).
532  * Nonqueued Messages are those that Windows will send directly to this
533  * function (like WM_DESTROY, WM_WINDOWPOSCHANGED...)
534  *****************************************************************************/
535 long FAR PASCAL WinDXEventProc( HWND hwnd, UINT message,
536                                 WPARAM wParam, LPARAM lParam )
537 {
538     switch( message )
539     {
540
541     case WM_ACTIVATEAPP:
542         intf_WarnMsg( 3, "vout: WinDX WinProc WM_ACTIVEAPP" );
543
544         break;
545
546     case WM_SETCURSOR:
547         intf_WarnMsg( 3, "vout: WinDX WinProc WM_SETCURSOR" );
548         /* turn the cursor off by setting it's value to NULL */
549         SetCursor(NULL);
550         break;
551
552     case WM_CREATE:
553         intf_WarnMsg( 3, "vout: WinDX WinProc WM_CREATE" );
554         break;
555
556     /* test your key states in this case */
557     case WM_KEYDOWN:
558         intf_WarnMsg( 3, "vout: WinDX WinProc WM_KEYDOWN" );
559         switch( wParam )
560         {
561         case VK_ESCAPE:
562         case VK_F12:
563             PostMessage(hwnd,WM_CLOSE,0,0);
564             break;
565
566         }
567         break;
568
569     /* this case is touched when the application is shutting down */
570     case WM_DESTROY:
571         intf_WarnMsg( 3, "vout: WinDX WinProc WM_DESTROY" );
572         PostQuitMessage( 0 );
573         break;
574
575     case WM_QUIT:
576         intf_WarnMsg( 3, "vout: WinDX WinProc WM_QUIT" );
577         break;
578
579     case WM_SYSCOMMAND:
580         switch (wParam)
581         {
582             case SC_SCREENSAVE:                     /* catch the screensaver */
583             case SC_MONITORPOWER:              /* catch the monitor turn-off */
584             intf_WarnMsg( 3, "vout: WinDX WinProc WM_SYSCOMMAND" );
585             return 0;                      /* this stops them from happening */
586         }
587         break;
588
589     case WM_MOVE:
590     case WM_SIZE:
591     case WM_WINDOWPOSCHANGED:
592         intf_WarnMsg( 3, "vout: WinDX WinProc WM_MOVE, WMSIZE" );
593         PostMessage(hwnd,WM_MOVE,0,0);
594
595         break;
596     }
597
598     return DefWindowProc(hwnd, message, wParam, lParam);
599 }
600
601 /*****************************************************************************
602  * WinDXCreateWindow: create a windows window where the video will play.
603  *****************************************************************************
604  * Before creating a direct draw surface, we need to create a window in which
605  * the video will be displayed. This window will also allow us to capture the
606  * events.
607  *****************************************************************************/
608 static int WinDXCreateWindow( vout_thread_t *p_vout )
609 {
610     HINSTANCE hInstance;
611     WNDCLASS  wc;                                 /* window class components */
612     RECT      rect_window;
613
614     intf_WarnMsg( 3, "vout: WinDX WinDXCreateWindow" );
615
616     /* get this module's instance */
617     hInstance = GetModuleHandle(NULL);
618
619     /* fill in the window class structure */
620     wc.style         = 0;                               /* no special styles */
621     wc.lpfnWndProc   = (WNDPROC)WinDXEventProc;             /* event handler */
622     wc.cbClsExtra    = 0;                             /* no extra class data */
623     wc.cbWndExtra    = 0;                            /* no extra window data */
624     wc.hInstance     = hInstance;                                /* instance */
625     wc.hIcon         = LoadIcon(NULL, IDI_WINLOGO);   /* load a default icon */
626     wc.hCursor       = LoadCursor(NULL, IDC_ARROW); /* load a default cursor */
627     wc.hbrBackground = NULL;                            /* redraw our own bg */
628     wc.lpszMenuName  = NULL;                                      /* no menu */
629     wc.lpszClassName = "VLC DirectX";                 /* use a special class */
630
631     /* register the window class */
632     if (!RegisterClass(&wc)) {
633         intf_WarnMsg( 3, "vout: WinDX register window FAILED" );
634         return (1);
635     }
636
637     /* when you create a window you give the dimensions you wish it to have.
638      * Unfortunatly these dimensions will include the borders and title bar.
639      * We use the following function to find out the size of the window
640      * corresponding to the useable surface we want */
641     rect_window.top    = 10;
642     rect_window.left   = 10;
643     rect_window.right  = rect_window.left + p_vout->p_sys->i_window_width;
644     rect_window.bottom = rect_window.top + p_vout->p_sys->i_window_height;
645     AdjustWindowRect( &rect_window, WS_OVERLAPPEDWINDOW|WS_SIZEBOX, 0 );
646
647     /* create the window */
648     p_vout->p_sys->hwnd = CreateWindow("VLC DirectX",/* name of window class */
649                     "VLC DirectX",                  /* window title bar text */
650                     WS_OVERLAPPEDWINDOW
651                     | WS_SIZEBOX | WS_VISIBLE,               /* window style */
652                     10,                              /* default X coordinate */
653                     10,                              /* default Y coordinate */
654                     rect_window.right - rect_window.left,    /* window width */
655                     rect_window.bottom - rect_window.top,   /* window height */
656                     NULL,                                /* no parent window */
657                     NULL,                          /* no menu in this window */
658                     hInstance,            /* handle of this program instance */
659                     NULL);                        /* no additional arguments */
660
661     if (p_vout->p_sys->hwnd == NULL) {
662         intf_WarnMsg( 3, "vout: WinDX create window FAILED" );
663         return (1);
664     }
665
666     /* now display the window */
667     ShowWindow(p_vout->p_sys->hwnd, SW_SHOW);
668
669     return ( 0 );
670 }
671
672 /*****************************************************************************
673  * WinDXInitDDraw: Takes care of all the DirectDraw initialisations
674  *****************************************************************************
675  * This function initialise and allocate resources for DirectDraw.
676  *****************************************************************************/
677 static int WinDXInitDDraw( vout_thread_t *p_vout )
678 {
679     HRESULT     dxresult;
680     DWORD       flags;
681
682     intf_WarnMsg( 3, "vout: WinDX WinDXInitDDraw" );
683
684     /* Initialize DirectDraw */
685     dxresult = DirectDrawCreate( NULL, &p_vout->p_sys->p_ddobject, NULL );
686     if( dxresult != DD_OK )
687     {
688         intf_ErrMsg( "vout error: can't initialize Direct Draw" );
689         return( 1 );
690     }
691
692     /* Set DirectDraw Cooperative level, ie what control we want over Windows
693        display */
694     if( p_vout->b_fullscreen )
695     {
696         flags = DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN;
697     }
698     else
699     {
700         flags = DDSCL_NORMAL;
701     }
702
703     dxresult = IDirectDraw_SetCooperativeLevel( p_vout->p_sys->p_ddobject,
704                                                 p_vout->p_sys->hwnd, flags );
705     if( dxresult != DD_OK )
706     {
707         intf_ErrMsg( "vout error: can't set direct draw cooperative level." );
708         IDirectDraw_Release(p_vout->p_sys->p_ddobject);
709         p_vout->p_sys->p_ddobject = NULL;
710         return( 1 );
711     }
712
713     return( 0 );
714 }
715
716 /*****************************************************************************
717  * WinDXCreateDisplay: create the DirectDraw display.
718  *****************************************************************************
719  * Create and initialize display according to preferences specified in the vout
720  * thread fields.
721  *****************************************************************************/
722 static int WinDXCreateDisplay( vout_thread_t *p_vout )
723 {
724     DDCAPS        ddcaps;
725     HRESULT       dxresult;
726     DDSURFACEDESC ddsd;
727     BOOL          bHasOverlay, bHasColorKey, bCanStretch;
728
729     /* Now create the primary surface. This surface is the displayed surface */
730     /* The following two steps are important! */
731     memset( &ddsd, 0, sizeof( DDSURFACEDESC ));
732     ddsd.dwSize = sizeof(DDSURFACEDESC);
733     ddsd.dwFlags = DDSD_CAPS;
734     ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
735
736     dxresult = IDirectDraw_CreateSurface( p_vout->p_sys->p_ddobject,
737                                           &ddsd,
738                                           &p_vout->p_sys->p_display, NULL );
739     if( dxresult != DD_OK )
740     {
741         intf_ErrMsg( "vout error: can't create direct draw primary surface." );
742         p_vout->p_sys->p_display = NULL;
743         return( 1 );
744     }
745
746     /* Now create a clipper for our window.
747      * This clipper prevents us to modify by mistake anything on the screen
748      * (primary surface) which doesn't belong to our window */
749     dxresult = IDirectDraw_CreateClipper(p_vout->p_sys->p_ddobject, 0,
750                                          &p_vout->p_sys->p_clipper, NULL);
751     if( dxresult != DD_OK )
752     {
753         intf_ErrMsg( "vout error: can't create clipper." );
754         IDirectDrawSurface_Release( p_vout->p_sys->p_display );
755         p_vout->p_sys->p_display = NULL;
756         return( 1 );
757     }
758
759     dxresult = IDirectDrawClipper_SetHWnd(p_vout->p_sys->p_clipper, 0,
760                                               p_vout->p_sys->hwnd);
761     if( dxresult != DD_OK )
762     {
763         intf_ErrMsg( "vout error: can't attach clipper to window." );
764         IDirectDrawSurface_Release( p_vout->p_sys->p_display );
765         p_vout->p_sys->p_display = NULL;
766         return( 1 );
767     }
768
769     dxresult = IDirectDrawSurface_SetClipper(p_vout->p_sys->p_display,
770                                               p_vout->p_sys->p_clipper);
771     if( dxresult != DD_OK )
772     {
773         intf_ErrMsg( "vout error: can't attach clipper to surface." );
774         IDirectDrawSurface_Release( p_vout->p_sys->p_display );
775         p_vout->p_sys->p_display = NULL;
776         return( 1 );
777     }
778
779
780     /* Probe the capabilities of the hardware */
781     /* This is just an indication of whever or not we'll support overlay,
782      * but with this test we don't know if we support YUV overlay */
783     memset( &ddcaps, 0, sizeof( DDCAPS ));
784     ddcaps.dwSize = sizeof(DDCAPS);
785     dxresult = IDirectDraw_GetCaps( p_vout->p_sys->p_ddobject,
786                                     &ddcaps, NULL );
787     if(dxresult != DD_OK )
788     {
789         intf_ErrMsg( "vout error: can't get caps." );
790         bHasOverlay  = FALSE;
791         bHasColorKey = FALSE;
792         bCanStretch  = FALSE;
793     }
794     else
795     {
796         /* Determine if the hardware supports overlay surfaces */
797         bHasOverlay = ((ddcaps.dwCaps & DDCAPS_OVERLAY) ==
798                        DDCAPS_OVERLAY) ? TRUE : FALSE;
799         /* Determine if the hardware supports colorkeying */
800         bHasColorKey = ((ddcaps.dwCaps & DDCAPS_COLORKEY) ==
801                         DDCAPS_COLORKEY) ? TRUE : FALSE;
802         /* Determine if the hardware supports scaling of the overlay surface */
803         bCanStretch = ((ddcaps.dwCaps & DDCAPS_OVERLAYSTRETCH) ==
804                        DDCAPS_OVERLAYSTRETCH) ? TRUE : FALSE;
805         intf_WarnMsg( 3, "vout: WinDX Caps: overlay=%i colorkey=%i stretch=%i",
806                          bHasOverlay, bHasColorKey, bCanStretch );
807     }
808
809     if( bHasOverlay && bHasColorKey && bCanStretch )
810     {
811         if( !WinDXCreateYUVOverlay( p_vout ) )
812         {
813            /* Overlay created successfully */
814            p_vout->b_need_render = 0;
815         }
816     }
817
818
819     /* Now do some initialisation for video_output */
820     if( p_vout->b_need_render )
821     {
822         /* if we want a valid pointer to the surface memory, we must lock
823          * the surface */
824         memset( &ddsd, 0, sizeof( DDSURFACEDESC ));
825         ddsd.dwSize = sizeof(DDSURFACEDESC);
826         dxresult = IDirectDrawSurface_Lock(p_vout->p_sys->p_display,
827                                            NULL, &ddsd,
828                                            DDLOCK_NOSYSLOCK, NULL);
829         if ( dxresult == DDERR_SURFACELOST )
830         {
831             /* Your surface can be lost so be sure
832              * to check this and restore it if needed */
833             dxresult = IDirectDrawSurface_Restore( p_vout->p_sys->p_display );
834             dxresult = IDirectDrawSurface_Lock( p_vout->p_sys->p_display,
835                                                 NULL, &ddsd, DDLOCK_NOSYSLOCK
836                                                 | DDLOCK_WAIT, NULL);
837         }
838         if( dxresult != DD_OK )
839         {
840             intf_WarnMsg( 3, "vout: WinDX could not lock the surface" );
841             return( 1 );
842         }
843
844         /* Set the pointer to the surface memory */
845         p_vout->p_sys->p_windx_buf[ 0 ] = ddsd.lpSurface;
846         /* back buffer, none for now */
847         p_vout->p_sys->p_windx_buf[ 1 ] = ddsd.lpSurface;
848
849
850         /* Set thread information */
851         p_vout->i_width =           ddsd.dwWidth;
852         p_vout->i_height =          ddsd.dwHeight;
853         p_vout->i_bytes_per_line =  ddsd.u1.lPitch;
854
855         p_vout->i_screen_depth =    ddsd.ddpfPixelFormat.u1.dwRGBBitCount;
856         p_vout->i_bytes_per_pixel = ddsd.ddpfPixelFormat.u1.dwRGBBitCount/8;
857
858         p_vout->i_red_mask =        ddsd.ddpfPixelFormat.u2.dwRBitMask;
859         p_vout->i_green_mask =      ddsd.ddpfPixelFormat.u3.dwGBitMask;
860         p_vout->i_blue_mask =       ddsd.ddpfPixelFormat.u4.dwBBitMask;
861
862         /* Unlock the Surface */
863         dxresult = IDirectDrawSurface_Unlock(p_vout->p_sys->p_display,
864                                              ddsd.lpSurface );
865         /* FIXME: palette in 8bpp ?? */
866         /* Set and initialize buffers */
867         vout_SetBuffers( p_vout, p_vout->p_sys->p_windx_buf[ 0 ],
868                                  p_vout->p_sys->p_windx_buf[ 1 ] );
869     }
870     else
871     {
872         /* Lock the surface */
873         memset( &ddsd, 0, sizeof( DDSURFACEDESC ));
874         ddsd.dwSize = sizeof(DDSURFACEDESC);
875         dxresult = IDirectDrawSurface_Lock(p_vout->p_sys->p_overlay,
876                                           NULL, &ddsd, DDLOCK_NOSYSLOCK, NULL);
877         if ( dxresult == DDERR_SURFACELOST )
878         {
879             /* Your surface can be lost (thanks to windows) so be sure
880              * to check this every time you want to do something with
881              * it */
882             dxresult = IDirectDrawSurface_Restore(
883                                            p_vout->p_sys->p_overlay );
884             dxresult = IDirectDrawSurface_Lock( p_vout->p_sys->p_overlay
885                         , NULL, &ddsd,DDLOCK_NOSYSLOCK| DDLOCK_WAIT, NULL);
886         }
887         if( dxresult != DD_OK )
888         {
889             intf_WarnMsg( 3, "vout: WinDX could not lock the surface" );
890             return( 1 );
891         }
892
893         p_vout->p_sys->p_windx_buf[ 0 ] = ddsd.lpSurface;
894         p_vout->p_sys->p_windx_buf[ 1 ] = ddsd.lpSurface;
895
896         /* Set thread information */
897         p_vout->i_width =           ddsd.dwWidth;
898         p_vout->i_height =          ddsd.dwHeight;
899         p_vout->i_bytes_per_line =  ddsd.u1.lPitch;
900
901         /* Unlock the Surface */
902         dxresult = IDirectDrawSurface_Unlock(p_vout->p_sys->p_overlay,
903                                              ddsd.lpSurface );
904
905         vout_SetBuffers( p_vout, p_vout->p_sys->p_windx_buf[ 0 ],
906                                  p_vout->p_sys->p_windx_buf[ 1 ] );
907     }
908
909     return( 0 );
910 }
911
912 /*****************************************************************************
913  * WinDXCreateYUVOveraly: create an YUV overlay surface for the video.
914  *****************************************************************************
915  * The best method of display is with an YUV overlay because the YUV->RGB
916  * conversion is done in hardware.
917  * This function will try to create an YUV overlay.
918  *****************************************************************************/
919 static int WinDXCreateYUVOverlay( vout_thread_t *p_vout )
920 {
921     HRESULT dxresult;
922     DDSURFACEDESC ddsd;
923
924     /* Now create the overlay surface. This overlay will be displayed on
925      * top of the primary surface.
926      * A color key is used to determine whether or not the overlay will be
927      * displayed, ie the overlay will be displayed in place of the primary
928      * surface wherever the primary surface will have this color.
929      * This color will be painted by WinDXClipOverlay which in turn is called
930      * by a WM_PAINT event */
931
932     memset( &ddsd, 0, sizeof( DDSURFACEDESC ));
933     ddsd.dwSize = sizeof(DDSURFACEDESC);
934     ddsd.ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT);
935     ddsd.ddpfPixelFormat.dwFlags = DDPF_FOURCC;
936     ddsd.ddpfPixelFormat.dwFourCC = mmioFOURCC('Y','V','1','2');
937     ddsd.ddpfPixelFormat.u1.dwYUVBitCount = 16;
938
939     ddsd.dwSize = sizeof(DDSURFACEDESC);
940     ddsd.dwFlags = DDSD_CAPS |
941                    DDSD_HEIGHT |
942                    DDSD_WIDTH |
943                    DDSD_PIXELFORMAT;
944     ddsd.ddsCaps.dwCaps = DDSCAPS_OVERLAY | DDSCAPS_VIDEOMEMORY;
945     ddsd.dwHeight =  p_vout->p_sys->i_image_height;
946     ddsd.dwWidth =  p_vout->p_sys->i_image_width;
947
948     dxresult = IDirectDraw_CreateSurface( p_vout->p_sys->p_ddobject,
949                                           &ddsd,
950                                           &p_vout->p_sys->p_overlay, NULL );
951     if( dxresult != DD_OK )
952     {
953         intf_ErrMsg( "vout error: can't create overlay surface." );
954     }
955     else
956     {
957         intf_WarnMsg( 3, "vout: WinDX YUV overlay created successfully" );
958     }
959     /* Hide the overlay for now */
960     IDirectDrawSurface_UpdateOverlay(p_vout->p_sys->p_overlay,
961                                      NULL,
962                                      p_vout->p_sys->p_display,
963                                      NULL,
964                                      DDOVER_HIDE,
965                                      NULL);
966
967     return ( 0 );
968 }
969
970 /*****************************************************************************
971  * WinDXUpdateOverlay: Move or resize overlay surface on video display.
972  *****************************************************************************
973  * This function is used to move or resize an overlay surface on the screen.
974  * Ususally the overlay is moved by the user and thus, by a move or resize
975  * event (in vout_Manage).
976  *****************************************************************************/
977 static int WinDXUpdateOverlay( vout_thread_t *p_vout )
978 {
979     DDOVERLAYFX     ddofx;
980     RECT            rect_window, rect_client;
981     DWORD           dwFlags;
982     HRESULT         dxresult;
983
984     if( p_vout->p_sys->p_overlay == NULL || p_vout->b_need_render)
985     {
986         intf_WarnMsg( 3, "vout: WinDX no overlay !!" );
987         return( 0 );
988     }
989
990     if( !p_vout->p_sys->b_display_enabled )
991     {
992         return( 0 );
993     }
994
995
996     /* Now get the coordinates of the window. We don't actually want the
997      * window coordinates but these of the usable surface inside the window.
998      * By specification rect_client.right = rect_client.top = 0 */
999     GetWindowRect(p_vout->p_sys->hwnd, &rect_window);
1000     GetClientRect(p_vout->p_sys->hwnd, &rect_client);;
1001     rect_window.left = ( (rect_window.right - rect_window.left) -
1002                           rect_client.right ) / 2 + rect_window.left;
1003     rect_window.right = rect_window.left + rect_client.right;
1004     rect_window.top = rect_window.bottom - rect_client.bottom;
1005
1006     /* We want to keep the aspect ratio of the video */
1007     if( p_vout->b_scale )
1008     {
1009         switch( p_vout->p_rendered_pic->i_aspect_ratio )
1010         {
1011             case AR_16_9_PICTURE:
1012             if( ((rect_window.right-rect_window.left)*9)
1013                 > ((rect_window.bottom-rect_window.top)*16) )
1014             {
1015                 int temp;
1016                 temp = (rect_window.bottom-rect_window.top)*16/9;
1017                 temp = (rect_window.right-rect_window.left) - temp;
1018                 rect_window.left += (temp/2);
1019                 rect_window.right -= (temp/2);
1020             }
1021             else
1022             {
1023                 int temp;
1024                 temp = (rect_window.right-rect_window.left)*9/16;
1025                 temp = (rect_window.bottom-rect_window.top) - temp;
1026                 rect_window.top += (temp/2);
1027                 rect_window.bottom -= (temp/2);
1028             }
1029             break;
1030
1031             case AR_221_1_PICTURE:
1032             if( ((rect_window.right-rect_window.left)*100)
1033                 > ((rect_window.bottom-rect_window.top)*221) )
1034             {
1035                 int temp;
1036                 temp = (rect_window.bottom-rect_window.top)*221/100;
1037                 temp = (rect_window.right-rect_window.left) - temp;
1038                 rect_window.left += (temp/2);
1039                 rect_window.right -= (temp/2);
1040             }
1041             else
1042             {
1043                 int temp;
1044                 temp = (rect_window.right-rect_window.left)*100/221;
1045                 temp = (rect_window.bottom-rect_window.top) - temp;
1046                 rect_window.top += (temp/2);
1047                 rect_window.bottom -= (temp/2);
1048             }
1049             break;
1050
1051             case AR_SQUARE_PICTURE:
1052             if( (rect_window.right-rect_window.left)
1053                 > (rect_window.bottom-rect_window.top) )
1054             {
1055                 int temp;
1056                 temp = (rect_window.bottom-rect_window.top);
1057                 temp = (rect_window.right-rect_window.left) - temp;
1058                 rect_window.left += (temp/2);
1059                 rect_window.right -= (temp/2);
1060             }
1061             else
1062             {
1063                 int temp;
1064                 temp = (rect_window.right-rect_window.left);
1065                 temp = (rect_window.bottom-rect_window.top) - temp;
1066                 rect_window.top += (temp/2);
1067                 rect_window.bottom -= (temp/2);
1068             }
1069             break;
1070
1071             case AR_3_4_PICTURE:
1072             default:
1073             if( ((rect_window.right-rect_window.left)*3)
1074                 > ((rect_window.bottom-rect_window.top)*4) )
1075             {
1076                 int temp;
1077                 temp = (rect_window.bottom-rect_window.top)*4/3;
1078                 temp = (rect_window.right-rect_window.left) - temp;
1079                 rect_window.left += (temp/2);
1080                 rect_window.right -= (temp/2);
1081             }
1082             else
1083             {
1084                 int temp;
1085                 temp = (rect_window.right-rect_window.left)*3/4;
1086                 temp = (rect_window.bottom-rect_window.top) - temp;
1087                 rect_window.top += (temp/2);
1088                 rect_window.bottom -= (temp/2);
1089             }
1090             break;
1091         }
1092     }
1093
1094
1095     /* Position and show the overlay */
1096     memset(&ddofx, 0, sizeof(DDOVERLAYFX));
1097     ddofx.dwSize = sizeof(DDOVERLAYFX);
1098     ddofx.dckDestColorkey.dwColorSpaceLowValue = OVERLAY_COLOR_KEY;
1099     ddofx.dckDestColorkey.dwColorSpaceHighValue = OVERLAY_COLOR_KEY;
1100
1101     dwFlags = DDOVER_KEYDESTOVERRIDE | DDOVER_SHOW;
1102
1103     dxresult = IDirectDrawSurface_UpdateOverlay(p_vout->p_sys->p_overlay,
1104                                                 NULL,
1105                                                 p_vout->p_sys->p_display,
1106                                                 &rect_window,
1107                                                 dwFlags,
1108                                                 &ddofx);
1109     if(dxresult != DD_OK)
1110     {
1111         intf_WarnMsg( 3, "vout: WinDX WM_MOVE can't move or resize overlay" );
1112     }
1113
1114     return ( 0 );
1115 }
1116
1117 /*****************************************************************************
1118  * WinDXClipOveraly: Clip overlay surface on video display.
1119  *****************************************************************************
1120  * The overlay is displayed on top of the primary surface (which is the
1121  * screen).
1122  * This overlay must be clipped whenever another window is supposed to cover
1123  * it.
1124  * For this, we use a color key which we paint on the parts of the window
1125  * which aren't covered by anything else. The video adapter will then only
1126  * display the overlay on the surfaces painted with this color key.
1127  * This function is called whenever a WM_PAINT event is generated
1128  * (in vout_Manage).
1129  *****************************************************************************/
1130 static int WinDXClipOverlay( vout_thread_t *p_vout )
1131 {
1132     PAINTSTRUCT ps;
1133     POINT       ptClient;
1134     RECT        rectBlt;
1135     DDBLTFX     ddbfx;
1136
1137     if( p_vout->p_sys->p_overlay == NULL || p_vout->b_need_render)
1138     {
1139         intf_WarnMsg( 3, "vout: WinDX no overlay !!" );
1140         return( 0 );
1141     }
1142
1143     BeginPaint(p_vout->p_sys->hwnd, &ps);
1144
1145     /* Fill the client area with colour key */
1146     ptClient.x = ps.rcPaint.left;
1147     ptClient.y = ps.rcPaint.top;
1148     ClientToScreen(p_vout->p_sys->hwnd, &ptClient);
1149     rectBlt.left = ptClient.x;
1150     rectBlt.top = ptClient.y;
1151
1152     ptClient.x = ps.rcPaint.right;
1153     ptClient.y = ps.rcPaint.bottom;
1154     ClientToScreen(p_vout->p_sys->hwnd, &ptClient);
1155     rectBlt.right = ptClient.x;
1156     rectBlt.bottom = ptClient.y;
1157
1158     memset(&ddbfx, 0, sizeof(DDBLTFX));
1159     ddbfx.dwSize = sizeof(DDBLTFX);
1160     ddbfx.u5.dwFillColor = OVERLAY_COLOR_KEY;
1161
1162     IDirectDrawSurface_Blt(p_vout->p_sys->p_display,
1163                            &rectBlt,
1164                            NULL,
1165                            &rectBlt,
1166                            DDBLT_COLORFILL, // | DDBLT_WAIT,
1167                            &ddbfx);
1168
1169     EndPaint(p_vout->p_sys->hwnd, &ps);
1170
1171     return ( 0 );
1172 }
1173
1174 /*****************************************************************************
1175  * WinDXCloseWindow: close the window created by WinDXCreateWindow
1176  *****************************************************************************
1177  * This function returns all resources allocated by WinDXCreateWindow.
1178  *****************************************************************************/
1179 static void WinDXCloseWindow( vout_thread_t *p_vout )
1180 {
1181     HINSTANCE hInstance;
1182
1183     if( p_vout->p_sys->hwnd != INVALID_HANDLE_VALUE )
1184     {
1185         DestroyWindow( p_vout->p_sys->hwnd);
1186         p_vout->p_sys->hwnd = INVALID_HANDLE_VALUE;
1187     }
1188
1189     hInstance = GetModuleHandle(NULL);
1190     UnregisterClass( "VLC DirectX",                            /* class name */
1191                      hInstance );          /* handle to application instance */
1192
1193 }
1194
1195 /*****************************************************************************
1196  * WinDXCloseDDraw: Release the DDraw object allocated by WinDXInitDDraw
1197  *****************************************************************************
1198  * This function returns all resources allocated by WinDXInitDDraw.
1199  *****************************************************************************/
1200 static void WinDXCloseDDraw( vout_thread_t *p_vout )
1201 {
1202     if( p_vout->p_sys->p_ddobject != NULL )
1203     {
1204         IDirectDraw_Release(p_vout->p_sys->p_ddobject);
1205         p_vout->p_sys->p_ddobject = NULL;
1206     }
1207 }
1208
1209 /*****************************************************************************
1210  * WinDXCloseDisplay: close and reset DirectX device
1211  *****************************************************************************
1212  * This function returns all resources allocated by WinDXCreateDisplay and
1213  * restore the original state of the device.
1214  *****************************************************************************/
1215 static void WinDXCloseDisplay( vout_thread_t *p_vout )
1216 {
1217     if( p_vout->p_sys->p_display != NULL )
1218     {
1219         if( p_vout->p_sys->p_overlay != NULL )
1220         {
1221             IDirectDraw_Release( p_vout->p_sys->p_overlay );
1222             p_vout->p_sys->p_overlay = NULL;
1223         }
1224
1225         if( p_vout->p_sys->p_clipper != NULL )
1226         {
1227             IDirectDraw_Release( p_vout->p_sys->p_clipper );
1228             p_vout->p_sys->p_clipper = NULL;
1229         }
1230
1231         IDirectDraw_Release( p_vout->p_sys->p_display );
1232         p_vout->p_sys->p_display = NULL;
1233     }
1234 }
1235
1236 /*****************************************************************************
1237  * WinDXCloseYUVOverlay: close the overlay surface
1238  *****************************************************************************
1239  * This function returns all resources allocated by the overlay surface.
1240  * We also call this function when the decoded picture change its dimensions
1241  * (in that case we close the overlay surface and reopen another with the
1242  * right dimensions).
1243  *****************************************************************************/
1244 static void WinDXCloseYUVOverlay( vout_thread_t *p_vout )
1245 {
1246     if( p_vout->p_sys->p_overlay != NULL )
1247     {
1248         IDirectDraw_Release( p_vout->p_sys->p_overlay );
1249         p_vout->p_sys->p_overlay = NULL;
1250     }
1251     p_vout->p_sys->b_display_enabled = 0;
1252 }
1253