video_output.c 82.8 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 15 16 17 18 19 20 21 22 23 24
 * 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.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * 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-1307, USA.
25
 *****************************************************************************/
Michel Kaempf's avatar
Michel Kaempf committed
26

27
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
28
 * Preamble
29
 *****************************************************************************/
30 31
#include "defs.h"

32 33 34 35
#include <errno.h>                                                 /* ENOMEM */
#include <stdlib.h>                                                /* free() */
#include <stdio.h>                                              /* sprintf() */
#include <string.h>                                            /* strerror() */
Vincent Seguin's avatar
Vincent Seguin committed
36

Michel Kaempf's avatar
Michel Kaempf committed
37
#include "config.h"
38 39
#include "common.h"
#include "threads.h"
Michel Kaempf's avatar
Michel Kaempf committed
40
#include "mtime.h"
41
#include "plugins.h"
Michel Kaempf's avatar
Michel Kaempf committed
42 43
#include "video.h"
#include "video_output.h"
Vincent Seguin's avatar
Vincent Seguin committed
44
#include "video_text.h"
Sam Hocevar's avatar
NEWS:  
Sam Hocevar committed
45
#include "video_spu.h"
46
#include "video_yuv.h"
47

Vincent Seguin's avatar
Vincent Seguin committed
48
#include "intf_msg.h"
49
#include "main.h"
Vincent Seguin's avatar
Vincent Seguin committed
50

51
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
52
 * Local prototypes
53
 *****************************************************************************/
Vincent Seguin's avatar
Vincent Seguin committed
54 55
static int      BinaryLog         ( u32 i );
static void     MaskToShift       ( int *pi_left, int *pi_right, u32 i_mask );
56 57 58 59 60
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 );
61
static void     Print             ( vout_thread_t *p_vout, int i_x, int i_y,
62 63 64 65 66 67 68 69 70 71 72 73
                                    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 );
74
static void     Synchronize       ( vout_thread_t *p_vout, s64 i_delay );
75 76 77 78
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 );
79 80
static void     SetPalette        ( p_vout_thread_t p_vout, u16 *red,
                                    u16 *green, u16 *blue, u16 *transp );
Michel Kaempf's avatar
Michel Kaempf committed
81

82
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
83
 * vout_CreateThread: creates a new video output thread
84
 *****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
85 86 87
 * 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.
88
 * If not, it will be updated using one of the THREAD_* constants.
89
 *****************************************************************************/
