video_output.c 84.9 KB
Newer Older
1
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
2 3 4
 * video_output.c : video output thread
 * This module describes the programming interface for video output threads.
 * It includes functions allowing to open a new thread, send pictures to a
5 6 7
 * thread, and destroy a previously oppened video output thread.
 *****************************************************************************
 * Copyright (C) 2000 VideoLAN
8
 * $Id: video_output.c,v 1.141 2001/10/01 16:18:49 massiot Exp $
9
 *
Sam Hocevar's avatar
 
Sam Hocevar committed
10
 * Authors: Vincent Seguin <seguin@via.ecp.fr>
11 12 13 14 15
 *
 * 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.
Sam Hocevar's avatar
Sam Hocevar committed
16
 *
17 18
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 20
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
21
 *
22 23 24
 * 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.
25
 *****************************************************************************/
Michel Kaempf's avatar
Michel Kaempf committed
26

27
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
28
 * Preamble
29
 *****************************************************************************/
30 31
#include "defs.h"

32 33 34 35
#include <errno.h>                                                 /* ENOMEM */
#include <stdlib.h>                                                /* free() */
#include <stdio.h>                                              /* sprintf() */
#include <string.h>                                            /* strerror() */
Vincent Seguin's avatar
Vincent Seguin committed
36

37
#include <sys/times.h>
38

Michel Kaempf's avatar
Michel Kaempf committed
39
#include "config.h"
40 41
#include "common.h"
#include "threads.h"
Michel Kaempf's avatar
Michel Kaempf committed
42
#include "mtime.h"
Sam Hocevar's avatar
 
Sam Hocevar committed
43 44
#include "modules.h"

Michel Kaempf's avatar
Michel Kaempf committed
45 46
#include "video.h"
#include "video_output.h"
Vincent Seguin's avatar
Vincent Seguin committed
47
#include "video_text.h"
Sam Hocevar's avatar
NEWS:  
Sam Hocevar committed
48
#include "video_spu.h"
49
#include "video_yuv.h"
50

Vincent Seguin's avatar
Vincent Seguin committed
51
#include "intf_msg.h"
Sam Hocevar's avatar
 
Sam Hocevar committed
52

53
#include "main.h"
Vincent Seguin's avatar
Vincent Seguin committed
54

55
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
56
 * Local prototypes
57
 *****************************************************************************/
Vincent Seguin's avatar
Vincent Seguin committed
58 59
static int      BinaryLog         ( u32 i );
static void     MaskToShift       ( int *pi_left, int *pi_right, u32 i_mask );
60 61 62 63 64
static int      InitThread        ( vout_thread_t *p_vout );
static void     RunThread         ( vout_thread_t *p_vout );
static void     ErrorThread       ( vout_thread_t *p_vout );
static void     EndThread         ( vout_thread_t *p_vout );
static void     DestroyThread     ( vout_thread_t *p_vout, int i_status );
65
static void     Print             ( vout_thread_t *p_vout, int i_x, int i_y,
66 67
                                    int i_h_align, int i_v_align,
                                    unsigned char *psz_text );
Sam Hocevar's avatar
 
Sam Hocevar committed
68
static void     SetBuffers        ( vout_thread_t *p_vout, void *, void * );
69 70 71 72 73
static void     SetBufferArea     ( vout_thread_t *p_vout, int i_x, int i_y,
                                    int i_w, int i_h );
static void     SetBufferPicture  ( vout_thread_t *p_vout, picture_t *p_pic );
static void     RenderPicture     ( vout_thread_t *p_vout, picture_t *p_pic );
static void     RenderPictureInfo ( vout_thread_t *p_vout, picture_t *p_pic );
Sam Hocevar's avatar
 
Sam Hocevar committed
74
static void     RenderSubPicture  ( vout_thread_t *p_vout, picture_t *p_pic,
75 76 77 78 79 80 81
                                    subpicture_t *p_subpic );
static int      RenderIdle        ( vout_thread_t *p_vout );
static void     RenderInfo        ( vout_thread_t *p_vout );
static int      Manage            ( vout_thread_t *p_vout );
static int      Align             ( vout_thread_t *p_vout, int *pi_x,
                                    int *pi_y, int i_width, int i_height,
                                    int i_h_align, int i_v_align );
82 83
static void     SetPalette        ( p_vout_thread_t p_vout, u16 *red,
                                    u16 *green, u16 *blue, u16 *transp );
Michel Kaempf's avatar
Michel Kaempf committed
84

Sam Hocevar's avatar
 
Sam Hocevar committed
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
/*****************************************************************************
 * vout_InitBank: initialize the video output bank.
 *****************************************************************************/
void vout_InitBank ( void )
{
    p_vout_bank->i_count = 0;

    vlc_mutex_init( &p_vout_bank->lock );
}

/*****************************************************************************
 * vout_EndBank: empty the video output bank.
 *****************************************************************************
 * This function ends all unused video outputs and empties the bank in
 * case of success.
 *****************************************************************************/
void vout_EndBank ( void )
{
    /* Ask all remaining video outputs to die */
    while( p_vout_bank->i_count )
    {
        vout_DestroyThread(
                p_vout_bank->pp_vout[ --p_vout_bank->i_count ], NULL );
Sam Hocevar's avatar
 
Sam Hocevar committed
108
    }
Sam Hocevar's avatar
 
Sam Hocevar committed
109 110 111 112

    vlc_mutex_destroy( &p_vout_bank->lock );
}

113
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
114
 * vout_CreateThread: creates a new video output thread
115
 *****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
116 117 118
 * This function creates a new video output thread, and returns a pointer
 * to its description. On error, it returns NULL.
 * If pi_status is NULL, then the function will block until the thread is ready.
119
 * If not, it will be updated using one of the THREAD_* constants.
120
 *****************************************************************************/
121
vout_thread_t * vout_CreateThread   ( int *pi_status, int i_width, int i_height )
Michel Kaempf's avatar
Michel Kaempf committed
122
{
123 124 125
    vout_thread_t * p_vout;                             /* thread descriptor */
    int             i_status;                               /* thread status */
    int             i_index;               /* index for array initialization */
Michel Kaempf's avatar
Michel Kaempf committed
126

127
    /* Allocate descriptor */
Michel Kaempf's avatar
Michel Kaempf committed
128
    p_vout = (vout_thread_t *) malloc( sizeof(vout_thread_t) );
129
    if( p_vout == NULL )
Michel Kaempf's avatar
Michel Kaempf committed
130
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
131 132
        intf_ErrMsg( "vout error: vout thread creation returned %s",
                     strerror(ENOMEM) );
Michel Kaempf's avatar
Michel Kaempf committed
133 134
        return( NULL );
    }
