1 /*****************************************************************************
2 * vout_directx.c: Windows DirectX video output display method
3 *****************************************************************************
4 * Copyright (C) 2001 VideoLAN
5 * $Id: vout_directx.c,v 1.17 2001/12/30 07:09:54 sam 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 *****************************************************************************/
28 * Port this plugin to Video Output IV
31 /*****************************************************************************
34 * This plugin will use YUV overlay if supported, using overlay will result in
35 * the best video quality (hardware interpolation when rescaling the picture)
36 * and the fastest display as it requires less processing.
38 * If YUV overlay is not supported the plugin will use an RGB offscreen video
39 * surface that will be blitted onto the primary surface (display) to
40 * effectively display the picture. this fallback method enables us to display
41 * video in window mode.
42 * Another fallback method (which isn't implemented yet) would be to use the
43 * primary surface as the video buffer. This would allow for better
44 * performance but this is restricted to fullscreen video. In short,
45 * implementing this is not considered high priority.
47 *****************************************************************************/
48 #include <errno.h> /* ENOMEM */
49 #include <stdlib.h> /* free() */
50 #include <string.h> /* strerror() */
52 #include <videolan/vlc.h>
57 #if defined( _MSC_VER )
66 #include "video_output.h"
68 #include "interface.h"
70 #include "vout_directx.h"
72 /*****************************************************************************
74 *****************************************************************************/
75 static int vout_Probe ( probedata_t *p_data );
76 static int vout_Create ( struct vout_thread_s * );
77 static int vout_Init ( struct vout_thread_s * );
78 static void vout_End ( struct vout_thread_s * );
79 static void vout_Destroy ( struct vout_thread_s * );
80 static int vout_Manage ( struct vout_thread_s * );
81 static void vout_Display ( struct vout_thread_s * );
82 static void vout_SetPalette( p_vout_thread_t p_vout, u16 *red, u16 *green,
83 u16 *blue, u16 *transp );
85 static int DirectXInitDDraw ( vout_thread_t *p_vout );
86 static int DirectXCreateDisplay ( vout_thread_t *p_vout );
87 static int DirectXCreateSurface ( vout_thread_t *p_vout );
88 static int DirectXCreateClipper ( vout_thread_t *p_vout );
89 static int DirectXUpdateOverlay ( vout_thread_t *p_vout );
90 static void DirectXCloseDDraw ( vout_thread_t *p_vout );
91 static void DirectXCloseDisplay ( vout_thread_t *p_vout );
92 static void DirectXCloseSurface ( vout_thread_t *p_vout );
93 static void DirectXKeepAspectRatio( vout_thread_t *p_vout, RECT *coordinates );
95 /*****************************************************************************
96 * Functions exported as capabilities. They are declared as static so that
97 * we don't pollute the namespace too much.
98 *****************************************************************************/
99 void _M( vout_getfunctions )( function_list_t * p_function_list )
101 p_function_list->pf_probe = vout_Probe;
102 p_function_list->functions.vout.pf_create = vout_Create;
103 p_function_list->functions.vout.pf_init = vout_Init;
104 p_function_list->functions.vout.pf_end = vout_End;
105 p_function_list->functions.vout.pf_destroy = vout_Destroy;
106 p_function_list->functions.vout.pf_manage = vout_Manage;
107 p_function_list->functions.vout.pf_display = vout_Display;
108 p_function_list->functions.vout.pf_setpalette = vout_SetPalette;
111 /*****************************************************************************
112 * vout_Probe: probe the video driver and return a score
113 *****************************************************************************
114 * This function tries to initialize Windows DirectX and returns a score to
115 * the plugin manager so that it can select the best plugin.
116 *****************************************************************************/
117 static int vout_Probe( probedata_t *p_data )
120 if( TestMethod( VOUT_METHOD_VAR, "directx" ) )
125 /* Check that at least DirectX5 is installed on the computer */
131 /*****************************************************************************
132 * vout_Create: allocate DirectX video thread output method
133 *****************************************************************************
134 * This function allocates and initialize the DirectX vout method.
135 *****************************************************************************/
136 static int vout_Create( vout_thread_t *p_vout )
138 /* Allocate structure */
139 p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
140 if( p_vout->p_sys == NULL )
142 intf_ErrMsg( "vout error: can't create p_sys (%s)", strerror(ENOMEM) );
146 /* Initialisations */
147 p_vout->p_sys->p_ddobject = NULL;
148 p_vout->p_sys->p_display = NULL;
149 p_vout->p_sys->p_surface = NULL;
150 p_vout->p_sys->p_clipper = NULL;
151 p_vout->p_sys->hbrush = NULL;
152 p_vout->p_sys->hwnd = NULL;
153 p_vout->p_sys->i_changes = 0;
154 p_vout->p_sys->b_event_thread_die = 0;
155 p_vout->p_sys->b_display_enabled = 0;
157 p_vout->p_sys->b_cursor = 1; /* TODO should be done with a main_GetInt.. */
159 p_vout->p_sys->b_cursor_autohidden = 0;
160 p_vout->p_sys->i_lastmoved = mdate();
162 p_vout->b_fullscreen = main_GetIntVariable( VOUT_FULLSCREEN_VAR,
163 VOUT_FULLSCREEN_DEFAULT );
165 p_vout->b_need_render = !main_GetIntVariable( VOUT_OVERLAY_VAR,
166 VOUT_OVERLAY_DEFAULT );
168 p_vout->b_need_render = 0; /* default = overlay */
170 p_vout->p_sys->i_window_width = main_GetIntVariable( VOUT_WIDTH_VAR,
171 VOUT_WIDTH_DEFAULT );
172 p_vout->p_sys->i_window_height = main_GetIntVariable( VOUT_HEIGHT_VAR,
173 VOUT_HEIGHT_DEFAULT );
174 /* We don't know yet the dimensions of the video so the best guess is to
175 * pick the same as the window */
176 p_vout->p_sys->i_image_width = p_vout->p_sys->i_window_width;
177 p_vout->p_sys->i_image_height = p_vout->p_sys->i_window_height;
180 /* Set locks and condition variables */
181 vlc_mutex_init( &p_vout->p_sys->event_thread_lock );
182 vlc_cond_init( &p_vout->p_sys->event_thread_wait );
183 p_vout->p_sys->i_event_thread_status = THREAD_CREATE;
185 /* Create the DirectXEventThread, this thread is created by us to isolate
186 * the Win32 PeekMessage function calls. We want to do this because
187 * Windows can stay blocked inside this call for a long time, and when
188 * this happens it thus blocks vlc's video_output thread.
189 * DirectXEventThread will take care of the creation of the video
190 * window (because PeekMessage has to be called from the same thread which
191 * created the window). */
192 intf_WarnMsg( 3, "vout: vout_Create creating DirectXEventThread" );
193 if( vlc_thread_create( &p_vout->p_sys->event_thread_id,
194 "DirectX Events Thread",
195 (void *) DirectXEventThread, (void *) p_vout) )
197 intf_ErrMsg( "vout error: can't create DirectXEventThread" );
198 intf_ErrMsg("vout error: %s", strerror(ENOMEM));
199 free( p_vout->p_sys );
203 /* We need to wait for the actual creation of the thread and window */
204 if( p_vout->p_sys->i_event_thread_status == THREAD_CREATE )
206 vlc_mutex_lock( &p_vout->p_sys->event_thread_lock );
207 vlc_cond_wait ( &p_vout->p_sys->event_thread_wait,
208 &p_vout->p_sys->event_thread_lock );
209 vlc_mutex_unlock( &p_vout->p_sys->event_thread_lock );
211 if( p_vout->p_sys->i_event_thread_status != THREAD_READY )
213 intf_ErrMsg( "vout error: DirectXEventThread failed" );
214 free( p_vout->p_sys );
219 intf_WarnMsg( 3, "vout : vout_Create DirectXEventThread running" );
221 /* Initialise DirectDraw */
222 if( DirectXInitDDraw( p_vout ) )
224 intf_ErrMsg( "vout error: can't initialise DirectDraw" );
226 /* Kill DirectXEventThread */
227 p_vout->p_sys->b_event_thread_die = 1;
228 /* we need to be sure DirectXEventThread won't stay stuck in
229 * GetMessage, so we send a fake message */
230 PostMessage( p_vout->p_sys->hwnd, WM_CHAR, (WPARAM)'^', 0);
231 vlc_thread_join( p_vout->p_sys->event_thread_id );
236 /* Create the directx display */
237 if( DirectXCreateDisplay( p_vout ) )
239 intf_ErrMsg( "vout error: can't initialise DirectDraw" );
240 DirectXCloseDDraw( p_vout );
242 /* Kill DirectXEventThread */
243 p_vout->p_sys->b_event_thread_die = 1;
244 /* we need to be sure DirectXEventThread won't stay stuck in
245 * GetMessage, so we send a fake message */
246 PostMessage( p_vout->p_sys->hwnd, WM_CHAR, (WPARAM)'^', 0);
247 vlc_thread_join( p_vout->p_sys->event_thread_id );
255 /*****************************************************************************
256 * vout_Init: initialize DirectX video thread output method
257 *****************************************************************************
259 *****************************************************************************/
260 static int vout_Init( vout_thread_t *p_vout )
265 /*****************************************************************************
266 * vout_End: terminate Sys video thread output method
267 *****************************************************************************
268 * Terminate an output method created by vout_Create.
269 * It is called at the end of the thread.
270 *****************************************************************************/
271 static void vout_End( vout_thread_t *p_vout )
276 /*****************************************************************************
277 * vout_Destroy: destroy Sys video thread output method
278 *****************************************************************************
279 * Terminate an output method created by vout_Create
280 *****************************************************************************/
281 static void vout_Destroy( vout_thread_t *p_vout )
283 intf_WarnMsg( 3, "vout: vout_Destroy" );
284 DirectXCloseDisplay( p_vout );
285 DirectXCloseDDraw( p_vout );
287 /* Kill DirectXEventThread */
288 p_vout->p_sys->b_event_thread_die = 1;
289 /* we need to be sure DirectXEventThread won't stay stuck in GetMessage,
290 * so we send a fake message */
291 if( p_vout->p_sys->i_event_thread_status == THREAD_READY )
293 PostMessage( p_vout->p_sys->hwnd, WM_CHAR, (WPARAM)'q', 0);
294 vlc_thread_join( p_vout->p_sys->event_thread_id );
297 if( p_vout->p_sys != NULL )
299 free( p_vout->p_sys );
300 p_vout->p_sys = NULL;
304 /*****************************************************************************
305 * vout_Manage: handle Sys events
306 *****************************************************************************
307 * This function should be called regularly by video output thread. It returns
308 * a non null value if an error occured.
309 *****************************************************************************/
310 static int vout_Manage( vout_thread_t *p_vout )
312 WINDOWPLACEMENT window_placement;
313 extern int b_directx_update_overlay;
315 /* We used to call the Win32 PeekMessage function here to read the window
316 * messages. But since window can stay blocked into this function for a
317 * long time (for example when you move your window on the screen), I
318 * decided to isolate PeekMessage in another thread. */
323 if( p_vout->i_changes & VOUT_SCALE_CHANGE
324 || p_vout->p_sys->i_changes & VOUT_SCALE_CHANGE)
326 intf_WarnMsg( 3, "vout: vout_Manage Scale Change" );
327 if( p_vout->b_need_render )
328 InvalidateRect( p_vout->p_sys->hwnd, NULL, TRUE );
329 if( DirectXUpdateOverlay( p_vout ) )
330 /* failed so try again next time */
331 PostMessage( p_vout->p_sys->hwnd, WM_CHAR, (WPARAM)'S', 0);
332 p_vout->i_changes &= ~VOUT_SCALE_CHANGE;
333 p_vout->p_sys->i_changes &= ~VOUT_SCALE_CHANGE;
339 if( p_vout->i_changes & VOUT_SIZE_CHANGE
340 || p_vout->p_sys->i_changes & VOUT_SIZE_CHANGE
341 || b_directx_update_overlay )
343 intf_WarnMsg( 3, "vout: vout_Manage Size Change" );
344 if( DirectXUpdateOverlay( p_vout ) )
345 /* failed so try again next time */
346 PostMessage( p_vout->p_sys->hwnd, WM_APP, 0, 0);
347 p_vout->i_changes &= ~VOUT_SIZE_CHANGE;
348 p_vout->p_sys->i_changes &= ~VOUT_SIZE_CHANGE;
349 b_directx_update_overlay = 0;
355 if( p_vout->i_changes & VOUT_YUV_CHANGE
356 || p_vout->p_sys->i_changes & VOUT_YUV_CHANGE )
358 p_vout->b_need_render = ! p_vout->b_need_render;
360 /* Need to reopen display */
361 DirectXCloseSurface( p_vout );
362 if( DirectXCreateSurface( p_vout ) )
364 intf_ErrMsg( "error: can't reopen display after YUV change" );
368 /* Repaint the window background (needed by the overlay surface) */
369 if( !p_vout->b_need_render )
371 InvalidateRect( p_vout->p_sys->hwnd, NULL, TRUE );
372 p_vout->p_sys->b_display_enabled = 1;
373 if( DirectXUpdateOverlay( p_vout ) )
374 /* failed so try again next time */
375 PostMessage( p_vout->p_sys->hwnd, WM_APP, 0, 0);
377 p_vout->i_changes &= ~VOUT_YUV_CHANGE;
378 p_vout->p_sys->i_changes &= ~VOUT_YUV_CHANGE;
384 if( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE
385 || p_vout->p_sys->i_changes & VOUT_FULLSCREEN_CHANGE )
387 p_vout->b_fullscreen = ! p_vout->b_fullscreen;
389 /* We need to switch between Maximized and Normal sized window */
390 window_placement.length = sizeof(WINDOWPLACEMENT);
391 GetWindowPlacement( p_vout->p_sys->hwnd, &window_placement );
392 if( p_vout->b_fullscreen )
394 /* Maximized window */
395 window_placement.showCmd = SW_SHOWMAXIMIZED;
396 /* Change window style, no borders and no title bar */
397 SetWindowLong( p_vout->p_sys->hwnd, GWL_STYLE, 0 );
403 window_placement.showCmd = SW_SHOWNORMAL;
404 /* Change window style, borders and title bar */
405 SetWindowLong( p_vout->p_sys->hwnd, GWL_STYLE,
406 WS_OVERLAPPEDWINDOW | WS_SIZEBOX | WS_VISIBLE );
409 SetWindowPlacement( p_vout->p_sys->hwnd, &window_placement );
411 p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
412 p_vout->p_sys->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
418 if( ! p_vout->p_sys->b_cursor_autohidden &&
419 ( mdate() - p_vout->p_sys->i_lastmoved > 5000000 ) )
421 /* Hide the mouse automatically */
422 p_vout->p_sys->b_cursor_autohidden = 1;
426 if( p_vout->i_changes & VOUT_CURSOR_CHANGE
427 || p_vout->p_sys->i_changes & VOUT_CURSOR_CHANGE )
429 p_vout->p_sys->b_cursor = ! p_vout->p_sys->b_cursor;
431 ShowCursor( p_vout->p_sys->b_cursor &&
432 ! p_vout->p_sys->b_cursor_autohidden );
434 p_vout->i_changes &= ~VOUT_CURSOR_CHANGE;
435 p_vout->p_sys->i_changes &= ~VOUT_CURSOR_CHANGE;
441 /*****************************************************************************
442 * vout_SetPalette: sets an 8 bpp palette
443 *****************************************************************************
444 * This function sets the palette given as an argument. It does not return
445 * anything, but could later send information on which colors it was unable
447 *****************************************************************************/
448 static void vout_SetPalette( p_vout_thread_t p_vout, u16 *red, u16 *green,
449 u16 *blue, u16 *transp)
455 /*****************************************************************************
456 * vout_Display: displays previously rendered output
457 *****************************************************************************
458 * This function send the currently rendered image to the display, wait until
459 * it is displayed and switch the two rendering buffer, preparing next frame.
460 *****************************************************************************/
461 static void vout_Display( vout_thread_t *p_vout )
470 if( (p_vout->p_sys->p_display == NULL) )
472 intf_WarnMsg( 3, "vout error: vout_Display no display!!" );
476 /* if the size of the decoded pictures has changed then we close the
477 * video surface (which doesn't have the right size anymore). */
478 i_image_width = ( p_vout->p_rendered_pic ) ?
479 p_vout->p_rendered_pic->i_width : p_vout->p_sys->i_image_width;
480 i_image_height = ( p_vout->p_rendered_pic ) ?
481 p_vout->p_rendered_pic->i_height : p_vout->p_sys->i_image_height;
483 if( p_vout->p_sys->i_image_width != i_image_width
484 || p_vout->p_sys->i_image_height != i_image_height )
486 intf_WarnMsg( 3, "vout: video surface size changed" );
487 p_vout->p_sys->i_image_width = i_image_width;
488 p_vout->p_sys->i_image_height = i_image_height;
489 DirectXCloseSurface( p_vout );
492 if( p_vout->b_need_render )
499 if( p_vout->p_sys->p_surface == NULL )
501 intf_WarnMsg( 3, "vout: no video surface, open one..." );
502 if( DirectXCreateSurface( p_vout ) )
504 intf_WarnMsg( 3, "vout: cannot open a new video surface !!" );
507 /* Display the surface */
508 p_vout->p_sys->b_display_enabled = 1;
511 /* Now get the coordinates of the window. We don't actually want the
512 * window coordinates but these of the usable surface inside the window
513 * By specification GetClientRect will always set rect_window.left and
514 * rect_window.top to 0 because the Client area is always relative to
515 * the container window */
516 GetClientRect(p_vout->p_sys->hwnd, &rect_window);
520 ClientToScreen(p_vout->p_sys->hwnd, &point_window);
521 rect_window.left = point_window.x;
522 rect_window.top = point_window.y;
524 point_window.x = rect_window.right;
525 point_window.y = rect_window.bottom;
526 ClientToScreen(p_vout->p_sys->hwnd, &point_window);
527 rect_window.right = point_window.x;
528 rect_window.bottom = point_window.y;
530 /* We want to keep the aspect ratio of the video */
532 if( p_vout->b_scale )
534 DirectXKeepAspectRatio( p_vout, &rect_window );
538 /* We ask for the "NOTEARING" option */
539 memset( &ddbltfx, 0, sizeof(DDBLTFX) );
540 ddbltfx.dwSize = sizeof(DDBLTFX);
541 ddbltfx.dwDDFX = DDBLTFX_NOTEARING;
543 /* Blit video surface to display */
544 dxresult = IDirectDrawSurface3_Blt(p_vout->p_sys->p_display,
546 p_vout->p_sys->p_surface,
549 if( dxresult != DD_OK )
551 intf_WarnMsg( 3, "vout: could not Blit the surface" );
559 * p_vout->p_rendered_pic->p_y/u/v contains the YUV buffers to
562 /* TODO: support for streams other than 4:2:0 */
564 if( p_vout->p_sys->p_surface == NULL )
566 intf_WarnMsg( 3, "vout: no video surface, open one..." );
567 if( DirectXCreateSurface( p_vout ) )
569 intf_WarnMsg( 3, "vout: cannot open a new video surface !!" );
574 /* Lock the overlay surface */
575 memset( &ddsd, 0, sizeof( DDSURFACEDESC ));
576 ddsd.dwSize = sizeof(DDSURFACEDESC);
577 dxresult = IDirectDrawSurface3_Lock(p_vout->p_sys->p_surface, NULL,
578 &ddsd, DDLOCK_NOSYSLOCK, NULL);
579 if ( dxresult == DDERR_SURFACELOST )
581 /* Your surface can be lost (thanks to windows) so be sure
582 * to check this and restore it if needed */
583 dxresult = IDirectDrawSurface3_Restore( p_vout->p_sys->p_surface );
584 dxresult = IDirectDrawSurface3_Lock( p_vout->p_sys->p_surface,
585 NULL, &ddsd, DDLOCK_NOSYSLOCK
586 | DDLOCK_WAIT, NULL);
588 if( dxresult != DD_OK )
590 intf_WarnMsg( 3, "vout: could not lock the surface" );
594 /* Now we can do the actual image copy.
595 * The copy has to be done line by line because of the special case
596 * when the Pitch does not equal the width of the picture */
597 for( i=0; i < ddsd.dwHeight/2; i++)
599 #ifdef NONAMELESSUNION
600 /* copy Y, we copy two lines at once */
601 memcpy(ddsd.lpSurface + i*2*ddsd.u1.lPitch,
602 p_vout->p_rendered_pic->p_y + i*2*i_image_width,
604 memcpy(ddsd.lpSurface + (i*2+1)*ddsd.u1.lPitch,
605 p_vout->p_rendered_pic->p_y + (i*2+1)*i_image_width,
608 memcpy((ddsd.lpSurface + ddsd.dwHeight * ddsd.u1.lPitch)
609 + i * ddsd.u1.lPitch/2,
610 p_vout->p_rendered_pic->p_v + i*i_image_width/2,
613 memcpy((ddsd.lpSurface + ddsd.dwHeight * ddsd.u1.lPitch)
614 + (ddsd.dwHeight * ddsd.u1.lPitch/4)
615 + i * ddsd.u1.lPitch/2,
616 p_vout->p_rendered_pic->p_u + i*i_image_width/2,
619 /* copy Y, we copy two lines at once */
620 memcpy((u8*)ddsd.lpSurface + i*2*ddsd.lPitch,
621 p_vout->p_rendered_pic->p_y + i*2*i_image_width,
623 memcpy((u8*)ddsd.lpSurface + (i*2+1)*ddsd.lPitch,
624 p_vout->p_rendered_pic->p_y + (i*2+1)*i_image_width,
627 memcpy(((u8*)ddsd.lpSurface + ddsd.dwHeight * ddsd.lPitch)
629 p_vout->p_rendered_pic->p_v + i*i_image_width/2,
632 memcpy(((u8*)ddsd.lpSurface + ddsd.dwHeight * ddsd.lPitch)
633 + (ddsd.dwHeight * ddsd.lPitch/4)
635 p_vout->p_rendered_pic->p_u + i*i_image_width/2,
637 #endif /* NONAMELESSUNION */
641 /* Unlock the Surface */
642 dxresult = IDirectDrawSurface3_Unlock(p_vout->p_sys->p_surface,
645 /* If display not enabled yet then enable */
646 if( !p_vout->p_sys->b_display_enabled )
648 p_vout->p_sys->b_display_enabled = 1;
649 DirectXUpdateOverlay( p_vout );
654 /* The first time this function is called it enables the display */
655 p_vout->p_sys->b_display_enabled = 1;
660 /* following functions are local */
662 /*****************************************************************************
663 * DirectXInitDDraw: Takes care of all the DirectDraw initialisations
664 *****************************************************************************
665 * This function initialise and allocate resources for DirectDraw.
666 *****************************************************************************/
667 static int DirectXInitDDraw( vout_thread_t *p_vout )
670 HRESULT (WINAPI *OurDirectDrawCreate)(GUID *,LPDIRECTDRAW *,IUnknown *);
671 LPDIRECTDRAW p_ddobject;
673 intf_WarnMsg( 3, "vout: DirectXInitDDraw" );
675 /* load direct draw DLL */
676 p_vout->p_sys->hddraw_dll = LoadLibrary("DDRAW.DLL");
677 if( p_vout->p_sys->hddraw_dll == NULL )
679 intf_WarnMsg( 3, "vout: DirectXInitDDraw failed loading ddraw.dll" );
683 OurDirectDrawCreate =
684 (void *)GetProcAddress(p_vout->p_sys->hddraw_dll, "DirectDrawCreate");
685 if ( OurDirectDrawCreate == NULL )
687 intf_ErrMsg( "vout error: DirectXInitDDraw failed GetProcAddress" );
688 FreeLibrary( p_vout->p_sys->hddraw_dll );
689 p_vout->p_sys->hddraw_dll = NULL;
693 /* Initialize DirectDraw now */
694 dxresult = OurDirectDrawCreate( NULL, &p_ddobject, NULL );
695 if( dxresult != DD_OK )
697 intf_ErrMsg( "vout error: DirectXInitDDraw can't initialize DDraw" );
698 p_vout->p_sys->p_ddobject = NULL;
699 FreeLibrary( p_vout->p_sys->hddraw_dll );
700 p_vout->p_sys->hddraw_dll = NULL;
704 /* Set DirectDraw Cooperative level, ie what control we want over Windows
706 dxresult = IDirectDraw_SetCooperativeLevel( p_ddobject,
707 p_vout->p_sys->hwnd, DDSCL_NORMAL );
708 if( dxresult != DD_OK )
710 intf_ErrMsg( "vout error: can't set direct draw cooperative level." );
711 IDirectDraw_Release( p_ddobject );
712 p_vout->p_sys->p_ddobject = NULL;
713 FreeLibrary( p_vout->p_sys->hddraw_dll );
714 p_vout->p_sys->hddraw_dll = NULL;
718 /* Get the IDirectDraw2 interface */
719 dxresult = IDirectDraw_QueryInterface( p_ddobject, &IID_IDirectDraw2,
720 (LPVOID *)&p_vout->p_sys->p_ddobject );
721 if( dxresult != DD_OK )
723 intf_ErrMsg( "vout error: can't get IDirectDraw2 interface." );
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;
732 /* Release the unused interface */
733 IDirectDraw_Release( p_ddobject );
736 intf_WarnMsg( 3, "vout: End DirectXInitDDraw" );
740 /*****************************************************************************
741 * DirectXCreateDisplay: create the DirectDraw display.
742 *****************************************************************************
743 * Create and initialize display according to preferences specified in the vout
745 *****************************************************************************/
746 static int DirectXCreateDisplay( vout_thread_t *p_vout )
750 LPDIRECTDRAWSURFACE p_display;
751 DDPIXELFORMAT ddpfPixelFormat;
753 intf_WarnMsg( 3, "vout: DirectXCreateDisplay" );
755 /* Now create the primary surface. This surface is what you actually see
757 memset( &ddsd, 0, sizeof( DDSURFACEDESC ));
758 ddsd.dwSize = sizeof(DDSURFACEDESC);
759 ddsd.dwFlags = DDSD_CAPS;
760 ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
762 dxresult = IDirectDraw2_CreateSurface( p_vout->p_sys->p_ddobject,
765 if( dxresult != DD_OK )
767 intf_ErrMsg( "vout error: can't create direct draw primary surface." );
768 p_vout->p_sys->p_display = NULL;
772 dxresult = IDirectDrawSurface_QueryInterface( p_display,
773 &IID_IDirectDrawSurface3,
774 (LPVOID *)&p_vout->p_sys->p_display );
775 if ( dxresult != DD_OK )
777 intf_ErrMsg( "vout error: can't get IDirectDrawSurface3 interface." );
778 IDirectDrawSurface_Release( p_display );
779 p_vout->p_sys->p_display = NULL;
784 /* Release the old interface */
785 IDirectDrawSurface_Release( p_display );
789 /* We need to fill in some information for the video output thread.
790 * We do this here because it must be done before the video_output
791 * thread enters its main loop - and DirectXCreateSurface can be called
793 ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT);
794 IDirectDrawSurface3_GetPixelFormat( p_vout->p_sys->p_display,
796 #ifdef NONAMELESSUNION
797 p_vout->i_screen_depth = ddpfPixelFormat.u1.dwRGBBitCount;
798 p_vout->i_bytes_per_pixel = ddpfPixelFormat.u1.dwRGBBitCount/8;
800 p_vout->i_red_mask = ddpfPixelFormat.u2.dwRBitMask;
801 p_vout->i_green_mask = ddpfPixelFormat.u3.dwGBitMask;
802 p_vout->i_blue_mask = ddpfPixelFormat.u4.dwBBitMask;
804 p_vout->i_screen_depth = ddpfPixelFormat.dwRGBBitCount;
805 p_vout->i_bytes_per_pixel = ddpfPixelFormat.dwRGBBitCount/8;
807 p_vout->i_red_mask = ddpfPixelFormat.dwRBitMask;
808 p_vout->i_green_mask = ddpfPixelFormat.dwGBitMask;
809 p_vout->i_blue_mask = ddpfPixelFormat.dwBBitMask;
810 #endif /* NONAMELESSUNION */
812 /* Create a video surface. This function will try to create an
813 * YUV overlay first and if it can't it will create a simple RGB surface */
814 if( DirectXCreateSurface( p_vout ) )
816 intf_ErrMsg( "vout error: can't create a video surface." );
817 IDirectDrawSurface3_Release( p_vout->p_sys->p_display );
818 p_vout->p_sys->p_display = NULL;
825 /*****************************************************************************
826 * DirectXCreateSurface: create an YUV overlay or RGB surface for the video.
827 *****************************************************************************
828 * The best method of display is with an YUV overlay because the YUV->RGB
829 * conversion is done in hardware, so we'll try to create this surface first.
830 * If we fail, we'll try to create a plain RGB surface.
831 * ( Maybe we could also try an RGB overlay surface, which could have hardware
832 * scaling and which would also be faster in window mode because you don't
833 * need to do any blitting to the main display...)
834 *****************************************************************************/
835 static int DirectXCreateSurface( vout_thread_t *p_vout )
839 LPDIRECTDRAWSURFACE p_surface;
842 intf_WarnMsg( 3, "vout: DirectXCreateSurface" );
844 /* Disable display */
845 p_vout->p_sys->b_display_enabled = 0;
848 /* Probe the capabilities of the hardware */
849 /* This is just an indication of whether or not we'll support overlay,
850 * but with this test we don't know if we support YUV overlay */
851 memset( &ddcaps, 0, sizeof( DDCAPS ));
852 ddcaps.dwSize = sizeof(DDCAPS);
853 dxresult = IDirectDraw2_GetCaps( p_vout->p_sys->p_ddobject,
855 if(dxresult != DD_OK )
857 intf_WarnMsg( 3,"vout error: can't get caps." );
861 BOOL bHasOverlay, bHasColorKey, bCanStretch;
863 /* Determine if the hardware supports overlay surfaces */
864 bHasOverlay = ((ddcaps.dwCaps & DDCAPS_OVERLAY) ==
865 DDCAPS_OVERLAY) ? TRUE : FALSE;
866 /* Determine if the hardware supports colorkeying */
867 bHasColorKey = ((ddcaps.dwCaps & DDCAPS_COLORKEY) ==
868 DDCAPS_COLORKEY) ? TRUE : FALSE;
869 /* Determine if the hardware supports scaling of the overlay surface */
870 bCanStretch = ((ddcaps.dwCaps & DDCAPS_OVERLAYSTRETCH) ==
871 DDCAPS_OVERLAYSTRETCH) ? TRUE : FALSE;
872 intf_WarnMsg( 3, "vout: Dx Caps: overlay=%i colorkey=%i stretch=%i",
873 bHasOverlay, bHasColorKey, bCanStretch );
876 if( !bHasOverlay ) p_vout->b_need_render = 1;
882 /* Create the video surface */
883 if( !p_vout->b_need_render )
885 /* Now try to create the YUV overlay surface.
886 * This overlay will be displayed on top of the primary surface.
887 * A color key is used to determine whether or not the overlay will be
888 * displayed, ie the overlay will be displayed in place of the primary
889 * surface wherever the primary surface will have this color.
890 * The video window has been created with a background of this color so
891 * the overlay will be only displayed on top of this window */
893 memset( &ddsd, 0, sizeof( DDSURFACEDESC ));
894 ddsd.dwSize = sizeof(DDSURFACEDESC);
895 ddsd.ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT);
896 ddsd.ddpfPixelFormat.dwFlags = DDPF_FOURCC;
897 ddsd.ddpfPixelFormat.dwFourCC = mmioFOURCC('Y','V','1','2');
898 #ifdef NONAMELESSUNION
899 ddsd.ddpfPixelFormat.u1.dwYUVBitCount = 16;
901 ddsd.ddpfPixelFormat.dwYUVBitCount = 16;
903 ddsd.dwFlags = DDSD_CAPS |
907 ddsd.ddsCaps.dwCaps = DDSCAPS_OVERLAY | DDSCAPS_VIDEOMEMORY;
908 ddsd.dwHeight = p_vout->p_sys->i_image_height;
909 ddsd.dwWidth = p_vout->p_sys->i_image_width;
910 ddsd.dwBackBufferCount = 1; /* One back buffer */
912 dxresult = IDirectDraw2_CreateSurface( p_vout->p_sys->p_ddobject,
913 &ddsd, &p_surface, NULL );
914 if( dxresult == DD_OK )
916 intf_WarnMsg( 3,"vout: DirectX YUV overlay created successfully" );
920 intf_ErrMsg( "vout error: can't create YUV overlay surface." );
921 p_vout->b_need_render = 1;
925 if( p_vout->b_need_render )
927 /* Now try to create a plain RGB surface. */
928 memset( &ddsd, 0, sizeof( DDSURFACEDESC ));
929 ddsd.dwSize = sizeof(DDSURFACEDESC);
930 ddsd.dwFlags = DDSD_HEIGHT |
933 ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
934 ddsd.dwHeight = p_vout->p_sys->i_image_height;
935 ddsd.dwWidth = p_vout->p_sys->i_image_width;
937 dxresult = IDirectDraw2_CreateSurface( p_vout->p_sys->p_ddobject,
938 &ddsd, &p_surface, NULL );
939 if( dxresult == DD_OK )
941 intf_WarnMsg( 3,"vout: DirectX RGB surface created successfully" );
945 intf_ErrMsg( "vout error: can't create RGB surface." );
946 p_vout->p_sys->p_surface = NULL;
951 /* Now that the surface is created, try to get a newer DirectX interface */
952 dxresult = IDirectDrawSurface_QueryInterface( p_surface,
953 &IID_IDirectDrawSurface3,
954 (LPVOID *)&p_vout->p_sys->p_surface );
955 if ( dxresult != DD_OK )
957 intf_ErrMsg( "vout error: can't get IDirectDrawSurface3 interface." );
958 IDirectDrawSurface_Release( p_surface );
959 p_vout->p_sys->p_surface = NULL;
964 /* Release the old interface */
965 IDirectDrawSurface_Release( p_surface );
968 if( !p_vout->b_need_render )
970 /* Hide the overlay for now */
971 IDirectDrawSurface3_UpdateOverlay(p_vout->p_sys->p_surface,
973 p_vout->p_sys->p_display,
980 DirectXCreateClipper( p_vout );
984 /* From now on, do some initialisation for video_output */
986 /* if we want a valid pointer to the surface memory, we must lock
989 memset( &ddsd, 0, sizeof( DDSURFACEDESC ));
990 ddsd.dwSize = sizeof(DDSURFACEDESC);
991 dxresult = IDirectDrawSurface3_Lock( p_vout->p_sys->p_surface, NULL, &ddsd,
992 DDLOCK_NOSYSLOCK | DDLOCK_WAIT, NULL);
993 if ( dxresult == DDERR_SURFACELOST )
995 /* Your surface can be lost so be sure
996 * to check this and restore it if needed */
997 dxresult = IDirectDrawSurface3_Restore( p_vout->p_sys->p_surface );
998 dxresult = IDirectDrawSurface3_Lock( p_vout->p_sys->p_surface,
999 NULL, &ddsd, DDLOCK_NOSYSLOCK
1000 | DDLOCK_WAIT, NULL);
1002 if( dxresult != DD_OK )
1004 intf_ErrMsg( "vout: DirectXCreateDisplay could not lock the surface" );
1008 /* Set the pointer to the surface memory */
1009 p_vout->p_sys->p_directx_buf[ 0 ] = ddsd.lpSurface;
1010 /* back buffer, none for now */
1011 p_vout->p_sys->p_directx_buf[ 1 ] = ddsd.lpSurface;
1013 /* Set thread information */
1014 p_vout->i_width = ddsd.dwWidth;
1015 p_vout->i_height = ddsd.dwHeight;
1016 #ifdef NONAMELESSUNION
1017 p_vout->i_bytes_per_line = ddsd.u1.lPitch;
1019 p_vout->i_bytes_per_line = ddsd.lPitch;
1020 #endif /* NONAMELESSUNION */
1023 if( p_vout->b_need_render )
1025 /* For an RGB surface we need to fill in some more info */
1026 #ifdef NONAMELESSUNION
1027 p_vout->i_screen_depth = ddsd.ddpfPixelFormat.u1.dwRGBBitCount;
1028 p_vout->i_bytes_per_pixel = ddsd.ddpfPixelFormat.u1.dwRGBBitCount/8;
1030 p_vout->i_red_mask = ddsd.ddpfPixelFormat.u2.dwRBitMask;
1031 p_vout->i_green_mask = ddsd.ddpfPixelFormat.u3.dwGBitMask;
1032 p_vout->i_blue_mask = ddsd.ddpfPixelFormat.u4.dwBBitMask;
1034 p_vout->i_screen_depth = ddsd.ddpfPixelFormat.dwRGBBitCount;
1035 p_vout->i_bytes_per_pixel = ddsd.ddpfPixelFormat.dwRGBBitCount/8;
1037 p_vout->i_red_mask = ddsd.ddpfPixelFormat.dwRBitMask;
1038 p_vout->i_green_mask = ddsd.ddpfPixelFormat.dwGBitMask;
1039 p_vout->i_blue_mask = ddsd.ddpfPixelFormat.dwBBitMask;
1041 #endif /* NONAMELESSUNION */
1044 /* Unlock the Surface */
1045 dxresult = IDirectDrawSurface3_Unlock(p_vout->p_sys->p_surface,
1048 /* Set and initialize buffers */
1049 p_vout->pf_setbuffers( p_vout, p_vout->p_sys->p_directx_buf[ 0 ],
1050 p_vout->p_sys->p_directx_buf[ 1 ] );
1057 /*****************************************************************************
1058 * DirectXCreateClipper: Create a clipper that will be used when blitting the
1059 * RGB surface to the main display.
1060 *****************************************************************************
1061 * This clipper prevents us to modify by mistake anything on the screen
1062 * which doesn't belong to our window. For example when a part of our video
1063 * window is hidden by another window.
1064 *****************************************************************************/
1065 static int DirectXCreateClipper( vout_thread_t *p_vout )
1069 intf_WarnMsg( 3, "vout: DirectXCreateClipper" );
1071 /* Create the clipper */
1072 dxresult = IDirectDraw2_CreateClipper( p_vout->p_sys->p_ddobject, 0,
1073 &p_vout->p_sys->p_clipper, NULL );
1074 if( dxresult != DD_OK )
1076 intf_WarnMsg( 3, "vout: DirectXCreateClipper can't create clipper." );
1077 IDirectDrawSurface_Release( p_vout->p_sys->p_clipper );
1078 p_vout->p_sys->p_clipper = NULL;
1082 /* associate the clipper to the window */
1083 dxresult = IDirectDrawClipper_SetHWnd(p_vout->p_sys->p_clipper, 0,
1084 p_vout->p_sys->hwnd);
1085 if( dxresult != DD_OK )
1088 "vout: DirectXCreateClipper can't attach clipper to window." );
1089 IDirectDrawSurface_Release( p_vout->p_sys->p_clipper );
1090 p_vout->p_sys->p_clipper = NULL;
1094 /* associate the clipper with the surface */
1095 dxresult = IDirectDrawSurface_SetClipper(p_vout->p_sys->p_display,
1096 p_vout->p_sys->p_clipper);
1097 if( dxresult != DD_OK )
1100 "vout: DirectXCreateClipper can't attach clipper to surface." );
1101 IDirectDrawSurface_Release( p_vout->p_sys->p_clipper );
1102 p_vout->p_sys->p_clipper = NULL;
1110 /*****************************************************************************
1111 * DirectXUpdateOverlay: Move or resize overlay surface on video display.
1112 *****************************************************************************
1113 * This function is used to move or resize an overlay surface on the screen.
1114 * Ususally the overlay is moved by the user and thus, by a move or resize
1115 * event (in vout_Manage).
1116 *****************************************************************************/
1117 static int DirectXUpdateOverlay( vout_thread_t *p_vout )
1120 RECT rect_window, rect_window_backup, rect_image;
1125 DDPIXELFORMAT pixel_format;
1128 if( p_vout->p_sys->p_surface == NULL || p_vout->b_need_render )
1130 intf_WarnMsg( 3, "vout: DirectXUpdateOverlay no overlay !!" );
1134 if( !p_vout->p_rendered_pic )
1136 intf_WarnMsg( 3, "vout: DirectXUpdateOverlay p_rendered_pic=NULL !" );
1140 if( !p_vout->p_sys->b_display_enabled )
1145 /* Now get the coordinates of the window. We don't actually want the
1146 * window coordinates but these of the usable surface inside the window.
1147 * By specification GetClientRect will always set rect_window.left and
1148 * rect_window.top to 0 because the Client area is always relative to the
1149 * container window */
1150 GetClientRect(p_vout->p_sys->hwnd, &rect_window);
1154 ClientToScreen(p_vout->p_sys->hwnd, &point_window);
1155 rect_window.left = point_window.x;
1156 rect_window.top = point_window.y;
1158 point_window.x = rect_window.right;
1159 point_window.y = rect_window.bottom;
1160 ClientToScreen(p_vout->p_sys->hwnd, &point_window);
1161 rect_window.right = point_window.x;
1162 rect_window.bottom = point_window.y;
1165 /* We want to keep the aspect ratio of the video */
1166 if( p_vout->b_scale )
1168 DirectXKeepAspectRatio( p_vout, &rect_window );
1171 /* It seems we can't feed the UpdateOverlay directdraw function with
1172 * negative values so we have to clip the computed rectangles */
1173 memset( &ddsd, 0, sizeof( DDSURFACEDESC ));
1174 ddsd.dwSize = sizeof(DDSURFACEDESC);
1175 ddsd.dwFlags = DDSD_HEIGHT | DDSD_WIDTH;
1176 IDirectDraw2_GetDisplayMode( p_vout->p_sys->p_ddobject, &ddsd );
1178 rect_window_backup = rect_window;
1180 /* Clip the destination window */
1181 rect_window.left = (rect_window.left < 0) ? 0 : rect_window.left;
1182 rect_window.right = (rect_window.right < 0) ? 0 : rect_window.right;
1183 rect_window.top = (rect_window.top < 0) ? 0 : rect_window.top;
1184 rect_window.bottom = (rect_window.bottom < 0) ? 0 : rect_window.bottom;
1186 rect_window.left = (rect_window.left > ddsd.dwWidth) ? ddsd.dwWidth
1188 rect_window.right = (rect_window.right > ddsd.dwWidth) ? ddsd.dwWidth
1189 : rect_window.right;
1190 rect_window.top = (rect_window.top > ddsd.dwHeight) ? ddsd.dwHeight
1192 rect_window.bottom = (rect_window.bottom > ddsd.dwHeight) ? ddsd.dwHeight
1193 : rect_window.bottom;
1195 intf_WarnMsg( 3, "vout: DirectXUpdateOverlay window coords: %i,%i,%i,%i",
1196 rect_window.left, rect_window.top,
1197 rect_window.right, rect_window.bottom);
1199 /* the 2 following lines are to fix a bug when click on Windows desktop */
1200 if( (rect_window.right-rect_window.left)==0 ||
1201 (rect_window.bottom-rect_window.top)==0 ) return 0;
1203 /* Clip the source image */
1204 rect_image.left = ( rect_window.left == rect_window_backup.left ) ? 0
1205 : labs(rect_window_backup.left - rect_window.left) *
1206 p_vout->p_rendered_pic->i_width /
1207 (rect_window_backup.right - rect_window_backup.left);
1208 rect_image.right = ( rect_window.right == rect_window_backup.right ) ?
1209 p_vout->p_rendered_pic->i_width
1210 : p_vout->p_rendered_pic->i_width -
1211 labs(rect_window_backup.right - rect_window.right) *
1212 p_vout->p_rendered_pic->i_width /
1213 (rect_window_backup.right - rect_window_backup.left);
1214 rect_image.top = ( rect_window.top == rect_window_backup.top ) ? 0
1215 : labs(rect_window_backup.top - rect_window.top) *
1216 p_vout->p_rendered_pic->i_height /
1217 (rect_window_backup.bottom - rect_window_backup.top);
1218 rect_image.bottom = ( rect_window.bottom == rect_window_backup.bottom ) ?
1219 p_vout->p_rendered_pic->i_height
1220 : p_vout->p_rendered_pic->i_height -
1221 labs(rect_window_backup.bottom - rect_window.bottom) *
1222 p_vout->p_rendered_pic->i_height /
1223 (rect_window_backup.bottom - rect_window_backup.top);
1225 intf_WarnMsg( 3, "vout: DirectXUpdateOverlay image coords: %i,%i,%i,%i",
1226 rect_image.left, rect_image.top,
1227 rect_image.right, rect_image.bottom);
1229 /* compute the colorkey pixel value from the RGB value we've got */
1230 memset( &pixel_format, 0, sizeof( DDPIXELFORMAT ));
1231 pixel_format.dwSize = sizeof( DDPIXELFORMAT );
1232 dxresult = IDirectDrawSurface3_GetPixelFormat( p_vout->p_sys->p_display,
1234 if( dxresult != DD_OK )
1235 intf_WarnMsg( 3, "vout: DirectXUpdateOverlay GetPixelFormat failed" );
1236 dw_colorkey = (DWORD)p_vout->p_sys->i_colorkey;
1237 #ifdef NONAMELESSUNION
1238 dw_colorkey = (DWORD)((( dw_colorkey * pixel_format.u2.dwRBitMask) / 255)
1239 & pixel_format.u2.dwRBitMask);
1241 dw_colorkey = (DWORD)((( dw_colorkey * pixel_format.dwRBitMask) / 255)
1242 & pixel_format.dwRBitMask);
1245 /* Position and show the overlay */
1246 memset(&ddofx, 0, sizeof(DDOVERLAYFX));
1247 ddofx.dwSize = sizeof(DDOVERLAYFX);
1248 ddofx.dckDestColorkey.dwColorSpaceLowValue = dw_colorkey;
1249 ddofx.dckDestColorkey.dwColorSpaceHighValue = dw_colorkey;
1251 dwFlags = DDOVER_KEYDESTOVERRIDE | DDOVER_SHOW;
1253 dxresult = IDirectDrawSurface3_UpdateOverlay(p_vout->p_sys->p_surface,
1255 p_vout->p_sys->p_display,
1259 if(dxresult != DD_OK)
1262 "vout: DirectXUpdateOverlay can't move or resize overlay" );
1268 /*****************************************************************************
1269 * DirectXCloseDDraw: Release the DDraw object allocated by DirectXInitDDraw
1270 *****************************************************************************
1271 * This function returns all resources allocated by DirectXInitDDraw.
1272 *****************************************************************************/
1273 static void DirectXCloseDDraw( vout_thread_t *p_vout )
1275 intf_WarnMsg(3, "vout: DirectXCloseDDraw" );
1276 if( p_vout->p_sys->p_ddobject != NULL )
1278 IDirectDraw2_Release(p_vout->p_sys->p_ddobject);
1279 p_vout->p_sys->p_ddobject = NULL;
1282 if( p_vout->p_sys->hddraw_dll != NULL )
1284 FreeLibrary( p_vout->p_sys->hddraw_dll );
1285 p_vout->p_sys->hddraw_dll = NULL;
1289 /*****************************************************************************
1290 * DirectXCloseDisplay: close and reset the DirectX display device
1291 *****************************************************************************
1292 * This function returns all resources allocated by DirectXCreateDisplay.
1293 *****************************************************************************/
1294 static void DirectXCloseDisplay( vout_thread_t *p_vout )
1296 intf_WarnMsg( 3, "vout: DirectXCloseDisplay" );
1297 if( p_vout->p_sys->p_display != NULL )
1299 DirectXCloseSurface( p_vout );
1301 intf_WarnMsg( 3, "vout: DirectXCloseDisplay display" );
1302 IDirectDraw2_Release( p_vout->p_sys->p_display );
1303 p_vout->p_sys->p_display = NULL;
1307 /*****************************************************************************
1308 * DirectXCloseSurface: close the YUV overlay or RGB surface.
1309 *****************************************************************************
1310 * This function returns all resources allocated by the surface.
1311 * We also call this function when the decoded picture change its dimensions
1312 * (in that case we close the overlay surface and reopen another with the
1313 * right dimensions).
1314 *****************************************************************************/
1315 static void DirectXCloseSurface( vout_thread_t *p_vout )
1317 intf_WarnMsg( 3, "vout: DirectXCloseSurface" );
1318 if( p_vout->p_sys->p_surface != NULL )
1320 intf_WarnMsg( 3, "vout: DirectXCloseSurface surface" );
1321 IDirectDraw2_Release( p_vout->p_sys->p_surface );
1322 p_vout->p_sys->p_surface = NULL;
1325 if( p_vout->p_sys->p_clipper != NULL )
1327 intf_WarnMsg( 3, "vout: DirectXCloseSurface clipper" );
1328 IDirectDraw2_Release( p_vout->p_sys->p_clipper );
1329 p_vout->p_sys->p_clipper = NULL;
1332 /* Disable any display */
1333 p_vout->p_sys->b_display_enabled = 0;
1336 /*****************************************************************************
1337 * DirectXKeepAspectRatio:
1338 *****************************************************************************
1339 * This function adjusts the coordinates of the video rectangle to keep the
1340 * aspect/ratio of the video.
1341 *****************************************************************************/
1342 static void DirectXKeepAspectRatio( vout_thread_t *p_vout, RECT *rect_window )
1345 if( !p_vout->p_rendered_pic ) return;
1347 switch( p_vout->p_rendered_pic->i_aspect )
1349 case AR_16_9_PICTURE:
1350 if( ((rect_window->right-rect_window->left)*9)
1351 > ((rect_window->bottom-rect_window->top)*16) )
1354 temp = (rect_window->bottom-rect_window->top)*16/9;
1355 temp = (rect_window->right-rect_window->left) - temp;
1356 rect_window->left += (temp/2);
1357 rect_window->right -= (temp/2);
1362 temp = (rect_window->right-rect_window->left)*9/16;
1363 temp = (rect_window->bottom-rect_window->top) - temp;
1364 rect_window->top += (temp/2);
1365 rect_window->bottom -= (temp/2);
1369 case AR_221_1_PICTURE:
1370 if( ((rect_window->right-rect_window->left)*100)
1371 > ((rect_window->bottom-rect_window->top)*221) )
1374 temp = (rect_window->bottom-rect_window->top)*221/100;
1375 temp = (rect_window->right-rect_window->left) - temp;
1376 rect_window->left += (temp/2);
1377 rect_window->right -= (temp/2);
1382 temp = (rect_window->right-rect_window->left)*100/221;
1383 temp = (rect_window->bottom-rect_window->top) - temp;
1384 rect_window->top += (temp/2);
1385 rect_window->bottom -= (temp/2);
1389 case AR_3_4_PICTURE:
1390 if( ((rect_window->right-rect_window->left)*3)
1391 > ((rect_window->bottom-rect_window->top)*4) )
1394 temp = (rect_window->bottom-rect_window->top)*4/3;
1395 temp = (rect_window->right-rect_window->left) - temp;
1396 rect_window->left += (temp/2);
1397 rect_window->right -= (temp/2);
1402 temp = (rect_window->right-rect_window->left)*3/4;
1403 temp = (rect_window->bottom-rect_window->top) - temp;
1404 rect_window->top += (temp/2);
1405 rect_window->bottom -= (temp/2);
1409 case AR_SQUARE_PICTURE:
1411 if( (rect_window->right-rect_window->left)
1412 > (rect_window->bottom-rect_window->top) )
1415 temp = (rect_window->bottom-rect_window->top);
1416 temp = (rect_window->right-rect_window->left) - temp;
1417 rect_window->left += (temp/2);
1418 rect_window->right -= (temp/2);
1423 temp = (rect_window->right-rect_window->left);
1424 temp = (rect_window->bottom-rect_window->top) - temp;
1425 rect_window->top += (temp/2);
1426 rect_window->bottom -= (temp/2);