]> git.sesse.net Git - vlc/blob - plugins/directx/vout_directx.c
1ca5d9c44b12320f32f40a0a8406048430712244
[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.20 2002/01/27 22:14:52 gbazin Exp $
6  *
7  * Authors: Gildas Bazin <gbazin@netcourrier.com>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble:
26  *
27  * This plugin will use YUV overlay if supported, using overlay will result in
28  * the best video quality (hardware interpolation when rescaling the picture)
29  * and the fastest display as it requires less processing.
30  *
31  * If YUV overlay is not supported this plugin will use RGB offscreen video
32  * surfaces that will be blitted onto the primary surface (display) to
33  * effectively display the pictures. this fallback method enables us to display
34  * video in window mode.
35  * Another fallback method (which isn't implemented) would be take the
36  * exclusive control of the screen so we could spare the blitting process and
37  * decode directly to video memory. This should theoretically allow for better
38  * performance (although on my system it is actually slower) but this is
39  * restricted to fullscreen video.
40  * 
41  *****************************************************************************/
42 #include <errno.h>                                                 /* ENOMEM */
43 #include <stdlib.h>                                                /* free() */
44 #include <string.h>                                            /* strerror() */
45
46 #include <videolan/vlc.h>
47
48 #include <windows.h>
49 #include <windowsx.h>
50
51 #include <ddraw.h>
52
53 #include "netutils.h"
54
55 #include "video.h"
56 #include "video_output.h"
57
58 #include "interface.h"
59
60 #include "vout_directx.h"
61
62 /*****************************************************************************
63  * DirectDraw GUIDs.
64  * Defining them here allows us to get rid of the dxguid library during
65  * the linking stage.
66  *****************************************************************************/
67 #include <initguid.h>
68 DEFINE_GUID( IID_IDirectDraw2, 0xB3A6F3E0,0x2B43,0x11CF,0xA2,0xDE,0x00,0xAA,0x00,0xB9,0x33,0x56 );
69 DEFINE_GUID( IID_IDirectDrawSurface3, 0xDA044E00,0x69B2,0x11D0,0xA1,0xD5,0x00,0xAA,0x00,0xB8,0xDF,0xBB );
70
71 /*****************************************************************************
72  * Local prototypes.
73  *****************************************************************************/
74 static int  vout_Probe     ( probedata_t *p_data );
75 static int  vout_Create    ( vout_thread_t * );
76 static void vout_Destroy   ( vout_thread_t * );
77 static int  vout_Init      ( vout_thread_t * );
78 static void vout_End       ( vout_thread_t * );
79 static int  vout_Manage    ( vout_thread_t * );
80 static void vout_Render    ( vout_thread_t *, picture_t * );
81 static void vout_Display   ( vout_thread_t *, picture_t * );
82
83 static int  NewPictureVec  ( vout_thread_t *, picture_t *, int );
84 static void FreePictureVec ( vout_thread_t *, picture_t *, int );
85 static int  UpdatePictureStruct( vout_thread_t *, picture_t *, int );
86
87 static int  DirectXInitDDraw      ( vout_thread_t *p_vout );
88 static void DirectXCloseDDraw     ( vout_thread_t *p_vout );
89 static int  DirectXCreateDisplay  ( vout_thread_t *p_vout );
90 static void DirectXCloseDisplay   ( vout_thread_t *p_vout );
91 static int  DirectXCreateSurface  ( vout_thread_t *p_vout,
92                                     LPDIRECTDRAWSURFACE3 *, int, int );
93 static void DirectXCloseSurface   ( vout_thread_t *p_vout,
94                                     LPDIRECTDRAWSURFACE3 );
95 static int  DirectXCreateClipper  ( vout_thread_t *p_vout );
96 static void DirectXGetDDrawCaps   ( vout_thread_t *p_vout );
97 static int  DirectXGetSurfaceDesc ( picture_t *p_pic );
98
99 /*****************************************************************************
100  * Functions exported as capabilities. They are declared as static so that
101  * we don't pollute the namespace too much.
102  *****************************************************************************/
103 void _M( vout_getfunctions )( function_list_t * p_function_list )
104 {
105     p_function_list->pf_probe = vout_Probe;
106     p_function_list->functions.vout.pf_create     = vout_Create;
107     p_function_list->functions.vout.pf_init       = vout_Init;
108     p_function_list->functions.vout.pf_end        = vout_End;
109     p_function_list->functions.vout.pf_destroy    = vout_Destroy;
110     p_function_list->functions.vout.pf_manage     = vout_Manage;
111     p_function_list->functions.vout.pf_render     = vout_Render;
112     p_function_list->functions.vout.pf_display    = vout_Display;
113 }
114
115 /*****************************************************************************
116  * vout_Probe: probe the video driver and return a score
117  *****************************************************************************
118  * This function tries to initialize Windows DirectX and returns a score to
119  * the plugin manager so that it can select the best plugin.
120  *****************************************************************************/
121 static int vout_Probe( probedata_t *p_data )
122 {
123
124     /* Check that at least DirectX5 is installed on the computer */
125     /* Fixme */
126
127     return( 400 );
128 }
129
130 /*****************************************************************************
131  * vout_Create: allocate DirectX video thread output method
132  *****************************************************************************
133  * This function allocates and initialize the DirectX vout method.
134  *****************************************************************************/
135 static int vout_Create( vout_thread_t *p_vout )
136 {
137     /* Allocate structure */
138     p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
139     if( p_vout->p_sys == NULL )
140     {
141         intf_ErrMsg( "vout error: can't create p_sys (%s)", strerror(ENOMEM) );
142         return( 1 );
143     }
144
145     /* Initialisations */
146     p_vout->p_sys->p_ddobject = NULL;
147     p_vout->p_sys->p_display = NULL;
148     p_vout->p_sys->p_current_surface = NULL;
149     p_vout->p_sys->p_clipper = NULL;
150     p_vout->p_sys->hbrush = NULL;
151     p_vout->p_sys->hwnd = NULL;
152     p_vout->p_sys->i_changes = 0;
153     p_vout->p_sys->b_event_thread_die = 0;
154     p_vout->p_sys->b_caps_overlay_clipping = 0;
155     SetRectEmpty( &p_vout->p_sys->rect_display );
156     p_vout->p_sys->b_using_overlay =
157         !main_GetIntVariable( VOUT_NOOVERLAY_VAR, VOUT_NOOVERLAY_DEFAULT );
158
159     p_vout->p_sys->b_cursor = 1;
160
161     p_vout->p_sys->b_cursor_autohidden = 0;
162     p_vout->p_sys->i_lastmoved = mdate();
163
164     /* Set main window's size */
165     if( p_vout->render.i_height * p_vout->render.i_aspect
166         >= p_vout->render.i_width * VOUT_ASPECT_FACTOR )
167     {
168         p_vout->p_sys->i_window_width = p_vout->render.i_height
169           * p_vout->render.i_aspect / VOUT_ASPECT_FACTOR;
170         p_vout->p_sys->i_window_height = p_vout->render.i_height;
171     }
172     else
173     {
174         p_vout->p_sys->i_window_width = p_vout->render.i_width;
175         p_vout->p_sys->i_window_height = p_vout->render.i_width
176           * VOUT_ASPECT_FACTOR / p_vout->render.i_aspect;
177     }
178
179 #if 0
180     p_vout->p_sys->i_window_width = main_GetIntVariable( VOUT_WIDTH_VAR,
181                                                          VOUT_WIDTH_DEFAULT );
182     p_vout->p_sys->i_window_height = main_GetIntVariable( VOUT_HEIGHT_VAR,
183                                                          VOUT_HEIGHT_DEFAULT );
184 #endif
185
186     /* Set locks and condition variables */
187     vlc_mutex_init( &p_vout->p_sys->event_thread_lock );
188     vlc_cond_init( &p_vout->p_sys->event_thread_wait );
189     p_vout->p_sys->i_event_thread_status = THREAD_CREATE;
190
191     /* Create the DirectXEventThread, this thread is created by us to isolate
192      * the Win32 PeekMessage function calls. We want to do this because
193      * Windows can stay blocked inside this call for a long time, and when
194      * this happens it thus blocks vlc's video_output thread.
195      * DirectXEventThread will take care of the creation of the video
196      * window (because PeekMessage has to be called from the same thread which
197      * created the window). */
198     intf_WarnMsg( 3, "vout: vout_Create creating DirectXEventThread" );
199     if( vlc_thread_create( &p_vout->p_sys->event_thread_id,
200                            "DirectX Events Thread",
201                            (void *) DirectXEventThread, (void *) p_vout) )
202     {
203         intf_ErrMsg( "vout error: can't create DirectXEventThread" );
204         intf_ErrMsg("vout error: %s", strerror(ENOMEM));
205         free( p_vout->p_sys );
206         return( 1 );
207     }
208
209     /* We need to wait for the actual creation of the thread and window */
210     if( p_vout->p_sys->i_event_thread_status == THREAD_CREATE )
211     {
212         vlc_mutex_lock( &p_vout->p_sys->event_thread_lock );
213         vlc_cond_wait ( &p_vout->p_sys->event_thread_wait,
214                         &p_vout->p_sys->event_thread_lock );
215         vlc_mutex_unlock( &p_vout->p_sys->event_thread_lock );
216     }
217     if( p_vout->p_sys->i_event_thread_status != THREAD_READY )
218     {
219         intf_ErrMsg( "vout error: DirectXEventThread failed" );
220         free( p_vout->p_sys );
221         return( 1 );
222     }
223
224     intf_WarnMsg( 3, "vout: vout_Create DirectXEventThread running" );
225
226
227     /* Initialise DirectDraw */
228     if( DirectXInitDDraw( p_vout ) )
229     {
230         intf_ErrMsg( "vout error: can't initialise DirectDraw" );
231
232         /* Kill DirectXEventThread */
233         p_vout->p_sys->b_event_thread_die = 1;
234         /* we need to be sure DirectXEventThread won't stay stuck in
235          * GetMessage, so we send a fake message */
236         PostMessage( p_vout->p_sys->hwnd, WM_CHAR, (WPARAM)'^', 0);
237         vlc_thread_join( p_vout->p_sys->event_thread_id );
238
239         return ( 1 );
240     }
241
242     /* Create the directx display */
243     if( DirectXCreateDisplay( p_vout ) )
244     {
245         intf_ErrMsg( "vout error: can't initialise DirectDraw" );
246         DirectXCloseDDraw( p_vout );
247
248         /* Kill DirectXEventThread */
249         p_vout->p_sys->b_event_thread_die = 1;
250         /* we need to be sure DirectXEventThread won't stay stuck in
251          * GetMessage, so we send a fake message */
252         PostMessage( p_vout->p_sys->hwnd, WM_CHAR, (WPARAM)'^', 0);
253         vlc_thread_join( p_vout->p_sys->event_thread_id );
254
255         return ( 1 );
256     }
257
258     /* Attach the current thread input queue to the events thread qeue.
259      * This allows us to hide or show the cursor in vout_Manage() */
260     ShowCursor( TRUE ); ShowCursor( FALSE );           /* create input queue */
261     AttachThreadInput( GetCurrentThreadId(),
262                        GetWindowThreadProcessId( p_vout->p_sys->hwnd, NULL ),
263                        1 );
264
265     return( 0 );
266 }
267
268 /*****************************************************************************
269  * vout_Init: initialize DirectX video thread output method
270  *****************************************************************************
271  * This function create the directx surfaces needed by the output thread.
272  * It is called at the beginning of the thread.
273  *****************************************************************************/
274 static int vout_Init( vout_thread_t *p_vout )
275 {
276
277     /* Initialize the output structure.
278      * Since DirectDraw can do rescaling for us, stick to the default
279      * coordinates and aspect. */
280     p_vout->output.i_width  = p_vout->render.i_width;
281     p_vout->output.i_height = p_vout->render.i_height;
282     p_vout->output.i_aspect = p_vout->render.i_aspect;
283
284 #define MAX_DIRECTBUFFERS 1
285
286     NewPictureVec( p_vout, p_vout->p_picture, MAX_DIRECTBUFFERS );
287
288     /* Change the window title bar text */
289     if( p_vout->p_sys->b_using_overlay )
290         SetWindowText( p_vout->p_sys->hwnd,
291                        "VLC DirectX (using hardware overlay)" );
292
293     return( 0 );
294 }
295
296 /*****************************************************************************
297  * vout_End: terminate Sys video thread output method
298  *****************************************************************************
299  * Terminate an output method created by vout_Create.
300  * It is called at the end of the thread.
301  *****************************************************************************/
302 static void vout_End( vout_thread_t *p_vout )
303 {
304     FreePictureVec( p_vout, p_vout->p_picture, I_OUTPUTPICTURES );
305     return;
306 }
307
308 /*****************************************************************************
309  * vout_Destroy: destroy Sys video thread output method
310  *****************************************************************************
311  * Terminate an output method created by vout_Create
312  *****************************************************************************/
313 static void vout_Destroy( vout_thread_t *p_vout )
314 {
315     intf_WarnMsg( 3, "vout: vout_Destroy" );
316     DirectXCloseDisplay( p_vout );
317     DirectXCloseDDraw( p_vout );
318
319     /* Kill DirectXEventThread */
320     p_vout->p_sys->b_event_thread_die = 1;
321     /* we need to be sure DirectXEventThread won't stay stuck in GetMessage,
322      * so we send a fake message */
323     if( p_vout->p_sys->i_event_thread_status == THREAD_READY &&
324         p_vout->p_sys->hwnd )
325     {
326         PostMessage( p_vout->p_sys->hwnd, WM_CHAR, (WPARAM)'q', 0);
327         vlc_thread_join( p_vout->p_sys->event_thread_id );
328     }
329
330     if( p_vout->p_sys != NULL )
331     {
332         free( p_vout->p_sys );
333         p_vout->p_sys = NULL;
334     }
335 }
336
337 /*****************************************************************************
338  * vout_Manage: handle Sys events
339  *****************************************************************************
340  * This function should be called regularly by the video output thread.
341  * It returns a non null value if an error occured.
342  *****************************************************************************/
343 static int vout_Manage( vout_thread_t *p_vout )
344 {
345     WINDOWPLACEMENT window_placement;
346
347     /* We used to call the Win32 PeekMessage function here to read the window
348      * messages. But since window can stay blocked into this function for a
349      * long time (for example when you move your window on the screen), I
350      * decided to isolate PeekMessage in another thread. */
351
352     /*
353      * Scale Change 
354      */
355     if( p_vout->i_changes & VOUT_SCALE_CHANGE
356         || p_vout->p_sys->i_changes & VOUT_SCALE_CHANGE)
357     {
358         intf_WarnMsg( 3, "vout: vout_Manage Scale Change" );
359         if( !p_vout->p_sys->b_using_overlay )
360             InvalidateRect( p_vout->p_sys->hwnd, NULL, TRUE );
361         else
362             DirectXUpdateOverlay( p_vout );
363         p_vout->i_changes &= ~VOUT_SCALE_CHANGE;
364         p_vout->p_sys->i_changes &= ~VOUT_SCALE_CHANGE;
365     }
366
367     /*
368      * Size Change 
369      */
370     if( p_vout->i_changes & VOUT_SIZE_CHANGE
371         || p_vout->p_sys->i_changes & VOUT_SIZE_CHANGE )
372     {
373         intf_WarnMsg( 3, "vout: vout_Manage Size Change" );
374         if( !p_vout->p_sys->b_using_overlay )
375             InvalidateRect( p_vout->p_sys->hwnd, NULL, TRUE );
376         else
377             DirectXUpdateOverlay( p_vout );
378         p_vout->i_changes &= ~VOUT_SIZE_CHANGE;
379         p_vout->p_sys->i_changes &= ~VOUT_SIZE_CHANGE;
380     }
381
382     /*
383      * Fullscreen change
384      */
385     if( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE
386         || p_vout->p_sys->i_changes & VOUT_FULLSCREEN_CHANGE )
387     {
388         p_vout->b_fullscreen = ! p_vout->b_fullscreen;
389
390         /* We need to switch between Maximized and Normal sized window */
391         window_placement.length = sizeof(WINDOWPLACEMENT);
392         GetWindowPlacement( p_vout->p_sys->hwnd, &window_placement );
393         if( p_vout->b_fullscreen )
394         {
395             /* Maximized window */
396             window_placement.showCmd = SW_SHOWMAXIMIZED;
397             /* Change window style, no borders and no title bar */
398             SetWindowLong( p_vout->p_sys->hwnd, GWL_STYLE, 0 );
399
400         }
401         else
402         {
403             /* Normal window */
404             window_placement.showCmd = SW_SHOWNORMAL;
405             /* Change window style, borders and title bar */
406             SetWindowLong( p_vout->p_sys->hwnd, GWL_STYLE,
407                            WS_OVERLAPPEDWINDOW | WS_SIZEBOX | WS_VISIBLE );
408         }
409
410         SetWindowPlacement( p_vout->p_sys->hwnd, &window_placement );
411
412         p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
413         p_vout->p_sys->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
414     }
415
416     /*
417      * Pointer change
418      */
419     if( ! p_vout->p_sys->b_cursor_autohidden &&
420         ( mdate() - p_vout->p_sys->i_lastmoved > 5000000 ) )
421     {
422         /* Hide the mouse automatically */
423         p_vout->p_sys->b_cursor_autohidden = 1;
424         ShowCursor( FALSE );
425     }
426
427 #if 0
428     if( p_vout->i_changes & VOUT_CURSOR_CHANGE
429         || p_vout->p_sys->i_changes & VOUT_CURSOR_CHANGE )
430     {
431         p_vout->p_sys->b_cursor = ! p_vout->p_sys->b_cursor;
432
433         ShowCursor( p_vout->p_sys->b_cursor &&
434                      ! p_vout->p_sys->b_cursor_autohidden );
435
436         p_vout->i_changes &= ~VOUT_CURSOR_CHANGE;
437         p_vout->p_sys->i_changes &= ~VOUT_CURSOR_CHANGE;
438     }
439 #endif
440
441     /* Check if the event thread is still running */
442     if( p_vout->p_sys->b_event_thread_die )
443         return 1; /* exit */
444
445     return( 0 );
446 }
447
448 /*****************************************************************************
449  * vout_Render: render previously calculated output
450  *****************************************************************************/
451 static void vout_Render( vout_thread_t *p_vout, picture_t *p_pic )
452 {
453     ;
454 }
455
456 /*****************************************************************************
457  * vout_Display: displays previously rendered output
458  *****************************************************************************
459  * This function sends the currently rendered image to the display, wait until
460  * it is displayed and switch the two rendering buffers, preparing next frame.
461  *****************************************************************************/
462 static void vout_Display( vout_thread_t *p_vout, picture_t *p_pic )
463 {
464     HRESULT dxresult;
465
466     if( (p_vout->p_sys->p_display == NULL) )
467     {
468         intf_WarnMsg( 3, "vout error: vout_Display no display!!" );
469         return;
470     }
471
472     if( !p_vout->p_sys->b_using_overlay )
473     {
474         DDBLTFX  ddbltfx;
475
476         /* We ask for the "NOTEARING" option */
477         memset( &ddbltfx, 0, sizeof(DDBLTFX) );
478         ddbltfx.dwSize = sizeof(DDBLTFX);
479         ddbltfx.dwDDFX = DDBLTFX_NOTEARING | DDBLT_ASYNC;
480
481         /* Blit video surface to display */
482         dxresult = IDirectDrawSurface3_Blt(p_vout->p_sys->p_display,
483                                            &p_vout->p_sys->rect_dest_clipped,
484                                            p_pic->p_sys->p_surface,
485                                            &p_vout->p_sys->rect_src_clipped,
486                                            0, &ddbltfx );
487         if ( dxresult == DDERR_SURFACELOST )
488         {
489             /* Our surface can be lost so be sure
490              * to check this and restore it if needed */
491             IDirectDrawSurface3_Restore( p_vout->p_sys->p_display );
492
493             /* Now that the surface has been restored try to display again */
494             dxresult = IDirectDrawSurface3_Blt(p_vout->p_sys->p_display,
495                                            &p_vout->p_sys->rect_dest_clipped,
496                                            p_pic->p_sys->p_surface,
497                                            &p_vout->p_sys->rect_src_clipped,
498                                            0, &ddbltfx );
499         }
500
501         if( dxresult != DD_OK )
502         {
503             intf_WarnMsg( 3, "vout: could not Blit the surface" );
504             return;
505         }
506
507     }
508     else /* using overlay */
509     {
510
511         /* Flip the overlay buffers */
512         dxresult = IDirectDrawSurface3_Flip( p_pic->p_sys->p_front_surface,
513                                              NULL, DDFLIP_WAIT );
514         if ( dxresult == DDERR_SURFACELOST )
515         {
516             /* Our surface can be lost so be sure
517              * to check this and restore it if needed */
518             IDirectDrawSurface3_Restore( p_vout->p_sys->p_display );
519             IDirectDrawSurface3_Restore( p_pic->p_sys->p_front_surface );
520
521             /* Now that the surface has been restored try to display again */
522             dxresult = IDirectDrawSurface3_Flip( p_pic->p_sys->p_front_surface,
523                                                  NULL, DDFLIP_WAIT );
524             DirectXUpdateOverlay( p_vout );
525         }
526
527         if( dxresult != DD_OK )
528             intf_WarnMsg( 8, "vout: couldn't flip overlay surface" );
529
530         if( !DirectXGetSurfaceDesc( p_pic ) )
531         {
532             /* AAARRGG */
533             intf_ErrMsg( "vout error: vout_Display cannot get surface desc" );
534             return;
535         }
536
537         if( !UpdatePictureStruct( p_vout, p_pic, p_vout->output.i_chroma ) )
538         {
539             /* AAARRGG */
540             intf_ErrMsg( "vout error: vout_Display unvalid pic chroma" );
541             return;
542         }
543
544         /* set currently displayed pic */
545         p_vout->p_sys->p_current_surface = p_pic->p_sys->p_front_surface;
546     }
547
548 }
549
550
551 /* following functions are local */
552
553 /*****************************************************************************
554  * DirectXInitDDraw: Takes care of all the DirectDraw initialisations
555  *****************************************************************************
556  * This function initialise and allocate resources for DirectDraw.
557  *****************************************************************************/
558 static int DirectXInitDDraw( vout_thread_t *p_vout )
559 {
560     HRESULT    dxresult;
561     HRESULT    (WINAPI *OurDirectDrawCreate)(GUID *,LPDIRECTDRAW *,IUnknown *);
562     LPDIRECTDRAW  p_ddobject;
563
564     intf_WarnMsg( 3, "vout: DirectXInitDDraw" );
565
566     /* load direct draw DLL */
567     p_vout->p_sys->hddraw_dll = LoadLibrary("DDRAW.DLL");
568     if( p_vout->p_sys->hddraw_dll == NULL )
569     {
570         intf_WarnMsg( 3, "vout: DirectXInitDDraw failed loading ddraw.dll" );
571         return( 1 );
572     }
573       
574     OurDirectDrawCreate = 
575       (void *)GetProcAddress(p_vout->p_sys->hddraw_dll, "DirectDrawCreate");
576     if ( OurDirectDrawCreate == NULL )
577     {
578         intf_ErrMsg( "vout error: DirectXInitDDraw failed GetProcAddress" );
579         FreeLibrary( p_vout->p_sys->hddraw_dll );
580         p_vout->p_sys->hddraw_dll = NULL;
581         return( 1 );    
582     }
583
584     /* Initialize DirectDraw now */
585     dxresult = OurDirectDrawCreate( NULL, &p_ddobject, NULL );
586     if( dxresult != DD_OK )
587     {
588         intf_ErrMsg( "vout error: DirectXInitDDraw can't initialize DDraw" );
589         p_vout->p_sys->p_ddobject = NULL;
590         FreeLibrary( p_vout->p_sys->hddraw_dll );
591         p_vout->p_sys->hddraw_dll = NULL;
592         return( 1 );
593     }
594
595     /* Set DirectDraw Cooperative level, ie what control we want over Windows
596      * display */
597     dxresult = IDirectDraw_SetCooperativeLevel( p_ddobject,
598                                            p_vout->p_sys->hwnd, DDSCL_NORMAL );
599     if( dxresult != DD_OK )
600     {
601         intf_ErrMsg( "vout error: can't set direct draw cooperative level." );
602         IDirectDraw_Release( p_ddobject );
603         p_vout->p_sys->p_ddobject = NULL;
604         FreeLibrary( p_vout->p_sys->hddraw_dll );
605         p_vout->p_sys->hddraw_dll = NULL;
606         return( 1 );
607     }
608
609     /* Get the IDirectDraw2 interface */
610     dxresult = IDirectDraw_QueryInterface( p_ddobject, &IID_IDirectDraw2,
611                                         (LPVOID *)&p_vout->p_sys->p_ddobject );
612     if( dxresult != DD_OK )
613     {
614         intf_ErrMsg( "vout error: can't get IDirectDraw2 interface." );
615         IDirectDraw_Release( p_ddobject );
616         p_vout->p_sys->p_ddobject = NULL;
617         FreeLibrary( p_vout->p_sys->hddraw_dll );
618         p_vout->p_sys->hddraw_dll = NULL;
619         return( 1 );
620     }
621     else
622     {
623         /* Release the unused interface */
624         IDirectDraw_Release( p_ddobject );
625     }
626
627     /* Probe the capabilities of the hardware */
628     DirectXGetDDrawCaps( p_vout );
629
630     intf_WarnMsg( 3, "vout: End DirectXInitDDraw" );
631     return( 0 );
632 }
633
634 /*****************************************************************************
635  * DirectXCreateDisplay: create the DirectDraw display.
636  *****************************************************************************
637  * Create and initialize display according to preferences specified in the vout
638  * thread fields.
639  *****************************************************************************/
640 static int DirectXCreateDisplay( vout_thread_t *p_vout )
641 {
642     HRESULT              dxresult;
643     DDSURFACEDESC        ddsd;
644     LPDIRECTDRAWSURFACE  p_display;
645     DDPIXELFORMAT   pixel_format;
646
647     intf_WarnMsg( 3, "vout: DirectXCreateDisplay" );
648
649     /* Now get the primary surface. This surface is what you actually see
650      * on your screen */
651     memset( &ddsd, 0, sizeof( DDSURFACEDESC ));
652     ddsd.dwSize = sizeof(DDSURFACEDESC);
653     ddsd.dwFlags = DDSD_CAPS;
654     ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
655
656     dxresult = IDirectDraw2_CreateSurface( p_vout->p_sys->p_ddobject,
657                                            &ddsd,
658                                            &p_display, NULL );
659     if( dxresult != DD_OK )
660     {
661         intf_ErrMsg( "vout error: can't get direct draw primary surface." );
662         p_vout->p_sys->p_display = NULL;
663         return( 1 );
664     }
665
666     dxresult = IDirectDrawSurface_QueryInterface( p_display,
667                                          &IID_IDirectDrawSurface3,
668                                          (LPVOID *)&p_vout->p_sys->p_display );
669     if ( dxresult != DD_OK )
670     {
671         intf_ErrMsg( "vout error: can't get IDirectDrawSurface3 interface." );
672         IDirectDrawSurface_Release( p_display );
673         p_vout->p_sys->p_display = NULL;
674         return( 1 );
675     }
676     else
677     {
678         /* Release the old interface */
679         IDirectDrawSurface_Release( p_display );
680     }
681
682
683     /* The clipper will be used only in non-overlay mode */
684     DirectXCreateClipper( p_vout );
685
686
687 #if 1
688     /* compute the colorkey pixel value from the RGB value we've got */
689     memset( &pixel_format, 0, sizeof( DDPIXELFORMAT ));
690     pixel_format.dwSize = sizeof( DDPIXELFORMAT );
691     dxresult = IDirectDrawSurface3_GetPixelFormat( p_vout->p_sys->p_display,
692                                                    &pixel_format );
693     if( dxresult != DD_OK )
694         intf_WarnMsg( 3, "vout: DirectXUpdateOverlay GetPixelFormat failed" );
695     p_vout->p_sys->i_colorkey = (DWORD)((( p_vout->p_sys->i_rgb_colorkey
696                                            * pixel_format.dwRBitMask) / 255)
697                                         & pixel_format.dwRBitMask);
698 #endif
699
700     return( 0 );
701 }
702
703
704 /*****************************************************************************
705  * DirectXCreateClipper: Create a clipper that will be used when blitting the
706  *                       RGB surface to the main display.
707  *****************************************************************************
708  * This clipper prevents us to modify by mistake anything on the screen
709  * which doesn't belong to our window. For example when a part of our video
710  * window is hidden by another window.
711  *****************************************************************************/
712 static int DirectXCreateClipper( vout_thread_t *p_vout )
713 {
714     HRESULT dxresult;
715
716     intf_WarnMsg( 3, "vout: DirectXCreateClipper" );
717
718     /* Create the clipper */
719     dxresult = IDirectDraw2_CreateClipper( p_vout->p_sys->p_ddobject, 0,
720                                            &p_vout->p_sys->p_clipper, NULL );
721     if( dxresult != DD_OK )
722     {
723         intf_WarnMsg( 3, "vout: DirectXCreateClipper can't create clipper." );
724         p_vout->p_sys->p_clipper = NULL;
725         return( 1 );
726     }
727
728     /* associate the clipper to the window */
729     dxresult = IDirectDrawClipper_SetHWnd(p_vout->p_sys->p_clipper, 0,
730                                           p_vout->p_sys->hwnd);
731     if( dxresult != DD_OK )
732     {
733         intf_WarnMsg( 3,
734             "vout: DirectXCreateClipper can't attach clipper to window." );
735         IDirectDrawSurface_Release( p_vout->p_sys->p_clipper );
736         p_vout->p_sys->p_clipper = NULL;
737         return( 1 );
738     }
739
740     /* associate the clipper with the surface */
741     dxresult = IDirectDrawSurface_SetClipper(p_vout->p_sys->p_display,
742                                              p_vout->p_sys->p_clipper);
743     if( dxresult != DD_OK )
744     {
745         intf_WarnMsg( 3,
746             "vout: DirectXCreateClipper can't attach clipper to surface." );
747         IDirectDrawSurface_Release( p_vout->p_sys->p_clipper );
748         p_vout->p_sys->p_clipper = NULL;
749         return( 1 );
750     }    
751
752     return( 0 );
753 }
754
755 /*****************************************************************************
756  * DirectXCreateSurface: create an YUV overlay or RGB surface for the video.
757  *****************************************************************************
758  * The best method of display is with an YUV overlay because the YUV->RGB
759  * conversion is done in hardware.
760  * You can also create a plain RGB surface.
761  * ( Maybe we could also try an RGB overlay surface, which could have hardware
762  * scaling and which would also be faster in window mode because you don't
763  * need to do any blitting to the main display...)
764  *****************************************************************************/
765 static int DirectXCreateSurface( vout_thread_t *p_vout,
766                                  LPDIRECTDRAWSURFACE3 *pp_surface_final,
767                                  int i_chroma, int b_overlay )
768 {
769     HRESULT dxresult;
770     LPDIRECTDRAWSURFACE p_surface;
771     DDSURFACEDESC ddsd;
772
773     intf_WarnMsg( 3, "vout: DirectXCreateSurface" );
774
775     /* Create the video surface */
776     if( b_overlay )
777     {
778         /* Now try to create the YUV overlay surface.
779          * This overlay will be displayed on top of the primary surface.
780          * A color key is used to determine whether or not the overlay will be
781          * displayed, ie the overlay will be displayed in place of the primary
782          * surface wherever the primary surface will have this color.
783          * The video window has been created with a background of this color so
784          * the overlay will be only displayed on top of this window */
785
786         memset( &ddsd, 0, sizeof( DDSURFACEDESC ));
787         ddsd.dwSize = sizeof(DDSURFACEDESC);
788         ddsd.ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT);
789         ddsd.ddpfPixelFormat.dwFlags = DDPF_FOURCC;
790         ddsd.ddpfPixelFormat.dwFourCC = i_chroma;
791         ddsd.dwFlags = DDSD_CAPS |
792                        DDSD_HEIGHT |
793                        DDSD_WIDTH |
794                        DDSD_BACKBUFFERCOUNT |
795                        DDSD_PIXELFORMAT;
796         ddsd.ddsCaps.dwCaps = DDSCAPS_OVERLAY |
797                               DDSCAPS_COMPLEX |
798                               DDSCAPS_FLIP |
799                               DDSCAPS_VIDEOMEMORY;
800         ddsd.dwHeight = p_vout->render.i_height;
801         ddsd.dwWidth = p_vout->render.i_width;
802         ddsd.dwBackBufferCount = 1;                       /* One back buffer */
803
804         dxresult = IDirectDraw2_CreateSurface( p_vout->p_sys->p_ddobject,
805                                                &ddsd,
806                                                &p_surface, NULL );
807         if( dxresult == DD_OK )
808         {
809             intf_WarnMsg( 3,"vout: DirectX YUV overlay created successfully" );
810         }
811         else
812         {
813             intf_ErrMsg( "vout error: can't create YUV overlay surface." );
814             *pp_surface_final = NULL;
815             return 0;
816         }
817     }
818
819     if( !b_overlay )
820     {
821         /* Now try to create a plain RGB surface. */
822         memset( &ddsd, 0, sizeof( DDSURFACEDESC ) );
823         ddsd.dwSize = sizeof(DDSURFACEDESC);
824         ddsd.dwFlags = DDSD_HEIGHT |
825                        DDSD_WIDTH |
826                        DDSD_CAPS;
827         ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN |
828                               DDSCAPS_SYSTEMMEMORY;
829         ddsd.dwHeight = p_vout->render.i_height;
830         ddsd.dwWidth = p_vout->render.i_width;
831
832         dxresult = IDirectDraw2_CreateSurface( p_vout->p_sys->p_ddobject,
833                                                &ddsd,
834                                                &p_surface, NULL );
835         if( dxresult == DD_OK )
836         {
837             intf_WarnMsg( 3,"vout: DirectX RGB surface created successfully" );
838         }
839         else
840         {
841             intf_ErrMsg( "vout error: can't create RGB surface." );
842             *pp_surface_final = NULL;
843             return 0;
844         }
845     }
846       
847     /* Now that the surface is created, try to get a newer DirectX interface */
848     dxresult = IDirectDrawSurface_QueryInterface( p_surface,
849                                      &IID_IDirectDrawSurface3,
850                                      (LPVOID *)pp_surface_final );
851     IDirectDrawSurface_Release( p_surface );    /* Release the old interface */
852     if ( dxresult != DD_OK )
853     {
854         intf_ErrMsg( "vout error: can't get IDirectDrawSurface3 interface." );
855         *pp_surface_final = NULL;
856         return 0;
857     }
858
859     return 1;
860 }
861
862
863 /*****************************************************************************
864  * DirectXUpdateOverlay: Move or resize overlay surface on video display.
865  *****************************************************************************
866  * This function is used to move or resize an overlay surface on the screen.
867  * Ususally the overlay is moved by the user and thus, by a move or resize
868  * event (in vout_Manage).
869  *****************************************************************************/
870 void DirectXUpdateOverlay( vout_thread_t *p_vout )
871 {
872     DDOVERLAYFX     ddofx;
873     DWORD           dwFlags;
874     HRESULT         dxresult;
875
876     if( p_vout->p_sys->p_current_surface == NULL ||
877         !p_vout->p_sys->b_using_overlay )
878     {
879         intf_WarnMsg( 5, "vout: DirectXUpdateOverlay no overlay !!" );
880         return;
881     }
882
883     /* The new window dimensions should already have been computed by the
884      * caller of this function */
885
886     /* Position and show the overlay */
887     memset(&ddofx, 0, sizeof(DDOVERLAYFX));
888     ddofx.dwSize = sizeof(DDOVERLAYFX);
889     ddofx.dckDestColorkey.dwColorSpaceLowValue = p_vout->p_sys->i_colorkey;
890     ddofx.dckDestColorkey.dwColorSpaceHighValue = p_vout->p_sys->i_colorkey;
891
892     dwFlags = DDOVER_SHOW;
893     if( !p_vout->p_sys->b_caps_overlay_clipping )
894         dwFlags |= DDOVER_KEYDESTOVERRIDE;
895
896     dxresult = IDirectDrawSurface3_UpdateOverlay(
897                                          p_vout->p_sys->p_current_surface,
898                                          &p_vout->p_sys->rect_src_clipped,
899                                          p_vout->p_sys->p_display,
900                                          &p_vout->p_sys->rect_dest_clipped,
901                                          dwFlags,
902                                          &ddofx );
903     if(dxresult != DD_OK)
904     {
905         intf_WarnMsg( 3,
906           "vout: DirectXUpdateOverlay can't move or resize overlay" );
907     }
908
909 }
910
911 /*****************************************************************************
912  * DirectXCloseDDraw: Release the DDraw object allocated by DirectXInitDDraw
913  *****************************************************************************
914  * This function returns all resources allocated by DirectXInitDDraw.
915  *****************************************************************************/
916 static void DirectXCloseDDraw( vout_thread_t *p_vout )
917 {
918     intf_WarnMsg(3, "vout: DirectXCloseDDraw" );
919     if( p_vout->p_sys->p_ddobject != NULL )
920     {
921         IDirectDraw2_Release(p_vout->p_sys->p_ddobject);
922         p_vout->p_sys->p_ddobject = NULL;
923     }
924
925     if( p_vout->p_sys->hddraw_dll != NULL )
926     {
927         FreeLibrary( p_vout->p_sys->hddraw_dll );
928         p_vout->p_sys->hddraw_dll = NULL;
929     }
930 }
931
932 /*****************************************************************************
933  * DirectXCloseDisplay: close and reset the DirectX display device
934  *****************************************************************************
935  * This function returns all resources allocated by DirectXCreateDisplay.
936  *****************************************************************************/
937 static void DirectXCloseDisplay( vout_thread_t *p_vout )
938 {
939     intf_WarnMsg( 3, "vout: DirectXCloseDisplay" );
940
941     if( p_vout->p_sys->p_clipper != NULL )
942     {
943         intf_WarnMsg( 3, "vout: DirectXCloseDisplay clipper" );
944         IDirectDraw2_Release( p_vout->p_sys->p_clipper );
945         p_vout->p_sys->p_clipper = NULL;
946     }
947
948     if( p_vout->p_sys->p_display != NULL )
949     {
950         intf_WarnMsg( 3, "vout: DirectXCloseDisplay display" );
951         IDirectDraw2_Release( p_vout->p_sys->p_display );
952         p_vout->p_sys->p_display = NULL;
953     }
954 }
955
956 /*****************************************************************************
957  * DirectXCloseSurface: close the YUV overlay or RGB surface.
958  *****************************************************************************
959  * This function returns all resources allocated for the surface.
960  *****************************************************************************/
961 static void DirectXCloseSurface( vout_thread_t *p_vout,
962                                  LPDIRECTDRAWSURFACE3 p_surface )
963 {
964     intf_WarnMsg( 3, "vout: DirectXCloseSurface" );
965     if( p_surface != NULL )
966     {
967         IDirectDraw2_Release( p_surface );
968     }
969 }
970
971 /*****************************************************************************
972  * NewPictureVec: allocate a vector of identical pictures
973  *****************************************************************************
974  * Returns 0 on success, -1 otherwise
975  *****************************************************************************/
976 static int NewPictureVec( vout_thread_t *p_vout, picture_t *p_pic,
977                           int i_num_pics )
978 {
979     int i;
980     LPDIRECTDRAWSURFACE3 p_surface;
981
982 #if 0
983     /* We couldn't use an YUV overlay so we need to indicate to video_output
984      * which format we are falling back to */
985     switch( )
986     {
987         case 8: /* FIXME: set the palette */
988             p_vout->output.i_chroma = FOURCC_BI_RGB; break;
989         case 15:
990             p_vout->output.i_chroma = FOURCC_RV15; break;
991         case 16:
992             p_vout->output.i_chroma = FOURCC_RV16; break;
993         case 24:
994             p_vout->output.i_chroma = FOURCC_BI_BITFIELDS; break;
995         case 32:
996             p_vout->output.i_chroma = FOURCC_BI_BITFIELDS; break;
997         default:
998             intf_ErrMsg( "vout error: unknown screen depth" );
999             return( 0 );
1000     }
1001 #endif
1002
1003     intf_WarnMsg( 3, "vout: NewPictureVec" );
1004
1005     I_OUTPUTPICTURES = 0;
1006
1007     /* chroma asked for */
1008     p_vout->output.i_chroma = p_vout->render.i_chroma;
1009
1010     /* hack */
1011 #if 1
1012     if( p_vout->render.i_chroma == FOURCC_I420 )
1013         p_vout->output.i_chroma = FOURCC_YV12;
1014 #endif
1015
1016     /* First we try to create an overlay surface.
1017      * It looks like with most hardware it's not possible to create several
1018      * overlay surfaces, and even if it was I bet it would be slower anyway to
1019      * use them as direct buffers because they usually reside in video memory
1020      * which is quite slow.
1021      * So the overlay surface (with a back-buffer) that we create won't be used
1022      * to decode directly into it but instead picture buffers in system memory
1023      * will be blitted to it. */
1024     if( p_vout->p_sys->b_using_overlay )
1025     {
1026         if( DirectXCreateSurface( p_vout, &p_surface, p_vout->output.i_chroma,
1027                                   p_vout->p_sys->b_using_overlay ) )
1028         {
1029             DDSCAPS dds_caps;
1030
1031             /* Allocate internal structure */
1032             p_pic[0].p_sys = malloc( sizeof( picture_sys_t ) );
1033             if( p_pic[0].p_sys == NULL )
1034             {
1035                 DirectXCloseSurface( p_vout, p_surface );
1036                 return -1;
1037             }
1038
1039             /* set front buffer */
1040             p_pic[0].p_sys->p_front_surface = p_surface;
1041
1042             /* Get the back buffer */
1043             memset( &dds_caps, 0, sizeof( DDSCAPS ));
1044             dds_caps.dwCaps = DDSCAPS_BACKBUFFER;
1045             if( DD_OK != IDirectDrawSurface3_GetAttachedSurface(
1046                                                 p_surface, &dds_caps,
1047                                                 &p_pic[0].p_sys->p_surface ) )
1048             {
1049                 intf_WarnMsg( 3, "vout: NewPictureVec couldn't get "
1050                               "back buffer" );
1051                 /* front buffer is the same as back buffer */
1052                 p_pic[0].p_sys->p_surface = p_surface;
1053             }
1054
1055
1056             p_vout->p_sys->p_current_surface= p_pic[0].p_sys->p_front_surface;
1057             DirectXUpdateOverlay( p_vout );
1058             I_OUTPUTPICTURES = 1;
1059         }
1060         else p_vout->p_sys->b_using_overlay = 0;
1061     }
1062
1063     /* As we can't have overlays, will try to create plain RBG surfaces in
1064      * system memory. These surfaces will then be blitted onto the primary
1065      * surface (display) so they can be displayed */
1066     if( !p_vout->p_sys->b_using_overlay )
1067     {
1068         /* FixMe */
1069         p_vout->output.i_chroma = FOURCC_RV16;
1070
1071         for( i = 0; i < i_num_pics; i++ )
1072         {
1073             if( DirectXCreateSurface( p_vout, &p_surface,
1074                                       p_vout->output.i_chroma,
1075                                       p_vout->p_sys->b_using_overlay ) )
1076             {
1077                 /* Allocate internal structure */
1078                 p_pic[i].p_sys = malloc( sizeof( picture_sys_t ) );
1079                 if( p_pic[i].p_sys == NULL )
1080                 {
1081                     DirectXCloseSurface( p_vout, p_surface );
1082                     FreePictureVec( p_vout, p_pic, I_OUTPUTPICTURES );
1083                     I_OUTPUTPICTURES = 0;
1084                     return -1;
1085                 }
1086                 p_pic[i].p_sys->p_surface = p_surface;
1087                 p_pic[i].p_sys->p_front_surface = NULL;
1088                 I_OUTPUTPICTURES++;
1089
1090             }
1091             else break;
1092         }
1093     }
1094
1095
1096     /* Now that we've got all our direct-buffers, we can finish filling in the
1097      * picture_t structures */
1098     for( i = 0; i < I_OUTPUTPICTURES; i++ )
1099     {
1100         p_pic[i].i_status = DESTROYED_PICTURE;
1101         p_pic[i].i_type   = DIRECT_PICTURE;
1102         PP_OUTPUTPICTURE[i] = &p_pic[i];
1103
1104         if( !DirectXGetSurfaceDesc( &p_pic[i] ) )
1105         {
1106             /* AAARRGG */
1107             FreePictureVec( p_vout, p_pic, I_OUTPUTPICTURES );
1108             I_OUTPUTPICTURES = 0;
1109             return -1;
1110         }
1111
1112         if( !UpdatePictureStruct(p_vout, &p_pic[i], p_vout->output.i_chroma) )
1113         {
1114
1115             /* Unknown chroma, tell the guy to get lost */
1116             intf_ErrMsg( "vout error: never heard of chroma 0x%.8x (%4.4s)",
1117                          p_vout->output.i_chroma,
1118                          (char*)&p_vout->output.i_chroma );
1119             FreePictureVec( p_vout, p_pic, I_OUTPUTPICTURES );
1120             I_OUTPUTPICTURES = 0;
1121             return -1;
1122         }
1123     }
1124
1125     intf_WarnMsg( 3, "vout: End NewPictureVec");
1126     return 0;
1127 }
1128
1129 /*****************************************************************************
1130  * FreePicture: destroy a picture vector allocated with NewPictureVec
1131  *****************************************************************************
1132  * 
1133  *****************************************************************************/
1134 static void FreePictureVec( vout_thread_t *p_vout, picture_t *p_pic,
1135                             int i_num_pics )
1136 {
1137     int i;
1138
1139     for( i = 0; i < i_num_pics; i++ )
1140     {
1141 #if 0
1142         if( p_pic->p_sys->p_front_surface && 
1143             ( p_pic->p_sys->p_surface != p_pic->p_sys->p_front_surface ) )
1144             DirectXCloseSurface( p_vout, p_pic[i].p_sys->p_front_surface );
1145 #endif
1146
1147         DirectXCloseSurface( p_vout, p_pic[i].p_sys->p_surface );
1148
1149         for( i = 0; i < i_num_pics; i++ )
1150         {
1151             free( p_pic[i].p_sys );
1152         }
1153     }
1154 }
1155
1156 /*****************************************************************************
1157  * UpdatePictureStruct: updates the internal data in the picture_t structure
1158  *****************************************************************************
1159  * This will setup stuff for use by the video_output thread
1160  *****************************************************************************/
1161 static int UpdatePictureStruct( vout_thread_t *p_vout, picture_t *p_pic,
1162                                 int i_chroma )
1163 {
1164
1165     switch( p_vout->output.i_chroma )
1166     {
1167
1168         case FOURCC_YV12:
1169
1170             p_pic->Y_PIXELS = p_pic->p_sys->ddsd.lpSurface;
1171             p_pic->p[Y_PLANE].i_lines = p_vout->output.i_height;
1172             p_pic->p[Y_PLANE].i_pitch = p_pic->p_sys->ddsd.lPitch;
1173             p_pic->p[Y_PLANE].i_pixel_bytes = 1;
1174             p_pic->p[Y_PLANE].b_margin = 0;
1175
1176             p_pic->V_PIXELS =  p_pic->Y_PIXELS
1177               + p_pic->p[Y_PLANE].i_lines * p_pic->p[Y_PLANE].i_pitch;
1178             p_pic->p[V_PLANE].i_lines = p_vout->output.i_height / 2;
1179             p_pic->p[V_PLANE].i_pitch = p_pic->p[Y_PLANE].i_pitch / 2;
1180             p_pic->p[V_PLANE].i_pixel_bytes = 1;
1181             p_pic->p[V_PLANE].b_margin = 0;
1182
1183             p_pic->U_PIXELS = p_pic->V_PIXELS
1184               + p_pic->p[V_PLANE].i_lines * p_pic->p[V_PLANE].i_pitch;
1185             p_pic->p[U_PLANE].i_lines = p_vout->output.i_height / 2;
1186             p_pic->p[U_PLANE].i_pitch = p_pic->p[Y_PLANE].i_pitch / 2;
1187             p_pic->p[U_PLANE].i_pixel_bytes = 1;
1188             p_pic->p[U_PLANE].b_margin = 0;
1189
1190             p_pic->i_planes = 3;
1191             break;
1192
1193         case FOURCC_RV16:
1194
1195             p_pic->p->p_pixels = p_pic->p_sys->ddsd.lpSurface;
1196             p_pic->p->i_lines = p_vout->output.i_height;
1197             p_pic->p->i_pitch = p_pic->p_sys->ddsd.lPitch;
1198             p_pic->p->i_pixel_bytes = 2;
1199             p_pic->p->b_margin = 0;
1200
1201             p_pic->p->i_red_mask   = 0x001f;
1202             p_pic->p->i_green_mask = 0x03e0;
1203             p_pic->p->i_blue_mask  = 0x7c00;
1204
1205             p_pic->i_planes = 1;
1206             break;
1207
1208         case FOURCC_RV15:
1209
1210             p_pic->p->p_pixels = p_pic->p_sys->ddsd.lpSurface;
1211             p_pic->p->i_lines = p_vout->output.i_height;
1212             p_pic->p->i_pitch = p_pic->p_sys->ddsd.lPitch;
1213             p_pic->p->i_pixel_bytes = 2;
1214             p_pic->p->b_margin = 0;
1215
1216             p_pic->p->i_red_mask   = 0x001f;
1217             p_pic->p->i_green_mask = 0x07e0;
1218             p_pic->p->i_blue_mask  = 0xf800;
1219
1220             p_pic->i_planes = 1;
1221             break;
1222
1223         case FOURCC_I420:
1224
1225             p_pic->Y_PIXELS = p_pic->p_sys->ddsd.lpSurface;
1226             p_pic->p[Y_PLANE].i_lines = p_vout->output.i_height;
1227             p_pic->p[Y_PLANE].i_pitch = p_pic->p_sys->ddsd.lPitch;
1228             p_pic->p[Y_PLANE].i_pixel_bytes = 1;
1229             p_pic->p[Y_PLANE].b_margin = 0;
1230
1231             p_pic->U_PIXELS = p_pic->Y_PIXELS
1232               + p_pic->p[Y_PLANE].i_lines * p_pic->p[Y_PLANE].i_pitch;
1233             p_pic->p[U_PLANE].i_lines = p_vout->output.i_height / 2;
1234             p_pic->p[U_PLANE].i_pitch = p_pic->p[Y_PLANE].i_pitch / 2;
1235             p_pic->p[U_PLANE].i_pixel_bytes = 1;
1236             p_pic->p[U_PLANE].b_margin = 0;
1237
1238             p_pic->V_PIXELS = p_pic->U_PIXELS
1239               + p_pic->p[U_PLANE].i_lines * p_pic->p[U_PLANE].i_pitch;
1240             p_pic->p[V_PLANE].i_lines = p_vout->output.i_height / 2;
1241             p_pic->p[V_PLANE].i_pitch = p_pic->p[U_PLANE].i_pitch;
1242             p_pic->p[V_PLANE].i_pixel_bytes = 1;
1243             p_pic->p[V_PLANE].b_margin = 0;
1244
1245             p_pic->i_planes = 3;
1246             break;
1247
1248 #if 0
1249         case FOURCC_Y211:
1250
1251             p_pic->p->p_pixels = p_pic->p_sys->p_image->data
1252                                   + p_pic->p_sys->p_image->offsets[0];
1253             p_pic->p->i_lines = p_vout->output.i_height;
1254             /* XXX: this just looks so plain wrong... check it out ! */
1255             p_pic->p->i_pitch = p_pic->p_sys->p_image->pitches[0] / 4;
1256             p_pic->p->i_pixel_bytes = 4;
1257             p_pic->p->b_margin = 0;
1258
1259             p_pic->i_planes = 1;
1260             break;
1261
1262         case FOURCC_YUY2:
1263         case FOURCC_UYVY:
1264
1265             p_pic->p->p_pixels = p_pic->p_sys->p_image->data
1266                                   + p_pic->p_sys->p_image->offsets[0];
1267             p_pic->p->i_lines = p_vout->output.i_height;
1268             p_pic->p->i_pitch = p_pic->p_sys->p_image->pitches[0];
1269             p_pic->p->i_pixel_bytes = 4;
1270             p_pic->p->b_margin = 0;
1271
1272             p_pic->i_planes = 1;
1273             break;
1274 #endif
1275
1276         default:
1277             /* Not supported */
1278             return 0;
1279
1280     }
1281
1282     return 1;
1283 }
1284
1285 /*****************************************************************************
1286  * DirectXGetDDrawCaps: Probe the capabilities of the hardware
1287  *****************************************************************************
1288  * It is nice to know which features are supported by the hardware so we can
1289  * find ways to optimize our rendering.
1290  *****************************************************************************/
1291 static void DirectXGetDDrawCaps( vout_thread_t *p_vout )
1292 {
1293     DDCAPS ddcaps;
1294     HRESULT dxresult;
1295
1296     /* This is just an indication of whether or not we'll support overlay,
1297      * but with this test we don't know if we support YUV overlay */
1298     memset( &ddcaps, 0, sizeof( DDCAPS ));
1299     ddcaps.dwSize = sizeof(DDCAPS);
1300     dxresult = IDirectDraw2_GetCaps( p_vout->p_sys->p_ddobject,
1301                                      &ddcaps, NULL );
1302     if(dxresult != DD_OK )
1303     {
1304         intf_WarnMsg( 3,"vout error: can't get caps." );
1305     }
1306     else
1307     {
1308         BOOL bHasOverlay, bHasOverlayFourCC, bCanClipOverlay,
1309              bHasColorKey, bCanStretch;
1310
1311         /* Determine if the hardware supports overlay surfaces */
1312         bHasOverlay = ((ddcaps.dwCaps & DDCAPS_OVERLAY) ==
1313                        DDCAPS_OVERLAY) ? TRUE : FALSE;
1314         /* Determine if the hardware supports overlay surfaces */
1315         bHasOverlayFourCC = ((ddcaps.dwCaps & DDCAPS_OVERLAYFOURCC) ==
1316                        DDCAPS_OVERLAYFOURCC) ? TRUE : FALSE;
1317         /* Determine if the hardware supports overlay surfaces */
1318         bCanClipOverlay = ((ddcaps.dwCaps & DDCAPS_OVERLAYCANTCLIP) ==
1319                        0 ) ? TRUE : FALSE;
1320         /* Determine if the hardware supports colorkeying */
1321         bHasColorKey = ((ddcaps.dwCaps & DDCAPS_COLORKEY) ==
1322                         DDCAPS_COLORKEY) ? TRUE : FALSE;
1323         /* Determine if the hardware supports scaling of the overlay surface */
1324         bCanStretch = ((ddcaps.dwCaps & DDCAPS_OVERLAYSTRETCH) ==
1325                        DDCAPS_OVERLAYSTRETCH) ? TRUE : FALSE;
1326         intf_WarnMsg( 3, "vout: DirectDraw Capabilities:" );
1327         intf_WarnMsg( 3, "       overlay=%i yuvoverlay=%i can_clip_overlay=%i "
1328                          "colorkey=%i stretch=%i",
1329                       bHasOverlay, bHasOverlayFourCC, bCanClipOverlay,
1330                       bHasColorKey, bCanStretch );
1331
1332         /* Overlay clipping support is interesting for us as it means we can
1333          * get rid of the colorkey alltogether */
1334         p_vout->p_sys->b_caps_overlay_clipping = bCanClipOverlay;
1335
1336     }
1337 }
1338
1339 /*****************************************************************************
1340  * DirectXGetSurfaceDesc: Get some more information about the surface
1341  *****************************************************************************
1342  * This function get and stores the surface descriptor which among things
1343  * has the pointer to the picture data.
1344  *****************************************************************************/
1345 static int DirectXGetSurfaceDesc( picture_t *p_pic )
1346 {
1347     HRESULT         dxresult;
1348
1349     /* Lock the surface to get a valid pointer to the picture buffer */
1350     memset( &p_pic->p_sys->ddsd, 0, sizeof( DDSURFACEDESC ));
1351     p_pic->p_sys->ddsd.dwSize = sizeof(DDSURFACEDESC);
1352     dxresult = IDirectDrawSurface3_Lock( p_pic->p_sys->p_surface,
1353                                          NULL, &p_pic->p_sys->ddsd,
1354                                          DDLOCK_NOSYSLOCK | DDLOCK_WAIT,
1355                                          NULL );
1356     if ( dxresult == DDERR_SURFACELOST )
1357     {
1358         /* Your surface can be lost so be sure
1359          * to check this and restore it if needed */
1360         dxresult = IDirectDrawSurface3_Restore( p_pic->p_sys->p_surface );
1361         dxresult = IDirectDrawSurface3_Lock( p_pic->p_sys->p_surface, NULL,
1362                                              &p_pic->p_sys->ddsd,
1363                                              DDLOCK_NOSYSLOCK | DDLOCK_WAIT,
1364                                              NULL);
1365     }
1366     if( dxresult != DD_OK )
1367     {
1368         intf_ErrMsg( "vout: DirectXGetSurfaceDesc can't lock surface" );
1369         return 0;
1370     }
1371
1372     /* Unlock the Surface */
1373     dxresult = IDirectDrawSurface3_Unlock( p_pic->p_sys->p_surface, NULL );
1374
1375     return 1;
1376 }