]> git.sesse.net Git - vlc/blob - modules/video_output/msw/wingdi.c
41fb2c7360f5a666836b878b88ef334cfacf2812
[vlc] / modules / video_output / msw / wingdi.c
1 /*****************************************************************************
2  * wingdi.c : Win32 / WinCE GDI video output plugin for vlc
3  *****************************************************************************
4  * Copyright (C) 2002-2009 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Gildas Bazin <gbazin@videolan.org>
8  *          Samuel Hocevar <sam@zoy.org>
9  *
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.
14  *
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.
19  *
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  *****************************************************************************/
24
25 /*****************************************************************************
26  * Preamble
27  *****************************************************************************/
28
29 #ifdef HAVE_CONFIG_H
30 # include "config.h"
31 #endif
32
33 #include <vlc_common.h>
34 #include <vlc_plugin.h>
35 #include <vlc_interface.h>
36 #include <vlc_playlist.h>
37 #include <vlc_vout.h>
38
39 #include <windows.h>
40 #include <tchar.h>
41 #include <commctrl.h>
42
43 #include "vout.h"
44
45 #define MAX_DIRECTBUFFERS 10
46
47 #ifndef WS_NONAVDONEBUTTON
48 #define WS_NONAVDONEBUTTON 0
49 #endif
50 /*****************************************************************************
51  * Local prototypes
52  *****************************************************************************/
53 static int  OpenVideo  ( vlc_object_t * );
54 static void CloseVideo ( vlc_object_t * );
55
56 static int  Init      ( vout_thread_t * );
57 static void End       ( vout_thread_t * );
58 static int  Manage    ( vout_thread_t * );
59 static void Render    ( vout_thread_t *, picture_t * );
60 #ifdef MODULE_NAME_IS_wingapi
61 static void FirstDisplayGAPI( vout_thread_t *, picture_t * );
62 static void DisplayGAPI( vout_thread_t *, picture_t * );
63 static int GAPILockSurface( vout_thread_t *, picture_t * );
64 static int GAPIUnlockSurface( vout_thread_t *, picture_t * );
65 #else
66 static void FirstDisplayGDI( vout_thread_t *, picture_t * );
67 static void DisplayGDI( vout_thread_t *, picture_t * );
68 #endif
69 static void SetPalette( vout_thread_t *, uint16_t *, uint16_t *, uint16_t * );
70
71 static void InitBuffers        ( vout_thread_t * );
72
73
74
75 #define DX_POSITION_CHANGE 0x1000
76
77 /*****************************************************************************
78  * Module descriptor
79  *****************************************************************************/
80 vlc_module_begin ()
81     set_category( CAT_VIDEO )
82     set_subcategory( SUBCAT_VIDEO_VOUT )
83 #ifdef MODULE_NAME_IS_wingapi
84     set_shortname( "Windows GAPI" )
85     set_description( N_("Windows GAPI video output") )
86     set_capability( "video output", 20 )
87 #else
88     set_shortname( "Windows GDI" )
89     set_description( N_("Windows GDI video output") )
90     set_capability( "video output", 10 )
91 #endif
92     set_callbacks( OpenVideo, CloseVideo )
93 vlc_module_end ()
94
95 /*****************************************************************************
96  * OpenVideo: activate GDI video thread output method
97  *****************************************************************************/
98 static int OpenVideo ( vlc_object_t *p_this )
99 {
100     vout_thread_t * p_vout = (vout_thread_t *)p_this;
101
102     p_vout->p_sys = (vout_sys_t *)calloc( 1, sizeof(vout_sys_t) );
103     if( !p_vout->p_sys ) return VLC_ENOMEM;
104
105 #ifdef MODULE_NAME_IS_wingapi
106     /* Load GAPI */
107     p_vout->p_sys->gapi_dll = LoadLibrary( _T("GX.DLL") );
108     if( p_vout->p_sys->gapi_dll == NULL )
109     {
110         msg_Warn( p_vout, "failed loading gx.dll" );
111         free( p_vout->p_sys );
112         return VLC_EGENERIC;
113     }
114
115     GXOpenDisplay = (void *)GetProcAddress( p_vout->p_sys->gapi_dll,
116         _T("?GXOpenDisplay@@YAHPAUHWND__@@K@Z") );
117     GXCloseDisplay = (void *)GetProcAddress( p_vout->p_sys->gapi_dll,
118         _T("?GXCloseDisplay@@YAHXZ") );
119     GXBeginDraw = (void *)GetProcAddress( p_vout->p_sys->gapi_dll,
120         _T("?GXBeginDraw@@YAPAXXZ") );
121     GXEndDraw = (void *)GetProcAddress( p_vout->p_sys->gapi_dll,
122         _T("?GXEndDraw@@YAHXZ") );
123     GXGetDisplayProperties = (void *)GetProcAddress( p_vout->p_sys->gapi_dll,
124         _T("?GXGetDisplayProperties@@YA?AUGXDisplayProperties@@XZ") );
125     GXSuspend = (void *)GetProcAddress( p_vout->p_sys->gapi_dll,
126         _T("?GXSuspend@@YAHXZ") );
127     GXResume = GetProcAddress( p_vout->p_sys->gapi_dll,
128         _T("?GXResume@@YAHXZ") );
129
130     if( !GXOpenDisplay || !GXCloseDisplay || !GXBeginDraw || !GXEndDraw ||
131         !GXGetDisplayProperties || !GXSuspend || !GXResume )
132     {
133         msg_Err( p_vout, "failed GetProcAddress on gapi.dll" );
134         free( p_vout->p_sys );
135         return VLC_EGENERIC;
136     }
137
138     msg_Dbg( p_vout, "GAPI DLL loaded" );
139
140     p_vout->p_sys->render_width = p_vout->render.i_width;
141     p_vout->p_sys->render_height = p_vout->render.i_height;
142 #endif
143
144     p_vout->p_sys->p_event = (vlc_object_t *)
145         vlc_object_create( p_vout, sizeof( vlc_object_t ) );
146     if( !p_vout->p_sys->p_event )
147     {
148         free( p_vout->p_sys );
149         return VLC_ENOMEM;
150     }
151
152     p_vout->pf_init = Init;
153     p_vout->pf_end = End;
154     p_vout->pf_manage = Manage;
155     p_vout->pf_render = Render;
156 #ifdef MODULE_NAME_IS_wingapi
157     p_vout->pf_display = FirstDisplayGAPI;
158
159     p_vout->p_sys->b_focus = 0;
160     p_vout->p_sys->b_parent_focus = 0;
161
162 #else
163     p_vout->pf_display = FirstDisplayGDI;
164 #endif
165
166     p_vout->p_sys->hwnd = p_vout->p_sys->hvideownd = NULL;
167     p_vout->p_sys->hparent = p_vout->p_sys->hfswnd = NULL;
168     p_vout->p_sys->i_changes = 0;
169     vlc_mutex_init( &p_vout->p_sys->lock );
170     SetRectEmpty( &p_vout->p_sys->rect_display );
171     SetRectEmpty( &p_vout->p_sys->rect_parent );
172
173     var_Create( p_vout, "video-title", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
174     var_Create( p_vout, "disable-screensaver", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
175
176     p_vout->p_sys->b_cursor_hidden = 0;
177     p_vout->p_sys->i_lastmoved = mdate();
178     p_vout->p_sys->i_mouse_hide_timeout =
179         var_GetInteger(p_vout, "mouse-hide-timeout") * 1000;
180
181     /* Set main window's size */
182     p_vout->p_sys->i_window_width = p_vout->i_window_width;
183     p_vout->p_sys->i_window_height = p_vout->i_window_height;
184
185     if ( CreateEventThread( p_vout ) )
186     {
187
188 #ifndef UNDER_CE
189         /* Variable to indicate if the window should be on top of others */
190         /* Trigger a callback right now */
191         var_TriggerCallback( p_vout, "video-on-top" );
192
193         DisableScreensaver ( p_vout );
194 #endif
195         return VLC_SUCCESS;
196     }
197     else
198     {
199         CloseVideo( VLC_OBJECT(p_vout) );
200         return VLC_EGENERIC;
201     }
202 }
203
204 /*****************************************************************************
205  * CloseVideo: deactivate the GDI video output
206  *****************************************************************************/
207 static void CloseVideo ( vlc_object_t *p_this )
208 {
209     vout_thread_t * p_vout = (vout_thread_t *)p_this;
210
211     StopEventThread( p_vout );
212
213 #ifndef UNDER_CE
214     RestoreScreensaver( p_vout );
215 #endif
216
217 #ifdef MODULE_NAME_IS_wingapi
218     FreeLibrary( p_vout->p_sys->gapi_dll );
219 #endif
220
221     free( p_vout->p_sys );
222     p_vout->p_sys = NULL;
223 }
224
225 /*****************************************************************************
226  * Init: initialize video thread output method
227  *****************************************************************************/
228 static int Init( vout_thread_t *p_vout )
229 {
230     picture_t *p_pic;
231
232     /* Initialize offscreen buffer */
233     InitBuffers( p_vout );
234
235     p_vout->p_sys->rect_display.left = 0;
236     p_vout->p_sys->rect_display.top = 0;
237     p_vout->p_sys->rect_display.right  = GetSystemMetrics(SM_CXSCREEN);
238     p_vout->p_sys->rect_display.bottom = GetSystemMetrics(SM_CYSCREEN);
239
240     I_OUTPUTPICTURES = 0;
241
242     /* Initialize the output structure */
243     switch( p_vout->p_sys->i_depth )
244     {
245     case 8:
246         p_vout->output.i_chroma = VLC_CODEC_RGB8;
247         p_vout->output.pf_setpalette = SetPalette;
248         break;
249     case 15:
250         p_vout->output.i_chroma = VLC_CODEC_RGB15;
251         p_vout->output.i_rmask  = 0x7c00;
252         p_vout->output.i_gmask  = 0x03e0;
253         p_vout->output.i_bmask  = 0x001f;
254         break;
255     case 16:
256         p_vout->output.i_chroma = VLC_CODEC_RGB16;
257         p_vout->output.i_rmask  = 0xf800;
258         p_vout->output.i_gmask  = 0x07e0;
259         p_vout->output.i_bmask  = 0x001f;
260         break;
261     case 24:
262         p_vout->output.i_chroma = VLC_CODEC_RGB24;
263         p_vout->output.i_rmask  = 0x00ff0000;
264         p_vout->output.i_gmask  = 0x0000ff00;
265         p_vout->output.i_bmask  = 0x000000ff;
266         break;
267     case 32:
268         p_vout->output.i_chroma = VLC_CODEC_RGB32;
269         p_vout->output.i_rmask  = 0x00ff0000;
270         p_vout->output.i_gmask  = 0x0000ff00;
271         p_vout->output.i_bmask  = 0x000000ff;
272         break;
273     default:
274         msg_Err( p_vout, "screen depth %i not supported",
275                  p_vout->p_sys->i_depth );
276         return VLC_EGENERIC;
277         break;
278     }
279
280     p_pic = &p_vout->p_picture[0];
281
282 #ifdef MODULE_NAME_IS_wingapi
283     p_vout->output.i_width  = 0;
284     p_vout->output.i_height = 0;
285     p_pic->pf_lock  = GAPILockSurface;
286     p_pic->pf_unlock = GAPIUnlockSurface;
287     Manage( p_vout );
288     GAPILockSurface( p_vout, p_pic );
289     p_vout->i_changes = 0;
290     p_vout->output.i_width  = p_vout->p_sys->render_width;
291     p_vout->output.i_height = p_vout->p_sys->render_height;
292
293 #else
294     p_vout->output.i_width  = p_vout->render.i_width;
295     p_vout->output.i_height = p_vout->render.i_height;
296
297     p_vout->fmt_out = p_vout->fmt_in;
298     p_vout->fmt_out.i_chroma = p_vout->output.i_chroma;
299 #endif
300
301     p_vout->output.i_aspect = p_vout->render.i_aspect;
302
303     p_pic->p->p_pixels = p_vout->p_sys->p_pic_buffer;
304     p_pic->p->i_lines = p_vout->output.i_height;
305     p_pic->p->i_visible_lines = p_vout->output.i_height;
306     p_pic->p->i_pitch = p_vout->p_sys->i_pic_pitch;
307     p_pic->p->i_pixel_pitch = p_vout->p_sys->i_pic_pixel_pitch;
308     p_pic->p->i_visible_pitch = p_vout->output.i_width *
309         p_pic->p->i_pixel_pitch;
310     p_pic->i_planes = 1;
311     p_pic->i_status = DESTROYED_PICTURE;
312     p_pic->i_type   = DIRECT_PICTURE;
313
314     PP_OUTPUTPICTURE[ I_OUTPUTPICTURES++ ] = p_pic;
315
316     /* Change the window title bar text */
317     PostMessage( p_vout->p_sys->hwnd, WM_VLC_CHANGE_TEXT, 0, 0 );
318     UpdateRects( p_vout, true );
319
320     return VLC_SUCCESS;
321 }
322
323 /*****************************************************************************
324  * End: terminate video thread output method
325  *****************************************************************************/
326 static void End( vout_thread_t *p_vout )
327 {
328 #ifdef MODULE_NAME_IS_wingapi
329     GXCloseDisplay();
330 #else
331     DeleteDC( p_vout->p_sys->off_dc );
332     DeleteObject( p_vout->p_sys->off_bitmap );
333 #endif
334 }
335
336 /*****************************************************************************
337  * Manage: handle events
338  *****************************************************************************
339  * This function should be called regularly by video output thread. It manages
340  * console events. It returns a non null value on error.
341  *****************************************************************************/
342 static int Manage( vout_thread_t *p_vout )
343 {
344     /* If we do not control our window, we check for geometry changes
345      * ourselves because the parent might not send us its events. */
346     vlc_mutex_lock( &p_vout->p_sys->lock );
347     if( p_vout->p_sys->hparent && !p_vout->b_fullscreen )
348     {
349         RECT rect_parent;
350         POINT point;
351
352         vlc_mutex_unlock( &p_vout->p_sys->lock );
353
354         GetClientRect( p_vout->p_sys->hparent, &rect_parent );
355         point.x = point.y = 0;
356         ClientToScreen( p_vout->p_sys->hparent, &point );
357         OffsetRect( &rect_parent, point.x, point.y );
358
359         if( !EqualRect( &rect_parent, &p_vout->p_sys->rect_parent ) )
360         {
361             unsigned int i_x, i_y, i_width, i_height;
362             p_vout->p_sys->rect_parent = rect_parent;
363
364             /* This one is to force the update even if only
365              * the position has changed */
366             SetWindowPos( p_vout->p_sys->hwnd, 0, 1, 1,
367                           rect_parent.right - rect_parent.left,
368                           rect_parent.bottom - rect_parent.top, 0 );
369
370             SetWindowPos( p_vout->p_sys->hwnd, 0, 0, 0,
371                           rect_parent.right - rect_parent.left,
372                           rect_parent.bottom - rect_parent.top, 0 );
373
374             vout_PlacePicture( p_vout, rect_parent.right - rect_parent.left,
375                                rect_parent.bottom - rect_parent.top,
376                                &i_x, &i_y, &i_width, &i_height );
377
378             SetWindowPos( p_vout->p_sys->hvideownd, HWND_TOP,
379                           i_x, i_y, i_width, i_height, 0 );
380         }
381     }
382     else
383     {
384         vlc_mutex_unlock( &p_vout->p_sys->lock );
385     }
386
387     /* autoscale toggle */
388     if( p_vout->i_changes & VOUT_SCALE_CHANGE )
389     {
390         p_vout->i_changes &= ~VOUT_SCALE_CHANGE;
391
392         p_vout->b_autoscale = var_GetBool( p_vout, "autoscale" );
393         p_vout->i_zoom = (int) ZOOM_FP_FACTOR;
394
395         UpdateRects( p_vout, true );
396     }
397
398     /* scaling factor */
399     if( p_vout->i_changes & VOUT_ZOOM_CHANGE )
400     {
401         p_vout->i_changes &= ~VOUT_ZOOM_CHANGE;
402
403         p_vout->b_autoscale = false;
404         p_vout->i_zoom =
405             (int)( ZOOM_FP_FACTOR * var_GetFloat( p_vout, "scale" ) );
406         UpdateRects( p_vout, true );
407     }
408
409     /* Check for cropping / aspect changes */
410     if( p_vout->i_changes & VOUT_CROP_CHANGE ||
411         p_vout->i_changes & VOUT_ASPECT_CHANGE )
412     {
413         p_vout->i_changes &= ~VOUT_CROP_CHANGE;
414         p_vout->i_changes &= ~VOUT_ASPECT_CHANGE;
415
416         p_vout->fmt_out.i_x_offset = p_vout->fmt_in.i_x_offset;
417         p_vout->fmt_out.i_y_offset = p_vout->fmt_in.i_y_offset;
418         p_vout->fmt_out.i_visible_width = p_vout->fmt_in.i_visible_width;
419         p_vout->fmt_out.i_visible_height = p_vout->fmt_in.i_visible_height;
420         p_vout->fmt_out.i_aspect = p_vout->fmt_in.i_aspect;
421         p_vout->fmt_out.i_sar_num = p_vout->fmt_in.i_sar_num;
422         p_vout->fmt_out.i_sar_den = p_vout->fmt_in.i_sar_den;
423         p_vout->output.i_aspect = p_vout->fmt_in.i_aspect;
424         UpdateRects( p_vout, true );
425     }
426
427     /*
428      * Position Change
429      */
430     if( p_vout->p_sys->i_changes & DX_POSITION_CHANGE )
431     {
432         p_vout->p_sys->i_changes &= ~DX_POSITION_CHANGE;
433     }
434
435     /* We used to call the Win32 PeekMessage function here to read the window
436      * messages. But since window can stay blocked into this function for a
437      * long time (for example when you move your window on the screen), I
438      * decided to isolate PeekMessage in another thread. */
439
440     /*
441      * Fullscreen change
442      */
443     if( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE
444         || p_vout->p_sys->i_changes & VOUT_FULLSCREEN_CHANGE )
445     {
446         Win32ToggleFullscreen( p_vout );
447
448         p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
449         p_vout->p_sys->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
450     }
451
452     /*
453      * Pointer change
454      */
455     if( p_vout->b_fullscreen && !p_vout->p_sys->b_cursor_hidden &&
456         (mdate() - p_vout->p_sys->i_lastmoved) >
457             p_vout->p_sys->i_mouse_hide_timeout )
458     {
459         POINT point;
460         HWND hwnd;
461
462         /* Hide the cursor only if it is inside our window */
463         GetCursorPos( &point );
464         hwnd = WindowFromPoint(point);
465         if( hwnd == p_vout->p_sys->hwnd || hwnd == p_vout->p_sys->hvideownd )
466         {
467             PostMessage( p_vout->p_sys->hwnd, WM_VLC_HIDE_MOUSE, 0, 0 );
468         }
469         else
470         {
471             p_vout->p_sys->i_lastmoved = mdate();
472         }
473     }
474
475     /*
476      * "Always on top" status change
477      */
478     if( p_vout->p_sys->b_on_top_change )
479     {
480         vlc_value_t val;
481         HMENU hMenu = GetSystemMenu( p_vout->p_sys->hwnd, FALSE );
482
483         var_Get( p_vout, "video-on-top", &val );
484
485         /* Set the window on top if necessary */
486         if( val.b_bool && !( GetWindowLong( p_vout->p_sys->hwnd, GWL_EXSTYLE )
487                            & WS_EX_TOPMOST ) )
488         {
489             CheckMenuItem( hMenu, IDM_TOGGLE_ON_TOP,
490                            MF_BYCOMMAND | MFS_CHECKED );
491             SetWindowPos( p_vout->p_sys->hwnd, HWND_TOPMOST, 0, 0, 0, 0,
492                           SWP_NOSIZE | SWP_NOMOVE );
493         }
494         else
495         /* The window shouldn't be on top */
496         if( !val.b_bool && ( GetWindowLong( p_vout->p_sys->hwnd, GWL_EXSTYLE )
497                            & WS_EX_TOPMOST ) )
498         {
499             CheckMenuItem( hMenu, IDM_TOGGLE_ON_TOP,
500                            MF_BYCOMMAND | MFS_UNCHECKED );
501             SetWindowPos( p_vout->p_sys->hwnd, HWND_NOTOPMOST, 0, 0, 0, 0,
502                           SWP_NOSIZE | SWP_NOMOVE );
503         }
504
505         p_vout->p_sys->b_on_top_change = false;
506     }
507
508     /* Check if the event thread is still running */
509     if( !vlc_object_alive (p_vout->p_sys->p_event) )
510     {
511         return VLC_EGENERIC; /* exit */
512     }
513
514     return VLC_SUCCESS;
515 }
516
517 /*****************************************************************************
518  * Render: render previously calculated output
519  *****************************************************************************/
520 static void Render( vout_thread_t *p_vout, picture_t *p_pic )
521 {
522     /* No need to do anything, the fake direct buffers stay as they are */
523     (void)p_vout;
524     (void)p_pic;
525 }
526
527 /*****************************************************************************
528  * Display: displays previously rendered output
529  *****************************************************************************/
530 #define rect_src p_vout->p_sys->rect_src
531 #define rect_src_clipped p_vout->p_sys->rect_src_clipped
532 #define rect_dest p_vout->p_sys->rect_dest
533 #define rect_dest_clipped p_vout->p_sys->rect_dest_clipped
534
535 #ifndef MODULE_NAME_IS_wingapi
536 static void DisplayGDI( vout_thread_t *p_vout, picture_t *p_pic )
537 {
538     VLC_UNUSED( p_pic );
539
540     vout_sys_t *p_sys = p_vout->p_sys;
541     RECT rect_dst = rect_dest_clipped;
542     HDC hdc = GetDC( p_sys->hvideownd );
543
544     OffsetRect( &rect_dst, -rect_dest.left, -rect_dest.top );
545     SelectObject( p_sys->off_dc, p_sys->off_bitmap );
546
547     if( rect_dest_clipped.right - rect_dest_clipped.left !=
548         rect_src_clipped.right - rect_src_clipped.left ||
549         rect_dest_clipped.bottom - rect_dest_clipped.top !=
550         rect_src_clipped.bottom - rect_src_clipped.top )
551     {
552         StretchBlt( hdc, rect_dst.left, rect_dst.top,
553                     rect_dst.right, rect_dst.bottom,
554                     p_sys->off_dc, rect_src_clipped.left, rect_src_clipped.top,
555                     rect_src_clipped.right, rect_src_clipped.bottom, SRCCOPY );
556     }
557     else
558     {
559         BitBlt( hdc, rect_dst.left, rect_dst.top,
560                 rect_dst.right, rect_dst.bottom,
561                 p_sys->off_dc, rect_src_clipped.left,
562                 rect_src_clipped.top, SRCCOPY );
563     }
564
565     ReleaseDC( p_sys->hvideownd, hdc );
566 }
567
568 static void FirstDisplayGDI( vout_thread_t *p_vout, picture_t *p_pic )
569 {
570     /*
571     ** Video window is initially hidden, show it now since we got a
572     ** picture to show.
573     */
574     SetWindowPos( p_vout->p_sys->hvideownd, 0, 0, 0, 0, 0,
575         SWP_ASYNCWINDOWPOS|
576         SWP_FRAMECHANGED|
577         SWP_SHOWWINDOW|
578         SWP_NOMOVE|
579         SWP_NOSIZE|
580         SWP_NOZORDER );
581
582     /* get initial picture presented */
583     DisplayGDI(p_vout, p_pic);
584
585     /* use and restores proper display function for further pictures */
586     p_vout->pf_display = DisplayGDI;
587 }
588
589 #else
590
591 static int GAPILockSurface( vout_thread_t *p_vout, picture_t *p_pic )
592 {
593     vout_sys_t *p_sys = p_vout->p_sys;
594     int i_x, i_y, i_width, i_height;
595     RECT video_rect;
596     POINT point;
597
598     GetClientRect( p_sys->hwnd, &video_rect);
599     vout_PlacePicture( p_vout, video_rect.right - video_rect.left,
600                        video_rect.bottom - video_rect.top,
601                        &i_x, &i_y, &i_width, &i_height );
602     point.x = point.y = 0;
603     ClientToScreen( p_sys->hwnd, &point );
604     i_x += point.x + video_rect.left;
605     i_y += point.y + video_rect.top;
606
607     if( i_width != p_vout->output.i_width ||
608         i_height != p_vout->output.i_height )
609     {
610         GXDisplayProperties gxdisplayprop = GXGetDisplayProperties();
611
612         p_sys->render_width = i_width;
613         p_sys->render_height = i_height;
614         p_vout->i_changes |= VOUT_SIZE_CHANGE;
615
616         msg_Dbg( p_vout, "vout size change (%ix%i -> %ix%i)",
617                  i_width, i_height, p_vout->output.i_width,
618                  p_vout->output.i_height );
619
620         p_vout->p_sys->i_pic_pixel_pitch = gxdisplayprop.cbxPitch;
621         p_vout->p_sys->i_pic_pitch = gxdisplayprop.cbyPitch;
622         return VLC_EGENERIC;
623     }
624     else
625     {
626         GXDisplayProperties gxdisplayprop;
627         RECT display_rect, dest_rect;
628         uint8_t *p_dest, *p_src = p_pic->p->p_pixels;
629
630         video_rect.left = i_x; video_rect.top = i_y;
631         video_rect.right = i_x + i_width;
632         video_rect.bottom = i_y + i_height;
633
634         gxdisplayprop = GXGetDisplayProperties();
635         display_rect.left = 0; display_rect.top = 0;
636         display_rect.right = gxdisplayprop.cxWidth;
637         display_rect.bottom = gxdisplayprop.cyHeight;
638
639         if( !IntersectRect( &dest_rect, &video_rect, &display_rect ) )
640         {
641             return VLC_EGENERIC;
642         }
643
644 #ifndef NDEBUG
645         msg_Dbg( p_vout, "video (%d,%d,%d,%d) display (%d,%d,%d,%d) "
646                  "dest (%d,%d,%d,%d)",
647                  video_rect.left, video_rect.right,
648                  video_rect.top, video_rect.bottom,
649                  display_rect.left, display_rect.right,
650                  display_rect.top, display_rect.bottom,
651                  dest_rect.left, dest_rect.right,
652                  dest_rect.top, dest_rect.bottom );
653 #endif
654
655         if( !(p_dest = GXBeginDraw()) )
656         {
657 #ifndef NDEBUG
658             msg_Err( p_vout, "GXBeginDraw error %d ", GetLastError() );
659 #endif
660             return VLC_EGENERIC;
661         }
662
663         p_src += (dest_rect.left - video_rect.left) * gxdisplayprop.cbxPitch +
664             (dest_rect.top - video_rect.top) * p_pic->p->i_pitch;
665         p_dest += dest_rect.left * gxdisplayprop.cbxPitch +
666             dest_rect.top * gxdisplayprop.cbyPitch;
667         i_width = dest_rect.right - dest_rect.left;
668         i_height = dest_rect.bottom - dest_rect.top;
669
670         p_pic->p->p_pixels = p_dest;
671     }
672
673     return VLC_SUCCESS;
674 }
675
676 static int GAPIUnlockSurface( vout_thread_t *p_vout, picture_t *p_pic )
677 {
678     GXEndDraw();
679     return VLC_SUCCESS;
680 }
681
682 static void DisplayGAPI( vout_thread_t *p_vout, picture_t *p_pic )
683 {
684 }
685
686 static void FirstDisplayGAPI( vout_thread_t *p_vout, picture_t *p_pic )
687 {
688     /* get initial picture presented through D3D */
689     DisplayGAPI(p_vout, p_pic);
690
691     /*
692     ** Video window is initially hidden, show it now since we got a
693     ** picture to show.
694     */
695     SetWindowPos( p_vout->p_sys->hvideownd, 0, 0, 0, 0, 0,
696         SWP_ASYNCWINDOWPOS|
697         SWP_FRAMECHANGED|
698         SWP_SHOWWINDOW|
699         SWP_NOMOVE|
700         SWP_NOSIZE|
701         SWP_NOZORDER );
702
703     /* use and restores proper display function for further pictures */
704     p_vout->pf_display = DisplayGAPI;
705 }
706
707 #endif
708
709 #undef rect_src
710 #undef rect_src_clipped
711 #undef rect_dest
712 #undef rect_dest_clipped
713 /*****************************************************************************
714  * SetPalette: sets an 8 bpp palette
715  *****************************************************************************/
716 static void SetPalette( vout_thread_t *p_vout,
717                         uint16_t *red, uint16_t *green, uint16_t *blue )
718 {
719     VLC_UNUSED( red ); VLC_UNUSED( green );VLC_UNUSED( blue );
720     msg_Err( p_vout, "FIXME: SetPalette unimplemented" );
721 }
722
723 /*****************************************************************************
724  * InitBuffers: initialize an offscreen bitmap for direct buffer operations.
725  *****************************************************************************/
726 static void InitBuffers( vout_thread_t *p_vout )
727 {
728     BITMAPINFOHEADER *p_header = &p_vout->p_sys->bitmapinfo.bmiHeader;
729     BITMAPINFO *p_info = &p_vout->p_sys->bitmapinfo;
730     HDC window_dc = GetDC( p_vout->p_sys->hvideownd );
731
732     /* Get screen properties */
733 #ifdef MODULE_NAME_IS_wingapi
734     GXDisplayProperties gx_displayprop = GXGetDisplayProperties();
735     p_vout->p_sys->i_depth = gx_displayprop.cBPP;
736 #else
737     p_vout->p_sys->i_depth = GetDeviceCaps( window_dc, PLANES ) *
738         GetDeviceCaps( window_dc, BITSPIXEL );
739 #endif
740     msg_Dbg( p_vout, "GDI depth is %i", p_vout->p_sys->i_depth );
741
742 #ifdef MODULE_NAME_IS_wingapi
743     GXOpenDisplay( p_vout->p_sys->hvideownd, GX_FULLSCREEN );
744
745 #else
746
747     /* Initialize offscreen bitmap */
748     memset( p_info, 0, sizeof( BITMAPINFO ) + 3 * sizeof( RGBQUAD ) );
749
750     p_header->biSize = sizeof( BITMAPINFOHEADER );
751     p_header->biSizeImage = 0;
752     p_header->biPlanes = 1;
753     switch( p_vout->p_sys->i_depth )
754     {
755     case 8:
756         p_header->biBitCount = 8;
757         p_header->biCompression = BI_RGB;
758         /* FIXME: we need a palette here */
759         break;
760     case 15:
761         p_header->biBitCount = 15;
762         p_header->biCompression = BI_BITFIELDS;//BI_RGB;
763         ((DWORD*)p_info->bmiColors)[0] = 0x00007c00;
764         ((DWORD*)p_info->bmiColors)[1] = 0x000003e0;
765         ((DWORD*)p_info->bmiColors)[2] = 0x0000001f;
766         break;
767     case 16:
768         p_header->biBitCount = 16;
769         p_header->biCompression = BI_BITFIELDS;//BI_RGB;
770         ((DWORD*)p_info->bmiColors)[0] = 0x0000f800;
771         ((DWORD*)p_info->bmiColors)[1] = 0x000007e0;
772         ((DWORD*)p_info->bmiColors)[2] = 0x0000001f;
773         break;
774     case 24:
775         p_header->biBitCount = 24;
776         p_header->biCompression = BI_RGB;
777         ((DWORD*)p_info->bmiColors)[0] = 0x00ff0000;
778         ((DWORD*)p_info->bmiColors)[1] = 0x0000ff00;
779         ((DWORD*)p_info->bmiColors)[2] = 0x000000ff;
780         break;
781     case 32:
782         p_header->biBitCount = 32;
783         p_header->biCompression = BI_RGB;
784         ((DWORD*)p_info->bmiColors)[0] = 0x00ff0000;
785         ((DWORD*)p_info->bmiColors)[1] = 0x0000ff00;
786         ((DWORD*)p_info->bmiColors)[2] = 0x000000ff;
787         break;
788     default:
789         msg_Err( p_vout, "screen depth %i not supported",
790                  p_vout->p_sys->i_depth );
791         return;
792         break;
793     }
794     p_header->biWidth = p_vout->render.i_width;
795     p_header->biHeight = -p_vout->render.i_height;
796     p_header->biClrImportant = 0;
797     p_header->biClrUsed = 0;
798     p_header->biXPelsPerMeter = 0;
799     p_header->biYPelsPerMeter = 0;
800
801     p_vout->p_sys->i_pic_pixel_pitch = p_header->biBitCount / 8;
802     p_vout->p_sys->i_pic_pitch = p_header->biBitCount * p_header->biWidth / 8;
803
804     p_vout->p_sys->off_bitmap =
805         CreateDIBSection( window_dc, (BITMAPINFO *)p_header, DIB_RGB_COLORS,
806                           (void**)&p_vout->p_sys->p_pic_buffer, NULL, 0 );
807
808     p_vout->p_sys->off_dc = CreateCompatibleDC( window_dc );
809
810     SelectObject( p_vout->p_sys->off_dc, p_vout->p_sys->off_bitmap );
811     ReleaseDC( p_vout->p_sys->hvideownd, window_dc );
812 #endif
813 }
814