]> git.sesse.net Git - vlc/blob - src/video_output/video_output.c
Integration de display.c � vout.
[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     p_vout->b_info              = 0;    
181     p_vout->b_grayscale         = main_GetIntVariable( VOUT_GRAYSCALE_VAR, 
182                                                        VOUT_GRAYSCALE_DEFAULT );
183     p_vout->i_width             = i_width;
184     p_vout->i_height            = i_height;
185     p_vout->i_bytes_per_line    = i_width * 2;    
186     p_vout->i_screen_depth      = 15;
187     p_vout->i_bytes_per_pixel   = 2;
188     p_vout->f_x_ratio           = 1;
189     p_vout->f_y_ratio           = 1;
190     intf_DbgMsg("wished configuration: %dx%d,%d (%d bytes/pixel, %d bytes/line), ratio %.2f:%.2f, gray=%d\n",
191                 p_vout->i_width, p_vout->i_height, p_vout->i_screen_depth,
192                 p_vout->i_bytes_per_pixel, p_vout->i_bytes_per_line,
193                 p_vout->f_x_ratio, p_vout->f_y_ratio, p_vout->b_grayscale );
194    
195     /* Create and initialize system-dependant method - this function issues its
196      * own error messages */
197     if( vout_SysCreate( p_vout
198 #if defined(VIDEO_X11)
199                         , psz_display, root_window 
200 #endif
201         ) )
202     {
203       free( p_vout );
204       return( NULL );
205     }
206     intf_DbgMsg("actual configuration: %dx%d,%d (%d bytes/pixel, %d bytes/line), ratio %.2f:%.2f, gray=%d\n",
207                 p_vout->i_width, p_vout->i_height, p_vout->i_screen_depth,
208                 p_vout->i_bytes_per_pixel, p_vout->i_bytes_per_line,
209                 p_vout->f_x_ratio, p_vout->f_y_ratio, p_vout->b_grayscale );
210   
211     /* Terminate the initialization */
212     p_vout->b_die               = 0;
213     p_vout->b_error             = 0;    
214     p_vout->b_active            = 0;
215     p_vout->pi_status           = (pi_status != NULL) ? pi_status : &i_status;
216     *p_vout->pi_status          = THREAD_CREATE;    
217 #ifdef STATS
218     p_vout->c_loops             = 0;
219     p_vout->c_idle_loops        = 0;
220     p_vout->c_pictures          = 0;
221 #endif      
222
223     /* Create thread and set locks */
224     vlc_mutex_init( &p_vout->lock );
225     if( vlc_thread_create( &p_vout->thread_id, "video output", 
226                            (void *) RunThread, (void *) p_vout) )
227     {
228         intf_ErrMsg("error: %s\n", strerror(ENOMEM));
229         vout_SysDestroy( p_vout );
230         free( p_vout );
231         return( NULL );
232     }   
233
234     intf_Msg("Video: display initialized (%dx%d, %d bpp)\n", 
235              p_vout->i_width, p_vout->i_height, p_vout->i_screen_depth );    
236
237     /* If status is NULL, wait until the thread is created */
238     if( pi_status == NULL )
239     {
240         do
241         {            
242             msleep( THREAD_SLEEP );
243         }while( (i_status != THREAD_READY) && (i_status != THREAD_ERROR) 
244                 && (i_status != THREAD_FATAL) );
245         if( i_status != THREAD_READY )
246         {
247             return( NULL );            
248         }        
249     }
250     return( p_vout );
251 }
252
253 /*******************************************************************************
254  * vout_DestroyThread: destroys a previously created thread
255  *******************************************************************************
256  * Destroy a terminated thread. 
257  * The function will request a destruction of the specified thread. If pi_error
258  * is NULL, it will return once the thread is destroyed. Else, it will be 
259  * update using one of the THREAD_* constants.
260  *******************************************************************************/
261 void vout_DestroyThread( vout_thread_t *p_vout, int *pi_status )
262 {  
263     int     i_status;                                         /* thread status */
264
265     /* Set status */
266     p_vout->pi_status = (pi_status != NULL) ? pi_status : &i_status;
267     *p_vout->pi_status = THREAD_DESTROY;    
268      
269     /* Request thread destruction */
270     p_vout->b_die = 1;
271
272     /* If status is NULL, wait until thread has been destroyed */
273     if( pi_status == NULL )
274     {
275         do
276         {
277             msleep( THREAD_SLEEP );
278         }while( (i_status != THREAD_OVER) && (i_status != THREAD_ERROR) 
279                 && (i_status != THREAD_FATAL) );   
280     }
281 }
282
283 /*******************************************************************************
284  * vout_DisplayPicture: display a picture
285  *******************************************************************************
286  * Remove the reservation flag of a picture, which will cause it to be ready for
287  * display.
288  *******************************************************************************/
289 void  vout_DisplayPicture( vout_thread_t *p_vout, picture_t *p_pic )
290 {
291 #ifdef DEBUG_VIDEO
292     char        psz_date[MSTRTIME_MAX_SIZE];         /* buffer for date string */
293 #endif
294   
295    vlc_mutex_lock( &p_vout->lock );
296
297 #ifdef DEBUG_VIDEO
298    /* Check if picture status is valid */
299    if( p_pic->i_status != RESERVED_PICTURE )
300    {
301        intf_DbgMsg("error: picture %d has invalid status %d\n", 
302                    p_pic, p_pic->i_status );       
303    }   
304 #endif
305
306     /* Remove reservation flag */
307     p_pic->i_status = READY_PICTURE;
308
309 #ifdef STATS
310     /* Update stats */
311     p_vout->c_pictures++;
312 #endif
313
314 #ifdef DEBUG_VIDEO
315     /* Send picture informations */
316     intf_DbgMsg("picture %p: type=%d, %dx%d, date=%s\n", p_pic, p_pic->i_type, 
317                 p_pic->i_width,p_pic->i_height, mstrtime( psz_date, p_pic->date ) );    
318 #endif
319
320     vlc_mutex_unlock( &p_vout->lock );
321 }
322
323 /*******************************************************************************
324  * vout_CreatePicture: allocate a picture in the video output heap.
325  *******************************************************************************
326  * This function create a reserved image in the video output heap. 
327  * A null pointer is returned if the function fails. This method provides an
328  * already allocated zone of memory in the picture data fields.
329  *******************************************************************************/
330 picture_t *vout_CreatePicture( vout_thread_t *p_vout, int i_type, 
331                                int i_width, int i_height, int i_bytes_per_line )
332 {
333     int         i_picture;                                    /* picture index */
334     picture_t * p_free_picture = NULL;                   /* first free picture */    
335     picture_t * p_destroyed_picture = NULL;         /* first destroyed picture */    
336
337     /* Get lock */
338     vlc_mutex_lock( &p_vout->lock );
339
340     /* 
341      * Look for an empty place 
342      */
343     for( i_picture = 0; 
344          i_picture < VOUT_MAX_PICTURES; 
345          i_picture++ )
346     {
347         if( p_vout->p_picture[i_picture].i_status == DESTROYED_PICTURE )
348         {
349             /* Picture is marked for destruction, but is still allocated */
350             if( (p_vout->p_picture[i_picture].i_type           == i_type)   &&
351                 (p_vout->p_picture[i_picture].i_height         == i_height) &&
352                 (p_vout->p_picture[i_picture].i_bytes_per_line == i_bytes_per_line) )
353             {
354                 /* Memory size do match : memory will not be reallocated, and function
355                  * can end immediately - this is the best possible case, since no
356                  * memory allocation needs to be done */
357                 p_vout->p_picture[i_picture].i_width  = i_width;
358                 p_vout->p_picture[i_picture].i_status = RESERVED_PICTURE;
359 #ifdef DEBUG_VIDEO
360                 intf_DbgMsg("picture %p (in destroyed picture slot)\n", 
361                             &p_vout->p_picture[i_picture] );                
362 #endif
363                 vlc_mutex_unlock( &p_vout->lock );
364                 return( &p_vout->p_picture[i_picture] );
365             }
366             else if( p_destroyed_picture == NULL )
367             {
368                 /* Memory size do not match, but picture index will be kept in
369                  * case no other place are left */
370                 p_destroyed_picture = &p_vout->p_picture[i_picture];                
371             }       
372         }
373         else if( (p_free_picture == NULL) && 
374                  (p_vout->p_picture[i_picture].i_status == FREE_PICTURE ))
375         {
376             /* Picture is empty and ready for allocation */
377             p_free_picture = &p_vout->p_picture[i_picture];            
378         }
379     }
380
381     /* If no free picture is available, use a destroyed picture */
382     if( (p_free_picture == NULL) && (p_destroyed_picture != NULL ) )
383     { 
384         /* No free picture or matching destroyed picture has been found, but
385          * a destroyed picture is still avalaible */
386         free( p_destroyed_picture->p_data );        
387         p_free_picture = p_destroyed_picture;        
388     }
389
390     /*
391      * Prepare picture
392      */
393     if( p_free_picture != NULL )
394     {
395         /* Allocate memory */
396         switch( i_type )
397         {
398         case YUV_420_PICTURE:                   /* YUV picture: bits per pixel */
399         case YUV_422_PICTURE:
400         case YUV_444_PICTURE:
401             p_free_picture->p_data = malloc( 3 * i_height * i_bytes_per_line );                
402             p_free_picture->p_y = (yuv_data_t *) p_free_picture->p_data;
403             p_free_picture->p_u = (yuv_data_t *)(p_free_picture->p_data + i_height * i_bytes_per_line);
404             p_free_picture->p_v = (yuv_data_t *)(p_free_picture->p_data + i_height * i_bytes_per_line * 2);
405             break;                
406 #ifdef DEBUG
407         default:
408             intf_DbgMsg("error: unknown picture type %d\n", i_type );
409             p_free_picture->p_data   =  NULL;            
410             break;            
411 #endif    
412         }
413
414         if( p_free_picture->p_data != NULL )
415         {        
416             /* Copy picture informations */
417             p_free_picture->i_type                      = i_type;
418             p_free_picture->i_status                    = RESERVED_PICTURE;
419             p_free_picture->i_width                     = i_width;
420             p_free_picture->i_height                    = i_height;
421             p_free_picture->i_bytes_per_line            = i_bytes_per_line;
422             p_free_picture->i_refcount                  = 0;            
423             p_free_picture->i_matrix_coefficients       = 1; 
424         }
425         else
426         {
427             /* Memory allocation failed : set picture as empty */
428             p_free_picture->i_type   =  EMPTY_PICTURE;            
429             p_free_picture->i_status =  FREE_PICTURE;            
430             p_free_picture =            NULL;            
431             intf_ErrMsg("warning: %s\n", strerror( ENOMEM ) );            
432         }
433         
434 #ifdef DEBUG_VIDEO
435         intf_DbgMsg("picture %p (in free picture slot)\n", p_free_picture );        
436 #endif
437         vlc_mutex_unlock( &p_vout->lock );
438         return( p_free_picture );
439     }
440     
441     // No free or destroyed picture could be found
442     intf_DbgMsg( "warning: heap is full\n" );
443     vlc_mutex_unlock( &p_vout->lock );
444     return( NULL );
445 }
446
447 /*******************************************************************************
448  * vout_DestroyPicture: remove a permanent or reserved picture from the heap
449  *******************************************************************************
450  * This function frees a previously reserved picture or a permanent
451  * picture. It is meant to be used when the construction of a picture aborted.
452  * Note that the picture will be destroyed even if it is linked !
453  *******************************************************************************/
454 void vout_DestroyPicture( vout_thread_t *p_vout, picture_t *p_pic )
455 {
456     vlc_mutex_lock( &p_vout->lock );
457
458 #ifdef DEBUG_VIDEO
459    /* Check if picture status is valid */
460    if( p_pic->i_status != RESERVED_PICTURE )
461    {
462        intf_DbgMsg("error: picture %d has invalid status %d\n", 
463                    p_pic, p_pic->i_status );       
464    }   
465 #endif
466
467     p_pic->i_status = DESTROYED_PICTURE;
468
469 #ifdef DEBUG_VIDEO
470     intf_DbgMsg("picture %p\n", p_pic);    
471 #endif
472
473     vlc_mutex_unlock( &p_vout->lock );
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.
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 is the only operation requiring
683          * the lock on the picture, since once a READY_PICTURE has been found,
684          * it can't be modified by the other threads (except if it is unliked,
685          * but its data remains)
686          */
687         p_pic = NULL;         
688         vlc_mutex_lock( &p_vout->lock );
689         for( i_picture = 0; i_picture < VOUT_MAX_PICTURES; i_picture++ )
690         {
691             if( (p_vout->p_picture[i_picture].i_status == READY_PICTURE) &&
692                 ( (p_pic == NULL) || 
693                   (p_vout->p_picture[i_picture].date < pic_date) ) )
694             {
695                 p_pic = &p_vout->p_picture[i_picture];
696                 pic_date = p_pic->date;                
697             }
698         }
699         vlc_mutex_unlock( &p_vout->lock );
700
701         /* 
702          * Render picture if any
703          */
704         if( p_pic )
705         {
706 #ifdef STATS
707             /* Computes FPS rate */
708             p_vout->fps_sample[ p_vout->i_fps_index++ ] = pic_date;
709             if( p_vout->i_fps_index == VOUT_FPS_SAMPLES )
710             {
711                 p_vout->i_fps_index = 0;                
712             }                            
713 #endif
714             current_date = mdate();
715             if( pic_date < current_date )
716             {
717                 /* Picture is late: it will be destroyed and the thread will go
718                  * immediately to next picture */
719                 vlc_mutex_lock( &p_vout->lock );
720                 if( p_pic->i_refcount )
721                 {
722                     p_pic->i_status = DISPLAYED_PICTURE;
723                 }
724                 else
725                 {
726                     p_pic->i_status = DESTROYED_PICTURE;
727                 }
728
729 #ifdef DEBUG_VIDEO
730                 intf_DbgMsg( "warning: late picture %p skipped\n", p_pic );
731 #endif
732                 vlc_mutex_unlock( &p_vout->lock );
733                 p_pic = NULL;
734             }
735             else if( pic_date > current_date + VOUT_DISPLAY_DELAY )
736             {
737                 /* A picture is ready to be rendered, but its rendering date is
738                  * far from the current one so the thread will perform an empty loop
739                  * as if no picture were found. The picture state is unchanged */
740                 p_pic = NULL;
741             }
742             else
743             {
744                 /* Picture has not yet been displayed, and has a valid display
745                  * date : render it, then forget it */
746                 RenderPicture( p_vout, p_pic );
747                 vlc_mutex_lock( &p_vout->lock );
748                 if( p_pic->i_refcount )
749                 {
750                     p_pic->i_status = DISPLAYED_PICTURE;
751                 }
752                 else
753                 {
754                     p_pic->i_status = DESTROYED_PICTURE;
755                 }
756                 vlc_mutex_unlock( &p_vout->lock );
757
758                 /* Print additional informations */
759                 if( p_vout->b_info )
760                 {                    
761                     RenderInfo( p_vout );
762                 }                
763             }
764         }
765     
766         /*
767          * Check events, sleep and display picture
768          */
769         i_err = vout_SysManage( p_vout );
770         if( i_err < 0 )
771         {
772             /* A fatal error occured, and the thread must terminate immediately,
773              * without displaying anything - setting b_error to 1 cause the
774              * immediate end of the main while() loop. */
775             p_vout->b_error = 1;
776         }
777         else 
778         {
779             if( p_pic )
780             {
781                 /* A picture is ready to be displayed : sleep until its display date */
782                 mwait( pic_date );
783
784                 if( !i_err )
785                 {
786                     vout_SysDisplay( p_vout );
787                 }
788             }
789             else
790             {
791                 /* Sleep to wait for new pictures */
792                 msleep( VOUT_IDLE_SLEEP );
793 #ifdef STATS
794                 /* Update counters */
795                 p_vout->c_idle_loops++;
796 #endif
797             }
798         }
799
800 #ifdef STATS
801         /* Update counters */
802         p_vout->c_loops++;
803 #endif
804     } 
805
806     /*
807      * Error loop
808      */
809     if( p_vout->b_error )
810     {
811         ErrorThread( p_vout );        
812     }
813
814     /* End of thread */
815     EndThread( p_vout );
816     intf_DbgMsg( "thread end\n" );
817 }
818
819 /*******************************************************************************
820  * ErrorThread: RunThread() error loop
821  *******************************************************************************
822  * This function is called when an error occured during thread main's loop. The
823  * thread can still receive feed, but must be ready to terminate as soon as
824  * possible.
825  *******************************************************************************/
826 static void ErrorThread( vout_thread_t *p_vout )
827 {
828     /* Wait until a `die' order */
829     while( !p_vout->b_die )
830     {
831         /* Sleep a while */
832         msleep( VOUT_IDLE_SLEEP );                
833     }
834 }
835
836 /*******************************************************************************
837  * EndThread: thread destruction
838  *******************************************************************************
839  * This function is called when the thread ends after a sucessfull 
840  * initialization.
841  *******************************************************************************/
842 static void EndThread( vout_thread_t *p_vout )
843 {
844     int *   pi_status;                                        /* thread status */
845     int     i_picture;
846         
847     /* Store status */
848     pi_status = p_vout->pi_status;    
849     *pi_status = THREAD_END;    
850
851     /* Destroy all remaining pictures */
852     for( i_picture = 0; i_picture < VOUT_MAX_PICTURES; i_picture++ )
853     {
854         if( p_vout->p_picture[i_picture].i_status != FREE_PICTURE )
855         {
856             free( p_vout->p_picture[i_picture].p_data );
857         }
858     }
859
860     /* Destroy translation tables - remeber these tables are translated */    
861     free( p_vout->pi_trans16_red - 384 );
862     free( p_vout->pi_trans16_green - 384 );
863     free( p_vout->pi_trans16_blue - 384 );
864     
865     /* Destroy thread structures allocated by InitThread */
866     vout_SysEnd( p_vout );
867     vout_SysDestroy( p_vout );
868     free( p_vout );
869
870     /* Update status */
871     *pi_status = THREAD_OVER;    
872 }
873
874 /*******************************************************************************
875  * RenderPicture: render a picture
876  *******************************************************************************
877  * This function convert a picture from a video heap to a pixel-encoded image
878  * and copy it to the current rendering buffer. No lock is required, since the
879  * rendered picture has been determined as existant, and will only be destroyed
880  * by the vout thread later.
881  * ???? 24 and 32 bpp should probably be separated
882  *******************************************************************************/
883 static void RenderPicture( vout_thread_t *p_vout, picture_t *p_pic )
884 {
885 #ifdef DEBUG_VIDEO
886     /* Send picture informations */
887     intf_DbgMsg("picture %p\n", p_pic );
888
889     /* Store rendering start date */
890     p_vout->picture_render_time = mdate();    
891 #endif
892
893     switch( p_pic->i_type )
894     {
895     case YUV_420_PICTURE:                   /* YUV picture: YUV transformation */        
896     case YUV_422_PICTURE:
897     case YUV_444_PICTURE:
898         if( p_vout->b_grayscale )                                 /* grayscale */
899         {
900             RenderYUVGrayPicture( p_vout, p_pic );            
901         }
902         else if( p_vout->i_bytes_per_pixel == 2 )        /* color 15 or 16 bpp */
903         {
904             RenderYUV16Picture( p_vout, p_pic );        
905         }
906         else                                             /* color 24 or 32 bpp */
907         {
908             RenderYUV32Picture( p_vout, p_pic );            
909         }
910         break;        
911 #ifdef DEBUG
912     default:        
913         intf_DbgMsg("error: unknown picture type %d\n", p_pic->i_type );
914         break;        
915 #endif
916     }
917
918 #ifdef DEBUG_VIDEO
919     /* Computes rendering time */
920     p_vout->picture_render_time = mdate() - p_vout->picture_render_time;    
921 #endif
922 }
923
924 /*******************************************************************************
925  * RenderYUVGrayPicture: render a 15, 16, 24 or 32 bpp YUV picture in grayscale
926  *******************************************************************************
927  * Performs the YUV convertion. The picture sent to this function should only
928  * have YUV_420, YUV_422 or YUV_444 types.
929  *******************************************************************************/
930 static void RenderYUVGrayPicture( vout_thread_t *p_vout, picture_t *p_pic )
931 {
932     int         i_pic_x, i_pic_y;                /* x,y coordinates in picture */
933     int         i_width, i_height;                             /* picture size */
934     int         i_eol_offset;          /* pixels from end of line to next line */   
935     yuv_data_t *p_y;                                     /* Y data base adress */
936     yuv_data_t  i_y;                                               /* Y sample */
937     u16 *       pi_pic16;                 /* destination picture, 15 or 16 bpp */
938     u32 *       pi_pic32;                 /* destination picture, 24 or 32 bpp */
939     u16 *       pi_trans16_red;                    /* red transformation table */
940     u16 *       pi_trans16_green;                /* green transformation table */
941     u16 *       pi_trans16_blue;                  /* blue transformation table */
942     u32 *       pi_trans32_red;                    /* red transformation table */
943     u32 *       pi_trans32_green;                /* green transformation table */
944     u32 *       pi_trans32_blue;                  /* blue transformation table */
945  
946     /* Set the base pointers and transformation parameters */
947     p_y =               p_pic->p_y;
948     i_width =           p_pic->i_width;
949     i_height =          p_pic->i_height;
950     i_eol_offset =      p_vout->i_bytes_per_line / p_vout->i_bytes_per_pixel - i_width;
951
952     /* Get base adress for destination image and translation tables, then
953      * transform image */
954     switch( p_vout->i_screen_depth )
955     {
956     case 15:
957     case 16:
958         pi_trans16_red =      p_vout->pi_trans16_red;
959         pi_trans16_green =    p_vout->pi_trans16_green;
960         pi_trans16_blue =     p_vout->pi_trans16_blue;        
961         pi_pic16 = (u16 *) vout_SysGetPicture( p_vout );
962
963         YUV_GRAYSCALE( pi_trans16_red, pi_trans16_green, pi_trans16_blue,
964                        pi_pic16 );
965         break;        
966     case 24:        
967     case 32:
968         pi_trans32_red =      p_vout->pi_trans32_red;
969         pi_trans32_green =    p_vout->pi_trans32_green;
970         pi_trans32_blue =     p_vout->pi_trans32_blue;    
971         pi_pic32 = (u32 *) vout_SysGetPicture( p_vout );
972
973         YUV_GRAYSCALE( pi_trans32_red, pi_trans32_green, pi_trans32_blue,
974                        pi_pic32 );
975         break;        
976 #ifdef DEBUG
977     default:
978         intf_DbgMsg("error: invalid screen depth %d\n", p_vout->i_screen_depth );
979         break;    
980 #endif      
981     }
982 }
983
984
985 /*******************************************************************************
986  * RenderYUV16Picture: render a 15 or 16 bpp YUV picture
987  *******************************************************************************
988  * Performs the YUV convertion. The picture sent to this function should only
989  * have YUV_420, YUV_422 or YUV_444 types.
990  *******************************************************************************/
991 static void RenderYUV16Picture( vout_thread_t *p_vout, picture_t *p_pic )
992 {
993     int         i_crv, i_cbu, i_cgu, i_cgv;     /* transformation coefficients */
994     int         i_pic_x, i_pic_y;                /* x,y coordinates in picture */
995     int         i_y, i_u, i_v;                           /* Y, U and V samples */
996     int         i_width, i_height;                             /* picture size */
997     int         i_chroma_width;                                /* chroma width */    
998     int         i_eol_offset;          /* pixels from end of line to next line */
999     yuv_data_t *p_y;                                     /* Y data base adress */
1000     yuv_data_t *p_u;                                     /* U data base adress */
1001     yuv_data_t *p_v;                                     /* V data base adress */
1002     u16 *       pi_pic;                 /* base adress for destination picture */
1003     u16 *       pi_trans_red;                      /* red transformation table */
1004     u16 *       pi_trans_green;                  /* green transformation table */
1005     u16 *       pi_trans_blue;                    /* blue transformation table */
1006  
1007     /* Choose transformation matrix coefficients */
1008     i_crv = MATRIX_COEFFICIENTS_TABLE[p_pic->i_matrix_coefficients][0];
1009     i_cbu = MATRIX_COEFFICIENTS_TABLE[p_pic->i_matrix_coefficients][1];
1010     i_cgu = MATRIX_COEFFICIENTS_TABLE[p_pic->i_matrix_coefficients][2];
1011     i_cgv = MATRIX_COEFFICIENTS_TABLE[p_pic->i_matrix_coefficients][3];
1012
1013     /* Choose the conversions tables */
1014     pi_trans_red =      p_vout->pi_trans16_red;
1015     pi_trans_green =    p_vout->pi_trans16_green;
1016     pi_trans_blue =     p_vout->pi_trans16_blue;    
1017
1018     /* Set the base pointers and transformation parameters */
1019     p_y =               p_pic->p_y;
1020     p_u =               p_pic->p_u;
1021     p_v =               p_pic->p_v;
1022     i_width =           p_pic->i_width;
1023     i_height =          p_pic->i_height;
1024     i_chroma_width =    i_width / 2;
1025     i_eol_offset =      p_vout->i_bytes_per_line / 2 - i_width;    
1026         
1027     /* Get base adress for destination image */
1028     pi_pic = (u16 *)vout_SysGetPicture( p_vout );
1029
1030     /* Do YUV transformation - the loops are repeated for optimization */
1031     switch( p_pic->i_type )
1032     {
1033     case YUV_420_PICTURE:                   /* 15 or 16 bpp 420 transformation */
1034 #ifdef HAVE_MMX
1035         vout_YUV420_16_MMX( p_y, p_u, p_v, 
1036                             i_width, i_height, 
1037                             i_width, i_chroma_width,
1038                             0, (u8 *) pi_pic, 
1039                             0, 0, p_vout->i_bytes_per_line, 
1040                             p_vout->i_screen_depth == 15 );
1041 #else
1042         YUV_TRANSFORM( 420,
1043                        pi_trans_red, 
1044                        pi_trans_green, 
1045                        pi_trans_blue,
1046                        pi_pic );            
1047 #endif
1048         break;
1049     case YUV_422_PICTURE:                   /* 15 or 16 bpp 422 transformation */
1050         YUV_TRANSFORM( 422,
1051                        pi_trans_red, 
1052                        pi_trans_green, 
1053                        pi_trans_blue,
1054                        pi_pic );            
1055         break;
1056     case YUV_444_PICTURE:                   /* 15 or 16 bpp 444 transformation */
1057         YUV_TRANSFORM( 444,
1058                        pi_trans_red, 
1059                        pi_trans_green, 
1060                        pi_trans_blue,
1061                        pi_pic );            
1062         break;                 
1063     }
1064 }
1065
1066 /*******************************************************************************
1067  * RenderYUV32Picture: render a 24 or 32 bpp YUV picture
1068  *******************************************************************************
1069  * Performs the YUV convertion. The picture sent to this function should only
1070  * have YUV_420, YUV_422 or YUV_444 types.
1071  *******************************************************************************/
1072 static void RenderYUV32Picture( vout_thread_t *p_vout, picture_t *p_pic )
1073 {
1074     int         i_crv, i_cbu, i_cgu, i_cgv;     /* transformation coefficients */
1075     int         i_pic_x, i_pic_y;                /* x,y coordinates in picture */
1076     int         i_y, i_u, i_v;                           /* Y, U and V samples */
1077     int         i_width, i_height;                             /* picture size */
1078     int         i_chroma_width;                                /* chroma width */    
1079     int         i_eol_offset;          /* pixels from end of line to next line */
1080     yuv_data_t *p_y;                                     /* Y data base adress */
1081     yuv_data_t *p_u;                                     /* U data base adress */
1082     yuv_data_t *p_v;                                     /* V data base adress */
1083     u32 *       pi_pic;                 /* base adress for destination picture */
1084     u32 *       pi_trans_red;                      /* red transformation table */
1085     u32 *       pi_trans_green;                  /* green transformation table */
1086     u32 *       pi_trans_blue;                    /* blue transformation table */
1087  
1088     /* Choose transformation matrix coefficients */
1089     i_crv = MATRIX_COEFFICIENTS_TABLE[p_pic->i_matrix_coefficients][0];
1090     i_cbu = MATRIX_COEFFICIENTS_TABLE[p_pic->i_matrix_coefficients][1];
1091     i_cgu = MATRIX_COEFFICIENTS_TABLE[p_pic->i_matrix_coefficients][2];
1092     i_cgv = MATRIX_COEFFICIENTS_TABLE[p_pic->i_matrix_coefficients][3];
1093
1094     /* Choose the conversions tables */
1095     pi_trans_red =      p_vout->pi_trans32_red;
1096     pi_trans_green =    p_vout->pi_trans32_green;
1097     pi_trans_blue =     p_vout->pi_trans32_blue;    
1098
1099     /* Set the base pointers and transformation parameters */
1100     p_y =               p_pic->p_y;
1101     p_u =               p_pic->p_u;
1102     p_v =               p_pic->p_v;
1103     i_width =           p_pic->i_width;
1104     i_height =          p_pic->i_height;
1105     i_chroma_width =    i_width / 2;
1106     i_eol_offset =      p_vout->i_bytes_per_line / p_vout->i_bytes_per_pixel - i_width;
1107         
1108     /* Get base adress for destination image */
1109     pi_pic = (u32 *)vout_SysGetPicture( p_vout );
1110
1111     /* Do YUV transformation - the loops are repeated for optimization */
1112     switch( p_pic->i_type )
1113     {
1114     case YUV_420_PICTURE:                   /* 24 or 32 bpp 420 transformation */
1115         YUV_TRANSFORM( 420,
1116                        pi_trans_red, 
1117                        pi_trans_green, 
1118                        pi_trans_blue,
1119                        pi_pic );            
1120         break;
1121     case YUV_422_PICTURE:                   /* 24 or 32 bpp 422 transformation */
1122         YUV_TRANSFORM( 422,
1123                        pi_trans_red, 
1124                        pi_trans_green, 
1125                        pi_trans_blue,
1126                        pi_pic );            
1127         break;
1128     case YUV_444_PICTURE:                   /* 24 or 32 bpp 444 transformation */
1129         YUV_TRANSFORM( 444,
1130                        pi_trans_red, 
1131                        pi_trans_green, 
1132                        pi_trans_blue,
1133                        pi_pic );            
1134         break;                 
1135     }
1136 }
1137
1138 /*******************************************************************************
1139  * RenderInfo: print additionnal informations on a picture
1140  *******************************************************************************
1141  * This function will add informations such as fps and buffer size on a picture
1142  *******************************************************************************/
1143 static void RenderInfo( vout_thread_t *p_vout )
1144 {
1145     char        psz_buffer[256];                              /* string buffer */
1146
1147 #ifdef STATS
1148     /* Print FPS rate */
1149     if( p_vout->c_pictures > VOUT_FPS_SAMPLES )
1150     {        
1151         sprintf( psz_buffer, "%.2f fps", (double) VOUT_FPS_SAMPLES * 1000000 /
1152                  ( p_vout->fps_sample[ (p_vout->i_fps_index + (VOUT_FPS_SAMPLES - 1)) % 
1153                                      VOUT_FPS_SAMPLES ] -
1154                    p_vout->fps_sample[ p_vout->i_fps_index ] ) );        
1155         vout_SysPrint( p_vout, p_vout->i_width, 0, 1, -1, psz_buffer );
1156     }
1157
1158     /* Print statistics */
1159     sprintf( psz_buffer, "%ld pictures, %.1f %% idle loops", p_vout->c_pictures,
1160              (double) p_vout->c_idle_loops * 100 / p_vout->c_loops );    
1161     vout_SysPrint( p_vout, 0, 0, -1, -1, psz_buffer );    
1162 #endif
1163     
1164 #ifdef DEBUG
1165     /* Print heap size  */
1166     sprintf( psz_buffer, "video heap size: %d (%.1f %%)", p_vout->i_pictures,
1167              (double) p_vout->i_pictures * 100 / VOUT_MAX_PICTURES );
1168     vout_SysPrint( p_vout, 0, p_vout->i_height, -1, 1, psz_buffer );    
1169 #endif
1170
1171 #ifdef DEBUG_VIDEO
1172     /* Print rendering statistics */
1173     sprintf( psz_buffer, "picture rendering time: %lu us", 
1174              (unsigned long) p_vout->picture_render_time );    
1175     vout_SysPrint( p_vout, p_vout->i_width, p_vout->i_height, 1, 1, psz_buffer );    
1176 #endif
1177 }
1178
1179