video_output.c 83.2 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
Sam Hocevar's avatar
 
Sam Hocevar committed
8
 * $Id: video_output.c,v 1.132 2001/06/14 01:49:44 sam Exp $
9
 *
Sam Hocevar's avatar
 
Sam Hocevar committed
10
 * Authors: Vincent Seguin <seguin@via.ecp.fr>
11 12 13 14 15
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
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
 *****************************************************************************/
Sam Hocevar's avatar
 
Sam Hocevar committed
123
vout_thread_t * vout_CreateThread   ( int *pi_status )
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 */
Renaud Dartus's avatar
 
Renaud Dartus committed
177
    p_vout->i_changes             = 0;
Sam Hocevar's avatar
 
Sam Hocevar committed
178 179 180 181 182
    p_vout->i_width               = main_GetIntVariable( VOUT_WIDTH_VAR,
                                                         VOUT_WIDTH_DEFAULT );
    p_vout->i_height              = main_GetIntVariable( VOUT_HEIGHT_VAR,
                                                         VOUT_HEIGHT_DEFAULT );
    p_vout->i_bytes_per_line      = p_vout->i_width * 2;
183 184
    p_vout->i_screen_depth        = main_GetIntVariable( VOUT_DEPTH_VAR,
                                                         VOUT_DEPTH_DEFAULT );
Renaud Dartus's avatar
 
Renaud Dartus committed
185
    p_vout->i_bytes_per_pixel     = 2;
Sam Hocevar's avatar
 
Sam Hocevar committed
186
    p_vout->f_gamma               = VOUT_GAMMA_DEFAULT; // FIXME: replace with
187
                                                        // variable
188
    p_vout->b_need_render         = 1;
Sam Hocevar's avatar
 
Sam Hocevar committed
189
    p_vout->b_YCbr                = 0;
Sam Hocevar's avatar
 
Sam Hocevar committed
190

Renaud Dartus's avatar
 
Renaud Dartus committed
191
    p_vout->b_grayscale           = main_GetIntVariable( VOUT_GRAYSCALE_VAR,
Sam Hocevar's avatar
 
Sam Hocevar committed
192
                                                     VOUT_GRAYSCALE_DEFAULT );
Renaud Dartus's avatar
 
Renaud Dartus committed
193 194 195
    p_vout->b_info                = 0;
    p_vout->b_interface           = 0;
    p_vout->b_scale               = 1;
196 197
    p_vout->b_fullscreen          = main_GetIntVariable( VOUT_FULLSCREEN_VAR,
                                                     VOUT_FULLSCREEN_DEFAULT );
198

199
    intf_WarnMsg( 3, "wished configuration: %dx%d, %d/%d bpp (%d Bpl)",
Sam Hocevar's avatar
 
Sam Hocevar committed
200 201
                  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 );
202

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

209
    /* Initialize statistics fields */
210
    p_vout->c_fps_samples       = 0;
211 212 213 214

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

215
    /* Initialize pictures and subpictures - translation tables and functions
216
     * will be initialized later in InitThread */
217 218
    for( i_index = 0; i_index < VOUT_MAX_PICTURES; i_index++)
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
219 220
        p_vout->p_picture[i_index].i_type   = EMPTY_PICTURE;
        p_vout->p_picture[i_index].i_status = FREE_PICTURE;
221
    }
Sam Hocevar's avatar
 
Sam Hocevar committed
222

223 224
    for( i_index = 0; i_index < VOUT_MAX_SUBPICTURES; i_index++)
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
225 226
        p_vout->p_subpicture[i_index].i_type   = EMPTY_SUBPICTURE;
        p_vout->p_subpicture[i_index].i_status = FREE_SUBPICTURE;
227
    }
Sam Hocevar's avatar
 
Sam Hocevar committed
228

229
    p_vout->i_pictures = 0;
230

Michel Kaempf's avatar
Michel Kaempf committed
231
    /* Create thread and set locks */
Vincent Seguin's avatar
Vincent Seguin committed
232
    vlc_mutex_init( &p_vout->picture_lock );
233 234
    vlc_mutex_init( &p_vout->subpicture_lock );
    vlc_mutex_init( &p_vout->change_lock );
235

236 237
    if( vlc_thread_create( &p_vout->thread_id, "video output",
                           (void *) RunThread, (void *) p_vout) )
Michel Kaempf's avatar
Michel Kaempf committed
238
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
239
        intf_ErrMsg("vout error: %s", strerror(ENOMEM));
Vincent Seguin's avatar
Vincent Seguin committed
240
        vout_UnloadFont( p_vout->p_default_font );
