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
 * thread, and destroy a previously oppened video output thread.
 *****************************************************************************
 * Copyright (C) 2000 VideoLAN
 *
Sam Hocevar's avatar
 
Sam Hocevar committed
9
 * Authors:
10 11 12 13 14
 *
 * 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

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

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

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

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

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

56
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
57
 * Local prototypes
58
 *****************************************************************************/
Vincent Seguin's avatar
Vincent Seguin committed
59 60
static int      BinaryLog         ( u32 i );
static void     MaskToShift       ( int *pi_left, int *pi_right, u32 i_mask );
61 62 63 64 65
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 );
66
static void     Print             ( vout_thread_t *p_vout, int i_x, int i_y,
67 68 69 70 71 72 73 74 75 76 77
                                    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
78
static int      RenderSplash      ( vout_thread_t *p_vout );
79 80 81 82 83
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

87
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
88
 * vout_CreateThread: creates a new video output thread
89
 *****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
90 91 92
 * 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.
93
 * If not, it will be updated using one of the THREAD_* constants.
94
 *****************************************************************************/
Sam Hocevar's avatar
 
Sam Hocevar committed
95
vout_thread_t * vout_CreateThread   ( int *pi_status )
Michel Kaempf's avatar
Michel Kaempf committed
96
{
97 98 99
    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
100

101
    /* Allocate descriptor */
Michel Kaempf's avatar
Michel Kaempf committed
102
    p_vout = (vout_thread_t *) malloc( sizeof(vout_thread_t) );
103
    if( p_vout == NULL )
Michel Kaempf's avatar
Michel Kaempf committed
104
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
105 106
        intf_ErrMsg( "vout error: vout thread creation returned %s",
                     strerror(ENOMEM) );
Michel Kaempf's avatar
Michel Kaempf committed
107 108
        return( NULL );
    }
109

Sam Hocevar's avatar
 
Sam Hocevar committed
110 111 112
    /* Choose the best module */
    p_vout->p_module = module_Need( p_main->p_bank,
                                    MODULE_CAPABILITY_VOUT, NULL );
113

Sam Hocevar's avatar
 
Sam Hocevar committed
114
    if( p_vout->p_module == NULL )
Sam Hocevar's avatar
Sam Hocevar committed
115
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
116
        intf_ErrMsg( "vout error: no suitable vout module" );
Sam Hocevar's avatar
Sam Hocevar committed
117 118 119 120
        free( p_vout );
        return( NULL );
    }

Sam Hocevar's avatar
 
Sam Hocevar committed
121 122 123 124 125 126 127 128 129 130 131 132 133 134
#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

    if( p_vout->pf_setpalette == NULL )
    {
        p_vout->pf_setpalette = SetPalette;
    }
Sam Hocevar's avatar
Sam Hocevar committed
135

136
    /* Initialize thread properties - thread id and locks will be initialized
137
     * later */
138
    p_vout->b_die               = 0;
139
    p_vout->b_error             = 0;
140 141
    p_vout->b_active            = 0;
    p_vout->pi_status           = (pi_status != NULL) ? pi_status : &i_status;
142
    *p_vout->pi_status          = THREAD_CREATE;
143

144 145 146
    /* 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
147
    p_vout->i_changes             = 0;
Sam Hocevar's avatar
 
Sam Hocevar committed
148 149 150 151 152
    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;
Renaud Dartus's avatar
 
Renaud Dartus committed
153 154 155
    p_vout->i_screen_depth        = 15;
    p_vout->i_bytes_per_pixel     = 2;
    p_vout->f_gamma               = VOUT_GAMMA;
156
    p_vout->b_need_render         = 1;
Sam Hocevar's avatar
 
Sam Hocevar committed
157 158
    p_vout->b_YCbr                = 0;
    
Renaud Dartus's avatar
 
Renaud Dartus committed
159
    p_vout->b_grayscale           = main_GetIntVariable( VOUT_GRAYSCALE_VAR,
Sam Hocevar's avatar
 
Sam Hocevar committed
160
                                                     VOUT_GRAYSCALE_DEFAULT );
Renaud Dartus's avatar
 
Renaud Dartus committed
161 162 163
    p_vout->b_info                = 0;
    p_vout->b_interface           = 0;
    p_vout->b_scale               = 1;
164

Sam Hocevar's avatar
 
Sam Hocevar committed
165 166 167
    intf_WarnMsg( 1, "wished configuration: %dx%d, %d/%d bpp (%d Bpl)",
                  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 );
168

169
    /* Initialize idle screen */
