vout_sdl.c 14.2 KB
Newer Older
Pierre Baillet's avatar
Pierre Baillet committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
/*****************************************************************************
 * vout_sdl.c: SDL video output display method
 *****************************************************************************
 * Copyright (C) 1998, 1999, 2000 VideoLAN
 *
 * Authors:
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
 *****************************************************************************/

/*****************************************************************************
 * Preamble
 *****************************************************************************/
#include "defs.h"

#include <errno.h>                                                 /* ENOMEM */
#include <stdlib.h>                                                /* free() */
#include <string.h>                                            /* strerror() */

#include <SDL/SDL.h>

#include "config.h"
#include "common.h"
#include "threads.h"
#include "mtime.h"
#include "plugins.h"

#include "video.h"
#include "video_output.h"

#include "intf_msg.h"

/*****************************************************************************
 * vout_sys_t: video output SDL method descriptor
 *****************************************************************************
 * This structure is part of the video output thread descriptor.
 * It describes the SDL specific properties of an output thread.
 *****************************************************************************/
typedef struct vout_sys_s
{
    SDL_Surface *   p_display;                             /* display device */
54
55
56
    SDL_Overlay *   p_overlay;                             /* overlay device */
    boolean_t   b_fullscreen;
    boolean_t   b_reopen_display;
Pierre Baillet's avatar
Pierre Baillet committed
57
58
59
60
61
62
63
64
    Uint8   *   p_buffer[2];
                                                     /* Buffers informations */
    boolean_t   b_must_acquire;           /* must be acquired before writing */
}   vout_sys_t;

/*****************************************************************************
 * Local prototypes
 *****************************************************************************/
65
static int     SDLOpenDisplay   ( vout_thread_t *p_vout );
Pierre Baillet's avatar
Pierre Baillet committed
66
67
68
69
70
71
72
73
74
static void    SDLCloseDisplay  ( vout_thread_t *p_vout );

/*****************************************************************************
 * vout_SDLCreate: allocate SDL video thread output method
 *****************************************************************************
 * This function allocate and initialize a SDL vout method. It uses some of the
 * vout properties to choose the correct mode, and change them according to the
 * mode actually used.
 *****************************************************************************/
75
76
int vout_SDLCreate( vout_thread_t *p_vout, char *psz_display,
                    int i_root_window, void *p_data )
Pierre Baillet's avatar
Pierre Baillet committed
77
78
79
80
81
{
    /* Allocate structure */
    p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
    if( p_vout->p_sys == NULL )
    {
82
        intf_ErrMsg( "error: %s\n", strerror(ENOMEM) );
Pierre Baillet's avatar
Pierre Baillet committed
83
84
85
        return( 1 );
    }

86
87
88
89
90
    p_vout->p_sys->p_display = NULL;
    p_vout->p_sys->p_overlay = NULL;

    /* Initialize library */
    if( SDL_Init(SDL_INIT_VIDEO) < 0 )
Pierre Baillet's avatar
Pierre Baillet committed
91
    {
92
93
        intf_ErrMsg( "error: can't initialize SDL library: %s\n",
                     SDL_GetError() );
Pierre Baillet's avatar
Pierre Baillet committed
94
95
96
        free( p_vout->p_sys );
        return( 1 );
    }
97
98

    if( SDLOpenDisplay(p_vout) )
99
    {
100
101
102
103
        intf_ErrMsg( "error: can't initialize SDL library: %s\n",
                     SDL_GetError() );
        free( p_vout->p_sys );
        return( 1 );
104
    }
105
106
107
108
109
110
111
112
113
114
115
116
117
118

    /* Force the software yuv even if it is not used */
    /* If we don't do this, p_vout is not correctly initialized
       and it's impossible to switch between soft/hard yuv */
    p_vout->b_need_render = 1;

    if(psz_display != NULL && strcmp(psz_display,"fullscreen")==0)
    {
        p_vout->p_sys->b_fullscreen = 1;
    } else {
        p_vout->p_sys->b_fullscreen = 0;
    }
    p_vout->p_sys->b_reopen_display = 1;

Pierre Baillet's avatar
Pierre Baillet committed
119
120
121
122
123
124
125
126
127
128
129
130
131
    return( 0 );
}

