]> git.sesse.net Git - vlc/blob - plugins/directx/vout_directx.c
* Fixed a segfault on exit under Windows 2000
[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.10 2001/08/05 15:32:46 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 #define MODULE_NAME directx
25 #include "modules_inner.h"
26
27 /* ToDo:
28  *
29  * Double buffering
30  *
31  * Port this plugin to Video Output IV
32  */
33
34 /*****************************************************************************
35  * Preamble:
36  *
37  * This plugin will use YUV overlay if supported, using overlay will result in
38  * the best video quality (hardware interpolation when rescaling the picture)
39  * and the fastest display as it requires less processing.
40  *
41  * If YUV overlay is not supported the plugin will use an RGB offscreen video
42  * surface that will be blitted onto the primary surface (display) to
43  * effectively display the picture. this fallback method enables us to display
44  * video in window mode.
45  * Another fallback method (which isn't implemented yet) would be to use the
46  * primary surface as the video buffer. This would allow for better
47  * performance but this is restricted to fullscreen video. In short,
48  * implementing this is not considered high priority.
49  * 
50  *****************************************************************************/
51 #include "defs.h"
52
53 #include <errno.h>                                                 /* ENOMEM */
54 #include <stdlib.h>                                                /* free() */
55 #include <string.h>                                            /* strerror() */
56
57 #include <windows.h>
58 #include <windowsx.h>
59
60 #if defined( _MSC_VER )
61 #   include <ddraw.h>
62 #else
63 #   include <directx.h>
64 #endif
65
66 #include "config.h"
67 #include "common.h"
68 #include "threads.h"
69 #include "mtime.h"
70 #include "tests.h"
71 #include "netutils.h"
72
73 #include "video.h"
74 #include "video_output.h"
75
76 #include "intf_msg.h"
77 #include "interface.h"
78 #include "main.h"
79
80 #include "modules.h"
81 #include "modules_export.h"
82
83 #include "vout_directx.h"
84
85 /*****************************************************************************
86  * Local prototypes.
87  *****************************************************************************/
88 static int  vout_Probe     ( probedata_t *p_data );
89 static int  vout_Create    ( struct vout_thread_s * );
90 static int  vout_Init      ( struct vout_thread_s * );
91 static void vout_End       ( struct vout_thread_s * );
92 static void vout_Destroy   ( struct vout_thread_s * );
93 static int  vout_Manage    ( struct vout_thread_s * );
94 static void vout_Display   ( struct vout_thread_s * );
95 static void vout_SetPalette( p_vout_thread_t p_vout, u16 *red, u16 *green,
96                              u16 *blue, u16 *transp );
97
98 static int  DirectXInitDDraw      ( vout_thread_t *p_vout );
99 static int  DirectXCreateDisplay  ( vout_thread_t *p_vout );
100 static int  DirectXCreateSurface  ( vout_thread_t *p_vout );
101 static int  DirectXCreateClipper  ( vout_thread_t *p_vout );
102 static int  DirectXUpdateOverlay  ( vout_thread_t *p_vout );
103 static void DirectXCloseDDraw     ( vout_thread_t *p_vout );
104 static void DirectXCloseDisplay   ( vout_thread_t *p_vout );
105 static void DirectXCloseSurface   ( vout_thread_t *p_vout );
106 static void DirectXKeepAspectRatio( vout_thread_t *p_vout, RECT *coordinates );
107
108 /*****************************************************************************
109  * Functions exported as capabilities. They are declared as static so that
110  * we don't pollute the namespace too much.
111  *****************************************************************************/
112 void _M( vout_getfunctions )( function_list_t * p_function_list )
113 {
114     p_function_list->pf_probe = vout_Probe;
115     p_function_list->functions.vout.pf_create     = vout_Create;
116     p_function_list->functions.vout.pf_init       = vout_Init;
117     p_function_list->functions.vout.pf_end        = vout_End;
118     p_function_list->functions.vout.pf_destroy    = vout_Destroy;
119     p_function_list->functions.vout.pf_manage     = vout_Manage;
120     p_function_list->functions.vout.pf_display    = vout_Display;
121     p_function_list->functions.vout.pf_setpalette = vout_SetPalette;
122 }
123
124 /*****************************************************************************
125  * vout_Probe: probe the video driver and return a score
126  *****************************************************************************
127  * This function tries to initialize Windows DirectX and returns a score to
128  * the plugin manager so that it can select the best plugin.
129  *****************************************************************************/
130 static int vout_Probe( probedata_t *p_data )
131 {
132
133     if( TestMethod( VOUT_METHOD_VAR, "directx" ) )
134     {
135         return( 999 );
136     }
137
138     /* Check that at least DirectX5 is installed on the computer */
139     /* Fixme */
140
141     return( 400 );
142 }
143
144 /*****************************************************************************
145  * vout_Create: allocate DirectX video thread output method
146  *****************************************************************************
147  * This function allocates and initialize the DirectX vout method.
148  *****************************************************************************/
149 static int vout_Create( vout_thread_t *p_vout )
150 {
151     /* Allocate structure */
152     p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
153     if( p_vout->p_sys == NULL )
154     {
155         intf_ErrMsg( "vout error: can't create p_sys (%s)", strerror(ENOMEM) );
156         return( 1 );
157     }
158
159     /* Initialisations */
160     p_vout->p_sys->p_ddobject = NULL;
161     p_vout->p_sys->p_display = NULL;
162     p_vout->p_sys->p_surface = NULL;
163     p_vout->p_sys->p_clipper = NULL;
164     p_vout->p_sys->hbrush = NULL;
165     p_vout->p_sys->hwnd = NULL;
166     p_vout->p_sys->i_changes = 0;
167     p_vout->p_sys->b_event_thread_die = 0;
168     p_vout->p_sys->b_display_enabled = 0;
169
170     p_vout->p_sys->b_cursor = 1; /* TODO should be done with a main_GetInt.. */
171
172     p_vout->p_sys->b_cursor_autohidden = 0;
173     p_vout->p_sys->i_lastmoved = mdate();
174
175     p_vout->b_fullscreen = main_GetIntVariable( VOUT_FULLSCREEN_VAR,
176                                                 VOUT_FULLSCREEN_DEFAULT );
177 #if 0
178     p_vout->b_need_render = !main_GetIntVariable( VOUT_OVERLAY_VAR,
179                                                   VOUT_OVERLAY_DEFAULT );
180 #else
181     p_vout->b_need_render = 0;                          /* default = overlay */
182 #endif
183     p_vout->p_sys->i_window_width = main_GetIntVariable( VOUT_WIDTH_VAR,
184                                                          VOUT_WIDTH_DEFAULT );
185     p_vout->p_sys->i_window_height = main_GetIntVariable( VOUT_HEIGHT_VAR,
186                                                          VOUT_HEIGHT_DEFAULT );
187     /* We don't know yet the dimensions of the video so the best guess is to
188      * pick the same as the window */
189     p_vout->p_sys->i_image_width = p_vout->p_sys->i_window_width;
190     p_vout->p_sys->i_image_height = p_vout->p_sys->i_window_height;
191
192  
193     /* Set locks and condition variables */
194     vlc_mutex_init( &p_vout->p_sys->event_thread_lock );
195     vlc_cond_init( &p_vout->p_sys->event_thread_wait );
196     p_vout->p_sys->i_event_thread_status = THREAD_CREATE;
197
198     /* Create the DirectXEventThread, this thread is created by us to isolate
199      * the Win32 PeekMessage function calls. We want to do this because
200      * Windows can stay blocked inside this call for a long time, and when
201      * this happens it thus blocks vlc's video_output thread.
202      * DirectXEventThread will take care of the creation of the video
203      * window (because PeekMessage has to be called from the same thread which
204      * created the window). */
205     intf_WarnMsg( 3, "vout: vout_Create creating DirectXEventThread" );
206     if( vlc_thread_create( &p_vout->p_sys->event_thread_id,
207                            "DirectX Events Thread",
208                            (void *) DirectXEventThread, (void *) p_vout) )
209     {
210         intf_ErrMsg( "vout error: can't create DirectXEventThread" );
211         intf_ErrMsg("vout error: %s", strerror(ENOMEM));
212         free( p_vout->p_sys );
213         return( 1 );
214     }
215
216     /* We need to wait for the actual creation of the thread and window */
217     if( p_vout->p_sys->i_event_thread_status == THREAD_CREATE )
218     {
219         vlc_mutex_lock( &p_vout->p_sys->event_thread_lock );
220         vlc_cond_wait ( &p_vout->p_sys->event_thread_wait,
221                         &p_vout->p_sys->event_thread_lock );
222         vlc_mutex_unlock( &p_vout->p_sys->event_thread_lock );
223     }
224     if( p_vout->p_sys->i_event_thread_status != THREAD_READY )
225     {
226         intf_ErrMsg( "vout error: DirectXEventThread failed" );
227         free( p_vout->p_sys );
228         return( 1 );
229     }
230
231
232     intf_WarnMsg( 3, "vout : vout_Create DirectXEventThread running" );
233
234     /* Initialise DirectDraw */
235     if( DirectXInitDDraw( p_vout ) )
236     {
237         intf_ErrMsg( "vout error: can't initialise DirectDraw" );
238
239         /* Kill DirectXEventThread */
240         p_vout->p_sys->b_event_thread_die = 1;
241         /* we need to be sure DirectXEventThread won't stay stuck in
242          * GetMessage, so we send a fake message */
243         PostMessage( p_vout->p_sys->hwnd, WM_CHAR, (WPARAM)'^', 0);
244         vlc_thread_join( p_vout->p_sys->event_thread_id );
245
246         return ( 1 );
247     }
248
249     /* Create the directx display */
250     if( DirectXCreateDisplay( p_vout ) )
251     {
252         intf_ErrMsg( "vout error: can't initialise DirectDraw" );
253         DirectXCloseDDraw( p_vout );
254
255         /* Kill DirectXEventThread */
256         p_vout->p_sys->b_event_thread_die = 1;
257         /* we need to be sure DirectXEventThread won't stay stuck in
258          * GetMessage, so we send a fake message */
259         PostMessage( p_vout->p_sys->hwnd, WM_CHAR, (WPARAM)'^', 0);
260         vlc_thread_join( p_vout->p_sys->event_thread_id );
261
262         return ( 1 );
263     }
264
265     return( 0 );
266 }
267
268 /*****************************************************************************
269  * vout_Init: initialize DirectX video thread output method
270  *****************************************************************************
271  *
272  *****************************************************************************/
273 static int vout_Init( vout_thread_t *p_vout )
274 {
275     return( 0 );
276 }
277
278 /*****************************************************************************
279  * vout_End: terminate Sys video thread output method
280  *****************************************************************************
281  * Terminate an output method created by vout_Create.
282  * It is called at the end of the thread.
283  *****************************************************************************/
284 static void vout_End( vout_thread_t *p_vout )
285 {
286     return;
287 }
288
289 /*****************************************************************************
290  * vout_Destroy: destroy Sys video thread output method
291  *****************************************************************************
292  * Terminate an output method created by vout_Create
293  *****************************************************************************/
294 static void vout_Destroy( vout_thread_t *p_vout )
295 {
296     intf_WarnMsg( 3, "vout: vout_Destroy" );
297     DirectXCloseDisplay( p_vout );
298     DirectXCloseDDraw( p_vout );
299
300     /* Kill DirectXEventThread */
301     p_vout->p_sys->b_event_thread_die = 1;
302     /* we need to be sure DirectXEventThread won't stay stuck in GetMessage,
303      * so we send a fake message */
304     if( p_vout->p_sys->i_event_thread_status == THREAD_READY )
305     {
306         PostMessage( p_vout->p_sys->hwnd, WM_CHAR, (WPARAM)'^', 0);
307         vlc_thread_join( p_vout->p_sys->event_thread_id );
308     }
309
310     if( p_vout->p_sys != NULL )
311     {
312         free( p_vout->p_sys );
313         p_vout->p_sys = NULL;
314     }
315 }
316
317 /*****************************************************************************
318  * vout_Manage: handle Sys events
319  *****************************************************************************
320  * This function should be called regularly by video output thread. It returns
321  * a non null value if an error occured.
322  *****************************************************************************/
323 static int vout_Manage( vout_thread_t *p_vout )
324 {
325     WINDOWPLACEMENT window_placement;
326     extern int b_directx_update_overlay;
327
328     /* We used to call the Win32 PeekMessage function here to read the window
329      * messages. But since window can stay blocked into this function for a
330      * long time (for example when you move your window on the screen), I
331      * decided to isolate PeekMessage in another thread. */
332
333     /*
334      * Scale Change 
335      */
336     if( p_vout->i_changes & VOUT_SCALE_CHANGE
337         || p_vout->p_sys->i_changes & VOUT_SCALE_CHANGE)
338     {
339         intf_WarnMsg( 3, "vout: vout_Manage Scale Change" );
340         if( p_vout->b_need_render )
341             InvalidateRect( p_vout->p_sys->hwnd, NULL, TRUE );
342         if( DirectXUpdateOverlay( p_vout ) )
343             /* failed so try again next time */
344             PostMessage( p_vout->p_sys->hwnd, WM_CHAR, (WPARAM)'S', 0);
345         p_vout->i_changes &= ~VOUT_SCALE_CHANGE;
346         p_vout->p_sys->i_changes &= ~VOUT_SCALE_CHANGE;
347     }
348
349     /*
350      * Size Change 
351      */
352     if( p_vout->i_changes & VOUT_SIZE_CHANGE
353         || p_vout->p_sys->i_changes & VOUT_SIZE_CHANGE
354         || b_directx_update_overlay )
355     {
356         intf_WarnMsg( 3, "vout: vout_Manage Size Change" );
357         if( DirectXUpdateOverlay( p_vout ) )
358             /* failed so try again next time */
359             PostMessage( p_vout->p_sys->hwnd, WM_APP, 0, 0);
360         p_vout->i_changes &= ~VOUT_SIZE_CHANGE;
361         p_vout->p_sys->i_changes &= ~VOUT_SIZE_CHANGE;
362         b_directx_update_overlay = 0;
363     }
364
365     /*
366      * YUV Change 
367      */
368     if( p_vout->i_changes & VOUT_YUV_CHANGE
369         || p_vout->p_sys->i_changes & VOUT_YUV_CHANGE )
370     {
371         p_vout->b_need_render = ! p_vout->b_need_render;
372         
373         /* Need to reopen display */
374         DirectXCloseSurface( p_vout );
375         if( DirectXCreateSurface( p_vout ) )
376         {
377           intf_ErrMsg( "error: can't reopen display after YUV change" );
378           return( 1 );
379         }
380
381         /* Repaint the window background (needed by the overlay surface) */
382         if( !p_vout->b_need_render )
383         {
384             InvalidateRect( p_vout->p_sys->hwnd, NULL, TRUE );
385             p_vout->p_sys->b_display_enabled = 1;
386             if( DirectXUpdateOverlay( p_vout ) )
387                 /* failed so try again next time */
388                 PostMessage( p_vout->p_sys->hwnd, WM_APP, 0, 0);
389         }
390         p_vout->i_changes &= ~VOUT_YUV_CHANGE;
391         p_vout->p_sys->i_changes &= ~VOUT_YUV_CHANGE;
392     }
393
394     /*
395      * Fullscreen change
396      */
397     if( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE
398         || p_vout->p_sys->i_changes & VOUT_FULLSCREEN_CHANGE )
399     {
400         p_vout->b_fullscreen = ! p_vout->b_fullscreen;
401
402         /* We need to switch between Maximized and Normal sized window */
403         window_placement.length = sizeof(WINDOWPLACEMENT);
404         GetWindowPlacement( p_vout->p_sys->hwnd, &window_placement );
405         if( p_vout->b_fullscreen )
406         {
407             /* Maximized window */
408             window_placement.showCmd = SW_SHOWMAXIMIZED;
409             /* Change window style, no borders and no title bar */
410             SetWindowLong( p_vout->p_sys->hwnd, GWL_STYLE, 0 );
411
412         }
413         else
414         {
415             /* Normal window */
416             window_placement.showCmd = SW_SHOWNORMAL;
417             /* Change window style, borders and title bar */
418             SetWindowLong( p_vout->p_sys->hwnd, GWL_STYLE,
419                            WS_OVERLAPPEDWINDOW | WS_SIZEBOX | WS_VISIBLE );
420         }
421
422         SetWindowPlacement( p_vout->p_sys->hwnd, &window_placement );
423
424         p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
425         p_vout->p_sys->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
426     }
427
428     /*
429      * Pointer change
430      */
431     if( ! p_vout->p_sys->b_cursor_autohidden &&
432         ( mdate() - p_vout->p_sys->i_lastmoved > 5000000 ) )
433     {
434         /* Hide the mouse automatically */
435         p_vout->p_sys->b_cursor_autohidden = 1;
436         ShowCursor( FALSE );
437     }
438
439     if( p_vout->i_changes & VOUT_CURSOR_CHANGE
440         || p_vout->p_sys->i_changes & VOUT_CURSOR_CHANGE )
441     {
442         p_vout->p_sys->b_cursor = ! p_vout->p_sys->b_cursor;
443
444         ShowCursor( p_vout->p_sys->b_cursor &&
445                      ! p_vout->p_sys->b_cursor_autohidden );
446
447         p_vout->i_changes &= ~VOUT_CURSOR_CHANGE;
448         p_vout->p_sys->i_changes &= ~VOUT_CURSOR_CHANGE;
449     }
450
451     return( 0 );
452 }
453
454 /*****************************************************************************
455  * vout_SetPalette: sets an 8 bpp palette
456  *****************************************************************************
457  * This function sets the palette given as an argument. It does not return
458  * anything, but could later send information on which colors it was unable
459  * to set.
460  *****************************************************************************/
461 static void vout_SetPalette( p_vout_thread_t p_vout, u16 *red, u16 *green,
462                          u16 *blue, u16 *transp)
463 {
464     /* Nothing yet */
465     return;
466 }
467
468 /*****************************************************************************
469  * vout_Display: displays previously rendered output
470  *****************************************************************************
471  * This function send the currently rendered image to the display, wait until
472  * it is displayed and switch the two rendering buffer, preparing next frame.
473  *****************************************************************************/
474 static void vout_Display( vout_thread_t *p_vout )
475 {
476     DDSURFACEDESC ddsd;
477     HRESULT       dxresult;
478
479     int           i;
480     int           i_image_width;
481     int           i_image_height;
482
483     if( (p_vout->p_sys->p_display == NULL) )
484     {
485         intf_WarnMsg( 3, "vout error: vout_Display no display!!" );
486         return;
487     }
488
489     /* if the size of the decoded pictures has changed then we close the
490      * video surface (which doesn't have the right size anymore). */
491     i_image_width = ( p_vout->p_rendered_pic ) ?
492       p_vout->p_rendered_pic->i_width : p_vout->p_sys->i_image_width;
493     i_image_height = ( p_vout->p_rendered_pic ) ?
494       p_vout->p_rendered_pic->i_height : p_vout->p_sys->i_image_height;
495
496     if( p_vout->p_sys->i_image_width != i_image_width
497         || p_vout->p_sys->i_image_height != i_image_height )
498     {
499         intf_WarnMsg( 3, "vout: video surface size changed" );
500         p_vout->p_sys->i_image_width = i_image_width;
501         p_vout->p_sys->i_image_height = i_image_height;
502         DirectXCloseSurface( p_vout );
503     }
504
505     if( p_vout->b_need_render )
506     {
507         RECT     rect_window;
508         POINT    point_window;
509         DDBLTFX  ddbltfx;
510   
511         /* Nothing yet */
512         if( p_vout->p_sys->p_surface == NULL )
513         {
514             intf_WarnMsg( 3, "vout: no video surface, open one..." );
515             if( DirectXCreateSurface( p_vout ) )
516             {
517                 intf_WarnMsg( 3, "vout: cannot open a new video surface !!" );
518                 return;
519             }
520             /* Display the surface */
521             p_vout->p_sys->b_display_enabled = 1;
522         }
523
524         /* Now get the coordinates of the window. We don't actually want the
525          * window coordinates but these of the usable surface inside the window
526          * By specification GetClientRect will always set rect_window.left and
527          * rect_window.top to 0 because the Client area is always relative to
528          * the container window */
529         GetClientRect(p_vout->p_sys->hwnd, &rect_window);
530         
531         point_window.x = 0;
532         point_window.y = 0;
533         ClientToScreen(p_vout->p_sys->hwnd, &point_window);
534         rect_window.left = point_window.x;
535         rect_window.top = point_window.y;
536         
537         point_window.x = rect_window.right;
538         point_window.y = rect_window.bottom;
539         ClientToScreen(p_vout->p_sys->hwnd, &point_window);
540         rect_window.right = point_window.x;
541         rect_window.bottom = point_window.y;
542
543         /* We want to keep the aspect ratio of the video */
544 #if 0
545         if( p_vout->b_scale )
546         {
547             DirectXKeepAspectRatio( p_vout, &rect_window );
548         }
549 #endif
550
551         /* We ask for the "NOTEARING" option */
552         memset( &ddbltfx, 0, sizeof(DDBLTFX) );
553         ddbltfx.dwSize = sizeof(DDBLTFX);
554         ddbltfx.dwDDFX = DDBLTFX_NOTEARING;
555
556         /* Blit video surface to display */
557         dxresult = IDirectDrawSurface3_Blt(p_vout->p_sys->p_display,
558                                            &rect_window,
559                                            p_vout->p_sys->p_surface,
560                                            NULL,
561                                            0, &ddbltfx );
562         if( dxresult != DD_OK )
563         {
564             intf_WarnMsg( 3, "vout: could not Blit the surface" );
565             return;
566         }
567
568     }
569     else
570     {
571         /*
572          * p_vout->p_rendered_pic->p_y/u/v contains the YUV buffers to
573          * render
574          */
575         /* TODO: support for streams other than 4:2:0 */
576
577         if( p_vout->p_sys->p_surface == NULL )
578         {
579             intf_WarnMsg( 3, "vout: no video surface, open one..." );
580             if( DirectXCreateSurface( p_vout ) )
581             {
582                 intf_WarnMsg( 3, "vout: cannot open a new video surface !!" );
583                 return;
584             }
585         }
586
587         /* Lock the overlay surface */
588         memset( &ddsd, 0, sizeof( DDSURFACEDESC ));
589         ddsd.dwSize = sizeof(DDSURFACEDESC);
590         dxresult = IDirectDrawSurface3_Lock(p_vout->p_sys->p_surface, NULL,
591                                             &ddsd, DDLOCK_NOSYSLOCK, NULL);
592         if ( dxresult == DDERR_SURFACELOST )
593         {
594             /* Your surface can be lost (thanks to windows) so be sure
595              * to check this and restore it if needed */
596             dxresult = IDirectDrawSurface3_Restore( p_vout->p_sys->p_surface );
597             dxresult = IDirectDrawSurface3_Lock( p_vout->p_sys->p_surface,
598                                                  NULL, &ddsd, DDLOCK_NOSYSLOCK
599                                                  | DDLOCK_WAIT, NULL);
600         }
601         if( dxresult != DD_OK )
602         {
603             intf_WarnMsg( 3, "vout: could not lock the surface" );
604             return;
605         }
606
607         /* Now we can do the actual image copy.
608          * The copy has to be done line by line because of the special case
609          * when the Pitch does not equal the width of the picture */
610         for( i=0; i < ddsd.dwHeight/2; i++)
611         {
612 #ifdef NONAMELESSUNION
613             /* copy Y, we copy two lines at once */
614             memcpy(ddsd.lpSurface + i*2*ddsd.u1.lPitch,
615                    p_vout->p_rendered_pic->p_y + i*2*i_image_width,
616                    i_image_width);
617             memcpy(ddsd.lpSurface + (i*2+1)*ddsd.u1.lPitch,
618                    p_vout->p_rendered_pic->p_y + (i*2+1)*i_image_width,
619                    i_image_width);
620             /* then V */
621             memcpy((ddsd.lpSurface + ddsd.dwHeight * ddsd.u1.lPitch)
622                       + i * ddsd.u1.lPitch/2,
623                    p_vout->p_rendered_pic->p_v + i*i_image_width/2,
624                    i_image_width/2);
625             /* and U */
626             memcpy((ddsd.lpSurface + ddsd.dwHeight * ddsd.u1.lPitch)
627                       + (ddsd.dwHeight * ddsd.u1.lPitch/4)
628                       + i * ddsd.u1.lPitch/2,
629                    p_vout->p_rendered_pic->p_u + i*i_image_width/2,
630                    i_image_width/2);
631 #else
632             /* copy Y, we copy two lines at once */
633             memcpy((u8*)ddsd.lpSurface + i*2*ddsd.lPitch,
634                    p_vout->p_rendered_pic->p_y + i*2*i_image_width,
635                    i_image_width);
636             memcpy((u8*)ddsd.lpSurface + (i*2+1)*ddsd.lPitch,
637                    p_vout->p_rendered_pic->p_y + (i*2+1)*i_image_width,
638                    i_image_width);
639             /* then V */
640             memcpy(((u8*)ddsd.lpSurface + ddsd.dwHeight * ddsd.lPitch)
641                       + i * ddsd.lPitch/2,
642                    p_vout->p_rendered_pic->p_v + i*i_image_width/2,
643                    i_image_width/2);
644             /* and U */
645             memcpy(((u8*)ddsd.lpSurface + ddsd.dwHeight * ddsd.lPitch)
646                       + (ddsd.dwHeight * ddsd.lPitch/4)
647                       + i * ddsd.lPitch/2,
648                    p_vout->p_rendered_pic->p_u + i*i_image_width/2,
649                    i_image_width/2);
650 #endif /* NONAMELESSUNION */
651
652         }
653
654         /* Unlock the Surface */
655         dxresult = IDirectDrawSurface3_Unlock(p_vout->p_sys->p_surface,
656                                               ddsd.lpSurface );
657
658         /* If display not enabled yet then enable */
659         if( !p_vout->p_sys->b_display_enabled )
660         {
661             p_vout->p_sys->b_display_enabled = 1;
662             DirectXUpdateOverlay( p_vout );
663         }
664
665     }
666
667     /* The first time this function is called it enables the display */
668     p_vout->p_sys->b_display_enabled = 1;
669
670 }
671
672
673 /* following functions are local */
674
675 /*****************************************************************************
676  * DirectXInitDDraw: Takes care of all the DirectDraw initialisations
677  *****************************************************************************
678  * This function initialise and allocate resources for DirectDraw.
679  *****************************************************************************/
680 static int DirectXInitDDraw( vout_thread_t *p_vout )
681 {
682     HRESULT    dxresult;
683     HRESULT    (WINAPI *OurDirectDrawCreate)(GUID *,LPDIRECTDRAW *,IUnknown *);
684     LPDIRECTDRAW  p_ddobject;
685
686     intf_WarnMsg( 3, "vout: DirectXInitDDraw" );
687
688     /* load direct draw DLL */
689     p_vout->p_sys->hddraw_dll = LoadLibrary("DDRAW.DLL");
690     if( p_vout->p_sys->hddraw_dll == NULL )
691     {
692         intf_WarnMsg( 3, "vout: DirectXInitDDraw failed loading ddraw.dll" );
693         return( 1 );
694     }
695       
696     OurDirectDrawCreate = 
697       (void *)GetProcAddress(p_vout->p_sys->hddraw_dll, "DirectDrawCreate");
698     if ( OurDirectDrawCreate == NULL )
699     {
700         intf_ErrMsg( "vout error: DirectXInitDDraw failed GetProcAddress" );
701         FreeLibrary( p_vout->p_sys->hddraw_dll );
702         p_vout->p_sys->hddraw_dll = NULL;
703         return( 1 );    
704     }
705
706     /* Initialize DirectDraw now */
707     dxresult = OurDirectDrawCreate( NULL, &p_ddobject, NULL );
708     if( dxresult != DD_OK )
709     {
710         intf_ErrMsg( "vout error: DirectXInitDDraw can't initialize DDraw" );
711         p_vout->p_sys->p_ddobject = NULL;
712         FreeLibrary( p_vout->p_sys->hddraw_dll );
713         p_vout->p_sys->hddraw_dll = NULL;
714         return( 1 );
715     }
716
717     /* Set DirectDraw Cooperative level, ie what control we want over Windows
718      * display */
719     dxresult = IDirectDraw_SetCooperativeLevel( p_ddobject,
720                                            p_vout->p_sys->hwnd, DDSCL_NORMAL );
721     if( dxresult != DD_OK )
722     {
723         intf_ErrMsg( "vout error: can't set direct draw cooperative level." );
724         IDirectDraw_Release( p_ddobject );
725         p_vout->p_sys->p_ddobject = NULL;
726         FreeLibrary( p_vout->p_sys->hddraw_dll );
727         p_vout->p_sys->hddraw_dll = NULL;
728         return( 1 );
729     }
730
731     /* Get the IDirectDraw2 interface */
732     dxresult = IDirectDraw_QueryInterface( p_ddobject, &IID_IDirectDraw2,
733                                         (LPVOID *)&p_vout->p_sys->p_ddobject );
734     if( dxresult != DD_OK )
735     {
736         intf_ErrMsg( "vout error: can't get IDirectDraw2 interface." );
737         IDirectDraw_Release( p_ddobject );
738         p_vout->p_sys->p_ddobject = NULL;
739         FreeLibrary( p_vout->p_sys->hddraw_dll );
740         p_vout->p_sys->hddraw_dll = NULL;
741         return( 1 );
742     }
743     else
744     {
745         /* Release the unused interface */
746         IDirectDraw_Release( p_ddobject );
747     }
748
749     intf_WarnMsg( 3, "vout: End DirectXInitDDraw" );
750     return( 0 );
751 }
752
753 /*****************************************************************************
754  * DirectXCreateDisplay: create the DirectDraw display.
755  *****************************************************************************
756  * Create and initialize display according to preferences specified in the vout
757  * thread fields.
758  *****************************************************************************/
759 static int DirectXCreateDisplay( vout_thread_t *p_vout )
760 {
761     HRESULT              dxresult;
762     DDSURFACEDESC        ddsd;
763     LPDIRECTDRAWSURFACE  p_display;
764     DDPIXELFORMAT        ddpfPixelFormat;
765
766     intf_WarnMsg( 3, "vout: DirectXCreateDisplay" );
767
768     /* Now create the primary surface. This surface is what you actually see
769      * on your screen */
770     memset( &ddsd, 0, sizeof( DDSURFACEDESC ));
771     ddsd.dwSize = sizeof(DDSURFACEDESC);
772     ddsd.dwFlags = DDSD_CAPS;
773     ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
774
775     dxresult = IDirectDraw2_CreateSurface( p_vout->p_sys->p_ddobject,
776                                            &ddsd,
777                                            &p_display, NULL );
778     if( dxresult != DD_OK )
779     {
780         intf_ErrMsg( "vout error: can't create direct draw primary surface." );
781         p_vout->p_sys->p_display = NULL;
782         return( 1 );
783     }
784
785     dxresult = IDirectDrawSurface_QueryInterface( p_display,
786                                          &IID_IDirectDrawSurface3,
787                                          (LPVOID *)&p_vout->p_sys->p_display );
788     if ( dxresult != DD_OK )
789     {
790         intf_ErrMsg( "vout error: can't get IDirectDrawSurface3 interface." );
791         IDirectDrawSurface_Release( p_display );
792         p_vout->p_sys->p_display = NULL;
793         return( 1 );
794     }
795     else
796     {
797         /* Release the old interface */
798         IDirectDrawSurface_Release( p_display );
799     }
800
801
802     /* We need to fill in some information for the video output thread.
803      * We do this here because it must be done before the video_output
804      * thread enters its main loop - and DirectXCreateSurface can be called
805      * after that ! */
806     ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT);
807     IDirectDrawSurface3_GetPixelFormat( p_vout->p_sys->p_display,
808                                         &ddpfPixelFormat );
809 #ifdef NONAMELESSUNION
810     p_vout->i_screen_depth =    ddpfPixelFormat.u1.dwRGBBitCount;
811     p_vout->i_bytes_per_pixel = ddpfPixelFormat.u1.dwRGBBitCount/8;
812     
813     p_vout->i_red_mask =        ddpfPixelFormat.u2.dwRBitMask;
814     p_vout->i_green_mask =      ddpfPixelFormat.u3.dwGBitMask;
815     p_vout->i_blue_mask =       ddpfPixelFormat.u4.dwBBitMask;
816 #else
817     p_vout->i_screen_depth =    ddpfPixelFormat.dwRGBBitCount;
818     p_vout->i_bytes_per_pixel = ddpfPixelFormat.dwRGBBitCount/8;
819
820     p_vout->i_red_mask =        ddpfPixelFormat.dwRBitMask;
821     p_vout->i_green_mask =      ddpfPixelFormat.dwGBitMask;
822     p_vout->i_blue_mask =       ddpfPixelFormat.dwBBitMask;
823 #endif /* NONAMELESSUNION */
824
825     /* Create a video surface. This function will try to create an
826      * YUV overlay first and if it can't it will create a simple RGB surface */
827     if( DirectXCreateSurface( p_vout ) )
828     {
829         intf_ErrMsg( "vout error: can't create a video surface." );
830         IDirectDrawSurface3_Release( p_vout->p_sys->p_display );
831         p_vout->p_sys->p_display = NULL;
832         return( 1 );
833     }
834       
835     return( 0 );
836 }
837
838 /*****************************************************************************
839  * DirectXCreateSurface: create an YUV overlay or RGB surface for the video.
840  *****************************************************************************
841  * The best method of display is with an YUV overlay because the YUV->RGB
842  * conversion is done in hardware, so we'll try to create this surface first.
843  * If we fail, we'll try to create a plain RGB surface.
844  * ( Maybe we could also try an RGB overlay surface, which could have hardware
845  * scaling and which would also be faster in window mode because you don't
846  * need to do any blitting to the main display...)
847  *****************************************************************************/
848 static int DirectXCreateSurface( vout_thread_t *p_vout )
849 {
850     HRESULT dxresult;
851     DDSURFACEDESC ddsd;
852     LPDIRECTDRAWSURFACE p_surface;
853     DDCAPS ddcaps;
854
855     intf_WarnMsg( 3, "vout: DirectXCreateSurface" );
856
857     /* Disable display */
858     p_vout->p_sys->b_display_enabled = 0;
859
860 #if 1
861     /* Probe the capabilities of the hardware */
862     /* This is just an indication of whether or not we'll support overlay,
863      * but with this test we don't know if we support YUV overlay */
864     memset( &ddcaps, 0, sizeof( DDCAPS ));
865     ddcaps.dwSize = sizeof(DDCAPS);
866     dxresult = IDirectDraw2_GetCaps( p_vout->p_sys->p_ddobject,
867                                      &ddcaps, NULL );
868     if(dxresult != DD_OK )
869     {
870         intf_WarnMsg( 3,"vout error: can't get caps." );
871     }
872     else
873     {
874         BOOL bHasOverlay, bHasColorKey, bCanStretch;
875
876         /* Determine if the hardware supports overlay surfaces */
877         bHasOverlay = ((ddcaps.dwCaps & DDCAPS_OVERLAY) ==
878                        DDCAPS_OVERLAY) ? TRUE : FALSE;
879         /* Determine if the hardware supports colorkeying */
880         bHasColorKey = ((ddcaps.dwCaps & DDCAPS_COLORKEY) ==
881                         DDCAPS_COLORKEY) ? TRUE : FALSE;
882         /* Determine if the hardware supports scaling of the overlay surface */
883         bCanStretch = ((ddcaps.dwCaps & DDCAPS_OVERLAYSTRETCH) ==
884                        DDCAPS_OVERLAYSTRETCH) ? TRUE : FALSE;
885         intf_WarnMsg( 3, "vout: Dx Caps: overlay=%i colorkey=%i stretch=%i",
886                          bHasOverlay, bHasColorKey, bCanStretch );
887
888 #if 0
889         if( !bHasOverlay ) p_vout->b_need_render = 1;
890 #endif
891     }
892 #endif
893
894
895     /* Create the video surface */
896     if( !p_vout->b_need_render )
897     {
898         /* Now try to create the YUV overlay surface.
899          * This overlay will be displayed on top of the primary surface.
900          * A color key is used to determine whether or not the overlay will be
901          * displayed, ie the overlay will be displayed in place of the primary
902          * surface wherever the primary surface will have this color.
903          * The video window has been created with a background of this color so
904          * the overlay will be only displayed on top of this window */
905
906         memset( &ddsd, 0, sizeof( DDSURFACEDESC ));
907         ddsd.dwSize = sizeof(DDSURFACEDESC);
908         ddsd.ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT);
909         ddsd.ddpfPixelFormat.dwFlags = DDPF_FOURCC;
910         ddsd.ddpfPixelFormat.dwFourCC = mmioFOURCC('Y','V','1','2');
911 #ifdef NONAMELESSUNION
912         ddsd.ddpfPixelFormat.u1.dwYUVBitCount = 16;
913 #else
914         ddsd.ddpfPixelFormat.dwYUVBitCount = 16;
915 #endif
916         ddsd.dwFlags = DDSD_CAPS |
917                        DDSD_HEIGHT |
918                        DDSD_WIDTH |
919                        DDSD_PIXELFORMAT;
920         ddsd.ddsCaps.dwCaps = DDSCAPS_OVERLAY | DDSCAPS_VIDEOMEMORY;
921         ddsd.dwHeight =  p_vout->p_sys->i_image_height;
922         ddsd.dwWidth =  p_vout->p_sys->i_image_width;
923         ddsd.dwBackBufferCount = 1;                       /* One back buffer */
924
925         dxresult = IDirectDraw2_CreateSurface( p_vout->p_sys->p_ddobject,
926                                                &ddsd, &p_surface, NULL );
927         if( dxresult == DD_OK )
928         {
929             intf_WarnMsg( 3,"vout: DirectX YUV overlay created successfully" );
930         }
931         else
932         {
933             intf_ErrMsg( "vout error: can't create YUV overlay surface." );
934             p_vout->b_need_render = 1;
935         }
936     }
937
938     if( p_vout->b_need_render )
939     {
940         /* Now try to create a plain RGB surface. */
941         memset( &ddsd, 0, sizeof( DDSURFACEDESC ));
942         ddsd.dwSize = sizeof(DDSURFACEDESC);
943         ddsd.dwFlags = DDSD_HEIGHT |
944                        DDSD_WIDTH |
945                        DDSD_CAPS;
946         ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
947         ddsd.dwHeight =  p_vout->p_sys->i_image_height;
948         ddsd.dwWidth =  p_vout->p_sys->i_image_width;
949
950         dxresult = IDirectDraw2_CreateSurface( p_vout->p_sys->p_ddobject,
951                                                &ddsd, &p_surface, NULL );
952         if( dxresult == DD_OK )
953         {
954             intf_WarnMsg( 3,"vout: DirectX RGB surface created successfully" );
955         }
956         else
957         {
958             intf_ErrMsg( "vout error: can't create RGB surface." );
959             p_vout->p_sys->p_surface = NULL;
960             return( 1 );
961         }
962     }
963       
964     /* Now that the surface is created, try to get a newer DirectX interface */
965     dxresult = IDirectDrawSurface_QueryInterface( p_surface,
966                                          &IID_IDirectDrawSurface3,
967                                          (LPVOID *)&p_vout->p_sys->p_surface );
968     if ( dxresult != DD_OK )
969     {
970         intf_ErrMsg( "vout error: can't get IDirectDrawSurface3 interface." );
971         IDirectDrawSurface_Release( p_surface );
972         p_vout->p_sys->p_surface = NULL;
973         return( 1 );
974     }
975     else
976     {
977         /* Release the old interface */
978         IDirectDrawSurface_Release( p_surface );
979     }
980
981     if( !p_vout->b_need_render )
982     {
983         /* Hide the overlay for now */
984         IDirectDrawSurface3_UpdateOverlay(p_vout->p_sys->p_surface,
985                                           NULL,
986                                           p_vout->p_sys->p_display,
987                                           NULL,
988                                           DDOVER_HIDE,
989                                           NULL);
990     }
991     else
992     {
993          DirectXCreateClipper( p_vout );
994     }
995
996
997     /* From now on, do some initialisation for video_output */
998
999     /* if we want a valid pointer to the surface memory, we must lock
1000      * the surface */
1001
1002     memset( &ddsd, 0, sizeof( DDSURFACEDESC ));
1003     ddsd.dwSize = sizeof(DDSURFACEDESC);
1004     dxresult = IDirectDrawSurface3_Lock( p_vout->p_sys->p_surface, NULL, &ddsd,
1005                                          DDLOCK_NOSYSLOCK | DDLOCK_WAIT, NULL);
1006     if ( dxresult == DDERR_SURFACELOST )
1007     {
1008         /* Your surface can be lost so be sure
1009          * to check this and restore it if needed */
1010         dxresult = IDirectDrawSurface3_Restore( p_vout->p_sys->p_surface );
1011         dxresult = IDirectDrawSurface3_Lock( p_vout->p_sys->p_surface,
1012                                              NULL, &ddsd, DDLOCK_NOSYSLOCK
1013                                              | DDLOCK_WAIT, NULL);
1014     }
1015     if( dxresult != DD_OK )
1016     {
1017         intf_ErrMsg( "vout: DirectXCreateDisplay could not lock the surface" );
1018         return( 1 );
1019     }
1020
1021     /* Set the pointer to the surface memory */
1022     p_vout->p_sys->p_directx_buf[ 0 ] = ddsd.lpSurface;
1023     /* back buffer, none for now */
1024     p_vout->p_sys->p_directx_buf[ 1 ] = ddsd.lpSurface;
1025
1026     /* Set thread information */
1027     p_vout->i_width =  ddsd.dwWidth;
1028     p_vout->i_height = ddsd.dwHeight;
1029 #ifdef NONAMELESSUNION
1030     p_vout->i_bytes_per_line =  ddsd.u1.lPitch;
1031 #else
1032     p_vout->i_bytes_per_line =  ddsd.lPitch;
1033 #endif /* NONAMELESSUNION */
1034
1035
1036     if( p_vout->b_need_render )
1037     {
1038         /* For an RGB surface we need to fill in some more info */
1039 #ifdef NONAMELESSUNION
1040         p_vout->i_screen_depth =    ddsd.ddpfPixelFormat.u1.dwRGBBitCount;
1041         p_vout->i_bytes_per_pixel = ddsd.ddpfPixelFormat.u1.dwRGBBitCount/8;
1042
1043         p_vout->i_red_mask =        ddsd.ddpfPixelFormat.u2.dwRBitMask;
1044         p_vout->i_green_mask =      ddsd.ddpfPixelFormat.u3.dwGBitMask;
1045         p_vout->i_blue_mask =       ddsd.ddpfPixelFormat.u4.dwBBitMask;
1046 #else
1047         p_vout->i_screen_depth =    ddsd.ddpfPixelFormat.dwRGBBitCount;
1048         p_vout->i_bytes_per_pixel = ddsd.ddpfPixelFormat.dwRGBBitCount/8;
1049
1050         p_vout->i_red_mask =        ddsd.ddpfPixelFormat.dwRBitMask;
1051         p_vout->i_green_mask =      ddsd.ddpfPixelFormat.dwGBitMask;
1052         p_vout->i_blue_mask =       ddsd.ddpfPixelFormat.dwBBitMask;
1053
1054 #endif /* NONAMELESSUNION */
1055     }
1056
1057     /* Unlock the Surface */
1058     dxresult = IDirectDrawSurface3_Unlock(p_vout->p_sys->p_surface,
1059                                           ddsd.lpSurface );
1060
1061     /* Set and initialize buffers */
1062     p_vout->pf_setbuffers( p_vout, p_vout->p_sys->p_directx_buf[ 0 ],
1063                            p_vout->p_sys->p_directx_buf[ 1 ] );
1064
1065
1066     return ( 0 );
1067 }
1068
1069
1070 /*****************************************************************************
1071  * DirectXCreateClipper: Create a clipper that will be used when blitting the
1072  *                       RGB surface to the main display.
1073  *****************************************************************************
1074  * This clipper prevents us to modify by mistake anything on the screen
1075  * which doesn't belong to our window. For example when a part of our video
1076  * window is hidden by another window.
1077  *****************************************************************************/
1078 static int DirectXCreateClipper( vout_thread_t *p_vout )
1079 {
1080     HRESULT dxresult;
1081
1082     intf_WarnMsg( 3, "vout: DirectXCreateClipper" );
1083
1084     /* Create the clipper */
1085     dxresult = IDirectDraw2_CreateClipper( p_vout->p_sys->p_ddobject, 0,
1086                                            &p_vout->p_sys->p_clipper, NULL );
1087     if( dxresult != DD_OK )
1088     {
1089         intf_WarnMsg( 3, "vout: DirectXCreateClipper can't create clipper." );
1090         IDirectDrawSurface_Release( p_vout->p_sys->p_clipper );
1091         p_vout->p_sys->p_clipper = NULL;
1092         return( 1 );
1093     }
1094     
1095     /* associate the clipper to the window */
1096     dxresult = IDirectDrawClipper_SetHWnd(p_vout->p_sys->p_clipper, 0,
1097                                           p_vout->p_sys->hwnd);
1098     if( dxresult != DD_OK )
1099     {
1100         intf_WarnMsg( 3,
1101             "vout: DirectXCreateClipper can't attach clipper to window." );
1102         IDirectDrawSurface_Release( p_vout->p_sys->p_clipper );
1103         p_vout->p_sys->p_clipper = NULL;
1104         return( 1 );
1105     }
1106     
1107     /* associate the clipper with the surface */
1108     dxresult = IDirectDrawSurface_SetClipper(p_vout->p_sys->p_display,
1109                                              p_vout->p_sys->p_clipper);
1110     if( dxresult != DD_OK )
1111     {
1112         intf_WarnMsg( 3,
1113             "vout: DirectXCreateClipper can't attach clipper to surface." );
1114         IDirectDrawSurface_Release( p_vout->p_sys->p_clipper );
1115         p_vout->p_sys->p_clipper = NULL;
1116         return( 1 );
1117     }    
1118      
1119     return( 0 );
1120 }
1121
1122
1123 /*****************************************************************************
1124  * DirectXUpdateOverlay: Move or resize overlay surface on video display.
1125  *****************************************************************************
1126  * This function is used to move or resize an overlay surface on the screen.
1127  * Ususally the overlay is moved by the user and thus, by a move or resize
1128  * event (in vout_Manage).
1129  *****************************************************************************/
1130 static int DirectXUpdateOverlay( vout_thread_t *p_vout )
1131 {
1132     DDOVERLAYFX     ddofx;
1133     RECT            rect_window, rect_window_backup, rect_image;
1134     POINT           point_window;
1135     DWORD           dwFlags;
1136     HRESULT         dxresult;
1137     DWORD           dw_colorkey;
1138     DDPIXELFORMAT   pixel_format;
1139     DDSURFACEDESC   ddsd;
1140
1141     if( p_vout->p_sys->p_surface == NULL || p_vout->b_need_render )
1142     {
1143         intf_WarnMsg( 3, "vout: DirectXUpdateOverlay no overlay !!" );
1144         return( 0 );
1145     }
1146
1147     if( !p_vout->p_rendered_pic )
1148     {
1149         intf_WarnMsg( 3, "vout: DirectXUpdateOverlay p_rendered_pic=NULL !" );
1150         return( 1 );
1151     }
1152
1153     if( !p_vout->p_sys->b_display_enabled )
1154     {
1155         return( 0 );
1156     }
1157
1158     /* Now get the coordinates of the window. We don't actually want the
1159      * window coordinates but these of the usable surface inside the window.
1160      * By specification GetClientRect will always set rect_window.left and
1161      * rect_window.top to 0 because the Client area is always relative to the
1162      * container window */
1163     GetClientRect(p_vout->p_sys->hwnd, &rect_window);
1164
1165     point_window.x = 0;
1166     point_window.y = 0;
1167     ClientToScreen(p_vout->p_sys->hwnd, &point_window);
1168     rect_window.left = point_window.x;
1169     rect_window.top = point_window.y;
1170
1171     point_window.x = rect_window.right;
1172     point_window.y = rect_window.bottom;
1173     ClientToScreen(p_vout->p_sys->hwnd, &point_window);
1174     rect_window.right = point_window.x;
1175     rect_window.bottom = point_window.y;
1176
1177
1178     /* We want to keep the aspect ratio of the video */
1179     if( p_vout->b_scale )
1180     {
1181         DirectXKeepAspectRatio( p_vout, &rect_window );
1182     }
1183
1184     /* It seems we can't feed the UpdateOverlay directdraw function with
1185      * negative values so we have to clip the computed rectangles */
1186     memset( &ddsd, 0, sizeof( DDSURFACEDESC ));
1187     ddsd.dwSize = sizeof(DDSURFACEDESC);
1188     ddsd.dwFlags = DDSD_HEIGHT | DDSD_WIDTH;
1189     IDirectDraw2_GetDisplayMode( p_vout->p_sys->p_ddobject, &ddsd );
1190
1191     rect_window_backup = rect_window;
1192
1193     /* Clip the destination window */
1194     rect_window.left = (rect_window.left < 0) ? 0 : rect_window.left;
1195     rect_window.right = (rect_window.right < 0) ? 0 : rect_window.right;
1196     rect_window.top = (rect_window.top < 0) ? 0 : rect_window.top;
1197     rect_window.bottom = (rect_window.bottom < 0) ? 0 : rect_window.bottom;
1198
1199     rect_window.left = (rect_window.left > ddsd.dwWidth) ? ddsd.dwWidth
1200       : rect_window.left;
1201     rect_window.right = (rect_window.right > ddsd.dwWidth) ? ddsd.dwWidth
1202       : rect_window.right;
1203     rect_window.top = (rect_window.top > ddsd.dwHeight) ? ddsd.dwHeight
1204       : rect_window.top;
1205     rect_window.bottom = (rect_window.bottom > ddsd.dwHeight) ? ddsd.dwHeight
1206       : rect_window.bottom;
1207
1208     intf_WarnMsg( 3, "vout: DirectXUpdateOverlay window coords: %i,%i,%i,%i",
1209                   rect_window.left, rect_window.top,
1210                   rect_window.right, rect_window.bottom);
1211
1212     /* the 2 following lines are to fix a bug when click on Windows desktop */
1213     if( (rect_window.right-rect_window.left)==0 ||
1214         (rect_window.bottom-rect_window.top)==0 ) return 0;
1215
1216     /* Clip the source image */
1217     rect_image.left = ( rect_window.left == rect_window_backup.left ) ? 0
1218       : labs(rect_window_backup.left - rect_window.left) *
1219       p_vout->p_rendered_pic->i_width /
1220       (rect_window_backup.right - rect_window_backup.left);
1221     rect_image.right = ( rect_window.right == rect_window_backup.right ) ?
1222       p_vout->p_rendered_pic->i_width
1223       : p_vout->p_rendered_pic->i_width -
1224       labs(rect_window_backup.right - rect_window.right) *
1225       p_vout->p_rendered_pic->i_width /
1226       (rect_window_backup.right - rect_window_backup.left);
1227     rect_image.top = ( rect_window.top == rect_window_backup.top ) ? 0
1228       : labs(rect_window_backup.top - rect_window.top) *
1229       p_vout->p_rendered_pic->i_height /
1230       (rect_window_backup.bottom - rect_window_backup.top);
1231     rect_image.bottom = ( rect_window.bottom == rect_window_backup.bottom ) ?
1232       p_vout->p_rendered_pic->i_height
1233       : p_vout->p_rendered_pic->i_height -
1234       labs(rect_window_backup.bottom - rect_window.bottom) *
1235       p_vout->p_rendered_pic->i_height /
1236       (rect_window_backup.bottom - rect_window_backup.top);
1237
1238     intf_WarnMsg( 3, "vout: DirectXUpdateOverlay image coords: %i,%i,%i,%i",
1239                   rect_image.left, rect_image.top,
1240                   rect_image.right, rect_image.bottom);
1241
1242     /* compute the colorkey pixel value from the RGB value we've got */
1243     memset( &pixel_format, 0, sizeof( DDPIXELFORMAT ));
1244     pixel_format.dwSize = sizeof( DDPIXELFORMAT );
1245     dxresult = IDirectDrawSurface3_GetPixelFormat( p_vout->p_sys->p_display,
1246                                                    &pixel_format );
1247     if( dxresult != DD_OK )
1248         intf_WarnMsg( 3, "vout: DirectXUpdateOverlay GetPixelFormat failed" );
1249     dw_colorkey = (DWORD)p_vout->p_sys->i_colorkey;
1250 #ifdef NONAMELESSUNION
1251     dw_colorkey = (DWORD)((( dw_colorkey * pixel_format.u2.dwRBitMask) / 255)
1252                           & pixel_format.u2.dwRBitMask);
1253 #else
1254     dw_colorkey = (DWORD)((( dw_colorkey * pixel_format.dwRBitMask) / 255)
1255                           & pixel_format.dwRBitMask);
1256 #endif
1257
1258     /* Position and show the overlay */
1259     memset(&ddofx, 0, sizeof(DDOVERLAYFX));
1260     ddofx.dwSize = sizeof(DDOVERLAYFX);
1261     ddofx.dckDestColorkey.dwColorSpaceLowValue = dw_colorkey;
1262     ddofx.dckDestColorkey.dwColorSpaceHighValue = dw_colorkey;
1263
1264     dwFlags = DDOVER_KEYDESTOVERRIDE | DDOVER_SHOW;
1265
1266     dxresult = IDirectDrawSurface3_UpdateOverlay(p_vout->p_sys->p_surface,
1267                                                  &rect_image,
1268                                                  p_vout->p_sys->p_display,
1269                                                  &rect_window,
1270                                                  dwFlags,
1271                                                  &ddofx);
1272     if(dxresult != DD_OK)
1273     {
1274         intf_WarnMsg( 3,
1275           "vout: DirectXUpdateOverlay can't move or resize overlay" );
1276     }
1277
1278     return ( 0 );
1279 }
1280
1281 /*****************************************************************************
1282  * DirectXCloseDDraw: Release the DDraw object allocated by DirectXInitDDraw
1283  *****************************************************************************
1284  * This function returns all resources allocated by DirectXInitDDraw.
1285  *****************************************************************************/
1286 static void DirectXCloseDDraw( vout_thread_t *p_vout )
1287 {
1288     intf_WarnMsg(3, "vout: DirectXCloseDDraw" );
1289     if( p_vout->p_sys->p_ddobject != NULL )
1290     {
1291         IDirectDraw2_Release(p_vout->p_sys->p_ddobject);
1292         p_vout->p_sys->p_ddobject = NULL;
1293     }
1294
1295     if( p_vout->p_sys->hddraw_dll != NULL )
1296     {
1297         FreeLibrary( p_vout->p_sys->hddraw_dll );
1298         p_vout->p_sys->hddraw_dll = NULL;
1299     }
1300 }
1301
1302 /*****************************************************************************
1303  * DirectXCloseDisplay: close and reset the DirectX display device
1304  *****************************************************************************
1305  * This function returns all resources allocated by DirectXCreateDisplay.
1306  *****************************************************************************/
1307 static void DirectXCloseDisplay( vout_thread_t *p_vout )
1308 {
1309     intf_WarnMsg( 3, "vout: DirectXCloseDisplay" );
1310     if( p_vout->p_sys->p_display != NULL )
1311     {
1312         DirectXCloseSurface( p_vout );
1313
1314         intf_WarnMsg( 3, "vout: DirectXCloseDisplay display" );
1315         IDirectDraw2_Release( p_vout->p_sys->p_display );
1316         p_vout->p_sys->p_display = NULL;
1317     }
1318 }
1319
1320 /*****************************************************************************
1321  * DirectXCloseSurface: close the YUV overlay or RGB surface.
1322  *****************************************************************************
1323  * This function returns all resources allocated by the surface.
1324  * We also call this function when the decoded picture change its dimensions
1325  * (in that case we close the overlay surface and reopen another with the
1326  * right dimensions).
1327  *****************************************************************************/
1328 static void DirectXCloseSurface( vout_thread_t *p_vout )
1329 {
1330     intf_WarnMsg( 3, "vout: DirectXCloseSurface" );
1331     if( p_vout->p_sys->p_surface != NULL )
1332     {
1333         intf_WarnMsg( 3, "vout: DirectXCloseSurface surface" );
1334         IDirectDraw2_Release( p_vout->p_sys->p_surface );
1335         p_vout->p_sys->p_surface = NULL;
1336     }
1337
1338     if( p_vout->p_sys->p_clipper != NULL )
1339     {
1340         intf_WarnMsg( 3, "vout: DirectXCloseSurface clipper" );
1341         IDirectDraw2_Release( p_vout->p_sys->p_clipper );
1342         p_vout->p_sys->p_clipper = NULL;
1343     }
1344
1345     /* Disable any display */
1346     p_vout->p_sys->b_display_enabled = 0;
1347 }
1348
1349 /*****************************************************************************
1350  * DirectXKeepAspectRatio: 
1351  *****************************************************************************
1352  * This function adjusts the coordinates of the video rectangle to keep the
1353  * aspect/ratio of the video.
1354  *****************************************************************************/
1355 static void DirectXKeepAspectRatio( vout_thread_t *p_vout, RECT *rect_window )
1356 {
1357
1358   if( !p_vout->p_rendered_pic ) return;
1359
1360   switch( p_vout->p_rendered_pic->i_aspect_ratio )
1361   {
1362       case AR_16_9_PICTURE:
1363       if( ((rect_window->right-rect_window->left)*9)
1364           > ((rect_window->bottom-rect_window->top)*16) )
1365       {
1366         int temp;
1367         temp = (rect_window->bottom-rect_window->top)*16/9;
1368         temp = (rect_window->right-rect_window->left) - temp;
1369         rect_window->left += (temp/2);
1370         rect_window->right -= (temp/2);
1371       }
1372       else
1373         {
1374           int temp;
1375           temp = (rect_window->right-rect_window->left)*9/16;
1376           temp = (rect_window->bottom-rect_window->top) - temp;
1377           rect_window->top += (temp/2);
1378           rect_window->bottom -= (temp/2);
1379         }
1380       break;
1381       
1382   case AR_221_1_PICTURE:
1383     if( ((rect_window->right-rect_window->left)*100)
1384         > ((rect_window->bottom-rect_window->top)*221) )
1385       {
1386         int temp;
1387         temp = (rect_window->bottom-rect_window->top)*221/100;
1388         temp = (rect_window->right-rect_window->left) - temp;
1389         rect_window->left += (temp/2);
1390         rect_window->right -= (temp/2);
1391       }
1392     else
1393       {
1394         int temp;
1395         temp = (rect_window->right-rect_window->left)*100/221;
1396         temp = (rect_window->bottom-rect_window->top) - temp;
1397         rect_window->top += (temp/2);
1398         rect_window->bottom -= (temp/2);
1399       }
1400     break;
1401     
1402   case AR_3_4_PICTURE:
1403     if( ((rect_window->right-rect_window->left)*3)
1404         > ((rect_window->bottom-rect_window->top)*4) )
1405       {
1406         int temp;
1407         temp = (rect_window->bottom-rect_window->top)*4/3;
1408         temp = (rect_window->right-rect_window->left) - temp;
1409         rect_window->left += (temp/2);
1410         rect_window->right -= (temp/2);
1411       }
1412     else
1413       {
1414         int temp;
1415         temp = (rect_window->right-rect_window->left)*3/4;
1416         temp = (rect_window->bottom-rect_window->top) - temp;
1417         rect_window->top += (temp/2);
1418         rect_window->bottom -= (temp/2);
1419       }
1420     break;
1421
1422   case AR_SQUARE_PICTURE:
1423   default:
1424     if( (rect_window->right-rect_window->left)
1425         > (rect_window->bottom-rect_window->top) )
1426       {
1427         int temp;
1428         temp = (rect_window->bottom-rect_window->top);
1429         temp = (rect_window->right-rect_window->left) - temp;
1430         rect_window->left += (temp/2);
1431         rect_window->right -= (temp/2);
1432       }
1433     else
1434       {
1435         int temp;
1436         temp = (rect_window->right-rect_window->left);
1437         temp = (rect_window->bottom-rect_window->top) - temp;
1438         rect_window->top += (temp/2);
1439         rect_window->bottom -= (temp/2);
1440       }
1441     break;
1442     
1443   }
1444
1445 }