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

/*******************************************************************************
 * Preamble
 *******************************************************************************/
Vincent Seguin's avatar
Vincent Seguin committed
13 14
#include "vlc.h"
/*
Michel Kaempf's avatar
Michel Kaempf committed
15 16 17 18 19 20 21 22 23
#include <errno.h> 
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <X11/Xlib.h>

#include "common.h"
#include "config.h"
#include "mtime.h"
24
#include "vlc_thread.h"
Michel Kaempf's avatar
Michel Kaempf committed
25 26 27 28 29 30
#include "thread.h"

#include "video.h"
#include "video_graphics.h"
#include "video_output.h"
#include "video_x11.h"
Vincent Seguin's avatar
Vincent Seguin committed
31
*/
Michel Kaempf's avatar
Michel Kaempf committed
32 33 34 35 36 37 38 39 40

/*
 * Local prototypes
 */
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 );

Vincent Seguin's avatar
Vincent Seguin committed
41
static void     RenderPicture   ( vout_thread_t *p_vout, picture_t *p_pic );
Michel Kaempf's avatar
Michel Kaempf committed
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58

/*******************************************************************************
 * vout_CreateThread: creates a new video output thread
 *******************************************************************************
 * This function creates a new video output thread, and returns a pointer
 * to its description. On error, it returns NULL.
 * Following configuration properties are used:
 *  VIDEO_CFG_SIZE      video heap maximal size
 *  VIDEO_CFG_WIDTH     window width
 *  VIDEO_CFG_HEIGHT    window height 
 * Using X11 display method (the only one supported yet):
 *  VIDEO_CFG_DISPLAY   display used
 *  VIDEO_CFG_TITLE     window title
 *  VIDEO_CFG_SHM_EXT   try to use XShm extension
 * If pi_status is NULL, then the function will block until the thread is ready.
 * If not, pi_error will be updated using one of the THREAD_* constants.
 *******************************************************************************/
Vincent Seguin's avatar
Vincent Seguin committed
59 60
vout_thread_t * vout_CreateThread               ( 
#if defined(VIDEO_X11)
61
                                                  char *psz_display, Window root_window, 
Vincent Seguin's avatar
Vincent Seguin committed
62 63 64 65 66
#elif defined(VIDEO_FB)
                                                  //??
#endif
                                                  int i_width, int i_height, int *pi_status 
                                                )
Michel Kaempf's avatar
Michel Kaempf committed
67 68 69 70
{
    vout_thread_t * p_vout;                               /* thread descriptor */
    int             i_status;                                 /* thread status */

Vincent Seguin's avatar
Vincent Seguin committed
71
    /* Allocate descriptor and create method */
Michel Kaempf's avatar
Michel Kaempf committed
72 73 74 75 76
    p_vout = (vout_thread_t *) malloc( sizeof(vout_thread_t) );
    if( p_vout == NULL )                                              /* error */
    {
        return( NULL );
    }
Vincent Seguin's avatar
Vincent Seguin committed
77 78 79
    intf_DbgMsg( "0x%x\n", p_vout );
    if( vout_SysCreate( p_vout
#if defined(VIDEO_X11)
80
                        , psz_display, root_window 
Vincent Seguin's avatar
Vincent Seguin committed
81 82 83 84
#elif defined(VIDEO_FB)
                        //??
#endif
        ) )
Michel Kaempf's avatar
Michel Kaempf committed
85
    {
Vincent Seguin's avatar
Vincent Seguin committed
86 87
      free( p_vout );
      return( NULL );
Michel Kaempf's avatar
Michel Kaempf committed
88
    }
Vincent Seguin's avatar
Vincent Seguin committed
89 90 91 92 93 94 95 96 97
  
    /* Initialize */
    p_vout->i_width            = i_width;
    p_vout->i_height           = i_height;
    p_vout->pi_status          = (pi_status != NULL) ? pi_status : &i_status;
    *p_vout->pi_status         = THREAD_CREATE;
    p_vout->b_die              = 0;
    p_vout->b_error            = 0;    
    p_vout->b_active           = 0;
Michel Kaempf's avatar
Michel Kaempf committed
98 99

    /* Create thread and set locks */
Vincent Seguin's avatar
Vincent Seguin committed
100 101 102
    vlc_mutex_init( &p_vout->lock );
    if( vlc_thread_create( &p_vout->thread_id, "video output", 
			   (void *) RunThread, (void *) p_vout) )
Michel Kaempf's avatar
Michel Kaempf committed
103 104
    {
        intf_ErrMsg("vout error: %s\n", strerror(ENOMEM));
Vincent Seguin's avatar
Vincent Seguin committed
105
	vout_SysDestroy( p_vout );
Michel Kaempf's avatar
Michel Kaempf committed
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
        free( p_vout );
        return( NULL );
    }   

    /* If status is NULL, wait until the thread is created */
    if( pi_status == NULL )
    {
        do
        {            
            msleep( THREAD_SLEEP );
        }while( (i_status != THREAD_READY) && (i_status != THREAD_ERROR) 
                && (i_status != THREAD_FATAL) );
        if( i_status != THREAD_READY )
        {
            return( NULL );            
        }        
    }

    return( p_vout );
}