90 91
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
92
{
93 94 95
    vout_thread_t * p_vout;                             /* thread descriptor */
    int             i_status;                               /* thread status */
    int             i_index;               /* index for array initialization */
96
    char *          psz_method;
Michel Kaempf's avatar
Michel Kaempf committed
97

98
    /* Allocate descriptor */
99
    intf_DbgMsg("\n");
Michel Kaempf's avatar
Michel Kaempf committed
100
    p_vout = (vout_thread_t *) malloc( sizeof(vout_thread_t) );
101
    if( p_vout == NULL )
Michel Kaempf's avatar
Michel Kaempf committed
102
    {
103
        intf_ErrMsg( "error: %s\n", strerror(ENOMEM) );
Michel Kaempf's avatar
Michel Kaempf committed
104 105
        return( NULL );
    }
106

107
    /* Request an interface plugin */
108 109
    psz_method = main_GetPszVariable( VOUT_METHOD_VAR, VOUT_DEFAULT_METHOD );

110
    if( RequestPlugin( &p_vout->vout_plugin, "vout", psz_method ) < 0 )
111
    {
112
        intf_ErrMsg( "error: could not open video plugin vout_%s.so\n", psz_method );
113 114
        free( p_vout );
        return( NULL );
115
    }
116 117

    /* Get plugins */
118 119 120 121 122 123
    p_vout->p_sys_create =  GetPluginFunction( p_vout->vout_plugin, "vout_SysCreate" );
    p_vout->p_sys_init =    GetPluginFunction( p_vout->vout_plugin, "vout_SysInit" );
    p_vout->p_sys_end =     GetPluginFunction( p_vout->vout_plugin, "vout_SysEnd" );
    p_vout->p_sys_destroy = GetPluginFunction( p_vout->vout_plugin, "vout_SysDestroy" );
    p_vout->p_sys_manage =  GetPluginFunction( p_vout->vout_plugin, "vout_SysManage" );
    p_vout->p_sys_display = GetPluginFunction( p_vout->vout_plugin, "vout_SysDisplay" );
124

125
    /* Initialize thread properties - thread id and locks will be initialized
126
     * later */
127
    p_vout->b_die               = 0;
128
    p_vout->b_error             = 0;
129 130
    p_vout->b_active            = 0;
    p_vout->pi_status           = (pi_status != NULL) ? pi_status : &i_status;
131
    *p_vout->pi_status          = THREAD_CREATE;
132

133
    /* Initialize some fields used by the system-dependant method - these fields will
134
     * probably be modified by the method, and are only preferences */
135
    p_vout->i_changes           = 0;
136 137
    p_vout->i_width             = i_width;
    p_vout->i_height            = i_height;
138
    p_vout->i_bytes_per_line    = i_width * 2;
139 140
    p_vout->i_screen_depth      = 15;
    p_vout->i_bytes_per_pixel   = 2;
141
    p_vout->f_gamma             = VOUT_GAMMA;
142

Vincent Seguin's avatar
Vincent Seguin committed
143
    p_vout->b_grayscale         = main_GetIntVariable( VOUT_GRAYSCALE_VAR, VOUT_GRAYSCALE_DEFAULT );
144
    p_vout->b_info              = 0;
145 146
    p_vout->b_interface         = 0;
    p_vout->b_scale             = 0;
147 148

    p_vout->p_set_palette       = SetPalette;
149

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

154 155
    /* Initialize idle screen */
    p_vout->last_display_date   = mdate();
156
    p_vout->last_display_date   = 0;
157 158
    p_vout->last_idle_date      = 0;

159 160
#ifdef STATS
    /* Initialize statistics fields */
161 162 163
    p_vout->render_time         = 0;
    p_vout->c_fps_samples       = 0;
#endif
164 165 166 167

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

168
    /* Initialize pictures and subpictures - translation tables and functions
169
     * will be initialized later in InitThread */
170 171
    for( i_index = 0; i_index < VOUT_MAX_PICTURES; i_index++)
    {
172 173
        p_vout->p_picture[i_index].i_type   =   EMPTY_PICTURE;
        p_vout->p_picture[i_index].i_status =   FREE_PICTURE;
174 175 176
    }
    for( i_index = 0; i_index < VOUT_MAX_SUBPICTURES; i_index++)
    {
177 178
        p_vout->p_subpicture[i_index].i_type  = EMPTY_SUBPICTURE;
        p_vout->p_subpicture[i_index].i_status= FREE_SUBPICTURE;
179
    }
180
    p_vout->i_pictures = 0;
181 182 183

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

185 186
    /* Create and initialize system-dependant method - this function issues its
     * own error messages */
187
    if( p_vout->p_sys_create( p_vout, psz_display, i_root_window ) )
Michel Kaempf's avatar
Michel Kaempf committed
188
    {
189
        TrashPlugin( p_vout->vout_plugin );
190 191
        free( p_vout );
        return( NULL );
Michel Kaempf's avatar
Michel Kaempf committed
192
    }
Vincent Seguin's avatar
Vincent Seguin committed
193
    intf_DbgMsg("actual configuration: %dx%d, %d/%d bpp (%d Bpl), masks: 0x%x/0x%x/0x%x\n",
194
                p_vout->i_width, p_vout->i_height, p_vout->i_screen_depth,
Vincent Seguin's avatar
Vincent Seguin committed
195 196 197 198 199 200 201 202
                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 );

203
    /* Set some useful colors */
204
    p_vout->i_white_pixel = RGB2PIXEL( p_vout, 255, 255, 255 );
Vincent Seguin's avatar
Vincent Seguin committed
205 206
    p_vout->i_black_pixel = RGB2PIXEL( p_vout, 0, 0, 0 );
    p_vout->i_gray_pixel  = RGB2PIXEL( p_vout, 128, 128, 128 );
207
    p_vout->i_blue_pixel  = RGB2PIXEL( p_vout, 0, 0, 50 );
208

209 210
    /* Load fonts - fonts must be initialized after the system method since
     * they may be dependant on screen depth and other thread properties */
211 212 213 214 215
    p_vout->p_default_font      = vout_LoadFont( DATA_PATH "/" VOUT_DEFAULT_FONT );
    if( p_vout->p_default_font == NULL )
    {
        p_vout->p_default_font  = vout_LoadFont( "share/" VOUT_DEFAULT_FONT );
    }
Vincent Seguin's avatar
Vincent Seguin committed
216 217
    if( p_vout->p_default_font == NULL )
    {
218
        p_vout->p_sys_destroy( p_vout );
219
        TrashPlugin( p_vout->vout_plugin );
220 221 222
        free( p_vout );
        return( NULL );
    }
223 224 225 226 227
    p_vout->p_large_font        = vout_LoadFont( DATA_PATH "/" VOUT_LARGE_FONT );
    if( p_vout->p_large_font == NULL )
    {
        p_vout->p_large_font    = vout_LoadFont( "share/" VOUT_LARGE_FONT );
    }
Vincent Seguin's avatar
Vincent Seguin committed
228 229
    if( p_vout->p_large_font == NULL )
    {
230
        vout_UnloadFont( p_vout->p_default_font );
231
        p_vout->p_sys_destroy( p_vout );
232
        TrashPlugin( p_vout->vout_plugin );
233 234 235
        free( p_vout );
        return( NULL );
    }
Vincent Seguin's avatar
Vincent Seguin committed
236

Michel Kaempf's avatar
Michel Kaempf committed
237
    /* Create thread and set locks */
Vincent Seguin's avatar
Vincent Seguin committed
238
    vlc_mutex_init( &p_vout->picture_lock );
239 240 241
    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
242
    if( vlc_thread_create( &p_vout->thread_id, "video output", (void *) RunThread, (void *) p_vout) )
Michel Kaempf's avatar
Michel Kaempf committed
243
    {
244
        intf_ErrMsg("error: %s\n", strerror(ENOMEM));
Vincent Seguin's avatar
Vincent Seguin committed
245
        vout_UnloadFont( p_vout->p_default_font );
246
        vout_UnloadFont( p_vout->p_large_font );
247
        p_vout->p_sys_destroy( p_vout );
248
        TrashPlugin( p_vout->vout_plugin );
Michel Kaempf's avatar
Michel Kaempf committed
249 250
        free( p_vout );
        return( NULL );
251
    }
Michel Kaempf's avatar
Michel Kaempf committed
252

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

Michel Kaempf's avatar
Michel Kaempf committed
256 257 258 259
    /* If status is NULL, wait until the thread is created */
    if( pi_status == NULL )
    {
        do
260
        {
Michel Kaempf's avatar
Michel Kaempf committed
261
            msleep( THREAD_SLEEP );
262
        }while( (i_status != THREAD_READY) && (i_status != THREAD_ERROR)
Michel Kaempf's avatar
Michel Kaempf committed
263 264 265
                && (i_status != THREAD_FATAL) );
        if( i_status != THREAD_READY )
        {
266 267
            return( NULL );
        }
Michel Kaempf's avatar
Michel Kaempf committed
268 269 270 271
    }
    return( p_vout );
}

