1 /*****************************************************************************
2 * vout.c: Windows DirectX video output display method
3 *****************************************************************************
4 * Copyright (C) 2001 VideoLAN
5 * $Id: directx.c,v 1.2 2002/10/05 17:29:50 gbazin Exp $
7 * Authors: Gildas Bazin <gbazin@netcourrier.com>
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.
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.
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 *****************************************************************************/
24 /*****************************************************************************
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.
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.
36 *****************************************************************************/
37 #include <errno.h> /* ENOMEM */
38 #include <stdlib.h> /* free() */
39 #include <string.h> /* strerror() */
51 /*****************************************************************************
53 * Defining them here allows us to get rid of the dxguid library during
55 *****************************************************************************/
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 );
60 /*****************************************************************************
62 *****************************************************************************/
63 static int OpenVideo ( vlc_object_t * );
64 static void CloseVideo ( vlc_object_t * );
66 static int Init ( vout_thread_t * );
67 static void End ( vout_thread_t * );
68 static int Manage ( vout_thread_t * );
69 static void Display ( vout_thread_t *, picture_t * );
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 );
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 );
87 /*****************************************************************************
89 *****************************************************************************/
90 #define HW_YUV_TEXT N_("use hardware YUV->RGB conversions")
91 #define HW_YUV_LONGTEXT N_( \
92 "Try to use hardware acceleration for YUV->RGB conversions. " \
93 "This option doesn't have any effect when using overlays." )
94 #define SYSMEM_TEXT N_("use video buffers in system memory")
95 #define SYSMEM_LONGTEXT N_( \
96 "Create video buffers in system memory instead of video memory. This " \
97 "isn't recommended as usually using video memory allows to benefit from " \
98 "more hardware acceleration (like rescaling or YUV->RGB conversions). " \
99 "This option doesn't have any effect when using overlays." )
102 add_category_hint( N_("Video"), NULL );
103 add_bool( "directx-hw-yuv", 1, NULL, HW_YUV_TEXT, HW_YUV_LONGTEXT );
104 add_bool( "directx-use-sysmem", 0, NULL, SYSMEM_TEXT, SYSMEM_LONGTEXT );
105 set_description( _("DirectX video module") );
106 set_capability( "video output", 100 );
107 set_callbacks( OpenVideo, CloseVideo );
111 /* check if we registered a window class because we need to
114 if( GetClassInfo( GetModuleHandle(NULL), "VLC DirectX", &wndclass ) )
115 UnregisterClass( "VLC DirectX", GetModuleHandle(NULL) );
118 /*****************************************************************************
119 * OpenVideo: allocate DirectX video thread output method
120 *****************************************************************************
121 * This function allocates and initialize the DirectX vout method.
122 *****************************************************************************/
123 static int OpenVideo( vlc_object_t *p_this )
125 vout_thread_t * p_vout = (vout_thread_t *)p_this;
127 /* Allocate structure */
128 p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
129 if( p_vout->p_sys == NULL )
131 msg_Err( p_vout, "out of memory" );
135 /* Initialisations */
136 p_vout->pf_init = Init;
137 p_vout->pf_end = End;
138 p_vout->pf_manage = Manage;
139 p_vout->pf_render = NULL;
140 p_vout->pf_display = Display;
142 p_vout->p_sys->p_ddobject = NULL;
143 p_vout->p_sys->p_display = NULL;
144 p_vout->p_sys->p_current_surface = NULL;
145 p_vout->p_sys->p_clipper = NULL;
146 p_vout->p_sys->hbrush = NULL;
147 p_vout->p_sys->hwnd = NULL;
148 p_vout->p_sys->i_changes = 0;
149 p_vout->p_sys->b_caps_overlay_clipping = 0;
150 SetRectEmpty( &p_vout->p_sys->rect_display );
151 p_vout->p_sys->b_using_overlay = config_GetInt( p_vout, "overlay" );
152 p_vout->p_sys->b_use_sysmem = config_GetInt( p_vout, "directx-use-sysmem");
153 p_vout->p_sys->b_hw_yuv = config_GetInt( p_vout, "directx-hw-yuv" );
155 p_vout->p_sys->b_cursor_hidden = 0;
156 p_vout->p_sys->i_lastmoved = mdate();
158 /* Set main window's size */
159 p_vout->p_sys->i_window_width = p_vout->i_window_width;
160 p_vout->p_sys->i_window_height = p_vout->i_window_height;
162 /* Create the DirectXEventThread, this thread is created by us to isolate
163 * the Win32 PeekMessage function calls. We want to do this because
164 * Windows can stay blocked inside this call for a long time, and when
165 * this happens it thus blocks vlc's video_output thread.
166 * DirectXEventThread will take care of the creation of the video
167 * window (because PeekMessage has to be called from the same thread which
168 * created the window). */
169 msg_Dbg( p_vout, "creating DirectXEventThread" );
170 p_vout->p_sys->p_event =
171 vlc_object_create( p_vout, sizeof(event_thread_t) );
172 p_vout->p_sys->p_event->p_vout = p_vout;
173 if( vlc_thread_create( p_vout->p_sys->p_event,
174 "DirectX Events Thread", DirectXEventThread,
175 VLC_THREAD_PRIORITY_LOW, 1 ) )
177 msg_Err( p_vout, "cannot create DirectXEventThread" );
178 vlc_object_destroy( p_vout->p_sys->p_event );
179 p_vout->p_sys->p_event = NULL;
183 if( p_vout->p_sys->p_event->b_error )
185 msg_Err( p_vout, "DirectXEventThread failed" );
189 vlc_object_attach( p_vout->p_sys->p_event, p_vout );
191 msg_Dbg( p_vout, "DirectXEventThread running" );
193 /* Initialise DirectDraw */
194 if( DirectXInitDDraw( p_vout ) )
196 msg_Err( p_vout, "cannot initialize DirectDraw" );
200 /* Create the directx display */
201 if( DirectXCreateDisplay( p_vout ) )
203 msg_Err( p_vout, "cannot initialize DirectDraw" );
210 CloseVideo( VLC_OBJECT(p_vout) );
215 /*****************************************************************************
216 * Init: initialize DirectX video thread output method
217 *****************************************************************************
218 * This function create the directx surfaces needed by the output thread.
219 * It is called at the beginning of the thread.
220 *****************************************************************************/
221 static int Init( vout_thread_t *p_vout )
225 /* Initialize the output structure.
226 * Since DirectDraw can do rescaling for us, stick to the default
227 * coordinates and aspect. */
228 p_vout->output.i_width = p_vout->render.i_width;
229 p_vout->output.i_height = p_vout->render.i_height;
230 p_vout->output.i_aspect = p_vout->render.i_aspect;
232 #define MAX_DIRECTBUFFERS 1
233 /* Right now we use only 1 directbuffer because we don't want the
234 * video decoder to decode directly into direct buffers as they are
235 * created into video memory and video memory is _really_ slow */
237 /* Choose the chroma we will try first. */
238 switch( p_vout->render.i_chroma )
240 case VLC_FOURCC('Y','U','Y','2'):
241 case VLC_FOURCC('Y','U','N','V'):
242 p_vout->output.i_chroma = VLC_FOURCC('Y','U','Y','2');
244 case VLC_FOURCC('U','Y','V','Y'):
245 case VLC_FOURCC('U','Y','N','V'):
246 case VLC_FOURCC('Y','4','2','2'):
247 p_vout->output.i_chroma = VLC_FOURCC('U','Y','V','Y');
249 case VLC_FOURCC('Y','V','Y','U'):
250 p_vout->output.i_chroma = VLC_FOURCC('Y','V','Y','U');
253 p_vout->output.i_chroma = VLC_FOURCC('Y','V','1','2');
257 NewPictureVec( p_vout, p_vout->p_picture, MAX_DIRECTBUFFERS );
259 i_chroma_backup = p_vout->output.i_chroma;
261 if( !I_OUTPUTPICTURES )
263 /* hmmm, it didn't work! Let's try commonly supported chromas */
264 p_vout->output.i_chroma = VLC_FOURCC('Y','V','1','2');
265 NewPictureVec( p_vout, p_vout->p_picture, MAX_DIRECTBUFFERS );
266 if( !I_OUTPUTPICTURES )
268 /* hmmm, it didn't work! Let's try commonly supported chromas */
269 p_vout->output.i_chroma = VLC_FOURCC('Y','U','Y','2');
270 NewPictureVec( p_vout, p_vout->p_picture, MAX_DIRECTBUFFERS );
274 if( !I_OUTPUTPICTURES )
276 /* If it still didn't work then don't try to use an overlay */
277 p_vout->output.i_chroma = i_chroma_backup;
278 p_vout->p_sys->b_using_overlay = 0;
279 NewPictureVec( p_vout, p_vout->p_picture, MAX_DIRECTBUFFERS );
282 /* Change the window title bar text */
283 if( p_vout->p_sys->b_using_overlay )
284 SetWindowText( p_vout->p_sys->hwnd,
285 VOUT_TITLE " (hardware YUV overlay DirectX output)" );
286 else if( p_vout->p_sys->b_hw_yuv )
287 SetWindowText( p_vout->p_sys->hwnd,
288 VOUT_TITLE " (hardware YUV DirectX output)" );
289 else SetWindowText( p_vout->p_sys->hwnd,
290 VOUT_TITLE " (software RGB DirectX output)" );
295 /*****************************************************************************
296 * End: terminate Sys video thread output method
297 *****************************************************************************
298 * Terminate an output method created by Create.
299 * It is called at the end of the thread.
300 *****************************************************************************/
301 static void End( vout_thread_t *p_vout )
303 FreePictureVec( p_vout, p_vout->p_picture, I_OUTPUTPICTURES );
307 /*****************************************************************************
308 * CloseVideo: destroy Sys video thread output method
309 *****************************************************************************
310 * Terminate an output method created by Create
311 *****************************************************************************/
312 static void CloseVideo( vlc_object_t *p_this )
314 vout_thread_t * p_vout = (vout_thread_t *)p_this;
316 msg_Dbg( p_vout, "CloseVideo" );
318 DirectXCloseDisplay( p_vout );
319 DirectXCloseDDraw( p_vout );
321 if( p_vout->p_sys->p_event )
323 vlc_object_detach( p_vout->p_sys->p_event );
325 /* Kill DirectXEventThread */
326 p_vout->p_sys->p_event->b_die = 1;
328 /* we need to be sure DirectXEventThread won't stay stuck in
329 * GetMessage, so we send a fake message */
330 if( p_vout->p_sys->hwnd )
331 PostMessage( p_vout->p_sys->hwnd, WM_NULL, 0, 0);
333 vlc_thread_join( p_vout->p_sys->p_event );
334 vlc_object_destroy( p_vout->p_sys->p_event );
339 free( p_vout->p_sys );
340 p_vout->p_sys = NULL;
344 /*****************************************************************************
345 * Manage: handle Sys events
346 *****************************************************************************
347 * This function should be called regularly by the video output thread.
348 * It returns a non null value if an error occured.
349 *****************************************************************************/
350 static int Manage( vout_thread_t *p_vout )
352 WINDOWPLACEMENT window_placement;
354 /* We used to call the Win32 PeekMessage function here to read the window
355 * messages. But since window can stay blocked into this function for a
356 * long time (for example when you move your window on the screen), I
357 * decided to isolate PeekMessage in another thread. */
362 if( p_vout->i_changes & VOUT_SCALE_CHANGE
363 || p_vout->p_sys->i_changes & VOUT_SCALE_CHANGE)
365 msg_Dbg( p_vout, "Scale Change" );
366 if( !p_vout->p_sys->b_using_overlay )
367 InvalidateRect( p_vout->p_sys->hwnd, NULL, TRUE );
369 DirectXUpdateOverlay( p_vout );
370 p_vout->i_changes &= ~VOUT_SCALE_CHANGE;
371 p_vout->p_sys->i_changes &= ~VOUT_SCALE_CHANGE;
377 if( p_vout->i_changes & VOUT_SIZE_CHANGE
378 || p_vout->p_sys->i_changes & VOUT_SIZE_CHANGE )
380 msg_Dbg( p_vout, "Size Change" );
381 if( !p_vout->p_sys->b_using_overlay )
382 InvalidateRect( p_vout->p_sys->hwnd, NULL, TRUE );
384 DirectXUpdateOverlay( p_vout );
385 p_vout->i_changes &= ~VOUT_SIZE_CHANGE;
386 p_vout->p_sys->i_changes &= ~VOUT_SIZE_CHANGE;
392 if( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE
393 || p_vout->p_sys->i_changes & VOUT_FULLSCREEN_CHANGE )
395 p_vout->b_fullscreen = ! p_vout->b_fullscreen;
397 /* We need to switch between Maximized and Normal sized window */
398 window_placement.length = sizeof(WINDOWPLACEMENT);
399 GetWindowPlacement( p_vout->p_sys->hwnd, &window_placement );
400 if( p_vout->b_fullscreen )
402 /* Maximized window */
403 window_placement.showCmd = SW_SHOWMAXIMIZED;
404 /* Change window style, no borders and no title bar */
405 SetWindowLong( p_vout->p_sys->hwnd, GWL_STYLE, 0 );
411 window_placement.showCmd = SW_SHOWNORMAL;
412 /* Change window style, borders and title bar */
413 SetWindowLong( p_vout->p_sys->hwnd, GWL_STYLE,
414 WS_OVERLAPPEDWINDOW | WS_SIZEBOX | WS_VISIBLE );
417 SetWindowPlacement( p_vout->p_sys->hwnd, &window_placement );
419 p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
420 p_vout->p_sys->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
426 if( (!p_vout->p_sys->b_cursor_hidden) &&
427 ( (mdate() - p_vout->p_sys->i_lastmoved) > 5000000 ) )
429 /* Hide the mouse automatically */
430 p_vout->p_sys->b_cursor_hidden = 1;
431 PostMessage( p_vout->p_sys->hwnd, WM_VLC_HIDE_MOUSE, 0, 0 );
434 /* Check if the event thread is still running */
435 if( p_vout->p_sys->p_event->b_die )
441 /*****************************************************************************
442 * Display: displays previously rendered output
443 *****************************************************************************
444 * This function sends the currently rendered image to the display, wait until
445 * it is displayed and switch the two rendering buffers, preparing next frame.
446 *****************************************************************************/
447 static void Display( vout_thread_t *p_vout, picture_t *p_pic )
451 if( (p_vout->p_sys->p_display == NULL) )
453 msg_Warn( p_vout, "no display!!" );
457 if( !p_vout->p_sys->b_using_overlay )
461 /* We ask for the "NOTEARING" option */
462 memset( &ddbltfx, 0, sizeof(DDBLTFX) );
463 ddbltfx.dwSize = sizeof(DDBLTFX);
464 ddbltfx.dwDDFX = DDBLTFX_NOTEARING;
466 /* Blit video surface to display */
467 dxresult = IDirectDrawSurface2_Blt(p_vout->p_sys->p_display,
468 &p_vout->p_sys->rect_dest_clipped,
469 p_pic->p_sys->p_surface,
470 &p_vout->p_sys->rect_src_clipped,
471 DDBLT_ASYNC, &ddbltfx );
472 if ( dxresult == DDERR_SURFACELOST )
474 /* Our surface can be lost so be sure
475 * to check this and restore it if needed */
476 IDirectDrawSurface2_Restore( p_vout->p_sys->p_display );
478 /* Now that the surface has been restored try to display again */
479 dxresult = IDirectDrawSurface2_Blt(p_vout->p_sys->p_display,
480 &p_vout->p_sys->rect_dest_clipped,
481 p_pic->p_sys->p_surface,
482 &p_vout->p_sys->rect_src_clipped,
483 DDBLT_ASYNC, &ddbltfx );
486 if( dxresult != DD_OK )
488 msg_Warn( p_vout, "could not Blit the surface" );
493 else /* using overlay */
496 /* Flip the overlay buffers if we are using back buffers */
497 if( p_pic->p_sys->p_front_surface == p_pic->p_sys->p_surface )
500 dxresult = IDirectDrawSurface2_Flip( p_pic->p_sys->p_front_surface,
502 if ( dxresult == DDERR_SURFACELOST )
504 /* Our surface can be lost so be sure
505 * to check this and restore it if needed */
506 IDirectDrawSurface2_Restore( p_vout->p_sys->p_display );
507 IDirectDrawSurface2_Restore( p_pic->p_sys->p_front_surface );
509 /* Now that the surface has been restored try to display again */
510 dxresult = IDirectDrawSurface2_Flip( p_pic->p_sys->p_front_surface,
512 DirectXUpdateOverlay( p_vout );
515 if( dxresult != DD_OK )
516 msg_Warn( p_vout, "could not flip overlay surface" );
518 if( !DirectXGetSurfaceDesc( p_pic ) )
521 msg_Err( p_vout, "cannot get surface desc" );
525 if( !UpdatePictureStruct( p_vout, p_pic, p_vout->output.i_chroma ) )
528 msg_Err( p_vout, "invalid pic chroma" );
532 /* set currently displayed pic */
533 p_vout->p_sys->p_current_surface = p_pic->p_sys->p_front_surface;
539 /* following functions are local */
541 /*****************************************************************************
542 * DirectXInitDDraw: Takes care of all the DirectDraw initialisations
543 *****************************************************************************
544 * This function initialise and allocate resources for DirectDraw.
545 *****************************************************************************/
546 static int DirectXInitDDraw( vout_thread_t *p_vout )
549 HRESULT (WINAPI *OurDirectDrawCreate)(GUID *,LPDIRECTDRAW *,IUnknown *);
550 LPDIRECTDRAW p_ddobject;
552 msg_Dbg( p_vout, "DirectXInitDDraw" );
554 /* load direct draw DLL */
555 p_vout->p_sys->hddraw_dll = LoadLibrary("DDRAW.DLL");
556 if( p_vout->p_sys->hddraw_dll == NULL )
558 msg_Warn( p_vout, "DirectXInitDDraw failed loading ddraw.dll" );
562 OurDirectDrawCreate =
563 (void *)GetProcAddress(p_vout->p_sys->hddraw_dll, "DirectDrawCreate");
564 if ( OurDirectDrawCreate == NULL )
566 msg_Err( p_vout, "DirectXInitDDraw failed GetProcAddress" );
570 /* Initialize DirectDraw now */
571 dxresult = OurDirectDrawCreate( NULL, &p_ddobject, NULL );
572 if( dxresult != DD_OK )
574 msg_Err( p_vout, "DirectXInitDDraw cannot initialize DDraw" );
578 /* Get the IDirectDraw2 interface */
579 dxresult = IDirectDraw_QueryInterface( p_ddobject, &IID_IDirectDraw2,
580 (LPVOID *)&p_vout->p_sys->p_ddobject );
581 /* Release the unused interface */
582 IDirectDraw_Release( p_ddobject );
583 if( dxresult != DD_OK )
585 msg_Err( p_vout, "cannot get IDirectDraw2 interface" );
589 /* Set DirectDraw Cooperative level, ie what control we want over Windows
591 dxresult = IDirectDraw2_SetCooperativeLevel( p_vout->p_sys->p_ddobject,
592 p_vout->p_sys->hwnd, DDSCL_NORMAL );
593 if( dxresult != DD_OK )
595 msg_Err( p_vout, "cannot set direct draw cooperative level" );
599 /* Probe the capabilities of the hardware */
600 DirectXGetDDrawCaps( p_vout );
602 msg_Dbg( p_vout, "End DirectXInitDDraw" );
606 if( p_vout->p_sys->p_ddobject )
607 IDirectDraw2_Release( p_vout->p_sys->p_ddobject );
608 if( p_vout->p_sys->hddraw_dll )
609 FreeLibrary( p_vout->p_sys->hddraw_dll );
610 p_vout->p_sys->hddraw_dll = NULL;
611 p_vout->p_sys->p_ddobject = NULL;
615 /*****************************************************************************
616 * DirectXCreateDisplay: create the DirectDraw display.
617 *****************************************************************************
618 * Create and initialize display according to preferences specified in the vout
620 *****************************************************************************/
621 static int DirectXCreateDisplay( vout_thread_t *p_vout )
625 LPDIRECTDRAWSURFACE p_display;
626 DDPIXELFORMAT pixel_format;
628 msg_Dbg( p_vout, "DirectXCreateDisplay" );
630 /* Now get the primary surface. This surface is what you actually see
632 memset( &ddsd, 0, sizeof( DDSURFACEDESC ));
633 ddsd.dwSize = sizeof(DDSURFACEDESC);
634 ddsd.dwFlags = DDSD_CAPS;
635 ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
637 dxresult = IDirectDraw2_CreateSurface( p_vout->p_sys->p_ddobject,
640 if( dxresult != DD_OK )
642 msg_Err( p_vout, "cannot get direct draw primary surface" );
646 dxresult = IDirectDrawSurface_QueryInterface( p_display,
647 &IID_IDirectDrawSurface2,
648 (LPVOID *)&p_vout->p_sys->p_display );
649 /* Release the old interface */
650 IDirectDrawSurface_Release( p_display );
651 if ( dxresult != DD_OK )
653 msg_Err( p_vout, "cannot get IDirectDrawSurface2 interface" );
657 /* The clipper will be used only in non-overlay mode */
658 DirectXCreateClipper( p_vout );
662 /* compute the colorkey pixel value from the RGB value we've got */
663 memset( &pixel_format, 0, sizeof( DDPIXELFORMAT ));
664 pixel_format.dwSize = sizeof( DDPIXELFORMAT );
665 dxresult = IDirectDrawSurface2_GetPixelFormat( p_vout->p_sys->p_display,
667 if( dxresult != DD_OK )
668 msg_Warn( p_vout, "DirectXUpdateOverlay GetPixelFormat failed" );
669 p_vout->p_sys->i_colorkey = (DWORD)((( p_vout->p_sys->i_rgb_colorkey
670 * pixel_format.dwRBitMask) / 255)
671 & pixel_format.dwRBitMask);
678 /*****************************************************************************
679 * DirectXCreateClipper: Create a clipper that will be used when blitting the
680 * RGB surface to the main display.
681 *****************************************************************************
682 * This clipper prevents us to modify by mistake anything on the screen
683 * which doesn't belong to our window. For example when a part of our video
684 * window is hidden by another window.
685 *****************************************************************************/
686 static int DirectXCreateClipper( vout_thread_t *p_vout )
690 msg_Dbg( p_vout, "DirectXCreateClipper" );
692 /* Create the clipper */
693 dxresult = IDirectDraw2_CreateClipper( p_vout->p_sys->p_ddobject, 0,
694 &p_vout->p_sys->p_clipper, NULL );
695 if( dxresult != DD_OK )
697 msg_Warn( p_vout, "DirectXCreateClipper cannot create clipper" );
701 /* associate the clipper to the window */
702 dxresult = IDirectDrawClipper_SetHWnd(p_vout->p_sys->p_clipper, 0,
703 p_vout->p_sys->hwnd);
704 if( dxresult != DD_OK )
707 "DirectXCreateClipper cannot attach clipper to window" );
711 /* associate the clipper with the surface */
712 dxresult = IDirectDrawSurface_SetClipper(p_vout->p_sys->p_display,
713 p_vout->p_sys->p_clipper);
714 if( dxresult != DD_OK )
717 "DirectXCreateClipper cannot attach clipper to surface" );
724 if( p_vout->p_sys->p_clipper )
725 IDirectDrawClipper_Release( p_vout->p_sys->p_clipper );
726 p_vout->p_sys->p_clipper = NULL;
731 /*****************************************************************************
732 * DirectXCreateSurface: create an YUV overlay or RGB surface for the video.
733 *****************************************************************************
734 * The best method of display is with an YUV overlay because the YUV->RGB
735 * conversion is done in hardware.
736 * You can also create a plain RGB surface.
737 * ( Maybe we could also try an RGB overlay surface, which could have hardware
738 * scaling and which would also be faster in window mode because you don't
739 * need to do any blitting to the main display...)
740 *****************************************************************************/
741 static int DirectXCreateSurface( vout_thread_t *p_vout,
742 LPDIRECTDRAWSURFACE2 *pp_surface_final,
743 int i_chroma, int b_overlay,
747 LPDIRECTDRAWSURFACE p_surface;
750 /* Create the video surface */
753 /* Now try to create the YUV overlay surface.
754 * This overlay will be displayed on top of the primary surface.
755 * A color key is used to determine whether or not the overlay will be
756 * displayed, ie the overlay will be displayed in place of the primary
757 * surface wherever the primary surface will have this color.
758 * The video window has been created with a background of this color so
759 * the overlay will be only displayed on top of this window */
761 memset( &ddsd, 0, sizeof( DDSURFACEDESC ));
762 ddsd.dwSize = sizeof(DDSURFACEDESC);
763 ddsd.ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT);
764 ddsd.ddpfPixelFormat.dwFlags = DDPF_FOURCC;
765 ddsd.ddpfPixelFormat.dwFourCC = i_chroma;
766 ddsd.dwFlags = DDSD_CAPS |
770 ddsd.dwFlags |= (i_backbuffers ? DDSD_BACKBUFFERCOUNT : 0);
771 ddsd.ddsCaps.dwCaps = DDSCAPS_OVERLAY |
773 ddsd.ddsCaps.dwCaps |= (i_backbuffers ? DDSCAPS_COMPLEX | DDSCAPS_FLIP
775 ddsd.dwHeight = p_vout->render.i_height;
776 ddsd.dwWidth = p_vout->render.i_width;
777 ddsd.dwBackBufferCount = i_backbuffers;
779 dxresult = IDirectDraw2_CreateSurface( p_vout->p_sys->p_ddobject,
782 if( dxresult != DD_OK )
784 *pp_surface_final = NULL;
791 vlc_bool_t b_rgb_surface =
792 ( i_chroma == VLC_FOURCC('R','G','B','2') )
793 || ( i_chroma == VLC_FOURCC('R','V','1','5') )
794 || ( i_chroma == VLC_FOURCC('R','V','1','6') )
795 || ( i_chroma == VLC_FOURCC('R','V','2','4') )
796 || ( i_chroma == VLC_FOURCC('R','V','3','2') );
798 memset( &ddsd, 0, sizeof( DDSURFACEDESC ) );
799 ddsd.dwSize = sizeof(DDSURFACEDESC);
800 ddsd.ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT);
801 ddsd.dwFlags = DDSD_HEIGHT |
804 ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
805 ddsd.dwHeight = p_vout->render.i_height;
806 ddsd.dwWidth = p_vout->render.i_width;
808 if( p_vout->p_sys->b_use_sysmem )
809 ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
811 ddsd.ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY;
815 ddsd.dwFlags |= DDSD_PIXELFORMAT;
816 ddsd.ddpfPixelFormat.dwFlags = DDPF_FOURCC;
817 ddsd.ddpfPixelFormat.dwFourCC = i_chroma;
820 dxresult = IDirectDraw2_CreateSurface( p_vout->p_sys->p_ddobject,
823 if( dxresult != DD_OK )
825 *pp_surface_final = NULL;
830 /* Now that the surface is created, try to get a newer DirectX interface */
831 dxresult = IDirectDrawSurface_QueryInterface( p_surface,
832 &IID_IDirectDrawSurface2,
833 (LPVOID *)pp_surface_final );
834 IDirectDrawSurface_Release( p_surface ); /* Release the old interface */
835 if ( dxresult != DD_OK )
837 msg_Err( p_vout, "cannot get IDirectDrawSurface2 interface" );
838 *pp_surface_final = NULL;
845 /*****************************************************************************
846 * DirectXUpdateOverlay: Move or resize overlay surface on video display.
847 *****************************************************************************
848 * This function is used to move or resize an overlay surface on the screen.
849 * Ususally the overlay is moved by the user and thus, by a move or resize
851 *****************************************************************************/
852 void DirectXUpdateOverlay( vout_thread_t *p_vout )
858 if( p_vout->p_sys->p_current_surface == NULL ||
859 !p_vout->p_sys->b_using_overlay )
862 /* The new window dimensions should already have been computed by the
863 * caller of this function */
865 /* Position and show the overlay */
866 memset(&ddofx, 0, sizeof(DDOVERLAYFX));
867 ddofx.dwSize = sizeof(DDOVERLAYFX);
868 ddofx.dckDestColorkey.dwColorSpaceLowValue = p_vout->p_sys->i_colorkey;
869 ddofx.dckDestColorkey.dwColorSpaceHighValue = p_vout->p_sys->i_colorkey;
871 dwFlags = DDOVER_SHOW;
872 if( !p_vout->p_sys->b_caps_overlay_clipping )
873 dwFlags |= DDOVER_KEYDESTOVERRIDE;
875 dxresult = IDirectDrawSurface2_UpdateOverlay(
876 p_vout->p_sys->p_current_surface,
877 &p_vout->p_sys->rect_src_clipped,
878 p_vout->p_sys->p_display,
879 &p_vout->p_sys->rect_dest_clipped,
882 if(dxresult != DD_OK)
885 "DirectXUpdateOverlay cannot move or resize overlay" );
890 /*****************************************************************************
891 * DirectXCloseDDraw: Release the DDraw object allocated by DirectXInitDDraw
892 *****************************************************************************
893 * This function returns all resources allocated by DirectXInitDDraw.
894 *****************************************************************************/
895 static void DirectXCloseDDraw( vout_thread_t *p_vout )
897 msg_Dbg( p_vout, "DirectXCloseDDraw" );
898 if( p_vout->p_sys->p_ddobject != NULL )
900 IDirectDraw2_Release(p_vout->p_sys->p_ddobject);
901 p_vout->p_sys->p_ddobject = NULL;
904 if( p_vout->p_sys->hddraw_dll != NULL )
906 FreeLibrary( p_vout->p_sys->hddraw_dll );
907 p_vout->p_sys->hddraw_dll = NULL;
911 /*****************************************************************************
912 * DirectXCloseDisplay: close and reset the DirectX display device
913 *****************************************************************************
914 * This function returns all resources allocated by DirectXCreateDisplay.
915 *****************************************************************************/
916 static void DirectXCloseDisplay( vout_thread_t *p_vout )
918 msg_Dbg( p_vout, "DirectXCloseDisplay" );
920 if( p_vout->p_sys->p_clipper != NULL )
922 msg_Dbg( p_vout, "DirectXCloseDisplay clipper" );
923 IDirectDrawClipper_Release( p_vout->p_sys->p_clipper );
924 p_vout->p_sys->p_clipper = NULL;
927 if( p_vout->p_sys->p_display != NULL )
929 msg_Dbg( p_vout, "DirectXCloseDisplay display" );
930 IDirectDrawSurface2_Release( p_vout->p_sys->p_display );
931 p_vout->p_sys->p_display = NULL;
935 /*****************************************************************************
936 * DirectXCloseSurface: close the YUV overlay or RGB surface.
937 *****************************************************************************
938 * This function returns all resources allocated for the surface.
939 *****************************************************************************/
940 static void DirectXCloseSurface( vout_thread_t *p_vout,
941 LPDIRECTDRAWSURFACE2 p_surface )
943 msg_Dbg( p_vout, "DirectXCloseSurface" );
944 if( p_surface != NULL )
946 IDirectDrawSurface2_Release( p_surface );
950 /*****************************************************************************
951 * NewPictureVec: allocate a vector of identical pictures
952 *****************************************************************************
953 * Returns 0 on success, -1 otherwise
954 *****************************************************************************/
955 static int NewPictureVec( vout_thread_t *p_vout, picture_t *p_pic,
959 vlc_bool_t b_result_ok;
960 LPDIRECTDRAWSURFACE2 p_surface;
962 msg_Dbg( p_vout, "NewPictureVec" );
964 I_OUTPUTPICTURES = 0;
966 /* First we try to use an YUV overlay surface.
967 * The overlay surface that we create won't be used to decode directly
968 * into it because accessing video memory directly is way to slow (remember
969 * that pictures are decoded macroblock per macroblock). Instead the video
970 * will be decoded in picture buffers in system memory which will then be
971 * memcpy() to the overlay surface. */
972 if( p_vout->p_sys->b_using_overlay )
974 /* Triple buffering rocks! it doesn't have any processing overhead
975 * (you don't have to wait for the vsync) and provides for a very nice
976 * video quality (no tearing). */
978 b_result_ok = DirectXCreateSurface( p_vout, &p_surface,
979 p_vout->output.i_chroma,
980 p_vout->p_sys->b_using_overlay,
981 2 /* number of backbuffers */ );
984 /* Try to reduce the number of backbuffers */
985 b_result_ok = DirectXCreateSurface( p_vout, &p_surface,
986 p_vout->output.i_chroma,
987 p_vout->p_sys->b_using_overlay,
988 0 /* number of backbuffers */);
994 picture_sys_t front_pic_sys;
995 front_pic.p_sys = &front_pic_sys;
997 /* Allocate internal structure */
998 p_pic[0].p_sys = malloc( sizeof( picture_sys_t ) );
999 if( p_pic[0].p_sys == NULL )
1001 DirectXCloseSurface( p_vout, p_surface );
1005 /* set front buffer */
1006 p_pic[0].p_sys->p_front_surface = p_surface;
1008 /* Get the back buffer */
1009 memset( &dds_caps, 0, sizeof( DDSCAPS ) );
1010 dds_caps.dwCaps = DDSCAPS_BACKBUFFER;
1011 if( DD_OK != IDirectDrawSurface2_GetAttachedSurface(
1012 p_surface, &dds_caps,
1013 &p_pic[0].p_sys->p_surface ) )
1015 msg_Warn( p_vout, "NewPictureVec could not get back buffer" );
1016 /* front buffer is the same as back buffer */
1017 p_pic[0].p_sys->p_surface = p_surface;
1021 p_vout->p_sys->p_current_surface = front_pic.p_sys->p_surface =
1022 p_pic[0].p_sys->p_front_surface;
1024 /* reset the front buffer memory */
1025 if( DirectXGetSurfaceDesc( &front_pic ) &&
1026 UpdatePictureStruct( p_vout, &front_pic,
1027 p_vout->output.i_chroma ) )
1030 for( i = 0; i < front_pic.i_planes; i++ )
1031 for( j = 0; j < front_pic.p[i].i_lines; j++)
1032 memset( front_pic.p[i].p_pixels + j *
1033 front_pic.p[i].i_pitch, 127,
1034 front_pic.p[i].i_visible_pitch );
1037 DirectXUpdateOverlay( p_vout );
1038 I_OUTPUTPICTURES = 1;
1039 msg_Dbg( p_vout, "DirectX YUV overlay created successfully" );
1043 /* As we can't have an overlay, we'll try to create a plain offscreen
1044 * surface. This surface will reside in video memory because there's a
1045 * better chance then that we'll be able to use some kind of hardware
1046 * acceleration like rescaling, blitting or YUV->RGB conversions.
1047 * We then only need to blit this surface onto the main display when we
1048 * want to display it */
1049 if( !p_vout->p_sys->b_using_overlay )
1052 if( p_vout->p_sys->b_hw_yuv )
1053 b_result_ok = DirectXCreateSurface( p_vout, &p_surface,
1054 p_vout->output.i_chroma,
1055 p_vout->p_sys->b_using_overlay,
1056 0 /* no back buffers */ );
1058 if( !p_vout->p_sys->b_hw_yuv || !b_result_ok )
1060 /* Our last choice is to use a plain RGB surface */
1061 DDPIXELFORMAT ddpfPixelFormat;
1063 ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT);
1064 IDirectDrawSurface2_GetPixelFormat( p_vout->p_sys->p_display,
1067 if( ddpfPixelFormat.dwFlags & DDPF_RGB )
1069 switch( ddpfPixelFormat.dwRGBBitCount )
1071 case 8: /* FIXME: set the palette */
1072 p_vout->output.i_chroma = VLC_FOURCC('R','G','B','2');
1075 p_vout->output.i_chroma = VLC_FOURCC('R','V','1','5');
1078 p_vout->output.i_chroma = VLC_FOURCC('R','V','1','6');
1081 p_vout->output.i_chroma = VLC_FOURCC('R','V','2','4');
1084 p_vout->output.i_chroma = VLC_FOURCC('R','V','3','2');
1087 msg_Err( p_vout, "unknown screen depth" );
1090 p_vout->output.i_rmask = ddpfPixelFormat.dwRBitMask;
1091 p_vout->output.i_gmask = ddpfPixelFormat.dwGBitMask;
1092 p_vout->output.i_bmask = ddpfPixelFormat.dwBBitMask;
1095 p_vout->p_sys->b_hw_yuv = 0;
1097 b_result_ok = DirectXCreateSurface( p_vout, &p_surface,
1098 p_vout->output.i_chroma,
1099 p_vout->p_sys->b_using_overlay,
1100 0 /* no back buffers */ );
1105 /* Allocate internal structure */
1106 p_pic[0].p_sys = malloc( sizeof( picture_sys_t ) );
1107 if( p_pic[0].p_sys == NULL )
1109 DirectXCloseSurface( p_vout, p_surface );
1112 p_pic[0].p_sys->p_surface = p_pic[0].p_sys->p_front_surface
1115 I_OUTPUTPICTURES = 1;
1117 msg_Dbg( p_vout, "DirectX plain surface created successfully" );
1122 /* Now that we've got all our direct-buffers, we can finish filling in the
1123 * picture_t structures */
1124 for( i = 0; i < I_OUTPUTPICTURES; i++ )
1126 p_pic[i].i_status = DESTROYED_PICTURE;
1127 p_pic[i].i_type = DIRECT_PICTURE;
1128 PP_OUTPUTPICTURE[i] = &p_pic[i];
1130 if( !DirectXGetSurfaceDesc( &p_pic[i] ) )
1133 FreePictureVec( p_vout, p_pic, I_OUTPUTPICTURES );
1134 I_OUTPUTPICTURES = 0;
1138 if( !UpdatePictureStruct(p_vout, &p_pic[i], p_vout->output.i_chroma) )
1141 /* Unknown chroma, tell the guy to get lost */
1142 msg_Err( p_vout, "never heard of chroma 0x%.8x (%4.4s)",
1143 p_vout->output.i_chroma, (char*)&p_vout->output.i_chroma );
1144 FreePictureVec( p_vout, p_pic, I_OUTPUTPICTURES );
1145 I_OUTPUTPICTURES = 0;
1150 msg_Dbg( p_vout, "End NewPictureVec");
1154 /*****************************************************************************
1155 * FreePicture: destroy a picture vector allocated with NewPictureVec
1156 *****************************************************************************
1158 *****************************************************************************/
1159 static void FreePictureVec( vout_thread_t *p_vout, picture_t *p_pic,
1164 for( i = 0; i < i_num_pics; i++ )
1166 DirectXCloseSurface( p_vout, p_pic[i].p_sys->p_front_surface );
1168 for( i = 0; i < i_num_pics; i++ )
1170 free( p_pic[i].p_sys );
1175 /*****************************************************************************
1176 * UpdatePictureStruct: updates the internal data in the picture_t structure
1177 *****************************************************************************
1178 * This will setup stuff for use by the video_output thread
1179 *****************************************************************************/
1180 static int UpdatePictureStruct( vout_thread_t *p_vout, picture_t *p_pic,
1184 switch( p_vout->output.i_chroma )
1186 case VLC_FOURCC('R','G','B','2'):
1187 case VLC_FOURCC('R','V','1','5'):
1188 case VLC_FOURCC('R','V','1','6'):
1189 case VLC_FOURCC('R','V','2','4'):
1190 case VLC_FOURCC('R','V','3','2'):
1191 p_pic->p->p_pixels = p_pic->p_sys->ddsd.lpSurface;
1192 p_pic->p->i_lines = p_vout->output.i_height;
1193 p_pic->p->i_pitch = p_pic->p_sys->ddsd.lPitch;
1194 switch( p_vout->output.i_chroma )
1196 case VLC_FOURCC('R','G','B','2'):
1197 p_pic->p->i_pixel_pitch = 1;
1199 case VLC_FOURCC('R','V','1','5'):
1200 case VLC_FOURCC('R','V','1','6'):
1201 p_pic->p->i_pixel_pitch = 2;
1203 case VLC_FOURCC('R','V','2','4'):
1204 case VLC_FOURCC('R','V','3','2'):
1205 p_pic->p->i_pixel_pitch = 4;
1210 p_pic->p->i_visible_pitch = p_vout->output.i_width *
1211 p_pic->p->i_pixel_pitch;
1212 p_pic->i_planes = 1;
1215 case VLC_FOURCC('Y','V','1','2'):
1217 p_pic->Y_PIXELS = p_pic->p_sys->ddsd.lpSurface;
1218 p_pic->p[Y_PLANE].i_lines = p_vout->output.i_height;
1219 p_pic->p[Y_PLANE].i_pitch = p_pic->p_sys->ddsd.lPitch;
1220 p_pic->p[Y_PLANE].i_pixel_pitch = 1;
1221 p_pic->p[Y_PLANE].i_visible_pitch = p_vout->output.i_width *
1222 p_pic->p[Y_PLANE].i_pixel_pitch;
1224 p_pic->V_PIXELS = p_pic->Y_PIXELS
1225 + p_pic->p[Y_PLANE].i_lines * p_pic->p[Y_PLANE].i_pitch;
1226 p_pic->p[V_PLANE].i_lines = p_vout->output.i_height / 2;
1227 p_pic->p[V_PLANE].i_pitch = p_pic->p[Y_PLANE].i_pitch / 2;
1228 p_pic->p[V_PLANE].i_pixel_pitch = 1;
1229 p_pic->p[V_PLANE].i_visible_pitch = p_vout->output.i_width *
1230 p_pic->p[V_PLANE].i_pixel_pitch;
1232 p_pic->U_PIXELS = p_pic->V_PIXELS
1233 + p_pic->p[V_PLANE].i_lines * p_pic->p[V_PLANE].i_pitch;
1234 p_pic->p[U_PLANE].i_lines = p_vout->output.i_height / 2;
1235 p_pic->p[U_PLANE].i_pitch = p_pic->p[Y_PLANE].i_pitch / 2;
1236 p_pic->p[U_PLANE].i_pixel_pitch = 1;
1237 p_pic->p[U_PLANE].i_visible_pitch = p_vout->output.i_width *
1238 p_pic->p[U_PLANE].i_pixel_pitch;
1240 p_pic->i_planes = 3;
1243 case VLC_FOURCC('I','Y','U','V'):
1245 p_pic->Y_PIXELS = p_pic->p_sys->ddsd.lpSurface;
1246 p_pic->p[Y_PLANE].i_lines = p_vout->output.i_height;
1247 p_pic->p[Y_PLANE].i_pitch = p_pic->p_sys->ddsd.lPitch;
1248 p_pic->p[Y_PLANE].i_pixel_pitch = 1;
1249 p_pic->p[Y_PLANE].i_visible_pitch = p_vout->output.i_width *
1250 p_pic->p[Y_PLANE].i_pixel_pitch;
1252 p_pic->U_PIXELS = p_pic->Y_PIXELS
1253 + p_pic->p[Y_PLANE].i_lines * p_pic->p[Y_PLANE].i_pitch;
1254 p_pic->p[U_PLANE].i_lines = p_vout->output.i_height / 2;
1255 p_pic->p[U_PLANE].i_pitch = p_pic->p[Y_PLANE].i_pitch / 2;
1256 p_pic->p[U_PLANE].i_pixel_pitch = 1;
1257 p_pic->p[U_PLANE].i_visible_pitch = p_vout->output.i_width *
1258 p_pic->p[U_PLANE].i_pixel_pitch;
1260 p_pic->V_PIXELS = p_pic->U_PIXELS
1261 + p_pic->p[U_PLANE].i_lines * p_pic->p[U_PLANE].i_pitch;
1262 p_pic->p[V_PLANE].i_lines = p_vout->output.i_height / 2;
1263 p_pic->p[V_PLANE].i_pitch = p_pic->p[Y_PLANE].i_pitch / 2;
1264 p_pic->p[V_PLANE].i_pixel_pitch = 1;
1265 p_pic->p[V_PLANE].i_visible_pitch = p_vout->output.i_width *
1266 p_pic->p[V_PLANE].i_pixel_pitch;
1268 p_pic->i_planes = 3;
1271 case VLC_FOURCC('Y','U','Y','2'):
1273 p_pic->p->p_pixels = p_pic->p_sys->ddsd.lpSurface;
1274 p_pic->p->i_lines = p_vout->output.i_height;
1275 p_pic->p->i_pitch = p_pic->p_sys->ddsd.lPitch;
1276 p_pic->p->i_pixel_pitch = 2;
1277 p_pic->p->i_visible_pitch = p_vout->output.i_width *
1278 p_pic->p->i_pixel_pitch;
1280 p_pic->i_planes = 1;
1292 /*****************************************************************************
1293 * DirectXGetDDrawCaps: Probe the capabilities of the hardware
1294 *****************************************************************************
1295 * It is nice to know which features are supported by the hardware so we can
1296 * find ways to optimize our rendering.
1297 *****************************************************************************/
1298 static void DirectXGetDDrawCaps( vout_thread_t *p_vout )
1303 /* This is just an indication of whether or not we'll support overlay,
1304 * but with this test we don't know if we support YUV overlay */
1305 memset( &ddcaps, 0, sizeof( DDCAPS ));
1306 ddcaps.dwSize = sizeof(DDCAPS);
1307 dxresult = IDirectDraw2_GetCaps( p_vout->p_sys->p_ddobject,
1309 if(dxresult != DD_OK )
1311 msg_Warn( p_vout, "cannot get caps" );
1315 BOOL bHasOverlay, bHasOverlayFourCC, bCanClipOverlay,
1316 bHasColorKey, bCanStretch;
1318 /* Determine if the hardware supports overlay surfaces */
1319 bHasOverlay = ((ddcaps.dwCaps & DDCAPS_OVERLAY) ==
1320 DDCAPS_OVERLAY) ? TRUE : FALSE;
1321 /* Determine if the hardware supports overlay surfaces */
1322 bHasOverlayFourCC = ((ddcaps.dwCaps & DDCAPS_OVERLAYFOURCC) ==
1323 DDCAPS_OVERLAYFOURCC) ? TRUE : FALSE;
1324 /* Determine if the hardware supports overlay surfaces */
1325 bCanClipOverlay = ((ddcaps.dwCaps & DDCAPS_OVERLAYCANTCLIP) ==
1327 /* Determine if the hardware supports colorkeying */
1328 bHasColorKey = ((ddcaps.dwCaps & DDCAPS_COLORKEY) ==
1329 DDCAPS_COLORKEY) ? TRUE : FALSE;
1330 /* Determine if the hardware supports scaling of the overlay surface */
1331 bCanStretch = ((ddcaps.dwCaps & DDCAPS_OVERLAYSTRETCH) ==
1332 DDCAPS_OVERLAYSTRETCH) ? TRUE : FALSE;
1333 msg_Dbg( p_vout, "DirectDraw Capabilities: overlay=%i yuvoverlay=%i "
1334 "can_clip_overlay=%i colorkey=%i stretch=%i",
1335 bHasOverlay, bHasOverlayFourCC, bCanClipOverlay,
1336 bHasColorKey, bCanStretch );
1338 /* Overlay clipping support is interesting for us as it means we can
1339 * get rid of the colorkey alltogether */
1340 p_vout->p_sys->b_caps_overlay_clipping = bCanClipOverlay;
1345 /*****************************************************************************
1346 * DirectXGetSurfaceDesc: Get some more information about the surface
1347 *****************************************************************************
1348 * This function get and stores the surface descriptor which among things
1349 * has the pointer to the picture data.
1350 *****************************************************************************/
1351 static int DirectXGetSurfaceDesc( picture_t *p_pic )
1355 /* Lock the surface to get a valid pointer to the picture buffer */
1356 memset( &p_pic->p_sys->ddsd, 0, sizeof( DDSURFACEDESC ));
1357 p_pic->p_sys->ddsd.dwSize = sizeof(DDSURFACEDESC);
1358 dxresult = IDirectDrawSurface2_Lock( p_pic->p_sys->p_surface,
1359 NULL, &p_pic->p_sys->ddsd,
1360 DDLOCK_NOSYSLOCK | DDLOCK_WAIT,
1362 if ( dxresult == DDERR_SURFACELOST )
1364 /* Your surface can be lost so be sure
1365 * to check this and restore it if needed */
1366 dxresult = IDirectDrawSurface2_Restore( p_pic->p_sys->p_surface );
1367 dxresult = IDirectDrawSurface2_Lock( p_pic->p_sys->p_surface, NULL,
1368 &p_pic->p_sys->ddsd,
1369 DDLOCK_NOSYSLOCK | DDLOCK_WAIT,
1372 if( dxresult != DD_OK )
1374 //X msg_Err( p_vout, "DirectXGetSurfaceDesc cannot lock surface" );
1378 /* Unlock the Surface */
1379 dxresult = IDirectDrawSurface2_Unlock( p_pic->p_sys->p_surface, NULL );