/*******************************************************************************
 * vout_DestroyThread: destroys a previously created thread
 *******************************************************************************
 * Destroy a terminated thread. 
 * The function will request a destruction of the specified thread. If pi_error
 * is NULL, it will return once the thread is destroyed. Else, it will be 
 * update using one of the THREAD_* constants.
 *******************************************************************************/
void vout_DestroyThread( vout_thread_t *p_vout, int *pi_status )
{  
    int     i_status;                                         /* thread status */

Vincent Seguin's avatar
Vincent Seguin committed
139 140
    intf_DbgMsg( "0x%x\n", p_vout );

Michel Kaempf's avatar
Michel Kaempf committed
141 142
    /* Set status */
    p_vout->pi_status = (pi_status != NULL) ? pi_status : &i_status;
Vincent Seguin's avatar
Vincent Seguin committed
143
    *p_vout->pi_status = THREAD_DESTROY;    
Michel Kaempf's avatar
Michel Kaempf committed
144 145 146 147 148
     
    /* Request thread destruction */
    p_vout->b_die = 1;

    /* If status is NULL, wait until thread has been destroyed */
149
    if( pi_status == NULL )
Michel Kaempf's avatar
Michel Kaempf committed
150 151 152 153 154 155 156 157 158 159
    {
        do
        {
            msleep( THREAD_SLEEP );
        }while( (i_status != THREAD_OVER) && (i_status != THREAD_ERROR) 
                && (i_status != THREAD_FATAL) );   
    }
}

/*******************************************************************************
Vincent Seguin's avatar
Vincent Seguin committed
160
 * vout_DisplayPicture: display a picture
Michel Kaempf's avatar
Michel Kaempf committed
161
 *******************************************************************************
Vincent Seguin's avatar
Vincent Seguin committed
162 163
 * Remove the reservation flag of a picture, which will cause it to be ready for
 * display.
Michel Kaempf's avatar
Michel Kaempf committed
164
 *******************************************************************************/
Vincent Seguin's avatar
Vincent Seguin committed
165
void  vout_DisplayPicture( vout_thread_t *p_vout, picture_t *p_pic )
Michel Kaempf's avatar
Michel Kaempf committed
166
{
Vincent Seguin's avatar
Vincent Seguin committed
167
    vlc_mutex_lock( &p_vout->lock );
Michel Kaempf's avatar
Michel Kaempf committed
168 169

    /* Remove reservation flag */
Vincent Seguin's avatar
Vincent Seguin committed
170
    p_pic->i_status = READY_PICTURE;
Michel Kaempf's avatar
Michel Kaempf committed
171 172 173 174 175 176

#ifdef STATS
    /* Update stats */
    p_vout->c_pictures++;
#endif

Vincent Seguin's avatar
Vincent Seguin committed
177
    vlc_mutex_unlock( &p_vout->lock );
Michel Kaempf's avatar
Michel Kaempf committed
178 179 180
}