272
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
273
 * vout_DestroyThread: destroys a previously created thread
274 275
 *****************************************************************************
 * Destroy a terminated thread.
Michel Kaempf's avatar
Michel Kaempf committed
276
 * The function will request a destruction of the specified thread. If pi_error
277
 * is NULL, it will return once the thread is destroyed. Else, it will be
Michel Kaempf's avatar
Michel Kaempf committed
278
 * update using one of the THREAD_* constants.
279
 *****************************************************************************/
Michel Kaempf's avatar
Michel Kaempf committed
280
void vout_DestroyThread( vout_thread_t *p_vout, int *pi_status )
281 282
{
    int     i_status;                                       /* thread status */
Michel Kaempf's avatar
Michel Kaempf committed
283 284

    /* Set status */
285
    intf_DbgMsg("\n");
Michel Kaempf's avatar
Michel Kaempf committed
286
    p_vout->pi_status = (pi_status != NULL) ? pi_status : &i_status;
287 288
    *p_vout->pi_status = THREAD_DESTROY;

Michel Kaempf's avatar
Michel Kaempf committed
289 290 291 292
    /* Request thread destruction */
    p_vout->b_die = 1;

    /* If status is NULL, wait until thread has been destroyed */
293
    if( pi_status == NULL )
Michel Kaempf's avatar
Michel Kaempf committed
294 295 296 297
    {
        do
        {
            msleep( THREAD_SLEEP );
298 299
        }while( (i_status != THREAD_OVER) && (i_status != THREAD_ERROR)
                && (i_status != THREAD_FATAL) );
Michel Kaempf's avatar
Michel Kaempf committed
300 301 302
    }
}

