video_output.c 83.5 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 8 9 10 11 12 13 14
 * thread, and destroy a previously oppened video output thread.
 *****************************************************************************
 * Copyright (C) 2000 VideoLAN
 *
 * Authors:
 *
 * 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
15
 *
16 17
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 19
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
20
 *
21 22 23
 * 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.
24
 *****************************************************************************/
Michel Kaempf's avatar
Michel Kaempf committed
25

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

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

Michel Kaempf's avatar
Michel Kaempf committed
36
#include "config.h"
37 38
#include "common.h"
#include "threads.h"
Michel Kaempf's avatar
Michel Kaempf committed
39
#include "mtime.h"
40
#include "plugins.h"
Michel Kaempf's avatar
Michel Kaempf committed
41 42
#include "video.h"
#include "video_output.h"
Vincent Seguin's avatar
Vincent Seguin committed
43
#include "video_text.h"
Sam Hocevar's avatar
NEWS:  
Sam Hocevar committed
44
#include "video_spu.h"
45
#include "video_yuv.h"
46

Vincent Seguin's avatar
Vincent Seguin committed
47
#include "intf_msg.h"
48
#include "main.h"
Vincent Seguin's avatar
Vincent Seguin committed
49

Renaud Dartus's avatar
 
Renaud Dartus committed
50 51 52
#include "vdec_idct.h"
#include "video_decoder.h"

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

84
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
85
 * vout_CreateThread: creates a new video output thread
86
 *****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
87 88 89
 * 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.
90
 * If not, it will be updated using one of the THREAD_* constants.
91
 *****************************************************************************/
92
vout_thread_t * vout_CreateThread   ( char *psz_display, int i_root_window,
93 94
                          int i_width, int i_height, int *pi_status,
                          int i_method, void *p_data )