/*******************************************************************************
Vincent Seguin's avatar
Vincent Seguin committed
181
 * vout_CreatePicture: allocate a picture in the video output heap.
Michel Kaempf's avatar
Michel Kaempf committed
182 183
 *******************************************************************************
 * This function create a reserved image in the video output heap. 
Vincent Seguin's avatar
Vincent Seguin committed
184 185
 * A null pointer is returned if the function fails. This method provides an
 * already allocated zone of memory in the picture data fields.
Michel Kaempf's avatar
Michel Kaempf committed
186
 *******************************************************************************/
Vincent Seguin's avatar
Vincent Seguin committed
187 188
picture_t *vout_CreatePicture( vout_thread_t *p_vout, int i_type, 
			       int i_width, int i_height, int i_bytes_per_line )
Michel Kaempf's avatar
Michel Kaempf committed
189
{
Vincent Seguin's avatar
Vincent Seguin committed
190 191 192
    int         i_picture;                                    /* picture index */
    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
193

Vincent Seguin's avatar
Vincent Seguin committed
194 195
    /* Get lock */
    vlc_mutex_lock( &p_vout->lock );
Michel Kaempf's avatar
Michel Kaempf committed
196

Vincent Seguin's avatar
Vincent Seguin committed
197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231
    /* 
     * Look for an empty place 
     */
    for( i_picture = 0; 
         i_picture < VOUT_MAX_PICTURES; 
         i_picture++ )
    {
	if( p_vout->p_picture[i_picture].i_status == DESTROYED_PICTURE )
	{
	    /* Picture is marked for destruction, but is still allocated */
	    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_bytes_per_line == i_bytes_per_line) )
	    {
		/* Memory size do match : memory will not be reallocated, and function
                 * can end immediately - this is the best possible case, since no
                 * memory allocation needs to be done */
		p_vout->p_picture[i_picture].i_width  = i_width;
		p_vout->p_picture[i_picture].i_status = RESERVED_PICTURE;
		vlc_mutex_unlock( &p_vout->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];                
	    }	    
	}
        else if( (p_free_picture == NULL) && 
                 (p_vout->p_picture[i_picture].i_status == FREE_PICTURE ))
        {
	    /* Picture is empty and ready for allocation */
            p_free_picture = &p_vout->p_picture[i_picture];            
        }
Michel Kaempf's avatar
Michel Kaempf committed
232 233
    }

Vincent Seguin's avatar
Vincent Seguin committed
234 235 236 237 238 239 240
    /* If no free picture is available, use a destroyed picture */
    if( (p_free_picture == NULL) && (p_destroyed_picture != NULL ) )
    { 
	/* No free picture or matching destroyed picture has been found, but
	 * a destroyed picture is still avalaible */
        free( p_destroyed_picture->p_data );        
        p_free_picture = p_destroyed_picture;        
Michel Kaempf's avatar
Michel Kaempf committed
241 242
    }

