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