video_output.c 74.1 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 53 54 55 56
                                    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 );
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 );
57 58
static void     SetPalette        ( p_vout_thread_t p_vout, u16 *red,
                                    u16 *green, u16 *blue, u16 *transp );
Michel Kaempf's avatar
Michel Kaempf committed
59

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

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

84
    /* Initialize thread properties - thread id and locks will be initialized
85
     * later */
86
    p_vout->b_die               = 0;
87
    p_vout->b_error             = 0;
88 89
    p_vout->b_active            = 0;
    p_vout->pi_status           = (pi_status != NULL) ? pi_status : &i_status;
90
    *p_vout->pi_status          = THREAD_CREATE;
91

92
    /* Initialize some fields used by the system-dependant method - these fields will
93
     * probably be modified by the method, and are only preferences */
94
    p_vout->i_changes           = 0;
95 96
    p_vout->i_width             = i_width;
    p_vout->i_height            = i_height;
97
    p_vout->i_bytes_per_line    = i_width * 2;
98 99
    p_vout->i_screen_depth      = 15;
    p_vout->i_bytes_per_pixel   = 2;
100
    p_vout->f_gamma             = VOUT_GAMMA;
101

Vincent Seguin's avatar
Vincent Seguin committed
102
    p_vout->b_grayscale         = main_GetIntVariable( VOUT_GRAYSCALE_VAR, VOUT_GRAYSCALE_DEFAULT );
103
    p_vout->b_info              = 0;
104 105
    p_vout->b_interface         = 0;
    p_vout->b_scale             = 0;
106 107

    p_vout->p_set_palette       = SetPalette;
108

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

113 114
    /* Initialize idle screen */
    p_vout->last_display_date   = mdate();
115
    p_vout->last_display_date   = 0;
116 117
    p_vout->last_idle_date      = 0;

118 119
#ifdef STATS
    /* Initialize statistics fields */
120 121 122
    p_vout->render_time         = 0;
    p_vout->c_fps_samples       = 0;
#endif
123 124 125 126

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

127
    /* Initialize pictures and subpictures - translation tables and functions
128
     * will be initialized later in InitThread */
129 130
    for( i_index = 0; i_index < VOUT_MAX_PICTURES; i_index++)
    {
131 132 133 134
        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;
135
    }
136

137 138
    /* Create and initialize system-dependant method - this function issues its
     * own error messages */
Vincent Seguin's avatar
Vincent Seguin committed
139
    if( vout_SysCreate( p_vout, psz_display, i_root_window ) )
Michel Kaempf's avatar
Michel Kaempf committed
140
    {
Vincent Seguin's avatar
Vincent Seguin committed
141 142
      free( p_vout );
      return( NULL );
Michel Kaempf's avatar
Michel Kaempf committed
143
    }
Vincent Seguin's avatar
Vincent Seguin committed
144
    intf_DbgMsg("actual configuration: %dx%d, %d/%d bpp (%d Bpl), masks: 0x%x/0x%x/0x%x\n",
145
                p_vout->i_width, p_vout->i_height, p_vout->i_screen_depth,
Vincent Seguin's avatar
Vincent Seguin committed
146 147 148 149 150 151 152 153
                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 );

154
    /* Set some useful colors */
155
    p_vout->i_white_pixel = RGB2PIXEL( p_vout, 255, 255, 255 );
Vincent Seguin's avatar
Vincent Seguin committed
156 157
    p_vout->i_black_pixel = RGB2PIXEL( p_vout, 0, 0, 0 );
    p_vout->i_gray_pixel  = RGB2PIXEL( p_vout, 128, 128, 128 );
158
    p_vout->i_blue_pixel  = RGB2PIXEL( p_vout, 0, 0, 50 );
159

160 161
    /* Load fonts - fonts must be initialized after the systme method since
     * they may be dependant of screen depth and other thread properties */
162
    p_vout->p_default_font      = vout_LoadFont( VOUT_DEFAULT_FONT );
Vincent Seguin's avatar
Vincent Seguin committed
163 164
    if( p_vout->p_default_font == NULL )
    {
165 166 167 168 169
        vout_SysDestroy( p_vout );
        free( p_vout );
        return( NULL );
    }
    p_vout->p_large_font        = vout_LoadFont( VOUT_LARGE_FONT );