Vincent Seguin's avatar
Vincent Seguin committed
243 244 245 246 247 248 249
    /*
     * Prepare picture
     */
    if( p_free_picture != NULL )
    {
        /* Allocate memory */
        switch( i_type )
Michel Kaempf's avatar
Michel Kaempf committed
250
        {
251 252
        case YUV_420_PICTURE:           /* YUV picture: 3*16 ?? bits per pixel */
        case YUV_422_PICTURE:
Vincent Seguin's avatar
Vincent Seguin committed
253 254
        case YUV_444_PICTURE:
            p_free_picture->p_data = malloc( 3 * i_height * i_bytes_per_line );                
255 256 257
            p_free_picture->p_y = (yuv_data_t *) p_free_picture->p_data;
            p_free_picture->p_u = (yuv_data_t *)(p_free_picture->p_data + i_height * i_bytes_per_line);
            p_free_picture->p_v = (yuv_data_t *)(p_free_picture->p_data + i_height * i_bytes_per_line * 2);
Vincent Seguin's avatar
Vincent Seguin committed
258 259 260 261 262 263
            break;                
#ifdef DEBUG
        default:
            intf_DbgMsg("0x%x error: unknown picture type %d\n", p_vout, i_type );
            p_free_picture->p_data = NULL;            
#endif    
Michel Kaempf's avatar
Michel Kaempf committed
264 265
        }

Vincent Seguin's avatar
Vincent Seguin committed
266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286
        if( p_free_picture->p_data != NULL )
        {        
            /* Copy picture informations */
            p_free_picture->i_type           = i_type;
            p_free_picture->i_status         = RESERVED_PICTURE;
            p_free_picture->i_width          = i_width;
            p_free_picture->i_height         = i_height;
            p_free_picture->i_bytes_per_line = i_bytes_per_line;
            p_free_picture->i_refcount       = 0;            
        }
        else
        {
            /* Memory allocation failed : set picture as empty */
            p_free_picture->i_type   = EMPTY_PICTURE;            
            p_free_picture->i_status = FREE_PICTURE;            
            p_free_picture = NULL;            
            intf_DbgMsg("0x%x malloc for new picture failed\n");            
        }
        
        vlc_mutex_unlock( &p_vout->lock );
        return( p_free_picture );
Michel Kaempf's avatar
Michel Kaempf committed
287
    }
Vincent Seguin's avatar
Vincent Seguin committed
288 289 290 291 292
    
    // No free or destroyed picture could be found
    intf_DbgMsg("0x%x no picture available\n");
    vlc_mutex_unlock( &p_vout->lock );
    return( NULL );
Michel Kaempf's avatar
Michel Kaempf committed
293 294 295 296 297 298
}

/*******************************************************************************
 * vout_RemovePicture: remove a permanent or reserved picture from the heap
 *******************************************************************************
 * This function frees a previously reserved picture or a permanent
Vincent Seguin's avatar
Vincent Seguin committed
299 300
 * 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 !
Michel Kaempf's avatar
Michel Kaempf committed
301
 *******************************************************************************/
Vincent Seguin's avatar
Vincent Seguin committed
302
void vout_DestroyPicture( vout_thread_t *p_vout, picture_t *p_pic )
Michel Kaempf's avatar
Michel Kaempf committed
303
{
Vincent Seguin's avatar
Vincent Seguin committed
304
    vlc_mutex_lock( &p_vout->lock );
Michel Kaempf's avatar
Michel Kaempf committed
305 306

    /* Mark picture for destruction */
Vincent Seguin's avatar
Vincent Seguin committed
307 308
    p_pic->i_status = DESTROYED_PICTURE;
    intf_DbgMsg("%p -> picture %p destroyed\n", p_vout, p_pic );
Michel Kaempf's avatar
Michel Kaempf committed
309

Vincent Seguin's avatar
Vincent Seguin committed
310
    vlc_mutex_unlock( &p_vout->lock );
Michel Kaempf's avatar
Michel Kaempf committed
311 312 313 314 315 316 317 318 319 320
}

/*******************************************************************************
 * vout_LinkPicture: increment reference counter of a picture
 *******************************************************************************
 * This function increment the reference counter of a picture in the video
 * heap.
 *******************************************************************************/
void vout_LinkPicture( vout_thread_t *p_vout, picture_t *p_pic )
{
Vincent Seguin's avatar
Vincent Seguin committed
321
    vlc_mutex_lock( &p_vout->lock );
Michel Kaempf's avatar
Michel Kaempf committed
322
    p_pic->i_refcount++;
Vincent Seguin's avatar
Vincent Seguin committed
323
    vlc_mutex_unlock( &p_vout->lock );
Michel Kaempf's avatar
Michel Kaempf committed
324 325 326 327 328 329 330 331 332
}

