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.142 2001/10/03 03:32:05 xav 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
#ifndef WIN32
38
#include <sys/times.h>
39
#endif
40

Michel Kaempf's avatar
Michel Kaempf committed
41
#include "config.h"
42 43
#include "common.h"
#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

Vincent Seguin's avatar
Vincent Seguin committed
53
#include "intf_msg.h"
Sam Hocevar's avatar
 
Sam Hocevar committed
54

55
#include "main.h"
Vincent Seguin's avatar
Vincent Seguin committed
56

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

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

    vlc_mutex_destroy( &p_vout_bank->lock );
}

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

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

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

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

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

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

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

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

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

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

215
    /* Initialize statistics fields */
216
    p_vout->c_fps_samples       = 0;
217 218 219 220 221
    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;
222 223 224 225

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

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

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

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

244
    p_vout->i_pictures = 0;
245

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

484
    p_subpic->i_status = DESTROYED_SUBPICTURE;
Vincent Seguin's avatar
Vincent Seguin committed
485

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

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

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

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

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

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

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

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

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

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

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

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

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

Vincent Seguin's avatar
Vincent Seguin committed
702
        return( p_free_picture );
Michel Kaempf's avatar
Michel Kaempf committed
703
    }
704

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Vincent Seguin's avatar
Vincent Seguin committed
791 792 793 794 795 796 797 798 799 800 801 802 803
/*****************************************************************************
 * 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
804 805
/* following functions are local */

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

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

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

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

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

879 880
    vlc_mutex_lock( &p_vout->change_lock );

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

Gildas Bazin's avatar
 
Gildas Bazin committed
892 893 894 895
    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
896
    intf_WarnMsg( 3, "vout info: got %dx%d, %d/%d bpp (%d Bpl), "
Sam Hocevar's avatar
 
Sam Hocevar committed
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 929 930
                  "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(