135

Sam Hocevar's avatar
 
Sam Hocevar committed
136
    /* Choose the best module */
Sam Hocevar's avatar
 
Sam Hocevar committed
137
    p_vout->p_module = module_Need( MODULE_CAPABILITY_VOUT, NULL );
138

Sam Hocevar's avatar
 
Sam Hocevar committed
139
    if( p_vout->p_module == NULL )
Sam Hocevar's avatar
Sam Hocevar committed
140
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
141
        intf_ErrMsg( "vout error: no suitable vout module" );
Sam Hocevar's avatar
Sam Hocevar committed
142 143 144 145
        free( p_vout );
        return( NULL );
    }

Sam Hocevar's avatar
 
Sam Hocevar committed
146 147 148 149 150 151 152 153 154 155
#define f p_vout->p_module->p_functions->vout.functions.vout
    p_vout->pf_create     = f.pf_create;
    p_vout->pf_init       = f.pf_init;
    p_vout->pf_end        = f.pf_end;
    p_vout->pf_destroy    = f.pf_destroy;
    p_vout->pf_manage     = f.pf_manage;
    p_vout->pf_display    = f.pf_display;
    p_vout->pf_setpalette = f.pf_setpalette;
#undef f

Sam Hocevar's avatar
 
Sam Hocevar committed
156 157 158
    /* Initialize callbacks */
    p_vout->pf_setbuffers       = SetBuffers;

Sam Hocevar's avatar
 
Sam Hocevar committed
159 160
    if( p_vout->pf_setpalette == NULL )
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
161
        p_vout->pf_setpalette   = SetPalette;
Sam Hocevar's avatar
 
Sam Hocevar committed
162
    }
Sam Hocevar's avatar
Sam Hocevar committed
163

164
    /* Initialize thread properties - thread id and locks will be initialized
165
     * later */
166
    p_vout->b_die               = 0;
167
    p_vout->b_error             = 0;
168 169
    p_vout->b_active            = 0;
    p_vout->pi_status           = (pi_status != NULL) ? pi_status : &i_status;
170
    *p_vout->pi_status          = THREAD_CREATE;
171

172 173 174
    /* Initialize some fields used by the system-dependant method - these
     * fields will probably be modified by the method, and are only
     * preferences */
175 176 177 178 179 180 181 182 183 184 185 186 187
    p_vout->i_changes           = 0;
    p_vout->i_width             = main_GetIntVariable( VOUT_WIDTH_VAR, 0 );
    if( !p_vout->i_width )
    {
        p_vout->i_width         = i_width ? i_width : VOUT_WIDTH_DEFAULT;
    }
    p_vout->i_height            = main_GetIntVariable( VOUT_HEIGHT_VAR, 0 );
    if( !p_vout->i_height )
    {
        p_vout->i_height        = i_height ? i_height : VOUT_HEIGHT_DEFAULT;
    }
    p_vout->i_bytes_per_line    = p_vout->i_width * 2;
    p_vout->i_screen_depth      = main_GetIntVariable( VOUT_DEPTH_VAR,
188
                                                         VOUT_DEPTH_DEFAULT );
189 190 191 192 193 194 195 196 197 198 199 200
    p_vout->i_bytes_per_pixel   = 2;
    p_vout->f_gamma             = VOUT_GAMMA_DEFAULT; // FIXME: replace with
                                                      // variable
    p_vout->b_need_render       = 1;
    p_vout->b_YCbr              = 0;

    p_vout->b_grayscale         = main_GetIntVariable( VOUT_GRAYSCALE_VAR,
                                                       VOUT_GRAYSCALE_DEFAULT );
    p_vout->b_info              = 0;
    p_vout->b_interface         = 0;
    p_vout->b_scale             = 1;
    p_vout->b_fullscreen        = main_GetIntVariable( VOUT_FULLSCREEN_VAR,
201
                                                     VOUT_FULLSCREEN_DEFAULT );
202

Sam Hocevar's avatar
 
Sam Hocevar committed
203
    intf_WarnMsg( 3, "vout info: asking for %dx%d, %d/%d bpp (%d Bpl)",
Sam Hocevar's avatar
 
Sam Hocevar committed
204 205
                  p_vout->i_width, p_vout->i_height, p_vout->i_screen_depth,
                  p_vout->i_bytes_per_pixel * 8, p_vout->i_bytes_per_line );
206

207
    /* Initialize idle screen */
208
    p_vout->last_display_date   = 0;
209
    p_vout->last_idle_date      = 0;
210
    p_vout->init_display_date   = mdate();
211
    p_vout->render_time         = 10000;
212

213
    /* Initialize statistics fields */
214
    p_vout->c_fps_samples       = 0;
215 216 217 218 219
    p_vout->c_pictures          = 0;
    p_vout->c_late_pictures     = 0;
    p_vout->c_jitter_samples    = 0;
    p_vout->display_jitter      = 0;
    p_vout->c_loops             = 0;
220 221 222 223

    /* Initialize buffer index */
    p_vout->i_buffer_index      = 0;

Gildas Bazin's avatar
 
Gildas Bazin committed
224
    /* Initialize fonts */
225 226
    p_vout->p_default_font      = NULL;
    p_vout->p_large_font        = NULL;
Gildas Bazin's avatar
 
Gildas Bazin committed
227

228
    /* Initialize pictures and subpictures - translation tables and functions
229
     * will be initialized later in InitThread */
230 231
    for( i_index = 0; i_index < VOUT_MAX_PICTURES; i_index++)
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
232 233
        p_vout->p_picture[i_index].i_type   = EMPTY_PICTURE;
        p_vout->p_picture[i_index].i_status = FREE_PICTURE;
234
    }
Sam Hocevar's avatar
 
Sam Hocevar committed
235