/*****************************************************************************
 * vout_SDLInit: initialize SDL video thread output method
 *****************************************************************************
 * This function initialize the SDL display device.
 *****************************************************************************/
int vout_SDLInit( vout_thread_t *p_vout )
{
    /* Acquire first buffer */
    if( p_vout->p_sys->b_must_acquire )
    {
132
        SDL_LockSurface(p_vout->p_sys->p_display);
Pierre Baillet's avatar
Pierre Baillet committed
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
    }

    return( 0 );
}

/*****************************************************************************
 * vout_SDLEnd: terminate Sys video thread output method
 *****************************************************************************
 * Terminate an output method created by vout_SDLCreate
 *****************************************************************************/
void vout_SDLEnd( vout_thread_t *p_vout )
{
    /* Release buffer */
    if( p_vout->p_sys->b_must_acquire )
    {
        SDL_UnlockSurface ( p_vout->p_sys->p_display );
    }
150
    free( p_vout->p_sys );
Pierre Baillet's avatar
Pierre Baillet committed
151
152
153
154
155
156
157
158
159
}

/*****************************************************************************
 * vout_SDLDestroy: destroy Sys video thread output method
 *****************************************************************************
 * Terminate an output method created by vout_SDLCreate
 *****************************************************************************/
void vout_SDLDestroy( vout_thread_t *p_vout )
{
160
    SDLCloseDisplay( p_vout );
Pierre Baillet's avatar
Pierre Baillet committed
161
162
163
164
165
166
167
168
169
170
171
    free( p_vout->p_sys );
}

/*****************************************************************************
 * vout_SDLManage: handle Sys events
 *****************************************************************************
 * This function should be called regularly by video output thread. It returns
 * a non null value if an error occured.
 *****************************************************************************/
int vout_SDLManage( vout_thread_t *p_vout )
{
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
    /* If the display has to be reopened we do so */
    if( p_vout->p_sys->b_reopen_display )
    {
        p_vout->p_sys->b_must_acquire = 0;
        if( p_vout->p_sys->p_display )
        {
            if( p_vout->p_sys->p_overlay )
            {
                SDL_FreeYUVOverlay(p_vout->p_sys->p_overlay);
                p_vout->p_sys->p_overlay = NULL;
            }
            SDL_FreeSurface( p_vout->p_sys->p_display );
            p_vout->p_sys->p_display = NULL;
        }

        if( SDLOpenDisplay(p_vout) )
        {
          intf_ErrMsg( "error: can't open DISPLAY default display\n" );
          return( 1 );
        }
        p_vout->p_sys->b_reopen_display = 0;
    }
Pierre Baillet's avatar
Pierre Baillet committed
194
195
196
197
198
199
200
201
202
203
204
    return( 0 );
}

/*****************************************************************************
 * vout_SDLDisplay: displays previously rendered output
 *****************************************************************************
 * This function send the currently rendered image to the display, wait until
 * it is displayed and switch the two rendering buffer, preparing next frame.
 *****************************************************************************/
