1 /*****************************************************************************
2 * wingdi.c : Win32 / WinCE GDI video output plugin for vlc
3 *****************************************************************************
4 * Copyright (C) 2002 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>
41 /*#ifdef MODULE_NAME_IS_wingapi
42 typedef struct GXDisplayProperties {
49 } GXDisplayProperties;
51 typedef struct GXScreenRect {
58 # define GX_FULLSCREEN 0x01
59 # define GX_NORMALKEYS 0x02
60 # define GX_LANDSCAPEKEYS 0x03
63 # define kfLandscape 0x8
64 # define kfPalette 0x10
65 # define kfDirect 0x20
66 # define kfDirect555 0x40
67 # define kfDirect565 0x80
68 # define kfDirect888 0x100
69 # define kfDirect444 0x200
70 # define kfDirectInverted 0x400
72 #endif /* MODULE_NAME_IS_wingapi */
76 #define MAX_DIRECTBUFFERS 10
79 #ifndef WS_OVERLAPPEDWINDOW
80 # define WS_OVERLAPPEDWINDOW 0xcf0000
82 #ifndef WS_EX_NOPARENTNOTIFY
83 # define WS_EX_NOPARENTNOTIFY 4
85 #ifndef WS_EX_APPWINDOW
86 #define WS_EX_APPWINDOW 0x40000
88 //#define SetWindowLongPtr SetWindowLong
89 //#define GetWindowLongPtr GetWindowLong
90 //#define GWLP_USERDATA GWL_USERDATA
91 #define AdjustWindowRect(a,b,c)
94 #ifndef WS_NONAVDONEBUTTON
95 #define WS_NONAVDONEBUTTON 0
97 /*****************************************************************************
99 *****************************************************************************/
100 static int OpenVideo ( vlc_object_t * );
101 static void CloseVideo ( vlc_object_t * );
103 static int Init ( vout_thread_t * );
104 static void End ( vout_thread_t * );
105 static int Manage ( vout_thread_t * );
106 static void Render ( vout_thread_t *, picture_t * );
107 #ifdef MODULE_NAME_IS_wingapi
108 static void FirstDisplayGAPI( vout_thread_t *, picture_t * );
109 static void DisplayGAPI( vout_thread_t *, picture_t * );
110 static int GAPILockSurface( vout_thread_t *, picture_t * );
111 static int GAPIUnlockSurface( vout_thread_t *, picture_t * );
113 static void FirstDisplayGDI( vout_thread_t *, picture_t * );
114 static void DisplayGDI( vout_thread_t *, picture_t * );
116 static void SetPalette( vout_thread_t *, uint16_t *, uint16_t *, uint16_t * );
118 static void InitBuffers ( vout_thread_t * );
120 #ifdef MODULE_NAME_IS_wingapi
121 # define GXOpenDisplay p_vout->p_sys->GXOpenDisplay
122 # define GXCloseDisplay p_vout->p_sys->GXCloseDisplay
123 # define GXBeginDraw p_vout->p_sys->GXBeginDraw
124 # define GXEndDraw p_vout->p_sys->GXEndDraw
125 # define GXGetDisplayProperties p_vout->p_sys->GXGetDisplayProperties
126 # define GXSuspend p_vout->p_sys->GXSuspend
127 # define GXResume p_vout->p_sys->GXResume
130 #define DX_POSITION_CHANGE 0x1000
132 /*****************************************************************************
134 *****************************************************************************/
136 set_category( CAT_VIDEO )
137 set_subcategory( SUBCAT_VIDEO_VOUT )
138 #ifdef MODULE_NAME_IS_wingapi
139 set_shortname( "Windows GAPI" )
140 set_description( N_("Windows GAPI video output") )
141 set_capability( "video output", 20 )
143 set_shortname( "Windows GDI" )
144 set_description( N_("Windows GDI video output") )
145 set_capability( "video output", 10 )
147 set_callbacks( OpenVideo, CloseVideo )
150 /*****************************************************************************
151 * OpenVideo: activate GDI video thread output method
152 *****************************************************************************/
153 static int OpenVideo ( vlc_object_t *p_this )
155 vout_thread_t * p_vout = (vout_thread_t *)p_this;
158 p_vout->p_sys = (vout_sys_t *)malloc( sizeof(vout_sys_t) );
159 if( !p_vout->p_sys ) return VLC_ENOMEM;
160 memset( p_vout->p_sys, 0, sizeof( vout_sys_t ) );
162 #ifdef MODULE_NAME_IS_wingapi
164 p_vout->p_sys->gapi_dll = LoadLibrary( _T("GX.DLL") );
165 if( p_vout->p_sys->gapi_dll == NULL )
167 msg_Warn( p_vout, "failed loading gx.dll" );
168 free( p_vout->p_sys );
172 GXOpenDisplay = (void *)GetProcAddress( p_vout->p_sys->gapi_dll,
173 _T("?GXOpenDisplay@@YAHPAUHWND__@@K@Z") );
174 GXCloseDisplay = (void *)GetProcAddress( p_vout->p_sys->gapi_dll,
175 _T("?GXCloseDisplay@@YAHXZ") );
176 GXBeginDraw = (void *)GetProcAddress( p_vout->p_sys->gapi_dll,
177 _T("?GXBeginDraw@@YAPAXXZ") );
178 GXEndDraw = (void *)GetProcAddress( p_vout->p_sys->gapi_dll,
179 _T("?GXEndDraw@@YAHXZ") );
180 GXGetDisplayProperties = (void *)GetProcAddress( p_vout->p_sys->gapi_dll,
181 _T("?GXGetDisplayProperties@@YA?AUGXDisplayProperties@@XZ") );
182 GXSuspend = (void *)GetProcAddress( p_vout->p_sys->gapi_dll,
183 _T("?GXSuspend@@YAHXZ") );
184 GXResume = GetProcAddress( p_vout->p_sys->gapi_dll,
185 _T("?GXResume@@YAHXZ") );
187 if( !GXOpenDisplay || !GXCloseDisplay || !GXBeginDraw || !GXEndDraw ||
188 !GXGetDisplayProperties || !GXSuspend || !GXResume )
190 msg_Err( p_vout, "failed GetProcAddress on gapi.dll" );
191 free( p_vout->p_sys );
195 msg_Dbg( p_vout, "GAPI DLL loaded" );
197 p_vout->p_sys->render_width = p_vout->render.i_width;
198 p_vout->p_sys->render_height = p_vout->render.i_height;
201 p_vout->p_sys->p_event = (vlc_object_t *)
202 vlc_object_create( p_vout, sizeof( vlc_object_t ) );
203 if( !p_vout->p_sys->p_event )
205 free( p_vout->p_sys );
209 p_vout->pf_init = Init;
210 p_vout->pf_end = End;
211 p_vout->pf_manage = Manage;
212 p_vout->pf_render = Render;
213 #ifdef MODULE_NAME_IS_wingapi
214 p_vout->pf_display = FirstDisplayGAPI;
216 p_vout->p_sys->b_focus = 0;
217 p_vout->p_sys->b_parent_focus = 0;
220 p_vout->pf_display = FirstDisplayGDI;
223 p_vout->p_sys->hwnd = p_vout->p_sys->hvideownd = NULL;
224 p_vout->p_sys->hparent = p_vout->p_sys->hfswnd = NULL;
225 p_vout->p_sys->i_changes = 0;
226 vlc_mutex_init( &p_vout->p_sys->lock );
227 SetRectEmpty( &p_vout->p_sys->rect_display );
228 SetRectEmpty( &p_vout->p_sys->rect_parent );
230 var_Create( p_vout, "video-title", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
231 var_Create( p_vout, "disable-screensaver", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
233 p_vout->p_sys->b_cursor_hidden = 0;
234 p_vout->p_sys->i_lastmoved = mdate();
235 p_vout->p_sys->i_mouse_hide_timeout =
236 var_GetInteger(p_vout, "mouse-hide-timeout") * 1000;
238 /* Set main window's size */
239 p_vout->p_sys->i_window_width = p_vout->i_window_width;
240 p_vout->p_sys->i_window_height = p_vout->i_window_height;
242 /* Create the EventThread, this thread is created by us to isolate
243 * the Win32 PeekMessage function calls. We want to do this because
244 * Windows can stay blocked inside this call for a long time, and when
245 * this happens it thus blocks vlc's video_output thread.
246 * Vout EventThread will take care of the creation of the video
247 * window (because PeekMessage has to be called from the same thread which
248 * created the window). */
249 msg_Dbg( p_vout, "creating Vout EventThread" );
250 p_vout->p_sys->p_event =
251 vlc_object_create( p_vout, sizeof(event_thread_t) );
252 p_vout->p_sys->p_event->p_vout = p_vout;
253 if( vlc_thread_create( p_vout->p_sys->p_event, "VLC Vout Events Thread",
254 EventThread, 0, 1 ) )
256 msg_Err( p_vout, "cannot create Vout EventThread" );
257 vlc_object_release( p_vout->p_sys->p_event );
258 p_vout->p_sys->p_event = NULL;
262 if( p_vout->p_sys->p_event->b_error )
264 msg_Err( p_vout, "Vout EventThread failed" );
268 vlc_object_attach( p_vout->p_sys->p_event, p_vout );
270 msg_Dbg( p_vout, "Vout EventThread running" );
273 /* Variable to indicate if the window should be on top of others */
274 /* Trigger a callback right now */
275 var_Get( p_vout, "video-on-top", &val );
276 var_Set( p_vout, "video-on-top", val );
278 /* disable screensaver by temporarily changing system settings */
279 p_vout->p_sys->i_spi_lowpowertimeout = 0;
280 p_vout->p_sys->i_spi_powerofftimeout = 0;
281 p_vout->p_sys->i_spi_screensavetimeout = 0;
282 var_Get( p_vout, "disable-screensaver", &val);
284 msg_Dbg(p_vout, "disabling screen saver");
285 SystemParametersInfo(SPI_GETLOWPOWERTIMEOUT,
286 0, &(p_vout->p_sys->i_spi_lowpowertimeout), 0);
287 if( 0 != p_vout->p_sys->i_spi_lowpowertimeout ) {
288 SystemParametersInfo(SPI_SETLOWPOWERTIMEOUT, 0, NULL, 0);
290 SystemParametersInfo(SPI_GETPOWEROFFTIMEOUT, 0,
291 &(p_vout->p_sys->i_spi_powerofftimeout), 0);
292 if( 0 != p_vout->p_sys->i_spi_powerofftimeout ) {
293 SystemParametersInfo(SPI_SETPOWEROFFTIMEOUT, 0, NULL, 0);
295 SystemParametersInfo(SPI_GETSCREENSAVETIMEOUT, 0,
296 &(p_vout->p_sys->i_spi_screensavetimeout), 0);
297 if( 0 != p_vout->p_sys->i_spi_screensavetimeout ) {
298 SystemParametersInfo(SPI_SETSCREENSAVETIMEOUT, 0, NULL, 0);
305 CloseVideo( VLC_OBJECT(p_vout) );
309 /*****************************************************************************
310 * CloseVideo: deactivate the GDI video output
311 *****************************************************************************/
312 static void CloseVideo ( vlc_object_t *p_this )
314 vout_thread_t * p_vout = (vout_thread_t *)p_this;
316 if( p_vout->b_fullscreen )
318 msg_Dbg( p_vout, "Quitting fullscreen" );
319 Win32ToggleFullscreen( p_vout );
320 /* Force fullscreen in the core for the next video */
321 var_SetBool( p_vout, "fullscreen", true );
324 if( p_vout->p_sys->p_event )
326 vlc_object_detach( p_vout->p_sys->p_event );
328 /* Kill Vout EventThread */
329 vlc_object_kill( p_vout->p_sys->p_event );
331 /* we need to be sure Vout EventThread won't stay stuck in
332 * GetMessage, so we send a fake message */
333 if( p_vout->p_sys->hwnd )
335 PostMessage( p_vout->p_sys->hwnd, WM_NULL, 0, 0);
338 vlc_thread_join( p_vout->p_sys->p_event );
339 vlc_object_release( p_vout->p_sys->p_event );
341 vlc_mutex_destroy( &p_vout->p_sys->lock );
344 /* restore screensaver system settings */
345 if( 0 != p_vout->p_sys->i_spi_lowpowertimeout ) {
346 SystemParametersInfo(SPI_SETLOWPOWERTIMEOUT,
347 p_vout->p_sys->i_spi_lowpowertimeout, NULL, 0);
349 if( 0 != p_vout->p_sys->i_spi_powerofftimeout ) {
350 SystemParametersInfo(SPI_SETPOWEROFFTIMEOUT,
351 p_vout->p_sys->i_spi_powerofftimeout, NULL, 0);
353 if( 0 != p_vout->p_sys->i_spi_screensavetimeout ) {
354 SystemParametersInfo(SPI_SETSCREENSAVETIMEOUT,
355 p_vout->p_sys->i_spi_screensavetimeout, NULL, 0);
359 #ifdef MODULE_NAME_IS_wingapi
360 FreeLibrary( p_vout->p_sys->gapi_dll );
363 free( p_vout->p_sys );
364 p_vout->p_sys = NULL;
367 /*****************************************************************************
368 * Init: initialize video thread output method
369 *****************************************************************************/
370 static int Init( vout_thread_t *p_vout )
374 /* Initialize offscreen buffer */
375 InitBuffers( p_vout );
377 p_vout->p_sys->rect_display.left = 0;
378 p_vout->p_sys->rect_display.top = 0;
379 p_vout->p_sys->rect_display.right = GetSystemMetrics(SM_CXSCREEN);
380 p_vout->p_sys->rect_display.bottom = GetSystemMetrics(SM_CYSCREEN);
382 I_OUTPUTPICTURES = 0;
384 /* Initialize the output structure */
385 switch( p_vout->p_sys->i_depth )
388 p_vout->output.i_chroma = VLC_FOURCC('R','G','B','2');
389 p_vout->output.pf_setpalette = SetPalette;
392 p_vout->output.i_chroma = VLC_FOURCC('R','V','1','5');
393 p_vout->output.i_rmask = 0x7c00;
394 p_vout->output.i_gmask = 0x03e0;
395 p_vout->output.i_bmask = 0x001f;
398 p_vout->output.i_chroma = VLC_FOURCC('R','V','1','6');
399 p_vout->output.i_rmask = 0xf800;
400 p_vout->output.i_gmask = 0x07e0;
401 p_vout->output.i_bmask = 0x001f;
404 p_vout->output.i_chroma = VLC_FOURCC('R','V','2','4');
405 p_vout->output.i_rmask = 0x00ff0000;
406 p_vout->output.i_gmask = 0x0000ff00;
407 p_vout->output.i_bmask = 0x000000ff;
410 p_vout->output.i_chroma = VLC_FOURCC('R','V','3','2');
411 p_vout->output.i_rmask = 0x00ff0000;
412 p_vout->output.i_gmask = 0x0000ff00;
413 p_vout->output.i_bmask = 0x000000ff;
416 msg_Err( p_vout, "screen depth %i not supported",
417 p_vout->p_sys->i_depth );
422 p_pic = &p_vout->p_picture[0];
424 #ifdef MODULE_NAME_IS_wingapi
425 p_vout->output.i_width = 0;
426 p_vout->output.i_height = 0;
427 p_pic->pf_lock = GAPILockSurface;
428 p_pic->pf_unlock = GAPIUnlockSurface;
430 GAPILockSurface( p_vout, p_pic );
431 p_vout->i_changes = 0;
432 p_vout->output.i_width = p_vout->p_sys->render_width;
433 p_vout->output.i_height = p_vout->p_sys->render_height;
436 p_vout->output.i_width = p_vout->render.i_width;
437 p_vout->output.i_height = p_vout->render.i_height;
439 p_vout->fmt_out = p_vout->fmt_in;
440 p_vout->fmt_out.i_chroma = p_vout->output.i_chroma;
443 p_vout->output.i_aspect = p_vout->render.i_aspect;
445 p_pic->p->p_pixels = p_vout->p_sys->p_pic_buffer;
446 p_pic->p->i_lines = p_vout->output.i_height;
447 p_pic->p->i_visible_lines = p_vout->output.i_height;
448 p_pic->p->i_pitch = p_vout->p_sys->i_pic_pitch;
449 p_pic->p->i_pixel_pitch = p_vout->p_sys->i_pic_pixel_pitch;
450 p_pic->p->i_visible_pitch = p_vout->output.i_width *
451 p_pic->p->i_pixel_pitch;
453 p_pic->i_status = DESTROYED_PICTURE;
454 p_pic->i_type = DIRECT_PICTURE;
456 PP_OUTPUTPICTURE[ I_OUTPUTPICTURES++ ] = p_pic;
458 /* Change the window title bar text */
459 PostMessage( p_vout->p_sys->hwnd, WM_VLC_CHANGE_TEXT, 0, 0 );
460 UpdateRects( p_vout, true );
465 /*****************************************************************************
466 * End: terminate video thread output method
467 *****************************************************************************/
468 static void End( vout_thread_t *p_vout )
470 #ifdef MODULE_NAME_IS_wingapi
473 DeleteDC( p_vout->p_sys->off_dc );
474 DeleteObject( p_vout->p_sys->off_bitmap );
478 /*****************************************************************************
479 * Manage: handle events
480 *****************************************************************************
481 * This function should be called regularly by video output thread. It manages
482 * console events. It returns a non null value on error.
483 *****************************************************************************/
484 static int Manage( vout_thread_t *p_vout )
486 /* If we do not control our window, we check for geometry changes
487 * ourselves because the parent might not send us its events. */
488 vlc_mutex_lock( &p_vout->p_sys->lock );
489 if( p_vout->p_sys->hparent && !p_vout->b_fullscreen )
494 vlc_mutex_unlock( &p_vout->p_sys->lock );
496 GetClientRect( p_vout->p_sys->hparent, &rect_parent );
497 point.x = point.y = 0;
498 ClientToScreen( p_vout->p_sys->hparent, &point );
499 OffsetRect( &rect_parent, point.x, point.y );
501 if( !EqualRect( &rect_parent, &p_vout->p_sys->rect_parent ) )
503 int i_x, i_y, i_width, i_height;
504 p_vout->p_sys->rect_parent = rect_parent;
506 /* This one is to force the update even if only
507 * the position has changed */
508 SetWindowPos( p_vout->p_sys->hwnd, 0, 1, 1,
509 rect_parent.right - rect_parent.left,
510 rect_parent.bottom - rect_parent.top, 0 );
512 SetWindowPos( p_vout->p_sys->hwnd, 0, 0, 0,
513 rect_parent.right - rect_parent.left,
514 rect_parent.bottom - rect_parent.top, 0 );
516 vout_PlacePicture( p_vout, rect_parent.right - rect_parent.left,
517 rect_parent.bottom - rect_parent.top,
518 &i_x, &i_y, &i_width, &i_height );
520 SetWindowPos( p_vout->p_sys->hvideownd, HWND_TOP,
521 i_x, i_y, i_width, i_height, 0 );
526 vlc_mutex_unlock( &p_vout->p_sys->lock );
529 /* Check for cropping / aspect changes */
530 if( p_vout->i_changes & VOUT_CROP_CHANGE ||
531 p_vout->i_changes & VOUT_ASPECT_CHANGE )
533 p_vout->i_changes &= ~VOUT_CROP_CHANGE;
534 p_vout->i_changes &= ~VOUT_ASPECT_CHANGE;
536 p_vout->fmt_out.i_x_offset = p_vout->fmt_in.i_x_offset;
537 p_vout->fmt_out.i_y_offset = p_vout->fmt_in.i_y_offset;
538 p_vout->fmt_out.i_visible_width = p_vout->fmt_in.i_visible_width;
539 p_vout->fmt_out.i_visible_height = p_vout->fmt_in.i_visible_height;
540 p_vout->fmt_out.i_aspect = p_vout->fmt_in.i_aspect;
541 p_vout->fmt_out.i_sar_num = p_vout->fmt_in.i_sar_num;
542 p_vout->fmt_out.i_sar_den = p_vout->fmt_in.i_sar_den;
543 p_vout->output.i_aspect = p_vout->fmt_in.i_aspect;
544 UpdateRects( p_vout, true );
550 if( p_vout->p_sys->i_changes & DX_POSITION_CHANGE )
552 p_vout->p_sys->i_changes &= ~DX_POSITION_CHANGE;
555 /* We used to call the Win32 PeekMessage function here to read the window
556 * messages. But since window can stay blocked into this function for a
557 * long time (for example when you move your window on the screen), I
558 * decided to isolate PeekMessage in another thread. */
563 if( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE
564 || p_vout->p_sys->i_changes & VOUT_FULLSCREEN_CHANGE )
566 Win32ToggleFullscreen( p_vout );
568 p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
569 p_vout->p_sys->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
575 if( p_vout->b_fullscreen && !p_vout->p_sys->b_cursor_hidden &&
576 (mdate() - p_vout->p_sys->i_lastmoved) >
577 p_vout->p_sys->i_mouse_hide_timeout )
582 /* Hide the cursor only if it is inside our window */
583 GetCursorPos( &point );
584 hwnd = WindowFromPoint(point);
585 if( hwnd == p_vout->p_sys->hwnd || hwnd == p_vout->p_sys->hvideownd )
587 PostMessage( p_vout->p_sys->hwnd, WM_VLC_HIDE_MOUSE, 0, 0 );
591 p_vout->p_sys->i_lastmoved = mdate();
596 * "Always on top" status change
598 if( p_vout->p_sys->b_on_top_change )
601 HMENU hMenu = GetSystemMenu( p_vout->p_sys->hwnd, FALSE );
603 var_Get( p_vout, "video-on-top", &val );
605 /* Set the window on top if necessary */
606 if( val.b_bool && !( GetWindowLong( p_vout->p_sys->hwnd, GWL_EXSTYLE )
609 CheckMenuItem( hMenu, IDM_TOGGLE_ON_TOP,
610 MF_BYCOMMAND | MFS_CHECKED );
611 SetWindowPos( p_vout->p_sys->hwnd, HWND_TOPMOST, 0, 0, 0, 0,
612 SWP_NOSIZE | SWP_NOMOVE );
615 /* The window shouldn't be on top */
616 if( !val.b_bool && ( GetWindowLong( p_vout->p_sys->hwnd, GWL_EXSTYLE )
619 CheckMenuItem( hMenu, IDM_TOGGLE_ON_TOP,
620 MF_BYCOMMAND | MFS_UNCHECKED );
621 SetWindowPos( p_vout->p_sys->hwnd, HWND_NOTOPMOST, 0, 0, 0, 0,
622 SWP_NOSIZE | SWP_NOMOVE );
625 p_vout->p_sys->b_on_top_change = false;
628 /* Check if the event thread is still running */
629 if( !vlc_object_alive (p_vout->p_sys->p_event) )
631 return VLC_EGENERIC; /* exit */
637 /*****************************************************************************
638 * Render: render previously calculated output
639 *****************************************************************************/
640 static void Render( vout_thread_t *p_vout, picture_t *p_pic )
642 /* No need to do anything, the fake direct buffers stay as they are */
647 /*****************************************************************************
648 * Display: displays previously rendered output
649 *****************************************************************************/
650 #define rect_src p_vout->p_sys->rect_src
651 #define rect_src_clipped p_vout->p_sys->rect_src_clipped
652 #define rect_dest p_vout->p_sys->rect_dest
653 #define rect_dest_clipped p_vout->p_sys->rect_dest_clipped
655 #ifndef MODULE_NAME_IS_wingapi
656 static void DisplayGDI( vout_thread_t *p_vout, picture_t *p_pic )
658 vout_sys_t *p_sys = p_vout->p_sys;
659 RECT rect_dst = rect_dest_clipped;
660 HDC hdc = GetDC( p_sys->hvideownd );
662 OffsetRect( &rect_dst, -rect_dest.left, -rect_dest.top );
663 SelectObject( p_sys->off_dc, p_sys->off_bitmap );
665 if( rect_dest_clipped.right - rect_dest_clipped.left !=
666 rect_src_clipped.right - rect_src_clipped.left ||
667 rect_dest_clipped.bottom - rect_dest_clipped.top !=
668 rect_src_clipped.bottom - rect_src_clipped.top )
670 StretchBlt( hdc, rect_dst.left, rect_dst.top,
671 rect_dst.right, rect_dst.bottom,
672 p_sys->off_dc, rect_src_clipped.left, rect_src_clipped.top,
673 rect_src_clipped.right, rect_src_clipped.bottom, SRCCOPY );
677 BitBlt( hdc, rect_dst.left, rect_dst.top,
678 rect_dst.right, rect_dst.bottom,
679 p_sys->off_dc, rect_src_clipped.left,
680 rect_src_clipped.top, SRCCOPY );
683 ReleaseDC( p_sys->hvideownd, hdc );
686 static void FirstDisplayGDI( vout_thread_t *p_vout, picture_t *p_pic )
689 ** Video window is initially hidden, show it now since we got a
692 SetWindowPos( p_vout->p_sys->hvideownd, 0, 0, 0, 0, 0,
700 /* get initial picture presented */
701 DisplayGDI(p_vout, p_pic);
703 /* use and restores proper display function for further pictures */
704 p_vout->pf_display = DisplayGDI;
709 static int GAPILockSurface( vout_thread_t *p_vout, picture_t *p_pic )
711 vout_sys_t *p_sys = p_vout->p_sys;
712 int i_x, i_y, i_width, i_height;
716 GetClientRect( p_sys->hwnd, &video_rect);
717 vout_PlacePicture( p_vout, video_rect.right - video_rect.left,
718 video_rect.bottom - video_rect.top,
719 &i_x, &i_y, &i_width, &i_height );
720 point.x = point.y = 0;
721 ClientToScreen( p_sys->hwnd, &point );
722 i_x += point.x + video_rect.left;
723 i_y += point.y + video_rect.top;
725 if( i_width != p_vout->output.i_width ||
726 i_height != p_vout->output.i_height )
728 GXDisplayProperties gxdisplayprop = GXGetDisplayProperties();
730 p_sys->render_width = i_width;
731 p_sys->render_height = i_height;
732 p_vout->i_changes |= VOUT_SIZE_CHANGE;
734 msg_Dbg( p_vout, "vout size change (%ix%i -> %ix%i)",
735 i_width, i_height, p_vout->output.i_width,
736 p_vout->output.i_height );
738 p_vout->p_sys->i_pic_pixel_pitch = gxdisplayprop.cbxPitch;
739 p_vout->p_sys->i_pic_pitch = gxdisplayprop.cbyPitch;
744 GXDisplayProperties gxdisplayprop;
745 RECT display_rect, dest_rect;
746 uint8_t *p_dest, *p_src = p_pic->p->p_pixels;
748 video_rect.left = i_x; video_rect.top = i_y;
749 video_rect.right = i_x + i_width;
750 video_rect.bottom = i_y + i_height;
752 gxdisplayprop = GXGetDisplayProperties();
753 display_rect.left = 0; display_rect.top = 0;
754 display_rect.right = gxdisplayprop.cxWidth;
755 display_rect.bottom = gxdisplayprop.cyHeight;
757 if( !IntersectRect( &dest_rect, &video_rect, &display_rect ) )
763 msg_Err( p_vout, "video (%d,%d,%d,%d) display (%d,%d,%d,%d) "
764 "dest (%d,%d,%d,%d)",
765 video_rect.left, video_rect.right,
766 video_rect.top, video_rect.bottom,
767 display_rect.left, display_rect.right,
768 display_rect.top, display_rect.bottom,
769 dest_rect.left, dest_rect.right,
770 dest_rect.top, dest_rect.bottom );
773 if( !(p_dest = GXBeginDraw()) )
776 msg_Err( p_vout, "GXBeginDraw error %d ", GetLastError() );
781 p_src += (dest_rect.left - video_rect.left) * gxdisplayprop.cbxPitch +
782 (dest_rect.top - video_rect.top) * p_pic->p->i_pitch;
783 p_dest += dest_rect.left * gxdisplayprop.cbxPitch +
784 dest_rect.top * gxdisplayprop.cbyPitch;
785 i_width = dest_rect.right - dest_rect.left;
786 i_height = dest_rect.bottom - dest_rect.top;
788 p_pic->p->p_pixels = p_dest;
794 static int GAPIUnlockSurface( vout_thread_t *p_vout, picture_t *p_pic )
800 static void DisplayGAPI( vout_thread_t *p_vout, picture_t *p_pic )
804 static void FirstDisplayGAPI( vout_thread_t *p_vout, picture_t *p_pic )
806 /* get initial picture presented through D3D */
807 DisplayGAPI(p_vout, p_pic);
810 ** Video window is initially hidden, show it now since we got a
813 SetWindowPos( p_vout->p_sys->hvideownd, 0, 0, 0, 0, 0,
821 /* use and restores proper display function for further pictures */
822 p_vout->pf_display = DisplayGAPI;
828 #undef rect_src_clipped
830 #undef rect_dest_clipped
831 /*****************************************************************************
832 * SetPalette: sets an 8 bpp palette
833 *****************************************************************************/
834 static void SetPalette( vout_thread_t *p_vout,
835 uint16_t *red, uint16_t *green, uint16_t *blue )
837 msg_Err( p_vout, "FIXME: SetPalette unimplemented" );
840 /*****************************************************************************
841 * InitBuffers: initialize an offscreen bitmap for direct buffer operations.
842 *****************************************************************************/
843 static void InitBuffers( vout_thread_t *p_vout )
845 BITMAPINFOHEADER *p_header = &p_vout->p_sys->bitmapinfo.bmiHeader;
846 BITMAPINFO *p_info = &p_vout->p_sys->bitmapinfo;
847 HDC window_dc = GetDC( p_vout->p_sys->hvideownd );
849 /* Get screen properties */
850 #ifdef MODULE_NAME_IS_wingapi
851 GXDisplayProperties gx_displayprop = GXGetDisplayProperties();
852 p_vout->p_sys->i_depth = gx_displayprop.cBPP;
854 p_vout->p_sys->i_depth = GetDeviceCaps( window_dc, PLANES ) *
855 GetDeviceCaps( window_dc, BITSPIXEL );
857 msg_Dbg( p_vout, "GDI depth is %i", p_vout->p_sys->i_depth );
859 #ifdef MODULE_NAME_IS_wingapi
860 GXOpenDisplay( p_vout->p_sys->hvideownd, GX_FULLSCREEN );
864 /* Initialize offscreen bitmap */
865 memset( p_info, 0, sizeof( BITMAPINFO ) + 3 * sizeof( RGBQUAD ) );
867 p_header->biSize = sizeof( BITMAPINFOHEADER );
868 p_header->biSizeImage = 0;
869 p_header->biPlanes = 1;
870 switch( p_vout->p_sys->i_depth )
873 p_header->biBitCount = 8;
874 p_header->biCompression = BI_RGB;
875 /* FIXME: we need a palette here */
878 p_header->biBitCount = 15;
879 p_header->biCompression = BI_BITFIELDS;//BI_RGB;
880 ((DWORD*)p_info->bmiColors)[0] = 0x00007c00;
881 ((DWORD*)p_info->bmiColors)[1] = 0x000003e0;
882 ((DWORD*)p_info->bmiColors)[2] = 0x0000001f;
885 p_header->biBitCount = 16;
886 p_header->biCompression = BI_BITFIELDS;//BI_RGB;
887 ((DWORD*)p_info->bmiColors)[0] = 0x0000f800;
888 ((DWORD*)p_info->bmiColors)[1] = 0x000007e0;
889 ((DWORD*)p_info->bmiColors)[2] = 0x0000001f;
892 p_header->biBitCount = 24;
893 p_header->biCompression = BI_RGB;
894 ((DWORD*)p_info->bmiColors)[0] = 0x00ff0000;
895 ((DWORD*)p_info->bmiColors)[1] = 0x0000ff00;
896 ((DWORD*)p_info->bmiColors)[2] = 0x000000ff;
899 p_header->biBitCount = 32;
900 p_header->biCompression = BI_RGB;
901 ((DWORD*)p_info->bmiColors)[0] = 0x00ff0000;
902 ((DWORD*)p_info->bmiColors)[1] = 0x0000ff00;
903 ((DWORD*)p_info->bmiColors)[2] = 0x000000ff;
906 msg_Err( p_vout, "screen depth %i not supported",
907 p_vout->p_sys->i_depth );
911 p_header->biWidth = p_vout->render.i_width;
912 p_header->biHeight = -p_vout->render.i_height;
913 p_header->biClrImportant = 0;
914 p_header->biClrUsed = 0;
915 p_header->biXPelsPerMeter = 0;
916 p_header->biYPelsPerMeter = 0;
918 p_vout->p_sys->i_pic_pixel_pitch = p_header->biBitCount / 8;
919 p_vout->p_sys->i_pic_pitch = p_header->biBitCount * p_header->biWidth / 8;
921 p_vout->p_sys->off_bitmap =
922 CreateDIBSection( window_dc, (BITMAPINFO *)p_header, DIB_RGB_COLORS,
923 (void**)&p_vout->p_sys->p_pic_buffer, NULL, 0 );
925 p_vout->p_sys->off_dc = CreateCompatibleDC( window_dc );
927 SelectObject( p_vout->p_sys->off_dc, p_vout->p_sys->off_bitmap );
928 ReleaseDC( p_vout->p_sys->hvideownd, window_dc );