236 237
    for( i_index = 0; i_index < VOUT_MAX_SUBPICTURES; i_index++)
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
238 239
        p_vout->p_subpicture[i_index].i_type   = EMPTY_SUBPICTURE;
        p_vout->p_subpicture[i_index].i_status = FREE_SUBPICTURE;
240
    }
Sam Hocevar's avatar
 
Sam Hocevar committed
241

242
    p_vout->i_pictures = 0;
243

Michel Kaempf's avatar
Michel Kaempf committed
244
    /* Create thread and set locks */
Vincent Seguin's avatar
Vincent Seguin committed
245
    vlc_mutex_init( &p_vout->picture_lock );
246 247
    vlc_mutex_init( &p_vout->subpicture_lock );
    vlc_mutex_init( &p_vout->change_lock );
248

249 250
    if( vlc_thread_create( &p_vout->thread_id, "video output",
                           (void *) RunThread, (void *) p_vout) )
Michel Kaempf's avatar
Michel Kaempf committed
251
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
252
        intf_ErrMsg("vout error: %s", strerror(ENOMEM));
Gildas Bazin's avatar
 
Gildas Bazin committed
253
        module_Unneed( p_vout->p_module );
Michel Kaempf's avatar
Michel Kaempf committed
254 255
        free( p_vout );
        return( NULL );
256
    }
Michel Kaempf's avatar
Michel Kaempf committed
257 258 259 260 261

    /* If status is NULL, wait until the thread is created */
    if( pi_status == NULL )
    {
        do
262
        {
Michel Kaempf's avatar
Michel Kaempf committed
263
            msleep( THREAD_SLEEP );
264
        }while( (i_status != THREAD_READY) && (i_status != THREAD_ERROR)
Michel Kaempf's avatar
Michel Kaempf committed
265 266 267
                && (i_status != THREAD_FATAL) );
        if( i_status != THREAD_READY )
        {
268 269
            return( NULL );
        }
Michel Kaempf's avatar
Michel Kaempf committed
270 271 272 273
    }
    return( p_vout );
}

274
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
275
 * vout_DestroyThread: destroys a previously created thread
276 277
 *****************************************************************************
 * Destroy a terminated thread.
Michel Kaempf's avatar
Michel Kaempf committed
278
 * The function will request a destruction of the specified thread. If pi_error
279
 * is NULL, it will return once the thread is destroyed. Else, it will be
Michel Kaempf's avatar
Michel Kaempf committed
280
 * update using one of the THREAD_* constants.
281
 *****************************************************************************/
Michel Kaempf's avatar
Michel Kaempf committed
282
void vout_DestroyThread( vout_thread_t *p_vout, int *pi_status )
283 284
{
    int     i_status;                                       /* thread status */
Michel Kaempf's avatar
Michel Kaempf committed
285 286

    /* Set status */
Sam Hocevar's avatar
 
Sam Hocevar committed
287
    intf_DbgMsg("");
Michel Kaempf's avatar
Michel Kaempf committed
288
    p_vout->pi_status = (pi_status != NULL) ? pi_status : &i_status;
289 290
    *p_vout->pi_status = THREAD_DESTROY;

Michel Kaempf's avatar
Michel Kaempf committed
291 292 293 294
    /* Request thread destruction */
    p_vout->b_die = 1;

    /* If status is NULL, wait until thread has been destroyed */
295
    if( pi_status == NULL )
Michel Kaempf's avatar
Michel Kaempf committed
296 297 298 299
    {
        do
        {
            msleep( THREAD_SLEEP );
300 301
        } while( (i_status != THREAD_OVER) && (i_status != THREAD_ERROR)
                 && (i_status != THREAD_FATAL) );
Michel Kaempf's avatar
Michel Kaempf committed
302 303 304
    }
}

305
/*****************************************************************************
306
 * vout_DisplaySubPicture: display a subpicture unit
307
 *****************************************************************************
Sam Hocevar's avatar
 
Sam Hocevar committed
308
 * Remove the reservation flag of a subpicture, which will cause it to be ready
309
 * for display. The picture does not need to be locked, since it is ignored by
Vincent Seguin's avatar
Vincent Seguin committed
310
 * the output thread if is reserved.
311
 *****************************************************************************/
312
void  vout_DisplaySubPicture( vout_thread_t *p_vout, subpicture_t *p_subpic )
Vincent Seguin's avatar
Vincent Seguin committed
313
{
314
#ifdef TRACE_VOUT
Sam Hocevar's avatar
 
Sam Hocevar committed
315 316
    char        psz_start[ MSTRTIME_MAX_SIZE ];    /* buffer for date string */
    char        psz_stop[ MSTRTIME_MAX_SIZE ];     /* buffer for date string */
Vincent Seguin's avatar
Vincent Seguin committed
317 318 319 320
#endif

#ifdef DEBUG
    /* Check if status is valid */
321
    if( p_subpic->i_status != RESERVED_SUBPICTURE )
Vincent Seguin's avatar
Vincent Seguin committed
322
    {
323
        intf_ErrMsg("error: subpicture %p has invalid status %d", p_subpic,
324 325
                    p_subpic->i_status );
    }
Vincent Seguin's avatar
Vincent Seguin committed
326 327 328
#endif

    /* Remove reservation flag */
329
    p_subpic->i_status = READY_SUBPICTURE;
Vincent Seguin's avatar
Vincent Seguin committed
330

331
#ifdef TRACE_VOUT
Sam Hocevar's avatar
Sam Hocevar committed
332
    /* Send subpicture information */
Sam Hocevar's avatar
 
Sam Hocevar committed
333
    intf_DbgMsg("subpicture %p: type=%d, begin date=%s, end date=%s",
334
                p_subpic, p_subpic->i_type,
Sam Hocevar's avatar
 
Sam Hocevar committed
335 336
                mstrtime( psz_start, p_subpic->i_start ),
                mstrtime( psz_stop, p_subpic->i_stop ) );
Vincent Seguin's avatar
Vincent Seguin committed
337 338 339
#endif
}

340
/*****************************************************************************
Sam Hocevar's avatar
Sam Hocevar committed
341
 * vout_CreateSubPicture: allocate a subpicture in the video output heap.
342 343
 *****************************************************************************
 * This function create a reserved subpicture in the video output heap.
Vincent Seguin's avatar
Vincent Seguin committed
344
 * A null pointer is returned if the function fails. This method provides an
345
 * already allocated zone of memory in the spu data fields. It needs locking
346 347 348
 * since several pictures can be created by several producers threads.
 *****************************************************************************/
