video_output.c 82.9 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 */
Sam Hocevar's avatar
Sam Hocevar committed
118 119 120 121 122 123 124 125 126 127 128 129
    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" );
130

131
    /* Initialize thread properties - thread id and locks will be initialized
132
     * later */
133
    p_vout->b_die               = 0;
134
    p_vout->b_error             = 0;
135 136
    p_vout->b_active            = 0;
    p_vout->pi_status           = (pi_status != NULL) ? pi_status : &i_status;
137
    *p_vout->pi_status          = THREAD_CREATE;
138

139
    /* Initialize some fields used by the system-dependant method - these fields will
140
     * probably be modified by the method, and are only preferences */
141
    p_vout->i_changes           = 0;
142 143
    p_vout->i_width             = i_width;
    p_vout->i_height            = i_height;
144
    p_vout->i_bytes_per_line    = i_width * 2;
145 146
    p_vout->i_screen_depth      = 15;
    p_vout->i_bytes_per_pixel   = 2;
147
    p_vout->f_gamma             = VOUT_GAMMA;
148

Sam Hocevar's avatar
Sam Hocevar committed
149 150
    p_vout->b_grayscale         = main_GetIntVariable( VOUT_GRAYSCALE_VAR,
                                                       VOUT_GRAYSCALE_DEFAULT );
151
    p_vout->b_info              = 0;
152 153
    p_vout->b_interface         = 0;
    p_vout->b_scale             = 0;
154 155

    p_vout->p_set_palette       = SetPalette;
156

Sam Hocevar's avatar
Sam Hocevar committed
157 158 159
    intf_DbgMsg( "wished configuration: %dx%d, %d/%d bpp (%d Bpl)\n",
                 p_vout->i_width, p_vout->i_height, p_vout->i_screen_depth,
                 p_vout->i_bytes_per_pixel * 8, p_vout->i_bytes_per_line );
160

161 162
    /* Initialize idle screen */
    p_vout->last_display_date   = mdate();
163
    p_vout->last_display_date   = 0;
164 165
    p_vout->last_idle_date      = 0;

166 167
#ifdef STATS
    /* Initialize statistics fields */
168 169 170
    p_vout->render_time         = 0;
    p_vout->c_fps_samples       = 0;
#endif
171 172 173 174

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

175
    /* Initialize pictures and subpictures - translation tables and functions
176
     * will be initialized later in InitThread */
177 178
    for( i_index = 0; i_index < VOUT_MAX_PICTURES; i_index++)
    {
179 180
        p_vout->p_picture[i_index].i_type   =   EMPTY_PICTURE;
        p_vout->p_picture[i_index].i_status =   FREE_PICTURE;
181 182 183
    }
    for( i_index = 0; i_index < VOUT_MAX_SUBPICTURES; i_index++)
    {
184 185
        p_vout->p_subpicture[i_index].i_type  = EMPTY_SUBPICTURE;
        p_vout->p_subpicture[i_index].i_status= FREE_SUBPICTURE;
186
    }
187
    p_vout->i_pictures = 0;
188 189 190

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

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

210
    /* Set some useful colors */
211
    p_vout->i_white_pixel = RGB2PIXEL( p_vout, 255, 255, 255 );
Vincent Seguin's avatar
Vincent Seguin committed
212 213
    p_vout->i_black_pixel = RGB2PIXEL( p_vout, 0, 0, 0 );
    p_vout->i_gray_pixel  = RGB2PIXEL( p_vout, 128, 128, 128 );
214
    p_vout->i_blue_pixel  = RGB2PIXEL( p_vout, 0, 0, 50 );
215

216 217
    /* Load fonts - fonts must be initialized after the system method since
     * they may be dependant on screen depth and other thread properties */
218 219 220 221 222
    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
223 224
    if( p_vout->p_default_font == NULL )
    {
225
        p_vout->p_sys_destroy( p_vout );
226
        TrashPlugin( p_vout->vout_plugin );
227 228 229
        free( p_vout );
        return( NULL );
    }
230 231 232 233 234
    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