303
/*****************************************************************************
304
 * vout_DisplaySubPicture: display a subpicture unit
305 306
 *****************************************************************************
 * Remove the reservation flag of an subpicture, which will cause it to be ready
307
 * for display. The picture does not need to be locked, since it is ignored by
Vincent Seguin's avatar
Vincent Seguin committed
308
 * the output thread if is reserved.
309
 *****************************************************************************/
310
void  vout_DisplaySubPicture( vout_thread_t *p_vout, subpicture_t *p_subpic )
Vincent Seguin's avatar
Vincent Seguin committed
311 312
{
#ifdef DEBUG_VIDEO
313 314
    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
315 316 317 318
#endif

#ifdef DEBUG
    /* Check if status is valid */
319
    if( p_subpic->i_status != RESERVED_SUBPICTURE )
Vincent Seguin's avatar
Vincent Seguin committed
320
    {
321 322 323
        intf_DbgMsg("error: subpicture %p has invalid status %d\n", p_subpic,
                    p_subpic->i_status );
    }
Vincent Seguin's avatar
Vincent Seguin committed
324 325 326
#endif

    /* Remove reservation flag */
327
    p_subpic->i_status = READY_SUBPICTURE;
Vincent Seguin's avatar
Vincent Seguin committed
328 329

#ifdef DEBUG_VIDEO
330
    /* Send subpicture informations */
331 332 333 334
    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
335 336 337
#endif
}

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

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

356 357
    /*
     * Look for an empty place
358
     */
359
    for( i_subpic = 0; i_subpic < VOUT_MAX_SUBPICTURES; i_subpic++ )
360
    {
361 362 363 364 365 366
        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
367 368 369 370
                /* 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 */
371
                p_vout->p_subpicture[i_subpic].i_status = RESERVED_SUBPICTURE;
372
#ifdef DEBUG_VIDEO
373 374
                intf_DbgMsg("subpicture %p (in destroyed subpicture slot)\n",
                            &p_vout->p_subpicture[i_subpic] );
375
#endif
376 377 378 379 380 381 382 383 384 385
                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];
            }
        }
386
        else if( (p_free_subpic == NULL) &&
387 388
                 (p_vout->p_subpicture[i_subpic].i_status == FREE_SUBPICTURE ))
        {
389
            /* Subpicture is empty and ready for allocation */
390 391 392 393 394 395
            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 ) )