Michel Kaempf's avatar
Michel Kaempf committed
95
{
96
    vout_thread_t * p_vout;                             /* thread descriptor */
97
    typedef void    ( vout_getplugin_t ) ( vout_thread_t * p_vout );
98 99
    int             i_status;                               /* thread status */
    int             i_index;               /* index for array initialization */
Sam Hocevar's avatar
Sam Hocevar committed
100
    int             i_best_index = 0, i_best_score = 0;
Michel Kaempf's avatar
Michel Kaempf committed
101

102
    /* Allocate descriptor */
103
    intf_DbgMsg("\n");
Michel Kaempf's avatar
Michel Kaempf committed
104
    p_vout = (vout_thread_t *) malloc( sizeof(vout_thread_t) );
105
    if( p_vout == NULL )
Michel Kaempf's avatar
Michel Kaempf committed
106
    {
107
        intf_ErrMsg( "error: %s\n", strerror(ENOMEM) );
Michel Kaempf's avatar
Michel Kaempf committed
108 109
        return( NULL );
    }
110

111
    p_vout->p_set_palette       = SetPalette;
112

113 114
    /* Get a suitable video plugin */
    for( i_index = 0 ; i_index < p_main->p_bank->i_plugin_count ; i_index++ )
115
    {
116 117 118 119 120 121
        /* If there's a plugin in p_info ... */
        if( p_main->p_bank->p_info[ i_index ] != NULL )
        {
            /* ... and if this plugin provides the functions we want ... */
            if( p_main->p_bank->p_info[ i_index ]->vout_GetPlugin != NULL )
            {
Sam Hocevar's avatar
Sam Hocevar committed
122 123 124 125 126 127 128
                /* ... and if this plugin has a good score ... */
                if( p_main->p_bank->p_info[ i_index ]->i_score > i_best_score )
                {
                    /* ... then take it */
                    i_best_score = p_main->p_bank->p_info[ i_index ]->i_score;
                    i_best_index = i_index;
                }
129 130
            }
        }
131
    }
132

Sam Hocevar's avatar
Sam Hocevar committed
133 134 135 136 137 138 139 140 141 142
    if( i_best_score == 0 )
    {
        free( p_vout );
        return( NULL );
    }

    /* Get the plugin functions */
    ( (vout_getplugin_t *)
      p_main->p_bank->p_info[ i_best_index ]->vout_GetPlugin )( p_vout );

143
    /* Initialize thread properties - thread id and locks will be initialized
144
     * later */
145
    p_vout->b_die               = 0;
146
    p_vout->b_error             = 0;
147 148
    p_vout->b_active            = 0;
    p_vout->pi_status           = (pi_status != NULL) ? pi_status : &i_status;
149
    *p_vout->pi_status          = THREAD_CREATE;
150

151 152 153
    /* 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
154 155 156 157 158 159 160
    p_vout->i_changes             = 0;
    p_vout->i_width               = i_width;
    p_vout->i_height              = i_height;
    p_vout->i_bytes_per_line      = i_width * 2;
    p_vout->i_screen_depth        = 15;
    p_vout->i_bytes_per_pixel     = 2;
    p_vout->f_gamma               = VOUT_GAMMA;
161
    p_vout->b_need_render         = 1;
Renaud Dartus's avatar
 
Renaud Dartus committed
162 163

    p_vout->b_grayscale           = main_GetIntVariable( VOUT_GRAYSCALE_VAR,
Sam Hocevar's avatar
Sam Hocevar committed
164
                                                       VOUT_GRAYSCALE_DEFAULT );
Renaud Dartus's avatar
 
Renaud Dartus committed
165 166 167 168
    p_vout->vdec_DecodeMacroblock = vdec_DecodeMacroblockC;
    p_vout->b_info                = 0;
    p_vout->b_interface           = 0;
    p_vout->b_scale               = 1;
169

Sam Hocevar's avatar
Sam Hocevar committed
170 171 172
    intf_DbgMsg( "wished configuration: %dx%d, %d/%d bpp (%d Bpl)\n",
                 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 );
173

174
    /* Initialize idle screen */
175
    p_vout->last_display_date   = 0;
176
    p_vout->last_idle_date      = 0;
177
    p_vout->init_display_date   = mdate();
178
    p_vout->render_time         = 10000;
179

180
    /* Initialize statistics fields */
181
    p_vout->c_fps_samples       = 0;
182 183 184 185

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

186
    /* Initialize pictures and subpictures - translation tables and functions
187
     * will be initialized later in InitThread */
188 189
    for( i_index = 0; i_index < VOUT_MAX_PICTURES; i_index++)
    {
190 191
        p_vout->p_picture[i_index].i_type   =   EMPTY_PICTURE;
        p_vout->p_picture[i_index].i_status =   FREE_PICTURE;
192 193 194
    }
    for( i_index = 0; i_index < VOUT_MAX_SUBPICTURES; i_index++)
    {
195 196
        p_vout->p_subpicture[i_index].i_type  = EMPTY_SUBPICTURE;
        p_vout->p_subpicture[i_index].i_status= FREE_SUBPICTURE;
197
    }
198
    p_vout->i_pictures = 0;
199

200 201
    /* Create and initialize system-dependant method - this function issues its
     * own error messages */
202
    if( p_vout->p_sys_create( p_vout, psz_display, i_root_window, p_data ) )
Michel Kaempf's avatar
Michel Kaempf committed
203
    {
204 205
        free( p_vout );
        return( NULL );
Michel Kaempf's avatar
Michel Kaempf committed
206
    }
207 208 209 210 211 212
    intf_DbgMsg( "actual configuration: %dx%d, %d/%d bpp (%d Bpl), "
                 "masks: 0x%x/0x%x/0x%x\n",
                 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 );
Vincent Seguin's avatar
Vincent Seguin committed
213 214

    /* Calculate shifts from system-updated masks */
215 216 217 218 219 220
    MaskToShift( &p_vout->i_red_lshift, &p_vout->i_red_rshift,
                 p_vout->i_red_mask );
    MaskToShift( &p_vout->i_green_lshift, &p_vout->i_green_rshift,
                 p_vout->i_green_mask );
    MaskToShift( &p_vout->i_blue_lshift, &p_vout->i_blue_rshift,
                 p_vout->i_blue_mask );
Vincent Seguin's avatar
Vincent Seguin committed
221

222
    /* Set some useful colors */
223
    p_vout->i_white_pixel = RGB2PIXEL( p_vout, 255, 255, 255 );
Vincent Seguin's avatar
Vincent Seguin committed
224 225
    p_vout->i_black_pixel = RGB2PIXEL( p_vout, 0, 0, 0 );
    p_vout->i_gray_pixel  = RGB2PIXEL( p_vout, 128, 128, 128 );
226
    p_vout->i_blue_pixel  = RGB2PIXEL( p_vout, 0, 0, 50 );
227

228 229
    /* Load fonts - fonts must be initialized after the system method since
     * they may be dependant on screen depth and other thread properties */
230
    p_vout->p_default_font = vout_LoadFont( DATA_PATH "/" VOUT_DEFAULT_FONT );
231 232
    if( p_vout->p_default_font == NULL )
    {
233
        p_vout->p_default_font = vout_LoadFont( "share/" VOUT_DEFAULT_FONT );
234
    }
Vincent Seguin's avatar
Vincent Seguin committed
235 236
    if( p_vout->p_default_font == NULL )
    {
237
        intf_ErrMsg( "vout error: could not load default font\n" );
238
        p_vout->p_sys_destroy( p_vout );
239 240 241
        free( p_vout );
        return( NULL );
    }
242
    p_vout->p_large_font = vout_LoadFont( DATA_PATH "/" VOUT_LARGE_FONT );
243 244
    if( p_vout->p_large_font == NULL )
    {
245
        p_vout->p_large_font = vout_LoadFont( "share/" VOUT_LARGE_FONT );
246
    }
Vincent Seguin's avatar
Vincent Seguin committed
247 248
    if( p_vout->p_large_font == NULL )
    {
249
        intf_ErrMsg( "vout error: could not load large font\n" );
250
        vout_UnloadFont( p_vout->p_default_font );
251
        p_vout->p_sys_destroy( p_vout );
252 253 254
        free( p_vout );
        return( NULL );
    }
Vincent Seguin's avatar
Vincent Seguin committed
255

Michel Kaempf's avatar
Michel Kaempf committed
256
    /* Create thread and set locks */
Vincent Seguin's avatar
Vincent Seguin committed
257
    vlc_mutex_init( &p_vout->picture_lock );
258 259 260
    vlc_mutex_init( &p_vout->subpicture_lock );
    vlc_mutex_init( &p_vout->change_lock );
    vlc_mutex_lock( &p_vout->change_lock );
261 262
    if( vlc_thread_create( &p_vout->thread_id, "video output",
                           (void *) RunThread, (void *) p_vout) )
Michel Kaempf's avatar
Michel Kaempf committed
263
    {
264
        intf_ErrMsg("error: %s\n", strerror(ENOMEM));
Vincent Seguin's avatar
Vincent Seguin committed
265
        vout_UnloadFont( p_vout->p_default_font );
266
        vout_UnloadFont( p_vout->p_large_font );
267
        p_vout->p_sys_destroy( p_vout );
Michel Kaempf's avatar
Michel Kaempf committed
268 269
        free( p_vout );
        return( NULL );
270
    }
Michel Kaempf's avatar
Michel Kaempf committed
271

272 273 274
    intf_Msg( "Video display initialized (%dx%d, %d/%d bpp)\n", p_vout->i_width,
              p_vout->i_height, p_vout->i_screen_depth,
              p_vout->i_bytes_per_pixel * 8 );
275

Michel Kaempf's avatar
Michel Kaempf committed
276 277 278 279
    /* If status is NULL, wait until the thread is created */
    if( pi_status == NULL )
    {
        do
280
        {
Michel Kaempf's avatar
Michel Kaempf committed
281
            msleep( THREAD_SLEEP );
282
        }while( (i_status != THREAD_READY) && (i_status != THREAD_ERROR)
Michel Kaempf's avatar
Michel Kaempf committed
283 284 285
                && (i_status != THREAD_FATAL) );
        if( i_status != THREAD_READY )
        {
286 287
            return( NULL );
        }
Michel Kaempf's avatar
Michel Kaempf committed
288 289 290 291
    }
    return( p_vout );
}

