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