1 /*****************************************************************************
2 * wingdi.c : Win32 / WinCE GDI video output plugin for vlc
3 *****************************************************************************
4 * Copyright (C) 2002 VideoLAN
5 * $Id: wingdi.c,v 1.6 2003/03/30 18:14:38 gbazin Exp $
7 * Authors: Samuel Hocevar <sam@zoy.org>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
22 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
27 #include <stdlib.h> /* malloc(), free() */
33 #define WIN32_LEAN_AND_MEAN
36 #define MAX_DIRECTBUFFERS 10
38 /*****************************************************************************
40 *****************************************************************************/
41 static int OpenVideo ( vlc_object_t * );
42 static void CloseVideo ( vlc_object_t * );
44 static int Init ( vout_thread_t * );
45 static void End ( vout_thread_t * );
46 static int Manage ( vout_thread_t * );
47 static void Render ( vout_thread_t *, picture_t * );
48 static void Display ( vout_thread_t *, picture_t * );
49 static void SetPalette( vout_thread_t *, uint16_t *, uint16_t *, uint16_t * );
51 static void EventThread ( vlc_object_t * );
52 static long FAR PASCAL WndProc ( HWND, UINT, WPARAM, LPARAM );
53 static void InitBuffers ( vout_thread_t * );
55 /*****************************************************************************
57 *****************************************************************************/
60 /* The event thread */
61 vlc_object_t * p_event;
63 /* Our video output window */
67 /* Our offscreen bitmap and its framebuffer */
72 BITMAPINFO bitmapinfo;
78 /*****************************************************************************
80 *****************************************************************************/
82 set_description( _("Windows GDI video output") );
83 set_capability( "video output", 10 );
84 set_callbacks( OpenVideo, CloseVideo );
87 /*****************************************************************************
88 * OpenVideo: activate GDI video thread output method
89 *****************************************************************************/
90 static int OpenVideo ( vlc_object_t *p_this )
92 vout_thread_t * p_vout = (vout_thread_t *)p_this;
95 p_vout->p_sys = malloc( sizeof(vout_sys_t) );
101 p_vout->p_sys->p_event = vlc_object_create( p_vout, VLC_OBJECT_GENERIC );
102 if( !p_vout->p_sys->p_event )
104 free( p_vout->p_sys );
108 var_Create( p_vout->p_sys->p_event, "p_vout", VLC_VAR_ADDRESS );
109 val.p_address = (void *)p_vout;
110 var_Set( p_vout->p_sys->p_event, "p_vout", val );
112 p_vout->pf_init = Init;
113 p_vout->pf_end = End;
114 p_vout->pf_manage = Manage;
115 p_vout->pf_render = Render;
116 p_vout->pf_display = Display;
121 /*****************************************************************************
122 * CloseVideo: deactivate the GDI video output
123 *****************************************************************************/
124 static void CloseVideo ( vlc_object_t *p_this )
126 vout_thread_t * p_vout = (vout_thread_t *)p_this;
128 var_Destroy( p_vout->p_sys->p_event, "p_vout" );
129 vlc_object_destroy( p_vout->p_sys->p_event );
130 free( p_vout->p_sys );
133 /*****************************************************************************
134 * Init: initialize video thread output method
135 *****************************************************************************/
136 static int Init( vout_thread_t *p_vout )
141 if( vlc_thread_create( p_vout->p_sys->p_event, "GDI Event Thread",
142 EventThread, 0, 1 ) )
144 msg_Err( p_vout, "cannot spawn EventThread" );
148 I_OUTPUTPICTURES = 0;
150 /* Initialize the output structure */
151 switch( p_vout->p_sys->i_depth )
154 p_vout->output.i_chroma = VLC_FOURCC('R','G','B','2');
155 p_vout->output.pf_setpalette = SetPalette;
158 p_vout->output.i_chroma = VLC_FOURCC('R','V','3','2');
159 p_vout->output.i_rmask = 0x00ff0000;
160 p_vout->output.i_gmask = 0x0000ff00;
161 p_vout->output.i_bmask = 0x000000ff;
165 p_vout->output.i_chroma = VLC_FOURCC('R','V','1','5');
166 p_vout->output.i_rmask = 0x7c00;
167 p_vout->output.i_gmask = 0x03e0;
168 p_vout->output.i_bmask = 0x001f;
172 p_vout->output.i_width = p_vout->render.i_width;
173 p_vout->output.i_height = p_vout->render.i_height;
174 p_vout->output.i_aspect = p_vout->render.i_aspect;
176 /* Try to initialize MAX_DIRECTBUFFERS direct buffers */
177 while( I_OUTPUTPICTURES < MAX_DIRECTBUFFERS )
181 /* Find an empty picture slot */
182 for( i_index = 0 ; i_index < VOUT_MAX_PICTURES ; i_index++ )
184 if( p_vout->p_picture[ i_index ].i_status == FREE_PICTURE )
186 p_pic = p_vout->p_picture + i_index;
191 /* Allocate the picture */
197 vout_AllocatePicture( p_vout, p_pic, p_vout->output.i_width,
198 p_vout->output.i_height,
199 p_vout->output.i_chroma );
201 if( p_pic->i_planes == 0 )
206 p_pic->i_status = DESTROYED_PICTURE;
207 p_pic->i_type = DIRECT_PICTURE;
209 PP_OUTPUTPICTURE[ I_OUTPUTPICTURES ] = p_pic;
217 /*****************************************************************************
218 * End: terminate video thread output method
219 *****************************************************************************/
220 static void End( vout_thread_t *p_vout )
224 /* Free the fake output buffers we allocated */
225 for( i_index = I_OUTPUTPICTURES ; i_index ; )
228 free( PP_OUTPUTPICTURE[ i_index ]->p_data_orig );
231 p_vout->p_sys->p_event->b_die = VLC_TRUE;
232 PostMessage( p_vout->p_sys->window, WM_NULL, 0, 0 );
233 vlc_thread_join( p_vout->p_sys->p_event );
236 /*****************************************************************************
237 * Manage: handle events
238 *****************************************************************************
239 * This function should be called regularly by video output thread. It manages
240 * console events. It returns a non null value on error.
241 *****************************************************************************/
242 static int Manage( vout_thread_t *p_vout )
247 /*****************************************************************************
248 * Render: render previously calculated output
249 *****************************************************************************/
250 static void Render( vout_thread_t *p_vout, picture_t *p_pic )
252 /* No need to do anything, the fake direct buffers stay as they are */
255 /*****************************************************************************
256 * Display: displays previously rendered output
257 *****************************************************************************/
258 static void Display( vout_thread_t *p_vout, picture_t *p_pic )
260 /* No need to do anything, the fake direct buffers stay as they are */
262 int i_src_bytes, i_dest_bytes;
264 hdc = GetDC( p_vout->p_sys->window );
265 SelectObject( p_vout->p_sys->off_dc, p_vout->p_sys->off_bitmap );
267 /* Stupid GDI is upside-down */
268 i_src_bytes = p_pic->p->i_lines * p_pic->p->i_pitch;
273 i_src_bytes -= p_pic->p->i_pitch;
275 p_vout->p_vlc->pf_memcpy( p_vout->p_sys->p_buffer + i_dest_bytes,
276 p_pic->p->p_pixels + i_src_bytes,
277 p_pic->p->i_visible_pitch );
279 i_dest_bytes += p_pic->p->i_pitch;
282 BitBlt( hdc, 0, 0, p_vout->output.i_width, p_vout->output.i_height,
283 p_vout->p_sys->off_dc, 0, 0, SRCCOPY );
285 ReleaseDC( p_vout->p_sys->window, hdc );
288 /*****************************************************************************
289 * SetPalette: sets an 8 bpp palette
290 *****************************************************************************/
291 static void SetPalette( vout_thread_t *p_vout,
292 uint16_t *red, uint16_t *green, uint16_t *blue )
294 msg_Err( p_vout, "FIXME: SetPalette unimplemented" );
297 /*****************************************************************************
298 * EventThread: Event handling thread
299 *****************************************************************************/
300 static void EventThread ( vlc_object_t *p_event )
302 vout_thread_t * p_vout;
310 wchar_t *psz_class = L"VOUT";
311 wchar_t *psz_title = L"Video Output";
313 char *psz_class = "VOUT";
314 char *psz_title = "Video Output";
317 var_Get( p_event, "p_vout", &val );
318 p_vout = (vout_thread_t *)val.p_address;
320 instance = GetModuleHandle( NULL );
322 /* Register window class */
323 memset( &wc, 0, sizeof(wc) );
324 wc.style = CS_HREDRAW | CS_VREDRAW;
325 wc.lpfnWndProc = (WNDPROC)WndProc;
328 wc.hInstance = instance;
331 wc.hbrBackground = (HBRUSH)GetStockObject( BLACK_BRUSH );
333 wc.lpszClassName = psz_class;
335 RegisterClass( &wc );
337 /* Create output window */
338 p_vout->p_sys->window =
339 CreateWindow( psz_class, psz_title,
340 WS_VISIBLE | WS_SIZEBOX | WS_CAPTION,
341 CW_USEDEFAULT, CW_USEDEFAULT,
342 p_vout->render.i_width,
343 p_vout->render.i_height + 10,
344 NULL, NULL, instance, (LPVOID)p_vout );
346 /* Initialize offscreen buffer */
347 InitBuffers( p_vout );
349 /* Tell the video output we're ready to receive data */
350 vlc_thread_ready( p_event );
352 /* Display our window */
353 ShowWindow( p_vout->p_sys->window, SW_SHOWNORMAL );
354 UpdateWindow( p_vout->p_sys->window );
356 while( !p_event->b_die
357 && GetMessage( &msg, p_vout->p_sys->window, 0, 0 ) )
364 switch( msg.message )
370 p_event->p_vlc->b_die = VLC_TRUE;
373 TranslateMessage( &msg );
381 p_event->p_vlc->b_die = VLC_TRUE;
387 TranslateMessage( &msg );
388 DispatchMessage( &msg );
393 DestroyWindow( p_vout->p_sys->window );
395 DeleteDC( p_vout->p_sys->off_dc );
396 DeleteObject( p_vout->p_sys->off_bitmap );
399 /*****************************************************************************
400 * Message handler for the main window
401 *****************************************************************************/
402 static long FAR PASCAL WndProc ( HWND hWnd, UINT message,
403 WPARAM wParam, LPARAM lParam )
405 /* Caution: this only works */
406 vout_thread_t *p_vout;
408 if( message == WM_CREATE )
410 /* Store p_vout for future use */
411 p_vout = (vout_thread_t *)((CREATESTRUCT *)lParam)->lpCreateParams;
412 SetWindowLong( hWnd, GWL_USERDATA, (LONG)p_vout );
416 p_vout = (vout_thread_t *)GetWindowLong( hWnd, GWL_USERDATA );
432 PostQuitMessage( 0 );
436 return DefWindowProc( hWnd, message, wParam, lParam );
442 /*****************************************************************************
443 * InitBuffers: initialize an offscreen bitmap for direct buffer operations.
444 *****************************************************************************/
445 static void InitBuffers( vout_thread_t *p_vout )
447 BITMAPINFOHEADER * p_header = &p_vout->p_sys->bitmapinfo.bmiHeader;
448 BITMAPINFO * p_info = &p_vout->p_sys->bitmapinfo;
449 int i_pixels = p_vout->render.i_height * p_vout->render.i_width;
452 window_dc = GetDC( p_vout->p_sys->window );
454 /* Get screen properties */
455 p_vout->p_sys->i_depth = GetDeviceCaps( window_dc, PLANES )
456 * GetDeviceCaps( window_dc, BITSPIXEL );
457 msg_Dbg( p_vout, "GDI depth is %i", p_vout->p_sys->i_depth );
459 /* Initialize offscreen bitmap */
460 memset( p_info, 0, sizeof( BITMAPINFO ) + 3 * sizeof( RGBQUAD ) );
462 p_header->biSize = sizeof( BITMAPINFOHEADER );
463 p_header->biPlanes = 1;
464 switch( p_vout->p_sys->i_depth )
467 p_header->biBitCount = 8;
468 p_header->biSizeImage = i_pixels;
469 p_header->biCompression = BI_RGB;
470 /* FIXME: we need a palette here */
474 p_header->biBitCount = 32;
475 p_header->biSizeImage = i_pixels * 4;
476 p_header->biCompression = BI_BITFIELDS;
477 ((DWORD*)p_info->bmiColors)[0] = 0x00ff0000;
478 ((DWORD*)p_info->bmiColors)[1] = 0x0000ff00;
479 ((DWORD*)p_info->bmiColors)[2] = 0x000000ff;
483 p_header->biBitCount = 16;
484 p_header->biSizeImage = i_pixels * 2;
485 p_header->biCompression = BI_BITFIELDS;
486 ((DWORD*)p_info->bmiColors)[0] = 0x00007c00;
487 ((DWORD*)p_info->bmiColors)[1] = 0x000003e0;
488 ((DWORD*)p_info->bmiColors)[2] = 0x0000001f;
491 p_header->biWidth = p_vout->render.i_width;
492 p_header->biHeight = p_vout->render.i_height;
493 p_header->biClrImportant = 0;
494 p_header->biClrUsed = 0;
495 p_header->biXPelsPerMeter = 0;
496 p_header->biYPelsPerMeter = 0;
498 p_vout->p_sys->off_bitmap =
499 CreateDIBSection( window_dc, (BITMAPINFO *)p_header, DIB_RGB_COLORS,
500 (void**)&p_vout->p_sys->p_buffer, NULL, 0 );
502 p_vout->p_sys->off_dc = CreateCompatibleDC( window_dc );
504 SelectObject( p_vout->p_sys->off_dc, p_vout->p_sys->off_bitmap );
505 ReleaseDC( 0, window_dc );