235 236
    if( p_vout->p_large_font == NULL )
    {
237
        vout_UnloadFont( p_vout->p_default_font );
238
        p_vout->p_sys_destroy( p_vout );
239
        TrashPlugin( p_vout->vout_plugin );
240 241 242
        free( p_vout );
        return( NULL );
    }
Vincent Seguin's avatar
Vincent Seguin committed
243

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

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

Michel Kaempf's avatar
Michel Kaempf committed
263 264 265 266
    /* If status is NULL, wait until the thread is created */
    if( pi_status == NULL )
    {
        do
267
        {
Michel Kaempf's avatar
Michel Kaempf committed
268
            msleep( THREAD_SLEEP );
269
        }while( (i_status != THREAD_READY) && (i_status != THREAD_ERROR)
Michel Kaempf's avatar
Michel Kaempf committed
270 271 272
                && (i_status != THREAD_FATAL) );
        if( i_status != THREAD_READY )
        {
273 274
            return( NULL );
        }
Michel Kaempf's avatar
Michel Kaempf committed
275 276 277 278
    }
    return( p_vout );
}

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

    /* Set status */
292
    intf_DbgMsg("\n");
Michel Kaempf's avatar
Michel Kaempf committed
293
    p_vout->pi_status = (pi_status != NULL) ? pi_status : &i_status;
294 295
    *p_vout->pi_status = THREAD_DESTROY;

Michel Kaempf's avatar
Michel Kaempf committed
296 297 298 299
    /* Request thread destruction */
    p_vout->b_die = 1;

    /* If status is NULL, wait until thread has been destroyed */
300
    if( pi_status == NULL )
Michel Kaempf's avatar
Michel Kaempf committed
301 302 303 304
    {
        do
        {
            msleep( THREAD_SLEEP );
305 306
        }while( (i_status != THREAD_OVER) && (i_status != THREAD_ERROR)
                && (i_status != THREAD_FATAL) );
Michel Kaempf's avatar
Michel Kaempf committed
307 308 309
    }
}

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

#ifdef DEBUG
    /* Check if status is valid */
326
    if( p_subpic->i_status != RESERVED_SUBPICTURE )
Vincent Seguin's avatar
Vincent Seguin committed
327
    {
328 329 330
        intf_DbgMsg("error: subpicture %p has invalid status %d\n", p_subpic,
                    p_subpic->i_status );
    }
Vincent Seguin's avatar
Vincent Seguin committed
331 332 333
#endif

    /* Remove reservation flag */
334
    p_subpic->i_status = READY_SUBPICTURE;
Vincent Seguin's avatar
Vincent Seguin committed
335 336

#ifdef DEBUG_VIDEO
337
    /* Send subpicture informations */
338 339 340 341
    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
342 343 344
#endif
}

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

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

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

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

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

453
#ifdef DEBUG_VIDEO
454
        intf_DbgMsg("subpicture %p (in free subpicture slot)\n", p_free_subpic );
455 456 457 458
#endif
        vlc_mutex_unlock( &p_vout->subpicture_lock );
        return( p_free_subpic );
    }
459

460 461 462 463
    /* 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
464 465
}

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

485
    p_subpic->i_status = DESTROYED_SUBPICTURE;
Vincent Seguin's avatar
Vincent Seguin committed
486 487

#ifdef DEBUG_VIDEO
488
    intf_DbgMsg("subpicture %p\n", p_subpic);
Vincent Seguin's avatar
Vincent Seguin committed
489 490 491
#endif
}

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

517
#ifdef DEBUG_VIDEO
Vincent Seguin's avatar
Vincent Seguin committed
518
    intf_DbgMsg("picture %p\n", p_pic);
519
#endif
520
    vlc_mutex_unlock( &p_vout->picture_lock );
Michel Kaempf's avatar
Michel Kaempf committed
521 522
}

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

536
    vlc_mutex_lock( &p_vout->picture_lock );
537
    p_pic->date = date;
538 539
    switch( p_pic->i_status )
    {
540
    case RESERVED_PICTURE:
541
        p_pic->i_status = RESERVED_DATED_PICTURE;
542
        break;
543 544
    case RESERVED_DISP_PICTURE:
        p_pic->i_status = READY_PICTURE;
545
        break;
546
#ifdef DEBUG
547 548 549
    default:
        intf_DbgMsg("error: picture %p has invalid status %d\n", p_pic, p_pic->i_status );
        break;
550 551 552 553
#endif
    }

#ifdef DEBUG_VIDEO
Vincent Seguin's avatar
Vincent Seguin committed
554
    intf_DbgMsg("picture %p, display date: %s\n", p_pic, mstrtime( psz_date, p_pic->date) );
555
#endif
556
    vlc_mutex_unlock( &p_vout->picture_lock );
557 558
}

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

Vincent Seguin's avatar
Vincent Seguin committed
575
    /* Get lock */