241
        vout_UnloadFont( p_vout->p_large_font );
Sam Hocevar's avatar
 
Sam Hocevar committed
242
        p_vout->pf_destroy( p_vout );
Michel Kaempf's avatar
Michel Kaempf committed
243 244
        free( p_vout );
        return( NULL );
245
    }
Michel Kaempf's avatar
Michel Kaempf committed
246

247
    intf_WarnMsg( 1, "vout: video display initialized (%dx%d, %d/%d bpp)",
Sam Hocevar's avatar
 
Sam Hocevar committed
248
              p_vout->i_width, p_vout->i_height, p_vout->i_screen_depth,
249
              p_vout->i_bytes_per_pixel * 8 );
250

Michel Kaempf's avatar
Michel Kaempf committed
251 252 253 254
    /* If status is NULL, wait until the thread is created */
    if( pi_status == NULL )
    {
        do
255
        {
Michel Kaempf's avatar
Michel Kaempf committed
256
            msleep( THREAD_SLEEP );
257
        }while( (i_status != THREAD_READY) && (i_status != THREAD_ERROR)
Michel Kaempf's avatar
Michel Kaempf committed
258 259 260
                && (i_status != THREAD_FATAL) );
        if( i_status != THREAD_READY )
        {
261 262
            return( NULL );
        }
Michel Kaempf's avatar
Michel Kaempf committed
263 264 265 266
    }
    return( p_vout );
}

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

    /* Set status */
Sam Hocevar's avatar
 
Sam Hocevar committed
280
    intf_DbgMsg("");
Michel Kaempf's avatar
Michel Kaempf committed
281
    p_vout->pi_status = (pi_status != NULL) ? pi_status : &i_status;
282 283
    *p_vout->pi_status = THREAD_DESTROY;

Michel Kaempf's avatar
Michel Kaempf committed
284 285 286 287
    /* Request thread destruction */
    p_vout->b_die = 1;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

475
    p_subpic->i_status = DESTROYED_SUBPICTURE;
Vincent Seguin's avatar
Vincent Seguin committed
476

477
#ifdef TRACE_VOUT
Sam Hocevar's avatar
 
Sam Hocevar committed
478
    intf_DbgMsg("subpicture %p", p_subpic);
Vincent Seguin's avatar
Vincent Seguin committed
479 480 481
#endif
}

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

507
#ifdef TRACE_VOUT
Sam Hocevar's avatar
 
Sam Hocevar committed
508
    intf_DbgMsg("picture %p", p_pic);
509
#endif
510
    vlc_mutex_unlock( &p_vout->picture_lock );
Michel Kaempf's avatar
Michel Kaempf committed
511 512
}

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

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

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

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

Vincent Seguin's avatar
Vincent Seguin committed
565
    /* Get lock */
Vincent Seguin's avatar
Vincent Seguin committed
566
    vlc_mutex_lock( &p_vout->picture_lock );
Michel Kaempf's avatar
Michel Kaempf committed
567

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

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

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

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

685
#ifdef TRACE_VOUT
Sam Hocevar's avatar
 
Sam Hocevar committed
686
        intf_DbgMsg("picture %p (in free picture slot)", p_free_picture );
687
#endif
Vincent Seguin's avatar
Vincent Seguin committed
688
        vlc_mutex_unlock( &p_vout->picture_lock );
Henri Fallon's avatar
 
Henri Fallon committed
689 690 691

        /* Initialize mutex */
        vlc_mutex_init( &(p_free_picture->lock_deccount) );
Sam Hocevar's avatar
 
Sam Hocevar committed
692

Vincent Seguin's avatar
Vincent Seguin committed
693
        return( p_free_picture );
Michel Kaempf's avatar
Michel Kaempf committed
694
    }
695

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

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

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

Henri Fallon's avatar
 
Henri Fallon committed
723 724
    p_pic->i_status = DESTROYED_PICTURE;
    p_vout->i_pictures--;
725

726
#ifdef TRACE_VOUT
Henri Fallon's avatar
 
Henri Fallon committed
727
    intf_DbgMsg("picture %p", p_pic);
728
#endif
Henri Fallon's avatar
 
Henri Fallon committed
729

Henri Fallon's avatar
 
Henri Fallon committed
730 731
    /* destroy the lock that had been initialized in CreatePicture */
    vlc_mutex_destroy( &(p_pic->lock_deccount) );
Sam Hocevar's avatar
 
Sam Hocevar committed
732

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

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

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

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

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

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

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

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

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