396
    {
Sam Hocevar's avatar
NEWS:  
Sam Hocevar committed
397 398
        /* No free subpicture or matching destroyed subpicture has been
         * found, but a destroyed subpicture is still avalaible */
399
        free( p_destroyed_subpic->p_data );
400 401 402 403 404 405 406 407 408 409 410
        p_free_subpic = p_destroyed_subpic;
    }

    /*
     * Prepare subpicture
     */
    if( p_free_subpic != NULL )
    {
        /* Allocate memory */
        switch( i_type )
        {
411 412
        case TEXT_SUBPICTURE:                             /* text subpicture */
            p_free_subpic->p_data = malloc( i_size + 1 );
413
            break;
414 415 416
        case DVD_SUBPICTURE:                          /* DVD subpicture unit */
            p_free_subpic->p_data = malloc( i_size );
            break;
417 418 419
#ifdef DEBUG
        default:
            intf_DbgMsg("error: unknown subpicture type %d\n", i_type );
420 421 422
            p_free_subpic->p_data   =  NULL;
            break;
#endif
423 424 425
        }

        if( p_free_subpic->p_data != NULL )
426
        {           /* Copy subpicture informations, set some default values */
427 428
            p_free_subpic->i_type                      = i_type;
            p_free_subpic->i_status                    = RESERVED_SUBPICTURE;
429
            p_free_subpic->i_size                      = i_size;
430
            p_free_subpic->i_x                         = 0;
431
            p_free_subpic->i_y                         = 0;
432 433
            p_free_subpic->i_width                     = 0;
            p_free_subpic->i_height                    = 0;
434 435
            p_free_subpic->i_horizontal_align          = CENTER_RALIGN;
            p_free_subpic->i_vertical_align            = CENTER_RALIGN;
436 437 438 439
        }
        else
        {
            /* Memory allocation failed : set subpicture as empty */
440 441 442 443
            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 ) );
444
        }
445

446
#ifdef DEBUG_VIDEO
447
        intf_DbgMsg("subpicture %p (in free subpicture slot)\n", p_free_subpic );
448 449 450 451
#endif
        vlc_mutex_unlock( &p_vout->subpicture_lock );
        return( p_free_subpic );
    }
452

453 454 455 456
    /* 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
457 458
}

459
/*****************************************************************************
460
 * vout_DestroySubPicture: remove a subpicture from the heap
461
 *****************************************************************************
462
 * This function frees a previously reserved subpicture.
Vincent Seguin's avatar
Vincent Seguin committed
463
 * It is meant to be used when the construction of a picture aborted.
464
 * This function does not need locking since reserved subpictures are ignored
465
 * by the output thread.
466
 *****************************************************************************/
467
void vout_DestroySubPicture( vout_thread_t *p_vout, subpicture_t *p_subpic )
Vincent Seguin's avatar
Vincent Seguin committed
468 469
{
#ifdef DEBUG
470 471
   /* Check if status is valid */
   if( p_subpic->i_status != RESERVED_SUBPICTURE )
Vincent Seguin's avatar
Vincent Seguin committed
472
   {
473 474 475
       intf_DbgMsg("error: subpicture %p has invalid status %d\n",
                   p_subpic, p_subpic->i_status );
   }
Vincent Seguin's avatar
Vincent Seguin committed
476 477
#endif

478
    p_subpic->i_status = DESTROYED_SUBPICTURE;
Vincent Seguin's avatar
Vincent Seguin committed
479 480

#ifdef DEBUG_VIDEO
481
    intf_DbgMsg("subpicture %p\n", p_subpic);
Vincent Seguin's avatar
Vincent Seguin committed
482 483 484
#endif
}

485
/*****************************************************************************
Vincent Seguin's avatar
Vincent Seguin committed
486
 * vout_DisplayPicture: display a picture
487
 *****************************************************************************
Vincent Seguin's avatar
Vincent Seguin committed
488
 * Remove the reservation flag of a picture, which will cause it to be ready for
489
 * display. The picture won't be displayed until vout_DatePicture has been
490
 * called.
491
 *****************************************************************************/
