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