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