video_output.c 85.6 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.126 2001/05/07 04:42:42 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 70 71 72 73 74 75 76 77 78
                                    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
79
static int      RenderSplash      ( vout_thread_t *p_vout );
80 81 82 83 84
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 );
85 86
static void     SetPalette        ( p_vout_thread_t p_vout, u16 *red,
                                    u16 *green, u16 *blue, u16 *transp );
Michel Kaempf's avatar
Michel Kaempf committed
87

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

    vlc_mutex_destroy( &p_vout_bank->lock );
}

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

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

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

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

Sam Hocevar's avatar
 
Sam Hocevar committed
149 150 151 152 153 154 155 156 157 158 159 160 161 162
#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
163

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

172 173 174
    /* 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
175
    p_vout->i_changes             = 0;
Sam Hocevar's avatar
 
Sam Hocevar committed
176 177 178 179 180
    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;
181 182
    p_vout->i_screen_depth        = main_GetIntVariable( VOUT_DEPTH_VAR,
                                                         VOUT_DEPTH_DEFAULT );
Renaud Dartus's avatar
 
Renaud Dartus committed
183
    p_vout->i_bytes_per_pixel     = 2;
184 185
    p_vout->f_gamma               = VOUT_GAMMA_DEFAULT; // FIXME: replace with 
                                                        // variable
186
    p_vout->b_need_render         = 1;
Sam Hocevar's avatar
 
Sam Hocevar committed
187 188
    p_vout->b_YCbr                = 0;
    
Renaud Dartus's avatar
 
Renaud Dartus committed
189
    p_vout->b_grayscale           = main_GetIntVariable( VOUT_GRAYSCALE_VAR,
Sam Hocevar's avatar
 
Sam Hocevar committed
190
                                                     VOUT_GRAYSCALE_DEFAULT );
Renaud Dartus's avatar
 
Renaud Dartus committed
191 192 193
    p_vout->b_info                = 0;
    p_vout->b_interface           = 0;
    p_vout->b_scale               = 1;
194 195
    p_vout->b_fullscreen          = main_GetIntVariable( VOUT_FULLSCREEN_VAR,
                                                     VOUT_FULLSCREEN_DEFAULT );
196

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

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

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

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

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

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

227
    p_vout->i_pictures = 0;
228

229 230
    /* Create and initialize system-dependant method - this function issues its
     * own error messages */
Sam Hocevar's avatar
 
Sam Hocevar committed
231
    if( p_vout->pf_create( p_vout ) )
Michel Kaempf's avatar
Michel Kaempf committed
232
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
233
        module_Unneed( p_vout->p_module );
234 235
        free( p_vout );
        return( NULL );
Michel Kaempf's avatar
Michel Kaempf committed
236
    }
Sam Hocevar's avatar
 
Sam Hocevar committed
237

238
    intf_WarnMsg( 3, "actual configuration: %dx%d, %d/%d bpp (%d Bpl), "
Sam Hocevar's avatar
 
Sam Hocevar committed
239 240 241 242 243
                  "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
244 245

    /* Calculate shifts from system-updated masks */
246 247 248 249 250 251
    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
252

253
    /* Set some useful colors */
254
    p_vout->i_white_pixel = RGB2PIXEL( p_vout, 255, 255, 255 );
Vincent Seguin's avatar
Vincent Seguin committed
255 256
    p_vout->i_black_pixel = RGB2PIXEL( p_vout, 0, 0, 0 );
    p_vout->i_gray_pixel  = RGB2PIXEL( p_vout, 128, 128, 128 );
257
    p_vout->i_blue_pixel  = RGB2PIXEL( p_vout, 0, 0, 50 );
258

259 260
    /* 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
261
    p_vout->p_default_font = vout_LoadFont( VOUT_DEFAULT_FONT );
Vincent Seguin's avatar
Vincent Seguin committed
262 263
    if( p_vout->p_default_font == NULL )
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
264
        intf_ErrMsg( "vout error: could not load default font" );
265
    }
Sam Hocevar's avatar
 
Sam Hocevar committed
266 267

    p_vout->p_large_font = vout_LoadFont( VOUT_LARGE_FONT );
Vincent Seguin's avatar
Vincent Seguin committed
268 269
    if( p_vout->p_large_font == NULL )
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
270
        intf_ErrMsg( "vout error: could not load large font" );
271
    }
Vincent Seguin's avatar
Vincent Seguin committed
272

Michel Kaempf's avatar
Michel Kaempf committed
273
    /* Create thread and set locks */
Vincent Seguin's avatar
Vincent Seguin committed
274
    vlc_mutex_init( &p_vout->picture_lock );
275 276
    vlc_mutex_init( &p_vout->subpicture_lock );
    vlc_mutex_init( &p_vout->change_lock );
277

278 279
    if( vlc_thread_create( &p_vout->thread_id, "video output",
                           (void *) RunThread, (void *) p_vout) )
Michel Kaempf's avatar
Michel Kaempf committed
280
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
281
        intf_ErrMsg("vout error: %s", strerror(ENOMEM));
Vincent Seguin's avatar
Vincent Seguin committed
282
        vout_UnloadFont( p_vout->p_default_font );
283
        vout_UnloadFont( p_vout->p_large_font );
Sam Hocevar's avatar
 
Sam Hocevar committed
284
        p_vout->pf_destroy( p_vout );
Michel Kaempf's avatar
Michel Kaempf committed
285 286
        free( p_vout );
        return( NULL );
287
    }
