]> git.sesse.net Git - vlc/blob - plugins/sdl/vout_sdl.c
* Fixed a total breakage of decoder plugins introduced by fast_memcpy.
[vlc] / plugins / sdl / vout_sdl.c
1 /*****************************************************************************
2  * vout_sdl.c: SDL video output display method
3  *****************************************************************************
4  * Copyright (C) 1998-2001 VideoLAN
5  * $Id: vout_sdl.c,v 1.67 2001/12/07 18:33:08 sam Exp $
6  *
7  * Authors: Samuel Hocevar <sam@zoy.org>
8  *          Pierre Baillet <oct@zoy.org>
9  *          Arnaud de Bossoreille de Ribou <bozo@via.ecp.fr>
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  * 
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
24  *****************************************************************************/
25
26 #define MODULE_NAME sdl
27 #include "modules_inner.h"
28
29 /*****************************************************************************
30  * Preamble
31  *****************************************************************************/
32 #include "defs.h"
33
34 #include <errno.h>                                                 /* ENOMEM */
35 #include <stdlib.h>                                                /* free() */
36 #include <string.h>                                            /* strerror() */
37
38 #include <sys/types.h>
39 #ifndef WIN32
40 #   include <netinet/in.h>                            /* BSD: struct in_addr */
41 #endif
42
43 #include SDL_INCLUDE_FILE
44
45 #include "common.h"
46 #include "intf_msg.h"
47 #include "threads.h"
48 #include "mtime.h"
49 #include "tests.h"
50
51 #include "video.h"
52 #include "video_output.h"
53
54 #include "interface.h"
55 /* FIXME: get rid of this */
56 #include "keystrokes.h"
57 #include "netutils.h"
58
59 #include "modules.h"
60 #include "modules_export.h"
61
62 /*****************************************************************************
63  * FIXME: this file is ...                                                   *
64  *                                                                           *
65  *              XXX   XXX     FIXME     XXX     XXX   XXX   XXX              *
66  *              XXX   XXX   XXX   XXX   XXX     XXX   XXX   XXX              *
67  *              XXX   XXX   XXX         XXX       FIXME     XXX              *
68  *              XXX   XXX   XXX  TODO   XXX        XXX      XXX              *
69  *              XXX   XXX   XXX   XXX   XXX        XXX                       *
70  *                FIXME       FIXME       FIXME    XXX      XXX              *
71  *                                                                           *
72  *****************************************************************************/
73
74 /*****************************************************************************
75  * vout_sys_t: video output SDL method descriptor
76  *****************************************************************************
77  * This structure is part of the video output thread descriptor.
78  * It describes the SDL specific properties of an output thread.
79  *****************************************************************************/
80 typedef struct vout_sys_s
81 {
82     int i_width;
83     int i_height;
84
85     SDL_Surface *   p_display;                             /* display device */
86     SDL_Overlay *   p_overlay;                             /* overlay device */
87
88     boolean_t   b_overlay;
89     boolean_t   b_cursor;
90     boolean_t   b_reopen_display;
91
92     boolean_t   b_cursor_autohidden;
93     mtime_t     i_lastmoved;
94
95     Uint8   *   p_sdl_buf[2];                          /* Buffer information */
96
97 } vout_sys_t;
98
99 /*****************************************************************************
100  * Local prototypes.
101  *****************************************************************************/
102 static int  vout_Probe     ( probedata_t *p_data );
103 static int  vout_Create    ( struct vout_thread_s * );
104 static int  vout_Init      ( struct vout_thread_s * );
105 static void vout_End       ( struct vout_thread_s * );
106 static void vout_Destroy   ( struct vout_thread_s * );
107 static int  vout_Manage    ( struct vout_thread_s * );
108 static void vout_Display   ( struct vout_thread_s * );
109 static void vout_SetPalette( p_vout_thread_t p_vout, u16 *red, u16 *green,
110                              u16 *blue, u16 *transp );
111
112 static int  SDLOpenDisplay     ( vout_thread_t *p_vout );
113 static void SDLCloseDisplay    ( vout_thread_t *p_vout );
114 static void OutputCoords       ( const picture_t *p_pic, const boolean_t scale,
115                                  const int win_w, const int win_h,
116                                  int *dx, int *dy, int *w, int *h );
117
118 /*****************************************************************************
119  * Functions exported as capabilities. They are declared as static so that
120  * we don't pollute the namespace too much.
121  *****************************************************************************/
122 void _M( vout_getfunctions )( function_list_t * p_function_list )
123 {
124     p_function_list->pf_probe = vout_Probe;
125     p_function_list->functions.vout.pf_create     = vout_Create;
126     p_function_list->functions.vout.pf_init       = vout_Init;
127     p_function_list->functions.vout.pf_end        = vout_End;
128     p_function_list->functions.vout.pf_destroy    = vout_Destroy;
129     p_function_list->functions.vout.pf_manage     = vout_Manage;
130     p_function_list->functions.vout.pf_display    = vout_Display;
131     p_function_list->functions.vout.pf_setpalette = vout_SetPalette;
132 }
133
134 /*****************************************************************************
135  * vout_Probe: probe the video driver and return a score
136  *****************************************************************************
137  * This function tries to initialize SDL and returns a score to the
138  * plugin manager so that it can select the best plugin.
139  *****************************************************************************/
140 static int vout_Probe( probedata_t *p_data )
141 {
142     if( TestMethod( VOUT_METHOD_VAR, "sdl" ) )
143     {
144         return( 999 );
145     }
146
147     return( 100 );
148 }
149
150 /*****************************************************************************
151  * vout_Create: allocate SDL video thread output method
152  *****************************************************************************
153  * This function allocate and initialize a SDL vout method. It uses some of the
154  * vout properties to choose the correct mode, and change them according to the
155  * mode actually used.
156  *****************************************************************************/
157 static int vout_Create( vout_thread_t *p_vout )
158 {
159     /* Allocate structure */
160     p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
161     if( p_vout->p_sys == NULL )
162     {
163         intf_ErrMsg( "vout error: can't create p_sys (%s)", strerror(ENOMEM) );
164         return( 1 );
165     }
166
167     /* Initialize library */
168     if( SDL_Init( SDL_INIT_VIDEO
169 #ifndef WIN32
170     /* Win32 SDL implementation doesn't support SDL_INIT_EVENTTHREAD yet*/
171                 | SDL_INIT_EVENTTHREAD
172 #endif
173 #ifdef DEBUG
174     /* In debug mode you may want vlc to dump a core instead of staying
175      * stuck */
176                 | SDL_INIT_NOPARACHUTE
177 #endif
178                 ) < 0 )
179     {
180         intf_ErrMsg( "vout error: can't initialize SDL (%s)", SDL_GetError() );
181         free( p_vout->p_sys );
182         return( 1 );
183     }
184
185     p_vout->p_sys->b_cursor = 1; /* TODO should be done with a main_GetInt.. */
186
187     p_vout->p_sys->b_cursor_autohidden = 0;
188     p_vout->p_sys->i_lastmoved = mdate();
189
190     p_vout->b_fullscreen = main_GetIntVariable( VOUT_FULLSCREEN_VAR,
191                                 VOUT_FULLSCREEN_DEFAULT );
192     p_vout->p_sys->b_overlay = main_GetIntVariable( VOUT_OVERLAY_VAR,
193                                 VOUT_OVERLAY_DEFAULT );
194     p_vout->p_sys->i_width = p_vout->i_width;
195     p_vout->p_sys->i_height = p_vout->i_height;
196
197     p_vout->p_sys->p_display = NULL;
198     p_vout->p_sys->p_overlay = NULL;
199
200     if( SDLOpenDisplay(p_vout) )
201     {
202         intf_ErrMsg( "vout error: can't set up SDL (%s)", SDL_GetError() );
203         free( p_vout->p_sys );
204         return( 1 );
205     }
206
207     /* FIXME: get rid of this ASAP, it's FUCKING UGLY */
208     { intf_thread_t * p_intf = p_main->p_intf;
209     intf_AssignKey(p_intf, SDLK_q,      INTF_KEY_QUIT, 0);
210     intf_AssignKey(p_intf, SDLK_ESCAPE, INTF_KEY_QUIT, 0);
211     /* intf_AssignKey(p_intf,3,'Q'); */
212     intf_AssignKey(p_intf, SDLK_0,      INTF_KEY_SET_CHANNEL,0);
213     intf_AssignKey(p_intf, SDLK_1,      INTF_KEY_SET_CHANNEL,1);
214     intf_AssignKey(p_intf, SDLK_2,      INTF_KEY_SET_CHANNEL,2);
215     intf_AssignKey(p_intf, SDLK_3,      INTF_KEY_SET_CHANNEL,3);
216     intf_AssignKey(p_intf, SDLK_4,      INTF_KEY_SET_CHANNEL,4);
217     intf_AssignKey(p_intf, SDLK_5,      INTF_KEY_SET_CHANNEL,5);
218     intf_AssignKey(p_intf, SDLK_6,      INTF_KEY_SET_CHANNEL,6);
219     intf_AssignKey(p_intf, SDLK_7,      INTF_KEY_SET_CHANNEL,7);
220     intf_AssignKey(p_intf, SDLK_8,      INTF_KEY_SET_CHANNEL,8);
221     intf_AssignKey(p_intf, SDLK_9,      INTF_KEY_SET_CHANNEL,9);
222     intf_AssignKey(p_intf, SDLK_PLUS,   INTF_KEY_INC_VOLUME, 0);
223     intf_AssignKey(p_intf, SDLK_MINUS,  INTF_KEY_DEC_VOLUME, 0);
224     intf_AssignKey(p_intf, SDLK_m,      INTF_KEY_TOGGLE_VOLUME, 0);
225     /* intf_AssignKey(p_intf,'M','M'); */
226     intf_AssignKey(p_intf, SDLK_g,      INTF_KEY_DEC_GAMMA, 0);
227     /* intf_AssignKey(p_intf,'G','G'); */
228     intf_AssignKey(p_intf, SDLK_c,      INTF_KEY_TOGGLE_GRAYSCALE, 0);
229     intf_AssignKey(p_intf, SDLK_SPACE,  INTF_KEY_TOGGLE_INTERFACE, 0);
230     intf_AssignKey(p_intf, SDLK_i,      INTF_KEY_TOGGLE_INFO, 0);
231     intf_AssignKey(p_intf, SDLK_s,      INTF_KEY_TOGGLE_SCALING, 0);
232     intf_AssignKey(p_intf, SDLK_d,      INTF_KEY_DUMP_STREAM, 0); }
233
234     return( 0 );
235 }
236
237 /*****************************************************************************
238  * vout_Init: initialize SDL video thread output method
239  *****************************************************************************
240  * This function initialize the SDL display device.
241  *****************************************************************************/
242 static int vout_Init( vout_thread_t *p_vout )
243 {
244     /* This hack is hugly, but hey, you are, too. */
245
246     SDL_Overlay *   p_overlay;
247     
248     p_overlay = SDL_CreateYUVOverlay( 
249            main_GetIntVariable( VOUT_WIDTH_VAR,VOUT_WIDTH_DEFAULT ),
250            main_GetIntVariable( VOUT_HEIGHT_VAR,VOUT_HEIGHT_DEFAULT ),
251                                       SDL_YV12_OVERLAY, 
252                                       p_vout->p_sys->p_display );
253
254     if( p_overlay == NULL )
255     {
256         intf_ErrMsg( "vout error: could not create SDL overlay" );
257         p_vout->b_need_render = 1;
258         return( 0 );
259     }
260
261     intf_WarnMsg( 2, "vout: YUV acceleration %s",
262               p_overlay->hw_overlay ? "activated" : "unavailable !" ); 
263     p_vout->b_need_render = !p_overlay->hw_overlay;
264
265     SDL_FreeYUVOverlay( p_overlay );
266
267     return( 0 );
268 }
269
270 /*****************************************************************************
271  * vout_End: terminate Sys video thread output method
272  *****************************************************************************
273  * Terminate an output method created by vout_SDLCreate
274  *****************************************************************************/
275 static void vout_End( vout_thread_t *p_vout )
276 {
277     SDLCloseDisplay( p_vout );
278     SDL_QuitSubSystem( SDL_INIT_VIDEO );
279 }
280
281 /*****************************************************************************
282  * vout_Destroy: destroy Sys video thread output method
283  *****************************************************************************
284  * Terminate an output method created by vout_SDLCreate
285  *****************************************************************************/
286 static void vout_Destroy( vout_thread_t *p_vout )
287 {
288     free( p_vout->p_sys );
289 }
290
291 /*****************************************************************************
292  * vout_Manage: handle Sys events
293  *****************************************************************************
294  * This function should be called regularly by video output thread. It returns
295  * a non null value if an error occured.
296  *****************************************************************************/
297 static int vout_Manage( vout_thread_t *p_vout )
298 {
299     SDL_Event event;                                            /* SDL event */
300     char *    p_key;
301
302     /* Process events */
303     while( SDL_PollEvent(&event) )
304     {
305         switch( event.type )
306         {
307         case SDL_VIDEORESIZE:                          /* Resizing of window */
308             p_vout->i_width = event.resize.w;
309             p_vout->i_height = event.resize.h;
310             p_vout->i_changes |= VOUT_SIZE_CHANGE;
311             break;
312
313         case SDL_MOUSEMOTION:
314             if( p_vout->p_sys->b_cursor &&
315                 (abs(event.motion.xrel) > 2 || abs(event.motion.yrel) > 2) )
316             {
317                 if( p_vout->p_sys->b_cursor_autohidden )
318                 {
319                     p_vout->p_sys->b_cursor_autohidden = 0;
320                     SDL_ShowCursor( 1 );
321                 }
322                 else
323                 {
324                     p_vout->p_sys->i_lastmoved = mdate();
325                 }
326             }
327             break;
328
329         case SDL_MOUSEBUTTONUP:
330             switch( event.button.button )
331             {
332             case SDL_BUTTON_RIGHT:
333                 p_main->p_intf->b_menu_change = 1;
334                 break;
335             }
336             break;
337
338         case SDL_MOUSEBUTTONDOWN:
339             switch( event.button.button )
340             {
341             case SDL_BUTTON_MIDDLE:
342                 p_vout->i_changes |= VOUT_CURSOR_CHANGE;
343                 break;
344             }
345             break;
346
347         case SDL_QUIT:
348             intf_ProcessKey( p_main->p_intf, SDLK_q );
349             break;
350
351         case SDL_KEYDOWN:                             /* if a key is pressed */
352
353             switch( event.key.keysym.sym )
354             {
355             case SDLK_f:                             /* switch to fullscreen */
356                 p_vout->i_changes |= VOUT_FULLSCREEN_CHANGE;
357                 break;
358
359             case SDLK_y:                               /* switch to hard YUV */
360                 p_vout->i_changes |= VOUT_YUV_CHANGE;
361                 break;
362
363             case SDLK_c:                                 /* toggle grayscale */
364                 p_vout->b_grayscale = ! p_vout->b_grayscale;
365                 p_vout->i_changes |= VOUT_GRAYSCALE_CHANGE;
366                 break;
367
368             case SDLK_i:                                      /* toggle info */
369                 p_vout->b_info = ! p_vout->b_info;
370                 p_vout->i_changes |= VOUT_INFO_CHANGE;
371                 break;
372
373             case SDLK_s:                                   /* toggle scaling */
374                 p_vout->b_scale = ! p_vout->b_scale;
375                 p_vout->i_changes |= VOUT_SCALE_CHANGE;
376                 break;
377
378             case SDLK_SPACE:                             /* toggle interface */
379                 p_vout->b_interface = ! p_vout->b_interface;
380                 p_vout->i_changes |= VOUT_INTF_CHANGE;
381                 break;
382             
383             case SDLK_F10:
384                 network_ChannelJoin( 0 );
385                 break;
386             case SDLK_F1:
387                 network_ChannelJoin( 1 );
388                 break;
389             case SDLK_F2:
390                 network_ChannelJoin( 2 );
391                 break;
392             case SDLK_F3:
393                 network_ChannelJoin( 3 );
394                 break;
395             case SDLK_F4:
396                 network_ChannelJoin( 4 );
397                 break;
398             case SDLK_F5:
399                 network_ChannelJoin( 5 );
400                 break;
401             case SDLK_F6:
402                 network_ChannelJoin( 6 );
403                 break;
404             case SDLK_F7:
405                 network_ChannelJoin( 7 );
406                 break;
407             case SDLK_F8:
408                 network_ChannelJoin( 8 );
409                 break;
410             case SDLK_F9:
411                 network_ChannelJoin( 9 );
412                 break;
413
414             case SDLK_MENU:
415                 p_main->p_intf->b_menu_change = 1;
416                 break;
417                 
418             default:
419                 p_key = SDL_GetKeyName( event.key.keysym.sym ) ;
420                 if( intf_ProcessKey( p_main->p_intf, 
421                                      (char )event.key.keysym.sym ) )
422                 {
423                    intf_DbgMsg( "unhandled key '%c' (%i)", 
424                                 (char)event.key.keysym.sym, 
425                                 event.key.keysym.sym );                
426                 }
427                 break;
428             }
429             break;
430
431         default:
432             break;
433         }
434     }
435
436     /*
437      * Size Change 
438      */
439     if( p_vout->i_changes & VOUT_SIZE_CHANGE )
440     {
441         p_vout->p_sys->i_width = p_vout->i_width;
442         p_vout->p_sys->i_height = p_vout->i_height;
443
444         /* Need to reopen display */
445         SDLCloseDisplay( p_vout );
446         if( SDLOpenDisplay( p_vout ) )
447         {
448           intf_ErrMsg( "vout error: can't reopen display after resize" );
449           return( 1 );
450         }
451         p_vout->i_changes &= ~VOUT_SIZE_CHANGE;
452     }
453     
454     /*
455      * YUV Change 
456      */
457     if( p_vout->i_changes & VOUT_YUV_CHANGE )
458     {
459         p_vout->b_need_render = ! p_vout->b_need_render;
460         
461         /* Need to reopen display */
462         SDLCloseDisplay( p_vout );
463         if( SDLOpenDisplay( p_vout ) )
464         {
465           intf_ErrMsg( "error: can't reopen display after YUV change" );
466           return( 1 );
467         }
468         p_vout->i_changes &= ~VOUT_YUV_CHANGE;
469     }
470
471     /*
472      * Fullscreen change
473      */
474     if( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE )
475     {
476         p_vout->b_fullscreen = ! p_vout->b_fullscreen;
477
478         SDL_WM_ToggleFullScreen(p_vout->p_sys->p_display);
479
480         p_vout->p_sys->b_cursor_autohidden = 0;
481         SDL_ShowCursor( p_vout->p_sys->b_cursor &&
482                         ! p_vout->p_sys->b_cursor_autohidden );
483
484         p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
485     }
486
487     /*
488      * Pointer change
489      */
490     if( ! p_vout->p_sys->b_cursor_autohidden &&
491         ( mdate() - p_vout->p_sys->i_lastmoved > 2000000 ) )
492     {
493         /* Hide the mouse automatically */
494         p_vout->p_sys->b_cursor_autohidden = 1;
495         SDL_ShowCursor( 0 );
496     }
497
498     if( p_vout->i_changes & VOUT_CURSOR_CHANGE )
499     {
500         p_vout->p_sys->b_cursor = ! p_vout->p_sys->b_cursor;
501
502         SDL_ShowCursor( p_vout->p_sys->b_cursor &&
503                         ! p_vout->p_sys->b_cursor_autohidden );
504
505         p_vout->i_changes &= ~VOUT_CURSOR_CHANGE;
506     }
507     
508     return( 0 );
509 }
510
511 /*****************************************************************************
512  * vout_SetPalette: sets an 8 bpp palette
513  *****************************************************************************
514  * This function sets the palette given as an argument. It does not return
515  * anything, but could later send information on which colors it was unable
516  * to set.
517  *****************************************************************************/
518 static void vout_SetPalette( p_vout_thread_t p_vout, u16 *red, u16 *green,
519                          u16 *blue, u16 *transp)
520 {
521      /* Create a display surface with a grayscale palette */
522     SDL_Color colors[256];
523     int i;
524   
525     /* Fill colors with color information */
526     for( i = 0; i < 256; i++ )
527     {
528         colors[ i ].r = red[ i ] >> 8;
529         colors[ i ].g = green[ i ] >> 8;
530         colors[ i ].b = blue[ i ] >> 8;
531     }
532
533     /* Set palette */
534     if( SDL_SetColors( p_vout->p_sys->p_display, colors, 0, 256 ) == 0 )
535     {
536         intf_ErrMsg( "vout error: failed setting palette" );
537     }
538
539 }
540
541 /*****************************************************************************
542  * vout_Display: displays previously rendered output
543  *****************************************************************************
544  * This function send the currently rendered image to the display, wait until
545  * it is displayed and switch the two rendering buffer, preparing next frame.
546  *****************************************************************************/
547 static void vout_Display( vout_thread_t *p_vout )
548 {
549     SDL_Rect    disp;
550
551     if((p_vout->p_sys->p_display != NULL) && !p_vout->p_sys->b_reopen_display)
552     {
553         if( !p_vout->b_need_render )
554         {
555             /*
556              * p_vout->p_rendered_pic->p_y/u/v contains the YUV buffers to
557              * render 
558              */
559             /* TODO: support for streams other than 4:2:0 */
560             if( p_vout->p_rendered_pic->i_type != YUV_420_PICTURE )
561             {
562                 intf_ErrMsg("sdl vout error: no support for that kind of pictures");
563                 return;
564             }
565             /* create the overlay if necessary */
566             if( p_vout->p_sys->p_overlay == NULL )
567             {
568                 p_vout->p_sys->p_overlay = SDL_CreateYUVOverlay( 
569                                              p_vout->p_rendered_pic->i_width, 
570                                              p_vout->p_rendered_pic->i_height,
571                                              SDL_YV12_OVERLAY, 
572                                              p_vout->p_sys->p_display );
573
574                 if( p_vout->p_sys->p_overlay != NULL )
575                 {
576                     intf_WarnMsg( 2, "vout: YUV acceleration %s",
577                                   p_vout->p_sys->p_overlay->hw_overlay
578                                    ? "activated" : "unavailable !" ); 
579                 }
580             }
581
582             if( p_vout->p_sys->p_overlay == NULL )
583             {
584                 /* Overlay allocation failed, switch back to software mode */
585                 intf_ErrMsg( "vout error: could not create SDL overlay" );
586                 p_vout->b_need_render = 1;
587             }
588             else
589             {
590                 int i_x, i_y, i_w, i_h;
591
592                 SDL_LockYUVOverlay( p_vout->p_sys->p_overlay );
593                 /* copy the data into video buffers */
594                 /* Y first */
595                 p_main->fast_memcpy( p_vout->p_sys->p_overlay->pixels[0],
596                                      p_vout->p_rendered_pic->p_y,
597                                      p_vout->p_sys->p_overlay->h *
598                                      p_vout->p_sys->p_overlay->pitches[0] );
599                 /* then V */
600                 p_main->fast_memcpy( p_vout->p_sys->p_overlay->pixels[1],
601                                      p_vout->p_rendered_pic->p_v,
602                                      p_vout->p_sys->p_overlay->h *
603                                      p_vout->p_sys->p_overlay->pitches[1] / 2 );
604                 /* and U */
605                 p_main->fast_memcpy( p_vout->p_sys->p_overlay->pixels[2],
606                                      p_vout->p_rendered_pic->p_u,
607                                      p_vout->p_sys->p_overlay->h *
608                                      p_vout->p_sys->p_overlay->pitches[2] / 2 );
609
610                 OutputCoords( p_vout->p_rendered_pic, 1,
611                               p_vout->p_sys->i_width,
612                               p_vout->p_sys->i_height,
613                               &i_x, &i_y,
614                               &i_w, &i_h);
615                 disp.x = i_x;
616                 disp.y = i_y;
617                 disp.w = i_w;
618                 disp.h = i_h;
619
620                 SDL_DisplayYUVOverlay( p_vout->p_sys->p_overlay , &disp );
621                 SDL_UnlockYUVOverlay(p_vout->p_sys->p_overlay);
622
623                 return;
624             }
625         }
626     
627         /* Software YUV: change display frame */
628         SDL_Flip( p_vout->p_sys->p_display );
629     }
630 }
631
632 /* following functions are local */
633
634 /*****************************************************************************
635  * SDLOpenDisplay: open and initialize SDL device
636  *****************************************************************************
637  * Open and initialize display according to preferences specified in the vout
638  * thread fields.
639  *****************************************************************************/
640 static int SDLOpenDisplay( vout_thread_t *p_vout )
641 {
642     SDL_Rect    clipping_rect;
643     Uint32      flags;
644     int bpp;
645     /* Open display 
646      * TODO: Check that we can request for a DOUBLEBUF HWSURFACE display
647      */
648
649     /* init flags and cursor */
650     flags = SDL_ANYFORMAT | SDL_HWPALETTE;
651
652     if( p_vout->b_fullscreen )
653     {
654         flags |= SDL_FULLSCREEN;
655     }
656     else
657     {
658         flags |= SDL_RESIZABLE;
659     }
660
661     if( p_vout->b_need_render )
662     {
663         flags |= SDL_HWSURFACE | SDL_DOUBLEBUF;
664     }
665     else
666     {
667         flags |= SDL_SWSURFACE; /* save video memory */
668     }
669
670     bpp = SDL_VideoModeOK( p_vout->p_sys->i_width,
671                            p_vout->p_sys->i_height,
672                            p_vout->i_screen_depth, flags );
673
674     if( bpp == 0 )
675     {
676         intf_ErrMsg( "vout error: no video mode available" );
677         return( 1 );
678     }
679
680     p_vout->p_sys->p_display = SDL_SetVideoMode(p_vout->p_sys->i_width,
681                                                 p_vout->p_sys->i_height,
682                                                 bpp, flags);
683
684     if( p_vout->p_sys->p_display == NULL )
685     {
686         intf_ErrMsg( "vout error: cannot set video mode" );
687         return( 1 );
688     }
689
690     SDL_LockSurface( p_vout->p_sys->p_display );
691
692     SDL_WM_SetCaption( VOUT_TITLE " (SDL output)",
693                        VOUT_TITLE " (SDL output)" );
694     SDL_EventState(SDL_KEYUP , SDL_IGNORE);                /* ignore keys up */
695
696     if( p_vout->b_need_render )
697     {
698         p_vout->p_sys->p_sdl_buf[ 0 ] = p_vout->p_sys->p_display->pixels;
699         SDL_Flip(p_vout->p_sys->p_display);
700         p_vout->p_sys->p_sdl_buf[ 1 ] = p_vout->p_sys->p_display->pixels;
701         SDL_Flip(p_vout->p_sys->p_display);
702
703         /* Set clipping for text */
704         clipping_rect.x = 0;
705         clipping_rect.y = 0;
706         clipping_rect.w = p_vout->p_sys->p_display->w;
707         clipping_rect.h = p_vout->p_sys->p_display->h;
708         SDL_SetClipRect(p_vout->p_sys->p_display, &clipping_rect);
709
710         /* Set thread information */
711         p_vout->i_width =           p_vout->p_sys->p_display->w;
712         p_vout->i_height =          p_vout->p_sys->p_display->h;
713         p_vout->i_bytes_per_line =  p_vout->p_sys->p_display->pitch;
714
715         p_vout->i_screen_depth =
716             p_vout->p_sys->p_display->format->BitsPerPixel;
717         p_vout->i_bytes_per_pixel =
718             p_vout->p_sys->p_display->format->BytesPerPixel;
719
720         p_vout->i_red_mask =        p_vout->p_sys->p_display->format->Rmask;
721         p_vout->i_green_mask =      p_vout->p_sys->p_display->format->Gmask;
722         p_vout->i_blue_mask =       p_vout->p_sys->p_display->format->Bmask;
723
724         /* FIXME: palette in 8bpp ?? */
725         /* Set and initialize buffers */
726         p_vout->pf_setbuffers( p_vout, p_vout->p_sys->p_sdl_buf[ 0 ],
727                                        p_vout->p_sys->p_sdl_buf[ 1 ] );
728     }
729     else
730     {
731         p_vout->p_sys->p_sdl_buf[ 0 ] = p_vout->p_sys->p_display->pixels;
732         p_vout->p_sys->p_sdl_buf[ 1 ] = p_vout->p_sys->p_display->pixels;
733
734         /* Set thread information */
735         p_vout->i_width =           p_vout->p_sys->p_display->w;
736         p_vout->i_height =          p_vout->p_sys->p_display->h;
737         p_vout->i_bytes_per_line =  p_vout->p_sys->p_display->pitch;
738
739         p_vout->pf_setbuffers( p_vout, p_vout->p_sys->p_sdl_buf[ 0 ],
740                                        p_vout->p_sys->p_sdl_buf[ 1 ] );
741     }
742
743     p_vout->p_sys->b_reopen_display = 0;
744
745     return( 0 );
746 }
747
748 /*****************************************************************************
749  * SDLCloseDisplay: close and reset SDL device
750  *****************************************************************************
751  * This function returns all resources allocated by SDLOpenDisplay and restore
752  * the original state of the device.
753  *****************************************************************************/
754 static void SDLCloseDisplay( vout_thread_t *p_vout )
755 {
756     if( p_vout->p_sys->p_display != NULL )
757     {
758         if( p_vout->p_sys->p_overlay != NULL )
759         {            
760             SDL_FreeYUVOverlay( p_vout->p_sys->p_overlay );
761             p_vout->p_sys->p_overlay = NULL;
762         }
763
764         SDL_UnlockSurface ( p_vout->p_sys->p_display );
765         SDL_FreeSurface( p_vout->p_sys->p_display );
766         p_vout->p_sys->p_display = NULL;
767     }
768 }
769
770 /*****************************************************************************
771  * OutputCoords: compute the dimensions of the destination image
772  *****************************************************************************
773  * This based on some code in SetBufferPicture... , it is also in use in the
774  * the xvideo plugin. Maybe we should think about putting standard video
775  * processing functions in a common library ?
776  *****************************************************************************/
777 static void OutputCoords( const picture_t *p_pic, const boolean_t scale,
778                           const int win_w, const int win_h,
779                           int *dx, int *dy, int *w, int *h )
780 {
781     if( !scale )
782     {
783         *w = p_pic->i_width; *h = p_pic->i_height;
784     }
785     else
786     {
787         *w = win_w;
788         switch( p_pic->i_aspect_ratio )
789         {
790             case AR_3_4_PICTURE:
791                 *h = win_w * 3 / 4;
792                 break;
793
794             case AR_16_9_PICTURE:
795                 *h = win_w * 9 / 16;
796                 break;
797
798             case AR_221_1_PICTURE:
799                 *h = win_w * 100 / 221;
800                 break;
801
802             case AR_SQUARE_PICTURE:
803             default:
804                 *h = win_w * p_pic->i_height / p_pic->i_width;
805                 break;
806         }
807
808         if( *h > win_h )
809         {
810             *h = win_h;
811             switch( p_pic->i_aspect_ratio )
812             {
813                 case AR_3_4_PICTURE:
814                     *w = win_h * 4 / 3;
815                     break;
816
817                 case AR_16_9_PICTURE:
818                     *w = win_h * 16 / 9;
819                     break;
820
821                 case AR_221_1_PICTURE:
822                     *w = win_h * 221 / 100;
823                     break;
824
825                 case AR_SQUARE_PICTURE:
826                 default:
827                     *w = win_h * p_pic->i_width / p_pic->i_height;
828                     break;
829             }
830         }
831     }
832
833     /* Set picture position */
834     *dx = (win_w - *w) / 2;
835     *dy = (win_h - *h) / 2;
836 }