/*******************************************************************************
 * vout_UnlinkPicture: decrement reference counter of a picture
 *******************************************************************************
 * This function decrement the reference counter of a picture in the video heap.
 *******************************************************************************/
void vout_UnlinkPicture( vout_thread_t *p_vout, picture_t *p_pic )
{
Vincent Seguin's avatar
Vincent Seguin committed
333
    vlc_mutex_lock( &p_vout->lock );
Michel Kaempf's avatar
Michel Kaempf committed
334
    p_pic->i_refcount--;
Vincent Seguin's avatar
Vincent Seguin committed
335
    if( (p_pic->i_refcount == 0) && (p_pic->i_status == DISPLAYED_PICTURE) )
Michel Kaempf's avatar
Michel Kaempf committed
336
    {
Vincent Seguin's avatar
Vincent Seguin committed
337
	p_pic->i_status = DESTROYED_PICTURE;
Michel Kaempf's avatar
Michel Kaempf committed
338
    }
Vincent Seguin's avatar
Vincent Seguin committed
339
    vlc_mutex_unlock( &p_vout->lock );    
Michel Kaempf's avatar
Michel Kaempf committed
340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358
}

/* following functions are local */

/*******************************************************************************
 * InitThread: initialize video output thread
 *******************************************************************************
 * 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.
 *******************************************************************************/
static int InitThread( vout_thread_t *p_vout )
{
    int     i_index;                                          /* generic index */    

    /* Update status */
    *p_vout->pi_status = THREAD_START;    
    
    /* Initialize pictures */    
Vincent Seguin's avatar
Vincent Seguin committed
359
    for( i_index = 0; i_index < VOUT_MAX_PICTURES; i_index++)
Michel Kaempf's avatar
Michel Kaempf committed
360
    {
Vincent Seguin's avatar
Vincent Seguin committed
361 362
        p_vout->p_picture[i_index].i_type  = EMPTY_PICTURE;
        p_vout->p_picture[i_index].i_status= FREE_PICTURE;
Michel Kaempf's avatar
Michel Kaempf committed
363 364 365 366 367 368 369 370 371 372 373 374 375
    }

    /* Initialize other properties */
    p_vout->i_pictures = 0;
#ifdef STATS
    p_vout->c_loops = 0;
    p_vout->c_idle_loops = 0;
    p_vout->c_pictures = 0;
    p_vout->c_rendered_pictures = 0;
#endif

    /* Initialize output method - width, height, screen depth and bytes per 
     * pixel are initialized by this call. */
Vincent Seguin's avatar
Vincent Seguin committed
376
    if( vout_SysInit( p_vout ) )                        /* error */
Michel Kaempf's avatar
Michel Kaempf committed
377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399
    {
        *p_vout->pi_status = THREAD_ERROR;        
        return( 1 );
    } 

    /* Mark thread as running and return */
    *p_vout->pi_status = THREAD_READY;    
    intf_DbgMsg("%p -> succeeded\n", p_vout);    
    return(0);    
}

/*******************************************************************************
 * RunThread: video output thread
 *******************************************************************************
 * 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.
 *******************************************************************************/
