video_output.c 83.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.140 2001/09/26 12:32:25 massiot Exp $
9
 *
Sam Hocevar's avatar
 
Sam Hocevar committed
10
 * Authors: Vincent Seguin <seguin@via.ecp.fr>
11 12 13 14 15
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
Sam Hocevar's avatar
Sam Hocevar committed
16
 *
17 18
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 20
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
21
 *
22 23 24
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
25
 *****************************************************************************/
Michel Kaempf's avatar
Michel Kaempf committed
26

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

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

37 38 39 40
#ifdef STATS
#   include <sys/times.h>
#endif

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

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

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

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

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

239
    p_vout->i_pictures = 0;
240

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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