]> git.sesse.net Git - vlc/blob - src/video_output/video_output.c
Resize sous X11, gestion du screen saver.
[vlc] / src / video_output / video_output.c
1 /*******************************************************************************
2  * video_output.c : video output thread
3  * (c)2000 VideoLAN
4  *******************************************************************************
5  * This module describes the programming interface for video output threads.
6  * It includes functions allowing to open a new thread, send pictures to a
7  * thread, and destroy a previously oppenned video output thread.
8  *******************************************************************************/
9
10 /*******************************************************************************
11  * Preamble
12  *******************************************************************************/
13 #include <errno.h> 
14 #include <stdlib.h>
15 #include <stdio.h>
16 #include <string.h>
17
18 #ifdef VIDEO_X11
19 #include <X11/Xlib.h>                           /* for video_sys.h in X11 mode */
20 #endif
21
22 #include "common.h"
23 #include "config.h"
24 #include "mtime.h"
25 #include "vlc_thread.h"
26 #include "video.h"
27 #include "video_output.h"
28 #include "video_sys.h"
29 #include "intf_msg.h"
30 #include "main.h"
31
32 /*******************************************************************************
33  * Macros
34  *******************************************************************************/
35
36 /* CLIP_BYTE: return value if between 0 and 255, else return nearest boundary 
37  * (0 or 255), used to build translations tables */
38 #define CLIP_BYTE( i_val ) ( (i_val < 0) ? 0 : ((i_val > 255) ? 255 : i_val) )
39
40 /* YUV_GRAYSCALE: parametric macro for YUV grayscale transformation.
41  * Due to the high performance need of this loop, all possible conditions 
42  * evaluations are made outside the transformation loop. However, the code does 
43  * not change much for two different loops. This macro allows to change slightly
44  * the content of the loop without having to copy and paste code. It is used in 
45  * RenderYUVPicture function. */
46 #define YUV_GRAYSCALE( TRANS_RED, TRANS_GREEN, TRANS_BLUE, P_PIC )      \
47 /* Main loop */                                                         \
48 for (i_pic_y=0; i_pic_y < p_pic->i_height ; i_pic_y++)                  \
49 {                                                                       \
50     for (i_pic_x=0; i_pic_x< p_pic->i_width; i_pic_x++)                 \
51     {                                                                   \
52         i_y = *p_y++;                                                   \
53         *P_PIC++ = TRANS_RED[i_y] | TRANS_GREEN[i_y] | TRANS_BLUE[i_y]; \
54     }                                                                   \
55     /* Skip until beginning of next line */                             \
56     P_PIC += i_eol_offset;                                              \
57 }                                                                       
58
59 /* YUV_TRANSFORM: parametric macro for YUV transformation.
60  * Due to the high performance need of this loop, all possible conditions 
61  * evaluations are made outside the transformation loop. However, the code does 
62  * not change much for two different loops. This macro allows to change slightly
63  * the content of the loop without having to copy and paste code. It is used in 
64  * RenderYUVPicture function. */
65 #define YUV_TRANSFORM( CHROMA, TRANS_RED, TRANS_GREEN, TRANS_BLUE, P_PIC ) \
66 /* Main loop */                                                         \
67 for (i_pic_y=0; i_pic_y < p_pic->i_height ; i_pic_y++)                  \
68 {                                                                       \
69     for (i_pic_x=0; i_pic_x< p_pic->i_width; i_pic_x+=2)                \
70     {                                                                   \
71         /* First sample (complete) */                                   \
72         i_y = 76309 * *p_y++ - 1188177;                                 \
73         i_u = *p_u++ - 128;                                             \
74         i_v = *p_v++ - 128;                                             \
75         *P_PIC++ =                                                      \
76             TRANS_RED   [(i_y+i_crv*i_v)                >>16] |         \
77             TRANS_GREEN [(i_y-i_cgu*i_u-i_cgv*i_v)      >>16] |         \
78             TRANS_BLUE  [(i_y+i_cbu*i_u)                >>16];          \
79         i_y = 76309 * *p_y++ - 1188177;                                 \
80         /* Second sample (partial) */                                   \
81         if( CHROMA == 444 )                                             \
82         {                                                               \
83             i_u = *p_u++ - 128;                                         \
84             i_v = *p_v++ - 128;                                         \
85         }                                                               \
86         *P_PIC++ =                                                      \
87             TRANS_RED   [(i_y+i_crv*i_v)                >>16] |         \
88             TRANS_GREEN [(i_y-i_cgu*i_u-i_cgv*i_v)      >>16] |         \
89             TRANS_BLUE  [(i_y+i_cbu*i_u)                >>16];          \
90     }                                                                   \
91     if( (CHROMA == 420) && !(i_pic_y & 0x1) )                           \
92     {                                                                   \
93         p_u -= i_chroma_width;                                          \
94         p_v -= i_chroma_width;                                          \
95     }                                                                   \
96     /* Skip until beginning of next line */                             \
97     P_PIC += i_eol_offset;                                              \
98 }
99
100 /*******************************************************************************
101  * Constants
102  *******************************************************************************/
103
104 /* RGB/YUV inversion matrix (ISO/IEC 13818-2 section 6.3.6, table 6.9) */
105 const int MATRIX_COEFFICIENTS_TABLE[8][4] =
106 {
107   {117504, 138453, 13954, 34903},       /* no sequence_display_extension */
108   {117504, 138453, 13954, 34903},       /* ITU-R Rec. 709 (1990) */
109   {104597, 132201, 25675, 53279},       /* unspecified */
110   {104597, 132201, 25675, 53279},       /* reserved */
111   {104448, 132798, 24759, 53109},       /* FCC */
112   {104597, 132201, 25675, 53279},       /* ITU-R Rec. 624-4 System B, G */
113   {104597, 132201, 25675, 53279},       /* SMPTE 170M */
114   {117579, 136230, 16907, 35559}        /* SMPTE 240M (1987) */
115 };
116
117 /*******************************************************************************
118  * External prototypes
119  *******************************************************************************/
120 #ifdef HAVE_MMX
121 /* YUV transformations for MMX - in yuv-mmx.S 
122  *      p_y, p_u, p_v:          Y U and V planes
123  *      i_width, i_height:      frames dimensions (pixels)
124  *      i_ypitch, i_vpitch:     Y and V lines sizes (bytes)
125  *      i_aspect:               vertical aspect factor
126  *      pi_pic:                 RGB frame
127  *      i_dci_offset:           ?? x offset for left image border
128  *      i_offset_to_line_0:     ?? x offset for left image border
129  *      i_pitch:                RGB line size (bytes)
130  *      i_colortype:            0 for 565, 1 for 555 */
131 void vout_YUV420_16_MMX( u8* p_y, u8* p_u, u8 *p_v, 
132                          unsigned int i_width, unsigned int i_height,
133                          unsigned int i_ypitch, unsigned int i_vpitch,
134                          unsigned int i_aspect, u8 *pi_pic, 
135                          u32 i_dci_offset, u32 i_offset_to_line_0,
136                          int CCOPitch, int i_colortype );
137 #endif
138
139 /*******************************************************************************
140  * Local prototypes
141  *******************************************************************************/
142 static int      InitThread              ( vout_thread_t *p_vout );
143 static void     RunThread               ( vout_thread_t *p_vout );
144 static void     ErrorThread             ( vout_thread_t *p_vout );
145 static void     EndThread               ( vout_thread_t *p_vout );
146 static void     RenderPicture           ( vout_thread_t *p_vout, picture_t *p_pic );
147 static void     RenderYUVGrayPicture    ( vout_thread_t *p_vout, picture_t *p_pic );
148 static void     RenderYUV16Picture      ( vout_thread_t *p_vout, picture_t *p_pic );
149 static void     RenderYUV32Picture      ( vout_thread_t *p_vout, picture_t *p_pic );
150 static void     RenderInfo              ( vout_thread_t *p_vout );
151 static int      RenderIdle              ( vout_thread_t *p_vout, int i_level );
152
153 /*******************************************************************************
154  * vout_CreateThread: creates a new video output thread
155  *******************************************************************************
156  * This function creates a new video output thread, and returns a pointer
157  * to its description. On error, it returns NULL.
158  * If pi_status is NULL, then the function will block until the thread is ready.
159  * If not, it will be updated using one of the THREAD_* constants.
160  *******************************************************************************/
161 vout_thread_t * vout_CreateThread               ( 
162 #ifdef VIDEO_X11
163                                                   char *psz_display, Window root_window, 
164 #endif
165                                                   int i_width, int i_height, int *pi_status 
166                                                 )
167 {
168     vout_thread_t * p_vout;                               /* thread descriptor */
169     int             i_status;                                 /* thread status */
170
171     /* Allocate descriptor */
172     p_vout = (vout_thread_t *) malloc( sizeof(vout_thread_t) );
173     if( p_vout == NULL )
174     {
175         intf_ErrMsg("error: %s\n", strerror(ENOMEM));        
176         return( NULL );
177     }
178
179     /* Initialize some fields used by the system-dependant method - these fields will
180      * probably be modified by the method */
181 #ifdef DEBUG
182     p_vout->b_info              = 1;    
183 #else
184     p_vout->b_info              = 0;    
185 #endif
186     p_vout->b_grayscale         = main_GetIntVariable( VOUT_GRAYSCALE_VAR, 
187                                                        VOUT_GRAYSCALE_DEFAULT );
188     p_vout->i_width             = i_width;
189     p_vout->i_height            = i_height;
190     p_vout->i_bytes_per_line    = i_width * 2;    
191     p_vout->i_screen_depth      = 15;
192     p_vout->i_bytes_per_pixel   = 2;
193     p_vout->f_x_ratio           = 1;
194     p_vout->f_y_ratio           = 1;
195     intf_DbgMsg("wished configuration: %dx%d,%d (%d bytes/pixel, %d bytes/line), ratio %.2f:%.2f, gray=%d\n",
196                 p_vout->i_width, p_vout->i_height, p_vout->i_screen_depth,
197                 p_vout->i_bytes_per_pixel, p_vout->i_bytes_per_line,
198                 p_vout->f_x_ratio, p_vout->f_y_ratio, p_vout->b_grayscale );
199    
200     /* Create and initialize system-dependant method - this function issues its
201      * own error messages */
202     if( vout_SysCreate( p_vout
203 #if defined(VIDEO_X11)
204                         , psz_display, root_window 
205 #endif
206         ) )
207     {
208       free( p_vout );
209       return( NULL );
210     }
211     intf_DbgMsg("actual configuration: %dx%d,%d (%d bytes/pixel, %d bytes/line), ratio %.2f:%.2f, gray=%d\n",
212                 p_vout->i_width, p_vout->i_height, p_vout->i_screen_depth,
213                 p_vout->i_bytes_per_pixel, p_vout->i_bytes_per_line,
214                 p_vout->f_x_ratio, p_vout->f_y_ratio, p_vout->b_grayscale );
215   
216     /* Terminate the initialization */
217     p_vout->b_die               = 0;
218     p_vout->b_error             = 0;    
219     p_vout->b_active            = 0;
220     p_vout->pi_status           = (pi_status != NULL) ? pi_status : &i_status;
221     *p_vout->pi_status          = THREAD_CREATE;    
222 #ifdef STATS
223     p_vout->c_loops             = 0;
224     p_vout->c_idle_loops        = 0;
225     p_vout->c_fps_samples       = 0;
226 #endif      
227
228     /* Create thread and set locks */
229     vlc_mutex_init( &p_vout->lock );
230     if( vlc_thread_create( &p_vout->thread_id, "video output", 
231                            (void *) RunThread, (void *) p_vout) )
232     {
233         intf_ErrMsg("error: %s\n", strerror(ENOMEM));
234         vout_SysDestroy( p_vout );
235         free( p_vout );
236         return( NULL );
237     }   
238
239     intf_Msg("Video: display initialized (%dx%d, %d bpp)\n", 
240              p_vout->i_width, p_vout->i_height, p_vout->i_screen_depth );    
241
242     /* If status is NULL, wait until the thread is created */
243     if( pi_status == NULL )
244     {
245         do
246         {            
247             msleep( THREAD_SLEEP );
248         }while( (i_status != THREAD_READY) && (i_status != THREAD_ERROR) 
249                 && (i_status != THREAD_FATAL) );
250         if( i_status != THREAD_READY )
251         {
252             return( NULL );            
253         }        
254     }
255     return( p_vout );
256 }
257
258 /*******************************************************************************
259  * vout_DestroyThread: destroys a previously created thread
260  *******************************************************************************
261  * Destroy a terminated thread. 
262  * The function will request a destruction of the specified thread. If pi_error
263  * is NULL, it will return once the thread is destroyed. Else, it will be 
264  * update using one of the THREAD_* constants.
265  *******************************************************************************/
266 void vout_DestroyThread( vout_thread_t *p_vout, int *pi_status )
267 {  
268     int     i_status;                                         /* thread status */
269
270     /* Set status */
271     p_vout->pi_status = (pi_status != NULL) ? pi_status : &i_status;
272     *p_vout->pi_status = THREAD_DESTROY;    
273      
274     /* Request thread destruction */
275     p_vout->b_die = 1;
276
277     /* If status is NULL, wait until thread has been destroyed */
278     if( pi_status == NULL )
279     {
280         do
281         {
282             msleep( THREAD_SLEEP );
283         }while( (i_status != THREAD_OVER) && (i_status != THREAD_ERROR) 
284                 && (i_status != THREAD_FATAL) );   
285     }
286 }
287
288 /*******************************************************************************
289  * vout_DisplayPicture: display a picture
290  *******************************************************************************
291  * Remove the reservation flag of a picture, which will cause it to be ready for
292  * display. The picture does not need to be locked, since it is ignored by
293  * the output thread if is reserved.
294  *******************************************************************************/
295 void  vout_DisplayPicture( vout_thread_t *p_vout, picture_t *p_pic )
296 {
297 #ifdef DEBUG_VIDEO
298     char        psz_date[MSTRTIME_MAX_SIZE];         /* buffer for date string */
299 #endif
300
301 #ifdef DEBUG
302     /* Check if picture status is valid */
303     if( p_pic->i_status != RESERVED_PICTURE )
304     {
305         intf_DbgMsg("error: picture %d has invalid status %d\n", p_pic, p_pic->i_status );       
306     }   
307 #endif
308
309     /* Remove reservation flag */
310     p_pic->i_status = READY_PICTURE;
311
312 #ifdef DEBUG_VIDEO
313     /* Send picture informations */
314     intf_DbgMsg("picture %p: type=%d, %dx%d, date=%s\n", p_pic, p_pic->i_type, 
315                 p_pic->i_width,p_pic->i_height, mstrtime( psz_date, p_pic->date ) );    
316 #endif
317 }
318
319 /*******************************************************************************
320  * vout_CreatePicture: allocate a picture in the video output heap.
321  *******************************************************************************
322  * This function create a reserved image in the video output heap. 
323  * A null pointer is returned if the function fails. This method provides an
324  * already allocated zone of memory in the picture data fields. It needs locking
325  * since several pictures can be created by several producers threads.
326  *******************************************************************************/
327 picture_t *vout_CreatePicture( vout_thread_t *p_vout, int i_type, 
328                                int i_width, int i_height, int i_bytes_per_line )
329 {
330     int         i_picture;                                    /* picture index */
331     picture_t * p_free_picture = NULL;                   /* first free picture */    
332     picture_t * p_destroyed_picture = NULL;         /* first destroyed picture */    
333
334     /* Get lock */
335     vlc_mutex_lock( &p_vout->lock );
336
337     /* 
338      * Look for an empty place 
339      */
340     for( i_picture = 0; 
341          i_picture < VOUT_MAX_PICTURES; 
342          i_picture++ )
343     {
344         if( p_vout->p_picture[i_picture].i_status == DESTROYED_PICTURE )
345         {
346             /* Picture is marked for destruction, but is still allocated */
347             if( (p_vout->p_picture[i_picture].i_type           == i_type)   &&
348                 (p_vout->p_picture[i_picture].i_height         == i_height) &&
349                 (p_vout->p_picture[i_picture].i_bytes_per_line == i_bytes_per_line) )
350             {
351                 /* Memory size do match : memory will not be reallocated, and function
352                  * can end immediately - this is the best possible case, since no
353                  * memory allocation needs to be done */
354                 p_vout->p_picture[i_picture].i_width  = i_width;
355                 p_vout->p_picture[i_picture].i_status = RESERVED_PICTURE;
356 #ifdef DEBUG_VIDEO
357                 intf_DbgMsg("picture %p (in destroyed picture slot)\n", 
358                             &p_vout->p_picture[i_picture] );                
359 #endif
360                 vlc_mutex_unlock( &p_vout->lock );
361                 return( &p_vout->p_picture[i_picture] );
362             }
363             else if( p_destroyed_picture == NULL )
364             {
365                 /* Memory size do not match, but picture index will be kept in
366                  * case no other place are left */
367                 p_destroyed_picture = &p_vout->p_picture[i_picture];                
368             }       
369         }
370         else if( (p_free_picture == NULL) && 
371                  (p_vout->p_picture[i_picture].i_status == FREE_PICTURE ))
372         {
373             /* Picture is empty and ready for allocation */
374             p_free_picture = &p_vout->p_picture[i_picture];            
375         }
376     }
377
378     /* If no free picture is available, use a destroyed picture */
379     if( (p_free_picture == NULL) && (p_destroyed_picture != NULL ) )
380     { 
381         /* No free picture or matching destroyed picture has been found, but
382          * a destroyed picture is still avalaible */
383         free( p_destroyed_picture->p_data );        
384         p_free_picture = p_destroyed_picture;        
385     }
386
387     /*
388      * Prepare picture
389      */
390     if( p_free_picture != NULL )
391     {
392         /* Allocate memory */
393         switch( i_type )
394         {
395         case YUV_420_PICTURE:                   /* YUV picture: bits per pixel */
396         case YUV_422_PICTURE:
397         case YUV_444_PICTURE:
398             p_free_picture->p_data = malloc( 3 * i_height * i_bytes_per_line );                
399             p_free_picture->p_y = (yuv_data_t *) p_free_picture->p_data;
400             p_free_picture->p_u = (yuv_data_t *)(p_free_picture->p_data + i_height * i_bytes_per_line);
401             p_free_picture->p_v = (yuv_data_t *)(p_free_picture->p_data + i_height * i_bytes_per_line * 2);
402             break;                
403 #ifdef DEBUG
404         default:
405             intf_DbgMsg("error: unknown picture type %d\n", i_type );
406             p_free_picture->p_data   =  NULL;            
407             break;            
408 #endif    
409         }
410
411         if( p_free_picture->p_data != NULL )
412         {        
413             /* Copy picture informations */
414             p_free_picture->i_type                      = i_type;
415             p_free_picture->i_status                    = RESERVED_PICTURE;
416             p_free_picture->i_width                     = i_width;
417             p_free_picture->i_height                    = i_height;
418             p_free_picture->i_bytes_per_line            = i_bytes_per_line;
419             p_free_picture->i_refcount                  = 0;            
420             p_free_picture->i_matrix_coefficients       = 1; 
421         }
422         else
423         {
424             /* Memory allocation failed : set picture as empty */
425             p_free_picture->i_type   =  EMPTY_PICTURE;            
426             p_free_picture->i_status =  FREE_PICTURE;            
427             p_free_picture =            NULL;            
428             intf_ErrMsg("warning: %s\n", strerror( ENOMEM ) );            
429         }
430         
431 #ifdef DEBUG_VIDEO
432         intf_DbgMsg("picture %p (in free picture slot)\n", p_free_picture );        
433 #endif
434         vlc_mutex_unlock( &p_vout->lock );
435         return( p_free_picture );
436     }
437     
438     // No free or destroyed picture could be found
439     intf_DbgMsg( "warning: heap is full\n" );
440     vlc_mutex_unlock( &p_vout->lock );
441     return( NULL );
442 }
443
444 /*******************************************************************************
445  * vout_DestroyPicture: remove a permanent or reserved picture from the heap
446  *******************************************************************************
447  * This function frees a previously reserved picture or a permanent
448  * picture. It is meant to be used when the construction of a picture aborted.
449  * Note that the picture will be destroyed even if it is linked !
450  * This function does not need locking since reserved pictures are ignored by
451  * the output thread.
452  *******************************************************************************/
453 void vout_DestroyPicture( vout_thread_t *p_vout, picture_t *p_pic )
454 {
455 #ifdef DEBUG
456    /* Check if picture status is valid */
457    if( p_pic->i_status != RESERVED_PICTURE )
458    {
459        intf_DbgMsg("error: picture %d has invalid status %d\n", p_pic, p_pic->i_status );       
460    }   
461 #endif
462
463     p_pic->i_status = DESTROYED_PICTURE;
464
465 #ifdef DEBUG_VIDEO
466     intf_DbgMsg("picture %p\n", p_pic);    
467 #endif
468 }
469
470 /*******************************************************************************
471  * vout_LinkPicture: increment reference counter of a picture
472  *******************************************************************************
473  * This function increment the reference counter of a picture in the video
474  * heap. It needs a lock since several producer threads can access the picture.
475  *******************************************************************************/
476 void vout_LinkPicture( vout_thread_t *p_vout, picture_t *p_pic )
477 {
478     vlc_mutex_lock( &p_vout->lock );
479     p_pic->i_refcount++;
480     vlc_mutex_unlock( &p_vout->lock );
481
482 #ifdef DEBUG_VIDEO
483     intf_DbgMsg("picture %p\n", p_pic);    
484 #endif
485 }
486
487 /*******************************************************************************
488  * vout_UnlinkPicture: decrement reference counter of a picture
489  *******************************************************************************
490  * This function decrement the reference counter of a picture in the video heap.
491  *******************************************************************************/
492 void vout_UnlinkPicture( vout_thread_t *p_vout, picture_t *p_pic )
493 {
494     vlc_mutex_lock( &p_vout->lock );
495     p_pic->i_refcount--;
496     if( (p_pic->i_refcount == 0) && (p_pic->i_status == DISPLAYED_PICTURE) )
497     {
498         p_pic->i_status = DESTROYED_PICTURE;
499     }
500     vlc_mutex_unlock( &p_vout->lock );
501
502 #ifdef DEBUG_VIDEO
503     intf_DbgMsg("picture %p\n", p_pic);    
504 #endif
505 }
506
507 /* following functions are local */
508
509 /*******************************************************************************
510  * InitThread: initialize video output thread
511  *******************************************************************************
512  * This function is called from RunThread and performs the second step of the
513  * initialization. It returns 0 on success. Note that the thread's flag are not
514  * modified inside this function.
515  *******************************************************************************/
516 static int InitThread( vout_thread_t *p_vout )
517 {
518     int     i_index;                                          /* generic index */    
519     int     i_pixel_size;     /* pixel size, in bytes, for translations tables */    
520
521     /* Update status */
522     *p_vout->pi_status = THREAD_START;    
523     
524     /* Initialize pictures */    
525     for( i_index = 0; i_index < VOUT_MAX_PICTURES; i_index++)
526     {
527         p_vout->p_picture[i_index].i_type  = EMPTY_PICTURE;
528         p_vout->p_picture[i_index].i_status= FREE_PICTURE;
529     }
530
531     /* Initialize output method - this function issues its own error messages */
532     if( vout_SysInit( p_vout ) )
533     {
534         *p_vout->pi_status = THREAD_ERROR;        
535         return( 1 );
536     } 
537
538     /* Allocate translation tables */
539     switch( p_vout->i_bytes_per_pixel )
540     {
541     case 2:                   /* 15 or 16 bpp, use 16 bits translations tables */        
542         i_pixel_size = sizeof( u16 );        
543         break;                
544     case 3:                   /* 24 or 32 bpp, use 32 bits translations tables */        
545     case 4:
546 #ifndef DEBUG
547     default:        
548 #endif
549         i_pixel_size = sizeof( u32 );
550         break;
551 #ifdef DEBUG
552     default:
553         intf_DbgMsg("error: invalid bytes_per_pixel %d\n", p_vout->i_bytes_per_pixel );
554         i_pixel_size = sizeof( u32 );        
555         break;              
556 #endif
557     }
558     p_vout->pi_trans32_red =   (u32 *)p_vout->pi_trans16_red =   
559         (u16 *)malloc( 1024 * i_pixel_size );
560     p_vout->pi_trans32_green = (u32 *)p_vout->pi_trans16_green = 
561         (u16 *)malloc( 1024 * i_pixel_size );
562     p_vout->pi_trans32_blue =  (u32 *)p_vout->pi_trans16_blue =  
563         (u16 *)malloc( 1024 * i_pixel_size );
564     if( (p_vout->pi_trans16_red == NULL) || 
565         (p_vout->pi_trans16_green == NULL ) ||
566         (p_vout->pi_trans16_blue == NULL ) )
567     {
568         intf_ErrMsg("error: %s\n", strerror(ENOMEM) );
569         *p_vout->pi_status = THREAD_ERROR;   
570         if( p_vout->pi_trans16_red != NULL )
571         {
572             free( p_vout->pi_trans16_red );
573         }
574         if( p_vout->pi_trans16_green != NULL )
575         {
576             free( p_vout->pi_trans16_green );
577         }
578         if( p_vout->pi_trans16_blue != NULL )
579         {
580             free( p_vout->pi_trans16_blue );
581         }
582         return( 1 );
583     }              
584     
585     /* Translate translation tables */
586     p_vout->pi_trans16_red      += 384;
587     p_vout->pi_trans16_green    += 384;
588     p_vout->pi_trans16_blue     += 384;
589     p_vout->pi_trans32_red      += 384;
590     p_vout->pi_trans32_green    += 384;
591     p_vout->pi_trans32_blue     += 384;
592
593     /* Build translation tables */
594     switch( p_vout->i_screen_depth )
595     {
596     case 15:
597         for( i_index = -384; i_index < 640; i_index++) 
598         {
599             p_vout->pi_trans16_red[i_index]     = (CLIP_BYTE( i_index ) & 0xf8)<<7;
600             p_vout->pi_trans16_green[i_index]   = (CLIP_BYTE( i_index ) & 0xf8)<<2;
601             p_vout->pi_trans16_blue[i_index]    =  CLIP_BYTE( i_index ) >> 3;
602         }
603         break;        
604     case 16:
605         for( i_index = -384; i_index < 640; i_index++) 
606         {
607             p_vout->pi_trans16_red[i_index]     = (CLIP_BYTE( i_index ) & 0xf8)<<8;
608             p_vout->pi_trans16_green[i_index]   = (CLIP_BYTE( i_index ) & 0xfc)<<3;
609             p_vout->pi_trans16_blue[i_index]    =  CLIP_BYTE( i_index ) >> 3;
610         }
611         break;        
612     case 24:
613     case 32:        
614         for( i_index = -384; i_index < 640; i_index++) 
615         {
616             p_vout->pi_trans32_red[i_index]     =  CLIP_BYTE( i_index ) <<16;
617             p_vout->pi_trans32_green[i_index]   =  CLIP_BYTE( i_index ) <<8;
618             p_vout->pi_trans32_blue[i_index]    =  CLIP_BYTE( i_index ) ;
619         }
620         break;        
621 #ifdef DEBUG
622     default:
623         intf_DbgMsg("error: invalid screen depth %d\n", p_vout->i_screen_depth );
624         break;      
625 #endif
626     }
627     
628     /* Mark thread as running and return */
629     p_vout->b_active =          1;    
630     *p_vout->pi_status =        THREAD_READY;    
631     intf_DbgMsg("thread ready\n");    
632     return( 0 );    
633 }
634
635 /*******************************************************************************
636  * RunThread: video output thread
637  *******************************************************************************
638  * Video output thread. This function does only returns when the thread is
639  * terminated. It handles the pictures arriving in the video heap and the
640  * display device events.
641  *******************************************************************************/
642 static void RunThread( vout_thread_t *p_vout)
643 {
644     int             i_picture;                                /* picture index */
645     int             i_err;                                       /* error code */
646     int             i_idle_level = 0;                            /* idle level */
647     mtime_t         current_date;                              /* current date */
648     mtime_t         pic_date = 0;                              /* picture date */    
649     mtime_t         last_date = 0;                        /* last picture date */    
650     boolean_t       b_display;                                 /* display flag */    
651     picture_t *     p_pic;                                  /* picture pointer */
652      
653     /* 
654      * Initialize thread and free configuration 
655      */
656     p_vout->b_error = InitThread( p_vout );
657     if( p_vout->b_error )
658     {
659         free( p_vout );                                  /* destroy descriptor */
660         return;        
661     }    
662
663     /*
664      * Main loop - it is not executed if an error occured during
665      * initialization
666      */
667     while( (!p_vout->b_die) && (!p_vout->b_error) )
668     {
669         /* 
670          * Find the picture to display - this operation does not need lock,
671          * since only READY_PICTURES are handled 
672          */
673         p_pic = NULL;         
674         for( i_picture = 0; i_picture < VOUT_MAX_PICTURES; i_picture++ )
675         {
676             if( (p_vout->p_picture[i_picture].i_status == READY_PICTURE) &&
677                 ( (p_pic == NULL) || 
678                   (p_vout->p_picture[i_picture].date < pic_date) ) )
679             {
680                 p_pic = &p_vout->p_picture[i_picture];
681                 pic_date = p_pic->date;                
682             }
683         }
684         current_date = mdate();
685
686         /* 
687          * Render picture if any
688          */
689         if( p_pic )
690         {
691 #ifdef STATS
692             /* Computes FPS rate */
693             p_vout->fps_sample[ p_vout->c_fps_samples++ % VOUT_FPS_SAMPLES ] = pic_date;
694 #endif      
695             if( pic_date < current_date )
696             {
697                 /* Picture is late: it will be destroyed and the thread will sleep and
698                  * go to next picture */
699                 vlc_mutex_lock( &p_vout->lock );
700                 p_pic->i_status = p_pic->i_refcount ? DISPLAYED_PICTURE : DESTROYED_PICTURE;
701                 vlc_mutex_unlock( &p_vout->lock );
702 #ifdef DEBUG_VIDEO
703                 intf_DbgMsg( "warning: late picture %p skipped\n", p_pic );
704 #endif
705                 p_pic =         NULL;                
706             }
707             else if( pic_date > current_date + VOUT_DISPLAY_DELAY )
708             {
709                 /* A picture is ready to be rendered, but its rendering date is
710                  * far from the current one so the thread will perform an empty loop
711                  * as if no picture were found. The picture state is unchanged */
712                 p_pic =         NULL;                
713             }
714             else
715             {
716                 /* Picture has not yet been displayed, and has a valid display
717                  * date : render it, then mark it as displayed */
718                 if( p_vout->b_active )
719                 {                    
720                     RenderPicture( p_vout, p_pic );
721                 }                
722                 vlc_mutex_lock( &p_vout->lock );
723                 p_pic->i_status = p_pic->i_refcount ? DISPLAYED_PICTURE : DESTROYED_PICTURE;
724                 vlc_mutex_unlock( &p_vout->lock );
725             }
726         }
727
728         /*
729          * Check events, sleep and display picture
730          */
731         i_err = vout_SysManage( p_vout );
732         if( i_err < 0 )
733         {
734             /* A fatal error occured, and the thread must terminate immediately,
735              * without displaying anything - setting b_error to 1 cause the
736              * immediate end of the main while() loop. */
737             p_vout->b_error = 1;
738         }
739         else 
740         {            
741             if( p_pic )
742             {
743                 /* A picture is ready to be displayed : remove blank screen flag */
744                 last_date =     pic_date;
745                 i_idle_level =  0;
746                 b_display =     1;                
747                 
748                 /* Render additionnal informations */
749                 if( p_vout->b_active && p_vout->b_info )
750                 {
751                     RenderInfo( p_vout );    
752                 }                
753                 
754                 /* Sleep until its display date */
755                 mwait( pic_date );
756             }
757             else
758             {
759                 /* If last picture was a long time ago, increase idle level, reset
760                  * date and render idle screen */
761                 if( !i_err && (current_date - last_date > VOUT_IDLE_DELAY) )
762                 {       
763                     last_date = current_date;                    
764                     b_display = p_vout->b_active && RenderIdle( p_vout, i_idle_level++ );
765                 }
766                 else
767                 {
768                     b_display = 0;                    
769                 }
770                 
771 #ifdef STATS
772                 /* Update counters */
773                 p_vout->c_idle_loops++;
774 #endif
775
776                 /* Sleep to wait for new pictures */
777                 msleep( VOUT_IDLE_SLEEP );
778             }
779
780             /* On awakening, send immediately picture to display */
781             if( b_display && p_vout->b_active )
782             {
783                 vout_SysDisplay( p_vout );
784             }
785         }
786
787 #ifdef STATS
788         /* Update counters */
789         p_vout->c_loops++;
790 #endif
791     } 
792
793     /*
794      * Error loop
795      */
796     if( p_vout->b_error )
797     {
798         ErrorThread( p_vout );        
799     }
800
801     /* End of thread */
802     EndThread( p_vout );
803     intf_DbgMsg( "thread end\n" );
804 }
805
806 /*******************************************************************************
807  * ErrorThread: RunThread() error loop
808  *******************************************************************************
809  * This function is called when an error occured during thread main's loop. The
810  * thread can still receive feed, but must be ready to terminate as soon as
811  * possible.
812  *******************************************************************************/
813 static void ErrorThread( vout_thread_t *p_vout )
814 {
815     /* Wait until a `die' order */
816     while( !p_vout->b_die )
817     {
818         /* Sleep a while */
819         msleep( VOUT_IDLE_SLEEP );                
820     }
821 }
822
823 /*******************************************************************************
824  * EndThread: thread destruction
825  *******************************************************************************
826  * This function is called when the thread ends after a sucessfull 
827  * initialization.
828  *******************************************************************************/
829 static void EndThread( vout_thread_t *p_vout )
830 {
831     int *   pi_status;                                        /* thread status */
832     int     i_picture;
833         
834     /* Store status */
835     pi_status = p_vout->pi_status;    
836     *pi_status = THREAD_END;    
837
838     /* Destroy all remaining pictures */
839     for( i_picture = 0; i_picture < VOUT_MAX_PICTURES; i_picture++ )
840     {
841         if( p_vout->p_picture[i_picture].i_status != FREE_PICTURE )
842         {
843             free( p_vout->p_picture[i_picture].p_data );
844         }
845     }
846
847     /* Destroy translation tables - remeber these tables are translated */    
848     free( p_vout->pi_trans16_red - 384 );
849     free( p_vout->pi_trans16_green - 384 );
850     free( p_vout->pi_trans16_blue - 384 );
851     
852     /* Destroy thread structures allocated by InitThread */
853     vout_SysEnd( p_vout );
854     vout_SysDestroy( p_vout );
855     free( p_vout );
856
857     /* Update status */
858     *pi_status = THREAD_OVER;    
859 }
860
861 /*******************************************************************************
862  * RenderPicture: render a picture
863  *******************************************************************************
864  * This function convert a picture from a video heap to a pixel-encoded image
865  * and copy it to the current rendering buffer. No lock is required, since the
866  * rendered picture has been determined as existant, and will only be destroyed
867  * by the vout thread later.
868  * ???? 24 and 32 bpp should probably be separated
869  *******************************************************************************/
870 static void RenderPicture( vout_thread_t *p_vout, picture_t *p_pic )
871 {
872 #ifdef DEBUG_VIDEO
873     /* Send picture informations */
874     intf_DbgMsg("picture %p\n", p_pic );
875
876     /* Store rendering start date */
877     p_vout->picture_render_time = mdate();    
878 #endif
879
880     switch( p_pic->i_type )
881     {
882     case YUV_420_PICTURE:                   /* YUV picture: YUV transformation */        
883     case YUV_422_PICTURE:
884     case YUV_444_PICTURE:
885         if( p_vout->b_grayscale )                                 /* grayscale */
886         {
887             RenderYUVGrayPicture( p_vout, p_pic );            
888         }
889         else if( p_vout->i_bytes_per_pixel == 2 )        /* color 15 or 16 bpp */
890         {
891             RenderYUV16Picture( p_vout, p_pic );        
892         }
893         else                                             /* color 24 or 32 bpp */
894         {
895             RenderYUV32Picture( p_vout, p_pic );            
896         }
897         break;        
898 #ifdef DEBUG
899     default:        
900         intf_DbgMsg("error: unknown picture type %d\n", p_pic->i_type );
901         break;        
902 #endif
903     }
904
905 #ifdef DEBUG_VIDEO
906     /* Computes rendering time */
907     p_vout->picture_render_time = mdate() - p_vout->picture_render_time;    
908 #endif
909 }
910
911 /*******************************************************************************
912  * RenderYUVGrayPicture: render a 15, 16, 24 or 32 bpp YUV picture in grayscale
913  *******************************************************************************
914  * Performs the YUV convertion. The picture sent to this function should only
915  * have YUV_420, YUV_422 or YUV_444 types.
916  *******************************************************************************/
917 static void RenderYUVGrayPicture( vout_thread_t *p_vout, picture_t *p_pic )
918 {
919     int         i_pic_x, i_pic_y;                /* x,y coordinates in picture */
920     int         i_width, i_height;                             /* picture size */
921     int         i_eol_offset;          /* pixels from end of line to next line */   
922     yuv_data_t *p_y;                                     /* Y data base adress */
923     yuv_data_t  i_y;                                               /* Y sample */
924     u16 *       pi_pic16;                 /* destination picture, 15 or 16 bpp */
925     u32 *       pi_pic32;                 /* destination picture, 24 or 32 bpp */
926     u16 *       pi_trans16_red;                    /* red transformation table */
927     u16 *       pi_trans16_green;                /* green transformation table */
928     u16 *       pi_trans16_blue;                  /* blue transformation table */
929     u32 *       pi_trans32_red;                    /* red transformation table */
930     u32 *       pi_trans32_green;                /* green transformation table */
931     u32 *       pi_trans32_blue;                  /* blue transformation table */
932  
933     /* Set the base pointers and transformation parameters */
934     p_y =               p_pic->p_y;
935     i_width =           p_pic->i_width;
936     i_height =          p_pic->i_height;
937     i_eol_offset =      p_vout->i_bytes_per_line / p_vout->i_bytes_per_pixel - i_width;
938
939     /* Get base adress for destination image and translation tables, then
940      * transform image */
941     switch( p_vout->i_screen_depth )
942     {
943     case 15:
944     case 16:
945         pi_trans16_red =      p_vout->pi_trans16_red;
946         pi_trans16_green =    p_vout->pi_trans16_green;
947         pi_trans16_blue =     p_vout->pi_trans16_blue;        
948         pi_pic16 = (u16 *) vout_SysGetPicture( p_vout );
949
950         YUV_GRAYSCALE( pi_trans16_red, pi_trans16_green, pi_trans16_blue,
951                        pi_pic16 );
952         break;        
953     case 24:        
954     case 32:
955         pi_trans32_red =      p_vout->pi_trans32_red;
956         pi_trans32_green =    p_vout->pi_trans32_green;
957         pi_trans32_blue =     p_vout->pi_trans32_blue;    
958         pi_pic32 = (u32 *) vout_SysGetPicture( p_vout );
959
960         YUV_GRAYSCALE( pi_trans32_red, pi_trans32_green, pi_trans32_blue,
961                        pi_pic32 );
962         break;        
963 #ifdef DEBUG
964     default:
965         intf_DbgMsg("error: invalid screen depth %d\n", p_vout->i_screen_depth );
966         break;    
967 #endif      
968     }
969 }
970
971
972 /*******************************************************************************
973  * RenderYUV16Picture: render a 15 or 16 bpp YUV picture
974  *******************************************************************************
975  * Performs the YUV convertion. The picture sent to this function should only
976  * have YUV_420, YUV_422 or YUV_444 types.
977  *******************************************************************************/
978 static void RenderYUV16Picture( vout_thread_t *p_vout, picture_t *p_pic )
979 {
980     int         i_crv, i_cbu, i_cgu, i_cgv;     /* transformation coefficients */
981     int         i_pic_x, i_pic_y;                /* x,y coordinates in picture */
982     int         i_y, i_u, i_v;                           /* Y, U and V samples */
983     int         i_width, i_height;                             /* picture size */
984     int         i_chroma_width;                                /* chroma width */    
985     int         i_eol_offset;          /* pixels from end of line to next line */
986     yuv_data_t *p_y;                                     /* Y data base adress */
987     yuv_data_t *p_u;                                     /* U data base adress */
988     yuv_data_t *p_v;                                     /* V data base adress */
989     u16 *       pi_pic;                 /* base adress for destination picture */
990     u16 *       pi_trans_red;                      /* red transformation table */
991     u16 *       pi_trans_green;                  /* green transformation table */
992     u16 *       pi_trans_blue;                    /* blue transformation table */
993  
994     /* Choose transformation matrix coefficients */
995     i_crv = MATRIX_COEFFICIENTS_TABLE[p_pic->i_matrix_coefficients][0];
996     i_cbu = MATRIX_COEFFICIENTS_TABLE[p_pic->i_matrix_coefficients][1];
997     i_cgu = MATRIX_COEFFICIENTS_TABLE[p_pic->i_matrix_coefficients][2];
998     i_cgv = MATRIX_COEFFICIENTS_TABLE[p_pic->i_matrix_coefficients][3];
999
1000     /* Choose the conversions tables */
1001     pi_trans_red =      p_vout->pi_trans16_red;
1002     pi_trans_green =    p_vout->pi_trans16_green;
1003     pi_trans_blue =     p_vout->pi_trans16_blue;    
1004
1005     /* Set the base pointers and transformation parameters */
1006     p_y =               p_pic->p_y;
1007     p_u =               p_pic->p_u;
1008     p_v =               p_pic->p_v;
1009     i_width =           p_pic->i_width;
1010     i_height =          p_pic->i_height;
1011     i_chroma_width =    i_width / 2;
1012     i_eol_offset =      p_vout->i_bytes_per_line / 2 - i_width;    
1013         
1014     /* Get base adress for destination image */
1015     pi_pic = (u16 *)vout_SysGetPicture( p_vout );
1016
1017     /* Do YUV transformation - the loops are repeated for optimization */
1018     switch( p_pic->i_type )
1019     {
1020     case YUV_420_PICTURE:                   /* 15 or 16 bpp 420 transformation */
1021 #ifdef HAVE_MMX
1022         vout_YUV420_16_MMX( p_y, p_u, p_v, 
1023                             i_width, i_height, 
1024                             i_width, i_chroma_width,
1025                             0, (u8 *) pi_pic, 
1026                             0, 0, p_vout->i_bytes_per_line, 
1027                             p_vout->i_screen_depth == 15 );
1028 #else
1029         YUV_TRANSFORM( 420,
1030                        pi_trans_red, 
1031                        pi_trans_green, 
1032                        pi_trans_blue,
1033                        pi_pic );            
1034 #endif
1035         break;
1036     case YUV_422_PICTURE:                   /* 15 or 16 bpp 422 transformation */
1037         YUV_TRANSFORM( 422,
1038                        pi_trans_red, 
1039                        pi_trans_green, 
1040                        pi_trans_blue,
1041                        pi_pic );            
1042         break;
1043     case YUV_444_PICTURE:                   /* 15 or 16 bpp 444 transformation */
1044         YUV_TRANSFORM( 444,
1045                        pi_trans_red, 
1046                        pi_trans_green, 
1047                        pi_trans_blue,
1048                        pi_pic );            
1049         break;                 
1050     }
1051 }
1052
1053 /*******************************************************************************
1054  * RenderYUV32Picture: render a 24 or 32 bpp YUV picture
1055  *******************************************************************************
1056  * Performs the YUV convertion. The picture sent to this function should only
1057  * have YUV_420, YUV_422 or YUV_444 types.
1058  *******************************************************************************/
1059 static void RenderYUV32Picture( vout_thread_t *p_vout, picture_t *p_pic )
1060 {
1061     int         i_crv, i_cbu, i_cgu, i_cgv;     /* transformation coefficients */
1062     int         i_pic_x, i_pic_y;                /* x,y coordinates in picture */
1063     int         i_y, i_u, i_v;                           /* Y, U and V samples */
1064     int         i_width, i_height;                             /* picture size */
1065     int         i_chroma_width;                                /* chroma width */    
1066     int         i_eol_offset;          /* pixels from end of line to next line */
1067     yuv_data_t *p_y;                                     /* Y data base adress */
1068     yuv_data_t *p_u;                                     /* U data base adress */
1069     yuv_data_t *p_v;                                     /* V data base adress */
1070     u32 *       pi_pic;                 /* base adress for destination picture */
1071     u32 *       pi_trans_red;                      /* red transformation table */
1072     u32 *       pi_trans_green;                  /* green transformation table */
1073     u32 *       pi_trans_blue;                    /* blue transformation table */
1074  
1075     /* Choose transformation matrix coefficients */
1076     i_crv = MATRIX_COEFFICIENTS_TABLE[p_pic->i_matrix_coefficients][0];
1077     i_cbu = MATRIX_COEFFICIENTS_TABLE[p_pic->i_matrix_coefficients][1];
1078     i_cgu = MATRIX_COEFFICIENTS_TABLE[p_pic->i_matrix_coefficients][2];
1079     i_cgv = MATRIX_COEFFICIENTS_TABLE[p_pic->i_matrix_coefficients][3];
1080
1081     /* Choose the conversions tables */
1082     pi_trans_red =      p_vout->pi_trans32_red;
1083     pi_trans_green =    p_vout->pi_trans32_green;
1084     pi_trans_blue =     p_vout->pi_trans32_blue;    
1085
1086     /* Set the base pointers and transformation parameters */
1087     p_y =               p_pic->p_y;
1088     p_u =               p_pic->p_u;
1089     p_v =               p_pic->p_v;
1090     i_width =           p_pic->i_width;
1091     i_height =          p_pic->i_height;
1092     i_chroma_width =    i_width / 2;
1093     i_eol_offset =      p_vout->i_bytes_per_line / p_vout->i_bytes_per_pixel - i_width;
1094         
1095     /* Get base adress for destination image */
1096     pi_pic = (u32 *)vout_SysGetPicture( p_vout );
1097
1098     /* Do YUV transformation - the loops are repeated for optimization */
1099     switch( p_pic->i_type )
1100     {
1101     case YUV_420_PICTURE:                   /* 24 or 32 bpp 420 transformation */
1102         YUV_TRANSFORM( 420,
1103                        pi_trans_red, 
1104                        pi_trans_green, 
1105                        pi_trans_blue,
1106                        pi_pic );            
1107         break;
1108     case YUV_422_PICTURE:                   /* 24 or 32 bpp 422 transformation */
1109         YUV_TRANSFORM( 422,
1110                        pi_trans_red, 
1111                        pi_trans_green, 
1112                        pi_trans_blue,
1113                        pi_pic );            
1114         break;
1115     case YUV_444_PICTURE:                   /* 24 or 32 bpp 444 transformation */
1116         YUV_TRANSFORM( 444,
1117                        pi_trans_red, 
1118                        pi_trans_green, 
1119                        pi_trans_blue,
1120                        pi_pic );            
1121         break;                 
1122     }
1123 }
1124
1125 /*******************************************************************************
1126  * RenderInfo: print additionnal informations on a picture
1127  *******************************************************************************
1128  * This function will add informations such as fps and buffer size on a picture
1129  *******************************************************************************/
1130 static void RenderInfo( vout_thread_t *p_vout )
1131 {
1132     char        psz_buffer[256];                              /* string buffer */
1133 #ifdef DEBUG
1134     int         i_ready_pic = 0;                             /* ready pictures */
1135     int         i_reserved_pic = 0;                       /* reserved pictures */
1136     int         i_picture;                                    /* picture index */
1137 #endif
1138
1139 #ifdef STATS
1140     /* Print FPS rate in upper right corner */
1141     if( p_vout->c_fps_samples > VOUT_FPS_SAMPLES )
1142     {        
1143         sprintf( psz_buffer, "%.2f fps", (double) VOUT_FPS_SAMPLES * 1000000 /
1144                  ( p_vout->fps_sample[ (p_vout->c_fps_samples - 1) % VOUT_FPS_SAMPLES ] -
1145                    p_vout->fps_sample[ p_vout->c_fps_samples % VOUT_FPS_SAMPLES ] ) );        
1146         vout_SysPrint( p_vout, p_vout->i_width, 0, 1, -1, psz_buffer );
1147     }
1148
1149     /* Print statistics in upper left corner */
1150     sprintf( psz_buffer, "%ld frames (%.1f %% idle)", p_vout->c_fps_samples,
1151              p_vout->c_loops ? 
1152              (double ) p_vout->c_idle_loops * 100 / p_vout->c_loops : 100. );    
1153     vout_SysPrint( p_vout, 0, 0, -1, -1, psz_buffer );    
1154 #endif
1155     
1156 #ifdef DEBUG
1157     /* Print heap state in lower left corner  */
1158     for( i_picture = 0; i_picture < VOUT_MAX_PICTURES; i_picture++ )
1159     {
1160         switch( p_vout->p_picture[i_picture].i_status )
1161         {
1162         case RESERVED_PICTURE:
1163             i_reserved_pic++;            
1164             break;            
1165         case READY_PICTURE:
1166             i_ready_pic++;            
1167             break;            
1168         }        
1169     }
1170     sprintf( psz_buffer, "video heap: %d/%d/%d", i_reserved_pic, i_ready_pic, 
1171              VOUT_MAX_PICTURES );
1172     vout_SysPrint( p_vout, 0, p_vout->i_height, -1, 1, psz_buffer );    
1173 #endif
1174
1175 #ifdef DEBUG_VIDEO
1176     /* Print rendering statistics in lower right corner */
1177     sprintf( psz_buffer, "picture rendering time: %lu us", 
1178              (unsigned long) p_vout->picture_render_time );    
1179     vout_SysPrint( p_vout, p_vout->i_width, p_vout->i_height, 1, 1, psz_buffer );    
1180 #endif
1181 }
1182
1183 /*******************************************************************************
1184  * RenderIdle: render idle picture
1185  *******************************************************************************
1186  * This function will clear the display or print a logo. Level will vary from 0
1187  * to a very high value that noone should never reach. It returns non 0 if 
1188  * something needs to be displayed and 0 if the previous picture can be kept.
1189  *******************************************************************************/
1190 static int RenderIdle( vout_thread_t *p_vout, int i_level )
1191 {
1192     byte_t      *pi_pic;                            /* pointer to picture data */
1193     
1194     /* Get frame pointer and clear display */
1195     pi_pic = vout_SysGetPicture( p_vout );    
1196      
1197     
1198     switch( i_level )
1199     {
1200     case 0:                                           /* level 0: clear screen */
1201         memset( pi_pic, 0, p_vout->i_bytes_per_line * p_vout->i_height );
1202         break;                
1203     case 1:                                            /* level 1: "no stream" */        
1204         memset( pi_pic, 0, p_vout->i_bytes_per_line * p_vout->i_height );
1205         vout_SysPrint( p_vout, p_vout->i_width / 2, p_vout->i_height / 2,
1206                        0, 0, "no stream" );     
1207         break;
1208     case 50:                                    /* level 50: copyright message */
1209         memset( pi_pic, 0, p_vout->i_bytes_per_line * p_vout->i_height );
1210         vout_SysPrint( p_vout, p_vout->i_width / 2, p_vout->i_height / 2,
1211                        0, 0, COPYRIGHT_MESSAGE );        
1212         break; 
1213     default:                            /* other levels: keep previous picture */
1214         return( 0 );
1215         break;        
1216     }
1217
1218     return( 1 );    
1219 }
1220