Michel Kaempf's avatar
Michel Kaempf committed
288

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

Michel Kaempf's avatar
Michel Kaempf committed
293 294 295 296
    /* If status is NULL, wait until the thread is created */
    if( pi_status == NULL )
    {
        do
297
        {
Michel Kaempf's avatar
Michel Kaempf committed
298
            msleep( THREAD_SLEEP );
299
        }while( (i_status != THREAD_READY) && (i_status != THREAD_ERROR)
Michel Kaempf's avatar
Michel Kaempf committed
300 301 302
                && (i_status != THREAD_FATAL) );
        if( i_status != THREAD_READY )
        {
303 304
            return( NULL );
        }
Michel Kaempf's avatar
Michel Kaempf committed
305 306 307 308
    }
    return( p_vout );
}

309
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
310
 * vout_DestroyThread: destroys a previously created thread
311 312
 *****************************************************************************
 * Destroy a terminated thread.
Michel Kaempf's avatar
Michel Kaempf committed
313
 * The function will request a destruction of the specified thread. If pi_error
314
 * is NULL, it will return once the thread is destroyed. Else, it will be
Michel Kaempf's avatar
Michel Kaempf committed
315
 * update using one of the THREAD_* constants.
316
 *****************************************************************************/
Michel Kaempf's avatar
Michel Kaempf committed
317
void vout_DestroyThread( vout_thread_t *p_vout, int *pi_status )
318 319
{
    int     i_status;                                       /* thread status */
Michel Kaempf's avatar
Michel Kaempf committed
320 321

    /* Set status */
Sam Hocevar's avatar
 
Sam Hocevar committed
322
    intf_DbgMsg("");
Michel Kaempf's avatar
Michel Kaempf committed
323
    p_vout->pi_status = (pi_status != NULL) ? pi_status : &i_status;
324 325
    *p_vout->pi_status = THREAD_DESTROY;

Michel Kaempf's avatar
Michel Kaempf committed
326 327 328 329
    /* Request thread destruction */
    p_vout->b_die = 1;

    /* If status is NULL, wait until thread has been destroyed */
330
    if( pi_status == NULL )
Michel Kaempf's avatar
Michel Kaempf committed
331 332 333 334
    {
        do
        {
            msleep( THREAD_SLEEP );
335 336
        }while( (i_status != THREAD_OVER) && (i_status != THREAD_ERROR)
                && (i_status != THREAD_FATAL) );
Michel Kaempf's avatar
Michel Kaempf committed
337 338 339
    }
}

340
/*****************************************************************************
341
 * vout_DisplaySubPicture: display a subpicture unit
342
 *****************************************************************************
Sam Hocevar's avatar
 
Sam Hocevar committed
343
 * Remove the reservation flag of a subpicture, which will cause it to be ready
344
 * for display. The picture does not need to be locked, since it is ignored by
Vincent Seguin's avatar
Vincent Seguin committed
345
 * the output thread if is reserved.
346
 *****************************************************************************/
