1 /*****************************************************************************
2 * wingdi.c : Win32 / WinCE GDI video output plugin for vlc
3 *****************************************************************************
4 * Copyright (C) 2002-2009 the VideoLAN team
7 * Authors: Gildas Bazin <gbazin@videolan.org>
8 * Samuel Hocevar <sam@zoy.org>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23 *****************************************************************************/
25 /*****************************************************************************
27 *****************************************************************************/
33 #include <vlc_common.h>
34 #include <vlc_plugin.h>
35 #include <vlc_interface.h>
36 #include <vlc_playlist.h>
43 /*#ifdef MODULE_NAME_IS_wingapi
44 typedef struct GXDisplayProperties {
51 } GXDisplayProperties;
53 typedef struct GXScreenRect {
60 # define GX_FULLSCREEN 0x01
61 # define GX_NORMALKEYS 0x02
62 # define GX_LANDSCAPEKEYS 0x03
65 # define kfLandscape 0x8
66 # define kfPalette 0x10
67 # define kfDirect 0x20
68 # define kfDirect555 0x40
69 # define kfDirect565 0x80
70 # define kfDirect888 0x100
71 # define kfDirect444 0x200
72 # define kfDirectInverted 0x400
74 #endif */ /* MODULE_NAME_IS_wingapi */
78 #define MAX_DIRECTBUFFERS 10
81 #ifndef WS_OVERLAPPEDWINDOW
82 # define WS_OVERLAPPEDWINDOW 0xcf0000
84 #ifndef WS_EX_NOPARENTNOTIFY
85 # define WS_EX_NOPARENTNOTIFY 4
87 #ifndef WS_EX_APPWINDOW
88 #define WS_EX_APPWINDOW 0x40000
90 //#define SetWindowLongPtr SetWindowLong
91 //#define GetWindowLongPtr GetWindowLong
92 //#define GWLP_USERDATA GWL_USERDATA
93 #define AdjustWindowRect(a,b,c)
96 #ifndef WS_NONAVDONEBUTTON
97 #define WS_NONAVDONEBUTTON 0
99 /*****************************************************************************
101 *****************************************************************************/
102 static int OpenVideo ( vlc_object_t * );
103 static void CloseVideo ( vlc_object_t * );
105 static int Init ( vout_thread_t * );
106 static void End ( vout_thread_t * );
107 static int Manage ( vout_thread_t * );
108 static void Render ( vout_thread_t *, picture_t * );
109 #ifdef MODULE_NAME_IS_wingapi
110 static void FirstDisplayGAPI( vout_thread_t *, picture_t * );
111 static void DisplayGAPI( vout_thread_t *, picture_t * );
112 static int GAPILockSurface( vout_thread_t *, picture_t * );
113 static int GAPIUnlockSurface( vout_thread_t *, picture_t * );
115 static void FirstDisplayGDI( vout_thread_t *, picture_t * );
116 static void DisplayGDI( vout_thread_t *, picture_t * );
118 static void SetPalette( vout_thread_t *, uint16_t *, uint16_t *, uint16_t * );
120 static void InitBuffers ( vout_thread_t * );
124 #define DX_POSITION_CHANGE 0x1000
126 /*****************************************************************************
128 *****************************************************************************/
130 set_category( CAT_VIDEO )
131 set_subcategory( SUBCAT_VIDEO_VOUT )
132 #ifdef MODULE_NAME_IS_wingapi
133 set_shortname( "Windows GAPI" )
134 set_description( N_("Windows GAPI video output") )
135 set_capability( "video output", 20 )
137 set_shortname( "Windows GDI" )
138 set_description( N_("Windows GDI video output") )
139 set_capability( "video output", 10 )
141 set_callbacks( OpenVideo, CloseVideo )
144 /*****************************************************************************
145 * OpenVideo: activate GDI video thread output method
146 *****************************************************************************/
147 static int OpenVideo ( vlc_object_t *p_this )
149 vout_thread_t * p_vout = (vout_thread_t *)p_this;
151 p_vout->p_sys = (vout_sys_t *)calloc( 1, sizeof(vout_sys_t) );
152 if( !p_vout->p_sys ) return VLC_ENOMEM;
154 #ifdef MODULE_NAME_IS_wingapi
156 p_vout->p_sys->gapi_dll = LoadLibrary( _T("GX.DLL") );
157 if( p_vout->p_sys->gapi_dll == NULL )
159 msg_Warn( p_vout, "failed loading gx.dll" );
160 free( p_vout->p_sys );
164 GXOpenDisplay = (void *)GetProcAddress( p_vout->p_sys->gapi_dll,
165 _T("?GXOpenDisplay@@YAHPAUHWND__@@K@Z") );
166 GXCloseDisplay = (void *)GetProcAddress( p_vout->p_sys->gapi_dll,
167 _T("?GXCloseDisplay@@YAHXZ") );
168 GXBeginDraw = (void *)GetProcAddress( p_vout->p_sys->gapi_dll,
169 _T("?GXBeginDraw@@YAPAXXZ") );
170 GXEndDraw = (void *)GetProcAddress( p_vout->p_sys->gapi_dll,
171 _T("?GXEndDraw@@YAHXZ") );
172 GXGetDisplayProperties = (void *)GetProcAddress( p_vout->p_sys->gapi_dll,
173 _T("?GXGetDisplayProperties@@YA?AUGXDisplayProperties@@XZ") );
174 GXSuspend = (void *)GetProcAddress( p_vout->p_sys->gapi_dll,
175 _T("?GXSuspend@@YAHXZ") );
176 GXResume = GetProcAddress( p_vout->p_sys->gapi_dll,
177 _T("?GXResume@@YAHXZ") );
179 if( !GXOpenDisplay || !GXCloseDisplay || !GXBeginDraw || !GXEndDraw ||
180 !GXGetDisplayProperties || !GXSuspend || !GXResume )
182 msg_Err( p_vout, "failed GetProcAddress on gapi.dll" );
183 free( p_vout->p_sys );
187 msg_Dbg( p_vout, "GAPI DLL loaded" );
189 p_vout->p_sys->render_width = p_vout->render.i_width;
190 p_vout->p_sys->render_height = p_vout->render.i_height;
193 p_vout->p_sys->p_event = (vlc_object_t *)
194 vlc_object_create( p_vout, sizeof( vlc_object_t ) );
195 if( !p_vout->p_sys->p_event )
197 free( p_vout->p_sys );
201 p_vout->pf_init = Init;
202 p_vout->pf_end = End;
203 p_vout->pf_manage = Manage;
204 p_vout->pf_render = Render;
205 #ifdef MODULE_NAME_IS_wingapi
206 p_vout->pf_display = FirstDisplayGAPI;
208 p_vout->p_sys->b_focus = 0;
209 p_vout->p_sys->b_parent_focus = 0;
212 p_vout->pf_display = FirstDisplayGDI;
215 p_vout->p_sys->hwnd = p_vout->p_sys->hvideownd = NULL;
216 p_vout->p_sys->hparent = p_vout->p_sys->hfswnd = NULL;
217 p_vout->p_sys->i_changes = 0;
218 vlc_mutex_init( &p_vout->p_sys->lock );
219 SetRectEmpty( &p_vout->p_sys->rect_display );
220 SetRectEmpty( &p_vout->p_sys->rect_parent );
222 var_Create( p_vout, "video-title", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
223 var_Create( p_vout, "disable-screensaver", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
225 p_vout->p_sys->b_cursor_hidden = 0;
226 p_vout->p_sys->i_lastmoved = mdate();
227 p_vout->p_sys->i_mouse_hide_timeout =
228 var_GetInteger(p_vout, "mouse-hide-timeout") * 1000;
230 /* Set main window's size */
231 p_vout->p_sys->i_window_width = p_vout->i_window_width;
232 p_vout->p_sys->i_window_height = p_vout->i_window_height;
234 /* Create the EventThread, this thread is created by us to isolate
235 * the Win32 PeekMessage function calls. We want to do this because
236 * Windows can stay blocked inside this call for a long time, and when
237 * this happens it thus blocks vlc's video_output thread.
238 * Vout EventThread will take care of the creation of the video
239 * window (because PeekMessage has to be called from the same thread which
240 * created the window). */
241 msg_Dbg( p_vout, "creating Vout EventThread" );
242 p_vout->p_sys->p_event =
243 vlc_object_create( p_vout, sizeof(event_thread_t) );
244 p_vout->p_sys->p_event->p_vout = p_vout;
245 p_vout->p_sys->p_event->window_ready = CreateEvent( NULL, TRUE, FALSE, NULL );
246 if( vlc_thread_create( p_vout->p_sys->p_event, "Vout Events Thread",
249 msg_Err( p_vout, "cannot create Vout EventThread" );
250 CloseHandle( p_vout->p_sys->p_event->window_ready );
251 vlc_object_release( p_vout->p_sys->p_event );
252 p_vout->p_sys->p_event = NULL;
255 WaitForSingleObject( p_vout->p_sys->p_event->window_ready, INFINITE );
256 CloseHandle( p_vout->p_sys->p_event->window_ready );
258 if( p_vout->p_sys->p_event->b_error )
260 msg_Err( p_vout, "Vout EventThread failed" );
264 vlc_object_attach( p_vout->p_sys->p_event, p_vout );
266 msg_Dbg( p_vout, "Vout EventThread running" );
269 /* Variable to indicate if the window should be on top of others */
270 /* Trigger a callback right now */
271 var_TriggerCallback( p_vout, "video-on-top" );
273 /* disable screensaver by temporarily changing system settings */
274 p_vout->p_sys->i_spi_lowpowertimeout = 0;
275 p_vout->p_sys->i_spi_powerofftimeout = 0;
276 p_vout->p_sys->i_spi_screensavetimeout = 0;
277 if( var_GetBool( p_vout, "disable-screensaver" ) ) {
278 msg_Dbg(p_vout, "disabling screen saver");
279 SystemParametersInfo(SPI_GETLOWPOWERTIMEOUT,
280 0, &(p_vout->p_sys->i_spi_lowpowertimeout), 0);
281 if( 0 != p_vout->p_sys->i_spi_lowpowertimeout ) {
282 SystemParametersInfo(SPI_SETLOWPOWERTIMEOUT, 0, NULL, 0);
284 SystemParametersInfo(SPI_GETPOWEROFFTIMEOUT, 0,
285 &(p_vout->p_sys->i_spi_powerofftimeout), 0);
286 if( 0 != p_vout->p_sys->i_spi_powerofftimeout ) {
287 SystemParametersInfo(SPI_SETPOWEROFFTIMEOUT, 0, NULL, 0);
289 SystemParametersInfo(SPI_GETSCREENSAVETIMEOUT, 0,
290 &(p_vout->p_sys->i_spi_screensavetimeout), 0);
291 if( 0 != p_vout->p_sys->i_spi_screensavetimeout ) {
292 SystemParametersInfo(SPI_SETSCREENSAVETIMEOUT, 0, NULL, 0);
299 CloseVideo( VLC_OBJECT(p_vout) );
303 /*****************************************************************************
304 * CloseVideo: deactivate the GDI video output
305 *****************************************************************************/
306 static void CloseVideo ( vlc_object_t *p_this )
308 vout_thread_t * p_vout = (vout_thread_t *)p_this;
310 if( p_vout->b_fullscreen )
312 msg_Dbg( p_vout, "Quitting fullscreen" );
313 Win32ToggleFullscreen( p_vout );
314 /* Force fullscreen in the core for the next video */
315 var_SetBool( p_vout, "fullscreen", true );
318 if( p_vout->p_sys->p_event )
320 vlc_object_detach( p_vout->p_sys->p_event );
322 /* Kill Vout EventThread */
323 vlc_object_kill( p_vout->p_sys->p_event );
325 /* we need to be sure Vout EventThread won't stay stuck in
326 * GetMessage, so we send a fake message */
327 if( p_vout->p_sys->hwnd )
329 PostMessage( p_vout->p_sys->hwnd, WM_NULL, 0, 0);
332 vlc_thread_join( p_vout->p_sys->p_event );
333 vlc_object_release( p_vout->p_sys->p_event );
335 vlc_mutex_destroy( &p_vout->p_sys->lock );
338 /* restore screensaver system settings */
339 if( 0 != p_vout->p_sys->i_spi_lowpowertimeout ) {
340 SystemParametersInfo(SPI_SETLOWPOWERTIMEOUT,
341 p_vout->p_sys->i_spi_lowpowertimeout, NULL, 0);
343 if( 0 != p_vout->p_sys->i_spi_powerofftimeout ) {
344 SystemParametersInfo(SPI_SETPOWEROFFTIMEOUT,
345 p_vout->p_sys->i_spi_powerofftimeout, NULL, 0);
347 if( 0 != p_vout->p_sys->i_spi_screensavetimeout ) {
348 SystemParametersInfo(SPI_SETSCREENSAVETIMEOUT,
349 p_vout->p_sys->i_spi_screensavetimeout, NULL, 0);
353 #ifdef MODULE_NAME_IS_wingapi
354 FreeLibrary( p_vout->p_sys->gapi_dll );
357 free( p_vout->p_sys );
358 p_vout->p_sys = NULL;
361 /*****************************************************************************
362 * Init: initialize video thread output method
363 *****************************************************************************/
364 static int Init( vout_thread_t *p_vout )
368 /* Initialize offscreen buffer */
369 InitBuffers( p_vout );
371 p_vout->p_sys->rect_display.left = 0;
372 p_vout->p_sys->rect_display.top = 0;
373 p_vout->p_sys->rect_display.right = GetSystemMetrics(SM_CXSCREEN);
374 p_vout->p_sys->rect_display.bottom = GetSystemMetrics(SM_CYSCREEN);
376 I_OUTPUTPICTURES = 0;
378 /* Initialize the output structure */
379 switch( p_vout->p_sys->i_depth )
382 p_vout->output.i_chroma = VLC_CODEC_RGB8;
383 p_vout->output.pf_setpalette = SetPalette;
386 p_vout->output.i_chroma = VLC_CODEC_RGB15;
387 p_vout->output.i_rmask = 0x7c00;
388 p_vout->output.i_gmask = 0x03e0;
389 p_vout->output.i_bmask = 0x001f;
392 p_vout->output.i_chroma = VLC_CODEC_RGB16;
393 p_vout->output.i_rmask = 0xf800;
394 p_vout->output.i_gmask = 0x07e0;
395 p_vout->output.i_bmask = 0x001f;
398 p_vout->output.i_chroma = VLC_CODEC_RGB24;
399 p_vout->output.i_rmask = 0x00ff0000;
400 p_vout->output.i_gmask = 0x0000ff00;
401 p_vout->output.i_bmask = 0x000000ff;
404 p_vout->output.i_chroma = VLC_CODEC_RGB32;
405 p_vout->output.i_rmask = 0x00ff0000;
406 p_vout->output.i_gmask = 0x0000ff00;
407 p_vout->output.i_bmask = 0x000000ff;
410 msg_Err( p_vout, "screen depth %i not supported",
411 p_vout->p_sys->i_depth );
416 p_pic = &p_vout->p_picture[0];
418 #ifdef MODULE_NAME_IS_wingapi
419 p_vout->output.i_width = 0;
420 p_vout->output.i_height = 0;
421 p_pic->pf_lock = GAPILockSurface;
422 p_pic->pf_unlock = GAPIUnlockSurface;
424 GAPILockSurface( p_vout, p_pic );
425 p_vout->i_changes = 0;
426 p_vout->output.i_width = p_vout->p_sys->render_width;
427 p_vout->output.i_height = p_vout->p_sys->render_height;
430 p_vout->output.i_width = p_vout->render.i_width;
431 p_vout->output.i_height = p_vout->render.i_height;
433 p_vout->fmt_out = p_vout->fmt_in;
434 p_vout->fmt_out.i_chroma = p_vout->output.i_chroma;
437 p_vout->output.i_aspect = p_vout->render.i_aspect;
439 p_pic->p->p_pixels = p_vout->p_sys->p_pic_buffer;
440 p_pic->p->i_lines = p_vout->output.i_height;
441 p_pic->p->i_visible_lines = p_vout->output.i_height;
442 p_pic->p->i_pitch = p_vout->p_sys->i_pic_pitch;
443 p_pic->p->i_pixel_pitch = p_vout->p_sys->i_pic_pixel_pitch;
444 p_pic->p->i_visible_pitch = p_vout->output.i_width *
445 p_pic->p->i_pixel_pitch;
447 p_pic->i_status = DESTROYED_PICTURE;
448 p_pic->i_type = DIRECT_PICTURE;
450 PP_OUTPUTPICTURE[ I_OUTPUTPICTURES++ ] = p_pic;
452 /* Change the window title bar text */
453 PostMessage( p_vout->p_sys->hwnd, WM_VLC_CHANGE_TEXT, 0, 0 );
454 UpdateRects( p_vout, true );
459 /*****************************************************************************
460 * End: terminate video thread output method
461 *****************************************************************************/
462 static void End( vout_thread_t *p_vout )
464 #ifdef MODULE_NAME_IS_wingapi
467 DeleteDC( p_vout->p_sys->off_dc );
468 DeleteObject( p_vout->p_sys->off_bitmap );
472 /*****************************************************************************
473 * Manage: handle events
474 *****************************************************************************
475 * This function should be called regularly by video output thread. It manages
476 * console events. It returns a non null value on error.
477 *****************************************************************************/
478 static int Manage( vout_thread_t *p_vout )
480 /* If we do not control our window, we check for geometry changes
481 * ourselves because the parent might not send us its events. */
482 vlc_mutex_lock( &p_vout->p_sys->lock );
483 if( p_vout->p_sys->hparent && !p_vout->b_fullscreen )
488 vlc_mutex_unlock( &p_vout->p_sys->lock );
490 GetClientRect( p_vout->p_sys->hparent, &rect_parent );
491 point.x = point.y = 0;
492 ClientToScreen( p_vout->p_sys->hparent, &point );
493 OffsetRect( &rect_parent, point.x, point.y );
495 if( !EqualRect( &rect_parent, &p_vout->p_sys->rect_parent ) )
497 int i_x, i_y, i_width, i_height;
498 p_vout->p_sys->rect_parent = rect_parent;
500 /* This one is to force the update even if only
501 * the position has changed */
502 SetWindowPos( p_vout->p_sys->hwnd, 0, 1, 1,
503 rect_parent.right - rect_parent.left,
504 rect_parent.bottom - rect_parent.top, 0 );
506 SetWindowPos( p_vout->p_sys->hwnd, 0, 0, 0,
507 rect_parent.right - rect_parent.left,
508 rect_parent.bottom - rect_parent.top, 0 );
510 vout_PlacePicture( p_vout, rect_parent.right - rect_parent.left,
511 rect_parent.bottom - rect_parent.top,
512 &i_x, &i_y, &i_width, &i_height );
514 SetWindowPos( p_vout->p_sys->hvideownd, HWND_TOP,
515 i_x, i_y, i_width, i_height, 0 );
520 vlc_mutex_unlock( &p_vout->p_sys->lock );
523 /* autoscale toggle */
524 if( p_vout->i_changes & VOUT_SCALE_CHANGE )
526 p_vout->i_changes &= ~VOUT_SCALE_CHANGE;
528 p_vout->b_autoscale = var_GetBool( p_vout, "autoscale" );
529 p_vout->i_zoom = (int) ZOOM_FP_FACTOR;
531 UpdateRects( p_vout, true );
535 if( p_vout->i_changes & VOUT_ZOOM_CHANGE )
537 p_vout->i_changes &= ~VOUT_ZOOM_CHANGE;
539 p_vout->b_autoscale = false;
541 (int)( ZOOM_FP_FACTOR * var_GetFloat( p_vout, "scale" ) );
542 UpdateRects( p_vout, true );
545 /* Check for cropping / aspect changes */
546 if( p_vout->i_changes & VOUT_CROP_CHANGE ||
547 p_vout->i_changes & VOUT_ASPECT_CHANGE )
549 p_vout->i_changes &= ~VOUT_CROP_CHANGE;
550 p_vout->i_changes &= ~VOUT_ASPECT_CHANGE;
552 p_vout->fmt_out.i_x_offset = p_vout->fmt_in.i_x_offset;
553 p_vout->fmt_out.i_y_offset = p_vout->fmt_in.i_y_offset;
554 p_vout->fmt_out.i_visible_width = p_vout->fmt_in.i_visible_width;
555 p_vout->fmt_out.i_visible_height = p_vout->fmt_in.i_visible_height;
556 p_vout->fmt_out.i_aspect = p_vout->fmt_in.i_aspect;
557 p_vout->fmt_out.i_sar_num = p_vout->fmt_in.i_sar_num;
558 p_vout->fmt_out.i_sar_den = p_vout->fmt_in.i_sar_den;
559 p_vout->output.i_aspect = p_vout->fmt_in.i_aspect;
560 UpdateRects( p_vout, true );
566 if( p_vout->p_sys->i_changes & DX_POSITION_CHANGE )
568 p_vout->p_sys->i_changes &= ~DX_POSITION_CHANGE;
571 /* We used to call the Win32 PeekMessage function here to read the window
572 * messages. But since window can stay blocked into this function for a
573 * long time (for example when you move your window on the screen), I
574 * decided to isolate PeekMessage in another thread. */
579 if( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE
580 || p_vout->p_sys->i_changes & VOUT_FULLSCREEN_CHANGE )
582 Win32ToggleFullscreen( p_vout );
584 p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
585 p_vout->p_sys->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
591 if( p_vout->b_fullscreen && !p_vout->p_sys->b_cursor_hidden &&
592 (mdate() - p_vout->p_sys->i_lastmoved) >
593 p_vout->p_sys->i_mouse_hide_timeout )
598 /* Hide the cursor only if it is inside our window */
599 GetCursorPos( &point );
600 hwnd = WindowFromPoint(point);
601 if( hwnd == p_vout->p_sys->hwnd || hwnd == p_vout->p_sys->hvideownd )
603 PostMessage( p_vout->p_sys->hwnd, WM_VLC_HIDE_MOUSE, 0, 0 );
607 p_vout->p_sys->i_lastmoved = mdate();
612 * "Always on top" status change
614 if( p_vout->p_sys->b_on_top_change )
617 HMENU hMenu = GetSystemMenu( p_vout->p_sys->hwnd, FALSE );
619 var_Get( p_vout, "video-on-top", &val );
621 /* Set the window on top if necessary */
622 if( val.b_bool && !( GetWindowLong( p_vout->p_sys->hwnd, GWL_EXSTYLE )
625 CheckMenuItem( hMenu, IDM_TOGGLE_ON_TOP,
626 MF_BYCOMMAND | MFS_CHECKED );
627 SetWindowPos( p_vout->p_sys->hwnd, HWND_TOPMOST, 0, 0, 0, 0,
628 SWP_NOSIZE | SWP_NOMOVE );
631 /* The window shouldn't be on top */
632 if( !val.b_bool && ( GetWindowLong( p_vout->p_sys->hwnd, GWL_EXSTYLE )
635 CheckMenuItem( hMenu, IDM_TOGGLE_ON_TOP,
636 MF_BYCOMMAND | MFS_UNCHECKED );
637 SetWindowPos( p_vout->p_sys->hwnd, HWND_NOTOPMOST, 0, 0, 0, 0,
638 SWP_NOSIZE | SWP_NOMOVE );
641 p_vout->p_sys->b_on_top_change = false;
644 /* Check if the event thread is still running */
645 if( !vlc_object_alive (p_vout->p_sys->p_event) )
647 return VLC_EGENERIC; /* exit */
653 /*****************************************************************************
654 * Render: render previously calculated output
655 *****************************************************************************/
656 static void Render( vout_thread_t *p_vout, picture_t *p_pic )
658 /* No need to do anything, the fake direct buffers stay as they are */
663 /*****************************************************************************
664 * Display: displays previously rendered output
665 *****************************************************************************/
666 #define rect_src p_vout->p_sys->rect_src
667 #define rect_src_clipped p_vout->p_sys->rect_src_clipped
668 #define rect_dest p_vout->p_sys->rect_dest
669 #define rect_dest_clipped p_vout->p_sys->rect_dest_clipped
671 #ifndef MODULE_NAME_IS_wingapi
672 static void DisplayGDI( vout_thread_t *p_vout, picture_t *p_pic )
674 vout_sys_t *p_sys = p_vout->p_sys;
675 RECT rect_dst = rect_dest_clipped;
676 HDC hdc = GetDC( p_sys->hvideownd );
678 OffsetRect( &rect_dst, -rect_dest.left, -rect_dest.top );
679 SelectObject( p_sys->off_dc, p_sys->off_bitmap );
681 if( rect_dest_clipped.right - rect_dest_clipped.left !=
682 rect_src_clipped.right - rect_src_clipped.left ||
683 rect_dest_clipped.bottom - rect_dest_clipped.top !=
684 rect_src_clipped.bottom - rect_src_clipped.top )
686 StretchBlt( hdc, rect_dst.left, rect_dst.top,
687 rect_dst.right, rect_dst.bottom,
688 p_sys->off_dc, rect_src_clipped.left, rect_src_clipped.top,
689 rect_src_clipped.right, rect_src_clipped.bottom, SRCCOPY );
693 BitBlt( hdc, rect_dst.left, rect_dst.top,
694 rect_dst.right, rect_dst.bottom,
695 p_sys->off_dc, rect_src_clipped.left,
696 rect_src_clipped.top, SRCCOPY );
699 ReleaseDC( p_sys->hvideownd, hdc );
702 static void FirstDisplayGDI( vout_thread_t *p_vout, picture_t *p_pic )
705 ** Video window is initially hidden, show it now since we got a
708 SetWindowPos( p_vout->p_sys->hvideownd, 0, 0, 0, 0, 0,
716 /* get initial picture presented */
717 DisplayGDI(p_vout, p_pic);
719 /* use and restores proper display function for further pictures */
720 p_vout->pf_display = DisplayGDI;
725 static int GAPILockSurface( vout_thread_t *p_vout, picture_t *p_pic )
727 vout_sys_t *p_sys = p_vout->p_sys;
728 int i_x, i_y, i_width, i_height;
732 GetClientRect( p_sys->hwnd, &video_rect);
733 vout_PlacePicture( p_vout, video_rect.right - video_rect.left,
734 video_rect.bottom - video_rect.top,
735 &i_x, &i_y, &i_width, &i_height );
736 point.x = point.y = 0;
737 ClientToScreen( p_sys->hwnd, &point );
738 i_x += point.x + video_rect.left;
739 i_y += point.y + video_rect.top;
741 if( i_width != p_vout->output.i_width ||
742 i_height != p_vout->output.i_height )
744 GXDisplayProperties gxdisplayprop = GXGetDisplayProperties();
746 p_sys->render_width = i_width;
747 p_sys->render_height = i_height;
748 p_vout->i_changes |= VOUT_SIZE_CHANGE;
750 msg_Dbg( p_vout, "vout size change (%ix%i -> %ix%i)",
751 i_width, i_height, p_vout->output.i_width,
752 p_vout->output.i_height );
754 p_vout->p_sys->i_pic_pixel_pitch = gxdisplayprop.cbxPitch;
755 p_vout->p_sys->i_pic_pitch = gxdisplayprop.cbyPitch;
760 GXDisplayProperties gxdisplayprop;
761 RECT display_rect, dest_rect;
762 uint8_t *p_dest, *p_src = p_pic->p->p_pixels;
764 video_rect.left = i_x; video_rect.top = i_y;
765 video_rect.right = i_x + i_width;
766 video_rect.bottom = i_y + i_height;
768 gxdisplayprop = GXGetDisplayProperties();
769 display_rect.left = 0; display_rect.top = 0;
770 display_rect.right = gxdisplayprop.cxWidth;
771 display_rect.bottom = gxdisplayprop.cyHeight;
773 if( !IntersectRect( &dest_rect, &video_rect, &display_rect ) )
779 msg_Err( p_vout, "video (%d,%d,%d,%d) display (%d,%d,%d,%d) "
780 "dest (%d,%d,%d,%d)",
781 video_rect.left, video_rect.right,
782 video_rect.top, video_rect.bottom,
783 display_rect.left, display_rect.right,
784 display_rect.top, display_rect.bottom,
785 dest_rect.left, dest_rect.right,
786 dest_rect.top, dest_rect.bottom );
789 if( !(p_dest = GXBeginDraw()) )
792 msg_Err( p_vout, "GXBeginDraw error %d ", GetLastError() );
797 p_src += (dest_rect.left - video_rect.left) * gxdisplayprop.cbxPitch +
798 (dest_rect.top - video_rect.top) * p_pic->p->i_pitch;
799 p_dest += dest_rect.left * gxdisplayprop.cbxPitch +
800 dest_rect.top * gxdisplayprop.cbyPitch;
801 i_width = dest_rect.right - dest_rect.left;
802 i_height = dest_rect.bottom - dest_rect.top;
804 p_pic->p->p_pixels = p_dest;
810 static int GAPIUnlockSurface( vout_thread_t *p_vout, picture_t *p_pic )
816 static void DisplayGAPI( vout_thread_t *p_vout, picture_t *p_pic )
820 static void FirstDisplayGAPI( vout_thread_t *p_vout, picture_t *p_pic )
822 /* get initial picture presented through D3D */
823 DisplayGAPI(p_vout, p_pic);
826 ** Video window is initially hidden, show it now since we got a
829 SetWindowPos( p_vout->p_sys->hvideownd, 0, 0, 0, 0, 0,
837 /* use and restores proper display function for further pictures */
838 p_vout->pf_display = DisplayGAPI;
844 #undef rect_src_clipped
846 #undef rect_dest_clipped
847 /*****************************************************************************
848 * SetPalette: sets an 8 bpp palette
849 *****************************************************************************/
850 static void SetPalette( vout_thread_t *p_vout,
851 uint16_t *red, uint16_t *green, uint16_t *blue )
853 msg_Err( p_vout, "FIXME: SetPalette unimplemented" );
856 /*****************************************************************************
857 * InitBuffers: initialize an offscreen bitmap for direct buffer operations.
858 *****************************************************************************/
859 static void InitBuffers( vout_thread_t *p_vout )
861 BITMAPINFOHEADER *p_header = &p_vout->p_sys->bitmapinfo.bmiHeader;
862 BITMAPINFO *p_info = &p_vout->p_sys->bitmapinfo;
863 HDC window_dc = GetDC( p_vout->p_sys->hvideownd );
865 /* Get screen properties */
866 #ifdef MODULE_NAME_IS_wingapi
867 GXDisplayProperties gx_displayprop = GXGetDisplayProperties();
868 p_vout->p_sys->i_depth = gx_displayprop.cBPP;
870 p_vout->p_sys->i_depth = GetDeviceCaps( window_dc, PLANES ) *
871 GetDeviceCaps( window_dc, BITSPIXEL );
873 msg_Dbg( p_vout, "GDI depth is %i", p_vout->p_sys->i_depth );
875 #ifdef MODULE_NAME_IS_wingapi
876 GXOpenDisplay( p_vout->p_sys->hvideownd, GX_FULLSCREEN );
880 /* Initialize offscreen bitmap */
881 memset( p_info, 0, sizeof( BITMAPINFO ) + 3 * sizeof( RGBQUAD ) );
883 p_header->biSize = sizeof( BITMAPINFOHEADER );
884 p_header->biSizeImage = 0;
885 p_header->biPlanes = 1;
886 switch( p_vout->p_sys->i_depth )
889 p_header->biBitCount = 8;
890 p_header->biCompression = BI_RGB;
891 /* FIXME: we need a palette here */
894 p_header->biBitCount = 15;
895 p_header->biCompression = BI_BITFIELDS;//BI_RGB;
896 ((DWORD*)p_info->bmiColors)[0] = 0x00007c00;
897 ((DWORD*)p_info->bmiColors)[1] = 0x000003e0;
898 ((DWORD*)p_info->bmiColors)[2] = 0x0000001f;
901 p_header->biBitCount = 16;
902 p_header->biCompression = BI_BITFIELDS;//BI_RGB;
903 ((DWORD*)p_info->bmiColors)[0] = 0x0000f800;
904 ((DWORD*)p_info->bmiColors)[1] = 0x000007e0;
905 ((DWORD*)p_info->bmiColors)[2] = 0x0000001f;
908 p_header->biBitCount = 24;
909 p_header->biCompression = BI_RGB;
910 ((DWORD*)p_info->bmiColors)[0] = 0x00ff0000;
911 ((DWORD*)p_info->bmiColors)[1] = 0x0000ff00;
912 ((DWORD*)p_info->bmiColors)[2] = 0x000000ff;
915 p_header->biBitCount = 32;
916 p_header->biCompression = BI_RGB;
917 ((DWORD*)p_info->bmiColors)[0] = 0x00ff0000;
918 ((DWORD*)p_info->bmiColors)[1] = 0x0000ff00;
919 ((DWORD*)p_info->bmiColors)[2] = 0x000000ff;
922 msg_Err( p_vout, "screen depth %i not supported",
923 p_vout->p_sys->i_depth );
927 p_header->biWidth = p_vout->render.i_width;
928 p_header->biHeight = -p_vout->render.i_height;
929 p_header->biClrImportant = 0;
930 p_header->biClrUsed = 0;
931 p_header->biXPelsPerMeter = 0;
932 p_header->biYPelsPerMeter = 0;
934 p_vout->p_sys->i_pic_pixel_pitch = p_header->biBitCount / 8;
935 p_vout->p_sys->i_pic_pitch = p_header->biBitCount * p_header->biWidth / 8;
937 p_vout->p_sys->off_bitmap =
938 CreateDIBSection( window_dc, (BITMAPINFO *)p_header, DIB_RGB_COLORS,
939 (void**)&p_vout->p_sys->p_pic_buffer, NULL, 0 );
941 p_vout->p_sys->off_dc = CreateCompatibleDC( window_dc );
943 SelectObject( p_vout->p_sys->off_dc, p_vout->p_sys->off_bitmap );
944 ReleaseDC( p_vout->p_sys->hvideownd, window_dc );