Vincent Seguin's avatar
Vincent Seguin committed
170 171
    if( p_vout->p_large_font == NULL )
    {
172 173 174 175 176
        vout_UnloadFont( p_vout->p_default_font );
        vout_SysDestroy( p_vout );
        free( p_vout );
        return( NULL );
    }
Vincent Seguin's avatar
Vincent Seguin committed
177

Michel Kaempf's avatar
Michel Kaempf committed
178
    /* Create thread and set locks */
Vincent Seguin's avatar
Vincent Seguin committed
179
    vlc_mutex_init( &p_vout->picture_lock );
180 181 182
    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
183
    if( vlc_thread_create( &p_vout->thread_id, "video output", (void *) RunThread, (void *) p_vout) )
Michel Kaempf's avatar
Michel Kaempf committed
184
    {
185
        intf_ErrMsg("error: %s\n", strerror(ENOMEM));
Vincent Seguin's avatar
Vincent Seguin committed
186
        vout_UnloadFont( p_vout->p_default_font );
187
        vout_UnloadFont( p_vout->p_large_font );
Vincent Seguin's avatar
Vincent Seguin committed
188
	vout_SysDestroy( p_vout );
Michel Kaempf's avatar
Michel Kaempf committed
189 190
        free( p_vout );
        return( NULL );
191
    }
Michel Kaempf's avatar
Michel Kaempf committed
192

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

Michel Kaempf's avatar
Michel Kaempf committed
196 197 198 199
    /* If status is NULL, wait until the thread is created */
    if( pi_status == NULL )
    {
        do
200
        {
Michel Kaempf's avatar
Michel Kaempf committed
201
            msleep( THREAD_SLEEP );
202
        }while( (i_status != THREAD_READY) && (i_status != THREAD_ERROR)
Michel Kaempf's avatar
Michel Kaempf committed
203 204 205
                && (i_status != THREAD_FATAL) );
        if( i_status != THREAD_READY )
        {
206 207
            return( NULL );
        }
Michel Kaempf's avatar
Michel Kaempf committed
208 209 210 211
    }
    return( p_vout );
}

212
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
213
 * vout_DestroyThread: destroys a previously created thread
214 215
 *****************************************************************************
 * Destroy a terminated thread.
Michel Kaempf's avatar
Michel Kaempf committed
216
 * The function will request a destruction of the specified thread. If pi_error
217
 * is NULL, it will return once the thread is destroyed. Else, it will be
Michel Kaempf's avatar
Michel Kaempf committed
218
 * update using one of the THREAD_* constants.
219
 *****************************************************************************/
Michel Kaempf's avatar
Michel Kaempf committed
220
void vout_DestroyThread( vout_thread_t *p_vout, int *pi_status )
221 222
{
    int     i_status;                                       /* thread status */
Michel Kaempf's avatar
Michel Kaempf committed
223 224

    /* Set status */
225
    intf_DbgMsg("\n");
Michel Kaempf's avatar
Michel Kaempf committed
226
    p_vout->pi_status = (pi_status != NULL) ? pi_status : &i_status;
227 228
    *p_vout->pi_status = THREAD_DESTROY;

Michel Kaempf's avatar
Michel Kaempf committed
229 230 231 232
    /* Request thread destruction */
    p_vout->b_die = 1;

    /* If status is NULL, wait until thread has been destroyed */
233
    if( pi_status == NULL )
Michel Kaempf's avatar
Michel Kaempf committed
234 235 236 237
    {
        do
        {
            msleep( THREAD_SLEEP );
238 239
        }while( (i_status != THREAD_OVER) && (i_status != THREAD_ERROR)
                && (i_status != THREAD_FATAL) );
Michel Kaempf's avatar
Michel Kaempf committed
240 241 242
    }
}

243
/*****************************************************************************
244
 * vout_DisplaySubPicture: display a subpicture unit
245 246
 *****************************************************************************
 * Remove the reservation flag of an subpicture, which will cause it to be ready
247
 * for display. The picture does not need to be locked, since it is ignored by
Vincent Seguin's avatar
Vincent Seguin committed
248
 * the output thread if is reserved.
249
 *****************************************************************************/
