1 /*****************************************************************************
2 * video_output.c : video output thread
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
11 * Authors: Vincent Seguin <seguin@via.ecp.fr>
12 * Gildas Bazin <gbazin@videolan.org>
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.
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.
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 *****************************************************************************/
29 /*****************************************************************************
31 *****************************************************************************/
34 #include <stdlib.h> /* free() */
38 #ifdef HAVE_SYS_TIMES_H
39 # include <sys/times.h>
43 #include <vlc_playlist.h>
45 #include <vlc_filter.h>
48 #if defined( __APPLE__ )
49 /* Include darwin_specific.h here if needed */
52 /** FIXME This is quite ugly but needed while we don't have counters
54 #include "input/input_internal.h"
56 /*****************************************************************************
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 * );
65 static void AspectRatio ( int, int *, int * );
66 static int BinaryLog ( uint32_t );
67 static void MaskToShift ( int *, int *, uint32_t );
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 * );
77 /* From vout_intf.c */
78 int vout_Snapshot( vout_thread_t *, picture_t * );
80 /* Video filter2 parsing */
81 static int ParseVideoFilter2Chain( vout_thread_t *, char * );
82 static void RemoveVideoFilters2( vout_thread_t *p_vout );
84 /*****************************************************************************
85 * Video Filter2 functions
86 *****************************************************************************/
87 struct filter_owner_sys_t
89 vout_thread_t *p_vout;
92 static picture_t *video_new_buffer_filter( filter_t *p_filter )
95 vout_thread_t *p_vout = p_filter->p_owner->p_vout;
97 p_picture = vout_CreatePicture( p_vout, 0, 0, 0 );
102 static void video_del_buffer_filter( filter_t *p_filter, picture_t *p_pic )
104 vout_DestroyPicture( p_filter->p_owner->p_vout, p_pic );
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 )
118 /* Reattach video output to playlist before bailing out */
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 );
130 /* If a video output was provided, lock it, otherwise look for one. */
133 vlc_object_yield( p_vout );
137 p_vout = vlc_object_find( p_this, VLC_OBJECT_VOUT, FIND_CHILD );
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 )
148 vlc_object_release( p_vout );
152 vlc_object_detach( p_vout ); /* Remove it from the GC */
153 vlc_mutex_unlock( &p_playlist->gc_lock );
154 pl_Release( p_this );
158 /* If we now have a video output, check it has the right properties */
161 char *psz_filter_chain;
164 /* We don't directly check for the "vout-filter" variable for obvious
165 * performance reasons. */
166 if( p_vout->b_filter_change )
168 var_Get( p_vout, "vout-filter", &val );
169 psz_filter_chain = val.psz_string;
171 if( psz_filter_chain && !*psz_filter_chain )
173 free( psz_filter_chain );
174 psz_filter_chain = NULL;
176 if( p_vout->psz_filter_chain && !*p_vout->psz_filter_chain )
178 free( p_vout->psz_filter_chain );
179 p_vout->psz_filter_chain = NULL;
182 if( !psz_filter_chain && !p_vout->psz_filter_chain )
184 p_vout->b_filter_change = VLC_FALSE;
187 if( psz_filter_chain ) free( psz_filter_chain );
190 if( ( p_vout->fmt_render.i_width != p_fmt->i_width ) ||
191 ( p_vout->fmt_render.i_height != p_fmt->i_height ) ||
192 ( p_vout->fmt_render.i_chroma != p_fmt->i_chroma ) ||
193 ( p_vout->fmt_render.i_aspect != p_fmt->i_aspect ) ||
194 p_vout->b_filter_change )
196 /* We are not interested in this format, close this vout */
197 vlc_object_release( p_vout );
198 vout_Destroy( p_vout );
203 /* This video output is cool! Hijack it. */
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 );
212 msg_Dbg( p_this, "no usable vout present, spawning one" );
214 p_vout = vout_Create( p_this, p_fmt );
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 )
228 vout_thread_t * p_vout; /* thread descriptor */
229 input_thread_t * p_input_thread;
230 int i_index; /* loop variable */
231 vlc_value_t val, text;
233 unsigned int i_width = p_fmt->i_width;
234 unsigned int i_height = p_fmt->i_height;
235 vlc_fourcc_t i_chroma = p_fmt->i_chroma;
236 unsigned int i_aspect = p_fmt->i_aspect;
238 config_chain_t *p_cfg;
242 /* Allocate descriptor */
243 p_vout = vlc_object_create( p_parent, VLC_OBJECT_VOUT );
246 msg_Err( p_parent, "out of memory" );
250 /* Initialize pictures - translation tables and functions
251 * will be initialized later in InitThread */
252 for( i_index = 0; i_index < 2 * VOUT_MAX_PICTURES + 1; i_index++)
254 p_vout->p_picture[i_index].pf_lock = NULL;
255 p_vout->p_picture[i_index].pf_unlock = NULL;
256 p_vout->p_picture[i_index].i_status = FREE_PICTURE;
257 p_vout->p_picture[i_index].i_type = EMPTY_PICTURE;
258 p_vout->p_picture[i_index].b_slow = 0;
261 /* No images in the heap */
262 p_vout->i_heap_size = 0;
264 /* Initialize the rendering heap */
265 I_RENDERPICTURES = 0;
267 vlc_ureduce( &p_fmt->i_sar_num, &p_fmt->i_sar_den,
268 p_fmt->i_sar_num, p_fmt->i_sar_den, 50000 );
269 p_vout->fmt_render = *p_fmt; /* FIXME palette */
270 p_vout->fmt_in = *p_fmt; /* FIXME palette */
272 p_vout->render.i_width = i_width;
273 p_vout->render.i_height = i_height;
274 p_vout->render.i_chroma = i_chroma;
275 p_vout->render.i_aspect = i_aspect;
277 p_vout->render.i_rmask = 0;
278 p_vout->render.i_gmask = 0;
279 p_vout->render.i_bmask = 0;
281 p_vout->render.i_last_used_pic = -1;
282 p_vout->render.b_allow_modify_pics = 1;
284 /* Zero the output heap */
285 I_OUTPUTPICTURES = 0;
286 p_vout->output.i_width = 0;
287 p_vout->output.i_height = 0;
288 p_vout->output.i_chroma = 0;
289 p_vout->output.i_aspect = 0;
291 p_vout->output.i_rmask = 0;
292 p_vout->output.i_gmask = 0;
293 p_vout->output.i_bmask = 0;
295 /* Initialize misc stuff */
296 p_vout->i_changes = 0;
298 p_vout->b_grayscale = 0;
300 p_vout->b_interface = 0;
302 p_vout->b_fullscreen = 0;
303 p_vout->i_alignment = 0;
304 p_vout->render_time = 10;
305 p_vout->c_fps_samples = 0;
306 p_vout->b_filter_change = 0;
307 p_vout->pf_control = 0;
308 p_vout->p_parent_intf = 0;
309 p_vout->i_par_num = p_vout->i_par_den = 1;
311 /* Initialize locks */
312 vlc_mutex_init( p_vout, &p_vout->picture_lock );
313 vlc_mutex_init( p_vout, &p_vout->change_lock );
314 vlc_mutex_init( p_vout, &p_vout->vfilter_lock );
316 /* Mouse coordinates */
317 var_Create( p_vout, "mouse-x", VLC_VAR_INTEGER );
318 var_Create( p_vout, "mouse-y", VLC_VAR_INTEGER );
319 var_Create( p_vout, "mouse-button-down", VLC_VAR_INTEGER );
320 var_Create( p_vout, "mouse-moved", VLC_VAR_BOOL );
321 var_Create( p_vout, "mouse-clicked", VLC_VAR_INTEGER );
323 /* Initialize subpicture unit */
324 p_vout->p_spu = spu_Create( p_vout );
325 spu_Attach( p_vout->p_spu, p_parent, VLC_TRUE );
327 /* Attach the new object now so we can use var inheritance below */
328 vlc_object_attach( p_vout, p_parent );
330 spu_Init( p_vout->p_spu );
332 /* Take care of some "interface/control" related initialisations */
333 vout_IntfInit( p_vout );
335 /* If the parent is not a VOUT object, that means we are at the start of
336 * the video output pipe */
337 if( p_parent->i_object_type != VLC_OBJECT_VOUT )
339 /* Look for the default filter configuration */
340 var_Create( p_vout, "vout-filter", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
341 var_Get( p_vout, "vout-filter", &val );
342 p_vout->psz_filter_chain = val.psz_string;
344 /* Apply video filter2 objects on the first vout */
345 var_Create( p_vout, "video-filter",
346 VLC_VAR_STRING | VLC_VAR_DOINHERIT );
347 var_Get( p_vout, "video-filter", &val );
348 ParseVideoFilter2Chain( p_vout, val.psz_string );
349 free( val.psz_string );
353 /* continue the parent's filter chain */
356 /* Ugly hack to jump to our configuration chain */
357 p_vout->psz_filter_chain
358 = ((vout_thread_t *)p_parent)->psz_filter_chain;
359 p_vout->psz_filter_chain
360 = config_ChainCreate( &psz_tmp, &p_cfg, p_vout->psz_filter_chain );
361 config_ChainDestroy( p_cfg );
364 /* Create a video filter2 var ... but don't inherit values */
365 var_Create( p_vout, "video-filter", VLC_VAR_STRING );
366 ParseVideoFilter2Chain( p_vout, NULL );
369 var_AddCallback( p_vout, "video-filter", VideoFilter2Callback, NULL );
370 p_vout->b_vfilter_change = VLC_TRUE;
371 p_vout->i_vfilters = 0;
373 /* Choose the video output module */
374 if( !p_vout->psz_filter_chain || !*p_vout->psz_filter_chain )
376 var_Create( p_vout, "vout", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
377 var_Get( p_vout, "vout", &val );
378 psz_parser = val.psz_string;
382 psz_parser = strdup( p_vout->psz_filter_chain );
385 /* Create the vout thread */
386 config_ChainCreate( &psz_name, &p_cfg, psz_parser );
388 p_vout->p_cfg = p_cfg;
389 p_vout->p_module = module_Need( p_vout,
390 ( p_vout->psz_filter_chain && *p_vout->psz_filter_chain ) ?
391 "video filter" : "video output", psz_name, 0 );
394 if( p_vout->p_module == NULL )
396 msg_Err( p_vout, "no suitable vout module" );
397 vlc_object_detach( p_vout );
398 vlc_object_destroy( p_vout );
402 /* Create a few object variables for interface interaction */
403 var_Create( p_vout, "deinterlace", VLC_VAR_STRING | VLC_VAR_HASCHOICE );
404 text.psz_string = _("Deinterlace");
405 var_Change( p_vout, "deinterlace", VLC_VAR_SETTEXT, &text, NULL );
406 val.psz_string = (char *)""; text.psz_string = _("Disable");
407 var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text );
408 val.psz_string = (char *)"discard"; text.psz_string = _("Discard");
409 var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text );
410 val.psz_string = (char *)"blend"; text.psz_string = _("Blend");
411 var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text );
412 val.psz_string = (char *)"mean"; text.psz_string = _("Mean");
413 var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text );
414 val.psz_string = (char *)"bob"; text.psz_string = _("Bob");
415 var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text );
416 val.psz_string = (char *)"linear"; text.psz_string = _("Linear");
417 var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text );
418 val.psz_string = (char *)"x"; text.psz_string = (char *)"X";
419 var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text );
421 if( var_Get( p_vout, "deinterlace-mode", &val ) == VLC_SUCCESS )
423 var_Set( p_vout, "deinterlace", val );
424 if( val.psz_string ) free( val.psz_string );
426 var_AddCallback( p_vout, "deinterlace", DeinterlaceCallback, NULL );
429 var_Create( p_vout, "vout-filter", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
430 text.psz_string = _("Filters");
431 var_Change( p_vout, "vout-filter", VLC_VAR_SETTEXT, &text, NULL );
432 var_AddCallback( p_vout, "vout-filter", FilterCallback, NULL );
434 /* Calculate delay created by internal caching */
435 p_input_thread = (input_thread_t *)vlc_object_find( p_vout,
436 VLC_OBJECT_INPUT, FIND_ANYWHERE );
439 p_vout->i_pts_delay = p_input_thread->i_pts_delay;
440 vlc_object_release( p_input_thread );
444 p_vout->i_pts_delay = DEFAULT_PTS_DELAY;
447 if( vlc_thread_create( p_vout, "video output", RunThread,
448 VLC_THREAD_PRIORITY_OUTPUT, VLC_TRUE ) )
450 msg_Err( p_vout, "out of memory" );
451 module_Unneed( p_vout, p_vout->p_module );
452 vlc_object_detach( p_vout );
453 vlc_object_destroy( p_vout );
457 if( p_vout->b_error )
459 msg_Err( p_vout, "video output creation failed" );
461 /* Make sure the thread is destroyed */
462 p_vout->b_die = VLC_TRUE;
464 vlc_thread_join( p_vout );
466 vlc_object_detach( p_vout );
467 vlc_object_destroy( p_vout );
474 /*****************************************************************************
475 * vout_Destroy: destroys a previously created video output
476 *****************************************************************************
477 * Destroy a terminated thread.
478 * The function will request a destruction of the specified thread. If pi_error
479 * is NULL, it will return once the thread is destroyed. Else, it will be
480 * update using one of the THREAD_* constants.
481 *****************************************************************************/
482 void vout_Destroy( vout_thread_t *p_vout )
484 vout_thread_t *p_another_vout;
485 playlist_t *p_playlist = pl_Yield( p_vout );
487 /* Request thread destruction */
488 p_vout->b_die = VLC_TRUE;
489 vlc_thread_join( p_vout );
491 var_Destroy( p_vout, "intf-change" );
493 if( p_vout->psz_filter_chain ) free( p_vout->psz_filter_chain );
495 config_ChainDestroy( p_vout->p_cfg );
498 vlc_object_destroy( p_vout );
500 /* This is a dirty hack for mostly Linux, where there is no way to get the GUI
501 back if you closed it while playing video. This is solved in Mac OS X,
502 where we have this novelty called menubar, that will always allow you access
503 to the applications main functionality. They should try that on linux sometime */
504 p_another_vout = vlc_object_find( p_playlist,
505 VLC_OBJECT_VOUT, FIND_ANYWHERE );
506 if( p_another_vout == NULL )
509 val.b_bool = VLC_TRUE;
510 var_Set( p_playlist, "intf-show", val );
514 vlc_object_release( p_another_vout );
517 vlc_object_release( p_playlist );
520 /*****************************************************************************
521 * InitThread: initialize video output thread
522 *****************************************************************************
523 * This function is called from RunThread and performs the second step of the
524 * initialization. It returns 0 on success. Note that the thread's flag are not
525 * modified inside this function.
526 *****************************************************************************/
527 static int InitThread( vout_thread_t *p_vout )
529 int i, i_aspect_x, i_aspect_y;
531 vlc_mutex_lock( &p_vout->change_lock );
537 /* Initialize output method, it allocates direct buffers for us */
538 if( p_vout->pf_init( p_vout ) )
540 vlc_mutex_unlock( &p_vout->change_lock );
544 if( !I_OUTPUTPICTURES )
546 msg_Err( p_vout, "plugin was unable to allocate at least "
547 "one direct buffer" );
548 p_vout->pf_end( p_vout );
549 vlc_mutex_unlock( &p_vout->change_lock );
553 if( I_OUTPUTPICTURES > VOUT_MAX_PICTURES )
555 msg_Err( p_vout, "plugin allocated too many direct buffers, "
556 "our internal buffers must have overflown." );
557 p_vout->pf_end( p_vout );
558 vlc_mutex_unlock( &p_vout->change_lock );
562 msg_Dbg( p_vout, "got %i direct buffer(s)", I_OUTPUTPICTURES );
564 AspectRatio( p_vout->fmt_render.i_aspect, &i_aspect_x, &i_aspect_y );
566 msg_Dbg( p_vout, "picture in %ix%i (%i,%i,%ix%i), "
567 "chroma %4.4s, ar %i:%i, sar %i:%i",
568 p_vout->fmt_render.i_width, p_vout->fmt_render.i_height,
569 p_vout->fmt_render.i_x_offset, p_vout->fmt_render.i_y_offset,
570 p_vout->fmt_render.i_visible_width,
571 p_vout->fmt_render.i_visible_height,
572 (char*)&p_vout->fmt_render.i_chroma,
573 i_aspect_x, i_aspect_y,
574 p_vout->fmt_render.i_sar_num, p_vout->fmt_render.i_sar_den );
576 AspectRatio( p_vout->fmt_in.i_aspect, &i_aspect_x, &i_aspect_y );
578 msg_Dbg( p_vout, "picture user %ix%i (%i,%i,%ix%i), "
579 "chroma %4.4s, ar %i:%i, sar %i:%i",
580 p_vout->fmt_in.i_width, p_vout->fmt_in.i_height,
581 p_vout->fmt_in.i_x_offset, p_vout->fmt_in.i_y_offset,
582 p_vout->fmt_in.i_visible_width,
583 p_vout->fmt_in.i_visible_height,
584 (char*)&p_vout->fmt_in.i_chroma,
585 i_aspect_x, i_aspect_y,
586 p_vout->fmt_in.i_sar_num, p_vout->fmt_in.i_sar_den );
588 if( !p_vout->fmt_out.i_width || !p_vout->fmt_out.i_height )
590 p_vout->fmt_out.i_width = p_vout->fmt_out.i_visible_width =
591 p_vout->output.i_width;
592 p_vout->fmt_out.i_height = p_vout->fmt_out.i_visible_height =
593 p_vout->output.i_height;
594 p_vout->fmt_out.i_x_offset = p_vout->fmt_out.i_y_offset = 0;
596 p_vout->fmt_out.i_aspect = p_vout->output.i_aspect;
597 p_vout->fmt_out.i_chroma = p_vout->output.i_chroma;
599 if( !p_vout->fmt_out.i_sar_num || !p_vout->fmt_out.i_sar_num )
601 p_vout->fmt_out.i_sar_num = p_vout->fmt_out.i_aspect *
602 p_vout->fmt_out.i_height;
603 p_vout->fmt_out.i_sar_den = VOUT_ASPECT_FACTOR *
604 p_vout->fmt_out.i_width;
607 vlc_ureduce( &p_vout->fmt_out.i_sar_num, &p_vout->fmt_out.i_sar_den,
608 p_vout->fmt_out.i_sar_num, p_vout->fmt_out.i_sar_den, 0 );
610 AspectRatio( p_vout->fmt_out.i_aspect, &i_aspect_x, &i_aspect_y );
612 msg_Dbg( p_vout, "picture out %ix%i (%i,%i,%ix%i), "
613 "chroma %4.4s, ar %i:%i, sar %i:%i",
614 p_vout->fmt_out.i_width, p_vout->fmt_out.i_height,
615 p_vout->fmt_out.i_x_offset, p_vout->fmt_out.i_y_offset,
616 p_vout->fmt_out.i_visible_width,
617 p_vout->fmt_out.i_visible_height,
618 (char*)&p_vout->fmt_out.i_chroma,
619 i_aspect_x, i_aspect_y,
620 p_vout->fmt_out.i_sar_num, p_vout->fmt_out.i_sar_den );
622 /* Calculate shifts from system-updated masks */
623 MaskToShift( &p_vout->output.i_lrshift, &p_vout->output.i_rrshift,
624 p_vout->output.i_rmask );
625 MaskToShift( &p_vout->output.i_lgshift, &p_vout->output.i_rgshift,
626 p_vout->output.i_gmask );
627 MaskToShift( &p_vout->output.i_lbshift, &p_vout->output.i_rbshift,
628 p_vout->output.i_bmask );
630 /* Check whether we managed to create direct buffers similar to
631 * the render buffers, ie same size and chroma */
632 if( ( p_vout->output.i_width == p_vout->render.i_width )
633 && ( p_vout->output.i_height == p_vout->render.i_height )
634 && ( vout_ChromaCmp( p_vout->output.i_chroma, p_vout->render.i_chroma ) ) )
636 /* Cool ! We have direct buffers, we can ask the decoder to
637 * directly decode into them ! Map the first render buffers to
638 * the first direct buffers, but keep the first direct buffer
639 * for memcpy operations */
640 p_vout->b_direct = 1;
642 for( i = 1; i < VOUT_MAX_PICTURES; i++ )
644 if( p_vout->p_picture[ i ].i_type != DIRECT_PICTURE &&
645 I_RENDERPICTURES >= VOUT_MIN_DIRECT_PICTURES - 1 &&
646 p_vout->p_picture[ i - 1 ].i_type == DIRECT_PICTURE )
648 /* We have enough direct buffers so there's no need to
649 * try to use system memory buffers. */
652 PP_RENDERPICTURE[ I_RENDERPICTURES ] = &p_vout->p_picture[ i ];
656 msg_Dbg( p_vout, "direct render, mapping "
657 "render pictures 0-%i to system pictures 1-%i",
658 VOUT_MAX_PICTURES - 2, VOUT_MAX_PICTURES - 1 );
662 /* Rats... Something is wrong here, we could not find an output
663 * plugin able to directly render what we decode. See if we can
664 * find a chroma plugin to do the conversion */
665 p_vout->b_direct = 0;
667 /* Choose the best module */
668 p_vout->chroma.p_module = module_Need( p_vout, "chroma", NULL, 0 );
670 if( p_vout->chroma.p_module == NULL )
672 msg_Err( p_vout, "no chroma module for %4.4s to %4.4s",
673 (char*)&p_vout->render.i_chroma,
674 (char*)&p_vout->output.i_chroma );
675 p_vout->pf_end( p_vout );
676 vlc_mutex_unlock( &p_vout->change_lock );
680 msg_Dbg( p_vout, "indirect render, mapping "
681 "render pictures 0-%i to system pictures %i-%i",
682 VOUT_MAX_PICTURES - 1, I_OUTPUTPICTURES,
683 I_OUTPUTPICTURES + VOUT_MAX_PICTURES - 1 );
685 /* Append render buffers after the direct buffers */
686 for( i = I_OUTPUTPICTURES; i < 2 * VOUT_MAX_PICTURES; i++ )
688 PP_RENDERPICTURE[ I_RENDERPICTURES ] = &p_vout->p_picture[ i ];
691 /* Check if we have enough render pictures */
692 if( I_RENDERPICTURES == VOUT_MAX_PICTURES )
697 /* Link pictures back to their heap */
698 for( i = 0 ; i < I_RENDERPICTURES ; i++ )
700 PP_RENDERPICTURE[ i ]->p_heap = &p_vout->render;
703 for( i = 0 ; i < I_OUTPUTPICTURES ; i++ )
705 PP_OUTPUTPICTURE[ i ]->p_heap = &p_vout->output;
708 /* XXX XXX mark thread ready */
712 /*****************************************************************************
713 * RunThread: video output thread
714 *****************************************************************************
715 * Video output thread. This function does only returns when the thread is
716 * terminated. It handles the pictures arriving in the video heap and the
717 * display device events.
718 *****************************************************************************/
719 static void RunThread( vout_thread_t *p_vout)
721 int i_index; /* index in heap */
722 int i_idle_loops = 0; /* loops without displaying a picture */
723 mtime_t current_date; /* current date */
724 mtime_t display_date; /* display date */
726 picture_t * p_picture; /* picture pointer */
727 picture_t * p_last_picture = NULL; /* last picture */
728 picture_t * p_directbuffer; /* direct buffer to display */
730 subpicture_t * p_subpic = NULL; /* subpicture pointer */
732 input_thread_t *p_input = NULL ; /* Parent input, if it exists */
735 vlc_bool_t b_drop_late;
737 int i_displayed = 0, i_lost = 0, i_loops = 0;
742 p_vout->b_error = InitThread( p_vout );
744 var_Create( p_vout, "drop-late-frames", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
745 var_Get( p_vout, "drop-late-frames", &val );
746 b_drop_late = val.b_bool;
748 /* signal the creation of the vout */
749 vlc_thread_ready( p_vout );
751 if( p_vout->b_error )
753 /* Destroy thread structures allocated by Create and InitThread */
754 DestroyThread( p_vout );
759 * Main loop - it is not executed if an error occurred during
762 while( (!p_vout->b_die) && (!p_vout->b_error) )
764 /* Initialize loop variables */
767 current_date = mdate();
769 if( p_input && p_input->b_die )
771 vlc_object_release( p_input );
776 if( i_loops % 20 == 0 )
780 p_input = vlc_object_find( p_vout, VLC_OBJECT_INPUT,
785 vlc_mutex_lock( &p_input->p->counters.counters_lock );
786 stats_UpdateInteger( p_vout, p_input->p->counters.p_lost_pictures,
788 stats_UpdateInteger( p_vout,
789 p_input->p->counters.p_displayed_pictures,
791 i_displayed = i_lost = 0;
792 vlc_mutex_unlock( &p_input->p->counters.counters_lock );
797 if( !(p_vout->c_loops % VOUT_STATS_NB_LOOPS) )
799 msg_Dbg( p_vout, "picture heap: %d/%d",
800 I_RENDERPICTURES, p_vout->i_heap_size );
805 * Find the picture to display (the one with the earliest date).
806 * This operation does not need lock, since only READY_PICTUREs
808 for( i_index = 0; i_index < I_RENDERPICTURES; i_index++ )
810 if( (PP_RENDERPICTURE[i_index]->i_status == READY_PICTURE)
811 && ( (p_picture == NULL) ||
812 (PP_RENDERPICTURE[i_index]->date < display_date) ) )
814 p_picture = PP_RENDERPICTURE[i_index];
815 display_date = p_picture->date;
821 /* If we met the last picture, parse again to see whether there is
822 * a more appropriate one. */
823 if( p_picture == p_last_picture )
825 for( i_index = 0; i_index < I_RENDERPICTURES; i_index++ )
827 if( (PP_RENDERPICTURE[i_index]->i_status == READY_PICTURE)
828 && (PP_RENDERPICTURE[i_index] != p_last_picture)
829 && ((p_picture == p_last_picture) ||
830 (PP_RENDERPICTURE[i_index]->date < display_date)) )
832 p_picture = PP_RENDERPICTURE[i_index];
833 display_date = p_picture->date;
838 /* If we found better than the last picture, destroy it */
839 if( p_last_picture && p_picture != p_last_picture )
841 vlc_mutex_lock( &p_vout->picture_lock );
842 if( p_last_picture->i_refcount )
844 p_last_picture->i_status = DISPLAYED_PICTURE;
848 p_last_picture->i_status = DESTROYED_PICTURE;
849 p_vout->i_heap_size--;
851 vlc_mutex_unlock( &p_vout->picture_lock );
852 p_last_picture = NULL;
855 /* Compute FPS rate */
856 p_vout->p_fps_sample[ p_vout->c_fps_samples++ % VOUT_FPS_SAMPLES ]
859 if( !p_picture->b_force &&
860 p_picture != p_last_picture &&
861 display_date < current_date + p_vout->render_time &&
864 /* Picture is late: it will be destroyed and the thread
865 * will directly choose the next picture */
866 vlc_mutex_lock( &p_vout->picture_lock );
867 if( p_picture->i_refcount )
869 /* Pretend we displayed the picture, but don't destroy
870 * it since the decoder might still need it. */
871 p_picture->i_status = DISPLAYED_PICTURE;
875 /* Destroy the picture without displaying it */
876 p_picture->i_status = DESTROYED_PICTURE;
877 p_vout->i_heap_size--;
879 msg_Warn( p_vout, "late picture skipped ("I64Fd")",
880 current_date - display_date );
882 vlc_mutex_unlock( &p_vout->picture_lock );
888 current_date + p_vout->i_pts_delay + VOUT_BOGUS_DELAY )
890 /* Picture is waaay too early: it will be destroyed */
891 vlc_mutex_lock( &p_vout->picture_lock );
892 if( p_picture->i_refcount )
894 /* Pretend we displayed the picture, but don't destroy
895 * it since the decoder might still need it. */
896 p_picture->i_status = DISPLAYED_PICTURE;
900 /* Destroy the picture without displaying it */
901 p_picture->i_status = DESTROYED_PICTURE;
902 p_vout->i_heap_size--;
905 msg_Warn( p_vout, "vout warning: early picture skipped "
906 "("I64Fd")", display_date - current_date
907 - p_vout->i_pts_delay );
908 vlc_mutex_unlock( &p_vout->picture_lock );
913 if( display_date > current_date + VOUT_DISPLAY_DELAY )
915 /* A picture is ready to be rendered, but its rendering date
916 * is far from the current one so the thread will perform an
917 * empty loop as if no picture were found. The picture state
922 else if( p_picture == p_last_picture )
924 /* We are asked to repeat the previous picture, but we first
925 * wait for a couple of idle loops */
926 if( i_idle_loops < 4 )
933 /* We set the display date to something high, otherwise
934 * we'll have lots of problems with late pictures */
935 display_date = current_date + p_vout->render_time;
940 if( p_picture == NULL )
945 /* Video Filter2 stuff */
946 if( p_vout->b_vfilter_change == VLC_TRUE )
949 vlc_mutex_lock( &p_vout->vfilter_lock );
950 RemoveVideoFilters2( p_vout );
951 for( i = 0; i < p_vout->i_vfilters_cfg; i++ )
953 filter_t *p_vfilter =
954 p_vout->pp_vfilters[p_vout->i_vfilters] =
955 vlc_object_create( p_vout, VLC_OBJECT_FILTER );
957 vlc_object_attach( p_vfilter, p_vout );
959 p_vfilter->pf_vout_buffer_new = video_new_buffer_filter;
960 p_vfilter->pf_vout_buffer_del = video_del_buffer_filter;
962 if( !p_vout->i_vfilters )
964 p_vfilter->fmt_in.video = p_vout->fmt_render;
968 p_vfilter->fmt_in.video = (p_vfilter-1)->fmt_out.video;
970 /* TODO: one day filters in the middle of the chain might
971 * have a different fmt_out.video than fmt_render ... */
972 p_vfilter->fmt_out.video = p_vout->fmt_render;
974 p_vfilter->p_cfg = p_vout->p_vfilters_cfg[i];
975 p_vfilter->p_module = module_Need( p_vfilter, "video filter2",
976 p_vout->psz_vfilters[i], 0 );
978 if( p_vfilter->p_module )
981 malloc( sizeof( filter_owner_sys_t ) );
982 p_vfilter->p_owner->p_vout = p_vout;
983 p_vout->i_vfilters++;
984 msg_Dbg( p_vout, "video filter found (%s)",
985 p_vout->psz_vfilters[i] );
989 msg_Err( p_vout, "no video filter found (%s)",
990 p_vout->psz_vfilters[i] );
991 vlc_object_detach( p_vfilter );
992 vlc_object_destroy( p_vfilter );
995 p_vout->b_vfilter_change = VLC_FALSE;
996 vlc_mutex_unlock( &p_vout->vfilter_lock );
1002 for( i = 0; i < p_vout->i_vfilters; i++ )
1004 picture_t *p_old = p_picture;
1005 p_picture = p_vout->pp_vfilters[i]->pf_video_filter(
1006 p_vout->pp_vfilters[i], p_picture );
1011 /* FIXME: this is kind of wrong
1012 * if you have 2 or more vfilters and the 2nd breaks,
1013 * on the next loop the 1st one will be applied again */
1015 /* if p_old and p_picture are the same (ie the filter
1016 * worked on the old picture), then following code is
1017 * still alright since i_status gets changed back to
1018 * the right value */
1019 if( p_old->i_refcount )
1021 p_old->i_status = DISPLAYED_PICTURE;
1025 p_old->i_status = DESTROYED_PICTURE;
1027 p_picture->i_status = READY_PICTURE;
1031 if( p_picture && p_vout->b_snapshot )
1033 p_vout->b_snapshot = VLC_FALSE;
1034 vout_Snapshot( p_vout, p_picture );
1038 * Check for subpictures to display
1040 if( display_date > 0 )
1044 p_input = vlc_object_find( p_vout, VLC_OBJECT_INPUT,
1047 p_subpic = spu_SortSubpictures( p_vout->p_spu, display_date,
1048 p_input ? var_GetBool( p_input, "state" ) == PAUSE_S : VLC_FALSE );
1055 p_directbuffer = vout_RenderPicture( p_vout, p_picture, p_subpic );
1058 * Call the plugin-specific rendering method if there is one
1060 if( p_picture != NULL && p_directbuffer != NULL && p_vout->pf_render )
1062 /* Render the direct buffer returned by vout_RenderPicture */
1063 p_vout->pf_render( p_vout, p_directbuffer );
1069 if( display_date != 0 && p_directbuffer != NULL )
1071 mtime_t current_render_time = mdate() - current_date;
1072 /* if render time is very large we don't include it in the mean */
1073 if( current_render_time < p_vout->render_time +
1074 VOUT_DISPLAY_DELAY )
1076 /* Store render time using a sliding mean weighting to
1077 * current value in a 3 to 1 ratio*/
1078 p_vout->render_time *= 3;
1079 p_vout->render_time += current_render_time;
1080 p_vout->render_time >>= 2;
1084 /* Give back change lock */
1085 vlc_mutex_unlock( &p_vout->change_lock );
1087 /* Sleep a while or until a given date */
1088 if( display_date != 0 )
1090 /* If there are filters in the chain, better give them the picture
1092 if( !p_vout->psz_filter_chain || !*p_vout->psz_filter_chain )
1094 mwait( display_date - VOUT_MWAIT_TOLERANCE );
1099 msleep( VOUT_IDLE_SLEEP );
1102 /* On awakening, take back lock and send immediately picture
1104 vlc_mutex_lock( &p_vout->change_lock );
1107 * Display the previously rendered picture
1109 if( p_picture != NULL && p_directbuffer != NULL )
1111 /* Display the direct buffer returned by vout_RenderPicture */
1112 if( p_vout->pf_display )
1114 p_vout->pf_display( p_vout, p_directbuffer );
1117 /* Tell the vout this was the last picture and that it does not
1118 * need to be forced anymore. */
1119 p_last_picture = p_picture;
1120 p_last_picture->b_force = 0;
1123 if( p_picture != NULL )
1125 /* Reinitialize idle loop count */
1130 * Check events and manage thread
1132 if( p_vout->pf_manage && p_vout->pf_manage( p_vout ) )
1134 /* A fatal error occurred, and the thread must terminate
1135 * immediately, without displaying anything - setting b_error to 1
1136 * causes the immediate end of the main while() loop. */
1137 p_vout->b_error = 1;
1140 if( p_vout->i_changes & VOUT_SIZE_CHANGE )
1142 /* this must only happen when the vout plugin is incapable of
1143 * rescaling the picture itself. In this case we need to destroy
1144 * the current picture buffers and recreate new ones with the right
1148 p_vout->i_changes &= ~VOUT_SIZE_CHANGE;
1150 p_vout->pf_end( p_vout );
1151 for( i = 0; i < I_OUTPUTPICTURES; i++ )
1152 p_vout->p_picture[ i ].i_status = FREE_PICTURE;
1154 I_OUTPUTPICTURES = 0;
1155 if( p_vout->pf_init( p_vout ) )
1157 msg_Err( p_vout, "cannot resize display" );
1158 /* FIXME: pf_end will be called again in EndThread() */
1159 p_vout->b_error = 1;
1162 /* Need to reinitialise the chroma plugin */
1163 if( p_vout->chroma.p_module )
1165 if( p_vout->chroma.p_module->pf_deactivate )
1166 p_vout->chroma.p_module->pf_deactivate( VLC_OBJECT(p_vout) );
1167 p_vout->chroma.p_module->pf_activate( VLC_OBJECT(p_vout) );
1171 if( p_vout->i_changes & VOUT_PICTURE_BUFFERS_CHANGE )
1173 /* This happens when the picture buffers need to be recreated.
1174 * This is useful on multimonitor displays for instance.
1176 * Warning: This only works when the vout creates only 1 picture
1178 p_vout->i_changes &= ~VOUT_PICTURE_BUFFERS_CHANGE;
1180 if( !p_vout->b_direct )
1182 module_Unneed( p_vout, p_vout->chroma.p_module );
1185 vlc_mutex_lock( &p_vout->picture_lock );
1187 p_vout->pf_end( p_vout );
1189 I_OUTPUTPICTURES = I_RENDERPICTURES = 0;
1191 p_vout->b_error = InitThread( p_vout );
1193 vlc_mutex_unlock( &p_vout->picture_lock );
1199 vlc_object_release( p_input );
1203 * Error loop - wait until the thread destruction is requested
1205 if( p_vout->b_error )
1207 ErrorThread( p_vout );
1211 EndThread( p_vout );
1213 /* Destroy thread structures allocated by CreateThread */
1214 DestroyThread( p_vout );
1217 /*****************************************************************************
1218 * ErrorThread: RunThread() error loop
1219 *****************************************************************************
1220 * This function is called when an error occurred during thread main's loop.
1221 * The thread can still receive feed, but must be ready to terminate as soon
1223 *****************************************************************************/
1224 static void ErrorThread( vout_thread_t *p_vout )
1226 /* Wait until a `die' order */
1227 while( !p_vout->b_die )
1230 msleep( VOUT_IDLE_SLEEP );
1234 /*****************************************************************************
1235 * EndThread: thread destruction
1236 *****************************************************************************
1237 * This function is called when the thread ends after a sucessful
1238 * initialization. It frees all resources allocated by InitThread.
1239 *****************************************************************************/
1240 static void EndThread( vout_thread_t *p_vout )
1242 int i_index; /* index in heap */
1246 struct tms cpu_usage;
1247 times( &cpu_usage );
1249 msg_Dbg( p_vout, "cpu usage (user: %d, system: %d)",
1250 cpu_usage.tms_utime, cpu_usage.tms_stime );
1254 if( !p_vout->b_direct )
1256 module_Unneed( p_vout, p_vout->chroma.p_module );
1259 /* Destroy all remaining pictures */
1260 for( i_index = 0; i_index < 2 * VOUT_MAX_PICTURES + 1; i_index++ )
1262 if ( p_vout->p_picture[i_index].i_type == MEMORY_PICTURE )
1264 free( p_vout->p_picture[i_index].p_data_orig );
1268 /* Destroy subpicture unit */
1269 spu_Attach( p_vout->p_spu, VLC_OBJECT(p_vout), VLC_FALSE );
1270 spu_Destroy( p_vout->p_spu );
1272 /* Destroy the video filters2 */
1273 RemoveVideoFilters2( p_vout );
1275 /* Destroy translation tables */
1276 p_vout->pf_end( p_vout );
1278 /* Release the change lock */
1279 vlc_mutex_unlock( &p_vout->change_lock );
1282 /*****************************************************************************
1283 * DestroyThread: thread destruction
1284 *****************************************************************************
1285 * This function is called when the thread ends. It frees all ressources
1286 * allocated by CreateThread. Status is available at this stage.
1287 *****************************************************************************/
1288 static void DestroyThread( vout_thread_t *p_vout )
1290 /* Destroy the locks */
1291 vlc_mutex_destroy( &p_vout->picture_lock );
1292 vlc_mutex_destroy( &p_vout->change_lock );
1293 vlc_mutex_destroy( &p_vout->vfilter_lock );
1295 /* Release the module */
1296 if( p_vout && p_vout->p_module )
1298 module_Unneed( p_vout, p_vout->p_module );
1302 /* following functions are local */
1304 static int ReduceHeight( int i_ratio )
1306 int i_dummy = VOUT_ASPECT_FACTOR;
1314 /* VOUT_ASPECT_FACTOR is (2^7 * 3^3 * 5^3), we just check for 2, 3 and 5 */
1315 while( !(i_ratio & 1) && !(i_dummy & 1) )
1322 while( !(i_ratio % 3) && !(i_dummy % 3) )
1329 while( !(i_ratio % 5) && !(i_dummy % 5) )
1339 static void AspectRatio( int i_aspect, int *i_aspect_x, int *i_aspect_y )
1341 unsigned int i_pgcd = ReduceHeight( i_aspect );
1342 *i_aspect_x = i_aspect / i_pgcd;
1343 *i_aspect_y = VOUT_ASPECT_FACTOR / i_pgcd;
1346 /*****************************************************************************
1347 * BinaryLog: computes the base 2 log of a binary value
1348 *****************************************************************************
1349 * This functions is used by MaskToShift, to get a bit index from a binary
1351 *****************************************************************************/
1352 static int BinaryLog( uint32_t i )
1356 if( i == 0 ) return -31337;
1358 if( i & 0xffff0000 ) i_log += 16;
1359 if( i & 0xff00ff00 ) i_log += 8;
1360 if( i & 0xf0f0f0f0 ) i_log += 4;
1361 if( i & 0xcccccccc ) i_log += 2;
1362 if( i & 0xaaaaaaaa ) i_log += 1;
1367 /*****************************************************************************
1368 * MaskToShift: transform a color mask into right and left shifts
1369 *****************************************************************************
1370 * This function is used for obtaining color shifts from masks.
1371 *****************************************************************************/
1372 static void MaskToShift( int *pi_left, int *pi_right, uint32_t i_mask )
1374 uint32_t i_low, i_high; /* lower hand higher bits of the mask */
1378 *pi_left = *pi_right = 0;
1383 i_low = i_high = i_mask;
1385 i_low &= - (int32_t)i_low; /* lower bit of the mask */
1386 i_high += i_low; /* higher bit of the mask */
1388 /* Transform bits into an index. Also deal with i_high overflow, which
1389 * is faster than changing the BinaryLog code to handle 64 bit integers. */
1390 i_low = BinaryLog (i_low);
1391 i_high = i_high ? BinaryLog (i_high) : 32;
1393 /* Update pointers and return */
1395 *pi_right = (8 - i_high + i_low);
1398 /*****************************************************************************
1399 * vout_VarCallback: generic callback for intf variables
1400 *****************************************************************************/
1401 int vout_VarCallback( vlc_object_t * p_this, const char * psz_variable,
1402 vlc_value_t old_value, vlc_value_t new_value,
1405 vout_thread_t * p_vout = (vout_thread_t *)p_this;
1407 val.b_bool = VLC_TRUE;
1408 var_Set( p_vout, "intf-change", val );
1412 /*****************************************************************************
1413 * Helper thread for object variables callbacks.
1414 * Only used to avoid deadlocks when using the video embedded mode.
1415 *****************************************************************************/
1416 typedef struct suxor_thread_t
1419 input_thread_t *p_input;
1423 static void SuxorRestartVideoES( suxor_thread_t *p_this )
1427 vlc_thread_ready( p_this );
1429 /* Now restart current video stream */
1430 var_Get( p_this->p_input, "video-es", &val );
1431 if( val.i_int >= 0 )
1434 val_es.i_int = -VIDEO_ES;
1435 var_Set( p_this->p_input, "video-es", val_es );
1436 var_Set( p_this->p_input, "video-es", val );
1439 vlc_object_release( p_this->p_input );
1442 CloseHandle( p_this->thread_id );
1445 vlc_object_destroy( p_this );
1448 /*****************************************************************************
1449 * object variables callbacks: a bunch of object variables are used by the
1450 * interfaces to interact with the vout.
1451 *****************************************************************************/
1452 static int DeinterlaceCallback( vlc_object_t *p_this, char const *psz_cmd,
1453 vlc_value_t oldval, vlc_value_t newval, void *p_data )
1455 vout_thread_t *p_vout = (vout_thread_t *)p_this;
1456 input_thread_t *p_input;
1459 char *psz_mode = newval.psz_string;
1460 char *psz_filter, *psz_deinterlace = NULL;
1462 var_Get( p_vout, "vout-filter", &val );
1463 psz_filter = val.psz_string;
1464 if( psz_filter ) psz_deinterlace = strstr( psz_filter, "deinterlace" );
1466 if( !psz_mode || !*psz_mode )
1468 if( psz_deinterlace )
1470 char *psz_src = psz_deinterlace + sizeof("deinterlace") - 1;
1471 if( psz_src[0] == ':' ) psz_src++;
1472 memmove( psz_deinterlace, psz_src, strlen(psz_src) + 1 );
1475 else if( !psz_deinterlace )
1477 psz_filter = realloc( psz_filter, strlen( psz_filter ) +
1478 sizeof(":deinterlace") );
1479 if( psz_filter && *psz_filter ) strcat( psz_filter, ":" );
1480 strcat( psz_filter, "deinterlace" );
1483 p_input = (input_thread_t *)vlc_object_find( p_this, VLC_OBJECT_INPUT,
1485 if( !p_input ) return VLC_EGENERIC;
1487 if( psz_mode && *psz_mode )
1489 /* Modify input as well because the vout might have to be restarted */
1490 val.psz_string = psz_mode;
1491 var_Create( p_input, "deinterlace-mode", VLC_VAR_STRING );
1492 var_Set( p_input, "deinterlace-mode", val );
1494 vlc_object_release( p_input );
1496 val.b_bool = VLC_TRUE;
1497 var_Set( p_vout, "intf-change", val );
1499 val.psz_string = psz_filter;
1500 var_Set( p_vout, "vout-filter", val );
1501 if( psz_filter ) free( psz_filter );
1506 static int FilterCallback( vlc_object_t *p_this, char const *psz_cmd,
1507 vlc_value_t oldval, vlc_value_t newval, void *p_data )
1509 vout_thread_t *p_vout = (vout_thread_t *)p_this;
1510 input_thread_t *p_input;
1513 p_input = (input_thread_t *)vlc_object_find( p_this, VLC_OBJECT_INPUT,
1517 msg_Err( p_vout, "Input not found" );
1518 return( VLC_EGENERIC );
1521 val.b_bool = VLC_TRUE;
1522 var_Set( p_vout, "intf-change", val );
1524 /* Modify input as well because the vout might have to be restarted */
1525 val.psz_string = newval.psz_string;
1526 var_Create( p_input, "vout-filter", VLC_VAR_STRING );
1528 var_Set( p_input, "vout-filter", val );
1530 /* Now restart current video stream */
1531 var_Get( p_input, "video-es", &val );
1532 if( val.i_int >= 0 )
1534 suxor_thread_t *p_suxor =
1535 vlc_object_create( p_vout, sizeof(suxor_thread_t) );
1536 p_suxor->p_input = p_input;
1537 p_vout->b_filter_change = VLC_TRUE;
1538 vlc_object_yield( p_input );
1539 vlc_thread_create( p_suxor, "suxor", SuxorRestartVideoES,
1540 VLC_THREAD_PRIORITY_LOW, VLC_FALSE );
1543 vlc_object_release( p_input );
1548 /*****************************************************************************
1549 * Video Filter2 stuff
1550 *****************************************************************************/
1551 static int ParseVideoFilter2Chain( vout_thread_t *p_vout, char *psz_vfilters )
1554 for( i = 0; i < p_vout->i_vfilters_cfg; i++ )
1556 struct config_chain_t *p_cfg =
1557 p_vout->p_vfilters_cfg[p_vout->i_vfilters_cfg];
1558 config_ChainDestroy( p_cfg );
1559 if( p_vout->psz_vfilters[p_vout->i_vfilters_cfg] )
1561 free( p_vout->psz_vfilters[p_vout->i_vfilters_cfg] );
1562 p_vout->psz_vfilters[p_vout->i_vfilters_cfg] = NULL;
1565 p_vout->i_vfilters_cfg = 0;
1566 if( psz_vfilters && *psz_vfilters )
1568 char *psz_parser = psz_vfilters;
1570 while( psz_parser && *psz_parser )
1572 psz_parser = config_ChainCreate(
1573 &p_vout->psz_vfilters[p_vout->i_vfilters_cfg],
1574 &p_vout->p_vfilters_cfg[p_vout->i_vfilters_cfg],
1576 msg_Dbg( p_vout, "adding vfilter: %s",
1577 p_vout->psz_vfilters[p_vout->i_vfilters_cfg] );
1578 p_vout->i_vfilters_cfg++;
1579 if( psz_parser && *psz_parser )
1581 if( p_vout->i_vfilters_cfg == MAX_VFILTERS )
1584 "maximum number of video filters reached. \"%s\" discarded",
1594 static int VideoFilter2Callback( vlc_object_t *p_this, char const *psz_cmd,
1595 vlc_value_t oldval, vlc_value_t newval, void *p_data )
1597 vout_thread_t *p_vout = (vout_thread_t *)p_this;
1599 vlc_mutex_lock( &p_vout->vfilter_lock );
1600 ParseVideoFilter2Chain( p_vout, newval.psz_string );
1601 p_vout->b_vfilter_change = VLC_TRUE;
1602 vlc_mutex_unlock( &p_vout->vfilter_lock );
1607 static void RemoveVideoFilters2( vout_thread_t *p_vout )
1610 for( i = 0; i < p_vout->i_vfilters; i++ )
1612 vlc_object_detach( p_vout->pp_vfilters[i] );
1613 if( p_vout->pp_vfilters[i]->p_module )
1615 module_Unneed( p_vout->pp_vfilters[i],
1616 p_vout->pp_vfilters[i]->p_module );
1619 free( p_vout->pp_vfilters[i]->p_owner );
1620 vlc_object_destroy( p_vout->pp_vfilters[i] );
1622 p_vout->i_vfilters = 0;