Vincent Seguin's avatar
Vincent Seguin committed
576
    vlc_mutex_lock( &p_vout->picture_lock );
Michel Kaempf's avatar
Michel Kaempf committed
577

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

Vincent Seguin's avatar
Vincent Seguin committed
619 620
    /* If no free picture is available, use a destroyed picture */
    if( (p_free_picture == NULL) && (p_destroyed_picture != NULL ) )
621
    {
622 623
        /* No free picture or matching destroyed picture has been found, but
         * a destroyed picture is still avalaible */
624 625
        free( p_destroyed_picture->p_data );
        p_free_picture = p_destroyed_picture;
Michel Kaempf's avatar
Michel Kaempf committed
626 627
    }

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

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

691
#ifdef DEBUG_VIDEO
692
        intf_DbgMsg("picture %p (in free picture slot)\n", p_free_picture );
693
#endif
Vincent Seguin's avatar
Vincent Seguin committed
694
        vlc_mutex_unlock( &p_vout->picture_lock );
Vincent Seguin's avatar
Vincent Seguin committed
695
        return( p_free_picture );
Michel Kaempf's avatar
Michel Kaempf committed
696
    }
697

698
    /* No free or destroyed picture could be found */
699
    intf_DbgMsg( "warning: heap is full\n" );
Vincent Seguin's avatar
Vincent Seguin committed
700
    vlc_mutex_unlock( &p_vout->picture_lock );
Vincent Seguin's avatar
Vincent Seguin committed
701
    return( NULL );
Michel Kaempf's avatar
Michel Kaempf committed
702 703
}

704
/*****************************************************************************
705
 * vout_DestroyPicture: remove a permanent or reserved picture from the heap
706
 *****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
707
 * This function frees a previously reserved picture or a permanent
Vincent Seguin's avatar
Vincent Seguin committed
708 709
 * 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 !
710
 *****************************************************************************/
Vincent Seguin's avatar
Vincent Seguin committed
711
void vout_DestroyPicture( vout_thread_t *p_vout, picture_t *p_pic )
Michel Kaempf's avatar
Michel Kaempf committed
712
{
713
   vlc_mutex_lock( &p_vout->picture_lock );
714

715
#ifdef DEBUG
716
   /* Check if picture status is valid */
717
   if( (p_pic->i_status != RESERVED_PICTURE) &&
718 719
       (p_pic->i_status != RESERVED_DATED_PICTURE) &&
       (p_pic->i_status != RESERVED_DISP_PICTURE) )
720
   {
721 722
       intf_DbgMsg("error: picture %p has invalid status %d\n", p_pic, p_pic->i_status );
   }
723 724
#endif

725
   p_pic->i_status = DESTROYED_PICTURE;
726
   p_vout->i_pictures--;
727 728

#ifdef DEBUG_VIDEO
729
   intf_DbgMsg("picture %p\n", p_pic);
730
#endif
731
   vlc_mutex_unlock( &p_vout->picture_lock );
Michel Kaempf's avatar
Michel Kaempf committed
732 733
}

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

#ifdef DEBUG_VIDEO
746
    intf_DbgMsg("picture %p refcount=%d\n", p_pic, p_pic->i_refcount );
747
#endif
748 749

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