Vincent Seguin's avatar
Vincent Seguin committed
492
void  vout_DisplayPicture( vout_thread_t *p_vout, picture_t *p_pic )
Michel Kaempf's avatar
Michel Kaempf committed
493
{
494 495
    vlc_mutex_lock( &p_vout->picture_lock );
    switch( p_pic->i_status )
496
    {
497
    case RESERVED_PICTURE:
498
        p_pic->i_status = RESERVED_DISP_PICTURE;
499
        break;
500 501
    case RESERVED_DATED_PICTURE:
        p_pic->i_status = READY_PICTURE;
502
        break;
503
#ifdef DEBUG
504 505 506
    default:
        intf_DbgMsg("error: picture %p has invalid status %d\n", p_pic, p_pic->i_status );
        break;
507
#endif
508
    }
Michel Kaempf's avatar
Michel Kaempf committed
509

510
#ifdef DEBUG_VIDEO
Vincent Seguin's avatar
Vincent Seguin committed
511
    intf_DbgMsg("picture %p\n", p_pic);
512
#endif
513
    vlc_mutex_unlock( &p_vout->picture_lock );
Michel Kaempf's avatar
Michel Kaempf committed
514 515
}

516
/*****************************************************************************
517
 * vout_DatePicture: date a picture
518
 *****************************************************************************
519
 * Remove the reservation flag of a picture, which will cause it to be ready for
520
 * display. The picture won't be displayed until vout_DisplayPicture has been
521
 * called.
522
 *****************************************************************************/
523 524
void  vout_DatePicture( vout_thread_t *p_vout, picture_t *p_pic, mtime_t date )
{
Vincent Seguin's avatar
Vincent Seguin committed
525
#ifdef DEBUG_VIDEO
526
    char        psz_date[MSTRTIME_MAX_SIZE];                         /* date */
Vincent Seguin's avatar
Vincent Seguin committed
527 528
#endif

529
    vlc_mutex_lock( &p_vout->picture_lock );
530
    p_pic->date = date;
531 532
    switch( p_pic->i_status )
    {
533
    case RESERVED_PICTURE:
534
        p_pic->i_status = RESERVED_DATED_PICTURE;
535
        break;
536 537
    case RESERVED_DISP_PICTURE:
        p_pic->i_status = READY_PICTURE;
538
        break;
539
#ifdef DEBUG
540 541 542
    default:
        intf_DbgMsg("error: picture %p has invalid status %d\n", p_pic, p_pic->i_status );
        break;
543 544 545 546
#endif
    }

#ifdef DEBUG_VIDEO
Vincent Seguin's avatar
Vincent Seguin committed
547
    intf_DbgMsg("picture %p, display date: %s\n", p_pic, mstrtime( psz_date, p_pic->date) );
548
#endif
549
    vlc_mutex_unlock( &p_vout->picture_lock );
550 551
}

552
/*****************************************************************************
Vincent Seguin's avatar
Vincent Seguin committed
553
 * vout_CreatePicture: allocate a picture in the video output heap.
554 555
 *****************************************************************************
 * This function create a reserved image in the video output heap.
Vincent Seguin's avatar
Vincent Seguin committed
556
 * A null pointer is returned if the function fails. This method provides an
557
 * already allocated zone of memory in the picture data fields. It needs locking
558 559 560
 * since several pictures can be created by several producers threads.
 *****************************************************************************/
picture_t *vout_CreatePicture( vout_thread_t *p_vout, int i_type,
561
                               int i_width, int i_height )