static void RunThread( vout_thread_t *p_vout)
{
    int             i_picture;                                /* picture index */
    int             i_err;                                       /* error code */
    mtime_t         current_date;                              /* current date */
Vincent Seguin's avatar
Vincent Seguin committed
400
    picture_t *     p_pic = NULL;
Michel Kaempf's avatar
Michel Kaempf committed
401 402 403 404 405 406 407
#ifdef VOUT_DEBUG
    char            sz_date[MSTRTIME_MAX_SIZE];                 /* date buffer */
#endif

    /* 
     * Initialize thread and free configuration 
     */
Vincent Seguin's avatar
Vincent Seguin committed
408
    intf_DbgMsg( "0x%x begin\n", p_vout );
Michel Kaempf's avatar
Michel Kaempf committed
409 410 411 412 413 414 415 416 417 418 419 420 421
    p_vout->b_error = InitThread( p_vout );
    if( p_vout->b_error )
    {
        free( p_vout );                                  /* destroy descriptor */
        return;        
    }    

    /*
     * Main loop - it is not executed if an error occured during
     * initialization
     */
    while( (!p_vout->b_die) && (!p_vout->b_error) )
    {
Vincent Seguin's avatar
Vincent Seguin committed
422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445
        /* 
	 * Find the picture to display - this is the only operation requiring
	 * the lock on the picture, since once a READY_PICTURE has been found,
	 * it can't be modified by the other threads (except if it is unliked,
	 * but its data remains)
	 */
        vlc_mutex_lock( &p_vout->lock );

	for( i_picture = 0; i_picture < VOUT_MAX_PICTURES; i_picture++ )
	{
	    if( (p_vout->p_picture[i_picture].i_status == READY_PICTURE) &&
		( (p_pic == NULL) || 
		  (p_vout->p_picture[i_picture].date < p_pic->date) ) )
	    {
		p_pic = &p_vout->p_picture[i_picture];
	    }
	}

	vlc_mutex_unlock( &p_vout->lock );

        /* 
	 * Render picture if any
	 */
        if( p_pic )
Michel Kaempf's avatar
Michel Kaempf committed
446
        {
Vincent Seguin's avatar
Vincent Seguin committed
447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477
	    current_date = mdate();
	    if( p_pic->date < current_date )
	    {
		/* Picture is late: it will be destroyed and the thread will go
		 * immediately to next picture */
		vlc_mutex_lock( &p_vout->lock );
		if( p_pic->i_refcount )
		{
		    p_pic->i_status = DISPLAYED_PICTURE;
		}
		else
		{
		    p_pic->i_status = DESTROYED_PICTURE;
		}
		vlc_mutex_unlock( &p_vout->lock );
		intf_ErrMsg( "vout error: picture %p was late - skipped\n", p_pic );
		p_pic = NULL;
	    }
	    else if( p_pic->date > current_date + VOUT_DISPLAY_DELAY )
	    {
		/* A picture is ready to be rendered, but its rendering date is
		 * far from the current one so the thread will perform an empty loop
		 * as if no picture were found. The picture state is unchanged */
		p_pic = NULL;
	    }
	    else
	    {
		/* Picture has not yet been displayed, and has a valid display
		 * date : render it */
		RenderPicture( p_vout, p_pic );
	    }
Michel Kaempf's avatar
Michel Kaempf committed
478
        }
Vincent Seguin's avatar
Vincent Seguin committed
479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518
    
        /*
         * Check events, sleep and display picture
	 */
        i_err = vout_SysManage( p_vout );
	if( i_err < 0 )
	{
	    /* A fatal error occured, and the thread must terminate immediately,
	     * without displaying anything - setting b_error to 1 cause the
	     * immediate end of the main while() loop. */
	    p_vout->b_error = 1;
	}
	else 
	{
	    if( p_pic )
	    {
		/* A picture is ready to be displayed : sleep until its display date */
		mwait( p_pic->date );

		if( !i_err )
		{
		    vout_SysDisplay( p_vout );
		}

		/* Picture has been displayed : destroy it */
		vlc_mutex_lock( &p_vout->lock );
		if( p_pic->i_refcount )
		{
		    p_pic->i_status = DISPLAYED_PICTURE;
		}
		else
		{
		    p_pic->i_status = DESTROYED_PICTURE;
		}
		vlc_mutex_unlock( &p_vout->lock );
	    }
	    else
	    {
		/* Sleep to wait for new pictures */
		msleep( VOUT_IDLE_SLEEP );
Michel Kaempf's avatar
Michel Kaempf committed
519
#ifdef STATS
Vincent Seguin's avatar
Vincent Seguin committed
520 521
		/* Update counters */
		p_vout->c_idle_loops++;
Michel Kaempf's avatar
Michel Kaempf committed
522
#endif
Vincent Seguin's avatar
Vincent Seguin committed
523 524
	    }
	}
Michel Kaempf's avatar
Michel Kaempf committed
525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541

#ifdef STATS
        /* Update counters */
        p_vout->c_loops++;
#endif
    } 

    /*
     * Error loop
     */
    if( p_vout->b_error )
    {
        ErrorThread( p_vout );        
    }

    /* End of thread */
    EndThread( p_vout );
Vincent Seguin's avatar
Vincent Seguin committed
542
    intf_DbgMsg( "0x%x end\n", p_vout );
Michel Kaempf's avatar
Michel Kaempf committed
543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570
}