250
void  vout_DisplaySubPicture( vout_thread_t *p_vout, subpicture_t *p_subpic )
Vincent Seguin's avatar
Vincent Seguin committed
251 252
{
#ifdef DEBUG_VIDEO
253 254
    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
255 256 257 258
#endif

#ifdef DEBUG
    /* Check if status is valid */
259
    if( p_subpic->i_status != RESERVED_SUBPICTURE )
Vincent Seguin's avatar
Vincent Seguin committed
260
    {
261 262 263
        intf_DbgMsg("error: subpicture %p has invalid status %d\n", p_subpic,
                    p_subpic->i_status );
    }
Vincent Seguin's avatar
Vincent Seguin committed
264 265 266
#endif

    /* Remove reservation flag */
267
    p_subpic->i_status = READY_SUBPICTURE;
Vincent Seguin's avatar
Vincent Seguin committed
268 269

#ifdef DEBUG_VIDEO
270
    /* Send subpicture informations */
271 272 273 274
    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
275 276 277
#endif
}

278
/*****************************************************************************
279
 * vout_CreateSubPicture: allocate an subpicture in the video output heap.
280 281
 *****************************************************************************
 * This function create a reserved subpicture in the video output heap.
Vincent Seguin's avatar
Vincent Seguin committed
282
 * A null pointer is returned if the function fails. This method provides an
283
 * already allocated zone of memory in the spu data fields. It needs locking
284 285 286
 * since several pictures can be created by several producers threads.
 *****************************************************************************/
subpicture_t *vout_CreateSubPicture( vout_thread_t *p_vout, int i_type,
287
                                     int i_size )
Vincent Seguin's avatar
Vincent Seguin committed
288
{
289 290 291
    int                 i_subpic;                        /* subpicture index */
    subpicture_t *      p_free_subpic = NULL;       /* first free subpicture */
    subpicture_t *      p_destroyed_subpic = NULL; /* first destroyed subpic */
292 293 294 295

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

296 297
    /*
     * Look for an empty place
298 299 300 301 302 303 304 305 306
     */
    for( i_subpic = 0; i_subpic < VOUT_MAX_PICTURES; i_subpic++ )
    {
	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) )
	    {
307 308
		/* Memory size do match or is smaller : memory will not be reallocated,
                 * and function can end immediately - this is the best possible case,
309 310 311
                 * since no memory allocation needs to be done */
		p_vout->p_subpicture[i_subpic].i_status = RESERVED_SUBPICTURE;
#ifdef DEBUG_VIDEO
312 313
                intf_DbgMsg("subpicture %p (in destroyed subpicture slot)\n",
                            &p_vout->p_subpicture[i_subpic] );
314 315 316 317 318 319 320 321
#endif
		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 */
322 323
		p_destroyed_subpic = &p_vout->p_subpicture[i_subpic];
	    }	
324
	}
325
        else if( (p_free_subpic == NULL) &&
326 327 328 329 330 331 332 333 334
                 (p_vout->p_subpicture[i_subpic].i_status == FREE_SUBPICTURE ))
        {
	    /* Subpicture is empty and ready for allocation */
            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 ) )
335
    {
336 337
	/* No free subpicture or matching destroyed subpicture has been found, but
	 * a destroyed subpicture is still avalaible */
338
        free( p_destroyed_subpic->p_data );
339 340 341 342 343 344 345 346 347 348 349
        p_free_subpic = p_destroyed_subpic;
    }

    /*
     * Prepare subpicture
     */
    if( p_free_subpic != NULL )
    {
        /* Allocate memory */
        switch( i_type )
        {
350 351
        case TEXT_SUBPICTURE:                             /* text subpicture */
            p_free_subpic->p_data = malloc( i_size + 1 );
352 353 354 355
            break;
#ifdef DEBUG
        default:
            intf_DbgMsg("error: unknown subpicture type %d\n", i_type );
356 357 358
            p_free_subpic->p_data   =  NULL;
            break;
#endif
359 360 361 362 363 364
        }

        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;
365
            p_free_subpic->i_size                      = i_size;
366
            p_free_subpic->i_x                         = 0;
367
            p_free_subpic->i_y                         = 0;
368 369
            p_free_subpic->i_width                     = 0;
            p_free_subpic->i_height                    = 0;
370 371
            p_free_subpic->i_horizontal_align          = CENTER_RALIGN;
            p_free_subpic->i_vertical_align            = CENTER_RALIGN;
372 373 374 375
        }
        else
        {
            /* Memory allocation failed : set subpicture as empty */
376 377 378 379
            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 ) );
380
        }
381

382
#ifdef DEBUG_VIDEO
383
        intf_DbgMsg("subpicture %p (in free subpicture slot)\n", p_free_subpic );
