1 /*****************************************************************************
2 * vout_directx.c: Windows DirectX video output display method
3 *****************************************************************************
4 * Copyright (C) 1998, 1999, 2000 VideoLAN
5 * $Id: vout_directx.c,v 1.10 2001/08/05 15:32:46 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 #define MODULE_NAME directx
25 #include "modules_inner.h"
31 * Port this plugin to Video Output IV
34 /*****************************************************************************
37 * This plugin will use YUV overlay if supported, using overlay will result in
38 * the best video quality (hardware interpolation when rescaling the picture)
39 * and the fastest display as it requires less processing.
41 * If YUV overlay is not supported the plugin will use an RGB offscreen video
42 * surface that will be blitted onto the primary surface (display) to
43 * effectively display the picture. this fallback method enables us to display
44 * video in window mode.
45 * Another fallback method (which isn't implemented yet) would be to use the
46 * primary surface as the video buffer. This would allow for better
47 * performance but this is restricted to fullscreen video. In short,
48 * implementing this is not considered high priority.
50 *****************************************************************************/
53 #include <errno.h> /* ENOMEM */
54 #include <stdlib.h> /* free() */
55 #include <string.h> /* strerror() */
60 #if defined( _MSC_VER )
74 #include "video_output.h"
77 #include "interface.h"
81 #include "modules_export.h"
83 #include "vout_directx.h"
85 /*****************************************************************************
87 *****************************************************************************/
88 static int vout_Probe ( probedata_t *p_data );
89 static int vout_Create ( struct vout_thread_s * );
90 static int vout_Init ( struct vout_thread_s * );
91 static void vout_End ( struct vout_thread_s * );
92 static void vout_Destroy ( struct vout_thread_s * );
93 static int vout_Manage ( struct vout_thread_s * );
94 static void vout_Display ( struct vout_thread_s * );
95 static void vout_SetPalette( p_vout_thread_t p_vout, u16 *red, u16 *green,
96 u16 *blue, u16 *transp );
98 static int DirectXInitDDraw ( vout_thread_t *p_vout );
99 static int DirectXCreateDisplay ( vout_thread_t *p_vout );
100 static int DirectXCreateSurface ( vout_thread_t *p_vout );
101 static int DirectXCreateClipper ( vout_thread_t *p_vout );
102 static int DirectXUpdateOverlay ( vout_thread_t *p_vout );
103 static void DirectXCloseDDraw ( vout_thread_t *p_vout );
104 static void DirectXCloseDisplay ( vout_thread_t *p_vout );
105 static void DirectXCloseSurface ( vout_thread_t *p_vout );
106 static void DirectXKeepAspectRatio( vout_thread_t *p_vout, RECT *coordinates );
108 /*****************************************************************************
109 * Functions exported as capabilities. They are declared as static so that
110 * we don't pollute the namespace too much.
111 *****************************************************************************/
112 void _M( vout_getfunctions )( function_list_t * p_function_list )
114 p_function_list->pf_probe = vout_Probe;
115 p_function_list->functions.vout.pf_create = vout_Create;
116 p_function_list->functions.vout.pf_init = vout_Init;
117 p_function_list->functions.vout.pf_end = vout_End;
118 p_function_list->functions.vout.pf_destroy = vout_Destroy;
119 p_function_list->functions.vout.pf_manage = vout_Manage;
120 p_function_list->functions.vout.pf_display = vout_Display;
121 p_function_list->functions.vout.pf_setpalette = vout_SetPalette;
124 /*****************************************************************************
125 * vout_Probe: probe the video driver and return a score
126 *****************************************************************************
127 * This function tries to initialize Windows DirectX and returns a score to
128 * the plugin manager so that it can select the best plugin.
129 *****************************************************************************/
130 static int vout_Probe( probedata_t *p_data )
133 if( TestMethod( VOUT_METHOD_VAR, "directx" ) )
138 /* Check that at least DirectX5 is installed on the computer */
144 /*****************************************************************************
145 * vout_Create: allocate DirectX video thread output method
146 *****************************************************************************
147 * This function allocates and initialize the DirectX vout method.
148 *****************************************************************************/
149 static int vout_Create( vout_thread_t *p_vout )
151 /* Allocate structure */
152 p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
153 if( p_vout->p_sys == NULL )
155 intf_ErrMsg( "vout error: can't create p_sys (%s)", strerror(ENOMEM) );
159 /* Initialisations */
160 p_vout->p_sys->p_ddobject = NULL;
161 p_vout->p_sys->p_display = NULL;
162 p_vout->p_sys->p_surface = NULL;
163 p_vout->p_sys->p_clipper = NULL;
164 p_vout->p_sys->hbrush = NULL;
165 p_vout->p_sys->hwnd = NULL;
166 p_vout->p_sys->i_changes = 0;
167 p_vout->p_sys->b_event_thread_die = 0;
168 p_vout->p_sys->b_display_enabled = 0;
170 p_vout->p_sys->b_cursor = 1; /* TODO should be done with a main_GetInt.. */
172 p_vout->p_sys->b_cursor_autohidden = 0;
173 p_vout->p_sys->i_lastmoved = mdate();
175 p_vout->b_fullscreen = main_GetIntVariable( VOUT_FULLSCREEN_VAR,
176 VOUT_FULLSCREEN_DEFAULT );
178 p_vout->b_need_render = !main_GetIntVariable( VOUT_OVERLAY_VAR,
179 VOUT_OVERLAY_DEFAULT );
181 p_vout->b_need_render = 0; /* default = overlay */
183 p_vout->p_sys->i_window_width = main_GetIntVariable( VOUT_WIDTH_VAR,
184 VOUT_WIDTH_DEFAULT );
185 p_vout->p_sys->i_window_height = main_GetIntVariable( VOUT_HEIGHT_VAR,
186 VOUT_HEIGHT_DEFAULT );
187 /* We don't know yet the dimensions of the video so the best guess is to
188 * pick the same as the window */
189 p_vout->p_sys->i_image_width = p_vout->p_sys->i_window_width;
190 p_vout->p_sys->i_image_height = p_vout->p_sys->i_window_height;
193 /* Set locks and condition variables */
194 vlc_mutex_init( &p_vout->p_sys->event_thread_lock );
195 vlc_cond_init( &p_vout->p_sys->event_thread_wait );
196 p_vout->p_sys->i_event_thread_status = THREAD_CREATE;
198 /* Create the DirectXEventThread, this thread is created by us to isolate
199 * the Win32 PeekMessage function calls. We want to do this because
200 * Windows can stay blocked inside this call for a long time, and when
201 * this happens it thus blocks vlc's video_output thread.
202 * DirectXEventThread will take care of the creation of the video
203 * window (because PeekMessage has to be called from the same thread which
204 * created the window). */
205 intf_WarnMsg( 3, "vout: vout_Create creating DirectXEventThread" );
206 if( vlc_thread_create( &p_vout->p_sys->event_thread_id,
207 "DirectX Events Thread",
208 (void *) DirectXEventThread, (void *) p_vout) )
210 intf_ErrMsg( "vout error: can't create DirectXEventThread" );
211 intf_ErrMsg("vout error: %s", strerror(ENOMEM));
212 free( p_vout->p_sys );
216 /* We need to wait for the actual creation of the thread and window */
217 if( p_vout->p_sys->i_event_thread_status == THREAD_CREATE )
219 vlc_mutex_lock( &p_vout->p_sys->event_thread_lock );
220 vlc_cond_wait ( &p_vout->p_sys->event_thread_wait,
221 &p_vout->p_sys->event_thread_lock );
222 vlc_mutex_unlock( &p_vout->p_sys->event_thread_lock );
224 if( p_vout->p_sys->i_event_thread_status != THREAD_READY )
226 intf_ErrMsg( "vout error: DirectXEventThread failed" );
227 free( p_vout->p_sys );
232 intf_WarnMsg( 3, "vout : vout_Create DirectXEventThread running" );
234 /* Initialise DirectDraw */
235 if( DirectXInitDDraw( p_vout ) )
237 intf_ErrMsg( "vout error: can't initialise DirectDraw" );
239 /* Kill DirectXEventThread */
240 p_vout->p_sys->b_event_thread_die = 1;
241 /* we need to be sure DirectXEventThread won't stay stuck in
242 * GetMessage, so we send a fake message */
243 PostMessage( p_vout->p_sys->hwnd, WM_CHAR, (WPARAM)'^', 0);
244 vlc_thread_join( p_vout->p_sys->event_thread_id );
249 /* Create the directx display */
250 if( DirectXCreateDisplay( p_vout ) )
252 intf_ErrMsg( "vout error: can't initialise DirectDraw" );
253 DirectXCloseDDraw( p_vout );
255 /* Kill DirectXEventThread */
256 p_vout->p_sys->b_event_thread_die = 1;
257 /* we need to be sure DirectXEventThread won't stay stuck in
258 * GetMessage, so we send a fake message */
259 PostMessage( p_vout->p_sys->hwnd, WM_CHAR, (WPARAM)'^', 0);
260 vlc_thread_join( p_vout->p_sys->event_thread_id );
268 /*****************************************************************************
269 * vout_Init: initialize DirectX video thread output method
270 *****************************************************************************
272 *****************************************************************************/
273 static int vout_Init( vout_thread_t *p_vout )
278 /*****************************************************************************
279 * vout_End: terminate Sys video thread output method
280 *****************************************************************************
281 * Terminate an output method created by vout_Create.
282 * It is called at the end of the thread.
283 *****************************************************************************/
284 static void vout_End( vout_thread_t *p_vout )
289 /*****************************************************************************
290 * vout_Destroy: destroy Sys video thread output method
291 *****************************************************************************
292 * Terminate an output method created by vout_Create
293 *****************************************************************************/
294 static void vout_Destroy( vout_thread_t *p_vout )
296 intf_WarnMsg( 3, "vout: vout_Destroy" );
297 DirectXCloseDisplay( p_vout );
298 DirectXCloseDDraw( p_vout );
300 /* Kill DirectXEventThread */
301 p_vout->p_sys->b_event_thread_die = 1;
302 /* we need to be sure DirectXEventThread won't stay stuck in GetMessage,
303 * so we send a fake message */
304 if( p_vout->p_sys->i_event_thread_status == THREAD_READY )
306 PostMessage( p_vout->p_sys->hwnd, WM_CHAR, (WPARAM)'^', 0);
307 vlc_thread_join( p_vout->p_sys->event_thread_id );
310 if( p_vout->p_sys != NULL )
312 free( p_vout->p_sys );
313 p_vout->p_sys = NULL;
317 /*****************************************************************************
318 * vout_Manage: handle Sys events
319 *****************************************************************************
320 * This function should be called regularly by video output thread. It returns
321 * a non null value if an error occured.
322 *****************************************************************************/
323 static int vout_Manage( vout_thread_t *p_vout )
325 WINDOWPLACEMENT window_placement;
326 extern int b_directx_update_overlay;
328 /* We used to call the Win32 PeekMessage function here to read the window
329 * messages. But since window can stay blocked into this function for a
330 * long time (for example when you move your window on the screen), I
331 * decided to isolate PeekMessage in another thread. */
336 if( p_vout->i_changes & VOUT_SCALE_CHANGE
337 || p_vout->p_sys->i_changes & VOUT_SCALE_CHANGE)
339 intf_WarnMsg( 3, "vout: vout_Manage Scale Change" );
340 if( p_vout->b_need_render )
341 InvalidateRect( p_vout->p_sys->hwnd, NULL, TRUE );
342 if( DirectXUpdateOverlay( p_vout ) )
343 /* failed so try again next time */
344 PostMessage( p_vout->p_sys->hwnd, WM_CHAR, (WPARAM)'S', 0);
345 p_vout->i_changes &= ~VOUT_SCALE_CHANGE;
346 p_vout->p_sys->i_changes &= ~VOUT_SCALE_CHANGE;
352 if( p_vout->i_changes & VOUT_SIZE_CHANGE
353 || p_vout->p_sys->i_changes & VOUT_SIZE_CHANGE
354 || b_directx_update_overlay )
356 intf_WarnMsg( 3, "vout: vout_Manage Size Change" );
357 if( DirectXUpdateOverlay( p_vout ) )
358 /* failed so try again next time */
359 PostMessage( p_vout->p_sys->hwnd, WM_APP, 0, 0);
360 p_vout->i_changes &= ~VOUT_SIZE_CHANGE;
361 p_vout->p_sys->i_changes &= ~VOUT_SIZE_CHANGE;
362 b_directx_update_overlay = 0;
368 if( p_vout->i_changes & VOUT_YUV_CHANGE
369 || p_vout->p_sys->i_changes & VOUT_YUV_CHANGE )
371 p_vout->b_need_render = ! p_vout->b_need_render;
373 /* Need to reopen display */
374 DirectXCloseSurface( p_vout );
375 if( DirectXCreateSurface( p_vout ) )
377 intf_ErrMsg( "error: can't reopen display after YUV change" );
381 /* Repaint the window background (needed by the overlay surface) */
382 if( !p_vout->b_need_render )
384 InvalidateRect( p_vout->p_sys->hwnd, NULL, TRUE );
385 p_vout->p_sys->b_display_enabled = 1;
386 if( DirectXUpdateOverlay( p_vout ) )
387 /* failed so try again next time */
388 PostMessage( p_vout->p_sys->hwnd, WM_APP, 0, 0);
390 p_vout->i_changes &= ~VOUT_YUV_CHANGE;
391 p_vout->p_sys->i_changes &= ~VOUT_YUV_CHANGE;
397 if( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE
398 || p_vout->p_sys->i_changes & VOUT_FULLSCREEN_CHANGE )
400 p_vout->b_fullscreen = ! p_vout->b_fullscreen;
402 /* We need to switch between Maximized and Normal sized window */
403 window_placement.length = sizeof(WINDOWPLACEMENT);
404 GetWindowPlacement( p_vout->p_sys->hwnd, &window_placement );
405 if( p_vout->b_fullscreen )
407 /* Maximized window */
408 window_placement.showCmd = SW_SHOWMAXIMIZED;
409 /* Change window style, no borders and no title bar */
410 SetWindowLong( p_vout->p_sys->hwnd, GWL_STYLE, 0 );
416 window_placement.showCmd = SW_SHOWNORMAL;
417 /* Change window style, borders and title bar */
418 SetWindowLong( p_vout->p_sys->hwnd, GWL_STYLE,
419 WS_OVERLAPPEDWINDOW | WS_SIZEBOX | WS_VISIBLE );
422 SetWindowPlacement( p_vout->p_sys->hwnd, &window_placement );
424 p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
425 p_vout->p_sys->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
431 if( ! p_vout->p_sys->b_cursor_autohidden &&
432 ( mdate() - p_vout->p_sys->i_lastmoved > 5000000 ) )
434 /* Hide the mouse automatically */
435 p_vout->p_sys->b_cursor_autohidden = 1;
439 if( p_vout->i_changes & VOUT_CURSOR_CHANGE
440 || p_vout->p_sys->i_changes & VOUT_CURSOR_CHANGE )
442 p_vout->p_sys->b_cursor = ! p_vout->p_sys->b_cursor;
444 ShowCursor( p_vout->p_sys->b_cursor &&
445 ! p_vout->p_sys->b_cursor_autohidden );
447 p_vout->i_changes &= ~VOUT_CURSOR_CHANGE;
448 p_vout->p_sys->i_changes &= ~VOUT_CURSOR_CHANGE;
454 /*****************************************************************************
455 * vout_SetPalette: sets an 8 bpp palette
456 *****************************************************************************
457 * This function sets the palette given as an argument. It does not return
458 * anything, but could later send information on which colors it was unable
460 *****************************************************************************/
461 static void vout_SetPalette( p_vout_thread_t p_vout, u16 *red, u16 *green,
462 u16 *blue, u16 *transp)
468 /*****************************************************************************
469 * vout_Display: displays previously rendered output
470 *****************************************************************************
471 * This function send the currently rendered image to the display, wait until
472 * it is displayed and switch the two rendering buffer, preparing next frame.
473 *****************************************************************************/
474 static void vout_Display( vout_thread_t *p_vout )
483 if( (p_vout->p_sys->p_display == NULL) )
485 intf_WarnMsg( 3, "vout error: vout_Display no display!!" );
489 /* if the size of the decoded pictures has changed then we close the
490 * video surface (which doesn't have the right size anymore). */
491 i_image_width = ( p_vout->p_rendered_pic ) ?
492 p_vout->p_rendered_pic->i_width : p_vout->p_sys->i_image_width;
493 i_image_height = ( p_vout->p_rendered_pic ) ?
494 p_vout->p_rendered_pic->i_height : p_vout->p_sys->i_image_height;
496 if( p_vout->p_sys->i_image_width != i_image_width
497 || p_vout->p_sys->i_image_height != i_image_height )
499 intf_WarnMsg( 3, "vout: video surface size changed" );
500 p_vout->p_sys->i_image_width = i_image_width;
501 p_vout->p_sys->i_image_height = i_image_height;
502 DirectXCloseSurface( p_vout );
505 if( p_vout->b_need_render )
512 if( p_vout->p_sys->p_surface == NULL )
514 intf_WarnMsg( 3, "vout: no video surface, open one..." );
515 if( DirectXCreateSurface( p_vout ) )
517 intf_WarnMsg( 3, "vout: cannot open a new video surface !!" );
520 /* Display the surface */
521 p_vout->p_sys->b_display_enabled = 1;
524 /* Now get the coordinates of the window. We don't actually want the
525 * window coordinates but these of the usable surface inside the window
526 * By specification GetClientRect will always set rect_window.left and
527 * rect_window.top to 0 because the Client area is always relative to
528 * the container window */
529 GetClientRect(p_vout->p_sys->hwnd, &rect_window);
533 ClientToScreen(p_vout->p_sys->hwnd, &point_window);
534 rect_window.left = point_window.x;
535 rect_window.top = point_window.y;
537 point_window.x = rect_window.right;
538 point_window.y = rect_window.bottom;
539 ClientToScreen(p_vout->p_sys->hwnd, &point_window);
540 rect_window.right = point_window.x;
541 rect_window.bottom = point_window.y;
543 /* We want to keep the aspect ratio of the video */
545 if( p_vout->b_scale )
547 DirectXKeepAspectRatio( p_vout, &rect_window );
551 /* We ask for the "NOTEARING" option */
552 memset( &ddbltfx, 0, sizeof(DDBLTFX) );
553 ddbltfx.dwSize = sizeof(DDBLTFX);
554 ddbltfx.dwDDFX = DDBLTFX_NOTEARING;
556 /* Blit video surface to display */
557 dxresult = IDirectDrawSurface3_Blt(p_vout->p_sys->p_display,
559 p_vout->p_sys->p_surface,
562 if( dxresult != DD_OK )
564 intf_WarnMsg( 3, "vout: could not Blit the surface" );
572 * p_vout->p_rendered_pic->p_y/u/v contains the YUV buffers to
575 /* TODO: support for streams other than 4:2:0 */
577 if( p_vout->p_sys->p_surface == NULL )
579 intf_WarnMsg( 3, "vout: no video surface, open one..." );
580 if( DirectXCreateSurface( p_vout ) )
582 intf_WarnMsg( 3, "vout: cannot open a new video surface !!" );
587 /* Lock the overlay surface */
588 memset( &ddsd, 0, sizeof( DDSURFACEDESC ));
589 ddsd.dwSize = sizeof(DDSURFACEDESC);
590 dxresult = IDirectDrawSurface3_Lock(p_vout->p_sys->p_surface, NULL,
591 &ddsd, DDLOCK_NOSYSLOCK, NULL);
592 if ( dxresult == DDERR_SURFACELOST )
594 /* Your surface can be lost (thanks to windows) so be sure
595 * to check this and restore it if needed */
596 dxresult = IDirectDrawSurface3_Restore( p_vout->p_sys->p_surface );
597 dxresult = IDirectDrawSurface3_Lock( p_vout->p_sys->p_surface,
598 NULL, &ddsd, DDLOCK_NOSYSLOCK
599 | DDLOCK_WAIT, NULL);
601 if( dxresult != DD_OK )
603 intf_WarnMsg( 3, "vout: could not lock the surface" );
607 /* Now we can do the actual image copy.
608 * The copy has to be done line by line because of the special case
609 * when the Pitch does not equal the width of the picture */
610 for( i=0; i < ddsd.dwHeight/2; i++)
612 #ifdef NONAMELESSUNION
613 /* copy Y, we copy two lines at once */
614 memcpy(ddsd.lpSurface + i*2*ddsd.u1.lPitch,
615 p_vout->p_rendered_pic->p_y + i*2*i_image_width,
617 memcpy(ddsd.lpSurface + (i*2+1)*ddsd.u1.lPitch,
618 p_vout->p_rendered_pic->p_y + (i*2+1)*i_image_width,
621 memcpy((ddsd.lpSurface + ddsd.dwHeight * ddsd.u1.lPitch)
622 + i * ddsd.u1.lPitch/2,
623 p_vout->p_rendered_pic->p_v + i*i_image_width/2,
626 memcpy((ddsd.lpSurface + ddsd.dwHeight * ddsd.u1.lPitch)
627 + (ddsd.dwHeight * ddsd.u1.lPitch/4)
628 + i * ddsd.u1.lPitch/2,
629 p_vout->p_rendered_pic->p_u + i*i_image_width/2,
632 /* copy Y, we copy two lines at once */
633 memcpy((u8*)ddsd.lpSurface + i*2*ddsd.lPitch,
634 p_vout->p_rendered_pic->p_y + i*2*i_image_width,
636 memcpy((u8*)ddsd.lpSurface + (i*2+1)*ddsd.lPitch,
637 p_vout->p_rendered_pic->p_y + (i*2+1)*i_image_width,
640 memcpy(((u8*)ddsd.lpSurface + ddsd.dwHeight * ddsd.lPitch)
642 p_vout->p_rendered_pic->p_v + i*i_image_width/2,
645 memcpy(((u8*)ddsd.lpSurface + ddsd.dwHeight * ddsd.lPitch)
646 + (ddsd.dwHeight * ddsd.lPitch/4)
648 p_vout->p_rendered_pic->p_u + i*i_image_width/2,
650 #endif /* NONAMELESSUNION */
654 /* Unlock the Surface */
655 dxresult = IDirectDrawSurface3_Unlock(p_vout->p_sys->p_surface,
658 /* If display not enabled yet then enable */
659 if( !p_vout->p_sys->b_display_enabled )
661 p_vout->p_sys->b_display_enabled = 1;
662 DirectXUpdateOverlay( p_vout );
667 /* The first time this function is called it enables the display */
668 p_vout->p_sys->b_display_enabled = 1;
673 /* following functions are local */
675 /*****************************************************************************
676 * DirectXInitDDraw: Takes care of all the DirectDraw initialisations
677 *****************************************************************************
678 * This function initialise and allocate resources for DirectDraw.
679 *****************************************************************************/
680 static int DirectXInitDDraw( vout_thread_t *p_vout )
683 HRESULT (WINAPI *OurDirectDrawCreate)(GUID *,LPDIRECTDRAW *,IUnknown *);
684 LPDIRECTDRAW p_ddobject;
686 intf_WarnMsg( 3, "vout: DirectXInitDDraw" );
688 /* load direct draw DLL */
689 p_vout->p_sys->hddraw_dll = LoadLibrary("DDRAW.DLL");
690 if( p_vout->p_sys->hddraw_dll == NULL )
692 intf_WarnMsg( 3, "vout: DirectXInitDDraw failed loading ddraw.dll" );
696 OurDirectDrawCreate =
697 (void *)GetProcAddress(p_vout->p_sys->hddraw_dll, "DirectDrawCreate");
698 if ( OurDirectDrawCreate == NULL )
700 intf_ErrMsg( "vout error: DirectXInitDDraw failed GetProcAddress" );
701 FreeLibrary( p_vout->p_sys->hddraw_dll );
702 p_vout->p_sys->hddraw_dll = NULL;
706 /* Initialize DirectDraw now */
707 dxresult = OurDirectDrawCreate( NULL, &p_ddobject, NULL );
708 if( dxresult != DD_OK )
710 intf_ErrMsg( "vout error: DirectXInitDDraw can't initialize DDraw" );
711 p_vout->p_sys->p_ddobject = NULL;
712 FreeLibrary( p_vout->p_sys->hddraw_dll );
713 p_vout->p_sys->hddraw_dll = NULL;
717 /* Set DirectDraw Cooperative level, ie what control we want over Windows
719 dxresult = IDirectDraw_SetCooperativeLevel( p_ddobject,
720 p_vout->p_sys->hwnd, DDSCL_NORMAL );
721 if( dxresult != DD_OK )
723 intf_ErrMsg( "vout error: can't set direct draw cooperative level." );
724 IDirectDraw_Release( p_ddobject );
725 p_vout->p_sys->p_ddobject = NULL;
726 FreeLibrary( p_vout->p_sys->hddraw_dll );
727 p_vout->p_sys->hddraw_dll = NULL;
731 /* Get the IDirectDraw2 interface */
732 dxresult = IDirectDraw_QueryInterface( p_ddobject, &IID_IDirectDraw2,
733 (LPVOID *)&p_vout->p_sys->p_ddobject );
734 if( dxresult != DD_OK )
736 intf_ErrMsg( "vout error: can't get IDirectDraw2 interface." );
737 IDirectDraw_Release( p_ddobject );
738 p_vout->p_sys->p_ddobject = NULL;
739 FreeLibrary( p_vout->p_sys->hddraw_dll );
740 p_vout->p_sys->hddraw_dll = NULL;
745 /* Release the unused interface */
746 IDirectDraw_Release( p_ddobject );
749 intf_WarnMsg( 3, "vout: End DirectXInitDDraw" );
753 /*****************************************************************************
754 * DirectXCreateDisplay: create the DirectDraw display.
755 *****************************************************************************
756 * Create and initialize display according to preferences specified in the vout
758 *****************************************************************************/
759 static int DirectXCreateDisplay( vout_thread_t *p_vout )
763 LPDIRECTDRAWSURFACE p_display;
764 DDPIXELFORMAT ddpfPixelFormat;
766 intf_WarnMsg( 3, "vout: DirectXCreateDisplay" );
768 /* Now create the primary surface. This surface is what you actually see
770 memset( &ddsd, 0, sizeof( DDSURFACEDESC ));
771 ddsd.dwSize = sizeof(DDSURFACEDESC);
772 ddsd.dwFlags = DDSD_CAPS;
773 ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
775 dxresult = IDirectDraw2_CreateSurface( p_vout->p_sys->p_ddobject,
778 if( dxresult != DD_OK )
780 intf_ErrMsg( "vout error: can't create direct draw primary surface." );
781 p_vout->p_sys->p_display = NULL;
785 dxresult = IDirectDrawSurface_QueryInterface( p_display,
786 &IID_IDirectDrawSurface3,
787 (LPVOID *)&p_vout->p_sys->p_display );
788 if ( dxresult != DD_OK )
790 intf_ErrMsg( "vout error: can't get IDirectDrawSurface3 interface." );
791 IDirectDrawSurface_Release( p_display );
792 p_vout->p_sys->p_display = NULL;
797 /* Release the old interface */
798 IDirectDrawSurface_Release( p_display );
802 /* We need to fill in some information for the video output thread.
803 * We do this here because it must be done before the video_output
804 * thread enters its main loop - and DirectXCreateSurface can be called
806 ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT);
807 IDirectDrawSurface3_GetPixelFormat( p_vout->p_sys->p_display,
809 #ifdef NONAMELESSUNION
810 p_vout->i_screen_depth = ddpfPixelFormat.u1.dwRGBBitCount;
811 p_vout->i_bytes_per_pixel = ddpfPixelFormat.u1.dwRGBBitCount/8;
813 p_vout->i_red_mask = ddpfPixelFormat.u2.dwRBitMask;
814 p_vout->i_green_mask = ddpfPixelFormat.u3.dwGBitMask;
815 p_vout->i_blue_mask = ddpfPixelFormat.u4.dwBBitMask;
817 p_vout->i_screen_depth = ddpfPixelFormat.dwRGBBitCount;
818 p_vout->i_bytes_per_pixel = ddpfPixelFormat.dwRGBBitCount/8;
820 p_vout->i_red_mask = ddpfPixelFormat.dwRBitMask;
821 p_vout->i_green_mask = ddpfPixelFormat.dwGBitMask;
822 p_vout->i_blue_mask = ddpfPixelFormat.dwBBitMask;
823 #endif /* NONAMELESSUNION */
825 /* Create a video surface. This function will try to create an
826 * YUV overlay first and if it can't it will create a simple RGB surface */
827 if( DirectXCreateSurface( p_vout ) )
829 intf_ErrMsg( "vout error: can't create a video surface." );
830 IDirectDrawSurface3_Release( p_vout->p_sys->p_display );
831 p_vout->p_sys->p_display = NULL;
838 /*****************************************************************************
839 * DirectXCreateSurface: create an YUV overlay or RGB surface for the video.
840 *****************************************************************************
841 * The best method of display is with an YUV overlay because the YUV->RGB
842 * conversion is done in hardware, so we'll try to create this surface first.
843 * If we fail, we'll try to create a plain RGB surface.
844 * ( Maybe we could also try an RGB overlay surface, which could have hardware
845 * scaling and which would also be faster in window mode because you don't
846 * need to do any blitting to the main display...)
847 *****************************************************************************/
848 static int DirectXCreateSurface( vout_thread_t *p_vout )
852 LPDIRECTDRAWSURFACE p_surface;
855 intf_WarnMsg( 3, "vout: DirectXCreateSurface" );
857 /* Disable display */
858 p_vout->p_sys->b_display_enabled = 0;
861 /* Probe the capabilities of the hardware */
862 /* This is just an indication of whether or not we'll support overlay,
863 * but with this test we don't know if we support YUV overlay */
864 memset( &ddcaps, 0, sizeof( DDCAPS ));
865 ddcaps.dwSize = sizeof(DDCAPS);
866 dxresult = IDirectDraw2_GetCaps( p_vout->p_sys->p_ddobject,
868 if(dxresult != DD_OK )
870 intf_WarnMsg( 3,"vout error: can't get caps." );
874 BOOL bHasOverlay, bHasColorKey, bCanStretch;
876 /* Determine if the hardware supports overlay surfaces */
877 bHasOverlay = ((ddcaps.dwCaps & DDCAPS_OVERLAY) ==
878 DDCAPS_OVERLAY) ? TRUE : FALSE;
879 /* Determine if the hardware supports colorkeying */
880 bHasColorKey = ((ddcaps.dwCaps & DDCAPS_COLORKEY) ==
881 DDCAPS_COLORKEY) ? TRUE : FALSE;
882 /* Determine if the hardware supports scaling of the overlay surface */
883 bCanStretch = ((ddcaps.dwCaps & DDCAPS_OVERLAYSTRETCH) ==
884 DDCAPS_OVERLAYSTRETCH) ? TRUE : FALSE;
885 intf_WarnMsg( 3, "vout: Dx Caps: overlay=%i colorkey=%i stretch=%i",
886 bHasOverlay, bHasColorKey, bCanStretch );
889 if( !bHasOverlay ) p_vout->b_need_render = 1;
895 /* Create the video surface */
896 if( !p_vout->b_need_render )
898 /* Now try to create the YUV overlay surface.
899 * This overlay will be displayed on top of the primary surface.
900 * A color key is used to determine whether or not the overlay will be
901 * displayed, ie the overlay will be displayed in place of the primary
902 * surface wherever the primary surface will have this color.
903 * The video window has been created with a background of this color so
904 * the overlay will be only displayed on top of this window */
906 memset( &ddsd, 0, sizeof( DDSURFACEDESC ));
907 ddsd.dwSize = sizeof(DDSURFACEDESC);
908 ddsd.ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT);
909 ddsd.ddpfPixelFormat.dwFlags = DDPF_FOURCC;
910 ddsd.ddpfPixelFormat.dwFourCC = mmioFOURCC('Y','V','1','2');
911 #ifdef NONAMELESSUNION
912 ddsd.ddpfPixelFormat.u1.dwYUVBitCount = 16;
914 ddsd.ddpfPixelFormat.dwYUVBitCount = 16;
916 ddsd.dwFlags = DDSD_CAPS |
920 ddsd.ddsCaps.dwCaps = DDSCAPS_OVERLAY | DDSCAPS_VIDEOMEMORY;
921 ddsd.dwHeight = p_vout->p_sys->i_image_height;
922 ddsd.dwWidth = p_vout->p_sys->i_image_width;
923 ddsd.dwBackBufferCount = 1; /* One back buffer */
925 dxresult = IDirectDraw2_CreateSurface( p_vout->p_sys->p_ddobject,
926 &ddsd, &p_surface, NULL );
927 if( dxresult == DD_OK )
929 intf_WarnMsg( 3,"vout: DirectX YUV overlay created successfully" );
933 intf_ErrMsg( "vout error: can't create YUV overlay surface." );
934 p_vout->b_need_render = 1;
938 if( p_vout->b_need_render )
940 /* Now try to create a plain RGB surface. */
941 memset( &ddsd, 0, sizeof( DDSURFACEDESC ));
942 ddsd.dwSize = sizeof(DDSURFACEDESC);
943 ddsd.dwFlags = DDSD_HEIGHT |
946 ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
947 ddsd.dwHeight = p_vout->p_sys->i_image_height;
948 ddsd.dwWidth = p_vout->p_sys->i_image_width;
950 dxresult = IDirectDraw2_CreateSurface( p_vout->p_sys->p_ddobject,
951 &ddsd, &p_surface, NULL );
952 if( dxresult == DD_OK )
954 intf_WarnMsg( 3,"vout: DirectX RGB surface created successfully" );
958 intf_ErrMsg( "vout error: can't create RGB surface." );
959 p_vout->p_sys->p_surface = NULL;
964 /* Now that the surface is created, try to get a newer DirectX interface */
965 dxresult = IDirectDrawSurface_QueryInterface( p_surface,
966 &IID_IDirectDrawSurface3,
967 (LPVOID *)&p_vout->p_sys->p_surface );
968 if ( dxresult != DD_OK )
970 intf_ErrMsg( "vout error: can't get IDirectDrawSurface3 interface." );
971 IDirectDrawSurface_Release( p_surface );
972 p_vout->p_sys->p_surface = NULL;
977 /* Release the old interface */
978 IDirectDrawSurface_Release( p_surface );
981 if( !p_vout->b_need_render )
983 /* Hide the overlay for now */
984 IDirectDrawSurface3_UpdateOverlay(p_vout->p_sys->p_surface,
986 p_vout->p_sys->p_display,
993 DirectXCreateClipper( p_vout );
997 /* From now on, do some initialisation for video_output */
999 /* if we want a valid pointer to the surface memory, we must lock
1002 memset( &ddsd, 0, sizeof( DDSURFACEDESC ));
1003 ddsd.dwSize = sizeof(DDSURFACEDESC);
1004 dxresult = IDirectDrawSurface3_Lock( p_vout->p_sys->p_surface, NULL, &ddsd,
1005 DDLOCK_NOSYSLOCK | DDLOCK_WAIT, NULL);
1006 if ( dxresult == DDERR_SURFACELOST )
1008 /* Your surface can be lost so be sure
1009 * to check this and restore it if needed */
1010 dxresult = IDirectDrawSurface3_Restore( p_vout->p_sys->p_surface );
1011 dxresult = IDirectDrawSurface3_Lock( p_vout->p_sys->p_surface,
1012 NULL, &ddsd, DDLOCK_NOSYSLOCK
1013 | DDLOCK_WAIT, NULL);
1015 if( dxresult != DD_OK )
1017 intf_ErrMsg( "vout: DirectXCreateDisplay could not lock the surface" );
1021 /* Set the pointer to the surface memory */
1022 p_vout->p_sys->p_directx_buf[ 0 ] = ddsd.lpSurface;
1023 /* back buffer, none for now */
1024 p_vout->p_sys->p_directx_buf[ 1 ] = ddsd.lpSurface;
1026 /* Set thread information */
1027 p_vout->i_width = ddsd.dwWidth;
1028 p_vout->i_height = ddsd.dwHeight;
1029 #ifdef NONAMELESSUNION
1030 p_vout->i_bytes_per_line = ddsd.u1.lPitch;
1032 p_vout->i_bytes_per_line = ddsd.lPitch;
1033 #endif /* NONAMELESSUNION */
1036 if( p_vout->b_need_render )
1038 /* For an RGB surface we need to fill in some more info */
1039 #ifdef NONAMELESSUNION
1040 p_vout->i_screen_depth = ddsd.ddpfPixelFormat.u1.dwRGBBitCount;
1041 p_vout->i_bytes_per_pixel = ddsd.ddpfPixelFormat.u1.dwRGBBitCount/8;
1043 p_vout->i_red_mask = ddsd.ddpfPixelFormat.u2.dwRBitMask;
1044 p_vout->i_green_mask = ddsd.ddpfPixelFormat.u3.dwGBitMask;
1045 p_vout->i_blue_mask = ddsd.ddpfPixelFormat.u4.dwBBitMask;
1047 p_vout->i_screen_depth = ddsd.ddpfPixelFormat.dwRGBBitCount;
1048 p_vout->i_bytes_per_pixel = ddsd.ddpfPixelFormat.dwRGBBitCount/8;
1050 p_vout->i_red_mask = ddsd.ddpfPixelFormat.dwRBitMask;
1051 p_vout->i_green_mask = ddsd.ddpfPixelFormat.dwGBitMask;
1052 p_vout->i_blue_mask = ddsd.ddpfPixelFormat.dwBBitMask;
1054 #endif /* NONAMELESSUNION */
1057 /* Unlock the Surface */
1058 dxresult = IDirectDrawSurface3_Unlock(p_vout->p_sys->p_surface,
1061 /* Set and initialize buffers */
1062 p_vout->pf_setbuffers( p_vout, p_vout->p_sys->p_directx_buf[ 0 ],
1063 p_vout->p_sys->p_directx_buf[ 1 ] );
1070 /*****************************************************************************
1071 * DirectXCreateClipper: Create a clipper that will be used when blitting the
1072 * RGB surface to the main display.
1073 *****************************************************************************
1074 * This clipper prevents us to modify by mistake anything on the screen
1075 * which doesn't belong to our window. For example when a part of our video
1076 * window is hidden by another window.
1077 *****************************************************************************/
1078 static int DirectXCreateClipper( vout_thread_t *p_vout )
1082 intf_WarnMsg( 3, "vout: DirectXCreateClipper" );
1084 /* Create the clipper */
1085 dxresult = IDirectDraw2_CreateClipper( p_vout->p_sys->p_ddobject, 0,
1086 &p_vout->p_sys->p_clipper, NULL );
1087 if( dxresult != DD_OK )
1089 intf_WarnMsg( 3, "vout: DirectXCreateClipper can't create clipper." );
1090 IDirectDrawSurface_Release( p_vout->p_sys->p_clipper );
1091 p_vout->p_sys->p_clipper = NULL;
1095 /* associate the clipper to the window */
1096 dxresult = IDirectDrawClipper_SetHWnd(p_vout->p_sys->p_clipper, 0,
1097 p_vout->p_sys->hwnd);
1098 if( dxresult != DD_OK )
1101 "vout: DirectXCreateClipper can't attach clipper to window." );
1102 IDirectDrawSurface_Release( p_vout->p_sys->p_clipper );
1103 p_vout->p_sys->p_clipper = NULL;
1107 /* associate the clipper with the surface */
1108 dxresult = IDirectDrawSurface_SetClipper(p_vout->p_sys->p_display,
1109 p_vout->p_sys->p_clipper);
1110 if( dxresult != DD_OK )
1113 "vout: DirectXCreateClipper can't attach clipper to surface." );
1114 IDirectDrawSurface_Release( p_vout->p_sys->p_clipper );
1115 p_vout->p_sys->p_clipper = NULL;
1123 /*****************************************************************************
1124 * DirectXUpdateOverlay: Move or resize overlay surface on video display.
1125 *****************************************************************************
1126 * This function is used to move or resize an overlay surface on the screen.
1127 * Ususally the overlay is moved by the user and thus, by a move or resize
1128 * event (in vout_Manage).
1129 *****************************************************************************/
1130 static int DirectXUpdateOverlay( vout_thread_t *p_vout )
1133 RECT rect_window, rect_window_backup, rect_image;
1138 DDPIXELFORMAT pixel_format;
1141 if( p_vout->p_sys->p_surface == NULL || p_vout->b_need_render )
1143 intf_WarnMsg( 3, "vout: DirectXUpdateOverlay no overlay !!" );
1147 if( !p_vout->p_rendered_pic )
1149 intf_WarnMsg( 3, "vout: DirectXUpdateOverlay p_rendered_pic=NULL !" );
1153 if( !p_vout->p_sys->b_display_enabled )
1158 /* Now get the coordinates of the window. We don't actually want the
1159 * window coordinates but these of the usable surface inside the window.
1160 * By specification GetClientRect will always set rect_window.left and
1161 * rect_window.top to 0 because the Client area is always relative to the
1162 * container window */
1163 GetClientRect(p_vout->p_sys->hwnd, &rect_window);
1167 ClientToScreen(p_vout->p_sys->hwnd, &point_window);
1168 rect_window.left = point_window.x;
1169 rect_window.top = point_window.y;
1171 point_window.x = rect_window.right;
1172 point_window.y = rect_window.bottom;
1173 ClientToScreen(p_vout->p_sys->hwnd, &point_window);
1174 rect_window.right = point_window.x;
1175 rect_window.bottom = point_window.y;
1178 /* We want to keep the aspect ratio of the video */
1179 if( p_vout->b_scale )
1181 DirectXKeepAspectRatio( p_vout, &rect_window );
1184 /* It seems we can't feed the UpdateOverlay directdraw function with
1185 * negative values so we have to clip the computed rectangles */
1186 memset( &ddsd, 0, sizeof( DDSURFACEDESC ));
1187 ddsd.dwSize = sizeof(DDSURFACEDESC);
1188 ddsd.dwFlags = DDSD_HEIGHT | DDSD_WIDTH;
1189 IDirectDraw2_GetDisplayMode( p_vout->p_sys->p_ddobject, &ddsd );
1191 rect_window_backup = rect_window;
1193 /* Clip the destination window */
1194 rect_window.left = (rect_window.left < 0) ? 0 : rect_window.left;
1195 rect_window.right = (rect_window.right < 0) ? 0 : rect_window.right;
1196 rect_window.top = (rect_window.top < 0) ? 0 : rect_window.top;
1197 rect_window.bottom = (rect_window.bottom < 0) ? 0 : rect_window.bottom;
1199 rect_window.left = (rect_window.left > ddsd.dwWidth) ? ddsd.dwWidth
1201 rect_window.right = (rect_window.right > ddsd.dwWidth) ? ddsd.dwWidth
1202 : rect_window.right;
1203 rect_window.top = (rect_window.top > ddsd.dwHeight) ? ddsd.dwHeight
1205 rect_window.bottom = (rect_window.bottom > ddsd.dwHeight) ? ddsd.dwHeight
1206 : rect_window.bottom;
1208 intf_WarnMsg( 3, "vout: DirectXUpdateOverlay window coords: %i,%i,%i,%i",
1209 rect_window.left, rect_window.top,
1210 rect_window.right, rect_window.bottom);
1212 /* the 2 following lines are to fix a bug when click on Windows desktop */
1213 if( (rect_window.right-rect_window.left)==0 ||
1214 (rect_window.bottom-rect_window.top)==0 ) return 0;
1216 /* Clip the source image */
1217 rect_image.left = ( rect_window.left == rect_window_backup.left ) ? 0
1218 : labs(rect_window_backup.left - rect_window.left) *
1219 p_vout->p_rendered_pic->i_width /
1220 (rect_window_backup.right - rect_window_backup.left);
1221 rect_image.right = ( rect_window.right == rect_window_backup.right ) ?
1222 p_vout->p_rendered_pic->i_width
1223 : p_vout->p_rendered_pic->i_width -
1224 labs(rect_window_backup.right - rect_window.right) *
1225 p_vout->p_rendered_pic->i_width /
1226 (rect_window_backup.right - rect_window_backup.left);
1227 rect_image.top = ( rect_window.top == rect_window_backup.top ) ? 0
1228 : labs(rect_window_backup.top - rect_window.top) *
1229 p_vout->p_rendered_pic->i_height /
1230 (rect_window_backup.bottom - rect_window_backup.top);
1231 rect_image.bottom = ( rect_window.bottom == rect_window_backup.bottom ) ?
1232 p_vout->p_rendered_pic->i_height
1233 : p_vout->p_rendered_pic->i_height -
1234 labs(rect_window_backup.bottom - rect_window.bottom) *
1235 p_vout->p_rendered_pic->i_height /
1236 (rect_window_backup.bottom - rect_window_backup.top);
1238 intf_WarnMsg( 3, "vout: DirectXUpdateOverlay image coords: %i,%i,%i,%i",
1239 rect_image.left, rect_image.top,
1240 rect_image.right, rect_image.bottom);
1242 /* compute the colorkey pixel value from the RGB value we've got */
1243 memset( &pixel_format, 0, sizeof( DDPIXELFORMAT ));
1244 pixel_format.dwSize = sizeof( DDPIXELFORMAT );
1245 dxresult = IDirectDrawSurface3_GetPixelFormat( p_vout->p_sys->p_display,
1247 if( dxresult != DD_OK )
1248 intf_WarnMsg( 3, "vout: DirectXUpdateOverlay GetPixelFormat failed" );
1249 dw_colorkey = (DWORD)p_vout->p_sys->i_colorkey;
1250 #ifdef NONAMELESSUNION
1251 dw_colorkey = (DWORD)((( dw_colorkey * pixel_format.u2.dwRBitMask) / 255)
1252 & pixel_format.u2.dwRBitMask);
1254 dw_colorkey = (DWORD)((( dw_colorkey * pixel_format.dwRBitMask) / 255)
1255 & pixel_format.dwRBitMask);
1258 /* Position and show the overlay */
1259 memset(&ddofx, 0, sizeof(DDOVERLAYFX));
1260 ddofx.dwSize = sizeof(DDOVERLAYFX);
1261 ddofx.dckDestColorkey.dwColorSpaceLowValue = dw_colorkey;
1262 ddofx.dckDestColorkey.dwColorSpaceHighValue = dw_colorkey;
1264 dwFlags = DDOVER_KEYDESTOVERRIDE | DDOVER_SHOW;
1266 dxresult = IDirectDrawSurface3_UpdateOverlay(p_vout->p_sys->p_surface,
1268 p_vout->p_sys->p_display,
1272 if(dxresult != DD_OK)
1275 "vout: DirectXUpdateOverlay can't move or resize overlay" );
1281 /*****************************************************************************
1282 * DirectXCloseDDraw: Release the DDraw object allocated by DirectXInitDDraw
1283 *****************************************************************************
1284 * This function returns all resources allocated by DirectXInitDDraw.
1285 *****************************************************************************/
1286 static void DirectXCloseDDraw( vout_thread_t *p_vout )
1288 intf_WarnMsg(3, "vout: DirectXCloseDDraw" );
1289 if( p_vout->p_sys->p_ddobject != NULL )
1291 IDirectDraw2_Release(p_vout->p_sys->p_ddobject);
1292 p_vout->p_sys->p_ddobject = NULL;
1295 if( p_vout->p_sys->hddraw_dll != NULL )
1297 FreeLibrary( p_vout->p_sys->hddraw_dll );
1298 p_vout->p_sys->hddraw_dll = NULL;
1302 /*****************************************************************************
1303 * DirectXCloseDisplay: close and reset the DirectX display device
1304 *****************************************************************************
1305 * This function returns all resources allocated by DirectXCreateDisplay.
1306 *****************************************************************************/
1307 static void DirectXCloseDisplay( vout_thread_t *p_vout )
1309 intf_WarnMsg( 3, "vout: DirectXCloseDisplay" );
1310 if( p_vout->p_sys->p_display != NULL )
1312 DirectXCloseSurface( p_vout );
1314 intf_WarnMsg( 3, "vout: DirectXCloseDisplay display" );
1315 IDirectDraw2_Release( p_vout->p_sys->p_display );
1316 p_vout->p_sys->p_display = NULL;
1320 /*****************************************************************************
1321 * DirectXCloseSurface: close the YUV overlay or RGB surface.
1322 *****************************************************************************
1323 * This function returns all resources allocated by the surface.
1324 * We also call this function when the decoded picture change its dimensions
1325 * (in that case we close the overlay surface and reopen another with the
1326 * right dimensions).
1327 *****************************************************************************/
1328 static void DirectXCloseSurface( vout_thread_t *p_vout )
1330 intf_WarnMsg( 3, "vout: DirectXCloseSurface" );
1331 if( p_vout->p_sys->p_surface != NULL )
1333 intf_WarnMsg( 3, "vout: DirectXCloseSurface surface" );
1334 IDirectDraw2_Release( p_vout->p_sys->p_surface );
1335 p_vout->p_sys->p_surface = NULL;
1338 if( p_vout->p_sys->p_clipper != NULL )
1340 intf_WarnMsg( 3, "vout: DirectXCloseSurface clipper" );
1341 IDirectDraw2_Release( p_vout->p_sys->p_clipper );
1342 p_vout->p_sys->p_clipper = NULL;
1345 /* Disable any display */
1346 p_vout->p_sys->b_display_enabled = 0;
1349 /*****************************************************************************
1350 * DirectXKeepAspectRatio:
1351 *****************************************************************************
1352 * This function adjusts the coordinates of the video rectangle to keep the
1353 * aspect/ratio of the video.
1354 *****************************************************************************/
1355 static void DirectXKeepAspectRatio( vout_thread_t *p_vout, RECT *rect_window )
1358 if( !p_vout->p_rendered_pic ) return;
1360 switch( p_vout->p_rendered_pic->i_aspect_ratio )
1362 case AR_16_9_PICTURE:
1363 if( ((rect_window->right-rect_window->left)*9)
1364 > ((rect_window->bottom-rect_window->top)*16) )
1367 temp = (rect_window->bottom-rect_window->top)*16/9;
1368 temp = (rect_window->right-rect_window->left) - temp;
1369 rect_window->left += (temp/2);
1370 rect_window->right -= (temp/2);
1375 temp = (rect_window->right-rect_window->left)*9/16;
1376 temp = (rect_window->bottom-rect_window->top) - temp;
1377 rect_window->top += (temp/2);
1378 rect_window->bottom -= (temp/2);
1382 case AR_221_1_PICTURE:
1383 if( ((rect_window->right-rect_window->left)*100)
1384 > ((rect_window->bottom-rect_window->top)*221) )
1387 temp = (rect_window->bottom-rect_window->top)*221/100;
1388 temp = (rect_window->right-rect_window->left) - temp;
1389 rect_window->left += (temp/2);
1390 rect_window->right -= (temp/2);
1395 temp = (rect_window->right-rect_window->left)*100/221;
1396 temp = (rect_window->bottom-rect_window->top) - temp;
1397 rect_window->top += (temp/2);
1398 rect_window->bottom -= (temp/2);
1402 case AR_3_4_PICTURE:
1403 if( ((rect_window->right-rect_window->left)*3)
1404 > ((rect_window->bottom-rect_window->top)*4) )
1407 temp = (rect_window->bottom-rect_window->top)*4/3;
1408 temp = (rect_window->right-rect_window->left) - temp;
1409 rect_window->left += (temp/2);
1410 rect_window->right -= (temp/2);
1415 temp = (rect_window->right-rect_window->left)*3/4;
1416 temp = (rect_window->bottom-rect_window->top) - temp;
1417 rect_window->top += (temp/2);
1418 rect_window->bottom -= (temp/2);
1422 case AR_SQUARE_PICTURE:
1424 if( (rect_window->right-rect_window->left)
1425 > (rect_window->bottom-rect_window->top) )
1428 temp = (rect_window->bottom-rect_window->top);
1429 temp = (rect_window->right-rect_window->left) - temp;
1430 rect_window->left += (temp/2);
1431 rect_window->right -= (temp/2);
1436 temp = (rect_window->right-rect_window->left);
1437 temp = (rect_window->bottom-rect_window->top) - temp;
1438 rect_window->top += (temp/2);
1439 rect_window->bottom -= (temp/2);