Michel Kaempf's avatar
Michel Kaempf committed
562
{
563 564 565 566
    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
567

Vincent Seguin's avatar
Vincent Seguin committed
568
    /* Get lock */
Vincent Seguin's avatar
Vincent Seguin committed
569
    vlc_mutex_lock( &p_vout->picture_lock );
Michel Kaempf's avatar
Michel Kaempf committed
570

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

Vincent Seguin's avatar
Vincent Seguin committed
612 613
    /* If no free picture is available, use a destroyed picture */
    if( (p_free_picture == NULL) && (p_destroyed_picture != NULL ) )
614
    {
615 616
        /* No free picture or matching destroyed picture has been found, but
         * a destroyed picture is still avalaible */
617 618
        free( p_destroyed_picture->p_data );
        p_free_picture = p_destroyed_picture;
Michel Kaempf's avatar
Michel Kaempf committed
619 620
    }

Vincent Seguin's avatar
Vincent Seguin committed
621 622 623 624 625 626 627
    /*
     * Prepare picture
     */
    if( p_free_picture != NULL )
    {
        /* Allocate memory */
        switch( i_type )
Michel Kaempf's avatar
Michel Kaempf committed
628
        {
629 630
        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
631
            p_free_picture->p_data = malloc( i_height * i_chroma_width * 3 * sizeof( yuv_data_t ) );
632
            p_free_picture->p_y = (yuv_data_t *)p_free_picture->p_data;
Vincent Seguin's avatar
Vincent Seguin committed
633 634
            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;
635
            break;
636 637
        case YUV_422_PICTURE:        /* YUV 422: 1,1/2,1/2 samples per pixel */
            i_chroma_width = i_width / 2;
638 639
            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
640 641
            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;
642
            break;
643 644
        case YUV_444_PICTURE:            /* YUV 444: 1,1,1 samples per pixel */
            i_chroma_width = i_width;
645 646
            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
647 648
            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;
649
            break;
Vincent Seguin's avatar
Vincent Seguin committed
650 651
#ifdef DEBUG
        default:
652
            intf_DbgMsg("error: unknown picture type %d\n", i_type );
653 654 655
            p_free_picture->p_data   =  NULL;
            break;
#endif
Michel Kaempf's avatar
Michel Kaempf committed
656 657
        }

Vincent Seguin's avatar
Vincent Seguin committed
658
        if( p_free_picture->p_data != NULL )
659
        {
660
            /* Copy picture informations, set some default values */
661 662
            p_free_picture->i_type                      = i_type;
            p_free_picture->i_status                    = RESERVED_PICTURE;
663
            p_free_picture->i_matrix_coefficients       = 1;
664 665
            p_free_picture->i_width                     = i_width;
            p_free_picture->i_height                    = i_height;
666
            p_free_picture->i_chroma_width              = i_chroma_width;
667
            p_free_picture->i_display_horizontal_offset = 0;
668
            p_free_picture->i_display_vertical_offset   = 0;
669 670
            p_free_picture->i_display_width             = i_width;
            p_free_picture->i_display_height            = i_height;
671 672
            p_free_picture->i_aspect_ratio              = AR_SQUARE_PICTURE;
            p_free_picture->i_refcount                  = 0;
673
            p_vout->i_pictures++;
Vincent Seguin's avatar
Vincent Seguin committed
674 675 676 677
        }
        else
        {
            /* Memory allocation failed : set picture as empty */
678 679 680 681
            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
682
        }
683

684
#ifdef DEBUG_VIDEO
685
        intf_DbgMsg("picture %p (in free picture slot)\n", p_free_picture );
686
#endif
Vincent Seguin's avatar
Vincent Seguin committed
687
        vlc_mutex_unlock( &p_vout->picture_lock );
Vincent Seguin's avatar
Vincent Seguin committed
688
        return( p_free_picture );
Michel Kaempf's avatar
Michel Kaempf committed
689
    }
690

691
    /* No free or destroyed picture could be found */
692
    intf_DbgMsg( "warning: heap is full\n" );
Vincent Seguin's avatar
Vincent Seguin committed
693
    vlc_mutex_unlock( &p_vout->picture_lock );
Vincent Seguin's avatar
Vincent Seguin committed
694
    return( NULL );
Michel Kaempf's avatar
Michel Kaempf committed
695 696
}

697
/*****************************************************************************
698
 * vout_DestroyPicture: remove a permanent or reserved picture from the heap
699
 *****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
700
 * This function frees a previously reserved picture or a permanent
Vincent Seguin's avatar
Vincent Seguin committed
701 702
 * 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 !
703
 *****************************************************************************/