292
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
293
 * vout_DestroyThread: destroys a previously created thread
294 295
 *****************************************************************************
 * Destroy a terminated thread.
Michel Kaempf's avatar
Michel Kaempf committed
296
 * The function will request a destruction of the specified thread. If pi_error
297
 * is NULL, it will return once the thread is destroyed. Else, it will be
Michel Kaempf's avatar
Michel Kaempf committed
298
 * update using one of the THREAD_* constants.
299
 *****************************************************************************/
Michel Kaempf's avatar
Michel Kaempf committed
300
void vout_DestroyThread( vout_thread_t *p_vout, int *pi_status )
301 302
{
    int     i_status;                                       /* thread status */
Michel Kaempf's avatar
Michel Kaempf committed
303 304

    /* Set status */
305
    intf_DbgMsg("\n");
Michel Kaempf's avatar
Michel Kaempf committed
306
    p_vout->pi_status = (pi_status != NULL) ? pi_status : &i_status;
307 308
    *p_vout->pi_status = THREAD_DESTROY;

Michel Kaempf's avatar
Michel Kaempf committed
309 310 311 312
    /* Request thread destruction */
    p_vout->b_die = 1;

    /* If status is NULL, wait until thread has been destroyed */
313
    if( pi_status == NULL )
Michel Kaempf's avatar
Michel Kaempf committed
314 315 316 317
    {
        do
        {
            msleep( THREAD_SLEEP );
318 319
        }while( (i_status != THREAD_OVER) && (i_status != THREAD_ERROR)
                && (i_status != THREAD_FATAL) );
Michel Kaempf's avatar
Michel Kaempf committed
320 321 322
    }
}

