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