video_output.c 81.6 KB
Newer Older
1
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
2
 * video_output.c : video output thread
3
 * (c)2000 VideoLAN
4
 *****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
5 6 7
 * This module describes the programming interface for video output threads.
 * It includes functions allowing to open a new thread, send pictures to a
 * thread, and destroy a previously oppenned video output thread.
8
 *****************************************************************************/
Michel Kaempf's avatar
Michel Kaempf committed
9

10
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
11
 * Preamble
12
 *****************************************************************************/
13
#include <errno.h>
Michel Kaempf's avatar
Michel Kaempf committed
14 15 16
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
Vincent Seguin's avatar
Vincent Seguin committed
17

Michel Kaempf's avatar
Michel Kaempf committed
18 19 20
#include "common.h"
#include "config.h"
#include "mtime.h"
21
#include "vlc_thread.h"
Michel Kaempf's avatar
Michel Kaempf committed
22 23
#include "video.h"
#include "video_output.h"
Vincent Seguin's avatar
Vincent Seguin committed
24
#include "video_text.h"
Vincent Seguin's avatar
Vincent Seguin committed
25
#include "video_sys.h"
26
#include "video_yuv.h"
Vincent Seguin's avatar
Vincent Seguin committed
27
#include "intf_msg.h"
28
#include "main.h"
Vincent Seguin's avatar
Vincent Seguin committed
29

30
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
31
 * Local prototypes
32
 *****************************************************************************/
Vincent Seguin's avatar
Vincent Seguin committed
33 34
static int      BinaryLog         ( u32 i );
static void     MaskToShift       ( int *pi_left, int *pi_right, u32 i_mask );
35 36 37 38 39
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 );
40
static void     Print             ( vout_thread_t *p_vout, int i_x, int i_y,
41 42 43 44 45 46 47 48 49 50 51 52
                                    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 );
static void     RenderInfo        ( vout_thread_t *p_vout );
53
static void     Synchronize       ( vout_thread_t *p_vout, s64 i_delay );
54 55 56 57
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 );
58 59
static void     SetPalette        ( p_vout_thread_t p_vout, u16 *red,
                                    u16 *green, u16 *blue, u16 *transp );
Michel Kaempf's avatar
Michel Kaempf committed
60

61
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
62
 * vout_CreateThread: creates a new video output thread
63
 *****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
64 65 66
 * 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.
67
 * If not, it will be updated using one of the THREAD_* constants.
68
 *****************************************************************************/
69 70
vout_thread_t * vout_CreateThread   ( char *psz_display, int i_root_window,
                          int i_width, int i_height, int *pi_status, int i_method )