384 385 386 387
#endif
        vlc_mutex_unlock( &p_vout->subpicture_lock );
        return( p_free_subpic );
    }
388

389 390 391 392
    /* 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
393 394
}

395
/*****************************************************************************
396
 * vout_DestroySubPicture: remove a subpicture from the heap
397
 *****************************************************************************
398
 * This function frees a previously reserved subpicture.
Vincent Seguin's avatar
Vincent Seguin committed
399
 * It is meant to be used when the construction of a picture aborted.
400
 * This function does not need locking since reserved subpictures are ignored
401
 * by the output thread.
402
 *****************************************************************************/
403
void vout_DestroySubPicture( vout_thread_t *p_vout, subpicture_t *p_subpic )
Vincent Seguin's avatar
Vincent Seguin committed
404 405
{
#ifdef DEBUG
406 407
   /* Check if status is valid */
   if( p_subpic->i_status != RESERVED_SUBPICTURE )
Vincent Seguin's avatar
Vincent Seguin committed
408
   {
409 410 411
       intf_DbgMsg("error: subpicture %p has invalid status %d\n",
                   p_subpic, p_subpic->i_status );
   }
Vincent Seguin's avatar
Vincent Seguin committed
412 413
#endif

414
    p_subpic->i_status = DESTROYED_SUBPICTURE;
Vincent Seguin's avatar
Vincent Seguin committed
415 416

#ifdef DEBUG_VIDEO
417
    intf_DbgMsg("subpicture %p\n", p_subpic);
Vincent Seguin's avatar
Vincent Seguin committed
418 419 420
#endif
}

421
/*****************************************************************************
Vincent Seguin's avatar
Vincent Seguin committed
422
 * vout_DisplayPicture: display a picture
423
 *****************************************************************************
Vincent Seguin's avatar
Vincent Seguin committed
424
 * Remove the reservation flag of a picture, which will cause it to be ready for
425
 * display. The picture won't be displayed until vout_DatePicture has been
426
 * called.
427
 *****************************************************************************/
Vincent Seguin's avatar
Vincent Seguin committed
428
void  vout_DisplayPicture( vout_thread_t *p_vout, picture_t *p_pic )
Michel Kaempf's avatar
Michel Kaempf committed
429
{
430 431
    vlc_mutex_lock( &p_vout->picture_lock );
    switch( p_pic->i_status )
432
    {
433
    case RESERVED_PICTURE:
434
        p_pic->i_status = RESERVED_DISP_PICTURE;
435
        break;
436 437
    case RESERVED_DATED_PICTURE:
        p_pic->i_status = READY_PICTURE;
438
        break;
439
#ifdef DEBUG
440 441 442
    default:
        intf_DbgMsg("error: picture %p has invalid status %d\n", p_pic, p_pic->i_status );
        break;
443
#endif
444
    }
Michel Kaempf's avatar
Michel Kaempf committed
445

446
#ifdef DEBUG_VIDEO
Vincent Seguin's avatar
Vincent Seguin committed
447
    intf_DbgMsg("picture %p\n", p_pic);
448
#endif
449
    vlc_mutex_unlock( &p_vout->picture_lock );
Michel Kaempf's avatar
Michel Kaempf committed
450 451
}

452
/*****************************************************************************
453
 * vout_DatePicture: date a picture
454
 *****************************************************************************
455
 * Remove the reservation flag of a picture, which will cause it to be ready for
456
 * display. The picture won't be displayed until vout_DisplayPicture has been
457
 * called.
458
 *****************************************************************************/
459 460
void  vout_DatePicture( vout_thread_t *p_vout, picture_t *p_pic, mtime_t date )
{
Vincent Seguin's avatar
Vincent Seguin committed
461
#ifdef DEBUG_VIDEO
462
    char        psz_date[MSTRTIME_MAX_SIZE];                         /* date */
Vincent Seguin's avatar
Vincent Seguin committed
463 464
#endif

465
    vlc_mutex_lock( &p_vout->picture_lock );
466
    p_pic->date = date;
467 468
    switch( p_pic->i_status )
    {
469
    case RESERVED_PICTURE:
470
        p_pic->i_status = RESERVED_DATED_PICTURE;
471
        break;
472 473
    case RESERVED_DISP_PICTURE:
        p_pic->i_status = READY_PICTURE;
474
        break;
475
#ifdef DEBUG
476 477 478
    default:
        intf_DbgMsg("error: picture %p has invalid status %d\n", p_pic, p_pic->i_status );
        break;
479 480 481 482
#endif
    }

#ifdef DEBUG_VIDEO
Vincent Seguin's avatar
Vincent Seguin committed
483
    intf_DbgMsg("picture %p, display date: %s\n", p_pic, mstrtime( psz_date, p_pic->date) );
484
#endif
485
    vlc_mutex_unlock( &p_vout->picture_lock );
486 487
}