subpicture_t *vout_CreateSubPicture( vout_thread_t *p_vout, int i_type,
349
                                     int i_size )
Vincent Seguin's avatar
Vincent Seguin committed
350
{
351 352 353
    int                 i_subpic;                        /* subpicture index */
    subpicture_t *      p_free_subpic = NULL;       /* first free subpicture */
    subpicture_t *      p_destroyed_subpic = NULL; /* first destroyed subpic */
354 355 356 357

    /* Get lock */
    vlc_mutex_lock( &p_vout->subpicture_lock );

358 359
    /*
     * Look for an empty place
360
     */
361
    for( i_subpic = 0; i_subpic < VOUT_MAX_SUBPICTURES; i_subpic++ )
362
    {
363 364 365 366 367 368
        if( p_vout->p_subpicture[i_subpic].i_status == DESTROYED_SUBPICTURE )
        {
            /* Subpicture is marked for destruction, but is still allocated */
            if( (p_vout->p_subpicture[i_subpic].i_type  == i_type)   &&
                (p_vout->p_subpicture[i_subpic].i_size  >= i_size) )
            {
Sam Hocevar's avatar
NEWS:  
Sam Hocevar committed
369 370 371 372
                /* Memory size do match or is smaller : memory will not be
                 * reallocated, and function can end immediately - this is
                 * the best possible case, since no memory allocation needs
                 * to be done */
373
                p_vout->p_subpicture[i_subpic].i_status = RESERVED_SUBPICTURE;
374
#ifdef TRACE_VOUT
Sam Hocevar's avatar
 
Sam Hocevar committed
375
                intf_DbgMsg("subpicture %p (in destroyed subpicture slot)",
376
                            &p_vout->p_subpicture[i_subpic] );
377
#endif
378 379 380 381 382
                vlc_mutex_unlock( &p_vout->subpicture_lock );
                return( &p_vout->p_subpicture[i_subpic] );
            }
            else if( p_destroyed_subpic == NULL )
            {
Sam Hocevar's avatar
 
Sam Hocevar committed
383 384
                /* Memory size do not match, but subpicture index will be kept
                 * in case we find no other place */
385 386 387
                p_destroyed_subpic = &p_vout->p_subpicture[i_subpic];
            }
        }
388
        else if( (p_free_subpic == NULL) &&
389 390
                 (p_vout->p_subpicture[i_subpic].i_status == FREE_SUBPICTURE ))
        {
391
            /* Subpicture is empty and ready for allocation */
392 393 394 395
            p_free_subpic = &p_vout->p_subpicture[i_subpic];
        }
    }

Sam Hocevar's avatar
Sam Hocevar committed
396
    /* If no free subpictures are available, use a destroyed subpicture */
397
    if( (p_free_subpic == NULL) && (p_destroyed_subpic != NULL ) )
398
    {
Sam Hocevar's avatar
Sam Hocevar committed
399
        /* No free subpicture or matching destroyed subpictures have been
Sam Hocevar's avatar
NEWS:  
Sam Hocevar committed
400
         * found, but a destroyed subpicture is still avalaible */
401
        free( p_destroyed_subpic->p_data );
402 403 404 405 406 407 408 409 410 411 412
        p_free_subpic = p_destroyed_subpic;
    }

    /*
     * Prepare subpicture
     */
    if( p_free_subpic != NULL )
    {
        /* Allocate memory */
        switch( i_type )
        {
413
        case TEXT_SUBPICTURE:                             /* text subpicture */
414
            p_free_subpic->p_data = memalign( 16, i_size + 1 );
415
            break;
416
        case DVD_SUBPICTURE:                          /* DVD subpicture unit */
417
            p_free_subpic->p_data = memalign( 16, i_size );
418
            break;
419 420
#ifdef DEBUG
        default:
421
            intf_ErrMsg("error: unknown subpicture type %d", i_type );
422 423 424
            p_free_subpic->p_data   =  NULL;
            break;
#endif
425 426 427
        }

        if( p_free_subpic->p_data != NULL )
Sam Hocevar's avatar
Sam Hocevar committed
428 429
        {
            /* Copy subpicture information, set some default values */
430 431
            p_free_subpic->i_type                      = i_type;
            p_free_subpic->i_status                    = RESERVED_SUBPICTURE;
432
            p_free_subpic->i_size                      = i_size;
433
            p_free_subpic->i_x                         = 0;
434
            p_free_subpic->i_y                         = 0;
435 436
            p_free_subpic->i_width                     = 0;
            p_free_subpic->i_height                    = 0;
437 438
            p_free_subpic->i_horizontal_align          = CENTER_RALIGN;
            p_free_subpic->i_vertical_align            = CENTER_RALIGN;
439 440 441 442
        }
        else
        {
            /* Memory allocation failed : set subpicture as empty */
443 444 445
            p_free_subpic->i_type   =  EMPTY_SUBPICTURE;
            p_free_subpic->i_status =  FREE_SUBPICTURE;
            p_free_subpic =            NULL;
Sam Hocevar's avatar
 
Sam Hocevar committed
446 447
            intf_ErrMsg( "vout error: spu allocation returned %s",
                         strerror( ENOMEM ) );
448
        }
449

450
#ifdef TRACE_VOUT
Sam Hocevar's avatar
 
Sam Hocevar committed
451
        intf_DbgMsg("subpicture %p (in free subpicture slot)", p_free_subpic );
452 453 454 455
#endif
        vlc_mutex_unlock( &p_vout->subpicture_lock );
        return( p_free_subpic );
    }
456

457
    /* No free or destroyed subpicture could be found */
Sam Hocevar's avatar
 
Sam Hocevar committed
458
    intf_DbgMsg( "warning: subpicture heap is full" );
459 460
    vlc_mutex_unlock( &p_vout->subpicture_lock );
    return( NULL );
Vincent Seguin's avatar
Vincent Seguin committed
461 462
}

