]> git.sesse.net Git - vlc/blob - src/video_output/video_output.c
Don't include config.h from the headers - refs #297.
[vlc] / src / video_output / video_output.c
1 /*****************************************************************************
2  * video_output.c : video output thread
3  *
4  * This module describes the programming interface for video output threads.
5  * It includes functions allowing to open a new thread, send pictures to a
6  * thread, and destroy a previously oppened video output thread.
7  *****************************************************************************
8  * Copyright (C) 2000-2007 the VideoLAN team
9  * $Id$
10  *
11  * Authors: Vincent Seguin <seguin@via.ecp.fr>
12  *          Gildas Bazin <gbazin@videolan.org>
13  *
14  * This program is free software; you can redistribute it and/or modify
15  * it under the terms of the GNU General Public License as published by
16  * the Free Software Foundation; either version 2 of the License, or
17  * (at your option) any later version.
18  *
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with this program; if not, write to the Free Software
26  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
27  *****************************************************************************/
28
29 /*****************************************************************************
30  * Preamble
31  *****************************************************************************/
32 #ifdef HAVE_CONFIG_H
33 # include "config.h"
34 #endif
35
36 #include <vlc/vlc.h>
37
38 #include <stdlib.h>                                                /* free() */
39 #include <string.h>
40
41
42 #ifdef HAVE_SYS_TIMES_H
43 #   include <sys/times.h>
44 #endif
45
46 #include <vlc_vout.h>
47 #include <vlc_playlist.h>
48
49 #include <vlc_filter.h>
50 #include <vlc_osd.h>
51
52 #if defined( __APPLE__ )
53 /* Include darwin_specific.h here if needed */
54 #endif
55
56 /** FIXME This is quite ugly but needed while we don't have counters
57  * helpers */
58 #include "input/input_internal.h"
59
60 #include "modules/modules.h"
61
62 /*****************************************************************************
63  * Local prototypes
64  *****************************************************************************/
65 static int      InitThread        ( vout_thread_t * );
66 static void     RunThread         ( vout_thread_t * );
67 static void     ErrorThread       ( vout_thread_t * );
68 static void     EndThread         ( vout_thread_t * );
69 static void     DestroyThread     ( vout_thread_t * );
70
71 static void     AspectRatio       ( int, int *, int * );
72 static int      BinaryLog         ( uint32_t );
73 static void     MaskToShift       ( int *, int *, uint32_t );
74
75 /* Object variables callbacks */
76 static int DeinterlaceCallback( vlc_object_t *, char const *,
77                                 vlc_value_t, vlc_value_t, void * );
78 static int FilterCallback( vlc_object_t *, char const *,
79                            vlc_value_t, vlc_value_t, void * );
80 static int VideoFilter2Callback( vlc_object_t *, char const *,
81                                  vlc_value_t, vlc_value_t, void * );
82
83 /* From vout_intf.c */
84 int vout_Snapshot( vout_thread_t *, picture_t * );
85
86 /* Video filter2 parsing */
87 static int ParseVideoFilter2Chain( vout_thread_t *, char * );
88 static void RemoveVideoFilters2( vout_thread_t *p_vout );
89
90 /* Display media title in OSD */
91 static void DisplayTitleOnOSD( vout_thread_t *p_vout );
92
93 /*****************************************************************************
94  * Video Filter2 functions
95  *****************************************************************************/
96 struct filter_owner_sys_t
97 {
98     vout_thread_t *p_vout;
99 };
100
101 static picture_t *video_new_buffer_filter( filter_t *p_filter )
102 {
103     picture_t *p_picture;
104     vout_thread_t *p_vout = p_filter->p_owner->p_vout;
105
106     p_picture = vout_CreatePicture( p_vout, 0, 0, 0 );
107
108     return p_picture;
109 }
110
111 static void video_del_buffer_filter( filter_t *p_filter, picture_t *p_pic )
112 {
113     vout_DestroyPicture( p_filter->p_owner->p_vout, p_pic );
114 }
115
116 /*****************************************************************************
117  * vout_Request: find a video output thread, create one, or destroy one.
118  *****************************************************************************
119  * This function looks for a video output thread matching the current
120  * properties. If not found, it spawns a new one.
121  *****************************************************************************/
122 vout_thread_t *__vout_Request( vlc_object_t *p_this, vout_thread_t *p_vout,
123                                video_format_t *p_fmt )
124 {
125     if( !p_fmt )
126     {
127         /* Reattach video output to playlist before bailing out */
128         if( p_vout )
129         {
130             playlist_t  *p_playlist = pl_Yield( p_this );
131             spu_Attach( p_vout->p_spu, p_this, VLC_FALSE );
132             vlc_object_detach( p_vout );
133             vlc_object_attach( p_vout, p_playlist );
134             pl_Release( p_this );
135         }
136         return NULL;
137     }
138
139     /* If a video output was provided, lock it, otherwise look for one. */
140     if( p_vout )
141     {
142         vlc_object_yield( p_vout );
143     }
144     else
145     {
146         p_vout = vlc_object_find( p_this, VLC_OBJECT_VOUT, FIND_CHILD );
147
148         if( !p_vout )
149         {
150             playlist_t *p_playlist = pl_Yield( p_this );
151             vlc_mutex_lock( &p_playlist->gc_lock );
152             p_vout = vlc_object_find( p_playlist,
153                                       VLC_OBJECT_VOUT, FIND_CHILD );
154             /* only first children of p_input for unused vout */
155             if( p_vout && p_vout->p_parent != (vlc_object_t *)p_playlist )
156             {
157                 vlc_object_release( p_vout );
158                 p_vout = NULL;
159             }
160             if( p_vout )
161                 vlc_object_detach( p_vout );    /* Remove it from the GC */
162             vlc_mutex_unlock( &p_playlist->gc_lock );
163             pl_Release( p_this );
164         }
165     }
166
167     /* If we now have a video output, check it has the right properties */
168     if( p_vout )
169     {
170         char *psz_filter_chain;
171         vlc_value_t val;
172
173         /* We don't directly check for the "vout-filter" variable for obvious
174          * performance reasons. */
175         if( p_vout->b_filter_change )
176         {
177             var_Get( p_vout, "vout-filter", &val );
178             psz_filter_chain = val.psz_string;
179
180             if( psz_filter_chain && !*psz_filter_chain )
181             {
182                 free( psz_filter_chain );
183                 psz_filter_chain = NULL;
184             }
185             if( p_vout->psz_filter_chain && !*p_vout->psz_filter_chain )
186             {
187                 free( p_vout->psz_filter_chain );
188                 p_vout->psz_filter_chain = NULL;
189             }
190
191             if( !psz_filter_chain && !p_vout->psz_filter_chain )
192             {
193                 p_vout->b_filter_change = VLC_FALSE;
194             }
195
196             if( psz_filter_chain ) free( psz_filter_chain );
197         }
198
199         if( ( p_vout->fmt_render.i_width != p_fmt->i_width ) ||
200             ( p_vout->fmt_render.i_height != p_fmt->i_height ) ||
201             ( p_vout->fmt_render.i_aspect != p_fmt->i_aspect ) ||
202             p_vout->b_filter_change )
203         {
204             /* We are not interested in this format, close this vout */
205             vlc_object_release( p_vout );
206             vout_Destroy( p_vout );
207             p_vout = NULL;
208         }
209         else
210         {
211             /* This video output is cool! Hijack it. */
212             spu_Attach( p_vout->p_spu, p_this, VLC_TRUE );
213             vlc_object_attach( p_vout, p_this );
214             if( p_vout->b_title_show )
215                 DisplayTitleOnOSD( p_vout );
216             vlc_object_release( p_vout );
217         }
218     }
219
220     if( !p_vout )
221     {
222         msg_Dbg( p_this, "no usable vout present, spawning one" );
223
224         p_vout = vout_Create( p_this, p_fmt );
225     }
226
227     return p_vout;
228 }
229
230 /*****************************************************************************
231  * vout_Create: creates a new video output thread
232  *****************************************************************************
233  * This function creates a new video output thread, and returns a pointer
234  * to its description. On error, it returns NULL.
235  *****************************************************************************/
236 vout_thread_t * __vout_Create( vlc_object_t *p_parent, video_format_t *p_fmt )
237 {
238     vout_thread_t  * p_vout;                            /* thread descriptor */
239     input_thread_t * p_input_thread;
240     int              i_index;                               /* loop variable */
241     vlc_value_t      val, text;
242
243     unsigned int i_width = p_fmt->i_width;
244     unsigned int i_height = p_fmt->i_height;
245     vlc_fourcc_t i_chroma = p_fmt->i_chroma;
246     unsigned int i_aspect = p_fmt->i_aspect;
247
248     config_chain_t *p_cfg;
249     char *psz_parser;
250     char *psz_name;
251
252     /* Allocate descriptor */
253     p_vout = vlc_object_create( p_parent, VLC_OBJECT_VOUT );
254     if( p_vout == NULL )
255     {
256         msg_Err( p_parent, "out of memory" );
257         return NULL;
258     }
259
260     /* Initialize pictures - translation tables and functions
261      * will be initialized later in InitThread */
262     for( i_index = 0; i_index < 2 * VOUT_MAX_PICTURES + 1; i_index++)
263     {
264         p_vout->p_picture[i_index].pf_lock = NULL;
265         p_vout->p_picture[i_index].pf_unlock = NULL;
266         p_vout->p_picture[i_index].i_status = FREE_PICTURE;
267         p_vout->p_picture[i_index].i_type   = EMPTY_PICTURE;
268         p_vout->p_picture[i_index].b_slow   = 0;
269     }
270
271     /* No images in the heap */
272     p_vout->i_heap_size = 0;
273
274     /* Initialize the rendering heap */
275     I_RENDERPICTURES = 0;
276
277     vlc_ureduce( &p_fmt->i_sar_num, &p_fmt->i_sar_den,
278                  p_fmt->i_sar_num, p_fmt->i_sar_den, 50000 );
279     p_vout->fmt_render        = *p_fmt;   /* FIXME palette */
280     p_vout->fmt_in            = *p_fmt;   /* FIXME palette */
281
282     p_vout->render.i_width    = i_width;
283     p_vout->render.i_height   = i_height;
284     p_vout->render.i_chroma   = i_chroma;
285     p_vout->render.i_aspect   = i_aspect;
286
287     p_vout->render.i_rmask    = 0;
288     p_vout->render.i_gmask    = 0;
289     p_vout->render.i_bmask    = 0;
290
291     p_vout->render.i_last_used_pic = -1;
292     p_vout->render.b_allow_modify_pics = 1;
293
294     /* Zero the output heap */
295     I_OUTPUTPICTURES = 0;
296     p_vout->output.i_width    = 0;
297     p_vout->output.i_height   = 0;
298     p_vout->output.i_chroma   = 0;
299     p_vout->output.i_aspect   = 0;
300
301     p_vout->output.i_rmask    = 0;
302     p_vout->output.i_gmask    = 0;
303     p_vout->output.i_bmask    = 0;
304
305     /* Initialize misc stuff */
306     p_vout->i_changes    = 0;
307     p_vout->f_gamma      = 0;
308     p_vout->b_grayscale  = 0;
309     p_vout->b_info       = 0;
310     p_vout->b_interface  = 0;
311     p_vout->b_scale      = 1;
312     p_vout->b_fullscreen = 0;
313     p_vout->i_alignment  = 0;
314     p_vout->render_time  = 10;
315     p_vout->c_fps_samples = 0;
316     p_vout->b_filter_change = 0;
317     p_vout->pf_control = 0;
318     p_vout->p_parent_intf = 0;
319     p_vout->i_par_num = p_vout->i_par_den = 1;
320
321     /* Initialize locks */
322     vlc_mutex_init( p_vout, &p_vout->picture_lock );
323     vlc_mutex_init( p_vout, &p_vout->change_lock );
324     vlc_mutex_init( p_vout, &p_vout->vfilter_lock );
325
326     /* Mouse coordinates */
327     var_Create( p_vout, "mouse-x", VLC_VAR_INTEGER );
328     var_Create( p_vout, "mouse-y", VLC_VAR_INTEGER );
329     var_Create( p_vout, "mouse-button-down", VLC_VAR_INTEGER );
330     var_Create( p_vout, "mouse-moved", VLC_VAR_BOOL );
331     var_Create( p_vout, "mouse-clicked", VLC_VAR_INTEGER );
332
333     /* Initialize subpicture unit */
334     p_vout->p_spu = spu_Create( p_vout );
335     spu_Attach( p_vout->p_spu, p_parent, VLC_TRUE );
336
337     /* Attach the new object now so we can use var inheritance below */
338     vlc_object_attach( p_vout, p_parent );
339
340     spu_Init( p_vout->p_spu );
341
342     /* Take care of some "interface/control" related initialisations */
343     vout_IntfInit( p_vout );
344
345     /* If the parent is not a VOUT object, that means we are at the start of
346      * the video output pipe */
347     if( p_parent->i_object_type != VLC_OBJECT_VOUT )
348     {
349         /* Look for the default filter configuration */
350         var_Create( p_vout, "vout-filter", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
351         var_Get( p_vout, "vout-filter", &val );
352         p_vout->psz_filter_chain = val.psz_string;
353
354         /* Apply video filter2 objects on the first vout */
355         var_Create( p_vout, "video-filter",
356                     VLC_VAR_STRING | VLC_VAR_DOINHERIT );
357         var_Get( p_vout, "video-filter", &val );
358         ParseVideoFilter2Chain( p_vout, val.psz_string );
359         free( val.psz_string );
360     }
361     else
362     {
363         /* continue the parent's filter chain */
364         char *psz_tmp;
365
366         /* Ugly hack to jump to our configuration chain */
367         p_vout->psz_filter_chain
368             = ((vout_thread_t *)p_parent)->psz_filter_chain;
369         p_vout->psz_filter_chain
370             = config_ChainCreate( &psz_tmp, &p_cfg, p_vout->psz_filter_chain );
371         config_ChainDestroy( p_cfg );
372         free( psz_tmp );
373
374         /* Create a video filter2 var ... but don't inherit values */
375         var_Create( p_vout, "video-filter", VLC_VAR_STRING );
376         ParseVideoFilter2Chain( p_vout, NULL );
377     }
378
379     var_AddCallback( p_vout, "video-filter", VideoFilter2Callback, NULL );
380     p_vout->b_vfilter_change = VLC_TRUE;
381     p_vout->i_vfilters = 0;
382
383     /* Choose the video output module */
384     if( !p_vout->psz_filter_chain || !*p_vout->psz_filter_chain )
385     {
386         var_Create( p_vout, "vout", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
387         var_Get( p_vout, "vout", &val );
388         psz_parser = val.psz_string;
389     }
390     else
391     {
392         psz_parser = strdup( p_vout->psz_filter_chain );
393     }
394
395     /* Create the vout thread */
396     config_ChainCreate( &psz_name, &p_cfg, psz_parser );
397     free( psz_parser );
398     p_vout->p_cfg = p_cfg;
399     p_vout->p_module = module_Need( p_vout,
400         ( p_vout->psz_filter_chain && *p_vout->psz_filter_chain ) ?
401         "video filter" : "video output", psz_name, p_vout->psz_filter_chain && *p_vout->psz_filter_chain );
402     free( psz_name );
403
404     if( p_vout->p_module == NULL )
405     {
406         msg_Err( p_vout, "no suitable vout module" );
407         vlc_object_detach( p_vout );
408         vlc_object_destroy( p_vout );
409         return NULL;
410     }
411
412     /* Create a few object variables for interface interaction */
413     var_Create( p_vout, "deinterlace", VLC_VAR_STRING | VLC_VAR_HASCHOICE );
414     text.psz_string = _("Deinterlace");
415     var_Change( p_vout, "deinterlace", VLC_VAR_SETTEXT, &text, NULL );
416     val.psz_string = (char *)""; text.psz_string = _("Disable");
417     var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text );
418     val.psz_string = (char *)"discard"; text.psz_string = _("Discard");
419     var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text );
420     val.psz_string = (char *)"blend"; text.psz_string = _("Blend");
421     var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text );
422     val.psz_string = (char *)"mean"; text.psz_string = _("Mean");
423     var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text );
424     val.psz_string = (char *)"bob"; text.psz_string = _("Bob");
425     var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text );
426     val.psz_string = (char *)"linear"; text.psz_string = _("Linear");
427     var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text );
428     val.psz_string = (char *)"x"; text.psz_string = (char *)"X";
429     var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text );
430
431     if( var_Get( p_vout, "deinterlace-mode", &val ) == VLC_SUCCESS )
432     {
433         var_Set( p_vout, "deinterlace", val );
434         if( val.psz_string ) free( val.psz_string );
435     }
436     var_AddCallback( p_vout, "deinterlace", DeinterlaceCallback, NULL );
437
438     var_Create( p_vout, "vout-filter", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
439     text.psz_string = _("Filters");
440     var_Change( p_vout, "vout-filter", VLC_VAR_SETTEXT, &text, NULL );
441     var_AddCallback( p_vout, "vout-filter", FilterCallback, NULL );
442
443     /* Calculate delay created by internal caching */
444     p_input_thread = (input_thread_t *)vlc_object_find( p_vout,
445                                            VLC_OBJECT_INPUT, FIND_ANYWHERE );
446     if( p_input_thread )
447     {
448         p_vout->i_pts_delay = p_input_thread->i_pts_delay;
449         vlc_object_release( p_input_thread );
450     }
451     else
452     {
453         p_vout->i_pts_delay = DEFAULT_PTS_DELAY;
454     }
455
456     if( vlc_thread_create( p_vout, "video output", RunThread,
457                            VLC_THREAD_PRIORITY_OUTPUT, VLC_TRUE ) )
458     {
459         msg_Err( p_vout, "out of memory" );
460         module_Unneed( p_vout, p_vout->p_module );
461         vlc_object_detach( p_vout );
462         vlc_object_destroy( p_vout );
463         return NULL;
464     }
465
466     if( p_vout->b_error )
467     {
468         msg_Err( p_vout, "video output creation failed" );
469
470         /* Make sure the thread is destroyed */
471         vlc_object_kill( p_vout );
472         vlc_thread_join( p_vout );
473
474         vlc_object_detach( p_vout );
475         vlc_object_destroy( p_vout );
476         return NULL;
477     }
478
479     return p_vout;
480 }
481
482 /*****************************************************************************
483  * vout_Destroy: destroys a previously created video output
484  *****************************************************************************
485  * Destroy a terminated thread.
486  * The function will request a destruction of the specified thread. If pi_error
487  * is NULL, it will return once the thread is destroyed. Else, it will be
488  * update using one of the THREAD_* constants.
489  *****************************************************************************/
490 void vout_Destroy( vout_thread_t *p_vout )
491 {
492     vout_thread_t *p_another_vout;
493     playlist_t *p_playlist = pl_Yield( p_vout );
494
495     /* Request thread destruction */
496     vlc_object_kill( p_vout );
497     vlc_thread_join( p_vout );
498
499     var_Destroy( p_vout, "intf-change" );
500
501     if( p_vout->psz_filter_chain ) free( p_vout->psz_filter_chain );
502
503     config_ChainDestroy( p_vout->p_cfg );
504
505     /* Free structure */
506     vlc_object_destroy( p_vout );
507 #ifndef __APPLE__
508     /* This is a dirty hack for mostly Linux, where there is no way to get the GUI
509        back if you closed it while playing video. This is solved in Mac OS X,
510        where we have this novelty called menubar, that will always allow you access
511        to the applications main functionality. They should try that on linux sometime */
512     p_another_vout = vlc_object_find( p_playlist,
513                                       VLC_OBJECT_VOUT, FIND_ANYWHERE );
514     if( p_another_vout == NULL )
515     {
516         vlc_value_t val;
517         val.b_bool = VLC_TRUE;
518         var_Set( p_playlist, "intf-show", val );
519     }
520     else
521     {
522         vlc_object_release( p_another_vout );
523     }
524 #endif
525     vlc_object_release( p_playlist );
526 }
527
528 /*****************************************************************************
529  * InitThread: initialize video output thread
530  *****************************************************************************
531  * This function is called from RunThread and performs the second step of the
532  * initialization. It returns 0 on success. Note that the thread's flag are not
533  * modified inside this function.
534  *****************************************************************************/
535 static int InitThread( vout_thread_t *p_vout )
536 {
537     int i, i_aspect_x, i_aspect_y;
538
539     vlc_mutex_lock( &p_vout->change_lock );
540
541 #ifdef STATS
542     p_vout->c_loops = 0;
543 #endif
544
545     /* Initialize output method, it allocates direct buffers for us */
546     if( p_vout->pf_init( p_vout ) )
547     {
548         vlc_mutex_unlock( &p_vout->change_lock );
549         return VLC_EGENERIC;
550     }
551
552     if( !I_OUTPUTPICTURES )
553     {
554         msg_Err( p_vout, "plugin was unable to allocate at least "
555                          "one direct buffer" );
556         p_vout->pf_end( p_vout );
557         vlc_mutex_unlock( &p_vout->change_lock );
558         return VLC_EGENERIC;
559     }
560
561     if( I_OUTPUTPICTURES > VOUT_MAX_PICTURES )
562     {
563         msg_Err( p_vout, "plugin allocated too many direct buffers, "
564                          "our internal buffers must have overflown." );
565         p_vout->pf_end( p_vout );
566         vlc_mutex_unlock( &p_vout->change_lock );
567         return VLC_EGENERIC;
568     }
569
570     msg_Dbg( p_vout, "got %i direct buffer(s)", I_OUTPUTPICTURES );
571
572     AspectRatio( p_vout->fmt_render.i_aspect, &i_aspect_x, &i_aspect_y );
573
574     msg_Dbg( p_vout, "picture in %ix%i (%i,%i,%ix%i), "
575              "chroma %4.4s, ar %i:%i, sar %i:%i",
576              p_vout->fmt_render.i_width, p_vout->fmt_render.i_height,
577              p_vout->fmt_render.i_x_offset, p_vout->fmt_render.i_y_offset,
578              p_vout->fmt_render.i_visible_width,
579              p_vout->fmt_render.i_visible_height,
580              (char*)&p_vout->fmt_render.i_chroma,
581              i_aspect_x, i_aspect_y,
582              p_vout->fmt_render.i_sar_num, p_vout->fmt_render.i_sar_den );
583
584     AspectRatio( p_vout->fmt_in.i_aspect, &i_aspect_x, &i_aspect_y );
585
586     msg_Dbg( p_vout, "picture user %ix%i (%i,%i,%ix%i), "
587              "chroma %4.4s, ar %i:%i, sar %i:%i",
588              p_vout->fmt_in.i_width, p_vout->fmt_in.i_height,
589              p_vout->fmt_in.i_x_offset, p_vout->fmt_in.i_y_offset,
590              p_vout->fmt_in.i_visible_width,
591              p_vout->fmt_in.i_visible_height,
592              (char*)&p_vout->fmt_in.i_chroma,
593              i_aspect_x, i_aspect_y,
594              p_vout->fmt_in.i_sar_num, p_vout->fmt_in.i_sar_den );
595
596     if( !p_vout->fmt_out.i_width || !p_vout->fmt_out.i_height )
597     {
598         p_vout->fmt_out.i_width = p_vout->fmt_out.i_visible_width =
599             p_vout->output.i_width;
600         p_vout->fmt_out.i_height = p_vout->fmt_out.i_visible_height =
601             p_vout->output.i_height;
602         p_vout->fmt_out.i_x_offset =  p_vout->fmt_out.i_y_offset = 0;
603
604         p_vout->fmt_out.i_aspect = p_vout->output.i_aspect;
605         p_vout->fmt_out.i_chroma = p_vout->output.i_chroma;
606     }
607     if( !p_vout->fmt_out.i_sar_num || !p_vout->fmt_out.i_sar_num )
608     {
609         p_vout->fmt_out.i_sar_num = p_vout->fmt_out.i_aspect *
610             p_vout->fmt_out.i_height;
611         p_vout->fmt_out.i_sar_den = VOUT_ASPECT_FACTOR *
612             p_vout->fmt_out.i_width;
613     }
614
615     vlc_ureduce( &p_vout->fmt_out.i_sar_num, &p_vout->fmt_out.i_sar_den,
616                  p_vout->fmt_out.i_sar_num, p_vout->fmt_out.i_sar_den, 0 );
617
618     AspectRatio( p_vout->fmt_out.i_aspect, &i_aspect_x, &i_aspect_y );
619
620     msg_Dbg( p_vout, "picture out %ix%i (%i,%i,%ix%i), "
621              "chroma %4.4s, ar %i:%i, sar %i:%i",
622              p_vout->fmt_out.i_width, p_vout->fmt_out.i_height,
623              p_vout->fmt_out.i_x_offset, p_vout->fmt_out.i_y_offset,
624              p_vout->fmt_out.i_visible_width,
625              p_vout->fmt_out.i_visible_height,
626              (char*)&p_vout->fmt_out.i_chroma,
627              i_aspect_x, i_aspect_y,
628              p_vout->fmt_out.i_sar_num, p_vout->fmt_out.i_sar_den );
629
630     /* Calculate shifts from system-updated masks */
631     MaskToShift( &p_vout->output.i_lrshift, &p_vout->output.i_rrshift,
632                  p_vout->output.i_rmask );
633     MaskToShift( &p_vout->output.i_lgshift, &p_vout->output.i_rgshift,
634                  p_vout->output.i_gmask );
635     MaskToShift( &p_vout->output.i_lbshift, &p_vout->output.i_rbshift,
636                  p_vout->output.i_bmask );
637
638     /* Check whether we managed to create direct buffers similar to
639      * the render buffers, ie same size and chroma */
640     if( ( p_vout->output.i_width == p_vout->render.i_width )
641      && ( p_vout->output.i_height == p_vout->render.i_height )
642      && ( vout_ChromaCmp( p_vout->output.i_chroma, p_vout->render.i_chroma ) ) )
643     {
644         /* Cool ! We have direct buffers, we can ask the decoder to
645          * directly decode into them ! Map the first render buffers to
646          * the first direct buffers, but keep the first direct buffer
647          * for memcpy operations */
648         p_vout->b_direct = 1;
649
650         for( i = 1; i < VOUT_MAX_PICTURES; i++ )
651         {
652             if( p_vout->p_picture[ i ].i_type != DIRECT_PICTURE &&
653                 I_RENDERPICTURES >= VOUT_MIN_DIRECT_PICTURES - 1 &&
654                 p_vout->p_picture[ i - 1 ].i_type == DIRECT_PICTURE )
655             {
656                 /* We have enough direct buffers so there's no need to
657                  * try to use system memory buffers. */
658                 break;
659             }
660             PP_RENDERPICTURE[ I_RENDERPICTURES ] = &p_vout->p_picture[ i ];
661             I_RENDERPICTURES++;
662         }
663
664         msg_Dbg( p_vout, "direct render, mapping "
665                  "render pictures 0-%i to system pictures 1-%i",
666                  VOUT_MAX_PICTURES - 2, VOUT_MAX_PICTURES - 1 );
667     }
668     else
669     {
670         /* Rats... Something is wrong here, we could not find an output
671          * plugin able to directly render what we decode. See if we can
672          * find a chroma plugin to do the conversion */
673         p_vout->b_direct = 0;
674
675         /* Choose the best module */
676         p_vout->chroma.p_module = module_Need( p_vout, "chroma", NULL, 0 );
677
678         if( p_vout->chroma.p_module == NULL )
679         {
680             msg_Err( p_vout, "no chroma module for %4.4s to %4.4s",
681                      (char*)&p_vout->render.i_chroma,
682                      (char*)&p_vout->output.i_chroma );
683             p_vout->pf_end( p_vout );
684             vlc_mutex_unlock( &p_vout->change_lock );
685             return VLC_EGENERIC;
686         }
687
688         msg_Dbg( p_vout, "indirect render, mapping "
689                  "render pictures 0-%i to system pictures %i-%i",
690                  VOUT_MAX_PICTURES - 1, I_OUTPUTPICTURES,
691                  I_OUTPUTPICTURES + VOUT_MAX_PICTURES - 1 );
692
693         /* Append render buffers after the direct buffers */
694         for( i = I_OUTPUTPICTURES; i < 2 * VOUT_MAX_PICTURES; i++ )
695         {
696             PP_RENDERPICTURE[ I_RENDERPICTURES ] = &p_vout->p_picture[ i ];
697             I_RENDERPICTURES++;
698
699             /* Check if we have enough render pictures */
700             if( I_RENDERPICTURES == VOUT_MAX_PICTURES )
701                 break;
702         }
703     }
704
705     /* Link pictures back to their heap */
706     for( i = 0 ; i < I_RENDERPICTURES ; i++ )
707     {
708         PP_RENDERPICTURE[ i ]->p_heap = &p_vout->render;
709     }
710
711     for( i = 0 ; i < I_OUTPUTPICTURES ; i++ )
712     {
713         PP_OUTPUTPICTURE[ i ]->p_heap = &p_vout->output;
714     }
715
716 /* XXX XXX mark thread ready */
717     return VLC_SUCCESS;
718 }
719
720 /*****************************************************************************
721  * RunThread: video output thread
722  *****************************************************************************
723  * Video output thread. This function does only returns when the thread is
724  * terminated. It handles the pictures arriving in the video heap and the
725  * display device events.
726  *****************************************************************************/
727 static void RunThread( vout_thread_t *p_vout)
728 {
729     int             i_index;                                /* index in heap */
730     int             i_idle_loops = 0;  /* loops without displaying a picture */
731     mtime_t         current_date;                            /* current date */
732     mtime_t         display_date;                            /* display date */
733
734     picture_t *     p_picture;                            /* picture pointer */
735     picture_t *     p_last_picture = NULL;                   /* last picture */
736     picture_t *     p_directbuffer;              /* direct buffer to display */
737
738     subpicture_t *  p_subpic = NULL;                   /* subpicture pointer */
739
740     input_thread_t *p_input = NULL ;           /* Parent input, if it exists */
741
742     vlc_value_t     val;
743     vlc_bool_t      b_drop_late;
744
745     int             i_displayed = 0, i_lost = 0, i_loops = 0;
746
747     /*
748      * Initialize thread
749      */
750     p_vout->b_error = InitThread( p_vout );
751
752     var_Create( p_vout, "drop-late-frames", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
753     var_Get( p_vout, "drop-late-frames", &val );
754     b_drop_late = val.b_bool;
755
756     /* signal the creation of the vout */
757     vlc_thread_ready( p_vout );
758
759     if( p_vout->b_error )
760     {
761         /* Destroy thread structures allocated by Create and InitThread */
762         DestroyThread( p_vout );
763         return;
764     }
765
766     if( p_vout->b_title_show )
767         DisplayTitleOnOSD( p_vout );
768
769     /*
770      * Main loop - it is not executed if an error occurred during
771      * initialization
772      */
773     while( (!p_vout->b_die) && (!p_vout->b_error) )
774     {
775         /* Initialize loop variables */
776         p_picture = NULL;
777         display_date = 0;
778         current_date = mdate();
779
780         if( p_input && p_input->b_die )
781         {
782             vlc_object_release( p_input );
783             p_input = NULL;
784         }
785
786         i_loops++;
787         if( i_loops % 20 == 0 )
788         {
789             if( !p_input )
790             {
791                 p_input = vlc_object_find( p_vout, VLC_OBJECT_INPUT,
792                                            FIND_PARENT );
793             }
794             if( p_input )
795             {
796                 vlc_mutex_lock( &p_input->p->counters.counters_lock );
797                 stats_UpdateInteger( p_vout, p_input->p->counters.p_lost_pictures,
798                                      i_lost , NULL);
799                 stats_UpdateInteger( p_vout,
800                                      p_input->p->counters.p_displayed_pictures,
801                                      i_displayed , NULL);
802                 i_displayed = i_lost = 0;
803                 vlc_mutex_unlock( &p_input->p->counters.counters_lock );
804             }
805         }
806 #if 0
807         p_vout->c_loops++;
808         if( !(p_vout->c_loops % VOUT_STATS_NB_LOOPS) )
809         {
810             msg_Dbg( p_vout, "picture heap: %d/%d",
811                      I_RENDERPICTURES, p_vout->i_heap_size );
812         }
813 #endif
814
815         /*
816          * Find the picture to display (the one with the earliest date).
817          * This operation does not need lock, since only READY_PICTUREs
818          * are handled. */
819         for( i_index = 0; i_index < I_RENDERPICTURES; i_index++ )
820         {
821             if( (PP_RENDERPICTURE[i_index]->i_status == READY_PICTURE)
822                 && ( (p_picture == NULL) ||
823                      (PP_RENDERPICTURE[i_index]->date < display_date) ) )
824             {
825                 p_picture = PP_RENDERPICTURE[i_index];
826                 display_date = p_picture->date;
827             }
828         }
829
830         if( p_picture )
831         {
832             /* If we met the last picture, parse again to see whether there is
833              * a more appropriate one. */
834             if( p_picture == p_last_picture )
835             {
836                 for( i_index = 0; i_index < I_RENDERPICTURES; i_index++ )
837                 {
838                     if( (PP_RENDERPICTURE[i_index]->i_status == READY_PICTURE)
839                         && (PP_RENDERPICTURE[i_index] != p_last_picture)
840                         && ((p_picture == p_last_picture) ||
841                             (PP_RENDERPICTURE[i_index]->date < display_date)) )
842                     {
843                         p_picture = PP_RENDERPICTURE[i_index];
844                         display_date = p_picture->date;
845                     }
846                 }
847             }
848
849             /* If we found better than the last picture, destroy it */
850             if( p_last_picture && p_picture != p_last_picture )
851             {
852                 vlc_mutex_lock( &p_vout->picture_lock );
853                 if( p_last_picture->i_refcount )
854                 {
855                     p_last_picture->i_status = DISPLAYED_PICTURE;
856                 }
857                 else
858                 {
859                     p_last_picture->i_status = DESTROYED_PICTURE;
860                     p_vout->i_heap_size--;
861                 }
862                 vlc_mutex_unlock( &p_vout->picture_lock );
863                 p_last_picture = NULL;
864             }
865
866             /* Compute FPS rate */
867             p_vout->p_fps_sample[ p_vout->c_fps_samples++ % VOUT_FPS_SAMPLES ]
868                 = display_date;
869
870             if( !p_picture->b_force &&
871                 p_picture != p_last_picture &&
872                 display_date < current_date + p_vout->render_time &&
873                 b_drop_late )
874             {
875                 /* Picture is late: it will be destroyed and the thread
876                  * will directly choose the next picture */
877                 vlc_mutex_lock( &p_vout->picture_lock );
878                 if( p_picture->i_refcount )
879                 {
880                     /* Pretend we displayed the picture, but don't destroy
881                      * it since the decoder might still need it. */
882                     p_picture->i_status = DISPLAYED_PICTURE;
883                 }
884                 else
885                 {
886                     /* Destroy the picture without displaying it */
887                     p_picture->i_status = DESTROYED_PICTURE;
888                     p_vout->i_heap_size--;
889                 }
890                 msg_Warn( p_vout, "late picture skipped ("I64Fd")",
891                                   current_date - display_date );
892                 i_lost++;
893                 vlc_mutex_unlock( &p_vout->picture_lock );
894
895                 continue;
896             }
897
898             if( display_date >
899                 current_date + p_vout->i_pts_delay + VOUT_BOGUS_DELAY )
900             {
901                 /* Picture is waaay too early: it will be destroyed */
902                 vlc_mutex_lock( &p_vout->picture_lock );
903                 if( p_picture->i_refcount )
904                 {
905                     /* Pretend we displayed the picture, but don't destroy
906                      * it since the decoder might still need it. */
907                     p_picture->i_status = DISPLAYED_PICTURE;
908                 }
909                 else
910                 {
911                     /* Destroy the picture without displaying it */
912                     p_picture->i_status = DESTROYED_PICTURE;
913                     p_vout->i_heap_size--;
914                 }
915                 i_lost++;
916                 msg_Warn( p_vout, "vout warning: early picture skipped "
917                           "("I64Fd")", display_date - current_date
918                           - p_vout->i_pts_delay );
919                 vlc_mutex_unlock( &p_vout->picture_lock );
920
921                 continue;
922             }
923
924             if( display_date > current_date + VOUT_DISPLAY_DELAY )
925             {
926                 /* A picture is ready to be rendered, but its rendering date
927                  * is far from the current one so the thread will perform an
928                  * empty loop as if no picture were found. The picture state
929                  * is unchanged */
930                 p_picture    = NULL;
931                 display_date = 0;
932             }
933             else if( p_picture == p_last_picture )
934             {
935                 /* We are asked to repeat the previous picture, but we first
936                  * wait for a couple of idle loops */
937                 if( i_idle_loops < 4 )
938                 {
939                     p_picture    = NULL;
940                     display_date = 0;
941                 }
942                 else
943                 {
944                     /* We set the display date to something high, otherwise
945                      * we'll have lots of problems with late pictures */
946                     display_date = current_date + p_vout->render_time;
947                 }
948             }
949         }
950
951         if( p_picture == NULL )
952         {
953             i_idle_loops++;
954         }
955
956         /* Video Filter2 stuff */
957         if( p_vout->b_vfilter_change == VLC_TRUE )
958         {
959             int i;
960             vlc_mutex_lock( &p_vout->vfilter_lock );
961             RemoveVideoFilters2( p_vout );
962             for( i = 0; i < p_vout->i_vfilters_cfg; i++ )
963             {
964                 filter_t *p_vfilter =
965                     p_vout->pp_vfilters[p_vout->i_vfilters] =
966                         vlc_object_create( p_vout, VLC_OBJECT_FILTER );
967
968                 vlc_object_attach( p_vfilter, p_vout );
969
970                 p_vfilter->pf_vout_buffer_new = video_new_buffer_filter;
971                 p_vfilter->pf_vout_buffer_del = video_del_buffer_filter;
972
973                 if( !p_vout->i_vfilters )
974                 {
975                     p_vfilter->fmt_in.video = p_vout->fmt_render;
976                 }
977                 else
978                 {
979                     p_vfilter->fmt_in.video = (p_vfilter-1)->fmt_out.video;
980                 }
981                 /* TODO: one day filters in the middle of the chain might
982                  * have a different fmt_out.video than fmt_render ... */
983                 p_vfilter->fmt_out.video = p_vout->fmt_render;
984
985                 p_vfilter->p_cfg = p_vout->p_vfilters_cfg[i];
986                 p_vfilter->p_module = module_Need( p_vfilter, "video filter2",
987                                                    p_vout->psz_vfilters[i],
988                                                    VLC_TRUE );
989
990                 if( p_vfilter->p_module )
991                 {
992                     p_vfilter->p_owner =
993                         malloc( sizeof( filter_owner_sys_t ) );
994                     p_vfilter->p_owner->p_vout = p_vout;
995                     p_vout->i_vfilters++;
996                     msg_Dbg( p_vout, "video filter found (%s)",
997                              p_vout->psz_vfilters[i] );
998                 }
999                 else
1000                 {
1001                     msg_Err( p_vout, "no video filter found (%s)",
1002                              p_vout->psz_vfilters[i] );
1003                     vlc_object_detach( p_vfilter );
1004                     vlc_object_destroy( p_vfilter );
1005                 }
1006             }
1007             p_vout->b_vfilter_change = VLC_FALSE;
1008             vlc_mutex_unlock( &p_vout->vfilter_lock );
1009         }
1010
1011         if( p_picture )
1012         {
1013             int i;
1014             for( i = 0; i < p_vout->i_vfilters; i++ )
1015             {
1016                 picture_t *p_old = p_picture;
1017                 p_picture  = p_vout->pp_vfilters[i]->pf_video_filter(
1018                                  p_vout->pp_vfilters[i], p_picture );
1019                 if( !p_picture )
1020                 {
1021                     break;
1022                 }
1023                 /* FIXME: this is kind of wrong
1024                  * if you have 2 or more vfilters and the 2nd breaks,
1025                  * on the next loop the 1st one will be applied again */
1026
1027                 /* if p_old and p_picture are the same (ie the filter
1028                  * worked on the old picture), then following code is
1029                  * still alright since i_status gets changed back to
1030                  * the right value */
1031                 if( p_old->i_refcount )
1032                 {
1033                     p_old->i_status = DISPLAYED_PICTURE;
1034                 }
1035                 else
1036                 {
1037                     p_old->i_status = DESTROYED_PICTURE;
1038                 }
1039                 p_picture->i_status = READY_PICTURE;
1040             }
1041         }
1042
1043         if( p_picture && p_vout->b_snapshot )
1044         {
1045             p_vout->b_snapshot = VLC_FALSE;
1046             vout_Snapshot( p_vout, p_picture );
1047         }
1048
1049         /*
1050          * Check for subpictures to display
1051          */
1052         if( display_date > 0 )
1053         {
1054             if( !p_input )
1055             {
1056                 p_input = vlc_object_find( p_vout, VLC_OBJECT_INPUT,
1057                                            FIND_PARENT );
1058             }
1059             p_subpic = spu_SortSubpictures( p_vout->p_spu, display_date,
1060             p_input ? var_GetBool( p_input, "state" ) == PAUSE_S : VLC_FALSE );
1061         }
1062
1063         /*
1064          * Perform rendering
1065          */
1066         i_displayed++;
1067         p_directbuffer = vout_RenderPicture( p_vout, p_picture, p_subpic );
1068
1069         /*
1070          * Call the plugin-specific rendering method if there is one
1071          */
1072         if( p_picture != NULL && p_directbuffer != NULL && p_vout->pf_render )
1073         {
1074             /* Render the direct buffer returned by vout_RenderPicture */
1075             p_vout->pf_render( p_vout, p_directbuffer );
1076         }
1077
1078         /*
1079          * Sleep, wake up
1080          */
1081         if( display_date != 0 && p_directbuffer != NULL )
1082         {
1083             mtime_t current_render_time = mdate() - current_date;
1084             /* if render time is very large we don't include it in the mean */
1085             if( current_render_time < p_vout->render_time +
1086                 VOUT_DISPLAY_DELAY )
1087             {
1088                 /* Store render time using a sliding mean weighting to
1089                  * current value in a 3 to 1 ratio*/
1090                 p_vout->render_time *= 3;
1091                 p_vout->render_time += current_render_time;
1092                 p_vout->render_time >>= 2;
1093             }
1094         }
1095
1096         /* Give back change lock */
1097         vlc_mutex_unlock( &p_vout->change_lock );
1098
1099         /* Sleep a while or until a given date */
1100         if( display_date != 0 )
1101         {
1102             /* If there are filters in the chain, better give them the picture
1103              * in advance */
1104             if( !p_vout->psz_filter_chain || !*p_vout->psz_filter_chain )
1105             {
1106                 mwait( display_date - VOUT_MWAIT_TOLERANCE );
1107             }
1108         }
1109         else
1110         {
1111             msleep( VOUT_IDLE_SLEEP );
1112         }
1113
1114         /* On awakening, take back lock and send immediately picture
1115          * to display. */
1116         vlc_mutex_lock( &p_vout->change_lock );
1117
1118         /*
1119          * Display the previously rendered picture
1120          */
1121         if( p_picture != NULL && p_directbuffer != NULL )
1122         {
1123             /* Display the direct buffer returned by vout_RenderPicture */
1124             if( p_vout->pf_display )
1125             {
1126                 p_vout->pf_display( p_vout, p_directbuffer );
1127             }
1128
1129             /* Tell the vout this was the last picture and that it does not
1130              * need to be forced anymore. */
1131             p_last_picture = p_picture;
1132             p_last_picture->b_force = 0;
1133         }
1134
1135         if( p_picture != NULL )
1136         {
1137             /* Reinitialize idle loop count */
1138             i_idle_loops = 0;
1139         }
1140
1141         /*
1142          * Check events and manage thread
1143          */
1144         if( p_vout->pf_manage && p_vout->pf_manage( p_vout ) )
1145         {
1146             /* A fatal error occurred, and the thread must terminate
1147              * immediately, without displaying anything - setting b_error to 1
1148              * causes the immediate end of the main while() loop. */
1149             p_vout->b_error = 1;
1150         }
1151
1152         if( p_vout->i_changes & VOUT_SIZE_CHANGE )
1153         {
1154             /* this must only happen when the vout plugin is incapable of
1155              * rescaling the picture itself. In this case we need to destroy
1156              * the current picture buffers and recreate new ones with the right
1157              * dimensions */
1158             int i;
1159
1160             p_vout->i_changes &= ~VOUT_SIZE_CHANGE;
1161
1162             p_vout->pf_end( p_vout );
1163             for( i = 0; i < I_OUTPUTPICTURES; i++ )
1164                  p_vout->p_picture[ i ].i_status = FREE_PICTURE;
1165
1166             I_OUTPUTPICTURES = 0;
1167             if( p_vout->pf_init( p_vout ) )
1168             {
1169                 msg_Err( p_vout, "cannot resize display" );
1170                 /* FIXME: pf_end will be called again in EndThread() */
1171                 p_vout->b_error = 1;
1172             }
1173
1174             /* Need to reinitialise the chroma plugin */
1175             if( p_vout->chroma.p_module )
1176             {
1177                 if( p_vout->chroma.p_module->pf_deactivate )
1178                     p_vout->chroma.p_module->pf_deactivate( VLC_OBJECT(p_vout) );
1179                 p_vout->chroma.p_module->pf_activate( VLC_OBJECT(p_vout) );
1180             }
1181         }
1182
1183         if( p_vout->i_changes & VOUT_PICTURE_BUFFERS_CHANGE )
1184         {
1185             /* This happens when the picture buffers need to be recreated.
1186              * This is useful on multimonitor displays for instance.
1187              *
1188              * Warning: This only works when the vout creates only 1 picture
1189              * buffer!! */
1190             p_vout->i_changes &= ~VOUT_PICTURE_BUFFERS_CHANGE;
1191
1192             if( !p_vout->b_direct )
1193             {
1194                 module_Unneed( p_vout, p_vout->chroma.p_module );
1195             }
1196
1197             vlc_mutex_lock( &p_vout->picture_lock );
1198
1199             p_vout->pf_end( p_vout );
1200
1201             I_OUTPUTPICTURES = I_RENDERPICTURES = 0;
1202
1203             p_vout->b_error = InitThread( p_vout );
1204
1205             vlc_mutex_unlock( &p_vout->picture_lock );
1206         }
1207     }
1208
1209     if( p_input )
1210     {
1211         vlc_object_release( p_input );
1212     }
1213
1214     /*
1215      * Error loop - wait until the thread destruction is requested
1216      */
1217     if( p_vout->b_error )
1218     {
1219         ErrorThread( p_vout );
1220     }
1221
1222     /* End of thread */
1223     EndThread( p_vout );
1224
1225     /* Destroy thread structures allocated by CreateThread */
1226     DestroyThread( p_vout );
1227 }
1228
1229 /*****************************************************************************
1230  * ErrorThread: RunThread() error loop
1231  *****************************************************************************
1232  * This function is called when an error occurred during thread main's loop.
1233  * The thread can still receive feed, but must be ready to terminate as soon
1234  * as possible.
1235  *****************************************************************************/
1236 static void ErrorThread( vout_thread_t *p_vout )
1237 {
1238     /* Wait until a `die' order */
1239     while( !p_vout->b_die )
1240     {
1241         /* Sleep a while */
1242         msleep( VOUT_IDLE_SLEEP );
1243     }
1244 }
1245
1246 /*****************************************************************************
1247  * EndThread: thread destruction
1248  *****************************************************************************
1249  * This function is called when the thread ends after a sucessful
1250  * initialization. It frees all resources allocated by InitThread.
1251  *****************************************************************************/
1252 static void EndThread( vout_thread_t *p_vout )
1253 {
1254     int     i_index;                                        /* index in heap */
1255
1256 #ifdef STATS
1257     {
1258         struct tms cpu_usage;
1259         times( &cpu_usage );
1260
1261         msg_Dbg( p_vout, "cpu usage (user: %d, system: %d)",
1262                  cpu_usage.tms_utime, cpu_usage.tms_stime );
1263     }
1264 #endif
1265
1266     if( !p_vout->b_direct )
1267     {
1268         module_Unneed( p_vout, p_vout->chroma.p_module );
1269     }
1270
1271     /* Destroy all remaining pictures */
1272     for( i_index = 0; i_index < 2 * VOUT_MAX_PICTURES + 1; i_index++ )
1273     {
1274         if ( p_vout->p_picture[i_index].i_type == MEMORY_PICTURE )
1275         {
1276             free( p_vout->p_picture[i_index].p_data_orig );
1277         }
1278     }
1279
1280     /* Destroy subpicture unit */
1281     spu_Attach( p_vout->p_spu, VLC_OBJECT(p_vout), VLC_FALSE );
1282     spu_Destroy( p_vout->p_spu );
1283
1284     /* Destroy the video filters2 */
1285     RemoveVideoFilters2( p_vout );
1286
1287     /* Destroy translation tables */
1288     p_vout->pf_end( p_vout );
1289
1290     /* Release the change lock */
1291     vlc_mutex_unlock( &p_vout->change_lock );
1292 }
1293
1294 /*****************************************************************************
1295  * DestroyThread: thread destruction
1296  *****************************************************************************
1297  * This function is called when the thread ends. It frees all ressources
1298  * allocated by CreateThread. Status is available at this stage.
1299  *****************************************************************************/
1300 static void DestroyThread( vout_thread_t *p_vout )
1301 {
1302     /* Destroy the locks */
1303     vlc_mutex_destroy( &p_vout->picture_lock );
1304     vlc_mutex_destroy( &p_vout->change_lock );
1305     vlc_mutex_destroy( &p_vout->vfilter_lock );
1306
1307     /* Release the module */
1308     if( p_vout && p_vout->p_module )
1309     {
1310         module_Unneed( p_vout, p_vout->p_module );
1311     }
1312 }
1313
1314 /* following functions are local */
1315
1316 static int ReduceHeight( int i_ratio )
1317 {
1318     int i_dummy = VOUT_ASPECT_FACTOR;
1319     int i_pgcd  = 1;
1320
1321     if( !i_ratio )
1322     {
1323         return i_pgcd;
1324     }
1325
1326     /* VOUT_ASPECT_FACTOR is (2^7 * 3^3 * 5^3), we just check for 2, 3 and 5 */
1327     while( !(i_ratio & 1) && !(i_dummy & 1) )
1328     {
1329         i_ratio >>= 1;
1330         i_dummy >>= 1;
1331         i_pgcd  <<= 1;
1332     }
1333
1334     while( !(i_ratio % 3) && !(i_dummy % 3) )
1335     {
1336         i_ratio /= 3;
1337         i_dummy /= 3;
1338         i_pgcd  *= 3;
1339     }
1340
1341     while( !(i_ratio % 5) && !(i_dummy % 5) )
1342     {
1343         i_ratio /= 5;
1344         i_dummy /= 5;
1345         i_pgcd  *= 5;
1346     }
1347
1348     return i_pgcd;
1349 }
1350
1351 static void AspectRatio( int i_aspect, int *i_aspect_x, int *i_aspect_y )
1352 {
1353     unsigned int i_pgcd = ReduceHeight( i_aspect );
1354     *i_aspect_x = i_aspect / i_pgcd;
1355     *i_aspect_y = VOUT_ASPECT_FACTOR / i_pgcd;
1356 }
1357
1358 /*****************************************************************************
1359  * BinaryLog: computes the base 2 log of a binary value
1360  *****************************************************************************
1361  * This functions is used by MaskToShift, to get a bit index from a binary
1362  * value.
1363  *****************************************************************************/
1364 static int BinaryLog( uint32_t i )
1365 {
1366     int i_log = 0;
1367
1368     if( i == 0 ) return -31337;
1369
1370     if( i & 0xffff0000 ) i_log += 16;
1371     if( i & 0xff00ff00 ) i_log += 8;
1372     if( i & 0xf0f0f0f0 ) i_log += 4;
1373     if( i & 0xcccccccc ) i_log += 2;
1374     if( i & 0xaaaaaaaa ) i_log += 1;
1375
1376     return i_log;
1377 }
1378
1379 /*****************************************************************************
1380  * MaskToShift: transform a color mask into right and left shifts
1381  *****************************************************************************
1382  * This function is used for obtaining color shifts from masks.
1383  *****************************************************************************/
1384 static void MaskToShift( int *pi_left, int *pi_right, uint32_t i_mask )
1385 {
1386     uint32_t i_low, i_high;            /* lower hand higher bits of the mask */
1387
1388     if( !i_mask )
1389     {
1390         *pi_left = *pi_right = 0;
1391         return;
1392     }
1393
1394     /* Get bits */
1395     i_low = i_high = i_mask;
1396
1397     i_low &= - (int32_t)i_low;          /* lower bit of the mask */
1398     i_high += i_low;                    /* higher bit of the mask */
1399
1400     /* Transform bits into an index. Also deal with i_high overflow, which
1401      * is faster than changing the BinaryLog code to handle 64 bit integers. */
1402     i_low =  BinaryLog (i_low);
1403     i_high = i_high ? BinaryLog (i_high) : 32;
1404
1405     /* Update pointers and return */
1406     *pi_left =   i_low;
1407     *pi_right = (8 - i_high + i_low);
1408 }
1409
1410 /*****************************************************************************
1411  * vout_VarCallback: generic callback for intf variables
1412  *****************************************************************************/
1413 int vout_VarCallback( vlc_object_t * p_this, const char * psz_variable,
1414                       vlc_value_t oldval, vlc_value_t newval,
1415                       void *p_data )
1416 {
1417     vout_thread_t * p_vout = (vout_thread_t *)p_this;
1418     vlc_value_t val;
1419     (void)psz_variable; (void)newval; (void)oldval; (void)p_data;
1420     val.b_bool = VLC_TRUE;
1421     var_Set( p_vout, "intf-change", val );
1422     return VLC_SUCCESS;
1423 }
1424
1425 /*****************************************************************************
1426  * Helper thread for object variables callbacks.
1427  * Only used to avoid deadlocks when using the video embedded mode.
1428  *****************************************************************************/
1429 typedef struct suxor_thread_t
1430 {
1431     VLC_COMMON_MEMBERS
1432     input_thread_t *p_input;
1433
1434 } suxor_thread_t;
1435
1436 static void SuxorRestartVideoES( suxor_thread_t *p_this )
1437 {
1438     vlc_value_t val;
1439
1440     vlc_thread_ready( p_this );
1441
1442     /* Now restart current video stream */
1443     var_Get( p_this->p_input, "video-es", &val );
1444     if( val.i_int >= 0 )
1445     {
1446         vlc_value_t val_es;
1447         val_es.i_int = -VIDEO_ES;
1448         var_Set( p_this->p_input, "video-es", val_es );
1449         var_Set( p_this->p_input, "video-es", val );
1450     }
1451
1452     vlc_object_release( p_this->p_input );
1453
1454     vlc_object_destroy( p_this );
1455 }
1456
1457 /*****************************************************************************
1458  * object variables callbacks: a bunch of object variables are used by the
1459  * interfaces to interact with the vout.
1460  *****************************************************************************/
1461 static int DeinterlaceCallback( vlc_object_t *p_this, char const *psz_cmd,
1462                        vlc_value_t oldval, vlc_value_t newval, void *p_data )
1463 {
1464     vout_thread_t *p_vout = (vout_thread_t *)p_this;
1465     input_thread_t *p_input;
1466     vlc_value_t val;
1467
1468     char *psz_mode = newval.psz_string;
1469     char *psz_filter, *psz_deinterlace = NULL;
1470     (void)psz_cmd; (void)oldval; (void)p_data;
1471
1472     var_Get( p_vout, "vout-filter", &val );
1473     psz_filter = val.psz_string;
1474     if( psz_filter ) psz_deinterlace = strstr( psz_filter, "deinterlace" );
1475
1476     if( !psz_mode || !*psz_mode )
1477     {
1478         if( psz_deinterlace )
1479         {
1480             char *psz_src = psz_deinterlace + sizeof("deinterlace") - 1;
1481             if( psz_src[0] == ':' ) psz_src++;
1482             memmove( psz_deinterlace, psz_src, strlen(psz_src) + 1 );
1483         }
1484     }
1485     else if( !psz_deinterlace )
1486     {
1487         psz_filter = realloc( psz_filter, strlen( psz_filter ) +
1488                               sizeof(":deinterlace") );
1489         if( psz_filter && *psz_filter ) strcat( psz_filter, ":" );
1490         strcat( psz_filter, "deinterlace" );
1491     }
1492
1493     p_input = (input_thread_t *)vlc_object_find( p_this, VLC_OBJECT_INPUT,
1494                                                  FIND_PARENT );
1495     if( !p_input ) return VLC_EGENERIC;
1496
1497     if( psz_mode && *psz_mode )
1498     {
1499         /* Modify input as well because the vout might have to be restarted */
1500         val.psz_string = psz_mode;
1501         var_Create( p_input, "deinterlace-mode", VLC_VAR_STRING );
1502         var_Set( p_input, "deinterlace-mode", val );
1503     }
1504     vlc_object_release( p_input );
1505
1506     val.b_bool = VLC_TRUE;
1507     var_Set( p_vout, "intf-change", val );
1508
1509     val.psz_string = psz_filter;
1510     var_Set( p_vout, "vout-filter", val );
1511     if( psz_filter ) free( psz_filter );
1512
1513     return VLC_SUCCESS;
1514 }
1515
1516 static int FilterCallback( vlc_object_t *p_this, char const *psz_cmd,
1517                        vlc_value_t oldval, vlc_value_t newval, void *p_data )
1518 {
1519     vout_thread_t *p_vout = (vout_thread_t *)p_this;
1520     input_thread_t *p_input;
1521     vlc_value_t val;
1522     (void)psz_cmd; (void)oldval; (void)p_data;
1523
1524     p_input = (input_thread_t *)vlc_object_find( p_this, VLC_OBJECT_INPUT,
1525                                                  FIND_PARENT );
1526     if (!p_input)
1527     {
1528         msg_Err( p_vout, "Input not found" );
1529         return( VLC_EGENERIC );
1530     }
1531
1532     val.b_bool = VLC_TRUE;
1533     var_Set( p_vout, "intf-change", val );
1534
1535     /* Modify input as well because the vout might have to be restarted */
1536     val.psz_string = newval.psz_string;
1537     var_Create( p_input, "vout-filter", VLC_VAR_STRING );
1538
1539     var_Set( p_input, "vout-filter", val );
1540
1541     /* Now restart current video stream */
1542     var_Get( p_input, "video-es", &val );
1543     if( val.i_int >= 0 )
1544     {
1545         suxor_thread_t *p_suxor =
1546             vlc_object_create( p_vout, sizeof(suxor_thread_t) );
1547         p_suxor->p_input = p_input;
1548         p_vout->b_filter_change = VLC_TRUE;
1549         vlc_object_yield( p_input );
1550         vlc_thread_create( p_suxor, "suxor", SuxorRestartVideoES,
1551                            VLC_THREAD_PRIORITY_LOW, VLC_FALSE );
1552     }
1553
1554     vlc_object_release( p_input );
1555
1556     return VLC_SUCCESS;
1557 }
1558
1559 /*****************************************************************************
1560  * Video Filter2 stuff
1561  *****************************************************************************/
1562 static int ParseVideoFilter2Chain( vout_thread_t *p_vout, char *psz_vfilters )
1563 {
1564     int i;
1565     for( i = 0; i < p_vout->i_vfilters_cfg; i++ )
1566     {
1567         struct config_chain_t *p_cfg =
1568             p_vout->p_vfilters_cfg[p_vout->i_vfilters_cfg];
1569         config_ChainDestroy( p_cfg );
1570         if( p_vout->psz_vfilters[p_vout->i_vfilters_cfg] )
1571         {
1572             free( p_vout->psz_vfilters[p_vout->i_vfilters_cfg] );
1573             p_vout->psz_vfilters[p_vout->i_vfilters_cfg] = NULL;
1574         }
1575     }
1576     p_vout->i_vfilters_cfg = 0;
1577     if( psz_vfilters && *psz_vfilters )
1578     {
1579         char *psz_parser = psz_vfilters;
1580
1581         while( psz_parser && *psz_parser )
1582         {
1583             psz_parser = config_ChainCreate(
1584                             &p_vout->psz_vfilters[p_vout->i_vfilters_cfg],
1585                             &p_vout->p_vfilters_cfg[p_vout->i_vfilters_cfg],
1586                             psz_parser );
1587             msg_Dbg( p_vout, "adding vfilter: %s",
1588                      p_vout->psz_vfilters[p_vout->i_vfilters_cfg] );
1589             p_vout->i_vfilters_cfg++;
1590             if( psz_parser && *psz_parser )
1591             {
1592                 if( p_vout->i_vfilters_cfg == MAX_VFILTERS )
1593                 {
1594                     msg_Warn( p_vout,
1595                   "maximum number of video filters reached. \"%s\" discarded",
1596                               psz_parser );
1597                     break;
1598                 }
1599             }
1600         }
1601     }
1602     return VLC_SUCCESS;
1603 }
1604
1605 static int VideoFilter2Callback( vlc_object_t *p_this, char const *psz_cmd,
1606                        vlc_value_t oldval, vlc_value_t newval, void *p_data )
1607 {
1608     vout_thread_t *p_vout = (vout_thread_t *)p_this;
1609     (void)psz_cmd; (void)oldval; (void)p_data;
1610
1611     vlc_mutex_lock( &p_vout->vfilter_lock );
1612     ParseVideoFilter2Chain( p_vout, newval.psz_string );
1613     p_vout->b_vfilter_change = VLC_TRUE;
1614     vlc_mutex_unlock( &p_vout->vfilter_lock );
1615
1616     return VLC_SUCCESS;
1617 }
1618
1619 static void RemoveVideoFilters2( vout_thread_t *p_vout )
1620 {
1621     int i;
1622     for( i = 0; i < p_vout->i_vfilters; i++ )
1623     {
1624         vlc_object_detach( p_vout->pp_vfilters[i] );
1625         if( p_vout->pp_vfilters[i]->p_module )
1626         {
1627             module_Unneed( p_vout->pp_vfilters[i],
1628                            p_vout->pp_vfilters[i]->p_module );
1629         }
1630
1631         free( p_vout->pp_vfilters[i]->p_owner );
1632         vlc_object_destroy( p_vout->pp_vfilters[i] );
1633     }
1634     p_vout->i_vfilters = 0;
1635 }
1636
1637 static void DisplayTitleOnOSD( vout_thread_t *p_vout )
1638 {
1639     input_thread_t *p_input;
1640     mtime_t i_now, i_stop;
1641
1642     p_input = (input_thread_t *)vlc_object_find( p_vout,
1643               VLC_OBJECT_INPUT, FIND_ANYWHERE );
1644     if( p_input )
1645     {
1646         i_now = mdate();
1647         i_stop = i_now + (mtime_t)(p_vout->i_title_timeout * 1000);
1648         char *psz_nowplaying =
1649             input_item_GetNowPlaying( input_GetItem( p_input ) );
1650         char *psz_artist = input_item_GetArtist( input_GetItem( p_input ) );
1651         char *psz_name = input_item_GetTitle( input_GetItem( p_input ) );
1652         if( EMPTY_STR( psz_name ) )
1653         {
1654             free( psz_name );
1655             psz_name = input_item_GetName( input_GetItem( p_input ) );
1656         }
1657         if( !EMPTY_STR( psz_nowplaying ) )
1658         {
1659             vout_ShowTextAbsolute( p_vout, DEFAULT_CHAN,
1660                                    psz_nowplaying, NULL,
1661                                    p_vout->i_title_position,
1662                                    30 + p_vout->fmt_in.i_width
1663                                       - p_vout->fmt_in.i_visible_width
1664                                       - p_vout->fmt_in.i_x_offset,
1665                                    20 + p_vout->fmt_in.i_y_offset,
1666                                    i_now, i_stop );
1667         }
1668         else if( !EMPTY_STR( psz_artist ) )
1669         {
1670             char *psz_string = NULL;
1671             if( asprintf( &psz_string, "%s - %s", psz_name, psz_artist ) != -1 )
1672             {
1673                 vout_ShowTextAbsolute( p_vout, DEFAULT_CHAN,
1674                                        psz_string, NULL,
1675                                        p_vout->i_title_position,
1676                                        30 + p_vout->fmt_in.i_width
1677                                           - p_vout->fmt_in.i_visible_width
1678                                           - p_vout->fmt_in.i_x_offset,
1679                                        20 + p_vout->fmt_in.i_y_offset,
1680                                        i_now, i_stop );
1681                 free( psz_string );
1682             }
1683         }
1684         else
1685         {
1686             vout_ShowTextAbsolute( p_vout, DEFAULT_CHAN,
1687                                    psz_name, NULL,
1688                                    p_vout->i_title_position,
1689                                    30 + p_vout->fmt_in.i_width
1690                                       - p_vout->fmt_in.i_visible_width
1691                                       - p_vout->fmt_in.i_x_offset,
1692                                    20 + p_vout->fmt_in.i_y_offset,
1693                                    i_now, i_stop );
1694         }
1695         vlc_object_release( p_input );
1696         free( psz_artist );
1697         free( psz_name );
1698         free( psz_nowplaying );
1699     }
1700 }
1701