488
/*****************************************************************************
Vincent Seguin's avatar
Vincent Seguin committed
489
 * vout_CreatePicture: allocate a picture in the video output heap.
490 491
 *****************************************************************************
 * This function create a reserved image in the video output heap.
Vincent Seguin's avatar
Vincent Seguin committed
492
 * A null pointer is returned if the function fails. This method provides an
493
 * already allocated zone of memory in the picture data fields. It needs locking
494 495 496
 * since several pictures can be created by several producers threads.
 *****************************************************************************/
picture_t *vout_CreatePicture( vout_thread_t *p_vout, int i_type,
497
			       int i_width, int i_height )
Michel Kaempf's avatar
Michel Kaempf committed
498
{
499 500 501 502
    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
503

Vincent Seguin's avatar
Vincent Seguin committed
504
    /* Get lock */
Vincent Seguin's avatar
Vincent Seguin committed
505
    vlc_mutex_lock( &p_vout->picture_lock );
Michel Kaempf's avatar
Michel Kaempf committed
506

507 508
    /*
     * Look for an empty place
Vincent Seguin's avatar
Vincent Seguin committed
509
     */
510
    for( i_picture = 0; i_picture < VOUT_MAX_PICTURES; i_picture++ )
Vincent Seguin's avatar
Vincent Seguin committed
511 512 513
    {
	if( p_vout->p_picture[i_picture].i_status == DESTROYED_PICTURE )
	{
514
	    /* Picture is marked for destruction, but is still allocated - note
515
             * that if width and type are the same for two pictures, chroma_width
516
             * should also be the same */
Vincent Seguin's avatar
Vincent Seguin committed
517 518
	    if( (p_vout->p_picture[i_picture].i_type           == i_type)   &&
		(p_vout->p_picture[i_picture].i_height         == i_height) &&
519
		(p_vout->p_picture[i_picture].i_width          == i_width) )
Vincent Seguin's avatar
Vincent Seguin committed
520 521 522 523 524
	    {
		/* Memory size do match : memory will not be reallocated, and function
                 * can end immediately - this is the best possible case, since no
                 * memory allocation needs to be done */
		p_vout->p_picture[i_picture].i_status = RESERVED_PICTURE;
525
#ifdef DEBUG_VIDEO
526 527
                intf_DbgMsg("picture %p (in destroyed picture slot)\n",
                            &p_vout->p_picture[i_picture] );
528
#endif
Vincent Seguin's avatar
Vincent Seguin committed
529
		vlc_mutex_unlock( &p_vout->picture_lock );
Vincent Seguin's avatar
Vincent Seguin committed
530 531 532 533 534 535
		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 */
536 537
		p_destroyed_picture = &p_vout->p_picture[i_picture];
	    }	
Vincent Seguin's avatar
Vincent Seguin committed
538
	}
539
        else if( (p_free_picture == NULL) &&
Vincent Seguin's avatar
Vincent Seguin committed
540 541 542
                 (p_vout->p_picture[i_picture].i_status == FREE_PICTURE ))
        {
	    /* Picture is empty and ready for allocation */
543
            p_free_picture = &p_vout->p_picture[i_picture];
Vincent Seguin's avatar
Vincent Seguin committed
544
        }
Michel Kaempf's avatar
Michel Kaempf committed
545 546
    }

Vincent Seguin's avatar
Vincent Seguin committed
547 548
    /* If no free picture is available, use a destroyed picture */
    if( (p_free_picture == NULL) && (p_destroyed_picture != NULL ) )
549
    {
Vincent Seguin's avatar
Vincent Seguin committed
550 551
	/* No free picture or matching destroyed picture has been found, but
	 * a destroyed picture is still avalaible */
552 553
        free( p_destroyed_picture->p_data );
        p_free_picture = p_destroyed_picture;
Michel Kaempf's avatar
Michel Kaempf committed
554 555
    }

Vincent Seguin's avatar
Vincent Seguin committed
556 557 558 559 560 561 562
    /*
     * Prepare picture
     */
    if( p_free_picture != NULL )
    {
        /* Allocate memory */
        switch( i_type )
Michel Kaempf's avatar
Michel Kaempf committed
563
        {
564 565
        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
566
            p_free_picture->p_data = malloc( i_height * i_chroma_width * 3 * sizeof( yuv_data_t ) );
567
            p_free_picture->p_y = (yuv_data_t *)p_free_picture->p_data;
Vincent Seguin's avatar
Vincent Seguin committed
568 569
            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;
570
            break;
571 572
        case YUV_422_PICTURE:        /* YUV 422: 1,1/2,1/2 samples per pixel */
            i_chroma_width = i_width / 2;
573 574
            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
575 576
            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;
577
            break;
578 579
        case YUV_444_PICTURE:            /* YUV 444: 1,1,1 samples per pixel */
            i_chroma_width = i_width;
580 581
            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
582 583
            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;
584
            break;
Vincent Seguin's avatar
Vincent Seguin committed
585 586
#ifdef DEBUG
        default:
587
            intf_DbgMsg("error: unknown picture type %d\n", i_type );
588 589 590
            p_free_picture->p_data   =  NULL;
            break;
#endif
Michel Kaempf's avatar
Michel Kaempf committed
591 592
        }

Vincent Seguin's avatar
Vincent Seguin committed
593
        if( p_free_picture->p_data != NULL )
594
        {
595
            /* Copy picture informations, set some default values */
596 597
            p_free_picture->i_type                      = i_type;
            p_free_picture->i_status                    = RESERVED_PICTURE;
598
            p_free_picture->i_matrix_coefficients       = 1;
599 600
            p_free_picture->i_width                     = i_width;
            p_free_picture->i_height                    = i_height;
601
            p_free_picture->i_chroma_width              = i_chroma_width;
602
            p_free_picture->i_display_horizontal_offset = 0;
603
            p_free_picture->i_display_vertical_offset   = 0;
604 605
            p_free_picture->i_display_width             = i_width;
            p_free_picture->i_display_height            = i_height;
606 607
            p_free_picture->i_aspect_ratio              = AR_SQUARE_PICTURE;
            p_free_picture->i_refcount                  = 0;
Vincent Seguin's avatar
Vincent Seguin committed
608 609 610 611
        }
        else
        {
            /* Memory allocation failed : set picture as empty */
612 613 614 615
            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
616
        }
617

618
#ifdef DEBUG_VIDEO
619
        intf_DbgMsg("picture %p (in free picture slot)\n", p_free_picture );
620
#endif
Vincent Seguin's avatar
Vincent Seguin committed
621
        vlc_mutex_unlock( &p_vout->picture_lock );
Vincent Seguin's avatar
Vincent Seguin committed
622
        return( p_free_picture );
Michel Kaempf's avatar
Michel Kaempf committed
623
    }
624

625
    /* No free or destroyed picture could be found */
626
    intf_DbgMsg( "warning: heap is full\n" );
Vincent Seguin's avatar
Vincent Seguin committed
627
    vlc_mutex_unlock( &p_vout->picture_lock );
Vincent Seguin's avatar
Vincent Seguin committed
628
    return( NULL );
Michel Kaempf's avatar
Michel Kaempf committed
629 630
}