void vout_SDLDisplay( vout_thread_t *p_vout )
{
Pierre Baillet's avatar
Pierre Baillet committed
205
    SDL_Rect    disp;
206
207
    if(p_vout->b_need_render)
    {  
Pierre Baillet's avatar
Pierre Baillet committed
208
209
210
        /* Change display frame */
        if( p_vout->p_sys->b_must_acquire )
        {
211
            
Pierre Baillet's avatar
Pierre Baillet committed
212
            SDL_Flip( p_vout->p_sys->p_display );
213
            
214
            /* Swap buffers and change write frame */
Pierre Baillet's avatar
Pierre Baillet committed
215
216
            SDL_LockSurface ( p_vout->p_sys->p_display );
        }
217
218
219
     }
     else
     {
220
        
Pierre Baillet's avatar
Pierre Baillet committed
221
        /*
222
         * p_vout->p_rendered_pic->p_y/u/v contains the YUV buffers to render 
Pierre Baillet's avatar
Pierre Baillet committed
223
         */
224
225
226
227
228
229
230
231
232
233
234
235
        if( p_vout->p_sys->b_must_acquire )
        {
            /* TODO: support for streams other than 4:2:0 */
            /* create the overlay if necessary */
            if( !p_vout->p_sys->p_overlay )
            {
                p_vout->p_sys->p_overlay = SDL_CreateYUVOverlay( 
                                             p_vout->p_rendered_pic->i_width, 
                                             p_vout->p_rendered_pic->i_height, 
                                             SDL_YV12_OVERLAY, 
                                             p_vout->p_sys->p_display
                                           );
236
237
                intf_Msg("[YUV acceleration] : %d,\n",
                            p_vout->p_sys->p_overlay->hw_overlay); 
238
            }
239

240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
            SDL_LockYUVOverlay(p_vout->p_sys->p_overlay);
            /* copy the data into video buffers */
            /* Y first */
            memcpy(p_vout->p_sys->p_overlay->pixels[0],
                   p_vout->p_rendered_pic->p_y,
                   p_vout->p_sys->p_overlay->h *
                   p_vout->p_sys->p_overlay->pitches[0]);
            /* then V */
            memcpy(p_vout->p_sys->p_overlay->pixels[1],
                   p_vout->p_rendered_pic->p_v,
                   p_vout->p_sys->p_overlay->h *
                   p_vout->p_sys->p_overlay->pitches[1] / 2);
            /* and U */
            memcpy(p_vout->p_sys->p_overlay->pixels[2],
                   p_vout->p_rendered_pic->p_u,
                   p_vout->p_sys->p_overlay->h *
                   p_vout->p_sys->p_overlay->pitches[2] / 2);
257
258
259
260
261
262
       
            disp.w = (&p_vout->p_buffer[p_vout->i_buffer_index])->i_pic_width;
            disp.h = (&p_vout->p_buffer[p_vout->i_buffer_index])->i_pic_height;
            disp.x = (p_vout->i_width - disp.w)/2;
            disp.y = (p_vout->i_height - disp.h)/2;
 
263
264
265
266
            SDL_DisplayYUVOverlay( p_vout->p_sys->p_overlay , &disp );
            SDL_UnlockYUVOverlay(p_vout->p_sys->p_overlay);
        }
    }
Pierre Baillet's avatar
Pierre Baillet committed
267
268
269
270
271
272
273
274
275
276
}

/* following functions are local */

/*****************************************************************************
 * SDLOpenDisplay: open and initialize SDL device
 *****************************************************************************
 * Open and initialize display according to preferences specified in the vout
 * thread fields.
 *****************************************************************************/