Michel Kaempf's avatar
Michel Kaempf committed
71
{
72 73 74
    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
75

76
    /* Allocate descriptor */
77
    intf_DbgMsg("\n");
Michel Kaempf's avatar
Michel Kaempf committed
78
    p_vout = (vout_thread_t *) malloc( sizeof(vout_thread_t) );
79
    if( p_vout == NULL )
Michel Kaempf's avatar
Michel Kaempf committed
80
    {
81
        intf_ErrMsg("error: %s\n", strerror(ENOMEM));
Michel Kaempf's avatar
Michel Kaempf committed
82 83
        return( NULL );
    }
84

85 86 87
    /* Sets method-specific functions */
    switch( i_method )
    {
88
#ifdef VIDEO_DUMMY
89 90 91 92 93 94 95 96
        case VOUT_DUMMY_METHOD:
            p_vout->p_sys_create =    vout_DummySysCreate;
            p_vout->p_sys_init =      vout_DummySysInit;
            p_vout->p_sys_end =       vout_DummySysEnd;
            p_vout->p_sys_destroy =   vout_DummySysDestroy;
            p_vout->p_sys_manage =    vout_DummySysManage;
            p_vout->p_sys_display =   vout_DummySysDisplay;
            break;
97
#endif
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
#ifdef VIDEO_X11
        case VOUT_X11_METHOD:
            p_vout->p_sys_create =    vout_X11SysCreate;
            p_vout->p_sys_init =      vout_X11SysInit;
            p_vout->p_sys_end =       vout_X11SysEnd;
            p_vout->p_sys_destroy =   vout_X11SysDestroy;
            p_vout->p_sys_manage =    vout_X11SysManage;
            p_vout->p_sys_display =   vout_X11SysDisplay;
            break;
#endif
#ifdef VIDEO_FB
        case VOUT_FB_METHOD:
            p_vout->p_sys_create =    vout_FBSysCreate;
            p_vout->p_sys_init =      vout_FBSysInit;
            p_vout->p_sys_end =       vout_FBSysEnd;
            p_vout->p_sys_destroy =   vout_FBSysDestroy;
            p_vout->p_sys_manage =    vout_FBSysManage;
            p_vout->p_sys_display =   vout_FBSysDisplay;
            break;
#endif
#ifdef VIDEO_GLIDE
        case VOUT_GLIDE_METHOD:
            p_vout->p_sys_create =    vout_GlideSysCreate;
            p_vout->p_sys_init =      vout_GlideSysInit;
            p_vout->p_sys_end =       vout_GlideSysEnd;
            p_vout->p_sys_destroy =   vout_GlideSysDestroy;
            p_vout->p_sys_manage =    vout_GlideSysManage;
            p_vout->p_sys_display =   vout_GlideSysDisplay;
            break;
#endif
#ifdef VIDEO_DGA
        case VOUT_DGA_METHOD:
            p_vout->p_sys_create =    vout_DGASysCreate;
            p_vout->p_sys_init =      vout_DGASysInit;
            p_vout->p_sys_end =       vout_DGASysEnd;
            p_vout->p_sys_destroy =   vout_DGASysDestroy;
            p_vout->p_sys_manage =    vout_DGASysManage;
            p_vout->p_sys_display =   vout_DGASysDisplay;
            break;
#endif
#ifdef VIDEO_GGI
        case VOUT_GGI_METHOD:
            p_vout->p_sys_create =    vout_GGISysCreate;
            p_vout->p_sys_init =      vout_GGISysInit;
            p_vout->p_sys_end =       vout_GGISysEnd;
            p_vout->p_sys_destroy =   vout_GGISysDestroy;
            p_vout->p_sys_manage =    vout_GGISysManage;
            p_vout->p_sys_display =   vout_GGISysDisplay;
            break;
#endif
#ifdef VIDEO_BEOS
        case VOUT_BEOS_METHOD:
150 151 152 153 154 155
            p_vout->p_sys_create =    vout_BSysCreate;
            p_vout->p_sys_init =      vout_BSysInit;
            p_vout->p_sys_end =       vout_BSysEnd;
            p_vout->p_sys_destroy =   vout_BSysDestroy;
            p_vout->p_sys_manage =    vout_BSysManage;
            p_vout->p_sys_display =   vout_BSysDisplay;
156 157 158 159 160 161 162 163
            break;
#endif
        default:
            intf_ErrMsg( "error: video output method not available\n" );
            free( p_vout );
            return( NULL );
    }

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
    /* Initialize some fields used by the system-dependant method - these fields will
173
     * probably be modified by the method, and are only preferences */
174
    p_vout->i_changes           = 0;
175 176
    p_vout->i_width             = i_width;
    p_vout->i_height            = i_height;
177
    p_vout->i_bytes_per_line    = i_width * 2;
178 179
    p_vout->i_screen_depth      = 15;
    p_vout->i_bytes_per_pixel   = 2;
180
    p_vout->f_gamma             = VOUT_GAMMA;
181

Vincent Seguin's avatar
Vincent Seguin committed
182
    p_vout->b_grayscale         = main_GetIntVariable( VOUT_GRAYSCALE_VAR, VOUT_GRAYSCALE_DEFAULT );
183
    p_vout->b_info              = 0;
184 185
    p_vout->b_interface         = 0;
    p_vout->b_scale             = 0;
186 187

    p_vout->p_set_palette       = SetPalette;
188

Vincent Seguin's avatar
Vincent Seguin committed
189
    intf_DbgMsg("wished configuration: %dx%d, %d/%d bpp (%d Bpl)\n",
190
                p_vout->i_width, p_vout->i_height, p_vout->i_screen_depth,
Vincent Seguin's avatar
Vincent Seguin committed
191
                p_vout->i_bytes_per_pixel * 8, p_vout->i_bytes_per_line );
192

193 194
    /* Initialize idle screen */
    p_vout->last_display_date   = mdate();
195
    p_vout->last_display_date   = 0;
196 197
    p_vout->last_idle_date      = 0;

198 199
#ifdef STATS
    /* Initialize statistics fields */
200 201 202
    p_vout->render_time         = 0;
    p_vout->c_fps_samples       = 0;
#endif
203 204 205 206

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

207
    /* Initialize pictures and subpictures - translation tables and functions
208
     * will be initialized later in InitThread */
209 210
    for( i_index = 0; i_index < VOUT_MAX_PICTURES; i_index++)
    {
211 212 213 214
        p_vout->p_picture[i_index].i_type   =   EMPTY_PICTURE;
        p_vout->p_picture[i_index].i_status =   FREE_PICTURE;
        p_vout->p_subpicture[i_index].i_type  = EMPTY_SUBPICTURE;
        p_vout->p_subpicture[i_index].i_status= FREE_SUBPICTURE;
215
    }
216 217 218 219
    p_vout->i_pictures = 0;    

    /* Initialize synchronization informations */
    p_vout->i_synchro_level     = VOUT_SYNCHRO_LEVEL_START;
220

221 222
    /* Create and initialize system-dependant method - this function issues its
     * own error messages */
223
    if( p_vout->p_sys_create( p_vout, psz_display, i_root_window ) )
Michel Kaempf's avatar
Michel Kaempf committed
224
    {
Vincent Seguin's avatar
Vincent Seguin committed
225 226
      free( p_vout );
      return( NULL );
Michel Kaempf's avatar
Michel Kaempf committed
227
    }
Vincent Seguin's avatar
Vincent Seguin committed
228
    intf_DbgMsg("actual configuration: %dx%d, %d/%d bpp (%d Bpl), masks: 0x%x/0x%x/0x%x\n",
229
                p_vout->i_width, p_vout->i_height, p_vout->i_screen_depth,
Vincent Seguin's avatar
Vincent Seguin committed
230 231 232 233 234 235 236 237
                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 );

    /* Calculate shifts from system-updated masks */
    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 );