347
void  vout_DisplaySubPicture( vout_thread_t *p_vout, subpicture_t *p_subpic )
Vincent Seguin's avatar
Vincent Seguin committed
348
{
349
#ifdef TRACE_VOUT
Sam Hocevar's avatar
 
Sam Hocevar committed
350 351
    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
352 353 354 355
#endif

#ifdef DEBUG
    /* Check if status is valid */
356
    if( p_subpic->i_status != RESERVED_SUBPICTURE )
Vincent Seguin's avatar
Vincent Seguin committed
357
    {
358
        intf_ErrMsg("error: subpicture %p has invalid status %d", p_subpic,
359 360
                    p_subpic->i_status );
    }
Vincent Seguin's avatar
Vincent Seguin committed
361 362 363
#endif

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

366
#ifdef TRACE_VOUT
Sam Hocevar's avatar
Sam Hocevar committed
367
    /* Send subpicture information */
Sam Hocevar's avatar
 
Sam Hocevar committed
368
    intf_DbgMsg("subpicture %p: type=%d, begin date=%s, end date=%s",
369
                p_subpic, p_subpic->i_type,
Sam Hocevar's avatar
 
Sam Hocevar committed
370 371
                mstrtime( psz_start, p_subpic->i_start ),
                mstrtime( psz_stop, p_subpic->i_stop ) );
Vincent Seguin's avatar
Vincent Seguin committed
372 373 374
#endif
}

375
/*****************************************************************************
Sam Hocevar's avatar
Sam Hocevar committed
376
 * vout_CreateSubPicture: allocate a subpicture in the video output heap.
377 378
 *****************************************************************************
 * This function create a reserved subpicture in the video output heap.
Vincent Seguin's avatar
Vincent Seguin committed
379
 * A null pointer is returned if the function fails. This method provides an
380
 * already allocated zone of memory in the spu data fields. It needs locking
381 382 383
 * since several pictures can be created by several producers threads.
 *****************************************************************************/
subpicture_t *vout_CreateSubPicture( vout_thread_t *p_vout, int i_type,
384
                                     int i_size )
Vincent Seguin's avatar
Vincent Seguin committed
385
{
386 387 388
    int                 i_subpic;                        /* subpicture index */
    subpicture_t *      p_free_subpic = NULL;       /* first free subpicture */
    subpicture_t *      p_destroyed_subpic = NULL; /* first destroyed subpic */
389 390 391 392

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

393 394
    /*
     * Look for an empty place
395
     */
396
    for( i_subpic = 0; i_subpic < VOUT_MAX_SUBPICTURES; i_subpic++ )
397
    {
398 399 400 401 402 403
        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
404 405 406 407
                /* 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 */
408
                p_vout->p_subpicture[i_subpic].i_status = RESERVED_SUBPICTURE;
409
#ifdef TRACE_VOUT
Sam Hocevar's avatar
 
Sam Hocevar committed
410
                intf_DbgMsg("subpicture %p (in destroyed subpicture slot)",
411
                            &p_vout->p_subpicture[i_subpic] );
412
#endif
413 414 415 416 417 418 419 420 421 422
                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];
            }
        }
423
        else if( (p_free_subpic == NULL) &&
424 425
                 (p_vout->p_subpicture[i_subpic].i_status == FREE_SUBPICTURE ))
        {
426
            /* Subpicture is empty and ready for allocation */
427 428 429 430
            p_free_subpic = &p_vout->p_subpicture[i_subpic];
        }
    }

Sam Hocevar's avatar
Sam Hocevar committed
431
    /* If no free subpictures are available, use a destroyed subpicture */
432
    if( (p_free_subpic == NULL) && (p_destroyed_subpic != NULL ) )
