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
    {
Benoit Steiner's avatar
Benoit Steiner committed
107
        intf_ErrMsg( "vout 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
    {
Benoit Steiner's avatar
Benoit Steiner committed
264
        intf_ErrMsg("vout 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
793 794

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

797
/*****************************************************************************
798
 * vout_SetBuffers: set buffers adresses
799 800
 *****************************************************************************
 * This function is called by system drivers to set buffers video memory
801
 * adresses.
802
 *****************************************************************************/
803
void vout_SetBuffers( vout_thread_t *p_vout, void *p_buf1, void *p_buf2 )
804 805
{
    /* No picture previously */
806 807 808 809 810 811 812 813
    p_vout->p_buffer[0].i_pic_x =         0;
    p_vout->p_buffer[0].i_pic_y =         0;
    p_vout->p_buffer[0].i_pic_width =     0;
    p_vout->p_buffer[0].i_pic_height =    0;
    p_vout->p_buffer[1].i_pic_x =         0;
    p_vout->p_buffer[1].i_pic_y =         0;
    p_vout->p_buffer[1].i_pic_width =     0;
    p_vout->p_buffer[1].i_pic_height =    0;
814 815

    /* The first area covers all the screen */
816 817 818 819 820 821 822 823
    p_vout->p_buffer[0].i_areas =                 1;
    p_vout->p_buffer[0].pi_area_begin[0] =        0;
    p_vout->p_buffer[0].pi_area_end[0] =          p_vout->i_height - 1;
    p_vout->p_buffer[1].i_areas =                 1;
    p_vout->p_buffer[1].pi_area_begin[0] =        0;
    p_vout->p_buffer[1].pi_area_end[0] =          p_vout->i_height - 1;

    /* Set adresses */
824 825
    p_vout->p_buffer[0].p_data = p_buf1;
    p_vout->p_buffer[1].p_data = p_buf2;
826 827
}

Vincent Seguin's avatar
Vincent Seguin committed
828 829 830 831 832 833 834 835 836 837 838 839 840
/*****************************************************************************
 * vout_Pixel2RGB: return red, green and blue from pixel value
 *****************************************************************************
 * Return color values, in 0-255 range, of the decomposition of a pixel. This
 * is a slow routine and should only be used for initialization phase.
 *****************************************************************************/
void vout_Pixel2RGB( vout_thread_t *p_vout, u32 i_pixel, int *pi_red, int *pi_green, int *pi_blue )
{
    *pi_red =   i_pixel & p_vout->i_red_mask;
    *pi_green = i_pixel & p_vout->i_green_mask;
    *pi_blue =  i_pixel & p_vout->i_blue_mask;
}

Michel Kaempf's avatar
Michel Kaempf committed
841 842
/* following functions are local */

Vincent Seguin's avatar
Vincent Seguin committed
843 844 845
/*****************************************************************************
 * BinaryLog: computes the base 2 log of a binary value
 *****************************************************************************
846
 * This functions is used by MaskToShift, to get a bit index from a binary
Vincent Seguin's avatar
Vincent Seguin committed
847 848 849 850 851 852 853
 * value.
 *****************************************************************************/
static int BinaryLog(u32 i)
{
    int i_log;

    i_log = 0;
854 855
    if (i & 0xffff0000)
    {
Vincent Seguin's avatar
Vincent Seguin committed
856
        i_log = 16;
857 858 859
    }
    if (i & 0xff00ff00)
    {
Vincent Seguin's avatar
Vincent Seguin committed
860
        i_log += 8;
861 862 863
    }
    if (i & 0xf0f0f0f0)
    {
Vincent Seguin's avatar
Vincent Seguin committed
864
        i_log += 4;
865 866 867
    }
    if (i & 0xcccccccc)
    {
Vincent Seguin's avatar
Vincent Seguin committed
868
        i_log += 2;
869 870 871
    }
    if (i & 0xaaaaaaaa)
    {
Vincent Seguin's avatar
Vincent Seguin committed
872
        i_log++;
873
    }
Vincent Seguin's avatar
Vincent Seguin committed
874
    if (i != ((u32)1 << i_log))
875
    {
876
        intf_DbgMsg("internal error: binary log overflow\n");
877
    }
Vincent Seguin's avatar
Vincent Seguin committed
878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903

    return( i_log );
}

/*****************************************************************************
 * MaskToShift: transform a color mask into right and left shifts
 *****************************************************************************
 * This function is used for obtaining color shifts from masks.
 *****************************************************************************/
static void MaskToShift( int *pi_left, int *pi_right, u32 i_mask )
{
    u32 i_low, i_high;                 /* lower hand higher bits of the mask */

    /* Get bits */
    i_low =  i_mask & (- i_mask);                   /* lower bit of the mask */
    i_high = i_mask + i_low;                       /* higher bit of the mask */

    /* Transform bits into an index */
    i_low =  BinaryLog (i_low);
    i_high = BinaryLog (i_high);

    /* Update pointers and return */
    *pi_left =   i_low;
    *pi_right = (8 - i_high + i_low);
}

904
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
905
 * InitThread: initialize video output thread
906
 *****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
907 908 909
 * This function is called from RunThread and performs the second step of the
 * initialization. It returns 0 on success. Note that the thread's flag are not
 * modified inside this function.