463
/*****************************************************************************
464
 * vout_DestroySubPicture: remove a subpicture from the heap
465
 *****************************************************************************
466
 * This function frees a previously reserved subpicture.
Vincent Seguin's avatar
Vincent Seguin committed
467
 * It is meant to be used when the construction of a picture aborted.
468
 * This function does not need locking since reserved subpictures are ignored
469
 * by the output thread.
470
 *****************************************************************************/
471
void vout_DestroySubPicture( vout_thread_t *p_vout, subpicture_t *p_subpic )
Vincent Seguin's avatar
Vincent Seguin committed
472 473
{
#ifdef DEBUG
474 475
   /* Check if status is valid */
   if( p_subpic->i_status != RESERVED_SUBPICTURE )
Vincent Seguin's avatar
Vincent Seguin committed
476
   {
477
       intf_ErrMsg("error: subpicture %p has invalid status %d",
478 479
                   p_subpic, p_subpic->i_status );
   }
Vincent Seguin's avatar
Vincent Seguin committed
480 481
#endif

482
    p_subpic->i_status = DESTROYED_SUBPICTURE;
Vincent Seguin's avatar
Vincent Seguin committed
483

484
#ifdef TRACE_VOUT
Sam Hocevar's avatar
 
Sam Hocevar committed
485
    intf_DbgMsg("subpicture %p", p_subpic);
Vincent Seguin's avatar
Vincent Seguin committed
486 487 488
#endif
}

489
/*****************************************************************************
Vincent Seguin's avatar
Vincent Seguin committed
490
 * vout_DisplayPicture: display a picture
491
 *****************************************************************************
Vincent Seguin's avatar
Vincent Seguin committed
492
 * Remove the reservation flag of a picture, which will cause it to be ready for
493
 * display. The picture won't be displayed until vout_DatePicture has been
494
 * called.
495
 *****************************************************************************/
Vincent Seguin's avatar
Vincent Seguin committed
496
void  vout_DisplayPicture( vout_thread_t *p_vout, picture_t *p_pic )
Michel Kaempf's avatar
Michel Kaempf committed
497
{
498 499
    vlc_mutex_lock( &p_vout->picture_lock );
    switch( p_pic->i_status )
500
    {
501
    case RESERVED_PICTURE:
502
        p_pic->i_status = RESERVED_DISP_PICTURE;
503
        break;
504 505
    case RESERVED_DATED_PICTURE:
        p_pic->i_status = READY_PICTURE;
506
        break;
507
#ifdef DEBUG
508
    default:
509
        intf_ErrMsg("error: picture %p has invalid status %d", p_pic, p_pic->i_status );
510
        break;
511
#endif
512
    }
Michel Kaempf's avatar
Michel Kaempf committed
513

514
#ifdef TRACE_VOUT
Sam Hocevar's avatar
 
Sam Hocevar committed
515
    intf_DbgMsg("picture %p", p_pic);
516
#endif
517
    vlc_mutex_unlock( &p_vout->picture_lock );
Michel Kaempf's avatar
Michel Kaempf committed
518 519
}

520
/*****************************************************************************
521
 * vout_DatePicture: date a picture
522
 *****************************************************************************
523
 * Remove the reservation flag of a picture, which will cause it to be ready for
524
 * display. The picture won't be displayed until vout_DisplayPicture has been
525
 * called.
526
 *****************************************************************************/
527 528
void  vout_DatePicture( vout_thread_t *p_vout, picture_t *p_pic, mtime_t date )
{
529
#ifdef TRACE_VOUT
530
    char        psz_date[MSTRTIME_MAX_SIZE];                         /* date */
Vincent Seguin's avatar
Vincent Seguin committed
531 532
#endif

533
    vlc_mutex_lock( &p_vout->picture_lock );
534
    p_pic->date = date;
535 536
    switch( p_pic->i_status )
    {
537
    case RESERVED_PICTURE:
538
        p_pic->i_status = RESERVED_DATED_PICTURE;
539
        break;
540 541
    case RESERVED_DISP_PICTURE:
        p_pic->i_status = READY_PICTURE;
542
        break;
543
#ifdef DEBUG
544
    default:
545
        intf_ErrMsg("error: picture %p has invalid status %d", p_pic, p_pic->i_status );
546
        break;
547 548 549
#endif
    }

550
#ifdef TRACE_VOUT
Sam Hocevar's avatar
 
Sam Hocevar committed
551
    intf_DbgMsg("picture %p, display date: %s", p_pic, mstrtime( psz_date, p_pic->date) );
552
#endif
553
    vlc_mutex_unlock( &p_vout->picture_lock );
554 555
}

556
/*****************************************************************************
Vincent Seguin's avatar
Vincent Seguin committed
557
 * vout_CreatePicture: allocate a picture in the video output heap.
558 559
 *****************************************************************************
 * This function create a reserved image in the video output heap.
Vincent Seguin's avatar
Vincent Seguin committed
560
 * A null pointer is returned if the function fails. This method provides an
561
 * already allocated zone of memory in the picture data fields. It needs locking
562 563 564
 * since several pictures can be created by several producers threads.
 *****************************************************************************/
picture_t *vout_CreatePicture( vout_thread_t *p_vout, int i_type,
565
                               int i_width, int i_height )
