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