277
static int SDLOpenDisplay( vout_thread_t *p_vout )
Pierre Baillet's avatar
Pierre Baillet committed
278
{
279
    SDL_Rect    clipping_rect;
280
    
Pierre Baillet's avatar
Pierre Baillet committed
281
282
283
    /* Open display 
     * TODO: Check that we can request for a DOUBLEBUF HWSURFACE display
     */
284
    if( p_vout->p_sys->b_fullscreen )
Pierre Baillet's avatar
Pierre Baillet committed
285
    {
Pierre Baillet's avatar
Pierre Baillet committed
286
287
        p_vout->p_sys->p_display = SDL_SetVideoMode(p_vout->i_width, 
            p_vout->i_height, 
288
            0, 
Pierre Baillet's avatar
Pierre Baillet committed
289
            SDL_ANYFORMAT | SDL_HWSURFACE | SDL_DOUBLEBUF | SDL_FULLSCREEN );
290
        SDL_ShowCursor( 0 );
Pierre Baillet's avatar
Pierre Baillet committed
291
292
293
    } else {
        p_vout->p_sys->p_display = SDL_SetVideoMode(p_vout->i_width, 
            p_vout->i_height, 
294
295
296
            0, 
            SDL_ANYFORMAT | SDL_HWSURFACE | SDL_DOUBLEBUF  );
        SDL_ShowCursor( 1 );
Pierre Baillet's avatar
Pierre Baillet committed
297
298
299
300
    }
	
    if( p_vout->p_sys->p_display == NULL )
    {
301
        intf_ErrMsg( "error: can't open DISPLAY default display\n" );
Pierre Baillet's avatar
Pierre Baillet committed
302
303
        return( 1 );
    }
304
    p_vout->p_sys->p_overlay = NULL;
305
    SDL_WM_SetCaption( VOUT_TITLE , VOUT_TITLE );
Pierre Baillet's avatar
Pierre Baillet committed
306
307
    SDL_EventState(SDL_KEYUP , SDL_IGNORE);	/* ignore keys up */

Pierre Baillet's avatar
Pierre Baillet committed
308
    /* Check buffers properties */	
Pierre Baillet's avatar
Pierre Baillet committed
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
    p_vout->p_sys->b_must_acquire = 1;		/* always acquire */
	p_vout->p_sys->p_buffer[ 0 ] =
             p_vout->p_sys->p_display->pixels;
	
	SDL_Flip(p_vout->p_sys->p_display);
	p_vout->p_sys->p_buffer[ 1 ] =
             p_vout->p_sys->p_display->pixels;
	SDL_Flip(p_vout->p_sys->p_display);

    /* Set graphic context colors */

/*
	col_fg.r = col_fg.g = col_fg.b = -1;
    col_bg.r = col_bg.g = col_bg.b = 0;
    if( ggiSetGCForeground(p_vout->p_sys->p_display,
                           ggiMapColor(p_vout->p_sys->p_display,&col_fg)) ||
        ggiSetGCBackground(p_vout->p_sys->p_display,
                           ggiMapColor(p_vout->p_sys->p_display,&col_bg)) )
    {
        intf_ErrMsg("error: can't set colors\n");
        ggiClose( p_vout->p_sys->p_display );
        ggiExit();
        return( 1 );
    }
*/
		
    /* Set clipping for text */
336
337
338
339
340
    clipping_rect.x = 0;
    clipping_rect.y = 0;
    clipping_rect.w = p_vout->p_sys->p_display->w;
    clipping_rect.h = p_vout->p_sys->p_display->h;
    SDL_SetClipRect(p_vout->p_sys->p_display, &clipping_rect);
Pierre Baillet's avatar
Pierre Baillet committed
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358


	
    /* Set thread information */
    p_vout->i_width =           p_vout->p_sys->p_display->w;
    p_vout->i_height =          p_vout->p_sys->p_display->h;

    p_vout->i_bytes_per_line = p_vout->p_sys->p_display->format->BytesPerPixel *
	    			p_vout->p_sys->p_display->w ;
		
    p_vout->i_screen_depth =    p_vout->p_sys->p_display->format->BitsPerPixel;
    p_vout->i_bytes_per_pixel = p_vout->p_sys->p_display->format->BytesPerPixel;
    p_vout->i_red_mask =        p_vout->p_sys->p_display->format->Rmask;
    p_vout->i_green_mask =      p_vout->p_sys->p_display->format->Gmask;
    p_vout->i_blue_mask =       p_vout->p_sys->p_display->format->Bmask;

    /* FIXME: palette in 8bpp ?? */
    /* Set and initialize buffers */
359
360
    vout_SetBuffers( p_vout, p_vout->p_sys->p_buffer[ 0 ],
                             p_vout->p_sys->p_buffer[ 1 ] );
Pierre Baillet's avatar
Pierre Baillet committed
361
362
363
364
365
366
367
368
369
370
371
372

    return( 0 );
}

/*****************************************************************************
 * SDLCloseDisplay: close and reset SDL device
 *****************************************************************************
 * This function returns all resources allocated by SDLOpenDisplay and restore
 * the original state of the device.
 *****************************************************************************/
static void SDLCloseDisplay( vout_thread_t *p_vout )
{
373
374
375
376
377
378
379
380
381
382
383
384
    if( p_vout->p_sys->p_display )
    {
        p_vout->p_sys->b_must_acquire = 0;
        if( p_vout->p_sys->p_overlay )
        {
            SDL_FreeYUVOverlay(p_vout->p_sys->p_overlay);
            p_vout->p_sys->p_overlay = NULL;
        }
        SDL_FreeSurface( p_vout->p_sys->p_display );
        p_vout->p_sys->p_display = NULL;
    }

Pierre Baillet's avatar
Pierre Baillet committed
385
386
387
    SDL_Quit();
}