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