752
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
753
 * vout_UnlinkPicture: decrement reference counter of a picture
754
 *****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
755
 * This function decrement the reference counter of a picture in the video heap.
756
 *****************************************************************************/
Michel Kaempf's avatar
Michel Kaempf committed
757 758
void vout_UnlinkPicture( vout_thread_t *p_vout, picture_t *p_pic )
{
Vincent Seguin's avatar
Vincent Seguin committed
759
    vlc_mutex_lock( &p_vout->picture_lock );
Michel Kaempf's avatar
Michel Kaempf committed
760
    p_pic->i_refcount--;
761 762 763 764 765

#ifdef DEBUG_VIDEO
    if( p_pic->i_refcount < 0 )
    {
        intf_DbgMsg("error: refcount < 0\n");
766 767
        p_pic->i_refcount = 0;
    }
768 769
#endif

Vincent Seguin's avatar
Vincent Seguin committed
770
    if( (p_pic->i_refcount == 0) && (p_pic->i_status == DISPLAYED_PICTURE) )
Michel Kaempf's avatar
Michel Kaempf committed
771
    {
772
        p_pic->i_status = DESTROYED_PICTURE;
773
        p_vout->i_pictures--;
Michel Kaempf's avatar
Michel Kaempf committed
774
    }
775 776

#ifdef DEBUG_VIDEO
777
    intf_DbgMsg("picture %p refcount=%d\n", p_pic, p_pic->i_refcount );
778
#endif
779 780

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

783
/*****************************************************************************
784
 * vout_SetBuffers: set buffers adresses
785 786
 *****************************************************************************
 * This function is called by system drivers to set buffers video memory
787
 * adresses.
788
 *****************************************************************************/
789
void vout_SetBuffers( vout_thread_t *p_vout, void *p_buf1, void *p_buf2 )
790 791
{
    /* No picture previously */
792 793 794 795 796 797 798 799
    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;
800 801

    /* The first area covers all the screen */
802 803 804 805 806 807 808 809
    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 */
810 811
    p_vout->p_buffer[0].p_data = p_buf1;
    p_vout->p_buffer[1].p_data = p_buf2;
812 813
}

Vincent Seguin's avatar
Vincent Seguin committed
814 815 816 817 818 819 820 821 822 823 824 825 826
/*****************************************************************************
 * 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
827 828
/* following functions are local */

Vincent Seguin's avatar
Vincent Seguin committed
829 830 831
/*****************************************************************************
 * BinaryLog: computes the base 2 log of a binary value
 *****************************************************************************
832
 * This functions is used by MaskToShift, to get a bit index from a binary
Vincent Seguin's avatar
Vincent Seguin committed
833 834 835 836 837 838 839
 * value.
 *****************************************************************************/
static int BinaryLog(u32 i)
{
    int i_log;

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

    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);
}

890
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
891
 * InitThread: initialize video output thread
892
 *****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
893 894 895
 * 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.
896
 *****************************************************************************/
Michel Kaempf's avatar
Michel Kaempf committed
897 898 899
static int InitThread( vout_thread_t *p_vout )
{
    /* Update status */
900
    intf_DbgMsg("\n");
901
    *p_vout->pi_status = THREAD_START;
Michel Kaempf's avatar
Michel Kaempf committed
902

903
   /* Initialize output method - this function issues its own error messages */
904
    if( p_vout->p_sys_init( p_vout ) )
Michel Kaempf's avatar
Michel Kaempf committed
905 906
    {
        return( 1 );
907
    }
Michel Kaempf's avatar
Michel Kaempf committed
908

909
    /* Initialize convertion tables and functions */
910
    if( vout_InitYUV( p_vout ) )
911
    {
912
        intf_ErrMsg("error: can't allocate YUV translation tables\n");
913
        return( 1 );
Vincent Seguin's avatar
Vincent Seguin committed
914
    }
915

Michel Kaempf's avatar
Michel Kaempf committed
916
    /* Mark thread as running and return */
917 918 919 920
    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
921 922
}

923
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
924
 * RunThread: video output thread
925
 *****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
926 927 928
 * 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.