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