323
/*****************************************************************************
324
 * vout_DisplaySubPicture: display a subpicture unit
325 326
 *****************************************************************************
 * Remove the reservation flag of an subpicture, which will cause it to be ready
327
 * for display. The picture does not need to be locked, since it is ignored by
Vincent Seguin's avatar
Vincent Seguin committed
328
 * the output thread if is reserved.
329
 *****************************************************************************/
330
void  vout_DisplaySubPicture( vout_thread_t *p_vout, subpicture_t *p_subpic )
Vincent Seguin's avatar
Vincent Seguin committed
331
{
332
#ifdef DEBUG_VOUT
333 334
    char        psz_begin_date[MSTRTIME_MAX_SIZE]; /* buffer for date string */
    char        psz_end_date[MSTRTIME_MAX_SIZE];   /* buffer for date string */
Vincent Seguin's avatar
Vincent Seguin committed
335 336 337 338
#endif

#ifdef DEBUG
    /* Check if status is valid */
339
    if( p_subpic->i_status != RESERVED_SUBPICTURE )
Vincent Seguin's avatar
Vincent Seguin committed
340
    {
341 342 343
        intf_DbgMsg("error: subpicture %p has invalid status %d\n", p_subpic,
                    p_subpic->i_status );
    }
Vincent Seguin's avatar
Vincent Seguin committed
344 345 346
#endif

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

349
#ifdef DEBUG_VOUT
Sam Hocevar's avatar
Sam Hocevar committed
350
    /* Send subpicture information */
351 352 353 354
    intf_DbgMsg("subpicture %p: type=%d, begin date=%s, end date=%s\n",
                p_subpic, p_subpic->i_type,
                mstrtime( psz_begin_date, p_subpic->begin_date ),
                mstrtime( psz_end_date, p_subpic->end_date ) );
Vincent Seguin's avatar
Vincent Seguin committed
355 356 357
#endif
}

358
/*****************************************************************************
Sam Hocevar's avatar
Sam Hocevar committed
359
 * vout_CreateSubPicture: allocate a subpicture in the video output heap.
360 361
 *****************************************************************************
 * This function create a reserved subpicture in the video output heap.
Vincent Seguin's avatar
Vincent Seguin committed
362
 * A null pointer is returned if the function fails. This method provides an
363
 * already allocated zone of memory in the spu data fields. It needs locking
364 365 366
 * since several pictures can be created by several producers threads.
 *****************************************************************************/
subpicture_t *vout_CreateSubPicture( vout_thread_t *p_vout, int i_type,
367
                                     int i_size )
Vincent Seguin's avatar
Vincent Seguin committed
368
{
369 370 371
    int                 i_subpic;                        /* subpicture index */
    subpicture_t *      p_free_subpic = NULL;       /* first free subpicture */
    subpicture_t *      p_destroyed_subpic = NULL; /* first destroyed subpic */
372 373 374 375

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

376 377
    /*
     * Look for an empty place
378
     */
379
    for( i_subpic = 0; i_subpic < VOUT_MAX_SUBPICTURES; i_subpic++ )
380
    {
381 382 383 384 385 386
        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
387 388 389 390
                /* 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 */
391
                p_vout->p_subpicture[i_subpic].i_status = RESERVED_SUBPICTURE;
392
#ifdef DEBUG_VOUT
393 394
                intf_DbgMsg("subpicture %p (in destroyed subpicture slot)\n",
                            &p_vout->p_subpicture[i_subpic] );
395
#endif
396 397 398 399 400 401 402 403 404 405
                vlc_mutex_unlock( &p_vout->subpicture_lock );
                return( &p_vout->p_subpicture[i_subpic] );
            }
            else if( p_destroyed_subpic == NULL )
            {
                /* Memory size do not match, but subpicture index will be kept in
                 * case no other place are left */
                p_destroyed_subpic = &p_vout->p_subpicture[i_subpic];
            }
        }
406
        else if( (p_free_subpic == NULL) &&
407 408
                 (p_vout->p_subpicture[i_subpic].i_status == FREE_SUBPICTURE ))
        {
409
            /* Subpicture is empty and ready for allocation */
410 411 412 413
            p_free_subpic = &p_vout->p_subpicture[i_subpic];
        }
    }

