]> git.sesse.net Git - vlc/blob - modules/video_output/sdl.c
* ALL: use i_visible_lines in plane_t.
[vlc] / modules / video_output / sdl.c
1 /*****************************************************************************
2  * sdl.c: SDL video output display method
3  *****************************************************************************
4  * Copyright (C) 1998-2001 VideoLAN
5  * $Id$
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 /*****************************************************************************
27  * Preamble
28  *****************************************************************************/
29 #include <errno.h>                                                 /* ENOMEM */
30 #include <stdlib.h>                                                /* free() */
31 #include <string.h>                                            /* strerror() */
32
33 #include <vlc/vlc.h>
34 #include <vlc/intf.h>
35 #include <vlc/vout.h>
36 #include <vlc/aout.h>
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 #define SDL_MAX_DIRECTBUFFERS 10
46 #define SDL_DEFAULT_BPP 16
47
48 /*****************************************************************************
49  * vout_sys_t: video output SDL method descriptor
50  *****************************************************************************
51  * This structure is part of the video output thread descriptor.
52  * It describes the SDL specific properties of an output thread.
53  *****************************************************************************/
54 struct vout_sys_t
55 {
56     SDL_Surface *   p_display;                             /* display device */
57
58     int i_width;
59     int i_height;
60
61     /* For YUV output */
62     SDL_Overlay * p_overlay;   /* An overlay we keep to grab the XVideo port */
63
64     /* For RGB output */
65     int i_surfaces;
66
67     vlc_bool_t  b_cursor;
68     vlc_bool_t  b_cursor_autohidden;
69     mtime_t     i_lastmoved;
70     mtime_t     i_lastpressed;                        /* to track dbl-clicks */
71 };
72
73 /*****************************************************************************
74  * picture_sys_t: direct buffer method descriptor
75  *****************************************************************************
76  * This structure is part of the picture descriptor, it describes the
77  * SDL specific properties of a direct buffer.
78  *****************************************************************************/
79 struct picture_sys_t
80 {
81     SDL_Overlay *p_overlay;
82 };
83
84 /*****************************************************************************
85  * Local prototypes
86  *****************************************************************************/
87 static int  Open      ( vlc_object_t * );
88 static void Close     ( vlc_object_t * );
89 static int  Init      ( vout_thread_t * );
90 static void End       ( vout_thread_t * );
91 static int  Manage    ( vout_thread_t * );
92 static void Display   ( vout_thread_t *, picture_t * );
93
94 static int  OpenDisplay     ( vout_thread_t * );
95 static void CloseDisplay    ( vout_thread_t * );
96 static int  NewPicture      ( vout_thread_t *, picture_t * );
97 static void SetPalette      ( vout_thread_t *,
98                               uint16_t *, uint16_t *, uint16_t * );
99
100 /*****************************************************************************
101  * Module descriptor
102  *****************************************************************************/
103 vlc_module_begin();
104     set_description( _("Simple DirectMedia Layer video output") );
105     set_capability( "video output", 60 );
106     add_shortcut( "sdl" );
107     set_callbacks( Open, Close );
108     /* XXX: check for conflicts with the SDL audio output */
109     var_Create( p_module->p_libvlc, "sdl", VLC_VAR_MUTEX );
110 #if defined( __i386__ )
111     /* On i386, SDL is linked against svgalib */
112     linked_with_a_crap_library_which_uses_atexit();
113 #endif
114 vlc_module_end();
115
116 /*****************************************************************************
117  * OpenVideo: allocate SDL video thread output method
118  *****************************************************************************
119  * This function allocate and initialize a SDL vout method. It uses some of the
120  * vout properties to choose the correct mode, and change them according to the
121  * mode actually used.
122  *****************************************************************************/
123 static int Open ( vlc_object_t *p_this )
124 {
125     vout_thread_t * p_vout = (vout_thread_t *)p_this;
126     vlc_value_t lockval;
127
128 #ifdef HAVE_SETENV
129     char *psz_method;
130 #endif
131
132     var_Get( p_this->p_libvlc, "sdl", &lockval );
133     vlc_mutex_lock( lockval.p_address );
134
135     if( SDL_WasInit( SDL_INIT_VIDEO ) != 0 )
136     {
137         vlc_mutex_unlock( lockval.p_address );
138         return VLC_EGENERIC;
139     }
140
141     /* Allocate structure */
142     p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
143     if( p_vout->p_sys == NULL )
144     {
145         msg_Err( p_vout, "out of memory" );
146         vlc_mutex_unlock( lockval.p_address );
147         return VLC_ENOMEM;
148     }
149
150     p_vout->pf_init = Init;
151     p_vout->pf_end = End;
152     p_vout->pf_manage = Manage;
153     p_vout->pf_render = NULL;
154     p_vout->pf_display = Display;
155
156 #ifdef HAVE_SETENV
157     psz_method = config_GetPsz( p_vout, "vout" );
158     if( psz_method )
159     {
160         while( *psz_method && *psz_method != ':' )
161         {
162             psz_method++;
163         }
164
165         if( *psz_method )
166         {
167             setenv( "SDL_VIDEODRIVER", psz_method + 1, 1 );
168         }
169     }
170 #endif
171
172     /* Initialize library */
173     if( SDL_Init( SDL_INIT_VIDEO
174 #ifndef WIN32
175     /* Win32 SDL implementation doesn't support SDL_INIT_EVENTTHREAD yet*/
176                 | SDL_INIT_EVENTTHREAD
177 #endif
178 #ifdef DEBUG
179     /* In debug mode you may want vlc to dump a core instead of staying
180      * stuck */
181                 | SDL_INIT_NOPARACHUTE
182 #endif
183                 ) < 0 )
184     {
185         msg_Err( p_vout, "cannot initialize SDL (%s)", SDL_GetError() );
186         free( p_vout->p_sys );
187         vlc_mutex_unlock( lockval.p_address );
188         return VLC_EGENERIC;
189     }
190
191     vlc_mutex_unlock( lockval.p_address );
192
193     p_vout->p_sys->b_cursor = 1;
194     p_vout->p_sys->b_cursor_autohidden = 0;
195     p_vout->p_sys->i_lastmoved = mdate();
196
197     if( OpenDisplay( p_vout ) )
198     {
199         msg_Err( p_vout, "cannot set up SDL (%s)", SDL_GetError() );
200         SDL_QuitSubSystem( SDL_INIT_VIDEO );
201         free( p_vout->p_sys );
202         return VLC_EGENERIC;
203     }
204
205     return VLC_SUCCESS;
206 }
207
208 /*****************************************************************************
209  * Init: initialize SDL video thread output method
210  *****************************************************************************
211  * This function initialize the SDL display device.
212  *****************************************************************************/
213 static int Init( vout_thread_t *p_vout )
214 {
215     int i_index;
216     picture_t *p_pic;
217
218     p_vout->p_sys->i_surfaces = 0;
219
220     I_OUTPUTPICTURES = 0;
221
222     /* Initialize the output structure */
223     if( p_vout->p_sys->p_overlay == NULL )
224     {
225         /* All we have is an RGB image with square pixels */
226         p_vout->output.i_width  = p_vout->p_sys->i_width;
227         p_vout->output.i_height = p_vout->p_sys->i_height;
228         p_vout->output.i_aspect = p_vout->output.i_width
229                                    * VOUT_ASPECT_FACTOR
230                                    / p_vout->output.i_height;
231     }
232     else
233     {
234         /* We may need to convert the chroma, but at least we keep the
235          * aspect ratio */
236         p_vout->output.i_width  = p_vout->render.i_width;
237         p_vout->output.i_height = p_vout->render.i_height;
238         p_vout->output.i_aspect = p_vout->render.i_aspect;
239     }
240
241     /* Try to initialize SDL_MAX_DIRECTBUFFERS direct buffers */
242     while( I_OUTPUTPICTURES < SDL_MAX_DIRECTBUFFERS )
243     {
244         p_pic = NULL;
245
246         /* Find an empty picture slot */
247         for( i_index = 0 ; i_index < VOUT_MAX_PICTURES ; i_index++ )
248         {
249             if( p_vout->p_picture[ i_index ].i_status == FREE_PICTURE )
250             {
251                 p_pic = p_vout->p_picture + i_index;
252                 break;
253             }
254         }
255
256         /* Allocate the picture if we found one */
257         if( p_pic == NULL || NewPicture( p_vout, p_pic ) )
258         {
259             break;
260         }
261
262         p_pic->i_status = DESTROYED_PICTURE;
263         p_pic->i_type   = DIRECT_PICTURE;
264
265         PP_OUTPUTPICTURE[ I_OUTPUTPICTURES ] = p_pic;
266
267         I_OUTPUTPICTURES++;
268     }
269
270     return VLC_SUCCESS;
271 }
272
273 /*****************************************************************************
274  * End: terminate Sys video thread output method
275  *****************************************************************************
276  * Terminate an output method created by OpenVideo
277  *****************************************************************************/
278 static void End( vout_thread_t *p_vout )
279 {
280     int i_index;
281
282     /* Free the output buffers we allocated */
283     for( i_index = I_OUTPUTPICTURES ; i_index ; )
284     {
285         i_index--;
286         if( p_vout->p_sys->p_overlay == NULL )
287         {
288             /* RGB picture */
289         }
290         else
291         {
292             SDL_UnlockYUVOverlay(
293                     PP_OUTPUTPICTURE[ i_index ]->p_sys->p_overlay );
294             SDL_FreeYUVOverlay(
295                     PP_OUTPUTPICTURE[ i_index ]->p_sys->p_overlay );
296         }
297         free( PP_OUTPUTPICTURE[ i_index ]->p_sys );
298     }
299 }
300
301 /*****************************************************************************
302  * CloseVideo: destroy Sys video thread output method
303  *****************************************************************************
304  * Terminate an output method created by vout_SDLCreate
305  *****************************************************************************/
306 static void Close ( vlc_object_t *p_this )
307 {
308     vout_thread_t * p_vout = (vout_thread_t *)p_this;
309
310     CloseDisplay( p_vout );
311     SDL_QuitSubSystem( SDL_INIT_VIDEO );
312
313     free( p_vout->p_sys );
314 }
315
316 /*****************************************************************************
317  * Manage: handle Sys events
318  *****************************************************************************
319  * This function should be called regularly by video output thread. It returns
320  * a non null value if an error occurred.
321  *****************************************************************************/
322 static int Manage( vout_thread_t *p_vout )
323 {
324     SDL_Event event;                                            /* SDL event */
325     vlc_value_t val;
326     int i_width, i_height, i_x, i_y;
327
328     /* Process events */
329     while( SDL_PollEvent(&event) )
330     {
331         switch( event.type )
332         {
333         case SDL_VIDEORESIZE:                          /* Resizing of window */
334             /* Update dimensions */
335             p_vout->i_changes |= VOUT_SIZE_CHANGE;
336             p_vout->i_window_width = p_vout->p_sys->i_width = event.resize.w;
337             p_vout->i_window_height = p_vout->p_sys->i_height = event.resize.h;
338             break;
339
340         case SDL_MOUSEMOTION:
341             vout_PlacePicture( p_vout, p_vout->p_sys->i_width,
342                                p_vout->p_sys->i_height,
343                                &i_x, &i_y, &i_width, &i_height );
344
345             val.i_int = ( event.motion.x - i_x )
346                          * p_vout->render.i_width / i_width;
347             var_Set( p_vout, "mouse-x", val );
348             val.i_int = ( event.motion.y - i_y )
349                          * p_vout->render.i_height / i_height;
350             var_Set( p_vout, "mouse-y", val );
351
352             val.b_bool = VLC_TRUE;
353             var_Set( p_vout, "mouse-moved", val );
354
355             if( p_vout->p_sys->b_cursor &&
356                 (abs(event.motion.xrel) > 2 || abs(event.motion.yrel) > 2) )
357             {
358                 if( p_vout->p_sys->b_cursor_autohidden )
359                 {
360                     p_vout->p_sys->b_cursor_autohidden = 0;
361                     SDL_ShowCursor( 1 );
362                 }
363                 else
364                 {
365                     p_vout->p_sys->i_lastmoved = mdate();
366                 }
367             }
368             break;
369
370         case SDL_MOUSEBUTTONUP:
371             switch( event.button.button )
372             {
373             case SDL_BUTTON_LEFT:
374                 val.b_bool = VLC_TRUE;
375                 var_Set( p_vout, "mouse-clicked", val );
376                 break;
377
378             case SDL_BUTTON_RIGHT:
379                 {
380                     intf_thread_t *p_intf;
381                     p_intf = vlc_object_find( p_vout, VLC_OBJECT_INTF,
382                                                       FIND_ANYWHERE );
383                     if( p_intf )
384                     {
385                         p_intf->b_menu_change = 1;
386                         vlc_object_release( p_intf );
387                     }
388                 }
389                 break;
390             }
391             break;
392
393         case SDL_MOUSEBUTTONDOWN:
394             switch( event.button.button )
395             {
396             case SDL_BUTTON_LEFT:
397                 /* In this part we will eventually manage
398                  * clicks for DVD navigation for instance. */
399
400                 /* detect double-clicks */
401                 if( ( mdate() - p_vout->p_sys->i_lastpressed ) < 300000 )
402                     p_vout->i_changes |= VOUT_FULLSCREEN_CHANGE;
403
404                 p_vout->p_sys->i_lastpressed = mdate();
405                 break;
406
407             case 4:
408                 break;
409
410             case 5:
411                 break;
412             }
413             break;
414
415         case SDL_QUIT:
416             p_vout->p_vlc->b_die = 1;
417             break;
418
419         case SDL_KEYDOWN:                             /* if a key is pressed */
420
421             switch( event.key.keysym.sym )
422             {
423             case SDLK_ESCAPE:
424                 if( p_vout->b_fullscreen )
425                 {
426                     p_vout->i_changes |= VOUT_FULLSCREEN_CHANGE;
427                 }
428                 else
429                 {
430                     p_vout->p_vlc->b_die = 1;
431                 }
432                 break;
433
434             case SDLK_q:                                             /* quit */
435                 p_vout->p_vlc->b_die = 1;
436                 break;
437
438             case SDLK_f:                             /* switch to fullscreen */
439                 p_vout->i_changes |= VOUT_FULLSCREEN_CHANGE;
440                 break;
441
442             case SDLK_c:                                 /* toggle grayscale */
443                 p_vout->b_grayscale = ! p_vout->b_grayscale;
444                 p_vout->i_changes |= VOUT_GRAYSCALE_CHANGE;
445                 break;
446
447             case SDLK_i:                                      /* toggle info */
448                 p_vout->b_info = ! p_vout->b_info;
449                 p_vout->i_changes |= VOUT_INFO_CHANGE;
450                 break;
451
452             case SDLK_s:                                   /* toggle scaling */
453                 p_vout->b_scale = ! p_vout->b_scale;
454                 p_vout->i_changes |= VOUT_SCALE_CHANGE;
455                 break;
456
457             case SDLK_SPACE:                             /* toggle interface */
458                 p_vout->b_interface = ! p_vout->b_interface;
459                 p_vout->i_changes |= VOUT_INTF_CHANGE;
460                 break;
461
462             case SDLK_MENU:
463                 {
464                     intf_thread_t *p_intf;
465                     p_intf = vlc_object_find( p_vout, VLC_OBJECT_INTF,
466                                                       FIND_ANYWHERE );
467                     if( p_intf != NULL )
468                     {
469                         p_intf->b_menu_change = 1;
470                         vlc_object_release( p_intf );
471                     }
472                 }
473                 break;
474
475             case SDLK_LEFT:
476                 break;
477
478             case SDLK_RIGHT:
479                 break;
480
481             case SDLK_UP:
482                 break;
483
484             case SDLK_DOWN:
485                 break;
486
487             case SDLK_b:
488                 {
489                     audio_volume_t i_volume;
490                     if ( !aout_VolumeDown( p_vout, 1, &i_volume ) )
491                     {
492                         msg_Dbg( p_vout, "audio volume is now %d", i_volume );
493                     }
494                     else
495                     {
496                         msg_Dbg( p_vout, "audio volume: operation not supported" );
497                     }
498                 }
499                 break;
500
501             case SDLK_n:
502                 {
503                     audio_volume_t i_volume;
504                     if ( !aout_VolumeUp( p_vout, 1, &i_volume ) )
505                     {
506                         msg_Dbg( p_vout, "audio volume is now %d", i_volume );
507                     }
508                     else
509                     {
510                         msg_Dbg( p_vout, "audio volume: operation not supported" );
511                     }
512                 }
513                 break;
514
515              default:
516                 break;
517             }
518             break;
519
520         default:
521             break;
522         }
523     }
524
525     /* Fullscreen change */
526     if( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE )
527     {
528         p_vout->b_fullscreen = ! p_vout->b_fullscreen;
529
530         p_vout->p_sys->b_cursor_autohidden = 0;
531         SDL_ShowCursor( p_vout->p_sys->b_cursor &&
532                         ! p_vout->p_sys->b_cursor_autohidden );
533
534         p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
535         p_vout->i_changes |= VOUT_SIZE_CHANGE;
536     }
537
538     /*
539      * Size change
540      */
541     if( p_vout->i_changes & VOUT_SIZE_CHANGE )
542     {
543         msg_Dbg( p_vout, "video display resized (%dx%d)",
544                  p_vout->p_sys->i_width, p_vout->p_sys->i_height );
545
546         CloseDisplay( p_vout );
547         OpenDisplay( p_vout );
548
549         /* We don't need to signal the vout thread about the size change if
550          * we can handle rescaling ourselves */
551         if( p_vout->p_sys->p_overlay != NULL )
552             p_vout->i_changes &= ~VOUT_SIZE_CHANGE;
553
554     }
555
556     /* Pointer change */
557     if( ! p_vout->p_sys->b_cursor_autohidden &&
558         ( mdate() - p_vout->p_sys->i_lastmoved > 2000000 ) )
559     {
560         /* Hide the mouse automatically */
561         p_vout->p_sys->b_cursor_autohidden = 1;
562         SDL_ShowCursor( 0 );
563     }
564
565     return VLC_SUCCESS;
566 }
567
568 /*****************************************************************************
569  * Display: displays previously rendered output
570  *****************************************************************************
571  * This function sends the currently rendered image to the display.
572  *****************************************************************************/
573 static void Display( vout_thread_t *p_vout, picture_t *p_pic )
574 {
575     int x, y, w, h;
576     SDL_Rect disp;
577
578     vout_PlacePicture( p_vout, p_vout->p_sys->i_width, p_vout->p_sys->i_height,
579                        &x, &y, &w, &h );
580     disp.x = x;
581     disp.y = y;
582     disp.w = w;
583     disp.h = h;
584
585     if( p_vout->p_sys->p_overlay == NULL )
586     {
587         /* RGB picture */
588         SDL_Flip( p_vout->p_sys->p_display );
589     }
590     else
591     {
592         /* Overlay picture */
593         SDL_UnlockYUVOverlay( p_pic->p_sys->p_overlay);
594         SDL_DisplayYUVOverlay( p_pic->p_sys->p_overlay , &disp );
595         SDL_LockYUVOverlay( p_pic->p_sys->p_overlay);
596     }
597 }
598
599 /* following functions are local */
600
601 /*****************************************************************************
602  * OpenDisplay: open and initialize SDL device
603  *****************************************************************************
604  * Open and initialize display according to preferences specified in the vout
605  * thread fields.
606  *****************************************************************************/
607 static int OpenDisplay( vout_thread_t *p_vout )
608 {
609     uint32_t i_flags;
610     int i_bpp;
611
612     /* SDL fucked up fourcc definitions on bigendian machines */
613     uint32_t i_sdl_chroma;
614
615     /* Set main window's size */
616     p_vout->p_sys->i_width = p_vout->b_fullscreen ? p_vout->output.i_width :
617                                                     p_vout->i_window_width;
618     p_vout->p_sys->i_height = p_vout->b_fullscreen ? p_vout->output.i_height :
619                                                      p_vout->i_window_height;
620
621     /* Initialize flags and cursor */
622     i_flags = SDL_ANYFORMAT | SDL_HWPALETTE | SDL_HWSURFACE | SDL_DOUBLEBUF;
623     i_flags |= p_vout->b_fullscreen ? SDL_FULLSCREEN : SDL_RESIZABLE;
624
625     i_bpp = SDL_VideoModeOK( p_vout->p_sys->i_width, p_vout->p_sys->i_height,
626                              SDL_DEFAULT_BPP, i_flags );
627     if( i_bpp == 0 )
628     {
629         msg_Err( p_vout, "no video mode available" );
630         return VLC_EGENERIC;
631     }
632
633     p_vout->p_sys->p_display = SDL_SetVideoMode( p_vout->p_sys->i_width,
634                                                  p_vout->p_sys->i_height,
635                                                  i_bpp, i_flags );
636
637     if( p_vout->p_sys->p_display == NULL )
638     {
639         msg_Err( p_vout, "cannot set video mode" );
640         return VLC_EGENERIC;
641     }
642
643     SDL_LockSurface( p_vout->p_sys->p_display );
644
645     /* Choose the chroma we will try first. */
646     switch( p_vout->render.i_chroma )
647     {
648         case VLC_FOURCC('Y','U','Y','2'):
649         case VLC_FOURCC('Y','U','N','V'):
650             p_vout->output.i_chroma = VLC_FOURCC('Y','U','Y','2');
651             i_sdl_chroma = SDL_YUY2_OVERLAY;
652             break;
653         case VLC_FOURCC('U','Y','V','Y'):
654         case VLC_FOURCC('U','Y','N','V'):
655         case VLC_FOURCC('Y','4','2','2'):
656             p_vout->output.i_chroma = VLC_FOURCC('U','Y','V','Y');
657             i_sdl_chroma = SDL_UYVY_OVERLAY;
658             break;
659         case VLC_FOURCC('Y','V','Y','U'):
660             p_vout->output.i_chroma = VLC_FOURCC('Y','V','Y','U');
661             i_sdl_chroma = SDL_YVYU_OVERLAY;
662             break;
663         case VLC_FOURCC('Y','V','1','2'):
664         case VLC_FOURCC('I','4','2','0'):
665         case VLC_FOURCC('I','Y','U','V'):
666         default:
667             p_vout->output.i_chroma = VLC_FOURCC('Y','V','1','2');
668             i_sdl_chroma = SDL_YV12_OVERLAY;
669             break;
670     }
671
672     p_vout->p_sys->p_overlay =
673         SDL_CreateYUVOverlay( 32, 32, i_sdl_chroma, p_vout->p_sys->p_display );
674     /* FIXME: if the first overlay we find is software, don't stop,
675      * because we may find a hardware one later ... */
676
677     /* If this best choice failed, fall back to other chromas */
678     if( p_vout->p_sys->p_overlay == NULL )
679     {
680         p_vout->output.i_chroma = VLC_FOURCC('I','Y','U','V');
681         p_vout->p_sys->p_overlay =
682             SDL_CreateYUVOverlay( 32, 32, SDL_IYUV_OVERLAY,
683                                   p_vout->p_sys->p_display );
684     }
685
686     if( p_vout->p_sys->p_overlay == NULL )
687     {
688         p_vout->output.i_chroma = VLC_FOURCC('Y','V','1','2');
689         p_vout->p_sys->p_overlay =
690             SDL_CreateYUVOverlay( 32, 32, SDL_YV12_OVERLAY,
691                                   p_vout->p_sys->p_display );
692     }
693
694     if( p_vout->p_sys->p_overlay == NULL )
695     {
696         p_vout->output.i_chroma = VLC_FOURCC('Y','U','Y','2');
697         p_vout->p_sys->p_overlay =
698             SDL_CreateYUVOverlay( 32, 32, SDL_YUY2_OVERLAY,
699                                   p_vout->p_sys->p_display );
700     }
701
702     if( p_vout->p_sys->p_overlay == NULL )
703     {
704         msg_Warn( p_vout, "no SDL overlay for 0x%.8x (%4.4s)",
705                   p_vout->render.i_chroma, (char*)&p_vout->render.i_chroma );
706
707         switch( p_vout->p_sys->p_display->format->BitsPerPixel )
708         {
709             case 8:
710                 p_vout->output.i_chroma = VLC_FOURCC('R','G','B','2');
711                 p_vout->output.pf_setpalette = SetPalette;
712                 break;
713             case 15:
714                 p_vout->output.i_chroma = VLC_FOURCC('R','V','1','5');
715                 break;
716             case 16:
717                 p_vout->output.i_chroma = VLC_FOURCC('R','V','1','6');
718                 break;
719             case 24:
720                 p_vout->output.i_chroma = VLC_FOURCC('R','V','2','4');
721                 break;
722             case 32:
723                 p_vout->output.i_chroma = VLC_FOURCC('R','V','3','2');
724                 break;
725             default:
726                 msg_Err( p_vout, "unknown screen depth %i",
727                          p_vout->p_sys->p_display->format->BitsPerPixel );
728                 SDL_UnlockSurface( p_vout->p_sys->p_display );
729                 SDL_FreeSurface( p_vout->p_sys->p_display );
730                 return VLC_EGENERIC;
731         }
732
733         p_vout->output.i_rmask = p_vout->p_sys->p_display->format->Rmask;
734         p_vout->output.i_gmask = p_vout->p_sys->p_display->format->Gmask;
735         p_vout->output.i_bmask = p_vout->p_sys->p_display->format->Bmask;
736
737         SDL_WM_SetCaption( VOUT_TITLE " (software RGB SDL output)",
738                            VOUT_TITLE " (software RGB SDL output)" );
739     }
740     else
741     {
742         if( p_vout->p_sys->p_overlay->hw_overlay )
743         {
744             SDL_WM_SetCaption( VOUT_TITLE " (hardware YUV SDL output)",
745                                VOUT_TITLE " (hardware YUV SDL output)" );
746         }
747         else
748         {
749             SDL_WM_SetCaption( VOUT_TITLE " (software YUV SDL output)",
750                                VOUT_TITLE " (software YUV SDL output)" );
751         }
752     }
753
754     SDL_EventState( SDL_KEYUP, SDL_IGNORE );               /* ignore keys up */
755
756     return VLC_SUCCESS;
757 }
758
759 /*****************************************************************************
760  * CloseDisplay: close and reset SDL device
761  *****************************************************************************
762  * This function returns all resources allocated by OpenDisplay and restore
763  * the original state of the device.
764  *****************************************************************************/
765 static void CloseDisplay( vout_thread_t *p_vout )
766 {
767     SDL_FreeYUVOverlay( p_vout->p_sys->p_overlay );
768     SDL_UnlockSurface ( p_vout->p_sys->p_display );
769     SDL_FreeSurface( p_vout->p_sys->p_display );
770 }
771
772 /*****************************************************************************
773  * NewPicture: allocate a picture
774  *****************************************************************************
775  * Returns 0 on success, -1 otherwise
776  *****************************************************************************/
777 static int NewPicture( vout_thread_t *p_vout, picture_t *p_pic )
778 {
779     int i_width  = p_vout->output.i_width;
780     int i_height = p_vout->output.i_height;
781
782     if( p_vout->p_sys->p_overlay == NULL )
783     {
784         /* RGB picture */
785         if( p_vout->p_sys->i_surfaces )
786         {
787             /* We already allocated this surface, return */
788             return VLC_EGENERIC;
789         }
790
791         p_pic->p_sys = malloc( sizeof( picture_sys_t ) );
792
793         if( p_pic->p_sys == NULL )
794         {
795             return VLC_ENOMEM;
796         }
797
798         switch( p_vout->p_sys->p_display->format->BitsPerPixel )
799         {
800             case 8:
801                 p_pic->p->i_pixel_pitch = 1;
802                 break;
803             case 15:
804             case 16:
805                 p_pic->p->i_pixel_pitch = 2;
806                 break;
807             case 24:
808             case 32:
809                 p_pic->p->i_pixel_pitch = 4;
810                 break;
811             default:
812                 return VLC_EGENERIC;
813         }
814
815         p_pic->p->p_pixels = p_vout->p_sys->p_display->pixels;
816         p_pic->p->i_lines = p_vout->p_sys->p_display->h;
817         p_pic->p->i_visible_lines = p_vout->p_sys->p_display->h;
818         p_pic->p->i_pitch = p_vout->p_sys->p_display->pitch;
819         p_pic->p->i_visible_pitch =
820             p_pic->p->i_pixel_pitch * p_vout->p_sys->p_display->w;
821
822         p_vout->p_sys->i_surfaces++;
823
824         p_pic->i_planes = 1;
825     }
826     else
827     {
828         p_pic->p_sys = malloc( sizeof( picture_sys_t ) );
829
830         if( p_pic->p_sys == NULL )
831         {
832             return VLC_ENOMEM;
833         }
834
835         p_pic->p_sys->p_overlay =
836             SDL_CreateYUVOverlay( i_width, i_height,
837                                   p_vout->output.i_chroma,
838                                   p_vout->p_sys->p_display );
839
840         if( p_pic->p_sys->p_overlay == NULL )
841         {
842             free( p_pic->p_sys );
843             return VLC_EGENERIC;
844         }
845
846         SDL_LockYUVOverlay( p_pic->p_sys->p_overlay );
847
848         p_pic->Y_PIXELS = p_pic->p_sys->p_overlay->pixels[0];
849         p_pic->p[Y_PLANE].i_lines = p_pic->p_sys->p_overlay->h;
850         p_pic->p[Y_PLANE].i_visible_lines = p_pic->p_sys->p_overlay->h;
851         p_pic->p[Y_PLANE].i_pitch = p_pic->p_sys->p_overlay->pitches[0];
852
853         switch( p_vout->output.i_chroma )
854         {
855         case SDL_YV12_OVERLAY:
856             p_pic->p[Y_PLANE].i_pixel_pitch = 1;
857             p_pic->p[Y_PLANE].i_visible_pitch = p_pic->p_sys->p_overlay->w;
858
859             p_pic->U_PIXELS = p_pic->p_sys->p_overlay->pixels[2];
860             p_pic->p[U_PLANE].i_lines = p_pic->p_sys->p_overlay->h / 2;
861             p_pic->p[U_PLANE].i_visible_lines = p_pic->p_sys->p_overlay->h / 2;
862             p_pic->p[U_PLANE].i_pitch = p_pic->p_sys->p_overlay->pitches[2];
863             p_pic->p[U_PLANE].i_pixel_pitch = 1;
864             p_pic->p[U_PLANE].i_visible_pitch = p_pic->p_sys->p_overlay->w / 2;
865
866             p_pic->V_PIXELS = p_pic->p_sys->p_overlay->pixels[1];
867             p_pic->p[V_PLANE].i_lines = p_pic->p_sys->p_overlay->h / 2;
868             p_pic->p[V_PLANE].i_visible_lines = p_pic->p_sys->p_overlay->h / 2;
869             p_pic->p[V_PLANE].i_pitch = p_pic->p_sys->p_overlay->pitches[1];
870             p_pic->p[V_PLANE].i_pixel_pitch = 1;
871             p_pic->p[V_PLANE].i_visible_pitch = p_pic->p_sys->p_overlay->w / 2;
872
873             p_pic->i_planes = 3;
874             break;
875
876         case SDL_IYUV_OVERLAY:
877             p_pic->p[Y_PLANE].i_pixel_pitch = 1;
878             p_pic->p[Y_PLANE].i_visible_pitch = p_pic->p_sys->p_overlay->w;
879
880             p_pic->U_PIXELS = p_pic->p_sys->p_overlay->pixels[1];
881             p_pic->p[U_PLANE].i_lines = p_pic->p_sys->p_overlay->h / 2;
882             p_pic->p[U_PLANE].i_visible_lines = p_pic->p_sys->p_overlay->h / 2;
883             p_pic->p[U_PLANE].i_pitch = p_pic->p_sys->p_overlay->pitches[1];
884             p_pic->p[U_PLANE].i_pixel_pitch = 1;
885             p_pic->p[U_PLANE].i_visible_pitch = p_pic->p_sys->p_overlay->w / 2;
886
887             p_pic->V_PIXELS = p_pic->p_sys->p_overlay->pixels[2];
888             p_pic->p[V_PLANE].i_lines = p_pic->p_sys->p_overlay->h / 2;
889             p_pic->p[V_PLANE].i_visible_lines = p_pic->p_sys->p_overlay->h / 2;
890             p_pic->p[V_PLANE].i_pitch = p_pic->p_sys->p_overlay->pitches[2];
891             p_pic->p[V_PLANE].i_pixel_pitch = 1;
892             p_pic->p[V_PLANE].i_visible_pitch = p_pic->p_sys->p_overlay->w / 2;
893
894             p_pic->i_planes = 3;
895             break;
896
897         default:
898             p_pic->p[Y_PLANE].i_pixel_pitch = 2;
899             p_pic->p[U_PLANE].i_visible_pitch = p_pic->p_sys->p_overlay->w * 2;
900
901             p_pic->i_planes = 1;
902             break;
903         }
904     }
905
906     return VLC_SUCCESS;
907 }
908
909 /*****************************************************************************
910  * SetPalette: sets an 8 bpp palette
911  *****************************************************************************/
912 static void SetPalette( vout_thread_t *p_vout,
913                         uint16_t *red, uint16_t *green, uint16_t *blue )
914 {
915     SDL_Color colors[256];
916     int i;
917
918     /* Fill colors with color information */
919     for( i = 0; i < 256; i++ )
920     {
921         colors[ i ].r = red[ i ] >> 8;
922         colors[ i ].g = green[ i ] >> 8;
923         colors[ i ].b = blue[ i ] >> 8;
924     }
925
926     /* Set palette */
927     if( SDL_SetColors( p_vout->p_sys->p_display, colors, 0, 256 ) == 0 )
928     {
929         msg_Err( p_vout, "failed setting palette" );
930     }
931 }
932