170
    p_vout->last_display_date   = 0;
171
    p_vout->last_idle_date      = 0;
172
    p_vout->init_display_date   = mdate();
173
    p_vout->render_time         = 10000;
174

175
    /* Initialize statistics fields */
176
    p_vout->c_fps_samples       = 0;
177 178 179 180

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

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

195 196
    /* Create and initialize system-dependant method - this function issues its
     * own error messages */
Sam Hocevar's avatar
 
Sam Hocevar committed
197
    if( p_vout->pf_create( p_vout ) )
Michel Kaempf's avatar
Michel Kaempf committed
198
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
199
        module_Unneed( p_main->p_bank, p_vout->p_module );
200 201
        free( p_vout );
        return( NULL );
Michel Kaempf's avatar
Michel Kaempf committed
202
    }
Sam Hocevar's avatar
 
Sam Hocevar committed
203 204 205 206 207 208
    intf_WarnMsg( 1, "actual configuration: %dx%d, %d/%d bpp (%d Bpl), "
                  "masks: 0x%x/0x%x/0x%x",
                  p_vout->i_width, p_vout->i_height, p_vout->i_screen_depth,
                  p_vout->i_bytes_per_pixel * 8, p_vout->i_bytes_per_line,
                  p_vout->i_red_mask, p_vout->i_green_mask,
                  p_vout->i_blue_mask );
Vincent Seguin's avatar
Vincent Seguin committed
209 210

    /* Calculate shifts from system-updated masks */
211 212 213 214 215 216
    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
217

218
    /* Set some useful colors */
219
    p_vout->i_white_pixel = RGB2PIXEL( p_vout, 255, 255, 255 );
Vincent Seguin's avatar
Vincent Seguin committed
220 221
    p_vout->i_black_pixel = RGB2PIXEL( p_vout, 0, 0, 0 );
    p_vout->i_gray_pixel  = RGB2PIXEL( p_vout, 128, 128, 128 );
222
    p_vout->i_blue_pixel  = RGB2PIXEL( p_vout, 0, 0, 50 );
223

224 225
    /* Load fonts - fonts must be initialized after the system method since
     * they may be dependant on screen depth and other thread properties */
Sam Hocevar's avatar
 
Sam Hocevar committed
226
    p_vout->p_default_font = vout_LoadFont( VOUT_DEFAULT_FONT );
Vincent Seguin's avatar
Vincent Seguin committed
227 228
    if( p_vout->p_default_font == NULL )
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
229
        intf_ErrMsg( "vout error: could not load default font" );
Sam Hocevar's avatar
 
Sam Hocevar committed
230
        p_vout->pf_destroy( p_vout );
231 232 233
        free( p_vout );
        return( NULL );
    }
Sam Hocevar's avatar
 
Sam Hocevar committed
234 235

    p_vout->p_large_font = vout_LoadFont( VOUT_LARGE_FONT );
Vincent Seguin's avatar
Vincent Seguin committed
236 237
    if( p_vout->p_large_font == NULL )
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
238
        intf_ErrMsg( "vout error: could not load large font" );
239
        vout_UnloadFont( p_vout->p_default_font );
Sam Hocevar's avatar
 
Sam Hocevar committed
240
        p_vout->pf_destroy( p_vout );
241 242 243
        free( p_vout );
        return( NULL );
    }
Vincent Seguin's avatar
Vincent Seguin committed
244

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

250 251
    if( vlc_thread_create( &p_vout->thread_id, "video output",
                           (void *) RunThread, (void *) p_vout) )
Michel Kaempf's avatar
Michel Kaempf committed
252
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
253
        intf_ErrMsg("vout error: %s", strerror(ENOMEM));
Vincent Seguin's avatar
Vincent Seguin committed
254
        vout_UnloadFont( p_vout->p_default_font );
255
        vout_UnloadFont( p_vout->p_large_font );
Sam Hocevar's avatar
 
Sam Hocevar committed
256
        p_vout->pf_destroy( p_vout );
Michel Kaempf's avatar
Michel Kaempf committed
257 258
        free( p_vout );
        return( NULL );
259
    }
Michel Kaempf's avatar
Michel Kaempf committed
260

Sam Hocevar's avatar
 