Sam Hocevar's avatar
Sam Hocevar committed
414
    /* If no free subpictures are available, use a destroyed subpicture */
415
    if( (p_free_subpic == NULL) && (p_destroyed_subpic != NULL ) )
416
    {
Sam Hocevar's avatar
Sam Hocevar committed
417
        /* No free subpicture or matching destroyed subpictures have been
Sam Hocevar's avatar
NEWS:  
Sam Hocevar committed
418
         * found, but a destroyed subpicture is still avalaible */
419
        free( p_destroyed_subpic->p_data );
420 421 422 423 424 425 426 427 428 429 430
        p_free_subpic = p_destroyed_subpic;
    }

    /*
     * Prepare subpicture
     */
    if( p_free_subpic != NULL )
    {
        /* Allocate memory */
        switch( i_type )
        {
431 432
        case TEXT_SUBPICTURE:                             /* text subpicture */
            p_free_subpic->p_data = malloc( i_size + 1 );
433
            break;
434 435 436
        case DVD_SUBPICTURE:                          /* DVD subpicture unit */
            p_free_subpic->p_data = malloc( i_size );
            break;
437 438 439
#ifdef DEBUG
        default:
            intf_DbgMsg("error: unknown subpicture type %d\n", i_type );
440 441 442
            p_free_subpic->p_data   =  NULL;
            break;
#endif
443 444 445
        }

        if( p_free_subpic->p_data != NULL )
Sam Hocevar's avatar
Sam Hocevar committed
446 447
        {
            /* Copy subpicture information, set some default values */
448 449
            p_free_subpic->i_type                      = i_type;
            p_free_subpic->i_status                    = RESERVED_SUBPICTURE;
450
            p_free_subpic->i_size                      = i_size;
451
            p_free_subpic->i_x                         = 0;
452
            p_free_subpic->i_y                         = 0;
453 454
            p_free_subpic->i_width                     = 0;
            p_free_subpic->i_height                    = 0;
455 456
            p_free_subpic->i_horizontal_align          = CENTER_RALIGN;
            p_free_subpic->i_vertical_align            = CENTER_RALIGN;
457 458 459 460
        }
        else
        {
            /* Memory allocation failed : set subpicture as empty */
461 462 463
            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
464
            intf_ErrMsg("spu warning: %s\n", strerror( ENOMEM ) );
465
        }
466

467
#ifdef DEBUG_VOUT
468
        intf_DbgMsg("subpicture %p (in free subpicture slot)\n", p_free_subpic );
469 470 471 472
#endif
        vlc_mutex_unlock( &p_vout->subpicture_lock );
        return( p_free_subpic );
    }
473

474
    /* No free or destroyed subpicture could be found */
Sam Hocevar's avatar
Sam Hocevar committed
475
    intf_DbgMsg( "warning: subpicture heap is full\n" );
476 477
    vlc_mutex_unlock( &p_vout->subpicture_lock );
    return( NULL );
Vincent Seguin's avatar
Vincent Seguin committed
478 479
}

480
/*****************************************************************************
481
 * vout_DestroySubPicture: remove a subpicture from the heap
482
 *****************************************************************************
483
 * This function frees a previously reserved subpicture.
Vincent Seguin's avatar
Vincent Seguin committed
484
 * It is meant to be used when the construction of a picture aborted.
485
 * This function does not need locking since reserved subpictures are ignored
486
 * by the output thread.
487
 *****************************************************************************/
488
void vout_DestroySubPicture( vout_thread_t *p_vout, subpicture_t *p_subpic )
Vincent Seguin's avatar
Vincent Seguin committed
489 490
{
#ifdef DEBUG
491 492
   /* Check if status is valid */
   if( p_subpic->i_status != RESERVED_SUBPICTURE )
Vincent Seguin's avatar
Vincent Seguin committed
493
   {
494 495 496
       intf_DbgMsg("error: subpicture %p has invalid status %d\n",
                   p_subpic, p_subpic->i_status );
   }
Vincent Seguin's avatar
Vincent Seguin committed
497 498
#endif

499
    p_subpic->i_status = DESTROYED_SUBPICTURE;
Vincent Seguin's avatar
Vincent Seguin committed
500

501
#ifdef DEBUG_VOUT
502
    intf_DbgMsg("subpicture %p\n", p_subpic);
Vincent Seguin's avatar
Vincent Seguin committed
503 504 505
#endif
}