238
    /* Set some useful colors */
239
    p_vout->i_white_pixel = RGB2PIXEL( p_vout, 255, 255, 255 );
Vincent Seguin's avatar
Vincent Seguin committed
240 241
    p_vout->i_black_pixel = RGB2PIXEL( p_vout, 0, 0, 0 );
    p_vout->i_gray_pixel  = RGB2PIXEL( p_vout, 128, 128, 128 );
242
    p_vout->i_blue_pixel  = RGB2PIXEL( p_vout, 0, 0, 50 );
243

244 245
    /* Load fonts - fonts must be initialized after the system method since
     * they may be dependant on screen depth and other thread properties */
246
    p_vout->p_default_font      = vout_LoadFont( VOUT_DEFAULT_FONT );
Vincent Seguin's avatar
Vincent Seguin committed
247 248
    if( p_vout->p_default_font == NULL )
    {
249
        p_vout->p_sys_destroy( p_vout );
250 251 252 253
        free( p_vout );
        return( NULL );
    }
    p_vout->p_large_font        = vout_LoadFont( VOUT_LARGE_FONT );
Vincent Seguin's avatar
Vincent Seguin committed
254 255
    if( p_vout->p_large_font == NULL )
    {
256
        vout_UnloadFont( p_vout->p_default_font );
257
        p_vout->p_sys_destroy( p_vout );
258 259 260
        free( p_vout );
        return( NULL );
    }
Vincent Seguin's avatar
Vincent Seguin committed
261

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

277
    intf_Msg("Video display initialized (%dx%d, %d/%d bpp)\n", p_vout->i_width,
Vincent Seguin's avatar
Vincent Seguin committed
278
             p_vout->i_height, p_vout->i_screen_depth, p_vout->i_bytes_per_pixel * 8 );
279

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

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

    /* Set status */
309
    intf_DbgMsg("\n");
Michel Kaempf's avatar
Michel Kaempf committed
310
    p_vout->pi_status = (pi_status != NULL) ? pi_status : &i_status;
311 312
    *p_vout->pi_status = THREAD_DESTROY;

Michel Kaempf's avatar
Michel Kaempf committed
313 314 315 316
    /* Request thread destruction */
    p_vout->b_die = 1;

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

327
/*****************************************************************************
328
 * vout_DisplaySubPicture: display a subpicture unit
329 330
 *****************************************************************************
 * Remove the reservation flag of an subpicture, which will cause it to be ready
331
 * for display. The picture does not need to be locked, since it is ignored by
Vincent Seguin's avatar
Vincent Seguin committed
332
 * the output thread if is reserved.
333
 *****************************************************************************/
334
void  vout_DisplaySubPicture( vout_thread_t *p_vout, subpicture_t *p_subpic )
Vincent Seguin's avatar
Vincent Seguin committed
335 336
{
#ifdef DEBUG_VIDEO
337 338
    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
339 340 341 342
#endif

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

    /* Remove reservation flag */
351
    p_subpic->i_status = READY_SUBPICTURE;
Vincent Seguin's avatar
Vincent Seguin committed
352 353

#ifdef DEBUG_VIDEO
354
    /* Send subpicture informations */
355 356 357 358
    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
359 360 361
#endif
}

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

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