Sam Hocevar committed
261 262
    intf_Msg( "vout: video display initialized (%dx%d, %d/%d bpp)",
              p_vout->i_width, p_vout->i_height, p_vout->i_screen_depth,
263
              p_vout->i_bytes_per_pixel * 8 );
264

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

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

    /* Set status */
Sam Hocevar's avatar
 
Sam Hocevar committed
294
    intf_DbgMsg("");
Michel Kaempf's avatar
Michel Kaempf committed
295
    p_vout->pi_status = (pi_status != NULL) ? pi_status : &i_status;
296 297
    *p_vout->pi_status = THREAD_DESTROY;

Michel Kaempf's avatar
Michel Kaempf committed
298 299 300 301
    /* Request thread destruction */
    p_vout->b_die = 1;

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

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

#ifdef DEBUG
    /* Check if status is valid */
328
    if( p_subpic->i_status != RESERVED_SUBPICTURE )
Vincent Seguin's avatar
Vincent Seguin committed
329
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
330
        intf_DbgMsg("error: subpicture %p has invalid status %d", p_subpic,
331 332
                    p_subpic->i_status );
    }
Vincent Seguin's avatar
Vincent Seguin committed
333 334 335
#endif

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

338
#ifdef DEBUG_VOUT
Sam Hocevar's avatar
Sam Hocevar committed
339
    /* Send subpicture information */
Sam Hocevar's avatar
 
Sam Hocevar committed
340
    intf_DbgMsg("subpicture %p: type=%d, begin date=%s, end date=%s",
341 342 343
                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
344 345 346
#endif
}

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

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

365 366
    /*
     * Look for an empty place
367
     */
368
    for( i_subpic = 0; i_subpic < VOUT_MAX_SUBPICTURES; i_subpic++ )
369
    {
370 371 372 373 374 375
        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
376 377 378 379
                /* 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 */
380
                p_vout->p_subpicture[i_subpic].i_status = RESERVED_SUBPICTURE;
381
#ifdef DEBUG_VOUT
Sam Hocevar's avatar
 
Sam Hocevar committed
382
                intf_DbgMsg("subpicture %p (in destroyed subpicture slot)",
383
                            &p_vout->p_subpicture[i_subpic] );
384
#endif
385 386 387 388 389 390 391 392 393 394
                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];
            }
        }
395
        else if( (p_free_subpic == NULL) &&
396 397
                 (p_vout->p_subpicture[i_subpic].i_status == FREE_SUBPICTURE ))
        {
398
            /* Subpicture is empty and ready for allocation */
399 400 401 402
            p_free_subpic = &p_vout->p_subpicture[i_subpic];
        }
    }

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

    /*
     * Prepare subpicture
     */
    if( p_free_subpic != NULL )
    {
        /* Allocate memory */
        switch( i_type )
        {
420 421
        case TEXT_SUBPICTURE:                             /* text subpicture */
            p_free_subpic->p_data = malloc( i_size + 1 );
422
            break;
423 424 425
        case DVD_SUBPICTURE:                          /* DVD subpicture unit */
            p_free_subpic->p_data = malloc( i_size );
            break;
426 427
#ifdef DEBUG
        default:
Sam Hocevar's avatar
 
Sam Hocevar committed
428
            intf_DbgMsg("error: unknown subpicture type %d", i_type );
429 430 431
            p_free_subpic->p_data   =  NULL;
            break;
#endif
432 433 434
        }

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

457
#ifdef DEBUG_VOUT
Sam Hocevar's avatar
 
Sam Hocevar committed
458
        intf_DbgMsg("subpicture %p (in free subpicture slot)", p_free_subpic );
459 460 461 462
#endif
        vlc_mutex_unlock( &p_vout->subpicture_lock );
        return( p_free_subpic );
    }
463

464
    /* No free or destroyed subpicture could be found */
Sam Hocevar's avatar
 
Sam Hocevar committed
465
    intf_DbgMsg( "warning: subpicture heap is full" );
466 467
    vlc_mutex_unlock( &p_vout->subpicture_lock );
    return( NULL );
Vincent Seguin's avatar
Vincent Seguin committed
468 469
}

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

489
    p_subpic->i_status = DESTROYED_SUBPICTURE;
Vincent Seguin's avatar
Vincent Seguin committed
490

491
#ifdef DEBUG_VOUT
Sam Hocevar's avatar
 