/*******************************************************************************
 * ErrorThread: RunThread() error loop
 *******************************************************************************
 * This function is called when an error occured during thread main's loop. The
 * thread can still receive feed, but must be ready to terminate as soon as
 * possible.
 *******************************************************************************/
static void ErrorThread( vout_thread_t *p_vout )
{
    /* Wait until a `die' order */
    while( !p_vout->b_die )
    {
        /* Sleep a while */
        msleep( VOUT_IDLE_SLEEP );                
    }
}

/*******************************************************************************
 * EndThread: thread destruction
 *******************************************************************************
 * This function is called when the thread ends after a sucessfull 
 * initialization.
 *******************************************************************************/
static void EndThread( vout_thread_t *p_vout )
{
    int *   pi_status;                                        /* thread status */
Vincent Seguin's avatar
Vincent Seguin committed
571
    int     i_picture;
Michel Kaempf's avatar
Michel Kaempf committed
572 573 574 575 576
        
    /* Store status */
    pi_status = p_vout->pi_status;    
    *pi_status = THREAD_END;    

Vincent Seguin's avatar
Vincent Seguin committed
577 578 579 580 581 582 583 584 585
    /* Destroy all remaining pictures */
    for( i_picture = 0; i_picture < VOUT_MAX_PICTURES; i_picture++ )
    {
	if( p_vout->p_picture[i_picture].i_status != FREE_PICTURE )
	{
            free( p_vout->p_picture[i_picture].p_data );
        }
    }
    
Michel Kaempf's avatar
Michel Kaempf committed
586
    /* Destroy thread structures allocated by InitThread */
Vincent Seguin's avatar
Vincent Seguin committed
587 588
    vout_SysEnd( p_vout );
    vout_SysDestroy( p_vout );            /* destroy output method */
Michel Kaempf's avatar
Michel Kaempf committed
589 590 591 592 593 594 595 596 597 598 599 600 601
    free( p_vout );

    /* Update status */
    *pi_status = THREAD_OVER;    
    intf_DbgMsg("%p\n", p_vout);
}

/*******************************************************************************
 * RenderPicture: render a picture
 *******************************************************************************
 * This function convert a picture from a video heap to a pixel-encoded image
 * and copy it to the current rendering buffer. No lock is required, since the
 * rendered picture has been determined as existant, and will only be destroyed
Vincent Seguin's avatar
Vincent Seguin committed
602
 * by the vout thread later.
Michel Kaempf's avatar
Michel Kaempf committed
603 604 605
 *******************************************************************************/
static void RenderPicture( vout_thread_t *p_vout, picture_t *p_pic )
{
606 607 608
    intf_DbgMsg("0x%x Picture 0x%x type=%d, %dx%d\n", 
                p_vout, p_pic, p_pic->i_type, p_pic->i_width, p_pic->i_height );
    
Vincent Seguin's avatar
Vincent Seguin committed
609
    /*???*/
Michel Kaempf's avatar
Michel Kaempf committed
610 611
}