Michel Kaempf's avatar
Michel Kaempf committed
566
{
567 568 569 570
    int         i_picture;                                  /* picture index */
    int         i_chroma_width = 0;                          /* chroma width */
    picture_t * p_free_picture = NULL;                 /* first free picture */
    picture_t * p_destroyed_picture = NULL;       /* first destroyed picture */
Michel Kaempf's avatar
Michel Kaempf committed
571

Vincent Seguin's avatar
Vincent Seguin committed
572
    /* Get lock */
Vincent Seguin's avatar
Vincent Seguin committed
573
    vlc_mutex_lock( &p_vout->picture_lock );
Michel Kaempf's avatar
Michel Kaempf committed
574

575 576
    /*
     * Look for an empty place
Vincent Seguin's avatar
Vincent Seguin committed
577
     */
578
    for( i_picture = 0; i_picture < VOUT_MAX_PICTURES; i_picture++ )
Vincent Seguin's avatar
Vincent Seguin committed
579
    {
580 581 582
        if( p_vout->p_picture[i_picture].i_status == DESTROYED_PICTURE )
        {
            /* Picture is marked for destruction, but is still allocated - note
583
             * that if width and type are the same for two pictures, chroma_width
584
             * should also be the same */
585 586 587 588 589
            if( (p_vout->p_picture[i_picture].i_type           == i_type)   &&
                (p_vout->p_picture[i_picture].i_height         == i_height) &&
                (p_vout->p_picture[i_picture].i_width          == i_width) )
            {
                /* Memory size do match : memory will not be reallocated, and function
Vincent Seguin's avatar
Vincent Seguin committed
590 591
                 * can end immediately - this is the best possible case, since no
                 * memory allocation needs to be done */
592
                p_vout->p_picture[i_picture].i_status = RESERVED_PICTURE;
593
                p_vout->i_pictures++;
594
#ifdef TRACE_VOUT
Sam Hocevar's avatar
 
Sam Hocevar committed
595
                intf_DbgMsg("picture %p (in destroyed picture slot)",
596
                            &p_vout->p_picture[i_picture] );
597
#endif
598 599 600 601 602 603 604 605 606 607
                vlc_mutex_unlock( &p_vout->picture_lock );
                return( &p_vout->p_picture[i_picture] );
            }
            else if( p_destroyed_picture == NULL )
            {
                /* Memory size do not match, but picture index will be kept in
                 * case no other place are left */
                p_destroyed_picture = &p_vout->p_picture[i_picture];
            }
        }
608
        else if( (p_free_picture == NULL) &&
Vincent Seguin's avatar
Vincent Seguin committed
609 610
                 (p_vout->p_picture[i_picture].i_status == FREE_PICTURE ))
        {
611
            /* Picture is empty and ready for allocation */
612
            p_free_picture = &p_vout->p_picture[i_picture];
Vincent Seguin's avatar
Vincent Seguin committed
613
        }
Michel Kaempf's avatar
Michel Kaempf committed
614 615
    }

Vincent Seguin's avatar
Vincent Seguin committed
616 617
    /* If no free picture is available, use a destroyed picture */
    if( (p_free_picture == NULL) && (p_destroyed_picture != NULL ) )
618
    {
619 620
        /* No free picture or matching destroyed picture has been found, but
         * a destroyed picture is still avalaible */
621 622
        free( p_destroyed_picture->p_data );
        p_free_picture = p_destroyed_picture;
Michel Kaempf's avatar
Michel Kaempf committed
623 624
    }

Vincent Seguin's avatar
Vincent Seguin committed
625 626 627 628 629 630 631
    /*
     * Prepare picture
     */
    if( p_free_picture != NULL )
    {
        /* Allocate memory */
        switch( i_type )
Michel Kaempf's avatar
Michel Kaempf committed
632
        {
633 634
        case YUV_420_PICTURE:        /* YUV 420: 1,1/4,1/4 samples per pixel */
            i_chroma_width = i_width / 2;
635 636
            p_free_picture->p_data = memalign( 16, i_height * i_chroma_width
                                                 * 3 * sizeof( yuv_data_t ) );
637
            p_free_picture->p_y = (yuv_data_t *)p_free_picture->p_data;
Vincent Seguin's avatar
Vincent Seguin committed
638 639
            p_free_picture->p_u = (yuv_data_t *)p_free_picture->p_data +i_height*i_chroma_width*4/2;
            p_free_picture->p_v = (yuv_data_t *)p_free_picture->p_data +i_height*i_chroma_width*5/2;
640
            break;
641 642
        case YUV_422_PICTURE:        /* YUV 422: 1,1/2,1/2 samples per pixel */
            i_chroma_width = i_width / 2;
643 644
            p_free_picture->p_data = memalign( 16, i_height * i_chroma_width
                                                 * 4 * sizeof( yuv_data_t ) );
645
            p_free_picture->p_y = (yuv_data_t *)p_free_picture->p_data;
Vincent Seguin's avatar
Vincent Seguin committed
646 647
            p_free_picture->p_u = (yuv_data_t *)p_free_picture->p_data +i_height*i_chroma_width*2;
            p_free_picture->p_v = (yuv_data_t *)p_free_picture->p_data +i_height*i_chroma_width*3;
648
            break;
649 650
        case YUV_444_PICTURE:            /* YUV 444: 1,1,1 samples per pixel */
            i_chroma_width = i_width;
651 652
            p_free_picture->p_data = memalign( 16, i_height * i_chroma_width
                                                 * 3 * sizeof( yuv_data_t ) );
653
            p_free_picture->p_y = (yuv_data_t *)p_free_picture->p_data;
Vincent Seguin's avatar
Vincent Seguin committed
654 655
            p_free_picture->p_u = (yuv_data_t *)p_free_picture->p_data +i_height*i_chroma_width;
            p_free_picture->p_v = (yuv_data_t *)p_free_picture->p_data +i_height*i_chroma_width*2;
656
            break;
Vincent Seguin's avatar
Vincent Seguin committed
657 658
#ifdef DEBUG
        default:
659
            intf_ErrMsg("error: unknown picture type %d", i_type );
660 661 662
            p_free_picture->p_data   =  NULL;
            break;
#endif
Michel Kaempf's avatar
Michel Kaempf committed
663 664
        }

Vincent Seguin's avatar
Vincent Seguin committed
665
        if( p_free_picture->p_data != NULL )
666
        {
Sam Hocevar's avatar
Sam Hocevar committed
667
            /* Copy picture information, set some default values */
668 669
            p_free_picture->i_type                      = i_type;
            p_free_picture->i_status                    = RESERVED_PICTURE;
670
            p_free_picture->i_matrix_coefficients       = 1;
671 672
            p_free_picture->i_width                     = i_width;
            p_free_picture->i_height                    = i_height;
673
            p_free_picture->i_chroma_width              = i_chroma_width;
674 675 676
            p_free_picture->i_size                      = i_width * i_height;
            p_free_picture->i_chroma_size               = i_chroma_width
                                                            * i_height;
677
            p_free_picture->i_display_horizontal_offset = 0;
678
            p_free_picture->i_display_vertical_offset   = 0;
679 680
            p_free_picture->i_display_width             = i_width;
            p_free_picture->i_display_height            = i_height;
681 682
            p_free_picture->i_aspect_ratio              = AR_SQUARE_PICTURE;
            p_free_picture->i_refcount                  = 0;
683
            p_vout->i_pictures++;
Vincent Seguin's avatar
Vincent Seguin committed
684 685 686 687
        }
        else
        {
            /* Memory allocation failed : set picture as empty */
688 689 690
            p_free_picture->i_type   =  EMPTY_PICTURE;
            p_free_picture->i_status =  FREE_PICTURE;
            p_free_picture =            NULL;
Sam Hocevar's avatar
 
Sam Hocevar committed
691 692
            intf_ErrMsg( "vout error: picture allocation returned %s",
                         strerror( ENOMEM ) );
Vincent Seguin's avatar
Vincent Seguin committed
693
        }
694

695
#ifdef TRACE_VOUT
Sam Hocevar's avatar
 
Sam Hocevar committed
696
        intf_DbgMsg("picture %p (in free picture slot)", p_free_picture );
697
#endif
Vincent Seguin's avatar
Vincent Seguin committed
698
        vlc_mutex_unlock( &p_vout->picture_lock );
Henri Fallon's avatar
 
Henri Fallon committed
699

Vincent Seguin's avatar
Vincent Seguin committed
700
        return( p_free_picture );
Michel Kaempf's avatar
Michel Kaempf committed
701
    }
702

703
    /* No free or destroyed picture could be found */
Sam Hocevar's avatar
 
Sam Hocevar committed
704
    intf_DbgMsg( "warning: picture heap is full" );
Vincent Seguin's avatar
Vincent Seguin committed
705
    vlc_mutex_unlock( &p_vout->picture_lock );
Vincent Seguin's avatar
Vincent Seguin committed
706
    return( NULL );
Michel Kaempf's avatar
Michel Kaempf committed
707 708
}