Sam Hocevar committed
492
    intf_DbgMsg("subpicture %p", p_subpic);
Vincent Seguin's avatar
Vincent Seguin committed
493 494 495
#endif
}

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

521
#ifdef DEBUG_VOUT
Sam Hocevar's avatar
 
Sam Hocevar committed
522
    intf_DbgMsg("picture %p", p_pic);
523
#endif
524
    vlc_mutex_unlock( &p_vout->picture_lock );
Michel Kaempf's avatar
Michel Kaempf committed
525 526
}

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

540
    vlc_mutex_lock( &p_vout->picture_lock );
541
    p_pic->date = date;
542 543
    switch( p_pic->i_status )
    {
544
    case RESERVED_PICTURE:
545
        p_pic->i_status = RESERVED_DATED_PICTURE;
546
        break;
547 548
    case RESERVED_DISP_PICTURE:
        p_pic->i_status = READY_PICTURE;
549
        break;
550
#ifdef DEBUG
551
    default:
Sam Hocevar's avatar
 
Sam Hocevar committed
552
        intf_DbgMsg("error: picture %p has invalid status %d", p_pic, p_pic->i_status );
553
        break;
554 555 556
#endif
    }

557
#ifdef DEBUG_VOUT
Sam Hocevar's avatar
 
Sam Hocevar committed
558
    intf_DbgMsg("picture %p, display date: %s", p_pic, mstrtime( psz_date, p_pic->date) );
559
#endif
560
    vlc_mutex_unlock( &p_vout->picture_lock );
561 562
}

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

Vincent Seguin's avatar
Vincent Seguin committed
579
    /* Get lock */
Vincent Seguin's avatar
Vincent Seguin committed
580
    vlc_mutex_lock( &p_vout->picture_lock );
Michel Kaempf's avatar
Michel Kaempf committed
581

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

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

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

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

699
#ifdef DEBUG_VOUT
Sam Hocevar's avatar
 
Sam Hocevar committed
700
        intf_DbgMsg("picture %p (in free picture slot)", p_free_picture );
701
#endif
Vincent Seguin's avatar
Vincent Seguin committed
702
        vlc_mutex_unlock( &p_vout->picture_lock );
Henri Fallon's avatar
 
Henri Fallon committed
703 704 705 706

        /* Initialize mutex */
        vlc_mutex_init( &(p_free_picture->lock_deccount) );
        
Vincent Seguin's avatar
Vincent Seguin committed
707
        return( p_free_picture );
Michel Kaempf's avatar
Michel Kaempf committed
708
    }
709

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

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

727
#ifdef DEBUG
Henri Fallon's avatar
 
Henri Fallon committed
728 729 730 731 732 733 734
    /* 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) )
    {
        intf_DbgMsg("error: picture %p has invalid status %d", p_pic, p_pic->i_status );
    }
735 736
#endif

Henri Fallon's avatar
 
Henri Fallon committed
737 738
    p_pic->i_status = DESTROYED_PICTURE;
    p_vout->i_pictures--;
739

740
#ifdef DEBUG_VOUT
Henri Fallon's avatar
 
Henri Fallon committed
741
    intf_DbgMsg("picture %p", p_pic);
742
#endif
Henri Fallon's avatar
 
Henri Fallon committed
743

Henri Fallon's avatar
 
Henri Fallon committed
744 745
    /* destroy the lock that had been initialized in CreatePicture */
    vlc_mutex_destroy( &(p_pic->lock_deccount) );
Henri Fallon's avatar
 
Henri Fallon committed
746
   
Henri Fallon's avatar
 
Henri Fallon committed
747
    vlc_mutex_unlock( &p_vout->picture_lock );
Michel Kaempf's avatar
Michel Kaempf committed
748 749
}

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

761
#ifdef DEBUG_VOUT
Sam Hocevar's avatar
 
Sam Hocevar committed
762
    intf_DbgMsg("picture %p refcount=%d", p_pic, p_pic->i_refcount );
763
#endif
764 765

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

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

778
#ifdef DEBUG_VOUT
779 780
    if( p_pic->i_refcount < 0 )
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
781
        intf_DbgMsg("error: refcount < 0");
782 783
        p_pic->i_refcount = 0;
    }
784 785
#endif

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

792
#ifdef DEBUG_VOUT
Sam Hocevar's avatar
 
Sam Hocevar committed
793
    intf_DbgMsg("picture %p refcount=%d", p_pic