video_output.c 85 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
 * thread, and destroy a previously oppened video output thread.
 *****************************************************************************
7
 * Copyright (C) 2000-2001 VideoLAN
Sam Hocevar's avatar
 
Sam Hocevar committed
8
 * $Id: video_output.c,v 1.145 2001/12/07 18:33:08 sam 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.
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 38
#ifdef HAVE_SYS_TIMES_H
#   include <sys/times.h>
39
#endif
40

41
#include "common.h"
42
#include "intf_msg.h"
43
#include "threads.h"
Michel Kaempf's avatar
Michel Kaempf committed
44
#include "mtime.h"
Sam Hocevar's avatar
 
Sam Hocevar committed
45 46
#include "modules.h"

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

53
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
54
 * Local prototypes
55
 *****************************************************************************/
Vincent Seguin's avatar
Vincent Seguin committed
56 57
static int      BinaryLog         ( u32 i );
static void     MaskToShift       ( int *pi_left, int *pi_right, u32 i_mask );
58 59 60 61 62
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 );
63
static void     Print             ( vout_thread_t *p_vout, int i_x, int i_y,
64 65
                                    int i_h_align, int i_v_align,
                                    unsigned char *psz_text );
Sam Hocevar's avatar
 
Sam Hocevar committed
66
static void     SetBuffers        ( vout_thread_t *p_vout, void *, void * );
67 68 69 70 71
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
72
static void     RenderSubPicture  ( vout_thread_t *p_vout, picture_t *p_pic,
73 74 75 76 77 78 79
                                    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 );
80 81
static void     SetPalette        ( p_vout_thread_t p_vout, u16 *red,
                                    u16 *green, u16 *blue, u16 *transp );
Michel Kaempf's avatar
Michel Kaempf committed
82

Sam Hocevar's avatar
 
Sam Hocevar committed
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
/*****************************************************************************
 * 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
106
    }
Sam Hocevar's avatar
 
Sam Hocevar committed
107 108 109 110

    vlc_mutex_destroy( &p_vout_bank->lock );
}

111
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
112
 * vout_CreateThread: creates a new video output thread
113
 *****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
114 115 116
 * 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.
117
 * If not, it will be updated using one of the THREAD_* constants.
118
 *****************************************************************************/
119
vout_thread_t * vout_CreateThread   ( int *pi_status, int i_width, int i_height )
Michel Kaempf's avatar
Michel Kaempf committed
120
{
121 122 123
    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
124

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

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

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

Sam Hocevar's avatar
 
Sam Hocevar committed
144 145 146 147 148 149 150 151 152 153
#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
154 155 156
    /* Initialize callbacks */
    p_vout->pf_setbuffers       = SetBuffers;

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

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

170 171 172
    /* Initialize some fields used by the system-dependant method - these
     * fields will probably be modified by the method, and are only
     * preferences */
173 174 175 176 177 178 179 180 181 182 183 184 185
    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,
186
                                                         VOUT_DEPTH_DEFAULT );
187 188 189 190 191 192 193 194 195 196 197 198
    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,
199
                                                     VOUT_FULLSCREEN_DEFAULT );
200

Sam Hocevar's avatar
 
Sam Hocevar committed
201
    intf_WarnMsg( 3, "vout info: asking for %dx%d, %d/%d bpp (%d Bpl)",
Sam Hocevar's avatar
 
Sam Hocevar committed
202 203
                  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 );
204

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

211
    /* Initialize statistics fields */
212
    p_vout->c_fps_samples       = 0;
213 214 215 216 217
    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;
218 219 220 221

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

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

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

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

240
    p_vout->i_pictures = 0;
241

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

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

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

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

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

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

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

303
/*****************************************************************************
304
 * vout_DisplaySubPicture: display a subpicture unit
305
 *****************************************************************************
Sam Hocevar's avatar
 
Sam Hocevar committed
306
 * Remove the reservation flag of a subpicture, which will cause it to be ready
307
 * for display. The picture does not need to be locked, since it is ignored by
Vincent Seguin's avatar
Vincent Seguin committed
308
 * the output thread if is reserved.
309
 *****************************************************************************/
310
void  vout_DisplaySubPicture( vout_thread_t *p_vout, subpicture_t *p_subpic )
Vincent Seguin's avatar
Vincent Seguin committed
311
{
312
#ifdef TRACE_VOUT
Sam Hocevar's avatar
 
Sam Hocevar committed
313 314
    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
315 316 317 318
#endif

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

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

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

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

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

356 357
    /*
     * Look for an empty place
358
     */
359
    for( i_subpic = 0; i_subpic < VOUT_MAX_SUBPICTURES; i_subpic++ )
360
    {
361 362 363 364 365 366
        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
367 368 369 370
                /* 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 */
371
                p_vout->p_subpicture[i_subpic].i_status = RESERVED_SUBPICTURE;
372
#ifdef TRACE_VOUT
Sam Hocevar's avatar
 
Sam Hocevar committed
373
                intf_DbgMsg("subpicture %p (in destroyed subpicture slot)",
374
                            &p_vout->p_subpicture[i_subpic] );
375
#endif
376 377 378 379 380
                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
381 382
                /* Memory size do not match, but subpicture index will be kept
                 * in case we find no other place */
383 384 385
                p_destroyed_subpic = &p_vout->p_subpicture[i_subpic];
            }
        }