380 381
    /*
     * Look for an empty place
382 383 384
     */
    for( i_subpic = 0; i_subpic < VOUT_MAX_PICTURES; i_subpic++ )
    {
385 386 387 388 389 390 391
        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) )
            {
                /* Memory size do match or is smaller : memory will not be reallocated,
392
                 * and function can end immediately - this is the best possible case,
393
                 * since no memory allocation needs to be done */
394
                p_vout->p_subpicture[i_subpic].i_status = RESERVED_SUBPICTURE;
395
#ifdef DEBUG_VIDEO
396 397
                intf_DbgMsg("subpicture %p (in destroyed subpicture slot)\n",
                            &p_vout->p_subpicture[i_subpic] );
398
#endif
399 400 401 402 403 404 405 406 407 408
                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];
            }
        }
409
        else if( (p_free_subpic == NULL) &&
410 411
                 (p_vout->p_subpicture[i_subpic].i_status == FREE_SUBPICTURE ))
        {
412
            /* Subpicture is empty and ready for allocation */
413 414 415 416 417 418
            p_free_subpic = &p_vout->p_subpicture[i_subpic];
        }
    }

    /* If no free subpicture is available, use a destroyed subpicture */
    if( (p_free_subpic == NULL) && (p_destroyed_subpic != NULL ) )
419
    {
420 421
        /* No free subpicture or matching destroyed subpicture has been found, but
         * a destroyed subpicture is still avalaible */
422
        free( p_destroyed_subpic->p_data );
423 424 425 426 427 428 429 430 431 432 433
        p_free_subpic = p_destroyed_subpic;
    }

    /*
     * Prepare subpicture
     */
    if( p_free_subpic != NULL )
    {
        /* Allocate memory */
        switch( i_type )
        {
434 435
        case TEXT_SUBPICTURE:                             /* text subpicture */
            p_free_subpic->p_data = malloc( i_size + 1 );
436 437 438 439
            break;
#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 446 447 448
        }

        if( p_free_subpic->p_data != NULL )
        {                    /* Copy subpicture informations, set some default values */
            p_free_subpic->i_type                      = i_type;
            p_free_subpic->i_status                    = RESERVED_SUBPICTURE;
449
            p_free_subpic->i_size                      = i_size;
450
            p_free_subpic->i_x                         = 0;
451
            p_free_subpic->i_y                         = 0;
452 453
            p_free_subpic->i_width                     = 0;
            p_free_subpic->i_height                    = 0;
454 455
            p_free_subpic->i_horizontal_align          = CENTER_RALIGN;
            p_free_subpic->i_vertical_align            = CENTER_RALIGN;
456 457 458 459
        }
        else
        {
            /* Memory allocation failed : set subpicture as empty */
460 461 462 463
            p_free_subpic->i_type   =  EMPTY_SUBPICTURE;
            p_free_subpic->i_status =  FREE_SUBPICTURE;
            p_free_subpic =            NULL;
            intf_ErrMsg("warning: %s\n", strerror( ENOMEM ) );
464
        }
465

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

#ifdef DEBUG_VIDEO
790
    intf_DbgMsg("picture %p refcount=%d\n", 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
/*****************************************************************************
797
 * vout_SetBuffers: set buffers adresses
798 799
 *****************************************************************************
 * This function is called by system drivers to set buffers video memory
800
 * adresses.
801
 *****************************************************************************/
802
void vout_SetBuffers( vout_thread_t *p_vout, void *p_buf1, void *p_buf2 )
803 804
{
    /* No picture previously */
805 806 807 808 809 810 811 812
    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;
813 814

    /* The first area covers all the screen */
815 816 817 818 819 820 821 822
    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 */
823 824
    p_vout->p_buffer[0].p_data = p_buf1;
    p_vout->p_buffer[1].p_data = p_buf2;
825 826
}

Vincent Seguin's avatar
Vincent Seguin committed
827 828 829 830 831 832 833 834 835 836 837 838 839
/*****************************************************************************
 * 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
840 841
/* following functions are local */

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

    i_log = 0;
853 854
    if (i & 0xffff0000)
    {
Vincent Seguin's avatar
Vincent Seguin committed
855
        i_log = 16;
856 857 858
    }
    if (i & 0xff00ff00)
    {
Vincent Seguin's avatar
Vincent Seguin committed
859
        i_log += 8;