bafcc19e6f37eda0c2b88b5a7ead48163c734e69
[vlc.git] / 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_playlist.h>
36 #include <vlc_vout.h>
37
38 #include <windows.h>
39 #include <commctrl.h>
40
41 #include "vout.h"
42
43 #define MAX_DIRECTBUFFERS 10
44
45 #ifndef WS_NONAVDONEBUTTON
46 #define WS_NONAVDONEBUTTON 0
47 #endif
48 /*****************************************************************************
49  * Local prototypes
50  *****************************************************************************/
51 static int  OpenVideo  ( vlc_object_t * );
52 static void CloseVideo ( vlc_object_t * );
53
54 static int  Init      ( vout_thread_t * );
55 static void End       ( vout_thread_t * );
56 static int  Manage    ( vout_thread_t * );
57 static void Render    ( vout_thread_t *, picture_t * );
58 #ifdef MODULE_NAME_IS_wingapi
59 static void FirstDisplayGAPI( vout_thread_t *, picture_t * );
60 static void DisplayGAPI( vout_thread_t *, picture_t * );
61 static int GAPILockSurface( vout_thread_t *, picture_t * );
62 static int GAPIUnlockSurface( vout_thread_t *, picture_t * );
63 #else
64 static void FirstDisplayGDI( vout_thread_t *, picture_t * );
65 static void DisplayGDI( vout_thread_t *, picture_t * );
66 #endif
67 static void SetPalette( vout_thread_t *, uint16_t *, uint16_t *, uint16_t * );
68
69 static void InitBuffers        ( vout_thread_t * );
70
71 /*****************************************************************************
72  * Module descriptor
73  *****************************************************************************/
74 vlc_module_begin ()
75     set_category( CAT_VIDEO )
76     set_subcategory( SUBCAT_VIDEO_VOUT )
77 #ifdef MODULE_NAME_IS_wingapi
78     set_shortname( "Windows GAPI" )
79     set_description( N_("Windows GAPI video output") )
80     set_capability( "video output", 20 )
81 #else
82     set_shortname( "Windows GDI" )
83     set_description( N_("Windows GDI video output") )
84     set_capability( "video output", 10 )
85 #endif
86     set_callbacks( OpenVideo, CloseVideo )
87 vlc_module_end ()
88
89 /*****************************************************************************
90  * OpenVideo: activate GDI video thread output method
91  *****************************************************************************/
92 static int OpenVideo ( vlc_object_t *p_this )
93 {
94     vout_thread_t * p_vout = (vout_thread_t *)p_this;
95
96     p_vout->p_sys = (vout_sys_t *)calloc( 1, sizeof(vout_sys_t) );
97     if( !p_vout->p_sys ) return VLC_ENOMEM;
98
99 #ifdef MODULE_NAME_IS_wingapi
100     /* Load GAPI */
101     p_vout->p_sys->gapi_dll = LoadLibrary( _T("GX.DLL") );
102     if( p_vout->p_sys->gapi_dll == NULL )
103     {
104         msg_Warn( p_vout, "failed loading gx.dll" );
105         free( p_vout->p_sys );
106         return VLC_EGENERIC;
107     }
108
109     GXOpenDisplay = (void *)GetProcAddress( p_vout->p_sys->gapi_dll,
110         _T("?GXOpenDisplay@@YAHPAUHWND__@@K@Z") );
111     GXCloseDisplay = (void *)GetProcAddress( p_vout->p_sys->gapi_dll,
112         _T("?GXCloseDisplay@@YAHXZ") );
113     GXBeginDraw = (void *)GetProcAddress( p_vout->p_sys->gapi_dll,
114         _T("?GXBeginDraw@@YAPAXXZ") );
115     GXEndDraw = (void *)GetProcAddress( p_vout->p_sys->gapi_dll,
116         _T("?GXEndDraw@@YAHXZ") );
117     GXGetDisplayProperties = (void *)GetProcAddress( p_vout->p_sys->gapi_dll,
118         _T("?GXGetDisplayProperties@@YA?AUGXDisplayProperties@@XZ") );
119     GXSuspend = (void *)GetProcAddress( p_vout->p_sys->gapi_dll,
120         _T("?GXSuspend@@YAHXZ") );
121     GXResume = GetProcAddress( p_vout->p_sys->gapi_dll,
122         _T("?GXResume@@YAHXZ") );
123
124     if( !GXOpenDisplay || !GXCloseDisplay || !GXBeginDraw || !GXEndDraw ||
125         !GXGetDisplayProperties || !GXSuspend || !GXResume )
126     {
127         msg_Err( p_vout, "failed GetProcAddress on gapi.dll" );
128         free( p_vout->p_sys );
129         return VLC_EGENERIC;
130     }
131
132     msg_Dbg( p_vout, "GAPI DLL loaded" );
133
134     p_vout->p_sys->render_width = p_vout->render.i_width;
135     p_vout->p_sys->render_height = p_vout->render.i_height;
136 #endif
137
138     p_vout->pf_init = Init;
139     p_vout->pf_end = End;
140     p_vout->pf_manage = Manage;
141     p_vout->pf_render = Render;
142     p_vout->pf_control = Control;
143 #ifdef MODULE_NAME_IS_wingapi
144     p_vout->pf_display = FirstDisplayGAPI;
145 #else
146     p_vout->pf_display = FirstDisplayGDI;
147 #endif
148
149     if( CommonInit( p_vout ) )
150         goto error;
151
152     return VLC_SUCCESS;
153
154 error:
155     CloseVideo( VLC_OBJECT(p_vout) );
156     return VLC_EGENERIC;
157 }
158
159 /*****************************************************************************
160  * CloseVideo: deactivate the GDI video output
161  *****************************************************************************/
162 static void CloseVideo ( vlc_object_t *p_this )
163 {
164     vout_thread_t * p_vout = (vout_thread_t *)p_this;
165
166     CommonClean( p_vout );
167
168 #ifdef MODULE_NAME_IS_wingapi
169     FreeLibrary( p_vout->p_sys->gapi_dll );
170 #endif
171
172     free( p_vout->p_sys );
173 }
174
175 /*****************************************************************************
176  * Init: initialize video thread output method
177  *****************************************************************************/
178 static int Init( vout_thread_t *p_vout )
179 {
180     picture_t *p_pic;
181
182     /* Initialize offscreen buffer */
183     InitBuffers( p_vout );
184
185     p_vout->p_sys->rect_display.left = 0;
186     p_vout->p_sys->rect_display.top = 0;
187     p_vout->p_sys->rect_display.right  = GetSystemMetrics(SM_CXSCREEN);
188     p_vout->p_sys->rect_display.bottom = GetSystemMetrics(SM_CYSCREEN);
189
190     I_OUTPUTPICTURES = 0;
191
192     /* Initialize the output structure */
193     switch( p_vout->p_sys->i_depth )
194     {
195     case 8:
196         p_vout->output.i_chroma = VLC_CODEC_RGB8;
197         p_vout->output.pf_setpalette = SetPalette;
198         break;
199     case 15:
200         p_vout->output.i_chroma = VLC_CODEC_RGB15;
201         p_vout->output.i_rmask  = 0x7c00;
202         p_vout->output.i_gmask  = 0x03e0;
203         p_vout->output.i_bmask  = 0x001f;
204         break;
205     case 16:
206         p_vout->output.i_chroma = VLC_CODEC_RGB16;
207         p_vout->output.i_rmask  = 0xf800;
208         p_vout->output.i_gmask  = 0x07e0;
209         p_vout->output.i_bmask  = 0x001f;
210         break;
211     case 24:
212         p_vout->output.i_chroma = VLC_CODEC_RGB24;
213         p_vout->output.i_rmask  = 0x00ff0000;
214         p_vout->output.i_gmask  = 0x0000ff00;
215         p_vout->output.i_bmask  = 0x000000ff;
216         break;
217     case 32:
218         p_vout->output.i_chroma = VLC_CODEC_RGB32;
219         p_vout->output.i_rmask  = 0x00ff0000;
220         p_vout->output.i_gmask  = 0x0000ff00;
221         p_vout->output.i_bmask  = 0x000000ff;
222         break;
223     default:
224         msg_Err( p_vout, "screen depth %i not supported",
225                  p_vout->p_sys->i_depth );
226         return VLC_EGENERIC;
227         break;
228     }
229
230     p_pic = &p_vout->p_picture[0];
231
232 #ifdef MODULE_NAME_IS_wingapi
233     p_vout->output.i_width  = 0;
234     p_vout->output.i_height = 0;
235     p_pic->pf_lock  = GAPILockSurface;
236     p_pic->pf_unlock = GAPIUnlockSurface;
237     Manage( p_vout );
238     GAPILockSurface( p_vout, p_pic );
239     p_vout->i_changes = 0;
240     p_vout->output.i_width  = p_vout->p_sys->render_width;
241     p_vout->output.i_height = p_vout->p_sys->render_height;
242
243 #else
244     p_vout->output.i_width  = p_vout->render.i_width;
245     p_vout->output.i_height = p_vout->render.i_height;
246
247     p_vout->fmt_out = p_vout->fmt_in;
248     p_vout->fmt_out.i_chroma = p_vout->output.i_chroma;
249 #endif
250
251     p_vout->output.i_aspect = p_vout->render.i_aspect;
252
253     p_pic->p->p_pixels = p_vout->p_sys->p_pic_buffer;
254     p_pic->p->i_lines = p_vout->output.i_height;
255     p_pic->p->i_visible_lines = p_vout->output.i_height;
256     p_pic->p->i_pitch = p_vout->p_sys->i_pic_pitch;
257     p_pic->p->i_pixel_pitch = p_vout->p_sys->i_pic_pixel_pitch;
258     p_pic->p->i_visible_pitch = p_vout->output.i_width *
259         p_pic->p->i_pixel_pitch;
260     p_pic->i_planes = 1;
261     p_pic->i_status = DESTROYED_PICTURE;
262     p_pic->i_type   = DIRECT_PICTURE;
263
264     PP_OUTPUTPICTURE[ I_OUTPUTPICTURES++ ] = p_pic;
265
266     /* Change the window title bar text */
267 #ifdef MODULE_NAME_IS_wingapi
268     EventThreadUpdateTitle( p_vout->p_sys->p_event, VOUT_TITLE " (WinGAPI output)" );
269 #else
270     EventThreadUpdateTitle( p_vout->p_sys->p_event, VOUT_TITLE " (WinGDI output)" );
271 #endif
272     UpdateRects( p_vout, true );
273
274     return VLC_SUCCESS;
275 }
276
277 /*****************************************************************************
278  * End: terminate video thread output method
279  *****************************************************************************/
280 static void End( vout_thread_t *p_vout )
281 {
282 #ifdef MODULE_NAME_IS_wingapi
283     GXCloseDisplay();
284 #else
285     DeleteDC( p_vout->p_sys->off_dc );
286     DeleteObject( p_vout->p_sys->off_bitmap );
287 #endif
288 }
289
290 /*****************************************************************************
291  * Manage: handle events
292  *****************************************************************************
293  * This function should be called regularly by video output thread. It manages
294  * console events. It returns a non null value on error.
295  *****************************************************************************/
296 static int Manage( vout_thread_t *p_vout )
297 {
298     /*
299      * Position Change
300      */
301     if( p_vout->p_sys->i_changes & DX_POSITION_CHANGE )
302     {
303         p_vout->p_sys->i_changes &= ~DX_POSITION_CHANGE;
304     }
305
306     CommonManage( p_vout );
307
308     return VLC_SUCCESS;
309 }
310
311 /*****************************************************************************
312  * Render: render previously calculated output
313  *****************************************************************************/
314 static void Render( vout_thread_t *p_vout, picture_t *p_pic )
315 {
316     /* No need to do anything, the fake direct buffers stay as they are */
317     (void)p_vout;
318     (void)p_pic;
319 }
320
321 /*****************************************************************************
322  * Display: displays previously rendered output
323  *****************************************************************************/
324 #define rect_src p_vout->p_sys->rect_src
325 #define rect_src_clipped p_vout->p_sys->rect_src_clipped
326 #define rect_dest p_vout->p_sys->rect_dest
327 #define rect_dest_clipped p_vout->p_sys->rect_dest_clipped
328
329 #ifndef MODULE_NAME_IS_wingapi
330 static void DisplayGDI( vout_thread_t *p_vout, picture_t *p_pic )
331 {
332     VLC_UNUSED( p_pic );
333
334     vout_sys_t *p_sys = p_vout->p_sys;
335     RECT rect_dst = rect_dest_clipped;
336     HDC hdc = GetDC( p_sys->hvideownd );
337
338     OffsetRect( &rect_dst, -rect_dest.left, -rect_dest.top );
339     SelectObject( p_sys->off_dc, p_sys->off_bitmap );
340
341     if( rect_dest_clipped.right - rect_dest_clipped.left !=
342         rect_src_clipped.right - rect_src_clipped.left ||
343         rect_dest_clipped.bottom - rect_dest_clipped.top !=
344         rect_src_clipped.bottom - rect_src_clipped.top )
345     {
346         StretchBlt( hdc, rect_dst.left, rect_dst.top,
347                     rect_dst.right, rect_dst.bottom,
348                     p_sys->off_dc, rect_src_clipped.left, rect_src_clipped.top,
349                     rect_src_clipped.right, rect_src_clipped.bottom, SRCCOPY );
350     }
351     else
352     {
353         BitBlt( hdc, rect_dst.left, rect_dst.top,
354                 rect_dst.right, rect_dst.bottom,
355                 p_sys->off_dc, rect_src_clipped.left,
356                 rect_src_clipped.top, SRCCOPY );
357     }
358
359     ReleaseDC( p_sys->hvideownd, hdc );
360 }
361
362 static void FirstDisplayGDI( vout_thread_t *p_vout, picture_t *p_pic )
363 {
364     /*
365     ** Video window is initially hidden, show it now since we got a
366     ** picture to show.
367     */
368     SetWindowPos( p_vout->p_sys->hvideownd, 0, 0, 0, 0, 0,
369         SWP_ASYNCWINDOWPOS|
370         SWP_FRAMECHANGED|
371         SWP_SHOWWINDOW|
372         SWP_NOMOVE|
373         SWP_NOSIZE|
374         SWP_NOZORDER );
375
376     /* get initial picture presented */
377     DisplayGDI(p_vout, p_pic);
378
379     /* use and restores proper display function for further pictures */
380     p_vout->pf_display = DisplayGDI;
381 }
382
383 #else
384
385 static int GAPILockSurface( vout_thread_t *p_vout, picture_t *p_pic )
386 {
387     vout_sys_t *p_sys = p_vout->p_sys;
388     int i_x, i_y, i_width, i_height;
389     RECT video_rect;
390     POINT point;
391
392     GetClientRect( p_sys->hwnd, &video_rect);
393     vout_PlacePicture( p_vout, video_rect.right - video_rect.left,
394                        video_rect.bottom - video_rect.top,
395                        &i_x, &i_y, &i_width, &i_height );
396     point.x = point.y = 0;
397     ClientToScreen( p_sys->hwnd, &point );
398     i_x += point.x + video_rect.left;
399     i_y += point.y + video_rect.top;
400
401     if( i_width != p_vout->output.i_width ||
402         i_height != p_vout->output.i_height )
403     {
404         GXDisplayProperties gxdisplayprop = GXGetDisplayProperties();
405
406         p_sys->render_width = i_width;
407         p_sys->render_height = i_height;
408         p_vout->i_changes |= VOUT_SIZE_CHANGE;
409
410         msg_Dbg( p_vout, "vout size change (%ix%i -> %ix%i)",
411                  i_width, i_height, p_vout->output.i_width,
412                  p_vout->output.i_height );
413
414         p_vout->p_sys->i_pic_pixel_pitch = gxdisplayprop.cbxPitch;
415         p_vout->p_sys->i_pic_pitch = gxdisplayprop.cbyPitch;
416         return VLC_EGENERIC;
417     }
418     else
419     {
420         GXDisplayProperties gxdisplayprop;
421         RECT display_rect, dest_rect;
422         uint8_t *p_dest, *p_src = p_pic->p->p_pixels;
423
424         video_rect.left = i_x; video_rect.top = i_y;
425         video_rect.right = i_x + i_width;
426         video_rect.bottom = i_y + i_height;
427
428         gxdisplayprop = GXGetDisplayProperties();
429         display_rect.left = 0; display_rect.top = 0;
430         display_rect.right = gxdisplayprop.cxWidth;
431         display_rect.bottom = gxdisplayprop.cyHeight;
432
433         if( !IntersectRect( &dest_rect, &video_rect, &display_rect ) )
434         {
435             return VLC_EGENERIC;
436         }
437
438 #ifndef NDEBUG
439         msg_Dbg( p_vout, "video (%d,%d,%d,%d) display (%d,%d,%d,%d) "
440                  "dest (%d,%d,%d,%d)",
441                  video_rect.left, video_rect.right,
442                  video_rect.top, video_rect.bottom,
443                  display_rect.left, display_rect.right,
444                  display_rect.top, display_rect.bottom,
445                  dest_rect.left, dest_rect.right,
446                  dest_rect.top, dest_rect.bottom );
447 #endif
448
449         if( !(p_dest = GXBeginDraw()) )
450         {
451 #ifndef NDEBUG
452             msg_Err( p_vout, "GXBeginDraw error %d ", GetLastError() );
453 #endif
454             return VLC_EGENERIC;
455         }
456
457         p_src += (dest_rect.left - video_rect.left) * gxdisplayprop.cbxPitch +
458             (dest_rect.top - video_rect.top) * p_pic->p->i_pitch;
459         p_dest += dest_rect.left * gxdisplayprop.cbxPitch +
460             dest_rect.top * gxdisplayprop.cbyPitch;
461         i_width = dest_rect.right - dest_rect.left;
462         i_height = dest_rect.bottom - dest_rect.top;
463
464         p_pic->p->p_pixels = p_dest;
465     }
466
467     return VLC_SUCCESS;
468 }
469
470 static int GAPIUnlockSurface( vout_thread_t *p_vout, picture_t *p_pic )
471 {
472     GXEndDraw();
473     return VLC_SUCCESS;
474 }
475
476 static void DisplayGAPI( vout_thread_t *p_vout, picture_t *p_pic )
477 {
478 }
479
480 static void FirstDisplayGAPI( vout_thread_t *p_vout, picture_t *p_pic )
481 {
482     /* get initial picture presented through D3D */
483     DisplayGAPI(p_vout, p_pic);
484
485     /*
486     ** Video window is initially hidden, show it now since we got a
487     ** picture to show.
488     */
489     SetWindowPos( p_vout->p_sys->hvideownd, 0, 0, 0, 0, 0,
490         SWP_ASYNCWINDOWPOS|
491         SWP_FRAMECHANGED|
492         SWP_SHOWWINDOW|
493         SWP_NOMOVE|
494         SWP_NOSIZE|
495         SWP_NOZORDER );
496
497     /* use and restores proper display function for further pictures */
498     p_vout->pf_display = DisplayGAPI;
499 }
500
501 #endif
502
503 #undef rect_src
504 #undef rect_src_clipped
505 #undef rect_dest
506 #undef rect_dest_clipped
507 /*****************************************************************************
508  * SetPalette: sets an 8 bpp palette
509  *****************************************************************************/
510 static void SetPalette( vout_thread_t *p_vout,
511                         uint16_t *red, uint16_t *green, uint16_t *blue )
512 {
513     VLC_UNUSED( red ); VLC_UNUSED( green );VLC_UNUSED( blue );
514     msg_Err( p_vout, "FIXME: SetPalette unimplemented" );
515 }
516
517 /*****************************************************************************
518  * InitBuffers: initialize an offscreen bitmap for direct buffer operations.
519  *****************************************************************************/
520 static void InitBuffers( vout_thread_t *p_vout )
521 {
522     BITMAPINFOHEADER *p_header = &p_vout->p_sys->bitmapinfo.bmiHeader;
523     BITMAPINFO *p_info = &p_vout->p_sys->bitmapinfo;
524     HDC window_dc = GetDC( p_vout->p_sys->hvideownd );
525
526     /* Get screen properties */
527 #ifdef MODULE_NAME_IS_wingapi
528     GXDisplayProperties gx_displayprop = GXGetDisplayProperties();
529     p_vout->p_sys->i_depth = gx_displayprop.cBPP;
530 #else
531     p_vout->p_sys->i_depth = GetDeviceCaps( window_dc, PLANES ) *
532         GetDeviceCaps( window_dc, BITSPIXEL );
533 #endif
534     msg_Dbg( p_vout, "GDI depth is %i", p_vout->p_sys->i_depth );
535
536 #ifdef MODULE_NAME_IS_wingapi
537     GXOpenDisplay( p_vout->p_sys->hvideownd, GX_FULLSCREEN );
538
539 #else
540
541     /* Initialize offscreen bitmap */
542     memset( p_info, 0, sizeof( BITMAPINFO ) + 3 * sizeof( RGBQUAD ) );
543
544     p_header->biSize = sizeof( BITMAPINFOHEADER );
545     p_header->biSizeImage = 0;
546     p_header->biPlanes = 1;
547     switch( p_vout->p_sys->i_depth )
548     {
549     case 8:
550         p_header->biBitCount = 8;
551         p_header->biCompression = BI_RGB;
552         /* FIXME: we need a palette here */
553         break;
554     case 15:
555         p_header->biBitCount = 15;
556         p_header->biCompression = BI_BITFIELDS;//BI_RGB;
557         ((DWORD*)p_info->bmiColors)[0] = 0x00007c00;
558         ((DWORD*)p_info->bmiColors)[1] = 0x000003e0;
559         ((DWORD*)p_info->bmiColors)[2] = 0x0000001f;
560         break;
561     case 16:
562         p_header->biBitCount = 16;
563         p_header->biCompression = BI_BITFIELDS;//BI_RGB;
564         ((DWORD*)p_info->bmiColors)[0] = 0x0000f800;
565         ((DWORD*)p_info->bmiColors)[1] = 0x000007e0;
566         ((DWORD*)p_info->bmiColors)[2] = 0x0000001f;
567         break;
568     case 24:
569         p_header->biBitCount = 24;
570         p_header->biCompression = BI_RGB;
571         ((DWORD*)p_info->bmiColors)[0] = 0x00ff0000;
572         ((DWORD*)p_info->bmiColors)[1] = 0x0000ff00;
573         ((DWORD*)p_info->bmiColors)[2] = 0x000000ff;
574         break;
575     case 32:
576         p_header->biBitCount = 32;
577         p_header->biCompression = BI_RGB;
578         ((DWORD*)p_info->bmiColors)[0] = 0x00ff0000;
579         ((DWORD*)p_info->bmiColors)[1] = 0x0000ff00;
580         ((DWORD*)p_info->bmiColors)[2] = 0x000000ff;
581         break;
582     default:
583         msg_Err( p_vout, "screen depth %i not supported",
584                  p_vout->p_sys->i_depth );
585         return;
586         break;
587     }
588     p_header->biWidth = p_vout->render.i_width;
589     p_header->biHeight = -p_vout->render.i_height;
590     p_header->biClrImportant = 0;
591     p_header->biClrUsed = 0;
592     p_header->biXPelsPerMeter = 0;
593     p_header->biYPelsPerMeter = 0;
594
595     p_vout->p_sys->i_pic_pixel_pitch = p_header->biBitCount / 8;
596     p_vout->p_sys->i_pic_pitch = p_header->biBitCount * p_header->biWidth / 8;
597
598     p_vout->p_sys->off_bitmap =
599         CreateDIBSection( window_dc, (BITMAPINFO *)p_header, DIB_RGB_COLORS,
600                           &p_vout->p_sys->p_pic_buffer, NULL, 0 );
601
602     p_vout->p_sys->off_dc = CreateCompatibleDC( window_dc );
603
604     SelectObject( p_vout->p_sys->off_dc, p_vout->p_sys->off_bitmap );
605     ReleaseDC( p_vout->p_sys->hvideownd, window_dc );
606 #endif
607 }
608