631
/*****************************************************************************
632
 * vout_DestroyPicture: remove a permanent or reserved picture from the heap
633
 *****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
634
 * This function frees a previously reserved picture or a permanent
Vincent Seguin's avatar
Vincent Seguin committed
635 636
 * 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 !
637 638
 * This function does not need locking since reserved pictures are ignored by
 * the output thread.
639
 *****************************************************************************/
Vincent Seguin's avatar
Vincent Seguin committed
640
void vout_DestroyPicture( vout_thread_t *p_vout, picture_t *p_pic )
Michel Kaempf's avatar
Michel Kaempf committed
641
{
642
#ifdef DEBUG
643
   /* Check if picture status is valid */
644
   if( (p_pic->i_status != RESERVED_PICTURE) &&
645 646
       (p_pic->i_status != RESERVED_DATED_PICTURE) &&
       (p_pic->i_status != RESERVED_DISP_PICTURE) )
647
   {
648 649
       intf_DbgMsg("error: picture %p has invalid status %d\n", p_pic, p_pic->i_status );
   }
650 651
#endif

Vincent Seguin's avatar
Vincent Seguin committed
652
    p_pic->i_status = DESTROYED_PICTURE;
653 654

#ifdef DEBUG_VIDEO
655
    intf_DbgMsg("picture %p\n", p_pic);
656
#endif
Michel Kaempf's avatar
Michel Kaempf committed
657 658
}

