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