]> git.sesse.net Git - vlc/blob - src/video_output/video_output.c
Mise au point du driver GGI.
[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.
292  *******************************************************************************/
293 void  vout_DisplayPicture( vout_thread_t *p_vout, picture_t *p_pic )
294 {
295 #ifdef DEBUG_VIDEO
296     char        psz_date[MSTRTIME_MAX_SIZE];         /* buffer for date string */
297 #endif
298   
299    vlc_mutex_lock( &p_vout->lock );
300
301 #ifdef DEBUG_VIDEO
302    /* Check if picture status is valid */
303    if( p_pic->i_status != RESERVED_PICTURE )
304    {
305        intf_DbgMsg("error: picture %d has invalid status %d\n", 
306                    p_pic, p_pic->i_status );       
307    }   
308 #endif
309
310     /* Remove reservation flag */
311     p_pic->i_status = READY_PICTURE;
312
313 #ifdef STATS
314     /* Update stats */
315     p_vout->c_pictures++;
316 #endif
317
318 #ifdef DEBUG_VIDEO
319     /* Send picture informations */
320     intf_DbgMsg("picture %p: type=%d, %dx%d, date=%s\n", p_pic, p_pic->i_type, 
321                 p_pic->i_width,p_pic->i_height, mstrtime( psz_date, p_pic->date ) );    
322 #endif
323
324     vlc_mutex_unlock( &p_vout->lock );
325 }
326
327 /*******************************************************************************
328  * vout_CreatePicture: allocate a picture in the video output heap.
329  *******************************************************************************
330  * This function create a reserved image in the video output heap. 
331  * A null pointer is returned if the function fails. This method provides an
332  * already allocated zone of memory in the picture data fields.
333  *******************************************************************************/
334 picture_t *vout_CreatePicture( vout_thread_t *p_vout, int i_type, 
335                                int i_width, int i_height, int i_bytes_per_line )
336 {
337     int         i_picture;                                    /* picture index */
338     picture_t * p_free_picture = NULL;                   /* first free picture */    
339     picture_t * p_destroyed_picture = NULL;         /* first destroyed picture */    
340
341     /* Get lock */
342     vlc_mutex_lock( &p_vout->lock );
343
344     /* 
345      * Look for an empty place 
346      */
347     for( i_picture = 0; 
348          i_picture < VOUT_MAX_PICTURES; 
349          i_picture++ )
350     {
351         if( p_vout->p_picture[i_picture].i_status == DESTROYED_PICTURE )
352         {
353             /* Picture is marked for destruction, but is still allocated */
354             if( (p_vout->p_picture[i_picture].i_type           == i_type)   &&
355                 (p_vout->p_picture[i_picture].i_height         == i_height) &&
356                 (p_vout->p_picture[i_picture].i_bytes_per_line == i_bytes_per_line) )
357             {
358                 /* Memory size do match : memory will not be reallocated, and function
359                  * can end immediately - this is the best possible case, since no
360                  * memory allocation needs to be done */
361                 p_vout->p_picture[i_picture].i_width  = i_width;
362                 p_vout->p_picture[i_picture].i_status = RESERVED_PICTURE;
363 #ifdef DEBUG_VIDEO
364                 intf_DbgMsg("picture %p (in destroyed picture slot)\n", 
365                             &p_vout->p_picture[i_picture] );                
366 #endif
367                 vlc_mutex_unlock( &p_vout->lock );
368                 return( &p_vout->p_picture[i_picture] );
369             }
370             else if( p_destroyed_picture == NULL )
371             {
372                 /* Memory size do not match, but picture index will be kept in
373                  * case no other place are left */
374                 p_destroyed_picture = &p_vout->p_picture[i_picture];                
375             }       
376         }
377         else if( (p_free_picture == NULL) && 
378                  (p_vout->p_picture[i_picture].i_status == FREE_PICTURE ))
379         {
380             /* Picture is empty and ready for allocation */
381             p_free_picture = &p_vout->p_picture[i_picture];            
382         }
383     }
384
385     /* If no free picture is available, use a destroyed picture */
386     if( (p_free_picture == NULL) && (p_destroyed_picture != NULL ) )
387     { 
388         /* No free picture or matching destroyed picture has been found, but
389          * a destroyed picture is still avalaible */
390         free( p_destroyed_picture->p_data );        
391         p_free_picture = p_destroyed_picture;        
392     }
393
394     /*
395      * Prepare picture
396      */
397     if( p_free_picture != NULL )
398     {
399         /* Allocate memory */
400         switch( i_type )
401         {
402         case YUV_420_PICTURE:                   /* YUV picture: bits per pixel */
403         case YUV_422_PICTURE:
404         case YUV_444_PICTURE:
405             p_free_picture->p_data = malloc( 3 * i_height * i_bytes_per_line );                
406             p_free_picture->p_y = (yuv_data_t *) p_free_picture->p_data;
407             p_free_picture->p_u = (yuv_data_t *)(p_free_picture->p_data + i_height * i_bytes_per_line);
408             p_free_picture->p_v = (yuv_data_t *)(p_free_picture->p_data + i_height * i_bytes_per_line * 2);
409             break;                
410 #ifdef DEBUG
411         default:
412             intf_DbgMsg("error: unknown picture type %d\n", i_type );
413             p_free_picture->p_data   =  NULL;            
414             break;            
415 #endif    
416         }
417
418         if( p_free_picture->p_data != NULL )
419         {        
420             /* Copy picture informations */
421             p_free_picture->i_type                      = i_type;
422             p_free_picture->i_status                    = RESERVED_PICTURE;
423             p_free_picture->i_width                     = i_width;
424             p_free_picture->i_height                    = i_height;
425             p_free_picture->i_bytes_per_line            = i_bytes_per_line;
426             p_free_picture->i_refcount                  = 0;            
427             p_free_picture->i_matrix_coefficients       = 1; 
428         }
429         else
430         {
431             /* Memory allocation failed : set picture as empty */
432             p_free_picture->i_type   =  EMPTY_PICTURE;            
433             p_free_picture->i_status =  FREE_PICTURE;            
434             p_free_picture =            NULL;            
435             intf_ErrMsg("warning: %s\n", strerror( ENOMEM ) );            
436         }
437         
438 #ifdef DEBUG_VIDEO
439         intf_DbgMsg("picture %p (in free picture slot)\n", p_free_picture );        
440 #endif
441         vlc_mutex_unlock( &p_vout->lock );
442         return( p_free_picture );
443     }
444     
445     // No free or destroyed picture could be found
446     intf_DbgMsg( "warning: heap is full\n" );
447     vlc_mutex_unlock( &p_vout->lock );
448     return( NULL );
449 }
450
451 /*******************************************************************************
452  * vout_DestroyPicture: remove a permanent or reserved picture from the heap
453  *******************************************************************************
454  * This function frees a previously reserved picture or a permanent
455  * picture. It is meant to be used when the construction of a picture aborted.
456  * Note that the picture will be destroyed even if it is linked !
457  *******************************************************************************/
458 void vout_DestroyPicture( vout_thread_t *p_vout, picture_t *p_pic )
459 {
460     vlc_mutex_lock( &p_vout->lock );
461
462 #ifdef DEBUG_VIDEO
463    /* Check if picture status is valid */
464    if( p_pic->i_status != RESERVED_PICTURE )
465    {
466        intf_DbgMsg("error: picture %d has invalid status %d\n", 
467                    p_pic, p_pic->i_status );       
468    }   
469 #endif
470
471     p_pic->i_status = DESTROYED_PICTURE;
472
473 #ifdef DEBUG_VIDEO
474     intf_DbgMsg("picture %p\n", p_pic);    
475 #endif
476
477     vlc_mutex_unlock( &p_vout->lock );
478 }
479
480 /*******************************************************************************
481  * vout_LinkPicture: increment reference counter of a picture
482  *******************************************************************************
483  * This function increment the reference counter of a picture in the video
484  * heap.
485  *******************************************************************************/
486 void vout_LinkPicture( vout_thread_t *p_vout, picture_t *p_pic )
487 {
488     vlc_mutex_lock( &p_vout->lock );
489     p_pic->i_refcount++;
490
491 #ifdef DEBUG_VIDEO
492     intf_DbgMsg("picture %p\n", p_pic);    
493 #endif
494
495     vlc_mutex_unlock( &p_vout->lock );
496 }
497
498 /*******************************************************************************
499  * vout_UnlinkPicture: decrement reference counter of a picture
500  *******************************************************************************
501  * This function decrement the reference counter of a picture in the video heap.
502  *******************************************************************************/
503 void vout_UnlinkPicture( vout_thread_t *p_vout, picture_t *p_pic )
504 {
505     vlc_mutex_lock( &p_vout->lock );
506     p_pic->i_refcount--;
507     if( (p_pic->i_refcount == 0) && (p_pic->i_status == DISPLAYED_PICTURE) )
508     {
509         p_pic->i_status = DESTROYED_PICTURE;
510     }
511
512 #ifdef DEBUG_VIDEO
513     intf_DbgMsg("picture %p\n", p_pic);    
514 #endif
515
516     vlc_mutex_unlock( &p_vout->lock );    
517 }
518
519 /* following functions are local */
520
521 /*******************************************************************************
522  * InitThread: initialize video output thread
523  *******************************************************************************
524  * This function is called from RunThread and performs the second step of the
525  * initialization. It returns 0 on success. Note that the thread's flag are not
526  * modified inside this function.
527  *******************************************************************************/
528 static int InitThread( vout_thread_t *p_vout )
529 {
530     int     i_index;                                          /* generic index */    
531     int     i_pixel_size;     /* pixel size, in bytes, for translations tables */    
532
533     /* Update status */
534     *p_vout->pi_status = THREAD_START;    
535     
536     /* Initialize pictures */    
537     p_vout->i_pictures = 0;
538     for( i_index = 0; i_index < VOUT_MAX_PICTURES; i_index++)
539     {
540         p_vout->p_picture[i_index].i_type  = EMPTY_PICTURE;
541         p_vout->p_picture[i_index].i_status= FREE_PICTURE;
542     }
543
544 #ifdef STATS
545     /* Initialize FPS index - since samples won't be used until a minimum of
546      * pictures, they don't need to be initialized */
547     p_vout->i_fps_index = 0;    
548 #endif
549
550     /* Initialize output method - this function issues its own error messages */
551     if( vout_SysInit( p_vout ) )
552     {
553         *p_vout->pi_status = THREAD_ERROR;        
554         return( 1 );
555     } 
556
557     /* Allocate translation tables */
558     switch( p_vout->i_bytes_per_pixel )
559     {
560     case 2:                   /* 15 or 16 bpp, use 16 bits translations tables */        
561         i_pixel_size = sizeof( u16 );        
562         break;                
563     case 3:                   /* 24 or 32 bpp, use 32 bits translations tables */        
564     case 4:
565 #ifndef DEBUG
566     default:        
567 #endif
568         i_pixel_size = sizeof( u32 );
569         break;
570 #ifdef DEBUG
571     default:
572         intf_DbgMsg("error: invalid bytes_per_pixel %d\n", p_vout->i_bytes_per_pixel );
573         i_pixel_size = sizeof( u32 );        
574         break;              
575 #endif
576     }
577     p_vout->pi_trans32_red =   (u32 *)p_vout->pi_trans16_red =   
578         (u16 *)malloc( 1024 * i_pixel_size );
579     p_vout->pi_trans32_green = (u32 *)p_vout->pi_trans16_green = 
580         (u16 *)malloc( 1024 * i_pixel_size );
581     p_vout->pi_trans32_blue =  (u32 *)p_vout->pi_trans16_blue =  
582         (u16 *)malloc( 1024 * i_pixel_size );
583     if( (p_vout->pi_trans16_red == NULL) || 
584         (p_vout->pi_trans16_green == NULL ) ||
585         (p_vout->pi_trans16_blue == NULL ) )
586     {
587         intf_ErrMsg("error: %s\n", strerror(ENOMEM) );
588         *p_vout->pi_status = THREAD_ERROR;   
589         if( p_vout->pi_trans16_red != NULL )
590         {
591             free( p_vout->pi_trans16_red );
592         }
593         if( p_vout->pi_trans16_green != NULL )
594         {
595             free( p_vout->pi_trans16_green );
596         }
597         if( p_vout->pi_trans16_blue != NULL )
598         {
599             free( p_vout->pi_trans16_blue );
600         }
601         return( 1 );
602     }              
603     
604     /* Translate translation tables */
605     p_vout->pi_trans16_red      += 384;
606     p_vout->pi_trans16_green    += 384;
607     p_vout->pi_trans16_blue     += 384;
608     p_vout->pi_trans32_red      += 384;
609     p_vout->pi_trans32_green    += 384;
610     p_vout->pi_trans32_blue     += 384;
611
612     /* Build translation tables */
613     switch( p_vout->i_screen_depth )
614     {
615     case 15:
616         for( i_index = -384; i_index < 640; i_index++) 
617         {
618             p_vout->pi_trans16_red[i_index]     = (CLIP_BYTE( i_index ) & 0xf8)<<7;
619             p_vout->pi_trans16_green[i_index]   = (CLIP_BYTE( i_index ) & 0xf8)<<2;
620             p_vout->pi_trans16_blue[i_index]    =  CLIP_BYTE( i_index ) >> 3;
621         }
622         break;        
623     case 16:
624         for( i_index = -384; i_index < 640; i_index++) 
625         {
626             p_vout->pi_trans16_red[i_index]     = (CLIP_BYTE( i_index ) & 0xf8)<<8;
627             p_vout->pi_trans16_green[i_index]   = (CLIP_BYTE( i_index ) & 0xfc)<<3;
628             p_vout->pi_trans16_blue[i_index]    =  CLIP_BYTE( i_index ) >> 3;
629         }
630         break;        
631     case 24:
632     case 32:        
633         for( i_index = -384; i_index < 640; i_index++) 
634         {
635             p_vout->pi_trans32_red[i_index]     =  CLIP_BYTE( i_index ) <<16;
636             p_vout->pi_trans32_green[i_index]   =  CLIP_BYTE( i_index ) <<8;
637             p_vout->pi_trans32_blue[i_index]    =  CLIP_BYTE( i_index ) ;
638         }
639         break;        
640 #ifdef DEBUG
641     default:
642         intf_DbgMsg("error: invalid screen depth %d\n", p_vout->i_screen_depth );
643         break;      
644 #endif
645     }
646     
647     /* Mark thread as running and return */
648     p_vout->b_active =          1;    
649     *p_vout->pi_status =        THREAD_READY;    
650     intf_DbgMsg("thread ready\n");    
651     return(0);    
652 }
653
654 /*******************************************************************************
655  * RunThread: video output thread
656  *******************************************************************************
657  * Video output thread. This function does only returns when the thread is
658  * terminated. It handles the pictures arriving in the video heap and the
659  * display device events.
660  *******************************************************************************/
661 static void RunThread( vout_thread_t *p_vout)
662 {
663     int             i_picture;                                /* picture index */
664     int             i_err;                                       /* error code */
665     mtime_t         current_date;                              /* current date */
666     picture_t *     p_pic;                                  /* picture pointer */    
667     mtime_t         pic_date = 0;                              /* picture date */    
668
669     /* 
670      * Initialize thread and free configuration 
671      */
672     p_vout->b_error = InitThread( p_vout );
673     if( p_vout->b_error )
674     {
675         free( p_vout );                                  /* destroy descriptor */
676         return;        
677     }    
678
679     /*
680      * Main loop - it is not executed if an error occured during
681      * initialization
682      */
683     while( (!p_vout->b_die) && (!p_vout->b_error) )
684     {
685         /* 
686          * Find the picture to display - this is the only operation requiring
687          * the lock on the picture, since once a READY_PICTURE has been found,
688          * it can't be modified by the other threads (except if it is unliked,
689          * but its data remains)
690          */
691         p_pic = NULL;         
692         vlc_mutex_lock( &p_vout->lock );
693         for( i_picture = 0; i_picture < VOUT_MAX_PICTURES; i_picture++ )
694         {
695             if( (p_vout->p_picture[i_picture].i_status == READY_PICTURE) &&
696                 ( (p_pic == NULL) || 
697                   (p_vout->p_picture[i_picture].date < pic_date) ) )
698             {
699                 p_pic = &p_vout->p_picture[i_picture];
700                 pic_date = p_pic->date;                
701             }
702         }
703         vlc_mutex_unlock( &p_vout->lock );
704
705         /* 
706          * Render picture if any
707          */
708         if( p_pic )
709         {
710 #ifdef STATS
711             /* Computes FPS rate */
712             p_vout->fps_sample[ p_vout->i_fps_index++ ] = pic_date;
713             if( p_vout->i_fps_index == VOUT_FPS_SAMPLES )
714             {
715                 p_vout->i_fps_index = 0;                
716             }                            
717 #endif
718             current_date = mdate();
719             if( pic_date < current_date )
720             {
721                 /* Picture is late: it will be destroyed and the thread will go
722                  * immediately to next picture */
723                 vlc_mutex_lock( &p_vout->lock );
724                 if( p_pic->i_refcount )
725                 {
726                     p_pic->i_status = DISPLAYED_PICTURE;
727                 }
728                 else
729                 {
730                     p_pic->i_status = DESTROYED_PICTURE;
731                 }
732
733 #ifdef DEBUG_VIDEO
734                 intf_DbgMsg( "warning: late picture %p skipped\n", p_pic );
735 #endif
736                 vlc_mutex_unlock( &p_vout->lock );
737                 p_pic = NULL;
738             }
739             else if( pic_date > current_date + VOUT_DISPLAY_DELAY )
740             {
741                 /* A picture is ready to be rendered, but its rendering date is
742                  * far from the current one so the thread will perform an empty loop
743                  * as if no picture were found. The picture state is unchanged */
744                 p_pic = NULL;
745             }
746             else
747             {
748                 /* Picture has not yet been displayed, and has a valid display
749                  * date : render it, then forget it */
750                 RenderPicture( p_vout, p_pic );
751                 vlc_mutex_lock( &p_vout->lock );
752                 if( p_pic->i_refcount )
753                 {
754                     p_pic->i_status = DISPLAYED_PICTURE;
755                 }
756                 else
757                 {
758                     p_pic->i_status = DESTROYED_PICTURE;
759                 }
760                 vlc_mutex_unlock( &p_vout->lock );
761
762                 /* Print additional informations */
763                 if( p_vout->b_info )
764                 {                    
765                     RenderInfo( p_vout );
766                 }                
767             }
768         }
769     
770         /*
771          * Check events, sleep and display picture
772          */
773         i_err = vout_SysManage( p_vout );
774         if( i_err < 0 )
775         {
776             /* A fatal error occured, and the thread must terminate immediately,
777              * without displaying anything - setting b_error to 1 cause the
778              * immediate end of the main while() loop. */
779             p_vout->b_error = 1;
780         }
781         else 
782         {
783             if( p_pic )
784             {
785                 /* A picture is ready to be displayed : sleep until its display date */
786                 mwait( pic_date );
787
788                 if( !i_err )
789                 {
790                     vout_SysDisplay( p_vout );
791                 }
792             }
793             else
794             {
795                 /* Sleep to wait for new pictures */
796                 msleep( VOUT_IDLE_SLEEP );
797 #ifdef STATS
798                 /* Update counters */
799                 p_vout->c_idle_loops++;
800 #endif
801             }
802         }
803
804 #ifdef STATS
805         /* Update counters */
806         p_vout->c_loops++;
807 #endif
808     } 
809
810     /*
811      * Error loop
812      */
813     if( p_vout->b_error )
814     {
815         ErrorThread( p_vout );        
816     }
817
818     /* End of thread */
819     EndThread( p_vout );
820     intf_DbgMsg( "thread end\n" );
821 }
822
823 /*******************************************************************************
824  * ErrorThread: RunThread() error loop
825  *******************************************************************************
826  * This function is called when an error occured during thread main's loop. The
827  * thread can still receive feed, but must be ready to terminate as soon as
828  * possible.
829  *******************************************************************************/
830 static void ErrorThread( vout_thread_t *p_vout )
831 {
832     /* Wait until a `die' order */
833     while( !p_vout->b_die )
834     {
835         /* Sleep a while */
836         msleep( VOUT_IDLE_SLEEP );                
837     }
838 }
839
840 /*******************************************************************************
841  * EndThread: thread destruction
842  *******************************************************************************
843  * This function is called when the thread ends after a sucessfull 
844  * initialization.
845  *******************************************************************************/
846 static void EndThread( vout_thread_t *p_vout )
847 {
848     int *   pi_status;                                        /* thread status */
849     int     i_picture;
850         
851     /* Store status */
852     pi_status = p_vout->pi_status;    
853     *pi_status = THREAD_END;    
854
855     /* Destroy all remaining pictures */
856     for( i_picture = 0; i_picture < VOUT_MAX_PICTURES; i_picture++ )
857     {
858         if( p_vout->p_picture[i_picture].i_status != FREE_PICTURE )
859         {
860             free( p_vout->p_picture[i_picture].p_data );
861         }
862     }
863
864     /* Destroy translation tables - remeber these tables are translated */    
865     free( p_vout->pi_trans16_red - 384 );
866     free( p_vout->pi_trans16_green - 384 );
867     free( p_vout->pi_trans16_blue - 384 );
868     
869     /* Destroy thread structures allocated by InitThread */
870     vout_SysEnd( p_vout );
871     vout_SysDestroy( p_vout );
872     free( p_vout );
873
874     /* Update status */
875     *pi_status = THREAD_OVER;    
876 }
877
878 /*******************************************************************************
879  * RenderPicture: render a picture
880  *******************************************************************************
881  * This function convert a picture from a video heap to a pixel-encoded image
882  * and copy it to the current rendering buffer. No lock is required, since the
883  * rendered picture has been determined as existant, and will only be destroyed
884  * by the vout thread later.
885  * ???? 24 and 32 bpp should probably be separated
886  *******************************************************************************/
887 static void RenderPicture( vout_thread_t *p_vout, picture_t *p_pic )
888 {
889 #ifdef DEBUG_VIDEO
890     /* Send picture informations */
891     intf_DbgMsg("picture %p\n", p_pic );
892
893     /* Store rendering start date */
894     p_vout->picture_render_time = mdate();    
895 #endif
896
897     switch( p_pic->i_type )
898     {
899     case YUV_420_PICTURE:                   /* YUV picture: YUV transformation */        
900     case YUV_422_PICTURE:
901     case YUV_444_PICTURE:
902         if( p_vout->b_grayscale )                                 /* grayscale */
903         {
904             RenderYUVGrayPicture( p_vout, p_pic );            
905         }
906         else if( p_vout->i_bytes_per_pixel == 2 )        /* color 15 or 16 bpp */
907         {
908             RenderYUV16Picture( p_vout, p_pic );        
909         }
910         else                                             /* color 24 or 32 bpp */
911         {
912             RenderYUV32Picture( p_vout, p_pic );            
913         }
914         break;        
915 #ifdef DEBUG
916     default:        
917         intf_DbgMsg("error: unknown picture type %d\n", p_pic->i_type );
918         break;        
919 #endif
920     }
921
922 #ifdef DEBUG_VIDEO
923     /* Computes rendering time */
924     p_vout->picture_render_time = mdate() - p_vout->picture_render_time;    
925 #endif
926 }
927
928 /*******************************************************************************
929  * RenderYUVGrayPicture: render a 15, 16, 24 or 32 bpp YUV picture in grayscale
930  *******************************************************************************
931  * Performs the YUV convertion. The picture sent to this function should only
932  * have YUV_420, YUV_422 or YUV_444 types.
933  *******************************************************************************/
934 static void RenderYUVGrayPicture( vout_thread_t *p_vout, picture_t *p_pic )
935 {
936     int         i_pic_x, i_pic_y;                /* x,y coordinates in picture */
937     int         i_width, i_height;                             /* picture size */
938     int         i_eol_offset;          /* pixels from end of line to next line */   
939     yuv_data_t *p_y;                                     /* Y data base adress */
940     yuv_data_t  i_y;                                               /* Y sample */
941     u16 *       pi_pic16;                 /* destination picture, 15 or 16 bpp */
942     u32 *       pi_pic32;                 /* destination picture, 24 or 32 bpp */
943     u16 *       pi_trans16_red;                    /* red transformation table */
944     u16 *       pi_trans16_green;                /* green transformation table */
945     u16 *       pi_trans16_blue;                  /* blue transformation table */
946     u32 *       pi_trans32_red;                    /* red transformation table */
947     u32 *       pi_trans32_green;                /* green transformation table */
948     u32 *       pi_trans32_blue;                  /* blue transformation table */
949  
950     /* Set the base pointers and transformation parameters */
951     p_y =               p_pic->p_y;
952     i_width =           p_pic->i_width;
953     i_height =          p_pic->i_height;
954     i_eol_offset =      p_vout->i_bytes_per_line / p_vout->i_bytes_per_pixel - i_width;
955
956     /* Get base adress for destination image and translation tables, then
957      * transform image */
958     switch( p_vout->i_screen_depth )
959     {
960     case 15:
961     case 16:
962         pi_trans16_red =      p_vout->pi_trans16_red;
963         pi_trans16_green =    p_vout->pi_trans16_green;
964         pi_trans16_blue =     p_vout->pi_trans16_blue;        
965         pi_pic16 = (u16 *) vout_SysGetPicture( p_vout );
966
967         YUV_GRAYSCALE( pi_trans16_red, pi_trans16_green, pi_trans16_blue,
968                        pi_pic16 );
969         break;        
970     case 24:        
971     case 32:
972         pi_trans32_red =      p_vout->pi_trans32_red;
973         pi_trans32_green =    p_vout->pi_trans32_green;
974         pi_trans32_blue =     p_vout->pi_trans32_blue;    
975         pi_pic32 = (u32 *) vout_SysGetPicture( p_vout );
976
977         YUV_GRAYSCALE( pi_trans32_red, pi_trans32_green, pi_trans32_blue,
978                        pi_pic32 );
979         break;        
980 #ifdef DEBUG
981     default:
982         intf_DbgMsg("error: invalid screen depth %d\n", p_vout->i_screen_depth );
983         break;    
984 #endif      
985     }
986 }
987
988
989 /*******************************************************************************
990  * RenderYUV16Picture: render a 15 or 16 bpp YUV picture
991  *******************************************************************************
992  * Performs the YUV convertion. The picture sent to this function should only
993  * have YUV_420, YUV_422 or YUV_444 types.
994  *******************************************************************************/
995 static void RenderYUV16Picture( vout_thread_t *p_vout, picture_t *p_pic )
996 {
997     int         i_crv, i_cbu, i_cgu, i_cgv;     /* transformation coefficients */
998     int         i_pic_x, i_pic_y;                /* x,y coordinates in picture */
999     int         i_y, i_u, i_v;                           /* Y, U and V samples */
1000     int         i_width, i_height;                             /* picture size */
1001     int         i_chroma_width;                                /* chroma width */    
1002     int         i_eol_offset;          /* pixels from end of line to next line */
1003     yuv_data_t *p_y;                                     /* Y data base adress */
1004     yuv_data_t *p_u;                                     /* U data base adress */
1005     yuv_data_t *p_v;                                     /* V data base adress */
1006     u16 *       pi_pic;                 /* base adress for destination picture */
1007     u16 *       pi_trans_red;                      /* red transformation table */
1008     u16 *       pi_trans_green;                  /* green transformation table */
1009     u16 *       pi_trans_blue;                    /* blue transformation table */
1010  
1011     /* Choose transformation matrix coefficients */
1012     i_crv = MATRIX_COEFFICIENTS_TABLE[p_pic->i_matrix_coefficients][0];
1013     i_cbu = MATRIX_COEFFICIENTS_TABLE[p_pic->i_matrix_coefficients][1];
1014     i_cgu = MATRIX_COEFFICIENTS_TABLE[p_pic->i_matrix_coefficients][2];
1015     i_cgv = MATRIX_COEFFICIENTS_TABLE[p_pic->i_matrix_coefficients][3];
1016
1017     /* Choose the conversions tables */
1018     pi_trans_red =      p_vout->pi_trans16_red;
1019     pi_trans_green =    p_vout->pi_trans16_green;
1020     pi_trans_blue =     p_vout->pi_trans16_blue;    
1021
1022     /* Set the base pointers and transformation parameters */
1023     p_y =               p_pic->p_y;
1024     p_u =               p_pic->p_u;
1025     p_v =               p_pic->p_v;
1026     i_width =           p_pic->i_width;
1027     i_height =          p_pic->i_height;
1028     i_chroma_width =    i_width / 2;
1029     i_eol_offset =      p_vout->i_bytes_per_line / 2 - i_width;    
1030         
1031     /* Get base adress for destination image */
1032     pi_pic = (u16 *)vout_SysGetPicture( p_vout );
1033
1034     /* Do YUV transformation - the loops are repeated for optimization */
1035     switch( p_pic->i_type )
1036     {
1037     case YUV_420_PICTURE:                   /* 15 or 16 bpp 420 transformation */
1038 #ifdef HAVE_MMX
1039         vout_YUV420_16_MMX( p_y, p_u, p_v, 
1040                             i_width, i_height, 
1041                             i_width, i_chroma_width,
1042                             0, (u8 *) pi_pic, 
1043                             0, 0, p_vout->i_bytes_per_line, 
1044                             p_vout->i_screen_depth == 15 );
1045 #else
1046         YUV_TRANSFORM( 420,
1047                        pi_trans_red, 
1048                        pi_trans_green, 
1049                        pi_trans_blue,
1050                        pi_pic );            
1051 #endif
1052         break;
1053     case YUV_422_PICTURE:                   /* 15 or 16 bpp 422 transformation */
1054         YUV_TRANSFORM( 422,
1055                        pi_trans_red, 
1056                        pi_trans_green, 
1057                        pi_trans_blue,
1058                        pi_pic );            
1059         break;
1060     case YUV_444_PICTURE:                   /* 15 or 16 bpp 444 transformation */
1061         YUV_TRANSFORM( 444,
1062                        pi_trans_red, 
1063                        pi_trans_green, 
1064                        pi_trans_blue,
1065                        pi_pic );            
1066         break;                 
1067     }
1068 }
1069
1070 /*******************************************************************************
1071  * RenderYUV32Picture: render a 24 or 32 bpp YUV picture
1072  *******************************************************************************
1073  * Performs the YUV convertion. The picture sent to this function should only
1074  * have YUV_420, YUV_422 or YUV_444 types.
1075  *******************************************************************************/
1076 static void RenderYUV32Picture( vout_thread_t *p_vout, picture_t *p_pic )
1077 {
1078     int         i_crv, i_cbu, i_cgu, i_cgv;     /* transformation coefficients */
1079     int         i_pic_x, i_pic_y;                /* x,y coordinates in picture */
1080     int         i_y, i_u, i_v;                           /* Y, U and V samples */
1081     int         i_width, i_height;                             /* picture size */
1082     int         i_chroma_width;                                /* chroma width */    
1083     int         i_eol_offset;          /* pixels from end of line to next line */
1084     yuv_data_t *p_y;                                     /* Y data base adress */
1085     yuv_data_t *p_u;                                     /* U data base adress */
1086     yuv_data_t *p_v;                                     /* V data base adress */
1087     u32 *       pi_pic;                 /* base adress for destination picture */
1088     u32 *       pi_trans_red;                      /* red transformation table */
1089     u32 *       pi_trans_green;                  /* green transformation table */
1090     u32 *       pi_trans_blue;                    /* blue transformation table */
1091  
1092     /* Choose transformation matrix coefficients */
1093     i_crv = MATRIX_COEFFICIENTS_TABLE[p_pic->i_matrix_coefficients][0];
1094     i_cbu = MATRIX_COEFFICIENTS_TABLE[p_pic->i_matrix_coefficients][1];
1095     i_cgu = MATRIX_COEFFICIENTS_TABLE[p_pic->i_matrix_coefficients][2];
1096     i_cgv = MATRIX_COEFFICIENTS_TABLE[p_pic->i_matrix_coefficients][3];
1097
1098     /* Choose the conversions tables */
1099     pi_trans_red =      p_vout->pi_trans32_red;
1100     pi_trans_green =    p_vout->pi_trans32_green;
1101     pi_trans_blue =     p_vout->pi_trans32_blue;    
1102
1103     /* Set the base pointers and transformation parameters */
1104     p_y =               p_pic->p_y;
1105     p_u =               p_pic->p_u;
1106     p_v =               p_pic->p_v;
1107     i_width =           p_pic->i_width;
1108     i_height =          p_pic->i_height;
1109     i_chroma_width =    i_width / 2;
1110     i_eol_offset =      p_vout->i_bytes_per_line / p_vout->i_bytes_per_pixel - i_width;
1111         
1112     /* Get base adress for destination image */
1113     pi_pic = (u32 *)vout_SysGetPicture( p_vout );
1114
1115     /* Do YUV transformation - the loops are repeated for optimization */
1116     switch( p_pic->i_type )
1117     {
1118     case YUV_420_PICTURE:                   /* 24 or 32 bpp 420 transformation */
1119         YUV_TRANSFORM( 420,
1120                        pi_trans_red, 
1121                        pi_trans_green, 
1122                        pi_trans_blue,
1123                        pi_pic );            
1124         break;
1125     case YUV_422_PICTURE:                   /* 24 or 32 bpp 422 transformation */
1126         YUV_TRANSFORM( 422,
1127                        pi_trans_red, 
1128                        pi_trans_green, 
1129                        pi_trans_blue,
1130                        pi_pic );            
1131         break;
1132     case YUV_444_PICTURE:                   /* 24 or 32 bpp 444 transformation */
1133         YUV_TRANSFORM( 444,
1134                        pi_trans_red, 
1135                        pi_trans_green, 
1136                        pi_trans_blue,
1137                        pi_pic );            
1138         break;                 
1139     }
1140 }
1141
1142 /*******************************************************************************
1143  * RenderInfo: print additionnal informations on a picture
1144  *******************************************************************************
1145  * This function will add informations such as fps and buffer size on a picture
1146  *******************************************************************************/
1147 static void RenderInfo( vout_thread_t *p_vout )
1148 {
1149     char        psz_buffer[256];                              /* string buffer */
1150
1151 #ifdef STATS
1152     /* Print FPS rate */
1153     if( p_vout->c_pictures > VOUT_FPS_SAMPLES )
1154     {        
1155         sprintf( psz_buffer, "%.2f fps", (double) VOUT_FPS_SAMPLES * 1000000 /
1156                  ( p_vout->fps_sample[ (p_vout->i_fps_index + (VOUT_FPS_SAMPLES - 1)) % 
1157                                      VOUT_FPS_SAMPLES ] -
1158                    p_vout->fps_sample[ p_vout->i_fps_index ] ) );        
1159         vout_SysPrint( p_vout, p_vout->i_width, 0, 1, -1, psz_buffer );
1160     }
1161
1162     /* Print statistics */
1163     sprintf( psz_buffer, "%ld pictures, %.1f %% idle loops", p_vout->c_pictures,
1164              (double) p_vout->c_idle_loops * 100 / p_vout->c_loops );    
1165     vout_SysPrint( p_vout, 0, 0, -1, -1, psz_buffer );    
1166 #endif
1167     
1168 #ifdef DEBUG
1169     /* Print heap size  */
1170     sprintf( psz_buffer, "video heap size: %d (%.1f %%)", p_vout->i_pictures,
1171              (double) p_vout->i_pictures * 100 / VOUT_MAX_PICTURES );
1172     vout_SysPrint( p_vout, 0, p_vout->i_height, -1, 1, psz_buffer );    
1173 #endif
1174
1175 #ifdef DEBUG_VIDEO
1176     /* Print rendering statistics */
1177     sprintf( psz_buffer, "picture rendering time: %lu us", 
1178              (unsigned long) p_vout->picture_render_time );    
1179     vout_SysPrint( p_vout, p_vout->i_width, p_vout->i_height, 1, 1, psz_buffer );    
1180 #endif
1181 }
1182
1183