709
/*****************************************************************************
710
 * vout_DestroyPicture: remove a permanent or reserved picture from the heap
711
 *****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
712
 * This function frees a previously reserved picture or a permanent
Vincent Seguin's avatar
Vincent Seguin committed
713 714
 * picture. It is meant to be used when the construction of a picture aborted.
 * Note that the picture will be destroyed even if it is linked !
715
 *****************************************************************************/
Vincent Seguin's avatar
Vincent Seguin committed
716
void vout_DestroyPicture( vout_thread_t *p_vout, picture_t *p_pic )
Michel Kaempf's avatar
Michel Kaempf committed
717
{
Henri Fallon's avatar
 
Henri Fallon committed
718
    vlc_mutex_lock( &p_vout->picture_lock );
719

720
#ifdef DEBUG
Henri Fallon's avatar
 
Henri Fallon committed
721 722 723 724 725
    /* Check if picture status is valid */
    if( (p_pic->i_status != RESERVED_PICTURE) &&
        (p_pic->i_status != RESERVED_DATED_PICTURE) &&
        (p_pic->i_status != RESERVED_DISP_PICTURE) )
    {
726
        intf_ErrMsg("error: picture %p has invalid status %d", p_pic, p_pic->i_status );
Henri Fallon's avatar
 
Henri Fallon committed
727
    }
728 729
#endif

Henri Fallon's avatar
 
Henri Fallon committed
730 731
    p_pic->i_status = DESTROYED_PICTURE;
    p_vout->i_pictures--;
732

733
#ifdef TRACE_VOUT
Henri Fallon's avatar
 
Henri Fallon committed
734
    intf_DbgMsg("picture %p", p_pic);
735
#endif
Henri Fallon's avatar
 
Henri Fallon committed
736

Henri Fallon's avatar
 
Henri Fallon committed
737
    vlc_mutex_unlock( &p_vout->picture_lock );
Michel Kaempf's avatar
Michel Kaempf committed
738 739
}

740
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
741
 * vout_LinkPicture: increment reference counter of a picture
742
 *****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
743
 * This function increment the reference counter of a picture in the video
744
 * heap. It needs a lock since several producer threads can access the picture.
745
 *****************************************************************************/
Michel Kaempf's avatar
Michel Kaempf committed
746 747
void vout_LinkPicture( vout_thread_t *p_vout, picture_t *p_pic )
{
Vincent Seguin's avatar
Vincent Seguin committed
748
    vlc_mutex_lock( &p_vout->picture_lock );
Michel Kaempf's avatar
Michel Kaempf committed
749
    p_pic->i_refcount++;
750

751
#ifdef TRACE_VOUT
Sam Hocevar's avatar
 
Sam Hocevar committed
752
    intf_DbgMsg("picture %p refcount=%d", p_pic, p_pic->i_refcount );
753
#endif
754 755

    vlc_mutex_unlock( &p_vout->picture_lock );
Michel Kaempf's avatar
Michel Kaempf committed
756 757
}

758
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
759
 * vout_UnlinkPicture: decrement reference counter of a picture
760
 *****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
761
 * This function decrement the reference counter of a picture in the video heap.
762
 *****************************************************************************/
Michel Kaempf's avatar
Michel Kaempf committed
763 764
void vout_UnlinkPicture( vout_thread_t *p_vout, picture_t *p_pic )
{
Vincent Seguin's avatar
Vincent Seguin committed
765
    vlc_mutex_lock( &p_vout->picture_lock );
Michel Kaempf's avatar
Michel Kaempf committed
766
    p_pic->i_refcount--;
767

768
#ifdef TRACE_VOUT
769 770
    if( p_pic->i_refcount < 0 )
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
771
        intf_DbgMsg("error: refcount < 0");
772 773
        p_pic->i_refcount = 0;
    }
774 775
#endif

Vincent Seguin's avatar
Vincent Seguin committed
776
    if( (p_pic->i_refcount == 0) && (p_pic->i_status == DISPLAYED_PICTURE) )
Michel Kaempf's avatar
Michel Kaempf committed
777
    {
778
        p_pic->i_status = DESTROYED_PICTURE;
779
        p_vout->i_pictures--;
Michel Kaempf's avatar
Michel Kaempf committed
780
    }
781

782
#ifdef TRACE_VOUT
Sam Hocevar's avatar
 
Sam Hocevar committed
783
    intf_DbgMsg("picture %p refcount=%d", p_pic, p_pic->i_refcount );
784
#endif
785 786

    vlc_mutex_unlock( &p_vout->picture_lock );
Michel Kaempf's avatar
Michel Kaempf committed
787 788
}