433
    {
Sam Hocevar's avatar
Sam Hocevar committed
434
        /* No free subpicture or matching destroyed subpictures have been
Sam Hocevar's avatar
NEWS:  
Sam Hocevar committed
435
         * found, but a destroyed subpicture is still avalaible */
436
        free( p_destroyed_subpic->p_data );
437 438 439 440 441 442 443 444 445 446 447
        p_free_subpic = p_destroyed_subpic;
    }

    /*
     * Prepare subpicture
     */
    if( p_free_subpic != NULL )
    {
        /* Allocate memory */
        switch( i_type )
        {
448 449
        case TEXT_SUBPICTURE:                             /* text subpicture */
            p_free_subpic->p_data = malloc( i_size + 1 );
450
            break;
451 452 453
        case DVD_SUBPICTURE:                          /* DVD subpicture unit */
            p_free_subpic->p_data = malloc( i_size );
            break;
454 455
#ifdef DEBUG
        default:
456
            intf_ErrMsg("error: unknown subpicture type %d", i_type );
457 458 459
            p_free_subpic->p_data   =  NULL;
            break;
#endif
460 461 462
        }

        if( p_free_subpic->p_data != NULL )
Sam Hocevar's avatar
Sam Hocevar committed
463 464
        {
            /* Copy subpicture information, set some default values */
465 466
            p_free_subpic->i_type                      = i_type;
            p_free_subpic->i_status                    = RESERVED_SUBPICTURE;
467
            p_free_subpic->i_size                      = i_size;
468
            p_free_subpic->i_x                         = 0;
469
            p_free_subpic->i_y                         = 0;
470 471
            p_free_subpic->i_width                     = 0;
            p_free_subpic->i_height                    = 0;
472 473
            p_free_subpic->i_horizontal_align          = CENTER_RALIGN;
            p_free_subpic->i_vertical_align            = CENTER_RALIGN;
474 475 476 477
        }
        else
        {
            /* Memory allocation failed : set subpicture as empty */
478 479 480
            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
481 482
            intf_ErrMsg( "vout error: spu allocation returned %s",
                         strerror( ENOMEM ) );
483
        }
484

485
#ifdef TRACE_VOUT
Sam Hocevar's avatar
 
Sam Hocevar committed
486
        intf_DbgMsg("subpicture %p (in free subpicture slot)", p_free_subpic );
487 488 489 490
#endif
        vlc_mutex_unlock( &p_vout->subpicture_lock );
        return( p_free_subpic );
    }
491

492
    /* No free or destroyed subpicture could be found */
Sam Hocevar's avatar
 
Sam Hocevar committed
493
    intf_DbgMsg( "warning: subpicture heap is full" );
494 495
    vlc_mutex_unlock( &p_vout->subpicture_lock );
    return( NULL );
Vincent Seguin's avatar
Vincent Seguin committed
496 497
}

498
/*****************************************************************************
499
 * vout_DestroySubPicture: remove a subpicture from the heap
500
 *****************************************************************************
501
 * This function frees a previously reserved subpicture.
Vincent Seguin's avatar
Vincent Seguin committed
502
 * It is meant to be used when the construction of a picture aborted.
503
 * This function does not need locking since reserved subpictures are ignored
504
 * by the output thread.
505
 *****************************************************************************/
506
void vout_DestroySubPicture( vout_thread_t *p_vout, subpicture_t *p_subpic )
Vincent Seguin's avatar
Vincent Seguin committed
507 508
{
#ifdef DEBUG
509 510
   /* Check if status is valid */
   if( p_subpic->i_status != RESERVED_SUBPICTURE )
Vincent Seguin's avatar
Vincent Seguin committed
511
   {
512
       intf_ErrMsg("error: subpicture %p has invalid status %d",
513 514
                   p_subpic, p_subpic->i_status );
   }
Vincent Seguin's avatar
Vincent Seguin committed
515 516
#endif

517
    p_subpic->i_status = DESTROYED_SUBPICTURE;
Vincent Seguin's avatar
Vincent Seguin committed
518

519
#ifdef TRACE_VOUT
Sam Hocevar's avatar
 
Sam Hocevar committed
520
    intf_DbgMsg("subpicture %p", p_subpic);
Vincent Seguin's avatar
Vincent Seguin committed
521 522 523
#endif
}

524
/*****************************************************************************
Vincent Seguin's avatar
Vincent Seguin committed
525
 * vout_DisplayPicture: display a picture
526
 *****************************************************************************
Vincent Seguin's avatar
Vincent Seguin committed
527
 * Remove the reservation flag of a picture, which will cause it to be ready for
528
 * display. The picture won't be displayed until vout_DatePicture has been
529
 * called.
530
 *****************************************************************************/
