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