]> git.sesse.net Git - vlc/blob - src/video_output/video_output.c
GGI fonctionnel. N'oubliez pas de d�finit GII_INPUT.
[vlc] / src / video_output / video_output.c
1 /*******************************************************************************
2  * video_output.c : video output thread
3  * (c)1999 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
31 /*******************************************************************************
32  * Macros
33  *******************************************************************************/
34
35 /* CLIP_BYTE: return value if between 0 and 255, else return nearest boundary 
36  * (0 or 255) */
37 #define CLIP_BYTE( i_val ) ( (i_val < 0) ? 0 : ((i_val > 255) ? 255 : i_val) )
38
39 /* YUV_TRANSFORM: parametric macro for YUV transformation.
40  * Due to the high performance need of this loop, all possible conditions 
41  * evaluations are made outside the transformation loop. However, the code does 
42  * not change much for two different loops. This macro allows to change slightly
43  * the content of the loop without having to copy and paste code. It is used in 
44  * RenderYUVPicture function. */
45 #define YUV_TRANSFORM( CHROMA, TRANS_RED, TRANS_GREEN, TRANS_BLUE, P_PIC ) \
46 /* Main loop */                                                         \
47 for (i_pic_y=0; i_pic_y < p_pic->i_height ; i_pic_y++)                  \
48 {                                                                       \
49     for (i_pic_x=0; i_pic_x< p_pic->i_width; i_pic_x+=2)                \
50     {                                                                   \
51         /* First sample (complete) */                                   \
52         i_y = 76309 * *p_y++ - 1188177;                                 \
53         i_u = *p_u++ - 128;                                             \
54         i_v = *p_v++ - 128;                                             \
55         *P_PIC++ =                                                      \
56             TRANS_RED   [(i_y+i_crv*i_v)                >>16] |         \
57             TRANS_GREEN [(i_y-i_cgu*i_u-i_cgv*i_v)      >>16] |         \
58             TRANS_BLUE  [(i_y+i_cbu*i_u)                >>16];          \
59         i_y = 76309 * *p_y++ - 1188177;                                 \
60         /* Second sample (partial) */                                   \
61         if( CHROMA == 444 )                                             \
62         {                                                               \
63             i_u = *p_u++ - 128;                                         \
64             i_v = *p_v++ - 128;                                         \
65         }                                                               \
66         *P_PIC++ =                                                      \
67             TRANS_RED   [(i_y+i_crv*i_v)                >>16] |         \
68             TRANS_GREEN [(i_y-i_cgu*i_u-i_cgv*i_v)      >>16] |         \
69             TRANS_BLUE  [(i_y+i_cbu*i_u)                >>16];          \
70     }                                                                   \
71     if( (CHROMA == 420) && !(i_pic_y & 0x1) )                           \
72     {                                                                   \
73         p_u -= p_pic->i_width;                                          \
74         p_v -= p_pic->i_width;                                          \
75     }                                                                   \
76     /* Skip until beginning of next line */                             \
77     P_PIC += i_pic_eol_offset - p_pic->i_width;                         \
78 }
79
80 /*******************************************************************************
81  * Constants
82  *******************************************************************************/
83
84 /* RGB/YUV inversion matrix (ISO/IEC 13818-2 section 6.3.6, table 6.9) */
85 int matrix_coefficients_table[8][4] =
86 {
87   {117504, 138453, 13954, 34903},       /* no sequence_display_extension */
88   {117504, 138453, 13954, 34903},       /* ITU-R Rec. 709 (1990) */
89   {104597, 132201, 25675, 53279},       /* unspecified */
90   {104597, 132201, 25675, 53279},       /* reserved */
91   {104448, 132798, 24759, 53109},       /* FCC */
92   {104597, 132201, 25675, 53279},       /* ITU-R Rec. 624-4 System B, G */
93   {104597, 132201, 25675, 53279},       /* SMPTE 170M */
94   {117579, 136230, 16907, 35559}        /* SMPTE 240M (1987) */
95 };
96
97 /*******************************************************************************
98  * Local prototypes
99  *******************************************************************************/
100 static int      InitThread      ( vout_thread_t *p_vout );
101 static void     RunThread       ( vout_thread_t *p_vout );
102 static void     ErrorThread     ( vout_thread_t *p_vout );
103 static void     EndThread       ( vout_thread_t *p_vout );
104 static void     RenderPicture   ( vout_thread_t *p_vout, picture_t *p_pic );
105 static void     RenderYUVPicture( vout_thread_t *p_vout, picture_t *p_pic );
106
107 /*******************************************************************************
108  * vout_CreateThread: creates a new video output thread
109  *******************************************************************************
110  * This function creates a new video output thread, and returns a pointer
111  * to its description. On error, it returns NULL.
112  * If pi_status is NULL, then the function will block until the thread is ready.
113  * If not, it will be updated using one of the THREAD_* constants.
114  *******************************************************************************/
115 vout_thread_t * vout_CreateThread               ( 
116 #ifdef VIDEO_X11
117                                                   char *psz_display, Window root_window, 
118 #endif
119                                                   int i_width, int i_height, int *pi_status 
120                                                 )
121 {
122     vout_thread_t * p_vout;                               /* thread descriptor */
123     int             i_status;                                 /* thread status */
124
125     /* Allocate descriptor */
126     p_vout = (vout_thread_t *) malloc( sizeof(vout_thread_t) );
127     if( p_vout == NULL )
128     {
129         intf_ErrMsg("error: %s\n", strerror(ENOMEM));        
130         return( NULL );
131     }
132
133     /* Initialize some fields used by the system-dependant method - these fields will
134      * probably be modified by the method */
135     p_vout->i_width             = i_width;
136     p_vout->i_height            = i_height;
137     p_vout->i_screen_depth      = 15;
138     p_vout->i_bytes_per_pixel   = 2;
139     p_vout->f_x_ratio           = 1;
140     p_vout->f_y_ratio           = 1;
141     intf_DbgMsg("wished configuration: %dx%dx%d (%d bytes per pixel), ratio %f:%f\n",
142                 p_vout->i_width, p_vout->i_height, p_vout->i_screen_depth,
143                 p_vout->i_bytes_per_pixel, p_vout->f_x_ratio, p_vout->f_y_ratio );    
144    
145     /* Create and initialize system-dependant method - this function issues its
146      * own error messages */
147     if( vout_SysCreate( p_vout
148 #if defined(VIDEO_X11)
149                         , psz_display, root_window 
150 #endif
151         ) )
152     {
153       free( p_vout );
154       return( NULL );
155     }
156     intf_DbgMsg("actual configuration: %dx%dx%d (%d bytes per pixel), ratio %f:%f\n",
157                 p_vout->i_width, p_vout->i_height, p_vout->i_screen_depth,
158                 p_vout->i_bytes_per_pixel, p_vout->f_x_ratio, p_vout->f_y_ratio );    
159   
160     /* Terminate the initialization */
161     p_vout->b_die               = 0;
162     p_vout->b_error             = 0;    
163     p_vout->b_active            = 0;
164     p_vout->pi_status           = (pi_status != NULL) ? pi_status : &i_status;
165     *p_vout->pi_status          = THREAD_CREATE;    
166 #ifdef STATS
167     p_vout->c_loops             = 0;
168     p_vout->c_idle_loops        = 0;
169     p_vout->c_pictures          = 0;    
170 #endif      
171
172     /* Create thread and set locks */
173     vlc_mutex_init( &p_vout->lock );
174     if( vlc_thread_create( &p_vout->thread_id, "video output", 
175                            (void *) RunThread, (void *) p_vout) )
176     {
177         intf_ErrMsg("error: %s\n", strerror(ENOMEM));
178         vout_SysDestroy( p_vout );
179         free( p_vout );
180         return( NULL );
181     }   
182
183     intf_Msg("Video: display initialized (%dx%d, %d bpp)\n", 
184              p_vout->i_width, p_vout->i_height, p_vout->i_screen_depth );    
185
186     /* If status is NULL, wait until the thread is created */
187     if( pi_status == NULL )
188     {
189         do
190         {            
191             msleep( THREAD_SLEEP );
192         }while( (i_status != THREAD_READY) && (i_status != THREAD_ERROR) 
193                 && (i_status != THREAD_FATAL) );
194         if( i_status != THREAD_READY )
195         {
196             return( NULL );            
197         }        
198     }
199     return( p_vout );
200 }
201
202 /*******************************************************************************
203  * vout_DestroyThread: destroys a previously created thread
204  *******************************************************************************
205  * Destroy a terminated thread. 
206  * The function will request a destruction of the specified thread. If pi_error
207  * is NULL, it will return once the thread is destroyed. Else, it will be 
208  * update using one of the THREAD_* constants.
209  *******************************************************************************/
210 void vout_DestroyThread( vout_thread_t *p_vout, int *pi_status )
211 {  
212     int     i_status;                                         /* thread status */
213
214     /* Set status */
215     p_vout->pi_status = (pi_status != NULL) ? pi_status : &i_status;
216     *p_vout->pi_status = THREAD_DESTROY;    
217      
218     /* Request thread destruction */
219     p_vout->b_die = 1;
220
221     /* If status is NULL, wait until thread has been destroyed */
222     if( pi_status == NULL )
223     {
224         do
225         {
226             msleep( THREAD_SLEEP );
227         }while( (i_status != THREAD_OVER) && (i_status != THREAD_ERROR) 
228                 && (i_status != THREAD_FATAL) );   
229     }
230 }
231
232 /*******************************************************************************
233  * vout_DisplayPicture: display a picture
234  *******************************************************************************
235  * Remove the reservation flag of a picture, which will cause it to be ready for
236  * display.
237  *******************************************************************************/
238 void  vout_DisplayPicture( vout_thread_t *p_vout, picture_t *p_pic )
239 {
240     vlc_mutex_lock( &p_vout->lock );
241
242     /* Remove reservation flag */
243     p_pic->i_status = READY_PICTURE;
244
245 #ifdef STATS
246     /* Update stats */
247     p_vout->c_pictures++;
248 #endif
249
250     vlc_mutex_unlock( &p_vout->lock );
251 }
252
253 /*******************************************************************************
254  * vout_CreatePicture: allocate a picture in the video output heap.
255  *******************************************************************************
256  * This function create a reserved image in the video output heap. 
257  * A null pointer is returned if the function fails. This method provides an
258  * already allocated zone of memory in the picture data fields.
259  *******************************************************************************/
260 picture_t *vout_CreatePicture( vout_thread_t *p_vout, int i_type, 
261                                int i_width, int i_height, int i_bytes_per_line )
262 {
263     int         i_picture;                                    /* picture index */
264     picture_t * p_free_picture = NULL;                   /* first free picture */    
265     picture_t * p_destroyed_picture = NULL;         /* first destroyed picture */    
266
267     /* Get lock */
268     vlc_mutex_lock( &p_vout->lock );
269
270     /* 
271      * Look for an empty place 
272      */
273     for( i_picture = 0; 
274          i_picture < VOUT_MAX_PICTURES; 
275          i_picture++ )
276     {
277         if( p_vout->p_picture[i_picture].i_status == DESTROYED_PICTURE )
278         {
279             /* Picture is marked for destruction, but is still allocated */
280             if( (p_vout->p_picture[i_picture].i_type           == i_type)   &&
281                 (p_vout->p_picture[i_picture].i_height         == i_height) &&
282                 (p_vout->p_picture[i_picture].i_bytes_per_line == i_bytes_per_line) )
283             {
284                 /* Memory size do match : memory will not be reallocated, and function
285                  * can end immediately - this is the best possible case, since no
286                  * memory allocation needs to be done */
287                 p_vout->p_picture[i_picture].i_width  = i_width;
288                 p_vout->p_picture[i_picture].i_status = RESERVED_PICTURE;
289                 vlc_mutex_unlock( &p_vout->lock );
290                 return( &p_vout->p_picture[i_picture] );
291             }
292             else if( p_destroyed_picture == NULL )
293             {
294                 /* Memory size do not match, but picture index will be kept in
295                  * case no other place are left */
296                 p_destroyed_picture = &p_vout->p_picture[i_picture];                
297             }       
298         }
299         else if( (p_free_picture == NULL) && 
300                  (p_vout->p_picture[i_picture].i_status == FREE_PICTURE ))
301         {
302             /* Picture is empty and ready for allocation */
303             p_free_picture = &p_vout->p_picture[i_picture];            
304         }
305     }
306
307     /* If no free picture is available, use a destroyed picture */
308     if( (p_free_picture == NULL) && (p_destroyed_picture != NULL ) )
309     { 
310         /* No free picture or matching destroyed picture has been found, but
311          * a destroyed picture is still avalaible */
312         free( p_destroyed_picture->p_data );        
313         p_free_picture = p_destroyed_picture;        
314     }
315
316     /*
317      * Prepare picture
318      */
319     if( p_free_picture != NULL )
320     {
321         /* Allocate memory */
322         switch( i_type )
323         {
324         case YUV_420_PICTURE:                   /* YUV picture: bits per pixel */
325         case YUV_422_PICTURE:
326         case YUV_444_PICTURE:
327             p_free_picture->p_data = malloc( 3 * i_height * i_bytes_per_line );                
328             p_free_picture->p_y = (yuv_data_t *) p_free_picture->p_data;
329             p_free_picture->p_u = (yuv_data_t *)(p_free_picture->p_data + i_height * i_bytes_per_line);
330             p_free_picture->p_v = (yuv_data_t *)(p_free_picture->p_data + i_height * i_bytes_per_line * 2);
331             break;                
332 #ifdef DEBUG
333         default:
334             intf_DbgMsg("unknown picture type %d\n", i_type );
335             p_free_picture->p_data   =  NULL;            
336             break;            
337 #endif    
338         }
339
340         if( p_free_picture->p_data != NULL )
341         {        
342             /* Copy picture informations */
343             p_free_picture->i_type           = i_type;
344             p_free_picture->i_status         = RESERVED_PICTURE;
345             p_free_picture->i_width          = i_width;
346             p_free_picture->i_height         = i_height;
347             p_free_picture->i_bytes_per_line = i_bytes_per_line;
348             p_free_picture->i_refcount       = 0;            
349             p_free_picture->i_matrix_coefficients = 1; // ?? default value            
350         }
351         else
352         {
353             /* Memory allocation failed : set picture as empty */
354             p_free_picture->i_type   =  EMPTY_PICTURE;            
355             p_free_picture->i_status =  FREE_PICTURE;            
356             p_free_picture =            NULL;            
357             intf_ErrMsg("warning: %s\n", strerror( ENOMEM ) );            
358         }
359         
360         vlc_mutex_unlock( &p_vout->lock );
361         return( p_free_picture );
362     }
363     
364     // No free or destroyed picture could be found
365     intf_DbgMsg( "heap is full\n" );
366     vlc_mutex_unlock( &p_vout->lock );
367     return( NULL );
368 }
369
370 /*******************************************************************************
371  * vout_RemovePicture: remove a permanent or reserved picture from the heap
372  *******************************************************************************
373  * This function frees a previously reserved picture or a permanent
374  * picture. It is meant to be used when the construction of a picture aborted.
375  * Note that the picture will be destroyed even if it is linked !
376  *******************************************************************************/
377 void vout_DestroyPicture( vout_thread_t *p_vout, picture_t *p_pic )
378 {
379     vlc_mutex_lock( &p_vout->lock );
380     p_pic->i_status = DESTROYED_PICTURE;
381     vlc_mutex_unlock( &p_vout->lock );
382 }
383
384 /*******************************************************************************
385  * vout_LinkPicture: increment reference counter of a picture
386  *******************************************************************************
387  * This function increment the reference counter of a picture in the video
388  * heap.
389  *******************************************************************************/
390 void vout_LinkPicture( vout_thread_t *p_vout, picture_t *p_pic )
391 {
392     vlc_mutex_lock( &p_vout->lock );
393     p_pic->i_refcount++;
394     vlc_mutex_unlock( &p_vout->lock );
395 }
396
397 /*******************************************************************************
398  * vout_UnlinkPicture: decrement reference counter of a picture
399  *******************************************************************************
400  * This function decrement the reference counter of a picture in the video heap.
401  *******************************************************************************/
402 void vout_UnlinkPicture( vout_thread_t *p_vout, picture_t *p_pic )
403 {
404     vlc_mutex_lock( &p_vout->lock );
405     p_pic->i_refcount--;
406     if( (p_pic->i_refcount == 0) && (p_pic->i_status == DISPLAYED_PICTURE) )
407     {
408         p_pic->i_status = DESTROYED_PICTURE;
409     }
410     vlc_mutex_unlock( &p_vout->lock );    
411 }
412
413 /* following functions are local */
414
415 /*******************************************************************************
416  * InitThread: initialize video output thread
417  *******************************************************************************
418  * This function is called from RunThread and performs the second step of the
419  * initialization. It returns 0 on success. Note that the thread's flag are not
420  * modified inside this function.
421  *******************************************************************************/
422 static int InitThread( vout_thread_t *p_vout )
423 {
424     int     i_index;                                          /* generic index */    
425     int     i_pixel_size;     /* pixel size, in bytes, for translations tables */    
426
427     /* Update status */
428     *p_vout->pi_status = THREAD_START;    
429     
430     /* Initialize pictures */    
431     p_vout->i_pictures = 0;
432     for( i_index = 0; i_index < VOUT_MAX_PICTURES; i_index++)
433     {
434         p_vout->p_picture[i_index].i_type  = EMPTY_PICTURE;
435         p_vout->p_picture[i_index].i_status= FREE_PICTURE;
436     }
437
438     /* Initialize output method - this function issues its own error messages */
439     if( vout_SysInit( p_vout ) )
440     {
441         *p_vout->pi_status = THREAD_ERROR;        
442         return( 1 );
443     } 
444
445     /* Allocate translation tables */
446     switch( p_vout->i_bytes_per_pixel )
447     {
448     case 2:                   /* 15 or 16 bpp, use 16 bits translations tables */        
449         i_pixel_size = sizeof( u16 );        
450         break;                
451     case 3:                   /* 24 or 32 bpp, use 32 bits translations tables */        
452     case 4:
453 #ifndef DEBUG
454     default:        
455 #endif
456         i_pixel_size = sizeof( u32 );
457         break;
458 #ifdef DEBUG
459     default:
460         intf_DbgMsg("invalid bytes_per_pixel %d\n", p_vout->i_bytes_per_pixel );
461         i_pixel_size = sizeof( u32 );        
462         break;              
463 #endif
464     }
465     p_vout->pi_trans32_red =   (u32 *)p_vout->pi_trans16_red =   
466         (u16 *)malloc( 1024 * i_pixel_size );
467     p_vout->pi_trans32_green = (u32 *)p_vout->pi_trans16_green = 
468         (u16 *)malloc( 1024 * i_pixel_size );
469     p_vout->pi_trans32_blue =  (u32 *)p_vout->pi_trans16_blue =  
470         (u16 *)malloc( 1024 * i_pixel_size );
471     if( (p_vout->pi_trans16_red == NULL) || 
472         (p_vout->pi_trans16_green == NULL ) ||
473         (p_vout->pi_trans16_blue == NULL ) )
474     {
475         intf_ErrMsg("error: %s\n", strerror(ENOMEM) );
476         *p_vout->pi_status = THREAD_ERROR;   
477         if( p_vout->pi_trans16_red != NULL )
478         {
479             free( p_vout->pi_trans16_red );
480         }
481         if( p_vout->pi_trans16_green != NULL )
482         {
483             free( p_vout->pi_trans16_green );
484         }
485         if( p_vout->pi_trans16_blue != NULL )
486         {
487             free( p_vout->pi_trans16_blue );
488         }
489         return( 1 );
490     }              
491     
492     /* Translate translation tables */
493     p_vout->pi_trans16_red      += 384;
494     p_vout->pi_trans16_green    += 384;
495     p_vout->pi_trans16_blue     += 384;
496     p_vout->pi_trans32_red      += 384;
497     p_vout->pi_trans32_green    += 384;
498     p_vout->pi_trans32_blue     += 384;
499
500     /* Build translation tables */
501     switch( p_vout->i_screen_depth )
502     {
503     case 15:
504         for( i_index = -384; i_index < 640; i_index++) 
505         {
506             p_vout->pi_trans16_red[i_index]     = (CLIP_BYTE( i_index ) & 0xf8)<<7;
507             p_vout->pi_trans16_green[i_index]   = (CLIP_BYTE( i_index ) & 0xf8)<<2;
508             p_vout->pi_trans16_blue[i_index]    =  CLIP_BYTE( i_index ) >> 3;
509         }
510         break;        
511     case 16:
512         for( i_index = -384; i_index < 640; i_index++) 
513         {
514             p_vout->pi_trans16_red[i_index]     = (CLIP_BYTE( i_index ) & 0xf8)<<8;
515             p_vout->pi_trans16_green[i_index]   = (CLIP_BYTE( i_index ) & 0xf8)<<3;
516             p_vout->pi_trans16_blue[i_index]    =  CLIP_BYTE( i_index ) >> 3;
517         }
518         break;        
519     case 24:
520     case 32:        
521         for( i_index = -384; i_index < 640; i_index++) 
522         {
523             p_vout->pi_trans32_red[i_index]     =  CLIP_BYTE( i_index ) <<16;
524             p_vout->pi_trans32_green[i_index]   =  CLIP_BYTE( i_index ) <<8;
525             p_vout->pi_trans32_blue[i_index]    =  CLIP_BYTE( i_index ) ;
526         }
527         break;        
528 #ifdef DEBUG
529     default:
530         intf_DbgMsg("invalid screen depth %d\n", p_vout->i_screen_depth );
531         break;      
532 #endif
533     }
534     
535     /* Mark thread as running and return */
536     p_vout->b_active =          1;    
537     *p_vout->pi_status =        THREAD_READY;    
538     intf_DbgMsg("thread ready");    
539     return(0);    
540 }
541
542 /*******************************************************************************
543  * RunThread: video output thread
544  *******************************************************************************
545  * Video output thread. This function does only returns when the thread is
546  * terminated. It handles the pictures arriving in the video heap and the
547  * display device events.
548  *******************************************************************************/
549 static void RunThread( vout_thread_t *p_vout)
550 {
551     int             i_picture;                                /* picture index */
552     int             i_err;                                       /* error code */
553     mtime_t         current_date;                              /* current date */
554     picture_t *     p_pic = NULL;                           /* picture pointer */    
555
556     /* 
557      * Initialize thread and free configuration 
558      */
559     p_vout->b_error = InitThread( p_vout );
560     if( p_vout->b_error )
561     {
562         free( p_vout );                                  /* destroy descriptor */
563         return;        
564     }    
565
566     /*
567      * Main loop - it is not executed if an error occured during
568      * initialization
569      */
570     while( (!p_vout->b_die) && (!p_vout->b_error) )
571     {
572         /* 
573          * Find the picture to display - this is the only operation requiring
574          * the lock on the picture, since once a READY_PICTURE has been found,
575          * it can't be modified by the other threads (except if it is unliked,
576          * but its data remains)
577          */
578         vlc_mutex_lock( &p_vout->lock );
579
580         for( i_picture = 0; i_picture < VOUT_MAX_PICTURES; i_picture++ )
581         {
582             if( (p_vout->p_picture[i_picture].i_status == READY_PICTURE) &&
583                 ( (p_pic == NULL) || 
584                   (p_vout->p_picture[i_picture].date < p_pic->date) ) )
585             {
586                 p_pic = &p_vout->p_picture[i_picture];
587             }
588         }
589
590         vlc_mutex_unlock( &p_vout->lock );
591
592         /* 
593          * Render picture if any
594          */
595         if( p_pic )
596         {
597             current_date = mdate();
598             if( p_pic->date < current_date )
599             {
600                 /* Picture is late: it will be destroyed and the thread will go
601                  * immediately to next picture */
602                 vlc_mutex_lock( &p_vout->lock );
603                 if( p_pic->i_refcount )
604                 {
605                     p_pic->i_status = DISPLAYED_PICTURE;
606                 }
607                 else
608                 {
609                     p_pic->i_status = DESTROYED_PICTURE;
610                 }
611                 vlc_mutex_unlock( &p_vout->lock );
612                 intf_ErrMsg( "warning: late picture skipped\n" );
613                 p_pic = NULL;
614             }
615             else if( p_pic->date > current_date + VOUT_DISPLAY_DELAY )
616             {
617                 /* A picture is ready to be rendered, but its rendering date is
618                  * far from the current one so the thread will perform an empty loop
619                  * as if no picture were found. The picture state is unchanged */
620                 p_pic = NULL;
621             }
622             else
623             {
624                 /* Picture has not yet been displayed, and has a valid display
625                  * date : render it */
626                 RenderPicture( p_vout, p_pic );
627             }
628         }
629     
630         /*
631          * Check events, sleep and display picture
632          */
633         i_err = vout_SysManage( p_vout );
634         if( i_err < 0 )
635         {
636             /* A fatal error occured, and the thread must terminate immediately,
637              * without displaying anything - setting b_error to 1 cause the
638              * immediate end of the main while() loop. */
639             p_vout->b_error = 1;
640         }
641         else 
642         {
643             if( p_pic )
644             {
645                 /* A picture is ready to be displayed : sleep until its display date */
646                 mwait( p_pic->date );
647
648                 if( !i_err )
649                 {
650                     vout_SysDisplay( p_vout );
651                 }
652
653                 /* Picture has been displayed : destroy it */
654                 vlc_mutex_lock( &p_vout->lock );
655                 if( p_pic->i_refcount )
656                 {
657                     p_pic->i_status = DISPLAYED_PICTURE;
658                 }
659                 else
660                 {
661                     p_pic->i_status = DESTROYED_PICTURE;
662                 }
663                 vlc_mutex_unlock( &p_vout->lock );
664             }
665             else
666             {
667                 /* Sleep to wait for new pictures */
668                 msleep( VOUT_IDLE_SLEEP );
669 #ifdef STATS
670                 /* Update counters */
671                 p_vout->c_idle_loops++;
672 #endif
673             }
674         }
675
676 #ifdef STATS
677         /* Update counters */
678         p_vout->c_loops++;
679 #endif
680     } 
681
682     /*
683      * Error loop
684      */
685     if( p_vout->b_error )
686     {
687         ErrorThread( p_vout );        
688     }
689
690     /* End of thread */
691     EndThread( p_vout );
692     intf_DbgMsg( "thread end\n" );
693 }
694
695 /*******************************************************************************
696  * ErrorThread: RunThread() error loop
697  *******************************************************************************
698  * This function is called when an error occured during thread main's loop. The
699  * thread can still receive feed, but must be ready to terminate as soon as
700  * possible.
701  *******************************************************************************/
702 static void ErrorThread( vout_thread_t *p_vout )
703 {
704     /* Wait until a `die' order */
705     while( !p_vout->b_die )
706     {
707         /* Sleep a while */
708         msleep( VOUT_IDLE_SLEEP );                
709     }
710 }
711
712 /*******************************************************************************
713  * EndThread: thread destruction
714  *******************************************************************************
715  * This function is called when the thread ends after a sucessfull 
716  * initialization.
717  *******************************************************************************/
718 static void EndThread( vout_thread_t *p_vout )
719 {
720     int *   pi_status;                                        /* thread status */
721     int     i_picture;
722         
723     /* Store status */
724     pi_status = p_vout->pi_status;    
725     *pi_status = THREAD_END;    
726
727     /* Destroy all remaining pictures */
728     for( i_picture = 0; i_picture < VOUT_MAX_PICTURES; i_picture++ )
729     {
730         if( p_vout->p_picture[i_picture].i_status != FREE_PICTURE )
731         {
732             free( p_vout->p_picture[i_picture].p_data );
733         }
734     }
735
736     /* Destroy translation tables - remeber these tables are translated */    
737     free( p_vout->pi_trans16_red - 384 );
738     free( p_vout->pi_trans16_green - 384 );
739     free( p_vout->pi_trans16_blue - 384 );
740     
741     /* Destroy thread structures allocated by InitThread */
742     vout_SysEnd( p_vout );
743     vout_SysDestroy( p_vout );
744     free( p_vout );
745
746     /* Update status */
747     *pi_status = THREAD_OVER;    
748 }
749
750 /*******************************************************************************
751  * RenderPicture: render a picture
752  *******************************************************************************
753  * This function convert a picture from a video heap to a pixel-encoded image
754  * and copy it to the current rendering buffer. No lock is required, since the
755  * rendered picture has been determined as existant, and will only be destroyed
756  * by the vout thread later.
757  *******************************************************************************/
758 static void RenderPicture( vout_thread_t *p_vout, picture_t *p_pic )
759 {
760     switch( p_pic->i_type )
761     {
762     case YUV_420_PICTURE:                   /* YUV picture: YUV transformation */        
763     case YUV_422_PICTURE:
764     case YUV_444_PICTURE:
765         RenderYUVPicture( p_vout, p_pic );        
766         break;        
767 #ifdef DEBUG
768     default:        
769         intf_DbgMsg("unknown picture type %d\n", p_pic->i_type );
770         break;        
771 #endif
772     }
773 }
774
775 /*******************************************************************************
776  * RenderYUVPicture: render a YUV picture
777  *******************************************************************************
778  * Performs the YUV convertion. The picture sent to this function should only
779  * have YUV_420, YUV_422 or YUV_444 types.
780  *******************************************************************************/
781 static void RenderYUVPicture( vout_thread_t *p_vout, picture_t *p_pic )
782 {
783     int         i_crv;    
784     int         i_cbu;
785     int         i_cgu;
786     int         i_cgv;    
787     int         i_pic_x;                            /* x coordinate in picture */
788     int         i_pic_y;                            /* y coordinate in picture */
789     yuv_data_t *p_y;                                     /* Y data base adress */
790     yuv_data_t *p_u;                                     /* U data base adress */
791     yuv_data_t *p_v;                                     /* V data base adress */
792     yuv_data_t  i_y;                                               /* Y sample */
793     yuv_data_t  i_u;                                               /* U sample */
794     yuv_data_t  i_v;                                               /* V sample */
795     u16        *pi_pic16;               /* base adress for destination picture */
796     u32        *pi_pic32;               /* base adress for destination picture */
797     int         i_pic_eol_offset;                        /* end of line offset */    
798     
799     /* Choose transformation matrix coefficients */
800     i_crv = matrix_coefficients_table[p_pic->i_matrix_coefficients][0];
801     i_cbu = matrix_coefficients_table[p_pic->i_matrix_coefficients][1];
802     i_cgu = matrix_coefficients_table[p_pic->i_matrix_coefficients][2];
803     i_cgv = matrix_coefficients_table[p_pic->i_matrix_coefficients][3];
804
805     /* Set the base pointers */
806     p_y = p_pic->p_y;
807     p_u = p_pic->p_u;
808     p_v = p_pic->p_v;
809     
810     /* Get base adress for destination image */
811     pi_pic32 = (u32 *)pi_pic16 = 
812         (u16 *)vout_SysGetPicture( p_vout, &i_pic_eol_offset );
813
814     //?? copy used values (translation, height, width) to local variables ?
815
816     /* Do YUV transformation - the loops are repeated for optimization */
817     switch( p_vout->i_screen_depth )
818     {
819     case 15:
820     case 16:
821         switch( p_pic->i_type )
822         {
823           case YUV_420_PICTURE:             /* 15 or 16 bpp 420 transformation */
824 //#ifdef HAVE_MMX
825             // ?? MMX
826 //#else
827             YUV_TRANSFORM( 420,
828                            p_vout->pi_trans16_red, 
829                            p_vout->pi_trans16_green, 
830                            p_vout->pi_trans16_blue,
831                            pi_pic16 );            
832 //#endif
833             break;
834           case YUV_422_PICTURE:             /* 15 or 16 bpp 422 transformation */
835             YUV_TRANSFORM( 422,
836                            p_vout->pi_trans16_red, 
837                            p_vout->pi_trans16_green, 
838                            p_vout->pi_trans16_blue,
839                            pi_pic16 );            
840            break;
841           case YUV_444_PICTURE:             /* 15 or 16 bpp 444 transformation */
842             YUV_TRANSFORM( 444,
843                            p_vout->pi_trans16_red, 
844                            p_vout->pi_trans16_green, 
845                            p_vout->pi_trans16_blue,
846                            pi_pic16 );            
847             break;                
848         }
849         break;        
850     case 24: // ?? probably wrong !
851        switch( p_pic->i_type )
852         {
853           case YUV_420_PICTURE:                   /* 24 bpp 420 transformation */
854             YUV_TRANSFORM( 420,  
855                            p_vout->pi_trans32_red, 
856                            p_vout->pi_trans32_green, 
857                            p_vout->pi_trans32_blue,
858                            pi_pic32 );
859             break;
860           case YUV_422_PICTURE:                   /* 24 bpp 422 transformation */
861             YUV_TRANSFORM( 422,
862                            p_vout->pi_trans32_red, 
863                            p_vout->pi_trans32_green, 
864                            p_vout->pi_trans32_blue,
865                            pi_pic32 );
866             break;
867           case YUV_444_PICTURE:                   /* 24 bpp 444 transformation */
868             YUV_TRANSFORM( 444,
869                            p_vout->pi_trans32_red, 
870                            p_vout->pi_trans32_green, 
871                            p_vout->pi_trans32_blue,
872                            pi_pic32 );
873             break;                
874         }
875         break;        
876     case 32:
877         switch( p_pic->i_type )
878         {
879           case YUV_420_PICTURE:                   /* 32 bpp 420 transformation */
880             YUV_TRANSFORM( 420,
881                            p_vout->pi_trans32_red, 
882                            p_vout->pi_trans32_green, 
883                            p_vout->pi_trans32_blue,
884                            pi_pic32 );            
885             break;
886           case YUV_422_PICTURE:                   /* 32 bpp 422 transformation */
887             YUV_TRANSFORM( 422,
888                            p_vout->pi_trans32_red, 
889                            p_vout->pi_trans32_green, 
890                            p_vout->pi_trans32_blue,
891                            pi_pic32 );
892             break;
893           case YUV_444_PICTURE:                   /* 32 bpp 444 transformation */
894             YUV_TRANSFORM( 444,
895                            p_vout->pi_trans32_red, 
896                            p_vout->pi_trans32_green, 
897                            p_vout->pi_trans32_blue,
898                            pi_pic32 );
899            break;                
900         }
901         break;
902 #ifdef DEBUG
903     default:        
904         intf_DbgMsg("invalid screen depth %d\n", p_vout->i_screen_depth );
905         break;        
906 #endif
907     }                
908 }
909