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