1 /*****************************************************************************
2 * wingdi.c : Win32 / WinCE GDI video output plugin for vlc
3 *****************************************************************************
4 * Copyright (C) 2002 VideoLAN
5 * $Id: wingdi.c,v 1.8 2003/12/04 14:48:24 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','2','4');
159 p_vout->output.i_rmask = 0x00ff0000;
160 p_vout->output.i_gmask = 0x0000ff00;
161 p_vout->output.i_bmask = 0x000000ff;
164 p_vout->output.i_chroma = VLC_FOURCC('R','V','3','2');
165 p_vout->output.i_rmask = 0x00ff0000;
166 p_vout->output.i_gmask = 0x0000ff00;
167 p_vout->output.i_bmask = 0x000000ff;
171 p_vout->output.i_chroma = VLC_FOURCC('R','V','1','5');
172 p_vout->output.i_rmask = 0x7c00;
173 p_vout->output.i_gmask = 0x03e0;
174 p_vout->output.i_bmask = 0x001f;
178 p_vout->output.i_width = p_vout->render.i_width;
179 p_vout->output.i_height = p_vout->render.i_height;
180 p_vout->output.i_aspect = p_vout->render.i_aspect;
182 /* Try to initialize MAX_DIRECTBUFFERS direct buffers */
183 while( I_OUTPUTPICTURES < MAX_DIRECTBUFFERS )
187 /* Find an empty picture slot */
188 for( i_index = 0 ; i_index < VOUT_MAX_PICTURES ; i_index++ )
190 if( p_vout->p_picture[ i_index ].i_status == FREE_PICTURE )
192 p_pic = p_vout->p_picture + i_index;
197 /* Allocate the picture */
203 vout_AllocatePicture( p_vout, p_pic, p_vout->output.i_chroma,
204 p_vout->output.i_width, p_vout->output.i_height,
205 p_vout->output.i_aspect );
207 if( p_pic->i_planes == 0 )
212 p_pic->i_status = DESTROYED_PICTURE;
213 p_pic->i_type = DIRECT_PICTURE;
215 PP_OUTPUTPICTURE[ I_OUTPUTPICTURES ] = p_pic;
223 /*****************************************************************************
224 * End: terminate video thread output method
225 *****************************************************************************/
226 static void End( vout_thread_t *p_vout )
230 /* Free the fake output buffers we allocated */
231 for( i_index = I_OUTPUTPICTURES ; i_index ; )
234 free( PP_OUTPUTPICTURE[ i_index ]->p_data_orig );
237 p_vout->p_sys->p_event->b_die = VLC_TRUE;
238 PostMessage( p_vout->p_sys->window, WM_NULL, 0, 0 );
239 vlc_thread_join( p_vout->p_sys->p_event );
242 /*****************************************************************************
243 * Manage: handle events
244 *****************************************************************************
245 * This function should be called regularly by video output thread. It manages
246 * console events. It returns a non null value on error.
247 *****************************************************************************/
248 static int Manage( vout_thread_t *p_vout )
253 /*****************************************************************************
254 * Render: render previously calculated output
255 *****************************************************************************/
256 static void Render( vout_thread_t *p_vout, picture_t *p_pic )
258 /* No need to do anything, the fake direct buffers stay as they are */
261 /*****************************************************************************
262 * Display: displays previously rendered output
263 *****************************************************************************/
264 static void Display( vout_thread_t *p_vout, picture_t *p_pic )
266 /* No need to do anything, the fake direct buffers stay as they are */
268 int i_src_bytes, i_dest_bytes;
270 hdc = GetDC( p_vout->p_sys->window );
271 SelectObject( p_vout->p_sys->off_dc, p_vout->p_sys->off_bitmap );
273 /* Stupid GDI is upside-down */
274 i_src_bytes = p_pic->p->i_lines * p_pic->p->i_pitch;
279 i_src_bytes -= p_pic->p->i_pitch;
281 p_vout->p_vlc->pf_memcpy( p_vout->p_sys->p_buffer + i_dest_bytes,
282 p_pic->p->p_pixels + i_src_bytes,
283 p_pic->p->i_visible_pitch );
285 i_dest_bytes += p_pic->p->i_pitch;
288 BitBlt( hdc, 0, 0, p_vout->output.i_width, p_vout->output.i_height,
289 p_vout->p_sys->off_dc, 0, 0, SRCCOPY );
291 ReleaseDC( p_vout->p_sys->window, hdc );
294 /*****************************************************************************
295 * SetPalette: sets an 8 bpp palette
296 *****************************************************************************/
297 static void SetPalette( vout_thread_t *p_vout,
298 uint16_t *red, uint16_t *green, uint16_t *blue )
300 msg_Err( p_vout, "FIXME: SetPalette unimplemented" );
303 /*****************************************************************************
304 * EventThread: Event handling thread
305 *****************************************************************************/
306 static void EventThread ( vlc_object_t *p_event )
308 vout_thread_t * p_vout;
316 wchar_t *psz_class = L"VOUT";
317 wchar_t *psz_title = L"Video Output";
319 char *psz_class = "VOUT";
320 char *psz_title = "Video Output";
323 var_Get( p_event, "p_vout", &val );
324 p_vout = (vout_thread_t *)val.p_address;
326 instance = GetModuleHandle( NULL );
328 /* Register window class */
329 memset( &wc, 0, sizeof(wc) );
330 wc.style = CS_HREDRAW | CS_VREDRAW;
331 wc.lpfnWndProc = (WNDPROC)WndProc;
334 wc.hInstance = instance;
337 wc.hbrBackground = (HBRUSH)GetStockObject( BLACK_BRUSH );
339 wc.lpszClassName = psz_class;
341 RegisterClass( &wc );
343 /* Create output window */
344 p_vout->p_sys->window =
345 CreateWindow( psz_class, psz_title,
346 WS_VISIBLE | WS_SIZEBOX | WS_CAPTION,
347 CW_USEDEFAULT, CW_USEDEFAULT,
348 p_vout->render.i_width,
349 p_vout->render.i_height + 10,
350 NULL, NULL, instance, (LPVOID)p_vout );
352 /* Initialize offscreen buffer */
353 InitBuffers( p_vout );
355 /* Tell the video output we're ready to receive data */
356 vlc_thread_ready( p_event );
358 /* Display our window */
359 ShowWindow( p_vout->p_sys->window, SW_SHOWNORMAL );
360 UpdateWindow( p_vout->p_sys->window );
362 while( !p_event->b_die
363 && GetMessage( &msg, p_vout->p_sys->window, 0, 0 ) )
370 switch( msg.message )
376 p_event->p_vlc->b_die = VLC_TRUE;
379 TranslateMessage( &msg );
387 p_event->p_vlc->b_die = VLC_TRUE;
393 TranslateMessage( &msg );
394 DispatchMessage( &msg );
399 DestroyWindow( p_vout->p_sys->window );
401 DeleteDC( p_vout->p_sys->off_dc );
402 DeleteObject( p_vout->p_sys->off_bitmap );
405 /*****************************************************************************
406 * Message handler for the main window
407 *****************************************************************************/
408 static long FAR PASCAL WndProc ( HWND hWnd, UINT message,
409 WPARAM wParam, LPARAM lParam )
411 /* Caution: this only works */
412 vout_thread_t *p_vout;
414 if( message == WM_CREATE )
416 /* Store p_vout for future use */
417 p_vout = (vout_thread_t *)((CREATESTRUCT *)lParam)->lpCreateParams;
418 SetWindowLong( hWnd, GWL_USERDATA, (LONG)p_vout );
422 p_vout = (vout_thread_t *)GetWindowLong( hWnd, GWL_USERDATA );
438 PostQuitMessage( 0 );
442 return DefWindowProc( hWnd, message, wParam, lParam );
448 /*****************************************************************************
449 * InitBuffers: initialize an offscreen bitmap for direct buffer operations.
450 *****************************************************************************/
451 static void InitBuffers( vout_thread_t *p_vout )
453 BITMAPINFOHEADER * p_header = &p_vout->p_sys->bitmapinfo.bmiHeader;
454 BITMAPINFO * p_info = &p_vout->p_sys->bitmapinfo;
455 int i_pixels = p_vout->render.i_height * p_vout->render.i_width;
458 window_dc = GetDC( p_vout->p_sys->window );
460 /* Get screen properties */
461 p_vout->p_sys->i_depth = GetDeviceCaps( window_dc, PLANES )
462 * GetDeviceCaps( window_dc, BITSPIXEL );
463 msg_Dbg( p_vout, "GDI depth is %i", p_vout->p_sys->i_depth );
465 /* Initialize offscreen bitmap */
466 memset( p_info, 0, sizeof( BITMAPINFO ) + 3 * sizeof( RGBQUAD ) );
468 p_header->biSize = sizeof( BITMAPINFOHEADER );
469 p_header->biSizeImage = 0;
470 p_header->biPlanes = 1;
471 switch( p_vout->p_sys->i_depth )
474 p_header->biBitCount = 8;
475 p_header->biCompression = BI_RGB;
476 /* FIXME: we need a palette here */
479 p_header->biBitCount = 24;
480 p_header->biCompression = BI_RGB;
481 ((DWORD*)p_info->bmiColors)[0] = 0x00ff0000;
482 ((DWORD*)p_info->bmiColors)[1] = 0x0000ff00;
483 ((DWORD*)p_info->bmiColors)[2] = 0x000000ff;
486 p_header->biBitCount = 32;
487 p_header->biCompression = BI_RGB;
488 ((DWORD*)p_info->bmiColors)[0] = 0x00ff0000;
489 ((DWORD*)p_info->bmiColors)[1] = 0x0000ff00;
490 ((DWORD*)p_info->bmiColors)[2] = 0x000000ff;
494 p_header->biBitCount = 16;
495 p_header->biCompression = BI_RGB;
496 ((DWORD*)p_info->bmiColors)[0] = 0x00007c00;
497 ((DWORD*)p_info->bmiColors)[1] = 0x000003e0;
498 ((DWORD*)p_info->bmiColors)[2] = 0x0000001f;
501 p_header->biWidth = p_vout->render.i_width;
502 p_header->biHeight = p_vout->render.i_height;
503 p_header->biClrImportant = 0;
504 p_header->biClrUsed = 0;
505 p_header->biXPelsPerMeter = 0;
506 p_header->biYPelsPerMeter = 0;
508 p_vout->p_sys->off_bitmap =
509 CreateDIBSection( window_dc, (BITMAPINFO *)p_header, DIB_RGB_COLORS,
510 (void**)&p_vout->p_sys->p_buffer, NULL, 0 );
512 p_vout->p_sys->off_dc = CreateCompatibleDC( window_dc );
514 SelectObject( p_vout->p_sys->off_dc, p_vout->p_sys->off_bitmap );
515 ReleaseDC( 0, window_dc );