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