Vincent Seguin's avatar
Vincent Seguin committed
704
void vout_DestroyPicture( vout_thread_t *p_vout, picture_t *p_pic )
Michel Kaempf's avatar
Michel Kaempf committed
705
{
706
   vlc_mutex_lock( &p_vout->picture_lock );
707

708
#ifdef DEBUG
709
   /* Check if picture status is valid */
710
   if( (p_pic->i_status != RESERVED_PICTURE) &&
711 712
       (p_pic->i_status != RESERVED_DATED_PICTURE) &&
       (p_pic->i_status != RESERVED_DISP_PICTURE) )
713
   {
714 715
       intf_DbgMsg("error: picture %p has invalid status %d\n", p_pic, p_pic->i_status );
   }
716 717
#endif

718
   p_pic->i_status = DESTROYED_PICTURE;
719
   p_vout->i_pictures--;
720 721

#ifdef DEBUG_VIDEO
722
   intf_DbgMsg("picture %p\n", p_pic);
723
#endif
724
   vlc_mutex_unlock( &p_vout->picture_lock );
Michel Kaempf's avatar
Michel Kaempf committed
725 726
}

727
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
728
 * vout_LinkPicture: increment reference counter of a picture
729
 *****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
730
 * This function increment the reference counter of a picture in the video
731
 * heap. It needs a lock since several producer threads can access the picture.
732
 *****************************************************************************/
Michel Kaempf's avatar
Michel Kaempf committed
733 734
void vout_LinkPicture( vout_thread_t *p_vout, picture_t *p_pic )
{
Vincent Seguin's avatar
Vincent Seguin committed
735
    vlc_mutex_lock( &p_vout->picture_lock );
Michel Kaempf's avatar
Michel Kaempf committed
736
    p_pic->i_refcount++;
737 738

#ifdef DEBUG_VIDEO
739
    intf_DbgMsg("picture %p refcount=%d\n", p_pic, p_pic->i_refcount );
740
#endif
741 742

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

745
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
746
 * vout_UnlinkPicture: decrement reference counter of a picture
747
 *****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
748
 * This function decrement the reference counter of a picture in the video heap.
749
 *****************************************************************************/
Michel Kaempf's avatar
Michel Kaempf committed
750 751
void vout_UnlinkPicture( vout_thread_t *p_vout, picture_t *p_pic )
{
Vincent Seguin's avatar
Vincent Seguin committed
752
    vlc_mutex_lock( &p_vout->picture_lock );
Michel Kaempf's avatar
Michel Kaempf committed
753
    p_pic->i_refcount--;
754 755 756 757 758

#ifdef DEBUG_VIDEO
    if( p_pic->i_refcount < 0 )
    {
        intf_DbgMsg("error: refcount < 0\n");
759 760
        p_pic->i_refcount = 0;
    }
761 762
#endif

Vincent Seguin's avatar
Vincent Seguin committed
763
    if( (p_pic->i_refcount == 0) && (p_pic->i_status == DISPLAYED_PICTURE) )
Michel Kaempf's avatar
Michel Kaempf committed
764
    {
765
        p_pic->i_status = DESTROYED_PICTURE;
766
        p_vout->i_pictures--;
Michel Kaempf's avatar
Michel Kaempf committed
767
    }
768 769

#ifdef DEBUG_VIDEO
770
    intf_DbgMsg("picture %p refcount=%d\n", p_pic, p_pic->i_refcount );
771
#endif
772 773

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

776
/*****************************************************************************
777
 * vout_SetBuffers: set buffers adresses
778 779
 *****************************************************************************
 * This function is called by system drivers to set buffers video memory
780
 * adresses.
781
 *****************************************************************************/
782
void vout_SetBuffers( vout_thread_t *p_vout, void *p_buf1, void *p_buf2 )
783 784
{
    /* No picture previously */
785 786 787 788 789 790 791 792
    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;
793 794

    /* The first area covers all the screen */
795 796 797 798 799 800 801 802
    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 */
803 804
    p_vout->p_buffer[0].p_data = p_buf1;
    p_vout->p_buffer[1].p_data = p_buf2;
805 806
}

Vincent Seguin's avatar
Vincent Seguin committed
807 808 809 810 811 812 813 814 815 816 817