659
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
660
 * vout_LinkPicture: increment reference counter of a picture
661
 *****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
662
 * This function increment the reference counter of a picture in the video
663
 * heap. It needs a lock since several producer threads can access the picture.
664
 *****************************************************************************/
Michel Kaempf's avatar
Michel Kaempf committed
665 666
void vout_LinkPicture( vout_thread_t *p_vout, picture_t *p_pic )
{
Vincent Seguin's avatar
Vincent Seguin committed
667
    vlc_mutex_lock( &p_vout->picture_lock );
Michel Kaempf's avatar
Michel Kaempf committed
668
    p_pic->i_refcount++;
669 670

#ifdef DEBUG_VIDEO
671
    intf_DbgMsg("picture %p refcount=%d\n", p_pic, p_pic->i_refcount );
672
#endif
673 674

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

677
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
678
 * vout_UnlinkPicture: decrement reference counter of a picture
679
 *****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
680
 * This function decrement the reference counter of a picture in the video heap.
681
 *****************************************************************************/
Michel Kaempf's avatar
Michel Kaempf committed
682 683
void vout_UnlinkPicture( vout_thread_t *p_vout, picture_t *p_pic )
{
Vincent Seguin's avatar
Vincent Seguin committed
684
    vlc_mutex_lock( &p_vout->picture_lock );
Michel Kaempf's avatar
Michel Kaempf committed
685
    p_pic->i_refcount--;
686 687 688 689 690

#ifdef DEBUG_VIDEO
    if( p_pic->i_refcount < 0 )
    {
        intf_DbgMsg("error: refcount < 0\n");
691 692
        p_pic->i_refcount = 0;
    }
693 694
#endif

Vincent Seguin's avatar
Vincent Seguin committed
695
    if( (p_pic->i_refcount == 0) && (p_pic->i_status == DISPLAYED_PICTURE) )
Michel Kaempf's avatar
Michel Kaempf committed
696
    {
Vincent Seguin's avatar
Vincent Seguin committed
697
	p_pic->i_status = DESTROYED_PICTURE;
Michel Kaempf's avatar
Michel Kaempf committed
698
    }
699 700

#ifdef DEBUG_VIDEO
701
    intf_DbgMsg("picture %p refcount=%d\n", p_pic, p_pic->i_refcount );
702
#endif
703 704

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

707
/*****************************************************************************
708
 * vout_SetBuffers: set buffers adresses
709 710
 *****************************************************************************
 * This function is called by system drivers to set buffers video memory
711
 * adresses.
712
 *****************************************************************************/
713
void vout_SetBuffers( vout_thread_t *p_vout, void *p_buf1, void *p_buf2 )
714 715
{
    /* No picture previously */
716 717 718 719 720 721 722 723
    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;
724 725

    /* The first area covers all the screen */
726 727 728 729 730 731 732 733
    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 */
734 735
    p_vout->p_buffer[0].p_data = p_buf1;
    p_vout->p_buffer[1].p_data = p_buf2;
736 737
}

Vincent Seguin's avatar
Vincent Seguin committed
738 739 740 741 742 743 744 745 746 747 748 749 750
/*****************************************************************************
 * 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
751 752
/* following functions are local */

Vincent Seguin's avatar
Vincent Seguin committed
753 754 755
/*****************************************************************************
 * BinaryLog: computes the base 2 log of a binary value
 *****************************************************************************
756
 * This functions is used by MaskToShift, to get a bit index from a binary
Vincent Seguin's avatar
Vincent Seguin committed
757 758 759 760 761 762 763
 * value.
 *****************************************************************************/
static int BinaryLog(u32 i)
{
    int i_log;

    i_log = 0;
764 765
    if (i & 0xffff0000)
    {
Vincent Seguin's avatar
Vincent Seguin committed
766
        i_log = 16;
767 768 769
    }
    if (i & 0xff00ff00)
    {
Vincent Seguin's avatar
Vincent Seguin committed
770
        i_log += 8;
771 772 773
    }
    if (i & 0xf0f0f0f0)
    {