]> git.sesse.net Git - vlc/blob - src/video_output/video_output.c
Redimensionnement de la fenetre en fonction de la taille des images sous X11.
[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     RenderPictureInfo       ( vout_thread_t *p_vout, picture_t *p_pic );
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                     if( p_vout->b_info )
688                     {
689                         RenderPictureInfo( p_vout, p_pic );                        
690                     }                    
691                 }                
692                 vlc_mutex_lock( &p_vout->lock );
693                 p_pic->i_status = p_pic->i_refcount ? DISPLAYED_PICTURE : DESTROYED_PICTURE;
694                 vlc_mutex_unlock( &p_vout->lock );
695             }
696         }
697
698         /* 
699          * Rebuild tables if gamma has changed
700          */
701         if( p_vout->b_gamma_change )
702         {
703             p_vout->b_gamma_change = 0;            
704             BuildTables( p_vout );            
705         }        
706
707         /*
708          * Check events, sleep and display picture
709          */
710         i_err = vout_SysManage( p_vout );
711         if( i_err < 0 )
712         {
713             /* A fatal error occured, and the thread must terminate immediately,
714              * without displaying anything - setting b_error to 1 cause the
715              * immediate end of the main while() loop. */
716             p_vout->b_error = 1;
717         }
718         else 
719         {            
720             if( p_pic )
721             {
722                 /* A picture is ready to be displayed : remove blank screen flag */
723                 last_date =     pic_date;
724                 i_idle_level =  0;
725                 b_display =     1;                
726                 
727                 /* Sleep until its display date */
728                 mwait( pic_date );
729             }
730             else
731             {
732                 /* If last picture was a long time ago, increase idle level, reset
733                  * date and render idle screen */
734                 if( !i_err && (current_date - last_date > VOUT_IDLE_DELAY) )
735                 {       
736                     last_date = current_date;                    
737                     b_display = p_vout->b_active && RenderIdle( p_vout, i_idle_level++ );
738                 }
739                 else
740                 {
741                     b_display = 0;                    
742                 }
743                 
744 #ifdef STATS
745                 /* Update counters */
746                 p_vout->c_idle_loops++;
747 #endif
748
749                 /* Sleep to wait for new pictures */
750                 msleep( VOUT_IDLE_SLEEP );
751             }
752
753             /* On awakening, send immediately picture to display */
754             if( b_display && p_vout->b_active )
755             {
756                 vout_SysDisplay( p_vout );
757             }
758         }
759
760 #ifdef STATS
761         /* Update counters */
762         p_vout->c_loops++;
763 #endif
764     } 
765
766     /*
767      * Error loop
768      */
769     if( p_vout->b_error )
770     {
771         ErrorThread( p_vout );        
772     }
773
774     /* End of thread */
775     EndThread( p_vout );
776     intf_DbgMsg( "thread end\n" );
777 }
778
779 /*******************************************************************************
780  * ErrorThread: RunThread() error loop
781  *******************************************************************************
782  * This function is called when an error occured during thread main's loop. The
783  * thread can still receive feed, but must be ready to terminate as soon as
784  * possible.
785  *******************************************************************************/
786 static void ErrorThread( vout_thread_t *p_vout )
787 {
788     /* Wait until a `die' order */
789     while( !p_vout->b_die )
790     {
791         /* Sleep a while */
792         msleep( VOUT_IDLE_SLEEP );                
793     }
794 }
795
796 /*******************************************************************************
797  * EndThread: thread destruction
798  *******************************************************************************
799  * This function is called when the thread ends after a sucessfull 
800  * initialization.
801  *******************************************************************************/
802 static void EndThread( vout_thread_t *p_vout )
803 {
804     int *   pi_status;                                        /* thread status */
805     int     i_picture;
806         
807     /* Store status */
808     pi_status = p_vout->pi_status;    
809     *pi_status = THREAD_END;    
810
811     /* Destroy all remaining pictures */
812     for( i_picture = 0; i_picture < VOUT_MAX_PICTURES; i_picture++ )
813     {
814         if( p_vout->p_picture[i_picture].i_status != FREE_PICTURE )
815         {
816             free( p_vout->p_picture[i_picture].p_data );
817         }
818     }
819
820     /* Destroy translation tables */
821     free( p_vout->p_trans_base );
822     
823     /* Destroy thread structures allocated by InitThread */
824     vout_SysEnd( p_vout );
825     vout_SysDestroy( p_vout );
826     free( p_vout );
827
828     /* Update status */
829     *pi_status = THREAD_OVER;    
830 }
831
832 /*******************************************************************************
833  * BuildTables: build YUV translation tables
834  *******************************************************************************
835  * This function will build translations tables according to pixel width and
836  * gamma.
837  *******************************************************************************/  
838 static void BuildTables( vout_thread_t *p_vout )
839 {
840     u16 *       p_trans16_red =         (u16 *) p_vout->p_trans_red;
841     u16 *       p_trans16_green =       (u16 *) p_vout->p_trans_green;
842     u16 *       p_trans16_blue =        (u16 *) p_vout->p_trans_blue;
843     u16 *       p_trans16_gray =        (u16 *) p_vout->p_trans_gray;
844     u32 *       p_trans32_red =         (u32 *) p_vout->p_trans_red;
845     u32 *       p_trans32_green =       (u32 *) p_vout->p_trans_green;
846     u32 *       p_trans32_blue =        (u32 *) p_vout->p_trans_blue;
847     u32 *       p_trans32_gray =        (u32 *) p_vout->p_trans_gray;          
848     u8          i_gamma[256];                                   /* gamma table */    
849     int         i_index;                                    /* index in tables */
850     
851     /* Build gamma table */     
852     for( i_index = 0; i_index < 256; i_index++ )
853     {
854         i_gamma[i_index] = 255. * pow( (double)i_index / 255., p_vout->f_gamma );        
855     }
856         
857     /* Build red, green, blue and gray tables */
858     switch( p_vout->i_screen_depth )
859     {
860     case 15:
861         for( i_index = -384; i_index < 640; i_index++) 
862         {
863             p_trans16_red[i_index]     = (i_gamma[CLIP_BYTE( i_index )] & 0xf8)<<7;
864             p_trans16_green[i_index]   = (i_gamma[CLIP_BYTE( i_index )] & 0xf8)<<2;
865             p_trans16_blue[i_index]    =  i_gamma[CLIP_BYTE( i_index )] >> 3;
866             p_trans16_gray[i_index]    = p_trans16_red[i_index] | 
867                 p_trans16_green[i_index] | p_trans16_blue[i_index];            
868         }
869         break;        
870     case 16:
871         for( i_index = -384; i_index < 640; i_index++) 
872         {
873             p_trans16_red[i_index]     = (i_gamma[CLIP_BYTE( i_index )] & 0xf8)<<8;
874             p_trans16_green[i_index]   = (i_gamma[CLIP_BYTE( i_index )] & 0xfc)<<3;
875             p_trans16_blue[i_index]    =  i_gamma[CLIP_BYTE( i_index )] >> 3;
876             p_trans16_gray[i_index]    = p_trans16_red[i_index] |
877                 p_trans16_green[i_index] | p_trans16_blue[i_index];
878         }        
879         break;        
880     case 32:        
881         for( i_index = -384; i_index < 640; i_index++) 
882         {
883             p_trans32_red[i_index]     = i_gamma[CLIP_BYTE( i_index )] <<16;
884             p_trans32_green[i_index]   = i_gamma[CLIP_BYTE( i_index )] <<8;
885             p_trans32_blue[i_index]    = i_gamma[CLIP_BYTE( i_index )] ;
886             p_trans32_gray[i_index]    = p_trans32_red[i_index] |
887                 p_trans32_green[i_index] | p_trans32_blue[i_index];
888         }
889         break;        
890 #ifdef DEBUG
891     default:
892         intf_DbgMsg("error: invalid screen depth %d\n", p_vout->i_screen_depth );
893         break;      
894 #endif
895     } 
896
897     /* Build red, green and blue tables for optimized transformation */
898     //????
899     switch( p_vout->i_screen_depth )
900     {
901     case 16:
902         rgbTable16( (short *) p_vout->p_trans_optimized, 0xf800, 0x07e0, 0x01f, i_gamma );
903         break;        
904     }    
905 }
906
907 /*******************************************************************************
908  * RenderPicture: render a picture
909  *******************************************************************************
910  * This function convert a picture from a video heap to a pixel-encoded image
911  * and copy it to the current rendering buffer. No lock is required, since the
912  * rendered picture has been determined as existant, and will only be destroyed
913  * by the vout thread later.
914  * ???? 24 and 32 bpp should probably be separated
915  *******************************************************************************/
916 static void RenderPicture( vout_thread_t *p_vout, picture_t *p_pic )
917 {
918 #ifdef DEBUG_VIDEO
919     /* Send picture informations */
920     intf_DbgMsg("picture %p\n", p_pic );
921
922     /* Store rendering start date */
923     p_vout->picture_render_time = mdate();    
924 #endif
925
926     /* Change aspect ratio or resize frame to fit frame */
927     if( (p_pic->i_width > p_vout->i_width) || (p_pic->i_height > p_vout->i_height) )
928     {
929 #ifdef VIDEO_X11
930         /* X11: window can be resized, so resize it - the picture won't be 
931          * rendered since any alteration of the window size means recreating the
932          * XImages */
933         p_vout->i_new_width =   p_pic->i_width;
934         p_vout->i_new_height =  p_pic->i_height;
935         return;        
936 #else
937         /* Other drivers: the video output thread can't change its size, so
938          * we need to change the aspect ratio */
939         //????
940 #endif
941     }    
942
943     /* Choose appropriate rendering function */
944     switch( p_pic->i_type )
945     {
946     case YUV_420_PICTURE:                   /* YUV picture: YUV transformation */        
947     case YUV_422_PICTURE:
948     case YUV_444_PICTURE:
949         if( p_vout->b_grayscale )                                 /* grayscale */
950         {
951             RenderYUVGrayPicture( p_vout, p_pic );            
952         }
953         else if( p_vout->i_bytes_per_pixel == 2 )        /* color 15 or 16 bpp */
954         {
955             RenderYUV16Picture( p_vout, p_pic );        
956         }
957         else if( p_vout->i_bytes_per_pixel == 4 )              /* color 32 bpp */
958         {
959             RenderYUV32Picture( p_vout, p_pic );            
960         }
961         break;        
962 #ifdef DEBUG
963     default:        
964         intf_DbgMsg("error: unknown picture type %d\n", p_pic->i_type );
965         break;        
966 #endif
967     }
968
969 #ifdef DEBUG_VIDEO
970     /* Computes rendering time */
971     p_vout->picture_render_time = mdate() - p_vout->picture_render_time;    
972 #endif
973 }
974
975 /*******************************************************************************
976  * RenderYUVGrayPicture: render YUV picture in grayscale
977  *******************************************************************************
978  * Performs the YUV convertion. The picture sent to this function should only
979  * have YUV_420, YUV_422 or YUV_444 types.
980  *******************************************************************************/
981 static void RenderYUVGrayPicture( vout_thread_t *p_vout, picture_t *p_pic )
982 {
983     int         i_pic_x, i_pic_y;                /* x,y coordinates in picture */
984     int         i_width, i_height;                             /* picture size */
985     int         i_eol_offset;          /* pixels from end of line to next line */   
986     yuv_data_t *p_y;                                     /* Y data base adress */
987     u16 *       p_pic16;                  /* destination picture, 15 or 16 bpp */
988     u32 *       p_pic32;                        /* destination picture, 32 bpp */
989     u16 *       p_trans16_gray;          /* transformation table, 15 or 16 bpp */
990     u32 *       p_trans32_gray;                /* transformation table, 32 bpp */
991  
992     /* Set the base pointers and transformation parameters */
993     p_y =               p_pic->p_y;
994     i_width =           p_pic->i_width;
995     i_height =          p_pic->i_height;
996     i_eol_offset =      p_vout->i_bytes_per_line / p_vout->i_bytes_per_pixel - i_width;
997
998     /* Get base adress for destination image and translation tables, then
999      * transform image */
1000     switch( p_vout->i_screen_depth )
1001     {
1002     case 15:
1003     case 16:
1004         p_trans16_gray =       (u16 *) p_vout->p_trans_gray;
1005         p_pic16 =              (u16 *) vout_SysGetPicture( p_vout );
1006         YUV_GRAYSCALE( p_trans16_gray, p_pic16 );
1007         break;        
1008     case 32:
1009         p_trans32_gray =       (u32 *) p_vout->p_trans_gray;
1010         p_pic32 =              (u32 *) vout_SysGetPicture( p_vout );
1011         YUV_GRAYSCALE( p_trans32_gray, p_pic32 );
1012         break;        
1013 #ifdef DEBUG
1014     default:
1015         intf_DbgMsg("error: invalid screen depth %d\n", p_vout->i_screen_depth );
1016         break;    
1017 #endif      
1018     }
1019 }
1020
1021
1022 /*******************************************************************************
1023  * RenderYUV16Picture: render a 15 or 16 bpp YUV picture
1024  *******************************************************************************
1025  * Performs the YUV convertion. The picture sent to this function should only
1026  * have YUV_420, YUV_422 or YUV_444 types.
1027  *******************************************************************************/
1028 static void RenderYUV16Picture( vout_thread_t *p_vout, picture_t *p_pic )
1029 {
1030     int         i_crv, i_cbu, i_cgu, i_cgv;     /* transformation coefficients */
1031     int         i_pic_x, i_pic_y;                /* x,y coordinates in picture */
1032     int         i_y, i_u, i_v;                           /* Y, U and V samples */
1033     int         i_width, i_height;                             /* picture size */
1034     int         i_chroma_width;                                /* chroma width */    
1035     int         i_eol_offset;          /* pixels from end of line to next line */
1036     yuv_data_t *p_y;                                     /* Y data base adress */
1037     yuv_data_t *p_u;                                     /* U data base adress */
1038     yuv_data_t *p_v;                                     /* V data base adress */
1039     u16 *       p_data;                 /* base adress for destination picture */
1040     u16 *       p_trans_red;                       /* red transformation table */
1041     u16 *       p_trans_green;                   /* green transformation table */
1042     u16 *       p_trans_blue;                     /* blue transformation table */
1043  
1044     /* Choose transformation matrix coefficients */
1045     i_crv = MATRIX_COEFFICIENTS_TABLE[p_pic->i_matrix_coefficients][0];
1046     i_cbu = MATRIX_COEFFICIENTS_TABLE[p_pic->i_matrix_coefficients][1];
1047     i_cgu = MATRIX_COEFFICIENTS_TABLE[p_pic->i_matrix_coefficients][2];
1048     i_cgv = MATRIX_COEFFICIENTS_TABLE[p_pic->i_matrix_coefficients][3];
1049
1050     /* Choose the conversions tables and picture address */
1051     p_trans_red =       (u16 *) p_vout->p_trans_red;
1052     p_trans_green =     (u16 *) p_vout->p_trans_green;
1053     p_trans_blue =      (u16 *) p_vout->p_trans_blue;    
1054     p_data =            (u16 *) vout_SysGetPicture( p_vout );
1055
1056     /* Set the base pointers and transformation parameters */
1057     p_y =               p_pic->p_y;
1058     p_u =               p_pic->p_u;
1059     p_v =               p_pic->p_v;
1060     i_width =           p_pic->i_width;
1061     i_height =          p_pic->i_height;
1062     i_chroma_width =    i_width / 2;
1063     i_eol_offset =      p_vout->i_bytes_per_line / 2 - i_width;    
1064         
1065     /* Do YUV transformation - the loops are repeated for optimization */
1066     switch( p_pic->i_type )
1067     {
1068     case YUV_420_PICTURE:                   /* 15 or 16 bpp 420 transformation */
1069 #ifdef HAVE_MMX
1070         vout_YUV420_16_MMX( p_y, p_u, p_v, 
1071                             i_width, i_height, 
1072                             i_width, i_chroma_width,
1073                             0, p_data, 
1074                             0, 0, p_vout->i_bytes_per_line, 
1075                             p_vout->i_screen_depth == 15 );
1076 #else
1077         YUV_TRANSFORM( 420,
1078                        p_trans_red, 
1079                        p_trans_green, 
1080                        p_trans_blue,
1081                        p_data );            
1082   //???      yuvToRgb16( p_y, p_u, p_v, p_data, p_vout->p_trans_optimized, i_width*i_height );
1083 #endif
1084         break;
1085     case YUV_422_PICTURE:                   /* 15 or 16 bpp 422 transformation */
1086         YUV_TRANSFORM( 422,
1087                        p_trans_red, 
1088                        p_trans_green, 
1089                        p_trans_blue,
1090                        p_data );            
1091         break;
1092     case YUV_444_PICTURE:                   /* 15 or 16 bpp 444 transformation */
1093         YUV_TRANSFORM( 444,
1094                        p_trans_red, 
1095                        p_trans_green, 
1096                        p_trans_blue,
1097                        p_data );            
1098         break;                 
1099     }
1100 }
1101
1102 /*******************************************************************************
1103  * RenderYUV32Picture: render a 32 bpp YUV picture
1104  *******************************************************************************
1105  * Performs the YUV convertion. The picture sent to this function should only
1106  * have YUV_420, YUV_422 or YUV_444 types.
1107  *******************************************************************************/
1108 static void RenderYUV32Picture( vout_thread_t *p_vout, picture_t *p_pic )
1109 {
1110     int         i_crv, i_cbu, i_cgu, i_cgv;     /* transformation coefficients */
1111     int         i_pic_x, i_pic_y;                /* x,y coordinates in picture */
1112     int         i_y, i_u, i_v;                           /* Y, U and V samples */
1113     int         i_width, i_height;                             /* picture size */
1114     int         i_chroma_width;                                /* chroma width */    
1115     int         i_eol_offset;          /* pixels from end of line to next line */
1116     yuv_data_t *p_y;                                     /* Y data base adress */
1117     yuv_data_t *p_u;                                     /* U data base adress */
1118     yuv_data_t *p_v;                                     /* V data base adress */
1119     u32 *       p_data;                 /* base adress for destination picture */
1120     u32 *       p_trans_red;                       /* red transformation table */
1121     u32 *       p_trans_green;                   /* green transformation table */
1122     u32 *       p_trans_blue;                     /* blue transformation table */
1123  
1124     /* Choose transformation matrix coefficients */
1125     i_crv = MATRIX_COEFFICIENTS_TABLE[p_pic->i_matrix_coefficients][0];
1126     i_cbu = MATRIX_COEFFICIENTS_TABLE[p_pic->i_matrix_coefficients][1];
1127     i_cgu = MATRIX_COEFFICIENTS_TABLE[p_pic->i_matrix_coefficients][2];
1128     i_cgv = MATRIX_COEFFICIENTS_TABLE[p_pic->i_matrix_coefficients][3];
1129
1130     /* Choose the conversions tables and picture address */
1131     p_trans_red =       (u32 *) p_vout->p_trans_red;
1132     p_trans_green =     (u32 *) p_vout->p_trans_green;
1133     p_trans_blue =      (u32 *) p_vout->p_trans_blue;    
1134     p_data =            (u32 *) vout_SysGetPicture( p_vout );
1135
1136     /* Set the base pointers and transformation parameters */
1137     p_y =               p_pic->p_y;
1138     p_u =               p_pic->p_u;
1139     p_v =               p_pic->p_v;
1140     i_width =           p_pic->i_width;
1141     i_height =          p_pic->i_height;
1142     i_chroma_width =    i_width / 2;
1143     i_eol_offset =      p_vout->i_bytes_per_line / p_vout->i_bytes_per_pixel - i_width;
1144         
1145     /* Do YUV transformation - the loops are repeated for optimization */
1146     switch( p_pic->i_type )
1147     {
1148     case YUV_420_PICTURE:                         /* 32 bpp 420 transformation */
1149         YUV_TRANSFORM( 420,
1150                        p_trans_red, 
1151                        p_trans_green, 
1152                        p_trans_blue,
1153                        p_data );            
1154         break;
1155     case YUV_422_PICTURE:                         /* 32 bpp 422 transformation */
1156         YUV_TRANSFORM( 422,
1157                        p_trans_red, 
1158                        p_trans_green, 
1159                        p_trans_blue,
1160                        p_data );            
1161         break;
1162     case YUV_444_PICTURE:                         /* 32 bpp 444 transformation */
1163         YUV_TRANSFORM( 444,
1164                        p_trans_red, 
1165                        p_trans_green, 
1166                        p_trans_blue,
1167                        p_data );            
1168         break;                 
1169     }
1170 }
1171
1172 /*******************************************************************************
1173  * RenderPictureInfo: print additionnal informations on a picture
1174  *******************************************************************************
1175  * This function will add informations such as fps and buffer size on a picture
1176  *******************************************************************************/
1177 static void RenderPictureInfo( vout_thread_t *p_vout, picture_t *p_pic )
1178 {
1179     char        psz_buffer[256];                              /* string buffer */
1180 #ifdef DEBUG
1181     int         i_ready_pic = 0;                             /* ready pictures */
1182     int         i_reserved_pic = 0;                       /* reserved pictures */
1183     int         i_picture;                                    /* picture index */
1184 #endif
1185
1186 #ifdef STATS
1187     /* 
1188      * Print FPS rate in upper right corner 
1189      */
1190     if( p_vout->c_fps_samples > VOUT_FPS_SAMPLES )
1191     {        
1192         sprintf( psz_buffer, "%.2f fps", (double) VOUT_FPS_SAMPLES * 1000000 /
1193                  ( p_vout->fps_sample[ (p_vout->c_fps_samples - 1) % VOUT_FPS_SAMPLES ] -
1194                    p_vout->fps_sample[ p_vout->c_fps_samples % VOUT_FPS_SAMPLES ] ) );        
1195         vout_SysPrint( p_vout, p_vout->i_width, 0, 1, -1, psz_buffer );
1196     }
1197
1198     /* 
1199      * Print statistics in upper left corner 
1200      */
1201     sprintf( psz_buffer, "gamma=%.2f   %ld frames (%.1f %% idle)", 
1202              p_vout->f_gamma, p_vout->c_fps_samples, p_vout->c_loops ? 
1203              (double ) p_vout->c_idle_loops * 100 / p_vout->c_loops : 100. );    
1204     vout_SysPrint( p_vout, 0, 0, -1, -1, psz_buffer );    
1205 #endif
1206     
1207 #ifdef DEBUG
1208     /* 
1209      * Print heap state in lower left corner  
1210      */
1211     for( i_picture = 0; i_picture < VOUT_MAX_PICTURES; i_picture++ )
1212     {
1213         switch( p_vout->p_picture[i_picture].i_status )
1214         {
1215         case RESERVED_PICTURE:
1216             i_reserved_pic++;            
1217             break;            
1218         case READY_PICTURE:
1219             i_ready_pic++;            
1220             break;            
1221         }        
1222     }
1223     sprintf( psz_buffer, "video heap: %d/%d/%d", i_reserved_pic, i_ready_pic, 
1224              VOUT_MAX_PICTURES );
1225     vout_SysPrint( p_vout, 0, p_vout->i_height, -1, 1, psz_buffer );    
1226 #endif
1227
1228 #ifdef DEBUG_VIDEO
1229     /* 
1230      * Print picture info in lower right corner 
1231      */
1232     switch( p_pic->i_type )
1233     {
1234     case YUV_420_PICTURE:
1235         sprintf( psz_buffer, "YUV 4:2:0 picture, rendering time: %lu us", 
1236                  (unsigned long) p_vout->picture_render_time );
1237         break;        
1238     case YUV_422_PICTURE:
1239         sprintf( psz_buffer, "YUV 4:2:2 picture, rendering time: %lu us", 
1240                  (unsigned long) p_vout->picture_render_time );
1241         break;        
1242     case YUV_444_PICTURE:
1243         sprintf( psz_buffer, "YUV 4:4:4 picture, rendering time: %lu us", 
1244                  (unsigned long) p_vout->picture_render_time );
1245         break;
1246     default:
1247         sprintf( psz_buffer, "unknown picture, rendering time: %lu us", 
1248                  (unsigned long) p_vout->picture_render_time );    
1249         break;        
1250     }    
1251     vout_SysPrint( p_vout, p_vout->i_width, p_vout->i_height, 1, 1, psz_buffer );    
1252 #endif
1253 }
1254
1255 /*******************************************************************************
1256  * RenderIdle: render idle picture
1257  *******************************************************************************
1258  * This function will clear the display or print a logo. Level will vary from 0
1259  * to a very high value that noone should never reach. It returns non 0 if 
1260  * something needs to be displayed and 0 if the previous picture can be kept.
1261  *******************************************************************************/
1262 static int RenderIdle( vout_thread_t *p_vout, int i_level )
1263 {
1264     byte_t      *pi_pic;                            /* pointer to picture data */
1265     
1266     /* Get frame pointer and clear display */
1267     pi_pic = vout_SysGetPicture( p_vout );    
1268      
1269     
1270     switch( i_level )
1271     {
1272     case 0:                                           /* level 0: clear screen */
1273         memset( pi_pic, 0, p_vout->i_bytes_per_line * p_vout->i_height );
1274         break;                
1275     case 1:                                            /* level 1: "no stream" */        
1276         memset( pi_pic, 0, p_vout->i_bytes_per_line * p_vout->i_height );
1277         vout_SysPrint( p_vout, p_vout->i_width / 2, p_vout->i_height / 2,
1278                        0, 0, "no stream" );     
1279         break;
1280     case 50:                                    /* level 50: copyright message */
1281         memset( pi_pic, 0, p_vout->i_bytes_per_line * p_vout->i_height );
1282         vout_SysPrint( p_vout, p_vout->i_width / 2, p_vout->i_height / 2,
1283                        0, 0, COPYRIGHT_MESSAGE );        
1284         break; 
1285     default:                            /* other levels: keep previous picture */
1286         return( 0 );
1287         break;        
1288     }
1289
1290     return( 1 );    
1291 }
1292