Vincent Seguin's avatar
Vincent Seguin committed
531
void  vout_DisplayPicture( vout_thread_t *p_vout, picture_t *p_pic )
Michel Kaempf's avatar
Michel Kaempf committed
532
{
533 534
    vlc_mutex_lock( &p_vout->picture_lock );
    switch( p_pic->i_status )
535
    {
536
    case RESERVED_PICTURE:
537
        p_pic->i_status = RESERVED_DISP_PICTURE;
538
        break;
539 540
    case RESERVED_DATED_PICTURE:
        p_pic->i_status = READY_PICTURE;
541
        break;
542
#ifdef DEBUG
543
    default:
544
        intf_ErrMsg("error: picture %p has invalid status %d", p_pic, p_pic->i_status );
545
        break;
546
#endif
547
    }
Michel Kaempf's avatar
Michel Kaempf committed
548

549
#ifdef TRACE_VOUT
Sam Hocevar's avatar
 
Sam Hocevar committed
550
    intf_DbgMsg("picture %p", p_pic);
551
#endif
552
    vlc_mutex_unlock( &p_vout->picture_lock );
Michel Kaempf's avatar
Michel Kaempf committed
553 554
}

555
/*****************************************************************************
556
 * vout_DatePicture: date a picture
557
 *****************************************************************************
558
 * Remove the reservation flag of a picture, which will cause it to be ready for
559
 * display. The picture won't be displayed until vout_DisplayPicture has been
560
 * called.
561
 *****************************************************************************/
562 563
void  vout_DatePicture( vout_thread_t *p_vout, picture_t *p_pic, mtime_t date )
{
564
#ifdef TRACE_VOUT
565
    char        psz_date[MSTRTIME_MAX_SIZE];                         /* date */
Vincent Seguin's avatar
Vincent Seguin committed
566 567
#endif

568
    vlc_mutex_lock( &p_vout->picture_lock );
569
    p_pic->date = date;
570 571
    switch( p_pic->i_status )
    {
572
    case RESERVED_PICTURE:
573
        p_pic->i_status = RESERVED_DATED_PICTURE;
574
        break;
575 576
    case RESERVED_DISP_PICTURE:
        p_pic->i_status = READY_PICTURE;
577
        break;
578
#ifdef DEBUG
579
    default:
580
        intf_ErrMsg("error: picture %p has invalid status %d", p_pic, p_pic->i_status );
581
        break;
582 583 584
#endif
    }

585
#ifdef TRACE_VOUT
Sam Hocevar's avatar
 
Sam Hocevar committed
586
    intf_DbgMsg("picture %p, display date: %s", p_pic, mstrtime( psz_date, p_pic->date) );
587
#endif
588
    vlc_mutex_unlock( &p_vout->picture_lock );
589 590
}

591
/*****************************************************************************
Vincent Seguin's avatar
Vincent Seguin committed
592
 * vout_CreatePicture: allocate a picture in the video output heap.
593 594
 *****************************************************************************
 * This function create a reserved image in the video output heap.
Vincent Seguin's avatar
Vincent Seguin committed
595
 * A null pointer is returned if the function fails. This method provides an
596
 * already allocated zone of memory in the picture data fields. It needs locking
597 598 599
 * since several pictures can be created by several producers threads.
 *****************************************************************************/
picture_t *vout_CreatePicture( vout_thread_t *p_vout, int i_type,
600
                               int i_width, int i_height )
Michel Kaempf's avatar
Michel Kaempf committed
601
{
602 603 604 605
    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
606

Vincent Seguin's avatar
Vincent Seguin committed
607
    /* Get lock */
Vincent Seguin's avatar
Vincent Seguin committed
608
    vlc_mutex_lock( &p_vout->picture_lock );
Michel Kaempf's avatar
Michel Kaempf committed
609

610 611
    /*
     * Look for an empty place
Vincent Seguin's avatar
Vincent Seguin committed
612
     */
613
    for( i_picture = 0; i_picture < VOUT_MAX_PICTURES; i_picture++ )
Vincent Seguin's avatar
Vincent Seguin committed
614
    {
615 616 617
        if( p_vout->p_picture[i_picture].i_status == DESTROYED_PICTURE )
        {
            /* Picture is marked for destruction, but is still allocated - note
618
             * that if width and type are the same for two pictures, chroma_width
619
             * should also be the same */
620 621 622 623 624
            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
625 626
                 * can end immediately - this is the best possible case, since no
                 * memory allocation needs to be done */
627
                p_vout->p_picture[i_picture].i_status = RESERVED_PICTURE;
628
                p_vout->i_pictures++;
629
#ifdef TRACE_VOUT
Sam Hocevar's avatar
 
Sam Hocevar committed
630
                intf_DbgMsg("picture %p (in destroyed picture slot)",
631
                            &p_vout->p_picture[i_picture] );
632
#endif
633 634 635 636 637 638 639 640 641 642
                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];
            }
        }
