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