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-2007 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 #include "modules/modules.h"
58 /*****************************************************************************
60 *****************************************************************************/
61 static int InitThread ( vout_thread_t * );
62 static void RunThread ( vout_thread_t * );
63 static void ErrorThread ( vout_thread_t * );
64 static void EndThread ( vout_thread_t * );
65 static void DestroyThread ( vout_thread_t * );
67 static void AspectRatio ( int, int *, int * );
68 static int BinaryLog ( uint32_t );
69 static void MaskToShift ( int *, int *, uint32_t );
71 /* Object variables callbacks */
72 static int DeinterlaceCallback( vlc_object_t *, char const *,
73 vlc_value_t, vlc_value_t, void * );
74 static int FilterCallback( vlc_object_t *, char const *,
75 vlc_value_t, vlc_value_t, void * );
76 static int VideoFilter2Callback( vlc_object_t *, char const *,
77 vlc_value_t, vlc_value_t, void * );
79 /* From vout_intf.c */
80 int vout_Snapshot( vout_thread_t *, picture_t * );
82 /* Video filter2 parsing */
83 static int ParseVideoFilter2Chain( vout_thread_t *, char * );
84 static void RemoveVideoFilters2( vout_thread_t *p_vout );
86 /*****************************************************************************
87 * Video Filter2 functions
88 *****************************************************************************/
89 struct filter_owner_sys_t
91 vout_thread_t *p_vout;
94 static picture_t *video_new_buffer_filter( filter_t *p_filter )
97 vout_thread_t *p_vout = p_filter->p_owner->p_vout;
99 p_picture = vout_CreatePicture( p_vout, 0, 0, 0 );
104 static void video_del_buffer_filter( filter_t *p_filter, picture_t *p_pic )
106 vout_DestroyPicture( p_filter->p_owner->p_vout, p_pic );
109 /*****************************************************************************
110 * vout_Request: find a video output thread, create one, or destroy one.
111 *****************************************************************************
112 * This function looks for a video output thread matching the current
113 * properties. If not found, it spawns a new one.
114 *****************************************************************************/
115 vout_thread_t *__vout_Request( vlc_object_t *p_this, vout_thread_t *p_vout,
116 video_format_t *p_fmt )
120 /* Reattach video output to playlist before bailing out */
123 playlist_t *p_playlist = pl_Yield( p_this );
124 spu_Attach( p_vout->p_spu, p_this, VLC_FALSE );
125 vlc_object_detach( p_vout );
126 vlc_object_attach( p_vout, p_playlist );
127 pl_Release( p_this );
132 /* If a video output was provided, lock it, otherwise look for one. */
135 vlc_object_yield( p_vout );
139 p_vout = vlc_object_find( p_this, VLC_OBJECT_VOUT, FIND_CHILD );
143 playlist_t *p_playlist = pl_Yield( p_this );
144 vlc_mutex_lock( &p_playlist->gc_lock );
145 p_vout = vlc_object_find( p_playlist,
146 VLC_OBJECT_VOUT, FIND_CHILD );
147 /* only first children of p_input for unused vout */
148 if( p_vout && p_vout->p_parent != (vlc_object_t *)p_playlist )
150 vlc_object_release( p_vout );
154 vlc_object_detach( p_vout ); /* Remove it from the GC */
155 vlc_mutex_unlock( &p_playlist->gc_lock );
156 pl_Release( p_this );
160 /* If we now have a video output, check it has the right properties */
163 char *psz_filter_chain;
166 /* We don't directly check for the "vout-filter" variable for obvious
167 * performance reasons. */
168 if( p_vout->b_filter_change )
170 var_Get( p_vout, "vout-filter", &val );
171 psz_filter_chain = val.psz_string;
173 if( psz_filter_chain && !*psz_filter_chain )
175 free( psz_filter_chain );
176 psz_filter_chain = NULL;
178 if( p_vout->psz_filter_chain && !*p_vout->psz_filter_chain )
180 free( p_vout->psz_filter_chain );
181 p_vout->psz_filter_chain = NULL;
184 if( !psz_filter_chain && !p_vout->psz_filter_chain )
186 p_vout->b_filter_change = VLC_FALSE;
189 if( psz_filter_chain ) free( psz_filter_chain );
192 if( ( p_vout->fmt_render.i_width != p_fmt->i_width ) ||
193 ( p_vout->fmt_render.i_height != p_fmt->i_height ) ||
194 ( p_vout->fmt_render.i_chroma != p_fmt->i_chroma ) ||
195 ( p_vout->fmt_render.i_aspect != p_fmt->i_aspect ) ||
196 p_vout->b_filter_change )
198 /* We are not interested in this format, close this vout */
199 vlc_object_release( p_vout );
200 vout_Destroy( p_vout );
205 /* This video output is cool! Hijack it. */
206 spu_Attach( p_vout->p_spu, p_this, VLC_TRUE );
207 vlc_object_attach( p_vout, p_this );
208 vlc_object_release( p_vout );
214 msg_Dbg( p_this, "no usable vout present, spawning one" );
216 p_vout = vout_Create( p_this, p_fmt );
222 /*****************************************************************************
223 * vout_Create: creates a new video output thread
224 *****************************************************************************
225 * This function creates a new video output thread, and returns a pointer
226 * to its description. On error, it returns NULL.
227 *****************************************************************************/
228 vout_thread_t * __vout_Create( vlc_object_t *p_parent, video_format_t *p_fmt )
230 vout_thread_t * p_vout; /* thread descriptor */
231 input_thread_t * p_input_thread;
232 int i_index; /* loop variable */
233 vlc_value_t val, text;
235 unsigned int i_width = p_fmt->i_width;
236 unsigned int i_height = p_fmt->i_height;
237 vlc_fourcc_t i_chroma = p_fmt->i_chroma;
238 unsigned int i_aspect = p_fmt->i_aspect;
240 config_chain_t *p_cfg;
244 /* Allocate descriptor */
245 p_vout = vlc_object_create( p_parent, VLC_OBJECT_VOUT );
248 msg_Err( p_parent, "out of memory" );
252 /* Initialize pictures - translation tables and functions
253 * will be initialized later in InitThread */
254 for( i_index = 0; i_index < 2 * VOUT_MAX_PICTURES + 1; i_index++)
256 p_vout->p_picture[i_index].pf_lock = NULL;
257 p_vout->p_picture[i_index].pf_unlock = NULL;
258 p_vout->p_picture[i_index].i_status = FREE_PICTURE;
259 p_vout->p_picture[i_index].i_type = EMPTY_PICTURE;
260 p_vout->p_picture[i_index].b_slow = 0;
263 /* No images in the heap */
264 p_vout->i_heap_size = 0;
266 /* Initialize the rendering heap */
267 I_RENDERPICTURES = 0;
269 vlc_ureduce( &p_fmt->i_sar_num, &p_fmt->i_sar_den,
270 p_fmt->i_sar_num, p_fmt->i_sar_den, 50000 );
271 p_vout->fmt_render = *p_fmt; /* FIXME palette */
272 p_vout->fmt_in = *p_fmt; /* FIXME palette */
274 p_vout->render.i_width = i_width;
275 p_vout->render.i_height = i_height;
276 p_vout->render.i_chroma = i_chroma;
277 p_vout->render.i_aspect = i_aspect;
279 p_vout->render.i_rmask = 0;
280 p_vout->render.i_gmask = 0;
281 p_vout->render.i_bmask = 0;
283 p_vout->render.i_last_used_pic = -1;
284 p_vout->render.b_allow_modify_pics = 1;
286 /* Zero the output heap */
287 I_OUTPUTPICTURES = 0;
288 p_vout->output.i_width = 0;
289 p_vout->output.i_height = 0;
290 p_vout->output.i_chroma = 0;
291 p_vout->output.i_aspect = 0;
293 p_vout->output.i_rmask = 0;
294 p_vout->output.i_gmask = 0;
295 p_vout->output.i_bmask = 0;
297 /* Initialize misc stuff */
298 p_vout->i_changes = 0;
300 p_vout->b_grayscale = 0;
302 p_vout->b_interface = 0;
304 p_vout->b_fullscreen = 0;
305 p_vout->i_alignment = 0;
306 p_vout->render_time = 10;
307 p_vout->c_fps_samples = 0;
308 p_vout->b_filter_change = 0;
309 p_vout->pf_control = 0;
310 p_vout->p_parent_intf = 0;
311 p_vout->i_par_num = p_vout->i_par_den = 1;
313 /* Initialize locks */
314 vlc_mutex_init( p_vout, &p_vout->picture_lock );
315 vlc_mutex_init( p_vout, &p_vout->change_lock );
316 vlc_mutex_init( p_vout, &p_vout->vfilter_lock );
318 /* Mouse coordinates */
319 var_Create( p_vout, "mouse-x", VLC_VAR_INTEGER );
320 var_Create( p_vout, "mouse-y", VLC_VAR_INTEGER );
321 var_Create( p_vout, "mouse-button-down", VLC_VAR_INTEGER );
322 var_Create( p_vout, "mouse-moved", VLC_VAR_BOOL );
323 var_Create( p_vout, "mouse-clicked", VLC_VAR_INTEGER );
325 /* Initialize subpicture unit */
326 p_vout->p_spu = spu_Create( p_vout );
327 spu_Attach( p_vout->p_spu, p_parent, VLC_TRUE );
329 /* Attach the new object now so we can use var inheritance below */
330 vlc_object_attach( p_vout, p_parent );
332 spu_Init( p_vout->p_spu );
334 /* Take care of some "interface/control" related initialisations */
335 vout_IntfInit( p_vout );
337 /* If the parent is not a VOUT object, that means we are at the start of
338 * the video output pipe */
339 if( p_parent->i_object_type != VLC_OBJECT_VOUT )
341 /* Look for the default filter configuration */
342 var_Create( p_vout, "vout-filter", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
343 var_Get( p_vout, "vout-filter", &val );
344 p_vout->psz_filter_chain = val.psz_string;
346 /* Apply video filter2 objects on the first vout */
347 var_Create( p_vout, "video-filter",
348 VLC_VAR_STRING | VLC_VAR_DOINHERIT );
349 var_Get( p_vout, "video-filter", &val );
350 ParseVideoFilter2Chain( p_vout, val.psz_string );
351 free( val.psz_string );
355 /* continue the parent's filter chain */
358 /* Ugly hack to jump to our configuration chain */
359 p_vout->psz_filter_chain
360 = ((vout_thread_t *)p_parent)->psz_filter_chain;
361 p_vout->psz_filter_chain
362 = config_ChainCreate( &psz_tmp, &p_cfg, p_vout->psz_filter_chain );
363 config_ChainDestroy( p_cfg );
366 /* Create a video filter2 var ... but don't inherit values */
367 var_Create( p_vout, "video-filter", VLC_VAR_STRING );
368 ParseVideoFilter2Chain( p_vout, NULL );
371 var_AddCallback( p_vout, "video-filter", VideoFilter2Callback, NULL );
372 p_vout->b_vfilter_change = VLC_TRUE;
373 p_vout->i_vfilters = 0;
375 /* Choose the video output module */
376 if( !p_vout->psz_filter_chain || !*p_vout->psz_filter_chain )
378 var_Create( p_vout, "vout", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
379 var_Get( p_vout, "vout", &val );
380 psz_parser = val.psz_string;
384 psz_parser = strdup( p_vout->psz_filter_chain );
387 /* Create the vout thread */
388 config_ChainCreate( &psz_name, &p_cfg, psz_parser );
390 p_vout->p_cfg = p_cfg;
391 p_vout->p_module = module_Need( p_vout,
392 ( p_vout->psz_filter_chain && *p_vout->psz_filter_chain ) ?
393 "video filter" : "video output", psz_name, 0 );
396 if( p_vout->p_module == NULL )
398 msg_Err( p_vout, "no suitable vout module" );
399 vlc_object_detach( p_vout );
400 vlc_object_destroy( p_vout );
404 /* Create a few object variables for interface interaction */
405 var_Create( p_vout, "deinterlace", VLC_VAR_STRING | VLC_VAR_HASCHOICE );
406 text.psz_string = _("Deinterlace");
407 var_Change( p_vout, "deinterlace", VLC_VAR_SETTEXT, &text, NULL );
408 val.psz_string = (char *)""; text.psz_string = _("Disable");
409 var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text );
410 val.psz_string = (char *)"discard"; text.psz_string = _("Discard");
411 var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text );
412 val.psz_string = (char *)"blend"; text.psz_string = _("Blend");
413 var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text );
414 val.psz_string = (char *)"mean"; text.psz_string = _("Mean");
415 var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text );
416 val.psz_string = (char *)"bob"; text.psz_string = _("Bob");
417 var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text );
418 val.psz_string = (char *)"linear"; text.psz_string = _("Linear");
419 var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text );
420 val.psz_string = (char *)"x"; text.psz_string = (char *)"X";
421 var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text );
423 if( var_Get( p_vout, "deinterlace-mode", &val ) == VLC_SUCCESS )
425 var_Set( p_vout, "deinterlace", val );
426 if( val.psz_string ) free( val.psz_string );
428 var_AddCallback( p_vout, "deinterlace", DeinterlaceCallback, NULL );
431 var_Create( p_vout, "vout-filter", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
432 text.psz_string = _("Filters");
433 var_Change( p_vout, "vout-filter", VLC_VAR_SETTEXT, &text, NULL );
434 var_AddCallback( p_vout, "vout-filter", FilterCallback, NULL );
436 /* Calculate delay created by internal caching */
437 p_input_thread = (input_thread_t *)vlc_object_find( p_vout,
438 VLC_OBJECT_INPUT, FIND_ANYWHERE );
441 p_vout->i_pts_delay = p_input_thread->i_pts_delay;
442 vlc_object_release( p_input_thread );
446 p_vout->i_pts_delay = DEFAULT_PTS_DELAY;
449 if( vlc_thread_create( p_vout, "video output", RunThread,
450 VLC_THREAD_PRIORITY_OUTPUT, VLC_TRUE ) )
452 msg_Err( p_vout, "out of memory" );
453 module_Unneed( p_vout, p_vout->p_module );
454 vlc_object_detach( p_vout );
455 vlc_object_destroy( p_vout );
459 if( p_vout->b_error )
461 msg_Err( p_vout, "video output creation failed" );
463 /* Make sure the thread is destroyed */
464 p_vout->b_die = VLC_TRUE;
466 vlc_thread_join( p_vout );
468 vlc_object_detach( p_vout );
469 vlc_object_destroy( p_vout );
476 /*****************************************************************************
477 * vout_Destroy: destroys a previously created video output
478 *****************************************************************************
479 * Destroy a terminated thread.
480 * The function will request a destruction of the specified thread. If pi_error
481 * is NULL, it will return once the thread is destroyed. Else, it will be
482 * update using one of the THREAD_* constants.
483 *****************************************************************************/
484 void vout_Destroy( vout_thread_t *p_vout )
486 vout_thread_t *p_another_vout;
487 playlist_t *p_playlist = pl_Yield( p_vout );
489 /* Request thread destruction */
490 p_vout->b_die = VLC_TRUE;
491 vlc_thread_join( p_vout );
493 var_Destroy( p_vout, "intf-change" );
495 if( p_vout->psz_filter_chain ) free( p_vout->psz_filter_chain );
497 config_ChainDestroy( p_vout->p_cfg );
500 vlc_object_destroy( p_vout );
502 /* This is a dirty hack for mostly Linux, where there is no way to get the GUI
503 back if you closed it while playing video. This is solved in Mac OS X,
504 where we have this novelty called menubar, that will always allow you access
505 to the applications main functionality. They should try that on linux sometime */
506 p_another_vout = vlc_object_find( p_playlist,
507 VLC_OBJECT_VOUT, FIND_ANYWHERE );
508 if( p_another_vout == NULL )
511 val.b_bool = VLC_TRUE;
512 var_Set( p_playlist, "intf-show", val );
516 vlc_object_release( p_another_vout );
519 vlc_object_release( p_playlist );
522 /*****************************************************************************
523 * InitThread: initialize video output thread
524 *****************************************************************************
525 * This function is called from RunThread and performs the second step of the
526 * initialization. It returns 0 on success. Note that the thread's flag are not
527 * modified inside this function.
528 *****************************************************************************/
529 static int InitThread( vout_thread_t *p_vout )
531 int i, i_aspect_x, i_aspect_y;
533 vlc_mutex_lock( &p_vout->change_lock );
539 /* Initialize output method, it allocates direct buffers for us */
540 if( p_vout->pf_init( p_vout ) )
542 vlc_mutex_unlock( &p_vout->change_lock );
546 if( !I_OUTPUTPICTURES )
548 msg_Err( p_vout, "plugin was unable to allocate at least "
549 "one direct buffer" );
550 p_vout->pf_end( p_vout );
551 vlc_mutex_unlock( &p_vout->change_lock );
555 if( I_OUTPUTPICTURES > VOUT_MAX_PICTURES )
557 msg_Err( p_vout, "plugin allocated too many direct buffers, "
558 "our internal buffers must have overflown." );
559 p_vout->pf_end( p_vout );
560 vlc_mutex_unlock( &p_vout->change_lock );
564 msg_Dbg( p_vout, "got %i direct buffer(s)", I_OUTPUTPICTURES );
566 AspectRatio( p_vout->fmt_render.i_aspect, &i_aspect_x, &i_aspect_y );
568 msg_Dbg( p_vout, "picture in %ix%i (%i,%i,%ix%i), "
569 "chroma %4.4s, ar %i:%i, sar %i:%i",
570 p_vout->fmt_render.i_width, p_vout->fmt_render.i_height,
571 p_vout->fmt_render.i_x_offset, p_vout->fmt_render.i_y_offset,
572 p_vout->fmt_render.i_visible_width,
573 p_vout->fmt_render.i_visible_height,
574 (char*)&p_vout->fmt_render.i_chroma,
575 i_aspect_x, i_aspect_y,
576 p_vout->fmt_render.i_sar_num, p_vout->fmt_render.i_sar_den );
578 AspectRatio( p_vout->fmt_in.i_aspect, &i_aspect_x, &i_aspect_y );
580 msg_Dbg( p_vout, "picture user %ix%i (%i,%i,%ix%i), "
581 "chroma %4.4s, ar %i:%i, sar %i:%i",
582 p_vout->fmt_in.i_width, p_vout->fmt_in.i_height,
583 p_vout->fmt_in.i_x_offset, p_vout->fmt_in.i_y_offset,
584 p_vout->fmt_in.i_visible_width,
585 p_vout->fmt_in.i_visible_height,
586 (char*)&p_vout->fmt_in.i_chroma,
587 i_aspect_x, i_aspect_y,
588 p_vout->fmt_in.i_sar_num, p_vout->fmt_in.i_sar_den );
590 if( !p_vout->fmt_out.i_width || !p_vout->fmt_out.i_height )
592 p_vout->fmt_out.i_width = p_vout->fmt_out.i_visible_width =
593 p_vout->output.i_width;
594 p_vout->fmt_out.i_height = p_vout->fmt_out.i_visible_height =
595 p_vout->output.i_height;
596 p_vout->fmt_out.i_x_offset = p_vout->fmt_out.i_y_offset = 0;
598 p_vout->fmt_out.i_aspect = p_vout->output.i_aspect;
599 p_vout->fmt_out.i_chroma = p_vout->output.i_chroma;
601 if( !p_vout->fmt_out.i_sar_num || !p_vout->fmt_out.i_sar_num )
603 p_vout->fmt_out.i_sar_num = p_vout->fmt_out.i_aspect *
604 p_vout->fmt_out.i_height;
605 p_vout->fmt_out.i_sar_den = VOUT_ASPECT_FACTOR *
606 p_vout->fmt_out.i_width;
609 vlc_ureduce( &p_vout->fmt_out.i_sar_num, &p_vout->fmt_out.i_sar_den,
610 p_vout->fmt_out.i_sar_num, p_vout->fmt_out.i_sar_den, 0 );
612 AspectRatio( p_vout->fmt_out.i_aspect, &i_aspect_x, &i_aspect_y );
614 msg_Dbg( p_vout, "picture out %ix%i (%i,%i,%ix%i), "
615 "chroma %4.4s, ar %i:%i, sar %i:%i",
616 p_vout->fmt_out.i_width, p_vout->fmt_out.i_height,
617 p_vout->fmt_out.i_x_offset, p_vout->fmt_out.i_y_offset,
618 p_vout->fmt_out.i_visible_width,
619 p_vout->fmt_out.i_visible_height,
620 (char*)&p_vout->fmt_out.i_chroma,
621 i_aspect_x, i_aspect_y,
622 p_vout->fmt_out.i_sar_num, p_vout->fmt_out.i_sar_den );
624 /* Calculate shifts from system-updated masks */
625 MaskToShift( &p_vout->output.i_lrshift, &p_vout->output.i_rrshift,
626 p_vout->output.i_rmask );
627 MaskToShift( &p_vout->output.i_lgshift, &p_vout->output.i_rgshift,
628 p_vout->output.i_gmask );
629 MaskToShift( &p_vout->output.i_lbshift, &p_vout->output.i_rbshift,
630 p_vout->output.i_bmask );
632 /* Check whether we managed to create direct buffers similar to
633 * the render buffers, ie same size and chroma */
634 if( ( p_vout->output.i_width == p_vout->render.i_width )
635 && ( p_vout->output.i_height == p_vout->render.i_height )
636 && ( vout_ChromaCmp( p_vout->output.i_chroma, p_vout->render.i_chroma ) ) )
638 /* Cool ! We have direct buffers, we can ask the decoder to
639 * directly decode into them ! Map the first render buffers to
640 * the first direct buffers, but keep the first direct buffer
641 * for memcpy operations */
642 p_vout->b_direct = 1;
644 for( i = 1; i < VOUT_MAX_PICTURES; i++ )
646 if( p_vout->p_picture[ i ].i_type != DIRECT_PICTURE &&
647 I_RENDERPICTURES >= VOUT_MIN_DIRECT_PICTURES - 1 &&
648 p_vout->p_picture[ i - 1 ].i_type == DIRECT_PICTURE )
650 /* We have enough direct buffers so there's no need to
651 * try to use system memory buffers. */
654 PP_RENDERPICTURE[ I_RENDERPICTURES ] = &p_vout->p_picture[ i ];
658 msg_Dbg( p_vout, "direct render, mapping "
659 "render pictures 0-%i to system pictures 1-%i",
660 VOUT_MAX_PICTURES - 2, VOUT_MAX_PICTURES - 1 );
664 /* Rats... Something is wrong here, we could not find an output
665 * plugin able to directly render what we decode. See if we can
666 * find a chroma plugin to do the conversion */
667 p_vout->b_direct = 0;
669 /* Choose the best module */
670 p_vout->chroma.p_module = module_Need( p_vout, "chroma", NULL, 0 );
672 if( p_vout->chroma.p_module == NULL )
674 msg_Err( p_vout, "no chroma module for %4.4s to %4.4s",
675 (char*)&p_vout->render.i_chroma,
676 (char*)&p_vout->output.i_chroma );
677 p_vout->pf_end( p_vout );
678 vlc_mutex_unlock( &p_vout->change_lock );
682 msg_Dbg( p_vout, "indirect render, mapping "
683 "render pictures 0-%i to system pictures %i-%i",
684 VOUT_MAX_PICTURES - 1, I_OUTPUTPICTURES,
685 I_OUTPUTPICTURES + VOUT_MAX_PICTURES - 1 );
687 /* Append render buffers after the direct buffers */
688 for( i = I_OUTPUTPICTURES; i < 2 * VOUT_MAX_PICTURES; i++ )
690 PP_RENDERPICTURE[ I_RENDERPICTURES ] = &p_vout->p_picture[ i ];
693 /* Check if we have enough render pictures */
694 if( I_RENDERPICTURES == VOUT_MAX_PICTURES )
699 /* Link pictures back to their heap */
700 for( i = 0 ; i < I_RENDERPICTURES ; i++ )
702 PP_RENDERPICTURE[ i ]->p_heap = &p_vout->render;
705 for( i = 0 ; i < I_OUTPUTPICTURES ; i++ )
707 PP_OUTPUTPICTURE[ i ]->p_heap = &p_vout->output;
710 /* XXX XXX mark thread ready */
714 /*****************************************************************************
715 * RunThread: video output thread
716 *****************************************************************************
717 * Video output thread. This function does only returns when the thread is
718 * terminated. It handles the pictures arriving in the video heap and the
719 * display device events.
720 *****************************************************************************/
721 static void RunThread( vout_thread_t *p_vout)
723 int i_index; /* index in heap */
724 int i_idle_loops = 0; /* loops without displaying a picture */
725 mtime_t current_date; /* current date */
726 mtime_t display_date; /* display date */
728 picture_t * p_picture; /* picture pointer */
729 picture_t * p_last_picture = NULL; /* last picture */
730 picture_t * p_directbuffer; /* direct buffer to display */
732 subpicture_t * p_subpic = NULL; /* subpicture pointer */
734 input_thread_t *p_input = NULL ; /* Parent input, if it exists */
737 vlc_bool_t b_drop_late;
739 int i_displayed = 0, i_lost = 0, i_loops = 0;
744 p_vout->b_error = InitThread( p_vout );
746 var_Create( p_vout, "drop-late-frames", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
747 var_Get( p_vout, "drop-late-frames", &val );
748 b_drop_late = val.b_bool;
750 /* signal the creation of the vout */
751 vlc_thread_ready( p_vout );
753 if( p_vout->b_error )
755 /* Destroy thread structures allocated by Create and InitThread */
756 DestroyThread( p_vout );
761 * Main loop - it is not executed if an error occurred during
764 while( (!p_vout->b_die) && (!p_vout->b_error) )
766 /* Initialize loop variables */
769 current_date = mdate();
771 if( p_input && p_input->b_die )
773 vlc_object_release( p_input );
778 if( i_loops % 20 == 0 )
782 p_input = vlc_object_find( p_vout, VLC_OBJECT_INPUT,
787 vlc_mutex_lock( &p_input->p->counters.counters_lock );
788 stats_UpdateInteger( p_vout, p_input->p->counters.p_lost_pictures,
790 stats_UpdateInteger( p_vout,
791 p_input->p->counters.p_displayed_pictures,
793 i_displayed = i_lost = 0;
794 vlc_mutex_unlock( &p_input->p->counters.counters_lock );
799 if( !(p_vout->c_loops % VOUT_STATS_NB_LOOPS) )
801 msg_Dbg( p_vout, "picture heap: %d/%d",
802 I_RENDERPICTURES, p_vout->i_heap_size );
807 * Find the picture to display (the one with the earliest date).
808 * This operation does not need lock, since only READY_PICTUREs
810 for( i_index = 0; i_index < I_RENDERPICTURES; i_index++ )
812 if( (PP_RENDERPICTURE[i_index]->i_status == READY_PICTURE)
813 && ( (p_picture == NULL) ||
814 (PP_RENDERPICTURE[i_index]->date < display_date) ) )
816 p_picture = PP_RENDERPICTURE[i_index];
817 display_date = p_picture->date;
823 /* If we met the last picture, parse again to see whether there is
824 * a more appropriate one. */
825 if( p_picture == p_last_picture )
827 for( i_index = 0; i_index < I_RENDERPICTURES; i_index++ )
829 if( (PP_RENDERPICTURE[i_index]->i_status == READY_PICTURE)
830 && (PP_RENDERPICTURE[i_index] != p_last_picture)
831 && ((p_picture == p_last_picture) ||
832 (PP_RENDERPICTURE[i_index]->date < display_date)) )
834 p_picture = PP_RENDERPICTURE[i_index];
835 display_date = p_picture->date;
840 /* If we found better than the last picture, destroy it */
841 if( p_last_picture && p_picture != p_last_picture )
843 vlc_mutex_lock( &p_vout->picture_lock );
844 if( p_last_picture->i_refcount )
846 p_last_picture->i_status = DISPLAYED_PICTURE;
850 p_last_picture->i_status = DESTROYED_PICTURE;
851 p_vout->i_heap_size--;
853 vlc_mutex_unlock( &p_vout->picture_lock );
854 p_last_picture = NULL;
857 /* Compute FPS rate */
858 p_vout->p_fps_sample[ p_vout->c_fps_samples++ % VOUT_FPS_SAMPLES ]
861 if( !p_picture->b_force &&
862 p_picture != p_last_picture &&
863 display_date < current_date + p_vout->render_time &&
866 /* Picture is late: it will be destroyed and the thread
867 * will directly choose the next picture */
868 vlc_mutex_lock( &p_vout->picture_lock );
869 if( p_picture->i_refcount )
871 /* Pretend we displayed the picture, but don't destroy
872 * it since the decoder might still need it. */
873 p_picture->i_status = DISPLAYED_PICTURE;
877 /* Destroy the picture without displaying it */
878 p_picture->i_status = DESTROYED_PICTURE;
879 p_vout->i_heap_size--;
881 msg_Warn( p_vout, "late picture skipped ("I64Fd")",
882 current_date - display_date );
884 vlc_mutex_unlock( &p_vout->picture_lock );
890 current_date + p_vout->i_pts_delay + VOUT_BOGUS_DELAY )
892 /* Picture is waaay too early: it will be destroyed */
893 vlc_mutex_lock( &p_vout->picture_lock );
894 if( p_picture->i_refcount )
896 /* Pretend we displayed the picture, but don't destroy
897 * it since the decoder might still need it. */
898 p_picture->i_status = DISPLAYED_PICTURE;
902 /* Destroy the picture without displaying it */
903 p_picture->i_status = DESTROYED_PICTURE;
904 p_vout->i_heap_size--;
907 msg_Warn( p_vout, "vout warning: early picture skipped "
908 "("I64Fd")", display_date - current_date
909 - p_vout->i_pts_delay );
910 vlc_mutex_unlock( &p_vout->picture_lock );
915 if( display_date > current_date + VOUT_DISPLAY_DELAY )
917 /* A picture is ready to be rendered, but its rendering date
918 * is far from the current one so the thread will perform an
919 * empty loop as if no picture were found. The picture state
924 else if( p_picture == p_last_picture )
926 /* We are asked to repeat the previous picture, but we first
927 * wait for a couple of idle loops */
928 if( i_idle_loops < 4 )
935 /* We set the display date to something high, otherwise
936 * we'll have lots of problems with late pictures */
937 display_date = current_date + p_vout->render_time;
942 if( p_picture == NULL )
947 /* Video Filter2 stuff */
948 if( p_vout->b_vfilter_change == VLC_TRUE )
951 vlc_mutex_lock( &p_vout->vfilter_lock );
952 RemoveVideoFilters2( p_vout );
953 for( i = 0; i < p_vout->i_vfilters_cfg; i++ )
955 filter_t *p_vfilter =
956 p_vout->pp_vfilters[p_vout->i_vfilters] =
957 vlc_object_create( p_vout, VLC_OBJECT_FILTER );
959 vlc_object_attach( p_vfilter, p_vout );
961 p_vfilter->pf_vout_buffer_new = video_new_buffer_filter;
962 p_vfilter->pf_vout_buffer_del = video_del_buffer_filter;
964 if( !p_vout->i_vfilters )
966 p_vfilter->fmt_in.video = p_vout->fmt_render;
970 p_vfilter->fmt_in.video = (p_vfilter-1)->fmt_out.video;
972 /* TODO: one day filters in the middle of the chain might
973 * have a different fmt_out.video than fmt_render ... */
974 p_vfilter->fmt_out.video = p_vout->fmt_render;
976 p_vfilter->p_cfg = p_vout->p_vfilters_cfg[i];
977 p_vfilter->p_module = module_Need( p_vfilter, "video filter2",
978 p_vout->psz_vfilters[i], 0 );
980 if( p_vfilter->p_module )
983 malloc( sizeof( filter_owner_sys_t ) );
984 p_vfilter->p_owner->p_vout = p_vout;
985 p_vout->i_vfilters++;
986 msg_Dbg( p_vout, "video filter found (%s)",
987 p_vout->psz_vfilters[i] );
991 msg_Err( p_vout, "no video filter found (%s)",
992 p_vout->psz_vfilters[i] );
993 vlc_object_detach( p_vfilter );
994 vlc_object_destroy( p_vfilter );
997 p_vout->b_vfilter_change = VLC_FALSE;
998 vlc_mutex_unlock( &p_vout->vfilter_lock );
1004 for( i = 0; i < p_vout->i_vfilters; i++ )
1006 picture_t *p_old = p_picture;
1007 p_picture = p_vout->pp_vfilters[i]->pf_video_filter(
1008 p_vout->pp_vfilters[i], p_picture );
1013 /* FIXME: this is kind of wrong
1014 * if you have 2 or more vfilters and the 2nd breaks,
1015 * on the next loop the 1st one will be applied again */
1017 /* if p_old and p_picture are the same (ie the filter
1018 * worked on the old picture), then following code is
1019 * still alright since i_status gets changed back to
1020 * the right value */
1021 if( p_old->i_refcount )
1023 p_old->i_status = DISPLAYED_PICTURE;
1027 p_old->i_status = DESTROYED_PICTURE;
1029 p_picture->i_status = READY_PICTURE;
1033 if( p_picture && p_vout->b_snapshot )
1035 p_vout->b_snapshot = VLC_FALSE;
1036 vout_Snapshot( p_vout, p_picture );
1040 * Check for subpictures to display
1042 if( display_date > 0 )
1046 p_input = vlc_object_find( p_vout, VLC_OBJECT_INPUT,
1049 p_subpic = spu_SortSubpictures( p_vout->p_spu, display_date,
1050 p_input ? var_GetBool( p_input, "state" ) == PAUSE_S : VLC_FALSE );
1057 p_directbuffer = vout_RenderPicture( p_vout, p_picture, p_subpic );
1060 * Call the plugin-specific rendering method if there is one
1062 if( p_picture != NULL && p_directbuffer != NULL && p_vout->pf_render )
1064 /* Render the direct buffer returned by vout_RenderPicture */
1065 p_vout->pf_render( p_vout, p_directbuffer );
1071 if( display_date != 0 && p_directbuffer != NULL )
1073 mtime_t current_render_time = mdate() - current_date;
1074 /* if render time is very large we don't include it in the mean */
1075 if( current_render_time < p_vout->render_time +
1076 VOUT_DISPLAY_DELAY )
1078 /* Store render time using a sliding mean weighting to
1079 * current value in a 3 to 1 ratio*/
1080 p_vout->render_time *= 3;
1081 p_vout->render_time += current_render_time;
1082 p_vout->render_time >>= 2;
1086 /* Give back change lock */
1087 vlc_mutex_unlock( &p_vout->change_lock );
1089 /* Sleep a while or until a given date */
1090 if( display_date != 0 )
1092 /* If there are filters in the chain, better give them the picture
1094 if( !p_vout->psz_filter_chain || !*p_vout->psz_filter_chain )
1096 mwait( display_date - VOUT_MWAIT_TOLERANCE );
1101 msleep( VOUT_IDLE_SLEEP );
1104 /* On awakening, take back lock and send immediately picture
1106 vlc_mutex_lock( &p_vout->change_lock );
1109 * Display the previously rendered picture
1111 if( p_picture != NULL && p_directbuffer != NULL )
1113 /* Display the direct buffer returned by vout_RenderPicture */
1114 if( p_vout->pf_display )
1116 p_vout->pf_display( p_vout, p_directbuffer );
1119 /* Tell the vout this was the last picture and that it does not
1120 * need to be forced anymore. */
1121 p_last_picture = p_picture;
1122 p_last_picture->b_force = 0;
1125 if( p_picture != NULL )
1127 /* Reinitialize idle loop count */
1132 * Check events and manage thread
1134 if( p_vout->pf_manage && p_vout->pf_manage( p_vout ) )
1136 /* A fatal error occurred, and the thread must terminate
1137 * immediately, without displaying anything - setting b_error to 1
1138 * causes the immediate end of the main while() loop. */
1139 p_vout->b_error = 1;
1142 if( p_vout->i_changes & VOUT_SIZE_CHANGE )
1144 /* this must only happen when the vout plugin is incapable of
1145 * rescaling the picture itself. In this case we need to destroy
1146 * the current picture buffers and recreate new ones with the right
1150 p_vout->i_changes &= ~VOUT_SIZE_CHANGE;
1152 p_vout->pf_end( p_vout );
1153 for( i = 0; i < I_OUTPUTPICTURES; i++ )
1154 p_vout->p_picture[ i ].i_status = FREE_PICTURE;
1156 I_OUTPUTPICTURES = 0;
1157 if( p_vout->pf_init( p_vout ) )
1159 msg_Err( p_vout, "cannot resize display" );
1160 /* FIXME: pf_end will be called again in EndThread() */
1161 p_vout->b_error = 1;
1164 /* Need to reinitialise the chroma plugin */
1165 if( p_vout->chroma.p_module )
1167 if( p_vout->chroma.p_module->pf_deactivate )
1168 p_vout->chroma.p_module->pf_deactivate( VLC_OBJECT(p_vout) );
1169 p_vout->chroma.p_module->pf_activate( VLC_OBJECT(p_vout) );
1173 if( p_vout->i_changes & VOUT_PICTURE_BUFFERS_CHANGE )
1175 /* This happens when the picture buffers need to be recreated.
1176 * This is useful on multimonitor displays for instance.
1178 * Warning: This only works when the vout creates only 1 picture
1180 p_vout->i_changes &= ~VOUT_PICTURE_BUFFERS_CHANGE;
1182 if( !p_vout->b_direct )
1184 module_Unneed( p_vout, p_vout->chroma.p_module );
1187 vlc_mutex_lock( &p_vout->picture_lock );
1189 p_vout->pf_end( p_vout );
1191 I_OUTPUTPICTURES = I_RENDERPICTURES = 0;
1193 p_vout->b_error = InitThread( p_vout );
1195 vlc_mutex_unlock( &p_vout->picture_lock );
1201 vlc_object_release( p_input );
1205 * Error loop - wait until the thread destruction is requested
1207 if( p_vout->b_error )
1209 ErrorThread( p_vout );
1213 EndThread( p_vout );
1215 /* Destroy thread structures allocated by CreateThread */
1216 DestroyThread( p_vout );
1219 /*****************************************************************************
1220 * ErrorThread: RunThread() error loop
1221 *****************************************************************************
1222 * This function is called when an error occurred during thread main's loop.
1223 * The thread can still receive feed, but must be ready to terminate as soon
1225 *****************************************************************************/
1226 static void ErrorThread( vout_thread_t *p_vout )
1228 /* Wait until a `die' order */
1229 while( !p_vout->b_die )
1232 msleep( VOUT_IDLE_SLEEP );
1236 /*****************************************************************************
1237 * EndThread: thread destruction
1238 *****************************************************************************
1239 * This function is called when the thread ends after a sucessful
1240 * initialization. It frees all resources allocated by InitThread.
1241 *****************************************************************************/
1242 static void EndThread( vout_thread_t *p_vout )
1244 int i_index; /* index in heap */
1248 struct tms cpu_usage;
1249 times( &cpu_usage );
1251 msg_Dbg( p_vout, "cpu usage (user: %d, system: %d)",
1252 cpu_usage.tms_utime, cpu_usage.tms_stime );
1256 if( !p_vout->b_direct )
1258 module_Unneed( p_vout, p_vout->chroma.p_module );
1261 /* Destroy all remaining pictures */
1262 for( i_index = 0; i_index < 2 * VOUT_MAX_PICTURES + 1; i_index++ )
1264 if ( p_vout->p_picture[i_index].i_type == MEMORY_PICTURE )
1266 free( p_vout->p_picture[i_index].p_data_orig );
1270 /* Destroy subpicture unit */
1271 spu_Attach( p_vout->p_spu, VLC_OBJECT(p_vout), VLC_FALSE );
1272 spu_Destroy( p_vout->p_spu );
1274 /* Destroy the video filters2 */
1275 RemoveVideoFilters2( p_vout );
1277 /* Destroy translation tables */
1278 p_vout->pf_end( p_vout );
1280 /* Release the change lock */
1281 vlc_mutex_unlock( &p_vout->change_lock );
1284 /*****************************************************************************
1285 * DestroyThread: thread destruction
1286 *****************************************************************************
1287 * This function is called when the thread ends. It frees all ressources
1288 * allocated by CreateThread. Status is available at this stage.
1289 *****************************************************************************/
1290 static void DestroyThread( vout_thread_t *p_vout )
1292 /* Destroy the locks */
1293 vlc_mutex_destroy( &p_vout->picture_lock );
1294 vlc_mutex_destroy( &p_vout->change_lock );
1295 vlc_mutex_destroy( &p_vout->vfilter_lock );
1297 /* Release the module */
1298 if( p_vout && p_vout->p_module )
1300 module_Unneed( p_vout, p_vout->p_module );
1304 /* following functions are local */
1306 static int ReduceHeight( int i_ratio )
1308 int i_dummy = VOUT_ASPECT_FACTOR;
1316 /* VOUT_ASPECT_FACTOR is (2^7 * 3^3 * 5^3), we just check for 2, 3 and 5 */
1317 while( !(i_ratio & 1) && !(i_dummy & 1) )
1324 while( !(i_ratio % 3) && !(i_dummy % 3) )
1331 while( !(i_ratio % 5) && !(i_dummy % 5) )
1341 static void AspectRatio( int i_aspect, int *i_aspect_x, int *i_aspect_y )
1343 unsigned int i_pgcd = ReduceHeight( i_aspect );
1344 *i_aspect_x = i_aspect / i_pgcd;
1345 *i_aspect_y = VOUT_ASPECT_FACTOR / i_pgcd;
1348 /*****************************************************************************
1349 * BinaryLog: computes the base 2 log of a binary value
1350 *****************************************************************************
1351 * This functions is used by MaskToShift, to get a bit index from a binary
1353 *****************************************************************************/
1354 static int BinaryLog( uint32_t i )
1358 if( i == 0 ) return -31337;
1360 if( i & 0xffff0000 ) i_log += 16;
1361 if( i & 0xff00ff00 ) i_log += 8;
1362 if( i & 0xf0f0f0f0 ) i_log += 4;
1363 if( i & 0xcccccccc ) i_log += 2;
1364 if( i & 0xaaaaaaaa ) i_log += 1;
1369 /*****************************************************************************
1370 * MaskToShift: transform a color mask into right and left shifts
1371 *****************************************************************************
1372 * This function is used for obtaining color shifts from masks.
1373 *****************************************************************************/
1374 static void MaskToShift( int *pi_left, int *pi_right, uint32_t i_mask )
1376 uint32_t i_low, i_high; /* lower hand higher bits of the mask */
1380 *pi_left = *pi_right = 0;
1385 i_low = i_high = i_mask;
1387 i_low &= - (int32_t)i_low; /* lower bit of the mask */
1388 i_high += i_low; /* higher bit of the mask */
1390 /* Transform bits into an index. Also deal with i_high overflow, which
1391 * is faster than changing the BinaryLog code to handle 64 bit integers. */
1392 i_low = BinaryLog (i_low);
1393 i_high = i_high ? BinaryLog (i_high) : 32;
1395 /* Update pointers and return */
1397 *pi_right = (8 - i_high + i_low);
1400 /*****************************************************************************
1401 * vout_VarCallback: generic callback for intf variables
1402 *****************************************************************************/
1403 int vout_VarCallback( vlc_object_t * p_this, const char * psz_variable,
1404 vlc_value_t oldval, vlc_value_t newval,
1407 vout_thread_t * p_vout = (vout_thread_t *)p_this;
1409 (void)psz_variable; (void)newval; (void)oldval; (void)p_data;
1410 val.b_bool = VLC_TRUE;
1411 var_Set( p_vout, "intf-change", val );
1415 /*****************************************************************************
1416 * Helper thread for object variables callbacks.
1417 * Only used to avoid deadlocks when using the video embedded mode.
1418 *****************************************************************************/
1419 typedef struct suxor_thread_t
1422 input_thread_t *p_input;
1426 static void SuxorRestartVideoES( suxor_thread_t *p_this )
1430 vlc_thread_ready( p_this );
1432 /* Now restart current video stream */
1433 var_Get( p_this->p_input, "video-es", &val );
1434 if( val.i_int >= 0 )
1437 val_es.i_int = -VIDEO_ES;
1438 var_Set( p_this->p_input, "video-es", val_es );
1439 var_Set( p_this->p_input, "video-es", val );
1442 vlc_object_release( p_this->p_input );
1445 CloseHandle( p_this->thread_id );
1448 vlc_object_destroy( p_this );
1451 /*****************************************************************************
1452 * object variables callbacks: a bunch of object variables are used by the
1453 * interfaces to interact with the vout.
1454 *****************************************************************************/
1455 static int DeinterlaceCallback( vlc_object_t *p_this, char const *psz_cmd,
1456 vlc_value_t oldval, vlc_value_t newval, void *p_data )
1458 vout_thread_t *p_vout = (vout_thread_t *)p_this;
1459 input_thread_t *p_input;
1462 char *psz_mode = newval.psz_string;
1463 char *psz_filter, *psz_deinterlace = NULL;
1464 (void)psz_cmd; (void)oldval; (void)p_data;
1466 var_Get( p_vout, "vout-filter", &val );
1467 psz_filter = val.psz_string;
1468 if( psz_filter ) psz_deinterlace = strstr( psz_filter, "deinterlace" );
1470 if( !psz_mode || !*psz_mode )
1472 if( psz_deinterlace )
1474 char *psz_src = psz_deinterlace + sizeof("deinterlace") - 1;
1475 if( psz_src[0] == ':' ) psz_src++;
1476 memmove( psz_deinterlace, psz_src, strlen(psz_src) + 1 );
1479 else if( !psz_deinterlace )
1481 psz_filter = realloc( psz_filter, strlen( psz_filter ) +
1482 sizeof(":deinterlace") );
1483 if( psz_filter && *psz_filter ) strcat( psz_filter, ":" );
1484 strcat( psz_filter, "deinterlace" );
1487 p_input = (input_thread_t *)vlc_object_find( p_this, VLC_OBJECT_INPUT,
1489 if( !p_input ) return VLC_EGENERIC;
1491 if( psz_mode && *psz_mode )
1493 /* Modify input as well because the vout might have to be restarted */
1494 val.psz_string = psz_mode;
1495 var_Create( p_input, "deinterlace-mode", VLC_VAR_STRING );
1496 var_Set( p_input, "deinterlace-mode", val );
1498 vlc_object_release( p_input );
1500 val.b_bool = VLC_TRUE;
1501 var_Set( p_vout, "intf-change", val );
1503 val.psz_string = psz_filter;
1504 var_Set( p_vout, "vout-filter", val );
1505 if( psz_filter ) free( psz_filter );
1510 static int FilterCallback( vlc_object_t *p_this, char const *psz_cmd,
1511 vlc_value_t oldval, vlc_value_t newval, void *p_data )
1513 vout_thread_t *p_vout = (vout_thread_t *)p_this;
1514 input_thread_t *p_input;
1516 (void)psz_cmd; (void)oldval; (void)p_data;
1518 p_input = (input_thread_t *)vlc_object_find( p_this, VLC_OBJECT_INPUT,
1522 msg_Err( p_vout, "Input not found" );
1523 return( VLC_EGENERIC );
1526 val.b_bool = VLC_TRUE;
1527 var_Set( p_vout, "intf-change", val );
1529 /* Modify input as well because the vout might have to be restarted */
1530 val.psz_string = newval.psz_string;
1531 var_Create( p_input, "vout-filter", VLC_VAR_STRING );
1533 var_Set( p_input, "vout-filter", val );
1535 /* Now restart current video stream */
1536 var_Get( p_input, "video-es", &val );
1537 if( val.i_int >= 0 )
1539 suxor_thread_t *p_suxor =
1540 vlc_object_create( p_vout, sizeof(suxor_thread_t) );
1541 p_suxor->p_input = p_input;
1542 p_vout->b_filter_change = VLC_TRUE;
1543 vlc_object_yield( p_input );
1544 vlc_thread_create( p_suxor, "suxor", SuxorRestartVideoES,
1545 VLC_THREAD_PRIORITY_LOW, VLC_FALSE );
1548 vlc_object_release( p_input );
1553 /*****************************************************************************
1554 * Video Filter2 stuff
1555 *****************************************************************************/
1556 static int ParseVideoFilter2Chain( vout_thread_t *p_vout, char *psz_vfilters )
1559 for( i = 0; i < p_vout->i_vfilters_cfg; i++ )
1561 struct config_chain_t *p_cfg =
1562 p_vout->p_vfilters_cfg[p_vout->i_vfilters_cfg];
1563 config_ChainDestroy( p_cfg );
1564 if( p_vout->psz_vfilters[p_vout->i_vfilters_cfg] )
1566 free( p_vout->psz_vfilters[p_vout->i_vfilters_cfg] );
1567 p_vout->psz_vfilters[p_vout->i_vfilters_cfg] = NULL;
1570 p_vout->i_vfilters_cfg = 0;
1571 if( psz_vfilters && *psz_vfilters )
1573 char *psz_parser = psz_vfilters;
1575 while( psz_parser && *psz_parser )
1577 psz_parser = config_ChainCreate(
1578 &p_vout->psz_vfilters[p_vout->i_vfilters_cfg],
1579 &p_vout->p_vfilters_cfg[p_vout->i_vfilters_cfg],
1581 msg_Dbg( p_vout, "adding vfilter: %s",
1582 p_vout->psz_vfilters[p_vout->i_vfilters_cfg] );
1583 p_vout->i_vfilters_cfg++;
1584 if( psz_parser && *psz_parser )
1586 if( p_vout->i_vfilters_cfg == MAX_VFILTERS )
1589 "maximum number of video filters reached. \"%s\" discarded",
1599 static int VideoFilter2Callback( vlc_object_t *p_this, char const *psz_cmd,
1600 vlc_value_t oldval, vlc_value_t newval, void *p_data )
1602 vout_thread_t *p_vout = (vout_thread_t *)p_this;
1603 (void)psz_cmd; (void)oldval; (void)p_data;
1605 vlc_mutex_lock( &p_vout->vfilter_lock );
1606 ParseVideoFilter2Chain( p_vout, newval.psz_string );
1607 p_vout->b_vfilter_change = VLC_TRUE;
1608 vlc_mutex_unlock( &p_vout->vfilter_lock );
1613 static void RemoveVideoFilters2( vout_thread_t *p_vout )
1616 for( i = 0; i < p_vout->i_vfilters; i++ )
1618 vlc_object_detach( p_vout->pp_vfilters[i] );
1619 if( p_vout->pp_vfilters[i]->p_module )
1621 module_Unneed( p_vout->pp_vfilters[i],
1622 p_vout->pp_vfilters[i]->p_module );
1625 free( p_vout->pp_vfilters[i]->p_owner );
1626 vlc_object_destroy( p_vout->pp_vfilters[i] );
1628 p_vout->i_vfilters = 0;