643
        else if( (p_free_picture == NULL) &&
Vincent Seguin's avatar
Vincent Seguin committed
644 645
                 (p_vout->p_picture[i_picture].i_status == FREE_PICTURE ))
        {
646
            /* Picture is empty and ready for allocation */
647
            p_free_picture = &p_vout->p_picture[i_picture];
Vincent Seguin's avatar
Vincent Seguin committed
648
        }
Michel Kaempf's avatar
Michel Kaempf committed
649 650
    }

Vincent Seguin's avatar
Vincent Seguin committed
651 652
    /* If no free picture is available, use a destroyed picture */
    if( (p_free_picture == NULL) && (p_destroyed_picture != NULL ) )
653
    {
654 655
        /* No free picture or matching destroyed picture has been found, but
         * a destroyed picture is still avalaible */
656 657
        free( p_destroyed_picture->p_data );
        p_free_picture = p_destroyed_picture;
Michel Kaempf's avatar
Michel Kaempf committed
658 659
    }

Vincent Seguin's avatar
Vincent Seguin committed
660 661 662 663 664 665 666
    /*
     * Prepare picture
     */
    if( p_free_picture != NULL )
    {
        /* Allocate memory */
        switch( i_type )
Michel Kaempf's avatar
Michel Kaempf committed
667
        {
668 669
        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
670
            p_free_picture->p_data = malloc( i_height * i_chroma_width * 3 * sizeof( yuv_data_t ) );
671
            p_free_picture->p_y = (yuv_data_t *)p_free_picture->p_data;
Vincent Seguin's avatar
Vincent Seguin committed
672 673
            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;
674
            break;
675 676
        case YUV_422_PICTURE:        /* YUV 422: 1,1/2,1/2 samples per pixel */
            i_chroma_width = i_width / 2;
677 678
            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
679 680
            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;
681
            break;
682 683
        case YUV_444_PICTURE:            /* YUV 444: 1,1,1 samples per pixel */
            i_chroma_width = i_width;
684 685
            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
686 687
            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;
688
            break;
Vincent Seguin's avatar
Vincent Seguin committed
689 690
#ifdef DEBUG
        default:
691
            intf_ErrMsg("error: unknown picture type %d", i_type );
692 693 694
            p_free_picture->p_data   =  NULL;
            break;
#endif
Michel Kaempf's avatar
Michel Kaempf committed
695 696
        }

Vincent Seguin's avatar
Vincent Seguin committed
697
        if( p_free_picture->p_data != NULL )
698
        {
Sam Hocevar's avatar
Sam Hocevar committed
699
            /* Copy picture information, set some default values */
700 701
            p_free_picture->i_type                      = i_type;
            p_free_picture->i_status                    = RESERVED_PICTURE;
702
            p_free_picture->i_matrix_coefficients       = 1;
703 704
            p_free_picture->i_width                     = i_width;
            p_free_picture->i_height                    = i_height;
705
            p_free_picture->i_chroma_width              = i_chroma_width;
706 707 708
            p_free_picture->i_size                      = i_width * i_height;
            p_free_picture->i_chroma_size               = i_chroma_width
                                                            * i_height;
709
            p_free_picture->i_display_horizontal_offset = 0;
710
            p_free_picture->i_display_vertical_offset   = 0;
711 712
            p_free_picture->i_display_width             = i_width;
            p_free_picture->i_display_height            = i_height;
713 714
            p_free_picture->i_aspect_ratio              = AR_SQUARE_PICTURE;
            p_free_picture->i_refcount                  = 0;
715
            p_vout->i_pictures++;
Vincent Seguin's avatar
Vincent Seguin committed
716 717 718 719
        }
        else
        {
            /* Memory allocation failed : set picture as empty */
720 721 722
            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
723 724
            intf_ErrMsg( "vout error: picture allocation returned %s",
                         strerror( ENOMEM ) );
Vincent Seguin's avatar
Vincent Seguin committed
725
        }
726

727
#ifdef TRACE_VOUT
Sam Hocevar's avatar
 
Sam Hocevar committed
728
        intf_DbgMsg("picture %p (in free picture slot)", p_free_picture );
729
#endif
Vincent Seguin's avatar
Vincent Seguin committed
730
        vlc_mutex_unlock( &p_vout->picture_lock );
Henri Fallon's avatar
 
Henri Fallon committed
731 732 733 734

        /* Initialize mutex */
        vlc_mutex_init( &(p_free_picture->lock_deccount) );
        
Vincent Seguin's avatar
Vincent Seguin committed
735
        return( p_free_picture );
Michel Kaempf's avatar
Michel Kaempf committed
736
    }