506
/*****************************************************************************
Vincent Seguin's avatar
Vincent Seguin committed
507
 * vout_DisplayPicture: display a picture
508
 *****************************************************************************
Vincent Seguin's avatar
Vincent Seguin committed
509
 * Remove the reservation flag of a picture, which will cause it to be ready for
510
 * display. The picture won't be displayed until vout_DatePicture has been
511
 * called.
512
 *****************************************************************************/
Vincent Seguin's avatar
Vincent Seguin committed
513
void  vout_DisplayPicture( vout_thread_t *p_vout, picture_t *p_pic )
Michel Kaempf's avatar
Michel Kaempf committed
514
{
515 516
    vlc_mutex_lock( &p_vout->picture_lock );
    switch( p_pic->i_status )
517
    {
518
    case RESERVED_PICTURE:
519
        p_pic->i_status = RESERVED_DISP_PICTURE;
520
        break;
521 522
    case RESERVED_DATED_PICTURE:
        p_pic->i_status = READY_PICTURE;
523
        break;
524
#ifdef DEBUG
525 526 527
    default:
        intf_DbgMsg("error: picture %p has invalid status %d\n", p_pic, p_pic->i_status );
        break;
528
#endif
529
    }
Michel Kaempf's avatar
Michel Kaempf committed
530

531
#ifdef DEBUG_VOUT
Vincent Seguin's avatar
Vincent Seguin committed
532
    intf_DbgMsg("picture %p\n", p_pic);
533
#endif
534
    vlc_mutex_unlock( &p_vout->picture_lock );
Michel Kaempf's avatar
Michel Kaempf committed
535 536
}

537
/*****************************************************************************
538
 * vout_DatePicture: date a picture
539
 *****************************************************************************
540
 * Remove the reservation flag of a picture, which will cause it to be ready for
541
 * display. The picture won't be displayed until vout_DisplayPicture has been
542
 * called.
543
 *****************************************************************************/
544 545
void  vout_DatePicture( vout_thread_t *p_vout, picture_t *p_pic, mtime_t date )
{
546
#ifdef DEBUG_VOUT
547
    char        psz_date[MSTRTIME_MAX_SIZE];                         /* date */
Vincent Seguin's avatar
Vincent Seguin committed
548 549
#endif

550
    vlc_mutex_lock( &p_vout->picture_lock );
551
    p_pic->date = date;
552 553
    switch( p_pic->i_status )
    {
554
    case RESERVED_PICTURE:
555
        p_pic->i_status = RESERVED_DATED_PICTURE;
556
        break;
557 558
    case RESERVED_DISP_PICTURE:
        p_pic->i_status = READY_PICTURE;
559
        break;
560
#ifdef DEBUG
561 562 563
    default:
        intf_DbgMsg("error: picture %p has invalid status %d\n", p_pic, p_pic->i_status );
        break;
564 565 566
#endif
    }

567
#ifdef DEBUG_VOUT
Vincent Seguin's avatar
Vincent Seguin committed
568
    intf_DbgMsg("picture %p, display date: %s\n", p_pic, mstrtime( psz_date, p_pic->date) );
569
#endif
570
    vlc_mutex_unlock( &p_vout->picture_lock );
571 572
}

573
/*****************************************************************************
Vincent Seguin's avatar
Vincent Seguin committed
574
 * vout_CreatePicture: allocate a picture in the video output heap.
575 576
 *****************************************************************************
 * This function create a reserved image in the video output heap.
Vincent Seguin's avatar
Vincent Seguin committed
577
 * A null pointer is returned if the function fails. This method provides an
578
 * already allocated zone of memory in the picture data fields. It needs locking
579 580 581
 * since several pictures can be created by several producers threads.
 *****************************************************************************/
picture_t *vout_CreatePicture( vout_thread_t *p_vout, int i_type,
582
                               int i_width, int i_height )