Vincent Seguin's avatar
Vincent Seguin committed
789 790 791 792 793 794 795 796 797 798 799 800 801
/*****************************************************************************
 * vout_Pixel2RGB: return red, green and blue from pixel value
 *****************************************************************************
 * Return color values, in 0-255 range, of the decomposition of a pixel. This
 * is a slow routine and should only be used for initialization phase.
 *****************************************************************************/
void vout_Pixel2RGB( vout_thread_t *p_vout, u32 i_pixel, int *pi_red, int *pi_green, int *pi_blue )
{
    *pi_red =   i_pixel & p_vout->i_red_mask;
    *pi_green = i_pixel & p_vout->i_green_mask;
    *pi_blue =  i_pixel & p_vout->i_blue_mask;
}

Michel Kaempf's avatar
Michel Kaempf committed
802 803
/* following functions are local */

Vincent Seguin's avatar
Vincent Seguin committed
804 805 806
/*****************************************************************************
 * BinaryLog: computes the base 2 log of a binary value
 *****************************************************************************
807
 * This functions is used by MaskToShift, to get a bit index from a binary
Vincent Seguin's avatar
Vincent Seguin committed
808 809 810 811
 * value.
 *****************************************************************************/
static int BinaryLog(u32 i)
{
812
    int i_log = 0;
Vincent Seguin's avatar
Vincent Seguin committed
813

814 815
    if(i & 0xffff0000)
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
816
        i_log += 16;
817 818 819
    }
    if(i & 0xff00ff00)
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
820
        i_log += 8;
821 822 823
    }
    if(i & 0xf0f0f0f0)
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
824
        i_log += 4;
825 826 827
    }
    if(i & 0xcccccccc)
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
828
        i_log += 2;
829 830 831
    }
    if(i & 0xaaaaaaaa)
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
832
        i_log += 1;
833
    }
Benoit Steiner's avatar
Benoit Steiner committed
834

Vincent Seguin's avatar
Vincent Seguin committed
835
    if (i != ((u32)1 << i_log))
836
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
837
        intf_DbgMsg("internal error: binary log overflow");
838
    }
Vincent Seguin's avatar
Vincent Seguin committed
839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864

    return( i_log );
}

/*****************************************************************************
 * MaskToShift: transform a color mask into right and left shifts
 *****************************************************************************
 * This function is used for obtaining color shifts from masks.
 *****************************************************************************/
static void MaskToShift( int *pi_left, int *pi_right, u32 i_mask )
{
    u32 i_low, i_high;                 /* lower hand higher bits of the mask */

    /* Get bits */
    i_low =  i_mask & (- i_mask);                   /* lower bit of the mask */
    i_high = i_mask + i_low;                       /* higher bit of the mask */

    /* Transform bits into an index */
    i_low =  BinaryLog (i_low);
    i_high = BinaryLog (i_high);

    /* Update pointers and return */
    *pi_left =   i_low;
    *pi_right = (8 - i_high + i_low);
}

865
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
866
 * InitThread: initialize video output thread
867
 *****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
868 869 870
 * This function is called from RunThread and performs the second step of the
 * initialization. It returns 0 on success. Note that the thread's flag are not
 * modified inside this function.
871
 *****************************************************************************/
Michel Kaempf's avatar
Michel Kaempf committed
872 873 874
static int InitThread( vout_thread_t *p_vout )
{
    /* Update status */
875
    *p_vout->pi_status = THREAD_START;
Michel Kaempf's avatar
Michel Kaempf committed
876

877 878
    vlc_mutex_lock( &p_vout->change_lock );

Sam Hocevar's avatar
 
Sam Hocevar committed
879 880 881 882
    /* Create and initialize system-dependant method - this function issues its
     * own error messages */
    if( p_vout->pf_create( p_vout ) )
    {
Gildas Bazin's avatar
 
Gildas Bazin committed
883
        /* If pf_create has failed then we have to make sure
Sam Hocevar's avatar
 
Sam Hocevar committed
884 885
         * pf_destroy won't be called, because the plugin should have
         * cleaned up all its mess */
Gildas Bazin's avatar
 
Gildas Bazin committed
886
        p_vout->pf_destroy = NULL;
Sam Hocevar's avatar
 
Sam Hocevar committed
887
        return( 1 );
Sam Hocevar's avatar
 
Sam Hocevar committed
888 889
    }

Gildas Bazin's avatar
 
Gildas Bazin committed
890 891 892 893
    intf_WarnMsg( 1, "vout: video display initialized (%dx%d, %d/%d bpp)",
              p_vout->i_width, p_vout->i_height, p_vout->i_screen_depth,
              p_vout->i_bytes_per_pixel * 8 );

Sam Hocevar's avatar
 
Sam Hocevar committed
894
    intf_WarnMsg( 3, "vout info: got %dx%d, %d/%d bpp (%d Bpl), "
Sam Hocevar's avatar
 
Sam Hocevar committed
895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928
                  "masks: 0x%x/0x%x/0x%x",
                  p_vout->i_width, p_vout->i_height, p_vout->i_screen_depth,
                  p_vout->i_bytes_per_pixel * 8, p_vout->i_bytes_per_line,
                  p_vout->i_red_mask, p_vout->i_green_mask,
                  p_vout->i_blue_mask );

    /* Calculate shifts from system-updated masks */
    MaskToShift( &p_vout->i_red_lshift, &p_vout->i_red_rshift,
                 p_vout->i_red_mask );
    MaskToShift( &p_vout->i_green_lshift, &p_vout->i_green_rshift,
                 p_vout->i_green_mask );
    MaskToShift( &p_vout->i_blue_lshift, &p_vout->i_blue_rshift,
                 p_vout->i_blue_mask );

    /* Set some useful colors */
    p_vout->i_white_pixel = RGB2PIXEL( p_vout, 255, 255, 255 );
    p_vout->i_black_pixel = RGB2PIXEL( p_vout, 0, 0, 0 );
    p_vout->i_gray_pixel  = RGB2PIXEL( p_vout, 128, 128, 128 );
    p_vout->i_blue_pixel  = RGB2PIXEL( p_vout, 0, 0, 50 );

    /* Load fonts - fonts must be initialized after the system method since
     * they may be dependant on screen depth and other thread properties */
    p_vout->p_default_font =