386
        else if( (p_free_subpic == NULL) &&
387 388
                 (p_vout->p_subpicture[i_subpic].i_status == FREE_SUBPICTURE ))
        {
389
            /* Subpicture is empty and ready for allocation */
390 391 392 393
            p_free_subpic = &p_vout->p_subpicture[i_subpic];
        }
    }

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

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

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

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

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

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

480
    p_subpic->i_status = DESTROYED_SUBPICTURE;
Vincent Seguin's avatar
Vincent Seguin committed
481

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

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

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

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

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

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

554
/*****************************************************************************
Vincent Seguin's avatar
Vincent Seguin committed
555
 * vout_CreatePicture: allocate a picture in the video output heap.
556 557
 *****************************************************************************
 * This function create a reserved image in the video output heap.
Vincent Seguin's avatar
Vincent Seguin committed
558
 * A null pointer is returned if the function fails. This method provides an
559
 * already allocated zone of memory in the picture data fields. It needs locking
560 561 562
 * since several pictures can be created by several producers threads.
 *****************************************************************************/
picture_t *vout_CreatePicture( vout_thread_t *p_vout, int i_type,
563
                               int i_width, int i_height )
Michel Kaempf's avatar
Michel Kaempf committed
564
{
565 566 567 568
    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
569

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

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

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

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

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

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

Vincent Seguin's avatar
Vincent Seguin committed
698
        return( p_free_picture );
Michel Kaempf's avatar
Michel Kaempf committed
699
    }
700

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

707
/*****************************************************************************
708
 * vout_DestroyPicture: remove a permanent or reserved picture from the heap
709
 *****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
710
 * This function frees a previously reserved picture or a permanent
Vincent Seguin's avatar
Vincent Seguin committed
711 712
 * 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 !
713
 *****************************************************************************/
Vincent Seguin's avatar
Vincent Seguin committed
714
void vout_DestroyPicture( vout_thread_t *p_vout, picture_t *p_pic )
Michel Kaempf's avatar
Michel Kaempf committed
715
{
Henri Fallon's avatar
 
Henri Fallon committed
716
    vlc_mutex_lock( &p_vout->picture_lock );
717

718
#ifdef DEBUG
Henri Fallon's avatar
 
Henri Fallon committed
719 720 721 722 723
    /* 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) )
    {
724
        intf_ErrMsg("error: picture %p has invalid status %d", p_pic, p_pic->i_status );
Henri Fallon's avatar
 
Henri Fallon committed
725
    }
726 727
#endif

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

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

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

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

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

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

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

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

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

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

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

Vincent Seguin's avatar
Vincent Seguin committed
787 788 789 790 791 792 793 794 795 796 797 798 799
/*****************************************************************************
 * 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
800 801
/* following functions are local */

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

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

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

    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);
}

863
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
864
 * InitThread: initialize video output thread
865
 *****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
866 867 868
 * 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.
869
 *****************************************************************************/
Michel Kaempf's avatar
Michel Kaempf committed
870 871 872
static int InitThread( vout_thread_t *p_vout )
{
    /* Update status */
873
    *p_vout->pi_status = THREAD_START;
Michel Kaempf's avatar
Michel Kaempf committed
874

875 876
    vlc_mutex_lock( &p_vout->change_lock );

Sam Hocevar's avatar
 
Sam Hocevar committed
877 878 879 880
    /* 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
881
        /* If pf_create has failed then we have to make sure
Sam Hocevar's avatar
 
Sam Hocevar committed
882 883
         * pf_destroy won't be called, because the plugin should have
         * cleaned up all its mess */
Gildas Bazin's avatar
 
Gildas Bazin committed
884
        p_vout->pf_destroy = NULL;
Sam Hocevar's avatar
 
Sam Hocevar committed
885
        return( 1 );
Sam Hocevar's avatar
 
Sam Hocevar committed
886 887
    }

Gildas Bazin's avatar
 
Gildas Bazin committed
888 889 890 891
    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
892
    intf_WarnMsg( 3, "vout info: got %dx%d, %d/%d bpp (%d Bpl), "
Sam Hocevar's avatar
 
Sam Hocevar committed
893 894 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
                  "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 = vout_LoadFont( VOUT_DEFAULT_FONT );
    if( p_vout->p_default_font == NULL )
    {
        intf_ErrMsg( "vout error: could not load default font" );
    }

    p_vout->p_large_font = vout_LoadFont( VOUT_LARGE_FONT );
    if( p_vout->p_large_font == NULL )
    {
        intf_ErrMsg( "vout error: could not load large font" );
    }

Gildas Bazin's avatar