Michel Kaempf's avatar
Michel Kaempf committed
583
{
584 585 586 587
    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
588

Vincent Seguin's avatar
Vincent Seguin committed
589
    /* Get lock */
Vincent Seguin's avatar
Vincent Seguin committed
590
    vlc_mutex_lock( &p_vout->picture_lock );
Michel Kaempf's avatar
Michel Kaempf committed
591

592 593
    /*
     * Look for an empty place
Vincent Seguin's avatar
Vincent Seguin committed
594
     */
595
    for( i_picture = 0; i_picture < VOUT_MAX_PICTURES; i_picture++ )
Vincent Seguin's avatar
Vincent Seguin committed
596
    {
597 598 599
        if( p_vout->p_picture[i_picture].i_status == DESTROYED_PICTURE )
        {
            /* Picture is marked for destruction, but is still allocated - note
600
             * that if width and type are the same for two pictures, chroma_width
601
             * should also be the same */
602 603 604 605 606
            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
607 608
                 * can end immediately - this is the best possible case, since no
                 * memory allocation needs to be done */
609
                p_vout->p_picture[i_picture].i_status = RESERVED_PICTURE;
610
                p_vout->i_pictures++;
611
#ifdef DEBUG_VOUT
612 613
                intf_DbgMsg("picture %p (in destroyed picture slot)\n",
                            &p_vout->p_picture[i_picture] );
614
#endif
615 616 617 618 619 620 621 622 623 624
                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];
            }
        }
625
        else if( (p_free_picture == NULL) &&
Vincent Seguin's avatar
Vincent Seguin committed
626 627
                 (p_vout->p_picture[i_picture].i_status == FREE_PICTURE ))
        {
628
            /* Picture is empty and ready for allocation */
629
            p_free_picture = &p_vout->p_picture[i_picture];
Vincent Seguin's avatar
Vincent Seguin committed
630
        }
Michel Kaempf's avatar
Michel Kaempf committed
631 632
    }

Vincent Seguin's avatar
Vincent Seguin committed
633 634
    /* If no free picture is available, use a destroyed picture */
    if( (p_free_picture == NULL) && (p_destroyed_picture != NULL ) )
635
    {
636 637
        /* No free picture or matching destroyed picture has been found, but
         * a destroyed picture is still avalaible */
638 639
        free( p_destroyed_picture->p_data );
        p_free_picture = p_destroyed_picture;
Michel Kaempf's avatar
Michel Kaempf committed
640 641
    }

Vincent Seguin's avatar
Vincent Seguin committed
642 643 644 645 646 647 648
    /*
     * Prepare picture
     */
    if( p_free_picture != NULL )
    {
        /* Allocate memory */
        switch( i_type )
Michel Kaempf's avatar
Michel Kaempf committed
649
        {
650 651
        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
652
            p_free_picture->p_data = malloc( i_height * i_chroma_width * 3 * sizeof( yuv_data_t ) );
653
            p_free_picture->p_y = (yuv_data_t *)p_free_picture->p_data;
Vincent Seguin's avatar
Vincent Seguin committed
654 655
            p_free_picture->p_u = (yuv_data_t *)p_free_picture->p_data +i_height*i_chroma_width*4/2;
            p_free_picture->p_v = (yuv_data_t *)p_free_picture->p_data +i_height*i_chroma_width*5/2;
656
            break;
657 658
        case YUV_422_PICTURE:        /* YUV 422: 1,1/2,1/2 samples per pixel */
            i_chroma_width = i_width / 2;
659 660
            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
661 662
            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;
663
            break;
664 665
        case YUV_444_PICTURE:            /* YUV 444: 1,1,1 samples per pixel */
            i_chroma_width = i_width;
666 667
            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
668 669
            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;
670
            break;
Vincent Seguin's avatar
Vincent Seguin committed
671 672
#ifdef DEBUG
        default:
673
            intf_DbgMsg("error: unknown picture type %d\n", i_type );
674 675 676
            p_free_picture->p_data   =  NULL;
            break;
#endif
Michel Kaempf's avatar
Michel Kaempf committed
677 678
        }

Vincent Seguin's avatar
Vincent Seguin committed
679
        if( p_free_picture->p_data != NULL )
680
        {
Sam Hocevar's avatar
Sam Hocevar committed
681
            /* Copy picture information, set some default values */
682 683
            p_free_picture->i_type                      = i_type;
            p_free_picture->i_status                    = RESERVED_PICTURE;
684
            p_free_picture->i_matrix_coefficients       = 1;
685 686
            p_free_picture->i_width                     = i_width;
            p_free_picture->i_height                    = i_height;
687
            p_free_picture->i_chroma_width              = i_chroma_width;
688
            p_free_picture->i_display_horizontal_offset = 0;
689
            p_free_picture->i_display_vertical_offset   = 0;
690 691
            p_free_picture->i_display_width             = i_width;
            p_free_picture->i_display_height            = i_height;
692 693
            p_free_picture->i_aspect_ratio              = AR_SQUARE_PICTURE;
            p_free_picture->i_refcount                  = 0;
694
            p_vout->i_pictures++;
Vincent Seguin's avatar
Vincent Seguin committed
695 696 697 698
        }
        else
        {
            /* Memory allocation failed : set picture as empty */
699 700 701
            p_free_picture->i_type   =  EMPTY_PICTURE;
            p_free_picture->i_status =  FREE_PICTURE;
            p_free_picture =            NULL;
702
            intf_ErrMsg( "vout warning: %s\n", strerror( ENOMEM ) );
Vincent Seguin's avatar
Vincent Seguin committed
703
        }
704

705
#ifdef DEBUG_VOUT
706
        intf_DbgMsg("picture %p (in free picture slot)\n", p_free_picture );
707
#endif
Vincent Seguin's avatar
Vincent Seguin committed
708
        vlc_mutex_unlock( &p_vout->picture_lock );
Vincent Seguin's avatar
Vincent Seguin committed
709
        return( p_free_picture );
Michel Kaempf's avatar
Michel Kaempf committed
710
    }