737

738
    /* No free or destroyed picture could be found */
Sam Hocevar's avatar
 
Sam Hocevar committed
739
    intf_DbgMsg( "warning: picture heap is full" );
Vincent Seguin's avatar
Vincent Seguin committed
740
    vlc_mutex_unlock( &p_vout->picture_lock );
Vincent Seguin's avatar
Vincent Seguin committed
741
    return( NULL );
Michel Kaempf's avatar
Michel Kaempf committed
742 743
}

744
/*****************************************************************************
745
 * vout_DestroyPicture: remove a permanent or reserved picture from the heap
746
 *****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
747
 * This function frees a previously reserved picture or a permanent
Vincent Seguin's avatar
Vincent Seguin committed
748 749
 * 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 !
750
 *****************************************************************************/
Vincent Seguin's avatar
Vincent Seguin committed
751
void vout_DestroyPicture( vout_thread_t *p_vout, picture_t *p_pic )
Michel Kaempf's avatar
Michel Kaempf committed
752
{
Henri Fallon's avatar
 
Henri Fallon committed
753
    vlc_mutex_lock( &p_vout->picture_lock );
754

755
#ifdef DEBUG
Henri Fallon's avatar
 
Henri Fallon committed
756 757 758 759 760
    /* 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) )
    {
761
        intf_ErrMsg("error: picture %p has invalid status %d", p_pic, p_pic->i_status );
Henri Fallon's avatar
 
Henri Fallon committed
762
    }
763 764
#endif

Henri Fallon's avatar
 
Henri Fallon committed
765 766
    p_pic->i_status = DESTROYED_PICTURE;
    p_vout->i_pictures--;
767

768
#ifdef TRACE_VOUT
Henri Fallon's avatar
 
Henri Fallon committed
769
    intf_DbgMsg("picture %p", p_pic);
770
#endif
Henri Fallon's avatar
 
Henri Fallon committed
771

Henri Fallon's avatar
 
Henri Fallon committed
772 773
    /* destroy the lock that had been initialized in CreatePicture */
    vlc_mutex_destroy( &(p_pic->lock_deccount) );
Henri Fallon's avatar
 
Henri Fallon committed
774
   
Henri Fallon's avatar
 
Henri Fallon committed
775
    vlc_mutex_unlock( &p_vout->picture_lock );
Michel Kaempf's avatar
Michel Kaempf committed
776 777
}

778
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
779
 * vout_LinkPicture: increment reference counter of a picture
780
 *****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
781
 * This function increment the reference counter of a picture in the video
782
 * heap. It needs a lock since several producer threads can access the picture.
783
 *****************************************************************************/
Michel Kaempf's avatar
Michel Kaempf committed
784 785
void vout_LinkPicture( vout_thread_t *p_vout, picture_t *p_pic )
{
Vincent Seguin's avatar
Vincent Seguin committed
786
    vlc_mutex_lock( &p_vout->picture_lock );
Michel Kaempf's avatar
Michel Kaempf committed
787
    p_pic->i_refcount++;
788

789
#ifdef TRACE_VOUT
Sam Hocevar's avatar
 
Sam Hocevar committed
790
    intf_DbgMsg("picture %p refcount=%d", p_pic, p_pic->i_refcount );
791
#endif
792 793

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

796
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
797
 * vout_UnlinkPicture: decrement reference counter of a picture
798
 *****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
799
 * This function decrement the reference counter of a picture in the video heap.