video_output.c 81.7 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 174 175
        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;
176
    }
177
    p_vout->i_pictures = 0;
178 179 180

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

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

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

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

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

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

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

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

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

Michel Kaempf's avatar
Michel Kaempf committed
286 287 288 289
    /* Request thread destruction */
    p_vout->b_die = 1;

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

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

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

    /* Remove reservation flag */
324
    p_subpic->i_status = READY_SUBPICTURE;
Vincent Seguin's avatar
Vincent Seguin committed
325 326

#ifdef DEBUG_VIDEO
327
    /* Send subpicture informations */
328 329 330 331
    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
332 333 334
#endif
}

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

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

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

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

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

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

450 451 452 453
    /* 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
454 455
}

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

475
    p_subpic->i_status = DESTROYED_SUBPICTURE;
Vincent Seguin's avatar
Vincent Seguin committed
476 477

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

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

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

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

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

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

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

Vincent Seguin's avatar
Vincent Seguin committed
565
    /* Get lock */
Vincent Seguin's avatar
Vincent Seguin committed
566
    vlc_mutex_lock( &p_vout->picture_lock );
Michel Kaempf's avatar
Michel Kaempf committed
567

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

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

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

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

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

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

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

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

715
   p_pic->i_status = DESTROYED_PICTURE;
716
   p_vout->i_pictures--;
717 718

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

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

#ifdef DEBUG_VIDEO
736
    intf_DbgMsg("picture %p refcount=%d\n", p_pic, p_pic->i_refcount );
737
#endif
738 739

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

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

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

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

#ifdef DEBUG_VIDEO
767
    intf_DbgMsg("picture %p refcount=%d\n", p_pic, p_pic->i_refcount );
768
#endif
769 770

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

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

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

Vincent Seguin's avatar
Vincent Seguin committed
804 805 806 807 808 809 810 811 812 813 814 815 816
/*****************************************************************************
 * 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
817 818
/* following functions are local */

Vincent Seguin's avatar
Vincent Seguin committed
819 820 821
/*****************************************************************************
 * BinaryLog: computes the base 2 log of a binary value
 *****************************************************************************
822
 * This functions is used by MaskToShift, to get a bit index from a binary
Vincent Seguin's avatar
Vincent Seguin committed
823 824 825 826 827 828 829
 * value.
 *****************************************************************************/
static int BinaryLog(u32 i)
{
    int i_log;

    i_log = 0;
830 831
    if (i & 0xffff0000)
    {
Vincent Seguin's avatar
Vincent Seguin committed
832
        i_log = 16;
833 834 835
    }
    if (i & 0xff00ff00)
    {
Vincent Seguin's avatar
Vincent Seguin committed
836
        i_log += 8;
837 838 839
    }
    if (i & 0xf0f0f0f0)
    {
Vincent Seguin's avatar
Vincent Seguin committed
840
        i_log += 4;
841 842 843
    }
    if (i & 0xcccccccc)
    {
Vincent Seguin's avatar
Vincent Seguin committed
844
        i_log += 2;
845 846 847
    }
    if (i & 0xaaaaaaaa)
    {
Vincent Seguin's avatar
Vincent Seguin committed
848
        i_log++;
849
    }
Vincent Seguin's avatar
Vincent Seguin committed
850
    if (i != ((u32)1 << i_log))
851
    {
852
        intf_ErrMsg("internal error: binary log overflow\n");
853
    }
Vincent Seguin's avatar
Vincent Seguin committed
854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879

    return( i_log );
}

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

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

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

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

880
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
881
 * InitThread: initialize video output thread
882
 *****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
883 884 885
 * This function is called from RunThread and performs the second step of the
 * initialization. It returns 0 on success. Note that the thread's flag are not
 * modified inside this function.
886
 *****************************************************************************/
Michel Kaempf's avatar
Michel Kaempf committed
887 888 889
static int InitThread( vout_thread_t *p_vout )
{
    /* Update status */
890
    intf_DbgMsg("\n");
891
    *p_vout->pi_status = THREAD_START;
Michel Kaempf's avatar
Michel Kaempf committed
892

893
   /* Initialize output method - this function issues its own error messages */
894
    if( p_vout->p_sys_init( p_vout ) )
Michel Kaempf's avatar
Michel Kaempf committed
895 896
    {
        return( 1 );
897
    }
Michel Kaempf's avatar
Michel Kaempf committed
898

899
    /* Initialize convertion tables and functions */
900
    if( vout_InitYUV( p_vout ) )
901
    {
902
        intf_ErrMsg("error: can't allocate YUV translation tables\n");
903
        return( 1 );
Vincent Seguin's avatar
Vincent Seguin committed
904
    }
905

Michel Kaempf's avatar
Michel Kaempf committed
906
    /* Mark thread as running and return */
907 908 909 910
    p_vout->b_active =          1;
    *p_vout->pi_status =        THREAD_READY;
    intf_DbgMsg("thread ready\n");
    return( 0 );
Michel Kaempf's avatar
Michel Kaempf committed
911 912
}

913
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
914
 * RunThread: video output thread
915
 *****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
916 917 918
 * Video output thread. This function does only returns when the thread is
 * terminated. It handles the pictures arriving in the video heap and the
 * display device events.
919
 *****************************************************************************/
Michel Kaempf's avatar
Michel Kaempf committed
920 921
static void RunThread( vout_thread_t *p_vout)
{