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