]> git.sesse.net Git - vlc/blob - src/video_output/video_output.c
55a5aa2d75376a2a63acf4f3a9e01686661a8724
[vlc] / src / video_output / video_output.c
1 /*****************************************************************************
2  * video_output.c : video output thread
3  * This module describes the programming interface for video output threads.
4  * It includes functions allowing to open a new thread, send pictures to a
5  * thread, and destroy a previously oppened video output thread.
6  *****************************************************************************
7  * Copyright (C) 2000 VideoLAN
8  * $Id: video_output.c,v 1.136 2001/08/03 18:03:32 gbazin Exp $
9  *
10  * Authors: Vincent Seguin <seguin@via.ecp.fr>
11  *
12  * This program is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; either version 2 of the License, or
15  * (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
25  *****************************************************************************/
26
27 /*****************************************************************************
28  * Preamble
29  *****************************************************************************/
30 #include "defs.h"
31
32 #include <errno.h>                                                 /* ENOMEM */
33 #include <stdlib.h>                                                /* free() */
34 #include <stdio.h>                                              /* sprintf() */
35 #include <string.h>                                            /* strerror() */
36
37 #ifdef STATS
38 #   include <sys/times.h>
39 #endif
40
41 #include "config.h"
42 #include "common.h"
43 #include "threads.h"
44 #include "mtime.h"
45 #include "modules.h"
46
47 #include "video.h"
48 #include "video_output.h"
49 #include "video_text.h"
50 #include "video_spu.h"
51 #include "video_yuv.h"
52
53 #include "intf_msg.h"
54
55 #include "main.h"
56
57 /*****************************************************************************
58  * Local prototypes
59  *****************************************************************************/
60 static int      BinaryLog         ( u32 i );
61 static void     MaskToShift       ( int *pi_left, int *pi_right, u32 i_mask );
62 static int      InitThread        ( vout_thread_t *p_vout );
63 static void     RunThread         ( vout_thread_t *p_vout );
64 static void     ErrorThread       ( vout_thread_t *p_vout );
65 static void     EndThread         ( vout_thread_t *p_vout );
66 static void     DestroyThread     ( vout_thread_t *p_vout, int i_status );
67 static void     Print             ( vout_thread_t *p_vout, int i_x, int i_y,
68                                     int i_h_align, int i_v_align,
69                                     unsigned char *psz_text );
70 static void     SetBuffers        ( vout_thread_t *p_vout, void *, void * );
71 static void     SetBufferArea     ( vout_thread_t *p_vout, int i_x, int i_y,
72                                     int i_w, int i_h );
73 static void     SetBufferPicture  ( vout_thread_t *p_vout, picture_t *p_pic );
74 static void     RenderPicture     ( vout_thread_t *p_vout, picture_t *p_pic );
75 static void     RenderPictureInfo ( vout_thread_t *p_vout, picture_t *p_pic );
76 static void     RenderSubPicture  ( vout_thread_t *p_vout, picture_t *p_pic,
77                                     subpicture_t *p_subpic );
78 static int      RenderIdle        ( vout_thread_t *p_vout );
79 static void     RenderInfo        ( vout_thread_t *p_vout );
80 static int      Manage            ( vout_thread_t *p_vout );
81 static int      Align             ( vout_thread_t *p_vout, int *pi_x,
82                                     int *pi_y, int i_width, int i_height,
83                                     int i_h_align, int i_v_align );
84 static void     SetPalette        ( p_vout_thread_t p_vout, u16 *red,
85                                     u16 *green, u16 *blue, u16 *transp );
86
87 /*****************************************************************************
88  * vout_InitBank: initialize the video output bank.
89  *****************************************************************************/
90 void vout_InitBank ( void )
91 {
92     p_vout_bank->i_count = 0;
93
94     vlc_mutex_init( &p_vout_bank->lock );
95 }
96
97 /*****************************************************************************
98  * vout_EndBank: empty the video output bank.
99  *****************************************************************************
100  * This function ends all unused video outputs and empties the bank in
101  * case of success.
102  *****************************************************************************/
103 void vout_EndBank ( void )
104 {
105     /* Ask all remaining video outputs to die */
106     while( p_vout_bank->i_count )
107     {
108         vout_DestroyThread(
109                 p_vout_bank->pp_vout[ --p_vout_bank->i_count ], NULL );
110     }
111
112     vlc_mutex_destroy( &p_vout_bank->lock );
113 }
114
115 /*****************************************************************************
116  * vout_CreateThread: creates a new video output thread
117  *****************************************************************************
118  * This function creates a new video output thread, and returns a pointer
119  * to its description. On error, it returns NULL.
120  * If pi_status is NULL, then the function will block until the thread is ready.
121  * If not, it will be updated using one of the THREAD_* constants.
122  *****************************************************************************/
123 vout_thread_t * vout_CreateThread   ( int *pi_status )
124 {
125     vout_thread_t * p_vout;                             /* thread descriptor */
126     int             i_status;                               /* thread status */
127     int             i_index;               /* index for array initialization */
128
129     /* Allocate descriptor */
130     p_vout = (vout_thread_t *) malloc( sizeof(vout_thread_t) );
131     if( p_vout == NULL )
132     {
133         intf_ErrMsg( "vout error: vout thread creation returned %s",
134                      strerror(ENOMEM) );
135         return( NULL );
136     }
137
138     /* Choose the best module */
139     p_vout->p_module = module_Need( MODULE_CAPABILITY_VOUT, NULL );
140
141     if( p_vout->p_module == NULL )
142     {
143         intf_ErrMsg( "vout error: no suitable vout module" );
144         free( p_vout );
145         return( NULL );
146     }
147
148 #define f p_vout->p_module->p_functions->vout.functions.vout
149     p_vout->pf_create     = f.pf_create;
150     p_vout->pf_init       = f.pf_init;
151     p_vout->pf_end        = f.pf_end;
152     p_vout->pf_destroy    = f.pf_destroy;
153     p_vout->pf_manage     = f.pf_manage;
154     p_vout->pf_display    = f.pf_display;
155     p_vout->pf_setpalette = f.pf_setpalette;
156 #undef f
157
158     /* Initialize callbacks */
159     p_vout->pf_setbuffers       = SetBuffers;
160
161     if( p_vout->pf_setpalette == NULL )
162     {
163         p_vout->pf_setpalette   = SetPalette;
164     }
165
166     /* Initialize thread properties - thread id and locks will be initialized
167      * later */
168     p_vout->b_die               = 0;
169     p_vout->b_error             = 0;
170     p_vout->b_active            = 0;
171     p_vout->pi_status           = (pi_status != NULL) ? pi_status : &i_status;
172     *p_vout->pi_status          = THREAD_CREATE;
173
174     /* Initialize some fields used by the system-dependant method - these
175      * fields will probably be modified by the method, and are only
176      * preferences */
177     p_vout->i_changes             = 0;
178     p_vout->i_width               = main_GetIntVariable( VOUT_WIDTH_VAR,
179                                                          VOUT_WIDTH_DEFAULT );
180     p_vout->i_height              = main_GetIntVariable( VOUT_HEIGHT_VAR,
181                                                          VOUT_HEIGHT_DEFAULT );
182     p_vout->i_bytes_per_line      = p_vout->i_width * 2;
183     p_vout->i_screen_depth        = main_GetIntVariable( VOUT_DEPTH_VAR,
184                                                          VOUT_DEPTH_DEFAULT );
185     p_vout->i_bytes_per_pixel     = 2;
186     p_vout->f_gamma               = VOUT_GAMMA_DEFAULT; // FIXME: replace with
187                                                         // variable
188     p_vout->b_need_render         = 1;
189     p_vout->b_YCbr                = 0;
190
191     p_vout->b_grayscale           = main_GetIntVariable( VOUT_GRAYSCALE_VAR,
192                                                      VOUT_GRAYSCALE_DEFAULT );
193     p_vout->b_info                = 0;
194     p_vout->b_interface           = 0;
195     p_vout->b_scale               = 1;
196     p_vout->b_fullscreen          = main_GetIntVariable( VOUT_FULLSCREEN_VAR,
197                                                      VOUT_FULLSCREEN_DEFAULT );
198
199     intf_WarnMsg( 3, "vout info: asking for %dx%d, %d/%d bpp (%d Bpl)",
200                   p_vout->i_width, p_vout->i_height, p_vout->i_screen_depth,
201                   p_vout->i_bytes_per_pixel * 8, p_vout->i_bytes_per_line );
202
203     /* Initialize idle screen */
204     p_vout->last_display_date   = 0;
205     p_vout->last_idle_date      = 0;
206     p_vout->init_display_date   = mdate();
207     p_vout->render_time         = 10000;
208
209     /* Initialize statistics fields */
210     p_vout->c_fps_samples       = 0;
211
212     /* Initialize buffer index */
213     p_vout->i_buffer_index      = 0;
214
215     /* Initialize fonts */
216     p_vout->p_default_font = NULL;
217     p_vout->p_large_font = NULL;
218
219     /* Initialize pictures and subpictures - translation tables and functions
220      * will be initialized later in InitThread */
221     for( i_index = 0; i_index < VOUT_MAX_PICTURES; i_index++)
222     {
223         p_vout->p_picture[i_index].i_type   = EMPTY_PICTURE;
224         p_vout->p_picture[i_index].i_status = FREE_PICTURE;
225     }
226
227     for( i_index = 0; i_index < VOUT_MAX_SUBPICTURES; i_index++)
228     {
229         p_vout->p_subpicture[i_index].i_type   = EMPTY_SUBPICTURE;
230         p_vout->p_subpicture[i_index].i_status = FREE_SUBPICTURE;
231     }
232
233     p_vout->i_pictures = 0;
234
235     /* Create thread and set locks */
236     vlc_mutex_init( &p_vout->picture_lock );
237     vlc_mutex_init( &p_vout->subpicture_lock );
238     vlc_mutex_init( &p_vout->change_lock );
239
240     if( vlc_thread_create( &p_vout->thread_id, "video output",
241                            (void *) RunThread, (void *) p_vout) )
242     {
243         intf_ErrMsg("vout error: %s", strerror(ENOMEM));
244         module_Unneed( p_vout->p_module );
245         free( p_vout );
246         return( NULL );
247     }
248
249     /* If status is NULL, wait until the thread is created */
250     if( pi_status == NULL )
251     {
252         do
253         {
254             msleep( THREAD_SLEEP );
255         }while( (i_status != THREAD_READY) && (i_status != THREAD_ERROR)
256                 && (i_status != THREAD_FATAL) );
257         if( i_status != THREAD_READY )
258         {
259             return( NULL );
260         }
261     }
262     return( p_vout );
263 }
264
265 /*****************************************************************************
266  * vout_DestroyThread: destroys a previously created thread
267  *****************************************************************************
268  * Destroy a terminated thread.
269  * The function will request a destruction of the specified thread. If pi_error
270  * is NULL, it will return once the thread is destroyed. Else, it will be
271  * update using one of the THREAD_* constants.
272  *****************************************************************************/
273 void vout_DestroyThread( vout_thread_t *p_vout, int *pi_status )
274 {
275     int     i_status;                                       /* thread status */
276
277     /* Set status */
278     intf_DbgMsg("");
279     p_vout->pi_status = (pi_status != NULL) ? pi_status : &i_status;
280     *p_vout->pi_status = THREAD_DESTROY;
281
282     /* Request thread destruction */
283     p_vout->b_die = 1;
284
285     /* If status is NULL, wait until thread has been destroyed */
286     if( pi_status == NULL )
287     {
288         do
289         {
290             msleep( THREAD_SLEEP );
291         }while( (i_status != THREAD_OVER) && (i_status != THREAD_ERROR)
292                 && (i_status != THREAD_FATAL) );
293     }
294 }
295
296 /*****************************************************************************
297  * vout_DisplaySubPicture: display a subpicture unit
298  *****************************************************************************
299  * Remove the reservation flag of a subpicture, which will cause it to be ready
300  * for display. The picture does not need to be locked, since it is ignored by
301  * the output thread if is reserved.
302  *****************************************************************************/
303 void  vout_DisplaySubPicture( vout_thread_t *p_vout, subpicture_t *p_subpic )
304 {
305 #ifdef TRACE_VOUT
306     char        psz_start[ MSTRTIME_MAX_SIZE ];    /* buffer for date string */
307     char        psz_stop[ MSTRTIME_MAX_SIZE ];     /* buffer for date string */
308 #endif
309
310 #ifdef DEBUG
311     /* Check if status is valid */
312     if( p_subpic->i_status != RESERVED_SUBPICTURE )
313     {
314         intf_ErrMsg("error: subpicture %p has invalid status %d", p_subpic,
315                     p_subpic->i_status );
316     }
317 #endif
318
319     /* Remove reservation flag */
320     p_subpic->i_status = READY_SUBPICTURE;
321
322 #ifdef TRACE_VOUT
323     /* Send subpicture information */
324     intf_DbgMsg("subpicture %p: type=%d, begin date=%s, end date=%s",
325                 p_subpic, p_subpic->i_type,
326                 mstrtime( psz_start, p_subpic->i_start ),
327                 mstrtime( psz_stop, p_subpic->i_stop ) );
328 #endif
329 }
330
331 /*****************************************************************************
332  * vout_CreateSubPicture: allocate a subpicture in the video output heap.
333  *****************************************************************************
334  * This function create a reserved subpicture in the video output heap.
335  * A null pointer is returned if the function fails. This method provides an
336  * already allocated zone of memory in the spu data fields. It needs locking
337  * since several pictures can be created by several producers threads.
338  *****************************************************************************/
339 subpicture_t *vout_CreateSubPicture( vout_thread_t *p_vout, int i_type,
340                                      int i_size )
341 {
342     int                 i_subpic;                        /* subpicture index */
343     subpicture_t *      p_free_subpic = NULL;       /* first free subpicture */
344     subpicture_t *      p_destroyed_subpic = NULL; /* first destroyed subpic */
345
346     /* Get lock */
347     vlc_mutex_lock( &p_vout->subpicture_lock );
348
349     /*
350      * Look for an empty place
351      */
352     for( i_subpic = 0; i_subpic < VOUT_MAX_SUBPICTURES; i_subpic++ )
353     {
354         if( p_vout->p_subpicture[i_subpic].i_status == DESTROYED_SUBPICTURE )
355         {
356             /* Subpicture is marked for destruction, but is still allocated */
357             if( (p_vout->p_subpicture[i_subpic].i_type  == i_type)   &&
358                 (p_vout->p_subpicture[i_subpic].i_size  >= i_size) )
359             {
360                 /* Memory size do match or is smaller : memory will not be
361                  * reallocated, and function can end immediately - this is
362                  * the best possible case, since no memory allocation needs
363                  * to be done */
364                 p_vout->p_subpicture[i_subpic].i_status = RESERVED_SUBPICTURE;
365 #ifdef TRACE_VOUT
366                 intf_DbgMsg("subpicture %p (in destroyed subpicture slot)",
367                             &p_vout->p_subpicture[i_subpic] );
368 #endif
369                 vlc_mutex_unlock( &p_vout->subpicture_lock );
370                 return( &p_vout->p_subpicture[i_subpic] );
371             }
372             else if( p_destroyed_subpic == NULL )
373             {
374                 /* Memory size do not match, but subpicture index will be kept
375                  * in case we find no other place */
376                 p_destroyed_subpic = &p_vout->p_subpicture[i_subpic];
377             }
378         }
379         else if( (p_free_subpic == NULL) &&
380                  (p_vout->p_subpicture[i_subpic].i_status == FREE_SUBPICTURE ))
381         {
382             /* Subpicture is empty and ready for allocation */
383             p_free_subpic = &p_vout->p_subpicture[i_subpic];
384         }
385     }
386
387     /* If no free subpictures are available, use a destroyed subpicture */
388     if( (p_free_subpic == NULL) && (p_destroyed_subpic != NULL ) )
389     {
390         /* No free subpicture or matching destroyed subpictures have been
391          * found, but a destroyed subpicture is still avalaible */
392         free( p_destroyed_subpic->p_data );
393         p_free_subpic = p_destroyed_subpic;
394     }
395
396     /*
397      * Prepare subpicture
398      */
399     if( p_free_subpic != NULL )
400     {
401         /* Allocate memory */
402         switch( i_type )
403         {
404         case TEXT_SUBPICTURE:                             /* text subpicture */
405             p_free_subpic->p_data = malloc( i_size + 1 );
406             break;
407         case DVD_SUBPICTURE:                          /* DVD subpicture unit */
408             p_free_subpic->p_data = malloc( i_size );
409             break;
410 #ifdef DEBUG
411         default:
412             intf_ErrMsg("error: unknown subpicture type %d", i_type );
413             p_free_subpic->p_data   =  NULL;
414             break;
415 #endif
416         }
417
418         if( p_free_subpic->p_data != NULL )
419         {
420             /* Copy subpicture information, set some default values */
421             p_free_subpic->i_type                      = i_type;
422             p_free_subpic->i_status                    = RESERVED_SUBPICTURE;
423             p_free_subpic->i_size                      = i_size;
424             p_free_subpic->i_x                         = 0;
425             p_free_subpic->i_y                         = 0;
426             p_free_subpic->i_width                     = 0;
427             p_free_subpic->i_height                    = 0;
428             p_free_subpic->i_horizontal_align          = CENTER_RALIGN;
429             p_free_subpic->i_vertical_align            = CENTER_RALIGN;
430         }
431         else
432         {
433             /* Memory allocation failed : set subpicture as empty */
434             p_free_subpic->i_type   =  EMPTY_SUBPICTURE;
435             p_free_subpic->i_status =  FREE_SUBPICTURE;
436             p_free_subpic =            NULL;
437             intf_ErrMsg( "vout error: spu allocation returned %s",
438                          strerror( ENOMEM ) );
439         }
440
441 #ifdef TRACE_VOUT
442         intf_DbgMsg("subpicture %p (in free subpicture slot)", p_free_subpic );
443 #endif
444         vlc_mutex_unlock( &p_vout->subpicture_lock );
445         return( p_free_subpic );
446     }
447
448     /* No free or destroyed subpicture could be found */
449     intf_DbgMsg( "warning: subpicture heap is full" );
450     vlc_mutex_unlock( &p_vout->subpicture_lock );
451     return( NULL );
452 }
453
454 /*****************************************************************************
455  * vout_DestroySubPicture: remove a subpicture from the heap
456  *****************************************************************************
457  * This function frees a previously reserved subpicture.
458  * It is meant to be used when the construction of a picture aborted.
459  * This function does not need locking since reserved subpictures are ignored
460  * by the output thread.
461  *****************************************************************************/
462 void vout_DestroySubPicture( vout_thread_t *p_vout, subpicture_t *p_subpic )
463 {
464 #ifdef DEBUG
465    /* Check if status is valid */
466    if( p_subpic->i_status != RESERVED_SUBPICTURE )
467    {
468        intf_ErrMsg("error: subpicture %p has invalid status %d",
469                    p_subpic, p_subpic->i_status );
470    }
471 #endif
472
473     p_subpic->i_status = DESTROYED_SUBPICTURE;
474
475 #ifdef TRACE_VOUT
476     intf_DbgMsg("subpicture %p", p_subpic);
477 #endif
478 }
479
480 /*****************************************************************************
481  * vout_DisplayPicture: display a picture
482  *****************************************************************************
483  * Remove the reservation flag of a picture, which will cause it to be ready for
484  * display. The picture won't be displayed until vout_DatePicture has been
485  * called.
486  *****************************************************************************/
487 void  vout_DisplayPicture( vout_thread_t *p_vout, picture_t *p_pic )
488 {
489     vlc_mutex_lock( &p_vout->picture_lock );
490     switch( p_pic->i_status )
491     {
492     case RESERVED_PICTURE:
493         p_pic->i_status = RESERVED_DISP_PICTURE;
494         break;
495     case RESERVED_DATED_PICTURE:
496         p_pic->i_status = READY_PICTURE;
497         break;
498 #ifdef DEBUG
499     default:
500         intf_ErrMsg("error: picture %p has invalid status %d", p_pic, p_pic->i_status );
501         break;
502 #endif
503     }
504
505 #ifdef TRACE_VOUT
506     intf_DbgMsg("picture %p", p_pic);
507 #endif
508     vlc_mutex_unlock( &p_vout->picture_lock );
509 }
510
511 /*****************************************************************************
512  * vout_DatePicture: date a picture
513  *****************************************************************************
514  * Remove the reservation flag of a picture, which will cause it to be ready for
515  * display. The picture won't be displayed until vout_DisplayPicture has been
516  * called.
517  *****************************************************************************/
518 void  vout_DatePicture( vout_thread_t *p_vout, picture_t *p_pic, mtime_t date )
519 {
520 #ifdef TRACE_VOUT
521     char        psz_date[MSTRTIME_MAX_SIZE];                         /* date */
522 #endif
523
524     vlc_mutex_lock( &p_vout->picture_lock );
525     p_pic->date = date;
526     switch( p_pic->i_status )
527     {
528     case RESERVED_PICTURE:
529         p_pic->i_status = RESERVED_DATED_PICTURE;
530         break;
531     case RESERVED_DISP_PICTURE:
532         p_pic->i_status = READY_PICTURE;
533         break;
534 #ifdef DEBUG
535     default:
536         intf_ErrMsg("error: picture %p has invalid status %d", p_pic, p_pic->i_status );
537         break;
538 #endif
539     }
540
541 #ifdef TRACE_VOUT
542     intf_DbgMsg("picture %p, display date: %s", p_pic, mstrtime( psz_date, p_pic->date) );
543 #endif
544     vlc_mutex_unlock( &p_vout->picture_lock );
545 }
546
547 /*****************************************************************************
548  * vout_CreatePicture: allocate a picture in the video output heap.
549  *****************************************************************************
550  * This function create a reserved image in the video output heap.
551  * A null pointer is returned if the function fails. This method provides an
552  * already allocated zone of memory in the picture data fields. It needs locking
553  * since several pictures can be created by several producers threads.
554  *****************************************************************************/
555 picture_t *vout_CreatePicture( vout_thread_t *p_vout, int i_type,
556                                int i_width, int i_height )
557 {
558     int         i_picture;                                  /* picture index */
559     int         i_chroma_width = 0;                          /* chroma width */
560     picture_t * p_free_picture = NULL;                 /* first free picture */
561     picture_t * p_destroyed_picture = NULL;       /* first destroyed picture */
562
563     /* Get lock */
564     vlc_mutex_lock( &p_vout->picture_lock );
565
566     /*
567      * Look for an empty place
568      */
569     for( i_picture = 0; i_picture < VOUT_MAX_PICTURES; i_picture++ )
570     {
571         if( p_vout->p_picture[i_picture].i_status == DESTROYED_PICTURE )
572         {
573             /* Picture is marked for destruction, but is still allocated - note
574              * that if width and type are the same for two pictures, chroma_width
575              * should also be the same */
576             if( (p_vout->p_picture[i_picture].i_type           == i_type)   &&
577                 (p_vout->p_picture[i_picture].i_height         == i_height) &&
578                 (p_vout->p_picture[i_picture].i_width          == i_width) )
579             {
580                 /* Memory size do match : memory will not be reallocated, and function
581                  * can end immediately - this is the best possible case, since no
582                  * memory allocation needs to be done */
583                 p_vout->p_picture[i_picture].i_status = RESERVED_PICTURE;
584                 p_vout->i_pictures++;
585 #ifdef TRACE_VOUT
586                 intf_DbgMsg("picture %p (in destroyed picture slot)",
587                             &p_vout->p_picture[i_picture] );
588 #endif
589                 vlc_mutex_unlock( &p_vout->picture_lock );
590                 return( &p_vout->p_picture[i_picture] );
591             }
592             else if( p_destroyed_picture == NULL )
593             {
594                 /* Memory size do not match, but picture index will be kept in
595                  * case no other place are left */
596                 p_destroyed_picture = &p_vout->p_picture[i_picture];
597             }
598         }
599         else if( (p_free_picture == NULL) &&
600                  (p_vout->p_picture[i_picture].i_status == FREE_PICTURE ))
601         {
602             /* Picture is empty and ready for allocation */
603             p_free_picture = &p_vout->p_picture[i_picture];
604         }
605     }
606
607     /* If no free picture is available, use a destroyed picture */
608     if( (p_free_picture == NULL) && (p_destroyed_picture != NULL ) )
609     {
610         /* No free picture or matching destroyed picture has been found, but
611          * a destroyed picture is still avalaible */
612         free( p_destroyed_picture->p_data );
613         p_free_picture = p_destroyed_picture;
614     }
615
616     /*
617      * Prepare picture
618      */
619     if( p_free_picture != NULL )
620     {
621         /* Allocate memory */
622         switch( i_type )
623         {
624         case YUV_420_PICTURE:        /* YUV 420: 1,1/4,1/4 samples per pixel */
625             i_chroma_width = i_width / 2;
626             p_free_picture->p_data = malloc( i_height * i_chroma_width * 3 * sizeof( yuv_data_t ) );
627             p_free_picture->p_y = (yuv_data_t *)p_free_picture->p_data;
628             p_free_picture->p_u = (yuv_data_t *)p_free_picture->p_data +i_height*i_chroma_width*4/2;
629             p_free_picture->p_v = (yuv_data_t *)p_free_picture->p_data +i_height*i_chroma_width*5/2;
630             break;
631         case YUV_422_PICTURE:        /* YUV 422: 1,1/2,1/2 samples per pixel */
632             i_chroma_width = i_width / 2;
633             p_free_picture->p_data = malloc( i_height * i_chroma_width * 4 * sizeof( yuv_data_t ) );
634             p_free_picture->p_y = (yuv_data_t *)p_free_picture->p_data;
635             p_free_picture->p_u = (yuv_data_t *)p_free_picture->p_data +i_height*i_chroma_width*2;
636             p_free_picture->p_v = (yuv_data_t *)p_free_picture->p_data +i_height*i_chroma_width*3;
637             break;
638         case YUV_444_PICTURE:            /* YUV 444: 1,1,1 samples per pixel */
639             i_chroma_width = i_width;
640             p_free_picture->p_data = malloc( i_height * i_chroma_width * 3 * sizeof( yuv_data_t ) );
641             p_free_picture->p_y = (yuv_data_t *)p_free_picture->p_data;
642             p_free_picture->p_u = (yuv_data_t *)p_free_picture->p_data +i_height*i_chroma_width;
643             p_free_picture->p_v = (yuv_data_t *)p_free_picture->p_data +i_height*i_chroma_width*2;
644             break;
645 #ifdef DEBUG
646         default:
647             intf_ErrMsg("error: unknown picture type %d", i_type );
648             p_free_picture->p_data   =  NULL;
649             break;
650 #endif
651         }
652
653         if( p_free_picture->p_data != NULL )
654         {
655             /* Copy picture information, set some default values */
656             p_free_picture->i_type                      = i_type;
657             p_free_picture->i_status                    = RESERVED_PICTURE;
658             p_free_picture->i_matrix_coefficients       = 1;
659             p_free_picture->i_width                     = i_width;
660             p_free_picture->i_height                    = i_height;
661             p_free_picture->i_chroma_width              = i_chroma_width;
662             p_free_picture->i_size                      = i_width * i_height;
663             p_free_picture->i_chroma_size               = i_chroma_width
664                                                             * i_height;
665             p_free_picture->i_display_horizontal_offset = 0;
666             p_free_picture->i_display_vertical_offset   = 0;
667             p_free_picture->i_display_width             = i_width;
668             p_free_picture->i_display_height            = i_height;
669             p_free_picture->i_aspect_ratio              = AR_SQUARE_PICTURE;
670             p_free_picture->i_refcount                  = 0;
671             p_vout->i_pictures++;
672         }
673         else
674         {
675             /* Memory allocation failed : set picture as empty */
676             p_free_picture->i_type   =  EMPTY_PICTURE;
677             p_free_picture->i_status =  FREE_PICTURE;
678             p_free_picture =            NULL;
679             intf_ErrMsg( "vout error: picture allocation returned %s",
680                          strerror( ENOMEM ) );
681         }
682
683 #ifdef TRACE_VOUT
684         intf_DbgMsg("picture %p (in free picture slot)", p_free_picture );
685 #endif
686         vlc_mutex_unlock( &p_vout->picture_lock );
687
688         return( p_free_picture );
689     }
690
691     /* No free or destroyed picture could be found */
692     intf_DbgMsg( "warning: picture heap is full" );
693     vlc_mutex_unlock( &p_vout->picture_lock );
694     return( NULL );
695 }
696
697 /*****************************************************************************
698  * vout_DestroyPicture: remove a permanent or reserved picture from the heap
699  *****************************************************************************
700  * This function frees a previously reserved picture or a permanent
701  * picture. It is meant to be used when the construction of a picture aborted.
702  * Note that the picture will be destroyed even if it is linked !
703  *****************************************************************************/
704 void vout_DestroyPicture( vout_thread_t *p_vout, picture_t *p_pic )
705 {
706     vlc_mutex_lock( &p_vout->picture_lock );
707
708 #ifdef DEBUG
709     /* Check if picture status is valid */
710     if( (p_pic->i_status != RESERVED_PICTURE) &&
711         (p_pic->i_status != RESERVED_DATED_PICTURE) &&
712         (p_pic->i_status != RESERVED_DISP_PICTURE) )
713     {
714         intf_ErrMsg("error: picture %p has invalid status %d", p_pic, p_pic->i_status );
715     }
716 #endif
717
718     p_pic->i_status = DESTROYED_PICTURE;
719     p_vout->i_pictures--;
720
721 #ifdef TRACE_VOUT
722     intf_DbgMsg("picture %p", p_pic);
723 #endif
724
725     vlc_mutex_unlock( &p_vout->picture_lock );
726 }
727
728 /*****************************************************************************
729  * vout_LinkPicture: increment reference counter of a picture
730  *****************************************************************************
731  * This function increment the reference counter of a picture in the video
732  * heap. It needs a lock since several producer threads can access the picture.
733  *****************************************************************************/
734 void vout_LinkPicture( vout_thread_t *p_vout, picture_t *p_pic )
735 {
736     vlc_mutex_lock( &p_vout->picture_lock );
737     p_pic->i_refcount++;
738
739 #ifdef TRACE_VOUT
740     intf_DbgMsg("picture %p refcount=%d", p_pic, p_pic->i_refcount );
741 #endif
742
743     vlc_mutex_unlock( &p_vout->picture_lock );
744 }
745
746 /*****************************************************************************
747  * vout_UnlinkPicture: decrement reference counter of a picture
748  *****************************************************************************
749  * This function decrement the reference counter of a picture in the video heap.
750  *****************************************************************************/
751 void vout_UnlinkPicture( vout_thread_t *p_vout, picture_t *p_pic )
752 {
753     vlc_mutex_lock( &p_vout->picture_lock );
754     p_pic->i_refcount--;
755
756 #ifdef TRACE_VOUT
757     if( p_pic->i_refcount < 0 )
758     {
759         intf_DbgMsg("error: refcount < 0");
760         p_pic->i_refcount = 0;
761     }
762 #endif
763
764     if( (p_pic->i_refcount == 0) && (p_pic->i_status == DISPLAYED_PICTURE) )
765     {
766         p_pic->i_status = DESTROYED_PICTURE;
767         p_vout->i_pictures--;
768     }
769
770 #ifdef TRACE_VOUT
771     intf_DbgMsg("picture %p refcount=%d", p_pic, p_pic->i_refcount );
772 #endif
773
774     vlc_mutex_unlock( &p_vout->picture_lock );
775 }
776
777 /*****************************************************************************
778  * vout_Pixel2RGB: return red, green and blue from pixel value
779  *****************************************************************************
780  * Return color values, in 0-255 range, of the decomposition of a pixel. This
781  * is a slow routine and should only be used for initialization phase.
782  *****************************************************************************/
783 void vout_Pixel2RGB( vout_thread_t *p_vout, u32 i_pixel, int *pi_red, int *pi_green, int *pi_blue )
784 {
785     *pi_red =   i_pixel & p_vout->i_red_mask;
786     *pi_green = i_pixel & p_vout->i_green_mask;
787     *pi_blue =  i_pixel & p_vout->i_blue_mask;
788 }
789
790 /* following functions are local */
791
792 /*****************************************************************************
793  * BinaryLog: computes the base 2 log of a binary value
794  *****************************************************************************
795  * This functions is used by MaskToShift, to get a bit index from a binary
796  * value.
797  *****************************************************************************/
798 static int BinaryLog(u32 i)
799 {
800     int i_log = 0;
801
802     if(i & 0xffff0000)
803     {
804         i_log += 16;
805     }
806     if(i & 0xff00ff00)
807     {
808         i_log += 8;
809     }
810     if(i & 0xf0f0f0f0)
811     {
812         i_log += 4;
813     }
814     if(i & 0xcccccccc)
815     {
816         i_log += 2;
817     }
818     if(i & 0xaaaaaaaa)
819     {
820         i_log += 1;
821     }
822
823     if (i != ((u32)1 << i_log))
824     {
825         intf_DbgMsg("internal error: binary log overflow");
826     }
827
828     return( i_log );
829 }
830
831 /*****************************************************************************
832  * MaskToShift: transform a color mask into right and left shifts
833  *****************************************************************************
834  * This function is used for obtaining color shifts from masks.
835  *****************************************************************************/
836 static void MaskToShift( int *pi_left, int *pi_right, u32 i_mask )
837 {
838     u32 i_low, i_high;                 /* lower hand higher bits of the mask */
839
840     /* Get bits */
841     i_low =  i_mask & (- i_mask);                   /* lower bit of the mask */
842     i_high = i_mask + i_low;                       /* higher bit of the mask */
843
844     /* Transform bits into an index */
845     i_low =  BinaryLog (i_low);
846     i_high = BinaryLog (i_high);
847
848     /* Update pointers and return */
849     *pi_left =   i_low;
850     *pi_right = (8 - i_high + i_low);
851 }
852
853 /*****************************************************************************
854  * InitThread: initialize video output thread
855  *****************************************************************************
856  * This function is called from RunThread and performs the second step of the
857  * initialization. It returns 0 on success. Note that the thread's flag are not
858  * modified inside this function.
859  *****************************************************************************/
860 static int InitThread( vout_thread_t *p_vout )
861 {
862     /* Update status */
863     *p_vout->pi_status = THREAD_START;
864
865     vlc_mutex_lock( &p_vout->change_lock );
866
867 #ifdef STATS
868     p_vout->c_loops = 0;
869 #endif
870
871     /* Create and initialize system-dependant method - this function issues its
872      * own error messages */
873     if( p_vout->pf_create( p_vout ) )
874     {
875         /* If pf_create has failed then we have to make sure
876          * pf_destroy won't be called, because the plugin should have
877          * cleaned up all its mess */
878         p_vout->pf_destroy = NULL;
879         return( 1 );
880     }
881
882     intf_WarnMsg( 1, "vout: video display initialized (%dx%d, %d/%d bpp)",
883               p_vout->i_width, p_vout->i_height, p_vout->i_screen_depth,
884               p_vout->i_bytes_per_pixel * 8 );
885
886     intf_WarnMsg( 3, "vout info: got %dx%d, %d/%d bpp (%d Bpl), "
887                   "masks: 0x%x/0x%x/0x%x",
888                   p_vout->i_width, p_vout->i_height, p_vout->i_screen_depth,
889                   p_vout->i_bytes_per_pixel * 8, p_vout->i_bytes_per_line,
890                   p_vout->i_red_mask, p_vout->i_green_mask,
891                   p_vout->i_blue_mask );
892
893     /* Calculate shifts from system-updated masks */
894     MaskToShift( &p_vout->i_red_lshift, &p_vout->i_red_rshift,
895                  p_vout->i_red_mask );
896     MaskToShift( &p_vout->i_green_lshift, &p_vout->i_green_rshift,
897                  p_vout->i_green_mask );
898     MaskToShift( &p_vout->i_blue_lshift, &p_vout->i_blue_rshift,
899                  p_vout->i_blue_mask );
900
901     /* Set some useful colors */
902     p_vout->i_white_pixel = RGB2PIXEL( p_vout, 255, 255, 255 );
903     p_vout->i_black_pixel = RGB2PIXEL( p_vout, 0, 0, 0 );
904     p_vout->i_gray_pixel  = RGB2PIXEL( p_vout, 128, 128, 128 );
905     p_vout->i_blue_pixel  = RGB2PIXEL( p_vout, 0, 0, 50 );
906
907     /* Load fonts - fonts must be initialized after the system method since
908      * they may be dependant on screen depth and other thread properties */
909     p_vout->p_default_font = vout_LoadFont( VOUT_DEFAULT_FONT );
910     if( p_vout->p_default_font == NULL )
911     {
912         intf_ErrMsg( "vout error: could not load default font" );
913     }
914
915     p_vout->p_large_font = vout_LoadFont( VOUT_LARGE_FONT );
916     if( p_vout->p_large_font == NULL )
917     {
918         intf_ErrMsg( "vout error: could not load large font" );
919     }
920
921     /* Initialize output method. This function issues its own error messages */
922     if( p_vout->pf_init( p_vout ) )
923     {
924         /* If pf_init has failed then we have to make sure
925          * pf_destroy won't be called, because the plugin should have
926          * cleaned up all its mess */
927         p_vout->pf_destroy = NULL;
928         return( 1 );
929     }
930
931     /* Initialize convertion tables and functions */
932     if( vout_InitYUV( p_vout ) )
933     {
934         intf_ErrMsg("vout error: can't allocate YUV translation tables");
935         p_vout->pf_destroy( p_vout );
936         /* Make sure pf_destroy won't be called again */
937         p_vout->pf_destroy = NULL;
938         return( 1 );
939     }
940
941     /* Mark thread as running and return */
942     p_vout->b_active =          1;
943     *p_vout->pi_status =        THREAD_READY;
944
945
946     intf_DbgMsg("thread ready");
947     return( 0 );
948 }
949
950 /*****************************************************************************
951  * RunThread: video output thread
952  *****************************************************************************
953  * Video output thread. This function does only returns when the thread is
954  * terminated. It handles the pictures arriving in the video heap and the
955  * display device events.
956  *****************************************************************************/
957 static void RunThread( vout_thread_t *p_vout)
958 {
959     int             i_index;                                /* index in heap */
960     mtime_t         current_date;                            /* current date */
961     mtime_t         display_date;                            /* display date */
962     boolean_t       b_display;                               /* display flag */
963
964     picture_t *     p_pic;                                /* picture pointer */
965
966     subpicture_t *  p_subpic;                          /* subpicture pointer */
967     subpicture_t *  p_ephemer;        /* youngest ephemer subpicture pointer */
968     mtime_t         ephemer_date;                /* earliest subpicture date */
969
970     /*
971      * Initialize thread
972      */
973     if( InitThread( p_vout ) )
974     {
975         /* Something bad happened */
976         DestroyThread( p_vout, THREAD_ERROR );
977         return;
978     }
979     /*
980      * Main loop - it is not executed if an error occured during
981      * initialization
982      */
983     while( (!p_vout->b_die) && (!p_vout->b_error) )
984     {
985         /* Initialize loop variables */
986         p_vout->p_rendered_pic = NULL;
987         p_pic =         NULL;
988         p_subpic =      NULL;
989         p_ephemer =     NULL;
990         ephemer_date =  0;
991         display_date =  0;
992         current_date =  mdate();
993 #ifdef STATS
994         p_vout->c_loops++;
995         if( !(p_vout->c_loops % VOUT_STATS_NB_LOOPS) )
996         {
997             intf_Msg("vout stats: picture heap: %d/%d",
998                      p_vout->i_pictures, VOUT_MAX_PICTURES);
999         }
1000 #endif
1001
1002         /*
1003          * Find the picture to display - this operation does not need lock,
1004          * since only READY_PICTUREs are handled
1005          */
1006         for( i_index = 0; i_index < VOUT_MAX_PICTURES; i_index++ )
1007         {
1008             if( (p_vout->p_picture[i_index].i_status == READY_PICTURE) &&
1009             ( (p_pic == NULL) ||
1010               (p_vout->p_picture[i_index].date < display_date) ) )
1011             {
1012                 p_pic = &p_vout->p_picture[i_index];
1013                 display_date = p_pic->date;
1014             }
1015         }
1016
1017         if( p_pic )
1018         {
1019             /* Computes FPS rate */
1020             p_vout->p_fps_sample[ p_vout->c_fps_samples++ % VOUT_FPS_SAMPLES ] = display_date;
1021
1022             if( display_date < current_date - p_vout->render_time )
1023             {
1024                 /* Picture is late: it will be destroyed and the thread
1025                  * will sleep and go to next picture */
1026
1027                 vlc_mutex_lock( &p_vout->picture_lock );
1028                 if( p_pic->i_refcount )
1029                 {
1030                     p_pic->i_status = DISPLAYED_PICTURE;
1031                 }
1032                 else
1033                 {
1034                     p_pic->i_status = DESTROYED_PICTURE;
1035                     p_vout->i_pictures--;
1036                 }
1037                 intf_WarnMsg( 1,
1038                         "vout warning: late picture skipped (%p)", p_pic );
1039                 vlc_mutex_unlock( &p_vout->picture_lock );
1040
1041                 continue;
1042             }
1043             else if( display_date > current_date + VOUT_DISPLAY_DELAY )
1044             {
1045                 /* A picture is ready to be rendered, but its rendering date
1046                  * is far from the current one so the thread will perform an
1047                  * empty loop as if no picture were found. The picture state
1048                  * is unchanged */
1049                 p_pic =         NULL;
1050                 display_date =  0;
1051             }
1052         }
1053
1054         /*
1055          * Find the subpictures to display - this operation does not need
1056          * lock, since only READY_SUBPICTURE are handled. If no picture
1057          * has been selected, display_date will depend on the subpicture.
1058          *
1059          * We also check for ephemer DVD subpictures (subpictures that have
1060          * to be removed if a newer one is available), which makes it a lot
1061          * more difficult to guess if a subpicture has to be rendered or not.
1062          *
1063          * We get an easily parsable chained list of subpictures which
1064          * ends with NULL since p_subpic was initialized to NULL.
1065          */
1066         for( i_index = 0; i_index < VOUT_MAX_SUBPICTURES; i_index++ )
1067         {
1068             if( p_vout->p_subpicture[i_index].i_status == READY_SUBPICTURE )
1069             {
1070                 /* If it is a DVD subpicture, check its date */
1071                 if( p_vout->p_subpicture[i_index].i_type == DVD_SUBPICTURE )
1072                 {
1073                     if( display_date > p_vout->p_subpicture[i_index].i_stop )
1074                     {
1075                         /* Too late, destroy the subpic */
1076                         vout_DestroySubPicture( p_vout,
1077                                         &p_vout->p_subpicture[i_index] );
1078                         continue;
1079                     }
1080
1081                     if( display_date < p_vout->p_subpicture[i_index].i_start )
1082                     {
1083                         /* Too early, come back next monday */
1084                         continue;
1085                     }
1086
1087                     /* If this is an ephemer subpic, see if it's the
1088                      * youngest we have */
1089                     if( p_vout->p_subpicture[i_index].b_ephemer )
1090                     {
1091                         if( p_ephemer == NULL )
1092                         {
1093                             p_ephemer = &p_vout->p_subpicture[i_index];
1094                             continue;
1095                         }
1096
1097                         if( p_vout->p_subpicture[i_index].i_start
1098                                                          < p_ephemer->i_start )
1099                         {
1100                             /* Link the previous ephemer subpicture and
1101                              * replace it with the current one */
1102                             p_ephemer->p_next = p_subpic;
1103                             p_subpic = p_ephemer;
1104                             p_ephemer = &p_vout->p_subpicture[i_index];
1105
1106                             /* If it's the 2nd youngest subpicture,
1107                              * register its date */
1108                             if( !ephemer_date
1109                                   || ephemer_date > p_subpic->i_start )
1110                             {
1111                                 ephemer_date = p_subpic->i_start;
1112                             }
1113
1114                             continue;
1115                         }
1116                     }
1117
1118                     p_vout->p_subpicture[i_index].p_next = p_subpic;
1119                     p_subpic = &p_vout->p_subpicture[i_index];
1120
1121                     /* If it's the 2nd youngest subpicture, register its date */
1122                     if( !ephemer_date || ephemer_date > p_subpic->i_start )
1123                     {
1124                         ephemer_date = p_subpic->i_start;
1125                     }
1126                 }
1127                 /* If it's not a DVD subpicture, just register it */
1128                 else
1129                 {
1130                     p_vout->p_subpicture[i_index].p_next = p_subpic;
1131                     p_subpic = &p_vout->p_subpicture[i_index];
1132                 }
1133             }
1134         }
1135
1136         /* If we found an ephemer subpicture, check if it has to be
1137          * displayed */
1138         if( p_ephemer != NULL )
1139         {
1140             if( p_ephemer->i_start < ephemer_date )
1141             {
1142                 /* Ephemer subpicture has lived too long */
1143                 vout_DestroySubPicture( p_vout, p_ephemer );
1144             }
1145             else
1146             {
1147                 /* Ephemer subpicture can still live a bit */
1148                 p_ephemer->p_next = p_subpic;
1149                 p_subpic = p_ephemer;
1150             }
1151         }
1152
1153         /*
1154          * Perform rendering, sleep and display rendered picture
1155          */
1156         if( p_pic )                        /* picture and perhaps subpicture */
1157         {
1158             b_display = p_vout->b_active;
1159             p_vout->last_display_date = display_date;
1160             p_vout->p_rendered_pic = p_pic;
1161
1162             /* FIXME: if b_need_render == 0 we need to do something with
1163              * the subpictures one day. */
1164
1165             if( p_vout->b_need_render && b_display )
1166             {
1167                 /* Set picture dimensions and clear buffer */
1168                 SetBufferPicture( p_vout, p_pic );
1169
1170                 /* Render picture and information */
1171                 RenderPicture( p_vout, p_pic );
1172                 if( p_vout->b_info )
1173                 {
1174                     RenderPictureInfo( p_vout, p_pic );
1175                     RenderInfo( p_vout );
1176                 }
1177             }
1178             if( b_display ) /* XXX: quick HACK */
1179             {
1180                 if( p_subpic )
1181                 {
1182                     RenderSubPicture( p_vout, p_pic, p_subpic );
1183                 }
1184             }
1185         }
1186         else if( p_vout->b_active && p_vout->b_need_render
1187                   && p_vout->init_display_date == 0)
1188         {
1189             /* Idle or interface screen alone */
1190
1191             if( p_vout->b_interface && 0 /* && XXX?? intf_change */ )
1192             {
1193                 /* Interface has changed, so a new rendering is required - force
1194                  * it by setting last idle date to 0 */
1195                 p_vout->last_idle_date = 0;
1196             }
1197
1198             /* Render idle screen and update idle date, then render interface if
1199              * required */
1200             b_display = RenderIdle( p_vout );
1201             if( b_display )
1202             {
1203                 p_vout->last_idle_date = current_date;
1204             }
1205
1206         }
1207         else
1208         {
1209             b_display = 0;
1210         }
1211
1212
1213         /*
1214          * Check for the current time and
1215          * display splash screen if everything is on time
1216          */
1217         if( p_vout->init_display_date > 0 && p_vout->b_need_render )
1218         {
1219             p_vout->init_display_date = 0;
1220         }
1221
1222
1223         /*
1224          * Sleep, wake up and display rendered picture
1225          */
1226
1227         if( display_date != 0 )
1228         {
1229             /* Store render time using Bresenham algorithm */
1230             p_vout->render_time += mdate() - current_date;
1231             p_vout->render_time >>= 1;
1232         }
1233
1234         /* Give back change lock */
1235         vlc_mutex_unlock( &p_vout->change_lock );
1236
1237         /* Sleep a while or until a given date */
1238         if( display_date != 0 )
1239         {
1240             mwait( display_date - VOUT_MWAIT_TOLERANCE );
1241         }
1242         else
1243         {
1244             msleep( VOUT_IDLE_SLEEP );
1245         }
1246
1247         /* On awakening, take back lock and send immediately picture to display,
1248          * then swap buffers */
1249         vlc_mutex_lock( &p_vout->change_lock );
1250 #ifdef TRACE_VOUT
1251         intf_DbgMsg( "picture %p, subpicture %p in buffer %d, display=%d", p_pic, p_subpic,
1252                      p_vout->i_buffer_index, b_display /* && !(p_vout->i_changes & VOUT_NODISPLAY_CHANGE) */ );
1253 #endif
1254         if( b_display /* && !(p_vout->i_changes & VOUT_NODISPLAY_CHANGE) */ )
1255         {
1256             p_vout->pf_display( p_vout );
1257 #ifndef SYS_BEOS
1258             p_vout->i_buffer_index = ++p_vout->i_buffer_index & 1;
1259 #endif
1260         }
1261
1262         if( p_pic )
1263         {
1264             /* Remove picture from heap */
1265             vlc_mutex_lock( &p_vout->picture_lock );
1266             if( p_pic->i_refcount )
1267             {
1268                 p_pic->i_status = DISPLAYED_PICTURE;
1269             }
1270             else
1271             {
1272                 p_pic->i_status = DESTROYED_PICTURE;
1273                 p_vout->i_pictures--;
1274             }
1275             vlc_mutex_unlock( &p_vout->picture_lock );
1276         }
1277
1278
1279         /*
1280          * Check events and manage thread
1281          */
1282         if( p_vout->pf_manage( p_vout ) | Manage( p_vout ) )
1283         {
1284             /* A fatal error occured, and the thread must terminate immediately
1285              * without displaying anything - setting b_error to 1 cause the
1286              * immediate end of the main while() loop. */
1287             p_vout->b_error = 1;
1288         }
1289     }
1290
1291     /*
1292      * Error loop - wait until the thread destruction is requested
1293      */
1294     if( p_vout->b_error )
1295     {
1296         ErrorThread( p_vout );
1297     }
1298
1299     /* End of thread */
1300     EndThread( p_vout );
1301     DestroyThread( p_vout, THREAD_OVER );
1302     intf_DbgMsg( "thread end" );
1303 }
1304
1305 /*****************************************************************************
1306  * ErrorThread: RunThread() error loop
1307  *****************************************************************************
1308  * This function is called when an error occured during thread main's loop. The
1309  * thread can still receive feed, but must be ready to terminate as soon as
1310  * possible.
1311  *****************************************************************************/
1312 static void ErrorThread( vout_thread_t *p_vout )
1313 {
1314     /* Wait until a `die' order */
1315     while( !p_vout->b_die )
1316     {
1317         /* Sleep a while */
1318         msleep( VOUT_IDLE_SLEEP );
1319     }
1320 }
1321
1322 /*****************************************************************************
1323  * EndThread: thread destruction
1324  *****************************************************************************
1325  * This function is called when the thread ends after a sucessful
1326  * initialization. It frees all ressources allocated by InitThread.
1327  *****************************************************************************/
1328 static void EndThread( vout_thread_t *p_vout )
1329 {
1330     int     i_index;                                        /* index in heap */
1331
1332     /* Store status */
1333     *p_vout->pi_status = THREAD_END;
1334
1335 #ifdef STATS
1336     {
1337         struct tms cpu_usage;
1338         times( &cpu_usage );
1339
1340         intf_Msg( "vout stats: cpu usage (user: %d, system: %d)",
1341                   cpu_usage.tms_utime, cpu_usage.tms_stime );
1342     }
1343 #endif
1344
1345     /* Destroy all remaining pictures and subpictures */
1346     for( i_index = 0; i_index < VOUT_MAX_PICTURES; i_index++ )
1347     {
1348         if( p_vout->p_picture[i_index].i_status != FREE_PICTURE )
1349         {
1350             free( p_vout->p_picture[i_index].p_data );
1351         }
1352     }
1353
1354     for( i_index = 0; i_index < VOUT_MAX_SUBPICTURES; i_index++ )
1355     {
1356         if( p_vout->p_subpicture[i_index].i_status != FREE_SUBPICTURE )
1357         {
1358             free( p_vout->p_subpicture[i_index].p_data );
1359         }
1360     }
1361
1362     /* Destroy translation tables */
1363     vout_EndYUV( p_vout );
1364     p_vout->pf_end( p_vout );
1365
1366     /* Release the change lock */
1367     vlc_mutex_unlock( &p_vout->change_lock );
1368 }
1369
1370 /*****************************************************************************
1371  * DestroyThread: thread destruction
1372  *****************************************************************************
1373  * This function is called when the thread ends. It frees all ressources
1374  * allocated by CreateThread. Status is available at this stage.
1375  *****************************************************************************/
1376 static void DestroyThread( vout_thread_t *p_vout, int i_status )
1377 {
1378     int *pi_status;                                         /* status adress */
1379
1380     /* Store status adress */
1381     pi_status = p_vout->pi_status;
1382
1383     /* Destroy thread structures allocated by Create and InitThread */
1384     vout_UnloadFont( p_vout->p_default_font );
1385     vout_UnloadFont( p_vout->p_large_font );
1386     if( p_vout->pf_destroy != NULL ) p_vout->pf_destroy( p_vout );
1387
1388     /* Destroy the locks */
1389     vlc_mutex_destroy( &p_vout->picture_lock );
1390     vlc_mutex_destroy( &p_vout->subpicture_lock );
1391     vlc_mutex_destroy( &p_vout->change_lock );
1392
1393     /* Release the module */
1394     module_Unneed( p_vout->p_module );
1395
1396     /* Free structure */
1397     free( p_vout );
1398     *pi_status = i_status;
1399 }
1400
1401 /*****************************************************************************
1402  * Print: print simple text on a picture
1403  *****************************************************************************
1404  * This function will print a simple text on the picture. It is designed to
1405  * print debugging or general information.
1406  *****************************************************************************/
1407 void Print( vout_thread_t *p_vout, int i_x, int i_y, int i_h_align, int i_v_align, unsigned char *psz_text )
1408 {
1409     int                 i_text_height;                  /* total text height */
1410     int                 i_text_width;                    /* total text width */
1411
1412     /* Update upper left coordinates according to alignment */
1413     vout_TextSize( p_vout->p_default_font, 0, psz_text, &i_text_width, &i_text_height );
1414     if( !Align( p_vout, &i_x, &i_y, i_text_width, i_text_height, i_h_align, i_v_align ) )
1415     {
1416         /* Set area and print text */
1417         SetBufferArea( p_vout, i_x, i_y, i_text_width, i_text_height );
1418         vout_Print( p_vout->p_default_font, p_vout->p_buffer[ p_vout->i_buffer_index ].p_data +
1419                     i_y * p_vout->i_bytes_per_line + i_x * p_vout->i_bytes_per_pixel,
1420                     p_vout->i_bytes_per_pixel, p_vout->i_bytes_per_line,
1421                     p_vout->i_white_pixel, 0, 0,
1422                     0, psz_text, 100 );
1423     }
1424 }
1425
1426 /*****************************************************************************
1427  * SetBuffers: set buffers adresses
1428  *****************************************************************************
1429  * This function is called by system drivers to set buffers video memory
1430  * adresses.
1431  *****************************************************************************/
1432 static void SetBuffers( vout_thread_t *p_vout, void *p_buf1, void *p_buf2 )
1433 {
1434     /* No picture previously */
1435     p_vout->p_buffer[0].i_pic_x =         0;
1436     p_vout->p_buffer[0].i_pic_y =         0;
1437     p_vout->p_buffer[0].i_pic_width =     0;
1438     p_vout->p_buffer[0].i_pic_height =    0;
1439     p_vout->p_buffer[1].i_pic_x =         0;
1440     p_vout->p_buffer[1].i_pic_y =         0;
1441     p_vout->p_buffer[1].i_pic_width =     0;
1442     p_vout->p_buffer[1].i_pic_height =    0;
1443
1444     /* The first area covers all the screen */
1445     p_vout->p_buffer[0].i_areas =                 1;
1446     p_vout->p_buffer[0].pi_area_begin[0] =        0;
1447     p_vout->p_buffer[0].pi_area_end[0] =          p_vout->i_height - 1;
1448     p_vout->p_buffer[1].i_areas =                 1;
1449     p_vout->p_buffer[1].pi_area_begin[0] =        0;
1450     p_vout->p_buffer[1].pi_area_end[0] =          p_vout->i_height - 1;
1451
1452     /* Set adresses */
1453     p_vout->p_buffer[0].p_data = p_buf1;
1454     p_vout->p_buffer[1].p_data = p_buf2;
1455 }
1456
1457 /*****************************************************************************
1458  * SetBufferArea: activate an area in current buffer
1459  *****************************************************************************
1460  * This function is called when something is rendered on the current buffer.
1461  * It set the area as active and prepare it to be cleared on next rendering.
1462  * Pay attention to the fact that in this functions, i_h is in fact the end y
1463  * coordinate of the new area.
1464  *****************************************************************************/
1465 static void SetBufferArea( vout_thread_t *p_vout, int i_x, int i_y, int i_w, int i_h )
1466 {
1467     vout_buffer_t *     p_buffer;                          /* current buffer */
1468     int                 i_area_begin, i_area_end; /* area vertical extension */
1469     int                 i_area, i_area_copy;                   /* area index */
1470     int                 i_area_shift;            /* shift distance for areas */
1471
1472     /* Choose buffer and modify h to end of area position */
1473     p_buffer =  &p_vout->p_buffer[ p_vout->i_buffer_index ];
1474     i_h +=      i_y - 1;
1475
1476     /*
1477      * Remove part of the area which is inside the picture - this is done
1478      * by calling again SetBufferArea with the correct areas dimensions.
1479      */
1480     if( (i_x >= p_buffer->i_pic_x) && (i_x + i_w <= p_buffer->i_pic_x + p_buffer->i_pic_width) )
1481     {
1482         i_area_begin =  p_buffer->i_pic_y;
1483         i_area_end =    i_area_begin + p_buffer->i_pic_height - 1;
1484
1485         if( ((i_y >= i_area_begin) && (i_y <= i_area_end)) ||
1486             ((i_h >= i_area_begin) && (i_h <= i_area_end)) ||
1487             ((i_y <  i_area_begin) && (i_h > i_area_end)) )
1488         {
1489             /* Keep the stripe above the picture, if any */
1490             if( i_y < i_area_begin )
1491             {
1492                 SetBufferArea( p_vout, i_x, i_y, i_w, i_area_begin - i_y );
1493             }
1494             /* Keep the stripe below the picture, if any */
1495             if( i_h > i_area_end )
1496             {
1497                 SetBufferArea( p_vout, i_x, i_area_end, i_w, i_h - i_area_end );
1498             }
1499             return;
1500         }
1501     }
1502
1503     /* Skip some extensions until interesting areas */
1504     for( i_area = 0;
1505          (i_area < p_buffer->i_areas) &&
1506              (p_buffer->pi_area_end[i_area] + 1 <= i_y);
1507          i_area++ )
1508     {
1509         ;
1510     }
1511
1512     if( i_area == p_buffer->i_areas )
1513     {
1514         /* New area is below all existing ones: just add it at the end of the
1515          * array, if possible - otherwise, append it to the last one */
1516         if( i_area < VOUT_MAX_AREAS )
1517         {
1518             p_buffer->pi_area_begin[i_area] = i_y;
1519             p_buffer->pi_area_end[i_area] = i_h;
1520             p_buffer->i_areas++;
1521         }
1522         else
1523         {
1524 #ifdef TRACE_VOUT
1525             intf_DbgMsg("area overflow");
1526 #endif
1527             p_buffer->pi_area_end[VOUT_MAX_AREAS - 1] = i_h;
1528         }
1529     }
1530     else
1531     {
1532         i_area_begin =  p_buffer->pi_area_begin[i_area];
1533         i_area_end =    p_buffer->pi_area_end[i_area];
1534
1535         if( i_y < i_area_begin )
1536         {
1537             if( i_h >= i_area_begin - 1 )
1538             {
1539                 /* Extend area above */
1540                 p_buffer->pi_area_begin[i_area] = i_y;
1541             }
1542             else
1543             {
1544                 /* Create a new area above : merge last area if overflow, then
1545                  * move all old areas down */
1546                 if( p_buffer->i_areas == VOUT_MAX_AREAS )
1547                 {
1548 #ifdef TRACE_VOUT
1549                     intf_DbgMsg("areas overflow");
1550 #endif
1551                     p_buffer->pi_area_end[VOUT_MAX_AREAS - 2] = p_buffer->pi_area_end[VOUT_MAX_AREAS - 1];
1552                 }
1553                 else
1554                 {
1555                     p_buffer->i_areas++;
1556                 }
1557                 for( i_area_copy = p_buffer->i_areas - 1; i_area_copy > i_area; i_area_copy-- )
1558                 {
1559                     p_buffer->pi_area_begin[i_area_copy] = p_buffer->pi_area_begin[i_area_copy - 1];
1560                     p_buffer->pi_area_end[i_area_copy] =   p_buffer->pi_area_end[i_area_copy - 1];
1561                 }
1562                 p_buffer->pi_area_begin[i_area] = i_y;
1563                 p_buffer->pi_area_end[i_area] = i_h;
1564                 return;
1565             }
1566         }
1567         if( i_h > i_area_end )
1568         {
1569             /* Find further areas which can be merged with the new one */
1570             for( i_area_copy = i_area + 1;
1571                  (i_area_copy < p_buffer->i_areas) &&
1572                      (p_buffer->pi_area_begin[i_area] <= i_h);
1573                  i_area_copy++ )
1574             {
1575                 ;
1576             }
1577             i_area_copy--;
1578
1579             if( i_area_copy != i_area )
1580             {
1581                 /* Merge with last possible areas */
1582                 //p_buffer->pi_area_end[i_area] = MAX( i_h, p_buffer->pi_area_end[i_area_copy] );
1583
1584                 /* Shift lower areas upward */
1585                 i_area_shift = i_area_copy - i_area;
1586                 p_buffer->i_areas -= i_area_shift;
1587                 for( i_area_copy = i_area + 1; i_area_copy < p_buffer->i_areas; i_area_copy++ )
1588                 {
1589                     p_buffer->pi_area_begin[i_area_copy] = p_buffer->pi_area_begin[i_area_copy + i_area_shift];
1590                     p_buffer->pi_area_end[i_area_copy] =   p_buffer->pi_area_end[i_area_copy + i_area_shift];
1591                 }
1592             }
1593             else
1594             {
1595                 /* Extend area below */
1596                 p_buffer->pi_area_end[i_area] = i_h;
1597             }
1598         }
1599     }
1600 }
1601
1602 /*****************************************************************************
1603  * SetBufferPicture: clear buffer and set picture area
1604  *****************************************************************************
1605  * This function is called before any rendering. It clears the current
1606  * rendering buffer and set the new picture area. If the picture pointer is
1607  * NULL, then no picture area is defined. Floating operations are avoided since
1608  * some MMX calculations may follow.
1609  *****************************************************************************/
1610 static void SetBufferPicture( vout_thread_t *p_vout, picture_t *p_pic )
1611 {
1612     vout_buffer_t *     p_buffer;                          /* current buffer */
1613     int                 i_pic_x, i_pic_y;                /* picture position */
1614     int                 i_pic_width, i_pic_height;     /* picture dimensions */
1615     int                 i_old_pic_y, i_old_pic_height;   /* old picture area */
1616     int                 i_vout_width, i_vout_height;   /* display dimensions */
1617     int                 i_area;                                /* area index */
1618     int                 i_data_index;                     /* area data index */
1619     int                 i_data_size;   /* area data size, in 256 bytes blocs */
1620     u64 *               p_data;                   /* area data, for clearing */
1621     byte_t *            p_data8;           /* area data, for clearing (slow) */
1622
1623     /* Choose buffer and set display dimensions */
1624     p_buffer =          &p_vout->p_buffer[ p_vout->i_buffer_index ];
1625     i_vout_width =      p_vout->i_width;
1626     i_vout_height =     p_vout->i_height;
1627
1628     /*
1629      * Computes new picture size
1630      */
1631     if( p_pic != NULL )
1632     {
1633         /* Try horizontal scaling first - width must be a mutiple of 16 */
1634         i_pic_width = (( p_vout->b_scale || (p_pic->i_width > i_vout_width)) ?
1635                        i_vout_width : p_pic->i_width) & ~0xf;
1636         switch( p_pic->i_aspect_ratio )
1637         {
1638         case AR_3_4_PICTURE:
1639             i_pic_height = i_pic_width * 3 / 4;
1640             break;
1641         case AR_16_9_PICTURE:
1642             i_pic_height = i_pic_width * 9 / 16;
1643             break;
1644         case AR_221_1_PICTURE:
1645             i_pic_height = i_pic_width * 100 / 221;
1646             break;
1647         case AR_SQUARE_PICTURE:
1648         default:
1649             i_pic_height = p_pic->i_height * i_pic_width / p_pic->i_width;
1650             break;
1651         }
1652
1653         /* If picture dimensions using horizontal scaling are too large, use
1654          * vertical scaling. Since width must be a multiple of 16, height is
1655          * adjusted again after. */
1656         if( i_pic_height > i_vout_height )
1657         {
1658             i_pic_height = ( p_vout->b_scale || (p_pic->i_height > i_vout_height)) ?
1659                 i_vout_height : p_pic->i_height;
1660             switch( p_pic->i_aspect_ratio )
1661             {
1662             case AR_3_4_PICTURE:
1663                 i_pic_width = (i_pic_height * 4 / 3) & ~0xf;
1664                 i_pic_height = i_pic_width * 3 / 4;
1665                 break;
1666             case AR_16_9_PICTURE:
1667                 i_pic_width = (i_pic_height * 16 / 9) & ~0xf;
1668                 i_pic_height = i_pic_width * 9 / 16;
1669                 break;
1670             case AR_221_1_PICTURE:
1671                 i_pic_width = (i_pic_height * 221 / 100) & ~0xf;
1672                 i_pic_height = i_pic_width * 100 / 221;
1673                 break;
1674             case AR_SQUARE_PICTURE:
1675             default:
1676                 i_pic_width = (p_pic->i_width * i_pic_height / p_pic->i_height) & ~0xf;
1677                 i_pic_height = p_pic->i_height * i_pic_width / p_pic->i_width;
1678                 break;
1679             }
1680         }
1681
1682         /* Set picture position */
1683         i_pic_x = (p_vout->i_width - i_pic_width) / 2;
1684         i_pic_y = (p_vout->i_height - i_pic_height) / 2;
1685
1686     }
1687     else
1688     {
1689         /* No picture: size is 0 */
1690         i_pic_x =       0;
1691         i_pic_y =       0;
1692         i_pic_width =   0;
1693         i_pic_height =  0;
1694     }
1695
1696     /*
1697      * Set new picture size - if it is smaller than the previous one, clear
1698      * around it. Since picture are centered, only their size is tested.
1699      */
1700     if( (p_buffer->i_pic_width > i_pic_width) || (p_buffer->i_pic_height > i_pic_height) )
1701     {
1702         i_old_pic_y =            p_buffer->i_pic_y;
1703         i_old_pic_height =       p_buffer->i_pic_height;
1704         p_buffer->i_pic_x =      i_pic_x;
1705         p_buffer->i_pic_y =      i_pic_y;
1706         p_buffer->i_pic_width =  i_pic_width;
1707         p_buffer->i_pic_height = i_pic_height;
1708         SetBufferArea( p_vout, 0, i_old_pic_y, p_vout->i_width, i_old_pic_height );
1709     }
1710     else
1711     {
1712         p_buffer->i_pic_x =      i_pic_x;
1713         p_buffer->i_pic_y =      i_pic_y;
1714         p_buffer->i_pic_width =  i_pic_width;
1715         p_buffer->i_pic_height = i_pic_height;
1716     }
1717
1718     /*
1719      * Clear areas
1720      */
1721     for( i_area = 0; i_area < p_buffer->i_areas; i_area++ )
1722     {
1723 #ifdef TRACE_VOUT
1724         intf_DbgMsg("clearing picture %p area in buffer %d: %d-%d", p_pic,
1725                     p_vout->i_buffer_index, p_buffer->pi_area_begin[i_area], p_buffer->pi_area_end[i_area] );
1726 #endif
1727         i_data_size = (p_buffer->pi_area_end[i_area] - p_buffer->pi_area_begin[i_area] + 1) * p_vout->i_bytes_per_line;
1728         p_data = (u64*) (p_buffer->p_data + p_vout->i_bytes_per_line * p_buffer->pi_area_begin[i_area]);
1729
1730         for( i_data_index = i_data_size / 256; i_data_index-- ; )
1731         {
1732             /* Clear 256 bytes block */
1733             *p_data++ = 0;  *p_data++ = 0;  *p_data++ = 0;  *p_data++ = 0;
1734             *p_data++ = 0;  *p_data++ = 0;  *p_data++ = 0;  *p_data++ = 0;
1735             *p_data++ = 0;  *p_data++ = 0;  *p_data++ = 0;  *p_data++ = 0;
1736             *p_data++ = 0;  *p_data++ = 0;  *p_data++ = 0;  *p_data++ = 0;
1737             *p_data++ = 0;  *p_data++ = 0;  *p_data++ = 0;  *p_data++ = 0;
1738             *p_data++ = 0;  *p_data++ = 0;  *p_data++ = 0;  *p_data++ = 0;
1739             *p_data++ = 0;  *p_data++ = 0;  *p_data++ = 0;  *p_data++ = 0;
1740             *p_data++ = 0;  *p_data++ = 0;  *p_data++ = 0;  *p_data++ = 0;
1741         }
1742         for( i_data_index = (i_data_size % 256) / 16; i_data_index--; )
1743         {
1744             /* Clear remaining 16 bytes blocks */
1745             *p_data++ = 0;  *p_data++ = 0;
1746         }
1747         p_data8 = (byte_t *)p_data;
1748         for( i_data_index = i_data_size % 16; i_data_index--; )
1749         {
1750             /* Clear remaining bytes */
1751             *p_data8++ = 0;
1752         }
1753     }
1754
1755     /*
1756      * Clear areas array
1757      */
1758     p_buffer->i_areas = 0;
1759 }
1760
1761 /*****************************************************************************
1762  * RenderPicture: render a picture
1763  *****************************************************************************
1764  * This function converts a picture from a video heap to a pixel-encoded image
1765  * and copies it to the current rendering buffer. No lock is required, since
1766  * the * rendered picture has been determined as existant, and will only be
1767  * destroyed by the vout thread later.
1768  *****************************************************************************/
1769 static void RenderPicture( vout_thread_t *p_vout, picture_t *p_pic )
1770 {
1771 #ifdef TRACE_VOUT
1772     char                psz_date[MSTRTIME_MAX_SIZE];         /* picture date */
1773     mtime_t             render_time;               /* picture rendering time */
1774 #endif
1775     vout_buffer_t *     p_buffer;                        /* rendering buffer */
1776     byte_t *            p_pic_data;                /* convertion destination */
1777
1778     /* Get and set rendering information */
1779     p_buffer =          &p_vout->p_buffer[ p_vout->i_buffer_index ];
1780     p_pic_data =        p_buffer->p_data +
1781                         p_buffer->i_pic_x * p_vout->i_bytes_per_pixel +
1782                         p_buffer->i_pic_y * p_vout->i_bytes_per_line;
1783 #ifdef TRACE_VOUT
1784     render_time = mdate();
1785 #endif
1786
1787
1788
1789     /*
1790      * Choose appropriate rendering function and render picture
1791      */
1792     switch( p_pic->i_type )
1793     {
1794     case YUV_420_PICTURE:
1795         p_vout->yuv.pf_yuv420( p_vout, p_pic_data,
1796                                p_pic->p_y, p_pic->p_u, p_pic->p_v,
1797                                p_pic->i_width, p_pic->i_height,
1798                                p_buffer->i_pic_width, p_buffer->i_pic_height,
1799                                p_vout->i_bytes_per_line / p_vout->i_bytes_per_pixel,
1800                                p_pic->i_matrix_coefficients );
1801         break;
1802     case YUV_422_PICTURE:
1803         p_vout->yuv.pf_yuv422( p_vout, p_pic_data,
1804                                p_pic->p_y, p_pic->p_u, p_pic->p_v,
1805                                p_pic->i_width, p_pic->i_height,
1806                                p_buffer->i_pic_width, p_buffer->i_pic_height,
1807                                p_vout->i_bytes_per_line / p_vout->i_bytes_per_pixel,
1808                                p_pic->i_matrix_coefficients );
1809         break;
1810     case YUV_444_PICTURE:
1811         p_vout->yuv.pf_yuv444( p_vout, p_pic_data,
1812                                p_pic->p_y, p_pic->p_u, p_pic->p_v,
1813                                p_pic->i_width, p_pic->i_height,
1814                                p_buffer->i_pic_width, p_buffer->i_pic_height,
1815                                p_vout->i_bytes_per_line / p_vout->i_bytes_per_pixel,
1816                                p_pic->i_matrix_coefficients );
1817         break;
1818 #ifdef DEBUG
1819     default:
1820         intf_ErrMsg("error: unknown picture type %d", p_pic->i_type );
1821         break;
1822 #endif
1823     }
1824
1825 #ifdef TRACE_VOUT
1826     /* Print picture date and rendering time */
1827     intf_DbgMsg("picture %p rendered in buffer %d (%ld us), display date: %s", p_pic,
1828                 p_vout->i_buffer_index, (long) (mdate() - render_time),
1829                 mstrtime( psz_date, p_pic->date ));
1830 #endif
1831 }
1832
1833 /*****************************************************************************
1834  * RenderPictureInfo: print additionnal information on a picture
1835  *****************************************************************************
1836  * This function will print information such as fps and other picture
1837  * dependant information.
1838  *****************************************************************************/
1839 static void RenderPictureInfo( vout_thread_t *p_vout, picture_t *p_pic )
1840 {
1841     char        psz_buffer[256];                            /* string buffer */
1842
1843     /*
1844      * Print FPS rate in upper right corner
1845      */
1846     if( p_vout->c_fps_samples > VOUT_FPS_SAMPLES )
1847     {
1848         long i_fps = VOUT_FPS_SAMPLES * 1000000 * 10 /
1849                            ( p_vout->p_fps_sample[ (p_vout->c_fps_samples - 1)
1850                                                    % VOUT_FPS_SAMPLES ] -
1851                              p_vout->p_fps_sample[ p_vout->c_fps_samples
1852                                                    % VOUT_FPS_SAMPLES ] );
1853         sprintf( psz_buffer, "%li.%i fps", i_fps / 10, (int)i_fps % 10 );
1854         Print( p_vout, 0, 0, RIGHT_RALIGN, TOP_RALIGN, psz_buffer );
1855     }
1856
1857     /*
1858      * Print frames count and loop time in upper left corner
1859      */
1860     sprintf( psz_buffer, "%ld frames, render: %ldus",
1861              (long) p_vout->c_fps_samples, (long) p_vout->render_time );
1862     Print( p_vout, 0, 0, LEFT_RALIGN, TOP_RALIGN, psz_buffer );
1863
1864 #ifdef STATS
1865     /*
1866      * Print picture information in lower right corner
1867      */
1868     sprintf( psz_buffer, "%s picture %dx%d (%dx%d%+d%+d %s) -> %dx%d+%d+%d",
1869              (p_pic->i_type == YUV_420_PICTURE) ? "4:2:0" :
1870              ((p_pic->i_type == YUV_422_PICTURE) ? "4:2:2" :
1871               ((p_pic->i_type == YUV_444_PICTURE) ? "4:4:4" : "ukn-type")),
1872              p_pic->i_width, p_pic->i_height,
1873              p_pic->i_display_width, p_pic->i_display_height,
1874              p_pic->i_display_horizontal_offset, p_pic->i_display_vertical_offset,
1875              (p_pic->i_aspect_ratio == AR_SQUARE_PICTURE) ? "sq" :
1876              ((p_pic->i_aspect_ratio == AR_3_4_PICTURE) ? "4:3" :
1877               ((p_pic->i_aspect_ratio == AR_16_9_PICTURE) ? "16:9" :
1878                ((p_pic->i_aspect_ratio == AR_221_1_PICTURE) ? "2.21:1" : "ukn-ar" ))),
1879              p_vout->p_buffer[ p_vout->i_buffer_index ].i_pic_width,
1880              p_vout->p_buffer[ p_vout->i_buffer_index ].i_pic_height,
1881              p_vout->p_buffer[ p_vout->i_buffer_index ].i_pic_x,
1882              p_vout->p_buffer[ p_vout->i_buffer_index ].i_pic_y );
1883     Print( p_vout, 0, 0, RIGHT_RALIGN, BOTTOM_RALIGN, psz_buffer );
1884 #endif
1885 }
1886
1887 /*****************************************************************************
1888  * RenderIdle: render idle picture
1889  *****************************************************************************
1890  * This function will print something on the screen. It will return 0 if
1891  * nothing has been rendered, or 1 if something has been changed on the screen.
1892  * Note that if you absolutely want something to be printed, you will have
1893  * to force it by setting the last idle date to 0.
1894  * Unlike other rendering functions, this one calls the SetBufferPicture
1895  * function when needed.
1896  *****************************************************************************/
1897 int RenderIdle( vout_thread_t *p_vout )
1898 {
1899 #if 0
1900     int         i_x = 0, i_y = 0;                           /* text position */
1901     int         i_width, i_height;                              /* text size */
1902     int         i_amount = 0;                             /*  amount to draw */
1903     char *psz_text =    "Waiting for stream";            /* text to display */
1904     char *psz_wtext =   "[................]";
1905 #endif
1906     mtime_t     current_date;                                /* current date */
1907
1908
1909     memset( p_vout->p_buffer[ p_vout->i_buffer_index ].p_data,
1910                     p_vout->i_bytes_per_line * p_vout->i_height, 12);
1911
1912
1913     current_date = mdate();
1914     if( (current_date - p_vout->last_display_date) > VOUT_IDLE_DELAY
1915 //            && (current_date - p_vout->last_idle_date) > VOUT_IDLE_DELAY
1916     )
1917     {
1918         /* FIXME: idle screen disabled */
1919 #if 0
1920         SetBufferPicture( p_vout, NULL );
1921         vout_TextSize( p_vout->p_large_font, WIDE_TEXT | OUTLINED_TEXT, psz_text,
1922                        &i_width, &i_height );
1923         if( !Align( p_vout, &i_x, &i_y, i_width, i_height * 2, CENTER_RALIGN, CENTER_RALIGN ) )
1924         {
1925             i_amount = (int) ((current_date - p_vout->last_display_date ) / 5000LL);
1926             vout_Print( p_vout->p_large_font,
1927                         p_vout->p_buffer[ p_vout->i_buffer_index ].p_data +
1928                         i_x * p_vout->i_bytes_per_pixel + i_y * p_vout->i_bytes_per_line,
1929                         p_vout->i_bytes_per_pixel, p_vout->i_bytes_per_line,
1930                         p_vout->i_white_pixel, p_vout->i_gray_pixel, 0,
1931                         WIDE_TEXT | OUTLINED_TEXT, psz_text,  (i_amount / 3 ) %110);
1932
1933             vout_Print( p_vout->p_large_font,
1934                     p_vout->p_buffer[ p_vout->i_buffer_index ].p_data +
1935                     i_x * p_vout->i_bytes_per_pixel + (i_y + 16) * p_vout->i_bytes_per_line,
1936                     p_vout->i_bytes_per_pixel, p_vout->i_bytes_per_line,
1937                     p_vout->i_white_pixel, p_vout->i_gray_pixel, 0,
1938                     WIDE_TEXT | OUTLINED_TEXT, psz_wtext,  (i_amount/5)%110 );
1939
1940
1941             SetBufferArea( p_vout, i_x, i_y, i_width, i_height * 2 );
1942         }
1943 #endif
1944         return( 1 );
1945     }
1946     return( 0 );
1947 }
1948
1949 /*****************************************************************************
1950  * RenderInfo: render additionnal information
1951  *****************************************************************************
1952  * This function renders information which do not depend on the current
1953  * picture rendered.
1954  *****************************************************************************/
1955 static void RenderInfo( vout_thread_t *p_vout )
1956 {
1957 #ifdef DEBUG
1958     char        psz_buffer[256];                            /* string buffer */
1959     int         i_ready_pic = 0;                           /* ready pictures */
1960     int         i_reserved_pic = 0;                     /* reserved pictures */
1961     int         i_picture;                                  /* picture index */
1962 #endif
1963
1964 #ifdef DEBUG
1965     /*
1966      * Print thread state in lower left corner
1967      */
1968     for( i_picture = 0; i_picture < VOUT_MAX_PICTURES; i_picture++ )
1969     {
1970         switch( p_vout->p_picture[i_picture].i_status )
1971         {
1972         case RESERVED_PICTURE:
1973         case RESERVED_DATED_PICTURE:
1974         case RESERVED_DISP_PICTURE:
1975             i_reserved_pic++;
1976             break;
1977         case READY_PICTURE:
1978             i_ready_pic++;
1979             break;
1980         }
1981     }
1982     sprintf( psz_buffer, "pic: %d (%d/%d)/%d",
1983              p_vout->i_pictures, i_reserved_pic, i_ready_pic, VOUT_MAX_PICTURES );
1984     Print( p_vout, 0, 0, LEFT_RALIGN, BOTTOM_RALIGN, psz_buffer );
1985 #endif
1986 }
1987
1988 /*****************************************************************************
1989  * RenderSubPicture: render a subpicture
1990  *****************************************************************************
1991  * This function renders a sub picture unit.
1992  *****************************************************************************/
1993 static void RenderSubPicture( vout_thread_t *p_vout, picture_t *p_pic,
1994                               subpicture_t *p_subpic )
1995 {
1996     p_vout_font_t       p_font;                                 /* text font */
1997     int                 i_width, i_height;          /* subpicture dimensions */
1998
1999     while( p_subpic != NULL )
2000     {
2001         switch( p_subpic->i_type )
2002         {
2003         case DVD_SUBPICTURE:                          /* DVD subpicture unit */
2004             vout_RenderRGBSPU( p_pic, p_subpic,
2005                                &p_vout->p_buffer[ p_vout->i_buffer_index ],
2006                                p_vout->i_bytes_per_pixel,
2007                                p_vout->i_bytes_per_line );
2008             /* vout_RenderYUVSPU( p_pic, p_subpic ); */
2009             break;
2010
2011         case TEXT_SUBPICTURE:                            /* single line text */
2012             /* Select default font if not specified */
2013             p_font = p_subpic->type.text.p_font;
2014             if( p_font == NULL )
2015             {
2016                 p_font = p_vout->p_default_font;
2017             }
2018
2019             /* Compute text size (width and height fields are ignored)
2020              * and print it */
2021             vout_TextSize( p_font, p_subpic->type.text.i_style,
2022                            p_subpic->p_data, &i_width, &i_height );
2023             if( !Align( p_vout, &p_subpic->i_x, &p_subpic->i_y,
2024                         i_width, i_height, p_subpic->i_horizontal_align,
2025                         p_subpic->i_vertical_align ) )
2026             {
2027                 vout_Print( p_font,
2028                             p_vout->p_buffer[ p_vout->i_buffer_index ].p_data +
2029                             p_subpic->i_x * p_vout->i_bytes_per_pixel +
2030                             p_subpic->i_y * p_vout->i_bytes_per_line,
2031                             p_vout->i_bytes_per_pixel, p_vout->i_bytes_per_line,
2032                             p_subpic->type.text.i_char_color,
2033                             p_subpic->type.text.i_border_color,
2034                             p_subpic->type.text.i_bg_color,
2035                             p_subpic->type.text.i_style, p_subpic->p_data, 100 );
2036                 SetBufferArea( p_vout, p_subpic->i_x, p_subpic->i_y,
2037                                i_width, i_height );
2038             }
2039             break;
2040
2041         default:
2042 #ifdef DEBUG
2043             intf_ErrMsg( "error: unknown subpicture %p type %d",
2044                          p_subpic, p_subpic->i_type );
2045 #endif
2046             break;
2047         }
2048
2049         p_subpic = p_subpic->p_next;
2050     }
2051 }
2052
2053 /*****************************************************************************
2054  * Manage: manage thread
2055  *****************************************************************************
2056  * This function will handle changes in thread configuration.
2057  *****************************************************************************/
2058 static int Manage( vout_thread_t *p_vout )
2059 {
2060 #ifdef TRACE_VOUT
2061     if( p_vout->i_changes )
2062     {
2063         intf_DbgMsg("changes: 0x%x (no display: 0x%x)", p_vout->i_changes,
2064                     0 /* p_vout->i_changes & VOUT_NODISPLAY_CHANGE */ );
2065     }
2066 #endif
2067
2068     /* On gamma or grayscale change, rebuild tables */
2069     if( p_vout->i_changes & (VOUT_GAMMA_CHANGE | VOUT_GRAYSCALE_CHANGE |
2070                              VOUT_YUV_CHANGE) )
2071     {
2072         if( vout_ResetYUV( p_vout ) )
2073         {
2074             intf_ErrMsg( "vout error: can't rebuild conversion tables" );
2075             return( 1 );
2076         }
2077     }
2078
2079     /* Clear changes flags which does not need management or have been
2080      * handled */
2081     p_vout->i_changes &= ~(VOUT_GAMMA_CHANGE  | VOUT_GRAYSCALE_CHANGE |
2082                            VOUT_YUV_CHANGE    | VOUT_INFO_CHANGE |
2083                            VOUT_INTF_CHANGE   | VOUT_SCALE_CHANGE |
2084                            VOUT_CURSOR_CHANGE | VOUT_FULLSCREEN_CHANGE );
2085
2086     /* Detect unauthorized changes */
2087     if( p_vout->i_changes )
2088     {
2089         /* Some changes were not acknowledged by p_vout->pf_manage or this
2090          * function, it means they should not be authorized */
2091         intf_ErrMsg( "vout error: unauthorized changes in the vout thread" );
2092         return( 1 );
2093     }
2094
2095     return( 0 );
2096 }
2097
2098 /*****************************************************************************
2099  * Align: align a subpicture in the screen
2100  *****************************************************************************
2101  * This function is used for rendering text or subpictures. It returns non 0
2102  * it the final aera is not fully included in display area. Return coordinates
2103  * are absolute.
2104  *****************************************************************************/
2105 static int Align( vout_thread_t *p_vout, int *pi_x, int *pi_y,
2106                    int i_width, int i_height, int i_h_align, int i_v_align )
2107 {
2108     /* Align horizontally */
2109     switch( i_h_align )
2110     {
2111     case CENTER_ALIGN:
2112         *pi_x -= i_width / 2;
2113         break;
2114     case CENTER_RALIGN:
2115         *pi_x += (p_vout->i_width - i_width) / 2;
2116         break;
2117     case RIGHT_ALIGN:
2118         *pi_x -= i_width;
2119         break;
2120     case RIGHT_RALIGN:
2121         *pi_x += p_vout->i_width - i_width;
2122         break;
2123     }
2124
2125     /* Align vertically */
2126     switch( i_v_align )
2127     {
2128     case CENTER_ALIGN:
2129         *pi_y -= i_height / 2;
2130         break;
2131     case CENTER_RALIGN:
2132         *pi_y += (p_vout->i_height - i_height) / 2;
2133         break;
2134     case BOTTOM_ALIGN:
2135         *pi_y -= i_height;
2136         break;
2137     case BOTTOM_RALIGN:
2138         *pi_y += p_vout->i_height - i_height;
2139         break;
2140     case SUBTITLE_RALIGN:
2141         *pi_y += (p_vout->i_height + p_vout->p_buffer[ p_vout->i_buffer_index ].i_pic_y +
2142                   p_vout->p_buffer[ p_vout->i_buffer_index ].i_pic_height - i_height) / 2;
2143         break;
2144     }
2145
2146     /* Return non 0 if clipping failed */
2147     return( (*pi_x < 0) || (*pi_y < 0) ||
2148             (*pi_x + i_width > p_vout->i_width) || (*pi_y + i_height > p_vout->i_height) );
2149 }
2150
2151 /*****************************************************************************
2152  * SetPalette: sets an 8 bpp palette
2153  *****************************************************************************
2154  * This function is just a prototype that does nothing. Architectures that
2155  * support palette allocation should override it.
2156  *****************************************************************************/
2157 static void     SetPalette        ( p_vout_thread_t p_vout, u16 *red,
2158                                     u16 *green, u16 *blue, u16 *transp )
2159 {
2160     intf_ErrMsg( "vout error: method does not support palette changing" );
2161 }
2162