711

712
    /* No free or destroyed picture could be found */
Sam Hocevar's avatar
Sam Hocevar committed
713
    intf_DbgMsg( "warning: picture heap is full\n" );
Vincent Seguin's avatar
Vincent Seguin committed
714
    vlc_mutex_unlock( &p_vout->picture_lock );
Vincent Seguin's avatar
Vincent Seguin committed
715
    return( NULL );
Michel Kaempf's avatar
Michel Kaempf committed
716 717
}

718
/*****************************************************************************
719
 * vout_DestroyPicture: remove a permanent or reserved picture from the heap
720
 *****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
721
 * This function frees a previously reserved picture or a permanent
Vincent Seguin's avatar
Vincent Seguin committed
722 723
 * 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 !
724
 *****************************************************************************/
Vincent Seguin's avatar
Vincent Seguin committed
725
void vout_DestroyPicture( vout_thread_t *p_vout, picture_t *p_pic )
Michel Kaempf's avatar
Michel Kaempf committed
726
{
727
   vlc_mutex_lock( &p_vout->picture_lock );
728

729
#ifdef DEBUG
730
   /* Check if picture status is valid */
731
   if( (p_pic->i_status != RESERVED_PICTURE) &&
732 733
       (p_pic->i_status != RESERVED_DATED_PICTURE) &&
       (p_pic->i_status != RESERVED_DISP_PICTURE) )
734
   {
735 736
       intf_DbgMsg("error: picture %p has invalid status %d\n", p_pic, p_pic->i_status );
   }
737 738
#endif

739
   p_pic->i_status = DESTROYED_PICTURE;
740
   p_vout->i_pictures--;
741

742
#ifdef DEBUG_VOUT
743
   intf_DbgMsg("picture %p\n", p_pic);
744
#endif
745
   vlc_mutex_unlock( &p_vout->picture_lock );
Michel Kaempf's avatar
Michel Kaempf committed
746 747
}

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

759
#ifdef DEBUG_VOUT
760
    intf_DbgMsg("picture %p refcount=%d\n", p_pic, p_pic->i_refcount );
761
#endif
762 763

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

766
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
767
 * vout_UnlinkPicture: decrement reference counter of a picture
768
 *****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
769
 * This function decrement the reference counter of a picture in the video heap.
770
 *****************************************************************************/
Michel Kaempf's avatar
Michel Kaempf committed
771 772
void vout_UnlinkPicture( vout_thread_t *p_vout, picture_t *p_pic )
{
Vincent Seguin's avatar
Vincent Seguin committed
773
    vlc_mutex_lock( &p_vout->picture_lock );
Michel Kaempf's avatar
Michel Kaempf committed
774
    p_pic->i_refcount--;
775

776
#ifdef DEBUG_VOUT
777 778 779
    if( p_pic->i_refcount < 0 )
    {
        intf_DbgMsg("error: refcount < 0\n");
780 781
        p_pic->i_refcount = 0;
    }
782 783
#endif

Vincent Seguin's avatar
Vincent Seguin committed
784
    if( (p_pic->i_refcount == 0) && (p_pic->i_status == DISPLAYED_PICTURE) )
Michel Kaempf's avatar
Michel Kaempf committed
785
    {
786
        p_pic->i_status = DESTROYED_PICTURE;
787
        p_vout->i_pictures--;
Michel Kaempf's avatar
Michel Kaempf committed
788
    }
789

790
#ifdef DEBUG_VOUT
791
    intf_DbgMsg("picture %p refcount=%d\n", p_pic, p_pic->i_refcount );
792
#endif