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